ReactOS 0.4.17-dev-1190-g4c812f4
mkshelllink.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Shell Link maker
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Shell Link maker
5 * COPYRIGHT: Copyright 2011 Rafal Harabien <rafalh@reactos.org>
6 * Copyright 2024 Whindmar Saksit <whindsaks@proton.me>
7 * Copyright 2026 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
8 */
9
10/* INCLUDES ******************************************************************/
11
12#include <stdarg.h>
13#include <stdbool.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <ctype.h> // For isalpha(), isdigit()
18
19#ifndef C_ASSERT
20#define C_ASSERT(expr) extern char (*c_assert(void)) [(expr) ? 1 : -1]
21#endif
22
23/* Function attributes for GCC */
24#if !defined(_MSC_VER) && !defined(__cdecl)
25#define __cdecl // __attribute__((cdecl)) // warning: ‘cdecl’ attribute ignored
26#endif
27
28#ifndef _MSC_VER
29#include <stdint.h>
30#else
31typedef unsigned __int8 uint8_t;
32typedef unsigned __int16 uint16_t;
33typedef unsigned __int32 uint32_t;
34typedef __int32 int32_t;
35#endif
36
37C_ASSERT(sizeof(wchar_t) == sizeof(uint16_t)); // Ensure wchar_t is 16-bit (UTF16 character)
38
39#ifndef _countof
40#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))
41#endif
42#ifndef min
43#define min(a,b) (((a) < (b)) ? (a) : (b))
44#endif
45
46#ifdef _WIN32
47#define strcasecmp _stricmp
48#endif
49
50
51/* SHELL LINK DEFINITIONS ****************************************************/
52
53#define SW_SHOWNORMAL 1
54#define SW_SHOWMINNOACTIVE 7
55
56typedef struct _GUID
57{
63C_ASSERT(sizeof(GUID) == 16);
64
65typedef struct _FILETIME
66{
70
71#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 } }
72DEFINE_GUID2(CLSID_ShellLink, 0x00021401,0,0,0xC0,0,0,0,0,0,0,0x46);
73DEFINE_GUID2(CLSID_MyComputer,0x20D04FE0,0x3AEA,0x1069,0xA2,0xD8,0x08,0x00,0x2B,0x30,0x30,0x9D);
74
75#define LOCATOR_LOCAL 0x1
76#define LOCATOR_NETWORK 0x2
77
78#pragma pack(push, 1)
79
80/*
81 * Specification:
82 * "[MS-SHLLINK]: Shell Link (.LNK) Binary File Format"
83 * https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink/16cb4ca1-9339-4d0c-a68d-bf1d6cc0f943
84 * Definitions adapted from undocshell.h
85 */
86
87/* SHELL_LINK_HEADER flags. SHELL_LINK_DATA_FLAGS definitions taken from shlobj.h */
88#define SLDF_DEFAULT 0x00000000
89#define SLDF_HAS_ID_LIST 0x00000001
90#define SLDF_HAS_LINK_INFO 0x00000002
91#define SLDF_HAS_NAME 0x00000004
92#define SLDF_HAS_RELPATH 0x00000008
93#define SLDF_HAS_WORKINGDIR 0x00000010
94#define SLDF_HAS_ARGS 0x00000020
95#define SLDF_HAS_ICONLOCATION 0x00000040
96#define SLDF_UNICODE 0x00000080
97#define SLDF_HAS_EXP_SZ 0x00000200
98#define SLDF_HAS_EXP_ICON_SZ 0x00004000
99
100#define LINK_ID_LIST SLDF_HAS_ID_LIST
101#define LINK_FILE SLDF_HAS_LINK_INFO
102#define LINK_DESCRIPTION SLDF_HAS_NAME
103#define LINK_RELATIVE_PATH SLDF_HAS_RELPATH
104#define LINK_WORKING_DIR SLDF_HAS_WORKINGDIR
105#define LINK_CMDLINE_ARGS SLDF_HAS_ARGS
106#define LINK_ICON SLDF_HAS_ICONLOCATION
107#define LINK_UNICODE SLDF_UNICODE
108
109// SHELL_LINK_HEADER
110typedef struct _LNK_HEADER
111{
119 uint32_t FileSizeLow; /* Only the least significant 32 bits */
127
128// SHELL_LINK_INFOA
129typedef struct _LNK_LOCATOR_INFO
130{
138 char Data[0];
140
141// SHELL_LINK_INFO_VOLUME_IDA
143{
145 uint32_t VolumeType; /* See GetDriveType */
148 char VolumeLabel[0];
150
151/* For ITEMIDLIST/SHITEMID */
152#define PT_GUID 0x1F
153#define PT_DRIVE1 0x2F
154#define PT_FOLDER 0x31
155#define PT_VALUE 0x32
156
157/* uSortOrder values */
158#define REGITEMORDER_DEFAULT 0x80
159#define REGITEMORDER_LIBRARIES 0x42
160#define REGITEMORDER_USERSFILEFOLDER 0x44
161#define REGITEMORDER_MYCOMPUTER 0x50
162
163// struct tagGUIDStruct
164typedef struct _ID_LIST_GUID
165{
171
172// struct tagDriveStruct
173typedef struct _ID_LIST_DRIVE
174{
177 char szDriveName[20];
180
181// struct tagFileStruct
182typedef struct _ID_LIST_FILE
183{
191 /* Here are coming two strings. The first is the long name.
192 The second the dos name when needed or just 0x00 */
193 char szName[0];
195
196#define EXP_SPECIAL_FOLDER_SIG 0xA0000005
198{
204
205#define MAX_PATH 260
206
207#define EXP_SZ_LINK_SIG 0xA0000001
208#define EXP_SZ_ICON_SIG 0xA0000007
209typedef struct _EXP_SZ_LINK
210{
216
217#pragma pack(pop)
218
219
220/* GLOBALS *******************************************************************/
221
222static bool g_Verbose = false;
223
224/* For a complete list, see: https://smallvoid.com/article/winnt-shell-keyword.html */
225#define CSIDL_WINDOWS 0x24
226#define CSIDL_SYSTEM 0x25
227static const struct SPECIALFOLDER
228{
229 unsigned char csidl;
230 const char* name;
231 const char* dummyPath;
232 const char* unexpPath;
233} g_specialfolders[] = {
234 { CSIDL_WINDOWS, "windows", "X:\\reactos", "%SystemRoot%" },
235 { CSIDL_SYSTEM, "system", "X:\\reactos\\system32", "%SystemRoot%\\system32" },
236 { 0, NULL, NULL, NULL }
238
239
240/* FUNCTIONS *****************************************************************/
241
242/*
243 * Poor-man ANSI-to-UTF16LE conversion.
244 * We cannot use the host mbstowcs() routine, since on *nix systems the iconv
245 * library being used may have been compiled with a 32-bit wchar_t (even if
246 * the tool is compiled with: `-fshort-wchar -fwide-exec-charset=UTF-16LE`).
247 */
248size_t
250 wchar_t *wcstr,
251 const char *mbstr,
252 size_t count)
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}
272
273static void __cdecl trace(const char *format, ...)
274{
276
277 if (!g_Verbose)
278 return;
279
282 va_end(args);
283}
284
285static bool is_path_separator(char c)
286{
287 return (c == '\\' || c == '/');
288}
289
290/* Check whether a string contains Win32 environment variables,
291 * by searching for a pair of '%'. */
292static bool has_env_variables(const char *str)
293{
294 const char *ptr = strchr(str, '%');
295 return (ptr && strchr(ptr + 1, '%'));
296}
297
298static void strip_quotes_and_unescape_envvars(char **pstr)
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}
333
334static const struct SPECIALFOLDER* get_special_folder(const char *target)
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}
357
358/*
359 * Write an ANSI string buffer to the shell link,
360 * converting it to UTF16LE Unicode if necessary.
361 */
362static void write_string(FILE *pFile, bool bUnicode, const char *str)
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}
382
383int main(int argc, const char *argv[])
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 isspace(c)
Definition: acclib.h:69
#define isalpha(c)
Definition: acclib.h:74
#define trace
Definition: atltest.h:70
Definition: Header.h:9
#define NULL
Definition: types.h:112
INT32 int32_t
Definition: types.h:71
UINT32 uint32_t
Definition: types.h:75
MonoAssembly int argc
Definition: metahost.c:107
int CDECL vprintf(const char *format, va_list valist)
Definition: file.c:5517
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
#define __int8
Definition: corecrt.h:60
#define __int16
Definition: corecrt.h:63
#define __int32
Definition: corecrt.h:66
#define va_end(v)
Definition: stdarg.h:28
#define va_start(v, l)
Definition: stdarg.h:26
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 char *__cdecl strchr(const char *, int)
Definition: string.c:3291
_ACRTIMP size_t __cdecl strlen(const char *)
Definition: string.c:1597
_ACRTIMP int __cdecl strcmp(const char *, const char *)
Definition: string.c:3324
_ACRTIMP char *__cdecl strrchr(const char *, int)
Definition: string.c:3303
char * va_list
Definition: vadefs.h:50
static const WCHAR IconIndex[]
Definition: install.c:52
int main()
Definition: test.c:6
#define strcasecmp
Definition: fake.h:9
#define printf
Definition: freeldr.h:103
MdFileObject pFile
GLuint GLuint GLsizei count
Definition: gl.h:1545
const GLubyte * c
Definition: glext.h:8905
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLenum GLenum dst
Definition: glext.h:6340
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
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
static PVOID ptr
Definition: dispmode.c:27
#define sprintf
Definition: sprintf.c:45
#define argv
Definition: mplay32.c:18
#define uint32_t
Definition: nsiface.idl:61
#define int32_t
Definition: nsiface.idl:56
#define uint16_t
Definition: nsiface.idl:60
#define uint8_t
Definition: nsiface.idl:59
const WCHAR * str
strncpy
Definition: string.h:335
#define memset(x, y, z)
Definition: compat.h:39
#define args
Definition: format.c:66
DWORD idSpecialFolder
Definition: shlobj.h:2088
const char * name
Definition: mkshelllink.c:230
const char * unexpPath
Definition: mkshelllink.c:232
const char * dummyPath
Definition: mkshelllink.c:231
unsigned char csidl
Definition: mkshelllink.c:229
uint32_t idSpecialFolder
Definition: mkshelllink.c:201
uint32_t dwHighDateTime
Definition: mkshelllink.c:68
uint32_t dwLowDateTime
Definition: mkshelllink.c:67
Definition: scsiwmi.h:51
unsigned char Data4[8]
Definition: scsiwmi.h:55
uint16_t Data2
Definition: mkshelllink.c:59
uint32_t Data1
Definition: mkshelllink.c:58
uint16_t Data3
Definition: mkshelllink.c:60
uint16_t unknown
Definition: mkshelllink.c:178
char szDriveName[20]
Definition: mkshelllink.c:177
uint16_t Size
Definition: mkshelllink.c:175
char szName[0]
Definition: mkshelllink.c:193
uint16_t uFileDate
Definition: mkshelllink.c:188
uint32_t dwFileSize
Definition: mkshelllink.c:187
uint8_t Type
Definition: mkshelllink.c:185
uint16_t uFileTime
Definition: mkshelllink.c:189
uint8_t dummy
Definition: mkshelllink.c:186
uint16_t Size
Definition: mkshelllink.c:184
uint16_t uFileAttribs
Definition: mkshelllink.c:190
uint8_t uSortOrder
Definition: mkshelllink.c:168
uint8_t Type
Definition: mkshelllink.c:167
uint16_t Size
Definition: mkshelllink.c:166
uint32_t ShowCmd
Definition: mkshelllink.c:121
int32_t IconIndex
Definition: mkshelllink.c:120
uint32_t Flags
Definition: mkshelllink.c:114
uint32_t Attributes
Definition: mkshelllink.c:115
uint32_t Size
Definition: mkshelllink.c:112
uint16_t HotKey
Definition: mkshelllink.c:122
FILETIME CreationTime
Definition: mkshelllink.c:116
uint32_t FileSizeLow
Definition: mkshelllink.c:119
uint16_t Reserved1
Definition: mkshelllink.c:123
FILETIME LastWriteTime
Definition: mkshelllink.c:118
FILETIME LastAccessTime
Definition: mkshelllink.c:117
uint32_t Reserved3
Definition: mkshelllink.c:125
uint32_t Reserved2
Definition: mkshelllink.c:124
uint32_t DataOffset
Definition: mkshelllink.c:132
uint32_t LocalBasePathnameOffset
Definition: mkshelllink.c:135
uint32_t LocalVolumeInfoOffset
Definition: mkshelllink.c:134
uint32_t RemainingPathnameOffset
Definition: mkshelllink.c:137
uint32_t NetworkVolumeInfoOffset
Definition: mkshelllink.c:136
Definition: match.c:390
Definition: tools.h:99
_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