dlgapp.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 32k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. //////////////////////////////////////////////////////////////////////////
  2. //
  3. //  dlgapp.cpp
  4. //
  5. //      This file contains the main entry point into the application and
  6. //      the implementation of the CDlgApp class.
  7. //
  8. //  (C) Copyright 1997 by Microsoft Corporation. All rights reserved.
  9. //
  10. //////////////////////////////////////////////////////////////////////////
  11. #include <windows.h>
  12. #include <commctrl.h>
  13. #include <shlwapi.h>    // for string compare functions
  14. #include <debug.h>
  15. #include <tchar.h>
  16. #pragma hdrstop
  17. #include "dlgapp.h"
  18. #include "resource.h"
  19. #define WINDOW_CLASS    TEXT("_BerksWin2kAutorunApp_")
  20. //////////////////////////////////////////////////////////////////////////
  21. // Global Data
  22. //////////////////////////////////////////////////////////////////////////
  23. bool    g_bTaskRunning = false;     // true when we have a running task open
  24. int     g_iSelectedItem = -1;       // 
  25. WNDPROC g_fnBtnProc = NULL;         // the window proc for a button.
  26. //////////////////////////////////////////////////////////////////////////
  27. // Prototypes
  28. //////////////////////////////////////////////////////////////////////////
  29. LONG_PTR CALLBACK ButtonWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  30. //////////////////////////////////////////////////////////////////////////
  31. // Metrics
  32. // Our metrics are constants that never change.  All sizes are in pixels (as per the spec):
  33. //////////////////////////////////////////////////////////////////////////
  34. #define c_cyLogoImage                   87  // height of the branding image.
  35. #define c_cyFadeBar                     6   // height of the color fade bar
  36. #define c_cyBranding                    (c_cyLogoImage+c_cyFadeBar) // height of top region that contains our branding images and the fade bar
  37. #define c_cxCheckTextLeftEdge           29  // width from left edge for checkbox text label
  38. #define c_cxMenuItemPadding             10  // width from left of menu item to left of text and right of text to right of menu item
  39. #define c_cyMenuItemPadding             5   // height from top of menu item to top of text and bottom of text to bottom of menu item
  40. #define c_cyMenuItemSpacing             1   // gap from top of one menu item to bottom of next item
  41. #define c_cyBarToTitlePadding           12  // vertical padding from botton of fade bar to top of title text
  42. #define c_cyTitleToBodyPadding          6   // vertical padding from bottom of title text to top of body text
  43. #define c_cyBodyToBottomPadding         53  // vertical padding from body of body text to bottom of client area
  44. #define c_cxRightPanelPadding           16  // generic horizontal padding used on both edges of the right pane
  45. #define c_cyCheckTextToBottomPadding    8   // vertical padding from bottom of "Show at startup" text to bottom of client area
  46. #define c_cxCheckBox                    13
  47. #define c_cyCheckBox                    12
  48. // Code to ensure only one instance of a particular window is running
  49. HANDLE CheckForOtherInstance(HINSTANCE hInstance)
  50. {
  51.     TCHAR   szCaption[128];
  52.     HANDLE  hMutex;
  53.     LoadString(hInstance, IDS_TITLE, szCaption, 128);
  54.     // We don't want to launch autorun when winnt32 is running.  The standard way
  55.     // to check for this is the following mutex, which winnt32 creates:
  56.     hMutex = OpenMutex( MUTEX_ALL_ACCESS, FALSE, TEXT("Winnt32 Is Running") );
  57.     if ( hMutex )
  58.     {
  59.         // The mutex exists, this means winnt32 is running so we shouldn't.
  60.         // REVIEW: Should we try to findwindow and activate winnt32?
  61.         CloseHandle( hMutex );
  62.         return 0;
  63.     }
  64.     // We create a named mutex with our window caption just as a way to check
  65.     // if we are already running autorun.exe.  Only if we are the first to
  66.     // create the mutex do we continue.
  67.     hMutex = CreateMutex (NULL, FALSE, szCaption);
  68.     if ( !hMutex )
  69.     {
  70.         // failed to create the mutex
  71.         return 0;
  72.     }
  73.     else if (GetLastError() == ERROR_ALREADY_EXISTS)
  74.     {
  75.         // Mutex created but by someone else, activate that window
  76.         HWND hwnd = FindWindow( WINDOW_CLASS, szCaption );
  77.         SetForegroundWindow(hwnd);
  78.         CloseHandle(hMutex);
  79.         return 0;
  80.     }
  81.     // we are the first
  82.     return hMutex;
  83. }
  84. /**
  85. *  This function is the main entry point into our application.
  86. *
  87. *  @return     int     Exit code.
  88. */
  89. int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin, int nShowCmd )
  90. {
  91.     HANDLE hMutex = CheckForOtherInstance(hInstance);
  92.     if ( hMutex )
  93.     {
  94.         CDlgApp dlgapp;
  95.         dlgapp.Register(hInstance);
  96.         if ( dlgapp.InitializeData() )
  97.         {
  98.             dlgapp.Create(nShowCmd);
  99.             dlgapp.MessageLoop();
  100.         }
  101.         CloseHandle(hMutex);
  102.     }
  103.     return 0;
  104. }
  105. typedef DWORD (WINAPI *PFNGETLAYOUT)(HDC);                   // gdi32!GetLayout
  106. typedef DWORD (WINAPI *PFNSETLAYOUT)(HDC, DWORD);            // gdi32!SetLayout
  107. /**
  108. *  This function gets the DC layout.
  109. *
  110. *  @return     DWORD     DC layout.
  111. */
  112. DWORD Mirror_GetLayout( HDC hdc )
  113. {
  114.     DWORD dwRet=0;
  115.     static PFNGETLAYOUT pfnGetLayout=NULL;
  116.     static BOOL bTriedToLoadBefore = FALSE;
  117.     if( (NULL == pfnGetLayout) && !bTriedToLoadBefore)
  118.     {
  119.         HMODULE hmod = GetModuleHandleA("GDI32");
  120.         if( hmod )
  121.             pfnGetLayout = (PFNGETLAYOUT)GetProcAddress(hmod, "GetLayout");
  122.         bTriedToLoadBefore = TRUE;    
  123.     }
  124.     if( pfnGetLayout )
  125.         dwRet = pfnGetLayout( hdc );
  126.     return dwRet;
  127. }
  128. /**
  129. *  This function sets the DC layout.
  130. *
  131. *  @return     DWORD     old DC layout.
  132. */
  133. DWORD Mirror_SetLayout( HDC hdc , DWORD dwLayout )
  134. {
  135.     DWORD dwRet=0;
  136.     static PFNSETLAYOUT pfnSetLayout=NULL;
  137.     static BOOL bTriedToLoadBefore = FALSE;
  138.     if( (NULL == pfnSetLayout) && !bTriedToLoadBefore)
  139.     {
  140.         HMODULE hmod = GetModuleHandleA("GDI32");
  141.         if( hmod )
  142.             pfnSetLayout = (PFNSETLAYOUT)GetProcAddress(hmod, "SetLayout");
  143.         bTriedToLoadBefore = TRUE;            
  144.     }
  145.     if( pfnSetLayout )
  146.         dwRet = pfnSetLayout( hdc , dwLayout );
  147.     return dwRet;
  148. }
  149. /**
  150. *  This method is our contstructor for our class. It initialize all
  151. *  of the instance data.
  152. */
  153. CDlgApp::CDlgApp()
  154. {
  155.     m_hInstance     = NULL;
  156.     m_hwnd          = NULL;
  157.     m_bHighContrast = false;
  158.     m_hfontTitle = NULL;
  159.     m_hfontMenu  = NULL;
  160.     m_hfontBody  = NULL;
  161.     m_hbrMenuItem   = NULL;
  162.     m_hbrMenuBorder = NULL;
  163.     m_hbrRightPanel = NULL;
  164.     m_szDefTitle[0] = NULL;
  165.     m_szDefBody[0] = NULL;
  166.     // In theory, all of these metrics could be adjusted to resize the window.  Resizing wouldn't
  167.     // effect the paddings and spacings so these are defined above as constants.  In the real
  168.     // world we are only resizing vertically to adjust for oversized content.  These are more to
  169.     // allow future expansion.
  170.     m_cxClient = 478;       // width of the client area
  171.     m_cyClient = 322;       // This is currently the only metirc we actually adjust.
  172.     m_cxLeftPanel = 179;    // width of the panel that contains the menu items.
  173.     m_hdcTop = NULL;
  174.     m_hcurHand = NULL;
  175.     m_bLowColor = false;
  176.     m_iColors = -1;
  177.     m_hpal = NULL;
  178. }
  179. CDlgApp::~CDlgApp()
  180. {
  181.     DeleteObject(m_hfontTitle);
  182.     DeleteObject(m_hfontMenu);
  183.     DeleteObject(m_hfontBody);
  184.     DeleteObject(m_hbrMenuItem);
  185.     DeleteObject(m_hbrMenuBorder);
  186.     DeleteObject(m_hbrRightPanel);
  187.     DeleteDC(m_hdcTop);
  188. }
  189. /**
  190. *  This method will register our window class for the application.
  191. *
  192. *  @param  hInstance   The application instance handle.
  193. *
  194. *  @return             No return value.
  195. */
  196. void CDlgApp::Register(HINSTANCE hInstance)
  197. {
  198.     WNDCLASS  wndclass;
  199.     m_hInstance = hInstance;
  200.     
  201.     wndclass.style          = CS_OWNDC;
  202.     wndclass.lpfnWndProc    = WndProc;
  203.     wndclass.cbClsExtra     = 0;
  204.     wndclass.cbWndExtra     = 0;
  205.     wndclass.hInstance      = hInstance;
  206.     wndclass.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WEBAPP));
  207.     wndclass.hCursor        = LoadCursor(NULL, IDC_ARROW);
  208.     wndclass.hbrBackground  = NULL;
  209.     wndclass.lpszMenuName   = NULL;
  210.     wndclass.lpszClassName  = WINDOW_CLASS;
  211.     RegisterClass(&wndclass);
  212. }
  213. /**
  214. *  This method will initialize the data object.
  215. *
  216. *  @return         No return value.
  217. */
  218. bool CDlgApp::InitializeData()
  219. {
  220.     // Determine if we should use Direct Animaiton to display our intro graphics.
  221.     // We don't use DA on slow machines, machines with less than 256 color displays,
  222.     // and hydra terminals.  For everything else we use DA.
  223.     HWND hwnd = GetDesktopWindow();
  224.     HDC hdc = GetDC( hwnd );
  225.     m_iColors = GetDeviceCaps( hdc, NUMCOLORS );
  226.     m_bLowColor = ((m_iColors != -1) && (m_iColors <= 256));
  227.     if ( m_bLowColor )
  228.     {
  229.         m_hpal = CreateHalftonePalette(hdc);
  230.     }
  231.     ReleaseDC( hwnd, hdc );
  232.     // Initialize the items from the INI file.
  233.     if ( !m_DataSrc.Init() )
  234.     {
  235.         // this is a sign from the data source that we should exit
  236.         return false;
  237.     }
  238.     // Are we in accesibility mode?  This call won't work on NT 4.0 because this flag wasn't known.
  239.     HIGHCONTRAST hc;
  240.     hc.cbSize = sizeof(HIGHCONTRAST);
  241.     hc.dwFlags = 0; // avoid random result should SPI fail
  242.     if ( SystemParametersInfo( SPI_GETHIGHCONTRAST, sizeof(HIGHCONTRAST), &hc, 0 ) )
  243.     {
  244.         m_bHighContrast = ( hc.dwFlags & HCF_HIGHCONTRASTON );
  245.     }
  246.     else
  247.     {
  248.         // we must be on NT 4.0 or below.  Just assume we aren't in high contrast mode.
  249.         ASSERT( false == m_bHighContrast );
  250.     }
  251.     // Set the color table based on our HighContrast mode setting.
  252.     SetColorTable();
  253.     // create the fonts that we need to use.
  254.     CreateWelcomeFonts(hdc);
  255.     // create the image for the top region
  256.     CreateBrandingBanner();
  257.     // we pre load the background images so they draw more quickly.
  258.     LoadBkgndImages();
  259.     // load the resource strings that we always need
  260.     LoadString( m_hInstance, IDS_DEFTITLE, m_szDefTitle, ARRAYSIZE(m_szDefTitle) );
  261.     LoadString( m_hInstance, IDS_DEFBODY, m_szDefBody, ARRAYSIZE(m_szDefBody) );
  262.     m_hcurHand = LoadCursor( m_hInstance, MAKEINTRESOURCE(IDC_BRHAND) );
  263.     return true;
  264. }
  265. BOOL CDlgApp::SetColorTable()
  266. {
  267.     if ( m_bHighContrast )
  268.     {
  269.         // set to high contrast values
  270.         m_hbrMenuItem   = (HBRUSH)(COLOR_BTNFACE+1);
  271.         m_hbrMenuBorder = (HBRUSH)(COLOR_BTNSHADOW+1);
  272.         m_hbrRightPanel = (HBRUSH)(COLOR_WINDOW+1);
  273.         m_crMenuText    = GetSysColor(COLOR_BTNTEXT);
  274.         m_crNormalText  = GetSysColor(COLOR_WINDOWTEXT);
  275.         m_crTitleText   = m_crNormalText;
  276.         m_crSelectedText= GetSysColor(COLOR_GRAYTEXT);
  277.     }
  278.     else
  279.     {
  280.         m_crMenuText    = RGB(0,0,0);
  281.         m_crNormalText  = RGB(0,0,0);
  282.         m_crSelectedText= RGB(0x80, 0x80, 0x80);    // default value for COLOR_GRAYTEXTs
  283.         m_crTitleText   = RGB(51,102,153);
  284.         m_hbrRightPanel = (HBRUSH)GetStockObject( WHITE_BRUSH );
  285.         if ( m_bLowColor )
  286.         {
  287.             if (m_iColors <= 16)
  288.             {
  289.                 // Set to colors that work well in 16 color mode.
  290.                 HBITMAP hbmp;
  291.                 hbmp = (HBITMAP)LoadImage(m_hInstance, MAKEINTRESOURCE(IDB_16MENU), IMAGE_BITMAP, 0,0, LR_CREATEDIBSECTION);
  292.                 m_hbrMenuItem   = CreatePatternBrush(hbmp);
  293.                 DeleteObject(hbmp);
  294.                 hbmp = (HBITMAP)LoadImage(m_hInstance, MAKEINTRESOURCE(IDB_16BORDER), IMAGE_BITMAP, 0,0, LR_CREATEDIBSECTION);
  295.                 m_hbrMenuBorder = CreatePatternBrush( hbmp );
  296.                 DeleteObject(hbmp);
  297. //
  298. //                if ( WeAreRunningOnWin95 )
  299. //                    m_crMenuText    = RGB(255,255,255);
  300.             }
  301.             else
  302.             {
  303.                 // Set to colors that work well in 256 color mode.  Use colors from the halftone palette.
  304.                 HBITMAP hbmp;
  305.                 hbmp = (HBITMAP)LoadImage(m_hInstance, MAKEINTRESOURCE(IDB_256MENU), IMAGE_BITMAP, 0,0, LR_CREATEDIBSECTION);
  306.                 m_hbrMenuItem   = CreatePatternBrush(hbmp);
  307.                 DeleteObject(hbmp);
  308.                 hbmp = (HBITMAP)LoadImage(m_hInstance, MAKEINTRESOURCE(IDB_256BORDER), IMAGE_BITMAP, 0,0, LR_CREATEDIBSECTION);
  309.                 m_hbrMenuBorder = CreatePatternBrush( hbmp );
  310.                 DeleteObject(hbmp);
  311.             }
  312.         }
  313.         else
  314.         {
  315.             m_hbrMenuItem   = CreateSolidBrush( RGB(166,202,240) );
  316.             m_hbrMenuBorder = CreateSolidBrush( m_crTitleText );
  317.         }
  318.     }
  319.     return TRUE;
  320. }
  321. BOOL CDlgApp::CreateWelcomeFonts(HDC hdc)
  322. {
  323.     LOGFONT lf;
  324.     CHARSETINFO csInfo;
  325.     TCHAR szFontSize[6];
  326.     memset(&lf,0,sizeof(lf));
  327.     lf.lfWeight = FW_BOLD;
  328.     lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
  329.     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  330.     lf.lfQuality = DEFAULT_QUALITY;
  331.     lf.lfPitchAndFamily = DEFAULT_PITCH|FF_SWISS;
  332.     LoadString( m_hInstance, IDS_FONTFACE, lf.lfFaceName, ARRAYSIZE(lf.lfFaceName) );
  333.     // Set charset
  334.     if (TranslateCharsetInfo((DWORD*)GetACP(), &csInfo, TCI_SRCCODEPAGE) == 0)
  335.     {
  336.         csInfo.ciCharset = 0;
  337.     }
  338.     lf.lfCharSet = (BYTE)csInfo.ciCharset;
  339.     // TODO:  If user has accesibility large fonts turned on then scale the font sizes.
  340.     LoadString( m_hInstance, IDS_CYTITLEFONT, szFontSize, ARRAYSIZE(szFontSize) );
  341.     lf.lfHeight  = -_ttoi(szFontSize);
  342.     m_hfontTitle = CreateFontIndirect(&lf);
  343.     LoadString( m_hInstance, IDS_CYMENUITEMFONT, szFontSize, ARRAYSIZE(szFontSize) );
  344.     lf.lfHeight  = -_ttoi(szFontSize);
  345.     m_hfontMenu  = CreateFontIndirect(&lf);
  346.     lf.lfWeight = FW_NORMAL;
  347.     LoadString( m_hInstance, IDS_CYBODYFONT, szFontSize, ARRAYSIZE(szFontSize) );
  348.     lf.lfHeight  = -_ttoi(szFontSize);
  349.     m_hfontBody  = CreateFontIndirect(&lf);
  350.     return TRUE;
  351. }
  352. BOOL CDlgApp::CreateBrandingBanner()
  353. {
  354.     HBITMAP hbm;
  355.     int iBitmap;
  356.     m_hdcTop = CreateCompatibleDC(NULL);
  357.     if ( m_bLowColor && (m_iColors <= 16) )
  358.     {
  359.         iBitmap = IDB_BANNER16;
  360.     }
  361.     else
  362.     {
  363.         iBitmap = IDB_BANNER;
  364.     }
  365.     hbm = (HBITMAP)LoadImage(m_hInstance, MAKEINTRESOURCE(iBitmap), IMAGE_BITMAP, 0,0, LR_CREATEDIBSECTION);
  366.     SelectObject( m_hdcTop, hbm );
  367.     return TRUE;
  368. }
  369. BOOL CDlgApp::LoadBkgndImages()
  370. {
  371.     BITMAP bm;
  372.     for (int i=0; i<4; i++)
  373.     {
  374.         m_aBkgnd[i].hbm = (HBITMAP)LoadImage(m_hInstance, MAKEINTRESOURCE(IDB_BKGND0+i), IMAGE_BITMAP, 0,0, LR_CREATEDIBSECTION);
  375.         // REVIEW: are all these the same size?  If yes, skip this part and use a constant:
  376.         GetObject(m_aBkgnd[i].hbm,sizeof(bm),&bm);
  377.         m_aBkgnd[i].cx = bm.bmWidth;
  378.         m_aBkgnd[i].cy = bm.bmHeight;
  379.     }
  380.     return TRUE;
  381. }
  382. BOOL CDlgApp::AdjustToFitFonts(DWORD dwStyle)
  383. {
  384.     RECT rect;
  385.     int cyLowestBodyPoint = 0;
  386.     HDC hdc = GetDC(m_hwnd);
  387.     // now based on the users prefered font size we allow these sizes to adjust slightly
  388.     HFONT hfontOld = (HFONT)SelectObject(hdc,m_hfontTitle);
  389.     int iMenuItemTop = c_cyBranding;
  390.     for (int i=0; i<m_DataSrc.m_iItems; i++ )
  391.     {
  392.         rect.left = m_cxLeftPanel+c_cxRightPanelPadding;
  393.         rect.top = c_cyBranding + c_cyBarToTitlePadding;
  394.         rect.right = m_cxClient-c_cxRightPanelPadding;
  395.         SelectObject(hdc,m_hfontTitle);
  396.         DrawText(hdc,m_DataSrc[i].GetTitle(),-1,&rect,DT_CALCRECT|DT_WORDBREAK); // this computes rcLargestTitle.bottom
  397.         rect.left = m_cxLeftPanel+c_cxRightPanelPadding;
  398.         rect.top = rect.bottom + c_cyTitleToBodyPadding;
  399.         rect.right = m_cxClient-c_cxRightPanelPadding;
  400.         SelectObject(hdc,m_hfontBody);
  401.         DrawText(hdc,m_DataSrc[i].GetDescription(),-1,&rect,DT_CALCRECT|DT_WORDBREAK); // this computes rcLargestBody.bottom
  402.         if ( rect.bottom > cyLowestBodyPoint )
  403.             cyLowestBodyPoint = rect.bottom;
  404.         rect.left = c_cxMenuItemPadding;
  405.         rect.top = iMenuItemTop+c_cyMenuItemPadding;
  406.         rect.right = m_cxLeftPanel-c_cxMenuItemPadding;
  407.         SelectObject(hdc,m_hfontMenu);
  408.         DrawText(hdc,m_DataSrc[i].GetMenuName(),-1,&rect,DT_CALCRECT|DT_WORDBREAK);
  409.         HWND hwnd;
  410.         hwnd = GetDlgItem(m_hwnd, IDM_MENUITEM1+i);
  411.         SetWindowPos(
  412.                 hwnd,
  413.                 NULL,
  414.                 0,
  415.                 iMenuItemTop,
  416.                 m_cxLeftPanel,
  417.                 rect.bottom + c_cyMenuItemPadding + 1 + c_cyMenuItemSpacing - iMenuItemTop,   // +1 to improve centering (due to drop letters)
  418.                 SWP_NOZORDER );
  419.         iMenuItemTop = rect.bottom + c_cyMenuItemPadding + 1 + c_cyMenuItemSpacing;
  420.     }
  421.     // store the bottom most menu point.  Needed for drawing the background rect later.
  422.     m_cyBottomOfMenuItems = iMenuItemTop;
  423.     // we now adjust the height of our window to accomadate the largest item.
  424.     if ( cyLowestBodyPoint + c_cyBodyToBottomPadding > m_cyClient )
  425.         m_cyClient = cyLowestBodyPoint + c_cyBodyToBottomPadding;
  426.     // if the menu items plus the check box are too tall, make the dialog taller
  427.     if ( iMenuItemTop + c_cyCheckTextToBottomPadding > m_cyClient )
  428.         m_cyClient = iMenuItemTop + c_cyCheckTextToBottomPadding;
  429.     // restore the DC to its original value
  430.     SelectObject(hdc,hfontOld);
  431.     //  set the client area to a fixed size and center the window on screen
  432.     rect.left = 0;
  433.     rect.top = 0;
  434.     rect.right = m_cxClient;
  435.     rect.bottom = m_cyClient;
  436.     AdjustWindowRect( &rect, dwStyle, FALSE );
  437.     rect.right -= rect.left;
  438.     rect.bottom -= rect.top;
  439.     RECT rcDesktop;
  440.     SystemParametersInfo(SPI_GETWORKAREA,0, &rcDesktop, FALSE);
  441.     rect.left = (rcDesktop.left+rcDesktop.right-rect.right)/2;
  442.     rect.top = (rcDesktop.top+rcDesktop.bottom-rect.bottom)/2;
  443.     SetWindowPos(m_hwnd, HWND_TOP, rect.left, rect.top, rect.right, rect.bottom, 0);
  444.     return TRUE;
  445. }
  446. /**
  447. *  This method will create the application window.
  448. *
  449. *  @return         No return value.
  450. */
  451. void CDlgApp::Create(int nCmdShow)
  452. {
  453.     //
  454.     //  load the window title from the resource.
  455.     //
  456.     TCHAR szTitle[MAX_PATH];
  457.     LoadString(m_hInstance, IDS_TITLE, szTitle, MAX_PATH);
  458.     const DWORD dwStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_CLIPCHILDREN;
  459.     
  460.     m_hwnd = CreateWindowEx(
  461.             WS_EX_CONTROLPARENT,
  462.             WINDOW_CLASS,
  463.             szTitle,
  464.             dwStyle,
  465.             0,
  466.             0,
  467.             0,
  468.             0,
  469.             NULL,
  470.             NULL,
  471.             m_hInstance,
  472.             this);
  473.     // We created the window with zero size, now we adjust that size to take into
  474.     // acount the selected font size, etc.
  475.     AdjustToFitFonts(dwStyle);
  476.     ShowWindow(m_hwnd, nCmdShow);
  477.     // give our data source the opertunity to display a startup sequence
  478.     m_DataSrc.ShowSplashScreen( m_hwnd );
  479.     InvalidateRect(m_hwnd, NULL, TRUE);
  480.     UpdateWindow(m_hwnd);
  481. }
  482. /**
  483. *  This method is our application message loop.
  484. *
  485. *  @return         No return value.
  486. */
  487. void CDlgApp::MessageLoop()
  488. {
  489.     MSG msg;
  490.     
  491.     while (GetMessage(&msg, NULL, 0, 0))
  492.     {
  493.         // IsDialogMessage cannot understand the concept of ownerdraw default pushbuttons.  It treats
  494.         // these attributes as mutually exclusive.  As a result, we handle this ourselves.  We want
  495.         // whatever control has focus to act as the default pushbutton.
  496.         if ( (WM_KEYDOWN == msg.message) && (VK_RETURN == msg.wParam) )
  497.         {
  498.             HWND hwndFocus = GetFocus();
  499.             if ( hwndFocus )
  500.             {
  501.                 SendMessage(m_hwnd, WM_COMMAND, MAKELONG(GetDlgCtrlID(hwndFocus), BN_CLICKED), (LPARAM)hwndFocus);
  502.             }
  503.             continue;
  504.         }
  505.         if ( IsDialogMessage(m_hwnd, &msg) )
  506.             continue;
  507.         TranslateMessage(&msg);
  508.         DispatchMessage(&msg);
  509.     }
  510. }
  511. /**
  512. *  This is the window procedure for the container application. It is used
  513. *  to deal with all messages to our window.
  514. *
  515. *  @param      hwnd        Window handle.
  516. *  @param      msg         The window message.
  517. *  @param      wParam      Window Parameter.
  518. *  @param      lParam      Window Parameter.
  519. *
  520. *  @return     LRESULT
  521. */
  522. LRESULT CALLBACK CDlgApp::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  523. {
  524.     CDlgApp *web = (CDlgApp *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  525.     switch(msg)
  526.     {
  527.     case WM_NCCREATE:
  528.         web = (CDlgApp *)(((LPCREATESTRUCT)lParam)->lpCreateParams);
  529.         SetWindowLongPtr(hwnd, GWLP_USERDATA, (LRESULT)web);
  530.         break;
  531.     case WM_CREATE:
  532.         return web->OnCreate(hwnd);
  533.     case WM_DESTROY:
  534.         return web->OnDestroy();
  535.     case WM_ACTIVATE:
  536.         return web->OnActivate(wParam);
  537.     case WM_PAINT:
  538.         return web->OnPaint((HDC)wParam);
  539.     case WM_ERASEBKGND:
  540.         return web->OnEraseBkgnd((HDC)wParam);
  541.     case WM_MOUSEMOVE:
  542.         return web->OnMouseMove(LOWORD(lParam), HIWORD(lParam), (DWORD)wParam);
  543.     case WM_SETCURSOR:
  544.         return web->OnSetCursor((HWND)wParam, LOWORD(lParam), HIWORD(lParam));
  545.     case WM_COMMAND:
  546.     case WM_SYSCOMMAND:
  547.         if ( web->OnCommand(LOWORD(wParam)) )
  548.             return 0;
  549.         break;
  550.     case WM_DRAWITEM:
  551.         return web->OnDrawItem((UINT)wParam, (LPDRAWITEMSTRUCT)lParam);
  552.     case WM_QUERYNEWPALETTE:
  553.         return web->OnQueryNewPalette();
  554.     case WM_PALETTECHANGED:
  555.         return web->OnPaletteChanged((HWND)wParam);
  556.     }
  557.     
  558.     return DefWindowProc(hwnd, msg, wParam, lParam);
  559. }
  560. /**
  561. *  This method is called on WM_CREATE.
  562. *
  563. *  @param  hwnd    Window handle for the application.
  564. *
  565. *  @return         No return value.
  566. */
  567. LRESULT CDlgApp::OnCreate(HWND hwnd)
  568. {
  569.     int i;
  570.     m_hwnd = hwnd;
  571.     // Create one window for each button.  These windows will get resized and moved
  572.     // after we call AdjustToFitFonts.
  573.     for (i=0; i<m_DataSrc.m_iItems; i++)
  574.     {
  575.         hwnd = CreateWindowEx(
  576.                 0,
  577.                 TEXT("BUTTON"),
  578.                 m_DataSrc.m_data[i].GetMenuName(),
  579.                 WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_PUSHBUTTON|BS_MULTILINE|BS_OWNERDRAW,
  580.                 0,0,0,0,
  581.                 m_hwnd,
  582.                 NULL,
  583.                 m_hInstance,
  584.                 NULL );
  585.         SetWindowLongPtr(hwnd, GWLP_ID, IDM_MENUITEM1 + i);
  586.         SendMessage(hwnd, WM_SETFONT, (WPARAM)m_hfontMenu, 0);
  587.         g_fnBtnProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)ButtonWndProc);
  588.     }
  589.     hwnd = GetDlgItem(m_hwnd,IDM_MENUITEM4);
  590.     SetFocus(hwnd);
  591.     // Create two static text controls, one for the title and one for the body.  The
  592.     // only purpose these serve is to allow screen readers to read the correct text.
  593.     return 0;
  594. }
  595. /**
  596. *  This method handles the WM_DESTROY message.
  597. *
  598. *  @return         No return value.
  599. */
  600. LRESULT CDlgApp::OnDestroy()
  601. {
  602.     // Shutdown the data source.
  603.     m_DataSrc.Uninit(0);
  604.     // ensure this is the last message we care about
  605.     SetWindowLongPtr(m_hwnd, GWLP_USERDATA, 0);
  606.     
  607.     PostQuitMessage(0);
  608.     return 0;
  609. }
  610. LRESULT CDlgApp::OnActivate(WPARAM wParam)
  611. {
  612.     // Note: we are actually checking two things, the HIWORD(wParam) must be zero (i.e. window not minimized)
  613.     // and the LOWORD(wParam) must be one of the following two values (i.e. window being activated):
  614.     if ( WA_ACTIVE == wParam || WA_CLICKACTIVE == wParam)
  615.     {
  616.         HWND hwnd;
  617.         hwnd = GetDlgItem(m_hwnd,IDM_MENUITEM4);
  618.         SetFocus(hwnd);
  619.     }
  620.     return 0;
  621. }
  622. /**
  623. *  This method handles the WM_PAINT message.
  624. *
  625. *  @return         No return value.
  626. */
  627. LRESULT CDlgApp::OnPaint(HDC hdc)
  628. {
  629.     PAINTSTRUCT ps;
  630.     BeginPaint(m_hwnd,&ps);
  631.     EndPaint(m_hwnd,&ps);
  632.     return 0;
  633. }
  634. // winver 0x0500 definition
  635. #ifndef NOMIRRORBITMAP
  636. #define NOMIRRORBITMAP            (DWORD)0x80000000
  637. #endif // NOMIRRORBITMAP
  638. #ifndef LAYOUT_RTL
  639. #define LAYOUT_RTL                              0x00000001 // Right to left
  640. #endif // LAYOUT_RTL
  641. /**
  642. *  This method handles the WM_ERASEBKGND message.
  643. *
  644. *  @return         No return value.
  645. */
  646. LRESULT CDlgApp::OnEraseBkgnd(HDC hdc)
  647. {
  648.     RECT rect;
  649.     HPALETTE hpalOld = NULL;
  650.     if ( m_hpal )
  651.     {
  652.         hpalOld = SelectPalette(hdc, m_hpal, FALSE);
  653.         RealizePalette(hdc);
  654.     }
  655.     SetMapMode(hdc, MM_TEXT);
  656.     SetBkMode(hdc, TRANSPARENT);
  657.     // Draw the branding area:
  658.     DWORD dwRop  = SRCCOPY;
  659.     if(Mirror_GetLayout(hdc) & LAYOUT_RTL)
  660.     {
  661.         dwRop |= NOMIRRORBITMAP;
  662.     }
  663.     BitBlt( hdc,0,0,m_cxClient,c_cyBranding, m_hdcTop,0,0, dwRop );
  664.     // Draw the left pane:
  665.     // fill rect for background below menu items
  666.     rect.left = 0;
  667.     rect.top = m_cyBottomOfMenuItems;
  668.     rect.right = m_cxLeftPanel;
  669.     rect.bottom = m_cyClient;
  670.     FillRect(hdc, &rect, m_hbrMenuItem);
  671.     // Draw the right pane:
  672.     // fill right pane's background
  673.     rect.left = m_cxLeftPanel;
  674.     rect.top = c_cyBranding;
  675.     rect.right = m_cxClient;
  676.     rect.bottom = m_cyClient;
  677.     FillRect(hdc, &rect, m_hbrRightPanel);
  678.     // draw background image
  679.     if ( !m_bHighContrast )
  680.     {
  681.         int iImgIndex;
  682.         if ( -1 == g_iSelectedItem )
  683.         {
  684.             iImgIndex = 0;
  685.         }
  686.         else
  687.         {
  688.             iImgIndex = m_DataSrc.m_data[g_iSelectedItem].GetImgIndex();
  689.         }
  690.         HDC hdcBkgnd = CreateCompatibleDC(hdc);
  691.         Mirror_SetLayout(hdcBkgnd, 0);        
  692.         HBITMAP hbmOld = (HBITMAP)SelectObject(hdcBkgnd, m_aBkgnd[iImgIndex].hbm);
  693.         BitBlt( hdc,
  694.                 m_cxClient-m_aBkgnd[iImgIndex].cx,
  695.                 m_cyClient-m_aBkgnd[iImgIndex].cy,
  696.                 m_aBkgnd[iImgIndex].cx,
  697.                 m_aBkgnd[iImgIndex].cy,
  698.                 hdcBkgnd,0,0, SRCCOPY );
  699.         SelectObject(hdcBkgnd,hbmOld);
  700.         DeleteDC(hdcBkgnd);
  701.     }
  702.     // draw title text
  703.     rect.top = c_cyBranding + c_cyBarToTitlePadding;
  704.     rect.left = m_cxLeftPanel + c_cxRightPanelPadding;
  705.     rect.right = m_cxClient - c_cxRightPanelPadding;
  706.     rect.bottom = m_cyClient;
  707.     HFONT hfontOld = (HFONT)SelectObject(hdc,m_hfontTitle);
  708.     SetTextColor(hdc,m_crTitleText);
  709.     rect.top += c_cyTitleToBodyPadding +
  710.         DrawText(hdc,((-1==g_iSelectedItem)?m_szDefTitle:m_DataSrc[g_iSelectedItem].GetTitle()),-1,&rect,DT_NOCLIP|DT_WORDBREAK);
  711.     // draw body text
  712.     SelectObject(hdc,m_hfontBody);
  713.     SetTextColor(hdc,m_crNormalText);
  714.     DrawText(hdc,((-1==g_iSelectedItem)?m_szDefBody:m_DataSrc[g_iSelectedItem].GetDescription()),-1,&rect,DT_NOCLIP|DT_WORDBREAK);
  715.     // restore the DC to its original value
  716.     SelectObject(hdc,hfontOld);
  717.     if(hpalOld)
  718.         SelectPalette(hdc, hpalOld, FALSE);
  719.     return TRUE;
  720. }
  721. LRESULT CDlgApp::OnMouseMove(int x, int y, DWORD fwKeys)
  722. {
  723.     // if a task is running then we leave the menu item for that task selected until that
  724.     // task finishes running instead of doing the following logic.
  725.     if ( !g_bTaskRunning )
  726.     {
  727.         // Didn't move over one of our menu items, select the default text.
  728.         if (-1 != g_iSelectedItem)
  729.         {
  730.             g_iSelectedItem = -1;
  731.             HWND hwnd = GetDlgItem(m_hwnd,IDM_MENUITEM4);
  732.             SetFocus(hwnd);
  733.             InvalidateRect(m_hwnd, NULL, TRUE);
  734.         }
  735.     }
  736.     return 0;
  737. }
  738. LRESULT CDlgApp::OnSetCursor(HWND hwnd, int nHittest, int wMouseMsg)
  739. {
  740.     if ( !g_bTaskRunning )
  741.     {
  742.         if ( hwnd != m_hwnd )
  743.         {
  744.             SetCursor(m_hcurHand);
  745.             return TRUE;
  746.         }
  747.     }
  748.     SetCursor(LoadCursor(NULL,IDC_ARROW));
  749.     return TRUE;
  750. }
  751. LRESULT CDlgApp::OnCommand(int wID)
  752. {
  753.     int iNewSelectedItem = g_iSelectedItem;
  754.     bool bRun = false;
  755.     switch(wID)
  756.     {
  757.     case IDM_MENUITEM1:
  758.     case IDM_MENUITEM2:
  759.     case IDM_MENUITEM3:
  760.     case IDM_MENUITEM4:
  761.     case IDM_MENUITEM5:
  762.     case IDM_MENUITEM6:
  763.     case IDM_MENUITEM7:
  764.         bRun = true;
  765.         g_iSelectedItem = wID - IDM_MENUITEM1;
  766.         // g_iSelectedItem should be a real menu item now, but just to make sure:
  767.         ASSERT( (g_iSelectedItem < m_DataSrc.m_iItems) && (g_iSelectedItem >= 0) );
  768.         break;
  769.     default:
  770.         // When we hit this then this isn't a message we care about.  We return FALSE which
  771.         // tells our WndProc to call DefWndProc which makes everything happy.
  772.         return FALSE;
  773.     }
  774.     if ( !g_bTaskRunning )
  775.     {
  776.         if ( iNewSelectedItem != g_iSelectedItem )
  777.         {
  778.             InvalidateRect(m_hwnd, NULL, TRUE);
  779.         }
  780.         if ( bRun )
  781.         {
  782.             g_bTaskRunning = TRUE;
  783.             m_DataSrc.Invoke( g_iSelectedItem, m_hwnd );
  784.             g_bTaskRunning = FALSE;
  785.         }
  786.     }
  787.     else
  788.     {
  789.         // currently the only commands that are valid while another task is running are
  790.         // IDM_SHOWCHECK and anything that goes to the default handler above.  Everything
  791.         // else will come to here and cause a message beep
  792.         MessageBeep(0);
  793.     }
  794.     return TRUE;
  795. }
  796. LRESULT CDlgApp::OnQueryNewPalette()
  797. {
  798.     if ( m_hpal )
  799.     {
  800.         HDC hdc = GetDC(m_hwnd);
  801.         HPALETTE hpalOld = SelectPalette(hdc, m_hpal, FALSE);
  802.         UnrealizeObject(m_hpal);
  803.         RealizePalette(hdc);
  804.         InvalidateRect(m_hwnd, NULL, TRUE);
  805.         UpdateWindow(m_hwnd);
  806.         if(hpalOld)
  807.             SelectPalette(hdc, hpalOld, FALSE);
  808.         ReleaseDC(m_hwnd, hdc);
  809.         return TRUE;
  810.     }
  811.     return FALSE;
  812. }
  813. LRESULT CDlgApp::OnPaletteChanged(HWND hwnd)
  814. {
  815.     if ( m_hpal && (m_hwnd != hwnd) )
  816.     {
  817.         HDC hdc = GetDC(m_hwnd);
  818.         HPALETTE hpalOld = SelectPalette(hdc, m_hpal, FALSE);
  819.         RealizePalette(hdc);
  820.         UpdateColors(hdc);
  821.         if (hpalOld)
  822.             SelectPalette(hdc, hpalOld, FALSE);
  823.         ReleaseDC(m_hwnd, hdc);
  824.     }
  825.     return TRUE;
  826. }
  827. LRESULT CDlgApp::OnDrawItem(UINT iCtlID, LPDRAWITEMSTRUCT pdis)
  828. {
  829.     RECT rect = pdis->rcItem;
  830.     int i = iCtlID - IDM_MENUITEM1;
  831.     HPALETTE hpalOld = NULL;
  832.     ASSERT( (i < m_DataSrc.m_iItems) && (i >= 0) );
  833.     if ( m_hpal )
  834.     {
  835.         hpalOld = SelectPalette(pdis->hDC, m_hpal, FALSE);
  836.         RealizePalette(pdis->hDC);
  837.     }
  838.     rect.bottom -= c_cyMenuItemSpacing;
  839.     FillRect( pdis->hDC, &rect, (pdis->itemState & ODS_FOCUS)?m_hbrRightPanel:m_hbrMenuItem );
  840.     
  841.     rect.top = rect.bottom;
  842.     rect.bottom += c_cyMenuItemSpacing;
  843.     FillRect( pdis->hDC, &rect, m_hbrMenuBorder );
  844.     rect.top = pdis->rcItem.top;
  845.     // draw menu item text
  846.     rect.left += c_cxMenuItemPadding;
  847.     rect.top += c_cyMenuItemPadding;
  848.     rect.right -= c_cxMenuItemPadding;
  849.     SetBkMode(pdis->hDC, TRANSPARENT);
  850.     SetTextColor(
  851.             pdis->hDC,
  852.             ((m_DataSrc[i].m_dwFlags&WF_ALTERNATECOLOR)?m_crSelectedText:
  853.             ((pdis->itemState & ODS_FOCUS)?m_crNormalText:m_crMenuText)));
  854.     DrawText(pdis->hDC,m_DataSrc[i].GetMenuName(),-1,&rect,DT_NOCLIP|DT_WORDBREAK);
  855.     if ( pdis->itemState & ODS_FOCUS )
  856.     {
  857.         if ( m_bHighContrast )
  858.         {
  859.             rect.left -= 1;
  860.             rect.top -= 2;
  861.             rect.right += 1;
  862.             rect.bottom -= 2;
  863.             DrawFocusRect(pdis->hDC,&rect);
  864.         }
  865.     }
  866.     if ( hpalOld )
  867.     {
  868.         SelectPalette(pdis->hDC, hpalOld, FALSE);
  869.     }
  870.     return TRUE;
  871. }
  872. LONG_PTR CALLBACK ButtonWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  873. {
  874.     CDlgApp *web = (CDlgApp *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  875.     switch (uMsg)
  876.     {
  877.     case WM_MOUSEMOVE:
  878.         if ( !g_bTaskRunning )
  879.         {
  880.             int iID = ((int)GetWindowLongPtr(hwnd, GWLP_ID)) - IDM_MENUITEM1;
  881.             
  882.             if ( iID != g_iSelectedItem )
  883.             {
  884.                 SetFocus(hwnd);
  885.             }
  886.         }
  887.         break;
  888.     case WM_SETFOCUS:
  889.         if ( !g_bTaskRunning )
  890.         {
  891.             int iID = ((int)GetWindowLongPtr(hwnd, GWLP_ID)) - IDM_MENUITEM1;
  892.             
  893.             if ( iID != g_iSelectedItem )
  894.             {
  895.                 g_iSelectedItem = iID;
  896.                 InvalidateRect(GetParent(hwnd), NULL, TRUE);
  897.                 ASSERT( (g_iSelectedItem < 7) && (g_iSelectedItem >= 0) );
  898.             }
  899.         }
  900.         break;
  901.     }
  902.     return CallWindowProc(g_fnBtnProc, hwnd, uMsg, wParam, lParam);
  903. }