]> git.ipfire.org Git - thirdparty/wireguard-go.git/commitdiff
setupapi: Add support for driver info lists
authorSimon Rozman <simon@rozman.si>
Tue, 5 Feb 2019 15:29:17 +0000 (16:29 +0100)
committerSimon Rozman <simon@rozman.si>
Tue, 5 Feb 2019 15:29:17 +0000 (16:29 +0100)
Signed-off-by: Simon Rozman <simon@rozman.si>
setupapi/setupapi_windows.go
setupapi/setupapi_windows_test.go
setupapi/types_windows.go
setupapi/zsetupapi_windows.go

index 750a81b8c9839a495d3c78dc1c1ef637743c1810..84d324d79096f7e3cd389c821a536d710a3e3c5f 100644 (file)
@@ -100,6 +100,101 @@ func (DeviceInfoSet DevInfo) Close() error {
        return SetupDiDestroyDeviceInfoList(DeviceInfoSet)
 }
 
+//sys  SetupDiBuildDriverInfoList(DeviceInfoSet DevInfo, DeviceInfoData *SP_DEVINFO_DATA, DriverType SPDIT) (err error) = setupapi.SetupDiBuildDriverInfoList
+
+// BuildDriverInfoList method builds a list of drivers that is associated with a specific device or with the global class driver list for a device information set.
+func (DeviceInfoSet DevInfo) BuildDriverInfoList(DeviceInfoData *SP_DEVINFO_DATA, DriverType SPDIT) (err error) {
+       return SetupDiBuildDriverInfoList(DeviceInfoSet, DeviceInfoData, DriverType)
+}
+
+//sys  SetupDiCancelDriverInfoSearch(DeviceInfoSet DevInfo) (err error) = setupapi.SetupDiCancelDriverInfoSearch
+
+// CancelDriverInfoSearch method cancels a driver list search that is currently in progress in a different thread.
+func (DeviceInfoSet DevInfo) CancelDriverInfoSearch() (err error) {
+       return SetupDiCancelDriverInfoSearch(DeviceInfoSet)
+}
+
+//sys  setupDiEnumDriverInfo(DeviceInfoSet DevInfo, DeviceInfoData *SP_DEVINFO_DATA, DriverType SPDIT, MemberIndex uint32, DriverInfoData *SP_DRVINFO_DATA) (err error) = setupapi.SetupDiEnumDriverInfoW
+
+// SetupDiEnumDriverInfo function enumerates the members of a driver list.
+func SetupDiEnumDriverInfo(DeviceInfoSet DevInfo, DeviceInfoData *SP_DEVINFO_DATA, DriverType SPDIT, MemberIndex int) (DriverInfoData *SP_DRVINFO_DATA, err error) {
+       data := &SP_DRVINFO_DATA{}
+       data.Size = uint32(unsafe.Sizeof(*data))
+
+       return data, setupDiEnumDriverInfo(DeviceInfoSet, DeviceInfoData, DriverType, uint32(MemberIndex), data)
+}
+
+// EnumDriverInfo method enumerates the members of a driver list.
+func (DeviceInfoSet DevInfo) EnumDriverInfo(DeviceInfoData *SP_DEVINFO_DATA, DriverType SPDIT, MemberIndex int) (DriverInfoData *SP_DRVINFO_DATA, err error) {
+       return SetupDiEnumDriverInfo(DeviceInfoSet, DeviceInfoData, DriverType, MemberIndex)
+}
+
+//sys  setupDiGetSelectedDriver(DeviceInfoSet DevInfo, DeviceInfoData *SP_DEVINFO_DATA, DriverInfoData *SP_DRVINFO_DATA) (err error) = setupapi.SetupDiGetSelectedDriverW
+
+// SetupDiGetSelectedDriver function retrieves the selected driver for a device information set or a particular device information element.
+func SetupDiGetSelectedDriver(DeviceInfoSet DevInfo, DeviceInfoData *SP_DEVINFO_DATA) (DriverInfoData *SP_DRVINFO_DATA, err error) {
+       data := &SP_DRVINFO_DATA{}
+       data.Size = uint32(unsafe.Sizeof(*data))
+
+       return data, setupDiGetSelectedDriver(DeviceInfoSet, DeviceInfoData, data)
+}
+
+// GetSelectedDriver method retrieves the selected driver for a device information set or a particular device information element.
+func (DeviceInfoSet DevInfo) GetSelectedDriver(DeviceInfoData *SP_DEVINFO_DATA) (DriverInfoData *SP_DRVINFO_DATA, err error) {
+       return SetupDiGetSelectedDriver(DeviceInfoSet, DeviceInfoData)
+}
+
+//sys  SetupDiSetSelectedDriver(DeviceInfoSet DevInfo, DeviceInfoData *SP_DEVINFO_DATA, DriverInfoData *SP_DRVINFO_DATA) (err error) = setupapi.SetupDiSetSelectedDriverW
+
+// SetSelectedDriver method sets, or resets, the selected driver for a device information element or the selected class driver for a device information set.
+func (DeviceInfoSet DevInfo) SetSelectedDriver(DeviceInfoData *SP_DEVINFO_DATA, DriverInfoData *SP_DRVINFO_DATA) (err error) {
+       return SetupDiSetSelectedDriver(DeviceInfoSet, DeviceInfoData, DriverInfoData)
+}
+
+//sys  setupDiGetDriverInfoDetail(DeviceInfoSet DevInfo, DeviceInfoData *SP_DEVINFO_DATA, DriverInfoData *SP_DRVINFO_DATA, DriverInfoDetailData *_SP_DRVINFO_DETAIL_DATA, DriverInfoDetailDataSize uint32, RequiredSize *uint32) (err error) = setupapi.SetupDiGetDriverInfoDetailW
+
+// SetupDiGetDriverInfoDetail function retrieves driver information detail for a device information set or a particular device information element in the device information set.
+func SetupDiGetDriverInfoDetail(DeviceInfoSet DevInfo, DeviceInfoData *SP_DEVINFO_DATA, DriverInfoData *SP_DRVINFO_DATA) (DriverInfoDetailData *DrvInfoDetailData, err error) {
+       const bufCapacity = 0x800
+       buf := [bufCapacity]byte{}
+       var bufLen uint32
+
+       _data := (*_SP_DRVINFO_DETAIL_DATA)(unsafe.Pointer(&buf[0]))
+       _data.Size = uint32(unsafe.Sizeof(*_data))
+
+       err = setupDiGetDriverInfoDetail(DeviceInfoSet, DeviceInfoData, DriverInfoData, _data, bufCapacity, &bufLen)
+       if err == nil {
+               // The buffer was was sufficiently big.
+               return _data.toGo(bufLen), nil
+       }
+
+       if errWin, ok := err.(syscall.Errno); ok && errWin == windows.ERROR_INSUFFICIENT_BUFFER {
+               // The buffer was too small. Now that we got the required size, create another one big enough and retry.
+               buf := make([]byte, bufLen)
+               _data := (*_SP_DRVINFO_DETAIL_DATA)(unsafe.Pointer(&buf[0]))
+               _data.Size = uint32(unsafe.Sizeof(*_data))
+
+               err = setupDiGetDriverInfoDetail(DeviceInfoSet, DeviceInfoData, DriverInfoData, _data, bufLen, &bufLen)
+               if err == nil {
+                       return _data.toGo(bufLen), nil
+               }
+       }
+
+       return
+}
+
+// GetDriverInfoDetail method retrieves driver information detail for a device information set or a particular device information element in the device information set.
+func (DeviceInfoSet DevInfo) GetDriverInfoDetail(DeviceInfoData *SP_DEVINFO_DATA, DriverInfoData *SP_DRVINFO_DATA) (DriverInfoDetailData *DrvInfoDetailData, err error) {
+       return SetupDiGetDriverInfoDetail(DeviceInfoSet, DeviceInfoData, DriverInfoData)
+}
+
+//sys  SetupDiDestroyDriverInfoList(DeviceInfoSet DevInfo, DeviceInfoData *SP_DEVINFO_DATA, DriverType SPDIT) (err error) = setupapi.SetupDiDestroyDriverInfoList
+
+// DestroyDriverInfoList method deletes a driver list.
+func (DeviceInfoSet DevInfo) DestroyDriverInfoList(DeviceInfoData *SP_DEVINFO_DATA, DriverType SPDIT) (err error) {
+       return SetupDiDestroyDriverInfoList(DeviceInfoSet, DeviceInfoData, DriverType)
+}
+
 //sys  setupDiGetClassDevsEx(ClassGUID *windows.GUID, Enumerator *uint16, hwndParent uintptr, Flags DIGCF, DeviceInfoSet DevInfo, MachineName *uint16, reserved uintptr) (handle DevInfo, err error) [failretval==DevInfo(windows.InvalidHandle)] = setupapi.SetupDiGetClassDevsExW
 
 // SetupDiGetClassDevsEx function returns a handle to a device information set that contains requested device information elements for a local or a remote computer.
index 93ae42a219fa6446267efa79759d2b7a16ddd7b2..12b5fe12f287967abea858191341a5b4b90bcb0f 100644 (file)
@@ -136,6 +136,69 @@ func TestSetupDiEnumDeviceInfo(t *testing.T) {
        }
 }
 
+func TestDevInfo_BuildDriverInfoList(t *testing.T) {
+       devInfoList, err := SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, DIGCF_PRESENT, DevInfo(0), "")
+       if err != nil {
+               t.Errorf("Error calling SetupDiGetClassDevsEx: %s", err.Error())
+       }
+       defer devInfoList.Close()
+
+       for i := 0; true; i++ {
+               deviceData, err := devInfoList.EnumDeviceInfo(i)
+               if err != nil {
+                       if errWin, ok := err.(syscall.Errno); ok && errWin == 259 /*ERROR_NO_MORE_ITEMS*/ {
+                               break
+                       }
+                       continue
+               }
+
+               const driverType SPDIT = SPDIT_COMPATDRIVER
+               err = devInfoList.BuildDriverInfoList(deviceData, driverType)
+               if err != nil {
+                       t.Errorf("Error calling SetupDiBuildDriverInfoList: %s", err.Error())
+               }
+               defer devInfoList.DestroyDriverInfoList(deviceData, driverType)
+
+               var selectedDriverData *SP_DRVINFO_DATA
+               for j := 0; true; j++ {
+                       driverData, err := devInfoList.EnumDriverInfo(deviceData, driverType, j)
+                       if err != nil {
+                               if errWin, ok := err.(syscall.Errno); ok && errWin == 259 /*ERROR_NO_MORE_ITEMS*/ {
+                                       break
+                               }
+                               continue
+                       }
+
+                       if driverData2, err2 := driverData.ToGo().ToWindows(); err2 != nil || *driverData2 != *driverData {
+                               t.Error("Error converting between SP_DRVINFO_DATA and DrvInfoData")
+                       }
+
+                       if driverData.DriverType == 0 {
+                               continue
+                       }
+
+                       err = devInfoList.SetSelectedDriver(deviceData, driverData)
+                       if err != nil {
+                               t.Errorf("Error calling SetupDiSetSelectedDriver: %s", err.Error())
+                       } else {
+                               selectedDriverData = driverData
+                       }
+
+                       _, err = devInfoList.GetDriverInfoDetail(deviceData, driverData)
+                       if err != nil {
+                               t.Errorf("Error calling SetupDiGetDriverInfoDetail: %s", err.Error())
+                       }
+               }
+
+               selectedDriverData2, err := devInfoList.GetSelectedDriver(deviceData)
+               if err != nil {
+                       t.Errorf("Error calling SetupDiGetSelectedDriver: %s", err.Error())
+               } else if *selectedDriverData != *selectedDriverData2 {
+                       t.Error("SetupDiGetSelectedDriver should return driver selected with SetupDiSetSelectedDriver")
+               }
+       }
+}
+
 func TestSetupDiGetClassDevsEx(t *testing.T) {
        devInfoList, err := SetupDiGetClassDevsEx(&deviceClassNetGUID, "PCI", 0, DIGCF_PRESENT, DevInfo(0), computerName)
        if err == nil {
index 9bbe38b67e04ea8e828da9c2eb899ceda52786d7..0eb640ca8d236077771d150d1ed4fc87f5fa43f2 100644 (file)
@@ -23,6 +23,20 @@ const (
        CONFIGMG_VERSION    = 0x0400
 )
 
+//
+// Define maximum string length constants
+//
+const (
+       LINE_LEN                    = 256  // Windows 9x-compatible maximum for displayable strings coming from a device INF.
+       MAX_INF_STRING_LENGTH       = 4096 // Actual maximum size of an INF string (including string substitutions).
+       MAX_INF_SECTION_NAME_LENGTH = 255  // For Windows 9x compatibility, INF section names should be constrained to 32 characters.
+       MAX_TITLE_LEN               = 60
+       MAX_INSTRUCTION_LEN         = 256
+       MAX_LABEL_LEN               = 30
+       MAX_SERVICE_NAME_LEN        = 256
+       MAX_SUBTITLE_LEN            = 256
+)
+
 const (
        // SP_MAX_MACHINENAME_LENGTH defines maximum length of a machine name in the format expected by ConfigMgr32 CM_Connect_Machine (i.e., "\\\\MachineName\0").
        SP_MAX_MACHINENAME_LENGTH = windows.MAX_PATH + 3
@@ -285,6 +299,128 @@ const (
        DICS_FLAG_CONFIGGENERAL  DICS_FLAG = 0x00000004 // 1 or more hardware profile-specific changes to follow
 )
 
+type SP_DRVINFO_DATA struct {
+       Size          uint32
+       DriverType    uint32
+       _             uintptr
+       Description   [LINE_LEN]uint16
+       MfgName       [LINE_LEN]uint16
+       ProviderName  [LINE_LEN]uint16
+       DriverDate    windows.Filetime
+       DriverVersion uint64
+}
+
+func (data SP_DRVINFO_DATA) ToGo() *DrvInfoData {
+       return &DrvInfoData{
+               DriverType:    data.DriverType,
+               Description:   windows.UTF16ToString(data.Description[:]),
+               MfgName:       windows.UTF16ToString(data.MfgName[:]),
+               ProviderName:  windows.UTF16ToString(data.ProviderName[:]),
+               DriverDate:    data.DriverDate,
+               DriverVersion: data.DriverVersion,
+       }
+}
+
+// DrvInfoData is driver information structure (member of a driver info list that may be associated with a particular device instance, or (globally) with a device information set)
+type DrvInfoData struct {
+       DriverType    uint32
+       Description   string
+       MfgName       string
+       ProviderName  string
+       DriverDate    windows.Filetime
+       DriverVersion uint64
+}
+
+func (DriverInfoData DrvInfoData) ToWindows() (data *SP_DRVINFO_DATA, err error) {
+       data = &SP_DRVINFO_DATA{
+               DriverType:    DriverInfoData.DriverType,
+               DriverDate:    DriverInfoData.DriverDate,
+               DriverVersion: DriverInfoData.DriverVersion,
+       }
+       data.Size = uint32(unsafe.Sizeof(*data))
+
+       DescriptionUTF16, err := syscall.UTF16FromString(DriverInfoData.Description)
+       if err != nil {
+               return
+       }
+       copy(data.Description[:], DescriptionUTF16)
+
+       MfgNameUTF16, err := syscall.UTF16FromString(DriverInfoData.MfgName)
+       if err != nil {
+               return
+       }
+       copy(data.MfgName[:], MfgNameUTF16)
+
+       ProviderNameUTF16, err := syscall.UTF16FromString(DriverInfoData.ProviderName)
+       if err != nil {
+               return
+       }
+       copy(data.ProviderName[:], ProviderNameUTF16)
+
+       return
+}
+
+type _SP_DRVINFO_DETAIL_DATA struct {
+       Size            uint32
+       InfDate         windows.Filetime
+       CompatIDsOffset uint32
+       CompatIDsLength uint32
+       _               uintptr
+       SectionName     [LINE_LEN]uint16
+       InfFileName     [windows.MAX_PATH]uint16
+       DrvDescription  [LINE_LEN]uint16
+       HardwareID      [1]uint16
+}
+
+func (_data _SP_DRVINFO_DETAIL_DATA) toGo(bufLen uint32) (DriverInfoDetailData *DrvInfoDetailData) {
+       DriverInfoDetailData = &DrvInfoDetailData{
+               InfDate:        _data.InfDate,
+               SectionName:    windows.UTF16ToString(_data.SectionName[:]),
+               InfFileName:    windows.UTF16ToString(_data.InfFileName[:]),
+               DrvDescription: windows.UTF16ToString(_data.DrvDescription[:]),
+               CompatIDs:      []string{},
+       }
+
+       bufW := _data.getBuf(bufLen)
+
+       if _data.CompatIDsOffset > 1 {
+               DriverInfoDetailData.HardwareID = windows.UTF16ToString(bufW[:wcslen(bufW)])
+       }
+
+       if _data.CompatIDsLength > 0 {
+               bufW = bufW[_data.CompatIDsOffset : _data.CompatIDsOffset+_data.CompatIDsLength]
+               for i := 0; i < len(bufW); {
+                       j := i + wcslen(bufW[i:])
+                       if i < j {
+                               DriverInfoDetailData.CompatIDs = append(DriverInfoDetailData.CompatIDs, windows.UTF16ToString(bufW[i:j]))
+                       }
+                       i = j + 1
+               }
+       }
+
+       return
+}
+
+func (_data _SP_DRVINFO_DETAIL_DATA) getBuf(bufLen uint32) []uint16 {
+       len := (bufLen - uint32(unsafe.Offsetof(_data.HardwareID))) / 2
+       sl := struct {
+               addr *uint16
+               len  int
+               cap  int
+       }{&_data.HardwareID[0], int(len), int(len)}
+       return *(*[]uint16)(unsafe.Pointer(&sl))
+}
+
+// DrvInfoDetailData is driver information details structure (provides detailed information about a particular driver information structure)
+type DrvInfoDetailData struct {
+       InfDate        windows.Filetime
+       SectionName    string
+       InfFileName    string
+       DrvDescription string
+       HardwareID     string
+       CompatIDs      []string
+}
+
 // DICD flags control SetupDiCreateDeviceInfo
 type DICD uint32
 
@@ -293,6 +429,19 @@ const (
        DICD_INHERIT_CLASSDRVS DICD = 0x00000002
 )
 
+//
+// SPDIT flags to distinguish between class drivers and
+// device drivers.
+// (Passed in 'DriverType' parameter of driver information list APIs)
+//
+type SPDIT uint32
+
+const (
+       SPDIT_NODRIVER     SPDIT = 0x00000000
+       SPDIT_CLASSDRIVER  SPDIT = 0x00000001
+       SPDIT_COMPATDRIVER SPDIT = 0x00000002
+)
+
 // DIGCF flags control what is included in the device information set built by SetupDiGetClassDevs
 type DIGCF uint32
 
index c9aa72aed1609b494b6f7d2ec4e8a09443697bc2..7e681f5baad9ad02736d84541c3c1899abc2537b 100644 (file)
@@ -44,6 +44,13 @@ var (
        procSetupDiCreateDeviceInfoW          = modsetupapi.NewProc("SetupDiCreateDeviceInfoW")
        procSetupDiEnumDeviceInfo             = modsetupapi.NewProc("SetupDiEnumDeviceInfo")
        procSetupDiDestroyDeviceInfoList      = modsetupapi.NewProc("SetupDiDestroyDeviceInfoList")
+       procSetupDiBuildDriverInfoList        = modsetupapi.NewProc("SetupDiBuildDriverInfoList")
+       procSetupDiCancelDriverInfoSearch     = modsetupapi.NewProc("SetupDiCancelDriverInfoSearch")
+       procSetupDiEnumDriverInfoW            = modsetupapi.NewProc("SetupDiEnumDriverInfoW")
+       procSetupDiGetSelectedDriverW         = modsetupapi.NewProc("SetupDiGetSelectedDriverW")
+       procSetupDiSetSelectedDriverW         = modsetupapi.NewProc("SetupDiSetSelectedDriverW")
+       procSetupDiGetDriverInfoDetailW       = modsetupapi.NewProc("SetupDiGetDriverInfoDetailW")
+       procSetupDiDestroyDriverInfoList      = modsetupapi.NewProc("SetupDiDestroyDriverInfoList")
        procSetupDiGetClassDevsExW            = modsetupapi.NewProc("SetupDiGetClassDevsExW")
        procSetupDiCallClassInstaller         = modsetupapi.NewProc("SetupDiCallClassInstaller")
        procSetupDiOpenDevRegKey              = modsetupapi.NewProc("SetupDiOpenDevRegKey")
@@ -120,6 +127,90 @@ func SetupDiDestroyDeviceInfoList(DeviceInfoSet DevInfo) (err error) {
        return
 }
 
+func SetupDiBuildDriverInfoList(DeviceInfoSet DevInfo, DeviceInfoData *SP_DEVINFO_DATA, DriverType SPDIT) (err error) {
+       r1, _, e1 := syscall.Syscall(procSetupDiBuildDriverInfoList.Addr(), 3, uintptr(DeviceInfoSet), uintptr(unsafe.Pointer(DeviceInfoData)), uintptr(DriverType))
+       if r1 == 0 {
+               if e1 != 0 {
+                       err = errnoErr(e1)
+               } else {
+                       err = syscall.EINVAL
+               }
+       }
+       return
+}
+
+func SetupDiCancelDriverInfoSearch(DeviceInfoSet DevInfo) (err error) {
+       r1, _, e1 := syscall.Syscall(procSetupDiCancelDriverInfoSearch.Addr(), 1, uintptr(DeviceInfoSet), 0, 0)
+       if r1 == 0 {
+               if e1 != 0 {
+                       err = errnoErr(e1)
+               } else {
+                       err = syscall.EINVAL
+               }
+       }
+       return
+}
+
+func setupDiEnumDriverInfo(DeviceInfoSet DevInfo, DeviceInfoData *SP_DEVINFO_DATA, DriverType SPDIT, MemberIndex uint32, DriverInfoData *SP_DRVINFO_DATA) (err error) {
+       r1, _, e1 := syscall.Syscall6(procSetupDiEnumDriverInfoW.Addr(), 5, uintptr(DeviceInfoSet), uintptr(unsafe.Pointer(DeviceInfoData)), uintptr(DriverType), uintptr(MemberIndex), uintptr(unsafe.Pointer(DriverInfoData)), 0)
+       if r1 == 0 {
+               if e1 != 0 {
+                       err = errnoErr(e1)
+               } else {
+                       err = syscall.EINVAL
+               }
+       }
+       return
+}
+
+func setupDiGetSelectedDriver(DeviceInfoSet DevInfo, DeviceInfoData *SP_DEVINFO_DATA, DriverInfoData *SP_DRVINFO_DATA) (err error) {
+       r1, _, e1 := syscall.Syscall(procSetupDiGetSelectedDriverW.Addr(), 3, uintptr(DeviceInfoSet), uintptr(unsafe.Pointer(DeviceInfoData)), uintptr(unsafe.Pointer(DriverInfoData)))
+       if r1 == 0 {
+               if e1 != 0 {
+                       err = errnoErr(e1)
+               } else {
+                       err = syscall.EINVAL
+               }
+       }
+       return
+}
+
+func SetupDiSetSelectedDriver(DeviceInfoSet DevInfo, DeviceInfoData *SP_DEVINFO_DATA, DriverInfoData *SP_DRVINFO_DATA) (err error) {
+       r1, _, e1 := syscall.Syscall(procSetupDiSetSelectedDriverW.Addr(), 3, uintptr(DeviceInfoSet), uintptr(unsafe.Pointer(DeviceInfoData)), uintptr(unsafe.Pointer(DriverInfoData)))
+       if r1 == 0 {
+               if e1 != 0 {
+                       err = errnoErr(e1)
+               } else {
+                       err = syscall.EINVAL
+               }
+       }
+       return
+}
+
+func setupDiGetDriverInfoDetail(DeviceInfoSet DevInfo, DeviceInfoData *SP_DEVINFO_DATA, DriverInfoData *SP_DRVINFO_DATA, DriverInfoDetailData *_SP_DRVINFO_DETAIL_DATA, DriverInfoDetailDataSize uint32, RequiredSize *uint32) (err error) {
+       r1, _, e1 := syscall.Syscall6(procSetupDiGetDriverInfoDetailW.Addr(), 6, uintptr(DeviceInfoSet), uintptr(unsafe.Pointer(DeviceInfoData)), uintptr(unsafe.Pointer(DriverInfoData)), uintptr(unsafe.Pointer(DriverInfoDetailData)), uintptr(DriverInfoDetailDataSize), uintptr(unsafe.Pointer(RequiredSize)))
+       if r1 == 0 {
+               if e1 != 0 {
+                       err = errnoErr(e1)
+               } else {
+                       err = syscall.EINVAL
+               }
+       }
+       return
+}
+
+func SetupDiDestroyDriverInfoList(DeviceInfoSet DevInfo, DeviceInfoData *SP_DEVINFO_DATA, DriverType SPDIT) (err error) {
+       r1, _, e1 := syscall.Syscall(procSetupDiDestroyDriverInfoList.Addr(), 3, uintptr(DeviceInfoSet), uintptr(unsafe.Pointer(DeviceInfoData)), uintptr(DriverType))
+       if r1 == 0 {
+               if e1 != 0 {
+                       err = errnoErr(e1)
+               } else {
+                       err = syscall.EINVAL
+               }
+       }
+       return
+}
+
 func setupDiGetClassDevsEx(ClassGUID *windows.GUID, Enumerator *uint16, hwndParent uintptr, Flags DIGCF, DeviceInfoSet DevInfo, MachineName *uint16, reserved uintptr) (handle DevInfo, err error) {
        r0, _, e1 := syscall.Syscall9(procSetupDiGetClassDevsExW.Addr(), 7, uintptr(unsafe.Pointer(ClassGUID)), uintptr(unsafe.Pointer(Enumerator)), uintptr(hwndParent), uintptr(Flags), uintptr(DeviceInfoSet), uintptr(unsafe.Pointer(MachineName)), uintptr(reserved), 0, 0)
        handle = DevInfo(r0)