1// Copyright 2021 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package windows
6
7import (
8	"encoding/binary"
9	"errors"
10	"fmt"
11	"runtime"
12	"strings"
13	"syscall"
14	"unsafe"
15)
16
17// This file contains functions that wrap SetupAPI.dll and CfgMgr32.dll,
18// core system functions for managing hardware devices, drivers, and the PnP tree.
19// Information about these APIs can be found at:
20//     https://docs.microsoft.com/en-us/windows-hardware/drivers/install/setupapi
21//     https://docs.microsoft.com/en-us/windows/win32/devinst/cfgmgr32-
22
23const (
24	ERROR_EXPECTED_SECTION_NAME                  Errno = 0x20000000 | 0xC0000000 | 0
25	ERROR_BAD_SECTION_NAME_LINE                  Errno = 0x20000000 | 0xC0000000 | 1
26	ERROR_SECTION_NAME_TOO_LONG                  Errno = 0x20000000 | 0xC0000000 | 2
27	ERROR_GENERAL_SYNTAX                         Errno = 0x20000000 | 0xC0000000 | 3
28	ERROR_WRONG_INF_STYLE                        Errno = 0x20000000 | 0xC0000000 | 0x100
29	ERROR_SECTION_NOT_FOUND                      Errno = 0x20000000 | 0xC0000000 | 0x101
30	ERROR_LINE_NOT_FOUND                         Errno = 0x20000000 | 0xC0000000 | 0x102
31	ERROR_NO_BACKUP                              Errno = 0x20000000 | 0xC0000000 | 0x103
32	ERROR_NO_ASSOCIATED_CLASS                    Errno = 0x20000000 | 0xC0000000 | 0x200
33	ERROR_CLASS_MISMATCH                         Errno = 0x20000000 | 0xC0000000 | 0x201
34	ERROR_DUPLICATE_FOUND                        Errno = 0x20000000 | 0xC0000000 | 0x202
35	ERROR_NO_DRIVER_SELECTED                     Errno = 0x20000000 | 0xC0000000 | 0x203
36	ERROR_KEY_DOES_NOT_EXIST                     Errno = 0x20000000 | 0xC0000000 | 0x204
37	ERROR_INVALID_DEVINST_NAME                   Errno = 0x20000000 | 0xC0000000 | 0x205
38	ERROR_INVALID_CLASS                          Errno = 0x20000000 | 0xC0000000 | 0x206
39	ERROR_DEVINST_ALREADY_EXISTS                 Errno = 0x20000000 | 0xC0000000 | 0x207
40	ERROR_DEVINFO_NOT_REGISTERED                 Errno = 0x20000000 | 0xC0000000 | 0x208
41	ERROR_INVALID_REG_PROPERTY                   Errno = 0x20000000 | 0xC0000000 | 0x209
42	ERROR_NO_INF                                 Errno = 0x20000000 | 0xC0000000 | 0x20A
43	ERROR_NO_SUCH_DEVINST                        Errno = 0x20000000 | 0xC0000000 | 0x20B
44	ERROR_CANT_LOAD_CLASS_ICON                   Errno = 0x20000000 | 0xC0000000 | 0x20C
45	ERROR_INVALID_CLASS_INSTALLER                Errno = 0x20000000 | 0xC0000000 | 0x20D
46	ERROR_DI_DO_DEFAULT                          Errno = 0x20000000 | 0xC0000000 | 0x20E
47	ERROR_DI_NOFILECOPY                          Errno = 0x20000000 | 0xC0000000 | 0x20F
48	ERROR_INVALID_HWPROFILE                      Errno = 0x20000000 | 0xC0000000 | 0x210
49	ERROR_NO_DEVICE_SELECTED                     Errno = 0x20000000 | 0xC0000000 | 0x211
50	ERROR_DEVINFO_LIST_LOCKED                    Errno = 0x20000000 | 0xC0000000 | 0x212
51	ERROR_DEVINFO_DATA_LOCKED                    Errno = 0x20000000 | 0xC0000000 | 0x213
52	ERROR_DI_BAD_PATH                            Errno = 0x20000000 | 0xC0000000 | 0x214
53	ERROR_NO_CLASSINSTALL_PARAMS                 Errno = 0x20000000 | 0xC0000000 | 0x215
54	ERROR_FILEQUEUE_LOCKED                       Errno = 0x20000000 | 0xC0000000 | 0x216
55	ERROR_BAD_SERVICE_INSTALLSECT                Errno = 0x20000000 | 0xC0000000 | 0x217
56	ERROR_NO_CLASS_DRIVER_LIST                   Errno = 0x20000000 | 0xC0000000 | 0x218
57	ERROR_NO_ASSOCIATED_SERVICE                  Errno = 0x20000000 | 0xC0000000 | 0x219
58	ERROR_NO_DEFAULT_DEVICE_INTERFACE            Errno = 0x20000000 | 0xC0000000 | 0x21A
59	ERROR_DEVICE_INTERFACE_ACTIVE                Errno = 0x20000000 | 0xC0000000 | 0x21B
60	ERROR_DEVICE_INTERFACE_REMOVED               Errno = 0x20000000 | 0xC0000000 | 0x21C
61	ERROR_BAD_INTERFACE_INSTALLSECT              Errno = 0x20000000 | 0xC0000000 | 0x21D
62	ERROR_NO_SUCH_INTERFACE_CLASS                Errno = 0x20000000 | 0xC0000000 | 0x21E
63	ERROR_INVALID_REFERENCE_STRING               Errno = 0x20000000 | 0xC0000000 | 0x21F
64	ERROR_INVALID_MACHINENAME                    Errno = 0x20000000 | 0xC0000000 | 0x220
65	ERROR_REMOTE_COMM_FAILURE                    Errno = 0x20000000 | 0xC0000000 | 0x221
66	ERROR_MACHINE_UNAVAILABLE                    Errno = 0x20000000 | 0xC0000000 | 0x222
67	ERROR_NO_CONFIGMGR_SERVICES                  Errno = 0x20000000 | 0xC0000000 | 0x223
68	ERROR_INVALID_PROPPAGE_PROVIDER              Errno = 0x20000000 | 0xC0000000 | 0x224
69	ERROR_NO_SUCH_DEVICE_INTERFACE               Errno = 0x20000000 | 0xC0000000 | 0x225
70	ERROR_DI_POSTPROCESSING_REQUIRED             Errno = 0x20000000 | 0xC0000000 | 0x226
71	ERROR_INVALID_COINSTALLER                    Errno = 0x20000000 | 0xC0000000 | 0x227
72	ERROR_NO_COMPAT_DRIVERS                      Errno = 0x20000000 | 0xC0000000 | 0x228
73	ERROR_NO_DEVICE_ICON                         Errno = 0x20000000 | 0xC0000000 | 0x229
74	ERROR_INVALID_INF_LOGCONFIG                  Errno = 0x20000000 | 0xC0000000 | 0x22A
75	ERROR_DI_DONT_INSTALL                        Errno = 0x20000000 | 0xC0000000 | 0x22B
76	ERROR_INVALID_FILTER_DRIVER                  Errno = 0x20000000 | 0xC0000000 | 0x22C
77	ERROR_NON_WINDOWS_NT_DRIVER                  Errno = 0x20000000 | 0xC0000000 | 0x22D
78	ERROR_NON_WINDOWS_DRIVER                     Errno = 0x20000000 | 0xC0000000 | 0x22E
79	ERROR_NO_CATALOG_FOR_OEM_INF                 Errno = 0x20000000 | 0xC0000000 | 0x22F
80	ERROR_DEVINSTALL_QUEUE_NONNATIVE             Errno = 0x20000000 | 0xC0000000 | 0x230
81	ERROR_NOT_DISABLEABLE                        Errno = 0x20000000 | 0xC0000000 | 0x231
82	ERROR_CANT_REMOVE_DEVINST                    Errno = 0x20000000 | 0xC0000000 | 0x232
83	ERROR_INVALID_TARGET                         Errno = 0x20000000 | 0xC0000000 | 0x233
84	ERROR_DRIVER_NONNATIVE                       Errno = 0x20000000 | 0xC0000000 | 0x234
85	ERROR_IN_WOW64                               Errno = 0x20000000 | 0xC0000000 | 0x235
86	ERROR_SET_SYSTEM_RESTORE_POINT               Errno = 0x20000000 | 0xC0000000 | 0x236
87	ERROR_SCE_DISABLED                           Errno = 0x20000000 | 0xC0000000 | 0x238
88	ERROR_UNKNOWN_EXCEPTION                      Errno = 0x20000000 | 0xC0000000 | 0x239
89	ERROR_PNP_REGISTRY_ERROR                     Errno = 0x20000000 | 0xC0000000 | 0x23A
90	ERROR_REMOTE_REQUEST_UNSUPPORTED             Errno = 0x20000000 | 0xC0000000 | 0x23B
91	ERROR_NOT_AN_INSTALLED_OEM_INF               Errno = 0x20000000 | 0xC0000000 | 0x23C
92	ERROR_INF_IN_USE_BY_DEVICES                  Errno = 0x20000000 | 0xC0000000 | 0x23D
93	ERROR_DI_FUNCTION_OBSOLETE                   Errno = 0x20000000 | 0xC0000000 | 0x23E
94	ERROR_NO_AUTHENTICODE_CATALOG                Errno = 0x20000000 | 0xC0000000 | 0x23F
95	ERROR_AUTHENTICODE_DISALLOWED                Errno = 0x20000000 | 0xC0000000 | 0x240
96	ERROR_AUTHENTICODE_TRUSTED_PUBLISHER         Errno = 0x20000000 | 0xC0000000 | 0x241
97	ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED     Errno = 0x20000000 | 0xC0000000 | 0x242
98	ERROR_AUTHENTICODE_PUBLISHER_NOT_TRUSTED     Errno = 0x20000000 | 0xC0000000 | 0x243
99	ERROR_SIGNATURE_OSATTRIBUTE_MISMATCH         Errno = 0x20000000 | 0xC0000000 | 0x244
100	ERROR_ONLY_VALIDATE_VIA_AUTHENTICODE         Errno = 0x20000000 | 0xC0000000 | 0x245
101	ERROR_DEVICE_INSTALLER_NOT_READY             Errno = 0x20000000 | 0xC0000000 | 0x246
102	ERROR_DRIVER_STORE_ADD_FAILED                Errno = 0x20000000 | 0xC0000000 | 0x247
103	ERROR_DEVICE_INSTALL_BLOCKED                 Errno = 0x20000000 | 0xC0000000 | 0x248
104	ERROR_DRIVER_INSTALL_BLOCKED                 Errno = 0x20000000 | 0xC0000000 | 0x249
105	ERROR_WRONG_INF_TYPE                         Errno = 0x20000000 | 0xC0000000 | 0x24A
106	ERROR_FILE_HASH_NOT_IN_CATALOG               Errno = 0x20000000 | 0xC0000000 | 0x24B
107	ERROR_DRIVER_STORE_DELETE_FAILED             Errno = 0x20000000 | 0xC0000000 | 0x24C
108	ERROR_UNRECOVERABLE_STACK_OVERFLOW           Errno = 0x20000000 | 0xC0000000 | 0x300
109	EXCEPTION_SPAPI_UNRECOVERABLE_STACK_OVERFLOW Errno = ERROR_UNRECOVERABLE_STACK_OVERFLOW
110	ERROR_NO_DEFAULT_INTERFACE_DEVICE            Errno = ERROR_NO_DEFAULT_DEVICE_INTERFACE
111	ERROR_INTERFACE_DEVICE_ACTIVE                Errno = ERROR_DEVICE_INTERFACE_ACTIVE
112	ERROR_INTERFACE_DEVICE_REMOVED               Errno = ERROR_DEVICE_INTERFACE_REMOVED
113	ERROR_NO_SUCH_INTERFACE_DEVICE               Errno = ERROR_NO_SUCH_DEVICE_INTERFACE
114)
115
116const (
117	MAX_DEVICE_ID_LEN   = 200
118	MAX_DEVNODE_ID_LEN  = MAX_DEVICE_ID_LEN
119	MAX_GUID_STRING_LEN = 39 // 38 chars + terminator null
120	MAX_CLASS_NAME_LEN  = 32
121	MAX_PROFILE_LEN     = 80
122	MAX_CONFIG_VALUE    = 9999
123	MAX_INSTANCE_VALUE  = 9999
124	CONFIGMG_VERSION    = 0x0400
125)
126
127// Maximum string length constants
128const (
129	LINE_LEN                    = 256  // Windows 9x-compatible maximum for displayable strings coming from a device INF.
130	MAX_INF_STRING_LENGTH       = 4096 // Actual maximum size of an INF string (including string substitutions).
131	MAX_INF_SECTION_NAME_LENGTH = 255  // For Windows 9x compatibility, INF section names should be constrained to 32 characters.
132	MAX_TITLE_LEN               = 60
133	MAX_INSTRUCTION_LEN         = 256
134	MAX_LABEL_LEN               = 30
135	MAX_SERVICE_NAME_LEN        = 256
136	MAX_SUBTITLE_LEN            = 256
137)
138
139const (
140	// SP_MAX_MACHINENAME_LENGTH defines maximum length of a machine name in the format expected by ConfigMgr32 CM_Connect_Machine (i.e., "\\\\MachineName\0").
141	SP_MAX_MACHINENAME_LENGTH = MAX_PATH + 3
142)
143
144// HSPFILEQ is type for setup file queue
145type HSPFILEQ uintptr
146
147// DevInfo holds reference to device information set
148type DevInfo Handle
149
150// DEVINST is a handle usually recognized by cfgmgr32 APIs
151type DEVINST uint32
152
153// DevInfoData is a device information structure (references a device instance that is a member of a device information set)
154type DevInfoData struct {
155	size      uint32
156	ClassGUID GUID
157	DevInst   DEVINST
158	_         uintptr
159}
160
161// DevInfoListDetailData is a structure for detailed information on a device information set (used for SetupDiGetDeviceInfoListDetail which supersedes the functionality of SetupDiGetDeviceInfoListClass).
162type DevInfoListDetailData struct {
163	size                uint32 // Use unsafeSizeOf method
164	ClassGUID           GUID
165	RemoteMachineHandle Handle
166	remoteMachineName   [SP_MAX_MACHINENAME_LENGTH]uint16
167}
168
169func (*DevInfoListDetailData) unsafeSizeOf() uint32 {
170	if unsafe.Sizeof(uintptr(0)) == 4 {
171		// Windows declares this with pshpack1.h
172		return uint32(unsafe.Offsetof(DevInfoListDetailData{}.remoteMachineName) + unsafe.Sizeof(DevInfoListDetailData{}.remoteMachineName))
173	}
174	return uint32(unsafe.Sizeof(DevInfoListDetailData{}))
175}
176
177func (data *DevInfoListDetailData) RemoteMachineName() string {
178	return UTF16ToString(data.remoteMachineName[:])
179}
180
181func (data *DevInfoListDetailData) SetRemoteMachineName(remoteMachineName string) error {
182	str, err := UTF16FromString(remoteMachineName)
183	if err != nil {
184		return err
185	}
186	copy(data.remoteMachineName[:], str)
187	return nil
188}
189
190// DI_FUNCTION is function type for device installer
191type DI_FUNCTION uint32
192
193const (
194	DIF_SELECTDEVICE                   DI_FUNCTION = 0x00000001
195	DIF_INSTALLDEVICE                  DI_FUNCTION = 0x00000002
196	DIF_ASSIGNRESOURCES                DI_FUNCTION = 0x00000003
197	DIF_PROPERTIES                     DI_FUNCTION = 0x00000004
198	DIF_REMOVE                         DI_FUNCTION = 0x00000005
199	DIF_FIRSTTIMESETUP                 DI_FUNCTION = 0x00000006
200	DIF_FOUNDDEVICE                    DI_FUNCTION = 0x00000007
201	DIF_SELECTCLASSDRIVERS             DI_FUNCTION = 0x00000008
202	DIF_VALIDATECLASSDRIVERS           DI_FUNCTION = 0x00000009
203	DIF_INSTALLCLASSDRIVERS            DI_FUNCTION = 0x0000000A
204	DIF_CALCDISKSPACE                  DI_FUNCTION = 0x0000000B
205	DIF_DESTROYPRIVATEDATA             DI_FUNCTION = 0x0000000C
206	DIF_VALIDATEDRIVER                 DI_FUNCTION = 0x0000000D
207	DIF_DETECT                         DI_FUNCTION = 0x0000000F
208	DIF_INSTALLWIZARD                  DI_FUNCTION = 0x00000010
209	DIF_DESTROYWIZARDDATA              DI_FUNCTION = 0x00000011
210	DIF_PROPERTYCHANGE                 DI_FUNCTION = 0x00000012
211	DIF_ENABLECLASS                    DI_FUNCTION = 0x00000013
212	DIF_DETECTVERIFY                   DI_FUNCTION = 0x00000014
213	DIF_INSTALLDEVICEFILES             DI_FUNCTION = 0x00000015
214	DIF_UNREMOVE                       DI_FUNCTION = 0x00000016
215	DIF_SELECTBESTCOMPATDRV            DI_FUNCTION = 0x00000017
216	DIF_ALLOW_INSTALL                  DI_FUNCTION = 0x00000018
217	DIF_REGISTERDEVICE                 DI_FUNCTION = 0x00000019
218	DIF_NEWDEVICEWIZARD_PRESELECT      DI_FUNCTION = 0x0000001A
219	DIF_NEWDEVICEWIZARD_SELECT         DI_FUNCTION = 0x0000001B
220	DIF_NEWDEVICEWIZARD_PREANALYZE     DI_FUNCTION = 0x0000001C
221	DIF_NEWDEVICEWIZARD_POSTANALYZE    DI_FUNCTION = 0x0000001D
222	DIF_NEWDEVICEWIZARD_FINISHINSTALL  DI_FUNCTION = 0x0000001E
223	DIF_INSTALLINTERFACES              DI_FUNCTION = 0x00000020
224	DIF_DETECTCANCEL                   DI_FUNCTION = 0x00000021
225	DIF_REGISTER_COINSTALLERS          DI_FUNCTION = 0x00000022
226	DIF_ADDPROPERTYPAGE_ADVANCED       DI_FUNCTION = 0x00000023
227	DIF_ADDPROPERTYPAGE_BASIC          DI_FUNCTION = 0x00000024
228	DIF_TROUBLESHOOTER                 DI_FUNCTION = 0x00000026
229	DIF_POWERMESSAGEWAKE               DI_FUNCTION = 0x00000027
230	DIF_ADDREMOTEPROPERTYPAGE_ADVANCED DI_FUNCTION = 0x00000028
231	DIF_UPDATEDRIVER_UI                DI_FUNCTION = 0x00000029
232	DIF_FINISHINSTALL_ACTION           DI_FUNCTION = 0x0000002A
233)
234
235// DevInstallParams is device installation parameters structure (associated with a particular device information element, or globally with a device information set)
236type DevInstallParams struct {
237	size                     uint32
238	Flags                    DI_FLAGS
239	FlagsEx                  DI_FLAGSEX
240	hwndParent               uintptr
241	InstallMsgHandler        uintptr
242	InstallMsgHandlerContext uintptr
243	FileQueue                HSPFILEQ
244	_                        uintptr
245	_                        uint32
246	driverPath               [MAX_PATH]uint16
247}
248
249func (params *DevInstallParams) DriverPath() string {
250	return UTF16ToString(params.driverPath[:])
251}
252
253func (params *DevInstallParams) SetDriverPath(driverPath string) error {
254	str, err := UTF16FromString(driverPath)
255	if err != nil {
256		return err
257	}
258	copy(params.driverPath[:], str)
259	return nil
260}
261
262// DI_FLAGS is SP_DEVINSTALL_PARAMS.Flags values
263type DI_FLAGS uint32
264
265const (
266	// Flags for choosing a device
267	DI_SHOWOEM       DI_FLAGS = 0x00000001 // support Other... button
268	DI_SHOWCOMPAT    DI_FLAGS = 0x00000002 // show compatibility list
269	DI_SHOWCLASS     DI_FLAGS = 0x00000004 // show class list
270	DI_SHOWALL       DI_FLAGS = 0x00000007 // both class & compat list shown
271	DI_NOVCP         DI_FLAGS = 0x00000008 // don't create a new copy queue--use caller-supplied FileQueue
272	DI_DIDCOMPAT     DI_FLAGS = 0x00000010 // Searched for compatible devices
273	DI_DIDCLASS      DI_FLAGS = 0x00000020 // Searched for class devices
274	DI_AUTOASSIGNRES DI_FLAGS = 0x00000040 // No UI for resources if possible
275
276	// Flags returned by DiInstallDevice to indicate need to reboot/restart
277	DI_NEEDRESTART DI_FLAGS = 0x00000080 // Reboot required to take effect
278	DI_NEEDREBOOT  DI_FLAGS = 0x00000100 // ""
279
280	// Flags for device installation
281	DI_NOBROWSE DI_FLAGS = 0x00000200 // no Browse... in InsertDisk
282
283	// Flags set by DiBuildDriverInfoList
284	DI_MULTMFGS DI_FLAGS = 0x00000400 // Set if multiple manufacturers in class driver list
285
286	// Flag indicates that device is disabled
287	DI_DISABLED DI_FLAGS = 0x00000800 // Set if device disabled
288
289	// Flags for Device/Class Properties
290	DI_GENERALPAGE_ADDED  DI_FLAGS = 0x00001000
291	DI_RESOURCEPAGE_ADDED DI_FLAGS = 0x00002000
292
293	// Flag to indicate the setting properties for this Device (or class) caused a change so the Dev Mgr UI probably needs to be updated.
294	DI_PROPERTIES_CHANGE DI_FLAGS = 0x00004000
295
296	// Flag to indicate that the sorting from the INF file should be used.
297	DI_INF_IS_SORTED DI_FLAGS = 0x00008000
298
299	// Flag to indicate that only the the INF specified by SP_DEVINSTALL_PARAMS.DriverPath should be searched.
300	DI_ENUMSINGLEINF DI_FLAGS = 0x00010000
301
302	// Flag that prevents ConfigMgr from removing/re-enumerating devices during device
303	// registration, installation, and deletion.
304	DI_DONOTCALLCONFIGMG DI_FLAGS = 0x00020000
305
306	// The following flag can be used to install a device disabled
307	DI_INSTALLDISABLED DI_FLAGS = 0x00040000
308
309	// Flag that causes SetupDiBuildDriverInfoList to build a device's compatible driver
310	// list from its existing class driver list, instead of the normal INF search.
311	DI_COMPAT_FROM_CLASS DI_FLAGS = 0x00080000
312
313	// This flag is set if the Class Install params should be used.
314	DI_CLASSINSTALLPARAMS DI_FLAGS = 0x00100000
315
316	// This flag is set if the caller of DiCallClassInstaller does NOT want the internal default action performed if the Class installer returns ERROR_DI_DO_DEFAULT.
317	DI_NODI_DEFAULTACTION DI_FLAGS = 0x00200000
318
319	// Flags for device installation
320	DI_QUIETINSTALL        DI_FLAGS = 0x00800000 // don't confuse the user with questions or excess info
321	DI_NOFILECOPY          DI_FLAGS = 0x01000000 // No file Copy necessary
322	DI_FORCECOPY           DI_FLAGS = 0x02000000 // Force files to be copied from install path
323	DI_DRIVERPAGE_ADDED    DI_FLAGS = 0x04000000 // Prop provider added Driver page.
324	DI_USECI_SELECTSTRINGS DI_FLAGS = 0x08000000 // Use Class Installer Provided strings in the Select Device Dlg
325	DI_OVERRIDE_INFFLAGS   DI_FLAGS = 0x10000000 // Override INF flags
326	DI_PROPS_NOCHANGEUSAGE DI_FLAGS = 0x20000000 // No Enable/Disable in General Props
327
328	DI_NOSELECTICONS DI_FLAGS = 0x40000000 // No small icons in select device dialogs
329
330	DI_NOWRITE_IDS DI_FLAGS = 0x80000000 // Don't write HW & Compat IDs on install
331)
332
333// DI_FLAGSEX is SP_DEVINSTALL_PARAMS.FlagsEx values
334type DI_FLAGSEX uint32
335
336const (
337	DI_FLAGSEX_CI_FAILED                DI_FLAGSEX = 0x00000004 // Failed to Load/Call class installer
338	DI_FLAGSEX_FINISHINSTALL_ACTION     DI_FLAGSEX = 0x00000008 // Class/co-installer wants to get a DIF_FINISH_INSTALL action in client context.
339	DI_FLAGSEX_DIDINFOLIST              DI_FLAGSEX = 0x00000010 // Did the Class Info List
340	DI_FLAGSEX_DIDCOMPATINFO            DI_FLAGSEX = 0x00000020 // Did the Compat Info List
341	DI_FLAGSEX_FILTERCLASSES            DI_FLAGSEX = 0x00000040
342	DI_FLAGSEX_SETFAILEDINSTALL         DI_FLAGSEX = 0x00000080
343	DI_FLAGSEX_DEVICECHANGE             DI_FLAGSEX = 0x00000100
344	DI_FLAGSEX_ALWAYSWRITEIDS           DI_FLAGSEX = 0x00000200
345	DI_FLAGSEX_PROPCHANGE_PENDING       DI_FLAGSEX = 0x00000400 // One or more device property sheets have had changes made to them, and need to have a DIF_PROPERTYCHANGE occur.
346	DI_FLAGSEX_ALLOWEXCLUDEDDRVS        DI_FLAGSEX = 0x00000800
347	DI_FLAGSEX_NOUIONQUERYREMOVE        DI_FLAGSEX = 0x00001000
348	DI_FLAGSEX_USECLASSFORCOMPAT        DI_FLAGSEX = 0x00002000 // Use the device's class when building compat drv list. (Ignored if DI_COMPAT_FROM_CLASS flag is specified.)
349	DI_FLAGSEX_NO_DRVREG_MODIFY         DI_FLAGSEX = 0x00008000 // Don't run AddReg and DelReg for device's software (driver) key.
350	DI_FLAGSEX_IN_SYSTEM_SETUP          DI_FLAGSEX = 0x00010000 // Installation is occurring during initial system setup.
351	DI_FLAGSEX_INET_DRIVER              DI_FLAGSEX = 0x00020000 // Driver came from Windows Update
352	DI_FLAGSEX_APPENDDRIVERLIST         DI_FLAGSEX = 0x00040000 // Cause SetupDiBuildDriverInfoList to append a new driver list to an existing list.
353	DI_FLAGSEX_PREINSTALLBACKUP         DI_FLAGSEX = 0x00080000 // not used
354	DI_FLAGSEX_BACKUPONREPLACE          DI_FLAGSEX = 0x00100000 // not used
355	DI_FLAGSEX_DRIVERLIST_FROM_URL      DI_FLAGSEX = 0x00200000 // build driver list from INF(s) retrieved from URL specified in SP_DEVINSTALL_PARAMS.DriverPath (empty string means Windows Update website)
356	DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS DI_FLAGSEX = 0x00800000 // Don't include old Internet drivers when building a driver list. Ignored on Windows Vista and later.
357	DI_FLAGSEX_POWERPAGE_ADDED          DI_FLAGSEX = 0x01000000 // class installer added their own power page
358	DI_FLAGSEX_FILTERSIMILARDRIVERS     DI_FLAGSEX = 0x02000000 // only include similar drivers in class list
359	DI_FLAGSEX_INSTALLEDDRIVER          DI_FLAGSEX = 0x04000000 // only add the installed driver to the class or compat driver list.  Used in calls to SetupDiBuildDriverInfoList
360	DI_FLAGSEX_NO_CLASSLIST_NODE_MERGE  DI_FLAGSEX = 0x08000000 // Don't remove identical driver nodes from the class list
361	DI_FLAGSEX_ALTPLATFORM_DRVSEARCH    DI_FLAGSEX = 0x10000000 // Build driver list based on alternate platform information specified in associated file queue
362	DI_FLAGSEX_RESTART_DEVICE_ONLY      DI_FLAGSEX = 0x20000000 // only restart the device drivers are being installed on as opposed to restarting all devices using those drivers.
363	DI_FLAGSEX_RECURSIVESEARCH          DI_FLAGSEX = 0x40000000 // Tell SetupDiBuildDriverInfoList to do a recursive search
364	DI_FLAGSEX_SEARCH_PUBLISHED_INFS    DI_FLAGSEX = 0x80000000 // Tell SetupDiBuildDriverInfoList to do a "published INF" search
365)
366
367// ClassInstallHeader is the first member of any class install parameters structure. It contains the device installation request code that defines the format of the rest of the install parameters structure.
368type ClassInstallHeader struct {
369	size            uint32
370	InstallFunction DI_FUNCTION
371}
372
373func MakeClassInstallHeader(installFunction DI_FUNCTION) *ClassInstallHeader {
374	hdr := &ClassInstallHeader{InstallFunction: installFunction}
375	hdr.size = uint32(unsafe.Sizeof(*hdr))
376	return hdr
377}
378
379// DICS_STATE specifies values indicating a change in a device's state
380type DICS_STATE uint32
381
382const (
383	DICS_ENABLE     DICS_STATE = 0x00000001 // The device is being enabled.
384	DICS_DISABLE    DICS_STATE = 0x00000002 // The device is being disabled.
385	DICS_PROPCHANGE DICS_STATE = 0x00000003 // The properties of the device have changed.
386	DICS_START      DICS_STATE = 0x00000004 // The device is being started (if the request is for the currently active hardware profile).
387	DICS_STOP       DICS_STATE = 0x00000005 // The device is being stopped. The driver stack will be unloaded and the CSCONFIGFLAG_DO_NOT_START flag will be set for the device.
388)
389
390// DICS_FLAG specifies the scope of a device property change
391type DICS_FLAG uint32
392
393const (
394	DICS_FLAG_GLOBAL         DICS_FLAG = 0x00000001 // make change in all hardware profiles
395	DICS_FLAG_CONFIGSPECIFIC DICS_FLAG = 0x00000002 // make change in specified profile only
396	DICS_FLAG_CONFIGGENERAL  DICS_FLAG = 0x00000004 // 1 or more hardware profile-specific changes to follow (obsolete)
397)
398
399// PropChangeParams is a structure corresponding to a DIF_PROPERTYCHANGE install function.
400type PropChangeParams struct {
401	ClassInstallHeader ClassInstallHeader
402	StateChange        DICS_STATE
403	Scope              DICS_FLAG
404	HwProfile          uint32
405}
406
407// DI_REMOVEDEVICE specifies the scope of the device removal
408type DI_REMOVEDEVICE uint32
409
410const (
411	DI_REMOVEDEVICE_GLOBAL         DI_REMOVEDEVICE = 0x00000001 // Make this change in all hardware profiles. Remove information about the device from the registry.
412	DI_REMOVEDEVICE_CONFIGSPECIFIC DI_REMOVEDEVICE = 0x00000002 // Make this change to only the hardware profile specified by HwProfile. this flag only applies to root-enumerated devices. When Windows removes the device from the last hardware profile in which it was configured, Windows performs a global removal.
413)
414
415// RemoveDeviceParams is a structure corresponding to a DIF_REMOVE install function.
416type RemoveDeviceParams struct {
417	ClassInstallHeader ClassInstallHeader
418	Scope              DI_REMOVEDEVICE
419	HwProfile          uint32
420}
421
422// 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)
423type DrvInfoData struct {
424	size          uint32
425	DriverType    uint32
426	_             uintptr
427	description   [LINE_LEN]uint16
428	mfgName       [LINE_LEN]uint16
429	providerName  [LINE_LEN]uint16
430	DriverDate    Filetime
431	DriverVersion uint64
432}
433
434func (data *DrvInfoData) Description() string {
435	return UTF16ToString(data.description[:])
436}
437
438func (data *DrvInfoData) SetDescription(description string) error {
439	str, err := UTF16FromString(description)
440	if err != nil {
441		return err
442	}
443	copy(data.description[:], str)
444	return nil
445}
446
447func (data *DrvInfoData) MfgName() string {
448	return UTF16ToString(data.mfgName[:])
449}
450
451func (data *DrvInfoData) SetMfgName(mfgName string) error {
452	str, err := UTF16FromString(mfgName)
453	if err != nil {
454		return err
455	}
456	copy(data.mfgName[:], str)
457	return nil
458}
459
460func (data *DrvInfoData) ProviderName() string {
461	return UTF16ToString(data.providerName[:])
462}
463
464func (data *DrvInfoData) SetProviderName(providerName string) error {
465	str, err := UTF16FromString(providerName)
466	if err != nil {
467		return err
468	}
469	copy(data.providerName[:], str)
470	return nil
471}
472
473// IsNewer method returns true if DrvInfoData date and version is newer than supplied parameters.
474func (data *DrvInfoData) IsNewer(driverDate Filetime, driverVersion uint64) bool {
475	if data.DriverDate.HighDateTime > driverDate.HighDateTime {
476		return true
477	}
478	if data.DriverDate.HighDateTime < driverDate.HighDateTime {
479		return false
480	}
481
482	if data.DriverDate.LowDateTime > driverDate.LowDateTime {
483		return true
484	}
485	if data.DriverDate.LowDateTime < driverDate.LowDateTime {
486		return false
487	}
488
489	if data.DriverVersion > driverVersion {
490		return true
491	}
492	if data.DriverVersion < driverVersion {
493		return false
494	}
495
496	return false
497}
498
499// DrvInfoDetailData is driver information details structure (provides detailed information about a particular driver information structure)
500type DrvInfoDetailData struct {
501	size            uint32 // Use unsafeSizeOf method
502	InfDate         Filetime
503	compatIDsOffset uint32
504	compatIDsLength uint32
505	_               uintptr
506	sectionName     [LINE_LEN]uint16
507	infFileName     [MAX_PATH]uint16
508	drvDescription  [LINE_LEN]uint16
509	hardwareID      [1]uint16
510}
511
512func (*DrvInfoDetailData) unsafeSizeOf() uint32 {
513	if unsafe.Sizeof(uintptr(0)) == 4 {
514		// Windows declares this with pshpack1.h
515		return uint32(unsafe.Offsetof(DrvInfoDetailData{}.hardwareID) + unsafe.Sizeof(DrvInfoDetailData{}.hardwareID))
516	}
517	return uint32(unsafe.Sizeof(DrvInfoDetailData{}))
518}
519
520func (data *DrvInfoDetailData) SectionName() string {
521	return UTF16ToString(data.sectionName[:])
522}
523
524func (data *DrvInfoDetailData) InfFileName() string {
525	return UTF16ToString(data.infFileName[:])
526}
527
528func (data *DrvInfoDetailData) DrvDescription() string {
529	return UTF16ToString(data.drvDescription[:])
530}
531
532func (data *DrvInfoDetailData) HardwareID() string {
533	if data.compatIDsOffset > 1 {
534		bufW := data.getBuf()
535		return UTF16ToString(bufW[:wcslen(bufW)])
536	}
537
538	return ""
539}
540
541func (data *DrvInfoDetailData) CompatIDs() []string {
542	a := make([]string, 0)
543
544	if data.compatIDsLength > 0 {
545		bufW := data.getBuf()
546		bufW = bufW[data.compatIDsOffset : data.compatIDsOffset+data.compatIDsLength]
547		for i := 0; i < len(bufW); {
548			j := i + wcslen(bufW[i:])
549			if i < j {
550				a = append(a, UTF16ToString(bufW[i:j]))
551			}
552			i = j + 1
553		}
554	}
555
556	return a
557}
558
559func (data *DrvInfoDetailData) getBuf() []uint16 {
560	len := (data.size - uint32(unsafe.Offsetof(data.hardwareID))) / 2
561	sl := struct {
562		addr *uint16
563		len  int
564		cap  int
565	}{&data.hardwareID[0], int(len), int(len)}
566	return *(*[]uint16)(unsafe.Pointer(&sl))
567}
568
569// IsCompatible method tests if given hardware ID matches the driver or is listed on the compatible ID list.
570func (data *DrvInfoDetailData) IsCompatible(hwid string) bool {
571	hwidLC := strings.ToLower(hwid)
572	if strings.ToLower(data.HardwareID()) == hwidLC {
573		return true
574	}
575	a := data.CompatIDs()
576	for i := range a {
577		if strings.ToLower(a[i]) == hwidLC {
578			return true
579		}
580	}
581
582	return false
583}
584
585// DICD flags control SetupDiCreateDeviceInfo
586type DICD uint32
587
588const (
589	DICD_GENERATE_ID       DICD = 0x00000001
590	DICD_INHERIT_CLASSDRVS DICD = 0x00000002
591)
592
593// SUOI flags control SetupUninstallOEMInf
594type SUOI uint32
595
596const (
597	SUOI_FORCEDELETE SUOI = 0x0001
598)
599
600// SPDIT flags to distinguish between class drivers and
601// device drivers. (Passed in 'DriverType' parameter of
602// driver information list APIs)
603type SPDIT uint32
604
605const (
606	SPDIT_NODRIVER     SPDIT = 0x00000000
607	SPDIT_CLASSDRIVER  SPDIT = 0x00000001
608	SPDIT_COMPATDRIVER SPDIT = 0x00000002
609)
610
611// DIGCF flags control what is included in the device information set built by SetupDiGetClassDevs
612type DIGCF uint32
613
614const (
615	DIGCF_DEFAULT         DIGCF = 0x00000001 // only valid with DIGCF_DEVICEINTERFACE
616	DIGCF_PRESENT         DIGCF = 0x00000002
617	DIGCF_ALLCLASSES      DIGCF = 0x00000004
618	DIGCF_PROFILE         DIGCF = 0x00000008
619	DIGCF_DEVICEINTERFACE DIGCF = 0x00000010
620)
621
622// DIREG specifies values for SetupDiCreateDevRegKey, SetupDiOpenDevRegKey, and SetupDiDeleteDevRegKey.
623type DIREG uint32
624
625const (
626	DIREG_DEV  DIREG = 0x00000001 // Open/Create/Delete device key
627	DIREG_DRV  DIREG = 0x00000002 // Open/Create/Delete driver key
628	DIREG_BOTH DIREG = 0x00000004 // Delete both driver and Device key
629)
630
631// SPDRP specifies device registry property codes
632// (Codes marked as read-only (R) may only be used for
633// SetupDiGetDeviceRegistryProperty)
634//
635// These values should cover the same set of registry properties
636// as defined by the CM_DRP codes in cfgmgr32.h.
637//
638// Note that SPDRP codes are zero based while CM_DRP codes are one based!
639type SPDRP uint32
640
641const (
642	SPDRP_DEVICEDESC                  SPDRP = 0x00000000 // DeviceDesc (R/W)
643	SPDRP_HARDWAREID                  SPDRP = 0x00000001 // HardwareID (R/W)
644	SPDRP_COMPATIBLEIDS               SPDRP = 0x00000002 // CompatibleIDs (R/W)
645	SPDRP_SERVICE                     SPDRP = 0x00000004 // Service (R/W)
646	SPDRP_CLASS                       SPDRP = 0x00000007 // Class (R--tied to ClassGUID)
647	SPDRP_CLASSGUID                   SPDRP = 0x00000008 // ClassGUID (R/W)
648	SPDRP_DRIVER                      SPDRP = 0x00000009 // Driver (R/W)
649	SPDRP_CONFIGFLAGS                 SPDRP = 0x0000000A // ConfigFlags (R/W)
650	SPDRP_MFG                         SPDRP = 0x0000000B // Mfg (R/W)
651	SPDRP_FRIENDLYNAME                SPDRP = 0x0000000C // FriendlyName (R/W)
652	SPDRP_LOCATION_INFORMATION        SPDRP = 0x0000000D // LocationInformation (R/W)
653	SPDRP_PHYSICAL_DEVICE_OBJECT_NAME SPDRP = 0x0000000E // PhysicalDeviceObjectName (R)
654	SPDRP_CAPABILITIES                SPDRP = 0x0000000F // Capabilities (R)
655	SPDRP_UI_NUMBER                   SPDRP = 0x00000010 // UiNumber (R)
656	SPDRP_UPPERFILTERS                SPDRP = 0x00000011 // UpperFilters (R/W)
657	SPDRP_LOWERFILTERS                SPDRP = 0x00000012 // LowerFilters (R/W)
658	SPDRP_BUSTYPEGUID                 SPDRP = 0x00000013 // BusTypeGUID (R)
659	SPDRP_LEGACYBUSTYPE               SPDRP = 0x00000014 // LegacyBusType (R)
660	SPDRP_BUSNUMBER                   SPDRP = 0x00000015 // BusNumber (R)
661	SPDRP_ENUMERATOR_NAME             SPDRP = 0x00000016 // Enumerator Name (R)
662	SPDRP_SECURITY                    SPDRP = 0x00000017 // Security (R/W, binary form)
663	SPDRP_SECURITY_SDS                SPDRP = 0x00000018 // Security (W, SDS form)
664	SPDRP_DEVTYPE                     SPDRP = 0x00000019 // Device Type (R/W)
665	SPDRP_EXCLUSIVE                   SPDRP = 0x0000001A // Device is exclusive-access (R/W)
666	SPDRP_CHARACTERISTICS             SPDRP = 0x0000001B // Device Characteristics (R/W)
667	SPDRP_ADDRESS                     SPDRP = 0x0000001C // Device Address (R)
668	SPDRP_UI_NUMBER_DESC_FORMAT       SPDRP = 0x0000001D // UiNumberDescFormat (R/W)
669	SPDRP_DEVICE_POWER_DATA           SPDRP = 0x0000001E // Device Power Data (R)
670	SPDRP_REMOVAL_POLICY              SPDRP = 0x0000001F // Removal Policy (R)
671	SPDRP_REMOVAL_POLICY_HW_DEFAULT   SPDRP = 0x00000020 // Hardware Removal Policy (R)
672	SPDRP_REMOVAL_POLICY_OVERRIDE     SPDRP = 0x00000021 // Removal Policy Override (RW)
673	SPDRP_INSTALL_STATE               SPDRP = 0x00000022 // Device Install State (R)
674	SPDRP_LOCATION_PATHS              SPDRP = 0x00000023 // Device Location Paths (R)
675	SPDRP_BASE_CONTAINERID            SPDRP = 0x00000024 // Base ContainerID (R)
676
677	SPDRP_MAXIMUM_PROPERTY SPDRP = 0x00000025 // Upper bound on ordinals
678)
679
680// DEVPROPTYPE represents the property-data-type identifier that specifies the
681// data type of a device property value in the unified device property model.
682type DEVPROPTYPE uint32
683
684const (
685	DEVPROP_TYPEMOD_ARRAY DEVPROPTYPE = 0x00001000
686	DEVPROP_TYPEMOD_LIST  DEVPROPTYPE = 0x00002000
687
688	DEVPROP_TYPE_EMPTY                      DEVPROPTYPE = 0x00000000
689	DEVPROP_TYPE_NULL                       DEVPROPTYPE = 0x00000001
690	DEVPROP_TYPE_SBYTE                      DEVPROPTYPE = 0x00000002
691	DEVPROP_TYPE_BYTE                       DEVPROPTYPE = 0x00000003
692	DEVPROP_TYPE_INT16                      DEVPROPTYPE = 0x00000004
693	DEVPROP_TYPE_UINT16                     DEVPROPTYPE = 0x00000005
694	DEVPROP_TYPE_INT32                      DEVPROPTYPE = 0x00000006
695	DEVPROP_TYPE_UINT32                     DEVPROPTYPE = 0x00000007
696	DEVPROP_TYPE_INT64                      DEVPROPTYPE = 0x00000008
697	DEVPROP_TYPE_UINT64                     DEVPROPTYPE = 0x00000009
698	DEVPROP_TYPE_FLOAT                      DEVPROPTYPE = 0x0000000A
699	DEVPROP_TYPE_DOUBLE                     DEVPROPTYPE = 0x0000000B
700	DEVPROP_TYPE_DECIMAL                    DEVPROPTYPE = 0x0000000C
701	DEVPROP_TYPE_GUID                       DEVPROPTYPE = 0x0000000D
702	DEVPROP_TYPE_CURRENCY                   DEVPROPTYPE = 0x0000000E
703	DEVPROP_TYPE_DATE                       DEVPROPTYPE = 0x0000000F
704	DEVPROP_TYPE_FILETIME                   DEVPROPTYPE = 0x00000010
705	DEVPROP_TYPE_BOOLEAN                    DEVPROPTYPE = 0x00000011
706	DEVPROP_TYPE_STRING                     DEVPROPTYPE = 0x00000012
707	DEVPROP_TYPE_STRING_LIST                DEVPROPTYPE = DEVPROP_TYPE_STRING | DEVPROP_TYPEMOD_LIST
708	DEVPROP_TYPE_SECURITY_DESCRIPTOR        DEVPROPTYPE = 0x00000013
709	DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING DEVPROPTYPE = 0x00000014
710	DEVPROP_TYPE_DEVPROPKEY                 DEVPROPTYPE = 0x00000015
711	DEVPROP_TYPE_DEVPROPTYPE                DEVPROPTYPE = 0x00000016
712	DEVPROP_TYPE_BINARY                     DEVPROPTYPE = DEVPROP_TYPE_BYTE | DEVPROP_TYPEMOD_ARRAY
713	DEVPROP_TYPE_ERROR                      DEVPROPTYPE = 0x00000017
714	DEVPROP_TYPE_NTSTATUS                   DEVPROPTYPE = 0x00000018
715	DEVPROP_TYPE_STRING_INDIRECT            DEVPROPTYPE = 0x00000019
716
717	MAX_DEVPROP_TYPE    DEVPROPTYPE = 0x00000019
718	MAX_DEVPROP_TYPEMOD DEVPROPTYPE = 0x00002000
719
720	DEVPROP_MASK_TYPE    DEVPROPTYPE = 0x00000FFF
721	DEVPROP_MASK_TYPEMOD DEVPROPTYPE = 0x0000F000
722)
723
724// DEVPROPGUID specifies a property category.
725type DEVPROPGUID GUID
726
727// DEVPROPID uniquely identifies the property within the property category.
728type DEVPROPID uint32
729
730const DEVPROPID_FIRST_USABLE DEVPROPID = 2
731
732// DEVPROPKEY represents a device property key for a device property in the
733// unified device property model.
734type DEVPROPKEY struct {
735	FmtID DEVPROPGUID
736	PID   DEVPROPID
737}
738
739// CONFIGRET is a return value or error code from cfgmgr32 APIs
740type CONFIGRET uint32
741
742func (ret CONFIGRET) Error() string {
743	if win32Error, ok := ret.Unwrap().(Errno); ok {
744		return fmt.Sprintf("%s (CfgMgr error: 0x%08x)", win32Error.Error(), uint32(ret))
745	}
746	return fmt.Sprintf("CfgMgr error: 0x%08x", uint32(ret))
747}
748
749func (ret CONFIGRET) Win32Error(defaultError Errno) Errno {
750	return cm_MapCrToWin32Err(ret, defaultError)
751}
752
753func (ret CONFIGRET) Unwrap() error {
754	const noMatch = Errno(^uintptr(0))
755	win32Error := ret.Win32Error(noMatch)
756	if win32Error == noMatch {
757		return nil
758	}
759	return win32Error
760}
761
762const (
763	CR_SUCCESS                  CONFIGRET = 0x00000000
764	CR_DEFAULT                  CONFIGRET = 0x00000001
765	CR_OUT_OF_MEMORY            CONFIGRET = 0x00000002
766	CR_INVALID_POINTER          CONFIGRET = 0x00000003
767	CR_INVALID_FLAG             CONFIGRET = 0x00000004
768	CR_INVALID_DEVNODE          CONFIGRET = 0x00000005
769	CR_INVALID_DEVINST                    = CR_INVALID_DEVNODE
770	CR_INVALID_RES_DES          CONFIGRET = 0x00000006
771	CR_INVALID_LOG_CONF         CONFIGRET = 0x00000007
772	CR_INVALID_ARBITRATOR       CONFIGRET = 0x00000008
773	CR_INVALID_NODELIST         CONFIGRET = 0x00000009
774	CR_DEVNODE_HAS_REQS         CONFIGRET = 0x0000000A
775	CR_DEVINST_HAS_REQS                   = CR_DEVNODE_HAS_REQS
776	CR_INVALID_RESOURCEID       CONFIGRET = 0x0000000B
777	CR_DLVXD_NOT_FOUND          CONFIGRET = 0x0000000C
778	CR_NO_SUCH_DEVNODE          CONFIGRET = 0x0000000D
779	CR_NO_SUCH_DEVINST                    = CR_NO_SUCH_DEVNODE
780	CR_NO_MORE_LOG_CONF         CONFIGRET = 0x0000000E
781	CR_NO_MORE_RES_DES          CONFIGRET = 0x0000000F
782	CR_ALREADY_SUCH_DEVNODE     CONFIGRET = 0x00000010
783	CR_ALREADY_SUCH_DEVINST               = CR_ALREADY_SUCH_DEVNODE
784	CR_INVALID_RANGE_LIST       CONFIGRET = 0x00000011
785	CR_INVALID_RANGE            CONFIGRET = 0x00000012
786	CR_FAILURE                  CONFIGRET = 0x00000013
787	CR_NO_SUCH_LOGICAL_DEV      CONFIGRET = 0x00000014
788	CR_CREATE_BLOCKED           CONFIGRET = 0x00000015
789	CR_NOT_SYSTEM_VM            CONFIGRET = 0x00000016
790	CR_REMOVE_VETOED            CONFIGRET = 0x00000017
791	CR_APM_VETOED               CONFIGRET = 0x00000018
792	CR_INVALID_LOAD_TYPE        CONFIGRET = 0x00000019
793	CR_BUFFER_SMALL             CONFIGRET = 0x0000001A
794	CR_NO_ARBITRATOR            CONFIGRET = 0x0000001B
795	CR_NO_REGISTRY_HANDLE       CONFIGRET = 0x0000001C
796	CR_REGISTRY_ERROR           CONFIGRET = 0x0000001D
797	CR_INVALID_DEVICE_ID        CONFIGRET = 0x0000001E
798	CR_INVALID_DATA             CONFIGRET = 0x0000001F
799	CR_INVALID_API              CONFIGRET = 0x00000020
800	CR_DEVLOADER_NOT_READY      CONFIGRET = 0x00000021
801	CR_NEED_RESTART             CONFIGRET = 0x00000022
802	CR_NO_MORE_HW_PROFILES      CONFIGRET = 0x00000023
803	CR_DEVICE_NOT_THERE         CONFIGRET = 0x00000024
804	CR_NO_SUCH_VALUE            CONFIGRET = 0x00000025
805	CR_WRONG_TYPE               CONFIGRET = 0x00000026
806	CR_INVALID_PRIORITY         CONFIGRET = 0x00000027
807	CR_NOT_DISABLEABLE          CONFIGRET = 0x00000028
808	CR_FREE_RESOURCES           CONFIGRET = 0x00000029
809	CR_QUERY_VETOED             CONFIGRET = 0x0000002A
810	CR_CANT_SHARE_IRQ           CONFIGRET = 0x0000002B
811	CR_NO_DEPENDENT             CONFIGRET = 0x0000002C
812	CR_SAME_RESOURCES           CONFIGRET = 0x0000002D
813	CR_NO_SUCH_REGISTRY_KEY     CONFIGRET = 0x0000002E
814	CR_INVALID_MACHINENAME      CONFIGRET = 0x0000002F
815	CR_REMOTE_COMM_FAILURE      CONFIGRET = 0x00000030
816	CR_MACHINE_UNAVAILABLE      CONFIGRET = 0x00000031
817	CR_NO_CM_SERVICES           CONFIGRET = 0x00000032
818	CR_ACCESS_DENIED            CONFIGRET = 0x00000033
819	CR_CALL_NOT_IMPLEMENTED     CONFIGRET = 0x00000034
820	CR_INVALID_PROPERTY         CONFIGRET = 0x00000035
821	CR_DEVICE_INTERFACE_ACTIVE  CONFIGRET = 0x00000036
822	CR_NO_SUCH_DEVICE_INTERFACE CONFIGRET = 0x00000037
823	CR_INVALID_REFERENCE_STRING CONFIGRET = 0x00000038
824	CR_INVALID_CONFLICT_LIST    CONFIGRET = 0x00000039
825	CR_INVALID_INDEX            CONFIGRET = 0x0000003A
826	CR_INVALID_STRUCTURE_SIZE   CONFIGRET = 0x0000003B
827	NUM_CR_RESULTS              CONFIGRET = 0x0000003C
828)
829
830const (
831	CM_GET_DEVICE_INTERFACE_LIST_PRESENT     = 0 // only currently 'live' device interfaces
832	CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES = 1 // all registered device interfaces, live or not
833)
834
835const (
836	DN_ROOT_ENUMERATED       = 0x00000001        // Was enumerated by ROOT
837	DN_DRIVER_LOADED         = 0x00000002        // Has Register_Device_Driver
838	DN_ENUM_LOADED           = 0x00000004        // Has Register_Enumerator
839	DN_STARTED               = 0x00000008        // Is currently configured
840	DN_MANUAL                = 0x00000010        // Manually installed
841	DN_NEED_TO_ENUM          = 0x00000020        // May need reenumeration
842	DN_NOT_FIRST_TIME        = 0x00000040        // Has received a config
843	DN_HARDWARE_ENUM         = 0x00000080        // Enum generates hardware ID
844	DN_LIAR                  = 0x00000100        // Lied about can reconfig once
845	DN_HAS_MARK              = 0x00000200        // Not CM_Create_DevInst lately
846	DN_HAS_PROBLEM           = 0x00000400        // Need device installer
847	DN_FILTERED              = 0x00000800        // Is filtered
848	DN_MOVED                 = 0x00001000        // Has been moved
849	DN_DISABLEABLE           = 0x00002000        // Can be disabled
850	DN_REMOVABLE             = 0x00004000        // Can be removed
851	DN_PRIVATE_PROBLEM       = 0x00008000        // Has a private problem
852	DN_MF_PARENT             = 0x00010000        // Multi function parent
853	DN_MF_CHILD              = 0x00020000        // Multi function child
854	DN_WILL_BE_REMOVED       = 0x00040000        // DevInst is being removed
855	DN_NOT_FIRST_TIMEE       = 0x00080000        // Has received a config enumerate
856	DN_STOP_FREE_RES         = 0x00100000        // When child is stopped, free resources
857	DN_REBAL_CANDIDATE       = 0x00200000        // Don't skip during rebalance
858	DN_BAD_PARTIAL           = 0x00400000        // This devnode's log_confs do not have same resources
859	DN_NT_ENUMERATOR         = 0x00800000        // This devnode's is an NT enumerator
860	DN_NT_DRIVER             = 0x01000000        // This devnode's is an NT driver
861	DN_NEEDS_LOCKING         = 0x02000000        // Devnode need lock resume processing
862	DN_ARM_WAKEUP            = 0x04000000        // Devnode can be the wakeup device
863	DN_APM_ENUMERATOR        = 0x08000000        // APM aware enumerator
864	DN_APM_DRIVER            = 0x10000000        // APM aware driver
865	DN_SILENT_INSTALL        = 0x20000000        // Silent install
866	DN_NO_SHOW_IN_DM         = 0x40000000        // No show in device manager
867	DN_BOOT_LOG_PROB         = 0x80000000        // Had a problem during preassignment of boot log conf
868	DN_NEED_RESTART          = DN_LIAR           // System needs to be restarted for this Devnode to work properly
869	DN_DRIVER_BLOCKED        = DN_NOT_FIRST_TIME // One or more drivers are blocked from loading for this Devnode
870	DN_LEGACY_DRIVER         = DN_MOVED          // This device is using a legacy driver
871	DN_CHILD_WITH_INVALID_ID = DN_HAS_MARK       // One or more children have invalid IDs
872	DN_DEVICE_DISCONNECTED   = DN_NEEDS_LOCKING  // The function driver for a device reported that the device is not connected.  Typically this means a wireless device is out of range.
873	DN_QUERY_REMOVE_PENDING  = DN_MF_PARENT      // Device is part of a set of related devices collectively pending query-removal
874	DN_QUERY_REMOVE_ACTIVE   = DN_MF_CHILD       // Device is actively engaged in a query-remove IRP
875	DN_CHANGEABLE_FLAGS      = DN_NOT_FIRST_TIME | DN_HARDWARE_ENUM | DN_HAS_MARK | DN_DISABLEABLE | DN_REMOVABLE | DN_MF_CHILD | DN_MF_PARENT | DN_NOT_FIRST_TIMEE | DN_STOP_FREE_RES | DN_REBAL_CANDIDATE | DN_NT_ENUMERATOR | DN_NT_DRIVER | DN_SILENT_INSTALL | DN_NO_SHOW_IN_DM
876)
877
878//sys	setupDiCreateDeviceInfoListEx(classGUID *GUID, hwndParent uintptr, machineName *uint16, reserved uintptr) (handle DevInfo, err error) [failretval==DevInfo(InvalidHandle)] = setupapi.SetupDiCreateDeviceInfoListExW
879
880// 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.
881func SetupDiCreateDeviceInfoListEx(classGUID *GUID, hwndParent uintptr, machineName string) (deviceInfoSet DevInfo, err error) {
882	var machineNameUTF16 *uint16
883	if machineName != "" {
884		machineNameUTF16, err = UTF16PtrFromString(machineName)
885		if err != nil {
886			return
887		}
888	}
889	return setupDiCreateDeviceInfoListEx(classGUID, hwndParent, machineNameUTF16, 0)
890}
891
892//sys	setupDiGetDeviceInfoListDetail(deviceInfoSet DevInfo, deviceInfoSetDetailData *DevInfoListDetailData) (err error) = setupapi.SetupDiGetDeviceInfoListDetailW
893
894// SetupDiGetDeviceInfoListDetail function retrieves information associated with a device information set including the class GUID, remote computer handle, and remote computer name.
895func SetupDiGetDeviceInfoListDetail(deviceInfoSet DevInfo) (deviceInfoSetDetailData *DevInfoListDetailData, err error) {
896	data := &DevInfoListDetailData{}
897	data.size = data.unsafeSizeOf()
898
899	return data, setupDiGetDeviceInfoListDetail(deviceInfoSet, data)
900}
901
902// DeviceInfoListDetail method retrieves information associated with a device information set including the class GUID, remote computer handle, and remote computer name.
903func (deviceInfoSet DevInfo) DeviceInfoListDetail() (*DevInfoListDetailData, error) {
904	return SetupDiGetDeviceInfoListDetail(deviceInfoSet)
905}
906
907//sys	setupDiCreateDeviceInfo(deviceInfoSet DevInfo, DeviceName *uint16, classGUID *GUID, DeviceDescription *uint16, hwndParent uintptr, CreationFlags DICD, deviceInfoData *DevInfoData) (err error) = setupapi.SetupDiCreateDeviceInfoW
908
909// SetupDiCreateDeviceInfo function creates a new device information element and adds it as a new member to the specified device information set.
910func SetupDiCreateDeviceInfo(deviceInfoSet DevInfo, deviceName string, classGUID *GUID, deviceDescription string, hwndParent uintptr, creationFlags DICD) (deviceInfoData *DevInfoData, err error) {
911	deviceNameUTF16, err := UTF16PtrFromString(deviceName)
912	if err != nil {
913		return
914	}
915
916	var deviceDescriptionUTF16 *uint16
917	if deviceDescription != "" {
918		deviceDescriptionUTF16, err = UTF16PtrFromString(deviceDescription)
919		if err != nil {
920			return
921		}
922	}
923
924	data := &DevInfoData{}
925	data.size = uint32(unsafe.Sizeof(*data))
926
927	return data, setupDiCreateDeviceInfo(deviceInfoSet, deviceNameUTF16, classGUID, deviceDescriptionUTF16, hwndParent, creationFlags, data)
928}
929
930// CreateDeviceInfo method creates a new device information element and adds it as a new member to the specified device information set.
931func (deviceInfoSet DevInfo) CreateDeviceInfo(deviceName string, classGUID *GUID, deviceDescription string, hwndParent uintptr, creationFlags DICD) (*DevInfoData, error) {
932	return SetupDiCreateDeviceInfo(deviceInfoSet, deviceName, classGUID, deviceDescription, hwndParent, creationFlags)
933}
934
935//sys	setupDiEnumDeviceInfo(deviceInfoSet DevInfo, memberIndex uint32, deviceInfoData *DevInfoData) (err error) = setupapi.SetupDiEnumDeviceInfo
936
937// SetupDiEnumDeviceInfo function returns a DevInfoData structure that specifies a device information element in a device information set.
938func SetupDiEnumDeviceInfo(deviceInfoSet DevInfo, memberIndex int) (*DevInfoData, error) {
939	data := &DevInfoData{}
940	data.size = uint32(unsafe.Sizeof(*data))
941
942	return data, setupDiEnumDeviceInfo(deviceInfoSet, uint32(memberIndex), data)
943}
944
945// EnumDeviceInfo method returns a DevInfoData structure that specifies a device information element in a device information set.
946func (deviceInfoSet DevInfo) EnumDeviceInfo(memberIndex int) (*DevInfoData, error) {
947	return SetupDiEnumDeviceInfo(deviceInfoSet, memberIndex)
948}
949
950// SetupDiDestroyDeviceInfoList function deletes a device information set and frees all associated memory.
951//sys	SetupDiDestroyDeviceInfoList(deviceInfoSet DevInfo) (err error) = setupapi.SetupDiDestroyDeviceInfoList
952
953// Close method deletes a device information set and frees all associated memory.
954func (deviceInfoSet DevInfo) Close() error {
955	return SetupDiDestroyDeviceInfoList(deviceInfoSet)
956}
957
958//sys	SetupDiBuildDriverInfoList(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT) (err error) = setupapi.SetupDiBuildDriverInfoList
959
960// 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.
961func (deviceInfoSet DevInfo) BuildDriverInfoList(deviceInfoData *DevInfoData, driverType SPDIT) error {
962	return SetupDiBuildDriverInfoList(deviceInfoSet, deviceInfoData, driverType)
963}
964
965//sys	SetupDiCancelDriverInfoSearch(deviceInfoSet DevInfo) (err error) = setupapi.SetupDiCancelDriverInfoSearch
966
967// CancelDriverInfoSearch method cancels a driver list search that is currently in progress in a different thread.
968func (deviceInfoSet DevInfo) CancelDriverInfoSearch() error {
969	return SetupDiCancelDriverInfoSearch(deviceInfoSet)
970}
971
972//sys	setupDiEnumDriverInfo(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT, memberIndex uint32, driverInfoData *DrvInfoData) (err error) = setupapi.SetupDiEnumDriverInfoW
973
974// SetupDiEnumDriverInfo function enumerates the members of a driver list.
975func SetupDiEnumDriverInfo(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT, memberIndex int) (*DrvInfoData, error) {
976	data := &DrvInfoData{}
977	data.size = uint32(unsafe.Sizeof(*data))
978
979	return data, setupDiEnumDriverInfo(deviceInfoSet, deviceInfoData, driverType, uint32(memberIndex), data)
980}
981
982// EnumDriverInfo method enumerates the members of a driver list.
983func (deviceInfoSet DevInfo) EnumDriverInfo(deviceInfoData *DevInfoData, driverType SPDIT, memberIndex int) (*DrvInfoData, error) {
984	return SetupDiEnumDriverInfo(deviceInfoSet, deviceInfoData, driverType, memberIndex)
985}
986
987//sys	setupDiGetSelectedDriver(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (err error) = setupapi.SetupDiGetSelectedDriverW
988
989// SetupDiGetSelectedDriver function retrieves the selected driver for a device information set or a particular device information element.
990func SetupDiGetSelectedDriver(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (*DrvInfoData, error) {
991	data := &DrvInfoData{}
992	data.size = uint32(unsafe.Sizeof(*data))
993
994	return data, setupDiGetSelectedDriver(deviceInfoSet, deviceInfoData, data)
995}
996
997// SelectedDriver method retrieves the selected driver for a device information set or a particular device information element.
998func (deviceInfoSet DevInfo) SelectedDriver(deviceInfoData *DevInfoData) (*DrvInfoData, error) {
999	return SetupDiGetSelectedDriver(deviceInfoSet, deviceInfoData)
1000}
1001
1002//sys	SetupDiSetSelectedDriver(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (err error) = setupapi.SetupDiSetSelectedDriverW
1003
1004// SetSelectedDriver method sets, or resets, the selected driver for a device information element or the selected class driver for a device information set.
1005func (deviceInfoSet DevInfo) SetSelectedDriver(deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) error {
1006	return SetupDiSetSelectedDriver(deviceInfoSet, deviceInfoData, driverInfoData)
1007}
1008
1009//sys	setupDiGetDriverInfoDetail(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData, driverInfoDetailData *DrvInfoDetailData, driverInfoDetailDataSize uint32, requiredSize *uint32) (err error) = setupapi.SetupDiGetDriverInfoDetailW
1010
1011// SetupDiGetDriverInfoDetail function retrieves driver information detail for a device information set or a particular device information element in the device information set.
1012func SetupDiGetDriverInfoDetail(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (*DrvInfoDetailData, error) {
1013	reqSize := uint32(2048)
1014	for {
1015		buf := make([]byte, reqSize)
1016		data := (*DrvInfoDetailData)(unsafe.Pointer(&buf[0]))
1017		data.size = data.unsafeSizeOf()
1018		err := setupDiGetDriverInfoDetail(deviceInfoSet, deviceInfoData, driverInfoData, data, uint32(len(buf)), &reqSize)
1019		if err == ERROR_INSUFFICIENT_BUFFER {
1020			continue
1021		}
1022		if err != nil {
1023			return nil, err
1024		}
1025		data.size = reqSize
1026		return data, nil
1027	}
1028}
1029
1030// DriverInfoDetail method retrieves driver information detail for a device information set or a particular device information element in the device information set.
1031func (deviceInfoSet DevInfo) DriverInfoDetail(deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (*DrvInfoDetailData, error) {
1032	return SetupDiGetDriverInfoDetail(deviceInfoSet, deviceInfoData, driverInfoData)
1033}
1034
1035//sys	SetupDiDestroyDriverInfoList(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT) (err error) = setupapi.SetupDiDestroyDriverInfoList
1036
1037// DestroyDriverInfoList method deletes a driver list.
1038func (deviceInfoSet DevInfo) DestroyDriverInfoList(deviceInfoData *DevInfoData, driverType SPDIT) error {
1039	return SetupDiDestroyDriverInfoList(deviceInfoSet, deviceInfoData, driverType)
1040}
1041
1042//sys	setupDiGetClassDevsEx(classGUID *GUID, Enumerator *uint16, hwndParent uintptr, Flags DIGCF, deviceInfoSet DevInfo, machineName *uint16, reserved uintptr) (handle DevInfo, err error) [failretval==DevInfo(InvalidHandle)] = setupapi.SetupDiGetClassDevsExW
1043
1044// SetupDiGetClassDevsEx function returns a handle to a device information set that contains requested device information elements for a local or a remote computer.
1045func SetupDiGetClassDevsEx(classGUID *GUID, enumerator string, hwndParent uintptr, flags DIGCF, deviceInfoSet DevInfo, machineName string) (handle DevInfo, err error) {
1046	var enumeratorUTF16 *uint16
1047	if enumerator != "" {
1048		enumeratorUTF16, err = UTF16PtrFromString(enumerator)
1049		if err != nil {
1050			return
1051		}
1052	}
1053	var machineNameUTF16 *uint16
1054	if machineName != "" {
1055		machineNameUTF16, err = UTF16PtrFromString(machineName)
1056		if err != nil {
1057			return
1058		}
1059	}
1060	return setupDiGetClassDevsEx(classGUID, enumeratorUTF16, hwndParent, flags, deviceInfoSet, machineNameUTF16, 0)
1061}
1062
1063// SetupDiCallClassInstaller function calls the appropriate class installer, and any registered co-installers, with the specified installation request (DIF code).
1064//sys	SetupDiCallClassInstaller(installFunction DI_FUNCTION, deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) = setupapi.SetupDiCallClassInstaller
1065
1066// CallClassInstaller member calls the appropriate class installer, and any registered co-installers, with the specified installation request (DIF code).
1067func (deviceInfoSet DevInfo) CallClassInstaller(installFunction DI_FUNCTION, deviceInfoData *DevInfoData) error {
1068	return SetupDiCallClassInstaller(installFunction, deviceInfoSet, deviceInfoData)
1069}
1070
1071// SetupDiOpenDevRegKey function opens a registry key for device-specific configuration information.
1072//sys	SetupDiOpenDevRegKey(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, Scope DICS_FLAG, HwProfile uint32, KeyType DIREG, samDesired uint32) (key Handle, err error) [failretval==InvalidHandle] = setupapi.SetupDiOpenDevRegKey
1073
1074// OpenDevRegKey method opens a registry key for device-specific configuration information.
1075func (deviceInfoSet DevInfo) OpenDevRegKey(DeviceInfoData *DevInfoData, Scope DICS_FLAG, HwProfile uint32, KeyType DIREG, samDesired uint32) (Handle, error) {
1076	return SetupDiOpenDevRegKey(deviceInfoSet, DeviceInfoData, Scope, HwProfile, KeyType, samDesired)
1077}
1078
1079//sys	setupDiGetDeviceProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, propertyKey *DEVPROPKEY, propertyType *DEVPROPTYPE, propertyBuffer *byte, propertyBufferSize uint32, requiredSize *uint32, flags uint32) (err error) = setupapi.SetupDiGetDevicePropertyW
1080
1081// SetupDiGetDeviceProperty function retrieves a specified device instance property.
1082func SetupDiGetDeviceProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, propertyKey *DEVPROPKEY) (value interface{}, err error) {
1083	reqSize := uint32(256)
1084	for {
1085		var dataType DEVPROPTYPE
1086		buf := make([]byte, reqSize)
1087		err = setupDiGetDeviceProperty(deviceInfoSet, deviceInfoData, propertyKey, &dataType, &buf[0], uint32(len(buf)), &reqSize, 0)
1088		if err == ERROR_INSUFFICIENT_BUFFER {
1089			continue
1090		}
1091		if err != nil {
1092			return
1093		}
1094		switch dataType {
1095		case DEVPROP_TYPE_STRING:
1096			ret := UTF16ToString(bufToUTF16(buf))
1097			runtime.KeepAlive(buf)
1098			return ret, nil
1099		}
1100		return nil, errors.New("unimplemented property type")
1101	}
1102}
1103
1104//sys	setupDiGetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP, propertyRegDataType *uint32, propertyBuffer *byte, propertyBufferSize uint32, requiredSize *uint32) (err error) = setupapi.SetupDiGetDeviceRegistryPropertyW
1105
1106// SetupDiGetDeviceRegistryProperty function retrieves a specified Plug and Play device property.
1107func SetupDiGetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP) (value interface{}, err error) {
1108	reqSize := uint32(256)
1109	for {
1110		var dataType uint32
1111		buf := make([]byte, reqSize)
1112		err = setupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, &dataType, &buf[0], uint32(len(buf)), &reqSize)
1113		if err == ERROR_INSUFFICIENT_BUFFER {
1114			continue
1115		}
1116		if err != nil {
1117			return
1118		}
1119		return getRegistryValue(buf[:reqSize], dataType)
1120	}
1121}
1122
1123func getRegistryValue(buf []byte, dataType uint32) (interface{}, error) {
1124	switch dataType {
1125	case REG_SZ:
1126		ret := UTF16ToString(bufToUTF16(buf))
1127		runtime.KeepAlive(buf)
1128		return ret, nil
1129	case REG_EXPAND_SZ:
1130		value := UTF16ToString(bufToUTF16(buf))
1131		if value == "" {
1132			return "", nil
1133		}
1134		p, err := syscall.UTF16PtrFromString(value)
1135		if err != nil {
1136			return "", err
1137		}
1138		ret := make([]uint16, 100)
1139		for {
1140			n, err := ExpandEnvironmentStrings(p, &ret[0], uint32(len(ret)))
1141			if err != nil {
1142				return "", err
1143			}
1144			if n <= uint32(len(ret)) {
1145				return UTF16ToString(ret[:n]), nil
1146			}
1147			ret = make([]uint16, n)
1148		}
1149	case REG_BINARY:
1150		return buf, nil
1151	case REG_DWORD_LITTLE_ENDIAN:
1152		return binary.LittleEndian.Uint32(buf), nil
1153	case REG_DWORD_BIG_ENDIAN:
1154		return binary.BigEndian.Uint32(buf), nil
1155	case REG_MULTI_SZ:
1156		bufW := bufToUTF16(buf)
1157		a := []string{}
1158		for i := 0; i < len(bufW); {
1159			j := i + wcslen(bufW[i:])
1160			if i < j {
1161				a = append(a, UTF16ToString(bufW[i:j]))
1162			}
1163			i = j + 1
1164		}
1165		runtime.KeepAlive(buf)
1166		return a, nil
1167	case REG_QWORD_LITTLE_ENDIAN:
1168		return binary.LittleEndian.Uint64(buf), nil
1169	default:
1170		return nil, fmt.Errorf("Unsupported registry value type: %v", dataType)
1171	}
1172}
1173
1174// bufToUTF16 function reinterprets []byte buffer as []uint16
1175func bufToUTF16(buf []byte) []uint16 {
1176	sl := struct {
1177		addr *uint16
1178		len  int
1179		cap  int
1180	}{(*uint16)(unsafe.Pointer(&buf[0])), len(buf) / 2, cap(buf) / 2}
1181	return *(*[]uint16)(unsafe.Pointer(&sl))
1182}
1183
1184// utf16ToBuf function reinterprets []uint16 as []byte
1185func utf16ToBuf(buf []uint16) []byte {
1186	sl := struct {
1187		addr *byte
1188		len  int
1189		cap  int
1190	}{(*byte)(unsafe.Pointer(&buf[0])), len(buf) * 2, cap(buf) * 2}
1191	return *(*[]byte)(unsafe.Pointer(&sl))
1192}
1193
1194func wcslen(str []uint16) int {
1195	for i := 0; i < len(str); i++ {
1196		if str[i] == 0 {
1197			return i
1198		}
1199	}
1200	return len(str)
1201}
1202
1203// DeviceRegistryProperty method retrieves a specified Plug and Play device property.
1204func (deviceInfoSet DevInfo) DeviceRegistryProperty(deviceInfoData *DevInfoData, property SPDRP) (interface{}, error) {
1205	return SetupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property)
1206}
1207
1208//sys	setupDiSetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP, propertyBuffer *byte, propertyBufferSize uint32) (err error) = setupapi.SetupDiSetDeviceRegistryPropertyW
1209
1210// SetupDiSetDeviceRegistryProperty function sets a Plug and Play device property for a device.
1211func SetupDiSetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP, propertyBuffers []byte) error {
1212	return setupDiSetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, &propertyBuffers[0], uint32(len(propertyBuffers)))
1213}
1214
1215// SetDeviceRegistryProperty function sets a Plug and Play device property for a device.
1216func (deviceInfoSet DevInfo) SetDeviceRegistryProperty(deviceInfoData *DevInfoData, property SPDRP, propertyBuffers []byte) error {
1217	return SetupDiSetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, propertyBuffers)
1218}
1219
1220// SetDeviceRegistryPropertyString method sets a Plug and Play device property string for a device.
1221func (deviceInfoSet DevInfo) SetDeviceRegistryPropertyString(deviceInfoData *DevInfoData, property SPDRP, str string) error {
1222	str16, err := UTF16FromString(str)
1223	if err != nil {
1224		return err
1225	}
1226	err = SetupDiSetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, utf16ToBuf(append(str16, 0)))
1227	runtime.KeepAlive(str16)
1228	return err
1229}
1230
1231//sys	setupDiGetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, deviceInstallParams *DevInstallParams) (err error) = setupapi.SetupDiGetDeviceInstallParamsW
1232
1233// SetupDiGetDeviceInstallParams function retrieves device installation parameters for a device information set or a particular device information element.
1234func SetupDiGetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (*DevInstallParams, error) {
1235	params := &DevInstallParams{}
1236	params.size = uint32(unsafe.Sizeof(*params))
1237
1238	return params, setupDiGetDeviceInstallParams(deviceInfoSet, deviceInfoData, params)
1239}
1240
1241// DeviceInstallParams method retrieves device installation parameters for a device information set or a particular device information element.
1242func (deviceInfoSet DevInfo) DeviceInstallParams(deviceInfoData *DevInfoData) (*DevInstallParams, error) {
1243	return SetupDiGetDeviceInstallParams(deviceInfoSet, deviceInfoData)
1244}
1245
1246//sys	setupDiGetDeviceInstanceId(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, instanceId *uint16, instanceIdSize uint32, instanceIdRequiredSize *uint32) (err error) = setupapi.SetupDiGetDeviceInstanceIdW
1247
1248// SetupDiGetDeviceInstanceId function retrieves the instance ID of the device.
1249func SetupDiGetDeviceInstanceId(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (string, error) {
1250	reqSize := uint32(1024)
1251	for {
1252		buf := make([]uint16, reqSize)
1253		err := setupDiGetDeviceInstanceId(deviceInfoSet, deviceInfoData, &buf[0], uint32(len(buf)), &reqSize)
1254		if err == ERROR_INSUFFICIENT_BUFFER {
1255			continue
1256		}
1257		if err != nil {
1258			return "", err
1259		}
1260		return UTF16ToString(buf), nil
1261	}
1262}
1263
1264// DeviceInstanceID method retrieves the instance ID of the device.
1265func (deviceInfoSet DevInfo) DeviceInstanceID(deviceInfoData *DevInfoData) (string, error) {
1266	return SetupDiGetDeviceInstanceId(deviceInfoSet, deviceInfoData)
1267}
1268
1269// SetupDiGetClassInstallParams function retrieves class installation parameters for a device information set or a particular device information element.
1270//sys	SetupDiGetClassInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32, requiredSize *uint32) (err error) = setupapi.SetupDiGetClassInstallParamsW
1271
1272// ClassInstallParams method retrieves class installation parameters for a device information set or a particular device information element.
1273func (deviceInfoSet DevInfo) ClassInstallParams(deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32, requiredSize *uint32) error {
1274	return SetupDiGetClassInstallParams(deviceInfoSet, deviceInfoData, classInstallParams, classInstallParamsSize, requiredSize)
1275}
1276
1277//sys	SetupDiSetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, deviceInstallParams *DevInstallParams) (err error) = setupapi.SetupDiSetDeviceInstallParamsW
1278
1279// SetDeviceInstallParams member sets device installation parameters for a device information set or a particular device information element.
1280func (deviceInfoSet DevInfo) SetDeviceInstallParams(deviceInfoData *DevInfoData, deviceInstallParams *DevInstallParams) error {
1281	return SetupDiSetDeviceInstallParams(deviceInfoSet, deviceInfoData, deviceInstallParams)
1282}
1283
1284// SetupDiSetClassInstallParams function sets or clears class install parameters for a device information set or a particular device information element.
1285//sys	SetupDiSetClassInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32) (err error) = setupapi.SetupDiSetClassInstallParamsW
1286
1287// SetClassInstallParams method sets or clears class install parameters for a device information set or a particular device information element.
1288func (deviceInfoSet DevInfo) SetClassInstallParams(deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32) error {
1289	return SetupDiSetClassInstallParams(deviceInfoSet, deviceInfoData, classInstallParams, classInstallParamsSize)
1290}
1291
1292//sys	setupDiClassNameFromGuidEx(classGUID *GUID, className *uint16, classNameSize uint32, requiredSize *uint32, machineName *uint16, reserved uintptr) (err error) = setupapi.SetupDiClassNameFromGuidExW
1293
1294// SetupDiClassNameFromGuidEx function retrieves the class name associated with a class GUID. The class can be installed on a local or remote computer.
1295func SetupDiClassNameFromGuidEx(classGUID *GUID, machineName string) (className string, err error) {
1296	var classNameUTF16 [MAX_CLASS_NAME_LEN]uint16
1297
1298	var machineNameUTF16 *uint16
1299	if machineName != "" {
1300		machineNameUTF16, err = UTF16PtrFromString(machineName)
1301		if err != nil {
1302			return
1303		}
1304	}
1305
1306	err = setupDiClassNameFromGuidEx(classGUID, &classNameUTF16[0], MAX_CLASS_NAME_LEN, nil, machineNameUTF16, 0)
1307	if err != nil {
1308		return
1309	}
1310
1311	className = UTF16ToString(classNameUTF16[:])
1312	return
1313}
1314
1315//sys	setupDiClassGuidsFromNameEx(className *uint16, classGuidList *GUID, classGuidListSize uint32, requiredSize *uint32, machineName *uint16, reserved uintptr) (err error) = setupapi.SetupDiClassGuidsFromNameExW
1316
1317// 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.
1318func SetupDiClassGuidsFromNameEx(className string, machineName string) ([]GUID, error) {
1319	classNameUTF16, err := UTF16PtrFromString(className)
1320	if err != nil {
1321		return nil, err
1322	}
1323
1324	var machineNameUTF16 *uint16
1325	if machineName != "" {
1326		machineNameUTF16, err = UTF16PtrFromString(machineName)
1327		if err != nil {
1328			return nil, err
1329		}
1330	}
1331
1332	reqSize := uint32(4)
1333	for {
1334		buf := make([]GUID, reqSize)
1335		err = setupDiClassGuidsFromNameEx(classNameUTF16, &buf[0], uint32(len(buf)), &reqSize, machineNameUTF16, 0)
1336		if err == ERROR_INSUFFICIENT_BUFFER {
1337			continue
1338		}
1339		if err != nil {
1340			return nil, err
1341		}
1342		return buf[:reqSize], nil
1343	}
1344}
1345
1346//sys	setupDiGetSelectedDevice(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) = setupapi.SetupDiGetSelectedDevice
1347
1348// SetupDiGetSelectedDevice function retrieves the selected device information element in a device information set.
1349func SetupDiGetSelectedDevice(deviceInfoSet DevInfo) (*DevInfoData, error) {
1350	data := &DevInfoData{}
1351	data.size = uint32(unsafe.Sizeof(*data))
1352
1353	return data, setupDiGetSelectedDevice(deviceInfoSet, data)
1354}
1355
1356// SelectedDevice method retrieves the selected device information element in a device information set.
1357func (deviceInfoSet DevInfo) SelectedDevice() (*DevInfoData, error) {
1358	return SetupDiGetSelectedDevice(deviceInfoSet)
1359}
1360
1361// SetupDiSetSelectedDevice function sets a device information element as the selected member of a device information set. This function is typically used by an installation wizard.
1362//sys	SetupDiSetSelectedDevice(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) = setupapi.SetupDiSetSelectedDevice
1363
1364// SetSelectedDevice method sets a device information element as the selected member of a device information set. This function is typically used by an installation wizard.
1365func (deviceInfoSet DevInfo) SetSelectedDevice(deviceInfoData *DevInfoData) error {
1366	return SetupDiSetSelectedDevice(deviceInfoSet, deviceInfoData)
1367}
1368
1369//sys	setupUninstallOEMInf(infFileName *uint16, flags SUOI, reserved uintptr) (err error) = setupapi.SetupUninstallOEMInfW
1370
1371// SetupUninstallOEMInf uninstalls the specified driver.
1372func SetupUninstallOEMInf(infFileName string, flags SUOI) error {
1373	infFileName16, err := UTF16PtrFromString(infFileName)
1374	if err != nil {
1375		return err
1376	}
1377	return setupUninstallOEMInf(infFileName16, flags, 0)
1378}
1379
1380//sys cm_MapCrToWin32Err(configRet CONFIGRET, defaultWin32Error Errno) (ret Errno) = CfgMgr32.CM_MapCrToWin32Err
1381
1382//sys cm_Get_Device_Interface_List_Size(len *uint32, interfaceClass *GUID, deviceID *uint16, flags uint32) (ret CONFIGRET) = CfgMgr32.CM_Get_Device_Interface_List_SizeW
1383//sys cm_Get_Device_Interface_List(interfaceClass *GUID, deviceID *uint16, buffer *uint16, bufferLen uint32, flags uint32) (ret CONFIGRET) = CfgMgr32.CM_Get_Device_Interface_ListW
1384
1385func CM_Get_Device_Interface_List(deviceID string, interfaceClass *GUID, flags uint32) ([]string, error) {
1386	deviceID16, err := UTF16PtrFromString(deviceID)
1387	if err != nil {
1388		return nil, err
1389	}
1390	var buf []uint16
1391	var buflen uint32
1392	for {
1393		if ret := cm_Get_Device_Interface_List_Size(&buflen, interfaceClass, deviceID16, flags); ret != CR_SUCCESS {
1394			return nil, ret
1395		}
1396		buf = make([]uint16, buflen)
1397		if ret := cm_Get_Device_Interface_List(interfaceClass, deviceID16, &buf[0], buflen, flags); ret == CR_SUCCESS {
1398			break
1399		} else if ret != CR_BUFFER_SMALL {
1400			return nil, ret
1401		}
1402	}
1403	var interfaces []string
1404	for i := 0; i < len(buf); {
1405		j := i + wcslen(buf[i:])
1406		if i < j {
1407			interfaces = append(interfaces, UTF16ToString(buf[i:j]))
1408		}
1409		i = j + 1
1410	}
1411	if interfaces == nil {
1412		return nil, ERROR_NO_SUCH_DEVICE_INTERFACE
1413	}
1414	return interfaces, nil
1415}
1416
1417//sys cm_Get_DevNode_Status(status *uint32, problemNumber *uint32, devInst DEVINST, flags uint32) (ret CONFIGRET) = CfgMgr32.CM_Get_DevNode_Status
1418
1419func CM_Get_DevNode_Status(status *uint32, problemNumber *uint32, devInst DEVINST, flags uint32) error {
1420	ret := cm_Get_DevNode_Status(status, problemNumber, devInst, flags)
1421	if ret == CR_SUCCESS {
1422		return nil
1423	}
1424	return ret
1425}
1426