Browse Source

Use QueryFullProcessImageName() if available.

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.
Iain Patterson 5 years ago
parent
commit
94d25a5dcf
4 changed files with 34 additions and 6 deletions
  1. 3 0
      README.txt
  2. 10 5
      imports.cpp
  3. 9 0
      imports.h
  4. 12 1
      process.cpp

+ 3 - 0
README.txt

@@ -878,6 +878,9 @@ processes started by a given service:
 
     nssm processes <servicename>
 
+Note that if 32-bit NSSM is run on a 64-bit system running an older version of
+Windows than Vista it will not be able to query the paths of 64-bit processes.
+
 
 Exporting service configuration
 -------------------------------

+ 10 - 5
imports.cpp

@@ -59,14 +59,19 @@ int get_imports() {
       if (error != ERROR_PROC_NOT_FOUND) return 2;
     }
 
+    imports.QueryFullProcessImageName = (QueryFullProcessImageName_ptr) get_import(imports.kernel32, QUERYFULLPROCESSIMAGENAME_EXPORT, &error);
+    if (! imports.QueryFullProcessImageName) {
+      if (error != ERROR_PROC_NOT_FOUND) return 3;
+    }
+
     imports.SleepConditionVariableCS = (SleepConditionVariableCS_ptr) get_import(imports.kernel32, "SleepConditionVariableCS", &error);
     if (! imports.SleepConditionVariableCS) {
-      if (error != ERROR_PROC_NOT_FOUND) return 3;
+      if (error != ERROR_PROC_NOT_FOUND) return 4;
     }
 
     imports.WakeConditionVariable = (WakeConditionVariable_ptr) get_import(imports.kernel32, "WakeConditionVariable", &error);
     if (! imports.WakeConditionVariable) {
-      if (error != ERROR_PROC_NOT_FOUND) return 4;
+      if (error != ERROR_PROC_NOT_FOUND) return 5;
     }
   }
   else if (error != ERROR_MOD_NOT_FOUND) return 1;
@@ -75,14 +80,14 @@ int get_imports() {
   if (imports.advapi32) {
     imports.CreateWellKnownSid = (CreateWellKnownSid_ptr) get_import(imports.advapi32, "CreateWellKnownSid", &error);
     if (! imports.CreateWellKnownSid) {
-      if (error != ERROR_PROC_NOT_FOUND) return 6;
+      if (error != ERROR_PROC_NOT_FOUND) return 7;
     }
     imports.IsWellKnownSid = (IsWellKnownSid_ptr) get_import(imports.advapi32, "IsWellKnownSid", &error);
     if (! imports.IsWellKnownSid) {
-      if (error != ERROR_PROC_NOT_FOUND) return 7;
+      if (error != ERROR_PROC_NOT_FOUND) return 8;
     }
   }
-  else if (error != ERROR_MOD_NOT_FOUND) return 5;
+  else if (error != ERROR_MOD_NOT_FOUND) return 6;
 
   return 0;
 }

+ 9 - 0
imports.h

@@ -1,8 +1,16 @@
 #ifndef IMPORTS_H
 #define IMPORTS_H
 
+/* Some functions don't have decorated versions. */
+#ifdef UNICODE
+#define QUERYFULLPROCESSIMAGENAME_EXPORT "QueryFullProcessImageNameW"
+#else
+#define QUERYFULLPROCESSIMAGENAME_EXPORT "QueryFullProcessImageNameA"
+#endif
+
 typedef BOOL (WINAPI *AttachConsole_ptr)(DWORD);
 typedef BOOL (WINAPI *SleepConditionVariableCS_ptr)(PCONDITION_VARIABLE, PCRITICAL_SECTION, DWORD);
+typedef BOOL (WINAPI *QueryFullProcessImageName_ptr)(HANDLE, unsigned long, LPTSTR, unsigned long *);
 typedef void (WINAPI *WakeConditionVariable_ptr)(PCONDITION_VARIABLE);
 typedef BOOL (WINAPI *CreateWellKnownSid_ptr)(WELL_KNOWN_SID_TYPE, SID *, SID *, unsigned long *);
 typedef BOOL (WINAPI *IsWellKnownSid_ptr)(SID *, WELL_KNOWN_SID_TYPE);
@@ -12,6 +20,7 @@ typedef struct {
   HMODULE advapi32;
   AttachConsole_ptr AttachConsole;
   SleepConditionVariableCS_ptr SleepConditionVariableCS;
+  QueryFullProcessImageName_ptr QueryFullProcessImageName;
   WakeConditionVariable_ptr WakeConditionVariable;
   CreateWellKnownSid_ptr CreateWellKnownSid;
   IsWellKnownSid_ptr IsWellKnownSid;

+ 12 - 1
process.cpp

@@ -411,7 +411,18 @@ int print_process(nssm_service_t *service, kill_t *k) {
       buffer[i] = _T('\0');
     }
   }
-  if (! GetModuleFileNameEx(k->process_handle, NULL, exe, _countof(exe))) _sntprintf_s(exe, _countof(exe), _TRUNCATE, _T("???"));
+
+  unsigned long size = _countof(exe);
+  if (! imports.QueryFullProcessImageName || ! imports.QueryFullProcessImageName(k->process_handle, 0, exe, &size)) {
+    /*
+      Fall back to GetModuleFileNameEx(), which won't work for WOW64 processes.
+    */
+    if (! GetModuleFileNameEx(k->process_handle, NULL, exe, _countof(exe))) {
+      long error = GetLastError();
+      if (error == ERROR_PARTIAL_COPY) _sntprintf_s(exe, _countof(exe), _TRUNCATE, _T("[WOW64]"));
+      else _sntprintf_s(exe, _countof(exe), _TRUNCATE, _T("???"));
+    }
+  }
 
   _tprintf(_T("% 8lu %s%s\n"), k->pid, buffer ? buffer : _T(""), exe);