ReactOS 0.4.16-dev-974-g5022a45
mkshelllink.c
Go to the documentation of this file.
1/* COPYRIGHT: See COPYING in the top level directory
2 * PROJECT: ReactOS Shell Link maker
3 * FILE: tools/mkshelllink/mkshelllink.c
4 * PURPOSE: Shell Link maker
5 * PROGRAMMER: Rafal Harabien
6 */
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <ctype.h>
12
13#ifndef _MSC_VER
14#include <stdint.h>
15#else
16typedef unsigned __int8 uint8_t;
17typedef unsigned __int16 uint16_t;
18typedef unsigned __int32 uint32_t;
19#endif
20
21#ifdef _WIN32
22#define strcasecmp _stricmp
23#endif
24
25#define SW_SHOWNORMAL 1
26#define SW_SHOWMINNOACTIVE 7
27#define CSIDL_WINDOWS 0x24
28#define CSIDL_SYSTEM 0x25
29
30typedef struct _GUID
31{
37
38typedef struct _FILETIME {
42
43#define DEFINE_GUID2(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) const GUID name = { l,w1,w2,{ b1,b2,b3,b4,b5,b6,b7,b8 } }
44DEFINE_GUID2(CLSID_ShellLink,0x00021401L,0,0,0xC0,0,0,0,0,0,0,0x46);
45DEFINE_GUID2(CLSID_MyComputer,0x20D04FE0,0x3AEA,0x1069,0xA2,0xD8,0x08,0x00,0x2B,0x30,0x30,0x9D);
46
47#define LINK_ID_LIST 0x01
48#define LINK_FILE 0x02
49#define LINK_DESCRIPTION 0x04
50#define LINK_RELATIVE_PATH 0x08
51#define LINK_WORKING_DIR 0x10
52#define LINK_CMD_LINE_ARGS 0x20
53#define LINK_ICON 0x40
54#define LINK_UNICODE 0x80
55
56#define LOCATOR_LOCAL 0x1
57#define LOCATOR_NETWORK 0x2
58
59#pragma pack(push, 1)
60
61/* Specification: http://ithreats.files.wordpress.com/2009/05/lnk_the_windows_shortcut_file_format.pdf */
62
63typedef struct _LNK_HEADER
64{
79
80typedef struct _LNK_LOCATOR_INFO
81{
89 char Data[0];
91
93{
95 uint32_t VolumeType; /* See GetDriveType */
98 char VolumeLabel[0];
100
101#define PT_GUID 0x1F
102#define PT_DRIVE1 0x2F
103#define PT_FOLDER 0x31
104#define PT_VALUE 0x32
105
106typedef struct _ID_LIST_FILE
107{
115 char szName[0];
117
118typedef struct _ID_LIST_GUID
119{
125
126typedef struct _ID_LIST_DRIVE
127{
130 char szDriveName[20];
133
134#define EXP_SPECIAL_FOLDER_SIG 0xA0000005
136{
139
140#pragma pack(pop)
141
142static const struct SPECIALFOLDER {
143 unsigned char csidl;
144 const char* name;
145} g_specialfolders[] = {
146 { CSIDL_WINDOWS, "windows" },
147 { CSIDL_SYSTEM, "system" },
148 { 0, NULL}
150
151static unsigned int is_path_separator(unsigned int c)
152{
153 return c == '\\' || c == '/';
154}
155
156static const struct SPECIALFOLDER* get_special_folder(const char *target)
157{
158 char buf[256];
159 strncpy(buf, target, sizeof(buf));
160 buf[sizeof("shell:") - 1] = '\0';
161 if (strcasecmp("shell:", buf))
162 return NULL;
163
164 target += sizeof("shell:") - 1;
165 for (unsigned long i = 0;; ++i)
166 {
167 unsigned long len;
168 const struct SPECIALFOLDER *special = &g_specialfolders[i];
169 if (!special->name)
170 return NULL;
171 len = strlen(special->name);
172 strncpy(buf, target, sizeof(buf));
173 buf[len] = '\0';
174 if (!strcasecmp(special->name, buf) && (is_path_separator(target[len]) || !target[len]))
175 return &g_specialfolders[i];
176 }
177}
178
179int main(int argc, const char *argv[])
180{
181 int i;
182 const char *pszOutputPath = "shortcut.lnk";
183 const char *pszTarget = NULL;
184 const char *pszDescription = NULL;
185 const char *pszWorkingDir = NULL;
186 const char *pszCmdLineArgs = NULL;
187 const char *pszIcon = NULL;
188 char targetpath[260];
189 int IconNr = 0;
190 GUID Guid = CLSID_MyComputer;
191 int bHelp = 0, bMinimized = 0;
192 FILE *pFile;
194 uint16_t uhTmp;
195 uint32_t dwTmp;
196 EXP_SPECIAL_FOLDER CsidlBlock, *pCsidlBlock = NULL;
197
198 for (i = 1; i < argc; ++i)
199 {
200 if (argv[i][0] != '-' && argv[i][0] != '/')
201 pszTarget = argv[i];
202 else if (!strcmp(argv[i] + 1, "h"))
203 bHelp = 1;
204 else if (!strcmp(argv[i] + 1, "o") && i + 1 < argc)
205 pszOutputPath = argv[++i];
206 else if (!strcmp(argv[i] + 1, "d") && i + 1 < argc)
207 pszDescription = argv[++i];
208 else if (!strcmp(argv[i] + 1, "w") && i + 1 < argc)
209 pszWorkingDir = argv[++i];
210 else if (!strcmp(argv[i] + 1, "c") && i + 1 < argc)
211 pszCmdLineArgs = argv[++i];
212 else if (!strcmp(argv[i] + 1, "i") && i + 1 < argc)
213 {
214 pszIcon = argv[++i];
215 if (i + 1 < argc && isdigit(argv[i + 1][0]))
216 IconNr = atoi(argv[++i]);
217 }
218 else if (!strcmp(argv[i] + 1, "m"))
219 bMinimized = 1;
220 else if (!strcmp(argv[i] + 1, "g") && i + 1 < argc)
221 {
222 unsigned Data4Tmp[8], j;
223
224 sscanf(argv[++i], "{%8x-%4hx-%4hx-%2x%2x-%2x%2x%2x%2x%2x%2x}",
225 &Guid.Data1, &Guid.Data2, &Guid.Data3,
226 &Data4Tmp[0], &Data4Tmp[1], &Data4Tmp[2], &Data4Tmp[3],
227 &Data4Tmp[4], &Data4Tmp[5], &Data4Tmp[6], &Data4Tmp[7]);
228 for (j = 0; j < 8; ++j)
229 Guid.Data4[j] = (uint8_t)Data4Tmp[j];
230 }
231 else
232 printf("Invalid option: %s\n", argv[i]);
233 }
234
235 if (!pszTarget || bHelp)
236 {
237 printf("Usage: %s [-o path][-d descr][-w path][-c cmd_line_args][-i icon_path [nr]][-h][-g guid] target\n"
238 "-o path\tSets output path\n"
239 "-d descr\tSets shortcut description\n"
240 "-w path\tSets working directory for executable\n"
241 "-c cmd_line_args\tSets command line arguments passed to program\n"
242 "-i icon_path [nr]\tSets icon file and optionally icon index\n"
243 "-m\tStart minimized\n"
244 "-g guid\tSets GUID to which target path is relative. Default value is MyComputer GUID.\n"
245 "target\tAbsolute or relative to guid specified with -g option path\n", argv[0]);
246 return 0;
247 }
248
249 pFile = fopen(pszOutputPath, "wb");
250 if (!pFile)
251 {
252 printf("Failed to open %s\n", pszOutputPath);
253 return -1;
254 }
255
256 // Header
257 memset(&Header, 0, sizeof(Header));
258 Header.Signature = (uint32_t)'L';
259 Header.Guid = CLSID_ShellLink;
260 Header.Flags = LINK_ID_LIST;
261 if (pszDescription)
262 Header.Flags |= LINK_DESCRIPTION;
263 if (pszWorkingDir)
264 Header.Flags |= LINK_WORKING_DIR;
265 if (pszCmdLineArgs)
266 Header.Flags |= LINK_CMD_LINE_ARGS;
267 if (pszIcon)
268 Header.Flags |= LINK_ICON;
269 Header.IconNr = IconNr;
270 Header.Show = bMinimized ? SW_SHOWMINNOACTIVE : SW_SHOWNORMAL;
271 fwrite(&Header, sizeof(Header), 1, pFile);
272
273 if (Header.Flags & LINK_ID_LIST)
274 {
275 ID_LIST_FILE IdListFile;
276 ID_LIST_GUID IdListGuid;
277 ID_LIST_DRIVE IdListDrive;
278 unsigned cbListSize = sizeof(IdListGuid) + sizeof(uint16_t), cchName;
279 const char *pszName = pszTarget;
280 int index = 1, specialindex = -1;
281 const struct SPECIALFOLDER *special = get_special_folder(pszTarget);
282
283 // ID list
284 // It seems explorer does not accept links without id list. List is relative to desktop.
285
286 if (special)
287 {
288 Header.Flags &= ~LINK_RELATIVE_PATH;
289 CsidlBlock.cbSize = sizeof(CsidlBlock);
291 CsidlBlock.idSpecialFolder = special->csidl;
292 specialindex = 3; // Skip GUID, drive and fake windows/reactos folder
293 sprintf(targetpath, "x:\\reactos\\%s", pszTarget + sizeof("shell:") + strlen(special->name));
294 pszName = pszTarget = targetpath;
295 }
296
297 if (pszName[0] && pszName[0] != ':' && pszName[1] == ':')
298 {
299 ++index;
300 cbListSize += sizeof(IdListDrive);
301 pszName += 2;
302 while (*pszName == '\\' || *pszName == '/')
303 ++pszName;
304 }
305
306 while (*pszName)
307 {
308 cchName = 0;
309 while (pszName[cchName] && pszName[cchName] != '\\' && pszName[cchName] != '/')
310 ++cchName;
311
312 if (cchName != 1 || pszName[0] != '.')
313 cbListSize += sizeof(IdListFile) + 2 * (cchName + 1);
314
315 if (++index == specialindex)
316 {
317 CsidlBlock.cbOffset = cbListSize - sizeof(uint16_t);
318 pCsidlBlock = &CsidlBlock;
319 }
320
321 pszName += cchName;
322 while (*pszName == '\\' || *pszName == '/')
323 ++pszName;
324 }
325
326 uhTmp = cbListSize;
327 fwrite(&uhTmp, sizeof(uhTmp), 1, pFile); // size
328
329 IdListGuid.Size = sizeof(IdListGuid);
330 IdListGuid.Type = PT_GUID;
331 IdListGuid.dummy = 0x50;
332 IdListGuid.guid = Guid;
333 fwrite(&IdListGuid, sizeof(IdListGuid), 1, pFile);
334
335 pszName = pszTarget;
336
337 if (isalpha(pszName[0]) && pszName[1] == ':')
338 {
339 memset(&IdListDrive, 0, sizeof(IdListDrive));
340 IdListDrive.Size = sizeof(IdListDrive);
341 IdListDrive.Type = PT_DRIVE1;
342 sprintf(IdListDrive.szDriveName, "%c:\\", pszName[0]);
343 fwrite(&IdListDrive, sizeof(IdListDrive), 1, pFile);
344 pszName += 2;
345 while(*pszName == '\\' || *pszName == '/')
346 ++pszName;
347 }
348
349 while (*pszName)
350 {
351 cchName = 0;
352 while (pszName[cchName] && pszName[cchName] != '\\' && pszName[cchName] != '/')
353 ++cchName;
354
355 if (cchName != 1 || pszName[0] != '.')
356 {
357 memset(&IdListFile, 0, sizeof(IdListFile));
358 IdListFile.Size = sizeof(IdListFile) + 2 * (cchName + 1);
359 if (!pszName[cchName])
360 IdListFile.Type = PT_VALUE; // File
361 else
362 IdListFile.Type = PT_FOLDER;
363 fwrite(&IdListFile, sizeof(IdListFile), 1, pFile);
364 fwrite(pszName, cchName, 1, pFile);
365 fputc(0, pFile);
366 fwrite(pszName, cchName, 1, pFile);
367 fputc(0, pFile);
368 }
369
370 pszName += cchName;
371 while (*pszName == '\\' || *pszName == '/')
372 ++pszName;
373 }
374
375 uhTmp = 0; // list end
376 fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
377 }
378
379 if (Header.Flags & LINK_DESCRIPTION)
380 {
381 // Description
382 uhTmp = strlen(pszDescription);
383 fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
384 fputs(pszDescription, pFile);
385 }
386
387 if (Header.Flags & LINK_RELATIVE_PATH)
388 {
389 // Relative Path
390 uhTmp = strlen(pszTarget);
391 fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
392 fputs(pszTarget, pFile);
393 }
394
395 if (Header.Flags & LINK_WORKING_DIR)
396 {
397 // Working Dir
398 uhTmp = strlen(pszWorkingDir);
399 fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
400 fputs(pszWorkingDir, pFile);
401 }
402
403 if (Header.Flags & LINK_CMD_LINE_ARGS)
404 {
405 // Command line arguments
406 uhTmp = strlen(pszCmdLineArgs);
407 fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
408 fputs(pszCmdLineArgs, pFile);
409 }
410
411 if (Header.Flags & LINK_ICON)
412 {
413 // Command line arguments
414 uhTmp = strlen(pszIcon);
415 fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
416 fputs(pszIcon, pFile);
417 }
418
419 // Extra stuff
420 if (pCsidlBlock)
421 fwrite(pCsidlBlock, sizeof(*pCsidlBlock), 1, pFile);
422 dwTmp = 0;
423 fwrite(&dwTmp, sizeof(dwTmp), 1, pFile);
424
425 fclose(pFile);
426
427 return 0;
428}
static int argc
Definition: ServiceArgs.c:12
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
#define isalpha(c)
Definition: acclib.h:74
#define isdigit(c)
Definition: acclib.h:68
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
unsigned short int uint16_t
Definition: acefiex.h:54
#define index(s, c)
Definition: various.h:29
#define __int8
Definition: basetyps.h:25
#define __int16
Definition: basetyps.h:22
#define __int32
Definition: basetyps.h:19
Definition: Header.h:9
#define NULL
Definition: types.h:112
UINT32 uint32_t
Definition: types.h:75
int main()
Definition: test.c:6
#define strcasecmp
Definition: fake.h:9
#define printf
Definition: freeldr.h:97
MdFileObject pFile
const GLubyte * c
Definition: glext.h:8905
GLuint index
Definition: glext.h:6031
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLenum GLsizei len
Definition: glext.h:6722
GLenum target
Definition: glext.h:7315
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
_Check_return_opt_ _CRTIMP int __cdecl fputs(_In_z_ const char *_Str, _Inout_ FILE *_File)
_Check_return_ _CRTIMP FILE *__cdecl fopen(_In_z_ const char *_Filename, _In_z_ const char *_Mode)
_Check_return_opt_ _CRTIMP int __cdecl fputc(_In_ int _Ch, _Inout_ FILE *_File)
_Check_return_opt_ _CRTIMP int __cdecl fclose(_Inout_ FILE *_File)
_Check_return_opt_ _CRTIMP size_t __cdecl fwrite(_In_reads_bytes_(_Size *_Count) const void *_Str, _In_ size_t _Size, _In_ size_t _Count, _Inout_ FILE *_File)
_Check_return_ _CRTIMP int __cdecl sscanf(_In_z_ const char *_Src, _In_z_ _Scanf_format_string_ const char *_Format,...)
_Check_return_ int __cdecl atoi(_In_z_ const char *_Str)
#define sprintf(buf, format,...)
Definition: sprintf.c:55
#define argv
Definition: mplay32.c:18
BYTE uint8_t
Definition: msvideo1.c:66
#define uint32_t
Definition: nsiface.idl:61
#define uint16_t
Definition: nsiface.idl:60
#define uint8_t
Definition: nsiface.idl:59
strncpy
Definition: string.h:335
#define memset(x, y, z)
Definition: compat.h:39
DWORD idSpecialFolder
Definition: shlobj.h:2049
const char * name
Definition: mkshelllink.c:144
unsigned char csidl
Definition: mkshelllink.c:143
uint32_t idSpecialFolder
Definition: mkshelllink.c:137
uint32_t dwHighDateTime
Definition: mkshelllink.c:40
uint32_t dwLowDateTime
Definition: mkshelllink.c:39
Definition: scsiwmi.h:51
unsigned char Data4[8]
Definition: scsiwmi.h:55
uint16_t Data2
Definition: mkshelllink.c:33
uint32_t Data1
Definition: mkshelllink.c:32
uint16_t Data3
Definition: mkshelllink.c:34
uint16_t unknown
Definition: mkshelllink.c:131
char szDriveName[20]
Definition: mkshelllink.c:130
uint16_t Size
Definition: mkshelllink.c:128
char szName[0]
Definition: mkshelllink.c:115
uint16_t uFileDate
Definition: mkshelllink.c:112
uint32_t dwFileSize
Definition: mkshelllink.c:111
uint8_t Type
Definition: mkshelllink.c:109
uint16_t uFileTime
Definition: mkshelllink.c:113
uint8_t dummy
Definition: mkshelllink.c:110
uint16_t Size
Definition: mkshelllink.c:108
uint16_t uFileAttribs
Definition: mkshelllink.c:114
uint8_t Type
Definition: mkshelllink.c:121
uint8_t dummy
Definition: mkshelllink.c:122
uint16_t Size
Definition: mkshelllink.c:120
uint32_t Signature
Definition: mkshelllink.c:65
uint32_t Flags
Definition: mkshelllink.c:67
uint32_t Attributes
Definition: mkshelllink.c:68
uint32_t IconNr
Definition: mkshelllink.c:73
FILETIME ModificationTime
Definition: mkshelllink.c:70
uint32_t Unknown2
Definition: mkshelllink.c:77
uint32_t Hotkey
Definition: mkshelllink.c:75
FILETIME CreationTime
Definition: mkshelllink.c:69
uint32_t FileSize
Definition: mkshelllink.c:72
uint32_t Show
Definition: mkshelllink.c:74
FILETIME LastAccessTime
Definition: mkshelllink.c:71
uint32_t Unknown
Definition: mkshelllink.c:76
uint32_t DataOffset
Definition: mkshelllink.c:83
uint32_t LocalBasePathnameOffset
Definition: mkshelllink.c:86
uint32_t LocalVolumeInfoOffset
Definition: mkshelllink.c:85
uint32_t RemainingPathnameOffset
Definition: mkshelllink.c:88
uint32_t NetworkVolumeInfoOffset
Definition: mkshelllink.c:87
_Must_inspect_result_ _In_ WDFOBJECT _In_ CONST GUID * Guid
Definition: wdfobject.h:762
_In_ PSID _Out_writes_to_opt_ cchName LPSTR _Inout_ LPDWORD cchName
Definition: winbase.h:2798