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

5939 lines
211 KiB

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