Leaked source code of windows server 2003
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.

1082 lines
30 KiB

  1. //=--------------------------------------------------------------------------=
  2. // PropertyPages.Cpp
  3. //=--------------------------------------------------------------------------=
  4. // Copyright 1995 Microsoft Corporation. All Rights Reserved.
  5. //
  6. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  7. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  8. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  9. // PARTICULAR PURPOSE.
  10. //=--------------------------------------------------------------------------=
  11. //
  12. // implementation of CPropertyPage object.
  13. //
  14. #include "pch.h"
  15. #include "PropPage.H"
  16. #if defined(VS_HELP) || defined(HTML_HELP)
  17. #ifdef MS_BUILD
  18. #include "HtmlHelp.h"
  19. #else
  20. #include "HtmlHelp.hxx"
  21. #endif
  22. #ifdef VS_HELP
  23. #include "VSHelp.h" // Visual Studio html help support
  24. #endif
  25. #endif
  26. // for ASSERT and FAIL
  27. //
  28. SZTHISFILE
  29. // this variable is used to pass the pointer to the object to the hwnd.
  30. //
  31. static CPropertyPage *s_pLastPageCreated;
  32. //=--------------------------------------------------------------------------=
  33. // CPropertyPage::CPropertyPage
  34. //=--------------------------------------------------------------------------=
  35. // constructor.
  36. //
  37. // Parameters:
  38. // IUnknown * - [in] controlling unknown
  39. // int - [in] object type.
  40. //
  41. // Notes:
  42. //
  43. #pragma warning(disable:4355) // using 'this' in constructor
  44. CPropertyPage::CPropertyPage
  45. (
  46. IUnknown *pUnkOuter,
  47. int iObjectType
  48. )
  49. : CUnknownObject(pUnkOuter, this), m_ObjectType(iObjectType)
  50. {
  51. // initialize various dudes.
  52. //
  53. m_pPropertyPageSite = NULL;
  54. m_hwnd = NULL;
  55. m_cObjects = 0;
  56. m_fDirty = FALSE;
  57. m_fActivated = FALSE;
  58. m_fDeactivating = FALSE;
  59. m_ppUnkObjects = NULL;
  60. }
  61. #pragma warning(default:4355) // using 'this' in constructor
  62. //=--------------------------------------------------------------------------=
  63. // CPropertyPage::~CPropertyPage
  64. //=--------------------------------------------------------------------------=
  65. // destructor.
  66. //
  67. // Notes:
  68. //
  69. CPropertyPage::~CPropertyPage()
  70. {
  71. // clean up our window.
  72. //
  73. if (m_hwnd) {
  74. SetWindowLong(m_hwnd, GWL_USERDATA, 0xffffffff);
  75. DestroyWindow(m_hwnd);
  76. m_hwnd = NULL;
  77. }
  78. // release all the objects we're holding on to.
  79. //
  80. ReleaseAllObjects();
  81. // release the site
  82. //
  83. RELEASE_OBJECT(m_pPropertyPageSite);
  84. }
  85. //=--------------------------------------------------------------------------=
  86. // CPropertyPage::InternalQueryInterface
  87. //=--------------------------------------------------------------------------=
  88. // we support IPP and IPP2.
  89. //
  90. // Parameters:
  91. // REFIID - [in] interface they want
  92. // void ** - [out] where they want to put the resulting object ptr.
  93. //
  94. // Output:
  95. // HRESULT - S_OK, E_NOINTERFACE
  96. //
  97. // Notes:
  98. //
  99. HRESULT CPropertyPage::InternalQueryInterface
  100. (
  101. REFIID riid,
  102. void **ppvObjOut
  103. )
  104. {
  105. IUnknown *pUnk;
  106. *ppvObjOut = NULL;
  107. if (DO_GUIDS_MATCH(IID_IPropertyPage, riid)) {
  108. pUnk = (IUnknown *)this;
  109. } else if (DO_GUIDS_MATCH(IID_IPropertyPage2, riid)) {
  110. pUnk = (IUnknown *)this;
  111. } else {
  112. return CUnknownObject::InternalQueryInterface(riid, ppvObjOut);
  113. }
  114. pUnk->AddRef();
  115. *ppvObjOut = (void *)pUnk;
  116. return S_OK;
  117. }
  118. //=--------------------------------------------------------------------------=
  119. // CPropertyPage::SetPageSite [IPropertyPage]
  120. //=--------------------------------------------------------------------------=
  121. // the initialization function for a property page through which the page
  122. // receives an IPropertyPageSite pointer.
  123. //
  124. // Parameters:
  125. // IPropertyPageSite * - [in] new site.
  126. //
  127. // Output:
  128. // HRESULT
  129. //
  130. // Notes;
  131. //
  132. STDMETHODIMP CPropertyPage::SetPageSite
  133. (
  134. IPropertyPageSite *pPropertyPageSite
  135. )
  136. {
  137. RELEASE_OBJECT(m_pPropertyPageSite);
  138. m_pPropertyPageSite = pPropertyPageSite;
  139. ADDREF_OBJECT(pPropertyPageSite);
  140. return S_OK;
  141. }
  142. //=--------------------------------------------------------------------------=
  143. // CPropertyPage::Activate [IPropertyPage]
  144. //=--------------------------------------------------------------------------=
  145. // instructs the page to create it's display window as a child of hwndparent
  146. // and to position it according to prc.
  147. //
  148. // Parameters:
  149. // HWND - [in] parent window
  150. // LPCRECT - [in] where to position ourselves
  151. // BOOL - [in] whether we're modal or not.
  152. //
  153. // Output:
  154. // HRESULT
  155. //
  156. // Notes:
  157. //
  158. STDMETHODIMP CPropertyPage::Activate
  159. (
  160. HWND hwndParent,
  161. LPCRECT prcBounds,
  162. BOOL fModal
  163. )
  164. {
  165. HRESULT hr;
  166. // first make sure the dialog window is loaded and created.
  167. //
  168. hr = EnsureLoaded();
  169. RETURN_ON_FAILURE(hr);
  170. // fire off a PPM_NEWOBJECTS now
  171. //
  172. hr = NewObjects(); // Note: m_fDirty is cleared after this call
  173. RETURN_ON_FAILURE(hr);
  174. // set our parent window if we haven't done so yet.
  175. //
  176. if (!m_fActivated) {
  177. SetParent(m_hwnd, hwndParent);
  178. m_fActivated = TRUE;
  179. }
  180. // now move ourselves to where we're told to be and show ourselves
  181. //
  182. Move(prcBounds);
  183. ShowWindow(m_hwnd, SW_SHOW);
  184. return S_OK;
  185. }
  186. //=--------------------------------------------------------------------------=
  187. // CPropertyPage::Deactivate [IPropertyPage]
  188. //=--------------------------------------------------------------------------=
  189. // instructs the page to destroy the window created in activate
  190. //
  191. // Output:
  192. // HRESULT
  193. //
  194. // Notes:
  195. //
  196. STDMETHODIMP CPropertyPage::Deactivate
  197. (
  198. void
  199. )
  200. {
  201. HRESULT hr = S_OK;
  202. m_fDeactivating = TRUE;
  203. SendMessage(m_hwnd, PPM_FREEOBJECTS, 0, (LPARAM)&hr);
  204. RETURN_ON_FAILURE(hr);
  205. // blow away your window.
  206. //
  207. if (m_hwnd)
  208. {
  209. DestroyWindow(m_hwnd);
  210. m_hwnd = NULL;
  211. }
  212. m_fActivated = FALSE;
  213. m_fDeactivating = FALSE;
  214. return S_OK;
  215. }
  216. //=--------------------------------------------------------------------------=
  217. // CPropertyPage::GetPageInfo [IPropertyPage]
  218. //=--------------------------------------------------------------------------=
  219. // asks the page to fill a PROPPAGEINFO structure
  220. //
  221. // Parameters:
  222. // PROPPAGEINFO * - [out] where to put info.
  223. //
  224. // Output:
  225. // HRESULT
  226. //
  227. // Notes:
  228. //
  229. STDMETHODIMP CPropertyPage::GetPageInfo
  230. (
  231. PROPPAGEINFO *pPropPageInfo
  232. )
  233. {
  234. RECT rect;
  235. CHECK_POINTER(pPropPageInfo);
  236. EnsureLoaded();
  237. // clear it out first.
  238. //
  239. memset(pPropPageInfo, 0, sizeof(PROPPAGEINFO));
  240. pPropPageInfo->pszTitle = OLESTRFROMRESID(TITLEIDOFPROPPAGE(m_ObjectType));
  241. pPropPageInfo->pszDocString = OLESTRFROMRESID(DOCSTRINGIDOFPROPPAGE(m_ObjectType));
  242. pPropPageInfo->pszHelpFile = OLESTRFROMANSI(HELPFILEOFPROPPAGE(m_ObjectType));
  243. pPropPageInfo->dwHelpContext = HELPCONTEXTOFPROPPAGE(m_ObjectType);
  244. if (!(pPropPageInfo->pszTitle && pPropPageInfo->pszDocString && pPropPageInfo->pszHelpFile))
  245. goto CleanUp;
  246. // if we've got a window yet, go and set up the size information they want.
  247. //
  248. if (m_hwnd) {
  249. GetWindowRect(m_hwnd, &rect);
  250. pPropPageInfo->size.cx = rect.right - rect.left;
  251. pPropPageInfo->size.cy = rect.bottom - rect.top;
  252. }
  253. return S_OK;
  254. CleanUp:
  255. if (pPropPageInfo->pszDocString) {
  256. CoTaskMemFree(pPropPageInfo->pszDocString);
  257. pPropPageInfo->pszDocString = NULL;
  258. }
  259. if (pPropPageInfo->pszHelpFile) {
  260. CoTaskMemFree(pPropPageInfo->pszHelpFile);
  261. pPropPageInfo->pszHelpFile = NULL;
  262. }
  263. if (pPropPageInfo->pszTitle) {
  264. CoTaskMemFree(pPropPageInfo->pszTitle);
  265. pPropPageInfo->pszTitle = NULL;
  266. }
  267. return E_OUTOFMEMORY;
  268. }
  269. //=--------------------------------------------------------------------------=
  270. // CPropertyPage::SetObjects [IPropertyPage]
  271. //=--------------------------------------------------------------------------=
  272. // provides the page with the objects being affected by the changes.
  273. //
  274. // Parameters:
  275. // ULONG - [in] count of objects.
  276. // IUnknown ** - [in] objects.
  277. //
  278. // Output:
  279. // HRESULT
  280. //
  281. // Notes:
  282. //
  283. STDMETHODIMP CPropertyPage::SetObjects
  284. (
  285. ULONG cObjects,
  286. IUnknown **ppUnkObjects
  287. )
  288. {
  289. HRESULT hr;
  290. ULONG x;
  291. //Vegas 33683 - joejo
  292. // make sure the old control is updated
  293. // if page is dirty!
  294. if (m_fDirty)
  295. hr = Apply();
  296. // make sure we've been loaded, and free out any other objects that might
  297. // have been hanging around
  298. //
  299. ReleaseAllObjects();
  300. if (!cObjects)
  301. return S_OK;
  302. // now go and set up the new ones.
  303. //
  304. m_ppUnkObjects = (IUnknown **)CtlHeapAlloc(g_hHeap, 0, cObjects * sizeof(IUnknown *));
  305. RETURN_ON_NULLALLOC(m_ppUnkObjects);
  306. // loop through and copy over all the objects.
  307. //
  308. for (x = 0; x < cObjects; x++) {
  309. m_ppUnkObjects[x] = ppUnkObjects[x];
  310. ADDREF_OBJECT(m_ppUnkObjects[x]);
  311. }
  312. // go and tell the page that there are new objects [but only if it's been
  313. // activated]
  314. //
  315. hr = S_OK;
  316. m_cObjects = cObjects;
  317. if (m_fActivated)
  318. hr = NewObjects(); // Note: m_fDirty is cleared after this call
  319. return hr;
  320. }
  321. //=--------------------------------------------------------------------------=
  322. // CPropertyPage::Show [IPropertyPage]
  323. //=--------------------------------------------------------------------------=
  324. // asks the page to show or hide its window
  325. //
  326. // Parameters:
  327. // UINT - [in] whether to show or hide
  328. //
  329. // Output:
  330. // HRESULT
  331. //
  332. // Notes:
  333. //
  334. STDMETHODIMP CPropertyPage::Show
  335. (
  336. UINT nCmdShow
  337. )
  338. {
  339. if (m_hwnd)
  340. ShowWindow(m_hwnd, nCmdShow);
  341. else
  342. return E_UNEXPECTED;
  343. return S_OK;
  344. }
  345. //=--------------------------------------------------------------------------=
  346. // CPropertyPage::Move [IPropertyPage]
  347. //=--------------------------------------------------------------------------=
  348. // asks the page to relocate and resize itself to a position other than what
  349. // was specified through Activate
  350. //
  351. // Parameters:
  352. // LPCRECT - [in] new position and size
  353. //
  354. // Output:
  355. // HRESULT
  356. //
  357. // Notes:
  358. //
  359. STDMETHODIMP CPropertyPage::Move
  360. (
  361. LPCRECT prcBounds
  362. )
  363. {
  364. // do what they sez
  365. //
  366. if (m_hwnd)
  367. SetWindowPos(m_hwnd, NULL, prcBounds->left, prcBounds->top,
  368. prcBounds->right - prcBounds->left,
  369. prcBounds->bottom - prcBounds->top,
  370. SWP_NOZORDER);
  371. else
  372. return E_UNEXPECTED;
  373. return S_OK;
  374. }
  375. //=--------------------------------------------------------------------------=
  376. // CPropertyPage::IsPageDirty [IPropertyPage]
  377. //=--------------------------------------------------------------------------=
  378. // asks the page whether it has changed its state
  379. //
  380. // Output
  381. // S_OK - yep
  382. // S_FALSE - nope
  383. //
  384. // Notes:
  385. //
  386. STDMETHODIMP CPropertyPage::IsPageDirty
  387. (
  388. void
  389. )
  390. {
  391. return m_fDirty ? S_OK : S_FALSE;
  392. }
  393. //=--------------------------------------------------------------------------=
  394. // CPropertyPage::Apply [IPropertyPage]
  395. //=--------------------------------------------------------------------------=
  396. // instructs the page to send its changes to all the objects passed through
  397. // SetObjects()
  398. //
  399. // Output:
  400. // HRESULT
  401. //
  402. // Notes:
  403. //
  404. STDMETHODIMP CPropertyPage::Apply
  405. (
  406. void
  407. )
  408. {
  409. HRESULT hr = S_OK;
  410. if (m_hwnd) {
  411. SendMessage(m_hwnd, PPM_APPLY, 0, (LPARAM)&hr);
  412. RETURN_ON_FAILURE(hr);
  413. if (m_fDirty) {
  414. m_fDirty = FALSE;
  415. if (m_pPropertyPageSite && !m_fDeactivating)
  416. m_pPropertyPageSite->OnStatusChange(PROPPAGESTATUS_DIRTY);
  417. }
  418. } else
  419. return E_UNEXPECTED;
  420. return S_OK;
  421. }
  422. //=--------------------------------------------------------------------------=
  423. // CPropertyPage::Help [IPropertyPage]
  424. //=--------------------------------------------------------------------------=
  425. // instructs the page that the help button was clicked.
  426. //
  427. // Parameters:
  428. // LPCOLESTR - [in] help directory
  429. //
  430. // Output:
  431. // HRESULT
  432. //
  433. // Notes:
  434. //
  435. STDMETHODIMP CPropertyPage::Help
  436. (
  437. LPCOLESTR pszHelpDir // Note: With VS_HELP set this parameter is ignored
  438. )
  439. {
  440. char *pszExt;
  441. char buf[MAX_PATH];
  442. BOOL f = FALSE;
  443. #ifdef VS_HELP
  444. BOOL bHelpStarted;
  445. HRESULT hr;
  446. #endif
  447. ASSERT(m_hwnd, "CPropertyPage::Help called with no hwnd!");
  448. pszExt = FileExtension(HELPFILEOFPROPPAGE(m_ObjectType));
  449. if (pszExt)
  450. {
  451. #ifdef VS_HELP
  452. #else
  453. #endif
  454. #if defined(VS_HELP) || defined(HTML_HELP)
  455. if (lstrcmpi(pszExt, "CHM") == 0)
  456. {
  457. #ifdef VS_HELP
  458. lstrcpy(buf, HELPFILEOFPROPPAGE(m_ObjectType));
  459. // First try to show help through VisualStudio
  460. //
  461. hr = VisualStudioShowHelpTopic(buf, HELPCONTEXTOFPROPPAGE(m_ObjectType), &bHelpStarted);
  462. f = SUCCEEDED(hr);
  463. // Check to see if Visual Studio help could be successfully started. If not,
  464. // assume it doesn't exist
  465. //
  466. if (!bHelpStarted)
  467. #endif
  468. {
  469. MAKE_ANSIPTR_FROMWIDE(psz, pszHelpDir);
  470. lstrcpy(buf, psz);
  471. lstrcat(buf, "\\");
  472. lstrcat(buf, HELPFILEOFPROPPAGE(m_ObjectType));
  473. // Show the help topic manually by calling HtmlHelp directly
  474. //
  475. f = (BOOL) HtmlHelp(m_hwnd, buf, HH_HELP_CONTEXT,
  476. HELPCONTEXTOFPROPPAGE(m_ObjectType));
  477. }
  478. #ifdef VS_HELP
  479. else
  480. {
  481. ASSERT(SUCCEEDED(hr), "Failed to show help topic from Visual Studio");
  482. }
  483. #endif
  484. }
  485. else if (lstrcmpi(pszExt, "HLP") == 0)
  486. #endif
  487. {
  488. // WinHelp
  489. // get the helpfile name
  490. //
  491. MAKE_ANSIPTR_FROMWIDE(psz, pszHelpDir);
  492. lstrcpy(buf, psz);
  493. lstrcat(buf, "\\");
  494. lstrcat(buf, HELPFILEOFPROPPAGE(m_ObjectType));
  495. lstrcat(buf, ">LangRef"); // Use LangRef window style
  496. f = WinHelp(m_hwnd, buf, HELP_CONTEXT,
  497. HELPCONTEXTOFPROPPAGE(m_ObjectType));
  498. }
  499. #if defined(VS_HELP) || defined(HTML_HELP)
  500. else
  501. {
  502. FAIL("Unrecognized help file type");
  503. }
  504. #endif
  505. }
  506. return f ? S_OK : E_FAIL;
  507. }
  508. static BOOL IsLastTabItem(HWND hdlg, HWND hctl, UINT nCmd)
  509. {
  510. if ((SendMessage(hdlg, WM_GETDLGCODE, 0, 0L) &
  511. (DLGC_WANTALLKEYS | DLGC_WANTMESSAGE | DLGC_WANTTAB)) == 0)
  512. {
  513. // Get top level child for controls with children, like combo.
  514. //
  515. HWND hwnd;
  516. for (/**/; hctl != hdlg; hctl = GetParent(hctl))
  517. hwnd = hctl;
  518. // Walk the zorder list until we reached the end
  519. // or until we get to a valid tab item
  520. //
  521. do
  522. {
  523. if ((hwnd = GetWindow(hwnd, nCmd)) == NULL)
  524. return TRUE;
  525. }
  526. while ((GetWindowLong(hwnd, GWL_STYLE) & (WS_DISABLED|WS_TABSTOP|WS_VISIBLE)) != (WS_TABSTOP|WS_VISIBLE));
  527. }
  528. return FALSE;
  529. }
  530. //=--------------------------------------------------------------------------=
  531. // CPropertyPage::TranslateAccelerator [IPropertyPage]
  532. //=--------------------------------------------------------------------------=
  533. // informs the page of keyboard events, allowing it to implement it's own
  534. // keyboard interface.
  535. //
  536. // Parameters:
  537. // LPMSG - [in] message that triggered this
  538. //
  539. // Output:
  540. // HRESULT
  541. //
  542. // Notes:
  543. //
  544. STDMETHODIMP CPropertyPage::TranslateAccelerator
  545. (
  546. LPMSG pmsg
  547. )
  548. {
  549. ASSERT(m_hwnd, "How can we get a TranslateAccelerator call if we're not visible?");
  550. CHECK_POINTER(pmsg);
  551. BOOL fHandled = FALSE;
  552. HWND hctl;
  553. // Special consideration for the Return and Escape keys.
  554. //
  555. if ((pmsg->message == WM_KEYDOWN) &&
  556. ((pmsg->wParam == VK_RETURN) || (pmsg->wParam == VK_ESCAPE))) {
  557. // Always let the frame handle the Escape key, but if we have the
  558. // Return key, then we need to ask the focus control if it wants it.
  559. // Usually, controls that want the Return key will return DLGC_WANTALLKEYS
  560. // when they process WM_GETDLGCODE. This is the case when an
  561. // Edit or RichEdit control has the ES_MULTILINE style
  562. //
  563. if (VK_RETURN == pmsg->wParam && m_hwnd != pmsg->hwnd
  564. && (SendMessage(pmsg->hwnd, WM_GETDLGCODE, 0, 0L) & DLGC_WANTALLKEYS)) {
  565. // Pass the Return key on as a WM_CHAR, because
  566. // this is what TranslateMessage will do for a
  567. // WM_KEYDOWN
  568. //
  569. // If a control does not process this message, then
  570. // it should return non-zero, in which case we can
  571. // pass it on to the Frame
  572. //
  573. fHandled = !SendMessage(pmsg->hwnd, WM_CHAR, pmsg->wParam, pmsg->lParam);
  574. }
  575. // If the message was not handled, then let the
  576. // Frame handle this message, but we need to change
  577. // the window handle to that of the propage.
  578. // This needs to be done because edit controls
  579. // with ES_WANTRETURN will return DLGC_WANTALLKEYS,
  580. // which will cause the Frame not to handle the Escape key
  581. //
  582. return fHandled ? S_OK : (pmsg->hwnd = m_hwnd, S_FALSE);
  583. }
  584. if (pmsg->message == WM_KEYDOWN && pmsg->wParam == VK_TAB && GetKeyState(VK_CONTROL) >= 0) {
  585. // If we already have the focus. Let's determine whether we should
  586. // pass focus up to the frame.
  587. //
  588. if (IsChild(m_hwnd, pmsg->hwnd)) {
  589. // Fix for default button border
  590. //
  591. DWORD dwDefID = SendMessage(m_hwnd, DM_GETDEFID, 0, 0);
  592. if (HIWORD(dwDefID) == DC_HASDEFID) {
  593. hctl = GetDlgItem(m_hwnd, LOWORD(dwDefID));
  594. if (NULL != hctl && IsWindowEnabled(hctl))
  595. SendMessage(m_hwnd, WM_NEXTDLGCTL, (WPARAM)hctl, 1L);
  596. }
  597. // If the focus control is the last the the tab order
  598. // then we will pass the message to the frame
  599. //
  600. if (IsLastTabItem(m_hwnd, pmsg->hwnd, GetKeyState(VK_SHIFT) < 0 ?
  601. GW_HWNDPREV : GW_HWNDNEXT)) {
  602. // Pass focus to the frame by letting the page site handle
  603. // this message.
  604. if (NULL != m_pPropertyPageSite)
  605. fHandled = m_pPropertyPageSite->TranslateAccelerator(pmsg) == S_OK;
  606. }
  607. } else {
  608. // We don't already have the focus. The frame is passing the
  609. // focus to us.
  610. //
  611. hctl = GetNextDlgTabItem(m_hwnd, NULL, GetKeyState(VK_SHIFT) < 0);
  612. if (NULL != hctl)
  613. fHandled = (BOOL)SendMessage(m_hwnd, WM_NEXTDLGCTL, (WPARAM)hctl, 1L);
  614. }
  615. }
  616. // just pass this message on to the dialog proc and see if they want it.
  617. //
  618. // just pass this message on to the dialog proc and see if they want it.
  619. //
  620. if (FALSE == fHandled) {
  621. // In order for accelerators to work properly, we need to
  622. // temporarily replace the message window handle to that
  623. // of the first child in the property page in response
  624. // to a WM_SYSKEYDOWN. This will allow the user to use an
  625. // accelerator key to go from a tab to a control on the
  626. // active page.
  627. //
  628. hctl = pmsg->hwnd;
  629. if (WM_SYSKEYDOWN == pmsg->message && !IsChild(m_hwnd, pmsg->hwnd))
  630. pmsg->hwnd = GetWindow(m_hwnd, GW_CHILD);
  631. fHandled = IsDialogMessage(m_hwnd, pmsg);
  632. pmsg->hwnd = hctl;
  633. }
  634. return fHandled ? S_OK : S_FALSE;
  635. }
  636. //=--------------------------------------------------------------------------=
  637. // CPropertyPage::EditProperty [IPropertyPage2]
  638. //=--------------------------------------------------------------------------=
  639. // instructs the page to set the focus to the property matching the dispid.
  640. //
  641. // Parameters:
  642. // DISPID - [in] dispid of property to set focus to.
  643. //
  644. // Output:
  645. // HRESULT
  646. //
  647. // Notes:
  648. //
  649. STDMETHODIMP CPropertyPage::EditProperty
  650. (
  651. DISPID dispid
  652. )
  653. {
  654. HRESULT hr = E_NOTIMPL;
  655. // send the message on to the control, and see what they want to do with it.
  656. //
  657. SendMessage(m_hwnd, PPM_EDITPROPERTY, (WPARAM)dispid, (LPARAM)&hr);
  658. return hr;
  659. }
  660. //=--------------------------------------------------------------------------=
  661. // CPropertyPage::EnsureLoaded
  662. //=--------------------------------------------------------------------------=
  663. // makes sure the dialog is actually loaded
  664. //
  665. // Output:
  666. // HRESULT
  667. //
  668. // Notes:
  669. //
  670. HRESULT CPropertyPage::EnsureLoaded
  671. (
  672. void
  673. )
  674. {
  675. HRESULT hr = S_OK;
  676. HRSRC hrsrc;
  677. HGLOBAL hDlg;
  678. LPCDLGTEMPLATE pDlg;
  679. HWND hwndDlg;
  680. // duh
  681. //
  682. if (m_hwnd)
  683. return S_OK;
  684. // create the dialog window
  685. //
  686. hrsrc = FindResource(GetResourceHandle(), TEMPLATENAMEOFPROPPAGE(m_ObjectType), RT_DIALOG);
  687. ASSERT(hrsrc, "Failed to find dialog template");
  688. if (!hrsrc)
  689. return HRESULT_FROM_WIN32(GetLastError());
  690. hDlg = LoadResource(GetResourceHandle(), hrsrc);
  691. ASSERT(hDlg, "Failed to load dialog resource");
  692. if (!hDlg)
  693. return HRESULT_FROM_WIN32(GetLastError());
  694. pDlg = (LPCDLGTEMPLATE) LockResource(hDlg);
  695. ASSERT(pDlg, "Failed to lock dialog resource");
  696. if (!pDlg)
  697. return HRESULT_FROM_WIN32(GetLastError());
  698. // set up the global variable so that when we're in the dialog proc, we can
  699. // stuff this in the hwnd
  700. //
  701. // crit sect this whole creation process for apartment threading support.
  702. //
  703. ENTERCRITICALSECTION1(&g_CriticalSection);
  704. s_pLastPageCreated = this;
  705. // Why not call CreateDialog instead? The answer is that the property page
  706. // dialog resource may contain Windows custom controls where the window proc for the
  707. // Windows control resides in your control DLL (e.g., .OCX file), not the
  708. // satellite DLL. If CreateDialog calls CreateWindow to create your Windows custom control
  709. // with a different instance than where the window class for the control is
  710. // registered, it will fail.
  711. //
  712. hwndDlg = CreateDialogIndirect(g_hInstance, pDlg, GetParkingWindow(),
  713. CPropertyPage::PropPageDlgProc);
  714. ASSERT(hwndDlg, "Couldn't load Dialog Resource!!!");
  715. ASSERT(hwndDlg == m_hwnd, "Returned hwnd doesn't match cached hwnd");
  716. // clean up variables and leave the critical section
  717. //
  718. s_pLastPageCreated = NULL;
  719. LEAVECRITICALSECTION1(&g_CriticalSection);
  720. if (!m_hwnd)
  721. return HRESULT_FROM_WIN32(GetLastError());
  722. #if 0
  723. // go and notify the window that it should pick up any objects that are
  724. // available
  725. //
  726. SendMessage(m_hwnd, PPM_NEWOBJECTS, 0, (LPARAM)&hr);
  727. #endif // 0
  728. return hr;
  729. }
  730. //=--------------------------------------------------------------------------=
  731. // CPropertyPage::ReleaseAllObjects
  732. //=--------------------------------------------------------------------------=
  733. // releases all the objects that we're working with
  734. //
  735. // Notes:
  736. //
  737. void CPropertyPage::ReleaseAllObjects
  738. (
  739. void
  740. )
  741. {
  742. HRESULT hr;
  743. UINT x;
  744. // some people will want to stash pointers in the PPM_INITOBJECTS case, so
  745. // we want to tell them to release them now.
  746. //
  747. if (m_fActivated && m_hwnd)
  748. SendMessage(m_hwnd, PPM_FREEOBJECTS, 0, (LPARAM)&hr);
  749. if (!m_cObjects) return;
  750. // loop through and blow them all away.
  751. //
  752. for (x = 0; x < m_cObjects; x++)
  753. QUICK_RELEASE(m_ppUnkObjects[x]);
  754. CtlHeapFree(g_hHeap, 0, m_ppUnkObjects);
  755. m_ppUnkObjects = NULL;
  756. m_cObjects = 0;
  757. }
  758. //=--------------------------------------------------------------------------=
  759. // CPropertyPage::PropPageDlgProc
  760. //=--------------------------------------------------------------------------=
  761. // static global helper dialog proc that gets called before we pass the message
  762. // on to anybody ..
  763. //
  764. // Parameters:
  765. // - see win32sdk docs on DialogProc
  766. //
  767. // Notes:
  768. //
  769. INT_PTR CALLBACK CPropertyPage::PropPageDlgProc
  770. (
  771. HWND hwnd,
  772. UINT msg,
  773. WPARAM wParam,
  774. LPARAM lParam
  775. )
  776. {
  777. CPropertyPage *pPropertyPage;
  778. // get the window long, and see if it's been set to the object this hwnd
  779. // is operating against. if not, go and set it now.
  780. //
  781. pPropertyPage = (CPropertyPage *)GetWindowLong(hwnd, GWL_USERDATA);
  782. if ((ULONG)pPropertyPage == 0xffffffff)
  783. return FALSE;
  784. if (!pPropertyPage) {
  785. SetWindowLong(hwnd, GWL_USERDATA, (LONG)s_pLastPageCreated);
  786. pPropertyPage = s_pLastPageCreated;
  787. pPropertyPage->m_hwnd = hwnd;
  788. }
  789. ASSERT(pPropertyPage, "Uh oh. Got a window, but no CpropertyPage for it!");
  790. // just call the user dialog proc and see if they want to do anything.
  791. //
  792. return pPropertyPage->DialogProc(hwnd, msg, wParam, lParam);
  793. }
  794. //=--------------------------------------------------------------------------=
  795. // CPropertyPage::FirstControl
  796. //=--------------------------------------------------------------------------=
  797. // returns the first controlish object that we are showing ourselves for.
  798. // returns a cookie that must be passed in for Next ...
  799. //
  800. // Parameters:
  801. // DWORD * - [out] cookie to be used for Next
  802. //
  803. // Output:
  804. // IUnknown *
  805. //
  806. // Notes:
  807. //
  808. IUnknown *CPropertyPage::FirstControl
  809. (
  810. DWORD *pdwCookie
  811. )
  812. {
  813. // just use the implementation of NEXT.
  814. //
  815. *pdwCookie = 0;
  816. return NextControl(pdwCookie);
  817. }
  818. //=--------------------------------------------------------------------------=
  819. // CPropertyPage::NextControl
  820. //=--------------------------------------------------------------------------=
  821. // returns the next control in the chain of people to work with given a cookie
  822. //
  823. // Parameters:
  824. // DWORD * - [in/out] cookie to get next from, and new cookie.
  825. //
  826. // Output:
  827. // IUnknown *
  828. //
  829. // Notes:
  830. //
  831. IUnknown *CPropertyPage::NextControl
  832. (
  833. DWORD *pdwCookie
  834. )
  835. {
  836. UINT i;
  837. // go looking through all the objects that we've got, and find the
  838. // first non-null one.
  839. //
  840. for (i = *pdwCookie; i < m_cObjects; i++) {
  841. if (!m_ppUnkObjects[i]) continue;
  842. *pdwCookie = i + 1; // + 1 so we start at next item next time
  843. return m_ppUnkObjects[i];
  844. }
  845. // couldn't find it .
  846. //
  847. *pdwCookie = 0xffffffff;
  848. return NULL;
  849. }
  850. //=--------------------------------------------------------------------------=
  851. // CPropertyPage::NewObjects [helper]
  852. //=--------------------------------------------------------------------------=
  853. // Sends PPM_NEWOBJECTS message to the property page dialog, so that
  854. // it can initialize its dialog fields.
  855. //
  856. // Notes:
  857. //
  858. HRESULT CPropertyPage::NewObjects()
  859. {
  860. HRESULT hr = S_OK;
  861. SendMessage(m_hwnd, PPM_NEWOBJECTS, 0, (LPARAM) &hr);
  862. // Clear the dirty bit and make sure the Apply button gets disabled.
  863. //
  864. if (m_fDirty)
  865. {
  866. m_fDirty = FALSE;
  867. ASSERT(m_fDeactivating == FALSE, "We're being deactivated?");
  868. if (m_pPropertyPageSite)
  869. m_pPropertyPageSite->OnStatusChange(PROPPAGESTATUS_DIRTY);
  870. }
  871. return hr;
  872. }
  873. //=--------------------------------------------------------------------------=
  874. // CPropertyPage::MakeDirty [helper, callable]
  875. //=--------------------------------------------------------------------------=
  876. // marks a page as dirty.
  877. //
  878. // Notes:
  879. //
  880. void CPropertyPage::MakeDirty
  881. (
  882. void
  883. )
  884. {
  885. m_fDirty = TRUE;
  886. // Need to make sure we have a page site and we're not being deactivated
  887. // IE 4.0 will crash if we attempt to call OnStatusChange while we're being
  888. // deactivated
  889. //
  890. if (m_pPropertyPageSite && !m_fDeactivating)
  891. m_pPropertyPageSite->OnStatusChange(PROPPAGESTATUS_DIRTY|PROPPAGESTATUS_VALIDATE);
  892. }
  893. // from Globals.C
  894. //
  895. extern HINSTANCE g_hInstResources;
  896. //=--------------------------------------------------------------------------=
  897. // CPropertyPage::GetResourceHandle [helper, callable]
  898. //=--------------------------------------------------------------------------=
  899. // returns current resource handle, based on pagesites ambient LCID.
  900. //
  901. // Output:
  902. // HINSTANCE
  903. //
  904. // Notes:
  905. //
  906. HINSTANCE CPropertyPage::GetResourceHandle
  907. (
  908. void
  909. )
  910. {
  911. if (!g_fSatelliteLocalization)
  912. return g_hInstance;
  913. // if we've already got it, then there's not all that much to do.
  914. // don't need to crit sect this one right here since even if they do fall
  915. // into the ::GetResourceHandle call, it'll properly deal with things.
  916. //
  917. if (g_hInstResources)
  918. return g_hInstResources;
  919. // we'll get the ambient localeid from the host, and pass that on to the
  920. // automation object.
  921. //
  922. // enter a critical section for g_lcidLocale and g_fHavelocale
  923. //
  924. ENTERCRITICALSECTION1(&g_CriticalSection);
  925. if (!g_fHaveLocale) {
  926. if (m_pPropertyPageSite) {
  927. m_pPropertyPageSite->GetLocaleID(&g_lcidLocale);
  928. g_fHaveLocale = TRUE;
  929. }
  930. }
  931. LEAVECRITICALSECTION1(&g_CriticalSection);
  932. return ::GetResourceHandle();
  933. }