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.

871 lines
31 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. devprop.c
  5. Abstract:
  6. Device Installer functions for property sheet support.
  7. Author:
  8. Lonny McMichael (lonnym) 07-Sep-1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. //
  14. // Private routine prototypes.
  15. //
  16. BOOL
  17. CALLBACK
  18. pSetupAddPropPage(
  19. IN HPROPSHEETPAGE hPage,
  20. IN LPARAM lParam
  21. );
  22. //
  23. // Define the context structure that gets passed to pSetupAddPropPage as lParam.
  24. //
  25. typedef struct _SP_PROPPAGE_ADDPROC_CONTEXT {
  26. BOOL NoCancelOnFailure; // input
  27. LPPROPSHEETHEADER PropertySheetHeader; // input
  28. DWORD PageListSize; // input
  29. DWORD NumPages; // output
  30. } SP_PROPPAGE_ADDPROC_CONTEXT, *PSP_PROPPAGE_ADDPROC_CONTEXT;
  31. #ifdef UNICODE
  32. //
  33. // ANSI version
  34. //
  35. BOOL
  36. WINAPI
  37. SetupDiGetClassDevPropertySheetsA(
  38. IN HDEVINFO DeviceInfoSet,
  39. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  40. IN LPPROPSHEETHEADERA PropertySheetHeader,
  41. IN DWORD PropertySheetHeaderPageListSize,
  42. OUT PDWORD RequiredSize, OPTIONAL
  43. IN DWORD PropertySheetType
  44. )
  45. {
  46. PROPSHEETHEADERW UnicodePropertySheetHeader;
  47. DWORD Err = NO_ERROR;
  48. //
  49. // Make sure we're running interactively.
  50. //
  51. if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
  52. SetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
  53. return FALSE;
  54. }
  55. //
  56. // None of the fields that we care about in this structure contain
  57. // characters. Thus, we'll simply copy over the fields we need into
  58. // our unicode property sheet header, and pass that into the W-API.
  59. //
  60. // The fields that we care about are the following:
  61. //
  62. // dwFlags (in)
  63. // nPages (in/out)
  64. // phpage (in/out)
  65. //
  66. ZeroMemory(&UnicodePropertySheetHeader, sizeof(UnicodePropertySheetHeader));
  67. try {
  68. UnicodePropertySheetHeader.dwFlags = PropertySheetHeader->dwFlags;
  69. UnicodePropertySheetHeader.nPages = PropertySheetHeader->nPages;
  70. UnicodePropertySheetHeader.phpage = PropertySheetHeader->phpage;
  71. if(SetupDiGetClassDevPropertySheetsW(DeviceInfoSet,
  72. DeviceInfoData,
  73. &UnicodePropertySheetHeader,
  74. PropertySheetHeaderPageListSize,
  75. RequiredSize,
  76. PropertySheetType)) {
  77. PropertySheetHeader->nPages = UnicodePropertySheetHeader.nPages;
  78. PropertySheetHeader->phpage = UnicodePropertySheetHeader.phpage;
  79. } else {
  80. Err = GetLastError();
  81. }
  82. } except(EXCEPTION_EXECUTE_HANDLER) {
  83. Err = ERROR_INVALID_PARAMETER;
  84. }
  85. SetLastError(Err);
  86. return(Err == NO_ERROR);
  87. }
  88. #else
  89. //
  90. // Unicode stub
  91. //
  92. BOOL
  93. WINAPI
  94. SetupDiGetClassDevPropertySheetsW(
  95. IN HDEVINFO DeviceInfoSet,
  96. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  97. IN LPPROPSHEETHEADERW PropertySheetHeader,
  98. IN DWORD PropertySheetHeaderPageListSize,
  99. OUT PDWORD RequiredSize, OPTIONAL
  100. IN DWORD PropertySheetType
  101. )
  102. {
  103. UNREFERENCED_PARAMETER(DeviceInfoSet);
  104. UNREFERENCED_PARAMETER(DeviceInfoData);
  105. UNREFERENCED_PARAMETER(PropertySheetHeader);
  106. UNREFERENCED_PARAMETER(PropertySheetHeaderPageListSize);
  107. UNREFERENCED_PARAMETER(RequiredSize);
  108. UNREFERENCED_PARAMETER(PropertySheetType);
  109. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  110. return(FALSE);
  111. }
  112. #endif
  113. BOOL
  114. WINAPI
  115. SetupDiGetClassDevPropertySheets(
  116. IN HDEVINFO DeviceInfoSet,
  117. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  118. IN LPPROPSHEETHEADER PropertySheetHeader,
  119. IN DWORD PropertySheetHeaderPageListSize,
  120. OUT PDWORD RequiredSize, OPTIONAL
  121. IN DWORD PropertySheetType
  122. )
  123. /*++
  124. Routine Description:
  125. This routine adds property sheets to the supplied property sheet
  126. header for the device information set or element.
  127. Arguments:
  128. DeviceInfoSet - Supplies a handle to the device information set for
  129. which property sheets are to be retrieved.
  130. DeviceInfoData - Optionally, supplies the address of a SP_DEVINFO_DATA
  131. structure for which property sheets are to be retrieved. If this
  132. parameter is not specified, then property sheets are retrieved based
  133. on the global class driver list associated with the device information
  134. set itself.
  135. PropertySheetHeader - Supplies the property sheet header to which the
  136. property sheets are to be added.
  137. NOTE: PropertySheetHeader->dwFlags _must not_ have the PSH_PROPSHEETPAGE
  138. flag set, or this API will fail with ERROR_INVALID_FLAGS.
  139. PropertySheetHeaderPageListSize - Specifies the size of the
  140. HPROPSHEETPAGE array pointed to by the PropertySheetHeader->phpage.
  141. Note that this is _not_ the same value as PropertySheetHeader->nPages.
  142. The latter specifies the number of page handles currently in the
  143. list. The number of pages that may be added by this routine equals
  144. PropertySheetHeaderPageListSize - PropertySheetHeader->nPages. If the
  145. property page provider attempts to add more pages than the property
  146. sheet header list can hold, this API will fail, and GetLastError will
  147. return ERROR_INSUFFICIENT_BUFFER. However, any pages that have already
  148. been added will be in the PropertySheetHeader->phpage list, and the
  149. nPages field will contain the correct count. It is the caller's
  150. responsibility to destroy all property page handles in this list via
  151. DestroyPropertySheetPage (unless the caller goes ahead and uses
  152. PropertySheetHeader in a call to PropertySheet).
  153. RequiredSize - Optionally, supplies the address of a variable that receives
  154. the number of property page handles added to the PropertySheetHeader. If
  155. this API fails with ERROR_INSUFFICIENT_BUFFER, this variable will be set
  156. to the total number of property pages that the property page provider(s)
  157. _attempted to add_ (i.e., including those which were not successfully
  158. added because the PropertySheetHeader->phpage array wasn't big enough).
  159. Note: This number will not equal PropertySheetHeader->nPages upon return
  160. if either (a) there were already property pages in the list before this
  161. API was called, or (b) the call failed with ERROR_INSUFFICIENT_BUFFER.
  162. PropertySheetType - Specifies what type of property sheets are to be
  163. retrieved. May be one of the following values:
  164. DIGCDP_FLAG_BASIC - Retrieve basic property sheets (typically, for
  165. CPL applets).
  166. DIGCDP_FLAG_ADVANCED - Retrieve advanced property sheets (typically,
  167. for the Device Manager).
  168. DIGCDP_FLAG_REMOTE_BASIC - Currently not used.
  169. DIGCDP_FLAG_REMOTE_ADVANCED - Retrieve advanced property sheets for a device
  170. on a remote machine (typically, for the Device
  171. Manager).
  172. Return Value:
  173. If the function succeeds, the return value is TRUE.
  174. If the function fails, the return value is FALSE. To get extended error
  175. information, call GetLastError.
  176. --*/
  177. {
  178. PDEVICE_INFO_SET pDeviceInfoSet;
  179. DWORD Err;
  180. PDEVINFO_ELEM DevInfoElem;
  181. PDEVINSTALL_PARAM_BLOCK InstallParamBlock;
  182. LPGUID ClassGuid;
  183. HKEY hk;
  184. SP_PROPSHEETPAGE_REQUEST PropPageRequest;
  185. SP_PROPPAGE_ADDPROC_CONTEXT PropPageAddProcContext;
  186. SP_ADDPROPERTYPAGE_DATA PropertyPageData;
  187. UINT OriginalPageCount;
  188. SPFUSIONINSTANCE spFusionInstance;
  189. //
  190. // Make sure we're running interactively.
  191. //
  192. if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
  193. SetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
  194. return FALSE;
  195. }
  196. //
  197. // Make sure the caller passed us a valid PropertySheetType.
  198. //
  199. if((PropertySheetType != DIGCDP_FLAG_BASIC) &&
  200. (PropertySheetType != DIGCDP_FLAG_ADVANCED) &&
  201. (PropertySheetType != DIGCDP_FLAG_REMOTE_ADVANCED)) {
  202. SetLastError(ERROR_INVALID_PARAMETER);
  203. return FALSE;
  204. }
  205. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  206. SetLastError(ERROR_INVALID_HANDLE);
  207. return FALSE;
  208. }
  209. Err = NO_ERROR;
  210. DevInfoElem = NULL;
  211. hk = INVALID_HANDLE_VALUE;
  212. try {
  213. //
  214. // Make sure the property sheet header doesn't have the PSH_PROPSHEETPAGE flag set.
  215. //
  216. if(PropertySheetHeader->dwFlags & PSH_PROPSHEETPAGE) {
  217. Err = ERROR_INVALID_FLAGS;
  218. goto clean0;
  219. }
  220. //
  221. // Also, ensure that the parts of the property sheet header we'll be dealing with
  222. // look reasonable.
  223. //
  224. OriginalPageCount = PropertySheetHeader->nPages;
  225. if((OriginalPageCount > PropertySheetHeaderPageListSize) ||
  226. (PropertySheetHeaderPageListSize && !(PropertySheetHeader->phpage))) {
  227. Err = ERROR_INVALID_PARAMETER;
  228. goto clean0;
  229. }
  230. if(DeviceInfoData) {
  231. //
  232. // Then we are to retrieve property sheets for a particular device.
  233. //
  234. if(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  235. DeviceInfoData,
  236. NULL))
  237. {
  238. InstallParamBlock = &(DevInfoElem->InstallParamBlock);
  239. ClassGuid = &(DevInfoElem->ClassGuid);
  240. } else {
  241. Err = ERROR_INVALID_PARAMETER;
  242. goto clean0;
  243. }
  244. } else {
  245. //
  246. // We're retrieving (advanced) property pages for the set's class.
  247. //
  248. if(pDeviceInfoSet->HasClassGuid) {
  249. InstallParamBlock = &(pDeviceInfoSet->InstallParamBlock);
  250. ClassGuid = &(pDeviceInfoSet->ClassGuid);
  251. } else {
  252. Err = ERROR_NO_ASSOCIATED_CLASS;
  253. goto clean0;
  254. }
  255. }
  256. //
  257. // Fill in a property sheet request structure for later use.
  258. //
  259. PropPageRequest.cbSize = sizeof(SP_PROPSHEETPAGE_REQUEST);
  260. PropPageRequest.DeviceInfoSet = DeviceInfoSet;
  261. PropPageRequest.DeviceInfoData = DeviceInfoData;
  262. //
  263. // Fill in the context structure for use later on by our AddPropPageProc
  264. // callback.
  265. //
  266. PropPageAddProcContext.PropertySheetHeader = PropertySheetHeader;
  267. PropPageAddProcContext.PageListSize = PropertySheetHeaderPageListSize;
  268. PropPageAddProcContext.NumPages = 0;
  269. //
  270. // If the caller supplied the RequiredSize output parameter, then we don't
  271. // want to abort the callback process, even if we run out of space in the
  272. // hPage list.
  273. //
  274. PropPageAddProcContext.NoCancelOnFailure = RequiredSize ? TRUE : FALSE;
  275. //
  276. // Check if we should be getting Basic or Advanced Property Sheets.
  277. // Essentially, CPL's will want BASIC sheets, and the Device Manager
  278. // will want advanced sheets.
  279. //
  280. switch (PropertySheetType) {
  281. case DIGCDP_FLAG_BASIC:
  282. //
  283. // The BasicProperties32 entrypoint is only supplied via a device's
  284. // driver key. Thus, a device information element must be specified
  285. // when basic property pages are requested.
  286. //
  287. // NOTE: this is different from setupx, which enumerates _all_ lpdi's
  288. // in the list, retrieving basic properties for each. This doesn't
  289. // seem to have any practical application, and if it is really
  290. // required, then the caller can loop through each devinfo element
  291. // themselves, and retrieve basic property pages for each one.
  292. //
  293. if(!DevInfoElem) {
  294. Err = ERROR_INVALID_PARAMETER;
  295. goto clean0;
  296. }
  297. //
  298. // If the basic property page provider has not been loaded, then load
  299. // it and get the function address for the BasicProperties32 function.
  300. //
  301. if(!InstallParamBlock->hinstBasicPropProvider) {
  302. hk = SetupDiOpenDevRegKey(DeviceInfoSet,
  303. DeviceInfoData,
  304. DICS_FLAG_GLOBAL,
  305. 0,
  306. DIREG_DRV,
  307. KEY_READ
  308. );
  309. if(hk != INVALID_HANDLE_VALUE) {
  310. try {
  311. Err = GetModuleEntryPoint(hk,
  312. pszBasicProperties32,
  313. pszBasicPropDefaultProc,
  314. &(InstallParamBlock->hinstBasicPropProvider),
  315. &((FARPROC)InstallParamBlock->EnumBasicPropertiesEntryPoint),
  316. &(InstallParamBlock->EnumBasicPropertiesFusionContext),
  317. NULL,
  318. NULL,
  319. NULL,
  320. NULL,
  321. SetupapiVerifyNoProblem,
  322. NULL,
  323. DRIVERSIGN_NONE,
  324. TRUE,
  325. NULL
  326. );
  327. if(Err == ERROR_DI_DO_DEFAULT) {
  328. //
  329. // The BasicProperties32 value wasn't present--this is not an error.
  330. //
  331. Err = NO_ERROR;
  332. } else if(Err != NO_ERROR) {
  333. Err = ERROR_INVALID_PROPPAGE_PROVIDER;
  334. }
  335. } except(EXCEPTION_EXECUTE_HANDLER) {
  336. Err = ERROR_INVALID_PROPPAGE_PROVIDER;
  337. InstallParamBlock->EnumBasicPropertiesEntryPoint = NULL;
  338. }
  339. RegCloseKey(hk);
  340. hk = INVALID_HANDLE_VALUE;
  341. if(Err != NO_ERROR) {
  342. goto clean0;
  343. }
  344. }
  345. }
  346. //
  347. // If there is a basic property page provider entry point, then call it.
  348. //
  349. if(InstallParamBlock->EnumBasicPropertiesEntryPoint) {
  350. PropPageRequest.PageRequested = SPPSR_ENUM_BASIC_DEVICE_PROPERTIES;
  351. //
  352. // We must first release the HDEVINFO lock, so we don't run into any weird
  353. // deadlock issues
  354. //
  355. UnlockDeviceInfoSet(pDeviceInfoSet);
  356. pDeviceInfoSet = NULL;
  357. spFusionEnterContext(InstallParamBlock->EnumBasicPropertiesFusionContext,
  358. &spFusionInstance);
  359. try {
  360. InstallParamBlock->EnumBasicPropertiesEntryPoint(
  361. &PropPageRequest,
  362. pSetupAddPropPage,
  363. (LPARAM)&PropPageAddProcContext
  364. );
  365. } finally {
  366. spFusionLeaveContext(&spFusionInstance);
  367. }
  368. }
  369. //
  370. // Now use the new DIF_ADDPROPERTYPAGE_BASIC call to see if any
  371. // class-/co-installers want to add basic property pages as well.
  372. //
  373. memset(&PropertyPageData, 0, sizeof(SP_ADDPROPERTYPAGE_DATA));
  374. PropertyPageData.ClassInstallHeader.InstallFunction = DIF_ADDPROPERTYPAGE_BASIC;
  375. PropertyPageData.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  376. PropertyPageData.hwndWizardDlg = PropertySheetHeader->hwndParent;
  377. Err = DoInstallActionWithParams(DIF_ADDPROPERTYPAGE_BASIC,
  378. DeviceInfoSet,
  379. DeviceInfoData,
  380. &PropertyPageData.ClassInstallHeader,
  381. sizeof(SP_ADDPROPERTYPAGE_DATA),
  382. INSTALLACTION_CALL_CI);
  383. if (ERROR_DI_DO_DEFAULT == Err) {
  384. //
  385. // The class-/co-installers do not have any pages to add--this is not an error.
  386. //
  387. Err = NO_ERROR;
  388. }
  389. if ((NO_ERROR == Err) &&
  390. (PropertyPageData.NumDynamicPages > 0))
  391. {
  392. DWORD NumPages = 0;
  393. while (NumPages < PropertyPageData.NumDynamicPages) {
  394. pSetupAddPropPage(PropertyPageData.DynamicPages[NumPages++],
  395. (LPARAM)&PropPageAddProcContext
  396. );
  397. }
  398. }
  399. break;
  400. case DIGCDP_FLAG_ADVANCED:
  401. //
  402. // We're retrieving advanced property pages. We want to look for EnumPropPages32
  403. // entries in both the class key and (if we're talking about a specific device) in
  404. // the device's driver key.
  405. //
  406. if(!InstallParamBlock->hinstClassPropProvider) {
  407. hk = SetupDiOpenClassRegKey(ClassGuid, KEY_READ);
  408. if(hk != INVALID_HANDLE_VALUE) {
  409. try {
  410. Err = GetModuleEntryPoint(hk,
  411. pszEnumPropPages32,
  412. pszEnumPropDefaultProc,
  413. &(InstallParamBlock->hinstClassPropProvider),
  414. &((FARPROC)InstallParamBlock->ClassEnumPropPagesEntryPoint),
  415. &(InstallParamBlock->ClassEnumPropPagesFusionContext),
  416. NULL,
  417. NULL,
  418. NULL,
  419. NULL,
  420. SetupapiVerifyNoProblem,
  421. NULL,
  422. DRIVERSIGN_NONE,
  423. TRUE,
  424. NULL
  425. );
  426. if(Err == ERROR_DI_DO_DEFAULT) {
  427. //
  428. // The EnumPropPages32 value wasn't present--this is not an error.
  429. //
  430. Err = NO_ERROR;
  431. } else if(Err != NO_ERROR) {
  432. Err = ERROR_INVALID_PROPPAGE_PROVIDER;
  433. }
  434. } except(EXCEPTION_EXECUTE_HANDLER) {
  435. Err = ERROR_INVALID_PROPPAGE_PROVIDER;
  436. InstallParamBlock->ClassEnumPropPagesEntryPoint = NULL;
  437. }
  438. RegCloseKey(hk);
  439. hk = INVALID_HANDLE_VALUE;
  440. if(Err != NO_ERROR) {
  441. goto clean0;
  442. }
  443. }
  444. }
  445. if(DevInfoElem && !InstallParamBlock->hinstDevicePropProvider) {
  446. hk = SetupDiOpenDevRegKey(DeviceInfoSet,
  447. DeviceInfoData,
  448. DICS_FLAG_GLOBAL,
  449. 0,
  450. DIREG_DRV,
  451. KEY_READ
  452. );
  453. if(hk != INVALID_HANDLE_VALUE) {
  454. try {
  455. Err = GetModuleEntryPoint(hk,
  456. pszEnumPropPages32,
  457. pszEnumPropDefaultProc,
  458. &(InstallParamBlock->hinstDevicePropProvider),
  459. &((FARPROC)InstallParamBlock->DeviceEnumPropPagesEntryPoint),
  460. &(InstallParamBlock->DeviceEnumPropPagesFusionContext),
  461. NULL,
  462. NULL,
  463. NULL,
  464. NULL,
  465. SetupapiVerifyNoProblem,
  466. NULL,
  467. DRIVERSIGN_NONE,
  468. TRUE,
  469. NULL
  470. );
  471. if(Err == ERROR_DI_DO_DEFAULT) {
  472. //
  473. // The EnumPropPages32 value wasn't present--this is not an error.
  474. //
  475. Err = NO_ERROR;
  476. } else if(Err != NO_ERROR) {
  477. Err = ERROR_INVALID_PROPPAGE_PROVIDER;
  478. }
  479. } except(EXCEPTION_EXECUTE_HANDLER) {
  480. Err = ERROR_INVALID_PROPPAGE_PROVIDER;
  481. InstallParamBlock->DeviceEnumPropPagesEntryPoint = NULL;
  482. }
  483. RegCloseKey(hk);
  484. hk = INVALID_HANDLE_VALUE;
  485. if(Err != NO_ERROR) {
  486. goto clean0;
  487. }
  488. }
  489. }
  490. //
  491. // Clear the DI_GENERALPAGE_ADDED, DI_DRIVERPAGE_ADDED, and DI_RESOURCEPAGE_ADDED flags.
  492. //
  493. InstallParamBlock->Flags &= ~(DI_GENERALPAGE_ADDED | DI_RESOURCEPAGE_ADDED | DI_DRIVERPAGE_ADDED);
  494. PropPageRequest.PageRequested = SPPSR_ENUM_ADV_DEVICE_PROPERTIES;
  495. //
  496. // We must first release the HDEVINFO lock, so we don't run into any weird
  497. // deadlock issues
  498. //
  499. UnlockDeviceInfoSet(pDeviceInfoSet);
  500. pDeviceInfoSet = NULL;
  501. //
  502. // If there is an advanced property page provider for this class, then call it.
  503. //
  504. if(InstallParamBlock->ClassEnumPropPagesEntryPoint) {
  505. spFusionEnterContext(InstallParamBlock->ClassEnumPropPagesFusionContext,
  506. &spFusionInstance);
  507. try {
  508. InstallParamBlock->ClassEnumPropPagesEntryPoint(
  509. &PropPageRequest,
  510. pSetupAddPropPage,
  511. (LPARAM)&PropPageAddProcContext
  512. );
  513. } finally {
  514. spFusionLeaveContext(&spFusionInstance);
  515. }
  516. }
  517. //
  518. // If there is an advanced property page provider for this particular device, then call it.
  519. //
  520. if(InstallParamBlock->DeviceEnumPropPagesEntryPoint) {
  521. spFusionEnterContext(InstallParamBlock->DeviceEnumPropPagesFusionContext,
  522. &spFusionInstance);
  523. try {
  524. InstallParamBlock->DeviceEnumPropPagesEntryPoint(
  525. &PropPageRequest,
  526. pSetupAddPropPage,
  527. (LPARAM)&PropPageAddProcContext
  528. );
  529. } finally {
  530. spFusionLeaveContext(&spFusionInstance);
  531. }
  532. }
  533. //
  534. // Now use the new DIF_ADDPROPERTYPAGE_ADVANCED call to see if any
  535. // class-/co-installers want to add advanced property pages as well.
  536. //
  537. memset(&PropertyPageData, 0, sizeof(SP_ADDPROPERTYPAGE_DATA));
  538. PropertyPageData.ClassInstallHeader.InstallFunction = DIF_ADDPROPERTYPAGE_ADVANCED;
  539. PropertyPageData.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  540. PropertyPageData.hwndWizardDlg = PropertySheetHeader->hwndParent;
  541. Err = DoInstallActionWithParams(DIF_ADDPROPERTYPAGE_ADVANCED,
  542. DeviceInfoSet,
  543. DeviceInfoData,
  544. &PropertyPageData.ClassInstallHeader,
  545. sizeof(SP_ADDPROPERTYPAGE_DATA),
  546. INSTALLACTION_CALL_CI);
  547. if (ERROR_DI_DO_DEFAULT == Err) {
  548. //
  549. // The class-/co-installers do not have any pages to add--this is not an error.
  550. //
  551. Err = NO_ERROR;
  552. }
  553. if ((NO_ERROR == Err) ||
  554. (PropertyPageData.NumDynamicPages > 0))
  555. {
  556. DWORD NumPages = 0;
  557. while (NumPages < PropertyPageData.NumDynamicPages) {
  558. pSetupAddPropPage(PropertyPageData.DynamicPages[NumPages++],
  559. (LPARAM)&PropPageAddProcContext
  560. );
  561. }
  562. }
  563. break;
  564. case DIGCDP_FLAG_REMOTE_ADVANCED:
  565. //
  566. // Now use the new DIF_ADDREMOTEPROPERTYPAGE_ADVANCED call to see if any
  567. // class-/co-installers want to add advanced property pages as well.
  568. //
  569. memset(&PropertyPageData, 0, sizeof(SP_ADDPROPERTYPAGE_DATA));
  570. PropertyPageData.ClassInstallHeader.InstallFunction = DIF_ADDREMOTEPROPERTYPAGE_ADVANCED;
  571. PropertyPageData.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  572. PropertyPageData.hwndWizardDlg = PropertySheetHeader->hwndParent;
  573. Err = DoInstallActionWithParams(DIF_ADDREMOTEPROPERTYPAGE_ADVANCED,
  574. DeviceInfoSet,
  575. DeviceInfoData,
  576. &PropertyPageData.ClassInstallHeader,
  577. sizeof(SP_ADDPROPERTYPAGE_DATA),
  578. INSTALLACTION_CALL_CI);
  579. if (ERROR_DI_DO_DEFAULT == Err) {
  580. //
  581. // The class-/co-installers do not have any pages to add--this is not an error.
  582. //
  583. Err = NO_ERROR;
  584. }
  585. if ((NO_ERROR == Err) ||
  586. (PropertyPageData.NumDynamicPages > 0))
  587. {
  588. DWORD NumPages = 0;
  589. while (NumPages < PropertyPageData.NumDynamicPages) {
  590. pSetupAddPropPage(PropertyPageData.DynamicPages[NumPages++],
  591. (LPARAM)&PropPageAddProcContext
  592. );
  593. }
  594. }
  595. break;
  596. }
  597. if(RequiredSize) {
  598. *RequiredSize = PropPageAddProcContext.NumPages;
  599. }
  600. if((OriginalPageCount + PropPageAddProcContext.NumPages) > PropertySheetHeaderPageListSize) {
  601. Err = ERROR_INSUFFICIENT_BUFFER;
  602. }
  603. clean0: ; // nothing to do.
  604. } except(EXCEPTION_EXECUTE_HANDLER) {
  605. Err = ERROR_INVALID_PARAMETER;
  606. if(hk != INVALID_HANDLE_VALUE) {
  607. RegCloseKey(hk);
  608. }
  609. //
  610. // Reference the following variable so the compiler will respect our statement ordering
  611. // w.r.t. assignment.
  612. //
  613. pDeviceInfoSet = pDeviceInfoSet;
  614. }
  615. if(pDeviceInfoSet) {
  616. UnlockDeviceInfoSet(pDeviceInfoSet);
  617. }
  618. SetLastError(Err);
  619. return(Err == NO_ERROR);
  620. }
  621. BOOL
  622. CALLBACK
  623. pSetupAddPropPage(
  624. IN HPROPSHEETPAGE hPage,
  625. IN LPARAM lParam
  626. )
  627. /*++
  628. Routine Description:
  629. This is the callback routine that is passed to property page providers.
  630. This routine is called for each property page that the provider wishes to
  631. add.
  632. Arguments:
  633. hPage - Supplies a handle to the property page being added.
  634. lParam - Supplies a pointer to a context structure used when adding the new
  635. property page handle.
  636. Return Value:
  637. If the function succeeds, the return value is TRUE.
  638. If the function fails, the return value is FALSE.
  639. --*/
  640. {
  641. PSP_PROPPAGE_ADDPROC_CONTEXT Context = (PSP_PROPPAGE_ADDPROC_CONTEXT)lParam;
  642. //
  643. // Regardless of whether we successfully add this new hPage, we want to keep
  644. // a count of how many pages we were asked to add.
  645. //
  646. Context->NumPages++;
  647. if(Context->PropertySheetHeader->nPages < Context->PageListSize) {
  648. Context->PropertySheetHeader->phpage[Context->PropertySheetHeader->nPages++] = hPage;
  649. return TRUE;
  650. }
  651. return Context->NoCancelOnFailure;
  652. }
  653. BOOL
  654. CALLBACK
  655. ExtensionPropSheetPageProc(
  656. IN LPVOID lpv,
  657. IN LPFNADDPROPSHEETPAGE lpfnAddPropSheetPageProc,
  658. IN LPARAM lParam
  659. )
  660. {
  661. PSP_PROPSHEETPAGE_REQUEST PropPageRequest = (PSP_PROPSHEETPAGE_REQUEST)lpv;
  662. HPROPSHEETPAGE hPropSheetPage = NULL;
  663. BOOL b = FALSE;
  664. //
  665. // Make sure we're running interactively.
  666. //
  667. if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
  668. SetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
  669. return FALSE;
  670. }
  671. try {
  672. if(PropPageRequest->cbSize != sizeof(SP_PROPSHEETPAGE_REQUEST)) {
  673. goto clean0;
  674. }
  675. switch(PropPageRequest->PageRequested) {
  676. case SPPSR_SELECT_DEVICE_RESOURCES :
  677. if(!(hPropSheetPage = GetResourceSelectionPage(PropPageRequest->DeviceInfoSet,
  678. PropPageRequest->DeviceInfoData))) {
  679. goto clean0;
  680. }
  681. break;
  682. default :
  683. //
  684. // Don't know what to do with this request.
  685. //
  686. goto clean0;
  687. }
  688. if(lpfnAddPropSheetPageProc(hPropSheetPage, lParam)) {
  689. //
  690. // Page successfully handed off to requestor. Reset our handle so that we don't
  691. // try to free it.
  692. //
  693. hPropSheetPage = NULL;
  694. b = TRUE;
  695. }
  696. clean0: ; // nothing to do
  697. } except(EXCEPTION_EXECUTE_HANDLER) {
  698. //
  699. // Access the hPropSheetPage variable, so that the compiler will respect our statement
  700. // order w.r.t. assignment.
  701. //
  702. hPropSheetPage = hPropSheetPage;
  703. }
  704. if(hPropSheetPage) {
  705. //
  706. // Property page was successfully created, but never handed off to requestor. Free
  707. // it now.
  708. //
  709. DestroyPropertySheetPage(hPropSheetPage);
  710. }
  711. return b;
  712. }