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.

413 lines
9.1 KiB

  1. /*++
  2. Copyright (c) 2000-2002 Microsoft Corporation
  3. Module Name:
  4. RestrictDisplayModes.cpp
  5. Abstract:
  6. Restrict the mode list enumerated by EnumDisplaySettings. This shim was
  7. built for an application that enumerated only 10 modes and was hoping to
  8. find 800x600 in that list. However, other applications that have fixed
  9. size buffers for mode tables may also find this shim useful.
  10. Notes:
  11. This is a general purpose shim.
  12. History:
  13. 05/05/2000 linstev Created
  14. 02/18/2002 robkenny Protected g_pModeTable with a critical section
  15. --*/
  16. #include "precomp.h"
  17. #include "CharVector.h"
  18. IMPLEMENT_SHIM_BEGIN(HideDisplayModes)
  19. #include "ShimHookMacro.h"
  20. APIHOOK_ENUM_BEGIN
  21. APIHOOK_ENUM_ENTRY(EnumDisplaySettingsA)
  22. APIHOOK_ENUM_ENTRY(EnumDisplaySettingsW)
  23. APIHOOK_ENUM_END
  24. //
  25. // Data needed in mode table
  26. //
  27. typedef struct _MODE
  28. {
  29. DWORD dmBitsPerPel;
  30. DWORD dmPelsWidth;
  31. DWORD dmPelsHeight;
  32. DWORD dmDisplayFlags;
  33. DWORD dmDisplayFrequency;
  34. DWORD dwActualIndex;
  35. DWORD bIgnore;
  36. } MODE;
  37. // Used by BuildModeList to prevent multiple simultaneous access to g_pModeTable
  38. CRITICAL_SECTION g_CriticalSection;
  39. // Permanent mode table
  40. MODE* g_pModeTable = NULL;
  41. // Number of entries in the mode table
  42. DWORD g_dwCount = 0;
  43. // Build the mode table on first call
  44. BOOL g_bInit = FALSE;
  45. void BuildModeList(void);
  46. /*++
  47. Lookup from the sanitized mode table.
  48. --*/
  49. BOOL
  50. APIHOOK(EnumDisplaySettingsA)(
  51. LPCSTR lpszDeviceName,
  52. DWORD iModeNum,
  53. LPDEVMODEA lpDevMode
  54. )
  55. {
  56. BuildModeList();
  57. BOOL bRet = FALSE;
  58. if (lpszDeviceName || ((LONG)iModeNum < 0) || !g_pModeTable) {
  59. bRet = ORIGINAL_API(EnumDisplaySettingsA)(
  60. lpszDeviceName,
  61. iModeNum,
  62. lpDevMode);
  63. } else if (iModeNum < g_dwCount) {
  64. MODE* pmode = g_pModeTable + iModeNum;
  65. bRet = ORIGINAL_API(EnumDisplaySettingsA)(
  66. lpszDeviceName,
  67. pmode->dwActualIndex,
  68. lpDevMode);
  69. if (bRet) {
  70. LOGN(
  71. eDbgLevelError,
  72. "[EnumDisplaySettingsA] Returning shorter list of display modes.");
  73. lpDevMode->dmBitsPerPel = pmode->dmBitsPerPel;
  74. lpDevMode->dmPelsWidth = pmode->dmPelsWidth;
  75. lpDevMode->dmPelsHeight = pmode->dmPelsHeight;
  76. lpDevMode->dmDisplayFlags = pmode->dmDisplayFlags;
  77. lpDevMode->dmDisplayFrequency = pmode->dmDisplayFrequency;
  78. }
  79. }
  80. return bRet;
  81. }
  82. /*++
  83. Lookup from the sanitized mode table.
  84. --*/
  85. BOOL
  86. APIHOOK(EnumDisplaySettingsW)(
  87. LPCWSTR lpszDeviceName,
  88. DWORD iModeNum,
  89. LPDEVMODEW lpDevMode
  90. )
  91. {
  92. BuildModeList();
  93. BOOL bRet = FALSE;
  94. if (lpszDeviceName || ((LONG)iModeNum < 0) || !g_pModeTable) {
  95. bRet = ORIGINAL_API(EnumDisplaySettingsW)(
  96. lpszDeviceName,
  97. iModeNum,
  98. lpDevMode);
  99. } else if (iModeNum < g_dwCount) {
  100. MODE* pmode = g_pModeTable + iModeNum;
  101. bRet = ORIGINAL_API(EnumDisplaySettingsW)(
  102. lpszDeviceName,
  103. pmode->dwActualIndex,
  104. lpDevMode);
  105. if (bRet) {
  106. LOGN(
  107. eDbgLevelError,
  108. "[EnumDisplaySettingsW] Returning shorter list of display modes.");
  109. lpDevMode->dmBitsPerPel = pmode->dmBitsPerPel;
  110. lpDevMode->dmPelsWidth = pmode->dmPelsWidth;
  111. lpDevMode->dmPelsHeight = pmode->dmPelsHeight;
  112. lpDevMode->dmDisplayFlags = pmode->dmDisplayFlags;
  113. lpDevMode->dmDisplayFrequency = pmode->dmDisplayFrequency;
  114. }
  115. }
  116. return bRet;
  117. }
  118. /*++
  119. Sort the table by Width+Height+BitsPerPel+Frequency in that order so that
  120. they can be easily filtered.
  121. --*/
  122. int
  123. _cdecl
  124. compare1(
  125. const void* a1,
  126. const void* a2
  127. )
  128. {
  129. MODE* arg1 = (MODE*)a1;
  130. MODE* arg2 = (MODE*)a2;
  131. int d;
  132. d = arg1->dmPelsWidth - arg2->dmPelsWidth;
  133. if (d == 0) {
  134. d = arg1->dmPelsHeight - arg2->dmPelsHeight;
  135. }
  136. if (d == 0) {
  137. d = arg1->dmBitsPerPel - arg2->dmBitsPerPel;
  138. }
  139. if (d == 0) {
  140. d = arg1->dmDisplayFrequency - arg2->dmDisplayFrequency;
  141. }
  142. return d;
  143. }
  144. /*++
  145. Sort the table so it looks like a Win9x mode table, i.e. BitsPerPel is the
  146. primary sort key.
  147. --*/
  148. int
  149. _cdecl
  150. compare2(
  151. const void* a1,
  152. const void* a2
  153. )
  154. {
  155. MODE* arg1 = (MODE*)a1;
  156. MODE* arg2 = (MODE*)a2;
  157. int d;
  158. d = arg1->dmBitsPerPel - arg2->dmBitsPerPel;
  159. if (d == 0) {
  160. d = arg1->dmPelsWidth - arg2->dmPelsWidth;
  161. }
  162. if (d == 0) {
  163. d = arg1->dmPelsHeight - arg2->dmPelsHeight;
  164. }
  165. if (d == 0) {
  166. d = arg1->dmDisplayFrequency - arg2->dmDisplayFrequency;
  167. }
  168. return d;
  169. }
  170. /*++
  171. Create a new mode table based upon the sanitized existing table. To do this,
  172. we do the following:
  173. 1. Get the entire table
  174. 2. Sort it - to allow efficient removal of duplicates
  175. 3. Remove duplicates and unwanted modes
  176. 4. Build a new table with only the modes that 'pass'
  177. --*/
  178. void
  179. BuildModeList(
  180. void
  181. )
  182. {
  183. CAutoCrit autoCrit(&g_CriticalSection);
  184. if (g_bInit) {
  185. return;
  186. }
  187. DEVMODEA dm;
  188. ULONG i, j;
  189. dm.dmSize = sizeof(DEVMODEA);
  190. //
  191. // Figure out how many modes there are.
  192. //
  193. i = 0;
  194. while (EnumDisplaySettingsA(NULL, i, &dm)) {
  195. i++;
  196. }
  197. //
  198. // Allocate the full mode table.
  199. //
  200. MODE* pTempTable = (MODE*)malloc(sizeof(MODE) * i);
  201. if (!pTempTable) {
  202. LOGN(
  203. eDbgLevelError,
  204. "[BuildModeList] Failed to allocate %d bytes.",
  205. sizeof(MODE) * i);
  206. return;
  207. }
  208. MODE* pmode = pTempTable;
  209. //
  210. // Get all the modes.
  211. //
  212. i = 0;
  213. while (EnumDisplaySettingsA(NULL, i, &dm)) {
  214. pmode->dmBitsPerPel = dm.dmBitsPerPel;
  215. pmode->dmPelsWidth = dm.dmPelsWidth;
  216. pmode->dmPelsHeight = dm.dmPelsHeight;
  217. pmode->dmDisplayFlags = dm.dmDisplayFlags;
  218. pmode->dmDisplayFrequency = 0; // dm.dmDisplayFrequency;
  219. pmode->dwActualIndex = i;
  220. pmode->bIgnore = FALSE;
  221. pmode++;
  222. i++;
  223. }
  224. //
  225. // Sort the full table so we can remove duplicates easily.
  226. //
  227. qsort((void*)pTempTable, (size_t)i, sizeof(MODE), compare1);
  228. //
  229. // Strip away bad modes by setting them as ignored.
  230. //
  231. pmode = pTempTable;
  232. MODE* pprev = NULL;
  233. for (j = 0; j < i; j++) {
  234. if ((pmode->dmBitsPerPel < 8) ||
  235. (pmode->dmPelsWidth < 640) ||
  236. (pmode->dmPelsHeight < 480) ||
  237. (pmode->dmPelsWidth > 1280) ||
  238. (pprev &&
  239. (pprev->dmBitsPerPel == pmode->dmBitsPerPel) &&
  240. (pprev->dmPelsWidth == pmode->dmPelsWidth) &&
  241. (pprev->dmPelsHeight == pmode->dmPelsHeight))) {
  242. //
  243. // Special-case 640x480x4bit.
  244. //
  245. if ((pmode->dmBitsPerPel == 4) &&
  246. (pmode->dmPelsWidth == 640) &&
  247. (pmode->dmPelsHeight == 480)) {
  248. g_dwCount++;
  249. } else {
  250. pmode->bIgnore = TRUE;
  251. }
  252. } else {
  253. g_dwCount++;
  254. }
  255. pprev = pmode;
  256. pmode++;
  257. }
  258. //
  259. // Build the new table with only the modes that passed.
  260. //
  261. g_pModeTable = (MODE*)malloc(sizeof(MODE) * g_dwCount);
  262. if (!g_pModeTable) {
  263. LOGN(
  264. eDbgLevelError,
  265. "[BuildModeList] Failed to allocate %d bytes.",
  266. sizeof(MODE) * g_dwCount);
  267. free(pTempTable);
  268. return;
  269. }
  270. MODE* pmoden = g_pModeTable;
  271. pmode = pTempTable;
  272. for (j = 0; j < i; j++) {
  273. if (!pmode->bIgnore) {
  274. MoveMemory(pmoden, pmode, sizeof(MODE));
  275. pmoden++;
  276. }
  277. pmode++;
  278. }
  279. //
  280. // Sort the full table so we can remove duplicates easily.
  281. //
  282. qsort((void*)g_pModeTable, (size_t)g_dwCount, sizeof(MODE), compare2);
  283. free(pTempTable);
  284. g_bInit = TRUE;
  285. }
  286. BOOL
  287. NOTIFY_FUNCTION(
  288. DWORD fdwReason)
  289. {
  290. if (fdwReason == DLL_PROCESS_ATTACH)
  291. {
  292. return InitializeCriticalSectionAndSpinCount(&g_CriticalSection, 0x80000000);
  293. }
  294. return TRUE;
  295. }
  296. /*++
  297. Register hooked functions
  298. --*/
  299. HOOK_BEGIN
  300. CALL_NOTIFY_FUNCTION
  301. APIHOOK_ENTRY(USER32.DLL, EnumDisplaySettingsA)
  302. APIHOOK_ENTRY(USER32.DLL, EnumDisplaySettingsW)
  303. HOOK_END
  304. IMPLEMENT_SHIM_END