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.

6181 lines
212 KiB

  1. /*++
  2. Copyright (c) 1993-2000 Microsoft Corporation
  3. Module Name:
  4. devinfo.c
  5. Abstract:
  6. Device Installer routines dealing with device information sets
  7. Author:
  8. Lonny McMichael (lonnym) 10-May-1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. //
  14. // Define the context structure used by the default device comparison
  15. // callback (used by SetupDiRegisterDeviceInfo).
  16. //
  17. typedef struct _DEFAULT_DEVCMP_CONTEXT {
  18. PCS_RESOURCE NewDevCsResource;
  19. PCS_RESOURCE CurDevCsResource;
  20. ULONG CsResourceSize; // applies to both buffers.
  21. } DEFAULT_DEVCMP_CONTEXT, *PDEFAULT_DEVCMP_CONTEXT;
  22. //
  23. // Private routine prototypes.
  24. //
  25. DWORD
  26. pSetupOpenAndAddNewDevInfoElem(
  27. IN PDEVICE_INFO_SET DeviceInfoSet,
  28. IN PCTSTR DeviceInstanceId,
  29. IN BOOL AllowPhantom,
  30. IN CONST GUID *ClassGuid, OPTIONAL
  31. IN HWND hwndParent, OPTIONAL
  32. OUT PDEVINFO_ELEM *DevInfoElem,
  33. IN BOOL CheckIfAlreadyThere,
  34. OUT PBOOL AlreadyPresent, OPTIONAL
  35. IN BOOL OpenExistingOnly,
  36. IN ULONG CmLocateFlags,
  37. IN PDEVICE_INFO_SET ContainingDeviceInfoSet
  38. );
  39. DWORD
  40. pSetupAddNewDeviceInfoElement(
  41. IN PDEVICE_INFO_SET DeviceInfoSet,
  42. IN DEVINST DevInst,
  43. IN CONST GUID *ClassGuid,
  44. IN PCTSTR Description, OPTIONAL
  45. IN HWND hwndParent, OPTIONAL
  46. IN DWORD DiElemFlags,
  47. IN PDEVICE_INFO_SET ContainingDeviceInfoSet,
  48. OUT PDEVINFO_ELEM *DeviceInfoElement
  49. );
  50. DWORD
  51. pSetupClassGuidFromDevInst(
  52. IN DEVINST DevInst,
  53. IN HMACHINE hMachine,
  54. OUT LPGUID ClassGuid
  55. );
  56. DWORD
  57. pSetupDupDevCompare(
  58. IN HDEVINFO DeviceInfoSet,
  59. IN PSP_DEVINFO_DATA NewDeviceData,
  60. IN PSP_DEVINFO_DATA ExistingDeviceData,
  61. IN PVOID CompareContext
  62. );
  63. DWORD
  64. pSetupAddInterfaceDeviceToDevInfoElem(
  65. IN PDEVICE_INFO_SET DeviceInfoSet,
  66. IN PDEVINFO_ELEM DevInfoElem,
  67. IN CONST GUID *ClassGuid,
  68. IN PTSTR InterfaceDeviceName,
  69. IN BOOL IsActive,
  70. IN BOOL IsDefault,
  71. IN BOOL StoreTruncateNode,
  72. IN BOOL OpenExistingOnly,
  73. OUT PINTERFACE_DEVICE_NODE *InterfaceDeviceNode OPTIONAL
  74. );
  75. DWORD
  76. _SetupDiOpenInterfaceDevice(
  77. IN HDEVINFO DeviceInfoSet,
  78. IN PTSTR DevicePath,
  79. IN DWORD OpenFlags,
  80. OUT PSP_DEVICE_INTERFACE_DATA InterfaceDeviceData OPTIONAL
  81. );
  82. DWORD
  83. pSetupGetDevInstNameAndStatusForInterfaceDevice(
  84. IN HKEY hKeyInterfaceClass,
  85. IN PCTSTR InterfaceDeviceName,
  86. OUT PTSTR OwningDevInstName, OPTIONAL
  87. IN DWORD OwningDevInstNameSize,
  88. OUT PBOOL IsActive, OPTIONAL
  89. OUT PBOOL IsDefault OPTIONAL
  90. );
  91. BOOL
  92. pSetupDiGetOrSetDeviceInfoContext(
  93. IN HDEVINFO DeviceInfoSet,
  94. IN PSP_DEVINFO_DATA DeviceInfoData,
  95. IN DWORD InContext,
  96. OUT PDWORD OutContext OPTIONAL
  97. );
  98. HDEVINFO
  99. WINAPI
  100. SetupDiCreateDeviceInfoList(
  101. IN CONST GUID *ClassGuid, OPTIONAL
  102. IN HWND hwndParent OPTIONAL
  103. )
  104. /*++
  105. Routine Description:
  106. This API creates an empty device information set that will contain device
  107. device information member elements. This set may be associated with an
  108. optionally-specified class GUID.
  109. Arguments:
  110. ClassGuid - Optionally, supplies a pointer to the class GUID that is to be
  111. associated with this set.
  112. hwndParent - Optionally, supplies the window handle of the top-level window
  113. to use for any UI related to installation of a class driver contained
  114. in this set's global class driver list (if it has one).
  115. Return Value:
  116. If the function succeeds, the return value is a handle to an empty device
  117. information set.
  118. If the function fails, the return value is INVALID_HANDLE_VALUE. To get
  119. extended error information, call GetLastError.
  120. --*/
  121. {
  122. return SetupDiCreateDeviceInfoListEx(ClassGuid, hwndParent, NULL, NULL);
  123. }
  124. #ifdef UNICODE
  125. //
  126. // ANSI version
  127. //
  128. HDEVINFO
  129. WINAPI
  130. SetupDiCreateDeviceInfoListExA(
  131. IN CONST GUID *ClassGuid, OPTIONAL
  132. IN HWND hwndParent, OPTIONAL
  133. IN PCSTR MachineName, OPTIONAL
  134. IN PVOID Reserved
  135. )
  136. {
  137. PCWSTR UnicodeMachineName;
  138. DWORD rc;
  139. HDEVINFO hDevInfo;
  140. hDevInfo = INVALID_HANDLE_VALUE;
  141. if(MachineName) {
  142. rc = pSetupCaptureAndConvertAnsiArg(MachineName, &UnicodeMachineName);
  143. } else {
  144. UnicodeMachineName = NULL;
  145. rc = NO_ERROR;
  146. }
  147. if(rc == NO_ERROR) {
  148. hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid,
  149. hwndParent,
  150. UnicodeMachineName,
  151. Reserved
  152. );
  153. rc = GetLastError();
  154. if(UnicodeMachineName) {
  155. MyFree(UnicodeMachineName);
  156. }
  157. }
  158. SetLastError(rc);
  159. return hDevInfo;
  160. }
  161. #else
  162. //
  163. // Unicode version
  164. //
  165. HDEVINFO
  166. WINAPI
  167. SetupDiCreateDeviceInfoListExW(
  168. IN CONST GUID *ClassGuid, OPTIONAL
  169. IN HWND hwndParent, OPTIONAL
  170. IN PCWSTR MachineName, OPTIONAL
  171. IN PVOID Reserved
  172. )
  173. {
  174. UNREFERENCED_PARAMETER(ClassGuid);
  175. UNREFERENCED_PARAMETER(hwndParent);
  176. UNREFERENCED_PARAMETER(MachineName);
  177. UNREFERENCED_PARAMETER(Reserved);
  178. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  179. return(FALSE);
  180. }
  181. #endif
  182. HDEVINFO
  183. WINAPI
  184. SetupDiCreateDeviceInfoListEx(
  185. IN CONST GUID *ClassGuid, OPTIONAL
  186. IN HWND hwndParent, OPTIONAL
  187. IN PCTSTR MachineName, OPTIONAL
  188. IN PVOID Reserved
  189. )
  190. /*++
  191. Routine Description:
  192. This API creates an empty device information set that will contain device
  193. device information member elements. This set may be associated with an
  194. optionally-specified class GUID.
  195. Arguments:
  196. ClassGuid - Optionally, supplies a pointer to the class GUID that is to be
  197. associated with this set.
  198. hwndParent - Optionally, supplies the window handle of the top-level window
  199. to use for any UI related to installation of a class driver contained
  200. in this set's global class driver list (if it has one).
  201. MachineName - Optionally, supplies the name of the machine for which this
  202. device information set is to be related. Only devices on that machine
  203. may be opened/created. If this parameter is NULL, then the local machine
  204. is used.
  205. Reserved - Reserved for future use--must be NULL.
  206. Return Value:
  207. If the function succeeds, the return value is a handle to an empty device
  208. information set.
  209. If the function fails, the return value is INVALID_HANDLE_VALUE. To get
  210. extended error information, call GetLastError.
  211. --*/
  212. {
  213. PDEVICE_INFO_SET DeviceInfoSet;
  214. DWORD Err = NO_ERROR;
  215. CONFIGRET cr;
  216. //
  217. // Make sure the user didn't pass us anything in the Reserved parameter.
  218. //
  219. if(Reserved) {
  220. SetLastError(ERROR_INVALID_PARAMETER);
  221. return INVALID_HANDLE_VALUE;
  222. }
  223. if(DeviceInfoSet = AllocateDeviceInfoSet()) {
  224. try {
  225. //
  226. // If the user specified the name of a remote machine, connect to
  227. // that machine now.
  228. //
  229. if(MachineName) {
  230. if(CR_SUCCESS != (cr = CM_Connect_Machine(MachineName, &(DeviceInfoSet->hMachine)))) {
  231. //
  232. // Make sure hMachine is still NULL, so we won't try to disconnect later.
  233. //
  234. DeviceInfoSet->hMachine = NULL;
  235. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  236. goto clean0;
  237. }
  238. //
  239. // Store the machine name in the string table, so it can be
  240. // retrieved later via SetupDiGetDeviceInfoListDetail.
  241. //
  242. if(-1 == (DeviceInfoSet->MachineName = pStringTableAddString(DeviceInfoSet->StringTable,
  243. (PTSTR)MachineName,
  244. STRTAB_CASE_SENSITIVE,
  245. NULL,
  246. 0))) {
  247. Err = ERROR_NOT_ENOUGH_MEMORY;
  248. goto clean0;
  249. }
  250. }
  251. if(ClassGuid) {
  252. //
  253. // If a class GUID was specified, then store it away in
  254. // the device information set.
  255. //
  256. CopyMemory(&(DeviceInfoSet->ClassGuid),
  257. ClassGuid,
  258. sizeof(GUID)
  259. );
  260. DeviceInfoSet->HasClassGuid = TRUE;
  261. }
  262. DeviceInfoSet->InstallParamBlock.hwndParent = hwndParent;
  263. clean0: ; // nothing to do.
  264. } except(EXCEPTION_EXECUTE_HANDLER) {
  265. Err = ERROR_INVALID_PARAMETER;
  266. //
  267. // Reference the following variable so the compiler will respect statement ordering
  268. // w.r.t. assignment.
  269. //
  270. DeviceInfoSet->hMachine = DeviceInfoSet->hMachine;
  271. }
  272. if(Err != NO_ERROR) {
  273. DestroyDeviceInfoSet(NULL, DeviceInfoSet);
  274. }
  275. } else {
  276. Err = ERROR_NOT_ENOUGH_MEMORY;
  277. }
  278. SetLastError(Err);
  279. return (Err == NO_ERROR) ? (HDEVINFO)DeviceInfoSet
  280. : (HDEVINFO)INVALID_HANDLE_VALUE;
  281. }
  282. BOOL
  283. WINAPI
  284. SetupDiGetDeviceInfoListClass(
  285. IN HDEVINFO DeviceInfoSet,
  286. OUT LPGUID ClassGuid
  287. )
  288. /*++
  289. Routine Description:
  290. This API retrieves the class GUID associated with a device information
  291. set (if it has an associated class).
  292. Arguments:
  293. DeviceInfoSet - Supplies a handle to a device information set whose associated
  294. class is being queried.
  295. ClassGuid - Supplies a pointer to a variable that receives the GUID for the
  296. associated class.
  297. Return Value:
  298. If the function succeeds, the return value is TRUE.
  299. If the function fails, the return value is FALSE. To get extended error
  300. information, call GetLastError. If the set has no associated class, then
  301. GetLastError will return ERROR_NO_ASSOCIATED_CLASS.
  302. --*/
  303. {
  304. PDEVICE_INFO_SET pDeviceInfoSet;
  305. DWORD Err;
  306. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  307. SetLastError(ERROR_INVALID_HANDLE);
  308. return FALSE;
  309. }
  310. Err = NO_ERROR;
  311. try {
  312. if(pDeviceInfoSet->HasClassGuid) {
  313. //
  314. // Copy the GUID to the user-supplied buffer.
  315. //
  316. CopyMemory(ClassGuid,
  317. &(pDeviceInfoSet->ClassGuid),
  318. sizeof(GUID)
  319. );
  320. } else {
  321. Err = ERROR_NO_ASSOCIATED_CLASS;
  322. }
  323. } except(EXCEPTION_EXECUTE_HANDLER) {
  324. Err = ERROR_INVALID_PARAMETER;
  325. }
  326. UnlockDeviceInfoSet(pDeviceInfoSet);
  327. SetLastError(Err);
  328. return (Err == NO_ERROR);
  329. }
  330. #ifdef UNICODE
  331. //
  332. // ANSI version
  333. //
  334. BOOL
  335. WINAPI
  336. SetupDiGetDeviceInfoListDetailA(
  337. IN HDEVINFO DeviceInfoSet,
  338. OUT PSP_DEVINFO_LIST_DETAIL_DATA_A DeviceInfoSetDetailData
  339. )
  340. {
  341. DWORD rc;
  342. BOOL b;
  343. SP_DEVINFO_LIST_DETAIL_DATA_W UnicodeDevInfoSetDetails;
  344. UnicodeDevInfoSetDetails.cbSize = sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W);
  345. b = SetupDiGetDeviceInfoListDetailW(DeviceInfoSet, &UnicodeDevInfoSetDetails);
  346. rc = GetLastError();
  347. if(b) {
  348. rc = pSetupDiDevInfoSetDetailDataUnicodeToAnsi(&UnicodeDevInfoSetDetails, DeviceInfoSetDetailData);
  349. if(rc != NO_ERROR) {
  350. b = FALSE;
  351. }
  352. }
  353. SetLastError(rc);
  354. return(b);
  355. }
  356. #else
  357. //
  358. // Unicode stub
  359. //
  360. BOOL
  361. WINAPI
  362. SetupDiGetDeviceInfoListDetailW(
  363. IN HDEVINFO DeviceInfoSet,
  364. OUT PSP_DEVINFO_LIST_DETAIL_DATA_W DeviceInfoSetDetailData
  365. )
  366. {
  367. UNREFERENCED_PARAMETER(DeviceInfoSet);
  368. UNREFERENCED_PARAMETER(DeviceInfoSetDetailData);
  369. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  370. return(FALSE);
  371. }
  372. #endif
  373. BOOL
  374. WINAPI
  375. SetupDiGetDeviceInfoListDetail(
  376. IN HDEVINFO DeviceInfoSet,
  377. OUT PSP_DEVINFO_LIST_DETAIL_DATA DeviceInfoSetDetailData
  378. )
  379. /*++
  380. Routine Description:
  381. This routine retrieves information about the specified device information set,
  382. such as its associated class (if any), and the remote machine it was opened for
  383. (if this is a remoted HDEVINFO). This API supercedes SetupDiGetDeviceInfoListClass.
  384. Arguments:
  385. DeviceInfoSet - Supplies a handle to the device information set to retrieve
  386. detailed information for.
  387. DeviceInfoSetDetailData - Supplies the address of a structure that receives
  388. information about the specified device information set. This structure is
  389. defined as follows:
  390. typedef struct _SP_DEVINFO_LIST_DETAIL_DATA {
  391. DWORD cbSize;
  392. GUID ClassGuid;
  393. HANDLE RemoteMachineHandle;
  394. TCHAR RemoteMachineName[SP_MAX_MACHINENAME_LENGTH];
  395. } SP_DEVINFO_LIST_DETAIL_DATA, *PSP_DEVINFO_LIST_DETAIL_DATA;
  396. where:
  397. ClassGuid specifies the class associated with the device information
  398. set, or GUID_NULL if there is no associated class.
  399. RemoteMachineHandle is the ConfigMgr32 machine handle used to access
  400. the remote machine, if this is a remoted HDEVINFO (i.e., a
  401. MachineName was specified when the set was created via
  402. SetupDiCreateDeviceInfoListEx or SetupDiGetClassDevsEx). All
  403. DevInst handles stored in SP_DEVINFO_DATA structures for elements
  404. of this set are relative to this handle, and must be used in
  405. combination with this handle when calling any CM_*_Ex APIs.
  406. If this is not a device information set for a remote machine, this
  407. field will be NULL.
  408. NOTE: DO NOT destroy this handle via CM_Disconnect_Machine. This
  409. handle will be cleaned up when the device information set is destroyed
  410. via SetupDiDestroyDeviceInfoList.
  411. RemoteMachineName specifies the name used to connect to the remote
  412. machine whose handle is stored in RemoteMachineHandle. If this is
  413. not a device information set for a remote machine, this will be an
  414. empty string.
  415. Return Value:
  416. If the function succeeds, the return value is TRUE.
  417. If the function fails, the return value is FALSE. To get extended error
  418. information, call GetLastError.
  419. Remarks:
  420. The cbSize field of the output structure must be set to
  421. sizeof(SP_DEVINFO_LIST_DETAIL_DATA) or the call will fail with
  422. ERROR_INVALID_USER_BUFFER.
  423. --*/
  424. {
  425. PDEVICE_INFO_SET pDeviceInfoSet;
  426. DWORD Err;
  427. PCTSTR MachineName;
  428. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  429. SetLastError(ERROR_INVALID_HANDLE);
  430. return FALSE;
  431. }
  432. Err = NO_ERROR;
  433. try {
  434. if(DeviceInfoSetDetailData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA)) {
  435. Err = ERROR_INVALID_USER_BUFFER;
  436. goto clean0;
  437. }
  438. //
  439. // Store the set's associated class GUID, or GUID_NULL if there isn't one.
  440. //
  441. if(pDeviceInfoSet->HasClassGuid) {
  442. CopyMemory(&(DeviceInfoSetDetailData->ClassGuid),
  443. &(pDeviceInfoSet->ClassGuid),
  444. sizeof(GUID)
  445. );
  446. } else {
  447. CopyMemory(&(DeviceInfoSetDetailData->ClassGuid), &GUID_NULL, sizeof(GUID));
  448. }
  449. DeviceInfoSetDetailData->RemoteMachineHandle = pDeviceInfoSet->hMachine;
  450. //
  451. // If this is a remoted HDEVINFO, store the machine name in the caller's buffer,
  452. // otherwise store an empty string.
  453. //
  454. if(pDeviceInfoSet->hMachine) {
  455. MYASSERT(pDeviceInfoSet->MachineName != -1);
  456. MachineName = pStringTableStringFromId(pDeviceInfoSet->StringTable, pDeviceInfoSet->MachineName);
  457. lstrcpyn(DeviceInfoSetDetailData->RemoteMachineName,
  458. MachineName,
  459. SIZECHARS(DeviceInfoSetDetailData->RemoteMachineName)
  460. );
  461. } else {
  462. MYASSERT(pDeviceInfoSet->MachineName == -1);
  463. *(DeviceInfoSetDetailData->RemoteMachineName) = TEXT('\0');
  464. }
  465. clean0: ; // nothing to do.
  466. } except(EXCEPTION_EXECUTE_HANDLER) {
  467. Err = ERROR_INVALID_PARAMETER;
  468. }
  469. UnlockDeviceInfoSet(pDeviceInfoSet);
  470. SetLastError(Err);
  471. return (Err == NO_ERROR);
  472. }
  473. BOOL
  474. WINAPI
  475. SetupDiDestroyDeviceInfoList(
  476. IN HDEVINFO DeviceInfoSet
  477. )
  478. /*++
  479. Routine Description:
  480. This API destroys a device information set, freeing all associated memory.
  481. Arguments:
  482. DeviceInfoSet - Supplies a handle to a device information set to be destroyed.
  483. Return Value:
  484. If the function succeeds, the return value is TRUE.
  485. If the function fails, the return value is FALSE. To get extended error
  486. information, call GetLastError.
  487. --*/
  488. {
  489. DWORD Err;
  490. PDEVICE_INFO_SET pDeviceInfoSet;
  491. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  492. SetLastError(ERROR_INVALID_HANDLE);
  493. return FALSE;
  494. }
  495. try {
  496. Err = DestroyDeviceInfoSet(DeviceInfoSet, pDeviceInfoSet);
  497. } except(EXCEPTION_EXECUTE_HANDLER) {
  498. Err = ERROR_INVALID_HANDLE;
  499. }
  500. SetLastError(Err);
  501. return (Err == NO_ERROR);
  502. }
  503. #ifdef UNICODE
  504. //
  505. // ANSI version
  506. //
  507. BOOL
  508. WINAPI
  509. SetupDiCreateDeviceInfoA(
  510. IN HDEVINFO DeviceInfoSet,
  511. IN PCSTR DeviceName,
  512. IN CONST GUID *ClassGuid,
  513. IN PCSTR DeviceDescription, OPTIONAL
  514. IN HWND hwndParent, OPTIONAL
  515. IN DWORD CreationFlags,
  516. OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  517. )
  518. {
  519. PCWSTR deviceName,deviceDescription;
  520. DWORD rc;
  521. BOOL b;
  522. b = FALSE;
  523. rc = pSetupCaptureAndConvertAnsiArg(DeviceName,&deviceName);
  524. if(rc == NO_ERROR) {
  525. if(DeviceDescription) {
  526. rc = pSetupCaptureAndConvertAnsiArg(DeviceDescription,&deviceDescription);
  527. } else {
  528. deviceDescription = NULL;
  529. }
  530. if(rc == NO_ERROR) {
  531. b = SetupDiCreateDeviceInfoW(
  532. DeviceInfoSet,
  533. deviceName,
  534. ClassGuid,
  535. deviceDescription,
  536. hwndParent,
  537. CreationFlags,
  538. DeviceInfoData
  539. );
  540. rc = GetLastError();
  541. if(deviceDescription) {
  542. MyFree(deviceDescription);
  543. }
  544. }
  545. MyFree(deviceName);
  546. } else {
  547. //
  548. // The DeviceName parameter was bad--return the same error the unicode API does.
  549. //
  550. rc = ERROR_INVALID_DEVINST_NAME;
  551. }
  552. SetLastError(rc);
  553. return(b);
  554. }
  555. #else
  556. //
  557. // Unicode version
  558. //
  559. BOOL
  560. WINAPI
  561. SetupDiCreateDeviceInfoW(
  562. IN HDEVINFO DeviceInfoSet,
  563. IN PCWSTR DeviceName,
  564. IN CONST GUID *ClassGuid,
  565. IN PCWSTR DeviceDescription, OPTIONAL
  566. IN HWND hwndParent, OPTIONAL
  567. IN DWORD CreationFlags,
  568. OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  569. )
  570. {
  571. UNREFERENCED_PARAMETER(DeviceInfoSet);
  572. UNREFERENCED_PARAMETER(DeviceName);
  573. UNREFERENCED_PARAMETER(ClassGuid);
  574. UNREFERENCED_PARAMETER(DeviceDescription);
  575. UNREFERENCED_PARAMETER(hwndParent);
  576. UNREFERENCED_PARAMETER(CreationFlags);
  577. UNREFERENCED_PARAMETER(DeviceInfoData);
  578. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  579. return(FALSE);
  580. }
  581. #endif
  582. BOOL
  583. WINAPI
  584. SetupDiCreateDeviceInfo(
  585. IN HDEVINFO DeviceInfoSet,
  586. IN PCTSTR DeviceName,
  587. IN CONST GUID *ClassGuid,
  588. IN PCTSTR DeviceDescription, OPTIONAL
  589. IN HWND hwndParent, OPTIONAL
  590. IN DWORD CreationFlags,
  591. OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  592. )
  593. /*++
  594. Routine Description:
  595. This API creates a new device information element, and adds it as a new member
  596. to the specified set.
  597. Arguments:
  598. DeviceInfoSet - Supplies a handle to a device information set to which this
  599. new device information element is to be added.
  600. DeviceName - Supplies either a full device instance ID (e.g., Root\*PNP0500\0000)
  601. or a Root-enumerated device ID, minus enumerator branch prefix and instance
  602. ID suffix (e.g., *PNP0500). The latter may only be specified if the
  603. DICD_GENERATE_ID flag is specified in the CreationFlags parameter.
  604. ClassGuid - Supplies a pointer to the GUID for this device's class. If the
  605. class is not yet known, this value should be GUID_NULL.
  606. DeviceDescription - Optionally, supplies a textual description of the device.
  607. hwndParent - Optionally, supplies the window handle of the top-level window
  608. to use for any UI related to installing the device.
  609. CreationFlags - Supplies flags controlling how the device information element
  610. is to be created. May be a combination of the following values:
  611. DICD_GENERATE_ID - If this flag is specified, then DeviceName contains only
  612. a Root-enumerated device ID, and needs to have a unique
  613. device instance key created for it. This unique device
  614. instance key will be generated as:
  615. Enum\Root\<DeviceName>\<InstanceID>
  616. where <InstanceID> is a 4-digit, base-10 number that
  617. is unique among all subkeys under Enum\Root\<DeviceName>.
  618. The API, SetupDiGetDeviceInstanceId, may be called to
  619. find out what ID was generated for this device information
  620. element.
  621. DICD_INHERIT_CLASSDRVS - If this flag is specified, then the resulting device
  622. information element will inherit the class driver list (if any)
  623. associated with the device information set itself. In addition,
  624. if there is a selected driver for the device information set,
  625. that same driver will be selected for the new device information
  626. element.
  627. DeviceInfoData - Optionaly, supplies a pointer to the variable that receives
  628. a context structure initialized for this new device information element.
  629. Return Value:
  630. If the function succeeds, the return value is TRUE.
  631. If the function fails, the return value is FALSE. To get extended error
  632. information, call GetLastError.
  633. Remarks:
  634. If this device instance is being added to a set that has an associated class,
  635. then the device class must be the same, or the call will fail, and GetLastError
  636. will return ERROR_CLASS_MISMATCH.
  637. If the specified device instance is the same as an existing device instance key in
  638. the registry, the call will fail with ERROR_DEVINST_ALREADY_EXISTS. (This only
  639. applies if DICD_GENERATE_ID is not specified.)
  640. The specified class GUID will be written out to the ClassGUID device instance
  641. value entry. If the class name can be retrieved (via SetupDiClassNameFromGuid),
  642. then it will be written to the Class value entry as well.
  643. If the new device information element was successfully created, but the
  644. user-supplied DeviceInfoData buffer is invalid, this API will return FALSE, with
  645. GetLastError returning ERROR_INVALID_USER_BUFFER. The device information element
  646. _will_ have been added as a new member of the set, however.
  647. Note that since new device information elements are always added at the end
  648. of the existing list, the enumeration ordering is preserved, thus we don't
  649. need to invalidate our enumeration hint.
  650. --*/
  651. {
  652. PDEVICE_INFO_SET pDeviceInfoSet;
  653. DWORD Err, StringLen;
  654. PDEVINFO_ELEM DevInfoElem, PrevTailDevInfoElem;
  655. DEVINST DevInst, RootDevInst;
  656. CONFIGRET cr;
  657. ULONG CmFlags;
  658. TCHAR TempString[GUID_STRING_LEN];
  659. PDRIVER_LIST_OBJECT CurDrvListObject;
  660. //
  661. // We use the TempString buffer both for the string representation of
  662. // a Class GUID, and for the Class name. The following assert ensures
  663. // that our assumptions about the relative lengths of these two strings
  664. // continues to be valid.
  665. //
  666. MYASSERT(GUID_STRING_LEN >= MAX_CLASS_NAME_LEN);
  667. if(CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS)) {
  668. SetLastError(ERROR_INVALID_FLAGS);
  669. return FALSE;
  670. }
  671. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  672. SetLastError(ERROR_INVALID_HANDLE);
  673. return FALSE;
  674. }
  675. Err = NO_ERROR;
  676. DevInst = 0;
  677. DevInfoElem = NULL;
  678. try {
  679. //
  680. // Get a pointer to the current tail of the devinfo element list for this
  681. // set, so that we can easily lop off the new node if we encounter an error
  682. // after insertion.
  683. //
  684. PrevTailDevInfoElem = pDeviceInfoSet->DeviceInfoTail;
  685. //
  686. // Get a handle to the root device instance, to be used as the parent
  687. // for the phantom device instance we're about to create.
  688. //
  689. if(CM_Locate_DevInst_Ex(&RootDevInst, NULL, CM_LOCATE_DEVINST_NORMAL,
  690. pDeviceInfoSet->hMachine) != CR_SUCCESS) {
  691. //
  692. // We're really hosed if we can't get a handle to the root device
  693. // instance!
  694. //
  695. Err = ERROR_INVALID_DATA;
  696. goto clean0;
  697. }
  698. //
  699. // Create a handle to a phantom device instance.
  700. //
  701. CmFlags = CM_CREATE_DEVINST_PHANTOM;
  702. if(CreationFlags & DICD_GENERATE_ID) {
  703. CmFlags |= CM_CREATE_DEVINST_GENERATE_ID;
  704. }
  705. if((cr = CM_Create_DevInst_Ex(&DevInst,
  706. (DEVINSTID)DeviceName,
  707. RootDevInst,
  708. CmFlags,
  709. pDeviceInfoSet->hMachine)) != CR_SUCCESS) {
  710. //
  711. // Make sure DevInst handle is still invalid, so we won't try to
  712. // delete it later.
  713. //
  714. DevInst = 0;
  715. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  716. goto clean0;
  717. }
  718. if(NO_ERROR != (Err = pSetupAddNewDeviceInfoElement(pDeviceInfoSet,
  719. DevInst,
  720. ClassGuid,
  721. DeviceDescription,
  722. hwndParent,
  723. DIE_IS_PHANTOM,
  724. pDeviceInfoSet,
  725. &DevInfoElem))) {
  726. //
  727. // Make sure DevInfoElem is still NULL, so we won't try to free it later.
  728. //
  729. DevInfoElem = NULL;
  730. goto clean0;
  731. }
  732. //
  733. // Now, set the Class and ClassGUID properties for the new device instance.
  734. //
  735. pSetupStringFromGuid(ClassGuid, TempString, SIZECHARS(TempString));
  736. CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  737. CM_DRP_CLASSGUID,
  738. (PVOID)TempString,
  739. GUID_STRING_LEN * sizeof(TCHAR),
  740. 0,pDeviceInfoSet->hMachine);
  741. if(!IsEqualGUID(ClassGuid, &GUID_NULL) &&
  742. SetupDiClassNameFromGuid(ClassGuid,
  743. TempString,
  744. SIZECHARS(TempString),
  745. &StringLen)) {
  746. CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  747. CM_DRP_CLASS,
  748. (PVOID)TempString,
  749. StringLen * sizeof(TCHAR),
  750. 0,pDeviceInfoSet->hMachine);
  751. }
  752. //
  753. // If the caller wants the newly-created devinfo element to inherit the global
  754. // class driver list, do that now.
  755. //
  756. if((CreationFlags & DICD_INHERIT_CLASSDRVS) && (pDeviceInfoSet->ClassDriverHead)) {
  757. //
  758. // Find the global class driver list in the devinfo set's list of driver lists.
  759. //
  760. CurDrvListObject = GetAssociatedDriverListObject(pDeviceInfoSet->ClassDrvListObjectList,
  761. pDeviceInfoSet->ClassDriverHead,
  762. NULL
  763. );
  764. MYASSERT(CurDrvListObject && (CurDrvListObject->RefCount > 0));
  765. //
  766. // We found the driver list object, now do the inheritance, and increment the refcount.
  767. //
  768. DevInfoElem->ClassDriverCount = pDeviceInfoSet->ClassDriverCount;
  769. DevInfoElem->ClassDriverHead = pDeviceInfoSet->ClassDriverHead;
  770. DevInfoElem->ClassDriverTail = pDeviceInfoSet->ClassDriverTail;
  771. if(DevInfoElem->SelectedDriver = pDeviceInfoSet->SelectedClassDriver) {
  772. DevInfoElem->SelectedDriverType = SPDIT_CLASSDRIVER;
  773. }
  774. DevInfoElem->InstallParamBlock.Flags |= CurDrvListObject->ListCreationFlags;
  775. DevInfoElem->InstallParamBlock.FlagsEx |= CurDrvListObject->ListCreationFlagsEx;
  776. DevInfoElem->InstallParamBlock.DriverPath = CurDrvListObject->ListCreationDriverPath;
  777. CurDrvListObject->RefCount++;
  778. }
  779. clean0:
  780. ; // Nothing to do.
  781. } except(EXCEPTION_EXECUTE_HANDLER) {
  782. Err = ERROR_INVALID_PARAMETER;
  783. //
  784. // Reference the following variables so the compiler will respect our statement ordering
  785. // w.r.t. assignment.
  786. //
  787. DevInst = DevInst;
  788. DevInfoElem = DevInfoElem;
  789. PrevTailDevInfoElem = PrevTailDevInfoElem;
  790. }
  791. if(Err == NO_ERROR) {
  792. if(DeviceInfoData) {
  793. //
  794. // The user supplied a buffer to receive a SP_DEVINFO_DATA
  795. // structure, so fill that in now.
  796. //
  797. try {
  798. if(!(DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
  799. DevInfoElem,
  800. DeviceInfoData))) {
  801. Err = ERROR_INVALID_USER_BUFFER;
  802. }
  803. } except(EXCEPTION_EXECUTE_HANDLER) {
  804. Err = ERROR_INVALID_USER_BUFFER;
  805. }
  806. }
  807. } else if(DevInst) {
  808. //
  809. // This should never fail.
  810. //
  811. cr = CM_Uninstall_DevInst(DevInst, 0);
  812. MYASSERT(cr == CR_SUCCESS);
  813. if(DevInfoElem) {
  814. //
  815. // An error occurred after we created the device information element--clean it up now.
  816. //
  817. try {
  818. MYASSERT(!DevInfoElem->Next);
  819. if(PrevTailDevInfoElem) {
  820. MYASSERT(PrevTailDevInfoElem->Next == DevInfoElem);
  821. PrevTailDevInfoElem->Next = NULL;
  822. pDeviceInfoSet->DeviceInfoTail = PrevTailDevInfoElem;
  823. } else {
  824. pDeviceInfoSet->DeviceInfoHead = pDeviceInfoSet->DeviceInfoTail = NULL;
  825. }
  826. MYASSERT(pDeviceInfoSet->DeviceInfoCount > 0);
  827. pDeviceInfoSet->DeviceInfoCount--;
  828. MyFree(DevInfoElem);
  829. } except(EXCEPTION_EXECUTE_HANDLER) {
  830. ; // nothing to do.
  831. }
  832. }
  833. }
  834. UnlockDeviceInfoSet(pDeviceInfoSet);
  835. SetLastError(Err);
  836. return(Err == NO_ERROR);
  837. }
  838. #ifdef UNICODE
  839. //
  840. // ANSI version
  841. //
  842. BOOL
  843. WINAPI
  844. SetupDiOpenDeviceInfoA(
  845. IN HDEVINFO DeviceInfoSet,
  846. IN PCSTR DeviceInstanceId,
  847. IN HWND hwndParent, OPTIONAL
  848. IN DWORD OpenFlags,
  849. OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  850. )
  851. {
  852. PCWSTR deviceInstanceId;
  853. DWORD rc;
  854. BOOL b;
  855. rc = pSetupCaptureAndConvertAnsiArg(DeviceInstanceId,&deviceInstanceId);
  856. if(rc == NO_ERROR) {
  857. b = SetupDiOpenDeviceInfoW(
  858. DeviceInfoSet,
  859. deviceInstanceId,
  860. hwndParent,
  861. OpenFlags,
  862. DeviceInfoData
  863. );
  864. rc = GetLastError();
  865. MyFree(deviceInstanceId);
  866. } else {
  867. b = FALSE;
  868. }
  869. SetLastError(rc);
  870. return(b);
  871. }
  872. #else
  873. //
  874. // Unicode version
  875. //
  876. BOOL
  877. WINAPI
  878. SetupDiOpenDeviceInfoW(
  879. IN HDEVINFO DeviceInfoSet,
  880. IN PCWSTR DeviceInstanceId,
  881. IN HWND hwndParent, OPTIONAL
  882. IN DWORD OpenFlags,
  883. OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  884. )
  885. {
  886. UNREFERENCED_PARAMETER(DeviceInfoSet);
  887. UNREFERENCED_PARAMETER(DeviceInstanceId);
  888. UNREFERENCED_PARAMETER(hwndParent);
  889. UNREFERENCED_PARAMETER(OpenFlags);
  890. UNREFERENCED_PARAMETER(DeviceInfoData);
  891. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  892. return(FALSE);
  893. }
  894. #endif
  895. BOOL
  896. WINAPI
  897. SetupDiOpenDeviceInfo(
  898. IN HDEVINFO DeviceInfoSet,
  899. IN PCTSTR DeviceInstanceId,
  900. IN HWND hwndParent, OPTIONAL
  901. IN DWORD OpenFlags,
  902. OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  903. )
  904. /*++
  905. Routine Description:
  906. This API retrieves information about an existing device instance, and adds
  907. it to the specified device information set. If a device information element
  908. already exists for this device instance, the existing element is returned.
  909. Arguments:
  910. DeviceInfoSet - Supplies a handle to a device information set to which the
  911. opened device information element is to be added.
  912. DeviceInstanceId - Supplies the ID of the device instance. This is the
  913. registry path (relative to the Enum branch) of the device instance key.
  914. (E.g., Root\*PNP0500\0000)
  915. hwndParent - Optionally, supplies the window handle of the top-level window
  916. to use for any UI related to installing the device.
  917. OpenFlags - Supplies flags controlling how the device information element
  918. is to be opened. May be a combination of the following values:
  919. DIOD_INHERIT_CLASSDRVS - If this flag is specified, then the resulting device
  920. information element will inherit the class driver
  921. list (if any) associated with the device information
  922. set itself. In addition, if there is a selected
  923. driver for the device information set, that same
  924. driver will be selected for the new device information
  925. element.
  926. If the device information element was already present,
  927. its class driver list (if any) will be replaced with
  928. this new, inherited, list.
  929. DIOD_CANCEL_REMOVE - If this flag is set, a device that was marked for removal
  930. will be have its pending removal cancelled.
  931. DeviceInfoData - Optionally, supplies a pointer to the variable that receives
  932. a context structure initialized for the opened device information element.
  933. Return Value:
  934. If the function succeeds, the return value is TRUE.
  935. If the function fails, the return value is FALSE. To get extended error
  936. information, call GetLastError.
  937. Remarks:
  938. If this device instance is being added to a set that has an associated class,
  939. then the device class must be the same, or the call will fail, and GetLastError
  940. will return ERROR_CLASS_MISMATCH.
  941. If the new device information element was successfully opened, but the
  942. user-supplied DeviceInfoData buffer is invalid, this API will return FALSE,
  943. with GetLastError returning ERROR_INVALID_USER_BUFFER. The device information
  944. element _will_ have been added as a new member of the set, however.
  945. Note that since new device information elements are always added at the end
  946. of the existing list, the enumeration ordering is preserved, thus we don't
  947. need to invalidate our enumeration hint.
  948. --*/
  949. {
  950. PDEVICE_INFO_SET pDeviceInfoSet;
  951. DWORD Err;
  952. PDEVINFO_ELEM DevInfoElem;
  953. PDRIVER_LIST_OBJECT CurDrvListObject;
  954. BOOL AlreadyPresent;
  955. if(OpenFlags & ~(DIOD_INHERIT_CLASSDRVS | DIOD_CANCEL_REMOVE)) {
  956. SetLastError(ERROR_INVALID_FLAGS);
  957. return FALSE;
  958. }
  959. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  960. SetLastError(ERROR_INVALID_HANDLE);
  961. return FALSE;
  962. }
  963. Err = NO_ERROR;
  964. try {
  965. Err = pSetupOpenAndAddNewDevInfoElem(pDeviceInfoSet,
  966. DeviceInstanceId,
  967. TRUE,
  968. NULL,
  969. hwndParent,
  970. &DevInfoElem,
  971. TRUE,
  972. &AlreadyPresent,
  973. FALSE,
  974. ((OpenFlags & DIOD_CANCEL_REMOVE)
  975. ? CM_LOCATE_DEVNODE_CANCELREMOVE : 0),
  976. pDeviceInfoSet
  977. );
  978. if(Err != NO_ERROR) {
  979. goto clean0;
  980. }
  981. //
  982. // If the caller wants the newly-opened devinfo element to inherit the global
  983. // class driver list, do that now.
  984. //
  985. if(OpenFlags & DIOD_INHERIT_CLASSDRVS) {
  986. //
  987. // If this devinfo element already existed, then it may already have a class
  988. // driver list. Destroy that list before inheriting from the global class
  989. // driver list.
  990. //
  991. if(AlreadyPresent) {
  992. //
  993. // If the selected driver is a class driver, then reset the selection.
  994. //
  995. if(DevInfoElem->SelectedDriverType == SPDIT_CLASSDRIVER) {
  996. DevInfoElem->SelectedDriverType = SPDIT_NODRIVER;
  997. DevInfoElem->SelectedDriver = NULL;
  998. }
  999. //
  1000. // Destroy the existing class driver list for this device.
  1001. //
  1002. DereferenceClassDriverList(pDeviceInfoSet, DevInfoElem->ClassDriverHead);
  1003. DevInfoElem->ClassDriverCount = 0;
  1004. DevInfoElem->ClassDriverHead = DevInfoElem->ClassDriverTail = NULL;
  1005. DevInfoElem->InstallParamBlock.Flags &= ~(DI_DIDCLASS | DI_MULTMFGS);
  1006. DevInfoElem->InstallParamBlock.FlagsEx &= ~DI_FLAGSEX_DIDINFOLIST;
  1007. }
  1008. if(pDeviceInfoSet->ClassDriverHead) {
  1009. //
  1010. // Find the global class driver list in the devinfo set's list of driver lists.
  1011. //
  1012. CurDrvListObject = GetAssociatedDriverListObject(pDeviceInfoSet->ClassDrvListObjectList,
  1013. pDeviceInfoSet->ClassDriverHead,
  1014. NULL
  1015. );
  1016. MYASSERT(CurDrvListObject && (CurDrvListObject->RefCount > 0));
  1017. //
  1018. // We found the driver list object, now increment its refcount, and do the
  1019. // inheritance.
  1020. //
  1021. CurDrvListObject->RefCount++;
  1022. DevInfoElem->ClassDriverCount = pDeviceInfoSet->ClassDriverCount;
  1023. DevInfoElem->ClassDriverHead = pDeviceInfoSet->ClassDriverHead;
  1024. DevInfoElem->ClassDriverTail = pDeviceInfoSet->ClassDriverTail;
  1025. if(pDeviceInfoSet->SelectedClassDriver) {
  1026. DevInfoElem->SelectedDriver = pDeviceInfoSet->SelectedClassDriver;
  1027. DevInfoElem->SelectedDriverType = SPDIT_CLASSDRIVER;
  1028. }
  1029. DevInfoElem->InstallParamBlock.Flags |= CurDrvListObject->ListCreationFlags;
  1030. DevInfoElem->InstallParamBlock.FlagsEx |= CurDrvListObject->ListCreationFlagsEx;
  1031. DevInfoElem->InstallParamBlock.DriverPath = CurDrvListObject->ListCreationDriverPath;
  1032. }
  1033. }
  1034. clean0: ; // nothing to do
  1035. } except(EXCEPTION_EXECUTE_HANDLER) {
  1036. Err = ERROR_INVALID_PARAMETER;
  1037. }
  1038. if((Err == NO_ERROR) && DeviceInfoData) {
  1039. //
  1040. // The user supplied a buffer to receive a SP_DEVINFO_DATA
  1041. // structure, so fill that in now.
  1042. //
  1043. try {
  1044. if(!(DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
  1045. DevInfoElem,
  1046. DeviceInfoData))) {
  1047. Err = ERROR_INVALID_USER_BUFFER;
  1048. }
  1049. } except(EXCEPTION_EXECUTE_HANDLER) {
  1050. Err = ERROR_INVALID_USER_BUFFER;
  1051. }
  1052. }
  1053. UnlockDeviceInfoSet(pDeviceInfoSet);
  1054. SetLastError(Err);
  1055. return(Err == NO_ERROR);
  1056. }
  1057. #ifdef UNICODE
  1058. //
  1059. // ANSI version
  1060. //
  1061. HDEVINFO
  1062. WINAPI
  1063. SetupDiGetClassDevsA(
  1064. IN CONST GUID *ClassGuid, OPTIONAL
  1065. IN PCSTR Enumerator, OPTIONAL
  1066. IN HWND hwndParent, OPTIONAL
  1067. IN DWORD Flags
  1068. )
  1069. {
  1070. PCWSTR enumerator;
  1071. DWORD rc;
  1072. HDEVINFO h;
  1073. if(Enumerator) {
  1074. rc = pSetupCaptureAndConvertAnsiArg(Enumerator,&enumerator);
  1075. if(rc != NO_ERROR) {
  1076. SetLastError(rc);
  1077. return INVALID_HANDLE_VALUE;
  1078. }
  1079. } else {
  1080. enumerator = NULL;
  1081. }
  1082. h = SetupDiGetClassDevsExW(ClassGuid,
  1083. enumerator,
  1084. hwndParent,
  1085. Flags,
  1086. NULL,
  1087. NULL,
  1088. NULL
  1089. );
  1090. rc = GetLastError();
  1091. if(enumerator) {
  1092. MyFree(enumerator);
  1093. }
  1094. SetLastError(rc);
  1095. return h;
  1096. }
  1097. #else
  1098. //
  1099. // Unicode version
  1100. //
  1101. HDEVINFO
  1102. WINAPI
  1103. SetupDiGetClassDevsW(
  1104. IN CONST GUID *ClassGuid, OPTIONAL
  1105. IN PCWSTR Enumerator, OPTIONAL
  1106. IN HWND hwndParent, OPTIONAL
  1107. IN DWORD Flags
  1108. )
  1109. {
  1110. UNREFERENCED_PARAMETER(ClassGuid);
  1111. UNREFERENCED_PARAMETER(Enumerator);
  1112. UNREFERENCED_PARAMETER(hwndParent);
  1113. UNREFERENCED_PARAMETER(Flags);
  1114. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  1115. return(INVALID_HANDLE_VALUE);
  1116. }
  1117. #endif
  1118. HDEVINFO
  1119. WINAPI
  1120. SetupDiGetClassDevs(
  1121. IN CONST GUID *ClassGuid, OPTIONAL
  1122. IN PCTSTR Enumerator, OPTIONAL
  1123. IN HWND hwndParent, OPTIONAL
  1124. IN DWORD Flags
  1125. )
  1126. /*++
  1127. Routine Description:
  1128. See SetupDiGetClassDevsEx for details.
  1129. --*/
  1130. {
  1131. return SetupDiGetClassDevsEx(ClassGuid,
  1132. Enumerator,
  1133. hwndParent,
  1134. Flags,
  1135. NULL,
  1136. NULL,
  1137. NULL
  1138. );
  1139. }
  1140. #ifdef UNICODE
  1141. //
  1142. // ANSI version
  1143. //
  1144. HDEVINFO
  1145. WINAPI
  1146. SetupDiGetClassDevsExA(
  1147. IN CONST GUID *ClassGuid, OPTIONAL
  1148. IN PCSTR Enumerator, OPTIONAL
  1149. IN HWND hwndParent, OPTIONAL
  1150. IN DWORD Flags,
  1151. IN HDEVINFO DeviceInfoSet, OPTIONAL
  1152. IN PCSTR MachineName, OPTIONAL
  1153. IN PVOID Reserved
  1154. )
  1155. {
  1156. PCWSTR UnicodeEnumerator, UnicodeMachineName;
  1157. DWORD rc;
  1158. HDEVINFO h;
  1159. h = INVALID_HANDLE_VALUE;
  1160. if(Enumerator) {
  1161. rc = pSetupCaptureAndConvertAnsiArg(Enumerator, &UnicodeEnumerator);
  1162. if(rc != NO_ERROR) {
  1163. goto clean0;
  1164. }
  1165. } else {
  1166. UnicodeEnumerator = NULL;
  1167. }
  1168. if(MachineName) {
  1169. rc = pSetupCaptureAndConvertAnsiArg(MachineName,&UnicodeMachineName);
  1170. if(rc != NO_ERROR) {
  1171. goto clean1;
  1172. }
  1173. } else {
  1174. UnicodeMachineName = NULL;
  1175. }
  1176. h = SetupDiGetClassDevsExW(ClassGuid,
  1177. UnicodeEnumerator,
  1178. hwndParent,
  1179. Flags,
  1180. DeviceInfoSet,
  1181. UnicodeMachineName,
  1182. Reserved
  1183. );
  1184. rc = GetLastError();
  1185. if(UnicodeMachineName) {
  1186. MyFree(UnicodeMachineName);
  1187. }
  1188. clean1:
  1189. if(UnicodeEnumerator) {
  1190. MyFree(UnicodeEnumerator);
  1191. }
  1192. clean0:
  1193. SetLastError(rc);
  1194. return h;
  1195. }
  1196. #else
  1197. //
  1198. // Unicode version
  1199. //
  1200. HDEVINFO
  1201. WINAPI
  1202. SetupDiGetClassDevsExW(
  1203. IN CONST GUID *ClassGuid, OPTIONAL
  1204. IN PCWSTR Enumerator, OPTIONAL
  1205. IN HWND hwndParent, OPTIONAL
  1206. IN DWORD Flags,
  1207. IN HDEVINFO DeviceInfoSet, OPTIONAL
  1208. IN PCWSTR MachineName, OPTIONAL
  1209. IN PVOID Reserved
  1210. )
  1211. {
  1212. UNREFERENCED_PARAMETER(ClassGuid);
  1213. UNREFERENCED_PARAMETER(Enumerator);
  1214. UNREFERENCED_PARAMETER(hwndParent);
  1215. UNREFERENCED_PARAMETER(Flags);
  1216. UNREFERENCED_PARAMETER(DeviceInfoSet);
  1217. UNREFERENCED_PARAMETER(MachineName);
  1218. UNREFERENCED_PARAMETER(Reserved);
  1219. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  1220. return(INVALID_HANDLE_VALUE);
  1221. }
  1222. #endif
  1223. HDEVINFO
  1224. WINAPI
  1225. SetupDiGetClassDevsEx(
  1226. IN CONST GUID *ClassGuid, OPTIONAL
  1227. IN PCTSTR Enumerator, OPTIONAL
  1228. IN HWND hwndParent, OPTIONAL
  1229. IN DWORD Flags,
  1230. IN HDEVINFO DeviceInfoSet, OPTIONAL
  1231. IN PCTSTR MachineName, OPTIONAL
  1232. IN PVOID Reserved
  1233. )
  1234. /*++
  1235. Routine Description:
  1236. This routine returns a device information set containing all installed
  1237. devices of the specified class.
  1238. Arguments:
  1239. ClassGuid - Optionally, supplies the address of the class GUID to use
  1240. when creating the list of devices. If the DIGCF_ALLCLASSES flag is
  1241. set, then this parameter is ignored, and the resulting list will
  1242. contain all classes of devices (i.e., every installed device).
  1243. If the DIGCF_DEVICEINTERFACE flag _is not_ set, then this class GUID
  1244. represents a setup class.
  1245. If the DIGCF_DEVICEINTERFACE flag _is_ set, then this class GUID
  1246. represents an interface class.
  1247. Enumerator - Optional parameter that filters the members of the returned
  1248. device information set based on their enumerator (i.e., provider).
  1249. If the DIGCF_DEVICEINTERFACE flag _is not_ set in the Flags parameter,
  1250. then this string represents the name of the key under the Enum branch
  1251. containing devices instances for which information is to be retrieved.
  1252. If this parameter is not specified, then device information will be
  1253. retrieved for all device instances in the entire Enum tree.
  1254. If the DIGCF_DEVICEINTERFACE flag _is_ set, then this string represents
  1255. the PnP name of a particular device for which interfaces are to be
  1256. retrieved. In this case, the resulting device information set will
  1257. consist of a single device information element--the device whose name
  1258. was specified as the enumerator. The interface devices provided by this
  1259. PnP device can then be enumerated via SetupDiEnumInterfaceDevice.
  1260. hwndParent - Optionally, supplies the handle of the top-level window to be
  1261. used for any UI relating to the members of this set.
  1262. Flags - Supplies control options used in building the device information set.
  1263. May be a combination of the following values:
  1264. DIGCF_PRESENT - Return only devices that are currently present.
  1265. DIGCF_ALLCLASSES - Return a list of installed devices for all classes.
  1266. If set, this flag will cause ClassGuid to be ignored.
  1267. DIGCF_PROFILE - Return only devices that are a part of the current
  1268. hardware profile.
  1269. DIGCF_DEVICEINTERFACE - Return a list of all devices that expose interfaces
  1270. of the class specified by ClassGUID (NOTE: in this
  1271. context, ClassGuid is an interface class, _not_ a
  1272. setup class). The interface devices exposed by the
  1273. members of the resulting set may be enumerated via
  1274. SetupDiEnumInterfaceDevice.
  1275. DIGCF_DEFAULT - When used with DIGCF_DEVICEINTERFACE, this flag
  1276. results in a list that contains only one device
  1277. information element. Enumerating that device will
  1278. return exactly one interface device--the one that has
  1279. been marked as the system default interface device for
  1280. that particular interface class. If there is no default
  1281. interface device for the specified class, the API will
  1282. fail, and GetLastError will return
  1283. ERROR_NO_DEFAULT_DEVICE_INTERFACE.
  1284. DeviceInfoSet - Optionally, supplies the handle of an existing device
  1285. information set into which these new device information elements (and,
  1286. if DIGCF_DEVICEINTERFACE is specified, device interfaces) will be added.
  1287. If this parameter is specified, then this same HDEVINFO will be returned
  1288. upon success, with the retrieved device information/device interface
  1289. elements added. If this parameter is not specified, then a new device
  1290. information set will be created, and its handle returned.
  1291. NOTE: if this parameter is specified, then the associated class of this
  1292. device information set (if any) must match the ClassGuid specified, if
  1293. that class GUID is a setup class (i.e., the DIGCF_DEVICEINTERFACE flag
  1294. isn't set). If the DIGCF_DEVICEINTERFACE flag is set, then the device
  1295. interfaces retrieved will be filtered based on whether or not their
  1296. corresponding device's setup class matches that of the device
  1297. information set. This trick can be used, for example, to retrieve a
  1298. list of device interfaces of a particular interface class, but only if
  1299. those interfaces are exposed by devices of a particular setup class.
  1300. E.g.,
  1301. 1. Create a device information set (via SetupDiCreateDeviceInfoList)
  1302. whose associated setup class is "Volume".
  1303. 2. Call SetupDiGetClassDevsEx to retrieve a list of all device
  1304. interfaces of interface class "mounted device", passing in the
  1305. HDEVINFO retrieved in step 1.
  1306. The result of the above steps would be a device information set
  1307. containing all device interfaces of (interface) class "mounted device"
  1308. that are exposed by devnodes of (setup) class "Volume".
  1309. Note that retrieval of new device information elements into an existing
  1310. HDEVINFO set doesn't invalidate our devinfo enumeration hint, since new
  1311. devinfo elements are always added onto the end of the list.
  1312. MachineName - Optionally, supplies the name of a remote machine for which a
  1313. device information set is to be retrieved. If this parameter is NULL,
  1314. then the local machine is used.
  1315. Reserved - Reserved for future use--must be NULL.
  1316. Return Value:
  1317. If the function succeeds, the return value is a handle to a device
  1318. information set containing all installed devices matching the specified
  1319. parameters.
  1320. If the function fails, the return value is INVALID_HANDLE_VALUE. To get
  1321. extended error information, call GetLastError.
  1322. --*/
  1323. {
  1324. HDEVINFO hDevInfo;
  1325. PDEVICE_INFO_SET pDeviceInfoSet;
  1326. PDEVINFO_ELEM DevInfoElem;
  1327. DWORD Err;
  1328. CONFIGRET cr;
  1329. PTCHAR DevIdBuffer;
  1330. ULONG DevIdBufferLen, CSConfigFlags;
  1331. PTSTR CurDevId, DeviceInstanceToOpen;
  1332. HKEY hKeyDevClassRoot, hKeyCurDevClass;
  1333. TCHAR InterfaceGuidString[GUID_STRING_LEN];
  1334. BOOL GetInterfaceList, GetNextInterfaceClass;
  1335. DWORD InterfaceClassKeyIndex;
  1336. FILETIME LastWriteTime;
  1337. GUID GuidBuffer;
  1338. TCHAR DeviceInstanceId[MAX_DEVICE_ID_LEN];
  1339. DWORD RegDataType, DataBufferSize;
  1340. BOOL DevInfoAlreadyPresent, IsActive, IsDefault;
  1341. SP_DEVINFO_DATA DeviceInfoData;
  1342. CONST GUID * ExistingClassGuid;
  1343. //
  1344. // Make sure the user didn't pass us anything in the Reserved parameter.
  1345. //
  1346. if(Reserved) {
  1347. SetLastError(ERROR_INVALID_PARAMETER);
  1348. return INVALID_HANDLE_VALUE;
  1349. }
  1350. //
  1351. // Unless the caller wants a list of all classes, they'd better supply a class GUID.
  1352. //
  1353. if(!(Flags & DIGCF_ALLCLASSES) && !ClassGuid) {
  1354. SetLastError(ERROR_INVALID_PARAMETER);
  1355. return INVALID_HANDLE_VALUE;
  1356. }
  1357. //
  1358. // DIGCF_DEFAULT can only be used in conjunction with DIGCF_DEVICEINTERFACE.
  1359. //
  1360. if((Flags & (DIGCF_DEFAULT | DIGCF_DEVICEINTERFACE)) == DIGCF_DEFAULT) {
  1361. SetLastError(ERROR_INVALID_FLAGS);
  1362. return INVALID_HANDLE_VALUE;
  1363. }
  1364. if(!DeviceInfoSet || (DeviceInfoSet == INVALID_HANDLE_VALUE)) {
  1365. //
  1366. // The caller didn't supply us with a device information set in which
  1367. // to add our newly-retrieved elements, so we need to create our own.
  1368. //
  1369. if((hDevInfo = SetupDiCreateDeviceInfoListEx((Flags & (DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE))
  1370. ? NULL
  1371. : ClassGuid,
  1372. hwndParent,
  1373. MachineName,
  1374. NULL)) == INVALID_HANDLE_VALUE) {
  1375. //
  1376. // Last error already set.
  1377. //
  1378. MYASSERT(GetLastError());
  1379. return INVALID_HANDLE_VALUE;
  1380. }
  1381. if(!(pDeviceInfoSet = AccessDeviceInfoSet(hDevInfo))) {
  1382. //
  1383. // this should not happen
  1384. //
  1385. MYASSERT(pDeviceInfoSet);
  1386. SetLastError(ERROR_INVALID_HANDLE);
  1387. return INVALID_HANDLE_VALUE;
  1388. }
  1389. } else {
  1390. //
  1391. // The caller wants us to use an existing device information set. Make
  1392. // a copy of it, and work with that one, so that if something fails, we
  1393. // haven't messed up the original one.
  1394. //
  1395. // NOTE: DO NOT do anything with the DeviceInfoSet after this point,
  1396. // as doing so will get the original out-of-sync with the current copy
  1397. // we're working with.
  1398. //
  1399. hDevInfo = NULL;
  1400. pDeviceInfoSet = CloneDeviceInfoSet(DeviceInfoSet);
  1401. if(!pDeviceInfoSet) {
  1402. SetLastError(ERROR_INVALID_PARAMETER);
  1403. return INVALID_HANDLE_VALUE;
  1404. }
  1405. }
  1406. Err = NO_ERROR;
  1407. DevIdBuffer = NULL;
  1408. hKeyDevClassRoot = hKeyCurDevClass = INVALID_HANDLE_VALUE;
  1409. try {
  1410. //
  1411. // If the caller supplied us with a previously-existing devinfo set in
  1412. // which to add new elements, we need to make sure that the setup class
  1413. // GUID associated with this devinfo set (if any) matches the setup
  1414. // class GUID that the caller supplied.
  1415. //
  1416. if(hDevInfo) {
  1417. //
  1418. // We always want the ExistingClassGuid pointer to be NULL when we
  1419. // haven't been passed in a previously-existing device information
  1420. // set.
  1421. //
  1422. ExistingClassGuid = NULL;
  1423. } else {
  1424. if(pDeviceInfoSet->HasClassGuid) {
  1425. //
  1426. // Remember the devinfo set's associated setup class GUID, to
  1427. // be used later in filtering device interfaces based on the
  1428. // setup class of their underlying devnode.
  1429. //
  1430. ExistingClassGuid = &(pDeviceInfoSet->ClassGuid);
  1431. if(ClassGuid && !(Flags & (DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE))) {
  1432. if(!IsEqualGUID(ExistingClassGuid, ClassGuid)) {
  1433. Err = ERROR_CLASS_MISMATCH;
  1434. goto clean0;
  1435. }
  1436. }
  1437. } else {
  1438. //
  1439. // The caller-supplied devinfo set had no associated setup
  1440. // class. Remember that fact, so that we won't try to filter
  1441. // device interfaces based on the underlying devices' setup
  1442. // class.
  1443. //
  1444. ExistingClassGuid = NULL;
  1445. }
  1446. }
  1447. if(GetInterfaceList = (Flags & DIGCF_DEVICEINTERFACE)) { // yes, we want an assignment here.
  1448. //
  1449. // Open the root of the DeviceClasses registry branch
  1450. //
  1451. hKeyDevClassRoot = SetupDiOpenClassRegKeyEx(NULL,
  1452. KEY_READ,
  1453. DIOCR_INTERFACE,
  1454. MachineName,
  1455. NULL
  1456. );
  1457. if(hKeyDevClassRoot == INVALID_HANDLE_VALUE) {
  1458. Err = GetLastError();
  1459. goto clean0;
  1460. }
  1461. if(Flags & DIGCF_ALLCLASSES) {
  1462. InterfaceClassKeyIndex = 0;
  1463. ClassGuid = &GuidBuffer;
  1464. }
  1465. if(Flags & DIGCF_PRESENT) {
  1466. //
  1467. // Since we're only going to be retrieving a list of device
  1468. // interfaces that are currently 'active', we can set the
  1469. // 'IsActive' flag to always be TRUE.
  1470. //
  1471. IsActive = TRUE;
  1472. }
  1473. }
  1474. //
  1475. // As an optimization, start out with a 16K (character) buffer, in the hopes of avoiding
  1476. // two scans through the hardware tree (once to get the size, and again to get the data).
  1477. //
  1478. DevIdBufferLen = 16384;
  1479. do {
  1480. if(GetInterfaceList) {
  1481. if(Flags & DIGCF_ALLCLASSES) {
  1482. //
  1483. // We have to enumerate through all interface device classes, and retrieve
  1484. // a list of device interfaces for each one.
  1485. //
  1486. DataBufferSize = SIZECHARS(InterfaceGuidString);
  1487. switch(RegEnumKeyEx(hKeyDevClassRoot,
  1488. InterfaceClassKeyIndex,
  1489. InterfaceGuidString,
  1490. &DataBufferSize,
  1491. NULL,
  1492. NULL,
  1493. NULL,
  1494. &LastWriteTime)) {
  1495. case ERROR_SUCCESS :
  1496. GetNextInterfaceClass = TRUE;
  1497. InterfaceClassKeyIndex++;
  1498. break;
  1499. case ERROR_NO_MORE_ITEMS :
  1500. //
  1501. // We've processed all of the interface class GUIDs--we're done.
  1502. //
  1503. GetNextInterfaceClass = FALSE;
  1504. continue;
  1505. default :
  1506. //
  1507. // Some other error occurred. Skip this subkey, and continue
  1508. // with the next one.
  1509. //
  1510. GetNextInterfaceClass = TRUE;
  1511. InterfaceClassKeyIndex++;
  1512. continue;
  1513. }
  1514. //
  1515. // Convert the GUID string retrieved above into its binary form, for use
  1516. // below.
  1517. //
  1518. if(pSetupGuidFromString(InterfaceGuidString, &GuidBuffer) != NO_ERROR) {
  1519. //
  1520. // The subkey we enumerated is not a valid GUID string--skip this
  1521. // subkey, and continue on with the next one.
  1522. //
  1523. continue;
  1524. }
  1525. } else {
  1526. //
  1527. // We're just retrieving devices for a single interface class (which the
  1528. // caller specified). All we need to do is initialize the GUID string
  1529. // buffer with the textual form of the GUID.
  1530. //
  1531. pSetupStringFromGuid(ClassGuid,
  1532. InterfaceGuidString,
  1533. SIZECHARS(InterfaceGuidString)
  1534. );
  1535. //
  1536. // We only need to go through this list once.
  1537. //
  1538. GetNextInterfaceClass = FALSE;
  1539. }
  1540. //
  1541. // We'll be using the same character buffer to store each device instance ID
  1542. // we're opening below.
  1543. //
  1544. DeviceInstanceToOpen = DeviceInstanceId;
  1545. } else {
  1546. //
  1547. // We're not retrieving a list of interface devices, so we'll never go through
  1548. // this loop more than once.
  1549. //
  1550. GetNextInterfaceClass = FALSE;
  1551. }
  1552. //
  1553. // Retrieve a list of device names.
  1554. //
  1555. while(TRUE) {
  1556. if(!DevIdBuffer) {
  1557. if(!(DevIdBuffer = MyMalloc(DevIdBufferLen * sizeof(TCHAR)))) {
  1558. Err = ERROR_NOT_ENOUGH_MEMORY;
  1559. goto clean0;
  1560. }
  1561. }
  1562. if(GetInterfaceList) {
  1563. cr = CM_Get_Device_Interface_List_Ex((LPGUID)ClassGuid,
  1564. (DEVINSTID)Enumerator,
  1565. DevIdBuffer,
  1566. DevIdBufferLen,
  1567. (Flags & DIGCF_PRESENT)
  1568. ? CM_GET_DEVICE_INTERFACE_LIST_PRESENT
  1569. : CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES,
  1570. pDeviceInfoSet->hMachine
  1571. );
  1572. } else {
  1573. cr = CM_Get_Device_ID_List_Ex(Enumerator,
  1574. DevIdBuffer,
  1575. DevIdBufferLen,
  1576. Enumerator ? CM_GETIDLIST_FILTER_ENUMERATOR
  1577. : CM_GETIDLIST_FILTER_NONE,
  1578. pDeviceInfoSet->hMachine
  1579. );
  1580. }
  1581. if(cr == CR_SUCCESS) {
  1582. //
  1583. // Device list successfully retrieved!
  1584. //
  1585. break;
  1586. } else {
  1587. //
  1588. // Free the current buffer before determining what error occurred.
  1589. //
  1590. MyFree(DevIdBuffer);
  1591. DevIdBuffer = NULL;
  1592. if(cr == CR_BUFFER_SMALL) {
  1593. //
  1594. // OK, so our buffer wasn't big enough--just how big
  1595. // does it need to be?
  1596. //
  1597. if(GetInterfaceList) {
  1598. if(CM_Get_Device_Interface_List_Size_Ex(&DevIdBufferLen,
  1599. (LPGUID)ClassGuid,
  1600. (DEVINSTID)Enumerator,
  1601. (Flags & DIGCF_PRESENT)
  1602. ? CM_GET_DEVICE_INTERFACE_LIST_PRESENT
  1603. : CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES,
  1604. pDeviceInfoSet->hMachine) != CR_SUCCESS) {
  1605. //
  1606. // Couldn't retrieve the list size--this should
  1607. // never happen.
  1608. //
  1609. Err = ERROR_INVALID_DATA;
  1610. goto clean0;
  1611. }
  1612. } else {
  1613. if(CM_Get_Device_ID_List_Size_Ex(&DevIdBufferLen,
  1614. Enumerator,
  1615. Enumerator ? CM_GETIDLIST_FILTER_ENUMERATOR
  1616. : CM_GETIDLIST_FILTER_NONE,
  1617. pDeviceInfoSet->hMachine) != CR_SUCCESS) {
  1618. //
  1619. // Couldn't retrieve the list size--this should
  1620. // never happen.
  1621. //
  1622. Err = ERROR_INVALID_DATA;
  1623. goto clean0;
  1624. }
  1625. }
  1626. } else {
  1627. //
  1628. // An error occurred, and it wasn't because we supplied
  1629. // too small a buffer.
  1630. //
  1631. Err = ERROR_INVALID_DATA;
  1632. goto clean0;
  1633. }
  1634. }
  1635. }
  1636. //
  1637. // We have now retrieved a list of all the specified devices. If
  1638. // these are device interfaces, we need to open the key for this
  1639. // interface class underneath the DeviceClasses key.
  1640. //
  1641. if(GetInterfaceList) {
  1642. if(RegOpenKeyEx(hKeyDevClassRoot,
  1643. InterfaceGuidString,
  1644. 0,
  1645. KEY_READ,
  1646. &hKeyCurDevClass) != ERROR_SUCCESS) {
  1647. //
  1648. // Make sure hKeyCurDevClass is still set to
  1649. // INVALID_HANDLE_VALUE, so that we'll know not to close it.
  1650. //
  1651. hKeyCurDevClass = INVALID_HANDLE_VALUE;
  1652. //
  1653. // Skip this interface class.
  1654. //
  1655. continue;
  1656. }
  1657. }
  1658. //
  1659. // Now create device information elements from the members of this
  1660. // list.
  1661. //
  1662. for(CurDevId = DevIdBuffer;
  1663. *CurDevId;
  1664. CurDevId += lstrlen(CurDevId) + 1) {
  1665. //
  1666. // If this is a device interface, we must retrieve the
  1667. // associated device instance name.
  1668. //
  1669. if(GetInterfaceList) {
  1670. if(NO_ERROR != pSetupGetDevInstNameAndStatusForInterfaceDevice(
  1671. hKeyCurDevClass,
  1672. CurDevId,
  1673. DeviceInstanceId,
  1674. SIZECHARS(DeviceInstanceId),
  1675. (Flags & DIGCF_PRESENT) ? NULL : &IsActive,
  1676. &IsDefault)) {
  1677. //
  1678. // Couldn't retrieve the name of the owning device
  1679. // instance--skip this device interface.
  1680. //
  1681. continue;
  1682. }
  1683. if ((Flags & DIGCF_DEFAULT) && !IsDefault) {
  1684. //
  1685. // The caller only wants the default device interface.
  1686. // Since CM_Get_Device_Interface_List places the default
  1687. // device interface first in the list (if there is one),
  1688. // and we stop searching the list when we find it, we
  1689. // know that if we get here, there is no default device
  1690. // interface for this interface class.
  1691. //
  1692. Err = ERROR_NO_DEFAULT_DEVICE_INTERFACE;
  1693. goto clean0;
  1694. }
  1695. } else {
  1696. DeviceInstanceToOpen = CurDevId;
  1697. }
  1698. if(Flags & DIGCF_PROFILE) {
  1699. //
  1700. // Verify that this device instance is part of the current
  1701. // hardware profile.
  1702. //
  1703. if(CM_Get_HW_Prof_Flags_Ex(DeviceInstanceToOpen,
  1704. 0,
  1705. &CSConfigFlags,
  1706. 0,
  1707. pDeviceInfoSet->hMachine) == CR_SUCCESS) {
  1708. if(CSConfigFlags & CSCONFIGFLAG_DO_NOT_CREATE) {
  1709. continue;
  1710. }
  1711. }
  1712. }
  1713. //
  1714. // Note the last parameter in the following call to
  1715. // pSetupOpenAndAddNewDevInfoElem--in the case where we're
  1716. // adding to an existing caller-supplied HDEVINFO set (i.e.,
  1717. // hDevInfo is NULL), we cast the HDEVINFO to a DEVICE_INFO_SET
  1718. // pointer, since that's what ends up getting stored in the
  1719. // ContainingDeviceInfoSet field of a devinfo element structure.
  1720. // That field is used for quick validation that a caller-
  1721. // supplied device information element is valid.
  1722. //
  1723. // If we ever decide to change the internal implementation of
  1724. // how an HDEVINFO translates into its underlying
  1725. // DEVICE_INFO_SET, then we'll need to update the code below
  1726. // accordingly. (See also the comments under
  1727. // AccessDeviceInfoSet, CloneDeviceInfoSet, and
  1728. // RollbackDeviceInfoSet.)
  1729. //
  1730. Err = pSetupOpenAndAddNewDevInfoElem(pDeviceInfoSet,
  1731. DeviceInstanceToOpen,
  1732. !(Flags & DIGCF_PRESENT),
  1733. ((Flags & (DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE))
  1734. ? ExistingClassGuid
  1735. : ClassGuid),
  1736. hwndParent,
  1737. &DevInfoElem,
  1738. (GetInterfaceList || !hDevInfo),
  1739. &DevInfoAlreadyPresent,
  1740. FALSE,
  1741. 0,
  1742. (hDevInfo ? pDeviceInfoSet : (PDEVICE_INFO_SET)DeviceInfoSet)
  1743. );
  1744. if(Err != NO_ERROR) {
  1745. if(Err == ERROR_NOT_ENOUGH_MEMORY) {
  1746. goto clean0;
  1747. }
  1748. Err = NO_ERROR;
  1749. continue;
  1750. }
  1751. if(GetInterfaceList) {
  1752. //
  1753. // Now that we've successfully opened up the device instance that 'owns'
  1754. // this device interface, add a new interface device node onto this
  1755. // devinfo element's list.
  1756. //
  1757. if(NO_ERROR != (Err = pSetupAddInterfaceDeviceToDevInfoElem(pDeviceInfoSet,
  1758. DevInfoElem,
  1759. ClassGuid,
  1760. CurDevId,
  1761. IsActive,
  1762. IsDefault,
  1763. !hDevInfo,
  1764. FALSE,
  1765. NULL))) {
  1766. //
  1767. // The only error we should be getting back from this routine is
  1768. // out-of-memory, which is always a fatal error.
  1769. //
  1770. goto clean0;
  1771. }
  1772. if ((Flags & DIGCF_DEFAULT) && IsDefault) {
  1773. //
  1774. // The caller only wants the default device interface,
  1775. // and this is it.
  1776. //
  1777. if ((Flags & DIGCF_PRESENT) && !IsActive) {
  1778. //
  1779. // The caller doesn't want to know about a
  1780. // non-present default device interface.
  1781. //
  1782. Err = ERROR_NO_DEFAULT_DEVICE_INTERFACE;
  1783. }
  1784. RegCloseKey(hKeyCurDevClass);
  1785. hKeyCurDevClass = INVALID_HANDLE_VALUE;
  1786. goto clean0;
  1787. }
  1788. }
  1789. }
  1790. //
  1791. // If we're working with interface devices, we need to close the interface
  1792. // class key we opened above.
  1793. //
  1794. if(GetInterfaceList) {
  1795. RegCloseKey(hKeyCurDevClass);
  1796. hKeyCurDevClass = INVALID_HANDLE_VALUE;
  1797. }
  1798. } while(GetNextInterfaceClass);
  1799. clean0:
  1800. ; // Nothing to do.
  1801. } except(EXCEPTION_EXECUTE_HANDLER) {
  1802. Err = ERROR_INVALID_PARAMETER;
  1803. if(hKeyCurDevClass != INVALID_HANDLE_VALUE) {
  1804. RegCloseKey(hKeyCurDevClass);
  1805. }
  1806. //
  1807. // Access the following variables, so the compiler will respect
  1808. // the statement ordering in the try clause.
  1809. //
  1810. DevIdBuffer = DevIdBuffer;
  1811. hKeyDevClassRoot = hKeyDevClassRoot;
  1812. }
  1813. if(DevIdBuffer) {
  1814. MyFree(DevIdBuffer);
  1815. }
  1816. if(hKeyDevClassRoot != INVALID_HANDLE_VALUE) {
  1817. RegCloseKey(hKeyDevClassRoot);
  1818. }
  1819. if(Err != NO_ERROR) {
  1820. if(hDevInfo) {
  1821. DestroyDeviceInfoSet(hDevInfo, pDeviceInfoSet);
  1822. } else {
  1823. if(!(pDeviceInfoSet = RollbackDeviceInfoSet(DeviceInfoSet, pDeviceInfoSet))) {
  1824. MYASSERT(pDeviceInfoSet);
  1825. } else {
  1826. UnlockDeviceInfoSet(pDeviceInfoSet);
  1827. }
  1828. }
  1829. SetLastError(Err);
  1830. hDevInfo = INVALID_HANDLE_VALUE;
  1831. } else {
  1832. if(!hDevInfo) {
  1833. //
  1834. // We retrieved additional elements into an existing device
  1835. // information set. Replace the existing device information set
  1836. // with the new one (i.e., into the same handle), and return the
  1837. // same HDEVINFO handle that the caller passed in as the
  1838. // DeviceInfoSet parameter.
  1839. //
  1840. pDeviceInfoSet = CommitDeviceInfoSet(DeviceInfoSet, pDeviceInfoSet);
  1841. MYASSERT(pDeviceInfoSet);
  1842. //
  1843. // Set hDevInfo to be the same as the DeviceInfoSet handle we were
  1844. // passed in, so that we can return it to the caller.
  1845. //
  1846. hDevInfo = DeviceInfoSet;
  1847. MYASSERT(hDevInfo);
  1848. }
  1849. if (pDeviceInfoSet) {
  1850. UnlockDeviceInfoSet(pDeviceInfoSet);
  1851. }
  1852. MYASSERT(hDevInfo != INVALID_HANDLE_VALUE);
  1853. }
  1854. return hDevInfo;
  1855. }
  1856. BOOL
  1857. WINAPI
  1858. SetupDiSetDeviceInterfaceDefault(
  1859. IN HDEVINFO DeviceInfoSet,
  1860. IN OUT PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
  1861. IN DWORD Flags,
  1862. IN PVOID Reserved
  1863. )
  1864. /*++
  1865. Routine Description:
  1866. This routine sets the specified device interface as the default device
  1867. interface for its class.
  1868. Arguments:
  1869. DeviceInfoSet - Points to the device information set containing the device
  1870. interface for which to set as the default device interface. This handle
  1871. is typically returned by SetupDiGetClassDevs.
  1872. DeviceInterfaceData - Points to a structure that identifies the device
  1873. interface within the device information set. This pointer is typically
  1874. returned by SetupDiEnumDeviceInterfaces. If successful, this routine
  1875. will update the information contained in this structure.
  1876. Flags - Not used, must be zero.
  1877. Reserved - Reserved for future use, must be NULL.
  1878. Return Value:
  1879. If the function succeeds, the return value is TRUE.
  1880. If the function fails, the return value is FALSE. To get extended error
  1881. information, call GetLastError.
  1882. Remarks:
  1883. The caller must have the appropriate permission to set the default device
  1884. interface.
  1885. --*/
  1886. {
  1887. DWORD Err;
  1888. PDEVICE_INFO_SET pDeviceInfoSet;
  1889. PDEVINFO_ELEM DevInfoElem;
  1890. PINTERFACE_DEVICE_NODE InterfaceDeviceNode;
  1891. PCTSTR MachineName, InterfaceDeviceName;
  1892. HKEY hKeyInterfaceClass = INVALID_HANDLE_VALUE;
  1893. BOOL IsActive, IsDefault;
  1894. //
  1895. // Make sure the user didn't pass us anything in the Reserved parameter.
  1896. //
  1897. if(Reserved) {
  1898. SetLastError(ERROR_INVALID_PARAMETER);
  1899. return FALSE;
  1900. }
  1901. if(Flags & ~(0x0)) {
  1902. SetLastError(ERROR_INVALID_FLAGS);
  1903. return FALSE;
  1904. }
  1905. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  1906. SetLastError(ERROR_INVALID_HANDLE);
  1907. return FALSE;
  1908. }
  1909. Err = NO_ERROR;
  1910. try {
  1911. //
  1912. // First, find the devinfo element that owns this interface device (for validation).
  1913. //
  1914. if(!(DevInfoElem = FindDevInfoElemForInterfaceDevice(pDeviceInfoSet, DeviceInterfaceData))) {
  1915. Err = ERROR_INVALID_PARAMETER;
  1916. goto clean0;
  1917. }
  1918. //
  1919. // Retrieve the name of the machine associated with this DeviceInfoSet.
  1920. //
  1921. if(pDeviceInfoSet->hMachine) {
  1922. MYASSERT(pDeviceInfoSet->MachineName != -1);
  1923. MachineName = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  1924. pDeviceInfoSet->MachineName);
  1925. } else {
  1926. MachineName = NULL;
  1927. }
  1928. //
  1929. // The Reserved field contains a pointer to the underlying interface device node.
  1930. //
  1931. InterfaceDeviceNode = (PINTERFACE_DEVICE_NODE)(DeviceInterfaceData->Reserved);
  1932. //
  1933. // Retrieve the device path (symbolic link name) for this interface device.
  1934. //
  1935. InterfaceDeviceName = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  1936. InterfaceDeviceNode->SymLinkName);
  1937. //
  1938. // Open this interface class key under the DeviceClasses registry branch.
  1939. //
  1940. hKeyInterfaceClass = SetupDiOpenClassRegKeyEx(&DeviceInterfaceData->InterfaceClassGuid,
  1941. KEY_READ | KEY_WRITE,
  1942. DIOCR_INTERFACE,
  1943. MachineName,
  1944. NULL);
  1945. if(hKeyInterfaceClass == INVALID_HANDLE_VALUE) {
  1946. Err = GetLastError();
  1947. goto clean0;
  1948. }
  1949. //
  1950. // Get the current status of this device interface.
  1951. //
  1952. Err = pSetupGetDevInstNameAndStatusForInterfaceDevice(hKeyInterfaceClass,
  1953. InterfaceDeviceName,
  1954. NULL,
  1955. 0,
  1956. &IsActive,
  1957. &IsDefault);
  1958. if (Err != NO_ERROR) {
  1959. goto clean0;
  1960. }
  1961. //
  1962. // If this interface is already the default, then we're done.
  1963. //
  1964. if (IsDefault) {
  1965. goto clean1;
  1966. }
  1967. //
  1968. // Set the "Default" value under this interface class key to this device
  1969. // interface.
  1970. //
  1971. Err = RegSetValueEx(hKeyInterfaceClass,
  1972. pszDefault,
  1973. 0,
  1974. REG_SZ,
  1975. (PBYTE)InterfaceDeviceName,
  1976. (lstrlen(InterfaceDeviceName) + 1) * sizeof(TCHAR));
  1977. if (Err != NO_ERROR) {
  1978. goto clean0;
  1979. }
  1980. //
  1981. // This interface was successfully set as the default device interface
  1982. // for this interface class.
  1983. //
  1984. IsDefault = TRUE;
  1985. clean1:
  1986. //
  1987. // Update the flags for this interface.
  1988. //
  1989. InterfaceDeviceNode->Flags = (InterfaceDeviceNode->Flags & ~SPINT_ACTIVE) | (IsActive ? SPINT_ACTIVE : 0);
  1990. InterfaceDeviceNode->Flags = (InterfaceDeviceNode->Flags & ~SPINT_DEFAULT) | (IsDefault ? SPINT_DEFAULT : 0);
  1991. //
  1992. // Finally, update the flags in the caller-supplied buffer to indicate the new status
  1993. // of this interface device.
  1994. //
  1995. DeviceInterfaceData->Flags = InterfaceDeviceNode->Flags;
  1996. clean0:
  1997. if(hKeyInterfaceClass != INVALID_HANDLE_VALUE) {
  1998. RegCloseKey(hKeyInterfaceClass);
  1999. }
  2000. } except(EXCEPTION_EXECUTE_HANDLER) {
  2001. Err = ERROR_INVALID_PARAMETER;
  2002. }
  2003. UnlockDeviceInfoSet(pDeviceInfoSet);
  2004. SetLastError(Err);
  2005. return (Err == NO_ERROR);
  2006. }
  2007. DWORD
  2008. pSetupAddNewDeviceInfoElement(
  2009. IN PDEVICE_INFO_SET pDeviceInfoSet,
  2010. IN DEVINST DevInst,
  2011. IN CONST GUID *ClassGuid,
  2012. IN PCTSTR Description, OPTIONAL
  2013. IN HWND hwndParent, OPTIONAL
  2014. IN DWORD DiElemFlags,
  2015. IN PDEVICE_INFO_SET ContainingDeviceInfoSet,
  2016. OUT PDEVINFO_ELEM *DeviceInfoElement
  2017. )
  2018. /*++
  2019. Routine Description:
  2020. This routine creates a new device information element based on the
  2021. supplied information, and adds it to the specified device information set.
  2022. ASSUMES THAT THE CALLING ROUTINE HAS ALREADY ACQUIRED THE LOCK!
  2023. Arguments:
  2024. pDeviceInfoSet - Device information set to add this new element to.
  2025. DevInst - Supplies the device instance handle of the element to be added.
  2026. ClassGuid - Class GUID of the element to be added.
  2027. Description - Optionally, supplies the description of the element to
  2028. be added.
  2029. hwndParent - Optionally, supplies the handle to the top level window for
  2030. UI relating to this element.
  2031. DiElemFlags - Specifies flags pertaining to the device information element
  2032. being created.
  2033. ContainingDeviceInfoSet - Supplies a pointer to the device information set
  2034. structure with which this element is to be associated. This may be
  2035. different from the pDeviceInfoSet parameter if we're working against a
  2036. cloned devinfo set (i.e., to facilitate rollback).
  2037. DeviceInfoElement - Supplies the address of the variable that receives a
  2038. pointer to the newly-allocated device information element.
  2039. Return Value:
  2040. If the function succeeds, the return value is NO_ERROR, otherwise the
  2041. ERROR_* code is returned.
  2042. Remarks:
  2043. Since the new element is added onto the end of the existing list, our
  2044. enumeration hint isn't invalidated.
  2045. --*/
  2046. {
  2047. DWORD Err = NO_ERROR;
  2048. TCHAR TempString[LINE_LEN];
  2049. *DeviceInfoElement = NULL;
  2050. try {
  2051. //
  2052. // If there is a class associated with this device information set,
  2053. // verify that it is the same as that of the new element.
  2054. //
  2055. if(pDeviceInfoSet->HasClassGuid &&
  2056. !IsEqualGUID(&(pDeviceInfoSet->ClassGuid), ClassGuid)) {
  2057. Err = ERROR_CLASS_MISMATCH;
  2058. goto clean0;
  2059. }
  2060. //
  2061. // Allocate storage for the element.
  2062. //
  2063. if(!(*DeviceInfoElement = MyMalloc(sizeof(DEVINFO_ELEM)))) {
  2064. Err = ERROR_NOT_ENOUGH_MEMORY;
  2065. goto clean0;
  2066. }
  2067. ZeroMemory(*DeviceInfoElement, sizeof(DEVINFO_ELEM));
  2068. //
  2069. // Store the address of the containing devinfo set in the structure
  2070. // for this element. This is used for efficient validation of a
  2071. // caller-supplied SP_DEVINFO_DATA.
  2072. //
  2073. (*DeviceInfoElement)->ContainingDeviceInfoSet = ContainingDeviceInfoSet;
  2074. //
  2075. // Initialize the element with the specified information
  2076. //
  2077. CopyMemory(&((*DeviceInfoElement)->ClassGuid),
  2078. ClassGuid,
  2079. sizeof(GUID)
  2080. );
  2081. (*DeviceInfoElement)->InstallParamBlock.hwndParent = hwndParent;
  2082. if(Description) {
  2083. //
  2084. // Set the device instance's DeviceDesc property to the specified
  2085. // description.
  2086. //
  2087. CM_Set_DevInst_Registry_Property_Ex(DevInst,
  2088. CM_DRP_DEVICEDESC,
  2089. Description,
  2090. (lstrlen(Description) + 1) * sizeof(TCHAR),
  2091. 0,
  2092. pDeviceInfoSet->hMachine);
  2093. //
  2094. // Store two versions of the description--one case-sensitive (for display)
  2095. // and the other case-insensitive (for fast lookup).
  2096. //
  2097. lstrcpyn(TempString, Description, SIZECHARS(TempString));
  2098. if((((*DeviceInfoElement)->DeviceDescriptionDisplayName =
  2099. pStringTableAddString(pDeviceInfoSet->StringTable,
  2100. TempString,
  2101. STRTAB_CASE_SENSITIVE,
  2102. NULL,0)) == -1) ||
  2103. (((*DeviceInfoElement)->DeviceDescription =
  2104. pStringTableAddString(pDeviceInfoSet->StringTable,
  2105. TempString,
  2106. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  2107. NULL,0)) == -1)) {
  2108. Err = ERROR_NOT_ENOUGH_MEMORY;
  2109. goto clean0;
  2110. }
  2111. } else {
  2112. (*DeviceInfoElement)->DeviceDescription =
  2113. (*DeviceInfoElement)->DeviceDescriptionDisplayName = -1;
  2114. }
  2115. (*DeviceInfoElement)->DevInst = DevInst;
  2116. (*DeviceInfoElement)->DiElemFlags = DiElemFlags;
  2117. (*DeviceInfoElement)->InstallParamBlock.DriverPath = -1;
  2118. (*DeviceInfoElement)->InstallParamBlock.CoInstallerCount = -1;
  2119. //
  2120. // If we're in GUI-mode setup on Windows NT, we'll automatically set
  2121. // the DI_FLAGSEX_IN_SYSTEM_SETUP flag in the devinstall parameter
  2122. // block for this devinfo element.
  2123. //
  2124. if(GuiSetupInProgress) {
  2125. (*DeviceInfoElement)->InstallParamBlock.FlagsEx |= DI_FLAGSEX_IN_SYSTEM_SETUP;
  2126. }
  2127. //
  2128. // If we're in non-interactive mode, set the "be quiet" bits.
  2129. //
  2130. if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
  2131. (*DeviceInfoElement)->InstallParamBlock.Flags |= DI_QUIETINSTALL;
  2132. (*DeviceInfoElement)->InstallParamBlock.FlagsEx |= DI_FLAGSEX_NOUIONQUERYREMOVE;
  2133. }
  2134. //
  2135. // Initialize our enumeration 'hints'
  2136. //
  2137. (*DeviceInfoElement)->ClassDriverEnumHintIndex = INVALID_ENUM_INDEX;
  2138. (*DeviceInfoElement)->CompatDriverEnumHintIndex = INVALID_ENUM_INDEX;
  2139. //
  2140. // Create a log context separate from the parent.
  2141. //
  2142. if(CreateLogContext(NULL, FALSE, &(*DeviceInfoElement)->InstallParamBlock.LogContext) != NO_ERROR) {
  2143. //
  2144. // if it failed, we will inheret the log context, since it's better than nothing
  2145. // in theory, this should never happen, or if it does, other things will fail too
  2146. //
  2147. (*DeviceInfoElement)->InstallParamBlock.LogContext = NULL;
  2148. Err = InheritLogContext(pDeviceInfoSet->InstallParamBlock.LogContext, &(*DeviceInfoElement)->InstallParamBlock.LogContext);
  2149. if (Err != NO_ERROR) {
  2150. goto clean0;
  2151. }
  2152. }
  2153. //
  2154. // Now, insert the new element at the end of the device
  2155. // information set's list of elements.
  2156. //
  2157. if(pDeviceInfoSet->DeviceInfoHead) {
  2158. pDeviceInfoSet->DeviceInfoTail->Next = *DeviceInfoElement;
  2159. pDeviceInfoSet->DeviceInfoTail = *DeviceInfoElement;
  2160. } else {
  2161. pDeviceInfoSet->DeviceInfoHead =
  2162. pDeviceInfoSet->DeviceInfoTail = *DeviceInfoElement;
  2163. }
  2164. pDeviceInfoSet->DeviceInfoCount++;
  2165. clean0:
  2166. ; // Nothing to do.
  2167. } except(EXCEPTION_EXECUTE_HANDLER) {
  2168. Err = ERROR_INVALID_PARAMETER;
  2169. }
  2170. if((Err != NO_ERROR) && *DeviceInfoElement) {
  2171. MyFree(*DeviceInfoElement);
  2172. *DeviceInfoElement = NULL;
  2173. }
  2174. return Err;
  2175. }
  2176. DWORD
  2177. pSetupClassGuidFromDevInst(
  2178. IN DEVINST DevInst,
  2179. IN HMACHINE hMachine,
  2180. OUT LPGUID ClassGuid
  2181. )
  2182. /*++
  2183. Routine Description:
  2184. This routine attempts to retrieve the class GUID for the specified device
  2185. instance from its device registry key. If it cannot retrieve one, it
  2186. returns GUID_NULL.
  2187. Arguments:
  2188. DevInst - Supplies the handle of the device instance whose class GUID is
  2189. to be retrieved.
  2190. hMachine - Machine context to operate in
  2191. ClassGuid - Supplies the address of the variable that receives the class
  2192. GUID, or GUID_NULL if no class GUID can be retrieved.
  2193. Return Value:
  2194. If the function succeeds, the return value is NO_ERROR.
  2195. If the function fails, an ERROR_* code is returned. (Presently, the only
  2196. failure condition returned is ERROR_NOT_ENOUGH_MEMORY.)
  2197. --*/
  2198. {
  2199. DWORD NumGuids;
  2200. TCHAR TempString[GUID_STRING_LEN];
  2201. DWORD StringSize;
  2202. StringSize = sizeof(TempString);
  2203. if(CM_Get_DevInst_Registry_Property_Ex(DevInst,
  2204. CM_DRP_CLASSGUID,
  2205. NULL,
  2206. TempString,
  2207. &StringSize,
  2208. 0,
  2209. hMachine) == CR_SUCCESS) {
  2210. //
  2211. // We retrieved the class GUID (in string form) for this device
  2212. // instance--now, convert it into its binary representation.
  2213. //
  2214. return pSetupGuidFromString(TempString, ClassGuid);
  2215. }
  2216. //
  2217. // We couldn't retrieve a ClassGUID--let's see if there's a Class name we can
  2218. // work with.
  2219. //
  2220. StringSize = sizeof(TempString);
  2221. if(CM_Get_DevInst_Registry_Property_Ex(DevInst,
  2222. CM_DRP_CLASS,
  2223. NULL,
  2224. TempString,
  2225. &StringSize,
  2226. 0,
  2227. hMachine) == CR_SUCCESS) {
  2228. //
  2229. // OK, we found out the class name. Now see if we can find a
  2230. // single class GUID to match it.
  2231. //
  2232. if(SetupDiClassGuidsFromName(TempString, ClassGuid, 1, &NumGuids) && NumGuids) {
  2233. //
  2234. // We found exactly one, so we're happy.
  2235. //
  2236. return NO_ERROR;
  2237. }
  2238. }
  2239. //
  2240. // We have no idea what class of device this is, so use GUID_NULL.
  2241. //
  2242. CopyMemory(ClassGuid, &GUID_NULL, sizeof(GUID));
  2243. return NO_ERROR;
  2244. }
  2245. BOOL
  2246. WINAPI
  2247. SetupDiDeleteDeviceInfo(
  2248. IN HDEVINFO DeviceInfoSet,
  2249. IN PSP_DEVINFO_DATA DeviceInfoData
  2250. )
  2251. /*++
  2252. Routine Description:
  2253. This routine deletes a member from the specified device information set.
  2254. THIS DOES NOT DELETE ACTUAL DEVICES!
  2255. Arguments:
  2256. DeviceInfoSet - Supplies a handle to the device information set containing
  2257. the device information element to be deleted.
  2258. DeviceInfoData - Supplies a pointer to the SP_DEVINFO_DATA structure for
  2259. the device information element to be deleted.
  2260. Return Value:
  2261. If the function succeeds, the return value is TRUE.
  2262. If the function fails, the return value is FALSE. To get extended error
  2263. information, call GetLastError.
  2264. Remarks:
  2265. If the specified device information element is explicitly in use by a wizard
  2266. page, then the call will fail, and GetLastError will return
  2267. ERROR_DEVINFO_DATA_LOCKED. This will happen if a handle to a wizard page was
  2268. retrieved via SetupDiGetWizardPage, and this element was specified, along with
  2269. the DIWP_FLAG_USE_DEVINFO_DATA flag. In order to be able to delete this element,
  2270. the wizard HPROPSHEETPAGE handle must be closed (either explicitly, or after a
  2271. call to PropertySheet() completes).
  2272. Since we don't track where this devinfo element lives in relation to our
  2273. current enumeration hint, we just invalidate the hint, so that next
  2274. enumeration must scan from the beginning of the list.
  2275. --*/
  2276. {
  2277. PDEVICE_INFO_SET pDeviceInfoSet;
  2278. DWORD Err;
  2279. PDEVINFO_ELEM ElemToDelete, PrevElem, NextElem;
  2280. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  2281. SetLastError(ERROR_INVALID_HANDLE);
  2282. return FALSE;
  2283. }
  2284. Err = NO_ERROR;
  2285. try {
  2286. //
  2287. // Get a pointer to the element we are to delete.
  2288. //
  2289. ElemToDelete = FindAssociatedDevInfoElem(pDeviceInfoSet,
  2290. DeviceInfoData,
  2291. &PrevElem
  2292. );
  2293. if(ElemToDelete) {
  2294. //
  2295. // Make sure that this element isn't currently locked by
  2296. // a wizard page.
  2297. //
  2298. if(ElemToDelete->DiElemFlags & DIE_IS_LOCKED) {
  2299. Err = ERROR_DEVINFO_DATA_LOCKED;
  2300. goto clean0;
  2301. }
  2302. NextElem = ElemToDelete->Next;
  2303. //
  2304. // Destroy the devinfo element. We need to do this before
  2305. // altering the list, because we will be calling the class
  2306. // installer with DIF_DESTROYPRIVATEDATA, and it needs to
  2307. // be able to access this element (obviously).
  2308. //
  2309. DestroyDeviceInfoElement(DeviceInfoSet, pDeviceInfoSet, ElemToDelete);
  2310. //
  2311. // Now remove the element from the list.
  2312. //
  2313. if(PrevElem) {
  2314. PrevElem->Next = NextElem;
  2315. } else {
  2316. pDeviceInfoSet->DeviceInfoHead = NextElem;
  2317. }
  2318. if(!NextElem) {
  2319. pDeviceInfoSet->DeviceInfoTail = PrevElem;
  2320. }
  2321. MYASSERT(pDeviceInfoSet->DeviceInfoCount > 0);
  2322. pDeviceInfoSet->DeviceInfoCount--;
  2323. //
  2324. // If this element was the currently selected device for this
  2325. // set, then reset the device selection.
  2326. //
  2327. if(pDeviceInfoSet->SelectedDevInfoElem == ElemToDelete) {
  2328. pDeviceInfoSet->SelectedDevInfoElem = NULL;
  2329. }
  2330. //
  2331. // Invalidate our enumeration hint for this devinfo element list.
  2332. //
  2333. pDeviceInfoSet->DeviceInfoEnumHint = NULL;
  2334. pDeviceInfoSet->DeviceInfoEnumHintIndex = INVALID_ENUM_INDEX;
  2335. } else {
  2336. Err = ERROR_INVALID_PARAMETER;
  2337. }
  2338. clean0: ; // nothing to do
  2339. } except(EXCEPTION_EXECUTE_HANDLER) {
  2340. Err = ERROR_INVALID_PARAMETER;
  2341. }
  2342. UnlockDeviceInfoSet(pDeviceInfoSet);
  2343. SetLastError(Err);
  2344. return(Err == NO_ERROR);
  2345. }
  2346. BOOL
  2347. WINAPI
  2348. SetupDiEnumDeviceInfo(
  2349. IN HDEVINFO DeviceInfoSet,
  2350. IN DWORD MemberIndex,
  2351. OUT PSP_DEVINFO_DATA DeviceInfoData
  2352. )
  2353. /*++
  2354. Routine Description:
  2355. This API enumerates the members of the specified device information set.
  2356. Arguments:
  2357. DeviceInfoSet - Supplies a handle to the device information set whose members
  2358. are to be enumerated.
  2359. MemberIndex - Supplies the zero-based index of the device information member
  2360. to be retreived.
  2361. DeviceInfoData - Supplies a pointer to a SP_DEVINFO_DATA structure that will
  2362. receive information about this member.
  2363. Return Value:
  2364. If the function succeeds, the return value is TRUE.
  2365. If the function fails, the return value is FALSE. To get extended error
  2366. information, call GetLastError.
  2367. Remarks:
  2368. To enumerate device information members, an application should initially call
  2369. the SetupDiEnumDeviceInfo function with the MemberIndex parameter set to zero.
  2370. The application should then increment MemberIndex and call the
  2371. SetupDiEnumDeviceInfo function until there are no more values (i.e., the
  2372. function fails, and GetLastError returns ERROR_NO_MORE_ITEMS).
  2373. --*/
  2374. {
  2375. PDEVICE_INFO_SET pDeviceInfoSet;
  2376. DWORD Err, i;
  2377. PDEVINFO_ELEM DevInfoElem;
  2378. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  2379. SetLastError(ERROR_INVALID_HANDLE);
  2380. return FALSE;
  2381. }
  2382. Err = NO_ERROR;
  2383. try {
  2384. if(MemberIndex >= pDeviceInfoSet->DeviceInfoCount) {
  2385. Err = ERROR_NO_MORE_ITEMS;
  2386. goto clean0;
  2387. }
  2388. //
  2389. // Find the element corresponding to the specified index (using our
  2390. // enumeration hint optimization, if possible)
  2391. //
  2392. if(pDeviceInfoSet->DeviceInfoEnumHintIndex <= MemberIndex) {
  2393. MYASSERT(pDeviceInfoSet->DeviceInfoEnumHint);
  2394. DevInfoElem = pDeviceInfoSet->DeviceInfoEnumHint;
  2395. i = pDeviceInfoSet->DeviceInfoEnumHintIndex;
  2396. } else {
  2397. DevInfoElem = pDeviceInfoSet->DeviceInfoHead;
  2398. i = 0;
  2399. }
  2400. for(; i < MemberIndex; i++) {
  2401. DevInfoElem = DevInfoElem->Next;
  2402. }
  2403. if(!(DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
  2404. DevInfoElem,
  2405. DeviceInfoData))) {
  2406. Err = ERROR_INVALID_USER_BUFFER;
  2407. }
  2408. //
  2409. // Remember this element as our new enumeration hint.
  2410. //
  2411. pDeviceInfoSet->DeviceInfoEnumHintIndex = MemberIndex;
  2412. pDeviceInfoSet->DeviceInfoEnumHint = DevInfoElem;
  2413. clean0:
  2414. ; // Nothing to do.
  2415. } except(EXCEPTION_EXECUTE_HANDLER) {
  2416. Err = ERROR_INVALID_PARAMETER;
  2417. }
  2418. UnlockDeviceInfoSet(pDeviceInfoSet);
  2419. SetLastError(Err);
  2420. return(Err == NO_ERROR);
  2421. }
  2422. BOOL
  2423. WINAPI
  2424. SetupDiRegisterDeviceInfo(
  2425. IN HDEVINFO DeviceInfoSet,
  2426. IN OUT PSP_DEVINFO_DATA DeviceInfoData,
  2427. IN DWORD Flags,
  2428. IN PSP_DETSIG_CMPPROC CompareProc, OPTIONAL
  2429. IN PVOID CompareContext, OPTIONAL
  2430. OUT PSP_DEVINFO_DATA DupDeviceInfoData OPTIONAL
  2431. )
  2432. /*++
  2433. Routine Description:
  2434. This API registers a device instance with the Plug & Play Manager.
  2435. Arguments:
  2436. DeviceInfoSet - Supplies a handle to the device information set that contains
  2437. the device information element for this device instance.
  2438. DeviceInfoData - Supplies a pointer to the SP_DEVINFO_DATA structure for the
  2439. device instance being registered. This is an IN OUT parameter, since the
  2440. DevInst field of the structure may be updated with a new handle value upon
  2441. return.
  2442. Flags - Controls how the device is to be registered. May be a combination of
  2443. the following values:
  2444. SPRDI_FIND_DUPS - Search for a previously-existing device instance
  2445. corresponding to this device information. If this
  2446. flag is not specified, the device instance will be
  2447. registered, regardless of whether a device instance
  2448. already exists for it.
  2449. CompareProc - Optionally, supplies a comparison callback function to be used in
  2450. duplicate detection. If specified, the function will be called for each
  2451. device instance that is of the same class as the device instance being
  2452. registered. The prototype of the callback function is as follows:
  2453. typedef DWORD (CALLBACK* PSP_DETSIG_CMPPROC)(
  2454. IN HDEVINFO DeviceInfoSet,
  2455. IN PSP_DEVINFO_DATA NewDeviceData,
  2456. IN PSP_DEVINFO_DATA ExistingDeviceData,
  2457. IN PVOID CompareContext OPTIONAL
  2458. );
  2459. The compare function must return ERROR_DUPLICATE_FOUND if it finds the two
  2460. devices to be duplicates of each other, and NO_ERROR otherwise. If some
  2461. other error (e.g., out-of-memory) is encountered, the callback should return
  2462. the appropriate ERROR_* code indicating the failure that occurred.
  2463. If a CompareProc is not supplied, and duplicate detection is requested, then a
  2464. default comparison behavior will be used. (See pSetupDupDevCompare for details.)
  2465. CompareContext - Optionally, supplies the address of a caller-supplied context
  2466. buffer that will be passed into the compare callback routine. This parameter
  2467. is ignored if CompareProc is not supplied.
  2468. DupDeviceInfoData - Optionally, supplies a pointer to a device information
  2469. element that will be initialized for the duplicate device instance, if any,
  2470. discovered as a result of attempting to register this device. This will
  2471. be filled in if the function returns FALSE, and GetLastError returns
  2472. ERROR_DUPLICATE_FOUND. This device information element will be added as
  2473. a member of the specified DeviceInfoSet (if it wasn't already a member).
  2474. If DupDeviceInfoData is not supplied, then the duplicate WILL NOT be added
  2475. to the device information set.
  2476. Return Value:
  2477. If the function succeeds, the return value is TRUE.
  2478. If the function fails, the return value is FALSE. To get extended error
  2479. information, call GetLastError.
  2480. Remarks:
  2481. After registering a device information element, the caller should refresh any
  2482. stored copies of the devinst handle associated with this device, as the handle
  2483. value may have changed during registration. The caller need not re-retrieve
  2484. the SP_DEVINFO_DATA structure, because the devinst field of the DeviceInfoData
  2485. structure will be updated to reflect the current handle value.
  2486. This API may invalidate our devinfo element enumeration hint.
  2487. --*/
  2488. {
  2489. PDEVICE_INFO_SET pDeviceInfoSet;
  2490. DWORD Err;
  2491. PDEVINFO_ELEM DevInfoElem, CurDevInfoElem;
  2492. CONFIGRET cr;
  2493. ULONG DevIdBufferLen, ulStatus, ulProblem;
  2494. PTCHAR DevIdBuffer = NULL;
  2495. PTSTR CurDevId;
  2496. DEVINST ParentDevInst;
  2497. BOOL AlreadyPresent;
  2498. SP_DEVINFO_DATA CurDevInfoData;
  2499. TCHAR DeviceInstanceId[MAX_DEVICE_ID_LEN];
  2500. DEFAULT_DEVCMP_CONTEXT DevCmpContext;
  2501. LOG_CONF NewDevLogConfig;
  2502. RES_DES NewDevResDes;
  2503. if(Flags & ~SPRDI_FIND_DUPS) {
  2504. SetLastError(ERROR_INVALID_FLAGS);
  2505. return FALSE;
  2506. }
  2507. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  2508. SetLastError(ERROR_INVALID_HANDLE);
  2509. return FALSE;
  2510. }
  2511. Err = NO_ERROR;
  2512. //
  2513. // Initialize the following variables so we'll know whether we need to free any of their
  2514. // associated resources.
  2515. //
  2516. ZeroMemory(&DevCmpContext, sizeof(DevCmpContext));
  2517. NewDevLogConfig = (LOG_CONF)NULL;
  2518. NewDevResDes = (RES_DES)NULL;
  2519. try {
  2520. DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  2521. DeviceInfoData,
  2522. NULL
  2523. );
  2524. if(!DevInfoElem) {
  2525. Err = ERROR_INVALID_PARAMETER;
  2526. goto clean0;
  2527. } else if(DevInfoElem->DiElemFlags & DIE_IS_REGISTERED) {
  2528. //
  2529. // Nothing to do--it's already been registered.
  2530. //
  2531. goto clean0;
  2532. }
  2533. //
  2534. // If the caller requested duplicate detection then retrieve
  2535. // all device instances of this class, and compare each one
  2536. // with the device instance being registered.
  2537. //
  2538. if(Flags & SPRDI_FIND_DUPS) {
  2539. do {
  2540. if(CM_Get_Device_ID_List_Size_Ex(&DevIdBufferLen, NULL, CM_GETIDLIST_FILTER_NONE,
  2541. pDeviceInfoSet->hMachine) != CR_SUCCESS) {
  2542. Err = ERROR_INVALID_DATA;
  2543. goto clean0;
  2544. } else if(!DevIdBufferLen) {
  2545. break;
  2546. }
  2547. if(!(DevIdBuffer = MyMalloc(DevIdBufferLen * sizeof(TCHAR)))) {
  2548. Err = ERROR_NOT_ENOUGH_MEMORY;
  2549. goto clean0;
  2550. }
  2551. cr = CM_Get_Device_ID_List_Ex(NULL,
  2552. DevIdBuffer,
  2553. DevIdBufferLen,
  2554. CM_GETIDLIST_FILTER_NONE,
  2555. pDeviceInfoSet->hMachine);
  2556. if(cr == CR_BUFFER_SMALL) {
  2557. //
  2558. // This will only happen if a device instance was added between
  2559. // the time that we calculated the size, and when we attempted
  2560. // to retrieve the list. In this case, we'll simply retrieve
  2561. // the size again, and re-attempt to retrieve the list.
  2562. //
  2563. MyFree(DevIdBuffer);
  2564. DevIdBuffer = NULL;
  2565. } else if(cr != CR_SUCCESS) {
  2566. Err = ERROR_INVALID_DATA;
  2567. goto clean0;
  2568. }
  2569. } while(cr == CR_BUFFER_SMALL);
  2570. if(!DevIdBufferLen) {
  2571. goto NoDups;
  2572. }
  2573. //
  2574. // Initialize the structure to be used during duplicate comparison callback.
  2575. //
  2576. CurDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  2577. //
  2578. // We have retrieved a list of every device instance in the system--now
  2579. // do the comparison for each one that matches the class of the device
  2580. // being registered.
  2581. //
  2582. if(!CompareProc) {
  2583. //
  2584. // We are supposed to do the comparisons, so set up to do our default comparison.
  2585. //
  2586. if((cr = CM_Get_First_Log_Conf_Ex(&NewDevLogConfig,
  2587. DevInfoElem->DevInst,
  2588. BOOT_LOG_CONF,
  2589. pDeviceInfoSet->hMachine)) != CR_SUCCESS) {
  2590. //
  2591. // Ensure that our NewDevLogConfig handle is still NULL, so we won't try
  2592. // to free it.
  2593. //
  2594. NewDevLogConfig = (LOG_CONF)NULL;
  2595. if(cr == CR_INVALID_DEVINST) {
  2596. Err = ERROR_INVALID_PARAMETER;
  2597. goto clean0;
  2598. } else {
  2599. //
  2600. // The only value we should get here is CR_NO_MORE_LOG_CONF.
  2601. // In this case, there is no comparison data, so we assume there is
  2602. // no possibility of duplication.
  2603. //
  2604. goto NoDups;
  2605. }
  2606. }
  2607. if(CM_Get_Next_Res_Des_Ex(&NewDevResDes,
  2608. NewDevLogConfig,
  2609. ResType_ClassSpecific,
  2610. NULL,
  2611. 0,
  2612. pDeviceInfoSet->hMachine) != CR_SUCCESS) {
  2613. //
  2614. // Ensure that our NewDevResDes is still NULL, so we won't try to free it.
  2615. //
  2616. NewDevResDes = (RES_DES)NULL;
  2617. //
  2618. // Since we can't retrieve the ResDes handle, assume there are no duplicates.
  2619. //
  2620. goto NoDups;
  2621. }
  2622. //
  2623. // Now retrieve the actual data for the ResDes.
  2624. //
  2625. do {
  2626. if((CM_Get_Res_Des_Data_Size_Ex(&DevCmpContext.CsResourceSize,
  2627. NewDevResDes,
  2628. 0,
  2629. pDeviceInfoSet->hMachine) != CR_SUCCESS) ||
  2630. !DevCmpContext.CsResourceSize) {
  2631. //
  2632. // Can't find out the size of the data, or there is none--assume no dups.
  2633. //
  2634. goto NoDups;
  2635. }
  2636. if(DevCmpContext.NewDevCsResource = MyMalloc(DevCmpContext.CsResourceSize)) {
  2637. if((cr = CM_Get_Res_Des_Data_Ex(NewDevResDes,
  2638. DevCmpContext.NewDevCsResource,
  2639. DevCmpContext.CsResourceSize,
  2640. 0,
  2641. pDeviceInfoSet->hMachine)) != CR_SUCCESS) {
  2642. if(cr == CR_BUFFER_SMALL) {
  2643. //
  2644. // Then someone increased the size of the resource data before we
  2645. // got a chance to read it. Free our buffer and try again.
  2646. //
  2647. MyFree(DevCmpContext.NewDevCsResource);
  2648. DevCmpContext.NewDevCsResource = NULL;
  2649. } else {
  2650. //
  2651. // Some other error occurred (highly unlikely). Assume no dups.
  2652. //
  2653. goto NoDups;
  2654. }
  2655. }
  2656. } else {
  2657. //
  2658. // not enough memory--this is bad enough for us to abort.
  2659. //
  2660. Err = ERROR_NOT_ENOUGH_MEMORY;
  2661. goto clean0;
  2662. }
  2663. } while(cr != CR_SUCCESS);
  2664. //
  2665. // We have successfully retrieved the class-specific resource data for the new
  2666. // device's boot LogConfig. Now allocate a buffer of the same size to store the
  2667. // corresponding resource data for each device instance we're comparing against.
  2668. // We don't have to worry about devices whose resource data is larger, because
  2669. // CM_Get_Res_Des_Data_Ex will do a partial fill to a buffer that's not large enough
  2670. // to contain the entire structure. Since our default comparison only compares
  2671. // the PnP detect signature (i.e., it ignores the legacy data at the very end of
  2672. // the buffer, we're guaranteed that we have enough data to make the determination.
  2673. //
  2674. if(!(DevCmpContext.CurDevCsResource = MyMalloc(DevCmpContext.CsResourceSize))) {
  2675. Err = ERROR_NOT_ENOUGH_MEMORY;
  2676. goto clean0;
  2677. }
  2678. CompareProc = pSetupDupDevCompare;
  2679. CompareContext = &DevCmpContext;
  2680. }
  2681. for(CurDevId = DevIdBuffer;
  2682. *CurDevId;
  2683. CurDevId += lstrlen(CurDevId) + 1) {
  2684. Err = pSetupOpenAndAddNewDevInfoElem(pDeviceInfoSet,
  2685. CurDevId,
  2686. TRUE,
  2687. &(DevInfoElem->ClassGuid),
  2688. pDeviceInfoSet->InstallParamBlock.hwndParent,
  2689. &CurDevInfoElem,
  2690. TRUE,
  2691. &AlreadyPresent,
  2692. FALSE,
  2693. 0,
  2694. pDeviceInfoSet
  2695. );
  2696. if(Err == ERROR_NOT_ENOUGH_MEMORY) {
  2697. //
  2698. // Out-of-memory error is the only one bad enough to get us to abort.
  2699. //
  2700. goto clean0;
  2701. } else if(Err != NO_ERROR) {
  2702. //
  2703. // Just ignore this device instance, and move on to the next.
  2704. //
  2705. Err = NO_ERROR;
  2706. continue;
  2707. }
  2708. DevInfoDataFromDeviceInfoElement(pDeviceInfoSet, CurDevInfoElem, &CurDevInfoData);
  2709. //
  2710. // We now have the possible duplicate in our set. Call the comparison callback
  2711. // routine.
  2712. //
  2713. Err = CompareProc(DeviceInfoSet, DeviceInfoData, &CurDevInfoData, CompareContext);
  2714. //
  2715. // If the device instance was created temporarily for the comparison, then it
  2716. // may need to be destroyed. It should be destroyed if it wasn't a duplicate,
  2717. // or if the duplicate output parameter wasn't supplied.
  2718. //
  2719. if(!AlreadyPresent) {
  2720. if((Err != ERROR_DUPLICATE_FOUND) || !DupDeviceInfoData) {
  2721. SetupDiDeleteDeviceInfo(DeviceInfoSet, &CurDevInfoData);
  2722. }
  2723. }
  2724. if(Err != NO_ERROR) {
  2725. goto clean0;
  2726. }
  2727. }
  2728. }
  2729. NoDups:
  2730. //
  2731. // To turn this phantom device instance into a 'live' device instance, we simply call
  2732. // CM_Create_DevInst_Ex, which does the right thing (without reenumerating the whole
  2733. // hardware tree!).
  2734. //
  2735. if(CM_Get_Device_ID_Ex(DevInfoElem->DevInst,
  2736. DeviceInstanceId,
  2737. SIZECHARS(DeviceInstanceId),
  2738. 0,
  2739. pDeviceInfoSet->hMachine) != CR_SUCCESS) {
  2740. //
  2741. // This should never happen!
  2742. //
  2743. Err = ERROR_NO_SUCH_DEVINST;
  2744. } else if(CM_Get_Parent_Ex(&ParentDevInst, DevInfoElem->DevInst, 0,pDeviceInfoSet->hMachine) != CR_SUCCESS) {
  2745. //
  2746. // This should never happen!
  2747. //
  2748. Err = ERROR_NO_SUCH_DEVINST;
  2749. } else if(CM_Create_DevInst_Ex(&(DevInfoElem->DevInst),
  2750. DeviceInstanceId,
  2751. ParentDevInst,
  2752. CM_CREATE_DEVINST_NORMAL |
  2753. CM_CREATE_DEVINST_DO_NOT_INSTALL,
  2754. pDeviceInfoSet->hMachine) == CR_SUCCESS) {
  2755. //
  2756. // Device is no longer a phantom!
  2757. //
  2758. DevInfoElem->DiElemFlags &= ~DIE_IS_PHANTOM;
  2759. } else {
  2760. //
  2761. // This should never happen!
  2762. //
  2763. Err = ERROR_NO_SUCH_DEVINST;
  2764. goto clean0;
  2765. }
  2766. DevInfoElem->DiElemFlags |= DIE_IS_REGISTERED;
  2767. clean0:
  2768. ; // Nothing to do.
  2769. } except(EXCEPTION_EXECUTE_HANDLER) {
  2770. Err = ERROR_INVALID_PARAMETER;
  2771. //
  2772. // Access the following variables so the compiler will respect our statement
  2773. // ordering in the try clause.
  2774. //
  2775. DevIdBuffer = DevIdBuffer;
  2776. DevCmpContext.NewDevCsResource = DevCmpContext.NewDevCsResource;
  2777. DevCmpContext.CurDevCsResource = DevCmpContext.CurDevCsResource;
  2778. NewDevLogConfig = NewDevLogConfig;
  2779. NewDevResDes = NewDevResDes;
  2780. }
  2781. if(DevIdBuffer) {
  2782. MyFree(DevIdBuffer);
  2783. }
  2784. if(DevCmpContext.NewDevCsResource) {
  2785. MyFree(DevCmpContext.NewDevCsResource);
  2786. }
  2787. if(DevCmpContext.CurDevCsResource) {
  2788. MyFree(DevCmpContext.CurDevCsResource);
  2789. }
  2790. if(NewDevResDes) {
  2791. CM_Free_Res_Des_Handle(NewDevResDes);
  2792. }
  2793. if(NewDevLogConfig) {
  2794. CM_Free_Log_Conf_Handle(NewDevLogConfig);
  2795. }
  2796. if((Err == ERROR_DUPLICATE_FOUND) && DupDeviceInfoData) {
  2797. //
  2798. // The user supplied a buffer to receive the SP_DEVINFO_DATA
  2799. // structure for the duplicate.
  2800. //
  2801. try {
  2802. if(!(DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
  2803. CurDevInfoElem,
  2804. DupDeviceInfoData))) {
  2805. Err = ERROR_INVALID_USER_BUFFER;
  2806. }
  2807. } except(EXCEPTION_EXECUTE_HANDLER) {
  2808. Err = ERROR_INVALID_USER_BUFFER;
  2809. }
  2810. }
  2811. UnlockDeviceInfoSet(pDeviceInfoSet);
  2812. SetLastError(Err);
  2813. return(Err == NO_ERROR);
  2814. }
  2815. DWORD
  2816. pSetupOpenAndAddNewDevInfoElem(
  2817. IN PDEVICE_INFO_SET pDeviceInfoSet,
  2818. IN PCTSTR DeviceInstanceId,
  2819. IN BOOL AllowPhantom,
  2820. IN CONST GUID *ClassGuid, OPTIONAL
  2821. IN HWND hwndParent, OPTIONAL
  2822. OUT PDEVINFO_ELEM *DevInfoElem,
  2823. IN BOOL CheckIfAlreadyPresent,
  2824. OUT PBOOL AlreadyPresent, OPTIONAL
  2825. IN BOOL OpenExistingOnly,
  2826. IN ULONG CmLocateFlags,
  2827. IN PDEVICE_INFO_SET ContainingDeviceInfoSet
  2828. )
  2829. /*++
  2830. Routine Description:
  2831. This routine opens a DEVINST handle to an existing device instance, and
  2832. creates a new device information element for it. This element is added
  2833. to the specified device information set.
  2834. ASSUMES THAT THE CALLING ROUTINE HAS ALREADY ACQUIRED THE LOCK!
  2835. Arguments:
  2836. DeviceInfoSet - Device information set to add the new element to.
  2837. DeviceInstanceId - Supplies the name of the device instance to be opened.
  2838. AllowPhantom - Specifies whether or not phantom device instances should be
  2839. allowed. If this flag is not set, and the specified device instance is
  2840. not currently active, then the routine will fail with ERROR_NO_SUCH_DEVINST.
  2841. ClassGuid - Optionally, supplies the class that the specified device instance
  2842. must be in order to be added to the set. If the device instance is found
  2843. to be of some class other than the one specified, then the call will fail with
  2844. ERROR_CLASS_MISMATCH. If this parameter is not specified, then the only check
  2845. that will be done on the device's class is to make sure that it matches the
  2846. class of the set (if the set has an associated class).
  2847. hwndParent - Optionally, supplies the handle to the top level window for
  2848. UI relating to this element.
  2849. DevInfoElem - Optionally, supplies the address of the variable that
  2850. receives a pointer to the newly-allocated device information element.
  2851. CheckIfAlreadyPresent - Specifies whether this routine should check to see whether
  2852. the device instance is already in the specified devinfo set.
  2853. AlreadyPresent - Optionally, supplies the address of a boolean variable
  2854. that is set to indicate whether or not the specified device instance
  2855. was already in the device information set. If CheckIfAlreadyThere is FALSE,
  2856. then this parameter is ignored.
  2857. OpenExistingOnly - If this flag is non-zero, then only succeed if the device
  2858. information element is already in the set. If this flag is TRUE, then
  2859. the CheckIfAlreadyPresent flag must also be TRUE.
  2860. CmLocateFlags - Supplies additional flags to be passed to CM_Locate_DevInst.
  2861. ContainingDeviceInfoSet - Supplies a pointer to the device information set
  2862. structure with which this element is to be associated. This may be
  2863. different from the pDeviceInfoSet parameter if we're working against a
  2864. cloned devinfo set (i.e., to facilitate rollback).
  2865. Return Value:
  2866. If the function succeeds, the return value is NO_ERROR, otherwise the
  2867. ERROR_* code is returned.
  2868. Remarks:
  2869. Note that since new device information elements are always added at the end
  2870. of the existing list, the enumeration ordering is preserved, thus we don't
  2871. need to invalidate our enumeration hint.
  2872. --*/
  2873. {
  2874. CONFIGRET cr;
  2875. DEVINST DevInst;
  2876. DWORD Err, DiElemFlags;
  2877. GUID GuidBuffer;
  2878. if((cr = CM_Locate_DevInst_Ex(&DevInst,
  2879. (DEVINSTID)DeviceInstanceId,
  2880. CM_LOCATE_DEVINST_NORMAL | CmLocateFlags,
  2881. pDeviceInfoSet->hMachine)) == CR_SUCCESS) {
  2882. DiElemFlags = DIE_IS_REGISTERED;
  2883. } else {
  2884. if(cr == CR_INVALID_DEVICE_ID) {
  2885. return ERROR_INVALID_DEVINST_NAME;
  2886. } else if(!AllowPhantom) {
  2887. return ERROR_NO_SUCH_DEVINST;
  2888. }
  2889. //
  2890. // It could be that the device instance is present in the registry, but
  2891. // not currently 'live'. If this is the case, we'll be able to get a
  2892. // handle to it by locating it as a phantom device instance.
  2893. //
  2894. if(CM_Locate_DevInst_Ex(&DevInst,
  2895. (DEVINSTID)DeviceInstanceId,
  2896. CM_LOCATE_DEVINST_PHANTOM | CmLocateFlags,
  2897. pDeviceInfoSet->hMachine) != CR_SUCCESS) {
  2898. return ERROR_NO_SUCH_DEVINST;
  2899. }
  2900. DiElemFlags = DIE_IS_REGISTERED | DIE_IS_PHANTOM;
  2901. }
  2902. //
  2903. // If requested, search through the current list of device information elements
  2904. // to see if this element already exists.
  2905. //
  2906. if(CheckIfAlreadyPresent) {
  2907. if(*DevInfoElem = FindDevInfoByDevInst(pDeviceInfoSet, DevInst, NULL)) {
  2908. //
  2909. // Make sure that this device instance is of the proper class, if a class GUID
  2910. // filter was supplied.
  2911. //
  2912. if(ClassGuid && !IsEqualGUID(ClassGuid, &((*DevInfoElem)->ClassGuid))) {
  2913. return ERROR_CLASS_MISMATCH;
  2914. }
  2915. if(AlreadyPresent) {
  2916. *AlreadyPresent = TRUE;
  2917. }
  2918. return NO_ERROR;
  2919. } else if(AlreadyPresent) {
  2920. *AlreadyPresent = FALSE;
  2921. if(OpenExistingOnly) {
  2922. //
  2923. // The requested device information element isn't in the set,
  2924. // so we must fail the call.
  2925. //
  2926. return ERROR_NO_SUCH_DEVICE_INTERFACE;
  2927. }
  2928. }
  2929. }
  2930. //
  2931. // Retrieve the class GUID for this device instance.
  2932. //
  2933. if((Err = pSetupClassGuidFromDevInst(DevInst, pDeviceInfoSet->hMachine,&GuidBuffer)) != NO_ERROR) {
  2934. return Err;
  2935. }
  2936. //
  2937. // If a class GUID filter was specified, then make sure that it matches the
  2938. // class GUID for this device instance.
  2939. //
  2940. if(ClassGuid && !IsEqualGUID(ClassGuid, &GuidBuffer)) {
  2941. return ERROR_CLASS_MISMATCH;
  2942. }
  2943. return pSetupAddNewDeviceInfoElement(pDeviceInfoSet,
  2944. DevInst,
  2945. &GuidBuffer,
  2946. NULL,
  2947. hwndParent,
  2948. DiElemFlags,
  2949. ContainingDeviceInfoSet,
  2950. DevInfoElem
  2951. );
  2952. }
  2953. DWORD
  2954. pSetupDupDevCompare(
  2955. IN HDEVINFO DeviceInfoSet,
  2956. IN PSP_DEVINFO_DATA NewDeviceData,
  2957. IN PSP_DEVINFO_DATA ExistingDeviceData,
  2958. IN PVOID CompareContext
  2959. )
  2960. /*++
  2961. Routine Description:
  2962. This routine is the default comparison routine for SetupDiRegisterDeviceInfo.
  2963. It is used to determine whether the new device (i.e., the one being registered) is
  2964. a duplicate of an existing device.
  2965. The current algorithm for duplicate detection is as follows:
  2966. Compare the BOOT_LOG_CONF logical configurations for the two devices. Two
  2967. resource types are used in this comparison--ResType_IO and ResType_ClassSpecific.
  2968. The IO ranges, if any, for the two devices will be compared to see if they're
  2969. identical. Also, if the devices have a class-specific resource, then the
  2970. CSD_ClassGuid, and the Plug&Play detect signature in CSD_Signature will be
  2971. binary-compared.
  2972. (lonnym): presently, the LogConfig only supports the class-specific resource,
  2973. so I/O resource comparison is not done.
  2974. Arguments:
  2975. DeviceInfoSet - Supplies the handle of the device information set containing both devices
  2976. being compared.
  2977. NewDeviceData - Supplies the address of the SP_DEVINFO_DATA for the device being registered.
  2978. ExistingDeviceData - Supplies the address of the SP_DEVINFO_DATA for the existing device with
  2979. which the new device is being compared.
  2980. CompareContext - Supplies the address of a context buffer used during the comparison. This
  2981. buffer is actually a DEFAULT_DEVCMP_CONTEXT structure, defined as follows:
  2982. typedef struct _DEFAULT_DEVCMP_CONTEXT {
  2983. PCS_RESOURCE NewDevCsResource;
  2984. PCS_RESOURCE CurDevCsResource;
  2985. ULONG CsResourceSize;
  2986. } DEFAULT_DEVCMP_CONTEXT, *PDEFAULT_DEVCMP_CONTEXT;
  2987. NewDevCsResource points to the class-specific resource buffer for the new device.
  2988. CurDevCsResource points to a working buffer that should be used to retrieve the
  2989. class-specific resource for the existing device.
  2990. CsResourceSize supplies the size in bytes of these two buffers (they're both the
  2991. same size).
  2992. Return Value:
  2993. If the two devices are not duplicates of each other, the return value is NO_ERROR.
  2994. If the two devices are duplicates of each other, the return value is ERROR_DUPLICATE_FOUND.
  2995. --*/
  2996. {
  2997. LOG_CONF ExistingDeviceLogConfig;
  2998. RES_DES ExistingDeviceResDes;
  2999. CONFIGRET cr;
  3000. PDEFAULT_DEVCMP_CONTEXT DevCmpContext;
  3001. PCS_DES NewCsDes, ExistingCsDes;
  3002. PDEVICE_INFO_SET pDeviceInfoSet;
  3003. DWORD Err;
  3004. HMACHINE hMachine;
  3005. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  3006. SetLastError(ERROR_INVALID_HANDLE);
  3007. return FALSE;
  3008. }
  3009. hMachine = pDeviceInfoSet->hMachine;
  3010. UnlockDeviceInfoSet(pDeviceInfoSet);
  3011. //
  3012. // First, retrieve the boot LogConfig for the existing device.
  3013. //
  3014. if(CM_Get_First_Log_Conf_Ex(&ExistingDeviceLogConfig,
  3015. ExistingDeviceData->DevInst,
  3016. BOOT_LOG_CONF,
  3017. hMachine) != CR_SUCCESS) {
  3018. //
  3019. // Couldn't get the boot LogConfig--assume this device isn't a duplicate.
  3020. //
  3021. return NO_ERROR;
  3022. }
  3023. //
  3024. // Assume there are no duplicates.
  3025. //
  3026. Err = NO_ERROR;
  3027. //
  3028. // Now, retrieve the the ResDes handle for the class-specific resource.
  3029. //
  3030. if(CM_Get_Next_Res_Des_Ex(&ExistingDeviceResDes,
  3031. ExistingDeviceLogConfig,
  3032. ResType_ClassSpecific,
  3033. NULL,
  3034. 0,
  3035. hMachine) != CR_SUCCESS) {
  3036. //
  3037. // Couldn't get the class-specific ResDes handle--assume this device isn't a duplicate
  3038. //
  3039. goto clean0;
  3040. }
  3041. //
  3042. // Now, retrieve the actual data associated with this ResDes. Note that we don't care if
  3043. // we get a CR_BUFFER_SMALL error, because we are guaranteed that we got back at least the
  3044. // amount of data that we have for the new device. That's all we need to do our comparison.
  3045. //
  3046. DevCmpContext = (PDEFAULT_DEVCMP_CONTEXT)CompareContext;
  3047. cr = CM_Get_Res_Des_Data_Ex(ExistingDeviceResDes,
  3048. DevCmpContext->CurDevCsResource,
  3049. DevCmpContext->CsResourceSize,
  3050. 0,
  3051. hMachine);
  3052. if((cr == CR_SUCCESS) || (cr == CR_BUFFER_SMALL)) {
  3053. //
  3054. // We got _at least_ enough of the buffer to do the comparison.
  3055. //
  3056. NewCsDes = &(DevCmpContext->NewDevCsResource->CS_Header);
  3057. ExistingCsDes = &(DevCmpContext->CurDevCsResource->CS_Header);
  3058. //
  3059. // First, see if the Plug&Play detect signatures are both the same size.
  3060. //
  3061. if(NewCsDes->CSD_SignatureLength == ExistingCsDes->CSD_SignatureLength) {
  3062. //
  3063. // See if the class GUIDs are the same.
  3064. //
  3065. if(IsEqualGUID(&(NewCsDes->CSD_ClassGuid), &(ExistingCsDes->CSD_ClassGuid))) {
  3066. //
  3067. // Finally, see if the PnP detect signatures are identical
  3068. //
  3069. if(!memcmp(NewCsDes->CSD_Signature,
  3070. ExistingCsDes->CSD_Signature,
  3071. NewCsDes->CSD_SignatureLength)) {
  3072. //
  3073. // We have ourselves a duplicate!
  3074. //
  3075. Err = ERROR_DUPLICATE_FOUND;
  3076. }
  3077. }
  3078. }
  3079. }
  3080. CM_Free_Res_Des_Handle(ExistingDeviceResDes);
  3081. clean0:
  3082. CM_Free_Log_Conf_Handle(ExistingDeviceLogConfig);
  3083. return Err;
  3084. }
  3085. #ifdef UNICODE
  3086. //
  3087. // ANSI version
  3088. //
  3089. BOOL
  3090. WINAPI
  3091. SetupDiGetDeviceInstanceIdA(
  3092. IN HDEVINFO DeviceInfoSet,
  3093. IN PSP_DEVINFO_DATA DeviceInfoData,
  3094. OUT PSTR DeviceInstanceId,
  3095. IN DWORD DeviceInstanceIdSize,
  3096. OUT PDWORD RequiredSize OPTIONAL
  3097. )
  3098. {
  3099. WCHAR deviceInstanceId[MAX_DEVICE_ID_LEN];
  3100. PSTR deviceInstanceIdA;
  3101. DWORD AnsiLength;
  3102. BOOL b;
  3103. DWORD rc;
  3104. DWORD requiredSize;
  3105. b = SetupDiGetDeviceInstanceIdW(
  3106. DeviceInfoSet,
  3107. DeviceInfoData,
  3108. deviceInstanceId,
  3109. MAX_DEVICE_ID_LEN,
  3110. &requiredSize
  3111. );
  3112. if(!b) {
  3113. return(FALSE);
  3114. }
  3115. rc = GetLastError();
  3116. if(deviceInstanceIdA = pSetupUnicodeToAnsi(deviceInstanceId)) {
  3117. AnsiLength = lstrlenA(deviceInstanceIdA) + 1;
  3118. if(RequiredSize) {
  3119. try {
  3120. *RequiredSize = AnsiLength;
  3121. } except(EXCEPTION_EXECUTE_HANDLER) {
  3122. rc = ERROR_INVALID_PARAMETER;
  3123. b = FALSE;
  3124. }
  3125. }
  3126. if(DeviceInstanceIdSize >= AnsiLength) {
  3127. if(!lstrcpyA(DeviceInstanceId,deviceInstanceIdA)) {
  3128. //
  3129. // lstrcpy faulted; assume caller's pointer invalid
  3130. //
  3131. rc = ERROR_INVALID_USER_BUFFER;
  3132. b = FALSE;
  3133. }
  3134. } else {
  3135. rc = ERROR_INSUFFICIENT_BUFFER;
  3136. b = FALSE;
  3137. }
  3138. MyFree(deviceInstanceIdA);
  3139. } else {
  3140. rc = ERROR_NOT_ENOUGH_MEMORY;
  3141. b = FALSE;
  3142. }
  3143. SetLastError(rc);
  3144. return(b);
  3145. }
  3146. #else
  3147. //
  3148. // Unicode version
  3149. //
  3150. BOOL
  3151. WINAPI
  3152. SetupDiGetDeviceInstanceIdW(
  3153. IN HDEVINFO DeviceInfoSet,
  3154. IN PSP_DEVINFO_DATA DeviceInfoData,
  3155. OUT PWSTR DeviceInstanceId,
  3156. IN DWORD DeviceInstanceIdSize,
  3157. OUT PDWORD RequiredSize OPTIONAL
  3158. )
  3159. {
  3160. UNREFERENCED_PARAMETER(DeviceInfoSet);
  3161. UNREFERENCED_PARAMETER(DeviceInfoData);
  3162. UNREFERENCED_PARAMETER(DeviceInstanceId);
  3163. UNREFERENCED_PARAMETER(DeviceInstanceIdSize);
  3164. UNREFERENCED_PARAMETER(RequiredSize);
  3165. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  3166. return(FALSE);
  3167. }
  3168. #endif
  3169. BOOL
  3170. WINAPI
  3171. SetupDiGetDeviceInstanceId(
  3172. IN HDEVINFO DeviceInfoSet,
  3173. IN PSP_DEVINFO_DATA DeviceInfoData,
  3174. OUT PTSTR DeviceInstanceId,
  3175. IN DWORD DeviceInstanceIdSize,
  3176. OUT PDWORD RequiredSize OPTIONAL
  3177. )
  3178. /*++
  3179. Routine Description:
  3180. This routine retrieves the device instance ID associated with a device
  3181. information element.
  3182. Arguments:
  3183. DeviceInfoSet - Supplies a handle to the device information set containing
  3184. the device information element whose ID is to be retrieved.
  3185. DeviceInfoData - Supplies a pointer to the SP_DEVINFO_DATA structure for
  3186. the device information element whose ID is to be retrieved.
  3187. DeviceInstanceId - Supplies the address of a character buffer that will
  3188. receive the ID for the specified device information element.
  3189. DeviceInstanceIdSize - Supplies the size, in characters, of the DeviceInstanceId
  3190. buffer.
  3191. RequiredSize - Optionally, supplies the address of a variable that receives the
  3192. number of characters required to store the device instance ID.
  3193. Return Value:
  3194. If the function succeeds, the return value is TRUE.
  3195. If the function fails, the return value is FALSE. To get extended error
  3196. information, call GetLastError.
  3197. --*/
  3198. {
  3199. PDEVICE_INFO_SET pDeviceInfoSet;
  3200. DWORD Err;
  3201. PDEVINFO_ELEM DevInfoElem;
  3202. CONFIGRET cr;
  3203. ULONG ulLen;
  3204. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  3205. SetLastError(ERROR_INVALID_HANDLE);
  3206. return FALSE;
  3207. }
  3208. Err = NO_ERROR;
  3209. try {
  3210. //
  3211. // Get a pointer to the element whose ID we are to retrieve.
  3212. //
  3213. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  3214. DeviceInfoData,
  3215. NULL))) {
  3216. Err = ERROR_INVALID_PARAMETER;
  3217. goto clean0;
  3218. }
  3219. //
  3220. // Find out how large the buffer needs to be. We always have to
  3221. // make this call first, because CM_Get_Device_ID_Ex doesn't return
  3222. // a CR_BUFFER_SMALL error if there isn't room for the terminating
  3223. // NULL.
  3224. //
  3225. if((cr = CM_Get_Device_ID_Size_Ex(&ulLen,
  3226. DevInfoElem->DevInst,
  3227. 0,
  3228. pDeviceInfoSet->hMachine)) == CR_SUCCESS) {
  3229. //
  3230. // The size returned from CM_Get_Device_ID_Size doesn't include
  3231. // the terminating NULL.
  3232. //
  3233. ulLen++;
  3234. } else {
  3235. Err = (cr == CR_INVALID_DEVINST) ? ERROR_NO_SUCH_DEVINST
  3236. : ERROR_INVALID_PARAMETER;
  3237. goto clean0;
  3238. }
  3239. if(RequiredSize) {
  3240. *RequiredSize = ulLen;
  3241. }
  3242. if(DeviceInstanceIdSize < ulLen) {
  3243. Err = ERROR_INSUFFICIENT_BUFFER;
  3244. goto clean0;
  3245. }
  3246. //
  3247. // Now retrieve the ID.
  3248. //
  3249. if((cr = CM_Get_Device_ID_Ex(DevInfoElem->DevInst,
  3250. DeviceInstanceId,
  3251. DeviceInstanceIdSize,
  3252. 0,
  3253. pDeviceInfoSet->hMachine)) != CR_SUCCESS) {
  3254. switch(cr) {
  3255. case CR_INVALID_POINTER :
  3256. Err = ERROR_INVALID_USER_BUFFER;
  3257. break;
  3258. default :
  3259. //
  3260. // Should never hit this!
  3261. //
  3262. Err = ERROR_INVALID_DATA;
  3263. }
  3264. }
  3265. clean0: ; // nothing to do.
  3266. } except(EXCEPTION_EXECUTE_HANDLER) {
  3267. Err = ERROR_INVALID_PARAMETER;
  3268. }
  3269. UnlockDeviceInfoSet(pDeviceInfoSet);
  3270. SetLastError(Err);
  3271. return(Err == NO_ERROR);
  3272. }
  3273. DWORD
  3274. pSetupAddInterfaceDeviceToDevInfoElem(
  3275. IN PDEVICE_INFO_SET DeviceInfoSet,
  3276. IN PDEVINFO_ELEM DevInfoElem,
  3277. IN CONST GUID *InterfaceClassGuid,
  3278. IN PTSTR InterfaceDeviceName,
  3279. IN BOOL IsActive,
  3280. IN BOOL IsDefault,
  3281. IN BOOL StoreTruncateNode,
  3282. IN BOOL OpenExistingOnly,
  3283. OUT PINTERFACE_DEVICE_NODE *InterfaceDeviceNode OPTIONAL
  3284. )
  3285. /*++
  3286. Routine Description:
  3287. This routine adds the specified interface device onto a device information
  3288. element's list of interface devices.
  3289. Arguments:
  3290. DeviceInfoSet - Supplies a pointer to the device information set
  3291. containing the specified element.
  3292. DevInfoElem - Supplies a pointer to the DEVINFO_ELEM structure whose
  3293. interface device list is being added to.
  3294. InterfaceClassGuid - Supplies a pointer to a GUID representing the class
  3295. that this interface device is a member of.
  3296. InterfaceDeviceName - Supplies the symbolic link name of the interface device
  3297. being added.
  3298. IsActive - Specifies whether or not the interface device is presently active.
  3299. IsDefault - Specifies whether or not the interface device is presently the
  3300. default device interface for this device interface class.
  3301. StoreTruncateNode - If non-zero, then store the address of this device
  3302. interface node (if newly-added) when this is the first such node added
  3303. to the device information elements device interface node list (i.e.,
  3304. the interface class list's InterfaceDeviceTruncateNode field is NULL).
  3305. OpenExistingOnly - If non-zero, then only succeed if the requested device
  3306. interface is already in the device information set.
  3307. InterfaceDeviceNode - Optionally, supplies the address of an interface device
  3308. node pointer to be filled in with the node created for this interface device.
  3309. Return Value:
  3310. If success, the return value is NO_ERROR.
  3311. If failure, the return value is ERROR_NOT_ENOUGH_MEMORY.
  3312. --*/
  3313. {
  3314. LONG GuidIndex;
  3315. PINTERFACE_CLASS_LIST InterfaceClassList;
  3316. PINTERFACE_DEVICE_NODE NewInterfaceDeviceNode, CurInterfaceDevice, PrevInterfaceDevice;
  3317. LONG SymLinkNameId;
  3318. //
  3319. // First, get a reference (i.e., pointer) to this interface class guid (create one
  3320. // if it's not already present for this set).
  3321. //
  3322. GuidIndex = AddOrGetGuidTableIndex(DeviceInfoSet, InterfaceClassGuid, TRUE);
  3323. if(GuidIndex == -1) {
  3324. return ERROR_NOT_ENOUGH_MEMORY;
  3325. }
  3326. //
  3327. // Now, get the interface class list for this class from the relevant
  3328. // devinfo element (again, we will create a new (empty) list if it doesn't
  3329. // already exist).
  3330. //
  3331. if(!(InterfaceClassList = AddOrGetInterfaceClassList(DeviceInfoSet,
  3332. DevInfoElem,
  3333. GuidIndex,
  3334. TRUE))) {
  3335. return ERROR_NOT_ENOUGH_MEMORY;
  3336. }
  3337. //
  3338. // Now we will add a new device interface node to this list (making sure
  3339. // that the node isn't already there).
  3340. //
  3341. SymLinkNameId = pStringTableAddString(DeviceInfoSet->StringTable,
  3342. InterfaceDeviceName,
  3343. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  3344. NULL,
  3345. 0
  3346. );
  3347. if(SymLinkNameId == -1) {
  3348. return ERROR_NOT_ENOUGH_MEMORY;
  3349. }
  3350. for(CurInterfaceDevice = InterfaceClassList->InterfaceDeviceNode, PrevInterfaceDevice = NULL;
  3351. CurInterfaceDevice;
  3352. PrevInterfaceDevice = CurInterfaceDevice, CurInterfaceDevice = CurInterfaceDevice->Next) {
  3353. if(CurInterfaceDevice->SymLinkName == SymLinkNameId) {
  3354. //
  3355. // The node is already in our list, we don't want to add it again.
  3356. // Update the flags for this interface device to reflect whether
  3357. // the device is presently active, and whether it is the default
  3358. // interface for this class.
  3359. //
  3360. CurInterfaceDevice->Flags = (CurInterfaceDevice->Flags & ~SPINT_ACTIVE) | (IsActive ? SPINT_ACTIVE : 0);
  3361. CurInterfaceDevice->Flags = (CurInterfaceDevice->Flags & ~SPINT_DEFAULT) | (IsDefault ? SPINT_DEFAULT : 0);
  3362. //
  3363. // Return this node to the caller.
  3364. //
  3365. if(InterfaceDeviceNode) {
  3366. *InterfaceDeviceNode = CurInterfaceDevice;
  3367. }
  3368. return NO_ERROR;
  3369. }
  3370. }
  3371. //
  3372. // The device interface node wasn't already in our list--add it (unless
  3373. // we've been told not to)
  3374. //
  3375. if(OpenExistingOnly) {
  3376. return ERROR_NO_SUCH_DEVICE_INTERFACE;
  3377. }
  3378. if(!(NewInterfaceDeviceNode = MyMalloc(sizeof(INTERFACE_DEVICE_NODE)))) {
  3379. return ERROR_NOT_ENOUGH_MEMORY;
  3380. }
  3381. ZeroMemory(NewInterfaceDeviceNode, sizeof(INTERFACE_DEVICE_NODE));
  3382. NewInterfaceDeviceNode->SymLinkName = SymLinkNameId;
  3383. if(PrevInterfaceDevice) {
  3384. PrevInterfaceDevice->Next = NewInterfaceDeviceNode;
  3385. } else {
  3386. InterfaceClassList->InterfaceDeviceNode = NewInterfaceDeviceNode;
  3387. }
  3388. InterfaceClassList->InterfaceDeviceCount++;
  3389. //
  3390. // If this is the first device interface node added to this list, then
  3391. // remember it so we can truncate the list at this point if we later find
  3392. // that we need to rollback (because we encountered some error).
  3393. //
  3394. if(StoreTruncateNode && !InterfaceClassList->InterfaceDeviceTruncateNode) {
  3395. InterfaceClassList->InterfaceDeviceTruncateNode = NewInterfaceDeviceNode;
  3396. }
  3397. //
  3398. // Store the interface class GUID index in the node, so that we can easily
  3399. // determine the class of the node later.
  3400. //
  3401. NewInterfaceDeviceNode->GuidIndex = GuidIndex;
  3402. //
  3403. // Setup the flags for this interface device (these are the same flags that
  3404. // the caller sees in the SP_INTERFACE_DEVICE_DATA structure).
  3405. //
  3406. NewInterfaceDeviceNode->Flags = IsActive ? SPINT_ACTIVE : 0;
  3407. NewInterfaceDeviceNode->Flags |= IsDefault ? SPINT_DEFAULT : 0;
  3408. //
  3409. // Store a back-pointer in the device interface node, so that we can get
  3410. // back to the devinfo element that owns it (there are circumstances when
  3411. // we will be given a device interface data buffer outside of the context
  3412. // of any devinfo element).
  3413. //
  3414. NewInterfaceDeviceNode->OwningDevInfoElem = DevInfoElem;
  3415. if(InterfaceDeviceNode) {
  3416. *InterfaceDeviceNode = NewInterfaceDeviceNode;
  3417. }
  3418. return NO_ERROR;
  3419. }
  3420. BOOL
  3421. WINAPI
  3422. SetupDiEnumDeviceInterfaces(
  3423. IN HDEVINFO DeviceInfoSet,
  3424. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  3425. IN CONST GUID *InterfaceClassGuid,
  3426. IN DWORD MemberIndex,
  3427. OUT PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData
  3428. )
  3429. /*++
  3430. Routine Description:
  3431. This API enumerates device interfaces of the specified class that are
  3432. contained in the devinfo set (optionally, filtered based on DeviceInfoData).
  3433. Arguments:
  3434. DeviceInfoSet - Supplies a handle to the device information set containing
  3435. device interfaces to be enumerated.
  3436. DeviceInfoData - Optionally, supplies a pointer to a device information
  3437. element for whom device interfaces are to be enumerated.
  3438. InterfaceClassGuid - Supplies a pointer to the interface class GUID whose
  3439. members are to be enumerated.
  3440. MemberIndex - Supplies the zero-based index of the device interface to be
  3441. retrieved. If DeviceInfoData is specified, then this is relative to
  3442. all device interfaces of the specified class owned by that device
  3443. information element. If DeviceInfoData is not specified, then this
  3444. index is relative to all device interfaces contained in the device
  3445. information set.
  3446. InterfaceDeviceData - Supplies a pointer to a device interface data buffer
  3447. that receives information about the specified device interface. The
  3448. cbSize field of this structure must be filled in with
  3449. sizeof(SP_DEVICE_INTERFACE_DATA), or the buffer is considered invalid.
  3450. Return Value:
  3451. If the function succeeds, the return value is TRUE.
  3452. If the function fails, the return value is FALSE. To get extended error
  3453. information, call GetLastError.
  3454. Remarks:
  3455. To enumerate device interface members, an application should initially call
  3456. the SetupDiEnumDeviceInterfaces function with the MemberIndex parameter set
  3457. to zero. The application should then increment MemberIndex and call the
  3458. SetupDiEnumDeviceInterfaces function until there are no more values (i.e.,
  3459. the function fails, and GetLastError returns ERROR_NO_MORE_ITEMS).
  3460. --*/
  3461. {
  3462. PDEVICE_INFO_SET pDeviceInfoSet;
  3463. DWORD Err, i;
  3464. PDEVINFO_ELEM DevInfoElem;
  3465. LONG InterfaceClassGuidIndex;
  3466. PINTERFACE_CLASS_LIST InterfaceClassList;
  3467. PINTERFACE_DEVICE_NODE InterfaceDeviceNode;
  3468. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  3469. SetLastError(ERROR_INVALID_HANDLE);
  3470. return FALSE;
  3471. }
  3472. Err = NO_ERROR;
  3473. try {
  3474. //
  3475. // Retrieve the index of this interface class GUID.
  3476. //
  3477. if((InterfaceClassGuidIndex = AddOrGetGuidTableIndex(pDeviceInfoSet,
  3478. InterfaceClassGuid,
  3479. FALSE)) == -1) {
  3480. Err = ERROR_NO_MORE_ITEMS;
  3481. goto clean0;
  3482. }
  3483. //
  3484. // Find the requested interface device.
  3485. //
  3486. if(DeviceInfoData) {
  3487. //
  3488. // Then we're enumerating only those interface devices that are owned
  3489. // by a particular devinfo element.
  3490. //
  3491. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  3492. DeviceInfoData,
  3493. NULL))) {
  3494. Err = ERROR_INVALID_PARAMETER;
  3495. goto clean0;
  3496. }
  3497. if(!(InterfaceClassList = AddOrGetInterfaceClassList(pDeviceInfoSet,
  3498. DevInfoElem,
  3499. InterfaceClassGuidIndex,
  3500. FALSE))
  3501. || (MemberIndex >= InterfaceClassList->InterfaceDeviceCount))
  3502. {
  3503. Err = ERROR_NO_MORE_ITEMS;
  3504. goto clean0;
  3505. }
  3506. } else {
  3507. //
  3508. // We're enumerating across all devinfo elements. Find the appropriate devinfo
  3509. // element, and adjust the member index accordingly.
  3510. //
  3511. for(DevInfoElem = pDeviceInfoSet->DeviceInfoHead;
  3512. DevInfoElem;
  3513. DevInfoElem = DevInfoElem->Next) {
  3514. if(InterfaceClassList = AddOrGetInterfaceClassList(pDeviceInfoSet,
  3515. DevInfoElem,
  3516. InterfaceClassGuidIndex,
  3517. FALSE)) {
  3518. if(MemberIndex < InterfaceClassList->InterfaceDeviceCount) {
  3519. //
  3520. // We've found the devinfo element containing the interface device
  3521. // we're looking for.
  3522. //
  3523. break;
  3524. } else {
  3525. //
  3526. // The interface device we're looking for isn't associated with
  3527. // this devinfo element. Adjust our index to eliminate the interface
  3528. // devices for this element, and continue searching.
  3529. //
  3530. MemberIndex -= InterfaceClassList->InterfaceDeviceCount;
  3531. }
  3532. }
  3533. }
  3534. if(!DevInfoElem) {
  3535. //
  3536. // Then the specified index was higher than the count of interface devices
  3537. // in this devinfo set.
  3538. //
  3539. Err = ERROR_NO_MORE_ITEMS;
  3540. goto clean0;
  3541. }
  3542. }
  3543. //
  3544. // If we reach this point, we've found the devinfo element that contains the requested
  3545. // interface device, and we have a pointer to the relevant interface class list. Now
  3546. // all we need to do is retrieve the correct member of this list, and fill in the caller's
  3547. // interface device data buffer with the appropriate information.
  3548. //
  3549. InterfaceDeviceNode = InterfaceClassList->InterfaceDeviceNode;
  3550. for(i = 0; i < MemberIndex; i++) {
  3551. InterfaceDeviceNode = InterfaceDeviceNode->Next;
  3552. }
  3553. if(!InterfaceDeviceDataFromNode(InterfaceDeviceNode, InterfaceClassGuid, DeviceInterfaceData)) {
  3554. Err = ERROR_INVALID_USER_BUFFER;
  3555. }
  3556. clean0:
  3557. ; // Nothing to do.
  3558. } except(EXCEPTION_EXECUTE_HANDLER) {
  3559. Err = ERROR_INVALID_PARAMETER;
  3560. }
  3561. UnlockDeviceInfoSet(pDeviceInfoSet);
  3562. SetLastError(Err);
  3563. return(Err == NO_ERROR);
  3564. }
  3565. #ifdef UNICODE
  3566. //
  3567. // ANSI version
  3568. //
  3569. BOOL
  3570. WINAPI
  3571. SetupDiGetDeviceInterfaceDetailA(
  3572. IN HDEVINFO DeviceInfoSet,
  3573. IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
  3574. OUT PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData, OPTIONAL
  3575. IN DWORD DeviceInterfaceDetailDataSize,
  3576. OUT PDWORD RequiredSize, OPTIONAL
  3577. OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  3578. )
  3579. {
  3580. //
  3581. // Since the maximum length for both the symbolic link and refstring components
  3582. // of the interface device name is 255 characters (excluding NULL), the maximum
  3583. // length of the entire interface device name is 512 characters
  3584. // (255 + 255 + 1 backslash + 1 NULL character).
  3585. //
  3586. // Thus, we will retrieve the unicode form of this information using a maximally-
  3587. // sized buffer, then convert it to ANSI, and store it in the caller's buffer, if
  3588. // the caller's buffer is large enough.
  3589. //
  3590. BYTE UnicodeBuffer[offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + (512 * sizeof(WCHAR))];
  3591. PCHAR AnsiBuffer;
  3592. PSP_DEVICE_INTERFACE_DETAIL_DATA_W UnicodeDetailData;
  3593. DWORD rc, UnicodeRequiredSize, ReturnBufferRequiredSize;
  3594. int AnsiStringSize;
  3595. //
  3596. // Check parameters.
  3597. //
  3598. rc = NO_ERROR;
  3599. try {
  3600. if(DeviceInterfaceDetailData) {
  3601. //
  3602. // Check signature and make sure buffer is large enough
  3603. // to hold fixed part and at least a valid empty string.
  3604. //
  3605. if((DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A))
  3606. || (DeviceInterfaceDetailDataSize < (offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A,DevicePath)+sizeof(CHAR)))) {
  3607. rc = ERROR_INVALID_USER_BUFFER;
  3608. }
  3609. } else {
  3610. //
  3611. // Doesn't want data, size has to be 0.
  3612. //
  3613. if(DeviceInterfaceDetailDataSize) {
  3614. rc = ERROR_INVALID_USER_BUFFER;
  3615. }
  3616. }
  3617. } except(EXCEPTION_EXECUTE_HANDLER) {
  3618. rc = ERROR_INVALID_USER_BUFFER;
  3619. }
  3620. if(rc != NO_ERROR) {
  3621. SetLastError(rc);
  3622. return FALSE;
  3623. }
  3624. UnicodeDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)UnicodeBuffer;
  3625. UnicodeDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
  3626. if(!SetupDiGetDeviceInterfaceDetailW(DeviceInfoSet,
  3627. DeviceInterfaceData,
  3628. UnicodeDetailData,
  3629. sizeof(UnicodeBuffer),
  3630. &UnicodeRequiredSize,
  3631. DeviceInfoData)) {
  3632. return FALSE;
  3633. }
  3634. //
  3635. // We successfully retrieved the (unicode) device interface details. Now convert it
  3636. // to ANSI, and store it in the caller's buffer.
  3637. //
  3638. UnicodeRequiredSize -= offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath);
  3639. UnicodeRequiredSize /= sizeof(WCHAR);
  3640. //
  3641. // Allocate an ANSI buffer to be used during the conversion. The maximum size the buffer
  3642. // would need to be would be 2 * NumUnicodeChars.
  3643. //
  3644. if(!(AnsiBuffer = MyMalloc(UnicodeRequiredSize * 2))) {
  3645. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  3646. return FALSE;
  3647. }
  3648. try {
  3649. AnsiStringSize = WideCharToMultiByte(CP_ACP,
  3650. 0,
  3651. UnicodeDetailData->DevicePath,
  3652. UnicodeRequiredSize,
  3653. AnsiBuffer,
  3654. UnicodeRequiredSize * 2,
  3655. NULL,
  3656. NULL
  3657. );
  3658. if(!AnsiStringSize) {
  3659. //
  3660. // This should never happen!
  3661. //
  3662. rc = GetLastError();
  3663. goto clean0;
  3664. }
  3665. ReturnBufferRequiredSize = AnsiStringSize + offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath);
  3666. if(RequiredSize) {
  3667. *RequiredSize = ReturnBufferRequiredSize;
  3668. }
  3669. if(ReturnBufferRequiredSize > DeviceInterfaceDetailDataSize) {
  3670. rc = ERROR_INSUFFICIENT_BUFFER;
  3671. goto clean0;
  3672. }
  3673. //
  3674. // OK, so we've determined that the caller's buffer is big enough. Now, copy the
  3675. // ANSI data into their buffer.
  3676. //
  3677. CopyMemory(DeviceInterfaceDetailData->DevicePath,
  3678. AnsiBuffer,
  3679. AnsiStringSize
  3680. );
  3681. clean0:
  3682. ; // nothing to do.
  3683. } except(EXCEPTION_EXECUTE_HANDLER) {
  3684. rc = ERROR_INVALID_USER_BUFFER;
  3685. }
  3686. MyFree(AnsiBuffer);
  3687. SetLastError(rc);
  3688. return (rc == NO_ERROR);
  3689. }
  3690. #else
  3691. //
  3692. // Unicode stub
  3693. //
  3694. BOOL
  3695. WINAPI
  3696. SetupDiGetDeviceInterfaceDetailW(
  3697. IN HDEVINFO DeviceInfoSet,
  3698. IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
  3699. OUT PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData, OPTIONAL
  3700. IN DWORD DeviceInterfaceDetailDataSize,
  3701. OUT PDWORD RequiredSize, OPTIONAL
  3702. OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  3703. )
  3704. {
  3705. UNREFERENCED_PARAMETER(DeviceInfoSet);
  3706. UNREFERENCED_PARAMETER(DeviceInterfaceData);
  3707. UNREFERENCED_PARAMETER(DeviceInterfaceDetailData);
  3708. UNREFERENCED_PARAMETER(DeviceInterfaceDetailDataSize);
  3709. UNREFERENCED_PARAMETER(RequiredSize);
  3710. UNREFERENCED_PARAMETER(DeviceInfoData);
  3711. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  3712. return(FALSE);
  3713. }
  3714. #endif
  3715. BOOL
  3716. WINAPI
  3717. SetupDiGetDeviceInterfaceDetail(
  3718. IN HDEVINFO DeviceInfoSet,
  3719. IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
  3720. OUT PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData, OPTIONAL
  3721. IN DWORD DeviceInterfaceDetailDataSize,
  3722. OUT PDWORD RequiredSize, OPTIONAL
  3723. OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  3724. )
  3725. /*++
  3726. Routine Description:
  3727. This routine retrieves details about a particular device interface (i.e., what
  3728. it's "name" is that you can do a CreateFile on).
  3729. Arguments:
  3730. DeviceInfoSet - Supplies a handle to a device information set containing
  3731. a device interface to retrieve details about.
  3732. DeviceInterfaceData - Supplies a device interface information structure
  3733. for which details are to be retrieved.
  3734. DeviceInterfaceDetailData - Optionally, supplies the address of a device
  3735. interface detail data structure that will receive additional information
  3736. about the specified device interface. If this parameter is not specified,
  3737. then DeviceInterfaceDetailDataSize must be zero (this would be done if the
  3738. caller was only interested in finding out how large of a buffer is required).
  3739. If this parameter is specified, the cbSize field of this structure must
  3740. be set to the size of the structure before calling this API. NOTE:
  3741. The 'size of the structure' on input means sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA).
  3742. Note that this is essentially just a signature and is entirely separate
  3743. from DeviceInterfaceDetailDataSize. See below.
  3744. DeviceInterfaceDetailDataSize - Supplies the size, in bytes, of the
  3745. DeviceInterfaceDetailData buffer. To be valid this buffer must be at least
  3746. offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA, DevicePath) + sizeof(TCHAR) bytes,
  3747. which allows storage of the fixed part of the structure and a single nul to
  3748. terminate an empty multi_sz. (Depending on structure alignment,
  3749. character width, and the data to be returned, this may actually be
  3750. smaller than sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA).
  3751. RequiredSize - Optionally, supplies the address of a variable that receives
  3752. the number of bytes required to store the detailed device interface
  3753. information. This value includes both the size of the structure itself,
  3754. and the additional number of bytes required for the variable-length
  3755. character buffer at the end of it that holds the device path.
  3756. DeviceInfoData - Optionally, supplies a pointer to a SP_DEVINFO_DATA structure
  3757. that will receive information about the device information element that
  3758. owns this device interface. Callers that only want to retrieve this parameter
  3759. may pass NULL for DeviceInterfaceDetailData, and pass 0 for
  3760. DeviceInterfaceDetailDataSize. Assuming the specified device interface is
  3761. valid, the API will fail, with GetLastError returning ERROR_INSUFFICIENT_BUFFER.
  3762. However, DeviceInfoData will have been correctly filled in with the
  3763. associated device information element.
  3764. Return Value:
  3765. If the function succeeds, the return value is TRUE.
  3766. If the function fails, the return value is FALSE. To get extended error
  3767. information, call GetLastError.
  3768. --*/
  3769. {
  3770. PDEVICE_INFO_SET pDeviceInfoSet;
  3771. DWORD Err;
  3772. PDEVINFO_ELEM DevInfoElem;
  3773. PINTERFACE_DEVICE_NODE InterfaceDeviceNode;
  3774. PCTSTR DevicePath;
  3775. DWORD DevicePathLength, BufferLengthNeeded;
  3776. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  3777. SetLastError(ERROR_INVALID_HANDLE);
  3778. return FALSE;
  3779. }
  3780. Err = NO_ERROR;
  3781. try {
  3782. //
  3783. // First, find the devinfo element that owns this interface device. This
  3784. // is used as a form of validation, and also may be needed later on, if the
  3785. // user supplied us with a DeviceInfoData buffer to be filled in.
  3786. //
  3787. if(!(DevInfoElem = FindDevInfoElemForInterfaceDevice(pDeviceInfoSet, DeviceInterfaceData))) {
  3788. Err = ERROR_INVALID_PARAMETER;
  3789. goto clean0;
  3790. }
  3791. //
  3792. // The Reserved field contains a pointer to the underlying interface device node.
  3793. //
  3794. InterfaceDeviceNode = (PINTERFACE_DEVICE_NODE)(DeviceInterfaceData->Reserved);
  3795. DevicePath = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  3796. InterfaceDeviceNode->SymLinkName
  3797. );
  3798. DevicePathLength = (lstrlen(DevicePath) + 1) * sizeof(TCHAR);
  3799. //
  3800. // Before attempting to store the device path in the caller's buffer, check to see
  3801. // whether they requested that the associated devinfo element be returned. If so,
  3802. // do that first.
  3803. //
  3804. if(DeviceInfoData) {
  3805. if(!(DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
  3806. DevInfoElem,
  3807. DeviceInfoData))) {
  3808. Err = ERROR_INVALID_USER_BUFFER;
  3809. goto clean0;
  3810. }
  3811. }
  3812. //
  3813. // Validate the caller's buffer.
  3814. //
  3815. if(DeviceInterfaceDetailData) {
  3816. if((DeviceInterfaceDetailDataSize <
  3817. (offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA, DevicePath) + sizeof(TCHAR))) ||
  3818. (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA))) {
  3819. Err = ERROR_INVALID_USER_BUFFER;
  3820. goto clean0;
  3821. }
  3822. } else if(DeviceInterfaceDetailDataSize) {
  3823. Err = ERROR_INVALID_USER_BUFFER;
  3824. goto clean0;
  3825. }
  3826. //
  3827. // Compute the buffer size required.
  3828. //
  3829. BufferLengthNeeded = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA, DevicePath) + DevicePathLength;
  3830. if(RequiredSize) {
  3831. *RequiredSize = BufferLengthNeeded;
  3832. }
  3833. if(BufferLengthNeeded > DeviceInterfaceDetailDataSize) {
  3834. Err = ERROR_INSUFFICIENT_BUFFER;
  3835. goto clean0;
  3836. }
  3837. CopyMemory(DeviceInterfaceDetailData->DevicePath, DevicePath, DevicePathLength);
  3838. clean0: ; // Nothing to do.
  3839. } except(EXCEPTION_EXECUTE_HANDLER) {
  3840. Err = ERROR_INVALID_PARAMETER;
  3841. }
  3842. UnlockDeviceInfoSet(pDeviceInfoSet);
  3843. SetLastError(Err);
  3844. return(Err == NO_ERROR);
  3845. }
  3846. #ifdef UNICODE
  3847. //
  3848. // ANSI version
  3849. //
  3850. BOOL
  3851. WINAPI
  3852. SetupDiOpenDeviceInterfaceA(
  3853. IN HDEVINFO DeviceInfoSet,
  3854. IN PCSTR DevicePath,
  3855. IN DWORD OpenFlags,
  3856. OUT PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData OPTIONAL
  3857. )
  3858. {
  3859. PCWSTR UnicodeDevicePath;
  3860. DWORD rc;
  3861. rc = pSetupCaptureAndConvertAnsiArg(DevicePath, &UnicodeDevicePath);
  3862. if(rc == NO_ERROR) {
  3863. rc = _SetupDiOpenInterfaceDevice(DeviceInfoSet,
  3864. (PWSTR)UnicodeDevicePath,
  3865. OpenFlags,
  3866. DeviceInterfaceData
  3867. );
  3868. MyFree(UnicodeDevicePath);
  3869. }
  3870. SetLastError(rc);
  3871. return(rc == NO_ERROR);
  3872. }
  3873. #else
  3874. //
  3875. // Unicode stub
  3876. //
  3877. BOOL
  3878. WINAPI
  3879. SetupDiOpenDeviceInterfaceW(
  3880. IN HDEVINFO DeviceInfoSet,
  3881. IN PCWSTR DevicePath,
  3882. IN DWORD OpenFlags,
  3883. OUT PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData OPTIONAL
  3884. )
  3885. {
  3886. UNREFERENCED_PARAMETER(DeviceInfoSet);
  3887. UNREFERENCED_PARAMETER(DevicePath);
  3888. UNREFERENCED_PARAMETER(OpenFlags);
  3889. UNREFERENCED_PARAMETER(DeviceInterfaceData);
  3890. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  3891. return(FALSE);
  3892. }
  3893. #endif
  3894. BOOL
  3895. WINAPI
  3896. SetupDiOpenDeviceInterface(
  3897. IN HDEVINFO DeviceInfoSet,
  3898. IN PCTSTR DevicePath,
  3899. IN DWORD OpenFlags,
  3900. OUT PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData OPTIONAL
  3901. )
  3902. /*++
  3903. Routine Description:
  3904. This routine opens up the device information element that exposes the
  3905. specified device interface (if it's not already in the device information
  3906. set), and then adds this device interface to the set.
  3907. Arguments:
  3908. DeviceInfoSet - Supplies a handle to a device information set into which this
  3909. new device interface element is to be opened.
  3910. NOTE: The class of the underlying device instance must match the class
  3911. of the set (or the set should have no associated class). If this is not
  3912. the case, the call will fail, and GetLastError will return ERROR_CLASS_MISMATCH.
  3913. DevicePath - Supplies the name of the device interface to be opened. This name
  3914. is a Win32 device path of the form "\\?\<InterfaceDeviceName>[\<RefString>]",
  3915. and is returned via a previous enumeration of device interface (i.e., via
  3916. SetupDiGetClassDevs(...DIGCF_INTERFACEDEVICE) or by notification via
  3917. RegisterDeviceNotification).
  3918. OpenFlags - Supplies flags controlling how the device interface element is
  3919. to be opened. May be a combination of the following values:
  3920. DIODI_NO_ADD - Only succeed the call (and optionally return the device
  3921. interface data) if the device interface already exists
  3922. in the device information set. This flag may be used to
  3923. get a device interface data context buffer back given a
  3924. device interface name, without causing that interface to
  3925. be opened if it's not already in the set.
  3926. This is useful, for example, when an app receives a
  3927. device interface removal notification. Such an app will
  3928. want to remove the corresponding device interface data
  3929. from the device information they're using as a container,
  3930. but they wouldn't want to open up a device interface
  3931. element not already in the set just so they can close it.
  3932. DeviceInterfaceData - Optionally, supplies a pointer to a device interface data
  3933. buffer that receives information about the specified device interface. The
  3934. cbSize field of this structure must be filled in with sizeof(SP_DEVICE_INTERFACE_DATA)
  3935. or the buffer is considered invalid.
  3936. Return Value:
  3937. If the function succeeds, the return value is TRUE.
  3938. If the function fails, the return value is FALSE. To get extended error
  3939. information, call GetLastError.
  3940. Remarks:
  3941. If the new device interface was successfully opened, but the user-supplied
  3942. DeviceInterfaceData buffer is invalid, this API will return FALSE, with
  3943. GetLastError returning ERROR_INVALID_USER_BUFFER. The device interface
  3944. element _will_ have been added as a new member of the set, however.
  3945. If the device interface already exists in the set, the flags will be updated
  3946. to reflect the current state of the device. Thus, for example, if a device
  3947. was not active when originally opened into the set, but has since become
  3948. active, this API may be used to 'refresh' the flags on that device interface
  3949. element, so that the SPINT_ACTIVE bit is once again in sync with reality.
  3950. Note that since new device information elements are always added at the end
  3951. of the existing list, the enumeration ordering is preserved, thus we don't
  3952. need to invalidate our enumeration hint.
  3953. --*/
  3954. {
  3955. PCTSTR WritableDevicePath;
  3956. DWORD rc;
  3957. rc = CaptureStringArg(DevicePath, &WritableDevicePath);
  3958. if(rc == NO_ERROR) {
  3959. rc = _SetupDiOpenInterfaceDevice(DeviceInfoSet,
  3960. (PTSTR)WritableDevicePath,
  3961. OpenFlags,
  3962. DeviceInterfaceData
  3963. );
  3964. MyFree(WritableDevicePath);
  3965. }
  3966. SetLastError(rc);
  3967. return(rc == NO_ERROR);
  3968. }
  3969. DWORD
  3970. _SetupDiOpenInterfaceDevice(
  3971. IN HDEVINFO DeviceInfoSet,
  3972. IN PTSTR DevicePath,
  3973. IN DWORD OpenFlags,
  3974. OUT PSP_DEVICE_INTERFACE_DATA InterfaceDeviceData OPTIONAL
  3975. )
  3976. /*++
  3977. Routine Description:
  3978. Worker routine for SetupDiOpenInterfaceDevice(A|W). This is a separate routine
  3979. so that both A and W versions can capture their DevicePath argument into a
  3980. writable buffer, because we need this for adding the case-insensitive form to
  3981. the string table.
  3982. Arguments:
  3983. See SetupDiOpenInterfaceDevice for details.
  3984. Return Value:
  3985. If the function succeeds, the return value is NO_ERROR. Otherwise, it is a
  3986. Win32 error code.
  3987. --*/
  3988. {
  3989. PDEVICE_INFO_SET pDeviceInfoSet;
  3990. DWORD Err, DevicePathLen;
  3991. PCTSTR p;
  3992. TCHAR InterfaceGuidString[GUID_STRING_LEN];
  3993. GUID InterfaceGuid;
  3994. HKEY hKey;
  3995. TCHAR DeviceInstanceId[MAX_DEVICE_ID_LEN];
  3996. PCTSTR MachineName;
  3997. BOOL DevInfoAlreadyPresent, IsActive, IsDefault;
  3998. PDEVINFO_ELEM DevInfoElem;
  3999. PINTERFACE_DEVICE_NODE InterfaceDeviceNode;
  4000. if(OpenFlags & ~DIODI_NO_ADD) {
  4001. return ERROR_INVALID_FLAGS;
  4002. }
  4003. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  4004. return ERROR_INVALID_HANDLE;
  4005. }
  4006. Err = NO_ERROR;
  4007. hKey = INVALID_HANDLE_VALUE;
  4008. DevInfoElem = NULL;
  4009. try {
  4010. //
  4011. // Retrieve the interface class of this device. Since the device path is of
  4012. // the form "\\?\MungedDevInstName#{InterfaceClassGuid}[\RefString]", we can
  4013. // retrieve the GUID from the name.
  4014. //
  4015. // NOTE: The algorithm about how this name is generated must be kept in sync
  4016. // with the kernel-mode implementation of IoRegisterDeviceClassAssocation, et. al.
  4017. //
  4018. DevicePathLen = lstrlen(DevicePath);
  4019. //
  4020. // Move past "\\?\" prefix (also allow "\\.\" until Memphis fixes their code)
  4021. //
  4022. if((DevicePathLen < 4) ||
  4023. (DevicePath[0] != TEXT('\\')) ||
  4024. (DevicePath[1] != TEXT('\\')) ||
  4025. ((DevicePath[2] != TEXT('?')) && (DevicePath[2] != TEXT('.'))) ||
  4026. (DevicePath[3] != TEXT('\\')))
  4027. {
  4028. Err = ERROR_BAD_PATHNAME;
  4029. goto clean0;
  4030. }
  4031. p = _tcschr(&(DevicePath[4]), TEXT('\\'));
  4032. if(!p) {
  4033. //
  4034. // This name has no refstring--set the pointer to the end of the string
  4035. //
  4036. p = DevicePath + DevicePathLen;
  4037. }
  4038. //
  4039. // Make sure there are enough characters preceding the current position for a
  4040. // GUID to fit.
  4041. //
  4042. if(p < (DevicePath + 3 + GUID_STRING_LEN)) {
  4043. Err = ERROR_BAD_PATHNAME;
  4044. goto clean0;
  4045. }
  4046. lstrcpyn(InterfaceGuidString, p - (GUID_STRING_LEN - 1), SIZECHARS(InterfaceGuidString));
  4047. if(pSetupGuidFromString(InterfaceGuidString, &InterfaceGuid) != NO_ERROR) {
  4048. Err = ERROR_BAD_PATHNAME;
  4049. goto clean0;
  4050. }
  4051. //
  4052. // Retrieve the name of the machine associated with this DeviceInfoSet.
  4053. //
  4054. if(pDeviceInfoSet->hMachine) {
  4055. MYASSERT(pDeviceInfoSet->MachineName != -1);
  4056. MachineName = pStringTableStringFromId(pDeviceInfoSet->StringTable, pDeviceInfoSet->MachineName);
  4057. } else {
  4058. MachineName = NULL;
  4059. }
  4060. //
  4061. // OK, now we know that we retrieved a valid GUID from an (apparently) valid device path.
  4062. // Go open up this interface device key under the DeviceClasses registry branch.
  4063. //
  4064. hKey = SetupDiOpenClassRegKeyEx(&InterfaceGuid,
  4065. KEY_READ,
  4066. DIOCR_INTERFACE,
  4067. MachineName,
  4068. NULL
  4069. );
  4070. if(hKey == INVALID_HANDLE_VALUE) {
  4071. Err = GetLastError();
  4072. goto clean0;
  4073. }
  4074. if(NO_ERROR != (Err = pSetupGetDevInstNameAndStatusForInterfaceDevice(
  4075. hKey,
  4076. DevicePath,
  4077. DeviceInstanceId,
  4078. SIZECHARS(DeviceInstanceId),
  4079. &IsActive,
  4080. &IsDefault)))
  4081. {
  4082. goto clean0;
  4083. }
  4084. if(NO_ERROR != (Err = pSetupOpenAndAddNewDevInfoElem(pDeviceInfoSet,
  4085. DeviceInstanceId,
  4086. TRUE,
  4087. NULL,
  4088. NULL,
  4089. &DevInfoElem,
  4090. TRUE,
  4091. &DevInfoAlreadyPresent,
  4092. (OpenFlags & DIODI_NO_ADD),
  4093. 0,
  4094. pDeviceInfoSet)))
  4095. {
  4096. //
  4097. // Make sure DevInfoElem is still NULL, so we won't try to delete it.
  4098. //
  4099. DevInfoElem = NULL;
  4100. goto clean0;
  4101. }
  4102. //
  4103. // Now that we've successfully opened up the device instance that 'owns'
  4104. // this interface device, add a new interface device node onto this
  4105. // devinfo element's list.
  4106. //
  4107. if((NO_ERROR == (Err = pSetupAddInterfaceDeviceToDevInfoElem(pDeviceInfoSet,
  4108. DevInfoElem,
  4109. &InterfaceGuid,
  4110. DevicePath,
  4111. IsActive,
  4112. IsDefault,
  4113. FALSE,
  4114. (OpenFlags & DIODI_NO_ADD),
  4115. &InterfaceDeviceNode)))
  4116. || DevInfoAlreadyPresent)
  4117. {
  4118. //
  4119. // Either we successfully added the interface device or the owning devinfo element
  4120. // was already in the set. In either case, we want to reset the DevInfoElem pointer
  4121. // to NULL so we won't try to delete it from the set.
  4122. //
  4123. DevInfoElem = NULL;
  4124. }
  4125. clean0: ; // nothing to do
  4126. } except(EXCEPTION_EXECUTE_HANDLER) {
  4127. Err = ERROR_INVALID_PARAMETER;
  4128. //
  4129. // Reference the following variables so the compiler will respect statement ordering
  4130. // w.r.t. assignment.
  4131. //
  4132. DevInfoElem = DevInfoElem;
  4133. hKey = hKey;
  4134. }
  4135. if(hKey != INVALID_HANDLE_VALUE) {
  4136. RegCloseKey(hKey);
  4137. }
  4138. if(Err != NO_ERROR) {
  4139. if(DevInfoElem) {
  4140. SP_DEVINFO_DATA DeviceInfoData;
  4141. DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  4142. DevInfoDataFromDeviceInfoElement(pDeviceInfoSet, DevInfoElem, &DeviceInfoData);
  4143. SetupDiDeleteDeviceInfo(DeviceInfoSet, &DeviceInfoData);
  4144. }
  4145. } else if(InterfaceDeviceData) {
  4146. try {
  4147. if(!InterfaceDeviceDataFromNode(InterfaceDeviceNode, &InterfaceGuid, InterfaceDeviceData)) {
  4148. Err = ERROR_INVALID_USER_BUFFER;
  4149. }
  4150. } except(EXCEPTION_EXECUTE_HANDLER) {
  4151. Err = ERROR_INVALID_USER_BUFFER;
  4152. }
  4153. }
  4154. UnlockDeviceInfoSet(pDeviceInfoSet);
  4155. return Err;
  4156. }
  4157. BOOL
  4158. WINAPI
  4159. SetupDiGetDeviceInterfaceAlias(
  4160. IN HDEVINFO DeviceInfoSet,
  4161. IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
  4162. IN CONST GUID *AliasInterfaceClassGuid,
  4163. OUT PSP_DEVICE_INTERFACE_DATA AliasDeviceInterfaceData
  4164. )
  4165. /*++
  4166. Routine Description:
  4167. This routine retrieves the device interface of a particular class that 'aliases'
  4168. the specified device interface. Two device interfaces are considered aliases of
  4169. each other if the following to criteria are met:
  4170. 1. Both device interfaces are exposed by the same device instance.
  4171. 2. Both device interfaces share the same RefString.
  4172. Arguments:
  4173. DeviceInfoSet - Supplies a handle to the device information set containing the
  4174. device interface for which an alias is to be retrieved.
  4175. DeviceInterfaceData - Specifies the device interface whose alias is to be
  4176. retrieved.
  4177. AliasInterfaceClassGuid - Supplies a pointer to the GUID representing the interface
  4178. class for which the alias is to be retrieved.
  4179. AliasDeviceInterfaceData - Supplies a pointer to a device interface data buffer
  4180. that receives information about the alias device interface. The cbSize field
  4181. of this structure must be filled in with sizeof(SP_DEVICE_INTERFACE_DATA) or
  4182. the buffer is considered invalid.
  4183. Return Value:
  4184. If the function succeeds, the return value is TRUE.
  4185. If the function fails, the return value is FALSE. To get extended error
  4186. information, call GetLastError.
  4187. Remarks:
  4188. If the alias device interface was successfully opened, but the user-supplied
  4189. AliasDeviceInterfaceData buffer is invalid, this API will return FALSE, with
  4190. GetLastError returning ERROR_INVALID_USER_BUFFER. The alias device interface
  4191. element _will_ have been added as a new member of the set, however.
  4192. --*/
  4193. {
  4194. PDEVICE_INFO_SET pDeviceInfoSet;
  4195. DWORD Err;
  4196. PDEVINFO_ELEM DevInfoElem, DevInfoElem2;
  4197. PINTERFACE_DEVICE_NODE InterfaceDeviceNode;
  4198. PCTSTR DevicePath;
  4199. PTSTR AliasPath;
  4200. ULONG AliasPathLength;
  4201. CONFIGRET cr;
  4202. SP_DEVICE_INTERFACE_DATA TempInterfaceDevData;
  4203. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  4204. SetLastError(ERROR_INVALID_HANDLE);
  4205. return FALSE;
  4206. }
  4207. Err = NO_ERROR;
  4208. AliasPath = NULL;
  4209. try {
  4210. //
  4211. // First, find the devinfo element that owns this interface device (for validation).
  4212. //
  4213. if(!(DevInfoElem = FindDevInfoElemForInterfaceDevice(pDeviceInfoSet, DeviceInterfaceData))) {
  4214. Err = ERROR_INVALID_PARAMETER;
  4215. goto clean0;
  4216. }
  4217. //
  4218. // The Reserved field contains a pointer to the underlying interface device node.
  4219. //
  4220. InterfaceDeviceNode = (PINTERFACE_DEVICE_NODE)(DeviceInterfaceData->Reserved);
  4221. //
  4222. // Get the device path for this interface device.
  4223. //
  4224. DevicePath = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  4225. InterfaceDeviceNode->SymLinkName
  4226. );
  4227. //
  4228. // Choose a buffer size that should always be large enough (we know this is the
  4229. // case today, but since there is no defined maximum length on this path, we leave
  4230. // the capability for it to grow in the future).
  4231. //
  4232. AliasPathLength = 512;
  4233. while(TRUE) {
  4234. if(!(AliasPath = MyMalloc(AliasPathLength * sizeof(TCHAR)))) {
  4235. Err = ERROR_NOT_ENOUGH_MEMORY;
  4236. goto clean0;
  4237. }
  4238. //
  4239. // Now retrieve the name of this interface device's alias in the specified class.
  4240. //
  4241. cr = CM_Get_Device_Interface_Alias_Ex(DevicePath,
  4242. (LPGUID)AliasInterfaceClassGuid,
  4243. AliasPath,
  4244. &AliasPathLength,
  4245. 0,
  4246. pDeviceInfoSet->hMachine);
  4247. if(cr == CR_SUCCESS) {
  4248. break;
  4249. } else {
  4250. //
  4251. // If our buffer was too small, then free it, and try again with a larger buffer.
  4252. //
  4253. if(cr == CR_BUFFER_SMALL) {
  4254. MyFree(AliasPath);
  4255. AliasPath = NULL;
  4256. } else {
  4257. Err = MapCrToSpError(cr, ERROR_NO_SUCH_DEVICE_INTERFACE);
  4258. goto clean0;
  4259. }
  4260. }
  4261. }
  4262. //
  4263. // If we get to here then we've successfully retrieved the alias name. Now open this
  4264. // interface device in our device information set.
  4265. //
  4266. TempInterfaceDevData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
  4267. if(!SetupDiOpenDeviceInterface(DeviceInfoSet,
  4268. AliasPath,
  4269. 0,
  4270. &TempInterfaceDevData)) {
  4271. //
  4272. // This should never happen.
  4273. //
  4274. Err = GetLastError();
  4275. goto clean0;
  4276. }
  4277. //
  4278. // Retrieve the device information element for this alias interface device (this has to succeed).
  4279. //
  4280. DevInfoElem2 = FindDevInfoElemForInterfaceDevice(pDeviceInfoSet, DeviceInterfaceData);
  4281. //
  4282. // Since these two interface devices are aliases of each other, they'd better be owned by
  4283. // the same devinfo element!
  4284. //
  4285. MYASSERT(DevInfoElem == DevInfoElem2);
  4286. InterfaceDeviceNode = (PINTERFACE_DEVICE_NODE)(TempInterfaceDevData.Reserved);
  4287. clean0: ; // nothing to do.
  4288. } except(EXCEPTION_EXECUTE_HANDLER) {
  4289. Err = ERROR_INVALID_PARAMETER;
  4290. //
  4291. // Reference the following variable so the compiler will respect our statement ordering
  4292. // w.r.t. assignment.
  4293. //
  4294. AliasPath = AliasPath;
  4295. }
  4296. UnlockDeviceInfoSet(pDeviceInfoSet);
  4297. if(AliasPath) {
  4298. MyFree(AliasPath);
  4299. }
  4300. if(Err == NO_ERROR) {
  4301. try {
  4302. if(!InterfaceDeviceDataFromNode(InterfaceDeviceNode,
  4303. AliasInterfaceClassGuid,
  4304. AliasDeviceInterfaceData)) {
  4305. Err = ERROR_INVALID_USER_BUFFER;
  4306. }
  4307. } except(EXCEPTION_EXECUTE_HANDLER) {
  4308. Err = ERROR_INVALID_USER_BUFFER;
  4309. }
  4310. }
  4311. SetLastError(Err);
  4312. return(Err == NO_ERROR);
  4313. }
  4314. DWORD
  4315. pSetupGetDevInstNameAndStatusForInterfaceDevice(
  4316. IN HKEY hKeyInterfaceClass,
  4317. IN PCTSTR InterfaceDeviceName,
  4318. OUT PTSTR OwningDevInstName, OPTIONAL
  4319. IN DWORD OwningDevInstNameSize,
  4320. OUT PBOOL IsActive, OPTIONAL
  4321. OUT PBOOL IsDefault OPTIONAL
  4322. )
  4323. /*++
  4324. Routine Description:
  4325. This routine retrieves the name of the device instance that exposes the specified
  4326. interface device and whether or not that interface device is currently active,
  4327. or is the default interface for the interface class to which it belongs.
  4328. Arguments:
  4329. hKeyInterfaceClass - Supplies a handle to the registry key for the interface class
  4330. of which this interface device is a member. E.g.,
  4331. HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{InterfaceClassGuid}
  4332. InterfaceDeviceName - Supplies the name of the interface device.
  4333. OwningDevInstName - Optionally, supplies the address of a character buffer that
  4334. receives the name of the device instance that exposes this interface device.
  4335. This buffer should be at least MAX_DEVICE_ID_LEN characters long.
  4336. OwningDevInstNameSize - Supplies the size, in characters, of the OwningDevInstName
  4337. buffer.
  4338. IsActive - Optionally, supplies the address of a boolean variable that is set upon
  4339. return to indicate whether this interface is presently exposed.
  4340. IsDefault - Optionally, supplies the address of a boolean variable that is set upon
  4341. return to indicate whether this interface is presently the default
  4342. device interface for its device class.
  4343. Return Value:
  4344. If the function succeeds, the return value is NO_ERROR. Otherwise, it is a Win32
  4345. error code.
  4346. --*/
  4347. {
  4348. DWORD Err, DataBufferSize, RegDataType;
  4349. HKEY hKeyInterfaceDevice, hKeyControl;
  4350. TCHAR InterfaceClassDefault[(2 * MAX_PATH) + 1]; // 2 max-sized regkey names + terminating NULL.
  4351. hKeyInterfaceDevice = hKeyControl = INVALID_HANDLE_VALUE;
  4352. try {
  4353. DataBufferSize = OwningDevInstNameSize * sizeof(TCHAR);
  4354. Err = OpenDeviceInterfaceSubKey(hKeyInterfaceClass,
  4355. InterfaceDeviceName,
  4356. KEY_READ,
  4357. &hKeyInterfaceDevice,
  4358. OwningDevInstName,
  4359. &DataBufferSize
  4360. );
  4361. if(Err != ERROR_SUCCESS) {
  4362. //
  4363. // Make sure the key handle is still invalid, so we'll know not to
  4364. // close it.
  4365. //
  4366. hKeyInterfaceDevice = INVALID_HANDLE_VALUE;
  4367. goto clean0;
  4368. }
  4369. if(IsActive) {
  4370. //
  4371. // The user wants to find out whether this interface device is currently active.
  4372. // Check the 'Linked' value entry under the volatile 'Control' subkey to find
  4373. // this out.
  4374. //
  4375. *IsActive = FALSE;
  4376. if(ERROR_SUCCESS == RegOpenKeyEx(hKeyInterfaceDevice,
  4377. pszControl,
  4378. 0,
  4379. KEY_READ,
  4380. &hKeyControl)) {
  4381. DataBufferSize = sizeof(*IsActive);
  4382. if(ERROR_SUCCESS != RegQueryValueEx(hKeyControl,
  4383. pszLinked,
  4384. NULL,
  4385. NULL,
  4386. (PBYTE)IsActive,
  4387. &DataBufferSize)) {
  4388. *IsActive = FALSE;
  4389. }
  4390. }
  4391. }
  4392. if(IsDefault) {
  4393. //
  4394. // The user wants to find out whether this interface device is the
  4395. // default device interface for its device class. Check the
  4396. // 'Default' value entry under the interface class key to find this
  4397. // out.
  4398. //
  4399. *IsDefault = FALSE;
  4400. DataBufferSize = sizeof(InterfaceClassDefault);
  4401. if(ERROR_SUCCESS == RegQueryValueEx(hKeyInterfaceClass,
  4402. pszDefault,
  4403. NULL,
  4404. NULL,
  4405. (PBYTE)InterfaceClassDefault,
  4406. &DataBufferSize)) {
  4407. if (lstrcmpi(InterfaceClassDefault, InterfaceDeviceName) == 0) {
  4408. *IsDefault = TRUE;
  4409. }
  4410. }
  4411. }
  4412. clean0: ; // nothing to do
  4413. } except(EXCEPTION_EXECUTE_HANDLER) {
  4414. Err = ERROR_INVALID_PARAMETER;
  4415. //
  4416. // Reference the following variables so the compiler will respect statement
  4417. // ordering w.r.t. assignment.
  4418. //
  4419. hKeyInterfaceDevice = hKeyInterfaceDevice;
  4420. hKeyControl = hKeyControl;
  4421. }
  4422. if(hKeyControl != INVALID_HANDLE_VALUE) {
  4423. RegCloseKey(hKeyControl);
  4424. }
  4425. if(hKeyInterfaceDevice != INVALID_HANDLE_VALUE) {
  4426. RegCloseKey(hKeyInterfaceDevice);
  4427. }
  4428. return Err;
  4429. }
  4430. #ifdef UNICODE
  4431. //
  4432. // ANSI version
  4433. //
  4434. BOOL
  4435. WINAPI
  4436. SetupDiCreateDeviceInterfaceA(
  4437. IN HDEVINFO DeviceInfoSet,
  4438. IN PSP_DEVINFO_DATA DeviceInfoData,
  4439. IN CONST GUID *InterfaceClassGuid,
  4440. IN PCSTR ReferenceString, OPTIONAL
  4441. IN DWORD CreationFlags,
  4442. OUT PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData OPTIONAL
  4443. )
  4444. {
  4445. PCWSTR UnicodeRefString;
  4446. DWORD rc;
  4447. BOOL b;
  4448. b = FALSE;
  4449. if(ReferenceString) {
  4450. rc = pSetupCaptureAndConvertAnsiArg(ReferenceString, &UnicodeRefString);
  4451. } else {
  4452. UnicodeRefString = NULL;
  4453. rc = NO_ERROR;
  4454. }
  4455. if(rc == NO_ERROR) {
  4456. b = SetupDiCreateDeviceInterfaceW(DeviceInfoSet,
  4457. DeviceInfoData,
  4458. InterfaceClassGuid,
  4459. UnicodeRefString,
  4460. CreationFlags,
  4461. DeviceInterfaceData
  4462. );
  4463. rc = GetLastError();
  4464. if(UnicodeRefString) {
  4465. MyFree(UnicodeRefString);
  4466. }
  4467. }
  4468. SetLastError(rc);
  4469. return(b);
  4470. }
  4471. #else
  4472. //
  4473. // Unicode version
  4474. //
  4475. BOOL
  4476. WINAPI
  4477. SetupDiCreateDeviceInterfaceW(
  4478. IN HDEVINFO DeviceInfoSet,
  4479. IN PSP_DEVINFO_DATA DeviceInfoData,
  4480. IN CONST GUID *InterfaceClassGuid,
  4481. IN PCWSTR ReferenceString, OPTIONAL
  4482. IN DWORD CreationFlags,
  4483. OUT PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData OPTIONAL
  4484. )
  4485. {
  4486. UNREFERENCED_PARAMETER(DeviceInfoSet);
  4487. UNREFERENCED_PARAMETER(DeviceInfoData);
  4488. UNREFERENCED_PARAMETER(InterfaceClassGuid);
  4489. UNREFERENCED_PARAMETER(ReferenceString);
  4490. UNREFERENCED_PARAMETER(CreationFlags);
  4491. UNREFERENCED_PARAMETER(DeviceInterfaceData);
  4492. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  4493. return(FALSE);
  4494. }
  4495. #endif
  4496. BOOL
  4497. WINAPI
  4498. SetupDiCreateDeviceInterface(
  4499. IN HDEVINFO DeviceInfoSet,
  4500. IN PSP_DEVINFO_DATA DeviceInfoData,
  4501. IN CONST GUID *InterfaceClassGuid,
  4502. IN PCTSTR ReferenceString, OPTIONAL
  4503. IN DWORD CreationFlags,
  4504. OUT PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData OPTIONAL
  4505. )
  4506. /*++
  4507. Routine Description:
  4508. This API creates (registers) a device interface for the specified device
  4509. information element, and adds this device interface to the device information
  4510. set.
  4511. Arguments:
  4512. DeviceInfoSet - Supplies a handle to a device information set containing the
  4513. device information element for which a new device interface is being added.
  4514. DeviceInfoData - Supplies the device information element for whom a device
  4515. interface is being added.
  4516. InterfaceClassGuid - Supplies the address of a GUID containing the class
  4517. for this new device interface.
  4518. ReferenceString - Optionally, supplies the reference string to be passed to the
  4519. driver when opening this device interface. This string becomes part of the
  4520. device interface's name (as an additional path component).
  4521. CreationFlags - Reserved for future use, must be set to 0.
  4522. DeviceInterfaceData - Optionally, supplies a pointer to a device interface data
  4523. buffer that receives information about the newly-created device interface.
  4524. The cbSize field of this structure must be filled in with sizeof(SP_DEVICE_INTERFACE_DATA)
  4525. or the buffer is considered invalid.
  4526. Return Value:
  4527. If the function succeeds, the return value is TRUE.
  4528. If the function fails, the return value is FALSE. To get extended error
  4529. information, call GetLastError.
  4530. Remarks:
  4531. If the new device interface was successfully created, but the user-supplied
  4532. DeviceInterfaceData buffer is invalid, this API will return FALSE, with
  4533. GetLastError returning ERROR_INVALID_USER_BUFFER. The device interface
  4534. element _will_ have been added as a new member of the set, however.
  4535. --*/
  4536. {
  4537. PDEVICE_INFO_SET pDeviceInfoSet;
  4538. DWORD Err;
  4539. PDEVINFO_ELEM DevInfoElem;
  4540. TCHAR InterfaceDeviceName[(2 * MAX_PATH) + 1]; // 2 max-sized regkey names + terminating NULL.
  4541. ULONG InterfaceDeviceNameSize;
  4542. PCTSTR MachineName;
  4543. CONFIGRET cr;
  4544. BOOL IsActive, IsDefault;
  4545. PINTERFACE_DEVICE_NODE InterfaceDeviceNode;
  4546. HKEY hKey;
  4547. if(CreationFlags) {
  4548. SetLastError(ERROR_INVALID_FLAGS);
  4549. return FALSE;
  4550. }
  4551. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  4552. SetLastError(ERROR_INVALID_HANDLE);
  4553. return FALSE;
  4554. }
  4555. Err = NO_ERROR;
  4556. hKey = INVALID_HANDLE_VALUE;
  4557. try {
  4558. //
  4559. // Get a pointer to the device information element we're registering an
  4560. // interface device for.
  4561. //
  4562. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  4563. DeviceInfoData,
  4564. NULL))) {
  4565. Err = ERROR_INVALID_PARAMETER;
  4566. goto clean0;
  4567. }
  4568. //
  4569. // Register the interface device.
  4570. //
  4571. InterfaceDeviceNameSize = SIZECHARS(InterfaceDeviceName);
  4572. cr = CM_Register_Device_Interface_Ex(DevInfoElem->DevInst,
  4573. (LPGUID)InterfaceClassGuid,
  4574. ReferenceString,
  4575. InterfaceDeviceName,
  4576. &InterfaceDeviceNameSize,
  4577. 0,
  4578. pDeviceInfoSet->hMachine);
  4579. if(cr != CR_SUCCESS) {
  4580. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  4581. goto clean0;
  4582. }
  4583. //
  4584. // Retrieve the name of the machine associated with this DeviceInfoSet.
  4585. //
  4586. if(pDeviceInfoSet->hMachine) {
  4587. MYASSERT(pDeviceInfoSet->MachineName != -1);
  4588. MachineName = pStringTableStringFromId(pDeviceInfoSet->StringTable, pDeviceInfoSet->MachineName);
  4589. } else {
  4590. MachineName = NULL;
  4591. }
  4592. //
  4593. // This interface device might have already been registered, in which case it
  4594. // could already be active. We must check the 'Linked' registry value to see
  4595. // whether this device is active.
  4596. //
  4597. hKey = SetupDiOpenClassRegKeyEx(InterfaceClassGuid,
  4598. KEY_READ,
  4599. DIOCR_INTERFACE,
  4600. MachineName,
  4601. NULL
  4602. );
  4603. if(hKey != INVALID_HANDLE_VALUE) {
  4604. if(NO_ERROR != pSetupGetDevInstNameAndStatusForInterfaceDevice(
  4605. hKey,
  4606. InterfaceDeviceName,
  4607. NULL,
  4608. 0,
  4609. &IsActive,
  4610. &IsDefault))
  4611. {
  4612. //
  4613. // This shouldn't fail, but if it does, then just assume that the
  4614. // interface device's status is non-active, and it is not the default.
  4615. //
  4616. IsActive = FALSE;
  4617. IsDefault = FALSE;
  4618. }
  4619. } else {
  4620. //
  4621. // This should never happen--if it does, assume that the interface device
  4622. // isn't active.
  4623. //
  4624. IsActive = FALSE;
  4625. IsDefault = FALSE;
  4626. }
  4627. //
  4628. // The interface device was successfully registered, now add it to the list of
  4629. // interface devices associated with this device information element.
  4630. //
  4631. Err = pSetupAddInterfaceDeviceToDevInfoElem(pDeviceInfoSet,
  4632. DevInfoElem,
  4633. InterfaceClassGuid,
  4634. InterfaceDeviceName,
  4635. IsActive,
  4636. IsDefault,
  4637. FALSE,
  4638. FALSE,
  4639. &InterfaceDeviceNode
  4640. );
  4641. clean0: ; // nothing to do.
  4642. } except(EXCEPTION_EXECUTE_HANDLER) {
  4643. Err = ERROR_INVALID_PARAMETER;
  4644. //
  4645. // Reference the following variable so the compiler will respect statement
  4646. // ordering w.r.t. assignment.
  4647. //
  4648. hKey = hKey;
  4649. }
  4650. if(hKey != INVALID_HANDLE_VALUE) {
  4651. RegCloseKey(hKey);
  4652. }
  4653. if((Err == NO_ERROR) && DeviceInterfaceData) {
  4654. try {
  4655. if(!InterfaceDeviceDataFromNode(InterfaceDeviceNode, InterfaceClassGuid, DeviceInterfaceData)) {
  4656. Err = ERROR_INVALID_USER_BUFFER;
  4657. }
  4658. } except(EXCEPTION_EXECUTE_HANDLER) {
  4659. Err = ERROR_INVALID_USER_BUFFER;
  4660. }
  4661. }
  4662. UnlockDeviceInfoSet(pDeviceInfoSet);
  4663. SetLastError(Err);
  4664. return (Err == NO_ERROR);
  4665. }
  4666. BOOL
  4667. WINAPI
  4668. SetupDiDeleteDeviceInterfaceData(
  4669. IN HDEVINFO DeviceInfoSet,
  4670. IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData
  4671. )
  4672. /*++
  4673. Routine Description:
  4674. This API deletes the specified device interface element from the device
  4675. information set. It _does not_ remove (unregister) the device interface
  4676. from the system (to do that, use SetupDiRemoveDeviceInterface).
  4677. Arguments:
  4678. DeviceInfoSet - Supplies a handle to the device information set containing
  4679. device interface to be deleted.
  4680. DeviceInterfaceData - Specifies the device interface to be deleted.
  4681. Return Value:
  4682. If the function succeeds, the return value is TRUE.
  4683. If the function fails, the return value is FALSE. To get extended error
  4684. information, call GetLastError.
  4685. Remarks:
  4686. After a device interface is deleted, the device interface enumeration index
  4687. is invalid, and enumeration should be re-started at index 0.
  4688. --*/
  4689. {
  4690. PDEVICE_INFO_SET pDeviceInfoSet;
  4691. DWORD Err;
  4692. PDEVINFO_ELEM DevInfoElem;
  4693. PINTERFACE_DEVICE_NODE InterfaceDeviceNode, CurInterfaceDeviceNode, PrevInterfaceDeviceNode;
  4694. PINTERFACE_CLASS_LIST InterfaceClassList;
  4695. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  4696. SetLastError(ERROR_INVALID_HANDLE);
  4697. return FALSE;
  4698. }
  4699. Err = NO_ERROR;
  4700. try {
  4701. //
  4702. // First, find the devinfo element that owns this interface device.
  4703. //
  4704. if(!(DevInfoElem = FindDevInfoElemForInterfaceDevice(pDeviceInfoSet, DeviceInterfaceData))) {
  4705. Err = ERROR_INVALID_PARAMETER;
  4706. goto clean0;
  4707. }
  4708. //
  4709. // The Reserved field contains a pointer to the underlying interface device node.
  4710. //
  4711. InterfaceDeviceNode = (PINTERFACE_DEVICE_NODE)(DeviceInterfaceData->Reserved);
  4712. //
  4713. // Find this devinfo element's interface device list for this class.
  4714. //
  4715. if(!(InterfaceClassList = AddOrGetInterfaceClassList(pDeviceInfoSet,
  4716. DevInfoElem,
  4717. InterfaceDeviceNode->GuidIndex,
  4718. FALSE)))
  4719. {
  4720. Err = ERROR_INVALID_PARAMETER;
  4721. goto clean0;
  4722. }
  4723. //
  4724. // Find this interface device node in the list of interface devices for this device
  4725. // information element.
  4726. //
  4727. for(CurInterfaceDeviceNode = InterfaceClassList->InterfaceDeviceNode, PrevInterfaceDeviceNode = NULL;
  4728. CurInterfaceDeviceNode;
  4729. PrevInterfaceDeviceNode = CurInterfaceDeviceNode, CurInterfaceDeviceNode = CurInterfaceDeviceNode->Next)
  4730. {
  4731. if(CurInterfaceDeviceNode == InterfaceDeviceNode) {
  4732. break;
  4733. }
  4734. }
  4735. if(!CurInterfaceDeviceNode) {
  4736. Err = ERROR_INVALID_PARAMETER;
  4737. goto clean0;
  4738. }
  4739. MYASSERT(InterfaceClassList->InterfaceDeviceCount);
  4740. if(PrevInterfaceDeviceNode) {
  4741. PrevInterfaceDeviceNode->Next = CurInterfaceDeviceNode->Next;
  4742. } else {
  4743. InterfaceClassList->InterfaceDeviceNode = CurInterfaceDeviceNode->Next;
  4744. }
  4745. MyFree(InterfaceDeviceNode);
  4746. InterfaceClassList->InterfaceDeviceCount--;
  4747. clean0: ; // Nothing to do.
  4748. } except(EXCEPTION_EXECUTE_HANDLER) {
  4749. Err = ERROR_INVALID_PARAMETER;
  4750. }
  4751. UnlockDeviceInfoSet(pDeviceInfoSet);
  4752. SetLastError(Err);
  4753. return(Err == NO_ERROR);
  4754. }
  4755. BOOL
  4756. WINAPI
  4757. SetupDiRemoveDeviceInterface(
  4758. IN HDEVINFO DeviceInfoSet,
  4759. IN OUT PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData
  4760. )
  4761. /*++
  4762. Routine Description:
  4763. This API removes (unregisters) the specified device interface. It _does not_
  4764. delete the device interface element from the device information set (thus
  4765. enumeration is not affected). Instead, it marks the device interface element
  4766. as invalid, so that it cannot be used in any subsequent API calls except
  4767. SetupDiDeleteDeviceInterfaceData.
  4768. Arguments:
  4769. DeviceInfoSet - Supplies a handle to the device information set containing
  4770. device interface to be removed.
  4771. DeviceInterfaceData - Specifies the device interface to be removed. All
  4772. traces of this device will be removed from the registry.
  4773. Upon return, the Flags field of this structure will be updated to reflect
  4774. the new state of this device interface.
  4775. Return Value:
  4776. If the function succeeds, the return value is TRUE.
  4777. If the function fails, the return value is FALSE. To get extended error
  4778. information, call GetLastError.
  4779. Remarks:
  4780. There is no way to unregister a device interface while it is active. Thus,
  4781. this API will fail with ERROR_DEVICE_INTERFACE_ACTIVE in this case. If this
  4782. happens, you can do one of the following things in an attempt to remove the
  4783. device interface:
  4784. 1. If there is some defined mechanism of communication to the device
  4785. interface/underlying device instance (e.g., an IOCTL) that causes the
  4786. driver to un-expose the device interface, then this method may be used,
  4787. and _then_ SetupDiRemoveDeviceInterface may be called.
  4788. 2. If there is no mechanism as described in method (1), then the owning
  4789. device instance must be stopped (e.g., via SetupDiChangeState), which
  4790. will cause all device interfaces owned by that device instance to go
  4791. inactive. After that is done, then SetupDiRemoveDeviceInterface may
  4792. be called.
  4793. --*/
  4794. {
  4795. PDEVICE_INFO_SET pDeviceInfoSet;
  4796. DWORD Err;
  4797. PDEVINFO_ELEM DevInfoElem;
  4798. PINTERFACE_DEVICE_NODE InterfaceDeviceNode;
  4799. PCTSTR DevicePath, MachineName;
  4800. TCHAR InterfaceClassDefault[(2 * MAX_PATH) + 1]; // 2 max-sized regkey names + terminating NULL.
  4801. DWORD DataBufferSize;
  4802. HKEY hKeyInterfaceClass;
  4803. CONFIGRET cr;
  4804. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  4805. SetLastError(ERROR_INVALID_HANDLE);
  4806. return FALSE;
  4807. }
  4808. Err = NO_ERROR;
  4809. try {
  4810. //
  4811. // Get a pointer to the device information element for the specified
  4812. // interface device.
  4813. //
  4814. if(!(DevInfoElem = FindDevInfoElemForInterfaceDevice(pDeviceInfoSet, DeviceInterfaceData))) {
  4815. Err = ERROR_INVALID_PARAMETER;
  4816. goto clean0;
  4817. }
  4818. //
  4819. // The Reserved field contains a pointer to the underlying interface device node.
  4820. //
  4821. InterfaceDeviceNode = (PINTERFACE_DEVICE_NODE)(DeviceInterfaceData->Reserved);
  4822. //
  4823. // OK, now open the interface device's root storage key.
  4824. //
  4825. DevicePath = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  4826. InterfaceDeviceNode->SymLinkName
  4827. );
  4828. cr = CM_Unregister_Device_Interface_Ex(DevicePath, 0,pDeviceInfoSet->hMachine);
  4829. if(cr != CR_SUCCESS) {
  4830. switch(cr) {
  4831. case CR_NO_SUCH_DEVICE_INTERFACE :
  4832. //
  4833. // The device interface was deleted after it was enumerated/opened
  4834. // by this client. In this case, we'll go ahead and succeed this
  4835. // call.
  4836. //
  4837. break;
  4838. case CR_DEVICE_INTERFACE_ACTIVE :
  4839. Err = ERROR_DEVICE_INTERFACE_ACTIVE;
  4840. //
  4841. // If our SPINT_ACTIVE flag isn't set, then that means that the device
  4842. // wasn't active the last time we looked. Update our flag to indicate
  4843. // the device's new state.
  4844. //
  4845. InterfaceDeviceNode->Flags |= SPINT_ACTIVE;
  4846. goto clean1;
  4847. default :
  4848. Err = ERROR_INVALID_DATA;
  4849. goto clean0;
  4850. }
  4851. }
  4852. //
  4853. // The interface device was successfully removed. Now, mark the interface device
  4854. // node to reflect that it's now invalid.
  4855. //
  4856. InterfaceDeviceNode->Flags |= SPINT_REMOVED;
  4857. //
  4858. // Also, clear the SPINT_ACTIVE flag, in case it's set. It's possible that we thought
  4859. // the device was active, even though it was deactivated since the last time we looked.
  4860. //
  4861. InterfaceDeviceNode->Flags &= ~SPINT_ACTIVE;
  4862. //
  4863. // Retrieve the name of the machine associated with this DeviceInfoSet.
  4864. //
  4865. if(pDeviceInfoSet->hMachine) {
  4866. MYASSERT(pDeviceInfoSet->MachineName != -1);
  4867. MachineName = pStringTableStringFromId(pDeviceInfoSet->StringTable, pDeviceInfoSet->MachineName);
  4868. } else {
  4869. MachineName = NULL;
  4870. }
  4871. //
  4872. // Open this interface class key under the DeviceClasses registry
  4873. // branch.
  4874. //
  4875. hKeyInterfaceClass = SetupDiOpenClassRegKeyEx(&DeviceInterfaceData->InterfaceClassGuid,
  4876. KEY_READ | KEY_WRITE,
  4877. DIOCR_INTERFACE,
  4878. MachineName,
  4879. NULL);
  4880. if(hKeyInterfaceClass == INVALID_HANDLE_VALUE) {
  4881. goto clean1;
  4882. }
  4883. //
  4884. // Check if this interface is specified in the registry as the default
  4885. // device interface.
  4886. //
  4887. DataBufferSize = sizeof(InterfaceClassDefault);
  4888. if(ERROR_SUCCESS == RegQueryValueEx(hKeyInterfaceClass,
  4889. pszDefault,
  4890. NULL,
  4891. NULL,
  4892. (PBYTE)InterfaceClassDefault,
  4893. &DataBufferSize)) {
  4894. if (lstrcmpi(InterfaceClassDefault, DevicePath) == 0) {
  4895. //
  4896. // Delete the "Default" value under this interface class key.
  4897. //
  4898. if(ERROR_SUCCESS == RegDeleteValue(hKeyInterfaceClass,
  4899. pszDefault)) {
  4900. //
  4901. // This interface has been successfully removed as the
  4902. // "Default" interface for this class. Clear the
  4903. // SPINT_DEFAULT flag.
  4904. //
  4905. InterfaceDeviceNode->Flags &= ~SPINT_DEFAULT;
  4906. }
  4907. } else {
  4908. //
  4909. // This interface is not listed in the registry as the
  4910. // current default device interface for this class, so clear
  4911. // the SPINT_DEFAULT flag.
  4912. //
  4913. InterfaceDeviceNode->Flags &= ~SPINT_DEFAULT;
  4914. }
  4915. } else {
  4916. //
  4917. // We could not retrieve the "Default" value, but we should still
  4918. // make sure to clear the SPINT_DEFAULT flag on this interface.
  4919. //
  4920. InterfaceDeviceNode->Flags &= ~SPINT_DEFAULT;
  4921. }
  4922. RegCloseKey(hKeyInterfaceClass);
  4923. clean1:
  4924. //
  4925. // Finally, updated the flags in the caller-supplied buffer to indicate the new status
  4926. // of this interface device.
  4927. //
  4928. DeviceInterfaceData->Flags = InterfaceDeviceNode->Flags;
  4929. clean0: ; // nothing to do
  4930. } except(EXCEPTION_EXECUTE_HANDLER) {
  4931. Err = ERROR_INVALID_PARAMETER;
  4932. }
  4933. UnlockDeviceInfoSet(pDeviceInfoSet);
  4934. SetLastError(Err);
  4935. return(Err == NO_ERROR);
  4936. }
  4937. BOOL
  4938. pSetupDiSetDeviceInfoContext(
  4939. IN HDEVINFO DeviceInfoSet,
  4940. IN PSP_DEVINFO_DATA DeviceInfoData,
  4941. IN DWORD Context
  4942. )
  4943. /*++
  4944. Routine Description:
  4945. This API stores a context value into the specified device information element
  4946. for later retrieval via pSetupDiGetDeviceInfoContext.
  4947. Arguments:
  4948. DeviceInfoSet - Supplies a handle to the device information set containing
  4949. the device information element with which the context data is to be
  4950. associated.
  4951. DeviceInfoData - Supplies the address of a SP_DEVINFO_DATA structure indicating
  4952. which element the context data should be associated with.
  4953. Context - Specifies the data value to be stored for this device information element.
  4954. Return Value:
  4955. If the function succeeds, the return value is TRUE.
  4956. If the function fails, the return value is FALSE. To get extended error
  4957. information, call GetLastError.
  4958. --*/
  4959. {
  4960. return pSetupDiGetOrSetDeviceInfoContext(DeviceInfoSet,
  4961. DeviceInfoData,
  4962. Context,
  4963. NULL
  4964. );
  4965. }
  4966. BOOL
  4967. pSetupDiGetDeviceInfoContext(
  4968. IN HDEVINFO DeviceInfoSet,
  4969. IN PSP_DEVINFO_DATA DeviceInfoData,
  4970. OUT PDWORD Context
  4971. )
  4972. /*++
  4973. Routine Description:
  4974. This API retrieves a context value from the specified device information element
  4975. (stored there via pSetupDiSetDeviceInfoContext).
  4976. Arguments:
  4977. DeviceInfoSet - Supplies a handle to the device information set containing
  4978. the device information element with which the context data is associated.
  4979. DeviceInfoData - Supplies the address of a SP_DEVINFO_DATA structure indicating
  4980. which element the context data is associated with.
  4981. Context - Supplies the address of a variable that receives the context value
  4982. stored for the device information element in a prior call to
  4983. pSetupDiSetDeviceInfoContext. If no context data has previously been stored
  4984. for this element, this variable will be filled in with zero upon return.
  4985. Return Value:
  4986. If the function succeeds, the return value is TRUE.
  4987. If the function fails, the return value is FALSE. To get extended error
  4988. information, call GetLastError.
  4989. --*/
  4990. {
  4991. //
  4992. // If we let a NULL context pointer go through to the worker routine, it will
  4993. // think this is a 'set' instead of a 'get'. Make sure that doesn't happen.
  4994. //
  4995. if(!Context) {
  4996. SetLastError(ERROR_INVALID_PARAMETER);
  4997. return FALSE;
  4998. }
  4999. return pSetupDiGetOrSetDeviceInfoContext(DeviceInfoSet,
  5000. DeviceInfoData,
  5001. 0, // ignored
  5002. Context
  5003. );
  5004. }
  5005. BOOL
  5006. pSetupDiGetOrSetDeviceInfoContext(
  5007. IN HDEVINFO DeviceInfoSet,
  5008. IN PSP_DEVINFO_DATA DeviceInfoData,
  5009. IN DWORD InContext,
  5010. OUT PDWORD OutContext OPTIONAL
  5011. )
  5012. /*++
  5013. Routine Description:
  5014. This API retrieves or sets a context value from the specified device information
  5015. element (stored there via pSetupDiSetDeviceInfoContext).
  5016. Arguments:
  5017. DeviceInfoSet - Supplies a handle to the device information set containing
  5018. the device information element with which the context data is associated.
  5019. DeviceInfoData - Supplies the address of a SP_DEVINFO_DATA structure indicating
  5020. which element the context data is associated with.
  5021. InContext - Specifies the data value to be stored for this device information element.
  5022. If OutContext is specified, then this is a 'get' instead of a 'set', and
  5023. this parameter is ignored.
  5024. OutContext - Optionally, supplies the address of a variable that receives the
  5025. context value stored for the device information element in a prior call to
  5026. pSetupDiSetDeviceInfoContext. If no context data has previously been stored
  5027. for this element, this variable will be filled in with zero upon return.
  5028. Return Value:
  5029. If the function succeeds, the return value is TRUE.
  5030. If the function fails, the return value is FALSE. To get extended error
  5031. information, call GetLastError.
  5032. --*/
  5033. {
  5034. PDEVICE_INFO_SET pDeviceInfoSet;
  5035. PDEVINFO_ELEM DevInfoElem;
  5036. DWORD Err;
  5037. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  5038. SetLastError(ERROR_INVALID_HANDLE);
  5039. return FALSE;
  5040. }
  5041. Err = NO_ERROR; // assume success.
  5042. try {
  5043. DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  5044. DeviceInfoData,
  5045. NULL
  5046. );
  5047. if(!DevInfoElem) {
  5048. Err = ERROR_INVALID_PARAMETER;
  5049. goto clean0;
  5050. }
  5051. if(OutContext) {
  5052. //
  5053. // Store the context in the caller-supplied buffer.
  5054. //
  5055. *OutContext = DevInfoElem->Context;
  5056. } else {
  5057. //
  5058. // Set the context to the caller-supplied value.
  5059. //
  5060. DevInfoElem->Context = InContext;
  5061. }
  5062. clean0:
  5063. ; // nothing to do
  5064. } except(EXCEPTION_EXECUTE_HANDLER) {
  5065. Err = ERROR_INVALID_PARAMETER;
  5066. }
  5067. UnlockDeviceInfoSet(pDeviceInfoSet);
  5068. SetLastError(Err);
  5069. return(Err == NO_ERROR);
  5070. }