Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1177 lines
29 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows/NT **/
  3. /** Copyright(c) Microsoft Corporation, 1997 - 1999 **/
  4. /**********************************************************************/
  5. /*
  6. proppage.cpp
  7. Implementation for property pages in MMC
  8. FILE HISTORY:
  9. */
  10. #include "stdafx.h"
  11. #include "dialog.h" // for FixupIpAddressHelp
  12. #include <prsht.h>
  13. #ifdef DEBUG_ALLOCATOR
  14. #ifdef _DEBUG
  15. #define new DEBUG_NEW
  16. #undef THIS_FILE
  17. static char THIS_FILE[] = __FILE__;
  18. #endif
  19. #endif
  20. //////////////////////////////////////////////////////////////////////////
  21. // private helper functions
  22. BOOL CALLBACK EnumThreadWndProc(HWND hwnd, /* enumerated HWND */
  23. LPARAM lParam /* pass a HWND* for return value*/ )
  24. {
  25. Assert(hwnd);
  26. HWND hParentWnd = GetParent(hwnd);
  27. // the main window of the MMC console should staitsfy this condition
  28. if ( ((hParentWnd == GetDesktopWindow()) || (hParentWnd == NULL)) && IsWindowVisible(hwnd) )
  29. {
  30. HWND* pH = (HWND*)lParam;
  31. *pH = hwnd;
  32. return FALSE; // stop enumerating
  33. }
  34. else if(hParentWnd)
  35. {
  36. HWND hGrandParentWnd = GetParent(hParentWnd);
  37. // the main window of the MMC console should staitsfy this condition
  38. if ( ((hGrandParentWnd == GetDesktopWindow()) || (hGrandParentWnd == NULL)) && IsWindowVisible(hParentWnd) )
  39. {
  40. HWND* pH = (HWND*)lParam;
  41. *pH = hParentWnd;
  42. return FALSE; // stop enumerating
  43. }
  44. }
  45. return TRUE;
  46. }
  47. HWND FindMMCMainWindow()
  48. {
  49. DWORD dwThreadID = ::GetCurrentThreadId();
  50. Assert(dwThreadID != 0);
  51. HWND hWnd = NULL;
  52. BOOL bEnum = EnumThreadWindows(dwThreadID, EnumThreadWndProc,(LPARAM)&hWnd);
  53. Assert(hWnd != NULL);
  54. return hWnd;
  55. }
  56. /////////////////////////////////////////////////////////////////////////////
  57. // CPropertyPageHolderBase
  58. CPropertyPageHolderBase::CPropertyPageHolderBase
  59. (
  60. ITFSNode * pNode,
  61. IComponentData *pComponentData,
  62. LPCTSTR pszSheetName,
  63. BOOL bIsScopePane
  64. )
  65. {
  66. m_stSheetTitle = pszSheetName;
  67. // default setting for a self deleting modeless property sheet,
  68. // automatically deleting all the pages
  69. m_bWizardMode = TRUE;
  70. m_bAutoDelete = TRUE;
  71. m_bAutoDeletePages = TRUE;
  72. m_nCreatedCount = 0;
  73. m_hSheetWindow = NULL;
  74. m_hConsoleHandle = 0;
  75. m_hEventHandle = NULL;
  76. m_bCalledFromConsole = FALSE;
  77. m_cDirty = 0;
  78. // setup from arguments
  79. SetNode(pNode);
  80. //Assert(pComponentData != NULL);
  81. m_spComponentData.Set(pComponentData);
  82. m_pPropChangePage = NULL;
  83. m_dwLastErr = 0;
  84. m_bSheetPosSet = FALSE;
  85. m_bIsScopePane = bIsScopePane;
  86. m_hThread = NULL;
  87. m_bWiz97 = FALSE;
  88. // by WeiJiang 5/11/98, PeekMessageDuringNotifyConsole flag
  89. m_bPeekMessageDuringNotifyConsole = FALSE;
  90. m_fSetDefaultSheetPos = TRUE;
  91. }
  92. CPropertyPageHolderBase::CPropertyPageHolderBase
  93. (
  94. ITFSNode * pNode,
  95. IComponent * pComponent,
  96. LPCTSTR pszSheetName,
  97. BOOL bIsScopePane
  98. )
  99. {
  100. m_stSheetTitle = pszSheetName;
  101. // default setting for a self deleting modeless property sheet,
  102. // automatically deleting all the pages
  103. m_bWizardMode = TRUE;
  104. m_bAutoDelete = TRUE;
  105. m_bAutoDeletePages = TRUE;
  106. m_nCreatedCount = 0;
  107. m_hSheetWindow = NULL;
  108. m_hConsoleHandle = 0;
  109. m_hEventHandle = NULL;
  110. m_bCalledFromConsole = FALSE;
  111. m_cDirty = 0;
  112. // setup from arguments
  113. SetNode(pNode);
  114. m_spComponent.Set(pComponent);
  115. m_pPropChangePage = NULL;
  116. m_dwLastErr = 0;
  117. m_bSheetPosSet = FALSE;
  118. m_bIsScopePane = bIsScopePane;
  119. m_hThread = NULL;
  120. m_bWiz97 = FALSE;
  121. // by WeiJiang 5/11/98, PeekMessageDuringNotifyConsole flag
  122. m_bPeekMessageDuringNotifyConsole = FALSE;
  123. }
  124. CPropertyPageHolderBase::~CPropertyPageHolderBase()
  125. {
  126. // Remove this assert, we could be dirty if we cancelled the page
  127. // Assert(m_cDirty == 0);
  128. FinalDestruct();
  129. m_spSheetCallback.Release();
  130. if (m_hEventHandle != NULL)
  131. {
  132. VERIFY(::CloseHandle(m_hEventHandle));
  133. m_hEventHandle = NULL;
  134. }
  135. }
  136. HRESULT
  137. CPropertyPageHolderBase::CreateModelessSheet
  138. (
  139. LPPROPERTYSHEETCALLBACK pSheetCallback,
  140. LONG_PTR hConsoleHandle
  141. )
  142. {
  143. Assert(pSheetCallback != NULL);
  144. Assert(m_spSheetCallback == NULL);
  145. Assert( (hConsoleHandle != NULL) && (m_hConsoleHandle == NULL) );
  146. m_hConsoleHandle = hConsoleHandle;
  147. m_bCalledFromConsole = TRUE;
  148. m_bWizardMode = FALSE; // we go modeless
  149. // notify the node it has a sheet up
  150. int nMessage = m_bIsScopePane ? TFS_NOTIFY_CREATEPROPSHEET :
  151. TFS_NOTIFY_RESULT_CREATEPROPSHEET;
  152. if (m_spNode)
  153. m_spNode->Notify(nMessage, (LPARAM) this);
  154. // temporarily attach the sheet callback to this object to add pages
  155. // do not addref, we will not hold on to it;
  156. m_spSheetCallback = pSheetCallback;
  157. HRESULT hr = AddAllPagesToSheet();
  158. m_spSheetCallback.Transfer(); // detach
  159. return hr;
  160. }
  161. HRESULT
  162. CPropertyPageHolderBase::DoModelessSheet()
  163. {
  164. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  165. SPIPropertySheetProvider spSheetProvider;
  166. SPIPropertySheetCallback spSheetCallback;
  167. SPIConsole spConsole;
  168. SPIDataObject spDataObject;
  169. MMC_COOKIE cookie;
  170. HRESULT hr = hrOK;
  171. HWND hWnd;
  172. int nMessage;
  173. m_bWizardMode = FALSE;
  174. // get an interface to a sheet provider
  175. CORg (::CoCreateInstance(CLSID_NodeManager, NULL, CLSCTX_INPROC,
  176. IID_IPropertySheetProvider, reinterpret_cast<void **>(&spSheetProvider)));
  177. Assert(spSheetProvider != NULL);
  178. // get an interface to a sheet callback
  179. CORg( spSheetCallback.HrQuery(spSheetProvider) );
  180. Assert(spSheetCallback != NULL);
  181. m_spSheetCallback.Set(spSheetCallback); // save to add/remove pages
  182. // create a data object for this node
  183. cookie = m_spNode->GetData(TFS_DATA_COOKIE);
  184. if (m_bIsScopePane)
  185. {
  186. CORg( m_spComponentData->QueryDataObject(cookie, CCT_SCOPE, &spDataObject) );
  187. Assert(spDataObject != NULL);
  188. }
  189. else
  190. {
  191. CORg( m_spComponent->QueryDataObject(cookie, CCT_RESULT, &spDataObject) );
  192. Assert(spDataObject != NULL);
  193. }
  194. // create sheet
  195. // CODEWORK: ericdav -- need to possible set options flag -- 0 for now
  196. CORg( spSheetProvider->CreatePropertySheet(m_stSheetTitle,
  197. TRUE /* prop page */, cookie, spDataObject, 0) );
  198. // add pages to sheet
  199. CORg( AddAllPagesToSheet() );
  200. // add pages
  201. // HRESULT AddPrimaryPages(LPUNKNOWN lpUnknown, BOOL bCreateHandle,
  202. // HWND hNotifyWindow, BOOL bScopePane);
  203. if (m_bIsScopePane)
  204. {
  205. //Assert(m_spComponentData != NULL);
  206. CORg( spSheetProvider->AddPrimaryPages(NULL, FALSE, NULL, TRUE) );
  207. }
  208. else
  209. {
  210. //Assert(m_spComponent != NULL);
  211. CORg( spSheetProvider->AddPrimaryPages(NULL, FALSE, NULL, FALSE) );
  212. }
  213. spSheetProvider->AddExtensionPages();
  214. // for further dynamic page manipulation, don't use the Console's
  215. // sheet callback interface but resurt to the Win32 API's
  216. m_spSheetCallback.Release();
  217. hWnd = ::FindMMCMainWindow();
  218. Assert(hWnd != NULL);
  219. CORg( spSheetProvider->Show((LONG_PTR) hWnd, 0) );
  220. // notify the node it has a sheet up
  221. nMessage = m_bIsScopePane ? TFS_NOTIFY_CREATEPROPSHEET :
  222. TFS_NOTIFY_RESULT_CREATEPROPSHEET;
  223. m_spNode->Notify(nMessage, (LPARAM) this);
  224. Error:
  225. return hr;
  226. }
  227. // use this function for property pages on the scope pane
  228. HRESULT DoPropertiesOurselvesSinceMMCSucks(ITFSNode * pNode,
  229. IComponentData * pComponentData,
  230. LPCTSTR pszSheetTitle)
  231. {
  232. Assert(pComponentData != NULL);
  233. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  234. SPIPropertySheetProvider spSheetProvider;
  235. SPIDataObject spDataObject;
  236. MMC_COOKIE cookie;
  237. HRESULT hr = hrOK;
  238. HWND hWnd = NULL;
  239. // get an interface to a sheet provider
  240. CORg (::CoCreateInstance(CLSID_NodeManager, NULL, CLSCTX_INPROC,
  241. IID_IPropertySheetProvider, reinterpret_cast<void **>(&spSheetProvider)));
  242. Assert(spSheetProvider != NULL);
  243. // create a data object for this node
  244. cookie = pNode->GetData(TFS_DATA_COOKIE);
  245. CORg( pComponentData->QueryDataObject(cookie, CCT_SCOPE, &spDataObject) );
  246. Assert(spDataObject != NULL);
  247. // create sheet
  248. // CODEWORK: ericdav -- need to possible set options flag -- 0 for now
  249. CORg( spSheetProvider->CreatePropertySheet(pszSheetTitle,
  250. TRUE /* prop page */, cookie, spDataObject, 0) );
  251. // add pages
  252. // HRESULT AddPrimaryPages(LPUNKNOWN lpUnknown, BOOL bCreateHandle,
  253. // HWND hNotifyWindow, BOOL bScopePane);
  254. // This needs to be fixed. Right now it only works if there is
  255. // one view of the snapin.
  256. //
  257. // As of 5/21/99, we no longer need to do this.
  258. // ----------------------------------------------------------------
  259. // hWnd = ::FindMMCMainWindow();
  260. // hWnd = ::FindWindowEx(hWnd, NULL, L"MDIClient", NULL);
  261. // hWnd = ::FindWindowEx(hWnd, NULL, L"MMCChildFrm", NULL);
  262. // hWnd = ::FindWindowEx(hWnd, NULL, L"MMCView", NULL);
  263. // Assert(hWnd != NULL);
  264. CORg( spSheetProvider->AddPrimaryPages(pComponentData, TRUE, hWnd, TRUE) );
  265. spSheetProvider->AddExtensionPages();
  266. CORg( spSheetProvider->Show((LONG_PTR) hWnd, 0) );
  267. Error:
  268. return hr;
  269. }
  270. // Use this function for property pages on the result pane
  271. HRESULT DoPropertiesOurselvesSinceMMCSucks(ITFSNode * pNode,
  272. IComponent * pComponent,
  273. LPCTSTR pszSheetTitle,
  274. int nVirtualIndex)
  275. {
  276. Assert(pComponent != NULL);
  277. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  278. SPIPropertySheetProvider spSheetProvider;
  279. SPIDataObject spDataObject;
  280. MMC_COOKIE cookie;
  281. HRESULT hr = hrOK;
  282. HWND hWnd;
  283. // get an interface to a sheet provider
  284. CORg (::CoCreateInstance(CLSID_NodeManager, NULL, CLSCTX_INPROC,
  285. IID_IPropertySheetProvider, reinterpret_cast<void **>(&spSheetProvider)));
  286. Assert(spSheetProvider != NULL);
  287. // create a data object for this node
  288. if (nVirtualIndex == -1)
  289. {
  290. cookie = pNode->GetData(TFS_DATA_COOKIE);
  291. }
  292. else
  293. {
  294. cookie = nVirtualIndex;
  295. }
  296. CORg( pComponent->QueryDataObject(cookie, CCT_RESULT, &spDataObject) );
  297. Assert(spDataObject != NULL);
  298. // create sheet
  299. // CODEWORK: ericdav -- need to possible set options flag -- 0 for now
  300. CORg( spSheetProvider->CreatePropertySheet(pszSheetTitle,
  301. TRUE /* prop page */, cookie, spDataObject, 0) );
  302. // add pages
  303. // HRESULT AddPrimaryPages(LPUNKNOWN lpUnknown, BOOL bCreateHandle,
  304. // HWND hNotifyWindow, BOOL bScopePane);
  305. // This needs to be fixed. Right now it only works if there is
  306. // one view of the snapin.
  307. hWnd = ::FindMMCMainWindow();
  308. hWnd = ::FindWindowEx(hWnd, NULL, L"MDIClient", NULL);
  309. hWnd = ::FindWindowEx(hWnd, NULL, L"MMCChildFrm", NULL);
  310. hWnd = ::FindWindowEx(hWnd, NULL, L"MMCView", NULL);
  311. Assert(hWnd != NULL);
  312. CORg( spSheetProvider->AddPrimaryPages(pComponent, TRUE, hWnd, FALSE) );
  313. spSheetProvider->AddExtensionPages();
  314. CORg( spSheetProvider->Show((LONG_PTR) hWnd, 0) );
  315. Error:
  316. return hr;
  317. }
  318. HRESULT
  319. CPropertyPageHolderBase::DoModalWizard()
  320. {
  321. Assert(m_spComponentData != NULL);
  322. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  323. SPIPropertySheetProvider spSheetProvider;
  324. SPITFSComponentData spTFSCompData;
  325. SPIConsole spConsole;
  326. SPIPropertySheetCallback spSheetCallback;
  327. SPIDataObject spDataObject;
  328. HRESULT hr = hrOK;
  329. HWND hWnd;
  330. MMC_COOKIE cookie;
  331. DWORD dwOptions = 0;
  332. m_bWizardMode = TRUE;
  333. CORg( spTFSCompData.HrQuery(m_spComponentData) );
  334. CORg( spTFSCompData->GetConsole(&spConsole) );
  335. // get an interface to a sheet provider
  336. CORg( spSheetProvider.HrQuery(spConsole) );
  337. Assert(spSheetProvider != NULL);
  338. // get an interface to a sheet callback
  339. CORg( spSheetCallback.HrQuery(spConsole) );
  340. Assert(spSheetCallback != NULL);
  341. m_spSheetCallback.Set(spSheetCallback); // save to add/remove pages
  342. // create a data object for this node
  343. cookie = m_spNode->GetData(TFS_DATA_COOKIE);
  344. // Create a dummy data object. AddPrimaryPages will call
  345. // IextendPropertySheet2::QueryPagesFor() and
  346. // IextendPropertySheet2::CreatePropertyPages()
  347. // that will ignore the un-initialized data object
  348. CORg( m_spComponentData->QueryDataObject(-1, CCT_UNINITIALIZED, &spDataObject) );
  349. Assert(spDataObject != NULL);
  350. // create sheet
  351. dwOptions = (m_bWiz97) ? MMC_PSO_NEWWIZARDTYPE : 0;
  352. dwOptions &= ~PSH_WIZARDCONTEXTHELP;
  353. CORg( spSheetProvider->CreatePropertySheet( m_stSheetTitle, FALSE /* wizard*/, cookie, spDataObject, dwOptions) );
  354. // add pages to sheet
  355. CORg( AddAllPagesToSheet() );
  356. // add pages
  357. // HRESULT AddPrimaryPages(LPUNKNOWN lpUnknown, BOOL bCreateHandle, HWND hNotifyWindow, BOOL bScopePane);
  358. if (m_bWiz97)
  359. CORg( spSheetProvider->AddPrimaryPages(spTFSCompData, FALSE, NULL, FALSE) );
  360. else
  361. CORg( spSheetProvider->AddPrimaryPages(NULL, FALSE, NULL, FALSE) );
  362. // for further dynamic page manipulation, don't use the Console's sheet callback interface
  363. // but resurt to the Win32 API's
  364. m_spSheetCallback.Release();
  365. //hWnd = ::FindMMCMainWindow();
  366. // To Support scripting of the MMC console, we need to get the parent from either the
  367. // active window or the desktop...
  368. hWnd = ::GetActiveWindow();
  369. if (hWnd == NULL)
  370. {
  371. hWnd = GetDesktopWindow();
  372. }
  373. Assert(hWnd != NULL);
  374. CORg( spSheetProvider->Show((LONG_PTR)hWnd, 0) );
  375. Error:
  376. return hr;
  377. }
  378. void
  379. CPropertyPageHolderBase::SetSheetWindow
  380. (
  381. HWND hSheetWindow
  382. )
  383. {
  384. Assert(hSheetWindow != NULL);
  385. Assert( (m_hSheetWindow == NULL) || ((m_hSheetWindow == hSheetWindow)) );
  386. m_hSheetWindow = hSheetWindow;
  387. if (!m_hThread)
  388. {
  389. HANDLE hPseudohandle;
  390. hPseudohandle = GetCurrentThread();
  391. BOOL bRet = DuplicateHandle(GetCurrentProcess(),
  392. hPseudohandle,
  393. GetCurrentProcess(),
  394. &m_hThread,
  395. 0,
  396. FALSE,
  397. DUPLICATE_SAME_ACCESS);
  398. if (!bRet)
  399. {
  400. DWORD dwLastErr = GetLastError();
  401. }
  402. Trace1("PROPERTY PAGE HOLDER BASE - Thread ID = %lx\n", GetCurrentThreadId());
  403. }
  404. if (m_hSheetWindow && m_fSetDefaultSheetPos)
  405. SetDefaultSheetPos();
  406. // turn of context sensitive help in the wizard... for some reason
  407. // mmc turns it on and we don't want it
  408. if (m_bWizardMode && m_hSheetWindow)
  409. {
  410. CWnd * pWnd = CWnd::FromHandle(m_hSheetWindow);
  411. if (pWnd)
  412. pWnd->ModifyStyleEx(WS_EX_CONTEXTHELP, 0, 0);
  413. }
  414. }
  415. BOOL
  416. CPropertyPageHolderBase::SetDefaultSheetPos()
  417. {
  418. HRESULT hr = hrOK;
  419. HWND hwndMMC;
  420. RECT rectSheet, rectMMC, rectWorkArea;
  421. SPITFSComponentData spTFSCompData;
  422. SPITFSComponent spTFSComponent;
  423. SPIConsole spConsole;
  424. int nX, nY;
  425. if (m_bSheetPosSet)
  426. return TRUE;
  427. if (m_bIsScopePane)
  428. {
  429. CORg( spTFSCompData.HrQuery(m_spComponentData) );
  430. Assert(spTFSCompData);
  431. CORg( spTFSCompData->GetConsole(&spConsole) );
  432. }
  433. else
  434. {
  435. CORg( spTFSComponent.HrQuery(m_spComponent) );
  436. Assert(spTFSComponent);
  437. CORg( spTFSComponent->GetConsole(&spConsole) );
  438. }
  439. spConsole->GetMainWindow(&hwndMMC);
  440. // get the MMC window and the PropSheet
  441. if (!GetWindowRect(hwndMMC, &rectMMC))
  442. return FALSE;
  443. if (!GetWindowRect(m_hSheetWindow, &rectSheet))
  444. return FALSE;
  445. nX = rectMMC.left + (((rectMMC.right - rectMMC.left) - (rectSheet.right - rectSheet.left)) / 2);
  446. nY = rectMMC.top + (((rectMMC.bottom - rectMMC.top) - (rectSheet.bottom - rectSheet.top)) / 2);
  447. // now check to make sure we're visible
  448. SystemParametersInfo(SPI_GETWORKAREA, 0, &rectWorkArea, 0);
  449. nX = (nX < 0) ? 1 : nX;
  450. nY = (nY < 0) ? 1 : nY;
  451. nX = (nX > (rectWorkArea.right - (rectSheet.right - rectSheet.left))) ?
  452. (rectWorkArea.right - (rectSheet.right - rectSheet.left)) :
  453. nX;
  454. nY = (nY > (rectWorkArea.bottom - (rectSheet.bottom - rectSheet.top))) ?
  455. (rectWorkArea.bottom - (rectSheet.bottom - rectSheet.top)) :
  456. nY;
  457. if (!SetWindowPos(m_hSheetWindow, HWND_TOP, nX, nY, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW))
  458. return FALSE;
  459. m_bSheetPosSet = TRUE;
  460. Error:
  461. return hr == hrOK;
  462. }
  463. void
  464. CPropertyPageHolderBase::Release()
  465. {
  466. m_nCreatedCount--;
  467. if ( m_bAutoDelete && (m_nCreatedCount == 0) )
  468. delete this;
  469. }
  470. void
  471. CPropertyPageHolderBase::ForceDestroy()
  472. {
  473. Assert(!m_bWizardMode); // should never occur on modal wizard
  474. Assert(m_bAutoDelete); // should be self deleting sheet
  475. Assert(::IsWindow(m_hSheetWindow));
  476. HWND hSheetWindow = m_hSheetWindow;
  477. if (hSheetWindow != NULL)
  478. {
  479. // this message will cause the sheet to close all the pages,
  480. // and eventually the destruction of "this"
  481. VERIFY(::PostMessage(hSheetWindow, WM_COMMAND, IDCANCEL, 0L) != 0);
  482. //VERIFY(::SendMessage(hSheetWindow, WM_CLOSE, 0, 0) == 0);
  483. }
  484. else
  485. {
  486. // explicitely delete "this", there is no sheet created
  487. delete this;
  488. return;
  489. }
  490. // now, if we've been initialized then wait for the property sheet thread
  491. // to terminate. The property sheet provider is holding onto our dataobject
  492. // that needs to be freed up before we can continue our cleanup. Also,
  493. // the cleanup does a sendmessage which will block if we don't forward
  494. // messages along.
  495. if (m_hThread)
  496. {
  497. DWORD dwRet;
  498. MSG msg;
  499. while(1)
  500. {
  501. dwRet = MsgWaitForMultipleObjects(1, &m_hThread, FALSE, INFINITE, QS_ALLINPUT);
  502. if (dwRet == WAIT_OBJECT_0)
  503. return; // The event was signaled
  504. if (dwRet != WAIT_OBJECT_0 + 1)
  505. break; // Something else happened
  506. // There is one or more window message available. Dispatch them
  507. while(PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE))
  508. {
  509. TranslateMessage(&msg);
  510. DispatchMessage(&msg);
  511. if (WaitForSingleObject(m_hThread, 0) == WAIT_OBJECT_0)
  512. return; // Event is now signaled.
  513. }
  514. }
  515. }
  516. }
  517. DWORD
  518. CPropertyPageHolderBase::NotifyConsole(CPropertyPageBase* pPage)
  519. {
  520. MSG msg;
  521. Assert(m_spNode != NULL);
  522. if (m_bWizardMode)
  523. {
  524. Assert(m_hConsoleHandle == NULL);
  525. return 0;
  526. }
  527. m_pPropChangePage = pPage; // to pass to the main thread
  528. m_dwLastErr = 0x0;
  529. Assert(m_hConsoleHandle != NULL);
  530. if (m_hEventHandle == NULL)
  531. {
  532. m_hEventHandle = ::CreateEvent(NULL,TRUE /*bManualReset*/,FALSE /*signalled*/, NULL);
  533. Assert(m_hEventHandle != NULL);
  534. }
  535. MMCPropertyChangeNotify(m_hConsoleHandle, reinterpret_cast<LONG_PTR>(this));
  536. Trace0("before wait\n");
  537. while ( WAIT_OBJECT_0 != ::WaitForSingleObject(m_hEventHandle, 500) )
  538. {
  539. // by WeiJiang 5/11/98, PeekMessageDuringNotifyConsole flag
  540. if(m_bPeekMessageDuringNotifyConsole)
  541. {
  542. // clean out the message queue while we wait
  543. while (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
  544. {
  545. TranslateMessage(&msg);
  546. DispatchMessage(&msg);
  547. }
  548. }
  549. }
  550. Trace0("after wait\n");
  551. VERIFY(0 != ::ResetEvent(m_hEventHandle));
  552. return m_dwLastErr;
  553. }
  554. void
  555. CPropertyPageHolderBase::AcknowledgeNotify()
  556. {
  557. Assert(!m_bWizardMode);
  558. Assert(m_hEventHandle != NULL);
  559. Trace0("before SetEvent\n");
  560. VERIFY(0 != ::SetEvent(m_hEventHandle));
  561. Trace0("after SetEvent\n");
  562. }
  563. BOOL
  564. CPropertyPageHolderBase::SetWizardButtons
  565. (
  566. DWORD dwFlags
  567. )
  568. {
  569. Assert(m_bWizardMode);
  570. Assert(::IsWindow(m_hSheetWindow));
  571. return (BOOL)SendMessage(m_hSheetWindow, PSM_SETWIZBUTTONS, 0, dwFlags);
  572. }
  573. BOOL
  574. CPropertyPageHolderBase::PressButton
  575. (
  576. int nButton
  577. )
  578. {
  579. Assert(m_bWizardMode);
  580. Assert(::IsWindow(m_hSheetWindow));
  581. return (BOOL) SendMessage(m_hSheetWindow, PSM_PRESSBUTTON, nButton, 0);
  582. }
  583. HRESULT
  584. CPropertyPageHolderBase::AddPageToSheet
  585. (
  586. CPropertyPageBase* pPage
  587. )
  588. {
  589. // remove the help button
  590. if (m_bWiz97)
  591. pPage->m_psp97.dwFlags &= ~PSP_HASHELP;
  592. else
  593. pPage->m_psp.dwFlags &= ~PSP_HASHELP;
  594. // call the MMC function because we are using MFC based pages
  595. if (!m_bWizardMode)
  596. {
  597. // if we are doing a property sheet then tell MMC to hook
  598. // the proc because we are running on a separate, non MFC thread.
  599. // Wizards don't run on a separate thread and therefore
  600. // don't need to make this call.
  601. if (m_bWiz97)
  602. VERIFY(SUCCEEDED(MMCPropPageCallback(&pPage->m_psp97)));
  603. else
  604. VERIFY(SUCCEEDED(MMCPropPageCallback(&pPage->m_psp)));
  605. }
  606. HPROPSHEETPAGE hPage;
  607. if (m_bWiz97)
  608. hPage = ::CreatePropertySheetPage(&pPage->m_psp97);
  609. else
  610. hPage = ::CreatePropertySheetPage(&pPage->m_psp);
  611. if (hPage == NULL)
  612. return E_UNEXPECTED;
  613. pPage->m_hPage = hPage;
  614. if (m_spSheetCallback != NULL)
  615. return m_spSheetCallback->AddPage(hPage);
  616. else
  617. {
  618. Assert(::IsWindow(m_hSheetWindow));
  619. return PropSheet_AddPage(m_hSheetWindow, hPage) ? S_OK : E_FAIL;
  620. }
  621. }
  622. HRESULT
  623. CPropertyPageHolderBase::RemovePageFromSheet
  624. (
  625. CPropertyPageBase* pPage
  626. )
  627. {
  628. Assert(pPage->m_hPage != NULL);
  629. if (m_spSheetCallback != NULL)
  630. return m_spSheetCallback->RemovePage(pPage->m_hPage);
  631. else
  632. {
  633. Assert(::IsWindow(m_hSheetWindow));
  634. return PropSheet_RemovePage(m_hSheetWindow, 0, pPage->m_hPage) ? S_OK : E_FAIL;
  635. }
  636. }
  637. HRESULT
  638. CPropertyPageHolderBase::AddAllPagesToSheet()
  639. {
  640. POSITION pos;
  641. for( pos = m_pageList.GetHeadPosition(); pos != NULL; )
  642. {
  643. CPropertyPageBase* pPropPage = m_pageList.GetNext(pos);
  644. HRESULT hr = AddPageToSheet(pPropPage);
  645. Assert(SUCCEEDED(hr));
  646. if (FAILED(hr))
  647. return hr;
  648. }
  649. return S_OK;
  650. }
  651. void
  652. CPropertyPageHolderBase::AddPageToList
  653. (
  654. CPropertyPageBase* pPage
  655. )
  656. {
  657. Assert(pPage != NULL);
  658. pPage->SetHolder(this);
  659. m_pageList.AddTail(pPage);
  660. }
  661. BOOL
  662. CPropertyPageHolderBase::RemovePageFromList
  663. (
  664. CPropertyPageBase* pPage,
  665. BOOL bDeleteObject
  666. )
  667. {
  668. Assert(pPage != NULL);
  669. POSITION pos = m_pageList.Find(pPage);
  670. if (pos == NULL)
  671. return FALSE;
  672. m_pageList.RemoveAt(pos);
  673. if (bDeleteObject)
  674. delete pPage;
  675. return TRUE;
  676. }
  677. void
  678. CPropertyPageHolderBase::DeleteAllPages()
  679. {
  680. if (!m_bAutoDeletePages)
  681. return;
  682. // assume all pages out of the heap
  683. while (!m_pageList.IsEmpty())
  684. {
  685. delete m_pageList.RemoveTail();
  686. }
  687. }
  688. void
  689. CPropertyPageHolderBase::FinalDestruct()
  690. {
  691. DeleteAllPages();
  692. if (m_bWizardMode)
  693. return;
  694. // if we were a modeless sheet, have to cleanup
  695. if (m_bCalledFromConsole)
  696. {
  697. Assert(m_hConsoleHandle != NULL);
  698. MMCFreeNotifyHandle(m_hConsoleHandle);
  699. }
  700. // Notify the node that this sheet is going away
  701. //
  702. int nMessage = m_bIsScopePane ? TFS_NOTIFY_DELETEPROPSHEET :
  703. TFS_NOTIFY_RESULT_DELETEPROPSHEET;
  704. if (m_spNode)
  705. {
  706. m_spNode->Notify(nMessage, (LPARAM) this);
  707. }
  708. }
  709. HWND
  710. CPropertyPageHolderBase::SetActiveWindow()
  711. {
  712. return ::SetActiveWindow(m_hSheetWindow);
  713. }
  714. BOOL CPropertyPageHolderBase::OnPropertyChange(BOOL bScopePane, LONG_PTR * pChangeMask)
  715. {
  716. ASSERT(!IsWizardMode());
  717. CPropertyPageBase* pPage = GetPropChangePage();
  718. if (pPage == NULL)
  719. return FALSE;
  720. return pPage->OnPropertyChange(bScopePane, pChangeMask);
  721. }
  722. /////////////////////////////////////////////////////////////////////////////
  723. // CPropertyPageBase
  724. IMPLEMENT_DYNCREATE(CPropertyPageBase, CPropertyPage)
  725. BEGIN_MESSAGE_MAP(CPropertyPageBase, CPropertyPage)
  726. ON_WM_CREATE()
  727. ON_WM_DESTROY()
  728. // help overrides
  729. ON_WM_HELPINFO()
  730. ON_WM_CONTEXTMENU()
  731. END_MESSAGE_MAP()
  732. CPropertyPageBase::CPropertyPageBase
  733. (
  734. UINT nIDTemplate,
  735. UINT nIDCaption
  736. ) : CPropertyPage(nIDTemplate, nIDCaption)
  737. {
  738. m_hPage = NULL;
  739. m_pPageHolder = NULL;
  740. m_bIsDirty = FALSE;
  741. }
  742. CPropertyPageBase::~CPropertyPageBase()
  743. {
  744. }
  745. int
  746. CPropertyPageBase::OnCreate
  747. (
  748. LPCREATESTRUCT lpCreateStruct
  749. )
  750. {
  751. if (m_pPageHolder)
  752. m_pPageHolder->AddRef();
  753. int res = CPropertyPage::OnCreate(lpCreateStruct);
  754. Assert(res == 0);
  755. Assert(m_hWnd != NULL);
  756. Assert(::IsWindow(m_hWnd));
  757. HWND hParent = ::GetParent(m_hWnd);
  758. Assert(hParent);
  759. if (m_pPageHolder)
  760. m_pPageHolder->SetSheetWindow(hParent);
  761. return res;
  762. }
  763. void
  764. CPropertyPageBase::OnDestroy()
  765. {
  766. Assert(m_hWnd != NULL);
  767. CPropertyPage::OnDestroy();
  768. if (m_pPageHolder)
  769. m_pPageHolder->Release();
  770. }
  771. BOOL
  772. CPropertyPageBase::OnApply()
  773. {
  774. if (IsDirty())
  775. {
  776. if (!m_pPageHolder ||
  777. m_pPageHolder->NotifyConsole(this) == 0x0)
  778. {
  779. SetDirty(FALSE);
  780. return TRUE;
  781. }
  782. else
  783. {
  784. return FALSE;
  785. }
  786. }
  787. return TRUE;
  788. }
  789. void CPropertyPageBase::CancelApply()
  790. {
  791. if (m_pPageHolder)
  792. m_pPageHolder->NotifyConsole(this);
  793. }
  794. // NOTE: This function must be called for all wizard 97 pages.
  795. // Since there are different sizes of the psp struct, depending
  796. // on how the project was compiled (common lib is compiled with
  797. // the wiz97 propsheet header and the snapin directory may not)
  798. // this function should only be called when running wizard 97 pages.
  799. // This allows us to have snapins that use the same code for both
  800. // old and new style wizards.
  801. void CPropertyPageBase::InitWiz97(BOOL bHideHeader,
  802. UINT nIDHeaderTitle,
  803. UINT nIDHeaderSubTitle)
  804. {
  805. // hack to have new struct size with old MFC and new NT 5.0 headers
  806. ZeroMemory(&m_psp97, sizeof(PROPSHEETPAGE));
  807. memcpy(&m_psp97, &m_psp, m_psp.dwSize);
  808. m_psp97.dwSize = sizeof(PROPSHEETPAGE);
  809. if (bHideHeader)
  810. {
  811. // for first and last page of the wizard
  812. m_psp97.dwFlags |= PSP_HIDEHEADER;
  813. }
  814. else
  815. {
  816. // for intermediate pages
  817. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  818. m_szHeaderTitle.LoadString(nIDHeaderTitle);
  819. m_szHeaderSubTitle.LoadString(nIDHeaderSubTitle);
  820. m_psp97.dwFlags |= PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
  821. m_psp97.pszHeaderTitle = (LPCTSTR)m_szHeaderTitle;
  822. m_psp97.pszHeaderSubTitle = (LPCTSTR)m_szHeaderSubTitle;
  823. }
  824. }
  825. /*!--------------------------------------------------------------------------
  826. CPropertyPageBase::OnHelpInfo
  827. Brings up the context-sensitive help for the controls.
  828. Author: EricDav
  829. ---------------------------------------------------------------------------*/
  830. BOOL CPropertyPageBase::OnHelpInfo(HELPINFO* pHelpInfo)
  831. {
  832. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  833. int i;
  834. DWORD dwCtrlId;
  835. if (pHelpInfo->iContextType == HELPINFO_WINDOW)
  836. {
  837. DWORD * pdwHelp = GetHelpMapInternal();
  838. if (pdwHelp)
  839. {
  840. // Ok to fix the f**king help for the f**king IP address
  841. // controls, we will need to add special case code. If we
  842. // can't find the id of our control in our list, then we look
  843. // to see if this is the child of the "RtrIpAddress" control, if
  844. // so then we change the pHelpInfo->hItemHandle to point to the
  845. // handle of the ip address control rather than the control in
  846. // the ip addrss control. *SIGH*
  847. dwCtrlId = ::GetDlgCtrlID((HWND) pHelpInfo->hItemHandle);
  848. for (i=0; pdwHelp[i]; i+=2)
  849. {
  850. if (pdwHelp[i] == dwCtrlId)
  851. break;
  852. }
  853. if (pdwHelp[i] == 0)
  854. {
  855. // Ok, we didn't find the control in our list, so let's
  856. // check to see if it's part of the IP address control.
  857. pHelpInfo->hItemHandle = FixupIpAddressHelp((HWND) pHelpInfo->hItemHandle);
  858. }
  859. ::WinHelp ((HWND)pHelpInfo->hItemHandle,
  860. AfxGetApp()->m_pszHelpFilePath,
  861. HELP_WM_HELP,
  862. (ULONG_PTR)pdwHelp);
  863. }
  864. }
  865. return TRUE;
  866. }
  867. /*!--------------------------------------------------------------------------
  868. CBaseDialog::OnContextMenu
  869. Brings up the help context menu for those controls that don't
  870. usually have context menus (i.e. buttons). Note that this won't
  871. work for static controls since they just eat up all messages.
  872. Author: KennT
  873. ---------------------------------------------------------------------------*/
  874. void CPropertyPageBase::OnContextMenu(CWnd* pWnd, CPoint point)
  875. {
  876. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  877. DWORD * pdwHelp = GetHelpMapInternal();
  878. if (pdwHelp)
  879. {
  880. ::WinHelp (pWnd->m_hWnd,
  881. AfxGetApp()->m_pszHelpFilePath,
  882. HELP_CONTEXTMENU,
  883. (ULONG_PTR)pdwHelp);
  884. }
  885. }
  886. // This can be found in dialog.cpp
  887. extern PFN_FINDHELPMAP g_pfnHelpMap;
  888. DWORD * CPropertyPageBase::GetHelpMapInternal()
  889. {
  890. DWORD * pdwHelpMap = NULL;
  891. DWORD dwIDD = 0;
  892. if ((ULONG_PTR) m_lpszTemplateName < 0xFFFF)
  893. dwIDD = (WORD) m_lpszTemplateName;
  894. // If there is no dialog IDD, give up
  895. // If there is no global help map function, give up
  896. if ((dwIDD == 0) ||
  897. (g_pfnHelpMap == NULL) ||
  898. ((pdwHelpMap = g_pfnHelpMap(dwIDD)) == NULL))
  899. return GetHelpMap();
  900. return pdwHelpMap;
  901. }
  902. struct EnableChildControlsEnumParam
  903. {
  904. HWND m_hWndParent;
  905. DWORD m_dwFlags;
  906. };
  907. BOOL CALLBACK EnableChildControlsEnumProc(HWND hWnd, LPARAM lParam)
  908. {
  909. EnableChildControlsEnumParam * pParam;
  910. pParam = reinterpret_cast<EnableChildControlsEnumParam *>(lParam);
  911. // Enable/disable only if this is an immediate descendent
  912. if (GetParent(hWnd) == pParam->m_hWndParent)
  913. {
  914. if (pParam->m_dwFlags & PROPPAGE_CHILD_SHOW)
  915. ::ShowWindow(hWnd, SW_SHOW);
  916. else if (pParam->m_dwFlags & PROPPAGE_CHILD_HIDE)
  917. ::ShowWindow(hWnd, SW_HIDE);
  918. if (pParam->m_dwFlags & PROPPAGE_CHILD_ENABLE)
  919. ::EnableWindow(hWnd, TRUE);
  920. else if (pParam->m_dwFlags & PROPPAGE_CHILD_DISABLE)
  921. ::EnableWindow(hWnd, FALSE);
  922. }
  923. return TRUE;
  924. }
  925. HRESULT EnableChildControls(HWND hWnd, DWORD dwFlags)
  926. {
  927. EnableChildControlsEnumParam param;
  928. param.m_hWndParent = hWnd;
  929. param.m_dwFlags = dwFlags;
  930. EnumChildWindows(hWnd, EnableChildControlsEnumProc, (LPARAM) &param);
  931. return hrOK;
  932. }
  933. HRESULT MultiEnableWindow(HWND hWndParent, BOOL fEnable, UINT first, ...)
  934. {
  935. UINT nCtrlId = first;
  936. HWND hWndCtrl;
  937. va_list marker;
  938. va_start(marker, first);
  939. while (nCtrlId != 0)
  940. {
  941. hWndCtrl = ::GetDlgItem(hWndParent, nCtrlId);
  942. Assert(hWndCtrl);
  943. if (hWndCtrl)
  944. ::EnableWindow(hWndCtrl, fEnable);
  945. // get the next item
  946. nCtrlId = va_arg(marker, UINT);
  947. }
  948. va_end(marker);
  949. return hrOK;
  950. }