[MKSHELLLINK] Add a verbose mode for diagnostics, disabled by default (#8936)

This commit is contained in:
Hermès Bélusca-Maïto
2026-05-03 22:47:13 +02:00
parent af0cb55edb
commit bc70254ad9

View File

@@ -9,6 +9,7 @@
/* INCLUDES ******************************************************************/
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@@ -19,6 +20,11 @@
#define C_ASSERT(expr) extern char (*c_assert(void)) [(expr) ? 1 : -1]
#endif
/* Function attributes for GCC */
#if !defined(_MSC_VER) && !defined(__cdecl)
#define __cdecl // __attribute__((cdecl)) // warning: cdecl attribute ignored
#endif
#ifndef _MSC_VER
#include <stdint.h>
#else
@@ -213,6 +219,8 @@ typedef struct _EXP_SZ_LINK
/* GLOBALS *******************************************************************/
static bool g_Verbose = false;
/* For a complete list, see: https://smallvoid.com/article/winnt-shell-keyword.html */
#define CSIDL_WINDOWS 0x24
#define CSIDL_SYSTEM 0x25
@@ -263,6 +271,18 @@ my_mbstowcs(
}
#define mbstowcs my_mbstowcs
static void __cdecl trace(const char *format, ...)
{
va_list args;
if (!g_Verbose)
return;
va_start(args, format);
vprintf(format, args);
va_end(args);
}
static bool is_path_separator(char c)
{
return (c == '\\' || c == '/');
@@ -346,28 +366,65 @@ int main(int argc, const char *argv[])
EXP_SZ_LINK SzLinkBlock, *pSzLinkBlock = NULL;
EXP_SZ_LINK SzIconBlock, *pSzIconBlock = NULL;
/* Check for verbose mode in the command-line */
for (i = 1; i < argc; ++i)
{
if ((argv[i][0] == '-' || argv[i][0] == '/') &&
!strcmp(argv[i] + 1, "v"))
{
g_Verbose = true;
break;
}
}
/* Parse the command-line */
for (i = 1; i < argc; ++i)
{
trace("argv[%d]: %s\n", i, argv[i]);
if (argv[i][0] != '-' && argv[i][0] != '/')
pszTarget = argv[i];
else if (!strcmp(argv[i] + 1, "h"))
bHelp = true;
else if (!strcmp(argv[i] + 1, "v"))
/* Verbose mode, separately handled above */;
else if (!strcmp(argv[i] + 1, "o") && (i + 1 < argc))
pszOutputPath = argv[++i];
{
++i;
trace("argv[%d]: %s\n", i, argv[i]);
pszOutputPath = argv[i];
}
else if (!strcmp(argv[i] + 1, "u"))
bUnicode = true;
else if (!strcmp(argv[i] + 1, "d") && (i + 1 < argc))
pszDescription = argv[++i];
{
++i;
trace("argv[%d]: %s\n", i, argv[i]);
pszDescription = argv[i];
}
else if (!strcmp(argv[i] + 1, "w") && (i + 1 < argc))
pszWorkingDir = argv[++i];
{
++i;
trace("argv[%d]: %s\n", i, argv[i]);
pszWorkingDir = argv[i];
}
else if (!strcmp(argv[i] + 1, "c") && (i + 1 < argc))
pszCmdLineArgs = argv[++i];
{
++i;
trace("argv[%d]: %s\n", i, argv[i]);
pszCmdLineArgs = argv[i];
}
else if (!strcmp(argv[i] + 1, "i") && (i + 1 < argc))
{
pszIcon = argv[++i];
++i;
trace("argv[%d]: %s\n", i, argv[i]);
pszIcon = argv[i];
if ((i + 1 < argc) && isdigit(argv[i + 1][0]))
IconIndex = atoi(argv[++i]);
{
++i;
trace("argv[%d]: %s\n", i, argv[i]);
IconIndex = atoi(argv[i]);
}
}
else if (!strcmp(argv[i] + 1, "m"))
bMinimized = true;
@@ -375,7 +432,9 @@ int main(int argc, const char *argv[])
{
unsigned Data4Tmp[8], j;
sscanf(argv[++i], "{%8x-%4hx-%4hx-%2x%2x-%2x%2x%2x%2x%2x%2x}",
++i;
trace("argv[%d]: %s\n", i, argv[i]);
sscanf(argv[i], "{%8x-%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]);
@@ -388,11 +447,14 @@ int main(int argc, const char *argv[])
bHelp = true;
}
}
if (argc > 1)
trace("\n");
if (!pszTarget || bHelp)
{
printf("Usage: %s [-h][-o path][-u][-d descr][-w path][-c cmdline_args][-i icon_path [nr]][-g guid] target\n"
printf("Usage: %s [-h][-v][-o path][-u][-d descr][-w path][-c cmdline_args][-i icon_path [nr]][-g guid] target\n"
"-h\tShows this help.\n"
"-v\tEnables verbose mode for diagnostics.\n"
"-o path\tSets the output path.\n"
"-u\tCreates a Unicode-aware shortcut.\n"
"-d descr\tSets the shortcut description.\n"
@@ -405,6 +467,16 @@ int main(int argc, const char *argv[])
return 0;
}
trace("OutputPath = %s\n"
"Target = %s\n"
"Description = %s\n"
"WorkingDir = %s\n"
"CmdLineArgs = %s\n"
"Icon = %s (%d)\n\n",
pszOutputPath, pszTarget, pszDescription,
pszWorkingDir, pszCmdLineArgs,
pszIcon, IconIndex);
pFile = fopen(pszOutputPath, "wb");
if (!pFile)
{
@@ -453,6 +525,11 @@ int main(int argc, const char *argv[])
if (pszIcon && has_env_variables(pszIcon))
Header.Flags |= SLDF_HAS_EXP_ICON_SZ;
trace("Header.Flags = 0x%08x\n"
"Header.IconIndex = %d\n"
"Header.ShowCmd = %u\n",
Header.Flags, Header.IconIndex, Header.ShowCmd);
fwrite(&Header, sizeof(Header), 1, pFile);
if (Header.Flags & LINK_ID_LIST)