3

私は Delphi XE5 および XE6 を使用しており、昇格を促して Delphi 関数を使用するプロセスをシェル化することにより、プログラムで多数のディレクトリ リンクを作成しています。

FileCreateSymLink( sLinkPath, sTargetPath )

この時点から、sLinkPath の使用は、ファイル システムによって sTarget パスに自動的にベクトル化されます。これはすべてうまくいきます。また、(a) リンクかどうか、および (b) どこを指しているかを調べるために、そのようなリンクに問い合わせる必要がある場合もあります。これを行うには、Delphi 関数を呼び出します

function FileGetSymLinkTarget(const FileName: string; var TargetName: string): Boolean;

ローカル ハード ディスク上の別のフォルダを指すリンクが正常に作成された場合、これは正常に機能します。ただし、次のようなネットワークの場所を指すリンクを作成すると

\\SERVER\Working\scratch\BJF\test

リンクはファイル システム レベルで完全に機能しますが、FileGetSymLinkTarget への Delphi 呼び出しは false と null ターゲット文字列を返します。SysUtils.pas に足を踏み入れると、「InternalGetFileNameFromSymLink」への呼び出しが明らかになり、適切なターゲット情報を取得するためにさまざまな呼び出しを「試行」するために手を振っていることが明らかになります。このルーチン内で成功する 1 つの試行は、への呼び出しであることに気付きました

GetObjectInfoName(Handle)

返すもの

\Device\Mup\SERVER\Working\scratch\BJF\test

(閉じる!) しかし、おそらく接頭辞が原因で、ExpandVolumeName によってヌル文字列に消去されます。

だから、私の質問は:

これは XE5 および XE6 のバグである可能性がありますか? SysUtils を使用せずにリンクのターゲットを読み取る他の方法はありますか?

受け入れられた回答に基づく後の追加:

ローカル ドライブとネットワーク パスの正しいシンボリック リンク パスを返す Sertac の例に基づいて、次のようなルーチンを作成しました。今は SysUtils.FileGetSymLinkTarget の代わりにこのルーチンを呼び出していますが、最初に SysUtils.FileGetSymLinkTarget を呼び出し、返されたターゲットが空の場合にのみこのルーチンを使用すると便利な場合があります。

  function MyFileGetSymLinkTarget( const APathToLink : string; var ATarget : string ) : boolean;
  var
    LinkHandle: THandle;
    TargetName: array [0..OFS_MAXPATHNAME-1] of Char;
  begin
    ATarget := '';
    LinkHandle := CreateFile( PChar(APathToLink), 0, FILE_SHARE_READ, nil,
        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
    Win32Check(LinkHandle <> INVALID_HANDLE_VALUE);
    try
      Result := GetFinalPathNameByHandle(LinkHandle, TargetName, OFS_MAXPATHNAME, FILE_NAME_NORMALIZED) > 0;
      if Result then
        begin
        ATarget := TargetName;
        if Pos( '\\?\UNC\', ATarget ) = 1 then
           begin
           Delete( ATarget, 1, 8 );
           Insert( '\\', ATarget, 1 );
           end
          else
          if Pos( '\\?\', ATarget ) = 1 then
             Delete( ATarget, 1, 4 );
        end;
    finally
      CloseHandle(LinkHandle);
    end;
  end;
4

1 に答える 1

3

以下は、を使用する私のテスト設定で機能しますGetFinalPathNameByHandle

var
  LinkHandle: THandle;
  TargetName: array [0..512] of Char;
begin
  LinkHandle := CreateFile('[path to sym link]', 0, FILE_SHARE_READ, nil,
      OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
  Win32Check(LinkHandle <> INVALID_HANDLE_VALUE);
  try
    if GetFinalPathNameByHandle(LinkHandle, TargetName, 512,
        FILE_NAME_NORMALIZED) > 0 then
      ShowMessage(TargetName)
    else
      RaiseLastOSError;
  finally
    CloseHandle(LinkHandle);
  end;

end;

ターゲット パスは として表示され\\?\UNC\Server\Share\Folder\SubFolder\ます。一番左側をもう一度テストして、必要に応じ\\?\UNCて置き換えることが\できます。

VOLUME_NAME_NONEの代わりにFILE_NAME_NORMALIZEDターゲット パスを に置き換えることもできます\Server\Share\Folder\SubFolder\

RTL は、 のVOLUME_NAME_NTようなパスを返す結果タイプを使用して試行の 1 つに同じ関数を使用しDevice\Mup\..、文字列の開始部分をローカル論理ボリューム ( ) の 1 つと一致させようとしGetLogicalDriveStringsます。パスがネットワーク ドライブを指しているため、一致しない場合は、ご指摘のとおり空の文字列が返されます。


ただし、マシン境界を越えたシンボリック リンクに関する RTL ソースのコメントに注意してください。

シンボリック リンクのアクセス権は、ネットワーク ドライブ上では予測できません。したがって、ネットワーク ドライブ上にシンボリック リンクを作成することはお勧めしません。Windows Vista および Windows 7 でシンボリック リンクのリモート アクセスを有効にするには、次のコマンドを使用します: "fsutil behavior set SymlinkEvaluation R2R:1 R2L:1"

于 2014-05-01T19:59:40.347 に答える