You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Service.cxx 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. /* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
  2. *
  3. * This is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This software is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this software; if not, write to the Free Software
  15. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  16. * USA.
  17. */
  18. // -=- Service.cxx
  19. #include <rfb_win32/Service.h>
  20. #include <rfb_win32/MsgWindow.h>
  21. #include <rfb_win32/Registry.h>
  22. #include <rfb_win32/Win32Util.h>
  23. #include <rfb_win32/OSVersion.h>
  24. #include <rfb/Threading.h>
  25. #include <rfb/LogWriter.h>
  26. #include <rfb/util.h>
  27. #include <rdr/Exception.h>
  28. #include <logmessages/messages.h>
  29. using namespace rdr;
  30. using namespace rfb;
  31. using namespace win32;
  32. static LogWriter vlog("Service");
  33. // - Internal service implementation functions
  34. Service* service = 0;
  35. VOID WINAPI serviceHandler(DWORD control) {
  36. vlog.debug("service control %u", control);
  37. switch (control) {
  38. case SERVICE_CONTROL_INTERROGATE:
  39. service->setStatus();
  40. break;
  41. case SERVICE_CONTROL_PARAMCHANGE:
  42. service->readParams();
  43. break;
  44. case SERVICE_CONTROL_SHUTDOWN:
  45. service->osShuttingDown();
  46. break;
  47. case SERVICE_CONTROL_STOP:
  48. service->setStatus(SERVICE_STOP_PENDING);
  49. service->stop();
  50. break;
  51. }
  52. }
  53. // -=- Message window derived class used under Win9x to implement stopService
  54. #define WM_SMSG_SERVICE_STOP WM_USER
  55. class ServiceMsgWindow : public MsgWindow {
  56. public:
  57. ServiceMsgWindow(const TCHAR* name) : MsgWindow(name) {}
  58. LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
  59. switch (msg) {
  60. case WM_SMSG_SERVICE_STOP:
  61. service->stop();
  62. return TRUE;
  63. }
  64. return MsgWindow::processMessage(msg, wParam, lParam);
  65. }
  66. static const TCHAR* baseName;
  67. };
  68. const TCHAR* ServiceMsgWindow::baseName = _T("ServiceWindow:");
  69. // -=- Service main procedure, used under WinNT/2K/XP by the SCM
  70. VOID WINAPI serviceProc(DWORD dwArgc, LPTSTR* lpszArgv) {
  71. vlog.debug("entering %s serviceProc", service->getName());
  72. service->status_handle = RegisterServiceCtrlHandler(service->getName(), serviceHandler);
  73. if (!service->status_handle) {
  74. vlog.error("unable to register service control handler");
  75. return;
  76. }
  77. service->setStatus(SERVICE_START_PENDING);
  78. vlog.debug("entering %s serviceMain", service->getName());
  79. service->status.dwWin32ExitCode = service->serviceMain(dwArgc, lpszArgv);
  80. vlog.debug("leaving %s serviceMain", service->getName());
  81. service->setStatus(SERVICE_STOPPED);
  82. }
  83. // -=- Service
  84. Service::Service(const TCHAR* name_) : name(name_) {
  85. vlog.debug("Service");
  86. status_handle = 0;
  87. status.dwControlsAccepted = SERVICE_CONTROL_INTERROGATE | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;
  88. status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;
  89. status.dwWin32ExitCode = NO_ERROR;
  90. status.dwServiceSpecificExitCode = 0;
  91. status.dwCheckPoint = 0;
  92. status.dwWaitHint = 30000;
  93. status.dwCurrentState = SERVICE_STOPPED;
  94. }
  95. void
  96. Service::start() {
  97. if (osVersion.isPlatformNT) {
  98. SERVICE_TABLE_ENTRY entry[2];
  99. entry[0].lpServiceName = (TCHAR*)name;
  100. entry[0].lpServiceProc = serviceProc;
  101. entry[1].lpServiceName = NULL;
  102. entry[1].lpServiceProc = NULL;
  103. vlog.debug("entering dispatcher");
  104. if (!SetProcessShutdownParameters(0x100, 0))
  105. vlog.error("unable to set shutdown parameters: %d", GetLastError());
  106. service = this;
  107. if (!StartServiceCtrlDispatcher(entry))
  108. throw SystemException("unable to start service", GetLastError());
  109. } else {
  110. // - Create the service window, so the service can be stopped
  111. TCharArray wndName(_tcslen(getName()) + _tcslen(ServiceMsgWindow::baseName) + 1);
  112. _tcscpy(wndName.buf, ServiceMsgWindow::baseName);
  113. _tcscat(wndName.buf, getName());
  114. ServiceMsgWindow service_window(wndName.buf);
  115. // - Locate the RegisterServiceProcess function
  116. typedef DWORD (WINAPI * _RegisterServiceProcess_proto)(DWORD, DWORD);
  117. DynamicFn<_RegisterServiceProcess_proto> _RegisterServiceProcess(_T("kernel32.dll"), "RegisterServiceProcess");
  118. if (!_RegisterServiceProcess.isValid())
  119. throw Exception("unable to find RegisterServiceProcess");
  120. // - Run the service
  121. (*_RegisterServiceProcess)(NULL, 1);
  122. service = this;
  123. serviceMain(0, 0);
  124. (*_RegisterServiceProcess)(NULL, 0);
  125. }
  126. }
  127. void
  128. Service::setStatus() {
  129. setStatus(status.dwCurrentState);
  130. }
  131. void
  132. Service::setStatus(DWORD state) {
  133. if (!osVersion.isPlatformNT)
  134. return;
  135. if (status_handle == 0) {
  136. vlog.debug("warning - cannot setStatus");
  137. return;
  138. }
  139. status.dwCurrentState = state;
  140. status.dwCheckPoint++;
  141. if (!SetServiceStatus(status_handle, &status)) {
  142. status.dwWin32ExitCode = GetLastError();
  143. vlog.error("unable to set service status:%u", status.dwWin32ExitCode);
  144. stop();
  145. }
  146. vlog.debug("set status to %u(%u)", state, status.dwCheckPoint);
  147. }
  148. Service::~Service() {
  149. vlog.debug("~Service");
  150. service = 0;
  151. }
  152. // Find out whether this process is running as the WinVNC service
  153. bool thisIsService() {
  154. return service && (service->status.dwCurrentState != SERVICE_STOPPED);
  155. }
  156. // -=- Desktop handling code
  157. // Switch the current thread to the specified desktop
  158. static bool
  159. switchToDesktop(HDESK desktop) {
  160. HDESK old_desktop = GetThreadDesktop(GetCurrentThreadId());
  161. if (!SetThreadDesktop(desktop)) {
  162. vlog.debug("switchToDesktop failed:%u", GetLastError());
  163. return false;
  164. }
  165. if (!CloseDesktop(old_desktop))
  166. vlog.debug("unable to close old desktop:%u", GetLastError());
  167. return true;
  168. }
  169. // Determine whether the thread's current desktop is the input one
  170. static bool
  171. inputDesktopSelected() {
  172. HDESK current = GetThreadDesktop(GetCurrentThreadId());
  173. HDESK input = OpenInputDesktop(0, FALSE,
  174. DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
  175. DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
  176. DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
  177. DESKTOP_SWITCHDESKTOP | GENERIC_WRITE);
  178. if (!input) {
  179. vlog.debug("unable to OpenInputDesktop(1):%u", GetLastError());
  180. return false;
  181. }
  182. DWORD size;
  183. char currentname[256];
  184. char inputname[256];
  185. if (!GetUserObjectInformation(current, UOI_NAME, currentname, 256, &size)) {
  186. vlog.debug("unable to GetUserObjectInformation(1):%u", GetLastError());
  187. CloseDesktop(input);
  188. return false;
  189. }
  190. if (!GetUserObjectInformation(input, UOI_NAME, inputname, 256, &size)) {
  191. vlog.debug("unable to GetUserObjectInformation(2):%u", GetLastError());
  192. CloseDesktop(input);
  193. return false;
  194. }
  195. if (!CloseDesktop(input))
  196. vlog.debug("unable to close input desktop:%u", GetLastError());
  197. // *** vlog.debug("current=%s, input=%s", currentname, inputname);
  198. bool result = strcmp(currentname, inputname) == 0;
  199. return result;
  200. }
  201. // Switch the current thread into the input desktop
  202. static bool
  203. selectInputDesktop() {
  204. // - Open the input desktop
  205. HDESK desktop = OpenInputDesktop(0, FALSE,
  206. DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
  207. DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
  208. DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
  209. DESKTOP_SWITCHDESKTOP | GENERIC_WRITE);
  210. if (!desktop) {
  211. vlog.debug("unable to OpenInputDesktop(2):%u", GetLastError());
  212. return false;
  213. }
  214. // - Switch into it
  215. if (!switchToDesktop(desktop)) {
  216. CloseDesktop(desktop);
  217. return false;
  218. }
  219. // ***
  220. DWORD size = 256;
  221. char currentname[256];
  222. if (GetUserObjectInformation(desktop, UOI_NAME, currentname, 256, &size)) {
  223. vlog.debug("switched to %s", currentname);
  224. }
  225. // ***
  226. vlog.debug("switched to input desktop");
  227. return true;
  228. }
  229. // -=- Access points to desktop-switching routines
  230. bool
  231. rfb::win32::desktopChangeRequired() {
  232. if (!osVersion.isPlatformNT)
  233. return false;
  234. return !inputDesktopSelected();
  235. }
  236. bool
  237. rfb::win32::changeDesktop() {
  238. if (!osVersion.isPlatformNT)
  239. return true;
  240. if (osVersion.cannotSwitchDesktop)
  241. return false;
  242. return selectInputDesktop();
  243. }
  244. // -=- Ctrl-Alt-Del emulation
  245. class CADThread : public Thread {
  246. public:
  247. CADThread() : Thread("CtrlAltDel Emulator"), result(false) {}
  248. virtual void run() {
  249. HDESK old_desktop = GetThreadDesktop(GetCurrentThreadId());
  250. if (switchToDesktop(OpenDesktop(_T("Winlogon"), 0, FALSE, DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
  251. DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
  252. DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
  253. DESKTOP_SWITCHDESKTOP | GENERIC_WRITE))) {
  254. PostMessage(HWND_BROADCAST, WM_HOTKEY, 0, MAKELONG(MOD_ALT | MOD_CONTROL, VK_DELETE));
  255. switchToDesktop(old_desktop);
  256. result = true;
  257. }
  258. }
  259. bool result;
  260. };
  261. bool
  262. rfb::win32::emulateCtrlAltDel() {
  263. if (!osVersion.isPlatformNT)
  264. return false;
  265. CADThread* cad_thread = new CADThread();
  266. vlog.debug("emulate Ctrl-Alt-Del");
  267. if (cad_thread) {
  268. cad_thread->start();
  269. cad_thread->join();
  270. bool result = cad_thread->result;
  271. delete cad_thread;
  272. return result;
  273. }
  274. return false;
  275. }
  276. // -=- Application Event Log target Logger class
  277. class Logger_EventLog : public Logger {
  278. public:
  279. Logger_EventLog(const TCHAR* srcname) : Logger("EventLog") {
  280. eventlog = RegisterEventSource(NULL, srcname);
  281. if (!eventlog)
  282. printf("Unable to open event log:%ld\n", GetLastError());
  283. }
  284. ~Logger_EventLog() {
  285. if (eventlog)
  286. DeregisterEventSource(eventlog);
  287. }
  288. virtual void write(int level, const char *logname, const char *message) {
  289. if (!eventlog) return;
  290. TStr log(logname), msg(message);
  291. const TCHAR* strings[] = {log, msg};
  292. WORD type = EVENTLOG_INFORMATION_TYPE;
  293. if (level == 0) type = EVENTLOG_ERROR_TYPE;
  294. if (!ReportEvent(eventlog, type, 0, VNC4LogMessage, NULL, 2, 0, strings, NULL)) {
  295. // *** It's not at all clear what is the correct behaviour if this fails...
  296. printf("ReportEvent failed:%ld\n", GetLastError());
  297. }
  298. }
  299. protected:
  300. HANDLE eventlog;
  301. };
  302. static Logger_EventLog* logger = 0;
  303. bool rfb::win32::initEventLogLogger(const TCHAR* srcname) {
  304. if (logger)
  305. return false;
  306. if (osVersion.isPlatformNT) {
  307. logger = new Logger_EventLog(srcname);
  308. logger->registerLogger();
  309. return true;
  310. } else {
  311. return false;
  312. }
  313. }
  314. // -=- Registering and unregistering the service
  315. bool rfb::win32::registerService(const TCHAR* name, const TCHAR* desc,
  316. int argc, const char* argv[]) {
  317. // - Initialise the default service parameters
  318. const TCHAR* defaultcmdline;
  319. if (osVersion.isPlatformNT)
  320. defaultcmdline = _T("-service");
  321. else
  322. defaultcmdline = _T("-noconsole -service");
  323. // - Get the full pathname of our executable
  324. ModuleFileName buffer;
  325. // - Calculate the command-line length
  326. int cmdline_len = _tcslen(buffer.buf) + 4;
  327. int i;
  328. for (i=0; i<argc; i++) {
  329. cmdline_len += strlen(argv[i]) + 3;
  330. }
  331. // - Add the supplied extra parameters to the command line
  332. TCharArray cmdline(cmdline_len+_tcslen(defaultcmdline));
  333. _stprintf(cmdline.buf, _T("\"%s\" %s"), buffer.buf, defaultcmdline);
  334. for (i=0; i<argc; i++) {
  335. _tcscat(cmdline.buf, _T(" \""));
  336. _tcscat(cmdline.buf, TStr(argv[i]));
  337. _tcscat(cmdline.buf, _T("\""));
  338. }
  339. // - Register the service
  340. if (osVersion.isPlatformNT) {
  341. // - Open the SCM
  342. ServiceHandle scm = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
  343. if (!scm)
  344. throw rdr::SystemException("unable to open Service Control Manager", GetLastError());
  345. ServiceHandle service = CreateService(scm,
  346. name, desc, SC_MANAGER_ALL_ACCESS,
  347. SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
  348. SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
  349. cmdline.buf, NULL, NULL, NULL, NULL, NULL);
  350. if (!service)
  351. throw rdr::SystemException("unable to create service", GetLastError());
  352. // - Register the event log source
  353. RegKey hk, hk2;
  354. hk2.createKey(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application"));
  355. hk.createKey(hk2, name);
  356. for (i=_tcslen(buffer.buf); i>0; i--) {
  357. if (buffer.buf[i] == _T('\\')) {
  358. buffer.buf[i+1] = 0;
  359. break;
  360. }
  361. }
  362. const TCHAR* dllFilename = _T("logmessages.dll");
  363. TCharArray dllPath(_tcslen(buffer.buf) + _tcslen(dllFilename) + 1);
  364. _tcscpy(dllPath.buf, buffer.buf);
  365. _tcscat(dllPath.buf, dllFilename);
  366. hk.setExpandString(_T("EventMessageFile"), dllPath.buf);
  367. hk.setInt(_T("TypesSupported"), EVENTLOG_ERROR_TYPE | EVENTLOG_INFORMATION_TYPE);
  368. } else {
  369. RegKey services;
  370. services.createKey(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows\\CurrentVersion\\RunServices"));
  371. services.setString(name, cmdline.buf);
  372. }
  373. Sleep(500);
  374. return true;
  375. }
  376. bool rfb::win32::unregisterService(const TCHAR* name) {
  377. if (osVersion.isPlatformNT) {
  378. // - Open the SCM
  379. ServiceHandle scm = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
  380. if (!scm)
  381. throw rdr::SystemException("unable to open Service Control Manager", GetLastError());
  382. // - Create the service
  383. ServiceHandle service = OpenService(scm, name, SC_MANAGER_ALL_ACCESS);
  384. if (!service)
  385. throw rdr::SystemException("unable to locate the service", GetLastError());
  386. if (!DeleteService(service))
  387. throw rdr::SystemException("unable to remove the service", GetLastError());
  388. // - Register the event log source
  389. RegKey hk;
  390. hk.openKey(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application"));
  391. hk.deleteKey(name);
  392. } else {
  393. RegKey services;
  394. services.openKey(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows\\CurrentVersion\\RunServices"));
  395. services.deleteValue(name);
  396. }
  397. Sleep(500);
  398. return true;
  399. }
  400. // -=- Starting and stopping the service
  401. HWND findServiceWindow(const TCHAR* name) {
  402. TCharArray wndName(_tcslen(ServiceMsgWindow::baseName)+_tcslen(name)+1);
  403. _tcscpy(wndName.buf, ServiceMsgWindow::baseName);
  404. _tcscat(wndName.buf, name);
  405. vlog.debug("searching for %s window", CStr(wndName.buf));
  406. return FindWindow(0, wndName.buf);
  407. }
  408. bool rfb::win32::startService(const TCHAR* name) {
  409. if (osVersion.isPlatformNT) {
  410. // - Open the SCM
  411. ServiceHandle scm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  412. if (!scm)
  413. throw rdr::SystemException("unable to open Service Control Manager", GetLastError());
  414. // - Locate the service
  415. ServiceHandle service = OpenService(scm, name, SERVICE_START);
  416. if (!service)
  417. throw rdr::SystemException("unable to open the service", GetLastError());
  418. // - Start the service
  419. if (!StartService(service, 0, NULL))
  420. throw rdr::SystemException("unable to start the service", GetLastError());
  421. } else {
  422. // - Check there is no service window
  423. if (findServiceWindow(name))
  424. throw rdr::Exception("the service is already running");
  425. // - Find the RunServices registry key
  426. RegKey services;
  427. services.openKey(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows\\CurrentVersion\\RunServices"));
  428. // - Read the command-line from it
  429. TCharArray cmdLine = services.getString(name);
  430. // - Start the service
  431. PROCESS_INFORMATION proc_info;
  432. STARTUPINFO startup_info;
  433. ZeroMemory(&startup_info, sizeof(startup_info));
  434. startup_info.cb = sizeof(startup_info);
  435. if (!CreateProcess(0, cmdLine.buf, 0, 0, FALSE, CREATE_NEW_CONSOLE, 0, 0, &startup_info, &proc_info)) {
  436. throw SystemException("unable to start service", GetLastError());
  437. }
  438. }
  439. Sleep(500);
  440. return true;
  441. }
  442. bool rfb::win32::stopService(const TCHAR* name) {
  443. if (osVersion.isPlatformNT) {
  444. // - Open the SCM
  445. ServiceHandle scm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  446. if (!scm)
  447. throw rdr::SystemException("unable to open Service Control Manager", GetLastError());
  448. // - Locate the service
  449. ServiceHandle service = OpenService(scm, name, SERVICE_STOP);
  450. if (!service)
  451. throw rdr::SystemException("unable to open the service", GetLastError());
  452. // - Start the service
  453. SERVICE_STATUS status;
  454. if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
  455. throw rdr::SystemException("unable to stop the service", GetLastError());
  456. } else {
  457. // - Find the service window
  458. HWND service_window = findServiceWindow(name);
  459. if (!service_window)
  460. throw Exception("unable to locate running service");
  461. // Tell it to quit
  462. vlog.debug("sending service stop request");
  463. if (!SendMessage(service_window, WM_SMSG_SERVICE_STOP, 0, 0))
  464. throw Exception("unable to stop service");
  465. // Check it's quitting...
  466. DWORD process_id = 0;
  467. HANDLE process = 0;
  468. if (!GetWindowThreadProcessId(service_window, &process_id))
  469. throw SystemException("unable to verify service has quit", GetLastError());
  470. process = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, FALSE, process_id);
  471. if (!process)
  472. throw SystemException("unable to obtain service handle", GetLastError());
  473. int retries = 5;
  474. vlog.debug("checking status");
  475. while (retries-- && (WaitForSingleObject(process, 1000) != WAIT_OBJECT_0)) {}
  476. if (!retries) {
  477. vlog.debug("failed to quit - terminating");
  478. // May not have quit because of silly Win9x registry watching bug..
  479. if (!TerminateProcess(process, 1))
  480. throw SystemException("unable to terminate process!", GetLastError());
  481. throw Exception("service failed to quit - called TerminateProcess");
  482. }
  483. }
  484. Sleep(500);
  485. return true;
  486. }
  487. void rfb::win32::printServiceStatus(const TCHAR* name) {
  488. if (osVersion.isPlatformNT) {
  489. // - Open the SCM
  490. ServiceHandle scm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  491. if (!scm)
  492. throw rdr::SystemException("unable to open Service Control Manager", GetLastError());
  493. // - Locate the service
  494. ServiceHandle service = OpenService(scm, name, SERVICE_INTERROGATE);
  495. if (!service)
  496. throw rdr::SystemException("unable to open the service", GetLastError());
  497. // - Get the service status
  498. SERVICE_STATUS status;
  499. if (!ControlService(service, SERVICE_CONTROL_INTERROGATE, (SERVICE_STATUS*)&status))
  500. throw rdr::SystemException("unable to query the service", GetLastError());
  501. printf("Service is in the ");
  502. switch (status.dwCurrentState) {
  503. case SERVICE_RUNNING: printf("running"); break;
  504. case SERVICE_STOPPED: printf("stopped"); break;
  505. case SERVICE_STOP_PENDING: printf("stop pending"); break;
  506. default: printf("unknown (%lu)", status.dwCurrentState); break;
  507. };
  508. printf(" state.\n");
  509. } else {
  510. HWND service_window = findServiceWindow(name);
  511. printf("Service is in the ");
  512. if (!service_window) printf("stopped");
  513. else printf("running");
  514. printf(" state.\n");
  515. }
  516. }
  517. bool rfb::win32::isServiceProcess() {
  518. return service != 0;
  519. }