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.

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