我正在使用 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
链接在文件系统级别完美工作,但 Delphi 调用 FileGetSymLinkTarget 返回 false 和空目标字符串。进入 SysUtils.pas 会发现对“InternalGetFileNameFromSymLink”的调用,这反过来又显示出大量的挥手“尝试”各种调用以获得合理的目标信息。我注意到在这个例程中成功的一次尝试是调用
GetObjectInfoName(Handle)
返回结果
\Device\Mup\SERVER\Working\scratch\BJF\test
(关闭!),但随后被 ExpandVolumeName 删除,可能是因为前缀,变为空字符串。
所以,我的问题是:
这可能是 XE5 和 XE6 中的错误吗? 是否有其他方法可以在不使用 SysUtils 的情况下读取链接的目标?
根据接受的答案稍后添加:
我根据 Sertac 的示例创建了一个例程,该例程返回本地驱动器和网络路径的正确符号链接(symbolic link)路径。虽然我现在调用此例程来代替 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;
最佳答案
以下内容在我的测试设置中有效,它使用 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
作为结果类型,返回类似 Device\Mup\..
的路径,然后尝试匹配具有本地逻辑卷之一的字符串的起始部分 (GetLogicalDriveStrings
)。当没有匹配项时,由于路径指向网络驱动器,因此它会返回一个空字符串,正如您所注意到的。
请注意 RTL 源中有关跨机器边界的符号链接(symbolic link)的注释:
The access rights of symlinks are unpredictable over network drives. It is therefore not recommended to create symlinks over a network drive. To enable remote access of symlinks under Windows Vista and Windows 7 use the command: "fsutil behavior set SymlinkEvaluation R2R:1 R2L:1"
关于delphi - 在Delphi XE5中使用FileGetSymLinkTarget不会返回它指向的网络地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23409775/