mirror of
https://github.com/reactos/reactos.git
synced 2024-09-30 14:37:45 +00:00
[MKSHELLLINK]
- Add host tool for creating .lnk files svn path=/trunk/; revision=54512
This commit is contained in:
parent
63ee24adb0
commit
ea682b6909
|
@ -13,6 +13,7 @@ add_subdirectory(mkhive)
|
||||||
add_subdirectory(obj2bin)
|
add_subdirectory(obj2bin)
|
||||||
add_subdirectory(spec2def)
|
add_subdirectory(spec2def)
|
||||||
add_subdirectory(unicode)
|
add_subdirectory(unicode)
|
||||||
|
add_subdirectory(mkshelllink)
|
||||||
|
|
||||||
if(NOT MSVC)
|
if(NOT MSVC)
|
||||||
add_subdirectory(rsym)
|
add_subdirectory(rsym)
|
||||||
|
|
2
reactos/tools/mkshelllink/CMakeLists.txt
Normal file
2
reactos/tools/mkshelllink/CMakeLists.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
add_executable(mkshelllink mkshelllink.c)
|
333
reactos/tools/mkshelllink/mkshelllink.c
Normal file
333
reactos/tools/mkshelllink/mkshelllink.c
Normal file
|
@ -0,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;
|
||||||
|
}
|
5
reactos/tools/mkshelllink/mkshelllink.rbuild
Normal file
5
reactos/tools/mkshelllink/mkshelllink.rbuild
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE module SYSTEM "../../tools/rbuild/project.dtd">
|
||||||
|
<module name="mkshelllink" type="buildtool">
|
||||||
|
<file>mkshelllink.c</file>
|
||||||
|
</module>
|
|
@ -46,4 +46,7 @@
|
||||||
<directory name="rbuild_helper">
|
<directory name="rbuild_helper">
|
||||||
<xi:include href="rbuild_helper/rbuild_helper.rbuild" />
|
<xi:include href="rbuild_helper/rbuild_helper.rbuild" />
|
||||||
</directory>
|
</directory>
|
||||||
|
<directory name="mkshelllink">
|
||||||
|
<xi:include href="mkshelllink/mkshelllink.rbuild" />
|
||||||
|
</directory>
|
||||||
</group>
|
</group>
|
||||||
|
|
Loading…
Reference in a new issue