Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1125 lines
32 KiB

//////////////////////////////////////////////////////////////////////////
//
// 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 <windows.h>
#include <commctrl.h>
#include <shlwapi.h> // for string compare functions
#include "debug.h"
#include <tchar.h>
#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<m_DataSrc.m_iItems; i++ )
{
rect.left = m_cxLeftPanel+c_cxRightPanelPadding;
rect.top = c_cyBranding + c_cyBarToTitlePadding;
rect.right = m_cxClient-c_cxRightPanelPadding;
SelectObject(hdc,m_hfontTitle);
TCHAR* pszTitle = m_DataSrc[i].GetTitle();
DrawText(hdc,pszTitle,-1,&rect,DT_CALCRECT|DT_WORDBREAK); // this computes rcLargestTitle.bottom
rect.left = m_cxLeftPanel+c_cxRightPanelPadding;
rect.top = rect.bottom + c_cyTitleToBodyPadding;
rect.right = m_cxClient-c_cxRightPanelPadding;
SelectObject(hdc,m_hfontBody);
DrawText(hdc,m_DataSrc[i].GetDescription(),-1,&rect,DT_CALCRECT|DT_WORDBREAK); // this computes rcLargestBody.bottom
if ( rect.bottom > 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<m_iItems; i++)
{
HWND hwnd = CreateWindowEx(
0,
TEXT("BUTTON"),
m_DataSrc.m_data[i].GetMenuName(),
WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_PUSHBUTTON|BS_MULTILINE|BS_OWNERDRAW,
0,0,0,0,
m_hwnd,
NULL,
m_hInstance,
NULL );
if ( hwnd )
{
SetWindowLongPtr(hwnd, GWLP_ID, IDM_MENUITEM1 + i);
SendMessage(hwnd, WM_SETFONT, (WPARAM)m_hfontMenu, 0);
g_fnBtnProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)ButtonWndProc);
SetFocus(GetDlgItem(m_hwnd,IDM_MENUITEM1+i));
}
}
// We created the window with zero size, now we adjust that size to take into
// acount the selected font size, etc.
AdjustToFitFonts();
// Create two static text controls, one for the title and one for the body. The
// only purpose these serve is to allow screen readers to read the correct text.
}
void CDlgApp::_DestroyMenu()
{
for (int i=0; i<m_iItems; i++)
{
DestroyWindow(GetDlgItem(m_hwnd, IDM_MENUITEM1+i));
}
m_iItems = 0;
}
/**
* This method handles the WM_DESTROY message.
*
* @return No return value.
*/
LRESULT CDlgApp::OnDestroy()
{
// Shutdown the data source.
m_DataSrc.Uninit(0);
// ensure this is the last message we care about
SetWindowLongPtr(m_hwnd, GWLP_USERDATA, 0);
PostQuitMessage(0);
return 0;
}
LRESULT CDlgApp::OnActivate(WPARAM wParam)
{
// Note: we are actually checking two things, the HIWORD(wParam) must be zero (i.e. window not minimized)
// and the LOWORD(wParam) must be one of the following two values (i.e. window being activated):
if ( WA_ACTIVE == wParam || WA_CLICKACTIVE == wParam)
{
HWND hwnd;
hwnd = GetDlgItem(m_hwnd,IDM_MENUITEM4);
SetFocus(hwnd);
}
return 0;
}
/**
* This method handles the WM_PAINT message.
*
* @return No return value.
*/
LRESULT CDlgApp::OnPaint(HDC hdc)
{
PAINTSTRUCT ps;
BeginPaint(m_hwnd,&ps);
EndPaint(m_hwnd,&ps);
return 0;
}
// winver 0x0500 definition
#ifndef NOMIRRORBITMAP
#define NOMIRRORBITMAP (DWORD)0x80000000
#endif // NOMIRRORBITMAP
#ifndef LAYOUT_RTL
#define LAYOUT_RTL 0x00000001 // Right to left
#endif // LAYOUT_RTL
/**
* This method handles the WM_ERASEBKGND message.
*
* @return No return value.
*/
LRESULT CDlgApp::OnEraseBkgnd(HDC hdc)
{
RECT rect;
HPALETTE hpalOld = NULL;
if ( m_hpal )
{
hpalOld = SelectPalette(hdc, m_hpal, FALSE);
RealizePalette(hdc);
}
SetMapMode(hdc, MM_TEXT);
SetBkMode(hdc, TRANSPARENT);
// Draw the branding area:
DWORD dwRop = SRCCOPY;
if(Mirror_GetLayout(hdc) & LAYOUT_RTL)
{
dwRop |= NOMIRRORBITMAP;
}
BitBlt( hdc,0,0,m_cxClient,c_cyBranding, m_hdcTop,0,0, dwRop );
// Draw the left pane:
// fill rect for background below menu items
rect.left = 0;
rect.top = m_cyBottomOfMenuItems;
rect.right = m_cxLeftPanel;
rect.bottom = m_cyClient;
FillRect(hdc, &rect, m_hbrMenuItem);
// Draw the right pane:
// fill right pane's background
rect.left = m_cxLeftPanel;
rect.top = c_cyBranding;
rect.right = m_cxClient;
rect.bottom = m_cyClient;
FillRect(hdc, &rect, m_hbrRightPanel);
// draw background image
if ( !m_bHighContrast )
{
int iImgIndex;
if ( -1 == g_iSelectedItem )
{
iImgIndex = 0;
}
else
{
iImgIndex = m_DataSrc.m_data[g_iSelectedItem].GetImgIndex();
}
HDC hdcBkgnd = CreateCompatibleDC(hdc);
if (hdcBkgnd)
{
Mirror_SetLayout(hdcBkgnd, 0);
HBITMAP hbmOld = (HBITMAP)SelectObject(hdcBkgnd, m_aBkgnd[iImgIndex].hbm);
BitBlt( hdc,
m_cxClient-m_aBkgnd[iImgIndex].cx,
m_cyClient-m_aBkgnd[iImgIndex].cy,
m_aBkgnd[iImgIndex].cx,
m_aBkgnd[iImgIndex].cy,
hdcBkgnd,0,0, SRCCOPY );
SelectObject(hdcBkgnd,hbmOld);
DeleteDC(hdcBkgnd);
}
}
// draw title text
rect.top = c_cyBranding + c_cyBarToTitlePadding;
rect.left = m_cxLeftPanel + c_cxRightPanelPadding;
rect.right = m_cxClient - c_cxRightPanelPadding;
rect.bottom = m_cyClient;
HFONT hfontOld = (HFONT)SelectObject(hdc,m_hfontTitle);
SetTextColor(hdc,m_crTitleText);
rect.top += c_cyTitleToBodyPadding +
DrawText(hdc,((-1==g_iSelectedItem)?m_szDefTitle:m_DataSrc[g_iSelectedItem].GetTitle()),-1,&rect,DT_NOCLIP|DT_WORDBREAK);
// draw body text
SelectObject(hdc,m_hfontBody);
SetTextColor(hdc,m_crNormalText);
DrawText(hdc,((-1==g_iSelectedItem)?m_szDefBody:m_DataSrc[g_iSelectedItem].GetDescription()),-1,&rect,DT_NOCLIP|DT_WORDBREAK);
// restore the DC to its original value
SelectObject(hdc,hfontOld);
if(hpalOld)
SelectPalette(hdc, hpalOld, FALSE);
return TRUE;
}
LRESULT CDlgApp::OnMouseMove(int x, int y, DWORD fwKeys)
{
// if a task is running then we leave the menu item for that task selected until that
// task finishes running instead of doing the following logic.
if ( !g_bTaskRunning )
{
// Didn't move over one of our menu items, select the default text.
if (-1 != g_iSelectedItem)
{
g_iSelectedItem = -1;
HWND hwnd = GetDlgItem(m_hwnd,IDM_MENUITEM4);
SetFocus(hwnd);
InvalidateRect(m_hwnd, NULL, TRUE);
}
}
return 0;
}
LRESULT CDlgApp::OnSetCursor(HWND hwnd, int nHittest, int wMouseMsg)
{
if ( !g_bTaskRunning )
{
if ( hwnd != m_hwnd )
{
SetCursor(m_hcurHand);
return TRUE;
}
}
SetCursor(LoadCursor(NULL,IDC_ARROW));
return TRUE;
}
LRESULT CDlgApp::_OnChangeScreen()
{
_DestroyMenu();
_CreateMenu();
InvalidateRect(m_hwnd, NULL, TRUE);
return TRUE;
}
LRESULT CDlgApp::OnCommand(int wID)
{
int iNewSelectedItem = g_iSelectedItem;
bool bRun = false;
switch(wID)
{
case IDM_MENUITEM1:
case IDM_MENUITEM2:
case IDM_MENUITEM3:
case IDM_MENUITEM4:
case IDM_MENUITEM5:
case IDM_MENUITEM6:
case IDM_MENUITEM7:
bRun = true;
g_iSelectedItem = wID - IDM_MENUITEM1;
// g_iSelectedItem should be a real menu item now, but just to make sure:
ASSERT( (g_iSelectedItem < m_DataSrc.m_iItems) && (g_iSelectedItem >= 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);
}