File links in Delphi

I am opening a file using assignfile as a text file. I need to have multiple copies of the file available in different locations. Rather than copy the file several times, I would rather uses NT links to point to the original file. I guess that when I open the link in Delphi as a text file, I'll just get the link contents, and not the file. How do I extract the file location information from the link as a Delphi text file ?
sparkidoAsked:
Who is Participating?
 
EpsylonConnect With a Mentor Commented:
You can use this to find the path to the file:


procedure TForm1.Button1Click(Sender: TObject);
var
  s1,s2,s3:String;
begin
  GetLinkInfo('c:\windows\start menu\programs\windows explorer.lnk',
              s1,s2,s3);
  ShowMessage('File: '+s1+#13+'Target: '+s2+#13+'Working: '+s3);
end;

procedure TForm1.GetLinkInfo(ALnk: String;
                             var AFile, APath, AWork: String);
const
  // took this TGUID from OLE2.pas
  IID_IPersistFile: TGUID = (D1:$0000010B;
                             D2:$0000;
                             D3:$0000;
                             D4:($C0,$00,$00,$00,$00,$00,$00,$46));
  // Missing from Windows.pas
  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
  // get an interface pointer to the IShellLink interface
  hResx := CoCreateInstance(CLSID_ShellLink,
                            nil,
                            CLSCTX_INPROC_SERVER,
                            IID_IShellLinkA,
                            fShellLink);
  if SUCCEEDED(hResx) then
  begin
    // get an interface pointer to the IPersistFile interface
    // of IShellLink
    hResx := fShellLink.QueryInterface(IID_IPersistFile,
                                       fPersistFile);
    if SUCCEEDED(hResx) then
    begin
      // convert the link file pathname to a PWideChar
      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;
      // terminate our widechar at the length returned
      fWideBuf[WideLen] := #0;
      // initialize the IShellLink object from its disk image
      hResx := fPersistFile.Load(@fWideBuf,
                                 STGM_READ or
                                 STGM_SHARE_DENY_NONE);
      if SUCCEEDED(hResx) then
      begin
        // get target file & path
        fShellLink.GetPath(@fBuf,
                           MAX_PATH,
                           fFindData,
                           0);
        AFile := fFindData.cFileName;
        APath := StrPas(fBuf);
        // get target directory
        fShellLink.GetWorkingDirectory(@fBuf,
                                       Max_Path);
        AWork := StrPas(fBuf);
      end;
    end;
  end;
end;
0
 
MadshiCommented:
Hi Epsylon, do you mind if I shorten your source a bit? I'm always a bit sad, if I see code that doesn't use all the Delphi goodies...

procedure TForm1.GetLinkInfo(ALnk: String;
                             var AFile, APath, AWork: String);
var fShellLink : IShellLink;
    fFindData  : TWin32FindData;
    fBuf       : array [0..MAX_PATH] of Char;
begin
  fShellLink := CreateComObject(CLSID_ShellLink) as IShellLink;
  if (fShellLink as IPersistFile).Load(PWideChar(wideString(ALnk)), 0) = 0 then begin
    fShellLink.GetPath(fBuf, MAX_PATH, fFindData, 0);
    AFile := fFindData.cFileName;
    APath := fBuf;
    fShellLink.GetWorkingDirectory(fBuf, MAX_PATH);
    AWork := fBuf;
  end;
end;

Okay, that were just some little changes, but together they make a difference, don't you think so?   :-)

Regards, Madshi.
0
 
EpsylonCommented:
Hi Madshi, I copy-pasted that code from a PAQ    :o)
Looks a lot better this way!
0
Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

 
sparkidoAuthor Commented:
I get an exception when I run the code on

if (fShellLink as IPersistFile).Load(PWideChar(wideString(ALnk)), 0) = 0 then begin ...

What format should ALnk take, full path and filename ???


0
 
MadshiCommented:
ALnk should be the exact file name, e.g. 'c:\windows\startmenu\programs\winword.lnk'.

Which exception do you get? It works fine for me.

Perhaps you need to add CoInitialize(nil) in your project's initialization.
0
 
sparkidoAuthor Commented:
I actual get an access violation.
I can't find any docs on FShellLink, so I'm struggling to work out why.
0
 
sparkidoAuthor Commented:
Ignore the last comment, I got it working. Thanks very much.

Submit an answer.
0
 
MadshiCommented:
You can accept Eps comment as the answer. There's a link in the top right of each comment with which you can convert a comment into an answer.
0
 
sparkidoAuthor Commented:
Ignore the last comment, I got it working. Thanks very much.

Submit an answer.
0
 
sparkidoAuthor Commented:
Spotted that after I had posted !! (twice!!)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.