Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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