Source code of Windows XP (NT5)
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.

1914 lines
51 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. tabsrv.cpp
  5. Abstract:
  6. This is the main module of the Tablet PC Listener service.
  7. Author:
  8. Michael Tsang (MikeTs) 01-Jun-2000
  9. Environment:
  10. User mode
  11. Revision History:
  12. --*/
  13. #ifndef INITGUID
  14. #define INITGUID
  15. #endif
  16. #include "pch.h"
  17. #include <userenv.h>
  18. extern "C"
  19. {
  20. HANDLE GetCurrentUserTokenW(WCHAR Winsta[], DWORD DesiredAccess);
  21. };
  22. //
  23. // Global data
  24. //
  25. HMODULE ghMod = NULL;
  26. DWORD gdwfTabSrv = 0;
  27. LIST_ENTRY glistNotifyClients = {0};
  28. HANDLE ghDesktopSwitchEvent = NULL;
  29. HANDLE ghmutNotifyList = NULL;
  30. HANDLE ghHotkeyEvent = NULL;
  31. HANDLE ghRefreshEvent = NULL;
  32. HANDLE ghRPCServerThread = NULL;
  33. HWND ghwndSuperTIP = NULL;
  34. HWND ghwndMouse = NULL;
  35. HWND ghwndSuperTIPInk = NULL;
  36. HCURSOR ghcurPressHold = NULL;
  37. HCURSOR ghcurNormal = NULL;
  38. UINT guimsgSuperTIPInk = 0;
  39. #ifdef DRAW_INK
  40. HWND ghwndDrawInk = NULL;
  41. #endif
  42. ISuperTip *gpISuperTip = NULL;
  43. ITellMe *gpITellMe = NULL;
  44. int gcxScreen = 0, gcyScreen = 0;
  45. int gcxPrimary = 0, gcyPrimary = 0;
  46. LONG glVirtualDesktopLeft = 0,
  47. glVirtualDesktopRight = 0,
  48. glVirtualDesktopTop = 0,
  49. glVirtualDesktopBottom = 0;
  50. LONG glLongOffset = 0, glShortOffset = 0;
  51. int giButtonsSwapped = 0;
  52. ULONG gdwMinX = 0,
  53. gdwMaxX = MAX_NORMALIZED_X,
  54. gdwRngX = MAX_NORMALIZED_X;
  55. ULONG gdwMinY = 0,
  56. gdwMaxY = MAX_NORMALIZED_Y,
  57. gdwRngY = MAX_NORMALIZED_Y;
  58. int gixIndex = 0, giyIndex = 0;
  59. INPUT gInput = {INPUT_MOUSE};
  60. DWORD gdwPenState = PENSTATE_NORMAL;
  61. DWORD gdwPenDownTime = 0;
  62. LONG glPenDownX = 0;
  63. LONG glPenDownY = 0;
  64. DWORD gdwPenUpTime = 0;
  65. LONG glPenUpX = 0;
  66. LONG glPenUpY = 0;
  67. WORD gwLastButtons = 0;
  68. CONFIG gConfig = {0};
  69. GESTURE_SETTINGS gDefGestureSettings =
  70. {
  71. sizeof(GESTURE_SETTINGS),
  72. GESTURE_FEATURE_RECOG_ENABLED |
  73. GESTURE_FEATURE_PRESSHOLD_ENABLED,
  74. 200, //iRadius
  75. 6, //iMinOutPts
  76. 800, //iMaxTimeToInspect
  77. 3, //iAspectRatio
  78. 400, //iCheckTime
  79. 4, //iPointsToExamine
  80. 50, //iStopDist
  81. 350, //iStopTime (was 200)
  82. 500, //iPressHoldTime
  83. 3, //iHoldTolerance
  84. 700, //iCancelPressHoldTime
  85. PopupSuperTIP,
  86. PopupMIP,
  87. GestureNoAction,
  88. GestureNoAction
  89. };
  90. BUTTON_SETTINGS gDefButtonSettings =
  91. {
  92. sizeof(BUTTON_SETTINGS),
  93. Enter,
  94. PageUp,
  95. InvokeNoteBook,
  96. AltEsc,
  97. PageDown,
  98. BUTTONSTATE_DEFHOTKEY
  99. };
  100. TSTHREAD gTabSrvThreads[] =
  101. {
  102. RPCServerThread, "RPCServer", TSF_RPCTHREAD,
  103. THREADF_ENABLED,
  104. 0, NULL, NULL, -1, NULL,
  105. SuperTIPThread, "SuperTIP", TSF_SUPERTIPTHREAD,
  106. THREADF_ENABLED | THREADF_SDT_POSTMSG | THREADF_RESTARTABLE,
  107. 0, NULL, NULL, -1, NULL,
  108. DeviceThread, "Digitizer", TSF_DIGITHREAD,
  109. THREADF_ENABLED | THREADF_SDT_SETEVENT | THREADF_RESTARTABLE,
  110. 0, NULL, NULL, -1, (PVOID)&gdevDigitizer,
  111. #ifdef MOUSE_THREAD
  112. MouseThread, "Mouse", TSF_MOUSETHREAD,
  113. THREADF_ENABLED | THREADF_SDT_POSTMSG | THREADF_RESTARTABLE,
  114. 0, NULL, NULL, -1, NULL,
  115. #endif
  116. DeviceThread, "Buttons", TSF_BUTTONTHREAD,
  117. THREADF_ENABLED | THREADF_SDT_SETEVENT | THREADF_RESTARTABLE,
  118. 0, NULL, NULL, -1, (PVOID)&gdevButtons,
  119. };
  120. #define NUM_THREADS ARRAYSIZE(gTabSrvThreads)
  121. TCHAR gtszTabSrvTitle[128] = {0};
  122. TCHAR gtszTabSrvName[] = TEXT(STR_TABSRV_NAME);
  123. TCHAR gtszGestureSettings[] = TEXT("GestureSettings");
  124. TCHAR gtszButtonSettings[] = TEXT("ButtonSettings");
  125. TCHAR gtszPenTilt[] = TEXT("PenTilt");
  126. TCHAR gtszLinearityMap[] = TEXT(STR_LINEARITY_MAP);
  127. TCHAR gtszRegPath[] = TEXT(STR_REGPATH_TABSRVPARAM);
  128. TCHAR gtszPortraitMode2[] = TEXT("PortraitMode2");
  129. TCHAR gtszInputDesktop[32] = {0};
  130. SERVICE_STATUS_HANDLE ghServStatus = NULL;
  131. SERVICE_STATUS gServStatus = {0};
  132. DIGITIZER_DATA gLastRawDigiReport = {0};
  133. DEVICE_DATA gdevDigitizer = {HID_USAGE_PAGE_DIGITIZER,
  134. HID_USAGE_DIGITIZER_PEN};
  135. DEVICE_DATA gdevButtons = {HID_USAGE_PAGE_CONSUMER,
  136. HID_USAGE_CONSUMERCTRL};
  137. #ifdef DEBUG
  138. NAMETABLE ServiceControlNames[] =
  139. {
  140. SERVICE_CONTROL_STOP, "Stop",
  141. SERVICE_CONTROL_PAUSE, "Pause",
  142. SERVICE_CONTROL_CONTINUE, "Continue",
  143. SERVICE_CONTROL_INTERROGATE, "Interrogate",
  144. SERVICE_CONTROL_SHUTDOWN, "Shutdown",
  145. SERVICE_CONTROL_PARAMCHANGE, "ParamChange",
  146. SERVICE_CONTROL_NETBINDADD, "NetBindAdd",
  147. SERVICE_CONTROL_NETBINDREMOVE, "NetBindRemove",
  148. SERVICE_CONTROL_NETBINDENABLE, "NetBindEnable",
  149. SERVICE_CONTROL_NETBINDDISABLE, "NetBindDisable",
  150. 0, NULL
  151. };
  152. NAMETABLE ConsoleControlNames[] =
  153. {
  154. CTRL_C_EVENT, "CtrlCEvent",
  155. CTRL_BREAK_EVENT, "CtrlBreakEvent",
  156. CTRL_CLOSE_EVENT, "CloseEvent",
  157. CTRL_LOGOFF_EVENT, "LogOffEvent",
  158. CTRL_SHUTDOWN_EVENT, "ShutDownEvent",
  159. 0, NULL
  160. };
  161. #endif
  162. /*++
  163. @doc EXTERNAL
  164. @func int | main | Program entry point.
  165. @parm IN int | icArgs | Specifies number of command line arguments.
  166. @parm IN PSZ * | apszArgs | Points to the array of argument strings.
  167. @rvalue SUCCESS | Returns 0.
  168. @rvalue FAILURE | Returns -1.
  169. --*/
  170. int __cdecl
  171. main(
  172. IN int icArgs,
  173. IN LPTSTR *aptszArgs
  174. )
  175. {
  176. TRACEPROC("main", 1)
  177. int rc = 0;
  178. TRACEINIT(STR_TABSRV_NAME, 0, 0);
  179. TRACEENTER(("(icArgs=%d,aptszArgs=%p)\n", icArgs, aptszArgs));
  180. ghMod = GetModuleHandle(NULL);
  181. TRACEASSERT(ghMod != NULL);
  182. LoadString(ghMod,
  183. IDS_TABSRV_TITLE,
  184. gtszTabSrvTitle,
  185. ARRAYSIZE(gtszTabSrvTitle));
  186. if (icArgs == 1)
  187. {
  188. //
  189. // No command line argument, must be SCM...
  190. //
  191. SERVICE_TABLE_ENTRY ServiceTable[] =
  192. {
  193. {gtszTabSrvName, TabSrvMain},
  194. {NULL, NULL}
  195. };
  196. if (!StartServiceCtrlDispatcher(ServiceTable))
  197. {
  198. TABSRVERR(("Failed to start service dispatcher (err=%d).\n",
  199. GetLastError()));
  200. rc = -1;
  201. }
  202. }
  203. else if (icArgs == 2)
  204. {
  205. if ((aptszArgs[1][0] == TEXT('-')) || (aptszArgs[1][0] == TEXT('/')))
  206. {
  207. if (lstrcmpi(&aptszArgs[1][1], TEXT("install")) == 0)
  208. {
  209. InstallTabSrv();
  210. }
  211. #ifdef ALLOW_REMOVE
  212. else if (lstrcmpi(&aptszArgs[1][1], TEXT("remove")) == 0)
  213. {
  214. RemoveTabSrv();
  215. }
  216. #endif
  217. #ifdef ALLOW_START
  218. else if (lstrcmpi(&aptszArgs[1][1], TEXT("start")) == 0)
  219. {
  220. StartTabSrv();
  221. }
  222. #endif
  223. #ifdef ALLOW_STOP
  224. else if (lstrcmpi(&aptszArgs[1][1], TEXT("stop")) == 0)
  225. {
  226. StopTabSrv();
  227. }
  228. #endif
  229. #ifdef ALLOW_DEBUG
  230. else if (lstrcmpi(&aptszArgs[1][1], TEXT("debug")) == 0)
  231. {
  232. gdwfTabSrv |= TSF_DEBUG_MODE;
  233. SetConsoleCtrlHandler(TabSrvConsoleHandler, TRUE);
  234. TabSrvMain(0, NULL);
  235. }
  236. #endif
  237. else
  238. {
  239. TABSRVERR(("Invalid command line argument \"%s\".\n",
  240. aptszArgs[1]));
  241. rc = -1;
  242. }
  243. }
  244. else
  245. {
  246. TABSRVERR(("Invalid command line syntax \"%s\".\n", aptszArgs[1]));
  247. rc = -1;
  248. }
  249. }
  250. else
  251. {
  252. TABSRVERR(("Too many command line arguments.\n"));
  253. rc = -1;
  254. }
  255. TRACEEXIT(("=%d\n", rc));
  256. TRACETERMINATE();
  257. return rc;
  258. } //main
  259. /*++
  260. @doc INTERNAL
  261. @func VOID | InstallTabSrv | Install TabSrv service.
  262. @parm None.
  263. @rvalue None.
  264. --*/
  265. VOID
  266. InstallTabSrv(
  267. VOID
  268. )
  269. {
  270. TRACEPROC("InstallTabSrv", 2)
  271. SC_HANDLE hSCM;
  272. SC_HANDLE hService;
  273. TRACEENTER(("()\n"));
  274. hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  275. TRACEASSERT(hSCM != NULL);
  276. hService = CreateService(hSCM,
  277. gtszTabSrvName,
  278. gtszTabSrvTitle,
  279. SERVICE_ALL_ACCESS | SERVICE_CHANGE_CONFIG,
  280. SERVICE_WIN32_OWN_PROCESS,
  281. SERVICE_AUTO_START,
  282. SERVICE_ERROR_NORMAL,
  283. TEXT("%SystemRoot%\\system32\\tabsrv.exe"),
  284. NULL,
  285. NULL,
  286. NULL,
  287. NULL,
  288. NULL);
  289. if (hService != NULL)
  290. {
  291. SetTabSrvConfig(hService);
  292. CloseServiceHandle(hService);
  293. }
  294. else
  295. {
  296. TABSRVERR(("Failed to create TabSrv service (err=%d).\n",
  297. GetLastError()));
  298. }
  299. CloseServiceHandle(hSCM);
  300. //
  301. // Go ahead and start the service for no-reboot install.
  302. //
  303. StartTabSrv();
  304. TRACEEXIT(("!\n"));
  305. return;
  306. } //InstallTabSrv
  307. /*++
  308. @doc INTERNAL
  309. @func VOID | SetTabSrvConfig | Set service configuration.
  310. @parm IN SC_HANDLE | hService | Service handle.
  311. @rvalue None.
  312. --*/
  313. VOID
  314. SetTabSrvConfig(
  315. IN SC_HANDLE hService
  316. )
  317. {
  318. TRACEPROC("SetTabSrvConfig", 2)
  319. SERVICE_FAILURE_ACTIONS FailActions;
  320. SC_ACTION Actions = {SC_ACTION_RESTART, 10000}; //restart after 10 sec.
  321. TRACEENTER(("(hService=%x)\n", hService));
  322. FailActions.dwResetPeriod = 86400; //reset failure count after 1 day.
  323. FailActions.lpRebootMsg = FailActions.lpCommand = NULL;
  324. FailActions.cActions = 1;
  325. FailActions.lpsaActions = &Actions;
  326. if (!ChangeServiceConfig2(hService,
  327. SERVICE_CONFIG_FAILURE_ACTIONS,
  328. &FailActions))
  329. {
  330. TABSRVERR(("Failed to set failure actions (err=%d)\n", GetLastError()));
  331. }
  332. TRACEEXIT(("!\n"));
  333. return;
  334. } //SetTabSrvConfig
  335. /*++
  336. @doc INTERNAL
  337. @func VOID | RemoveTabSrv | Remove TabSrv service.
  338. @parm None.
  339. @rvalue None.
  340. --*/
  341. VOID
  342. RemoveTabSrv(
  343. VOID
  344. )
  345. {
  346. TRACEPROC("RemoveTabSrv", 2)
  347. SC_HANDLE hSCM;
  348. SC_HANDLE hService;
  349. TRACEENTER(("()\n"));
  350. //
  351. // Stop the service first
  352. //
  353. StopTabSrv();
  354. hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  355. TRACEASSERT(hSCM != NULL);
  356. hService = OpenService(hSCM, gtszTabSrvName, DELETE);
  357. if (hService != NULL)
  358. {
  359. DeleteService(hService);
  360. CloseServiceHandle(hService);
  361. }
  362. else
  363. {
  364. TABSRVERR(("Failed to open service for delete.\n"));
  365. }
  366. CloseServiceHandle(hSCM);
  367. TRACEEXIT(("!\n"));
  368. return;
  369. } //RemoveTabSrv
  370. /*++
  371. @doc INTERNAL
  372. @func VOID | StartTabSrv | Start TabSrv service.
  373. @parm None.
  374. @rvalue None.
  375. --*/
  376. VOID
  377. StartTabSrv(
  378. VOID
  379. )
  380. {
  381. TRACEPROC("StartTabSrv", 2)
  382. SC_HANDLE hSCM;
  383. SC_HANDLE hService;
  384. TRACEENTER(("()\n"));
  385. hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  386. TRACEASSERT(hSCM != NULL);
  387. hService = OpenService(hSCM, gtszTabSrvName, SERVICE_START);
  388. if (hService != NULL)
  389. {
  390. if (!StartService(hService, 0, NULL))
  391. {
  392. TABSRVERR(("Failed to start service (err=%d).\n", GetLastError()));
  393. }
  394. CloseServiceHandle(hService);
  395. }
  396. else
  397. {
  398. TABSRVERR(("Failed to open service for start.\n"));
  399. }
  400. CloseServiceHandle(hSCM);
  401. TRACEEXIT(("!\n"));
  402. return;
  403. } //StartTabSrv
  404. /*++
  405. @doc INTERNAL
  406. @func VOID | StopTabSrv | Stop TabSrv service.
  407. @parm None.
  408. @rvalue None.
  409. --*/
  410. VOID
  411. StopTabSrv(
  412. VOID
  413. )
  414. {
  415. TRACEPROC("StopTabSrv", 2)
  416. SC_HANDLE hSCM;
  417. SC_HANDLE hService;
  418. SERVICE_STATUS Status;
  419. TRACEENTER(("()\n"));
  420. hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  421. TRACEASSERT(hSCM != NULL);
  422. hService = OpenService(hSCM, gtszTabSrvName, SERVICE_STOP);
  423. if (hService != NULL)
  424. {
  425. if (!ControlService(hService, SERVICE_CONTROL_STOP, &Status))
  426. {
  427. TABSRVERR(("Failed to stop service (err=%d).\n", GetLastError()));
  428. }
  429. CloseServiceHandle(hService);
  430. }
  431. else
  432. {
  433. TABSRVERR(("Failed to open service for stop.\n"));
  434. }
  435. CloseServiceHandle(hSCM);
  436. TRACEEXIT(("!\n"));
  437. return;
  438. } //StopTabSrv
  439. /*++
  440. @doc EXTERNAL
  441. @func VOID | TabSrvServiceHandler | Service handler.
  442. @parm IN DWORD | dwControl | Control code.
  443. @rvalue None.
  444. --*/
  445. VOID WINAPI
  446. TabSrvServiceHandler(
  447. IN DWORD dwControl
  448. )
  449. {
  450. TRACEPROC("TabSrvServiceHandler", 3)
  451. TRACEENTER(("(Control=%s)\n", LookupName(dwControl, ServiceControlNames)));
  452. switch (dwControl)
  453. {
  454. case SERVICE_CONTROL_INTERROGATE:
  455. SetServiceStatus(ghServStatus, &gServStatus);
  456. break;
  457. case SERVICE_CONTROL_STOP:
  458. case SERVICE_CONTROL_SHUTDOWN:
  459. SET_SERVICE_STATUS(SERVICE_STOP_PENDING);
  460. TabSrvTerminate(TRUE);
  461. break;
  462. default:
  463. TRACEWARN(("Unhandled control code (%s).\n",
  464. LookupName(dwControl, ServiceControlNames)));
  465. }
  466. TRACEEXIT(("!\n"));
  467. return;
  468. } //TabSrvServiceHandler
  469. #ifdef ALLOW_DEBUG
  470. /*++
  471. @doc EXTERNAL
  472. @func BOOL | TabSrvConsoleHandler | Console control handler.
  473. @parm IN DWORD | dwControl | Control code.
  474. @rvalue SUCCESS | Returns TRUE - handle the event.
  475. @rvalue FAILURE | Returns FALSE - do not handle the event.
  476. --*/
  477. BOOL WINAPI
  478. TabSrvConsoleHandler(
  479. IN DWORD dwControl
  480. )
  481. {
  482. TRACEPROC("TabSrvConsoleHandler", 3)
  483. BOOL rc = FALSE;
  484. TRACEENTER(("(Control=%s)\n", LookupName(dwControl, ConsoleControlNames)));
  485. switch (dwControl)
  486. {
  487. case CTRL_C_EVENT:
  488. case CTRL_BREAK_EVENT:
  489. case CTRL_CLOSE_EVENT:
  490. SET_SERVICE_STATUS(SERVICE_STOP_PENDING);
  491. TabSrvTerminate(TRUE);
  492. rc = TRUE;
  493. break;
  494. }
  495. TRACEEXIT(("=%x\n", rc));
  496. return rc;
  497. } //TabSrvConsoleHandler
  498. #endif
  499. /*++
  500. @doc EXTERNAL
  501. @func VOID | TabSrvMain | Service entry point.
  502. @parm IN int | icArgs | Specifies number of command line arguments.
  503. @parm IN PSZ * | apszArgs | Points to the array of argument strings.
  504. @rvalue None.
  505. --*/
  506. VOID WINAPI
  507. TabSrvMain(
  508. IN DWORD icArgs,
  509. IN LPTSTR *aptszArgs
  510. )
  511. {
  512. TRACEPROC("TabSrvMain", 2)
  513. TRACEENTER(("(icArgs=%d,aptszArgs=%p)\n", icArgs, aptszArgs));
  514. if ((icArgs == 2) && (lstrcmpi(aptszArgs[1], TEXT("/config")) == 0))
  515. {
  516. SC_HANDLE hSCM;
  517. SC_HANDLE hService;
  518. hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  519. TRACEASSERT(hSCM != NULL);
  520. hService = OpenService(hSCM,
  521. gtszTabSrvName,
  522. SERVICE_ALL_ACCESS | SERVICE_CHANGE_CONFIG);
  523. if (hService != NULL)
  524. {
  525. SetTabSrvConfig(hService);
  526. CloseServiceHandle(hService);
  527. }
  528. else
  529. {
  530. TABSRVERR(("Failed to open service for config.\n"));
  531. }
  532. CloseServiceHandle(hSCM);
  533. }
  534. InitializeListHead(&glistNotifyClients);
  535. ghcurPressHold = LoadCursor(ghMod, MAKEINTRESOURCE(IDC_PRESSHOLD));
  536. TRACEASSERT(ghcurPressHold != NULL);
  537. ghcurNormal = LoadCursor(ghMod, MAKEINTRESOURCE(IDC_NORMAL));
  538. TRACEASSERT(ghcurNormal != NULL);
  539. ghDesktopSwitchEvent = OpenEvent(SYNCHRONIZE,
  540. FALSE,
  541. TEXT("WinSta0_DesktopSwitch"));
  542. TRACEASSERT(ghDesktopSwitchEvent != NULL);
  543. ghmutNotifyList = CreateMutex(NULL, FALSE, NULL);
  544. TRACEASSERT(ghmutNotifyList != NULL);
  545. gdevDigitizer.hStopDeviceEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  546. TRACEASSERT(gdevDigitizer.hStopDeviceEvent != NULL);
  547. FindThread(TSF_DIGITHREAD)->pvSDTParam = gdevDigitizer.hStopDeviceEvent;
  548. gdevButtons.hStopDeviceEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  549. TRACEASSERT(gdevButtons.hStopDeviceEvent != NULL);
  550. FindThread(TSF_BUTTONTHREAD)->pvSDTParam = gdevButtons.hStopDeviceEvent;
  551. ghHotkeyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  552. TRACEASSERT(ghHotkeyEvent != NULL);
  553. ghRefreshEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  554. TRACEASSERT(ghRefreshEvent != NULL);
  555. gServStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  556. gServStatus.dwCurrentState = SERVICE_START_PENDING;
  557. gServStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  558. SERVICE_ACCEPT_SHUTDOWN;
  559. gServStatus.dwWin32ExitCode = NO_ERROR;
  560. gServStatus.dwServiceSpecificExitCode = NO_ERROR;
  561. gServStatus.dwCheckPoint = 0;
  562. gServStatus.dwWaitHint = 0;
  563. UpdateRotation();
  564. if (!(gdwfTabSrv & TSF_DEBUG_MODE))
  565. {
  566. ghServStatus = RegisterServiceCtrlHandler(gtszTabSrvName,
  567. TabSrvServiceHandler);
  568. TRACEASSERT(ghServStatus != NULL);
  569. SetServiceStatus(ghServStatus, &gServStatus);
  570. }
  571. //
  572. // For a noninteractive service application to interact with the user,
  573. // it must open the user's window station ("WinSta0") and desktop
  574. // ("Default").
  575. //
  576. HWINSTA hwinstaSave = GetProcessWindowStation();
  577. HWINSTA hwinsta = OpenWindowStation(TEXT("WinSta0"),
  578. FALSE,
  579. MAXIMUM_ALLOWED);
  580. TRACEASSERT(hwinstaSave != NULL);
  581. if (hwinsta != NULL)
  582. {
  583. SetProcessWindowStation(hwinsta);
  584. InitConfigFromReg();
  585. GetInputDesktopName(gtszInputDesktop, sizeof(gtszInputDesktop));
  586. if (InitThreads(gTabSrvThreads, NUM_THREADS))
  587. {
  588. SET_SERVICE_STATUS(SERVICE_RUNNING);
  589. WaitForTermination();
  590. SET_SERVICE_STATUS(SERVICE_STOPPED);
  591. }
  592. else
  593. {
  594. TabSrvTerminate(TRUE);
  595. }
  596. if (hwinstaSave != NULL)
  597. {
  598. SetProcessWindowStation(hwinstaSave);
  599. }
  600. CloseWindowStation(hwinsta);
  601. }
  602. else
  603. {
  604. TABSRVERR(("Failed to open window station.\n"));
  605. }
  606. DWORD rcWait = WaitForSingleObject(ghmutNotifyList, INFINITE);
  607. if (rcWait == WAIT_OBJECT_0)
  608. {
  609. PLIST_ENTRY plist;
  610. PNOTIFYCLIENT NotifyClient;
  611. while (!IsListEmpty(&glistNotifyClients))
  612. {
  613. plist = RemoveHeadList(&glistNotifyClients);
  614. NotifyClient = CONTAINING_RECORD(plist, NOTIFYCLIENT, list);
  615. free(NotifyClient);
  616. }
  617. ReleaseMutex(ghmutNotifyList);
  618. }
  619. else
  620. {
  621. TABSRVERR(("Failed to wait for RawPtList Mutex (rcWait=%x,err=%d).\n",
  622. rcWait, GetLastError()));
  623. }
  624. CloseHandle(ghRefreshEvent);
  625. CloseHandle(ghHotkeyEvent);
  626. CloseHandle(gdevDigitizer.hStopDeviceEvent);
  627. CloseHandle(gdevButtons.hStopDeviceEvent);
  628. ghHotkeyEvent = NULL;
  629. gdevDigitizer.hStopDeviceEvent = NULL;
  630. gdevButtons.hStopDeviceEvent = NULL;
  631. CloseHandle(ghmutNotifyList);
  632. ghmutNotifyList = NULL;
  633. CloseHandle(ghDesktopSwitchEvent);
  634. ghDesktopSwitchEvent = NULL;
  635. DestroyCursor(ghcurNormal);
  636. ghcurNormal = NULL;
  637. DestroyCursor(ghcurPressHold);
  638. ghcurPressHold = NULL;
  639. gdwfTabSrv = 0;
  640. TRACEINFO(1, ("Out of here.\n"));
  641. TRACEEXIT(("!\n"));
  642. return;
  643. } //TabSrvMain
  644. /*++
  645. @doc INTERNAL
  646. @func VOID | InitConfigFromReg | Initialize configuration from registry.
  647. @parm None.
  648. @rvalue None.
  649. --*/
  650. VOID
  651. InitConfigFromReg(
  652. VOID
  653. )
  654. {
  655. TRACEPROC("InitConfigFromReg", 2)
  656. LONG rcCfg;
  657. LPTSTR lptstrPenTilt;
  658. PTSTHREAD MouseThread;
  659. TRACEENTER(("()\n"));
  660. rcCfg = ReadConfig(gtszGestureSettings,
  661. (LPBYTE)&gConfig.GestureSettings,
  662. sizeof(gConfig.GestureSettings));
  663. if ((rcCfg != ERROR_SUCCESS) ||
  664. (gConfig.GestureSettings.dwcbLen != sizeof(gConfig.GestureSettings)))
  665. {
  666. if (rcCfg == ERROR_SUCCESS)
  667. {
  668. TABSRVERR(("Incorrect size on GestureSettings, use default.\n"));
  669. }
  670. gConfig.GestureSettings = gDefGestureSettings;
  671. }
  672. MouseThread = FindThread(TSF_MOUSETHREAD);
  673. if (MouseThread != NULL)
  674. {
  675. if (gConfig.GestureSettings.dwfFeatures & GESTURE_FEATURE_MOUSE_ENABLED)
  676. {
  677. MouseThread->dwfThread |= THREADF_ENABLED;
  678. }
  679. else
  680. {
  681. MouseThread->dwfThread &= ~THREADF_ENABLED;
  682. }
  683. }
  684. lptstrPenTilt = (gdwfTabSrv & TSF_PORTRAIT_MODE)?
  685. TEXT("PenTilt_Portrait"): TEXT("PenTilt_Landscape"),
  686. rcCfg = ReadConfig(lptstrPenTilt,
  687. (LPBYTE)&gConfig.PenTilt,
  688. sizeof(gConfig.PenTilt));
  689. rcCfg = ReadConfig(gtszLinearityMap,
  690. (LPBYTE)&gConfig.LinearityMap,
  691. sizeof(gConfig.LinearityMap));
  692. if ((rcCfg == ERROR_SUCCESS) &&
  693. (gConfig.LinearityMap.dwcbLen == sizeof(gConfig.LinearityMap)))
  694. {
  695. gdwfTabSrv |= TSF_HAS_LINEAR_MAP;
  696. }
  697. rcCfg = ReadConfig(gtszButtonSettings,
  698. (LPBYTE)&gConfig.ButtonSettings,
  699. sizeof(gConfig.ButtonSettings));
  700. if ((rcCfg != ERROR_SUCCESS) ||
  701. (gConfig.ButtonSettings.dwcbLen != sizeof(gConfig.ButtonSettings)))
  702. {
  703. if (rcCfg == ERROR_SUCCESS)
  704. {
  705. TABSRVERR(("Incorrect size on ButtonSettings, use default.\n"));
  706. }
  707. gConfig.ButtonSettings = gDefButtonSettings;
  708. }
  709. BOOL fPortraitMode2 = FALSE;
  710. rcCfg = ReadConfig(gtszPortraitMode2,
  711. (LPBYTE)&fPortraitMode2,
  712. sizeof(fPortraitMode2));
  713. if ((rcCfg == ERROR_SUCCESS) && fPortraitMode2)
  714. {
  715. gdwfTabSrv |= TSF_PORTRAIT_MODE2;
  716. }
  717. TRACEEXIT(("!\n"));
  718. return;
  719. } //InitConfigFromReg
  720. /*++
  721. @doc INTERNAL
  722. @func BOOL | InitThreads | Initialize various threads.
  723. @parm PTSTHREAD | pThreads | Points to the thread array for the threads
  724. to start.
  725. @parm int | nThreads | Specifies the number of threads in the array.
  726. @rvalue SUCCESS | Returns TRUE.
  727. @rvalue FAILURE | Returns FALSE.
  728. --*/
  729. BOOL
  730. InitThreads(
  731. IN PTSTHREAD pThreads,
  732. IN int nThreads
  733. )
  734. {
  735. TRACEPROC("InitThreads", 2)
  736. BOOL rc = TRUE;
  737. int i;
  738. unsigned uThreadID;
  739. TRACEENTER(("(pThreads=%p,NumThreads=%d)\n", pThreads, nThreads));
  740. for (i = 0; i < nThreads; ++i)
  741. {
  742. if (pThreads[i].dwfThread & THREADF_ENABLED)
  743. {
  744. pThreads[i].hThread = (HANDLE)_beginthreadex(
  745. NULL,
  746. 0,
  747. pThreads[i].pfnThread,
  748. pThreads[i].pvParam?
  749. pThreads[i].pvParam:
  750. &pThreads[i],
  751. 0,
  752. &uThreadID);
  753. if (pThreads[i].hThread != NULL)
  754. {
  755. gdwfTabSrv |= pThreads[i].dwThreadTag;
  756. }
  757. else
  758. {
  759. TABSRVERR(("Failed to create %s thread, LastError=%d.\n",
  760. pThreads[i].pszThreadName, GetLastError()));
  761. rc = FALSE;
  762. break;
  763. }
  764. }
  765. }
  766. SetEvent(ghRefreshEvent);
  767. TRACEEXIT(("=%x\n", rc));
  768. return rc;
  769. } //InitThreads
  770. /*++
  771. @doc INTERNAL
  772. @func PTSTHREAD | FindThread | Find a thread in the thread table.
  773. @parm DWORD | dwThreadTag | Specifies the thread to look for.
  774. @rvalue SUCCESS | Returns pointer to the thread entry in table.
  775. @rvalue FAILURE | Returns NULL.
  776. --*/
  777. PTSTHREAD
  778. FindThread(
  779. IN DWORD dwThreadTag
  780. )
  781. {
  782. TRACEPROC("FindThread", 2)
  783. PTSTHREAD Thread = NULL;
  784. int i;
  785. TRACEENTER(("(ThreadTag=%x)\n", dwThreadTag));
  786. for (i = 0; i < NUM_THREADS; ++i)
  787. {
  788. if (gTabSrvThreads[i].dwThreadTag == dwThreadTag)
  789. {
  790. Thread = &gTabSrvThreads[i];
  791. break;
  792. }
  793. }
  794. TRACEEXIT(("=%p\n", Thread));
  795. return Thread;
  796. } //FindThread
  797. /*++
  798. @doc INTERNAL
  799. @func VOID | WaitForTermination | Wait for termination.
  800. @parm None.
  801. @rvalue None.
  802. --*/
  803. VOID
  804. WaitForTermination(
  805. VOID
  806. )
  807. {
  808. TRACEPROC("WaitForTermination", 2)
  809. HANDLE ahWait[NUM_THREADS + 3];
  810. DWORD rcWait;
  811. int i;
  812. TRACEENTER(("()\n"));
  813. ahWait[0] = ghDesktopSwitchEvent;
  814. ahWait[1] = ghHotkeyEvent;
  815. ahWait[2] = ghRefreshEvent;
  816. //
  817. // Wait for termination.
  818. //
  819. for (;;)
  820. {
  821. DWORD n = 3;
  822. for (i = 0; i < NUM_THREADS; ++i)
  823. {
  824. if (gTabSrvThreads[i].hThread != NULL)
  825. {
  826. ahWait[n] = gTabSrvThreads[i].hThread;
  827. gTabSrvThreads[i].iThreadStatus = WAIT_OBJECT_0 + n;
  828. n++;
  829. }
  830. else
  831. {
  832. gTabSrvThreads[i].iThreadStatus = -1;
  833. }
  834. }
  835. rcWait = WaitForMultipleObjects(n, ahWait, FALSE, INFINITE);
  836. if ((rcWait == WAIT_OBJECT_0) || (rcWait == WAIT_OBJECT_0 + 1))
  837. {
  838. TCHAR tszDesktop[32];
  839. BOOL fDoSwitch = TRUE;
  840. if (rcWait == WAIT_OBJECT_0 + 1)
  841. {
  842. //
  843. // Send hot key event and tell all threads to switch.
  844. //
  845. TRACEINFO(1, ("Send Hotkey.\n"));
  846. SendAltCtrlDel();
  847. if (GetInputDesktopName(tszDesktop, sizeof(tszDesktop)))
  848. {
  849. TRACEINFO(1, ("[CAD] New input desktop=%s\n", tszDesktop));
  850. lstrcpyn(gtszInputDesktop,
  851. tszDesktop,
  852. ARRAYSIZE(gtszInputDesktop));
  853. }
  854. }
  855. else if (GetInputDesktopName(tszDesktop, sizeof(tszDesktop)))
  856. {
  857. if (lstrcmpi(tszDesktop, gtszInputDesktop) == 0)
  858. {
  859. //
  860. // It seems that when the user logs off, two desktop
  861. // switches are signaled in quick succession. The
  862. // desktop is still 'Default' after the first switch
  863. // is signaled. So we don't really want to switch
  864. // all threads to the same desktop.
  865. //
  866. TRACEINFO(1, ("Same desktop, don't switch (Desktop=%s).\n",
  867. tszDesktop));
  868. fDoSwitch = FALSE;
  869. }
  870. else
  871. {
  872. TRACEINFO(1, ("New input desktop=%s\n", tszDesktop));
  873. lstrcpyn(gtszInputDesktop,
  874. tszDesktop,
  875. ARRAYSIZE(gtszInputDesktop));
  876. }
  877. }
  878. if (fDoSwitch)
  879. {
  880. //
  881. // We are swtiching, tell all threads that need to switch
  882. // desktop to switch.
  883. //
  884. TabSrvTerminate(FALSE);
  885. }
  886. }
  887. else if (rcWait != WAIT_OBJECT_0 + 2)
  888. {
  889. for (i = 0; i < NUM_THREADS; ++i)
  890. {
  891. if (rcWait == (DWORD)gTabSrvThreads[i].iThreadStatus)
  892. {
  893. CloseHandle(gTabSrvThreads[i].hThread);
  894. gTabSrvThreads[i].hThread = NULL;
  895. gdwfTabSrv &= ~gTabSrvThreads[i].dwThreadTag;
  896. TRACEINFO(1, ("%s thread is killed.\n",
  897. gTabSrvThreads[i].pszThreadName));
  898. //
  899. // If a thread died unexpectedly and it is marked
  900. // restartable, restart it.
  901. //
  902. if (!(gdwfTabSrv & TSF_TERMINATE) &&
  903. (gTabSrvThreads[i].dwfThread & THREADF_RESTARTABLE))
  904. {
  905. if (gTabSrvThreads[i].dwcRestartTries < MAX_RESTARTS)
  906. {
  907. TRACEINFO(1, ("%s thread died unexpectedly, restarting (count=%d)\n",
  908. gTabSrvThreads[i].pszThreadName,
  909. gTabSrvThreads[i].dwcRestartTries));
  910. InitThreads(&gTabSrvThreads[i], 1);
  911. gTabSrvThreads[i].dwcRestartTries++;
  912. }
  913. else
  914. {
  915. TABSRVERR(("%s thread exceeds restart maximum.\n",
  916. gTabSrvThreads[i].pszThreadName));
  917. }
  918. }
  919. break;
  920. }
  921. }
  922. if (i == NUM_THREADS)
  923. {
  924. TABSRVERR(("WaitForMultipleObjects failed (rcWait=%x,err=%d).\n",
  925. rcWait, GetLastError()));
  926. break;
  927. }
  928. }
  929. if (!(gdwfTabSrv & TSF_ALLTHREAD))
  930. {
  931. //
  932. // All threads are dead, we can quit now.
  933. //
  934. break;
  935. }
  936. }
  937. TRACEEXIT(("!\n"));
  938. return;
  939. } //WaitForTermination
  940. /*++
  941. @doc INTERNAL
  942. @func VOID | TabSrvTerminate | Do clean up.
  943. @parm IN BOOL | fTerminate | TRUE if real termination, otherwise
  944. switching desktop.
  945. @rvalue None.
  946. --*/
  947. VOID
  948. TabSrvTerminate(
  949. IN BOOL fTerminate
  950. )
  951. {
  952. TRACEPROC("TabSrvTerminate", 2)
  953. int i;
  954. TRACEENTER(("(fTerminate=%x)\n", fTerminate));
  955. if (fTerminate)
  956. {
  957. gdwfTabSrv |= TSF_TERMINATE;
  958. }
  959. for (i = 0; i < NUM_THREADS; ++i)
  960. {
  961. if (gTabSrvThreads[i].dwfThread &
  962. (THREADF_SDT_POSTMSG | THREADF_SDT_SETEVENT))
  963. {
  964. if (gdwfTabSrv & gTabSrvThreads[i].dwThreadTag)
  965. {
  966. TRACEINFO(1, (fTerminate? "Kill %s thread.\n":
  967. "Switch %s thread desktop.\n",
  968. gTabSrvThreads[i].pszThreadName));
  969. TRACEASSERT(gTabSrvThreads[i].pvSDTParam != NULL);
  970. if (gTabSrvThreads[i].dwfThread & THREADF_SDT_POSTMSG)
  971. {
  972. if (IsWindow((HWND)gTabSrvThreads[i].pvSDTParam))
  973. {
  974. PostMessage((HWND)gTabSrvThreads[i].pvSDTParam,
  975. WM_CLOSE,
  976. 0,
  977. 0);
  978. }
  979. else
  980. {
  981. TRACEINFO(1, ("%s thread window handle (%x) is not valid.\n",
  982. gTabSrvThreads[i].pszThreadName,
  983. gTabSrvThreads[i].pvSDTParam));
  984. }
  985. }
  986. else
  987. {
  988. SetEvent((HANDLE)gTabSrvThreads[i].pvSDTParam);
  989. }
  990. }
  991. else if (!fTerminate &&
  992. (gTabSrvThreads[i].dwcRestartTries >= MAX_RESTARTS))
  993. {
  994. TRACEINFO(1, ("Retrying to start %s thread.\n",
  995. gTabSrvThreads[i].pszThreadName));
  996. InitThreads(&gTabSrvThreads[i], 1);
  997. gTabSrvThreads[i].dwcRestartTries = 1;
  998. }
  999. }
  1000. }
  1001. if (fTerminate && (gdwfTabSrv & TSF_RPCTHREAD))
  1002. {
  1003. RpcMgmtStopServerListening(NULL);
  1004. }
  1005. TRACEEXIT(("!\n"));
  1006. return;
  1007. } //TabSrvTerminate
  1008. /*++
  1009. @doc INTERNAL
  1010. @func VOID | TabSrvLogError | Log the error in the event log.
  1011. @parm IN PSZ | pszFormat | Points to the format string.
  1012. @parm ... | String arguments.
  1013. @rvalue None.
  1014. --*/
  1015. VOID
  1016. TabSrvLogError(
  1017. IN PSZ pszFormat,
  1018. ...
  1019. )
  1020. {
  1021. TRACEPROC("TabSrvLogError", 5)
  1022. TRACEENTER(("(Format=%s,...)\n", pszFormat));
  1023. if (!(gdwfTabSrv & TSF_DEBUG_MODE))
  1024. {
  1025. HANDLE hEventLog;
  1026. hEventLog = RegisterEventSource(NULL, TEXT(STR_TABSRV_NAME));
  1027. if (hEventLog != NULL)
  1028. {
  1029. char szMsg[256];
  1030. LPCSTR psz = szMsg;
  1031. va_list arglist;
  1032. va_start(arglist, pszFormat);
  1033. wvsprintfA(szMsg, pszFormat, arglist);
  1034. va_end(arglist);
  1035. ReportEventA(hEventLog, //handle of event source
  1036. EVENTLOG_ERROR_TYPE, //event type
  1037. 0, //event category
  1038. 0, //event ID
  1039. NULL, //current user's SID
  1040. 1, //number of strings
  1041. 0, //size of raw data
  1042. &psz, //array of strings
  1043. NULL); //no raw data
  1044. DeregisterEventSource(hEventLog);
  1045. }
  1046. }
  1047. TRACEEXIT(("!\n"));
  1048. return;
  1049. } //TabSrvLogError
  1050. /*++
  1051. @doc INTERNAL
  1052. @func LONG | ReadConfig | Read TabSrv configuration from registry.
  1053. @parm IN LPCTSTR | lptstrValueName | Points to the registry value
  1054. name string.
  1055. @parm OUT LPBYTE | lpbData | Points to the buffer to hold the value
  1056. read.
  1057. @parm IN DWORD | dwcb | Specifies the size of the buffer.
  1058. @rvalue SUCCESS | Returns ERROR_SUCCESS.
  1059. @rvalue FAILURE | Returns registry error code.
  1060. --*/
  1061. LONG
  1062. ReadConfig(
  1063. IN LPCTSTR lptstrValueName,
  1064. OUT LPBYTE lpbData,
  1065. IN DWORD dwcb
  1066. )
  1067. {
  1068. TRACEPROC("ReadConfig", 3)
  1069. LONG rc;
  1070. HKEY hkey;
  1071. TRACEENTER(("(Name=%s,pData=%p,Len=%d)\n", lptstrValueName, lpbData, dwcb));
  1072. rc = RegCreateKey(HKEY_LOCAL_MACHINE,
  1073. gtszRegPath,
  1074. &hkey);
  1075. if (rc == ERROR_SUCCESS)
  1076. {
  1077. rc = RegQueryValueEx(hkey,
  1078. lptstrValueName,
  1079. NULL,
  1080. NULL,
  1081. lpbData,
  1082. &dwcb);
  1083. if (rc != ERROR_SUCCESS)
  1084. {
  1085. TRACEWARN(("Failed to read \"%s\" from registry (rc=%d).\n",
  1086. lptstrValueName, rc));
  1087. }
  1088. RegCloseKey(hkey);
  1089. }
  1090. else
  1091. {
  1092. TABSRVERR(("Failed to open registry key to read configuration (rc=%d).\n",
  1093. rc));
  1094. }
  1095. TRACEEXIT(("=%d\n", rc));
  1096. return rc;
  1097. } //ReadConfig
  1098. /*++
  1099. @doc INTERNAL
  1100. @func LONG | WriteConfig | Write TabSrv configuration to registry.
  1101. @parm IN LPCTSTR | lptstrValueName | Points to the registry value
  1102. name string.
  1103. @parm IN DWORD | dwType | Specifies the registry value type.
  1104. name string.
  1105. @parm IN LPBYTE | lpbData | Points to the buffer to hold the value
  1106. read.
  1107. @parm IN DWORD | dwcb | Specifies the size of the buffer.
  1108. @rvalue SUCCESS | Returns ERROR_SUCCESS.
  1109. @rvalue FAILURE | Returns registry error code.
  1110. --*/
  1111. LONG
  1112. WriteConfig(
  1113. IN LPCTSTR lptstrValueName,
  1114. IN DWORD dwType,
  1115. IN LPBYTE lpbData,
  1116. IN DWORD dwcb
  1117. )
  1118. {
  1119. TRACEPROC("WriteConfig", 3)
  1120. LONG rc;
  1121. HKEY hkey;
  1122. TRACEENTER(("(Name=%s,Type=%d,pData=%p,Len=%d)\n",
  1123. lptstrValueName, dwType, lpbData, dwcb));
  1124. rc = RegCreateKey(HKEY_LOCAL_MACHINE,
  1125. gtszRegPath,
  1126. &hkey);
  1127. if (rc == ERROR_SUCCESS)
  1128. {
  1129. rc = RegSetValueEx(hkey,
  1130. lptstrValueName,
  1131. 0,
  1132. dwType,
  1133. lpbData,
  1134. dwcb);
  1135. if (rc != ERROR_SUCCESS)
  1136. {
  1137. TRACEWARN(("Failed to write \"%s\" to registry (rc=%d).\n",
  1138. lptstrValueName, rc));
  1139. }
  1140. RegCloseKey(hkey);
  1141. }
  1142. else
  1143. {
  1144. TABSRVERR(("Failed to create registry key to write configuration (rc=%d).\n",
  1145. rc));
  1146. }
  1147. TRACEEXIT(("=%d\n", rc));
  1148. return rc;
  1149. } //WriteConfig
  1150. /*++
  1151. @doc INTERNAL
  1152. @func HRESULT | GetRegValueString | Get registry string value.
  1153. @parm IN HKEY | hkeyTopLevel | Top level registry key.
  1154. @parm IN LPCTSTR | pszSubKey | Subkey string.
  1155. @parm IN LPCTSTR | pszValueName | Value name string.
  1156. @parm OUT LPTSTR | pszValueString | To hold value string.
  1157. @parm IN OUT LPDWORD | lpdwcb | Specify size of ValueString and to hold
  1158. result string size.
  1159. @rvalue SUCCESS | Returns ERROR_SUCCESS.
  1160. @rvalue FAILURE | Returns registry error code.
  1161. --*/
  1162. LONG
  1163. GetRegValueString(
  1164. IN HKEY hkeyTopLevel,
  1165. IN LPCTSTR pszSubKey,
  1166. IN LPCTSTR pszValueName,
  1167. OUT LPTSTR pszValueString,
  1168. IN OUT LPDWORD lpdwcb
  1169. )
  1170. {
  1171. TRACEPROC("GetRegValueString", 3)
  1172. LONG rc;
  1173. HKEY hkey;
  1174. TRACEASSERT(lpdwcb != NULL);
  1175. TRACEASSERT((pszValueString != NULL) || (*lpdwcb == 0));
  1176. TRACEENTER(("(hkTop=%x,SubKey=%s,ValueName=%s,ValueString=%p,Len=%d)\n",
  1177. hkeyTopLevel, pszSubKey, pszValueName, pszValueString,
  1178. *lpdwcb));
  1179. if (pszValueString != NULL)
  1180. {
  1181. pszValueString[0] = TEXT('\0');
  1182. }
  1183. rc = RegOpenKeyEx(hkeyTopLevel, pszSubKey, 0, KEY_READ, &hkey);
  1184. if (rc == ERROR_SUCCESS)
  1185. {
  1186. DWORD dwType = 0;
  1187. rc = RegQueryValueEx(hkey,
  1188. pszValueName,
  1189. 0,
  1190. &dwType,
  1191. (LPBYTE)pszValueString,
  1192. lpdwcb);
  1193. if (rc == ERROR_SUCCESS)
  1194. {
  1195. if (dwType != REG_SZ)
  1196. {
  1197. TABSRVERR(("Invalid registry data type (type=%x).\n", dwType));
  1198. rc = ERROR_INVALID_DATATYPE;
  1199. }
  1200. }
  1201. else
  1202. {
  1203. TABSRVERR(("Failed to read registry value %s\\%s (rc=%x).\n",
  1204. pszSubKey, pszValueName, rc));
  1205. }
  1206. RegCloseKey(hkey);
  1207. }
  1208. else
  1209. {
  1210. TABSRVERR(("Failed to open registry key %s (rc=%x).\n",
  1211. pszSubKey, rc));
  1212. }
  1213. TRACEEXIT(("=%d\n", rc));
  1214. return rc;
  1215. } //GetRegValueString
  1216. /*++
  1217. @doc INTERNAL
  1218. @func BOOL | SwitchThreadToInputDesktop | Switch thread to current
  1219. input desktop.
  1220. @parm IN PTSTHREAD | pThread | Points to the thread structure.
  1221. @rvalue SUCCESS | Returns TRUE.
  1222. @rvalue FAILURE | Returns FALSE.
  1223. --*/
  1224. BOOL
  1225. SwitchThreadToInputDesktop(
  1226. IN PTSTHREAD pThread
  1227. )
  1228. {
  1229. TRACEPROC("SwitchThreadToInputDesktop", 2)
  1230. BOOL rc = TRUE;
  1231. HDESK hdesk;
  1232. TRACEENTER(("(pThread=%p)\n", pThread));
  1233. hdesk = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED);
  1234. if (hdesk == NULL)
  1235. {
  1236. TRACEWARN(("Failed to open input desktop (err=%d), try Winlogon ...\n",
  1237. GetLastError()));
  1238. hdesk = OpenDesktop(TEXT("Winlogon"), 0, FALSE, MAXIMUM_ALLOWED);
  1239. if (hdesk == NULL)
  1240. {
  1241. TABSRVERR(("Failed to open winlogon desktop (err=%d).\n",
  1242. GetLastError()));
  1243. rc = FALSE;
  1244. }
  1245. }
  1246. if (rc == TRUE)
  1247. {
  1248. CloseDesktop(GetThreadDesktop(GetCurrentThreadId()));
  1249. rc = SetThreadDesktop(hdesk);
  1250. if (rc)
  1251. {
  1252. TCHAR tszDesktop[32];
  1253. DWORD dwcb;
  1254. if (GetUserObjectInformation(hdesk,
  1255. UOI_NAME,
  1256. tszDesktop,
  1257. sizeof(tszDesktop),
  1258. &dwcb))
  1259. {
  1260. TRACEINFO(1, ("Switch to Input desktop %s.\n", tszDesktop));
  1261. if (lstrcmpi(tszDesktop, TEXT("Winlogon")) == 0)
  1262. {
  1263. pThread->dwfThread |= THREADF_DESKTOP_WINLOGON;
  1264. }
  1265. else
  1266. {
  1267. pThread->dwfThread &= ~THREADF_DESKTOP_WINLOGON;
  1268. }
  1269. if (lstrcmpi(tszDesktop, gtszInputDesktop) != 0)
  1270. {
  1271. TRACEINFO(1, ("Input desktop name out of sync (old=%s, new=%s).\n",
  1272. gtszInputDesktop, tszDesktop));
  1273. lstrcpyn(gtszInputDesktop,
  1274. tszDesktop,
  1275. ARRAYSIZE(gtszInputDesktop));
  1276. }
  1277. }
  1278. }
  1279. else
  1280. {
  1281. TABSRVERR(("Failed to set thread desktop (err=%d)\n",
  1282. GetLastError()));
  1283. }
  1284. }
  1285. else
  1286. {
  1287. TABSRVERR(("Failed to open input desktop (err=%d)\n", GetLastError()));
  1288. }
  1289. TRACEEXIT(("=%x\n", rc));
  1290. return rc;
  1291. } //SwitchThreadToInputDesktop
  1292. /*++
  1293. @doc INTERNAL
  1294. @func BOOL | GetInputDesktopName | Get current input desktop name.
  1295. @parm OUT LPTSTR | pszDesktopName | Point to a buffer to hold the desktop
  1296. name.
  1297. @parm IN DWORD | dwcbLen | Specifies length of buffer.
  1298. @rvalue SUCCESS | Returns TRUE.
  1299. @rvalue FAILURE | Returns FALSE.
  1300. --*/
  1301. BOOL
  1302. GetInputDesktopName(
  1303. OUT LPTSTR pszDesktopName,
  1304. IN DWORD dwcbLen
  1305. )
  1306. {
  1307. TRACEPROC("GetInputDesktopName", 2)
  1308. BOOL rc = FALSE;
  1309. HDESK hdesk;
  1310. TRACEENTER(("(pszDesktopName=%p,Len=%d)\n", pszDesktopName, dwcbLen));
  1311. hdesk = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED);
  1312. if (hdesk == NULL)
  1313. {
  1314. TRACEWARN(("Failed to open input desktop (err=%d), try Winlogon ...\n",
  1315. GetLastError()));
  1316. hdesk = OpenDesktop(TEXT("Winlogon"), 0, FALSE, MAXIMUM_ALLOWED);
  1317. if (hdesk == NULL)
  1318. {
  1319. TABSRVERR(("Failed to open winlogon desktop (err=%d).\n",
  1320. GetLastError()));
  1321. }
  1322. }
  1323. if (hdesk != NULL)
  1324. {
  1325. if (GetUserObjectInformation(hdesk,
  1326. UOI_NAME,
  1327. pszDesktopName,
  1328. dwcbLen,
  1329. &dwcbLen))
  1330. {
  1331. rc = TRUE;
  1332. }
  1333. else
  1334. {
  1335. TRACEWARN(("Failed to get desktop name (err=%d).\n",
  1336. GetLastError()));
  1337. }
  1338. CloseDesktop(hdesk);
  1339. }
  1340. else
  1341. {
  1342. TRACEWARN(("failed to open input desktop (err=%d)\n", GetLastError()));
  1343. }
  1344. TRACEEXIT(("=%x (DeskTopName=%s)\n", rc, pszDesktopName));
  1345. return rc;
  1346. } //GetInputDesktopName
  1347. /*++
  1348. @doc INTERNAL
  1349. @func VOID | SendAltCtrlDel | Send Alt+Ctrl+Del
  1350. @parm None.
  1351. @rvalue SUCCESS | Returns TRUE.
  1352. @rvalue FAILURE | Returns FALSE.
  1353. --*/
  1354. BOOL
  1355. SendAltCtrlDel(
  1356. VOID
  1357. )
  1358. {
  1359. TRACEPROC("SendAltCtrlDel", 2)
  1360. BOOL rc = FALSE;
  1361. HWINSTA hwinstaSave;
  1362. HDESK hdeskSave;
  1363. TRACEENTER(("()\n"));
  1364. hwinstaSave = GetProcessWindowStation();
  1365. hdeskSave = GetThreadDesktop(GetCurrentThreadId());
  1366. if ((hwinstaSave != NULL) && (hdeskSave != NULL))
  1367. {
  1368. HWINSTA hwinsta;
  1369. HDESK hdesk;
  1370. hwinsta = OpenWindowStation(TEXT("WinSta0"), FALSE, MAXIMUM_ALLOWED);
  1371. if (hwinsta != NULL)
  1372. {
  1373. SetProcessWindowStation(hwinsta);
  1374. hdesk = OpenDesktop(TEXT("Winlogon"), 0, FALSE, MAXIMUM_ALLOWED);
  1375. if (hdesk != NULL)
  1376. {
  1377. HWND hwndSAS;
  1378. SetThreadDesktop(hdesk);
  1379. hwndSAS = FindWindow(NULL, TEXT("SAS window"));
  1380. if (hwndSAS != NULL)
  1381. {
  1382. SendMessage(hwndSAS, WM_HOTKEY, 0, 0);
  1383. rc = TRUE;
  1384. }
  1385. else
  1386. {
  1387. TABSRVERR(("Failed to find SAS window (err=%d).\n",
  1388. GetLastError()));
  1389. }
  1390. SetThreadDesktop(hdeskSave);
  1391. CloseDesktop(hdesk);
  1392. }
  1393. else
  1394. {
  1395. TABSRVERR(("Failed to open Winlogon (err=%d).\n",
  1396. GetLastError()));
  1397. }
  1398. SetProcessWindowStation(hwinsta);
  1399. CloseWindowStation(hwinsta);
  1400. }
  1401. else
  1402. {
  1403. TABSRVERR(("Failed to open WinSta0 (err=%d).\n", GetLastError()));
  1404. }
  1405. }
  1406. else
  1407. {
  1408. TABSRVERR(("GetProcessWindowStation or GetThreadDesktop failed (err=%d,hwinsta=%x,hdesk=%x).\n",
  1409. GetLastError(), hwinstaSave, hdeskSave));
  1410. }
  1411. TRACEEXIT(("=%x\n", rc));
  1412. return rc;
  1413. } //SendAltCtrlDel
  1414. /*++
  1415. @doc INTERNAL
  1416. @func VOID | NotifyClient | Check if we need to notify anybody.
  1417. @parm IN EVTNOTIFY | Event | Event to broadcast.
  1418. @parm IN WPARAM | wParam | wParam to send in the message.
  1419. @parm IN LPARAM | lParam | lParam to send in the message.
  1420. @rvalue None.
  1421. --*/
  1422. VOID
  1423. NotifyClient(
  1424. IN EVTNOTIFY Event,
  1425. IN WPARAM wParam,
  1426. IN LPARAM lParam
  1427. )
  1428. {
  1429. TRACEPROC("NotifyClient", 5)
  1430. TRACEENTER(("(Event=%x,wParam=%x,lParam=%x)\n", Event, wParam, lParam));
  1431. if (!IsListEmpty(&glistNotifyClients))
  1432. {
  1433. DWORD rcWait;
  1434. PLIST_ENTRY plist;
  1435. PNOTIFYCLIENT Client;
  1436. rcWait = WaitForSingleObject(ghmutNotifyList, INFINITE);
  1437. if (rcWait == WAIT_OBJECT_0)
  1438. {
  1439. for (plist = glistNotifyClients.Flink;
  1440. plist != &glistNotifyClients; plist = plist->Flink)
  1441. {
  1442. Client = CONTAINING_RECORD(plist,
  1443. NOTIFYCLIENT,
  1444. list);
  1445. if (Client->Event == Event)
  1446. {
  1447. PostMessage(Client->hwnd,
  1448. Client->uiMsg,
  1449. wParam,
  1450. lParam);
  1451. }
  1452. }
  1453. ReleaseMutex(ghmutNotifyList);
  1454. }
  1455. else
  1456. {
  1457. TABSRVERR(("failed to wait for Notify list mutex (rcWait=%x,err=%d).\n",
  1458. rcWait, GetLastError()));
  1459. }
  1460. }
  1461. TRACEEXIT(("!\n"));
  1462. return;
  1463. } //NotifyClient
  1464. /*++
  1465. @doc INTERNAL
  1466. @func BOOL | ImpersonateCurrentUser | Impersonate current logged on user.
  1467. @parm None.
  1468. @rvalue SUCCESS | Returns TRUE.
  1469. @rvalue FAILURE | Returns FALSE.
  1470. --*/
  1471. BOOL
  1472. ImpersonateCurrentUser(
  1473. VOID
  1474. )
  1475. {
  1476. TRACEPROC("ImpersonateCurrentUser", 3)
  1477. BOOL rc = FALSE;
  1478. HANDLE hToken;
  1479. TRACEENTER(("()\n"));
  1480. hToken = GetCurrentUserTokenW(L"WinSta0", TOKEN_ALL_ACCESS);
  1481. if (hToken != NULL)
  1482. {
  1483. rc = ImpersonateLoggedOnUser(hToken);
  1484. if (rc == FALSE)
  1485. {
  1486. TABSRVERR(("Failed to impersonate logged on user (err=%d).\n",
  1487. GetLastError()));
  1488. }
  1489. CloseHandle(hToken);
  1490. }
  1491. else
  1492. {
  1493. DWORD dwError = GetLastError();
  1494. if (dwError != ERROR_NOT_LOGGED_ON)
  1495. {
  1496. TABSRVERR(("Failed to get current user token (err=%d)\n",
  1497. dwError));
  1498. }
  1499. }
  1500. TRACEEXIT(("=%x\n", rc));
  1501. return rc;
  1502. } //ImpersonateCurrentUser
  1503. /*++
  1504. @doc INTERNAL
  1505. @func BOOL | RunProcessAsUser | Run a process as the logged on user.
  1506. @parm IN LPTSTR | pszCmd | Process command.
  1507. @rvalue SUCCESS | Returns TRUE.
  1508. @rvalue FAILURE | Returns FALSE.
  1509. --*/
  1510. BOOL
  1511. RunProcessAsUser(
  1512. IN LPTSTR pszCmd
  1513. )
  1514. {
  1515. TRACEPROC("RunProcessAsUser", 3)
  1516. BOOL rc = FALSE;
  1517. HANDLE hImpersonateToken;
  1518. HANDLE hPrimaryToken;
  1519. TRACEENTER(("(Cmd=%s)\n", pszCmd));
  1520. if (OpenThreadToken(GetCurrentThread(),
  1521. TOKEN_QUERY |
  1522. TOKEN_DUPLICATE |
  1523. TOKEN_ASSIGN_PRIMARY,
  1524. TRUE,
  1525. &hImpersonateToken))
  1526. {
  1527. if (DuplicateTokenEx(hImpersonateToken,
  1528. TOKEN_IMPERSONATE |
  1529. TOKEN_READ |
  1530. TOKEN_ASSIGN_PRIMARY |
  1531. TOKEN_DUPLICATE |
  1532. TOKEN_ADJUST_PRIVILEGES,
  1533. NULL,
  1534. SecurityImpersonation,
  1535. TokenPrimary,
  1536. &hPrimaryToken))
  1537. {
  1538. STARTUPINFO si;
  1539. PROCESS_INFORMATION pi;
  1540. LPVOID lpEnv = NULL;
  1541. if (!CreateEnvironmentBlock(&lpEnv, hImpersonateToken, TRUE))
  1542. {
  1543. TABSRVERR(("Failed to create environment block (err=%d).\n",
  1544. GetLastError()));
  1545. lpEnv = NULL;
  1546. }
  1547. memset(&si, 0, sizeof(si));
  1548. si.cb = sizeof(si);
  1549. si.lpDesktop = TEXT("WinSta0\\Default");
  1550. if (CreateProcessAsUser(hPrimaryToken,
  1551. NULL,
  1552. pszCmd,
  1553. NULL,
  1554. NULL,
  1555. FALSE,
  1556. NORMAL_PRIORITY_CLASS |
  1557. CREATE_UNICODE_ENVIRONMENT,
  1558. lpEnv,
  1559. NULL,
  1560. &si,
  1561. &pi))
  1562. {
  1563. CloseHandle(pi.hProcess);
  1564. CloseHandle(pi.hThread);
  1565. rc = TRUE;
  1566. }
  1567. else
  1568. {
  1569. TABSRVERR(("Failed to create process as user (err=%d).\n",
  1570. GetLastError()));
  1571. }
  1572. if (lpEnv != NULL)
  1573. {
  1574. DestroyEnvironmentBlock(lpEnv);
  1575. }
  1576. CloseHandle(hPrimaryToken);
  1577. }
  1578. else
  1579. {
  1580. TABSRVERR(("Failed to duplicate token (err=%d).\n",
  1581. GetLastError()));
  1582. }
  1583. CloseHandle(hImpersonateToken);
  1584. }
  1585. else
  1586. {
  1587. TABSRVERR(("Failed to open thread token (err=%d).\n",
  1588. GetLastError()));
  1589. }
  1590. TRACEEXIT(("=%x\n", rc));
  1591. return rc;
  1592. } //RunProcessAsUser
  1593. /*++
  1594. @doc EXTERNAL
  1595. @func void __RPC_FAR * | MIDL_user_allocate | MIDL allocate.
  1596. @parm IN size_t | len | size of allocation.
  1597. @rvalue SUCCESS | Returns the pointer to the memory allocated.
  1598. @rvalue FAILURE | Returns NULL.
  1599. --*/
  1600. void __RPC_FAR * __RPC_USER
  1601. MIDL_user_allocate(
  1602. IN size_t len
  1603. )
  1604. {
  1605. TRACEPROC("MIDL_user_allocate", 5)
  1606. void __RPC_FAR *ptr;
  1607. TRACEENTER(("(len=%d)\n", len));
  1608. ptr = malloc(len);
  1609. TRACEEXIT(("=%p\n", ptr));
  1610. return ptr;
  1611. } //MIDL_user_allocate
  1612. /*++
  1613. @doc EXTERNAL
  1614. @func void | MIDL_user_free | MIDL free.
  1615. @parm IN void __PRC_FAR * | ptr | Points to the memory to be freed.
  1616. @rvalue None.
  1617. --*/
  1618. void __RPC_USER
  1619. MIDL_user_free(
  1620. IN void __RPC_FAR *ptr
  1621. )
  1622. {
  1623. TRACEPROC("MIDL_user_free", 5)
  1624. TRACEENTER(("(ptr=%p)\n", ptr));
  1625. free(ptr);
  1626. TRACEEXIT(("!\n"));
  1627. return;
  1628. } //MIDL_user_free