Leaked source code of windows server 2003
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.

1044 lines
24 KiB

  1. #include "precomp.h"
  2. #include <RegEntry.h>
  3. #include <oprahcom.h>
  4. #include <asmaster.h>
  5. #define MLZ_FILE_ZONE ZONE_CORE
  6. ASMaster *g_pMaster = NULL;
  7. HRESULT WINAPI CreateASObject
  8. (
  9. IAppSharingNotify * pNotify,
  10. UINT flags,
  11. IAppSharing** ppAS
  12. )
  13. {
  14. HRESULT hr = E_OUTOFMEMORY;
  15. ASMaster * pMaster = NULL;
  16. DebugEntry(CreateASObject);
  17. ASSERT(ppAS);
  18. if (g_pMaster != NULL)
  19. {
  20. ERROR_OUT(("CreateASObject: IAppSharing * alreadycreated; only one allowed at a time"));
  21. hr = E_UNEXPECTED;
  22. DC_QUIT;
  23. }
  24. ASSERT(!g_asMainThreadId);
  25. ASSERT(!g_putOM);
  26. ASSERT(!g_putAL);
  27. ASSERT(!g_putAS);
  28. pMaster = new ASMaster(flags, pNotify);
  29. if (pMaster != NULL)
  30. {
  31. //
  32. // Register as the groupware primary, with an event proc but no exit proc
  33. //
  34. if (!UT_InitTask(UTTASK_UI, &g_putUI))
  35. {
  36. ERROR_OUT(("Failed to register UI task"));
  37. DC_QUIT;
  38. }
  39. UT_RegisterEvent(g_putUI, eventProc, g_putUI, UT_PRIORITY_NORMAL);
  40. // Start groupware thread.
  41. if (!DCS_StartThread(WorkThreadEntryPoint))
  42. {
  43. ERROR_OUT(("Couldn't start groupware thread"));
  44. DC_QUIT;
  45. }
  46. // Make sure the work thread initialization is ok
  47. if (! g_asMainThreadId)
  48. {
  49. ERROR_OUT(("Init failed in the work thread"));
  50. DC_QUIT;
  51. }
  52. //
  53. // Success!
  54. //
  55. }
  56. hr = S_OK;
  57. DC_EXIT_POINT:
  58. if (!SUCCEEDED(hr))
  59. {
  60. if (pMaster)
  61. {
  62. ERROR_OUT(("CreateASObject: Init of ASMaster failed"));
  63. pMaster->Release();
  64. pMaster = NULL;
  65. }
  66. }
  67. *ppAS = pMaster;
  68. DebugExitHRESULT(CreateASObject, hr);
  69. return hr;
  70. }
  71. ASMaster::ASMaster(UINT flags, IAppSharingNotify * pNotify) :
  72. m_cRefs (1),
  73. m_pNotify (pNotify)
  74. {
  75. DebugEntry(ASMaster::ASMaster);
  76. if (m_pNotify)
  77. {
  78. m_pNotify->AddRef();
  79. }
  80. ASSERT(!g_pMaster);
  81. g_pMaster = this;
  82. //
  83. // Set up global flags:
  84. // * service
  85. // * unattended
  86. //
  87. g_asOptions = flags;
  88. DebugExitVOID(ASMaster::ASMaster);
  89. }
  90. ASMaster::~ASMaster()
  91. {
  92. DebugEntry(ASMaster::~ASMaster);
  93. //
  94. // Kill any share that's current or pending in the queue
  95. // This will do nothing if no share is extant at the time the
  96. // message is received.
  97. //
  98. if (g_asMainWindow)
  99. {
  100. PostMessage(g_asMainWindow, DCS_KILLSHARE_MSG, 0, 0);
  101. }
  102. //
  103. // Kill off the worker thread
  104. //
  105. if (g_asMainThreadId)
  106. {
  107. PostThreadMessage(g_asMainThreadId, WM_QUIT, 0, 0);
  108. }
  109. //
  110. // Clean up the UI
  111. //
  112. if (g_putUI)
  113. {
  114. UT_TermTask(&g_putUI);
  115. }
  116. // global variables cleanup
  117. if (m_pNotify)
  118. {
  119. m_pNotify->Release();
  120. m_pNotify = NULL;
  121. }
  122. if (g_pMaster == this)
  123. {
  124. g_pMaster = NULL;
  125. }
  126. DebugExitVOID(ASMaster::~ASMaster);
  127. }
  128. STDMETHODIMP ASMaster::QueryInterface(REFIID iid, void ** pv)
  129. {
  130. return E_NOINTERFACE;
  131. }
  132. STDMETHODIMP_(ULONG) ASMaster::AddRef()
  133. {
  134. InterlockedIncrement(&m_cRefs);
  135. return m_cRefs;
  136. }
  137. STDMETHODIMP_(ULONG) ASMaster::Release()
  138. {
  139. ASSERT(m_cRefs > 0);
  140. if (::InterlockedDecrement(&m_cRefs) == 0)
  141. {
  142. delete this;
  143. return 0;
  144. }
  145. return m_cRefs;
  146. }
  147. //
  148. // WorkThreadEntryPoint()
  149. //
  150. // This is the groupware code--obman, taskloader, and app sharing
  151. //
  152. DWORD WINAPI WorkThreadEntryPoint(LPVOID hEventWait)
  153. {
  154. BOOL result = FALSE;
  155. BOOL fCMGCleanup = FALSE;
  156. BOOL fOMCleanup = FALSE;
  157. BOOL fALCleanup = FALSE;
  158. BOOL fDCSCleanup = FALSE;
  159. MSG msg;
  160. HWND hwndTop;
  161. DebugEntry(WorkThreadEntryPoint);
  162. //
  163. // Get the current thread ID. This is used in the stop code to know
  164. // if the previous thread is still exiting. In the run-when-windows
  165. // starts mode, our init code is called when Conf brings up UI and our
  166. // term code is called when Conf brings it down. We have a race condition
  167. // because this thread is created on each init. If we create a new
  168. // one while the old one is exiting, we will stomp over each other and
  169. // GP-fault.
  170. //
  171. g_asMainThreadId = GetCurrentThreadId();
  172. //
  173. // Get our policies
  174. //
  175. g_asPolicies = 0;
  176. if (g_asOptions & AS_SERVICE)
  177. {
  178. //
  179. // No old whiteboard, no how, for RDS
  180. //
  181. g_asPolicies |= SHP_POLICY_NOOLDWHITEBOARD;
  182. }
  183. else
  184. {
  185. RegEntry rePol(POLICIES_KEY, HKEY_CURRENT_USER);
  186. //
  187. // Is old whiteboard disabled?
  188. //
  189. if (rePol.GetNumber(REGVAL_POL_NO_OLDWHITEBOARD, DEFAULT_POL_NO_OLDWHITEBOARD))
  190. {
  191. WARNING_OUT(("Policy disables Old Whiteboard"));
  192. g_asPolicies |= SHP_POLICY_NOOLDWHITEBOARD;
  193. }
  194. //
  195. // Is application sharing disabled completely?
  196. //
  197. if (rePol.GetNumber(REGVAL_POL_NO_APP_SHARING, DEFAULT_POL_NO_APP_SHARING))
  198. {
  199. WARNING_OUT(("Policy disables App Sharing"));
  200. g_asPolicies |= SHP_POLICY_NOAPPSHARING;
  201. }
  202. else
  203. {
  204. //
  205. // Only grab AS policies if AS is even allowed
  206. //
  207. if (rePol.GetNumber(REGVAL_POL_NO_SHARING, DEFAULT_POL_NO_SHARING))
  208. {
  209. WARNING_OUT(("Policy prevents user from sharing"));
  210. g_asPolicies |= SHP_POLICY_NOSHARING;
  211. }
  212. if (rePol.GetNumber(REGVAL_POL_NO_MSDOS_SHARING, DEFAULT_POL_NO_MSDOS_SHARING))
  213. {
  214. WARNING_OUT(("Policy prevents user from sharing command prompt"));
  215. g_asPolicies |= SHP_POLICY_NODOSBOXSHARE;
  216. }
  217. if (rePol.GetNumber(REGVAL_POL_NO_EXPLORER_SHARING, DEFAULT_POL_NO_EXPLORER_SHARING))
  218. {
  219. WARNING_OUT(("Policy prevents user from sharing explorer"));
  220. g_asPolicies |= SHP_POLICY_NOEXPLORERSHARE;
  221. }
  222. if (rePol.GetNumber(REGVAL_POL_NO_DESKTOP_SHARING, DEFAULT_POL_NO_DESKTOP_SHARING))
  223. {
  224. WARNING_OUT(("Policy prevents user from sharing desktop"));
  225. g_asPolicies |= SHP_POLICY_NODESKTOPSHARE;
  226. }
  227. if (rePol.GetNumber(REGVAL_POL_NO_TRUECOLOR_SHARING, DEFAULT_POL_NO_TRUECOLOR_SHARING))
  228. {
  229. WARNING_OUT(("Policy prevents user from sharing in true color"));
  230. g_asPolicies |= SHP_POLICY_NOTRUECOLOR;
  231. }
  232. if (rePol.GetNumber(REGVAL_POL_NO_ALLOW_CONTROL, DEFAULT_POL_NO_ALLOW_CONTROL))
  233. {
  234. WARNING_OUT(("Policy prevents user from letting others control"));
  235. g_asPolicies |= SHP_POLICY_NOCONTROL;
  236. }
  237. }
  238. }
  239. // Register the call primary code, for T.120 GCC
  240. if (!CMP_Init(&fCMGCleanup))
  241. {
  242. ERROR_OUT(("CMP_Init failed"));
  243. DC_QUIT;
  244. }
  245. if (!(g_asPolicies & SHP_POLICY_NOOLDWHITEBOARD))
  246. {
  247. if (!OMP_Init(&fOMCleanup))
  248. {
  249. ERROR_OUT(("Couldn't start ObMan"));
  250. DC_QUIT;
  251. }
  252. if (!ALP_Init(&fALCleanup))
  253. {
  254. ERROR_OUT(("Couldn't start AppLoader"));
  255. DC_QUIT;
  256. }
  257. }
  258. //
  259. // Do DCS fast init; slow font enum will happen later off a posted
  260. // message. We can still share & participate in sharing without a
  261. // full font list...
  262. //
  263. if (!(g_asPolicies & SHP_POLICY_NOAPPSHARING))
  264. {
  265. fDCSCleanup = TRUE;
  266. if (!DCS_Init())
  267. {
  268. ERROR_OUT(("AS did not initialize"));
  269. DC_QUIT;
  270. }
  271. }
  272. //
  273. // We've successfully initialised - let the thread which created this
  274. // one continue
  275. //
  276. SetEvent((HANDLE)hEventWait);
  277. //
  278. // Enter the main message processing loop:
  279. //
  280. while (GetMessage(&msg, NULL, 0, 0))
  281. {
  282. //
  283. // For dialogs, it's OK to do normal message processing.
  284. //
  285. if (hwndTop = IsForDialog(msg.hwnd))
  286. {
  287. if (!IsDialogMessage(hwndTop, &msg))
  288. {
  289. TranslateMessage(&msg);
  290. DispatchMessage(&msg);
  291. }
  292. }
  293. else
  294. {
  295. //
  296. // Note that this message dispatch loop DOES NOT include a call to
  297. // Translate Message. This is because we do not want it to call
  298. // ToAscii and affect the state maintained internally by ToAscii.
  299. // We will call ToAscii ourselves in the IM when the user is typing
  300. // in a view and calling it more than once for a keystroke
  301. // will cause it to return wrong results (eg for dead keys).
  302. //
  303. // The consequence of this is that any windows which are driven by
  304. // this dispatch loop will NOT receive WM_CHAR or WM_SYSCHAR
  305. // messages. This is not a problem for dialog windows belonging to
  306. // a task using this message loop as the dialog will run its own
  307. // dispatch loop.
  308. //
  309. // If it becomes necessary for windows driven by this dispatch loop
  310. // to get their messages translated then we could add logic to
  311. // determine whether the message is destined for a view
  312. // before deciding whether to translate it.
  313. //
  314. //
  315. // Because we don't have a translate message in our message loop we
  316. // need to do the following to ensure the keyboard LEDs follow what
  317. // the user does when their input is going to this message loop.
  318. //
  319. if (((msg.message == WM_KEYDOWN) ||
  320. (msg.message == WM_SYSKEYDOWN) ||
  321. (msg.message == WM_KEYUP) ||
  322. (msg.message == WM_SYSKEYUP)) &&
  323. IM_KEY_IS_TOGGLE(msg.wParam))
  324. {
  325. BYTE kbState[256];
  326. //
  327. // There is a chance the LEDs state has changed so..
  328. //
  329. GetKeyboardState(kbState);
  330. SetKeyboardState(kbState);
  331. }
  332. DispatchMessage(&msg);
  333. }
  334. }
  335. result = (int)msg.wParam;
  336. //
  337. // We emerge from the processing loop when someone posts us a WM_QUIT.
  338. // We do ObMan specific termination then call UT_TermTask (which will
  339. // call any exit procedures we have registered).
  340. //
  341. DC_EXIT_POINT:
  342. if (fDCSCleanup)
  343. DCS_Term();
  344. if (fALCleanup)
  345. ALP_Term();
  346. if (fOMCleanup)
  347. OMP_Term();
  348. if (fCMGCleanup)
  349. CMP_Term();
  350. g_asMainThreadId = 0;
  351. DebugExitDWORD(WorkThreadEntryPoint, result);
  352. return(result);
  353. }
  354. //
  355. // IsForDialog()
  356. // Returns if the message is intended for a window in a dialog. AppSharing
  357. // has the host UI dialog, incoming request dialogs, and possibly
  358. // notification message box dialogs.
  359. //
  360. HWND IsForDialog(HWND hwnd)
  361. {
  362. BOOL rc = FALSE;
  363. HWND hwndParent;
  364. DebugEntry(IsForDialog);
  365. if (!hwnd)
  366. DC_QUIT;
  367. while (GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD)
  368. {
  369. hwndParent = GetParent(hwnd);
  370. if (hwndParent == GetDesktopWindow())
  371. break;
  372. hwnd = hwndParent;
  373. }
  374. if (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_DLGMODALFRAME)
  375. {
  376. // This is a dialog
  377. }
  378. else
  379. {
  380. hwnd = NULL;
  381. }
  382. DC_EXIT_POINT:
  383. DebugExitPTR(IsForDialog, hwnd);
  384. return(hwnd);
  385. }
  386. //
  387. // ASMaster member functions
  388. //
  389. //
  390. //
  391. //
  392. // ASMaster::OnEvent
  393. //
  394. // Parameters: event event type
  395. // param1 other parameter
  396. // param2 other parameter
  397. //
  398. //
  399. BOOL CALLBACK eventProc
  400. (
  401. LPVOID cpiHandle_,
  402. UINT event,
  403. UINT_PTR param1,
  404. UINT_PTR param2
  405. )
  406. {
  407. BOOL rc;
  408. if (g_pMaster)
  409. {
  410. rc = g_pMaster->OnEvent(event, param1, param2);
  411. }
  412. else
  413. {
  414. WARNING_OUT(("Received ASMaster event %d but no g_pMaster", event));
  415. rc = FALSE;
  416. }
  417. return rc;
  418. }
  419. BOOL ASMaster::OnEvent
  420. (
  421. UINT event,
  422. UINT_PTR param1,
  423. UINT_PTR param2
  424. )
  425. {
  426. BOOL rc = TRUE;
  427. DebugEntry(ASMaster::OnEvent);
  428. if (!m_pNotify)
  429. {
  430. // Nothing to do
  431. rc = FALSE;
  432. DC_QUIT;
  433. }
  434. switch (event)
  435. {
  436. case SH_EVT_APPSHARE_READY:
  437. m_pNotify->OnReadyToShare(param1 != 0);
  438. break;
  439. case SH_EVT_SHARE_STARTED:
  440. m_pNotify->OnShareStarted();
  441. break;
  442. case SH_EVT_SHARING_STARTED:
  443. m_pNotify->OnSharingStarted();
  444. break;
  445. case SH_EVT_SHARE_ENDED:
  446. m_pNotify->OnShareEnded();
  447. break;
  448. case SH_EVT_PERSON_JOINED:
  449. m_pNotify->OnPersonJoined((IAS_GCC_ID)param1);
  450. break;
  451. case SH_EVT_PERSON_LEFT:
  452. m_pNotify->OnPersonLeft((IAS_GCC_ID)param1);
  453. break;
  454. case SH_EVT_STARTINCONTROL:
  455. m_pNotify->OnStartInControl((IAS_GCC_ID)param1);
  456. break;
  457. case SH_EVT_STOPINCONTROL:
  458. m_pNotify->OnStopInControl((IAS_GCC_ID)param1);
  459. break;
  460. case SH_EVT_PAUSEDINCONTROL:
  461. m_pNotify->OnPausedInControl((IAS_GCC_ID)param1);
  462. break;
  463. case SH_EVT_UNPAUSEDINCONTROL:
  464. m_pNotify->OnUnpausedInControl((IAS_GCC_ID)param1);
  465. break;
  466. case SH_EVT_CONTROLLABLE:
  467. m_pNotify->OnControllable(param1 != 0);
  468. break;
  469. case SH_EVT_STARTCONTROLLED:
  470. m_pNotify->OnStartControlled((IAS_GCC_ID)param1);
  471. break;
  472. case SH_EVT_STOPCONTROLLED:
  473. m_pNotify->OnStopControlled((IAS_GCC_ID)param1);
  474. break;
  475. case SH_EVT_PAUSEDCONTROLLED:
  476. m_pNotify->OnPausedControlled((IAS_GCC_ID)param1);
  477. break;
  478. case SH_EVT_UNPAUSEDCONTROLLED:
  479. m_pNotify->OnUnpausedControlled((IAS_GCC_ID)param1);
  480. break;
  481. default:
  482. // Unrecognized, unhandled event
  483. rc = FALSE;
  484. break;
  485. }
  486. DC_EXIT_POINT:
  487. DebugExitBOOL(ASMaster::OnEvent, rc);
  488. return(rc);
  489. }
  490. //
  491. // ASMaster::IsSharingAvailable()
  492. //
  493. STDMETHODIMP_(BOOL) ASMaster::IsSharingAvailable()
  494. {
  495. return(g_asSession.hwndHostUI != NULL);
  496. }
  497. //
  498. // ASMaster::CanShareNow()
  499. //
  500. STDMETHODIMP_(BOOL) ASMaster::CanShareNow()
  501. {
  502. BOOL rc = FALSE;
  503. UT_Lock(UTLOCK_AS);
  504. //
  505. // We can share if
  506. // * We can capture graphic output on this OS
  507. // * We're in a call
  508. //
  509. if (g_asSession.hwndHostUI &&
  510. g_asSession.callID &&
  511. (g_asSession.attendeePermissions & NM_PERMIT_SHARE) &&
  512. (g_s20State >= S20_NO_SHARE))
  513. {
  514. rc = TRUE;
  515. }
  516. UT_Unlock(UTLOCK_AS);
  517. return(rc);
  518. }
  519. //
  520. // ASMaster::InInShare()
  521. //
  522. STDMETHODIMP_(BOOL) ASMaster::IsInShare()
  523. {
  524. return(g_asSession.pShare != NULL);
  525. }
  526. //
  527. // ASMaster::IsSharing()
  528. //
  529. STDMETHODIMP_(BOOL) ASMaster::IsSharing()
  530. {
  531. IAS_PERSON_STATUS personStatus;
  532. ::ZeroMemory(&personStatus, sizeof(personStatus));
  533. personStatus.cbSize = sizeof(personStatus);
  534. GetPersonStatus(0, &personStatus);
  535. return(personStatus.AreSharing != 0);
  536. }
  537. //
  538. // CanAllowControl()
  539. // We can allow control if we're sharing and it's not prevented by policy
  540. //
  541. STDMETHODIMP_(BOOL) ASMaster::CanAllowControl(void)
  542. {
  543. if (g_asPolicies & SHP_POLICY_NOCONTROL)
  544. return(FALSE);
  545. return(IsSharing());
  546. }
  547. //
  548. // IsControllable()
  549. // We are controllable if our state isn't detached.
  550. //
  551. STDMETHODIMP_(BOOL) ASMaster::IsControllable(void)
  552. {
  553. IAS_PERSON_STATUS personStatus;
  554. ::ZeroMemory(&personStatus, sizeof(personStatus));
  555. personStatus.cbSize = sizeof(personStatus);
  556. GetPersonStatus(0, &personStatus);
  557. return(personStatus.Controllable != 0);
  558. }
  559. //
  560. // GetPersonStatus()
  561. //
  562. STDMETHODIMP ASMaster::GetPersonStatus(IAS_GCC_ID Person, IAS_PERSON_STATUS * pStatus)
  563. {
  564. return(::SHP_GetPersonStatus(Person, pStatus));
  565. }
  566. //
  567. // ASMaster::IsWindowShareable()
  568. //
  569. STDMETHODIMP_(BOOL) ASMaster::IsWindowShareable(HWND hwnd)
  570. {
  571. return(CanShareNow() && HET_IsWindowShareable(hwnd));
  572. }
  573. //
  574. // ASMaster::IsWindowShared()
  575. //
  576. STDMETHODIMP_(BOOL) ASMaster::IsWindowShared(HWND hwnd)
  577. {
  578. return(HET_IsWindowShared(hwnd));
  579. }
  580. //
  581. //
  582. // ASMaster::Share
  583. //
  584. // Parameters: HWND of the window to share. This can be any (valid) HWND.
  585. //
  586. //
  587. STDMETHODIMP ASMaster::Share(HWND hwnd, IAS_SHARE_TYPE uAppType)
  588. {
  589. HRESULT hr;
  590. DebugEntry(ASMaster::Share);
  591. hr = E_FAIL;
  592. if (!CanShareNow())
  593. {
  594. WARNING_OUT(("Share failing; can't share now"));
  595. DC_QUIT;
  596. }
  597. //
  598. // If this is the desktop, check for a policy against just it.
  599. //
  600. if (hwnd == ::GetDesktopWindow())
  601. {
  602. if (g_asPolicies & SHP_POLICY_NODESKTOPSHARE)
  603. {
  604. WARNING_OUT(("Sharing desktop failing; prevented by policy"));
  605. DC_QUIT;
  606. }
  607. }
  608. switch (uAppType)
  609. {
  610. case IAS_SHARE_DEFAULT:
  611. case IAS_SHARE_BYPROCESS:
  612. case IAS_SHARE_BYTHREAD:
  613. case IAS_SHARE_BYWINDOW:
  614. break;
  615. default:
  616. {
  617. ERROR_OUT(("IAppSharing::Share - invalid share type %d", uAppType));
  618. return E_INVALIDARG;
  619. }
  620. }
  621. if (SHP_Share(hwnd, uAppType))
  622. {
  623. hr = S_OK;
  624. }
  625. DC_EXIT_POINT:
  626. DebugExitHRESULT(ASMaster::Share, hr);
  627. return hr;
  628. }
  629. //
  630. //
  631. // ASMaster::Unshare
  632. //
  633. // Parameters: HWND of the window to unshare
  634. //
  635. //
  636. STDMETHODIMP ASMaster::Unshare(HWND hwnd)
  637. {
  638. return(::SHP_Unshare(hwnd));
  639. }
  640. //
  641. //
  642. // ASMaster::LaunchHostUI()
  643. //
  644. //
  645. STDMETHODIMP ASMaster::LaunchHostUI(void)
  646. {
  647. return(SHP_LaunchHostUI());
  648. }
  649. //
  650. //
  651. // ASMaster::GetShareableApps
  652. //
  653. // Generates a list of HWND's into <validAppList>
  654. // These objects are allocated dynamically, so must be deleted by the
  655. // caller.
  656. //
  657. //
  658. STDMETHODIMP ASMaster::GetShareableApps(IAS_HWND_ARRAY **ppHwnds)
  659. {
  660. if (!CanShareNow())
  661. return(E_FAIL);
  662. return(HET_GetAppsList(ppHwnds) ? S_OK : E_FAIL);
  663. }
  664. STDMETHODIMP ASMaster::FreeShareableApps(IAS_HWND_ARRAY * pMemory)
  665. {
  666. HET_FreeAppsList(pMemory);
  667. return S_OK;
  668. }
  669. //
  670. // TakeControl()
  671. //
  672. // From viewer to host, asking to take control of host.
  673. //
  674. STDMETHODIMP ASMaster::TakeControl(IAS_GCC_ID PersonOf)
  675. {
  676. return(SHP_TakeControl(PersonOf));
  677. }
  678. //
  679. // CancelTakeControl()
  680. //
  681. // From viewer to host, to cancel pending TakeControl request.
  682. //
  683. STDMETHODIMP ASMaster::CancelTakeControl(IAS_GCC_ID PersonOf)
  684. {
  685. return(SHP_CancelTakeControl(PersonOf));
  686. }
  687. //
  688. // ReleaseControl()
  689. //
  690. // From viewer to host, telling host that viewer is not in control of host
  691. // anymore.
  692. //
  693. STDMETHODIMP ASMaster::ReleaseControl(IAS_GCC_ID PersonOf)
  694. {
  695. return(SHP_ReleaseControl(PersonOf));
  696. }
  697. //
  698. // PassControl()
  699. //
  700. // From viewer to host, when viewer is in control of host, asking to pass
  701. // control of host to a different viewer.
  702. STDMETHODIMP ASMaster::PassControl(IAS_GCC_ID PersonOf, IAS_GCC_ID PersonTo)
  703. {
  704. return(SHP_PassControl(PersonOf, PersonTo));
  705. }
  706. //
  707. // AllowControl()
  708. //
  709. // On host side, to allow/stop allowing control at all of shared apps/desktop.
  710. // When one starts to host, allowing control always starts as off. So
  711. // turning on allowing control, stopping sharing, then sharing something
  712. // else will not leave host vulnerable.
  713. //
  714. // When turning it off, if a viewer was in control of the host, kill control
  715. // from the host to the viewer will occur first.
  716. //
  717. // The "ESC" key is an accelerator to stop allowing control, when pressed
  718. // by the user on the host who is currently controlled.
  719. //
  720. STDMETHODIMP ASMaster::AllowControl(BOOL fAllow)
  721. {
  722. return(::SHP_AllowControl(fAllow));
  723. }
  724. //
  725. // GiveControl()
  726. //
  727. // From host to viewer, inviting the viewer to take control of the host.
  728. // It's the inverse of TakeControl.
  729. //
  730. STDMETHODIMP ASMaster::GiveControl(IAS_GCC_ID PersonTo)
  731. {
  732. return(SHP_GiveControl(PersonTo));
  733. }
  734. //
  735. // CancelGiveControl()
  736. //
  737. // From host to viewer, to cancel pending GiveControl request
  738. //
  739. STDMETHODIMP ASMaster::CancelGiveControl(IAS_GCC_ID PersonTo)
  740. {
  741. return(SHP_CancelGiveControl(PersonTo));
  742. }
  743. //
  744. // RevokeControl()
  745. //
  746. // From host to viewer, when host wishes to stop viewer from controlling him.
  747. // AllowControl is still on, for another to possibly take control of the host.
  748. //
  749. // Mouse clicks and key presses other than "ESC" by the user on the controlled
  750. // host host areaccelerators to kill control.
  751. //
  752. STDMETHODIMP ASMaster::RevokeControl(IAS_GCC_ID PersonTo)
  753. {
  754. return(SHP_RevokeControl(PersonTo));
  755. }
  756. //
  757. // PauseControl()
  758. //
  759. // On host, to temporarily allow local user to do stuff without breaking
  760. // control bond. We put the viewer on hold.
  761. //
  762. STDMETHODIMP ASMaster::PauseControl(IAS_GCC_ID PersonInControl)
  763. {
  764. return(SHP_PauseControl(PersonInControl, TRUE));
  765. }
  766. //
  767. // UnpauseControl()
  768. //
  769. // On host, to unpause control that has been paused. We take the viewer
  770. // off hold.
  771. //
  772. STDMETHODIMP ASMaster::UnpauseControl(IAS_GCC_ID PersonInControl)
  773. {
  774. return(SHP_PauseControl(PersonInControl, FALSE));
  775. }
  776. //
  777. // StartStopOldWB
  778. //
  779. extern "C"
  780. {
  781. BOOL WINAPI StartStopOldWB(LPCTSTR szFile)
  782. {
  783. LPTSTR szCopyOfFile;
  784. ValidateUTClient(g_putUI);
  785. if (g_asPolicies & SHP_POLICY_NOOLDWHITEBOARD)
  786. {
  787. WARNING_OUT(("Not launching old whiteboard; prevented by policy"));
  788. return(FALSE);
  789. }
  790. //
  791. // Because we're posting a message effectively, we have to make a
  792. // copy of the string. If we ever have "SendEvent", we won't have
  793. // that problem anymore.
  794. //
  795. if (szFile)
  796. {
  797. int cchLength;
  798. BOOL fSkippedQuote;
  799. // Skip past first quote
  800. if (fSkippedQuote = (*szFile == '"'))
  801. szFile++;
  802. cchLength = lstrlen(szFile);
  803. szCopyOfFile = (LPTSTR)::GlobalAlloc(GPTR, (cchLength+1)*sizeof(TCHAR));
  804. if (!szCopyOfFile)
  805. {
  806. ERROR_OUT(("Can't make file name copy for whiteboard launch"));
  807. return(FALSE);
  808. }
  809. lstrcpy(szCopyOfFile, szFile);
  810. //
  811. // NOTE:
  812. // There may be DBCS implications with this. Hence we check to see
  813. // if we skipped the first quote; we assume that if the file name
  814. // starts with a quote it must end with one also. But we need to check
  815. // it out.
  816. //
  817. // Strip last quote
  818. if (fSkippedQuote && (cchLength > 0) && (szCopyOfFile[cchLength - 1] == '"'))
  819. {
  820. TRACE_OUT(("Skipping last quote in file name %s", szCopyOfFile));
  821. szCopyOfFile[cchLength - 1] = '\0';
  822. }
  823. }
  824. else
  825. {
  826. szCopyOfFile = NULL;
  827. }
  828. UT_PostEvent(g_putUI, g_putAL, NO_DELAY,
  829. AL_INT_STARTSTOP_WB, 0, (UINT_PTR)szCopyOfFile);
  830. return(TRUE);
  831. }
  832. }