Getting Target Path from a Shortcut (.lnk file)

Ive found plenty of sources for creating a shortcut.  But how do i read a shortcut and get its target path?

I want to use this feature in a Directory tree, so that when a shortcut is double clicked it takes you to its target.
LVL 1
SpannerBracketAsked:
Who is Participating?

[Webinar] Streamline your web hosting managementRegister Today

x
 
intheConnect With a Mentor Commented:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls,shlobj,activex,comobj,commctrl,menus;

type
  TForm1 = class(TForm)
    Button1: TButton;
    OpenDialog1: TOpenDialog;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }

  public
    { Public declarations }
  end;

var
  Form1: TForm1;
   NeedToUninitialize : boolean = false;
implementation

{$R *.DFM}

function LoadShellLink(shellLinkFile: string;
                       var description, linkedObj, params: string;
                       var pidl: PItemIDList; var findData: TWin32FindData;
                       var iconPath: string; var iconIndex: integer;
                       var workingDir, hotKey: string;
                       var showCmd: integer) : boolean;
var sl  : IShellLink;
    w1  : word;
    s1  : string;
    wfd : TWin32FindData;
    i1  : integer;
begin
  NeedToUninitialize:=NeedToUninitialize or succeeded(CoInitialize(nil));
  sl:=CreateComObject(CLSID_ShellLink) as IShellLink;
  result:=(sl as IPersistFile).Load(PWideChar(wideString(ShellLinkFile)),0)=S_OK;
  if not result then exit;
  SetLength(description,MAX_PATH+1);
  if sl.GetDescription(PChar(description),MAX_PATH)=NOERROR then description:=string(PChar(description))
  else                                                           description:='';
  SetLength(s1,MAX_PATH+1);
  if sl.GetPath(PChar(s1),MAX_PATH,wfd,0)=NOERROR then begin
    linkedObj:=string(PChar(s1));
    findData :=wfd;
  end else begin
    linkedObj:='';
    ZeroMemory(@findData,sizeOf(TWin32FindData));
  end;
  SetLength(params,MAX_PATH+1);
  if sl.GetArguments(PChar(params),MAX_PATH)=NOERROR then params:=string(PChar(params))
  else                                                    params:='';
  if sl.GetIDList(pidl)<>NOERROR then pidl:=nil;
  SetLength(s1,MAX_PATH+1);
  if sl.GetIconLocation(pchar(s1),MAX_PATH,i1)=NOERROR then begin
    iconPath :=string(pchar(s1));
    iconIndex:=i1;
  end else begin
    iconPath :='';
    iconIndex:=-1;
  end;
  SetLength(workingDir,MAX_PATH+1);
  if sl.GetWorkingDirectory(PChar(workingDir),MAX_PATH)=NOERROR then workingDir:=string(PChar(workingDir))
  else                                                               workingDir:='';
  sl.GetHotKey(w1);
  if w1 and (HOTKEYF_ALT     shl 8)<>0 then w1:=(w1 and (not (HOTKEYF_ALT     shl 8))) or scAlt;
  if w1 and (HOTKEYF_CONTROL shl 8)<>0 then w1:=(w1 and (not (HOTKEYF_CONTROL shl 8))) or scCtrl;
  if w1 and (HOTKEYF_SHIFT   shl 8)<>0 then w1:=(w1 and (not (HOTKEYF_SHIFT   shl 8))) or scShift;
  hotKey:=ShortCutToText(w1);
  if sl.GetShowCmd(showCmd)<>NOERROR then showCmd:=-1;
end;

procedure FreePidl(var pidl: PItemIDList);
var malloc : IMalloc;
begin
  if (pidl<>nil) and (SHGetMalloc(malloc)=NOERROR) then begin
    malloc.Free(pidl);
    pidl:=nil;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  pi:PItemIDList;
  s1,Desc,s2:String;
  icon,workdir,htkey:string;
  Data: TWin32FindData;
  i,ii : integer;
begin
  opendialog1.execute;
  loadshelllink(opendialog1.filename,desc,s1,s2,pi,Data,icon,i,workdir,htkey,ii);
  ShowMessage('File ShortCut : '+opendialog1.filename+#13#10+'File TruePath : '+s1+#13#10+'Working Dir : '+workdir+#13#10
              +'HotKey : '+htkey+#13#10+'Show Command : '+inttostr(ii));
 FreePidl(pi);
end;


initialization
finalization
  if NeedToUninitialize then CoUninitialize;

end.
0
 
intheCommented:
Hi
above is an example of reading .lnk files and all the info they can hold ,including hotkeys etc ..

Regards Barry
0
 
SpannerBracketAuthor Commented:
Ive had a play with the code.. and i couldn't get this to work. No matter what i did (and yeah, i did try the code exactly as it was above =).

It wouldn't return any data apart from the shortcut path (im not really interested in any other data though), but then this is just got from using the OpenDialog1.Filename.

If i just create a form, and stick in an OpenDialog i can get the shortcut target from that method, but that defeats the point of what im trying to do.

I presume the code worked for you.. any idea what i might be doing wrong?

Cheers
0
[Webinar] Improve your customer journey

A positive customer journey is important in attracting and retaining business. To improve this experience, you can use Google Maps APIs to increase checkout conversions, boost user engagement, and optimize order fulfillment. Learn how in this webinar presented by Dito.

 
intheCommented:
im just on way to work but should only be for 3-4 hours then i test this when come home.
yes it did work i remember we spent ages trying to get it right.

leave a comment saying which parts you want to get.
ie only the file name/path the link points to or do you want any other info?
oh and what version of delphi you use.
0
 
duke_nCommented:
I had a component that does it somewhere(src included). If ye want, I'll be  sending it to ye.
0
 
SpannerBracketAuthor Commented:
Yeah, it was just the path the link points to that i was needing, and im on Delphi 4 =)

Duke, that would be great (err, being new to this experts.. and stuff, do i need to give you my email addy?).
0
 
duke_nCommented:
well, how else would I send it to ya?
0
 
SpannerBracketAuthor Commented:
Dunno... haven't explored Experts-Exchange properly yet, thought you might be able to get it from there... maybe not =)

spannerbracket@crosswinds.net
0
 
intheCommented:
hello ,
 sorry im late (for a change ;-)

i also use this in d4 and no probs can i ask what was problem?

try this instead:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls,shlobj,activex,comobj;

type
  TForm1 = class(TForm)
    Button1: TButton;
    OpenDialog1: TOpenDialog;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
   procedure GetLinkInfo(ALnk: String;
       var AFile, APath, AWork: String);
    public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}
procedure TForm1.GetLinkInfo(ALnk: String;
                             var AFile, APath, AWork: String);
const
  IID_IPersistFile: TGUID = (D1:$0000010B;
                             D2:$0000;
                             D3:$0000;
                             D4:($C0,$00,$00,$00,$00,$00,$00,$46));
  MB_ERR_INVALID_CHARS = $00000008;
var
  fShellLink   : IShellLink;
  fPersistFile : IPersistFile;
  fFindData    : TWin32FindData;
  fWideBuf     : array[0..MAX_PATH] of WideChar;
  fBuf         : array[0..MAX_PATH] of Char;
  hResx        : hResult;
  WideLen      : Integer;
begin
  hResx := CoCreateInstance(
  CLSID_ShellLink,nil,CLSCTX_INPROC_SERVER,IID_IShellLinkA,fShellLink);
  if SUCCEEDED(hResx) then
  begin
    hResx := fShellLink.QueryInterface(IID_IPersistFile,fPersistFile);
    if SUCCEEDED(hResx) then
    begin
      WideLen := MultiByteToWideChar(CP_ACP,
                                     MB_ERR_INVALID_CHARS,
                                     pChar(ALnk),
                                     Length(ALnk),
                                     @fWideBuf,
                                     MAX_PATH);
      if WideLen = 0 then
      begin
        ShowMessage('MultiByteToWideChar FAILED');
        Exit;
      end;
      fWideBuf[WideLen] := #0;
      hResx := fPersistFile.Load(@fWideBuf,
                                 STGM_READ or
                                 STGM_SHARE_DENY_NONE);
      if SUCCEEDED(hResx) then
      begin
        fShellLink.GetPath(@fBuf,
                           MAX_PATH,
                           fFindData,
                           0);
        AFile := fFindData.cFileName;
        APath := StrPas(fBuf);
        fShellLink.GetWorkingDirectory(@fBuf,Max_Path);
        AWork := StrPas(fBuf);
      end;
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  s1,s2,s3:String;
begin
  //opendialog1.execute;
  //GetLinkInfo(opendialog1.filename,s1,s2,s3);
  GetLinkInfo('c:\windows\start menu\programs\windows explorer.lnk',s1,s2,s3);
  ShowMessage(s2);
end;

end.



btw duke_n.
that component sounds interesting ;-)

BorgsAsimilate@Aol.Com


0
 
SpannerBracketAuthor Commented:
Aha.. works fine now.

Maybe i was doing something stupid before, but no matter what shortcut i gave it it would return no info, no error either.

You can find a ShellLink component on delphi.icm.edu.pl . Do a search for shortcut selecting Delphi 4.

Im using the component now for the simplicity of it, but thanks for going to the trouble of posting source, ill keep it as a reference if i ever get into delphi that deep =)

Cheers again,
0
 
SpannerBracketAuthor Commented:
Ooops.. probably misleading, i've selected the wrong source as the answer, the second bit of source worked for me =)
0
 
duke_nCommented:
Inthe, I coulndn't send an email to ye...:

Your e-mail is being returned to you because there was a problem with its
delivery.  The AOL address which was undeliverable is listed in the section
labeled: "----- The following addresses had permanent fatal errors -----".

{blablabla}

   ----- The following addresses had permanent fatal errors -----
<BorgsAsimilate@Aol.Com>
{blablabla}

sorry, muchacho
0
 
intheCommented:
hi thanks SpannerBracket ;-)

duke_n i miss and "s" sorry it should be either:

BorgsAssimilate@Aol.Com
or
Legend@Enterprise.Net
0
All Courses

From novice to tech pro — start learning today.