Use QueryFullProcessImageName() if available.
authorIain Patterson <me@iain.cx>
Wed, 27 Jul 2016 11:21:01 +0000 (12:21 +0100)
committerIain Patterson <me@iain.cx>
Thu, 28 Jul 2016 15:44:36 +0000 (16:44 +0100)
A 32-bit process running on 64-bit Windows can't read the image name of
a 64-bit process, so printing the process tree will fail.  However, on
Windows Vista or later we have QueryFullProcessImageName() which is able
to retrieve the path.

README.txt
imports.cpp
imports.h
process.cpp

index cc63c5d..e59326f 100644 (file)
@@ -878,6 +878,9 @@ processes started by a given service:
 \r
     nssm processes <servicename>\r
 \r
+Note that if 32-bit NSSM is run on a 64-bit system running an older version of\r
+Windows than Vista it will not be able to query the paths of 64-bit processes.\r
+\r
 \r
 Exporting service configuration\r
 -------------------------------\r
index 230bf43..f50591c 100644 (file)
@@ -59,14 +59,19 @@ int get_imports() {
       if (error != ERROR_PROC_NOT_FOUND) return 2;\r
     }\r
 \r
+    imports.QueryFullProcessImageName = (QueryFullProcessImageName_ptr) get_import(imports.kernel32, QUERYFULLPROCESSIMAGENAME_EXPORT, &error);\r
+    if (! imports.QueryFullProcessImageName) {\r
+      if (error != ERROR_PROC_NOT_FOUND) return 3;\r
+    }\r
+\r
     imports.SleepConditionVariableCS = (SleepConditionVariableCS_ptr) get_import(imports.kernel32, "SleepConditionVariableCS", &error);\r
     if (! imports.SleepConditionVariableCS) {\r
-      if (error != ERROR_PROC_NOT_FOUND) return 3;\r
+      if (error != ERROR_PROC_NOT_FOUND) return 4;\r
     }\r
 \r
     imports.WakeConditionVariable = (WakeConditionVariable_ptr) get_import(imports.kernel32, "WakeConditionVariable", &error);\r
     if (! imports.WakeConditionVariable) {\r
-      if (error != ERROR_PROC_NOT_FOUND) return 4;\r
+      if (error != ERROR_PROC_NOT_FOUND) return 5;\r
     }\r
   }\r
   else if (error != ERROR_MOD_NOT_FOUND) return 1;\r
@@ -75,14 +80,14 @@ int get_imports() {
   if (imports.advapi32) {\r
     imports.CreateWellKnownSid = (CreateWellKnownSid_ptr) get_import(imports.advapi32, "CreateWellKnownSid", &error);\r
     if (! imports.CreateWellKnownSid) {\r
-      if (error != ERROR_PROC_NOT_FOUND) return 6;\r
+      if (error != ERROR_PROC_NOT_FOUND) return 7;\r
     }\r
     imports.IsWellKnownSid = (IsWellKnownSid_ptr) get_import(imports.advapi32, "IsWellKnownSid", &error);\r
     if (! imports.IsWellKnownSid) {\r
-      if (error != ERROR_PROC_NOT_FOUND) return 7;\r
+      if (error != ERROR_PROC_NOT_FOUND) return 8;\r
     }\r
   }\r
-  else if (error != ERROR_MOD_NOT_FOUND) return 5;\r
+  else if (error != ERROR_MOD_NOT_FOUND) return 6;\r
 \r
   return 0;\r
 }\r
index 008a702..5c79cb4 100644 (file)
--- a/imports.h
+++ b/imports.h
@@ -1,8 +1,16 @@
 #ifndef IMPORTS_H\r
 #define IMPORTS_H\r
 \r
+/* Some functions don't have decorated versions. */\r
+#ifdef UNICODE\r
+#define QUERYFULLPROCESSIMAGENAME_EXPORT "QueryFullProcessImageNameW"\r
+#else\r
+#define QUERYFULLPROCESSIMAGENAME_EXPORT "QueryFullProcessImageNameA"\r
+#endif\r
+\r
 typedef BOOL (WINAPI *AttachConsole_ptr)(DWORD);\r
 typedef BOOL (WINAPI *SleepConditionVariableCS_ptr)(PCONDITION_VARIABLE, PCRITICAL_SECTION, DWORD);\r
+typedef BOOL (WINAPI *QueryFullProcessImageName_ptr)(HANDLE, unsigned long, LPTSTR, unsigned long *);\r
 typedef void (WINAPI *WakeConditionVariable_ptr)(PCONDITION_VARIABLE);\r
 typedef BOOL (WINAPI *CreateWellKnownSid_ptr)(WELL_KNOWN_SID_TYPE, SID *, SID *, unsigned long *);\r
 typedef BOOL (WINAPI *IsWellKnownSid_ptr)(SID *, WELL_KNOWN_SID_TYPE);\r
@@ -12,6 +20,7 @@ typedef struct {
   HMODULE advapi32;\r
   AttachConsole_ptr AttachConsole;\r
   SleepConditionVariableCS_ptr SleepConditionVariableCS;\r
+  QueryFullProcessImageName_ptr QueryFullProcessImageName;\r
   WakeConditionVariable_ptr WakeConditionVariable;\r
   CreateWellKnownSid_ptr CreateWellKnownSid;\r
   IsWellKnownSid_ptr IsWellKnownSid;\r
index dc99597..e78283c 100644 (file)
@@ -411,7 +411,18 @@ int print_process(nssm_service_t *service, kill_t *k) {
       buffer[i] = _T('\0');\r
     }\r
   }\r
-  if (! GetModuleFileNameEx(k->process_handle, NULL, exe, _countof(exe))) _sntprintf_s(exe, _countof(exe), _TRUNCATE, _T("???"));\r
+\r
+  unsigned long size = _countof(exe);\r
+  if (! imports.QueryFullProcessImageName || ! imports.QueryFullProcessImageName(k->process_handle, 0, exe, &size)) {\r
+    /*\r
+      Fall back to GetModuleFileNameEx(), which won't work for WOW64 processes.\r
+    */\r
+    if (! GetModuleFileNameEx(k->process_handle, NULL, exe, _countof(exe))) {\r
+      long error = GetLastError();\r
+      if (error == ERROR_PARTIAL_COPY) _sntprintf_s(exe, _countof(exe), _TRUNCATE, _T("[WOW64]"));\r
+      else _sntprintf_s(exe, _countof(exe), _TRUNCATE, _T("???"));\r
+    }\r
+  }\r
 \r
   _tprintf(_T("% 8lu %s%s\n"), k->pid, buffer ? buffer : _T(""), exe);\r
 \r