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.

468 lines
14 KiB

  1. #include "precomp.h"
  2. #ifndef DM_POSITION
  3. #define DM_POSITION 0x00000020L
  4. #endif
  5. //
  6. // OSI.CPP
  7. // OS Isolation layer, NT version
  8. //
  9. // Copyright(c) Microsoft 1997-
  10. //
  11. #include <version.h>
  12. #include <ndcgver.h>
  13. #include <osi.h>
  14. #define MLZ_FILE_ZONE ZONE_CORE
  15. //
  16. // NT 5.0 app sharing stuff.
  17. // NOTE:
  18. // The name for NetMeeting's display driver, s_szNmDD, comes from
  19. // mnmdd.sys. We have no define for it nor access to the source. DO NOT
  20. // CHANGE THIS without talking to Andre Vachon. Hopefully, he will perform
  21. // the same courtesy for us if he changes mnmdd.sys. If not, we can't share
  22. // anymore. We won't even find our driver to load.
  23. //
  24. typedef BOOL (WINAPI * FN_ENUMDD)(LPVOID, DWORD, LPDISPLAY_DEVICE, DWORD);
  25. static TCHAR s_szNmDD[] = "NetMeeting driver";
  26. //
  27. // OSI_Load()
  28. // This handles our process attach. We figure out if this is NT5 or not
  29. //
  30. void OSI_Load(void)
  31. {
  32. OSVERSIONINFO osVersion;
  33. ZeroMemory(&osVersion, sizeof(osVersion));
  34. osVersion.dwOSVersionInfoSize = sizeof(osVersion);
  35. GetVersionEx(&osVersion);
  36. ASSERT(osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT);
  37. if (osVersion.dwMajorVersion >= 5)
  38. g_asNT5 = TRUE;
  39. }
  40. //
  41. // OSI_Unload()
  42. // This handles our process detach. We currently do nothing.
  43. //
  44. void OSI_Unload(void)
  45. {
  46. return;
  47. }
  48. //
  49. // OSI_InitDriver50()
  50. //
  51. // Attemps to dynamically load/unload our display driver for NT 5.0. This is
  52. // called on the main thread, and if under a service, on the winlogon
  53. // thread also. It will only succeed on the input focus desktop.
  54. //
  55. void OSI_InitDriver50(BOOL fInit)
  56. {
  57. DWORD iEnum;
  58. DISPLAY_DEVICE dd;
  59. DEVMODE devmode;
  60. FN_ENUMDD pfnEnumDD;
  61. DebugEntry(OSI_InitDriver50);
  62. ASSERT(g_asNT5);
  63. pfnEnumDD = (FN_ENUMDD)GetProcAddress(GetModuleHandle("USER32.DLL"),
  64. "EnumDisplayDevicesA");
  65. if (pfnEnumDD != NULL)
  66. {
  67. ZeroMemory(&dd, sizeof(dd));
  68. dd.cb = sizeof(dd);
  69. iEnum = 0;
  70. while (pfnEnumDD(NULL, iEnum++, &dd, 0))
  71. {
  72. if ((dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) &&
  73. !lstrcmpi((LPCSTR)dd.DeviceString, s_szNmDD))
  74. {
  75. LONG lResult;
  76. //
  77. // There may be multiple monitors, drivers, etc.
  78. // We have to actually tell the system what bit depth,
  79. // format, etc. our driver wants just like if we were
  80. // a real driver. We therefore always ask to get 24bpp
  81. // format info, no myriad 16bpp and 32bpp formats to deal
  82. // with anymore.
  83. //
  84. // Also, no more 4bpp not VGA nonsense either--just 8 or 24.
  85. //
  86. ZeroMemory(&devmode, sizeof(devmode));
  87. devmode.dmSize = sizeof(devmode);
  88. devmode.dmFields = DM_POSITION | DM_BITSPERPEL | DM_PELSWIDTH |
  89. DM_PELSHEIGHT;
  90. if (fInit)
  91. {
  92. //
  93. // Fill in fields to get driver attached.
  94. //
  95. if (g_usrCaptureBPP <= 8)
  96. g_usrCaptureBPP = 8;
  97. else
  98. g_usrCaptureBPP = 24;
  99. devmode.dmBitsPerPel = g_usrCaptureBPP;
  100. // devmode.dmPosition is (0, 0), this means "primary"
  101. devmode.dmPelsWidth = GetSystemMetrics(SM_CXSCREEN);
  102. devmode.dmPelsHeight = GetSystemMetrics(SM_CYSCREEN);
  103. }
  104. //
  105. // Before we change the display settings in a multimonitor machine, we better move the cursor out of the way
  106. // If we do not do do we get an extra cursor in the middle of the primary monitor
  107. //
  108. ::SetCursorPos(-1, -1);
  109. //
  110. // This simply changes the state in the registry from
  111. // attached to unattached, without the system actually
  112. // reflecting the change. If/when we have multiple
  113. // listings for our shadow driver, move the CDS(NULL, 0)
  114. // call outside the loop, and get rid of the break.
  115. //
  116. lResult = ChangeDisplaySettingsEx((LPCSTR)dd.DeviceName, &devmode,
  117. NULL, CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
  118. if (lResult != DISP_CHANGE_SUCCESSFUL)
  119. {
  120. WARNING_OUT(("ChangeDisplaySettingsEx failed, error %d", lResult));
  121. }
  122. else
  123. {
  124. //
  125. // This causes Windows to actually go reread the registry and
  126. // update the current display to reflect the attached items,
  127. // positions, sizes, and color depths.
  128. //
  129. ChangeDisplaySettings(NULL, 0);
  130. #ifdef _DEBUG
  131. if (fInit)
  132. {
  133. HDC hdc;
  134. //
  135. // Create a temp DC based on this driver and make sure
  136. // the settings matched what we asked for.
  137. //
  138. hdc = CreateDC(NULL, (LPCSTR)dd.DeviceName, NULL, NULL);
  139. if (!hdc)
  140. {
  141. WARNING_OUT(("OSI_Init: dynamic display driver load failed"));
  142. }
  143. else
  144. {
  145. ASSERT(GetDeviceCaps(hdc, HORZRES) == (int)devmode.dmPelsWidth);
  146. ASSERT(GetDeviceCaps(hdc, VERTRES) == (int)devmode.dmPelsHeight);
  147. ASSERT(GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES) ==
  148. (int)g_usrCaptureBPP);
  149. DeleteDC(hdc);
  150. }
  151. }
  152. #endif // _DEBUG
  153. //
  154. // Tell MNMHOOK_ the name of our driver so it can talk
  155. // to it via ExtEscape.
  156. //
  157. OSI_SetDriverName(fInit ? (LPCSTR)dd.DeviceName : NULL);
  158. }
  159. break;
  160. }
  161. }
  162. }
  163. DebugExitVOID(OSI_InitDriver50);
  164. }
  165. //
  166. // OSI_Init - see osi.h
  167. //
  168. void OSI_Init(void)
  169. {
  170. UINT i;
  171. OSI_INIT_REQUEST requestBuffer;
  172. OSI_INIT_REQUEST requestTerm;
  173. DebugEntry(OSI_Init);
  174. //
  175. // First, setup up pointer to shared data. This data lives here in NT.
  176. //
  177. #ifdef DEBUG
  178. g_imSharedData.cbSize = sizeof(g_imSharedData);
  179. #endif
  180. g_lpimSharedData = &g_imSharedData;
  181. requestBuffer.result = FALSE;
  182. requestBuffer.pSharedMemory = NULL;
  183. requestBuffer.poaData[0] = NULL;
  184. requestBuffer.poaData[1] = NULL;
  185. requestBuffer.sbcEnabled = FALSE;
  186. for (i = 0; i < SBC_NUM_TILE_SIZES; i++)
  187. {
  188. ASSERT(!g_asbcShuntBuffers[i]);
  189. requestBuffer.psbcTileData[i] = NULL;
  190. }
  191. //
  192. // Do this FIRST. On NT5, only threads on the desktop with input
  193. // can succeed at calling ChangeDisplaySettings. So like other things,
  194. // we must try to dynamically load/unload our driver on both desks.
  195. //
  196. //
  197. // Create the winlogon desktop event injection helper thread
  198. // only if we're started as a service. Note that it will try to
  199. // load display at start too.
  200. //
  201. ASSERT(!g_imNTData.imOtherDesktopThread);
  202. if (g_asOptions & AS_SERVICE)
  203. {
  204. WARNING_OUT(("Starting other desktop thread for SERVICE"));
  205. if (!DCS_StartThread(IMOtherDesktopProc))
  206. {
  207. WARNING_OUT(( "Failed to create other desktop IM thread"));
  208. DC_QUIT;
  209. }
  210. }
  211. //
  212. // DO THIS ONLY FOR NT5
  213. // We are going to enumerate all the entries for our shadow driver
  214. // (currently only one) and attach each to the actual display.
  215. //
  216. if (g_asNT5)
  217. {
  218. OSI_InitDriver50(TRUE);
  219. }
  220. DC_EXIT_POINT:
  221. //$wilhelms - calling OSI_ESC_TERM in this case does not really help.
  222. // In the driver we try to delete the WNDOBJ objects on OSI_ESC_TERM
  223. // and we fail. The reason for that is the fact that you can't call EngDeleteWnd
  224. // if you are not in the context of a DrvEscape WNDOBJ_SETUP. If you are in the
  225. // right context GDI will aquire some locks before calling into your DrvEscape.
  226. // Without the right locks the EngDeleteWnd will fail.
  227. // First we will call HetClear to unshare all the windows (clear the atom and tell the
  228. // driver to delete the window tracking object). And then we will to a OSI_ESC_TERM to clean up other structures.
  229. // Note that the HET_ESC_UNSHARE_ALL is called as a WNDOBJ_SETUP function.
  230. HET_Clear();
  231. ZeroMemory(&requestTerm, sizeof(requestTerm));
  232. OSI_FunctionRequest(OSI_ESC_TERM, (LPOSI_ESCAPE_HEADER)&requestTerm,
  233. sizeof(requestTerm));
  234. g_osiInitialized = OSI_FunctionRequest(OSI_ESC_INIT, (LPOSI_ESCAPE_HEADER)&requestBuffer,
  235. sizeof(requestBuffer));
  236. if (!g_osiInitialized)
  237. {
  238. WARNING_OUT(("OSI_ESC_INIT: display driver not present"));
  239. }
  240. else
  241. {
  242. if (requestBuffer.result)
  243. {
  244. g_asCanHost = TRUE;
  245. //
  246. // Got shared memory pointers; keep them around
  247. //
  248. g_asSharedMemory = (LPSHM_SHARED_MEMORY)requestBuffer.pSharedMemory;
  249. ASSERT(g_asSharedMemory);
  250. g_poaData[0] = (LPOA_SHARED_DATA)requestBuffer.poaData[0];
  251. ASSERT(g_poaData[0]);
  252. g_poaData[1] = (LPOA_SHARED_DATA)requestBuffer.poaData[1];
  253. ASSERT(g_poaData[1]);
  254. g_sbcEnabled = requestBuffer.sbcEnabled;
  255. if (g_sbcEnabled)
  256. {
  257. //
  258. // Get shunt buffers
  259. //
  260. for (i = 0; i < SBC_NUM_TILE_SIZES; i++)
  261. {
  262. g_asbcShuntBuffers[i] = (LPSBC_SHUNT_BUFFER)requestBuffer.psbcTileData[i];
  263. ASSERT(g_asbcShuntBuffers[i]);
  264. TRACE_OUT(("OSI_Init: sbc shunt buffer %d: entries %08d, bytes 0x%08x",
  265. i, g_asbcShuntBuffers[i]->numEntries, g_asbcShuntBuffers[i]->numBytes));
  266. }
  267. for (i = 0; i < 3; i++)
  268. {
  269. g_asbcBitMasks[i] = requestBuffer.aBitmasks[i];
  270. }
  271. }
  272. }
  273. }
  274. if (g_asCanHost)
  275. {
  276. //
  277. // Tell HOOK dll (used for control as well as sharing) about our hwnd
  278. // and stuff. If we are able to host.
  279. //
  280. ASSERT(g_asMainWindow);
  281. ASSERT(g_asHostProp);
  282. HOOK_Init(g_asMainWindow, g_asHostProp);
  283. }
  284. DebugExitVOID(OSI_Init);
  285. }
  286. //
  287. // OSI_Term - see osi.h
  288. //
  289. void OSI_Term(void)
  290. {
  291. UINT i;
  292. DebugEntry(OSI_Term);
  293. //
  294. // This can be called on multiple threads:
  295. // * The main DCS thread
  296. // * The last thread of the process causing us to get a process
  297. // detach.
  298. // We call it in the latter case also to make sure we cleanup properly.
  299. //
  300. ASSERT(GetCurrentThreadId() == g_asMainThreadId);
  301. //
  302. // Kill the other desktop thread if it's around.
  303. //
  304. if (g_imNTData.imOtherDesktopThread != 0)
  305. {
  306. ASSERT(g_asOptions & AS_SERVICE);
  307. PostThreadMessage(g_imNTData.imOtherDesktopThread, WM_QUIT, 0, 0);
  308. while (g_imNTData.imOtherDesktopThread)
  309. {
  310. WARNING_OUT(("OSI_Term: waiting for other desktop thread to exit"));
  311. Sleep(1);
  312. }
  313. }
  314. if (g_osiInitialized)
  315. {
  316. OSI_TERM_REQUEST requestBuffer;
  317. g_osiInitialized = FALSE;
  318. //
  319. // We call the term routine only if the driver is actually loaded
  320. // (as opposed to whether something went wrong when trying to setup
  321. // for hosting) so that we will cleanup if something went wrong in
  322. // the middle.
  323. //
  324. OSI_FunctionRequest(OSI_ESC_TERM, (LPOSI_ESCAPE_HEADER)&requestBuffer,
  325. sizeof(requestBuffer));
  326. }
  327. //
  328. // ONLY DO THIS FOR NT5
  329. // We need to undo all the work we did at init time to attach our
  330. // driver(s) to the display, and detach them. Again, enumerate the
  331. // registry entries and look for ours.
  332. //
  333. //
  334. if (g_asNT5)
  335. {
  336. OSI_InitDriver50(FALSE);
  337. }
  338. // Clear our shared memory variables
  339. for (i = 0; i < 3; i++)
  340. {
  341. g_asbcBitMasks[i] = 0;
  342. }
  343. for (i = 0; i < SBC_NUM_TILE_SIZES; i++)
  344. {
  345. g_asbcShuntBuffers[i] = NULL;
  346. }
  347. g_sbcEnabled = FALSE;
  348. g_asSharedMemory = NULL;
  349. g_poaData[0] = NULL;
  350. g_poaData[1] = NULL;
  351. g_asCanHost = FALSE;
  352. g_lpimSharedData = NULL;
  353. DebugExitVOID(OSI_Term);
  354. }
  355. VOID OSI_RepaintDesktop(void)
  356. {
  357. DebugEntry(OSI_RepaintDesktop);
  358. // If this does not appear to be a window it may be a window on the
  359. // winlogon desktop, so we need to get the proxy thread to repaint it
  360. if ( g_imNTData.imOtherDesktopThread )
  361. {
  362. PostThreadMessage(g_imNTData.imOtherDesktopThread,
  363. OSI_WM_DESKTOPREPAINT, 0, 0);
  364. }
  365. DebugExitVOID(OSI_RepaintDesktop);
  366. }
  367. VOID OSI_SetGUIEffects(BOOL fOff)
  368. {
  369. DebugEntry(OSI_SetGUIEffects);
  370. if (g_imNTData.imOtherDesktopThread)
  371. {
  372. PostThreadMessage(g_imNTData.imOtherDesktopThread,
  373. OSI_WM_SETGUIEFFECTS, fOff, 0);
  374. }
  375. DebugExitVOID(OSI_SetGUIEffects);
  376. }