setupapi: Remove all device interfaces in SetupDiRemoveDevice().
[wine.git] / dlls / setupapi / devinst.c
blob7ff3cb01eb6e1d14dc00d802cb444b7ee8499685
1 /*
2 * SetupAPI device installer
4 * Copyright 2000 Andreas Mohr for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdlib.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winnt.h"
27 #include "winreg.h"
28 #include "winternl.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "winnls.h"
32 #include "winsvc.h"
33 #include "setupapi.h"
34 #include "wine/debug.h"
35 #include "wine/heap.h"
36 #include "wine/list.h"
37 #include "cfgmgr32.h"
38 #include "winioctl.h"
39 #include "rpc.h"
40 #include "rpcdce.h"
41 #include "cguid.h"
43 #include "setupapi_private.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
48 /* Unicode constants */
49 static const WCHAR Chicago[] = {'$','C','h','i','c','a','g','o','$',0};
50 static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0};
51 static const WCHAR Class[] = {'C','l','a','s','s',0};
52 static const WCHAR ClassInstall32[] = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
53 static const WCHAR NoDisplayClass[] = {'N','o','D','i','s','p','l','a','y','C','l','a','s','s',0};
54 static const WCHAR NoInstallClass[] = {'N','o','I','n','s','t','a','l','l','C','l','a','s','s',0};
55 static const WCHAR NoUseClass[] = {'N','o','U','s','e','C','l','a','s','s',0};
56 static const WCHAR NtExtension[] = {'.','N','T',0};
57 #ifdef __i386__
58 static const WCHAR NtPlatformExtension[] = {'.','N','T','x','8','6',0};
59 #elif defined(__x86_64__)
60 static const WCHAR NtPlatformExtension[] = {'.','N','T','a','m','d','6','4',0};
61 #elif defined(__arm__)
62 static const WCHAR NtPlatformExtension[] = {'.','N','T','a','r','m',0};
63 #elif defined(__aarch64__)
64 static const WCHAR NtPlatformExtension[] = {'.','N','T','a','r','m','6','4',0};
65 #endif
66 static const WCHAR Signature[] = {'S','i','g','n','a','t','u','r','e',0};
67 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
68 static const WCHAR WinExtension[] = {'.','W','i','n',0};
69 static const WCHAR WindowsNT[] = {'$','W','i','n','d','o','w','s',' ','N','T','$',0};
71 /* Registry key and value names */
72 static const WCHAR ControlClass[] = {'S','y','s','t','e','m','\\',
73 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
74 'C','o','n','t','r','o','l','\\',
75 'C','l','a','s','s',0};
77 static const WCHAR DeviceClasses[] = {'S','y','s','t','e','m','\\',
78 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
79 'C','o','n','t','r','o','l','\\',
80 'D','e','v','i','c','e','C','l','a','s','s','e','s',0};
81 static const WCHAR Enum[] = {'S','y','s','t','e','m','\\',
82 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
83 'E','n','u','m',0};
84 static const WCHAR DeviceDesc[] = {'D','e','v','i','c','e','D','e','s','c',0};
85 static const WCHAR DeviceInstance[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
86 static const WCHAR DeviceParameters[] = {'D','e','v','i','c','e',' ','P','a','r','a','m','e','t','e','r','s',0};
87 static const WCHAR HardwareId[] = {'H','a','r','d','w','a','r','e','I','D',0};
88 static const WCHAR CompatibleIDs[] = {'C','o','m','p','a','t','i','b','l','e','I','d','s',0};
89 static const WCHAR Service[] = {'S','e','r','v','i','c','e',0};
90 static const WCHAR Driver[] = {'D','r','i','v','e','r',0};
91 static const WCHAR ConfigFlags[] = {'C','o','n','f','i','g','F','l','a','g','s',0};
92 static const WCHAR Mfg[] = {'M','f','g',0};
93 static const WCHAR FriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
94 static const WCHAR LocationInformation[] = {'L','o','c','a','t','i','o','n','I','n','f','o','r','m','a','t','i','o','n',0};
95 static const WCHAR Capabilities[] = {'C','a','p','a','b','i','l','i','t','i','e','s',0};
96 static const WCHAR UINumber[] = {'U','I','N','u','m','b','e','r',0};
97 static const WCHAR UpperFilters[] = {'U','p','p','e','r','F','i','l','t','e','r','s',0};
98 static const WCHAR LowerFilters[] = {'L','o','w','e','r','F','i','l','t','e','r','s',0};
99 static const WCHAR Phantom[] = {'P','h','a','n','t','o','m',0};
100 static const WCHAR SymbolicLink[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
101 static const WCHAR Control[] = {'C','o','n','t','r','o','l',0};
102 static const WCHAR Linked[] = {'L','i','n','k','e','d',0};
103 static const WCHAR dotInterfaces[] = {'.','I','n','t','e','r','f','a','c','e','s',0};
104 static const WCHAR AddInterface[] = {'A','d','d','I','n','t','e','r','f','a','c','e',0};
105 static const WCHAR backslashW[] = {'\\',0};
106 static const WCHAR emptyW[] = {0};
108 #define SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES 128
110 struct driver
112 WCHAR inf_path[MAX_PATH];
113 WCHAR manufacturer[LINE_LEN];
114 WCHAR mfg_key[LINE_LEN];
115 WCHAR description[LINE_LEN];
116 WCHAR section[LINE_LEN];
119 /* is used to identify if a DeviceInfoSet pointer is
120 valid or not */
121 #define SETUP_DEVICE_INFO_SET_MAGIC 0xd00ff056
123 struct DeviceInfoSet
125 DWORD magic; /* if is equal to SETUP_DEVICE_INFO_SET_MAGIC struct is okay */
126 GUID ClassGuid;
127 HWND hwndParent;
128 struct list devices;
131 struct device
133 struct DeviceInfoSet *set;
134 HKEY key;
135 BOOL phantom;
136 WCHAR *instanceId;
137 struct list interfaces;
138 GUID class;
139 DEVINST devnode;
140 struct list entry;
141 BOOL removed;
142 SP_DEVINSTALL_PARAMS_W params;
143 struct driver *drivers;
144 unsigned int driver_count;
145 struct driver *selected_driver;
148 struct device_iface
150 WCHAR *refstr;
151 WCHAR *symlink;
152 struct device *device;
153 GUID class;
154 DWORD flags;
155 HKEY class_key;
156 HKEY refstr_key;
157 struct list entry;
160 static struct DeviceInfoSet *get_device_set(HDEVINFO devinfo)
162 struct DeviceInfoSet *set = devinfo;
164 if (!devinfo || devinfo == INVALID_HANDLE_VALUE || set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
166 SetLastError(ERROR_INVALID_HANDLE);
167 return NULL;
170 return set;
173 static struct device *get_device(HDEVINFO devinfo, const SP_DEVINFO_DATA *data)
175 struct DeviceInfoSet *set;
176 struct device *device;
178 if (!(set = get_device_set(devinfo)))
179 return FALSE;
181 if (!data || data->cbSize != sizeof(*data) || !data->Reserved)
183 SetLastError(ERROR_INVALID_PARAMETER);
184 return NULL;
187 device = (struct device *)data->Reserved;
189 if (device->set != set)
191 SetLastError(ERROR_INVALID_PARAMETER);
192 return NULL;
195 if (device->removed)
197 SetLastError(ERROR_NO_SUCH_DEVINST);
198 return NULL;
201 return device;
204 static struct device_iface *get_device_iface(HDEVINFO devinfo, const SP_DEVICE_INTERFACE_DATA *data)
206 if (!get_device_set(devinfo))
207 return FALSE;
209 if (!data || data->cbSize != sizeof(*data) || !data->Reserved)
211 SetLastError(ERROR_INVALID_PARAMETER);
212 return NULL;
215 return (struct device_iface *)data->Reserved;
218 static inline void copy_device_data(SP_DEVINFO_DATA *data, const struct device *device)
220 data->ClassGuid = device->class;
221 data->DevInst = device->devnode;
222 data->Reserved = (ULONG_PTR)device;
225 static inline void copy_device_iface_data(SP_DEVICE_INTERFACE_DATA *data,
226 const struct device_iface *iface)
228 data->InterfaceClassGuid = iface->class;
229 data->Flags = iface->flags;
230 data->Reserved = (ULONG_PTR)iface;
233 static struct device **devnode_table;
234 static unsigned int devnode_table_size;
236 static DEVINST alloc_devnode(struct device *device)
238 unsigned int i;
240 for (i = 0; i < devnode_table_size; ++i)
242 if (!devnode_table[i])
243 break;
246 if (i == devnode_table_size)
248 if (devnode_table)
250 devnode_table_size *= 2;
251 devnode_table = heap_realloc_zero(devnode_table,
252 devnode_table_size * sizeof(*devnode_table));
254 else
256 devnode_table_size = 256;
257 devnode_table = heap_alloc_zero(devnode_table_size * sizeof(*devnode_table));
261 devnode_table[i] = device;
262 return i;
265 static void free_devnode(DEVINST devnode)
267 devnode_table[devnode] = NULL;
270 static struct device *get_devnode_device(DEVINST devnode)
272 if (devnode < devnode_table_size)
273 return devnode_table[devnode];
275 WARN("device node %u not found\n", devnode);
276 return NULL;
279 static void SETUPDI_GuidToString(const GUID *guid, LPWSTR guidStr)
281 static const WCHAR fmt[] = {'{','%','0','8','X','-','%','0','4','X','-',
282 '%','0','4','X','-','%','0','2','X','%','0','2','X','-','%','0','2',
283 'X','%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X','%',
284 '0','2','X','}',0};
286 swprintf(guidStr, 39, fmt, guid->Data1, guid->Data2, guid->Data3,
287 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
288 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
291 static WCHAR *get_iface_key_path(struct device_iface *iface)
293 static const WCHAR slashW[] = {'\\',0};
294 WCHAR *path, *ptr;
295 size_t len = lstrlenW(DeviceClasses) + 1 + 38 + 1 + lstrlenW(iface->symlink);
297 if (!(path = heap_alloc((len + 1) * sizeof(WCHAR))))
299 SetLastError(ERROR_OUTOFMEMORY);
300 return NULL;
303 lstrcpyW(path, DeviceClasses);
304 lstrcatW(path, slashW);
305 SETUPDI_GuidToString(&iface->class, path + lstrlenW(path));
306 lstrcatW(path, slashW);
307 ptr = path + lstrlenW(path);
308 lstrcatW(path, iface->symlink);
309 if (lstrlenW(iface->symlink) > 3)
310 ptr[0] = ptr[1] = ptr[3] = '#';
312 ptr = wcschr(ptr, '\\');
313 if (ptr) *ptr = 0;
315 return path;
318 static WCHAR *get_refstr_key_path(struct device_iface *iface)
320 static const WCHAR hashW[] = {'#',0};
321 static const WCHAR slashW[] = {'\\',0};
322 WCHAR *path, *ptr;
323 size_t len = lstrlenW(DeviceClasses) + 1 + 38 + 1 + lstrlenW(iface->symlink) + 1 + 1;
325 if (iface->refstr)
326 len += lstrlenW(iface->refstr);
328 if (!(path = heap_alloc((len + 1) * sizeof(WCHAR))))
330 SetLastError(ERROR_OUTOFMEMORY);
331 return NULL;
334 lstrcpyW(path, DeviceClasses);
335 lstrcatW(path, slashW);
336 SETUPDI_GuidToString(&iface->class, path + lstrlenW(path));
337 lstrcatW(path, slashW);
338 ptr = path + lstrlenW(path);
339 lstrcatW(path, iface->symlink);
340 if (lstrlenW(iface->symlink) > 3)
341 ptr[0] = ptr[1] = ptr[3] = '#';
343 ptr = wcschr(ptr, '\\');
344 if (ptr) *ptr = 0;
346 lstrcatW(path, slashW);
347 lstrcatW(path, hashW);
349 if (iface->refstr)
350 lstrcatW(path, iface->refstr);
352 return path;
355 static BOOL is_valid_property_type(DEVPROPTYPE prop_type)
357 DWORD type = prop_type & DEVPROP_MASK_TYPE;
358 DWORD typemod = prop_type & DEVPROP_MASK_TYPEMOD;
360 if (type > MAX_DEVPROP_TYPE)
361 return FALSE;
362 if (typemod > MAX_DEVPROP_TYPEMOD)
363 return FALSE;
365 if (typemod == DEVPROP_TYPEMOD_ARRAY
366 && (type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL || type == DEVPROP_TYPE_STRING
367 || type == DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING))
368 return FALSE;
370 if (typemod == DEVPROP_TYPEMOD_LIST
371 && !(type == DEVPROP_TYPE_STRING || type == DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING))
372 return FALSE;
374 return TRUE;
377 static LPWSTR SETUPDI_CreateSymbolicLinkPath(LPCWSTR instanceId,
378 const GUID *InterfaceClassGuid, LPCWSTR ReferenceString)
380 static const WCHAR fmt[] = {'\\','\\','?','\\','%','s','#','%','s',0};
381 WCHAR guidStr[39];
382 DWORD len;
383 LPWSTR ret;
385 SETUPDI_GuidToString(InterfaceClassGuid, guidStr);
386 /* omit length of format specifiers, but include NULL terminator: */
387 len = lstrlenW(fmt) - 4 + 1;
388 len += lstrlenW(instanceId) + lstrlenW(guidStr);
389 if (ReferenceString && *ReferenceString)
391 /* space for a hash between string and reference string: */
392 len += lstrlenW(ReferenceString) + 1;
394 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
395 if (ret)
397 int printed = swprintf(ret, len, fmt, instanceId, guidStr);
398 LPWSTR ptr;
400 /* replace '\\' with '#' after the "\\\\?\\" beginning */
401 for (ptr = wcschr(ret + 4, '\\'); ptr; ptr = wcschr(ptr + 1, '\\'))
402 *ptr = '#';
403 if (ReferenceString && *ReferenceString)
405 ret[printed] = '\\';
406 lstrcpyW(ret + printed + 1, ReferenceString);
409 return ret;
412 static BOOL is_linked(HKEY key)
414 DWORD linked, type, size;
415 HKEY control_key;
416 BOOL ret = FALSE;
418 if (!RegOpenKeyW(key, Control, &control_key))
420 size = sizeof(DWORD);
421 if (!RegQueryValueExW(control_key, Linked, NULL, &type, (BYTE *)&linked, &size)
422 && type == REG_DWORD && linked)
423 ret = TRUE;
425 RegCloseKey(control_key);
428 return ret;
431 static struct device_iface *SETUPDI_CreateDeviceInterface(struct device *device,
432 const GUID *class, const WCHAR *refstr)
434 struct device_iface *iface = NULL;
435 WCHAR *refstr2 = NULL, *symlink = NULL, *path = NULL;
436 HKEY key;
437 LONG ret;
439 TRACE("%p %s %s\n", device, debugstr_guid(class), debugstr_w(refstr));
441 /* check if it already exists */
442 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
444 if (IsEqualGUID(&iface->class, class) && !lstrcmpiW(iface->refstr, refstr))
445 return iface;
448 iface = heap_alloc(sizeof(*iface));
449 symlink = SETUPDI_CreateSymbolicLinkPath(device->instanceId, class, refstr);
451 if (!iface || !symlink)
453 SetLastError(ERROR_OUTOFMEMORY);
454 goto err;
457 if (refstr && !(refstr2 = strdupW(refstr)))
459 SetLastError(ERROR_OUTOFMEMORY);
460 goto err;
462 iface->refstr = refstr2;
463 iface->symlink = symlink;
464 iface->device = device;
465 iface->class = *class;
466 iface->flags = 0;
468 if (!(path = get_iface_key_path(iface)))
470 SetLastError(ERROR_OUTOFMEMORY);
471 goto err;
474 if ((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, path, &key)))
476 SetLastError(ret);
477 goto err;
479 RegSetValueExW(key, DeviceInstance, 0, REG_SZ, (BYTE *)device->instanceId,
480 lstrlenW(device->instanceId) * sizeof(WCHAR));
481 heap_free(path);
483 iface->class_key = key;
485 if (!(path = get_refstr_key_path(iface)))
487 SetLastError(ERROR_OUTOFMEMORY);
488 goto err;
491 if ((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, path, &key)))
493 SetLastError(ret);
494 goto err;
496 RegSetValueExW(key, SymbolicLink, 0, REG_SZ, (BYTE *)iface->symlink,
497 lstrlenW(iface->symlink) * sizeof(WCHAR));
499 if (is_linked(key))
500 iface->flags |= SPINT_ACTIVE;
502 heap_free(path);
504 iface->refstr_key = key;
506 list_add_tail(&device->interfaces, &iface->entry);
507 return iface;
509 err:
510 heap_free(iface);
511 heap_free(refstr2);
512 heap_free(symlink);
513 heap_free(path);
514 return NULL;
517 static BOOL SETUPDI_SetInterfaceSymbolicLink(struct device_iface *iface,
518 const WCHAR *symlink)
520 heap_free(iface->symlink);
521 if ((iface->symlink = strdupW(symlink)))
522 return TRUE;
523 return FALSE;
526 static HKEY SETUPDI_CreateDevKey(struct device *device)
528 HKEY enumKey, key = INVALID_HANDLE_VALUE;
529 LONG l;
531 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_ALL_ACCESS,
532 NULL, &enumKey, NULL);
533 if (!l)
535 RegCreateKeyExW(enumKey, device->instanceId, 0, NULL, 0,
536 KEY_READ | KEY_WRITE, NULL, &key, NULL);
537 RegCloseKey(enumKey);
539 return key;
542 static LONG open_driver_key(struct device *device, REGSAM access, HKEY *key)
544 HKEY class_key;
545 WCHAR path[50];
546 DWORD size = sizeof(path);
547 LONG l;
549 if ((l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, ControlClass, 0, NULL, 0,
550 KEY_CREATE_SUB_KEY, NULL, &class_key, NULL)))
552 ERR("Failed to open driver class root key, error %u.\n", l);
553 return l;
556 if (!(l = RegGetValueW(device->key, NULL, Driver, RRF_RT_REG_SZ, NULL, path, &size)))
558 if (!(l = RegOpenKeyExW(class_key, path, 0, access, key)))
560 RegCloseKey(class_key);
561 return l;
563 ERR("Failed to open driver key, error %u.\n", l);
566 RegCloseKey(class_key);
567 return l;
570 static LONG create_driver_key(struct device *device, HKEY *key)
572 static const WCHAR formatW[] = {'%','0','4','u',0};
573 static const WCHAR slash[] = { '\\',0 };
574 unsigned int i = 0;
575 WCHAR path[50];
576 HKEY class_key;
577 DWORD dispos;
578 LONG l;
580 if (!open_driver_key(device, KEY_READ | KEY_WRITE, key))
581 return ERROR_SUCCESS;
583 if ((l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, ControlClass, 0, NULL, 0,
584 KEY_CREATE_SUB_KEY, NULL, &class_key, NULL)))
586 ERR("Failed to open driver class root key, error %u.\n", l);
587 return l;
590 SETUPDI_GuidToString(&device->class, path);
591 lstrcatW(path, slash);
592 /* Allocate a new driver key, by finding the first integer value that's not
593 * already taken. */
594 for (;;)
596 swprintf(path + 39, ARRAY_SIZE(path) - 39, formatW, i++);
597 if ((l = RegCreateKeyExW(class_key, path, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, key, &dispos)))
598 break;
599 else if (dispos == REG_CREATED_NEW_KEY)
601 RegSetValueExW(device->key, Driver, 0, REG_SZ, (BYTE *)path, lstrlenW(path) * sizeof(WCHAR));
602 RegCloseKey(class_key);
603 return ERROR_SUCCESS;
605 RegCloseKey(*key);
607 ERR("Failed to create driver key, error %u.\n", l);
608 RegCloseKey(class_key);
609 return l;
612 static LONG delete_driver_key(struct device *device)
614 HKEY key;
615 LONG l;
617 if (!(l = open_driver_key(device, KEY_READ | KEY_WRITE, &key)))
619 l = RegDeleteKeyW(key, emptyW);
620 RegCloseKey(key);
623 return l;
626 struct PropertyMapEntry
628 DWORD regType;
629 LPCSTR nameA;
630 LPCWSTR nameW;
633 static const struct PropertyMapEntry PropertyMap[] = {
634 { REG_SZ, "DeviceDesc", DeviceDesc },
635 { REG_MULTI_SZ, "HardwareId", HardwareId },
636 { REG_MULTI_SZ, "CompatibleIDs", CompatibleIDs },
637 { 0, NULL, NULL }, /* SPDRP_UNUSED0 */
638 { REG_SZ, "Service", Service },
639 { 0, NULL, NULL }, /* SPDRP_UNUSED1 */
640 { 0, NULL, NULL }, /* SPDRP_UNUSED2 */
641 { REG_SZ, "Class", Class },
642 { REG_SZ, "ClassGUID", ClassGUID },
643 { REG_SZ, "Driver", Driver },
644 { REG_DWORD, "ConfigFlags", ConfigFlags },
645 { REG_SZ, "Mfg", Mfg },
646 { REG_SZ, "FriendlyName", FriendlyName },
647 { REG_SZ, "LocationInformation", LocationInformation },
648 { 0, NULL, NULL }, /* SPDRP_PHYSICAL_DEVICE_OBJECT_NAME */
649 { REG_DWORD, "Capabilities", Capabilities },
650 { REG_DWORD, "UINumber", UINumber },
651 { REG_MULTI_SZ, "UpperFilters", UpperFilters },
652 { REG_MULTI_SZ, "LowerFilters", LowerFilters },
655 static BOOL SETUPDI_SetDeviceRegistryPropertyW(struct device *device,
656 DWORD prop, const BYTE *buffer, DWORD size)
658 if (prop < ARRAY_SIZE(PropertyMap) && PropertyMap[prop].nameW)
660 LONG ret = RegSetValueExW(device->key, PropertyMap[prop].nameW, 0,
661 PropertyMap[prop].regType, buffer, size);
662 if (!ret)
663 return TRUE;
665 SetLastError(ret);
667 return FALSE;
670 static void remove_device_iface(struct device_iface *iface)
672 RegDeleteTreeW(iface->refstr_key, NULL);
673 RegDeleteKeyW(iface->refstr_key, emptyW);
674 RegCloseKey(iface->refstr_key);
675 iface->refstr_key = NULL;
676 /* Also remove the class key if it's empty. */
677 RegDeleteKeyW(iface->class_key, emptyW);
678 RegCloseKey(iface->class_key);
679 iface->class_key = NULL;
680 iface->flags |= SPINT_REMOVED;
683 static void delete_device_iface(struct device_iface *iface)
685 list_remove(&iface->entry);
686 RegCloseKey(iface->refstr_key);
687 RegCloseKey(iface->class_key);
688 heap_free(iface->refstr);
689 heap_free(iface->symlink);
690 heap_free(iface);
693 /* remove all interfaces associated with the device, including those not
694 * enumerated in the set */
695 static void remove_all_device_ifaces(struct device *device)
697 HKEY classes_key;
698 DWORD i, len;
699 LONG ret;
701 if ((ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, DeviceClasses, 0, KEY_READ, &classes_key)))
703 ERR("Failed to open classes key, error %u.\n", ret);
704 return;
707 for (i = 0; ; ++i)
709 WCHAR class_name[40];
710 HKEY class_key;
711 DWORD j;
713 len = ARRAY_SIZE(class_name);
714 if ((ret = RegEnumKeyExW(classes_key, i, class_name, &len, NULL, NULL, NULL, NULL)))
716 if (ret != ERROR_NO_MORE_ITEMS) ERR("Failed to enumerate classes, error %u.\n", ret);
717 break;
720 if ((ret = RegOpenKeyExW(classes_key, class_name, 0, KEY_READ, &class_key)))
722 ERR("Failed to open class %s, error %u.\n", debugstr_w(class_name), ret);
723 continue;
726 for (j = 0; ; ++j)
728 WCHAR iface_name[MAX_DEVICE_ID_LEN + 39], device_name[MAX_DEVICE_ID_LEN];
729 HKEY iface_key;
731 len = ARRAY_SIZE(iface_name);
732 if ((ret = RegEnumKeyExW(class_key, j, iface_name, &len, NULL, NULL, NULL, NULL)))
734 if (ret != ERROR_NO_MORE_ITEMS) ERR("Failed to enumerate interfaces, error %u.\n", ret);
735 break;
738 if ((ret = RegOpenKeyExW(class_key, iface_name, 0, KEY_ALL_ACCESS, &iface_key)))
740 ERR("Failed to open interface %s, error %u.\n", debugstr_w(iface_name), ret);
741 continue;
744 len = sizeof(device_name);
745 if ((ret = RegQueryValueExW(iface_key, L"DeviceInstance", NULL, NULL, (BYTE *)device_name, &len)))
747 ERR("Failed to query device instance, error %u.\n", ret);
748 RegCloseKey(iface_key);
749 continue;
752 if (!wcsicmp(device_name, device->instanceId))
754 if ((ret = RegDeleteTreeW(iface_key, NULL)))
755 ERR("Failed to delete interface %s subkeys, error %u.\n", debugstr_w(iface_name), ret);
756 if ((ret = RegDeleteKeyW(iface_key, L"")))
757 ERR("Failed to delete interface %s, error %u.\n", debugstr_w(iface_name), ret);
760 RegCloseKey(iface_key);
762 RegCloseKey(class_key);
765 RegCloseKey(classes_key);
768 static void remove_device(struct device *device)
770 WCHAR id[MAX_DEVICE_ID_LEN], *p;
771 struct device_iface *iface;
772 HKEY enum_key;
774 delete_driver_key(device);
776 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
778 remove_device_iface(iface);
781 RegDeleteTreeW(device->key, NULL);
782 RegDeleteKeyW(device->key, emptyW);
784 /* delete all empty parents of the key */
785 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, 0, &enum_key))
787 lstrcpyW(id, device->instanceId);
789 while ((p = wcsrchr(id, '\\')))
791 *p = 0;
792 RegDeleteKeyW(enum_key, id);
795 RegCloseKey(enum_key);
798 RegCloseKey(device->key);
799 device->key = NULL;
800 device->removed = TRUE;
803 static void delete_device(struct device *device)
805 struct device_iface *iface, *next;
806 SP_DEVINFO_DATA device_data;
808 device_data.cbSize = sizeof(device_data);
809 copy_device_data(&device_data, device);
810 SetupDiCallClassInstaller(DIF_DESTROYPRIVATEDATA, device->set, &device_data);
812 if (device->phantom)
814 remove_device(device);
815 remove_all_device_ifaces(device);
818 RegCloseKey(device->key);
819 heap_free(device->instanceId);
820 heap_free(device->drivers);
822 LIST_FOR_EACH_ENTRY_SAFE(iface, next, &device->interfaces,
823 struct device_iface, entry)
825 delete_device_iface(iface);
827 free_devnode(device->devnode);
828 list_remove(&device->entry);
829 heap_free(device);
832 /* Create a new device, or return a device already in the set. */
833 static struct device *create_device(struct DeviceInfoSet *set,
834 const GUID *class, const WCHAR *instanceid, BOOL phantom)
836 const DWORD one = 1;
837 struct device *device;
838 WCHAR guidstr[MAX_GUID_STRING_LEN];
839 WCHAR class_name[MAX_CLASS_NAME_LEN];
840 DWORD size;
842 TRACE("%p, %s, %s, %d\n", set, debugstr_guid(class),
843 debugstr_w(instanceid), phantom);
845 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
847 if (!wcsicmp(instanceid, device->instanceId))
849 TRACE("Found device %p already in set.\n", device);
850 return device;
854 if (!(device = heap_alloc_zero(sizeof(*device))))
856 SetLastError(ERROR_OUTOFMEMORY);
857 return NULL;
860 if (!(device->instanceId = strdupW(instanceid)))
862 SetLastError(ERROR_OUTOFMEMORY);
863 heap_free(device);
864 return NULL;
867 wcsupr(device->instanceId);
868 device->set = set;
869 device->key = SETUPDI_CreateDevKey(device);
870 device->phantom = phantom;
871 list_init(&device->interfaces);
872 device->class = *class;
873 device->devnode = alloc_devnode(device);
874 device->removed = FALSE;
875 list_add_tail(&set->devices, &device->entry);
876 device->params.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
878 if (phantom)
879 RegSetValueExW(device->key, Phantom, 0, REG_DWORD, (const BYTE *)&one, sizeof(one));
881 SETUPDI_GuidToString(class, guidstr);
882 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_CLASSGUID,
883 (const BYTE *)guidstr, sizeof(guidstr));
885 if (SetupDiClassNameFromGuidW(class, class_name, ARRAY_SIZE(class_name), NULL))
887 size = (lstrlenW(class_name) + 1) * sizeof(WCHAR);
888 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_CLASS, (const BYTE *)class_name, size);
891 TRACE("Created new device %p.\n", device);
892 return device;
895 /***********************************************************************
896 * SetupDiBuildClassInfoList (SETUPAPI.@)
898 * Returns a list of setup class GUIDs that identify the classes
899 * that are installed on a local machine.
901 * PARAMS
902 * Flags [I] control exclusion of classes from the list.
903 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
904 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
905 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
907 * RETURNS
908 * Success: TRUE.
909 * Failure: FALSE.
911 BOOL WINAPI SetupDiBuildClassInfoList(
912 DWORD Flags,
913 LPGUID ClassGuidList,
914 DWORD ClassGuidListSize,
915 PDWORD RequiredSize)
917 TRACE("\n");
918 return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
919 ClassGuidListSize, RequiredSize,
920 NULL, NULL);
923 /***********************************************************************
924 * SetupDiBuildClassInfoListExA (SETUPAPI.@)
926 * Returns a list of setup class GUIDs that identify the classes
927 * that are installed on a local or remote machine.
929 * PARAMS
930 * Flags [I] control exclusion of classes from the list.
931 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
932 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
933 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
934 * MachineName [I] name of a remote machine.
935 * Reserved [I] must be NULL.
937 * RETURNS
938 * Success: TRUE.
939 * Failure: FALSE.
941 BOOL WINAPI SetupDiBuildClassInfoListExA(
942 DWORD Flags,
943 LPGUID ClassGuidList,
944 DWORD ClassGuidListSize,
945 PDWORD RequiredSize,
946 LPCSTR MachineName,
947 PVOID Reserved)
949 LPWSTR MachineNameW = NULL;
950 BOOL bResult;
952 TRACE("\n");
954 if (MachineName)
956 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
957 if (MachineNameW == NULL) return FALSE;
960 bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
961 ClassGuidListSize, RequiredSize,
962 MachineNameW, Reserved);
964 MyFree(MachineNameW);
966 return bResult;
969 /***********************************************************************
970 * SetupDiBuildClassInfoListExW (SETUPAPI.@)
972 * Returns a list of setup class GUIDs that identify the classes
973 * that are installed on a local or remote machine.
975 * PARAMS
976 * Flags [I] control exclusion of classes from the list.
977 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
978 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
979 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
980 * MachineName [I] name of a remote machine.
981 * Reserved [I] must be NULL.
983 * RETURNS
984 * Success: TRUE.
985 * Failure: FALSE.
987 BOOL WINAPI SetupDiBuildClassInfoListExW(
988 DWORD Flags,
989 LPGUID ClassGuidList,
990 DWORD ClassGuidListSize,
991 PDWORD RequiredSize,
992 LPCWSTR MachineName,
993 PVOID Reserved)
995 WCHAR szKeyName[40];
996 HKEY hClassesKey;
997 HKEY hClassKey;
998 DWORD dwLength;
999 DWORD dwIndex;
1000 LONG lError;
1001 DWORD dwGuidListIndex = 0;
1003 TRACE("\n");
1005 if (RequiredSize != NULL)
1006 *RequiredSize = 0;
1008 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
1009 KEY_ALL_ACCESS,
1010 DIOCR_INSTALLER,
1011 MachineName,
1012 Reserved);
1013 if (hClassesKey == INVALID_HANDLE_VALUE)
1015 return FALSE;
1018 for (dwIndex = 0; ; dwIndex++)
1020 dwLength = 40;
1021 lError = RegEnumKeyExW(hClassesKey,
1022 dwIndex,
1023 szKeyName,
1024 &dwLength,
1025 NULL,
1026 NULL,
1027 NULL,
1028 NULL);
1029 TRACE("RegEnumKeyExW() returns %d\n", lError);
1030 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
1032 TRACE("Key name: %p\n", szKeyName);
1034 if (RegOpenKeyExW(hClassesKey,
1035 szKeyName,
1037 KEY_ALL_ACCESS,
1038 &hClassKey))
1040 RegCloseKey(hClassesKey);
1041 return FALSE;
1044 if (!RegQueryValueExW(hClassKey,
1045 NoUseClass,
1046 NULL,
1047 NULL,
1048 NULL,
1049 NULL))
1051 TRACE("'NoUseClass' value found!\n");
1052 RegCloseKey(hClassKey);
1053 continue;
1056 if ((Flags & DIBCI_NOINSTALLCLASS) &&
1057 (!RegQueryValueExW(hClassKey,
1058 NoInstallClass,
1059 NULL,
1060 NULL,
1061 NULL,
1062 NULL)))
1064 TRACE("'NoInstallClass' value found!\n");
1065 RegCloseKey(hClassKey);
1066 continue;
1069 if ((Flags & DIBCI_NODISPLAYCLASS) &&
1070 (!RegQueryValueExW(hClassKey,
1071 NoDisplayClass,
1072 NULL,
1073 NULL,
1074 NULL,
1075 NULL)))
1077 TRACE("'NoDisplayClass' value found!\n");
1078 RegCloseKey(hClassKey);
1079 continue;
1082 RegCloseKey(hClassKey);
1084 TRACE("Guid: %p\n", szKeyName);
1085 if (dwGuidListIndex < ClassGuidListSize)
1087 if (szKeyName[0] == '{' && szKeyName[37] == '}')
1089 szKeyName[37] = 0;
1091 TRACE("Guid: %p\n", &szKeyName[1]);
1093 UuidFromStringW(&szKeyName[1],
1094 &ClassGuidList[dwGuidListIndex]);
1097 dwGuidListIndex++;
1100 if (lError != ERROR_SUCCESS)
1101 break;
1104 RegCloseKey(hClassesKey);
1106 if (RequiredSize != NULL)
1107 *RequiredSize = dwGuidListIndex;
1109 if (ClassGuidListSize < dwGuidListIndex)
1111 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1112 return FALSE;
1115 return TRUE;
1118 /***********************************************************************
1119 * SetupDiClassGuidsFromNameA (SETUPAPI.@)
1121 BOOL WINAPI SetupDiClassGuidsFromNameA(
1122 LPCSTR ClassName,
1123 LPGUID ClassGuidList,
1124 DWORD ClassGuidListSize,
1125 PDWORD RequiredSize)
1127 return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
1128 ClassGuidListSize, RequiredSize,
1129 NULL, NULL);
1132 /***********************************************************************
1133 * SetupDiClassGuidsFromNameW (SETUPAPI.@)
1135 BOOL WINAPI SetupDiClassGuidsFromNameW(
1136 LPCWSTR ClassName,
1137 LPGUID ClassGuidList,
1138 DWORD ClassGuidListSize,
1139 PDWORD RequiredSize)
1141 return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
1142 ClassGuidListSize, RequiredSize,
1143 NULL, NULL);
1146 /***********************************************************************
1147 * SetupDiClassGuidsFromNameExA (SETUPAPI.@)
1149 BOOL WINAPI SetupDiClassGuidsFromNameExA(
1150 LPCSTR ClassName,
1151 LPGUID ClassGuidList,
1152 DWORD ClassGuidListSize,
1153 PDWORD RequiredSize,
1154 LPCSTR MachineName,
1155 PVOID Reserved)
1157 LPWSTR ClassNameW = NULL;
1158 LPWSTR MachineNameW = NULL;
1159 BOOL bResult;
1161 ClassNameW = MultiByteToUnicode(ClassName, CP_ACP);
1162 if (ClassNameW == NULL)
1163 return FALSE;
1165 if (MachineName)
1167 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1168 if (MachineNameW == NULL)
1170 MyFree(ClassNameW);
1171 return FALSE;
1175 bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
1176 ClassGuidListSize, RequiredSize,
1177 MachineNameW, Reserved);
1179 MyFree(MachineNameW);
1180 MyFree(ClassNameW);
1182 return bResult;
1185 /***********************************************************************
1186 * SetupDiClassGuidsFromNameExW (SETUPAPI.@)
1188 BOOL WINAPI SetupDiClassGuidsFromNameExW(
1189 LPCWSTR ClassName,
1190 LPGUID ClassGuidList,
1191 DWORD ClassGuidListSize,
1192 PDWORD RequiredSize,
1193 LPCWSTR MachineName,
1194 PVOID Reserved)
1196 WCHAR szKeyName[40];
1197 WCHAR szClassName[256];
1198 HKEY hClassesKey;
1199 HKEY hClassKey;
1200 DWORD dwLength;
1201 DWORD dwIndex;
1202 LONG lError;
1203 DWORD dwGuidListIndex = 0;
1205 if (RequiredSize != NULL)
1206 *RequiredSize = 0;
1208 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
1209 KEY_ALL_ACCESS,
1210 DIOCR_INSTALLER,
1211 MachineName,
1212 Reserved);
1213 if (hClassesKey == INVALID_HANDLE_VALUE)
1215 return FALSE;
1218 for (dwIndex = 0; ; dwIndex++)
1220 dwLength = ARRAY_SIZE(szKeyName);
1221 lError = RegEnumKeyExW(hClassesKey,
1222 dwIndex,
1223 szKeyName,
1224 &dwLength,
1225 NULL,
1226 NULL,
1227 NULL,
1228 NULL);
1229 TRACE("RegEnumKeyExW() returns %d\n", lError);
1230 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
1232 TRACE("Key name: %p\n", szKeyName);
1234 if (RegOpenKeyExW(hClassesKey,
1235 szKeyName,
1237 KEY_ALL_ACCESS,
1238 &hClassKey))
1240 RegCloseKey(hClassesKey);
1241 return FALSE;
1244 dwLength = sizeof(szClassName);
1245 if (!RegQueryValueExW(hClassKey,
1246 Class,
1247 NULL,
1248 NULL,
1249 (LPBYTE)szClassName,
1250 &dwLength))
1252 TRACE("Class name: %p\n", szClassName);
1254 if (wcsicmp(szClassName, ClassName) == 0)
1256 TRACE("Found matching class name\n");
1258 TRACE("Guid: %p\n", szKeyName);
1259 if (dwGuidListIndex < ClassGuidListSize)
1261 if (szKeyName[0] == '{' && szKeyName[37] == '}')
1263 szKeyName[37] = 0;
1265 TRACE("Guid: %p\n", &szKeyName[1]);
1267 UuidFromStringW(&szKeyName[1],
1268 &ClassGuidList[dwGuidListIndex]);
1271 dwGuidListIndex++;
1275 RegCloseKey(hClassKey);
1278 if (lError != ERROR_SUCCESS)
1279 break;
1282 RegCloseKey(hClassesKey);
1284 if (RequiredSize != NULL)
1285 *RequiredSize = dwGuidListIndex;
1287 if (ClassGuidListSize < dwGuidListIndex)
1289 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1290 return FALSE;
1293 return TRUE;
1296 /***********************************************************************
1297 * SetupDiClassNameFromGuidA (SETUPAPI.@)
1299 BOOL WINAPI SetupDiClassNameFromGuidA(
1300 const GUID* ClassGuid,
1301 PSTR ClassName,
1302 DWORD ClassNameSize,
1303 PDWORD RequiredSize)
1305 return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
1306 ClassNameSize, RequiredSize,
1307 NULL, NULL);
1310 /***********************************************************************
1311 * SetupDiClassNameFromGuidW (SETUPAPI.@)
1313 BOOL WINAPI SetupDiClassNameFromGuidW(
1314 const GUID* ClassGuid,
1315 PWSTR ClassName,
1316 DWORD ClassNameSize,
1317 PDWORD RequiredSize)
1319 return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
1320 ClassNameSize, RequiredSize,
1321 NULL, NULL);
1324 /***********************************************************************
1325 * SetupDiClassNameFromGuidExA (SETUPAPI.@)
1327 BOOL WINAPI SetupDiClassNameFromGuidExA(
1328 const GUID* ClassGuid,
1329 PSTR ClassName,
1330 DWORD ClassNameSize,
1331 PDWORD RequiredSize,
1332 PCSTR MachineName,
1333 PVOID Reserved)
1335 WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
1336 LPWSTR MachineNameW = NULL;
1337 BOOL ret;
1339 if (MachineName)
1340 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1341 ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
1342 NULL, MachineNameW, Reserved);
1343 if (ret)
1345 int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
1346 ClassNameSize, NULL, NULL);
1348 if (!ClassNameSize && RequiredSize)
1349 *RequiredSize = len;
1351 MyFree(MachineNameW);
1352 return ret;
1355 /***********************************************************************
1356 * SetupDiClassNameFromGuidExW (SETUPAPI.@)
1358 BOOL WINAPI SetupDiClassNameFromGuidExW(
1359 const GUID* ClassGuid,
1360 PWSTR ClassName,
1361 DWORD ClassNameSize,
1362 PDWORD RequiredSize,
1363 PCWSTR MachineName,
1364 PVOID Reserved)
1366 HKEY hKey;
1367 DWORD dwLength;
1369 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
1370 KEY_ALL_ACCESS,
1371 DIOCR_INSTALLER,
1372 MachineName,
1373 Reserved);
1374 if (hKey == INVALID_HANDLE_VALUE)
1376 return FALSE;
1379 if (RequiredSize != NULL)
1381 dwLength = 0;
1382 if (RegQueryValueExW(hKey,
1383 Class,
1384 NULL,
1385 NULL,
1386 NULL,
1387 &dwLength))
1389 RegCloseKey(hKey);
1390 return FALSE;
1393 *RequiredSize = dwLength / sizeof(WCHAR);
1396 dwLength = ClassNameSize * sizeof(WCHAR);
1397 if (RegQueryValueExW(hKey,
1398 Class,
1399 NULL,
1400 NULL,
1401 (LPBYTE)ClassName,
1402 &dwLength))
1404 RegCloseKey(hKey);
1405 return FALSE;
1408 RegCloseKey(hKey);
1410 return TRUE;
1413 /***********************************************************************
1414 * SetupDiCreateDeviceInfoList (SETUPAPI.@)
1416 HDEVINFO WINAPI
1417 SetupDiCreateDeviceInfoList(const GUID *ClassGuid,
1418 HWND hwndParent)
1420 return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
1423 /***********************************************************************
1424 * SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
1426 HDEVINFO WINAPI
1427 SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
1428 HWND hwndParent,
1429 PCSTR MachineName,
1430 PVOID Reserved)
1432 LPWSTR MachineNameW = NULL;
1433 HDEVINFO hDevInfo;
1435 TRACE("\n");
1437 if (MachineName)
1439 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1440 if (MachineNameW == NULL)
1441 return INVALID_HANDLE_VALUE;
1444 hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
1445 MachineNameW, Reserved);
1447 MyFree(MachineNameW);
1449 return hDevInfo;
1452 /***********************************************************************
1453 * SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
1455 * Create an empty DeviceInfoSet list.
1457 * PARAMS
1458 * ClassGuid [I] if not NULL only devices with GUID ClassGuid are associated
1459 * with this list.
1460 * hwndParent [I] hwnd needed for interface related actions.
1461 * MachineName [I] name of machine to create empty DeviceInfoSet list, if NULL
1462 * local registry will be used.
1463 * Reserved [I] must be NULL
1465 * RETURNS
1466 * Success: empty list.
1467 * Failure: INVALID_HANDLE_VALUE.
1469 HDEVINFO WINAPI
1470 SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
1471 HWND hwndParent,
1472 PCWSTR MachineName,
1473 PVOID Reserved)
1475 struct DeviceInfoSet *list = NULL;
1476 DWORD size = sizeof(struct DeviceInfoSet);
1478 TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
1479 debugstr_w(MachineName), Reserved);
1481 if (MachineName && *MachineName)
1483 FIXME("remote support is not implemented\n");
1484 SetLastError(ERROR_INVALID_MACHINENAME);
1485 return INVALID_HANDLE_VALUE;
1488 if (Reserved != NULL)
1490 SetLastError(ERROR_INVALID_PARAMETER);
1491 return INVALID_HANDLE_VALUE;
1494 list = HeapAlloc(GetProcessHeap(), 0, size);
1495 if (!list)
1497 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1498 return INVALID_HANDLE_VALUE;
1501 list->magic = SETUP_DEVICE_INFO_SET_MAGIC;
1502 list->hwndParent = hwndParent;
1503 memcpy(&list->ClassGuid,
1504 ClassGuid ? ClassGuid : &GUID_NULL,
1505 sizeof(list->ClassGuid));
1506 list_init(&list->devices);
1508 return list;
1511 /***********************************************************************
1512 * SetupDiCreateDevRegKeyA (SETUPAPI.@)
1514 HKEY WINAPI SetupDiCreateDevRegKeyA(
1515 HDEVINFO DeviceInfoSet,
1516 PSP_DEVINFO_DATA DeviceInfoData,
1517 DWORD Scope,
1518 DWORD HwProfile,
1519 DWORD KeyType,
1520 HINF InfHandle,
1521 PCSTR InfSectionName)
1523 PWSTR InfSectionNameW = NULL;
1524 HKEY key;
1526 TRACE("%p %p %d %d %d %p %s\n", DeviceInfoSet, DeviceInfoData, Scope,
1527 HwProfile, KeyType, InfHandle, debugstr_a(InfSectionName));
1529 if (InfHandle)
1531 if (!InfSectionName)
1533 SetLastError(ERROR_INVALID_PARAMETER);
1534 return INVALID_HANDLE_VALUE;
1536 else
1538 InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
1539 if (InfSectionNameW == NULL) return INVALID_HANDLE_VALUE;
1542 key = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, Scope,
1543 HwProfile, KeyType, InfHandle, InfSectionNameW);
1544 MyFree(InfSectionNameW);
1545 return key;
1548 /***********************************************************************
1549 * SetupDiCreateDevRegKeyW (SETUPAPI.@)
1551 HKEY WINAPI SetupDiCreateDevRegKeyW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD Scope,
1552 DWORD HwProfile, DWORD KeyType, HINF InfHandle, const WCHAR *InfSectionName)
1554 struct device *device;
1555 HKEY key = INVALID_HANDLE_VALUE;
1556 LONG l;
1558 TRACE("devinfo %p, device_data %p, scope %d, profile %d, type %d, inf_handle %p, inf_section %s.\n",
1559 devinfo, device_data, Scope, HwProfile, KeyType, InfHandle, debugstr_w(InfSectionName));
1561 if (!(device = get_device(devinfo, device_data)))
1562 return INVALID_HANDLE_VALUE;
1564 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
1566 SetLastError(ERROR_INVALID_FLAGS);
1567 return INVALID_HANDLE_VALUE;
1569 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
1571 SetLastError(ERROR_INVALID_FLAGS);
1572 return INVALID_HANDLE_VALUE;
1574 if (device->phantom)
1576 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
1577 return INVALID_HANDLE_VALUE;
1579 if (Scope != DICS_FLAG_GLOBAL)
1580 FIXME("unimplemented for scope %d\n", Scope);
1581 switch (KeyType)
1583 case DIREG_DEV:
1584 l = RegCreateKeyExW(device->key, DeviceParameters, 0, NULL, 0,
1585 KEY_READ | KEY_WRITE, NULL, &key, NULL);
1586 break;
1587 case DIREG_DRV:
1588 l = create_driver_key(device, &key);
1589 break;
1590 default:
1591 FIXME("Unhandled type %#x.\n", KeyType);
1592 l = ERROR_CALL_NOT_IMPLEMENTED;
1594 if (InfHandle)
1595 SetupInstallFromInfSectionW(NULL, InfHandle, InfSectionName, SPINST_ALL,
1596 NULL, NULL, SP_COPY_NEWER_ONLY, NULL, NULL, devinfo, device_data);
1597 SetLastError(l);
1598 return l ? INVALID_HANDLE_VALUE : key;
1601 /***********************************************************************
1602 * SetupDiCreateDeviceInfoA (SETUPAPI.@)
1604 BOOL WINAPI SetupDiCreateDeviceInfoA(HDEVINFO DeviceInfoSet, const char *name,
1605 const GUID *ClassGuid, PCSTR DeviceDescription, HWND hwndParent, DWORD CreationFlags,
1606 PSP_DEVINFO_DATA DeviceInfoData)
1608 WCHAR nameW[MAX_DEVICE_ID_LEN];
1609 BOOL ret = FALSE;
1610 LPWSTR DeviceDescriptionW = NULL;
1612 if (!name || strlen(name) >= MAX_DEVICE_ID_LEN)
1614 SetLastError(ERROR_INVALID_DEVINST_NAME);
1615 return FALSE;
1618 MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, ARRAY_SIZE(nameW));
1620 if (DeviceDescription)
1622 DeviceDescriptionW = MultiByteToUnicode(DeviceDescription, CP_ACP);
1623 if (DeviceDescriptionW == NULL)
1624 return FALSE;
1627 ret = SetupDiCreateDeviceInfoW(DeviceInfoSet, nameW, ClassGuid, DeviceDescriptionW,
1628 hwndParent, CreationFlags, DeviceInfoData);
1630 MyFree(DeviceDescriptionW);
1632 return ret;
1635 /***********************************************************************
1636 * SetupDiCreateDeviceInfoW (SETUPAPI.@)
1638 BOOL WINAPI SetupDiCreateDeviceInfoW(HDEVINFO devinfo, const WCHAR *name, const GUID *class,
1639 const WCHAR *description, HWND parent, DWORD flags, SP_DEVINFO_DATA *device_data)
1641 WCHAR id[MAX_DEVICE_ID_LEN];
1642 struct DeviceInfoSet *set;
1643 HKEY enum_hkey;
1644 HKEY instance_hkey;
1645 struct device *device;
1646 LONG l;
1648 TRACE("devinfo %p, name %s, class %s, description %s, hwnd %p, flags %#x, device_data %p.\n",
1649 devinfo, debugstr_w(name), debugstr_guid(class), debugstr_w(description),
1650 parent, flags, device_data);
1652 if (!name || lstrlenW(name) >= MAX_DEVICE_ID_LEN)
1654 SetLastError(ERROR_INVALID_DEVINST_NAME);
1655 return FALSE;
1658 if (!(set = get_device_set(devinfo)))
1659 return FALSE;
1661 if (!class)
1663 SetLastError(ERROR_INVALID_PARAMETER);
1664 return FALSE;
1667 if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) && !IsEqualGUID(class, &set->ClassGuid))
1669 SetLastError(ERROR_CLASS_MISMATCH);
1670 return FALSE;
1672 if ((flags & DICD_GENERATE_ID))
1674 static const WCHAR formatW[] = {'R','O','O','T','\\','%','s','\\','%','0','4','u',0};
1675 unsigned int instance_id;
1677 if (wcschr(name, '\\'))
1679 SetLastError(ERROR_INVALID_DEVINST_NAME);
1680 return FALSE;
1683 for (instance_id = 0; ; ++instance_id)
1685 if (swprintf(id, ARRAY_SIZE(id), formatW, name, instance_id) == -1)
1687 SetLastError(ERROR_INVALID_DEVINST_NAME);
1688 return FALSE;
1691 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL, &enum_hkey, NULL);
1692 if (!(l = RegOpenKeyExW(enum_hkey, id, 0, KEY_READ, &instance_hkey)))
1693 RegCloseKey(instance_hkey);
1694 if (l == ERROR_FILE_NOT_FOUND)
1695 break;
1696 RegCloseKey(enum_hkey);
1699 else
1701 /* Check if instance is already in registry */
1702 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL, &enum_hkey, NULL);
1703 if (!RegOpenKeyExW(enum_hkey, name, 0, KEY_READ, &instance_hkey))
1705 RegCloseKey(instance_hkey);
1706 RegCloseKey(enum_hkey);
1707 SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
1708 return FALSE;
1710 RegCloseKey(enum_hkey);
1712 /* Check if instance is already in set */
1713 lstrcpyW(id, name);
1714 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
1716 if (!lstrcmpiW(name, device->instanceId))
1718 SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
1719 return FALSE;
1724 if (!(device = create_device(set, class, id, TRUE)))
1725 return FALSE;
1727 if (description)
1729 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_DEVICEDESC,
1730 (const BYTE *)description, lstrlenW(description) * sizeof(WCHAR));
1733 if (device_data)
1735 if (device_data->cbSize != sizeof(SP_DEVINFO_DATA))
1737 SetLastError(ERROR_INVALID_USER_BUFFER);
1738 return FALSE;
1740 else
1741 copy_device_data(device_data, device);
1744 return TRUE;
1747 /***********************************************************************
1748 * SetupDiRegisterDeviceInfo (SETUPAPI.@)
1750 BOOL WINAPI SetupDiRegisterDeviceInfo(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD flags,
1751 PSP_DETSIG_CMPPROC compare_proc, void *context, SP_DEVINFO_DATA *duplicate_data)
1753 struct device *device;
1755 TRACE("devinfo %p, data %p, flags %#x, compare_proc %p, context %p, duplicate_data %p.\n",
1756 devinfo, device_data, flags, compare_proc, context, duplicate_data);
1758 if (!(device = get_device(devinfo, device_data)))
1759 return FALSE;
1761 if (device->phantom)
1763 device->phantom = FALSE;
1764 RegDeleteValueW(device->key, Phantom);
1766 return TRUE;
1769 /***********************************************************************
1770 * SetupDiRemoveDevice (SETUPAPI.@)
1772 BOOL WINAPI SetupDiRemoveDevice(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
1774 SC_HANDLE manager = NULL, service = NULL;
1775 struct device *device;
1776 WCHAR *service_name;
1777 DWORD size;
1779 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
1781 if (!(device = get_device(devinfo, device_data)))
1782 return FALSE;
1784 if (!(manager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT)))
1785 return FALSE;
1787 if (!RegGetValueW(device->key, NULL, L"Service", RRF_RT_REG_SZ, NULL, NULL, &size))
1789 service_name = malloc(size);
1790 if (!RegGetValueW(device->key, NULL, L"Service", RRF_RT_REG_SZ, NULL, service_name, &size))
1791 service = OpenServiceW(manager, service_name, SERVICE_USER_DEFINED_CONTROL);
1792 free(service_name);
1795 remove_device(device);
1797 if (service)
1799 SERVICE_STATUS status;
1800 if (!ControlService(service, SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES, &status))
1801 ERR("Failed to control service %s, error %u.\n", debugstr_w(service_name), GetLastError());
1802 CloseServiceHandle(service);
1804 CloseServiceHandle(manager);
1806 remove_all_device_ifaces(device);
1808 return TRUE;
1811 /***********************************************************************
1812 * SetupDiDeleteDeviceInfo (SETUPAPI.@)
1814 BOOL WINAPI SetupDiDeleteDeviceInfo(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
1816 struct device *device;
1818 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
1820 if (!(device = get_device(devinfo, device_data)))
1821 return FALSE;
1823 delete_device(device);
1825 return TRUE;
1828 /***********************************************************************
1829 * SetupDiRemoveDeviceInterface (SETUPAPI.@)
1831 BOOL WINAPI SetupDiRemoveDeviceInterface(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data)
1833 struct device_iface *iface;
1835 TRACE("devinfo %p, iface_data %p.\n", devinfo, iface_data);
1837 if (!(iface = get_device_iface(devinfo, iface_data)))
1838 return FALSE;
1840 remove_device_iface(iface);
1842 return TRUE;
1845 /***********************************************************************
1846 * SetupDiDeleteDeviceInterfaceData (SETUPAPI.@)
1848 BOOL WINAPI SetupDiDeleteDeviceInterfaceData(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data)
1850 struct device_iface *iface;
1852 TRACE("devinfo %p, iface_data %p.\n", devinfo, iface_data);
1854 if (!(iface = get_device_iface(devinfo, iface_data)))
1855 return FALSE;
1857 delete_device_iface(iface);
1859 return TRUE;
1862 /***********************************************************************
1863 * SetupDiEnumDeviceInfo (SETUPAPI.@)
1865 BOOL WINAPI DECLSPEC_HOTPATCH SetupDiEnumDeviceInfo(HDEVINFO devinfo, DWORD index, SP_DEVINFO_DATA *device_data)
1867 struct DeviceInfoSet *set;
1868 struct device *device;
1869 DWORD i = 0;
1871 TRACE("devinfo %p, index %d, device_data %p\n", devinfo, index, device_data);
1873 if (!(set = get_device_set(devinfo)))
1874 return FALSE;
1876 if (!device_data)
1878 SetLastError(ERROR_INVALID_PARAMETER);
1879 return FALSE;
1882 if (device_data->cbSize != sizeof(SP_DEVINFO_DATA))
1884 SetLastError(ERROR_INVALID_USER_BUFFER);
1885 return FALSE;
1888 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
1890 if (i++ == index)
1892 copy_device_data(device_data, device);
1893 return TRUE;
1897 SetLastError(ERROR_NO_MORE_ITEMS);
1898 return FALSE;
1901 /***********************************************************************
1902 * SetupDiGetDeviceInstanceIdA (SETUPAPI.@)
1904 BOOL WINAPI SetupDiGetDeviceInstanceIdA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
1905 char *id, DWORD size, DWORD *needed)
1907 WCHAR idW[MAX_DEVICE_ID_LEN];
1909 TRACE("devinfo %p, device_data %p, id %p, size %d, needed %p.\n",
1910 devinfo, device_data, id, size, needed);
1912 if (!SetupDiGetDeviceInstanceIdW(devinfo, device_data, idW, ARRAY_SIZE(idW), NULL))
1913 return FALSE;
1915 if (needed)
1916 *needed = WideCharToMultiByte(CP_ACP, 0, idW, -1, NULL, 0, NULL, NULL);
1918 if (size && WideCharToMultiByte(CP_ACP, 0, idW, -1, id, size, NULL, NULL))
1919 return TRUE;
1921 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1922 return FALSE;
1925 /***********************************************************************
1926 * SetupDiGetDeviceInstanceIdW (SETUPAPI.@)
1928 BOOL WINAPI SetupDiGetDeviceInstanceIdW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
1929 WCHAR *DeviceInstanceId, DWORD DeviceInstanceIdSize, DWORD *RequiredSize)
1931 struct device *device;
1933 TRACE("devinfo %p, device_data %p, DeviceInstanceId %p, DeviceInstanceIdSize %d, RequiredSize %p.\n",
1934 devinfo, device_data, DeviceInstanceId, DeviceInstanceIdSize, RequiredSize);
1936 if (!(device = get_device(devinfo, device_data)))
1937 return FALSE;
1939 TRACE("instance ID: %s\n", debugstr_w(device->instanceId));
1940 if (DeviceInstanceIdSize < lstrlenW(device->instanceId) + 1)
1942 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1943 if (RequiredSize)
1944 *RequiredSize = lstrlenW(device->instanceId) + 1;
1945 return FALSE;
1947 lstrcpyW(DeviceInstanceId, device->instanceId);
1948 if (RequiredSize)
1949 *RequiredSize = lstrlenW(device->instanceId) + 1;
1950 return TRUE;
1953 /***********************************************************************
1954 * SetupDiGetActualSectionToInstallExA (SETUPAPI.@)
1956 BOOL WINAPI SetupDiGetActualSectionToInstallExA(HINF hinf, const char *section, SP_ALTPLATFORM_INFO *altplatform,
1957 char *section_ext, DWORD size, DWORD *needed, char **extptr, void *reserved)
1959 WCHAR sectionW[LINE_LEN], section_extW[LINE_LEN], *extptrW;
1960 BOOL ret;
1962 MultiByteToWideChar(CP_ACP, 0, section, -1, sectionW, ARRAY_SIZE(sectionW));
1964 ret = SetupDiGetActualSectionToInstallExW(hinf, sectionW, altplatform, section_extW,
1965 ARRAY_SIZE(section_extW), NULL, &extptrW, reserved);
1966 if (ret)
1968 if (needed)
1969 *needed = WideCharToMultiByte(CP_ACP, 0, section_extW, -1, NULL, 0, NULL, NULL);
1971 if (section_ext)
1972 ret = !!WideCharToMultiByte(CP_ACP, 0, section_extW, -1, section_ext, size, NULL, NULL);
1974 if (extptr)
1976 if (extptrW)
1977 *extptr = section_ext + WideCharToMultiByte(CP_ACP, 0, section_extW,
1978 extptrW - section_extW, NULL, 0, NULL, NULL);
1979 else
1980 *extptr = NULL;
1984 return ret;
1987 /***********************************************************************
1988 * SetupDiGetActualSectionToInstallA (SETUPAPI.@)
1990 BOOL WINAPI SetupDiGetActualSectionToInstallA(HINF hinf, const char *section, char *section_ext,
1991 DWORD size, DWORD *needed, char **extptr)
1993 return SetupDiGetActualSectionToInstallExA(hinf, section, NULL, section_ext, size,
1994 needed, extptr, NULL);
1997 /***********************************************************************
1998 * SetupDiGetActualSectionToInstallExW (SETUPAPI.@)
2000 BOOL WINAPI SetupDiGetActualSectionToInstallExW(HINF hinf, const WCHAR *section, SP_ALTPLATFORM_INFO *altplatform,
2001 WCHAR *section_ext, DWORD size, DWORD *needed, WCHAR **extptr, void *reserved)
2003 WCHAR buffer[MAX_PATH];
2004 DWORD len;
2005 DWORD full_len;
2006 LONG line_count = -1;
2008 TRACE("hinf %p, section %s, altplatform %p, ext %p, size %d, needed %p, extptr %p, reserved %p.\n",
2009 hinf, debugstr_w(section), altplatform, section_ext, size, needed, extptr, reserved);
2011 if (altplatform)
2012 FIXME("SP_ALTPLATFORM_INFO unsupported\n");
2014 lstrcpyW(buffer, section);
2015 len = lstrlenW(buffer);
2017 if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
2019 /* Test section name with '.NTx86' extension */
2020 lstrcpyW(&buffer[len], NtPlatformExtension);
2021 line_count = SetupGetLineCountW(hinf, buffer);
2023 if (line_count == -1)
2025 /* Test section name with '.NT' extension */
2026 lstrcpyW(&buffer[len], NtExtension);
2027 line_count = SetupGetLineCountW(hinf, buffer);
2030 else
2032 /* Test section name with '.Win' extension */
2033 lstrcpyW(&buffer[len], WinExtension);
2034 line_count = SetupGetLineCountW(hinf, buffer);
2037 if (line_count == -1)
2038 buffer[len] = 0;
2040 full_len = lstrlenW(buffer);
2042 if (section_ext != NULL && size != 0)
2044 if (size < (full_len + 1))
2046 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2047 return FALSE;
2050 lstrcpyW(section_ext, buffer);
2051 if (extptr != NULL)
2053 *extptr = (len == full_len) ? NULL : &section_ext[len];
2057 if (needed != NULL)
2059 *needed = full_len + 1;
2062 return TRUE;
2065 /***********************************************************************
2066 * SetupDiGetActualSectionToInstallW (SETUPAPI.@)
2068 BOOL WINAPI SetupDiGetActualSectionToInstallW(HINF hinf, const WCHAR *section, WCHAR *section_ext,
2069 DWORD size, DWORD *needed, WCHAR **extptr)
2071 return SetupDiGetActualSectionToInstallExW(hinf, section, NULL, section_ext, size,
2072 needed, extptr, NULL);
2075 /***********************************************************************
2076 * SetupDiGetClassDescriptionA (SETUPAPI.@)
2078 BOOL WINAPI SetupDiGetClassDescriptionA(
2079 const GUID* ClassGuid,
2080 PSTR ClassDescription,
2081 DWORD ClassDescriptionSize,
2082 PDWORD RequiredSize)
2084 return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
2085 ClassDescriptionSize,
2086 RequiredSize, NULL, NULL);
2089 /***********************************************************************
2090 * SetupDiGetClassDescriptionW (SETUPAPI.@)
2092 BOOL WINAPI SetupDiGetClassDescriptionW(
2093 const GUID* ClassGuid,
2094 PWSTR ClassDescription,
2095 DWORD ClassDescriptionSize,
2096 PDWORD RequiredSize)
2098 return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
2099 ClassDescriptionSize,
2100 RequiredSize, NULL, NULL);
2103 /***********************************************************************
2104 * SetupDiGetClassDescriptionExA (SETUPAPI.@)
2106 BOOL WINAPI SetupDiGetClassDescriptionExA(
2107 const GUID* ClassGuid,
2108 PSTR ClassDescription,
2109 DWORD ClassDescriptionSize,
2110 PDWORD RequiredSize,
2111 PCSTR MachineName,
2112 PVOID Reserved)
2114 HKEY hKey;
2115 DWORD dwLength;
2116 BOOL ret;
2118 hKey = SetupDiOpenClassRegKeyExA(ClassGuid,
2119 KEY_ALL_ACCESS,
2120 DIOCR_INSTALLER,
2121 MachineName,
2122 Reserved);
2123 if (hKey == INVALID_HANDLE_VALUE)
2125 WARN("SetupDiOpenClassRegKeyExA() failed (Error %u)\n", GetLastError());
2126 return FALSE;
2129 dwLength = ClassDescriptionSize;
2130 ret = !RegQueryValueExA( hKey, NULL, NULL, NULL,
2131 (LPBYTE)ClassDescription, &dwLength );
2132 if (RequiredSize) *RequiredSize = dwLength;
2133 RegCloseKey(hKey);
2134 return ret;
2137 /***********************************************************************
2138 * SetupDiGetClassDescriptionExW (SETUPAPI.@)
2140 BOOL WINAPI SetupDiGetClassDescriptionExW(
2141 const GUID* ClassGuid,
2142 PWSTR ClassDescription,
2143 DWORD ClassDescriptionSize,
2144 PDWORD RequiredSize,
2145 PCWSTR MachineName,
2146 PVOID Reserved)
2148 HKEY hKey;
2149 DWORD dwLength;
2150 BOOL ret;
2152 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
2153 KEY_ALL_ACCESS,
2154 DIOCR_INSTALLER,
2155 MachineName,
2156 Reserved);
2157 if (hKey == INVALID_HANDLE_VALUE)
2159 WARN("SetupDiOpenClassRegKeyExW() failed (Error %u)\n", GetLastError());
2160 return FALSE;
2163 dwLength = ClassDescriptionSize * sizeof(WCHAR);
2164 ret = !RegQueryValueExW( hKey, NULL, NULL, NULL,
2165 (LPBYTE)ClassDescription, &dwLength );
2166 if (RequiredSize) *RequiredSize = dwLength / sizeof(WCHAR);
2167 RegCloseKey(hKey);
2168 return ret;
2171 /***********************************************************************
2172 * SetupDiGetClassDevsA (SETUPAPI.@)
2174 HDEVINFO WINAPI SetupDiGetClassDevsA(const GUID *class, LPCSTR enumstr, HWND parent, DWORD flags)
2176 HDEVINFO ret;
2177 LPWSTR enumstrW = NULL;
2179 if (enumstr)
2181 int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
2182 enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2183 if (!enumstrW)
2185 ret = INVALID_HANDLE_VALUE;
2186 goto end;
2188 MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
2190 ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, NULL, NULL,
2191 NULL);
2192 HeapFree(GetProcessHeap(), 0, enumstrW);
2194 end:
2195 return ret;
2198 /***********************************************************************
2199 * SetupDiGetClassDevsExA (SETUPAPI.@)
2201 HDEVINFO WINAPI SetupDiGetClassDevsExA(
2202 const GUID *class,
2203 PCSTR enumstr,
2204 HWND parent,
2205 DWORD flags,
2206 HDEVINFO deviceset,
2207 PCSTR machine,
2208 PVOID reserved)
2210 HDEVINFO ret;
2211 LPWSTR enumstrW = NULL, machineW = NULL;
2213 if (enumstr)
2215 int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
2216 enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2217 if (!enumstrW)
2219 ret = INVALID_HANDLE_VALUE;
2220 goto end;
2222 MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
2224 if (machine)
2226 int len = MultiByteToWideChar(CP_ACP, 0, machine, -1, NULL, 0);
2227 machineW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2228 if (!machineW)
2230 HeapFree(GetProcessHeap(), 0, enumstrW);
2231 ret = INVALID_HANDLE_VALUE;
2232 goto end;
2234 MultiByteToWideChar(CP_ACP, 0, machine, -1, machineW, len);
2236 ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset,
2237 machineW, reserved);
2238 HeapFree(GetProcessHeap(), 0, enumstrW);
2239 HeapFree(GetProcessHeap(), 0, machineW);
2241 end:
2242 return ret;
2245 static void SETUPDI_AddDeviceInterfaces(struct device *device, HKEY key,
2246 const GUID *guid, DWORD flags)
2248 DWORD i, len;
2249 WCHAR subKeyName[MAX_PATH];
2250 LONG l = ERROR_SUCCESS;
2252 for (i = 0; !l; i++)
2254 len = ARRAY_SIZE(subKeyName);
2255 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2256 if (!l)
2258 HKEY subKey;
2259 struct device_iface *iface;
2261 if (*subKeyName == '#')
2263 /* The subkey name is the reference string, with a '#' prepended */
2264 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2265 if (!l)
2267 WCHAR symbolicLink[MAX_PATH];
2268 DWORD dataType;
2270 if (!(flags & DIGCF_PRESENT) || is_linked(subKey))
2272 iface = SETUPDI_CreateDeviceInterface(device, guid, subKeyName + 1);
2274 len = sizeof(symbolicLink);
2275 l = RegQueryValueExW(subKey, SymbolicLink, NULL, &dataType,
2276 (BYTE *)symbolicLink, &len);
2277 if (!l && dataType == REG_SZ)
2278 SETUPDI_SetInterfaceSymbolicLink(iface, symbolicLink);
2279 RegCloseKey(subKey);
2283 /* Allow enumeration to continue */
2284 l = ERROR_SUCCESS;
2287 /* FIXME: find and add all the device's interfaces to the device */
2290 static void SETUPDI_EnumerateMatchingInterfaces(HDEVINFO DeviceInfoSet,
2291 HKEY key, const GUID *guid, const WCHAR *enumstr, DWORD flags)
2293 struct DeviceInfoSet *set = DeviceInfoSet;
2294 DWORD i, len;
2295 WCHAR subKeyName[MAX_PATH];
2296 LONG l;
2297 HKEY enumKey = INVALID_HANDLE_VALUE;
2299 TRACE("%s\n", debugstr_w(enumstr));
2301 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL,
2302 &enumKey, NULL);
2303 for (i = 0; !l; i++)
2305 len = ARRAY_SIZE(subKeyName);
2306 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2307 if (!l)
2309 HKEY subKey;
2311 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2312 if (!l)
2314 WCHAR deviceInst[MAX_PATH * 3];
2315 DWORD dataType;
2317 len = sizeof(deviceInst);
2318 l = RegQueryValueExW(subKey, DeviceInstance, NULL, &dataType,
2319 (BYTE *)deviceInst, &len);
2320 if (!l && dataType == REG_SZ)
2322 TRACE("found instance ID %s\n", debugstr_w(deviceInst));
2323 if (!enumstr || !lstrcmpiW(enumstr, deviceInst))
2325 HKEY deviceKey;
2327 l = RegOpenKeyExW(enumKey, deviceInst, 0, KEY_READ,
2328 &deviceKey);
2329 if (!l)
2331 WCHAR deviceClassStr[40];
2333 len = sizeof(deviceClassStr);
2334 l = RegQueryValueExW(deviceKey, ClassGUID, NULL,
2335 &dataType, (BYTE *)deviceClassStr, &len);
2336 if (!l && dataType == REG_SZ &&
2337 deviceClassStr[0] == '{' &&
2338 deviceClassStr[37] == '}')
2340 GUID deviceClass;
2341 struct device *device;
2343 deviceClassStr[37] = 0;
2344 UuidFromStringW(&deviceClassStr[1],
2345 &deviceClass);
2346 if ((device = create_device(set, &deviceClass, deviceInst, FALSE)))
2347 SETUPDI_AddDeviceInterfaces(device, subKey, guid, flags);
2349 RegCloseKey(deviceKey);
2353 RegCloseKey(subKey);
2355 /* Allow enumeration to continue */
2356 l = ERROR_SUCCESS;
2359 if (enumKey != INVALID_HANDLE_VALUE)
2360 RegCloseKey(enumKey);
2363 static void SETUPDI_EnumerateInterfaces(HDEVINFO DeviceInfoSet,
2364 const GUID *guid, LPCWSTR enumstr, DWORD flags)
2366 HKEY interfacesKey = SetupDiOpenClassRegKeyExW(guid, KEY_READ,
2367 DIOCR_INTERFACE, NULL, NULL);
2369 TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(guid),
2370 debugstr_w(enumstr), flags);
2372 if (interfacesKey != INVALID_HANDLE_VALUE)
2374 if (flags & DIGCF_ALLCLASSES)
2376 DWORD i, len;
2377 WCHAR interfaceGuidStr[40];
2378 LONG l = ERROR_SUCCESS;
2380 for (i = 0; !l; i++)
2382 len = ARRAY_SIZE(interfaceGuidStr);
2383 l = RegEnumKeyExW(interfacesKey, i, interfaceGuidStr, &len,
2384 NULL, NULL, NULL, NULL);
2385 if (!l)
2387 if (interfaceGuidStr[0] == '{' &&
2388 interfaceGuidStr[37] == '}')
2390 HKEY interfaceKey;
2391 GUID interfaceGuid;
2393 interfaceGuidStr[37] = 0;
2394 UuidFromStringW(&interfaceGuidStr[1], &interfaceGuid);
2395 interfaceGuidStr[37] = '}';
2396 interfaceGuidStr[38] = 0;
2397 l = RegOpenKeyExW(interfacesKey, interfaceGuidStr, 0,
2398 KEY_READ, &interfaceKey);
2399 if (!l)
2401 SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
2402 interfaceKey, &interfaceGuid, enumstr, flags);
2403 RegCloseKey(interfaceKey);
2409 else
2411 /* In this case, SetupDiOpenClassRegKeyExW opened the specific
2412 * interface's key, so just pass that long
2414 SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
2415 interfacesKey, guid, enumstr, flags);
2417 RegCloseKey(interfacesKey);
2421 static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set,
2422 LPCWSTR enumerator, LPCWSTR deviceName, HKEY deviceKey,
2423 const GUID *class, DWORD flags)
2425 WCHAR id[MAX_DEVICE_ID_LEN];
2426 DWORD i, len;
2427 WCHAR deviceInstance[MAX_PATH];
2428 LONG l = ERROR_SUCCESS;
2430 TRACE("%s %s\n", debugstr_w(enumerator), debugstr_w(deviceName));
2432 for (i = 0; !l; i++)
2434 len = ARRAY_SIZE(deviceInstance);
2435 l = RegEnumKeyExW(deviceKey, i, deviceInstance, &len, NULL, NULL, NULL,
2436 NULL);
2437 if (!l)
2439 HKEY subKey;
2441 l = RegOpenKeyExW(deviceKey, deviceInstance, 0, KEY_READ, &subKey);
2442 if (!l)
2444 WCHAR classGuid[40];
2445 DWORD dataType;
2447 len = sizeof(classGuid);
2448 l = RegQueryValueExW(subKey, ClassGUID, NULL, &dataType,
2449 (BYTE *)classGuid, &len);
2450 if (!l && dataType == REG_SZ)
2452 if (classGuid[0] == '{' && classGuid[37] == '}')
2454 GUID deviceClass;
2456 classGuid[37] = 0;
2457 UuidFromStringW(&classGuid[1], &deviceClass);
2458 if ((flags & DIGCF_ALLCLASSES) ||
2459 IsEqualGUID(class, &deviceClass))
2461 static const WCHAR fmt[] =
2462 {'%','s','\\','%','s','\\','%','s',0};
2464 if (swprintf(id, ARRAY_SIZE(id), fmt, enumerator,
2465 deviceName, deviceInstance) != -1)
2467 create_device(set, &deviceClass, id, FALSE);
2472 RegCloseKey(subKey);
2474 /* Allow enumeration to continue */
2475 l = ERROR_SUCCESS;
2480 static void SETUPDI_EnumerateMatchingDevices(HDEVINFO DeviceInfoSet,
2481 LPCWSTR parent, HKEY key, const GUID *class, DWORD flags)
2483 struct DeviceInfoSet *set = DeviceInfoSet;
2484 DWORD i, len;
2485 WCHAR subKeyName[MAX_PATH];
2486 LONG l = ERROR_SUCCESS;
2488 TRACE("%s\n", debugstr_w(parent));
2490 for (i = 0; !l; i++)
2492 len = ARRAY_SIZE(subKeyName);
2493 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2494 if (!l)
2496 HKEY subKey;
2498 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2499 if (!l)
2501 TRACE("%s\n", debugstr_w(subKeyName));
2502 SETUPDI_EnumerateMatchingDeviceInstances(set, parent,
2503 subKeyName, subKey, class, flags);
2504 RegCloseKey(subKey);
2506 /* Allow enumeration to continue */
2507 l = ERROR_SUCCESS;
2512 static void SETUPDI_EnumerateDevices(HDEVINFO DeviceInfoSet, const GUID *class,
2513 LPCWSTR enumstr, DWORD flags)
2515 HKEY enumKey;
2516 LONG l;
2518 TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(class),
2519 debugstr_w(enumstr), flags);
2521 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL,
2522 &enumKey, NULL);
2523 if (enumKey != INVALID_HANDLE_VALUE)
2525 if (enumstr)
2527 HKEY enumStrKey;
2529 l = RegOpenKeyExW(enumKey, enumstr, 0, KEY_READ,
2530 &enumStrKey);
2531 if (!l)
2533 WCHAR *bus, *device;
2535 if (!wcschr(enumstr, '\\'))
2537 SETUPDI_EnumerateMatchingDevices(DeviceInfoSet, enumstr, enumStrKey, class, flags);
2539 else if ((bus = strdupW(enumstr)))
2541 device = wcschr(bus, '\\');
2542 *device++ = 0;
2544 SETUPDI_EnumerateMatchingDeviceInstances(DeviceInfoSet, bus, device, enumStrKey, class, flags);
2545 HeapFree(GetProcessHeap(), 0, bus);
2548 RegCloseKey(enumStrKey);
2551 else
2553 DWORD i, len;
2554 WCHAR subKeyName[MAX_PATH];
2556 l = ERROR_SUCCESS;
2557 for (i = 0; !l; i++)
2559 len = ARRAY_SIZE(subKeyName);
2560 l = RegEnumKeyExW(enumKey, i, subKeyName, &len, NULL,
2561 NULL, NULL, NULL);
2562 if (!l)
2564 HKEY subKey;
2566 l = RegOpenKeyExW(enumKey, subKeyName, 0, KEY_READ,
2567 &subKey);
2568 if (!l)
2570 SETUPDI_EnumerateMatchingDevices(DeviceInfoSet,
2571 subKeyName, subKey, class, flags);
2572 RegCloseKey(subKey);
2574 /* Allow enumeration to continue */
2575 l = ERROR_SUCCESS;
2579 RegCloseKey(enumKey);
2583 /***********************************************************************
2584 * SetupDiGetClassDevsW (SETUPAPI.@)
2586 HDEVINFO WINAPI SetupDiGetClassDevsW(const GUID *class, LPCWSTR enumstr, HWND parent, DWORD flags)
2588 return SetupDiGetClassDevsExW(class, enumstr, parent, flags, NULL, NULL,
2589 NULL);
2592 /***********************************************************************
2593 * SetupDiGetClassDevsExW (SETUPAPI.@)
2595 HDEVINFO WINAPI SetupDiGetClassDevsExW(const GUID *class, PCWSTR enumstr, HWND parent, DWORD flags,
2596 HDEVINFO deviceset, PCWSTR machine, void *reserved)
2598 static const DWORD unsupportedFlags = DIGCF_DEFAULT | DIGCF_PROFILE;
2599 HDEVINFO set;
2601 TRACE("%s %s %p 0x%08x %p %s %p\n", debugstr_guid(class),
2602 debugstr_w(enumstr), parent, flags, deviceset, debugstr_w(machine),
2603 reserved);
2605 if (!(flags & DIGCF_ALLCLASSES) && !class)
2607 SetLastError(ERROR_INVALID_PARAMETER);
2608 return INVALID_HANDLE_VALUE;
2610 if (flags & DIGCF_ALLCLASSES)
2611 class = NULL;
2613 if (flags & unsupportedFlags)
2614 WARN("unsupported flags %08x\n", flags & unsupportedFlags);
2615 if (deviceset)
2616 set = deviceset;
2617 else
2618 set = SetupDiCreateDeviceInfoListExW((flags & DIGCF_DEVICEINTERFACE) ? NULL : class, parent, machine, reserved);
2619 if (set != INVALID_HANDLE_VALUE)
2621 if (machine && *machine)
2622 FIXME("%s: unimplemented for remote machines\n",
2623 debugstr_w(machine));
2624 else if (flags & DIGCF_DEVICEINTERFACE)
2625 SETUPDI_EnumerateInterfaces(set, class, enumstr, flags);
2626 else
2627 SETUPDI_EnumerateDevices(set, class, enumstr, flags);
2629 return set;
2632 /***********************************************************************
2633 * SetupDiGetDeviceInfoListDetailA (SETUPAPI.@)
2635 BOOL WINAPI SetupDiGetDeviceInfoListDetailA(HDEVINFO devinfo, SP_DEVINFO_LIST_DETAIL_DATA_A *DevInfoData)
2637 struct DeviceInfoSet *set;
2639 TRACE("devinfo %p, detail_data %p.\n", devinfo, DevInfoData);
2641 if (!(set = get_device_set(devinfo)))
2642 return FALSE;
2644 if (!DevInfoData ||
2645 DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_A))
2647 SetLastError(ERROR_INVALID_PARAMETER);
2648 return FALSE;
2650 DevInfoData->ClassGuid = set->ClassGuid;
2651 DevInfoData->RemoteMachineHandle = NULL;
2652 DevInfoData->RemoteMachineName[0] = '\0';
2653 return TRUE;
2656 /***********************************************************************
2657 * SetupDiGetDeviceInfoListDetailW (SETUPAPI.@)
2659 BOOL WINAPI SetupDiGetDeviceInfoListDetailW(HDEVINFO devinfo, SP_DEVINFO_LIST_DETAIL_DATA_W *DevInfoData)
2661 struct DeviceInfoSet *set;
2663 TRACE("devinfo %p, detail_data %p.\n", devinfo, DevInfoData);
2665 if (!(set = get_device_set(devinfo)))
2666 return FALSE;
2668 if (!DevInfoData ||
2669 DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W))
2671 SetLastError(ERROR_INVALID_PARAMETER);
2672 return FALSE;
2674 DevInfoData->ClassGuid = set->ClassGuid;
2675 DevInfoData->RemoteMachineHandle = NULL;
2676 DevInfoData->RemoteMachineName[0] = '\0';
2677 return TRUE;
2680 /***********************************************************************
2681 * SetupDiCreateDeviceInterfaceA (SETUPAPI.@)
2683 BOOL WINAPI SetupDiCreateDeviceInterfaceA(
2684 HDEVINFO DeviceInfoSet,
2685 PSP_DEVINFO_DATA DeviceInfoData,
2686 const GUID *InterfaceClassGuid,
2687 PCSTR ReferenceString,
2688 DWORD CreationFlags,
2689 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2691 BOOL ret;
2692 LPWSTR ReferenceStringW = NULL;
2694 TRACE("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
2695 debugstr_guid(InterfaceClassGuid), debugstr_a(ReferenceString),
2696 CreationFlags, DeviceInterfaceData);
2698 if (ReferenceString)
2700 ReferenceStringW = MultiByteToUnicode(ReferenceString, CP_ACP);
2701 if (ReferenceStringW == NULL) return FALSE;
2704 ret = SetupDiCreateDeviceInterfaceW(DeviceInfoSet, DeviceInfoData,
2705 InterfaceClassGuid, ReferenceStringW, CreationFlags,
2706 DeviceInterfaceData);
2708 MyFree(ReferenceStringW);
2710 return ret;
2713 /***********************************************************************
2714 * SetupDiCreateDeviceInterfaceW (SETUPAPI.@)
2716 BOOL WINAPI SetupDiCreateDeviceInterfaceW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
2717 const GUID *class, const WCHAR *refstr, DWORD flags, SP_DEVICE_INTERFACE_DATA *iface_data)
2719 struct device *device;
2720 struct device_iface *iface;
2722 TRACE("devinfo %p, device_data %p, class %s, refstr %s, flags %#x, iface_data %p.\n",
2723 devinfo, device_data, debugstr_guid(class), debugstr_w(refstr), flags, iface_data);
2725 if (!(device = get_device(devinfo, device_data)))
2726 return FALSE;
2728 if (!class)
2730 SetLastError(ERROR_INVALID_USER_BUFFER);
2731 return FALSE;
2734 if (!(iface = SETUPDI_CreateDeviceInterface(device, class, refstr)))
2735 return FALSE;
2737 if (iface_data)
2739 if (iface_data->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2741 SetLastError(ERROR_INVALID_USER_BUFFER);
2742 return FALSE;
2745 copy_device_iface_data(iface_data, iface);
2747 return TRUE;
2750 /***********************************************************************
2751 * SetupDiCreateDeviceInterfaceRegKeyA (SETUPAPI.@)
2753 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyA(
2754 HDEVINFO DeviceInfoSet,
2755 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2756 DWORD Reserved,
2757 REGSAM samDesired,
2758 HINF InfHandle,
2759 PCSTR InfSectionName)
2761 HKEY key;
2762 PWSTR InfSectionNameW = NULL;
2764 TRACE("%p %p %d %08x %p %p\n", DeviceInfoSet, DeviceInterfaceData, Reserved,
2765 samDesired, InfHandle, InfSectionName);
2766 if (InfHandle)
2768 if (!InfSectionName)
2770 SetLastError(ERROR_INVALID_PARAMETER);
2771 return INVALID_HANDLE_VALUE;
2773 InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
2774 if (!InfSectionNameW)
2775 return INVALID_HANDLE_VALUE;
2777 key = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet,
2778 DeviceInterfaceData, Reserved, samDesired, InfHandle,
2779 InfSectionNameW);
2780 MyFree(InfSectionNameW);
2781 return key;
2784 static LONG create_iface_key(const struct device_iface *iface, REGSAM access, HKEY *key)
2786 return RegCreateKeyExW(iface->refstr_key, DeviceParameters, 0, NULL, 0, access, NULL, key, NULL);
2789 /***********************************************************************
2790 * SetupDiCreateDeviceInterfaceRegKeyW (SETUPAPI.@)
2792 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyW(HDEVINFO devinfo,
2793 SP_DEVICE_INTERFACE_DATA *iface_data, DWORD reserved, REGSAM access,
2794 HINF hinf, const WCHAR *section)
2796 struct device_iface *iface;
2797 HKEY params_key;
2798 LONG ret;
2800 TRACE("devinfo %p, iface_data %p, reserved %d, access %#x, hinf %p, section %s.\n",
2801 devinfo, iface_data, reserved, access, hinf, debugstr_w(section));
2803 if (!(iface = get_device_iface(devinfo, iface_data)))
2804 return INVALID_HANDLE_VALUE;
2806 if (hinf && !section)
2808 SetLastError(ERROR_INVALID_PARAMETER);
2809 return INVALID_HANDLE_VALUE;
2812 ret = create_iface_key(iface, access, &params_key);
2813 if (ret)
2815 SetLastError(ret);
2816 return INVALID_HANDLE_VALUE;
2819 return params_key;
2822 /***********************************************************************
2823 * SetupDiDeleteDeviceInterfaceRegKey (SETUPAPI.@)
2825 BOOL WINAPI SetupDiDeleteDeviceInterfaceRegKey(HDEVINFO devinfo,
2826 SP_DEVICE_INTERFACE_DATA *iface_data, DWORD reserved)
2828 struct device_iface *iface;
2829 LONG ret;
2831 TRACE("devinfo %p, iface_data %p, reserved %d.\n", devinfo, iface_data, reserved);
2833 if (!(iface = get_device_iface(devinfo, iface_data)))
2834 return FALSE;
2836 ret = RegDeleteKeyW(iface->refstr_key, DeviceParameters);
2837 if (ret)
2839 SetLastError(ret);
2840 return FALSE;
2843 return TRUE;
2846 /***********************************************************************
2847 * SetupDiEnumDeviceInterfaces (SETUPAPI.@)
2849 * PARAMS
2850 * DeviceInfoSet [I] Set of devices from which to enumerate
2851 * interfaces
2852 * DeviceInfoData [I] (Optional) If specified, a specific device
2853 * instance from which to enumerate interfaces.
2854 * If it isn't specified, all interfaces for all
2855 * devices in the set are enumerated.
2856 * InterfaceClassGuid [I] The interface class to enumerate.
2857 * MemberIndex [I] An index of the interface instance to enumerate.
2858 * A caller should start with MemberIndex set to 0,
2859 * and continue until the function fails with
2860 * ERROR_NO_MORE_ITEMS.
2861 * DeviceInterfaceData [I/O] Returns an enumerated interface. Its cbSize
2862 * member must be set to
2863 * sizeof(SP_DEVICE_INTERFACE_DATA).
2865 * RETURNS
2866 * Success: non-zero value.
2867 * Failure: FALSE. Call GetLastError() for more info.
2869 BOOL WINAPI SetupDiEnumDeviceInterfaces(HDEVINFO devinfo,
2870 SP_DEVINFO_DATA *device_data, const GUID *class, DWORD index,
2871 SP_DEVICE_INTERFACE_DATA *iface_data)
2873 struct DeviceInfoSet *set;
2874 struct device *device;
2875 struct device_iface *iface;
2876 DWORD i = 0;
2878 TRACE("devinfo %p, device_data %p, class %s, index %u, iface_data %p.\n",
2879 devinfo, device_data, debugstr_guid(class), index, iface_data);
2881 if (!iface_data || iface_data->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2883 SetLastError(ERROR_INVALID_PARAMETER);
2884 return FALSE;
2887 /* In case application fails to check return value, clear output */
2888 memset(iface_data, 0, sizeof(*iface_data));
2889 iface_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
2891 if (device_data)
2893 if (!(device = get_device(devinfo, device_data)))
2894 return FALSE;
2896 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
2898 if (IsEqualGUID(&iface->class, class))
2900 if (i == index)
2902 copy_device_iface_data(iface_data, iface);
2903 return TRUE;
2905 i++;
2909 else
2911 if (!(set = get_device_set(devinfo)))
2912 return FALSE;
2914 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
2916 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
2918 if (IsEqualGUID(&iface->class, class))
2920 if (i == index)
2922 copy_device_iface_data(iface_data, iface);
2923 return TRUE;
2925 i++;
2931 SetLastError(ERROR_NO_MORE_ITEMS);
2932 return FALSE;
2935 /***********************************************************************
2936 * SetupDiDestroyDeviceInfoList (SETUPAPI.@)
2938 * Destroy a DeviceInfoList and free all used memory of the list.
2940 * PARAMS
2941 * devinfo [I] DeviceInfoList pointer to list to destroy
2943 * RETURNS
2944 * Success: non zero value.
2945 * Failure: zero value.
2947 BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
2949 struct DeviceInfoSet *set;
2950 struct device *device, *device2;
2952 TRACE("devinfo %p.\n", devinfo);
2954 if (!(set = get_device_set(devinfo)))
2955 return FALSE;
2957 LIST_FOR_EACH_ENTRY_SAFE(device, device2, &set->devices, struct device, entry)
2959 delete_device(device);
2961 heap_free(set);
2963 SetLastError(ERROR_SUCCESS);
2964 return TRUE;
2967 /***********************************************************************
2968 * SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
2970 BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data,
2971 SP_DEVICE_INTERFACE_DETAIL_DATA_A *DeviceInterfaceDetailData,
2972 DWORD DeviceInterfaceDetailDataSize, DWORD *RequiredSize, SP_DEVINFO_DATA *device_data)
2974 struct device_iface *iface;
2975 DWORD bytesNeeded = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath[1]);
2976 BOOL ret = FALSE;
2978 TRACE("devinfo %p, iface_data %p, detail_data %p, size %d, needed %p, device_data %p.\n",
2979 devinfo, iface_data, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize,
2980 RequiredSize, device_data);
2982 if (!(iface = get_device_iface(devinfo, iface_data)))
2983 return FALSE;
2985 if (DeviceInterfaceDetailData &&
2986 DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A))
2988 SetLastError(ERROR_INVALID_USER_BUFFER);
2989 return FALSE;
2991 if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
2993 SetLastError(ERROR_INVALID_USER_BUFFER);
2994 return FALSE;
2997 if (iface->symlink)
2998 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, iface->symlink, -1,
2999 NULL, 0, NULL, NULL);
3000 if (DeviceInterfaceDetailDataSize >= bytesNeeded)
3002 if (iface->symlink)
3003 WideCharToMultiByte(CP_ACP, 0, iface->symlink, -1,
3004 DeviceInterfaceDetailData->DevicePath,
3005 DeviceInterfaceDetailDataSize -
3006 offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
3007 NULL, NULL);
3008 else
3009 DeviceInterfaceDetailData->DevicePath[0] = '\0';
3011 ret = TRUE;
3013 else
3015 if (RequiredSize)
3016 *RequiredSize = bytesNeeded;
3017 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3020 if (device_data && device_data->cbSize == sizeof(SP_DEVINFO_DATA))
3021 copy_device_data(device_data, iface->device);
3023 return ret;
3026 /***********************************************************************
3027 * SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
3029 BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data,
3030 SP_DEVICE_INTERFACE_DETAIL_DATA_W *DeviceInterfaceDetailData,
3031 DWORD DeviceInterfaceDetailDataSize, DWORD *RequiredSize, SP_DEVINFO_DATA *device_data)
3033 struct device_iface *iface;
3034 DWORD bytesNeeded = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
3035 + sizeof(WCHAR); /* include NULL terminator */
3036 BOOL ret = FALSE;
3038 TRACE("devinfo %p, iface_data %p, detail_data %p, size %d, needed %p, device_data %p.\n",
3039 devinfo, iface_data, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize,
3040 RequiredSize, device_data);
3042 if (!(iface = get_device_iface(devinfo, iface_data)))
3043 return FALSE;
3045 if (DeviceInterfaceDetailData && (DeviceInterfaceDetailData->cbSize <
3046 offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR) ||
3047 DeviceInterfaceDetailData->cbSize > sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W)))
3049 SetLastError(ERROR_INVALID_USER_BUFFER);
3050 return FALSE;
3052 if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
3054 SetLastError(ERROR_INVALID_USER_BUFFER);
3055 return FALSE;
3058 if (iface->symlink)
3059 bytesNeeded += sizeof(WCHAR) * lstrlenW(iface->symlink);
3060 if (DeviceInterfaceDetailDataSize >= bytesNeeded)
3062 if (iface->symlink)
3063 lstrcpyW(DeviceInterfaceDetailData->DevicePath, iface->symlink);
3064 else
3065 DeviceInterfaceDetailData->DevicePath[0] = '\0';
3067 ret = TRUE;
3069 else
3071 if (RequiredSize)
3072 *RequiredSize = bytesNeeded;
3073 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3076 if (device_data && device_data->cbSize == sizeof(SP_DEVINFO_DATA))
3077 copy_device_data(device_data, iface->device);
3079 return ret;
3082 /***********************************************************************
3083 * SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
3085 BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(HDEVINFO devinfo,
3086 SP_DEVINFO_DATA *device_data, DWORD Property, DWORD *PropertyRegDataType,
3087 BYTE *PropertyBuffer, DWORD PropertyBufferSize, DWORD *RequiredSize)
3089 BOOL ret = FALSE;
3090 struct device *device;
3092 TRACE("devinfo %p, device_data %p, property %d, type %p, buffer %p, size %d, required %p\n",
3093 devinfo, device_data, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize);
3095 if (!(device = get_device(devinfo, device_data)))
3096 return FALSE;
3098 if (PropertyBufferSize && PropertyBuffer == NULL)
3100 SetLastError(ERROR_INVALID_DATA);
3101 return FALSE;
3104 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameA)
3106 DWORD size = PropertyBufferSize;
3107 LONG l = RegQueryValueExA(device->key, PropertyMap[Property].nameA,
3108 NULL, PropertyRegDataType, PropertyBuffer, &size);
3110 if (l == ERROR_FILE_NOT_FOUND)
3111 SetLastError(ERROR_INVALID_DATA);
3112 else if (l == ERROR_MORE_DATA || !PropertyBufferSize)
3113 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3114 else if (!l)
3115 ret = TRUE;
3116 else
3117 SetLastError(l);
3118 if (RequiredSize)
3119 *RequiredSize = size;
3121 return ret;
3124 /***********************************************************************
3125 * SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
3127 BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(HDEVINFO devinfo,
3128 SP_DEVINFO_DATA *device_data, DWORD Property, DWORD *PropertyRegDataType,
3129 BYTE *PropertyBuffer, DWORD PropertyBufferSize, DWORD *RequiredSize)
3131 BOOL ret = FALSE;
3132 struct device *device;
3134 TRACE("devinfo %p, device_data %p, prop %d, type %p, buffer %p, size %d, required %p\n",
3135 devinfo, device_data, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize);
3137 if (!(device = get_device(devinfo, device_data)))
3138 return FALSE;
3140 if (PropertyBufferSize && PropertyBuffer == NULL)
3142 SetLastError(ERROR_INVALID_DATA);
3143 return FALSE;
3146 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameW)
3148 DWORD size = PropertyBufferSize;
3149 LONG l = RegQueryValueExW(device->key, PropertyMap[Property].nameW,
3150 NULL, PropertyRegDataType, PropertyBuffer, &size);
3152 if (l == ERROR_FILE_NOT_FOUND)
3153 SetLastError(ERROR_INVALID_DATA);
3154 else if (l == ERROR_MORE_DATA || !PropertyBufferSize)
3155 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3156 else if (!l)
3157 ret = TRUE;
3158 else
3159 SetLastError(l);
3160 if (RequiredSize)
3161 *RequiredSize = size;
3163 return ret;
3166 /***********************************************************************
3167 * SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
3169 BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
3170 DWORD Property, const BYTE *PropertyBuffer, DWORD PropertyBufferSize)
3172 BOOL ret = FALSE;
3173 struct device *device;
3175 TRACE("devinfo %p, device_data %p, prop %d, buffer %p, size %d.\n",
3176 devinfo, device_data, Property, PropertyBuffer, PropertyBufferSize);
3178 if (!(device = get_device(devinfo, device_data)))
3179 return FALSE;
3181 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameA)
3183 LONG l = RegSetValueExA(device->key, PropertyMap[Property].nameA, 0,
3184 PropertyMap[Property].regType, PropertyBuffer,
3185 PropertyBufferSize);
3186 if (!l)
3187 ret = TRUE;
3188 else
3189 SetLastError(l);
3191 return ret;
3194 /***********************************************************************
3195 * SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
3197 BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(HDEVINFO devinfo,
3198 SP_DEVINFO_DATA *device_data, DWORD prop, const BYTE *buffer, DWORD size)
3200 struct device *device;
3202 TRACE("devinfo %p, device_data %p, prop %d, buffer %p, size %d.\n",
3203 devinfo, device_data, prop, buffer, size);
3205 if (!(device = get_device(devinfo, device_data)))
3206 return FALSE;
3208 return SETUPDI_SetDeviceRegistryPropertyW(device, prop, buffer, size);
3211 /***********************************************************************
3212 * SetupDiInstallClassA (SETUPAPI.@)
3214 BOOL WINAPI SetupDiInstallClassA(
3215 HWND hwndParent,
3216 PCSTR InfFileName,
3217 DWORD Flags,
3218 HSPFILEQ FileQueue)
3220 UNICODE_STRING FileNameW;
3221 BOOL Result;
3223 if (!InfFileName)
3225 SetLastError(ERROR_INVALID_PARAMETER);
3226 return FALSE;
3228 if (!RtlCreateUnicodeStringFromAsciiz(&FileNameW, InfFileName))
3230 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3231 return FALSE;
3234 Result = SetupDiInstallClassW(hwndParent, FileNameW.Buffer, Flags, FileQueue);
3236 RtlFreeUnicodeString(&FileNameW);
3238 return Result;
3241 static HKEY CreateClassKey(HINF hInf)
3243 static const WCHAR slash[] = { '\\',0 };
3244 WCHAR FullBuffer[MAX_PATH];
3245 WCHAR Buffer[MAX_PATH];
3246 DWORD RequiredSize;
3247 HKEY hClassKey;
3249 if (!SetupGetLineTextW(NULL,
3250 hInf,
3251 Version,
3252 ClassGUID,
3253 Buffer,
3254 MAX_PATH,
3255 &RequiredSize))
3257 return INVALID_HANDLE_VALUE;
3260 lstrcpyW(FullBuffer, ControlClass);
3261 lstrcatW(FullBuffer, slash);
3262 lstrcatW(FullBuffer, Buffer);
3264 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3265 FullBuffer,
3267 KEY_ALL_ACCESS,
3268 &hClassKey))
3270 if (!SetupGetLineTextW(NULL,
3271 hInf,
3272 Version,
3273 Class,
3274 Buffer,
3275 MAX_PATH,
3276 &RequiredSize))
3278 return INVALID_HANDLE_VALUE;
3281 if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
3282 FullBuffer,
3284 NULL,
3285 REG_OPTION_NON_VOLATILE,
3286 KEY_ALL_ACCESS,
3287 NULL,
3288 &hClassKey,
3289 NULL))
3291 return INVALID_HANDLE_VALUE;
3296 if (RegSetValueExW(hClassKey,
3297 Class,
3299 REG_SZ,
3300 (LPBYTE)Buffer,
3301 RequiredSize * sizeof(WCHAR)))
3303 RegCloseKey(hClassKey);
3304 RegDeleteKeyW(HKEY_LOCAL_MACHINE,
3305 FullBuffer);
3306 return INVALID_HANDLE_VALUE;
3309 return hClassKey;
3312 /***********************************************************************
3313 * SetupDiInstallClassW (SETUPAPI.@)
3315 BOOL WINAPI SetupDiInstallClassW(
3316 HWND hwndParent,
3317 PCWSTR InfFileName,
3318 DWORD Flags,
3319 HSPFILEQ FileQueue)
3321 WCHAR SectionName[MAX_PATH];
3322 DWORD SectionNameLength = 0;
3323 HINF hInf;
3324 BOOL bFileQueueCreated = FALSE;
3325 HKEY hClassKey;
3328 FIXME("\n");
3330 if (!InfFileName)
3332 SetLastError(ERROR_INVALID_PARAMETER);
3333 return FALSE;
3335 if ((Flags & DI_NOVCP) && (FileQueue == NULL || FileQueue == INVALID_HANDLE_VALUE))
3337 SetLastError(ERROR_INVALID_PARAMETER);
3338 return FALSE;
3341 /* Open the .inf file */
3342 hInf = SetupOpenInfFileW(InfFileName,
3343 NULL,
3344 INF_STYLE_WIN4,
3345 NULL);
3346 if (hInf == INVALID_HANDLE_VALUE)
3349 return FALSE;
3352 /* Create or open the class registry key 'HKLM\\CurrentControlSet\\Class\\{GUID}' */
3353 hClassKey = CreateClassKey(hInf);
3354 if (hClassKey == INVALID_HANDLE_VALUE)
3356 SetupCloseInfFile(hInf);
3357 return FALSE;
3361 /* Try to append a layout file */
3362 SetupOpenAppendInfFileW(NULL, hInf, NULL);
3364 /* Retrieve the actual section name */
3365 SetupDiGetActualSectionToInstallW(hInf,
3366 ClassInstall32,
3367 SectionName,
3368 MAX_PATH,
3369 &SectionNameLength,
3370 NULL);
3372 #if 0
3373 if (!(Flags & DI_NOVCP))
3375 FileQueue = SetupOpenFileQueue();
3376 if (FileQueue == INVALID_HANDLE_VALUE)
3378 SetupCloseInfFile(hInf);
3379 return FALSE;
3382 bFileQueueCreated = TRUE;
3385 #endif
3387 SetupInstallFromInfSectionW(NULL,
3388 hInf,
3389 SectionName,
3390 SPINST_COPYINF | SPINST_FILES | SPINST_REGISTRY,
3391 hClassKey,
3392 NULL,
3394 NULL,
3395 NULL,
3396 INVALID_HANDLE_VALUE,
3397 NULL);
3399 /* FIXME: More code! */
3401 if (bFileQueueCreated)
3402 SetupCloseFileQueue(FileQueue);
3404 SetupCloseInfFile(hInf);
3406 return TRUE;
3410 /***********************************************************************
3411 * SetupDiOpenClassRegKey (SETUPAPI.@)
3413 HKEY WINAPI SetupDiOpenClassRegKey(
3414 const GUID* ClassGuid,
3415 REGSAM samDesired)
3417 return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3418 DIOCR_INSTALLER, NULL, NULL);
3422 /***********************************************************************
3423 * SetupDiOpenClassRegKeyExA (SETUPAPI.@)
3425 HKEY WINAPI SetupDiOpenClassRegKeyExA(
3426 const GUID* ClassGuid,
3427 REGSAM samDesired,
3428 DWORD Flags,
3429 PCSTR MachineName,
3430 PVOID Reserved)
3432 PWSTR MachineNameW = NULL;
3433 HKEY hKey;
3435 TRACE("\n");
3437 if (MachineName)
3439 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
3440 if (MachineNameW == NULL)
3441 return INVALID_HANDLE_VALUE;
3444 hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3445 Flags, MachineNameW, Reserved);
3447 MyFree(MachineNameW);
3449 return hKey;
3453 /***********************************************************************
3454 * SetupDiOpenClassRegKeyExW (SETUPAPI.@)
3456 HKEY WINAPI SetupDiOpenClassRegKeyExW(
3457 const GUID* ClassGuid,
3458 REGSAM samDesired,
3459 DWORD Flags,
3460 PCWSTR MachineName,
3461 PVOID Reserved)
3463 HKEY hClassesKey;
3464 HKEY key;
3465 LPCWSTR lpKeyName;
3466 LONG l;
3468 if (MachineName && *MachineName)
3470 FIXME("Remote access not supported yet!\n");
3471 return INVALID_HANDLE_VALUE;
3474 if (Flags == DIOCR_INSTALLER)
3476 lpKeyName = ControlClass;
3478 else if (Flags == DIOCR_INTERFACE)
3480 lpKeyName = DeviceClasses;
3482 else
3484 ERR("Invalid Flags parameter!\n");
3485 SetLastError(ERROR_INVALID_PARAMETER);
3486 return INVALID_HANDLE_VALUE;
3489 if (!ClassGuid)
3491 if ((l = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3492 lpKeyName,
3494 samDesired,
3495 &hClassesKey)))
3497 SetLastError(l);
3498 hClassesKey = INVALID_HANDLE_VALUE;
3500 key = hClassesKey;
3502 else
3504 WCHAR bracedGuidString[39];
3506 SETUPDI_GuidToString(ClassGuid, bracedGuidString);
3508 if (!(l = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3509 lpKeyName,
3511 samDesired,
3512 &hClassesKey)))
3514 if ((l = RegOpenKeyExW(hClassesKey,
3515 bracedGuidString,
3517 samDesired,
3518 &key)))
3520 SetLastError(l);
3521 key = INVALID_HANDLE_VALUE;
3523 RegCloseKey(hClassesKey);
3525 else
3527 SetLastError(l);
3528 key = INVALID_HANDLE_VALUE;
3531 return key;
3534 /***********************************************************************
3535 * SetupDiOpenDeviceInfoA (SETUPAPI.@)
3537 BOOL WINAPI SetupDiOpenDeviceInfoA(HDEVINFO devinfo, PCSTR instance_id, HWND hwnd_parent, DWORD flags,
3538 PSP_DEVINFO_DATA device_data)
3540 WCHAR instance_idW[MAX_DEVICE_ID_LEN];
3542 TRACE("%p %s %p 0x%08x %p\n", devinfo, debugstr_a(instance_id), hwnd_parent, flags, device_data);
3544 if (!instance_id || strlen(instance_id) >= MAX_DEVICE_ID_LEN)
3546 SetLastError(ERROR_INVALID_PARAMETER);
3547 return FALSE;
3550 MultiByteToWideChar(CP_ACP, 0, instance_id, -1, instance_idW, ARRAY_SIZE(instance_idW));
3551 return SetupDiOpenDeviceInfoW(devinfo, instance_idW, hwnd_parent, flags, device_data);
3554 /***********************************************************************
3555 * SetupDiOpenDeviceInfoW (SETUPAPI.@)
3557 BOOL WINAPI SetupDiOpenDeviceInfoW(HDEVINFO devinfo, PCWSTR instance_id, HWND hwnd_parent, DWORD flags,
3558 PSP_DEVINFO_DATA device_data)
3560 struct DeviceInfoSet *set;
3561 struct device *device;
3562 WCHAR classW[40];
3563 GUID guid;
3564 HKEY enumKey = NULL;
3565 HKEY instanceKey = NULL;
3566 DWORD phantom;
3567 DWORD size;
3568 DWORD error = ERROR_NO_SUCH_DEVINST;
3570 TRACE("%p %s %p 0x%08x %p\n", devinfo, debugstr_w(instance_id), hwnd_parent, flags, device_data);
3572 if (!(set = get_device_set(devinfo)))
3573 return FALSE;
3575 if (!instance_id)
3577 SetLastError(ERROR_INVALID_PARAMETER);
3578 return FALSE;
3581 if (hwnd_parent)
3582 FIXME("hwnd_parent unsupported\n");
3584 if (flags)
3585 FIXME("flags unsupported: 0x%08x\n", flags);
3587 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &enumKey, NULL);
3588 /* Instance needs to be already existent in registry, if not, report ERROR_NO_SUCH_DEVINST */
3589 if (RegOpenKeyExW(enumKey, instance_id, 0, KEY_READ, &instanceKey))
3590 goto done;
3592 /* If it's an unregistered instance, aka phantom instance, report ERROR_NO_SUCH_DEVINST */
3593 size = sizeof(phantom);
3594 if (!RegQueryValueExW(instanceKey, Phantom, NULL, NULL, (BYTE *)&phantom, &size))
3595 goto done;
3597 /* Check class GUID */
3598 size = sizeof(classW);
3599 if (RegQueryValueExW(instanceKey, ClassGUID, NULL, NULL, (BYTE *)classW, &size))
3600 goto done;
3602 classW[37] = 0;
3603 UuidFromStringW(&classW[1], &guid);
3605 if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) && !IsEqualGUID(&guid, &set->ClassGuid))
3607 error = ERROR_CLASS_MISMATCH;
3608 goto done;
3611 if (!(device = create_device(set, &guid, instance_id, FALSE)))
3612 goto done;
3614 if (!device_data || device_data->cbSize == sizeof(SP_DEVINFO_DATA))
3616 if (device_data)
3617 copy_device_data(device_data, device);
3618 error = NO_ERROR;
3620 else
3621 error = ERROR_INVALID_USER_BUFFER;
3623 done:
3624 RegCloseKey(instanceKey);
3625 RegCloseKey(enumKey);
3626 SetLastError(error);
3627 return !error;
3630 /***********************************************************************
3631 * SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
3633 BOOL WINAPI SetupDiOpenDeviceInterfaceW(
3634 HDEVINFO DeviceInfoSet,
3635 PCWSTR DevicePath,
3636 DWORD OpenFlags,
3637 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3639 FIXME("%p %s %08x %p\n",
3640 DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
3641 return FALSE;
3644 /***********************************************************************
3645 * SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
3647 BOOL WINAPI SetupDiOpenDeviceInterfaceA(
3648 HDEVINFO DeviceInfoSet,
3649 PCSTR DevicePath,
3650 DWORD OpenFlags,
3651 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3653 FIXME("%p %s %08x %p\n", DeviceInfoSet,
3654 debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
3655 return FALSE;
3658 /***********************************************************************
3659 * SetupDiOpenDeviceInterfaceRegKey (SETUPAPI.@)
3661 HKEY WINAPI SetupDiOpenDeviceInterfaceRegKey(HDEVINFO devinfo, PSP_DEVICE_INTERFACE_DATA iface_data,
3662 DWORD reserved, REGSAM access)
3664 struct device_iface *iface;
3665 LSTATUS lr;
3666 HKEY key;
3668 TRACE("devinfo %p, iface_data %p, reserved %d, access %#x.\n", devinfo, iface_data, reserved, access);
3670 if (!(iface = get_device_iface(devinfo, iface_data)))
3671 return INVALID_HANDLE_VALUE;
3673 lr = RegOpenKeyExW(iface->refstr_key, DeviceParameters, 0, access, &key);
3674 if (lr)
3676 SetLastError(lr);
3677 return INVALID_HANDLE_VALUE;
3680 return key;
3683 /***********************************************************************
3684 * SetupDiSetClassInstallParamsA (SETUPAPI.@)
3686 BOOL WINAPI SetupDiSetClassInstallParamsA(
3687 HDEVINFO DeviceInfoSet,
3688 PSP_DEVINFO_DATA DeviceInfoData,
3689 PSP_CLASSINSTALL_HEADER ClassInstallParams,
3690 DWORD ClassInstallParamsSize)
3692 FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
3693 ClassInstallParams->InstallFunction, ClassInstallParamsSize);
3694 return FALSE;
3697 /***********************************************************************
3698 * SetupDiSetClassInstallParamsW (SETUPAPI.@)
3700 BOOL WINAPI SetupDiSetClassInstallParamsW(
3701 HDEVINFO DeviceInfoSet,
3702 PSP_DEVINFO_DATA DeviceInfoData,
3703 PSP_CLASSINSTALL_HEADER ClassInstallParams,
3704 DWORD ClassInstallParamsSize)
3706 FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
3707 ClassInstallParams->InstallFunction, ClassInstallParamsSize);
3708 return FALSE;
3711 static BOOL call_coinstallers(WCHAR *list, DI_FUNCTION function, HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
3713 DWORD (CALLBACK *coinst_proc)(DI_FUNCTION, HDEVINFO, SP_DEVINFO_DATA *, COINSTALLER_CONTEXT_DATA *);
3714 COINSTALLER_CONTEXT_DATA coinst_ctx;
3715 WCHAR *p, *procnameW;
3716 HMODULE module;
3717 char *procname;
3718 DWORD ret;
3720 for (p = list; *p; p += lstrlenW(p) + 1)
3722 TRACE("Found co-installer %s.\n", debugstr_w(p));
3723 if ((procnameW = wcschr(p, ',')))
3724 *procnameW = 0;
3726 if ((module = LoadLibraryExW(p, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32)))
3728 if (procnameW)
3730 procname = strdupWtoA(procnameW + 1);
3731 coinst_proc = (void *)GetProcAddress(module, procname);
3732 heap_free(procname);
3734 else
3735 coinst_proc = (void *)GetProcAddress(module, "CoDeviceInstall");
3736 if (coinst_proc)
3738 memset(&coinst_ctx, 0, sizeof(coinst_ctx));
3739 TRACE("Calling co-installer %p.\n", coinst_proc);
3740 ret = coinst_proc(function, devinfo, device_data, &coinst_ctx);
3741 TRACE("Co-installer %p returned %#x.\n", coinst_proc, ret);
3742 if (ret == ERROR_DI_POSTPROCESSING_REQUIRED)
3743 FIXME("Co-installer postprocessing not implemented.\n");
3744 else if (ret)
3746 ERR("Co-installer returned error %#x.\n", ret);
3747 FreeLibrary(module);
3748 SetLastError(ret);
3749 return FALSE;
3752 FreeLibrary(module);
3756 return TRUE;
3759 /***********************************************************************
3760 * SetupDiCallClassInstaller (SETUPAPI.@)
3762 BOOL WINAPI SetupDiCallClassInstaller(DI_FUNCTION function, HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
3764 static const WCHAR class_coinst_pathW[] = {'S','y','s','t','e','m',
3765 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
3766 '\\','C','o','n','t','r','o','l',
3767 '\\','C','o','D','e','v','i','c','e','I','n','s','t','a','l','l','e','r','s',0};
3768 static const WCHAR coinstallers32W[] = {'C','o','I','n','s','t','a','l','l','e','r','s','3','2',0};
3769 static const WCHAR installer32W[] = {'I','n','s','t','a','l','l','e','r','3','2',0};
3770 DWORD (CALLBACK *classinst_proc)(DI_FUNCTION, HDEVINFO, SP_DEVINFO_DATA *);
3771 DWORD ret = ERROR_DI_DO_DEFAULT;
3772 HKEY class_key, coinst_key;
3773 WCHAR *path, *procnameW;
3774 struct device *device;
3775 WCHAR guidstr[39];
3776 BOOL coret = TRUE;
3777 HMODULE module;
3778 char *procname;
3779 DWORD size;
3781 TRACE("function %#x, devinfo %p, device_data %p.\n", function, devinfo, device_data);
3783 if (!(device = get_device(devinfo, device_data)))
3784 return FALSE;
3786 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, class_coinst_pathW, 0, KEY_READ, &coinst_key))
3788 SETUPDI_GuidToString(&device->class, guidstr);
3789 if (!RegGetValueW(coinst_key, NULL, guidstr, RRF_RT_REG_MULTI_SZ, NULL, NULL, &size))
3791 path = heap_alloc(size);
3792 if (!RegGetValueW(coinst_key, NULL, guidstr, RRF_RT_REG_MULTI_SZ, NULL, path, &size))
3793 coret = call_coinstallers(path, function, devinfo, device_data);
3794 heap_free(path);
3796 RegCloseKey(coinst_key);
3799 if (!coret)
3800 return FALSE;
3802 if (!open_driver_key(device, KEY_READ, &coinst_key))
3804 if (!RegGetValueW(coinst_key, NULL, coinstallers32W, RRF_RT_REG_MULTI_SZ, NULL, NULL, &size))
3806 path = heap_alloc(size);
3807 if (!RegGetValueW(coinst_key, NULL, coinstallers32W, RRF_RT_REG_MULTI_SZ, NULL, path, &size))
3808 coret = call_coinstallers(path, function, devinfo, device_data);
3809 heap_free(path);
3811 RegCloseKey(coinst_key);
3814 if ((class_key = SetupDiOpenClassRegKey(&device->class, KEY_READ)) != INVALID_HANDLE_VALUE)
3816 if (!RegGetValueW(class_key, NULL, installer32W, RRF_RT_REG_SZ, NULL, NULL, &size))
3818 path = heap_alloc(size);
3819 if (!RegGetValueW(class_key, NULL, installer32W, RRF_RT_REG_SZ, NULL, path, &size))
3821 TRACE("Found class installer %s.\n", debugstr_w(path));
3822 if ((procnameW = wcschr(path, ',')))
3823 *procnameW = 0;
3825 if ((module = LoadLibraryExW(path, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32)))
3827 if (procnameW)
3829 procname = strdupWtoA(procnameW + 1);
3830 classinst_proc = (void *)GetProcAddress(module, procname);
3831 heap_free(procname);
3833 else
3834 classinst_proc = (void *)GetProcAddress(module, "ClassInstall");
3835 if (classinst_proc)
3837 TRACE("Calling class installer %p.\n", classinst_proc);
3838 ret = classinst_proc(function, devinfo, device_data);
3839 TRACE("Class installer %p returned %#x.\n", classinst_proc, ret);
3841 FreeLibrary(module);
3844 heap_free(path);
3846 RegCloseKey(class_key);
3849 if (ret == ERROR_DI_DO_DEFAULT)
3851 switch (function)
3853 case DIF_REGISTERDEVICE:
3854 return SetupDiRegisterDeviceInfo(devinfo, device_data, 0, NULL, NULL, NULL);
3855 case DIF_REMOVE:
3856 return SetupDiRemoveDevice(devinfo, device_data);
3857 case DIF_SELECTBESTCOMPATDRV:
3858 return SetupDiSelectBestCompatDrv(devinfo, device_data);
3859 case DIF_REGISTER_COINSTALLERS:
3860 return SetupDiRegisterCoDeviceInstallers(devinfo, device_data);
3861 case DIF_INSTALLDEVICEFILES:
3862 return SetupDiInstallDriverFiles(devinfo, device_data);
3863 case DIF_INSTALLINTERFACES:
3864 return SetupDiInstallDeviceInterfaces(devinfo, device_data);
3865 case DIF_INSTALLDEVICE:
3866 return SetupDiInstallDevice(devinfo, device_data);
3867 case DIF_FINISHINSTALL_ACTION:
3868 case DIF_PROPERTYCHANGE:
3869 case DIF_SELECTDEVICE:
3870 case DIF_UNREMOVE:
3871 FIXME("Unhandled function %#x.\n", function);
3875 if (ret) SetLastError(ret);
3876 return !ret;
3879 /***********************************************************************
3880 * SetupDiGetDeviceInstallParamsW (SETUPAPI.@)
3882 BOOL WINAPI SetupDiGetDeviceInstallParamsW(HDEVINFO devinfo,
3883 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_W *params)
3885 struct device *device;
3887 TRACE("devinfo %p, device_data %p, params %p.\n", devinfo, device_data, params);
3889 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
3891 SetLastError(ERROR_INVALID_USER_BUFFER);
3892 return FALSE;
3895 if (!(device = get_device(devinfo, device_data)))
3896 return FALSE;
3898 *params = device->params;
3900 return TRUE;
3903 /***********************************************************************
3904 * SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
3906 BOOL WINAPI SetupDiGetDeviceInstallParamsA(HDEVINFO devinfo,
3907 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_A *params)
3909 SP_DEVINSTALL_PARAMS_W paramsW;
3910 BOOL ret;
3912 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
3914 SetLastError(ERROR_INVALID_USER_BUFFER);
3915 return FALSE;
3918 paramsW.cbSize = sizeof(paramsW);
3919 ret = SetupDiGetDeviceInstallParamsW(devinfo, device_data, &paramsW);
3920 params->Flags = paramsW.Flags;
3921 params->FlagsEx = paramsW.FlagsEx;
3922 params->hwndParent = paramsW.hwndParent;
3923 params->InstallMsgHandler = paramsW.InstallMsgHandler;
3924 params->InstallMsgHandlerContext = paramsW.InstallMsgHandlerContext;
3925 params->FileQueue = paramsW.FileQueue;
3926 params->ClassInstallReserved = paramsW.ClassInstallReserved;
3927 params->Reserved = paramsW.Reserved;
3928 WideCharToMultiByte(CP_ACP, 0, paramsW.DriverPath, -1, params->DriverPath, sizeof(params->DriverPath), NULL, NULL);
3930 return ret;
3933 /***********************************************************************
3934 * SetupDiSetDeviceInstallParamsA (SETUPAPI.@)
3936 BOOL WINAPI SetupDiSetDeviceInstallParamsA(HDEVINFO devinfo,
3937 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_A *params)
3939 SP_DEVINSTALL_PARAMS_W paramsW;
3941 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
3943 SetLastError(ERROR_INVALID_USER_BUFFER);
3944 return FALSE;
3947 paramsW.cbSize = sizeof(paramsW);
3948 paramsW.Flags = params->Flags;
3949 paramsW.FlagsEx = params->FlagsEx;
3950 paramsW.hwndParent = params->hwndParent;
3951 paramsW.InstallMsgHandler = params->InstallMsgHandler;
3952 paramsW.InstallMsgHandlerContext = params->InstallMsgHandlerContext;
3953 paramsW.FileQueue = params->FileQueue;
3954 paramsW.ClassInstallReserved = params->ClassInstallReserved;
3955 paramsW.Reserved = params->Reserved;
3956 MultiByteToWideChar(CP_ACP, 0, params->DriverPath, -1, paramsW.DriverPath, ARRAY_SIZE(paramsW.DriverPath));
3958 return SetupDiSetDeviceInstallParamsW(devinfo, device_data, &paramsW);
3961 /***********************************************************************
3962 * SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
3964 BOOL WINAPI SetupDiSetDeviceInstallParamsW(HDEVINFO devinfo,
3965 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_W *params)
3967 struct device *device;
3969 TRACE("devinfo %p, device_data %p, params %p.\n", devinfo, device_data, params);
3971 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
3973 SetLastError(ERROR_INVALID_USER_BUFFER);
3974 return FALSE;
3977 if (!(device = get_device(devinfo, device_data)))
3978 return FALSE;
3980 device->params = *params;
3982 return TRUE;
3985 BOOL WINAPI SetupDiSetDevicePropertyW(HDEVINFO devinfo, PSP_DEVINFO_DATA device_data, const DEVPROPKEY *key,
3986 DEVPROPTYPE type, const BYTE *buffer, DWORD size, DWORD flags)
3988 static const WCHAR propertiesW[] = {'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's', 0};
3989 static const WCHAR formatW[] = {'\\', '%', '0', '4', 'X', 0};
3990 struct device *device;
3991 HKEY properties_hkey, property_hkey;
3992 WCHAR property_hkey_path[44];
3993 LSTATUS ls;
3995 TRACE("%p %p %p %#x %p %d %#x\n", devinfo, device_data, key, type, buffer, size, flags);
3997 if (!(device = get_device(devinfo, device_data)))
3998 return FALSE;
4000 if (!key || !is_valid_property_type(type)
4001 || (buffer && !size && !(type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL))
4002 || (buffer && size && (type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL)))
4004 SetLastError(ERROR_INVALID_DATA);
4005 return FALSE;
4008 if (size && !buffer)
4010 SetLastError(ERROR_INVALID_USER_BUFFER);
4011 return FALSE;
4014 if (flags)
4016 SetLastError(ERROR_INVALID_FLAGS);
4017 return FALSE;
4020 ls = RegCreateKeyExW(device->key, propertiesW, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &properties_hkey, NULL);
4021 if (ls)
4023 SetLastError(ls);
4024 return FALSE;
4027 SETUPDI_GuidToString(&key->fmtid, property_hkey_path);
4028 swprintf(property_hkey_path + 38, ARRAY_SIZE(property_hkey_path) - 38, formatW, key->pid);
4030 if (type == DEVPROP_TYPE_EMPTY)
4032 ls = RegDeleteKeyW(properties_hkey, property_hkey_path);
4033 RegCloseKey(properties_hkey);
4034 SetLastError(ls == ERROR_FILE_NOT_FOUND ? ERROR_NOT_FOUND : ls);
4035 return !ls;
4037 else if (type == DEVPROP_TYPE_NULL)
4039 if (!(ls = RegOpenKeyW(properties_hkey, property_hkey_path, &property_hkey)))
4041 ls = RegDeleteValueW(property_hkey, NULL);
4042 RegCloseKey(property_hkey);
4045 RegCloseKey(properties_hkey);
4046 SetLastError(ls == ERROR_FILE_NOT_FOUND ? ERROR_NOT_FOUND : ls);
4047 return !ls;
4049 else
4051 if (!(ls = RegCreateKeyExW(properties_hkey, property_hkey_path, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL,
4052 &property_hkey, NULL)))
4054 ls = RegSetValueExW(property_hkey, NULL, 0, 0xffff0000 | (0xffff & type), buffer, size);
4055 RegCloseKey(property_hkey);
4058 RegCloseKey(properties_hkey);
4059 SetLastError(ls);
4060 return !ls;
4064 /***********************************************************************
4065 * SetupDiOpenDevRegKey (SETUPAPI.@)
4067 HKEY WINAPI SetupDiOpenDevRegKey(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4068 DWORD Scope, DWORD HwProfile, DWORD KeyType, REGSAM samDesired)
4070 struct device *device;
4071 HKEY key = INVALID_HANDLE_VALUE;
4072 LONG l;
4074 TRACE("devinfo %p, device_data %p, scope %d, profile %d, type %d, access %#x.\n",
4075 devinfo, device_data, Scope, HwProfile, KeyType, samDesired);
4077 if (!(device = get_device(devinfo, device_data)))
4078 return INVALID_HANDLE_VALUE;
4080 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
4082 SetLastError(ERROR_INVALID_FLAGS);
4083 return INVALID_HANDLE_VALUE;
4085 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
4087 SetLastError(ERROR_INVALID_FLAGS);
4088 return INVALID_HANDLE_VALUE;
4091 if (device->phantom)
4093 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
4094 return INVALID_HANDLE_VALUE;
4096 if (Scope != DICS_FLAG_GLOBAL)
4097 FIXME("unimplemented for scope %d\n", Scope);
4098 switch (KeyType)
4100 case DIREG_DEV:
4101 l = RegOpenKeyExW(device->key, DeviceParameters, 0, samDesired, &key);
4102 break;
4103 case DIREG_DRV:
4104 l = open_driver_key(device, samDesired, &key);
4105 break;
4106 default:
4107 FIXME("Unhandled type %#x.\n", KeyType);
4108 l = ERROR_CALL_NOT_IMPLEMENTED;
4110 SetLastError(l == ERROR_FILE_NOT_FOUND ? ERROR_KEY_DOES_NOT_EXIST : l);
4111 return l ? INVALID_HANDLE_VALUE : key;
4114 /***********************************************************************
4115 * SetupDiDeleteDevRegKey (SETUPAPI.@)
4117 BOOL WINAPI SetupDiDeleteDevRegKey(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4118 DWORD Scope, DWORD HwProfile, DWORD KeyType)
4120 struct device *device;
4121 LONG l;
4123 TRACE("devinfo %p, device_data %p, scope %d, profile %d, type %d.\n",
4124 devinfo, device_data, Scope, HwProfile, KeyType);
4126 if (!(device = get_device(devinfo, device_data)))
4127 return FALSE;
4129 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
4131 SetLastError(ERROR_INVALID_FLAGS);
4132 return FALSE;
4134 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV && KeyType != DIREG_BOTH)
4136 SetLastError(ERROR_INVALID_FLAGS);
4137 return FALSE;
4140 if (device->phantom)
4142 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
4143 return FALSE;
4145 if (Scope != DICS_FLAG_GLOBAL)
4146 FIXME("unimplemented for scope %d\n", Scope);
4147 switch (KeyType)
4149 case DIREG_DRV:
4150 l = delete_driver_key(device);
4151 break;
4152 case DIREG_BOTH:
4153 if ((l = delete_driver_key(device)))
4154 break;
4155 /* fall through */
4156 case DIREG_DEV:
4157 l = RegDeleteKeyW(device->key, DeviceParameters);
4158 break;
4159 default:
4160 FIXME("Unhandled type %#x.\n", KeyType);
4161 l = ERROR_CALL_NOT_IMPLEMENTED;
4163 SetLastError(l);
4164 return !l;
4167 /***********************************************************************
4168 * CM_Get_Device_IDA (SETUPAPI.@)
4170 CONFIGRET WINAPI CM_Get_Device_IDA(DEVINST devnode, char *buffer, ULONG len, ULONG flags)
4172 struct device *device = get_devnode_device(devnode);
4174 TRACE("%u, %p, %u, %#x\n", devnode, buffer, len, flags);
4176 if (!device)
4177 return CR_NO_SUCH_DEVINST;
4179 WideCharToMultiByte(CP_ACP, 0, device->instanceId, -1, buffer, len, 0, 0);
4180 TRACE("Returning %s\n", debugstr_a(buffer));
4181 return CR_SUCCESS;
4184 /***********************************************************************
4185 * CM_Get_Device_IDW (SETUPAPI.@)
4187 CONFIGRET WINAPI CM_Get_Device_IDW(DEVINST devnode, WCHAR *buffer, ULONG len, ULONG flags)
4189 struct device *device = get_devnode_device(devnode);
4191 TRACE("%u, %p, %u, %#x\n", devnode, buffer, len, flags);
4193 if (!device)
4194 return CR_NO_SUCH_DEVINST;
4196 lstrcpynW(buffer, device->instanceId, len);
4197 TRACE("Returning %s\n", debugstr_w(buffer));
4198 return CR_SUCCESS;
4201 /***********************************************************************
4202 * CM_Get_Device_ID_Size (SETUPAPI.@)
4204 CONFIGRET WINAPI CM_Get_Device_ID_Size(ULONG *len, DEVINST devnode, ULONG flags)
4206 struct device *device = get_devnode_device(devnode);
4208 TRACE("%p, %u, %#x\n", len, devnode, flags);
4210 if (!device)
4211 return CR_NO_SUCH_DEVINST;
4213 *len = lstrlenW(device->instanceId);
4214 return CR_SUCCESS;
4217 /***********************************************************************
4218 * SetupDiGetINFClassA (SETUPAPI.@)
4220 BOOL WINAPI SetupDiGetINFClassA(PCSTR inf, LPGUID class_guid, PSTR class_name,
4221 DWORD size, PDWORD required_size)
4223 BOOL retval;
4224 DWORD required_sizeA, required_sizeW;
4225 PWSTR class_nameW = NULL;
4226 UNICODE_STRING infW;
4228 if (inf)
4230 if (!RtlCreateUnicodeStringFromAsciiz(&infW, inf))
4232 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4233 return FALSE;
4236 else
4237 infW.Buffer = NULL;
4239 if (class_name && size)
4241 if (!(class_nameW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR))))
4243 RtlFreeUnicodeString(&infW);
4244 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4245 return FALSE;
4249 retval = SetupDiGetINFClassW(infW.Buffer, class_guid, class_nameW, size, &required_sizeW);
4251 if (retval)
4253 required_sizeA = WideCharToMultiByte( CP_ACP, 0, class_nameW, required_sizeW,
4254 class_name, size, NULL, NULL);
4256 if(required_size) *required_size = required_sizeA;
4258 else
4259 if(required_size) *required_size = required_sizeW;
4261 HeapFree(GetProcessHeap(), 0, class_nameW);
4262 RtlFreeUnicodeString(&infW);
4263 return retval;
4266 /***********************************************************************
4267 * SetupDiGetINFClassW (SETUPAPI.@)
4269 BOOL WINAPI SetupDiGetINFClassW(PCWSTR inf, LPGUID class_guid, PWSTR class_name,
4270 DWORD size, PDWORD required_size)
4272 BOOL have_guid, have_name;
4273 DWORD dret;
4274 WCHAR buffer[MAX_PATH];
4276 if (!inf)
4278 SetLastError(ERROR_INVALID_PARAMETER);
4279 return FALSE;
4282 if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(inf))
4284 FIXME("%s not found. Searching via DevicePath not implemented\n", debugstr_w(inf));
4285 SetLastError(ERROR_FILE_NOT_FOUND);
4286 return FALSE;
4289 if (!class_guid || !class_name || !size)
4291 SetLastError(ERROR_INVALID_PARAMETER);
4292 return FALSE;
4295 if (!GetPrivateProfileStringW(Version, Signature, NULL, buffer, MAX_PATH, inf))
4296 return FALSE;
4298 if (lstrcmpiW(buffer, Chicago) && lstrcmpiW(buffer, WindowsNT))
4299 return FALSE;
4301 buffer[0] = '\0';
4302 have_guid = 0 < GetPrivateProfileStringW(Version, ClassGUID, NULL, buffer, MAX_PATH, inf);
4303 if (have_guid)
4305 buffer[lstrlenW(buffer)-1] = 0;
4306 if (RPC_S_OK != UuidFromStringW(buffer + 1, class_guid))
4308 FIXME("failed to convert \"%s\" into a guid\n", debugstr_w(buffer));
4309 SetLastError(ERROR_INVALID_PARAMETER);
4310 return FALSE;
4314 buffer[0] = '\0';
4315 dret = GetPrivateProfileStringW(Version, Class, NULL, buffer, MAX_PATH, inf);
4316 have_name = 0 < dret;
4318 if (dret >= MAX_PATH -1) FIXME("buffer might be too small\n");
4319 if (have_guid && !have_name)
4321 class_name[0] = '\0';
4322 FIXME("class name lookup via guid not implemented\n");
4325 if (have_name)
4327 if (dret < size) lstrcpyW(class_name, buffer);
4328 else
4330 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4331 have_name = FALSE;
4335 if (required_size) *required_size = dret + ((dret) ? 1 : 0);
4337 return (have_guid || have_name);
4340 static LSTATUS get_device_property(struct device *device, const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type,
4341 BYTE *prop_buff, DWORD prop_buff_size, DWORD *required_size, DWORD flags)
4343 WCHAR key_path[55] = L"Properties\\";
4344 HKEY hkey;
4345 DWORD value_type;
4346 DWORD value_size = 0;
4347 LSTATUS ls;
4349 if (!prop_key)
4350 return ERROR_INVALID_DATA;
4352 if (!prop_type || (!prop_buff && prop_buff_size))
4353 return ERROR_INVALID_USER_BUFFER;
4355 if (flags)
4356 return ERROR_INVALID_FLAGS;
4358 SETUPDI_GuidToString(&prop_key->fmtid, key_path + 11);
4359 swprintf(key_path + 49, ARRAY_SIZE(key_path) - 49, L"\\%04X", prop_key->pid);
4361 ls = RegOpenKeyExW(device->key, key_path, 0, KEY_QUERY_VALUE, &hkey);
4362 if (!ls)
4364 value_size = prop_buff_size;
4365 ls = RegQueryValueExW(hkey, NULL, NULL, &value_type, prop_buff, &value_size);
4366 RegCloseKey(hkey);
4369 switch (ls)
4371 case NO_ERROR:
4372 case ERROR_MORE_DATA:
4373 *prop_type = 0xffff & value_type;
4374 ls = (ls == ERROR_MORE_DATA || !prop_buff) ? ERROR_INSUFFICIENT_BUFFER : NO_ERROR;
4375 break;
4376 case ERROR_FILE_NOT_FOUND:
4377 *prop_type = DEVPROP_TYPE_EMPTY;
4378 value_size = 0;
4379 ls = ERROR_NOT_FOUND;
4380 break;
4381 default:
4382 *prop_type = DEVPROP_TYPE_EMPTY;
4383 value_size = 0;
4384 FIXME("Unhandled error %#x\n", ls);
4385 break;
4388 if (required_size)
4389 *required_size = value_size;
4391 return ls;
4394 /***********************************************************************
4395 * SetupDiGetDevicePropertyW (SETUPAPI.@)
4397 BOOL WINAPI SetupDiGetDevicePropertyW(HDEVINFO devinfo, PSP_DEVINFO_DATA device_data,
4398 const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type, BYTE *prop_buff,
4399 DWORD prop_buff_size, DWORD *required_size, DWORD flags)
4401 struct device *device;
4402 LSTATUS ls;
4404 TRACE("%p, %p, %p, %p, %p, %d, %p, %#x\n", devinfo, device_data, prop_key, prop_type, prop_buff, prop_buff_size,
4405 required_size, flags);
4407 if (!(device = get_device(devinfo, device_data)))
4408 return FALSE;
4410 ls = get_device_property(device, prop_key, prop_type, prop_buff, prop_buff_size, required_size, flags);
4412 SetLastError(ls);
4413 return !ls;
4416 /***********************************************************************
4417 * CM_Get_DevNode_Property_ExW (SETUPAPI.@)
4419 CONFIGRET WINAPI CM_Get_DevNode_Property_ExW(DEVINST devnode, const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type,
4420 BYTE *prop_buff, ULONG *prop_buff_size, ULONG flags, HMACHINE machine)
4422 struct device *device = get_devnode_device(devnode);
4423 LSTATUS ls;
4425 TRACE("%u, %p, %p, %p, %p, %#x, %p\n", devnode, prop_key, prop_type, prop_buff, prop_buff_size,
4426 flags, machine);
4428 if (machine)
4429 return CR_MACHINE_UNAVAILABLE;
4431 if (!device)
4432 return CR_NO_SUCH_DEVINST;
4434 if (!prop_buff_size)
4435 return CR_INVALID_POINTER;
4437 ls = get_device_property(device, prop_key, prop_type, prop_buff, *prop_buff_size, prop_buff_size, flags);
4438 switch (ls)
4440 case NO_ERROR:
4441 return CR_SUCCESS;
4442 case ERROR_INVALID_DATA:
4443 return CR_INVALID_DATA;
4444 case ERROR_INVALID_USER_BUFFER:
4445 return CR_INVALID_POINTER;
4446 case ERROR_INVALID_FLAGS:
4447 return CR_INVALID_FLAG;
4448 case ERROR_INSUFFICIENT_BUFFER:
4449 return CR_BUFFER_SMALL;
4450 case ERROR_NOT_FOUND:
4451 return CR_NO_SUCH_VALUE;
4453 return CR_FAILURE;
4456 /***********************************************************************
4457 * CM_Get_DevNode_PropertyW (SETUPAPI.@)
4459 CONFIGRET WINAPI CM_Get_DevNode_PropertyW(DEVINST dev, const DEVPROPKEY *key, DEVPROPTYPE *type,
4460 PVOID buf, PULONG len, ULONG flags)
4462 return CM_Get_DevNode_Property_ExW(dev, key, type, buf, len, flags, NULL);
4465 /***********************************************************************
4466 * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
4468 BOOL WINAPI SetupDiInstallDeviceInterfaces(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4470 WCHAR section_ext[LINE_LEN], iface_section[LINE_LEN], refstr[LINE_LEN], guidstr[39];
4471 UINT install_flags = SPINST_ALL;
4472 struct device_iface *iface;
4473 struct device *device;
4474 struct driver *driver;
4475 void *callback_ctx;
4476 GUID iface_guid;
4477 INFCONTEXT ctx;
4478 HKEY iface_key;
4479 HINF hinf;
4480 LONG l;
4482 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
4484 if (!(device = get_device(devinfo, device_data)))
4485 return FALSE;
4487 if (!(driver = device->selected_driver))
4489 ERR("No driver selected for device %p.\n", devinfo);
4490 SetLastError(ERROR_NO_DRIVER_SELECTED);
4491 return FALSE;
4494 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4495 return FALSE;
4497 SetupDiGetActualSectionToInstallW(hinf, driver->section, section_ext, ARRAY_SIZE(section_ext), NULL, NULL);
4499 if (device->params.Flags & DI_NOFILECOPY)
4500 install_flags &= ~SPINST_FILES;
4502 callback_ctx = SetupInitDefaultQueueCallback(NULL);
4504 lstrcatW(section_ext, dotInterfaces);
4505 if (SetupFindFirstLineW(hinf, section_ext, AddInterface, &ctx))
4507 do {
4508 SetupGetStringFieldW(&ctx, 1, guidstr, ARRAY_SIZE(guidstr), NULL);
4509 SetupGetStringFieldW(&ctx, 2, refstr, ARRAY_SIZE(refstr), NULL);
4510 guidstr[37] = 0;
4511 UuidFromStringW(&guidstr[1], &iface_guid);
4513 if (!(iface = SETUPDI_CreateDeviceInterface(device, &iface_guid, refstr)))
4515 ERR("Failed to create device interface, error %#x.\n", GetLastError());
4516 continue;
4519 if ((l = create_iface_key(iface, KEY_ALL_ACCESS, &iface_key)))
4521 ERR("Failed to create interface key, error %u.\n", l);
4522 continue;
4525 SetupGetStringFieldW(&ctx, 3, iface_section, ARRAY_SIZE(iface_section), NULL);
4526 SetupInstallFromInfSectionW(NULL, hinf, iface_section, install_flags, iface_key,
4527 NULL, SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
4529 RegCloseKey(iface_key);
4530 } while (SetupFindNextMatchLineW(&ctx, AddInterface, &ctx));
4533 SetupTermDefaultQueueCallback(callback_ctx);
4535 SetupCloseInfFile(hinf);
4536 return TRUE;
4539 /***********************************************************************
4540 * SetupDiRegisterCoDeviceInstallers (SETUPAPI.@)
4542 BOOL WINAPI SetupDiRegisterCoDeviceInstallers(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4544 static const WCHAR coinstallersW[] = {'.','C','o','I','n','s','t','a','l','l','e','r','s',0};
4545 WCHAR coinst_key_ext[LINE_LEN];
4546 struct device *device;
4547 struct driver *driver;
4548 void *callback_ctx;
4549 HKEY driver_key;
4550 HINF hinf;
4551 LONG l;
4553 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
4555 if (!(device = get_device(devinfo, device_data)))
4556 return FALSE;
4558 if (!(driver = device->selected_driver))
4560 ERR("No driver selected for device %p.\n", devinfo);
4561 SetLastError(ERROR_NO_DRIVER_SELECTED);
4562 return FALSE;
4565 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4566 return FALSE;
4568 SetupDiGetActualSectionToInstallW(hinf, driver->section, coinst_key_ext, ARRAY_SIZE(coinst_key_ext), NULL, NULL);
4569 lstrcatW(coinst_key_ext, coinstallersW);
4571 if ((l = create_driver_key(device, &driver_key)))
4573 SetLastError(l);
4574 SetupCloseInfFile(hinf);
4575 return FALSE;
4578 callback_ctx = SetupInitDefaultQueueCallback(NULL);
4579 SetupInstallFromInfSectionW(NULL, hinf, coinst_key_ext, SPINST_ALL, driver_key, NULL,
4580 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
4581 SetupTermDefaultQueueCallback(callback_ctx);
4583 RegCloseKey(driver_key);
4584 SetupCloseInfFile(hinf);
4585 return TRUE;
4588 /* Check whether the given hardware or compatible ID matches any of the device's
4589 * own hardware or compatible IDs. */
4590 static BOOL device_matches_id(const struct device *device, const WCHAR *id_type, const WCHAR *id)
4592 WCHAR *device_ids;
4593 const WCHAR *p;
4594 DWORD size;
4596 if (!RegGetValueW(device->key, NULL, id_type, RRF_RT_REG_MULTI_SZ, NULL, NULL, &size))
4598 device_ids = heap_alloc(size);
4599 if (!RegGetValueW(device->key, NULL, id_type, RRF_RT_REG_MULTI_SZ, NULL, device_ids, &size))
4601 for (p = device_ids; *p; p += lstrlenW(p) + 1)
4603 if (!wcsicmp(p, id))
4605 heap_free(device_ids);
4606 return TRUE;
4610 heap_free(device_ids);
4613 return FALSE;
4616 static BOOL version_is_compatible(const WCHAR *version)
4618 const WCHAR *machine_ext = NtPlatformExtension + 1, *p;
4619 size_t len = lstrlenW(version);
4620 BOOL wow64;
4622 /* We are only concerned with architecture. */
4623 if ((p = wcschr(version, '.')))
4624 len = p - version;
4626 if (!wcsnicmp(version, NtExtension + 1, len))
4627 return TRUE;
4629 if (IsWow64Process(GetCurrentProcess(), &wow64) && wow64)
4631 #ifdef __i386__
4632 static const WCHAR wow_ext[] = {'N','T','a','m','d','6','4',0};
4633 machine_ext = wow_ext;
4634 #elif defined(__arm__)
4635 static const WCHAR wow_ext[] = {'N','T','a','r','m','6','4',0};
4636 machine_ext = wow_ext;
4637 #endif
4640 return !wcsnicmp(version, machine_ext, len);
4643 static void enum_compat_drivers_from_file(struct device *device, const WCHAR *path)
4645 static const WCHAR manufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4646 WCHAR mfg_name[LINE_LEN], mfg_key[LINE_LEN], mfg_key_ext[LINE_LEN], id[MAX_DEVICE_ID_LEN], version[MAX_DEVICE_ID_LEN];
4647 INFCONTEXT ctx;
4648 DWORD i, j, k;
4649 HINF hinf;
4651 TRACE("Enumerating drivers from %s.\n", debugstr_w(path));
4653 if ((hinf = SetupOpenInfFileW(path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4654 return;
4656 for (i = 0; SetupGetLineByIndexW(hinf, manufacturerW, i, &ctx); ++i)
4658 SetupGetStringFieldW(&ctx, 0, mfg_name, ARRAY_SIZE(mfg_name), NULL);
4659 if (!SetupGetStringFieldW(&ctx, 1, mfg_key, ARRAY_SIZE(mfg_key), NULL))
4660 lstrcpyW(mfg_key, mfg_name);
4662 if (SetupGetFieldCount(&ctx) >= 2)
4664 BOOL compatible = FALSE;
4665 for (j = 2; SetupGetStringFieldW(&ctx, j, version, ARRAY_SIZE(version), NULL); ++j)
4667 if (version_is_compatible(version))
4669 compatible = TRUE;
4670 break;
4673 if (!compatible)
4674 continue;
4677 if (!SetupDiGetActualSectionToInstallW(hinf, mfg_key, mfg_key_ext, ARRAY_SIZE(mfg_key_ext), NULL, NULL))
4679 WARN("Failed to find section for %s, skipping.\n", debugstr_w(mfg_key));
4680 continue;
4683 for (j = 0; SetupGetLineByIndexW(hinf, mfg_key_ext, j, &ctx); ++j)
4685 for (k = 2; SetupGetStringFieldW(&ctx, k, id, ARRAY_SIZE(id), NULL); ++k)
4687 if (device_matches_id(device, HardwareId, id) || device_matches_id(device, CompatibleIDs, id))
4689 unsigned int count = ++device->driver_count;
4691 device->drivers = heap_realloc(device->drivers, count * sizeof(*device->drivers));
4692 lstrcpyW(device->drivers[count - 1].inf_path, path);
4693 lstrcpyW(device->drivers[count - 1].manufacturer, mfg_name);
4694 lstrcpyW(device->drivers[count - 1].mfg_key, mfg_key_ext);
4695 SetupGetStringFieldW(&ctx, 0, device->drivers[count - 1].description,
4696 ARRAY_SIZE(device->drivers[count - 1].description), NULL);
4697 SetupGetStringFieldW(&ctx, 1, device->drivers[count - 1].section,
4698 ARRAY_SIZE(device->drivers[count - 1].section), NULL);
4700 TRACE("Found compatible driver: manufacturer %s, desc %s.\n",
4701 debugstr_w(mfg_name), debugstr_w(device->drivers[count - 1].description));
4707 SetupCloseInfFile(hinf);
4710 /***********************************************************************
4711 * SetupDiBuildDriverInfoList (SETUPAPI.@)
4713 BOOL WINAPI SetupDiBuildDriverInfoList(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD type)
4715 struct device *device;
4717 TRACE("devinfo %p, device_data %p, type %#x.\n", devinfo, device_data, type);
4719 if (type != SPDIT_COMPATDRIVER)
4721 FIXME("Unhandled type %#x.\n", type);
4722 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4723 return FALSE;
4726 if (!(device = get_device(devinfo, device_data)))
4727 return FALSE;
4729 if (device->params.Flags & DI_ENUMSINGLEINF)
4731 enum_compat_drivers_from_file(device, device->params.DriverPath);
4733 else
4735 static const WCHAR default_path[] = {'C',':','/','w','i','n','d','o','w','s','/','i','n','f',0};
4736 static const WCHAR wildcardW[] = {'*',0};
4737 WCHAR dir[MAX_PATH], file[MAX_PATH];
4738 WIN32_FIND_DATAW find_data;
4739 HANDLE find_handle;
4741 if (device->params.DriverPath[0])
4742 lstrcpyW(dir, device->params.DriverPath);
4743 else
4744 lstrcpyW(dir, default_path);
4745 lstrcatW(dir, backslashW);
4746 lstrcatW(dir, wildcardW);
4748 TRACE("Searching for drivers in %s.\n", debugstr_w(dir));
4750 if ((find_handle = FindFirstFileW(dir, &find_data)) != INVALID_HANDLE_VALUE)
4754 lstrcpyW(file, dir);
4755 lstrcpyW(file + lstrlenW(file) - 1, find_data.cFileName);
4756 enum_compat_drivers_from_file(device, file);
4757 } while (FindNextFileW(find_handle, &find_data));
4759 FindClose(find_handle);
4763 if (device->driver_count)
4765 WCHAR classname[MAX_CLASS_NAME_LEN], guidstr[39];
4766 GUID class;
4768 if (SetupDiGetINFClassW(device->drivers[0].inf_path, &class, classname, ARRAY_SIZE(classname), NULL))
4770 device_data->ClassGuid = device->class = class;
4771 SETUPDI_GuidToString(&class, guidstr);
4772 RegSetValueExW(device->key, L"ClassGUID", 0, REG_SZ, (BYTE *)guidstr, sizeof(guidstr));
4773 RegSetValueExW(device->key, L"Class", 0, REG_SZ, (BYTE *)classname, wcslen(classname) * sizeof(WCHAR));
4777 return TRUE;
4780 static BOOL copy_driver_data(SP_DRVINFO_DATA_W *data, const struct driver *driver)
4782 INFCONTEXT ctx;
4783 HINF hinf;
4785 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4786 return FALSE;
4788 data->ProviderName[0] = 0;
4789 if (SetupFindFirstLineW(hinf, L"Version", L"Provider", &ctx))
4790 SetupGetStringFieldW(&ctx, 1, data->ProviderName, ARRAY_SIZE(data->ProviderName), NULL);
4791 wcscpy(data->Description, driver->description);
4792 wcscpy(data->MfgName, driver->manufacturer);
4793 data->DriverType = SPDIT_COMPATDRIVER;
4794 data->Reserved = (ULONG_PTR)driver;
4796 SetupCloseInfFile(hinf);
4798 return TRUE;
4801 static void driver_data_wtoa(SP_DRVINFO_DATA_A *a, const SP_DRVINFO_DATA_W *w)
4803 a->DriverType = w->DriverType;
4804 a->Reserved = w->Reserved;
4805 WideCharToMultiByte(CP_ACP, 0, w->Description, -1, a->Description, sizeof(a->Description), NULL, NULL);
4806 WideCharToMultiByte(CP_ACP, 0, w->MfgName, -1, a->MfgName, sizeof(a->MfgName), NULL, NULL);
4807 WideCharToMultiByte(CP_ACP, 0, w->ProviderName, -1, a->ProviderName, sizeof(a->ProviderName), NULL, NULL);
4810 /***********************************************************************
4811 * SetupDiEnumDriverInfoW (SETUPAPI.@)
4813 BOOL WINAPI SetupDiEnumDriverInfoW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4814 DWORD type, DWORD index, SP_DRVINFO_DATA_W *driver_data)
4816 struct device *device;
4818 TRACE("devinfo %p, device_data %p, type %#x, index %u, driver_data %p.\n",
4819 devinfo, device_data, type, index, driver_data);
4821 if (type != SPDIT_COMPATDRIVER)
4823 FIXME("Unhandled type %#x.\n", type);
4824 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4825 return FALSE;
4828 if (!(device = get_device(devinfo, device_data)))
4829 return FALSE;
4831 if (index >= device->driver_count)
4833 SetLastError(ERROR_NO_MORE_ITEMS);
4834 return FALSE;
4837 return copy_driver_data(driver_data, &device->drivers[index]);
4840 /***********************************************************************
4841 * SetupDiEnumDriverInfoA (SETUPAPI.@)
4843 BOOL WINAPI SetupDiEnumDriverInfoA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4844 DWORD type, DWORD index, SP_DRVINFO_DATA_A *driver_data)
4846 SP_DRVINFO_DATA_W driver_dataW;
4847 BOOL ret;
4849 driver_dataW.cbSize = sizeof(driver_dataW);
4850 ret = SetupDiEnumDriverInfoW(devinfo, device_data, type, index, &driver_dataW);
4851 if (ret) driver_data_wtoa(driver_data, &driver_dataW);
4853 return ret;
4856 /***********************************************************************
4857 * SetupDiSelectBestCompatDrv (SETUPAPI.@)
4859 BOOL WINAPI SetupDiSelectBestCompatDrv(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4861 struct device *device;
4863 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
4865 if (!(device = get_device(devinfo, device_data)))
4866 return FALSE;
4868 if (!device->driver_count)
4870 WARN("No compatible drivers were enumerated for device %s.\n", debugstr_w(device->instanceId));
4871 SetLastError(ERROR_NO_COMPAT_DRIVERS);
4872 return FALSE;
4875 WARN("Semi-stub, selecting the first available driver.\n");
4877 device->selected_driver = &device->drivers[0];
4879 return TRUE;
4882 /***********************************************************************
4883 * SetupDiGetSelectedDriverW (SETUPAPI.@)
4885 BOOL WINAPI SetupDiGetSelectedDriverW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, SP_DRVINFO_DATA_W *driver_data)
4887 struct device *device;
4889 TRACE("devinfo %p, device_data %p, driver_data %p.\n", devinfo, device_data, driver_data);
4891 if (!(device = get_device(devinfo, device_data)))
4892 return FALSE;
4894 if (!device->selected_driver)
4896 SetLastError(ERROR_NO_DRIVER_SELECTED);
4897 return FALSE;
4900 return copy_driver_data(driver_data, device->selected_driver);
4903 /***********************************************************************
4904 * SetupDiGetSelectedDriverA (SETUPAPI.@)
4906 BOOL WINAPI SetupDiGetSelectedDriverA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, SP_DRVINFO_DATA_A *driver_data)
4908 SP_DRVINFO_DATA_W driver_dataW;
4909 BOOL ret;
4911 driver_dataW.cbSize = sizeof(driver_dataW);
4912 if ((ret = SetupDiGetSelectedDriverW(devinfo, device_data, &driver_dataW)))
4913 driver_data_wtoa(driver_data, &driver_dataW);
4914 return ret;
4917 /***********************************************************************
4918 * SetupDiGetDriverInfoDetailW (SETUPAPI.@)
4920 BOOL WINAPI SetupDiGetDriverInfoDetailW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4921 SP_DRVINFO_DATA_W *driver_data, SP_DRVINFO_DETAIL_DATA_W *detail_data, const DWORD size, DWORD *ret_size)
4923 struct driver *driver = (struct driver *)driver_data->Reserved;
4924 DWORD size_needed, i, id_size = 1;
4925 WCHAR id[MAX_DEVICE_ID_LEN];
4926 INFCONTEXT ctx;
4927 HANDLE file;
4928 HINF hinf;
4930 TRACE("devinfo %p, device_data %p, driver_data %p, detail_data %p, size %u, ret_size %p.\n",
4931 devinfo, device_data, driver_data, detail_data, size, ret_size);
4933 if ((detail_data || size) && size < sizeof(SP_DRVINFO_DETAIL_DATA_W))
4935 SetLastError(ERROR_INVALID_USER_BUFFER);
4936 return FALSE;
4939 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4940 return FALSE;
4942 SetupFindFirstLineW(hinf, driver->mfg_key, driver->description, &ctx);
4943 for (i = 2; SetupGetStringFieldW(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
4944 id_size += wcslen(id) + 1;
4946 size_needed = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID[id_size]);
4947 if (ret_size)
4948 *ret_size = size_needed;
4949 if (!detail_data)
4950 return TRUE;
4952 detail_data->CompatIDsLength = detail_data->CompatIDsOffset = 0;
4953 detail_data->HardwareID[0] = 0;
4955 if (size >= size_needed)
4957 id_size = 0;
4958 for (i = 2; SetupGetStringFieldW(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
4960 wcscpy(&detail_data->HardwareID[id_size], id);
4961 if (i == 3)
4962 detail_data->CompatIDsOffset = id_size;
4963 id_size += wcslen(id) + 1;
4965 detail_data->HardwareID[id_size++] = 0;
4966 if (i > 3)
4967 detail_data->CompatIDsLength = id_size - detail_data->CompatIDsOffset;
4970 SetupCloseInfFile(hinf);
4972 if ((file = CreateFileW(driver->inf_path, 0, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
4973 return FALSE;
4974 GetFileTime(file, NULL, NULL, &detail_data->InfDate);
4975 CloseHandle(file);
4977 wcscpy(detail_data->SectionName, driver->section);
4978 wcscpy(detail_data->InfFileName, driver->inf_path);
4979 wcscpy(detail_data->DrvDescription, driver->description);
4981 if (size < size_needed)
4983 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4984 return FALSE;
4987 return TRUE;
4990 /***********************************************************************
4991 * SetupDiGetDriverInfoDetailA (SETUPAPI.@)
4993 BOOL WINAPI SetupDiGetDriverInfoDetailA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4994 SP_DRVINFO_DATA_A *driver_data, SP_DRVINFO_DETAIL_DATA_A *detail_data, const DWORD size, DWORD *ret_size)
4996 struct driver *driver = (struct driver *)driver_data->Reserved;
4997 DWORD size_needed, i, id_size = 1;
4998 char id[MAX_DEVICE_ID_LEN];
4999 INFCONTEXT ctx;
5000 HANDLE file;
5001 HINF hinf;
5003 TRACE("devinfo %p, device_data %p, driver_data %p, detail_data %p, size %u, ret_size %p.\n",
5004 devinfo, device_data, driver_data, detail_data, size, ret_size);
5006 if ((detail_data || size) && size < sizeof(SP_DRVINFO_DETAIL_DATA_A))
5008 SetLastError(ERROR_INVALID_USER_BUFFER);
5009 return FALSE;
5012 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
5013 return FALSE;
5015 SetupFindFirstLineW(hinf, driver->mfg_key, driver->description, &ctx);
5016 for (i = 2; SetupGetStringFieldA(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
5017 id_size += strlen(id) + 1;
5019 size_needed = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID[id_size]);
5020 if (ret_size)
5021 *ret_size = size_needed;
5022 if (!detail_data)
5024 SetupCloseInfFile(hinf);
5025 return TRUE;
5028 detail_data->CompatIDsLength = detail_data->CompatIDsOffset = 0;
5029 detail_data->HardwareID[0] = 0;
5031 if (size >= size_needed)
5033 id_size = 0;
5034 for (i = 2; SetupGetStringFieldA(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
5036 strcpy(&detail_data->HardwareID[id_size], id);
5037 if (i == 3)
5038 detail_data->CompatIDsOffset = id_size;
5039 id_size += strlen(id) + 1;
5041 detail_data->HardwareID[id_size++] = 0;
5042 if (i > 3)
5043 detail_data->CompatIDsLength = id_size - detail_data->CompatIDsOffset;
5046 SetupCloseInfFile(hinf);
5048 if ((file = CreateFileW(driver->inf_path, 0, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
5049 return FALSE;
5050 GetFileTime(file, NULL, NULL, &detail_data->InfDate);
5051 CloseHandle(file);
5053 WideCharToMultiByte(CP_ACP, 0, driver->section, -1, detail_data->SectionName,
5054 sizeof(detail_data->SectionName), NULL, NULL);
5055 WideCharToMultiByte(CP_ACP, 0, driver->inf_path, -1, detail_data->InfFileName,
5056 sizeof(detail_data->InfFileName), NULL, NULL);
5057 WideCharToMultiByte(CP_ACP, 0, driver->description, -1, detail_data->DrvDescription,
5058 sizeof(detail_data->InfFileName), NULL, NULL);
5060 if (size < size_needed)
5062 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5063 return FALSE;
5066 return TRUE;
5069 /***********************************************************************
5070 * SetupDiInstallDriverFiles (SETUPAPI.@)
5072 BOOL WINAPI SetupDiInstallDriverFiles(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
5074 WCHAR section[LINE_LEN], section_ext[LINE_LEN], iface_section[LINE_LEN];
5075 struct device *device;
5076 struct driver *driver;
5077 void *callback_ctx;
5078 INFCONTEXT ctx;
5079 HINF hinf;
5081 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
5083 if (!(device = get_device(devinfo, device_data)))
5084 return FALSE;
5086 if (!(driver = device->selected_driver))
5088 ERR("No driver selected for device %p.\n", devinfo);
5089 SetLastError(ERROR_NO_DRIVER_SELECTED);
5090 return FALSE;
5093 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
5094 return FALSE;
5096 SetupFindFirstLineW(hinf, driver->mfg_key, driver->description, &ctx);
5097 SetupGetStringFieldW(&ctx, 1, section, ARRAY_SIZE(section), NULL);
5098 SetupDiGetActualSectionToInstallW(hinf, section, section_ext, ARRAY_SIZE(section_ext), NULL, NULL);
5100 callback_ctx = SetupInitDefaultQueueCallback(NULL);
5102 SetupInstallFromInfSectionW(NULL, hinf, section_ext, SPINST_FILES, NULL, NULL,
5103 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5105 lstrcatW(section_ext, dotInterfaces);
5106 if (SetupFindFirstLineW(hinf, section_ext, AddInterface, &ctx))
5108 do {
5109 SetupGetStringFieldW(&ctx, 3, iface_section, ARRAY_SIZE(iface_section), NULL);
5110 SetupInstallFromInfSectionW(NULL, hinf, iface_section, SPINST_FILES, NULL, NULL,
5111 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5112 } while (SetupFindNextMatchLineW(&ctx, AddInterface, &ctx));
5115 SetupTermDefaultQueueCallback(callback_ctx);
5117 SetupCloseInfFile(hinf);
5118 return TRUE;
5121 /***********************************************************************
5122 * SetupDiInstallDevice (SETUPAPI.@)
5124 BOOL WINAPI SetupDiInstallDevice(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
5126 static const WCHAR infpathW[] = {'I','n','f','P','a','t','h',0};
5127 static const WCHAR infsectionW[] = {'I','n','f','S','e','c','t','i','o','n',0};
5128 static const WCHAR infsectionextW[] = {'I','n','f','S','e','c','t','i','o','n','E','x','t',0};
5129 static const WCHAR dothwW[] = {'.','H','W',0};
5130 static const WCHAR dotservicesW[] = {'.','S','e','r','v','i','c','e','s',0};
5131 static const WCHAR addserviceW[] = {'A','d','d','S','e','r','v','i','c','e',0};
5132 static const WCHAR rootW[] = {'r','o','o','t','\\',0};
5133 WCHAR section_ext[LINE_LEN], subsection[LINE_LEN], inf_path[MAX_PATH], *extptr, *filepart;
5134 UINT install_flags = SPINST_ALL;
5135 HKEY driver_key, device_key;
5136 SC_HANDLE manager, service;
5137 WCHAR svc_name[LINE_LEN];
5138 struct device *device;
5139 struct driver *driver;
5140 void *callback_ctx;
5141 INFCONTEXT ctx;
5142 HINF hinf;
5143 LONG l;
5145 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
5147 if (!(device = get_device(devinfo, device_data)))
5148 return FALSE;
5150 if (!(driver = device->selected_driver))
5152 ERR("No driver selected for device %p.\n", devinfo);
5153 SetLastError(ERROR_NO_DRIVER_SELECTED);
5154 return FALSE;
5157 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
5158 return FALSE;
5160 RegSetValueExW(device->key, L"DeviceDesc", 0, REG_SZ, (BYTE *)driver->description,
5161 wcslen(driver->description) * sizeof(WCHAR));
5163 SetupDiGetActualSectionToInstallW(hinf, driver->section, section_ext, ARRAY_SIZE(section_ext), NULL, &extptr);
5165 if ((l = create_driver_key(device, &driver_key)))
5167 SetLastError(l);
5168 SetupCloseInfFile(hinf);
5169 return FALSE;
5172 if ((l = RegCreateKeyExW(device->key, DeviceParameters, 0, NULL, 0,
5173 KEY_READ | KEY_WRITE, NULL, &device_key, NULL)))
5175 SetLastError(l);
5176 RegCloseKey(driver_key);
5177 SetupCloseInfFile(hinf);
5178 return FALSE;
5181 if (device->params.Flags & DI_NOFILECOPY)
5182 install_flags &= ~SPINST_FILES;
5184 callback_ctx = SetupInitDefaultQueueCallback(NULL);
5186 SetupInstallFromInfSectionW(NULL, hinf, section_ext, install_flags, driver_key, NULL,
5187 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5189 lstrcpyW(subsection, section_ext);
5190 lstrcatW(subsection, dothwW);
5192 SetupInstallFromInfSectionW(NULL, hinf, subsection, install_flags, device_key, NULL,
5193 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5195 lstrcpyW(subsection, section_ext);
5196 lstrcatW(subsection, dotservicesW);
5197 SetupInstallServicesFromInfSectionW(hinf, subsection, 0);
5199 svc_name[0] = 0;
5200 if (SetupFindFirstLineW(hinf, subsection, addserviceW, &ctx))
5204 INT flags;
5206 if (SetupGetIntField(&ctx, 2, &flags) && (flags & SPSVCINST_ASSOCSERVICE))
5208 if (SetupGetStringFieldW(&ctx, 1, svc_name, ARRAY_SIZE(svc_name), NULL) && svc_name[0])
5209 RegSetValueExW(device->key, Service, 0, REG_SZ, (BYTE *)svc_name, lstrlenW(svc_name) * sizeof(WCHAR));
5210 break;
5212 } while (SetupFindNextMatchLineW(&ctx, addserviceW, &ctx));
5215 SetupTermDefaultQueueCallback(callback_ctx);
5216 SetupCloseInfFile(hinf);
5218 SetupCopyOEMInfW(driver->inf_path, NULL, SPOST_NONE, 0, inf_path, ARRAY_SIZE(inf_path), NULL, &filepart);
5219 TRACE("Copied INF file %s to %s.\n", debugstr_w(driver->inf_path), debugstr_w(inf_path));
5221 RegSetValueExW(driver_key, infpathW, 0, REG_SZ, (BYTE *)filepart, lstrlenW(filepart) * sizeof(WCHAR));
5222 RegSetValueExW(driver_key, infsectionW, 0, REG_SZ, (BYTE *)driver->section, lstrlenW(driver->section) * sizeof(WCHAR));
5223 if (extptr)
5224 RegSetValueExW(driver_key, infsectionextW, 0, REG_SZ, (BYTE *)extptr, lstrlenW(extptr) * sizeof(WCHAR));
5226 RegCloseKey(device_key);
5227 RegCloseKey(driver_key);
5229 if (!wcsnicmp(device->instanceId, rootW, lstrlenW(rootW)) && svc_name[0]
5230 && (manager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT)))
5232 if ((service = OpenServiceW(manager, svc_name, SERVICE_START | SERVICE_USER_DEFINED_CONTROL)))
5234 SERVICE_STATUS status;
5236 if (!StartServiceW(service, 0, NULL) && GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5238 ERR("Failed to start service %s for device %s, error %u.\n",
5239 debugstr_w(svc_name), debugstr_w(device->instanceId), GetLastError());
5241 if (!ControlService(service, SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES, &status))
5243 ERR("Failed to control service %s for device %s, error %u.\n",
5244 debugstr_w(svc_name), debugstr_w(device->instanceId), GetLastError());
5246 CloseServiceHandle(service);
5248 else
5249 ERR("Failed to open service %s for device %s.\n", debugstr_w(svc_name), debugstr_w(device->instanceId));
5250 CloseServiceHandle(manager);
5253 return TRUE;