Author: rharabien Date: Sun Nov 27 19:41:52 2011 New Revision: 54512
URL: http://svn.reactos.org/svn/reactos?rev=54512&view=rev Log: [MKSHELLLINK] - Add host tool for creating .lnk files
Added: trunk/reactos/tools/mkshelllink/ (with props) trunk/reactos/tools/mkshelllink/CMakeLists.txt (with props) trunk/reactos/tools/mkshelllink/mkshelllink.c (with props) trunk/reactos/tools/mkshelllink/mkshelllink.rbuild (with props) Modified: trunk/reactos/tools/CMakeLists.txt trunk/reactos/tools/tools.rbuild
Modified: trunk/reactos/tools/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/reactos/tools/CMakeLists.txt?rev=54... ============================================================================== --- trunk/reactos/tools/CMakeLists.txt [iso-8859-1] (original) +++ trunk/reactos/tools/CMakeLists.txt [iso-8859-1] Sun Nov 27 19:41:52 2011 @@ -13,6 +13,7 @@ add_subdirectory(obj2bin) add_subdirectory(spec2def) add_subdirectory(unicode) +add_subdirectory(mkshelllink)
if(NOT MSVC) add_subdirectory(rsym)
Propchange: trunk/reactos/tools/mkshelllink/ ------------------------------------------------------------------------------ --- bugtraq:logregex (added) +++ bugtraq:logregex Sun Nov 27 19:41:52 2011 @@ -1,0 +1,2 @@ +([Ii]ssue|[Bb]ug)s? #?(\d+)(,? ?#?(\d+))*(,? ?(and |or )?#?(\d+))? +(\d+)
Propchange: trunk/reactos/tools/mkshelllink/ ------------------------------------------------------------------------------ bugtraq:message = See issue #%BUGID% for more details.
Propchange: trunk/reactos/tools/mkshelllink/ ------------------------------------------------------------------------------ bugtraq:url = http://www.reactos.org/bugzilla/show_bug.cgi?id=%BUGID%
Propchange: trunk/reactos/tools/mkshelllink/ ------------------------------------------------------------------------------ tsvn:logminsize = 10
Added: trunk/reactos/tools/mkshelllink/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/reactos/tools/mkshelllink/CMakeList... ============================================================================== --- trunk/reactos/tools/mkshelllink/CMakeLists.txt (added) +++ trunk/reactos/tools/mkshelllink/CMakeLists.txt [iso-8859-1] Sun Nov 27 19:41:52 2011 @@ -1,0 +1,2 @@ + +add_executable(mkshelllink mkshelllink.c)
Propchange: trunk/reactos/tools/mkshelllink/CMakeLists.txt ------------------------------------------------------------------------------ svn:eol-style = native
Propchange: trunk/reactos/tools/mkshelllink/CMakeLists.txt ------------------------------------------------------------------------------ svn:keywords = Author Date Id Rev URL
Added: trunk/reactos/tools/mkshelllink/mkshelllink.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/tools/mkshelllink/mkshellli... ============================================================================== --- trunk/reactos/tools/mkshelllink/mkshelllink.c (added) +++ trunk/reactos/tools/mkshelllink/mkshelllink.c [iso-8859-1] Sun Nov 27 19:41:52 2011 @@ -1,0 +1,333 @@ +/* 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 <ctype.h> +#include <windows.h> + +#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_fo... */ + +typedef struct _LNK_HEADER +{ + DWORD Signature; + GUID Guid; + DWORD Flags; + DWORD Attributes; + FILETIME CreationTime; + FILETIME ModificationTime; + FILETIME LastAccessTime; + DWORD FileSize; + DWORD IconNr; + DWORD Show; + DWORD Hotkey; + DWORD Unknown; + DWORD Unknown2; +} LNK_HEADER; + +typedef struct _LNK_LOCATOR_INFO +{ + DWORD Size; + DWORD DataOffset; + DWORD Flags; + DWORD LocalVolumeInfoOffset; + DWORD LocalBasePathnameOffset; + DWORD NetworkVolumeInfoOffset; + DWORD RemainingPathnameOffset; + char Data[0]; +} LNK_LOCATOR_INFO; + +typedef struct _LNK_LOCAL_VOLUME_INFO +{ + DWORD Size; + DWORD VolumeType; /* See GetDriveType */ + DWORD SerialNumber; + DWORD 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 +{ + WORD Size; + BYTE Type; + BYTE dummy; + DWORD dwFileSize; + WORD uFileDate; + WORD uFileTime; + WORD uFileAttribs; + char szName[0]; +} ID_LIST_FILE; + +typedef struct _ID_LIST_GUID +{ + WORD Size; + BYTE Type; + BYTE dummy; + GUID guid; +} ID_LIST_GUID; + +typedef struct _ID_LIST_DRIVE +{ + WORD Size; + BYTE Type; + CHAR szDriveName[20]; + WORD 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; + BOOL bHelp = FALSE, bMinimized = FALSE; + FILE *pFile; + LNK_HEADER Header; + USHORT uhTmp; + DWORD dwTmp; + + for (i = 1; i < argc; ++i) + { + if (argv[i][0] != '-' && argv[i][0] != '/') + pszTarget = argv[i]; + else if (!stricmp(argv[i] + 1, "h")) + bHelp = TRUE; + else if (!stricmp(argv[i] + 1, "o") && i + 1 < argc) + pszOutputPath = argv[++i]; + else if (!stricmp(argv[i] + 1, "d") && i + 1 < argc) + pszDescription = argv[++i]; + else if (!stricmp(argv[i] + 1, "w") && i + 1 < argc) + pszWorkingDir = argv[++i]; + else if (!stricmp(argv[i] + 1, "c") && i + 1 < argc) + pszCmdLineArgs = argv[++i]; + else if (!stricmp(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 (!stricmp(argv[i] + 1, "m")) + bMinimized = TRUE; + else if (!stricmp(argv[i] + 1, "g") && i + 1 < argc) + { + unsigned Data4Tmp[8], j; + + sscanf(argv[++i], "{%8lx-%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] = (BYTE)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 = (DWORD)'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(WORD), 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; +}
Propchange: trunk/reactos/tools/mkshelllink/mkshelllink.c ------------------------------------------------------------------------------ svn:eol-style = native
Added: trunk/reactos/tools/mkshelllink/mkshelllink.rbuild URL: http://svn.reactos.org/svn/reactos/trunk/reactos/tools/mkshelllink/mkshellli... ============================================================================== --- trunk/reactos/tools/mkshelllink/mkshelllink.rbuild (added) +++ trunk/reactos/tools/mkshelllink/mkshelllink.rbuild [iso-8859-1] Sun Nov 27 19:41:52 2011 @@ -1,0 +1,5 @@ +<?xml version="1.0"?> +<!DOCTYPE module SYSTEM "../../tools/rbuild/project.dtd"> +<module name="mkshelllink" type="buildtool"> + <file>mkshelllink.c</file> +</module>
Propchange: trunk/reactos/tools/mkshelllink/mkshelllink.rbuild ------------------------------------------------------------------------------ svn:eol-style = native
Modified: trunk/reactos/tools/tools.rbuild URL: http://svn.reactos.org/svn/reactos/trunk/reactos/tools/tools.rbuild?rev=5451... ============================================================================== --- trunk/reactos/tools/tools.rbuild [iso-8859-1] (original) +++ trunk/reactos/tools/tools.rbuild [iso-8859-1] Sun Nov 27 19:41:52 2011 @@ -46,4 +46,7 @@ <directory name="rbuild_helper"> <xi:include href="rbuild_helper/rbuild_helper.rbuild" /> </directory> +<directory name="mkshelllink"> + <xi:include href="mkshelllink/mkshelllink.rbuild" /> +</directory> </group>