ReactOS 0.4.17-dev-1321-g5c122a9
mkshelllink.c File Reference
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdint.h>
Include dependency graph for mkshelllink.c:

Go to the source code of this file.

Classes

struct  _GUID
 
struct  _FILETIME
 
struct  _LNK_HEADER
 
struct  _LNK_LOCATOR_INFO
 
struct  _LNK_LOCAL_VOLUME_INFO
 
struct  _ID_LIST_GUID
 
struct  _ID_LIST_DRIVE
 
struct  _ID_LIST_FILE
 
struct  _EXP_SPECIAL_FOLDER
 
struct  _EXP_SZ_LINK
 
struct  SPECIALFOLDER
 

Macros

#define C_ASSERT(expr)   extern char (*c_assert(void)) [(expr) ? 1 : -1]
 
#define __cdecl
 
#define _countof(_Array)   (sizeof(_Array) / sizeof(_Array[0]))
 
#define min(a, b)   (((a) < (b)) ? (a) : (b))
 
#define SW_SHOWNORMAL   1
 
#define SW_SHOWMINNOACTIVE   7
 
#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 LOCATOR_LOCAL   0x1
 
#define LOCATOR_NETWORK   0x2
 
#define SLDF_DEFAULT   0x00000000
 
#define SLDF_HAS_ID_LIST   0x00000001
 
#define SLDF_HAS_LINK_INFO   0x00000002
 
#define SLDF_HAS_NAME   0x00000004
 
#define SLDF_HAS_RELPATH   0x00000008
 
#define SLDF_HAS_WORKINGDIR   0x00000010
 
#define SLDF_HAS_ARGS   0x00000020
 
#define SLDF_HAS_ICONLOCATION   0x00000040
 
#define SLDF_UNICODE   0x00000080
 
#define SLDF_HAS_EXP_SZ   0x00000200
 
#define SLDF_HAS_EXP_ICON_SZ   0x00004000
 
#define LINK_ID_LIST   SLDF_HAS_ID_LIST
 
#define LINK_FILE   SLDF_HAS_LINK_INFO
 
#define LINK_DESCRIPTION   SLDF_HAS_NAME
 
#define LINK_RELATIVE_PATH   SLDF_HAS_RELPATH
 
#define LINK_WORKING_DIR   SLDF_HAS_WORKINGDIR
 
#define LINK_CMDLINE_ARGS   SLDF_HAS_ARGS
 
#define LINK_ICON   SLDF_HAS_ICONLOCATION
 
#define LINK_UNICODE   SLDF_UNICODE
 
#define PT_GUID   0x1F
 
#define PT_DRIVE1   0x2F
 
#define PT_FOLDER   0x31
 
#define PT_VALUE   0x32
 
#define REGITEMORDER_DEFAULT   0x80
 
#define REGITEMORDER_LIBRARIES   0x42
 
#define REGITEMORDER_USERSFILEFOLDER   0x44
 
#define REGITEMORDER_MYCOMPUTER   0x50
 
#define EXP_SPECIAL_FOLDER_SIG   0xA0000005
 
#define MAX_PATH   260
 
#define EXP_SZ_LINK_SIG   0xA0000001
 
#define EXP_SZ_ICON_SIG   0xA0000007
 
#define CSIDL_WINDOWS   0x24
 
#define CSIDL_SYSTEM   0x25
 

Typedefs

typedef struct _GUID GUID
 
typedef struct _FILETIME FILETIME
 
typedef struct _FILETIME * PFILETIME
 
typedef struct _LNK_HEADER LNK_HEADER
 
typedef struct _LNK_LOCATOR_INFO LNK_LOCATOR_INFO
 
typedef struct _LNK_LOCAL_VOLUME_INFO LNK_LOCAL_VOLUME_INFO
 
typedef struct _ID_LIST_GUID ID_LIST_GUID
 
typedef struct _ID_LIST_DRIVE ID_LIST_DRIVE
 
typedef struct _ID_LIST_FILE ID_LIST_FILE
 
typedef struct _EXP_SPECIAL_FOLDER EXP_SPECIAL_FOLDER
 
typedef struct _EXP_SZ_LINK EXP_SZ_LINK
 

Functions

 C_ASSERT (sizeof(wchar_t)==sizeof(uint16_t))
 
 C_ASSERT (sizeof(GUID)==16)
 
 DEFINE_GUID2 (CLSID_ShellLink, 0x00021401, 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)
 
size_t mbstowcs16 (wchar_t *wcstr, const char *mbstr, size_t count)
 
static void __cdecl trace (const char *format,...)
 
static bool is_path_separator (char c)
 
static bool has_env_variables (const char *str)
 
static void strip_quotes_and_unescape_envvars (char **pstr)
 
static const struct SPECIALFOLDER * get_special_folder (const char *target)
 
static void write_string (FILE *pFile, bool bUnicode, const char *str)
 
int main (int argc, const char *argv[])
 

Variables

static bool g_Verbose = false
 
static const struct SPECIALFOLDER g_specialfolders []
 

Macro Definition Documentation

◆ __cdecl

#define __cdecl

Definition at line 25 of file mkshelllink.c.

◆ _countof

#define _countof (   _Array)    (sizeof(_Array) / sizeof(_Array[0]))

Definition at line 40 of file mkshelllink.c.

◆ C_ASSERT

#define C_ASSERT (   expr)    extern char (*c_assert(void)) [(expr) ? 1 : -1]

Definition at line 20 of file mkshelllink.c.

◆ CSIDL_SYSTEM

#define CSIDL_SYSTEM   0x25

Definition at line 226 of file mkshelllink.c.

◆ CSIDL_WINDOWS

#define CSIDL_WINDOWS   0x24

Definition at line 225 of file mkshelllink.c.

◆ DEFINE_GUID2

#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 } }

Definition at line 71 of file mkshelllink.c.

◆ EXP_SPECIAL_FOLDER_SIG

#define EXP_SPECIAL_FOLDER_SIG   0xA0000005

Definition at line 196 of file mkshelllink.c.

◆ EXP_SZ_ICON_SIG

#define EXP_SZ_ICON_SIG   0xA0000007

Definition at line 208 of file mkshelllink.c.

◆ EXP_SZ_LINK_SIG

#define EXP_SZ_LINK_SIG   0xA0000001

Definition at line 207 of file mkshelllink.c.

◆ LINK_CMDLINE_ARGS

#define LINK_CMDLINE_ARGS   SLDF_HAS_ARGS

Definition at line 105 of file mkshelllink.c.

◆ LINK_DESCRIPTION

#define LINK_DESCRIPTION   SLDF_HAS_NAME

Definition at line 102 of file mkshelllink.c.

◆ LINK_FILE

#define LINK_FILE   SLDF_HAS_LINK_INFO

Definition at line 101 of file mkshelllink.c.

◆ LINK_ICON

#define LINK_ICON   SLDF_HAS_ICONLOCATION

Definition at line 106 of file mkshelllink.c.

◆ LINK_ID_LIST

#define LINK_ID_LIST   SLDF_HAS_ID_LIST

Definition at line 100 of file mkshelllink.c.

◆ LINK_RELATIVE_PATH

#define LINK_RELATIVE_PATH   SLDF_HAS_RELPATH

Definition at line 103 of file mkshelllink.c.

◆ LINK_UNICODE

#define LINK_UNICODE   SLDF_UNICODE

Definition at line 107 of file mkshelllink.c.

◆ LINK_WORKING_DIR

#define LINK_WORKING_DIR   SLDF_HAS_WORKINGDIR

Definition at line 104 of file mkshelllink.c.

◆ LOCATOR_LOCAL

#define LOCATOR_LOCAL   0x1

Definition at line 75 of file mkshelllink.c.

◆ LOCATOR_NETWORK

#define LOCATOR_NETWORK   0x2

Definition at line 76 of file mkshelllink.c.

◆ MAX_PATH

#define MAX_PATH   260

Definition at line 205 of file mkshelllink.c.

◆ min

#define min (   a,
  b 
)    (((a) < (b)) ? (a) : (b))

Definition at line 43 of file mkshelllink.c.

◆ PT_DRIVE1

#define PT_DRIVE1   0x2F

Definition at line 153 of file mkshelllink.c.

◆ PT_FOLDER

#define PT_FOLDER   0x31

Definition at line 154 of file mkshelllink.c.

◆ PT_GUID

#define PT_GUID   0x1F

Definition at line 152 of file mkshelllink.c.

◆ PT_VALUE

#define PT_VALUE   0x32

Definition at line 155 of file mkshelllink.c.

◆ REGITEMORDER_DEFAULT

#define REGITEMORDER_DEFAULT   0x80

Definition at line 158 of file mkshelllink.c.

◆ REGITEMORDER_LIBRARIES

#define REGITEMORDER_LIBRARIES   0x42

Definition at line 159 of file mkshelllink.c.

◆ REGITEMORDER_MYCOMPUTER

#define REGITEMORDER_MYCOMPUTER   0x50

Definition at line 161 of file mkshelllink.c.

◆ REGITEMORDER_USERSFILEFOLDER

#define REGITEMORDER_USERSFILEFOLDER   0x44

Definition at line 160 of file mkshelllink.c.

◆ SLDF_DEFAULT

#define SLDF_DEFAULT   0x00000000

Definition at line 88 of file mkshelllink.c.

◆ SLDF_HAS_ARGS

#define SLDF_HAS_ARGS   0x00000020

Definition at line 94 of file mkshelllink.c.

◆ SLDF_HAS_EXP_ICON_SZ

#define SLDF_HAS_EXP_ICON_SZ   0x00004000

Definition at line 98 of file mkshelllink.c.

◆ SLDF_HAS_EXP_SZ

#define SLDF_HAS_EXP_SZ   0x00000200

Definition at line 97 of file mkshelllink.c.

◆ SLDF_HAS_ICONLOCATION

#define SLDF_HAS_ICONLOCATION   0x00000040

Definition at line 95 of file mkshelllink.c.

◆ SLDF_HAS_ID_LIST

#define SLDF_HAS_ID_LIST   0x00000001

Definition at line 89 of file mkshelllink.c.

◆ SLDF_HAS_LINK_INFO

#define SLDF_HAS_LINK_INFO   0x00000002

Definition at line 90 of file mkshelllink.c.

◆ SLDF_HAS_NAME

#define SLDF_HAS_NAME   0x00000004

Definition at line 91 of file mkshelllink.c.

◆ SLDF_HAS_RELPATH

#define SLDF_HAS_RELPATH   0x00000008

Definition at line 92 of file mkshelllink.c.

◆ SLDF_HAS_WORKINGDIR

#define SLDF_HAS_WORKINGDIR   0x00000010

Definition at line 93 of file mkshelllink.c.

◆ SLDF_UNICODE

#define SLDF_UNICODE   0x00000080

Definition at line 96 of file mkshelllink.c.

◆ SW_SHOWMINNOACTIVE

#define SW_SHOWMINNOACTIVE   7

Definition at line 54 of file mkshelllink.c.

◆ SW_SHOWNORMAL

#define SW_SHOWNORMAL   1

Definition at line 53 of file mkshelllink.c.

Typedef Documentation

◆ EXP_SPECIAL_FOLDER

◆ EXP_SZ_LINK

◆ FILETIME

◆ GUID

typedef struct _GUID GUID

◆ ID_LIST_DRIVE

◆ ID_LIST_FILE

◆ ID_LIST_GUID

◆ LNK_HEADER

◆ LNK_LOCAL_VOLUME_INFO

◆ LNK_LOCATOR_INFO

◆ PFILETIME

Function Documentation

◆ C_ASSERT() [1/2]

C_ASSERT ( sizeof(GUID)  = =16)

◆ C_ASSERT() [2/2]

C_ASSERT ( sizeof(wchar_t)  = =sizeof(uint16_t))

◆ DEFINE_GUID2() [1/2]

DEFINE_GUID2 ( CLSID_MyComputer  ,
0x20D04FE0  ,
0x3AEA  ,
0x1069  ,
0xA2  ,
0xD8  ,
0x08  ,
0x00  ,
0x2B  ,
0x30  ,
0x30  ,
0x9D   
)

◆ DEFINE_GUID2() [2/2]

DEFINE_GUID2 ( CLSID_ShellLink  ,
0x00021401  ,
0  ,
0  ,
0xC0  ,
0  ,
0  ,
0  ,
0  ,
0  ,
0  ,
0x46   
)

◆ get_special_folder()

static const struct SPECIALFOLDER * get_special_folder ( const char *  target)
static

Definition at line 334 of file mkshelllink.c.

335{
336 char buf[256];
337
338 strncpy(buf, target, sizeof(buf));
339 buf[sizeof("shell:") - 1] = '\0';
340 if (strcasecmp("shell:", buf))
341 return NULL;
342
343 target += sizeof("shell:") - 1;
344 for (unsigned long i = 0;; ++i)
345 {
346 unsigned long len;
347 const struct SPECIALFOLDER *special = &g_specialfolders[i];
348 if (!special->name)
349 return NULL;
350 len = strlen(special->name);
351 strncpy(buf, target, sizeof(buf));
352 buf[len] = '\0';
353 if (!strcasecmp(special->name, buf) && (is_path_separator(target[len]) || !target[len]))
354 return &g_specialfolders[i];
355 }
356}
#define NULL
Definition: types.h:112
_ACRTIMP size_t __cdecl strlen(const char *)
Definition: string.c:1597
#define strcasecmp
Definition: fake.h:9
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLenum GLsizei len
Definition: glext.h:6722
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
strncpy
Definition: string.h:335
const char * name
Definition: mkshelllink.c:230
Definition: tools.h:99

Referenced by main().

◆ has_env_variables()

static bool has_env_variables ( const char *  str)
static

Definition at line 292 of file mkshelllink.c.

293{
294 const char *ptr = strchr(str, '%');
295 return (ptr && strchr(ptr + 1, '%'));
296}
_ACRTIMP char *__cdecl strchr(const char *, int)
Definition: string.c:3291
static PVOID ptr
Definition: dispmode.c:27
const WCHAR * str

Referenced by main().

◆ is_path_separator()

static bool is_path_separator ( char  c)
static

Definition at line 285 of file mkshelllink.c.

286{
287 return (c == '\\' || c == '/');
288}
const GLubyte * c
Definition: glext.h:8905

Referenced by get_special_folder(), and main().

◆ main()

int main ( int  argc,
const char *  argv[] 
)

Definition at line 383 of file mkshelllink.c.

384{
385 const char *pszOutputPath = "shortcut.lnk";
386 const char *pszTarget = NULL;
387 const char *pszDescription = NULL;
388 const char *pszWorkingDir = NULL;
389 const char *pszCmdLineArgs = NULL;
390 const char *pszIcon = NULL;
391 char targetpath[MAX_PATH];
392 int32_t IconIndex = 0;
393 GUID Guid = CLSID_MyComputer;
394 bool bHelp = false, bUnicode = false, bMinimized = false;
395 int i;
396 FILE *pFile;
398 uint32_t dwTmp;
399 const struct SPECIALFOLDER *special;
400 EXP_SPECIAL_FOLDER CsidlBlock, *pCsidlBlock = NULL;
401 EXP_SZ_LINK SzLinkBlock, *pSzLinkBlock = NULL;
402 EXP_SZ_LINK SzIconBlock, *pSzIconBlock = NULL;
403
404 /* Check for verbose mode in the command-line */
405 for (i = 1; i < argc; ++i)
406 {
407 if ((argv[i][0] == '-' || argv[i][0] == '/') &&
408 !strcmp(argv[i] + 1, "v"))
409 {
410 g_Verbose = true;
411 break;
412 }
413 }
414
415 /* Parse the command-line */
416 for (i = 1; i < argc; ++i)
417 {
418 trace("argv[%d]: %s\n", i, argv[i]);
419
420 if (argv[i][0] != '-' && argv[i][0] != '/')
421 pszTarget = argv[i];
422 else if (!strcmp(argv[i] + 1, "h"))
423 bHelp = true;
424 else if (!strcmp(argv[i] + 1, "v"))
425 /* Verbose mode, separately handled above */;
426 else if (!strcmp(argv[i] + 1, "o") && (i + 1 < argc))
427 {
428 ++i;
429 trace("argv[%d]: %s\n", i, argv[i]);
430 pszOutputPath = argv[i];
431 }
432 else if (!strcmp(argv[i] + 1, "u"))
433 bUnicode = true;
434 else if (!strcmp(argv[i] + 1, "d") && (i + 1 < argc))
435 {
436 ++i;
437 trace("argv[%d]: %s\n", i, argv[i]);
438 pszDescription = argv[i];
439 }
440 else if (!strcmp(argv[i] + 1, "w") && (i + 1 < argc))
441 {
442 ++i;
443 trace("argv[%d]: %s\n", i, argv[i]);
444 pszWorkingDir = argv[i];
445 }
446 else if (!strcmp(argv[i] + 1, "c") && (i + 1 < argc))
447 {
448 ++i;
449 trace("argv[%d]: %s\n", i, argv[i]);
450 pszCmdLineArgs = argv[i];
451 }
452 else if (!strcmp(argv[i] + 1, "i") && (i + 1 < argc))
453 {
454 ++i;
455 trace("argv[%d]: %s\n", i, argv[i]);
456 pszIcon = argv[i];
457 }
458 else if (!strcmp(argv[i] + 1, "m"))
459 bMinimized = true;
460 else if (!strcmp(argv[i] + 1, "g") && (i + 1 < argc))
461 {
462 unsigned Data4Tmp[8], j;
463
464 ++i;
465 trace("argv[%d]: %s\n", i, argv[i]);
466 sscanf(argv[i], "{%8x-%4hx-%4hx-%2x%2x-%2x%2x%2x%2x%2x%2x}",
467 &Guid.Data1, &Guid.Data2, &Guid.Data3,
468 &Data4Tmp[0], &Data4Tmp[1], &Data4Tmp[2], &Data4Tmp[3],
469 &Data4Tmp[4], &Data4Tmp[5], &Data4Tmp[6], &Data4Tmp[7]);
470 for (j = 0; j < 8; ++j)
471 Guid.Data4[j] = (uint8_t)Data4Tmp[j];
472 }
473 else
474 {
475 printf("Invalid option: %s\n", argv[i]);
476 bHelp = true;
477 }
478 }
479 if (argc > 1)
480 trace("\n");
481
482 if (!pszTarget || bHelp)
483 {
484 printf("Usage: %s [-h][-v][-o path][-u][-d descr][-w path][-c cmdline_args][-i [icon_path[,nr]]][-g guid] target\n"
485 "-h\tShows this help.\n"
486 "-v\tEnables verbose mode for diagnostics.\n"
487 "-o path\tSets the output path.\n"
488 "-u\tCreates a Unicode-aware shortcut.\n"
489 "-d descr\tSets the shortcut description.\n"
490 "-w path\tSets the working directory for the executable.\n"
491 "-c cmdline_args\tSets the command-line arguments passed to the program.\n"
492 "-i [icon_path[,nr]]\tSets the icon path and optionally its index. If only an index is given (but no path), the target file is used instead.\n"
493 "-m\tStart minimized.\n"
494 "-g guid\tSets the GUID to which the target path is relative. Default value is MyComputer GUID.\n"
495 "target\tAbsolute or relative to GUID specified with the -g option path.\n", argv[0]);
496 return 0;
497 }
498
499 /* Process the parameters */
500 if (pszTarget)
501 strip_quotes_and_unescape_envvars((char**)&pszTarget);
502 if (pszWorkingDir)
503 strip_quotes_and_unescape_envvars((char**)&pszWorkingDir);
504 if (pszCmdLineArgs)
505 strip_quotes_and_unescape_envvars((char**)&pszCmdLineArgs);
506 if (pszIcon)
507 {
508 char *ptr, *endptr;
509
510 strip_quotes_and_unescape_envvars((char**)&pszIcon);
511
512 /* Check whether only an icon index was given */
513 dwTmp = strtol(pszIcon, &endptr, 0);
514 if (endptr && endptr != pszIcon)
515 {
516 /* Only an index was given; save it, and use the target as the icon file */
517 IconIndex = dwTmp;
518 pszIcon = (char*)1; // Canary value to tell to use pszTarget, once resolved.
519 }
520 else
521 {
522 /* No index was given: this is a file path, optionally followed by the icon index */
523 ptr = strrchr(pszIcon, ',');
524 if (ptr) // && isdigit(ptr[1])
525 {
526 /* We may have an index that follows the icon path */
527 dwTmp = strtol(ptr+1, &endptr, 0);
528 if (endptr && endptr != (ptr+1))
529 {
530 /* It's valid, retrieve it and truncate the string to where the icon path ends */
531 IconIndex = dwTmp;
532 *ptr = '\0';
533 }
534 }
535 pszIcon = pszIcon;
536 }
537 }
538
539 trace("OutputPath = %s\n"
540 "Target = %s\n"
541 "Description = %s\n"
542 "WorkingDir = %s\n"
543 "CmdLineArgs = %s\n"
544 "Icon = %s (%d)\n\n",
545 pszOutputPath, pszTarget, pszDescription,
546 pszWorkingDir, pszCmdLineArgs,
547 (pszIcon == (char*)1) ? pszTarget : pszIcon, IconIndex);
548
549 pFile = fopen(pszOutputPath, "wb");
550 if (!pFile)
551 {
552 printf("Failed to open %s\n", pszOutputPath);
553 return -1;
554 }
555
556 /* Header */
557 memset(&Header, 0, sizeof(Header));
558 Header.Size = sizeof(Header);
559 Header.Guid = CLSID_ShellLink;
560 Header.Flags = LINK_ID_LIST;
561 if (bUnicode)
562 Header.Flags |= LINK_UNICODE;
563 if (pszDescription)
564 Header.Flags |= LINK_DESCRIPTION;
565 if (pszWorkingDir)
566 Header.Flags |= LINK_WORKING_DIR;
567 if (pszCmdLineArgs)
568 Header.Flags |= LINK_CMDLINE_ARGS;
569 if (pszIcon)
570 Header.Flags |= LINK_ICON;
571 Header.IconIndex = IconIndex;
572 Header.ShowCmd = (bMinimized ? SW_SHOWMINNOACTIVE : SW_SHOWNORMAL);
573
574 /* Verify the target type before proceeding further */
575 special = get_special_folder(pszTarget);
576 if (special)
577 Header.Flags |= LINK_ID_LIST; // Definitively needed in this case.
578
579 /* Check whether the target path contains Win32 environment variables */
580 if (has_env_variables(pszTarget))
581 {
582 Header.Flags |= SLDF_HAS_EXP_SZ;
583 Header.Flags &= ~LINK_ID_LIST; // We cannot deal with PIDLs in this case.
584 }
585 if ((Header.Flags & LINK_ID_LIST) && special)
586 Header.Flags &= ~LINK_RELATIVE_PATH;
587
588 /* If it's not a direct target, check whether it uses a special
589 * folder that is defined using Win32 environment variables */
590 if (special && special->unexpPath && has_env_variables(special->unexpPath))
591 Header.Flags |= SLDF_HAS_EXP_SZ;
592
593 /*
594 * For the icon, first check the canary value that tells to use the target path.
595 * If present, the icon path will contain Win32 environment variables if the target has them.
596 * Otherwise, explicitly check whether the specified icon path contains environment variables.
597 */
598 if ((pszIcon == (char*)1) && (Header.Flags & SLDF_HAS_EXP_SZ))
600 else if (pszIcon && has_env_variables(pszIcon))
602
603 trace("Header.Flags = 0x%08x\n"
604 "Header.IconIndex = %d\n"
605 "Header.ShowCmd = %u\n",
606 Header.Flags, Header.IconIndex, Header.ShowCmd);
607
608 fwrite(&Header, sizeof(Header), 1, pFile);
609
610 if (Header.Flags & LINK_ID_LIST)
611 {
612 ID_LIST_GUID IdListGuid;
613 ID_LIST_DRIVE IdListDrive;
614 ID_LIST_FILE IdListFile;
615 unsigned int cbListSize = sizeof(IdListGuid) + sizeof(uint16_t);
616 unsigned int cchName;
617 const char *pszName;
618 const char *pszOrgTarget = pszTarget;
619 size_t specialPathLen = 0;
620 uint16_t uhTmp;
621
622 /* ID list. It appears explorer does not accept links
623 * without an ID list. It is relative to desktop. */
624 if (special)
625 {
626 CsidlBlock.cbSize = sizeof(CsidlBlock);
628 CsidlBlock.idSpecialFolder = special->csidl;
629 specialPathLen = strlen(special->dummyPath);
630 sprintf(targetpath, "%s\\%s", special->dummyPath, pszOrgTarget + sizeof("shell:") + strlen(special->name));
631 pszTarget = targetpath;
632 }
633 pszName = pszTarget;
634
635 if (pszName[0] && pszName[0] != ':' && pszName[1] == ':')
636 {
637 cbListSize += sizeof(IdListDrive);
638 pszName += 2;
639 while (is_path_separator(*pszName))
640 ++pszName;
641 }
642
643 while (*pszName)
644 {
645 cchName = 0;
646 while (pszName[cchName] && !is_path_separator(pszName[cchName]))
647 ++cchName;
648
649 if (cchName != 1 || pszName[0] != '.')
650 {
651 /* Don't care about the DOS name */
652 //cbListSize += sizeof(IdListFile) + 2 * (cchName + 1);
653 cbListSize += sizeof(IdListFile) + (cchName + 1) + 1;
654 }
655
656 if (special && ((pszName+cchName)-pszTarget == specialPathLen))
657 {
658 /* Point the special folder block to the rest of the path in the ID list */
659 CsidlBlock.cbOffset = cbListSize - sizeof(uint16_t);
660 pCsidlBlock = &CsidlBlock;
661 }
662
663 pszName += cchName;
664 while (is_path_separator(*pszName))
665 ++pszName;
666 }
667
668 /* ID list size */
669 uhTmp = cbListSize;
670 fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
671
672 IdListGuid.Size = sizeof(IdListGuid);
673 IdListGuid.Type = PT_GUID;
675 IdListGuid.guid = Guid;
676 fwrite(&IdListGuid, sizeof(IdListGuid), 1, pFile);
677
678 pszName = pszTarget;
679
680 if (isalpha(pszName[0]) && pszName[1] == ':')
681 {
682 memset(&IdListDrive, 0, sizeof(IdListDrive));
683 IdListDrive.Size = sizeof(IdListDrive);
684 IdListDrive.Type = PT_DRIVE1;
685 sprintf(IdListDrive.szDriveName, "%c:\\", pszName[0]);
686 fwrite(&IdListDrive, sizeof(IdListDrive), 1, pFile);
687 pszName += 2;
688 while (is_path_separator(*pszName))
689 ++pszName;
690 }
691
692 while (*pszName)
693 {
694 cchName = 0;
695 while (pszName[cchName] && !is_path_separator(pszName[cchName]))
696 ++cchName;
697
698 if (cchName != 1 || pszName[0] != '.')
699 {
700 memset(&IdListFile, 0, sizeof(IdListFile));
701 /* Don't care about the DOS name */
702 //IdListFile.Size = sizeof(IdListFile) + 2 * (cchName + 1);
703 IdListFile.Size = sizeof(IdListFile) + (cchName + 1) + 1;
704 if (!pszName[cchName])
705 IdListFile.Type = PT_VALUE; // File
706 else
707 IdListFile.Type = PT_FOLDER;
708 fwrite(&IdListFile, sizeof(IdListFile), 1, pFile);
709 fwrite(pszName, cchName, 1, pFile);
710 fputc(0, pFile); // NUL-terminate
711 /* Don't care about the DOS name */
712 //fwrite(pszName, cchName, 1, pFile);
713 fputc(0, pFile); // NUL-terminate
714 }
715
716 pszName += cchName;
717 while (is_path_separator(*pszName))
718 ++pszName;
719 }
720
721 /* End of ID list */
722 uhTmp = 0;
723 fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
724
725 /* Reset the target path to the actual unexpanded path */
726 if (special)
727 {
728 sprintf(targetpath, "%s\\%s", special->unexpPath, pszOrgTarget + sizeof("shell:") + strlen(special->name));
729 pszTarget = targetpath;
730 }
731 }
732
733 /* Now, set the icon path to the target path if it has the specific canary value */
734 if (pszIcon == (char*)1)
735 pszIcon = pszTarget;
736
737 if (Header.Flags & SLDF_HAS_EXP_SZ)
738 {
739 memset(&SzLinkBlock, 0, sizeof(SzLinkBlock));
740 SzLinkBlock.cbSize = sizeof(SzLinkBlock);
741 SzLinkBlock.dwSignature = EXP_SZ_LINK_SIG;
742
743 /* We have to store both ANSI and UTF16 versions of the string! */
744 strncpy(SzLinkBlock.szTarget, pszTarget, _countof(SzLinkBlock.szTarget));
745 mbstowcs16(SzLinkBlock.szwTarget, pszTarget, _countof(SzLinkBlock.szwTarget));
746
747 pSzLinkBlock = &SzLinkBlock;
748 }
749
750 if (Header.Flags & SLDF_HAS_EXP_ICON_SZ)
751 {
752 memset(&SzIconBlock, 0, sizeof(SzIconBlock));
753 SzIconBlock.cbSize = sizeof(SzIconBlock);
754 SzIconBlock.dwSignature = EXP_SZ_ICON_SIG;
755
756 /* We have to store both ANSI and UTF16 versions of the string! */
757 strncpy(SzIconBlock.szTarget, pszIcon, _countof(SzIconBlock.szTarget));
758 mbstowcs16(SzIconBlock.szwTarget, pszIcon, _countof(SzIconBlock.szwTarget));
759
760 pSzIconBlock = &SzIconBlock;
761 }
762
763 /* Description */
764 if (Header.Flags & LINK_DESCRIPTION)
765 write_string(pFile, bUnicode, pszDescription);
766
767 /* Relative path */
768 if (Header.Flags & LINK_RELATIVE_PATH)
769 write_string(pFile, bUnicode, pszTarget);
770
771 /* Working directory */
772 if (Header.Flags & LINK_WORKING_DIR)
773 write_string(pFile, bUnicode, pszWorkingDir);
774
775 /* Command-line arguments */
776 if (Header.Flags & LINK_CMDLINE_ARGS)
777 write_string(pFile, bUnicode, pszCmdLineArgs);
778
779 /* Icon path */
780 if (Header.Flags & LINK_ICON)
781 write_string(pFile, bUnicode, pszIcon);
782
783 /* Write the data block list */
784 if (pCsidlBlock)
785 fwrite(pCsidlBlock, sizeof(*pCsidlBlock), 1, pFile);
786 if (pSzLinkBlock)
787 fwrite(pSzLinkBlock, sizeof(*pSzLinkBlock), 1, pFile);
788 if (pSzIconBlock)
789 fwrite(pSzIconBlock, sizeof(*pSzIconBlock), 1, pFile);
790 /* End of data block list */
791 dwTmp = 0;
792 fwrite(&dwTmp, sizeof(dwTmp), 1, pFile);
793
794 fclose(pFile);
795
796 return 0;
797}
#define isalpha(c)
Definition: acclib.h:74
#define trace
Definition: atltest.h:70
Definition: Header.h:9
INT32 int32_t
Definition: types.h:71
UINT32 uint32_t
Definition: types.h:75
MonoAssembly int argc
Definition: metahost.c:107
int CDECL fclose(FILE *file)
Definition: file.c:3757
FILE *CDECL fopen(const char *path, const char *mode)
Definition: file.c:4310
int CDECL fputc(int c, FILE *file)
Definition: file.c:4360
size_t CDECL fwrite(const void *ptr, size_t size, size_t nmemb, FILE *file)
Definition: file.c:4129
unsigned short uint16_t
Definition: stdint.h:35
unsigned char uint8_t
Definition: stdint.h:33
_ACRTIMP int __cdecl _ACRTIMP int __cdecl _ACRTIMP int __cdecl _ACRTIMP int __cdecl _ACRTIMP int __cdecl _ACRTIMP int __cdecl _ACRTIMP int __cdecl sscanf(const char *, const char *,...) __WINE_CRT_SCANF_ATTR(2
_ACRTIMP __msvcrt_long __cdecl strtol(const char *, char **, int)
Definition: string.c:1838
_ACRTIMP int __cdecl strcmp(const char *, const char *)
Definition: string.c:3324
_ACRTIMP char *__cdecl strrchr(const char *, int)
Definition: string.c:3303
static const WCHAR IconIndex[]
Definition: install.c:52
#define printf
Definition: freeldr.h:103
MdFileObject pFile
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
#define sprintf
Definition: sprintf.c:45
#define argv
Definition: mplay32.c:18
#define uint16_t
Definition: nsiface.idl:60
#define memset(x, y, z)
Definition: compat.h:39
DWORD idSpecialFolder
Definition: shlobj.h:2088
const char * unexpPath
Definition: mkshelllink.c:232
const char * dummyPath
Definition: mkshelllink.c:231
unsigned char csidl
Definition: mkshelllink.c:229
char szDriveName[20]
Definition: mkshelllink.c:177
uint16_t Size
Definition: mkshelllink.c:175
uint8_t Type
Definition: mkshelllink.c:185
uint16_t Size
Definition: mkshelllink.c:184
uint8_t uSortOrder
Definition: mkshelllink.c:168
uint8_t Type
Definition: mkshelllink.c:167
uint16_t Size
Definition: mkshelllink.c:166
_Must_inspect_result_ _In_ WDFOBJECT _In_ CONST GUID * Guid
Definition: wdfobject.h:762
_In_ PSID _Out_writes_to_opt_ cchName LPSTR _Inout_ LPDWORD cchName
Definition: winbase.h:2497

◆ mbstowcs16()

size_t mbstowcs16 ( wchar_t *  wcstr,
const char *  mbstr,
size_t  count 
)

Definition at line 249 of file mkshelllink.c.

253{
254 size_t i;
255 size_t len = strlen(mbstr) + 1; // Count the NUL-terminator.
256
257 /* Convert up to the NUL-terminator (included) and at most 'count' characters */
258 count = min(count, len);
259
260 /* POSIX extension: if wcstr is NULL, return the number of wide
261 * characters that would be written to wcstr, if converted. */
262 if (!wcstr)
263 return count;
264
265 if (count == 0)
266 return (size_t)0; // dest string exists, but 0 bytes converted.
267 for (i = 0; i < count; ++i)
268 wcstr[i] = (wchar_t)mbstr[i];
269 /* Return the number of wide characters, excluding the NUL-terminator, written to wcstr */
270 return (i - 1);
271}
GLuint GLuint GLsizei count
Definition: gl.h:1545

Referenced by main(), and write_string().

◆ strip_quotes_and_unescape_envvars()

static void strip_quotes_and_unescape_envvars ( char **  pstr)
static

Definition at line 298 of file mkshelllink.c.

299{
300 char *str = *pstr;
301 char *ptr, *dst;
302
303 /* Skip leading spaces */
304 while (isspace(*str))
305 ++str;
306
307 /* Strip trailing spaces */
308 ptr = str + strlen(str);
309 while ((ptr > str) && isspace(*(ptr-1)))
310 --ptr;
311 *ptr = '\0';
312
313 /* If quoted, skip the leading and strip the trailing quotes */
314 if ((ptr > str + 1) && (*str == '"') && (*(ptr-1) == '"'))
315 {
316 ++str;
317 *(--ptr) = '\0';
318 }
319
320 /* Un-escape the '^%' in environment variables names */
321 for (dst = ptr = str; *ptr; ++ptr, ++dst)
322 {
323 if (*ptr == '^' && *(ptr+1) == '%')
324 ++ptr;
325 if (ptr > dst) // Copy characters as soon as source advances destination.
326 *dst = *ptr;
327 }
328 *dst = '\0';
329
330 /* Return the string */
331 *pstr = str;
332}
#define isspace(c)
Definition: acclib.h:69
GLenum GLenum dst
Definition: glext.h:6340

Referenced by main().

◆ trace()

static void __cdecl trace ( const char *  format,
  ... 
)
static

Definition at line 273 of file mkshelllink.c.

274{
276
277 if (!g_Verbose)
278 return;
279
282 va_end(args);
283}
int CDECL vprintf(const char *format, va_list valist)
Definition: file.c:5517
#define va_end(v)
Definition: stdarg.h:28
#define va_start(v, l)
Definition: stdarg.h:26
char * va_list
Definition: vadefs.h:50
#define args
Definition: format.c:66
Definition: match.c:390

◆ write_string()

static void write_string ( FILE *  pFile,
bool  bUnicode,
const char *  str 
)
static

Definition at line 362 of file mkshelllink.c.

363{
364 uint16_t uhTmp;
365
366 /* String length in number of ANSI or Unicode characters */
367 uhTmp = strlen(str);
368 fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
369
370 /* String data (ANSI or Unicode) */
371 if (!bUnicode)
372 {
373 fwrite(str, uhTmp, 1, pFile);
374 }
375 else
376 {
377 wchar_t tmpBufferU[1024]; // Large-enough buffer for string conversions.
378 uhTmp = (uint16_t)mbstowcs16(tmpBufferU, str, _countof(tmpBufferU));
379 fwrite(tmpBufferU, uhTmp * sizeof(wchar_t), 1, pFile);
380 }
381}

Referenced by main().

Variable Documentation

◆ g_specialfolders

const struct SPECIALFOLDER g_specialfolders[]
static
Initial value:
= {
{ CSIDL_WINDOWS, "windows", "X:\\reactos", "%SystemRoot%" },
{ CSIDL_SYSTEM, "system", "X:\\reactos\\system32", "%SystemRoot%\\system32" },
{ 0, NULL, NULL, NULL }
}

Referenced by get_special_folder().

◆ g_Verbose

bool g_Verbose = false
static

Definition at line 222 of file mkshelllink.c.

Referenced by main(), and trace().