Information from *.lnk
Information from *.lnk
I need extract information from file shortcut (*.lnk). I want a string containing full path and file name.
I suppose, it is possible after opening file shortcut by PureBasic command, but i don't know how read structure of file shortcut. Thank you for your help.
I suppose, it is possible after opening file shortcut by PureBasic command, but i don't know how read structure of file shortcut. Thank you for your help.
Windows 7 Professional / Service Pack 1 - 32bit, PureBasic 5.46 LTS (x86)
My mother tongue is Czech. I have a Czech version of Windows.
Who is not afraid of GOTO, the one need not afraid any things!
My mother tongue is Czech. I have a Czech version of Windows.
Who is not afraid of GOTO, the one need not afraid any things!
Re: Information from *.lnk
Hi,Lubos wrote:I need extract information from file shortcut (*.lnk). I want a string containing full path and file name.
I suppose, it is possible after opening file shortcut by PureBasic command, but i don't know how read structure of file shortcut. Thank you for your help.
If you want only the full name, you can do it simply with RegEx
Code: Select all
; Extract full filename from a .lnk file
; Marc56us - http://mdacme.com - 2015-11-27, 2018-02-18
RegEx.s = "^[A-Z]\:\\[\w\d\:\\\s\.()\-]+"
Source_Dir.s = GetHomeDirectory() + "Desktop\"
If Not CreateRegularExpression(1, RegEx)
Debug "Bad RegEx. Bye"
EndIf
If ExamineDirectory(0, Source_Dir, "*.lnk")
Debug ~"Target File from .LNK file\n"
While NextDirectoryEntry(0)
If DirectoryEntryType(0) =#PB_DirectoryEntry_File
File_Name.s = DirectoryEntryName(0)
If ReadFile(2, Source_Dir + File_Name)
While Eof(2) = 0
Txt.s = ReadString(2)
If MatchRegularExpression(1, Txt)
Debug RSet(File_Name, 50, ".") + " > [" + Txt + "]"
EndIf
Wend
CloseFile(2)
EndIf
EndIf
Wend
FinishDirectory(0)
EndIf
Re: Information from *.lnk
And here is result:Marc56us wrote: Hi,
If you want only the full name, you can do it simply with RegExCode: Select all
; Extract full filename from a .lnk file ; Marc56us - http://mdacme.com - 2015-11-27, 2018-02-18 ; Hi Marc56us, ;Here is my example which use your code: RegEx.s = "^[A-Z]\:\\[\w\d\:\\\s\.()\-]+" Source_Dir.s = "C:\\Users\A\Desktop\" If Not CreateRegularExpression(1, RegEx) Debug "Bad RegEx. Bye" EndIf If ExamineDirectory(0, Source_Dir, "*.lnk") Debug "Target File from .LNK file\n" While NextDirectoryEntry(0) If DirectoryEntryType(0) =#PB_DirectoryEntry_File File_Name.s = DirectoryEntryName(0) If ReadFile(2, Source_Dir + File_Name) While Eof(2) = 0 Txt.s = ReadString(2) If MatchRegularExpression(1, Txt) Debug RSet(File_Name, 50, ".") + " > [" + Txt + "]" EndIf Wend CloseFile(2) EndIf EndIf Wend FinishDirectory(0) EndIf
Target File from .LNK file\n
...........................agg25.pb – zástupce.lnk > [C:\Users\]
................................Crimson Editor.lnk > [C:\Program Files\Crimson Editor\cedt.exe]
....................................DirtySplit.lnk > [C:\Users\A\Saved Games\Dreamagination\DirtySplit\DirtySplit.exe]
..........................EVEREST Home Edition.lnk > [C:\Program Files\Lavalys\EVEREST Home Edition\everest.exe]
.........................................Flek!.lnk > [C:\Users\A\Desktop\FLEK\flekwin.exe]
..................FreeCommander.exe – zástupce.lnk > [C:\Program Files\FreeCommander\FreeCommander.exe]
..Hedvábník - Robert Galbraith .pdf – zástupce.lnk > [C:\Users\]
....................................I EXPLORER.lnk > [C:\Program Files\Internet Explorer\iexplore.exe]
.......................launcher.exe – zástupce.lnk > [C:\Program Files\Zakl?na?\launcher.exe]
...................miniREMINDER.txt – zástupce.lnk > [C:\Users\]
.........................mpc-hc.exe – zástupce.lnk > [C:\K-Lite Codec Pack\MPC-HC\mpc-hc.exe]
.....................................MV2Player.lnk > [C:\Program Files\Mv2Player\Mv2PlayerPlus.exe]
...............................Prohlížeč Opera.lnk > [C:\Users\]
......................PureBasic.exe – zástupce.lnk > [C:\Users\]
.........................SolveigMM AVI Trimmer.lnk > [C:\Program Files\Solveig Multimedia\SolveigMM AVI Trimmer\SMM_AVITrimmer.exe]
.............................Subtitle Workshop.lnk > [C:\Program Files\URUSoft\Subtitle Workshop\SubtitleWorkshop.exe]
....................................SumatraPDF.lnk > [C:\Program Files\SumatraPDF\SumatraPDF.exe]
It is clear that the results are not always satisfactory, but thank you for your effort and willingness.
Windows 7 Professional / Service Pack 1 - 32bit, PureBasic 5.46 LTS (x86)
My mother tongue is Czech. I have a Czech version of Windows.
Who is not afraid of GOTO, the one need not afraid any things!
My mother tongue is Czech. I have a Czech version of Windows.
Who is not afraid of GOTO, the one need not afraid any things!
Re: Information from *.lnk
I tried:
Code: Select all
Procedure.s ShortcutTarget(ShortcutFile$)
Result$ = ""
CoInitialize_(0)
If CoCreateInstance_(?CLSID_ShellLink, 0, 1,?IID_IShellLink, @ShellLink.IShellLinkA) = #S_OK
If ShellLink\QueryInterface(?IID_IPersistFile, @LinkFile.IPersistFile) = #S_OK
*buffer = AllocateMemory(1000)
If *buffer
MultiByteToWideChar_(#CP_ACP, 0, @ShortcutFile$, -1, *buffer, 1000)
If LinkFile\Load(*buffer, 0) = #S_OK
If ShellLink\Resolve(0, 1) = #S_OK
RtlZeroMemory_(*buffer, 1000)
ShellLink\GetPath(*buffer, 1000, 0, 0)
Result$ = PeekS(*buffer)
EndIf
EndIf
FreeMemory(*buffer)
EndIf
LinkFile\Release()
EndIf
ShellLink\Release()
EndIf
CoUninitialize_()
ProcedureReturn Result$
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
Data.l $000214EE
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
EndProcedure
Shortcut$ = "C:\Users\A\AppData\Roaming\Microsoft\Windows\Recent\001_George Jones - He Stopped Loving Her Today.mp3.lnk "
Target$ = ShortcutTarget(Shortcut$)
Debug Target$
It's probably not your code, and so it's not an explanation. But in any case, thank you for your willingness.
Windows 7 Professional / Service Pack 1 - 32bit, PureBasic 5.46 LTS (x86)
My mother tongue is Czech. I have a Czech version of Windows.
Who is not afraid of GOTO, the one need not afraid any things!
My mother tongue is Czech. I have a Czech version of Windows.
Who is not afraid of GOTO, the one need not afraid any things!
Re: Information from *.lnk
Unicode only.EDIT: Updated code with Bisonte's post of Sicro's code showing the IShellLinkW GUID.
Code: Select all
; NOTES:
; Header file winsdk-10.
; https://raw.githubusercontent.com/tpn/winsdk-10/master/Include/10.0.10240.0/um/ShObjIdl.h
; EXTERN_C const CLSID CLSID_ShellLink;
;
; #ifdef __cplusplus
;
; class DECLSPEC_UUID("00021401-0000-0000-C000-000000000046")
; ShellLink;
; #endif
; #ifndef __IShellLinkW_INTERFACE_DEFINED__
; #define __IShellLinkW_INTERFACE_DEFINED__
;
; /* interface IShellLinkW */
; /* [unique][object][uuid] */
;
;
; EXTERN_C const IID IID_IShellLinkW;
;
; #if defined(__cplusplus) && !defined(CINTERFACE)
;
; MIDL_INTERFACE("000214F9-0000-0000-C000-000000000046")
; IShellLinkW : public IUnknown
; {
; public:
; virtual HRESULT STDMETHODCALLTYPE GetPath(
; /* [size_is][string][out] */ __RPC__out_ecount_full_string(cch) LPWSTR pszFile,
; /* [in] */ int cch,
; /* [unique][out][in] */ __RPC__inout_opt WIN32_FIND_DATAW *pfd,
; /* [in] */ DWORD fFlags) = 0;
Procedure.s SHL_Shortcut_Path(ShortcutFile$)
; Sicro, http://www.purebasic.fr/german/viewtopic.php?f=6&t=23674
; Unicode only.
Protected ShellLink.IShellLinkW
Protected LinkFile.IPersistFile
Protected.i nBytes = #MAX_PATH * SizeOf(Character) + 2
Protected.s ShortCutPath$ = Space(#MAX_PATH + 2)
CoInitialize_(0)
If CoCreateInstance_(?CLSID_ShellLink, 0, 1,?IID_IShellLink, @ShellLink) = #S_OK
If ShellLink\QueryInterface(?IID_IPersistFile, @LinkFile) = #S_OK
If LinkFile\Load(ShortcutFile$, 0) = #S_OK
If ShellLink\Resolve(0, 1) = #S_OK
ShellLink\GetPath(@ShortCutPath$, nBytes, 0, 0)
EndIf
EndIf
LinkFile\Release()
EndIf
ShellLink\Release()
EndIf
CoUninitialize_()
ProcedureReturn ShortCutPath$
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_IShellLinkW, 0x000214F9L, 0, 0); C000-000000000046
Data.l $000214F9
Data.w $0000,$0000
Data.b $C0,$00,$00,$00,$00,$00,$00,$46
IID_IPersistFile:
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms687223(v=vs.85).aspx
; 0000010b-0000-0000-C000-000000000046
Data.l $0000010b
Data.w $0000,$0000
Data.b $C0,$00,$00,$00,$00,$00,$00,$46
EndDataSection
EndProcedure
Debug SHL_Shortcut_Path("C:\dev\favorites\dev.lnk")
Last edited by skywalk on Mon Feb 19, 2018 3:14 am, edited 2 times in total.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Re: Information from *.lnk
You're right Lubos, it's an old program I did in 2015, and it doesn't take all the cases.
It works for me (but not for all UNC). Character set ? (my Windows is in french)
I'll bend over again (and try not to fall) when I'll have time
In the meantime, here is another version that can also extract from LNK file using UNC paths.
(It contains the same bug)
I like to reinvent the wheel
Hope this help
It works for me (but not for all UNC). Character set ? (my Windows is in french)
I'll bend over again (and try not to fall) when I'll have time
In the meantime, here is another version that can also extract from LNK file using UNC paths.
(It contains the same bug)
Code: Select all
; Extract full filename from a .lnk file
; Marc56us - http://mdacme.com - 2015-11-27, 2018-02-18
; Standard and UNC version
RegEx.s = "^([A-Z]\:\\|\\\\)[\w\d\:\\\s\.()\-]+"
Source_Dir.s = GetHomeDirectory() + "Desktop\"
If Not CreateRegularExpression(1, RegEx)
Debug "Bad RegEx. Bye."
Else
If OpenWindow(0, x, y, 800, 600, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ListIconGadget(1, 10, 10, 780, 580, "#", 50, #PB_ListIcon_GridLines)
AddGadgetColumn(1, 1, "LNK File", 280)
AddGadgetColumn(1, 2, "Target", 430)
If ExamineDirectory(0, Source_Dir, "*.lnk")
While NextDirectoryEntry(0)
If DirectoryEntryType(0) =#PB_DirectoryEntry_File
File_Name.s = DirectoryEntryName(0)
If ReadFile(2, Source_Dir + File_Name)
While Eof(2) = 0
Txt.s = ReadString(2)
If MatchRegularExpression(1, Txt)
i + 1
AddGadgetItem(1, -1, Str(i) + Chr(10) + File_Name + Chr(10) + txt)
EndIf
Wend
CloseFile(2)
EndIf
EndIf
Wend
FinishDirectory(0)
EndIf
Repeat : Until WaitWindowEvent(50) = #PB_Event_CloseWindow
EndIf
EndIf
Hope this help
Re: Information from *.lnk
From Sicro at the german forum :
Code: Select all
Procedure.s GetShellLinkTargetPath(ShellLinkFilePath.s)
; Sicro - German forum : http://www.purebasic.fr/german/viewtopic.php?f=6&t=23674
Protected RetVal.s = Space(#MAX_PATH + 1)
Protected LinkFile.IPersistFile
CompilerSelect #PB_Compiler_Unicode
CompilerCase #True: Protected ShellLink.IShellLinkW
CompilerCase #False: Protected ShellLink.IShellLinkA
CompilerEndSelect
CoInitialize_(0)
If CoCreateInstance_(?CLSID_ShellLink, 0, 1, ?IID_IShellLink, @ShellLink) = #S_OK
If ShellLink\QueryInterface(?IID_IPersistFile, @LinkFile) = #S_OK
If LinkFile\Load(ShellLinkFilePath, 0) = #S_OK
If ShellLink\Resolve(0, 1) = #S_OK
CompilerSelect #PB_Compiler_Unicode
CompilerCase #True: ShellLink\GetPath(@RetVal, #MAX_PATH, 0, 0)
CompilerCase #False: ShellLink\GetPath(RetVal, #MAX_PATH, 0, 0)
CompilerEndSelect
EndIf
EndIf
LinkFile\Release()
EndIf
ShellLink\Release()
EndIf
CoUninitialize_()
ProcedureReturn RetVal
EndProcedure
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:
CompilerIf #PB_Compiler_Unicode ; IID_IShellLinkW : 000214F9-0000-0000-C000000000000046
Data.l $000214F9
CompilerElse ; IID_IShellLinkA : 000214EE-0000-0000-C000000000000046
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
Debug GetShellLinkTargetPath("C:\Users\Public\Desktop\Skype.lnk")
Re: Information from *.lnk
Thanks to everyone
Thank you "Marc56us" for the inspirational use of regular express and the willingness to solve my problem. I also thank "skywalk" but I have to admit that his solution goes beyond my modest knowledge. Finally, I chose a solution from "Bisonte". The recommended procedure is applicable in my program practically without modification. Thank you very much.
Thank you "Marc56us" for the inspirational use of regular express and the willingness to solve my problem. I also thank "skywalk" but I have to admit that his solution goes beyond my modest knowledge. Finally, I chose a solution from "Bisonte". The recommended procedure is applicable in my program practically without modification. Thank you very much.
Windows 7 Professional / Service Pack 1 - 32bit, PureBasic 5.46 LTS (x86)
My mother tongue is Czech. I have a Czech version of Windows.
Who is not afraid of GOTO, the one need not afraid any things!
My mother tongue is Czech. I have a Czech version of Windows.
Who is not afraid of GOTO, the one need not afraid any things!
Re: Information from *.lnk
Hi, the code just above by Bisonte (who got it from Sicro) doesn't work for a shortcut on my desktop that I made to "This PC":
From what I can see when I open the LNK file in a hex editor, it should return this:
Because when I put this into the Windows "Run" dialog, it opens "This PC":
Any suggestions on how to get this string from GetShellLinkTargetPath() instead of null?
Code: Select all
Debug GetShellLinkTargetPath("C:\Users\{my-user-name}\Desktop\This PC.lnk") ; Returns null
Code: Select all
{20D04FE0-3AEA-1069-A2D8-08002B30309D}
Code: Select all
Shell:::{20D04FE0-3AEA-1069-A2D8-08002B30309D}
Re: Information from *.lnk
How should we know the detaiuls of your lnk file
If you really want a solution, you have to provide a link where somone can download this file.
Then it is possible that someone looks into your problem.
If you really want a solution, you have to provide a link where somone can download this file.
Then it is possible that someone looks into your problem.
Re: Information from *.lnk
Because I already told you what it is. Right-click the "This PC" icon on your desktop, and make a shortcut of it. That shortcut is the LNK file.infratec wrote:How should we know the detaiuls of your lnk file
Re: Information from *.lnk
I have no 'This PC' icon on my desktop.
So I can not make a link of it.
So I can not make a link of it.
Re: Information from *.lnk
Modifying a snippet by "infratec"
Take it as a start and you can go from here
Take it as a start and you can go from here
Code: Select all
Structure ShellLinkHeaderStr
HeaderSize.l
LinkCLSID.a[16]
LinkFlags.l
FileAttributes.l
CreationTime.q
AccessTime.q
WriteTime.q
FileSize.l
IconIndex.l
ShowCommand.l
HotKey.w
Reserved1.w
Reserved2.l
Reserved3.l
EndStructure
Structure LinkInfoStr
LinkInfoSize.l
LinkInfoHeaderSize.l
LinkInfoFlags.l
VolumeIDOffset.l
LocalBasePathOffset.l
CommonNetworkRelativeLinkOffset.l
CommonPathSuffixOffset.l
LocalBasePathOffsetUnicode.l
CommonPathSuffixOffsetUnicode.l
EndStructure
Enumeration ; neccessary LinkFlags
#HasLinkTargetIDList
#HasLinkInfo
EndEnumeration
Procedure.s GetLinkTarget(FileName$)
If ReadFile(0, Filename$)
Define ByteLengthW.w, ByteLengthL.l, CharLength.w
ReadData(0, @ByteLengthL, 4)
FileSeek(0, 0)
*Header = AllocateMemory(ByteLengthL)
If ReadData(0, *Header, ByteLengthL) = ByteLengthL
*ShellLinkHeader.ShellLinkHeaderStr = *Header
If *ShellLinkHeader\LinkFlags & (1 << #HasLinkTargetIDList)
ReadData(0, @ByteLengthW, 2)
; skip the LinkTargetIDList for now
FileSeek(0, Loc(0) + ByteLengthW)
EndIf
Pos = Loc(0)
If *ShellLinkHeader\LinkFlags & (1 << #HasLinkInfo)
ReadData(0, @BytelengthL, 4)
If ByteLengthL > 0
FileSeek(0, Pos)
*Buffer = AllocateMemory(ByteLengthL)
If ReadData(0, *Buffer, ByteLengthL) = ByteLengthL
*LinkInfo.LinkInfoStr = *Buffer
Target$ = PeekS(*Buffer + *LinkInfo\LocalBasePathOffset,-1,#PB_Ascii)
Target$ + PeekS(*Buffer + *LinkInfo\CommonPathSuffixOffset,-1,#PB_Ascii)
Else
Target$ = "Error: A fault occured"
EndIf
FreeMemory(*Buffer)
EndIf
Else
Target$ = "Error: " + Filename$ + " has no LinkInfo"
EndIf
EndIf
FreeMemory(*Header)
CloseFile(0)
Else
Target$ = "Error: Was not able to open " + Filename$
EndIf
ProcedureReturn Target$
EndProcedure
target$ = "This_PC.lnk"
link$ = "C:\Users\Public\Desktop\"+target$
If FileSize(link$) < 0
link$ = GetHomeDirectory()+"Desktop\"+target$
If FileSize(link$) < 0
Debug "Error : Link not found"
link$ = ""
EndIf
EndIf
If link$ <> ""
Debug GetLinkTarget(link$)
EndIf
Egypt my love
Re: Information from *.lnk
It's Windows 10. On other versions, it's "Computer" or "My Computer". Just the icon that opens your PC info to show your drives, library folders, and so on.infratec wrote:I have no 'This PC' icon on my desktop.
https://support.microsoft.com/en-au/hel ... ow-this-pc
@Rashad: Thank you, I'll see what I can do.