本文介绍了JclShell.ShellLinkResolve 获取错误数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

限时删除!!

JclShell.TShellLink.Target 返回错误路径:

uses
  JclShell;
...
var
  ThisShellLinkRecord: JclShell.TShellLink;
  ThisTargetExePath: string;
begin
  JclShell.ShellLinkResolve('C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Xara\Xara Designer Pro X9\Xara Designer Pro X9.lnk', ThisShellLinkRecord);
  ThisTargetExePath := ThisShellLinkRecord.Target;

ThisTargetExePath 从上面的代码结果为:
C:\Program Files (x86)\Xara\Xara Designer Pro X9\DesignerPro.exe
请注意结果目标路径中的 (x86) 表示 32 位程序文件路径.

ThisTargetExePath from the above code results as:
C:\Program Files (x86)\Xara\Xara Designer Pro X9\DesignerPro.exe
Please note the (x86) in the resulting target path which indicates the 32-bit program files path.

然而,这是错误的路径,不存在!当我从 Windows 开始菜单手动打开 Xara Designer Pro 开始菜单链接的属性对话框时,目标路径为:
C:\Program Files\Xara\Xara Designer Pro X9\DesignerPro.exe
请注意,这是 64 位程序文件路径并且确实存在!

HOWEVER, this is the wrong path and does not exist! When I manually open the Properties dialog of the Xara Designer Pro start menu link from the Windows Start Menu, the target path is:
C:\Program Files\Xara\Xara Designer Pro X9\DesignerPro.exe
Please note that this is the 64-bit program files path and DOES exist!

那么为什么 ShellLinkResolve 会在这里返回错误的数据呢?

So why does ShellLinkResolve give back the wrong data here?

编辑:我在 Notepad++ 中打开了链接:我在其中只找到了 ABSOLUTE 64 位程序文件路径(没有环境变量),请参见此处:goo.gl/jWUDb9

EDIT: I've opened the link in Notepad++: I've found only the ABSOLUTE 64-bit program files path in it (no environment variable), see here: goo.gl/jWUDb9

EDIT2:

你说得对,编译为 32 位程序或编译为 64 位程序会有不同的结果:

You are right, there are different results if compiled as a 32-bit program or as a 64-bit program:

procedure TForm1.btn1Click(Sender: TObject);
var
  ThisShellLinkRecord: JclShell.TShellLink;
begin
  JclShell.ShellLinkResolve(Edit1.Text, ThisShellLinkRecord);

  {$IFDEF WIN32}
    Form1.Caption := 'This is a 32-bit program';
    Label1.Caption := ThisShellLinkRecord.Target;
  {$ELSE}
    Form1.Caption := 'This is a 64-bit program';
    Label1.Caption := JclFileUtils.PathGetLongName(ThisShellLinkRecord.Target);
  {$ENDIF}
end;

以下是视觉效果:
http://goo.gl/MttrZA
http://goo.gl/hvQqP6

EDIT3:这是编码的链接文件(Xara Designer Pro X9.lnk,用 Soap.EncdDecd.EncodeBase64 编码):

EDIT3: Here is the encoded link file (Xara Designer Pro X9.lnk, encoded with Soap.EncdDecd.EncodeBase64):

TAAAAAEUAgAAAAAAaaaaaaaeabAAAAICAAAHCmGD2HDc8Ba9NGcKwWzwFwphg9hw3PASiAxAEAAAAAAAQAAAAAAAAAAAAAAAAAAANcBFAAfuOBP0CDqOmkQotgIACswMJ0ZAC9DOlwAAAAAAAAAAAAAAAAAAAAAAAAAAAiAAxAAAAAAA1RFVrESBQUk9HUkF+MQAAcAAIAAQA777uOoUaNURVayoAAAA8AAAAAAABAAAAAAAAAAAAARgAAAAAAUAByAG8AZwByAGEAbQAgAEYAaQBsAGUAcwAAAEAAcwBoAGUAbABsADMAMgAuAGQAbABSACwALQAyADEANwA4ADEAAAAYAEoAMQAAAAAANURVaxAgWGFyYQAANgAIAAQA第7741章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

推荐答案

也许这有助于:通过解析内部结构直接从 lnk 文件读取目标路径:

Maybe this help: direct reading of target path from lnk file via parsing of internal structures:

type
  TdecShellLinkHeader = packed record
    HeaderSize: DWORD;
    LinkCLSID: TGUID;
    LinkFlags: DWORD;
    FileAttributes: DWORD;
    CreationTime: TFILETIME;
    AccessTime: TFILETIME;
    WriteTime: TFILETIME;
    FileSize: DWORD;
    IconIndex: Integer;
    ShowCommand: DWORD;
    HotKey: Word;
    Reserved1: Word;
    Reserved2: DWORD;
    Reserved3: DWORD;
  end;

const
  LnkFileCLSID: TGUID = '{00021401-0000-0000-C000-000000000046}';

function DirectReadTargetNameFromLnkFile(const AFileName: UnicodeString): UnicodeString;
var
  Stream: TStream;
  Header: TdecShellLinkHeader;
  Size: Word;
  IDList: PItemIDList;
  Desktop: IShellFolder;
  ShellFolder: IShellFolder;
  ChildItem: PItemIDList;
  StrRet: TStrRet;
  AnsiResult: AnsiString;
  Result2: UnicodeString;
begin
  Result := '';
  Stream := TFileStream.Create(AFileName, fmOpenRead);
  try
    Stream.ReadBuffer(Header, SizeOf(Header));
    if not (Header.HeaderSize = SizeOf(Header)) or
      not IsEqualCLSID(Header.LinkCLSID, LnkFileCLSID) then
        raise Exception.Create('Invalid Lnk file');

    if Header.LinkFlags and SLDF_HAS_ID_LIST <> 0 then
      begin
        Stream.ReadBuffer(Size, SizeOf(Size));
        IDList := CoTaskMemAlloc(Size);
        try
          Stream.ReadBuffer(IDList^, Size);
          OleCheck(SHGetDesktopFolder(Desktop));
          try
            OleCheck(SHBindToParent(IDList, IShellFolder, Pointer(ShellFolder), ChildItem));
            try
              OleCheck(ShellFolder.GetDisplayNameOf(ChildItem, SHGDN_FORPARSING, StrRet));
              case StrRet.uType of
                STRRET_WSTR:
                  begin
                    Result := StrRet.pOleStr;
                    CoTaskMemFree(StrRet.pOleStr);
                  end;
                STRRET_OFFSET:
                  begin
                    Inc(PByte(ChildItem), StrRet.uOffset);
                    Result := UnicodeString(PAnsiChar(ChildItem));
                  end;
                STRRET_CSTR:
                  Result := UnicodeString(AnsiString(StrRet.cStr));
              else Result := '';
              end;
              Exit;
            finally
              ShellFolder := nil;
            end;
          finally
            Desktop := nil;
          end;
        finally
          CoTaskMemFree(IDList);
        end;
      end;

    if Header.LinkFlags and SLDF_HAS_LINK_INFO <> 0 then
      begin
        Stream.ReadBuffer(Size, SizeOf(Size));
        Stream.Seek(Size - SizeOf(Size), soFromCurrent);
      end;

    if Header.LinkFlags and SLDF_HAS_NAME <> 0 then
      begin
        Stream.ReadBuffer(Size, SizeOf(Size));
        if Header.LinkFlags and SLDF_UNICODE <> 0 then
          Stream.Seek(Size * SizeOf(WideChar), soFromCurrent)
        else
          Stream.Seek(Size * SizeOf(AnsiChar), soFromCurrent);
      end;

    if Header.LinkFlags and SLDF_HAS_RELPATH <> 0 then
      begin
        Stream.ReadBuffer(Size, SizeOf(Size));
        if Header.LinkFlags and SLDF_UNICODE <> 0 then
          begin
            SetLength(Result, Size);
            if Size > 0 then
              Stream.ReadBuffer(PWideChar(Result)^, Size * SizeOf(WideChar));
          end
        else
          begin
            SetLength(AnsiResult, Size);
            if Size > 0 then
              Stream.ReadBuffer(PAnsiChar(AnsiResult)^, Size * SizeOf(AnsiChar));
            Result := AnsiResult;
          end;

        if Header.LinkFlags and SLDF_HAS_EXP_SZ <> 0 then
          begin
            Size := ExpandEnvironmentStringsW(PWideChar(Result), nil, 0);
            if Size > 1 then
              begin
                SetLength(Result2, Size - 1);
                ExpandEnvironmentStringsW(PWideChar(Result), PWideChar(Result2), Size);
                Result := Result2;
              end;
          end;

        Result2 := ExtractFileDir(AFileName);
        while Pos('..\', Result) = 1 do
          begin
            Result2 := ExtractFileDir(Result2);
            Delete(Result, 1, 3);
          end;
        Result := Result2 + '\' + Result;
      end;
  finally
    Stream.Free;
  end;
end;

使用风险自负!

这篇关于JclShell.ShellLinkResolve 获取错误数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

1403页,肝出来的..

09-07 01:59