+++ /dev/null
-/* COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS Shell Link maker
- * FILE: tools/mkshelllink/mkshelllink.c
- * PURPOSE: Shell Link maker
- * PROGRAMMER: Rafal Harabien
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-
-#ifndef _MSC_VER
-#include <stdint.h>
-#else
-typedef unsigned __int8 uint8_t;
-typedef unsigned __int16 uint16_t;
-typedef unsigned __int32 uint32_t;
-#endif
-
-#define SW_SHOWNORMAL 1
-#define SW_SHOWMINNOACTIVE 7
-
-typedef struct _GUID
-{
- uint32_t Data1;
- uint16_t Data2;
- uint16_t Data3;
- uint8_t Data4[8];
-} GUID;
-
-typedef struct _FILETIME {
- uint32_t dwLowDateTime;
- uint32_t dwHighDateTime;
-} FILETIME, *PFILETIME;
-
-#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 } }
-DEFINE_GUID2(CLSID_ShellLink,0x00021401L,0,0,0xC0,0,0,0,0,0,0,0x46);
-DEFINE_GUID2(CLSID_MyComputer,0x20D04FE0,0x3AEA,0x1069,0xA2,0xD8,0x08,0x00,0x2B,0x30,0x30,0x9D);
-
-#define LINK_ID_LIST 0x01
-#define LINK_FILE 0x02
-#define LINK_DESCRIPTION 0x04
-#define LINK_RELATIVE_PATH 0x08
-#define LINK_WORKING_DIR 0x10
-#define LINK_CMD_LINE_ARGS 0x20
-#define LINK_ICON 0x40
-#define LINK_UNICODE 0x80
-
-#define LOCATOR_LOCAL 0x1
-#define LOCATOR_NETWORK 0x2
-
-#pragma pack(push, 1)
-
-/* Specification: http://ithreats.files.wordpress.com/2009/05/lnk_the_windows_shortcut_file_format.pdf */
-
-typedef struct _LNK_HEADER
-{
- uint32_t Signature;
- GUID Guid;
- uint32_t Flags;
- uint32_t Attributes;
- FILETIME CreationTime;
- FILETIME ModificationTime;
- FILETIME LastAccessTime;
- uint32_t FileSize;
- uint32_t IconNr;
- uint32_t Show;
- uint32_t Hotkey;
- uint32_t Unknown;
- uint32_t Unknown2;
-} LNK_HEADER;
-
-typedef struct _LNK_LOCATOR_INFO
-{
- uint32_t Size;
- uint32_t DataOffset;
- uint32_t Flags;
- uint32_t LocalVolumeInfoOffset;
- uint32_t LocalBasePathnameOffset;
- uint32_t NetworkVolumeInfoOffset;
- uint32_t RemainingPathnameOffset;
- char Data[0];
-} LNK_LOCATOR_INFO;
-
-typedef struct _LNK_LOCAL_VOLUME_INFO
-{
- uint32_t Size;
- uint32_t VolumeType; /* See GetDriveType */
- uint32_t SerialNumber;
- uint32_t VolumeNameOffset;
- char VolumeLabel[0];
-} LNK_LOCAL_VOLUME_INFO;
-
-#define PT_GUID 0x1F
-#define PT_DRIVE1 0x2F
-#define PT_FOLDER 0x31
-#define PT_VALUE 0x32
-
-typedef struct _ID_LIST_FILE
-{
- uint16_t Size;
- uint8_t Type;
- uint8_t dummy;
- uint32_t dwFileSize;
- uint16_t uFileDate;
- uint16_t uFileTime;
- uint16_t uFileAttribs;
- char szName[0];
-} ID_LIST_FILE;
-
-typedef struct _ID_LIST_GUID
-{
- uint16_t Size;
- uint8_t Type;
- uint8_t dummy;
- GUID guid;
-} ID_LIST_GUID;
-
-typedef struct _ID_LIST_DRIVE
-{
- uint16_t Size;
- uint8_t Type;
- char szDriveName[20];
- uint16_t unknown;
-} ID_LIST_DRIVE;
-
-#pragma pack(pop)
-
-int main(int argc, const char *argv[])
-{
- unsigned i;
- const char *pszOutputPath = "shortcut.lnk";
- const char *pszTarget = NULL;
- const char *pszDescription = "Description";
- const char *pszWorkingDir = NULL;
- const char *pszCmdLineArgs = NULL;
- const char *pszIcon = NULL;
- int IconNr = 0;
- GUID Guid = CLSID_MyComputer;
- int bHelp = 0, bMinimized = 0;
- FILE *pFile;
- LNK_HEADER Header;
- uint16_t uhTmp;
- uint32_t dwTmp;
-
- for (i = 1; i < argc; ++i)
- {
- if (argv[i][0] != '-' && argv[i][0] != '/')
- pszTarget = argv[i];
- else if (!strcmp(argv[i] + 1, "h"))
- bHelp = 1;
- else if (!strcmp(argv[i] + 1, "o") && i + 1 < argc)
- pszOutputPath = argv[++i];
- else if (!strcmp(argv[i] + 1, "d") && i + 1 < argc)
- pszDescription = argv[++i];
- else if (!strcmp(argv[i] + 1, "w") && i + 1 < argc)
- pszWorkingDir = argv[++i];
- else if (!strcmp(argv[i] + 1, "c") && i + 1 < argc)
- pszCmdLineArgs = argv[++i];
- else if (!strcmp(argv[i] + 1, "i") && i + 1 < argc)
- {
- pszIcon = argv[++i];
- if (i + 1 < argc && isdigit(argv[i + 1][0]))
- IconNr = atoi(argv[++i]);
- }
- else if (!strcmp(argv[i] + 1, "m"))
- bMinimized = 1;
- else if (!strcmp(argv[i] + 1, "g") && i + 1 < argc)
- {
- unsigned Data4Tmp[8], j;
-
- sscanf(argv[++i], "{%8x-%4hx-%4hx-%2x%2x-%2x%2x%2x%2x%2x%2x}",
- &Guid.Data1, &Guid.Data2, &Guid.Data3,
- &Data4Tmp[0], &Data4Tmp[1], &Data4Tmp[2], &Data4Tmp[3],
- &Data4Tmp[4], &Data4Tmp[5], &Data4Tmp[6], &Data4Tmp[7]);
- for (j = 0; j < 8; ++j)
- Guid.Data4[j] = (uint8_t)Data4Tmp[j];
- }
- else
- printf("Invalid option: %s\n", argv[i]);
- }
-
- if (!pszTarget || bHelp)
- {
- printf("Usage: %s [-o path][-d descr][-w path][-c cmd_line_args][-i icon_path [nr]][-h][-g guid] target\n"
- "-o path\tSets output path\n"
- "-d descr\tSets shortcut description\n"
- "-w path\tSets working directory for executable\n"
- "-c cmd_line_args\tSets command line arguments passed to program\n"
- "-i icon_path [nr]\tSets icon file and optionally icon index\n"
- "-m\tStart minimized\n"
- "-g guid\tSets GUID to which target path is relative. Default value is MyComputer GUID.\n"
- "target\tAbsolute or relative to guid specified with -g option path\n", argv[0]);
- return 0;
- }
-
- pFile = fopen(pszOutputPath, "wb");
- if (!pFile)
- {
- printf("Failed to open %s\n", pszOutputPath);
- return -1;
- }
-
- // Header
- memset(&Header, 0, sizeof(Header));
- Header.Signature = (uint32_t)'L';
- Header.Guid = CLSID_ShellLink;
- Header.Flags = LINK_ID_LIST;
- if (pszDescription)
- Header.Flags |= LINK_DESCRIPTION;
- if (pszWorkingDir)
- Header.Flags |= LINK_WORKING_DIR;
- if (pszCmdLineArgs)
- Header.Flags |= LINK_CMD_LINE_ARGS;
- if (pszIcon)
- Header.Flags |= LINK_ICON;
- Header.IconNr = IconNr;
- Header.Show = bMinimized ? SW_SHOWMINNOACTIVE : SW_SHOWNORMAL;
- fwrite(&Header, sizeof(Header), 1, pFile);
-
- if (Header.Flags & LINK_ID_LIST)
- {
- ID_LIST_FILE IdListFile;
- ID_LIST_GUID IdListGuid;
- ID_LIST_DRIVE IdListDrive;
- unsigned cbListSize = sizeof(IdListGuid) + sizeof(uint16_t), cchName;
- const char *pszName = pszTarget;
-
- // ID list
- // It seems explorer does not accept links without id list. List is relative to desktop.
-
- pszName = pszTarget;
-
- if (pszName[0] && pszName[1] == ':')
- {
- cbListSize += sizeof(IdListDrive);
- pszName += 2;
- while (*pszName == '\\' || *pszName == '/')
- ++pszName;
- }
-
- while (*pszName)
- {
- cchName = 0;
- while (pszName[cchName] && pszName[cchName] != '\\' && pszName[cchName] != '/')
- ++cchName;
-
- if (cchName != 1 || pszName[0] != '.')
- cbListSize += sizeof(IdListFile) + 2 * (cchName + 1);
-
- pszName += cchName;
- while (*pszName == '\\' || *pszName == '/')
- ++pszName;
- }
-
- uhTmp = cbListSize;
- fwrite(&uhTmp, sizeof(uhTmp), 1, pFile); // size
-
- IdListGuid.Size = sizeof(IdListGuid);
- IdListGuid.Type = PT_GUID;
- IdListGuid.dummy = 0x50;
- IdListGuid.guid = Guid;
- fwrite(&IdListGuid, sizeof(IdListGuid), 1, pFile);
-
- pszName = pszTarget;
-
- if (isalpha(pszName[0]) && pszName[1] == ':')
- {
- memset(&IdListDrive, 0, sizeof(IdListDrive));
- IdListDrive.Size = sizeof(IdListDrive);
- IdListDrive.Type = PT_DRIVE1;
- sprintf(IdListDrive.szDriveName, "%c:\\", pszName[0]);
- fwrite(&IdListDrive, sizeof(IdListDrive), 1, pFile);
- pszName += 2;
- while(*pszName == '\\' || *pszName == '/')
- ++pszName;
- }
-
- while (*pszName)
- {
- cchName = 0;
- while (pszName[cchName] && pszName[cchName] != '\\' && pszName[cchName] != '/')
- ++cchName;
-
- if (cchName != 1 || pszName[0] != '.')
- {
- memset(&IdListFile, 0, sizeof(IdListFile));
- IdListFile.Size = sizeof(IdListFile) + 2 * (cchName + 1);
- if (!pszName[cchName])
- IdListFile.Type = PT_VALUE; // File
- else
- IdListFile.Type = PT_FOLDER;
- fwrite(&IdListFile, sizeof(IdListFile), 1, pFile);
- fwrite(pszName, cchName, 1, pFile);
- fputc(0, pFile);
- fwrite(pszName, cchName, 1, pFile);
- fputc(0, pFile);
- }
-
- pszName += cchName;
- while (*pszName == '\\' || *pszName == '/')
- ++pszName;
- }
-
- uhTmp = 0; // list end
- fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
- }
-
- if (Header.Flags & LINK_DESCRIPTION)
- {
- // Dscription
- uhTmp = strlen(pszDescription);
- fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
- fputs(pszDescription, pFile);
- }
-
- if (Header.Flags & LINK_RELATIVE_PATH)
- {
- // Relative Path
- uhTmp = strlen(pszTarget);
- fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
- fputs(pszTarget, pFile);
- }
-
- if (Header.Flags & LINK_WORKING_DIR)
- {
- // Working Dir
- uhTmp = strlen(pszWorkingDir);
- fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
- fputs(pszWorkingDir, pFile);
- }
-
- if (Header.Flags & LINK_CMD_LINE_ARGS)
- {
- // Command line arguments
- uhTmp = strlen(pszCmdLineArgs);
- fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
- fputs(pszCmdLineArgs, pFile);
- }
-
- if (Header.Flags & LINK_ICON)
- {
- // Command line arguments
- uhTmp = strlen(pszIcon);
- fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
- fputs(pszIcon, pFile);
- }
-
- // Extra stuff
- dwTmp = 0;
- fwrite(&dwTmp, sizeof(dwTmp), 1, pFile);
-
- fclose(pFile);
-
- return 0;
-}