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.

1031 lines
39 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. HPROPSHEETPAGE *PageList; // input(buffer)/output(contents therein)
  28. DWORD PageListSize; // input
  29. DWORD *pNumPages; // input/output
  30. } SP_PROPPAGE_ADDPROC_CONTEXT, *PSP_PROPPAGE_ADDPROC_CONTEXT;
  31. //
  32. // ANSI version
  33. //
  34. BOOL
  35. WINAPI
  36. SetupDiGetClassDevPropertySheetsA(
  37. IN HDEVINFO DeviceInfoSet,
  38. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  39. IN LPPROPSHEETHEADERA PropertySheetHeader,
  40. IN DWORD PropertySheetHeaderPageListSize,
  41. OUT PDWORD RequiredSize, OPTIONAL
  42. IN DWORD PropertySheetType
  43. )
  44. {
  45. PROPSHEETHEADERW UnicodePropertySheetHeader;
  46. DWORD Err;
  47. try {
  48. //
  49. // Make sure we're running interactively.
  50. //
  51. if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
  52. Err = ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION;
  53. leave;
  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:out (buffer pointer stays the same but contents are added)
  65. //
  66. ZeroMemory(&UnicodePropertySheetHeader, sizeof(UnicodePropertySheetHeader));
  67. UnicodePropertySheetHeader.dwFlags = PropertySheetHeader->dwFlags;
  68. UnicodePropertySheetHeader.nPages = PropertySheetHeader->nPages;
  69. UnicodePropertySheetHeader.phpage = PropertySheetHeader->phpage;
  70. Err = GLE_FN_CALL(FALSE,
  71. SetupDiGetClassDevPropertySheetsW(
  72. DeviceInfoSet,
  73. DeviceInfoData,
  74. &UnicodePropertySheetHeader,
  75. PropertySheetHeaderPageListSize,
  76. RequiredSize,
  77. PropertySheetType)
  78. );
  79. if(Err != NO_ERROR) {
  80. leave;
  81. }
  82. PropertySheetHeader->nPages = UnicodePropertySheetHeader.nPages;
  83. MYASSERT(PropertySheetHeader->phpage == UnicodePropertySheetHeader.phpage);
  84. } except(pSetupExceptionFilter(GetExceptionCode())) {
  85. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  86. }
  87. SetLastError(Err);
  88. return (Err == NO_ERROR);
  89. }
  90. BOOL
  91. WINAPI
  92. SetupDiGetClassDevPropertySheets(
  93. IN HDEVINFO DeviceInfoSet,
  94. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  95. IN LPPROPSHEETHEADER PropertySheetHeader,
  96. IN DWORD PropertySheetHeaderPageListSize,
  97. OUT PDWORD RequiredSize, OPTIONAL
  98. IN DWORD PropertySheetType
  99. )
  100. /*++
  101. Routine Description:
  102. This routine adds property sheets to the supplied property sheet
  103. header for the device information set or element.
  104. Arguments:
  105. DeviceInfoSet - Supplies a handle to the device information set for
  106. which property sheets are to be retrieved.
  107. DeviceInfoData - Optionally, supplies the address of a SP_DEVINFO_DATA
  108. structure for which property sheets are to be retrieved. If this
  109. parameter is not specified, then property sheets are retrieved based
  110. on the global class driver list associated with the device information
  111. set itself.
  112. PropertySheetHeader - Supplies the property sheet header to which the
  113. property sheets are to be added.
  114. NOTE: PropertySheetHeader->dwFlags _must not_ have the
  115. PSH_PROPSHEETPAGE flag set, or this API will fail with
  116. ERROR_INVALID_FLAGS.
  117. PropertySheetHeaderPageListSize - Specifies the size of the
  118. HPROPSHEETPAGE array pointed to by the PropertySheetHeader->phpage.
  119. Note that this is _not_ the same value as PropertySheetHeader->nPages.
  120. The latter specifies the number of page handles currently in the
  121. list. The number of pages that may be added by this routine equals
  122. PropertySheetHeaderPageListSize - PropertySheetHeader->nPages. If the
  123. property page provider attempts to add more pages than the property
  124. sheet header list can hold, this API will fail, and GetLastError will
  125. return ERROR_INSUFFICIENT_BUFFER. However, any pages that have already
  126. been added will be in the PropertySheetHeader->phpage list, and the
  127. nPages field will contain the correct count. It is the caller's
  128. responsibility to destroy all property page handles in this list via
  129. DestroyPropertySheetPage (unless the caller goes ahead and uses
  130. PropertySheetHeader in a call to PropertySheet).
  131. RequiredSize - Optionally, supplies the address of a variable that receives
  132. the number of property page handles added to the PropertySheetHeader.
  133. If this API fails with ERROR_INSUFFICIENT_BUFFER, this variable will be
  134. set to the total number of property pages that the property page
  135. provider(s) _attempted to add_ (i.e., including those which were not
  136. successfully added because the PropertySheetHeader->phpage array wasn't
  137. big enough).
  138. Note: This number will not equal PropertySheetHeader->nPages upon
  139. return if either (a) there were already property pages in the list
  140. before this API was called, or (b) the call failed with
  141. ERROR_INSUFFICIENT_BUFFER.
  142. PropertySheetType - Specifies what type of property sheets are to be
  143. retrieved. May be one of the following values:
  144. DIGCDP_FLAG_BASIC - Retrieve basic property sheets (typically, for CPL
  145. applets).
  146. DIGCDP_FLAG_ADVANCED - Retrieve advanced property sheets (typically,
  147. for the Device Manager).
  148. DIGCDP_FLAG_REMOTE_BASIC - Currently not used.
  149. DIGCDP_FLAG_REMOTE_ADVANCED - Retrieve advanced property sheets for a
  150. device on a remote machine (typically,
  151. for the Device Manager).
  152. Return Value:
  153. If the function succeeds, the return value is TRUE.
  154. If the function fails, the return value is FALSE. To get extended error
  155. information, call GetLastError.
  156. --*/
  157. {
  158. PDEVICE_INFO_SET pDeviceInfoSet = NULL;
  159. DWORD Err = NO_ERROR;
  160. PDEVINFO_ELEM DevInfoElem = NULL;
  161. PDEVINSTALL_PARAM_BLOCK InstallParamBlock;
  162. LPGUID ClassGuid;
  163. HKEY hk = INVALID_HANDLE_VALUE;
  164. SP_PROPSHEETPAGE_REQUEST PropPageRequest;
  165. SP_PROPPAGE_ADDPROC_CONTEXT PropPageAddProcContext;
  166. PSP_ADDPROPERTYPAGE_DATA pPropertyPageData = NULL;
  167. SPFUSIONINSTANCE spFusionInstance;
  168. BOOL bUnlockDevInfoElem = FALSE;
  169. BOOL bUnlockDevInfoSet = FALSE;
  170. HPROPSHEETPAGE *LocalPageList = NULL;
  171. DWORD LocalPageListCount = 0;
  172. DWORD PageIndex, NumPages;
  173. PROPSHEET_PROVIDER_PROC ClassPagesEntryPoint;
  174. HANDLE ClassPagesFusionContext;
  175. PROPSHEET_PROVIDER_PROC DevicePagesEntryPoint;
  176. HANDLE DevicePagesFusionContext;
  177. DWORD OriginalPageCount;
  178. try {
  179. //
  180. // Make sure we're running interactively.
  181. //
  182. if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
  183. Err = ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION;
  184. leave;
  185. }
  186. //
  187. // Make sure the caller passed us a valid PropertySheetType.
  188. //
  189. if((PropertySheetType != DIGCDP_FLAG_BASIC) &&
  190. (PropertySheetType != DIGCDP_FLAG_ADVANCED) &&
  191. (PropertySheetType != DIGCDP_FLAG_REMOTE_ADVANCED)) {
  192. Err = ERROR_INVALID_PARAMETER;
  193. leave;
  194. }
  195. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  196. Err = ERROR_INVALID_HANDLE;
  197. leave;
  198. }
  199. //
  200. // Make sure the property sheet header doesn't have the
  201. // PSH_PROPSHEETPAGE flag set.
  202. //
  203. if(PropertySheetHeader->dwFlags & PSH_PROPSHEETPAGE) {
  204. Err = ERROR_INVALID_FLAGS;
  205. leave;
  206. }
  207. //
  208. // Also, ensure that the parts of the property sheet header we'll be
  209. // dealing with look reasonable.
  210. //
  211. OriginalPageCount = PropertySheetHeader->nPages;
  212. if((OriginalPageCount > PropertySheetHeaderPageListSize) ||
  213. (PropertySheetHeaderPageListSize && !(PropertySheetHeader->phpage))) {
  214. Err = ERROR_INVALID_PARAMETER;
  215. leave;
  216. }
  217. if(DeviceInfoData) {
  218. //
  219. // Then we are to retrieve property sheets for a particular device.
  220. //
  221. if(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  222. DeviceInfoData,
  223. NULL))
  224. {
  225. InstallParamBlock = &(DevInfoElem->InstallParamBlock);
  226. ClassGuid = &(DevInfoElem->ClassGuid);
  227. } else {
  228. Err = ERROR_INVALID_PARAMETER;
  229. leave;
  230. }
  231. } else {
  232. //
  233. // We're retrieving (advanced) property pages for the set's class.
  234. //
  235. if(pDeviceInfoSet->HasClassGuid) {
  236. InstallParamBlock = &(pDeviceInfoSet->InstallParamBlock);
  237. ClassGuid = &(pDeviceInfoSet->ClassGuid);
  238. } else {
  239. Err = ERROR_NO_ASSOCIATED_CLASS;
  240. leave;
  241. }
  242. }
  243. //
  244. // Fill in a property sheet request structure for later use.
  245. //
  246. PropPageRequest.cbSize = sizeof(SP_PROPSHEETPAGE_REQUEST);
  247. PropPageRequest.DeviceInfoSet = DeviceInfoSet;
  248. PropPageRequest.DeviceInfoData = DeviceInfoData;
  249. //
  250. // Fill in the context structure for later use by our AddPropPageProc
  251. // callback. We want to allocate a local buffer of the same size as
  252. // the remaining space in the caller-supplied PropertySheetHeader.phpage
  253. // buffer.
  254. //
  255. PropPageAddProcContext.PageListSize = PropertySheetHeaderPageListSize -
  256. PropertySheetHeader->nPages;
  257. if(PropPageAddProcContext.PageListSize) {
  258. LocalPageList =
  259. MyMalloc(sizeof(HPROPSHEETPAGE) * PropPageAddProcContext.PageListSize);
  260. if(!LocalPageList) {
  261. Err = ERROR_NOT_ENOUGH_MEMORY;
  262. leave;
  263. }
  264. }
  265. PropPageAddProcContext.PageList = LocalPageList;
  266. PropPageAddProcContext.pNumPages = &LocalPageListCount;
  267. //
  268. // If the caller supplied the RequiredSize output parameter, then we don't
  269. // want to abort the callback process, even if we run out of space in the
  270. // hPage list.
  271. //
  272. PropPageAddProcContext.NoCancelOnFailure = RequiredSize ? TRUE : FALSE;
  273. //
  274. // Allocate and initialize an AddPropertyPage class install params
  275. // structure for later use in retrieval of property pages from co-/
  276. // class installers.
  277. //
  278. pPropertyPageData = MyMalloc(sizeof(SP_ADDPROPERTYPAGE_DATA));
  279. if(!pPropertyPageData) {
  280. Err = ERROR_NOT_ENOUGH_MEMORY;
  281. leave;
  282. }
  283. ZeroMemory(pPropertyPageData, sizeof(SP_ADDPROPERTYPAGE_DATA));
  284. pPropertyPageData->ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  285. pPropertyPageData->hwndWizardDlg = PropertySheetHeader->hwndParent;
  286. //
  287. // Check if we should be getting Basic or Advanced Property Sheets.
  288. // Essentially, CPL's will want BASIC sheets, and the Device Manager
  289. // will want advanced sheets.
  290. //
  291. switch (PropertySheetType) {
  292. case DIGCDP_FLAG_BASIC:
  293. //
  294. // The BasicProperties32 entrypoint is only supplied via a device's
  295. // driver key. Thus, a device information element must be specified
  296. // when basic property pages are requested.
  297. //
  298. // NOTE: this is different from setupx, which enumerates _all_ lpdi's
  299. // in the list, retrieving basic properties for each. This doesn't
  300. // seem to have any practical application, and if it is really
  301. // required, then the caller can loop through each devinfo element
  302. // themselves, and retrieve basic property pages for each one.
  303. //
  304. if(!DevInfoElem) {
  305. Err = ERROR_INVALID_PARAMETER;
  306. leave;
  307. }
  308. //
  309. // If the basic property page provider has not been loaded, then load
  310. // it and get the function address for the BasicProperties32 function.
  311. //
  312. if(!InstallParamBlock->hinstBasicPropProvider) {
  313. hk = SetupDiOpenDevRegKey(DeviceInfoSet,
  314. DeviceInfoData,
  315. DICS_FLAG_GLOBAL,
  316. 0,
  317. DIREG_DRV,
  318. KEY_READ
  319. );
  320. if(hk != INVALID_HANDLE_VALUE) {
  321. try {
  322. Err = GetModuleEntryPoint(hk,
  323. pszBasicProperties32,
  324. pszBasicPropDefaultProc,
  325. &(InstallParamBlock->hinstBasicPropProvider),
  326. &((FARPROC)InstallParamBlock->EnumBasicPropertiesEntryPoint),
  327. &(InstallParamBlock->EnumBasicPropertiesFusionContext),
  328. NULL,
  329. NULL,
  330. NULL,
  331. NULL,
  332. SetupapiVerifyNoProblem,
  333. NULL,
  334. DRIVERSIGN_NONE,
  335. TRUE,
  336. NULL
  337. );
  338. if(Err == ERROR_DI_DO_DEFAULT) {
  339. //
  340. // The BasicProperties32 value wasn't present--this is not an error.
  341. //
  342. Err = NO_ERROR;
  343. } else if(Err != NO_ERROR) {
  344. Err = ERROR_INVALID_PROPPAGE_PROVIDER;
  345. }
  346. } except(pSetupExceptionFilter(GetExceptionCode())) {
  347. pSetupExceptionHandler(GetExceptionCode(),
  348. ERROR_INVALID_PROPPAGE_PROVIDER,
  349. &Err
  350. );
  351. InstallParamBlock->EnumBasicPropertiesEntryPoint = NULL;
  352. InstallParamBlock->EnumBasicPropertiesFusionContext = NULL;
  353. }
  354. RegCloseKey(hk);
  355. hk = INVALID_HANDLE_VALUE;
  356. if(Err != NO_ERROR) {
  357. leave;
  358. }
  359. }
  360. }
  361. //
  362. // If there is a basic property page provider entry point, then
  363. // call it.
  364. //
  365. if(InstallParamBlock->EnumBasicPropertiesEntryPoint) {
  366. PropPageRequest.PageRequested = SPPSR_ENUM_BASIC_DEVICE_PROPERTIES;
  367. //
  368. // Capture the fusion context and function entry point into
  369. // local variables, because we're going to be unlocking the
  370. // devinfo set. Thus, it's possible the InstallParamBlock
  371. // could get modified (e.g., if the device's ClasssGUID were
  372. // changed during the call). We at least know, however, that
  373. // the entry point and fusion context won't be destroyed until
  374. // the InstallParamBlock is destroyed, which we're preventing
  375. // by setting the DIE_IS_LOCKED flag below.
  376. //
  377. DevicePagesFusionContext =
  378. InstallParamBlock->EnumBasicPropertiesFusionContext;
  379. DevicePagesEntryPoint =
  380. InstallParamBlock->EnumBasicPropertiesEntryPoint;
  381. //
  382. // Release the HDEVINFO lock, so we don't run into any weird
  383. // deadlock issues. We want to lock the devinfo element so
  384. // the helper module can't go deleting it out from under us!
  385. //
  386. if(!(DevInfoElem->DiElemFlags & DIE_IS_LOCKED)) {
  387. DevInfoElem->DiElemFlags |= DIE_IS_LOCKED;
  388. bUnlockDevInfoElem = TRUE;
  389. }
  390. UnlockDeviceInfoSet(pDeviceInfoSet);
  391. pDeviceInfoSet = NULL;
  392. spFusionEnterContext(DevicePagesFusionContext, &spFusionInstance);
  393. try {
  394. DevicePagesEntryPoint(&PropPageRequest,
  395. pSetupAddPropPage,
  396. (LPARAM)&PropPageAddProcContext
  397. );
  398. } finally {
  399. spFusionLeaveContext(&spFusionInstance);
  400. }
  401. }
  402. //
  403. // Finish initializing our class install params structure to
  404. // indicate we are asking for basic property pages from the class-/
  405. // co-installers.
  406. //
  407. pPropertyPageData->ClassInstallHeader.InstallFunction = DIF_ADDPROPERTYPAGE_BASIC;
  408. break;
  409. case DIGCDP_FLAG_ADVANCED:
  410. //
  411. // We're retrieving advanced property pages. We want to look for EnumPropPages32
  412. // entries in both the class key and (if we're talking about a specific device) in
  413. // the device's driver key.
  414. //
  415. if(!InstallParamBlock->hinstClassPropProvider) {
  416. hk = SetupDiOpenClassRegKey(ClassGuid, KEY_READ);
  417. if(hk != INVALID_HANDLE_VALUE) {
  418. try {
  419. Err = GetModuleEntryPoint(hk,
  420. pszEnumPropPages32,
  421. pszEnumPropDefaultProc,
  422. &(InstallParamBlock->hinstClassPropProvider),
  423. &((FARPROC)InstallParamBlock->ClassEnumPropPagesEntryPoint),
  424. &(InstallParamBlock->ClassEnumPropPagesFusionContext),
  425. NULL,
  426. NULL,
  427. NULL,
  428. NULL,
  429. SetupapiVerifyNoProblem,
  430. NULL,
  431. DRIVERSIGN_NONE,
  432. TRUE,
  433. NULL
  434. );
  435. if(Err == ERROR_DI_DO_DEFAULT) {
  436. //
  437. // The EnumPropPages32 value wasn't present--this is not an error.
  438. //
  439. Err = NO_ERROR;
  440. } else if(Err != NO_ERROR) {
  441. Err = ERROR_INVALID_PROPPAGE_PROVIDER;
  442. }
  443. } except(pSetupExceptionFilter(GetExceptionCode())) {
  444. pSetupExceptionHandler(GetExceptionCode(),
  445. ERROR_INVALID_PROPPAGE_PROVIDER,
  446. &Err
  447. );
  448. InstallParamBlock->ClassEnumPropPagesEntryPoint = NULL;
  449. InstallParamBlock->ClassEnumPropPagesFusionContext = NULL;
  450. }
  451. RegCloseKey(hk);
  452. hk = INVALID_HANDLE_VALUE;
  453. if(Err != NO_ERROR) {
  454. leave;
  455. }
  456. }
  457. }
  458. if(DevInfoElem && !InstallParamBlock->hinstDevicePropProvider) {
  459. hk = SetupDiOpenDevRegKey(DeviceInfoSet,
  460. DeviceInfoData,
  461. DICS_FLAG_GLOBAL,
  462. 0,
  463. DIREG_DRV,
  464. KEY_READ
  465. );
  466. if(hk != INVALID_HANDLE_VALUE) {
  467. try {
  468. Err = GetModuleEntryPoint(hk,
  469. pszEnumPropPages32,
  470. pszEnumPropDefaultProc,
  471. &(InstallParamBlock->hinstDevicePropProvider),
  472. &((FARPROC)InstallParamBlock->DeviceEnumPropPagesEntryPoint),
  473. &(InstallParamBlock->DeviceEnumPropPagesFusionContext),
  474. NULL,
  475. NULL,
  476. NULL,
  477. NULL,
  478. SetupapiVerifyNoProblem,
  479. NULL,
  480. DRIVERSIGN_NONE,
  481. TRUE,
  482. NULL
  483. );
  484. if(Err == ERROR_DI_DO_DEFAULT) {
  485. //
  486. // The EnumPropPages32 value wasn't present--this is not an error.
  487. //
  488. Err = NO_ERROR;
  489. } else if(Err != NO_ERROR) {
  490. Err = ERROR_INVALID_PROPPAGE_PROVIDER;
  491. }
  492. } except(pSetupExceptionFilter(GetExceptionCode())) {
  493. pSetupExceptionHandler(GetExceptionCode(),
  494. ERROR_INVALID_PROPPAGE_PROVIDER,
  495. &Err
  496. );
  497. InstallParamBlock->DeviceEnumPropPagesEntryPoint = NULL;
  498. InstallParamBlock->DeviceEnumPropPagesFusionContext = NULL;
  499. }
  500. RegCloseKey(hk);
  501. hk = INVALID_HANDLE_VALUE;
  502. if(Err != NO_ERROR) {
  503. leave;
  504. }
  505. }
  506. }
  507. //
  508. // Clear the DI_GENERALPAGE_ADDED, DI_DRIVERPAGE_ADDED, and
  509. // DI_RESOURCEPAGE_ADDED flags.
  510. //
  511. InstallParamBlock->Flags &= ~(DI_GENERALPAGE_ADDED | DI_RESOURCEPAGE_ADDED | DI_DRIVERPAGE_ADDED);
  512. PropPageRequest.PageRequested = SPPSR_ENUM_ADV_DEVICE_PROPERTIES;
  513. //
  514. // Capture the fusion contexts and function entry points into local
  515. // variables, because we're going to be unlocking the devinfo set.
  516. // Thus, it's possible the InstallParamBlock could get modified.
  517. //
  518. ClassPagesFusionContext =
  519. InstallParamBlock->ClassEnumPropPagesFusionContext;
  520. ClassPagesEntryPoint =
  521. InstallParamBlock->ClassEnumPropPagesEntryPoint;
  522. DevicePagesFusionContext =
  523. InstallParamBlock->DeviceEnumPropPagesFusionContext;
  524. DevicePagesEntryPoint =
  525. InstallParamBlock->DeviceEnumPropPagesEntryPoint;
  526. //
  527. // Release the HDEVINFO lock, so we don't run into any weird
  528. // deadlock issues. We want to lock the devinfo set/element so
  529. // we don't have to worry about the set being deleted out from
  530. // under us.
  531. //
  532. if(DevInfoElem) {
  533. //
  534. // If we have a devinfo element, then we'd prefer to lock at
  535. // that level.
  536. //
  537. if(!(DevInfoElem->DiElemFlags & DIE_IS_LOCKED)) {
  538. DevInfoElem->DiElemFlags |= DIE_IS_LOCKED;
  539. bUnlockDevInfoElem = TRUE;
  540. }
  541. } else {
  542. //
  543. // We don't have a device information element to lock, so we'll
  544. // lock the set itself...
  545. //
  546. if(!(pDeviceInfoSet->DiSetFlags & DISET_IS_LOCKED)) {
  547. pDeviceInfoSet->DiSetFlags |= DISET_IS_LOCKED;
  548. bUnlockDevInfoSet = TRUE;
  549. }
  550. }
  551. UnlockDeviceInfoSet(pDeviceInfoSet);
  552. pDeviceInfoSet = NULL;
  553. //
  554. // If there is an advanced property page provider for this class,
  555. // then call it.
  556. //
  557. if(ClassPagesEntryPoint) {
  558. spFusionEnterContext(ClassPagesFusionContext, &spFusionInstance);
  559. try {
  560. ClassPagesEntryPoint(&PropPageRequest,
  561. pSetupAddPropPage,
  562. (LPARAM)&PropPageAddProcContext
  563. );
  564. } finally {
  565. spFusionLeaveContext(&spFusionInstance);
  566. }
  567. }
  568. //
  569. // If there is an advanced property page provider for this
  570. // particular device, then call it.
  571. //
  572. if(DevicePagesEntryPoint) {
  573. spFusionEnterContext(DevicePagesFusionContext, &spFusionInstance);
  574. try {
  575. DevicePagesEntryPoint(&PropPageRequest,
  576. pSetupAddPropPage,
  577. (LPARAM)&PropPageAddProcContext
  578. );
  579. } finally {
  580. spFusionLeaveContext(&spFusionInstance);
  581. }
  582. }
  583. //
  584. // Finish initializing our class install params structure to
  585. // indicate we are asking for advanced property pages from the
  586. // class-/co-installers.
  587. //
  588. pPropertyPageData->ClassInstallHeader.InstallFunction = DIF_ADDPROPERTYPAGE_ADVANCED;
  589. break;
  590. case DIGCDP_FLAG_REMOTE_ADVANCED:
  591. //
  592. // Finish initializing our class install params structure to
  593. // indicate we are asking for remote advanced property pages from
  594. // the class-/co-installers.
  595. //
  596. pPropertyPageData->ClassInstallHeader.InstallFunction = DIF_ADDREMOTEPROPERTYPAGE_ADVANCED;
  597. break;
  598. }
  599. //
  600. // If we get here, then we should not have encountered any errors thus
  601. // far, and our class install parameter structure should be prepared
  602. // for requesting the appropriate pages from the class-/co-installers.
  603. //
  604. MYASSERT(NO_ERROR == Err);
  605. Err = DoInstallActionWithParams(
  606. pPropertyPageData->ClassInstallHeader.InstallFunction,
  607. DeviceInfoSet,
  608. DeviceInfoData,
  609. (PSP_CLASSINSTALL_HEADER)pPropertyPageData,
  610. sizeof(SP_ADDPROPERTYPAGE_DATA),
  611. INSTALLACTION_CALL_CI
  612. );
  613. if(ERROR_DI_DO_DEFAULT == Err) {
  614. //
  615. // This is not an error condition.
  616. //
  617. Err = NO_ERROR;
  618. }
  619. if(NO_ERROR == Err) {
  620. //
  621. // Add these pages to the list we're building to be handed back
  622. // to the caller.
  623. //
  624. for(PageIndex = 0;
  625. PageIndex < pPropertyPageData->NumDynamicPages;
  626. PageIndex++)
  627. {
  628. if(pSetupAddPropPage(pPropertyPageData->DynamicPages[PageIndex],
  629. (LPARAM)&PropPageAddProcContext)) {
  630. //
  631. // Clear this handle out of the class install params list,
  632. // because it's been either (a) transferred to the
  633. // LocalPageList or (b) destroyed (i.e., because there
  634. // wasn't room for it). We do this to prevent possible
  635. // double-free, e.g., if we hit an exception.
  636. //
  637. pPropertyPageData->DynamicPages[PageIndex] = NULL;
  638. } else {
  639. //
  640. // We ran out of room in our list, and were able to abort
  641. // early because the caller didn't request the RequiredSize
  642. // output.
  643. //
  644. break;
  645. }
  646. }
  647. } else {
  648. //
  649. // We encountered an error during our attempt to retrieve the
  650. // pages from the class-/co-installers. We may have gotten
  651. // some pages here, but we won't add these to our list. We
  652. // won't consider this a blocking error, because the class-/
  653. // co-installers shouldn't be allowed to prevent retrieval of
  654. // property pages from the legacy property page provider(s).
  655. //
  656. Err = NO_ERROR;
  657. }
  658. if(RequiredSize) {
  659. *RequiredSize = LocalPageListCount;
  660. }
  661. if(LocalPageListCount > PropPageAddProcContext.PageListSize) {
  662. Err = ERROR_INSUFFICIENT_BUFFER;
  663. }
  664. //
  665. // Copy our local buffer containing property sheet page handles over
  666. // into the phpage buffer in the caller-supplied property sheet header.
  667. //
  668. if(LocalPageList) {
  669. //
  670. // Make sure we skip over any pages that were already in the phpage
  671. // list...
  672. //
  673. NumPages = min(LocalPageListCount, PropPageAddProcContext.PageListSize);
  674. CopyMemory(&(PropertySheetHeader->phpage[PropertySheetHeader->nPages]),
  675. LocalPageList,
  676. NumPages * sizeof(HPROPSHEETPAGE)
  677. );
  678. PropertySheetHeader->nPages += NumPages;
  679. //
  680. // Free our local buffer so we won't try to destroy these handles
  681. // during clean-up.
  682. //
  683. MyFree(LocalPageList);
  684. LocalPageList = NULL;
  685. }
  686. } except(pSetupExceptionFilter(GetExceptionCode())) {
  687. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  688. }
  689. if(bUnlockDevInfoElem || bUnlockDevInfoSet) {
  690. try {
  691. if(!pDeviceInfoSet) {
  692. pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet);
  693. MYASSERT(pDeviceInfoSet);
  694. }
  695. if(pDeviceInfoSet) {
  696. if(bUnlockDevInfoElem) {
  697. MYASSERT(DevInfoElem);
  698. MYASSERT(DevInfoElem->DiElemFlags & DIE_IS_LOCKED);
  699. DevInfoElem->DiElemFlags &= ~DIE_IS_LOCKED;
  700. } else {
  701. MYASSERT(pDeviceInfoSet->DiSetFlags & DISET_IS_LOCKED);
  702. pDeviceInfoSet->DiSetFlags &= ~DISET_IS_LOCKED;
  703. }
  704. }
  705. } except(pSetupExceptionFilter(GetExceptionCode())) {
  706. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  707. }
  708. }
  709. //
  710. // Clean up any property sheet page handles that aren't getting
  711. // returned back to the caller (for whatever reason). Note that we protect
  712. // ourselves from exceptions in case the property page provider(s) gave us
  713. // bogus handles.
  714. //
  715. if(LocalPageList) {
  716. MYASSERT((Err != NO_ERROR) && (Err != ERROR_INSUFFICIENT_BUFFER));
  717. NumPages = min(LocalPageListCount, PropPageAddProcContext.PageListSize);
  718. for(PageIndex = 0; PageIndex < NumPages; PageIndex++) {
  719. if(LocalPageList[PageIndex]) {
  720. try {
  721. DestroyPropertySheetPage(LocalPageList[PageIndex]);
  722. } except(pSetupExceptionFilter(GetExceptionCode())) {
  723. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  724. }
  725. }
  726. }
  727. MyFree(LocalPageList);
  728. }
  729. if(pPropertyPageData) {
  730. for(PageIndex = 0;
  731. PageIndex < pPropertyPageData->NumDynamicPages;
  732. PageIndex++)
  733. {
  734. if(pPropertyPageData->DynamicPages[PageIndex]) {
  735. try {
  736. DestroyPropertySheetPage(pPropertyPageData->DynamicPages[PageIndex]);
  737. } except(pSetupExceptionFilter(GetExceptionCode())) {
  738. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  739. }
  740. }
  741. }
  742. MyFree(pPropertyPageData);
  743. }
  744. if(hk != INVALID_HANDLE_VALUE) {
  745. RegCloseKey(hk);
  746. }
  747. if(pDeviceInfoSet) {
  748. UnlockDeviceInfoSet(pDeviceInfoSet);
  749. }
  750. SetLastError(Err);
  751. return(Err == NO_ERROR);
  752. }
  753. BOOL
  754. CALLBACK
  755. pSetupAddPropPage(
  756. IN HPROPSHEETPAGE hPage,
  757. IN LPARAM lParam
  758. )
  759. /*++
  760. Routine Description:
  761. This is the callback routine that is passed to property page providers.
  762. This routine is called for each property page that the provider wishes to
  763. add.
  764. Arguments:
  765. hPage - Supplies a handle to the property page being added.
  766. lParam - Supplies a pointer to a context structure used when adding the new
  767. property page handle.
  768. Return Value:
  769. If the function succeeds, the return value is TRUE.
  770. If the function fails, the return value is FALSE.
  771. --*/
  772. {
  773. PSP_PROPPAGE_ADDPROC_CONTEXT Context = (PSP_PROPPAGE_ADDPROC_CONTEXT)lParam;
  774. DWORD PageIndex;
  775. //
  776. // Get the current page index and increment our page count. We want to do
  777. // this regardless of whether we have room in our list to store the hPage.
  778. //
  779. PageIndex = (*(Context->pNumPages))++;
  780. if(PageIndex < Context->PageListSize) {
  781. Context->PageList[PageIndex] = hPage;
  782. return TRUE;
  783. }
  784. //
  785. // We can't use this property page because it won't fit in our page list.
  786. // If we return FALSE, the caller should clean up the property page by
  787. // calling DestroyPropertySheetPage(). However, if we return TRUE (i.e.,
  788. // because we want to keep going to get a count of how many pages there are
  789. // in total), then the caller won't know that we're "throwing the pages
  790. // away", and they won't be cleaning these up. Thus, in that case we are
  791. // responsible for destroying the unused property pages.
  792. //
  793. if(Context->NoCancelOnFailure && hPage) {
  794. //
  795. // Protect ourselves in case the property page provider handed us a
  796. // bogus property sheet page handle...
  797. //
  798. try {
  799. DestroyPropertySheetPage(hPage);
  800. } except(pSetupExceptionFilter(GetExceptionCode())) {
  801. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  802. }
  803. }
  804. return Context->NoCancelOnFailure;
  805. }
  806. BOOL
  807. CALLBACK
  808. ExtensionPropSheetPageProc(
  809. IN LPVOID lpv,
  810. IN LPFNADDPROPSHEETPAGE lpfnAddPropSheetPageProc,
  811. IN LPARAM lParam
  812. )
  813. {
  814. PSP_PROPSHEETPAGE_REQUEST PropPageRequest = (PSP_PROPSHEETPAGE_REQUEST)lpv;
  815. HPROPSHEETPAGE hPropSheetPage = NULL;
  816. BOOL b = FALSE;
  817. try {
  818. //
  819. // Make sure we're running interactively.
  820. //
  821. if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
  822. leave;
  823. }
  824. if(PropPageRequest->cbSize != sizeof(SP_PROPSHEETPAGE_REQUEST)) {
  825. leave;
  826. }
  827. switch(PropPageRequest->PageRequested) {
  828. case SPPSR_SELECT_DEVICE_RESOURCES :
  829. if(!(hPropSheetPage = GetResourceSelectionPage(PropPageRequest->DeviceInfoSet,
  830. PropPageRequest->DeviceInfoData))) {
  831. leave;
  832. }
  833. break;
  834. default :
  835. //
  836. // Don't know what to do with this request.
  837. //
  838. leave;
  839. }
  840. if(lpfnAddPropSheetPageProc(hPropSheetPage, lParam)) {
  841. //
  842. // Page successfully handed off to requestor. Reset our handle so that we don't
  843. // try to free it.
  844. //
  845. hPropSheetPage = NULL;
  846. b = TRUE;
  847. }
  848. } except(pSetupExceptionFilter(GetExceptionCode())) {
  849. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  850. }
  851. if(hPropSheetPage) {
  852. //
  853. // Property page was successfully created, but never handed off to requestor. Free
  854. // it now.
  855. //
  856. DestroyPropertySheetPage(hPropSheetPage);
  857. }
  858. return b;
  859. }