home *** CD-ROM | disk | FTP | other *** search
/ Microsoft DirectX SDK 7.0 / Dx7.bin / DXF / samples / multimedia / ddraw / src / modetest / modetest.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-08-12  |  27.1 KB  |  767 lines

  1. //-----------------------------------------------------------------------------
  2. // File: ModeTest.cpp
  3. //
  4. // Desc: This example demonstrates basic usage of the IDirectDraw7::StartModeTest
  5. //   and IDirectDraw7::EvaluateMode methods. Together, these methods allow an
  6. //   application to explore what display modes and refresh rates the monitor
  7. //   connected to this display device is able to display, through a manual
  8. //   user-controlled process. The application will present the UI that asks
  9. //   the user if the current mode under test is being displayed correctly by
  10. //   the monitor.
  11. //
  12. //   Applications should use these methods when they are interested in using
  13. //   higher refresh rates.
  14. //
  15. //   The basic idea is that DirectDraw will setup a list of modes to be tested
  16. //   (based on the list the app passed in), and then sequentially test them
  17. //   under application control. The app starts the test process, and then
  18. //   calls IDirectDraw7::EvaluateMode continuously. DirectDraw will take care
  19. //   of setting the modes. All the app has to do is SetCooperativeLevel
  20. //   beforehand, and then handle surface loss and drawing the UI that asks the
  21. //   user if they can see the current mode under test. DirectDraw returns
  22. //   enough information from IDirectDraw7::EvaluateMode to allow the app to
  23. //   know when to do these things, and when to stop testing. The app can pass
  24. //   a flag to IDirectDraw7::EvaluateMode if the user happened to say they
  25. //   could see the mode corretly, which will cause DirectDraw to mark the mode
  26. //   as good and move on. DirectDraw may also decide that time as run out and
  27. //   give up on a certain mode.
  28. //
  29. //   DirectDraw uses information at its disposal from any automated means to
  30. //   make the testing process as short as possible, and applications only need
  31. //   to test modes they are interested in.
  32. //
  33. // Copyright (c) 1999 Microsoft Corp. All rights reserved.
  34. //-----------------------------------------------------------------------------
  35. #define STRICT
  36. #include <windows.h>
  37. #include <stdio.h>
  38. #include <commdlg.h>
  39. #include <initguid.h>
  40. #include <ddraw.h>
  41. #include "resource.h"
  42.  
  43.  
  44.  
  45.  
  46. //-----------------------------------------------------------------------------
  47. // Function-prototypes
  48. //-----------------------------------------------------------------------------
  49. BOOL CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  50. HRESULT GetDirectDrawDevices();
  51. VOID    OnInitDialog();
  52.  
  53. HRESULT ResetDeviceModes( DWORD dwDeviceIndex );
  54. HRESULT UpdateModesListBox( DWORD dwDeviceIndex );
  55.  
  56. BOOL    WINAPI DDEnumCallbackEx( GUID*, LPSTR, LPSTR, LPVOID, HMONITOR );
  57. HRESULT WINAPI EnumModesCallback( LPDDSURFACEDESC pddsd,  LPVOID pContext );
  58. HRESULT WINAPI EnumAllModesCallback( LPDDSURFACEDESC2 pddsd, LPVOID pContext );
  59.  
  60. HRESULT OnModeTest();
  61. HRESULT PerformDirectDrawModeTest( LPDIRECTDRAW7 pDD, SIZE* aTestModes, 
  62.                                    DWORD dwTestModes );
  63.  
  64.  
  65.  
  66.  
  67. //-----------------------------------------------------------------------------
  68. // Defines, constants, and global variables
  69. //-----------------------------------------------------------------------------
  70. #define SAFE_DELETE(p)  { if(p) { delete (p);     (p)=NULL; } }
  71. #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
  72.  
  73. struct DDRAW_DEVICE_STRUCT
  74. {
  75.     GUID  guid;
  76.     CHAR  strDescription[256];
  77.     CHAR  strDriverName[64];
  78.     DWORD dwModeCount;
  79.     SIZE  aModeSize[256];
  80. };
  81.  
  82. HWND                g_hDlg  = NULL;
  83. LPDIRECTDRAW        g_pDD   = NULL;
  84.  
  85. DDRAW_DEVICE_STRUCT g_aDevices[16];
  86. DWORD               g_dwDeviceCount;
  87.  
  88.  
  89.  
  90.  
  91. //-----------------------------------------------------------------------------
  92. // Name: WinMain()
  93. // Desc: Entry point for the application.  Since we use a simple dialog for 
  94. //       user interaction we don't need to pump messages.
  95. //-----------------------------------------------------------------------------
  96. INT APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, 
  97.                       INT nCmdShow )
  98. {
  99.     if( FAILED( GetDirectDrawDevices() ) )
  100.         return FALSE;
  101.  
  102.     // Display the main dialog box.
  103.     DialogBox( hInst, MAKEINTRESOURCE(IDD_MAIN), NULL, MainDlgProc );
  104.  
  105.     return TRUE;
  106. }
  107.  
  108.  
  109.  
  110.  
  111. //-----------------------------------------------------------------------------
  112. // Name: MainDlgProc()
  113. // Desc: Handles dialog messages
  114. //-----------------------------------------------------------------------------
  115. BOOL CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  116. {
  117.     switch( msg ) 
  118.     {
  119.         case WM_INITDIALOG:
  120.             // Store HWND in global
  121.             g_hDlg = hDlg;
  122.  
  123.             OnInitDialog();
  124.             break;
  125.  
  126.         case WM_COMMAND:
  127.             switch( LOWORD(wParam) )
  128.             {
  129.                 case IDCANCEL:
  130.                     EndDialog( hDlg, IDCANCEL );
  131.                     break;
  132.  
  133.                 case IDC_TEST:
  134.                     if( FAILED( OnModeTest() ) )
  135.                     {
  136.                         MessageBox( g_hDlg, "Error doing starting mode test. "
  137.                                     "Sample will now exit.", "DirectDraw Sample", 
  138.                                     MB_OK | MB_ICONERROR );
  139.                         EndDialog( g_hDlg, IDABORT );
  140.                     }
  141.                     break;
  142.  
  143.                 case IDC_RESET:
  144.                     HWND hWndDeviceList;
  145.                     DWORD dwDeviceIndex;
  146.  
  147.                     // Get the currently selected DirectDraw device
  148.                     hWndDeviceList = GetDlgItem( hDlg, IDC_DDRAW_DEVICE_LIST );
  149.                     dwDeviceIndex = SendMessage( hWndDeviceList, LB_GETCURSEL, 0, 0 );
  150.  
  151.                     // Reset the modes for it
  152.                     if( FAILED( ResetDeviceModes( dwDeviceIndex ) ) )
  153.                     {
  154.                         MessageBox( g_hDlg, "Error reset DirectDraw device. "
  155.                                     "Sample will now exit.", "DirectDraw Sample", 
  156.                                     MB_OK | MB_ICONERROR );
  157.                         EndDialog( g_hDlg, IDABORT );
  158.                     }
  159.                     break;
  160.  
  161.                 case IDC_DDRAW_DEVICE_LIST:
  162.                     switch( HIWORD(wParam) )
  163.                     {
  164.                         case LBN_SELCHANGE:
  165.                             // Get the currently selected DirectDraw device
  166.                             DWORD dwDeviceIndex;
  167.                             dwDeviceIndex = SendMessage( (HWND) lParam, 
  168.                                                          LB_GETCURSEL, 0, 0 );
  169.  
  170.                             // Update the list boxes using it 
  171.                             if( FAILED( UpdateModesListBox( dwDeviceIndex ) ) )
  172.                             {
  173.                                 MessageBox( g_hDlg, "Error enumerating DirectDraw modes."
  174.                                             "Sample will now exit.", "DirectDraw Sample", 
  175.                                             MB_OK | MB_ICONERROR );
  176.                                 EndDialog( g_hDlg, IDABORT );
  177.                             }
  178.  
  179.                             break;
  180.  
  181.                         default: 
  182.                             return FALSE;
  183.                     }
  184.                     break;
  185.  
  186.                 default:
  187.                     return FALSE; // Didn't handle message
  188.             }
  189.             break;
  190.  
  191.         default:
  192.             return FALSE; // Didn't handle message
  193.     }
  194.  
  195.     return TRUE; // Handled message
  196. }
  197.  
  198.  
  199.  
  200.  
  201. //-----------------------------------------------------------------------------
  202. // Name: GetDirectDrawDevices()
  203. // Desc: Retrieves all available DirectDraw devices and stores the information
  204. //       in g_aDevices[]
  205. //-----------------------------------------------------------------------------
  206. HRESULT GetDirectDrawDevices()
  207. {
  208.     return DirectDrawEnumerateEx( DDEnumCallbackEx, 
  209.                                   NULL,
  210.                                   DDENUM_ATTACHEDSECONDARYDEVICES |
  211.                                   DDENUM_DETACHEDSECONDARYDEVICES |
  212.                                   DDENUM_NONDISPLAYDEVICES );
  213. }
  214.  
  215.  
  216.  
  217.  
  218. //-----------------------------------------------------------------------------
  219. // Name: DDEnumCallbackEx()
  220. // Desc: Enumerates all available DirectDraw devices
  221. //-----------------------------------------------------------------------------
  222. BOOL WINAPI DDEnumCallbackEx( GUID* pGUID,    
  223.                               LPSTR strDriverDescription, 
  224.                               LPSTR strDriverName,        
  225.                               LPVOID pContext,           
  226.                               HMONITOR hm )       
  227. {
  228.     HRESULT hr;
  229.     LPDIRECTDRAW pDD = NULL;
  230.    
  231.     // Create a DirectDraw device using the enumerated guid 
  232.     hr = DirectDrawCreateEx( pGUID, (VOID**)&pDD, IID_IDirectDraw7, NULL );
  233.  
  234.     if( SUCCEEDED(hr) )
  235.     {
  236.         if( pGUID )
  237.         {
  238.             // Add it to the global storage structure
  239.             g_aDevices[ g_dwDeviceCount ].guid = *pGUID;
  240.         }
  241.         else
  242.         {
  243.             // Clear the guid from the global storage structure
  244.             ZeroMemory( &g_aDevices[ g_dwDeviceCount ].guid, 
  245.                         sizeof(GUID) );
  246.         }
  247.  
  248.         // Copy the description of the driver into the structure
  249.         lstrcpyn( g_aDevices[ g_dwDeviceCount ].strDescription, 
  250.                   strDriverDescription, 256 );
  251.         lstrcpyn( g_aDevices[ g_dwDeviceCount ].strDriverName, 
  252.                   strDriverName, 64 );
  253.  
  254.         // Retrive the modes this device can support
  255.         g_aDevices[ g_dwDeviceCount ].dwModeCount = 0;
  256.         hr = pDD->EnumDisplayModes( 0, NULL, NULL, EnumModesCallback );
  257.     
  258.         // Increase the counter for the number of devices found
  259.         g_dwDeviceCount++;
  260.  
  261.         // Release this device 
  262.         SAFE_RELEASE( pDD );
  263.     }
  264.  
  265.     // Continue looking for more devices
  266.     return TRUE;
  267. }
  268.  
  269.  
  270.  
  271.  
  272. //-----------------------------------------------------------------------------
  273. // Name: EnumModesCallback()
  274. // Desc: Enumerates the available modes for the device from which 
  275. //       EnumDisplayModes() was called.  It records the unique mode sizes in 
  276. //       the g_aDevices[g_dwDeviceCount].aModeSize array
  277. //-----------------------------------------------------------------------------
  278. HRESULT WINAPI EnumModesCallback( LPDDSURFACEDESC pddsd,  
  279.                                   LPVOID pContext )
  280. {
  281.     DWORD i;
  282.     DWORD dwModeSizeX;
  283.     DWORD dwModeSizeY;
  284.     DWORD dwModeCount;
  285.  
  286.     // For each mode, look through all previously found modes
  287.     // to see if this mode has already been added to the list
  288.     dwModeCount = g_aDevices[ g_dwDeviceCount ].dwModeCount;
  289.  
  290.     for( i = 0; i < dwModeCount; i ++ )
  291.     {
  292.         dwModeSizeX = g_aDevices[ g_dwDeviceCount ].aModeSize[i].cx;
  293.         dwModeSizeY = g_aDevices[ g_dwDeviceCount ].aModeSize[i].cy;
  294.  
  295.         if ( ( dwModeSizeX == pddsd->dwWidth ) &&
  296.              ( dwModeSizeY == pddsd->dwHeight ) )
  297.         {
  298.             // If this mode has been added, then stop looking
  299.             break;
  300.         }
  301.     }
  302.  
  303.     // If this mode was not in g_aDevices[g_dwDeviceCount].aModeSize[]
  304.     // then added it. 
  305.     if( i == g_aDevices[ g_dwDeviceCount ].dwModeCount )
  306.     {
  307.         g_aDevices[ g_dwDeviceCount ].aModeSize[i].cx = pddsd->dwWidth;
  308.         g_aDevices[ g_dwDeviceCount ].aModeSize[i].cy = pddsd->dwHeight;
  309.  
  310.         // Increase the number of modes found for this device
  311.         g_aDevices[ g_dwDeviceCount ].dwModeCount++;
  312.     }
  313.  
  314.     return TRUE;
  315. }
  316.  
  317.  
  318.  
  319.  
  320. //-----------------------------------------------------------------------------
  321. // Name: OnInitDialog()
  322. // Desc: Initializes the dialogs (sets up UI controls, etc.)
  323. //-----------------------------------------------------------------------------
  324. VOID OnInitDialog()
  325. {
  326.     // Load the icon
  327.     HINSTANCE hInst = (HINSTANCE) GetWindowLong( g_hDlg, GWL_HINSTANCE );
  328.     HICON hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_ICON1 ) );
  329.  
  330.     // Set the icon for this dialog.
  331.     PostMessage( g_hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  332.     PostMessage( g_hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  333.  
  334.     // Show all available DirectDraw devices in the listbox
  335.     HWND hWndDeviceList = GetDlgItem( g_hDlg, IDC_DDRAW_DEVICE_LIST );
  336.     for( UINT i = 0; i < g_dwDeviceCount; i++ )
  337.     {
  338.         SendMessage( hWndDeviceList, LB_ADDSTRING, 0,
  339.             (LPARAM) g_aDevices[i].strDescription );
  340.         SendMessage( hWndDeviceList, LB_SETITEMDATA, i, (LPARAM) i);
  341.     }
  342.  
  343.     // Select the first device by default
  344.     DWORD dwCurrentSelect = 0;
  345.  
  346.     SendMessage( hWndDeviceList, LB_SETCURSEL, dwCurrentSelect, 0);
  347.     if( FAILED( UpdateModesListBox( dwCurrentSelect ) ) )
  348.     {
  349.         MessageBox( g_hDlg, "Error enumerating DirectDraw modes."
  350.                     "Sample will now exit.", "DirectDraw Sample", 
  351.                     MB_OK | MB_ICONERROR );
  352.         EndDialog( g_hDlg, IDABORT );
  353.     }
  354.  
  355.     SetFocus( hWndDeviceList );
  356. }
  357.  
  358.  
  359.  
  360.  
  361. //-----------------------------------------------------------------------------
  362. // Name: ResetDeviceModes()
  363. // Desc: If the user makes a mistake, and accidently says YES when a mode 
  364. //       cannot be seen, or NO when a mode really can be seen (thus ending up 
  365. //       with a lower refresh rate than possible) this allows the user to reset 
  366. //       the test results and try again.
  367. //-----------------------------------------------------------------------------
  368. HRESULT ResetDeviceModes( DWORD dwDeviceIndex )
  369. {
  370.     LPDIRECTDRAW7 pDD = NULL;
  371.     HRESULT       hr;    
  372.  
  373.     // Create a DirectDraw device based using the selected device guid
  374.     hr = DirectDrawCreateEx( &g_aDevices[dwDeviceIndex].guid, 
  375.                              (VOID**) &pDD, IID_IDirectDraw7, NULL);
  376.  
  377.     if( SUCCEEDED(hr) )
  378.     {
  379.         // Set the cooperative level to normal
  380.         if( SUCCEEDED( hr = pDD->SetCooperativeLevel( g_hDlg, DDSCL_NORMAL ) ) )
  381.         {
  382.             // Clear the previous mode tests
  383.             //
  384.             // We ignore the return code, since we would do nothing different on error returns.
  385.             // Note that most applications would never need to call StartModeTest this way.
  386.             // The reset functionality is intended to be used when a user accidentally accepted
  387.             // a mode that didn't actually display correctly.
  388.             pDD->StartModeTest( NULL, 0, 0 );
  389.         }
  390.  
  391.         // Release this device
  392.         SAFE_RELEASE( pDD ); 
  393.     }
  394.  
  395.     hr = UpdateModesListBox( dwDeviceIndex );
  396.  
  397.     return hr;
  398. }
  399.  
  400.  
  401.  
  402.  
  403. //-----------------------------------------------------------------------------
  404. // Name: UpdateModesListBox()
  405. // Desc: Updates the "modes to test" and "all modes" list boxes
  406. //-----------------------------------------------------------------------------
  407. HRESULT UpdateModesListBox( DWORD dwDeviceIndex )
  408. {
  409.     LPDIRECTDRAW7 pDD = NULL;
  410.     HRESULT       hr;    
  411.  
  412.     HWND hWndModesToTest = GetDlgItem( g_hDlg, IDC_TEST_MODES_LIST );
  413.     SendMessage( hWndModesToTest, LB_RESETCONTENT, 0, 0 );
  414.  
  415.     // Update the "modes to test" list box based on the display device selected
  416.     for( DWORD i = 0; i < g_aDevices[dwDeviceIndex].dwModeCount; i++ )
  417.     {
  418.         CHAR strMode[64];
  419.  
  420.         // Make a string based on the this mode's size
  421.         sprintf( strMode, TEXT("%u x %u"),
  422.                  g_aDevices[dwDeviceIndex].aModeSize[i].cx, 
  423.                  g_aDevices[dwDeviceIndex].aModeSize[i].cy );
  424.  
  425.         // Add it to the list box
  426.         SendMessage( hWndModesToTest, LB_ADDSTRING, 0, (LPARAM) strMode );
  427.         SendMessage( hWndModesToTest, LB_SETITEMDATA, i, (LPARAM) i );
  428.     }
  429.  
  430.     // Create a DirectDraw device based using the selected device guid
  431.     if( SUCCEEDED( hr = DirectDrawCreateEx( &g_aDevices[dwDeviceIndex].guid, 
  432.                                          (VOID**) &pDD, IID_IDirectDraw7, NULL) ) )
  433.     {
  434.         HWND hWndAllModes = GetDlgItem( g_hDlg, IDC_ALL_MODES_LIST );
  435.         SendMessage( hWndAllModes, LB_RESETCONTENT, 0, 0 );
  436.  
  437.         // Enumerate and display all supported modes along
  438.         // with supported bit depth, and refresh rates 
  439.         // in the "All Modes" listbox
  440.         hr = pDD->EnumDisplayModes( DDEDM_REFRESHRATES, NULL,
  441.                                                 (VOID*) hWndAllModes, 
  442.                                                 EnumAllModesCallback );
  443.  
  444.         // Release this device
  445.         SAFE_RELEASE( pDD ); 
  446.     }
  447.  
  448.     return hr;
  449. }
  450.  
  451.  
  452.  
  453.  
  454. //-----------------------------------------------------------------------------
  455. // Name: EnumAllModesCallback()
  456. // Desc: For each mode enumerated, it adds it to the "All Modes" listbox.
  457. //-----------------------------------------------------------------------------
  458. HRESULT WINAPI EnumAllModesCallback( LPDDSURFACEDESC2 pddsd,  
  459.                                      LPVOID pContext )
  460. {
  461.     CHAR strMode[64];
  462.     HWND hWnd = (HWND) pContext;
  463.  
  464.     sprintf( strMode, TEXT("%ux%ux%u - %u Hz"),
  465.              pddsd->dwWidth, 
  466.              pddsd->dwHeight,
  467.              pddsd->ddpfPixelFormat.dwRGBBitCount, 
  468.              pddsd->dwRefreshRate );
  469.  
  470.     SendMessage( hWnd, LB_ADDSTRING, 0, (LPARAM) strMode );
  471.  
  472.     return TRUE;
  473. }
  474.  
  475.  
  476.  
  477.  
  478. //-----------------------------------------------------------------------------
  479. // Name: OnModeTest()
  480. // Desc: User hit the "Test" button
  481. //-----------------------------------------------------------------------------
  482. HRESULT OnModeTest() 
  483. {
  484.     HWND hWndModesToTest = GetDlgItem( g_hDlg, IDC_TEST_MODES_LIST );
  485.     DWORD dwSelectCount = SendMessage( hWndModesToTest, LB_GETSELCOUNT, 0, 0 );
  486.  
  487.     if( dwSelectCount > 0 )
  488.     {
  489.         LPDIRECTDRAW7 pDD = NULL;
  490.         HRESULT       hr;    
  491.         HWND          hWndDeviceList;
  492.         DWORD         dwDeviceIndex;
  493.  
  494.         // Get the currently selected DirectDraw device
  495.         hWndDeviceList = GetDlgItem( g_hDlg, IDC_DDRAW_DEVICE_LIST );
  496.         dwDeviceIndex = SendMessage( hWndDeviceList, LB_GETCURSEL, 0, 0 );
  497.  
  498.         // Create a DirectDraw device based using the selected device guid
  499.         if( FAILED( hr = DirectDrawCreateEx( &g_aDevices[dwDeviceIndex].guid, 
  500.                                             (VOID**) &pDD, IID_IDirectDraw7, NULL) ) )
  501.             return hr;
  502.  
  503.         // This is a good usage of DDSCL_CREATEDEVICEWINDOW: DirectDraw will create a window that covers
  504.         // the monitor, and won't mess around with our dialog box. Any mouse clicks on the cover window
  505.         // will therefore not be received and misinterpreted by the dialog box, since such clicks will
  506.         // be sent to DirectDraw's internal message procedure and therein ignored.
  507.  
  508.         if( FAILED( hr = pDD->SetCooperativeLevel( g_hDlg,
  509.                                                DDSCL_EXCLUSIVE          | 
  510.                                                DDSCL_FULLSCREEN         |
  511.                                                DDSCL_CREATEDEVICEWINDOW | 
  512.                                                DDSCL_SETFOCUSWINDOW ) ) )
  513.         {
  514.             SAFE_RELEASE( pDD ); 
  515.             return hr;
  516.         }
  517.  
  518.  
  519.  
  520.         SIZE aTestModes[256];
  521.         DWORD dwTestModes = 0;
  522.  
  523.         // Find out which modes are selected, then just test those
  524.         for( DWORD i = 0; i < g_aDevices[dwDeviceIndex].dwModeCount; i++ )
  525.         {
  526.             if( SendMessage( hWndModesToTest, LB_GETSEL, i, 0 ) )
  527.             {
  528.                 // Record the selected modes in aTestModes[]
  529.                 aTestModes[dwTestModes] = g_aDevices[dwDeviceIndex].aModeSize[i];
  530.                 dwTestModes++;
  531.             }
  532.         }
  533.  
  534.         // Perform test on each of the selected modes on the selected device
  535.         hr = PerformDirectDrawModeTest( pDD, aTestModes, dwTestModes );
  536.  
  537.         // Release this device
  538.         SAFE_RELEASE( pDD ); 
  539.  
  540.         switch (hr)
  541.         {
  542.         case DDERR_NOMONITORINFORMATION:
  543.             // No EDID data is present for the current monitor.
  544.             MessageBox(g_hDlg,
  545.                 "The current monitor cannot be identified electronically.\n"
  546.                 "High refresh rates are not allowed on such monitors, so the test will not be performed.",
  547.                 "Testing Will Not Proceed", MB_OK | MB_ICONINFORMATION);
  548.             break;
  549.         case DDERR_NODRIVERSUPPORT:
  550.             // The driver cannot support refresh rate testing.
  551.             MessageBox(g_hDlg,
  552.                 "The driver does not support specific refresh rates. Test cannot be performed.",
  553.                 "Testing Cannot Proceed", MB_OK | MB_ICONINFORMATION);
  554.             break;
  555.         default:
  556.             if( SUCCEEDED(hr) )
  557.             {
  558.                 MessageBox( g_hDlg, TEXT("Mode test completed"), TEXT("Result"), MB_OK );
  559.                 break;
  560.             }
  561.             else
  562.             {
  563.                 // A StartModeTest error occurred.
  564.                 MessageBox(g_hDlg,
  565.                 "StartModeTest returned an unexpected value when called with the DDSMT_ISTESTREQUIRED flag.",
  566.                 "StartModeTest Error", MB_OK | MB_ICONEXCLAMATION);
  567.                 return hr;
  568.             }
  569.         }
  570.  
  571.         // Update the mode list boxes based on the device selected
  572.         if( FAILED( hr = UpdateModesListBox( dwDeviceIndex ) ) )
  573.             return hr;
  574.     }
  575.     else
  576.     {
  577.         // There weren't any modes selected to test
  578.         MessageBox( g_hDlg, 
  579.                     TEXT("Select one or more modes to test from the list box"), 
  580.                     TEXT("No modes selected"), MB_OK );
  581.     }
  582.  
  583.     return S_OK;
  584. }
  585.  
  586.  
  587.  
  588.  
  589. //-----------------------------------------------------------------------------
  590. // Name: SetupPrimarySurface()
  591. // Desc: Setups a primary DirectDraw surface
  592. //-----------------------------------------------------------------------------
  593. HRESULT SetupPrimarySurface( LPDIRECTDRAW7 pDD, LPDIRECTDRAWSURFACE7* ppDDS )
  594. {
  595.     DDSURFACEDESC2 ddsd;
  596.  
  597.     ZeroMemory( &ddsd, sizeof(ddsd) );
  598.  
  599.     ddsd.dwSize         = sizeof(ddsd);
  600.     ddsd.dwFlags        = DDSD_CAPS;
  601.     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  602.  
  603.     return pDD->CreateSurface(&ddsd, ppDDS, NULL);
  604. }
  605.  
  606.  
  607.  
  608.  
  609. //-----------------------------------------------------------------------------
  610. // Name: UpdatePrimarySurface()
  611. // Desc: Fills the primary surface with white, and diplays the timeout value
  612. //       on screen
  613. //-----------------------------------------------------------------------------
  614. HRESULT UpdatePrimarySurface( LPDIRECTDRAWSURFACE7 pDDS, DWORD dwTimeout )
  615. {
  616.     DDBLTFX ddbltfx;
  617.     HDC     hDC;
  618.     char    strTimeout[128];
  619.     RECT    rect;
  620.     HRESULT hr;
  621.   
  622.     // Clear the screen:  
  623.     ZeroMemory( &ddbltfx, sizeof(ddbltfx) );
  624.     ddbltfx.dwSize      = sizeof(ddbltfx);
  625.     ddbltfx.dwFillColor = 0xFFFFFFFF;
  626.  
  627.     hr = pDDS->Blt( NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx );
  628.     if( FAILED( hr ) )
  629.         return hr;
  630.  
  631.     // Display the timeout value 
  632.     if( FAILED( hr = pDDS->GetDC( &hDC ) ) )
  633.         return hr;
  634.  
  635.     GetWindowRect( g_hDlg, &rect );
  636.     wsprintf( strTimeout, TEXT("Press space to accept or escape to reject. ")
  637.               TEXT("%2d seconds until timeout"), dwTimeout );
  638.     DrawText( hDC, strTimeout, strlen(strTimeout), &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE );
  639.  
  640.     // Cleanup
  641.     pDDS->ReleaseDC( hDC );
  642.  
  643.     return S_OK;
  644. }
  645.  
  646.  
  647.  
  648.  
  649. //-----------------------------------------------------------------------------
  650. // Name: PerformDirectDrawModeTest()
  651. // Desc: Perform the IDirectDraw7::StartModeTest and IDirectDraw7::EvaluateMode
  652. //       tests
  653. // Returns: S_OK if no modes needed testing, or all modes tested successfully,
  654. //          informative error code otherwise.
  655. //-----------------------------------------------------------------------------
  656. HRESULT PerformDirectDrawModeTest( LPDIRECTDRAW7 pDD, SIZE* aTestModes, 
  657.                                    DWORD dwTestModes )
  658. {
  659.     LPDIRECTDRAWSURFACE7 pDDSPrimary = NULL;
  660.     HRESULT hr;
  661.     MSG     msg;
  662.     DWORD   dwFlags = 0;
  663.     DWORD   dwTimeout;
  664.     BOOL    bMsgReady;
  665.  
  666.     // First call StartModeTest with the DDSMT_ISTESTREQUIRED flag to determine
  667.     // whether the tests can be performed and need to be performed.
  668.     hr = pDD->StartModeTest( aTestModes, dwTestModes, DDSMT_ISTESTREQUIRED);
  669.  
  670.     switch (hr)
  671.     {
  672.     case DDERR_NEWMODE:
  673.         // DDERR_NEWMODE means that there are modes that need testing.
  674.         break;
  675.     case DDERR_TESTFINISHED:
  676.         // DDERR_TESTFINISHED means that all the modes that we wish to test have already been tested correctly
  677.         return S_OK;
  678.     default:
  679.         //Possible return codes here include DDERR_NOMONITORINFORMATION or DDERR_NODRIVERSUPPORT or
  680.         //other fatal error codes (DDERR_INVALIDPARAMS, DDERR_NOEXCLUSIVEMODE, etc.)
  681.         return hr;
  682.     }
  683.  
  684.     hr = pDD->StartModeTest( aTestModes, dwTestModes, 0 );
  685.     if( hr == DDERR_TESTFINISHED )
  686.     {
  687.         // The tests completed early, so return
  688.         return S_OK;
  689.     }
  690.  
  691.     // Create the primary DirectDraw surface
  692.     if( FAILED( SetupPrimarySurface( pDD, &pDDSPrimary ) ) )
  693.         return hr;
  694.  
  695.     // Loop until the mode tests are complete
  696.     while( TRUE )
  697.     {
  698.         bMsgReady = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
  699.  
  700.         if( bMsgReady )
  701.         {
  702.             if (msg.message == WM_KEYDOWN)
  703.             {
  704.                 switch (msg.wParam)
  705.                 {
  706.                 case VK_SPACE:
  707.                     dwFlags = DDEM_MODEPASSED;
  708.                     break;
  709.  
  710.                 case VK_ESCAPE:
  711.                     dwFlags = DDEM_MODEFAILED;
  712.                     break;
  713.                 }
  714.             }
  715.             else
  716.             {
  717.                 TranslateMessage( &msg );
  718.                 DispatchMessage( &msg );
  719.             }
  720.         }
  721.         else
  722.         {
  723.             // This method will only succeed with monitors that contain EDID data. 
  724.             // If the monitor is not EDID compliant, then the method will return 
  725.             // DDERR_TESTFINISHED without testing any modes. If the EDID table does not 
  726.             // contain values higher than 60hz, no modes will tested. Refresh rates 
  727.             // higher than 100 hz will only be tested if the EDID table contains values 
  728.             // higher than 85hz.
  729.             hr = pDD->EvaluateMode(dwFlags, &dwTimeout);
  730.  
  731.             if( hr == DD_OK )
  732.             {
  733.                 if( pDDSPrimary )
  734.                 {
  735.                     // Clear the screen, and display the timeout value
  736.                     UpdatePrimarySurface( pDDSPrimary, dwTimeout );
  737.                 }
  738.             }
  739.             else if( hr == DDERR_NEWMODE )
  740.             {
  741.                 // Cleanup the last DirectDraw surface, and create
  742.                 // a new one for the new mode
  743.                 SAFE_RELEASE( pDDSPrimary );
  744.  
  745.                 if( FAILED( SetupPrimarySurface( pDD, &pDDSPrimary ) ) )
  746.                     return hr;
  747.  
  748.                 dwFlags = 0;
  749.             }
  750.             else if( hr == DDERR_TESTFINISHED )
  751.             {
  752.                 // Test complete, so stop looping
  753.                 break;
  754.             }
  755.  
  756.             Sleep( 100 );
  757.         }
  758.     }
  759.  
  760.     // Cleanup
  761.     SAFE_RELEASE( pDDSPrimary );
  762.  
  763.     return S_OK;
  764. }
  765.  
  766.  
  767.