blob: 99b3eaa18c34048ad93bfb2ed14ced3530e46274 [file] [log] [blame]
Constantin Kaplinsky729598c2006-05-25 05:12:25 +00001/* Copyright (C) 2002-2005 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
19// -=- Service.cxx
20
21#include <rfb_win32/Service.h>
22#include <rfb_win32/MsgWindow.h>
23#include <rfb_win32/DynamicFn.h>
24#include <rfb_win32/ModuleFileName.h>
25#include <rfb_win32/Registry.h>
26#include <rfb_win32/OSVersion.h>
27#include <rfb/Threading.h>
28#include <logmessages/messages.h>
29#include <rdr/Exception.h>
30#include <rfb/LogWriter.h>
31
32
33using namespace rdr;
34using namespace rfb;
35using namespace win32;
36
37static LogWriter vlog("Service");
38
39
40// - Internal service implementation functions
41
42Service* service = 0;
Samuel Mannehed60c41932014-02-07 14:53:24 +000043bool runAsService = false;
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000044
45VOID WINAPI serviceHandler(DWORD control) {
46 switch (control) {
47 case SERVICE_CONTROL_INTERROGATE:
48 vlog.info("cmd: report status");
49 service->setStatus();
50 return;
51 case SERVICE_CONTROL_PARAMCHANGE:
52 vlog.info("cmd: param change");
53 service->readParams();
54 return;
55 case SERVICE_CONTROL_SHUTDOWN:
56 vlog.info("cmd: OS shutdown");
57 service->osShuttingDown();
58 return;
59 case SERVICE_CONTROL_STOP:
60 vlog.info("cmd: stop");
61 service->setStatus(SERVICE_STOP_PENDING);
62 service->stop();
63 return;
64 };
65 vlog.debug("cmd: unknown %lu", control);
66}
67
68
69// -=- Message window derived class used under Win9x to implement stopService
70
71#define WM_SMSG_SERVICE_STOP WM_USER
72
73class ServiceMsgWindow : public MsgWindow {
74public:
75 ServiceMsgWindow(const TCHAR* name) : MsgWindow(name) {}
76 LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
77 switch (msg) {
78 case WM_SMSG_SERVICE_STOP:
79 service->stop();
80 return TRUE;
81 }
82 return MsgWindow::processMessage(msg, wParam, lParam);
83 }
84
85 static const TCHAR* baseName;
86};
87
88const TCHAR* ServiceMsgWindow::baseName = _T("ServiceWindow:");
89
90
91// -=- Service main procedure, used under WinNT/2K/XP by the SCM
92
93VOID WINAPI serviceProc(DWORD dwArgc, LPTSTR* lpszArgv) {
94 vlog.debug("entering %s serviceProc", service->getName());
95 vlog.info("registering handler...");
96 service->status_handle = RegisterServiceCtrlHandler(service->getName(), serviceHandler);
97 if (!service->status_handle) {
98 DWORD err = GetLastError();
99 vlog.error("failed to register handler: %lu", err);
100 ExitProcess(err);
101 }
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100102 vlog.debug("registered handler (%p)", service->status_handle);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000103 service->setStatus(SERVICE_START_PENDING);
104 vlog.debug("entering %s serviceMain", service->getName());
105 service->status.dwWin32ExitCode = service->serviceMain(dwArgc, lpszArgv);
106 vlog.debug("leaving %s serviceMain", service->getName());
107 service->setStatus(SERVICE_STOPPED);
108}
109
110
111// -=- Service
112
113Service::Service(const TCHAR* name_) : name(name_) {
114 vlog.debug("Service");
115 status_handle = 0;
116 status.dwControlsAccepted = SERVICE_CONTROL_INTERROGATE | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;
117 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;
118 status.dwWin32ExitCode = NO_ERROR;
119 status.dwServiceSpecificExitCode = 0;
120 status.dwCheckPoint = 0;
121 status.dwWaitHint = 30000;
122 status.dwCurrentState = SERVICE_STOPPED;
123}
124
125void
126Service::start() {
127 if (osVersion.isPlatformNT) {
128 SERVICE_TABLE_ENTRY entry[2];
129 entry[0].lpServiceName = (TCHAR*)name;
130 entry[0].lpServiceProc = serviceProc;
131 entry[1].lpServiceName = NULL;
132 entry[1].lpServiceProc = NULL;
133 vlog.debug("entering dispatcher");
134 if (!SetProcessShutdownParameters(0x100, 0))
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100135 vlog.error("unable to set shutdown parameters: %lu", GetLastError());
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000136 service = this;
137 if (!StartServiceCtrlDispatcher(entry))
138 throw SystemException("unable to start service", GetLastError());
139 } else {
140
141 // - Create the service window, so the service can be stopped
142 TCharArray wndName(_tcslen(getName()) + _tcslen(ServiceMsgWindow::baseName) + 1);
143 _tcscpy(wndName.buf, ServiceMsgWindow::baseName);
144 _tcscat(wndName.buf, getName());
145 ServiceMsgWindow service_window(wndName.buf);
146
147 // - Locate the RegisterServiceProcess function
148 typedef DWORD (WINAPI * _RegisterServiceProcess_proto)(DWORD, DWORD);
149 DynamicFn<_RegisterServiceProcess_proto> _RegisterServiceProcess(_T("kernel32.dll"), "RegisterServiceProcess");
150 if (!_RegisterServiceProcess.isValid())
151 throw Exception("unable to find RegisterServiceProcess");
152
153 // - Run the service
154 (*_RegisterServiceProcess)(NULL, 1);
155 service = this;
156 serviceMain(0, 0);
157 (*_RegisterServiceProcess)(NULL, 0);
158 }
159}
160
161void
162Service::setStatus() {
163 setStatus(status.dwCurrentState);
164}
165
166void
167Service::setStatus(DWORD state) {
168 if (!osVersion.isPlatformNT)
169 return;
170 if (status_handle == 0) {
171 vlog.debug("warning - cannot setStatus");
172 return;
173 }
174 status.dwCurrentState = state;
175 status.dwCheckPoint++;
176 if (!SetServiceStatus(status_handle, &status)) {
177 status.dwCurrentState = SERVICE_STOPPED;
178 status.dwWin32ExitCode = GetLastError();
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100179 vlog.error("unable to set service status:%lu", status.dwWin32ExitCode);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000180 }
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100181 vlog.debug("set status to %lu(%lu)", state, status.dwCheckPoint);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000182}
183
184Service::~Service() {
185 vlog.debug("~Service");
186 service = 0;
187}
188
189
190// Find out whether this process is running as the WinVNC service
191bool thisIsService() {
192 return service && (service->status.dwCurrentState != SERVICE_STOPPED);
193}
194
195
196// -=- Desktop handling code
197
198// Switch the current thread to the specified desktop
199static bool
200switchToDesktop(HDESK desktop) {
201 HDESK old_desktop = GetThreadDesktop(GetCurrentThreadId());
202 if (!SetThreadDesktop(desktop)) {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100203 vlog.debug("switchToDesktop failed:%lu", GetLastError());
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000204 return false;
205 }
206 if (!CloseDesktop(old_desktop))
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100207 vlog.debug("unable to close old desktop:%lu", GetLastError());
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000208 return true;
209}
210
211// Determine whether the thread's current desktop is the input one
212static bool
213inputDesktopSelected() {
214 HDESK current = GetThreadDesktop(GetCurrentThreadId());
215 HDESK input = OpenInputDesktop(0, FALSE,
216 DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
217 DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
218 DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
219 DESKTOP_SWITCHDESKTOP | GENERIC_WRITE);
220 if (!input) {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100221 vlog.debug("unable to OpenInputDesktop(1):%lu", GetLastError());
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000222 return false;
223 }
224
225 DWORD size;
226 char currentname[256];
227 char inputname[256];
228
229 if (!GetUserObjectInformation(current, UOI_NAME, currentname, 256, &size)) {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100230 vlog.debug("unable to GetUserObjectInformation(1):%lu", GetLastError());
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000231 CloseDesktop(input);
232 return false;
233 }
234 if (!GetUserObjectInformation(input, UOI_NAME, inputname, 256, &size)) {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100235 vlog.debug("unable to GetUserObjectInformation(2):%lu", GetLastError());
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000236 CloseDesktop(input);
237 return false;
238 }
239 if (!CloseDesktop(input))
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100240 vlog.debug("unable to close input desktop:%lu", GetLastError());
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000241
242 // *** vlog.debug("current=%s, input=%s", currentname, inputname);
243 bool result = strcmp(currentname, inputname) == 0;
244 return result;
245}
246
247// Switch the current thread into the input desktop
248static bool
249selectInputDesktop() {
250 // - Open the input desktop
251 HDESK desktop = OpenInputDesktop(0, FALSE,
252 DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
253 DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
254 DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
255 DESKTOP_SWITCHDESKTOP | GENERIC_WRITE);
256 if (!desktop) {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100257 vlog.debug("unable to OpenInputDesktop(2):%lu", GetLastError());
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000258 return false;
259 }
260
261 // - Switch into it
262 if (!switchToDesktop(desktop)) {
263 CloseDesktop(desktop);
264 return false;
265 }
266
267 // ***
268 DWORD size = 256;
269 char currentname[256];
270 if (GetUserObjectInformation(desktop, UOI_NAME, currentname, 256, &size)) {
271 vlog.debug("switched to %s", currentname);
272 }
273 // ***
274
275 vlog.debug("switched to input desktop");
276
277 return true;
278}
279
280
281// -=- Access points to desktop-switching routines
282
283bool
284rfb::win32::desktopChangeRequired() {
285 if (!osVersion.isPlatformNT)
286 return false;
287
288 return !inputDesktopSelected();
289}
290
291bool
292rfb::win32::changeDesktop() {
293 if (!osVersion.isPlatformNT)
294 return true;
295 if (osVersion.cannotSwitchDesktop)
296 return false;
297
298 return selectInputDesktop();
299}
300
301
302// -=- Ctrl-Alt-Del emulation
303
304class CADThread : public Thread {
305public:
306 CADThread() : Thread("CtrlAltDel Emulator"), result(false) {}
307 virtual void run() {
308 HDESK old_desktop = GetThreadDesktop(GetCurrentThreadId());
309
310 if (switchToDesktop(OpenDesktop(_T("Winlogon"), 0, FALSE, DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
311 DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
312 DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
313 DESKTOP_SWITCHDESKTOP | GENERIC_WRITE))) {
314 PostMessage(HWND_BROADCAST, WM_HOTKEY, 0, MAKELONG(MOD_ALT | MOD_CONTROL, VK_DELETE));
315 switchToDesktop(old_desktop);
316 result = true;
317 }
318 }
319 bool result;
320};
321
322bool
323rfb::win32::emulateCtrlAltDel() {
324 if (!osVersion.isPlatformNT)
325 return false;
326
Samuel Mannehed60c41932014-02-07 14:53:24 +0000327 if (osVersion.dwMajorVersion >= 6) {
328 rfb::win32::Handle sessionEventCad =
329 CreateEvent(0, FALSE, FALSE, "Global\\SessionEventTigerVNCCad");
330 SetEvent(sessionEventCad);
331 return true;
332 }
333
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000334 CADThread* cad_thread = new CADThread();
335 vlog.debug("emulate Ctrl-Alt-Del");
336 if (cad_thread) {
337 cad_thread->start();
338 cad_thread->join();
339 bool result = cad_thread->result;
340 delete cad_thread;
341 return result;
342 }
343 return false;
344}
345
346
347// -=- Application Event Log target Logger class
348
349class Logger_EventLog : public Logger {
350public:
351 Logger_EventLog(const TCHAR* srcname) : Logger("EventLog") {
352 eventlog = RegisterEventSource(NULL, srcname);
353 if (!eventlog)
354 printf("Unable to open event log:%ld\n", GetLastError());
355 }
356 ~Logger_EventLog() {
357 if (eventlog)
358 DeregisterEventSource(eventlog);
359 }
360
361 virtual void write(int level, const char *logname, const char *message) {
362 if (!eventlog) return;
363 TStr log(logname), msg(message);
364 const TCHAR* strings[] = {log, msg};
365 WORD type = EVENTLOG_INFORMATION_TYPE;
366 if (level == 0) type = EVENTLOG_ERROR_TYPE;
367 if (!ReportEvent(eventlog, type, 0, VNC4LogMessage, NULL, 2, 0, strings, NULL)) {
368 // *** It's not at all clear what is the correct behaviour if this fails...
369 printf("ReportEvent failed:%ld\n", GetLastError());
370 }
371 }
372
373protected:
374 HANDLE eventlog;
375};
376
377static Logger_EventLog* logger = 0;
378
379bool rfb::win32::initEventLogLogger(const TCHAR* srcname) {
380 if (logger)
381 return false;
382 if (osVersion.isPlatformNT) {
383 logger = new Logger_EventLog(srcname);
384 logger->registerLogger();
385 return true;
386 } else {
387 return false;
388 }
389}
390
391
392// -=- Registering and unregistering the service
393
394bool rfb::win32::registerService(const TCHAR* name, const TCHAR* desc,
Adam Tkac8fb6ac02010-06-25 11:24:27 +0000395 int argc, char** argv) {
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000396
397 // - Initialise the default service parameters
398 const TCHAR* defaultcmdline;
399 if (osVersion.isPlatformNT)
400 defaultcmdline = _T("-service");
401 else
402 defaultcmdline = _T("-noconsole -service");
403
404 // - Get the full pathname of our executable
405 ModuleFileName buffer;
406
407 // - Calculate the command-line length
408 int cmdline_len = _tcslen(buffer.buf) + 4;
409 int i;
410 for (i=0; i<argc; i++) {
411 cmdline_len += strlen(argv[i]) + 3;
412 }
413
414 // - Add the supplied extra parameters to the command line
415 TCharArray cmdline(cmdline_len+_tcslen(defaultcmdline));
416 _stprintf(cmdline.buf, _T("\"%s\" %s"), buffer.buf, defaultcmdline);
417 for (i=0; i<argc; i++) {
418 _tcscat(cmdline.buf, _T(" \""));
419 _tcscat(cmdline.buf, TStr(argv[i]));
420 _tcscat(cmdline.buf, _T("\""));
421 }
422
423 // - Register the service
424
425 if (osVersion.isPlatformNT) {
426
427 // - Open the SCM
428 ServiceHandle scm = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
429 if (!scm)
430 throw rdr::SystemException("unable to open Service Control Manager", GetLastError());
431
432
433 ServiceHandle service = CreateService(scm,
434 name, desc, SC_MANAGER_ALL_ACCESS,
435 SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
436 SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
437 cmdline.buf, NULL, NULL, NULL, NULL, NULL);
438 if (!service)
439 throw rdr::SystemException("unable to create service", GetLastError());
440
441 // - Register the event log source
442 RegKey hk, hk2;
443
444 hk2.createKey(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application"));
445 hk.createKey(hk2, name);
446
447 for (i=_tcslen(buffer.buf); i>0; i--) {
448 if (buffer.buf[i] == _T('\\')) {
449 buffer.buf[i+1] = 0;
450 break;
451 }
452 }
453
454 const TCHAR* dllFilename = _T("logmessages.dll");
455 TCharArray dllPath(_tcslen(buffer.buf) + _tcslen(dllFilename) + 1);
456 _tcscpy(dllPath.buf, buffer.buf);
457 _tcscat(dllPath.buf, dllFilename);
458
459 hk.setExpandString(_T("EventMessageFile"), dllPath.buf);
460 hk.setInt(_T("TypesSupported"), EVENTLOG_ERROR_TYPE | EVENTLOG_INFORMATION_TYPE);
461
462 } else {
463
464 RegKey services;
465 services.createKey(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows\\CurrentVersion\\RunServices"));
466 services.setString(name, cmdline.buf);
467
468 }
469
470 Sleep(500);
471
472 return true;
473}
474
475bool rfb::win32::unregisterService(const TCHAR* name) {
476 if (osVersion.isPlatformNT) {
477
478 // - Open the SCM
479 ServiceHandle scm = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
480 if (!scm)
481 throw rdr::SystemException("unable to open Service Control Manager", GetLastError());
482
483 // - Create the service
484 ServiceHandle service = OpenService(scm, name, SC_MANAGER_ALL_ACCESS);
485 if (!service)
486 throw rdr::SystemException("unable to locate the service", GetLastError());
487 if (!DeleteService(service))
488 throw rdr::SystemException("unable to remove the service", GetLastError());
489
490 // - Register the event log source
491 RegKey hk;
492 hk.openKey(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application"));
493 hk.deleteKey(name);
494
495 } else {
496
497 RegKey services;
498 services.openKey(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows\\CurrentVersion\\RunServices"));
499 services.deleteValue(name);
500
501 }
502
503 Sleep(500);
504
505 return true;
506}
507
508
509// -=- Starting and stopping the service
510
511HWND findServiceWindow(const TCHAR* name) {
512 TCharArray wndName(_tcslen(ServiceMsgWindow::baseName)+_tcslen(name)+1);
513 _tcscpy(wndName.buf, ServiceMsgWindow::baseName);
514 _tcscat(wndName.buf, name);
Peter Åstrand79ed17a2008-12-10 13:02:50 +0000515 vlog.debug("searching for %s window", wndName.buf);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000516 return FindWindow(0, wndName.buf);
517}
518
519bool rfb::win32::startService(const TCHAR* name) {
520
521 if (osVersion.isPlatformNT) {
522 // - Open the SCM
523 ServiceHandle scm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
524 if (!scm)
525 throw rdr::SystemException("unable to open Service Control Manager", GetLastError());
526
527 // - Locate the service
528 ServiceHandle service = OpenService(scm, name, SERVICE_START);
529 if (!service)
530 throw rdr::SystemException("unable to open the service", GetLastError());
531
532 // - Start the service
533 if (!StartService(service, 0, NULL))
534 throw rdr::SystemException("unable to start the service", GetLastError());
535 } else {
536 // - Check there is no service window
537 if (findServiceWindow(name))
538 throw rdr::Exception("the service is already running");
539
540 // - Find the RunServices registry key
541 RegKey services;
542 services.openKey(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows\\CurrentVersion\\RunServices"));
543
544 // - Read the command-line from it
Peter Åstrandb22dbef2008-12-09 14:57:53 +0000545 TCharArray cmdLine(services.getString(name));
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000546
547 // - Start the service
548 PROCESS_INFORMATION proc_info;
549 STARTUPINFO startup_info;
550 ZeroMemory(&startup_info, sizeof(startup_info));
551 startup_info.cb = sizeof(startup_info);
552 if (!CreateProcess(0, cmdLine.buf, 0, 0, FALSE, CREATE_NEW_CONSOLE, 0, 0, &startup_info, &proc_info)) {
553 throw SystemException("unable to start service", GetLastError());
554 }
555 }
556
557 Sleep(500);
558
559 return true;
560}
561
562bool rfb::win32::stopService(const TCHAR* name) {
563 if (osVersion.isPlatformNT) {
564 // - Open the SCM
565 ServiceHandle scm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
566 if (!scm)
567 throw rdr::SystemException("unable to open Service Control Manager", GetLastError());
568
569 // - Locate the service
570 ServiceHandle service = OpenService(scm, name, SERVICE_STOP);
571 if (!service)
572 throw rdr::SystemException("unable to open the service", GetLastError());
573
574 // - Start the service
575 SERVICE_STATUS status;
576 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
577 throw rdr::SystemException("unable to stop the service", GetLastError());
578
579 } else {
580 // - Find the service window
581 HWND service_window = findServiceWindow(name);
582 if (!service_window)
583 throw Exception("unable to locate running service");
584
585 // Tell it to quit
586 vlog.debug("sending service stop request");
587 if (!SendMessage(service_window, WM_SMSG_SERVICE_STOP, 0, 0))
588 throw Exception("unable to stop service");
589
590 // Check it's quitting...
591 DWORD process_id = 0;
592 HANDLE process = 0;
593 if (!GetWindowThreadProcessId(service_window, &process_id))
594 throw SystemException("unable to verify service has quit", GetLastError());
595 process = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, FALSE, process_id);
596 if (!process)
597 throw SystemException("unable to obtain service handle", GetLastError());
598 int retries = 5;
599 vlog.debug("checking status");
600 while (retries-- && (WaitForSingleObject(process, 1000) != WAIT_OBJECT_0)) {}
601 if (!retries) {
602 vlog.debug("failed to quit - terminating");
603 // May not have quit because of silly Win9x registry watching bug..
604 if (!TerminateProcess(process, 1))
605 throw SystemException("unable to terminate process!", GetLastError());
606 throw Exception("service failed to quit - called TerminateProcess");
607 }
608 }
609
610 Sleep(500);
611
612 return true;
613}
614
615DWORD rfb::win32::getServiceState(const TCHAR* name) {
616 if (osVersion.isPlatformNT) {
617 // - Open the SCM
618 ServiceHandle scm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
619 if (!scm)
620 throw rdr::SystemException("unable to open Service Control Manager", GetLastError());
621
622 // - Locate the service
623 ServiceHandle service = OpenService(scm, name, SERVICE_INTERROGATE);
624 if (!service)
625 throw rdr::SystemException("unable to open the service", GetLastError());
626
627 // - Get the service status
628 SERVICE_STATUS status;
629 if (!ControlService(service, SERVICE_CONTROL_INTERROGATE, (SERVICE_STATUS*)&status))
630 throw rdr::SystemException("unable to query the service", GetLastError());
631
632 return status.dwCurrentState;
633 } else {
634 HWND service_window = findServiceWindow(name);
635 return service_window ? SERVICE_RUNNING : SERVICE_STOPPED;
636 }
637}
638
639char* rfb::win32::serviceStateName(DWORD state) {
640 switch (state) {
641 case SERVICE_RUNNING: return strDup("Running");
642 case SERVICE_STOPPED: return strDup("Stopped");
643 case SERVICE_STOP_PENDING: return strDup("Stopping");
644 };
645 CharArray tmp(32);
646 sprintf(tmp.buf, "Unknown (%lu)", state);
647 return tmp.takeBuf();
648}
649
650
651bool rfb::win32::isServiceProcess() {
Samuel Mannehed60c41932014-02-07 14:53:24 +0000652 return runAsService;
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000653}