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.

478 lines
14 KiB

  1. #include "precomp.h"
  2. //
  3. // AWC.CPP
  4. // Active Window Coordinator
  5. //
  6. // Copyright(c) Microsoft 1997-
  7. //
  8. #define MLZ_FILE_ZONE ZONE_CORE
  9. //
  10. // The AWC code does three things:
  11. // * Notifies everybody in the share what the current active window
  12. // is when sharing (either a shared window or something else)
  13. // * When in control, requests to restore/activate a remote's shared
  14. // window
  15. // * When being controlled, handles request to restore/activate
  16. // a local hosted window
  17. //
  18. //
  19. // For the purposes of this strategy the AWC packets can be split into two
  20. // categories.
  21. //
  22. // 1. Immediate - these are the packets which are generated when a shadow
  23. // window is controlled by some means other than direct keyboard or mouse
  24. // input to the shadow window (which is all sent to the host system and
  25. // handled there). Examples include the Task List, window switching
  26. // (Alt-TAB, Alt-Esc etc), minimising or closing another app which may pass
  27. // activation on to a shadow window etc. The packets in this category are:
  28. //
  29. // AWC_MSG_ACTIVATE_WINDOW
  30. // AWC_MSG_RESTORE_WINDOW
  31. //
  32. // These packets can be (and are) sent immediately that the event happens.
  33. // This is because they always refer to real windows on the host system.
  34. //
  35. // 2. Periodic - these are the packets sent when the AWC detects that the
  36. // active window has changed locally and it should inform the remote AWC.
  37. // This packet is sent when AWC_Periodic is called. The packets in this
  38. // category are:
  39. //
  40. // AWC_MSG_ACTIVE_CHANGE_SHARED
  41. // AWC_MSG_ACTIVE_CHANGE_LOCAL
  42. // AWC_MSG_ACTIVE_CHANGE_INVISIBLE
  43. //
  44. // These are only sent when AWC_Periodic is called because they may refer
  45. // to shadow windows and therefore we avoid sending it until we know that
  46. // the SWL has succesfully sent a window structure which includes the
  47. // window referenced in the message.
  48. //
  49. // For packets in the first category we will queue up to two packets and at
  50. // the point where we have three packets we cannot send we will discard
  51. // packets from the front of the queue so that a users most recent actions
  52. // have priority over any previous actions. We will try to send all queued
  53. // packets whenever a new category 1 packet is generated and on the
  54. // AWC_Periodic call.
  55. //
  56. // For packets in the second category we will drop the packets if we cannot
  57. // send them but remember that we have failed to send a packet and retry on
  58. // the next call to AWC_Periodic. This is not the same as queueing as the
  59. // active window may change between us dropping a packet and being able to
  60. // send the next packet from AWC_Periodic. Queuing the dropped packet
  61. // would have been pointless as it would now be out of date.
  62. //
  63. // All AWC packets go on the same stream (the updates stream) so that they
  64. // are guaranteed to arrive in the same order as they are generated to
  65. // prevent a AWC_MSG_ACTIVE_CHANGE_XXX being overtaken by an
  66. // AWC_MSG_ACTIVATE_WINDOW and therefore the effect of
  67. // AWC_MSG_ACTIVATE_WINDOW being overridden by the
  68. // AWC_MSG_ACTIVE_CHANGE_XXX.
  69. //
  70. //
  71. // AWC_ReceivedPacket()
  72. //
  73. void ASShare::AWC_ReceivedPacket
  74. (
  75. ASPerson * pasPerson,
  76. PS20DATAPACKET pPacket
  77. )
  78. {
  79. PAWCPACKET pAWCPacket;
  80. UINT activateWhat;
  81. HWND hwnd;
  82. DebugEntry(ASShare::AWC_ReceivedPacket);
  83. ValidatePerson(pasPerson);
  84. pAWCPacket = (PAWCPACKET)pPacket;
  85. //
  86. // We trace the person ID out here so we don't bother to do it
  87. // elsewhere in this function on TRACE lines.
  88. //
  89. TRACE_OUT(("AWC_ReceivedPacket from [%d] - msg %x token %u data 0x%08x",
  90. pasPerson->mcsID,
  91. pAWCPacket->msg,
  92. pAWCPacket->token,
  93. pAWCPacket->data1));
  94. if (AWC_IS_INDICATION(pAWCPacket->msg))
  95. {
  96. //
  97. // We should simply change the view of the remote.
  98. //
  99. if (pasPerson->awcActiveWinID != pAWCPacket->data1)
  100. {
  101. pasPerson->awcActiveWinID = pAWCPacket->data1;
  102. if (pasPerson->m_pView)
  103. {
  104. // Update the pressed item on the window bar.
  105. VIEW_WindowBarChangedActiveWindow(pasPerson);
  106. }
  107. }
  108. }
  109. else if (AWC_MSG_SAS == pAWCPacket->msg)
  110. {
  111. //
  112. // Cause Ctrl+Alt+Del to be injected if we're in a service app,
  113. // we're hosting, and we're controlled by the sender.
  114. //
  115. if ((g_asOptions & AS_SERVICE) && (pasPerson->m_caInControlOf == m_pasLocal))
  116. {
  117. ASSERT(m_pHost);
  118. OSI_InjectCtrlAltDel();
  119. }
  120. }
  121. else
  122. {
  123. hwnd = (HWND)pAWCPacket->data1;
  124. //
  125. // Only accept requests if we're being controlled currently by
  126. // this person. We might get renegade packets from remotes that
  127. // don't yet they aren't in control, or from back-level systems.
  128. //
  129. if (pasPerson->m_caInControlOf != m_pasLocal)
  130. {
  131. // We're not controlled by this person
  132. DC_QUIT;
  133. }
  134. ASSERT(m_pHost);
  135. if ((pAWCPacket->msg == AWC_MSG_ACTIVATE_WINDOW) &&
  136. IsWindow(hwnd) &&
  137. IsWindowEnabled(hwnd))
  138. {
  139. // Ony get owned window if enabled and we're activating.
  140. hwnd = GetLastActivePopup(hwnd);
  141. }
  142. if (IsWindow(hwnd) &&
  143. HET_WindowIsHosted(hwnd) &&
  144. IsWindowEnabled(hwnd))
  145. {
  146. switch (pAWCPacket->msg)
  147. {
  148. case AWC_MSG_ACTIVATE_WINDOW:
  149. //
  150. // Activate the window.
  151. //
  152. TRACE_OUT(("Received AWC_MSG_ACTIVATE_WINDOW for hwnd 0x%08x from [%d]",
  153. hwnd, pasPerson->mcsID));
  154. m_pHost->AWC_ActivateWindow(hwnd);
  155. break;
  156. case AWC_MSG_RESTORE_WINDOW:
  157. //
  158. // Restore the window
  159. //
  160. TRACE_OUT(("Received AWC_MSG_RESTORE_WINDOW for hwnd 0x%08x from [%d]",
  161. hwnd, pasPerson->mcsID));
  162. if (IsIconic(hwnd))
  163. {
  164. PostMessage(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
  165. }
  166. break;
  167. default:
  168. WARNING_OUT(("Received invalid msg %d from [%d]",
  169. pAWCPacket->msg, pasPerson->mcsID));
  170. break;
  171. }
  172. }
  173. }
  174. DC_EXIT_POINT:
  175. DebugExitVOID(ASShare::AWC_ReceivedPacket);
  176. }
  177. //
  178. // AWC_Periodic()
  179. //
  180. void ASHost::AWC_Periodic(void)
  181. {
  182. HWND currentActiveWindow;
  183. HWND sendActiveWindow;
  184. TSHR_UINT16 sendMsg;
  185. DebugEntry(ASHost::AWC_Periodic);
  186. //
  187. // If we are hosting the desktop, skip this.
  188. //
  189. if (m_pShare->m_pasLocal->hetCount == HET_DESKTOPSHARED)
  190. {
  191. // Skip.
  192. DC_QUIT;
  193. }
  194. //
  195. // Find the current active window.
  196. //
  197. if (SWL_IsOurDesktopActive())
  198. {
  199. currentActiveWindow = GetForegroundWindow();
  200. }
  201. else
  202. {
  203. // Another desktop is up.
  204. currentActiveWindow = NULL;
  205. }
  206. if (m_pShare->HET_WindowIsHosted(currentActiveWindow))
  207. {
  208. //
  209. // A window which belongs to shared application is active -
  210. // find out if it is visible.
  211. //
  212. if (IsWindowVisible(currentActiveWindow))
  213. {
  214. //
  215. // The active window is also visible - this means the
  216. // remote system will know about it as it will have
  217. // been sent in a preceding SWL message.
  218. //
  219. sendMsg = AWC_MSG_ACTIVE_CHANGE_SHARED;
  220. sendActiveWindow = SWL_GetSharedIDFromLocalID(currentActiveWindow);
  221. }
  222. else
  223. {
  224. //
  225. // The active window is invisible - this means that
  226. // although it is shared the remote system will not
  227. // know about it. Send a message to inform the remote
  228. // system about this.
  229. //
  230. sendMsg = AWC_MSG_ACTIVE_CHANGE_INVISIBLE;
  231. sendActiveWindow = 0;
  232. }
  233. }
  234. else
  235. {
  236. //
  237. // A local application has been activated send
  238. // AWC_ACTIVE_WINDOW_LOCAL.
  239. //
  240. sendMsg = AWC_MSG_ACTIVE_CHANGE_LOCAL;
  241. sendActiveWindow = 0;
  242. }
  243. //
  244. // Now send the packet if it's not the same as the last packet we
  245. // sent. NOTE that for local unshared windows, we don't care if
  246. // we've deactivated one and activated another, they are generic. So
  247. // we send a message if we
  248. // * change activation from a shared window
  249. // * change activation to a shared window
  250. //
  251. if ((sendActiveWindow != m_awcLastActiveWindow) ||
  252. (sendMsg != m_awcLastActiveMsg))
  253. {
  254. //
  255. // Note that this packet is sent on the updates stream so that it
  256. // cannot overtake a SWL packet containing the newly active window.
  257. //
  258. TRACE_OUT(("Broadcasting AWC change msg %x, hwnd 0x%08x",
  259. sendMsg, sendActiveWindow));
  260. if (m_pShare->AWC_SendMsg(g_s20BroadcastID, sendMsg, HandleToUlong(sendActiveWindow), 0))
  261. {
  262. //
  263. // The packet was sent succesfully - remember which window we
  264. // sent.
  265. //
  266. m_awcLastActiveWindow = sendActiveWindow;
  267. m_awcLastActiveMsg = sendMsg;
  268. }
  269. else
  270. {
  271. //
  272. // The packet could not be sent for some reason - set
  273. // m_awcLastActiveWindow to invalid so that we will try again
  274. // on the next call to AWC_Periodic.
  275. //
  276. m_awcLastActiveWindow = AWC_INVALID_HWND;
  277. m_awcLastActiveMsg = AWC_MSG_INVALID;
  278. }
  279. }
  280. DC_EXIT_POINT:
  281. DebugExitVOID(ASHost::AWC_Periodic);
  282. }
  283. //
  284. // AWC_SyncOutgoing()
  285. //
  286. void ASHost::AWC_SyncOutgoing(void)
  287. {
  288. DebugEntry(ASHost::AWC_SyncOutgoing);
  289. //
  290. // Ensure that we resend an indication message as soon as possible
  291. //
  292. m_awcLastActiveWindow = AWC_INVALID_HWND;
  293. m_awcLastActiveMsg = AWC_MSG_INVALID;
  294. DebugExitVOID(ASHost::AWC_SyncOutgoing);
  295. }
  296. //
  297. // FUNCTION: AWC_SendMsg
  298. //
  299. // DESCRIPTION:
  300. //
  301. // Sends a AWC message to remote system
  302. // * Requests to activate are just to one host
  303. // * Notifications of activation are to everyone
  304. //
  305. // RETURNS: TRUE or FALSE - success or failure
  306. //
  307. //
  308. BOOL ASShare::AWC_SendMsg
  309. (
  310. UINT_PTR nodeID,
  311. UINT msg,
  312. UINT_PTR data1,
  313. UINT_PTR data2
  314. )
  315. {
  316. PAWCPACKET pAWCPacket;
  317. BOOL rc = FALSE;
  318. #ifdef _DEBUG
  319. UINT sentSize;
  320. #endif
  321. DebugEntry(ASShare::AWC_SendMsg);
  322. //
  323. // Allocate correct sized packet.
  324. //
  325. pAWCPacket = (PAWCPACKET)SC_AllocPkt(PROT_STR_UPDATES, nodeID, sizeof(AWCPACKET));
  326. if (!pAWCPacket)
  327. {
  328. WARNING_OUT(("Failed to alloc AWC packet"));
  329. DC_QUIT;
  330. }
  331. //
  332. // Set up the data header for an AWC message.
  333. //
  334. pAWCPacket->header.data.dataType = DT_AWC;
  335. //
  336. // Now set up the AWC fields. By passing AWC_SYNC_MSG_TOKEN in the
  337. // token field, we ensure that back-level remotes will never drop our
  338. // packets.
  339. //
  340. pAWCPacket->msg = (TSHR_UINT16)msg;
  341. pAWCPacket->data1 = data1;
  342. pAWCPacket->data2 = data2;
  343. pAWCPacket->token = AWC_SYNC_MSG_TOKEN;
  344. //
  345. // Send the packet.
  346. //
  347. if (m_scfViewSelf)
  348. AWC_ReceivedPacket(m_pasLocal, &(pAWCPacket->header));
  349. #ifdef _DEBUG
  350. sentSize =
  351. #endif // _DEBUG
  352. DCS_CompressAndSendPacket(PROT_STR_UPDATES, nodeID,
  353. &(pAWCPacket->header), sizeof(*pAWCPacket));
  354. TRACE_OUT(("AWC packet size: %08d, sent: %08d", sizeof(*pAWCPacket), sentSize));
  355. rc = TRUE;
  356. DC_EXIT_POINT:
  357. DebugExitDWORD(ASShare::AWC_SendMsg, rc);
  358. return(rc);
  359. }
  360. //
  361. // AWC_ActivateWindow()
  362. //
  363. // Activates a shared window via a remote controller's request.
  364. //
  365. void ASHost::AWC_ActivateWindow(HWND window)
  366. {
  367. BOOL rcSFW;
  368. HWND hwndForeground;
  369. DebugEntry(ASHost::AWC_ActivateWindow);
  370. if (!IsWindow(window))
  371. {
  372. WARNING_OUT(( "Trying to activate invalid window %08x", window));
  373. DC_QUIT;
  374. }
  375. //
  376. // SetForegroundWindow appears to be asynchronous. That is, it may
  377. // return successfully here but immediately querying the active
  378. // window does not always reveal the newly set foreground window to
  379. // be active.
  380. //
  381. rcSFW = SetForegroundWindow(window);
  382. hwndForeground = GetForegroundWindow();
  383. if (hwndForeground != window)
  384. {
  385. //
  386. // If a Screen Saver is active then it always refuses to let us
  387. // activate another window. Trace an alert if the call to
  388. // SetForegroundWindow, above, failed.
  389. //
  390. if (OSI_IsWindowScreenSaver(hwndForeground) ||
  391. (m_swlCurrentDesktop != DESKTOP_OURS))
  392. {
  393. WARNING_OUT(("Screen Saver or other desktop is up, failed to activate window 0x%08x",
  394. window));
  395. }
  396. else if ( !rcSFW )
  397. {
  398. //
  399. // The active window is not the one we set because
  400. // SetForegroundWindow failed.
  401. //
  402. WARNING_OUT(("Failed to activate window 0x%08x", window));
  403. }
  404. //
  405. // We have apparently failed to set the active window, but
  406. // SetForegroundWindow succeeded. This is probably just a lag in
  407. // Windows getting up to date, so continue as if all is normal.
  408. //
  409. }
  410. //
  411. // Whether we succeeded or failed, make sure we broadcast the current
  412. // active window.
  413. //
  414. m_awcLastActiveWindow = AWC_INVALID_HWND;
  415. m_awcLastActiveMsg = AWC_MSG_INVALID;
  416. DC_EXIT_POINT:
  417. DebugExitVOID(ASHost::AWC_ActivateWindow);
  418. }