AttachConsole() isn't available in Windows 2000.
authorIain Patterson <me@iain.cx>
Tue, 12 Nov 2013 10:50:21 +0000 (10:50 +0000)
committerIain Patterson <me@iain.cx>
Tue, 12 Nov 2013 12:49:52 +0000 (12:49 +0000)
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.

imports.cpp [new file with mode: 0644]
imports.h [new file with mode: 0644]
messages.mc
nssm.cpp
nssm.dsp
nssm.h
nssm.vcproj
process.cpp
service.cpp

diff --git a/imports.cpp b/imports.cpp
new file mode 100644 (file)
index 0000000..49483d4
--- /dev/null
@@ -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));
+}
diff --git a/imports.h b/imports.h
new file mode 100644 (file)
index 0000000..f731ad6
--- /dev/null
+++ b/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
index 0aea1ae..8b6c984 100644 (file)
@@ -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
+.
index 1ee38bd..0ce8664 100644 (file)
--- a/nssm.cpp
+++ b/nssm.cpp
@@ -2,6 +2,7 @@
 \r
 extern unsigned long tls_index;\r
 extern bool is_admin;\r
+extern imports_t imports;\r
 \r
 /* String function */\r
 int str_equiv(const char *a, const char *b) {\r
@@ -69,6 +70,9 @@ int main(int argc, char **argv) {
     This will save time when running with no arguments from a command prompt.\r
   */\r
   if (_fileno(stdin) < 0) {\r
+    /* Set up function pointers. */\r
+    if (get_imports()) exit(111);\r
+\r
     /* Start service magic */\r
     SERVICE_TABLE_ENTRY table[] = { { NSSM, service_main }, { 0, 0 } };\r
     if (! StartServiceCtrlDispatcher(table)) {\r
@@ -76,6 +80,7 @@ int main(int argc, char **argv) {
       /* User probably ran nssm with no argument */\r
       if (error == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) exit(usage(1));\r
       log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DISPATCHER_FAILED, error_string(error), 0);\r
+      free_imports();\r
       exit(100);\r
     }\r
   }\r
index a643e4d..2ac2b34 100644 (file)
--- a/nssm.dsp
+++ b/nssm.dsp
@@ -96,6 +96,10 @@ SOURCE=.\gui.cpp
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\imports.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\io.cpp\r
 # End Source File\r
 # Begin Source File\r
@@ -128,6 +132,10 @@ SOURCE=.\gui.h
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\imports.h\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\io.h\r
 # End Source File\r
 # Begin Source File\r
diff --git a/nssm.h b/nssm.h
index afff8c4..d297527 100644 (file)
--- a/nssm.h
+++ b/nssm.h
@@ -7,6 +7,7 @@
 #include <stdio.h>\r
 #include <windows.h>\r
 #include "event.h"\r
+#include "imports.h"\r
 #include "messages.h"\r
 #include "process.h"\r
 #include "registry.h"\r
index 2b16220..040039d 100755 (executable)
                                        />\r
                                </FileConfiguration>\r
                        </File>\r
+                       <File\r
+                               RelativePath=".\imports.cpp"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath=".\io.cpp"\r
                                >\r
                                RelativePath="gui.h"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath=".\imports.h"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath=".\io.h"\r
                                >\r
index 4c00e64..ee88af3 100644 (file)
@@ -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) {
index f82b9bd..fcb1c5a 100644 (file)
@@ -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. */\r
     case NSSM_EXIT_UNCLEAN:\r
       log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_EXIT_UNCLEAN, service_name, code, exit_action_strings[action], 0);\r
-      exit(stop_service(exitcode, false, default_action));\r
+      stop_service(exitcode, false, default_action);\r
+      free_imports();\r
+      exit(exitcode);\r
     break;\r
   }\r
 }\r