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.

498 lines
13 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: N C P R S H T . C P P
  7. //
  8. // Contents: NetCfg custom PropertySheet
  9. //
  10. // Notes:
  11. //
  12. // Author: billbe 8 Apr 1997
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include "ncprsht.h"
  18. #include <prsht.h>
  19. #include "nceh.h"
  20. // Necessary evil globals
  21. CAPAGES g_capPagesToAdd; // Counted array of pages to add after Property
  22. // Sheet is initialized
  23. CAINCP g_cai; // Counted array of INetCfgProperty pointers
  24. HRESULT g_hr; // Global error code
  25. BOOL g_fChanged; // Global flag representing whether a PSM_CHANGED
  26. // message was sent by a page
  27. DLGPROC lpfnOldWndProc; // Previous dialog procedure
  28. // NetCfg Property Sheet dialog procedure
  29. LONG FAR PASCAL NetCfgPsDlgProc(HWND hDlg, UINT msg, WPARAM wParam,
  30. LPARAM lParam);
  31. //+---------------------------------------------------------------------------
  32. //
  33. // Function: SetLastHresult
  34. //
  35. // Purpose: This sets a global hresult variable. The function
  36. // is analogous to SetLastError
  37. //
  38. // Arguments:
  39. // HRESULT [in] Result to set
  40. //
  41. // Returns: nothing
  42. //
  43. // Author: billbe 8 Apr 1997
  44. //
  45. // Notes:
  46. //
  47. //
  48. inline void
  49. SetLastHresult(HRESULT hr)
  50. {
  51. g_hr = hr;
  52. }
  53. //+---------------------------------------------------------------------------
  54. //
  55. // Function: HrGetLastHresult
  56. //
  57. // Purpose: This returns the value of the global hresult variable.
  58. // The function is analogous to GetLastError
  59. //
  60. // Arguments:
  61. // none
  62. //
  63. // Returns: HRESULT. Value of the global g_hr.
  64. //
  65. // Author: billbe 8 Apr 1997
  66. //
  67. // Notes:
  68. //
  69. //
  70. inline HRESULT
  71. HrGetLastHresult()
  72. {
  73. return (g_hr);
  74. }
  75. //+---------------------------------------------------------------------------
  76. //
  77. // Function: ResetChanged
  78. //
  79. // Purpose: This resets the global changed flag. The reset state
  80. // indicates that a PSM_VHANGED message was not sent
  81. //
  82. // Arguments:
  83. // none
  84. //
  85. // Returns:
  86. // (nothing)
  87. //
  88. // Author: billbe 3 May 1997
  89. //
  90. // Notes:
  91. //
  92. //
  93. inline void
  94. ResetChanged()
  95. {
  96. g_fChanged = FALSE;
  97. }
  98. //+---------------------------------------------------------------------------
  99. //
  100. // Function: SetChanged
  101. //
  102. // Purpose: This sets the global changed flag. The set state indicates
  103. // that a PSM_CHANGED message was sent
  104. //
  105. // Arguments:
  106. // none
  107. //
  108. // Returns:
  109. // (nothing)
  110. //
  111. // Author: billbe 3 May 1997
  112. //
  113. // Notes:
  114. //
  115. //
  116. inline void
  117. SetChanged()
  118. {
  119. g_fChanged = TRUE;
  120. }
  121. //+---------------------------------------------------------------------------
  122. //
  123. // Function: FGetChanged
  124. //
  125. // Purpose: This returns the state of the global changed flag. The set
  126. // state indicates whether a PSM_CHANGED message was sent
  127. // or not.
  128. //
  129. // Arguments:
  130. // none
  131. //
  132. // Returns:
  133. // BOOL. Value of the global g_fChanged flag.
  134. //
  135. // Author: billbe 3 May 1997
  136. //
  137. // Notes:
  138. //
  139. //
  140. inline BOOL
  141. FGetChanged()
  142. {
  143. return (g_fChanged);
  144. }
  145. //+---------------------------------------------------------------------------
  146. //
  147. // Function: NetCfgPropSheetCallback
  148. //
  149. // Purpose: This callback is called after the aheet dialog is
  150. // initialized. We subclass the dialog and add any OEM
  151. // pages here (if common pages exist). See Win32 for
  152. // discussion of PropSheetProc
  153. //
  154. // Arguments:
  155. // HWND [in] hwndDlg handle to the property sheet dialog box
  156. // UINT uMsg [in] message identifier
  157. // LPARAM lParam [in] message parameter
  158. //
  159. // Returns: int, The function returns zero.
  160. //
  161. // Author: billbe 11 Nov 1996
  162. //
  163. // Notes:
  164. //
  165. //
  166. int
  167. CALLBACK NetCfgPropSheetCallback(HWND hwndDlg, UINT uMsg, LPARAM lParam)
  168. {
  169. // If the sheet has just been initialized
  170. if (uMsg == PSCB_INITIALIZED)
  171. {
  172. // Replace the original procedure with ours
  173. lpfnOldWndProc = (DLGPROC)SetWindowLongPtr(hwndDlg, DWLP_DLGPROC, (LONG_PTR) NetCfgPsDlgProc);
  174. Assert(lpfnOldWndProc);
  175. // Add the OEM pages that were scheduled for late add
  176. // This will cause them to be clipped if they are larger than
  177. // the common (default) pages. Note that this is the desired
  178. // result.
  179. //
  180. for (int i = 0; i < g_capPagesToAdd.nCount; i++)
  181. {
  182. PropSheet_AddPage(hwndDlg, g_capPagesToAdd.ahpsp[i]);
  183. }
  184. }
  185. return (0);
  186. }
  187. //+---------------------------------------------------------------------------
  188. //
  189. // Function: HrCallValidateProperties
  190. //
  191. // Purpose: This function calls the notify objects'
  192. // INetCfgProperties::ValidateProperties method.
  193. //
  194. // Arguments:
  195. // none
  196. //
  197. // Returns: HRESULT, S_OK if all of the INetCfgProperties return S_OK
  198. // of the result of the first interface that does not
  199. // return S_OK.
  200. //
  201. // Author: billbe 8 Apr 1997
  202. //
  203. // Notes: If one of the interfaces returns something other than S_OK, the
  204. // others will not be called and the function will return the hresult
  205. // of that interface.
  206. //
  207. HRESULT
  208. HrCallValidateProperties(HWND hwndSheet)
  209. {
  210. HRESULT hr = S_OK;
  211. // enumerate through the counted array of interfaces
  212. // and call ValidateProperties
  213. //
  214. for (int i = 0; i < g_cai.nCount; i++)
  215. {
  216. // At the first sign of non-S_OK get out
  217. if (S_OK != (hr = g_cai.apncp[i]->ValidateProperties(hwndSheet)))
  218. break;
  219. }
  220. TraceError("HrCallValidateProperties", hr);
  221. return (hr);
  222. }
  223. //+---------------------------------------------------------------------------
  224. //
  225. // Function: NetCfgPsDlgProc
  226. //
  227. // Purpose: This function is the dialog procedure for the property sheet
  228. // See Win32 documentation on DialogProc for more information
  229. //
  230. // Arguments:
  231. // hwndDlg [in] handle to dialog box
  232. // uMsg [in] message
  233. // wParam [in] first message parameter
  234. // lParam [in] second message parameter
  235. //
  236. // Returns: LONG, Except in response to the WM_INITDIALOG message, the
  237. // dialog box procedure should return nonzero if it processes
  238. // the message, and zero if it does not.
  239. //
  240. // Author: billbe 8 Apr 1997
  241. //
  242. // Notes:
  243. //
  244. LONG
  245. FAR PASCAL NetCfgPsDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  246. {
  247. switch (msg)
  248. {
  249. case WM_DESTROY:
  250. // restore the dialog procedure before we exit
  251. SetWindowLongPtr(hDlg, DWLP_DLGPROC, (LONG_PTR) lpfnOldWndProc);
  252. break;
  253. case WM_SYSCOMMAND:
  254. // The user is closing through the system menu. This is like
  255. // canceling
  256. if (SC_CLOSE == wParam)
  257. {
  258. SetLastHresult(HRESULT_FROM_WIN32(ERROR_CANCELLED));
  259. }
  260. break;
  261. case PSM_CHANGED:
  262. SetChanged();
  263. break;
  264. case WM_COMMAND:
  265. // If the user pressed OK
  266. if ((IDOK == LOWORD(wParam)) && (BN_CLICKED == HIWORD(wParam)))
  267. {
  268. // Send a KillActive message to the currect page. This echoes
  269. // what the Win32 propertysheet would do. This results in a
  270. // second KillActive message being sent to the active page
  271. // when the OK message is processed. It is necessary
  272. // to send it here because we need its result before we
  273. // call HrCallValidateProperties which is done before the OK
  274. // is processed.
  275. //
  276. NMHDR nmhdr;
  277. ZeroMemory(&nmhdr, sizeof(NMHDR));
  278. nmhdr.hwndFrom = hDlg;
  279. nmhdr.code = PSN_KILLACTIVE;
  280. if (SendMessage(PropSheet_GetCurrentPageHwnd(hDlg), WM_NOTIFY,
  281. 0, (LPARAM) &nmhdr))
  282. {
  283. // The page does not want the PropertySheet to go away so exit
  284. // without allowing the original procedure to get the message
  285. return (TRUE);
  286. }
  287. // The current page validated okay so now we must call all the
  288. // ValidateProperties necessary.
  289. if (S_OK != HrCallValidateProperties(hDlg))
  290. {
  291. // One of the interfaces returned something other than S_OK
  292. // from Validateproperties so we exit without letting
  293. // the original dialog procedure process the message.
  294. // This will keep the PropertySheet active.
  295. return (TRUE);
  296. }
  297. }
  298. else if (IDCANCEL == LOWORD(wParam) && BN_CLICKED == HIWORD(wParam))
  299. {
  300. // If Cancel was pressed set the last hresult
  301. SetLastHresult(HRESULT_FROM_WIN32(ERROR_CANCELLED));
  302. }
  303. break;
  304. }
  305. // call the original dialog procedure
  306. return (CallWindowProc((WNDPROC)lpfnOldWndProc, hDlg, msg, wParam, lParam));
  307. }
  308. //+---------------------------------------------------------------------------
  309. //
  310. // Function: VerifyCAPAGES
  311. //
  312. // Synopsis: function to check the validity of a given CAPAGES structure
  313. //
  314. // Arguments: [cap] --
  315. //
  316. // Returns: BOOL
  317. //
  318. // Notes: 14-Jan-1998 SumitC Created
  319. //
  320. //----------------------------------------------------------------------------
  321. BOOL
  322. FVerifyCAPAGES(const struct CAPAGES& cap)
  323. {
  324. BOOL fGood = FALSE;
  325. if (cap.nCount == 0)
  326. {
  327. fGood = (cap.ahpsp == NULL);
  328. }
  329. else
  330. {
  331. fGood = !IsBadReadPtr(cap.ahpsp, sizeof(HPROPSHEETPAGE) * cap.nCount);
  332. }
  333. return fGood;
  334. }
  335. //+---------------------------------------------------------------------------
  336. //
  337. // Function: HrNetCfgPropertySheet
  338. //
  339. // Purpose: This function is sets up our custom property sheet which is
  340. // a subclassed Win32 property sheet.
  341. // See Win32 documentation on PropertySheet for more information
  342. //
  343. // Arguments:
  344. // lppsh [in] a PROPSHEETHEADER
  345. // capOem [in] A counted array of Oem pages
  346. // pStartPage [in] Name of the initial page that appears when the property
  347. // sheet dialog box is created. This member can specify
  348. // either the identifier of a string resource or the
  349. // pointer to a string that specifies the name.
  350. // caiProperties [in] A counted array of INetCfgProperties interfaces
  351. //
  352. // Returns: HRESULT, S_OK if OK was pressed and changes were made,
  353. // S_FALSE if OK was pressed and no changes were
  354. // made. An error code otherwise.
  355. //
  356. // Author: billbe 8 Apr 1997
  357. //
  358. // Notes:
  359. // HRESULT_FROM_WIN32(ERROR_CANCELLED) is returned if the
  360. // cancel button was pressed
  361. //
  362. HRESULT
  363. HrNetCfgPropertySheet(
  364. IN OUT LPPROPSHEETHEADER lppsh,
  365. IN const CAPAGES& capOem,
  366. IN PCWSTR pStartPage,
  367. const CAINCP& caiProperties)
  368. {
  369. HRESULT hr = S_OK;
  370. Assert(lppsh);
  371. // The following should not be set since we are setting them
  372. Assert(0 == lppsh->nPages);
  373. Assert(NULL == lppsh->phpage);
  374. Assert(!(PSH_USECALLBACK & lppsh->dwFlags));
  375. Assert(!(PSH_PROPSHEETPAGE & lppsh->dwFlags));
  376. // If a start page was specified than there had better be Oem Pages
  377. Assert(FImplies(pStartPage, capOem.nCount));
  378. // We have to have at least one INetCfgProperties since we are here
  379. Assert(caiProperties.nCount);
  380. Assert(caiProperties.apncp);
  381. // Set our global CAINCP structure
  382. g_cai.nCount = caiProperties.nCount;
  383. g_cai.apncp = caiProperties.apncp;
  384. // Reset our global CAPAGES
  385. g_capPagesToAdd.nCount = 0;
  386. g_capPagesToAdd.ahpsp = NULL;
  387. // We need to set up a callback to subclass the dialog
  388. lppsh->dwFlags |= PSH_USECALLBACK;
  389. lppsh->pfnCallback = NetCfgPropSheetCallback;
  390. // There are no common pages to show so we will use the OEM pages
  391. // instead
  392. Assert(capOem.nCount);
  393. if (FVerifyCAPAGES(capOem))
  394. {
  395. lppsh->nPages = capOem.nCount;
  396. lppsh->phpage = capOem.ahpsp;
  397. }
  398. else
  399. {
  400. //$ REVIEW sumitc: or just return E_INVALIDARG?
  401. lppsh->nPages = 0;
  402. lppsh->phpage = NULL;
  403. }
  404. Assert(FImplies(lppsh->nPages, lppsh->phpage));
  405. // If a start page was specified, set the propsheet flag and
  406. // start page member.
  407. // Note: (billbe) This will not work if common pages exist since
  408. // that means Oem pages are added after the sheet is initialized
  409. if (pStartPage)
  410. {
  411. lppsh->dwFlags |= PSH_USEPSTARTPAGE;
  412. lppsh->pStartPage = pStartPage;
  413. }
  414. // Clear last hresult and changed flag
  415. SetLastHresult(S_OK);
  416. ResetChanged();
  417. // Call the Win32 property sheet
  418. NC_TRY
  419. {
  420. int iRetVal = PropertySheet(lppsh);
  421. if (-1 == iRetVal)
  422. {
  423. // The Win32 Sheet failed so we return E_FAIL
  424. SetLastHresult(E_FAIL);
  425. }
  426. }
  427. NC_CATCH_ALL
  428. {
  429. hr = E_UNEXPECTED;
  430. }
  431. if (S_OK == hr)
  432. {
  433. // if the catch hasn't set hr to some error
  434. hr = HrGetLastHresult();
  435. }
  436. // if everthing went well, return the correct value based on whether
  437. // any of the pages changed
  438. //
  439. if (SUCCEEDED(hr))
  440. {
  441. // S_OK - changes were made, S_FALSE - no changes were made
  442. hr = FGetChanged() ? S_OK : S_FALSE;
  443. }
  444. TraceError("HrNetCfgPropertySheet",
  445. ((HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr) || (S_FALSE == hr)) ? S_OK : hr);
  446. return hr;
  447. }