Skip to content

Instantly share code, notes, and snippets.

@jay
Last active January 19, 2021 07:54
Show Gist options
  • Save jay/19aba48653bd591cf4b90eb9249a302c to your computer and use it in GitHub Desktop.
Save jay/19aba48653bd591cf4b90eb9249a302c to your computer and use it in GitHub Desktop.
Display how arguments are parsed in Windows
/*
Display how arguments are parsed in Windows.
VS 2010 x86:
cl /nologo /W4 getargs.c /MD /Fegetargs-cl && getargs-cl
VS 2010 x86, for win2k compatibility build against the WinDDK:
cl /nologo /W4 getargs.c /MD /Fegetargs-cl C:\WinDDK\7600.16385.1\lib\win7\i386\msvcrt_win2000.obj /IC:\WinDDK\7600.16385.1\inc\crt /link /SUBSYSTEM:CONSOLE,5.00 /OSVERSION:5.00 /LIBPATH:C:\WinDDK\7600.16385.1\lib\Crt\i386 && getargs-cl
mingw x86:
gcc -Wall -o getargs-gcc getargs.c -lpsapi && getargs-gcc
Copyright (C) 2016 Jay Satiro <raysatiro@yahoo.com>
http://curl.haxx.se/docs/copyright.html
https://curl.haxx.se/mail/archive-2016-12/0049.html
https://gist.github.com/jay/19aba48653bd591cf4b90eb9249a302c
*/
/*
Dev notes:
To print wide character strings (which are converted by the CRT to ANSI) use
[f]wprintf %s instead of printf %S because the latter will stop printing the
format string if conversion of the wide character string fails.
Additionally it seems gcc/MinGW builds cannot handle unicode characters at the
command line, therefore something like (UTF-8 encoded) getargs-gcc спасти
causes the parser to erroneously create argv that are actually directory names.
*/
#ifdef _MSC_VER
#pragma warning(disable: 4996) /* deprecated functions */
#pragma comment(lib, "psapi.lib")
#endif
#define _CRT_SECURE_NO_WARNINGS
#define _WIN32_WINNT 0x0500
#define PSAPI_VERSION 1
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <psapi.h>
#include <tlhelp32.h>
#ifndef PROCESS_QUERY_LIMITED_INFORMATION
#define PROCESS_QUERY_LIMITED_INFORMATION 0x1000
#endif
OSVERSIONINFO ver = { sizeof ver, };
DWORD (WINAPI *pGetProcessImageFileNameA)(HANDLE, LPSTR, DWORD) = NULL;
DWORD GetParentProcessId();
char *GetProcessPathname(DWORD);
int main(int argc, char **argv)
{
int i;
DWORD parent_pid;
wchar_t path[32767];
HMODULE psapi;
printf("\n");
if(!GetVersionEx(&ver)) {
fprintf(stderr, "FATAL: GetVersionEx failed, gle: %I32u\n",
GetLastError());
exit(1);
}
psapi = LoadLibraryA("psapi");
if(psapi) {
pGetProcessImageFileNameA = (DWORD (WINAPI *)(HANDLE, LPSTR, DWORD))
GetProcAddress(psapi, "GetProcessImageFileNameA");
}
if(GetEnvironmentVariableW(L"PATH", path, sizeof path) < sizeof path) {
wprintf(L"PATH=%s\n\n", path);
}
else {
fprintf(stderr, "ERROR: GetEnvironmentVariableW failed, gle: %I32u\n",
GetLastError());
}
parent_pid = GetParentProcessId();
if(parent_pid) {
char *parent_path = GetProcessPathname(parent_pid);
printf("Parent id: %I32u\n", parent_pid);
printf("Parent path: %s\n\n", parent_path ? parent_path : "");
}
else {
fprintf(stderr, "ERROR: GetParentProcessId failed!\n");
}
// If conversion fails it shows ?????? in cl builds and nothing in gcc builds
wprintf(L"GetCommandLineW: %s\n\n", GetCommandLineW());
for(i = 0; i < argc; ++i) {
printf("argv[%d]: %s\n", i, argv[i]);
}
return 1;
}
DWORD GetParentProcessId()
{
BOOL b;
DWORD our_pid = GetCurrentProcessId();
PROCESSENTRY32 pe = { sizeof pe, };
HANDLE snapshot;
static DWORD parent_pid;
if(parent_pid)
return parent_pid;
snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(snapshot == INVALID_HANDLE_VALUE) {
fprintf(stderr, "ERROR: CreateToolhelp32Snapshot failed creating process "
"list, gle: %I32u\n",
GetLastError());
return parent_pid;
}
for(b = Process32First(snapshot, &pe); b; b = Process32Next(snapshot, &pe)) {
if(our_pid == pe.th32ProcessID) {
parent_pid = pe.th32ParentProcessID;
break;
}
}
if(!parent_pid)
fprintf(stderr, "ERROR: Parent pid not found in process list!\n");
CloseHandle(snapshot);
return parent_pid;
}
// Returns pathname of a process or NULL on error
// pathname is freed by caller
char *GetProcessPathname(DWORD process_id)
{
int i;
HANDLE process;
DWORD drives;
char *path, buf[32768], buf2[32768];
process = OpenProcess((!pGetProcessImageFileNameA ?
(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ):
((ver.dwMajorVersion <= 5) ?
PROCESS_QUERY_INFORMATION :
PROCESS_QUERY_LIMITED_INFORMATION)),
FALSE, process_id);
if(!process) {
fprintf(stderr, "ERROR: OpenProcess failed opening process id "
"%I32u, gle: %I32u\n",
process_id, GetLastError());
return NULL;
}
if(pGetProcessImageFileNameA) {
if(!pGetProcessImageFileNameA(process, buf, sizeof buf)) {
fprintf(stderr, "ERROR: GetProcessImageFileName failed getting the path "
"of process id %I32u, gle: %I32u\n",
process_id, GetLastError());
return NULL;
}
drives = GetLogicalDrives();
if(!drives) {
fprintf(stderr, "ERROR: GetLogicalDrives failed, gle: %I32u\n",
GetLastError());
return NULL;
}
for(i = 0; i < 26; ++i) {
size_t rootlen;
char dev[] = "A:";
if(!(drives & (1 << i)))
continue;
dev[0] += (char)i;
if(!QueryDosDeviceA(dev, buf2, sizeof buf2) || !buf2[0])
continue;
rootlen = strlen(buf2);
if(buf2[rootlen - 1] != '\\') {
if(rootlen + 1 == sizeof buf2)
continue;
buf2[rootlen] = '\\';
++rootlen;
buf2[rootlen] = 0;
}
if(!strncmp(buf, buf2, rootlen)) {
size_t buflen = strlen(buf);
size_t devlen = strlen(dev);
if(buflen - rootlen + devlen + 1 /* \ */ + 1 > sizeof buf)
continue;
memmove(&buf[devlen + 1], &buf[rootlen], buflen - rootlen + 1);
strcpy(buf, dev);
buf[devlen] = '\\';
break;
}
}
}
/* GetProcessImageFileNameA is not in Win2k so use GetModuleFileNameExA */
else {
if(ver.dwMajorVersion > 5 ||
(ver.dwMajorVersion == 5 && ver.dwMinorVersion > 0)) {
fprintf(stderr, "ERROR: GetProcessImageFileNameA not found, falling "
"back on GetModuleFileNameExA\n");
}
if(!GetModuleFileNameExA(process, NULL, buf, sizeof buf)) {
fprintf(stderr, "ERROR: GetModuleFileNameExA failed getting the path "
"of process id %I32u, gle: %I32u\n",
process_id, GetLastError());
return NULL;
}
}
path = malloc(strlen(buf) + 1);
if(!path) {
fprintf(stderr, "ERROR: malloc out of memory\n");
return NULL;
}
strcpy(path, buf);
return path;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment