2019-01-31 15:20:11 +01:00
/ * SPDX - License - Identifier : MIT
*
* Copyright ( C ) 2019 WireGuard LLC . All Rights Reserved .
* /
package setupapi
import (
2019-02-01 10:58:06 +01:00
"syscall"
2019-02-01 11:39:57 +01:00
"unsafe"
2019-02-01 10:58:06 +01:00
2019-01-31 15:20:11 +01:00
"golang.org/x/sys/windows"
2019-02-01 13:00:44 +01:00
"golang.org/x/sys/windows/registry"
2019-01-31 15:20:11 +01:00
)
2019-02-04 08:39:31 +01:00
//sys setupDiClassNameFromGuidEx(ClassGUID *windows.GUID, ClassName *uint16, ClassNameSize uint32, RequiredSize *uint32, MachineName *uint16, Reserved uintptr) (err error) = setupapi.SetupDiClassNameFromGuidExW
2019-02-04 09:36:42 +01:00
//sys setupDiClassGuidsFromNameEx(ClassName *uint16, ClassGuidList *windows.GUID, ClassGuidListSize uint32, RequiredSize *uint32, MachineName *uint16, Reserved uintptr) (err error) = setupapi.SetupDiClassGuidsFromNameExW
2019-02-04 11:49:26 +01:00
//sys setupDiCreateDeviceInfoListEx(ClassGUID *windows.GUID, hwndParent uintptr, MachineName *uint16, Reserved uintptr) (handle DevInfo, err error) [failretval==DevInfo(windows.InvalidHandle)] = setupapi.SetupDiCreateDeviceInfoListExW
2019-02-01 11:39:57 +01:00
//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
2019-02-01 10:58:06 +01:00
//sys SetupDiDestroyDeviceInfoList(DeviceInfoSet DevInfo) (err error) = setupapi.SetupDiDestroyDeviceInfoList
2019-02-01 12:17:09 +01:00
//sys setupDiGetDeviceInfoListDetail(DeviceInfoSet DevInfo, DeviceInfoSetDetailData *_SP_DEVINFO_LIST_DETAIL_DATA) (err error) = setupapi.SetupDiGetDeviceInfoListDetailW
2019-02-01 13:00:44 +01:00
//sys setupDiEnumDeviceInfo(DeviceInfoSet DevInfo, MemberIndex uint32, DeviceInfoData *SP_DEVINFO_DATA) (err error) = setupapi.SetupDiEnumDeviceInfo
//sys setupDiOpenDevRegKey(DeviceInfoSet DevInfo, DeviceInfoData *SP_DEVINFO_DATA, Scope DICS_FLAG, HwProfile uint32, KeyType DIREG, samDesired uint32) (key windows.Handle, err error) [failretval==windows.InvalidHandle] = setupapi.SetupDiOpenDevRegKey
2019-02-01 13:59:53 +01:00
//sys setupDiGetDeviceInstallParams(DeviceInfoSet DevInfo, DeviceInfoData *SP_DEVINFO_DATA, DeviceInstallParams *_SP_DEVINSTALL_PARAMS) (err error) = setupapi.SetupDiGetDeviceInstallParamsW
//sys setupDiSetDeviceInstallParams(DeviceInfoSet DevInfo, DeviceInfoData *SP_DEVINFO_DATA, DeviceInstallParams *_SP_DEVINSTALL_PARAMS) (err error) = setupapi.SetupDiSetDeviceInstallParamsW
2019-02-01 14:58:59 +01:00
//sys SetupDiGetClassInstallParams(DeviceInfoSet DevInfo, DeviceInfoData *SP_DEVINFO_DATA, ClassInstallParams *SP_CLASSINSTALL_HEADER, ClassInstallParamsSize uint32, RequiredSize *uint32) (err error) = setupapi.SetupDiGetClassInstallParamsW
//sys SetupDiSetClassInstallParams(DeviceInfoSet DevInfo, DeviceInfoData *SP_DEVINFO_DATA, ClassInstallParams *SP_CLASSINSTALL_HEADER, ClassInstallParamsSize uint32) (err error) = setupapi.SetupDiSetClassInstallParamsW
2019-02-04 07:50:30 +01:00
//sys SetupDiCallClassInstaller(InstallFunction DI_FUNCTION, DeviceInfoSet DevInfo, DeviceInfoData *SP_DEVINFO_DATA) (err error) = setupapi.SetupDiCallClassInstaller
2019-01-31 15:20:11 +01:00
2019-02-04 08:39:31 +01:00
// SetupDiClassNameFromGuidEx function retrieves the class name associated with a class GUID. The class can be installed on a local or remote computer.
func SetupDiClassNameFromGuidEx ( ClassGUID * windows . GUID , MachineName string ) ( ClassName string , err error ) {
2019-02-04 09:51:19 +01:00
var classNameUTF16 [ MAX_CLASS_NAME_LEN ] uint16
2019-02-04 08:23:55 +01:00
2019-02-04 09:51:19 +01:00
var machineNameUTF16 * uint16
2019-02-04 08:39:31 +01:00
if MachineName != "" {
2019-02-04 09:51:19 +01:00
machineNameUTF16 , err = syscall . UTF16PtrFromString ( MachineName )
2019-02-04 08:39:31 +01:00
if err != nil {
return
}
}
2019-02-04 09:51:19 +01:00
err = setupDiClassNameFromGuidEx ( ClassGUID , & classNameUTF16 [ 0 ] , MAX_CLASS_NAME_LEN , nil , machineNameUTF16 , 0 )
2019-02-04 08:23:55 +01:00
if err != nil {
return
}
2019-02-04 09:51:19 +01:00
ClassName = windows . UTF16ToString ( classNameUTF16 [ : ] )
2019-02-04 08:23:55 +01:00
return
}
2019-02-04 09:36:42 +01:00
// SetupDiClassGuidsFromNameEx function retrieves the GUIDs associated with the specified class name. This resulting list contains the classes currently installed on a local or remote computer.
func SetupDiClassGuidsFromNameEx ( ClassName string , MachineName string ) ( ClassGuidList [ ] windows . GUID , err error ) {
2019-02-04 09:51:19 +01:00
classNameUTF16 , err := syscall . UTF16PtrFromString ( ClassName )
2019-02-04 09:36:42 +01:00
if err != nil {
return
}
2019-02-04 09:51:19 +01:00
const bufLen = 4
var buf [ bufLen ] windows . GUID
var bufCount uint32
2019-02-04 09:36:42 +01:00
2019-02-04 09:51:19 +01:00
var machineNameUTF16 * uint16
2019-02-04 09:36:42 +01:00
if MachineName != "" {
2019-02-04 09:51:19 +01:00
machineNameUTF16 , err = syscall . UTF16PtrFromString ( MachineName )
2019-02-04 09:36:42 +01:00
if err != nil {
return
}
}
2019-02-04 09:51:19 +01:00
err = setupDiClassGuidsFromNameEx ( classNameUTF16 , & buf [ 0 ] , bufLen , & bufCount , machineNameUTF16 , 0 )
2019-02-04 09:36:42 +01:00
if err == nil {
// The GUID array was sufficiently big. Return its slice.
2019-02-04 09:51:19 +01:00
return buf [ : bufCount ] , nil
2019-02-04 09:36:42 +01:00
}
if errWin , ok := err . ( syscall . Errno ) ; ok && errWin == windows . ERROR_INSUFFICIENT_BUFFER {
// The GUID array was too small. Now that we got the required size, create another one big enough and retry.
2019-02-04 09:51:19 +01:00
buf := make ( [ ] windows . GUID , bufCount )
err = setupDiClassGuidsFromNameEx ( classNameUTF16 , & buf [ 0 ] , bufCount , & bufCount , machineNameUTF16 , 0 )
2019-02-04 09:36:42 +01:00
if err == nil {
2019-02-04 09:51:19 +01:00
return buf [ : bufCount ] , nil
2019-02-04 09:36:42 +01:00
}
}
return
}
2019-02-04 11:49:26 +01:00
// SetupDiCreateDeviceInfoListEx function creates an empty device information set on a remote or a local computer and optionally associates the set with a device setup class.
func SetupDiCreateDeviceInfoListEx ( ClassGUID * windows . GUID , hwndParent uintptr , MachineName string ) ( handle DevInfo , err error ) {
var machineNameUTF16 * uint16
if MachineName != "" {
machineNameUTF16 , err = syscall . UTF16PtrFromString ( MachineName )
if err != nil {
return
}
}
return setupDiCreateDeviceInfoListEx ( ClassGUID , hwndParent , machineNameUTF16 , 0 )
}
2019-02-01 11:39:57 +01:00
// SetupDiGetClassDevsEx function returns a handle to a device information set that contains requested device information elements for a local or a remote computer.
func SetupDiGetClassDevsEx ( ClassGUID * windows . GUID , Enumerator string , hwndParent uintptr , Flags DIGCF , DeviceInfoSet DevInfo , MachineName string ) ( handle DevInfo , err error ) {
2019-02-04 09:51:19 +01:00
var enumeratorUTF16 * uint16
2019-02-01 10:58:06 +01:00
if Enumerator != "" {
2019-02-04 09:51:19 +01:00
enumeratorUTF16 , err = syscall . UTF16PtrFromString ( Enumerator )
2019-02-01 10:58:06 +01:00
if err != nil {
return
}
}
2019-02-04 09:51:19 +01:00
var machineNameUTF16 * uint16
2019-02-01 10:58:06 +01:00
if MachineName != "" {
2019-02-04 09:51:19 +01:00
machineNameUTF16 , err = syscall . UTF16PtrFromString ( MachineName )
2019-02-01 10:58:06 +01:00
if err != nil {
return
}
}
2019-02-04 09:51:19 +01:00
return setupDiGetClassDevsEx ( ClassGUID , enumeratorUTF16 , hwndParent , Flags , DeviceInfoSet , machineNameUTF16 , 0 )
2019-02-01 11:39:57 +01:00
}
// SetupDiGetDeviceInfoListDetail function retrieves information associated with a device information set including the class GUID, remote computer handle, and remote computer name.
2019-02-04 11:42:51 +01:00
func SetupDiGetDeviceInfoListDetail ( DeviceInfoSet DevInfo ) ( DeviceInfoSetDetailData * DevInfoListDetailData , err error ) {
2019-02-04 09:51:19 +01:00
var _data _SP_DEVINFO_LIST_DETAIL_DATA
_data . Size = uint32 ( unsafe . Sizeof ( _data ) )
2019-02-01 11:39:57 +01:00
2019-02-04 09:51:19 +01:00
err = setupDiGetDeviceInfoListDetail ( DeviceInfoSet , & _data )
2019-02-01 11:39:57 +01:00
if err != nil {
return
}
2019-02-04 11:42:51 +01:00
return & DevInfoListDetailData {
2019-02-04 09:51:19 +01:00
ClassGUID : _data . ClassGUID ,
RemoteMachineHandle : _data . RemoteMachineHandle ,
RemoteMachineName : windows . UTF16ToString ( _data . RemoteMachineName [ : ] ) ,
2019-02-04 11:42:51 +01:00
} , nil
2019-01-31 15:20:11 +01:00
}
2019-02-01 12:17:09 +01:00
// SetupDiEnumDeviceInfo function returns a SP_DEVINFO_DATA structure that specifies a device information element in a device information set.
2019-02-04 11:40:44 +01:00
func SetupDiEnumDeviceInfo ( DeviceInfoSet DevInfo , MemberIndex int ) ( DeviceInfoData * SP_DEVINFO_DATA , err error ) {
data := SP_DEVINFO_DATA { }
data . Size = uint32 ( unsafe . Sizeof ( data ) )
return & data , setupDiEnumDeviceInfo ( DeviceInfoSet , uint32 ( MemberIndex ) , & data )
2019-02-01 13:00:44 +01:00
}
2019-02-01 12:17:09 +01:00
2019-02-01 13:00:44 +01:00
// SetupDiOpenDevRegKey function opens a registry key for device-specific configuration information.
func SetupDiOpenDevRegKey ( DeviceInfoSet DevInfo , DeviceInfoData * SP_DEVINFO_DATA , Scope DICS_FLAG , HwProfile uint32 , KeyType DIREG , samDesired uint32 ) ( key registry . Key , err error ) {
handle , err := setupDiOpenDevRegKey ( DeviceInfoSet , DeviceInfoData , Scope , HwProfile , KeyType , samDesired )
return registry . Key ( handle ) , err
2019-02-01 12:17:09 +01:00
}
2019-02-01 13:59:53 +01:00
// SetupDiGetDeviceInstallParams function retrieves device installation parameters for a device information set or a particular device information element.
2019-02-04 11:42:51 +01:00
func SetupDiGetDeviceInstallParams ( DeviceInfoSet DevInfo , DeviceInfoData * SP_DEVINFO_DATA ) ( DeviceInstallParams * DevInstallParams , err error ) {
2019-02-04 09:51:19 +01:00
var _data _SP_DEVINSTALL_PARAMS
_data . Size = uint32 ( unsafe . Sizeof ( _data ) )
2019-02-01 13:59:53 +01:00
2019-02-04 09:51:19 +01:00
err = setupDiGetDeviceInstallParams ( DeviceInfoSet , DeviceInfoData , & _data )
2019-02-01 13:59:53 +01:00
if err != nil {
return
}
2019-02-04 11:42:51 +01:00
return & DevInstallParams {
2019-02-04 09:51:19 +01:00
Flags : _data . Flags ,
FlagsEx : _data . FlagsEx ,
hwndParent : _data . hwndParent ,
InstallMsgHandler : _data . InstallMsgHandler ,
InstallMsgHandlerContext : _data . InstallMsgHandlerContext ,
FileQueue : _data . FileQueue ,
DriverPath : windows . UTF16ToString ( _data . DriverPath [ : ] ) ,
2019-02-04 11:42:51 +01:00
} , nil
2019-02-01 13:59:53 +01:00
}
// SetupDiSetDeviceInstallParams function sets device installation parameters for a device information set or a particular device information element.
func SetupDiSetDeviceInstallParams ( DeviceInfoSet DevInfo , DeviceInfoData * SP_DEVINFO_DATA , DeviceInstallParams * DevInstallParams ) ( err error ) {
2019-02-04 09:51:19 +01:00
_data := _SP_DEVINSTALL_PARAMS {
2019-02-01 13:59:53 +01:00
Flags : DeviceInstallParams . Flags ,
FlagsEx : DeviceInstallParams . FlagsEx ,
hwndParent : DeviceInstallParams . hwndParent ,
InstallMsgHandler : DeviceInstallParams . InstallMsgHandler ,
InstallMsgHandlerContext : DeviceInstallParams . InstallMsgHandlerContext ,
FileQueue : DeviceInstallParams . FileQueue ,
}
2019-02-04 09:51:19 +01:00
_data . Size = uint32 ( unsafe . Sizeof ( _data ) )
2019-02-01 13:59:53 +01:00
2019-02-04 09:51:19 +01:00
driverPathUTF16 , err := syscall . UTF16FromString ( DeviceInstallParams . DriverPath )
2019-02-01 13:59:53 +01:00
if err != nil {
return
}
2019-02-04 09:51:19 +01:00
copy ( _data . DriverPath [ : ] , driverPathUTF16 )
2019-02-01 13:59:53 +01:00
2019-02-04 09:51:19 +01:00
return setupDiSetDeviceInstallParams ( DeviceInfoSet , DeviceInfoData , & _data )
2019-02-01 13:59:53 +01:00
}