opengl32: Preserve the remainder of the version string when limiting the version...
[wine.git] / dlls / setupapi / devinst.c
blob2a8820ba07f7438d7fa0dac084e6887a4ea22645
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/list.h"
36 #include "cfgmgr32.h"
37 #include "winioctl.h"
38 #include "rpc.h"
39 #include "rpcdce.h"
40 #include "cguid.h"
42 #include "setupapi_private.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
47 /* Unicode constants */
48 static const WCHAR Chicago[] = {'$','C','h','i','c','a','g','o','$',0};
49 static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0};
50 static const WCHAR Class[] = {'C','l','a','s','s',0};
51 static const WCHAR ClassInstall32[] = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
52 static const WCHAR NoDisplayClass[] = {'N','o','D','i','s','p','l','a','y','C','l','a','s','s',0};
53 static const WCHAR NoInstallClass[] = {'N','o','I','n','s','t','a','l','l','C','l','a','s','s',0};
54 static const WCHAR NoUseClass[] = {'N','o','U','s','e','C','l','a','s','s',0};
55 static const WCHAR NtExtension[] = {'.','N','T',0};
56 #ifdef __i386__
57 static const WCHAR NtPlatformExtension[] = {'.','N','T','x','8','6',0};
58 #elif defined(__x86_64__)
59 static const WCHAR NtPlatformExtension[] = {'.','N','T','a','m','d','6','4',0};
60 #elif defined(__arm__)
61 static const WCHAR NtPlatformExtension[] = {'.','N','T','a','r','m',0};
62 #elif defined(__aarch64__)
63 static const WCHAR NtPlatformExtension[] = {'.','N','T','a','r','m','6','4',0};
64 #endif
65 static const WCHAR Signature[] = {'S','i','g','n','a','t','u','r','e',0};
66 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
67 static const WCHAR WinExtension[] = {'.','W','i','n',0};
68 static const WCHAR WindowsNT[] = {'$','W','i','n','d','o','w','s',' ','N','T','$',0};
70 /* Registry key and value names */
71 static const WCHAR ControlClass[] = {'S','y','s','t','e','m','\\',
72 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
73 'C','o','n','t','r','o','l','\\',
74 'C','l','a','s','s',0};
76 static const WCHAR DeviceClasses[] = {'S','y','s','t','e','m','\\',
77 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
78 'C','o','n','t','r','o','l','\\',
79 'D','e','v','i','c','e','C','l','a','s','s','e','s',0};
80 static const WCHAR Enum[] = {'S','y','s','t','e','m','\\',
81 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
82 'E','n','u','m',0};
83 static const WCHAR DeviceDesc[] = {'D','e','v','i','c','e','D','e','s','c',0};
84 static const WCHAR DeviceInstance[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
85 static const WCHAR DeviceParameters[] = {'D','e','v','i','c','e',' ','P','a','r','a','m','e','t','e','r','s',0};
86 static const WCHAR HardwareId[] = {'H','a','r','d','w','a','r','e','I','D',0};
87 static const WCHAR CompatibleIDs[] = {'C','o','m','p','a','t','i','b','l','e','I','d','s',0};
88 static const WCHAR Service[] = {'S','e','r','v','i','c','e',0};
89 static const WCHAR Driver[] = {'D','r','i','v','e','r',0};
90 static const WCHAR ConfigFlags[] = {'C','o','n','f','i','g','F','l','a','g','s',0};
91 static const WCHAR Mfg[] = {'M','f','g',0};
92 static const WCHAR FriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
93 static const WCHAR LocationInformation[] = {'L','o','c','a','t','i','o','n','I','n','f','o','r','m','a','t','i','o','n',0};
94 static const WCHAR Capabilities[] = {'C','a','p','a','b','i','l','i','t','i','e','s',0};
95 static const WCHAR UINumber[] = {'U','I','N','u','m','b','e','r',0};
96 static const WCHAR UpperFilters[] = {'U','p','p','e','r','F','i','l','t','e','r','s',0};
97 static const WCHAR LowerFilters[] = {'L','o','w','e','r','F','i','l','t','e','r','s',0};
98 static const WCHAR ContainerId[] = {'C','o','n','t','a','i','n','e','r','I','d',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 DWORD rank;
113 WCHAR inf_path[MAX_PATH];
114 WCHAR manufacturer[LINE_LEN];
115 WCHAR mfg_key[LINE_LEN];
116 WCHAR description[LINE_LEN];
117 WCHAR section[LINE_LEN];
120 /* is used to identify if a DeviceInfoSet pointer is
121 valid or not */
122 #define SETUP_DEVICE_INFO_SET_MAGIC 0xd00ff056
124 struct DeviceInfoSet
126 DWORD magic; /* if is equal to SETUP_DEVICE_INFO_SET_MAGIC struct is okay */
127 GUID ClassGuid;
128 HWND hwndParent;
129 struct list devices;
132 struct device
134 struct DeviceInfoSet *set;
135 HKEY key;
136 BOOL phantom;
137 WCHAR *instanceId;
138 struct list interfaces;
139 GUID class;
140 DEVINST devnode;
141 struct list entry;
142 BOOL removed;
143 SP_DEVINSTALL_PARAMS_W params;
144 struct driver *drivers;
145 unsigned int driver_count;
146 struct driver *selected_driver;
149 struct device_iface
151 WCHAR *refstr;
152 WCHAR *symlink;
153 struct device *device;
154 GUID class;
155 DWORD flags;
156 HKEY class_key;
157 HKEY refstr_key;
158 struct list entry;
161 static struct DeviceInfoSet *get_device_set(HDEVINFO devinfo)
163 struct DeviceInfoSet *set = devinfo;
165 if (!devinfo || devinfo == INVALID_HANDLE_VALUE || set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
167 SetLastError(ERROR_INVALID_HANDLE);
168 return NULL;
171 return set;
174 static struct device *get_device(HDEVINFO devinfo, const SP_DEVINFO_DATA *data)
176 struct DeviceInfoSet *set;
177 struct device *device;
179 if (!(set = get_device_set(devinfo)))
180 return FALSE;
182 if (!data || data->cbSize != sizeof(*data) || !data->Reserved)
184 SetLastError(ERROR_INVALID_PARAMETER);
185 return NULL;
188 device = (struct device *)data->Reserved;
190 if (device->set != set)
192 SetLastError(ERROR_INVALID_PARAMETER);
193 return NULL;
196 if (device->removed)
198 SetLastError(ERROR_NO_SUCH_DEVINST);
199 return NULL;
202 return device;
205 static struct device_iface *get_device_iface(HDEVINFO devinfo, const SP_DEVICE_INTERFACE_DATA *data)
207 if (!get_device_set(devinfo))
208 return FALSE;
210 if (!data || data->cbSize != sizeof(*data) || !data->Reserved)
212 SetLastError(ERROR_INVALID_PARAMETER);
213 return NULL;
216 return (struct device_iface *)data->Reserved;
219 static inline void copy_device_data(SP_DEVINFO_DATA *data, const struct device *device)
221 data->ClassGuid = device->class;
222 data->DevInst = device->devnode;
223 data->Reserved = (ULONG_PTR)device;
226 static inline void copy_device_iface_data(SP_DEVICE_INTERFACE_DATA *data,
227 const struct device_iface *iface)
229 data->InterfaceClassGuid = iface->class;
230 data->Flags = iface->flags;
231 data->Reserved = (ULONG_PTR)iface;
234 static struct device **devnode_table;
235 static unsigned int devnode_table_size;
237 static DEVINST alloc_devnode(struct device *device)
239 unsigned int i;
241 for (i = 0; i < devnode_table_size; ++i)
243 if (!devnode_table[i])
244 break;
247 if (i == devnode_table_size)
249 if (devnode_table)
251 devnode_table = realloc(devnode_table, devnode_table_size * 2 * sizeof(*devnode_table));
252 memset(devnode_table + devnode_table_size, 0, devnode_table_size * sizeof(*devnode_table));
253 devnode_table_size *= 2;
255 else
257 devnode_table_size = 256;
258 devnode_table = calloc(devnode_table_size, sizeof(*devnode_table));
262 devnode_table[i] = device;
263 return i;
266 static void free_devnode(DEVINST devnode)
268 devnode_table[devnode] = NULL;
271 static struct device *get_devnode_device(DEVINST devnode)
273 if (devnode < devnode_table_size)
274 return devnode_table[devnode];
276 WARN("device node %lu not found\n", devnode);
277 return NULL;
280 static void SETUPDI_GuidToString(const GUID *guid, LPWSTR guidStr)
282 static const WCHAR fmt[] = {'{','%','0','8','X','-','%','0','4','X','-',
283 '%','0','4','X','-','%','0','2','X','%','0','2','X','-','%','0','2',
284 'X','%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X','%',
285 '0','2','X','}',0};
287 swprintf(guidStr, 39, fmt, guid->Data1, guid->Data2, guid->Data3,
288 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
289 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
292 static WCHAR *get_iface_key_path(struct device_iface *iface)
294 static const WCHAR slashW[] = {'\\',0};
295 WCHAR *path, *ptr;
296 size_t len = lstrlenW(DeviceClasses) + 1 + 38 + 1 + lstrlenW(iface->symlink);
298 if (!(path = malloc((len + 1) * sizeof(WCHAR))))
300 SetLastError(ERROR_OUTOFMEMORY);
301 return NULL;
304 lstrcpyW(path, DeviceClasses);
305 lstrcatW(path, slashW);
306 SETUPDI_GuidToString(&iface->class, path + lstrlenW(path));
307 lstrcatW(path, slashW);
308 ptr = path + lstrlenW(path);
309 lstrcatW(path, iface->symlink);
310 if (lstrlenW(iface->symlink) > 3)
311 ptr[0] = ptr[1] = ptr[3] = '#';
313 ptr = wcschr(ptr, '\\');
314 if (ptr) *ptr = 0;
316 return path;
319 static WCHAR *get_refstr_key_path(struct device_iface *iface)
321 static const WCHAR hashW[] = {'#',0};
322 static const WCHAR slashW[] = {'\\',0};
323 WCHAR *path, *ptr;
324 size_t len = lstrlenW(DeviceClasses) + 1 + 38 + 1 + lstrlenW(iface->symlink) + 1 + 1;
326 if (iface->refstr)
327 len += lstrlenW(iface->refstr);
329 if (!(path = malloc((len + 1) * sizeof(WCHAR))))
331 SetLastError(ERROR_OUTOFMEMORY);
332 return NULL;
335 lstrcpyW(path, DeviceClasses);
336 lstrcatW(path, slashW);
337 SETUPDI_GuidToString(&iface->class, path + lstrlenW(path));
338 lstrcatW(path, slashW);
339 ptr = path + lstrlenW(path);
340 lstrcatW(path, iface->symlink);
341 if (lstrlenW(iface->symlink) > 3)
342 ptr[0] = ptr[1] = ptr[3] = '#';
344 ptr = wcschr(ptr, '\\');
345 if (ptr) *ptr = 0;
347 lstrcatW(path, slashW);
348 lstrcatW(path, hashW);
350 if (iface->refstr)
351 lstrcatW(path, iface->refstr);
353 return path;
356 static BOOL is_valid_property_type(DEVPROPTYPE prop_type)
358 DWORD type = prop_type & DEVPROP_MASK_TYPE;
359 DWORD typemod = prop_type & DEVPROP_MASK_TYPEMOD;
361 if (type > MAX_DEVPROP_TYPE)
362 return FALSE;
363 if (typemod > MAX_DEVPROP_TYPEMOD)
364 return FALSE;
366 if (typemod == DEVPROP_TYPEMOD_ARRAY
367 && (type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL || type == DEVPROP_TYPE_STRING
368 || type == DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING))
369 return FALSE;
371 if (typemod == DEVPROP_TYPEMOD_LIST
372 && !(type == DEVPROP_TYPE_STRING || type == DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING))
373 return FALSE;
375 return TRUE;
378 static LPWSTR SETUPDI_CreateSymbolicLinkPath(LPCWSTR instanceId,
379 const GUID *InterfaceClassGuid, LPCWSTR ReferenceString)
381 static const WCHAR fmt[] = {'\\','\\','?','\\','%','s','#','%','s',0};
382 WCHAR guidStr[39];
383 DWORD len;
384 LPWSTR ret;
386 SETUPDI_GuidToString(InterfaceClassGuid, guidStr);
387 /* omit length of format specifiers, but include NULL terminator: */
388 len = lstrlenW(fmt) - 4 + 1;
389 len += lstrlenW(instanceId) + lstrlenW(guidStr);
390 if (ReferenceString && *ReferenceString)
392 /* space for a hash between string and reference string: */
393 len += lstrlenW(ReferenceString) + 1;
395 ret = malloc(len * sizeof(WCHAR));
396 if (ret)
398 int printed = swprintf(ret, len, fmt, instanceId, guidStr);
399 LPWSTR ptr;
401 /* replace '\\' with '#' after the "\\\\?\\" beginning */
402 for (ptr = wcschr(ret + 4, '\\'); ptr; ptr = wcschr(ptr + 1, '\\'))
403 *ptr = '#';
404 if (ReferenceString && *ReferenceString)
406 ret[printed] = '\\';
407 lstrcpyW(ret + printed + 1, ReferenceString);
411 CharLowerW(ret);
413 return ret;
416 static BOOL is_linked(HKEY key)
418 DWORD linked, type, size;
419 HKEY control_key;
420 BOOL ret = FALSE;
422 if (!RegOpenKeyW(key, Control, &control_key))
424 size = sizeof(DWORD);
425 if (!RegQueryValueExW(control_key, Linked, NULL, &type, (BYTE *)&linked, &size)
426 && type == REG_DWORD && linked)
427 ret = TRUE;
429 RegCloseKey(control_key);
432 return ret;
435 static struct device_iface *SETUPDI_CreateDeviceInterface(struct device *device,
436 const GUID *class, const WCHAR *refstr)
438 struct device_iface *iface = NULL;
439 WCHAR *refstr2 = NULL, *symlink = NULL, *path = NULL;
440 HKEY key;
441 LONG ret;
443 TRACE("%p %s %s\n", device, debugstr_guid(class), debugstr_w(refstr));
445 /* check if it already exists */
446 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
448 if (IsEqualGUID(&iface->class, class) && !lstrcmpiW(iface->refstr, refstr))
449 return iface;
452 iface = malloc(sizeof(*iface));
453 symlink = SETUPDI_CreateSymbolicLinkPath(device->instanceId, class, refstr);
455 if (!iface || !symlink)
457 SetLastError(ERROR_OUTOFMEMORY);
458 goto err;
461 if (refstr && !(refstr2 = wcsdup(refstr)))
463 SetLastError(ERROR_OUTOFMEMORY);
464 goto err;
466 iface->refstr = refstr2;
467 iface->symlink = symlink;
468 iface->device = device;
469 iface->class = *class;
470 iface->flags = 0;
472 if (!(path = get_iface_key_path(iface)))
474 SetLastError(ERROR_OUTOFMEMORY);
475 goto err;
478 if ((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, path, &key)))
480 SetLastError(ret);
481 goto err;
483 RegSetValueExW(key, DeviceInstance, 0, REG_SZ, (BYTE *)device->instanceId,
484 lstrlenW(device->instanceId) * sizeof(WCHAR));
485 free(path);
487 iface->class_key = key;
489 if (!(path = get_refstr_key_path(iface)))
491 SetLastError(ERROR_OUTOFMEMORY);
492 goto err;
495 if ((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, path, &key)))
497 SetLastError(ret);
498 goto err;
500 RegSetValueExW(key, SymbolicLink, 0, REG_SZ, (BYTE *)iface->symlink,
501 lstrlenW(iface->symlink) * sizeof(WCHAR));
503 if (is_linked(key))
504 iface->flags |= SPINT_ACTIVE;
506 free(path);
508 iface->refstr_key = key;
510 list_add_tail(&device->interfaces, &iface->entry);
511 return iface;
513 err:
514 free(iface);
515 free(refstr2);
516 free(symlink);
517 free(path);
518 return NULL;
521 static BOOL SETUPDI_SetInterfaceSymbolicLink(struct device_iface *iface,
522 const WCHAR *symlink)
524 free(iface->symlink);
525 if ((iface->symlink = wcsdup(symlink)))
526 return TRUE;
527 return FALSE;
530 static HKEY SETUPDI_CreateDevKey(struct device *device)
532 HKEY enumKey, key = INVALID_HANDLE_VALUE;
533 LONG l;
535 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_ALL_ACCESS,
536 NULL, &enumKey, NULL);
537 if (!l)
539 RegCreateKeyExW(enumKey, device->instanceId, 0, NULL, 0,
540 KEY_READ | KEY_WRITE, NULL, &key, NULL);
541 RegCloseKey(enumKey);
543 return key;
546 static LONG open_driver_key(struct device *device, REGSAM access, HKEY *key)
548 HKEY class_key;
549 WCHAR path[50];
550 DWORD size = sizeof(path);
551 LONG l;
553 if ((l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, ControlClass, 0, NULL, 0,
554 KEY_CREATE_SUB_KEY, NULL, &class_key, NULL)))
556 ERR("Failed to open driver class root key, error %lu.\n", l);
557 return l;
560 if (!(l = RegGetValueW(device->key, NULL, Driver, RRF_RT_REG_SZ, NULL, path, &size)))
562 if (!(l = RegOpenKeyExW(class_key, path, 0, access, key)))
564 RegCloseKey(class_key);
565 return l;
567 TRACE("Failed to open driver key, error %lu.\n", l);
570 RegCloseKey(class_key);
571 return l;
574 static LONG create_driver_key(struct device *device, HKEY *key)
576 static const WCHAR formatW[] = {'%','0','4','u',0};
577 static const WCHAR slash[] = { '\\',0 };
578 unsigned int i = 0;
579 WCHAR path[50];
580 HKEY class_key;
581 DWORD dispos;
582 LONG l;
584 if (!open_driver_key(device, KEY_READ | KEY_WRITE, key))
585 return ERROR_SUCCESS;
587 if ((l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, ControlClass, 0, NULL, 0,
588 KEY_CREATE_SUB_KEY, NULL, &class_key, NULL)))
590 ERR("Failed to open driver class root key, error %lu.\n", l);
591 return l;
594 SETUPDI_GuidToString(&device->class, path);
595 lstrcatW(path, slash);
596 /* Allocate a new driver key, by finding the first integer value that's not
597 * already taken. */
598 for (;;)
600 swprintf(path + 39, ARRAY_SIZE(path) - 39, formatW, i++);
601 if ((l = RegCreateKeyExW(class_key, path, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, key, &dispos)))
602 break;
603 else if (dispos == REG_CREATED_NEW_KEY)
605 RegSetValueExW(device->key, Driver, 0, REG_SZ, (BYTE *)path, lstrlenW(path) * sizeof(WCHAR));
606 RegCloseKey(class_key);
607 return ERROR_SUCCESS;
609 RegCloseKey(*key);
611 ERR("Failed to create driver key, error %lu.\n", l);
612 RegCloseKey(class_key);
613 return l;
616 static LONG delete_driver_key(struct device *device)
618 HKEY key;
619 LONG l;
621 if (!(l = open_driver_key(device, KEY_READ | KEY_WRITE, &key)))
623 l = RegDeleteKeyW(key, emptyW);
624 RegCloseKey(key);
627 return l;
630 struct PropertyMapEntry
632 DWORD regType;
633 LPCSTR nameA;
634 LPCWSTR nameW;
637 static const struct PropertyMapEntry PropertyMap[] = {
638 { REG_SZ, "DeviceDesc", DeviceDesc },
639 { REG_MULTI_SZ, "HardwareId", HardwareId },
640 { REG_MULTI_SZ, "CompatibleIDs", CompatibleIDs },
641 { 0, NULL, NULL }, /* SPDRP_UNUSED0 */
642 { REG_SZ, "Service", Service },
643 { 0, NULL, NULL }, /* SPDRP_UNUSED1 */
644 { 0, NULL, NULL }, /* SPDRP_UNUSED2 */
645 { REG_SZ, "Class", Class },
646 { REG_SZ, "ClassGUID", ClassGUID },
647 { REG_SZ, "Driver", Driver },
648 { REG_DWORD, "ConfigFlags", ConfigFlags },
649 { REG_SZ, "Mfg", Mfg },
650 { REG_SZ, "FriendlyName", FriendlyName },
651 { REG_SZ, "LocationInformation", LocationInformation },
652 { 0, NULL, NULL }, /* SPDRP_PHYSICAL_DEVICE_OBJECT_NAME */
653 { REG_DWORD, "Capabilities", Capabilities },
654 { REG_DWORD, "UINumber", UINumber },
655 { REG_MULTI_SZ, "UpperFilters", UpperFilters },
656 { REG_MULTI_SZ, "LowerFilters", LowerFilters },
657 [SPDRP_BASE_CONTAINERID] = { REG_SZ, "ContainerId", ContainerId },
660 static BOOL SETUPDI_SetDeviceRegistryPropertyW(struct device *device,
661 DWORD prop, const BYTE *buffer, DWORD size)
663 if (prop < ARRAY_SIZE(PropertyMap) && PropertyMap[prop].nameW)
665 LONG ret = RegSetValueExW(device->key, PropertyMap[prop].nameW, 0,
666 PropertyMap[prop].regType, buffer, size);
667 if (!ret)
668 return TRUE;
670 SetLastError(ret);
672 return FALSE;
675 static void remove_device_iface(struct device_iface *iface)
677 RegDeleteTreeW(iface->refstr_key, NULL);
678 RegDeleteKeyW(iface->refstr_key, emptyW);
679 RegCloseKey(iface->refstr_key);
680 iface->refstr_key = NULL;
681 /* Also remove the class key if it's empty. */
682 RegDeleteKeyW(iface->class_key, emptyW);
683 RegCloseKey(iface->class_key);
684 iface->class_key = NULL;
685 iface->flags |= SPINT_REMOVED;
688 static void delete_device_iface(struct device_iface *iface)
690 list_remove(&iface->entry);
691 RegCloseKey(iface->refstr_key);
692 RegCloseKey(iface->class_key);
693 free(iface->refstr);
694 free(iface->symlink);
695 free(iface);
698 /* remove all interfaces associated with the device, including those not
699 * enumerated in the set */
700 static void remove_all_device_ifaces(struct device *device)
702 HKEY classes_key;
703 DWORD i, len;
704 LONG ret;
706 if ((ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, DeviceClasses, 0, KEY_READ, &classes_key)))
708 WARN("Failed to open classes key, error %lu.\n", ret);
709 return;
712 for (i = 0; ; ++i)
714 WCHAR class_name[40];
715 HKEY class_key;
716 DWORD j;
718 len = ARRAY_SIZE(class_name);
719 if ((ret = RegEnumKeyExW(classes_key, i, class_name, &len, NULL, NULL, NULL, NULL)))
721 if (ret != ERROR_NO_MORE_ITEMS) ERR("Failed to enumerate classes, error %lu.\n", ret);
722 break;
725 if ((ret = RegOpenKeyExW(classes_key, class_name, 0, KEY_READ, &class_key)))
727 ERR("Failed to open class %s, error %lu.\n", debugstr_w(class_name), ret);
728 continue;
731 for (j = 0; ; ++j)
733 WCHAR iface_name[MAX_DEVICE_ID_LEN + 39], device_name[MAX_DEVICE_ID_LEN];
734 HKEY iface_key;
736 len = ARRAY_SIZE(iface_name);
737 if ((ret = RegEnumKeyExW(class_key, j, iface_name, &len, NULL, NULL, NULL, NULL)))
739 if (ret != ERROR_NO_MORE_ITEMS) ERR("Failed to enumerate interfaces, error %lu.\n", ret);
740 break;
743 if ((ret = RegOpenKeyExW(class_key, iface_name, 0, KEY_ALL_ACCESS, &iface_key)))
745 ERR("Failed to open interface %s, error %lu.\n", debugstr_w(iface_name), ret);
746 continue;
749 len = sizeof(device_name);
750 if ((ret = RegQueryValueExW(iface_key, L"DeviceInstance", NULL, NULL, (BYTE *)device_name, &len)))
752 ERR("Failed to query device instance, error %lu.\n", ret);
753 RegCloseKey(iface_key);
754 continue;
757 if (!wcsicmp(device_name, device->instanceId))
759 if ((ret = RegDeleteTreeW(iface_key, NULL)))
760 ERR("Failed to delete interface %s subkeys, error %lu.\n", debugstr_w(iface_name), ret);
761 if ((ret = RegDeleteKeyW(iface_key, L"")))
762 ERR("Failed to delete interface %s, error %lu.\n", debugstr_w(iface_name), ret);
765 RegCloseKey(iface_key);
767 RegCloseKey(class_key);
770 RegCloseKey(classes_key);
773 static void remove_device(struct device *device)
775 WCHAR id[MAX_DEVICE_ID_LEN], *p;
776 struct device_iface *iface;
777 HKEY enum_key;
779 delete_driver_key(device);
781 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
783 remove_device_iface(iface);
786 RegDeleteTreeW(device->key, NULL);
787 RegDeleteKeyW(device->key, emptyW);
789 /* delete all empty parents of the key */
790 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, 0, &enum_key))
792 lstrcpyW(id, device->instanceId);
794 while ((p = wcsrchr(id, '\\')))
796 *p = 0;
797 RegDeleteKeyW(enum_key, id);
800 RegCloseKey(enum_key);
803 RegCloseKey(device->key);
804 device->key = NULL;
805 device->removed = TRUE;
808 static void delete_device(struct device *device)
810 struct device_iface *iface, *next;
811 SP_DEVINFO_DATA device_data;
813 device_data.cbSize = sizeof(device_data);
814 copy_device_data(&device_data, device);
815 SetupDiCallClassInstaller(DIF_DESTROYPRIVATEDATA, device->set, &device_data);
817 if (device->phantom)
819 remove_device(device);
820 remove_all_device_ifaces(device);
823 RegCloseKey(device->key);
824 free(device->instanceId);
825 free(device->drivers);
827 LIST_FOR_EACH_ENTRY_SAFE(iface, next, &device->interfaces,
828 struct device_iface, entry)
830 delete_device_iface(iface);
832 free_devnode(device->devnode);
833 list_remove(&device->entry);
834 free(device);
837 /* Create a new device, or return a device already in the set. */
838 static struct device *create_device(struct DeviceInfoSet *set,
839 const GUID *class, const WCHAR *instanceid, BOOL phantom)
841 const DWORD one = 1;
842 struct device *device;
843 WCHAR guidstr[MAX_GUID_STRING_LEN];
844 WCHAR class_name[MAX_CLASS_NAME_LEN];
845 DWORD size;
847 TRACE("%p, %s, %s, %d\n", set, debugstr_guid(class),
848 debugstr_w(instanceid), phantom);
850 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
852 if (!wcsicmp(instanceid, device->instanceId))
854 TRACE("Found device %p already in set.\n", device);
855 return device;
859 if (!(device = calloc(1, sizeof(*device))))
861 SetLastError(ERROR_OUTOFMEMORY);
862 return NULL;
865 if (!(device->instanceId = wcsdup(instanceid)))
867 SetLastError(ERROR_OUTOFMEMORY);
868 free(device);
869 return NULL;
872 wcsupr(device->instanceId);
873 device->set = set;
874 device->key = SETUPDI_CreateDevKey(device);
875 device->phantom = phantom;
876 list_init(&device->interfaces);
877 device->class = *class;
878 device->devnode = alloc_devnode(device);
879 device->removed = FALSE;
880 list_add_tail(&set->devices, &device->entry);
881 device->params.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
883 if (phantom)
884 RegSetValueExW(device->key, Phantom, 0, REG_DWORD, (const BYTE *)&one, sizeof(one));
886 SETUPDI_GuidToString(class, guidstr);
887 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_CLASSGUID,
888 (const BYTE *)guidstr, sizeof(guidstr));
890 if (SetupDiClassNameFromGuidW(class, class_name, ARRAY_SIZE(class_name), NULL))
892 size = (lstrlenW(class_name) + 1) * sizeof(WCHAR);
893 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_CLASS, (const BYTE *)class_name, size);
896 TRACE("Created new device %p.\n", device);
897 return device;
900 /***********************************************************************
901 * SetupDiBuildClassInfoList (SETUPAPI.@)
903 * Returns a list of setup class GUIDs that identify the classes
904 * that are installed on a local machine.
906 * PARAMS
907 * Flags [I] control exclusion of classes from the list.
908 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
909 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
910 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
912 * RETURNS
913 * Success: TRUE.
914 * Failure: FALSE.
916 BOOL WINAPI SetupDiBuildClassInfoList(
917 DWORD Flags,
918 LPGUID ClassGuidList,
919 DWORD ClassGuidListSize,
920 PDWORD RequiredSize)
922 TRACE("\n");
923 return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
924 ClassGuidListSize, RequiredSize,
925 NULL, NULL);
928 /***********************************************************************
929 * SetupDiBuildClassInfoListExA (SETUPAPI.@)
931 * Returns a list of setup class GUIDs that identify the classes
932 * that are installed on a local or remote machine.
934 * PARAMS
935 * Flags [I] control exclusion of classes from the list.
936 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
937 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
938 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
939 * MachineName [I] name of a remote machine.
940 * Reserved [I] must be NULL.
942 * RETURNS
943 * Success: TRUE.
944 * Failure: FALSE.
946 BOOL WINAPI SetupDiBuildClassInfoListExA(
947 DWORD Flags,
948 LPGUID ClassGuidList,
949 DWORD ClassGuidListSize,
950 PDWORD RequiredSize,
951 LPCSTR MachineName,
952 PVOID Reserved)
954 LPWSTR MachineNameW = NULL;
955 BOOL bResult;
957 TRACE("\n");
959 if (MachineName)
961 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
962 if (MachineNameW == NULL) return FALSE;
965 bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
966 ClassGuidListSize, RequiredSize,
967 MachineNameW, Reserved);
969 MyFree(MachineNameW);
971 return bResult;
974 /***********************************************************************
975 * SetupDiBuildClassInfoListExW (SETUPAPI.@)
977 * Returns a list of setup class GUIDs that identify the classes
978 * that are installed on a local or remote machine.
980 * PARAMS
981 * Flags [I] control exclusion of classes from the list.
982 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
983 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
984 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
985 * MachineName [I] name of a remote machine.
986 * Reserved [I] must be NULL.
988 * RETURNS
989 * Success: TRUE.
990 * Failure: FALSE.
992 BOOL WINAPI SetupDiBuildClassInfoListExW(
993 DWORD Flags,
994 LPGUID ClassGuidList,
995 DWORD ClassGuidListSize,
996 PDWORD RequiredSize,
997 LPCWSTR MachineName,
998 PVOID Reserved)
1000 WCHAR szKeyName[40];
1001 HKEY hClassesKey;
1002 HKEY hClassKey;
1003 DWORD dwLength;
1004 DWORD dwIndex;
1005 LONG lError;
1006 DWORD dwGuidListIndex = 0;
1008 TRACE("\n");
1010 if (RequiredSize != NULL)
1011 *RequiredSize = 0;
1013 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
1014 KEY_ALL_ACCESS,
1015 DIOCR_INSTALLER,
1016 MachineName,
1017 Reserved);
1018 if (hClassesKey == INVALID_HANDLE_VALUE)
1020 return FALSE;
1023 for (dwIndex = 0; ; dwIndex++)
1025 dwLength = 40;
1026 lError = RegEnumKeyExW(hClassesKey,
1027 dwIndex,
1028 szKeyName,
1029 &dwLength,
1030 NULL,
1031 NULL,
1032 NULL,
1033 NULL);
1034 TRACE("RegEnumKeyExW() returns %ld\n", lError);
1035 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
1037 TRACE("Key name: %p\n", szKeyName);
1039 if (RegOpenKeyExW(hClassesKey,
1040 szKeyName,
1042 KEY_ALL_ACCESS,
1043 &hClassKey))
1045 RegCloseKey(hClassesKey);
1046 return FALSE;
1049 if (!RegQueryValueExW(hClassKey,
1050 NoUseClass,
1051 NULL,
1052 NULL,
1053 NULL,
1054 NULL))
1056 TRACE("'NoUseClass' value found!\n");
1057 RegCloseKey(hClassKey);
1058 continue;
1061 if ((Flags & DIBCI_NOINSTALLCLASS) &&
1062 (!RegQueryValueExW(hClassKey,
1063 NoInstallClass,
1064 NULL,
1065 NULL,
1066 NULL,
1067 NULL)))
1069 TRACE("'NoInstallClass' value found!\n");
1070 RegCloseKey(hClassKey);
1071 continue;
1074 if ((Flags & DIBCI_NODISPLAYCLASS) &&
1075 (!RegQueryValueExW(hClassKey,
1076 NoDisplayClass,
1077 NULL,
1078 NULL,
1079 NULL,
1080 NULL)))
1082 TRACE("'NoDisplayClass' value found!\n");
1083 RegCloseKey(hClassKey);
1084 continue;
1087 RegCloseKey(hClassKey);
1089 TRACE("Guid: %p\n", szKeyName);
1090 if (dwGuidListIndex < ClassGuidListSize)
1092 if (szKeyName[0] == '{' && szKeyName[37] == '}')
1094 szKeyName[37] = 0;
1096 TRACE("Guid: %p\n", &szKeyName[1]);
1098 UuidFromStringW(&szKeyName[1],
1099 &ClassGuidList[dwGuidListIndex]);
1102 dwGuidListIndex++;
1105 if (lError != ERROR_SUCCESS)
1106 break;
1109 RegCloseKey(hClassesKey);
1111 if (RequiredSize != NULL)
1112 *RequiredSize = dwGuidListIndex;
1114 if (ClassGuidListSize < dwGuidListIndex)
1116 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1117 return FALSE;
1120 return TRUE;
1123 /***********************************************************************
1124 * SetupDiClassGuidsFromNameA (SETUPAPI.@)
1126 BOOL WINAPI SetupDiClassGuidsFromNameA(
1127 LPCSTR ClassName,
1128 LPGUID ClassGuidList,
1129 DWORD ClassGuidListSize,
1130 PDWORD RequiredSize)
1132 return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
1133 ClassGuidListSize, RequiredSize,
1134 NULL, NULL);
1137 /***********************************************************************
1138 * SetupDiClassGuidsFromNameW (SETUPAPI.@)
1140 BOOL WINAPI SetupDiClassGuidsFromNameW(
1141 LPCWSTR ClassName,
1142 LPGUID ClassGuidList,
1143 DWORD ClassGuidListSize,
1144 PDWORD RequiredSize)
1146 return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
1147 ClassGuidListSize, RequiredSize,
1148 NULL, NULL);
1151 /***********************************************************************
1152 * SetupDiClassGuidsFromNameExA (SETUPAPI.@)
1154 BOOL WINAPI SetupDiClassGuidsFromNameExA(
1155 LPCSTR ClassName,
1156 LPGUID ClassGuidList,
1157 DWORD ClassGuidListSize,
1158 PDWORD RequiredSize,
1159 LPCSTR MachineName,
1160 PVOID Reserved)
1162 LPWSTR ClassNameW = NULL;
1163 LPWSTR MachineNameW = NULL;
1164 BOOL bResult;
1166 ClassNameW = MultiByteToUnicode(ClassName, CP_ACP);
1167 if (ClassNameW == NULL)
1168 return FALSE;
1170 if (MachineName)
1172 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1173 if (MachineNameW == NULL)
1175 MyFree(ClassNameW);
1176 return FALSE;
1180 bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
1181 ClassGuidListSize, RequiredSize,
1182 MachineNameW, Reserved);
1184 MyFree(MachineNameW);
1185 MyFree(ClassNameW);
1187 return bResult;
1190 /***********************************************************************
1191 * SetupDiClassGuidsFromNameExW (SETUPAPI.@)
1193 BOOL WINAPI SetupDiClassGuidsFromNameExW(
1194 LPCWSTR ClassName,
1195 LPGUID ClassGuidList,
1196 DWORD ClassGuidListSize,
1197 PDWORD RequiredSize,
1198 LPCWSTR MachineName,
1199 PVOID Reserved)
1201 WCHAR szKeyName[40];
1202 WCHAR szClassName[256];
1203 HKEY hClassesKey;
1204 HKEY hClassKey;
1205 DWORD dwLength;
1206 DWORD dwIndex;
1207 LONG lError;
1208 DWORD dwGuidListIndex = 0;
1210 if (RequiredSize != NULL)
1211 *RequiredSize = 0;
1213 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
1214 KEY_ALL_ACCESS,
1215 DIOCR_INSTALLER,
1216 MachineName,
1217 Reserved);
1218 if (hClassesKey == INVALID_HANDLE_VALUE)
1220 return FALSE;
1223 for (dwIndex = 0; ; dwIndex++)
1225 dwLength = ARRAY_SIZE(szKeyName);
1226 lError = RegEnumKeyExW(hClassesKey,
1227 dwIndex,
1228 szKeyName,
1229 &dwLength,
1230 NULL,
1231 NULL,
1232 NULL,
1233 NULL);
1234 TRACE("RegEnumKeyExW() returns %ld\n", lError);
1235 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
1237 TRACE("Key name: %p\n", szKeyName);
1239 if (RegOpenKeyExW(hClassesKey,
1240 szKeyName,
1242 KEY_ALL_ACCESS,
1243 &hClassKey))
1245 RegCloseKey(hClassesKey);
1246 return FALSE;
1249 dwLength = sizeof(szClassName);
1250 if (!RegQueryValueExW(hClassKey,
1251 Class,
1252 NULL,
1253 NULL,
1254 (LPBYTE)szClassName,
1255 &dwLength))
1257 TRACE("Class name: %p\n", szClassName);
1259 if (wcsicmp(szClassName, ClassName) == 0)
1261 TRACE("Found matching class name\n");
1263 TRACE("Guid: %p\n", szKeyName);
1264 if (dwGuidListIndex < ClassGuidListSize)
1266 if (szKeyName[0] == '{' && szKeyName[37] == '}')
1268 szKeyName[37] = 0;
1270 TRACE("Guid: %p\n", &szKeyName[1]);
1272 UuidFromStringW(&szKeyName[1],
1273 &ClassGuidList[dwGuidListIndex]);
1276 dwGuidListIndex++;
1280 RegCloseKey(hClassKey);
1283 if (lError != ERROR_SUCCESS)
1284 break;
1287 RegCloseKey(hClassesKey);
1289 if (RequiredSize != NULL)
1290 *RequiredSize = dwGuidListIndex;
1292 if (ClassGuidListSize < dwGuidListIndex)
1294 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1295 return FALSE;
1298 return TRUE;
1301 /***********************************************************************
1302 * SetupDiClassNameFromGuidA (SETUPAPI.@)
1304 BOOL WINAPI SetupDiClassNameFromGuidA(
1305 const GUID* ClassGuid,
1306 PSTR ClassName,
1307 DWORD ClassNameSize,
1308 PDWORD RequiredSize)
1310 return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
1311 ClassNameSize, RequiredSize,
1312 NULL, NULL);
1315 /***********************************************************************
1316 * SetupDiClassNameFromGuidW (SETUPAPI.@)
1318 BOOL WINAPI SetupDiClassNameFromGuidW(
1319 const GUID* ClassGuid,
1320 PWSTR ClassName,
1321 DWORD ClassNameSize,
1322 PDWORD RequiredSize)
1324 return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
1325 ClassNameSize, RequiredSize,
1326 NULL, NULL);
1329 /***********************************************************************
1330 * SetupDiClassNameFromGuidExA (SETUPAPI.@)
1332 BOOL WINAPI SetupDiClassNameFromGuidExA(
1333 const GUID* ClassGuid,
1334 PSTR ClassName,
1335 DWORD ClassNameSize,
1336 PDWORD RequiredSize,
1337 PCSTR MachineName,
1338 PVOID Reserved)
1340 WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
1341 LPWSTR MachineNameW = NULL;
1342 BOOL ret;
1344 if (MachineName)
1345 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1346 ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
1347 NULL, MachineNameW, Reserved);
1348 if (ret)
1350 int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
1351 ClassNameSize, NULL, NULL);
1353 if (!ClassNameSize && RequiredSize)
1354 *RequiredSize = len;
1356 MyFree(MachineNameW);
1357 return ret;
1360 /***********************************************************************
1361 * SetupDiClassNameFromGuidExW (SETUPAPI.@)
1363 BOOL WINAPI SetupDiClassNameFromGuidExW(
1364 const GUID* ClassGuid,
1365 PWSTR ClassName,
1366 DWORD ClassNameSize,
1367 PDWORD RequiredSize,
1368 PCWSTR MachineName,
1369 PVOID Reserved)
1371 HKEY hKey;
1372 DWORD dwLength;
1374 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
1375 KEY_ALL_ACCESS,
1376 DIOCR_INSTALLER,
1377 MachineName,
1378 Reserved);
1379 if (hKey == INVALID_HANDLE_VALUE)
1381 return FALSE;
1384 if (RequiredSize != NULL)
1386 dwLength = 0;
1387 if (RegQueryValueExW(hKey,
1388 Class,
1389 NULL,
1390 NULL,
1391 NULL,
1392 &dwLength))
1394 RegCloseKey(hKey);
1395 return FALSE;
1398 *RequiredSize = dwLength / sizeof(WCHAR);
1401 dwLength = ClassNameSize * sizeof(WCHAR);
1402 if (RegQueryValueExW(hKey,
1403 Class,
1404 NULL,
1405 NULL,
1406 (LPBYTE)ClassName,
1407 &dwLength))
1409 RegCloseKey(hKey);
1410 return FALSE;
1413 RegCloseKey(hKey);
1415 return TRUE;
1418 /***********************************************************************
1419 * SetupDiCreateDeviceInfoList (SETUPAPI.@)
1421 HDEVINFO WINAPI
1422 SetupDiCreateDeviceInfoList(const GUID *ClassGuid,
1423 HWND hwndParent)
1425 return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
1428 /***********************************************************************
1429 * SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
1431 HDEVINFO WINAPI
1432 SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
1433 HWND hwndParent,
1434 PCSTR MachineName,
1435 PVOID Reserved)
1437 LPWSTR MachineNameW = NULL;
1438 HDEVINFO hDevInfo;
1440 TRACE("\n");
1442 if (MachineName)
1444 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1445 if (MachineNameW == NULL)
1446 return INVALID_HANDLE_VALUE;
1449 hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
1450 MachineNameW, Reserved);
1452 MyFree(MachineNameW);
1454 return hDevInfo;
1457 /***********************************************************************
1458 * SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
1460 * Create an empty DeviceInfoSet list.
1462 * PARAMS
1463 * ClassGuid [I] if not NULL only devices with GUID ClassGuid are associated
1464 * with this list.
1465 * hwndParent [I] hwnd needed for interface related actions.
1466 * MachineName [I] name of machine to create empty DeviceInfoSet list, if NULL
1467 * local registry will be used.
1468 * Reserved [I] must be NULL
1470 * RETURNS
1471 * Success: empty list.
1472 * Failure: INVALID_HANDLE_VALUE.
1474 HDEVINFO WINAPI
1475 SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
1476 HWND hwndParent,
1477 PCWSTR MachineName,
1478 PVOID Reserved)
1480 struct DeviceInfoSet *list = NULL;
1481 DWORD size = sizeof(struct DeviceInfoSet);
1483 TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
1484 debugstr_w(MachineName), Reserved);
1486 if (MachineName && *MachineName)
1488 FIXME("remote support is not implemented\n");
1489 SetLastError(ERROR_INVALID_MACHINENAME);
1490 return INVALID_HANDLE_VALUE;
1493 if (Reserved != NULL)
1495 SetLastError(ERROR_INVALID_PARAMETER);
1496 return INVALID_HANDLE_VALUE;
1499 list = malloc(size);
1500 if (!list)
1502 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1503 return INVALID_HANDLE_VALUE;
1506 list->magic = SETUP_DEVICE_INFO_SET_MAGIC;
1507 list->hwndParent = hwndParent;
1508 memcpy(&list->ClassGuid,
1509 ClassGuid ? ClassGuid : &GUID_NULL,
1510 sizeof(list->ClassGuid));
1511 list_init(&list->devices);
1513 return list;
1516 /***********************************************************************
1517 * SetupDiCreateDevRegKeyA (SETUPAPI.@)
1519 HKEY WINAPI SetupDiCreateDevRegKeyA(
1520 HDEVINFO DeviceInfoSet,
1521 PSP_DEVINFO_DATA DeviceInfoData,
1522 DWORD Scope,
1523 DWORD HwProfile,
1524 DWORD KeyType,
1525 HINF InfHandle,
1526 PCSTR InfSectionName)
1528 PWSTR InfSectionNameW = NULL;
1529 HKEY key;
1531 TRACE("%p %p %ld %ld %ld %p %s\n", DeviceInfoSet, DeviceInfoData, Scope,
1532 HwProfile, KeyType, InfHandle, debugstr_a(InfSectionName));
1534 if (InfHandle)
1536 if (!InfSectionName)
1538 SetLastError(ERROR_INVALID_PARAMETER);
1539 return INVALID_HANDLE_VALUE;
1541 else
1543 InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
1544 if (InfSectionNameW == NULL) return INVALID_HANDLE_VALUE;
1547 key = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, Scope,
1548 HwProfile, KeyType, InfHandle, InfSectionNameW);
1549 MyFree(InfSectionNameW);
1550 return key;
1553 /***********************************************************************
1554 * SetupDiCreateDevRegKeyW (SETUPAPI.@)
1556 HKEY WINAPI SetupDiCreateDevRegKeyW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD Scope,
1557 DWORD HwProfile, DWORD KeyType, HINF InfHandle, const WCHAR *InfSectionName)
1559 struct device *device;
1560 HKEY key = INVALID_HANDLE_VALUE;
1561 LONG l;
1563 TRACE("devinfo %p, device_data %p, scope %ld, profile %ld, type %ld, inf_handle %p, inf_section %s.\n",
1564 devinfo, device_data, Scope, HwProfile, KeyType, InfHandle, debugstr_w(InfSectionName));
1566 if (!(device = get_device(devinfo, device_data)))
1567 return INVALID_HANDLE_VALUE;
1569 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
1571 SetLastError(ERROR_INVALID_FLAGS);
1572 return INVALID_HANDLE_VALUE;
1574 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
1576 SetLastError(ERROR_INVALID_FLAGS);
1577 return INVALID_HANDLE_VALUE;
1579 if (device->phantom)
1581 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
1582 return INVALID_HANDLE_VALUE;
1584 if (Scope != DICS_FLAG_GLOBAL)
1585 FIXME("unimplemented for scope %ld\n", Scope);
1586 switch (KeyType)
1588 case DIREG_DEV:
1589 l = RegCreateKeyExW(device->key, DeviceParameters, 0, NULL, 0,
1590 KEY_READ | KEY_WRITE, NULL, &key, NULL);
1591 break;
1592 case DIREG_DRV:
1593 l = create_driver_key(device, &key);
1594 break;
1595 default:
1596 FIXME("Unhandled type %#lx.\n", KeyType);
1597 l = ERROR_CALL_NOT_IMPLEMENTED;
1599 if (InfHandle)
1600 SetupInstallFromInfSectionW(NULL, InfHandle, InfSectionName, SPINST_ALL,
1601 NULL, NULL, SP_COPY_NEWER_ONLY, NULL, NULL, devinfo, device_data);
1602 SetLastError(l);
1603 return l ? INVALID_HANDLE_VALUE : key;
1606 /***********************************************************************
1607 * SetupDiCreateDeviceInfoA (SETUPAPI.@)
1609 BOOL WINAPI SetupDiCreateDeviceInfoA(HDEVINFO DeviceInfoSet, const char *name,
1610 const GUID *ClassGuid, PCSTR DeviceDescription, HWND hwndParent, DWORD CreationFlags,
1611 PSP_DEVINFO_DATA DeviceInfoData)
1613 WCHAR nameW[MAX_DEVICE_ID_LEN];
1614 BOOL ret = FALSE;
1615 LPWSTR DeviceDescriptionW = NULL;
1617 if (!name || strlen(name) >= MAX_DEVICE_ID_LEN)
1619 SetLastError(ERROR_INVALID_DEVINST_NAME);
1620 return FALSE;
1623 MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, ARRAY_SIZE(nameW));
1625 if (DeviceDescription)
1627 DeviceDescriptionW = MultiByteToUnicode(DeviceDescription, CP_ACP);
1628 if (DeviceDescriptionW == NULL)
1629 return FALSE;
1632 ret = SetupDiCreateDeviceInfoW(DeviceInfoSet, nameW, ClassGuid, DeviceDescriptionW,
1633 hwndParent, CreationFlags, DeviceInfoData);
1635 MyFree(DeviceDescriptionW);
1637 return ret;
1640 /***********************************************************************
1641 * SetupDiCreateDeviceInfoW (SETUPAPI.@)
1643 BOOL WINAPI SetupDiCreateDeviceInfoW(HDEVINFO devinfo, const WCHAR *name, const GUID *class,
1644 const WCHAR *description, HWND parent, DWORD flags, SP_DEVINFO_DATA *device_data)
1646 WCHAR id[MAX_DEVICE_ID_LEN];
1647 struct DeviceInfoSet *set;
1648 HKEY enum_hkey;
1649 HKEY instance_hkey;
1650 struct device *device;
1651 LONG l;
1653 TRACE("devinfo %p, name %s, class %s, description %s, hwnd %p, flags %#lx, device_data %p.\n",
1654 devinfo, debugstr_w(name), debugstr_guid(class), debugstr_w(description),
1655 parent, flags, device_data);
1657 if (!name || lstrlenW(name) >= MAX_DEVICE_ID_LEN)
1659 SetLastError(ERROR_INVALID_DEVINST_NAME);
1660 return FALSE;
1663 if (!(set = get_device_set(devinfo)))
1664 return FALSE;
1666 if (!class)
1668 SetLastError(ERROR_INVALID_PARAMETER);
1669 return FALSE;
1672 if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) && !IsEqualGUID(class, &set->ClassGuid))
1674 SetLastError(ERROR_CLASS_MISMATCH);
1675 return FALSE;
1677 if ((flags & DICD_GENERATE_ID))
1679 static const WCHAR formatW[] = {'R','O','O','T','\\','%','s','\\','%','0','4','u',0};
1680 unsigned int instance_id;
1682 if (wcschr(name, '\\'))
1684 SetLastError(ERROR_INVALID_DEVINST_NAME);
1685 return FALSE;
1688 for (instance_id = 0; ; ++instance_id)
1690 if (swprintf(id, ARRAY_SIZE(id), formatW, name, instance_id) == -1)
1692 SetLastError(ERROR_INVALID_DEVINST_NAME);
1693 return FALSE;
1696 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL, &enum_hkey, NULL);
1697 if (!(l = RegOpenKeyExW(enum_hkey, id, 0, KEY_READ, &instance_hkey)))
1698 RegCloseKey(instance_hkey);
1699 if (l == ERROR_FILE_NOT_FOUND)
1700 break;
1701 RegCloseKey(enum_hkey);
1704 else
1706 /* Check if instance is already in registry */
1707 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL, &enum_hkey, NULL);
1708 if (!RegOpenKeyExW(enum_hkey, name, 0, KEY_READ, &instance_hkey))
1710 RegCloseKey(instance_hkey);
1711 RegCloseKey(enum_hkey);
1712 SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
1713 return FALSE;
1715 RegCloseKey(enum_hkey);
1717 /* Check if instance is already in set */
1718 lstrcpyW(id, name);
1719 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
1721 if (!lstrcmpiW(name, device->instanceId))
1723 SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
1724 return FALSE;
1729 if (!(device = create_device(set, class, id, TRUE)))
1730 return FALSE;
1732 if (description)
1734 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_DEVICEDESC,
1735 (const BYTE *)description, lstrlenW(description) * sizeof(WCHAR));
1738 if (device_data)
1740 if (device_data->cbSize != sizeof(SP_DEVINFO_DATA))
1742 SetLastError(ERROR_INVALID_USER_BUFFER);
1743 return FALSE;
1745 else
1746 copy_device_data(device_data, device);
1749 return TRUE;
1752 /***********************************************************************
1753 * SetupDiRegisterDeviceInfo (SETUPAPI.@)
1755 BOOL WINAPI SetupDiRegisterDeviceInfo(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD flags,
1756 PSP_DETSIG_CMPPROC compare_proc, void *context, SP_DEVINFO_DATA *duplicate_data)
1758 struct device *device;
1760 TRACE("devinfo %p, data %p, flags %#lx, compare_proc %p, context %p, duplicate_data %p.\n",
1761 devinfo, device_data, flags, compare_proc, context, duplicate_data);
1763 if (!(device = get_device(devinfo, device_data)))
1764 return FALSE;
1766 if (device->phantom)
1768 device->phantom = FALSE;
1769 RegDeleteValueW(device->key, Phantom);
1771 return TRUE;
1774 /***********************************************************************
1775 * SetupDiRemoveDevice (SETUPAPI.@)
1777 BOOL WINAPI SetupDiRemoveDevice(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
1779 SC_HANDLE manager = NULL, service = NULL;
1780 struct device *device;
1781 WCHAR *service_name = NULL;
1782 DWORD size;
1784 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
1786 if (!(device = get_device(devinfo, device_data)))
1787 return FALSE;
1789 if (!(manager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT)))
1790 return FALSE;
1792 if (!RegGetValueW(device->key, NULL, L"Service", RRF_RT_REG_SZ, NULL, NULL, &size))
1794 service_name = malloc(size);
1795 if (!RegGetValueW(device->key, NULL, L"Service", RRF_RT_REG_SZ, NULL, service_name, &size))
1796 service = OpenServiceW(manager, service_name, SERVICE_USER_DEFINED_CONTROL);
1799 remove_device(device);
1801 if (service)
1803 SERVICE_STATUS status;
1804 if (!ControlService(service, SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES, &status))
1805 ERR("Failed to control service %s, error %lu.\n", debugstr_w(service_name), GetLastError());
1806 CloseServiceHandle(service);
1808 CloseServiceHandle(manager);
1810 free(service_name);
1812 remove_all_device_ifaces(device);
1814 return TRUE;
1817 /***********************************************************************
1818 * SetupDiDeleteDeviceInfo (SETUPAPI.@)
1820 BOOL WINAPI SetupDiDeleteDeviceInfo(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
1822 struct device *device;
1824 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
1826 if (!(device = get_device(devinfo, device_data)))
1827 return FALSE;
1829 delete_device(device);
1831 return TRUE;
1834 /***********************************************************************
1835 * SetupDiRemoveDeviceInterface (SETUPAPI.@)
1837 BOOL WINAPI SetupDiRemoveDeviceInterface(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data)
1839 struct device_iface *iface;
1841 TRACE("devinfo %p, iface_data %p.\n", devinfo, iface_data);
1843 if (!(iface = get_device_iface(devinfo, iface_data)))
1844 return FALSE;
1846 remove_device_iface(iface);
1848 return TRUE;
1851 /***********************************************************************
1852 * SetupDiDeleteDeviceInterfaceData (SETUPAPI.@)
1854 BOOL WINAPI SetupDiDeleteDeviceInterfaceData(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data)
1856 struct device_iface *iface;
1858 TRACE("devinfo %p, iface_data %p.\n", devinfo, iface_data);
1860 if (!(iface = get_device_iface(devinfo, iface_data)))
1861 return FALSE;
1863 delete_device_iface(iface);
1865 return TRUE;
1868 /***********************************************************************
1869 * SetupDiEnumDeviceInfo (SETUPAPI.@)
1871 BOOL WINAPI DECLSPEC_HOTPATCH SetupDiEnumDeviceInfo(HDEVINFO devinfo, DWORD index, SP_DEVINFO_DATA *device_data)
1873 struct DeviceInfoSet *set;
1874 struct device *device;
1875 DWORD i = 0;
1877 TRACE("devinfo %p, index %ld, device_data %p\n", devinfo, index, device_data);
1879 if (!(set = get_device_set(devinfo)))
1880 return FALSE;
1882 if (!device_data)
1884 SetLastError(ERROR_INVALID_PARAMETER);
1885 return FALSE;
1888 if (device_data->cbSize != sizeof(SP_DEVINFO_DATA))
1890 SetLastError(ERROR_INVALID_USER_BUFFER);
1891 return FALSE;
1894 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
1896 if (i++ == index)
1898 copy_device_data(device_data, device);
1899 return TRUE;
1903 SetLastError(ERROR_NO_MORE_ITEMS);
1904 return FALSE;
1907 /***********************************************************************
1908 * SetupDiGetDeviceInstanceIdA (SETUPAPI.@)
1910 BOOL WINAPI SetupDiGetDeviceInstanceIdA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
1911 char *id, DWORD size, DWORD *needed)
1913 WCHAR idW[MAX_DEVICE_ID_LEN];
1915 TRACE("devinfo %p, device_data %p, id %p, size %ld, needed %p.\n",
1916 devinfo, device_data, id, size, needed);
1918 if (!SetupDiGetDeviceInstanceIdW(devinfo, device_data, idW, ARRAY_SIZE(idW), NULL))
1919 return FALSE;
1921 if (needed)
1922 *needed = WideCharToMultiByte(CP_ACP, 0, idW, -1, NULL, 0, NULL, NULL);
1924 if (size && WideCharToMultiByte(CP_ACP, 0, idW, -1, id, size, NULL, NULL))
1925 return TRUE;
1927 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1928 return FALSE;
1931 /***********************************************************************
1932 * SetupDiGetDeviceInstanceIdW (SETUPAPI.@)
1934 BOOL WINAPI SetupDiGetDeviceInstanceIdW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
1935 WCHAR *DeviceInstanceId, DWORD DeviceInstanceIdSize, DWORD *RequiredSize)
1937 struct device *device;
1939 TRACE("devinfo %p, device_data %p, DeviceInstanceId %p, DeviceInstanceIdSize %ld, RequiredSize %p.\n",
1940 devinfo, device_data, DeviceInstanceId, DeviceInstanceIdSize, RequiredSize);
1942 if (!(device = get_device(devinfo, device_data)))
1943 return FALSE;
1945 TRACE("instance ID: %s\n", debugstr_w(device->instanceId));
1946 if (DeviceInstanceIdSize < lstrlenW(device->instanceId) + 1)
1948 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1949 if (RequiredSize)
1950 *RequiredSize = lstrlenW(device->instanceId) + 1;
1951 return FALSE;
1953 lstrcpyW(DeviceInstanceId, device->instanceId);
1954 if (RequiredSize)
1955 *RequiredSize = lstrlenW(device->instanceId) + 1;
1956 return TRUE;
1959 /***********************************************************************
1960 * SetupDiGetActualSectionToInstallExA (SETUPAPI.@)
1962 BOOL WINAPI SetupDiGetActualSectionToInstallExA(HINF hinf, const char *section, SP_ALTPLATFORM_INFO *altplatform,
1963 char *section_ext, DWORD size, DWORD *needed, char **extptr, void *reserved)
1965 WCHAR sectionW[LINE_LEN], section_extW[LINE_LEN], *extptrW;
1966 BOOL ret;
1968 MultiByteToWideChar(CP_ACP, 0, section, -1, sectionW, ARRAY_SIZE(sectionW));
1970 ret = SetupDiGetActualSectionToInstallExW(hinf, sectionW, altplatform, section_extW,
1971 ARRAY_SIZE(section_extW), NULL, &extptrW, reserved);
1972 if (ret)
1974 if (needed)
1975 *needed = WideCharToMultiByte(CP_ACP, 0, section_extW, -1, NULL, 0, NULL, NULL);
1977 if (section_ext)
1978 ret = !!WideCharToMultiByte(CP_ACP, 0, section_extW, -1, section_ext, size, NULL, NULL);
1980 if (extptr)
1982 if (extptrW)
1983 *extptr = section_ext + WideCharToMultiByte(CP_ACP, 0, section_extW,
1984 extptrW - section_extW, NULL, 0, NULL, NULL);
1985 else
1986 *extptr = NULL;
1990 return ret;
1993 /***********************************************************************
1994 * SetupDiGetActualSectionToInstallA (SETUPAPI.@)
1996 BOOL WINAPI SetupDiGetActualSectionToInstallA(HINF hinf, const char *section, char *section_ext,
1997 DWORD size, DWORD *needed, char **extptr)
1999 return SetupDiGetActualSectionToInstallExA(hinf, section, NULL, section_ext, size,
2000 needed, extptr, NULL);
2003 /***********************************************************************
2004 * SetupDiGetActualSectionToInstallExW (SETUPAPI.@)
2006 BOOL WINAPI SetupDiGetActualSectionToInstallExW(HINF hinf, const WCHAR *section, SP_ALTPLATFORM_INFO *altplatform,
2007 WCHAR *section_ext, DWORD size, DWORD *needed, WCHAR **extptr, void *reserved)
2009 WCHAR buffer[MAX_PATH];
2010 DWORD len;
2011 DWORD full_len;
2012 LONG line_count = -1;
2014 TRACE("hinf %p, section %s, altplatform %p, ext %p, size %ld, needed %p, extptr %p, reserved %p.\n",
2015 hinf, debugstr_w(section), altplatform, section_ext, size, needed, extptr, reserved);
2017 if (altplatform)
2018 FIXME("SP_ALTPLATFORM_INFO unsupported\n");
2020 lstrcpyW(buffer, section);
2021 len = lstrlenW(buffer);
2023 if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
2025 /* Test section name with '.NTx86' extension */
2026 lstrcpyW(&buffer[len], NtPlatformExtension);
2027 line_count = SetupGetLineCountW(hinf, buffer);
2029 if (line_count == -1)
2031 /* Test section name with '.NT' extension */
2032 lstrcpyW(&buffer[len], NtExtension);
2033 line_count = SetupGetLineCountW(hinf, buffer);
2036 else
2038 /* Test section name with '.Win' extension */
2039 lstrcpyW(&buffer[len], WinExtension);
2040 line_count = SetupGetLineCountW(hinf, buffer);
2043 if (line_count == -1)
2044 buffer[len] = 0;
2046 full_len = lstrlenW(buffer);
2048 if (section_ext != NULL && size != 0)
2050 if (size < (full_len + 1))
2052 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2053 return FALSE;
2056 lstrcpyW(section_ext, buffer);
2057 if (extptr != NULL)
2059 *extptr = (len == full_len) ? NULL : &section_ext[len];
2063 if (needed != NULL)
2065 *needed = full_len + 1;
2068 return TRUE;
2071 /***********************************************************************
2072 * SetupDiGetActualSectionToInstallW (SETUPAPI.@)
2074 BOOL WINAPI SetupDiGetActualSectionToInstallW(HINF hinf, const WCHAR *section, WCHAR *section_ext,
2075 DWORD size, DWORD *needed, WCHAR **extptr)
2077 return SetupDiGetActualSectionToInstallExW(hinf, section, NULL, section_ext, size,
2078 needed, extptr, NULL);
2081 /***********************************************************************
2082 * SetupDiGetClassDescriptionA (SETUPAPI.@)
2084 BOOL WINAPI SetupDiGetClassDescriptionA(
2085 const GUID* ClassGuid,
2086 PSTR ClassDescription,
2087 DWORD ClassDescriptionSize,
2088 PDWORD RequiredSize)
2090 return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
2091 ClassDescriptionSize,
2092 RequiredSize, NULL, NULL);
2095 /***********************************************************************
2096 * SetupDiGetClassDescriptionW (SETUPAPI.@)
2098 BOOL WINAPI SetupDiGetClassDescriptionW(
2099 const GUID* ClassGuid,
2100 PWSTR ClassDescription,
2101 DWORD ClassDescriptionSize,
2102 PDWORD RequiredSize)
2104 return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
2105 ClassDescriptionSize,
2106 RequiredSize, NULL, NULL);
2109 /***********************************************************************
2110 * SetupDiGetClassDescriptionExA (SETUPAPI.@)
2112 BOOL WINAPI SetupDiGetClassDescriptionExA(
2113 const GUID* ClassGuid,
2114 PSTR ClassDescription,
2115 DWORD ClassDescriptionSize,
2116 PDWORD RequiredSize,
2117 PCSTR MachineName,
2118 PVOID Reserved)
2120 HKEY hKey;
2121 DWORD dwLength;
2122 BOOL ret;
2124 hKey = SetupDiOpenClassRegKeyExA(ClassGuid,
2125 KEY_ALL_ACCESS,
2126 DIOCR_INSTALLER,
2127 MachineName,
2128 Reserved);
2129 if (hKey == INVALID_HANDLE_VALUE)
2131 WARN("SetupDiOpenClassRegKeyExA() failed (Error %lu)\n", GetLastError());
2132 return FALSE;
2135 dwLength = ClassDescriptionSize;
2136 ret = !RegQueryValueExA( hKey, NULL, NULL, NULL,
2137 (LPBYTE)ClassDescription, &dwLength );
2138 if (RequiredSize) *RequiredSize = dwLength;
2139 RegCloseKey(hKey);
2140 return ret;
2143 /***********************************************************************
2144 * SetupDiGetClassDescriptionExW (SETUPAPI.@)
2146 BOOL WINAPI SetupDiGetClassDescriptionExW(
2147 const GUID* ClassGuid,
2148 PWSTR ClassDescription,
2149 DWORD ClassDescriptionSize,
2150 PDWORD RequiredSize,
2151 PCWSTR MachineName,
2152 PVOID Reserved)
2154 HKEY hKey;
2155 DWORD dwLength;
2156 BOOL ret;
2158 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
2159 KEY_ALL_ACCESS,
2160 DIOCR_INSTALLER,
2161 MachineName,
2162 Reserved);
2163 if (hKey == INVALID_HANDLE_VALUE)
2165 WARN("SetupDiOpenClassRegKeyExW() failed (Error %lu)\n", GetLastError());
2166 return FALSE;
2169 dwLength = ClassDescriptionSize * sizeof(WCHAR);
2170 ret = !RegQueryValueExW( hKey, NULL, NULL, NULL,
2171 (LPBYTE)ClassDescription, &dwLength );
2172 if (RequiredSize) *RequiredSize = dwLength / sizeof(WCHAR);
2173 RegCloseKey(hKey);
2174 return ret;
2177 /***********************************************************************
2178 * SetupDiGetClassDevsA (SETUPAPI.@)
2180 HDEVINFO WINAPI SetupDiGetClassDevsA(const GUID *class, LPCSTR enumstr, HWND parent, DWORD flags)
2182 HDEVINFO ret;
2183 LPWSTR enumstrW = NULL;
2185 if (enumstr)
2187 int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
2188 enumstrW = malloc(len * sizeof(WCHAR));
2189 if (!enumstrW)
2191 ret = INVALID_HANDLE_VALUE;
2192 goto end;
2194 MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
2196 ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, NULL, NULL,
2197 NULL);
2198 free(enumstrW);
2200 end:
2201 return ret;
2204 /***********************************************************************
2205 * SetupDiGetClassDevsExA (SETUPAPI.@)
2207 HDEVINFO WINAPI SetupDiGetClassDevsExA(
2208 const GUID *class,
2209 PCSTR enumstr,
2210 HWND parent,
2211 DWORD flags,
2212 HDEVINFO deviceset,
2213 PCSTR machine,
2214 PVOID reserved)
2216 HDEVINFO ret;
2217 LPWSTR enumstrW = NULL, machineW = NULL;
2219 if (enumstr)
2221 int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
2222 enumstrW = malloc(len * sizeof(WCHAR));
2223 if (!enumstrW)
2225 ret = INVALID_HANDLE_VALUE;
2226 goto end;
2228 MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
2230 if (machine)
2232 int len = MultiByteToWideChar(CP_ACP, 0, machine, -1, NULL, 0);
2233 machineW = malloc(len * sizeof(WCHAR));
2234 if (!machineW)
2236 free(enumstrW);
2237 ret = INVALID_HANDLE_VALUE;
2238 goto end;
2240 MultiByteToWideChar(CP_ACP, 0, machine, -1, machineW, len);
2242 ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset,
2243 machineW, reserved);
2244 free(enumstrW);
2245 free(machineW);
2247 end:
2248 return ret;
2251 static void SETUPDI_AddDeviceInterfaces(struct device *device, HKEY key,
2252 const GUID *guid, DWORD flags)
2254 DWORD i, len;
2255 WCHAR subKeyName[MAX_PATH];
2256 LONG l = ERROR_SUCCESS;
2258 for (i = 0; !l; i++)
2260 len = ARRAY_SIZE(subKeyName);
2261 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2262 if (!l)
2264 HKEY subKey;
2265 struct device_iface *iface;
2267 if (*subKeyName == '#')
2269 /* The subkey name is the reference string, with a '#' prepended */
2270 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2271 if (!l)
2273 WCHAR symbolicLink[MAX_PATH];
2274 DWORD dataType;
2276 if (!(flags & DIGCF_PRESENT) || is_linked(subKey))
2278 iface = SETUPDI_CreateDeviceInterface(device, guid, subKeyName + 1);
2280 len = sizeof(symbolicLink);
2281 l = RegQueryValueExW(subKey, SymbolicLink, NULL, &dataType,
2282 (BYTE *)symbolicLink, &len);
2283 if (!l && dataType == REG_SZ)
2284 SETUPDI_SetInterfaceSymbolicLink(iface, symbolicLink);
2286 RegCloseKey(subKey);
2289 /* Allow enumeration to continue */
2290 l = ERROR_SUCCESS;
2293 /* FIXME: find and add all the device's interfaces to the device */
2296 static void SETUPDI_EnumerateMatchingInterfaces(HDEVINFO DeviceInfoSet,
2297 HKEY key, const GUID *guid, const WCHAR *enumstr, DWORD flags)
2299 struct DeviceInfoSet *set = DeviceInfoSet;
2300 DWORD i, len;
2301 WCHAR subKeyName[MAX_PATH];
2302 LONG l;
2303 HKEY enumKey = INVALID_HANDLE_VALUE;
2305 TRACE("%s\n", debugstr_w(enumstr));
2307 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL,
2308 &enumKey, NULL);
2309 for (i = 0; !l; i++)
2311 len = ARRAY_SIZE(subKeyName);
2312 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2313 if (!l)
2315 HKEY subKey;
2317 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2318 if (!l)
2320 WCHAR deviceInst[MAX_PATH * 3];
2321 DWORD dataType;
2323 len = sizeof(deviceInst);
2324 l = RegQueryValueExW(subKey, DeviceInstance, NULL, &dataType,
2325 (BYTE *)deviceInst, &len);
2326 if (!l && dataType == REG_SZ)
2328 TRACE("found instance ID %s\n", debugstr_w(deviceInst));
2329 if (!enumstr || !lstrcmpiW(enumstr, deviceInst))
2331 HKEY deviceKey;
2333 l = RegOpenKeyExW(enumKey, deviceInst, 0, KEY_READ,
2334 &deviceKey);
2335 if (!l)
2337 WCHAR deviceClassStr[40];
2339 len = sizeof(deviceClassStr);
2340 l = RegQueryValueExW(deviceKey, ClassGUID, NULL,
2341 &dataType, (BYTE *)deviceClassStr, &len);
2342 if (!l && dataType == REG_SZ &&
2343 deviceClassStr[0] == '{' &&
2344 deviceClassStr[37] == '}')
2346 GUID deviceClass;
2347 struct device *device;
2349 deviceClassStr[37] = 0;
2350 UuidFromStringW(&deviceClassStr[1],
2351 &deviceClass);
2352 if ((device = create_device(set, &deviceClass, deviceInst, FALSE)))
2353 SETUPDI_AddDeviceInterfaces(device, subKey, guid, flags);
2355 RegCloseKey(deviceKey);
2359 RegCloseKey(subKey);
2361 /* Allow enumeration to continue */
2362 l = ERROR_SUCCESS;
2365 if (enumKey != INVALID_HANDLE_VALUE)
2366 RegCloseKey(enumKey);
2369 static void SETUPDI_EnumerateInterfaces(HDEVINFO DeviceInfoSet,
2370 const GUID *guid, LPCWSTR enumstr, DWORD flags)
2372 HKEY interfacesKey = SetupDiOpenClassRegKeyExW(guid, KEY_READ,
2373 DIOCR_INTERFACE, NULL, NULL);
2375 TRACE("%p, %s, %s, %08lx\n", DeviceInfoSet, debugstr_guid(guid),
2376 debugstr_w(enumstr), flags);
2378 if (interfacesKey != INVALID_HANDLE_VALUE)
2380 if (flags & DIGCF_ALLCLASSES)
2382 DWORD i, len;
2383 WCHAR interfaceGuidStr[40];
2384 LONG l = ERROR_SUCCESS;
2386 for (i = 0; !l; i++)
2388 len = ARRAY_SIZE(interfaceGuidStr);
2389 l = RegEnumKeyExW(interfacesKey, i, interfaceGuidStr, &len,
2390 NULL, NULL, NULL, NULL);
2391 if (!l)
2393 if (interfaceGuidStr[0] == '{' &&
2394 interfaceGuidStr[37] == '}')
2396 HKEY interfaceKey;
2397 GUID interfaceGuid;
2399 interfaceGuidStr[37] = 0;
2400 UuidFromStringW(&interfaceGuidStr[1], &interfaceGuid);
2401 interfaceGuidStr[37] = '}';
2402 interfaceGuidStr[38] = 0;
2403 l = RegOpenKeyExW(interfacesKey, interfaceGuidStr, 0,
2404 KEY_READ, &interfaceKey);
2405 if (!l)
2407 SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
2408 interfaceKey, &interfaceGuid, enumstr, flags);
2409 RegCloseKey(interfaceKey);
2415 else
2417 /* In this case, SetupDiOpenClassRegKeyExW opened the specific
2418 * interface's key, so just pass that long
2420 SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
2421 interfacesKey, guid, enumstr, flags);
2423 RegCloseKey(interfacesKey);
2427 static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set,
2428 LPCWSTR enumerator, LPCWSTR deviceName, HKEY deviceKey,
2429 const GUID *class, DWORD flags)
2431 WCHAR id[MAX_DEVICE_ID_LEN];
2432 DWORD i, len;
2433 WCHAR deviceInstance[MAX_PATH];
2434 LONG l = ERROR_SUCCESS;
2436 TRACE("%s %s\n", debugstr_w(enumerator), debugstr_w(deviceName));
2438 for (i = 0; !l; i++)
2440 len = ARRAY_SIZE(deviceInstance);
2441 l = RegEnumKeyExW(deviceKey, i, deviceInstance, &len, NULL, NULL, NULL,
2442 NULL);
2443 if (!l)
2445 HKEY subKey;
2447 l = RegOpenKeyExW(deviceKey, deviceInstance, 0, KEY_READ, &subKey);
2448 if (!l)
2450 WCHAR classGuid[40];
2451 DWORD dataType;
2453 len = sizeof(classGuid);
2454 l = RegQueryValueExW(subKey, ClassGUID, NULL, &dataType,
2455 (BYTE *)classGuid, &len);
2456 if (!l && dataType == REG_SZ)
2458 if (classGuid[0] == '{' && classGuid[37] == '}')
2460 GUID deviceClass;
2462 classGuid[37] = 0;
2463 UuidFromStringW(&classGuid[1], &deviceClass);
2464 if ((flags & DIGCF_ALLCLASSES) ||
2465 IsEqualGUID(class, &deviceClass))
2467 static const WCHAR fmt[] =
2468 {'%','s','\\','%','s','\\','%','s',0};
2470 if (swprintf(id, ARRAY_SIZE(id), fmt, enumerator,
2471 deviceName, deviceInstance) != -1)
2473 create_device(set, &deviceClass, id, FALSE);
2478 RegCloseKey(subKey);
2480 /* Allow enumeration to continue */
2481 l = ERROR_SUCCESS;
2486 static void SETUPDI_EnumerateMatchingDevices(HDEVINFO DeviceInfoSet,
2487 LPCWSTR parent, HKEY key, const GUID *class, DWORD flags)
2489 struct DeviceInfoSet *set = DeviceInfoSet;
2490 DWORD i, len;
2491 WCHAR subKeyName[MAX_PATH];
2492 LONG l = ERROR_SUCCESS;
2494 TRACE("%s\n", debugstr_w(parent));
2496 for (i = 0; !l; i++)
2498 len = ARRAY_SIZE(subKeyName);
2499 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2500 if (!l)
2502 HKEY subKey;
2504 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2505 if (!l)
2507 TRACE("%s\n", debugstr_w(subKeyName));
2508 SETUPDI_EnumerateMatchingDeviceInstances(set, parent,
2509 subKeyName, subKey, class, flags);
2510 RegCloseKey(subKey);
2512 /* Allow enumeration to continue */
2513 l = ERROR_SUCCESS;
2518 static void SETUPDI_EnumerateDevices(HDEVINFO DeviceInfoSet, const GUID *class,
2519 LPCWSTR enumstr, DWORD flags)
2521 HKEY enumKey;
2522 LONG l;
2524 TRACE("%p, %s, %s, %08lx\n", DeviceInfoSet, debugstr_guid(class),
2525 debugstr_w(enumstr), flags);
2527 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL,
2528 &enumKey, NULL);
2529 if (enumKey != INVALID_HANDLE_VALUE)
2531 if (enumstr)
2533 HKEY enumStrKey;
2535 l = RegOpenKeyExW(enumKey, enumstr, 0, KEY_READ,
2536 &enumStrKey);
2537 if (!l)
2539 WCHAR *bus, *device;
2541 if (!wcschr(enumstr, '\\'))
2543 SETUPDI_EnumerateMatchingDevices(DeviceInfoSet, enumstr, enumStrKey, class, flags);
2545 else if ((bus = wcsdup(enumstr)))
2547 device = wcschr(bus, '\\');
2548 *device++ = 0;
2550 SETUPDI_EnumerateMatchingDeviceInstances(DeviceInfoSet, bus, device, enumStrKey, class, flags);
2551 free(bus);
2554 RegCloseKey(enumStrKey);
2557 else
2559 DWORD i, len;
2560 WCHAR subKeyName[MAX_PATH];
2562 l = ERROR_SUCCESS;
2563 for (i = 0; !l; i++)
2565 len = ARRAY_SIZE(subKeyName);
2566 l = RegEnumKeyExW(enumKey, i, subKeyName, &len, NULL,
2567 NULL, NULL, NULL);
2568 if (!l)
2570 HKEY subKey;
2572 l = RegOpenKeyExW(enumKey, subKeyName, 0, KEY_READ,
2573 &subKey);
2574 if (!l)
2576 SETUPDI_EnumerateMatchingDevices(DeviceInfoSet,
2577 subKeyName, subKey, class, flags);
2578 RegCloseKey(subKey);
2580 /* Allow enumeration to continue */
2581 l = ERROR_SUCCESS;
2585 RegCloseKey(enumKey);
2589 /***********************************************************************
2590 * SetupDiGetClassDevsW (SETUPAPI.@)
2592 HDEVINFO WINAPI SetupDiGetClassDevsW(const GUID *class, LPCWSTR enumstr, HWND parent, DWORD flags)
2594 return SetupDiGetClassDevsExW(class, enumstr, parent, flags, NULL, NULL,
2595 NULL);
2598 /***********************************************************************
2599 * SetupDiGetClassDevsExW (SETUPAPI.@)
2601 HDEVINFO WINAPI SetupDiGetClassDevsExW(const GUID *class, PCWSTR enumstr, HWND parent, DWORD flags,
2602 HDEVINFO deviceset, PCWSTR machine, void *reserved)
2604 static const DWORD unsupportedFlags = DIGCF_DEFAULT | DIGCF_PROFILE;
2605 HDEVINFO set;
2607 TRACE("%s %s %p 0x%08lx %p %s %p\n", debugstr_guid(class),
2608 debugstr_w(enumstr), parent, flags, deviceset, debugstr_w(machine),
2609 reserved);
2611 if (!(flags & DIGCF_ALLCLASSES) && !class)
2613 SetLastError(ERROR_INVALID_PARAMETER);
2614 return INVALID_HANDLE_VALUE;
2616 if (flags & DIGCF_ALLCLASSES)
2617 class = NULL;
2619 if (flags & unsupportedFlags)
2620 WARN("unsupported flags %08lx\n", flags & unsupportedFlags);
2621 if (deviceset)
2622 set = deviceset;
2623 else
2624 set = SetupDiCreateDeviceInfoListExW((flags & DIGCF_DEVICEINTERFACE) ? NULL : class, parent, machine, reserved);
2625 if (set != INVALID_HANDLE_VALUE)
2627 if (machine && *machine)
2628 FIXME("%s: unimplemented for remote machines\n",
2629 debugstr_w(machine));
2630 else if (flags & DIGCF_DEVICEINTERFACE)
2631 SETUPDI_EnumerateInterfaces(set, class, enumstr, flags);
2632 else
2633 SETUPDI_EnumerateDevices(set, class, enumstr, flags);
2635 return set;
2638 /***********************************************************************
2639 * SetupDiGetDeviceInfoListDetailA (SETUPAPI.@)
2641 BOOL WINAPI SetupDiGetDeviceInfoListDetailA(HDEVINFO devinfo, SP_DEVINFO_LIST_DETAIL_DATA_A *DevInfoData)
2643 struct DeviceInfoSet *set;
2645 TRACE("devinfo %p, detail_data %p.\n", devinfo, DevInfoData);
2647 if (!(set = get_device_set(devinfo)))
2648 return FALSE;
2650 if (!DevInfoData ||
2651 DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_A))
2653 SetLastError(ERROR_INVALID_PARAMETER);
2654 return FALSE;
2656 DevInfoData->ClassGuid = set->ClassGuid;
2657 DevInfoData->RemoteMachineHandle = NULL;
2658 DevInfoData->RemoteMachineName[0] = '\0';
2659 return TRUE;
2662 /***********************************************************************
2663 * SetupDiGetDeviceInfoListDetailW (SETUPAPI.@)
2665 BOOL WINAPI SetupDiGetDeviceInfoListDetailW(HDEVINFO devinfo, SP_DEVINFO_LIST_DETAIL_DATA_W *DevInfoData)
2667 struct DeviceInfoSet *set;
2669 TRACE("devinfo %p, detail_data %p.\n", devinfo, DevInfoData);
2671 if (!(set = get_device_set(devinfo)))
2672 return FALSE;
2674 if (!DevInfoData ||
2675 DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W))
2677 SetLastError(ERROR_INVALID_PARAMETER);
2678 return FALSE;
2680 DevInfoData->ClassGuid = set->ClassGuid;
2681 DevInfoData->RemoteMachineHandle = NULL;
2682 DevInfoData->RemoteMachineName[0] = '\0';
2683 return TRUE;
2686 /***********************************************************************
2687 * SetupDiCreateDeviceInterfaceA (SETUPAPI.@)
2689 BOOL WINAPI SetupDiCreateDeviceInterfaceA(
2690 HDEVINFO DeviceInfoSet,
2691 PSP_DEVINFO_DATA DeviceInfoData,
2692 const GUID *InterfaceClassGuid,
2693 PCSTR ReferenceString,
2694 DWORD CreationFlags,
2695 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2697 BOOL ret;
2698 LPWSTR ReferenceStringW = NULL;
2700 TRACE("%p %p %s %s %08lx %p\n", DeviceInfoSet, DeviceInfoData,
2701 debugstr_guid(InterfaceClassGuid), debugstr_a(ReferenceString),
2702 CreationFlags, DeviceInterfaceData);
2704 if (ReferenceString)
2706 ReferenceStringW = MultiByteToUnicode(ReferenceString, CP_ACP);
2707 if (ReferenceStringW == NULL) return FALSE;
2710 ret = SetupDiCreateDeviceInterfaceW(DeviceInfoSet, DeviceInfoData,
2711 InterfaceClassGuid, ReferenceStringW, CreationFlags,
2712 DeviceInterfaceData);
2714 MyFree(ReferenceStringW);
2716 return ret;
2719 /***********************************************************************
2720 * SetupDiCreateDeviceInterfaceW (SETUPAPI.@)
2722 BOOL WINAPI SetupDiCreateDeviceInterfaceW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
2723 const GUID *class, const WCHAR *refstr, DWORD flags, SP_DEVICE_INTERFACE_DATA *iface_data)
2725 struct device *device;
2726 struct device_iface *iface;
2728 TRACE("devinfo %p, device_data %p, class %s, refstr %s, flags %#lx, iface_data %p.\n",
2729 devinfo, device_data, debugstr_guid(class), debugstr_w(refstr), flags, iface_data);
2731 if (!(device = get_device(devinfo, device_data)))
2732 return FALSE;
2734 if (!class)
2736 SetLastError(ERROR_INVALID_USER_BUFFER);
2737 return FALSE;
2740 if (!(iface = SETUPDI_CreateDeviceInterface(device, class, refstr)))
2741 return FALSE;
2743 if (iface_data)
2745 if (iface_data->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2747 SetLastError(ERROR_INVALID_USER_BUFFER);
2748 return FALSE;
2751 copy_device_iface_data(iface_data, iface);
2753 return TRUE;
2756 /***********************************************************************
2757 * SetupDiCreateDeviceInterfaceRegKeyA (SETUPAPI.@)
2759 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyA(
2760 HDEVINFO DeviceInfoSet,
2761 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2762 DWORD Reserved,
2763 REGSAM samDesired,
2764 HINF InfHandle,
2765 PCSTR InfSectionName)
2767 HKEY key;
2768 PWSTR InfSectionNameW = NULL;
2770 TRACE("%p %p %ld %08lx %p %p\n", DeviceInfoSet, DeviceInterfaceData, Reserved,
2771 samDesired, InfHandle, InfSectionName);
2772 if (InfHandle)
2774 if (!InfSectionName)
2776 SetLastError(ERROR_INVALID_PARAMETER);
2777 return INVALID_HANDLE_VALUE;
2779 InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
2780 if (!InfSectionNameW)
2781 return INVALID_HANDLE_VALUE;
2783 key = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet,
2784 DeviceInterfaceData, Reserved, samDesired, InfHandle,
2785 InfSectionNameW);
2786 MyFree(InfSectionNameW);
2787 return key;
2790 static LONG create_iface_key(const struct device_iface *iface, REGSAM access, HKEY *key)
2792 return RegCreateKeyExW(iface->refstr_key, DeviceParameters, 0, NULL, 0, access, NULL, key, NULL);
2795 /***********************************************************************
2796 * SetupDiCreateDeviceInterfaceRegKeyW (SETUPAPI.@)
2798 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyW(HDEVINFO devinfo,
2799 SP_DEVICE_INTERFACE_DATA *iface_data, DWORD reserved, REGSAM access,
2800 HINF hinf, const WCHAR *section)
2802 struct device_iface *iface;
2803 HKEY params_key;
2804 LONG ret;
2806 TRACE("devinfo %p, iface_data %p, reserved %ld, access %#lx, hinf %p, section %s.\n",
2807 devinfo, iface_data, reserved, access, hinf, debugstr_w(section));
2809 if (!(iface = get_device_iface(devinfo, iface_data)))
2810 return INVALID_HANDLE_VALUE;
2812 if (hinf && !section)
2814 SetLastError(ERROR_INVALID_PARAMETER);
2815 return INVALID_HANDLE_VALUE;
2818 ret = create_iface_key(iface, access, &params_key);
2819 if (ret)
2821 SetLastError(ret);
2822 return INVALID_HANDLE_VALUE;
2825 return params_key;
2828 /***********************************************************************
2829 * SetupDiDeleteDeviceInterfaceRegKey (SETUPAPI.@)
2831 BOOL WINAPI SetupDiDeleteDeviceInterfaceRegKey(HDEVINFO devinfo,
2832 SP_DEVICE_INTERFACE_DATA *iface_data, DWORD reserved)
2834 struct device_iface *iface;
2835 LONG ret;
2837 TRACE("devinfo %p, iface_data %p, reserved %ld.\n", devinfo, iface_data, reserved);
2839 if (!(iface = get_device_iface(devinfo, iface_data)))
2840 return FALSE;
2842 ret = RegDeleteKeyW(iface->refstr_key, DeviceParameters);
2843 if (ret)
2845 SetLastError(ret);
2846 return FALSE;
2849 return TRUE;
2852 /***********************************************************************
2853 * SetupDiEnumDeviceInterfaces (SETUPAPI.@)
2855 * PARAMS
2856 * DeviceInfoSet [I] Set of devices from which to enumerate
2857 * interfaces
2858 * DeviceInfoData [I] (Optional) If specified, a specific device
2859 * instance from which to enumerate interfaces.
2860 * If it isn't specified, all interfaces for all
2861 * devices in the set are enumerated.
2862 * InterfaceClassGuid [I] The interface class to enumerate.
2863 * MemberIndex [I] An index of the interface instance to enumerate.
2864 * A caller should start with MemberIndex set to 0,
2865 * and continue until the function fails with
2866 * ERROR_NO_MORE_ITEMS.
2867 * DeviceInterfaceData [I/O] Returns an enumerated interface. Its cbSize
2868 * member must be set to
2869 * sizeof(SP_DEVICE_INTERFACE_DATA).
2871 * RETURNS
2872 * Success: non-zero value.
2873 * Failure: FALSE. Call GetLastError() for more info.
2875 BOOL WINAPI SetupDiEnumDeviceInterfaces(HDEVINFO devinfo,
2876 SP_DEVINFO_DATA *device_data, const GUID *class, DWORD index,
2877 SP_DEVICE_INTERFACE_DATA *iface_data)
2879 struct DeviceInfoSet *set;
2880 struct device *device;
2881 struct device_iface *iface;
2882 DWORD i = 0;
2884 TRACE("devinfo %p, device_data %p, class %s, index %lu, iface_data %p.\n",
2885 devinfo, device_data, debugstr_guid(class), index, iface_data);
2887 if (!iface_data || iface_data->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2889 SetLastError(ERROR_INVALID_PARAMETER);
2890 return FALSE;
2893 /* In case application fails to check return value, clear output */
2894 memset(iface_data, 0, sizeof(*iface_data));
2895 iface_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
2897 if (device_data)
2899 if (!(device = get_device(devinfo, device_data)))
2900 return FALSE;
2902 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
2904 if (IsEqualGUID(&iface->class, class))
2906 if (i == index)
2908 copy_device_iface_data(iface_data, iface);
2909 return TRUE;
2911 i++;
2915 else
2917 if (!(set = get_device_set(devinfo)))
2918 return FALSE;
2920 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
2922 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
2924 if (IsEqualGUID(&iface->class, class))
2926 if (i == index)
2928 copy_device_iface_data(iface_data, iface);
2929 return TRUE;
2931 i++;
2937 SetLastError(ERROR_NO_MORE_ITEMS);
2938 return FALSE;
2941 /***********************************************************************
2942 * SetupDiDestroyDeviceInfoList (SETUPAPI.@)
2944 * Destroy a DeviceInfoList and free all used memory of the list.
2946 * PARAMS
2947 * devinfo [I] DeviceInfoList pointer to list to destroy
2949 * RETURNS
2950 * Success: non zero value.
2951 * Failure: zero value.
2953 BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
2955 struct DeviceInfoSet *set;
2956 struct device *device, *device2;
2958 TRACE("devinfo %p.\n", devinfo);
2960 if (!(set = get_device_set(devinfo)))
2961 return FALSE;
2963 LIST_FOR_EACH_ENTRY_SAFE(device, device2, &set->devices, struct device, entry)
2965 delete_device(device);
2967 free(set);
2969 SetLastError(ERROR_SUCCESS);
2970 return TRUE;
2973 /***********************************************************************
2974 * SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
2976 BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data,
2977 SP_DEVICE_INTERFACE_DETAIL_DATA_A *DeviceInterfaceDetailData,
2978 DWORD DeviceInterfaceDetailDataSize, DWORD *ret_size, SP_DEVINFO_DATA *device_data)
2980 struct device_iface *iface;
2981 DWORD bytesNeeded = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath[1]);
2982 BOOL ret = FALSE;
2984 TRACE("devinfo %p, iface_data %p, detail_data %p, size %ld, ret_size %p, device_data %p.\n",
2985 devinfo, iface_data, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize,
2986 ret_size, device_data);
2988 if (!(iface = get_device_iface(devinfo, iface_data)))
2989 return FALSE;
2991 if (DeviceInterfaceDetailData &&
2992 DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A))
2994 SetLastError(ERROR_INVALID_USER_BUFFER);
2995 return FALSE;
2997 if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
2999 SetLastError(ERROR_INVALID_USER_BUFFER);
3000 return FALSE;
3003 if (iface->symlink)
3004 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, iface->symlink, -1,
3005 NULL, 0, NULL, NULL) - 1;
3007 if (ret_size)
3008 *ret_size = bytesNeeded;
3010 if (DeviceInterfaceDetailDataSize >= bytesNeeded)
3012 if (iface->symlink)
3013 WideCharToMultiByte(CP_ACP, 0, iface->symlink, -1,
3014 DeviceInterfaceDetailData->DevicePath,
3015 DeviceInterfaceDetailDataSize -
3016 offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
3017 NULL, NULL);
3018 else
3019 DeviceInterfaceDetailData->DevicePath[0] = '\0';
3021 ret = TRUE;
3023 else
3025 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3028 if (device_data && device_data->cbSize == sizeof(SP_DEVINFO_DATA))
3029 copy_device_data(device_data, iface->device);
3031 return ret;
3034 /***********************************************************************
3035 * SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
3037 BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data,
3038 SP_DEVICE_INTERFACE_DETAIL_DATA_W *DeviceInterfaceDetailData,
3039 DWORD DeviceInterfaceDetailDataSize, DWORD *ret_size, SP_DEVINFO_DATA *device_data)
3041 struct device_iface *iface;
3042 DWORD bytesNeeded = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
3043 + sizeof(WCHAR); /* include NULL terminator */
3044 BOOL ret = FALSE;
3046 TRACE("devinfo %p, iface_data %p, detail_data %p, size %ld, ret_size %p, device_data %p.\n",
3047 devinfo, iface_data, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize,
3048 ret_size, device_data);
3050 if (!(iface = get_device_iface(devinfo, iface_data)))
3051 return FALSE;
3053 if (DeviceInterfaceDetailData && (DeviceInterfaceDetailData->cbSize <
3054 offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR) ||
3055 DeviceInterfaceDetailData->cbSize > sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W)))
3057 SetLastError(ERROR_INVALID_USER_BUFFER);
3058 return FALSE;
3060 if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
3062 SetLastError(ERROR_INVALID_USER_BUFFER);
3063 return FALSE;
3066 if (iface->symlink)
3067 bytesNeeded += sizeof(WCHAR) * lstrlenW(iface->symlink);
3069 if (ret_size)
3070 *ret_size = bytesNeeded;
3072 if (DeviceInterfaceDetailDataSize >= bytesNeeded)
3074 if (iface->symlink)
3075 lstrcpyW(DeviceInterfaceDetailData->DevicePath, iface->symlink);
3076 else
3077 DeviceInterfaceDetailData->DevicePath[0] = '\0';
3079 ret = TRUE;
3081 else
3083 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3086 if (device_data && device_data->cbSize == sizeof(SP_DEVINFO_DATA))
3087 copy_device_data(device_data, iface->device);
3089 return ret;
3092 /***********************************************************************
3093 * SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
3095 BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(HDEVINFO devinfo,
3096 SP_DEVINFO_DATA *device_data, DWORD Property, DWORD *PropertyRegDataType,
3097 BYTE *PropertyBuffer, DWORD PropertyBufferSize, DWORD *RequiredSize)
3099 BOOL ret = FALSE;
3100 struct device *device;
3102 TRACE("devinfo %p, device_data %p, property %ld, type %p, buffer %p, size %ld, required %p\n",
3103 devinfo, device_data, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize);
3105 if (!(device = get_device(devinfo, device_data)))
3106 return FALSE;
3108 if (PropertyBufferSize && PropertyBuffer == NULL)
3110 SetLastError(ERROR_INVALID_DATA);
3111 return FALSE;
3114 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameA)
3116 DWORD size = PropertyBufferSize;
3117 LONG l = RegQueryValueExA(device->key, PropertyMap[Property].nameA,
3118 NULL, PropertyRegDataType, PropertyBuffer, &size);
3120 if (l == ERROR_FILE_NOT_FOUND)
3121 SetLastError(ERROR_INVALID_DATA);
3122 else if (l == ERROR_MORE_DATA || !PropertyBufferSize)
3123 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3124 else if (!l)
3125 ret = TRUE;
3126 else
3127 SetLastError(l);
3128 if (RequiredSize)
3129 *RequiredSize = size;
3131 return ret;
3134 /***********************************************************************
3135 * SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
3137 BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(HDEVINFO devinfo,
3138 SP_DEVINFO_DATA *device_data, DWORD Property, DWORD *PropertyRegDataType,
3139 BYTE *PropertyBuffer, DWORD PropertyBufferSize, DWORD *RequiredSize)
3141 BOOL ret = FALSE;
3142 struct device *device;
3144 TRACE("devinfo %p, device_data %p, prop %ld, type %p, buffer %p, size %ld, required %p\n",
3145 devinfo, device_data, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize);
3147 if (!(device = get_device(devinfo, device_data)))
3148 return FALSE;
3150 if (PropertyBufferSize && PropertyBuffer == NULL)
3152 SetLastError(ERROR_INVALID_DATA);
3153 return FALSE;
3156 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameW)
3158 DWORD size = PropertyBufferSize;
3159 LONG l = RegQueryValueExW(device->key, PropertyMap[Property].nameW,
3160 NULL, PropertyRegDataType, PropertyBuffer, &size);
3162 if (l == ERROR_FILE_NOT_FOUND)
3163 SetLastError(ERROR_INVALID_DATA);
3164 else if (l == ERROR_MORE_DATA || !PropertyBufferSize)
3165 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3166 else if (!l)
3167 ret = TRUE;
3168 else
3169 SetLastError(l);
3170 if (RequiredSize)
3171 *RequiredSize = size;
3173 return ret;
3176 /***********************************************************************
3177 * SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
3179 BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
3180 DWORD Property, const BYTE *PropertyBuffer, DWORD PropertyBufferSize)
3182 BOOL ret = FALSE;
3183 struct device *device;
3185 TRACE("devinfo %p, device_data %p, prop %ld, buffer %p, size %ld.\n",
3186 devinfo, device_data, Property, PropertyBuffer, PropertyBufferSize);
3188 if (!(device = get_device(devinfo, device_data)))
3189 return FALSE;
3191 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameA)
3193 LONG l = RegSetValueExA(device->key, PropertyMap[Property].nameA, 0,
3194 PropertyMap[Property].regType, PropertyBuffer,
3195 PropertyBufferSize);
3196 if (!l)
3197 ret = TRUE;
3198 else
3199 SetLastError(l);
3201 return ret;
3204 /***********************************************************************
3205 * SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
3207 BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(HDEVINFO devinfo,
3208 SP_DEVINFO_DATA *device_data, DWORD prop, const BYTE *buffer, DWORD size)
3210 struct device *device;
3212 TRACE("devinfo %p, device_data %p, prop %ld, buffer %p, size %ld.\n",
3213 devinfo, device_data, prop, buffer, size);
3215 if (!(device = get_device(devinfo, device_data)))
3216 return FALSE;
3218 return SETUPDI_SetDeviceRegistryPropertyW(device, prop, buffer, size);
3221 /***********************************************************************
3222 * SetupDiInstallClassA (SETUPAPI.@)
3224 BOOL WINAPI SetupDiInstallClassA(
3225 HWND hwndParent,
3226 PCSTR InfFileName,
3227 DWORD Flags,
3228 HSPFILEQ FileQueue)
3230 UNICODE_STRING FileNameW;
3231 BOOL Result;
3233 if (!InfFileName)
3235 SetLastError(ERROR_INVALID_PARAMETER);
3236 return FALSE;
3238 if (!RtlCreateUnicodeStringFromAsciiz(&FileNameW, InfFileName))
3240 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3241 return FALSE;
3244 Result = SetupDiInstallClassW(hwndParent, FileNameW.Buffer, Flags, FileQueue);
3246 RtlFreeUnicodeString(&FileNameW);
3248 return Result;
3251 static HKEY CreateClassKey(HINF hInf)
3253 static const WCHAR slash[] = { '\\',0 };
3254 WCHAR FullBuffer[MAX_PATH];
3255 WCHAR Buffer[MAX_PATH];
3256 DWORD RequiredSize;
3257 HKEY hClassKey;
3259 if (!SetupGetLineTextW(NULL,
3260 hInf,
3261 Version,
3262 ClassGUID,
3263 Buffer,
3264 MAX_PATH,
3265 &RequiredSize))
3267 return INVALID_HANDLE_VALUE;
3270 lstrcpyW(FullBuffer, ControlClass);
3271 lstrcatW(FullBuffer, slash);
3272 lstrcatW(FullBuffer, Buffer);
3274 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3275 FullBuffer,
3277 KEY_ALL_ACCESS,
3278 &hClassKey))
3280 if (!SetupGetLineTextW(NULL,
3281 hInf,
3282 Version,
3283 Class,
3284 Buffer,
3285 MAX_PATH,
3286 &RequiredSize))
3288 return INVALID_HANDLE_VALUE;
3291 if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
3292 FullBuffer,
3294 NULL,
3295 REG_OPTION_NON_VOLATILE,
3296 KEY_ALL_ACCESS,
3297 NULL,
3298 &hClassKey,
3299 NULL))
3301 return INVALID_HANDLE_VALUE;
3306 if (RegSetValueExW(hClassKey,
3307 Class,
3309 REG_SZ,
3310 (LPBYTE)Buffer,
3311 RequiredSize * sizeof(WCHAR)))
3313 RegCloseKey(hClassKey);
3314 RegDeleteKeyW(HKEY_LOCAL_MACHINE,
3315 FullBuffer);
3316 return INVALID_HANDLE_VALUE;
3319 return hClassKey;
3322 /***********************************************************************
3323 * SetupDiInstallClassW (SETUPAPI.@)
3325 BOOL WINAPI SetupDiInstallClassW(
3326 HWND hwndParent,
3327 PCWSTR InfFileName,
3328 DWORD Flags,
3329 HSPFILEQ FileQueue)
3331 WCHAR SectionName[MAX_PATH];
3332 DWORD SectionNameLength = 0;
3333 HINF hInf;
3334 BOOL bFileQueueCreated = FALSE;
3335 HKEY hClassKey;
3338 FIXME("\n");
3340 if (!InfFileName)
3342 SetLastError(ERROR_INVALID_PARAMETER);
3343 return FALSE;
3345 if ((Flags & DI_NOVCP) && (FileQueue == NULL || FileQueue == INVALID_HANDLE_VALUE))
3347 SetLastError(ERROR_INVALID_PARAMETER);
3348 return FALSE;
3351 /* Open the .inf file */
3352 hInf = SetupOpenInfFileW(InfFileName,
3353 NULL,
3354 INF_STYLE_WIN4,
3355 NULL);
3356 if (hInf == INVALID_HANDLE_VALUE)
3359 return FALSE;
3362 /* Create or open the class registry key 'HKLM\\CurrentControlSet\\Class\\{GUID}' */
3363 hClassKey = CreateClassKey(hInf);
3364 if (hClassKey == INVALID_HANDLE_VALUE)
3366 SetupCloseInfFile(hInf);
3367 return FALSE;
3371 /* Try to append a layout file */
3372 SetupOpenAppendInfFileW(NULL, hInf, NULL);
3374 /* Retrieve the actual section name */
3375 SetupDiGetActualSectionToInstallW(hInf,
3376 ClassInstall32,
3377 SectionName,
3378 MAX_PATH,
3379 &SectionNameLength,
3380 NULL);
3382 #if 0
3383 if (!(Flags & DI_NOVCP))
3385 FileQueue = SetupOpenFileQueue();
3386 if (FileQueue == INVALID_HANDLE_VALUE)
3388 SetupCloseInfFile(hInf);
3389 return FALSE;
3392 bFileQueueCreated = TRUE;
3395 #endif
3397 SetupInstallFromInfSectionW(NULL,
3398 hInf,
3399 SectionName,
3400 SPINST_COPYINF | SPINST_FILES | SPINST_REGISTRY,
3401 hClassKey,
3402 NULL,
3404 NULL,
3405 NULL,
3406 INVALID_HANDLE_VALUE,
3407 NULL);
3409 /* FIXME: More code! */
3411 if (bFileQueueCreated)
3412 SetupCloseFileQueue(FileQueue);
3414 SetupCloseInfFile(hInf);
3416 return TRUE;
3420 /***********************************************************************
3421 * SetupDiOpenClassRegKey (SETUPAPI.@)
3423 HKEY WINAPI SetupDiOpenClassRegKey(
3424 const GUID* ClassGuid,
3425 REGSAM samDesired)
3427 return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3428 DIOCR_INSTALLER, NULL, NULL);
3432 /***********************************************************************
3433 * SetupDiOpenClassRegKeyExA (SETUPAPI.@)
3435 HKEY WINAPI SetupDiOpenClassRegKeyExA(
3436 const GUID* ClassGuid,
3437 REGSAM samDesired,
3438 DWORD Flags,
3439 PCSTR MachineName,
3440 PVOID Reserved)
3442 PWSTR MachineNameW = NULL;
3443 HKEY hKey;
3445 TRACE("\n");
3447 if (MachineName)
3449 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
3450 if (MachineNameW == NULL)
3451 return INVALID_HANDLE_VALUE;
3454 hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3455 Flags, MachineNameW, Reserved);
3457 MyFree(MachineNameW);
3459 return hKey;
3463 /***********************************************************************
3464 * SetupDiOpenClassRegKeyExW (SETUPAPI.@)
3466 HKEY WINAPI SetupDiOpenClassRegKeyExW(
3467 const GUID* ClassGuid,
3468 REGSAM samDesired,
3469 DWORD Flags,
3470 PCWSTR MachineName,
3471 PVOID Reserved)
3473 HKEY hClassesKey;
3474 HKEY key;
3475 LPCWSTR lpKeyName;
3476 LONG l;
3478 if (MachineName && *MachineName)
3480 FIXME("Remote access not supported yet!\n");
3481 return INVALID_HANDLE_VALUE;
3484 if (Flags == DIOCR_INSTALLER)
3486 lpKeyName = ControlClass;
3488 else if (Flags == DIOCR_INTERFACE)
3490 lpKeyName = DeviceClasses;
3492 else
3494 ERR("Invalid Flags parameter!\n");
3495 SetLastError(ERROR_INVALID_PARAMETER);
3496 return INVALID_HANDLE_VALUE;
3499 if (!ClassGuid)
3501 if ((l = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3502 lpKeyName,
3504 samDesired,
3505 &hClassesKey)))
3507 SetLastError(l);
3508 hClassesKey = INVALID_HANDLE_VALUE;
3510 key = hClassesKey;
3512 else
3514 WCHAR bracedGuidString[39];
3516 SETUPDI_GuidToString(ClassGuid, bracedGuidString);
3518 if (!(l = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3519 lpKeyName,
3521 samDesired,
3522 &hClassesKey)))
3524 if ((l = RegOpenKeyExW(hClassesKey,
3525 bracedGuidString,
3527 samDesired,
3528 &key)))
3530 SetLastError(l);
3531 key = INVALID_HANDLE_VALUE;
3533 RegCloseKey(hClassesKey);
3535 else
3537 SetLastError(l);
3538 key = INVALID_HANDLE_VALUE;
3541 return key;
3544 /***********************************************************************
3545 * SetupDiOpenDeviceInfoA (SETUPAPI.@)
3547 BOOL WINAPI SetupDiOpenDeviceInfoA(HDEVINFO devinfo, PCSTR instance_id, HWND hwnd_parent, DWORD flags,
3548 PSP_DEVINFO_DATA device_data)
3550 WCHAR instance_idW[MAX_DEVICE_ID_LEN];
3552 TRACE("%p %s %p 0x%08lx %p\n", devinfo, debugstr_a(instance_id), hwnd_parent, flags, device_data);
3554 if (!instance_id || strlen(instance_id) >= MAX_DEVICE_ID_LEN)
3556 SetLastError(ERROR_INVALID_PARAMETER);
3557 return FALSE;
3560 MultiByteToWideChar(CP_ACP, 0, instance_id, -1, instance_idW, ARRAY_SIZE(instance_idW));
3561 return SetupDiOpenDeviceInfoW(devinfo, instance_idW, hwnd_parent, flags, device_data);
3564 /***********************************************************************
3565 * SetupDiOpenDeviceInfoW (SETUPAPI.@)
3567 BOOL WINAPI SetupDiOpenDeviceInfoW(HDEVINFO devinfo, PCWSTR instance_id, HWND hwnd_parent, DWORD flags,
3568 PSP_DEVINFO_DATA device_data)
3570 struct DeviceInfoSet *set;
3571 struct device *device;
3572 WCHAR classW[40];
3573 GUID guid;
3574 HKEY enumKey = NULL;
3575 HKEY instanceKey = NULL;
3576 DWORD phantom;
3577 DWORD size;
3578 DWORD error = ERROR_NO_SUCH_DEVINST;
3580 TRACE("%p %s %p 0x%08lx %p\n", devinfo, debugstr_w(instance_id), hwnd_parent, flags, device_data);
3582 if (!(set = get_device_set(devinfo)))
3583 return FALSE;
3585 if (!instance_id)
3587 SetLastError(ERROR_INVALID_PARAMETER);
3588 return FALSE;
3591 if (hwnd_parent)
3592 FIXME("hwnd_parent unsupported\n");
3594 if (flags)
3595 FIXME("flags unsupported: 0x%08lx\n", flags);
3597 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &enumKey, NULL);
3598 /* Instance needs to be already existent in registry, if not, report ERROR_NO_SUCH_DEVINST */
3599 if (RegOpenKeyExW(enumKey, instance_id, 0, KEY_READ, &instanceKey))
3600 goto done;
3602 /* If it's an unregistered instance, aka phantom instance, report ERROR_NO_SUCH_DEVINST */
3603 size = sizeof(phantom);
3604 if (!RegQueryValueExW(instanceKey, Phantom, NULL, NULL, (BYTE *)&phantom, &size))
3605 goto done;
3607 /* Check class GUID */
3608 size = sizeof(classW);
3609 if (RegQueryValueExW(instanceKey, ClassGUID, NULL, NULL, (BYTE *)classW, &size))
3610 goto done;
3612 classW[37] = 0;
3613 UuidFromStringW(&classW[1], &guid);
3615 if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) && !IsEqualGUID(&guid, &set->ClassGuid))
3617 error = ERROR_CLASS_MISMATCH;
3618 goto done;
3621 if (!(device = create_device(set, &guid, instance_id, FALSE)))
3622 goto done;
3624 if (!device_data || device_data->cbSize == sizeof(SP_DEVINFO_DATA))
3626 if (device_data)
3627 copy_device_data(device_data, device);
3628 error = NO_ERROR;
3630 else
3631 error = ERROR_INVALID_USER_BUFFER;
3633 done:
3634 RegCloseKey(instanceKey);
3635 RegCloseKey(enumKey);
3636 SetLastError(error);
3637 return !error;
3640 /***********************************************************************
3641 * SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
3643 BOOL WINAPI SetupDiOpenDeviceInterfaceW(
3644 HDEVINFO DeviceInfoSet,
3645 PCWSTR DevicePath,
3646 DWORD OpenFlags,
3647 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3649 FIXME("%p %s %08lx %p\n",
3650 DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
3651 return FALSE;
3654 /***********************************************************************
3655 * SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
3657 BOOL WINAPI SetupDiOpenDeviceInterfaceA(
3658 HDEVINFO DeviceInfoSet,
3659 PCSTR DevicePath,
3660 DWORD OpenFlags,
3661 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3663 FIXME("%p %s %08lx %p\n", DeviceInfoSet,
3664 debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
3665 return FALSE;
3668 /***********************************************************************
3669 * SetupDiOpenDeviceInterfaceRegKey (SETUPAPI.@)
3671 HKEY WINAPI SetupDiOpenDeviceInterfaceRegKey(HDEVINFO devinfo, PSP_DEVICE_INTERFACE_DATA iface_data,
3672 DWORD reserved, REGSAM access)
3674 struct device_iface *iface;
3675 LSTATUS lr;
3676 HKEY key;
3678 TRACE("devinfo %p, iface_data %p, reserved %ld, access %#lx.\n", devinfo, iface_data, reserved, access);
3680 if (!(iface = get_device_iface(devinfo, iface_data)))
3681 return INVALID_HANDLE_VALUE;
3683 lr = RegOpenKeyExW(iface->refstr_key, DeviceParameters, 0, access, &key);
3684 if (lr)
3686 SetLastError(lr);
3687 return INVALID_HANDLE_VALUE;
3690 return key;
3693 /***********************************************************************
3694 * SetupDiSetClassInstallParamsA (SETUPAPI.@)
3696 BOOL WINAPI SetupDiSetClassInstallParamsA(
3697 HDEVINFO DeviceInfoSet,
3698 PSP_DEVINFO_DATA DeviceInfoData,
3699 PSP_CLASSINSTALL_HEADER ClassInstallParams,
3700 DWORD ClassInstallParamsSize)
3702 FIXME("%p %p %x %lu\n",DeviceInfoSet, DeviceInfoData,
3703 ClassInstallParams->InstallFunction, ClassInstallParamsSize);
3704 return FALSE;
3707 /***********************************************************************
3708 * SetupDiSetClassInstallParamsW (SETUPAPI.@)
3710 BOOL WINAPI SetupDiSetClassInstallParamsW(
3711 HDEVINFO DeviceInfoSet,
3712 PSP_DEVINFO_DATA DeviceInfoData,
3713 PSP_CLASSINSTALL_HEADER ClassInstallParams,
3714 DWORD ClassInstallParamsSize)
3716 FIXME("%p %p %x %lu\n",DeviceInfoSet, DeviceInfoData,
3717 ClassInstallParams->InstallFunction, ClassInstallParamsSize);
3718 return FALSE;
3721 static BOOL call_coinstallers(WCHAR *list, DI_FUNCTION function, HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
3723 DWORD (CALLBACK *coinst_proc)(DI_FUNCTION, HDEVINFO, SP_DEVINFO_DATA *, COINSTALLER_CONTEXT_DATA *);
3724 COINSTALLER_CONTEXT_DATA coinst_ctx;
3725 WCHAR *p, *procnameW;
3726 HMODULE module;
3727 char *procname;
3728 DWORD ret;
3730 for (p = list; *p; p += lstrlenW(p) + 1)
3732 TRACE("Found co-installer %s.\n", debugstr_w(p));
3733 if ((procnameW = wcschr(p, ',')))
3734 *procnameW = 0;
3736 if ((module = LoadLibraryExW(p, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32)))
3738 if (procnameW)
3740 procname = strdupWtoA(procnameW + 1);
3741 coinst_proc = (void *)GetProcAddress(module, procname);
3742 free(procname);
3744 else
3745 coinst_proc = (void *)GetProcAddress(module, "CoDeviceInstall");
3746 if (coinst_proc)
3748 memset(&coinst_ctx, 0, sizeof(coinst_ctx));
3749 TRACE("Calling co-installer %p.\n", coinst_proc);
3750 ret = coinst_proc(function, devinfo, device_data, &coinst_ctx);
3751 TRACE("Co-installer %p returned %#lx.\n", coinst_proc, ret);
3752 if (ret == ERROR_DI_POSTPROCESSING_REQUIRED)
3753 FIXME("Co-installer postprocessing not implemented.\n");
3754 else if (ret)
3756 ERR("Co-installer returned error %#lx.\n", ret);
3757 FreeLibrary(module);
3758 SetLastError(ret);
3759 return FALSE;
3762 FreeLibrary(module);
3766 return TRUE;
3769 /***********************************************************************
3770 * SetupDiCallClassInstaller (SETUPAPI.@)
3772 BOOL WINAPI SetupDiCallClassInstaller(DI_FUNCTION function, HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
3774 static const WCHAR class_coinst_pathW[] = {'S','y','s','t','e','m',
3775 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
3776 '\\','C','o','n','t','r','o','l',
3777 '\\','C','o','D','e','v','i','c','e','I','n','s','t','a','l','l','e','r','s',0};
3778 static const WCHAR coinstallers32W[] = {'C','o','I','n','s','t','a','l','l','e','r','s','3','2',0};
3779 static const WCHAR installer32W[] = {'I','n','s','t','a','l','l','e','r','3','2',0};
3780 DWORD (CALLBACK *classinst_proc)(DI_FUNCTION, HDEVINFO, SP_DEVINFO_DATA *);
3781 DWORD ret = ERROR_DI_DO_DEFAULT;
3782 HKEY class_key, coinst_key;
3783 WCHAR *path, *procnameW;
3784 struct device *device;
3785 WCHAR guidstr[39];
3786 BOOL coret = TRUE;
3787 HMODULE module;
3788 char *procname;
3789 DWORD size;
3791 TRACE("function %#x, devinfo %p, device_data %p.\n", function, devinfo, device_data);
3793 if (!(device = get_device(devinfo, device_data)))
3794 return FALSE;
3796 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, class_coinst_pathW, 0, KEY_READ, &coinst_key))
3798 SETUPDI_GuidToString(&device->class, guidstr);
3799 if (!RegGetValueW(coinst_key, NULL, guidstr, RRF_RT_REG_MULTI_SZ, NULL, NULL, &size))
3801 path = malloc(size);
3802 if (!RegGetValueW(coinst_key, NULL, guidstr, RRF_RT_REG_MULTI_SZ, NULL, path, &size))
3803 coret = call_coinstallers(path, function, devinfo, device_data);
3804 free(path);
3806 RegCloseKey(coinst_key);
3809 if (!coret)
3810 return FALSE;
3812 if (!open_driver_key(device, KEY_READ, &coinst_key))
3814 if (!RegGetValueW(coinst_key, NULL, coinstallers32W, RRF_RT_REG_MULTI_SZ, NULL, NULL, &size))
3816 path = malloc(size);
3817 if (!RegGetValueW(coinst_key, NULL, coinstallers32W, RRF_RT_REG_MULTI_SZ, NULL, path, &size))
3818 coret = call_coinstallers(path, function, devinfo, device_data);
3819 free(path);
3821 RegCloseKey(coinst_key);
3824 if ((class_key = SetupDiOpenClassRegKey(&device->class, KEY_READ)) != INVALID_HANDLE_VALUE)
3826 if (!RegGetValueW(class_key, NULL, installer32W, RRF_RT_REG_SZ, NULL, NULL, &size))
3828 path = malloc(size);
3829 if (!RegGetValueW(class_key, NULL, installer32W, RRF_RT_REG_SZ, NULL, path, &size))
3831 TRACE("Found class installer %s.\n", debugstr_w(path));
3832 if ((procnameW = wcschr(path, ',')))
3833 *procnameW = 0;
3835 if ((module = LoadLibraryExW(path, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32)))
3837 if (procnameW)
3839 procname = strdupWtoA(procnameW + 1);
3840 classinst_proc = (void *)GetProcAddress(module, procname);
3841 free(procname);
3843 else
3844 classinst_proc = (void *)GetProcAddress(module, "ClassInstall");
3845 if (classinst_proc)
3847 TRACE("Calling class installer %p.\n", classinst_proc);
3848 ret = classinst_proc(function, devinfo, device_data);
3849 TRACE("Class installer %p returned %#lx.\n", classinst_proc, ret);
3851 FreeLibrary(module);
3854 free(path);
3856 RegCloseKey(class_key);
3859 if (ret == ERROR_DI_DO_DEFAULT)
3861 switch (function)
3863 case DIF_REGISTERDEVICE:
3864 return SetupDiRegisterDeviceInfo(devinfo, device_data, 0, NULL, NULL, NULL);
3865 case DIF_REMOVE:
3866 return SetupDiRemoveDevice(devinfo, device_data);
3867 case DIF_SELECTBESTCOMPATDRV:
3868 return SetupDiSelectBestCompatDrv(devinfo, device_data);
3869 case DIF_REGISTER_COINSTALLERS:
3870 return SetupDiRegisterCoDeviceInstallers(devinfo, device_data);
3871 case DIF_INSTALLDEVICEFILES:
3872 return SetupDiInstallDriverFiles(devinfo, device_data);
3873 case DIF_INSTALLINTERFACES:
3874 return SetupDiInstallDeviceInterfaces(devinfo, device_data);
3875 case DIF_INSTALLDEVICE:
3876 return SetupDiInstallDevice(devinfo, device_data);
3877 case DIF_FINISHINSTALL_ACTION:
3878 case DIF_PROPERTYCHANGE:
3879 case DIF_SELECTDEVICE:
3880 case DIF_UNREMOVE:
3881 FIXME("Unhandled function %#x.\n", function);
3885 if (ret) SetLastError(ret);
3886 return !ret;
3889 /***********************************************************************
3890 * SetupDiGetDeviceInstallParamsW (SETUPAPI.@)
3892 BOOL WINAPI SetupDiGetDeviceInstallParamsW(HDEVINFO devinfo,
3893 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_W *params)
3895 struct device *device;
3897 TRACE("devinfo %p, device_data %p, params %p.\n", devinfo, device_data, params);
3899 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
3901 SetLastError(ERROR_INVALID_USER_BUFFER);
3902 return FALSE;
3905 if (!(device = get_device(devinfo, device_data)))
3906 return FALSE;
3908 *params = device->params;
3910 return TRUE;
3913 /***********************************************************************
3914 * SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
3916 BOOL WINAPI SetupDiGetDeviceInstallParamsA(HDEVINFO devinfo,
3917 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_A *params)
3919 SP_DEVINSTALL_PARAMS_W paramsW;
3920 BOOL ret;
3922 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
3924 SetLastError(ERROR_INVALID_USER_BUFFER);
3925 return FALSE;
3928 paramsW.cbSize = sizeof(paramsW);
3929 ret = SetupDiGetDeviceInstallParamsW(devinfo, device_data, &paramsW);
3930 params->Flags = paramsW.Flags;
3931 params->FlagsEx = paramsW.FlagsEx;
3932 params->hwndParent = paramsW.hwndParent;
3933 params->InstallMsgHandler = paramsW.InstallMsgHandler;
3934 params->InstallMsgHandlerContext = paramsW.InstallMsgHandlerContext;
3935 params->FileQueue = paramsW.FileQueue;
3936 params->ClassInstallReserved = paramsW.ClassInstallReserved;
3937 params->Reserved = paramsW.Reserved;
3938 WideCharToMultiByte(CP_ACP, 0, paramsW.DriverPath, -1, params->DriverPath, sizeof(params->DriverPath), NULL, NULL);
3940 return ret;
3943 /***********************************************************************
3944 * SetupDiSetDeviceInstallParamsA (SETUPAPI.@)
3946 BOOL WINAPI SetupDiSetDeviceInstallParamsA(HDEVINFO devinfo,
3947 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_A *params)
3949 SP_DEVINSTALL_PARAMS_W paramsW;
3951 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
3953 SetLastError(ERROR_INVALID_USER_BUFFER);
3954 return FALSE;
3957 paramsW.cbSize = sizeof(paramsW);
3958 paramsW.Flags = params->Flags;
3959 paramsW.FlagsEx = params->FlagsEx;
3960 paramsW.hwndParent = params->hwndParent;
3961 paramsW.InstallMsgHandler = params->InstallMsgHandler;
3962 paramsW.InstallMsgHandlerContext = params->InstallMsgHandlerContext;
3963 paramsW.FileQueue = params->FileQueue;
3964 paramsW.ClassInstallReserved = params->ClassInstallReserved;
3965 paramsW.Reserved = params->Reserved;
3966 MultiByteToWideChar(CP_ACP, 0, params->DriverPath, -1, paramsW.DriverPath, ARRAY_SIZE(paramsW.DriverPath));
3968 return SetupDiSetDeviceInstallParamsW(devinfo, device_data, &paramsW);
3971 /***********************************************************************
3972 * SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
3974 BOOL WINAPI SetupDiSetDeviceInstallParamsW(HDEVINFO devinfo,
3975 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_W *params)
3977 struct device *device;
3979 TRACE("devinfo %p, device_data %p, params %p.\n", devinfo, device_data, params);
3981 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
3983 SetLastError(ERROR_INVALID_USER_BUFFER);
3984 return FALSE;
3987 if (!(device = get_device(devinfo, device_data)))
3988 return FALSE;
3990 device->params = *params;
3992 return TRUE;
3995 BOOL WINAPI SetupDiSetDevicePropertyW(HDEVINFO devinfo, PSP_DEVINFO_DATA device_data, const DEVPROPKEY *key,
3996 DEVPROPTYPE type, const BYTE *buffer, DWORD size, DWORD flags)
3998 static const WCHAR propertiesW[] = {'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's', 0};
3999 static const WCHAR formatW[] = {'\\', '%', '0', '4', 'X', 0};
4000 struct device *device;
4001 HKEY properties_hkey, property_hkey;
4002 WCHAR property_hkey_path[44];
4003 LSTATUS ls;
4005 TRACE("%p %p %p %#lx %p %ld %#lx\n", devinfo, device_data, key, type, buffer, size, flags);
4007 if (!(device = get_device(devinfo, device_data)))
4008 return FALSE;
4010 if (!key || !is_valid_property_type(type)
4011 || (buffer && !size && !(type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL))
4012 || (buffer && size && (type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL)))
4014 SetLastError(ERROR_INVALID_DATA);
4015 return FALSE;
4018 if (size && !buffer)
4020 SetLastError(ERROR_INVALID_USER_BUFFER);
4021 return FALSE;
4024 if (flags)
4026 SetLastError(ERROR_INVALID_FLAGS);
4027 return FALSE;
4030 ls = RegCreateKeyExW(device->key, propertiesW, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &properties_hkey, NULL);
4031 if (ls)
4033 SetLastError(ls);
4034 return FALSE;
4037 SETUPDI_GuidToString(&key->fmtid, property_hkey_path);
4038 swprintf(property_hkey_path + 38, ARRAY_SIZE(property_hkey_path) - 38, formatW, key->pid);
4040 if (type == DEVPROP_TYPE_EMPTY)
4042 ls = RegDeleteKeyW(properties_hkey, property_hkey_path);
4043 RegCloseKey(properties_hkey);
4044 SetLastError(ls == ERROR_FILE_NOT_FOUND ? ERROR_NOT_FOUND : ls);
4045 return !ls;
4047 else if (type == DEVPROP_TYPE_NULL)
4049 if (!(ls = RegOpenKeyW(properties_hkey, property_hkey_path, &property_hkey)))
4051 ls = RegDeleteValueW(property_hkey, NULL);
4052 RegCloseKey(property_hkey);
4055 RegCloseKey(properties_hkey);
4056 SetLastError(ls == ERROR_FILE_NOT_FOUND ? ERROR_NOT_FOUND : ls);
4057 return !ls;
4059 else
4061 if (!(ls = RegCreateKeyExW(properties_hkey, property_hkey_path, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL,
4062 &property_hkey, NULL)))
4064 ls = RegSetValueExW(property_hkey, NULL, 0, 0xffff0000 | (0xffff & type), buffer, size);
4065 RegCloseKey(property_hkey);
4068 RegCloseKey(properties_hkey);
4069 SetLastError(ls);
4070 return !ls;
4074 /***********************************************************************
4075 * SetupDiOpenDevRegKey (SETUPAPI.@)
4077 HKEY WINAPI SetupDiOpenDevRegKey(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4078 DWORD Scope, DWORD HwProfile, DWORD KeyType, REGSAM samDesired)
4080 struct device *device;
4081 HKEY key = INVALID_HANDLE_VALUE;
4082 LONG l;
4084 TRACE("devinfo %p, device_data %p, scope %ld, profile %ld, type %ld, access %#lx.\n",
4085 devinfo, device_data, Scope, HwProfile, KeyType, samDesired);
4087 if (!(device = get_device(devinfo, device_data)))
4088 return INVALID_HANDLE_VALUE;
4090 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
4092 SetLastError(ERROR_INVALID_FLAGS);
4093 return INVALID_HANDLE_VALUE;
4095 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
4097 SetLastError(ERROR_INVALID_FLAGS);
4098 return INVALID_HANDLE_VALUE;
4101 if (device->phantom)
4103 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
4104 return INVALID_HANDLE_VALUE;
4106 if (Scope != DICS_FLAG_GLOBAL)
4107 FIXME("unimplemented for scope %ld\n", Scope);
4108 switch (KeyType)
4110 case DIREG_DEV:
4111 l = RegOpenKeyExW(device->key, DeviceParameters, 0, samDesired, &key);
4112 break;
4113 case DIREG_DRV:
4114 l = open_driver_key(device, samDesired, &key);
4115 break;
4116 default:
4117 FIXME("Unhandled type %#lx.\n", KeyType);
4118 l = ERROR_CALL_NOT_IMPLEMENTED;
4120 SetLastError(l == ERROR_FILE_NOT_FOUND ? ERROR_KEY_DOES_NOT_EXIST : l);
4121 return l ? INVALID_HANDLE_VALUE : key;
4124 /***********************************************************************
4125 * SetupDiDeleteDevRegKey (SETUPAPI.@)
4127 BOOL WINAPI SetupDiDeleteDevRegKey(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4128 DWORD Scope, DWORD HwProfile, DWORD KeyType)
4130 struct device *device;
4131 LONG l;
4133 TRACE("devinfo %p, device_data %p, scope %ld, profile %ld, type %ld.\n",
4134 devinfo, device_data, Scope, HwProfile, KeyType);
4136 if (!(device = get_device(devinfo, device_data)))
4137 return FALSE;
4139 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
4141 SetLastError(ERROR_INVALID_FLAGS);
4142 return FALSE;
4144 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV && KeyType != DIREG_BOTH)
4146 SetLastError(ERROR_INVALID_FLAGS);
4147 return FALSE;
4150 if (device->phantom)
4152 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
4153 return FALSE;
4155 if (Scope != DICS_FLAG_GLOBAL)
4156 FIXME("unimplemented for scope %ld\n", Scope);
4157 switch (KeyType)
4159 case DIREG_DRV:
4160 l = delete_driver_key(device);
4161 break;
4162 case DIREG_BOTH:
4163 if ((l = delete_driver_key(device)))
4164 break;
4165 /* fall through */
4166 case DIREG_DEV:
4167 l = RegDeleteKeyW(device->key, DeviceParameters);
4168 break;
4169 default:
4170 FIXME("Unhandled type %#lx.\n", KeyType);
4171 l = ERROR_CALL_NOT_IMPLEMENTED;
4173 SetLastError(l);
4174 return !l;
4177 /***********************************************************************
4178 * CM_Get_Device_IDA (SETUPAPI.@)
4180 CONFIGRET WINAPI CM_Get_Device_IDA(DEVINST devnode, char *buffer, ULONG len, ULONG flags)
4182 struct device *device = get_devnode_device(devnode);
4184 TRACE("%lu, %p, %lu, %#lx\n", devnode, buffer, len, flags);
4186 if (!device)
4187 return CR_NO_SUCH_DEVINST;
4189 WideCharToMultiByte(CP_ACP, 0, device->instanceId, -1, buffer, len, 0, 0);
4190 TRACE("Returning %s\n", debugstr_a(buffer));
4191 return CR_SUCCESS;
4194 /***********************************************************************
4195 * CM_Get_Device_IDW (SETUPAPI.@)
4197 CONFIGRET WINAPI CM_Get_Device_IDW(DEVINST devnode, WCHAR *buffer, ULONG len, ULONG flags)
4199 struct device *device = get_devnode_device(devnode);
4201 TRACE("%lu, %p, %lu, %#lx\n", devnode, buffer, len, flags);
4203 if (!device)
4204 return CR_NO_SUCH_DEVINST;
4206 lstrcpynW(buffer, device->instanceId, len);
4207 TRACE("Returning %s\n", debugstr_w(buffer));
4208 return CR_SUCCESS;
4211 /***********************************************************************
4212 * CM_Get_Device_ID_Size (SETUPAPI.@)
4214 CONFIGRET WINAPI CM_Get_Device_ID_Size(ULONG *len, DEVINST devnode, ULONG flags)
4216 struct device *device = get_devnode_device(devnode);
4218 TRACE("%p, %lu, %#lx\n", len, devnode, flags);
4220 if (!device)
4221 return CR_NO_SUCH_DEVINST;
4223 *len = lstrlenW(device->instanceId);
4224 return CR_SUCCESS;
4227 /***********************************************************************
4228 * SetupDiGetINFClassA (SETUPAPI.@)
4230 BOOL WINAPI SetupDiGetINFClassA(PCSTR inf, LPGUID class_guid, PSTR class_name,
4231 DWORD size, PDWORD required_size)
4233 BOOL retval;
4234 DWORD required_sizeA, required_sizeW;
4235 PWSTR class_nameW = NULL;
4236 UNICODE_STRING infW;
4238 if (inf)
4240 if (!RtlCreateUnicodeStringFromAsciiz(&infW, inf))
4242 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4243 return FALSE;
4246 else
4247 infW.Buffer = NULL;
4249 if (class_name && size)
4251 if (!(class_nameW = malloc(size * sizeof(WCHAR))))
4253 RtlFreeUnicodeString(&infW);
4254 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4255 return FALSE;
4259 retval = SetupDiGetINFClassW(infW.Buffer, class_guid, class_nameW, size, &required_sizeW);
4261 if (retval)
4263 required_sizeA = WideCharToMultiByte( CP_ACP, 0, class_nameW, required_sizeW,
4264 class_name, size, NULL, NULL);
4266 if(required_size) *required_size = required_sizeA;
4268 else
4269 if(required_size) *required_size = required_sizeW;
4271 free(class_nameW);
4272 RtlFreeUnicodeString(&infW);
4273 return retval;
4276 /***********************************************************************
4277 * SetupDiGetINFClassW (SETUPAPI.@)
4279 BOOL WINAPI SetupDiGetINFClassW(PCWSTR inf, LPGUID class_guid, PWSTR class_name,
4280 DWORD size, PDWORD required_size)
4282 BOOL have_guid, have_name;
4283 DWORD dret;
4284 WCHAR buffer[MAX_PATH];
4286 if (!inf)
4288 SetLastError(ERROR_INVALID_PARAMETER);
4289 return FALSE;
4292 if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(inf))
4294 FIXME("%s not found. Searching via DevicePath not implemented\n", debugstr_w(inf));
4295 SetLastError(ERROR_FILE_NOT_FOUND);
4296 return FALSE;
4299 if (!class_guid || !class_name || !size)
4301 SetLastError(ERROR_INVALID_PARAMETER);
4302 return FALSE;
4305 if (!GetPrivateProfileStringW(Version, Signature, NULL, buffer, MAX_PATH, inf))
4306 return FALSE;
4308 if (lstrcmpiW(buffer, Chicago) && lstrcmpiW(buffer, WindowsNT))
4309 return FALSE;
4311 buffer[0] = '\0';
4312 have_guid = 0 < GetPrivateProfileStringW(Version, ClassGUID, NULL, buffer, MAX_PATH, inf);
4313 if (have_guid)
4315 buffer[lstrlenW(buffer)-1] = 0;
4316 if (RPC_S_OK != UuidFromStringW(buffer + 1, class_guid))
4318 FIXME("failed to convert \"%s\" into a guid\n", debugstr_w(buffer));
4319 SetLastError(ERROR_INVALID_PARAMETER);
4320 return FALSE;
4324 buffer[0] = '\0';
4325 dret = GetPrivateProfileStringW(Version, Class, NULL, buffer, MAX_PATH, inf);
4326 have_name = 0 < dret;
4328 if (dret >= MAX_PATH -1) FIXME("buffer might be too small\n");
4329 if (have_guid && !have_name)
4331 class_name[0] = '\0';
4332 FIXME("class name lookup via guid not implemented\n");
4335 if (have_name)
4337 if (dret < size) lstrcpyW(class_name, buffer);
4338 else
4340 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4341 have_name = FALSE;
4345 if (required_size) *required_size = dret + ((dret) ? 1 : 0);
4347 return (have_guid || have_name);
4350 static LSTATUS get_device_property(struct device *device, const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type,
4351 BYTE *prop_buff, DWORD prop_buff_size, DWORD *required_size, DWORD flags)
4353 WCHAR key_path[55] = L"Properties\\";
4354 HKEY hkey;
4355 DWORD value_type;
4356 DWORD value_size = 0;
4357 LSTATUS ls;
4359 if (!prop_key)
4360 return ERROR_INVALID_DATA;
4362 if (!prop_type || (!prop_buff && prop_buff_size))
4363 return ERROR_INVALID_USER_BUFFER;
4365 if (flags)
4366 return ERROR_INVALID_FLAGS;
4368 SETUPDI_GuidToString(&prop_key->fmtid, key_path + 11);
4369 swprintf(key_path + 49, ARRAY_SIZE(key_path) - 49, L"\\%04X", prop_key->pid);
4371 ls = RegOpenKeyExW(device->key, key_path, 0, KEY_QUERY_VALUE, &hkey);
4372 if (!ls)
4374 value_size = prop_buff_size;
4375 ls = RegQueryValueExW(hkey, NULL, NULL, &value_type, prop_buff, &value_size);
4376 RegCloseKey(hkey);
4379 switch (ls)
4381 case NO_ERROR:
4382 case ERROR_MORE_DATA:
4383 *prop_type = 0xffff & value_type;
4384 ls = (ls == ERROR_MORE_DATA || !prop_buff) ? ERROR_INSUFFICIENT_BUFFER : NO_ERROR;
4385 break;
4386 case ERROR_FILE_NOT_FOUND:
4387 *prop_type = DEVPROP_TYPE_EMPTY;
4388 value_size = 0;
4389 ls = ERROR_NOT_FOUND;
4390 break;
4391 default:
4392 *prop_type = DEVPROP_TYPE_EMPTY;
4393 value_size = 0;
4394 FIXME("Unhandled error %#lx\n", ls);
4395 break;
4398 if (required_size)
4399 *required_size = value_size;
4401 return ls;
4404 /***********************************************************************
4405 * SetupDiGetDevicePropertyW (SETUPAPI.@)
4407 BOOL WINAPI SetupDiGetDevicePropertyW(HDEVINFO devinfo, PSP_DEVINFO_DATA device_data,
4408 const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type, BYTE *prop_buff,
4409 DWORD prop_buff_size, DWORD *required_size, DWORD flags)
4411 struct device *device;
4412 LSTATUS ls;
4414 TRACE("%p, %p, %p, %p, %p, %ld, %p, %#lx\n", devinfo, device_data, prop_key, prop_type, prop_buff, prop_buff_size,
4415 required_size, flags);
4417 if (!(device = get_device(devinfo, device_data)))
4418 return FALSE;
4420 ls = get_device_property(device, prop_key, prop_type, prop_buff, prop_buff_size, required_size, flags);
4422 SetLastError(ls);
4423 return !ls;
4426 /***********************************************************************
4427 * CM_Get_DevNode_Property_ExW (SETUPAPI.@)
4429 CONFIGRET WINAPI CM_Get_DevNode_Property_ExW(DEVINST devnode, const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type,
4430 BYTE *prop_buff, ULONG *prop_buff_size, ULONG flags, HMACHINE machine)
4432 struct device *device = get_devnode_device(devnode);
4433 LSTATUS ls;
4435 TRACE("%lu, %p, %p, %p, %p, %#lx, %p\n", devnode, prop_key, prop_type, prop_buff, prop_buff_size,
4436 flags, machine);
4438 if (machine)
4439 return CR_MACHINE_UNAVAILABLE;
4441 if (!device)
4442 return CR_NO_SUCH_DEVINST;
4444 if (!prop_buff_size)
4445 return CR_INVALID_POINTER;
4447 ls = get_device_property(device, prop_key, prop_type, prop_buff, *prop_buff_size, prop_buff_size, flags);
4448 switch (ls)
4450 case NO_ERROR:
4451 return CR_SUCCESS;
4452 case ERROR_INVALID_DATA:
4453 return CR_INVALID_DATA;
4454 case ERROR_INVALID_USER_BUFFER:
4455 return CR_INVALID_POINTER;
4456 case ERROR_INVALID_FLAGS:
4457 return CR_INVALID_FLAG;
4458 case ERROR_INSUFFICIENT_BUFFER:
4459 return CR_BUFFER_SMALL;
4460 case ERROR_NOT_FOUND:
4461 return CR_NO_SUCH_VALUE;
4463 return CR_FAILURE;
4466 /***********************************************************************
4467 * CM_Get_DevNode_PropertyW (SETUPAPI.@)
4469 CONFIGRET WINAPI CM_Get_DevNode_PropertyW(DEVINST dev, const DEVPROPKEY *key, DEVPROPTYPE *type,
4470 PVOID buf, PULONG len, ULONG flags)
4472 return CM_Get_DevNode_Property_ExW(dev, key, type, buf, len, flags, NULL);
4475 /***********************************************************************
4476 * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
4478 BOOL WINAPI SetupDiInstallDeviceInterfaces(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4480 WCHAR section_ext[LINE_LEN], iface_section[LINE_LEN], refstr[LINE_LEN], guidstr[39];
4481 UINT install_flags = SPINST_ALL;
4482 struct device_iface *iface;
4483 struct device *device;
4484 struct driver *driver;
4485 void *callback_ctx;
4486 GUID iface_guid;
4487 INFCONTEXT ctx;
4488 HKEY iface_key;
4489 HINF hinf;
4490 LONG l;
4492 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
4494 if (!(device = get_device(devinfo, device_data)))
4495 return FALSE;
4497 if (!(driver = device->selected_driver))
4499 ERR("No driver selected for device %p.\n", devinfo);
4500 SetLastError(ERROR_NO_DRIVER_SELECTED);
4501 return FALSE;
4504 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4505 return FALSE;
4507 SetupDiGetActualSectionToInstallW(hinf, driver->section, section_ext, ARRAY_SIZE(section_ext), NULL, NULL);
4509 if (device->params.Flags & DI_NOFILECOPY)
4510 install_flags &= ~SPINST_FILES;
4512 callback_ctx = SetupInitDefaultQueueCallback(NULL);
4514 lstrcatW(section_ext, dotInterfaces);
4515 if (SetupFindFirstLineW(hinf, section_ext, AddInterface, &ctx))
4517 do {
4518 SetupGetStringFieldW(&ctx, 1, guidstr, ARRAY_SIZE(guidstr), NULL);
4519 SetupGetStringFieldW(&ctx, 2, refstr, ARRAY_SIZE(refstr), NULL);
4520 guidstr[37] = 0;
4521 UuidFromStringW(&guidstr[1], &iface_guid);
4523 if (!(iface = SETUPDI_CreateDeviceInterface(device, &iface_guid, refstr)))
4525 ERR("Failed to create device interface, error %#lx.\n", GetLastError());
4526 continue;
4529 if ((l = create_iface_key(iface, KEY_ALL_ACCESS, &iface_key)))
4531 ERR("Failed to create interface key, error %lu.\n", l);
4532 continue;
4535 SetupGetStringFieldW(&ctx, 3, iface_section, ARRAY_SIZE(iface_section), NULL);
4536 SetupInstallFromInfSectionW(NULL, hinf, iface_section, install_flags, iface_key,
4537 NULL, SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
4539 RegCloseKey(iface_key);
4540 } while (SetupFindNextMatchLineW(&ctx, AddInterface, &ctx));
4543 SetupTermDefaultQueueCallback(callback_ctx);
4545 SetupCloseInfFile(hinf);
4546 return TRUE;
4549 /***********************************************************************
4550 * SetupDiRegisterCoDeviceInstallers (SETUPAPI.@)
4552 BOOL WINAPI SetupDiRegisterCoDeviceInstallers(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4554 static const WCHAR coinstallersW[] = {'.','C','o','I','n','s','t','a','l','l','e','r','s',0};
4555 WCHAR coinst_key_ext[LINE_LEN];
4556 struct device *device;
4557 struct driver *driver;
4558 void *callback_ctx;
4559 HKEY driver_key;
4560 HINF hinf;
4561 LONG l;
4563 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
4565 if (!(device = get_device(devinfo, device_data)))
4566 return FALSE;
4568 if (!(driver = device->selected_driver))
4570 ERR("No driver selected for device %p.\n", devinfo);
4571 SetLastError(ERROR_NO_DRIVER_SELECTED);
4572 return FALSE;
4575 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4576 return FALSE;
4578 SetupDiGetActualSectionToInstallW(hinf, driver->section, coinst_key_ext, ARRAY_SIZE(coinst_key_ext), NULL, NULL);
4579 lstrcatW(coinst_key_ext, coinstallersW);
4581 if ((l = create_driver_key(device, &driver_key)))
4583 SetLastError(l);
4584 SetupCloseInfFile(hinf);
4585 return FALSE;
4588 callback_ctx = SetupInitDefaultQueueCallback(NULL);
4589 SetupInstallFromInfSectionW(NULL, hinf, coinst_key_ext, SPINST_ALL, driver_key, NULL,
4590 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
4591 SetupTermDefaultQueueCallback(callback_ctx);
4593 RegCloseKey(driver_key);
4594 SetupCloseInfFile(hinf);
4595 return TRUE;
4598 /* Check whether the given hardware or compatible ID matches any of the device's
4599 * own hardware or compatible IDs. */
4600 static BOOL device_matches_id(const struct device *device, const WCHAR *id_type, const WCHAR *id,
4601 DWORD *driver_rank)
4603 WCHAR *device_ids;
4604 const WCHAR *p;
4605 DWORD i, size;
4607 if (!RegGetValueW(device->key, NULL, id_type, RRF_RT_REG_MULTI_SZ, NULL, NULL, &size))
4609 device_ids = malloc(size);
4610 if (!RegGetValueW(device->key, NULL, id_type, RRF_RT_REG_MULTI_SZ, NULL, device_ids, &size))
4612 for (p = device_ids, i = 0; *p; p += lstrlenW(p) + 1, i++)
4614 if (!wcsicmp(p, id))
4616 *driver_rank += min(i, 0xff);
4617 free(device_ids);
4618 return TRUE;
4622 free(device_ids);
4625 return FALSE;
4628 static BOOL version_is_compatible(const WCHAR *version)
4630 const WCHAR *machine_ext = NtPlatformExtension + 1, *p;
4631 size_t len = lstrlenW(version);
4632 BOOL wow64;
4634 /* We are only concerned with architecture. */
4635 if ((p = wcschr(version, '.')))
4636 len = p - version;
4638 if (!wcsnicmp(version, NtExtension + 1, len))
4639 return TRUE;
4641 if (IsWow64Process(GetCurrentProcess(), &wow64) && wow64)
4643 #ifdef __i386__
4644 static const WCHAR wow_ext[] = {'N','T','a','m','d','6','4',0};
4645 machine_ext = wow_ext;
4646 #elif defined(__arm__)
4647 static const WCHAR wow_ext[] = {'N','T','a','r','m','6','4',0};
4648 machine_ext = wow_ext;
4649 #endif
4652 return !wcsnicmp(version, machine_ext, len);
4655 static void enum_compat_drivers_from_file(struct device *device, const WCHAR *path)
4657 static const WCHAR manufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4658 WCHAR mfg_key[LINE_LEN], id[MAX_DEVICE_ID_LEN], version[MAX_DEVICE_ID_LEN];
4659 DWORD i, j, k, driver_count = device->driver_count;
4660 struct driver driver, *drivers = device->drivers;
4661 INFCONTEXT ctx;
4662 BOOL found;
4663 HINF hinf;
4665 TRACE("Enumerating drivers from %s.\n", debugstr_w(path));
4667 if ((hinf = SetupOpenInfFileW(path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4668 return;
4670 lstrcpyW(driver.inf_path, path);
4672 for (i = 0; SetupGetLineByIndexW(hinf, manufacturerW, i, &ctx); ++i)
4674 SetupGetStringFieldW(&ctx, 0, driver.manufacturer, ARRAY_SIZE(driver.manufacturer), NULL);
4675 if (!SetupGetStringFieldW(&ctx, 1, mfg_key, ARRAY_SIZE(mfg_key), NULL))
4676 lstrcpyW(mfg_key, driver.manufacturer);
4678 if (SetupGetFieldCount(&ctx) >= 2)
4680 BOOL compatible = FALSE;
4681 for (j = 2; SetupGetStringFieldW(&ctx, j, version, ARRAY_SIZE(version), NULL); ++j)
4683 if (version_is_compatible(version))
4685 compatible = TRUE;
4686 break;
4689 if (!compatible)
4690 continue;
4693 if (!SetupDiGetActualSectionToInstallW(hinf, mfg_key, driver.mfg_key,
4694 ARRAY_SIZE(driver.mfg_key), NULL, NULL))
4696 WARN("Failed to find section for %s, skipping.\n", debugstr_w(mfg_key));
4697 continue;
4700 for (j = 0; SetupGetLineByIndexW(hinf, driver.mfg_key, j, &ctx); ++j)
4702 driver.rank = 0;
4703 for (k = 2, found = FALSE; SetupGetStringFieldW(&ctx, k, id, ARRAY_SIZE(id), NULL); ++k)
4705 if ((found = device_matches_id(device, HardwareId, id, &driver.rank))) break;
4706 driver.rank += 0x2000;
4707 if ((found = device_matches_id(device, CompatibleIDs, id, &driver.rank))) break;
4708 driver.rank = 0x1000 + min(0x0100 * (k - 2), 0xf00);
4711 if (found)
4713 SetupGetStringFieldW(&ctx, 0, driver.description, ARRAY_SIZE(driver.description), NULL);
4714 SetupGetStringFieldW(&ctx, 1, driver.section, ARRAY_SIZE(driver.section), NULL);
4716 TRACE("Found compatible driver: rank %#lx manufacturer %s, desc %s.\n",
4717 driver.rank, debugstr_w(driver.manufacturer), debugstr_w(driver.description));
4719 driver_count++;
4720 drivers = realloc(drivers, driver_count * sizeof(*drivers));
4721 drivers[driver_count - 1] = driver;
4726 SetupCloseInfFile(hinf);
4728 device->drivers = drivers;
4729 device->driver_count = driver_count;
4732 /***********************************************************************
4733 * SetupDiBuildDriverInfoList (SETUPAPI.@)
4735 BOOL WINAPI SetupDiBuildDriverInfoList(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD type)
4737 struct device *device;
4739 TRACE("devinfo %p, device_data %p, type %#lx.\n", devinfo, device_data, type);
4741 if (type != SPDIT_COMPATDRIVER)
4743 FIXME("Unhandled type %#lx.\n", type);
4744 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4745 return FALSE;
4748 if (!(device = get_device(devinfo, device_data)))
4749 return FALSE;
4751 if (device->params.Flags & DI_ENUMSINGLEINF)
4753 enum_compat_drivers_from_file(device, device->params.DriverPath);
4755 else
4757 static const WCHAR default_path[] = {'C',':','/','w','i','n','d','o','w','s','/','i','n','f',0};
4758 static const WCHAR wildcardW[] = {'*',0};
4759 WCHAR dir[MAX_PATH], file[MAX_PATH];
4760 WIN32_FIND_DATAW find_data;
4761 HANDLE find_handle;
4763 if (device->params.DriverPath[0])
4764 lstrcpyW(dir, device->params.DriverPath);
4765 else
4766 lstrcpyW(dir, default_path);
4767 lstrcatW(dir, backslashW);
4768 lstrcatW(dir, wildcardW);
4770 TRACE("Searching for drivers in %s.\n", debugstr_w(dir));
4772 if ((find_handle = FindFirstFileW(dir, &find_data)) != INVALID_HANDLE_VALUE)
4776 lstrcpyW(file, dir);
4777 lstrcpyW(file + lstrlenW(file) - 1, find_data.cFileName);
4778 enum_compat_drivers_from_file(device, file);
4779 } while (FindNextFileW(find_handle, &find_data));
4781 FindClose(find_handle);
4785 if (device->driver_count)
4787 WCHAR classname[MAX_CLASS_NAME_LEN], guidstr[39];
4788 GUID class;
4790 if (SetupDiGetINFClassW(device->drivers[0].inf_path, &class, classname, ARRAY_SIZE(classname), NULL))
4792 device_data->ClassGuid = device->class = class;
4793 SETUPDI_GuidToString(&class, guidstr);
4794 RegSetValueExW(device->key, L"ClassGUID", 0, REG_SZ, (BYTE *)guidstr, sizeof(guidstr));
4795 RegSetValueExW(device->key, L"Class", 0, REG_SZ, (BYTE *)classname, wcslen(classname) * sizeof(WCHAR));
4799 return TRUE;
4802 static BOOL copy_driver_data(SP_DRVINFO_DATA_W *data, const struct driver *driver)
4804 INFCONTEXT ctx;
4805 HINF hinf;
4807 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4808 return FALSE;
4810 data->ProviderName[0] = 0;
4811 if (SetupFindFirstLineW(hinf, L"Version", L"Provider", &ctx))
4812 SetupGetStringFieldW(&ctx, 1, data->ProviderName, ARRAY_SIZE(data->ProviderName), NULL);
4813 wcscpy(data->Description, driver->description);
4814 wcscpy(data->MfgName, driver->manufacturer);
4815 data->DriverType = SPDIT_COMPATDRIVER;
4816 data->Reserved = (ULONG_PTR)driver;
4818 SetupCloseInfFile(hinf);
4820 return TRUE;
4823 static void driver_data_wtoa(SP_DRVINFO_DATA_A *a, const SP_DRVINFO_DATA_W *w)
4825 a->DriverType = w->DriverType;
4826 a->Reserved = w->Reserved;
4827 WideCharToMultiByte(CP_ACP, 0, w->Description, -1, a->Description, sizeof(a->Description), NULL, NULL);
4828 WideCharToMultiByte(CP_ACP, 0, w->MfgName, -1, a->MfgName, sizeof(a->MfgName), NULL, NULL);
4829 WideCharToMultiByte(CP_ACP, 0, w->ProviderName, -1, a->ProviderName, sizeof(a->ProviderName), NULL, NULL);
4832 /***********************************************************************
4833 * SetupDiEnumDriverInfoW (SETUPAPI.@)
4835 BOOL WINAPI SetupDiEnumDriverInfoW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4836 DWORD type, DWORD index, SP_DRVINFO_DATA_W *driver_data)
4838 struct device *device;
4840 TRACE("devinfo %p, device_data %p, type %#lx, index %lu, driver_data %p.\n",
4841 devinfo, device_data, type, index, driver_data);
4843 if (type != SPDIT_COMPATDRIVER)
4845 FIXME("Unhandled type %#lx.\n", type);
4846 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4847 return FALSE;
4850 if (!(device = get_device(devinfo, device_data)))
4851 return FALSE;
4853 if (index >= device->driver_count)
4855 SetLastError(ERROR_NO_MORE_ITEMS);
4856 return FALSE;
4859 return copy_driver_data(driver_data, &device->drivers[index]);
4862 /***********************************************************************
4863 * SetupDiEnumDriverInfoA (SETUPAPI.@)
4865 BOOL WINAPI SetupDiEnumDriverInfoA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4866 DWORD type, DWORD index, SP_DRVINFO_DATA_A *driver_data)
4868 SP_DRVINFO_DATA_W driver_dataW;
4869 BOOL ret;
4871 driver_dataW.cbSize = sizeof(driver_dataW);
4872 ret = SetupDiEnumDriverInfoW(devinfo, device_data, type, index, &driver_dataW);
4873 if (ret) driver_data_wtoa(driver_data, &driver_dataW);
4875 return ret;
4878 /***********************************************************************
4879 * SetupDiSelectBestCompatDrv (SETUPAPI.@)
4881 BOOL WINAPI SetupDiSelectBestCompatDrv(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4883 struct device *device;
4884 struct driver *best;
4885 DWORD i;
4887 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
4889 if (!(device = get_device(devinfo, device_data)))
4890 return FALSE;
4892 if (!device->driver_count)
4894 WARN("No compatible drivers were enumerated for device %s.\n", debugstr_w(device->instanceId));
4895 SetLastError(ERROR_NO_COMPAT_DRIVERS);
4896 return FALSE;
4899 best = device->drivers;
4900 for (i = 1; i < device->driver_count; ++i)
4902 if (device->drivers[i].rank >= best->rank) continue;
4903 best = device->drivers + i;
4906 TRACE("selected driver: rank %#lx manufacturer %s, desc %s.\n",
4907 best->rank, debugstr_w(best->manufacturer), debugstr_w(best->description));
4909 device->selected_driver = best;
4910 return TRUE;
4913 /***********************************************************************
4914 * SetupDiGetSelectedDriverW (SETUPAPI.@)
4916 BOOL WINAPI SetupDiGetSelectedDriverW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, SP_DRVINFO_DATA_W *driver_data)
4918 struct device *device;
4920 TRACE("devinfo %p, device_data %p, driver_data %p.\n", devinfo, device_data, driver_data);
4922 if (!(device = get_device(devinfo, device_data)))
4923 return FALSE;
4925 if (!device->selected_driver)
4927 SetLastError(ERROR_NO_DRIVER_SELECTED);
4928 return FALSE;
4931 return copy_driver_data(driver_data, device->selected_driver);
4934 /***********************************************************************
4935 * SetupDiGetSelectedDriverA (SETUPAPI.@)
4937 BOOL WINAPI SetupDiGetSelectedDriverA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, SP_DRVINFO_DATA_A *driver_data)
4939 SP_DRVINFO_DATA_W driver_dataW;
4940 BOOL ret;
4942 driver_dataW.cbSize = sizeof(driver_dataW);
4943 if ((ret = SetupDiGetSelectedDriverW(devinfo, device_data, &driver_dataW)))
4944 driver_data_wtoa(driver_data, &driver_dataW);
4945 return ret;
4948 /***********************************************************************
4949 * SetupDiGetDriverInfoDetailW (SETUPAPI.@)
4951 BOOL WINAPI SetupDiGetDriverInfoDetailW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4952 SP_DRVINFO_DATA_W *driver_data, SP_DRVINFO_DETAIL_DATA_W *detail_data, const DWORD size, DWORD *ret_size)
4954 struct driver *driver = (struct driver *)driver_data->Reserved;
4955 DWORD size_needed, i, id_size = 1;
4956 WCHAR id[MAX_DEVICE_ID_LEN];
4957 INFCONTEXT ctx;
4958 HANDLE file;
4959 HINF hinf;
4961 TRACE("devinfo %p, device_data %p, driver_data %p, detail_data %p, size %lu, ret_size %p.\n",
4962 devinfo, device_data, driver_data, detail_data, size, ret_size);
4964 if ((detail_data || size) && size < sizeof(SP_DRVINFO_DETAIL_DATA_W))
4966 SetLastError(ERROR_INVALID_USER_BUFFER);
4967 return FALSE;
4970 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4971 return FALSE;
4973 SetupFindFirstLineW(hinf, driver->mfg_key, driver->description, &ctx);
4974 for (i = 2; SetupGetStringFieldW(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
4975 id_size += wcslen(id) + 1;
4977 size_needed = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID[id_size]);
4978 if (ret_size)
4979 *ret_size = size_needed;
4980 if (!detail_data)
4981 return TRUE;
4983 detail_data->CompatIDsLength = detail_data->CompatIDsOffset = 0;
4984 detail_data->HardwareID[0] = 0;
4986 if (size >= size_needed)
4988 id_size = 0;
4989 for (i = 2; SetupGetStringFieldW(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
4991 wcscpy(&detail_data->HardwareID[id_size], id);
4992 if (i == 3)
4993 detail_data->CompatIDsOffset = id_size;
4994 id_size += wcslen(id) + 1;
4996 detail_data->HardwareID[id_size++] = 0;
4997 if (i > 3)
4998 detail_data->CompatIDsLength = id_size - detail_data->CompatIDsOffset;
5001 SetupCloseInfFile(hinf);
5003 if ((file = CreateFileW(driver->inf_path, 0, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
5004 return FALSE;
5005 GetFileTime(file, NULL, NULL, &detail_data->InfDate);
5006 CloseHandle(file);
5008 wcscpy(detail_data->SectionName, driver->section);
5009 wcscpy(detail_data->InfFileName, driver->inf_path);
5010 wcscpy(detail_data->DrvDescription, driver->description);
5012 if (size < size_needed)
5014 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5015 return FALSE;
5018 return TRUE;
5021 /***********************************************************************
5022 * SetupDiGetDriverInfoDetailA (SETUPAPI.@)
5024 BOOL WINAPI SetupDiGetDriverInfoDetailA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
5025 SP_DRVINFO_DATA_A *driver_data, SP_DRVINFO_DETAIL_DATA_A *detail_data, const DWORD size, DWORD *ret_size)
5027 struct driver *driver = (struct driver *)driver_data->Reserved;
5028 DWORD size_needed, i, id_size = 1;
5029 char id[MAX_DEVICE_ID_LEN];
5030 INFCONTEXT ctx;
5031 HANDLE file;
5032 HINF hinf;
5034 TRACE("devinfo %p, device_data %p, driver_data %p, detail_data %p, size %lu, ret_size %p.\n",
5035 devinfo, device_data, driver_data, detail_data, size, ret_size);
5037 if ((detail_data || size) && size < sizeof(SP_DRVINFO_DETAIL_DATA_A))
5039 SetLastError(ERROR_INVALID_USER_BUFFER);
5040 return FALSE;
5043 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
5044 return FALSE;
5046 SetupFindFirstLineW(hinf, driver->mfg_key, driver->description, &ctx);
5047 for (i = 2; SetupGetStringFieldA(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
5048 id_size += strlen(id) + 1;
5050 size_needed = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID[id_size]);
5051 if (ret_size)
5052 *ret_size = size_needed;
5053 if (!detail_data)
5055 SetupCloseInfFile(hinf);
5056 return TRUE;
5059 detail_data->CompatIDsLength = detail_data->CompatIDsOffset = 0;
5060 detail_data->HardwareID[0] = 0;
5062 if (size >= size_needed)
5064 id_size = 0;
5065 for (i = 2; SetupGetStringFieldA(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
5067 strcpy(&detail_data->HardwareID[id_size], id);
5068 if (i == 3)
5069 detail_data->CompatIDsOffset = id_size;
5070 id_size += strlen(id) + 1;
5072 detail_data->HardwareID[id_size++] = 0;
5073 if (i > 3)
5074 detail_data->CompatIDsLength = id_size - detail_data->CompatIDsOffset;
5077 SetupCloseInfFile(hinf);
5079 if ((file = CreateFileW(driver->inf_path, 0, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
5080 return FALSE;
5081 GetFileTime(file, NULL, NULL, &detail_data->InfDate);
5082 CloseHandle(file);
5084 WideCharToMultiByte(CP_ACP, 0, driver->section, -1, detail_data->SectionName,
5085 sizeof(detail_data->SectionName), NULL, NULL);
5086 WideCharToMultiByte(CP_ACP, 0, driver->inf_path, -1, detail_data->InfFileName,
5087 sizeof(detail_data->InfFileName), NULL, NULL);
5088 WideCharToMultiByte(CP_ACP, 0, driver->description, -1, detail_data->DrvDescription,
5089 sizeof(detail_data->InfFileName), NULL, NULL);
5091 if (size < size_needed)
5093 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5094 return FALSE;
5097 return TRUE;
5100 /***********************************************************************
5101 * SetupDiInstallDriverFiles (SETUPAPI.@)
5103 BOOL WINAPI SetupDiInstallDriverFiles(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
5105 WCHAR section[LINE_LEN], section_ext[LINE_LEN], iface_section[LINE_LEN];
5106 struct device *device;
5107 struct driver *driver;
5108 void *callback_ctx;
5109 INFCONTEXT ctx;
5110 HINF hinf;
5112 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
5114 if (!(device = get_device(devinfo, device_data)))
5115 return FALSE;
5117 if (!(driver = device->selected_driver))
5119 ERR("No driver selected for device %p.\n", devinfo);
5120 SetLastError(ERROR_NO_DRIVER_SELECTED);
5121 return FALSE;
5124 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
5125 return FALSE;
5127 SetupFindFirstLineW(hinf, driver->mfg_key, driver->description, &ctx);
5128 SetupGetStringFieldW(&ctx, 1, section, ARRAY_SIZE(section), NULL);
5129 SetupDiGetActualSectionToInstallW(hinf, section, section_ext, ARRAY_SIZE(section_ext), NULL, NULL);
5131 callback_ctx = SetupInitDefaultQueueCallback(NULL);
5133 SetupInstallFromInfSectionW(NULL, hinf, section_ext, SPINST_FILES, NULL, NULL,
5134 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5136 lstrcatW(section_ext, dotInterfaces);
5137 if (SetupFindFirstLineW(hinf, section_ext, AddInterface, &ctx))
5139 do {
5140 SetupGetStringFieldW(&ctx, 3, iface_section, ARRAY_SIZE(iface_section), NULL);
5141 SetupInstallFromInfSectionW(NULL, hinf, iface_section, SPINST_FILES, NULL, NULL,
5142 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5143 } while (SetupFindNextMatchLineW(&ctx, AddInterface, &ctx));
5146 SetupTermDefaultQueueCallback(callback_ctx);
5148 SetupCloseInfFile(hinf);
5149 return TRUE;
5152 /***********************************************************************
5153 * SetupDiInstallDevice (SETUPAPI.@)
5155 BOOL WINAPI SetupDiInstallDevice(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
5157 static const WCHAR infpathW[] = {'I','n','f','P','a','t','h',0};
5158 static const WCHAR infsectionW[] = {'I','n','f','S','e','c','t','i','o','n',0};
5159 static const WCHAR infsectionextW[] = {'I','n','f','S','e','c','t','i','o','n','E','x','t',0};
5160 static const WCHAR dothwW[] = {'.','H','W',0};
5161 static const WCHAR dotservicesW[] = {'.','S','e','r','v','i','c','e','s',0};
5162 static const WCHAR addserviceW[] = {'A','d','d','S','e','r','v','i','c','e',0};
5163 static const WCHAR rootW[] = {'r','o','o','t','\\',0};
5164 WCHAR section_ext[LINE_LEN], subsection[LINE_LEN], inf_path[MAX_PATH], *extptr, *filepart;
5165 static const DWORD config_flags = 0;
5166 UINT install_flags = SPINST_ALL;
5167 HKEY driver_key, device_key;
5168 SC_HANDLE manager, service;
5169 WCHAR svc_name[LINE_LEN];
5170 struct device *device;
5171 struct driver *driver;
5172 void *callback_ctx;
5173 INFCONTEXT ctx;
5174 HINF hinf;
5175 LONG l;
5177 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
5179 if (!(device = get_device(devinfo, device_data)))
5180 return FALSE;
5182 if (!(driver = device->selected_driver))
5184 ERR("No driver selected for device %p.\n", devinfo);
5185 SetLastError(ERROR_NO_DRIVER_SELECTED);
5186 return FALSE;
5189 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
5190 return FALSE;
5192 RegSetValueExW(device->key, L"DeviceDesc", 0, REG_SZ, (BYTE *)driver->description,
5193 wcslen(driver->description) * sizeof(WCHAR));
5195 SetupDiGetActualSectionToInstallW(hinf, driver->section, section_ext, ARRAY_SIZE(section_ext), NULL, &extptr);
5197 if ((l = create_driver_key(device, &driver_key)))
5199 SetLastError(l);
5200 SetupCloseInfFile(hinf);
5201 return FALSE;
5204 if ((l = RegCreateKeyExW(device->key, DeviceParameters, 0, NULL, 0,
5205 KEY_READ | KEY_WRITE, NULL, &device_key, NULL)))
5207 SetLastError(l);
5208 RegCloseKey(driver_key);
5209 SetupCloseInfFile(hinf);
5210 return FALSE;
5213 if (!SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_CONFIGFLAGS,
5214 (BYTE *)&config_flags, sizeof(config_flags)))
5215 ERR("Failed to set config flags, error %#lx.\n", GetLastError());
5217 if (device->params.Flags & DI_NOFILECOPY)
5218 install_flags &= ~SPINST_FILES;
5220 callback_ctx = SetupInitDefaultQueueCallback(NULL);
5222 SetupInstallFromInfSectionW(NULL, hinf, section_ext, install_flags, driver_key, NULL,
5223 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5225 lstrcpyW(subsection, section_ext);
5226 lstrcatW(subsection, dothwW);
5228 SetupInstallFromInfSectionW(NULL, hinf, subsection, install_flags, device_key, NULL,
5229 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5231 lstrcpyW(subsection, section_ext);
5232 lstrcatW(subsection, dotservicesW);
5233 SetupInstallServicesFromInfSectionW(hinf, subsection, 0);
5235 svc_name[0] = 0;
5236 if (SetupFindFirstLineW(hinf, subsection, addserviceW, &ctx))
5240 INT flags;
5242 if (SetupGetIntField(&ctx, 2, &flags) && (flags & SPSVCINST_ASSOCSERVICE))
5244 if (SetupGetStringFieldW(&ctx, 1, svc_name, ARRAY_SIZE(svc_name), NULL) && svc_name[0])
5245 RegSetValueExW(device->key, Service, 0, REG_SZ, (BYTE *)svc_name, lstrlenW(svc_name) * sizeof(WCHAR));
5246 break;
5248 } while (SetupFindNextMatchLineW(&ctx, addserviceW, &ctx));
5251 SetupTermDefaultQueueCallback(callback_ctx);
5252 SetupCloseInfFile(hinf);
5254 SetupCopyOEMInfW(driver->inf_path, NULL, SPOST_NONE, 0, inf_path, ARRAY_SIZE(inf_path), NULL, &filepart);
5255 TRACE("Copied INF file %s to %s.\n", debugstr_w(driver->inf_path), debugstr_w(inf_path));
5257 RegSetValueExW(driver_key, infpathW, 0, REG_SZ, (BYTE *)filepart, lstrlenW(filepart) * sizeof(WCHAR));
5258 RegSetValueExW(driver_key, infsectionW, 0, REG_SZ, (BYTE *)driver->section, lstrlenW(driver->section) * sizeof(WCHAR));
5259 if (extptr)
5260 RegSetValueExW(driver_key, infsectionextW, 0, REG_SZ, (BYTE *)extptr, lstrlenW(extptr) * sizeof(WCHAR));
5262 RegCloseKey(device_key);
5263 RegCloseKey(driver_key);
5265 if (!wcsnicmp(device->instanceId, rootW, lstrlenW(rootW)) && svc_name[0]
5266 && (manager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT)))
5268 if ((service = OpenServiceW(manager, svc_name, SERVICE_START | SERVICE_USER_DEFINED_CONTROL)))
5270 SERVICE_STATUS status;
5272 if (!StartServiceW(service, 0, NULL) && GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5274 ERR("Failed to start service %s for device %s, error %lu.\n",
5275 debugstr_w(svc_name), debugstr_w(device->instanceId), GetLastError());
5277 if (!ControlService(service, SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES, &status))
5279 ERR("Failed to control service %s for device %s, error %lu.\n",
5280 debugstr_w(svc_name), debugstr_w(device->instanceId), GetLastError());
5282 CloseServiceHandle(service);
5284 else
5285 ERR("Failed to open service %s for device %s.\n", debugstr_w(svc_name), debugstr_w(device->instanceId));
5286 CloseServiceHandle(manager);
5289 return TRUE;