*!* http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q264203 *!* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/devio/base/setupdienumdeviceinterfaces.asp *!* typedef struct _SP_DEVINFO_DATA { *!* DWORD cbSize; 4 *!* GUID ClassGuid; 16 *!* DWORD DevInst; 4 *!* ULONG_PTR Reserved; 4 *!* } SP_DEVINFO_DATA 28 *!* Private Type Guid *!* Data1 As Long 4 *!* Data2 As Integer 2 *!* Data3 As Integer 2 *!* Data4(0 To 7) As Byte 8 *!* End Type 16 ********************************************************************************* *!* Defines ********************************************************************************* #Define DIGCF_ALLCLASSES 0x0004 #Define DIGCF_DEVICEINTERFACE 0x0010 #Define DIGCF_PRESENT 0x0002 #Define DIGCF_PROFILE 0x0008 #Define DIGCF_INTERFACEDEVICE DIGCF_DEVICEINTERFACE #Define ERROR_INSUFFICIENT_BUFFER 122 #Define ERROR_NO_MORE_ITEMS 259 #Define INVALID_HANDLE_VALUE -1 #Define SPDRP_ADDRESS 0x001C #Define SPDRP_BUSTYPEGUID 0x0013 #Define SPDRP_CAPABILITIES 0x000F #Define SPDRP_CHARACTERISTICS 0x001B #Define SPDRP_CLASS 0x0007 #Define SPDRP_CLASSGUID 0x0008 #Define SPDRP_COMPATIBLEIDS 0x0002 #Define SPDRP_CONFIGFLAGS 0x000A #Define SPDRP_DEVICE_POWER_DATA 0x000E #Define SPDRP_DEVICEDESC 0x0000 #Define SPDRP_DEVTYPE 0x0019 #Define SPDRP_DRIVER 0x0009 #Define SPDRP_ENUMERATOR_NAME 0x0016 #Define SPDRP_FRIENDLYNAME 0x000C #Define SPDRP_HARDWAREID 0x0001 #Define SPDRP_LOCATION_INFORMATION 0x000D #Define SPDRP_LOWERFILTERS 0x0012 #Define SPDRP_MFG 0x000B #Define SPDRP_PHYSICAL_DEVICE_OBJECT_NAME 0x000E #Define SPDRP_REMOVAL_POLICY 0x001F #Define SPDRP_REMOVAL_POLICY_HW_DEFAULT 0x0020 #Define SPDRP_REMOVAL_POLICY_OVERRIDE 0x0021 #Define SPDRP_SECURITY 0x0017 #Define SPDRP_SECURITY_SDS 0x0018 #Define SPDRP_SERVICE 0x0004 #Define SPDRP_UI_NUMBER 0x0010 #Define SPDRP_UI_NUMBER_DESC_FORMAT 0x001E #Define SPDRP_UPPERFILTERS 0x0011 *!* GUID_DEVCLASS_DISKDRIVE, 0x4d36e967L, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 #Define GUID_DEVCLASS_DISKDRIVE ; Chr(0x67) + Chr(0xE9) + Chr(0x36) + Chr(0x4D) + ; Chr(0x25) + Chr(0xE3) + ; Chr(0xCE) + Chr(0x11) + ; Chr(0xBF) + Chr(0xC1) + Chr(0x08) + Chr(0x00) + Chr(0x2B) + Chr(0xE1) + Chr(0x03) + Chr(0x18) ********************************************************************************* *!* Declarations, in order of use ********************************************************************************* Declare Integer SetupDiGetClassDevs In setupapi; String @ClassGuid,; Integer Enumerator,; Integer hwndParent,; Integer _Flags Declare Integer SetupDiEnumDeviceInfo In setupapi; Integer DeviceInfoSet,; Integer MemberIndex,; String @DeviceInfoData Declare Integer SetupDiGetDeviceRegistryProperty In setupapi; Integer DeviceInfoSet,; String @DeviceInfoData,; Integer _Property,; String @PropertyRegDataType,; String @PropertyBuffer,; Integer PropertyBufferSize,; String @RequiredSize Declare Integer GetLastError In win32api Declare Integer SetupDiDestroyDeviceInfoList In setupapi; Integer DeviceInfoSet ********************************************************************************* *!* Start ********************************************************************************* *!* This routine enumerates the disk devices using the Setup class interface *!* GUID GUID_DEVCLASS_DISKDRIVE. Gets the Device ID from the Registry *!* property. Clear Local ; lnDeviceInfoSet, ; lnEnumerator, ; lnhwndParent, ; lnFlags, ; lcClassGuid, ; lnRetVal, ; lcDeviceInfoData, ; lnx, ; lcDeviceProperty *!* We will first obtain a handle to a list of all disk drives available: *!* "The SetupDiGetClassDevs function retrieves a device information set *!* that contains all the devices of a specified class." m.lcClassGuid = GUID_DEVCLASS_DISKDRIVE m.lnEnumerator = 0 m.lnhwndParent = 0 m.lnFlags = DIGCF_PRESENT m.lnDeviceInfoSet = SetupDiGetClassDevs( ; @m.lcClassGuid, ; m.lnEnumerator, ; m.lnhwndParent, ; m.lnFlags) && All devices present on system *!* If the return value is -1 something went wrong If m.lnDeviceInfoSet = INVALID_HANDLE_VALUE Then ? [SetupDiGetClassDevs FAILED] Return Endif *!* Now that we have a handle to the list of disk drives, we will go thru *!* that list one device at a time: *!* "The SetupDiEnumDeviceInfo function retrieves a context structure for *!* a device information element of the specified device information set. *!* Each call returns information about one device. The function can be *!* called repeatedly to get information about several devices." *!* When SetupDiEnumDeviceInfo fails, we get out of the loop, and check why it failed *!* It will probably fail because we iterated trhu all devices m.lnx = 0 m.lnRetVal = -1 Do While m.lnRetVal <> 0 *!* Initialize empty SP_DEVINFO_DATA structure m.lcDeviceInfoData = Padr(BinToC(28, [4RS]), 4, Chr(0)) + Replicate(Chr(0), 24) m.lnRetVal = SetupDiEnumDeviceInfo( ; m.lnDeviceInfoSet, ; m.lnx, ; @m.lcDeviceInfoData) *!* If we got a handle to one disk drive, now we will retrieve some properties for it: If m.lnRetVal = 1 Then ?[Device: ], m.lnx m.lcDeviceProperty = GetRegistryProperty(m.lnDeviceInfoSet, m.lcDeviceInfoData, SPDRP_CLASS) ?[Property:], [CLASS: ], m.lcDeviceProperty m.lcDeviceProperty = GetRegistryProperty(m.lnDeviceInfoSet, m.lcDeviceInfoData, SPDRP_DEVICEDESC) ?[Property:], [DEVICEDESC: ], m.lcDeviceProperty m.lcDeviceProperty = GetRegistryProperty(m.lnDeviceInfoSet, m.lcDeviceInfoData, SPDRP_ENUMERATOR_NAME) ?[Property:], [ENUMERATOR_NAME: ], m.lcDeviceProperty m.lcDeviceProperty = GetRegistryProperty(m.lnDeviceInfoSet, m.lcDeviceInfoData, SPDRP_FRIENDLYNAME) ?[Property:], [FRIENDLYNAME: ], m.lcDeviceProperty m.lcDeviceProperty = GetRegistryProperty(m.lnDeviceInfoSet, m.lcDeviceInfoData, SPDRP_HARDWAREID) ?[Property:], [HARDWAREID: ], m.lcDeviceProperty m.lcDeviceProperty = GetRegistryProperty(m.lnDeviceInfoSet, m.lcDeviceInfoData, SPDRP_MFG) ?[Property:], [MFG: ], m.lcDeviceProperty m.lcDeviceProperty = GetRegistryProperty(m.lnDeviceInfoSet, m.lcDeviceInfoData, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME) ?[Property:], [PHYSICAL_DEVICE_OBJECT_NAME: ], m.lcDeviceProperty Endif m.lnx = m.lnx + 1 Enddo If GetLastError() = ERROR_NO_MORE_ITEMS Then ?[No more devices] Else ?[SetupDiEnumDeviceInfo FAILED] Endif *!* The SetupDiDestroyDeviceInfoList function destroys a device *!* information set and frees all associated memory. If m.lnDeviceInfoSet <> INVALID_HANDLE_VALUE Then If SetupDiDestroyDeviceInfoList(m.lnDeviceInfoSet) = 0 Then ? [SetupDiDestroyDeviceInfoList lnDeviceInfoSet FAILED] Endif Endif ********************************************************************************* Procedure GetRegistryProperty ********************************************************************************* Lparameters tnDeviceInfoSet, tcDeviceInfoData, tnProperty Local lnRetVal, lcPropertyBuffer, lcRequiredSize m.lcPropertyBuffer = Space(0) m.lcRequiredSize = Space(4) m.PropertyRegDataType = Space(4) *!* "The SetupDiGetDeviceRegistryProperty function retrieves the specified device property." *!* We don't know the size of the required string buffer for the property until we call the *!* function, so we first call it with a null string to get the required buffer size, then *!* we call again with the proper buffer size m.lnRetVal = SetupDiGetDeviceRegistryProperty( ; m.tnDeviceInfoSet, ; @m.tcDeviceInfoData, ; m.tnProperty, ; @m.PropertyRegDataType, ; @m.lcPropertyBuffer, ; LEN(m.lcPropertyBuffer), ; @m.lcRequiredSize) If m.lnRetVal = 0 And GetLastError() = ERROR_INSUFFICIENT_BUFFER Then m.lcPropertyBuffer = Space(CToBin(m.lcRequiredSize, [4RS])) m.lnRetVal = SetupDiGetDeviceRegistryProperty( ; m.tnDeviceInfoSet, ; @m.tcDeviceInfoData, ; m.tnProperty, ; 0, ; @m.lcPropertyBuffer, ; LEN(m.lcPropertyBuffer), ; @m.lcRequiredSize) Endif If m.lnRetVal = 0 Then ? [SetupDiGetDeviceRegistryProperty ERROR] m.lcPropertyBuffer = [SetupDiGetDeviceRegistryProperty ERROR] Else m.lcPropertyBuffer = Left(m.lcPropertyBuffer, At(Chr(0), m.lcPropertyBuffer) - 1) Endif Return m.lcPropertyBuffer