How to create a shortcut without using objects?

Just starting out? Need help? Post your questions and find answers here.
AZJIO
Addict
Addict
Posts: 2187
Joined: Sun May 14, 2017 1:48 am

How to create a shortcut without using objects?

Post by AZJIO »

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

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