Recent

Author Topic: Not updating Icon in creating a ".lnk" file  (Read 780 times)

zxandris

  • Jr. Member
  • **
  • Posts: 67
Not updating Icon in creating a ".lnk" file
« on: February 11, 2024, 11:54:59 pm »
Hey there, I was hoping someone would help.  I'm creating short cut files.  It creates the shortcut just fine, but it doesn't update the icon in the file.  It seems to be set correctly.  Anyway the code I'm using is below if you'd help pls.

Code: Pascal  [Select][+][-]
  1. procedure CreateLNKFile(const TargetName, PathName, LNKName, IconFile : String);
  2. var
  3.    IObject : IUnknown;
  4.    ISLink : IShellLink;
  5.    IPFile : IPersistFile;
  6.    IconName : array[0..MAX_PATH] of Char;
  7.    pSHort : array[0..MAX_PATH] of Char;
  8.    DWLen : DWord;
  9.    LinkName : WideString;
  10. begin
  11.       IObject := CreateComObject(CLSID_ShellLink) ;
  12.       ISLink := IObject as IShellLink;
  13.       IPFile := IObject as IPersistFile;
  14.       IconName := Pchar(IconFile);
  15.       pShort := '';
  16.       dwLen := 0;
  17.       DWLen := GetShortPathName(IconName, pShort, dwLen);
  18.       IsLink.SetIconLocation(IconName, dwLen);
  19.       LinkName := WideString(LnkName);
  20.       with ISLink do
  21.       begin
  22.         SetPath(pChar(TargetName));
  23.         SetWorkingDirectory(pChar(PathName)) ;
  24.       end;
  25.       IPFile.Save(PWChar(LinkName), false) ;
  26.       SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_IDLIST, nil, nil);
  27. end;
  28.  

If anyone can help I'd appreciate it, it's Odd! :)

jamie

  • Hero Member
  • *****
  • Posts: 6032
Re: Not updating Icon in creating a ".lnk" file
« Reply #1 on: February 12, 2024, 12:35:01 am »
The GetShortPathName is used wrongly at first glance.

You passed 0 for the size of the buffer, that will only return the required space needed for the name.

You need to call it again with that now known value, or simply pass it the size of your current buffer array..

that's starters anyways.
The only true wisdom is knowing you know nothing

bobby100

  • Full Member
  • ***
  • Posts: 160
    • Malzilla
Re: Not updating Icon in creating a ".lnk" file
« Reply #2 on: February 12, 2024, 12:37:10 am »
Icons are cached on Windows. If you have luck, it will be refreshed after restarting Windows.
btw. some time ago, I've made an app with the same functionality: https://sourceforge.net/projects/url-creator/
https://gitlab.com/bobby100 - my Lazarus components and units
https://sourceforge.net/u/boban_spasic/profile/ - my open source apps

https://malzilla.org/ - remainder at my previous life as a web security expert

zxandris

  • Jr. Member
  • **
  • Posts: 67
Re: Not updating Icon in creating a ".lnk" file
« Reply #3 on: February 12, 2024, 01:22:35 am »
The GetShortPathName is used wrongly at first glance.

You passed 0 for the size of the buffer, that will only return the required space needed for the name.

You need to call it again with that now known value, or simply pass it the size of your current buffer array..

that's starters anyways.

I tried recalling with the value but it creates the file fine and if you go into the lnk file the icon is set...sorta, but the icon on the lnk file in explorer is wrong?

Here's what I'm doing, you'll have to excuse me this is all very new to me, I generally avoided this sort of thing before lol
Code: Pascal  [Select][+][-]
  1. procedure CreateLNKFile2(const TargetName, PathName, LNKName, Args, iconFile : String);
  2. var
  3.    IObject : IUnknown;
  4.    ISLink : IShellLink;
  5.    IPFile : IPersistFile;
  6.    IconName : array[0..MAX_PATH] of Char;
  7.    pSHort : array[0..MAX_PATH] of Char;
  8.    DWLen : DWord;
  9.    LinkName : WideString;
  10. begin
  11.       IObject := CreateComObject(CLSID_ShellLink) ;
  12.       ISLink := IObject as IShellLink;
  13.       IPFile := IObject as IPersistFile;
  14.       IconName := Pchar(IconFile);
  15.       pShort := pchar('');
  16.       dwLen := MAX_PATH;
  17.       DWLen := GetShortPathName(IconName, pShort, dwLen);
  18.       DWLen := GetShortPathName(IconName, pShort, dwLen);
  19.       with ISLink do
  20.       begin
  21.         SetIconLocation(IconName, dwLen);
  22.         SetPath(pChar(TargetName));
  23.         SetArguments(pchar(Args));
  24.         SetWorkingDirectory(pChar(PathName));
  25.       end;
  26.       LinkName := WideString(LnkName);
  27.       IPFile.Save(PWChar(LinkName), false);
  28.       RefreshShellIconCache;
  29.       SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATHA or SHCNF_FLUSH, PChar(PathName), nil);
  30.       SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATHW or SHCNF_FLUSH, PChar(PathName), nil);
  31.       UpdateAssoc;
  32. end;
  33.  
  34.  
  35. procedure UpdateAssoc;
  36. begin
  37.      SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nil, nil);
  38. end;
  39.  
  40. procedure RefreshShellIconCache;
  41. begin
  42.      SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_IDLIST, nil, nil);
  43. end;
  44.  
  45.  

KodeZwerg

  • Hero Member
  • *****
  • Posts: 1999
  • Fifty shades of code.
    • Delphi & FreePascal
Re: Not updating Icon in creating a ".lnk" file
« Reply #4 on: February 12, 2024, 01:28:04 am »
Thats how I do with (unicode) Delphi:
Code: Pascal  [Select][+][-]
  1. function MakeALink(const sNewPathAndLinkfilename: String;
  2.   pTargetPathAndFilename, pAddCommandLine, pTargetWorkPath, pIconFromExe: PChar;
  3.   iIconIndex: Integer; pDescription: PChar): Boolean;
  4. // Create the shortcut named in the LinkFileName argument, and load its data from the non-nil arguments. Return True if successful.
  5. // small bug/feature shortpathnames are auto-expanded to long file format using quotes.
  6. // how to:
  7. // MakeALink ( 'sNewPathAndLinkfilename.lnk', pChar('pTargetPathAndFilename'), pChar('pAddCommandLine'), pChar('TargetWorkPath'), pChar(pIconFromExe), iIconIndex, pChar('pDescription'))
  8. // where 'sNewPathAndLinkfilename.lnk' = Drive:\Path\to\Filename.lnk - file that we create
  9. // 'pTargetPathAndFilename' = Drive:\Path\to\Source.ext - file that the link will be linked to
  10. // 'pAddCommandLine' = '' - any additional Command Line Flags
  11. // 'TargetWorkPath' = can be empty or a specific path
  12. // 'pIconFromExe' = FileName that contain Icon (.ico/.exe./.dll etc)
  13. // 'iIconIndex' = 0 for first Icon inside 'pIconFromExe'
  14. // 'pDescription' = optional Description, will displayed as a hint
  15. VAR
  16.   vUNK: IUnknown;
  17.   vISL: IShellLink;
  18.   vIPF: IPersistFile;
  19.   fNameW: ARRAY [0 .. MAX_PATH] OF WideChar;
  20. begin
  21.   Result := False;
  22.   try
  23.     StringToWideChar(sNewPathAndLinkfilename, fNameW, MAX_PATH);
  24.     vUNK := CreateComObject(CLSID_ShellLink);
  25.     vISL := vUNK AS IShellLink;
  26.     vIPF := vUNK AS IPersistFile;
  27.     try
  28.       IF pTargetPathAndFilename <> nil THEN
  29.         IF vISL.SetPath(pTargetPathAndFilename) <> S_OK THEN
  30.           Exit;
  31.       IF pAddCommandLine <> nil THEN
  32.         IF vISL.SetArguments(pAddCommandLine) <> S_OK THEN
  33.           Exit;
  34.       IF (pIconFromExe <> nil) THEN
  35.         IF vISL.SetIconLocation(pIconFromExe, iIconIndex) <> S_OK THEN
  36.           Exit;
  37.       IF pTargetWorkPath <> nil THEN
  38.         IF vISL.SetWorkingDirectory(pTargetWorkPath) <> S_OK THEN
  39.           Exit;
  40.       IF pDescription <> nil THEN
  41.         IF vISL.SetDescription(pDescription) <> S_OK THEN
  42.           Exit;
  43.       IF vIPF.Save(@fNameW, False) <> S_OK THEN
  44.         Exit;
  45.       Result := True;
  46.     finally
  47.       vIPF := nil;
  48.       vISL := nil;
  49.       vUNK := nil;
  50.     end;
  51.   except
  52.     ON Exception DO;
  53.   end;
  54. end;
« Last Edit: February 12, 2024, 01:56:31 am by KodeZwerg »
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

jamie

  • Hero Member
  • *****
  • Posts: 6032
Re: Not updating Icon in creating a ".lnk" file
« Reply #5 on: February 12, 2024, 01:32:24 am »
THat is closer to what I do but I always specify "TRUE" in the SAVE.


The only true wisdom is knowing you know nothing

KodeZwerg

  • Hero Member
  • *****
  • Posts: 1999
  • Fifty shades of code.
    • Delphi & FreePascal
Re: Not updating Icon in creating a ".lnk" file
« Reply #6 on: February 12, 2024, 01:53:33 am »
THat is closer to what I do but I always specify "TRUE" in the SAVE.
I have different methods for different tasks with .lnk files, that what I showed is to generate a new file from scratch, it will not overwrite. (FALSE)
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

zxandris

  • Jr. Member
  • **
  • Posts: 67
Re: Not updating Icon in creating a ".lnk" file
« Reply #7 on: February 12, 2024, 03:16:32 am »
Thats how I do with (unicode) Delphi:
Code: Pascal  [Select][+][-]
  1. function MakeALink(const sNewPathAndLinkfilename: String;
  2.   pTargetPathAndFilename, pAddCommandLine, pTargetWorkPath, pIconFromExe: PChar;
  3.   iIconIndex: Integer; pDescription: PChar): Boolean;
  4. // Create the shortcut named in the LinkFileName argument, and load its data from the non-nil arguments. Return True if successful.
  5. // small bug/feature shortpathnames are auto-expanded to long file format using quotes.
  6. // how to:
  7. // MakeALink ( 'sNewPathAndLinkfilename.lnk', pChar('pTargetPathAndFilename'), pChar('pAddCommandLine'), pChar('TargetWorkPath'), pChar(pIconFromExe), iIconIndex, pChar('pDescription'))
  8. // where 'sNewPathAndLinkfilename.lnk' = Drive:\Path\to\Filename.lnk - file that we create
  9. // 'pTargetPathAndFilename' = Drive:\Path\to\Source.ext - file that the link will be linked to
  10. // 'pAddCommandLine' = '' - any additional Command Line Flags
  11. // 'TargetWorkPath' = can be empty or a specific path
  12. // 'pIconFromExe' = FileName that contain Icon (.ico/.exe./.dll etc)
  13. // 'iIconIndex' = 0 for first Icon inside 'pIconFromExe'
  14. // 'pDescription' = optional Description, will displayed as a hint
  15. VAR
  16.   vUNK: IUnknown;
  17.   vISL: IShellLink;
  18.   vIPF: IPersistFile;
  19.   fNameW: ARRAY [0 .. MAX_PATH] OF WideChar;
  20. begin
  21.   Result := False;
  22.   try
  23.     StringToWideChar(sNewPathAndLinkfilename, fNameW, MAX_PATH);
  24.     vUNK := CreateComObject(CLSID_ShellLink);
  25.     vISL := vUNK AS IShellLink;
  26.     vIPF := vUNK AS IPersistFile;
  27.     try
  28.       IF pTargetPathAndFilename <> nil THEN
  29.         IF vISL.SetPath(pTargetPathAndFilename) <> S_OK THEN
  30.           Exit;
  31.       IF pAddCommandLine <> nil THEN
  32.         IF vISL.SetArguments(pAddCommandLine) <> S_OK THEN
  33.           Exit;
  34.       IF (pIconFromExe <> nil) THEN
  35.         IF vISL.SetIconLocation(pIconFromExe, iIconIndex) <> S_OK THEN
  36.           Exit;
  37.       IF pTargetWorkPath <> nil THEN
  38.         IF vISL.SetWorkingDirectory(pTargetWorkPath) <> S_OK THEN
  39.           Exit;
  40.       IF pDescription <> nil THEN
  41.         IF vISL.SetDescription(pDescription) <> S_OK THEN
  42.           Exit;
  43.       IF vIPF.Save(@fNameW, False) <> S_OK THEN
  44.         Exit;
  45.       Result := True;
  46.     finally
  47.       vIPF := nil;
  48.       vISL := nil;
  49.       vUNK := nil;
  50.     end;
  51.   except
  52.     ON Exception DO;
  53.   end;
  54. end;

That code doesn't work for me in lazarus errors on "
Code: Pascal  [Select][+][-]
  1. vUNK := CreateComObject(CLSID_ShellLink);
" perhaps I'm not including something that it uses?

zxandris

  • Jr. Member
  • **
  • Posts: 67
Re: Not updating Icon in creating a ".lnk" file
« Reply #8 on: February 12, 2024, 03:24:48 am »
This worked however, which I took from the given code and got the icon showing like it's supposed to.

Code: Pascal  [Select][+][-]
  1. procedure CreateLNKFile2(const TargetName, PathName, LNKName, Args, iconFile : String; const iIconIndex : Integer);
  2. var
  3.    IObject : IUnknown;
  4.    ISLink : IShellLink;
  5.    IPFile : IPersistFile;
  6.    LinkName : WideString;
  7. begin
  8.       IObject := CreateComObject(CLSID_ShellLink) ;
  9.       ISLink := IObject as IShellLink;
  10.       IPFile := IObject as IPersistFile;
  11.       with ISLink do
  12.       begin
  13.         SetIconLocation(pchar(iconFile), iIconIndex);
  14.         SetPath(pChar(TargetName));
  15.         SetArguments(pchar(Args));
  16.         SetWorkingDirectory(pChar(PathName));
  17.       end;
  18.       LinkName := WideString(LnkName);
  19.       IPFile.Save(PWChar(LinkName), false);
  20.       RefreshShellIconCache;
  21.       SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATHA or SHCNF_FLUSH, PChar(PathName), nil);
  22.       SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATHW or SHCNF_FLUSH, PChar(PathName), nil);
  23.       UpdateAssoc;
  24. end;
  25.  

In testing it created the icon just fine.

KodeZwerg

  • Hero Member
  • *****
  • Posts: 1999
  • Fifty shades of code.
    • Delphi & FreePascal
Re: Not updating Icon in creating a ".lnk" file
« Reply #9 on: February 12, 2024, 03:33:51 am »
Code: Pascal  [Select][+][-]
  1.       IObject := CreateComObject(CLSID_ShellLink) ;
Code: Pascal  [Select][+][-]
  1.     vUNK := CreateComObject(CLSID_ShellLink);
That code doesn't work for me in lazarus errors on ... perhaps I'm not including something that it uses?
Since the call that you show is the same as in your first example, how should I know what and why you removed something from "uses" ?
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

zxandris

  • Jr. Member
  • **
  • Posts: 67
Re: Not updating Icon in creating a ".lnk" file
« Reply #10 on: February 12, 2024, 05:52:15 am »
O
Code: Pascal  [Select][+][-]
  1.       IObject := CreateComObject(CLSID_ShellLink) ;
Code: Pascal  [Select][+][-]
  1.     vUNK := CreateComObject(CLSID_ShellLink);
That code doesn't work for me in lazarus errors on ... perhaps I'm not including something that it uses?
Since the call that you show is the same as in your first example, how should I know what and why you removed something from "uses" ?

OMG I'm an idiot, I was trying that code in another program, a test project.  Obviously didn't have what the original did.  Oh well, It is working now all told.

But thanks for all the help guys you're the Best!

 

TinyPortal © 2005-2018