Last active
January 19, 2021 07:54
-
-
Save jay/19aba48653bd591cf4b90eb9249a302c to your computer and use it in GitHub Desktop.
Display how arguments are parsed in Windows
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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