ReactOS  0.4.15-dev-1070-ge1a01de
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
16 typedef unsigned __int8 uint8_t;
17 typedef unsigned __int16 uint16_t;
18 typedef unsigned __int32 uint32_t;
19 #endif
20 
21 #define SW_SHOWNORMAL 1
22 #define SW_SHOWMINNOACTIVE 7
23 
24 typedef struct _GUID
25 {
30 } GUID;
31 
32 typedef struct _FILETIME {
36 
37 #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 } }
38 DEFINE_GUID2(CLSID_ShellLink,0x00021401L,0,0,0xC0,0,0,0,0,0,0,0x46);
39 DEFINE_GUID2(CLSID_MyComputer,0x20D04FE0,0x3AEA,0x1069,0xA2,0xD8,0x08,0x00,0x2B,0x30,0x30,0x9D);
40 
41 #define LINK_ID_LIST 0x01
42 #define LINK_FILE 0x02
43 #define LINK_DESCRIPTION 0x04
44 #define LINK_RELATIVE_PATH 0x08
45 #define LINK_WORKING_DIR 0x10
46 #define LINK_CMD_LINE_ARGS 0x20
47 #define LINK_ICON 0x40
48 #define LINK_UNICODE 0x80
49 
50 #define LOCATOR_LOCAL 0x1
51 #define LOCATOR_NETWORK 0x2
52 
53 #pragma pack(push, 1)
54 
55 /* Specification: http://ithreats.files.wordpress.com/2009/05/lnk_the_windows_shortcut_file_format.pdf */
56 
57 typedef struct _LNK_HEADER
58 {
72 } LNK_HEADER;
73 
74 typedef struct _LNK_LOCATOR_INFO
75 {
83  char Data[0];
85 
86 typedef struct _LNK_LOCAL_VOLUME_INFO
87 {
89  uint32_t VolumeType; /* See GetDriveType */
92  char VolumeLabel[0];
94 
95 #define PT_GUID 0x1F
96 #define PT_DRIVE1 0x2F
97 #define PT_FOLDER 0x31
98 #define PT_VALUE 0x32
99 
100 typedef struct _ID_LIST_FILE
101 {
109  char szName[0];
110 } ID_LIST_FILE;
111 
112 typedef struct _ID_LIST_GUID
113 {
118 } ID_LIST_GUID;
119 
120 typedef struct _ID_LIST_DRIVE
121 {
124  char szDriveName[20];
126 } ID_LIST_DRIVE;
127 
128 #pragma pack(pop)
129 
130 int main(int argc, const char *argv[])
131 {
132  int i;
133  const char *pszOutputPath = "shortcut.lnk";
134  const char *pszTarget = NULL;
135  const char *pszDescription = "Description";
136  const char *pszWorkingDir = NULL;
137  const char *pszCmdLineArgs = NULL;
138  const char *pszIcon = NULL;
139  int IconNr = 0;
140  GUID Guid = CLSID_MyComputer;
141  int bHelp = 0, bMinimized = 0;
142  FILE *pFile;
144  uint16_t uhTmp;
145  uint32_t dwTmp;
146 
147  for (i = 1; i < argc; ++i)
148  {
149  if (argv[i][0] != '-' && argv[i][0] != '/')
150  pszTarget = argv[i];
151  else if (!strcmp(argv[i] + 1, "h"))
152  bHelp = 1;
153  else if (!strcmp(argv[i] + 1, "o") && i + 1 < argc)
154  pszOutputPath = argv[++i];
155  else if (!strcmp(argv[i] + 1, "d") && i + 1 < argc)
156  pszDescription = argv[++i];
157  else if (!strcmp(argv[i] + 1, "w") && i + 1 < argc)
158  pszWorkingDir = argv[++i];
159  else if (!strcmp(argv[i] + 1, "c") && i + 1 < argc)
160  pszCmdLineArgs = argv[++i];
161  else if (!strcmp(argv[i] + 1, "i") && i + 1 < argc)
162  {
163  pszIcon = argv[++i];
164  if (i + 1 < argc && isdigit(argv[i + 1][0]))
165  IconNr = atoi(argv[++i]);
166  }
167  else if (!strcmp(argv[i] + 1, "m"))
168  bMinimized = 1;
169  else if (!strcmp(argv[i] + 1, "g") && i + 1 < argc)
170  {
171  unsigned Data4Tmp[8], j;
172 
173  sscanf(argv[++i], "{%8x-%4hx-%4hx-%2x%2x-%2x%2x%2x%2x%2x%2x}",
174  &Guid.Data1, &Guid.Data2, &Guid.Data3,
175  &Data4Tmp[0], &Data4Tmp[1], &Data4Tmp[2], &Data4Tmp[3],
176  &Data4Tmp[4], &Data4Tmp[5], &Data4Tmp[6], &Data4Tmp[7]);
177  for (j = 0; j < 8; ++j)
178  Guid.Data4[j] = (uint8_t)Data4Tmp[j];
179  }
180  else
181  printf("Invalid option: %s\n", argv[i]);
182  }
183 
184  if (!pszTarget || bHelp)
185  {
186  printf("Usage: %s [-o path][-d descr][-w path][-c cmd_line_args][-i icon_path [nr]][-h][-g guid] target\n"
187  "-o path\tSets output path\n"
188  "-d descr\tSets shortcut description\n"
189  "-w path\tSets working directory for executable\n"
190  "-c cmd_line_args\tSets command line arguments passed to program\n"
191  "-i icon_path [nr]\tSets icon file and optionally icon index\n"
192  "-m\tStart minimized\n"
193  "-g guid\tSets GUID to which target path is relative. Default value is MyComputer GUID.\n"
194  "target\tAbsolute or relative to guid specified with -g option path\n", argv[0]);
195  return 0;
196  }
197 
198  pFile = fopen(pszOutputPath, "wb");
199  if (!pFile)
200  {
201  printf("Failed to open %s\n", pszOutputPath);
202  return -1;
203  }
204 
205  // Header
206  memset(&Header, 0, sizeof(Header));
207  Header.Signature = (uint32_t)'L';
208  Header.Guid = CLSID_ShellLink;
209  Header.Flags = LINK_ID_LIST;
210  if (pszDescription)
211  Header.Flags |= LINK_DESCRIPTION;
212  if (pszWorkingDir)
213  Header.Flags |= LINK_WORKING_DIR;
214  if (pszCmdLineArgs)
215  Header.Flags |= LINK_CMD_LINE_ARGS;
216  if (pszIcon)
217  Header.Flags |= LINK_ICON;
218  Header.IconNr = IconNr;
219  Header.Show = bMinimized ? SW_SHOWMINNOACTIVE : SW_SHOWNORMAL;
220  fwrite(&Header, sizeof(Header), 1, pFile);
221 
222  if (Header.Flags & LINK_ID_LIST)
223  {
224  ID_LIST_FILE IdListFile;
225  ID_LIST_GUID IdListGuid;
226  ID_LIST_DRIVE IdListDrive;
227  unsigned cbListSize = sizeof(IdListGuid) + sizeof(uint16_t), cchName;
228  const char *pszName = pszTarget;
229 
230  // ID list
231  // It seems explorer does not accept links without id list. List is relative to desktop.
232 
233  pszName = pszTarget;
234 
235  if (pszName[0] && pszName[1] == ':')
236  {
237  cbListSize += sizeof(IdListDrive);
238  pszName += 2;
239  while (*pszName == '\\' || *pszName == '/')
240  ++pszName;
241  }
242 
243  while (*pszName)
244  {
245  cchName = 0;
246  while (pszName[cchName] && pszName[cchName] != '\\' && pszName[cchName] != '/')
247  ++cchName;
248 
249  if (cchName != 1 || pszName[0] != '.')
250  cbListSize += sizeof(IdListFile) + 2 * (cchName + 1);
251 
252  pszName += cchName;
253  while (*pszName == '\\' || *pszName == '/')
254  ++pszName;
255  }
256 
257  uhTmp = cbListSize;
258  fwrite(&uhTmp, sizeof(uhTmp), 1, pFile); // size
259 
260  IdListGuid.Size = sizeof(IdListGuid);
261  IdListGuid.Type = PT_GUID;
262  IdListGuid.dummy = 0x50;
263  IdListGuid.guid = Guid;
264  fwrite(&IdListGuid, sizeof(IdListGuid), 1, pFile);
265 
266  pszName = pszTarget;
267 
268  if (isalpha(pszName[0]) && pszName[1] == ':')
269  {
270  memset(&IdListDrive, 0, sizeof(IdListDrive));
271  IdListDrive.Size = sizeof(IdListDrive);
272  IdListDrive.Type = PT_DRIVE1;
273  sprintf(IdListDrive.szDriveName, "%c:\\", pszName[0]);
274  fwrite(&IdListDrive, sizeof(IdListDrive), 1, pFile);
275  pszName += 2;
276  while(*pszName == '\\' || *pszName == '/')
277  ++pszName;
278  }
279 
280  while (*pszName)
281  {
282  cchName = 0;
283  while (pszName[cchName] && pszName[cchName] != '\\' && pszName[cchName] != '/')
284  ++cchName;
285 
286  if (cchName != 1 || pszName[0] != '.')
287  {
288  memset(&IdListFile, 0, sizeof(IdListFile));
289  IdListFile.Size = sizeof(IdListFile) + 2 * (cchName + 1);
290  if (!pszName[cchName])
291  IdListFile.Type = PT_VALUE; // File
292  else
293  IdListFile.Type = PT_FOLDER;
294  fwrite(&IdListFile, sizeof(IdListFile), 1, pFile);
295  fwrite(pszName, cchName, 1, pFile);
296  fputc(0, pFile);
297  fwrite(pszName, cchName, 1, pFile);
298  fputc(0, pFile);
299  }
300 
301  pszName += cchName;
302  while (*pszName == '\\' || *pszName == '/')
303  ++pszName;
304  }
305 
306  uhTmp = 0; // list end
307  fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
308  }
309 
310  if (Header.Flags & LINK_DESCRIPTION)
311  {
312  // Dscription
313  uhTmp = strlen(pszDescription);
314  fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
315  fputs(pszDescription, pFile);
316  }
317 
318  if (Header.Flags & LINK_RELATIVE_PATH)
319  {
320  // Relative Path
321  uhTmp = strlen(pszTarget);
322  fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
323  fputs(pszTarget, pFile);
324  }
325 
326  if (Header.Flags & LINK_WORKING_DIR)
327  {
328  // Working Dir
329  uhTmp = strlen(pszWorkingDir);
330  fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
331  fputs(pszWorkingDir, pFile);
332  }
333 
334  if (Header.Flags & LINK_CMD_LINE_ARGS)
335  {
336  // Command line arguments
337  uhTmp = strlen(pszCmdLineArgs);
338  fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
339  fputs(pszCmdLineArgs, pFile);
340  }
341 
342  if (Header.Flags & LINK_ICON)
343  {
344  // Command line arguments
345  uhTmp = strlen(pszIcon);
346  fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
347  fputs(pszIcon, pFile);
348  }
349 
350  // Extra stuff
351  dwTmp = 0;
352  fwrite(&dwTmp, sizeof(dwTmp), 1, pFile);
353 
354  fclose(pFile);
355 
356  return 0;
357 }
uint16_t uFileDate
Definition: mkshelllink.c:106
static int argc
Definition: ServiceArgs.c:12
_Check_return_opt_ _CRTIMP int __cdecl fputc(_In_ int _Ch, _Inout_ FILE *_File)
uint32_t Show
Definition: mkshelllink.c:68
uint32_t IconNr
Definition: mkshelllink.c:67
uint32_t dwFileSize
Definition: mkshelllink.c:105
Definition: scsiwmi.h:51
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
uint32_t Data1
Definition: mkshelllink.c:26
char szName[0]
Definition: mkshelllink.c:109
#define isalpha(c)
Definition: acclib.h:74
uint32_t Flags
Definition: mkshelllink.c:61
unsigned short int uint16_t
Definition: acefiex.h:54
#define uint16_t
Definition: nsiface.idl:60
FILETIME CreationTime
Definition: mkshelllink.c:63
_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)
#define argv
Definition: mplay32.c:18
uint32_t FileSize
Definition: mkshelllink.c:66
#define sprintf(buf, format,...)
Definition: sprintf.c:55
_In_ PSID _Out_writes_to_opt_ cchName LPSTR _Inout_ LPDWORD cchName
Definition: winbase.h:2729
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
Definition: Header.h:8
uint16_t uFileTime
Definition: mkshelllink.c:107
uint32_t LocalBasePathnameOffset
Definition: mkshelllink.c:80
uint32_t Hotkey
Definition: mkshelllink.c:69
uint16_t Data3
Definition: mkshelllink.c:28
static GUID * Guid
Definition: apphelp.c:93
smooth NULL
Definition: ftsmooth.c:416
uint16_t Size
Definition: mkshelllink.c:114
_Check_return_ _CRTIMP int __cdecl sscanf(_In_z_ const char *_Src, _In_z_ _Scanf_format_string_ const char *_Format,...)
uint32_t dwHighDateTime
Definition: mkshelllink.c:34
#define isdigit(c)
Definition: acclib.h:68
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
uint32_t LocalVolumeInfoOffset
Definition: mkshelllink.c:79
uint16_t unknown
Definition: mkshelllink.c:125
uint8_t dummy
Definition: mkshelllink.c:116
FILETIME LastAccessTime
Definition: mkshelllink.c:65
uint32_t Attributes
Definition: mkshelllink.c:62
uint32_t dwLowDateTime
Definition: mkshelllink.c:33
uint8_t Type
Definition: mkshelllink.c:115
uint16_t Size
Definition: mkshelllink.c:122
_Check_return_opt_ _CRTIMP int __cdecl fclose(_Inout_ FILE *_File)
_Check_return_ _CRTIMP FILE *__cdecl fopen(_In_z_ const char *_Filename, _In_z_ const char *_Mode)
BYTE uint8_t
Definition: msvideo1.c:66
uint32_t Unknown
Definition: mkshelllink.c:70
#define uint8_t
Definition: nsiface.idl:59
#define __int32
Definition: basetyps.h:19
uint16_t uFileAttribs
Definition: mkshelllink.c:108
UINT32 uint32_t
Definition: types.h:75
unsigned char Data4[8]
Definition: scsiwmi.h:55
_Check_return_ int __cdecl atoi(_In_z_ const char *_Str)
#define __int8
Definition: basetyps.h:25
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
uint32_t Signature
Definition: mkshelllink.c:59
uint16_t Data2
Definition: mkshelllink.c:27
uint16_t Size
Definition: mkshelllink.c:102
uint32_t RemainingPathnameOffset
Definition: mkshelllink.c:82
uint8_t dummy
Definition: mkshelllink.c:104
uint32_t DataOffset
Definition: mkshelllink.c:77
#define uint32_t
Definition: nsiface.idl:61
#define memset(x, y, z)
Definition: compat.h:39
uint8_t Type
Definition: mkshelllink.c:103
uint32_t NetworkVolumeInfoOffset
Definition: mkshelllink.c:81
_Check_return_opt_ _CRTIMP int __cdecl fputs(_In_z_ const char *_Str, _Inout_ FILE *_File)
char szDriveName[20]
Definition: mkshelllink.c:124
#define __int16
Definition: basetyps.h:22
#define printf
Definition: config.h:203
FILETIME ModificationTime
Definition: mkshelllink.c:64
uint32_t Unknown2
Definition: mkshelllink.c:71