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.

2903 lines
95 KiB

  1. #include "precomp.h"
  2. //
  3. // SWL.CPP
  4. // Shared Window List
  5. //
  6. // Copyright(c) Microsoft 1997-
  7. //
  8. #define MLZ_FILE_ZONE ZONE_CORE
  9. //
  10. // SWL strategy when network packets are not available
  11. //
  12. // The SWL only sends one type of message - the window structure message.
  13. // When no network packets are available the SWL will drop its current
  14. // packet and remember that the window structure has changed since it was
  15. // last able to send a packet. SWL_Periodic will also return FALSE when
  16. // this happens so that the DCS will know not to send any updates if it
  17. // failed to send a window structure.
  18. //
  19. // This pending of window structure messages is integrated with the
  20. // ignore envelopes where the SWL wants to ignore changes caused by itself
  21. // (or other components if they call the SWL_Begin/EndIgnoreWindowChanges
  22. // functions).
  23. //
  24. //
  25. // SWL strategy for backward compatibility.
  26. //
  27. // The differences between the R2.0 and 3.0 SWL protocol are:
  28. // 1. Tokenless packets.
  29. // 2. No shadows.
  30. //
  31. //
  32. // SWL_PartyLeftShare()
  33. //
  34. void ASShare::SWL_PartyLeftShare(ASPerson * pasPerson)
  35. {
  36. DebugEntry(ASShare::SWL_PartyLeftShare);
  37. ValidatePerson(pasPerson);
  38. //
  39. // 2.x nodes will fake up a packet for a remote leaving with an empty
  40. // window list. That's how they'd nuke shadows for that person, if he
  41. // had been hosting. In so doing, they'd use a new token. We need to
  42. // bump our token value up also so that the next window list we send
  43. // is not dropped.
  44. //
  45. m_swlLastTokenSeen = SWL_CalculateNextToken(m_swlLastTokenSeen);
  46. TRACE_OUT(("SWL_PartyLeftShare: bumped up token to 0x%08x", m_swlLastTokenSeen));
  47. DebugExitVOID(ASShare::SWL_PartyLeftShare);
  48. }
  49. //
  50. // SWL_SyncOutgoing
  51. //
  52. void ASHost::SWL_SyncOutgoing(void)
  53. {
  54. DebugEntry(ASHost::SWL_SyncOutgoing);
  55. //
  56. // Ensure that we send an SWL packet next time we need.
  57. //
  58. m_swlfForceSend = TRUE;
  59. m_swlfSyncing = TRUE;
  60. DebugExitVOID(ASHost::SWL_SyncOutgoing);
  61. }
  62. //
  63. // SWL_HostStarting()
  64. //
  65. BOOL ASHost::SWL_HostStarting(void)
  66. {
  67. BOOL rc = FALSE;
  68. DebugEntry(ASHost::SWL_HostStarting);
  69. //
  70. // Get an atom to use in getting and setting window properties (which
  71. // will give us SWL information about the window).
  72. //
  73. m_swlPropAtom = GlobalAddAtom(SWL_ATOM_NAME);
  74. if (!m_swlPropAtom)
  75. {
  76. ERROR_OUT(( "GlobalAddAtom error %#x", GetLastError()));
  77. DC_QUIT;
  78. }
  79. //
  80. // If this is NT, get the name of our startup desktop
  81. //
  82. if (!g_asWin95)
  83. {
  84. ASSERT(m_aswlOurDesktopName[0] == 0);
  85. GetUserObjectInformation(GetThreadDesktop(g_asMainThreadId),
  86. UOI_NAME, m_aswlOurDesktopName,
  87. sizeof(m_aswlOurDesktopName), NULL);
  88. TRACE_OUT(("Our desktop name is %s", m_aswlOurDesktopName));
  89. }
  90. if (!m_aswlOurDesktopName[0])
  91. {
  92. // Use default name
  93. TRACE_OUT(("Couldn't get desktop name; using %s",
  94. NAME_DESKTOP_DEFAULT));
  95. lstrcpy(m_aswlOurDesktopName, NAME_DESKTOP_DEFAULT);
  96. }
  97. //
  98. // Allocate memory for the window titles. We fix the maximum size of
  99. // window title we will send - task list doesn't scroll horizontally so
  100. // we truncate window titles at MAX_WINDOW_TITLE_SEND. However, we do
  101. // not pad the titles so we try to send as little data as possible.
  102. // Allocate all the segment but the rest of the code does not rely on
  103. // this so we split them into more segments later if need be. The
  104. // memory pointed to by winNames[0] etc looks like this:
  105. //
  106. // For each entry in the corresponding WinStruct which is a window from
  107. // a shared task (and in the same order):
  108. //
  109. // either -
  110. // (char)0xFF - not a `task window' - give it a NULL title
  111. // or -
  112. // a null terminated string up to MAX_WINDOW_TITLE_SEND characters
  113. //
  114. // Note that we don't need full and compact versions because only
  115. // windows which will be in the compact WinStruct will have
  116. // corresponding entries in this structure.
  117. //
  118. m_aswlWinNames[0] =
  119. new char[2*SWL_MAX_WINDOWS*SWL_MAX_WINDOW_TITLE_SEND];
  120. if (!m_aswlWinNames[0])
  121. {
  122. ERROR_OUT(( "failed to get memory for window title lists"));
  123. DC_QUIT;
  124. }
  125. m_aswlWinNames[1] = m_aswlWinNames[0] +
  126. SWL_MAX_WINDOWS*SWL_MAX_WINDOW_TITLE_SEND;
  127. ASSERT(m_swlCurIndex == 0);
  128. rc = TRUE;
  129. DC_EXIT_POINT:
  130. DebugExitBOOL(ASHost::SWL_HostStarting, rc);
  131. return(rc);
  132. }
  133. //
  134. // SWL_HostEnded()
  135. //
  136. void ASHost::SWL_HostEnded(void)
  137. {
  138. DebugEntry(ASHost::SWL_HostEnded);
  139. //
  140. // For 2.x nodes, we must send out one last packet so they kill
  141. // their shadows.
  142. //
  143. //
  144. // Remove the SWL properties for all existing windows.
  145. //
  146. EnumWindows(SWLDestroyWindowProperty, 0);
  147. m_swlfSyncing = FALSE;
  148. if (m_pShare->m_scShareVersion < CAPS_VERSION_30)
  149. {
  150. //
  151. // SWL_Periodic() should NOT put properties on windows
  152. // when we're not hosting anymore.
  153. //
  154. ASSERT(m_pShare->m_pasLocal->hetCount == 0);
  155. TRACE_OUT(("SWL_HostEnded: Must send an empty window list for 2.x nodes"));
  156. m_swlfForceSend = TRUE;
  157. SWL_Periodic();
  158. }
  159. if (m_aswlNRInfo[0])
  160. {
  161. delete[] m_aswlNRInfo[0];
  162. m_aswlNRInfo[0] = NULL;
  163. }
  164. if (m_aswlNRInfo[1])
  165. {
  166. delete[] m_aswlNRInfo[1];
  167. m_aswlNRInfo[1] = NULL;
  168. }
  169. if (m_aswlWinNames[0])
  170. {
  171. delete[] m_aswlWinNames[0];
  172. m_aswlWinNames[0] = NULL;
  173. }
  174. if (m_swlPropAtom)
  175. {
  176. GlobalDeleteAtom(m_swlPropAtom);
  177. m_swlPropAtom = 0;
  178. }
  179. DebugExitVOID(ASHost::SWL_HostEnded);
  180. }
  181. //
  182. // FUNCTION: SWL_GetSharedIDFromLocalID
  183. //
  184. // DESCRIPTION:
  185. //
  186. // Given a window ID from a shared application which is running locally
  187. // this will return the top level parent. If this parent is invisible,
  188. // we return NULL.
  189. //
  190. // the parent window nearest the desktop. If this parent window is
  191. // invisible NULL is returned.
  192. //
  193. // PARAMETERS:
  194. //
  195. // window - the window in question
  196. //
  197. // RETURNS:
  198. //
  199. // a HWND or NULL if the window is not from a shared application
  200. //
  201. //
  202. HWND ASHost::SWL_GetSharedIDFromLocalID(HWND window)
  203. {
  204. HWND hwnd;
  205. HWND hwndParent;
  206. HWND hwndDesktop;
  207. DebugEntry(ASHost::SWL_GetSharedIDFromLocalID);
  208. hwnd = window;
  209. if (!hwnd)
  210. {
  211. DC_QUIT;
  212. }
  213. hwndDesktop = GetDesktopWindow();
  214. //
  215. // Get the real top level ancestor
  216. //
  217. while (GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD)
  218. {
  219. hwndParent = GetParent(hwnd);
  220. if (hwndParent == hwndDesktop)
  221. break;
  222. hwnd = hwndParent;
  223. }
  224. //
  225. // Is this a hosted guy?
  226. //
  227. if (m_pShare->HET_WindowIsHosted(hwnd))
  228. {
  229. if (!(GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE))
  230. {
  231. //
  232. // This window does not have the visible style. But it may just
  233. // be transiently invisible and SWL is still treating it as
  234. // visible. RAID3074 requires that a window which is not yet
  235. // believed to be invisible by SWL is treated as visible (since
  236. // the remote has not been informed that it is invisible). We
  237. // can determine whether SWL is traeting this window as visible
  238. // by looking at the SWL window property. If no property exists
  239. // then the window is new so the remote cannot know about it
  240. // and we can assume it is indeed invisible.
  241. //
  242. if (! ((UINT_PTR)GetProp(hwnd, MAKEINTATOM(m_swlPropAtom)) & SWL_PROP_COUNTDOWN_MASK))
  243. {
  244. //
  245. // SWL knows that the parent of a shared application is
  246. // invisible so we just return NULL.
  247. //
  248. hwnd = NULL;
  249. }
  250. }
  251. }
  252. else
  253. {
  254. hwnd = NULL;
  255. }
  256. DC_EXIT_POINT:
  257. DebugExitDWORD(ASHost::SWL_GetSharedIDFromLocalID, HandleToUlong(hwnd));
  258. return(hwnd);
  259. }
  260. //
  261. // SWL_UpdateCurrentDesktop()
  262. //
  263. // This checks what the current desktop is, and if it's changed, updates
  264. // the NT input hooks for winlogon/screensaver for the service. But normal
  265. // SWL and AWC also make use of this info.
  266. //
  267. void ASHost::SWL_UpdateCurrentDesktop(void)
  268. {
  269. HDESK hDeskCurrent = NULL;
  270. UINT newCurrentDesktop;
  271. char szName[SWL_DESKTOPNAME_MAX];
  272. DebugEntry(ASHost::SWL_UpdateCurrentDesktop);
  273. newCurrentDesktop = DESKTOP_OURS;
  274. if (g_asWin95)
  275. {
  276. // Nothing to do
  277. DC_QUIT;
  278. }
  279. //
  280. // Get the current desktop. If we can't even get it, assume it's the
  281. // winlogon desktop.
  282. //
  283. hDeskCurrent = OpenInputDesktop(0, TRUE, DESKTOP_READOBJECTS);
  284. if (!hDeskCurrent)
  285. {
  286. TRACE_OUT(("OpenInputDesktop failed; must be WINLOGON"));
  287. newCurrentDesktop = DESKTOP_WINLOGON;
  288. DC_QUIT;
  289. }
  290. // Get the name of the current desktop
  291. szName[0] = 0;
  292. GetUserObjectInformation(hDeskCurrent, UOI_NAME, szName,
  293. sizeof(szName), NULL);
  294. TRACE_OUT(("GetUserObjectInformation returned %s for name", szName));
  295. if (!lstrcmpi(szName, m_aswlOurDesktopName))
  296. {
  297. newCurrentDesktop = DESKTOP_OURS;
  298. }
  299. else if (!lstrcmpi(szName, NAME_DESKTOP_SCREENSAVER))
  300. {
  301. newCurrentDesktop = DESKTOP_SCREENSAVER;
  302. }
  303. else if (!lstrcmpi(szName, NAME_DESKTOP_WINLOGON))
  304. {
  305. newCurrentDesktop = DESKTOP_WINLOGON;
  306. }
  307. else
  308. {
  309. newCurrentDesktop = DESKTOP_OTHER;
  310. }
  311. DC_EXIT_POINT:
  312. if (newCurrentDesktop != m_swlCurrentDesktop)
  313. {
  314. //
  315. // If this is the service, adjust where we playback events
  316. // and/or block local input.
  317. //
  318. OSI_DesktopSwitch(m_swlCurrentDesktop, newCurrentDesktop);
  319. m_swlCurrentDesktop = newCurrentDesktop;
  320. }
  321. if (hDeskCurrent != NULL)
  322. {
  323. CloseDesktop(hDeskCurrent);
  324. }
  325. DebugExitVOID(ASHost::SWL_UpdateCurrentDesktop);
  326. }
  327. //
  328. // SWL_IsOurDesktopActive()
  329. //
  330. BOOL ASHost::SWL_IsOurDesktopActive(void)
  331. {
  332. return(!g_asSharedMemory->fullScreen && (m_swlCurrentDesktop == DESKTOP_OURS));
  333. }
  334. //
  335. // FUNCTION: SWLInitHostFullWinListEntry
  336. //
  337. // DESCRIPTION:
  338. //
  339. // Initializes a hosted window entry in the full window list.
  340. //
  341. // PARAMETERS: hwnd - Window ID of the hosted window
  342. // windowProp - SWL window properties for hwnd
  343. // ownerID - Window ID of hwnd's owner
  344. // pFullWinEntry - pointer to the list entry to initialize
  345. //
  346. // RETURNS: Nothing
  347. //
  348. //
  349. void ASHost::SWLInitHostFullWinListEntry
  350. (
  351. HWND hwnd,
  352. UINT windowProp,
  353. HWND hwndOwner,
  354. PSWLWINATTRIBUTES pFullWinEntry
  355. )
  356. {
  357. DebugEntry(ASHost::SWLInitHostFullWinListEntry);
  358. //
  359. // The window is a shared application hosted locally.
  360. // These get the application id, the local window id and the owner
  361. // window id.
  362. //
  363. // Note that the real owner of the window may be a child of a shared
  364. // window, and therefore not known to the remote machine. We therefore
  365. // pass the real owner to SWL_GetSharedIDFromLocalID() which will
  366. // traverse up the owner's window tree until it finds a window that is
  367. // shared and store the returned window handle in the window structure.
  368. //
  369. pFullWinEntry->flags = SWL_FLAG_WINDOW_HOSTED;
  370. pFullWinEntry->winID = HandleToUlong(hwnd);
  371. pFullWinEntry->extra = GetWindowThreadProcessId(hwnd, NULL);
  372. // NOTE: ownerWinID is ignored by NM 3.0 and up.
  373. pFullWinEntry->ownerWinID = HandleToUlong(SWL_GetSharedIDFromLocalID(hwndOwner));
  374. //
  375. // Check if the window is minimized.
  376. //
  377. if (IsIconic(hwnd))
  378. {
  379. pFullWinEntry->flags |= SWL_FLAG_WINDOW_MINIMIZED;
  380. }
  381. //
  382. // TAGGABLE is for 2.x nodes only; 3.0 and up don't look at this.
  383. //
  384. if (windowProp & SWL_PROP_TAGGABLE)
  385. {
  386. pFullWinEntry->flags |= SWL_FLAG_WINDOW_TAGGABLE;
  387. }
  388. if (windowProp & SWL_PROP_TRANSPARENT)
  389. {
  390. //
  391. // The window is transparent and (to have got this far) must be
  392. // shared or the desktop is shared, ie we will be sending the
  393. // window but need to fiddle the z-order. Flag the transparency so
  394. // we can do the z-order later.
  395. //
  396. pFullWinEntry->flags |= SWL_FLAG_WINDOW_TRANSPARENT;
  397. }
  398. else if (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST)
  399. {
  400. //
  401. // The window is not transparent and is topmost, so set the topmost
  402. // flag.
  403. //
  404. pFullWinEntry->flags |= SWL_FLAG_WINDOW_TOPMOST;
  405. }
  406. //
  407. // If this window is on the task bar then pass this info on
  408. //
  409. if (windowProp & SWL_PROP_TASKBAR)
  410. {
  411. pFullWinEntry->flags |= SWL_FLAG_WINDOW_TASKBAR;
  412. }
  413. else
  414. {
  415. pFullWinEntry->flags |= SWL_FLAG_WINDOW_NOTASKBAR;
  416. }
  417. DebugExitVOID(ASHost::SWLInitHostFullWinListEntry);
  418. }
  419. //
  420. // FUNCTION: SWLAddHostWindowTitle
  421. //
  422. // DESCRIPTION:
  423. //
  424. // Adds a hosted window title (or blank entry) to our window titles list.
  425. //
  426. // PARAMETERS: winid - Window ID of the hosted window
  427. // windowProp - SWL window properties for winid
  428. // ownerID - Window ID of winid's owner
  429. // ppWinNames - pointer to pointer to window names structure
  430. //
  431. // RETURNS: Nothing
  432. //
  433. //
  434. void ASHost::SWLAddHostWindowTitle
  435. (
  436. HWND hwnd,
  437. UINT windowProp,
  438. HWND hwndOwner,
  439. LPSTR *ppWinNames
  440. )
  441. {
  442. int lenTitle;
  443. DebugEntry(ASHost::SWLAddHostWindowTitle);
  444. //
  445. // This window gets an entry in our window titles data if it passes the
  446. // following tests
  447. //
  448. // for Windows: it has no owner, or its owner is invisible
  449. //
  450. //
  451. if ( (windowProp & SWL_PROP_TASKBAR) ||
  452. hwndOwner == NULL ||
  453. !IsWindowVisible(hwndOwner) )
  454. {
  455. //
  456. // LAURABU 2.x COMPAT:
  457. // 3.0 nodes only look at the text if TASKBAR is set. When 2.x
  458. // compat is gone, don't send text in the other cases.
  459. //
  460. //
  461. // Get the title - truncated and null terminated for us. First
  462. // look for the desktop, which may have a special, configurable
  463. // name.
  464. //
  465. lenTitle = GetWindowText(hwnd, *ppWinNames, SWL_MAX_WINDOW_TITLE_SEND);
  466. //
  467. // Check that the title has been null terminated.
  468. //
  469. (*ppWinNames)[lenTitle] = '\0';
  470. *ppWinNames += lenTitle;
  471. }
  472. else
  473. {
  474. //
  475. // This is not a task window - put a corresponding entry in the
  476. // title info.
  477. //
  478. **ppWinNames = '\xff';
  479. }
  480. *ppWinNames += 1;
  481. DebugExitVOID(ASHost::SWLAddHostWindowTitle);
  482. }
  483. //
  484. // FUNCTION: SWL_InitFullWindowListEntry
  485. //
  486. // DESCRIPTION:
  487. //
  488. // Initialises an entry in the full window list.
  489. //
  490. // PARAMETERS: hwnd - Window ID of the window for which an entry is
  491. // initialized
  492. // windowProp - SWL window properties for hwnd
  493. // ownerID - Window ID of hwnd's owner
  494. // pFullWinEntry - pointer to the list entry to initialize
  495. //
  496. // RETURNS: Nothing
  497. //
  498. //
  499. void ASHost::SWL_InitFullWindowListEntry
  500. (
  501. HWND hwnd,
  502. UINT windowProp,
  503. LPSTR * ppWinNames,
  504. PSWLWINATTRIBUTES pFullWinEntry
  505. )
  506. {
  507. HWND hwndOwner;
  508. RECT rect;
  509. DebugEntry(ASHost::SWL_InitFullWindowListEntry);
  510. if (windowProp & SWL_PROP_HOSTED)
  511. {
  512. //
  513. // The window is a shared application hosted locally.
  514. // Set up an entry in our full window structure.
  515. //
  516. hwndOwner = GetWindow(hwnd, GW_OWNER);
  517. SWLInitHostFullWinListEntry(hwnd,
  518. windowProp,
  519. hwndOwner,
  520. pFullWinEntry);
  521. SWLAddHostWindowTitle(hwnd, windowProp, hwndOwner, ppWinNames);
  522. }
  523. else
  524. {
  525. //
  526. // The window is a local (non-shared) application
  527. //
  528. pFullWinEntry->flags = SWL_FLAG_WINDOW_LOCAL;
  529. //
  530. // We set the winID here because we may need this info
  531. // again later, but we will NULL it out before we send the
  532. // protocol packet out because it is not info that the
  533. // remote needs
  534. //
  535. pFullWinEntry->winID = HandleToUlong(hwnd);
  536. pFullWinEntry->extra = MCSID_NULL;
  537. pFullWinEntry->ownerWinID = 0;
  538. }
  539. //
  540. // Get the position and size of the window, in inclusive
  541. // Virtual Desktop coordinates.
  542. //
  543. GetWindowRect(hwnd, &rect);
  544. //
  545. // TAGGABLE is for 2.x nodes only
  546. //
  547. if (IsRectEmpty(&rect))
  548. {
  549. pFullWinEntry->flags &= ~SWL_FLAG_WINDOW_TAGGABLE;
  550. }
  551. else
  552. {
  553. if (windowProp & SWL_PROP_TAGGABLE)
  554. {
  555. if (!SWLWindowIsTaggable(hwnd))
  556. pFullWinEntry->flags &= ~SWL_FLAG_WINDOW_TAGGABLE;
  557. }
  558. }
  559. //
  560. // Make the rectangle inclusive.
  561. //
  562. rect.right -= 1;
  563. rect.bottom -= 1;
  564. TSHR_RECT16_FROM_RECT(&(pFullWinEntry->position), rect);
  565. DebugExitVOID(ASHost::SWL_InitFullWindowListEntry);
  566. }
  567. //
  568. // FUNCTION: SWLCompactWindowList
  569. //
  570. // DESCRIPTION:
  571. //
  572. // Compacts the full window list into one containng only those windows SWL
  573. // needs to send (hosts and any locals overlapping hosts)
  574. //
  575. // PARAMETERS: numFullListEntries - number of entries in the full window
  576. // list.
  577. // pFullWinList - pointer to the full window list
  578. // pCompactWinList - pointer to the compact window list
  579. //
  580. // RETURNS: Number of entries copied to the compact window list
  581. //
  582. //
  583. UINT ASHost::SWLCompactWindowList
  584. (
  585. UINT numFullListEntries,
  586. PSWLWINATTRIBUTES pFullWinList,
  587. PSWLWINATTRIBUTES pCompactWinList
  588. )
  589. {
  590. UINT fullIndex;
  591. UINT compactIndex = 0;
  592. UINT i;
  593. DebugEntry(ASHost::SWLCompactWindowList);
  594. //
  595. // For each window in the full list...
  596. //
  597. for ( fullIndex = 0; fullIndex < numFullListEntries; fullIndex++ )
  598. {
  599. if (pFullWinList[fullIndex].flags & SWL_FLAG_WINDOW_LOCAL)
  600. {
  601. //
  602. // This is a local window so we need to track it only if it
  603. // overlaps a hosted window. Run through the remaining windows
  604. // until we either find an overlapped hosted window (meaning we
  605. // must track this local window) or reach the end of the list
  606. // (meaning we don't need to track this local window).
  607. //
  608. for ( i = fullIndex + 1; i < numFullListEntries; i++ )
  609. {
  610. //
  611. // If this window is hosted and intersects the local
  612. // window then we need to track the local window.
  613. //
  614. if ( (pFullWinList[i].flags & SWL_FLAG_WINDOW_HOSTED) &&
  615. (COM_Rect16sIntersect(&pFullWinList[fullIndex].position,
  616. &pFullWinList[i].position)))
  617. {
  618. //
  619. // Copy the local window to the compact array and
  620. // break out the inner loop.
  621. //
  622. TRACE_OUT(("Add local hwnd 0x%08x to list at %u",
  623. pFullWinList[fullIndex].winID, compactIndex));
  624. pCompactWinList[compactIndex++] =
  625. pFullWinList[fullIndex];
  626. break;
  627. }
  628. }
  629. }
  630. else
  631. {
  632. //
  633. // This is a shadow or hosted window so we must track it.
  634. //
  635. TRACE_OUT(("Add shared hwnd 0x%08x to list at %u",
  636. pFullWinList[fullIndex].winID, compactIndex));
  637. pCompactWinList[compactIndex++] = pFullWinList[fullIndex];
  638. }
  639. }
  640. DebugExitDWORD(ASHost::SWLCompactWindowList, compactIndex);
  641. return(compactIndex);
  642. }
  643. //
  644. // FUNCTION: SWLAdjustZOrderForTransparency
  645. //
  646. // DESCRIPTION:
  647. //
  648. // Rearranges the window structure z-order to take account of a transparent
  649. // window (winID). Must not be called if the transparent entry is the last
  650. // in the compact list.
  651. //
  652. // PARAMETERS: pTransparentListEntry - pointer to the transparent entry
  653. // pLastListEntry - pointer to the last compact window list
  654. // entry
  655. // winPosition - position of window in names array
  656. // pWinNames - hosted window names
  657. // sizeWinNames - number of bytes in winNames
  658. //
  659. // RETURNS: Nothing.
  660. //
  661. //
  662. void ASHost::SWLAdjustZOrderForTransparency
  663. (
  664. PSWLWINATTRIBUTES pTransparentListEntry,
  665. PSWLWINATTRIBUTES pLastListEntry,
  666. UINT winPosition,
  667. LPSTR pWinNames,
  668. UINT sizeWinNames
  669. )
  670. {
  671. SWLWINATTRIBUTES winCopyBuffer;
  672. LPSTR pEndNames = &pWinNames[sizeWinNames - 1];
  673. UINT nameLen;
  674. char windowText[TSHR_MAX_PERSON_NAME_LEN + SWL_MAX_WINDOW_TITLE_SEND];
  675. DebugEntry(ASHost::SWLAdjustZOrderForTransparency);
  676. //
  677. // - turn off the transparent flag (it's not part of the protocol)
  678. // - move the window to the end of the structure, ie bottom of the
  679. // z-order (unless the desktop is at the bottom, in which case
  680. // the window becomes next to bottom).
  681. //
  682. TRACE_OUT(("Adjust z-order for transparent hwnd 0x%08x position %u",
  683. pTransparentListEntry->winID,
  684. winPosition));
  685. pTransparentListEntry->flags &= ~SWL_FLAG_WINDOW_TRANSPARENT;
  686. winCopyBuffer = *pTransparentListEntry;
  687. //
  688. // Shuffle the windows after the transparent entry one place toward the
  689. // start of the list.
  690. //
  691. UT_MoveMemory(pTransparentListEntry,
  692. &pTransparentListEntry[1],
  693. (LPBYTE)pLastListEntry - (LPBYTE)pTransparentListEntry);
  694. *pLastListEntry = winCopyBuffer;
  695. //
  696. // Now rearrange the window names in the same way. First, find the name
  697. // for this window.
  698. //
  699. ASSERT((sizeWinNames != 0));
  700. for ( ;winPosition != 0; winPosition-- )
  701. {
  702. if ( *pWinNames == '\xff' )
  703. {
  704. //
  705. // No name exists for this window, so just advance past the
  706. // 0xff placeholder.
  707. //
  708. TRACE_OUT(("No name for %u", winPosition-1));
  709. pWinNames++;
  710. }
  711. else
  712. {
  713. //
  714. // A name exists for this window, so skip past all the
  715. // characters, including the NULL terminator.
  716. //
  717. TRACE_OUT(( "Ignore %s", pWinNames));
  718. while ( *pWinNames != '\0' )
  719. {
  720. pWinNames++;
  721. }
  722. }
  723. }
  724. //
  725. // winNames now points to the start of the name for the window being
  726. // reordered.
  727. //
  728. if ( *pWinNames == '\xff' )
  729. {
  730. //
  731. // This window has no name and simply has an 0xff placeholder in
  732. // the name list. Move all the remaining names down by one and add
  733. // the 0xff at the end.
  734. //
  735. TRACE_OUT(("Reorder nameless window"));
  736. UT_MoveMemory(pWinNames, pWinNames + 1, pEndNames - pWinNames);
  737. *pEndNames = (char)'\xff';
  738. }
  739. else
  740. {
  741. //
  742. // Move as many bytes as there are characters in the window name
  743. // then tack the name on the end.
  744. //
  745. TRACE_OUT(("Reorder %s", pWinNames));
  746. lstrcpy(windowText, pWinNames);
  747. nameLen = lstrlen(pWinNames);
  748. UT_MoveMemory(pWinNames, pWinNames + nameLen + 1, pEndNames - pWinNames -
  749. nameLen);
  750. lstrcpy(pEndNames - nameLen, windowText);
  751. }
  752. DebugExitVOID(ASHost::SWLAdjustZOrderForTransparency);
  753. }
  754. //
  755. // SWL_Periodic()
  756. //
  757. // DESCRIPTION:
  758. //
  759. // Called periodically. If the window structure has changed (such that it
  760. // impacts remote systems) then send a new one if we can.
  761. //
  762. // PARAMETERS:
  763. //
  764. // fSend - TRUE if the caller really wants us to try to send the new
  765. // structure.
  766. //
  767. // RETURNS: SWL_RC_ERROR : An error occurred
  768. // SWL_RC_SENT : Window structure sent successfully
  769. // SWL_RC_NOT_SENT : No need to send window structure
  770. //
  771. UINT ASHost::SWL_Periodic(void)
  772. {
  773. UINT fRC = SWL_RC_NOT_SENT;
  774. UINT newIndex;
  775. PSWLWINATTRIBUTES newFullWinStruct;
  776. PSWLWINATTRIBUTES curFullWinStruct;
  777. PSWLWINATTRIBUTES newCompactWinStruct;
  778. PSWLWINATTRIBUTES curCompactWinStruct;
  779. UINT i;
  780. UINT k;
  781. BOOL fNoTitlesChanged;
  782. HWND hwnd;
  783. SWLENUMSTRUCT swlEnumStruct;
  784. int complexity;
  785. UINT cNonRectData;
  786. UINT size;
  787. UINT ourSize;
  788. HRGN hrgnNR;
  789. HRGN hrgnRect;
  790. LPRGNDATA pRgnData = NULL;
  791. LPTSHR_INT16 pOurRgnData = NULL;
  792. LPTSHR_INT16 pEndRgnData;
  793. LPTSHR_INT16 pAllocRgnData = NULL;
  794. BOOL fNonRectangularInfoChanged;
  795. BOOL rgnOK;
  796. RECT rectBound;
  797. int left;
  798. int top;
  799. int right;
  800. int bottom;
  801. int lastleft;
  802. int lasttop;
  803. int lastright;
  804. int lastbottom;
  805. int deltaleft;
  806. int deltatop;
  807. int deltaright;
  808. int deltabottom;
  809. int lastdeltaleft;
  810. int lastdeltatop;
  811. int lastdeltaright;
  812. int lastdeltabottom;
  813. UINT numCompactWins;
  814. UINT lastTransparency;
  815. UINT winFlags;
  816. UINT iHosted;
  817. DebugEntry(ASSHost::SWL_Periodic);
  818. SWL_UpdateCurrentDesktop();
  819. //
  820. // If this party isn't hosting apps (and isn't faking up an empty
  821. // packet for 2.x nodes), there's nothing to do.
  822. //
  823. if (m_pShare->m_pasLocal->hetCount == HET_DESKTOPSHARED)
  824. {
  825. m_swlfForceSend = FALSE;
  826. fRC = SWL_RC_NOT_SENT;
  827. DC_QUIT;
  828. }
  829. //
  830. // Get the window structure into the "new" array.
  831. //
  832. newIndex = (m_swlCurIndex+1)%2;
  833. curFullWinStruct = &(m_aswlFullWinStructs[m_swlCurIndex * SWL_MAX_WINDOWS]);
  834. newFullWinStruct = &(m_aswlFullWinStructs[newIndex * SWL_MAX_WINDOWS]);
  835. //
  836. // Free any previously allocated data.
  837. //
  838. if (m_aswlNRInfo[newIndex])
  839. {
  840. delete[] m_aswlNRInfo[newIndex];
  841. m_aswlNRInfo[newIndex] = NULL;
  842. }
  843. m_aswlNRSize[newIndex] = 0;
  844. //
  845. // Start from the first child of the desktop - should be the top
  846. // top-level window
  847. //
  848. ZeroMemory(&swlEnumStruct, sizeof(swlEnumStruct));
  849. swlEnumStruct.pHost = this;
  850. swlEnumStruct.newWinNames = m_aswlWinNames[newIndex];
  851. swlEnumStruct.newFullWinStruct = newFullWinStruct;
  852. //
  853. // Before we consider the windows on the windows desktop we check for
  854. // an active full-screen session. If there is one then we insert a
  855. // local window the size of the physical screen first so that all
  856. // applications which are hosted on this system will become obscured
  857. // on the remote system.
  858. //
  859. ASSERT(swlEnumStruct.count == 0);
  860. if (!SWL_IsOurDesktopActive())
  861. {
  862. newFullWinStruct[0].flags = SWL_FLAG_WINDOW_LOCAL;
  863. newFullWinStruct[0].winID = 0;
  864. newFullWinStruct[0].extra = MCSID_NULL;
  865. newFullWinStruct[0].ownerWinID = 0;
  866. newFullWinStruct[0].position.left = 0;
  867. newFullWinStruct[0].position.top = 0;
  868. newFullWinStruct[0].position.right = (TSHR_UINT16)(m_pShare->m_pasLocal->cpcCaps.screen.capsScreenWidth-1);
  869. newFullWinStruct[0].position.bottom = (TSHR_UINT16)(m_pShare->m_pasLocal->cpcCaps.screen.capsScreenHeight-1);
  870. swlEnumStruct.count++;
  871. }
  872. EnumWindows(SWLEnumProc, (LPARAM)&swlEnumStruct);
  873. //
  874. // Check if we should bail out because of visibility detection
  875. //
  876. if (swlEnumStruct.fBailOut)
  877. {
  878. TRACE_OUT(("SWL_MaybeSendWindowList: bailing out due to visibility detection"));
  879. fRC = SWL_RC_ERROR;
  880. DC_QUIT;
  881. }
  882. m_aswlWinNamesSize[newIndex] = (UINT)(swlEnumStruct.newWinNames - m_aswlWinNames[newIndex]);
  883. m_aswlNumFullWins[newIndex] = swlEnumStruct.count;
  884. //
  885. // Check whether we found a transparent window.
  886. //
  887. lastTransparency = swlEnumStruct.count - 1;
  888. k = 0;
  889. iHosted = 0;
  890. while ( (swlEnumStruct.transparentCount > 0) && (k < lastTransparency) )
  891. {
  892. //
  893. // If the transparent flag is set then rearrange the z-order,
  894. // providing the transparent window is not already at the
  895. // bottom of the z-order.
  896. //
  897. if (newFullWinStruct[k].flags & SWL_FLAG_WINDOW_TRANSPARENT)
  898. {
  899. //
  900. // Now continue with the non-rectangular check - but this will
  901. // be on the window "shunted down" from what was the next
  902. // position in newCompactWinStruct, ie same value of i. We will
  903. // see the moved (transparent) window when we reach it
  904. // again at the end of this for-loop (when it will have the
  905. // transparent flag off, so we don't redo this bit).
  906. //
  907. SWLAdjustZOrderForTransparency(
  908. &newFullWinStruct[k],
  909. &newFullWinStruct[lastTransparency],
  910. iHosted,
  911. m_aswlWinNames[newIndex],
  912. m_aswlWinNamesSize[newIndex]);
  913. swlEnumStruct.transparentCount--;
  914. }
  915. else
  916. {
  917. if (newFullWinStruct[k].flags & SWL_FLAG_WINDOW_HOSTED)
  918. {
  919. iHosted++;
  920. }
  921. k++;
  922. }
  923. }
  924. //
  925. // Compare the current and new information - if they are identical then
  926. // we can quit now.
  927. //
  928. fNoTitlesChanged = ((m_aswlWinNamesSize[0] == m_aswlWinNamesSize[1]) &&
  929. (memcmp(m_aswlWinNames[0],
  930. m_aswlWinNames[1],
  931. m_aswlWinNamesSize[0]) == 0));
  932. if ( fNoTitlesChanged &&
  933. !m_swlfRegionalChanges &&
  934. (m_aswlNumFullWins[0] == m_aswlNumFullWins[1]) &&
  935. (memcmp(newFullWinStruct,
  936. curFullWinStruct,
  937. (m_aswlNumFullWins[0] * sizeof(SWLWINATTRIBUTES))) == 0) )
  938. {
  939. //
  940. // We don't need to send a window structure if nothing has changed
  941. // unless there has been a send override.
  942. //
  943. if (m_swlfForceSend)
  944. {
  945. //
  946. // This is a normal call AND there are pending changes.
  947. //
  948. TRACE_OUT(( "NORMAL, pending changes - send"));
  949. if (SWLSendPacket(&(m_aswlCompactWinStructs[m_swlCurIndex * SWL_MAX_WINDOWS]),
  950. m_aswlNumCompactWins[m_swlCurIndex],
  951. m_aswlWinNames[m_swlCurIndex],
  952. m_aswlWinNamesSize[m_swlCurIndex],
  953. m_aswlNRSize[m_swlCurIndex],
  954. m_aswlNRInfo[m_swlCurIndex]) )
  955. {
  956. //
  957. // Successfully sent this so reset the m_swlfForceSend
  958. // flag.
  959. //
  960. m_swlfForceSend = FALSE;
  961. fRC = SWL_RC_SENT;
  962. }
  963. else
  964. {
  965. //
  966. // Failed to send this packet so don't reset
  967. // m_swlfForceSend so that we retry next time and return
  968. // an error.
  969. //
  970. fRC = SWL_RC_ERROR;
  971. }
  972. }
  973. else
  974. {
  975. //
  976. // This is a normal call and we don't have any changes pending
  977. // so don't send anything.
  978. //
  979. TRACE_OUT(( "No changes - SWL not sent"));
  980. }
  981. DC_QUIT;
  982. }
  983. //
  984. // We can reset the flag that alerted us to potential regional window
  985. // changes now that we have gone and actually checked all the windows.
  986. //
  987. m_swlfRegionalChanges = FALSE;
  988. //
  989. // Something in the window structure has changed. Determine which
  990. // windows in the full list are unnecessary (local ones not overlapping
  991. // any hosted ones) and create a compact array of windows we really
  992. // need.
  993. //
  994. curCompactWinStruct = &(m_aswlCompactWinStructs[m_swlCurIndex * SWL_MAX_WINDOWS]);
  995. newCompactWinStruct = &(m_aswlCompactWinStructs[newIndex * SWL_MAX_WINDOWS]);
  996. numCompactWins = SWLCompactWindowList(m_aswlNumFullWins[newIndex],
  997. newFullWinStruct,
  998. newCompactWinStruct);
  999. m_aswlNumCompactWins[newIndex] = numCompactWins;
  1000. //
  1001. // Run through the compact window list to check for regional windows
  1002. //
  1003. cNonRectData = 0;
  1004. hrgnNR = CreateRectRgn(0, 0, 0, 0);
  1005. for (i = 0; i < numCompactWins; i++)
  1006. {
  1007. winFlags = newCompactWinStruct[i].flags;
  1008. hwnd = (HWND)newCompactWinStruct[i].winID;
  1009. //
  1010. // There are some "fake" windows for which we do not provide a
  1011. // winID - these will never be non-rectangular anyway.
  1012. //
  1013. if ( (hwnd != NULL) &&
  1014. (winFlags & (SWL_FLAG_WINDOW_LOCAL | SWL_FLAG_WINDOW_HOSTED)) )
  1015. {
  1016. //
  1017. // If any of the remote systems care, see if this window has a
  1018. // non rectangular region selected into it.
  1019. //
  1020. if (GetWindowRgn(hwnd, hrgnNR) != ERROR)
  1021. {
  1022. TRACE_OUT(("Regional window 0x%08x", hwnd));
  1023. //
  1024. // There is a region selected in.
  1025. //
  1026. // This region is exactly as the application passed it to
  1027. // Windows, and has not yet been clipped to the window
  1028. // rectangle itself.
  1029. // THE COORDS ARE INCLUSIVE, SO WE ADD ONE to BOTTOM-RIGHT
  1030. //
  1031. hrgnRect = CreateRectRgn(0, 0,
  1032. newCompactWinStruct[i].position.right -
  1033. newCompactWinStruct[i].position.left + 1,
  1034. newCompactWinStruct[i].position.bottom -
  1035. newCompactWinStruct[i].position.top + 1);
  1036. complexity = IntersectRgn(hrgnNR, hrgnNR, hrgnRect);
  1037. DeleteRgn(hrgnRect);
  1038. if (complexity == COMPLEXREGION)
  1039. {
  1040. //
  1041. // The intersection is still a non-rectangular region.
  1042. //
  1043. // See how big a buffer we need to get the data for
  1044. // this region.
  1045. //
  1046. size = GetRegionData(hrgnNR,
  1047. 0,
  1048. NULL);
  1049. //
  1050. // The size we are returned is the size of a full
  1051. // RGNDATAHEADER plus the rectangles stored in DWORDS.
  1052. // We can get away with just a WORD as the count of the
  1053. // rectangles, plus using WORDs for each of the
  1054. // coordinates.
  1055. //
  1056. size = (size - sizeof(RGNDATAHEADER)) / 2 + 2;
  1057. // Max UINT16 check
  1058. if ((size <= SWL_MAX_NONRECT_SIZE) &&
  1059. (size + cNonRectData < 65535))
  1060. {
  1061. //
  1062. // We will be able to query this data later, so
  1063. // we can flag this as a non-rectangular window.
  1064. //
  1065. newCompactWinStruct[i].flags
  1066. |= SWL_FLAG_WINDOW_NONRECTANGLE;
  1067. cNonRectData += size;
  1068. TRACE_OUT(("Regional window region is %d bytes", size));
  1069. }
  1070. else
  1071. {
  1072. //
  1073. // This region is far too complex for us, so we
  1074. // pretend it is simple so we just consider its
  1075. // bounding box.
  1076. //
  1077. TRACE_OUT(("Region too big %d - use bounds", size));
  1078. complexity = SIMPLEREGION;
  1079. }
  1080. }
  1081. if (complexity == SIMPLEREGION)
  1082. {
  1083. //
  1084. // The resultant intersection region happens to be a
  1085. // rectangle so we can send this via the standard
  1086. // structure.
  1087. //
  1088. // Apply the virtual desktop adjustment, make it
  1089. // inclusive, and remember we were passed back window
  1090. // relative coords for the region.
  1091. //
  1092. TRACE_OUT(( "rectangular clipped regional window"));
  1093. // Since we are modifying the compact window struct here
  1094. // we need to call this so we don't falsely assume that
  1095. // there are no changes in the window struct based on
  1096. // comparisons of the old and new full window structs
  1097. m_swlfRegionalChanges = TRUE;
  1098. GetRgnBox(hrgnNR, &rectBound);
  1099. newCompactWinStruct[i].position.left = (TSHR_INT16)
  1100. (newCompactWinStruct[i].position.left +
  1101. rectBound.left);
  1102. newCompactWinStruct[i].position.top = (TSHR_INT16)
  1103. (newCompactWinStruct[i].position.top +
  1104. rectBound.top);
  1105. newCompactWinStruct[i].position.right = (TSHR_INT16)
  1106. (newCompactWinStruct[i].position.left +
  1107. rectBound.right - rectBound.left - 1);
  1108. newCompactWinStruct[i].position.bottom = (TSHR_INT16)
  1109. (newCompactWinStruct[i].position.top +
  1110. rectBound.bottom - rectBound.top - 1);
  1111. }
  1112. }
  1113. }
  1114. }
  1115. //
  1116. // Get any non-rectangular areas we need.
  1117. //
  1118. if (cNonRectData)
  1119. {
  1120. //
  1121. // There was some data needed - allocate some memory for it.
  1122. //
  1123. rgnOK = FALSE;
  1124. pAllocRgnData = (LPTSHR_INT16) new BYTE[cNonRectData];
  1125. if (pAllocRgnData)
  1126. {
  1127. pOurRgnData = pAllocRgnData;
  1128. pEndRgnData = (LPTSHR_INT16)((LPBYTE)pAllocRgnData + cNonRectData);
  1129. rgnOK = TRUE;
  1130. //
  1131. // Loop through the windows again, getting the data this time.
  1132. //
  1133. for ( i = 0; i < numCompactWins; i++ )
  1134. {
  1135. if (newCompactWinStruct[i].flags &
  1136. SWL_FLAG_WINDOW_NONRECTANGLE)
  1137. {
  1138. GetWindowRgn((HWND)newCompactWinStruct[i].winID, hrgnNR);
  1139. //
  1140. // Clip the region to the window once again.
  1141. // THE COORDS ARE INCLUSIVE, SO ADD ONE TO BOTTOM-RIGHT
  1142. //
  1143. hrgnRect = CreateRectRgn(0, 0,
  1144. newCompactWinStruct[i].position.right -
  1145. newCompactWinStruct[i].position.left + 1,
  1146. newCompactWinStruct[i].position.bottom -
  1147. newCompactWinStruct[i].position.top + 1);
  1148. IntersectRgn(hrgnNR, hrgnNR, hrgnRect);
  1149. DeleteRgn(hrgnRect);
  1150. //
  1151. // Get the clipped region data.
  1152. //
  1153. // We have already excluded windows above that will
  1154. // return too large a size here, so we know we are only
  1155. // working with reasonable sizes now.
  1156. //
  1157. size = GetRegionData(hrgnNR, 0, NULL);
  1158. //
  1159. // For the moment we allocate memory each time for the
  1160. // region. Perhaps a better idea would be to save the
  1161. // max size from when we previously queried the region
  1162. // sizes, and allocate just that size one outside the
  1163. // loop.
  1164. //
  1165. pRgnData = (LPRGNDATA) new BYTE[size];
  1166. if (pRgnData)
  1167. {
  1168. GetRegionData(hrgnNR, size, pRgnData);
  1169. //
  1170. // There is a possibility that regions will have
  1171. // changed since we calculated the amount of data
  1172. // required. Before updating our structure with
  1173. // this window's region, check
  1174. // - the window hasn't become normal (ie 0 rects)
  1175. // - there is still enough space for the rects.
  1176. //
  1177. //
  1178. // Make sure this window still has regions
  1179. //
  1180. if (pRgnData->rdh.nCount == 0)
  1181. {
  1182. WARNING_OUT(( "No rects for window %#x",
  1183. newCompactWinStruct[i].winID));
  1184. newCompactWinStruct[i].flags &=
  1185. ~SWL_FLAG_WINDOW_NONRECTANGLE;
  1186. delete[] pRgnData;
  1187. //
  1188. // Move on to next window.
  1189. //
  1190. continue;
  1191. }
  1192. //
  1193. // Check we have enough space for the rects:
  1194. // - ourSize is the number of int16s required.
  1195. // - GetRegionData returns the number of
  1196. // rectangles.
  1197. //
  1198. // We need one extra int16 to contain the count of
  1199. // rectangles.
  1200. //
  1201. ourSize = (pRgnData->rdh.nCount * 4) + 1;
  1202. if ((pOurRgnData + ourSize) > pEndRgnData)
  1203. {
  1204. WARNING_OUT(( "Can't fit %d int16s of region data",
  1205. ourSize));
  1206. rgnOK = FALSE;
  1207. delete[] pRgnData;
  1208. //
  1209. // Give up processing regional windows.
  1210. //
  1211. break;
  1212. }
  1213. //
  1214. // Copy the data across to our SWL area in a more
  1215. // compact form.
  1216. //
  1217. // We take care to produce a compressible form
  1218. // because the raw data is essentially
  1219. // uncompressible via sliding window techniques.
  1220. // (Basically boils down to trying hard to make
  1221. // most values 0, or else of small magnitude).
  1222. //
  1223. //
  1224. // First we write the count of the number of
  1225. // rectangles.
  1226. //
  1227. *pOurRgnData++ = LOWORD(pRgnData->rdh.nCount);
  1228. //
  1229. // Now store the encoded rectangles.
  1230. //
  1231. lastleft = 0;
  1232. lasttop = 0;
  1233. lastright = 0;
  1234. lastbottom = 0;
  1235. lastdeltaleft = 0;
  1236. lastdeltatop = 0;
  1237. lastdeltaright = 0;
  1238. lastdeltabottom = 0;
  1239. for ( k = 0; k < (UINT)pRgnData->rdh.nCount; k++ )
  1240. {
  1241. //
  1242. // Extract 16bit quantities from the data we
  1243. // were returned.
  1244. //
  1245. // We also use inclusive coords whereas Windows
  1246. // gives us exclusive coords.
  1247. //
  1248. left = LOWORD(((LPRECT)(pRgnData->
  1249. Buffer))[k].left);
  1250. top = LOWORD(((LPRECT)(pRgnData->
  1251. Buffer))[k].top);
  1252. right = LOWORD(((LPRECT)(pRgnData->
  1253. Buffer))[k].right) - 1;
  1254. bottom = LOWORD(((LPRECT)(pRgnData->
  1255. Buffer))[k].bottom) - 1;
  1256. //
  1257. // The rectangles are ordered top to bottom,
  1258. // left to right, so the deltas are of smaller
  1259. // magnitude than the values themselves.
  1260. //
  1261. deltaleft = left - lastleft;
  1262. deltatop = top - lasttop;
  1263. deltaright = right - lastright;
  1264. deltabottom = bottom - lastbottom;
  1265. //
  1266. // In general, the left and right edges are
  1267. // connected lines, and the rectangles are of
  1268. // equal height so top/bottom are regular.
  1269. //
  1270. // Thus the values form a series which we can
  1271. // exploit to give a more compressible form.
  1272. //
  1273. // We already have the delta in each component,
  1274. // and these values themselves also form a
  1275. // series. For a straight line series all the
  1276. // deltas will be the same, so the "delta in
  1277. // the delta" will be zero. For a curve,
  1278. // although not all the deltas are the same,
  1279. // the "delta in the delta" is probably very
  1280. // small.
  1281. //
  1282. // A set of lots of zeros and small magnitude
  1283. // numbers is very compressible.
  1284. //
  1285. // Thus we store the "delta in the delta" for
  1286. // all components, rather than the values
  1287. // themselves. The receiver can undo all the
  1288. // deltaing to arive back at the original
  1289. // values.
  1290. //
  1291. *pOurRgnData++ =
  1292. (TSHR_UINT16)(deltaleft - lastdeltaleft);
  1293. *pOurRgnData++ =
  1294. (TSHR_UINT16)(deltatop - lastdeltatop);
  1295. *pOurRgnData++ =
  1296. (TSHR_UINT16)(deltaright - lastdeltaright);
  1297. *pOurRgnData++ =
  1298. (TSHR_UINT16)(deltabottom - lastdeltabottom);
  1299. //
  1300. // Update our last values.
  1301. //
  1302. lastleft = left;
  1303. lasttop = top;
  1304. lastright = right;
  1305. lastbottom = bottom;
  1306. lastdeltaleft = deltaleft;
  1307. lastdeltatop = deltatop;
  1308. lastdeltaright = deltaright;
  1309. lastdeltabottom = deltabottom;
  1310. }
  1311. //
  1312. // Free the data now we are finished with it.
  1313. //
  1314. delete[] pRgnData;
  1315. }
  1316. else
  1317. {
  1318. //
  1319. // Failed to get memory for the rectangles, so the
  1320. // best we can do is use the bounding rect
  1321. //
  1322. // Clear the nonrect flag.
  1323. //
  1324. TRACE_OUT(("Failed alloc %d - use bounds", i));
  1325. newCompactWinStruct[i].flags &=
  1326. ~SWL_FLAG_WINDOW_NONRECTANGLE;
  1327. }
  1328. if (newCompactWinStruct[i].flags & SWL_FLAG_WINDOW_LOCAL)
  1329. {
  1330. //
  1331. // The protocol defines that we will send a NULL
  1332. // winID for local windows, so NULL it out, now
  1333. // that we have finished with it.
  1334. //
  1335. newCompactWinStruct[i].winID = 0;
  1336. }
  1337. }
  1338. }
  1339. }
  1340. if (!rgnOK)
  1341. {
  1342. //
  1343. // Something went wrong, one of:
  1344. // - we failed to allocate the memory we need to store the
  1345. // non-rectangular data
  1346. // - we allocated the memory but it turned out not to be large
  1347. // enough.
  1348. //
  1349. // Either way, best to act as if there is no such data for us.
  1350. //
  1351. if (pAllocRgnData == NULL)
  1352. {
  1353. WARNING_OUT(( "Failed to alloc %d for NRInfo", cNonRectData));
  1354. }
  1355. else
  1356. {
  1357. delete[] pAllocRgnData;
  1358. pAllocRgnData = NULL;
  1359. }
  1360. cNonRectData = 0;
  1361. //
  1362. // Clear all the nonrect flags since we will not be sending any
  1363. // data.
  1364. //
  1365. for ( i = 0; i < numCompactWins; i++)
  1366. {
  1367. newCompactWinStruct[i].flags &= ~SWL_FLAG_WINDOW_NONRECTANGLE;
  1368. }
  1369. }
  1370. }
  1371. //
  1372. // Store the NR information
  1373. //
  1374. m_aswlNRSize[newIndex] = cNonRectData;
  1375. m_aswlNRInfo[newIndex] = (LPTSHR_UINT16)pAllocRgnData;
  1376. //
  1377. // We have finished with the region now.
  1378. //
  1379. DeleteRgn(hrgnNR);
  1380. //
  1381. // Did the data we stored change from the last time?
  1382. //
  1383. fNonRectangularInfoChanged = ((m_aswlNRSize[0] != m_aswlNRSize[1]) ||
  1384. (memcmp(m_aswlNRInfo[0], m_aswlNRInfo[1],
  1385. m_aswlNRSize[0])));
  1386. TRACE_OUT(("Non-rectinfo changed %d", fNonRectangularInfoChanged));
  1387. //
  1388. // Check again for no changes - quit if we can.
  1389. //
  1390. if (fNoTitlesChanged &&
  1391. !fNonRectangularInfoChanged &&
  1392. (m_aswlNumCompactWins[0] == m_aswlNumCompactWins[1]) &&
  1393. (!memcmp(newCompactWinStruct,
  1394. curCompactWinStruct,
  1395. (numCompactWins*sizeof(SWLWINATTRIBUTES)))))
  1396. {
  1397. if (!m_swlfForceSend)
  1398. {
  1399. //
  1400. // This is a normal call and we don't have any changes pending
  1401. // so don't send anything.
  1402. //
  1403. TRACE_OUT(("NORMAL no changes, not sent"));
  1404. }
  1405. else
  1406. {
  1407. //
  1408. // This is a normal call AND there are pending changes.
  1409. //
  1410. TRACE_OUT(( "NORMAL pending changes, send"));
  1411. if (SWLSendPacket(&(m_aswlCompactWinStructs[m_swlCurIndex * SWL_MAX_WINDOWS]),
  1412. m_aswlNumCompactWins[m_swlCurIndex],
  1413. m_aswlWinNames[m_swlCurIndex],
  1414. m_aswlWinNamesSize[m_swlCurIndex],
  1415. m_aswlNRSize[m_swlCurIndex],
  1416. m_aswlNRInfo[m_swlCurIndex]) )
  1417. {
  1418. //
  1419. // Succesfully sent this so reset the m_swlfForceSend
  1420. // flag.
  1421. //
  1422. m_swlfForceSend = FALSE;
  1423. fRC = SWL_RC_SENT;
  1424. }
  1425. else
  1426. {
  1427. //
  1428. // Failed to send this packet so don't reset
  1429. // m_swlfForceSend so that we retry next time and return
  1430. // an error.
  1431. //
  1432. fRC = SWL_RC_ERROR;
  1433. }
  1434. }
  1435. //
  1436. // We can exit here with a changed full window structure but an
  1437. // unchanged compact window structure. By updating the current
  1438. // index we avoid having to compact the window structure next time
  1439. // if the full list doesn't change, ie we will exit on the full
  1440. // list comparison. If the compact structure subsequently changes
  1441. // then the full structure must also change, so we will detect this
  1442. // change.
  1443. //
  1444. m_swlCurIndex = newIndex;
  1445. DC_QUIT;
  1446. }
  1447. //
  1448. // Now the window structure has changed so decide what to do.
  1449. //
  1450. m_swlCurIndex = newIndex;
  1451. //
  1452. // The window structure has changed so try to send it.
  1453. //
  1454. if (SWLSendPacket(&(m_aswlCompactWinStructs[m_swlCurIndex * SWL_MAX_WINDOWS]),
  1455. m_aswlNumCompactWins[m_swlCurIndex],
  1456. m_aswlWinNames[m_swlCurIndex],
  1457. m_aswlWinNamesSize[m_swlCurIndex],
  1458. m_aswlNRSize[m_swlCurIndex],
  1459. m_aswlNRInfo[m_swlCurIndex]) )
  1460. {
  1461. //
  1462. // We have succesfully sent changes so reset the m_swlfForceSend
  1463. // flag.
  1464. //
  1465. m_swlfForceSend = FALSE;
  1466. fRC = SWL_RC_SENT;
  1467. }
  1468. else
  1469. {
  1470. //
  1471. // There were changes but we have failed to send them - set the
  1472. // m_swlfForceSend flag and return error.
  1473. // We must tell DCS scheduling that we need a callback BEFORE any
  1474. // more changes are sent out.
  1475. //
  1476. m_swlfForceSend = TRUE;
  1477. fRC = SWL_RC_ERROR;
  1478. }
  1479. DC_EXIT_POINT:
  1480. DebugExitDWORD(ASHost::SWL_Periodic, fRC);
  1481. return(fRC);
  1482. }
  1483. //
  1484. // SWLEnumProc()
  1485. // Callback for top level window enumeration
  1486. //
  1487. BOOL CALLBACK SWLEnumProc(HWND hwnd, LPARAM lParam)
  1488. {
  1489. PSWLENUMSTRUCT pswlEnum = (PSWLENUMSTRUCT)lParam;
  1490. UINT_PTR property;
  1491. UINT windowProp;
  1492. UINT storedWindowProp;
  1493. UINT visibleCount;
  1494. BOOL fVisible;
  1495. BOOL rc = TRUE;
  1496. DebugEntry(SWLEnumProc);
  1497. //
  1498. // FIRST, WE DETERMINE THE PROPERTIES FOR THE WINDOW.
  1499. // Get the SWL properties for this window.
  1500. //
  1501. windowProp = (UINT)pswlEnum->pHost->SWL_GetWindowProperty(hwnd);
  1502. //
  1503. // We'll modify windowProp as we go, so keep a copy of the original
  1504. // value as stored in the window as we may need it later.
  1505. //
  1506. storedWindowProp = windowProp;
  1507. //
  1508. // HET tracks whether a window is hosted. Find out now and add this
  1509. // info to our window properties for convenience.
  1510. //
  1511. if (pswlEnum->pHost->m_pShare->HET_WindowIsHosted(hwnd))
  1512. {
  1513. windowProp |= SWL_PROP_HOSTED;
  1514. }
  1515. //
  1516. // Find out whether this window is transparent.
  1517. // A transparent window overpaints the desktop only, ie it is
  1518. // overpainted by all other windows. In other words, we can
  1519. // forget about it (treat it as invisible) unless a toolbar itself
  1520. // is shared. The MSOffice95
  1521. // hidden toolbar is a topmost transparent window (SFR1083).
  1522. // Add a property flag if transparent.
  1523. //
  1524. if (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TRANSPARENT)
  1525. {
  1526. windowProp |= SWL_PROP_TRANSPARENT;
  1527. }
  1528. //
  1529. // If this window is one that we have identified as generating no
  1530. // remote shadows, then treat it as being invisible.
  1531. //
  1532. fVisible = FALSE;
  1533. if (IsWindowVisible(hwnd) &&
  1534. !(windowProp & SWL_PROP_IGNORE) &&
  1535. (!(windowProp & SWL_PROP_TRANSPARENT) || (windowProp & SWL_PROP_HOSTED)))
  1536. {
  1537. //
  1538. // SFR1083: if the window is transparent but it is hosted,
  1539. // we need to send it. In such a case we drop into here to do
  1540. // the normal visibility processing and will handle
  1541. // z-order issues later.
  1542. //
  1543. // We have been informed that a top level window is visible.
  1544. // Make sure its visible countdown value is reset.
  1545. //
  1546. if ((pswlEnum->pHost->m_pShare->m_pasLocal->hetCount != 0) &&
  1547. ((windowProp & SWL_PROP_COUNTDOWN_MASK) != SWL_BELIEVE_INVISIBLE_COUNT))
  1548. {
  1549. //
  1550. // We were doing an invisibility countdown for this window
  1551. // but it has re-visibilized, so reset the counter.
  1552. //
  1553. TRACE_OUT(( "Reset visible countdown on hwnd 0x%08x", hwnd));
  1554. property = storedWindowProp;
  1555. property &= ~SWL_PROP_COUNTDOWN_MASK;
  1556. property |= SWL_BELIEVE_INVISIBLE_COUNT;
  1557. SetProp(hwnd, SWL_ATOM_NAME, (HANDLE)property);
  1558. }
  1559. //
  1560. // This window is visible
  1561. //
  1562. fVisible = TRUE;
  1563. }
  1564. else
  1565. {
  1566. //
  1567. // LAURABU BOGUS!
  1568. // With NM 3.0, who cares? It's only 2.x systems that will kill
  1569. // then recreate the shadow, causing flicker.
  1570. //
  1571. //
  1572. // We are told that this top level window is invisible.
  1573. // Check whether we're going to believe it.
  1574. // Some applications (ie WordPerfect, Freelance Graphics)
  1575. // upset AS-Shares window structure handling by doing something
  1576. // like this:
  1577. //
  1578. // Make a window invisible
  1579. // Do some processing which would not normally yield
  1580. // Make the window visible again
  1581. //
  1582. // There is a chance that DC-Share will get scheduled whilst
  1583. // the window is invisible (because of our cunning scheduling)
  1584. // and we will think the window is invisible when it is not.
  1585. //
  1586. // Also, 32bit tasks that use similar methods (Eg Word95,
  1587. // Freelance graphics and WM_SETREDRAW messages) may be
  1588. // interrupted while the window is (temporarily) marked as
  1589. // invisible. When the CORE is scheduled we may, again, think
  1590. // that the window is invisible when it is not.
  1591. //
  1592. // To overcome this the SWL window property contains a
  1593. // visibility count, initially set to
  1594. // SWL_BELIEVE_INVISIBLE_COUNT. Following a visible to
  1595. // invisible switch, the counter is decremented and only when
  1596. // it reaches zero does SWL believe that the window is
  1597. // invisible. The counter is reset when a window is detected as
  1598. // visible and the counter is not SWL_BELIEVE_INVISIBLE_COUNT.
  1599. //
  1600. // This would be fine but there are windows when we mistakenly
  1601. // pretend that a window which really has become invisible
  1602. // (rather than one which is transitionally invisible) is
  1603. // visible. This is exposed by menus and dialog boxes. To
  1604. // reduce this problem we will never pretend a window is
  1605. // visible if its class has a CS_SAVEBITS style which should
  1606. // be the case for windows which are transitionally
  1607. // visible like menus and dialog boxes.
  1608. //
  1609. // SFR1083: always treat a transparent window as invisible
  1610. //
  1611. if ( !(windowProp & SWL_PROP_TRANSPARENT) &&
  1612. !(windowProp & SWL_PROP_SAVEBITS) )
  1613. {
  1614. visibleCount = windowProp & SWL_PROP_COUNTDOWN_MASK;
  1615. if ((visibleCount != 0) && (pswlEnum->pHost->m_pShare->m_pasLocal->hetCount > 0))
  1616. {
  1617. //
  1618. // We are still treating this window as visible, ie we
  1619. // are doing a visibilty countdown. Update the count in
  1620. // the window property.
  1621. //
  1622. visibleCount--;
  1623. property = ~SWL_PROP_COUNTDOWN_MASK & storedWindowProp;
  1624. property |= visibleCount;
  1625. TRACE_OUT(( "Decrement visible countdown on window 0x%08x to %d",
  1626. hwnd, visibleCount));
  1627. SetProp(hwnd, SWL_ATOM_NAME, MAKEINTATOM(property));
  1628. //
  1629. // Delay sending of updates since the remote still
  1630. // has a window structure which includes this window
  1631. // but it is not on the local screen (so any updates
  1632. // sent may be for the area where this window was and
  1633. // the remote will not show them).
  1634. //
  1635. pswlEnum->fBailOut = TRUE;
  1636. rc = FALSE;
  1637. DC_QUIT;
  1638. }
  1639. }
  1640. }
  1641. //
  1642. // Only concerned about visible windows.
  1643. //
  1644. if (fVisible)
  1645. {
  1646. pswlEnum->pHost->SWL_InitFullWindowListEntry(hwnd, windowProp,
  1647. &(pswlEnum->newWinNames),
  1648. &(pswlEnum->newFullWinStruct[pswlEnum->count]));
  1649. //
  1650. // If we've added a transparent window then remember this.
  1651. //
  1652. if (windowProp & SWL_PROP_TRANSPARENT)
  1653. {
  1654. pswlEnum->transparentCount++;
  1655. }
  1656. //
  1657. // Update index
  1658. //
  1659. pswlEnum->count++;
  1660. if (pswlEnum->count == SWL_MAX_WINDOWS)
  1661. {
  1662. //
  1663. // We've reached our limit on # of top level windows, so bail
  1664. // out.
  1665. //
  1666. WARNING_OUT(("SWL_MAX_WINDOWS exceeded"));
  1667. rc = FALSE;
  1668. }
  1669. }
  1670. DC_EXIT_POINT:
  1671. DebugExitBOOL(SWLEnumProc, rc);
  1672. return(rc);
  1673. }
  1674. //
  1675. // SWLSendPacket()
  1676. //
  1677. // Called when the shared apps of this node have changed shape/text/position/
  1678. // zorder or there have been new windows created/old shared windows destroyed.
  1679. // We must send these updates out to the remote systems.
  1680. //
  1681. // RETURNS: TRUE or FALSE - success of failure.
  1682. //
  1683. //
  1684. BOOL ASHost::SWLSendPacket
  1685. (
  1686. PSWLWINATTRIBUTES pWindows,
  1687. UINT numWindows,
  1688. LPSTR pTitles,
  1689. UINT lenTitles,
  1690. UINT NRInfoSize,
  1691. LPTSHR_UINT16 pNRInfo
  1692. )
  1693. {
  1694. PSWLPACKET pSWLPacket;
  1695. UINT sizeWindowPkt;
  1696. UINT i;
  1697. LPSTR pString;
  1698. LPBYTE pCopyLocation;
  1699. UINT cCopySize;
  1700. SWLPACKETCHUNK chunk;
  1701. #ifdef _DEBUG
  1702. UINT sentSize;
  1703. #endif // _DEBUG
  1704. DebugEntry(ASHost::SWLSendPacket);
  1705. if (m_pShare->m_pasLocal->hetCount != 0)
  1706. {
  1707. //
  1708. // This is a real packet, not an empty one
  1709. //
  1710. if (!UP_MaybeSendSyncToken())
  1711. {
  1712. //
  1713. // We needed to send a sync token and couldn't so just return
  1714. // failure immediately.
  1715. //
  1716. TRACE_OUT(( "couldn't send sync token"));
  1717. return(FALSE);
  1718. }
  1719. }
  1720. //
  1721. // How big a packet do we need?
  1722. //
  1723. sizeWindowPkt = sizeof(SWLPACKET) + (numWindows - 1) * sizeof(SWLWINATTRIBUTES)
  1724. + lenTitles;
  1725. //
  1726. // Add in the size of the regional window information, plus the
  1727. // size we need for the chunk header.
  1728. //
  1729. if (NRInfoSize)
  1730. {
  1731. if (lenTitles & 1)
  1732. {
  1733. //
  1734. // We need an extra byte for correct alignment
  1735. //
  1736. sizeWindowPkt++;
  1737. }
  1738. sizeWindowPkt += NRInfoSize + sizeof(SWLPACKETCHUNK);
  1739. }
  1740. //
  1741. // Allocate a packet for the windows data.
  1742. //
  1743. pSWLPacket = (PSWLPACKET)m_pShare->SC_AllocPkt(PROT_STR_UPDATES, g_s20BroadcastID,
  1744. sizeWindowPkt);
  1745. if (!pSWLPacket)
  1746. {
  1747. WARNING_OUT(("Failed to alloc SWL packet, size %u", sizeWindowPkt));
  1748. return(FALSE);
  1749. }
  1750. //
  1751. // Packet successfully allocated. Fill in the data and send it.
  1752. //
  1753. pSWLPacket->header.data.dataType = DT_SWL;
  1754. pSWLPacket->msg = SWL_MSG_WINSTRUCT;
  1755. pSWLPacket->flags = 0;
  1756. if (m_swlfSyncing)
  1757. {
  1758. pSWLPacket->flags |= SWL_FLAG_STATE_SYNCING;
  1759. m_swlfSyncing = FALSE;
  1760. }
  1761. pSWLPacket->numWindows = (TSHR_UINT16)numWindows;
  1762. pCopyLocation = (LPBYTE)pSWLPacket->aWindows;
  1763. cCopySize = numWindows*sizeof(SWLWINATTRIBUTES);
  1764. memcpy(pCopyLocation, pWindows, cCopySize);
  1765. //
  1766. // Copy the title information
  1767. //
  1768. pCopyLocation += cCopySize;
  1769. cCopySize = lenTitles;
  1770. memcpy(pCopyLocation, pTitles, cCopySize);
  1771. //
  1772. // Copy any non-rectangular window information.
  1773. //
  1774. if (NRInfoSize)
  1775. {
  1776. pCopyLocation += cCopySize;
  1777. //
  1778. // The chunk must be word aligned in the packet
  1779. //
  1780. if (lenTitles & 1)
  1781. {
  1782. //
  1783. // An odd number of bytes of window titles has misaligned us,
  1784. // so write a 0 (compresses best!) to realign the pointer.
  1785. //
  1786. *pCopyLocation++ = 0;
  1787. }
  1788. //
  1789. // Write the chunk header
  1790. //
  1791. chunk.size = (TSHR_INT16)(NRInfoSize + sizeof(chunk));
  1792. chunk.idChunk = SWL_PACKET_ID_NONRECT;
  1793. cCopySize = sizeof(chunk);
  1794. memcpy(pCopyLocation, &chunk, cCopySize);
  1795. //
  1796. // Now write the variable info itself
  1797. //
  1798. pCopyLocation += cCopySize;
  1799. cCopySize = NRInfoSize;
  1800. memcpy(pCopyLocation, pNRInfo, cCopySize);
  1801. TRACE_OUT(("Non rect data length %d",NRInfoSize));
  1802. }
  1803. //
  1804. // Backwards compatibility.
  1805. //
  1806. pSWLPacket->tick = (TSHR_UINT16)GetTickCount();
  1807. pSWLPacket->token = m_pShare->SWL_CalculateNextToken(m_pShare->m_swlLastTokenSeen);
  1808. TRACE_OUT(("Updating m_swlLastTokenSeen to 0x%08x for sent packet",
  1809. pSWLPacket->token));
  1810. m_pShare->m_swlLastTokenSeen = pSWLPacket->token;
  1811. pSWLPacket->reserved = 0;
  1812. #ifdef _DEBUG
  1813. {
  1814. int iWin;
  1815. int cWins;
  1816. PSWLWINATTRIBUTES pSwl;
  1817. // Trace out the entries
  1818. pSwl = pSWLPacket->aWindows;
  1819. cWins = pSWLPacket->numWindows;
  1820. TRACE_OUT(("SWLSendPacket: Sending packet with %d windows", cWins));
  1821. for (iWin = 0; iWin < cWins; iWin++, pSwl++)
  1822. {
  1823. TRACE_OUT(("SWLSendPacket: Entry %d", iWin));
  1824. TRACE_OUT(("SWLSendPacket: Flags %08x", pSwl->flags));
  1825. TRACE_OUT(("SWLSendPacket: Window %08x", pSwl->winID));
  1826. TRACE_OUT(("SWLSendPacket: Position {%04d, %04d, %04d, %04d}",
  1827. pSwl->position.left, pSwl->position.top,
  1828. pSwl->position.right, pSwl->position.bottom));
  1829. }
  1830. }
  1831. #endif // _DEBUG
  1832. //
  1833. // Send the windows packet on the UPDATE stream.
  1834. //
  1835. if (m_pShare->m_scfViewSelf)
  1836. m_pShare->SWL_ReceivedPacket(m_pShare->m_pasLocal, &pSWLPacket->header);
  1837. #ifdef _DEBUG
  1838. sentSize =
  1839. #endif // _DEBUG
  1840. m_pShare->DCS_CompressAndSendPacket(PROT_STR_UPDATES, g_s20BroadcastID,
  1841. &(pSWLPacket->header), sizeWindowPkt);
  1842. TRACE_OUT(("SWL packet size: %08d, sent %08d", sizeWindowPkt, sentSize));
  1843. DebugExitBOOL(ASHost::SWLSendPacket, TRUE);
  1844. return(TRUE);
  1845. }
  1846. //
  1847. // SWL_CalculateNextToken()
  1848. //
  1849. // This calculates the next token to put in an outgoing SWL packet. This is
  1850. // only looked at by backlevel systems (<= NM 2.1) who treat all incoming
  1851. // SWL streams in one big messy global fashion. So we need to put something
  1852. // there, something that won't scare them but ensure that our
  1853. // packets aren't ignored if at all possible.
  1854. //
  1855. TSHR_UINT16 ASShare::SWL_CalculateNextToken(TSHR_UINT16 currentToken)
  1856. {
  1857. UINT increment;
  1858. TSHR_UINT16 newToken;
  1859. DebugEntry(ASShare::SWL_CalculateNextToken);
  1860. //
  1861. // We use the highest priority increment to make sure our packets get
  1862. // through. But will this cause collisions with other 3.0 sharers?
  1863. // Try lowest priority if necessary.
  1864. //
  1865. increment = SWL_NEW_ZORDER_FAKE_WINDOW_INC;
  1866. //
  1867. // Return the new token
  1868. //
  1869. newToken = SWL_MAKE_TOKEN(
  1870. SWL_GET_INDEX(currentToken) + SWL_GET_INCREMENT(currentToken), increment);
  1871. DebugExitDWORD(ASShare::SWL_CalculateNextToken, newToken);
  1872. return(newToken);
  1873. }
  1874. //
  1875. // SWL_ReceivedPacket()
  1876. //
  1877. // DESCRIPTION:
  1878. //
  1879. // Processes a windows structure packet which has been received from the
  1880. // PR. This defines the position of the shared windows hosted on the
  1881. // remote system, any obscured regions, and the Z-order relative to the
  1882. // shared windows hosted locally.
  1883. //
  1884. // NOTE: We don't do any token stuff for _incoming_ packets; we never
  1885. // want to drop them since we aren't zordering anything locally. We are
  1886. // simply applying the zorder/region/position info to the client area
  1887. // drawing.
  1888. //
  1889. void ASShare::SWL_ReceivedPacket
  1890. (
  1891. ASPerson * pasFrom,
  1892. PS20DATAPACKET pPacket
  1893. )
  1894. {
  1895. PSWLPACKET pSWLPacket;
  1896. UINT i;
  1897. UINT j;
  1898. PSWLWINATTRIBUTES wins;
  1899. UINT numWins;
  1900. HRGN hrgnShared;
  1901. HRGN hrgnObscured;
  1902. HRGN hrgnThisWindow;
  1903. HRGN hrgnRect;
  1904. LPTSHR_INT16 pOurRgnData;
  1905. LPSTR pOurRgnChunk;
  1906. UINT cNonRectWindows;
  1907. BOOL viewAnyChanges;
  1908. DebugEntry(ASShare::SWL_ReceivedPacket);
  1909. ValidatePerson(pasFrom);
  1910. pSWLPacket = (PSWLPACKET)pPacket;
  1911. switch (pSWLPacket->msg)
  1912. {
  1913. //
  1914. // This is the only packet we currently recognize.
  1915. //
  1916. case SWL_MSG_WINSTRUCT:
  1917. break;
  1918. default:
  1919. WARNING_OUT(("Unknown SWL packet msg %d from [%d]",
  1920. pSWLPacket->msg, pasFrom->mcsID));
  1921. DC_QUIT;
  1922. }
  1923. //
  1924. // Update the last token we've seen, if it's greater than the last
  1925. // one we know about. Unlike 2.x, we don't drop this packet if it isn't.
  1926. //
  1927. if (pSWLPacket->token > m_swlLastTokenSeen)
  1928. {
  1929. TRACE_OUT(("Updating m_swlLastTokenSeen to 0x%08x, received packet from person [%d]",
  1930. pSWLPacket->token, pasFrom->mcsID));
  1931. m_swlLastTokenSeen = pSWLPacket->token;
  1932. }
  1933. else if (pasFrom->cpcCaps.general.version < CAPS_VERSION_30)
  1934. {
  1935. WARNING_OUT(("Received SWL packet from [%d] with stale token 0x%08x",
  1936. pasFrom->mcsID, pSWLPacket->token));
  1937. }
  1938. //
  1939. // Return immediately and ignore this baby if we aren't sharing. Back
  1940. // level systems may send us a SYNC packet with no windows before we've
  1941. // shared, and may send us one final SWL packet after we're done
  1942. // sharing.
  1943. //
  1944. if (!pasFrom->m_pView)
  1945. {
  1946. WARNING_OUT(("SWL_ReceivedPacket: Ignoring SWL packet from person [%d] not hosting",
  1947. pasFrom->mcsID));
  1948. DC_QUIT;
  1949. }
  1950. //
  1951. // Set up local variables to access the data in the packet
  1952. //
  1953. wins = pSWLPacket->aWindows;
  1954. numWins = pSWLPacket->numWindows;
  1955. pOurRgnChunk = (LPSTR)wins + numWins*sizeof(SWLWINATTRIBUTES);
  1956. TRACE_OUT(("SWL_ReceivedPacket: Received packet with %d windows from [%d]",
  1957. numWins, pasFrom->mcsID));
  1958. //
  1959. // We can't handle more than SWL_MAX_WINDOWS in the packet
  1960. // BOGUS:
  1961. // LauraBu -- We should negotiate this (make it a cap) on how many
  1962. // windows we can handle receiving. Then we have an easy path to
  1963. // increase this number.
  1964. //
  1965. if (numWins > SWL_MAX_WINDOWS)
  1966. {
  1967. ERROR_OUT(("SWL_ReceivedPacket: too many windows (%04d) in packet from [%08d]",
  1968. numWins, pasFrom->mcsID));
  1969. DC_QUIT;
  1970. }
  1971. cNonRectWindows = 0;
  1972. //
  1973. // The first pass over the arriving packet is to count the amount of
  1974. // region data and to update the window tray.
  1975. //
  1976. viewAnyChanges = FALSE;
  1977. //
  1978. // This part we process front to back, since that's the order of the
  1979. // strings and we use them for putting entries on the traybar.
  1980. //
  1981. for (i = 0; i < numWins; i++)
  1982. {
  1983. // Mask out bogus old bits that aren't OK to process
  1984. wins[i].flags &= SWL_FLAGS_VALIDPACKET;
  1985. TRACE_OUT(("SWL_ReceivedPacket: Entry %d", i));
  1986. TRACE_OUT(("SWL_ReceivedPacket: Flags %08x", wins[i].flags));
  1987. TRACE_OUT(("SWL_ReceivedPacket: Window %08x", wins[i].winID));
  1988. TRACE_OUT(("SWL_ReceivedPacket: Position {%04d, %04d, %04d, %04d}",
  1989. wins[i].position.left, wins[i].position.top,
  1990. wins[i].position.right, wins[i].position.bottom));
  1991. //
  1992. // NOTE:
  1993. // 2.x nodes may send us a packet with an entry for a shadow.
  1994. // Go look up the REAL shadow rect from its host.
  1995. //
  1996. // And fix up the SWL packet then.
  1997. //
  1998. if (wins[i].flags & SWL_FLAG_WINDOW_SHADOW)
  1999. {
  2000. ASPerson * pasRealHost;
  2001. TRACE_OUT(("SWLReceivedPacket: Entry is 2.x SHADOW for host [%d]",
  2002. wins[i].extra));
  2003. // This must be a back level dude, giving us an empty rect.
  2004. ASSERT(wins[i].position.left == 0);
  2005. ASSERT(wins[i].position.top == 0);
  2006. ASSERT(wins[i].position.right == 0);
  2007. ASSERT(wins[i].position.bottom == 0);
  2008. // Find the real host of this window
  2009. SC_ValidateNetID(wins[i].extra, &pasRealHost);
  2010. if (pasRealHost != NULL)
  2011. {
  2012. int cSwl = 0;
  2013. PSWLWINATTRIBUTES pSwl = NULL;
  2014. // Try to find this window's entry
  2015. if (pasRealHost == m_pasLocal)
  2016. {
  2017. //
  2018. // This was shared by US. We can just use the scratch
  2019. // arrays we already have. m_swlCurIndex has the last
  2020. // one we sent out to everybody in the share, so the
  2021. // info it has is most likely reflected on that 2x
  2022. // remote.
  2023. //
  2024. if (m_pHost != NULL)
  2025. {
  2026. cSwl = m_pHost->m_aswlNumCompactWins[m_pHost->m_swlCurIndex];
  2027. pSwl = &(m_pHost->m_aswlCompactWinStructs[m_pHost->m_swlCurIndex * SWL_MAX_WINDOWS]);
  2028. }
  2029. }
  2030. else
  2031. {
  2032. //
  2033. // This was shared by somebody else, not us and not
  2034. // the person who sent this SWL packet. So go use the
  2035. // last SWL info we received from them.
  2036. //
  2037. if (pasRealHost->m_pView)
  2038. {
  2039. cSwl = pasRealHost->m_pView->m_swlCount;
  2040. pSwl = pasRealHost->m_pView->m_aswlLast;
  2041. }
  2042. }
  2043. //
  2044. // Loop through the window list for the real host to
  2045. // find the entry--we'll use the last REAL rect we got
  2046. // for this window.
  2047. //
  2048. while (cSwl > 0)
  2049. {
  2050. if (wins[i].winID == pSwl->winID)
  2051. {
  2052. // Copy the _real_ position into the packet.
  2053. TRACE_OUT(("SWLReceivedPacket: Using real rect {%04d, %04d, %04d, %04d}",
  2054. pSwl->position.left, pSwl->position.top,
  2055. pSwl->position.right, pSwl->position.bottom));
  2056. wins[i].position = pSwl->position;
  2057. break;
  2058. }
  2059. cSwl--;
  2060. pSwl++;
  2061. }
  2062. if (cSwl == 0)
  2063. {
  2064. ERROR_OUT(("SWLReceivedPacket: Couldn't find real window %08x from host [%d]",
  2065. wins[i].winID, wins[i].extra));
  2066. }
  2067. }
  2068. }
  2069. //
  2070. // 2.x nodes send us VD coords, not screen coords. But that's what
  2071. // we display for them, so that's what we save away. Note that this
  2072. // works even in the 2.x shadow case above. Hosted and shadowed
  2073. // windows both get moved in a desktop scroll, so they stay in the
  2074. // same place in the virtual desktop, meaning that the coords sent
  2075. // from the host stay the same even if the windows move, meaning that
  2076. // we can use the coords of the real host to get the real shadow
  2077. // rect.
  2078. //
  2079. if (wins[i].flags & SWL_FLAG_WINDOW_HOSTED)
  2080. {
  2081. TRACE_OUT(("SWL_ReceivedPacket: Hosted Window 0x%08x", wins[i].winID));
  2082. TRACE_OUT(("SWL_ReceivedPacket: Text %s", ((*pOurRgnChunk == '\xff') ? "" : pOurRgnChunk)));
  2083. TRACE_OUT(("SWL_ReceivedPacket: Flags %08x", wins[i].flags));
  2084. TRACE_OUT(("SWL_ReceivedPacket: Owner %08x", wins[i].ownerWinID));
  2085. TRACE_OUT(("SWL_ReceivedPacket: Position {%04d, %04d, %04d, %04d}",
  2086. wins[i].position.left, wins[i].position.top,
  2087. wins[i].position.right, wins[i].position.bottom));
  2088. //
  2089. // We are stepping through the titles (which get sent from
  2090. // downlevel systems) which do not contain an
  2091. // explicit length) so that we can get to the data that follows
  2092. //
  2093. if (*pOurRgnChunk == '\xff')
  2094. {
  2095. //
  2096. // This is the title for a non-task window - there is just
  2097. // a single byte to ignore
  2098. //
  2099. pOurRgnChunk++;
  2100. }
  2101. else
  2102. {
  2103. //
  2104. // This is the title for a task window - there is a NULL
  2105. // terminated string to ignore.
  2106. //
  2107. if (wins[i].flags & SWL_FLAG_WINDOW_TASKBAR)
  2108. {
  2109. if (VIEW_WindowBarUpdateItem(pasFrom, &wins[i], pOurRgnChunk))
  2110. {
  2111. viewAnyChanges = TRUE;
  2112. }
  2113. }
  2114. pOurRgnChunk += lstrlen(pOurRgnChunk)+1;
  2115. }
  2116. }
  2117. if (wins[i].flags & SWL_FLAG_WINDOW_NONRECTANGLE)
  2118. {
  2119. //
  2120. // We need to know how many windows have non rectangular data
  2121. // provided.
  2122. //
  2123. cNonRectWindows++;
  2124. }
  2125. }
  2126. if (cNonRectWindows)
  2127. {
  2128. TRACE_OUT(( "%d non-rect windows", cNonRectWindows));
  2129. //
  2130. // The window title data is variable length bytes, so may end with
  2131. // incorrect alignment. Any data which follows (currently only
  2132. // non-rectangular windows data) is word aligned.
  2133. //
  2134. // So check if offset from beginning of data is not aligned. Note
  2135. // that the packet may start on an ODD boundary because we get
  2136. // a pointer to the data directly and don't allocate a copy.
  2137. //
  2138. if ((LOWORD(pSWLPacket) & 1) != (LOWORD(pOurRgnChunk) & 1))
  2139. {
  2140. TRACE_OUT(("SWL_ReceivedPacket: Aligning region data"));
  2141. pOurRgnChunk++;
  2142. }
  2143. //
  2144. // Loop through the tagged chunks that follow until we find the
  2145. // one we want.
  2146. //
  2147. while (((PSWLPACKETCHUNK)pOurRgnChunk)->idChunk != SWL_PACKET_ID_NONRECT)
  2148. {
  2149. ERROR_OUT(("SWL_ReceivedPacket: unknown chunk 0x%04x",
  2150. ((PSWLPACKETCHUNK)pOurRgnChunk)->idChunk));
  2151. pOurRgnChunk += ((PSWLPACKETCHUNK)pOurRgnChunk)->size;
  2152. }
  2153. TRACE_OUT(("Total non rect data 0x%04x", ((PSWLPACKETCHUNK)pOurRgnChunk)->size));
  2154. }
  2155. //
  2156. // Now scan the wins array backwards (ie furthest away to closest
  2157. // window) to calculate the unshared region (obscured or nothing there).
  2158. // and the shared region.
  2159. //
  2160. hrgnShared = CreateRectRgn(0, 0, 0, 0);
  2161. hrgnObscured = CreateRectRgn(0, 0, 0, 0);
  2162. //
  2163. // Create a region we can make use of in the next bit of processing.
  2164. //
  2165. hrgnRect = CreateRectRgn(0, 0, 0, 0);
  2166. hrgnThisWindow = CreateRectRgn(0, 0, 0, 0);
  2167. //
  2168. // While we are building the shared/obscured regions, also fill in
  2169. // the host list. Note that this may contain references to local
  2170. // windows also if they obscure shared ones. Since we don't reference
  2171. // the list very often, it's easier to just copy the same stuff.
  2172. //
  2173. i = numWins;
  2174. while (i != 0)
  2175. {
  2176. i--;
  2177. //
  2178. // Consider whether this is a non rectangular window
  2179. //
  2180. if (wins[i].flags & SWL_FLAG_WINDOW_NONRECTANGLE)
  2181. {
  2182. UINT numRects;
  2183. UINT cStepOver;
  2184. int top;
  2185. int left;
  2186. int right;
  2187. int bottom;
  2188. int lasttop;
  2189. int lastleft;
  2190. int lastright;
  2191. int lastbottom;
  2192. int deltaleft;
  2193. int deltatop;
  2194. int deltaright;
  2195. int deltabottom;
  2196. int lastdeltaleft;
  2197. int lastdeltatop;
  2198. int lastdeltaright;
  2199. int lastdeltabottom;
  2200. //
  2201. // A non-rectangular region. We go ahead and create the region
  2202. // from the rectangles that describe it.
  2203. //
  2204. pOurRgnData = (LPTSHR_INT16)(pOurRgnChunk + sizeof(SWLPACKETCHUNK));
  2205. //
  2206. // We need to step through the non-rectangular data because we
  2207. // are processing windows in reverse z-order.
  2208. //
  2209. cStepOver = --cNonRectWindows;
  2210. while (cStepOver--)
  2211. {
  2212. //
  2213. // The next word in the chain contains the number of
  2214. // rectangles, so we multiply by 4 to get the number of
  2215. // words to advance.
  2216. //
  2217. pOurRgnData += *pOurRgnData++ * 4;
  2218. }
  2219. //
  2220. // Find the number of rectangles.
  2221. //
  2222. numRects = *pOurRgnData++;
  2223. //
  2224. // The encoding is based on a series of deltas, based on some
  2225. // initial assumptions
  2226. //
  2227. lastleft = 0;
  2228. lasttop = 0;
  2229. lastright = 0;
  2230. lastbottom = 0;
  2231. lastdeltaleft = 0;
  2232. lastdeltatop = 0;
  2233. lastdeltaright = 0;
  2234. lastdeltabottom = 0;
  2235. //
  2236. // Create the region from the first rectangle.
  2237. //
  2238. deltaleft = lastdeltaleft + *pOurRgnData++;
  2239. deltatop = lastdeltatop + *pOurRgnData++;
  2240. deltaright = lastdeltaright + *pOurRgnData++;
  2241. deltabottom = lastdeltabottom + *pOurRgnData++;
  2242. left = lastleft + deltaleft;
  2243. top = lasttop + deltatop;
  2244. right = lastright + deltaright;
  2245. bottom = lastbottom + deltabottom;
  2246. // THESE COORDS ARE INCLUSIVE, SO ADD ONE
  2247. SetRectRgn(hrgnThisWindow, left, top, right+1, bottom+1);
  2248. while (--numRects > 0)
  2249. {
  2250. //
  2251. // Move to the next rectangle.
  2252. //
  2253. lastleft = left;
  2254. lasttop = top;
  2255. lastright = right;
  2256. lastbottom = bottom;
  2257. lastdeltaleft = deltaleft;
  2258. lastdeltatop = deltatop;
  2259. lastdeltaright = deltaright;
  2260. lastdeltabottom = deltabottom;
  2261. deltaleft = lastdeltaleft + *pOurRgnData++;
  2262. deltatop = lastdeltatop + *pOurRgnData++;
  2263. deltaright = lastdeltaright + *pOurRgnData++;
  2264. deltabottom = lastdeltabottom + *pOurRgnData++;
  2265. left = lastleft + deltaleft;
  2266. top = lasttop + deltatop;
  2267. right = lastright + deltaright;
  2268. bottom = lastbottom + deltabottom;
  2269. //
  2270. // Get the current rectangle into a region.
  2271. // THESE COORDS ARE INCLUSIVE SO ADD ONE TO BOTTOM-RIGHT
  2272. //
  2273. SetRectRgn(hrgnRect, left, top, right+1, bottom+1);
  2274. //
  2275. // Add this region to the combined region.
  2276. //
  2277. UnionRgn(hrgnThisWindow, hrgnRect, hrgnThisWindow);
  2278. }
  2279. //
  2280. // Switch from window coords to desktop coords.
  2281. //
  2282. OffsetRgn(hrgnThisWindow,
  2283. wins[i].position.left,
  2284. wins[i].position.top);
  2285. }
  2286. else
  2287. {
  2288. //
  2289. // This window region is simply a rectangle.
  2290. SetRectRgn(hrgnThisWindow,
  2291. wins[i].position.left,
  2292. wins[i].position.top,
  2293. wins[i].position.right+1,
  2294. wins[i].position.bottom+1);
  2295. }
  2296. //
  2297. // Update the obscured region. As we are working from the back to
  2298. // the front of the Z-order we can simply add all local window
  2299. // entries in the incoming structure and subtract all hosted
  2300. // windows to arrive at the right answer.
  2301. //
  2302. if (wins[i].flags & SWL_FLAG_WINDOW_HOSTED)
  2303. {
  2304. //
  2305. // This is a hosted window, sitting above the previous ones.
  2306. // Add it to the shared region.
  2307. // Remove it from the obscured region.
  2308. //
  2309. UnionRgn(hrgnShared, hrgnShared, hrgnThisWindow);
  2310. SubtractRgn(hrgnObscured, hrgnObscured, hrgnThisWindow);
  2311. }
  2312. else
  2313. {
  2314. //
  2315. // Local windows
  2316. //
  2317. TRACE_OUT(( "Adding window %d (%d,%d):(%d,%d) to obscured rgn",
  2318. i,
  2319. wins[i].position.left,
  2320. wins[i].position.top,
  2321. wins[i].position.right,
  2322. wins[i].position.bottom ));
  2323. //
  2324. // This is a local window, sitting above the previous ones.
  2325. // We only care about what part of it intersects the current
  2326. // shared area of the windows behind it. If it doesn't
  2327. // intersect the shared area at all, it will add no new
  2328. // obscured bits.
  2329. //
  2330. // So figure out what part of the current shared area is now
  2331. // obscured. Add that piece to the obscured region, and
  2332. // subtract it from the shared region.
  2333. //
  2334. IntersectRgn(hrgnThisWindow, hrgnShared, hrgnThisWindow);
  2335. UnionRgn(hrgnObscured, hrgnObscured, hrgnThisWindow);
  2336. SubtractRgn(hrgnShared, hrgnShared, hrgnThisWindow);
  2337. }
  2338. }
  2339. //
  2340. // We can destroy the regions we created way back when.
  2341. //
  2342. DeleteRgn(hrgnRect);
  2343. DeleteRgn(hrgnThisWindow);
  2344. //
  2345. // Save the new host regions.
  2346. //
  2347. // Pass the newly calculated regions to the Shadow Window Presenter.
  2348. // The view code will take care of repainting the invalid parts. And
  2349. // will delete what was passed in if not kept.
  2350. //
  2351. VIEW_SetHostRegions(pasFrom, hrgnShared, hrgnObscured);
  2352. //
  2353. // Save the new window list as the current one.
  2354. //
  2355. pasFrom->m_pView->m_swlCount = numWins;
  2356. memcpy(pasFrom->m_pView->m_aswlLast, wins, numWins * sizeof(SWLWINATTRIBUTES));
  2357. //
  2358. // Finish updating the window list. This will repaint the tray bar. We
  2359. // do this now instead of earlier so that the visual changes and
  2360. // window bar changes appear together.
  2361. //
  2362. VIEW_WindowBarEndUpdateItems(pasFrom, viewAnyChanges);
  2363. if ((pSWLPacket->flags & SWL_FLAG_STATE_SYNCING) &&
  2364. (m_scShareVersion < CAPS_VERSION_30))
  2365. {
  2366. //
  2367. // With 2.x nodes in the picture, we need to do the old 2.x ping-
  2368. // pongy nonsense. We must force a packet if we're hosting when
  2369. // we receive a SYNC packet.
  2370. //
  2371. if (m_pHost)
  2372. {
  2373. m_pHost->m_swlfForceSend = TRUE;
  2374. }
  2375. }
  2376. DC_EXIT_POINT:
  2377. DebugExitVOID(ASShare::SWL_ReceivedPacket);
  2378. }
  2379. //
  2380. // Name: SWLWindowIsTaggable
  2381. //
  2382. // Purpose: Determine if a window would be taggable when hosted
  2383. //
  2384. // Returns: TRUE if the window would be taggable
  2385. // If the window is WS_EX_APPWINDOW or has a caption, it's tagged
  2386. //
  2387. // Params: winid - ID of window
  2388. //
  2389. //
  2390. BOOL ASHost::SWLWindowIsTaggable(HWND hwnd)
  2391. {
  2392. BOOL rc;
  2393. DebugEntry(ASHost::SWLWindowIsTaggable);
  2394. if (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_APPWINDOW)
  2395. rc = TRUE;
  2396. else if ((GetWindowLong(hwnd, GWL_STYLE) & WS_CAPTION) == WS_CAPTION)
  2397. rc = TRUE;
  2398. else
  2399. rc = FALSE;
  2400. DebugExitBOOL(ASHost::SWLWindowIsTaggable, rc);
  2401. return(rc);
  2402. }
  2403. //
  2404. // FUNCTION: SWLWindowIsOnTaskBar
  2405. //
  2406. // DESCRIPTION:
  2407. //
  2408. // Determines whether the given window is represented on the task bar
  2409. //
  2410. // PARAMETERS:
  2411. //
  2412. // hwnd - window to be queried
  2413. //
  2414. // RETURNS:
  2415. //
  2416. // TRUE - Window is represented on the task bar
  2417. //
  2418. // FALSE - Window is not represented on the task bar
  2419. //
  2420. //
  2421. BOOL ASHost::SWLWindowIsOnTaskBar(HWND hwnd)
  2422. {
  2423. BOOL rc = FALSE;
  2424. HWND owner;
  2425. RECT rect;
  2426. DebugEntry(ASHost::SWLWindowIsOnTaskBar);
  2427. //
  2428. // Our best understanding as to whether a window is on the task bar is
  2429. // the following:
  2430. //
  2431. // - it is a top level window (has no owner)
  2432. // AND - it does not have the WS_EX_TOOLWINDOW style
  2433. //
  2434. // Oprah1655: Visual Basic apps consist of a visible zero sized window
  2435. // with no owner and a window owned by the zero sized window. We do
  2436. // not want the zero sized window to be on the task bar, we do want the
  2437. // other window to be on the task bar.
  2438. //
  2439. //
  2440. owner = GetWindow(hwnd, GW_OWNER);
  2441. if (owner == NULL)
  2442. {
  2443. if (!(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW))
  2444. {
  2445. GetWindowRect(hwnd, &rect);
  2446. if ((rect.left < rect.right) &&
  2447. (rect.top < rect.bottom))
  2448. {
  2449. TRACE_OUT(("window 0x%08x allowed on task bar", hwnd));
  2450. rc = TRUE;
  2451. }
  2452. else
  2453. {
  2454. TRACE_OUT(( "window 0x%08x zero sized", hwnd));
  2455. }
  2456. }
  2457. }
  2458. else
  2459. {
  2460. //
  2461. // Is the owner window a top-level window of zero size?
  2462. //
  2463. if (GetWindow(owner, GW_OWNER) == NULL)
  2464. {
  2465. GetWindowRect(owner, &rect);
  2466. if (IsRectEmpty(&rect))
  2467. {
  2468. TRACE_OUT(("HWND 0x%08x has zero sized top-level owner",
  2469. hwnd));
  2470. rc = TRUE;
  2471. }
  2472. }
  2473. }
  2474. DebugExitDWORD(ASHost::SWLWindowIsOnTaskBar, rc);
  2475. return(rc);
  2476. }
  2477. //
  2478. // SWL_GetWindowProperty()
  2479. //
  2480. UINT_PTR ASHost::SWL_GetWindowProperty(HWND hwnd)
  2481. {
  2482. UINT_PTR properties;
  2483. char className[HET_CLASS_NAME_SIZE];
  2484. DebugEntry(ASHost::SWL_GetWindowProperty);
  2485. properties = (UINT_PTR)GetProp(hwnd, MAKEINTATOM(m_swlPropAtom));
  2486. if (properties != SWL_PROP_INVALID)
  2487. DC_QUIT;
  2488. //
  2489. // No property for this window - it must be new, so create its
  2490. // initial property state.
  2491. //
  2492. //
  2493. // Assign an initial value to the property, so we never set a property
  2494. // of zero (which we reserve to indicate invalid).
  2495. //
  2496. properties = SWL_PROP_INITIAL;
  2497. //
  2498. // TAGGABLE IS FOR < 3.0 nodes only.
  2499. //
  2500. if (SWLWindowIsTaggable(hwnd))
  2501. {
  2502. properties |= SWL_PROP_TAGGABLE;
  2503. }
  2504. //
  2505. // Get all the SWL info which is stored as a window property.
  2506. //
  2507. if (SWLWindowIsOnTaskBar(hwnd))
  2508. {
  2509. //
  2510. // This class of window gets tagged.
  2511. //
  2512. properties |= SWL_PROP_TASKBAR;
  2513. }
  2514. //
  2515. // Find out if the window class has the CS_SAVEBITS style.
  2516. //
  2517. if (GetClassLong(hwnd, GCL_STYLE) & CS_SAVEBITS)
  2518. {
  2519. //
  2520. // This window's class has the CS_SAVEBITS style.
  2521. //
  2522. properties |= SWL_PROP_SAVEBITS;
  2523. }
  2524. //
  2525. // Set the visibility count. This is 0 if the window is currently
  2526. // invisible, SWL_BELIEVE_INVISIBLE_COUNT if visible.
  2527. //
  2528. if (IsWindowVisible(hwnd))
  2529. {
  2530. properties |= SWL_BELIEVE_INVISIBLE_COUNT;
  2531. }
  2532. //
  2533. // Set the window property, which we will retrieve when SWL determines
  2534. // whether it needs to resend the window structure.
  2535. //
  2536. if (m_pShare->m_pasLocal->hetCount > 0)
  2537. {
  2538. SetProp(hwnd, SWL_ATOM_NAME, (HANDLE)properties);
  2539. }
  2540. DC_EXIT_POINT:
  2541. DebugExitDWORD(ASHost::SWL_GetWindowProperty, properties);
  2542. return(properties);
  2543. }
  2544. //
  2545. // FUNCTION: SWLDestroyWindowProperty
  2546. //
  2547. // DESCRIPTION:
  2548. //
  2549. // Destroys the window property for the supplied window.
  2550. //
  2551. // PARMETERS: winID - the window ID of the window for which the property is
  2552. // destroyed.
  2553. //
  2554. // RETURNS: Zero
  2555. //
  2556. //
  2557. BOOL CALLBACK SWLDestroyWindowProperty(HWND hwnd, LPARAM lParam)
  2558. {
  2559. //
  2560. // NOTE LAURABU:
  2561. // We set the property using a string, which bumps up the ref count,
  2562. // to work around a Win95 bug. We therefore want to remove it using a
  2563. // string, which bumps down the ref count. Otherwise we will quickly
  2564. // get a ref count overflow.
  2565. //
  2566. RemoveProp(hwnd, SWL_ATOM_NAME);
  2567. return(TRUE);
  2568. }
  2569.