Browse Source

Allow compiling as a Unicode application.

Overhaul the entire codebase so that it compiles and runs as either a
Unicode or ANSI application.
Iain Patterson 12 năm trước cách đây
mục cha
commit
5b9e64a9ae
17 tập tin đã thay đổi với 310 bổ sung296 xóa
  1. 23 23
      event.cpp
  2. 2 2
      event.h
  3. 43 39
      gui.cpp
  4. 1 1
      gui.h
  5. 2 2
      imports.cpp
  6. 1 1
      imports.h
  7. 19 19
      io.cpp
  8. 3 3
      io.h
  9. 12 0
      messages.mc
  10. 14 15
      nssm.cpp
  11. 6 5
      nssm.h
  12. 11 11
      process.cpp
  13. 1 1
      process.h
  14. 59 63
      registry.cpp
  15. 28 28
      registry.h
  16. 70 68
      service.cpp
  17. 15 15
      service.h

+ 23 - 23
event.cpp

@@ -5,27 +5,27 @@
 unsigned long tls_index;
 
 /* Convert error code to error string - must call LocalFree() on return value */
-char *error_string(unsigned long error) {
+TCHAR *error_string(unsigned long error) {
   /* Thread-safe buffer */
-  char *error_message = (char *) TlsGetValue(tls_index);
+  TCHAR *error_message = (TCHAR *) TlsGetValue(tls_index);
   if (! error_message) {
-    error_message = (char *) LocalAlloc(LPTR, NSSM_ERROR_BUFSIZE);
-    if (! error_message) return "<out of memory for error message>";
+    error_message = (TCHAR *) LocalAlloc(LPTR, NSSM_ERROR_BUFSIZE);
+    if (! error_message) return _T("<out of memory for error message>");
     TlsSetValue(tls_index, (void *) error_message);
   }
 
-  if (! FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char *) error_message, NSSM_ERROR_BUFSIZE, 0)) {
-    if (_snprintf_s(error_message, NSSM_ERROR_BUFSIZE, _TRUNCATE, "system error %lu", error) < 0) return 0;
+  if (! FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (TCHAR *) error_message, NSSM_ERROR_BUFSIZE, 0)) {
+    if (_sntprintf_s(error_message, NSSM_ERROR_BUFSIZE, _TRUNCATE, _T("system error %lu"), error) < 0) return 0;
   }
   return error_message;
 }
 
 /* Convert message code to format string */
-char *message_string(unsigned long error) {
-  char *ret;
-  if (! FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, 0, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &ret, NSSM_ERROR_BUFSIZE, 0)) {
-    ret = (char *) HeapAlloc(GetProcessHeap(), 0, 32);
-    if (_snprintf_s(ret, NSSM_ERROR_BUFSIZE, _TRUNCATE, "system error %lu", error) < 0) return 0;
+TCHAR *message_string(unsigned long error) {
+  TCHAR *ret;
+  if (! FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, 0, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &ret, NSSM_ERROR_BUFSIZE, 0)) {
+    ret = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, 32 * sizeof(TCHAR));
+    if (_sntprintf_s(ret, NSSM_ERROR_BUFSIZE, _TRUNCATE, _T("system error %lu"), error) < 0) return 0;
   }
   return ret;
 }
@@ -34,20 +34,20 @@ char *message_string(unsigned long error) {
 void log_event(unsigned short type, unsigned long id, ...) {
   va_list arg;
   int count;
-  char *s;
-  char *strings[NSSM_NUM_EVENT_STRINGS];
+  TCHAR *s;
+  TCHAR *strings[NSSM_NUM_EVENT_STRINGS];
 
   /* Open event log */
-  HANDLE handle = RegisterEventSource(0, TEXT(NSSM));
+  HANDLE handle = RegisterEventSource(0, NSSM);
   if (! handle) return;
 
   /* Log it */
   count = 0;
   va_start(arg, id);
-  while ((s = va_arg(arg, char *)) && count < NSSM_NUM_EVENT_STRINGS - 1) strings[count++] = s;
+  while ((s = va_arg(arg, TCHAR *)) && count < NSSM_NUM_EVENT_STRINGS - 1) strings[count++] = s;
   strings[count] = 0;
   va_end(arg);
-  ReportEvent(handle, type, 0, id, 0, count, 0, (const char **) strings, 0);
+  ReportEvent(handle, type, 0, id, 0, count, 0, (const TCHAR **) strings, 0);
 
   /* Close event log */
   DeregisterEventSource(handle);
@@ -57,11 +57,11 @@ void log_event(unsigned short type, unsigned long id, ...) {
 void print_message(FILE *file, unsigned long id, ...) {
   va_list arg;
 
-  char *format = message_string(id);
+  TCHAR *format = message_string(id);
   if (! format) return;
 
   va_start(arg, id);
-  vfprintf(file, format, arg);
+  _vftprintf(file, format, arg);
   va_end(arg);
 
   LocalFree(format);
@@ -71,17 +71,17 @@ void print_message(FILE *file, unsigned long id, ...) {
 int popup_message(unsigned int type, unsigned long id, ...) {
   va_list arg;
 
-  char *format = message_string(id);
+  TCHAR *format = message_string(id);
   if (! format) {
-    return MessageBox(0, "Message %lu was supposed to go here!", NSSM, MB_OK | MB_ICONEXCLAMATION);
+    return MessageBox(0, _T("Message %lu was supposed to go here!"), NSSM, MB_OK | MB_ICONEXCLAMATION);
   }
 
-  char blurb[256];
+  TCHAR blurb[256];
   va_start(arg, id);
-  if (vsnprintf_s(blurb, sizeof(blurb), _TRUNCATE, format, arg) < 0) {
+  if (_vsntprintf_s(blurb, sizeof(blurb), _TRUNCATE, format, arg) < 0) {
     va_end(arg);
     LocalFree(format);
-    return MessageBox(0, "Message %lu was supposed to go here!", NSSM, MB_OK | MB_ICONEXCLAMATION);
+    return MessageBox(0, _T("Message %lu was supposed to go here!"), NSSM, MB_OK | MB_ICONEXCLAMATION);
   }
   va_end(arg);
 

+ 2 - 2
event.h

@@ -1,8 +1,8 @@
 #ifndef EVENT_H
 #define EVENT_H
 
-char *error_string(unsigned long);
-char *message_string(unsigned long);
+TCHAR *error_string(unsigned long);
+TCHAR *message_string(unsigned long);
 void log_event(unsigned short, unsigned long, ...);
 void print_message(FILE *, unsigned long, ...);
 int popup_message(unsigned int, unsigned long, ...);

+ 43 - 39
gui.cpp

@@ -4,7 +4,7 @@ static enum { NSSM_TAB_APPLICATION, NSSM_TAB_SHUTDOWN, NSSM_TAB_EXIT, NSSM_TAB_I
 static HWND tablist[NSSM_NUM_TABS];
 static int selected_tab;
 
-int nssm_gui(int resource, char *name) {
+int nssm_gui(int resource, TCHAR *name) {
   /* Create window */
   HWND dlg = CreateDialog(0, MAKEINTRESOURCE(resource), 0, install_dlg);
   if (! dlg) {
@@ -74,7 +74,7 @@ static inline void check_method_timeout(HWND tab, unsigned long control, unsigne
   if (translated) *timeout = configured;
 }
 
-static inline void check_io(char *name, char *buffer, size_t bufsize, unsigned long control) {
+static inline void check_io(TCHAR *name, TCHAR *buffer, size_t bufsize, unsigned long control) {
   if (! SendMessage(GetDlgItem(tablist[NSSM_TAB_IO], control), WM_GETTEXTLENGTH, 0, 0)) return;
   if (GetDlgItemText(tablist[NSSM_TAB_IO], control, buffer, (int) bufsize)) return;
   popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_MESSAGE_PATH_TOO_LONG, name);
@@ -104,7 +104,7 @@ int install(HWND window) {
 
     /* Get startup directory. */
     if (! GetDlgItemText(tablist[NSSM_TAB_APPLICATION], IDC_DIR, service->dir, sizeof(service->dir))) {
-      memmove(service->dir, service->exe, sizeof(service->dir));
+      _sntprintf_s(service->dir, _countof(service->dir), _TRUNCATE, _T("%s"), service->exe);
       strip_basename(service->dir);
     }
 
@@ -132,9 +132,9 @@ int install(HWND window) {
     if (service->default_exit_action == CB_ERR) service->default_exit_action = 0;
 
     /* Get I/O stuff. */
-    check_io("stdin", service->stdin_path, sizeof(service->stdin_path), IDC_STDIN);
-    check_io("stdout", service->stdout_path, sizeof(service->stdout_path), IDC_STDOUT);
-    check_io("stderr", service->stderr_path, sizeof(service->stderr_path), IDC_STDERR);
+    check_io(_T("stdin"), service->stdin_path, sizeof(service->stdin_path), IDC_STDIN);
+    check_io(_T("stdout"), service->stdout_path, sizeof(service->stdout_path), IDC_STDOUT);
+    check_io(_T("stderr"), service->stderr_path, sizeof(service->stderr_path), IDC_STDERR);
     /* Override stdout and/or stderr. */
     if (SendDlgItemMessage(tablist[NSSM_TAB_IO], IDC_TRUNCATE, BM_GETCHECK, 0, 0) & BST_CHECKED) {
       if (service->stdout_path[0]) service->stdout_disposition = CREATE_ALWAYS;
@@ -144,9 +144,9 @@ int install(HWND window) {
     /* Get environment. */
     unsigned long envlen = (unsigned long) SendMessage(GetDlgItem(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT), WM_GETTEXTLENGTH, 0, 0);
     if (envlen) {
-      char *env = (char *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, envlen + 2);
+      TCHAR *env = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (envlen + 2) * sizeof(TCHAR));
       if (! env) {
-        popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, "environment", "install()");
+        popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("environment"), _T("install()"));
         cleanup_nssm_service(service);
         return 5;
       }
@@ -161,21 +161,21 @@ int install(HWND window) {
       /* Strip CR and replace LF with NULL. */
       unsigned long newlen = 0;
       unsigned long i, j;
-      for (i = 0; i < envlen; i++) if (env[i] != '\r') newlen++;
+      for (i = 0; i < envlen; i++) if (env[i] != _T('\r')) newlen++;
       /* Must end with two NULLs. */
       newlen += 2;
 
-      char *newenv = (char *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, newlen);
+      TCHAR *newenv = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, newlen * sizeof(TCHAR));
       if (! newenv) {
         HeapFree(GetProcessHeap(), 0, env);
-        popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, "environment", "install()");
+        popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("environment"), _T("install()"));
         cleanup_nssm_service(service);
         return 5;
       }
 
       for (i = 0, j = 0; i < envlen; i++) {
-        if (env[i] == '\r') continue;
-        if (env[i] == '\n') newenv[j] = '\0';
+        if (env[i] == _T('\r')) continue;
+        if (env[i] == _T('\n')) newenv[j] = _T('\0');
         else newenv[j] = env[i];
         j++;
       }
@@ -185,15 +185,19 @@ int install(HWND window) {
       envlen = newlen;
 
       /* Test the environment is valid. */
-      char path[MAX_PATH];
-      GetModuleFileName(0, path, sizeof(path));
+      TCHAR path[MAX_PATH];
+      GetModuleFileName(0, path, _countof(path));
       STARTUPINFO si;
       ZeroMemory(&si, sizeof(si));
       si.cb = sizeof(si);
       PROCESS_INFORMATION pi;
       ZeroMemory(&pi, sizeof(pi));
+      unsigned long flags = CREATE_SUSPENDED;
+#ifdef UNICODE
+      flags |= CREATE_UNICODE_ENVIRONMENT;
+#endif
 
-      if (! CreateProcess(0, path, 0, 0, 0, CREATE_SUSPENDED, env, 0, &si, &pi)) {
+      if (! CreateProcess(0, path, 0, 0, 0, flags, env, 0, &si, &pi)) {
         unsigned long error = GetLastError();
         if (error == ERROR_INVALID_PARAMETER) {
           popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_ENVIRONMENT);
@@ -219,7 +223,7 @@ int install(HWND window) {
   /* See if it works. */
   switch (install_service(service)) {
     case 1:
-      popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, "service", "install()");
+      popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("service"), _T("install()"));
       cleanup_nssm_service(service);
       return 1;
 
@@ -277,7 +281,7 @@ int remove(HWND window) {
 
   switch (remove_service(service)) {
     case 1:
-      popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, "service", "remove()");
+      popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("service"), _T("remove()"));
       cleanup_nssm_service(service);
       return 1;
 
@@ -302,12 +306,12 @@ int remove(HWND window) {
   return 0;
 }
 
-static char *browse_filter(int message) {
+static TCHAR *browse_filter(int message) {
   switch (message) {
-    case NSSM_GUI_BROWSE_FILTER_APPLICATIONS: return "*.exe;*.bat;*.cmd";
-    case NSSM_GUI_BROWSE_FILTER_DIRECTORIES: return ".";
+    case NSSM_GUI_BROWSE_FILTER_APPLICATIONS: return _T("*.exe;*.bat;*.cmd");
+    case NSSM_GUI_BROWSE_FILTER_DIRECTORIES: return _T(".");
     case NSSM_GUI_BROWSE_FILTER_ALL_FILES: /* Fall through. */
-    default: return "*.*";
+    default: return _T("*.*");
   }
 }
 
@@ -321,7 +325,7 @@ UINT_PTR CALLBACK browse_hook(HWND dlg, UINT message, WPARAM w, LPARAM l) {
 }
 
 /* Browse for application */
-void browse(HWND window, char *current, unsigned long flags, ...) {
+void browse(HWND window, TCHAR *current, unsigned long flags, ...) {
   if (! window) return;
 
   va_list arg;
@@ -332,7 +336,7 @@ void browse(HWND window, char *current, unsigned long flags, ...) {
   OPENFILENAME ofn;
   ZeroMemory(&ofn, sizeof(ofn));
   ofn.lStructSize = sizeof(ofn);
-  ofn.lpstrFilter = (char *) HeapAlloc(GetProcessHeap(), 0, bufsize);
+  ofn.lpstrFilter = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, bufsize * sizeof(TCHAR));
   /* XXX: Escaping nulls with FormatMessage is tricky */
   if (ofn.lpstrFilter) {
     ZeroMemory((void *) ofn.lpstrFilter, bufsize);
@@ -340,23 +344,23 @@ void browse(HWND window, char *current, unsigned long flags, ...) {
     /* "Applications" + NULL + "*.exe" + NULL */
     va_start(arg, flags);
     while (i = va_arg(arg, int)) {
-      char *localised = message_string(i);
-      _snprintf_s((char *) ofn.lpstrFilter + len, bufsize, _TRUNCATE, localised);
-      len += strlen(localised) + 1;
+      TCHAR *localised = message_string(i);
+      _sntprintf_s((TCHAR *) ofn.lpstrFilter + len, bufsize, _TRUNCATE, localised);
+      len += _tcslen(localised) + 1;
       LocalFree(localised);
-      char *filter = browse_filter(i);
-      _snprintf_s((char *) ofn.lpstrFilter + len, bufsize - len, _TRUNCATE, "%s", filter);
-      len += strlen(filter) + 1;
+      TCHAR *filter = browse_filter(i);
+      _sntprintf_s((TCHAR *) ofn.lpstrFilter + len, bufsize - len, _TRUNCATE, _T("%s"), filter);
+      len += _tcslen(filter) + 1;
     }
     va_end(arg);
     /* Remainder of the buffer is already zeroed */
   }
-  ofn.lpstrFile = new char[MAX_PATH];
+  ofn.lpstrFile = new TCHAR[MAX_PATH];
   if (flags & OFN_NOVALIDATE) {
     /* Directory hack. */
-    _snprintf_s(ofn.lpstrFile, MAX_PATH, _TRUNCATE, ":%s:", message_string(NSSM_GUI_BROWSE_FILTER_DIRECTORIES));
+    _sntprintf_s(ofn.lpstrFile, MAX_PATH, _TRUNCATE, _T(":%s:"), message_string(NSSM_GUI_BROWSE_FILTER_DIRECTORIES));
   }
-  else _snprintf_s(ofn.lpstrFile, MAX_PATH, _TRUNCATE, "%s", current);
+  else _sntprintf_s(ofn.lpstrFile, MAX_PATH, _TRUNCATE, _T("%s"), current);
   ofn.lpstrTitle = message_string(NSSM_GUI_BROWSE_TITLE);
   ofn.nMaxFile = MAX_PATH;
   ofn.Flags = OFN_EXPLORER | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | flags;
@@ -379,7 +383,7 @@ INT_PTR CALLBACK tab_dlg(HWND tab, UINT message, WPARAM w, LPARAM l) {
     /* Button was pressed or control was controlled. */
     case WM_COMMAND:
       HWND dlg;
-      char buffer[MAX_PATH];
+      TCHAR buffer[MAX_PATH];
 
       switch (LOWORD(w)) {
         /* Browse for application. */
@@ -455,14 +459,14 @@ INT_PTR CALLBACK install_dlg(HWND window, UINT message, WPARAM w, LPARAM l) {
 
       /* Application tab. */
       tab.pszText = message_string(NSSM_GUI_TAB_APPLICATION);
-      tab.cchTextMax = (int) strlen(tab.pszText);
+      tab.cchTextMax = (int) _tcslen(tab.pszText);
       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_APPLICATION, (LPARAM) &tab);
       tablist[NSSM_TAB_APPLICATION] = CreateDialog(0, MAKEINTRESOURCE(IDD_APPLICATION), window, tab_dlg);
       ShowWindow(tablist[NSSM_TAB_APPLICATION], SW_SHOW);
 
       /* Shutdown tab. */
       tab.pszText = message_string(NSSM_GUI_TAB_SHUTDOWN);
-      tab.cchTextMax = (int) strlen(tab.pszText);
+      tab.cchTextMax = (int) _tcslen(tab.pszText);
       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_SHUTDOWN, (LPARAM) &tab);
       tablist[NSSM_TAB_SHUTDOWN] = CreateDialog(0, MAKEINTRESOURCE(IDD_SHUTDOWN), window, tab_dlg);
       ShowWindow(tablist[NSSM_TAB_SHUTDOWN], SW_HIDE);
@@ -478,7 +482,7 @@ INT_PTR CALLBACK install_dlg(HWND window, UINT message, WPARAM w, LPARAM l) {
 
       /* Restart tab. */
       tab.pszText = message_string(NSSM_GUI_TAB_EXIT);
-      tab.cchTextMax = (int) strlen(tab.pszText);
+      tab.cchTextMax = (int) _tcslen(tab.pszText);
       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_EXIT, (LPARAM) &tab);
       tablist[NSSM_TAB_EXIT] = CreateDialog(0, MAKEINTRESOURCE(IDD_APPEXIT), window, tab_dlg);
       ShowWindow(tablist[NSSM_TAB_EXIT], SW_HIDE);
@@ -494,14 +498,14 @@ INT_PTR CALLBACK install_dlg(HWND window, UINT message, WPARAM w, LPARAM l) {
 
       /* I/O tab. */
       tab.pszText = message_string(NSSM_GUI_TAB_IO);
-      tab.cchTextMax = (int) strlen(tab.pszText) + 1;
+      tab.cchTextMax = (int) _tcslen(tab.pszText) + 1;
       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_IO, (LPARAM) &tab);
       tablist[NSSM_TAB_IO] = CreateDialog(0, MAKEINTRESOURCE(IDD_IO), window, tab_dlg);
       ShowWindow(tablist[NSSM_TAB_IO], SW_HIDE);
 
       /* Environment tab. */
       tab.pszText = message_string(NSSM_GUI_TAB_ENVIRONMENT);
-      tab.cchTextMax = (int) strlen(tab.pszText) + 1;
+      tab.cchTextMax = (int) _tcslen(tab.pszText) + 1;
       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_ENVIRONMENT, (LPARAM) &tab);
       tablist[NSSM_TAB_ENVIRONMENT] = CreateDialog(0, MAKEINTRESOURCE(IDD_ENVIRONMENT), window, tab_dlg);
       ShowWindow(tablist[NSSM_TAB_ENVIRONMENT], SW_HIDE);

+ 1 - 1
gui.h

@@ -6,7 +6,7 @@
 #include <commctrl.h>
 #include "resource.h"
 
-int nssm_gui(int, char *);
+int nssm_gui(int, TCHAR *);
 void centre_window(HWND);
 int install(HWND);
 int remove(HWND);

+ 2 - 2
imports.cpp

@@ -9,7 +9,7 @@ imports_t imports;
   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) {
+HMODULE get_dll(const TCHAR *dll, unsigned long *error) {
   *error = 0;
 
   HMODULE ret = LoadLibrary(dll);
@@ -38,7 +38,7 @@ int get_imports() {
 
   ZeroMemory(&imports, sizeof(imports));
 
-  imports.kernel32 = get_dll("kernel32.dll", &error);
+  imports.kernel32 = get_dll(_T("kernel32.dll"), &error);
   if (imports.kernel32) {
     imports.AttachConsole = (AttachConsole_ptr) get_import(imports.kernel32, "AttachConsole", &error);
     if (! imports.AttachConsole) {

+ 1 - 1
imports.h

@@ -12,7 +12,7 @@ typedef struct {
   WakeConditionVariable_ptr WakeConditionVariable;
 } imports_t;
 
-HMODULE get_dll(const char *, unsigned long *);
+HMODULE get_dll(const TCHAR *, unsigned long *);
 FARPROC get_import(HMODULE, const char *, unsigned long *);
 int get_imports();
 void free_imports();

+ 19 - 19
io.cpp

@@ -1,12 +1,12 @@
 #include "nssm.h"
 
 /* Get path, share mode, creation disposition and flags for a stream. */
-int get_createfile_parameters(HKEY key, char *prefix, char *path, unsigned long *sharing, unsigned long default_sharing, unsigned long *disposition, unsigned long default_disposition, unsigned long *flags, unsigned long default_flags) {
-  char value[NSSM_STDIO_LENGTH];
+int get_createfile_parameters(HKEY key, TCHAR *prefix, TCHAR *path, unsigned long *sharing, unsigned long default_sharing, unsigned long *disposition, unsigned long default_disposition, unsigned long *flags, unsigned long default_flags) {
+  TCHAR value[NSSM_STDIO_LENGTH];
 
   /* Path. */
-  if (_snprintf_s(value, sizeof(value), _TRUNCATE, "%s", prefix) < 0) {
-    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, prefix, "get_createfile_parameters()", 0);
+  if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s"), prefix) < 0) {
+    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, prefix, _T("get_createfile_parameters()"), 0);
     return 1;
   }
   switch (expand_parameter(key, value, path, MAX_PATH, true, false)) {
@@ -15,8 +15,8 @@ int get_createfile_parameters(HKEY key, char *prefix, char *path, unsigned long
   }
 
   /* ShareMode. */
-  if (_snprintf_s(value, sizeof(value), _TRUNCATE, "%s%s", prefix, NSSM_REG_STDIO_SHARING) < 0) {
-    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_SHARING, "get_createfile_parameters()", 0);
+  if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_SHARING) < 0) {
+    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_SHARING, _T("get_createfile_parameters()"), 0);
     return 3;
   }
   switch (get_number(key, value, sharing, false)) {
@@ -26,8 +26,8 @@ int get_createfile_parameters(HKEY key, char *prefix, char *path, unsigned long
   }
 
   /* CreationDisposition. */
-  if (_snprintf_s(value, sizeof(value), _TRUNCATE, "%s%s", prefix, NSSM_REG_STDIO_DISPOSITION) < 0) {
-    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_DISPOSITION, "get_createfile_parameters()", 0);
+  if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_DISPOSITION) < 0) {
+    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_DISPOSITION, _T("get_createfile_parameters()"), 0);
     return 5;
   }
   switch (get_number(key, value, disposition, false)) {
@@ -37,8 +37,8 @@ int get_createfile_parameters(HKEY key, char *prefix, char *path, unsigned long
   }
 
   /* Flags. */
-  if (_snprintf_s(value, sizeof(value), _TRUNCATE, "%s%s", prefix, NSSM_REG_STDIO_FLAGS) < 0) {
-    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_FLAGS, "get_createfile_parameters()", 0);
+  if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_FLAGS) < 0) {
+    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_FLAGS, _T("get_createfile_parameters()"), 0);
     return 7;
   }
   switch (get_number(key, value, flags, false)) {
@@ -50,18 +50,18 @@ int get_createfile_parameters(HKEY key, char *prefix, char *path, unsigned long
   return 0;
 }
 
-int set_createfile_parameter(HKEY key, char *prefix, char *suffix, unsigned long number) {
-  char value[NSSM_STDIO_LENGTH];
+int set_createfile_parameter(HKEY key, TCHAR *prefix, TCHAR *suffix, unsigned long number) {
+  TCHAR value[NSSM_STDIO_LENGTH];
 
-  if (_snprintf_s(value, sizeof(value), _TRUNCATE, "%s%s", prefix, suffix) < 0) {
-    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, suffix, "set_createfile_parameter()", 0);
+  if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, suffix) < 0) {
+    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, suffix, _T("set_createfile_parameter()"), 0);
     return 1;
   }
 
   return set_number(key, value, number);
 }
 
-HANDLE append_to_file(char *path, unsigned long sharing, SECURITY_ATTRIBUTES *attributes, unsigned long disposition, unsigned long flags) {
+HANDLE append_to_file(TCHAR *path, unsigned long sharing, SECURITY_ATTRIBUTES *attributes, unsigned long disposition, unsigned long flags) {
   HANDLE ret;
 
   /* Try to append to the file first. */
@@ -82,8 +82,8 @@ HANDLE append_to_file(char *path, unsigned long sharing, SECURITY_ATTRIBUTES *at
 }
 
 int get_output_handles(HKEY key, STARTUPINFO *si) {
-  char path[MAX_PATH];
-  char stdout_path[MAX_PATH];
+  TCHAR path[MAX_PATH];
+  TCHAR stdout_path[MAX_PATH];
   unsigned long sharing, disposition, flags;
   bool set_flags = false;
 
@@ -107,8 +107,8 @@ int get_output_handles(HKEY key, STARTUPINFO *si) {
   if (get_createfile_parameters(key, NSSM_REG_STDOUT, path, &sharing, NSSM_STDOUT_SHARING, &disposition, NSSM_STDOUT_DISPOSITION, &flags, NSSM_STDOUT_FLAGS)) return 3;
   if (path[0]) {
     /* Remember path for comparison with stderr. */
-    if (_snprintf_s(stdout_path, sizeof(stdout_path), _TRUNCATE, "%s", path) < 0) {
-      log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, "stdout_path", "get_output_handles", 0);
+    if (_sntprintf_s(stdout_path, _countof(stdout_path), _TRUNCATE, _T("%s"), path) < 0) {
+      log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("stdout_path"), _T("get_output_handles"), 0);
       return 4;
     }
 

+ 3 - 3
io.h

@@ -11,9 +11,9 @@
 #define NSSM_STDERR_DISPOSITION OPEN_ALWAYS
 #define NSSM_STDERR_FLAGS FILE_ATTRIBUTE_NORMAL
 
-int get_createfile_parameters(HKEY, char *, char *, unsigned long *, unsigned long, unsigned long *, unsigned long, unsigned long *, unsigned long);
-int set_createfile_parameter(HKEY, char *, char *, unsigned long);
-HANDLE append_to_file(char *, unsigned long, SECURITY_ATTRIBUTES *, unsigned long, unsigned long);
+int get_createfile_parameters(HKEY, TCHAR *, TCHAR *, unsigned long *, unsigned long, unsigned long *, unsigned long, unsigned long *, unsigned long);
+int set_createfile_parameter(HKEY, TCHAR *, TCHAR *, unsigned long);
+HANDLE append_to_file(TCHAR *, unsigned long, SECURITY_ATTRIBUTES *, unsigned long, unsigned long);
 int get_output_handles(HKEY, STARTUPINFO *);
 void close_output_handles(STARTUPINFO *);
 

+ 12 - 0
messages.mc

@@ -137,6 +137,18 @@ Language = Italian
 Il path completo verso %s è troppo lungo!
 .
 
+MessageId = +1
+SymbolicName = NSSM_MESSAGE_FLAGS_TOO_LONG
+Severity = Informational
+Language = English
+The program flags are too long!
+.
+Language = French
+The program flags are too long!
+.
+Language = Italian
+The program flags are too long!
+.
 
 MessageId = +1
 SymbolicName = NSSM_MESSAGE_OUT_OF_MEMORY_FOR_IMAGEPATH

+ 14 - 15
nssm.cpp

@@ -4,23 +4,22 @@ extern unsigned long tls_index;
 extern bool is_admin;
 extern imports_t imports;
 
-/* String function */
-int str_equiv(const char *a, const char *b) {
-  int i;
-  for (i = 0; ; i++) {
-    if (tolower(b[i]) != tolower(a[i])) return 0;
-    if (! a[i]) return 1;
-  }
+/* Are two strings case-insensitively equivalent? */
+int str_equiv(const TCHAR *a, const TCHAR *b) {
+  size_t len = _tcslen(a);
+  if (_tcslen(b) != len) return 0;
+  if (_tcsnicmp(a, b, len)) return 0;
+  return 1;
 }
 
 /* Remove basename of a path. */
-void strip_basename(char *buffer) {
-  size_t len = strlen(buffer);
+void strip_basename(TCHAR *buffer) {
+  size_t len = _tcslen(buffer);
   size_t i;
-  for (i = len; i && buffer[i] != '\\' && buffer[i] != '/'; i--);
+  for (i = len; i && buffer[i] != _T('\\') && buffer[i] != _T('/'); i--);
   /* X:\ is OK. */
-  if (i && buffer[i-1] == ':') i++;
-  buffer[i] = '\0';
+  if (i && buffer[i - 1] == _T(':')) i++;
+  buffer[i] = _T('\0');
 }
 
 /* How to use me correctly */
@@ -40,21 +39,21 @@ void check_admin() {
   FreeSid(AdministratorsGroup);
 }
 
-int main(int argc, char **argv) {
+int _tmain(int argc, TCHAR **argv) {
   /* Remember if we are admin */
   check_admin();
 
   /* Elevate */
   if (argc > 1) {
     /* Valid commands are install or remove */
-    if (str_equiv(argv[1], "install")) {
+    if (str_equiv(argv[1], _T("install"))) {
       if (! is_admin) {
         print_message(stderr, NSSM_MESSAGE_NOT_ADMINISTRATOR_CANNOT_INSTALL);
         exit(100);
       }
       exit(pre_install_service(argc - 2, argv + 2));
     }
-    if (str_equiv(argv[1], "remove")) {
+    if (str_equiv(argv[1], _T("remove"))) {
       if (! is_admin) {
         print_message(stderr, NSSM_MESSAGE_NOT_ADMINISTRATOR_CANNOT_REMOVE);
         exit(100);

+ 6 - 5
nssm.h

@@ -5,6 +5,7 @@
 #include <shlwapi.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <tchar.h>
 #include <windows.h>
 #include "service.h"
 #include "event.h"
@@ -15,13 +16,13 @@
 #include "io.h"
 #include "gui.h"
 
-int str_equiv(const char *, const char *);
-void strip_basename(char *);
+int str_equiv(const TCHAR *, const TCHAR *);
+void strip_basename(TCHAR *);
 
-#define NSSM "nssm"
-#define NSSM_VERSION "2.21"
+#define NSSM _T("nssm")
+#define NSSM_VERSION _T("2.21")
 #define NSSM_VERSIONINFO 2,21,0,0
-#define NSSM_DATE "2013-11-24"
+#define NSSM_DATE _T("2013-11-24")
 
 /*
   Throttle the restart of the service if it stops before this many

+ 11 - 11
process.cpp

@@ -40,8 +40,8 @@ int check_parent(nssm_service_t *service, PROCESSENTRY32 *pe, unsigned long ppid
   */
   HANDLE process_handle = OpenProcess(PROCESS_QUERY_INFORMATION, false, pe->th32ProcessID);
   if (! process_handle) {
-    char pid_string[16];
-    _snprintf_s(pid_string, sizeof(pid_string), _TRUNCATE, "%lu", pe->th32ProcessID);
+    TCHAR pid_string[16];
+    _sntprintf_s(pid_string, _countof(pid_string), _TRUNCATE, _T("%lu"), pe->th32ProcessID);
     log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OPENPROCESS_FAILED, pid_string, service->name, error_string(GetLastError()), 0);
     return 2;
   }
@@ -90,7 +90,7 @@ int CALLBACK kill_window(HWND window, LPARAM arg) {
   processes so this function returns only true if at least one thread was
   successfully prodded.
 */
-int kill_threads(char *service_name, kill_t *k) {
+int kill_threads(TCHAR *service_name, kill_t *k) {
   int ret = 0;
 
   /* Get a snapshot of all threads in the system. */
@@ -162,7 +162,7 @@ int kill_process(nssm_service_t *service, HANDLE process_handle, unsigned long p
   if (service->stop_method & NSSM_STOP_METHOD_WINDOW) {
     EnumWindows((WNDENUMPROC) kill_window, (LPARAM) &k);
     if (k.signalled) {
-      if (! await_shutdown(service, __FUNCTION__, service->kill_window_delay)) return 1;
+      if (! await_shutdown(service, _T(__FUNCTION__), service->kill_window_delay)) return 1;
     }
   }
 
@@ -173,7 +173,7 @@ int kill_process(nssm_service_t *service, HANDLE process_handle, unsigned long p
   */
   if (service->stop_method & NSSM_STOP_METHOD_THREADS) {
     if (kill_threads(service->name, &k)) {
-      if (! await_shutdown(service, __FUNCTION__, service->kill_threads_delay)) return 1;
+      if (! await_shutdown(service, _T(__FUNCTION__), service->kill_threads_delay)) return 1;
     }
   }
 
@@ -236,7 +236,7 @@ int kill_console(nssm_service_t *service) {
   }
 
   /* Wait for process to exit. */
-  if (await_shutdown(service, __FUNCTION__, service->kill_console_delay)) ret = 6;
+  if (await_shutdown(service, _T(__FUNCTION__), service->kill_console_delay)) ret = 6;
 
   return ret;
 }
@@ -245,9 +245,9 @@ void kill_process_tree(nssm_service_t *service, unsigned long pid, unsigned long
   /* Shouldn't happen unless the service failed to start. */
   if (! pid) return;
 
-  char pid_string[16], code[16];
-  _snprintf_s(pid_string, sizeof(pid_string), _TRUNCATE, "%lu", pid);
-  _snprintf_s(code, sizeof(code), _TRUNCATE, "%lu", exitcode);
+  TCHAR pid_string[16], code[16];
+  _sntprintf_s(pid_string, _countof(pid_string), _TRUNCATE, _T("%lu"), pid);
+  _sntprintf_s(code, _countof(code), _TRUNCATE, _T("%lu"), exitcode);
   log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_KILLING, service->name, pid_string, code, 0);
 
   /* Get a snapshot of all processes in the system. */
@@ -292,8 +292,8 @@ void kill_process_tree(nssm_service_t *service, unsigned long pid, unsigned long
     return;
   }
 
-  char ppid_string[16];
-  _snprintf_s(ppid_string, sizeof(ppid_string), _TRUNCATE, "%lu", ppid);
+  TCHAR ppid_string[16];
+  _sntprintf_s(ppid_string, _countof(ppid_string), _TRUNCATE, _T("%lu"), ppid);
   log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_KILL_PROCESS_TREE, pid_string, ppid_string, service->name, 0);
   if (! kill_process(service, process_handle, pid, exitcode)) {
     /* Maybe it already died. */

+ 1 - 1
process.h

@@ -11,7 +11,7 @@ typedef struct {
 
 int get_process_creation_time(HANDLE, FILETIME *);
 int get_process_exit_time(HANDLE, FILETIME *);
-int check_parent(char *, PROCESSENTRY32 *, unsigned long, FILETIME *, FILETIME *);
+int check_parent(TCHAR *, PROCESSENTRY32 *, unsigned long, FILETIME *, FILETIME *);
 int CALLBACK kill_window(HWND, LPARAM);
 int kill_threads(nssm_service_t *, kill_t *);
 int kill_console(nssm_service_t *);

+ 59 - 63
registry.cpp

@@ -1,13 +1,13 @@
 #include "nssm.h"
 
-extern const char *exit_action_strings[];
+extern const TCHAR *exit_action_strings[];
 
 int create_messages() {
   HKEY key;
 
-  char registry[KEY_LENGTH];
-  if (_snprintf_s(registry, sizeof(registry), _TRUNCATE, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s", NSSM) < 0) {
-    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, "eventlog registry", "create_messages()", 0);
+  TCHAR registry[KEY_LENGTH];
+  if (_sntprintf_s(registry, _countof(registry), _TRUNCATE, _T("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s"), NSSM) < 0) {
+    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("eventlog registry"), _T("create_messages()"), 0);
     return 1;
   }
 
@@ -17,22 +17,22 @@ int create_messages() {
   }
 
   /* Get path of this program */
-  char path[MAX_PATH];
-  GetModuleFileName(0, path, MAX_PATH);
+  TCHAR path[MAX_PATH];
+  GetModuleFileName(0, path, _countof(path));
 
   /* Try to register the module but don't worry so much on failure */
-  RegSetValueEx(key, "EventMessageFile", 0, REG_SZ, (const unsigned char *) path, (unsigned long) strlen(path) + 1);
+  RegSetValueEx(key, _T("EventMessageFile"), 0, REG_SZ, (const unsigned char *) path, (unsigned long) (_tcslen(path) +  1) * sizeof(TCHAR));
   unsigned long types = EVENTLOG_INFORMATION_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_ERROR_TYPE;
-  RegSetValueEx(key, "TypesSupported", 0, REG_DWORD, (const unsigned char *) &types, sizeof(types));
+  RegSetValueEx(key, _T("TypesSupported"), 0, REG_DWORD, (const unsigned char *) &types, sizeof(types));
 
   return 0;
 }
 
 int create_parameters(nssm_service_t *service) {
   /* Get registry */
-  char registry[KEY_LENGTH];
-  if (_snprintf_s(registry, sizeof(registry), _TRUNCATE, NSSM_REGISTRY, service->name) < 0) {
-    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, "NSSM_REGISTRY", "create_parameters()", 0);
+  TCHAR registry[KEY_LENGTH];
+  if (_sntprintf_s(registry, _countof(registry), _TRUNCATE, NSSM_REGISTRY, service->name) < 0) {
+    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("NSSM_REGISTRY"), _T("create_parameters()"), 0);
     return 1;
   }
 
@@ -89,12 +89,12 @@ int create_parameters(nssm_service_t *service) {
 
   /* Environment */
   if (service->env) {
-    if (RegSetValueEx(key, NSSM_REG_ENV, 0, REG_MULTI_SZ, (const unsigned char *) service->env, (unsigned long) service->envlen) != ERROR_SUCCESS) {
+    if (RegSetValueEx(key, NSSM_REG_ENV, 0, REG_MULTI_SZ, (const unsigned char *) service->env, (unsigned long) service->envlen * sizeof(TCHAR)) != ERROR_SUCCESS) {
       log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SETVALUE_FAILED, NSSM_REG_ENV, error_string(GetLastError()), 0);
     }
   }
   if (service->env_extra) {
-    if (RegSetValueEx(key, NSSM_REG_ENV_EXTRA, 0, REG_MULTI_SZ, (const unsigned char *) service->env_extra, (unsigned long) service->env_extralen) != ERROR_SUCCESS) {
+    if (RegSetValueEx(key, NSSM_REG_ENV_EXTRA, 0, REG_MULTI_SZ, (const unsigned char *) service->env_extra, (unsigned long) service->env_extralen * sizeof(TCHAR)) != ERROR_SUCCESS) {
       log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SETVALUE_FAILED, NSSM_REG_ENV_EXTRA, error_string(GetLastError()), 0);
     }
   }
@@ -105,11 +105,11 @@ int create_parameters(nssm_service_t *service) {
   return 0;
 }
 
-int create_exit_action(char *service_name, const char *action_string) {
+int create_exit_action(TCHAR *service_name, const TCHAR *action_string) {
   /* Get registry */
-  char registry[KEY_LENGTH];
-  if (_snprintf_s(registry, sizeof(registry), _TRUNCATE, NSSM_REGISTRY "\\%s", service_name, NSSM_REG_EXIT) < 0) {
-    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, "NSSM_REG_EXIT", "create_exit_action()", 0);
+  TCHAR registry[KEY_LENGTH];
+  if (_sntprintf_s(registry, _countof(registry), _TRUNCATE, NSSM_REGISTRY _T("\\%s"), service_name, NSSM_REG_EXIT) < 0) {
+    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("NSSM_REG_EXIT"), _T("create_exit_action()"), 0);
     return 1;
   }
 
@@ -128,7 +128,7 @@ int create_exit_action(char *service_name, const char *action_string) {
   }
 
   /* Create the default value */
-  if (RegSetValueEx(key, 0, 0, REG_SZ, (const unsigned char *) action_string, (unsigned long) strlen(action_string) + 1) != ERROR_SUCCESS) {
+  if (RegSetValueEx(key, 0, 0, REG_SZ, (const unsigned char *) action_string, (unsigned long) (_tcslen(action_string) + 1) * sizeof(TCHAR)) != ERROR_SUCCESS) {
     log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SETVALUE_FAILED, NSSM_REG_EXIT, error_string(GetLastError()), 0);
     RegCloseKey(key);
     return 3;
@@ -140,7 +140,7 @@ int create_exit_action(char *service_name, const char *action_string) {
   return 0;
 }
 
-int set_environment(char *service_name, HKEY key, char *value, char **env, unsigned long *envlen) {
+int set_environment(TCHAR *service_name, HKEY key, TCHAR *value, TCHAR **env, unsigned long *envlen) {
   unsigned long type = REG_MULTI_SZ;
 
   /* Dummy test to find buffer size */
@@ -164,9 +164,9 @@ int set_environment(char *service_name, HKEY key, char *value, char **env, unsig
   /* Previously initialised? */
   if (*env) HeapFree(GetProcessHeap(), 0, *env);
 
-  *env = (char *) HeapAlloc(GetProcessHeap(), 0, *envlen);
+  *env = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, *envlen);
   if (! *env) {
-    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, value, "set_environment()", 0);
+    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, value, _T("set_environment()"), 0);
     return 3;
   }
 
@@ -183,10 +183,10 @@ int set_environment(char *service_name, HKEY key, char *value, char **env, unsig
   return 0;
 }
 
-int expand_parameter(HKEY key, char *value, char *data, unsigned long datalen, bool sanitise, bool must_exist) {
-  unsigned char *buffer = (unsigned char *) HeapAlloc(GetProcessHeap(), 0, datalen);
+int expand_parameter(HKEY key, TCHAR *value, TCHAR *data, unsigned long datalen, bool sanitise, bool must_exist) {
+  TCHAR *buffer = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, datalen);
   if (! buffer) {
-    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, value, "expand_parameter()", 0);
+    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, value, _T("expand_parameter()"), 0);
     return 1;
   }
 
@@ -195,7 +195,7 @@ int expand_parameter(HKEY key, char *value, char *data, unsigned long datalen, b
   unsigned long type = REG_EXPAND_SZ;
   unsigned long buflen = datalen;
 
-  unsigned long ret = RegQueryValueEx(key, value, 0, &type, buffer, &buflen);
+  unsigned long ret = RegQueryValueEx(key, value, 0, &type, (unsigned char *) buffer, &buflen);
   if (ret != ERROR_SUCCESS) {
     unsigned long error = GetLastError();
     HeapFree(GetProcessHeap(), 0, buffer);
@@ -209,7 +209,7 @@ int expand_parameter(HKEY key, char *value, char *data, unsigned long datalen, b
   }
 
   /* Paths aren't allowed to contain quotes. */
-  if (sanitise) PathUnquoteSpaces((LPSTR) buffer);
+  if (sanitise) PathUnquoteSpaces(buffer);
 
   /* Technically we shouldn't expand environment strings from REG_SZ values */
   if (type != REG_EXPAND_SZ) {
@@ -218,7 +218,7 @@ int expand_parameter(HKEY key, char *value, char *data, unsigned long datalen, b
     return 0;
   }
 
-  ret = ExpandEnvironmentStrings((char *) buffer, data, datalen);
+  ret = ExpandEnvironmentStrings((TCHAR *) buffer, data, datalen);
   if (! ret || ret > datalen) {
     log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_EXPANDENVIRONMENTSTRINGS_FAILED, buffer, error_string(GetLastError()), 0);
     HeapFree(GetProcessHeap(), 0, buffer);
@@ -229,7 +229,7 @@ int expand_parameter(HKEY key, char *value, char *data, unsigned long datalen, b
   return 0;
 }
 
-int expand_parameter(HKEY key, char *value, char *data, unsigned long datalen, bool sanitise) {
+int expand_parameter(HKEY key, TCHAR *value, TCHAR *data, unsigned long datalen, bool sanitise) {
   return expand_parameter(key, value, data, datalen, sanitise, true);
 }
 
@@ -238,8 +238,8 @@ int expand_parameter(HKEY key, char *value, char *data, unsigned long datalen, b
   Returns: 0 if it was set.
            1 on error.
 */
-int set_expand_string(HKEY key, char *value, char *string) {
-  if (RegSetValueEx(key, value, 0, REG_EXPAND_SZ, (const unsigned char *) string, (unsigned long) strlen(string) + 1) == ERROR_SUCCESS) return 0;
+int set_expand_string(HKEY key, TCHAR *value, TCHAR *string) {
+  if (RegSetValueEx(key, value, 0, REG_EXPAND_SZ, (const unsigned char *) string, (unsigned long) (_tcslen(string) + 1) * sizeof(TCHAR)) == ERROR_SUCCESS) return 0;
   log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SETVALUE_FAILED, value, error_string(GetLastError()), 0);
   return 1;
 }
@@ -249,7 +249,7 @@ int set_expand_string(HKEY key, char *value, char *string) {
   Returns: 0 if it was set.
            1 on error.
 */
-int set_number(HKEY key, char *value, unsigned long number) {
+int set_number(HKEY key, TCHAR *value, unsigned long number) {
   if (RegSetValueEx(key, value, 0, REG_DWORD, (const unsigned char *) &number, sizeof(number)) == ERROR_SUCCESS) return 0;
   log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SETVALUE_FAILED, value, error_string(GetLastError()), 0);
   return 1;
@@ -262,7 +262,7 @@ int set_number(HKEY key, char *value, unsigned long number) {
            -1 if none was found and must_exist is true.
            -2 otherwise.
 */
-int get_number(HKEY key, char *value, unsigned long *number, bool must_exist) {
+int get_number(HKEY key, TCHAR *value, unsigned long *number, bool must_exist) {
   unsigned long type = REG_DWORD;
   unsigned long number_len = sizeof(unsigned long);
 
@@ -279,11 +279,11 @@ int get_number(HKEY key, char *value, unsigned long *number, bool must_exist) {
   return -2;
 }
 
-int get_number(HKEY key, char *value, unsigned long *number) {
+int get_number(HKEY key, TCHAR *value, unsigned long *number) {
   return get_number(key, value, number, true);
 }
 
-void override_milliseconds(char *service_name, HKEY key, char *value, unsigned long *buffer, unsigned long default_value, unsigned long event) {
+void override_milliseconds(TCHAR *service_name, HKEY key, TCHAR *value, unsigned long *buffer, unsigned long default_value, unsigned long event) {
   unsigned long type = REG_DWORD;
   unsigned long buflen = sizeof(unsigned long);
   bool ok = false;
@@ -291,8 +291,8 @@ void override_milliseconds(char *service_name, HKEY key, char *value, unsigned l
   if (ret != ERROR_SUCCESS) {
     if (ret != ERROR_FILE_NOT_FOUND) {
       if (type != REG_DWORD) {
-        char milliseconds[16];
-        _snprintf_s(milliseconds, sizeof(milliseconds), _TRUNCATE, "%lu", default_value);
+        TCHAR milliseconds[16];
+        _sntprintf_s(milliseconds, _countof(milliseconds), _TRUNCATE, _T("%lu"), default_value);
         log_event(EVENTLOG_WARNING_TYPE, event, service_name, value, milliseconds, 0);
       }
       else log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_QUERYVALUE_FAILED, value, error_string(GetLastError()), 0);
@@ -307,9 +307,9 @@ int get_parameters(nssm_service_t *service, STARTUPINFO *si) {
   unsigned long ret;
 
   /* Get registry */
-  char registry[KEY_LENGTH];
-  if (_snprintf_s(registry, sizeof(registry), _TRUNCATE, NSSM_REGISTRY, service->name) < 0) {
-    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, "NSSM_REGISTRY", "get_parameters()", 0);
+  TCHAR registry[KEY_LENGTH];
+  if (_sntprintf_s(registry, _countof(registry), _TRUNCATE, NSSM_REGISTRY, service->name) < 0) {
+    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("NSSM_REGISTRY"), _T("get_parameters()"), 0);
     return 1;
   }
 
@@ -334,14 +334,9 @@ int get_parameters(nssm_service_t *service, STARTUPINFO *si) {
 
   /* Try to get startup directory - may fail and we fall back to a default */
   if (expand_parameter(key, NSSM_REG_DIR, service->dir, sizeof(service->dir), true) || ! service->dir[0]) {
-    /* Our buffers are defined to be long enough for this to be safe */
-    size_t i;
-    for (i = strlen(service->exe); i && service->exe[i] != '\\' && service->exe[i] != '/'; i--);
-    if (i) {
-      memmove(service->dir, service->exe, i);
-      service->dir[i] = '\0';
-    }
-    else {
+    _sntprintf_s(service->dir, _countof(service->dir), _TRUNCATE, _T("%s"), service->exe);
+    strip_basename(service->dir);
+    if (service->dir[0] == _T('\0')) {
       /* Help! */
       ret = GetWindowsDirectory(service->dir, sizeof(service->dir));
       if (! ret || ret > sizeof(service->dir)) {
@@ -363,28 +358,29 @@ int get_parameters(nssm_service_t *service, STARTUPINFO *si) {
     if (service->env) {
       /* Append extra variables to configured variables. */
       unsigned long envlen = service->envlen + service->env_extralen - 1;
-      char *env = (char *) HeapAlloc(GetProcessHeap(), 0, envlen);
+      TCHAR *env = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, envlen);
       if (env) {
-        memmove(env, service->env, service->envlen - 1);
-        memmove(env + service->envlen - 1, service->env_extra, service->env_extralen);
+        memmove(env, service->env, service->envlen - sizeof(TCHAR));
+        /* envlen is in bytes. */
+        memmove(env + (service->envlen / sizeof(TCHAR)) - 1, service->env_extra, service->env_extralen);
 
         HeapFree(GetProcessHeap(), 0, service->env);
         service->env = env;
         service->envlen = envlen;
       }
-      else log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, "environment", "get_parameters()", 0);
+      else log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("environment"), _T("get_parameters()"), 0);
     }
     else {
       /* Append extra variables to our environment. */
-      char *env, *s;
+      TCHAR *env, *s;
       size_t envlen, len;
 
       env = service->env_extra;
       len = 0;
       while (*env) {
-        envlen = strlen(env) + 1;
-        for (s = env; *s && *s != '='; s++);
-        if (*s == '=') *s++ = '\0';
+        envlen = _tcslen(env) + 1;
+        for (s = env; *s && *s != _T('='); s++);
+        if (*s == _T('=')) *s++ = _T('\0');
         if (! SetEnvironmentVariable(env, s)) log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_SETENVIRONMENTVARIABLE_FAILED, env, s, error_string(GetLastError()));
         env += envlen;
       }
@@ -432,14 +428,14 @@ int get_parameters(nssm_service_t *service, STARTUPINFO *si) {
   return 0;
 }
 
-int get_exit_action(char *service_name, unsigned long *ret, unsigned char *action, bool *default_action) {
+int get_exit_action(TCHAR *service_name, unsigned long *ret, TCHAR *action, bool *default_action) {
   /* Are we returning the default action or a status-specific one? */
   *default_action = ! ret;
 
   /* Get registry */
-  char registry[KEY_LENGTH];
-  if (_snprintf_s(registry, sizeof(registry), _TRUNCATE, NSSM_REGISTRY "\\%s", service_name, NSSM_REG_EXIT) < 0) {
-    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, "NSSM_REG_EXIT", "get_exit_action()", 0);
+  TCHAR registry[KEY_LENGTH];
+  if (_sntprintf_s(registry, _countof(registry), _TRUNCATE, NSSM_REGISTRY _T("\\%s"), service_name, NSSM_REG_EXIT) < 0) {
+    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("NSSM_REG_EXIT"), _T("get_exit_action()"), 0);
     return 1;
   }
 
@@ -454,13 +450,13 @@ int get_exit_action(char *service_name, unsigned long *ret, unsigned char *actio
   unsigned long type = REG_SZ;
   unsigned long action_len = ACTION_LEN;
 
-  char code[64];
-  if (! ret) code[0] = '\0';
-  else if (_snprintf_s(code, sizeof(code), _TRUNCATE, "%lu", *ret) < 0) {
+  TCHAR code[16];
+  if (! ret) code[0] = _T('\0');
+  else if (_sntprintf_s(code, _countof(code), _TRUNCATE, _T("%lu"), *ret) < 0) {
     RegCloseKey(key);
     return get_exit_action(service_name, 0, action, default_action);
   }
-  if (RegQueryValueEx(key, code, 0, &type, action, &action_len) != ERROR_SUCCESS) {
+  if (RegQueryValueEx(key, code, 0, &type, (unsigned char *) action, &action_len) != ERROR_SUCCESS) {
     RegCloseKey(key);
     /* Try again with * as the key if an exit code was defined */
     if (ret) return get_exit_action(service_name, 0, action, default_action);

+ 28 - 28
registry.h

@@ -1,38 +1,38 @@
 #ifndef REGISTRY_H
 #define REGISTRY_H
 
-#define NSSM_REGISTRY "SYSTEM\\CurrentControlSet\\Services\\%s\\Parameters"
-#define NSSM_REG_EXE "Application"
-#define NSSM_REG_FLAGS "AppParameters"
-#define NSSM_REG_DIR "AppDirectory"
-#define NSSM_REG_ENV "AppEnvironment"
-#define NSSM_REG_ENV_EXTRA "AppEnvironmentExtra"
-#define NSSM_REG_EXIT "AppExit"
-#define NSSM_REG_THROTTLE "AppThrottle"
-#define NSSM_REG_STOP_METHOD_SKIP "AppStopMethodSkip"
-#define NSSM_REG_KILL_CONSOLE_GRACE_PERIOD "AppStopMethodConsole"
-#define NSSM_REG_KILL_WINDOW_GRACE_PERIOD "AppStopMethodWindow"
-#define NSSM_REG_KILL_THREADS_GRACE_PERIOD "AppStopMethodThreads"
-#define NSSM_REG_STDIN "AppStdin"
-#define NSSM_REG_STDOUT "AppStdout"
-#define NSSM_REG_STDERR "AppStderr"
-#define NSSM_REG_STDIO_SHARING "ShareMode"
-#define NSSM_REG_STDIO_DISPOSITION "CreationDisposition"
-#define NSSM_REG_STDIO_FLAGS "FlagsAndAttributes"
+#define NSSM_REGISTRY _T("SYSTEM\\CurrentControlSet\\Services\\%s\\Parameters")
+#define NSSM_REG_EXE _T("Application")
+#define NSSM_REG_FLAGS _T("AppParameters")
+#define NSSM_REG_DIR _T("AppDirectory")
+#define NSSM_REG_ENV _T("AppEnvironment")
+#define NSSM_REG_ENV_EXTRA _T("AppEnvironmentExtra")
+#define NSSM_REG_EXIT _T("AppExit")
+#define NSSM_REG_THROTTLE _T("AppThrottle")
+#define NSSM_REG_STOP_METHOD_SKIP _T("AppStopMethodSkip")
+#define NSSM_REG_KILL_CONSOLE_GRACE_PERIOD _T("AppStopMethodConsole")
+#define NSSM_REG_KILL_WINDOW_GRACE_PERIOD _T("AppStopMethodWindow")
+#define NSSM_REG_KILL_THREADS_GRACE_PERIOD _T("AppStopMethodThreads")
+#define NSSM_REG_STDIN _T("AppStdin")
+#define NSSM_REG_STDOUT _T("AppStdout")
+#define NSSM_REG_STDERR _T("AppStderr")
+#define NSSM_REG_STDIO_SHARING _T("ShareMode")
+#define NSSM_REG_STDIO_DISPOSITION _T("CreationDisposition")
+#define NSSM_REG_STDIO_FLAGS _T("FlagsAndAttributes")
 #define NSSM_STDIO_LENGTH 29
 
 int create_messages();
 int create_parameters(nssm_service_t *);
-int create_exit_action(char *, const char *);
-int set_environment(char *, HKEY, char *, char **, unsigned long *);
-int expand_parameter(HKEY, char *, char *, unsigned long, bool, bool);
-int expand_parameter(HKEY, char *, char *, unsigned long, bool);
-int set_expand_string(HKEY, char *, char *);
-int set_number(HKEY, char *, unsigned long);
-int get_number(HKEY, char *, unsigned long *, bool);
-int get_number(HKEY, char *, unsigned long *);
-void override_milliseconds(char *, HKEY, char *, unsigned long *, unsigned long, unsigned long);
+int create_exit_action(TCHAR *, const TCHAR *);
+int set_environment(TCHAR *, HKEY, TCHAR *, TCHAR **, unsigned long *);
+int expand_parameter(HKEY, TCHAR *, TCHAR *, unsigned long, bool, bool);
+int expand_parameter(HKEY, TCHAR *, TCHAR *, unsigned long, bool);
+int set_expand_string(HKEY, TCHAR *, TCHAR *);
+int set_number(HKEY, TCHAR *, unsigned long);
+int get_number(HKEY, TCHAR *, unsigned long *, bool);
+int get_number(HKEY, TCHAR *, unsigned long *);
+void override_milliseconds(TCHAR *, HKEY, TCHAR *, unsigned long *, unsigned long, unsigned long);
 int get_parameters(nssm_service_t *, STARTUPINFO *);
-int get_exit_action(char *, unsigned long *, unsigned char *, bool *);
+int get_exit_action(TCHAR *, unsigned long *, TCHAR *, bool *);
 
 #endif

+ 70 - 68
service.cpp

@@ -5,7 +5,7 @@ bool use_critical_section;
 
 extern imports_t imports;
 
-const char *exit_action_strings[] = { "Restart", "Ignore", "Exit", "Suicide", 0 };
+const TCHAR *exit_action_strings[] = { _T("Restart"), _T("Ignore"), _T("Exit"), _T("Suicide"), 0 };
 
 static inline int throttle_milliseconds(unsigned long throttle) {
   /* pow() operates on doubles. */
@@ -55,7 +55,7 @@ void set_nssm_service_defaults(nssm_service_t *service) {
 /* Allocate and zero memory for a service. */
 nssm_service_t *alloc_nssm_service() {
   nssm_service_t *service = (nssm_service_t *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(nssm_service_t));
-  if (! service) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, "service", "alloc_nssm_service()", 0);
+  if (! service) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("service"), _T("alloc_nssm_service()"), 0);
   return service;
 }
 
@@ -73,42 +73,40 @@ void cleanup_nssm_service(nssm_service_t *service) {
 }
 
 /* About to install the service */
-int pre_install_service(int argc, char **argv) {
+int pre_install_service(int argc, TCHAR **argv) {
   /* Show the dialogue box if we didn't give the service name and path */
   if (argc < 2) return nssm_gui(IDD_INSTALL, argv[0]);
 
   nssm_service_t *service = alloc_nssm_service();
   if (! service) {
-    print_message(stderr, NSSM_EVENT_OUT_OF_MEMORY, "service", "pre_install_service()");
+    print_message(stderr, NSSM_EVENT_OUT_OF_MEMORY, _T("service"), _T("pre_install_service()"));
     return 1;
   }
 
   set_nssm_service_defaults(service);
-  memmove(service->name, argv[0], strlen(argv[0]));
-  memmove(service->exe, argv[1], strlen(argv[1]));
+  _sntprintf_s(service->name, _countof(service->name), _TRUNCATE, _T("%s"), argv[0]);
+  _sntprintf_s(service->exe, _countof(service->exe), _TRUNCATE, _T("%s"), argv[1]);
 
   /* Arguments are optional */
   size_t flagslen = 0;
   size_t s = 0;
   int i;
-  for (i = 2; i < argc; i++) flagslen += strlen(argv[i]) + 1;
+  for (i = 2; i < argc; i++) flagslen += _tcslen(argv[i]) + 1;
   if (! flagslen) flagslen = 1;
+  if (flagslen > _countof(service->flags)) {
+    print_message(stderr, NSSM_MESSAGE_FLAGS_TOO_LONG);
+    return 2;
+  }
 
-  /*
-    This probably isn't UTF8-safe and should use std::string or something
-    but it's been broken for the best part of a decade and due for a rewrite
-    anyway so it'll do as a quick-'n'-dirty fix.  Note that we don't free
-    the flags buffer but as the program exits that isn't a big problem.
-  */
   for (i = 2; i < argc; i++) {
-    size_t len = strlen(argv[i]);
-    memmove(service->flags + s, argv[i], len);
+    size_t len = _tcslen(argv[i]);
+    memmove(service->flags + s, argv[i], len * sizeof(TCHAR));
     s += len;
-    if (i < argc - 1) service->flags[s++] = ' ';
+    if (i < argc - 1) service->flags[s++] = _T(' ');
   }
 
   /* Work out directory name */
-  memmove(service->dir, service->exe, sizeof(service->dir));
+  _sntprintf_s(service->dir, _countof(service->dir), _TRUNCATE, _T("%s"), service->exe);
   strip_basename(service->dir);
 
   int ret = install_service(service);
@@ -117,12 +115,12 @@ int pre_install_service(int argc, char **argv) {
 }
 
 /* About to remove the service */
-int pre_remove_service(int argc, char **argv) {
+int pre_remove_service(int argc, TCHAR **argv) {
   /* Show dialogue box if we didn't pass service name and "confirm" */
   if (argc < 2) return nssm_gui(IDD_REMOVE, argv[0]);
-  if (str_equiv(argv[1], "confirm")) {
+  if (str_equiv(argv[1], _T("confirm"))) {
     nssm_service_t *service = alloc_nssm_service();
-    memmove(service->name, argv[0], strlen(argv[0]));
+    _sntprintf_s(service->name, _countof(service->name), _TRUNCATE, _T("%s"), argv[0]);
     int ret = remove_service(service);
     cleanup_nssm_service(service);
     return ret;
@@ -144,17 +142,17 @@ int install_service(nssm_service_t *service) {
   }
 
   /* Get path of this program */
-  char path[MAX_PATH];
+  TCHAR path[MAX_PATH];
   GetModuleFileName(0, path, MAX_PATH);
 
   /* Construct command */
-  char command[CMD_LENGTH];
-  size_t pathlen = strlen(path);
+  TCHAR command[CMD_LENGTH];
+  size_t pathlen = _tcslen(path);
   if (pathlen + 1 >= VALUE_LENGTH) {
     print_message(stderr, NSSM_MESSAGE_PATH_TOO_LONG, NSSM);
     return 3;
   }
-  if (_snprintf_s(command, sizeof(command), _TRUNCATE, "\"%s\"", path) < 0) {
+  if (_sntprintf_s(command, sizeof(command), _TRUNCATE, _T("\"%s\""), path) < 0) {
     print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY_FOR_IMAGEPATH);
     return 4;
   }
@@ -219,12 +217,12 @@ int remove_service(nssm_service_t *service) {
 }
 
 /* Service initialisation */
-void WINAPI service_main(unsigned long argc, char **argv) {
+void WINAPI service_main(unsigned long argc, TCHAR **argv) {
   nssm_service_t *service = alloc_nssm_service();
   if (! service) return;
 
-  if (_snprintf_s(service->name, sizeof(service->name), _TRUNCATE, "%s", argv[0]) < 0) {
-    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, "service->name", "service_main()", 0);
+  if (_sntprintf_s(service->name, _countof(service->name), _TRUNCATE, _T("%s"), argv[0]) < 0) {
+    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("service->name"), _T("service_main()"), 0);
     return;
   }
 
@@ -305,8 +303,8 @@ int monitor_service(nssm_service_t *service) {
   /* Set service status to started */
   int ret = start_service(service);
   if (ret) {
-    char code[16];
-    _snprintf_s(code, sizeof(code), _TRUNCATE, "%d", ret);
+    TCHAR code[16];
+    _sntprintf_s(code, _countof(code), _TRUNCATE, _T("%d"), ret);
     log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_START_SERVICE_FAILED, service->exe, service->name, ret, 0);
     return ret;
   }
@@ -320,32 +318,32 @@ int monitor_service(nssm_service_t *service) {
   return 0;
 }
 
-char *service_control_text(unsigned long control) {
+TCHAR *service_control_text(unsigned long control) {
   switch (control) {
     /* HACK: there is no SERVICE_CONTROL_START constant */
-    case 0: return "START";
-    case SERVICE_CONTROL_STOP: return "STOP";
-    case SERVICE_CONTROL_SHUTDOWN: return "SHUTDOWN";
-    case SERVICE_CONTROL_PAUSE: return "PAUSE";
-    case SERVICE_CONTROL_CONTINUE: return "CONTINUE";
-    case SERVICE_CONTROL_INTERROGATE: return "INTERROGATE";
+    case 0: return _T("START");
+    case SERVICE_CONTROL_STOP: return _T("STOP");
+    case SERVICE_CONTROL_SHUTDOWN: return _T("SHUTDOWN");
+    case SERVICE_CONTROL_PAUSE: return _T("PAUSE");
+    case SERVICE_CONTROL_CONTINUE: return _T("CONTINUE");
+    case SERVICE_CONTROL_INTERROGATE: return _T("INTERROGATE");
     default: return 0;
   }
 }
 
-void log_service_control(char *service_name, unsigned long control, bool handled) {
-  char *text = service_control_text(control);
+void log_service_control(TCHAR *service_name, unsigned long control, bool handled) {
+  TCHAR *text = service_control_text(control);
   unsigned long event;
 
   if (! text) {
     /* "0x" + 8 x hex + NULL */
-    text = (char *) HeapAlloc(GetProcessHeap(), 0, 11);
+    text = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, 11 * sizeof(TCHAR));
     if (! text) {
-      log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, "control code", "log_service_control()", 0);
+      log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("control code"), _T("log_service_control()"), 0);
       return;
     }
-    if (_snprintf_s(text, 11, _TRUNCATE, "0x%08x", control) < 0) {
-      log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, "control code", "log_service_control()", 0);
+    if (_sntprintf_s(text, 11, _TRUNCATE, _T("0x%08x"), control) < 0) {
+      log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("control code"), _T("log_service_control()"), 0);
       HeapFree(GetProcessHeap(), 0, text);
       return;
     }
@@ -447,9 +445,9 @@ int start_service(nssm_service_t *service) {
   }
 
   /* Launch executable with arguments */
-  char cmd[CMD_LENGTH];
-  if (_snprintf_s(cmd, sizeof(cmd), _TRUNCATE, "\"%s\" %s", service->exe, service->flags) < 0) {
-    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, "command line", "start_service", 0);
+  TCHAR cmd[CMD_LENGTH];
+  if (_sntprintf_s(cmd, _countof(cmd), _TRUNCATE, _T("\"%s\" %s"), service->exe, service->flags) < 0) {
+    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("command line"), _T("start_service"), 0);
     close_output_handles(&si);
     return stop_service(service, 2, true, true);
   }
@@ -458,7 +456,11 @@ int start_service(nssm_service_t *service) {
 
   bool inherit_handles = false;
   if (si.dwFlags & STARTF_USESTDHANDLES) inherit_handles = true;
-  if (! CreateProcess(0, cmd, 0, 0, inherit_handles, 0, service->env, service->dir, &si, &pi)) {
+  unsigned long flags = 0;
+#ifdef UNICODE
+  flags |= CREATE_UNICODE_ENVIRONMENT;
+#endif
+  if (! CreateProcess(0, cmd, 0, 0, inherit_handles, flags, service->env, service->dir, &si, &pi)) {
     unsigned long error = GetLastError();
     if (error == ERROR_INVALID_PARAMETER && service->env) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEPROCESS_FAILED_INVALID_ENVIRONMENT, service->name, service->exe, NSSM_REG_ENV, 0);
     else log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEPROCESS_FAILED, service->name, service->exe, error_string(error), 0);
@@ -479,10 +481,10 @@ int start_service(nssm_service_t *service) {
   */
   unsigned long delay = service->throttle_delay;
   if (delay > NSSM_SERVICE_STATUS_DEADLINE) {
-    char delay_milliseconds[16];
-    _snprintf_s(delay_milliseconds, sizeof(delay_milliseconds), _TRUNCATE, "%lu", delay);
-    char deadline_milliseconds[16];
-    _snprintf_s(deadline_milliseconds, sizeof(deadline_milliseconds), _TRUNCATE, "%lu", NSSM_SERVICE_STATUS_DEADLINE);
+    TCHAR delay_milliseconds[16];
+    _sntprintf_s(delay_milliseconds, _countof(delay_milliseconds), _TRUNCATE, _T("%lu"), delay);
+    TCHAR deadline_milliseconds[16];
+    _sntprintf_s(deadline_milliseconds, _countof(deadline_milliseconds), _TRUNCATE, _T("%lu"), NSSM_SERVICE_STATUS_DEADLINE);
     log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_STARTUP_DELAY_TOO_LONG, service->name, delay_milliseconds, NSSM, deadline_milliseconds, 0);
     delay = NSSM_SERVICE_STATUS_DEADLINE;
   }
@@ -560,7 +562,7 @@ void CALLBACK end_service(void *arg, unsigned char why) {
 
   /* Check exit code */
   unsigned long exitcode = 0;
-  char code[16];
+  TCHAR code[16];
   GetExitCodeProcess(service->process_handle, &exitcode);
   if (exitcode == STILL_ACTIVE || get_process_exit_time(service->process_handle, &service->exit_time)) GetSystemTimeAsFileTime(&service->exit_time);
   CloseHandle(service->process_handle);
@@ -573,7 +575,7 @@ void CALLBACK end_service(void *arg, unsigned char why) {
     tree.  See below for the possible values of the why argument.
   */
   if (! why) {
-    _snprintf_s(code, sizeof(code), _TRUNCATE, "%lu", exitcode);
+    _sntprintf_s(code, _countof(code), _TRUNCATE, _T("%lu"), exitcode);
     log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_ENDED_SERVICE, service->exe, service->name, code, 0);
   }
 
@@ -592,11 +594,11 @@ void CALLBACK end_service(void *arg, unsigned char why) {
 
   /* What action should we take? */
   int action = NSSM_EXIT_RESTART;
-  unsigned char action_string[ACTION_LEN];
+  TCHAR action_string[ACTION_LEN];
   bool default_action;
   if (! get_exit_action(service->name, &exitcode, action_string, &default_action)) {
     for (int i = 0; exit_action_strings[i]; i++) {
-      if (! _strnicmp((const char *) action_string, exit_action_strings[i], ACTION_LEN)) {
+      if (! _tcsnicmp((const TCHAR *) action_string, exit_action_strings[i], ACTION_LEN)) {
         action = i;
         break;
       }
@@ -643,9 +645,9 @@ void throttle_restart(nssm_service_t *service) {
 
   if (service->throttle > 7) service->throttle = 8;
 
-  char threshold[8], milliseconds[8];
-  _snprintf_s(threshold, sizeof(threshold), _TRUNCATE, "%lu", service->throttle_delay);
-  _snprintf_s(milliseconds, sizeof(milliseconds), _TRUNCATE, "%lu", ms);
+  TCHAR threshold[8], milliseconds[8];
+  _sntprintf_s(threshold, _countof(threshold), _TRUNCATE, _T("%lu"), service->throttle_delay);
+  _sntprintf_s(milliseconds, _countof(milliseconds), _TRUNCATE, _T("%lu"), ms);
   log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_THROTTLED, service->name, threshold, milliseconds, 0);
 
   if (use_critical_section) EnterCriticalSection(&service->throttle_section);
@@ -696,24 +698,24 @@ void throttle_restart(nssm_service_t *service) {
            0 if the wait completed.
           -1 on error.
 */
-int await_shutdown(nssm_service_t *service, char *function_name, unsigned long timeout) {
+int await_shutdown(nssm_service_t *service, TCHAR *function_name, unsigned long timeout) {
   unsigned long interval;
   unsigned long waithint;
   unsigned long ret;
   unsigned long waited;
-  char interval_milliseconds[16];
-  char timeout_milliseconds[16];
-  char waited_milliseconds[16];
-  char *function = function_name;
+  TCHAR interval_milliseconds[16];
+  TCHAR timeout_milliseconds[16];
+  TCHAR waited_milliseconds[16];
+  TCHAR *function = function_name;
 
   /* Add brackets to function name. */
-  size_t funclen = strlen(function_name) + 3;
-  char *func = (char *) HeapAlloc(GetProcessHeap(), 0, funclen);
+  size_t funclen = _tcslen(function_name) + 3;
+  TCHAR *func = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, funclen * sizeof(TCHAR));
   if (func) {
-    if (_snprintf_s(func, funclen, _TRUNCATE, "%s()", function_name) > -1) function = func;
+    if (_sntprintf_s(func, funclen, _TRUNCATE, _T("%s()"), function_name) > -1) function = func;
   }
 
-  _snprintf_s(timeout_milliseconds, sizeof(timeout_milliseconds), _TRUNCATE, "%lu", timeout);
+  _sntprintf_s(timeout_milliseconds, _countof(timeout_milliseconds), _TRUNCATE, _T("%lu"), timeout);
 
   waithint = service->status.dwWaitHint;
   waited = 0;
@@ -727,8 +729,8 @@ int await_shutdown(nssm_service_t *service, char *function_name, unsigned long t
     SetServiceStatus(service->status_handle, &service->status);
 
     if (waited) {
-      _snprintf_s(waited_milliseconds, sizeof(waited_milliseconds), _TRUNCATE, "%lu", waited);
-      _snprintf_s(interval_milliseconds, sizeof(interval_milliseconds), _TRUNCATE, "%lu", interval);
+      _sntprintf_s(waited_milliseconds, _countof(waited_milliseconds), _TRUNCATE, _T("%lu"), waited);
+      _sntprintf_s(interval_milliseconds, _countof(interval_milliseconds), _TRUNCATE, _T("%lu"), interval);
       log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_AWAITING_SHUTDOWN, function, service->name, waited_milliseconds, interval_milliseconds, timeout_milliseconds, 0);
     }
 

+ 15 - 15
service.h

@@ -17,23 +17,23 @@
 #define ACTION_LEN 16
 
 typedef struct {
-  char name[SERVICE_NAME_LENGTH];
-  char exe[EXE_LENGTH];
-  char flags[VALUE_LENGTH];
-  char dir[MAX_PATH];
-  char *env;
+  TCHAR name[SERVICE_NAME_LENGTH];
+  TCHAR exe[EXE_LENGTH];
+  TCHAR flags[VALUE_LENGTH];
+  TCHAR dir[MAX_PATH];
+  TCHAR *env;
   unsigned long envlen;
-  char *env_extra;
+  TCHAR *env_extra;
   unsigned long env_extralen;
-  char stdin_path[MAX_PATH];
+  TCHAR stdin_path[MAX_PATH];
   unsigned long stdin_sharing;
   unsigned long stdin_disposition;
   unsigned long stdin_flags;
-  char stdout_path[MAX_PATH];
+  TCHAR stdout_path[MAX_PATH];
   unsigned long stdout_sharing;
   unsigned long stdout_disposition;
   unsigned long stdout_flags;
-  char stderr_path[MAX_PATH];
+  TCHAR stderr_path[MAX_PATH];
   unsigned long stderr_sharing;
   unsigned long stderr_disposition;
   unsigned long stderr_flags;
@@ -61,17 +61,17 @@ typedef struct {
   FILETIME exit_time;
 } nssm_service_t;
 
-void WINAPI service_main(unsigned long, char **);
-char *service_control_text(unsigned long);
-void log_service_control(char *, unsigned long, bool);
+void WINAPI service_main(unsigned long, TCHAR **);
+TCHAR *service_control_text(unsigned long);
+void log_service_control(TCHAR *, unsigned long, bool);
 unsigned long WINAPI service_control_handler(unsigned long, unsigned long, void *, void *);
 
 nssm_service_t *alloc_nssm_service();
 void set_nssm_service_defaults(nssm_service_t *);
 void cleanup_nssm_service(nssm_service_t *);
 SC_HANDLE open_service_manager();
-int pre_install_service(int, char **);
-int pre_remove_service(int, char **);
+int pre_install_service(int, TCHAR **);
+int pre_remove_service(int, TCHAR **);
 int install_service(nssm_service_t *);
 int remove_service(nssm_service_t *);
 void set_service_recovery(nssm_service_t *);
@@ -80,6 +80,6 @@ int start_service(nssm_service_t *);
 int stop_service(nssm_service_t *, unsigned long, bool, bool);
 void CALLBACK end_service(void *, unsigned char);
 void throttle_restart(nssm_service_t *);
-int await_shutdown(nssm_service_t *, char *, unsigned long);
+int await_shutdown(nssm_service_t *, TCHAR *, unsigned long);
 
 #endif