在Delphi XE5中使用FileGetSymLinkTarget不会返回它所指向的网络地址

在Delphi XE5中使用FileGetSymLinkTarget不会返回它所指向的网络地址,delphi,file-link,Delphi,File Link,我正在使用Delphi XE5和XE6,并通过炮击一个提示提升并使用Delphi函数的进程,以编程方式创建大量目录链接: FileCreateSymLink( sLinkPath, sTargetPath ) 从这一点开始,我对sLinkPath的使用被文件系统自动矢量化到sTarget path。这一切都很好。在其他时候,我也需要询问这样一个链接,看看(a)它是否是链接,以及(b)它指向哪里。为此,我调用Delphi函数 function FileGetSymLinkTarget(const

我正在使用Delphi XE5和XE6,并通过炮击一个提示提升并使用Delphi函数的进程,以编程方式创建大量目录链接:

FileCreateSymLink( sLinkPath, sTargetPath )
从这一点开始,我对sLinkPath的使用被文件系统自动矢量化到sTarget path。这一切都很好。在其他时候,我也需要询问这样一个链接,看看(a)它是否是链接,以及(b)它指向哪里。为此,我调用Delphi函数

function FileGetSymLinkTarget(const FileName: string; var TargetName: string): Boolean;
通过成功创建指向本地硬盘上另一个文件夹的链接,这一切正常。但是,当我创建指向网络位置的链接时,例如

\\SERVER\Working\scratch\BJF\test
该链接在文件系统级别上运行良好,但Delphi对FileGetSymLinkTarget的调用返回false和null目标字符串。进入SysUtils.pas会显示一个对“InternalGetFileNameFromSymLink”的调用,这反过来会显示大量的手势,以“尝试”各种调用来获取合理的目标信息。我注意到在这个例程中,成功的一个尝试是调用

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;
函数MyFileGetSymLinkTarget(const-APathToLink:string;var-ATarget:string):布尔值;
变量
链接句柄:THandle;
TargetName:Char的数组[0..OFS_MAXPATHNAME-1];
开始
目标:='';
LinkHandle:=CreateFile(PChar(apahtolink),0,文件共享读取,无,
打开\u现有,文件\u标志\u备份\u语义,0);
Win32Check(LinkHandle无效\u HANDLE\u值);
尝试
结果:=GetFinalPathNameByHandle(LinkHandle、TargetName、OFS\u MAXPATHNAME、文件名\u NORMALIZED)>0;
如果结果是这样的话
开始
ATarget:=TargetName;
如果位置(“\\?\UNC\”,ATarget)=1,则
开始
删除(目标,1,8);
插入(“\\”,目标,1);
结束
其他的
如果位置(“\\?\”,ATarget)=1,则
删除(目标,1,4);
结束;
最后
闭合手柄(链接手柄);
结束;
结束;

以下内容适用于我的测试设置,使用

var
链接句柄:THandle;
TargetName:字符的数组[0..512];
开始
LinkHandle:=CreateFile(“[path to sym link]”,0,文件共享读取,无,
打开\u现有,文件\u标志\u备份\u语义,0);
Win32Check(LinkHandle无效\u HANDLE\u值);
尝试
如果GetFinalPathNameByHandle(LinkHandle,TargetName,512,
文件名(标准化)>0然后
ShowMessage(TargetName)
其他的
赖斯·塞罗;
最后
闭合手柄(链接手柄);
结束;
结束;
目标路径显示为
\\?\UNC\Server\Share\Folder\SubFolder\
。您可以重新测试最左侧的
\\?\UNC
,如果愿意,可以将其替换为
\

您也可以用
卷名\u无
代替
文件名\u规范化
,使目标路径为
\Server\Share\Folder\SubFolder\

RTL在其一次尝试中使用相同的函数,结果类型为
VOLUME\u NAME\u NT
,返回类似
Device\Mup\..
的路径,然后尝试将字符串的起始部分与一个本地逻辑卷相匹配(
GetLogicalDriveStrings
)。如果没有匹配项,由于路径指向网络驱动器,它将返回一个空字符串,如您所述


请注意RTL源中关于跨越机器边界的符号链接的注释:

符号链接的访问权限在网络驱动器上是不可预测的。 因此,不建议通过网络创建符号链接 开车。在Windows Vista和下启用符号链接的远程访问 Windows 7使用命令:“fsutil行为集SymlinkEvaluation R2R:1 R2L:1“


ExpandVolumeName()
将对象前缀转换为本地驱动器号。它返回一个空白字符串,因为目标未映射到本地驱动器号,而是映射到UNC路径
FileGetSymLinkTarget()
使用未记录的
ObjectNameInformation
标志求助于
NTQueryObject()
来获取对象名称,这就是您获取系统定义名称的原因。符号链接在Windows上实现,Microsoft有用于处理重分析点的API,例如。我很惊讶RTL采用了手工破解而不是使用它们。谢谢你的评论,雷米。RTL以这种方式运行似乎很奇怪。我会向教统局提出一个问题,也许有人会看一看。。。。?!请查看
(Ansi)startText()
,而不是使用
Pos()=1
。当删除
\\?\UNC\
时,请单独使用
Delete(ATarget,3,6)
,而不是单独使用
Delete()
Insert()
。建议不错,雷米,谢谢。这非常有效,谢谢。我已经编辑了我的问题,以显示基于上述代码的最终解决方案,该解决方案现在适用于本地和网络驱动器。我确实看到了关于符号链接和网络驱动器的RTL说明,但我只在本地创建它们,并且(可能)指向网络位置,所以我认为这对我来说没问题。@Brian-不客气。你可能是对的,评论不适用于你的情况。如果你需要改变行为的话
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;