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.

798 lines
21 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // File: PROPSEXT.CPP
  4. //
  5. // Implementation of the CPropSheetExt object.
  6. //
  7. //---------------------------------------------------------------------------
  8. #include <windows.h>
  9. #include <stddef.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include "propsext.h"
  13. #include "rc.h"
  14. #include "string.h"
  15. #include "addon.h"
  16. #include <shlobj.h>
  17. //
  18. // Defines for getting registry settings
  19. //
  20. #define STR_MCDKEY (PCSTR)"Software\\Microsoft\\Windows\\CurrentVersion\\MCD"
  21. #define STR_ENABLE (LPSTR)"Enable"
  22. #define STR_SWAPSYNC (LPSTR)"SwapSync"
  23. #define STR_8BPP (LPSTR)"Palettized Formats"
  24. #define STR_IOPRIORITY (LPSTR)"IO Priority"
  25. #define STR_STENCIL (LPSTR)"Use Generic Stencil"
  26. #define STR_DEBUG (LPSTR)"Debug"
  27. #define STR_DCIKEY (PCSTR)"System\\CurrentControlSet\\Control\\GraphicsDrivers\\DCI"
  28. #define STR_TIMEOUT (LPSTR)"TimeOut"
  29. //
  30. // Structure describing current MCD settings.
  31. //
  32. typedef struct tagMcdRegistry
  33. {
  34. HKEY hkMcd; // Handle to MCD key in registry.
  35. BOOL bEnable;
  36. BOOL bSwapSync;
  37. BOOL bPalFormats;
  38. BOOL bIoPriority;
  39. BOOL bUseGenSten;
  40. #ifdef SUPPORT_MCDBG_FLAGS
  41. long lDebug;
  42. #endif
  43. HKEY hkDci; // Handle to DCI key in registry.
  44. long lTimeout;
  45. } MCDREGISTRY;
  46. MCDREGISTRY McdRegistry;
  47. //
  48. // Functions to get registry settings, setup dialog based on settings, and
  49. // save registry settings.
  50. //
  51. extern "C" {
  52. void McdInitRegistry(MCDREGISTRY *pMcdReg);
  53. BOOL McdOpenRegistry(MCDREGISTRY *pMcdReg);
  54. void McdUpdateDialogSettings(MCDREGISTRY *pMcdReg, HWND hDlg);
  55. void McdCloseRegistry(MCDREGISTRY *pMcdReg);
  56. void McdUpdateRegistry(MCDREGISTRY *pMcdReg);
  57. void McdSetRegValue(HKEY hkey, LPSTR lpstrValueName, long lData);
  58. long McdGetRegValue(HKEY hkey, LPSTR lpstrValueName, long lDefaultData);
  59. BOOL McdDetection(void);
  60. };
  61. //
  62. // Function prototype
  63. //
  64. BOOL CALLBACK McdDlgProc(HWND hDlg, UINT uMessage, WPARAM wParam,
  65. LPARAM lParam);
  66. //
  67. // Handle to the DLL
  68. //
  69. extern HINSTANCE g_hInst;
  70. //
  71. // Track state of OLE CoInitialize()
  72. //
  73. BOOL gfCoInitDone = FALSE;
  74. #if DBG
  75. ULONG
  76. DbgPrint(
  77. PCH DebugMessage,
  78. ...
  79. )
  80. {
  81. va_list ap;
  82. char buffer[256];
  83. va_start(ap, DebugMessage);
  84. vsprintf(buffer, DebugMessage, ap);
  85. OutputDebugStringA(buffer);
  86. va_end(ap);
  87. return(0);
  88. }
  89. VOID NTAPI
  90. DbgBreakPoint(VOID)
  91. {
  92. DebugBreak();
  93. }
  94. #endif
  95. ///////////////////////////// BEGIN CUT-AND-PASTE /////////////////////////////
  96. // //
  97. // This section of code is cut-and-paste from the Plus! Pack prop sheet //
  98. // code. The coding style is entirely the responsibility of someone //
  99. // over in building 27. :-) //
  100. // //
  101. // -- Gilman //
  102. // //
  103. //---------------------------------------------------------------------------
  104. // Class Member functions
  105. //---------------------------------------------------------------------------
  106. //---------------------------------------------------------------------------
  107. // Constructor
  108. //---------------------------------------------------------------------------
  109. CPropSheetExt::CPropSheetExt( LPUNKNOWN pUnkOuter, LPFNDESTROYED pfnDestroy )
  110. {
  111. m_cRef = 0;
  112. m_pUnkOuter = pUnkOuter;
  113. m_pfnDestroy = pfnDestroy;
  114. return;
  115. }
  116. //---------------------------------------------------------------------------
  117. // Destructor
  118. //---------------------------------------------------------------------------
  119. CPropSheetExt::~CPropSheetExt( void )
  120. {
  121. return;
  122. }
  123. //---------------------------------------------------------------------------
  124. // QueryInterface()
  125. //---------------------------------------------------------------------------
  126. STDMETHODIMP CPropSheetExt::QueryInterface( REFIID riid, LPVOID* ppv )
  127. {
  128. *ppv = NULL;
  129. if( IsEqualIID( riid, IID_IShellPropSheetExt ) )
  130. {
  131. *ppv = (LPVOID)this;
  132. ++m_cRef;
  133. return NOERROR;
  134. }
  135. return ResultFromScode(E_NOINTERFACE);
  136. }
  137. //---------------------------------------------------------------------------
  138. // AddRef()
  139. //---------------------------------------------------------------------------
  140. STDMETHODIMP_(ULONG) CPropSheetExt::AddRef( void )
  141. {
  142. return ++m_cRef;
  143. }
  144. //---------------------------------------------------------------------------
  145. // Release()
  146. //---------------------------------------------------------------------------
  147. STDMETHODIMP_(ULONG) CPropSheetExt::Release( void )
  148. {
  149. ULONG cRefT;
  150. cRefT = --m_cRef;
  151. if( m_cRef == 0 )
  152. {
  153. // Tell the housing that an object is going away so that it
  154. // can shut down if appropriate.
  155. if( NULL != m_pfnDestroy )
  156. (*m_pfnDestroy)();
  157. delete this;
  158. }
  159. return cRefT;
  160. }
  161. //---------------------------------------------------------------------------
  162. // AddPages()
  163. //---------------------------------------------------------------------------
  164. STDMETHODIMP CPropSheetExt::AddPages( LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam )
  165. {
  166. PROPSHEETPAGE psp;
  167. HPROPSHEETPAGE hpage;
  168. // Fail the call if not an MCD-enabled display
  169. // driver.
  170. if (!McdDetection())
  171. return ( E_FAIL );
  172. psp.dwSize = sizeof(PROPSHEETPAGE);
  173. // psp.dwFlags = PSP_USETITLE | PSP_HASHELP;
  174. psp.dwFlags = PSP_USETITLE;
  175. psp.hIcon = NULL;
  176. psp.hInstance = g_hInst;
  177. psp.pszTemplate = MAKEINTRESOURCE( MCD_DLG );
  178. psp.pfnDlgProc = (DLGPROC)McdDlgProc;
  179. psp.pszTitle = "3D";
  180. psp.lParam = 0;
  181. if( ( hpage = CreatePropertySheetPage( &psp ) ) == NULL )
  182. {
  183. return ( E_OUTOFMEMORY );
  184. }
  185. if( !lpfnAddPage( hpage, lParam ) )
  186. {
  187. DestroyPropertySheetPage( hpage );
  188. return ( E_FAIL );
  189. }
  190. return NOERROR;
  191. }
  192. //---------------------------------------------------------------------------
  193. // ReplacePage()
  194. //---------------------------------------------------------------------------
  195. STDMETHODIMP CPropSheetExt::ReplacePage( UINT uPageID, LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam )
  196. {
  197. return NOERROR;
  198. }
  199. // //
  200. // Guess its time to go back to my code. //
  201. // //
  202. // -- Gilman //
  203. // //
  204. ////////////////////////////// END CUT-AND-PASTE //////////////////////////////
  205. /******************************Public*Routine******************************\
  206. * McdDlgProc
  207. *
  208. * The dialog procedure for the "OpenGL MCD" property sheet page.
  209. *
  210. * History:
  211. * 05-Apr-1996 -by- Gilman Wong [gilmanw]
  212. * Wrote it.
  213. \**************************************************************************/
  214. BOOL CALLBACK
  215. McdDlgProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam)
  216. {
  217. LPPROPSHEETPAGE psp = (LPPROPSHEETPAGE) GetWindowLong(hDlg, DWL_USER);
  218. static char szHelpFile[32];
  219. switch( uMessage )
  220. {
  221. case WM_INITDIALOG:
  222. //!!! This is left over from the Plus!Pack propsheet. Is it needed?
  223. SetWindowLong( hDlg, DWL_USER, lParam );
  224. psp = (LPPROPSHEETPAGE)lParam;
  225. //
  226. // Get the name of the help file.
  227. //
  228. LoadString( g_hInst, IDS_HELPFILE, szHelpFile, 32 );
  229. //
  230. // Get the values for the settings from the registry and
  231. // set the checkboxes.
  232. //
  233. McdInitRegistry(&McdRegistry);
  234. McdOpenRegistry(&McdRegistry);
  235. McdUpdateDialogSettings(&McdRegistry, hDlg);
  236. break;
  237. case WM_DESTROY:
  238. if ( gfCoInitDone )
  239. CoUninitialize();
  240. McdCloseRegistry(&McdRegistry);
  241. break;
  242. case WM_COMMAND:
  243. switch( LOWORD(wParam) )
  244. {
  245. case IDC_MCD_ENABLE:
  246. McdRegistry.bEnable = IsDlgButtonChecked(hDlg, IDC_MCD_ENABLE);
  247. break;
  248. case IDC_MCD_SYNCSWAP:
  249. McdRegistry.bSwapSync = IsDlgButtonChecked(hDlg, IDC_MCD_SYNCSWAP);
  250. break;
  251. case IDC_MCD_PALFMTS:
  252. McdRegistry.bPalFormats = IsDlgButtonChecked(hDlg, IDC_MCD_PALFMTS);
  253. break;
  254. case IDC_MCD_IOPRIORITY:
  255. McdRegistry.bIoPriority = IsDlgButtonChecked(hDlg, IDC_MCD_IOPRIORITY);
  256. break;
  257. case IDC_MCD_STENCIL:
  258. McdRegistry.bUseGenSten = IsDlgButtonChecked(hDlg, IDC_MCD_STENCIL);
  259. break;
  260. case IDC_DCI_TIMEOUT:
  261. if (IsDlgButtonChecked(hDlg, IDC_DCI_TIMEOUT))
  262. McdRegistry.lTimeout = 7;
  263. else
  264. McdRegistry.lTimeout = 0;
  265. break;
  266. #ifdef SUPPORT_MCDBG_FLAGS
  267. case IDC_MCDBG_ALLOCBUF:
  268. if (!IsDlgButtonChecked(hDlg, IDC_MCDBG_ALLOCBUF))
  269. McdRegistry.lDebug |= MCDDEBUG_DISABLE_ALLOCBUF;
  270. else
  271. McdRegistry.lDebug &= ~MCDDEBUG_DISABLE_ALLOCBUF;
  272. break;
  273. case IDC_MCDBG_GETBUF:
  274. if (!IsDlgButtonChecked(hDlg, IDC_MCDBG_GETBUF))
  275. McdRegistry.lDebug |= MCDDEBUG_DISABLE_GETBUF;
  276. else
  277. McdRegistry.lDebug &= ~MCDDEBUG_DISABLE_GETBUF;
  278. break;
  279. case IDC_MCDBG_DRAW:
  280. if (!IsDlgButtonChecked(hDlg, IDC_MCDBG_DRAW))
  281. McdRegistry.lDebug |= MCDDEBUG_DISABLE_PROCBATCH;
  282. else
  283. McdRegistry.lDebug &= ~MCDDEBUG_DISABLE_PROCBATCH;
  284. break;
  285. case IDC_MCDBG_CLEAR:
  286. if (!IsDlgButtonChecked(hDlg, IDC_MCDBG_CLEAR))
  287. McdRegistry.lDebug |= MCDDEBUG_DISABLE_CLEAR;
  288. else
  289. McdRegistry.lDebug &= ~MCDDEBUG_DISABLE_CLEAR;
  290. break;
  291. #endif
  292. default:
  293. return FALSE;
  294. }
  295. //
  296. // If the user changed a setting, tell the property manager we
  297. // have outstanding changes. This will enable the "Apply Now" button...
  298. //
  299. SendMessage(GetParent(hDlg), PSM_CHANGED, (WPARAM) hDlg, 0L);
  300. break;
  301. case WM_NOTIFY:
  302. switch( ((NMHDR *)lParam)->code )
  303. {
  304. case PSN_APPLY: // OK or Apply clicked
  305. McdUpdateRegistry(&McdRegistry);
  306. break;
  307. case PSN_QUERYCANCEL: // Cancel clicked
  308. break;
  309. default:
  310. break;
  311. }
  312. break;
  313. #if 0
  314. case WM_HELP:
  315. {
  316. LPHELPINFO lphi = (LPHELPINFO)lParam;
  317. if( lphi->iContextType == HELPINFO_WINDOW )
  318. {
  319. WinHelp( (HWND)lphi->hItemHandle, (LPSTR)szHelpFile, HELP_WM_HELP,(DWORD)((POPUP_HELP_ARRAY FAR *)phaMainWin) );
  320. }
  321. }
  322. break;
  323. #endif
  324. //!!! This is also left over from Plus!Pack propsheet. Is it needed?
  325. case WM_CONTEXTMENU:
  326. // first check for dlg window
  327. if( (HWND)wParam == hDlg )
  328. {
  329. // let the def dlg proc decide whether to respond or ignore;
  330. // necessary for title bar sys menu on right click
  331. return FALSE;
  332. }
  333. #if 0
  334. else
  335. {
  336. // else go for the controls
  337. WinHelp( (HWND)wParam, (LPSTR)szHelpFile, HELP_CONTEXTMENU,(DWORD)((POPUP_HELP_ARRAY FAR *)phaMainWin) );
  338. }
  339. #endif
  340. break;
  341. default:
  342. return FALSE;
  343. }
  344. return TRUE;
  345. }
  346. /******************************Public*Routine******************************\
  347. * McdInitResistry
  348. *
  349. * Initializes the MCDREGISTRY structure.
  350. *
  351. * History:
  352. * 05-Apr-1996 -by- Gilman Wong [gilmanw]
  353. * Wrote it.
  354. \**************************************************************************/
  355. void McdInitRegistry(MCDREGISTRY *pMcdReg)
  356. {
  357. //
  358. // The registry keys must be set to zero. The data is valid
  359. // only if the corresponding keys are valid.
  360. //
  361. memset(pMcdReg, 0, sizeof(*pMcdReg));
  362. }
  363. /******************************Public*Routine******************************\
  364. * McdOpenRegistry
  365. *
  366. * Opens the MCD registry and initializes the settings to the values found
  367. * in the registry.
  368. *
  369. * Note:
  370. * The function will leave the registry keys open, so the caller should
  371. * make sure to call McdCloseRegistry when done.
  372. *
  373. * History:
  374. * 05-Apr-1996 -by- Gilman Wong [gilmanw]
  375. * Wrote it.
  376. \**************************************************************************/
  377. BOOL McdOpenRegistry(MCDREGISTRY *pMcdReg)
  378. {
  379. //
  380. // Open the MCD key and get the data.
  381. //
  382. if ( RegOpenKeyExA(HKEY_LOCAL_MACHINE,
  383. STR_MCDKEY,
  384. 0,
  385. KEY_QUERY_VALUE | KEY_SET_VALUE,
  386. &pMcdReg->hkMcd) == ERROR_SUCCESS )
  387. {
  388. pMcdReg->bEnable =
  389. McdGetRegValue(pMcdReg->hkMcd, STR_ENABLE, 0) != 0;
  390. pMcdReg->bSwapSync =
  391. McdGetRegValue(pMcdReg->hkMcd, STR_SWAPSYNC, 0) != 0;
  392. pMcdReg->bPalFormats =
  393. McdGetRegValue(pMcdReg->hkMcd, STR_8BPP, 0) != 0;
  394. pMcdReg->bIoPriority =
  395. McdGetRegValue(pMcdReg->hkMcd, STR_IOPRIORITY, 0) != 0;
  396. pMcdReg->bUseGenSten =
  397. McdGetRegValue(pMcdReg->hkMcd, STR_STENCIL, 0) != 0;
  398. #ifdef SUPPORT_MCDBG_FLAGS
  399. pMcdReg->lDebug = McdGetRegValue(pMcdReg->hkMcd, STR_DEBUG, 0);
  400. #endif
  401. }
  402. else
  403. {
  404. pMcdReg->hkMcd = (HKEY) NULL;
  405. }
  406. //
  407. // Open the DCI key and get the data.
  408. //
  409. if ( RegOpenKeyExA(HKEY_LOCAL_MACHINE,
  410. STR_DCIKEY,
  411. 0,
  412. KEY_QUERY_VALUE | KEY_SET_VALUE,
  413. &pMcdReg->hkDci) == ERROR_SUCCESS )
  414. {
  415. pMcdReg->lTimeout = McdGetRegValue(pMcdReg->hkDci, STR_TIMEOUT, 0);
  416. }
  417. else
  418. {
  419. pMcdReg->hkDci = (HKEY) NULL;
  420. }
  421. return TRUE;
  422. }
  423. /******************************Public*Routine******************************\
  424. * McdUpdateDialogSettings
  425. *
  426. * Sets the controls in the dialog to match the MCD registry settings.
  427. *
  428. * History:
  429. * 05-Apr-1996 -by- Gilman Wong [gilmanw]
  430. * Wrote it.
  431. \**************************************************************************/
  432. void McdUpdateDialogSettings(MCDREGISTRY *pMcdReg, HWND hDlg)
  433. {
  434. //
  435. // If the mcd key is valid, the data is valid. Use the
  436. // data to set the MCD controls in the dialog.
  437. //
  438. if (pMcdReg->hkMcd)
  439. {
  440. CheckDlgButton(hDlg, IDC_MCD_ENABLE, pMcdReg->bEnable);
  441. CheckDlgButton(hDlg, IDC_MCD_SYNCSWAP, pMcdReg->bSwapSync);
  442. CheckDlgButton(hDlg, IDC_MCD_PALFMTS, pMcdReg->bPalFormats);
  443. CheckDlgButton(hDlg, IDC_MCD_IOPRIORITY, pMcdReg->bIoPriority);
  444. CheckDlgButton(hDlg, IDC_MCD_STENCIL, pMcdReg->bUseGenSten);
  445. #ifdef SUPPORT_MCDBG_FLAGS
  446. CheckDlgButton(hDlg, IDC_MCDBG_ALLOCBUF, !(pMcdReg->lDebug & MCDDEBUG_DISABLE_ALLOCBUF ));
  447. CheckDlgButton(hDlg, IDC_MCDBG_GETBUF, !(pMcdReg->lDebug & MCDDEBUG_DISABLE_GETBUF ));
  448. CheckDlgButton(hDlg, IDC_MCDBG_DRAW, !(pMcdReg->lDebug & MCDDEBUG_DISABLE_PROCBATCH));
  449. CheckDlgButton(hDlg, IDC_MCDBG_CLEAR, !(pMcdReg->lDebug & MCDDEBUG_DISABLE_CLEAR ));
  450. #endif
  451. }
  452. //
  453. // If the dci key is valid, the data is valid. Use the
  454. // data to set the DCI controls in the dialog.
  455. //
  456. if (pMcdReg->hkDci)
  457. {
  458. CheckDlgButton(hDlg, IDC_DCI_TIMEOUT, pMcdReg->lTimeout != 0);
  459. }
  460. }
  461. /******************************Public*Routine******************************\
  462. * McdCloseRegistry
  463. *
  464. * Close any resources used in the MCDREGISTRY (i.e., close the open registry
  465. * keys).
  466. *
  467. * History:
  468. * 05-Apr-1996 -by- Gilman Wong [gilmanw]
  469. * Wrote it.
  470. \**************************************************************************/
  471. void McdCloseRegistry(MCDREGISTRY *pMcdReg)
  472. {
  473. //
  474. // Close open registry keys.
  475. //
  476. if (pMcdReg->hkMcd)
  477. {
  478. RegCloseKey(pMcdReg->hkMcd);
  479. pMcdReg->hkMcd = (HKEY) NULL;
  480. }
  481. if (pMcdReg->hkDci)
  482. {
  483. RegCloseKey(pMcdReg->hkDci);
  484. pMcdReg->hkDci = (HKEY) NULL;
  485. }
  486. }
  487. /******************************Public*Routine******************************\
  488. * McdUpdateRegistry
  489. *
  490. * Save the current values in MCDREGISTRY to the system
  491. * Effects:
  492. *
  493. * Warnings:
  494. *
  495. * History:
  496. * 05-Apr-1996 -by- Gilman Wong [gilmanw]
  497. * Wrote it.
  498. \**************************************************************************/
  499. void McdUpdateRegistry(MCDREGISTRY *pMcdReg)
  500. {
  501. //
  502. // If the mcd key is open, save the MCD data to the registry.
  503. //
  504. if (pMcdReg->hkMcd)
  505. {
  506. McdSetRegValue(pMcdReg->hkMcd, STR_ENABLE,
  507. (long) pMcdReg->bEnable);
  508. McdSetRegValue(pMcdReg->hkMcd, STR_SWAPSYNC,
  509. (long) pMcdReg->bSwapSync);
  510. McdSetRegValue(pMcdReg->hkMcd, STR_8BPP,
  511. (long) pMcdReg->bPalFormats);
  512. McdSetRegValue(pMcdReg->hkMcd, STR_IOPRIORITY,
  513. (long) pMcdReg->bIoPriority);
  514. McdSetRegValue(pMcdReg->hkMcd, STR_STENCIL,
  515. (long) pMcdReg->bUseGenSten);
  516. #ifdef SUPPORT_MCDBG_FLAGS
  517. McdSetRegValue(pMcdReg->hkMcd, STR_DEBUG,
  518. pMcdReg->lDebug);
  519. #endif
  520. }
  521. //
  522. // If the dci key is open, save the DCI data to the registry.
  523. //
  524. if (pMcdReg->hkDci)
  525. {
  526. McdSetRegValue(pMcdReg->hkDci, STR_TIMEOUT,
  527. pMcdReg->lTimeout);
  528. }
  529. }
  530. /******************************Public*Routine******************************\
  531. * McdGetRegValue
  532. *
  533. * Get the data value for the specified value name out of the specified
  534. * registry key.
  535. *
  536. * History:
  537. * 05-Apr-1996 -by- Gilman Wong [gilmanw]
  538. * Wrote it.
  539. \**************************************************************************/
  540. long McdGetRegValue(HKEY hkey, LPSTR lpstrValueName, long lDefaultData)
  541. {
  542. DWORD dwDataType;
  543. DWORD cjSize;
  544. long lData;
  545. //
  546. // For specified value, attempt to fetch the data.
  547. //
  548. cjSize = sizeof(long);
  549. if ( (RegQueryValueExA(hkey,
  550. lpstrValueName,
  551. (LPDWORD) NULL,
  552. &dwDataType,
  553. (LPBYTE) &lData,
  554. &cjSize) != ERROR_SUCCESS)
  555. || (dwDataType != REG_DWORD) )
  556. {
  557. lData = lDefaultData;
  558. }
  559. return lData;
  560. }
  561. /******************************Public*Routine******************************\
  562. * McdSetRegValue
  563. *
  564. * Set the specified value name of the registry key with the specified data.
  565. *
  566. * History:
  567. * 05-Apr-1996 -by- Gilman Wong [gilmanw]
  568. * Wrote it.
  569. \**************************************************************************/
  570. void McdSetRegValue(HKEY hkey, LPSTR lpstrValueName, long lData)
  571. {
  572. //
  573. // Set the specified value.
  574. //
  575. RegSetValueExA(hkey, lpstrValueName, 0, REG_DWORD, (BYTE *) &lData,
  576. sizeof(lData));
  577. }
  578. /******************************Public*Routine******************************\
  579. * McdDetection
  580. *
  581. * Detect MCD support in the driver by calling the MCDGetDriverInfo function.
  582. *
  583. * History:
  584. * 05-Apr-1996 -by- Gilman Wong [gilmanw]
  585. * Wrote it.
  586. \**************************************************************************/
  587. typedef struct _MCDRIVERINFO {
  588. ULONG verMajor;
  589. ULONG verMinor;
  590. ULONG verDriver;
  591. CHAR idStr[200];
  592. ULONG drvMemFlags;
  593. ULONG drvBatchMemSizeMax;
  594. } MCDDRIVERINFO;
  595. typedef BOOL (APIENTRY *MCDGETDRIVERINFOFUNC)(HDC hdc, MCDDRIVERINFO *pMCDDriverInfo);
  596. BOOL McdDetection(void)
  597. {
  598. static BOOL bFirstTime = TRUE;
  599. static BOOL bRet = FALSE;
  600. //ATTENTION -- Need a good way to detect MCD support independent of the
  601. //ATTENTION setting of the MCD Enable flag. MCDGetDriverInfo fails
  602. //ATTENTION if MCD is disabled (whether or not the driver has MCD
  603. //ATTENTION support).
  604. return TRUE;
  605. if (bFirstTime)
  606. {
  607. HMODULE hmodMcd;
  608. //
  609. // Only do this once.
  610. //
  611. bFirstTime = FALSE;
  612. //
  613. // Load the MCD32.DLL library.
  614. //
  615. hmodMcd = LoadLibraryA("mcd32.dll");
  616. if (hmodMcd)
  617. {
  618. MCDGETDRIVERINFOFUNC pMCDGetDriverInfo;
  619. //
  620. // Get the MCDGetDriverInfo entry point and call it.
  621. //
  622. pMCDGetDriverInfo = (MCDGETDRIVERINFOFUNC)
  623. GetProcAddress(hmodMcd, "MCDGetDriverInfo");
  624. if (pMCDGetDriverInfo)
  625. {
  626. HDC hdc;
  627. //
  628. // An hdc is required for the function call.
  629. //
  630. hdc = CreateDCA("display", NULL, NULL, NULL);
  631. if (hdc)
  632. {
  633. MCDDRIVERINFO McdInfo;
  634. //
  635. // Gee, the display driver really does support MCD.
  636. //
  637. bRet = (*pMCDGetDriverInfo)(hdc, &McdInfo);
  638. DeleteDC(hdc);
  639. }
  640. }
  641. FreeLibrary(hmodMcd);
  642. }
  643. }
  644. return bRet;
  645. }