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=54512&r1=54511&r2=54512&view=diff
==============================================================================
--- 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/CMakeLists.txt?rev=54512&view=auto
==============================================================================
--- 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/mkshelllink.c?rev=54512&view=auto
==============================================================================
--- 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_format.pdf
 */
+
+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/mkshelllink.rbuild?rev=54512&view=auto
==============================================================================
--- 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=54512&r1=54511&r2=54512&view=diff
==============================================================================
--- 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>


Reply via email to