Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenmkshelllink.c
Go to the documentation of this file.
00001 /* COPYRIGHT: See COPYING in the top level directory 00002 * PROJECT: ReactOS Shell Link maker 00003 * FILE: tools/mkshelllink/mkshelllink.c 00004 * PURPOSE: Shell Link maker 00005 * PROGRAMMER: Rafal Harabien 00006 */ 00007 00008 #include <stdio.h> 00009 #include <string.h> 00010 #include <ctype.h> 00011 #ifndef _MSC_VER 00012 #include <stdint.h> 00013 #else 00014 typedef unsigned __int8 uint8_t; 00015 typedef unsigned __int16 uint16_t; 00016 typedef unsigned __int32 uint32_t; 00017 #endif 00018 00019 #define SW_SHOWNORMAL 1 00020 #define SW_SHOWMINNOACTIVE 7 00021 00022 typedef struct _GUID { 00023 uint32_t Data1; 00024 uint16_t Data2; 00025 uint16_t Data3; 00026 uint8_t Data4[8]; 00027 } GUID; 00028 00029 typedef struct _FILETIME { 00030 uint32_t dwLowDateTime; 00031 uint32_t dwHighDateTime; 00032 } FILETIME, *PFILETIME; 00033 00034 #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 } } 00035 DEFINE_GUID2(CLSID_ShellLink,0x00021401L,0,0,0xC0,0,0,0,0,0,0,0x46); 00036 DEFINE_GUID2(CLSID_MyComputer,0x20D04FE0,0x3AEA,0x1069,0xA2,0xD8,0x08,0x00,0x2B,0x30,0x30,0x9D); 00037 00038 #define LINK_ID_LIST 0x01 00039 #define LINK_FILE 0x02 00040 #define LINK_DESCRIPTION 0x04 00041 #define LINK_RELATIVE_PATH 0x08 00042 #define LINK_WORKING_DIR 0x10 00043 #define LINK_CMD_LINE_ARGS 0x20 00044 #define LINK_ICON 0x40 00045 #define LINK_UNICODE 0x80 00046 00047 #define LOCATOR_LOCAL 0x1 00048 #define LOCATOR_NETWORK 0x2 00049 00050 #pragma pack(push, 1) 00051 00052 /* Specification: http://ithreats.files.wordpress.com/2009/05/lnk_the_windows_shortcut_file_format.pdf */ 00053 00054 typedef struct _LNK_HEADER 00055 { 00056 uint32_t Signature; 00057 GUID Guid; 00058 uint32_t Flags; 00059 uint32_t Attributes; 00060 FILETIME CreationTime; 00061 FILETIME ModificationTime; 00062 FILETIME LastAccessTime; 00063 uint32_t FileSize; 00064 uint32_t IconNr; 00065 uint32_t Show; 00066 uint32_t Hotkey; 00067 uint32_t Unknown; 00068 uint32_t Unknown2; 00069 } LNK_HEADER; 00070 00071 typedef struct _LNK_LOCATOR_INFO 00072 { 00073 uint32_t Size; 00074 uint32_t DataOffset; 00075 uint32_t Flags; 00076 uint32_t LocalVolumeInfoOffset; 00077 uint32_t LocalBasePathnameOffset; 00078 uint32_t NetworkVolumeInfoOffset; 00079 uint32_t RemainingPathnameOffset; 00080 char Data[0]; 00081 } LNK_LOCATOR_INFO; 00082 00083 typedef struct _LNK_LOCAL_VOLUME_INFO 00084 { 00085 uint32_t Size; 00086 uint32_t VolumeType; /* See GetDriveType */ 00087 uint32_t SerialNumber; 00088 uint32_t VolumeNameOffset; 00089 char VolumeLabel[0]; 00090 } LNK_LOCAL_VOLUME_INFO; 00091 00092 #define PT_GUID 0x1F 00093 #define PT_DRIVE1 0x2F 00094 #define PT_FOLDER 0x31 00095 #define PT_VALUE 0x32 00096 00097 typedef struct _ID_LIST_FILE 00098 { 00099 uint16_t Size; 00100 uint8_t Type; 00101 uint8_t dummy; 00102 uint32_t dwFileSize; 00103 uint16_t uFileDate; 00104 uint16_t uFileTime; 00105 uint16_t uFileAttribs; 00106 char szName[0]; 00107 } ID_LIST_FILE; 00108 00109 typedef struct _ID_LIST_GUID 00110 { 00111 uint16_t Size; 00112 uint8_t Type; 00113 uint8_t dummy; 00114 GUID guid; 00115 } ID_LIST_GUID; 00116 00117 typedef struct _ID_LIST_DRIVE 00118 { 00119 uint16_t Size; 00120 uint8_t Type; 00121 char szDriveName[20]; 00122 uint16_t unknown; 00123 } ID_LIST_DRIVE; 00124 00125 #pragma pack(pop) 00126 00127 int main(int argc, const char *argv[]) 00128 { 00129 unsigned i; 00130 const char *pszOutputPath = "shortcut.lnk"; 00131 const char *pszTarget = NULL; 00132 const char *pszDescription = "Description"; 00133 const char *pszWorkingDir = NULL; 00134 const char *pszCmdLineArgs = NULL; 00135 const char *pszIcon = NULL; 00136 int IconNr = 0; 00137 GUID Guid = CLSID_MyComputer; 00138 int bHelp = 0, bMinimized = 0; 00139 FILE *pFile; 00140 LNK_HEADER Header; 00141 uint16_t uhTmp; 00142 uint32_t dwTmp; 00143 00144 for (i = 1; i < argc; ++i) 00145 { 00146 if (argv[i][0] != '-' && argv[i][0] != '/') 00147 pszTarget = argv[i]; 00148 else if (!strcmp(argv[i] + 1, "h")) 00149 bHelp = 1; 00150 else if (!strcmp(argv[i] + 1, "o") && i + 1 < argc) 00151 pszOutputPath = argv[++i]; 00152 else if (!strcmp(argv[i] + 1, "d") && i + 1 < argc) 00153 pszDescription = argv[++i]; 00154 else if (!strcmp(argv[i] + 1, "w") && i + 1 < argc) 00155 pszWorkingDir = argv[++i]; 00156 else if (!strcmp(argv[i] + 1, "c") && i + 1 < argc) 00157 pszCmdLineArgs = argv[++i]; 00158 else if (!strcmp(argv[i] + 1, "i") && i + 1 < argc) 00159 { 00160 pszIcon = argv[++i]; 00161 if (i + 1 < argc && isdigit(argv[i + 1][0])) 00162 IconNr = atoi(argv[++i]); 00163 } 00164 else if (!strcmp(argv[i] + 1, "m")) 00165 bMinimized = 1; 00166 else if (!strcmp(argv[i] + 1, "g") && i + 1 < argc) 00167 { 00168 unsigned Data4Tmp[8], j; 00169 00170 sscanf(argv[++i], "{%8lx-%4hx-%4hx-%2x%2x-%2x%2x%2x%2x%2x%2x}", 00171 &Guid.Data1, &Guid.Data2, &Guid.Data3, 00172 &Data4Tmp[0], &Data4Tmp[1], &Data4Tmp[2], &Data4Tmp[3], 00173 &Data4Tmp[4], &Data4Tmp[5], &Data4Tmp[6], &Data4Tmp[7]); 00174 for (j = 0; j < 8; ++j) 00175 Guid.Data4[j] = (uint8_t)Data4Tmp[j]; 00176 } 00177 else 00178 printf("Invalid option: %s\n", argv[i]); 00179 } 00180 00181 if (!pszTarget || bHelp) 00182 { 00183 printf("Usage: %s [-o path][-d descr][-w path][-c cmd_line_args][-i icon_path [nr]][-h][-g guid] target\n" 00184 "-o path\tSets output path\n" 00185 "-d descr\tSets shortcut description\n" 00186 "-w path\tSets working directory for executable\n" 00187 "-c cmd_line_args\tSets command line arguments passed to program\n" 00188 "-i icon_path [nr]\tSets icon file and optionally icon index\n" 00189 "-m\tStart minimized\n" 00190 "-g guid\tSets GUID to which target path is relative. Default value is MyComputer GUID.\n" 00191 "target\tAbsolute or relative to guid specified with -g option path\n", argv[0]); 00192 return 0; 00193 } 00194 00195 pFile = fopen(pszOutputPath, "wb"); 00196 if (!pFile) 00197 { 00198 printf("Failed to open %s\n", pszOutputPath); 00199 return -1; 00200 } 00201 00202 // Header 00203 memset(&Header, 0, sizeof(Header)); 00204 Header.Signature = (uint32_t)'L'; 00205 Header.Guid = CLSID_ShellLink; 00206 Header.Flags = LINK_ID_LIST; 00207 if (pszDescription) 00208 Header.Flags |= LINK_DESCRIPTION; 00209 if (pszWorkingDir) 00210 Header.Flags |= LINK_WORKING_DIR; 00211 if (pszCmdLineArgs) 00212 Header.Flags |= LINK_CMD_LINE_ARGS; 00213 if (pszIcon) 00214 Header.Flags |= LINK_ICON; 00215 Header.IconNr = IconNr; 00216 Header.Show = bMinimized ? SW_SHOWMINNOACTIVE : SW_SHOWNORMAL; 00217 fwrite(&Header, sizeof(Header), 1, pFile); 00218 00219 if (Header.Flags & LINK_ID_LIST) 00220 { 00221 ID_LIST_FILE IdListFile; 00222 ID_LIST_GUID IdListGuid; 00223 ID_LIST_DRIVE IdListDrive; 00224 unsigned cbListSize = sizeof(IdListGuid) + sizeof(uint16_t), cchName; 00225 const char *pszName = pszTarget; 00226 00227 // ID list 00228 // It seems explorer does not accept links without id list. List is relative to desktop. 00229 00230 pszName = pszTarget; 00231 00232 if (pszName[0] && pszName[1] == ':') 00233 { 00234 cbListSize += sizeof(IdListDrive); 00235 pszName += 2; 00236 while (*pszName == '\\' || *pszName == '/') 00237 ++pszName; 00238 } 00239 00240 while (*pszName) 00241 { 00242 cchName = 0; 00243 while (pszName[cchName] && pszName[cchName] != '\\' && pszName[cchName] != '/') 00244 ++cchName; 00245 00246 if (cchName != 1 || pszName[0] != '.') 00247 cbListSize += sizeof(IdListFile) + 2 * (cchName + 1); 00248 00249 pszName += cchName; 00250 while (*pszName == '\\' || *pszName == '/') 00251 ++pszName; 00252 } 00253 00254 uhTmp = cbListSize; 00255 fwrite(&uhTmp, sizeof(uhTmp), 1, pFile); // size 00256 00257 IdListGuid.Size = sizeof(IdListGuid); 00258 IdListGuid.Type = PT_GUID; 00259 IdListGuid.dummy = 0x50; 00260 IdListGuid.guid = Guid; 00261 fwrite(&IdListGuid, sizeof(IdListGuid), 1, pFile); 00262 00263 pszName = pszTarget; 00264 00265 if (isalpha(pszName[0]) && pszName[1] == ':') 00266 { 00267 memset(&IdListDrive, 0, sizeof(IdListDrive)); 00268 IdListDrive.Size = sizeof(IdListDrive); 00269 IdListDrive.Type = PT_DRIVE1; 00270 sprintf(IdListDrive.szDriveName, "%c:\\", pszName[0]); 00271 fwrite(&IdListDrive, sizeof(IdListDrive), 1, pFile); 00272 pszName += 2; 00273 while(*pszName == '\\' || *pszName == '/') 00274 ++pszName; 00275 } 00276 00277 while (*pszName) 00278 { 00279 cchName = 0; 00280 while (pszName[cchName] && pszName[cchName] != '\\' && pszName[cchName] != '/') 00281 ++cchName; 00282 00283 if (cchName != 1 || pszName[0] != '.') 00284 { 00285 memset(&IdListFile, 0, sizeof(IdListFile)); 00286 IdListFile.Size = sizeof(IdListFile) + 2 * (cchName + 1); 00287 if (!pszName[cchName]) 00288 IdListFile.Type = PT_VALUE; // File 00289 else 00290 IdListFile.Type = PT_FOLDER; 00291 fwrite(&IdListFile, sizeof(IdListFile), 1, pFile); 00292 fwrite(pszName, cchName, 1, pFile); 00293 fputc(0, pFile); 00294 fwrite(pszName, cchName, 1, pFile); 00295 fputc(0, pFile); 00296 } 00297 00298 pszName += cchName; 00299 while (*pszName == '\\' || *pszName == '/') 00300 ++pszName; 00301 } 00302 00303 uhTmp = 0; // list end 00304 fwrite(&uhTmp, sizeof(uhTmp), 1, pFile); 00305 } 00306 00307 if (Header.Flags & LINK_DESCRIPTION) 00308 { 00309 // Dscription 00310 uhTmp = strlen(pszDescription); 00311 fwrite(&uhTmp, sizeof(uhTmp), 1, pFile); 00312 fputs(pszDescription, pFile); 00313 } 00314 00315 if (Header.Flags & LINK_RELATIVE_PATH) 00316 { 00317 // Relative Path 00318 uhTmp = strlen(pszTarget); 00319 fwrite(&uhTmp, sizeof(uhTmp), 1, pFile); 00320 fputs(pszTarget, pFile); 00321 } 00322 00323 if (Header.Flags & LINK_WORKING_DIR) 00324 { 00325 // Working Dir 00326 uhTmp = strlen(pszWorkingDir); 00327 fwrite(&uhTmp, sizeof(uhTmp), 1, pFile); 00328 fputs(pszWorkingDir, pFile); 00329 } 00330 00331 if (Header.Flags & LINK_CMD_LINE_ARGS) 00332 { 00333 // Command line arguments 00334 uhTmp = strlen(pszCmdLineArgs); 00335 fwrite(&uhTmp, sizeof(uhTmp), 1, pFile); 00336 fputs(pszCmdLineArgs, pFile); 00337 } 00338 00339 if (Header.Flags & LINK_ICON) 00340 { 00341 // Command line arguments 00342 uhTmp = strlen(pszIcon); 00343 fwrite(&uhTmp, sizeof(uhTmp), 1, pFile); 00344 fputs(pszIcon, pFile); 00345 } 00346 00347 // Extra stuff 00348 dwTmp = 0; 00349 fwrite(&dwTmp, sizeof(dwTmp), 1, pFile); 00350 00351 fclose(pFile); 00352 00353 return 0; 00354 } Generated on Sun May 27 2012 04:37:46 for ReactOS by
1.7.6.1
|