home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / gdi / setdisp / setdisp.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  38KB  |  1,371 lines

  1. /******************************************************************************\
  2. *       This is a part of the Microsoft Source Code Samples.
  3. *       Copyright (C) 1993-1997 Microsoft Corporation.
  4. *       All rights reserved.
  5. *       This source code is only intended as a supplement to
  6. *       Microsoft Development Tools and/or WinHelp documentation.
  7. *       See these sources for detailed information regarding the
  8. *       Microsoft samples programs.
  9. \******************************************************************************/
  10. /******************************************************************************\
  11. *                                                              
  12. *   Implementation file for SetDisp                           
  13. *                                                              
  14. *   SetDisp creates a tray Notification Icon                  
  15. *   that you can use to dynamically change your srceen         
  16. *   resolution. The core APIs used are:                        
  17. *                                                              
  18. *   Shell_NotifyIcon -- to create and maintain the tray icon   
  19. *   TrackPopupMenu   -- to implement the icon resolution       
  20. *                       context menu                           
  21. *   ChangeDisplaySettings -- to test and set the display       
  22. *                       settings dynamically and to update     
  23. *                       the registry with these setttings      
  24. *   EnumDisplaySettings -- to get the display settings that are
  25. *                       supported by the video driver          
  26. *
  27. *   KNOWN ISSUES:  On Windows 95 one cannot use the EnunDisplaySettings
  28. *   to get the current settings.  This causes the check mark to not
  29. *   be displayed and the current setting to not be bolded.  This 
  30. *   information could be obtained from the registry. Also on Windows 95
  31. *   color depth changes require a reboot.  None of the possible returns
  32. *   from ChangeDisplaySettings are currently handled execpt for 
  33. *   success and a message is displayed indicated the sample does not
  34. *   support a reboot. If your driver has many resolutions, the menu
  35. *   may not fit on some resolutions.  This could be resolved with 
  36. *   the use of sub menus for different settings such as color depth
  37. *   or frequencies.
  38. *                                                                 
  39. \******************************************************************************/
  40.  
  41. #if DBG
  42.  
  43. #define TRC(_x) OutputDebugString(TEXT(_x))
  44.  
  45. #else
  46.  
  47. #define TRC(_x)
  48.  
  49. #endif
  50.  
  51. #include "setdisp.h"
  52. #include <windowsx.h>
  53. #include <winuser.h>
  54. #include "resource.h"
  55.  
  56.  
  57. /**************************************************************\
  58. *                                                              * 
  59. *  Tray Icon Structure taken from Win32\TrayNot sample         *
  60. *                                                              * 
  61. \**************************************************************/
  62.  
  63. struct _DLGITEMS
  64. {
  65.     DWORD dwStart;
  66.     UINT uNotify;
  67.     UINT uDelayID;
  68.     UINT uState1;
  69.     UINT uTip1;
  70.     UINT uState2;
  71.     UINT uTip2;
  72. } g_sDlgItems [] =
  73.  
  74. //
  75. // Data for one tray icon
  76. //
  77.  
  78. {
  79.     {
  80.         0, IDC_NOTIFY1, IDC_DELAY1, IDC_STATE11, IDC_TIP11, IDC_STATE12, IDC_TIP12,
  81.     },
  82. } ;
  83.  
  84.  
  85.  /****************************************************************************
  86.  *                                                                          
  87.  *  FUNCTION   : WinMain (HINSTANCE hInstance,  HINSTANCE hPrevInstance, 
  88.  *                        LPSTR lpCmdLine, int nCmdShow )
  89.  *                                                                          
  90.  *  PURPOSE    : Creates a dialog box which implements the tray icon
  91.  *               and which handles the resolution changes
  92.  *                                                                          
  93.  \****************************************************************************/
  94.  
  95. int WINAPI WinMain (
  96.  
  97.   HINSTANCE hInstance, 
  98.   HINSTANCE hPrevInstance, 
  99.   LPSTR lpCmdLine, 
  100.   int nCmdShow )
  101. {
  102.  
  103.     g_hinst = hInstance;
  104.     
  105.     DialogBox(hInstance, MAKEINTRESOURCE(IDD_SETDISP), NULL, SetDispDlgProc);
  106.     
  107.     if (gpDevModes)
  108.     {
  109.         free(gpDevModes);
  110.     }
  111.  
  112.     return(FALSE);
  113.  
  114. }
  115.  
  116.  /****************************************************************************
  117.  *                                                                          
  118.  *  FUNCTION   : SetDispDlgProc (HWND hDlg, UINT uMsg,
  119.  *                                WPARAM wParam, LPARAM lParam)
  120.  *                                                                          
  121.  *  PURPOSE    : Dialog box callback which manages the tray icon
  122.  *               and which handles the resolution changes
  123.  *                                                                          
  124.  \****************************************************************************/
  125.  
  126. BOOL CALLBACK SetDispDlgProc (
  127.   
  128.    HWND hDlg, 
  129.    UINT uMsg, 
  130.    WPARAM wParam, 
  131.    LPARAM lParam)
  132. {
  133.  
  134.     switch (uMsg)
  135.     {
  136.     
  137.     case WM_INITDIALOG:
  138.     {
  139.     BOOL bRet;
  140.  
  141.     //
  142.     //Get DEVMODES
  143.     //
  144.  
  145.     bRet = GetDevModes (hDlg);
  146.  
  147.         if (bRet == FALSE)
  148.         {
  149.             //
  150.             // Failed to get DEVMODES so end the dialog
  151.             //
  152.         
  153.         EndDialog(hDlg, TRUE);
  154.  
  155.         break;
  156.         }
  157.         
  158.     //
  159.     // Initialize Menu with Resolutions
  160.     //
  161.  
  162.     SetResolutionMenu (hDlg);
  163.         
  164.     //
  165.     // Add Tray Notify Icon
  166.     //
  167.  
  168.     NotifyAdd(hDlg, 0);
  169.         
  170.     //
  171.     // Update Tip to current settings
  172.     //
  173.     {
  174.         
  175.         char szTip[50];
  176.  
  177.         //
  178.         // Set the menu text
  179.         //
  180.  
  181.         if (IsNT())
  182.             {
  183.                 wsprintf(szTip,"%d x %d, %d bit color at %d hz",
  184.                          gpCurrentMode->dmPelsWidth,
  185.                          gpCurrentMode->dmPelsHeight,
  186.                          gpCurrentMode->dmBitsPerPel,
  187.                          gpCurrentMode->dmDisplayFrequency);
  188.             }
  189.             else
  190.             {
  191.                 szTip[0] = '\0';
  192.             }
  193.             
  194.         //
  195.         // For the current mode, set the tool tip
  196.             //
  197.  
  198.         TrayMessage(hDlg, NIM_MODIFY, g_sDlgItems[0].uNotify,
  199.                         LoadImage(g_hinst, MAKEINTRESOURCE(IDI_SETDISP),
  200.                         IMAGE_ICON, 16, 16, 0), szTip);
  201.     }
  202.  
  203.     SetForegroundWindow (hDlg);
  204.  
  205.     break;
  206.     
  207.     }    // WM_INITDIALOG:
  208.  
  209.     case WM_DESTROY:    NotifyDelete(hDlg, 0);
  210.             break;
  211.  
  212.     case WM_COMMAND:
  213.     {
  214.     switch (GET_WM_COMMAND_ID(wParam, lParam))
  215.     {
  216.         case IDCANCEL:   EndDialog(hDlg, TRUE);
  217.                  break;
  218.  
  219.         case IDABORT:    ShowWindow(hDlg, SW_HIDE);
  220.                  break;
  221.         
  222.         case IDM_ABOUT:
  223.           DialogBox(g_hinst, MAKEINTRESOURCE(IDD_ABOUT),
  224.                 hDlg, (DLGPROC)About);
  225.           break;
  226.  
  227.         default:
  228.         
  229.         //
  230.         // handle MYWM_NOTIFYICON + 10 + i for diffent devmodes
  231.         //
  232.  
  233.             if ( MYWM_NOTIFYICON + 10  <= GET_WM_COMMAND_ID(wParam, lParam) &&
  234.          MYWM_NOTIFYICON + 11 + gnModes >= GET_WM_COMMAND_ID(wParam, lParam))
  235.         {
  236.         UINT nNewMode;
  237.                 
  238.                 nNewMode = GET_WM_COMMAND_ID(wParam, lParam) - (MYWM_NOTIFYICON + 10);
  239.                 
  240.         //
  241.         // Only update if the chose a new setting
  242.         //
  243.  
  244.                 if (gnCurrentMode != nNewMode)
  245.                 {            
  246.            ChangeResolution (nNewMode, hDlg);
  247.         }
  248.  
  249.         break;
  250.             
  251.             }
  252.  
  253.  
  254.     } //WM_COMMAN switch
  255.  
  256.     } //WM_COMMAND
  257.  
  258.     case MYWM_NOTIFYICON:
  259.     {
  260.     switch (lParam)
  261.     {
  262.  
  263.         case WM_LBUTTONDOWN:
  264.         
  265.          //
  266.          // Handle popup here when user right mouse clicks tray icon
  267.          //
  268.          {
  269.             
  270.              //
  271.              // Handle popup here
  272.              //
  273.  
  274.              POINT point;
  275.  
  276.              GetCursorPos (&point);
  277.  
  278.              HandlePopupMenu (hDlg, point);
  279.             
  280.              break;
  281.     
  282.          }
  283.         
  284.         
  285.         case WM_RBUTTONDOWN:
  286.          switch (wParam)
  287.          {
  288.             
  289.             //
  290.             // Diplay the dialog box on Left mouse click
  291.             // this is how the user gets the dialog back if it is hidden
  292.             //
  293.  
  294.             case IDC_NOTIFY1:  ShowWindow (hDlg, SW_RESTORE);
  295.                        SetForegroundWindow (hDlg);
  296.                        break;
  297.  
  298.             default:
  299.              break;
  300.             
  301.           }
  302.             
  303.        
  304.         default:
  305.          break;
  306.  
  307.     }  // lParam switch
  308.  
  309.     }// MYWM_NOTIFYICON
  310.  
  311.     default:
  312.      return(FALSE);
  313.     
  314.     }  // switch (uMsg)
  315.  
  316.     return(TRUE);
  317.  
  318. }
  319.  
  320. /****************************************************************************
  321. *                                                                          
  322. *  FUNCTION   : GetDevModes (hwnd)
  323. *                                                                          
  324. *  PURPOSE    : Get the display modes supported by the current driver
  325. *
  326. \****************************************************************************/
  327. BOOL GetDevModes (
  328.                   
  329.   HWND hwnd)
  330. {
  331.     
  332.     BOOL bRet = TRUE;
  333.     BOOL bAddDM;
  334.     UINT iModeNum = 0;
  335.     DEVMODE CurrentDM, WorkingDM;
  336.     INT i;
  337.     UINT nlist;
  338.     LPDEVMODE pDM;
  339.  
  340.     //
  341.     // setting param 1 to NULL (lpszDeviceName) uses current device on NT
  342.     // and NULL is required on Win95
  343.     //
  344.  
  345.     if (IsNT())
  346.     {
  347.     //
  348.     // NT specific; returns current devmode when param 2 set to ENUM_CURRENT_SETTINGS,
  349.     //
  350.  
  351.     EnumDisplaySettings (NULL, ENUM_CURRENT_SETTINGS, &CurrentDM);
  352.     }
  353.  
  354.     //
  355.     // Determine how much memory we need
  356.     //
  357.  
  358.     for (iModeNum = 0, gnModes = -1;
  359.          bRet && (gnModes <= MAX_MODES); 
  360.          iModeNum++)
  361.     {
  362.         bRet = EnumDisplaySettings 
  363.                      (NULL,            // use default device
  364.                      iModeNum,         // DEVMODEs start at 0
  365.                      &WorkingDM);      // if successful the system
  366.                                        // fills in the DEVMODE
  367.                                        // structure
  368.  
  369.         //
  370.         // For some reason my driver supports 1 hz display frequency
  371.         // So filter out settings we do not want to display
  372.         //
  373.         
  374.         if ( bRet & 
  375.          WorkingDM.dmPelsWidth      >= MIN_WIDTH &&
  376.             (WorkingDM.dmDisplayFrequency >= MIN_FREQUENCY  ||
  377.          WorkingDM.dmDisplayFrequency == 0) )
  378.  
  379.         //
  380.         // Accept 0 frequency since windows 95 does return frequency
  381.         //
  382.         {
  383.             //
  384.             // Increment to use next DEVMODE
  385.             //
  386.  
  387.             gnModes++;
  388.     }
  389.  
  390.     } // for loop
  391.     
  392.     if(-1 == gnModes)
  393.     {
  394.         MessageBox(hwnd, "No Display modes available.", "SetDisp Error", IDOK);
  395.         return (FALSE);
  396.     }
  397.  
  398.     //
  399.     // We need gnModes worth of DEVMODE Structures
  400.     //
  401.     
  402.     gpDevModes = (PDEVMODE) malloc ((size_t) (gnModes + 1) * sizeof(DEVMODE));
  403.  
  404.     if (gpDevModes == NULL)
  405.     {
  406.         return (FALSE);
  407.     }
  408.  
  409.     //
  410.     // Loop through EnumDisplaySetting to get each supported DEVMODE
  411.     // When returns false we have them all
  412.     //
  413.     
  414.     for (iModeNum = 0, i = 0, bRet = TRUE; 
  415.          bRet && i <= gnModes; 
  416.          iModeNum++)
  417.     {
  418.         bRet = EnumDisplaySettings 
  419.                      (NULL,            // use default device
  420.                      iModeNum,         // DEVMODEs start at 0
  421.                      &WorkingDM);      // if successful the system
  422.                                        // fills in the DEVMODE
  423.                                        // structure
  424.  
  425.         //
  426.         // Miniport drivers support 1 hz display frequency representing the default
  427.         // and older drivers support 0 hz display frequency representing the default
  428.         // So filter out settings we do not want to display
  429.         //
  430.         
  431.         if ( bRet && 
  432.              WorkingDM.dmPelsWidth        >= MIN_WIDTH      && 
  433.             (WorkingDM.dmDisplayFrequency >= MIN_FREQUENCY  ||
  434.              WorkingDM.dmDisplayFrequency == 0              ||
  435.              WorkingDM.dmDisplayFrequency == 1))
  436.              // Accept 0 or 1 frequency which represent default frequencies
  437.         {
  438.             bAddDM = TRUE;
  439.  
  440.             //
  441.             // We will take this one unless another default has already been 
  442.             // added at these settings
  443.             //
  444.  
  445.             if (WorkingDM.dmDisplayFrequency == 0 || 
  446.                 WorkingDM.dmDisplayFrequency == 1)
  447.             {
  448.                 for (nlist = 0; nlist <= gnCurrentMode; nlist++)
  449.                 {
  450.                       pDM = gpDevModes + nlist;
  451.  
  452.                       if (pDM->dmPelsWidth  == WorkingDM.dmPelsWidth   &&
  453.                           pDM->dmPelsHeight == WorkingDM.dmPelsHeight  &&
  454.                           pDM->dmBitsPerPel == WorkingDM.dmBitsPerPel)
  455.                       {
  456.                           //
  457.                           // If everything else is the same do not add another default
  458.                           //
  459.  
  460.                           bAddDM = FALSE;
  461.                       }
  462.                 } // end for nlist
  463.  
  464.             } // end if default
  465.  
  466.             if (bAddDM)
  467.             {
  468.                 //
  469.                 // Increment to use next DEVMODE
  470.                 //
  471.  
  472.                 if (i == 0)
  473.                 {
  474.                     gpCurrentMode = gpDevModes;
  475.                 }
  476.                 else
  477.                 {
  478.                     gpCurrentMode += 1;
  479.                 }
  480.  
  481.                 EnumDisplaySettings (NULL, iModeNum, gpCurrentMode);
  482.                 i++;
  483.  
  484.             } // end if bAddDM
  485.  
  486.         } // end bRet and hz if
  487.  
  488.     } // end for EnumDisplaySettings
  489.  
  490.  
  491.     //
  492.     // Sort the array for display; default sort
  493.     // A different compare routine could sort by different attributes
  494.     //
  495.     
  496.     qsort((void *) gpDevModes, 
  497.           (size_t) gnModes + 1,  // add one since gnModes is zero based 
  498.           (size_t) sizeof(DEVMODE), 
  499.           ( int (_cdecl*)(const void*,const void*) )CompareDevModes);
  500.      
  501.     //
  502.     // Set gCurrentMode to CurrentDM
  503.     //
  504.     if (IsNT())
  505.     {
  506.         for (i =0; i <= gnModes; i++)
  507.         {
  508.             
  509.             if (i == 0)
  510.             {
  511.                 gpCurrentMode = gpDevModes;
  512.             }
  513.             else
  514.             {
  515.                 gpCurrentMode += 1;
  516.             }
  517.  
  518.             if (0 == CompareDevModes (&CurrentDM, gpCurrentMode))
  519.             {
  520.                 gnCurrentMode = i;
  521.                 break;
  522.             }
  523.         }
  524.     }
  525.     else
  526.     {
  527.         //
  528.         // Default to the first one
  529.         // since we error out if there is not even this one
  530.         //
  531.  
  532.         gnCurrentMode = 0;
  533.     }
  534.  
  535.     //
  536.     // TODO: What if some of the DEVMODES are not supported on 
  537.     //       the physical Device?
  538.     //
  539.     
  540.     return (TRUE);
  541.  
  542. }  //GetDevModes scope
  543.  
  544.  
  545. /****************************************************************************
  546. *                                                
  547. *  FUNCTION   : ChangeResolution (UINT nNewMode, HWND hwnd)
  548. *                                                
  549. *  PURPOSE    : Change the resolution to the nNewMode index DEVMODE               
  550. *                                                                          
  551. \****************************************************************************/
  552. BOOL ChangeResolution (
  553.     UINT nNewMode, 
  554.     HWND hwnd )
  555. {
  556.   
  557.     LONG lResult;       //Result of ChangeDisplaySettings
  558.     INT nUserResponse;    //Return from VerifyRes Dlg
  559.     UINT nOldMode;
  560.  
  561.    /*
  562.     ChangeDisplaySettings can set
  563.     dmBitsPerPel        Bits per pixel
  564.     dmPelsWidth        Pixel width
  565.     dmPelsHeight        Pixel height
  566.     dmDisplayFlags        Mode flags
  567.     dmDisplayFrequency  Mode frequency
  568.         
  569.         but one of thes must be set in the DEVMODE dmFields
  570.         DM_BITSPERPEL        Use the dmBitsPerPel value.
  571.         DM_PELSWIDTH        Use the dmPelsWidth value.
  572.         DM_PELSHEIGHT        Use the dmPelsHeight value.
  573.         DM_DISPLAYFLAGS        Use the dmDisplayFlags value.
  574.     DM_DISPLAYFREQENCY  Use the dmDisplayFrequency value.
  575.  
  576.     */
  577.  
  578.     //
  579.     // First select a DevMode to use
  580.     // to start, just cycling through them
  581.     //
  582.  
  583.     nOldMode = gnCurrentMode;
  584.     gnCurrentMode = nNewMode;
  585.     
  586.     //
  587.     // Increment ptr to the new mode
  588.     //
  589.  
  590.     gpCurrentMode = gpDevModes;
  591.     gpCurrentMode += nNewMode;
  592.     
  593.     //
  594.     // Verify that the DEVMODE select will change something
  595.     //
  596.  
  597.     if (!(DM_BITSPERPEL         & gpCurrentMode->dmFields ||
  598.           DM_PELSWIDTH         & gpCurrentMode->dmFields ||
  599.           DM_PELSHEIGHT         & gpCurrentMode->dmFields ||
  600.           DM_DISPLAYFLAGS     & gpCurrentMode->dmFields ||
  601.           DM_DISPLAYFREQUENCY & gpCurrentMode->dmFields ) )
  602.     
  603.     {
  604.     
  605.     //
  606.         // Note our DEVMODE returned from EnumDisplaySettings
  607.     // So we should never enter here
  608.     //
  609.  
  610.         gnCurrentMode = nOldMode;
  611.         
  612.         gpCurrentMode = gpDevModes;
  613.         gpCurrentMode += gnCurrentMode;
  614.  
  615.         return (FALSE);
  616.     }
  617.  
  618.  
  619.     /************************************************************\
  620.     *                                                            *
  621.     *   Possible Flags for param 2 of ChangeDisplay Settings     *
  622.     *    0            The graphics mode for the current            *
  623.     *                screen will be changed dynamically.         *
  624.     *    CDS_UPDATEREGISTRY    The graphics mode for the            *
  625.     *                current screen will be changed dynamically  *
  626.     *                and the graphics mode will be updated in    *
  627.     *                the registry. The mode information is       *
  628.     *                stored in the USER profile.                 *
  629.     *    CDS_TEST    The system tests if the requested            *
  630.     *                graphics mode could be set.                 *
  631.     *                                                            *
  632.     \************************************************************/
  633.     
  634.     //
  635.     // First have the system test if we can set it
  636.     //
  637.  
  638.     //
  639.     // Param 1 is the new DEVMODE
  640.     // Param 2 is Test Flag, 
  641.     // which asks the operating system if this is a valid setting 
  642.     // to change to -- wedon't want to make the system unusable
  643.     //
  644.  
  645.     lResult = ChangeDisplaySettings
  646.                 ( gpCurrentMode, 
  647.                   CDS_TEST );               
  648.                                       
  649.     
  650.     if (lResult == DISP_CHANGE_RESTART)
  651.     {
  652.         MessageBox(hwnd, "This mode requires a reboot which\n"  \
  653.                          "is not supported in this sample.", 
  654.              "SetDisp Message", IDOK);
  655.         
  656.         gnCurrentMode = nOldMode;
  657.         gpCurrentMode = gpDevModes;
  658.         gpCurrentMode += gnCurrentMode;
  659.  
  660.         return FALSE;
  661.     }
  662.  
  663.     if (DISP_CHANGE_SUCCESSFUL ==lResult)
  664.     {
  665.     
  666.      //
  667.      // Param 2 is 0 to change dynamically
  668.      // hence the app name SetDisp!
  669.      //
  670.  
  671.          lResult = ChangeDisplaySettings
  672.                      ( gpCurrentMode,
  673.                        0 );  
  674.     }
  675.     
  676.  
  677.  
  678.     switch (lResult)
  679.     {
  680.  
  681.     case DISP_CHANGE_SUCCESSFUL:  //The settings change was successful.
  682.      TRC("DISP_CHANGE_SUCCESSFUL\n");
  683.      break;
  684.  
  685.     case DISP_CHANGE_RESTART:      //The computer must be restarted in order 
  686.                                   //  for the graphics mode to work.
  687.          TRC("DISP_CHANGE_RESTART\n");
  688.          break;
  689.  
  690.     case DISP_CHANGE_BADFLAGS:      //An invalid set of flags was passed in.
  691.          TRC("DISP_CHANGE_BADFLAGS\n");
  692.          break;
  693.  
  694.     case DISP_CHANGE_FAILED:      //The display driver failed the specified 
  695.                                   //  graphics mode.
  696.          TRC("DISP_CHANGE_FAILED\n");
  697.          break;
  698.  
  699.     case DISP_CHANGE_BADMODE:      //The graphics mode is not supported.
  700.          TRC("DISP_CHANGE_BADMODE\n");
  701.          break;
  702.  
  703.     case DISP_CHANGE_NOTUPDATED:  //Windows NT only: Unable to write settings 
  704.                                   //  to the registry.                        
  705.          TRC("DISP_CHANGE_NOTUPDATED\n");
  706.          break;
  707.     default:
  708.      TRC("Undocumented return value!!!!\n");
  709.      break;
  710.     }
  711.  
  712.  
  713.     //
  714.     // Set a timer to only give the user so much
  715.     // time to dedice incase the screen is garbled
  716.     //
  717.  
  718.     SetTimer(hwnd,    VERIFY_RESCHANGE, VERIFY_TIMEOUT, VerifyTimerProc);
  719.  
  720.     //
  721.     // Have the user verify the new resolution and depth
  722.     //
  723.  
  724.     nUserResponse = DialogBox(g_hinst,// handle this application 
  725.                               MAKEINTRESOURCE(IDD_VERIFYRES),// identifies dialog box template
  726.                               NULL,               // handle to owner window
  727.                               VerifyDlgProc);  // the dialog box procedure
  728.  
  729.  
  730.     //
  731.     // The verification is over, kill the timer
  732.     //
  733.  
  734.     KillTimer(hwnd,    VERIFY_RESCHANGE);
  735.     
  736.     if (IDYES == nUserResponse)
  737.     {
  738.     
  739.     //
  740.     // Keep resolution and update registry
  741.     //
  742.  
  743.         char szTip[50];
  744.  
  745.     //
  746.     // TODO: give them three choices:
  747.         //       Dynamic only, Registry too, or Abort
  748.     //
  749.  
  750.         lResult = ChangeDisplaySettings
  751.                     ( gpCurrentMode,
  752.                       CDS_UPDATEREGISTRY );  //  Flag to update registry
  753.         
  754.         switch (lResult)
  755.         
  756.         {
  757.         
  758.         case DISP_CHANGE_SUCCESSFUL: 
  759.             
  760.         //
  761.         // The settings change was successful.
  762.         //
  763.  
  764.             TRC("DISP_CHANGE_SUCCESSFUL - reg\n");
  765.             
  766.             wsprintf(szTip,"%d x %d, %d bit color at %d hz", 
  767.                  gpCurrentMode->dmPelsWidth,
  768.                  gpCurrentMode->dmPelsHeight,
  769.                  gpCurrentMode->dmBitsPerPel,
  770.                  gpCurrentMode->dmDisplayFrequency);
  771.  
  772.              {
  773.  
  774.          //
  775.          // Update the Menu informtion, just a check mark for now
  776.          //
  777.  
  778.                  HMENU hMenu, hMenu2;
  779.                  
  780.                  hMenu = GetMenu(hwnd);
  781.                  
  782.                  hMenu2 = GetSubMenu (hMenu, 0);
  783.  
  784.          //
  785.          // Uncheck the old
  786.          //
  787.  
  788.                  CheckMenuItem (hMenu2, nOldMode, MF_BYPOSITION | MF_UNCHECKED);
  789.                  
  790.          //
  791.          // Check the new
  792.          //
  793.  
  794.          CheckMenuItem (hMenu2, gnCurrentMode, MF_BYPOSITION | MF_CHECKED);
  795.              
  796.              }
  797.  
  798.          //
  799.          // Update the Notify_Icon quick tip
  800.          //
  801.  
  802.              TrayMessage(hwnd, NIM_MODIFY, g_sDlgItems[0].uNotify,
  803.                     LoadImage(g_hinst, MAKEINTRESOURCE(IDI_SETDISP),
  804.                     IMAGE_ICON, 16, 16, 0), szTip);
  805.  
  806.              break;
  807.  
  808.         case DISP_CHANGE_RESTART:      //The computer must be restarted in order 
  809.                                       //  for the graphics mode to work.
  810.              TRC("DISP_CHANGE_RESTART - reg\n");
  811.              break;
  812.  
  813.         case DISP_CHANGE_BADFLAGS:      //An invalid set of flags was passed in.
  814.              TRC("DISP_CHANGE_BADFLAGS - reg\n");
  815.              break;
  816.  
  817.         case DISP_CHANGE_FAILED:      //The display driver failed the specified 
  818.                                       //  graphics mode.
  819.              TRC("DISP_CHANGE_FAILED - reg\n");
  820.              break;
  821.  
  822.         case DISP_CHANGE_BADMODE:      //The graphics mode is not supported.
  823.              TRC("DISP_CHANGE_BADMODE - reg\n");
  824.              break;
  825.  
  826.         case DISP_CHANGE_NOTUPDATED:  //Windows NT only: Unable to write settings 
  827.                                       //  to the registry.                        
  828.              TRC("DISP_CHANGE_NOTUPDATED - reg\n");
  829.              break;
  830.         default:
  831.               TRC("Undocumented return value!!!! - reg\n");
  832.               break;
  833.         }
  834.     
  835.     }
  836.     
  837.     else
  838.     
  839.     {
  840.     //
  841.     // The user chose to not keep the setting or    we timed out
  842.         // so they may not have seen the dialog box to choose
  843.         //
  844.         // Change resolution back by calling
  845.         // ChangeDisplaySettings 
  846.         // with a NULL DEVMODE which returns us to the current
  847.         // registry settings
  848.     //
  849.  
  850.         lResult = ChangeDisplaySettings
  851.                     ( NULL, 
  852.                       0 );  // 0 to change dynamically
  853.         
  854.         gnCurrentMode = nOldMode;
  855.         
  856.         gpCurrentMode = gpDevModes;
  857.         gpCurrentMode += gnCurrentMode;
  858.     
  859.     }
  860.  
  861.     return (TRUE);
  862.  
  863. }
  864.  
  865.  
  866.  /****************************************************************************
  867.  *                                                                          
  868.  *  FUNCTION   : SetResolutionMenu (hwnd)                              
  869.  *                                                                          
  870.  *  PURPOSE    : Create a context menu with all of the resolutions
  871.  *               that are in the devmodes we obtained from the drive
  872.  *                                                                          
  873.  \****************************************************************************/
  874. BOOL SetResolutionMenu ( 
  875.     HWND hwnd)
  876. {
  877.   
  878.     HMENU hMenu, hWndMenu; //hMenuTrackPopup;
  879.     INT i;
  880.     BOOL bRet;
  881.     PDEVMODE pDevMode;
  882.     
  883.     //
  884.     // Create new Resolutions menu from the DevModes collected
  885.     //
  886.  
  887.     hMenu = CreateMenu(); 
  888.     
  889.     if (!hMenu)
  890.     {
  891.        return (FALSE);
  892.     }
  893.  
  894.     //
  895.     // For each devmode add an menu item
  896.     // TODO: make the description on BitPerPel better
  897.     //
  898.  
  899.     for(i=0; i<= gnModes; i++)
  900.     {
  901.     
  902.         char szRes[50];
  903.  
  904.         
  905.         if (i == 0)
  906.         {
  907.             pDevMode = gpDevModes;
  908.         }
  909.         else
  910.         {
  911.             pDevMode += 1;
  912.     }
  913.  
  914.         //
  915.     // Set the menu text
  916.     //
  917.  
  918.         if (pDevMode->dmDisplayFrequency == 0 ||
  919.             pDevMode->dmDisplayFrequency == 1)
  920.     {
  921.         wsprintf(szRes,"%d x %d, %d bit color, default frequency",
  922.                  pDevMode->dmPelsWidth,
  923.                  pDevMode->dmPelsHeight,
  924.                  pDevMode->dmBitsPerPel);
  925.     }
  926.     else
  927.     {
  928.         wsprintf(szRes,"%d x %d, %d bit color at %d hz",
  929.                  pDevMode->dmPelsWidth,
  930.                  pDevMode->dmPelsHeight,
  931.                  pDevMode->dmBitsPerPel,
  932.                  pDevMode->dmDisplayFrequency);
  933.     }
  934.         
  935.         bRet = AppendMenu (hMenu, MF_STRING, MYWM_NOTIFYICON + 10 + i, szRes);
  936.         
  937.         SetMenuItemBitmaps(
  938.           hMenu,     // handle of menu
  939.           gnCurrentMode, // menu item to receive new bitmaps
  940.                   MF_BYPOSITION, // menu item flags
  941.                   NULL,             // handle of unchecked bitmap
  942.           NULL);     // handle of checked bitmap
  943.                                  // if last two are NULL the default 
  944.                                  // bitmap is used
  945.  
  946.     
  947.     } // for loop to set menu
  948.     
  949.     if (!bRet)
  950.     {
  951.    
  952.         //
  953.         // if the last one worked they all likely worked
  954.         // otherwise let's clean up
  955.         //
  956.  
  957.         DestroyMenu(hMenu);
  958.         
  959.         return(FALSE);
  960.     
  961.     }
  962.     else
  963.     {
  964.  
  965.         if (IsNT())
  966.         {
  967.             //
  968.             // Check the Current one
  969.             //
  970.  
  971.             CheckMenuItem (hMenu, gnCurrentMode, MF_BYPOSITION | MF_CHECKED);
  972.     
  973.             //
  974.             // Set it as the default so it is easy to go back to
  975.             //
  976.  
  977.         SetMenuDefaultItem(hMenu, gnCurrentMode, TRUE ); //TRUE if for by Position
  978.  
  979.         }
  980.  
  981.         hWndMenu = GetMenu (hwnd);
  982.         
  983.         InsertMenu (hWndMenu, 0, MF_POPUP|MF_BYPOSITION, (DWORD)hMenu, "&Resolutions");
  984.         
  985.         return(TRUE);
  986.     
  987.     }
  988.     
  989. }
  990.  
  991.  
  992.  /****************************************************************************
  993.  *                                                                          
  994.  *  FUNCTION   : TrayMessage (HWND hDlg, DWORD dwMessage, UINT uID, 
  995.  *                            HICON hIcon, PSTR pszTip )
  996.  *                                                                          
  997.  *  PURPOSE    : Creates, Modifies or deletes the tray icon 
  998.  *               If pszTip is not null, it uses that for the tip
  999.  *               otherwise it sets a default tip
  1000.  *                                                                          
  1001.  \****************************************************************************/
  1002.  
  1003. BOOL TrayMessage (
  1004.                   
  1005.   HWND hDlg, 
  1006.   DWORD dwMessage, 
  1007.   UINT uID, 
  1008.   HICON hIcon, 
  1009.   PSTR pszTip )
  1010.  
  1011. {
  1012.     BOOL res;
  1013.     NOTIFYICONDATA tnd;
  1014.  
  1015.     //
  1016.     // Get the Tray Icon
  1017.     //
  1018.  
  1019.     hIcon = (HICON)LoadImage(g_hinst, MAKEINTRESOURCE(IDI_SETDISP), IMAGE_ICON,
  1020.                  16, 16, 0);
  1021.     
  1022.     tnd.cbSize        = sizeof(NOTIFYICONDATA);
  1023.     tnd.hWnd        = hDlg;
  1024.     tnd.uID        = uID;
  1025.     tnd.uFlags        = NIF_MESSAGE|NIF_ICON|NIF_TIP;
  1026.     tnd.uCallbackMessage= MYWM_NOTIFYICON;
  1027.     tnd.hIcon        = hIcon;
  1028.     
  1029.     //
  1030.     // If there is a specific tip, set it
  1031.     // otherwise use SetDisp as the default
  1032.     //
  1033.  
  1034.     if (pszTip)
  1035.     {
  1036.     lstrcpyn(tnd.szTip, pszTip, sizeof(tnd.szTip));
  1037.     }
  1038.     else
  1039.     {
  1040.     lstrcpyn(tnd.szTip, "SetDisp", sizeof("SetDisp"));;
  1041.     }
  1042.  
  1043.     
  1044.     //
  1045.     //    Use the Shell_NotifyIcon API to setup the tray icon
  1046.     //
  1047.  
  1048.     res = Shell_NotifyIcon(dwMessage, &tnd);
  1049.  
  1050.     if (hIcon)
  1051.     {
  1052.      DestroyIcon(hIcon);
  1053.     }
  1054.  
  1055.  
  1056.     return res;
  1057.  
  1058. }
  1059.  
  1060.  
  1061.  /****************************************************************************
  1062.  *                                                                          
  1063.  *  FUNCTION   : NotifyDelete (HWND hDlg, UINT uIndex)
  1064.  *                                                                          
  1065.  *  PURPOSE    : Deletes a tray icon based on the uIndex .
  1066.  *               In this SetDisp sample, it is only used for a single icon
  1067.  *                                                                          
  1068.  \****************************************************************************/
  1069.  
  1070. void NotifyDelete (
  1071.                    
  1072.   HWND hDlg, 
  1073.   UINT uIndex )
  1074.  
  1075. {
  1076.  
  1077.     TrayMessage(hDlg, NIM_DELETE, g_sDlgItems[uIndex].uNotify, NULL, NULL);
  1078.  
  1079. }
  1080.  
  1081.  
  1082.  /****************************************************************************
  1083.  *                                                                          
  1084.  *  FUNCTION   : NotifyAdd (HWND hDlg, UINT uIndex)
  1085.  *                                                                          
  1086.  *  PURPOSE    : Creates tray icons based on the uIndex .
  1087.  *               In this SetDisp sample, it is only used for a single icon
  1088.  *                                                                          
  1089.  \****************************************************************************/
  1090.  
  1091. void NotifyAdd (
  1092.                
  1093.   HWND hDlg, 
  1094.   UINT uIndex )
  1095.  
  1096. {
  1097.  
  1098.     TrayMessage(hDlg, NIM_ADD, g_sDlgItems[uIndex].uNotify, NULL, NULL);
  1099.  
  1100. }
  1101.  
  1102.  
  1103.  /****************************************************************************
  1104.  *                                                                          
  1105.  *  FUNCTION   : VerifyTimerProc (HWND hwnd, UINT uMsg, 
  1106.  *                                UINT idEvent, DWORD dwTime )
  1107.  *                                                                          
  1108.  *  PURPOSE    : Simply sends an IDNO to the Verify Dialog
  1109.  *               This is setup to give the user a limited amount of time
  1110.  *               to approve
  1111.  *                                                                          
  1112.  \****************************************************************************/
  1113.  
  1114. VOID CALLBACK VerifyTimerProc (
  1115.                                
  1116.   HWND hwnd, 
  1117.   UINT uMsg, 
  1118.   UINT idEvent,
  1119.   DWORD dwTime )
  1120. {
  1121.  
  1122.     SendMessage(ghVerifyDlg, WM_COMMAND, IDNO, 0);
  1123.  
  1124. }
  1125.  
  1126.  /****************************************************************************
  1127.  *                                                                          
  1128.  *  FUNCTION   : VerifyTimerProc (HWND hDlg, UINT uMsg,
  1129.  *                                WPARAM wParam, LPARAM lParam)
  1130.  *
  1131.  *                                                                          
  1132.  *  PURPOSE    : Ask the user if they want to keep the new resolution
  1133.  *                                                                          
  1134.  \****************************************************************************/
  1135.  
  1136. BOOL CALLBACK VerifyDlgProc(
  1137.     HWND hDlg,
  1138.     UINT uMsg,
  1139.     WPARAM wParam,
  1140.     LPARAM lParam)
  1141. {
  1142.     switch(uMsg)
  1143.     {
  1144.     case WM_INITDIALOG:    ghVerifyDlg = hDlg;
  1145.                 return(TRUE);
  1146.     
  1147.     case WM_COMMAND:
  1148.     
  1149.          //
  1150.          // LOWORD added for portability
  1151.          //
  1152.         
  1153.          switch (LOWORD(wParam))
  1154.          {
  1155.         
  1156.          case IDNO:
  1157.          case IDCANCEL:    ghVerifyDlg = NULL;
  1158.                 EndDialog(hDlg, IDNO);
  1159.                 return 0;
  1160.         
  1161.  
  1162.          case IDYES:    ghVerifyDlg = NULL;
  1163.                 EndDialog(hDlg, IDYES);
  1164.                 return 0;
  1165.           }
  1166.        
  1167.     default:
  1168.          break;
  1169.    
  1170.     }
  1171.    
  1172.     return(FALSE);
  1173.  
  1174.     UNREFERENCED_PARAMETER(lParam);
  1175.  
  1176. }
  1177.  
  1178. /****************************************************************************
  1179.  *                                                                          *
  1180.  *  FUNCTION   : HandlePopupMenu (hwnd, point)                              *
  1181.  *                                                                          *
  1182.  *  PURPOSE    : Handles the display of the "floating" popup that appears   *
  1183.  *               on a mouse click in the app's client area.                 *
  1184.  *                                                                          *
  1185.  ****************************************************************************/
  1186.  
  1187. VOID APIENTRY HandlePopupMenu (
  1188.     HWND  hwnd,
  1189.     POINT point)
  1190. {
  1191.     
  1192.     HMENU hMenu;
  1193.     HMENU hMenuTrackPopup;
  1194.  
  1195.     //
  1196.     // Get the menu for the windows
  1197.     //
  1198.  
  1199.     hMenu = GetMenu(hwnd);
  1200.  
  1201.     if (!hMenu)
  1202.     {
  1203.     return;
  1204.     }
  1205.  
  1206.     //
  1207.     // Get the first menu in it which we will use for the call to
  1208.     // TrackPopup(). This could also have been created on the fly using
  1209.     // CreatePopupMenu and then we could have used InsertMenu() or
  1210.     // AppendMenu.
  1211.     //
  1212.     
  1213.     hMenuTrackPopup = GetSubMenu (hMenu, 0);
  1214.  
  1215.     //
  1216.     // Draw and track the "floating" popup
  1217.     //
  1218.  
  1219.     if (point.x < (long) (gpCurrentMode->dmPelsWidth - 50))
  1220.         point.x = (long) (gpCurrentMode->dmPelsWidth - 50);
  1221.  
  1222.     if (point.y < (long) (gpCurrentMode->dmPelsHeight - 50))
  1223.         point.y = (long) (gpCurrentMode->dmPelsHeight - 50);
  1224.     
  1225.     
  1226.     //
  1227.     // This is required when using a notify icon -- see KB article
  1228.     // PRB: Menus for Notification Icons Don't Work Correctly
  1229.     //
  1230.  
  1231.     SetForegroundWindow (hwnd);
  1232.     
  1233.     TrackPopupMenu (hMenuTrackPopup, TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
  1234.                     point.x, point.y, 0, hwnd, NULL);
  1235.  
  1236.     //
  1237.     // This is required when using a notify icon -- see KB article
  1238.     // PRB: Menus for Notification Icons Don't Work Correctly
  1239.     //
  1240.  
  1241.     PostMessage (hwnd, WM_USER, 0, 0);
  1242.  
  1243. }
  1244.  
  1245.  
  1246. /****************************************************************************\
  1247. *                                                                          
  1248. *  FUNCTION   : CompareDevModes (DEVMODE *leftDM, DEVMODE *rightDM)                              
  1249. *                                                                          
  1250. *  PURPOSE    : Handles the display of the "floating" popup that appears   
  1251. *               on a mouse click in the app's client area.                 
  1252. *                                                                          
  1253. \****************************************************************************/
  1254. int CompareDevModes (
  1255.  
  1256.     DEVMODE *leftDM,
  1257.     DEVMODE *rightDM)
  1258. {
  1259.  
  1260.     //
  1261.     // Return 1  if left is bigger
  1262.     //        0  if equal
  1263.     //        -1 if right is bigger
  1264.     //
  1265.     // Comparison order is Width then Height then Bits then Frequency
  1266.     // This is an arbitrary order of importance. Often BitPerPels is
  1267.     // on considered the most important measure of a display setting
  1268.     //
  1269.     // return on the first one that is larger between left and right
  1270.     //
  1271.  
  1272.     if (leftDM->dmPelsWidth  > rightDM->dmPelsWidth)
  1273.     {
  1274.         return 1;
  1275.     }
  1276.     else if (leftDM->dmPelsWidth  < rightDM->dmPelsWidth)
  1277.     {
  1278.         return -1;
  1279.     }
  1280.  
  1281.  
  1282.     if (leftDM->dmPelsHeight > rightDM->dmPelsHeight)
  1283.     {
  1284.         return 1;
  1285.     }
  1286.     else if (leftDM->dmPelsHeight < rightDM->dmPelsHeight)
  1287.     {
  1288.         return -1;
  1289.     }
  1290.  
  1291.  
  1292.     if (leftDM->dmBitsPerPel > rightDM->dmBitsPerPel)
  1293.     {
  1294.         return 1;
  1295.     }
  1296.     else if (leftDM->dmBitsPerPel < rightDM->dmBitsPerPel)
  1297.     {
  1298.         return -1;
  1299.     }
  1300.     
  1301.  
  1302.     if (leftDM->dmDisplayFrequency > rightDM->dmDisplayFrequency)
  1303.     {
  1304.         return 1;
  1305.     }
  1306.     else if (leftDM->dmDisplayFrequency < rightDM->dmDisplayFrequency)
  1307.     {
  1308.         return -1;
  1309.     }
  1310.  
  1311.     //
  1312.     // All are equal
  1313.     //
  1314.  
  1315.     return 0;
  1316.  
  1317. }
  1318.  
  1319. /****************************************************************************\
  1320. *                                                                          
  1321. *  FUNCTION: About(HWND, UINT, UINT, LONG)
  1322. *
  1323. *  PURPOSE:  Processes messages for the "About" dialog box 
  1324. *
  1325. \****************************************************************************/
  1326. BOOL APIENTRY About(
  1327.     HWND hDlg,
  1328.     UINT message,
  1329.     UINT wParam,
  1330.     LONG lParam)
  1331. {
  1332.     switch (message)
  1333.     {
  1334.        case WM_INITDIALOG:
  1335.           return TRUE;
  1336.  
  1337.        case WM_COMMAND:              
  1338.          if (LOWORD(wParam) == IDOK)
  1339.          {
  1340.               EndDialog(hDlg, TRUE);
  1341.               return TRUE;
  1342.          }
  1343.  
  1344.          break;
  1345.  
  1346.        default:
  1347.  
  1348.         return FALSE;
  1349.  
  1350.     }
  1351.  
  1352. }
  1353.  
  1354. BOOL IsNT()
  1355. {
  1356.     OSVERSIONINFO          osvi;
  1357.     
  1358.     osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1359.     
  1360.     GetVersionEx(&osvi);
  1361.  
  1362.     if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) 
  1363.     {
  1364.         return TRUE;
  1365.     }
  1366.     else
  1367.     {
  1368.         return FALSE;
  1369.     }
  1370. }
  1371.