Browse Source

AttachConsole() isn't available in Windows 2000.

Instead of calling AttachConsole() directory use a function pointer in
the new global imports struct.  It's safe to skip any attempt to attach
to the console when the function isn't available.
Iain Patterson 10 years ago
parent
commit
e42e6900a5
9 changed files with 138 additions and 2 deletions
  1. 56 0
      imports.cpp
  2. 16 0
      imports.h
  3. 35 0
      messages.mc
  4. 5 0
      nssm.cpp
  5. 8 0
      nssm.dsp
  6. 1 0
      nssm.h
  7. 8 0
      nssm.vcproj
  8. 6 1
      process.cpp
  9. 3 1
      service.cpp

+ 56 - 0
imports.cpp

@@ -0,0 +1,56 @@
+#include "nssm.h"
+
+imports_t imports;
+
+/*
+  Try to set up function pointers.
+  In this first implementation it is not an error if we can't load them
+  because we aren't currently trying to load any functions which we
+  absolutely need.  If we later add some indispensible imports we can
+  return non-zero here to force an application exit.
+*/
+HMODULE get_dll(const char *dll, unsigned long *error) {
+  *error = 0;
+
+  HMODULE ret = LoadLibrary(dll);
+  if (! ret) {
+    *error = GetLastError();
+    log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_LOADLIBRARY_FAILED, dll, error_string(*error));
+  }
+
+  return ret;
+}
+
+FARPROC get_import(HMODULE library, const char *function, unsigned long *error) {
+  *error = 0;
+
+  FARPROC ret = GetProcAddress(library, function);
+  if (! ret) {
+    *error = GetLastError();
+    log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_GETPROCADDRESS_FAILED, function, error_string(*error));
+  }
+
+  return ret;
+}
+
+int get_imports() {
+  unsigned long error;
+
+  ZeroMemory(&imports, sizeof(imports));
+
+  imports.kernel32 = get_dll("kernel32.dll", &error);
+  if (imports.kernel32) {
+    imports.AttachConsole = (AttachConsole_ptr) get_import(imports.kernel32, "AttachConsole", &error);
+    if (! imports.AttachConsole) {
+      if (error != ERROR_PROC_NOT_FOUND) return 2;
+    }
+  }
+  else if (error != ERROR_MOD_NOT_FOUND) return 1;
+
+  return 0;
+}
+
+void free_imports() {
+  if (imports.kernel32) FreeLibrary(imports.kernel32);
+  ZeroMemory(&imports, sizeof(imports));
+}

+ 16 - 0
imports.h

@@ -0,0 +1,16 @@
+#ifndef IMPORTS_H
+#define IMPORTS_H
+
+typedef BOOL (WINAPI *AttachConsole_ptr)(DWORD);
+
+typedef struct {
+  HMODULE kernel32;
+  AttachConsole_ptr AttachConsole;
+} imports_t;
+
+HMODULE get_dll(const char *, unsigned long *);
+FARPROC get_import(HMODULE, const char *, unsigned long *);
+int get_imports();
+void free_imports();
+
+#endif

+ 35 - 0
messages.mc

@@ -1270,3 +1270,38 @@ The service %1 is stopping but PID %2 is still running.
 Usually %3 will call TerminateProcess() as a last resort to ensure that the process is stopped but the registry value %4 has been set and not all process termination methods have been attempted.
 It will no longer be possible to attempt to control the application and the service will report a stopped status.
 .
+
+MessageId = +1
+SymbolicName = NSSM_EVENT_LOADLIBRARY_FAILED
+Severity = Warning
+Language = English
+Error loading the %1 DLL!
+LoadLibrary() failed:
+%2
+.
+Language = French
+Erreur à l'ouverture de la DLL %1!
+LoadLibrary() a échoué:
+%2
+.
+Language = Italian
+Errore apertura DLL %1!
+Chiamata a LoadLibrary() fallita:
+%2
+.
+
+MessageId = +1
+SymbolicName = NSSM_EVENT_GETPROCADDRESS_FAILED
+Severity = Warning
+Language = English
+GetProcAddress(%1) failed:
+%2
+.
+Language = French
+GetProcAddress(%1) a échoué:
+%2
+.
+Language = Italian
+Chiamata a GetProcAddress(%1) fallita:
+%2
+.

+ 5 - 0
nssm.cpp

@@ -2,6 +2,7 @@
 
 extern unsigned long tls_index;
 extern bool is_admin;
+extern imports_t imports;
 
 /* String function */
 int str_equiv(const char *a, const char *b) {
@@ -69,6 +70,9 @@ int main(int argc, char **argv) {
     This will save time when running with no arguments from a command prompt.
   */
   if (_fileno(stdin) < 0) {
+    /* Set up function pointers. */
+    if (get_imports()) exit(111);
+
     /* Start service magic */
     SERVICE_TABLE_ENTRY table[] = { { NSSM, service_main }, { 0, 0 } };
     if (! StartServiceCtrlDispatcher(table)) {
@@ -76,6 +80,7 @@ int main(int argc, char **argv) {
       /* User probably ran nssm with no argument */
       if (error == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) exit(usage(1));
       log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DISPATCHER_FAILED, error_string(error), 0);
+      free_imports();
       exit(100);
     }
   }

+ 8 - 0
nssm.dsp

@@ -96,6 +96,10 @@ SOURCE=.\gui.cpp
 # End Source File
 # Begin Source File
 
+SOURCE=.\imports.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\io.cpp
 # End Source File
 # Begin Source File
@@ -128,6 +132,10 @@ SOURCE=.\gui.h
 # End Source File
 # Begin Source File
 
+SOURCE=.\imports.h
+# End Source File
+# Begin Source File
+
 SOURCE=.\io.h
 # End Source File
 # Begin Source File

+ 1 - 0
nssm.h

@@ -7,6 +7,7 @@
 #include <stdio.h>
 #include <windows.h>
 #include "event.h"
+#include "imports.h"
 #include "messages.h"
 #include "process.h"
 #include "registry.h"

+ 8 - 0
nssm.vcproj

@@ -466,6 +466,10 @@
 					/>
 				</FileConfiguration>
 			</File>
+			<File
+				RelativePath=".\imports.cpp"
+				>
+			</File>
 			<File
 				RelativePath=".\io.cpp"
 				>
@@ -627,6 +631,10 @@
 				RelativePath="gui.h"
 				>
 			</File>
+			<File
+				RelativePath=".\imports.h"
+				>
+			</File>
 			<File
 				RelativePath=".\io.h"
 				>

+ 6 - 1
process.cpp

@@ -1,5 +1,7 @@
 #include "nssm.h"
 
+extern imports_t imports;
+
 int get_process_creation_time(HANDLE process_handle, FILETIME *ft) {
   FILETIME creation_time, exit_time, kernel_time, user_time;
 
@@ -186,8 +188,11 @@ int kill_process(char *service_name, unsigned long stop_method, HANDLE process_h
 int kill_console(char *service_name, HANDLE process_handle, unsigned long pid) {
   unsigned long ret;
 
+  /* Check we loaded AttachConsole(). */
+  if (! imports.AttachConsole) return 4;
+
   /* Try to attach to the process's console. */
-  if (! AttachConsole(pid)) {
+  if (! imports.AttachConsole(pid)) {
     ret = GetLastError();
 
     switch (ret) {

+ 3 - 1
service.cpp

@@ -538,7 +538,9 @@ void CALLBACK end_service(void *arg, unsigned char why) {
     /* Fake a crash so pre-Vista service managers will run recovery actions. */
     case NSSM_EXIT_UNCLEAN:
       log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_EXIT_UNCLEAN, service_name, code, exit_action_strings[action], 0);
-      exit(stop_service(exitcode, false, default_action));
+      stop_service(exitcode, false, default_action);
+      free_imports();
+      exit(exitcode);
     break;
   }
 }