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.

1728 lines
39 KiB

  1. #include "precomp.h"
  2. //
  3. // DCS.CPP
  4. // Sharing main (init/term plus communication to/from ASMaster)
  5. //
  6. // Copyright(c) Microsoft 1997-
  7. //
  8. #define MLZ_FILE_ZONE ZONE_CORE
  9. //
  10. // DCS_Init()
  11. //
  12. BOOL DCS_Init(void)
  13. {
  14. WNDCLASS wc;
  15. BOOL rc = FALSE;
  16. HDC hdc;
  17. DebugEntry(DCS_Init);
  18. if (g_asOptions & AS_SERVICE)
  19. {
  20. WARNING_OUT(("AS is running as SERVICE"));
  21. }
  22. //
  23. // Register with the DC-Groupware Utility Services
  24. //
  25. if (!UT_InitTask(UTTASK_DCS, &g_putAS))
  26. {
  27. ERROR_OUT(( "Failed to init DCS task"));
  28. DC_QUIT;
  29. }
  30. UT_RegisterEvent(g_putAS, S20_UTEventProc, NULL, UT_PRIORITY_APPSHARING);
  31. //
  32. // Create the window
  33. //
  34. //
  35. // Register the main window class.
  36. //
  37. wc.style = 0;
  38. wc.lpfnWndProc = DCSMainWndProc;
  39. wc.cbClsExtra = 0;
  40. wc.cbWndExtra = 0;
  41. wc.hInstance = g_asInstance;
  42. wc.hIcon = NULL;
  43. wc.hCursor = NULL;
  44. wc.hbrBackground = NULL;
  45. wc.lpszMenuName = NULL;
  46. wc.lpszClassName = DCS_MAIN_WINDOW_CLASS;
  47. if (!RegisterClass(&wc))
  48. {
  49. ERROR_OUT(("DCS_Init: couldn't register main window class"));
  50. DC_QUIT;
  51. }
  52. //
  53. // Create the main window.
  54. //
  55. // We make the window topmost so that it is sent the WM_QUERYENDSESSION
  56. // message before any other (non-topmost) windows. This lets us
  57. // prevent the session from closing down if we are still in a share.
  58. //
  59. g_asMainWindow = CreateWindowEx(
  60. WS_EX_TOPMOST, // Make the window topmost
  61. DCS_MAIN_WINDOW_CLASS, // See RegisterClass() call.
  62. NULL, // Text for window title bar.
  63. 0, // Invisible.
  64. 0, // Default horizontal position.
  65. 0, // Default vertical position.
  66. 200, // Default width.
  67. 100, // Default height.
  68. NULL, // Overlapped windows have no parent.
  69. NULL, // Use the window class menu.
  70. g_asInstance,
  71. NULL // Pointer not needed.
  72. );
  73. if (!g_asMainWindow)
  74. {
  75. ERROR_OUT(("DCS_Init: couldn't create main window"));
  76. DC_QUIT;
  77. }
  78. //
  79. // Check that display driver is loaded (if it isn't we can't host)
  80. //
  81. hdc = GetDC(NULL);
  82. g_usrScreenBPP = GetDeviceCaps(hdc, BITSPIXEL) *
  83. GetDeviceCaps(hdc, PLANES);
  84. g_usrPalettized = ((GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) != 0);
  85. ReleaseDC(NULL, hdc);
  86. g_usrCaptureBPP = g_usrScreenBPP;
  87. ASSERT(!g_asCanHost);
  88. ASSERT(!g_osiInitialized);
  89. ASSERT(!g_asSharedMemory);
  90. ASSERT(!g_poaData[0]);
  91. ASSERT(!g_poaData[1]);
  92. ASSERT(!g_lpimSharedData);
  93. ASSERT(!g_sbcEnabled);
  94. ASSERT(!g_asbcBitMasks[0]);
  95. ASSERT(!g_asbcBitMasks[1]);
  96. ASSERT(!g_asbcBitMasks[2]);
  97. OSI_Init();
  98. //
  99. // If we can't get hold of a pointer to shared IM vars, we are hosed.
  100. //
  101. if (!g_lpimSharedData)
  102. {
  103. ERROR_OUT(("Failed to get shared IM data"));
  104. DC_QUIT;
  105. }
  106. ASSERT(g_lpimSharedData->cbSize == sizeof(IM_SHARED_DATA));
  107. if (g_asOptions & AS_UNATTENDED)
  108. {
  109. // Let the input pieces (Win9x or NT) know we're in unattended mode
  110. g_lpimSharedData->imUnattended = TRUE;
  111. }
  112. //
  113. // Scheduler
  114. //
  115. if (!SCH_Init())
  116. {
  117. ERROR_OUT(("SCH Init failed"));
  118. DC_QUIT;
  119. }
  120. //
  121. // Hosting
  122. //
  123. if (!HET_Init())
  124. {
  125. ERROR_OUT(("HET Init failed"));
  126. DC_QUIT;
  127. }
  128. //
  129. // Viewing
  130. //
  131. if (!VIEW_Init())
  132. {
  133. ERROR_OUT(("VIEW Init failed"));
  134. DC_QUIT;
  135. }
  136. //
  137. // T.120 & T.128 Net
  138. //
  139. //
  140. // Initialize the network layer last of all. This prevents us from
  141. // getting requests before we've fully initialized our components.
  142. //
  143. if (!S20_Init())
  144. {
  145. ERROR_OUT(("S20 Init failed"));
  146. DC_QUIT;
  147. }
  148. if (!SC_Init())
  149. {
  150. ERROR_OUT(("SC Init failed"));
  151. DC_QUIT;
  152. }
  153. //
  154. // We are now initialized. Post a deferred message to get fonts.
  155. //
  156. PostMessage(g_asMainWindow, DCS_FINISH_INIT_MSG, 0, 0);
  157. // All modules have successfully initialised. Return success.
  158. // We are now ready to participate in sharing.
  159. //
  160. rc = TRUE;
  161. DC_EXIT_POINT:
  162. DebugExitBOOL(DCS_Init, rc);
  163. return(rc);
  164. }
  165. //
  166. // DCS_Term()
  167. //
  168. void DCS_Term(void)
  169. {
  170. DebugEntry(DCS_Term);
  171. //
  172. // Kill window. Do this FIRST so that any attempts to send us requests
  173. // or notifications will fail.
  174. //
  175. if (g_asMainWindow)
  176. {
  177. DestroyWindow(g_asMainWindow);
  178. g_asMainWindow = NULL;
  179. }
  180. UnregisterClass(DCS_MAIN_WINDOW_CLASS, g_asInstance);
  181. //
  182. // Network layer - terminate this early because it will handle
  183. // termination in a call by generating approriate events.
  184. //
  185. S20_Term();
  186. SC_Term();
  187. //
  188. // Scheduler.
  189. //
  190. SCH_Term();
  191. //
  192. // Viewing
  193. //
  194. VIEW_Term();
  195. //
  196. // Hosting
  197. //
  198. HET_Term();
  199. //
  200. // Fonts
  201. //
  202. FH_Term();
  203. //
  204. // Terminate OSI
  205. //
  206. OSI_Term();
  207. //
  208. // Deregister from the Groupware Utility Services
  209. //
  210. if (g_putAS)
  211. {
  212. UT_TermTask(&g_putAS);
  213. }
  214. DebugExitVOID(DCS_Term);
  215. }
  216. //
  217. // DCS_FinishInit()
  218. //
  219. // This does slow font enumeration, and then tries to join a call if one
  220. // has started up. Even if font enum fails, we can share/view shared, we
  221. // just won't send text orders
  222. //
  223. void DCS_FinishInit(void)
  224. {
  225. DebugEntry(DCS_FinishInit);
  226. //
  227. // Determine what fonts we have locally.
  228. // Done after the r11 caps field is filled in, since if we dont support
  229. // some of the r11 caps, then we can reduce the amount of work we do
  230. // when we get the font metrics etc.
  231. //
  232. g_cpcLocalCaps.orders.capsNumFonts = (TSHR_UINT16)FH_Init();
  233. DebugExitVOID(DCS_FinishInit);
  234. }
  235. //
  236. // FUNCTION: DCS_PartyJoiningShare
  237. //
  238. BOOL ASShare::DCS_PartyJoiningShare(ASPerson * pasPerson)
  239. {
  240. BOOL rc = FALSE;
  241. UINT iDict;
  242. DebugEntry(ASShare::DCS_PartyJoiningShare);
  243. ValidatePerson(pasPerson);
  244. //
  245. // Allocate dictionaries for GDC Persistent dictionary compression if
  246. // this person supports it. We'll use them to decompress data
  247. // received from this person. NOTE: Win95 2.0 does not support
  248. // persistent pkzip.
  249. //
  250. TRACE_OUT(( "Allocating receive dictionary set for [%d]", pasPerson->mcsID));
  251. pasPerson->adcsDict = new GDC_DICTIONARY[GDC_DICT_COUNT];
  252. if (!pasPerson->adcsDict)
  253. {
  254. ERROR_OUT(("Failed to allocate persistent dictionaries for [%d]", pasPerson->mcsID));
  255. DC_QUIT;
  256. }
  257. else
  258. {
  259. //
  260. // Initialize cbUsed to zero
  261. //
  262. for (iDict = 0; iDict < GDC_DICT_COUNT; iDict++)
  263. {
  264. pasPerson->adcsDict[iDict].cbUsed = 0;
  265. }
  266. }
  267. rc = TRUE;
  268. DC_EXIT_POINT:
  269. DebugExitBOOL(ASShare::DCS_PartyJoiningShare, rc);
  270. return(rc);
  271. }
  272. //
  273. // FUNCTION: DCS_PartyLeftShare
  274. //
  275. void ASShare::DCS_PartyLeftShare(ASPerson * pasPerson)
  276. {
  277. DebugEntry(ASShare::DCS_PartyLeftShare);
  278. ValidatePerson(pasPerson);
  279. //
  280. // Free any dictionaries we allocated
  281. //
  282. if (pasPerson->adcsDict)
  283. {
  284. delete[] pasPerson->adcsDict;
  285. pasPerson->adcsDict = NULL;
  286. }
  287. DebugExitVOID(ASShare::DCS_PartyLeftShare);
  288. }
  289. //
  290. // DCS_RecalcCaps()
  291. //
  292. // Called when someone joins or leaves share.
  293. //
  294. void ASShare::DCS_RecalcCaps(BOOL fJoiner)
  295. {
  296. ASPerson * pasT;
  297. DebugEntry(ASShare::DCS_RecalcCaps);
  298. //
  299. // The combined compression support is initialised to the local support
  300. //
  301. ValidatePerson(m_pasLocal);
  302. DebugExitVOID(ASShare::DCS_RecalcCaps);
  303. }
  304. //
  305. // SC_Periodic()
  306. //
  307. // The Scheduler runs a separate thread which is responsible for posting
  308. // messages to our main thread, for which SC_Periodic() is the handler.
  309. // Posted messages have the highest priority in GetMessage(), above input,
  310. // paints, and timers.
  311. //
  312. // The Scheduler is in one of three states:
  313. // asleep, normal or turbo. When it is asleep, this function is not
  314. // called. When it is in normal mode, this function is called at least
  315. // once, but the scheduler is a lazy guy, so will fall asleep again unless
  316. // you keep prodding him. In turbo mode this function is called repeatedly
  317. // and rapidly, but only for a relatively short time, after which the
  318. // scheduler falls back into normal mode, and from there falls asleep.
  319. //
  320. void ASShare::SC_Periodic(void)
  321. {
  322. UINT currentTime;
  323. DebugEntry(ASShare::SC_Periodic);
  324. //
  325. // We must get the time accurately.
  326. //
  327. currentTime = GetTickCount();
  328. //
  329. // Dont do a lot of work if this is an immediate reschedule due to
  330. // multiple queued entries. Most processors will achieve this in
  331. // less than 5 mS.
  332. //
  333. if ((currentTime - m_dcsLastScheduleTime) < 5)
  334. {
  335. WARNING_OUT(("Quit early"));
  336. DC_QUIT;
  337. }
  338. m_dcsLastScheduleTime = currentTime;
  339. //
  340. // Call the input manager event playback function frequently so that
  341. // we keep the input queue empty. (Note that we do not want to just
  342. // dump the input queue into USER because we would lose all the
  343. // repeat keystroke packets we have so carefully sent across)
  344. // To trigger input we just use a 0 personid and NULL packet.
  345. //
  346. if ((currentTime - m_dcsLastIMTime) > DCS_IM_PERIOD)
  347. {
  348. m_dcsLastIMTime = currentTime;
  349. IM_ReceivedPacket(NULL, NULL);
  350. }
  351. //
  352. // There are calls which are made periodically but don't have any
  353. // dependencies. First call the ones we want to be called fairly
  354. // frequently.
  355. //
  356. if ((currentTime - m_dcsLastFastMiscTime) > DCS_FAST_MISC_PERIOD )
  357. {
  358. m_dcsLastFastMiscTime = currentTime;
  359. OE_Periodic();
  360. HET_Periodic();
  361. CA_Periodic();
  362. IM_Periodic();
  363. }
  364. //
  365. // Only send updates if we're hosting, and have managed to tell everyone
  366. // we're hosting.
  367. //
  368. if (m_pHost && !m_hetRetrySendState)
  369. {
  370. BOOL fetchedBounds = FALSE;
  371. m_pHost->CA_Periodic();
  372. //
  373. // See if we need to swap the buffers over. Only swap if we have
  374. // sent all the data from the current orders.
  375. //
  376. if (m_pHost->OA_GetFirstListOrder() == NULL)
  377. {
  378. //
  379. // Get the current bounds from the driver. This will fill in
  380. // the share core's copy of the bounds.
  381. //
  382. m_pHost->BA_FetchBounds();
  383. fetchedBounds = TRUE;
  384. //
  385. // Set up the new order list buffer
  386. //
  387. m_pHost->OA_ResetOrderList();
  388. //
  389. // Bounds data should be reset to a usable state by SDG once it
  390. // has finished with them, so we just need to swap the buffers
  391. // at this point.
  392. //
  393. SHM_SwitchReadBuffer();
  394. }
  395. //
  396. // In this high frequency code path we only send SWP info if it
  397. // is flagged as needed by the CBT hooks or if SWL determines a
  398. // send is required. Only SWL knows if a send is required so
  399. // pass the CBT indication into SWL and let it do the
  400. // determination.
  401. //
  402. // The SWL window scan performs preemptable operations and we
  403. // must detect the occurrence of preemption otherwise we find
  404. // ourselves sending updates against an invalid window
  405. // structure. Therefore we query OA and BA to see if any
  406. // updates have been accumulated in the interim. We can tight
  407. // loop trying to get a good SWL list because we really don't
  408. // want to yield at this point - it is just that we cannot
  409. // prevent it sometimes. (Sweeping through menus is a good way
  410. // to exercise this code.)
  411. //
  412. //
  413. // Synchronize the fast path data
  414. //
  415. SHM_SwitchFastBuffer();
  416. m_pHost->SWL_Periodic();
  417. m_pHost->UP_Periodic(currentTime);
  418. m_pHost->CM_Periodic();
  419. //
  420. // If we got the bounds from the driver, we have to let the driver know
  421. // how much of the bounds remain to be sent.
  422. //
  423. if (fetchedBounds)
  424. {
  425. m_pHost->BA_ReturnBounds();
  426. }
  427. }
  428. DC_EXIT_POINT:
  429. SCH_ContinueScheduling(SCH_MODE_NORMAL);
  430. DebugExitVOID(ASShare::SC_Periodic);
  431. }
  432. //
  433. // DCS_CompressAndSendPacket()
  434. //
  435. #ifdef _DEBUG
  436. UINT ASShare::DCS_CompressAndSendPacket
  437. #else
  438. void ASShare::DCS_CompressAndSendPacket
  439. #endif // _DEBUG
  440. (
  441. UINT streamID,
  442. UINT nodeID,
  443. PS20DATAPACKET pPacket,
  444. UINT packetLength
  445. )
  446. {
  447. UINT cbSrcDataSize;
  448. UINT cbDstDataSize;
  449. UINT compression;
  450. BOOL compressed;
  451. UINT dictionary;
  452. DebugEntry(ASShare::DCS_CompressAndSendPacket);
  453. ASSERT(streamID >= SC_STREAM_LOW);
  454. ASSERT(streamID <= SC_STREAM_HIGH);
  455. ASSERT(!m_ascSynced[streamID-1]);
  456. ASSERT(!m_scfInSync);
  457. ASSERT(packetLength < TSHR_MAX_SEND_PKT);
  458. //
  459. // Decide which (if any) compression algorithm we are going to use to
  460. // try and compress this packet.
  461. //
  462. compression = 0;
  463. cbSrcDataSize = packetLength - sizeof(S20DATAPACKET);
  464. //
  465. // Is the data a compressable size?
  466. //
  467. if ((cbSrcDataSize >= DCS_MIN_COMPRESSABLE_PACKET) &&
  468. (!m_dcsLargePacketCompressionOnly ||
  469. (cbSrcDataSize >= DCS_MIN_FAST_COMPRESSABLE_PACKET)))
  470. {
  471. if (cbSrcDataSize <= DCS_MAX_PDC_COMPRESSABLE_PACKET)
  472. {
  473. //
  474. // Use PERSIST_PKZIP compression
  475. //
  476. compression = GCT_PERSIST_PKZIP;
  477. }
  478. else
  479. {
  480. //
  481. // Use PKZIP compression
  482. //
  483. compression = GCT_PKZIP;
  484. }
  485. }
  486. //
  487. // Compress the packet
  488. //
  489. compressed = FALSE;
  490. if (compression != 0)
  491. {
  492. PGDC_DICTIONARY pgdcSrc = NULL;
  493. //
  494. // We compress only the data and not the header of course
  495. //
  496. cbDstDataSize = cbSrcDataSize;
  497. ASSERT(m_ascTmpBuffer != NULL);
  498. //
  499. // Compress the data following the packet header.
  500. //
  501. if (compression == GCT_PERSIST_PKZIP)
  502. {
  503. //
  504. // Figure out what dictionary to use for the stream priority
  505. //
  506. switch (streamID)
  507. {
  508. case PROT_STR_UPDATES:
  509. dictionary = GDC_DICT_UPDATES;
  510. break;
  511. case PROT_STR_MISC:
  512. dictionary = GDC_DICT_MISC;
  513. break;
  514. case PROT_STR_INPUT:
  515. dictionary = GDC_DICT_INPUT;
  516. break;
  517. }
  518. pgdcSrc = &m_pasLocal->adcsDict[dictionary];
  519. }
  520. compressed = GDC_Compress(pgdcSrc, GDCCO_MAXCOMPRESSION,
  521. m_agdcWorkBuf, (LPBYTE)(pPacket + 1),
  522. cbSrcDataSize, m_ascTmpBuffer, &cbDstDataSize);
  523. if (compressed)
  524. {
  525. //
  526. // The data was successfully compressed, copy it back
  527. //
  528. ASSERT(cbDstDataSize <= cbSrcDataSize);
  529. memcpy((pPacket+1), m_ascTmpBuffer, cbDstDataSize);
  530. //
  531. // The data length include the data header
  532. //
  533. pPacket->dataLength = (TSHR_UINT16)(cbDstDataSize + sizeof(DATAPACKETHEADER));
  534. pPacket->data.compressedLength = pPacket->dataLength;
  535. packetLength = cbDstDataSize + sizeof(S20DATAPACKET);
  536. }
  537. }
  538. //
  539. // Update the packet header.
  540. //
  541. if (!compressed)
  542. {
  543. pPacket->data.compressionType = 0;
  544. }
  545. else
  546. {
  547. pPacket->data.compressionType = (BYTE)compression;
  548. }
  549. //
  550. // Send the packet.
  551. //
  552. S20_SendDataPkt(streamID, nodeID, pPacket);
  553. #ifdef _DEBUG
  554. DebugExitDWORD(ASShare::DCS_CompressAndSendPacket, packetLength);
  555. return(packetLength);
  556. #else
  557. DebugExitVOID(ASShare::DCS_CompressAndSendPacket);
  558. #endif // _DEBUG
  559. }
  560. //
  561. // DCS_FlowControl()
  562. //
  563. // This is called back from our flow control code. The parameter passed
  564. // is the new bytes/second rate that data is flowing at. We turn small
  565. // packet compression off when the rate is large, it means we're on a
  566. // fast link so there's no need to bog down the CPU compressing small
  567. // packets.
  568. //
  569. void ASShare::DCS_FlowControl
  570. (
  571. UINT DataBytesPerSecond
  572. )
  573. {
  574. DebugEntry(ASShare::DCS_FlowControl);
  575. if (DataBytesPerSecond < DCS_FAST_THRESHOLD)
  576. {
  577. //
  578. // Throughput is slow
  579. //
  580. if (m_dcsLargePacketCompressionOnly)
  581. {
  582. m_dcsLargePacketCompressionOnly = FALSE;
  583. TRACE_OUT(("DCS_FlowControl: SLOW; compress small packets"));
  584. }
  585. }
  586. else
  587. {
  588. //
  589. // Throughput is fast
  590. //
  591. if (!m_dcsLargePacketCompressionOnly)
  592. {
  593. m_dcsLargePacketCompressionOnly = TRUE;
  594. TRACE_OUT(("DCS_FlowControl: FAST; don't compress small packets"));
  595. }
  596. }
  597. DebugExitVOID(ASShare::DCS_FlowControl);
  598. }
  599. //
  600. // DCS_SyncOutgoing() - see dcs.h
  601. //
  602. void ASShare::DCS_SyncOutgoing(void)
  603. {
  604. DebugEntry(ASShare::DCS_SyncOutgoing);
  605. //
  606. // Reset the send compression dictionaries
  607. //
  608. {
  609. UINT i;
  610. ASSERT(m_pasLocal->adcsDict);
  611. for (i = 0; i < GDC_DICT_COUNT; i++)
  612. {
  613. //
  614. // Somebody has joined or left. We need to start over
  615. // and wipe out any saved data.
  616. //
  617. m_pasLocal->adcsDict[i].cbUsed = 0;
  618. }
  619. }
  620. DebugExitVOID(ASShare::DCS_SyncOutgoing);
  621. }
  622. //
  623. // DCS_NotifyUI()
  624. //
  625. void DCS_NotifyUI
  626. (
  627. UINT eventID,
  628. UINT parm1,
  629. UINT parm2
  630. )
  631. {
  632. DebugEntry(DCS_NotifyUI);
  633. //
  634. // Post event to Front End
  635. //
  636. UT_PostEvent(g_putAS, g_putUI, 0, eventID, parm1, parm2);
  637. DebugExitVOID(DCS_NotifyUI);
  638. }
  639. //
  640. // DCSLocalDesktopSizeChanged
  641. //
  642. // Routine called whenever the desktop size changes.
  643. //
  644. // Updates local desktop size stored in capabilities and informs all other
  645. // machine in a share of the new size
  646. //
  647. void DCSLocalDesktopSizeChanged(UINT width, UINT height)
  648. {
  649. DebugEntry(DCSLocalDesktopSizeChanged);
  650. //
  651. // Check that the desktop has actually changed size
  652. //
  653. if ((g_cpcLocalCaps.screen.capsScreenHeight == height) &&
  654. (g_cpcLocalCaps.screen.capsScreenWidth == width))
  655. {
  656. TRACE_OUT(( "Desktop size has not changed!"));
  657. DC_QUIT;
  658. }
  659. //
  660. // Update the desktop size
  661. //
  662. g_cpcLocalCaps.screen.capsScreenWidth = (TSHR_UINT16)width;
  663. g_cpcLocalCaps.screen.capsScreenHeight = (TSHR_UINT16)height;
  664. if (g_asSession.pShare)
  665. {
  666. g_asSession.pShare->CPC_UpdatedCaps((PPROTCAPS)&g_cpcLocalCaps.screen);
  667. }
  668. DC_EXIT_POINT:
  669. DebugExitVOID(DCSLocalDesktopSizeChanged);
  670. }
  671. //
  672. // Main window message procedure.
  673. //
  674. LRESULT CALLBACK DCSMainWndProc
  675. (
  676. HWND hwnd,
  677. UINT message,
  678. WPARAM wParam,
  679. LPARAM lParam
  680. )
  681. {
  682. LRESULT rc = 0;
  683. DebugEntry(DCSMainWndProc);
  684. switch (message)
  685. {
  686. case DCS_FINISH_INIT_MSG:
  687. {
  688. DCS_FinishInit();
  689. break;
  690. }
  691. case DCS_PERIODIC_SCHEDULE_MSG:
  692. {
  693. if (g_asSession.pShare)
  694. {
  695. //
  696. // Call our periodic processing function if there's at least
  697. // another person in the share with us.
  698. //
  699. g_asSession.pShare->ValidatePerson(g_asSession.pShare->m_pasLocal);
  700. //
  701. // NOTE:
  702. // If we add record/playback capabilities, get rid of this
  703. // or change the check. This prevents us from allocating,
  704. // composing, and sending packets to nowhere when we are
  705. // the only person in the share.
  706. //
  707. if (g_asSession.pShare->m_pasLocal->pasNext || g_asSession.pShare->m_scfViewSelf)
  708. {
  709. g_asSession.pShare->SC_Periodic();
  710. }
  711. }
  712. //
  713. // Notify the Scheduler that we have processed the scheduling
  714. // message, which signals that another one can be sent (only
  715. // one is outstanding at a time).
  716. //
  717. SCH_SchedulingMessageProcessed();
  718. }
  719. break;
  720. case WM_ENDSESSION:
  721. {
  722. //
  723. // The wParam specifies whether the session is about to end.
  724. //
  725. if (wParam && !(g_asOptions & AS_SERVICE))
  726. {
  727. //
  728. // Windows is about to terminate (abruptly!). Call our
  729. // termination functions now - before Windows shuts down
  730. // the hardware device drivers.
  731. //
  732. // We don't leave this job to the WEP because by the time
  733. // it gets called the hardware device drivers have been
  734. // shut down and some of the calls we make then fail (e.g.
  735. // timeEndPeriod requires TIMER.DRV).
  736. //
  737. DCS_Term();
  738. }
  739. }
  740. break;
  741. case WM_CLOSE:
  742. {
  743. ERROR_OUT(("DCS window received WM_CLOSE, this should never happen"));
  744. }
  745. break;
  746. case WM_PALETTECHANGED:
  747. case WM_PALETTEISCHANGING:
  748. {
  749. //
  750. // Win95 patches the Palette DDIs which are more accurate,
  751. // so only key off this message for NT.
  752. //
  753. if (!g_asWin95 && g_asSharedMemory)
  754. {
  755. g_asSharedMemory->pmPaletteChanged = TRUE;
  756. }
  757. }
  758. break;
  759. case WM_DISPLAYCHANGE:
  760. {
  761. //
  762. // The desktop size is changing - we are passed the new size.
  763. //
  764. DCSLocalDesktopSizeChanged(LOWORD(lParam),
  765. HIWORD(lParam));
  766. }
  767. break;
  768. case WM_SETTINGCHANGE:
  769. case WM_USERCHANGED:
  770. if (g_asSession.pShare && g_asSession.pShare->m_pHost)
  771. {
  772. WARNING_OUT(("AS: Reset effects on %s", (message == WM_SETTINGCHANGE)
  773. ? "SETTINGCHANGE" : "USERCHANGE"));
  774. HET_SetGUIEffects(FALSE, &g_asSession.pShare->m_pHost->m_hetEffects);
  775. }
  776. break;
  777. //
  778. // Private app sharing messages
  779. //
  780. case DCS_KILLSHARE_MSG:
  781. SC_EndShare();
  782. break;
  783. case DCS_SHAREDESKTOP_MSG:
  784. DCS_ShareDesktop();
  785. break;
  786. case DCS_UNSHAREDESKTOP_MSG:
  787. DCS_UnshareDesktop();
  788. break;
  789. case DCS_ALLOWCONTROL_MSG:
  790. if (g_asSession.pShare)
  791. {
  792. g_asSession.pShare->CA_AllowControl((BOOL)wParam);
  793. }
  794. break;
  795. case DCS_TAKECONTROL_MSG:
  796. if (g_asSession.pShare)
  797. {
  798. g_asSession.pShare->DCS_TakeControl((UINT)wParam);
  799. }
  800. break;
  801. case DCS_CANCELTAKECONTROL_MSG:
  802. if (g_asSession.pShare)
  803. {
  804. g_asSession.pShare->DCS_CancelTakeControl((UINT)wParam);
  805. }
  806. break;
  807. case DCS_RELEASECONTROL_MSG:
  808. if (g_asSession.pShare)
  809. {
  810. g_asSession.pShare->DCS_ReleaseControl((UINT)wParam);
  811. }
  812. break;
  813. case DCS_PASSCONTROL_MSG:
  814. if (g_asSession.pShare)
  815. {
  816. g_asSession.pShare->DCS_PassControl((UINT)wParam, (UINT)lParam);
  817. }
  818. break;
  819. case DCS_GIVECONTROL_MSG:
  820. if (g_asSession.pShare)
  821. {
  822. g_asSession.pShare->DCS_GiveControl((UINT)wParam);
  823. }
  824. break;
  825. case DCS_CANCELGIVECONTROL_MSG:
  826. if (g_asSession.pShare)
  827. {
  828. g_asSession.pShare->DCS_CancelGiveControl((UINT)wParam);
  829. }
  830. break;
  831. case DCS_REVOKECONTROL_MSG:
  832. if (g_asSession.pShare)
  833. {
  834. g_asSession.pShare->DCS_RevokeControl((UINT)wParam);
  835. }
  836. break;
  837. default:
  838. rc = DefWindowProc(hwnd, message, wParam, lParam);
  839. break;
  840. }
  841. DebugExitDWORD(DCSMainWndProc, rc);
  842. return(rc);
  843. }
  844. //
  845. // DCS_ShareDesktop()
  846. //
  847. void DCS_ShareDesktop(void)
  848. {
  849. DWORD dwAppID;
  850. DebugEntry(DCS_ShareDesktop);
  851. if (!g_asSession.pShare)
  852. {
  853. //
  854. // Create one.
  855. //
  856. if (!SC_CreateShare(S20_CREATE))
  857. {
  858. WARNING_OUT(("Failing share request; in wrong state"));
  859. DC_QUIT;
  860. }
  861. }
  862. ASSERT(g_asSession.pShare);
  863. g_asSession.pShare->HET_ShareDesktop();
  864. DC_EXIT_POINT:
  865. DebugExitVOID(DCS_Share);
  866. }
  867. //
  868. // DCS_UnshareDesktop()
  869. //
  870. void DCS_UnshareDesktop(void)
  871. {
  872. DebugEntry(DCS_UnshareDesktop);
  873. if (!g_asSession.pShare || !g_asSession.pShare->m_pHost)
  874. {
  875. WARNING_OUT(("Failing unshare, nothing is shared by us"));
  876. DC_QUIT;
  877. }
  878. g_asSession.pShare->HET_UnshareAll();
  879. DC_EXIT_POINT:
  880. DebugExitVOID(DCS_Unshare);
  881. }
  882. //
  883. // DCSGetPerson()
  884. //
  885. // Validates GCC ID passed in, returns non-null ASPerson * if all is cool.
  886. //
  887. ASPerson * ASShare::DCSGetPerson(UINT gccID, BOOL fNull)
  888. {
  889. ASPerson * pasPerson = NULL;
  890. //
  891. // Special value?
  892. //
  893. if (!gccID)
  894. {
  895. if (fNull)
  896. {
  897. pasPerson = m_pasLocal->m_caInControlOf;
  898. }
  899. }
  900. else
  901. {
  902. pasPerson = SC_PersonFromGccID(gccID);
  903. }
  904. if (!pasPerson)
  905. {
  906. WARNING_OUT(("Person [%d] not in share", gccID));
  907. }
  908. else if (pasPerson == m_pasLocal)
  909. {
  910. ERROR_OUT(("Local person [%d] was passed in", gccID));
  911. pasPerson = NULL;
  912. }
  913. return(pasPerson);
  914. }
  915. //
  916. // DCS_TakeControl()
  917. //
  918. void ASShare::DCS_TakeControl(UINT gccOf)
  919. {
  920. ASPerson * pasHost;
  921. DebugEntry(ASShare::DCS_TakeControl);
  922. pasHost = DCSGetPerson(gccOf, FALSE);
  923. if (!pasHost)
  924. {
  925. WARNING_OUT(("DCS_TakeControl: ignoring, host [%d] not valid", gccOf));
  926. DC_QUIT;
  927. }
  928. CA_TakeControl(pasHost);
  929. DC_EXIT_POINT:
  930. DebugExitVOID(ASShare::DCS_TakeControl);
  931. }
  932. //
  933. // DCS_CancelTakeControl()
  934. //
  935. void ASShare::DCS_CancelTakeControl(UINT gccOf)
  936. {
  937. ASPerson * pasHost;
  938. DebugEntry(ASShare::DCS_CancelTakeControl);
  939. if (!gccOf)
  940. {
  941. pasHost = m_caWaitingForReplyFrom;
  942. }
  943. else
  944. {
  945. pasHost = DCSGetPerson(gccOf, FALSE);
  946. }
  947. if (!pasHost)
  948. {
  949. WARNING_OUT(("DCS_CancelTakeControl: Ignoring, host [%d] not valid", gccOf));
  950. DC_QUIT;
  951. }
  952. CA_CancelTakeControl(pasHost, TRUE);
  953. DC_EXIT_POINT:
  954. DebugExitVOID(ASShare::DCS_CancelTakeControl);
  955. }
  956. //
  957. // DCS_ReleaseControl()
  958. //
  959. void ASShare::DCS_ReleaseControl(UINT gccOf)
  960. {
  961. ASPerson * pasHost;
  962. DebugEntry(ASShare::DCS_ReleaseControl);
  963. //
  964. // Validate host
  965. //
  966. pasHost = DCSGetPerson(gccOf, TRUE);
  967. if (!pasHost)
  968. {
  969. WARNING_OUT(("DCS_ReleaseControl: ignoring, host [%d] not valid", gccOf));
  970. DC_QUIT;
  971. }
  972. CA_ReleaseControl(pasHost, TRUE);
  973. DC_EXIT_POINT:
  974. DebugExitVOID(ASShare::DCS_ReleaseControl);
  975. }
  976. //
  977. // DCS_PassControl()
  978. //
  979. void ASShare::DCS_PassControl(UINT gccOf, UINT gccTo)
  980. {
  981. ASPerson * pasHost;
  982. ASPerson * pasControllerNew;
  983. DebugEntry(ASShare::DCS_PassControl);
  984. //
  985. // Validate host
  986. //
  987. pasHost = DCSGetPerson(gccOf, TRUE);
  988. if (!pasHost)
  989. {
  990. WARNING_OUT(("DCS_PassControl: ignoring, host [%d] not valid", gccTo));
  991. DC_QUIT;
  992. }
  993. //
  994. // Validate new controller
  995. //
  996. pasControllerNew = DCSGetPerson(gccTo, FALSE);
  997. if (!pasControllerNew)
  998. {
  999. WARNING_OUT(("DCS_PassControl: ignoring, viewer [%d] not valid", gccTo));
  1000. DC_QUIT;
  1001. }
  1002. if (pasControllerNew == pasHost)
  1003. {
  1004. ERROR_OUT(("DCS_PassControl: ignoring, pass of == pass to [%d]", pasControllerNew->mcsID));
  1005. DC_QUIT;
  1006. }
  1007. CA_PassControl(pasHost, pasControllerNew);
  1008. DC_EXIT_POINT:
  1009. DebugExitVOID(ASShare::DCS_PassControl);
  1010. }
  1011. //
  1012. // DCS_GiveControl()
  1013. //
  1014. void ASShare::DCS_GiveControl(UINT gccTo)
  1015. {
  1016. ASPerson * pasViewer;
  1017. DebugEntry(ASShare::DCS_GiveControl);
  1018. //
  1019. // Validate viewer
  1020. //
  1021. pasViewer = DCSGetPerson(gccTo, FALSE);
  1022. if (!pasViewer)
  1023. {
  1024. WARNING_OUT(("DCS_GiveControl: ignoring, viewer [%d] not valid", gccTo));
  1025. DC_QUIT;
  1026. }
  1027. CA_GiveControl(pasViewer);
  1028. DC_EXIT_POINT:
  1029. DebugExitVOID(ASShare::DCS_GiveControl);
  1030. }
  1031. //
  1032. // DCS_CancelGiveControl()
  1033. //
  1034. void ASShare::DCS_CancelGiveControl(UINT gccTo)
  1035. {
  1036. ASPerson * pasTo;
  1037. DebugEntry(ASShare::DCS_CancelGiveControl);
  1038. if (!gccTo)
  1039. {
  1040. pasTo = m_caWaitingForReplyFrom;
  1041. }
  1042. else
  1043. {
  1044. pasTo = DCSGetPerson(gccTo, FALSE);
  1045. }
  1046. if (!pasTo)
  1047. {
  1048. WARNING_OUT(("DCS_CancelGiveControl: Ignoring, person [%d] not valid", gccTo));
  1049. DC_QUIT;
  1050. }
  1051. CA_CancelGiveControl(pasTo, TRUE);
  1052. DC_EXIT_POINT:
  1053. DebugExitVOID(ASShare::DCS_CancelGiveControl);
  1054. }
  1055. //
  1056. // DCS_RevokeControl()
  1057. //
  1058. void ASShare::DCS_RevokeControl(UINT gccController)
  1059. {
  1060. ASPerson * pasController;
  1061. DebugEntry(ASShare::DCS_RevokeControl);
  1062. if (!gccController)
  1063. {
  1064. // Special value: match whomever is controlling us
  1065. pasController = m_pasLocal->m_caControlledBy;
  1066. }
  1067. else
  1068. {
  1069. pasController = DCSGetPerson(gccController, FALSE);
  1070. }
  1071. if (!pasController)
  1072. {
  1073. WARNING_OUT(("DCS_RevokeControl: ignoring, controller [%d] not valid", gccController));
  1074. DC_QUIT;
  1075. }
  1076. CA_RevokeControl(pasController, TRUE);
  1077. DC_EXIT_POINT:
  1078. DebugExitVOID(ASShare::DCS_RevokeControl);
  1079. }
  1080. //
  1081. // SHP_ShareDesktop
  1082. //
  1083. BOOL SHP_ShareDesktop(void)
  1084. {
  1085. BOOL rc = FALSE;
  1086. DebugEntry(SHP_ShareDesktop);
  1087. if (g_asCanHost)
  1088. {
  1089. rc = PostMessage(g_asMainWindow, DCS_SHAREDESKTOP_MSG, 0, 0);
  1090. }
  1091. else
  1092. {
  1093. ERROR_OUT(("SHP_ShareDesktop: not able to share"));
  1094. }
  1095. DebugExitBOOL(SHP_ShareDesktop, rc);
  1096. return(rc);
  1097. }
  1098. //
  1099. // SHP_UnshareDesktop()
  1100. //
  1101. // For unsharing, we use a window. The window has all the information
  1102. // we need to stop sharing already set in its host prop.
  1103. //
  1104. HRESULT SHP_UnshareDesktop(void)
  1105. {
  1106. HRESULT hr = E_FAIL;
  1107. DebugEntry(SHP_UnshareDesktop);
  1108. if (g_asCanHost)
  1109. {
  1110. if (PostMessage(g_asMainWindow, DCS_UNSHAREDESKTOP_MSG, 0, 0))
  1111. {
  1112. hr = S_OK;
  1113. }
  1114. }
  1115. else
  1116. {
  1117. ERROR_OUT(("SHP_Unshare: not able to share"));
  1118. }
  1119. DebugExitHRESULT(SHP_UnshareDesktop, hr);
  1120. return(hr);
  1121. }
  1122. //
  1123. // SHP_TakeControl()
  1124. // Request to take control of a remote host.
  1125. // PersonOf is the GCC id of the remote.
  1126. //
  1127. HRESULT SHP_TakeControl(IAS_GCC_ID PersonOf)
  1128. {
  1129. HRESULT hr = E_FAIL;
  1130. DebugEntry(SHP_TakeControl);
  1131. if (g_asMainWindow &&
  1132. PostMessage(g_asMainWindow, DCS_TAKECONTROL_MSG, PersonOf, 0))
  1133. {
  1134. hr = S_OK;
  1135. }
  1136. DebugExitHRESULT(SHP_TakeControl, hr);
  1137. return(hr);
  1138. }
  1139. //
  1140. // SHP_CancelTakeControl()
  1141. // Cancel request to take control of a remote host.
  1142. // PersonOf is the GCC id of the remote.
  1143. //
  1144. HRESULT SHP_CancelTakeControl(IAS_GCC_ID PersonOf)
  1145. {
  1146. HRESULT hr = E_FAIL;
  1147. DebugEntry(SHP_CancelTakeControl);
  1148. if (g_asMainWindow &&
  1149. PostMessage(g_asMainWindow, DCS_CANCELTAKECONTROL_MSG, PersonOf, 0))
  1150. {
  1151. hr = S_OK;
  1152. }
  1153. DebugExitHRESULT(SHP_CancelTakeControl, hr);
  1154. return(hr);
  1155. }
  1156. //
  1157. // SHP_ReleaseControl()
  1158. // Release control of a remote host.
  1159. // PersonOf is the GCC id of the remote we are currently controlling
  1160. // and wish to stop. Zero means "whomever" we are in control of
  1161. // at the time.
  1162. //
  1163. HRESULT SHP_ReleaseControl(IAS_GCC_ID PersonOf)
  1164. {
  1165. HRESULT hr = E_FAIL;
  1166. DebugEntry(SHP_ReleaseControl);
  1167. if (g_asMainWindow &&
  1168. PostMessage(g_asMainWindow, DCS_RELEASECONTROL_MSG, PersonOf, 0))
  1169. {
  1170. hr = S_OK;
  1171. }
  1172. DebugExitHRESULT(SHP_ReleaseControl, hr);
  1173. return(hr);
  1174. }
  1175. //
  1176. // SHP_PassControl()
  1177. // Pass control of a remote to another prerson.
  1178. // PersonOf is the GCC id of the remote we are currently controlling
  1179. // PersonTo is the GCC id of the remote we wish to pass control to
  1180. //
  1181. HRESULT SHP_PassControl(IAS_GCC_ID PersonOf, IAS_GCC_ID PersonTo)
  1182. {
  1183. HRESULT hr = E_FAIL;
  1184. DebugEntry(SHP_PassControl);
  1185. if (g_asMainWindow &&
  1186. PostMessage(g_asMainWindow, DCS_PASSCONTROL_MSG, PersonOf, PersonTo))
  1187. {
  1188. hr = S_OK;
  1189. }
  1190. DebugExitHRESULT(SHP_PassControl, hr);
  1191. return(hr);
  1192. }
  1193. //
  1194. // SHP_AllowControl()
  1195. // Toggle the ability for remotes to control us (when we are sharing stuff)
  1196. //
  1197. HRESULT SHP_AllowControl(BOOL fAllowed)
  1198. {
  1199. HRESULT hr = E_FAIL;
  1200. DebugEntry(SHP_AllowControl);
  1201. if (!g_asCanHost)
  1202. {
  1203. ERROR_OUT(("SHP_AllowControl failing, can't host"));
  1204. DC_QUIT;
  1205. }
  1206. if (PostMessage(g_asMainWindow, DCS_ALLOWCONTROL_MSG, fAllowed, 0))
  1207. {
  1208. hr = S_OK;
  1209. }
  1210. DC_EXIT_POINT:
  1211. DebugExitHRESULT(SHP_AllowControl, hr);
  1212. return(hr);
  1213. }
  1214. //
  1215. // SHP_GiveControl()
  1216. //
  1217. // Give control of our shared stuff to a remote.
  1218. //
  1219. HRESULT SHP_GiveControl(IAS_GCC_ID PersonTo)
  1220. {
  1221. HRESULT hr = E_FAIL;
  1222. DebugEntry(SHP_GiveControl);
  1223. if (g_asMainWindow &&
  1224. PostMessage(g_asMainWindow, DCS_GIVECONTROL_MSG, PersonTo, 0))
  1225. {
  1226. hr = S_OK;
  1227. }
  1228. DebugExitHRESULT(SHP_GiveControl, hr);
  1229. return(hr);
  1230. }
  1231. //
  1232. // SHP_CancelGiveControl()
  1233. //
  1234. // Cancel giving control of our shared stuff to a remote.
  1235. //
  1236. HRESULT SHP_CancelGiveControl(IAS_GCC_ID PersonTo)
  1237. {
  1238. HRESULT hr = E_FAIL;
  1239. DebugEntry(SHP_CancelGiveControl);
  1240. if (g_asMainWindow &&
  1241. PostMessage(g_asMainWindow, DCS_CANCELGIVECONTROL_MSG, PersonTo, 0))
  1242. {
  1243. hr = S_OK;
  1244. }
  1245. DebugExitHRESULT(SHP_CancelGiveControl, hr);
  1246. return(hr);
  1247. }
  1248. //
  1249. // SHP_RevokeControl()
  1250. // Take control away from a remote who is in control of us.
  1251. //
  1252. // NOTE:
  1253. // SHP_AllowControl(FALSE) will of course revoke control if someone is
  1254. // in control of us at the time.
  1255. //
  1256. HRESULT SHP_RevokeControl(IAS_GCC_ID PersonTo)
  1257. {
  1258. HRESULT hr = E_FAIL;
  1259. DebugEntry(SHP_RevokeControl);
  1260. if (g_asMainWindow &&
  1261. PostMessage(g_asMainWindow, DCS_REVOKECONTROL_MSG, PersonTo, 0))
  1262. {
  1263. hr = S_OK;
  1264. }
  1265. DebugExitHRESULT(SHP_RevokeControl, hr);
  1266. return(hr);
  1267. }
  1268. //
  1269. // SHP_GetPersonStatus()
  1270. //
  1271. HRESULT SHP_GetPersonStatus(IAS_GCC_ID Person, IAS_PERSON_STATUS * pStatus)
  1272. {
  1273. HRESULT hr = E_FAIL;
  1274. UINT cbSize;
  1275. DebugEntry(SHP_GetPersonStatus);
  1276. UT_Lock(UTLOCK_AS);
  1277. if (IsBadWritePtr(pStatus, sizeof(*pStatus)))
  1278. {
  1279. ERROR_OUT(("SHP_GetPersonStatus failing; IAS_PERSON_STATUS pointer is bogus"));
  1280. DC_QUIT;
  1281. }
  1282. //
  1283. // Check that size field is filled in properly
  1284. //
  1285. cbSize = pStatus->cbSize;
  1286. if (cbSize != sizeof(*pStatus))
  1287. {
  1288. ERROR_OUT(("SHP_GetPersonStatus failing; cbSize field not right"));
  1289. DC_QUIT;
  1290. }
  1291. //
  1292. // First, clear the structure
  1293. //
  1294. ::ZeroMemory(pStatus, cbSize);
  1295. pStatus->cbSize = cbSize;
  1296. //
  1297. // Is AS present?
  1298. //
  1299. if (!g_asMainWindow)
  1300. {
  1301. ERROR_OUT(("SHP_GetPersonStatus failing; AS not present"));
  1302. DC_QUIT;
  1303. }
  1304. //
  1305. // Are we in a share?
  1306. //
  1307. if (g_asSession.pShare)
  1308. {
  1309. ASPerson * pasT;
  1310. //
  1311. // Find this person
  1312. //
  1313. if (!Person)
  1314. {
  1315. Person = g_asSession.gccID;
  1316. }
  1317. for (pasT = g_asSession.pShare->m_pasLocal; pasT != NULL; pasT = pasT->pasNext)
  1318. {
  1319. if (pasT->cpcCaps.share.gccID == Person)
  1320. {
  1321. ASPerson * pTemp;
  1322. //
  1323. // Found it
  1324. //
  1325. pStatus->InShare = TRUE;
  1326. switch (pasT->cpcCaps.general.version)
  1327. {
  1328. case CAPS_VERSION_10:
  1329. pStatus->Version = IAS_VERSION_10;
  1330. break;
  1331. default:
  1332. ERROR_OUT(("Unknown version %d", pasT->cpcCaps.general.version));
  1333. break;
  1334. }
  1335. if (pasT->hetCount == HET_DESKTOPSHARED)
  1336. pStatus->AreSharing = IAS_SHARING_DESKTOP;
  1337. else
  1338. pStatus->AreSharing = IAS_SHARING_NOTHING;
  1339. pStatus->Controllable = pasT->m_caAllowControl;
  1340. //
  1341. // We MUST assign to avoid faults.
  1342. //
  1343. pTemp = pasT->m_caInControlOf;
  1344. if (pTemp)
  1345. {
  1346. pStatus->InControlOf = pTemp->cpcCaps.share.gccID;
  1347. }
  1348. else
  1349. {
  1350. pTemp = pasT->m_caControlledBy;
  1351. if (pTemp)
  1352. {
  1353. pStatus->ControlledBy = pTemp->cpcCaps.share.gccID;
  1354. }
  1355. }
  1356. //
  1357. // We MUST assign to avoid faults.
  1358. //
  1359. pTemp = g_asSession.pShare->m_caWaitingForReplyFrom;
  1360. if (pTemp)
  1361. {
  1362. if (pasT == g_asSession.pShare->m_pasLocal)
  1363. {
  1364. //
  1365. // We have an outstanding request to this dude.
  1366. //
  1367. switch (g_asSession.pShare->m_caWaitingForReplyMsg)
  1368. {
  1369. case CA_REPLY_REQUEST_TAKECONTROL:
  1370. pStatus->InControlOfPending = pTemp->cpcCaps.share.gccID;
  1371. break;
  1372. case CA_REPLY_REQUEST_GIVECONTROL:
  1373. pStatus->ControlledByPending = pTemp->cpcCaps.share.gccID;
  1374. break;
  1375. }
  1376. }
  1377. else if (pasT == pTemp)
  1378. {
  1379. //
  1380. // This dude has an outstanding request from us.
  1381. //
  1382. switch (g_asSession.pShare->m_caWaitingForReplyMsg)
  1383. {
  1384. case CA_REPLY_REQUEST_TAKECONTROL:
  1385. pStatus->ControlledByPending = g_asSession.pShare->m_pasLocal->cpcCaps.share.gccID;
  1386. break;
  1387. case CA_REPLY_REQUEST_GIVECONTROL:
  1388. pStatus->InControlOfPending = g_asSession.pShare->m_pasLocal->cpcCaps.share.gccID;
  1389. break;
  1390. }
  1391. }
  1392. }
  1393. break;
  1394. }
  1395. }
  1396. }
  1397. hr = S_OK;
  1398. DC_EXIT_POINT:
  1399. UT_Unlock(UTLOCK_AS);
  1400. DebugExitHRESULT(SHP_GetPersonStatus, hr);
  1401. return(hr);
  1402. }