PropertyPageBase.cpp 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569
  1. /////////////////////////////////////////////////////////////////////////////
  2. // PropertyPageBase.cpp | Implementation of the TCPropertyPageBase class.
  3. #pragma warning(disable: 4786)
  4. #include <vector>
  5. #include <map>
  6. #include <set>
  7. #include <comdef.h>
  8. #include <typeinfo.h>
  9. #include "..\TCLib\AdviseHolder.h"
  10. #include "InsidePropPage.h"
  11. #include "PageEntry.h"
  12. #include "PropertyPageBase.h"
  13. /////////////////////////////////////////////////////////////////////////////
  14. // TCPropertyPageBase
  15. /////////////////////////////////////////////////////////////////////////////
  16. // Group=Construction / Destruction
  17. TCPropertyPageBase::TCPropertyPageBase() :
  18. m_iTable(0),
  19. m_bInitializing(true),
  20. m_bUpdating(true)
  21. {
  22. }
  23. TCPropertyPageBase::~TCPropertyPageBase()
  24. {
  25. // Release any objects saved for inside pages
  26. ReleaseObjectsForInsidePages();
  27. // Release any interfaces in the map of supported interfaces
  28. ReleaseSupportedInterfaces();
  29. }
  30. /////////////////////////////////////////////////////////////////////////////
  31. // Group=Attributes
  32. /////////////////////////////////////////////////////////////////////////////
  33. // Description: Retrieves a pointer to an embedded property page.
  34. //
  35. // Retrieves a pointer to the embedded property page specified by /idCtrl/.
  36. //
  37. // Parameters:
  38. // idCtrl - The identifier of the embedded property page.
  39. //
  40. // Return Value: An TCInsidePropPage pointer to the embedded property page if
  41. // /idCtrl/ is valid. Otherwise, *NULL*.
  42. //
  43. // See Also: Embedded Property Page Table Macros,
  44. // TCInsidePropPage, XInsidePage,
  45. // TCPropertyPageBase::GetInsidePageData,
  46. // TCPropertyPageBase::GetInsidePageText,
  47. // TCPropertyPageBase::GetDirtyInsidePage,
  48. // TCPropertyPageBase::SetDirtyInsidePage,
  49. // TCPropertyPageBase::ShowInsidePage,
  50. // TCPropertyPageBase::HideInsidePage,
  51. // TCPropertyPageBase::GetInsidePageOfGroup
  52. TCInsidePropPage* TCPropertyPageBase::GetInsidePage(UINT idCtrl)
  53. {
  54. // Lookup the specified page
  55. XInsidePage* pPage = _GetInsidePage(idCtrl);
  56. if (!pPage)
  57. return pPage;
  58. // Return the page
  59. assert(pPage->m_hWnd);
  60. return pPage;
  61. }
  62. /////////////////////////////////////////////////////////////////////////////
  63. // Description: Retrieves the application-defined 32-bit (DWORD) value
  64. // associated with an embedded property page.
  65. //
  66. // Retrieves the application-defined 32-bit (DWORD) value associated with the
  67. // embedded property page specified by /idCtrl/.
  68. //
  69. // Parameters:
  70. // idCtrl - The identifier of the embedded property page.
  71. //
  72. // Return Value: The application-defined 32-bit (DWORD) value associated with
  73. // the specified embedded property page, if /idCtrl/ is valid. Otherwise,
  74. // zero.
  75. //
  76. // See Also: Embedded Property Page Table Macros,
  77. // TCInsidePropPage, XInsidePage,
  78. // TCPropertyPageBase::GetInsidePage,
  79. // TCPropertyPageBase::GetInsidePageText,
  80. // TCPropertyPageBase::GetDirtyInsidePage,
  81. // TCPropertyPageBase::SetDirtyInsidePage,
  82. // TCPropertyPageBase::ShowInsidePage,
  83. // TCPropertyPageBase::HideInsidePage
  84. DWORD TCPropertyPageBase::GetInsidePageData(UINT idCtrl)
  85. {
  86. // Lookup the specified page
  87. XInsidePage* pPage = _GetInsidePage(idCtrl);
  88. // Return the page data
  89. return pPage ? pPage->m_pEntry->dwData : 0;
  90. }
  91. /////////////////////////////////////////////////////////////////////////////
  92. // Description: Retrieves the application-defined text associated with an
  93. // embedded property page.
  94. //
  95. // Retrieves the application-defined text associated with the embedded
  96. // property page specified by /idCtrl/.
  97. //
  98. // Parameters:
  99. // idCtrl - The identifier of the embedded property page.
  100. //
  101. // Return Value: The application-defined text associated with the specified
  102. // embedded property page, if /idCtrl/ is valid.
  103. // Otherwise, *NULL*.
  104. //
  105. // See Also: Embedded Property Page Table Macros,
  106. // TCInsidePropPage, XInsidePage,
  107. // TCPropertyPageBase::GetInsidePage,
  108. // TCPropertyPageBase::GetInsidePageData,
  109. // TCPropertyPageBase::GetDirtyInsidePage,
  110. // TCPropertyPageBase::SetDirtyInsidePage,
  111. // TCPropertyPageBase::ShowInsidePage,
  112. // TCPropertyPageBase::HideInsidePage,
  113. // TCPropertyPageBase::GetInsidePageOfGroupText
  114. LPCTSTR TCPropertyPageBase::GetInsidePageText(UINT idCtrl)
  115. {
  116. // Lookup the specified page
  117. XInsidePage* pPage = _GetInsidePage(idCtrl);
  118. // Return the page text
  119. return pPage ? pPage->m_pEntry->pszText : NULL;
  120. }
  121. /////////////////////////////////////////////////////////////////////////////
  122. // Description: Retrieves the state of the dirty flag of an embedded property
  123. // page.
  124. //
  125. // Retrieves the state of the dirty flag of the embedded property page
  126. // specified by /idCtrl/.
  127. //
  128. // Parameters:
  129. // idCtrl - The identifier of the embedded property page.
  130. //
  131. // Return Value: *true* if the embedded property page's dirty flag is set and
  132. // /idCtrl/ is valid. Otherwise, *false*.
  133. //
  134. // See Also: Embedded Property Page Table Macros,
  135. // TCInsidePropPage, XInsidePage,
  136. // TCPropertyPageBase::GetInsidePage,
  137. // TCPropertyPageBase::GetInsidePageData,
  138. // TCPropertyPageBase::GetInsidePageText,
  139. // TCPropertyPageBase::SetDirtyInsidePage,
  140. // TCPropertyPageBase::ShowInsidePage,
  141. // TCPropertyPageBase::HideInsidePage,
  142. // TCPropertyPageBase::GetDirtyInsidePageOfGroup
  143. bool TCPropertyPageBase::GetDirtyInsidePage(UINT idCtrl)
  144. {
  145. TCInsidePropPage* pPage = GetInsidePage(idCtrl);
  146. return pPage ? pPage->Page_IsDirty() : false;
  147. }
  148. /////////////////////////////////////////////////////////////////////////////
  149. // Description: Modifies the state of the dirty flag of an embedded property
  150. // page.
  151. //
  152. // Modifies the state of the dirty flag of the embedded property page
  153. // specified by /idCtrl/.
  154. //
  155. // Parameters:
  156. // idCtrl - The identifier of the embedded property page.
  157. // bDirty - The new state of the embedded property page's dirty flag. If
  158. // *true*, the embedded property page's state is marked as changed. If
  159. // *false*, it is marked as unchanged.
  160. //
  161. // See Also: Embedded Property Page Table Macros,
  162. // TCInsidePropPage, XInsidePage,
  163. // TCPropertyPageBase::GetInsidePage,
  164. // TCPropertyPageBase::GetInsidePageData,
  165. // TCPropertyPageBase::GetInsidePageText,
  166. // TCPropertyPageBase::GetDirtyInsidePage,
  167. // TCPropertyPageBase::ShowInsidePage,
  168. // TCPropertyPageBase::HideInsidePage,
  169. // TCPropertyPageBase::SetDirtyInsidePageOfGroup
  170. void TCPropertyPageBase::SetDirtyInsidePage(UINT idCtrl, bool bDirty)
  171. {
  172. TCInsidePropPage* pPage = GetInsidePage(idCtrl);
  173. if (pPage)
  174. pPage->SetDirty(bDirty);
  175. }
  176. /////////////////////////////////////////////////////////////////////////////
  177. // Description: Retrieves a pointer to an embedded property page within a
  178. // group of embedded property pages.
  179. //
  180. // Retrieves a pointer to the embedded property page specified by /dw/,
  181. // within the embedded property page group specified by /idGroup/.
  182. //
  183. // Parameters:
  184. // idGroup - The identifier of the embedded property page group.
  185. // dw - The application-defined 32-bit (DWORD) value that uniquely
  186. // identifies the page within the page group.
  187. //
  188. // Return Value: An TCInsidePropPage pointer to the embedded property page if
  189. // /idGroup/ and /dw/ are valid. Otherwise, *NULL*.
  190. //
  191. // See Also: Embedded Property Page Table Macros,
  192. // TCInsidePropPage, XInsidePage,
  193. // TCPropertyPageBase::GetInsidePageOfGroupText,
  194. // TCPropertyPageBase::GetDirtyInsidePageOfGroup,
  195. // TCPropertyPageBase::SetDirtyInsidePageOfGroup,
  196. // TCPropertyPageBase::ShowInsidePageOfGroup,
  197. // TCPropertyPageBase::HideInsidePageOfGroup,
  198. // TCPropertyPageBase::GetInsidePage
  199. TCInsidePropPage* TCPropertyPageBase::GetInsidePageOfGroup(UINT idGroup,
  200. DWORD dw)
  201. {
  202. // Lookup the specified group/page
  203. XInsidePage* pPage = _GetInsidePageOfGroup(idGroup, dw);
  204. if (!pPage)
  205. return pPage;
  206. // Return the page
  207. assert(pPage->m_hWnd);
  208. return pPage;
  209. }
  210. /////////////////////////////////////////////////////////////////////////////
  211. // Description: Retrieves the application-defined text associated with an
  212. // embedded property page within a group of embedded property pages.
  213. //
  214. // Retrieves the application-defined text associated with the embedded
  215. // property page specified by /dw/, within the embedded property page group
  216. // specified by /idGroup/.
  217. //
  218. // Parameters:
  219. // idGroup - The identifier of the embedded property page group.
  220. // dw - The application-defined 32-bit (DWORD) value that uniquely
  221. // identifies the page within the page group.
  222. //
  223. // Return Value: The application-defined text associated with the embedded
  224. // property page, if /idGroup/ and /dw/ are valid. Otherwise, *NULL*.
  225. //
  226. // See Also: Embedded Property Page Table Macros,
  227. // TCInsidePropPage, XInsidePage,
  228. // TCPropertyPageBase::GetInsidePageOfGroup,
  229. // TCPropertyPageBase::GetDirtyInsidePageOfGroup,
  230. // TCPropertyPageBase::SetDirtyInsidePageOfGroup,
  231. // TCPropertyPageBase::ShowInsidePageOfGroup,
  232. // TCPropertyPageBase::HideInsidePageOfGroup,
  233. // TCPropertyPageBase::GetInsidePageText
  234. LPCTSTR TCPropertyPageBase::GetInsidePageOfGroupText(UINT idGroup, DWORD dw)
  235. {
  236. // Lookup the specified group/page
  237. XInsidePage* pPage = _GetInsidePageOfGroup(idGroup, dw);
  238. if (!pPage)
  239. return NULL;
  240. // Return the text pointer
  241. return pPage->m_pEntry->pszText;
  242. }
  243. /////////////////////////////////////////////////////////////////////////////
  244. // Description: Retrieves the state of the dirty flag of an embedded
  245. // property page within a group of embedded property pages.
  246. //
  247. // Retrieves the state of the dirty flag of the embedded property page
  248. // specified by /dw/, within the embedded property page group specified by
  249. // /idGroup/.
  250. //
  251. // Parameters:
  252. // idGroup - The identifier of the embedded property page group.
  253. // dw - The application-defined 32-bit (DWORD) value that uniquely
  254. // identifies the page within the page group.
  255. //
  256. // Return Value: *true* if the embedded property page's dirty flag is set and
  257. // /idGroup/ and /dw/ are valid. Otherwise, *false*.
  258. //
  259. // See Also: Embedded Property Page Table Macros,
  260. // TCInsidePropPage, XInsidePage,
  261. // TCPropertyPageBase::GetInsidePageOfGroup,
  262. // TCPropertyPageBase::GetInsidePageOfGroupText,
  263. // TCPropertyPageBase::SetDirtyInsidePageOfGroup,
  264. // TCPropertyPageBase::ShowInsidePageOfGroup,
  265. // TCPropertyPageBase::HideInsidePageOfGroup,
  266. // TCPropertyPageBase::GetDirtyInsidePage
  267. bool TCPropertyPageBase::GetDirtyInsidePageOfGroup(UINT idGroup, DWORD dw)
  268. {
  269. TCInsidePropPage* pPage = GetInsidePageOfGroup(idGroup, dw);
  270. return pPage ? pPage->Page_IsDirty() : false;
  271. }
  272. /////////////////////////////////////////////////////////////////////////////
  273. // Description: Modifies the state of the dirty flag of an embedded property
  274. // page within a group of embedded property pages.
  275. //
  276. // Modifies the state of the dirty flag of the embedded property page
  277. // specified by /dw/, within the embedded property page group specified by
  278. // /idGroup/.
  279. //
  280. // Parameters:
  281. // idGroup - The identifier of the embedded property page group.
  282. // dw - The application-defined 32-bit (DWORD) value that uniquely
  283. // identifies the page within the page group.
  284. // bDirty - The new state of the embedded property page's dirty flag. If
  285. // *true*, the embedded property page's state is marked as changed. If
  286. // *false*, it is marked as unchanged.
  287. //
  288. // See Also: Embedded Property Page Table Macros,
  289. // TCInsidePropPage, XInsidePage,
  290. // TCPropertyPageBase::GetInsidePageOfGroup,
  291. // TCPropertyPageBase::GetInsidePageOfGroupText,
  292. // TCPropertyPageBase::GetDirtyInsidePageOfGroup,
  293. // TCPropertyPageBase::ShowInsidePageOfGroup,
  294. // TCPropertyPageBase::HideInsidePageOfGroup,
  295. // TCPropertyPageBase::SetDirtyInsidePage
  296. void TCPropertyPageBase::SetDirtyInsidePageOfGroup(UINT idGroup,
  297. DWORD dw, bool bDirty)
  298. {
  299. TCInsidePropPage* pPage = GetInsidePageOfGroup(idGroup, dw);
  300. if (pPage)
  301. pPage->SetDirty(bDirty);
  302. }
  303. /////////////////////////////////////////////////////////////////////////////
  304. // Description: Retrieves a pointer to the currently visible embedded
  305. // property page within a group of embedded property pages.
  306. //
  307. // Retrieves a pointer to the currently visible embedded property page within
  308. // a group of embedded property pages.
  309. //
  310. // Only one property page, at most, within a group of embedded property pages
  311. // may be visible. In other words, the visibility of pages within a group is
  312. // mutually exclusive.
  313. //
  314. // Parameters:
  315. // idGroup - The identifier of the embedded property page group.
  316. //
  317. // Return Value: An TCInsidePropPage pointer to the currently visible
  318. // embedded property page within the group, if any. Otherwise, *NULL*. If
  319. // /idGroup/ is not valid, *NULL* is also returned.
  320. //
  321. // See Also: Embedded Property Page Table Macros,
  322. // TCInsidePropPage, XInsidePage,
  323. // TCPropertyPageBase::GetInsidePageOfGroup,
  324. // TCPropertyPageBase::GetInsidePageOfGroupText,
  325. // TCPropertyPageBase::GetDirtyInsidePageOfGroup,
  326. // TCPropertyPageBase::SetDirtyInsidePageOfGroup,
  327. // TCPropertyPageBase::ShowInsidePageOfGroup,
  328. // TCPropertyPageBase::HideInsidePageOfGroup
  329. TCInsidePropPage* TCPropertyPageBase::GetVisiblePageOfGroup(UINT idGroup)
  330. {
  331. // Find the specified group ID in the map of groups
  332. CPageGroupIterator itGroup = m_mapPageGroups.find(idGroup);
  333. if (m_mapPageGroups.end() == itGroup)
  334. return NULL;
  335. // Find the currently visible page in the group
  336. CPageMap* pmap = itGroup->second;
  337. for (CPageIterator it = pmap->begin(); it != pmap->end(); ++it)
  338. {
  339. XInsidePage* pPage = it->second;
  340. if (IsWindow(*pPage) && pPage->IsWindowVisible())
  341. return pPage;
  342. }
  343. // Couldn't find a visible page in the group
  344. return NULL;
  345. }
  346. /////////////////////////////////////////////////////////////////////////////
  347. // Group=Operations
  348. /////////////////////////////////////////////////////////////////////////////
  349. // Description: Makes the window visible of an embedded property page.
  350. //
  351. // Makes the window visible of the embedded property page specified by
  352. // /idCtrl/.
  353. //
  354. // Parameters:
  355. // idCtrl - The identifier of the embedded property page.
  356. //
  357. // Return Value: *true* if /idCtrl/ is valid and the operation completed
  358. // successfully. Otherwise, *false*.
  359. //
  360. // See Also: Embedded Property Page Table Macros,
  361. // TCInsidePropPage, XInsidePage,
  362. // TCPropertyPageBase::GetInsidePage,
  363. // TCPropertyPageBase::GetInsidePageData,
  364. // TCPropertyPageBase::GetInsidePageText,
  365. // TCPropertyPageBase::GetDirtyInsidePage,
  366. // TCPropertyPageBase::SetDirtyInsidePage,
  367. // TCPropertyPageBase::HideInsidePage,
  368. // TCPropertyPageBase::ShowInsidePageOfGroup
  369. bool TCPropertyPageBase::ShowInsidePage(UINT idCtrl)
  370. {
  371. TCInsidePropPage* pPage = GetInsidePage(idCtrl);
  372. return pPage ? (IsWindow(*pPage) && pPage->ShowWindow(SW_SHOW)) : false;
  373. }
  374. /////////////////////////////////////////////////////////////////////////////
  375. // Description: Hides the window of an embedded property page.
  376. //
  377. // Hides the window of the embedded property page specified by /idCtrl/.
  378. //
  379. // Parameters:
  380. // idCtrl - The identifier of the embedded property page.
  381. //
  382. // Return Value: *true* if /idCtrl/ is valid and the operation completed
  383. // successfully. Otherwise, *false*.
  384. //
  385. // See Also: Embedded Property Page Table Macros,
  386. // TCInsidePropPage, XInsidePage,
  387. // TCPropertyPageBase::GetInsidePage,
  388. // TCPropertyPageBase::GetInsidePageData,
  389. // TCPropertyPageBase::GetInsidePageText,
  390. // TCPropertyPageBase::GetDirtyInsidePage,
  391. // TCPropertyPageBase::SetDirtyInsidePage,
  392. // TCPropertyPageBase::ShowInsidePage,
  393. // TCPropertyPageBase::HideInsidePageOfGroup
  394. bool TCPropertyPageBase::HideInsidePage(UINT idCtrl)
  395. {
  396. TCInsidePropPage* pPage = GetInsidePage(idCtrl);
  397. return pPage ? (IsWindow(*pPage) && pPage->ShowWindow(SW_HIDE)) : false;
  398. }
  399. /////////////////////////////////////////////////////////////////////////////
  400. // Description: Makes the window visible of an embedded property page within
  401. // a group of embedded property pages, hiding any previously visible page
  402. // within the same group.
  403. //
  404. // Makes the window visible of the embedded property page specified by
  405. // /dw/, within the embedded property page group specified by /idGroup/. If
  406. // another page within the same group was visible it now becomes hidden.
  407. //
  408. // Only one property page, at most, within a group of embedded property pages
  409. // may be visible. In other words, the visibility of pages within a group is
  410. // mutually exclusive.
  411. //
  412. // Parameters:
  413. // idGroup - The identifier of the embedded property page group.
  414. // dw - The application-defined 32-bit (DWORD) value that uniquely
  415. // identifies the page within the page group.
  416. //
  417. // Return Value: *true* if /idGroup/ and /dw/ are valid and the operation
  418. // completed successfully. Otherwise, *false*.
  419. //
  420. // See Also: Embedded Property Page Table Macros,
  421. // TCInsidePropPage, XInsidePage,
  422. // TCPropertyPageBase::GetInsidePageOfGroup,
  423. // TCPropertyPageBase::GetInsidePageOfGroupData,
  424. // TCPropertyPageBase::GetInsidePageOfGroupText,
  425. // TCPropertyPageBase::GetDirtyInsidePageOfGroup,
  426. // TCPropertyPageBase::SetDirtyInsidePageOfGroup,
  427. // TCPropertyPageBase::HideInsidePageOfGroup,
  428. // TCPropertyPageBase::ShowInsidePage
  429. bool TCPropertyPageBase::ShowInsidePageOfGroup(UINT idGroup, DWORD dw)
  430. {
  431. // Find the specified group ID in the map of groups
  432. CPageGroupIterator itGroup = m_mapPageGroups.find(idGroup);
  433. if (m_mapPageGroups.end() == itGroup)
  434. return false;
  435. // Find the specified page in the group
  436. CPageMap* pmap = itGroup->second;
  437. CPageIterator itPage = pmap->find(dw);
  438. if (pmap->end() == itPage)
  439. return false;
  440. // Buffer the window positioning
  441. TCDeferWindowPosHandle hdwp = ::BeginDeferWindowPos(2);
  442. UINT uFlags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER;
  443. // Find the currently visible page in the group and hide it
  444. for (CPageIterator it = pmap->begin(); it != pmap->end(); ++it)
  445. {
  446. XInsidePage* pPage = it->second;
  447. if (IsWindow(*pPage) && pPage->IsWindowVisible())
  448. {
  449. if (itPage != it)
  450. ::DeferWindowPos(hdwp, *pPage, NULL, 0, 0, 0, 0,
  451. uFlags | SWP_HIDEWINDOW);
  452. break;
  453. }
  454. }
  455. // Show the specified property page, if not already visible
  456. if (itPage != it)
  457. {
  458. // Create the page, if not already created
  459. XInsidePage* pPage = itPage->second;
  460. if (pPage->m_hWnd || CreateInsidePage(pPage, true))
  461. ::DeferWindowPos(hdwp, *pPage, HWND_TOP, 0, 0, 0, 0,
  462. uFlags | SWP_SHOWWINDOW);
  463. }
  464. // Indicate success
  465. return true;
  466. }
  467. /////////////////////////////////////////////////////////////////////////////
  468. // Description: Hides the window of an embedded property page within a group
  469. // of embedded property pages.
  470. //
  471. // Hides the window of the embedded property page specified by /dw/, within
  472. // the embedded property page group specified by /idGroup/.
  473. //
  474. // Parameters:
  475. // idGroup - The identifier of the embedded property page group.
  476. // dw - The application-defined 32-bit (DWORD) value that uniquely
  477. // identifies the page within the page group.
  478. //
  479. // Return Value: *true* if /idGroup/ and /dw/ are valid and the operation
  480. // completed successfully. Otherwise, *false*.
  481. //
  482. // See Also: Embedded Property Page Table Macros,
  483. // TCInsidePropPage, XInsidePage,
  484. // TCPropertyPageBase::GetInsidePageOfGroup,
  485. // TCPropertyPageBase::GetInsidePageOfGroupData,
  486. // TCPropertyPageBase::GetInsidePageOfGroupText,
  487. // TCPropertyPageBase::GetDirtyInsidePageOfGroup,
  488. // TCPropertyPageBase::SetDirtyInsidePageOfGroup,
  489. // TCPropertyPageBase::ShowInsidePageOfGroup,
  490. // TCPropertyPageBase::HideInsidePage
  491. bool TCPropertyPageBase::HideInsidePageOfGroup(UINT idGroup, DWORD dw)
  492. {
  493. // Lookup the specified group/page
  494. XInsidePage* pPage = _GetInsidePageOfGroup(idGroup, dw);
  495. if (!pPage)
  496. return false;
  497. // Hide the window, if it's valid
  498. if (IsWindow(*pPage))
  499. pPage->ShowWindow(SW_HIDE);
  500. // Indicate success
  501. return true;
  502. }
  503. /////////////////////////////////////////////////////////////////////////////
  504. // Group=Overrides
  505. /////////////////////////////////////////////////////////////////////////////
  506. // Description: Override to allow derived classes a proper place to
  507. // initialize user interface elements.
  508. //
  509. // A derived class should override this method to perform initialization that
  510. // needs to be done only when the property page dialog is first created. Such
  511. // initialization typically includes attaching member variables to fields on
  512. // the dialog box.
  513. //
  514. // Note: This is *not* the appropriate place to initialize the /values/ of
  515. // the dialog box fields. For more information on such initialization, see
  516. // the Property Page Field Update Macros.
  517. //
  518. // This method is called by the OnInitDialogHandler method, which is the
  519. // message handler for the *WM_INITDIALOG* message. When this method is
  520. // called, the following conditions are guaranteed:
  521. //
  522. // + The m_bInitializing flag is set to *true*.
  523. // + Embedded property pages specified in the property page table, if any,
  524. // have been created.
  525. // + Advisory connections with the set of objects being edited/viewed, if
  526. // any, have been established.
  527. //
  528. // Following the return from this method, the UpdateFields method is called,
  529. // which, in turn, will call the update methods specified in the entries of
  530. // the property field map.
  531. //
  532. // Return Value: The default return value is *false*, indicating that the
  533. // input focus should not be set to the first tabstop control.
  534. //
  535. // Note: The return value is effectively *void* since the base class
  536. // currently ignores it. Input focus control is not given to the derived
  537. // classes.
  538. //
  539. // See Also: Property Page Field Update Macros,
  540. // TCPropertyPageBase::OnInitDialogHandler
  541. bool TCPropertyPageBase::OnInitDialog()
  542. {
  543. // Return false to not set focus to the first tabstop control
  544. return false;
  545. }
  546. /////////////////////////////////////////////////////////////////////////////
  547. // Description: Override to allow derived classes to specify a table of
  548. // embedded property pages.
  549. //
  550. // Overridden by derived classes to specify a table of embedded property
  551. // pages. This table is used by the CreateInsidePages method.
  552. //
  553. // Note: A derived class should *not* override this method directly. Instead,
  554. // the derived class should use the Embedded Property Page Table Macros,
  555. // which provide the proper override of this method.
  556. //
  557. // Parameters:
  558. // ppTable - [out] A pointer to where the address of the table is to be
  559. // returned.
  560. // iTable - [in] Specifies the index of the page table which is being
  561. // requested. Most property pages have only 1 table, with an index of zero.
  562. // For more information on alternate page tables, see the ALT_INSIDE_PAGE_MAP
  563. // macro.
  564. //
  565. // Return Value: The number of entries in the page table returned thru the
  566. // /ppTable/ parameter. The default implementation returns zero.
  567. //
  568. // See Also: Embedded Property Page Table Macros, XInsidePageEntry
  569. // TCPropertyPageBase::CreateInsidePages
  570. UINT TCPropertyPageBase::GetInsidePageTable(
  571. const XInsidePageEntry** ppTable, UINT iTable)
  572. {
  573. UNUSED(iTable);
  574. // Default does nothing
  575. if (ppTable)
  576. *ppTable = NULL;
  577. return 0;
  578. }
  579. /////////////////////////////////////////////////////////////////////////////
  580. // Description: Override to allow derived classes to establish any further
  581. // advisory connections with the objects being edited/viewed.
  582. //
  583. // This method is called to allow a derived class an appropriate place to
  584. // establish advisory connections with the objects being edited/viewed.
  585. //
  586. // Note: It is *not* necessary to connect *IPropertyNotifySink* advises here,
  587. // since that is done automatically by the SetAllAdvises method, based on the
  588. // entries in the property field map. Therefore, this override is provided
  589. // only for the possible cases when connections *other* than
  590. // *IPropertyNotifySink* need to be established.
  591. //
  592. // Any advisory connections established in this method should be disconnected
  593. // in the derived class's override of OnClearAllAdvises.
  594. //
  595. // This method is called by the SetAllAdvises method, which is called from
  596. // both the SetObjects and OnInitDialogHandler methods. When this method is
  597. // called, the following conditions are guaranteed:
  598. //
  599. // + The property page is active, meaning that a window has been created for
  600. // the page.
  601. // + All *IPropertyNotifySink* advisory connections, if any, have already
  602. // been established, based on the entries in the property field map.
  603. // + The set of objects specified by the /cObjects/ and /ppUnk/ parameters
  604. // has been filtered down to only the set of objects that support the
  605. // interfaces specified by the entries of the property field map. This does
  606. // *not* include the property field map of any embedded property pages.
  607. //
  608. // Note: To assist with establishing advisory connections, consider using the
  609. // TCAdviseHolder class, of which instances can be stored in a collection.
  610. //
  611. // The default implementation of this method does nothing.
  612. //
  613. // Parameters:
  614. // cObjects - [in] Number of *IUnknown* pointers in the array pointed to by
  615. // /ppUnk/.
  616. // ppUnk - [in] Pointer to an array of *IUnknown* interface pointers, which
  617. // represents the set of objects being edited/viewed by this property page.
  618. //
  619. // See Also: Property Page Field Update Macros,
  620. // TCPropertyPageBase::OnClearAllAdvises,
  621. // TCPropertyPageBase::SetAllAdvises,
  622. // TCPropertyPageBase::OnInitDialogHandler
  623. void TCPropertyPageBase::OnSetAllAdvises(ULONG cObjects, IUnknown** ppUnk)
  624. {
  625. UNUSED(cObjects);
  626. UNUSED(ppUnk);
  627. }
  628. /////////////////////////////////////////////////////////////////////////////
  629. // Description: Override to allow derived classes to disconnect any advisory
  630. // connections established in OnSetAllAdvises.
  631. //
  632. // This method is called to allow a derived class an appropriate place to
  633. // disconnect advisory connections previously established with the objects
  634. // being edited/viewed.
  635. //
  636. // Note: It is *not* necessary to disconnect *IPropertyNotifySink* advises
  637. // here, since that is done automatically by the ClearAllAdvises method.
  638. //
  639. // The advisory connections disconnected in this method should exactly match
  640. // those established in the derived class's override of OnSetAllAdvises.
  641. //
  642. // This method is called by the ClearAllAdvises method, which is called from
  643. // both the SetObjects and OnNcDestroyHandler methods. When this method is
  644. // called, the following condition is guaranteed:
  645. //
  646. // + All established *IPropertyNotifySink* advisory connections, if any, have
  647. // not yet been broken.
  648. //
  649. // Following the return from this method, all established
  650. // *IPropertyNotifySink* advisory connections, if any, will be disconnected.
  651. //
  652. // Note: If the TCAdviseHolder class was used to establish a connection, it
  653. // will be broken when the instance is destroyed. So, if a collection of them
  654. // were being maintained, simply erasing the contents of the collection would
  655. // break the connections. This assumes, of course, that the collection holds
  656. // actual instances, rather than pointers to instances.
  657. //
  658. // The default implementation of this method does nothing.
  659. //
  660. // See Also: Property Page Field Update Macros,
  661. // TCPropertyPageBase::OnSetAllAdvises,
  662. // TCPropertyPageBase::SetAllAdvises,
  663. // TCPropertyPageBase::OnNcDestroyHandler
  664. void TCPropertyPageBase::OnClearAllAdvises()
  665. {
  666. }
  667. /////////////////////////////////////////////////////////////////////////////
  668. // Group=Implementation
  669. /////////////////////////////////////////////////////////////////////////////
  670. // Description: Creates the window of an embedded property page.
  671. //
  672. // This method is used by the implementation to create the window of the
  673. // specified embedded property page.
  674. //
  675. // Parameters:
  676. // pPage - The embedded property page instance for which a window is to be
  677. // created.
  678. // bOfGroup - Indicator of whether or not /pPage/ is a page belonging to a
  679. // mutually exclusive group of embedded property pages. *true* indicates
  680. // that it is a member of a group; *false* indicates that it is not.
  681. //
  682. // Return Value: *true* if the page was successfully created; otherwise
  683. // *false*.
  684. //
  685. // See Also: XInsidePage, TCPropertyPageBase::CreateInsidePages
  686. bool TCPropertyPageBase::CreateInsidePage(XInsidePage* pPage, bool bOfGroup)
  687. {
  688. // Save the focus window
  689. HWND hwndFocus = GetFocus();
  690. // Create the page
  691. HRESULT hr = SetObjectsToInsidePage(pPage);
  692. bool bCreated = pPage->Create(GetPageWindow(),
  693. IPropertyPageSitePtr(GetPageUnknown()), pPage->m_pEntry->idPosCtrl,
  694. *pPage->m_pEntry->pclsid, pPage->m_pEntry->bVisible,
  695. pPage->m_pEntry->bSizeToCtrl, !bOfGroup);
  696. #ifdef _DEBUG
  697. if (!bCreated)
  698. {
  699. char sz1[64], sz3[64];
  700. sprintf(sz1, "TCPropertyPageImpl<%hs>::CreateInsidePage", TypeName());
  701. LPCSTR sz2 = "Failed to create child property page ";
  702. if (!bOfGroup)
  703. sprintf(sz3, "with control id 0x%08X.", pPage->m_pEntry->idPosCtrl);
  704. else
  705. sprintf(sz3, "in page group 0x%08X with DWORD value 0x%08X.",
  706. pPage->m_pEntry->idPosCtrl, pPage->m_pEntry->dwData);
  707. _TRACE3("%hs%hs%hs\n", sz1, sz2, sz3);
  708. assert(bCreated);
  709. }
  710. #endif
  711. // Restore the focus to the previous focus window
  712. SetFocus(hwndFocus);
  713. return bCreated;
  714. }
  715. /////////////////////////////////////////////////////////////////////////////
  716. // Description: Creates the embedded property pages specified in the property
  717. // page map.
  718. //
  719. // This method is used by the implementation to create all the embedded
  720. // property pages specified in the property page map.
  721. //
  722. // This method loops thru the entries of the derived class's property page
  723. // map and creates an XInsidePage instance. Throughout this process, the
  724. // entries that represent pages within a group are seperated out and stored
  725. // appropriately.
  726. //
  727. // Once the objects are created, grouped, and stored, the pages that are to
  728. // be initially visible are created by calling the CreateInsidePage method.
  729. //
  730. // See Also: Embedded Property Page Table Macros, XInsidePageEntry,
  731. // XInsidePage, TCPropertyPageBase::CPageMap,
  732. // TCPropertyPageBase::CreateInsidePage,
  733. // TCPropertyPageBase::DestroyInsidePages
  734. void TCPropertyPageBase::CreateInsidePages()
  735. {
  736. // Get the table of child property pages
  737. const XInsidePageEntry* pEntries = NULL;
  738. UINT nCount = GetInsidePageTable(&pEntries, m_iTable);
  739. if (!nCount)
  740. return;
  741. // Seperate the group entries
  742. for (UINT i = 0; i < nCount; i++)
  743. {
  744. // Get the next entry in the table
  745. const XInsidePageEntry& entry = pEntries[i];
  746. UINT idCtrl = entry.idPosCtrl;
  747. // Find the entry's control ID in the map of pages
  748. CPageIterator it = m_mapPages.find(idCtrl);
  749. if (m_mapPages.end() == it)
  750. {
  751. // Find the entry's control ID in the map of page groups
  752. CPageGroupIterator itGroup = m_mapPageGroups.find(idCtrl);
  753. if (m_mapPageGroups.end() == itGroup)
  754. {
  755. // Map the control ID to a new page
  756. XInsidePage* pPage = new XInsidePage(&entry);
  757. CPageMap::value_type value(idCtrl, pPage);
  758. m_mapPages.insert(value);
  759. }
  760. else
  761. {
  762. // Get the page map for the group
  763. CPageMap* pmap = itGroup->second;
  764. // Map the DWORD value to a new page
  765. DWORD dw = entry.dwData;
  766. XInsidePage* pPage = new XInsidePage(&entry);
  767. CPageMap::value_type value(dw, pPage);
  768. bool bInserted = pmap->insert(value).second;
  769. if (!bInserted)
  770. {
  771. delete pPage;
  772. #ifdef _DEBUG
  773. char sz[_MAX_PATH];
  774. sprintf(sz, "TCPropertyPageImpl<%hs>::CreateInsidePages(): "
  775. "More than one entry\n\tin page group 0x%08X, was specified "
  776. "with a DWORD value of 0x%08x.\n\tDuplicate is being ignored.",
  777. TypeName(), idCtrl, dw);
  778. _TRACE1("%hs\n", sz);
  779. assert(bInserted);
  780. #endif
  781. }
  782. }
  783. }
  784. else
  785. {
  786. // Map the control ID to a new page group
  787. CPageMap* pPageMap = new CPageMap;
  788. CPageGroupMap::value_type valuePageMap(idCtrl, pPageMap);
  789. m_mapPageGroups.insert(valuePageMap);
  790. // Move the located page to the new page group
  791. XInsidePage* pPage = it->second;
  792. CPageMap::value_type valuePage(pPage->m_pEntry->dwData, pPage);
  793. pPageMap->insert(valuePage);
  794. m_mapPages.erase(it);
  795. // Repeat the loop iteration to add the new page to the new page group
  796. --i;
  797. }
  798. }
  799. // Create each page marked as visible
  800. for (CPageIterator it = m_mapPages.begin(); it != m_mapPages.end(); ++it)
  801. {
  802. XInsidePage* pPage = it->second;
  803. const XInsidePageEntry& entry = *pPage->m_pEntry;
  804. if (entry.bVisible)
  805. CreateInsidePage(pPage, false);
  806. }
  807. // Create, at most, one page marked as visible in each page group
  808. CPageGroupIterator itGroup = m_mapPageGroups.begin();
  809. for (; itGroup != m_mapPageGroups.end(); ++itGroup)
  810. {
  811. #ifdef _DEBUG
  812. bool bOneIsVisible = false;
  813. #endif // _DEBUG
  814. CPageMap* pmap = itGroup->second;
  815. for (CPageIterator it = pmap->begin(); it != pmap->end(); ++it)
  816. {
  817. XInsidePage* pPage = it->second;
  818. const XInsidePageEntry& entry = *pPage->m_pEntry;
  819. if (entry.bVisible)
  820. {
  821. #ifdef _DEBUG
  822. if (bOneIsVisible)
  823. {
  824. char sz[_MAX_PATH];
  825. sprintf(sz, "TCPropertyPageImpl<%hs>::CreateInsidePages(): "
  826. "More than one entry\n\tin page group 0x%08X was specified"
  827. "with a bVisible value of true.\n\tOnly the first one has"
  828. "been created.", TypeName(), entry.idPosCtrl);
  829. _TRACE1("%hs\n", sz);
  830. assert(!bOneIsVisible);
  831. }
  832. #endif // _DEBUG
  833. if (CreateInsidePage(pPage, true))
  834. {
  835. #ifdef _DEBUG
  836. bOneIsVisible = true;
  837. #else // _DEBUG
  838. break;
  839. #endif // _DEBUG
  840. }
  841. }
  842. }
  843. }
  844. }
  845. /////////////////////////////////////////////////////////////////////////////
  846. // Description: Destroys all instances of embedded property pages.
  847. //
  848. // This method is used by the implementation to destroy all instances of
  849. // embedded property pages, if any. This includes page groups and the pages
  850. // within them.
  851. //
  852. // See Also: TCPropertyPageBase::DestroyInsidePageMap
  853. void TCPropertyPageBase::DestroyInsidePages()
  854. {
  855. // Destroy the main page map
  856. DestroyInsidePageMap(&m_mapPages);
  857. // Destroy the page map of each page group
  858. CPageGroupIterator it;
  859. for (it = m_mapPageGroups.begin(); it != m_mapPageGroups.end(); ++it)
  860. {
  861. CPageMap* pmap = it->second;
  862. DestroyInsidePageMap(pmap);
  863. delete pmap;
  864. }
  865. // Clear the page group map
  866. m_mapPageGroups.clear();
  867. }
  868. /////////////////////////////////////////////////////////////////////////////
  869. // Description: Destroys all embedded property pages within a specified map.
  870. //
  871. // This method is used by the implementation to destroy all embedded property
  872. // pages within the specified map and clear the map of all entries.
  873. //
  874. // Parameters:
  875. // pmap - A pointer to the page map for whose pages are to be destroyed.
  876. //
  877. // See Also: TCPropertyPageBase::DestroyInsidePages,
  878. // TCPropertyPageBase::CPageMap
  879. void TCPropertyPageBase::DestroyInsidePageMap(
  880. TCPropertyPageBase::CPageMap* pmap)
  881. {
  882. // Loop thru each page of the specified map
  883. for (CPageIterator it = pmap->begin(); it != pmap->end(); ++it)
  884. {
  885. // Get the next page
  886. XInsidePage* pPage = it->second;
  887. // Ensure that the page window is destroyed
  888. assert(!IsWindow(*pPage));
  889. // Delete the page object
  890. delete pPage;
  891. }
  892. // Clear the map of all dead page entries
  893. pmap->clear();
  894. }
  895. /////////////////////////////////////////////////////////////////////////////
  896. // Description: Retrieves a pointer to an embedded property page, and ensures
  897. // that a window is created for the page.
  898. //
  899. // This method is used by the implementation to retrieve a pointer to the
  900. // embedded property page specified by /idCtrl/. If the page is not active
  901. // (does not have a window created for it), it calls CreateInsidePage to
  902. // create the window.
  903. //
  904. // Parameters:
  905. // idCtrl - The identifier of the embedded property page.
  906. //
  907. // Return Value: An XInsidePage pointer to the embedded property page if
  908. // /idCtrl/ is valid. Otherwise, *NULL*.
  909. //
  910. // See Also: Embedded Property Page Table Macros, XInsidePage,
  911. // TCPropertyPageBase::GetInsidePage,
  912. // TCPropertyPageBase::_GetInsidePageOfGroup
  913. XInsidePage* TCPropertyPageBase::_GetInsidePage(UINT idCtrl)
  914. {
  915. // Find the specified control ID in the map of pages
  916. CPageIterator it = m_mapPages.find(idCtrl);
  917. if (m_mapPages.end() == it)
  918. return NULL;
  919. // Create the page, if not already created
  920. XInsidePage* pPage = it->second;
  921. if (!pPage->m_hWnd)
  922. return CreateInsidePage(pPage, false) ? pPage : NULL;
  923. return pPage;
  924. }
  925. /////////////////////////////////////////////////////////////////////////////
  926. // Description: Retrieves a pointer to an embedded property page within a
  927. // group of embedded property pages, and ensures that a window is created for
  928. // the page.
  929. //
  930. // This method is used by the implementation to retrieve a pointer to the
  931. // embedded property page specified by /dw/, within the embedded property
  932. // page group specified by /idGroup/. If the page is not active (does not
  933. // have a window created for it), it calls CreateInsidePage to create the
  934. // window.
  935. //
  936. // Parameters:
  937. // idGroup - The identifier of the embedded property page group.
  938. // dw - The application-defined 32-bit (DWORD) value that uniquely
  939. // identifies the page within the page group.
  940. //
  941. // Return Value: An XInsidePage pointer to the embedded property page if
  942. // /idGroup/ and /dw/ are valid. Otherwise, *NULL*.
  943. //
  944. // See Also: Embedded Property Page Table Macros, XInsidePage,
  945. // TCPropertyPageBase::GetInsidePageOfGroup,
  946. // TCPropertyPageBase::_GetInsidePage
  947. XInsidePage* TCPropertyPageBase::_GetInsidePageOfGroup(UINT idGroup,
  948. DWORD dw)
  949. {
  950. // Find the specified group ID in the map of groups
  951. CPageGroupIterator itGroup = m_mapPageGroups.find(idGroup);
  952. if (m_mapPageGroups.end() == itGroup)
  953. return NULL;
  954. // Find the specified DWORD value in the map of pages for the group
  955. CPageMap* pmap = itGroup->second;
  956. CPageIterator it = pmap->find(dw);
  957. if (pmap->end() == it)
  958. return NULL;
  959. // Return the page
  960. XInsidePage* pPage = it->second;
  961. return pPage;
  962. }
  963. /////////////////////////////////////////////////////////////////////////////
  964. // Description: Filters a set of objects based on the entries in the property
  965. // field map.
  966. //
  967. // This method is used by the implementation to filter the specified set of
  968. // objects. Only the objects that support interfaces specified in the entries
  969. // of the property field map are copied to the destination array.
  970. //
  971. // This method first forwards the specified set of objects to each embedded
  972. // property page, including those within groups. It does this by calling the
  973. // SetObjectsOfInsidePages method. This gives each embedded property page the
  974. // opportunity to perform its own filtering from the original set of objects.
  975. //
  976. // Next, the method releases the previous set of interface pointers specified
  977. // by the /cObjectsDest/ and /ppUnkDest/ parameters and deletes the array. A
  978. // new array is then created and stored in the same parameters. The new array
  979. // is populated with the filtered set of objects.
  980. //
  981. // Finally, if the property page is active (a window has been created for
  982. // it), the UpdateFields and SetAllAdvises methods are called. If the page is
  983. // not active, those method calls are deferred to OnInitDialogHandler, which
  984. // will be called when the page does become active.
  985. //
  986. // TODO: Shouldn't the advises be set /prior/ to UpdateFields?
  987. //
  988. // Parameters:
  989. // cObjectsDest - [in, out] A reference to the number of *IUnknown* „
  990. // pointers in the array pointed to by /ppUnkDest/. The referenced variable
  991. // also receives the count of filtered objects upon return.
  992. // ppUnkDest - [in, out] A reference to a pointer to an array of
  993. // *IUnknown* interface pointers which is replaced with a pointer to the
  994. // filtered array of objects upon return.
  995. // cObjects - [in] The number of *IUnknown* pointers in the array pointed
  996. // to by /ppUnk/.
  997. // ppUnk - [in] A pointer to an array of *IUnknown* interface pointers
  998. // where each pointer identifies a unique object affected by the property
  999. // page. This array is considered the /original/ set, from which the
  1000. // /filtered/ set is determined.
  1001. //
  1002. // See Also: Property Page Field Update Macros,
  1003. // TCPropertyPageBase::SetObjectsOfInsidePages,
  1004. // TCPropertyPageBase::UpdateFields,
  1005. // TCPropertyPageBase::SetAllAdvises,
  1006. // TCPropertyPageBase::OnInitDialogHandler
  1007. HRESULT TCPropertyPageBase::SetObjects(ULONG& cObjectsDest,
  1008. IUnknown**& ppUnkDest, ULONG cObjects, IUnknown** ppUnk)
  1009. {
  1010. // Only save each object that this page knows how to talk to
  1011. HRESULT hr = S_OK;
  1012. CUnkVector pVec = NULL;
  1013. __try
  1014. {
  1015. // Forward the method to each embedded property page, including groups
  1016. if (SUCCEEDED(hr = SetObjectsOfInsidePages(cObjects, ppUnk)))
  1017. {
  1018. // Loop thru the specified objects, filtering out the unknown ones
  1019. ReleaseSupportedInterfaces();
  1020. CUnkVector& vec = *(pVec = new CUnkVector);
  1021. for (ULONG i = 0; i < cObjects; i++)
  1022. if (ppUnk[i] && IsObjectKnown(ppUnk[i]))
  1023. vec.push_back(ppUnk[i]);
  1024. // Release the previous set of destination interface pointers
  1025. for (UINT iObj = 0; iObj < cObjectsDest; ++iObj)
  1026. ppUnkDest[iObj]->Release();
  1027. if (ppUnkDest != NULL)
  1028. {
  1029. delete [] ppUnkDest;
  1030. ppUnkDest = NULL;
  1031. cObjectsDest = 0;
  1032. }
  1033. assert(0 == cObjectsDest);
  1034. // Save the filtered objects in the specified destination fields
  1035. if (vec.size())
  1036. {
  1037. ATLTRY(ppUnkDest = new IUnknown*[vec.size()]);
  1038. if (NULL == ppUnkDest)
  1039. hr = E_OUTOFMEMORY;
  1040. else
  1041. {
  1042. for (i = 0; i < vec.size(); ++i)
  1043. (ppUnkDest[i] = vec[i])->AddRef();
  1044. cObjectsDest = vec.size();
  1045. }
  1046. }
  1047. // Populate the dialog fields and set all advises, if the window exists
  1048. if (SUCCEEDED(hr) && ::IsWindow(GetPageWindow()))
  1049. {
  1050. // TODO: Shouldn't the advises be set /prior/ to UpdateFields?
  1051. UpdateFields();
  1052. SetAllAdvises(cObjectsDest, ppUnkDest);
  1053. }
  1054. }
  1055. }
  1056. __except(1)
  1057. {
  1058. _TRACE1(
  1059. "TCPropertyPageBase[%hs]::SetObjects(): Unknown Exception Caught!\n",
  1060. TypeName());
  1061. // Remove and unadvise all connections
  1062. ClearAllAdvises();
  1063. // Release any objects saved for inside pages
  1064. ReleaseObjectsForInsidePages();
  1065. // Release the previous set of interface pointers
  1066. ReleaseSupportedInterfaces();
  1067. for (UINT iObj = 0; iObj < cObjectsDest; ++iObj)
  1068. ppUnkDest[iObj]->Release();
  1069. if (ppUnkDest != NULL)
  1070. {
  1071. delete [] ppUnkDest;
  1072. ppUnkDest = NULL;
  1073. cObjectsDest = 0;
  1074. }
  1075. // Update dialog fields from objects, if the window exists
  1076. if (::IsWindow(GetPageWindow()))
  1077. UpdateFields();
  1078. // Interpret the exception as a server exception
  1079. hr = RPC_E_SERVERFAULT;
  1080. }
  1081. // Delete the vector object, if we used one
  1082. if (pVec)
  1083. delete pVec;
  1084. // Return last result
  1085. return hr;
  1086. }
  1087. /////////////////////////////////////////////////////////////////////////////
  1088. // Description: Forwards the original set of objects to each embedded
  1089. // property page, if any.
  1090. //
  1091. // This method is used by the implementation to forward the original set of
  1092. // objects to each embedded property page, if any. This gives each embedded
  1093. // property page the opportunity to perform its own filtering from the
  1094. // original set of objects.
  1095. //
  1096. // Parameters:
  1097. // cObjects - [in] The number of *IUnknown* pointers in the array pointed
  1098. // to by /ppUnk/.
  1099. // ppUnk - [in] A pointer to an array of *IUnknown* interface pointers
  1100. // where each pointer identifies a unique object affected by the property
  1101. // page.
  1102. //
  1103. // See Also: Embedded Property Page Table Macros, XInsidePage,
  1104. // TCPropertyPageBase::SetObjects,
  1105. // TCPropertyPageBase::SaveObjectsForInsidePages
  1106. HRESULT TCPropertyPageBase::SetObjectsOfInsidePages(ULONG cObjects,
  1107. IUnknown** ppUnk)
  1108. {
  1109. // Save the entire array of objects for use by inside pages
  1110. SaveObjectsForInsidePages(cObjects, ppUnk);
  1111. // Forward the method to each embedded property page
  1112. for (CPageIterator it = m_mapPages.begin(); it != m_mapPages.end(); ++it)
  1113. {
  1114. XInsidePage* pPage = it->second;
  1115. if (pPage->m_hWnd)
  1116. RETURN_FAILED(pPage->SetObjects(cObjects, ppUnk));
  1117. }
  1118. // Forward the method to each embedded property page of each group
  1119. CPageGroupIterator itGroup = m_mapPageGroups.begin();
  1120. for (; itGroup != m_mapPageGroups.end(); ++itGroup)
  1121. {
  1122. CPageMap* pmap = itGroup->second;
  1123. for (CPageIterator it = pmap->begin(); it != pmap->end(); ++it)
  1124. {
  1125. XInsidePage* pPage = it->second;
  1126. if (pPage->m_hWnd)
  1127. RETURN_FAILED(pPage->SetObjects(cObjects, ppUnk));
  1128. }
  1129. }
  1130. // Indicate success
  1131. return S_OK;
  1132. }
  1133. /////////////////////////////////////////////////////////////////////////////
  1134. // Description: Saves the original set of objects in order to be able to
  1135. // forward them on to any new embedded property pages, if any.
  1136. //
  1137. // This method is used by the implementation to save the original set of
  1138. // objects. This allows any new embedded property pages to be given the
  1139. // opportunity to perform its own filtering from the original set of
  1140. // objects.
  1141. //
  1142. // Parameters:
  1143. // cObjects - [in] The number of *IUnknown* pointers in the array pointed
  1144. // to by /ppUnk/.
  1145. // ppUnk - [in] A pointer to an array of *IUnknown* interface pointers
  1146. // where each pointer identifies a unique object affected by the property
  1147. // page.
  1148. //
  1149. // See Also: Embedded Property Page Table Macros, XInsidePage,
  1150. // TCPropertyPageBase::SetObjects,
  1151. // TCPropertyPageBase::SetObjectsOfInsidePages
  1152. void TCPropertyPageBase::SaveObjectsForInsidePages(ULONG cObjects,
  1153. IUnknown** ppUnk)
  1154. {
  1155. // Do nothing if there are no table entries
  1156. if (!GetInsidePageTable(NULL, m_iTable))
  1157. return;
  1158. // Release any current array of objects
  1159. ReleaseObjectsForInsidePages();
  1160. // Copy the specified array of objects
  1161. m_vecForInsidePages.resize(cObjects, NULL);
  1162. for (ULONG i = 0; i < cObjects; ++i)
  1163. {
  1164. IUnknown* punk = ppUnk[i];
  1165. m_vecForInsidePages[i] = punk;
  1166. if (punk)
  1167. punk->AddRef();
  1168. }
  1169. }
  1170. /////////////////////////////////////////////////////////////////////////////
  1171. // Description: Forwards the original set of objects to an embedded property
  1172. // page when it is first created.
  1173. //
  1174. // This method is used by the implementation to forward the original set of
  1175. // objects to the embedded property page specified byt /pPage/. The original
  1176. // set of objects is saved by the SaveObjectsForInsidePages method. This
  1177. // allows the freshly-created embedded property page the opportunity to
  1178. // perform its own filtering from the original set of objects.
  1179. //
  1180. // Parameters:
  1181. // pPage - A pointer to the embedded property page just create, to which
  1182. // the original set of objects will be forwarded.
  1183. //
  1184. // See Also: Embedded Property Page Table Macros, TCInsidePropPage,
  1185. // TCPropertyPageBase::SaveObjectsForInsidePages,
  1186. // TCPropertyPageBase::CreateInsidePage
  1187. HRESULT TCPropertyPageBase::SetObjectsToInsidePage(TCInsidePropPage* pPage)
  1188. {
  1189. ULONG cObjects = m_vecForInsidePages.size();
  1190. IUnknown** ppUnk = m_vecForInsidePages.begin();
  1191. return pPage->SetObjects(cObjects, ppUnk);
  1192. }
  1193. /////////////////////////////////////////////////////////////////////////////
  1194. // Description: Forwards the /Apply/ operation to each embedded property
  1195. // page, if any.
  1196. //
  1197. // This method is used by the implementation to forward the /Apply/ operation
  1198. // to each embedded property page, if any.
  1199. //
  1200. // See Also: Embedded Property Page Table Macros, XInsidePage,
  1201. // TCPropertyPageImpl::Apply
  1202. HRESULT TCPropertyPageBase::ApplyToInsidePages()
  1203. {
  1204. // Forward the method to each embedded property page
  1205. for (CPageIterator it = m_mapPages.begin(); it != m_mapPages.end(); ++it)
  1206. {
  1207. XInsidePage* pPage = it->second;
  1208. if ((IsWindow(*pPage) && pPage->IsWindowVisible())
  1209. || pPage->m_pEntry->bAlwaysApply)
  1210. RETURN_FAILED(pPage->Page_Apply());
  1211. }
  1212. // Forward the method to each embedded property page of each group
  1213. CPageGroupIterator itGroup = m_mapPageGroups.begin();
  1214. for (; itGroup != m_mapPageGroups.end(); ++itGroup)
  1215. {
  1216. CPageMap* pmap = itGroup->second;
  1217. CPageIterator itVisible = pmap->end();
  1218. for (CPageIterator it = pmap->begin(); it != pmap->end(); ++it)
  1219. {
  1220. XInsidePage* pPage = it->second;
  1221. if (IsWindow(*pPage))
  1222. {
  1223. if (pPage->IsWindowVisible())
  1224. itVisible = it;
  1225. else if (pPage->m_pEntry->bAlwaysApply)
  1226. RETURN_FAILED(pPage->Page_Apply());
  1227. }
  1228. }
  1229. if (pmap->end() != itVisible)
  1230. {
  1231. XInsidePage* pPage = itVisible->second;
  1232. RETURN_FAILED(pPage->Page_Apply());
  1233. }
  1234. }
  1235. // Indicate success
  1236. return S_OK;
  1237. }
  1238. /////////////////////////////////////////////////////////////////////////////
  1239. // Description: Releases the original set of objects that are maintained for
  1240. // when a new embedded property page is created.
  1241. //
  1242. // This method is used by the implementation to release the original set of
  1243. // objects that were saved by the SaveObjectsForInsidePages method.
  1244. //
  1245. // See Also: Embedded Property Page Table Macros,
  1246. // TCPropertyPageBase::SaveObjectsForInsidePages
  1247. void TCPropertyPageBase::ReleaseObjectsForInsidePages()
  1248. {
  1249. CUnkIterator it = m_vecForInsidePages.begin();
  1250. for (; it != m_vecForInsidePages.end(); ++it)
  1251. {
  1252. IUnknown* punk = *it;
  1253. if (punk)
  1254. punk->Release();
  1255. }
  1256. m_vecForInsidePages.clear();
  1257. }
  1258. /////////////////////////////////////////////////////////////////////////////
  1259. // Description: Releases the set of interfaces supported by this property
  1260. // page.
  1261. //
  1262. // This method is used by the implementation to release the set of interfaces
  1263. // supported by this property page, as previously determined from the
  1264. // property field map by the CreateInsidePages method.
  1265. //
  1266. // See Also: Property Page Field Update Macros,
  1267. // TCPropertyPageBase::CreateInsidePages
  1268. void TCPropertyPageBase::ReleaseSupportedInterfaces()
  1269. {
  1270. CUnkVectorMap::iterator it = m_mapInterfaces.begin();
  1271. for (; m_mapInterfaces.end() != it; ++it)
  1272. {
  1273. CUnkVector& vec = it->second;
  1274. for (CUnkIterator itUnk = vec.begin(); vec.end() != itUnk; ++itUnk)
  1275. {
  1276. IUnknown* punk = *itUnk;
  1277. punk->Release();
  1278. }
  1279. vec.clear();
  1280. }
  1281. }
  1282. /////////////////////////////////////////////////////////////////////////////
  1283. // Description: Establishes *IPropertyNotifySink* advisory connections with
  1284. // each of the specified objects.
  1285. //
  1286. // This method is used by the implementation to establish
  1287. // *IPropertyNotifySink* advisory connections with each of the specified
  1288. // objects. Special care is taken to ensure that an objects that is already
  1289. // connected is not broken and immediately reconnected, which would incur
  1290. // unnecessary DCOM round-trips.
  1291. //
  1292. // After established all of the connections, the OnSetAllAdvises virtual
  1293. // override is called to allow the derived class an opportunity to establish
  1294. // any other advisory connections it may need.
  1295. //
  1296. //
  1297. // See Also: TCPropertyPageBase::ClearAllAdvises,
  1298. // TCPropertyPageBase::SetAdvises, TCPropertyPageBase::OnSetAllAdvises
  1299. void TCPropertyPageBase::SetAllAdvises(ULONG cObjects, IUnknown** ppUnk)
  1300. {
  1301. // Keep a set of IConnectionPointContainer pointers
  1302. typedef std::set<IConnectionPointContainer*> CCPCSet;
  1303. typedef CCPCSet::iterator CCPCSetIterator;
  1304. CCPCSet setCPC;
  1305. // Set advises on each object
  1306. IUnknown* punkThis = GetPageUnknown();
  1307. IUnknown** ppunkEnd = ppUnk + cObjects;
  1308. for (IUnknown** it = ppUnk; it != ppunkEnd; ++it)
  1309. {
  1310. IConnectionPointContainer* pCPC = SetAdvises(*it, punkThis);
  1311. if (NULL != pCPC)
  1312. setCPC.insert(pCPC);
  1313. }
  1314. // Remove and unadvise each map item not in the array of objects
  1315. CAdviseIterator itAdv = m_mapAdvise.begin();
  1316. while (itAdv != m_mapAdvise.end())
  1317. {
  1318. // Lookup the object in the set
  1319. CCPCSetIterator itCPC = setCPC.find(itAdv->first);
  1320. if (setCPC.end() == itCPC)
  1321. itAdv = m_mapAdvise.erase(itAdv);
  1322. else
  1323. ++itAdv;
  1324. }
  1325. // Allow derived classes to set advises
  1326. OnSetAllAdvises(cObjects, ppUnk);
  1327. }
  1328. /////////////////////////////////////////////////////////////////////////////
  1329. // Description: Establishes a single *IPropertyNotifySink* advisory
  1330. // connection with the specified object.
  1331. //
  1332. // This method is used by the implementation to establish a single
  1333. // *IPropertyNotifySink* advisory connection with the specified object.
  1334. //
  1335. // See Also: TCPropertyPageBase::SetAdvises
  1336. IConnectionPointContainer* TCPropertyPageBase::SetAdvises(
  1337. IUnknown* punk, IUnknown* punkThis)
  1338. {
  1339. IConnectionPointContainer* pResult = NULL;
  1340. TCAdviseHolder pAdv = new TCAdviseHolder;
  1341. __try
  1342. {
  1343. // Find the IID_IPropertyNotifySink connection point
  1344. TCAdviseHolder& adv = *pAdv;
  1345. hr = adv.FindConnectionPoint(punk, IID_IPropertyNotifySink)
  1346. if (SUCCEEDED(hr))
  1347. {
  1348. // Ensure that we don't already hold an advise on this object
  1349. if (m_mapAdvise.end() == m_mapAdvise.find(adv.GetCPC()))
  1350. {
  1351. // Insert the connection advise holder into the map
  1352. if (SUCCEEDED(hr = adv.Advise(punkThis)))
  1353. m_mapAdvise.insert(CAdviseMap::value_type(adv.GetCPC(), adv));
  1354. }
  1355. // Return the IConnectionPointContainer pointer as identity
  1356. pResult = adv.GetCPC();
  1357. }
  1358. }
  1359. __except(1)
  1360. {
  1361. _TRACE1("%hs: Caught an unknown exception\n", szFn);
  1362. return NULL;
  1363. }
  1364. // Delete the advise holder
  1365. delete pAdv;
  1366. // Return the last result
  1367. return pResult;
  1368. }
  1369. /////////////////////////////////////////////////////////////////////////////
  1370. // Group=Message Handlers
  1371. /////////////////////////////////////////////////////////////////////////////
  1372. // Description: Message handler for *WM_INITDIALOG*.
  1373. //
  1374. // Handles the *WM_INITDIALOG* window message by creating any embedded
  1375. // property pages needed, establishing advisory connections, allowing the
  1376. // derived class to initialize itself, and updating the fields of the
  1377. // property page. Within the scope of this method, the m_bInitializing data
  1378. // member is set to *true*, returning to *false* at the end of the scope.
  1379. //
  1380. // See Also: TCPropertyPageBase::OnInitDialog,
  1381. // TCPropertyPageBase::m_bInitializing
  1382. void TCPropertyPageBase::OnInitDialogHandler(ULONG cObjects,
  1383. IUnknown** ppUnk)
  1384. {
  1385. // Set the initialization flag
  1386. m_bInitializing = true;
  1387. // Create the embedded property pages
  1388. CreateInsidePages();
  1389. // Set the advises for all the objects
  1390. if (!m_mapAdvise.size())
  1391. SetAllAdvises(cObjects, ppUnk);
  1392. // Allow derived class to initialize controls and such
  1393. bool bResult = OnInitDialog();
  1394. // Update dialog fields from objects
  1395. UpdateFields();
  1396. // Reset the initialization flag
  1397. m_bInitializing = false;
  1398. }
  1399. /////////////////////////////////////////////////////////////////////////////
  1400. // Description: Message handler for the TCPropertyPageImpl::wm_OnChanged
  1401. // message.
  1402. //
  1403. // Handles the TCPropertyPageImpl::wm_OnChanged window message which is
  1404. // posted from TCPropertyPageImpl's implementation of the
  1405. // *IPropertyNotifySink::OnChanged* interface method. That method posts the
  1406. // message in order to defer processing of the property change notification
  1407. // onto the window's main thread.
  1408. //
  1409. // This method simply calls the UpdateFields method with the DISPID of the
  1410. // property that has changed.
  1411. //
  1412. // See Also: Property Page Field Update Macros,
  1413. // TCPropertyPageBase::UpdateFields, TCPropertyPageImpl::wm_OnChanged
  1414. LRESULT TCPropertyPageBase::OnChangedHandler(UINT, WPARAM wp, LPARAM, BOOL&)
  1415. {
  1416. // Parse the message parameters
  1417. DISPID dispid = DISPID(wp);
  1418. _TRACE3("TCPropertyPageBase[%hs]::OnChangedHandler(): dispid = 0x%08X (%d)\n",
  1419. TypeName(), dispid, dispid);
  1420. // Update dialog fields from objects
  1421. UpdateFields(dispid);
  1422. // Obligatory return code
  1423. return 0;
  1424. }
  1425. /////////////////////////////////////////////////////////////////////////////
  1426. // Description: Message handler for *WM_NCDESTROY*.
  1427. //
  1428. // Handles the *WM_NCDESTROY* window message by calling ClearAllAdvises and
  1429. // DestroyInsidePages.
  1430. //
  1431. // See Also: TCPropertyPageBase::ClearAllAdvises,
  1432. // TCPropertyPageBase::DestroyInsidePages
  1433. LRESULT TCPropertyPageBase::OnNcDestroyHandler(UINT, WPARAM, LPARAM,
  1434. BOOL& bHandled)
  1435. {
  1436. _TRACE1("TCPropertyPageBase[%hs]::OnNcDestroyHandler()\n", TypeName());
  1437. // Remove and unadvise all connections
  1438. ClearAllAdvises();
  1439. // Destroy the embedded property pages
  1440. DestroyInsidePages();
  1441. // Allow default processing
  1442. return bHandled = FALSE;
  1443. }