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

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