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.

819 lines
22 KiB

  1. // TaskFrame.cpp : Implementation of CTaskUIApp and DLL registration.
  2. #include "stdafx.h"
  3. #include "TaskFrame.h"
  4. #include "cbsc.h"
  5. /////////////////////////////////////////////////////////////////////////////
  6. //
  7. //
  8. // Create and initialize an instance of the task frame.
  9. //
  10. HRESULT
  11. CTaskFrame::CreateInstance( // [static]
  12. IPropertyBag *pPropertyBag,
  13. ITaskPageFactory *pPageFactory,
  14. CComObject<CTaskFrame> **ppFrameOut
  15. )
  16. {
  17. ASSERT(NULL != pPropertyBag);
  18. ASSERT(NULL != pPageFactory);
  19. ASSERT(!IsBadWritePtr(ppFrameOut, sizeof(*ppFrameOut)));
  20. CComObject<CTaskFrame> *pFrame;
  21. HRESULT hr = CComObject<CTaskFrame>::CreateInstance(&pFrame);
  22. if (SUCCEEDED(hr))
  23. {
  24. hr = pFrame->_Init(pPropertyBag, pPageFactory);
  25. if (SUCCEEDED(hr))
  26. {
  27. pFrame->AddRef();
  28. }
  29. else
  30. {
  31. delete pFrame;
  32. pFrame = NULL;
  33. }
  34. }
  35. *ppFrameOut = pFrame;
  36. ASSERT(SUCCEEDED(hr) || NULL == *ppFrameOut);
  37. return hr;
  38. }
  39. CTaskFrame::CTaskFrame()
  40. : m_pPropertyBag(NULL), m_pPageFactory(NULL), m_pUIParser(NULL),
  41. m_hwndNavBar(NULL), m_hwndStatusBar(NULL),
  42. m_himlNBDef(NULL), m_himlNBHot(NULL), m_pbmWatermark(NULL)
  43. {
  44. SetRectEmpty(&m_rcPage);
  45. m_ptMinSize.x = m_ptMinSize.y = 0;
  46. // DUI initialization
  47. InitThread();
  48. }
  49. CTaskFrame::~CTaskFrame()
  50. {
  51. Close();
  52. // m_dpaHistory is self-destructing
  53. if (m_himlNBDef)
  54. ImageList_Destroy(m_himlNBDef);
  55. if (m_himlNBHot)
  56. ImageList_Destroy(m_himlNBHot);
  57. ATOMICRELEASE(m_pPropertyBag);
  58. ATOMICRELEASE(m_pPageFactory);
  59. delete m_pbmWatermark;
  60. delete m_pUIParser;
  61. // DUI shutdown
  62. UnInitThread();
  63. }
  64. void CALLBACK TaskUIParseError(LPCWSTR pszError, LPCWSTR pszToken, int dLine)
  65. {
  66. //#if DBG
  67. #if 1
  68. WCHAR buf[201];
  69. if (dLine != -1)
  70. swprintf(buf, L"%s '%s' at line %d", pszError, pszToken, dLine);
  71. else
  72. swprintf(buf, L"%s '%s'", pszError, pszToken);
  73. MessageBoxW(NULL, buf, L"Parser Message", MB_OK);
  74. #endif
  75. }
  76. HRESULT CTaskFrame::_Init(IPropertyBag* pBag, ITaskPageFactory* pPageFact)
  77. {
  78. HRESULT hr;
  79. if (!pBag || !pPageFact)
  80. return E_INVALIDARG;
  81. m_pPropertyBag = pBag;
  82. m_pPropertyBag->AddRef();
  83. m_pPageFactory = pPageFact;
  84. m_pPageFactory->AddRef();
  85. m_iCurrentPage = -1;
  86. hr = Parser::Create(IDR_TASKUI_UI, _Module.GetResourceInstance(), TaskUIParseError, &m_pUIParser);
  87. if (FAILED(hr))
  88. return hr;
  89. if (m_pUIParser->WasParseError())
  90. return E_FAIL;
  91. CWndClassInfo& wci = GetWndClassInfo();
  92. if (!wci.m_atom)
  93. {
  94. // Modify wndclass here if necessary
  95. wci.m_wc.style &= ~(CS_HREDRAW | CS_VREDRAW);
  96. }
  97. return S_OK;
  98. }
  99. HWND CTaskFrame::CreateFrameWindow(HWND hwndOwner, UINT nID, LPVOID pParam)
  100. {
  101. if (NULL == m_pPropertyBag)
  102. return NULL;
  103. // Register the AtlAxHost window class, etc.
  104. AtlAxWinInit();
  105. // Default window styles & dimensions
  106. DWORD dwWndStyle = GetWndStyle(0); // WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS
  107. DWORD dwWndExStyle = GetWndExStyle(0); // WS_EX_APPWINDOW | WS_EX_WINDOWEDGE
  108. RECT rcFrame = CWindow::rcDefault; // { CW_USEDEFAULT, CW_USEDEFAULT, 0, 0 }
  109. CComVariant var;
  110. // Get the initial window dimensions from the property bag
  111. if (SUCCEEDED(_ReadProp(TS_PROP_WIDTH, VT_I4, var)))
  112. {
  113. rcFrame.right = rcFrame.left + var.lVal;
  114. }
  115. if (SUCCEEDED(_ReadProp(TS_PROP_HEIGHT, VT_I4, var)))
  116. {
  117. rcFrame.bottom = rcFrame.top + var.lVal;
  118. }
  119. // See if we're resizable. Default is TRUE;
  120. m_bResizable = TRUE;
  121. if (SUCCEEDED(_ReadProp(TS_PROP_RESIZABLE, VT_BOOL, var)))
  122. {
  123. m_bResizable = (VARIANT_TRUE == var.boolVal);
  124. }
  125. if (m_bResizable)
  126. {
  127. // Resizable: get minimum dimensions if provided
  128. if (SUCCEEDED(_ReadProp(TS_PROP_MINWIDTH, VT_I4, var)))
  129. {
  130. m_ptMinSize.x = var.lVal;
  131. }
  132. if (SUCCEEDED(_ReadProp(TS_PROP_MINHEIGHT, VT_I4, var)))
  133. {
  134. m_ptMinSize.y = var.lVal;
  135. }
  136. }
  137. else
  138. {
  139. // No resize: switch to a simple border style and don't allow maximize
  140. dwWndStyle = (dwWndStyle & ~(WS_THICKFRAME | WS_MAXIMIZEBOX)) | WS_BORDER;
  141. }
  142. // See if we're modeless. Default is FALSE (modal).
  143. BOOL bModeless = FALSE;
  144. if (SUCCEEDED(_ReadProp(TS_PROP_MODELESS, VT_BOOL, var)))
  145. {
  146. bModeless = (VARIANT_TRUE == var.boolVal);
  147. }
  148. if (!bModeless)
  149. {
  150. // Modal
  151. if (!m_bResizable)
  152. dwWndExStyle |= WS_EX_DLGMODALFRAME;
  153. // If not a top-level window, disallow minimize
  154. if (hwndOwner)
  155. dwWndStyle &= ~WS_MINIMIZEBOX;
  156. }
  157. // Get the application graphics
  158. if (SUCCEEDED(_ReadProp(TS_PROP_WATERMARK, VT_BSTR, var)))
  159. {
  160. CComPtr<IStream> spStream;
  161. HRESULT hr = BindToURL(var.bstrVal, &spStream);
  162. if (SUCCEEDED(hr))
  163. {
  164. // Create GDI+ Bitmap from stream
  165. delete m_pbmWatermark;
  166. m_pbmWatermark = Bitmap::FromStream(spStream);
  167. if (NULL != m_pbmWatermark && (Ok != m_pbmWatermark->GetLastStatus()))
  168. {
  169. delete m_pbmWatermark;
  170. m_pbmWatermark = NULL;
  171. }
  172. // Later, when creating a page, set m_pbmWatermark as content of the
  173. // "Picture" element
  174. }
  175. }
  176. // Get the window title from the property bag
  177. CComVariant varTitle;
  178. if (FAILED(_ReadProp(TS_PROP_TITLE, VT_BSTR, varTitle)))
  179. {
  180. // Use NULL for no title
  181. varTitle.bstrVal = NULL;
  182. }
  183. dwWndExStyle |= WS_EX_CONTROLPARENT;
  184. return Create(hwndOwner, rcFrame, varTitle.bstrVal, dwWndStyle, dwWndExStyle, nID, pParam);
  185. }
  186. STDMETHODIMP CTaskFrame::ShowPage(REFCLSID rclsidNewPage, BOOL bTrimHistory)
  187. {
  188. HRESULT hr;
  189. int iPage;
  190. TaskPage *pSavePage = NULL;
  191. if (!m_dpaHistory.IsValid())
  192. return E_OUTOFMEMORY;
  193. hr = S_OK;
  194. // m_iCurrentPage = -1 should only occur when Count = 0
  195. ASSERT(-1 != m_iCurrentPage || 0 == m_dpaHistory.Count());
  196. // If we don't have any pages, then we can't trim the history
  197. if (-1 == m_iCurrentPage)
  198. bTrimHistory = FALSE;
  199. // First remove any forward pages from the history.
  200. // Note that we never remove the first page (index 0).
  201. for (iPage = m_dpaHistory.Count() - 1; iPage > 0 && iPage > m_iCurrentPage; iPage--)
  202. {
  203. TaskPage *pPage = m_dpaHistory[iPage];
  204. ASSERT(NULL != pPage);
  205. // Optimization: if we are navigating forward and the next page
  206. // is the page we want, go directly there and reinitialize it.
  207. if (!bTrimHistory && iPage == m_iCurrentPage+1 && rclsidNewPage == pPage->GetID())
  208. {
  209. hr = _ActivatePage(iPage, TRUE);
  210. if (SUCCEEDED(hr))
  211. {
  212. _SetNavBarState();
  213. return hr;
  214. }
  215. }
  216. m_dpaHistory.Remove(iPage);
  217. // TODO OPTIMIZATION: cache the page
  218. _DestroyPage(pPage);
  219. }
  220. // Either m_iCurrentPage = -1 and Count = 0, or
  221. // m_iCurrentPage is the last page (Count-1) since
  222. // we just truncated the history.
  223. ASSERT(m_iCurrentPage + 1 == m_dpaHistory.Count());
  224. iPage = m_iCurrentPage;
  225. _DeactivateCurrentPage(); // sets m_iCurrentPage to -1
  226. if (bTrimHistory)
  227. {
  228. // Can't delete this guy right right away since he's still
  229. // processing messages (this is the page we just deactivated).
  230. pSavePage = m_dpaHistory[iPage];
  231. // Work backwards looking for rclsidNewPage, trimming as we go.
  232. // Note that we never remove the first page (index 0).
  233. while (0 < iPage)
  234. {
  235. TaskPage *pPage = m_dpaHistory[iPage];
  236. ASSERT(NULL != pPage);
  237. if (rclsidNewPage == pPage->GetID())
  238. break;
  239. m_dpaHistory.Remove(iPage);
  240. if (pSavePage != pPage)
  241. {
  242. // TODO OPTIMIZATION: cache the page
  243. _DestroyPage(pPage);
  244. }
  245. --iPage;
  246. }
  247. }
  248. // Create a new page if necessary
  249. TaskPage *pNewPage = NULL;
  250. TaskPage *pCurrentPage = (-1 == iPage) ? NULL : m_dpaHistory[iPage];
  251. if (NULL == pCurrentPage || rclsidNewPage != pCurrentPage->GetID())
  252. {
  253. hr = _CreatePage(rclsidNewPage, &pNewPage);
  254. if (SUCCEEDED(hr))
  255. {
  256. iPage = m_dpaHistory.Append(pNewPage);
  257. }
  258. }
  259. if (FAILED(hr) || -1 == iPage)
  260. {
  261. // Something bad happened, try to activate the home page
  262. if (0 < m_dpaHistory.Count())
  263. {
  264. _ActivatePage(0);
  265. }
  266. if (NULL != pNewPage)
  267. {
  268. _DestroyPage(pNewPage);
  269. }
  270. }
  271. else
  272. {
  273. // Show the page
  274. hr = _ActivatePage(iPage, NULL != pNewPage ? FALSE : TRUE);
  275. }
  276. _SetNavBarState();
  277. if (pSavePage)
  278. {
  279. // TODO: need to free this guy later (currently leaked)
  280. }
  281. return hr;
  282. }
  283. STDMETHODIMP CTaskFrame::Back(UINT cPages)
  284. {
  285. HRESULT hr;
  286. if (-1 == m_iCurrentPage || 0 == m_dpaHistory.Count())
  287. return E_UNEXPECTED;
  288. hr = S_FALSE;
  289. if (0 < m_iCurrentPage)
  290. {
  291. int iNewPage;
  292. ASSERT(m_iCurrentPage < m_dpaHistory.Count());
  293. if (0 == cPages)
  294. iNewPage = m_iCurrentPage - 1;
  295. else if (cPages > (UINT)m_iCurrentPage)
  296. iNewPage = 0;
  297. else // cPages > 0 && cPages <= m_iCurrentPage
  298. iNewPage = m_iCurrentPage - cPages;
  299. hr = _ActivatePage(iNewPage);
  300. }
  301. _SetNavBarState();
  302. return hr;
  303. }
  304. STDMETHODIMP CTaskFrame::Forward()
  305. {
  306. HRESULT hr;
  307. if (-1 == m_iCurrentPage || 0 == m_dpaHistory.Count())
  308. return E_UNEXPECTED;
  309. hr = S_FALSE;
  310. int iNewPage = m_iCurrentPage + 1;
  311. if (iNewPage < m_dpaHistory.Count())
  312. {
  313. hr = _ActivatePage(iNewPage);
  314. }
  315. _SetNavBarState();
  316. return hr;
  317. }
  318. STDMETHODIMP CTaskFrame::Home()
  319. {
  320. if (-1 == m_iCurrentPage || 0 == m_dpaHistory.Count())
  321. return E_UNEXPECTED;
  322. HRESULT hr = _ActivatePage(0);
  323. _SetNavBarState();
  324. return hr;
  325. }
  326. STDMETHODIMP CTaskFrame::SetStatusText(LPCWSTR pszText)
  327. {
  328. if (NULL == m_hwndStatusBar)
  329. return E_UNEXPECTED;
  330. ::SendMessageW(m_hwndStatusBar, SB_SETTEXT, SB_SIMPLEID, (LPARAM)pszText);
  331. return S_OK;
  332. }
  333. HRESULT CTaskFrame::_ReadProp(LPCWSTR pszProp, VARTYPE vt, CComVariant& var)
  334. {
  335. HRESULT hr;
  336. ASSERT(NULL != m_pPropertyBag);
  337. var.Clear();
  338. hr = m_pPropertyBag->Read(pszProp, &var, NULL);
  339. if (SUCCEEDED(hr))
  340. {
  341. hr = var.ChangeType(vt);
  342. }
  343. return hr;
  344. }
  345. LRESULT CTaskFrame::_OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  346. {
  347. BOOL bNavBar;
  348. BOOL bStatusBar;
  349. CComVariant var;
  350. ASSERT(NULL != m_pPropertyBag);
  351. // See if we're supposed to show the NavBar. Default is TRUE.
  352. bNavBar = TRUE;
  353. if (SUCCEEDED(_ReadProp(TS_PROP_NAVBAR, VT_BOOL, var)))
  354. {
  355. bNavBar = (VARIANT_TRUE == var.boolVal);
  356. }
  357. if (bNavBar)
  358. {
  359. _CreateNavBar();
  360. }
  361. // See if we're supposed to show a status bar. Default is FALSE.
  362. bStatusBar = FALSE;
  363. if (SUCCEEDED(_ReadProp(TS_PROP_STATUSBAR, VT_BOOL, var)))
  364. {
  365. bStatusBar = (VARIANT_TRUE == var.boolVal);
  366. }
  367. if (bStatusBar)
  368. {
  369. DWORD dwStyle = WS_CHILD | WS_VISIBLE | CCS_BOTTOM;
  370. if (m_bResizable)
  371. dwStyle |= SBARS_SIZEGRIP;
  372. m_hwndStatusBar = CreateStatusWindowW(dwStyle, NULL, m_hWnd, IDC_STATUSBAR);
  373. }
  374. // Force m_rcPage to be calculated
  375. LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
  376. _OnSize(WM_SIZE, SIZE_RESTORED, MAKELONG(LOWORD(pcs->cx),LOWORD(pcs->cy)), bHandled);
  377. return 0;
  378. }
  379. LRESULT CTaskFrame::_OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  380. {
  381. if (SIZE_RESTORED == wParam || SIZE_MAXIMIZED == wParam)
  382. {
  383. GetClientRect(&m_rcPage);
  384. if (m_hwndNavBar)
  385. {
  386. RECT rc;
  387. ::SendMessageW(m_hwndNavBar, uMsg, wParam, lParam);
  388. ::GetWindowRect(m_hwndNavBar, &rc);
  389. m_rcPage.top += (rc.bottom - rc.top);
  390. }
  391. if (m_hwndStatusBar)
  392. {
  393. RECT rc;
  394. ::SendMessageW(m_hwndStatusBar, uMsg, wParam, lParam);
  395. ::GetWindowRect(m_hwndStatusBar, &rc);
  396. m_rcPage.bottom -= (rc.bottom - rc.top);
  397. }
  398. // At this point, m_rcPage represents the remaining usable client
  399. // area between the toolbar and statusbar.
  400. if (-1 != m_iCurrentPage)
  401. {
  402. // Resize the current page. Other pages will be resized
  403. // as necessary when we show them.
  404. _SyncPageRect(m_dpaHistory[m_iCurrentPage]);
  405. }
  406. }
  407. return 0;
  408. }
  409. LRESULT CTaskFrame::_OnTBGetInfoTip(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
  410. {
  411. LPNMTBGETINFOTIP pgit = (LPNMTBGETINFOTIP)pnmh;
  412. ::LoadStringW(_Module.GetResourceInstance(), pgit->iItem, pgit->pszText, pgit->cchTextMax);
  413. return 0;
  414. }
  415. LRESULT CTaskFrame::_OnTBCustomDraw(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
  416. {
  417. LPNMCUSTOMDRAW pcd = (LPNMCUSTOMDRAW)pnmh;
  418. switch (pcd->dwDrawStage)
  419. {
  420. case CDDS_PREPAINT:
  421. return CDRF_NOTIFYITEMERASE;
  422. case CDDS_PREERASE:
  423. FillRect(pcd->hdc, &pcd->rc, GetSysColorBrush(COLOR_3DFACE));
  424. break;
  425. }
  426. return CDRF_DODEFAULT;
  427. }
  428. LRESULT CTaskFrame::_OnAppCommand(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  429. {
  430. switch (GET_APPCOMMAND_LPARAM(lParam))
  431. {
  432. case APPCOMMAND_BROWSER_BACKWARD:
  433. Back(1);
  434. break;
  435. case APPCOMMAND_BROWSER_FORWARD:
  436. Forward();
  437. break;
  438. case APPCOMMAND_BROWSER_HOME:
  439. Home();
  440. break;
  441. default:
  442. bHandled = FALSE;
  443. break;
  444. }
  445. return 0;
  446. }
  447. LRESULT CTaskFrame::_OnGetMinMaxInfo(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
  448. {
  449. ((LPMINMAXINFO)lParam)->ptMinTrackSize = m_ptMinSize;
  450. return 0;
  451. }
  452. #define NAVBAR_CX 16
  453. void CTaskFrame::_CreateNavBar()
  454. {
  455. HINSTANCE hInst = _Module.GetResourceInstance();
  456. const DWORD dwStyle = WS_CHILD | WS_VISIBLE | CCS_TOP | TBSTYLE_FLAT | TBSTYLE_LIST | TBSTYLE_CUSTOMERASE | TBSTYLE_TOOLTIPS;
  457. // Create the NavBar toolbar control
  458. m_hwndNavBar = CreateWindowExW(TBSTYLE_EX_MIXEDBUTTONS /*| TBSTYLE_EX_DOUBLEBUFFER*/,
  459. TOOLBARCLASSNAME,
  460. NULL,
  461. dwStyle,
  462. 0, 0, 0, 0,
  463. m_hWnd,
  464. (HMENU)IDC_NAVBAR,
  465. hInst,
  466. NULL);
  467. if (m_hwndNavBar)
  468. {
  469. ::SendMessageW(m_hwndNavBar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
  470. int idBmp = IDB_NAVBAR;
  471. if (SHGetCurColorRes() > 8)
  472. idBmp += (IDB_NAVBARHICOLOR - IDB_NAVBAR);
  473. m_himlNBDef = ImageList_LoadImageW(hInst,
  474. MAKEINTRESOURCE(idBmp),
  475. NAVBAR_CX,
  476. 0,
  477. CLR_DEFAULT,
  478. IMAGE_BITMAP,
  479. LR_CREATEDIBSECTION);
  480. if (m_himlNBDef)
  481. ::SendMessageW(m_hwndNavBar, TB_SETIMAGELIST, 0, (LPARAM)m_himlNBDef);
  482. m_himlNBHot = ImageList_LoadImageW(hInst,
  483. MAKEINTRESOURCE(idBmp+1),
  484. NAVBAR_CX,
  485. 0,
  486. CLR_DEFAULT,
  487. IMAGE_BITMAP,
  488. LR_CREATEDIBSECTION);
  489. if (m_himlNBHot)
  490. ::SendMessageW(m_hwndNavBar, TB_SETHOTIMAGELIST, 0, (LPARAM)m_himlNBHot);
  491. if (!m_himlNBDef && !m_himlNBHot)
  492. {
  493. // Must be serious low memory or other resource problems.
  494. // There's no point having a toolbar without any images.
  495. ::DestroyWindow(m_hwndNavBar);
  496. m_hwndNavBar = NULL;
  497. }
  498. else
  499. {
  500. TCHAR szBack[64];
  501. TBBUTTON rgButtons[] =
  502. {
  503. {0, ID_BACK, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, {0}, 0, (INT_PTR)szBack},
  504. {1, ID_FORWARD, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, {0}, 0, 0},
  505. {2, ID_HOME, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, {0}, 0, 0},
  506. };
  507. ::LoadStringW(hInst, ID_BACK, szBack, ARRAYSIZE(szBack));
  508. ::SendMessageW(m_hwndNavBar, TB_ADDBUTTONSW, ARRAYSIZE(rgButtons), (LPARAM)rgButtons);
  509. // This happens in _OnSize
  510. //::SendMessageW(m_hwndNavBar, TB_AUTOSIZE, 0, 0);
  511. }
  512. _SetNavBarState();
  513. }
  514. }
  515. void CTaskFrame::_SetNavBarState()
  516. {
  517. if (m_hwndNavBar)
  518. {
  519. ::SendMessage(m_hwndNavBar, TB_ENABLEBUTTON, ID_BACK, MAKELONG((m_iCurrentPage > 0), 0));
  520. ::SendMessage(m_hwndNavBar, TB_ENABLEBUTTON, ID_HOME, MAKELONG((m_iCurrentPage > 0), 0));
  521. ::SendMessage(m_hwndNavBar, TB_ENABLEBUTTON, ID_FORWARD, MAKELONG((m_iCurrentPage < m_dpaHistory.Count() - 1), 0));
  522. }
  523. }
  524. HRESULT CTaskFrame::_CreatePage(REFCLSID rclsidPage, TaskPage **ppPage)
  525. {
  526. HRESULT hr;
  527. ASSERT(NULL != ppPage);
  528. *ppPage = NULL;
  529. if (NULL == m_pPageFactory || NULL == m_pUIParser)
  530. return E_UNEXPECTED;
  531. // Get this page's ITaskPage interface from the App
  532. CComPtr<ITaskPage> spTaskPage;
  533. hr = m_pPageFactory->CreatePage(rclsidPage, IID_ITaskPage, (void**)&spTaskPage.p);
  534. if (S_OK == hr)
  535. {
  536. // Give the ITaskPage our ITaskFrame interface
  537. CComQIPtr<ITaskFrame> spThis(this);
  538. if (spThis)
  539. spTaskPage->SetFrame(spThis);
  540. // Create an HWNDElement to contain and layout the page content
  541. TaskPage *pNewPage;
  542. hr = TaskPage::Create(rclsidPage, m_hWnd, &pNewPage);
  543. if (SUCCEEDED(hr))
  544. {
  545. Element* pe; // dummy
  546. // Fill contents from markup using substitution
  547. hr = m_pUIParser->CreateElement(L"main", pNewPage, &pe);
  548. if (SUCCEEDED(hr))
  549. {
  550. Element::StartDefer();
  551. _SyncPageRect(pNewPage);
  552. // Some examples of ways to add graphics to the page
  553. Element* pe = pNewPage->FindDescendent(StrToID(L"Picture"));
  554. //pe->SetContentGraphic(L"C:\\windows\\ua_bkgnd.bmp", GRAPHIC_EntireAlpha, 64);
  555. //pe->SetContentGraphic(L"C:\\windows\\ua_bkgnd.bmp", GRAPHIC_TransColorAuto);
  556. //Value* pv = Value::CreateGraphic(MAKEINTRESOURCE(IDB_BACKGROUND), GRAPHIC_TransColorAuto, 0, 0, 0, _Module.GetResourceInstance());
  557. //pe->SetValue(Element::ContentProp, PI_Local, pv);
  558. //pv->Release();
  559. #ifdef GADGET_ENABLE_GDIPLUS
  560. if (NULL != m_pbmWatermark)
  561. {
  562. Value* pv = Value::CreateGraphic(m_pbmWatermark);
  563. pe->SetValue(Element::ContentProp, PI_Local, pv);
  564. pv->Release();
  565. }
  566. #endif
  567. hr = pNewPage->CreateContent(spTaskPage);
  568. Element::EndDefer();
  569. }
  570. if (SUCCEEDED(hr))
  571. {
  572. *ppPage = pNewPage;
  573. }
  574. else
  575. {
  576. _DestroyPage(pNewPage);
  577. }
  578. }
  579. }
  580. return hr;
  581. }
  582. HRESULT CTaskFrame::_ActivatePage(int iPage, BOOL bInit)
  583. {
  584. HRESULT hr = S_OK;
  585. ASSERT(m_dpaHistory.IsValid());
  586. ASSERT(0 < m_dpaHistory.Count());
  587. ASSERT(iPage >= 0 && iPage < m_dpaHistory.Count());
  588. TaskPage *pPage = m_dpaHistory[iPage];
  589. ASSERT(NULL != pPage);
  590. if (bInit)
  591. {
  592. hr = pPage->Reinitialize();
  593. if (FAILED(hr))
  594. {
  595. // Can't reinitialize? Create a new instance instead.
  596. TaskPage *pNewPage = NULL;
  597. hr = _CreatePage(pPage->GetID(), &pNewPage);
  598. if (SUCCEEDED(hr))
  599. {
  600. m_dpaHistory.Set(iPage, pNewPage);
  601. _DestroyPage(pPage);
  602. pPage = pNewPage;
  603. }
  604. }
  605. }
  606. if (SUCCEEDED(hr))
  607. {
  608. if (m_iCurrentPage != iPage)
  609. {
  610. _DeactivateCurrentPage();
  611. }
  612. // In case we were resized since we last showed this page
  613. _SyncPageRect(pPage);
  614. m_iCurrentPage = iPage;
  615. ::ShowWindow(pPage->GetHWND(), SW_SHOW);
  616. ::SetFocus(pPage->GetHWND());
  617. }
  618. return hr;
  619. }
  620. HRESULT CTaskFrame::_DeactivateCurrentPage()
  621. {
  622. if (-1 != m_iCurrentPage)
  623. {
  624. ASSERT(m_dpaHistory.IsValid());
  625. ASSERT(m_iCurrentPage >= 0 && m_iCurrentPage < m_dpaHistory.Count());
  626. TaskPage *pPage = m_dpaHistory[m_iCurrentPage];
  627. ASSERT(NULL != pPage);
  628. m_iCurrentPage = -1;
  629. ::ShowWindow(pPage->GetHWND(), SW_HIDE);
  630. }
  631. return S_OK;
  632. }
  633. void CTaskFrame::_SyncPageRect(TaskPage* pPage)
  634. {
  635. if (NULL != pPage)
  636. {
  637. Element::StartDefer();
  638. pPage->SetX(m_rcPage.left);
  639. pPage->SetY(m_rcPage.top);
  640. pPage->SetWidth(m_rcPage.right-m_rcPage.left);
  641. pPage->SetHeight(m_rcPage.bottom-m_rcPage.top);
  642. Element::EndDefer();
  643. }
  644. }
  645. void CTaskFrame::_DestroyPage(TaskPage* pPage)
  646. {
  647. if (NULL != pPage)
  648. {
  649. HWND hwndPage = pPage->GetHWND();
  650. if (NULL != hwndPage && ::IsWindow(hwndPage))
  651. {
  652. // This causes pPage to be deleted
  653. ::DestroyWindow(hwndPage);
  654. }
  655. else
  656. {
  657. // If the window exists, this would not destroy it, so only
  658. // do this when there is no window.
  659. delete pPage;
  660. }
  661. }
  662. }