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.

742 lines
15 KiB

  1. #include "precomp.h"
  2. #include <RegEntry.h>
  3. #include <asmaster.h>
  4. #define MLZ_FILE_ZONE ZONE_CORE
  5. ASMaster *g_pMaster = NULL;
  6. HRESULT WINAPI CreateASObject
  7. (
  8. IAppSharingNotify * pNotify,
  9. UINT flags,
  10. IAppSharing** ppAS
  11. )
  12. {
  13. HRESULT hr = E_OUTOFMEMORY;
  14. ASMaster * pMaster = NULL;
  15. DebugEntry(CreateASObject);
  16. ASSERT(ppAS);
  17. if (g_pMaster != NULL)
  18. {
  19. ERROR_OUT(("CreateASObject: IAppSharing * alreadycreated; only one allowed at a time"));
  20. hr = E_UNEXPECTED;
  21. DC_QUIT;
  22. }
  23. ASSERT(!g_asMainThreadId);
  24. ASSERT(!g_putAS);
  25. pMaster = new ASMaster(flags, pNotify);
  26. if (pMaster != NULL)
  27. {
  28. //
  29. // Register as the groupware primary, with an event proc but no exit proc
  30. //
  31. if (!UT_InitTask(UTTASK_UI, &g_putUI))
  32. {
  33. ERROR_OUT(("Failed to register UI task"));
  34. DC_QUIT;
  35. }
  36. UT_RegisterEvent(g_putUI, eventProc, g_putUI, UT_PRIORITY_NORMAL);
  37. // Start groupware thread.
  38. if (!DCS_StartThread(WorkThreadEntryPoint))
  39. {
  40. ERROR_OUT(("Couldn't start groupware thread"));
  41. DC_QUIT;
  42. }
  43. // Make sure the work thread initialization is ok
  44. if (! g_asMainThreadId)
  45. {
  46. ERROR_OUT(("Init failed in the work thread"));
  47. DC_QUIT;
  48. }
  49. //
  50. // Success!
  51. //
  52. }
  53. hr = S_OK;
  54. DC_EXIT_POINT:
  55. if (!SUCCEEDED(hr))
  56. {
  57. if (pMaster)
  58. {
  59. ERROR_OUT(("CreateASObject: Init of ASMaster failed"));
  60. pMaster->Release();
  61. pMaster = NULL;
  62. }
  63. }
  64. *ppAS = pMaster;
  65. DebugExitHRESULT(CreateASObject, hr);
  66. return hr;
  67. }
  68. ASMaster::ASMaster(UINT flags, IAppSharingNotify * pNotify) :
  69. m_cRefs (1),
  70. m_pNotify (pNotify)
  71. {
  72. DebugEntry(ASMaster::ASMaster);
  73. if (m_pNotify)
  74. {
  75. m_pNotify->AddRef();
  76. }
  77. ASSERT(!g_pMaster);
  78. g_pMaster = this;
  79. //
  80. // Set up global flags:
  81. // * service
  82. // * unattended
  83. //
  84. g_asOptions = flags;
  85. DebugExitVOID(ASMaster::ASMaster);
  86. }
  87. ASMaster::~ASMaster()
  88. {
  89. DebugEntry(ASMaster::~ASMaster);
  90. //
  91. // Kill any share that's current or pending in the queue
  92. // This will do nothing if no share is extant at the time the
  93. // message is received.
  94. //
  95. if (g_asMainWindow)
  96. {
  97. PostMessage(g_asMainWindow, DCS_KILLSHARE_MSG, 0, 0);
  98. }
  99. //
  100. // Kill off the worker thread
  101. //
  102. if (g_asMainThreadId)
  103. {
  104. PostThreadMessage(g_asMainThreadId, WM_QUIT, 0, 0);
  105. }
  106. //
  107. // Clean up the UI
  108. //
  109. if (g_putUI)
  110. {
  111. UT_TermTask(&g_putUI);
  112. }
  113. // global variables cleanup
  114. if (m_pNotify)
  115. {
  116. m_pNotify->Release();
  117. m_pNotify = NULL;
  118. }
  119. if (g_pMaster == this)
  120. {
  121. g_pMaster = NULL;
  122. }
  123. DebugExitVOID(ASMaster::~ASMaster);
  124. }
  125. STDMETHODIMP ASMaster::QueryInterface(REFIID iid, void ** pv)
  126. {
  127. return E_NOINTERFACE;
  128. }
  129. STDMETHODIMP_(ULONG) ASMaster::AddRef()
  130. {
  131. InterlockedIncrement(&m_cRefs);
  132. return m_cRefs;
  133. }
  134. STDMETHODIMP_(ULONG) ASMaster::Release()
  135. {
  136. ASSERT(m_cRefs > 0);
  137. if (::InterlockedDecrement(&m_cRefs) == 0)
  138. {
  139. delete this;
  140. return 0;
  141. }
  142. return m_cRefs;
  143. }
  144. //
  145. // WorkThreadEntryPoint()
  146. //
  147. // This is the groupware code--obman, taskloader, and app sharing
  148. //
  149. DWORD WINAPI WorkThreadEntryPoint(LPVOID hEventWait)
  150. {
  151. BOOL result = FALSE;
  152. BOOL fCMGCleanup = FALSE;
  153. BOOL fDCSCleanup = FALSE;
  154. MSG msg;
  155. HWND hwndTop;
  156. DebugEntry(WorkThreadEntryPoint);
  157. //
  158. // Get the current thread ID. This is used in the stop code to know
  159. // if the previous thread is still exiting. In the run-when-windows
  160. // starts mode, our init code is called when Conf brings up UI and our
  161. // term code is called when Conf brings it down. We have a race condition
  162. // because this thread is created on each init. If we create a new
  163. // one while the old one is exiting, we will stomp over each other and
  164. // GP-fault.
  165. //
  166. g_asMainThreadId = GetCurrentThreadId();
  167. //
  168. // Get our policies
  169. //
  170. // Register the call primary code, for T.120 GCC
  171. if (!CMP_Init(&fCMGCleanup))
  172. {
  173. ERROR_OUT(("CMP_Init failed"));
  174. DC_QUIT;
  175. }
  176. //
  177. // Do DCS fast init; slow font enum will happen later off a posted
  178. // message. We can still share & participate in sharing without a
  179. // full font list...
  180. //
  181. fDCSCleanup = TRUE;
  182. if (!DCS_Init())
  183. {
  184. ERROR_OUT(("AS did not initialize"));
  185. DC_QUIT;
  186. }
  187. //
  188. // We've successfully initialised - let the thread which created this
  189. // one continue
  190. //
  191. SetEvent((HANDLE)hEventWait);
  192. //
  193. // Enter the main message processing loop:
  194. //
  195. while (GetMessage(&msg, NULL, 0, 0))
  196. {
  197. //
  198. // For dialogs, it's OK to do normal message processing.
  199. //
  200. if (hwndTop = IsForDialog(msg.hwnd))
  201. {
  202. if (!IsDialogMessage(hwndTop, &msg))
  203. {
  204. TranslateMessage(&msg);
  205. DispatchMessage(&msg);
  206. }
  207. }
  208. else
  209. {
  210. //
  211. // Note that this message dispatch loop DOES NOT include a call to
  212. // Translate Message. This is because we do not want it to call
  213. // ToAscii and affect the state maintained internally by ToAscii.
  214. // We will call ToAscii ourselves in the IM when the user is typing
  215. // in a view and calling it more than once for a keystroke
  216. // will cause it to return wrong results (eg for dead keys).
  217. //
  218. // The consequence of this is that any windows which are driven by
  219. // this dispatch loop will NOT receive WM_CHAR or WM_SYSCHAR
  220. // messages. This is not a problem for dialog windows belonging to
  221. // a task using this message loop as the dialog will run its own
  222. // dispatch loop.
  223. //
  224. // If it becomes necessary for windows driven by this dispatch loop
  225. // to get their messages translated then we could add logic to
  226. // determine whether the message is destined for a view
  227. // before deciding whether to translate it.
  228. //
  229. //
  230. // Because we don't have a translate message in our message loop we
  231. // need to do the following to ensure the keyboard LEDs follow what
  232. // the user does when their input is going to this message loop.
  233. //
  234. if (((msg.message == WM_KEYDOWN) ||
  235. (msg.message == WM_SYSKEYDOWN) ||
  236. (msg.message == WM_KEYUP) ||
  237. (msg.message == WM_SYSKEYUP)) &&
  238. IM_KEY_IS_TOGGLE(msg.wParam))
  239. {
  240. BYTE kbState[256];
  241. //
  242. // There is a chance the LEDs state has changed so..
  243. //
  244. GetKeyboardState(kbState);
  245. SetKeyboardState(kbState);
  246. }
  247. DispatchMessage(&msg);
  248. }
  249. }
  250. result = (int)msg.wParam;
  251. //
  252. // We emerge from the processing loop when someone posts us a WM_QUIT.
  253. // We do ObMan specific termination then call UT_TermTask (which will
  254. // call any exit procedures we have registered).
  255. //
  256. DC_EXIT_POINT:
  257. if (fDCSCleanup)
  258. DCS_Term();
  259. if (fCMGCleanup)
  260. CMP_Term();
  261. g_asMainThreadId = 0;
  262. DebugExitDWORD(WorkThreadEntryPoint, result);
  263. return(result);
  264. }
  265. //
  266. // IsForDialog()
  267. // Returns if the message is intended for a window in a dialog. AppSharing
  268. // has the host UI dialog, incoming request dialogs, and possibly
  269. // notification message box dialogs.
  270. //
  271. HWND IsForDialog(HWND hwnd)
  272. {
  273. BOOL rc = FALSE;
  274. HWND hwndParent;
  275. DebugEntry(IsForDialog);
  276. if (!hwnd)
  277. DC_QUIT;
  278. while (GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD)
  279. {
  280. hwndParent = GetParent(hwnd);
  281. if (hwndParent == GetDesktopWindow())
  282. break;
  283. hwnd = hwndParent;
  284. }
  285. if (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_DLGMODALFRAME)
  286. {
  287. // This is a dialog
  288. }
  289. else
  290. {
  291. hwnd = NULL;
  292. }
  293. DC_EXIT_POINT:
  294. DebugExitPTR(IsForDialog, hwnd);
  295. return(hwnd);
  296. }
  297. //
  298. // ASMaster member functions
  299. //
  300. //
  301. //
  302. //
  303. // ASMaster::OnEvent
  304. //
  305. // Parameters: event event type
  306. // param1 other parameter
  307. // param2 other parameter
  308. //
  309. //
  310. BOOL CALLBACK eventProc
  311. (
  312. LPVOID cpiHandle_,
  313. UINT event,
  314. UINT_PTR param1,
  315. UINT_PTR param2
  316. )
  317. {
  318. BOOL rc;
  319. if (g_pMaster)
  320. {
  321. rc = g_pMaster->OnEvent(event, param1, param2);
  322. }
  323. else
  324. {
  325. WARNING_OUT(("Received ASMaster event %d but no g_pMaster", event));
  326. rc = FALSE;
  327. }
  328. return rc;
  329. }
  330. BOOL ASMaster::OnEvent
  331. (
  332. UINT event,
  333. UINT_PTR param1,
  334. UINT_PTR param2
  335. )
  336. {
  337. BOOL rc = TRUE;
  338. DebugEntry(ASMaster::OnEvent);
  339. if (!m_pNotify)
  340. {
  341. // Nothing to do
  342. rc = FALSE;
  343. DC_QUIT;
  344. }
  345. switch (event)
  346. {
  347. case SH_EVT_APPSHARE_READY:
  348. m_pNotify->OnReadyToShare(param1 != 0);
  349. break;
  350. case SH_EVT_SHARE_STARTED:
  351. m_pNotify->OnShareStarted();
  352. break;
  353. case SH_EVT_SHARING_STARTED:
  354. m_pNotify->OnSharingStarted();
  355. break;
  356. case SH_EVT_SHARE_ENDED:
  357. m_pNotify->OnShareEnded();
  358. break;
  359. case SH_EVT_PERSON_JOINED:
  360. m_pNotify->OnPersonJoined((IAS_GCC_ID)param1);
  361. break;
  362. case SH_EVT_PERSON_LEFT:
  363. m_pNotify->OnPersonLeft((IAS_GCC_ID)param1);
  364. break;
  365. case SH_EVT_STARTINCONTROL:
  366. m_pNotify->OnStartInControl((IAS_GCC_ID)param1);
  367. break;
  368. case SH_EVT_STOPINCONTROL:
  369. m_pNotify->OnStopInControl((IAS_GCC_ID)param1);
  370. break;
  371. case SH_EVT_CONTROLLABLE:
  372. m_pNotify->OnControllable(param1 != 0);
  373. break;
  374. case SH_EVT_STARTCONTROLLED:
  375. m_pNotify->OnStartControlled((IAS_GCC_ID)param1);
  376. break;
  377. case SH_EVT_STOPCONTROLLED:
  378. m_pNotify->OnStopControlled((IAS_GCC_ID)param1);
  379. break;
  380. default:
  381. // Unrecognized, unhandled event
  382. rc = FALSE;
  383. break;
  384. }
  385. DC_EXIT_POINT:
  386. DebugExitBOOL(ASMaster::OnEvent, rc);
  387. return(rc);
  388. }
  389. //
  390. // ASMaster::IsSharingAvailable()
  391. //
  392. STDMETHODIMP_(BOOL) ASMaster::IsSharingAvailable()
  393. {
  394. return(g_asCanHost);
  395. }
  396. //
  397. // ASMaster::CanShareNow()
  398. //
  399. STDMETHODIMP_(BOOL) ASMaster::CanShareNow()
  400. {
  401. BOOL rc = FALSE;
  402. UT_Lock(UTLOCK_AS);
  403. //
  404. // We can share if
  405. // * We can capture graphic output on this OS
  406. // * We're in a call
  407. //
  408. if (g_asCanHost &&
  409. g_asSession.callID &&
  410. (g_s20State >= S20_NO_SHARE))
  411. {
  412. rc = TRUE;
  413. }
  414. UT_Unlock(UTLOCK_AS);
  415. return(rc);
  416. }
  417. //
  418. // ASMaster::InInShare()
  419. //
  420. STDMETHODIMP_(BOOL) ASMaster::IsInShare()
  421. {
  422. return(g_asSession.pShare != NULL);
  423. }
  424. //
  425. // ASMaster::IsSharing()
  426. //
  427. STDMETHODIMP_(BOOL) ASMaster::IsSharing()
  428. {
  429. IAS_PERSON_STATUS personStatus;
  430. ::ZeroMemory(&personStatus, sizeof(personStatus));
  431. personStatus.cbSize = sizeof(personStatus);
  432. GetPersonStatus(0, &personStatus);
  433. return(personStatus.AreSharing != 0);
  434. }
  435. //
  436. // CanAllowControl()
  437. // We can allow control if we're sharing and it's not prevented by policy
  438. //
  439. STDMETHODIMP_(BOOL) ASMaster::CanAllowControl(void)
  440. {
  441. return(IsSharing());
  442. }
  443. //
  444. // IsControllable()
  445. // We are controllable if our state isn't detached.
  446. //
  447. STDMETHODIMP_(BOOL) ASMaster::IsControllable(void)
  448. {
  449. IAS_PERSON_STATUS personStatus;
  450. ::ZeroMemory(&personStatus, sizeof(personStatus));
  451. personStatus.cbSize = sizeof(personStatus);
  452. GetPersonStatus(0, &personStatus);
  453. return(personStatus.Controllable != 0);
  454. }
  455. //
  456. // GetPersonStatus()
  457. //
  458. STDMETHODIMP ASMaster::GetPersonStatus(IAS_GCC_ID Person, IAS_PERSON_STATUS * pStatus)
  459. {
  460. return(::SHP_GetPersonStatus(Person, pStatus));
  461. }
  462. //
  463. //
  464. // ASMaster::ShareDesktop
  465. //
  466. //
  467. STDMETHODIMP ASMaster::ShareDesktop(void)
  468. {
  469. HRESULT hr;
  470. DebugEntry(ASMaster::ShareDesktop);
  471. hr = E_FAIL;
  472. if (!CanShareNow())
  473. {
  474. WARNING_OUT(("Share failing; can't share now"));
  475. DC_QUIT;
  476. }
  477. if (SHP_ShareDesktop())
  478. {
  479. hr = S_OK;
  480. }
  481. DC_EXIT_POINT:
  482. DebugExitHRESULT(ASMaster::ShareDesktop, hr);
  483. return hr;
  484. }
  485. //
  486. //
  487. // ASMaster::UnshareDesktop
  488. //
  489. // Parameters: HWND of the window to unshare
  490. //
  491. //
  492. STDMETHODIMP ASMaster::UnshareDesktop(void)
  493. {
  494. return(::SHP_UnshareDesktop());
  495. }
  496. //
  497. // TakeControl()
  498. //
  499. // From viewer to host, asking to take control of host.
  500. //
  501. STDMETHODIMP ASMaster::TakeControl(IAS_GCC_ID PersonOf)
  502. {
  503. return(SHP_TakeControl(PersonOf));
  504. }
  505. //
  506. // CancelTakeControl()
  507. //
  508. // From viewer to host, to cancel pending TakeControl request.
  509. //
  510. STDMETHODIMP ASMaster::CancelTakeControl(IAS_GCC_ID PersonOf)
  511. {
  512. return(SHP_CancelTakeControl(PersonOf));
  513. }
  514. //
  515. // ReleaseControl()
  516. //
  517. // From viewer to host, telling host that viewer is not in control of host
  518. // anymore.
  519. //
  520. STDMETHODIMP ASMaster::ReleaseControl(IAS_GCC_ID PersonOf)
  521. {
  522. return(SHP_ReleaseControl(PersonOf));
  523. }
  524. //
  525. // PassControl()
  526. //
  527. // From viewer to host, when viewer is in control of host, asking to pass
  528. // control of host to a different viewer.
  529. STDMETHODIMP ASMaster::PassControl(IAS_GCC_ID PersonOf, IAS_GCC_ID PersonTo)
  530. {
  531. return(SHP_PassControl(PersonOf, PersonTo));
  532. }
  533. //
  534. // AllowControl()
  535. //
  536. // On host side, to allow/stop allowing control at all of shared apps/desktop.
  537. // When one starts to host, allowing control always starts as off. So
  538. // turning on allowing control, stopping sharing, then sharing something
  539. // else will not leave host vulnerable.
  540. //
  541. // When turning it off, if a viewer was in control of the host, kill control
  542. // from the host to the viewer will occur first.
  543. //
  544. // The "ESC" key is an accelerator to stop allowing control, when pressed
  545. // by the user on the host who is currently controlled.
  546. //
  547. STDMETHODIMP ASMaster::AllowControl(BOOL fAllow)
  548. {
  549. return(::SHP_AllowControl(fAllow));
  550. }
  551. //
  552. // GiveControl()
  553. //
  554. // From host to viewer, inviting the viewer to take control of the host.
  555. // It's the inverse of TakeControl.
  556. //
  557. STDMETHODIMP ASMaster::GiveControl(IAS_GCC_ID PersonTo)
  558. {
  559. return(SHP_GiveControl(PersonTo));
  560. }
  561. //
  562. // CancelGiveControl()
  563. //
  564. // From host to viewer, to cancel pending GiveControl request
  565. //
  566. STDMETHODIMP ASMaster::CancelGiveControl(IAS_GCC_ID PersonTo)
  567. {
  568. return(SHP_CancelGiveControl(PersonTo));
  569. }
  570. //
  571. // RevokeControl()
  572. //
  573. // From host to viewer, when host wishes to stop viewer from controlling him.
  574. // AllowControl is still on, for another to possibly take control of the host.
  575. //
  576. // Mouse clicks and key presses other than "ESC" by the user on the controlled
  577. // host host areaccelerators to kill control.
  578. //
  579. STDMETHODIMP ASMaster::RevokeControl(IAS_GCC_ID PersonTo)
  580. {
  581. return(SHP_RevokeControl(PersonTo));
  582. }