Load icon image from file?

Just starting out? Need help? Post your questions and find answers here.
MachineCode
Addict
Addict
Posts: 1482
Joined: Tue Feb 22, 2011 1:16 pm

Load icon image from file?

Post by MachineCode »

I thought I knew how to do this, but I can't. :(

I need to load the icon image from a ".lnk" file from the Windows "Recent" directory:

Code: Select all

doc$="C:\Documents and Settings\Administrator\Recent\Test.txt.lnk"
ic=LoadImage_(GetModuleHandle_(0),@doc$,#IMAGE_ICON,16,16,#LR_LOADFROMFILE)
Debug ic
But the debug output is 0. What am I doing wrong? I've also tried by removing the ".lnk" from the filename, and yes, the file exists.
Microsoft Visual Basic only lasted 7 short years: 1991 to 1998.
PureBasic: Born in 1998 and still going strong to this very day!
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Re: Load icon image from file?

Post by Inf0Byt3 »

Hi. I hope I understood well your question. You cannot load an icon from a lnk file as it doesn't contain one, it just contains info about its target. If you want to get the icon for it, you have to resolve the path to its target file and work with that one. Below is something that works here on XP (both Ascii and Unicode). It does it by getting the shortcut's target first. If it's an exe, we can use ExtractIcon(Ex)_ and if not we ask the shell to get the default icon for the file:

Code: Select all

Procedure.s ShortcutTarget(Link.s)
  ;Inspired by Netmaestro's code
  ;http://forums.purebasic.com/english/viewtopic.php?p=327478&sid=b6724ae539278cb1e17bf4fcc3076408#p327478
  ;Modded for Unicode support
  CompilerIf #PB_Compiler_Unicode
    #CharLen = 2
    Protected PSL.IShellLinkW
  CompilerElse
    #CharLen = 1
    Protected PSL.IShellLinkA
  CompilerEndIf
  If CoInitialize_(0) = #S_OK
    If CoCreateInstance_(?CLSID_ShellLink, 0, 1, ?IID_IShellLink, @PSL) = #S_OK
      If PSL\QueryInterface(?IID_IPersistFile, @LinkFile.IPersistFile) = #S_OK
        If LinkFile\Load(Link, 0) = #S_OK
          If PSL\Resolve(0, 1) = #S_OK
            CompilerIf #PB_Compiler_Unicode
              *Target = AllocateMemory(#MAX_PATH + #CharLen)
              If *Target <> 0
                PSL\GetPath(*Target, #MAX_PATH, 0, 0)
                Result.s = PeekS(*Target)
                FreeMemory(*Target)
              EndIf
            CompilerElse
              Result.s = Space(#MAX_PATH + #CharLen)
              PSL\GetPath(Result, #MAX_PATH, 0, 0)
            CompilerEndIf
          EndIf
        EndIf
      EndIf
      PSL\Release()
    EndIf
    CoUninitialize_()
  EndIf
  ProcedureReturn Result
EndProcedure

Procedure.i GetExtensionIcon(Ext.s)
  SHInfo.SHFILEINFO 
  If Ext <> ""
    SHGetFileInfo_(Ext,#FILE_ATTRIBUTE_NORMAL,@SHInfo,SizeOf(SHFILEINFO),#SHGFI_USEFILEATTRIBUTES|#SHGFI_ICON) ;Also  see #SHGFI_SMALLICON
    ProcedureReturn SHInfo\hIcon
  EndIf
EndProcedure

;---- Put the link path here

MyTarget.s = ShortcutTarget("") ;Don't forget the ".lnk"
If MyTarget <> ""
  If OpenWindow(0, 60, 60, 80, 80, MyTarget, #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    
    Extension.s = LCase(GetExtensionPart(MyTarget))
    If Extension = "exe" Or Extension = "dll" Or Extension = "scr" ;More files can be added? :P
      ;An exe, extract the icon
      MyIcon = ExtractIcon_(GetModuleHandle_(0), MyTarget, 0)
    Else
      ;Any other filetype, get the icon from the system
      MyIcon = GetExtensionIcon("."+Extension)
    EndIf
    
    If MyIcon <> 0
      ImageGadget(0,  25, 25, 48, 48, MyIcon)
    Else
      Debug "Cannot get the icon"
    EndIf

    Repeat 
    Until WaitWindowEvent() = #PB_Event_CloseWindow
    CloseWindow(0)
    If MyIcon <> 0
      DestroyIcon_(MyIcon)
    EndIf
    
  EndIf
Else
  Debug "Can't get the target, check the link path / forgot to add .lnk?"
EndIf

DataSection
  CLSID_ShellLink:
  ;{00021401-0000-0000-C000-000000000046}
  Data.l $00021401
  Data.w $0000,$0000
  Data.b $C0,$00,$00,$00,$00,$00,$00,$46
  IID_IShellLink:
  ; DEFINE_SHLGUID(IID_IShellLinkA, 0x000214EEL, 0, 0);
  ; C000-000000000046
  CompilerIf #PB_Compiler_Unicode
    Data.l $000214F9
  CompilerElse
    Data.l $000214EE
  CompilerEndIf
  Data.w $0000,$0000
  Data.b $C0,$00,$00,$00,$00,$00,$00,$46
  IID_IPersistFile:
  ;{0000010b-0000-0000-C000-000000000046}
  Data.l $0000010b
  Data.w $0000,$0000
  Data.b $C0,$00,$00,$00,$00,$00,$00,$46
EndDataSection
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
MachineCode
Addict
Addict
Posts: 1482
Joined: Tue Feb 22, 2011 1:16 pm

Re: Load icon image from file?

Post by MachineCode »

Thanks Inf0Byt3, it works great. :) The thought never crossed my mind that the LNK file didn't have the icon data.
Microsoft Visual Basic only lasted 7 short years: 1991 to 1998.
PureBasic: Born in 1998 and still going strong to this very day!
MachineCode
Addict
Addict
Posts: 1482
Joined: Tue Feb 22, 2011 1:16 pm

Re: Load icon image from file?

Post by MachineCode »

Just for the record... you changed it to use "If CoInitialize_(0) = #S_OK" now, which fails at times now, because sometimes it returns #S_FALSE for me instead (which still works, though). In the post you linked to, it's just "CoInitialize_(0)" without an "If" test before it, which is the better way to do it, and makes the code work for me everytime. FYI. :)
Microsoft Visual Basic only lasted 7 short years: 1991 to 1998.
PureBasic: Born in 1998 and still going strong to this very day!
Post Reply