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.

3649 lines
95 KiB

  1. #include "precomp.h"
  2. //
  3. // HOST.CPP
  4. // Hosting, local and remote
  5. //
  6. // Copyright(c) Microsoft 1997-
  7. //
  8. #define MLZ_FILE_ZONE ZONE_CORE
  9. //
  10. // HET_Init()
  11. //
  12. // Initialization for hosting
  13. // * window tracking
  14. // * capabilities
  15. // * host UI
  16. //
  17. BOOL HET_Init(void)
  18. {
  19. BOOL rc = FALSE;
  20. int property;
  21. UINT i;
  22. LOGFONT lf;
  23. DebugEntry(HET_Init);
  24. //
  25. // Initialize T.128 capabilities, whether we can host or not.
  26. //
  27. ZeroMemory(&g_cpcLocalCaps, sizeof(g_cpcLocalCaps));
  28. g_cpcLocalCaps.header.numCapabilities = PROTCAPS_COUNT;
  29. // PROTCAPS_GENERAL
  30. // Check for compression setting (useful to debug protocol)
  31. // You can set CT_PKZIP (1) or none (0) instead of persistent PKZIP,
  32. // which is the default.
  33. //
  34. g_cpcLocalCaps.general.header.capID = CAPS_ID_GENERAL;
  35. g_cpcLocalCaps.general.header.capSize = sizeof(g_cpcLocalCaps.general);
  36. COM_ReadProfInt(DBG_INI_SECTION_NAME, GDC_INI_COMPRESSION,
  37. GCT_DEFAULT, &property);
  38. g_cpcLocalCaps.general.genCompressionType = (TSHR_UINT16)property;
  39. g_cpcLocalCaps.general.genCompressionLevel = CAPS_GEN_COMPRESSION_LEVEL_1;
  40. g_cpcLocalCaps.general.OS = CAPS_WINDOWS;
  41. g_cpcLocalCaps.general.OSVersion = (g_asWin95 ? CAPS_WINDOWS_95 : CAPS_WINDOWS_NT);
  42. g_cpcLocalCaps.general.typeFlags = 0;
  43. if (g_asOptions & AS_SERVICE)
  44. {
  45. g_cpcLocalCaps.general.typeFlags |= AS_SERVICE;
  46. }
  47. if (g_asOptions & AS_UNATTENDED)
  48. {
  49. g_cpcLocalCaps.general.typeFlags |= AS_UNATTENDED;
  50. }
  51. g_cpcLocalCaps.general.version = CAPS_VERSION_CURRENT;
  52. g_cpcLocalCaps.general.supportsDOS6Compression = CAPS_UNSUPPORTED;
  53. g_cpcLocalCaps.general.supportsCapsUpdate = CAPS_SUPPORTED;
  54. g_cpcLocalCaps.general.supportsRemoteUnshare = CAPS_UNSUPPORTED;
  55. //
  56. // PROTCAPS_SCREEN
  57. //
  58. g_cpcLocalCaps.screen.header.capID = CAPS_ID_SCREEN;
  59. g_cpcLocalCaps.screen.header.capSize = sizeof(g_cpcLocalCaps.screen);
  60. g_cpcLocalCaps.screen.capsSupports1BPP = CAPS_UNSUPPORTED;
  61. g_cpcLocalCaps.screen.capsSupports4BPP = CAPS_SUPPORTED;
  62. g_cpcLocalCaps.screen.capsSupports8BPP = CAPS_SUPPORTED;
  63. g_cpcLocalCaps.screen.capsSupports24BPP = CAPS_SUPPORTED;
  64. g_cpcLocalCaps.screen.capsScreenWidth = (TSHR_UINT16)GetSystemMetrics(SM_CXSCREEN);
  65. g_cpcLocalCaps.screen.capsScreenHeight = (TSHR_UINT16)GetSystemMetrics(SM_CYSCREEN);
  66. g_cpcLocalCaps.screen.capsSupportsDesktopResize = CAPS_SUPPORTED;
  67. //
  68. // Set up the V1 and/or V2 Bitmap Compression capabilities. For the
  69. // V2.0 protocol, both are supported by default (supporting V1
  70. // compression allows for negotiation down to V1 protocol systems), but
  71. // can be overidden in the INI file.
  72. //
  73. g_cpcLocalCaps.screen.capsSupportsV1Compression = CAPS_UNSUPPORTED;
  74. g_cpcLocalCaps.screen.capsSupportsV2Compression = CAPS_SUPPORTED;
  75. g_cpcLocalCaps.screen.capsBPP = (TSHR_UINT16)g_usrScreenBPP;
  76. // PROTCAPS_SC
  77. g_cpcLocalCaps.share.header.capID = CAPS_ID_SC;
  78. g_cpcLocalCaps.share.header.capSize = sizeof(g_cpcLocalCaps.share);
  79. g_cpcLocalCaps.share.gccID = 0;
  80. // PROTCAPS_CM
  81. g_cpcLocalCaps.cursor.header.capID = CAPS_ID_CM;
  82. g_cpcLocalCaps.cursor.header.capSize = sizeof(g_cpcLocalCaps.cursor);
  83. g_cpcLocalCaps.cursor.capsSupportsColorCursors = CAPS_SUPPORTED;
  84. g_cpcLocalCaps.cursor.capsCursorCacheSize = TSHR_CM_CACHE_ENTRIES;
  85. // PROTCAPS_PM
  86. g_cpcLocalCaps.palette.header.capID = CAPS_ID_PM;
  87. g_cpcLocalCaps.palette.header.capSize = sizeof(g_cpcLocalCaps.palette);
  88. g_cpcLocalCaps.palette.capsColorTableCacheSize = TSHR_PM_CACHE_ENTRIES;
  89. //
  90. // PROTCAPS_BITMAPCACHE
  91. //
  92. g_cpcLocalCaps.bitmaps.header.capID = CAPS_ID_BITMAPCACHE;
  93. g_cpcLocalCaps.bitmaps.header.capSize = sizeof(g_cpcLocalCaps.bitmaps);
  94. //
  95. // SEND BITMAP CACHE
  96. //
  97. // The cache is now more in line with what the display driver is doing.
  98. // The memory size for medium/large is the same. But large bitmaps are
  99. // 4x bigger, so there are 1/4 as many. The # of small bitmaps is the
  100. // same as the # of medium bitmaps. Since small bitmaps are 1/4 the
  101. // size, only 1/4 as much memory is used.
  102. //
  103. if (g_sbcEnabled)
  104. {
  105. UINT maxSendBPP;
  106. ASSERT(g_asbcShuntBuffers[SBC_MEDIUM_TILE_INDEX]);
  107. ASSERT(g_asbcShuntBuffers[SBC_LARGE_TILE_INDEX]);
  108. g_cpcLocalCaps.bitmaps.sender.capsSmallCacheNumEntries =
  109. (TSHR_UINT16)g_asbcShuntBuffers[SBC_MEDIUM_TILE_INDEX]->numEntries;
  110. g_cpcLocalCaps.bitmaps.sender.capsMediumCacheNumEntries =
  111. (TSHR_UINT16)g_asbcShuntBuffers[SBC_MEDIUM_TILE_INDEX]->numEntries;
  112. g_cpcLocalCaps.bitmaps.sender.capsLargeCacheNumEntries =
  113. (TSHR_UINT16)g_asbcShuntBuffers[SBC_LARGE_TILE_INDEX]->numEntries;
  114. if (g_usrScreenBPP >= 24)
  115. {
  116. maxSendBPP = 24;
  117. }
  118. else
  119. {
  120. maxSendBPP = 8;
  121. }
  122. g_cpcLocalCaps.bitmaps.sender.capsSmallCacheCellSize =
  123. MP_CACHE_CELLSIZE(MP_SMALL_TILE_WIDTH, MP_SMALL_TILE_WIDTH,
  124. maxSendBPP);
  125. g_cpcLocalCaps.bitmaps.sender.capsMediumCacheCellSize =
  126. MP_CACHE_CELLSIZE(MP_MEDIUM_TILE_WIDTH, MP_MEDIUM_TILE_HEIGHT,
  127. maxSendBPP);
  128. g_cpcLocalCaps.bitmaps.sender.capsLargeCacheCellSize =
  129. MP_CACHE_CELLSIZE(MP_LARGE_TILE_WIDTH, MP_LARGE_TILE_HEIGHT,
  130. maxSendBPP);
  131. }
  132. else
  133. {
  134. //
  135. // We can't use sizes of zero, 2.x nodes will fail if we do. But
  136. // we can use a tiny number so they don't allocate huge hunks of
  137. // memory for no reason. And 3.0 will treat '1' like '0'.
  138. //
  139. g_cpcLocalCaps.bitmaps.sender.capsSmallCacheNumEntries = 1;
  140. g_cpcLocalCaps.bitmaps.sender.capsSmallCacheCellSize = 1;
  141. g_cpcLocalCaps.bitmaps.sender.capsMediumCacheNumEntries = 1;
  142. g_cpcLocalCaps.bitmaps.sender.capsMediumCacheCellSize = 1;
  143. g_cpcLocalCaps.bitmaps.sender.capsLargeCacheNumEntries = 1;
  144. g_cpcLocalCaps.bitmaps.sender.capsLargeCacheCellSize = 1;
  145. }
  146. TRACE_OUT(("SBC small cache: %d entries, size %d",
  147. g_cpcLocalCaps.bitmaps.sender.capsSmallCacheNumEntries,
  148. g_cpcLocalCaps.bitmaps.sender.capsSmallCacheCellSize));
  149. TRACE_OUT(("SBC medium cache: %d entries, size %d",
  150. g_cpcLocalCaps.bitmaps.sender.capsMediumCacheNumEntries,
  151. g_cpcLocalCaps.bitmaps.sender.capsMediumCacheCellSize));
  152. TRACE_OUT(("SBC large cache: %d entries, size %d",
  153. g_cpcLocalCaps.bitmaps.sender.capsLargeCacheNumEntries,
  154. g_cpcLocalCaps.bitmaps.sender.capsLargeCacheCellSize));
  155. //
  156. // RECEIVE caps are obsolete with 3.0; receivers simply look at the
  157. // sender's attributes. So just fill in the MAX possible. 2.x remotes
  158. // will take the min of themselves and everybody else's receiver caps.
  159. //
  160. g_cpcLocalCaps.bitmaps.receiver.capsSmallCacheNumEntries = 0x7FFF;
  161. g_cpcLocalCaps.bitmaps.receiver.capsSmallCacheCellSize = 0x7FFF;
  162. g_cpcLocalCaps.bitmaps.receiver.capsMediumCacheNumEntries = 0x7FFF;
  163. g_cpcLocalCaps.bitmaps.receiver.capsMediumCacheCellSize = 0x7FFF;
  164. g_cpcLocalCaps.bitmaps.receiver.capsLargeCacheNumEntries = 0x7FFF;
  165. g_cpcLocalCaps.bitmaps.receiver.capsLargeCacheCellSize = 0x7FFF;
  166. //
  167. // PROTCAPS_ORDERS
  168. //
  169. g_cpcLocalCaps.orders.header.capID = CAPS_ID_ORDERS;
  170. g_cpcLocalCaps.orders.header.capSize = sizeof(g_cpcLocalCaps.orders);
  171. //
  172. // Fill in the SaveBitmap capabilities.
  173. //
  174. g_cpcLocalCaps.orders.capsSaveBitmapSize = TSHR_SSI_BITMAP_SIZE;
  175. g_cpcLocalCaps.orders.capsSaveBitmapXGranularity = TSHR_SSI_BITMAP_X_GRANULARITY;
  176. g_cpcLocalCaps.orders.capsSaveBitmapYGranularity = TSHR_SSI_BITMAP_Y_GRANULARITY;
  177. g_cpcLocalCaps.orders.capsSendSaveBitmapSize = g_cpcLocalCaps.orders.capsSaveBitmapSize;
  178. g_cpcLocalCaps.orders.capsReceiveSaveBitmapSize = g_cpcLocalCaps.orders.capsSaveBitmapSize;
  179. //
  180. // We support
  181. // * R20 Signatures (cell heights, better matching)
  182. // * Aspect matching
  183. // * Charset/code page matching
  184. // * Baseline text orders
  185. // * Em Heights
  186. // * DeltaX arrays for simulation if font not on remote
  187. //
  188. //
  189. // BOGUS LAURABU BUGBUG
  190. //
  191. // Baseline text orders not yet supported in Win95. But that's OK,
  192. // we don't mark any orders we generate on that platform with
  193. // NF_BASELINE, so they aren't treated as such.
  194. //
  195. g_cpcLocalCaps.orders.capsfFonts = CAPS_FONT_R20_SIGNATURE |
  196. CAPS_FONT_ASPECT |
  197. CAPS_FONT_CODEPAGE |
  198. CAPS_FONT_ALLOW_BASELINE |
  199. CAPS_FONT_EM_HEIGHT |
  200. CAPS_FONT_OLD_NEED_X |
  201. CAPS_FONT_NEED_X_SOMETIMES;
  202. //
  203. // Fill in which orders we support.
  204. //
  205. for (i = 0; i < ORD_NUM_LEVEL_1_ORDERS; i++)
  206. {
  207. //
  208. // Order indices for desktop-scrolling and memblt variants are not
  209. // to be negotiated by this mechanism... these currently consume
  210. // 3 order indices which must be excluded from this negotiation.
  211. //
  212. if ( (i == ORD_RESERVED_INDEX ) ||
  213. (i == ORD_MEMBLT_R2_INDEX ) ||
  214. (i == ORD_UNUSED_INDEX ) ||
  215. (i == ORD_MEM3BLT_R2_INDEX) )
  216. {
  217. continue;
  218. }
  219. g_cpcLocalCaps.orders.capsOrders[i] = ORD_LEVEL_1_ORDERS;
  220. }
  221. g_cpcLocalCaps.orders.capsMaxOrderlevel = ORD_LEVEL_1_ORDERS;
  222. //
  223. // Fill in encoding capabilities
  224. //
  225. //
  226. // Keep the "encoding disabled" option, it's handy for using our
  227. // protocol analyzer
  228. //
  229. COM_ReadProfInt(DBG_INI_SECTION_NAME, OE2_INI_2NDORDERENCODING,
  230. CAPS_ENCODING_DEFAULT, &property);
  231. g_cpcLocalCaps.orders.capsEncodingLevel = (TSHR_UINT16)property;
  232. g_cpcLocalCaps.orders.capsfSendScroll = FALSE;
  233. //
  234. // Get the app and desktop icons, big and small
  235. //
  236. g_hetASIcon = LoadIcon(g_asInstance, MAKEINTRESOURCE(IDI_SHAREICON));
  237. if (!g_hetASIcon)
  238. {
  239. ERROR_OUT(("HET_Init: Failed to load app icon"));
  240. DC_QUIT;
  241. }
  242. g_hetDeskIcon = LoadIcon(g_asInstance, MAKEINTRESOURCE(IDI_DESKTOPICON));
  243. if (!g_hetDeskIcon)
  244. {
  245. ERROR_OUT(("HET_Init: failed to load desktop icon"));
  246. DC_QUIT;
  247. }
  248. // Get the small icon, created, that we paint on the window bar items
  249. g_hetASIconSmall = (HICON)LoadImage(g_asInstance, MAKEINTRESOURCE(IDI_SHAREICON),
  250. IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
  251. LR_DEFAULTCOLOR);
  252. if (!g_hetASIconSmall)
  253. {
  254. ERROR_OUT(("HET_Init: Failed to load app small icon"));
  255. DC_QUIT;
  256. }
  257. g_hetDeskIconSmall = (HICON)LoadImage(g_asInstance, MAKEINTRESOURCE(IDI_DESKTOPICON),
  258. IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
  259. LR_DEFAULTCOLOR);
  260. if (!g_hetDeskIconSmall)
  261. {
  262. ERROR_OUT(("HET_Init: Failed to load desktop small icon"));
  263. DC_QUIT;
  264. }
  265. //
  266. // Get the checkmark image
  267. //
  268. g_hetCheckBitmap = LoadBitmap(NULL, MAKEINTRESOURCE(OBM_CHECK));
  269. if (!g_hetCheckBitmap)
  270. {
  271. ERROR_OUT(("HET_Init: Failed to load checkmark bitmap"));
  272. DC_QUIT;
  273. }
  274. //
  275. // Create a bolded font for shared items in the host list
  276. //
  277. GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(lf), &lf);
  278. lf.lfWeight += FW_LIGHT;
  279. g_hetSharedFont = CreateFontIndirect(&lf);
  280. if (!g_hetSharedFont)
  281. {
  282. ERROR_OUT(("HET_Init: Failed to create shared item font"));
  283. DC_QUIT;
  284. }
  285. if (g_asCanHost && !(g_asPolicies & SHP_POLICY_NOSHARING))
  286. {
  287. HET_Clear();
  288. //
  289. // Create the host UI dialog.
  290. //
  291. ASSERT(!g_asSession.hwndHostUI);
  292. ASSERT(!g_asSession.fHostUI);
  293. ASSERT(!g_asSession.fHostUIFrozen);
  294. g_asSession.hwndHostUI = CreateDialogParam(g_asInstance,
  295. MAKEINTRESOURCE(IDD_HOSTUI), NULL, HostDlgProc, 0);
  296. if (!g_asSession.hwndHostUI)
  297. {
  298. ERROR_OUT(("Failed to create hosting UI dialog"));
  299. DC_QUIT;
  300. }
  301. }
  302. rc = TRUE;
  303. DC_EXIT_POINT:
  304. DebugExitBOOL(HET_Init, rc);
  305. return(rc);
  306. }
  307. //
  308. // HET_Term()
  309. //
  310. // Cleanup hosting objects
  311. //
  312. void HET_Term(void)
  313. {
  314. DebugEntry(HET_Term);
  315. if (g_asSession.hwndHostUI)
  316. {
  317. DestroyWindow(g_asSession.hwndHostUI);
  318. g_asSession.hwndHostUI = NULL;
  319. }
  320. g_asSession.fHostUIFrozen = FALSE;
  321. g_asSession.fHostUI = FALSE;
  322. if (g_hetSharedFont != NULL)
  323. {
  324. DeleteFont(g_hetSharedFont);
  325. g_hetSharedFont = NULL;
  326. }
  327. if (g_hetCheckBitmap != NULL)
  328. {
  329. DeleteBitmap(g_hetCheckBitmap);
  330. g_hetCheckBitmap = NULL;
  331. }
  332. if (g_hetDeskIconSmall != NULL)
  333. {
  334. DestroyIcon(g_hetDeskIconSmall);
  335. g_hetDeskIconSmall = NULL;
  336. }
  337. if (g_hetDeskIcon != NULL)
  338. {
  339. DestroyIcon(g_hetDeskIcon);
  340. g_hetDeskIcon = NULL;
  341. }
  342. if (g_hetASIconSmall != NULL)
  343. {
  344. DestroyIcon(g_hetASIconSmall);
  345. g_hetASIconSmall = NULL;
  346. }
  347. if (g_hetASIcon != NULL)
  348. {
  349. DestroyIcon(g_hetASIcon);
  350. g_hetASIcon = NULL;
  351. }
  352. DebugExitVOID(HET_Term);
  353. }
  354. //
  355. // HET_IsShellThread()
  356. // Returns TRUE if thread is one of shell's special threads
  357. //
  358. BOOL HET_IsShellThread(DWORD threadID)
  359. {
  360. BOOL rc;
  361. DebugEntry(HET_IsShellThread);
  362. if ((threadID == GetWindowThreadProcessId(HET_GetShellDesktop(), NULL)) ||
  363. (threadID == GetWindowThreadProcessId(HET_GetShellTray(), NULL)))
  364. {
  365. rc = TRUE;
  366. }
  367. else
  368. {
  369. rc = FALSE;
  370. }
  371. DebugExitBOOL(HET_IsShellThread, rc);
  372. return(rc);
  373. }
  374. //
  375. // HET_IsShellWindow()
  376. // Returns TRUE if window is in same thread as tray or desktop
  377. //
  378. BOOL HET_IsShellWindow(HWND hwnd)
  379. {
  380. BOOL rc;
  381. DWORD threadID;
  382. DebugEntry(HET_IsShellWindow);
  383. threadID = GetWindowThreadProcessId(hwnd, NULL);
  384. rc = HET_IsShellThread(threadID);
  385. DebugExitBOOL(HET_IsShellWindow, rc);
  386. return(rc);
  387. }
  388. //
  389. // HET_ShareApp()
  390. // This shares an app. We have 3 types of sharing, only two
  391. // of which are supported currently:
  392. // (1) By process (normal)
  393. // (2) By thread (ConsoleNT or possibly Explorer)
  394. // (3) By window <??>
  395. //
  396. // For the first two types, we enumerate all top level windows and share
  397. // them also.
  398. //
  399. void ASShare::HET_ShareApp
  400. (
  401. WPARAM uType,
  402. LPARAM dwID
  403. )
  404. {
  405. HET_SHARE_INFO si;
  406. DebugEntry(ASShare::HET_ShareApp);
  407. //
  408. // If we're sharing the desktop, ignore this.
  409. //
  410. if (m_pasLocal->hetCount == HET_DESKTOPSHARED)
  411. {
  412. WARNING_OUT(("Can't share app; already sharing desktop"));
  413. DC_QUIT;
  414. }
  415. si.cWnds = 0;
  416. si.uType = (UINT)uType;
  417. si.dwID = (DWORD)dwID;
  418. //
  419. // We need to get setup for sharing if we aren't hosting.
  420. //
  421. if (m_pasLocal->hetCount == 0)
  422. {
  423. if (!HETStartHosting(FALSE))
  424. {
  425. ERROR_OUT(("Can't start sharing"));
  426. DC_QUIT;
  427. }
  428. }
  429. if (uType == IAS_SHARE_BYWINDOW)
  430. {
  431. HETShareCallback((HWND)dwID, (LPARAM)&si);
  432. }
  433. else
  434. {
  435. EnumWindows(HETShareCallback, (LPARAM)&si);
  436. }
  437. if (!si.cWnds)
  438. {
  439. //
  440. // Nothing happened. We couldn't find any top level windows.
  441. //
  442. if (m_pasLocal->hetCount == 0)
  443. {
  444. HETStopHosting(FALSE);
  445. }
  446. }
  447. else
  448. {
  449. HETUpdateLocalCount(m_pasLocal->hetCount + si.cWnds);
  450. }
  451. DC_EXIT_POINT:
  452. DebugExitVOID(HET_ShareApp);
  453. }
  454. //
  455. // HETShareCallback()
  456. //
  457. // This is the enumerator callback from HETShareApp(). We look for windows
  458. // matching the thread/process.
  459. //
  460. BOOL CALLBACK HETShareCallback
  461. (
  462. HWND hwnd,
  463. LPARAM lParam
  464. )
  465. {
  466. LPHET_SHARE_INFO lpsi = (LPHET_SHARE_INFO)lParam;
  467. DWORD idProcess;
  468. DWORD idThread;
  469. UINT hostType;
  470. char szClass[HET_CLASS_NAME_SIZE];
  471. DebugEntry(HETShareCallback);
  472. ASSERT(!IsBadWritePtr(lpsi, sizeof(HET_SHARE_INFO)));
  473. //
  474. // Does this window match?
  475. //
  476. idThread = GetWindowThreadProcessId(hwnd, &idProcess);
  477. // NOTE: If the window is bogus now, dwThread/dwProcess will be zero,
  478. // and will not match the ones passed in.
  479. if (lpsi->uType == IAS_SHARE_BYPROCESS)
  480. {
  481. if (idProcess != lpsi->dwID)
  482. {
  483. DC_QUIT;
  484. }
  485. TRACE_OUT(("Found window 0x%08x on process 0x%08x", hwnd, idProcess));
  486. }
  487. else if (lpsi->uType == IAS_SHARE_BYTHREAD)
  488. {
  489. if (idThread != lpsi->dwID)
  490. {
  491. DC_QUIT;
  492. }
  493. TRACE_OUT(("Found window 0x%08x on thread 0x%08x", hwnd, idThread));
  494. }
  495. //
  496. // Always skip special shell thread windows (the tray, the desktop, etc.)
  497. //
  498. if (HET_IsShellThread(idThread))
  499. {
  500. TRACE_OUT(("Skipping shell threads"));
  501. DC_QUIT;
  502. }
  503. //
  504. // Always skip menus and system tooltips, those are temporarily shared
  505. // when shown then unshared when hidden. That's because USER creates
  506. // global windows that move threads/processes as needed to use them.
  507. //
  508. // New menus being created are different, those never change task and
  509. // are treating like other windows in a shared app.
  510. //
  511. if (!GetClassName(hwnd, szClass, sizeof(szClass)))
  512. {
  513. TRACE_OUT(("Can't get class name for window 0x%08x", hwnd));
  514. DC_QUIT;
  515. }
  516. if (!lstrcmp(szClass, HET_MENU_CLASS))
  517. {
  518. TRACE_OUT(("Skipping menu popup window 0x%08x", hwnd));
  519. DC_QUIT;
  520. }
  521. if (!lstrcmp(szClass, HET_TOOLTIPS98_CLASS) ||
  522. !lstrcmp(szClass, HET_TOOLTIPSNT5_CLASS))
  523. {
  524. TRACE_OUT(("Skipping system tooltip %08lx", hwnd));
  525. DC_QUIT;
  526. }
  527. if (HET_GetHosting(hwnd))
  528. {
  529. WARNING_OUT(("Window %08lx already shared", hwnd));
  530. DC_QUIT;
  531. }
  532. hostType = HET_HOSTED_PERMANENT;
  533. if (lpsi->uType == IAS_SHARE_BYPROCESS)
  534. {
  535. hostType |= HET_HOSTED_BYPROCESS;
  536. }
  537. else if (lpsi->uType == IAS_SHARE_BYTHREAD)
  538. {
  539. hostType |= HET_HOSTED_BYTHREAD;
  540. }
  541. else if (lpsi->uType == IAS_SHARE_BYWINDOW)
  542. {
  543. hostType |= HET_HOSTED_BYWINDOW;
  544. }
  545. //
  546. // See if we can share it. This returns TRUE if success.
  547. //
  548. if (OSI_ShareWindow(hwnd, hostType, TRUE, FALSE))
  549. {
  550. lpsi->cWnds++;
  551. }
  552. DC_EXIT_POINT:
  553. DebugExitBOOL(HET_ShareCallback, TRUE);
  554. return(TRUE);
  555. }
  556. //
  557. // HET_UnshareApp()
  558. // This unshares an app. We have 3 types of sharing, only two
  559. // of which are supported currently:
  560. // (1) By process (normal)
  561. // (2) By thread (ConsoleNT or possibly Explorer)
  562. // (3) By window (temporary)
  563. //
  564. // For the first two types, we enumerate all top level windows and share
  565. // them also.
  566. //
  567. void ASShare::HET_UnshareApp
  568. (
  569. WPARAM uType,
  570. LPARAM dwID
  571. )
  572. {
  573. HET_SHARE_INFO si;
  574. DebugEntry(ASShare::HET_UnshareApp);
  575. //
  576. // If we aren't sharing apps (not sharing anything or sharing the
  577. // dekstop), ignore this.
  578. //
  579. if ((m_pasLocal->hetCount == 0) || (m_pasLocal->hetCount == HET_DESKTOPSHARED))
  580. {
  581. WARNING_OUT(("Can't unshare app; not sharing any"));
  582. DC_QUIT;
  583. }
  584. si.cWnds = 0;
  585. si.uType = (UINT)uType;
  586. si.dwID = (DWORD)dwID;
  587. if (uType == IAS_SHARE_BYWINDOW)
  588. {
  589. //
  590. // No enumeration, just this window.
  591. //
  592. HETUnshareCallback((HWND)dwID, (LPARAM)&si);
  593. }
  594. else
  595. {
  596. //
  597. // Stop sharing all windows in it.
  598. //
  599. EnumWindows(HETUnshareCallback, (LPARAM)&si);
  600. }
  601. if (si.cWnds)
  602. {
  603. HETUpdateLocalCount(m_pasLocal->hetCount - si.cWnds);
  604. }
  605. DC_EXIT_POINT:
  606. DebugExitVOID(ASShare::HET_UnshareApp);
  607. }
  608. //
  609. // HETUnshareCallback()
  610. //
  611. // This is the enumerator callback from HET_UnshareApp(). We look for windows
  612. // matching the thread/process. In this case, we don't care about menus
  613. // or explorer windows, since we assume that, from the time we shared and it
  614. // was set up properly, the window/task tracking code did the right thing.
  615. // If not, we'll wipe it out here anyway.
  616. //
  617. BOOL CALLBACK HETUnshareCallback
  618. (
  619. HWND hwnd,
  620. LPARAM lParam
  621. )
  622. {
  623. LPHET_SHARE_INFO lpsi = (LPHET_SHARE_INFO)lParam;
  624. DWORD dwProcess;
  625. DWORD dwThread;
  626. DebugEntry(HETUnshareCallback);
  627. ASSERT(!IsBadWritePtr(lpsi, sizeof(HET_SHARE_INFO)));
  628. //
  629. // Does this window match? If by window, always.
  630. //
  631. if (lpsi->uType != IAS_SHARE_BYWINDOW)
  632. {
  633. dwThread = GetWindowThreadProcessId(hwnd, &dwProcess);
  634. // NOTE: If the window is bogus now, dwThread/dwProcess will be zero,
  635. // and will not match the ones passed in.
  636. if (lpsi->uType == IAS_SHARE_BYPROCESS)
  637. {
  638. if (dwProcess != lpsi->dwID)
  639. {
  640. DC_QUIT;
  641. }
  642. TRACE_OUT(("Found window 0x%08x on process 0x%08x", hwnd, dwProcess));
  643. }
  644. else if (lpsi->uType == IAS_SHARE_BYTHREAD)
  645. {
  646. if (dwThread != lpsi->dwID)
  647. {
  648. DC_QUIT;
  649. }
  650. TRACE_OUT(("Found window 0x%08x on thread 0x%08x", hwnd, dwThread));
  651. }
  652. }
  653. //
  654. // This returns TRUE if we unshared a shared window.
  655. //
  656. if (OSI_UnshareWindow(hwnd, FALSE))
  657. {
  658. lpsi->cWnds++;
  659. }
  660. DC_EXIT_POINT:
  661. DebugExitBOOL(HETUnshareCallback, TRUE);
  662. return(TRUE);
  663. }
  664. //
  665. // HET_ShareDesktop()
  666. //
  667. void ASShare::HET_ShareDesktop(void)
  668. {
  669. ASPerson * pasT;
  670. DebugEntry(ASShare:HET_ShareDesktop);
  671. //
  672. // If we're sharing apps, ignore this.
  673. //
  674. if (m_pasLocal->hetCount != 0)
  675. {
  676. WARNING_OUT(("Ignoring share desktop request, sharing apps"));
  677. DC_QUIT;
  678. }
  679. TRACE_OUT(("HET_ShareDesktop: starting share"));
  680. if (!HETStartHosting(TRUE))
  681. {
  682. ERROR_OUT(("HET_ShareDesktop cannot start sharing desktop"));
  683. DC_QUIT;
  684. }
  685. //
  686. // Update the count of hosted entities (ie user-hosted windows)
  687. //
  688. HETUpdateLocalCount(HET_DESKTOPSHARED);
  689. //
  690. // Get the desktop(s) repainted if anybody's viewing it.
  691. //
  692. ASSERT(m_pHost);
  693. m_pHost->HET_RepaintAll();
  694. DC_EXIT_POINT:
  695. DebugExitVOID(ASShare::HET_ShareDesktop);
  696. }
  697. //
  698. // HET_UnshareAll()
  699. // Unshares everything including the desktop. If we had been sharing
  700. // apps before, we will unshare them all.
  701. //
  702. void ASShare::HET_UnshareAll(void)
  703. {
  704. DebugEntry(ASShare::HET_UnshareAll);
  705. if (m_pasLocal->hetCount != 0)
  706. {
  707. HETUpdateLocalCount(0);
  708. }
  709. DebugExitVOID(ASShare::HET_UnshareAll);
  710. }
  711. //
  712. // HET_PartyJoiningShare()
  713. //
  714. BOOL ASShare::HET_PartyJoiningShare(ASPerson * pasPerson)
  715. {
  716. BOOL rc = TRUE;
  717. DebugEntry(ASShare::HET_PartyJoiningShare);
  718. HET_CalcViewers(NULL);
  719. DebugExitBOOL(ASShare::HET_PartyJoiningShare, rc);
  720. return(rc);
  721. }
  722. //
  723. // HET_PartyLeftShare()
  724. //
  725. void ASShare::HET_PartyLeftShare(ASPerson * pasPerson)
  726. {
  727. DebugEntry(ASShare::HET_PartyLeftShare);
  728. // This guy is leaving the share, cleanup if he was sharing.
  729. ValidatePerson(pasPerson);
  730. if (pasPerson->hetCount != 0)
  731. {
  732. // This person is hosting
  733. if (pasPerson == m_pasLocal)
  734. {
  735. HETUpdateLocalCount(0);
  736. }
  737. else
  738. {
  739. HETUpdateRemoteCount(pasPerson, 0);
  740. }
  741. }
  742. //
  743. // If we're hosting, stop viewing if this is the last person in the share.
  744. //
  745. HET_CalcViewers(pasPerson);
  746. DebugExitVOID(ASShare::HET_PartyLeftShare);
  747. }
  748. //
  749. // HET_CalcViewers()
  750. //
  751. // If we or a remote is viewing our shared stuff, then we must accumulate
  752. // graphic output. If not, don't other, but keep the app tracked as necessary.
  753. //
  754. // This is called when we start to host, when somebody joins, or somebody
  755. // leaves the conference.
  756. //
  757. void ASShare::HET_CalcViewers(ASPerson * pasLeaving)
  758. {
  759. BOOL fViewers;
  760. DebugEntry(ASShare::HET_CalcViewers);
  761. fViewers = FALSE;
  762. if (m_pHost)
  763. {
  764. if (m_scfViewSelf)
  765. {
  766. fViewers = TRUE;
  767. }
  768. else if (!pasLeaving)
  769. {
  770. //
  771. // Nobody is leaving, so just check if anybody else is in the
  772. // share.
  773. //
  774. if (m_pasLocal->pasNext)
  775. {
  776. fViewers = TRUE;
  777. }
  778. }
  779. else if (pasLeaving->pasNext || (m_pasLocal->pasNext != pasLeaving))
  780. {
  781. //
  782. // Sombody is leaving.
  783. // The person leaving isn't the only other one besides us in the
  784. // share, since there are others after it or before it in the
  785. // members linked list.
  786. //
  787. fViewers = TRUE;
  788. }
  789. }
  790. if (fViewers != m_hetViewers)
  791. {
  792. HET_VIEWER viewer;
  793. m_hetViewers = fViewers;
  794. viewer.viewersPresent = fViewers;
  795. OSI_FunctionRequest(HET_ESC_VIEWER, (LPOSI_ESCAPE_HEADER)&viewer,
  796. sizeof(viewer));
  797. }
  798. DebugExitVOID(ASShare::HET_CalcViewers);
  799. }
  800. //
  801. // HET_ReceivedPacket()
  802. //
  803. void ASShare::HET_ReceivedPacket
  804. (
  805. ASPerson * pasPerson,
  806. PS20DATAPACKET pPacket
  807. )
  808. {
  809. PHETPACKET pHETPacket;
  810. DebugEntry(ASShare:;HET_ReceivedPacket);
  811. ValidatePerson(pasPerson);
  812. pHETPacket = (PHETPACKET)pPacket;
  813. switch (pHETPacket->msg)
  814. {
  815. case HET_MSG_NUMHOSTED:
  816. HETUpdateRemoteCount(pasPerson, pHETPacket->hostState);
  817. break;
  818. default:
  819. ERROR_OUT(("Unknown HET packet type %u from [%d]", pHETPacket->msg,
  820. pasPerson->mcsID));
  821. break;
  822. }
  823. DebugExitVOID(ASShare::HET_ReceivedPacket);
  824. }
  825. //
  826. // HET_SyncCommon()
  827. //
  828. // Called when somebody joins a share, after it is fully joined. We repaint
  829. // all shared windows and send the current hosted top-level count.
  830. //
  831. // Also called when sharing, and somebody joins later.
  832. //
  833. // NOTE that some of the resets don't do anything when are just starting to
  834. // share. But all are quick and benign.
  835. //
  836. void ASHost::HET_SyncCommon(void)
  837. {
  838. OSI_ESCAPE_HEADER osi;
  839. DebugEntry(ASHost::HET_SyncCommon);
  840. m_upfSyncTokenRequired = TRUE;
  841. BA_SyncOutgoing();
  842. OE2_SyncOutgoing(); // To reset order encoding
  843. OA_SyncOutgoing(); // To clear pending orders
  844. SBC_SyncOutgoing(); // To clear bitmap cache
  845. PM_SyncOutgoing(); // To clear palette cache
  846. SSI_SyncOutgoing(); // To reset savebits orders
  847. SWL_SyncOutgoing(); // To reset shared window list
  848. AWC_SyncOutgoing(); // To send active window
  849. CM_SyncOutgoing(); // To send cursor shape/pos
  850. //
  851. // Tell the driver we are syncing
  852. //
  853. OSI_FunctionRequest(OSI_ESC_SYNC_NOW, &osi, sizeof(osi));
  854. DebugExitVOID(ASHost::HET_SyncCommon);
  855. }
  856. //
  857. // HET_SyncAlreadyHosting()
  858. // Called in a sync when we are already hosting and somebody joins call
  859. //
  860. void ASHost::HET_SyncAlreadyHosting(void)
  861. {
  862. DebugEntry(ASHost::HET_SyncAlreadyHosting);
  863. HET_RepaintAll();
  864. // Send out the current hosted count
  865. m_pShare->m_hetRetrySendState = TRUE;
  866. DebugExitVOID(ASHost::HET_SyncAlreadyHosting);
  867. }
  868. //
  869. // HET_RepaintAll()
  870. //
  871. // Repaints all shared stuff if there's at least two people in the share...
  872. //
  873. void ASHost::HET_RepaintAll(void)
  874. {
  875. DebugEntry(ASHost::HET_RepaintAll);
  876. ASSERT(m_pShare);
  877. ASSERT(m_pShare->m_pasLocal);
  878. if (m_pShare->m_hetViewers)
  879. {
  880. //
  881. // Only repaint if somebody's viewing
  882. //
  883. if (m_pShare->m_pasLocal->hetCount == HET_DESKTOPSHARED)
  884. {
  885. // Desktop sharing, so repaint desktop(s)
  886. USR_RepaintWindow(NULL);
  887. OSI_RepaintDesktop(); //special repaint for winlogon desktop
  888. }
  889. else
  890. {
  891. // App sharing, so repaint shared apps
  892. EnumWindows(HETRepaintWindow, (LPARAM)m_pShare);
  893. }
  894. }
  895. DebugExitVOID(ASHost::HET_RepaintAll);
  896. }
  897. //
  898. // HET_Periodic()
  899. //
  900. void ASShare::HET_Periodic(void)
  901. {
  902. DebugEntry(ASShare::HET_Periodic);
  903. if (m_hetRetrySendState)
  904. {
  905. TRACE_OUT(( "Retry sending hosted count"));
  906. HETSendLocalCount();
  907. }
  908. DebugExitVOID(ASShare::HET_Periodic);
  909. }
  910. //
  911. // HET_WindowIsHosted - see het.h
  912. //
  913. BOOL ASShare::HET_WindowIsHosted(HWND hwnd)
  914. {
  915. BOOL rc = FALSE;
  916. HWND hwndParent;
  917. DebugEntry(ASShare::HET_WindowIsHosted);
  918. //
  919. // Desktop sharing: everything is shared
  920. //
  921. if (m_pasLocal->hetCount == HET_DESKTOPSHARED)
  922. {
  923. rc = TRUE;
  924. DC_QUIT;
  925. }
  926. if (!hwnd)
  927. {
  928. TRACE_OUT(("NULL window passed to HET_WindowIsHosted"));
  929. DC_QUIT;
  930. }
  931. //
  932. // Walk up to the top level window this one is part of
  933. //
  934. while (GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD)
  935. {
  936. hwndParent = GetParent(hwnd);
  937. if (hwndParent == GetDesktopWindow())
  938. break;
  939. hwnd = hwndParent;
  940. }
  941. rc = (BOOL)HET_GetHosting(hwnd);
  942. DC_EXIT_POINT:
  943. DebugExitBOOL(ASShare::HET_WindowIsHosted, rc);
  944. return(rc);
  945. }
  946. //
  947. // HET_HandleNewTopLevel()
  948. // Called when a shared top level window is shown or hidden. We update
  949. // our local top level count.
  950. //
  951. void ASShare::HET_HandleNewTopLevel(BOOL fShown)
  952. {
  953. DebugEntry(ASShare::HET_HandleNewTopLevel);
  954. //
  955. // If we aren't sharing any apps (not sharing at all or sharing the
  956. // desktop), ignore this.
  957. //
  958. if ((m_pasLocal->hetCount == 0) || (m_pasLocal->hetCount == HET_DESKTOPSHARED))
  959. {
  960. WARNING_OUT(("Ignoring new hosted notification; count is 0x%04x",
  961. m_pasLocal->hetCount));
  962. DC_QUIT;
  963. }
  964. if (fShown)
  965. HETUpdateLocalCount(m_pasLocal->hetCount + 1);
  966. else
  967. HETUpdateLocalCount(m_pasLocal->hetCount - 1);
  968. DC_EXIT_POINT:
  969. DebugExitVOID(ASShare::HET_HandleNewTopLevel);
  970. }
  971. //
  972. // HET_HandleRecountTopLevel()
  973. // Called when a massive change in the top level visible count occurs, so
  974. // that we can just set the new total at once, rather than handle
  975. // individual inc/dec messages.
  976. //
  977. void ASShare::HET_HandleRecountTopLevel(UINT uNewCount)
  978. {
  979. DebugEntry(ASShare::HET_HandleRecountTopLevel);
  980. //
  981. // If we aren't sharing any apps (not sharing at all or sharing the
  982. // desktop), ignore this.
  983. //
  984. if ((m_pasLocal->hetCount == 0) || (m_pasLocal->hetCount == HET_DESKTOPSHARED))
  985. {
  986. WARNING_OUT(("Ignoring new hosted notification; count is 0x%04x",
  987. m_pasLocal->hetCount));
  988. DC_QUIT;
  989. }
  990. HETUpdateLocalCount(uNewCount);
  991. DC_EXIT_POINT:
  992. DebugExitVOID(ASShare::HET_HandleRecountTopLevel);
  993. }
  994. //
  995. // HETStartHosting()
  996. //
  997. // Called when we are about to begin sharing windows. fDesktop is TRUE if
  998. // we are sharing the entire desktop, FALSE if just individual windows.
  999. //
  1000. BOOL ASShare::HETStartHosting(BOOL fDesktop)
  1001. {
  1002. BOOL rc = FALSE;
  1003. DebugEntry(ASShare::HETStartHosting);
  1004. //
  1005. // Create the hosting object
  1006. //
  1007. ASSERT(!m_pHost);
  1008. m_pHost = new ASHost;
  1009. if (!m_pHost)
  1010. {
  1011. ERROR_OUT(("HETStartHosting: couldn't create m_pHost"));
  1012. DC_QUIT;
  1013. }
  1014. ZeroMemory(m_pHost, sizeof(*(m_pHost)));
  1015. SET_STAMP(m_pHost, HOST);
  1016. //
  1017. // Init hosting
  1018. //
  1019. if (!m_pHost->HET_HostStarting(this))
  1020. {
  1021. ERROR_OUT(("Failed to init hosting for local person"));
  1022. DC_QUIT;
  1023. }
  1024. //
  1025. // Start tracking graphics/windows
  1026. //
  1027. if (fDesktop)
  1028. {
  1029. HET_SHARE_DESKTOP hdr;
  1030. //
  1031. // Shortcut directly to display driver. No need to track windows
  1032. // since everything will be shared.
  1033. //
  1034. if (!OSI_FunctionRequest(HET_ESC_SHARE_DESKTOP, (LPOSI_ESCAPE_HEADER)&hdr, sizeof(hdr)))
  1035. {
  1036. ERROR_OUT(("HET_ESC_SHARE_DESKTOP failed"));
  1037. DC_QUIT;
  1038. }
  1039. }
  1040. else
  1041. {
  1042. //
  1043. // Start tracking windows.
  1044. //
  1045. if (!OSI_StartWindowTracking())
  1046. {
  1047. ERROR_OUT(( "Failed to install window tracking hooks"));
  1048. DC_QUIT;
  1049. }
  1050. }
  1051. if (m_scfViewSelf && !HET_ViewStarting(m_pasLocal))
  1052. {
  1053. ERROR_OUT(("ViewSelf option is on, but can't create ASView data"));
  1054. DC_QUIT;
  1055. }
  1056. HET_CalcViewers(NULL);
  1057. rc = TRUE;
  1058. DC_EXIT_POINT:
  1059. //
  1060. // Return to caller
  1061. //
  1062. DebugExitBOOL(ASShare::HETStartHosting, rc);
  1063. return(rc);
  1064. }
  1065. //
  1066. //
  1067. // Name: HETStopHosting
  1068. //
  1069. // Description: Called when the last hosted window is unshared
  1070. // ALWAYS CALL THIS AFTER the "hethostedTopLevel" count is 0.
  1071. //
  1072. // Params: none
  1073. //
  1074. //
  1075. void ASShare::HETStopHosting(BOOL fDesktop)
  1076. {
  1077. DebugEntry(ASShare::HETStopHosting);
  1078. m_hetViewers = FALSE;
  1079. //
  1080. // Stop tracking graphics/windows. This will stop viewing, then uninstall
  1081. // hooks.
  1082. //
  1083. if (fDesktop)
  1084. {
  1085. HET_UNSHARE_DESKTOP hdr;
  1086. //
  1087. // There is no window tracking, just shortcut directly to the
  1088. // display driver.
  1089. //
  1090. OSI_FunctionRequest(HET_ESC_UNSHARE_DESKTOP, (LPOSI_ESCAPE_HEADER)&hdr, sizeof(hdr));
  1091. }
  1092. else
  1093. {
  1094. //
  1095. // Unshare any remaining shared windows
  1096. //
  1097. HET_Clear();
  1098. OSI_StopWindowTracking();
  1099. }
  1100. //
  1101. // Tell areas we are finished hosting
  1102. //
  1103. if (m_pHost)
  1104. {
  1105. //
  1106. // If we're viewing ourself, kill the view first
  1107. //
  1108. if (m_scfViewSelf)
  1109. {
  1110. HET_ViewEnded(m_pasLocal);
  1111. }
  1112. m_pHost->HET_HostEnded();
  1113. //
  1114. // Delete host object
  1115. //
  1116. delete m_pHost;
  1117. m_pHost = NULL;
  1118. }
  1119. //
  1120. // Return to caller
  1121. //
  1122. DebugExitVOID(ASShare::HETStopHosting);
  1123. }
  1124. //
  1125. // HETSendLocalCount()
  1126. // This sends the hosting count to remotes.
  1127. // * If zero, we are not sharing
  1128. // * If one, we are sharing apps
  1129. // * If 0xFFFF, we are sharing desktop
  1130. //
  1131. // Note that we used to send the real count of top level windows, so every
  1132. // time a new window came or went, we would broadcast a packet. But
  1133. // remotes only care when the value goes from zero to non-zero or back,
  1134. // and when non-zero if it's the special desktop value or not. So don't
  1135. // repeatedly broadcast values remotes don't care about!
  1136. //
  1137. void ASShare::HETSendLocalCount(void)
  1138. {
  1139. PHETPACKET pHETPacket;
  1140. #ifdef _DEBUG
  1141. UINT sentSize;
  1142. #endif // _DEBUG
  1143. DebugEntry(ASShare::HETSendLocalCount);
  1144. //
  1145. // Allocate a packet for the HET data.
  1146. //
  1147. pHETPacket = (PHETPACKET)SC_AllocPkt(PROT_STR_MISC, g_s20BroadcastID,
  1148. sizeof(HETPACKET));
  1149. if (!pHETPacket)
  1150. {
  1151. WARNING_OUT(("Failed to alloc HET host packet"));
  1152. m_hetRetrySendState = TRUE;
  1153. DC_QUIT;
  1154. }
  1155. //
  1156. // Packet successfully allocated. Fill in the data and send it.
  1157. //
  1158. pHETPacket->header.data.dataType = DT_HET;
  1159. pHETPacket->msg = HET_MSG_NUMHOSTED;
  1160. switch (m_pasLocal->hetCount)
  1161. {
  1162. case 0:
  1163. // Not hosting
  1164. pHETPacket->hostState = HET_NOTHOSTING;
  1165. break;
  1166. case HET_DESKTOPSHARED:
  1167. // Sharing desktop - 3.0 only
  1168. pHETPacket->header.data.dataType = DT_HET30;
  1169. pHETPacket->hostState = HET_DESKTOPSHARED;
  1170. break;
  1171. default:
  1172. // Sharing apps
  1173. pHETPacket->hostState = HET_APPSSHARED;
  1174. break;
  1175. }
  1176. //
  1177. // Compress and send the packet.
  1178. //
  1179. #ifdef _DEBUG
  1180. sentSize =
  1181. #endif // _DEBUG
  1182. DCS_CompressAndSendPacket(PROT_STR_MISC, g_s20BroadcastID,
  1183. &(pHETPacket->header), sizeof(*pHETPacket));
  1184. TRACE_OUT(("HET packet size: %08d, sent %08d", sizeof(*pHETPacket), sentSize));
  1185. TRACE_OUT(("Sent new HET packet (%d)", m_pasLocal->hetCount));
  1186. m_hetRetrySendState = FALSE;
  1187. //
  1188. // Return to caller
  1189. //
  1190. DC_EXIT_POINT:
  1191. DebugExitVOID(ASShare::HETSendLocalCount);
  1192. }
  1193. //
  1194. // HETUpdateLocalCount()
  1195. //
  1196. void ASShare::HETUpdateLocalCount(UINT newCount)
  1197. {
  1198. UINT oldCount;
  1199. DebugEntry(ASShare::HETUpdateLocalCount);
  1200. oldCount = m_pasLocal->hetCount;
  1201. m_pasLocal->hetCount = newCount;
  1202. if ((oldCount == 0) && (newCount != 0))
  1203. {
  1204. SendMessage(g_asSession.hwndHostUI, HOST_MSG_HOSTSTART, 0, 0);
  1205. //
  1206. // Don't bother sending net packets if nobody is viewing
  1207. //
  1208. if (m_hetViewers)
  1209. {
  1210. HETSendLocalCount();
  1211. }
  1212. HETCheckSharing(TRUE);
  1213. }
  1214. else if ((oldCount != 0) && (newCount == 0))
  1215. {
  1216. if (m_hetViewers)
  1217. {
  1218. //
  1219. // Ending host, desktop or apps
  1220. //
  1221. HETSendLocalCount();
  1222. }
  1223. //
  1224. // The local guy is stopping sharing.
  1225. //
  1226. HETStopHosting(oldCount == HET_DESKTOPSHARED);
  1227. ASSERT(IsWindow(g_asSession.hwndHostUI));
  1228. SendMessage(g_asSession.hwndHostUI, HOST_MSG_HOSTEND, 0, 0);
  1229. HETCheckSharing(FALSE);
  1230. }
  1231. ASSERT(IsWindow(g_asSession.hwndHostUI));
  1232. SendMessage(g_asSession.hwndHostUI, HOST_MSG_UPDATELIST, 0, 0);
  1233. DebugExitVOID(ASShare::HETUpdateLocalCount);
  1234. }
  1235. //
  1236. // HETUpdateRemoteCount()
  1237. //
  1238. // Updates the count of shared top level windows from a remote, and notifies
  1239. // the UI on transition from/to zero if a remote. If local, kills the share.
  1240. //
  1241. void ASShare::HETUpdateRemoteCount
  1242. (
  1243. ASPerson * pasPerson,
  1244. UINT newCount
  1245. )
  1246. {
  1247. UINT oldCount;
  1248. DebugEntry(ASShare::HETUpdateRemoteCount);
  1249. ValidatePerson(pasPerson);
  1250. ASSERT(pasPerson != m_pasLocal);
  1251. oldCount = pasPerson->hetCount;
  1252. pasPerson->hetCount = newCount;
  1253. TRACE_OUT(("HETUpdateRemoteCount: Person [%d] old %d, new %d",
  1254. pasPerson->mcsID, oldCount, newCount));
  1255. //
  1256. // We generate events for remote people if
  1257. // * They were sharing but now they aren't
  1258. // * There weren't sharing but now they are
  1259. //
  1260. if ((oldCount == 0) && (newCount != 0))
  1261. {
  1262. //
  1263. // The remote dude started to share
  1264. //
  1265. if (!HET_ViewStarting(pasPerson))
  1266. {
  1267. ERROR_OUT(("HET_ViewStarting failed; pretending remote not sharing"));
  1268. pasPerson->hetCount = 0;
  1269. HET_ViewEnded(pasPerson);
  1270. }
  1271. else
  1272. {
  1273. HETCheckSharing(TRUE);
  1274. }
  1275. }
  1276. else if ((oldCount != 0) && (newCount == 0))
  1277. {
  1278. //
  1279. // The remote dude stopped sharing. Notify the UI also.
  1280. //
  1281. HET_ViewEnded(pasPerson);
  1282. HETCheckSharing(FALSE);
  1283. }
  1284. DebugExitVOID(ASShare::HETUpdateRemoteCount);
  1285. }
  1286. //
  1287. // HETCheckSharing()
  1288. // Called when any member of the conference (local or remote) transitions
  1289. // to/from sharing. When the first person has shared something, we notify
  1290. // the UI. When the last person has stopped sharing, we kill the share which
  1291. // will notify the UI.
  1292. //
  1293. void ASShare::HETCheckSharing(BOOL fStarting)
  1294. {
  1295. DebugEntry(ASShare::HETCheckSharing);
  1296. if (fStarting)
  1297. {
  1298. ++m_hetHostCount;
  1299. if (m_hetHostCount == 1)
  1300. {
  1301. // First host started
  1302. TRACE_OUT(("First person started hosting"));
  1303. DCS_NotifyUI(SH_EVT_SHARING_STARTED, 0, 0);
  1304. }
  1305. }
  1306. else
  1307. {
  1308. ASSERT(m_hetHostCount > 0);
  1309. --m_hetHostCount;
  1310. if (m_hetHostCount == 0)
  1311. {
  1312. //
  1313. // Last host stopped sharing -- end share if we're not cleaning
  1314. // up after the fact. But don't do it NOW, post a message.
  1315. // We may have come in here because the share is ending already.
  1316. //
  1317. PostMessage(g_asMainWindow, DCS_KILLSHARE_MSG, 0, 0);
  1318. }
  1319. }
  1320. DebugExitVOID(ASShare::HETCheckSharing);
  1321. }
  1322. //
  1323. // HET_HostStarting()
  1324. //
  1325. // Called when we start to host applications. This creates our host data
  1326. // then calls the component HostStarting() routines
  1327. //
  1328. BOOL ASHost::HET_HostStarting(ASShare * pShare)
  1329. {
  1330. BOOL rc = FALSE;
  1331. DebugEntry(ASHost::HET_HostStarting);
  1332. // Set back pointer to share
  1333. m_pShare = pShare;
  1334. //
  1335. // Turn effects off
  1336. //
  1337. HET_SetGUIEffects(FALSE, &m_hetEffects);
  1338. OSI_SetGUIEffects(FALSE);
  1339. //
  1340. // Now call HostStarting() routines
  1341. //
  1342. if (!USR_HostStarting())
  1343. {
  1344. ERROR_OUT(("USR_HostStarting failed"));
  1345. DC_QUIT;
  1346. }
  1347. if (!OE2_HostStarting())
  1348. {
  1349. ERROR_OUT(("OE2_HostStarting failed"));
  1350. DC_QUIT;
  1351. }
  1352. if (!SBC_HostStarting())
  1353. {
  1354. ERROR_OUT(("SBC_HostStarting failed"));
  1355. DC_QUIT;
  1356. }
  1357. if (!CM_HostStarting())
  1358. {
  1359. ERROR_OUT(("CM_HostStarting failed"));
  1360. DC_QUIT;
  1361. }
  1362. if (!SSI_HostStarting())
  1363. {
  1364. ERROR_OUT(("SSI_HostStarting failed"));
  1365. DC_QUIT;
  1366. }
  1367. if (!PM_HostStarting())
  1368. {
  1369. ERROR_OUT(("PM_HostStarting failed"));
  1370. DC_QUIT;
  1371. }
  1372. if (!SWL_HostStarting())
  1373. {
  1374. ERROR_OUT(("SWL_HostStarting failed"));
  1375. DC_QUIT;
  1376. }
  1377. if (!VIEW_HostStarting())
  1378. {
  1379. ERROR_OUT(("VIEW_HostStarting failed"));
  1380. DC_QUIT;
  1381. }
  1382. //
  1383. // Now reset OUTGOING info. 2.x nodes do not; that's why we have to
  1384. // hang on to RBC, OD2, CM, PM data for them. When 2.x compat is gone,
  1385. // we can move ASPerson data in to ASView, which is only around while
  1386. // the person is in fact hosting.
  1387. //
  1388. OA_LocalHostReset();
  1389. //
  1390. // Reset OUTGOING data.
  1391. // Note corresponding cleanup for 3.0 nodes
  1392. // in CM, OD2, RBC, and PM.
  1393. // Note that we don't need to reset SSI incoming goop, since we will
  1394. // clear all pending orders and are invalidating everything shared
  1395. // from scratch. There will be no reference to a previous savebits.
  1396. //
  1397. HET_SyncCommon();
  1398. rc = TRUE;
  1399. DC_EXIT_POINT:
  1400. DebugExitBOOL(ASHost::HET_HostStarting, rc);
  1401. return(rc);
  1402. }
  1403. //
  1404. // HET_HostEnded()
  1405. //
  1406. // Called when we stop hosting applications.
  1407. //
  1408. void ASHost::HET_HostEnded(void)
  1409. {
  1410. DebugEntry(ASHost::HET_HostEnded);
  1411. //
  1412. // Call HostEnded() routines
  1413. //
  1414. CA_HostEnded();
  1415. SWL_HostEnded();
  1416. PM_HostEnded();
  1417. CM_HostEnded();
  1418. SBC_HostEnded();
  1419. OE2_HostEnded();
  1420. USR_HostEnded();
  1421. //
  1422. // Restore windows animation.
  1423. //
  1424. HET_SetGUIEffects(TRUE, &m_hetEffects);
  1425. OSI_SetGUIEffects(TRUE);
  1426. DebugExitVOID(ASHost::HET_HostEnded);
  1427. }
  1428. //
  1429. // HET_ViewStarting()
  1430. //
  1431. // Called to create the data needed to view somebody who is hosting.
  1432. //
  1433. BOOL ASShare::HET_ViewStarting(ASPerson * pasPerson)
  1434. {
  1435. BOOL rc = FALSE;
  1436. DebugEntry(ASShare::HET_ViewStarting);
  1437. ValidatePerson(pasPerson);
  1438. //
  1439. // Create ASView object
  1440. //
  1441. ASSERT(!pasPerson->m_pView);
  1442. // Allocate VIEW structure
  1443. pasPerson->m_pView = new ASView;
  1444. if (!pasPerson->m_pView)
  1445. {
  1446. // Abject, total, failure.
  1447. ERROR_OUT(("HET_ViewStarting: Couldn't allocate ASView for [%d]", pasPerson->mcsID));
  1448. DC_QUIT;
  1449. }
  1450. ZeroMemory(pasPerson->m_pView, sizeof(*(pasPerson->m_pView)));
  1451. SET_STAMP(pasPerson->m_pView, VIEW);
  1452. //
  1453. // Now call ViewStarting routines
  1454. //
  1455. if (!USR_ViewStarting(pasPerson))
  1456. {
  1457. ERROR_OUT(("USR_ViewStarting failed"));
  1458. DC_QUIT;
  1459. }
  1460. if (!OD2_ViewStarting(pasPerson))
  1461. {
  1462. ERROR_OUT(("OD2_ViewStarting failed"));
  1463. DC_QUIT;
  1464. }
  1465. if (!OD_ViewStarting(pasPerson))
  1466. {
  1467. ERROR_OUT(("OD_ViewStarting failed"));
  1468. DC_QUIT;
  1469. }
  1470. if (!RBC_ViewStarting(pasPerson))
  1471. {
  1472. ERROR_OUT(("RBC_ViewStarting failed"));
  1473. DC_QUIT;
  1474. }
  1475. if (!CM_ViewStarting(pasPerson))
  1476. {
  1477. ERROR_OUT(("CM_ViewStarting failed"));
  1478. DC_QUIT;
  1479. }
  1480. if (!SSI_ViewStarting(pasPerson))
  1481. {
  1482. ERROR_OUT(("SSI_ViewStarting failed"));
  1483. DC_QUIT;
  1484. }
  1485. if (!PM_ViewStarting(pasPerson))
  1486. {
  1487. ERROR_OUT(("PM_ViewStarting failed"));
  1488. DC_QUIT;
  1489. }
  1490. if (!VIEW_ViewStarting(pasPerson))
  1491. {
  1492. ERROR_OUT(("VIEW_ViewStarting failed"));
  1493. DC_QUIT;
  1494. }
  1495. if (!CA_ViewStarting(pasPerson))
  1496. {
  1497. ERROR_OUT(("CA_ViewStarting failed"));
  1498. DC_QUIT;
  1499. }
  1500. rc = TRUE;
  1501. DC_EXIT_POINT:
  1502. DebugExitBOOL(ASShare::HET_ViewStarting, rc);
  1503. return(rc);
  1504. }
  1505. //
  1506. // HET_ViewEnded()
  1507. //
  1508. // Called when we stop viewing a host
  1509. //
  1510. void ASShare::HET_ViewEnded(ASPerson * pasPerson)
  1511. {
  1512. DebugEntry(ASShare::HET_ViewEnded);
  1513. ValidatePerson(pasPerson);
  1514. if (pasPerson->m_pView)
  1515. {
  1516. //
  1517. // Call the component ViewEnded routines
  1518. //
  1519. CA_ViewEnded(pasPerson);
  1520. VIEW_ViewEnded(pasPerson);
  1521. PM_ViewEnded(pasPerson);
  1522. SSI_ViewEnded(pasPerson);
  1523. CM_ViewEnded(pasPerson);
  1524. RBC_ViewEnded(pasPerson);
  1525. OD_ViewEnded(pasPerson);
  1526. OD2_ViewEnded(pasPerson);
  1527. USR_ViewEnded(pasPerson);
  1528. delete pasPerson->m_pView;
  1529. pasPerson->m_pView = NULL;
  1530. }
  1531. DebugExitVOID(ASShare::HET_ViewEnded);
  1532. }
  1533. //
  1534. // HETUnshareAllWindows()
  1535. // EnumWindows() callback, to make sure when you exit a share on the local
  1536. // machine, we aren't left with any properties on top level windows.
  1537. //
  1538. BOOL CALLBACK HETUnshareAllWindows(HWND hwnd, LPARAM lParam)
  1539. {
  1540. DebugEntry(HETUnshareAllWindows);
  1541. HET_ClearHosting(hwnd);
  1542. DebugExitVOID(HETUnshareAllWindows);
  1543. return(TRUE);
  1544. }
  1545. //
  1546. // HET_Clear()
  1547. //
  1548. void HET_Clear(void)
  1549. {
  1550. HET_UNSHARE_ALL req;
  1551. DebugEntry(HET_Clear);
  1552. //
  1553. // Quick DD communication to wipe out the track list
  1554. //
  1555. OSI_FunctionRequest(HET_ESC_UNSHARE_ALL, (LPOSI_ESCAPE_HEADER)&req, sizeof(req));
  1556. //
  1557. // Enum all top level windows, and wipe out the property.
  1558. // if we can share.
  1559. //
  1560. EnumWindows(HETUnshareAllWindows, 0);
  1561. DebugExitVOID(HET_Clear);
  1562. }
  1563. //
  1564. // HETRepaintWindow()
  1565. // EnumWindows() callback to repaint each window, happens when somebody
  1566. // joins a share
  1567. //
  1568. BOOL CALLBACK HETRepaintWindow(HWND hwnd, LPARAM lParam)
  1569. {
  1570. ASShare * pShare = (ASShare *)lParam;
  1571. ASSERT(!IsBadWritePtr(pShare, sizeof(*pShare)));
  1572. if (pShare->HET_WindowIsHosted(hwnd))
  1573. {
  1574. USR_RepaintWindow(hwnd);
  1575. }
  1576. return(TRUE);
  1577. }
  1578. //
  1579. // HET_SetGUIEffects
  1580. //
  1581. // Turns various animations off/on when we start/stop hosting, to improve
  1582. // performance. Currently, we mess with
  1583. // * min animation
  1584. // * all of the effects in SPI_SETUIEFFECTS (tooltip fade, menu animation,
  1585. // etc.)
  1586. // * cursor shadows
  1587. //
  1588. // We don't turn off smooth scroll or full drag.
  1589. //
  1590. void HET_SetGUIEffects
  1591. (
  1592. BOOL fOn,
  1593. GUIEFFECTS * pEffects
  1594. )
  1595. {
  1596. DebugEntry(HET_SetGUIEffects);
  1597. ASSERT(!IsBadWritePtr(pEffects, sizeof(*pEffects)));
  1598. //
  1599. // NB. We deliberately do not track the state of animation whilst we
  1600. // are sharing. A determined user could, using some other app (such as
  1601. // the TweakUI control panel applet) reenable animation whilst in a
  1602. // share. We will respect this.
  1603. //
  1604. // We only affect the current 'in memory' setting - we do not write our
  1605. // temporary change to file.
  1606. //
  1607. if (fOn)
  1608. {
  1609. //
  1610. // If it was on before, restore it.
  1611. //
  1612. if (pEffects->hetAnimation.iMinAnimate)
  1613. {
  1614. pEffects->hetAnimation.cbSize = sizeof(pEffects->hetAnimation);
  1615. SystemParametersInfo(SPI_SETANIMATION, sizeof(pEffects->hetAnimation),
  1616. &pEffects->hetAnimation, 0);
  1617. }
  1618. if (pEffects->hetAdvanced)
  1619. {
  1620. SystemParametersInfo(SPI_SETUIEFFECTS, 0,
  1621. (LPVOID)pEffects->hetAdvanced, 0);
  1622. }
  1623. if (pEffects->hetCursorShadow)
  1624. {
  1625. SystemParametersInfo(SPI_SETCURSORSHADOW, 0,
  1626. (LPVOID)pEffects->hetCursorShadow, 0);
  1627. }
  1628. }
  1629. else
  1630. {
  1631. //
  1632. // Find out what animations are on.
  1633. //
  1634. ZeroMemory(&pEffects->hetAnimation, sizeof(pEffects->hetAnimation));
  1635. pEffects->hetAnimation.cbSize = sizeof(pEffects->hetAnimation);
  1636. SystemParametersInfo(SPI_GETANIMATION, sizeof(pEffects->hetAnimation),
  1637. &pEffects->hetAnimation, 0);
  1638. pEffects->hetAdvanced = FALSE;
  1639. SystemParametersInfo(SPI_GETUIEFFECTS, 0, &pEffects->hetAdvanced, 0);
  1640. pEffects->hetCursorShadow = FALSE;
  1641. SystemParametersInfo(SPI_GETCURSORSHADOW, 0, &pEffects->hetCursorShadow, 0);
  1642. //
  1643. // Turn off the animations which are on.
  1644. //
  1645. if (pEffects->hetAnimation.iMinAnimate)
  1646. {
  1647. //
  1648. // It's currently enabled, suppress it.
  1649. //
  1650. pEffects->hetAnimation.cbSize = sizeof(pEffects->hetAnimation);
  1651. pEffects->hetAnimation.iMinAnimate = FALSE;
  1652. SystemParametersInfo(SPI_SETANIMATION, sizeof(pEffects->hetAnimation),
  1653. &pEffects->hetAnimation, 0);
  1654. // SPI will wipe this out. Keep it set so we know to restore it.
  1655. pEffects->hetAnimation.iMinAnimate = TRUE;
  1656. }
  1657. if (pEffects->hetAdvanced)
  1658. {
  1659. SystemParametersInfo(SPI_SETUIEFFECTS, 0, FALSE, 0);
  1660. }
  1661. if (pEffects->hetCursorShadow)
  1662. {
  1663. SystemParametersInfo(SPI_SETCURSORSHADOW, 0, FALSE, 0);
  1664. }
  1665. }
  1666. DebugExitVOID(ASHost::HET_SetGUIEffects);
  1667. }
  1668. //
  1669. // HET_GetAppsList()
  1670. // Gets the list of shareable applications, the ones currently shared and
  1671. // the ones available for sharing.
  1672. //
  1673. // This routine does NOT check if we're in a call. The interface from the
  1674. // UI for the SDK does. This allows us to show the task list, disabled,
  1675. // always in the share host UI.
  1676. //
  1677. BOOL HET_GetAppsList(IAS_HWND_ARRAY ** ppArray)
  1678. {
  1679. BOOL rc = FALSE;
  1680. HOSTENUM hostEnum;
  1681. DebugEntry(HET_GetAppsList);
  1682. ASSERT(ppArray != NULL);
  1683. *ppArray = NULL;
  1684. //
  1685. // Generate a list of shareable apps
  1686. // This does NOT include the desktop.
  1687. //
  1688. ::COM_BasedListInit(&hostEnum.list);
  1689. hostEnum.count = 0;
  1690. hostEnum.countShared = 0;
  1691. ::EnumWindows(HostEnumProc, (LPARAM)&hostEnum);
  1692. //
  1693. // If there's nothing left in the list, but we know something is
  1694. // shared, it means there's a hidden/weird window the user can't
  1695. // see. Fake a catchall entry.
  1696. //
  1697. if (hostEnum.countShared && !hostEnum.count)
  1698. {
  1699. ::COM_SimpleListAppend(&hostEnum.list, HWND_BROADCAST);
  1700. hostEnum.count++;
  1701. }
  1702. *ppArray = (IAS_HWND_ARRAY *)new BYTE[sizeof(IAS_HWND_ARRAY) +
  1703. (hostEnum.count * sizeof(IAS_HWND))];
  1704. if (*ppArray != NULL)
  1705. {
  1706. (*ppArray)->cEntries = hostEnum.count;
  1707. (*ppArray)->cShared = hostEnum.countShared;
  1708. IAS_HWND * pEntry;
  1709. pEntry = (*ppArray)->aEntries;
  1710. while (! ::COM_BasedListIsEmpty(&hostEnum.list))
  1711. {
  1712. pEntry->hwnd = (HWND) ::COM_SimpleListRemoveHead(&hostEnum.list);
  1713. pEntry->fShared = (pEntry->hwnd == HWND_BROADCAST) ||
  1714. (HET_IsWindowShared(pEntry->hwnd));
  1715. pEntry++;
  1716. }
  1717. rc = TRUE;
  1718. }
  1719. else
  1720. {
  1721. WARNING_OUT(("HET_GetAppsList: can't allocate app array"));
  1722. }
  1723. DebugExitBOOL(HET_GetAppsList, rc);
  1724. return(rc);
  1725. }
  1726. //
  1727. // HET_FreeAppsList()
  1728. //
  1729. void HET_FreeAppsList(IAS_HWND_ARRAY * pArray)
  1730. {
  1731. ASSERT(!IsBadWritePtr(pArray, sizeof(*pArray)));
  1732. delete pArray;
  1733. }
  1734. //
  1735. // HostEnumProc()
  1736. //
  1737. // EnumWindows callback. This makes the shared/shareable task list.
  1738. //
  1739. BOOL CALLBACK HostEnumProc(HWND hwnd, LPARAM lParam)
  1740. {
  1741. PHOSTENUM phostEnum = (PHOSTENUM)lParam;
  1742. //
  1743. // We are only interested in windows which:
  1744. // - are shareable
  1745. // - have no owner. This should remove all top level windows
  1746. // except task windows
  1747. // - are not the front end itself, which should not be shared
  1748. // - are visible
  1749. // - are not shadowed or already hosted
  1750. //
  1751. // We are also only interested in already hosted or shadowed apps, but
  1752. // since only ASMaster knows our SHP_HANDLE, we let it test for that
  1753. // afterwards, since then we can use SHP_GetWindowStatus().
  1754. //
  1755. if (HET_IsWindowShared(hwnd))
  1756. {
  1757. phostEnum->countShared++;
  1758. }
  1759. HWND hwndOwner = ::GetWindow(hwnd, GW_OWNER);
  1760. //
  1761. // Note that we also want to skip windows with no title. There's not
  1762. // much point is showing <Untitled Application> in the Share menu since
  1763. // nobody will have a clue what it is.
  1764. //
  1765. if ( HET_IsWindowShareable(hwnd) &&
  1766. ((NULL == hwndOwner) || !::IsWindowVisible(hwndOwner)) &&
  1767. ::IsWindowVisible(hwnd) &&
  1768. ::GetWindowTextLength(hwnd)
  1769. )
  1770. {
  1771. ::COM_SimpleListAppend((PBASEDLIST)(&((PHOSTENUM)phostEnum)->list), (void *) hwnd);
  1772. phostEnum->count++;
  1773. }
  1774. //
  1775. // Return TRUE for the enumeration to continue
  1776. //
  1777. return TRUE;
  1778. }
  1779. //
  1780. // HET_IsWindowShared()
  1781. //
  1782. BOOL HET_IsWindowShared(HWND hwnd)
  1783. {
  1784. BOOL rc = FALSE;
  1785. UT_Lock(UTLOCK_AS);
  1786. if (g_asSession.pShare &&
  1787. g_asSession.pShare->m_pasLocal)
  1788. {
  1789. if (hwnd == GetDesktopWindow())
  1790. {
  1791. rc = (g_asSession.pShare->m_pasLocal->hetCount == HET_DESKTOPSHARED);
  1792. }
  1793. else if (hwnd == HWND_BROADCAST)
  1794. {
  1795. rc = (g_asSession.pShare->m_pasLocal->hetCount != 0);
  1796. }
  1797. else
  1798. {
  1799. rc = (HET_GetHosting(hwnd) != 0);
  1800. }
  1801. }
  1802. UT_Unlock(UTLOCK_AS);
  1803. return(rc);
  1804. }
  1805. //
  1806. // HET_IsWindowShareable()
  1807. //
  1808. BOOL HET_IsWindowShareable(HWND hwnd)
  1809. {
  1810. BOOL rc = FALSE;
  1811. UT_Lock(UTLOCK_AS);
  1812. if (HET_IsWindowShared(hwnd))
  1813. {
  1814. // It's shared -- so it must be shareable (or was at the time)
  1815. rc = TRUE;
  1816. DC_QUIT;
  1817. }
  1818. //
  1819. // Now check the window against share restrictions
  1820. //
  1821. // if this is the desktop, check it
  1822. if (hwnd == ::GetDesktopWindow())
  1823. {
  1824. if (g_asPolicies & SHP_POLICY_NODESKTOPSHARE)
  1825. {
  1826. //
  1827. // Policy prevents desktop sharing
  1828. //
  1829. DC_QUIT;
  1830. }
  1831. }
  1832. else
  1833. {
  1834. DWORD idProcess;
  1835. char szClass[HET_CLASS_NAME_SIZE];
  1836. if (GetWindowThreadProcessId(hwnd, &idProcess) &&
  1837. (idProcess == GetCurrentProcessId()))
  1838. {
  1839. //
  1840. // We NEVER let you share windows in the caller's process
  1841. //
  1842. DC_QUIT;
  1843. }
  1844. if (HET_IsShellWindow(hwnd))
  1845. {
  1846. //
  1847. // We NEVER let you share the tray or the shell desktop
  1848. //
  1849. DC_QUIT;
  1850. }
  1851. if ((g_asPolicies & SHP_POLICY_SHAREMASK) &&
  1852. GetClassName(hwnd, szClass, sizeof(szClass)))
  1853. {
  1854. //
  1855. // Check for CMD prompt
  1856. //
  1857. if (!lstrcmpi(szClass, HET_CMD95_CLASS) ||
  1858. !lstrcmpi(szClass, HET_CMDNT_CLASS))
  1859. {
  1860. if (g_asPolicies & SHP_POLICY_NODOSBOXSHARE)
  1861. {
  1862. //
  1863. // Policy prevents cmd prompt sharing
  1864. //
  1865. DC_QUIT;
  1866. }
  1867. }
  1868. //
  1869. // Check for SHELL
  1870. //
  1871. if (!lstrcmpi(szClass, HET_EXPLORER_CLASS) ||
  1872. !lstrcmpi(szClass, HET_CABINET_CLASS))
  1873. {
  1874. if (g_asPolicies & SHP_POLICY_NOEXPLORERSHARE)
  1875. {
  1876. //
  1877. // Policy prevents shell sharing
  1878. //
  1879. DC_QUIT;
  1880. }
  1881. }
  1882. }
  1883. }
  1884. //
  1885. // Finally! It's OK to share this.
  1886. //
  1887. rc = TRUE;
  1888. DC_EXIT_POINT:
  1889. UT_Unlock(UTLOCK_AS);
  1890. return(rc);
  1891. }
  1892. //
  1893. // HostDlgProc()
  1894. //
  1895. // Handles the hosting UI dialog. This may or may not be visible. It can
  1896. // only actually share apps and change control state when in a call. But
  1897. // users may keep it up as a mini-taskman thing, so we need to dyanmically
  1898. // update its state.
  1899. //
  1900. INT_PTR CALLBACK HostDlgProc
  1901. (
  1902. HWND hwnd,
  1903. UINT uMsg,
  1904. WPARAM wParam,
  1905. LPARAM lParam
  1906. )
  1907. {
  1908. BOOL rc = TRUE;
  1909. DebugEntry(HostDlgProc);
  1910. switch (uMsg)
  1911. {
  1912. case WM_INITDIALOG:
  1913. {
  1914. HOST_InitDialog(hwnd);
  1915. rc = FALSE;
  1916. break;
  1917. }
  1918. case WM_DESTROY:
  1919. {
  1920. //
  1921. // Because NT4.x has bad WM_DELETEITEM bugs, we must clear out
  1922. // the listbox now, to avoid leaking the memory for the
  1923. // items.
  1924. SendDlgItemMessage(hwnd, CTRL_PROGRAM_LIST, LB_RESETCONTENT, 0, 0);
  1925. rc = FALSE;
  1926. break;
  1927. }
  1928. case WM_INITMENU:
  1929. {
  1930. if (IsIconic(hwnd))
  1931. {
  1932. EnableMenuItem(GetSystemMenu(hwnd, FALSE), SC_RESTORE, MF_BYCOMMAND | MF_ENABLED);
  1933. EnableMenuItem(GetSystemMenu(hwnd, FALSE), SC_MINIMIZE, MF_BYCOMMAND | MF_GRAYED);
  1934. }
  1935. else
  1936. {
  1937. EnableMenuItem(GetSystemMenu(hwnd, FALSE), SC_RESTORE, MF_BYCOMMAND | MF_GRAYED);
  1938. EnableMenuItem(GetSystemMenu(hwnd, FALSE), SC_MINIMIZE, MF_BYCOMMAND | MF_ENABLED);
  1939. }
  1940. break;
  1941. }
  1942. case WM_SYSCOMMAND:
  1943. {
  1944. switch (wParam)
  1945. {
  1946. case CMD_TOPMOST:
  1947. {
  1948. if (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST)
  1949. {
  1950. CheckMenuItem(GetSystemMenu(hwnd, FALSE),
  1951. CMD_TOPMOST, MF_BYCOMMAND | MF_UNCHECKED);
  1952. SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
  1953. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  1954. }
  1955. else
  1956. {
  1957. CheckMenuItem(GetSystemMenu(hwnd, FALSE),
  1958. CMD_TOPMOST, MF_BYCOMMAND | MF_CHECKED);
  1959. SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
  1960. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  1961. }
  1962. break;
  1963. }
  1964. default:
  1965. {
  1966. rc = FALSE;
  1967. break;
  1968. }
  1969. }
  1970. break;
  1971. }
  1972. case WM_COMMAND:
  1973. {
  1974. switch (GET_WM_COMMAND_ID(wParam, lParam))
  1975. {
  1976. case IDOK:
  1977. if (::GetFocus() == GetDlgItem(hwnd, CTRL_PROGRAM_LIST))
  1978. {
  1979. // Do same thing as double-click
  1980. HOST_ChangeShareState(hwnd, CHANGE_TOGGLE);
  1981. break;
  1982. }
  1983. // FALL THROUGH
  1984. case IDCANCEL:
  1985. SendMessage(hwnd, WM_CLOSE, 0, 0);
  1986. break;
  1987. case CTRL_PROGRAM_LIST:
  1988. {
  1989. // Double-click/Enter means to toggle sharing
  1990. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  1991. {
  1992. case LBN_SELCHANGE:
  1993. {
  1994. HOST_OnSelChange(hwnd);
  1995. break;
  1996. }
  1997. case LBN_DBLCLK:
  1998. {
  1999. HOST_ChangeShareState(hwnd, CHANGE_TOGGLE);
  2000. break;
  2001. }
  2002. }
  2003. break;
  2004. }
  2005. case CTRL_SHARE_BTN:
  2006. {
  2007. HOST_ChangeShareState(hwnd, CHANGE_SHARED);
  2008. break;
  2009. }
  2010. case CTRL_UNSHARE_BTN:
  2011. {
  2012. HOST_ChangeShareState(hwnd, CHANGE_UNSHARED);
  2013. break;
  2014. }
  2015. case CTRL_UNSHAREALL_BTN:
  2016. {
  2017. HOST_ChangeShareState(hwnd, CHANGE_ALLUNSHARED);
  2018. break;
  2019. }
  2020. case CTRL_ALLOWCONTROL_BTN:
  2021. {
  2022. // Turn on allow state.
  2023. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  2024. {
  2025. case BN_CLICKED:
  2026. {
  2027. //
  2028. // CA_AllowControl() will send us a message back
  2029. // and cause us to change the button.
  2030. //
  2031. SendMessage(g_asMainWindow, DCS_ALLOWCONTROL_MSG, TRUE, 0);
  2032. break;
  2033. }
  2034. }
  2035. break;
  2036. }
  2037. case CTRL_PREVENTCONTROL_BTN:
  2038. {
  2039. // Turn off allow state.
  2040. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  2041. {
  2042. case BN_CLICKED:
  2043. {
  2044. //
  2045. // CA_AllowControl() will send us a message back
  2046. // and cause us to change the button.
  2047. //
  2048. SendMessage(g_asMainWindow, DCS_ALLOWCONTROL_MSG, FALSE, 0);
  2049. break;
  2050. }
  2051. }
  2052. break;
  2053. }
  2054. case CTRL_ENABLETRUECOLOR_CHECK:
  2055. {
  2056. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  2057. {
  2058. case BN_CLICKED:
  2059. {
  2060. //
  2061. // This takes effect the next time something
  2062. // changes--somebody joins, somebody leaves,
  2063. // you stop/start hosting
  2064. //
  2065. if (IsDlgButtonChecked(hwnd, CTRL_ENABLETRUECOLOR_CHECK))
  2066. {
  2067. g_asSettings |= SHP_SETTING_TRUECOLOR;
  2068. }
  2069. else
  2070. {
  2071. g_asSettings &= ~SHP_SETTING_TRUECOLOR;
  2072. }
  2073. break;
  2074. }
  2075. }
  2076. break;
  2077. }
  2078. case CTRL_AUTOACCEPTCONTROL_CHECK:
  2079. {
  2080. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  2081. {
  2082. case BN_CLICKED:
  2083. {
  2084. //
  2085. // This takes effect when the next control
  2086. // request comes in.
  2087. //
  2088. if (g_asSession.pShare && g_asSession.pShare->m_pHost)
  2089. {
  2090. g_asSession.pShare->m_pHost->m_caAutoAcceptRequests =
  2091. (IsDlgButtonChecked(hwnd, CTRL_AUTOACCEPTCONTROL_CHECK) != 0);
  2092. }
  2093. break;
  2094. }
  2095. }
  2096. break;
  2097. }
  2098. case CTRL_TEMPREJECTCONTROL_CHECK:
  2099. {
  2100. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  2101. {
  2102. case BN_CLICKED:
  2103. {
  2104. //
  2105. // This takes effect when the next control
  2106. // request comes in.
  2107. //
  2108. // NOTE THAT IT TAKES PRECEDENCE OVER AUTO-ACCEPT.
  2109. // This allows you to keep auto-accept on, but then
  2110. // temporarily do not disturb.
  2111. //
  2112. if (g_asSession.pShare && g_asSession.pShare->m_pHost)
  2113. {
  2114. g_asSession.pShare->m_pHost->m_caTempRejectRequests =
  2115. (IsDlgButtonChecked(hwnd, CTRL_TEMPREJECTCONTROL_CHECK) != 0);
  2116. }
  2117. break;
  2118. }
  2119. }
  2120. break;
  2121. }
  2122. }
  2123. break;
  2124. }
  2125. case WM_MEASUREITEM:
  2126. {
  2127. rc = HOST_MeasureItem(hwnd, (LPMEASUREITEMSTRUCT)lParam);
  2128. break;
  2129. }
  2130. case WM_DELETEITEM:
  2131. {
  2132. rc = HOST_DeleteItem(hwnd, (LPDELETEITEMSTRUCT)lParam);
  2133. break;
  2134. }
  2135. case WM_DRAWITEM:
  2136. {
  2137. rc = HOST_DrawItem(hwnd, (LPDRAWITEMSTRUCT)lParam);
  2138. break;
  2139. }
  2140. case WM_TIMER:
  2141. {
  2142. if (wParam != IDT_REFRESH)
  2143. {
  2144. rc = FALSE;
  2145. }
  2146. else
  2147. {
  2148. ASSERT(IsWindowVisible(hwnd));
  2149. HOST_FillList(hwnd);
  2150. }
  2151. break;
  2152. }
  2153. case WM_ACTIVATE:
  2154. {
  2155. //
  2156. // When activating, kill timer. When deactivating, start
  2157. // timer. The theory is, there's nothing else going on when we
  2158. // are active, so why poll for updates? On sharing state
  2159. // changes, we update the list anyway.
  2160. //
  2161. if (IsWindowVisible(hwnd))
  2162. {
  2163. if (wParam)
  2164. {
  2165. KillTimer(hwnd, IDT_REFRESH);
  2166. HOST_FillList(hwnd);
  2167. }
  2168. else
  2169. {
  2170. SetTimer(hwnd, IDT_REFRESH, PERIOD_REFRESH, 0);
  2171. }
  2172. }
  2173. break;
  2174. }
  2175. //
  2176. // Private communication messages
  2177. //
  2178. case HOST_MSG_CALL:
  2179. {
  2180. HOST_OnCall(hwnd, (wParam != FALSE));
  2181. break;
  2182. }
  2183. case HOST_MSG_OPEN:
  2184. {
  2185. //
  2186. // If we are temporarily hidden, ignore all open requests.
  2187. //
  2188. if (!g_asSession.fHostUIFrozen)
  2189. {
  2190. if (!IsWindowVisible(hwnd))
  2191. {
  2192. //
  2193. // Note, we may end up updating the list twice, once here
  2194. // and once under activation.
  2195. HOST_FillList(hwnd);
  2196. ShowWindow(hwnd, SW_SHOW);
  2197. g_asSession.fHostUI = TRUE;
  2198. }
  2199. if (IsIconic(hwnd))
  2200. SendMessage(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
  2201. SetForegroundWindow(hwnd);
  2202. }
  2203. break;
  2204. }
  2205. case WM_CLOSE:
  2206. case HOST_MSG_CLOSE:
  2207. {
  2208. if (IsWindowVisible(hwnd))
  2209. {
  2210. //
  2211. // Hiding the window will deactivate it. Deactivating it
  2212. // will kick off timer. So kill timer afterwards.
  2213. //
  2214. ShowWindow(hwnd, SW_HIDE);
  2215. KillTimer(hwnd, IDT_REFRESH);
  2216. g_asSession.fHostUI = FALSE;
  2217. }
  2218. break;
  2219. }
  2220. case HOST_MSG_UPDATELIST:
  2221. {
  2222. //
  2223. // We only do list stuff when the UI is up.
  2224. //
  2225. if (IsWindowVisible(hwnd))
  2226. {
  2227. HOST_FillList(hwnd);
  2228. //
  2229. // If timer is on, reset it. This is for case where you
  2230. // are hosting but this UI window is up in the background.
  2231. // There's no point in overlapping the updates. We want the
  2232. // list to update every time there's a top level shared
  2233. // window change OR PERIOD_REFRESH milliseconds have elapsed
  2234. // without a change.
  2235. //
  2236. if (hwnd != GetActiveWindow())
  2237. {
  2238. SetTimer(hwnd, IDT_REFRESH, PERIOD_REFRESH, 0);
  2239. }
  2240. }
  2241. break;
  2242. }
  2243. case HOST_MSG_HOSTSTART:
  2244. {
  2245. HOST_OnSharing(hwnd, TRUE);
  2246. break;
  2247. }
  2248. case HOST_MSG_HOSTEND:
  2249. {
  2250. HOST_OnSharing(hwnd, FALSE);
  2251. break;
  2252. }
  2253. case HOST_MSG_ALLOWCONTROL:
  2254. {
  2255. HOST_OnControllable(hwnd, (wParam != 0));
  2256. break;
  2257. }
  2258. case HOST_MSG_CONTROLLED:
  2259. {
  2260. if (wParam)
  2261. {
  2262. //
  2263. // Hide the window temporarily
  2264. //
  2265. ASSERT(!g_asSession.fHostUIFrozen);
  2266. g_asSession.fHostUIFrozen = TRUE;
  2267. if (IsWindowVisible(hwnd))
  2268. {
  2269. ASSERT(g_asSession.fHostUI);
  2270. SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE |
  2271. SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE |
  2272. SWP_HIDEWINDOW);
  2273. }
  2274. }
  2275. else
  2276. {
  2277. //
  2278. // Put the window back in the state it was
  2279. //
  2280. if (g_asSession.fHostUIFrozen)
  2281. {
  2282. g_asSession.fHostUIFrozen = FALSE;
  2283. if (g_asSession.fHostUI)
  2284. {
  2285. SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE |
  2286. SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE |
  2287. SWP_SHOWWINDOW);
  2288. }
  2289. }
  2290. }
  2291. break;
  2292. }
  2293. default:
  2294. rc = FALSE;
  2295. break;
  2296. }
  2297. DebugExitBOOL(HostDlgProc, rc);
  2298. return(rc);
  2299. }
  2300. //
  2301. // HOST_InitDialog()
  2302. //
  2303. // Initializes the host UI dialog
  2304. //
  2305. void HOST_InitDialog(HWND hwnd)
  2306. {
  2307. HMENU hMenu;
  2308. char szText[128];
  2309. MENUITEMINFO mi;
  2310. DebugEntry(HOST_InitDialog);
  2311. // Set title text
  2312. HOST_UpdateTitle(hwnd, IDS_NOTINCALL);
  2313. //
  2314. // Set window icon
  2315. //
  2316. SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)g_hetASIcon);
  2317. //
  2318. // Update system menu
  2319. //
  2320. hMenu = GetSystemMenu(hwnd, FALSE);
  2321. EnableMenuItem(hMenu, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
  2322. EnableMenuItem(hMenu, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
  2323. // Append separator, always on top to system menu
  2324. ZeroMemory(&mi, sizeof(mi));
  2325. mi.cbSize = sizeof(mi);
  2326. mi.fMask = MIIM_TYPE;
  2327. mi.fType = MFT_SEPARATOR;
  2328. InsertMenuItem(hMenu, -1, TRUE, &mi);
  2329. mi.fMask = MIIM_ID | MIIM_STATE | MIIM_TYPE;
  2330. mi.fType = MFT_STRING;
  2331. mi.fState = MFS_ENABLED;
  2332. mi.wID = CMD_TOPMOST;
  2333. LoadString(g_asInstance, IDS_TOPMOST, szText, sizeof(szText));
  2334. mi.dwTypeData = szText;
  2335. mi.cch = lstrlen(szText);
  2336. InsertMenuItem(hMenu, -1, TRUE, &mi);
  2337. //
  2338. // Enable/disable true color sharing control. If a policy prevents it
  2339. // or our screen depth isn't capable, disable it.
  2340. //
  2341. HOST_EnableCtrl(hwnd, CTRL_ENABLETRUECOLOR_CHECK,
  2342. ((g_usrScreenBPP >= 24) && !(g_asPolicies & SHP_POLICY_NOTRUECOLOR)));
  2343. //
  2344. // Get text, control buttons set.
  2345. //
  2346. HOST_OnControllable(hwnd, TRUE);
  2347. HOST_OnControllable(hwnd, FALSE);
  2348. DebugExitVOID(HOST_InitDialog);
  2349. }
  2350. //
  2351. // HOST_UpdateTitle()
  2352. //
  2353. // Updates title bar of hosting UI
  2354. //
  2355. void HOST_UpdateTitle(HWND hwnd, UINT idState)
  2356. {
  2357. char szText[64];
  2358. char szFormat[128];
  2359. char szTitle[192];
  2360. DebugEntry(HOST_UpdateTitle);
  2361. LoadString(g_asInstance, IDS_SHARING_FORMAT, szFormat, sizeof(szFormat));
  2362. LoadString(g_asInstance, idState, szText, sizeof(szText));
  2363. wsprintf(szTitle, szFormat, szText);
  2364. SetWindowText(hwnd, szTitle);
  2365. DebugExitVOID(HOST_UpdateTitle);
  2366. }
  2367. //
  2368. // HOST_OnCall()
  2369. //
  2370. // Handles call start/stop
  2371. //
  2372. void HOST_OnCall(HWND hwnd, BOOL fCall)
  2373. {
  2374. DebugEntry(HOST_OnCall);
  2375. // Update title bar
  2376. HOST_UpdateTitle(hwnd, (fCall ? IDS_NOTHING : IDS_NOTINCALL));
  2377. HOST_EnableCtrl(hwnd, CTRL_PROGRAM_LIST, fCall);
  2378. if (IsWindowVisible(hwnd))
  2379. {
  2380. SendMessage(hwnd, HOST_MSG_UPDATELIST, 0, 0);
  2381. }
  2382. DebugExitVOID(HOST_OnCall);
  2383. }
  2384. //
  2385. // HOST_OnSharing()
  2386. //
  2387. // Handles sharing start/stop
  2388. //
  2389. void HOST_OnSharing(HWND hwnd, BOOL fSharing)
  2390. {
  2391. DebugEntry(HOST_OnSharing);
  2392. // Update title bar
  2393. if (fSharing)
  2394. {
  2395. HOST_UpdateTitle(hwnd,
  2396. (g_asSession.pShare->m_pasLocal->hetCount == HET_DESKTOPSHARED) ?
  2397. IDS_DESKTOP : IDS_PROGRAMS);
  2398. }
  2399. else
  2400. {
  2401. HOST_UpdateTitle(hwnd, IDS_NOTHING);
  2402. }
  2403. //
  2404. // The ctrl button should always be Allow. When we stop hosting, we turn
  2405. // off allowing control first.
  2406. //
  2407. if (!(g_asPolicies & SHP_POLICY_NOCONTROL))
  2408. {
  2409. HOST_EnableCtrl(hwnd, CTRL_ALLOWCONTROL_BTN, fSharing);
  2410. }
  2411. HOST_EnableCtrl(hwnd, CTRL_UNSHAREALL_BTN, fSharing);
  2412. if ((g_usrScreenBPP >= 24) && !(g_asPolicies & SHP_POLICY_NOTRUECOLOR))
  2413. {
  2414. //
  2415. // Only dynamically change this checkbox if true color is available.
  2416. //
  2417. HOST_EnableCtrl(hwnd, CTRL_ENABLETRUECOLOR_CHECK, !fSharing);
  2418. }
  2419. DebugExitVOID(HOST_OnSharing);
  2420. }
  2421. //
  2422. // HOST_OnControllable()
  2423. //
  2424. // Updates the blurb, button text, and button ID when the controllable
  2425. // state changes.
  2426. //
  2427. void HOST_OnControllable(HWND hwnd, BOOL fControllable)
  2428. {
  2429. HWND hwndBtn;
  2430. TCHAR szText[256];
  2431. DebugEntry(HOST_OnControllable);
  2432. // Control blurb
  2433. LoadString(g_asInstance,
  2434. (fControllable ? IDS_MSG_TOPREVENTCONTROL : IDS_MSG_TOALLOWCONTROL),
  2435. szText, sizeof(szText));
  2436. SetDlgItemText(hwnd, CTRL_CONTROL_MSG, szText);
  2437. // Control button
  2438. if (fControllable)
  2439. {
  2440. hwndBtn = GetDlgItem(hwnd, CTRL_ALLOWCONTROL_BTN);
  2441. ASSERT(hwndBtn);
  2442. SetWindowLong(hwndBtn, GWL_ID, CTRL_PREVENTCONTROL_BTN);
  2443. LoadString(g_asInstance, IDS_PREVENTCONTROL, szText, sizeof(szText));
  2444. }
  2445. else
  2446. {
  2447. hwndBtn = GetDlgItem(hwnd, CTRL_PREVENTCONTROL_BTN);
  2448. ASSERT(hwndBtn);
  2449. SetWindowLong(hwndBtn, GWL_ID, CTRL_ALLOWCONTROL_BTN);
  2450. LoadString(g_asInstance, IDS_ALLOWCONTROL, szText, sizeof(szText));
  2451. }
  2452. SetWindowText(hwndBtn, szText);
  2453. // Enable/disable the control checkboxes, make sure they start unchecked.
  2454. HOST_EnableCtrl(hwnd, CTRL_TEMPREJECTCONTROL_CHECK, fControllable);
  2455. CheckDlgButton(hwnd, CTRL_TEMPREJECTCONTROL_CHECK, FALSE);
  2456. HOST_EnableCtrl(hwnd, CTRL_AUTOACCEPTCONTROL_CHECK, fControllable);
  2457. CheckDlgButton(hwnd, CTRL_AUTOACCEPTCONTROL_CHECK, FALSE);
  2458. DebugExitVOID(HOST_OnControllable);
  2459. }
  2460. //
  2461. // HOST_FillList()
  2462. //
  2463. // Fills the contents of the shared/unshared applications list
  2464. //
  2465. void HOST_FillList(HWND hwnd)
  2466. {
  2467. IAS_HWND_ARRAY * pArray;
  2468. int iItem;
  2469. PHOSTITEM pItem;
  2470. char szText[80];
  2471. UINT iWnd;
  2472. HICON hIcon;
  2473. BOOL fAppsAvailable;
  2474. HWND hwndSelect;
  2475. int iSelect;
  2476. int iTop;
  2477. int cxExtent;
  2478. RECT rc;
  2479. HFONT hfnT;
  2480. HFONT hfnControl;
  2481. HDC hdc;
  2482. //
  2483. // For the common case, remember what was selected and try to put that
  2484. // back.
  2485. //
  2486. // Save current top index
  2487. iTop = (int)SendDlgItemMessage(hwnd, CTRL_PROGRAM_LIST, LB_GETTOPINDEX, 0, 0);
  2488. // Save currently selected item
  2489. hwndSelect = HWND_BOTTOM;
  2490. iSelect = -1;
  2491. iItem = (int)SendDlgItemMessage(hwnd, CTRL_PROGRAM_LIST, LB_GETCURSEL, 0, 0);
  2492. if (iItem != -1)
  2493. {
  2494. pItem = (PHOSTITEM)SendDlgItemMessage(hwnd, CTRL_PROGRAM_LIST,
  2495. LB_GETITEMDATA, iItem, 0);
  2496. if (pItem)
  2497. {
  2498. hwndSelect = pItem->hwnd;
  2499. }
  2500. }
  2501. //
  2502. // Turn off redraw and clear the apps list.
  2503. //
  2504. SendDlgItemMessage(hwnd, CTRL_PROGRAM_LIST, WM_SETREDRAW, FALSE, 0);
  2505. SendDlgItemMessage(hwnd, CTRL_PROGRAM_LIST, LB_RESETCONTENT, 0, 0);
  2506. //
  2507. // We're going to calculate the horizontal extent since ownerdraw
  2508. // lists can't do that.
  2509. //
  2510. hdc = GetDC(hwnd);
  2511. hfnControl = (HFONT)SendDlgItemMessage(hwnd, CTRL_PROGRAM_LIST, WM_GETFONT, 0, 0);
  2512. cxExtent = 0;
  2513. //
  2514. // HET_GetAppsList() will fail if there's not enough memory to allocate
  2515. // the array. If we really can't allocate it, why add an item for the
  2516. // desktop?
  2517. //
  2518. if (HET_GetAppsList(&pArray))
  2519. {
  2520. ASSERT(pArray);
  2521. fAppsAvailable = TRUE;
  2522. //
  2523. // If desktop sharing is permitted, add desktop item.
  2524. //
  2525. if (!(g_asPolicies & SHP_POLICY_NODESKTOPSHARE))
  2526. {
  2527. pItem = new HOSTITEM;
  2528. if (!pItem)
  2529. {
  2530. ERROR_OUT(("Unable to alloc HOSTITEM for listbox"));
  2531. }
  2532. else
  2533. {
  2534. pItem->hwnd = GetDesktopWindow();
  2535. pItem->hIcon = g_hetDeskIconSmall;
  2536. LoadString(g_asInstance, IDS_DESKTOP, szText,
  2537. sizeof(szText));
  2538. pItem->fShared = (HET_IsWindowShared(pItem->hwnd) != FALSE);
  2539. if (pItem->fShared)
  2540. {
  2541. //
  2542. // When everything (the desktop) is shared, sharing
  2543. // individual apps makes no sense. We keep them in the
  2544. // list but draw them unavailable, same as if the list
  2545. // itself were completely disabled.
  2546. //
  2547. fAppsAvailable = FALSE;
  2548. pItem->fAvailable = TRUE;
  2549. }
  2550. else if (!pArray->cShared && g_asSession.callID &&
  2551. (g_asSession.attendeePermissions & NM_PERMIT_SHARE))
  2552. {
  2553. //
  2554. // No apps are shared, the desktop item is available.
  2555. //
  2556. pItem->fAvailable = TRUE;
  2557. }
  2558. else
  2559. {
  2560. //
  2561. // Apps are shared, sharing the entire desktop makes no
  2562. // sense.
  2563. //
  2564. pItem->fAvailable = FALSE;
  2565. }
  2566. iItem = (int)SendDlgItemMessage(hwnd, CTRL_PROGRAM_LIST,
  2567. LB_ADDSTRING, 0, (LPARAM)szText);
  2568. if (iItem == -1)
  2569. {
  2570. ERROR_OUT(("Couldn't append item to list"));
  2571. delete pItem;
  2572. }
  2573. else
  2574. {
  2575. SendDlgItemMessage(hwnd, CTRL_PROGRAM_LIST, LB_SETITEMDATA,
  2576. iItem, (LPARAM)pItem);
  2577. //
  2578. // Calculate width.
  2579. //
  2580. hfnT = SelectFont(hdc,
  2581. (pItem->fShared ? g_hetSharedFont : hfnControl));
  2582. SetRectEmpty(&rc);
  2583. DrawText(hdc, szText, lstrlen(szText), &rc,
  2584. DT_LEFT | DT_VCENTER | DT_EXTERNALLEADING | DT_NOPREFIX |
  2585. DT_SINGLELINE | DT_CALCRECT);
  2586. SelectFont(hdc, hfnT);
  2587. rc.right -= rc.left;
  2588. cxExtent = max(cxExtent, rc.right);
  2589. //
  2590. // If this desktop item were selected last time,
  2591. // remember so we select it again after.
  2592. //
  2593. if (pItem->hwnd == hwndSelect)
  2594. iSelect = iItem;
  2595. }
  2596. }
  2597. }
  2598. //
  2599. // Add items for apps.
  2600. //
  2601. for (iWnd = 0; iWnd < pArray->cEntries; iWnd++)
  2602. {
  2603. hIcon = NULL;
  2604. if (pArray->aEntries[iWnd].hwnd == HWND_BROADCAST)
  2605. {
  2606. LoadString(g_asInstance, IDS_HIDDEN_WINDOW, szText,
  2607. sizeof(szText));
  2608. hIcon = g_hetASIconSmall;
  2609. }
  2610. else
  2611. {
  2612. GetWindowText(pArray->aEntries[iWnd].hwnd, szText, sizeof(szText));
  2613. if (!szText[0])
  2614. continue;
  2615. // Try to get window small icon
  2616. SendMessageTimeout(pArray->aEntries[iWnd].hwnd, WM_GETICON, ICON_SMALL, 0,
  2617. SMTO_NORMAL, 1000, (DWORD_PTR*)&hIcon);
  2618. if (!hIcon)
  2619. {
  2620. hIcon = (HICON)GetClassLongPtr(pArray->aEntries[iWnd].hwnd, GCLP_HICON);
  2621. }
  2622. //
  2623. // Make a copy of the small icon, we can't just hang on to
  2624. // the application's, it could go away.
  2625. //
  2626. if (hIcon)
  2627. {
  2628. hIcon = (HICON)CopyImage(hIcon, IMAGE_ICON, 0, 0, 0);
  2629. }
  2630. if (!hIcon)
  2631. {
  2632. hIcon = g_hetASIconSmall;
  2633. }
  2634. }
  2635. //
  2636. // Add item to list
  2637. //
  2638. pItem = new HOSTITEM;
  2639. if (!pItem)
  2640. {
  2641. ERROR_OUT(("Unable to alloc HOSTITEM for listbox"));
  2642. }
  2643. else
  2644. {
  2645. pItem->hwnd = pArray->aEntries[iWnd].hwnd;
  2646. pItem->hIcon = hIcon;
  2647. pItem->fShared = pArray->aEntries[iWnd].fShared;
  2648. pItem->fAvailable = g_asSession.callID &&
  2649. (g_asSession.attendeePermissions & NM_PERMIT_SHARE) &&
  2650. (fAppsAvailable != FALSE);
  2651. iItem = (int)SendDlgItemMessage(hwnd, CTRL_PROGRAM_LIST,
  2652. LB_ADDSTRING, 0, (LPARAM)szText);
  2653. if (iItem == -1)
  2654. {
  2655. ERROR_OUT(("Couldn't append item to list"));
  2656. delete pItem;
  2657. }
  2658. else
  2659. {
  2660. SendDlgItemMessage(hwnd, CTRL_PROGRAM_LIST, LB_SETITEMDATA,
  2661. iItem, (LPARAM)pItem);
  2662. //
  2663. // Calculate width.
  2664. //
  2665. hfnT = SelectFont(hdc,
  2666. (pItem->fShared ? g_hetSharedFont : hfnControl));
  2667. SetRectEmpty(&rc);
  2668. DrawText(hdc, szText, lstrlen(szText), &rc,
  2669. DT_LEFT | DT_VCENTER | DT_EXTERNALLEADING | DT_NOPREFIX |
  2670. DT_SINGLELINE | DT_CALCRECT);
  2671. SelectFont(hdc, hfnT);
  2672. rc.right -= rc.left;
  2673. cxExtent = max(cxExtent, rc.right);
  2674. }
  2675. //
  2676. // If this app item were selected before, remember so we
  2677. // select it again when done.
  2678. //
  2679. if (pItem->hwnd == hwndSelect)
  2680. iSelect = iItem;
  2681. }
  2682. }
  2683. HET_FreeAppsList(pArray);
  2684. }
  2685. ReleaseDC(hwnd, hdc);
  2686. //
  2687. // Set cur sel, top index, update buttons
  2688. //
  2689. SendDlgItemMessage(hwnd, CTRL_PROGRAM_LIST, LB_SETTOPINDEX, iTop, 0);
  2690. SendDlgItemMessage(hwnd, CTRL_PROGRAM_LIST, LB_SETCURSEL, iSelect, 0);
  2691. HOST_OnSelChange(hwnd);
  2692. //
  2693. // Turn on redraw and repaint
  2694. //
  2695. SendDlgItemMessage(hwnd, CTRL_PROGRAM_LIST, WM_SETREDRAW, TRUE, 0);
  2696. //
  2697. // Set horizontal extent
  2698. //
  2699. if (cxExtent)
  2700. {
  2701. // Add on space for checkmark, icons
  2702. cxExtent += GetSystemMetrics(SM_CXMENUCHECK) + GetSystemMetrics(SM_CXSMICON) +
  2703. 3*GetSystemMetrics(SM_CXEDGE);
  2704. }
  2705. SendDlgItemMessage(hwnd, CTRL_PROGRAM_LIST, LB_SETHORIZONTALEXTENT, cxExtent, 0);
  2706. InvalidateRect(GetDlgItem(hwnd, CTRL_PROGRAM_LIST), NULL, TRUE);
  2707. UpdateWindow(GetDlgItem(hwnd, CTRL_PROGRAM_LIST));
  2708. DebugExitVOID(HOST_FillList);
  2709. }
  2710. //
  2711. // HOST_MeasureItem()
  2712. //
  2713. // Calculates height of ownerdraw items in host list
  2714. //
  2715. BOOL HOST_MeasureItem(HWND hwnd, LPMEASUREITEMSTRUCT lpmi)
  2716. {
  2717. BOOL rc = FALSE;
  2718. UINT cy;
  2719. TEXTMETRIC tm;
  2720. HDC hdc;
  2721. HFONT hfnT;
  2722. DebugEntry(HOST_MeasureItem);
  2723. if (lpmi->CtlID != CTRL_PROGRAM_LIST)
  2724. {
  2725. // Not for us
  2726. DC_QUIT;
  2727. }
  2728. // Get height of bolded font
  2729. hdc = GetDC(hwnd);
  2730. hfnT = SelectFont(hdc, g_hetSharedFont);
  2731. GetTextMetrics(hdc, &tm);
  2732. SelectFont(hdc, hfnT);
  2733. ReleaseDC(hwnd, hdc);
  2734. //
  2735. // Height is max of default height (height of char in font),
  2736. // checkmark height, and small icon height, plus dotted rect.
  2737. //
  2738. cy = (UINT)tm.tmHeight;
  2739. lpmi->itemHeight = max(lpmi->itemHeight, cy);
  2740. cy = (UINT)GetSystemMetrics(SM_CYMENUCHECK);
  2741. lpmi->itemHeight = max(lpmi->itemHeight, cy);
  2742. cy = (UINT)GetSystemMetrics(SM_CYSMICON);
  2743. lpmi->itemHeight = max(lpmi->itemHeight, cy);
  2744. lpmi->itemHeight += GetSystemMetrics(SM_CYEDGE);
  2745. rc = TRUE;
  2746. DC_EXIT_POINT:
  2747. DebugExitBOOL(HOST_MeasureItem, rc);
  2748. return(rc);
  2749. }
  2750. //
  2751. // HOST_DeleteItem()
  2752. //
  2753. // Cleans up after an item is deleted from the list.
  2754. //
  2755. BOOL HOST_DeleteItem(HWND hwnd, LPDELETEITEMSTRUCT lpdi)
  2756. {
  2757. PHOSTITEM pItem;
  2758. BOOL rc = FALSE;
  2759. DebugEntry(HOST_DeleteItem);
  2760. if (lpdi->CtlID != CTRL_PROGRAM_LIST)
  2761. {
  2762. DC_QUIT;
  2763. }
  2764. pItem = (PHOSTITEM)lpdi->itemData;
  2765. if (!pItem)
  2766. {
  2767. //
  2768. // NT 4.x has a terrible bug where the item data is not passed
  2769. // in the DELETEITEMSTRUCT always. So try to obtain it if not.
  2770. //
  2771. pItem = (PHOSTITEM)SendDlgItemMessage(hwnd, CTRL_PROGRAM_LIST, LB_GETITEMDATA,
  2772. lpdi->itemID, 0);
  2773. }
  2774. if (pItem)
  2775. {
  2776. if ((pItem->hIcon != g_hetASIconSmall) && (pItem->hIcon != g_hetDeskIconSmall))
  2777. {
  2778. DestroyIcon(pItem->hIcon);
  2779. }
  2780. delete pItem;
  2781. }
  2782. rc = TRUE;
  2783. DC_EXIT_POINT:
  2784. DebugExitBOOL(HOST_DeleteItem, rc);
  2785. return(rc);
  2786. }
  2787. //
  2788. // HOST_DrawItem()
  2789. //
  2790. // Draws list item
  2791. //
  2792. BOOL HOST_DrawItem(HWND hwnd, LPDRAWITEMSTRUCT lpdi)
  2793. {
  2794. COLORREF clrBk;
  2795. COLORREF clrText;
  2796. HBRUSH hbr;
  2797. HFONT hfnT;
  2798. RECT rcItem;
  2799. char szText[80];
  2800. PHOSTITEM pItem;
  2801. BOOL rc = FALSE;
  2802. if (lpdi->CtlID != CTRL_PROGRAM_LIST)
  2803. {
  2804. DC_QUIT;
  2805. }
  2806. pItem = (PHOSTITEM)lpdi->itemData;
  2807. if (!pItem)
  2808. {
  2809. // Empty item for focus
  2810. rc = TRUE;
  2811. DC_QUIT;
  2812. }
  2813. rcItem = lpdi->rcItem;
  2814. //
  2815. // Set up colors
  2816. //
  2817. if (!pItem->fAvailable)
  2818. {
  2819. // No selection color
  2820. clrBk = GetSysColor(COLOR_WINDOW);
  2821. hbr = GetSysColorBrush(COLOR_WINDOW);
  2822. clrText = GetSysColor(COLOR_GRAYTEXT);
  2823. }
  2824. else if (lpdi->itemState & ODS_SELECTED)
  2825. {
  2826. clrBk = GetSysColor(COLOR_HIGHLIGHT);
  2827. hbr = GetSysColorBrush(COLOR_HIGHLIGHT);
  2828. clrText = GetSysColor(COLOR_HIGHLIGHTTEXT);
  2829. }
  2830. else
  2831. {
  2832. clrBk = GetSysColor(COLOR_WINDOW);
  2833. hbr = GetSysColorBrush(COLOR_WINDOW);
  2834. clrText = GetSysColor(COLOR_WINDOWTEXT);
  2835. }
  2836. SetBkColor(lpdi->hDC, clrBk);
  2837. SetTextColor(lpdi->hDC, clrText);
  2838. // Erase background
  2839. FillRect(lpdi->hDC, &rcItem, hbr);
  2840. // Focus rect
  2841. if (lpdi->itemState & ODS_FOCUS)
  2842. {
  2843. DrawFocusRect(lpdi->hDC, &rcItem);
  2844. }
  2845. rcItem.left += GetSystemMetrics(SM_CXEDGE);
  2846. InflateRect(&rcItem, 0, -GetSystemMetrics(SM_CYBORDER));
  2847. //
  2848. // Draw checkmark and select bolded font
  2849. //
  2850. if (pItem->fShared)
  2851. {
  2852. HDC hdcT;
  2853. HBITMAP hbmpOld;
  2854. hdcT = CreateCompatibleDC(lpdi->hDC);
  2855. hbmpOld = SelectBitmap(hdcT, g_hetCheckBitmap);
  2856. SetTextColor(hdcT, clrText);
  2857. SetBkColor(hdcT, clrBk);
  2858. BitBlt(lpdi->hDC, rcItem.left,
  2859. (rcItem.top + rcItem.bottom - GetSystemMetrics(SM_CYMENUCHECK)) / 2,
  2860. GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK),
  2861. hdcT, 0, 0,
  2862. SRCCOPY);
  2863. SelectBitmap(hdcT, hbmpOld);
  2864. DeleteDC(hdcT);
  2865. hfnT = SelectFont(lpdi->hDC, g_hetSharedFont);
  2866. }
  2867. rcItem.left += GetSystemMetrics(SM_CXMENUCHECK) + GetSystemMetrics(SM_CXEDGE);
  2868. // Draw icon, centered vertically
  2869. DrawIconEx(lpdi->hDC, rcItem.left, (rcItem.top + rcItem.bottom -
  2870. GetSystemMetrics(SM_CYSMICON)) /2, pItem->hIcon,
  2871. GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
  2872. 0, NULL, DI_NORMAL);
  2873. rcItem.left += GetSystemMetrics(SM_CXSMICON) + GetSystemMetrics(SM_CXEDGE);
  2874. //
  2875. // Draw the text
  2876. //
  2877. szText[0] = 0;
  2878. SendMessage(lpdi->hwndItem, LB_GETTEXT, lpdi->itemID,
  2879. (LPARAM)szText);
  2880. DrawText(lpdi->hDC, szText, lstrlen(szText), &rcItem,
  2881. DT_LEFT | DT_VCENTER | DT_EXTERNALLEADING | DT_NOPREFIX | DT_SINGLELINE);
  2882. //
  2883. // Deselect bolded shared font
  2884. //
  2885. if (pItem->fShared)
  2886. {
  2887. SelectFont(lpdi->hDC, hfnT);
  2888. }
  2889. rc = TRUE;
  2890. DC_EXIT_POINT:
  2891. return(rc);
  2892. }
  2893. //
  2894. // HOST_ChangeShareState()
  2895. //
  2896. // Changes the sharing state of the currently selected item.
  2897. //
  2898. void HOST_ChangeShareState(HWND hwnd, UINT action)
  2899. {
  2900. int iItem;
  2901. PHOSTITEM pItem;
  2902. HWND hwndChange;
  2903. HCURSOR hcurT;
  2904. DebugEntry(HOST_ChangeShareState);
  2905. if (action == CHANGE_ALLUNSHARED)
  2906. {
  2907. hwndChange = HWND_BROADCAST;
  2908. action = CHANGE_UNSHARED;
  2909. goto ChangeState;
  2910. }
  2911. iItem = (int)SendDlgItemMessage(hwnd, CTRL_PROGRAM_LIST, LB_GETCURSEL, 0, 0);
  2912. if (iItem != -1)
  2913. {
  2914. pItem = (PHOSTITEM)SendDlgItemMessage(hwnd, CTRL_PROGRAM_LIST,
  2915. LB_GETITEMDATA, iItem, 0);
  2916. if (pItem && pItem->fAvailable)
  2917. {
  2918. hwndChange = pItem->hwnd;
  2919. if (action == CHANGE_TOGGLE)
  2920. {
  2921. if (HET_IsWindowShared(hwndChange))
  2922. {
  2923. action = CHANGE_UNSHARED;
  2924. }
  2925. else
  2926. {
  2927. action = CHANGE_SHARED;
  2928. }
  2929. }
  2930. ChangeState:
  2931. ASSERT((action == CHANGE_SHARED) || (action == CHANGE_UNSHARED));
  2932. //
  2933. // Set wait cursor
  2934. //
  2935. hcurT = SetCursor(LoadCursor(NULL, IDC_WAIT));
  2936. if (action == CHANGE_SHARED)
  2937. {
  2938. DCS_Share(hwndChange, IAS_SHARE_DEFAULT);
  2939. }
  2940. else
  2941. {
  2942. DCS_Unshare(hwndChange);
  2943. }
  2944. //
  2945. // Set wait cursor
  2946. //
  2947. SetCursor(hcurT);
  2948. }
  2949. }
  2950. DebugExitVOID(HOST_ChangeShareState);
  2951. }
  2952. //
  2953. // HOST_OnSelChange()
  2954. //
  2955. // Handles a selection change in the task list. We enable/disable
  2956. // buttons as appropriate, depending on whether item is available.
  2957. //
  2958. void HOST_OnSelChange(HWND hwnd)
  2959. {
  2960. int iItem;
  2961. PHOSTITEM pItem;
  2962. BOOL fShareBtn = FALSE;
  2963. BOOL fUnshareBtn = FALSE;
  2964. DebugEntry(HOST_OnSelChange);
  2965. //
  2966. // Get current selection, and decide what to do based off that.
  2967. //
  2968. iItem = (int)SendDlgItemMessage(hwnd, CTRL_PROGRAM_LIST, LB_GETCURSEL, 0, 0);
  2969. if (iItem != -1)
  2970. {
  2971. pItem = (PHOSTITEM)SendDlgItemMessage(hwnd, CTRL_PROGRAM_LIST,
  2972. LB_GETITEMDATA, iItem, 0);
  2973. if (pItem)
  2974. {
  2975. if (pItem->fShared)
  2976. {
  2977. fUnshareBtn = TRUE;
  2978. }
  2979. else if (pItem->fAvailable)
  2980. {
  2981. ASSERT(g_asSession.callID);
  2982. fShareBtn = TRUE;
  2983. }
  2984. }
  2985. }
  2986. HOST_EnableCtrl(hwnd, CTRL_UNSHARE_BTN, fUnshareBtn);
  2987. HOST_EnableCtrl(hwnd, CTRL_SHARE_BTN, fShareBtn);
  2988. DebugExitVOID(HOST_OnSelChange);
  2989. }
  2990. //
  2991. // HOST_EnableCtrl()
  2992. //
  2993. // This enables/disables the child control. If disabling, and this control
  2994. // used to have the focus, we make sure the dialog resets the focus control
  2995. // so the keyboard keeps working. We know that the Close button is always
  2996. // available, so this won't die.
  2997. //
  2998. void HOST_EnableCtrl
  2999. (
  3000. HWND hwnd,
  3001. UINT ctrl,
  3002. BOOL fEnable
  3003. )
  3004. {
  3005. HWND hwndCtrl;
  3006. DebugEntry(HOST_EnableCtrl);
  3007. hwndCtrl = GetDlgItem(hwnd, ctrl);
  3008. ASSERT(hwndCtrl);
  3009. if (fEnable)
  3010. {
  3011. EnableWindow(hwndCtrl, TRUE);
  3012. }
  3013. else
  3014. {
  3015. if (GetFocus() == hwndCtrl)
  3016. {
  3017. // Advance the focus
  3018. SendMessage(hwnd, WM_NEXTDLGCTL, 0, 0);
  3019. }
  3020. EnableWindow(hwndCtrl, FALSE);
  3021. }
  3022. DebugExitVOID(HOST_EnableCtrl);
  3023. }