소스 검색

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 년 전
부모
커밋
e42e6900a5
9개의 변경된 파일138개의 추가작업 그리고 2개의 파일을 삭제
  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;
   }
 }