How to create a shortcut without using objects?
Posted: Tue Jun 04, 2024 6:52 pm
When using objects, the path to the file that the shortcut refers to is checked, which is why the operation is very slow (2 minutes) when creating 100 shortcuts. This is useful when creating shortcuts in LiveCD when programs are on a flash drive. If the paths in the shortcut are checked for the existence of executable files, this will increase the startup time of the LiveCD.
ms-shllink.pdf
scheme
ms-shllink.pdf
scheme
Code: Select all
EnableExplicit
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
; Global ByteLengthL = SizeOf(ShellLinkHeaderStr)
; Global ByteLengthL2 = SizeOf(LinkInfoStr)
Global ByteLengthL = 76
Global ByteLengthL2 = 36
Procedure CreateLink()
Protected ShellLinkHeader.ShellLinkHeaderStr, LinkInfo.LinkInfoStr
Protected file_id
Protected Filename$, StringData$
Protected i, bytes
Filename$ = "C:\Temp\link-------------.lnk"
file_id = CreateFile(#PB_Any, Filename$)
If file_id
; ShellLinkHeader\HeaderSize = ByteLengthL
; ShellLinkHeader\LinkFlags = 2
With ShellLinkHeader
\HeaderSize = ByteLengthL
Restore CLSID_ShellLink
Read.l \LinkCLSID.a[0]
Read.w \LinkCLSID.a[4]
Read.w \LinkCLSID.a[6]
For i = 8 To 15
Read.w \LinkCLSID.a[i]
Next
\LinkFlags = 2 + 8 + 16 + 32 + 64
\FileAttributes = #PB_FileSystem_Normal
; \CreationTime =
; \AccessTime =
; \WriteTime =
; \FileSize =
; \IconIndex =
; \ShowCommand =
; \HotKey =
EndWith
WriteData(file_id, ShellLinkHeader, ByteLengthL)
; *Buffer = AllocateMemory(62+17)
; WriteData(file_id, *Buffer, 62+17)
; FreeMemory(*Buffer)
; Здесь буквы-индексы -A- — -G- всего лишь имена полей как описаны в справке.
If (ShellLinkHeader\LinkFlags & 1)
Debug "-A- LinkTargetIdList"
WriteWord(file_id, 2)
; WriteString()
EndIf
If (ShellLinkHeader\LinkFlags & 2)
Debug "-B- linkinfo"
; WriteLong(file_id, 36)
With LinkInfo
\LinkInfoSize = 172
\LinkInfoHeaderSize = 36
\LinkInfoFlags = 1
\VolumeIDOffset = 28
\LocalBasePathOffset = 38
\CommonNetworkRelativeLinkOffset = 0
\CommonPathSuffixOffset = 36
\LocalBasePathOffsetUnicode = 38
\CommonPathSuffixOffsetUnicode = 36
EndWith
WriteData(file_id, LinkInfo, ByteLengthL2) ; записываем структуру LinkInfo
EndIf
With ShellLinkHeader
If (\LinkFlags & 4)
Debug "-C- Имя"
WriteLong(file_id, 11)
StringData$ = "привет"
bytes = StringByteLength(StringData$, #PB_Unicode)
WriteWord(file_id, bytes)
WriteString(file_id, StringData$, #PB_Unicode) ; пишем строку
WriteData(file_id, @"", 1)
WriteData(file_id, @"", 1)
EndIf
If (\LinkFlags & 8)
Debug "-D- Относительный путь"
StringData$ = "C:\test\file.txt"
bytes = StringByteLength(StringData$, #PB_Unicode)
WriteWord(file_id, bytes)
WriteString(file_id, StringData$, #PB_Unicode) ; пишем строку
WriteData(file_id, @"", 1)
WriteData(file_id, @"", 1)
EndIf
If (\LinkFlags & 16)
Debug "-E- Рабочий каталог"
StringData$ = "C:\test\"
bytes = StringByteLength(StringData$, #PB_Unicode)
WriteWord(file_id, bytes)
WriteString(file_id, StringData$, #PB_Unicode) ; пишем строку
WriteData(file_id, @"", 1)
WriteData(file_id, @"", 1)
EndIf
If (\LinkFlags & 32)
Debug "-F- Аргументы"
StringData$ = "-t -e"
bytes = StringByteLength(StringData$, #PB_Unicode)
WriteWord(file_id, bytes)
WriteString(file_id, StringData$, #PB_Unicode) ; пишем строку
WriteData(file_id, @"", 1)
WriteData(file_id, @"", 1)
EndIf
If (\LinkFlags & 64)
Debug "-G- Значок"
StringData$ = "C:\Program Files\7-Zip\7zFM.exe"
bytes = StringByteLength(StringData$, #PB_Unicode)
WriteWord(file_id, bytes)
WriteString(file_id, StringData$, #PB_Unicode) ; пишем строку
WriteData(file_id, @"", 1)
WriteData(file_id, @"", 1)
EndIf
EndWith
CloseFile(file_id)
Else
Debug "Не удалось создать файл " + Filename$
EndIf
EndProcedure
CreateLink()
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-C000-000000000046}
Data.l $000214F9
CompilerElse
; 000214EE-0000-0000-C000-000000000046
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