ctlppg.cpp 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470
  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10. #include "stdafx.h"
  11. #ifdef AFXCTL_PAGE_SEG
  12. #pragma code_seg(AFXCTL_PAGE_SEG)
  13. #endif
  14. #ifdef _DEBUG
  15. #undef THIS_FILE
  16. static char THIS_FILE[] = __FILE__;
  17. #endif
  18. #define new DEBUG_NEW
  19. #define MAX_CLASS_NAME 100
  20. struct NotifyInfo
  21. {
  22. LPCTSTR szClassName; // Name of control's class
  23. WORD wNotifyCode; // Notification code
  24. };
  25. #define MAX_TEXT 1024
  26. BEGIN_INTERFACE_MAP(COlePropertyPage, CDialog)
  27. INTERFACE_PART(COlePropertyPage, IID_IPropertyPage2, PropertyPage)
  28. INTERFACE_PART(COlePropertyPage, IID_IPropertyPage, PropertyPage)
  29. END_INTERFACE_MAP()
  30. BEGIN_MESSAGE_MAP(COlePropertyPage, CDialog)
  31. //{{AFX_MSG_MAP(COlePropertyPage)
  32. ON_WM_CTLCOLOR()
  33. //}}AFX_MSG_MAP
  34. #ifndef _AFX_NO_CTL3D_SUPPORT
  35. ON_MESSAGE(WM_QUERY3DCONTROLS, OnQuery3dControls)
  36. #endif
  37. END_MESSAGE_MAP()
  38. /////////////////////////////////////////////////////////////////////////////
  39. // AFX_DDPDATA
  40. struct AFX_DDPDATA : public CObject
  41. {
  42. AFX_DDPDATA(LPVOID lpHandler, int nCtrlId, BOOL bEditCtrl, LPVOID lpMember,
  43. UINT nType, LPCTSTR lpszOleName);
  44. LPVOID m_lpHandler;
  45. int m_nCtrlId;
  46. BOOL m_bEditCtrl;
  47. LPVOID m_lpMember;
  48. UINT m_nType;
  49. LPCTSTR m_lpszOleName;
  50. };
  51. AFX_DDPDATA::AFX_DDPDATA(LPVOID lpHandler, int nCtrlId, BOOL bEditCtrl,
  52. LPVOID lpMember, UINT nType, LPCTSTR lpszOleName) :
  53. m_lpHandler(lpHandler),
  54. m_nCtrlId(nCtrlId),
  55. m_bEditCtrl(bEditCtrl),
  56. m_lpMember(lpMember),
  57. m_nType(nType),
  58. m_lpszOleName(lpszOleName)
  59. {
  60. }
  61. /////////////////////////////////////////////////////////////////////////////
  62. // cleanup helper function
  63. AFX_STATIC void AFXAPI _AfxCleanupDDPs(CPtrArray& arrayDDP)
  64. {
  65. int cDDP = arrayDDP.GetSize();
  66. for (int i = 0; i < cDDP; i++)
  67. {
  68. ASSERT(arrayDDP[i] != NULL);
  69. delete (AFX_DDPDATA*)(arrayDDP[i]);
  70. }
  71. arrayDDP.RemoveAll();
  72. }
  73. /////////////////////////////////////////////////////////////////////////////
  74. // page validation helper function (debug only)
  75. #ifdef _DEBUG
  76. void _ValidatePageDialog(CDialogTemplate& dt, CString& strPage,
  77. COlePropertyPage* pPage)
  78. {
  79. if (GetSystemMetrics(SM_DBCSENABLED))
  80. return;
  81. // Only display the message boxes the first time a page is shown.
  82. #ifdef _DEBUG
  83. BOOL bEnable = AfxEnableMemoryTracking(FALSE);
  84. #endif
  85. static CPtrList _classList;
  86. BOOL bMessageBox = FALSE;
  87. CRuntimeClass* pClass = pPage->GetRuntimeClass();
  88. if (_classList.Find(pClass) == NULL)
  89. {
  90. bMessageBox = TRUE;
  91. _classList.AddHead(pClass);
  92. }
  93. #ifdef _DEBUG
  94. AfxEnableMemoryTracking(bEnable);
  95. #endif
  96. SIZE sizeDLU;
  97. CString strFontName;
  98. WORD wFontSize;
  99. LPTSTR pszTmp;
  100. dt.GetSizeInDialogUnits(&sizeDLU);
  101. dt.GetFont(strFontName, wFontSize);
  102. if ((sizeDLU.cx != 250) || ((sizeDLU.cy != 62) && (sizeDLU.cy != 110)))
  103. {
  104. pszTmp = new TCHAR[strPage.GetLength() + 128];
  105. wsprintf(pszTmp, _T("Property page '%s' has nonstandard dimensions."),
  106. (LPCTSTR)strPage);
  107. TRACE1("Warning: %s\n", pszTmp);
  108. if (bMessageBox)
  109. {
  110. lstrcat(pszTmp,
  111. _T(" Dimensions should be 250x62 or 250x110 dialog units."));
  112. pPage->MessageBox(pszTmp, _T("Property page warning"),
  113. MB_ICONEXCLAMATION);
  114. }
  115. delete [] pszTmp;
  116. }
  117. if ((wFontSize != 8) ||
  118. (strFontName != _T("MS Sans Serif") && strFontName != _T("Helv") &&
  119. strFontName != _T("MS Shell Dlg")))
  120. {
  121. pszTmp = new TCHAR[strPage.GetLength() + 128];
  122. wsprintf(pszTmp, _T("Property page '%s' uses a nonstandard font."),
  123. (LPCTSTR)strPage);
  124. TRACE1("Warning: %s\n", pszTmp);
  125. if (bMessageBox)
  126. {
  127. lstrcat(pszTmp, _T(" Font should be MS Sans Serif 8."));
  128. pPage->MessageBox(pszTmp, _T("Property page warning"),
  129. MB_ICONEXCLAMATION);
  130. }
  131. delete [] pszTmp;
  132. }
  133. }
  134. #endif // _DEBUG
  135. /////////////////////////////////////////////////////////////////////////////
  136. // COlePropertyPage::COlePropertyPage
  137. COlePropertyPage::COlePropertyPage(UINT idDlg, UINT idCaption) :
  138. #ifdef _DEBUG
  139. m_bNonStandardSize(FALSE),
  140. #endif
  141. m_bDirty(FALSE),
  142. m_idCaption(idCaption),
  143. m_idDlg(idDlg),
  144. m_pPageSite(NULL),
  145. m_ppDisp(NULL),
  146. m_pAdvisors(NULL),
  147. m_bPropsChanged(FALSE),
  148. m_nObjects(0),
  149. m_bInitializing(TRUE),
  150. m_nControls(0),
  151. m_pStatus(NULL),
  152. m_hDialog(NULL),
  153. m_dwHelpContext(0)
  154. {
  155. // m_lpDialogTemplate is needed later by CWnd::ExecuteDlgInit
  156. m_lpszTemplateName = MAKEINTRESOURCE(m_idDlg);
  157. // Keep this DLL loaded at least until this object is deleted.
  158. AfxOleLockApp();
  159. }
  160. void COlePropertyPage::OnSetPageSite()
  161. {
  162. // Load the caption from resources
  163. CString strCaption;
  164. if (!strCaption.LoadString(m_idCaption))
  165. strCaption.LoadString(AFX_IDS_PROPPAGE_UNKNOWN);
  166. SetPageName(strCaption);
  167. // Try to load the dialog resource template into memory and get its size
  168. m_sizePage.cx = 0;
  169. m_sizePage.cy = 0;
  170. CDialogTemplate dt;
  171. dt.Load(MAKEINTRESOURCE(m_idDlg));
  172. #ifdef _DEBUG
  173. if (!m_bNonStandardSize)
  174. _ValidatePageDialog(dt, strCaption, this);
  175. #endif
  176. // If no font specified, set the system font.
  177. BOOL bSetSysFont = !dt.HasFont();
  178. CString strFace;
  179. WORD wSize;
  180. // On DBCS systems, also change "MS Sans Serif" or "Helv" to system font.
  181. if ((!bSetSysFont) && GetSystemMetrics(SM_DBCSENABLED))
  182. {
  183. CString strFace;
  184. dt.GetFont(strFace, wSize);
  185. bSetSysFont = (strFace == _T("MS Shell Dlg") ||
  186. strFace == _T("MS Sans Serif") || strFace == _T("Helv"));
  187. }
  188. // Here is where we actually set the font.
  189. if (bSetSysFont && AfxGetPropSheetFont(strFace, wSize, FALSE))
  190. dt.SetFont(strFace, wSize);
  191. dt.GetSizeInPixels(&m_sizePage);
  192. m_hDialog = dt.Detach();
  193. }
  194. BOOL COlePropertyPage::OnInitDialog()
  195. {
  196. CDialog::OnInitDialog();
  197. return 0;
  198. }
  199. BOOL COlePropertyPage::PreTranslateMessage(LPMSG lpMsg)
  200. {
  201. // Don't let CDialog process the Return key or Escape key.
  202. if ((lpMsg->message == WM_KEYDOWN) &&
  203. ((lpMsg->wParam == VK_RETURN) || (lpMsg->wParam == VK_ESCAPE)))
  204. {
  205. // Special case: if control with focus is an edit control with
  206. // ES_WANTRETURN style, let it handle the Return key.
  207. TCHAR szClass[10];
  208. CWnd* pWndFocus = GetFocus();
  209. if ((lpMsg->wParam == VK_RETURN) &&
  210. ((pWndFocus = GetFocus()) != NULL) &&
  211. IsChild(pWndFocus) &&
  212. (pWndFocus->GetStyle() & ES_WANTRETURN) &&
  213. GetClassName(pWndFocus->m_hWnd, szClass, 10) &&
  214. (lstrcmpi(szClass, _T("EDIT")) == 0))
  215. {
  216. pWndFocus->SendMessage(WM_CHAR, lpMsg->wParam, lpMsg->lParam);
  217. return TRUE;
  218. }
  219. return FALSE;
  220. }
  221. // If it's a WM_SYSKEYDOWN, temporarily replace the hwnd in the
  222. // message with the hwnd of our first control, and try to handle
  223. // the message for ourselves.
  224. BOOL bHandled;
  225. if ((lpMsg->message == WM_SYSKEYDOWN) && !::IsChild(m_hWnd, lpMsg->hwnd))
  226. {
  227. HWND hWndSave = lpMsg->hwnd;
  228. lpMsg->hwnd = ::GetWindow(m_hWnd, GW_CHILD);
  229. bHandled = CDialog::PreTranslateMessage(lpMsg);
  230. lpMsg->hwnd = hWndSave;
  231. }
  232. else
  233. {
  234. bHandled = CDialog::PreTranslateMessage(lpMsg);
  235. }
  236. return bHandled;
  237. }
  238. void COlePropertyPage::CleanupObjectArray()
  239. {
  240. if (m_pAdvisors)
  241. {
  242. for (ULONG nObject = 0; nObject < m_nObjects; nObject++)
  243. AfxConnectionUnadvise(m_ppDisp[nObject], IID_IPropertyNotifySink,
  244. &m_xPropNotifySink, FALSE, m_pAdvisors[nObject]);
  245. delete [] m_pAdvisors;
  246. m_pAdvisors = NULL;
  247. }
  248. if (m_ppDisp)
  249. {
  250. for (ULONG nObject = 0; nObject < m_nObjects; nObject++)
  251. RELEASE(m_ppDisp[nObject]);
  252. delete [] m_ppDisp;
  253. m_ppDisp = NULL;
  254. }
  255. }
  256. COlePropertyPage::~COlePropertyPage()
  257. {
  258. // Remember to free the resource we loaded!
  259. if (m_hDialog != NULL)
  260. GlobalFree(m_hDialog);
  261. if (m_pStatus != NULL)
  262. {
  263. delete [] m_pStatus;
  264. m_pStatus = NULL;
  265. }
  266. // Clean out any leftovers in the DDP map.
  267. _AfxCleanupDDPs(m_arrayDDP);
  268. RELEASE(m_pPageSite);
  269. CleanupObjectArray();
  270. AfxOleUnlockApp();
  271. }
  272. void COlePropertyPage::OnFinalRelease()
  273. {
  274. if (m_hWnd != NULL)
  275. DestroyWindow();
  276. delete this;
  277. }
  278. LRESULT COlePropertyPage::WindowProc(UINT msg, WPARAM wParam, LPARAM lParam)
  279. {
  280. AFX_MANAGE_STATE(m_pModuleState);
  281. // Forward WM_SYSCOMMAND messages to the frame for translation
  282. if (msg == WM_SYSCOMMAND && (wParam & 0xFFF0) != SC_KEYMENU && m_pPageSite != NULL)
  283. {
  284. if (m_pPageSite->TranslateAccelerator((LPMSG)GetCurrentMessage())
  285. == S_OK)
  286. {
  287. return 0;
  288. }
  289. }
  290. return CDialog::WindowProc(msg, wParam, lParam);
  291. }
  292. HBRUSH COlePropertyPage::OnCtlColor(CDC*, CWnd* pWnd, UINT)
  293. {
  294. // allow the control itself first crack at the color
  295. LRESULT lResult;
  296. if (pWnd->SendChildNotifyLastMsg(&lResult))
  297. return (HBRUSH)lResult;
  298. // allow the parent window to determine the color
  299. HWND hParent = ::GetParent(m_hWnd);
  300. const MSG* pMsg = GetCurrentMessage();
  301. HBRUSH hResult = (HBRUSH)::SendMessage(hParent,
  302. pMsg->message, pMsg->wParam, pMsg->lParam);
  303. // use default if parent returns NULL
  304. if (hResult == NULL)
  305. hResult = (HBRUSH)Default();
  306. return hResult;
  307. }
  308. BOOL COlePropertyPage::OnHelp(LPCTSTR)
  309. {
  310. // May be overridden by subclass.
  311. return FALSE;
  312. }
  313. BOOL COlePropertyPage::OnEditProperty(DISPID)
  314. {
  315. // May be overridden by subclass.
  316. return FALSE;
  317. }
  318. void COlePropertyPage::OnObjectsChanged()
  319. {
  320. // May be overridden by subclass.
  321. }
  322. LPDISPATCH* COlePropertyPage::GetObjectArray(ULONG* pnObjects)
  323. {
  324. ASSERT_POINTER(pnObjects, ULONG);
  325. if (pnObjects != NULL)
  326. *pnObjects = m_nObjects;
  327. return m_ppDisp;
  328. }
  329. void COlePropertyPage::SetModifiedFlag(BOOL bModified)
  330. {
  331. if (!bModified)
  332. m_bPropsChanged = FALSE;
  333. if ((m_bDirty && !bModified) || (!m_bDirty && bModified))
  334. {
  335. m_bDirty = bModified;
  336. if (m_pPageSite != NULL)
  337. {
  338. DWORD flags = 0;
  339. if (bModified)
  340. flags |= PROPPAGESTATUS_DIRTY;
  341. m_pPageSite->OnStatusChange(flags);
  342. }
  343. }
  344. }
  345. BOOL COlePropertyPage::IsModified()
  346. {
  347. return m_bDirty;
  348. }
  349. void COlePropertyPage::SetPageName(LPCTSTR lpszPageName)
  350. {
  351. ASSERT(AfxIsValidString(lpszPageName));
  352. m_strPageName = lpszPageName;
  353. }
  354. void COlePropertyPage::SetDialogResource(HGLOBAL hDialog)
  355. {
  356. if (m_hDialog != NULL)
  357. {
  358. GlobalFree(m_hDialog);
  359. m_hDialog = NULL;
  360. }
  361. CDialogTemplate dt(hDialog);
  362. #ifdef _DEBUG
  363. _ValidatePageDialog(dt, m_strPageName, this);
  364. #endif
  365. dt.GetSizeInPixels(&m_sizePage);
  366. m_hDialog = dt.Detach();
  367. }
  368. void COlePropertyPage::SetHelpInfo(LPCTSTR lpszDocString,
  369. LPCTSTR lpszHelpFile, DWORD dwHelpContext)
  370. {
  371. ASSERT((lpszDocString == NULL) || AfxIsValidString(lpszDocString));
  372. ASSERT((lpszHelpFile == NULL) || AfxIsValidString(lpszHelpFile));
  373. m_strDocString = lpszDocString;
  374. m_strHelpFile = lpszHelpFile;
  375. m_dwHelpContext = dwHelpContext;
  376. }
  377. LPPROPERTYPAGESITE COlePropertyPage::GetPageSite()
  378. {
  379. return m_pPageSite;
  380. }
  381. int COlePropertyPage::MessageBox(LPCTSTR lpszText, LPCTSTR lpszCaption,
  382. UINT nType)
  383. {
  384. // use caption of page by default
  385. if (lpszCaption == NULL)
  386. lpszCaption = m_strPageName;
  387. // start message box on safe owner of the page
  388. return ::MessageBox(GetSafeOwner_(m_hWnd, NULL), lpszText, lpszCaption, nType);
  389. }
  390. /////////////////////////////////////////////////////////////////////////////
  391. // COlePropertyPage::XPropertyPage
  392. STDMETHODIMP_(ULONG) COlePropertyPage::XPropertyPage::AddRef()
  393. {
  394. METHOD_PROLOGUE_EX_(COlePropertyPage, PropertyPage)
  395. return (ULONG)pThis->ExternalAddRef();
  396. }
  397. STDMETHODIMP_(ULONG) COlePropertyPage::XPropertyPage::Release()
  398. {
  399. METHOD_PROLOGUE_EX_(COlePropertyPage, PropertyPage)
  400. return (ULONG)pThis->ExternalRelease();
  401. }
  402. STDMETHODIMP COlePropertyPage::XPropertyPage::QueryInterface(
  403. REFIID iid, LPVOID* ppvObj)
  404. {
  405. METHOD_PROLOGUE_EX_(COlePropertyPage, PropertyPage)
  406. return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
  407. }
  408. STDMETHODIMP COlePropertyPage::XPropertyPage::SetPageSite(
  409. LPPROPERTYPAGESITE pPageSite)
  410. {
  411. METHOD_PROLOGUE_EX(COlePropertyPage, PropertyPage)
  412. ASSERT_VALID(pThis);
  413. ASSERT_POINTER(pPageSite, IPropertyPageSite);
  414. RELEASE(pThis->m_pPageSite); // release the old one
  415. pThis->m_pPageSite = pPageSite;
  416. if (pPageSite != NULL)
  417. pThis->m_pPageSite->AddRef(); // Bump the reference count
  418. pThis->OnSetPageSite();
  419. return S_OK;
  420. }
  421. STDMETHODIMP COlePropertyPage::XPropertyPage::Activate(HWND hWndParent,
  422. LPCRECT pRect, BOOL)
  423. {
  424. METHOD_PROLOGUE_EX(COlePropertyPage, PropertyPage)
  425. ASSERT_VALID(pThis);
  426. ASSERT_NULL_OR_POINTER(pRect, RECT);
  427. BOOL bSuccess = FALSE; // Did we successfully create the dialog box
  428. if (pThis->m_hDialog != NULL)
  429. {
  430. // We've already loaded the dialog template into memory so just
  431. // create it!
  432. void* lpDialogTemplate = LockResource(pThis->m_hDialog);
  433. if (lpDialogTemplate != NULL)
  434. {
  435. bSuccess = pThis->CreateIndirect(lpDialogTemplate, CWnd::FromHandle(hWndParent));
  436. UnlockResource(pThis->m_hDialog);
  437. }
  438. else
  439. bSuccess = pThis->Create(pThis->m_idDlg, CWnd::FromHandle(hWndParent));
  440. }
  441. else
  442. bSuccess = pThis->Create(pThis->m_idDlg, CWnd::FromHandle(hWndParent));
  443. // Were we successful in creating the dialog box!
  444. if (bSuccess)
  445. {
  446. pThis->MoveWindow(pRect); // Force page to fill area given by frame *
  447. pThis->m_bInitializing = TRUE;
  448. pThis->UpdateData(FALSE);
  449. pThis->SetModifiedFlag(FALSE);
  450. pThis->m_bInitializing = FALSE;
  451. if (pThis->m_pStatus != NULL)
  452. {
  453. delete [] pThis->m_pStatus;
  454. pThis->m_pStatus = NULL;
  455. }
  456. pThis->m_nControls = 0;
  457. ::EnumChildWindows(pThis->GetSafeHwnd(), (WNDENUMPROC) COlePropertyPage::EnumChildProc, (LPARAM) pThis);
  458. if (pThis->m_nControls > 0)
  459. pThis->m_pStatus = new AFX_PPFIELDSTATUS [UINT(pThis->m_nControls)];
  460. pThis->m_nControls = 0;
  461. EnumChildWindows(pThis->GetSafeHwnd(), (WNDENUMPROC) COlePropertyPage::EnumControls, (LPARAM) pThis);
  462. return S_OK;
  463. }
  464. return E_FAIL;
  465. }
  466. BOOL CALLBACK COlePropertyPage::EnumChildProc(HWND, LPARAM lParam)
  467. {
  468. COlePropertyPage* pDlg = (COlePropertyPage*) lParam;
  469. ASSERT_POINTER(pDlg, COlePropertyPage);
  470. pDlg->m_nControls++;
  471. return TRUE;
  472. }
  473. BOOL CALLBACK COlePropertyPage::EnumControls(HWND hWnd, LPARAM lParam)
  474. {
  475. COlePropertyPage* pDlg = (COlePropertyPage*) lParam;
  476. ASSERT_POINTER(pDlg, COlePropertyPage);
  477. ASSERT(pDlg->m_pStatus != NULL);
  478. pDlg->m_pStatus[pDlg->m_nControls].nID = (UINT)::GetDlgCtrlID(hWnd);
  479. pDlg->m_pStatus[pDlg->m_nControls].bDirty = FALSE;
  480. pDlg->m_nControls++;
  481. return TRUE;
  482. }
  483. STDMETHODIMP COlePropertyPage::XPropertyPage::Deactivate()
  484. {
  485. METHOD_PROLOGUE_EX(COlePropertyPage, PropertyPage)
  486. pThis->DestroyWindow();
  487. return S_OK;
  488. }
  489. STDMETHODIMP COlePropertyPage::XPropertyPage::GetPageInfo(
  490. LPPROPPAGEINFO pPageInfo)
  491. {
  492. METHOD_PROLOGUE_EX_(COlePropertyPage, PropertyPage)
  493. ASSERT_POINTER(pPageInfo, PROPPAGEINFO);
  494. pPageInfo->pszTitle = AfxAllocTaskOleString(pThis->m_strPageName);
  495. pPageInfo->size = pThis->m_sizePage;
  496. pPageInfo->pszDocString = AfxAllocTaskOleString(pThis->m_strDocString);
  497. pPageInfo->pszHelpFile = AfxAllocTaskOleString(pThis->m_strHelpFile);
  498. pPageInfo->dwHelpContext = pThis->m_dwHelpContext;
  499. return S_OK;
  500. }
  501. STDMETHODIMP COlePropertyPage::XPropertyPage::SetObjects(
  502. ULONG cObjects, LPUNKNOWN* ppUnk)
  503. {
  504. METHOD_PROLOGUE_EX(COlePropertyPage, PropertyPage)
  505. ASSERT_VALID(pThis);
  506. pThis->CleanupObjectArray();
  507. if (cObjects != 0)
  508. {
  509. ASSERT(AfxIsValidAddress(ppUnk, sizeof(LPUNKNOWN) * (int)cObjects, FALSE));
  510. pThis->m_ppDisp = new LPDISPATCH [(UINT)cObjects];
  511. pThis->m_pAdvisors = new DWORD [(UINT)cObjects];
  512. for (ULONG nObject = 0; nObject < cObjects; nObject++)
  513. {
  514. HRESULT hr = ppUnk[nObject]->QueryInterface(IID_IDispatch,
  515. (VOID**)&(pThis->m_ppDisp[nObject]));
  516. if (SUCCEEDED(hr))
  517. {
  518. AfxConnectionAdvise(ppUnk[nObject], IID_IPropertyNotifySink,
  519. &pThis->m_xPropNotifySink, FALSE,
  520. &pThis->m_pAdvisors[nObject]);
  521. }
  522. else
  523. {
  524. return hr;
  525. }
  526. }
  527. }
  528. pThis->m_nObjects = cObjects;
  529. // No painting during the data update.
  530. BOOL bLock = (pThis->m_hWnd != NULL) && pThis->IsWindowVisible();
  531. if (bLock)
  532. ::LockWindowUpdate(pThis->m_hWnd);
  533. pThis->OnObjectsChanged();
  534. // If window exists, update the data in its fields.
  535. if (cObjects != 0 && pThis->m_hWnd != NULL)
  536. {
  537. pThis->UpdateData(FALSE);
  538. pThis->SetModifiedFlag(FALSE);
  539. }
  540. if (bLock)
  541. ::LockWindowUpdate(NULL);
  542. return S_OK;
  543. }
  544. STDMETHODIMP COlePropertyPage::XPropertyPage::Show(UINT nCmdShow)
  545. {
  546. METHOD_PROLOGUE_EX_(COlePropertyPage, PropertyPage)
  547. pThis->ShowWindow(nCmdShow);
  548. if (nCmdShow == SW_SHOWNORMAL)
  549. pThis->SetFocus();
  550. return S_OK;
  551. }
  552. STDMETHODIMP COlePropertyPage::XPropertyPage::Move(LPCRECT pRect)
  553. {
  554. METHOD_PROLOGUE_EX_(COlePropertyPage, PropertyPage)
  555. ASSERT_POINTER(pRect, RECT);
  556. pThis->MoveWindow(pRect);
  557. return S_OK;
  558. }
  559. STDMETHODIMP COlePropertyPage::XPropertyPage::IsPageDirty()
  560. {
  561. METHOD_PROLOGUE_EX_(COlePropertyPage, PropertyPage)
  562. return pThis->m_bDirty ? S_OK : S_FALSE;
  563. }
  564. STDMETHODIMP COlePropertyPage::XPropertyPage::Apply()
  565. {
  566. METHOD_PROLOGUE_EX(COlePropertyPage, PropertyPage)
  567. ASSERT_VALID(pThis);
  568. HRESULT hr = S_OK;
  569. BOOL bClean = FALSE;
  570. if (pThis->m_bDirty)
  571. {
  572. if (pThis->UpdateData(TRUE))
  573. {
  574. pThis->m_bDirty = FALSE;
  575. bClean = TRUE;
  576. }
  577. else
  578. hr = E_FAIL;
  579. if (pThis->m_bPropsChanged)
  580. {
  581. pThis->UpdateData(FALSE);
  582. pThis->m_bPropsChanged = FALSE;
  583. bClean = TRUE;
  584. }
  585. if (bClean)
  586. {
  587. // Set the dirty status of all the controls on this page to FALSE.
  588. if (pThis->m_pStatus != NULL)
  589. {
  590. for (int nControl = 0; nControl < pThis->m_nControls; nControl++)
  591. pThis->m_pStatus[nControl].bDirty = FALSE;
  592. }
  593. }
  594. }
  595. else
  596. ASSERT(!pThis->m_bPropsChanged);
  597. return hr;
  598. }
  599. STDMETHODIMP COlePropertyPage::XPropertyPage::Help(LPCOLESTR lpszHelpDir)
  600. {
  601. METHOD_PROLOGUE_EX(COlePropertyPage, PropertyPage)
  602. ASSERT_VALID(pThis);
  603. ASSERT((lpszHelpDir == NULL) || AfxIsValidString(lpszHelpDir));
  604. USES_CONVERSION;
  605. if (!pThis->OnHelp(OLE2CT(lpszHelpDir)))
  606. return S_FALSE;
  607. else
  608. return S_OK;
  609. }
  610. BOOL AFXAPI _AfxAtEndOfTabList(CDialog* pDlg, UINT nCmd)
  611. {
  612. if ((pDlg->SendMessage(WM_GETDLGCODE) &
  613. (DLGC_WANTALLKEYS | DLGC_WANTMESSAGE | DLGC_WANTTAB)) == 0)
  614. {
  615. CWnd* pCtl = CWnd::GetFocus();
  616. if (pDlg->IsChild(pCtl))
  617. {
  618. // Get top level child for controls with children, like combo.
  619. while (pCtl->GetParent() != pDlg)
  620. {
  621. pCtl = pCtl->GetParent();
  622. ASSERT_VALID(pCtl);
  623. }
  624. do
  625. {
  626. if ((pCtl = pCtl->GetWindow(nCmd)) == NULL)
  627. return TRUE;
  628. }
  629. while ((pCtl->GetStyle() & (WS_DISABLED | WS_TABSTOP)) != WS_TABSTOP);
  630. }
  631. }
  632. return FALSE;
  633. }
  634. STDMETHODIMP COlePropertyPage::XPropertyPage::TranslateAccelerator(LPMSG lpMsg)
  635. {
  636. METHOD_PROLOGUE_EX(COlePropertyPage, PropertyPage)
  637. ASSERT_VALID(pThis);
  638. ASSERT_POINTER(lpMsg, MSG);
  639. BOOL bHandled = FALSE;
  640. if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam == VK_TAB &&
  641. GetKeyState(VK_CONTROL) >= 0)
  642. {
  643. if (pThis->IsChild(CWnd::GetFocus()))
  644. {
  645. // We already have the focus. Let's determine whether we should
  646. // pass focus up to the frame.
  647. if (_AfxAtEndOfTabList(pThis, GetKeyState(VK_SHIFT) < 0 ?
  648. GW_HWNDPREV : GW_HWNDNEXT))
  649. {
  650. // fix for default button border
  651. DWORD dwDefID = pThis->GetDefID();
  652. if (HIWORD(dwDefID) == DC_HASDEFID)
  653. {
  654. CWnd *pDefBtn = pThis->GetDlgItem(LOWORD(dwDefID));
  655. if (pDefBtn != NULL && pDefBtn->IsWindowEnabled())
  656. pThis->GotoDlgCtrl(pDefBtn);
  657. }
  658. // Pass focus to the frame by letting the page site handle
  659. // this message.
  660. if (pThis->m_pPageSite != NULL)
  661. bHandled =
  662. pThis->m_pPageSite->TranslateAccelerator(lpMsg) ==
  663. S_OK;
  664. }
  665. }
  666. else
  667. {
  668. // We don't already have the focus. The frame is passing the
  669. // focus to us.
  670. CWnd* pWnd = pThis->GetTopWindow();
  671. if (pWnd != NULL)
  672. {
  673. UINT gwInit;
  674. UINT gwMove;
  675. if (GetKeyState(VK_SHIFT) >= 0)
  676. {
  677. // Set the focus to the first tabstop in the page.
  678. gwInit = GW_HWNDFIRST;
  679. gwMove = GW_HWNDNEXT;
  680. }
  681. else
  682. {
  683. // Set the focus to the last tabstop in the page.
  684. gwInit = GW_HWNDLAST;
  685. gwMove = GW_HWNDPREV;
  686. }
  687. pWnd = pWnd->GetWindow(gwInit);
  688. while (pWnd != NULL)
  689. {
  690. if ((pWnd->GetStyle() & (WS_DISABLED | WS_TABSTOP)) ==
  691. WS_TABSTOP)
  692. {
  693. pThis->GotoDlgCtrl(pWnd);
  694. bHandled = TRUE;
  695. break;
  696. }
  697. pWnd = pWnd->GetWindow(gwMove);
  698. }
  699. }
  700. }
  701. }
  702. // If message was not handled here, call PreTranslateMessage
  703. return (bHandled || pThis->PreTranslateMessage(lpMsg)) ?
  704. S_OK : S_FALSE;
  705. }
  706. STDMETHODIMP COlePropertyPage::XPropertyPage::EditProperty(DISPID dispid)
  707. {
  708. METHOD_PROLOGUE_EX(COlePropertyPage, PropertyPage)
  709. ASSERT_VALID(pThis);
  710. return pThis->OnEditProperty(dispid) ? S_OK : E_NOTIMPL;
  711. }
  712. /////////////////////////////////////////////////////////////////////////////
  713. // COlePropertyPage::XPropNotifySink
  714. STDMETHODIMP_(ULONG) COlePropertyPage::XPropNotifySink::AddRef()
  715. {
  716. return 1;
  717. }
  718. STDMETHODIMP_(ULONG) COlePropertyPage::XPropNotifySink::Release()
  719. {
  720. return 0;
  721. }
  722. STDMETHODIMP COlePropertyPage::XPropNotifySink::QueryInterface(
  723. REFIID iid, LPVOID* ppvObj)
  724. {
  725. if (IsEqualIID(iid, IID_IPropertyNotifySink) ||
  726. IsEqualIID(iid, IID_IUnknown))
  727. {
  728. *ppvObj = this;
  729. return S_OK;
  730. }
  731. else
  732. {
  733. *ppvObj = NULL;
  734. return E_NOINTERFACE;
  735. }
  736. }
  737. STDMETHODIMP COlePropertyPage::XPropNotifySink::OnRequestEdit(DISPID)
  738. {
  739. return S_OK;
  740. }
  741. STDMETHODIMP COlePropertyPage::XPropNotifySink::OnChanged(DISPID)
  742. {
  743. METHOD_PROLOGUE_EX(COlePropertyPage, PropNotifySink)
  744. // If we're not currently in the middle of an UpdateData, call it now.
  745. _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
  746. if (pThis->m_hWnd != NULL &&
  747. pThreadState->m_hLockoutNotifyWindow != pThis->m_hWnd)
  748. {
  749. pThis->UpdateData(FALSE);
  750. }
  751. else
  752. {
  753. pThis->m_bPropsChanged = TRUE;
  754. }
  755. return S_OK;
  756. }
  757. /////////////////////////////////////////////////////////////////////////////
  758. // Handle control notifications
  759. AFX_STATIC_DATA const NotifyInfo _afxNotifyList[] = {
  760. { _T("edit"), EN_CHANGE },
  761. { _T("button"), BN_CLICKED },
  762. { _T("button"), BN_DOUBLECLICKED },
  763. { _T("combobox"), CBN_EDITCHANGE },
  764. { _T("combobox"), CBN_SELCHANGE },
  765. { _T("listbox"), LBN_SELCHANGE },
  766. };
  767. AFX_STATIC_DATA const NotifyInfo _afxUpdateList[] = {
  768. { _T("edit"), EN_KILLFOCUS },
  769. { _T("button"), BN_CLICKED },
  770. { _T("button"), BN_DOUBLECLICKED },
  771. { _T("combobox"), CBN_SELCHANGE },
  772. { _T("combobox"), CBN_KILLFOCUS },
  773. { _T("listbox"), LBN_SELCHANGE },
  774. };
  775. BOOL AFXAPI _AfxIsRadioButton(HWND hWnd)
  776. {
  777. DWORD dwButtonStyle = GetWindowLong(hWnd, GWL_STYLE) & 0x0000000FL;
  778. return ((dwButtonStyle == BS_RADIOBUTTON) ||
  779. (dwButtonStyle == BS_AUTORADIOBUTTON));
  780. }
  781. BOOL COlePropertyPage::OnCommand(WPARAM wParam, LPARAM lParam)
  782. {
  783. // Let the base class process the message first
  784. BOOL bSuccess = CDialog::OnCommand(wParam, lParam);
  785. // Are we just initializing the dialog box, or do we have no objects?
  786. if (m_bInitializing || m_ppDisp == NULL)
  787. return bSuccess;
  788. UINT nID = (UINT)LOWORD(wParam);
  789. HWND hWndCtl = (HWND)lParam;
  790. WORD wNotifyCode = HIWORD(wParam);
  791. DWORD flags = 0;
  792. if (hWndCtl != NULL)
  793. {
  794. BOOL bIgnoreControl = FALSE;
  795. for (int count = 0; count < m_IDArray.GetSize(); count++)
  796. {
  797. UINT nNotID = m_IDArray.GetAt(count);
  798. if (nID == nNotID)
  799. bIgnoreControl = TRUE;
  800. }
  801. if ( !bIgnoreControl )
  802. {
  803. TCHAR szClassName[MAX_CLASS_NAME];
  804. // We have a control message - check type of control and message
  805. ::GetClassName(hWndCtl, (LPTSTR)szClassName, MAX_CLASS_NAME);
  806. for (int iNotify = 0; iNotify < _countof(_afxNotifyList); iNotify++)
  807. {
  808. if (lstrcmpi(_afxNotifyList[iNotify].szClassName, szClassName) == 0
  809. && _afxNotifyList[iNotify].wNotifyCode == wNotifyCode )
  810. {
  811. if ((lstrcmpi(szClassName, _T("button")) == 0) &&
  812. _AfxIsRadioButton(hWndCtl))
  813. {
  814. // Special case for radio buttons:
  815. // mark first button in group
  816. while ((hWndCtl != NULL) &&
  817. !(GetWindowLong(hWndCtl, GWL_STYLE) & WS_GROUP))
  818. {
  819. hWndCtl = ::GetWindow(hWndCtl, GW_HWNDPREV);
  820. }
  821. // First button in group must have WS_GROUP style,
  822. // and must be a radio button.
  823. ASSERT(hWndCtl != NULL);
  824. ASSERT(_AfxIsRadioButton(hWndCtl));
  825. // Mark first radio button as dirty
  826. if (hWndCtl != NULL)
  827. nID = ::GetWindowLong(hWndCtl, GWL_ID);
  828. }
  829. // Control has been modified
  830. m_bDirty = TRUE;
  831. SetControlStatus(nID, TRUE);
  832. flags = PROPPAGESTATUS_DIRTY;
  833. break;
  834. }
  835. }
  836. if (m_bDirty)
  837. {
  838. for (int iNotify=0; iNotify < _countof(_afxUpdateList); iNotify++)
  839. {
  840. if (lstrcmpi(_afxUpdateList[iNotify].szClassName, szClassName)==0 &&
  841. _afxUpdateList[iNotify].wNotifyCode == wNotifyCode &&
  842. GetControlStatus(nID))
  843. {
  844. flags |= PROPPAGESTATUS_VALIDATE;
  845. }
  846. }
  847. }
  848. }
  849. }
  850. if (flags != 0)
  851. {
  852. ASSERT(m_pPageSite != NULL);
  853. m_pPageSite->OnStatusChange(flags);
  854. }
  855. return bSuccess;
  856. }
  857. void COlePropertyPage::IgnoreApply(UINT nID)
  858. {
  859. m_IDArray.Add(nID);
  860. }
  861. BOOL COlePropertyPage::GetControlStatus(UINT nID)
  862. {
  863. for (int nControl = 0; nControl < m_nControls; nControl++)
  864. if (m_pStatus[nControl].nID == nID)
  865. return m_pStatus[nControl].bDirty;
  866. // If we couldn't find the control - assume it is dirty
  867. return TRUE;
  868. }
  869. BOOL COlePropertyPage::SetControlStatus(UINT nID, BOOL bDirty)
  870. {
  871. for (int nControl = 0; nControl < m_nControls; nControl++)
  872. if (m_pStatus[nControl].nID == nID)
  873. {
  874. m_pStatus[nControl].bDirty = bDirty;
  875. return TRUE;
  876. }
  877. return FALSE;
  878. }
  879. //////////////////////////////////////////////////////////////////////////////
  880. // Function Templates using the Preprocessor
  881. // [This should be replaced with C++ Templates when the 16 bit compiler allows]
  882. #define DEFINE_GET_SET_PROP(ctype,casttype,vttype) \
  883. BOOL COlePropertyPage::SetPropText(LPCTSTR pszPropName, ctype& data ) \
  884. { \
  885. USES_CONVERSION;\
  886. COleDispatchDriver PropDispDriver; \
  887. BOOL bResult = FALSE; \
  888. for (ULONG i = 0; i < m_nObjects; i++) \
  889. { \
  890. DISPID dwDispID; \
  891. LPCOLESTR lpOleStr = T2COLE(pszPropName);\
  892. if (SUCCEEDED(m_ppDisp[i]->GetIDsOfNames(IID_NULL, (LPOLESTR*)&lpOleStr, 1, 0, &dwDispID))) \
  893. { \
  894. PropDispDriver.AttachDispatch(m_ppDisp[i], FALSE); \
  895. PropDispDriver.SetProperty(dwDispID, vttype, (casttype)data ); \
  896. PropDispDriver.DetachDispatch(); \
  897. bResult = TRUE; \
  898. } \
  899. } \
  900. return bResult; \
  901. } \
  902. BOOL COlePropertyPage::GetPropText(LPCTSTR pszPropName, ctype *data ) \
  903. { \
  904. USES_CONVERSION;\
  905. COleDispatchDriver PropDispDriver; \
  906. BOOL bSuccess = FALSE; \
  907. for (ULONG i = 0; i < m_nObjects; i++) \
  908. { \
  909. DISPID dwDispID; \
  910. LPCOLESTR lpOleStr = T2COLE(pszPropName);\
  911. if (SUCCEEDED(m_ppDisp[i]->GetIDsOfNames(IID_NULL, (LPOLESTR*)&lpOleStr, 1, 0, &dwDispID))) \
  912. { \
  913. ctype dataTemp; \
  914. static ctype fill; \
  915. PropDispDriver.AttachDispatch(m_ppDisp[i], FALSE); \
  916. PropDispDriver.GetProperty(dwDispID, vttype, &dataTemp); \
  917. PropDispDriver.DetachDispatch(); \
  918. if (i == 0) *data = dataTemp; \
  919. if (*data != dataTemp) *data = fill; \
  920. bSuccess = TRUE; \
  921. } \
  922. } \
  923. return bSuccess; \
  924. }
  925. /////////////////////////////////////////////////////////////////////////////
  926. // DDP_ property get/set helpers
  927. DEFINE_GET_SET_PROP( BYTE, BYTE, VT_UI1 );
  928. DEFINE_GET_SET_PROP( short, short, VT_I2 );
  929. DEFINE_GET_SET_PROP( int, int, VT_I4 );
  930. DEFINE_GET_SET_PROP( UINT, UINT, VT_I4 );
  931. DEFINE_GET_SET_PROP( long, long, VT_I4 );
  932. DEFINE_GET_SET_PROP( DWORD, DWORD, VT_I4 );
  933. DEFINE_GET_SET_PROP( float, float, VT_R4 );
  934. DEFINE_GET_SET_PROP( double, double, VT_R8 );
  935. DEFINE_GET_SET_PROP( CString, LPCTSTR, VT_BSTR );
  936. BOOL COlePropertyPage::SetPropCheck(LPCTSTR pszPropName, int Value)
  937. {
  938. USES_CONVERSION;
  939. COleDispatchDriver PropDispDriver;
  940. BOOL bResult = FALSE;
  941. BOOL bValue;
  942. if (Value == 1)
  943. bValue = TRUE;
  944. else
  945. bValue = FALSE; // default to off
  946. // Set the properties for all the objects
  947. for (ULONG i = 0; i < m_nObjects; i++)
  948. {
  949. DISPID dwDispID;
  950. // Get the Dispatch ID for the property and if successful set the value of the property
  951. LPCOLESTR lpOleStr = T2COLE(pszPropName);
  952. if (SUCCEEDED(m_ppDisp[i]->GetIDsOfNames(IID_NULL, (LPOLESTR*)&lpOleStr, 1, 0, &dwDispID)))
  953. {
  954. // Set property
  955. PropDispDriver.AttachDispatch(m_ppDisp[i], FALSE);
  956. PropDispDriver.SetProperty(dwDispID, VT_BOOL, bValue);
  957. PropDispDriver.DetachDispatch();
  958. bResult = TRUE;
  959. }
  960. }
  961. return bResult;
  962. }
  963. BOOL COlePropertyPage::GetPropCheck(LPCTSTR pszPropName, int* pValue)
  964. {
  965. USES_CONVERSION;
  966. COleDispatchDriver PropDispDriver;
  967. BOOL bSuccess = FALSE;
  968. // Check the property values for all the objects
  969. for (ULONG i = 0; i < m_nObjects; i++)
  970. {
  971. DISPID dwDispID;
  972. // Get the Dispatch ID for the property and if successful get the value of the property
  973. LPCOLESTR lpOleStr = T2COLE(pszPropName);
  974. if (SUCCEEDED(m_ppDisp[i]->GetIDsOfNames(IID_NULL, (LPOLESTR*)&lpOleStr, 1, 0, &dwDispID)))
  975. {
  976. // Get property
  977. BOOL bTemp = FALSE;
  978. int tempValue;
  979. PropDispDriver.AttachDispatch(m_ppDisp[i], FALSE);
  980. PropDispDriver.GetProperty(dwDispID, VT_BOOL, &bTemp);
  981. PropDispDriver.DetachDispatch();
  982. // Convert boolean value to check box equivalent
  983. if (bTemp)
  984. tempValue = 1;
  985. else
  986. tempValue = 0;
  987. // Handle special case for first object
  988. if (i == 0)
  989. *pValue = tempValue;
  990. // If the current check value is not the same as the one just retrieved then
  991. // set the current check value to the indeterminate state.
  992. if (tempValue != *pValue)
  993. *pValue = 2;
  994. bSuccess = TRUE;
  995. }
  996. }
  997. return bSuccess;
  998. }
  999. BOOL COlePropertyPage::SetPropRadio(LPCTSTR pszPropName, int Value)
  1000. {
  1001. USES_CONVERSION;
  1002. COleDispatchDriver PropDispDriver;
  1003. BOOL bSuccess = FALSE;
  1004. // Set the properties for all the objects
  1005. for (ULONG i = 0; i < m_nObjects; i++)
  1006. {
  1007. DISPID dwDispID;
  1008. // Get the Dispatch ID for the property and if successful set the value of the property
  1009. LPCOLESTR lpOleStr = T2COLE(pszPropName);
  1010. if (SUCCEEDED(m_ppDisp[i]->GetIDsOfNames(IID_NULL, (LPOLESTR*)&lpOleStr, 1, 0, &dwDispID)))
  1011. {
  1012. short nTemp = (short)Value;
  1013. // Set property
  1014. PropDispDriver.AttachDispatch(m_ppDisp[i], FALSE);
  1015. PropDispDriver.SetProperty(dwDispID, VT_I2, nTemp);
  1016. PropDispDriver.DetachDispatch();
  1017. bSuccess = TRUE;
  1018. }
  1019. }
  1020. return bSuccess;
  1021. }
  1022. BOOL COlePropertyPage::GetPropRadio(LPCTSTR pszPropName, int* pValue)
  1023. {
  1024. USES_CONVERSION;
  1025. COleDispatchDriver PropDispDriver;
  1026. BOOL bSuccess = FALSE;
  1027. // Check the property values for all the objects
  1028. for (ULONG i = 0; i < m_nObjects; i++)
  1029. {
  1030. DISPID dwDispID;
  1031. // Get the Dispatch ID for the property and if successful get the value of the property
  1032. LPCOLESTR lpOleStr = T2COLE(pszPropName);
  1033. if (SUCCEEDED(m_ppDisp[i]->GetIDsOfNames(IID_NULL, (LPOLESTR*)&lpOleStr, 1, 0, &dwDispID)))
  1034. {
  1035. short nTemp;
  1036. // Get property
  1037. PropDispDriver.AttachDispatch(m_ppDisp[i], FALSE);
  1038. PropDispDriver.GetProperty(dwDispID, VT_I2, &nTemp);
  1039. PropDispDriver.DetachDispatch();
  1040. // Handle special case for first object
  1041. if (i == 0)
  1042. *pValue = nTemp;
  1043. // Compare the current radio value with the one just retrieved then
  1044. // if they are different then set the radio value to -1, so that no
  1045. // radio buttons will be checked.
  1046. if (nTemp != *pValue)
  1047. *pValue = -1;
  1048. bSuccess = TRUE;
  1049. }
  1050. }
  1051. return bSuccess;
  1052. }
  1053. BOOL COlePropertyPage::SetPropIndex(LPCTSTR pszPropName, int Value)
  1054. {
  1055. return SetPropRadio(pszPropName, Value);
  1056. }
  1057. BOOL COlePropertyPage::GetPropIndex(LPCTSTR pszPropName, int* pValue)
  1058. {
  1059. return GetPropRadio(pszPropName, pValue);
  1060. }
  1061. /////////////////////////////////////////////////////////////////////////////
  1062. // DDP_Begin data exchange routines (Should be C++ templated someday!)
  1063. #define DEFINE_DDP_(group,ctype,vtype,bEditCtrl) \
  1064. void AFXAPI DDP_End##group(CDataExchange* pDX, int, \
  1065. ctype *member, LPCTSTR pszPropName ) \
  1066. { \
  1067. COlePropertyPage* propDialog = STATIC_DOWNCAST(COlePropertyPage, pDX->m_pDlgWnd); \
  1068. if (pDX->m_bSaveAndValidate) \
  1069. propDialog->SetProp##group(pszPropName, *member ); \
  1070. } \
  1071. void AFXAPI DDP_##group(CDataExchange* pDX, int nCtrlId, \
  1072. ctype &member, LPCTSTR pszPropName ) \
  1073. { \
  1074. ASSERT(AfxIsValidString(pszPropName)); \
  1075. COlePropertyPage* propDialog = STATIC_DOWNCAST(COlePropertyPage, pDX->m_pDlgWnd); \
  1076. if (pDX->m_bSaveAndValidate) /*Are we Saving?*/ \
  1077. { \
  1078. if (propDialog->GetControlStatus(nCtrlId)) /*Is Control Dirty?*/ \
  1079. { \
  1080. void (AFXAPI *pfv)(CDataExchange*,int,ctype*,LPCTSTR) = \
  1081. DDP_End##group; \
  1082. AFX_DDPDATA *pDDP = new AFX_DDPDATA( (void *)pfv, nCtrlId, bEditCtrl, \
  1083. (void*)&member, (UINT)vtype, \
  1084. pszPropName ); \
  1085. propDialog->m_arrayDDP.Add(pDDP); \
  1086. } \
  1087. } \
  1088. else /* Loading data from properties! */ \
  1089. { \
  1090. propDialog->GetProp##group(pszPropName, &member); \
  1091. propDialog->SetControlStatus(nCtrlId,FALSE); \
  1092. } \
  1093. }
  1094. /////////////////////////////////////////////////////////////////////////////
  1095. // DDP Functions (Pseudo Template Generation)
  1096. DEFINE_DDP_(Text,BYTE,VT_UI1,TRUE);
  1097. DEFINE_DDP_(Text,short,VT_I2,TRUE);
  1098. DEFINE_DDP_(Text,int,VT_I4,TRUE);
  1099. DEFINE_DDP_(Text,UINT,VT_UI4,TRUE);
  1100. DEFINE_DDP_(Text,long,VT_I4,TRUE);
  1101. DEFINE_DDP_(Text,DWORD,VT_UI4,TRUE);
  1102. DEFINE_DDP_(Text,float,VT_R4,TRUE);
  1103. DEFINE_DDP_(Text,double,VT_R8,TRUE);
  1104. DEFINE_DDP_(Text,CString,VT_BSTR,TRUE);
  1105. DEFINE_DDP_(Check,BOOL,VT_I4,FALSE);
  1106. DEFINE_DDP_(Radio,int,VT_I4,FALSE);
  1107. //////////////////////////////////////////////////////////////////////////////
  1108. // DDP Deferred Property Write Handler
  1109. void AFXAPI DDP_PostProcessing(CDataExchange*pDX)
  1110. {
  1111. if (pDX->m_bSaveAndValidate)
  1112. {
  1113. CPtrArray &arrayDDP =
  1114. ((COlePropertyPage *)pDX->m_pDlgWnd)->m_arrayDDP;
  1115. AFX_DDPDATA *pDDP = NULL;
  1116. int cDDP = arrayDDP.GetSize();
  1117. for (int i = 0 ; i < cDDP; i++)
  1118. {
  1119. pDDP = (AFX_DDPDATA*)arrayDDP[i];
  1120. TRY
  1121. {
  1122. if (pDDP->m_bEditCtrl)
  1123. pDX->PrepareEditCtrl(pDDP->m_nCtrlId);
  1124. else
  1125. pDX->PrepareCtrl(pDDP->m_nCtrlId);
  1126. switch( pDDP->m_nType )
  1127. {
  1128. case VT_I1:
  1129. {
  1130. typedef void (AFXAPI *PFV)(CDataExchange *, int,
  1131. char *, LPCTSTR );
  1132. (*(PFV)pDDP->m_lpHandler)(pDX, pDDP->m_nCtrlId,
  1133. (char *)pDDP->m_lpMember,
  1134. pDDP->m_lpszOleName );
  1135. break;
  1136. }
  1137. case VT_UI1:
  1138. {
  1139. typedef void (AFXAPI *PFV)(CDataExchange *, int,
  1140. BYTE *, LPCTSTR );
  1141. (*(PFV)pDDP->m_lpHandler)(pDX, pDDP->m_nCtrlId,
  1142. (BYTE *)pDDP->m_lpMember,
  1143. pDDP->m_lpszOleName );
  1144. break;
  1145. }
  1146. case VT_I2:
  1147. {
  1148. typedef void (AFXAPI *PFV)(CDataExchange *, int,
  1149. short *, LPCTSTR );
  1150. (*(PFV)pDDP->m_lpHandler)(pDX, pDDP->m_nCtrlId,
  1151. (short *)pDDP->m_lpMember,
  1152. pDDP->m_lpszOleName );
  1153. break;
  1154. }
  1155. case VT_UI2:
  1156. {
  1157. typedef void (AFXAPI *PFV)(CDataExchange *, int,
  1158. WORD *, LPCTSTR );
  1159. (*(PFV)pDDP->m_lpHandler)(pDX, pDDP->m_nCtrlId,
  1160. (WORD *)pDDP->m_lpMember,
  1161. pDDP->m_lpszOleName );
  1162. break;
  1163. }
  1164. case VT_I4:
  1165. {
  1166. typedef void (AFXAPI *PFV)(CDataExchange *, int,
  1167. long *, LPCTSTR );
  1168. (*(PFV)pDDP->m_lpHandler)(pDX, pDDP->m_nCtrlId,
  1169. (long *)pDDP->m_lpMember,
  1170. pDDP->m_lpszOleName );
  1171. break;
  1172. }
  1173. case VT_UI4:
  1174. {
  1175. typedef void (AFXAPI *PFV)(CDataExchange *, int,
  1176. DWORD *, LPCTSTR );
  1177. (*(PFV)pDDP->m_lpHandler)(pDX, pDDP->m_nCtrlId,
  1178. (DWORD *)pDDP->m_lpMember,
  1179. pDDP->m_lpszOleName);
  1180. break;
  1181. }
  1182. case VT_R4:
  1183. {
  1184. typedef void (AFXAPI *PFV)(CDataExchange *, int,
  1185. float *, LPCTSTR );
  1186. (*(PFV)pDDP->m_lpHandler)(pDX, pDDP->m_nCtrlId,
  1187. (float *)pDDP->m_lpMember,
  1188. pDDP->m_lpszOleName);
  1189. break;
  1190. }
  1191. case VT_R8:
  1192. {
  1193. typedef void (AFXAPI *PFV)(CDataExchange *, int,
  1194. double *, LPCTSTR );
  1195. (*(PFV)pDDP->m_lpHandler)(pDX, pDDP->m_nCtrlId,
  1196. (double *)pDDP->m_lpMember,
  1197. pDDP->m_lpszOleName );
  1198. break;
  1199. }
  1200. case VT_BSTR:
  1201. {
  1202. typedef void (AFXAPI *PFV)(CDataExchange *, int,
  1203. CString *, LPCTSTR );
  1204. (*(PFV)pDDP->m_lpHandler)(pDX, pDDP->m_nCtrlId,
  1205. (CString *)pDDP->m_lpMember,
  1206. pDDP->m_lpszOleName );
  1207. break;
  1208. }
  1209. default:
  1210. // Unknown Data Type!
  1211. ASSERT(FALSE);
  1212. break;
  1213. }
  1214. }
  1215. CATCH(COleDispatchException, e)
  1216. {
  1217. // Dleanup before pDX->Fail() throws exception.
  1218. _AfxCleanupDDPs(arrayDDP);
  1219. // Display message box for dispatch exceptions.
  1220. COlePropertyPage* pPropPage = (COlePropertyPage*)pDX->m_pDlgWnd;
  1221. pPropPage->MessageBox((LPCTSTR)e->m_strDescription, NULL,
  1222. MB_ICONEXCLAMATION | MB_OK);
  1223. DELETE_EXCEPTION(e);
  1224. pDX->Fail();
  1225. }
  1226. AND_CATCH_ALL(e)
  1227. {
  1228. // Ignore other exceptions.
  1229. DELETE_EXCEPTION(e);
  1230. }
  1231. END_CATCH_ALL
  1232. }
  1233. _AfxCleanupDDPs(arrayDDP);
  1234. }
  1235. }
  1236. /////////////////////////////////////////////////////////////////////////////
  1237. // Force any extra compiler-generated code into AFX_INIT_SEG
  1238. #ifdef AFX_INIT_SEG
  1239. #pragma code_seg(AFX_INIT_SEG)
  1240. #endif
  1241. IMPLEMENT_DYNAMIC(COlePropertyPage, CDialog)