dlgprop.cpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567
  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10. #include "stdafx.h"
  11. #include "occimpl.h"
  12. #ifdef AFX_CORE4_SEG
  13. #pragma code_seg(AFX_CORE4_SEG)
  14. #endif
  15. #ifdef _DEBUG
  16. #undef THIS_FILE
  17. static char THIS_FILE[] = __FILE__;
  18. #endif
  19. #define new DEBUG_NEW
  20. ////////////////////////////////////////////////////////////////////////////
  21. // CPropertyPage -- one page of a tabbed dialog
  22. UINT CALLBACK
  23. AfxPropPageCallback(HWND, UINT message, LPPROPSHEETPAGE pPropPage)
  24. {
  25. switch (message)
  26. {
  27. case PSPCB_CREATE:
  28. {
  29. ASSERT(AfxIsValidAddress(pPropPage, sizeof(AFX_OLDPROPSHEETPAGE)));
  30. ASSERT(AfxIsValidAddress(pPropPage, pPropPage->dwSize));
  31. CPropertyPage* pPage =
  32. STATIC_DOWNCAST(CPropertyPage, (CObject*)pPropPage->lParam);
  33. ASSERT_VALID(pPage);
  34. TRY
  35. {
  36. AfxHookWindowCreate(pPage);
  37. }
  38. CATCH_ALL(e)
  39. {
  40. // Note: DELETE_EXCEPTION(e) not necessary
  41. return FALSE;
  42. }
  43. END_CATCH_ALL
  44. }
  45. return TRUE;
  46. case PSPCB_RELEASE:
  47. AfxUnhookWindowCreate();
  48. break;
  49. }
  50. return 0;
  51. }
  52. BEGIN_MESSAGE_MAP(CPropertyPage, CDialog)
  53. //{{AFX_MSG_MAP(CPropertyPage)
  54. ON_WM_CTLCOLOR()
  55. //}}AFX_MSG_MAP
  56. #ifndef _AFX_NO_CTL3D_SUPPORT
  57. ON_MESSAGE(WM_QUERY3DCONTROLS, OnQuery3dControls)
  58. #endif
  59. END_MESSAGE_MAP()
  60. CPropertyPage::CPropertyPage(UINT nIDTemplate, UINT nIDCaption)
  61. {
  62. ASSERT(nIDTemplate != 0);
  63. CommonConstruct(MAKEINTRESOURCE(nIDTemplate), nIDCaption);
  64. }
  65. CPropertyPage::CPropertyPage(LPCTSTR lpszTemplateName, UINT nIDCaption)
  66. {
  67. ASSERT(AfxIsValidString(lpszTemplateName));
  68. CommonConstruct(lpszTemplateName, nIDCaption);
  69. }
  70. void CPropertyPage::Construct(UINT nIDTemplate, UINT nIDCaption)
  71. {
  72. ASSERT(nIDTemplate != 0);
  73. CommonConstruct(MAKEINTRESOURCE(nIDTemplate), nIDCaption);
  74. }
  75. void CPropertyPage::Construct(LPCTSTR lpszTemplateName, UINT nIDCaption)
  76. {
  77. ASSERT(HIWORD(lpszTemplateName) == 0 ||
  78. AfxIsValidString(lpszTemplateName));
  79. CommonConstruct(lpszTemplateName, nIDCaption);
  80. }
  81. CPropertyPage::CPropertyPage()
  82. {
  83. CommonConstruct(NULL, 0);
  84. }
  85. void CPropertyPage::CommonConstruct(LPCTSTR lpszTemplateName, UINT nIDCaption)
  86. {
  87. memset(&m_psp, 0, sizeof(m_psp));
  88. m_psp.dwSize = sizeof(m_psp);
  89. m_psp.dwFlags = PSP_USECALLBACK;
  90. if (lpszTemplateName != NULL)
  91. m_psp.hInstance = AfxFindResourceHandle(lpszTemplateName, RT_DIALOG);
  92. m_psp.pszTemplate = lpszTemplateName;
  93. m_psp.pfnDlgProc = AfxDlgProc;
  94. m_psp.lParam = (LPARAM)this;
  95. m_psp.pfnCallback = AfxPropPageCallback;
  96. if (nIDCaption != 0)
  97. {
  98. VERIFY(m_strCaption.LoadString(nIDCaption));
  99. m_psp.pszTitle = m_strCaption;
  100. m_psp.dwFlags |= PSP_USETITLE;
  101. }
  102. if (AfxHelpEnabled())
  103. m_psp.dwFlags |= PSP_HASHELP;
  104. if (HIWORD(lpszTemplateName) == 0)
  105. m_nIDHelp = LOWORD((DWORD)lpszTemplateName);
  106. m_lpszTemplateName = m_psp.pszTemplate;
  107. m_bFirstSetActive = TRUE;
  108. }
  109. CPropertyPage::~CPropertyPage()
  110. {
  111. #ifndef _AFX_NO_OCC_SUPPORT
  112. Cleanup();
  113. #endif
  114. if (m_hDialogTemplate != NULL)
  115. GlobalFree(m_hDialogTemplate);
  116. }
  117. #ifndef _AFX_NO_OCC_SUPPORT
  118. void CPropertyPage::Cleanup()
  119. {
  120. COccManager* pOccManager = afxOccManager;
  121. if ((pOccManager != NULL) && (m_pOccDialogInfo != NULL))
  122. {
  123. pOccManager->PostCreateDialog(m_pOccDialogInfo);
  124. free(m_pOccDialogInfo);
  125. m_pOccDialogInfo = NULL;
  126. }
  127. }
  128. AFX_STATIC DLGTEMPLATE* AFXAPI
  129. _AfxChangePropPageFont(const DLGTEMPLATE* pTemplate, BOOL bWizard)
  130. {
  131. CString strFaceDefault;
  132. WORD wSizeDefault;
  133. if (!AfxGetPropSheetFont(strFaceDefault, wSizeDefault, bWizard))
  134. return NULL;
  135. // set font of property page to same font used by property sheet
  136. CString strFace;
  137. WORD wSize;
  138. if ((!CDialogTemplate::GetFont(pTemplate, strFace, wSize)) ||
  139. (strFace != strFaceDefault) || (wSize != wSizeDefault))
  140. {
  141. CDialogTemplate dlgTemplate(pTemplate);
  142. dlgTemplate.SetFont(strFaceDefault, wSizeDefault);
  143. return (DLGTEMPLATE*)dlgTemplate.Detach();
  144. }
  145. return NULL;
  146. }
  147. const DLGTEMPLATE* CPropertyPage::InitDialogInfo(const DLGTEMPLATE* pTemplate)
  148. {
  149. // cleanup from previous run, if any
  150. Cleanup();
  151. m_pOccDialogInfo = (_AFX_OCC_DIALOG_INFO*)malloc(
  152. sizeof(_AFX_OCC_DIALOG_INFO));
  153. return afxOccManager->PreCreateDialog(m_pOccDialogInfo, pTemplate);
  154. }
  155. #endif
  156. void CPropertyPage::PreProcessPageTemplate(PROPSHEETPAGE& psp, BOOL bWizard)
  157. {
  158. const DLGTEMPLATE* pTemplate;
  159. if (psp.dwFlags & PSP_DLGINDIRECT)
  160. {
  161. pTemplate = psp.pResource;
  162. }
  163. else
  164. {
  165. HRSRC hResource = ::FindResource(psp.hInstance,
  166. psp.pszTemplate, RT_DIALOG);
  167. HGLOBAL hTemplate = LoadResource(psp.hInstance,
  168. hResource);
  169. pTemplate = (LPCDLGTEMPLATE)LockResource(hTemplate);
  170. }
  171. ASSERT(pTemplate != NULL);
  172. #ifdef _DEBUG
  173. // WINBUG: Windows currently does not support DIALOGEX resources!
  174. // Assert that the template is *not* a DIALOGEX template.
  175. // DIALOGEX templates are not supported by the PropertySheet API.
  176. // To change a DIALOGEX template back to a DIALOG template,
  177. // remove the following:
  178. // 1. Extended styles on the dialog
  179. // 2. Help IDs on any control in the dialog
  180. // 3. Control IDs that are DWORDs
  181. // 4. Weight, italic, or charset attributes on the dialog's font
  182. if (((DLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
  183. {
  184. // it's a DIALOGEX -- we'd better check
  185. DWORD dwVersion = ::GetVersion();
  186. if (dwVersion & 0x80000000)
  187. {
  188. // it's Win95 -- versions of COMCTL32.DLL that export
  189. // a function called DllGetVersion are okay
  190. HINSTANCE hInst = LoadLibrary(_T("COMCTL32.DLL"));
  191. ASSERT(hInst != NULL);
  192. if (hInst != NULL)
  193. {
  194. FARPROC proc = GetProcAddress(hInst, "DllGetVersion");
  195. if (proc == NULL)
  196. ASSERT(FALSE);
  197. FreeLibrary(hInst);
  198. }
  199. }
  200. else if (LOBYTE(LOWORD(dwVersion)) == 3)
  201. {
  202. // it's Windows NT 3.x; we have no hope of this working
  203. ASSERT(FALSE);
  204. }
  205. }
  206. #endif // _DEBUG
  207. #ifndef _AFX_NO_OCC_SUPPORT
  208. // if the dialog could contain OLE controls, deal with them now
  209. if (afxOccManager != NULL)
  210. pTemplate = InitDialogInfo(pTemplate);
  211. #endif
  212. // set font of property page to same font used by property sheet
  213. HGLOBAL hTemplate = _AfxChangePropPageFont(pTemplate, bWizard);
  214. if (m_hDialogTemplate != NULL)
  215. {
  216. GlobalFree(m_hDialogTemplate);
  217. m_hDialogTemplate = NULL;
  218. }
  219. if (hTemplate != NULL)
  220. {
  221. pTemplate = (LPCDLGTEMPLATE)hTemplate;
  222. m_hDialogTemplate = hTemplate;
  223. }
  224. psp.pResource = pTemplate;
  225. psp.dwFlags |= PSP_DLGINDIRECT;
  226. }
  227. void CPropertyPage::CancelToClose()
  228. {
  229. ASSERT(::IsWindow(m_hWnd));
  230. ASSERT(GetParent() != NULL);
  231. GetParent()->SendMessage(PSM_CANCELTOCLOSE);
  232. }
  233. void CPropertyPage::SetModified(BOOL bChanged)
  234. {
  235. if (m_hWnd == NULL) // allowed for backward compatibility
  236. return;
  237. ASSERT(::IsWindow(m_hWnd));
  238. ASSERT(GetParent() != NULL);
  239. CWnd* pParentWnd = GetParent();
  240. if (bChanged)
  241. pParentWnd->SendMessage(PSM_CHANGED, (WPARAM)m_hWnd);
  242. else
  243. pParentWnd->SendMessage(PSM_UNCHANGED, (WPARAM)m_hWnd);
  244. }
  245. LRESULT CPropertyPage::QuerySiblings(WPARAM wParam, LPARAM lParam)
  246. {
  247. ASSERT(::IsWindow(m_hWnd));
  248. ASSERT(GetParent() != NULL);
  249. return GetParent()->SendMessage(PSM_QUERYSIBLINGS, wParam, lParam);
  250. }
  251. BOOL CPropertyPage::OnApply()
  252. {
  253. ASSERT_VALID(this);
  254. OnOK();
  255. return TRUE;
  256. }
  257. void CPropertyPage::OnReset()
  258. {
  259. ASSERT_VALID(this);
  260. OnCancel();
  261. }
  262. void CPropertyPage::OnOK()
  263. {
  264. ASSERT_VALID(this);
  265. }
  266. void CPropertyPage::OnCancel()
  267. {
  268. ASSERT_VALID(this);
  269. }
  270. BOOL CPropertyPage::OnSetActive()
  271. {
  272. ASSERT_VALID(this);
  273. if (m_bFirstSetActive)
  274. m_bFirstSetActive = FALSE;
  275. else
  276. UpdateData(FALSE);
  277. return TRUE;
  278. }
  279. BOOL CPropertyPage::OnKillActive()
  280. {
  281. ASSERT_VALID(this);
  282. if (!UpdateData())
  283. {
  284. TRACE0("UpdateData failed during page deactivation\n");
  285. return FALSE;
  286. }
  287. return TRUE;
  288. }
  289. BOOL CPropertyPage::OnQueryCancel()
  290. {
  291. return TRUE; // ok to cancel
  292. }
  293. LRESULT CPropertyPage::OnWizardBack()
  294. {
  295. return 0;
  296. }
  297. LRESULT CPropertyPage::OnWizardNext()
  298. {
  299. return 0;
  300. }
  301. BOOL CPropertyPage::OnWizardFinish()
  302. {
  303. return TRUE;
  304. }
  305. LRESULT CPropertyPage::MapWizardResult(LRESULT lToMap)
  306. {
  307. // -1 and 0 are special
  308. if (lToMap == -1 || lToMap == 0)
  309. return lToMap;
  310. // only do special stuff if MFC owns the property sheet
  311. CWnd* pParent = GetParent();
  312. CPropertySheet* pSheet = DYNAMIC_DOWNCAST(CPropertySheet, pParent);
  313. if (pSheet != NULL)
  314. {
  315. // the structures are laid out different for CPropertySheeEx
  316. CPropertySheetEx* pSheetEx = DYNAMIC_DOWNCAST(CPropertySheetEx, pParent);
  317. const PROPSHEETPAGE* ppsp;
  318. if (pSheetEx != NULL)
  319. ppsp = pSheetEx->m_psh.ppsp;
  320. else
  321. ppsp = pSheet->m_psh.ppsp;
  322. // search the pages for a matching ID
  323. for (int i = 0; i < pSheet->m_pages.GetSize(); i++)
  324. {
  325. // check page[i] for a match
  326. CPropertyPage* pPage = pSheet->GetPage(i);
  327. if ((LRESULT)pPage->m_psp.pszTemplate == lToMap)
  328. return (LRESULT)ppsp->pResource;
  329. // jump to next page
  330. (BYTE*&)ppsp += ppsp->dwSize;
  331. }
  332. }
  333. // otherwise, just use the original value
  334. return lToMap;
  335. }
  336. BOOL CPropertyPage::IsButtonEnabled(int iButton)
  337. {
  338. HWND hWnd = ::GetDlgItem(::GetParent(m_hWnd), iButton);
  339. if (hWnd == NULL)
  340. return FALSE;
  341. return ::IsWindowEnabled(hWnd);
  342. }
  343. BOOL CPropertyPage::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
  344. {
  345. ASSERT(pResult != NULL);
  346. NMHDR* pNMHDR = (NMHDR*)lParam;
  347. // allow message map to override
  348. if (CDialog::OnNotify(wParam, lParam, pResult))
  349. return TRUE;
  350. // don't handle messages not from the page/sheet itself
  351. if (pNMHDR->hwndFrom != m_hWnd && pNMHDR->hwndFrom != ::GetParent(m_hWnd))
  352. return FALSE;
  353. // handle default
  354. switch (pNMHDR->code)
  355. {
  356. case PSN_SETACTIVE:
  357. {
  358. CPropertySheet* pSheet = DYNAMIC_DOWNCAST(CPropertySheet, GetParent());
  359. if (pSheet != NULL && !(pSheet->m_nFlags & WF_CONTINUEMODAL) && !(pSheet->m_bModeless))
  360. *pResult = -1;
  361. else
  362. *pResult = OnSetActive() ? 0 : -1;
  363. }
  364. break;
  365. case PSN_KILLACTIVE:
  366. *pResult = !OnKillActive();
  367. break;
  368. case PSN_APPLY:
  369. *pResult = OnApply() ? PSNRET_NOERROR : PSNRET_INVALID_NOCHANGEPAGE;
  370. break;
  371. case PSN_RESET:
  372. OnReset();
  373. break;
  374. case PSN_QUERYCANCEL:
  375. *pResult = !OnQueryCancel();
  376. break;
  377. case PSN_WIZNEXT:
  378. //WINBUG: Win32 will send a PSN_WIZBACK even if the button is disabled.
  379. if (IsButtonEnabled(ID_WIZNEXT))
  380. *pResult = MapWizardResult(OnWizardNext());
  381. break;
  382. case PSN_WIZBACK:
  383. //WINBUG: Win32 will send a PSN_WIZBACK even if the button is disabled.
  384. if (IsButtonEnabled(ID_WIZBACK))
  385. *pResult = MapWizardResult(OnWizardBack());
  386. break;
  387. case PSN_WIZFINISH:
  388. *pResult = !OnWizardFinish();
  389. break;
  390. case PSN_HELP:
  391. SendMessage(WM_COMMAND, ID_HELP);
  392. break;
  393. default:
  394. return FALSE; // not handled
  395. }
  396. return TRUE; // handled
  397. }
  398. /////////////////////////////////////////////////////////////////////////////
  399. // CPropertyPage message Handlers
  400. BOOL CPropertyPage::PreTranslateMessage(MSG* pMsg)
  401. {
  402. VERIFY(!CWnd::PreTranslateMessage(pMsg));
  403. return FALSE; // handled by CPropertySheet::PreTranslateMessage
  404. }
  405. HBRUSH CPropertyPage::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
  406. {
  407. LRESULT lResult;
  408. if (pWnd->SendChildNotifyLastMsg(&lResult))
  409. return (HBRUSH)lResult;
  410. if (afxData.bWin4)
  411. return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
  412. if (!GrayCtlColor(pDC->m_hDC, pWnd->GetSafeHwnd(), nCtlColor,
  413. afxData.hbrBtnFace, afxData.clrBtnText))
  414. return (HBRUSH)Default();
  415. return afxData.hbrBtnFace;
  416. }
  417. /////////////////////////////////////////////////////////////////////////////
  418. // CPropertyPage Diagnostics
  419. #ifdef _DEBUG
  420. void CPropertyPage::AssertValid() const
  421. {
  422. CDialog::AssertValid();
  423. ASSERT(m_psp.dwSize == sizeof(m_psp));
  424. ASSERT(m_psp.dwFlags & PSP_USECALLBACK);
  425. ASSERT(m_psp.pfnDlgProc == AfxDlgProc);
  426. ASSERT(m_psp.lParam == (LPARAM)this);
  427. }
  428. void CPropertyPage::Dump(CDumpContext& dc) const
  429. {
  430. CDialog::Dump(dc);
  431. dc << "m_strCaption = " << m_strCaption << "\n";
  432. dc << "m_psp.dwFlags = " << m_psp.dwFlags << "\n";
  433. }
  434. #endif //_DEBUG
  435. void CPropertyPage::EndDialog(int nID)
  436. {
  437. // Normally you shouldn't call EndDialog from a page. But in case it does
  438. // happen during error situations, call CPropertySheet::EndDialog instead.
  439. CPropertySheet* pParent = DYNAMIC_DOWNCAST(CPropertySheet, GetParent());
  440. if (pParent != NULL)
  441. pParent->EndDialog(nID);
  442. }
  443. /////////////////////////////////////////////////////////////////////////////
  444. // CPropertySheet -- a tabbed "dialog" (really a popup-window)
  445. BEGIN_MESSAGE_MAP(CPropertySheet, CWnd)
  446. //{{AFX_MSG_MAP(CPropertySheet)
  447. ON_WM_CTLCOLOR()
  448. ON_WM_NCCREATE()
  449. ON_MESSAGE(WM_INITDIALOG, HandleInitDialog)
  450. ON_MESSAGE(WM_COMMANDHELP, OnCommandHelp)
  451. ON_WM_CLOSE()
  452. ON_WM_SYSCOMMAND()
  453. ON_MESSAGE(DM_SETDEFID, OnSetDefID)
  454. //}}AFX_MSG_MAP
  455. END_MESSAGE_MAP()
  456. AFX_STATIC_DATA const int _afxPropSheetIDs[4] = { ID_WIZNEXT, ID_WIZFINISH, ID_WIZBACK, IDCANCEL };
  457. AFX_OLDPROPSHEETHEADER* CPropertySheet::GetPropSheetHeader()
  458. {
  459. CPropertySheetEx* pSheetEx = DYNAMIC_DOWNCAST(CPropertySheetEx, this);
  460. if (pSheetEx != NULL)
  461. return (AFX_OLDPROPSHEETHEADER*)&pSheetEx->m_psh;
  462. else
  463. return &m_psh;
  464. }
  465. LRESULT CPropertySheet::OnSetDefID(WPARAM wParam, LPARAM lParam)
  466. {
  467. // WINBUG -- A wrong or invalid ID may be passed in here. If this is the
  468. // case, then look for a valid one.
  469. HWND hWnd;
  470. if (IsWizard() &&
  471. (
  472. ((hWnd = ::GetDlgItem(m_hWnd, wParam)) == NULL) ||
  473. !(::GetWindowLong(hWnd, GWL_STYLE) & WS_VISIBLE) ||
  474. !::IsWindowEnabled(hWnd)
  475. ))
  476. {
  477. for (int i = 0; i < 4; i++)
  478. {
  479. // find first button that is visible and enabled
  480. HWND hWnd = ::GetDlgItem(m_hWnd, _afxPropSheetIDs[i]);
  481. if ((GetWindowLong(hWnd, GWL_STYLE) & WS_VISIBLE) &&
  482. ::IsWindowEnabled(hWnd))
  483. {
  484. //WINBUG -- focus could be incorrect as well in this case
  485. // so ... let's set it to the default button
  486. HWND hWndFocus = ::GetFocus();
  487. if (!::IsWindowEnabled(hWndFocus))
  488. ::SetFocus(hWnd);
  489. return DefWindowProc(DM_SETDEFID, _afxPropSheetIDs[i], lParam);
  490. }
  491. }
  492. }
  493. return Default();
  494. }
  495. CPropertySheet::CPropertySheet()
  496. {
  497. CommonConstruct(NULL, 0);
  498. }
  499. CPropertySheet::CPropertySheet(UINT nIDCaption, CWnd* pParentWnd,
  500. UINT iSelectPage)
  501. {
  502. ASSERT(nIDCaption != 0);
  503. VERIFY(m_strCaption.LoadString(nIDCaption) != 0);
  504. CommonConstruct(pParentWnd, iSelectPage);
  505. }
  506. CPropertySheet::CPropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd,
  507. UINT iSelectPage)
  508. {
  509. ASSERT(pszCaption != NULL);
  510. m_strCaption = pszCaption;
  511. CommonConstruct(pParentWnd, iSelectPage);
  512. }
  513. void CPropertySheet::Construct(UINT nIDCaption, CWnd* pParentWnd,
  514. UINT iSelectPage)
  515. {
  516. ASSERT(nIDCaption != 0);
  517. VERIFY(m_strCaption.LoadString(nIDCaption) != 0);
  518. CommonConstruct(pParentWnd, iSelectPage);
  519. }
  520. void CPropertySheet::Construct(LPCTSTR pszCaption, CWnd* pParentWnd,
  521. UINT iSelectPage)
  522. {
  523. ASSERT(pszCaption != NULL);
  524. m_strCaption = pszCaption;
  525. CommonConstruct(pParentWnd, iSelectPage);
  526. }
  527. void CPropertySheet::CommonConstruct(CWnd* pParentWnd, UINT iSelectPage)
  528. {
  529. memset(&m_psh, 0, sizeof(m_psh));
  530. m_psh.dwSize = sizeof(m_psh);
  531. m_psh.dwFlags = PSH_PROPSHEETPAGE;
  532. m_psh.pszCaption = m_strCaption;
  533. m_psh.nStartPage = iSelectPage;
  534. m_bStacked = TRUE;
  535. m_bModeless = FALSE;
  536. if (AfxHelpEnabled())
  537. m_psh.dwFlags |= PSH_HASHELP;
  538. m_pParentWnd = pParentWnd; // m_psh.hwndParent set in DoModal/create
  539. }
  540. void CPropertySheet::EnableStackedTabs(BOOL bStacked)
  541. {
  542. m_bStacked = bStacked;
  543. }
  544. void CPropertySheet::SetTitle(LPCTSTR lpszText, UINT nStyle)
  545. {
  546. ASSERT((nStyle & ~PSH_PROPTITLE) == 0); // only PSH_PROPTITLE is valid
  547. ASSERT(lpszText == NULL || AfxIsValidString(lpszText));
  548. if (m_hWnd == NULL)
  549. {
  550. AFX_OLDPROPSHEETHEADER* psh = GetPropSheetHeader();
  551. // set internal state
  552. m_strCaption = lpszText;
  553. psh->pszCaption = m_strCaption;
  554. psh->dwFlags &= ~PSH_PROPTITLE;
  555. psh->dwFlags |= nStyle;
  556. }
  557. else
  558. {
  559. // set external state
  560. SendMessage(PSM_SETTITLE, nStyle, (LPARAM)lpszText);
  561. }
  562. }
  563. CPropertySheet::~CPropertySheet()
  564. {
  565. delete[] (PROPSHEETPAGE*)m_psh.ppsp;
  566. }
  567. BOOL CPropertySheet::PreTranslateMessage(MSG* pMsg)
  568. {
  569. ASSERT_VALID(this);
  570. // allow tooltip messages to be filtered
  571. if (CWnd::PreTranslateMessage(pMsg))
  572. return TRUE;
  573. // allow sheet to translate Ctrl+Tab, Shift+Ctrl+Tab,
  574. // Ctrl+PageUp, and Ctrl+PageDown
  575. if (pMsg->message == WM_KEYDOWN && GetAsyncKeyState(VK_CONTROL) < 0 &&
  576. (pMsg->wParam == VK_TAB || pMsg->wParam == VK_PRIOR || pMsg->wParam == VK_NEXT))
  577. {
  578. if (SendMessage(PSM_ISDIALOGMESSAGE, 0, (LPARAM)pMsg))
  579. return TRUE;
  580. }
  581. // handle rest with IsDialogMessage
  582. return PreTranslateInput(pMsg);
  583. }
  584. BOOL CPropertySheet::OnCmdMsg(UINT nID, int nCode, void* pExtra,
  585. AFX_CMDHANDLERINFO* pHandlerInfo)
  586. {
  587. if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
  588. return TRUE;
  589. if ((nCode != CN_COMMAND && nCode != CN_UPDATE_COMMAND_UI) ||
  590. !IS_COMMAND_ID(nID) || nID >= 0xf000)
  591. {
  592. // control notification or non-command button or system command
  593. return FALSE; // not routed any further
  594. }
  595. // if we have an owner window, give it second crack
  596. CWnd* pOwner = GetParent();
  597. if (pOwner != NULL)
  598. {
  599. #ifdef _DEBUG
  600. if (afxTraceFlags & traceCmdRouting)
  601. TRACE1("Routing command id 0x%04X to owner window.\n", nID);
  602. #endif
  603. ASSERT(pOwner != this);
  604. if (pOwner->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
  605. return TRUE;
  606. }
  607. // last crack goes to the current CWinThread object
  608. CWinThread* pThread = AfxGetThread();
  609. if (pThread != NULL)
  610. {
  611. #ifdef _DEBUG
  612. if (afxTraceFlags & traceCmdRouting)
  613. TRACE1("Routing command id 0x%04X to app.\n", nID);
  614. #endif
  615. if (pThread->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
  616. return TRUE;
  617. }
  618. #ifdef _DEBUG
  619. if (afxTraceFlags & traceCmdRouting)
  620. {
  621. TRACE2("IGNORING command id 0x%04X sent to %hs dialog.\n", nID,
  622. GetRuntimeClass()->m_lpszClassName);
  623. }
  624. #endif
  625. return FALSE;
  626. }
  627. CPropertyPage* CPropertySheet::GetActivePage() const
  628. {
  629. ASSERT_VALID(this);
  630. CPropertyPage* pPage;
  631. if (m_hWnd != NULL)
  632. pPage = STATIC_DOWNCAST(CPropertyPage,
  633. CWnd::FromHandle((HWND)::SendMessage(m_hWnd, PSM_GETCURRENTPAGEHWND, 0, 0)));
  634. else
  635. pPage = GetPage(GetActiveIndex());
  636. return pPage;
  637. }
  638. BOOL CPropertySheet::ContinueModal()
  639. {
  640. // allow CWnd::EndModalLoop to be used
  641. if (!CWnd::ContinueModal())
  642. return FALSE;
  643. // when active page is NULL, the modal loop should end
  644. ASSERT(::IsWindow(m_hWnd));
  645. BOOL bResult = SendMessage(PSM_GETCURRENTPAGEHWND);
  646. return bResult;
  647. }
  648. int CPropertySheet::DoModal()
  649. {
  650. ASSERT_VALID(this);
  651. ASSERT(m_hWnd == NULL);
  652. // register common controls
  653. VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTLS_REG));
  654. AfxDeferRegisterClass(AFX_WNDCOMMCTLSNEW_REG);
  655. // finish building PROPSHEETHEADER structure
  656. BuildPropPageArray();
  657. // allow OLE servers to disable themselves
  658. CWinApp* pApp = AfxGetApp();
  659. if (pApp != NULL)
  660. pApp->EnableModeless(FALSE);
  661. // find parent HWND
  662. HWND hWndTop;
  663. HWND hWndParent = CWnd::GetSafeOwner_(m_pParentWnd->GetSafeHwnd(), &hWndTop);
  664. AFX_OLDPROPSHEETHEADER* psh = GetPropSheetHeader();
  665. psh->hwndParent = hWndParent;
  666. BOOL bEnableParent = FALSE;
  667. if (hWndParent != NULL && ::IsWindowEnabled(hWndParent))
  668. {
  669. ::EnableWindow(hWndParent, FALSE);
  670. bEnableParent = TRUE;
  671. }
  672. HWND hWndCapture = ::GetCapture();
  673. if (hWndCapture != NULL)
  674. ::SendMessage(hWndCapture, WM_CANCELMODE, 0, 0);
  675. // setup for modal loop and creation
  676. m_nModalResult = 0;
  677. m_nFlags |= WF_CONTINUEMODAL;
  678. // hook for creation of window
  679. AfxHookWindowCreate(this);
  680. psh->dwFlags |= PSH_MODELESS;
  681. m_nFlags |= WF_CONTINUEMODAL;
  682. HWND hWnd = (HWND)::PropertySheet((PROPSHEETHEADER*)psh);
  683. #ifdef _DEBUG
  684. DWORD dwError = ::GetLastError();
  685. #endif
  686. psh->dwFlags &= ~PSH_MODELESS;
  687. AfxUnhookWindowCreate();
  688. // handle error
  689. if (hWnd == NULL || hWnd == (HWND)-1)
  690. {
  691. TRACE1("PropertySheet() failed: GetLastError returned %d\n", dwError);
  692. m_nFlags &= ~WF_CONTINUEMODAL;
  693. }
  694. int nResult = m_nModalResult;
  695. if (ContinueModal())
  696. {
  697. // enter modal loop
  698. DWORD dwFlags = MLF_SHOWONIDLE;
  699. if (GetStyle() & DS_NOIDLEMSG)
  700. dwFlags |= MLF_NOIDLEMSG;
  701. nResult = RunModalLoop(dwFlags);
  702. }
  703. // hide the window before enabling parent window, etc.
  704. if (m_hWnd != NULL)
  705. {
  706. SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW|
  707. SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
  708. }
  709. if (bEnableParent)
  710. ::EnableWindow(hWndParent, TRUE);
  711. if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd)
  712. ::SetActiveWindow(hWndParent);
  713. // cleanup
  714. DestroyWindow();
  715. // allow OLE servers to enable themselves
  716. if (pApp != NULL)
  717. pApp->EnableModeless(TRUE);
  718. if (hWndTop != NULL)
  719. ::EnableWindow(hWndTop, TRUE);
  720. return nResult;
  721. }
  722. int CALLBACK
  723. AfxPropSheetCallback(HWND, UINT message, LPARAM lParam)
  724. {
  725. switch (message)
  726. {
  727. case PSCB_PRECREATE:
  728. {
  729. _AFX_THREAD_STATE* pState = AfxGetThreadState();
  730. LPDLGTEMPLATE lpTemplate = (LPDLGTEMPLATE)lParam;
  731. if (lpTemplate->style != pState->m_dwPropStyle ||
  732. lpTemplate->dwExtendedStyle != pState->m_dwPropExStyle)
  733. {
  734. // Mark the dialog template as read-write.
  735. DWORD dwOldProtect;
  736. VirtualProtect(lpTemplate, sizeof(DLGTEMPLATE), PAGE_READWRITE, &dwOldProtect);
  737. // Ensure DS_SETFONT is set correctly.
  738. lpTemplate->style = lpTemplate->style & DS_SETFONT ?
  739. pState->m_dwPropStyle | DS_SETFONT :
  740. pState->m_dwPropStyle & ~DS_SETFONT;
  741. lpTemplate->dwExtendedStyle = pState->m_dwPropExStyle;
  742. return TRUE;
  743. }
  744. return FALSE;
  745. }
  746. }
  747. return 0;
  748. }
  749. BOOL CPropertySheet::Create(CWnd* pParentWnd, DWORD dwStyle, DWORD dwExStyle)
  750. {
  751. _AFX_THREAD_STATE* pState = AfxGetThreadState();
  752. // Calculate the default window style.
  753. if (dwStyle == (DWORD)-1)
  754. {
  755. pState->m_dwPropStyle = DS_MODALFRAME | DS_3DLOOK | DS_CONTEXTHELP |
  756. DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION;
  757. // Wizards don't have WS_SYSMENU.
  758. if (!IsWizard())
  759. pState->m_dwPropStyle |= WS_SYSMENU;
  760. }
  761. else
  762. {
  763. pState->m_dwPropStyle = dwStyle;
  764. }
  765. pState->m_dwPropExStyle = dwExStyle;
  766. ASSERT_VALID(this);
  767. ASSERT(m_hWnd == NULL);
  768. VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTLS_REG));
  769. AfxDeferRegisterClass(AFX_WNDCOMMCTLSNEW_REG);
  770. // finish building PROPSHEETHEADER structure
  771. AFX_OLDPROPSHEETHEADER* psh = GetPropSheetHeader();
  772. BuildPropPageArray();
  773. m_bModeless = TRUE;
  774. psh->dwFlags |= (PSH_MODELESS|PSH_USECALLBACK);
  775. psh->pfnCallback = AfxPropSheetCallback;
  776. psh->hwndParent = pParentWnd->GetSafeHwnd();
  777. // hook the window creation process
  778. AfxHookWindowCreate(this);
  779. HWND hWnd = (HWND)PropertySheet((PROPSHEETHEADER*)psh);
  780. #ifdef _DEBUG
  781. DWORD dwError = ::GetLastError();
  782. #endif
  783. // cleanup on failure, otherwise return TRUE
  784. if (!AfxUnhookWindowCreate())
  785. PostNcDestroy(); // cleanup if Create fails
  786. if (hWnd == NULL || hWnd == (HWND)-1)
  787. {
  788. TRACE1("PropertySheet() failed: GetLastError returned %d\n", dwError);
  789. return FALSE;
  790. }
  791. ASSERT(hWnd == m_hWnd);
  792. return TRUE;
  793. }
  794. void CPropertySheet::BuildPropPageArray()
  795. {
  796. // delete existing prop page array
  797. delete[] (PROPSHEETPAGE*)m_psh.ppsp;
  798. m_psh.ppsp = NULL;
  799. // build new prop page array
  800. AFX_OLDPROPSHEETPAGE* ppsp = new AFX_OLDPROPSHEETPAGE[m_pages.GetSize()];
  801. m_psh.ppsp = (LPPROPSHEETPAGE)ppsp;
  802. BOOL bWizard = (m_psh.dwFlags & (PSH_WIZARD | PSH_WIZARD97));
  803. for (int i = 0; i < m_pages.GetSize(); i++)
  804. {
  805. CPropertyPage* pPage = GetPage(i);
  806. memcpy(&ppsp[i], &pPage->m_psp, sizeof(pPage->m_psp));
  807. pPage->PreProcessPageTemplate((PROPSHEETPAGE&)ppsp[i], bWizard);
  808. }
  809. m_psh.nPages = m_pages.GetSize();
  810. }
  811. ////////////////////////////////////////////////////////////////////////////
  812. int CPropertySheet::GetPageCount() const
  813. {
  814. ASSERT_VALID(this);
  815. if (m_hWnd == NULL)
  816. return m_pages.GetSize();
  817. CTabCtrl* pTab = GetTabControl();
  818. ASSERT_VALID(pTab);
  819. return pTab->GetItemCount();
  820. }
  821. int CPropertySheet::GetActiveIndex() const
  822. {
  823. if (m_hWnd == NULL)
  824. return ((CPropertySheet*)this)->GetPropSheetHeader()->nStartPage;
  825. CTabCtrl* pTab = GetTabControl();
  826. ASSERT_VALID(pTab);
  827. return pTab->GetCurSel();
  828. }
  829. BOOL CPropertySheet::SetActivePage(int nPage)
  830. {
  831. if (m_hWnd == NULL)
  832. {
  833. GetPropSheetHeader()->nStartPage = nPage;
  834. return TRUE;
  835. }
  836. return (BOOL)SendMessage(PSM_SETCURSEL, nPage);
  837. }
  838. int CPropertySheet::GetPageIndex(CPropertyPage* pPage)
  839. {
  840. for (int i = 0; i < GetPageCount(); i++)
  841. {
  842. if (GetPage(i) == pPage)
  843. return i;
  844. }
  845. return -1; // pPage not found
  846. }
  847. BOOL CPropertySheet::SetActivePage(CPropertyPage* pPage)
  848. {
  849. ASSERT_VALID(this);
  850. ASSERT(pPage != NULL);
  851. ASSERT_KINDOF(CPropertyPage, pPage);
  852. int nPage = GetPageIndex(pPage);
  853. ASSERT(pPage >= 0);
  854. return SetActivePage(nPage);
  855. }
  856. void CPropertySheet::AddPage(CPropertyPage* pPage)
  857. {
  858. ASSERT_VALID(this);
  859. ASSERT(pPage != NULL);
  860. ASSERT_KINDOF(CPropertyPage, pPage);
  861. ASSERT_VALID(pPage);
  862. // add page to internal list
  863. m_pages.Add(pPage);
  864. // add page externally
  865. if (m_hWnd != NULL)
  866. {
  867. // build new prop page array
  868. AFX_OLDPROPSHEETPAGE *ppsp = new AFX_OLDPROPSHEETPAGE[m_pages.GetSize()];
  869. memcpy(ppsp, m_psh.ppsp, sizeof(AFX_OLDPROPSHEETPAGE) * (m_pages.GetSize()-1));
  870. delete[] (PROPSHEETPAGE*)m_psh.ppsp;
  871. m_psh.ppsp = (PROPSHEETPAGE*)ppsp;
  872. ppsp += m_pages.GetSize()-1;
  873. // copy processed PROPSHEETPAGE struct to end
  874. memcpy(ppsp, &pPage->m_psp, sizeof(pPage->m_psp));
  875. pPage->PreProcessPageTemplate((PROPSHEETPAGE&)*ppsp, IsWizard());
  876. HPROPSHEETPAGE hPSP = CreatePropertySheetPage((PROPSHEETPAGE*)ppsp);
  877. if (hPSP == NULL)
  878. AfxThrowMemoryException();
  879. if (!SendMessage(PSM_ADDPAGE, 0, (LPARAM)hPSP))
  880. {
  881. DestroyPropertySheetPage(hPSP);
  882. AfxThrowMemoryException();
  883. }
  884. }
  885. }
  886. void CPropertySheet::RemovePage(CPropertyPage* pPage)
  887. {
  888. ASSERT_VALID(this);
  889. ASSERT(pPage != NULL);
  890. ASSERT_KINDOF(CPropertyPage, pPage);
  891. int nPage = GetPageIndex(pPage);
  892. ASSERT(nPage >= 0);
  893. RemovePage(nPage);
  894. }
  895. void CPropertySheet::RemovePage(int nPage)
  896. {
  897. ASSERT_VALID(this);
  898. // remove the page externally
  899. if (m_hWnd != NULL)
  900. SendMessage(PSM_REMOVEPAGE, nPage);
  901. // remove the page from internal list
  902. m_pages.RemoveAt(nPage);
  903. }
  904. void CPropertySheet::EndDialog(int nEndID)
  905. {
  906. ASSERT_VALID(this);
  907. CWnd::EndModalLoop(nEndID);
  908. if (m_bModeless)
  909. DestroyWindow();
  910. else
  911. PostMessage(PSM_PRESSBUTTON, PSBTN_CANCEL);
  912. }
  913. void CPropertySheet::OnClose()
  914. {
  915. m_nModalResult = IDCANCEL;
  916. if (m_bModeless)
  917. DestroyWindow();
  918. else
  919. Default();
  920. }
  921. void CPropertySheet::OnSysCommand(UINT nID, LPARAM)
  922. {
  923. m_nModalResult = IDCANCEL;
  924. switch (nID & 0xFFF0)
  925. {
  926. case SC_CLOSE:
  927. if (m_bModeless)
  928. {
  929. SendMessage(WM_CLOSE);
  930. return;
  931. }
  932. }
  933. Default();
  934. }
  935. /////////////////////////////////////////////////////////////////////////////
  936. // CPropertySheet message handlers
  937. AFX_STATIC_DATA int _afxPropSheetButtons[] = { IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP };
  938. BOOL CPropertySheet::OnInitDialog()
  939. {
  940. // change tab style if scrolling tabs desired (stacked tabs are default)
  941. if (!m_bStacked)
  942. {
  943. HWND hWndTab = (HWND)::GetDlgItem(m_hWnd, AFX_IDC_TAB_CONTROL);
  944. if (hWndTab != NULL)
  945. CWnd::ModifyStyle(hWndTab, TCS_MULTILINE, TCS_SINGLELINE, 0);
  946. }
  947. if (!IsWizard())
  948. {
  949. // resize the tab control so the layout is less restrictive
  950. HWND hWnd = (HWND)::GetDlgItem(m_hWnd, AFX_IDC_TAB_CONTROL);
  951. ASSERT(hWnd != NULL);
  952. CRect rectOld;
  953. ::GetWindowRect(hWnd, &rectOld);
  954. ScreenToClient(rectOld);
  955. CRect rectNew(0, 0, 0, 32);
  956. ::MapDialogRect(m_hWnd, &rectNew);
  957. if (rectNew.bottom < rectOld.bottom)
  958. {
  959. // move tab control
  960. int cyDiff = rectOld.Height() - rectNew.bottom;
  961. ::SetWindowPos(hWnd, NULL, 0, 0, rectOld.Width(), rectNew.bottom,
  962. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  963. // move buttons by similar amount
  964. for (int i = 0; i < _countof(_afxPropSheetButtons); i++)
  965. {
  966. hWnd = ::GetDlgItem(m_hWnd, _afxPropSheetButtons[i]);
  967. if (hWnd != NULL)
  968. {
  969. ::GetWindowRect(hWnd, &rectOld);
  970. ScreenToClient(&rectOld);
  971. ::SetWindowPos(hWnd, NULL,
  972. rectOld.left, rectOld.top - cyDiff,
  973. 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  974. }
  975. }
  976. // resize property sheet itself similarly
  977. GetWindowRect(&rectOld);
  978. SetWindowPos(NULL, 0, 0, rectOld.Width(), rectOld.Height() - cyDiff,
  979. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  980. }
  981. }
  982. BOOL bResult = (BOOL)Default();
  983. if (m_bModeless && !IsWizard())
  984. {
  985. // layout property sheet so button area is not accounted for
  986. CRect rectWnd;
  987. GetWindowRect(rectWnd);
  988. CRect rectButton;
  989. HWND hWnd = ::GetDlgItem(m_hWnd, IDOK);
  990. ASSERT(hWnd != NULL);
  991. ::GetWindowRect(hWnd, rectButton);
  992. SetWindowPos(NULL, 0, 0,
  993. rectWnd.Width(), rectButton.top - rectWnd.top,
  994. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  995. // remove standard buttons for modeless dialogs
  996. for (int i = 0; i < _countof(_afxPropSheetButtons); i++)
  997. {
  998. HWND hWnd = ::GetDlgItem(m_hWnd, _afxPropSheetButtons[i]);
  999. if (hWnd != NULL)
  1000. {
  1001. ::ShowWindow(hWnd, SW_HIDE);
  1002. ::EnableWindow(hWnd, FALSE);
  1003. }
  1004. }
  1005. }
  1006. // center the property sheet relative to the parent window
  1007. if (!(GetStyle() & WS_CHILD))
  1008. CenterWindow();
  1009. return bResult;
  1010. }
  1011. BOOL CPropertySheet::OnNcCreate(LPCREATESTRUCT)
  1012. {
  1013. // By default, MFC does not directly support the new style
  1014. // help button in the caption, so it is turned off here.
  1015. // It can be added back in and implemented by derived classes
  1016. // from CPropertySheet.
  1017. ModifyStyleEx(WS_EX_CONTEXTHELP, 0);
  1018. return (BOOL)Default();
  1019. }
  1020. LRESULT CPropertySheet::HandleInitDialog(WPARAM, LPARAM)
  1021. {
  1022. LRESULT lResult = OnInitDialog();
  1023. return lResult;
  1024. }
  1025. BOOL CPropertySheet::OnCommand(WPARAM wParam, LPARAM lParam)
  1026. {
  1027. // allow message map override
  1028. if (CWnd::OnCommand(wParam, lParam))
  1029. return TRUE;
  1030. // crack message parameters
  1031. UINT nID = LOWORD(wParam);
  1032. HWND hWndCtrl = (HWND)lParam;
  1033. int nCode = HIWORD(wParam);
  1034. // set m_nModalResult to ID of button, whenever button is clicked
  1035. if (hWndCtrl != NULL && nCode == BN_CLICKED)
  1036. {
  1037. if (::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0) &
  1038. (DLGC_BUTTON|DLGC_DEFPUSHBUTTON))
  1039. {
  1040. LONG lStyle = ::GetWindowLong(hWndCtrl, GWL_STYLE) & 0x0F;
  1041. if (lStyle == BS_PUSHBUTTON || lStyle == BS_DEFPUSHBUTTON ||
  1042. lStyle == BS_USERBUTTON || lStyle == BS_OWNERDRAW)
  1043. {
  1044. m_nModalResult = nID;
  1045. }
  1046. }
  1047. }
  1048. return FALSE;
  1049. }
  1050. LRESULT CPropertySheet::OnCommandHelp(WPARAM wParam, LPARAM lParam)
  1051. {
  1052. ASSERT_VALID(this);
  1053. CPropertyPage* pPage = GetActivePage();
  1054. ASSERT_VALID(pPage);
  1055. return AfxCallWndProc(pPage, pPage->m_hWnd, WM_COMMANDHELP, wParam, lParam);
  1056. }
  1057. HBRUSH CPropertySheet::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
  1058. {
  1059. LRESULT lResult;
  1060. if (pWnd->SendChildNotifyLastMsg(&lResult))
  1061. return (HBRUSH)lResult;
  1062. if (afxData.bWin4)
  1063. return CWnd::OnCtlColor(pDC, pWnd, nCtlColor);
  1064. if (!GrayCtlColor(pDC->m_hDC, pWnd->GetSafeHwnd(), nCtlColor,
  1065. afxData.hbrBtnFace, afxData.clrBtnText))
  1066. return (HBRUSH)Default();
  1067. return afxData.hbrBtnFace;
  1068. }
  1069. /////////////////////////////////////////////////////////////////////////////
  1070. // CPropertySheet Diagnostics
  1071. #ifdef _DEBUG
  1072. void CPropertySheet::AssertValid() const
  1073. {
  1074. CWnd::AssertValid();
  1075. m_pages.AssertValid();
  1076. ASSERT(m_psh.dwSize == sizeof(m_psh));
  1077. ASSERT((m_psh.dwFlags & PSH_PROPSHEETPAGE) == PSH_PROPSHEETPAGE);
  1078. }
  1079. void CPropertySheet::Dump(CDumpContext& dc) const
  1080. {
  1081. CWnd::Dump(dc);
  1082. dc << "m_strCaption = " << m_strCaption << "\n";
  1083. dc << "Number of Pages = " << m_pages.GetSize() << "\n";
  1084. dc << "Stacked = " << m_bStacked << "\n";
  1085. dc << "Modeless = " << m_bModeless << "\n";
  1086. }
  1087. #endif //_DEBUG
  1088. ////////////////////////////////////////////////////////////////////////////
  1089. // CPropertyPageEx -- one page of a tabbed dialog, extended for IE4 features
  1090. CPropertyPageEx::CPropertyPageEx(UINT nIDTemplate, UINT nIDCaption, UINT nIDHeaderTitle, UINT nIDHeaderSubTitle)
  1091. {
  1092. ASSERT(nIDTemplate != 0);
  1093. CommonConstruct(MAKEINTRESOURCE(nIDTemplate), nIDCaption, nIDHeaderTitle, nIDHeaderSubTitle);
  1094. }
  1095. CPropertyPageEx::CPropertyPageEx(LPCTSTR lpszTemplateName, UINT nIDCaption, UINT nIDHeaderTitle, UINT nIDHeaderSubTitle)
  1096. {
  1097. ASSERT(AfxIsValidString(lpszTemplateName));
  1098. CommonConstruct(lpszTemplateName, nIDCaption, nIDHeaderTitle, nIDHeaderSubTitle);
  1099. }
  1100. void CPropertyPageEx::Construct(UINT nIDTemplate, UINT nIDCaption, UINT nIDHeaderTitle, UINT nIDHeaderSubTitle)
  1101. {
  1102. ASSERT(nIDTemplate != 0);
  1103. CommonConstruct(MAKEINTRESOURCE(nIDTemplate), nIDCaption, nIDHeaderTitle, nIDHeaderSubTitle);
  1104. }
  1105. void CPropertyPageEx::Construct(LPCTSTR lpszTemplateName, UINT nIDCaption, UINT nIDHeaderTitle, UINT nIDHeaderSubTitle)
  1106. {
  1107. ASSERT(HIWORD(lpszTemplateName) == 0 ||
  1108. AfxIsValidString(lpszTemplateName));
  1109. CommonConstruct(lpszTemplateName, nIDCaption, nIDHeaderTitle, nIDHeaderSubTitle);
  1110. }
  1111. CPropertyPageEx::CPropertyPageEx()
  1112. {
  1113. CommonConstruct(NULL, 0, 0, 0);
  1114. }
  1115. void CPropertyPageEx::CommonConstruct(LPCTSTR lpszTemplateName, UINT nIDCaption, UINT nIDHeaderTitle, UINT nIDHeaderSubTitle)
  1116. {
  1117. memset(&m_psp, 0, sizeof(m_psp));
  1118. m_psp.dwSize = sizeof(m_psp);
  1119. m_psp.dwFlags = PSP_USECALLBACK;
  1120. if (lpszTemplateName != NULL)
  1121. m_psp.hInstance = AfxFindResourceHandle(lpszTemplateName, RT_DIALOG);
  1122. m_psp.pszTemplate = lpszTemplateName;
  1123. m_psp.pfnDlgProc = AfxDlgProc;
  1124. m_psp.lParam = (LPARAM)this;
  1125. m_psp.pfnCallback = AfxPropPageCallback;
  1126. if (nIDCaption != 0)
  1127. {
  1128. VERIFY(m_strCaption.LoadString(nIDCaption));
  1129. m_psp.pszTitle = m_strCaption;
  1130. m_psp.dwFlags |= PSP_USETITLE;
  1131. }
  1132. if (nIDHeaderTitle != 0)
  1133. VERIFY(m_strHeaderTitle.LoadString(nIDHeaderTitle));
  1134. if (nIDHeaderSubTitle != 0)
  1135. VERIFY(m_strHeaderSubTitle.LoadString(nIDHeaderSubTitle));
  1136. if (AfxHelpEnabled())
  1137. m_psp.dwFlags |= PSP_HASHELP;
  1138. if (HIWORD(lpszTemplateName) == 0)
  1139. m_nIDHelp = LOWORD((DWORD)lpszTemplateName);
  1140. m_lpszTemplateName = m_psp.pszTemplate;
  1141. m_bFirstSetActive = TRUE;
  1142. }
  1143. #ifdef _DEBUG
  1144. void CPropertyPageEx::AssertValid() const
  1145. {
  1146. CDialog::AssertValid();
  1147. ASSERT(m_psp.dwSize == sizeof(m_psp));
  1148. ASSERT(m_psp.dwFlags & PSP_USECALLBACK);
  1149. ASSERT(m_psp.pfnDlgProc == AfxDlgProc);
  1150. ASSERT(m_psp.lParam == (LPARAM)this);
  1151. }
  1152. void CPropertyPageEx::Dump(CDumpContext& dc) const
  1153. {
  1154. CDialog::Dump(dc);
  1155. dc << "m_strCaption = " << m_strCaption << "\n";
  1156. dc << "m_psp.dwFlags = " << m_psp.dwFlags << "\n";
  1157. dc << "m_strHeaderTitle = " << m_strHeaderTitle << "\n";
  1158. dc << "m_strHeaderSubTitle = " << m_strHeaderSubTitle << "\n";
  1159. }
  1160. #endif //_DEBUG
  1161. /////////////////////////////////////////////////////////////////////////////
  1162. // CPropertySheetEx -- a tabbed "dialog" (really a popup-window), extended
  1163. // for IE4
  1164. CPropertySheetEx::CPropertySheetEx()
  1165. {
  1166. CommonConstruct(NULL, 0, NULL, NULL, NULL);
  1167. }
  1168. CPropertySheetEx::CPropertySheetEx(UINT nIDCaption, CWnd* pParentWnd,
  1169. UINT iSelectPage, HBITMAP hbmWatermark, HPALETTE hpalWatermark,
  1170. HBITMAP hbmHeader)
  1171. {
  1172. ASSERT(nIDCaption != 0);
  1173. VERIFY(m_strCaption.LoadString(nIDCaption) != 0);
  1174. CommonConstruct(pParentWnd, iSelectPage, hbmWatermark, hpalWatermark, hbmHeader);
  1175. }
  1176. CPropertySheetEx::CPropertySheetEx(LPCTSTR pszCaption, CWnd* pParentWnd,
  1177. UINT iSelectPage, HBITMAP hbmWatermark, HPALETTE hpalWatermark,
  1178. HBITMAP hbmHeader)
  1179. {
  1180. ASSERT(pszCaption != NULL);
  1181. m_strCaption = pszCaption;
  1182. CommonConstruct(pParentWnd, iSelectPage, hbmWatermark, hpalWatermark, hbmHeader);
  1183. }
  1184. void CPropertySheetEx::Construct(UINT nIDCaption, CWnd* pParentWnd,
  1185. UINT iSelectPage, HBITMAP hbmWatermark, HPALETTE hpalWatermark,
  1186. HBITMAP hbmHeader)
  1187. {
  1188. ASSERT(nIDCaption != 0);
  1189. VERIFY(m_strCaption.LoadString(nIDCaption) != 0);
  1190. CommonConstruct(pParentWnd, iSelectPage, hbmWatermark, hpalWatermark, hbmHeader);
  1191. }
  1192. void CPropertySheetEx::Construct(LPCTSTR pszCaption, CWnd* pParentWnd,
  1193. UINT iSelectPage, HBITMAP hbmWatermark, HPALETTE hpalWatermark,
  1194. HBITMAP hbmHeader)
  1195. {
  1196. ASSERT(pszCaption != NULL);
  1197. m_strCaption = pszCaption;
  1198. CommonConstruct(pParentWnd, iSelectPage, hbmWatermark, hpalWatermark, hbmHeader);
  1199. }
  1200. void CPropertySheetEx::CommonConstruct(CWnd* pParentWnd, UINT iSelectPage,
  1201. HBITMAP hbmWatermark, HPALETTE hpalWatermark, HBITMAP hbmHeader)
  1202. {
  1203. memset(&m_psh, 0, sizeof(m_psh));
  1204. m_psh.dwSize = sizeof(m_psh);
  1205. m_psh.dwFlags = PSH_PROPSHEETPAGE;
  1206. m_psh.pszCaption = m_strCaption;
  1207. m_psh.nStartPage = iSelectPage;
  1208. m_bStacked = TRUE;
  1209. m_bModeless = FALSE;
  1210. if (AfxHelpEnabled())
  1211. m_psh.dwFlags |= PSH_HASHELP;
  1212. if (hbmWatermark != NULL)
  1213. {
  1214. m_psh.hbmWatermark = hbmWatermark;
  1215. m_psh.dwFlags |= (PSH_USEHBMWATERMARK | PSH_WATERMARK);
  1216. }
  1217. if (hpalWatermark != NULL)
  1218. {
  1219. m_psh.hplWatermark = hpalWatermark;
  1220. m_psh.dwFlags |= PSH_USEHPLWATERMARK;
  1221. }
  1222. if (hbmHeader != NULL)
  1223. {
  1224. m_psh.hbmHeader = hbmHeader;
  1225. m_psh.dwFlags |= (PSH_USEHBMHEADER | PSH_HEADER);
  1226. }
  1227. m_pParentWnd = pParentWnd; // m_psh.hwndParent set in DoModal/create
  1228. }
  1229. void CPropertySheetEx::BuildPropPageArray()
  1230. {
  1231. // delete existing prop page array
  1232. delete[] (PROPSHEETPAGE*)m_psh.ppsp;
  1233. m_psh.ppsp = NULL;
  1234. // build new prop page array
  1235. PROPSHEETPAGE* ppsp = new PROPSHEETPAGE[m_pages.GetSize()];
  1236. m_psh.ppsp = (LPPROPSHEETPAGE)ppsp;
  1237. BOOL bWizard = (m_psh.dwFlags & (PSH_WIZARD | PSH_WIZARD97));
  1238. for (int i = 0; i < m_pages.GetSize(); i++)
  1239. {
  1240. CPropertyPage* pPage = GetPage(i);
  1241. memcpy(&ppsp[i], &pPage->m_psp, sizeof(pPage->m_psp));
  1242. ppsp[i].dwSize = sizeof(PROPSHEETPAGE);
  1243. if (pPage->IsKindOf(RUNTIME_CLASS(CPropertyPageEx)))
  1244. {
  1245. CPropertyPageEx* pPageEx = (CPropertyPageEx*)pPage;
  1246. if (!pPageEx->m_strHeaderTitle.IsEmpty())
  1247. {
  1248. ppsp[i].pszHeaderTitle = pPageEx->m_strHeaderTitle;
  1249. ppsp[i].dwFlags |= PSP_USEHEADERTITLE;
  1250. }
  1251. if (!pPageEx->m_strHeaderSubTitle.IsEmpty())
  1252. {
  1253. ppsp[i].pszHeaderSubTitle = pPageEx->m_strHeaderSubTitle;
  1254. ppsp[i].dwFlags |= PSP_USEHEADERSUBTITLE;
  1255. }
  1256. }
  1257. pPage->PreProcessPageTemplate(ppsp[i], bWizard);
  1258. }
  1259. m_psh.nPages = m_pages.GetSize();
  1260. }
  1261. CPropertySheetEx::~CPropertySheetEx()
  1262. {
  1263. delete[] (PROPSHEETPAGE*)m_psh.ppsp;
  1264. }
  1265. void CPropertySheetEx::AddPage(CPropertyPageEx* pPage)
  1266. {
  1267. ASSERT_VALID(this);
  1268. ASSERT(pPage != NULL);
  1269. ASSERT_KINDOF(CPropertyPageEx, pPage);
  1270. ASSERT_VALID(pPage);
  1271. // add page to internal list
  1272. m_pages.Add(pPage);
  1273. // add page externally
  1274. if (m_hWnd != NULL)
  1275. {
  1276. // build new prop page array
  1277. PROPSHEETPAGE *ppsp = new PROPSHEETPAGE[m_pages.GetSize()];
  1278. memcpy(ppsp, m_psh.ppsp, sizeof(PROPSHEETPAGE) * (m_pages.GetSize()-1));
  1279. delete[] (PROPSHEETPAGE*)m_psh.ppsp;
  1280. m_psh.ppsp = ppsp;
  1281. ppsp += m_pages.GetSize()-1;
  1282. memcpy(ppsp, &pPage->m_psp, sizeof(pPage->m_psp));
  1283. pPage->PreProcessPageTemplate(*ppsp, IsWizard());
  1284. if (!pPage->m_strHeaderTitle.IsEmpty())
  1285. {
  1286. ppsp->pszHeaderTitle = pPage->m_strHeaderTitle;
  1287. ppsp->dwFlags |= PSP_USEHEADERTITLE;
  1288. }
  1289. if (!pPage->m_strHeaderSubTitle.IsEmpty())
  1290. {
  1291. ppsp->pszHeaderSubTitle = pPage->m_strHeaderSubTitle;
  1292. ppsp->dwFlags |= PSP_USEHEADERSUBTITLE;
  1293. }
  1294. HPROPSHEETPAGE hPSP = CreatePropertySheetPage(ppsp);
  1295. if (hPSP == NULL)
  1296. AfxThrowMemoryException();
  1297. if (!SendMessage(PSM_ADDPAGE, 0, (LPARAM)hPSP))
  1298. {
  1299. DestroyPropertySheetPage(hPSP);
  1300. AfxThrowMemoryException();
  1301. }
  1302. }
  1303. }
  1304. /////////////////////////////////////////////////////////////////////////////
  1305. // CPropertySheetEx Diagnostics
  1306. #ifdef _DEBUG
  1307. void CPropertySheetEx::AssertValid() const
  1308. {
  1309. CWnd::AssertValid();
  1310. m_pages.AssertValid();
  1311. ASSERT(m_psh.dwSize == sizeof(m_psh));
  1312. ASSERT((m_psh.dwFlags & PSH_PROPSHEETPAGE) == PSH_PROPSHEETPAGE);
  1313. }
  1314. void CPropertySheetEx::Dump(CDumpContext& dc) const
  1315. {
  1316. CWnd::Dump(dc);
  1317. dc << "m_strCaption = " << m_strCaption << "\n";
  1318. dc << "Number of Pages = " << m_pages.GetSize() << "\n";
  1319. dc << "Stacked = " << m_bStacked << "\n";
  1320. dc << "Modeless = " << m_bModeless << "\n";
  1321. }
  1322. #endif //_DEBUG
  1323. #ifdef AFX_INIT_SEG
  1324. #pragma code_seg(AFX_INIT_SEG)
  1325. #endif
  1326. IMPLEMENT_DYNAMIC(CPropertyPage, CDialog)
  1327. IMPLEMENT_DYNAMIC(CPropertySheet, CWnd)
  1328. IMPLEMENT_DYNAMIC(CPropertyPageEx, CPropertyPage)
  1329. IMPLEMENT_DYNAMIC(CPropertySheetEx, CPropertySheet)
  1330. /////////////////////////////////////////////////////////////////////////////