Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

544 lines
14 KiB

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