bool CArchDaemonWindows::canInstallDaemon(const char* name, bool allUsers) { // if not for all users then use the user's autostart registry. // key. if windows 95 family then use windows 95 services key. if (!allUsers || CArchMiscWindows::isWindows95Family()) { // check if we can open the registry key HKEY key = (allUsers && CArchMiscWindows::isWindows95Family()) ? open95ServicesKey() : openUserStartupKey(); CArchMiscWindows::closeKey(key); return (key != NULL); } // windows NT family services else { // check if we can open service manager for write SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE); if (mgr == NULL) { return false; } CloseServiceHandle(mgr); // check if we can open the registry key for this service HKEY key = openNTServicesKey(); key = CArchMiscWindows::openKey(key, name); key = CArchMiscWindows::openKey(key, _T("Parameters")); CArchMiscWindows::closeKey(key); return (key != NULL); } }
bool CArchDaemonWindows::isDaemonInstalled(const char* name, bool allUsers) { // if not for all users then use the user's autostart registry. // key. if windows 95 family then use windows 95 services key. if (!allUsers || CArchMiscWindows::isWindows95Family()) { // check if we can open the registry key HKEY key = (allUsers && CArchMiscWindows::isWindows95Family()) ? open95ServicesKey() : openUserStartupKey(); if (key == NULL) { return false; } // check for entry const bool installed = !CArchMiscWindows::readValueString(key, name).empty(); // clean up CArchMiscWindows::closeKey(key); return installed; } // windows NT family services else { // check parameters for this service HKEY key = openNTServicesKey(); key = CArchMiscWindows::openKey(key, name); key = CArchMiscWindows::openKey(key, _T("Parameters")); if (key != NULL) { const bool installed = !CArchMiscWindows::readValueString(key, _T("CommandLine")).empty(); CArchMiscWindows::closeKey(key); if (!installed) { return false; } } // open service manager SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ); if (mgr == NULL) { return false; } // open the service SC_HANDLE service = OpenService(mgr, name, GENERIC_READ); // clean up if (service != NULL) { CloseServiceHandle(service); } CloseServiceHandle(mgr); return (service != NULL); } }
bool ArchDaemonWindows::canInstallDaemon(const char* /*name*/) { // check if we can open service manager for write SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE); if (mgr == NULL) { return false; } CloseServiceHandle(mgr); // check if we can open the registry key HKEY key = openNTServicesKey(); ArchMiscWindows::closeKey(key); return (key != NULL); }
void ArchDaemonWindows::installDaemon(const char* name, const char* description, const char* pathname, const char* commandLine, const char* dependencies) { // open service manager SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE); if (mgr == NULL) { // can't open service manager throw XArchDaemonInstallFailed(new XArchEvalWindows); } // create the service SC_HANDLE service = CreateService( mgr, name, name, 0, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, pathname, NULL, NULL, dependencies, NULL, NULL); if (service == NULL) { // can't create service DWORD err = GetLastError(); if (err != ERROR_SERVICE_EXISTS) { CloseServiceHandle(mgr); throw XArchDaemonInstallFailed(new XArchEvalWindows(err)); } } else { // done with service (but only try to close if not null) CloseServiceHandle(service); } // done with manager CloseServiceHandle(mgr); // open the registry key for this service HKEY key = openNTServicesKey(); key = ArchMiscWindows::addKey(key, name); if (key == NULL) { // can't open key DWORD err = GetLastError(); try { uninstallDaemon(name); } catch (...) { // ignore } throw XArchDaemonInstallFailed(new XArchEvalWindows(err)); } // set the description ArchMiscWindows::setValue(key, _T("Description"), description); // set command line key = ArchMiscWindows::addKey(key, _T("Parameters")); if (key == NULL) { // can't open key DWORD err = GetLastError(); ArchMiscWindows::closeKey(key); try { uninstallDaemon(name); } catch (...) { // ignore } throw XArchDaemonInstallFailed(new XArchEvalWindows(err)); } ArchMiscWindows::setValue(key, _T("CommandLine"), commandLine); // done with registry ArchMiscWindows::closeKey(key); }
void ArchDaemonWindows::serviceMain(DWORD argc, LPTSTR* argvIn) { typedef std::vector<LPCTSTR> ArgList; typedef std::vector<std::string> Arguments; const char** argv = const_cast<const char**>(argvIn); // create synchronization objects m_serviceMutex = ARCH->newMutex(); m_serviceCondVar = ARCH->newCondVar(); // register our service handler function m_statusHandle = RegisterServiceCtrlHandler(argv[0], &ArchDaemonWindows::serviceHandlerEntry); if (m_statusHandle == 0) { // cannot start as service m_daemonResult = -1; ARCH->closeCondVar(m_serviceCondVar); ARCH->closeMutex(m_serviceMutex); return; } // tell service control manager that we're starting m_serviceState = SERVICE_START_PENDING; setStatus(m_serviceState, 0, 10000); std::string commandLine; // if no arguments supplied then try getting them from the registry. // the first argument doesn't count because it's the service name. Arguments args; ArgList myArgv; if (argc <= 1) { // read command line HKEY key = openNTServicesKey(); key = ArchMiscWindows::openKey(key, argvIn[0]); key = ArchMiscWindows::openKey(key, _T("Parameters")); if (key != NULL) { commandLine = ArchMiscWindows::readValueString(key, _T("CommandLine")); } // if the command line isn't empty then parse and use it if (!commandLine.empty()) { // parse, honoring double quoted substrings std::string::size_type i = commandLine.find_first_not_of(" \t"); while (i != std::string::npos && i != commandLine.size()) { // find end of string std::string::size_type e; if (commandLine[i] == '\"') { // quoted. find closing quote. ++i; e = commandLine.find("\"", i); // whitespace must follow closing quote if (e == std::string::npos || (e + 1 != commandLine.size() && commandLine[e + 1] != ' ' && commandLine[e + 1] != '\t')) { args.clear(); break; } // extract args.push_back(commandLine.substr(i, e - i)); i = e + 1; } else { // unquoted. find next whitespace. e = commandLine.find_first_of(" \t", i); if (e == std::string::npos) { e = commandLine.size(); } // extract args.push_back(commandLine.substr(i, e - i)); i = e + 1; } // next argument i = commandLine.find_first_not_of(" \t", i); } // service name goes first myArgv.push_back(argv[0]); // get pointers for (size_t j = 0; j < args.size(); ++j) { myArgv.push_back(args[j].c_str()); } // adjust argc/argv argc = (DWORD)myArgv.size(); argv = &myArgv[0]; } } m_commandLine = commandLine; try { // invoke daemon function m_daemonResult = m_daemonFunc(static_cast<int>(argc), argv); } catch (XArchDaemonRunFailed& e) { setStatusError(e.m_result); m_daemonResult = -1; } catch (...) { setStatusError(1); m_daemonResult = -1; } // clean up ARCH->closeCondVar(m_serviceCondVar); ARCH->closeMutex(m_serviceMutex); // we're going to exit now, so set status to stopped m_serviceState = SERVICE_STOPPED; setStatus(m_serviceState, 0, 10000); }
void ArchDaemonWindows::uninstallDaemon(const char* name) { // remove parameters for this service. ignore failures. HKEY key = openNTServicesKey(); key = ArchMiscWindows::openKey(key, name); if (key != NULL) { ArchMiscWindows::deleteKey(key, _T("Parameters")); ArchMiscWindows::closeKey(key); } // open service manager SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE); if (mgr == NULL) { // can't open service manager throw XArchDaemonUninstallFailed(new XArchEvalWindows); } // open the service. oddly, you must open a service to delete it. SC_HANDLE service = OpenService(mgr, name, DELETE | SERVICE_STOP); if (service == NULL) { DWORD err = GetLastError(); CloseServiceHandle(mgr); if (err != ERROR_SERVICE_DOES_NOT_EXIST) { throw XArchDaemonUninstallFailed(new XArchEvalWindows(err)); } throw XArchDaemonUninstallNotInstalled(new XArchEvalWindows(err)); } // stop the service. we don't care if we fail. SERVICE_STATUS status; ControlService(service, SERVICE_CONTROL_STOP, &status); // delete the service const bool okay = (DeleteService(service) == 0); const DWORD err = GetLastError(); // clean up CloseServiceHandle(service); CloseServiceHandle(mgr); // give windows a chance to remove the service before // we check if it still exists. ARCH->sleep(1); // handle failure. ignore error if service isn't installed anymore. if (!okay && isDaemonInstalled(name)) { if (err == ERROR_SUCCESS) { // this seems to occur even though the uninstall was successful. // it could be a timing issue, i.e., isDaemonInstalled is // called too soon. i've added a sleep to try and stop this. return; } if (err == ERROR_IO_PENDING) { // this seems to be a spurious error return; } if (err != ERROR_SERVICE_MARKED_FOR_DELETE) { throw XArchDaemonUninstallFailed(new XArchEvalWindows(err)); } throw XArchDaemonUninstallNotInstalled(new XArchEvalWindows(err)); } }
void CArchDaemonWindows::installDaemon(const char* name, const char* description, const char* pathname, const char* commandLine, const char* dependencies, bool allUsers) { // if not for all users then use the user's autostart registry. // key. if windows 95 family then use windows 95 services key. if (!allUsers || CArchMiscWindows::isWindows95Family()) { // open registry HKEY key = (allUsers && CArchMiscWindows::isWindows95Family()) ? open95ServicesKey() : openUserStartupKey(); if (key == NULL) { // can't open key throw XArchDaemonInstallFailed(new XArchEvalWindows); } // construct entry std::string value; value += "\""; value += pathname; value += "\" "; value += commandLine; // install entry CArchMiscWindows::setValue(key, name, value); // clean up CArchMiscWindows::closeKey(key); } // windows NT family services else { // open service manager SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE); if (mgr == NULL) { // can't open service manager throw XArchDaemonInstallFailed(new XArchEvalWindows); } // create the service SC_HANDLE service = CreateService(mgr, name, name, 0, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, pathname, NULL, NULL, dependencies, NULL, NULL); if (service == NULL) { // can't create service // FIXME -- handle ERROR_SERVICE_EXISTS DWORD err = GetLastError(); CloseServiceHandle(mgr); throw XArchDaemonInstallFailed(new XArchEvalWindows(err)); } // done with service and manager CloseServiceHandle(service); CloseServiceHandle(mgr); // open the registry key for this service HKEY key = openNTServicesKey(); key = CArchMiscWindows::openKey(key, name); if (key == NULL) { // can't open key DWORD err = GetLastError(); try { uninstallDaemon(name, allUsers); } catch (...) { // ignore } throw XArchDaemonInstallFailed(new XArchEvalWindows(err)); } // set the description CArchMiscWindows::setValue(key, _T("Description"), description); // set command line key = CArchMiscWindows::openKey(key, _T("Parameters")); if (key == NULL) { // can't open key DWORD err = GetLastError(); CArchMiscWindows::closeKey(key); try { uninstallDaemon(name, allUsers); } catch (...) { // ignore } throw XArchDaemonInstallFailed(new XArchEvalWindows(err)); } CArchMiscWindows::setValue(key, _T("CommandLine"), commandLine); // done with registry CArchMiscWindows::closeKey(key); } }
void CArchDaemonWindows::uninstallDaemon(const char* name, bool allUsers) { // if not for all users then use the user's autostart registry. // key. if windows 95 family then use windows 95 services key. if (!allUsers || CArchMiscWindows::isWindows95Family()) { // open registry HKEY key = (allUsers && CArchMiscWindows::isWindows95Family()) ? open95ServicesKey() : openUserStartupKey(); if (key == NULL) { // can't open key. daemon is probably not installed. throw XArchDaemonUninstallNotInstalled(new XArchEvalWindows); } // remove entry CArchMiscWindows::deleteValue(key, name); // clean up CArchMiscWindows::closeKey(key); } // windows NT family services else { // remove parameters for this service. ignore failures. HKEY key = openNTServicesKey(); key = CArchMiscWindows::openKey(key, name); if (key != NULL) { CArchMiscWindows::deleteKey(key, _T("Parameters")); CArchMiscWindows::closeKey(key); } // open service manager SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE); if (mgr == NULL) { // can't open service manager throw XArchDaemonUninstallFailed(new XArchEvalWindows); } // open the service. oddly, you must open a service to delete it. SC_HANDLE service = OpenService(mgr, name, DELETE); if (service == NULL) { DWORD err = GetLastError(); CloseServiceHandle(mgr); if (err != ERROR_SERVICE_DOES_NOT_EXIST) { throw XArchDaemonUninstallFailed(new XArchEvalWindows(err)); } throw XArchDaemonUninstallNotInstalled(new XArchEvalWindows(err)); } // delete the service const bool okay = (DeleteService(service) == 0); const DWORD err = GetLastError(); // clean up CloseServiceHandle(service); CloseServiceHandle(mgr); // handle failure. ignore error if service isn't installed anymore. if (!okay && isDaemonInstalled(name, allUsers)) { if (err != ERROR_SERVICE_MARKED_FOR_DELETE) { throw XArchDaemonUninstallFailed(new XArchEvalWindows(err)); } throw XArchDaemonUninstallNotInstalled(new XArchEvalWindows(err)); } } }