////////////////////////////////////////////////////////////////////////// // // dlgapp.cpp // // This file contains the main entry point into the application and // the implementation of the CDlgApp class. // // (C) Copyright 1997 by Microsoft Corporation. All rights reserved. // ////////////////////////////////////////////////////////////////////////// #include #include #include // for string compare functions #include "debug.h" #include #pragma hdrstop #include "dlgapp.h" #include "resource.h" #define WINDOW_CLASS TEXT("_BerksWin2kAutorunApp_") ////////////////////////////////////////////////////////////////////////// // Global Data ////////////////////////////////////////////////////////////////////////// bool g_bTaskRunning = false; // true when we have a running task open int g_iSelectedItem = -1; // WNDPROC g_fnBtnProc = NULL; // the window proc for a button. ////////////////////////////////////////////////////////////////////////// // Prototypes ////////////////////////////////////////////////////////////////////////// LONG_PTR CALLBACK ButtonWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); ////////////////////////////////////////////////////////////////////////// // Metrics // Our metrics are constants that never change. All sizes are in pixels (as per the spec): ////////////////////////////////////////////////////////////////////////// #define c_cyLogoImage 87 // height of the branding image. #define c_cyFadeBar 6 // height of the color fade bar #define c_cyBranding (c_cyLogoImage+c_cyFadeBar) // height of top region that contains our branding images and the fade bar #define c_cxCheckTextLeftEdge 29 // width from left edge for checkbox text label #define c_cxMenuItemPadding 10 // width from left of menu item to left of text and right of text to right of menu item #define c_cyMenuItemPadding 5 // height from top of menu item to top of text and bottom of text to bottom of menu item #define c_cyMenuItemSpacing 1 // gap from top of one menu item to bottom of next item #define c_cyBarToTitlePadding 12 // vertical padding from botton of fade bar to top of title text #define c_cyTitleToBodyPadding 6 // vertical padding from bottom of title text to top of body text #define c_cyBodyToBottomPadding 53 // vertical padding from body of body text to bottom of client area #define c_cxRightPanelPadding 16 // generic horizontal padding used on both edges of the right pane // Code to ensure only one instance of a particular window is running HANDLE CheckForOtherInstance(HINSTANCE hInstance) { TCHAR szCaption[128]; HANDLE hMutex; LoadString(hInstance, IDS_TITLE, szCaption, 128); // We don't want to launch autorun when winnt32 is running. The standard way // to check for this is the following mutex, which winnt32 creates: hMutex = OpenMutex( MUTEX_ALL_ACCESS, FALSE, TEXT("Winnt32 Is Running") ); if ( hMutex ) { // The mutex exists, this means winnt32 is running so we shouldn't. // REVIEW: Should we try to findwindow and activate winnt32? CloseHandle( hMutex ); return 0; } // We create a named mutex with our window caption just as a way to check // if we are already running autorun.exe. Only if we are the first to // create the mutex do we continue. hMutex = CreateMutex (NULL, FALSE, szCaption); if ( !hMutex ) { // failed to create the mutex return 0; } else if (GetLastError() == ERROR_ALREADY_EXISTS) { // Mutex created but by someone else, activate that window HWND hwnd = FindWindow( WINDOW_CLASS, szCaption ); SetForegroundWindow(hwnd); CloseHandle(hMutex); return 0; } // we are the first return hMutex; } /** * This function is the main entry point into our application. * * @return int Exit code. */ int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin, int nShowCmd ) { HANDLE hMutex = CheckForOtherInstance(hInstance); if ( hMutex ) { CDlgApp dlgapp; dlgapp.Register(hInstance); if ( dlgapp.InitializeData() ) { dlgapp.Create(nShowCmd); dlgapp.MessageLoop(); } CloseHandle(hMutex); } return 0; } typedef DWORD (WINAPI *PFNGETLAYOUT)(HDC); // gdi32!GetLayout typedef DWORD (WINAPI *PFNSETLAYOUT)(HDC, DWORD); // gdi32!SetLayout /** * This function gets the DC layout. * * @return DWORD DC layout. */ DWORD Mirror_GetLayout( HDC hdc ) { DWORD dwRet=0; static PFNGETLAYOUT pfnGetLayout=NULL; static BOOL bTriedToLoadBefore = FALSE; if( (NULL == pfnGetLayout) && !bTriedToLoadBefore) { HMODULE hmod = GetModuleHandleA("GDI32"); if( hmod ) pfnGetLayout = (PFNGETLAYOUT)GetProcAddress(hmod, "GetLayout"); bTriedToLoadBefore = TRUE; } if( pfnGetLayout ) dwRet = pfnGetLayout( hdc ); return dwRet; } /** * This function sets the DC layout. * * @return DWORD old DC layout. */ DWORD Mirror_SetLayout( HDC hdc , DWORD dwLayout ) { DWORD dwRet=0; static PFNSETLAYOUT pfnSetLayout=NULL; static BOOL bTriedToLoadBefore = FALSE; if( (NULL == pfnSetLayout) && !bTriedToLoadBefore) { HMODULE hmod = GetModuleHandleA("GDI32"); if( hmod ) pfnSetLayout = (PFNSETLAYOUT)GetProcAddress(hmod, "SetLayout"); bTriedToLoadBefore = TRUE; } if( pfnSetLayout ) dwRet = pfnSetLayout( hdc , dwLayout ); return dwRet; } /** * This method is our contstructor for our class. It initialize all * of the instance data. */ CDlgApp::CDlgApp() { m_hInstance = NULL; m_hwnd = NULL; m_bHighContrast = false; m_hfontTitle = NULL; m_hfontMenu = NULL; m_hfontBody = NULL; m_hbrMenuItem = NULL; m_hbrMenuBorder = NULL; m_hbrRightPanel = NULL; m_szDefTitle[0] = NULL; m_szDefBody[0] = NULL; // In theory, all of these metrics could be adjusted to resize the window. Resizing wouldn't // effect the paddings and spacings so these are defined above as constants. In the real // world we are only resizing vertically to adjust for oversized content. These are more to // allow future expansion. m_cxClient = 478; // width of the client area m_cyClient = 322; // This is currently the only metirc we actually adjust. m_cxLeftPanel = 179; // width of the panel that contains the menu items. m_hdcTop = NULL; m_hcurHand = NULL; m_bLowColor = false; m_iColors = -1; m_hpal = NULL; } CDlgApp::~CDlgApp() { DeleteObject(m_hfontTitle); DeleteObject(m_hfontMenu); DeleteObject(m_hfontBody); DeleteObject(m_hbrMenuItem); DeleteObject(m_hbrMenuBorder); DeleteObject(m_hbrRightPanel); DeleteDC(m_hdcTop); } /** * This method will register our window class for the application. * * @param hInstance The application instance handle. * * @return No return value. */ void CDlgApp::Register(HINSTANCE hInstance) { WNDCLASS wndclass; m_hInstance = hInstance; wndclass.style = CS_OWNDC; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WEBAPP)); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = NULL; wndclass.lpszMenuName = NULL; wndclass.lpszClassName = WINDOW_CLASS; RegisterClass(&wndclass); } /** * This method will initialize the data object. * * @return No return value. */ bool CDlgApp::InitializeData() { // Determine if we should use Direct Animaiton to display our intro graphics. // We don't use DA on slow machines, machines with less than 256 color displays, // and hydra terminals. For everything else we use DA. HWND hwnd = GetDesktopWindow(); HDC hdc = GetDC( hwnd ); m_iColors = GetDeviceCaps( hdc, NUMCOLORS ); m_bLowColor = ((m_iColors != -1) && (m_iColors <= 256)); if ( m_bLowColor ) { m_hpal = CreateHalftonePalette(hdc); } ReleaseDC( hwnd, hdc ); // Initialize the items from the INI file. if ( !m_DataSrc.Init() ) { // this is a sign from the data source that we should exit return false; } // Are we in accesibility mode? This call won't work on NT 4.0 because this flag wasn't known. HIGHCONTRAST hc; hc.cbSize = sizeof(HIGHCONTRAST); hc.dwFlags = 0; // avoid random result should SPI fail if ( SystemParametersInfo( SPI_GETHIGHCONTRAST, sizeof(HIGHCONTRAST), &hc, 0 ) ) { m_bHighContrast = ( hc.dwFlags & HCF_HIGHCONTRASTON ); } else { // we must be on NT 4.0 or below. Just assume we aren't in high contrast mode. ASSERT( false == m_bHighContrast ); } // Set the color table based on our HighContrast mode setting. SetColorTable(); // create the fonts that we need to use. CreateWelcomeFonts(hdc); // create the image for the top region CreateBrandingBanner(); // we pre load the background images so they draw more quickly. LoadBkgndImages(); // load the resource strings that we always need LoadString( m_hInstance, IDS_DEFTITLE, m_szDefTitle, ARRAYSIZE(m_szDefTitle) ); LoadString( m_hInstance, IDS_DEFBODY, m_szDefBody, ARRAYSIZE(m_szDefBody) ); m_hcurHand = LoadCursor( m_hInstance, MAKEINTRESOURCE(IDC_BRHAND) ); return true; } BOOL CDlgApp::SetColorTable() { if ( m_bHighContrast ) { // set to high contrast values m_hbrMenuItem = (HBRUSH)(COLOR_BTNFACE+1); m_hbrMenuBorder = (HBRUSH)(COLOR_BTNSHADOW+1); m_hbrRightPanel = (HBRUSH)(COLOR_WINDOW+1); m_crMenuText = GetSysColor(COLOR_BTNTEXT); m_crNormalText = GetSysColor(COLOR_WINDOWTEXT); m_crTitleText = m_crNormalText; m_crSelectedText= GetSysColor(COLOR_GRAYTEXT); } else { m_crMenuText = RGB(0,0,0); m_crNormalText = RGB(0,0,0); m_crSelectedText= RGB(0x80, 0x80, 0x80); // default value for COLOR_GRAYTEXTs m_crTitleText = RGB(51,102,153); m_hbrRightPanel = (HBRUSH)GetStockObject( WHITE_BRUSH ); if ( m_bLowColor ) { if (m_iColors <= 16) { // Set to colors that work well in 16 color mode. HBITMAP hbmp; hbmp = (HBITMAP)LoadImage(m_hInstance, MAKEINTRESOURCE(IDB_16MENU), IMAGE_BITMAP, 0,0, LR_CREATEDIBSECTION); if (hbmp) { m_hbrMenuItem = CreatePatternBrush(hbmp); DeleteObject(hbmp); } else m_hbrMenuItem = (HBRUSH)(COLOR_BTNFACE+1); hbmp = (HBITMAP)LoadImage(m_hInstance, MAKEINTRESOURCE(IDB_16BORDER), IMAGE_BITMAP, 0,0, LR_CREATEDIBSECTION); if (hbmp) { m_hbrMenuBorder = CreatePatternBrush( hbmp ); DeleteObject(hbmp); } else m_hbrMenuBorder = (HBRUSH)(COLOR_BTNSHADOW+1); // // if ( WeAreRunningOnWin95 ) // m_crMenuText = RGB(255,255,255); } else { // Set to colors that work well in 256 color mode. Use colors from the halftone palette. HBITMAP hbmp; hbmp = (HBITMAP)LoadImage(m_hInstance, MAKEINTRESOURCE(IDB_256MENU), IMAGE_BITMAP, 0,0, LR_CREATEDIBSECTION); if (hbmp) { m_hbrMenuItem = CreatePatternBrush(hbmp); DeleteObject(hbmp); } else m_hbrMenuItem = (HBRUSH)(COLOR_BTNFACE+1); hbmp = (HBITMAP)LoadImage(m_hInstance, MAKEINTRESOURCE(IDB_256BORDER), IMAGE_BITMAP, 0,0, LR_CREATEDIBSECTION); if (hbmp) { m_hbrMenuBorder = CreatePatternBrush( hbmp ); DeleteObject(hbmp); } else m_hbrMenuBorder = (HBRUSH)(COLOR_BTNSHADOW+1); } } else { m_hbrMenuItem = CreateSolidBrush( RGB(166,202,240) ); m_hbrMenuBorder = CreateSolidBrush( m_crTitleText ); } } return TRUE; } BOOL CDlgApp::CreateWelcomeFonts(HDC hdc) { LOGFONT lf; CHARSETINFO csInfo; TCHAR szFontSize[6]; memset(&lf,0,sizeof(lf)); lf.lfWeight = FW_BOLD; lf.lfOutPrecision = OUT_DEFAULT_PRECIS; lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; lf.lfQuality = DEFAULT_QUALITY; lf.lfPitchAndFamily = DEFAULT_PITCH|FF_SWISS; LoadString( m_hInstance, IDS_FONTFACE, lf.lfFaceName, ARRAYSIZE(lf.lfFaceName) ); // Set charset if (TranslateCharsetInfo((DWORD*)IntToPtr(GetACP()), &csInfo, TCI_SRCCODEPAGE) == 0) { csInfo.ciCharset = 0; } lf.lfCharSet = (BYTE)csInfo.ciCharset; // TODO: If user has accesibility large fonts turned on then scale the font sizes. LoadString( m_hInstance, IDS_CYTITLEFONT, szFontSize, ARRAYSIZE(szFontSize) ); lf.lfHeight = -_ttoi(szFontSize); m_hfontTitle = CreateFontIndirect(&lf); LoadString( m_hInstance, IDS_CYMENUITEMFONT, szFontSize, ARRAYSIZE(szFontSize) ); lf.lfHeight = -_ttoi(szFontSize); m_hfontMenu = CreateFontIndirect(&lf); lf.lfWeight = FW_NORMAL; LoadString( m_hInstance, IDS_CYBODYFONT, szFontSize, ARRAYSIZE(szFontSize) ); lf.lfHeight = -_ttoi(szFontSize); m_hfontBody = CreateFontIndirect(&lf); return TRUE; } BOOL CDlgApp::CreateBrandingBanner() { HBITMAP hbm; int iBitmap; m_hdcTop = CreateCompatibleDC(NULL); if ( m_bLowColor && (m_iColors <= 16) ) { iBitmap = IDB_BANNER16; } else { iBitmap = IDB_BANNER; } hbm = (HBITMAP)LoadImage(m_hInstance, MAKEINTRESOURCE(iBitmap), IMAGE_BITMAP, 0,0, LR_CREATEDIBSECTION); SelectObject( m_hdcTop, hbm ); return TRUE; } BOOL CDlgApp::LoadBkgndImages() { BITMAP bm; for (int i=0; i<4; i++) { m_aBkgnd[i].hbm = (HBITMAP)LoadImage(m_hInstance, MAKEINTRESOURCE(IDB_BKGND0+i), IMAGE_BITMAP, 0,0, LR_CREATEDIBSECTION); // REVIEW: are all these the same size? If yes, skip this part and use a constant: GetObject(m_aBkgnd[i].hbm,sizeof(bm),&bm); m_aBkgnd[i].cx = bm.bmWidth; m_aBkgnd[i].cy = bm.bmHeight; } return TRUE; } BOOL CDlgApp::AdjustToFitFonts() { RECT rect; int cyLowestBodyPoint = 0; HDC hdc = GetDC(m_hwnd); // now based on the users prefered font size we allow these sizes to adjust slightly HFONT hfontOld = (HFONT)SelectObject(hdc,m_hfontTitle); int iMenuItemTop = c_cyBranding; for (int i=0; i cyLowestBodyPoint ) cyLowestBodyPoint = rect.bottom; rect.left = c_cxMenuItemPadding; rect.top = iMenuItemTop+c_cyMenuItemPadding; rect.right = m_cxLeftPanel-c_cxMenuItemPadding; SelectObject(hdc,m_hfontMenu); DrawText(hdc,m_DataSrc[i].GetMenuName(),-1,&rect,DT_CALCRECT|DT_WORDBREAK); HWND hwnd; hwnd = GetDlgItem(m_hwnd, IDM_MENUITEM1+i); SetWindowPos( hwnd, NULL, 0, iMenuItemTop, m_cxLeftPanel, rect.bottom + c_cyMenuItemPadding + 1 + c_cyMenuItemSpacing - iMenuItemTop, // +1 to improve centering (due to drop letters) SWP_NOZORDER ); iMenuItemTop = rect.bottom + c_cyMenuItemPadding + 1 + c_cyMenuItemSpacing; } // store the bottom most menu point. Needed for drawing the background rect later. m_cyBottomOfMenuItems = iMenuItemTop; // restore the DC to its original value SelectObject(hdc,hfontOld); return TRUE; } /** * This method will create the application window. * * @return No return value. */ void CDlgApp::Create(int nCmdShow) { // // load the window title from the resource. // TCHAR szTitle[MAX_PATH]; #ifdef BUILD_OPK_VERSION LoadString(m_hInstance, IDS_TITLE_OPK, szTitle, MAX_PATH); #else LoadString(m_hInstance, IDS_TITLE, szTitle, MAX_PATH); #endif DWORD dwStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_CLIPCHILDREN; m_hwnd = CreateWindowEx( WS_EX_CONTROLPARENT, WINDOW_CLASS, szTitle, dwStyle, 0, 0, 0, 0, NULL, NULL, m_hInstance, this); // set the client area to a fixed size and center the window on screen RECT rect; rect.left = 0; rect.top = 0; rect.right = m_cxClient; rect.bottom = m_cyClient; AdjustWindowRect( &rect, dwStyle, FALSE ); rect.right -= rect.left; rect.bottom -= rect.top; RECT rcDesktop; SystemParametersInfo(SPI_GETWORKAREA,0, &rcDesktop, FALSE); rect.left = (rcDesktop.left+rcDesktop.right-rect.right)/2; rect.top = (rcDesktop.top+rcDesktop.bottom-rect.bottom)/2; SetWindowPos(m_hwnd, HWND_TOP, rect.left, rect.top, rect.right, rect.bottom, 0); ShowWindow(m_hwnd, nCmdShow); m_DataSrc.ShowSplashScreen( m_hwnd ); InvalidateRect(m_hwnd, NULL, TRUE); UpdateWindow(m_hwnd); } /** * This method is our application message loop. * * @return No return value. */ void CDlgApp::MessageLoop() { MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { // IsDialogMessage cannot understand the concept of ownerdraw default pushbuttons. It treats // these attributes as mutually exclusive. As a result, we handle this ourselves. We want // whatever control has focus to act as the default pushbutton. if ( (WM_KEYDOWN == msg.message) && (VK_RETURN == msg.wParam) ) { HWND hwndFocus = GetFocus(); if ( hwndFocus ) { SendMessage(m_hwnd, WM_COMMAND, MAKELONG(GetDlgCtrlID(hwndFocus), BN_CLICKED), (LPARAM)hwndFocus); } continue; } if ( IsDialogMessage(m_hwnd, &msg) ) continue; TranslateMessage(&msg); DispatchMessage(&msg); } } /** * This is the window procedure for the container application. It is used * to deal with all messages to our window. * * @param hwnd Window handle. * @param msg The window message. * @param wParam Window Parameter. * @param lParam Window Parameter. * * @return LRESULT */ LRESULT CALLBACK CDlgApp::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { CDlgApp *web = (CDlgApp *)GetWindowLongPtr(hwnd, GWLP_USERDATA); switch(msg) { case WM_NCCREATE: web = (CDlgApp *)(((LPCREATESTRUCT)lParam)->lpCreateParams); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LRESULT)web); break; case WM_CREATE: return web->OnCreate(hwnd); case WM_DESTROY: return web->OnDestroy(); case WM_ACTIVATE: return web->OnActivate(wParam); case WM_PAINT: return web->OnPaint((HDC)wParam); case WM_ERASEBKGND: return web->OnEraseBkgnd((HDC)wParam); case WM_MOUSEMOVE: return web->OnMouseMove(LOWORD(lParam), HIWORD(lParam), (DWORD)wParam); case WM_SETCURSOR: return web->OnSetCursor((HWND)wParam, LOWORD(lParam), HIWORD(lParam)); case WM_COMMAND: case WM_SYSCOMMAND: if ( web->OnCommand(LOWORD(wParam)) ) return 0; break; case WM_DRAWITEM: return web->OnDrawItem((UINT)wParam, (LPDRAWITEMSTRUCT)lParam); case WM_QUERYNEWPALETTE: return web->OnQueryNewPalette(); case WM_PALETTECHANGED: return web->OnPaletteChanged((HWND)wParam); case ARM_CHANGESCREEN: return web->_OnChangeScreen(); } return DefWindowProc(hwnd, msg, wParam, lParam); } /** * This method is called on WM_CREATE. * * @param hwnd Window handle for the application. * * @return No return value. */ LRESULT CDlgApp::OnCreate(HWND hwnd) { m_hwnd = hwnd; _CreateMenu(); return 0; } void CDlgApp::_CreateMenu() { // Create one window for each button. These windows will get resized and moved // after we call AdjustToFitFonts. m_iItems = m_DataSrc.m_iItems; for (int i=0; i= 0) ); break; default: // When we hit this then this isn't a message we care about. We return FALSE which // tells our WndProc to call DefWndProc which makes everything happy. return FALSE; } if ( !g_bTaskRunning ) { if ( iNewSelectedItem != g_iSelectedItem ) { InvalidateRect(m_hwnd, NULL, TRUE); } if ( bRun ) { g_bTaskRunning = TRUE; m_DataSrc.Invoke( g_iSelectedItem, m_hwnd ); g_bTaskRunning = FALSE; } } else { // currently the only commands that are valid while another task is running are // IDM_SHOWCHECK and anything that goes to the default handler above. Everything // else will come to here and cause a message beep MessageBeep(0); } return TRUE; } LRESULT CDlgApp::OnQueryNewPalette() { if ( m_hpal ) { HDC hdc = GetDC(m_hwnd); HPALETTE hpalOld = SelectPalette(hdc, m_hpal, FALSE); UnrealizeObject(m_hpal); RealizePalette(hdc); InvalidateRect(m_hwnd, NULL, TRUE); UpdateWindow(m_hwnd); if(hpalOld) SelectPalette(hdc, hpalOld, FALSE); ReleaseDC(m_hwnd, hdc); return TRUE; } return FALSE; } LRESULT CDlgApp::OnPaletteChanged(HWND hwnd) { if ( m_hpal && (m_hwnd != hwnd) ) { HDC hdc = GetDC(m_hwnd); HPALETTE hpalOld = SelectPalette(hdc, m_hpal, FALSE); RealizePalette(hdc); UpdateColors(hdc); if (hpalOld) SelectPalette(hdc, hpalOld, FALSE); ReleaseDC(m_hwnd, hdc); } return TRUE; } LRESULT CDlgApp::OnDrawItem(UINT iCtlID, LPDRAWITEMSTRUCT pdis) { RECT rect = pdis->rcItem; int i = iCtlID - IDM_MENUITEM1; HPALETTE hpalOld = NULL; ASSERT( (i < m_DataSrc.m_iItems) && (i >= 0) ); if ( m_hpal ) { hpalOld = SelectPalette(pdis->hDC, m_hpal, FALSE); RealizePalette(pdis->hDC); } rect.bottom -= c_cyMenuItemSpacing; FillRect( pdis->hDC, &rect, (pdis->itemState & ODS_FOCUS)?m_hbrRightPanel:m_hbrMenuItem ); rect.top = rect.bottom; rect.bottom += c_cyMenuItemSpacing; FillRect( pdis->hDC, &rect, m_hbrMenuBorder ); rect.top = pdis->rcItem.top; // draw menu item text rect.left += c_cxMenuItemPadding; rect.top += c_cyMenuItemPadding; rect.right -= c_cxMenuItemPadding; SetBkMode(pdis->hDC, TRANSPARENT); SetTextColor( pdis->hDC, ((m_DataSrc[i].m_dwFlags&WF_ALTERNATECOLOR)?m_crSelectedText: ((pdis->itemState & ODS_FOCUS)?m_crNormalText:m_crMenuText))); DrawText(pdis->hDC,m_DataSrc[i].GetMenuName(),-1,&rect,DT_NOCLIP|DT_WORDBREAK); if ( pdis->itemState & ODS_FOCUS ) { if ( m_bHighContrast ) { rect.left -= 1; rect.top -= 2; rect.right += 1; rect.bottom -= 2; DrawFocusRect(pdis->hDC,&rect); } } if ( hpalOld ) { SelectPalette(pdis->hDC, hpalOld, FALSE); } return TRUE; } LONG_PTR CALLBACK ButtonWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CDlgApp *web = (CDlgApp *)GetWindowLongPtr(hwnd, GWLP_USERDATA); switch (uMsg) { case WM_MOUSEMOVE: if ( !g_bTaskRunning ) { int iID = ((int)GetWindowLongPtr(hwnd, GWLP_ID)) - IDM_MENUITEM1; if ( iID != g_iSelectedItem ) { SetFocus(hwnd); } } break; case WM_SETFOCUS: if ( !g_bTaskRunning ) { int iID = ((int)GetWindowLongPtr(hwnd, GWLP_ID)) - IDM_MENUITEM1; if ( iID != g_iSelectedItem ) { g_iSelectedItem = iID; InvalidateRect(GetParent(hwnd), NULL, TRUE); ASSERT( (g_iSelectedItem < 7) && (g_iSelectedItem >= 0) ); } } break; } return CallWindowProc(g_fnBtnProc, hwnd, uMsg, wParam, lParam); }