--- /dev/null
+/* +------------------------------------+
+ * | Inspire Internet Relay Chat Daemon |
+ * +------------------------------------+
+ *
+ * InspIRCd: (C) 2002-2008 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ * the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */\r
+\r
+#include <windows.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+extern int smain(int argc, char** argv);\r
+\r
+static SERVICE_STATUS_HANDLE serviceStatusHandle;\r
+static HANDLE hThreadEvent;\r
+static HANDLE killServiceEvent;\r
+static int serviceCurrentStatus;\r
+\r
+// This is used to define ChangeServiceConf2() as we can't link\r
+// directly against this symbol (see below where it is used)\r
+typedef BOOL (CALLBACK* SETSERVDESC)(SC_HANDLE,DWORD,LPVOID);\r
+\r
+SETSERVDESC ChangeServiceConf; // A function pointer for dynamic linking tricks\r
+\r
+\r
+void KillService()\r
+{\r
+ /* FIXME: This should set a flag in the mainloop for shutting down */\r
+ SetEvent(hThreadEvent);\r
+ Sleep(2000);\r
+ SetEvent(killServiceEvent);\r
+}\r
+\r
+DWORD WINAPI WorkerThread(LPDWORD param)\r
+{\r
+ // *** REAL MAIN HERE ***\r
+ char modname[MAX_PATH];\r
+ GetModuleFileName(NULL, modname, sizeof(modname));\r
+ char* argv[] = { modname, "--nofork" };\r
+ smain(1, argv);\r
+ KillService();\r
+ return 0;\r
+}\r
+\r
+void StartServiceThread()\r
+{\r
+ DWORD dwd;\r
+ CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WorkerThread,NULL,0,&dwd);\r
+}\r
+\r
+\r
+BOOL UpdateSCMStatus (DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint, DWORD dwWaitHint)\r
+{\r
+ BOOL success;\r
+ SERVICE_STATUS serviceStatus;\r
+ serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;\r
+ serviceStatus.dwCurrentState = dwCurrentState;\r
+\r
+ if (dwCurrentState == SERVICE_START_PENDING)\r
+ {\r
+ serviceStatus.dwControlsAccepted = 0;\r
+ }\r
+ else\r
+ {\r
+ serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;\r
+ }\r
+\r
+ if (dwServiceSpecificExitCode == 0)\r
+ {\r
+ serviceStatus.dwWin32ExitCode = dwWin32ExitCode;\r
+ }\r
+ else\r
+ {\r
+ serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;\r
+ }\r
+ serviceStatus.dwServiceSpecificExitCode = dwServiceSpecificExitCode;\r
+ serviceStatus.dwCheckPoint = dwCheckPoint;\r
+ serviceStatus.dwWaitHint = dwWaitHint;\r
+\r
+ success = SetServiceStatus (serviceStatusHandle, &serviceStatus);\r
+ if (!success)\r
+ {\r
+ KillService();\r
+ }\r
+ return success;\r
+}\r
+\r
+\r
+void terminateService (int code, int wincode)\r
+{\r
+ UpdateSCMStatus(SERVICE_STOPPED,wincode?wincode:ERROR_SERVICE_SPECIFIC_ERROR,(wincode)?0:code,0,0);\r
+ return;\r
+}\r
+\r
+\r
+VOID ServiceCtrlHandler (DWORD controlCode)\r
+{\r
+ switch(controlCode)\r
+ {\r
+ case SERVICE_CONTROL_INTERROGATE:\r
+ break;\r
+ case SERVICE_CONTROL_SHUTDOWN:\r
+ case SERVICE_CONTROL_STOP:\r
+ serviceCurrentStatus = SERVICE_STOP_PENDING;\r
+ UpdateSCMStatus(SERVICE_STOP_PENDING, NO_ERROR, 0, 1, 5000);\r
+ KillService();\r
+ UpdateSCMStatus(SERVICE_STOPPED, NO_ERROR, 0, 0, 0);\r
+ return;\r
+ default:\r
+ break;\r
+ }\r
+ UpdateSCMStatus(serviceCurrentStatus, NO_ERROR, 0, 0, 0);\r
+}\r
+\r
+\r
+VOID ServiceMain(DWORD argc, LPTSTR *argv)\r
+{\r
+ BOOL success;\r
+ DWORD type=0, size=0;\r
+\r
+ serviceStatusHandle = RegisterServiceCtrlHandler("InspIRCd", (LPHANDLER_FUNCTION)ServiceCtrlHandler);\r
+ if (!serviceStatusHandle)\r
+ {\r
+ terminateService(1,GetLastError());\r
+ return;\r
+ }\r
+\r
+ success = UpdateSCMStatus(SERVICE_START_PENDING, NO_ERROR, 0, 1, 1000);\r
+ if (!success)\r
+ {\r
+ terminateService(2,GetLastError());\r
+ return;\r
+ }\r
+\r
+ killServiceEvent = CreateEvent(NULL,true,false,NULL);\r
+ hThreadEvent = CreateEvent(NULL,true,false,NULL);\r
+\r
+ if (!killServiceEvent || !hThreadEvent)\r
+ {\r
+ terminateService(99,GetLastError());\r
+ return;\r
+ }\r
+\r
+ success = UpdateSCMStatus(SERVICE_START_PENDING, NO_ERROR, 0, 2, 1000);\r
+ if (!success)\r
+ {\r
+ terminateService(2,GetLastError());\r
+ return;\r
+ }\r
+\r
+ StartServiceThread();\r
+ serviceCurrentStatus = SERVICE_RUNNING;\r
+ success = UpdateSCMStatus(SERVICE_RUNNING, NO_ERROR, 0, 0, 0);\r
+ if (!success)\r
+ {\r
+ terminateService(6,GetLastError());\r
+ return;\r
+ }\r
+ WaitForSingleObject (killServiceEvent, INFINITE);\r
+}\r
+\r
+void InstallService(void)\r
+{\r
+ SC_HANDLE myService, scm;\r
+ SERVICE_DESCRIPTION svDesc;\r
+ HINSTANCE advapi32;\r
+\r
+ char modname[MAX_PATH];\r
+ GetModuleFileName(NULL, modname, sizeof(modname));\r
+\r
+ scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);\r
+ if (!scm)\r
+ return;\r
+\r
+ myService = CreateService(scm,"InspIRCd","Inspire IRC Daemon", SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, modname, 0, 0, 0, 0, 0);\r
+\r
+ if (!myService)\r
+ {\r
+ CloseServiceHandle(scm);\r
+ return;\r
+ }\r
+\r
+ // *** Set service description ***\r
+ // this is supported from 5.0 (win2k) onwards only, so we can't link to the definition of\r
+ // this function in advapi32.lib, otherwise the program will not run on windows NT 4. We\r
+ // must use LoadLibrary and GetProcAddress to export the function name from advapi32.dll\r
+ advapi32 = LoadLibrary("advapi32.dll");\r
+ if (advapi32)\r
+ {\r
+ ChangeServiceConf = (SETSERVDESC)GetProcAddress(advapi32,"ChangeServiceConfig2A");\r
+ if (ChangeServiceConf)\r
+ {\r
+ char desc[] = "The Inspire Internet Relay Chat Daemon hosts IRC channels and conversations. \\r
+ If this service is stopped, the IRC server will not run.";\r
+ svDesc.lpDescription = desc;\r
+ BOOL success = ChangeServiceConf(myService,SERVICE_CONFIG_DESCRIPTION, &svDesc);\r
+ if (!success)\r
+ {\r
+ CloseServiceHandle(myService);\r
+ CloseServiceHandle(scm);\r
+ return;\r
+ }\r
+ }\r
+ FreeLibrary(advapi32);\r
+ }\r
+\r
+ CloseServiceHandle(myService);\r
+ CloseServiceHandle(scm);\r
+}\r
+\r
+void RemoveService(void)\r
+{\r
+ SC_HANDLE myService, scm;\r
+\r
+ scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);\r
+ if (!scm)\r
+ return;\r
+\r
+ myService = OpenService(scm,"InspIRCd",SERVICE_ALL_ACCESS);\r
+ if (!myService)\r
+ {\r
+ CloseServiceHandle(scm);\r
+ return;\r
+ }\r
+\r
+ if (!DeleteService(myService))\r
+ {\r
+ CloseServiceHandle(myService);\r
+ CloseServiceHandle(scm);\r
+ return;\r
+ }\r
+\r
+ CloseServiceHandle(myService);\r
+ CloseServiceHandle(scm);\r
+}\r
+\r
+/* In windows, our main() flows through here, before calling the 'real' main, smain() in inspircd.cpp */\r
+int main(int argc, char** argv)\r
+{\r
+ /* Check for parameters */\r
+ /*if (argc > 0)\r
+ {\r
+ if (!_stricmp(argv[1], "--installservice"))\r
+ {\r
+ InstallService();\r
+ return 0;\r
+ }\r
+ else if (!_stricmp(argv[1], "--removeservice"))\r
+ {\r
+ RemoveService();\r
+ return 0;\r
+ }\r
+ }*/\r
+\r
+ /* First, check if the service is installed.\r
+ * if it is not, just call smain().\r
+ */\r
+ SC_HANDLE myService, scm;\r
+ scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);\r
+ if (scm)\r
+ {\r
+ myService = OpenService(scm,"InspIRCd",SERVICE_ALL_ACCESS);\r
+ if (!myService)\r
+ {\r
+ /* Service not installed or no permission to modify it */\r
+ CloseServiceHandle(scm);\r
+ smain(argc, argv);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ /* Not enough privileges to open the SCM */\r
+ smain(argc, argv);\r
+ }\r
+\r
+ CloseServiceHandle(myService);\r
+ CloseServiceHandle(scm);\r
+\r
+ /* If we get here, we know the service is installed so we can start it */\r
+\r
+ SERVICE_TABLE_ENTRY serviceTable[] =\r
+ {\r
+ {"InspIRCd", (LPSERVICE_MAIN_FUNCTION) ServiceMain },\r
+ {NULL, NULL}\r
+ };\r
+\r
+ StartServiceCtrlDispatcher(serviceTable);\r
+ return 0;\r
+}\r