vncService.cpp
上传用户:sbftbdw
上传日期:2007-01-03
资源大小:379k
文件大小:25k
源码类别:

远程控制编程

开发平台:

Visual C++

  1. //  Copyright (C) 1997, 1998 Olivetti & Oracle Research Laboratory
  2. //
  3. //  This file is part of the VNC system.
  4. //
  5. //  The VNC system is free software; you can redistribute it and/or modify
  6. //  it under the terms of the GNU General Public License as published by
  7. //  the Free Software Foundation; either version 2 of the License, or
  8. //  (at your option) any later version.
  9. //
  10. //  This program is distributed in the hope that it will be useful,
  11. //  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. //  GNU General Public License for more details.
  14. //
  15. //  You should have received a copy of the GNU General Public License
  16. //  along with this program; if not, write to the Free Software
  17. //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
  18. //  USA.
  19. //
  20. // If the source code for the VNC system is not available from the place 
  21. // whence you received this file, check http://www.orl.co.uk/vnc or contact
  22. // the authors on vnc@orl.co.uk for information on obtaining it.
  23. // vncService
  24. // Implementation of service-oriented functionality of WinVNC
  25. #include "stdhdrs.h"
  26. // Header
  27. #include "vncService.h"
  28. #include <lmcons.h>
  29. #include "omnithread.h"
  30. #include "WinVNC.h"
  31. #include "vncMenu.h"
  32. #include "vncTimedMsgBox.h"
  33. // Error message logging
  34. void LogErrorMsg(char *message);
  35. // OS-SPECIFIC ROUTINES
  36. // Create an instance of the vncService class to cause the static fields to be
  37. // initialised properly
  38. vncService init;
  39. DWORD g_platform_id;
  40. vncService::vncService()
  41. {
  42.     OSVERSIONINFO osversioninfo;
  43.     osversioninfo.dwOSVersionInfoSize = sizeof(osversioninfo);
  44.     // Get the current OS version
  45.     if (!GetVersionEx(&osversioninfo))
  46.     g_platform_id = 0;
  47.     g_platform_id = osversioninfo.dwPlatformId;
  48. }
  49. // CurrentUser - fills a buffer with the name of the current user!
  50. BOOL
  51. vncService::CurrentUser(char *buffer, UINT size)
  52. {
  53. // How to obtain the name of the current user depends upon the OS being used
  54. if ((g_platform_id == VER_PLATFORM_WIN32_NT) && vncService::RunningAsService())
  55. {
  56. // Windows NT, service-mode
  57. // Get the current Window station
  58. HWINSTA station = GetProcessWindowStation();
  59. if (station == NULL)
  60. return FALSE;
  61. // Get the current user SID size
  62. DWORD usersize;
  63. GetUserObjectInformation(station,
  64. UOI_USER_SID, NULL, 0, &usersize);
  65. // Check the required buffer size isn't zero
  66. if (usersize == 0)
  67. {
  68. // No user is logged in, so return "" as the name...
  69. if (strlen("") >= size)
  70. return FALSE;
  71. strcpy(buffer, "");
  72. return TRUE;
  73. }
  74. // *** HACK - Use the registry to get the user name...
  75. {
  76. // Look into the winlogon registry section
  77. HKEY key;
  78. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  79. "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon",
  80. 0,
  81. KEY_QUERY_VALUE,
  82. &key) != ERROR_SUCCESS)
  83. {
  84. return FALSE;
  85. }
  86. // Now retrieve the user's name...
  87. DWORD valuetype;
  88. DWORD buffersize = size;
  89. if (RegQueryValueEx(key, "DefaultUserName",
  90. NULL, &valuetype,
  91. (unsigned char *)buffer, &buffersize) != ERROR_SUCCESS)
  92. {
  93. RegCloseKey(key);
  94. return FALSE;
  95. }
  96. RegCloseKey(key);
  97. }
  98. /* *** This code gets the Logon SID, not the User SID.... :(
  99. _RPT1(_CRT_WARN, VNCLOG("username=%sn"), buffer);
  100. // Now allocate an SID and retrieve it
  101. PSID puser = (PSID) new BYTE[usersize];
  102. if (puser == NULL)
  103. return FALSE;
  104. if (!GetUserObjectInformation(station,
  105. UOI_USER_SID, puser, usersize, &usersize))
  106. {
  107. delete [] puser;
  108. return FALSE;
  109. }
  110. char sidbuffer[1024];
  111. ULONG bufflen=1024;
  112. if (GetTextualSid(puser, sidbuffer, &bufflen))
  113. {
  114.     _RPT1(_CRT_WARN, VNCLOG("sid=%sn"), sidbuffer);
  115. }
  116. // We now have the SID
  117. SID_NAME_USE nameuse = (SID_NAME_USE) 0;
  118. char domainname[4096];
  119. DWORD userlen = size;
  120. DWORD domainlen = 4096;
  121. if (!LookupAccountSid(NULL,
  122. puser,
  123. buffer, &userlen,
  124. domainname, &domainlen,
  125. &nameuse))
  126. {
  127. _RPT2(_CRT_WARN, VNCLOG("vncService : LookupAccountSid returned %d, %dn"),
  128.   GetLastError(), (int)nameuse);
  129. _RPT2(_CRT_WARN, VNCLOG("vncService : user name size = %d/%dn"),
  130.   size, userlen);
  131. // Failed to get the user's name!
  132. delete [] puser;
  133. return FALSE;
  134. }
  135. _RPT1(_CRT_WARN, VNCLOG("username=%sn"), buffer);
  136. // We should by now have the user's name!
  137. delete [] puser;
  138. */
  139. return TRUE;
  140. }
  141. else
  142. switch (g_platform_id)
  143. {
  144. // Windows 95/98, either service or application mode.
  145. // WinNT, application mode.
  146. case VER_PLATFORM_WIN32_WINDOWS:
  147. case VER_PLATFORM_WIN32_NT:
  148. {
  149. // Just call GetCurrentUser
  150. DWORD length = size;
  151. if (GetUserName(buffer, &length) == 0)
  152. {
  153. UINT error = GetLastError();
  154. if (error == ERROR_NOT_LOGGED_ON)
  155. {
  156. // No user logged on
  157. if (strlen("") >= size)
  158. return FALSE;
  159. strcpy(buffer, "");
  160. return TRUE;
  161. }
  162. else
  163. {
  164. // Genuine error...
  165. log.Print(LL_INTERR, VNCLOG("getusername error %dn"), GetLastError());
  166. return FALSE;
  167. }
  168. }
  169. }
  170. return TRUE;
  171. };
  172. // OS was not recognised!
  173. return FALSE;
  174. }
  175. // IsWin95 - returns a BOOL indicating whether the current OS is Win95
  176. BOOL
  177. vncService::IsWin95()
  178. {
  179. return (g_platform_id == VER_PLATFORM_WIN32_WINDOWS);
  180. }
  181. // IsWinNT - returns a bool indicating whether the current OS is WinNT
  182. BOOL
  183. vncService::IsWinNT()
  184. {
  185. return (g_platform_id == VER_PLATFORM_WIN32_NT);
  186. }
  187. // Internal routine to find the WinVNC menu class window and
  188. // post a message to it!
  189. BOOL
  190. PostToWinVNC(UINT message)
  191. {
  192. // Locate the hidden WinVNC menu window
  193. HWND hservwnd = FindWindow(MENU_CLASS_NAME, NULL);
  194. if (hservwnd == NULL)
  195. return FALSE;
  196. // Post the message to WinVNC
  197. PostMessage(hservwnd, message, 0, 0);
  198. return TRUE;
  199. }
  200. // Static routine only used on Windows NT to ensure we're in the right desktop
  201. // This routine is generally available to any thread at any time.
  202. // Calling with a valid desktop name will place the thread in that desktop.
  203. // Calling with a NULL name will place the thread in the current input desktop.
  204. BOOL
  205. vncService::SelectDesktop(char *name)
  206. {
  207. // Are we running on NT?
  208. if (IsWinNT())
  209. {
  210. HDESK desktop;
  211. if (name != NULL)
  212. {
  213. // Attempt to open the named desktop
  214. desktop = OpenDesktop(name, 0, FALSE,
  215. DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
  216. DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
  217. DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
  218. DESKTOP_SWITCHDESKTOP | GENERIC_WRITE);
  219. }
  220. else
  221. {
  222. // No, so open the input desktop
  223. desktop = OpenInputDesktop(0, FALSE,
  224. DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
  225. DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
  226. DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
  227. DESKTOP_SWITCHDESKTOP | GENERIC_WRITE);
  228. }
  229. // Did we succeed?
  230. if (desktop == NULL)
  231. return FALSE;
  232. if (!SetThreadDesktop(desktop))
  233. return FALSE;
  234. // We successfully switched desktops!
  235. return TRUE;
  236. }
  237. return (name == NULL);
  238. }
  239. // NT only function to establish whether we're on the current input desktop
  240. BOOL
  241. vncService::InputDesktopSelected()
  242. {
  243. // Are we running on NT?
  244. if (IsWinNT())
  245. {
  246. // Retrieve a device context for the 
  247. HDESK threaddesktop = GetThreadDesktop(GetCurrentThreadId());
  248. HDESK inputdesktop = OpenInputDesktop(0, FALSE,
  249. DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
  250. DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
  251. DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
  252. DESKTOP_SWITCHDESKTOP | GENERIC_WRITE);
  253. // Get the desktop names:
  254. // *** I think this is horribly inefficient but I'm not sure.
  255. if (inputdesktop == NULL)
  256.     return FALSE;
  257. DWORD dummy;
  258. char threadname[256];
  259. char inputname[256];
  260. if (!GetUserObjectInformation(threaddesktop, UOI_NAME, &threadname, 256, &dummy))
  261. return FALSE;
  262. _ASSERT(dummy <= 256);
  263. if (!GetUserObjectInformation(inputdesktop, UOI_NAME, &inputname, 256, &dummy))
  264. return FALSE;
  265. _ASSERT(dummy <= 256);
  266. CloseDesktop(inputdesktop);
  267. if (strcmp(threadname, inputname) != 0)
  268. return FALSE;
  269. }
  270. return TRUE;
  271. }
  272. // Static routine used to fool Winlogon into thinking CtrlAltDel was pressed
  273. void *
  274. SimulateCtrlAltDelThreadFn(void *context)
  275. {
  276. // Switch into the Winlogon desktop
  277. if (!vncService::SelectDesktop("Winlogon"))
  278. {
  279. log.Print(LL_INTERR, VNCLOG("failed to select logon desktopn"));
  280. return FALSE;
  281. }
  282. log.Print(LL_ALL, VNCLOG("generating ctrl-alt-deln"));
  283. // Fake a hotkey event to any windows we find there.... :(
  284. // Winlogon uses hotkeys to trap Ctrl-Alt-Del...
  285. PostMessage(HWND_BROADCAST, WM_HOTKEY, 0, MAKELONG(MOD_ALT | MOD_CONTROL, VK_DELETE));
  286. return NULL;
  287. }
  288. // Static routine to simulate Ctrl-Alt-Del locally
  289. BOOL
  290. vncService::SimulateCtrlAltDel()
  291. {
  292. log.Print(LL_ALL, VNCLOG("preparing to generate ctrl-alt-deln"));
  293. // Are we running on NT?
  294. if (IsWinNT())
  295. {
  296. log.Print(LL_ALL, VNCLOG("spawn ctrl-alt-del thread...n"));
  297. // *** This is an unpleasant hack.  Oh dear.
  298. // I simulate CtrAltDel by posting a WM_HOTKEY message to all
  299. // the windows on the Winlogon desktop.
  300. // This requires that the current thread is part of the Winlogon desktop.
  301. // But the current thread has hooks set & a window open, so it can't
  302. // switch desktops, so I instead spawn a new thread & let that do the work...
  303. omni_thread *thread = omni_thread::create(SimulateCtrlAltDelThreadFn);
  304. if (thread == NULL)
  305. return FALSE;
  306. thread->join(NULL);
  307. return TRUE;
  308. }
  309. return TRUE;
  310. }
  311. // Static routine to show the Properties dialog for a currently-running
  312. // copy of WinVNC, (usually a servicified version.)
  313. BOOL
  314. vncService::ShowProperties()
  315. {
  316. // Post to the WinVNC menu window
  317. if (!PostToWinVNC(MENU_PROPERTIES_SHOW))
  318. {
  319. MessageBox(NULL, "No existing instance of WinVNC could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
  320. return FALSE;
  321. }
  322. return TRUE;
  323. }
  324. // Static routine to show the About dialog for a currently-running
  325. // copy of WinVNC, (usually a servicified version.)
  326. BOOL
  327. vncService::ShowAboutBox()
  328. {
  329. // Post to the WinVNC menu window
  330. if (!PostToWinVNC(MENU_ABOUTBOX_SHOW))
  331. {
  332. MessageBox(NULL, "No existing instance of WinVNC could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
  333. return FALSE;
  334. }
  335. return TRUE;
  336. }
  337. // SERVICE-MODE ROUTINES
  338. // Service-mode defines:
  339. // Executable name
  340. #define VNCAPPNAME            "winvnc"
  341. // Internal service name
  342. #define VNCSERVICENAME        "winvnc"
  343. // Displayed service name
  344. #define VNCSERVICEDISPLAYNAME "VNC Server"
  345. // List of other required services ("dependency 1dependency 2")
  346. // *** These need filling in properly
  347. #define VNCDEPENDENCIES       ""
  348. // Internal service state
  349. SERVICE_STATUS          g_srvstatus;       // current status of the service
  350. SERVICE_STATUS_HANDLE   g_hstatus;
  351. DWORD                   g_error = 0;
  352. DWORD g_servicethread = NULL;
  353. char*                   g_errortext[256];
  354. // Forward defines of internal service functions
  355. void WINAPI ServiceMain(DWORD argc, char **argv);
  356. void ServiceWorkThread(void *arg);
  357. void ServiceStop();
  358. void WINAPI ServiceCtrl(DWORD ctrlcode);
  359. bool WINAPI CtrlHandler (DWORD ctrltype);
  360. BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint);
  361. // ROUTINE TO QUERY WHETHER THIS PROCESS IS RUNNING AS A SERVICE OR NOT
  362. BOOL g_servicemode = FALSE;
  363. BOOL
  364. vncService::RunningAsService()
  365. {
  366. return g_servicemode;
  367. }
  368. BOOL
  369. vncService::KillRunningCopy()
  370. {
  371. // Locate the hidden WinVNC menu window
  372. HWND hservwnd;
  373. while ((hservwnd = FindWindow(MENU_CLASS_NAME, NULL)) != NULL)
  374. {
  375. // Post the message to WinVNC
  376. PostMessage(hservwnd, WM_CLOSE, 0, 0);
  377. omni_thread::sleep(1);
  378. }
  379. return TRUE;
  380. }
  381. // SERVICE MAIN ROUTINE
  382. int
  383. vncService::WinVNCServiceMain()
  384. {
  385. // Mark that we are a service
  386. g_servicemode = TRUE;
  387. // How to run as a service depends upon the OS being used
  388. switch (g_platform_id)
  389. {
  390. // Windows 95/98
  391. case VER_PLATFORM_WIN32_WINDOWS:
  392. {
  393. // Obtain a handle to the kernel library
  394. HINSTANCE kerneldll = LoadLibrary("KERNEL32.DLL");
  395. if (kerneldll == NULL)
  396. break;
  397. // And find the RegisterServiceProcess function
  398. DWORD (*RegisterService)(DWORD, DWORD);
  399. RegisterService = (DWORD (*)(DWORD, DWORD))
  400. GetProcAddress(kerneldll, "RegisterServiceProcess");
  401. if (RegisterService == NULL)
  402. break;
  403. // Register this process with the OS as a service!
  404. RegisterService(NULL, 1);
  405. // Run the service itself
  406. WinVNCAppMain();
  407. // Then remove the service from the system service table
  408. RegisterService(NULL, 0);
  409. // Free the kernel library
  410. FreeLibrary(kerneldll);
  411. // *** If we don't kill the process directly here, then 
  412. // for some reason, WinVNC crashes...
  413. ExitProcess(0);
  414. }
  415. break;
  416. // Windows NT
  417. case VER_PLATFORM_WIN32_NT:
  418. {
  419. // Create a service entry table
  420. SERVICE_TABLE_ENTRY dispatchTable[] =
  421.     {
  422. {VNCSERVICENAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
  423. {NULL, NULL}
  424. };
  425. // Call the service control dispatcher with our entry table
  426. if (!StartServiceCtrlDispatcher(dispatchTable))
  427. LogErrorMsg("StartServiceCtrlDispatcher failed.");
  428. }
  429. break;
  430. };
  431. return 0;
  432. }
  433. // SERVICE MAIN ROUTINE
  434. void WINAPI ServiceMain(DWORD argc, char**argv)
  435. {
  436. // Register the service control handler
  437.     g_hstatus = RegisterServiceCtrlHandler(VNCSERVICENAME, ServiceCtrl);
  438.     if (g_hstatus == 0)
  439. return;
  440. // Set up some standard service state values
  441.     g_srvstatus.dwServiceType = SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS;
  442.     g_srvstatus.dwServiceSpecificExitCode = 0;
  443. // Give this status to the SCM
  444.     if (!ReportStatus(
  445.         SERVICE_START_PENDING, // Service state
  446.         NO_ERROR, // Exit code type
  447.         15000)) // Hint as to how long WinVNC should have hung before you assume error
  448. {
  449.         ReportStatus(
  450. SERVICE_STOPPED,
  451. g_error,
  452.             0);
  453. return;
  454. }
  455. // Now start the service for real
  456.     omni_thread *workthread = omni_thread::create(ServiceWorkThread);
  457.     return;
  458. }
  459. // SERVICE START ROUTINE - thread that calls WinVNCAppMain
  460. void ServiceWorkThread(void *arg)
  461. {
  462. // Save the current thread identifier
  463. g_servicethread = GetCurrentThreadId();
  464.     // report the status to the service control manager.
  465.     //
  466.     if (!ReportStatus(
  467.         SERVICE_RUNNING,       // service state
  468.         NO_ERROR,              // exit code
  469.         0))                    // wait hint
  470. return;
  471. // RUN!
  472. WinVNCAppMain();
  473. // Mark that we're no longer running
  474. g_servicethread = NULL;
  475. // Tell the service manager that we've stopped.
  476.     ReportStatus(
  477. SERVICE_STOPPED,
  478. g_error,
  479. 0);
  480. }
  481. // SERVICE STOP ROUTINE - post a quit message to the relevant thread
  482. void ServiceStop()
  483. {
  484. // Post a quit message to the main service thread
  485. if (g_servicethread != NULL)
  486. {
  487. PostThreadMessage(g_servicethread, WM_QUIT, 0, 0);
  488. }
  489. }
  490. // SERVICE INSTALL ROUTINE
  491. int
  492. vncService::InstallService()
  493. {
  494. const int pathlength = 2048;
  495. char path[pathlength];
  496. char servicecmd[pathlength];
  497. // Get the filename of this executable
  498.     if (GetModuleFileName(NULL, path, pathlength-(strlen(winvncRunService)+2)) == 0)
  499.     {
  500. MessageBox(NULL, "Unable to install WinVNC service", szAppName, MB_ICONEXCLAMATION | MB_OK);
  501. return 0;
  502.     }
  503. // Append the service-start flag to the end of the path:
  504. if (strlen(path) + 4 + strlen(winvncRunService) < pathlength)
  505. sprintf(servicecmd, ""%s" %s", path, winvncRunService);
  506. else
  507. return 0;
  508. // How to add the WinVNC service depends upon the OS
  509. switch (g_platform_id)
  510. {
  511. // Windows 95/98
  512. case VER_PLATFORM_WIN32_WINDOWS:
  513. {
  514. // Locate the RunService registry entry
  515. HKEY runservices;
  516. if (RegCreateKey(HKEY_LOCAL_MACHINE, 
  517. "Software\Microsoft\Windows\CurrentVersion\RunServices",
  518. &runservices) != ERROR_SUCCESS)
  519. {
  520. MessageBox(NULL, "The SCM could not be contacted - the WinVNC service was not installed", szAppName, MB_ICONEXCLAMATION | MB_OK);
  521. break;
  522. }
  523. // Attempt to add a WinVNC key
  524. if (RegSetValueEx(runservices, szAppName, 0, REG_SZ, (unsigned char *)servicecmd, strlen(servicecmd)+1) != ERROR_SUCCESS)
  525. {
  526. RegCloseKey(runservices);
  527. MessageBox(NULL, "The WinVNC service could not be installed", szAppName, MB_ICONEXCLAMATION | MB_OK);
  528. break;
  529. }
  530. RegCloseKey(runservices);
  531. // We have successfully installed the service!
  532. vncTimedMsgBox::Do(
  533. "The WinVNC service was successfully installedn"
  534. "The service will start now and will automaticallyn"
  535. "be run the next time this machine is reset",
  536. szAppName,
  537. MB_ICONINFORMATION | MB_OK);
  538. // Run the service...
  539. STARTUPINFO si;
  540. si.cb = sizeof(si);
  541. si.cbReserved2 = 0;
  542. si.lpReserved = NULL;
  543. si.lpReserved2 = NULL;
  544. si.dwFlags = 0;
  545. si.lpTitle = NULL;
  546. PROCESS_INFORMATION pi;
  547. if (!CreateProcess(
  548. NULL, servicecmd, // Program name & path
  549. NULL, NULL, // Security attributes
  550. FALSE, // Inherit handles?
  551. NORMAL_PRIORITY_CLASS, // Extra startup flags
  552. NULL, // Environment table
  553. NULL, // Current directory
  554. &si,
  555. &pi
  556. ))
  557. {
  558. MessageBox(NULL, "The WinVNC service failed to start", szAppName, MB_ICONSTOP | MB_OK);
  559. break;
  560. }
  561. }
  562. break;
  563. // Windows NT
  564. case VER_PLATFORM_WIN32_NT:
  565. {
  566. SC_HANDLE   hservice;
  567.     SC_HANDLE   hsrvmanager;
  568. // Open the default, local Service Control Manager database
  569.     hsrvmanager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  570. if (hsrvmanager != NULL)
  571. {
  572. // Create an entry for the WinVNC service
  573. hservice = CreateService(
  574. hsrvmanager, // SCManager database
  575. VNCSERVICENAME, // name of service
  576. VNCSERVICEDISPLAYNAME, // name to display
  577. SERVICE_ALL_ACCESS, // desired access
  578. SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
  579. // service type
  580. SERVICE_AUTO_START, // start type
  581. SERVICE_ERROR_NORMAL, // error control type
  582. servicecmd, // service's binary
  583. NULL, // no load ordering group
  584. NULL, // no tag identifier
  585. VNCDEPENDENCIES, // dependencies
  586. NULL, // LocalSystem account
  587. NULL); // no password
  588. if (hservice != NULL)
  589. {
  590. vncTimedMsgBox::Do(
  591. "The WinVNC service was successfully installedn"
  592. "The service may be started from the Control Panel, and willn"
  593. "automatically be run the next time this machine is reset",
  594. szAppName,
  595. MB_ICONINFORMATION | MB_OK);
  596. CloseServiceHandle(hservice);
  597. }
  598. else
  599. {
  600. MessageBox(NULL,
  601. "The WinVNC service could not be installed",
  602. szAppName,
  603. MB_ICONEXCLAMATION | MB_OK);
  604. }
  605. CloseServiceHandle(hsrvmanager);
  606. }
  607. else
  608. MessageBox(NULL,
  609. "The SCM could not be contacted - the WinVNC service was not installed",
  610. szAppName,
  611. MB_ICONEXCLAMATION | MB_OK);
  612. }
  613. break;
  614. };
  615. return 0;
  616. }
  617. // SERVICE REMOVE ROUTINE
  618. int
  619. vncService::RemoveService()
  620. {
  621. // How to remove the WinVNC service depends upon the OS
  622. switch (g_platform_id)
  623. {
  624. // Windows 95/98
  625. case VER_PLATFORM_WIN32_WINDOWS:
  626. {
  627. // Locate the RunService registry entry
  628. HKEY runservices;
  629. if (RegOpenKey(HKEY_LOCAL_MACHINE, 
  630. "Software\Microsoft\Windows\CurrentVersion\RunServices",
  631. &runservices) != ERROR_SUCCESS)
  632. {
  633. MessageBox(NULL, "The SCM could not be contacted - the WinVNC service was not removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
  634. }
  635. else
  636. {
  637. // Attempt to delete the WinVNC key
  638. if (RegDeleteValue(runservices, szAppName) != ERROR_SUCCESS)
  639. {
  640. RegCloseKey(runservices);
  641. MessageBox(NULL, "The WinVNC service could not be removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
  642. }
  643. RegCloseKey(runservices);
  644. }
  645. // Try to kill any running copy of WinVNC
  646. if (!KillRunningCopy())
  647. {
  648. MessageBox(NULL,
  649. "The WinVNC service could not be contacted",
  650. szAppName,
  651. MB_ICONEXCLAMATION | MB_OK);
  652. break;
  653. }
  654. // We have successfully removed the service!
  655. vncTimedMsgBox::Do("The WinVNC service has been removed", szAppName, MB_ICONINFORMATION | MB_OK);
  656. }
  657. break;
  658. // Windows NT
  659. case VER_PLATFORM_WIN32_NT:
  660. {
  661. SC_HANDLE   hservice;
  662. SC_HANDLE   hsrvmanager;
  663. // Open the SCM
  664.     hsrvmanager = OpenSCManager(
  665.                         NULL,                   // machine (NULL == local)
  666.                         NULL,                   // database (NULL == default)
  667.                         SC_MANAGER_ALL_ACCESS   // access required
  668.                         );
  669.     if (hsrvmanager)
  670.     {
  671.         hservice = OpenService(hsrvmanager, VNCSERVICENAME, SERVICE_ALL_ACCESS);
  672. if (hservice != NULL)
  673. {
  674. SERVICE_STATUS status;
  675. // Try to stop the WinVNC service
  676. if (ControlService(hservice, SERVICE_CONTROL_STOP, &status))
  677. {
  678. while(QueryServiceStatus(hservice, &status))
  679. {
  680. if (status.dwCurrentState == SERVICE_STOP_PENDING)
  681. Sleep(1000);
  682. else
  683. break;
  684. }
  685. if (status.dwCurrentState != SERVICE_STOPPED)
  686. MessageBox(NULL, "The WinVNC service could not be stopped", szAppName, MB_ICONEXCLAMATION | MB_OK);
  687. }
  688. // Now remove the service from the SCM
  689. if(DeleteService(hservice))
  690. vncTimedMsgBox::Do("The WinVNC service has been removed", szAppName, MB_ICONINFORMATION | MB_OK);
  691. else
  692. MessageBox(NULL, "The WinVNC service could not be removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
  693. CloseServiceHandle(hservice);
  694. }
  695. else
  696. MessageBox(NULL, "The WinVNC service could not be found", szAppName, MB_ICONEXCLAMATION | MB_OK);
  697. CloseServiceHandle(hsrvmanager);
  698. }
  699. else
  700. MessageBox(NULL, "The SCM could not be contacted - the WinVNC service was not removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
  701. }
  702. break;
  703. };
  704. return 0;
  705. }
  706. // USEFUL SERVICE SUPPORT ROUTINES
  707. // Service control routine
  708. void WINAPI ServiceCtrl(DWORD ctrlcode)
  709. {
  710. // What control code have we been sent?
  711.     switch(ctrlcode)
  712.     {
  713. case SERVICE_CONTROL_STOP:
  714. // STOP : The service must stop
  715. g_srvstatus.dwCurrentState = SERVICE_STOP_PENDING;
  716.         ServiceStop();
  717.         break;
  718.     case SERVICE_CONTROL_INTERROGATE:
  719. // QUERY : Service control manager just wants to know our state
  720. break;
  721. default:
  722. // Control code not recognised
  723. break;
  724.     }
  725. // Tell the control manager what we're up to.
  726.     ReportStatus(g_srvstatus.dwCurrentState, NO_ERROR, 0);
  727. }
  728. // Service manager status reporting
  729. BOOL ReportStatus(DWORD state,
  730.   DWORD exitcode,
  731.   DWORD waithint)
  732. {
  733. static DWORD checkpoint = 1;
  734. BOOL result = TRUE;
  735. // If we're in the start state then we don't want the control manager
  736. // sending us control messages because they'll confuse us.
  737.     if (state == SERVICE_START_PENDING)
  738. g_srvstatus.dwControlsAccepted = 0;
  739. else
  740. g_srvstatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  741. // Save the new status we've been given
  742. g_srvstatus.dwCurrentState = state;
  743. g_srvstatus.dwWin32ExitCode = exitcode;
  744. g_srvstatus.dwWaitHint = waithint;
  745. // Update the checkpoint variable to let the SCM know that we
  746. // haven't died if requests take a long time
  747. if ((state == SERVICE_RUNNING) || (state == SERVICE_STOPPED))
  748. g_srvstatus.dwCheckPoint = 0;
  749. else
  750.         g_srvstatus.dwCheckPoint = checkpoint++;
  751. // Tell the SCM our new status
  752. if (!(result = SetServiceStatus(g_hstatus, &g_srvstatus)))
  753. LogErrorMsg("SetServiceStatus failed");
  754.     return result;
  755. }
  756. // Error reporting
  757. void LogErrorMsg(char *message)
  758. {
  759.     char msgbuff[256];
  760.     HANDLE heventsrc;
  761.     char * strings[2];
  762. // Save the error code
  763. g_error = GetLastError();
  764. // Use event logging to log the error
  765.     heventsrc = RegisterEventSource(NULL, VNCSERVICENAME);
  766. sprintf(msgbuff, "%s error: %d", VNCSERVICENAME, g_error);
  767.     strings[0] = msgbuff;
  768.     strings[1] = message;
  769. if (heventsrc != NULL)
  770. {
  771. MessageBeep(MB_OK);
  772. ReportEvent(
  773. heventsrc, // handle of event source
  774. EVENTLOG_ERROR_TYPE, // event type
  775. 0, // event category
  776. 0, // event ID
  777. NULL, // current user's SID
  778. 2, // strings in 'strings'
  779. 0, // no bytes of raw data
  780. (const char **)strings, // array of error strings
  781. NULL); // no raw data
  782. DeregisterEventSource(heventsrc);
  783. }
  784. }