msdasql: Support IRowsetInfo in IRowset interface.
[wine.git] / dlls / setupapi / devinst.c
blob29cfbbeb87fe005baa9b3e109a387dd35df10627
1 /*
2 * SetupAPI device installer
4 * Copyright 2000 Andreas Mohr for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdlib.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winnt.h"
27 #include "winreg.h"
28 #include "winternl.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "winnls.h"
32 #include "winsvc.h"
33 #include "setupapi.h"
34 #include "wine/debug.h"
35 #include "wine/heap.h"
36 #include "wine/list.h"
37 #include "cfgmgr32.h"
38 #include "winioctl.h"
39 #include "rpc.h"
40 #include "rpcdce.h"
41 #include "cguid.h"
43 #include "setupapi_private.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
48 /* Unicode constants */
49 static const WCHAR Chicago[] = {'$','C','h','i','c','a','g','o','$',0};
50 static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0};
51 static const WCHAR Class[] = {'C','l','a','s','s',0};
52 static const WCHAR ClassInstall32[] = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
53 static const WCHAR NoDisplayClass[] = {'N','o','D','i','s','p','l','a','y','C','l','a','s','s',0};
54 static const WCHAR NoInstallClass[] = {'N','o','I','n','s','t','a','l','l','C','l','a','s','s',0};
55 static const WCHAR NoUseClass[] = {'N','o','U','s','e','C','l','a','s','s',0};
56 static const WCHAR NtExtension[] = {'.','N','T',0};
57 #ifdef __i386__
58 static const WCHAR NtPlatformExtension[] = {'.','N','T','x','8','6',0};
59 #elif defined(__x86_64__)
60 static const WCHAR NtPlatformExtension[] = {'.','N','T','a','m','d','6','4',0};
61 #elif defined(__arm__)
62 static const WCHAR NtPlatformExtension[] = {'.','N','T','a','r','m',0};
63 #elif defined(__aarch64__)
64 static const WCHAR NtPlatformExtension[] = {'.','N','T','a','r','m','6','4',0};
65 #endif
66 static const WCHAR Signature[] = {'S','i','g','n','a','t','u','r','e',0};
67 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
68 static const WCHAR WinExtension[] = {'.','W','i','n',0};
69 static const WCHAR WindowsNT[] = {'$','W','i','n','d','o','w','s',' ','N','T','$',0};
71 /* Registry key and value names */
72 static const WCHAR ControlClass[] = {'S','y','s','t','e','m','\\',
73 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
74 'C','o','n','t','r','o','l','\\',
75 'C','l','a','s','s',0};
77 static const WCHAR DeviceClasses[] = {'S','y','s','t','e','m','\\',
78 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
79 'C','o','n','t','r','o','l','\\',
80 'D','e','v','i','c','e','C','l','a','s','s','e','s',0};
81 static const WCHAR Enum[] = {'S','y','s','t','e','m','\\',
82 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
83 'E','n','u','m',0};
84 static const WCHAR DeviceDesc[] = {'D','e','v','i','c','e','D','e','s','c',0};
85 static const WCHAR DeviceInstance[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
86 static const WCHAR DeviceParameters[] = {'D','e','v','i','c','e',' ','P','a','r','a','m','e','t','e','r','s',0};
87 static const WCHAR HardwareId[] = {'H','a','r','d','w','a','r','e','I','D',0};
88 static const WCHAR CompatibleIDs[] = {'C','o','m','p','a','t','i','b','l','e','I','d','s',0};
89 static const WCHAR Service[] = {'S','e','r','v','i','c','e',0};
90 static const WCHAR Driver[] = {'D','r','i','v','e','r',0};
91 static const WCHAR ConfigFlags[] = {'C','o','n','f','i','g','F','l','a','g','s',0};
92 static const WCHAR Mfg[] = {'M','f','g',0};
93 static const WCHAR FriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
94 static const WCHAR LocationInformation[] = {'L','o','c','a','t','i','o','n','I','n','f','o','r','m','a','t','i','o','n',0};
95 static const WCHAR Capabilities[] = {'C','a','p','a','b','i','l','i','t','i','e','s',0};
96 static const WCHAR UINumber[] = {'U','I','N','u','m','b','e','r',0};
97 static const WCHAR UpperFilters[] = {'U','p','p','e','r','F','i','l','t','e','r','s',0};
98 static const WCHAR LowerFilters[] = {'L','o','w','e','r','F','i','l','t','e','r','s',0};
99 static const WCHAR Phantom[] = {'P','h','a','n','t','o','m',0};
100 static const WCHAR SymbolicLink[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
101 static const WCHAR Control[] = {'C','o','n','t','r','o','l',0};
102 static const WCHAR Linked[] = {'L','i','n','k','e','d',0};
103 static const WCHAR dotInterfaces[] = {'.','I','n','t','e','r','f','a','c','e','s',0};
104 static const WCHAR AddInterface[] = {'A','d','d','I','n','t','e','r','f','a','c','e',0};
105 static const WCHAR backslashW[] = {'\\',0};
106 static const WCHAR emptyW[] = {0};
108 #define SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES 128
110 struct driver
112 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_size *= 2;
252 devnode_table = heap_realloc_zero(devnode_table,
253 devnode_table_size * sizeof(*devnode_table));
255 else
257 devnode_table_size = 256;
258 devnode_table = heap_alloc_zero(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 %u 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 = heap_alloc((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 = heap_alloc((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 = HeapAlloc(GetProcessHeap(), 0, 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);
410 return ret;
413 static BOOL is_linked(HKEY key)
415 DWORD linked, type, size;
416 HKEY control_key;
417 BOOL ret = FALSE;
419 if (!RegOpenKeyW(key, Control, &control_key))
421 size = sizeof(DWORD);
422 if (!RegQueryValueExW(control_key, Linked, NULL, &type, (BYTE *)&linked, &size)
423 && type == REG_DWORD && linked)
424 ret = TRUE;
426 RegCloseKey(control_key);
429 return ret;
432 static struct device_iface *SETUPDI_CreateDeviceInterface(struct device *device,
433 const GUID *class, const WCHAR *refstr)
435 struct device_iface *iface = NULL;
436 WCHAR *refstr2 = NULL, *symlink = NULL, *path = NULL;
437 HKEY key;
438 LONG ret;
440 TRACE("%p %s %s\n", device, debugstr_guid(class), debugstr_w(refstr));
442 /* check if it already exists */
443 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
445 if (IsEqualGUID(&iface->class, class) && !lstrcmpiW(iface->refstr, refstr))
446 return iface;
449 iface = heap_alloc(sizeof(*iface));
450 symlink = SETUPDI_CreateSymbolicLinkPath(device->instanceId, class, refstr);
452 if (!iface || !symlink)
454 SetLastError(ERROR_OUTOFMEMORY);
455 goto err;
458 if (refstr && !(refstr2 = strdupW(refstr)))
460 SetLastError(ERROR_OUTOFMEMORY);
461 goto err;
463 iface->refstr = refstr2;
464 iface->symlink = symlink;
465 iface->device = device;
466 iface->class = *class;
467 iface->flags = 0;
469 if (!(path = get_iface_key_path(iface)))
471 SetLastError(ERROR_OUTOFMEMORY);
472 goto err;
475 if ((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, path, &key)))
477 SetLastError(ret);
478 goto err;
480 RegSetValueExW(key, DeviceInstance, 0, REG_SZ, (BYTE *)device->instanceId,
481 lstrlenW(device->instanceId) * sizeof(WCHAR));
482 heap_free(path);
484 iface->class_key = key;
486 if (!(path = get_refstr_key_path(iface)))
488 SetLastError(ERROR_OUTOFMEMORY);
489 goto err;
492 if ((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, path, &key)))
494 SetLastError(ret);
495 goto err;
497 RegSetValueExW(key, SymbolicLink, 0, REG_SZ, (BYTE *)iface->symlink,
498 lstrlenW(iface->symlink) * sizeof(WCHAR));
500 if (is_linked(key))
501 iface->flags |= SPINT_ACTIVE;
503 heap_free(path);
505 iface->refstr_key = key;
507 list_add_tail(&device->interfaces, &iface->entry);
508 return iface;
510 err:
511 heap_free(iface);
512 heap_free(refstr2);
513 heap_free(symlink);
514 heap_free(path);
515 return NULL;
518 static BOOL SETUPDI_SetInterfaceSymbolicLink(struct device_iface *iface,
519 const WCHAR *symlink)
521 heap_free(iface->symlink);
522 if ((iface->symlink = strdupW(symlink)))
523 return TRUE;
524 return FALSE;
527 static HKEY SETUPDI_CreateDevKey(struct device *device)
529 HKEY enumKey, key = INVALID_HANDLE_VALUE;
530 LONG l;
532 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_ALL_ACCESS,
533 NULL, &enumKey, NULL);
534 if (!l)
536 RegCreateKeyExW(enumKey, device->instanceId, 0, NULL, 0,
537 KEY_READ | KEY_WRITE, NULL, &key, NULL);
538 RegCloseKey(enumKey);
540 return key;
543 static LONG open_driver_key(struct device *device, REGSAM access, HKEY *key)
545 HKEY class_key;
546 WCHAR path[50];
547 DWORD size = sizeof(path);
548 LONG l;
550 if ((l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, ControlClass, 0, NULL, 0,
551 KEY_CREATE_SUB_KEY, NULL, &class_key, NULL)))
553 ERR("Failed to open driver class root key, error %u.\n", l);
554 return l;
557 if (!(l = RegGetValueW(device->key, NULL, Driver, RRF_RT_REG_SZ, NULL, path, &size)))
559 if (!(l = RegOpenKeyExW(class_key, path, 0, access, key)))
561 RegCloseKey(class_key);
562 return l;
564 TRACE("Failed to open driver key, error %u.\n", l);
567 RegCloseKey(class_key);
568 return l;
571 static LONG create_driver_key(struct device *device, HKEY *key)
573 static const WCHAR formatW[] = {'%','0','4','u',0};
574 static const WCHAR slash[] = { '\\',0 };
575 unsigned int i = 0;
576 WCHAR path[50];
577 HKEY class_key;
578 DWORD dispos;
579 LONG l;
581 if (!open_driver_key(device, KEY_READ | KEY_WRITE, key))
582 return ERROR_SUCCESS;
584 if ((l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, ControlClass, 0, NULL, 0,
585 KEY_CREATE_SUB_KEY, NULL, &class_key, NULL)))
587 ERR("Failed to open driver class root key, error %u.\n", l);
588 return l;
591 SETUPDI_GuidToString(&device->class, path);
592 lstrcatW(path, slash);
593 /* Allocate a new driver key, by finding the first integer value that's not
594 * already taken. */
595 for (;;)
597 swprintf(path + 39, ARRAY_SIZE(path) - 39, formatW, i++);
598 if ((l = RegCreateKeyExW(class_key, path, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, key, &dispos)))
599 break;
600 else if (dispos == REG_CREATED_NEW_KEY)
602 RegSetValueExW(device->key, Driver, 0, REG_SZ, (BYTE *)path, lstrlenW(path) * sizeof(WCHAR));
603 RegCloseKey(class_key);
604 return ERROR_SUCCESS;
606 RegCloseKey(*key);
608 ERR("Failed to create driver key, error %u.\n", l);
609 RegCloseKey(class_key);
610 return l;
613 static LONG delete_driver_key(struct device *device)
615 HKEY key;
616 LONG l;
618 if (!(l = open_driver_key(device, KEY_READ | KEY_WRITE, &key)))
620 l = RegDeleteKeyW(key, emptyW);
621 RegCloseKey(key);
624 return l;
627 struct PropertyMapEntry
629 DWORD regType;
630 LPCSTR nameA;
631 LPCWSTR nameW;
634 static const struct PropertyMapEntry PropertyMap[] = {
635 { REG_SZ, "DeviceDesc", DeviceDesc },
636 { REG_MULTI_SZ, "HardwareId", HardwareId },
637 { REG_MULTI_SZ, "CompatibleIDs", CompatibleIDs },
638 { 0, NULL, NULL }, /* SPDRP_UNUSED0 */
639 { REG_SZ, "Service", Service },
640 { 0, NULL, NULL }, /* SPDRP_UNUSED1 */
641 { 0, NULL, NULL }, /* SPDRP_UNUSED2 */
642 { REG_SZ, "Class", Class },
643 { REG_SZ, "ClassGUID", ClassGUID },
644 { REG_SZ, "Driver", Driver },
645 { REG_DWORD, "ConfigFlags", ConfigFlags },
646 { REG_SZ, "Mfg", Mfg },
647 { REG_SZ, "FriendlyName", FriendlyName },
648 { REG_SZ, "LocationInformation", LocationInformation },
649 { 0, NULL, NULL }, /* SPDRP_PHYSICAL_DEVICE_OBJECT_NAME */
650 { REG_DWORD, "Capabilities", Capabilities },
651 { REG_DWORD, "UINumber", UINumber },
652 { REG_MULTI_SZ, "UpperFilters", UpperFilters },
653 { REG_MULTI_SZ, "LowerFilters", LowerFilters },
656 static BOOL SETUPDI_SetDeviceRegistryPropertyW(struct device *device,
657 DWORD prop, const BYTE *buffer, DWORD size)
659 if (prop < ARRAY_SIZE(PropertyMap) && PropertyMap[prop].nameW)
661 LONG ret = RegSetValueExW(device->key, PropertyMap[prop].nameW, 0,
662 PropertyMap[prop].regType, buffer, size);
663 if (!ret)
664 return TRUE;
666 SetLastError(ret);
668 return FALSE;
671 static void remove_device_iface(struct device_iface *iface)
673 RegDeleteTreeW(iface->refstr_key, NULL);
674 RegDeleteKeyW(iface->refstr_key, emptyW);
675 RegCloseKey(iface->refstr_key);
676 iface->refstr_key = NULL;
677 /* Also remove the class key if it's empty. */
678 RegDeleteKeyW(iface->class_key, emptyW);
679 RegCloseKey(iface->class_key);
680 iface->class_key = NULL;
681 iface->flags |= SPINT_REMOVED;
684 static void delete_device_iface(struct device_iface *iface)
686 list_remove(&iface->entry);
687 RegCloseKey(iface->refstr_key);
688 RegCloseKey(iface->class_key);
689 heap_free(iface->refstr);
690 heap_free(iface->symlink);
691 heap_free(iface);
694 /* remove all interfaces associated with the device, including those not
695 * enumerated in the set */
696 static void remove_all_device_ifaces(struct device *device)
698 HKEY classes_key;
699 DWORD i, len;
700 LONG ret;
702 if ((ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, DeviceClasses, 0, KEY_READ, &classes_key)))
704 WARN("Failed to open classes key, error %u.\n", ret);
705 return;
708 for (i = 0; ; ++i)
710 WCHAR class_name[40];
711 HKEY class_key;
712 DWORD j;
714 len = ARRAY_SIZE(class_name);
715 if ((ret = RegEnumKeyExW(classes_key, i, class_name, &len, NULL, NULL, NULL, NULL)))
717 if (ret != ERROR_NO_MORE_ITEMS) ERR("Failed to enumerate classes, error %u.\n", ret);
718 break;
721 if ((ret = RegOpenKeyExW(classes_key, class_name, 0, KEY_READ, &class_key)))
723 ERR("Failed to open class %s, error %u.\n", debugstr_w(class_name), ret);
724 continue;
727 for (j = 0; ; ++j)
729 WCHAR iface_name[MAX_DEVICE_ID_LEN + 39], device_name[MAX_DEVICE_ID_LEN];
730 HKEY iface_key;
732 len = ARRAY_SIZE(iface_name);
733 if ((ret = RegEnumKeyExW(class_key, j, iface_name, &len, NULL, NULL, NULL, NULL)))
735 if (ret != ERROR_NO_MORE_ITEMS) ERR("Failed to enumerate interfaces, error %u.\n", ret);
736 break;
739 if ((ret = RegOpenKeyExW(class_key, iface_name, 0, KEY_ALL_ACCESS, &iface_key)))
741 ERR("Failed to open interface %s, error %u.\n", debugstr_w(iface_name), ret);
742 continue;
745 len = sizeof(device_name);
746 if ((ret = RegQueryValueExW(iface_key, L"DeviceInstance", NULL, NULL, (BYTE *)device_name, &len)))
748 ERR("Failed to query device instance, error %u.\n", ret);
749 RegCloseKey(iface_key);
750 continue;
753 if (!wcsicmp(device_name, device->instanceId))
755 if ((ret = RegDeleteTreeW(iface_key, NULL)))
756 ERR("Failed to delete interface %s subkeys, error %u.\n", debugstr_w(iface_name), ret);
757 if ((ret = RegDeleteKeyW(iface_key, L"")))
758 ERR("Failed to delete interface %s, error %u.\n", debugstr_w(iface_name), ret);
761 RegCloseKey(iface_key);
763 RegCloseKey(class_key);
766 RegCloseKey(classes_key);
769 static void remove_device(struct device *device)
771 WCHAR id[MAX_DEVICE_ID_LEN], *p;
772 struct device_iface *iface;
773 HKEY enum_key;
775 delete_driver_key(device);
777 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
779 remove_device_iface(iface);
782 RegDeleteTreeW(device->key, NULL);
783 RegDeleteKeyW(device->key, emptyW);
785 /* delete all empty parents of the key */
786 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, 0, &enum_key))
788 lstrcpyW(id, device->instanceId);
790 while ((p = wcsrchr(id, '\\')))
792 *p = 0;
793 RegDeleteKeyW(enum_key, id);
796 RegCloseKey(enum_key);
799 RegCloseKey(device->key);
800 device->key = NULL;
801 device->removed = TRUE;
804 static void delete_device(struct device *device)
806 struct device_iface *iface, *next;
807 SP_DEVINFO_DATA device_data;
809 device_data.cbSize = sizeof(device_data);
810 copy_device_data(&device_data, device);
811 SetupDiCallClassInstaller(DIF_DESTROYPRIVATEDATA, device->set, &device_data);
813 if (device->phantom)
815 remove_device(device);
816 remove_all_device_ifaces(device);
819 RegCloseKey(device->key);
820 heap_free(device->instanceId);
821 heap_free(device->drivers);
823 LIST_FOR_EACH_ENTRY_SAFE(iface, next, &device->interfaces,
824 struct device_iface, entry)
826 delete_device_iface(iface);
828 free_devnode(device->devnode);
829 list_remove(&device->entry);
830 heap_free(device);
833 /* Create a new device, or return a device already in the set. */
834 static struct device *create_device(struct DeviceInfoSet *set,
835 const GUID *class, const WCHAR *instanceid, BOOL phantom)
837 const DWORD one = 1;
838 struct device *device;
839 WCHAR guidstr[MAX_GUID_STRING_LEN];
840 WCHAR class_name[MAX_CLASS_NAME_LEN];
841 DWORD size;
843 TRACE("%p, %s, %s, %d\n", set, debugstr_guid(class),
844 debugstr_w(instanceid), phantom);
846 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
848 if (!wcsicmp(instanceid, device->instanceId))
850 TRACE("Found device %p already in set.\n", device);
851 return device;
855 if (!(device = heap_alloc_zero(sizeof(*device))))
857 SetLastError(ERROR_OUTOFMEMORY);
858 return NULL;
861 if (!(device->instanceId = strdupW(instanceid)))
863 SetLastError(ERROR_OUTOFMEMORY);
864 heap_free(device);
865 return NULL;
868 wcsupr(device->instanceId);
869 device->set = set;
870 device->key = SETUPDI_CreateDevKey(device);
871 device->phantom = phantom;
872 list_init(&device->interfaces);
873 device->class = *class;
874 device->devnode = alloc_devnode(device);
875 device->removed = FALSE;
876 list_add_tail(&set->devices, &device->entry);
877 device->params.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
879 if (phantom)
880 RegSetValueExW(device->key, Phantom, 0, REG_DWORD, (const BYTE *)&one, sizeof(one));
882 SETUPDI_GuidToString(class, guidstr);
883 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_CLASSGUID,
884 (const BYTE *)guidstr, sizeof(guidstr));
886 if (SetupDiClassNameFromGuidW(class, class_name, ARRAY_SIZE(class_name), NULL))
888 size = (lstrlenW(class_name) + 1) * sizeof(WCHAR);
889 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_CLASS, (const BYTE *)class_name, size);
892 TRACE("Created new device %p.\n", device);
893 return device;
896 /***********************************************************************
897 * SetupDiBuildClassInfoList (SETUPAPI.@)
899 * Returns a list of setup class GUIDs that identify the classes
900 * that are installed on a local machine.
902 * PARAMS
903 * Flags [I] control exclusion of classes from the list.
904 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
905 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
906 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
908 * RETURNS
909 * Success: TRUE.
910 * Failure: FALSE.
912 BOOL WINAPI SetupDiBuildClassInfoList(
913 DWORD Flags,
914 LPGUID ClassGuidList,
915 DWORD ClassGuidListSize,
916 PDWORD RequiredSize)
918 TRACE("\n");
919 return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
920 ClassGuidListSize, RequiredSize,
921 NULL, NULL);
924 /***********************************************************************
925 * SetupDiBuildClassInfoListExA (SETUPAPI.@)
927 * Returns a list of setup class GUIDs that identify the classes
928 * that are installed on a local or remote machine.
930 * PARAMS
931 * Flags [I] control exclusion of classes from the list.
932 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
933 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
934 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
935 * MachineName [I] name of a remote machine.
936 * Reserved [I] must be NULL.
938 * RETURNS
939 * Success: TRUE.
940 * Failure: FALSE.
942 BOOL WINAPI SetupDiBuildClassInfoListExA(
943 DWORD Flags,
944 LPGUID ClassGuidList,
945 DWORD ClassGuidListSize,
946 PDWORD RequiredSize,
947 LPCSTR MachineName,
948 PVOID Reserved)
950 LPWSTR MachineNameW = NULL;
951 BOOL bResult;
953 TRACE("\n");
955 if (MachineName)
957 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
958 if (MachineNameW == NULL) return FALSE;
961 bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
962 ClassGuidListSize, RequiredSize,
963 MachineNameW, Reserved);
965 MyFree(MachineNameW);
967 return bResult;
970 /***********************************************************************
971 * SetupDiBuildClassInfoListExW (SETUPAPI.@)
973 * Returns a list of setup class GUIDs that identify the classes
974 * that are installed on a local or remote machine.
976 * PARAMS
977 * Flags [I] control exclusion of classes from the list.
978 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
979 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
980 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
981 * MachineName [I] name of a remote machine.
982 * Reserved [I] must be NULL.
984 * RETURNS
985 * Success: TRUE.
986 * Failure: FALSE.
988 BOOL WINAPI SetupDiBuildClassInfoListExW(
989 DWORD Flags,
990 LPGUID ClassGuidList,
991 DWORD ClassGuidListSize,
992 PDWORD RequiredSize,
993 LPCWSTR MachineName,
994 PVOID Reserved)
996 WCHAR szKeyName[40];
997 HKEY hClassesKey;
998 HKEY hClassKey;
999 DWORD dwLength;
1000 DWORD dwIndex;
1001 LONG lError;
1002 DWORD dwGuidListIndex = 0;
1004 TRACE("\n");
1006 if (RequiredSize != NULL)
1007 *RequiredSize = 0;
1009 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
1010 KEY_ALL_ACCESS,
1011 DIOCR_INSTALLER,
1012 MachineName,
1013 Reserved);
1014 if (hClassesKey == INVALID_HANDLE_VALUE)
1016 return FALSE;
1019 for (dwIndex = 0; ; dwIndex++)
1021 dwLength = 40;
1022 lError = RegEnumKeyExW(hClassesKey,
1023 dwIndex,
1024 szKeyName,
1025 &dwLength,
1026 NULL,
1027 NULL,
1028 NULL,
1029 NULL);
1030 TRACE("RegEnumKeyExW() returns %d\n", lError);
1031 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
1033 TRACE("Key name: %p\n", szKeyName);
1035 if (RegOpenKeyExW(hClassesKey,
1036 szKeyName,
1038 KEY_ALL_ACCESS,
1039 &hClassKey))
1041 RegCloseKey(hClassesKey);
1042 return FALSE;
1045 if (!RegQueryValueExW(hClassKey,
1046 NoUseClass,
1047 NULL,
1048 NULL,
1049 NULL,
1050 NULL))
1052 TRACE("'NoUseClass' value found!\n");
1053 RegCloseKey(hClassKey);
1054 continue;
1057 if ((Flags & DIBCI_NOINSTALLCLASS) &&
1058 (!RegQueryValueExW(hClassKey,
1059 NoInstallClass,
1060 NULL,
1061 NULL,
1062 NULL,
1063 NULL)))
1065 TRACE("'NoInstallClass' value found!\n");
1066 RegCloseKey(hClassKey);
1067 continue;
1070 if ((Flags & DIBCI_NODISPLAYCLASS) &&
1071 (!RegQueryValueExW(hClassKey,
1072 NoDisplayClass,
1073 NULL,
1074 NULL,
1075 NULL,
1076 NULL)))
1078 TRACE("'NoDisplayClass' value found!\n");
1079 RegCloseKey(hClassKey);
1080 continue;
1083 RegCloseKey(hClassKey);
1085 TRACE("Guid: %p\n", szKeyName);
1086 if (dwGuidListIndex < ClassGuidListSize)
1088 if (szKeyName[0] == '{' && szKeyName[37] == '}')
1090 szKeyName[37] = 0;
1092 TRACE("Guid: %p\n", &szKeyName[1]);
1094 UuidFromStringW(&szKeyName[1],
1095 &ClassGuidList[dwGuidListIndex]);
1098 dwGuidListIndex++;
1101 if (lError != ERROR_SUCCESS)
1102 break;
1105 RegCloseKey(hClassesKey);
1107 if (RequiredSize != NULL)
1108 *RequiredSize = dwGuidListIndex;
1110 if (ClassGuidListSize < dwGuidListIndex)
1112 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1113 return FALSE;
1116 return TRUE;
1119 /***********************************************************************
1120 * SetupDiClassGuidsFromNameA (SETUPAPI.@)
1122 BOOL WINAPI SetupDiClassGuidsFromNameA(
1123 LPCSTR ClassName,
1124 LPGUID ClassGuidList,
1125 DWORD ClassGuidListSize,
1126 PDWORD RequiredSize)
1128 return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
1129 ClassGuidListSize, RequiredSize,
1130 NULL, NULL);
1133 /***********************************************************************
1134 * SetupDiClassGuidsFromNameW (SETUPAPI.@)
1136 BOOL WINAPI SetupDiClassGuidsFromNameW(
1137 LPCWSTR ClassName,
1138 LPGUID ClassGuidList,
1139 DWORD ClassGuidListSize,
1140 PDWORD RequiredSize)
1142 return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
1143 ClassGuidListSize, RequiredSize,
1144 NULL, NULL);
1147 /***********************************************************************
1148 * SetupDiClassGuidsFromNameExA (SETUPAPI.@)
1150 BOOL WINAPI SetupDiClassGuidsFromNameExA(
1151 LPCSTR ClassName,
1152 LPGUID ClassGuidList,
1153 DWORD ClassGuidListSize,
1154 PDWORD RequiredSize,
1155 LPCSTR MachineName,
1156 PVOID Reserved)
1158 LPWSTR ClassNameW = NULL;
1159 LPWSTR MachineNameW = NULL;
1160 BOOL bResult;
1162 ClassNameW = MultiByteToUnicode(ClassName, CP_ACP);
1163 if (ClassNameW == NULL)
1164 return FALSE;
1166 if (MachineName)
1168 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1169 if (MachineNameW == NULL)
1171 MyFree(ClassNameW);
1172 return FALSE;
1176 bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
1177 ClassGuidListSize, RequiredSize,
1178 MachineNameW, Reserved);
1180 MyFree(MachineNameW);
1181 MyFree(ClassNameW);
1183 return bResult;
1186 /***********************************************************************
1187 * SetupDiClassGuidsFromNameExW (SETUPAPI.@)
1189 BOOL WINAPI SetupDiClassGuidsFromNameExW(
1190 LPCWSTR ClassName,
1191 LPGUID ClassGuidList,
1192 DWORD ClassGuidListSize,
1193 PDWORD RequiredSize,
1194 LPCWSTR MachineName,
1195 PVOID Reserved)
1197 WCHAR szKeyName[40];
1198 WCHAR szClassName[256];
1199 HKEY hClassesKey;
1200 HKEY hClassKey;
1201 DWORD dwLength;
1202 DWORD dwIndex;
1203 LONG lError;
1204 DWORD dwGuidListIndex = 0;
1206 if (RequiredSize != NULL)
1207 *RequiredSize = 0;
1209 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
1210 KEY_ALL_ACCESS,
1211 DIOCR_INSTALLER,
1212 MachineName,
1213 Reserved);
1214 if (hClassesKey == INVALID_HANDLE_VALUE)
1216 return FALSE;
1219 for (dwIndex = 0; ; dwIndex++)
1221 dwLength = ARRAY_SIZE(szKeyName);
1222 lError = RegEnumKeyExW(hClassesKey,
1223 dwIndex,
1224 szKeyName,
1225 &dwLength,
1226 NULL,
1227 NULL,
1228 NULL,
1229 NULL);
1230 TRACE("RegEnumKeyExW() returns %d\n", lError);
1231 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
1233 TRACE("Key name: %p\n", szKeyName);
1235 if (RegOpenKeyExW(hClassesKey,
1236 szKeyName,
1238 KEY_ALL_ACCESS,
1239 &hClassKey))
1241 RegCloseKey(hClassesKey);
1242 return FALSE;
1245 dwLength = sizeof(szClassName);
1246 if (!RegQueryValueExW(hClassKey,
1247 Class,
1248 NULL,
1249 NULL,
1250 (LPBYTE)szClassName,
1251 &dwLength))
1253 TRACE("Class name: %p\n", szClassName);
1255 if (wcsicmp(szClassName, ClassName) == 0)
1257 TRACE("Found matching class name\n");
1259 TRACE("Guid: %p\n", szKeyName);
1260 if (dwGuidListIndex < ClassGuidListSize)
1262 if (szKeyName[0] == '{' && szKeyName[37] == '}')
1264 szKeyName[37] = 0;
1266 TRACE("Guid: %p\n", &szKeyName[1]);
1268 UuidFromStringW(&szKeyName[1],
1269 &ClassGuidList[dwGuidListIndex]);
1272 dwGuidListIndex++;
1276 RegCloseKey(hClassKey);
1279 if (lError != ERROR_SUCCESS)
1280 break;
1283 RegCloseKey(hClassesKey);
1285 if (RequiredSize != NULL)
1286 *RequiredSize = dwGuidListIndex;
1288 if (ClassGuidListSize < dwGuidListIndex)
1290 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1291 return FALSE;
1294 return TRUE;
1297 /***********************************************************************
1298 * SetupDiClassNameFromGuidA (SETUPAPI.@)
1300 BOOL WINAPI SetupDiClassNameFromGuidA(
1301 const GUID* ClassGuid,
1302 PSTR ClassName,
1303 DWORD ClassNameSize,
1304 PDWORD RequiredSize)
1306 return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
1307 ClassNameSize, RequiredSize,
1308 NULL, NULL);
1311 /***********************************************************************
1312 * SetupDiClassNameFromGuidW (SETUPAPI.@)
1314 BOOL WINAPI SetupDiClassNameFromGuidW(
1315 const GUID* ClassGuid,
1316 PWSTR ClassName,
1317 DWORD ClassNameSize,
1318 PDWORD RequiredSize)
1320 return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
1321 ClassNameSize, RequiredSize,
1322 NULL, NULL);
1325 /***********************************************************************
1326 * SetupDiClassNameFromGuidExA (SETUPAPI.@)
1328 BOOL WINAPI SetupDiClassNameFromGuidExA(
1329 const GUID* ClassGuid,
1330 PSTR ClassName,
1331 DWORD ClassNameSize,
1332 PDWORD RequiredSize,
1333 PCSTR MachineName,
1334 PVOID Reserved)
1336 WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
1337 LPWSTR MachineNameW = NULL;
1338 BOOL ret;
1340 if (MachineName)
1341 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1342 ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
1343 NULL, MachineNameW, Reserved);
1344 if (ret)
1346 int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
1347 ClassNameSize, NULL, NULL);
1349 if (!ClassNameSize && RequiredSize)
1350 *RequiredSize = len;
1352 MyFree(MachineNameW);
1353 return ret;
1356 /***********************************************************************
1357 * SetupDiClassNameFromGuidExW (SETUPAPI.@)
1359 BOOL WINAPI SetupDiClassNameFromGuidExW(
1360 const GUID* ClassGuid,
1361 PWSTR ClassName,
1362 DWORD ClassNameSize,
1363 PDWORD RequiredSize,
1364 PCWSTR MachineName,
1365 PVOID Reserved)
1367 HKEY hKey;
1368 DWORD dwLength;
1370 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
1371 KEY_ALL_ACCESS,
1372 DIOCR_INSTALLER,
1373 MachineName,
1374 Reserved);
1375 if (hKey == INVALID_HANDLE_VALUE)
1377 return FALSE;
1380 if (RequiredSize != NULL)
1382 dwLength = 0;
1383 if (RegQueryValueExW(hKey,
1384 Class,
1385 NULL,
1386 NULL,
1387 NULL,
1388 &dwLength))
1390 RegCloseKey(hKey);
1391 return FALSE;
1394 *RequiredSize = dwLength / sizeof(WCHAR);
1397 dwLength = ClassNameSize * sizeof(WCHAR);
1398 if (RegQueryValueExW(hKey,
1399 Class,
1400 NULL,
1401 NULL,
1402 (LPBYTE)ClassName,
1403 &dwLength))
1405 RegCloseKey(hKey);
1406 return FALSE;
1409 RegCloseKey(hKey);
1411 return TRUE;
1414 /***********************************************************************
1415 * SetupDiCreateDeviceInfoList (SETUPAPI.@)
1417 HDEVINFO WINAPI
1418 SetupDiCreateDeviceInfoList(const GUID *ClassGuid,
1419 HWND hwndParent)
1421 return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
1424 /***********************************************************************
1425 * SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
1427 HDEVINFO WINAPI
1428 SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
1429 HWND hwndParent,
1430 PCSTR MachineName,
1431 PVOID Reserved)
1433 LPWSTR MachineNameW = NULL;
1434 HDEVINFO hDevInfo;
1436 TRACE("\n");
1438 if (MachineName)
1440 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1441 if (MachineNameW == NULL)
1442 return INVALID_HANDLE_VALUE;
1445 hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
1446 MachineNameW, Reserved);
1448 MyFree(MachineNameW);
1450 return hDevInfo;
1453 /***********************************************************************
1454 * SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
1456 * Create an empty DeviceInfoSet list.
1458 * PARAMS
1459 * ClassGuid [I] if not NULL only devices with GUID ClassGuid are associated
1460 * with this list.
1461 * hwndParent [I] hwnd needed for interface related actions.
1462 * MachineName [I] name of machine to create empty DeviceInfoSet list, if NULL
1463 * local registry will be used.
1464 * Reserved [I] must be NULL
1466 * RETURNS
1467 * Success: empty list.
1468 * Failure: INVALID_HANDLE_VALUE.
1470 HDEVINFO WINAPI
1471 SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
1472 HWND hwndParent,
1473 PCWSTR MachineName,
1474 PVOID Reserved)
1476 struct DeviceInfoSet *list = NULL;
1477 DWORD size = sizeof(struct DeviceInfoSet);
1479 TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
1480 debugstr_w(MachineName), Reserved);
1482 if (MachineName && *MachineName)
1484 FIXME("remote support is not implemented\n");
1485 SetLastError(ERROR_INVALID_MACHINENAME);
1486 return INVALID_HANDLE_VALUE;
1489 if (Reserved != NULL)
1491 SetLastError(ERROR_INVALID_PARAMETER);
1492 return INVALID_HANDLE_VALUE;
1495 list = HeapAlloc(GetProcessHeap(), 0, size);
1496 if (!list)
1498 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1499 return INVALID_HANDLE_VALUE;
1502 list->magic = SETUP_DEVICE_INFO_SET_MAGIC;
1503 list->hwndParent = hwndParent;
1504 memcpy(&list->ClassGuid,
1505 ClassGuid ? ClassGuid : &GUID_NULL,
1506 sizeof(list->ClassGuid));
1507 list_init(&list->devices);
1509 return list;
1512 /***********************************************************************
1513 * SetupDiCreateDevRegKeyA (SETUPAPI.@)
1515 HKEY WINAPI SetupDiCreateDevRegKeyA(
1516 HDEVINFO DeviceInfoSet,
1517 PSP_DEVINFO_DATA DeviceInfoData,
1518 DWORD Scope,
1519 DWORD HwProfile,
1520 DWORD KeyType,
1521 HINF InfHandle,
1522 PCSTR InfSectionName)
1524 PWSTR InfSectionNameW = NULL;
1525 HKEY key;
1527 TRACE("%p %p %d %d %d %p %s\n", DeviceInfoSet, DeviceInfoData, Scope,
1528 HwProfile, KeyType, InfHandle, debugstr_a(InfSectionName));
1530 if (InfHandle)
1532 if (!InfSectionName)
1534 SetLastError(ERROR_INVALID_PARAMETER);
1535 return INVALID_HANDLE_VALUE;
1537 else
1539 InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
1540 if (InfSectionNameW == NULL) return INVALID_HANDLE_VALUE;
1543 key = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, Scope,
1544 HwProfile, KeyType, InfHandle, InfSectionNameW);
1545 MyFree(InfSectionNameW);
1546 return key;
1549 /***********************************************************************
1550 * SetupDiCreateDevRegKeyW (SETUPAPI.@)
1552 HKEY WINAPI SetupDiCreateDevRegKeyW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD Scope,
1553 DWORD HwProfile, DWORD KeyType, HINF InfHandle, const WCHAR *InfSectionName)
1555 struct device *device;
1556 HKEY key = INVALID_HANDLE_VALUE;
1557 LONG l;
1559 TRACE("devinfo %p, device_data %p, scope %d, profile %d, type %d, inf_handle %p, inf_section %s.\n",
1560 devinfo, device_data, Scope, HwProfile, KeyType, InfHandle, debugstr_w(InfSectionName));
1562 if (!(device = get_device(devinfo, device_data)))
1563 return INVALID_HANDLE_VALUE;
1565 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
1567 SetLastError(ERROR_INVALID_FLAGS);
1568 return INVALID_HANDLE_VALUE;
1570 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
1572 SetLastError(ERROR_INVALID_FLAGS);
1573 return INVALID_HANDLE_VALUE;
1575 if (device->phantom)
1577 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
1578 return INVALID_HANDLE_VALUE;
1580 if (Scope != DICS_FLAG_GLOBAL)
1581 FIXME("unimplemented for scope %d\n", Scope);
1582 switch (KeyType)
1584 case DIREG_DEV:
1585 l = RegCreateKeyExW(device->key, DeviceParameters, 0, NULL, 0,
1586 KEY_READ | KEY_WRITE, NULL, &key, NULL);
1587 break;
1588 case DIREG_DRV:
1589 l = create_driver_key(device, &key);
1590 break;
1591 default:
1592 FIXME("Unhandled type %#x.\n", KeyType);
1593 l = ERROR_CALL_NOT_IMPLEMENTED;
1595 if (InfHandle)
1596 SetupInstallFromInfSectionW(NULL, InfHandle, InfSectionName, SPINST_ALL,
1597 NULL, NULL, SP_COPY_NEWER_ONLY, NULL, NULL, devinfo, device_data);
1598 SetLastError(l);
1599 return l ? INVALID_HANDLE_VALUE : key;
1602 /***********************************************************************
1603 * SetupDiCreateDeviceInfoA (SETUPAPI.@)
1605 BOOL WINAPI SetupDiCreateDeviceInfoA(HDEVINFO DeviceInfoSet, const char *name,
1606 const GUID *ClassGuid, PCSTR DeviceDescription, HWND hwndParent, DWORD CreationFlags,
1607 PSP_DEVINFO_DATA DeviceInfoData)
1609 WCHAR nameW[MAX_DEVICE_ID_LEN];
1610 BOOL ret = FALSE;
1611 LPWSTR DeviceDescriptionW = NULL;
1613 if (!name || strlen(name) >= MAX_DEVICE_ID_LEN)
1615 SetLastError(ERROR_INVALID_DEVINST_NAME);
1616 return FALSE;
1619 MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, ARRAY_SIZE(nameW));
1621 if (DeviceDescription)
1623 DeviceDescriptionW = MultiByteToUnicode(DeviceDescription, CP_ACP);
1624 if (DeviceDescriptionW == NULL)
1625 return FALSE;
1628 ret = SetupDiCreateDeviceInfoW(DeviceInfoSet, nameW, ClassGuid, DeviceDescriptionW,
1629 hwndParent, CreationFlags, DeviceInfoData);
1631 MyFree(DeviceDescriptionW);
1633 return ret;
1636 /***********************************************************************
1637 * SetupDiCreateDeviceInfoW (SETUPAPI.@)
1639 BOOL WINAPI SetupDiCreateDeviceInfoW(HDEVINFO devinfo, const WCHAR *name, const GUID *class,
1640 const WCHAR *description, HWND parent, DWORD flags, SP_DEVINFO_DATA *device_data)
1642 WCHAR id[MAX_DEVICE_ID_LEN];
1643 struct DeviceInfoSet *set;
1644 HKEY enum_hkey;
1645 HKEY instance_hkey;
1646 struct device *device;
1647 LONG l;
1649 TRACE("devinfo %p, name %s, class %s, description %s, hwnd %p, flags %#x, device_data %p.\n",
1650 devinfo, debugstr_w(name), debugstr_guid(class), debugstr_w(description),
1651 parent, flags, device_data);
1653 if (!name || lstrlenW(name) >= MAX_DEVICE_ID_LEN)
1655 SetLastError(ERROR_INVALID_DEVINST_NAME);
1656 return FALSE;
1659 if (!(set = get_device_set(devinfo)))
1660 return FALSE;
1662 if (!class)
1664 SetLastError(ERROR_INVALID_PARAMETER);
1665 return FALSE;
1668 if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) && !IsEqualGUID(class, &set->ClassGuid))
1670 SetLastError(ERROR_CLASS_MISMATCH);
1671 return FALSE;
1673 if ((flags & DICD_GENERATE_ID))
1675 static const WCHAR formatW[] = {'R','O','O','T','\\','%','s','\\','%','0','4','u',0};
1676 unsigned int instance_id;
1678 if (wcschr(name, '\\'))
1680 SetLastError(ERROR_INVALID_DEVINST_NAME);
1681 return FALSE;
1684 for (instance_id = 0; ; ++instance_id)
1686 if (swprintf(id, ARRAY_SIZE(id), formatW, name, instance_id) == -1)
1688 SetLastError(ERROR_INVALID_DEVINST_NAME);
1689 return FALSE;
1692 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL, &enum_hkey, NULL);
1693 if (!(l = RegOpenKeyExW(enum_hkey, id, 0, KEY_READ, &instance_hkey)))
1694 RegCloseKey(instance_hkey);
1695 if (l == ERROR_FILE_NOT_FOUND)
1696 break;
1697 RegCloseKey(enum_hkey);
1700 else
1702 /* Check if instance is already in registry */
1703 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL, &enum_hkey, NULL);
1704 if (!RegOpenKeyExW(enum_hkey, name, 0, KEY_READ, &instance_hkey))
1706 RegCloseKey(instance_hkey);
1707 RegCloseKey(enum_hkey);
1708 SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
1709 return FALSE;
1711 RegCloseKey(enum_hkey);
1713 /* Check if instance is already in set */
1714 lstrcpyW(id, name);
1715 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
1717 if (!lstrcmpiW(name, device->instanceId))
1719 SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
1720 return FALSE;
1725 if (!(device = create_device(set, class, id, TRUE)))
1726 return FALSE;
1728 if (description)
1730 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_DEVICEDESC,
1731 (const BYTE *)description, lstrlenW(description) * sizeof(WCHAR));
1734 if (device_data)
1736 if (device_data->cbSize != sizeof(SP_DEVINFO_DATA))
1738 SetLastError(ERROR_INVALID_USER_BUFFER);
1739 return FALSE;
1741 else
1742 copy_device_data(device_data, device);
1745 return TRUE;
1748 /***********************************************************************
1749 * SetupDiRegisterDeviceInfo (SETUPAPI.@)
1751 BOOL WINAPI SetupDiRegisterDeviceInfo(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD flags,
1752 PSP_DETSIG_CMPPROC compare_proc, void *context, SP_DEVINFO_DATA *duplicate_data)
1754 struct device *device;
1756 TRACE("devinfo %p, data %p, flags %#x, compare_proc %p, context %p, duplicate_data %p.\n",
1757 devinfo, device_data, flags, compare_proc, context, duplicate_data);
1759 if (!(device = get_device(devinfo, device_data)))
1760 return FALSE;
1762 if (device->phantom)
1764 device->phantom = FALSE;
1765 RegDeleteValueW(device->key, Phantom);
1767 return TRUE;
1770 /***********************************************************************
1771 * SetupDiRemoveDevice (SETUPAPI.@)
1773 BOOL WINAPI SetupDiRemoveDevice(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
1775 SC_HANDLE manager = NULL, service = NULL;
1776 struct device *device;
1777 WCHAR *service_name = NULL;
1778 DWORD size;
1780 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
1782 if (!(device = get_device(devinfo, device_data)))
1783 return FALSE;
1785 if (!(manager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT)))
1786 return FALSE;
1788 if (!RegGetValueW(device->key, NULL, L"Service", RRF_RT_REG_SZ, NULL, NULL, &size))
1790 service_name = malloc(size);
1791 if (!RegGetValueW(device->key, NULL, L"Service", RRF_RT_REG_SZ, NULL, service_name, &size))
1792 service = OpenServiceW(manager, service_name, SERVICE_USER_DEFINED_CONTROL);
1795 remove_device(device);
1797 if (service)
1799 SERVICE_STATUS status;
1800 if (!ControlService(service, SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES, &status))
1801 ERR("Failed to control service %s, error %u.\n", debugstr_w(service_name), GetLastError());
1802 CloseServiceHandle(service);
1804 CloseServiceHandle(manager);
1806 free(service_name);
1808 remove_all_device_ifaces(device);
1810 return TRUE;
1813 /***********************************************************************
1814 * SetupDiDeleteDeviceInfo (SETUPAPI.@)
1816 BOOL WINAPI SetupDiDeleteDeviceInfo(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
1818 struct device *device;
1820 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
1822 if (!(device = get_device(devinfo, device_data)))
1823 return FALSE;
1825 delete_device(device);
1827 return TRUE;
1830 /***********************************************************************
1831 * SetupDiRemoveDeviceInterface (SETUPAPI.@)
1833 BOOL WINAPI SetupDiRemoveDeviceInterface(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data)
1835 struct device_iface *iface;
1837 TRACE("devinfo %p, iface_data %p.\n", devinfo, iface_data);
1839 if (!(iface = get_device_iface(devinfo, iface_data)))
1840 return FALSE;
1842 remove_device_iface(iface);
1844 return TRUE;
1847 /***********************************************************************
1848 * SetupDiDeleteDeviceInterfaceData (SETUPAPI.@)
1850 BOOL WINAPI SetupDiDeleteDeviceInterfaceData(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data)
1852 struct device_iface *iface;
1854 TRACE("devinfo %p, iface_data %p.\n", devinfo, iface_data);
1856 if (!(iface = get_device_iface(devinfo, iface_data)))
1857 return FALSE;
1859 delete_device_iface(iface);
1861 return TRUE;
1864 /***********************************************************************
1865 * SetupDiEnumDeviceInfo (SETUPAPI.@)
1867 BOOL WINAPI DECLSPEC_HOTPATCH SetupDiEnumDeviceInfo(HDEVINFO devinfo, DWORD index, SP_DEVINFO_DATA *device_data)
1869 struct DeviceInfoSet *set;
1870 struct device *device;
1871 DWORD i = 0;
1873 TRACE("devinfo %p, index %d, device_data %p\n", devinfo, index, device_data);
1875 if (!(set = get_device_set(devinfo)))
1876 return FALSE;
1878 if (!device_data)
1880 SetLastError(ERROR_INVALID_PARAMETER);
1881 return FALSE;
1884 if (device_data->cbSize != sizeof(SP_DEVINFO_DATA))
1886 SetLastError(ERROR_INVALID_USER_BUFFER);
1887 return FALSE;
1890 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
1892 if (i++ == index)
1894 copy_device_data(device_data, device);
1895 return TRUE;
1899 SetLastError(ERROR_NO_MORE_ITEMS);
1900 return FALSE;
1903 /***********************************************************************
1904 * SetupDiGetDeviceInstanceIdA (SETUPAPI.@)
1906 BOOL WINAPI SetupDiGetDeviceInstanceIdA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
1907 char *id, DWORD size, DWORD *needed)
1909 WCHAR idW[MAX_DEVICE_ID_LEN];
1911 TRACE("devinfo %p, device_data %p, id %p, size %d, needed %p.\n",
1912 devinfo, device_data, id, size, needed);
1914 if (!SetupDiGetDeviceInstanceIdW(devinfo, device_data, idW, ARRAY_SIZE(idW), NULL))
1915 return FALSE;
1917 if (needed)
1918 *needed = WideCharToMultiByte(CP_ACP, 0, idW, -1, NULL, 0, NULL, NULL);
1920 if (size && WideCharToMultiByte(CP_ACP, 0, idW, -1, id, size, NULL, NULL))
1921 return TRUE;
1923 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1924 return FALSE;
1927 /***********************************************************************
1928 * SetupDiGetDeviceInstanceIdW (SETUPAPI.@)
1930 BOOL WINAPI SetupDiGetDeviceInstanceIdW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
1931 WCHAR *DeviceInstanceId, DWORD DeviceInstanceIdSize, DWORD *RequiredSize)
1933 struct device *device;
1935 TRACE("devinfo %p, device_data %p, DeviceInstanceId %p, DeviceInstanceIdSize %d, RequiredSize %p.\n",
1936 devinfo, device_data, DeviceInstanceId, DeviceInstanceIdSize, RequiredSize);
1938 if (!(device = get_device(devinfo, device_data)))
1939 return FALSE;
1941 TRACE("instance ID: %s\n", debugstr_w(device->instanceId));
1942 if (DeviceInstanceIdSize < lstrlenW(device->instanceId) + 1)
1944 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1945 if (RequiredSize)
1946 *RequiredSize = lstrlenW(device->instanceId) + 1;
1947 return FALSE;
1949 lstrcpyW(DeviceInstanceId, device->instanceId);
1950 if (RequiredSize)
1951 *RequiredSize = lstrlenW(device->instanceId) + 1;
1952 return TRUE;
1955 /***********************************************************************
1956 * SetupDiGetActualSectionToInstallExA (SETUPAPI.@)
1958 BOOL WINAPI SetupDiGetActualSectionToInstallExA(HINF hinf, const char *section, SP_ALTPLATFORM_INFO *altplatform,
1959 char *section_ext, DWORD size, DWORD *needed, char **extptr, void *reserved)
1961 WCHAR sectionW[LINE_LEN], section_extW[LINE_LEN], *extptrW;
1962 BOOL ret;
1964 MultiByteToWideChar(CP_ACP, 0, section, -1, sectionW, ARRAY_SIZE(sectionW));
1966 ret = SetupDiGetActualSectionToInstallExW(hinf, sectionW, altplatform, section_extW,
1967 ARRAY_SIZE(section_extW), NULL, &extptrW, reserved);
1968 if (ret)
1970 if (needed)
1971 *needed = WideCharToMultiByte(CP_ACP, 0, section_extW, -1, NULL, 0, NULL, NULL);
1973 if (section_ext)
1974 ret = !!WideCharToMultiByte(CP_ACP, 0, section_extW, -1, section_ext, size, NULL, NULL);
1976 if (extptr)
1978 if (extptrW)
1979 *extptr = section_ext + WideCharToMultiByte(CP_ACP, 0, section_extW,
1980 extptrW - section_extW, NULL, 0, NULL, NULL);
1981 else
1982 *extptr = NULL;
1986 return ret;
1989 /***********************************************************************
1990 * SetupDiGetActualSectionToInstallA (SETUPAPI.@)
1992 BOOL WINAPI SetupDiGetActualSectionToInstallA(HINF hinf, const char *section, char *section_ext,
1993 DWORD size, DWORD *needed, char **extptr)
1995 return SetupDiGetActualSectionToInstallExA(hinf, section, NULL, section_ext, size,
1996 needed, extptr, NULL);
1999 /***********************************************************************
2000 * SetupDiGetActualSectionToInstallExW (SETUPAPI.@)
2002 BOOL WINAPI SetupDiGetActualSectionToInstallExW(HINF hinf, const WCHAR *section, SP_ALTPLATFORM_INFO *altplatform,
2003 WCHAR *section_ext, DWORD size, DWORD *needed, WCHAR **extptr, void *reserved)
2005 WCHAR buffer[MAX_PATH];
2006 DWORD len;
2007 DWORD full_len;
2008 LONG line_count = -1;
2010 TRACE("hinf %p, section %s, altplatform %p, ext %p, size %d, needed %p, extptr %p, reserved %p.\n",
2011 hinf, debugstr_w(section), altplatform, section_ext, size, needed, extptr, reserved);
2013 if (altplatform)
2014 FIXME("SP_ALTPLATFORM_INFO unsupported\n");
2016 lstrcpyW(buffer, section);
2017 len = lstrlenW(buffer);
2019 if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
2021 /* Test section name with '.NTx86' extension */
2022 lstrcpyW(&buffer[len], NtPlatformExtension);
2023 line_count = SetupGetLineCountW(hinf, buffer);
2025 if (line_count == -1)
2027 /* Test section name with '.NT' extension */
2028 lstrcpyW(&buffer[len], NtExtension);
2029 line_count = SetupGetLineCountW(hinf, buffer);
2032 else
2034 /* Test section name with '.Win' extension */
2035 lstrcpyW(&buffer[len], WinExtension);
2036 line_count = SetupGetLineCountW(hinf, buffer);
2039 if (line_count == -1)
2040 buffer[len] = 0;
2042 full_len = lstrlenW(buffer);
2044 if (section_ext != NULL && size != 0)
2046 if (size < (full_len + 1))
2048 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2049 return FALSE;
2052 lstrcpyW(section_ext, buffer);
2053 if (extptr != NULL)
2055 *extptr = (len == full_len) ? NULL : &section_ext[len];
2059 if (needed != NULL)
2061 *needed = full_len + 1;
2064 return TRUE;
2067 /***********************************************************************
2068 * SetupDiGetActualSectionToInstallW (SETUPAPI.@)
2070 BOOL WINAPI SetupDiGetActualSectionToInstallW(HINF hinf, const WCHAR *section, WCHAR *section_ext,
2071 DWORD size, DWORD *needed, WCHAR **extptr)
2073 return SetupDiGetActualSectionToInstallExW(hinf, section, NULL, section_ext, size,
2074 needed, extptr, NULL);
2077 /***********************************************************************
2078 * SetupDiGetClassDescriptionA (SETUPAPI.@)
2080 BOOL WINAPI SetupDiGetClassDescriptionA(
2081 const GUID* ClassGuid,
2082 PSTR ClassDescription,
2083 DWORD ClassDescriptionSize,
2084 PDWORD RequiredSize)
2086 return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
2087 ClassDescriptionSize,
2088 RequiredSize, NULL, NULL);
2091 /***********************************************************************
2092 * SetupDiGetClassDescriptionW (SETUPAPI.@)
2094 BOOL WINAPI SetupDiGetClassDescriptionW(
2095 const GUID* ClassGuid,
2096 PWSTR ClassDescription,
2097 DWORD ClassDescriptionSize,
2098 PDWORD RequiredSize)
2100 return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
2101 ClassDescriptionSize,
2102 RequiredSize, NULL, NULL);
2105 /***********************************************************************
2106 * SetupDiGetClassDescriptionExA (SETUPAPI.@)
2108 BOOL WINAPI SetupDiGetClassDescriptionExA(
2109 const GUID* ClassGuid,
2110 PSTR ClassDescription,
2111 DWORD ClassDescriptionSize,
2112 PDWORD RequiredSize,
2113 PCSTR MachineName,
2114 PVOID Reserved)
2116 HKEY hKey;
2117 DWORD dwLength;
2118 BOOL ret;
2120 hKey = SetupDiOpenClassRegKeyExA(ClassGuid,
2121 KEY_ALL_ACCESS,
2122 DIOCR_INSTALLER,
2123 MachineName,
2124 Reserved);
2125 if (hKey == INVALID_HANDLE_VALUE)
2127 WARN("SetupDiOpenClassRegKeyExA() failed (Error %u)\n", GetLastError());
2128 return FALSE;
2131 dwLength = ClassDescriptionSize;
2132 ret = !RegQueryValueExA( hKey, NULL, NULL, NULL,
2133 (LPBYTE)ClassDescription, &dwLength );
2134 if (RequiredSize) *RequiredSize = dwLength;
2135 RegCloseKey(hKey);
2136 return ret;
2139 /***********************************************************************
2140 * SetupDiGetClassDescriptionExW (SETUPAPI.@)
2142 BOOL WINAPI SetupDiGetClassDescriptionExW(
2143 const GUID* ClassGuid,
2144 PWSTR ClassDescription,
2145 DWORD ClassDescriptionSize,
2146 PDWORD RequiredSize,
2147 PCWSTR MachineName,
2148 PVOID Reserved)
2150 HKEY hKey;
2151 DWORD dwLength;
2152 BOOL ret;
2154 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
2155 KEY_ALL_ACCESS,
2156 DIOCR_INSTALLER,
2157 MachineName,
2158 Reserved);
2159 if (hKey == INVALID_HANDLE_VALUE)
2161 WARN("SetupDiOpenClassRegKeyExW() failed (Error %u)\n", GetLastError());
2162 return FALSE;
2165 dwLength = ClassDescriptionSize * sizeof(WCHAR);
2166 ret = !RegQueryValueExW( hKey, NULL, NULL, NULL,
2167 (LPBYTE)ClassDescription, &dwLength );
2168 if (RequiredSize) *RequiredSize = dwLength / sizeof(WCHAR);
2169 RegCloseKey(hKey);
2170 return ret;
2173 /***********************************************************************
2174 * SetupDiGetClassDevsA (SETUPAPI.@)
2176 HDEVINFO WINAPI SetupDiGetClassDevsA(const GUID *class, LPCSTR enumstr, HWND parent, DWORD flags)
2178 HDEVINFO ret;
2179 LPWSTR enumstrW = NULL;
2181 if (enumstr)
2183 int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
2184 enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2185 if (!enumstrW)
2187 ret = INVALID_HANDLE_VALUE;
2188 goto end;
2190 MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
2192 ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, NULL, NULL,
2193 NULL);
2194 HeapFree(GetProcessHeap(), 0, enumstrW);
2196 end:
2197 return ret;
2200 /***********************************************************************
2201 * SetupDiGetClassDevsExA (SETUPAPI.@)
2203 HDEVINFO WINAPI SetupDiGetClassDevsExA(
2204 const GUID *class,
2205 PCSTR enumstr,
2206 HWND parent,
2207 DWORD flags,
2208 HDEVINFO deviceset,
2209 PCSTR machine,
2210 PVOID reserved)
2212 HDEVINFO ret;
2213 LPWSTR enumstrW = NULL, machineW = NULL;
2215 if (enumstr)
2217 int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
2218 enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2219 if (!enumstrW)
2221 ret = INVALID_HANDLE_VALUE;
2222 goto end;
2224 MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
2226 if (machine)
2228 int len = MultiByteToWideChar(CP_ACP, 0, machine, -1, NULL, 0);
2229 machineW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2230 if (!machineW)
2232 HeapFree(GetProcessHeap(), 0, enumstrW);
2233 ret = INVALID_HANDLE_VALUE;
2234 goto end;
2236 MultiByteToWideChar(CP_ACP, 0, machine, -1, machineW, len);
2238 ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset,
2239 machineW, reserved);
2240 HeapFree(GetProcessHeap(), 0, enumstrW);
2241 HeapFree(GetProcessHeap(), 0, machineW);
2243 end:
2244 return ret;
2247 static void SETUPDI_AddDeviceInterfaces(struct device *device, HKEY key,
2248 const GUID *guid, DWORD flags)
2250 DWORD i, len;
2251 WCHAR subKeyName[MAX_PATH];
2252 LONG l = ERROR_SUCCESS;
2254 for (i = 0; !l; i++)
2256 len = ARRAY_SIZE(subKeyName);
2257 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2258 if (!l)
2260 HKEY subKey;
2261 struct device_iface *iface;
2263 if (*subKeyName == '#')
2265 /* The subkey name is the reference string, with a '#' prepended */
2266 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2267 if (!l)
2269 WCHAR symbolicLink[MAX_PATH];
2270 DWORD dataType;
2272 if (!(flags & DIGCF_PRESENT) || is_linked(subKey))
2274 iface = SETUPDI_CreateDeviceInterface(device, guid, subKeyName + 1);
2276 len = sizeof(symbolicLink);
2277 l = RegQueryValueExW(subKey, SymbolicLink, NULL, &dataType,
2278 (BYTE *)symbolicLink, &len);
2279 if (!l && dataType == REG_SZ)
2280 SETUPDI_SetInterfaceSymbolicLink(iface, symbolicLink);
2281 RegCloseKey(subKey);
2285 /* Allow enumeration to continue */
2286 l = ERROR_SUCCESS;
2289 /* FIXME: find and add all the device's interfaces to the device */
2292 static void SETUPDI_EnumerateMatchingInterfaces(HDEVINFO DeviceInfoSet,
2293 HKEY key, const GUID *guid, const WCHAR *enumstr, DWORD flags)
2295 struct DeviceInfoSet *set = DeviceInfoSet;
2296 DWORD i, len;
2297 WCHAR subKeyName[MAX_PATH];
2298 LONG l;
2299 HKEY enumKey = INVALID_HANDLE_VALUE;
2301 TRACE("%s\n", debugstr_w(enumstr));
2303 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL,
2304 &enumKey, NULL);
2305 for (i = 0; !l; i++)
2307 len = ARRAY_SIZE(subKeyName);
2308 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2309 if (!l)
2311 HKEY subKey;
2313 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2314 if (!l)
2316 WCHAR deviceInst[MAX_PATH * 3];
2317 DWORD dataType;
2319 len = sizeof(deviceInst);
2320 l = RegQueryValueExW(subKey, DeviceInstance, NULL, &dataType,
2321 (BYTE *)deviceInst, &len);
2322 if (!l && dataType == REG_SZ)
2324 TRACE("found instance ID %s\n", debugstr_w(deviceInst));
2325 if (!enumstr || !lstrcmpiW(enumstr, deviceInst))
2327 HKEY deviceKey;
2329 l = RegOpenKeyExW(enumKey, deviceInst, 0, KEY_READ,
2330 &deviceKey);
2331 if (!l)
2333 WCHAR deviceClassStr[40];
2335 len = sizeof(deviceClassStr);
2336 l = RegQueryValueExW(deviceKey, ClassGUID, NULL,
2337 &dataType, (BYTE *)deviceClassStr, &len);
2338 if (!l && dataType == REG_SZ &&
2339 deviceClassStr[0] == '{' &&
2340 deviceClassStr[37] == '}')
2342 GUID deviceClass;
2343 struct device *device;
2345 deviceClassStr[37] = 0;
2346 UuidFromStringW(&deviceClassStr[1],
2347 &deviceClass);
2348 if ((device = create_device(set, &deviceClass, deviceInst, FALSE)))
2349 SETUPDI_AddDeviceInterfaces(device, subKey, guid, flags);
2351 RegCloseKey(deviceKey);
2355 RegCloseKey(subKey);
2357 /* Allow enumeration to continue */
2358 l = ERROR_SUCCESS;
2361 if (enumKey != INVALID_HANDLE_VALUE)
2362 RegCloseKey(enumKey);
2365 static void SETUPDI_EnumerateInterfaces(HDEVINFO DeviceInfoSet,
2366 const GUID *guid, LPCWSTR enumstr, DWORD flags)
2368 HKEY interfacesKey = SetupDiOpenClassRegKeyExW(guid, KEY_READ,
2369 DIOCR_INTERFACE, NULL, NULL);
2371 TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(guid),
2372 debugstr_w(enumstr), flags);
2374 if (interfacesKey != INVALID_HANDLE_VALUE)
2376 if (flags & DIGCF_ALLCLASSES)
2378 DWORD i, len;
2379 WCHAR interfaceGuidStr[40];
2380 LONG l = ERROR_SUCCESS;
2382 for (i = 0; !l; i++)
2384 len = ARRAY_SIZE(interfaceGuidStr);
2385 l = RegEnumKeyExW(interfacesKey, i, interfaceGuidStr, &len,
2386 NULL, NULL, NULL, NULL);
2387 if (!l)
2389 if (interfaceGuidStr[0] == '{' &&
2390 interfaceGuidStr[37] == '}')
2392 HKEY interfaceKey;
2393 GUID interfaceGuid;
2395 interfaceGuidStr[37] = 0;
2396 UuidFromStringW(&interfaceGuidStr[1], &interfaceGuid);
2397 interfaceGuidStr[37] = '}';
2398 interfaceGuidStr[38] = 0;
2399 l = RegOpenKeyExW(interfacesKey, interfaceGuidStr, 0,
2400 KEY_READ, &interfaceKey);
2401 if (!l)
2403 SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
2404 interfaceKey, &interfaceGuid, enumstr, flags);
2405 RegCloseKey(interfaceKey);
2411 else
2413 /* In this case, SetupDiOpenClassRegKeyExW opened the specific
2414 * interface's key, so just pass that long
2416 SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
2417 interfacesKey, guid, enumstr, flags);
2419 RegCloseKey(interfacesKey);
2423 static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set,
2424 LPCWSTR enumerator, LPCWSTR deviceName, HKEY deviceKey,
2425 const GUID *class, DWORD flags)
2427 WCHAR id[MAX_DEVICE_ID_LEN];
2428 DWORD i, len;
2429 WCHAR deviceInstance[MAX_PATH];
2430 LONG l = ERROR_SUCCESS;
2432 TRACE("%s %s\n", debugstr_w(enumerator), debugstr_w(deviceName));
2434 for (i = 0; !l; i++)
2436 len = ARRAY_SIZE(deviceInstance);
2437 l = RegEnumKeyExW(deviceKey, i, deviceInstance, &len, NULL, NULL, NULL,
2438 NULL);
2439 if (!l)
2441 HKEY subKey;
2443 l = RegOpenKeyExW(deviceKey, deviceInstance, 0, KEY_READ, &subKey);
2444 if (!l)
2446 WCHAR classGuid[40];
2447 DWORD dataType;
2449 len = sizeof(classGuid);
2450 l = RegQueryValueExW(subKey, ClassGUID, NULL, &dataType,
2451 (BYTE *)classGuid, &len);
2452 if (!l && dataType == REG_SZ)
2454 if (classGuid[0] == '{' && classGuid[37] == '}')
2456 GUID deviceClass;
2458 classGuid[37] = 0;
2459 UuidFromStringW(&classGuid[1], &deviceClass);
2460 if ((flags & DIGCF_ALLCLASSES) ||
2461 IsEqualGUID(class, &deviceClass))
2463 static const WCHAR fmt[] =
2464 {'%','s','\\','%','s','\\','%','s',0};
2466 if (swprintf(id, ARRAY_SIZE(id), fmt, enumerator,
2467 deviceName, deviceInstance) != -1)
2469 create_device(set, &deviceClass, id, FALSE);
2474 RegCloseKey(subKey);
2476 /* Allow enumeration to continue */
2477 l = ERROR_SUCCESS;
2482 static void SETUPDI_EnumerateMatchingDevices(HDEVINFO DeviceInfoSet,
2483 LPCWSTR parent, HKEY key, const GUID *class, DWORD flags)
2485 struct DeviceInfoSet *set = DeviceInfoSet;
2486 DWORD i, len;
2487 WCHAR subKeyName[MAX_PATH];
2488 LONG l = ERROR_SUCCESS;
2490 TRACE("%s\n", debugstr_w(parent));
2492 for (i = 0; !l; i++)
2494 len = ARRAY_SIZE(subKeyName);
2495 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2496 if (!l)
2498 HKEY subKey;
2500 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2501 if (!l)
2503 TRACE("%s\n", debugstr_w(subKeyName));
2504 SETUPDI_EnumerateMatchingDeviceInstances(set, parent,
2505 subKeyName, subKey, class, flags);
2506 RegCloseKey(subKey);
2508 /* Allow enumeration to continue */
2509 l = ERROR_SUCCESS;
2514 static void SETUPDI_EnumerateDevices(HDEVINFO DeviceInfoSet, const GUID *class,
2515 LPCWSTR enumstr, DWORD flags)
2517 HKEY enumKey;
2518 LONG l;
2520 TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(class),
2521 debugstr_w(enumstr), flags);
2523 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL,
2524 &enumKey, NULL);
2525 if (enumKey != INVALID_HANDLE_VALUE)
2527 if (enumstr)
2529 HKEY enumStrKey;
2531 l = RegOpenKeyExW(enumKey, enumstr, 0, KEY_READ,
2532 &enumStrKey);
2533 if (!l)
2535 WCHAR *bus, *device;
2537 if (!wcschr(enumstr, '\\'))
2539 SETUPDI_EnumerateMatchingDevices(DeviceInfoSet, enumstr, enumStrKey, class, flags);
2541 else if ((bus = strdupW(enumstr)))
2543 device = wcschr(bus, '\\');
2544 *device++ = 0;
2546 SETUPDI_EnumerateMatchingDeviceInstances(DeviceInfoSet, bus, device, enumStrKey, class, flags);
2547 HeapFree(GetProcessHeap(), 0, bus);
2550 RegCloseKey(enumStrKey);
2553 else
2555 DWORD i, len;
2556 WCHAR subKeyName[MAX_PATH];
2558 l = ERROR_SUCCESS;
2559 for (i = 0; !l; i++)
2561 len = ARRAY_SIZE(subKeyName);
2562 l = RegEnumKeyExW(enumKey, i, subKeyName, &len, NULL,
2563 NULL, NULL, NULL);
2564 if (!l)
2566 HKEY subKey;
2568 l = RegOpenKeyExW(enumKey, subKeyName, 0, KEY_READ,
2569 &subKey);
2570 if (!l)
2572 SETUPDI_EnumerateMatchingDevices(DeviceInfoSet,
2573 subKeyName, subKey, class, flags);
2574 RegCloseKey(subKey);
2576 /* Allow enumeration to continue */
2577 l = ERROR_SUCCESS;
2581 RegCloseKey(enumKey);
2585 /***********************************************************************
2586 * SetupDiGetClassDevsW (SETUPAPI.@)
2588 HDEVINFO WINAPI SetupDiGetClassDevsW(const GUID *class, LPCWSTR enumstr, HWND parent, DWORD flags)
2590 return SetupDiGetClassDevsExW(class, enumstr, parent, flags, NULL, NULL,
2591 NULL);
2594 /***********************************************************************
2595 * SetupDiGetClassDevsExW (SETUPAPI.@)
2597 HDEVINFO WINAPI SetupDiGetClassDevsExW(const GUID *class, PCWSTR enumstr, HWND parent, DWORD flags,
2598 HDEVINFO deviceset, PCWSTR machine, void *reserved)
2600 static const DWORD unsupportedFlags = DIGCF_DEFAULT | DIGCF_PROFILE;
2601 HDEVINFO set;
2603 TRACE("%s %s %p 0x%08x %p %s %p\n", debugstr_guid(class),
2604 debugstr_w(enumstr), parent, flags, deviceset, debugstr_w(machine),
2605 reserved);
2607 if (!(flags & DIGCF_ALLCLASSES) && !class)
2609 SetLastError(ERROR_INVALID_PARAMETER);
2610 return INVALID_HANDLE_VALUE;
2612 if (flags & DIGCF_ALLCLASSES)
2613 class = NULL;
2615 if (flags & unsupportedFlags)
2616 WARN("unsupported flags %08x\n", flags & unsupportedFlags);
2617 if (deviceset)
2618 set = deviceset;
2619 else
2620 set = SetupDiCreateDeviceInfoListExW((flags & DIGCF_DEVICEINTERFACE) ? NULL : class, parent, machine, reserved);
2621 if (set != INVALID_HANDLE_VALUE)
2623 if (machine && *machine)
2624 FIXME("%s: unimplemented for remote machines\n",
2625 debugstr_w(machine));
2626 else if (flags & DIGCF_DEVICEINTERFACE)
2627 SETUPDI_EnumerateInterfaces(set, class, enumstr, flags);
2628 else
2629 SETUPDI_EnumerateDevices(set, class, enumstr, flags);
2631 return set;
2634 /***********************************************************************
2635 * SetupDiGetDeviceInfoListDetailA (SETUPAPI.@)
2637 BOOL WINAPI SetupDiGetDeviceInfoListDetailA(HDEVINFO devinfo, SP_DEVINFO_LIST_DETAIL_DATA_A *DevInfoData)
2639 struct DeviceInfoSet *set;
2641 TRACE("devinfo %p, detail_data %p.\n", devinfo, DevInfoData);
2643 if (!(set = get_device_set(devinfo)))
2644 return FALSE;
2646 if (!DevInfoData ||
2647 DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_A))
2649 SetLastError(ERROR_INVALID_PARAMETER);
2650 return FALSE;
2652 DevInfoData->ClassGuid = set->ClassGuid;
2653 DevInfoData->RemoteMachineHandle = NULL;
2654 DevInfoData->RemoteMachineName[0] = '\0';
2655 return TRUE;
2658 /***********************************************************************
2659 * SetupDiGetDeviceInfoListDetailW (SETUPAPI.@)
2661 BOOL WINAPI SetupDiGetDeviceInfoListDetailW(HDEVINFO devinfo, SP_DEVINFO_LIST_DETAIL_DATA_W *DevInfoData)
2663 struct DeviceInfoSet *set;
2665 TRACE("devinfo %p, detail_data %p.\n", devinfo, DevInfoData);
2667 if (!(set = get_device_set(devinfo)))
2668 return FALSE;
2670 if (!DevInfoData ||
2671 DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W))
2673 SetLastError(ERROR_INVALID_PARAMETER);
2674 return FALSE;
2676 DevInfoData->ClassGuid = set->ClassGuid;
2677 DevInfoData->RemoteMachineHandle = NULL;
2678 DevInfoData->RemoteMachineName[0] = '\0';
2679 return TRUE;
2682 /***********************************************************************
2683 * SetupDiCreateDeviceInterfaceA (SETUPAPI.@)
2685 BOOL WINAPI SetupDiCreateDeviceInterfaceA(
2686 HDEVINFO DeviceInfoSet,
2687 PSP_DEVINFO_DATA DeviceInfoData,
2688 const GUID *InterfaceClassGuid,
2689 PCSTR ReferenceString,
2690 DWORD CreationFlags,
2691 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2693 BOOL ret;
2694 LPWSTR ReferenceStringW = NULL;
2696 TRACE("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
2697 debugstr_guid(InterfaceClassGuid), debugstr_a(ReferenceString),
2698 CreationFlags, DeviceInterfaceData);
2700 if (ReferenceString)
2702 ReferenceStringW = MultiByteToUnicode(ReferenceString, CP_ACP);
2703 if (ReferenceStringW == NULL) return FALSE;
2706 ret = SetupDiCreateDeviceInterfaceW(DeviceInfoSet, DeviceInfoData,
2707 InterfaceClassGuid, ReferenceStringW, CreationFlags,
2708 DeviceInterfaceData);
2710 MyFree(ReferenceStringW);
2712 return ret;
2715 /***********************************************************************
2716 * SetupDiCreateDeviceInterfaceW (SETUPAPI.@)
2718 BOOL WINAPI SetupDiCreateDeviceInterfaceW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
2719 const GUID *class, const WCHAR *refstr, DWORD flags, SP_DEVICE_INTERFACE_DATA *iface_data)
2721 struct device *device;
2722 struct device_iface *iface;
2724 TRACE("devinfo %p, device_data %p, class %s, refstr %s, flags %#x, iface_data %p.\n",
2725 devinfo, device_data, debugstr_guid(class), debugstr_w(refstr), flags, iface_data);
2727 if (!(device = get_device(devinfo, device_data)))
2728 return FALSE;
2730 if (!class)
2732 SetLastError(ERROR_INVALID_USER_BUFFER);
2733 return FALSE;
2736 if (!(iface = SETUPDI_CreateDeviceInterface(device, class, refstr)))
2737 return FALSE;
2739 if (iface_data)
2741 if (iface_data->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2743 SetLastError(ERROR_INVALID_USER_BUFFER);
2744 return FALSE;
2747 copy_device_iface_data(iface_data, iface);
2749 return TRUE;
2752 /***********************************************************************
2753 * SetupDiCreateDeviceInterfaceRegKeyA (SETUPAPI.@)
2755 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyA(
2756 HDEVINFO DeviceInfoSet,
2757 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2758 DWORD Reserved,
2759 REGSAM samDesired,
2760 HINF InfHandle,
2761 PCSTR InfSectionName)
2763 HKEY key;
2764 PWSTR InfSectionNameW = NULL;
2766 TRACE("%p %p %d %08x %p %p\n", DeviceInfoSet, DeviceInterfaceData, Reserved,
2767 samDesired, InfHandle, InfSectionName);
2768 if (InfHandle)
2770 if (!InfSectionName)
2772 SetLastError(ERROR_INVALID_PARAMETER);
2773 return INVALID_HANDLE_VALUE;
2775 InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
2776 if (!InfSectionNameW)
2777 return INVALID_HANDLE_VALUE;
2779 key = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet,
2780 DeviceInterfaceData, Reserved, samDesired, InfHandle,
2781 InfSectionNameW);
2782 MyFree(InfSectionNameW);
2783 return key;
2786 static LONG create_iface_key(const struct device_iface *iface, REGSAM access, HKEY *key)
2788 return RegCreateKeyExW(iface->refstr_key, DeviceParameters, 0, NULL, 0, access, NULL, key, NULL);
2791 /***********************************************************************
2792 * SetupDiCreateDeviceInterfaceRegKeyW (SETUPAPI.@)
2794 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyW(HDEVINFO devinfo,
2795 SP_DEVICE_INTERFACE_DATA *iface_data, DWORD reserved, REGSAM access,
2796 HINF hinf, const WCHAR *section)
2798 struct device_iface *iface;
2799 HKEY params_key;
2800 LONG ret;
2802 TRACE("devinfo %p, iface_data %p, reserved %d, access %#x, hinf %p, section %s.\n",
2803 devinfo, iface_data, reserved, access, hinf, debugstr_w(section));
2805 if (!(iface = get_device_iface(devinfo, iface_data)))
2806 return INVALID_HANDLE_VALUE;
2808 if (hinf && !section)
2810 SetLastError(ERROR_INVALID_PARAMETER);
2811 return INVALID_HANDLE_VALUE;
2814 ret = create_iface_key(iface, access, &params_key);
2815 if (ret)
2817 SetLastError(ret);
2818 return INVALID_HANDLE_VALUE;
2821 return params_key;
2824 /***********************************************************************
2825 * SetupDiDeleteDeviceInterfaceRegKey (SETUPAPI.@)
2827 BOOL WINAPI SetupDiDeleteDeviceInterfaceRegKey(HDEVINFO devinfo,
2828 SP_DEVICE_INTERFACE_DATA *iface_data, DWORD reserved)
2830 struct device_iface *iface;
2831 LONG ret;
2833 TRACE("devinfo %p, iface_data %p, reserved %d.\n", devinfo, iface_data, reserved);
2835 if (!(iface = get_device_iface(devinfo, iface_data)))
2836 return FALSE;
2838 ret = RegDeleteKeyW(iface->refstr_key, DeviceParameters);
2839 if (ret)
2841 SetLastError(ret);
2842 return FALSE;
2845 return TRUE;
2848 /***********************************************************************
2849 * SetupDiEnumDeviceInterfaces (SETUPAPI.@)
2851 * PARAMS
2852 * DeviceInfoSet [I] Set of devices from which to enumerate
2853 * interfaces
2854 * DeviceInfoData [I] (Optional) If specified, a specific device
2855 * instance from which to enumerate interfaces.
2856 * If it isn't specified, all interfaces for all
2857 * devices in the set are enumerated.
2858 * InterfaceClassGuid [I] The interface class to enumerate.
2859 * MemberIndex [I] An index of the interface instance to enumerate.
2860 * A caller should start with MemberIndex set to 0,
2861 * and continue until the function fails with
2862 * ERROR_NO_MORE_ITEMS.
2863 * DeviceInterfaceData [I/O] Returns an enumerated interface. Its cbSize
2864 * member must be set to
2865 * sizeof(SP_DEVICE_INTERFACE_DATA).
2867 * RETURNS
2868 * Success: non-zero value.
2869 * Failure: FALSE. Call GetLastError() for more info.
2871 BOOL WINAPI SetupDiEnumDeviceInterfaces(HDEVINFO devinfo,
2872 SP_DEVINFO_DATA *device_data, const GUID *class, DWORD index,
2873 SP_DEVICE_INTERFACE_DATA *iface_data)
2875 struct DeviceInfoSet *set;
2876 struct device *device;
2877 struct device_iface *iface;
2878 DWORD i = 0;
2880 TRACE("devinfo %p, device_data %p, class %s, index %u, iface_data %p.\n",
2881 devinfo, device_data, debugstr_guid(class), index, iface_data);
2883 if (!iface_data || iface_data->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2885 SetLastError(ERROR_INVALID_PARAMETER);
2886 return FALSE;
2889 /* In case application fails to check return value, clear output */
2890 memset(iface_data, 0, sizeof(*iface_data));
2891 iface_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
2893 if (device_data)
2895 if (!(device = get_device(devinfo, device_data)))
2896 return FALSE;
2898 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
2900 if (IsEqualGUID(&iface->class, class))
2902 if (i == index)
2904 copy_device_iface_data(iface_data, iface);
2905 return TRUE;
2907 i++;
2911 else
2913 if (!(set = get_device_set(devinfo)))
2914 return FALSE;
2916 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
2918 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
2920 if (IsEqualGUID(&iface->class, class))
2922 if (i == index)
2924 copy_device_iface_data(iface_data, iface);
2925 return TRUE;
2927 i++;
2933 SetLastError(ERROR_NO_MORE_ITEMS);
2934 return FALSE;
2937 /***********************************************************************
2938 * SetupDiDestroyDeviceInfoList (SETUPAPI.@)
2940 * Destroy a DeviceInfoList and free all used memory of the list.
2942 * PARAMS
2943 * devinfo [I] DeviceInfoList pointer to list to destroy
2945 * RETURNS
2946 * Success: non zero value.
2947 * Failure: zero value.
2949 BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
2951 struct DeviceInfoSet *set;
2952 struct device *device, *device2;
2954 TRACE("devinfo %p.\n", devinfo);
2956 if (!(set = get_device_set(devinfo)))
2957 return FALSE;
2959 LIST_FOR_EACH_ENTRY_SAFE(device, device2, &set->devices, struct device, entry)
2961 delete_device(device);
2963 heap_free(set);
2965 SetLastError(ERROR_SUCCESS);
2966 return TRUE;
2969 /***********************************************************************
2970 * SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
2972 BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data,
2973 SP_DEVICE_INTERFACE_DETAIL_DATA_A *DeviceInterfaceDetailData,
2974 DWORD DeviceInterfaceDetailDataSize, DWORD *RequiredSize, SP_DEVINFO_DATA *device_data)
2976 struct device_iface *iface;
2977 DWORD bytesNeeded = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath[1]);
2978 BOOL ret = FALSE;
2980 TRACE("devinfo %p, iface_data %p, detail_data %p, size %d, needed %p, device_data %p.\n",
2981 devinfo, iface_data, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize,
2982 RequiredSize, device_data);
2984 if (!(iface = get_device_iface(devinfo, iface_data)))
2985 return FALSE;
2987 if (DeviceInterfaceDetailData &&
2988 DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A))
2990 SetLastError(ERROR_INVALID_USER_BUFFER);
2991 return FALSE;
2993 if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
2995 SetLastError(ERROR_INVALID_USER_BUFFER);
2996 return FALSE;
2999 if (iface->symlink)
3000 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, iface->symlink, -1,
3001 NULL, 0, NULL, NULL);
3002 if (DeviceInterfaceDetailDataSize >= bytesNeeded)
3004 if (iface->symlink)
3005 WideCharToMultiByte(CP_ACP, 0, iface->symlink, -1,
3006 DeviceInterfaceDetailData->DevicePath,
3007 DeviceInterfaceDetailDataSize -
3008 offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
3009 NULL, NULL);
3010 else
3011 DeviceInterfaceDetailData->DevicePath[0] = '\0';
3013 ret = TRUE;
3015 else
3017 if (RequiredSize)
3018 *RequiredSize = bytesNeeded;
3019 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3022 if (device_data && device_data->cbSize == sizeof(SP_DEVINFO_DATA))
3023 copy_device_data(device_data, iface->device);
3025 return ret;
3028 /***********************************************************************
3029 * SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
3031 BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data,
3032 SP_DEVICE_INTERFACE_DETAIL_DATA_W *DeviceInterfaceDetailData,
3033 DWORD DeviceInterfaceDetailDataSize, DWORD *RequiredSize, SP_DEVINFO_DATA *device_data)
3035 struct device_iface *iface;
3036 DWORD bytesNeeded = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
3037 + sizeof(WCHAR); /* include NULL terminator */
3038 BOOL ret = FALSE;
3040 TRACE("devinfo %p, iface_data %p, detail_data %p, size %d, needed %p, device_data %p.\n",
3041 devinfo, iface_data, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize,
3042 RequiredSize, device_data);
3044 if (!(iface = get_device_iface(devinfo, iface_data)))
3045 return FALSE;
3047 if (DeviceInterfaceDetailData && (DeviceInterfaceDetailData->cbSize <
3048 offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR) ||
3049 DeviceInterfaceDetailData->cbSize > sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W)))
3051 SetLastError(ERROR_INVALID_USER_BUFFER);
3052 return FALSE;
3054 if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
3056 SetLastError(ERROR_INVALID_USER_BUFFER);
3057 return FALSE;
3060 if (iface->symlink)
3061 bytesNeeded += sizeof(WCHAR) * lstrlenW(iface->symlink);
3062 if (DeviceInterfaceDetailDataSize >= bytesNeeded)
3064 if (iface->symlink)
3065 lstrcpyW(DeviceInterfaceDetailData->DevicePath, iface->symlink);
3066 else
3067 DeviceInterfaceDetailData->DevicePath[0] = '\0';
3069 ret = TRUE;
3071 else
3073 if (RequiredSize)
3074 *RequiredSize = bytesNeeded;
3075 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3078 if (device_data && device_data->cbSize == sizeof(SP_DEVINFO_DATA))
3079 copy_device_data(device_data, iface->device);
3081 return ret;
3084 /***********************************************************************
3085 * SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
3087 BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(HDEVINFO devinfo,
3088 SP_DEVINFO_DATA *device_data, DWORD Property, DWORD *PropertyRegDataType,
3089 BYTE *PropertyBuffer, DWORD PropertyBufferSize, DWORD *RequiredSize)
3091 BOOL ret = FALSE;
3092 struct device *device;
3094 TRACE("devinfo %p, device_data %p, property %d, type %p, buffer %p, size %d, required %p\n",
3095 devinfo, device_data, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize);
3097 if (!(device = get_device(devinfo, device_data)))
3098 return FALSE;
3100 if (PropertyBufferSize && PropertyBuffer == NULL)
3102 SetLastError(ERROR_INVALID_DATA);
3103 return FALSE;
3106 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameA)
3108 DWORD size = PropertyBufferSize;
3109 LONG l = RegQueryValueExA(device->key, PropertyMap[Property].nameA,
3110 NULL, PropertyRegDataType, PropertyBuffer, &size);
3112 if (l == ERROR_FILE_NOT_FOUND)
3113 SetLastError(ERROR_INVALID_DATA);
3114 else if (l == ERROR_MORE_DATA || !PropertyBufferSize)
3115 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3116 else if (!l)
3117 ret = TRUE;
3118 else
3119 SetLastError(l);
3120 if (RequiredSize)
3121 *RequiredSize = size;
3123 return ret;
3126 /***********************************************************************
3127 * SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
3129 BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(HDEVINFO devinfo,
3130 SP_DEVINFO_DATA *device_data, DWORD Property, DWORD *PropertyRegDataType,
3131 BYTE *PropertyBuffer, DWORD PropertyBufferSize, DWORD *RequiredSize)
3133 BOOL ret = FALSE;
3134 struct device *device;
3136 TRACE("devinfo %p, device_data %p, prop %d, type %p, buffer %p, size %d, required %p\n",
3137 devinfo, device_data, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize);
3139 if (!(device = get_device(devinfo, device_data)))
3140 return FALSE;
3142 if (PropertyBufferSize && PropertyBuffer == NULL)
3144 SetLastError(ERROR_INVALID_DATA);
3145 return FALSE;
3148 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameW)
3150 DWORD size = PropertyBufferSize;
3151 LONG l = RegQueryValueExW(device->key, PropertyMap[Property].nameW,
3152 NULL, PropertyRegDataType, PropertyBuffer, &size);
3154 if (l == ERROR_FILE_NOT_FOUND)
3155 SetLastError(ERROR_INVALID_DATA);
3156 else if (l == ERROR_MORE_DATA || !PropertyBufferSize)
3157 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3158 else if (!l)
3159 ret = TRUE;
3160 else
3161 SetLastError(l);
3162 if (RequiredSize)
3163 *RequiredSize = size;
3165 return ret;
3168 /***********************************************************************
3169 * SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
3171 BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
3172 DWORD Property, const BYTE *PropertyBuffer, DWORD PropertyBufferSize)
3174 BOOL ret = FALSE;
3175 struct device *device;
3177 TRACE("devinfo %p, device_data %p, prop %d, buffer %p, size %d.\n",
3178 devinfo, device_data, Property, PropertyBuffer, PropertyBufferSize);
3180 if (!(device = get_device(devinfo, device_data)))
3181 return FALSE;
3183 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameA)
3185 LONG l = RegSetValueExA(device->key, PropertyMap[Property].nameA, 0,
3186 PropertyMap[Property].regType, PropertyBuffer,
3187 PropertyBufferSize);
3188 if (!l)
3189 ret = TRUE;
3190 else
3191 SetLastError(l);
3193 return ret;
3196 /***********************************************************************
3197 * SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
3199 BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(HDEVINFO devinfo,
3200 SP_DEVINFO_DATA *device_data, DWORD prop, const BYTE *buffer, DWORD size)
3202 struct device *device;
3204 TRACE("devinfo %p, device_data %p, prop %d, buffer %p, size %d.\n",
3205 devinfo, device_data, prop, buffer, size);
3207 if (!(device = get_device(devinfo, device_data)))
3208 return FALSE;
3210 return SETUPDI_SetDeviceRegistryPropertyW(device, prop, buffer, size);
3213 /***********************************************************************
3214 * SetupDiInstallClassA (SETUPAPI.@)
3216 BOOL WINAPI SetupDiInstallClassA(
3217 HWND hwndParent,
3218 PCSTR InfFileName,
3219 DWORD Flags,
3220 HSPFILEQ FileQueue)
3222 UNICODE_STRING FileNameW;
3223 BOOL Result;
3225 if (!InfFileName)
3227 SetLastError(ERROR_INVALID_PARAMETER);
3228 return FALSE;
3230 if (!RtlCreateUnicodeStringFromAsciiz(&FileNameW, InfFileName))
3232 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3233 return FALSE;
3236 Result = SetupDiInstallClassW(hwndParent, FileNameW.Buffer, Flags, FileQueue);
3238 RtlFreeUnicodeString(&FileNameW);
3240 return Result;
3243 static HKEY CreateClassKey(HINF hInf)
3245 static const WCHAR slash[] = { '\\',0 };
3246 WCHAR FullBuffer[MAX_PATH];
3247 WCHAR Buffer[MAX_PATH];
3248 DWORD RequiredSize;
3249 HKEY hClassKey;
3251 if (!SetupGetLineTextW(NULL,
3252 hInf,
3253 Version,
3254 ClassGUID,
3255 Buffer,
3256 MAX_PATH,
3257 &RequiredSize))
3259 return INVALID_HANDLE_VALUE;
3262 lstrcpyW(FullBuffer, ControlClass);
3263 lstrcatW(FullBuffer, slash);
3264 lstrcatW(FullBuffer, Buffer);
3266 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3267 FullBuffer,
3269 KEY_ALL_ACCESS,
3270 &hClassKey))
3272 if (!SetupGetLineTextW(NULL,
3273 hInf,
3274 Version,
3275 Class,
3276 Buffer,
3277 MAX_PATH,
3278 &RequiredSize))
3280 return INVALID_HANDLE_VALUE;
3283 if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
3284 FullBuffer,
3286 NULL,
3287 REG_OPTION_NON_VOLATILE,
3288 KEY_ALL_ACCESS,
3289 NULL,
3290 &hClassKey,
3291 NULL))
3293 return INVALID_HANDLE_VALUE;
3298 if (RegSetValueExW(hClassKey,
3299 Class,
3301 REG_SZ,
3302 (LPBYTE)Buffer,
3303 RequiredSize * sizeof(WCHAR)))
3305 RegCloseKey(hClassKey);
3306 RegDeleteKeyW(HKEY_LOCAL_MACHINE,
3307 FullBuffer);
3308 return INVALID_HANDLE_VALUE;
3311 return hClassKey;
3314 /***********************************************************************
3315 * SetupDiInstallClassW (SETUPAPI.@)
3317 BOOL WINAPI SetupDiInstallClassW(
3318 HWND hwndParent,
3319 PCWSTR InfFileName,
3320 DWORD Flags,
3321 HSPFILEQ FileQueue)
3323 WCHAR SectionName[MAX_PATH];
3324 DWORD SectionNameLength = 0;
3325 HINF hInf;
3326 BOOL bFileQueueCreated = FALSE;
3327 HKEY hClassKey;
3330 FIXME("\n");
3332 if (!InfFileName)
3334 SetLastError(ERROR_INVALID_PARAMETER);
3335 return FALSE;
3337 if ((Flags & DI_NOVCP) && (FileQueue == NULL || FileQueue == INVALID_HANDLE_VALUE))
3339 SetLastError(ERROR_INVALID_PARAMETER);
3340 return FALSE;
3343 /* Open the .inf file */
3344 hInf = SetupOpenInfFileW(InfFileName,
3345 NULL,
3346 INF_STYLE_WIN4,
3347 NULL);
3348 if (hInf == INVALID_HANDLE_VALUE)
3351 return FALSE;
3354 /* Create or open the class registry key 'HKLM\\CurrentControlSet\\Class\\{GUID}' */
3355 hClassKey = CreateClassKey(hInf);
3356 if (hClassKey == INVALID_HANDLE_VALUE)
3358 SetupCloseInfFile(hInf);
3359 return FALSE;
3363 /* Try to append a layout file */
3364 SetupOpenAppendInfFileW(NULL, hInf, NULL);
3366 /* Retrieve the actual section name */
3367 SetupDiGetActualSectionToInstallW(hInf,
3368 ClassInstall32,
3369 SectionName,
3370 MAX_PATH,
3371 &SectionNameLength,
3372 NULL);
3374 #if 0
3375 if (!(Flags & DI_NOVCP))
3377 FileQueue = SetupOpenFileQueue();
3378 if (FileQueue == INVALID_HANDLE_VALUE)
3380 SetupCloseInfFile(hInf);
3381 return FALSE;
3384 bFileQueueCreated = TRUE;
3387 #endif
3389 SetupInstallFromInfSectionW(NULL,
3390 hInf,
3391 SectionName,
3392 SPINST_COPYINF | SPINST_FILES | SPINST_REGISTRY,
3393 hClassKey,
3394 NULL,
3396 NULL,
3397 NULL,
3398 INVALID_HANDLE_VALUE,
3399 NULL);
3401 /* FIXME: More code! */
3403 if (bFileQueueCreated)
3404 SetupCloseFileQueue(FileQueue);
3406 SetupCloseInfFile(hInf);
3408 return TRUE;
3412 /***********************************************************************
3413 * SetupDiOpenClassRegKey (SETUPAPI.@)
3415 HKEY WINAPI SetupDiOpenClassRegKey(
3416 const GUID* ClassGuid,
3417 REGSAM samDesired)
3419 return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3420 DIOCR_INSTALLER, NULL, NULL);
3424 /***********************************************************************
3425 * SetupDiOpenClassRegKeyExA (SETUPAPI.@)
3427 HKEY WINAPI SetupDiOpenClassRegKeyExA(
3428 const GUID* ClassGuid,
3429 REGSAM samDesired,
3430 DWORD Flags,
3431 PCSTR MachineName,
3432 PVOID Reserved)
3434 PWSTR MachineNameW = NULL;
3435 HKEY hKey;
3437 TRACE("\n");
3439 if (MachineName)
3441 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
3442 if (MachineNameW == NULL)
3443 return INVALID_HANDLE_VALUE;
3446 hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3447 Flags, MachineNameW, Reserved);
3449 MyFree(MachineNameW);
3451 return hKey;
3455 /***********************************************************************
3456 * SetupDiOpenClassRegKeyExW (SETUPAPI.@)
3458 HKEY WINAPI SetupDiOpenClassRegKeyExW(
3459 const GUID* ClassGuid,
3460 REGSAM samDesired,
3461 DWORD Flags,
3462 PCWSTR MachineName,
3463 PVOID Reserved)
3465 HKEY hClassesKey;
3466 HKEY key;
3467 LPCWSTR lpKeyName;
3468 LONG l;
3470 if (MachineName && *MachineName)
3472 FIXME("Remote access not supported yet!\n");
3473 return INVALID_HANDLE_VALUE;
3476 if (Flags == DIOCR_INSTALLER)
3478 lpKeyName = ControlClass;
3480 else if (Flags == DIOCR_INTERFACE)
3482 lpKeyName = DeviceClasses;
3484 else
3486 ERR("Invalid Flags parameter!\n");
3487 SetLastError(ERROR_INVALID_PARAMETER);
3488 return INVALID_HANDLE_VALUE;
3491 if (!ClassGuid)
3493 if ((l = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3494 lpKeyName,
3496 samDesired,
3497 &hClassesKey)))
3499 SetLastError(l);
3500 hClassesKey = INVALID_HANDLE_VALUE;
3502 key = hClassesKey;
3504 else
3506 WCHAR bracedGuidString[39];
3508 SETUPDI_GuidToString(ClassGuid, bracedGuidString);
3510 if (!(l = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3511 lpKeyName,
3513 samDesired,
3514 &hClassesKey)))
3516 if ((l = RegOpenKeyExW(hClassesKey,
3517 bracedGuidString,
3519 samDesired,
3520 &key)))
3522 SetLastError(l);
3523 key = INVALID_HANDLE_VALUE;
3525 RegCloseKey(hClassesKey);
3527 else
3529 SetLastError(l);
3530 key = INVALID_HANDLE_VALUE;
3533 return key;
3536 /***********************************************************************
3537 * SetupDiOpenDeviceInfoA (SETUPAPI.@)
3539 BOOL WINAPI SetupDiOpenDeviceInfoA(HDEVINFO devinfo, PCSTR instance_id, HWND hwnd_parent, DWORD flags,
3540 PSP_DEVINFO_DATA device_data)
3542 WCHAR instance_idW[MAX_DEVICE_ID_LEN];
3544 TRACE("%p %s %p 0x%08x %p\n", devinfo, debugstr_a(instance_id), hwnd_parent, flags, device_data);
3546 if (!instance_id || strlen(instance_id) >= MAX_DEVICE_ID_LEN)
3548 SetLastError(ERROR_INVALID_PARAMETER);
3549 return FALSE;
3552 MultiByteToWideChar(CP_ACP, 0, instance_id, -1, instance_idW, ARRAY_SIZE(instance_idW));
3553 return SetupDiOpenDeviceInfoW(devinfo, instance_idW, hwnd_parent, flags, device_data);
3556 /***********************************************************************
3557 * SetupDiOpenDeviceInfoW (SETUPAPI.@)
3559 BOOL WINAPI SetupDiOpenDeviceInfoW(HDEVINFO devinfo, PCWSTR instance_id, HWND hwnd_parent, DWORD flags,
3560 PSP_DEVINFO_DATA device_data)
3562 struct DeviceInfoSet *set;
3563 struct device *device;
3564 WCHAR classW[40];
3565 GUID guid;
3566 HKEY enumKey = NULL;
3567 HKEY instanceKey = NULL;
3568 DWORD phantom;
3569 DWORD size;
3570 DWORD error = ERROR_NO_SUCH_DEVINST;
3572 TRACE("%p %s %p 0x%08x %p\n", devinfo, debugstr_w(instance_id), hwnd_parent, flags, device_data);
3574 if (!(set = get_device_set(devinfo)))
3575 return FALSE;
3577 if (!instance_id)
3579 SetLastError(ERROR_INVALID_PARAMETER);
3580 return FALSE;
3583 if (hwnd_parent)
3584 FIXME("hwnd_parent unsupported\n");
3586 if (flags)
3587 FIXME("flags unsupported: 0x%08x\n", flags);
3589 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &enumKey, NULL);
3590 /* Instance needs to be already existent in registry, if not, report ERROR_NO_SUCH_DEVINST */
3591 if (RegOpenKeyExW(enumKey, instance_id, 0, KEY_READ, &instanceKey))
3592 goto done;
3594 /* If it's an unregistered instance, aka phantom instance, report ERROR_NO_SUCH_DEVINST */
3595 size = sizeof(phantom);
3596 if (!RegQueryValueExW(instanceKey, Phantom, NULL, NULL, (BYTE *)&phantom, &size))
3597 goto done;
3599 /* Check class GUID */
3600 size = sizeof(classW);
3601 if (RegQueryValueExW(instanceKey, ClassGUID, NULL, NULL, (BYTE *)classW, &size))
3602 goto done;
3604 classW[37] = 0;
3605 UuidFromStringW(&classW[1], &guid);
3607 if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) && !IsEqualGUID(&guid, &set->ClassGuid))
3609 error = ERROR_CLASS_MISMATCH;
3610 goto done;
3613 if (!(device = create_device(set, &guid, instance_id, FALSE)))
3614 goto done;
3616 if (!device_data || device_data->cbSize == sizeof(SP_DEVINFO_DATA))
3618 if (device_data)
3619 copy_device_data(device_data, device);
3620 error = NO_ERROR;
3622 else
3623 error = ERROR_INVALID_USER_BUFFER;
3625 done:
3626 RegCloseKey(instanceKey);
3627 RegCloseKey(enumKey);
3628 SetLastError(error);
3629 return !error;
3632 /***********************************************************************
3633 * SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
3635 BOOL WINAPI SetupDiOpenDeviceInterfaceW(
3636 HDEVINFO DeviceInfoSet,
3637 PCWSTR DevicePath,
3638 DWORD OpenFlags,
3639 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3641 FIXME("%p %s %08x %p\n",
3642 DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
3643 return FALSE;
3646 /***********************************************************************
3647 * SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
3649 BOOL WINAPI SetupDiOpenDeviceInterfaceA(
3650 HDEVINFO DeviceInfoSet,
3651 PCSTR DevicePath,
3652 DWORD OpenFlags,
3653 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3655 FIXME("%p %s %08x %p\n", DeviceInfoSet,
3656 debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
3657 return FALSE;
3660 /***********************************************************************
3661 * SetupDiOpenDeviceInterfaceRegKey (SETUPAPI.@)
3663 HKEY WINAPI SetupDiOpenDeviceInterfaceRegKey(HDEVINFO devinfo, PSP_DEVICE_INTERFACE_DATA iface_data,
3664 DWORD reserved, REGSAM access)
3666 struct device_iface *iface;
3667 LSTATUS lr;
3668 HKEY key;
3670 TRACE("devinfo %p, iface_data %p, reserved %d, access %#x.\n", devinfo, iface_data, reserved, access);
3672 if (!(iface = get_device_iface(devinfo, iface_data)))
3673 return INVALID_HANDLE_VALUE;
3675 lr = RegOpenKeyExW(iface->refstr_key, DeviceParameters, 0, access, &key);
3676 if (lr)
3678 SetLastError(lr);
3679 return INVALID_HANDLE_VALUE;
3682 return key;
3685 /***********************************************************************
3686 * SetupDiSetClassInstallParamsA (SETUPAPI.@)
3688 BOOL WINAPI SetupDiSetClassInstallParamsA(
3689 HDEVINFO DeviceInfoSet,
3690 PSP_DEVINFO_DATA DeviceInfoData,
3691 PSP_CLASSINSTALL_HEADER ClassInstallParams,
3692 DWORD ClassInstallParamsSize)
3694 FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
3695 ClassInstallParams->InstallFunction, ClassInstallParamsSize);
3696 return FALSE;
3699 /***********************************************************************
3700 * SetupDiSetClassInstallParamsW (SETUPAPI.@)
3702 BOOL WINAPI SetupDiSetClassInstallParamsW(
3703 HDEVINFO DeviceInfoSet,
3704 PSP_DEVINFO_DATA DeviceInfoData,
3705 PSP_CLASSINSTALL_HEADER ClassInstallParams,
3706 DWORD ClassInstallParamsSize)
3708 FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
3709 ClassInstallParams->InstallFunction, ClassInstallParamsSize);
3710 return FALSE;
3713 static BOOL call_coinstallers(WCHAR *list, DI_FUNCTION function, HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
3715 DWORD (CALLBACK *coinst_proc)(DI_FUNCTION, HDEVINFO, SP_DEVINFO_DATA *, COINSTALLER_CONTEXT_DATA *);
3716 COINSTALLER_CONTEXT_DATA coinst_ctx;
3717 WCHAR *p, *procnameW;
3718 HMODULE module;
3719 char *procname;
3720 DWORD ret;
3722 for (p = list; *p; p += lstrlenW(p) + 1)
3724 TRACE("Found co-installer %s.\n", debugstr_w(p));
3725 if ((procnameW = wcschr(p, ',')))
3726 *procnameW = 0;
3728 if ((module = LoadLibraryExW(p, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32)))
3730 if (procnameW)
3732 procname = strdupWtoA(procnameW + 1);
3733 coinst_proc = (void *)GetProcAddress(module, procname);
3734 heap_free(procname);
3736 else
3737 coinst_proc = (void *)GetProcAddress(module, "CoDeviceInstall");
3738 if (coinst_proc)
3740 memset(&coinst_ctx, 0, sizeof(coinst_ctx));
3741 TRACE("Calling co-installer %p.\n", coinst_proc);
3742 ret = coinst_proc(function, devinfo, device_data, &coinst_ctx);
3743 TRACE("Co-installer %p returned %#x.\n", coinst_proc, ret);
3744 if (ret == ERROR_DI_POSTPROCESSING_REQUIRED)
3745 FIXME("Co-installer postprocessing not implemented.\n");
3746 else if (ret)
3748 ERR("Co-installer returned error %#x.\n", ret);
3749 FreeLibrary(module);
3750 SetLastError(ret);
3751 return FALSE;
3754 FreeLibrary(module);
3758 return TRUE;
3761 /***********************************************************************
3762 * SetupDiCallClassInstaller (SETUPAPI.@)
3764 BOOL WINAPI SetupDiCallClassInstaller(DI_FUNCTION function, HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
3766 static const WCHAR class_coinst_pathW[] = {'S','y','s','t','e','m',
3767 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
3768 '\\','C','o','n','t','r','o','l',
3769 '\\','C','o','D','e','v','i','c','e','I','n','s','t','a','l','l','e','r','s',0};
3770 static const WCHAR coinstallers32W[] = {'C','o','I','n','s','t','a','l','l','e','r','s','3','2',0};
3771 static const WCHAR installer32W[] = {'I','n','s','t','a','l','l','e','r','3','2',0};
3772 DWORD (CALLBACK *classinst_proc)(DI_FUNCTION, HDEVINFO, SP_DEVINFO_DATA *);
3773 DWORD ret = ERROR_DI_DO_DEFAULT;
3774 HKEY class_key, coinst_key;
3775 WCHAR *path, *procnameW;
3776 struct device *device;
3777 WCHAR guidstr[39];
3778 BOOL coret = TRUE;
3779 HMODULE module;
3780 char *procname;
3781 DWORD size;
3783 TRACE("function %#x, devinfo %p, device_data %p.\n", function, devinfo, device_data);
3785 if (!(device = get_device(devinfo, device_data)))
3786 return FALSE;
3788 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, class_coinst_pathW, 0, KEY_READ, &coinst_key))
3790 SETUPDI_GuidToString(&device->class, guidstr);
3791 if (!RegGetValueW(coinst_key, NULL, guidstr, RRF_RT_REG_MULTI_SZ, NULL, NULL, &size))
3793 path = heap_alloc(size);
3794 if (!RegGetValueW(coinst_key, NULL, guidstr, RRF_RT_REG_MULTI_SZ, NULL, path, &size))
3795 coret = call_coinstallers(path, function, devinfo, device_data);
3796 heap_free(path);
3798 RegCloseKey(coinst_key);
3801 if (!coret)
3802 return FALSE;
3804 if (!open_driver_key(device, KEY_READ, &coinst_key))
3806 if (!RegGetValueW(coinst_key, NULL, coinstallers32W, RRF_RT_REG_MULTI_SZ, NULL, NULL, &size))
3808 path = heap_alloc(size);
3809 if (!RegGetValueW(coinst_key, NULL, coinstallers32W, RRF_RT_REG_MULTI_SZ, NULL, path, &size))
3810 coret = call_coinstallers(path, function, devinfo, device_data);
3811 heap_free(path);
3813 RegCloseKey(coinst_key);
3816 if ((class_key = SetupDiOpenClassRegKey(&device->class, KEY_READ)) != INVALID_HANDLE_VALUE)
3818 if (!RegGetValueW(class_key, NULL, installer32W, RRF_RT_REG_SZ, NULL, NULL, &size))
3820 path = heap_alloc(size);
3821 if (!RegGetValueW(class_key, NULL, installer32W, RRF_RT_REG_SZ, NULL, path, &size))
3823 TRACE("Found class installer %s.\n", debugstr_w(path));
3824 if ((procnameW = wcschr(path, ',')))
3825 *procnameW = 0;
3827 if ((module = LoadLibraryExW(path, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32)))
3829 if (procnameW)
3831 procname = strdupWtoA(procnameW + 1);
3832 classinst_proc = (void *)GetProcAddress(module, procname);
3833 heap_free(procname);
3835 else
3836 classinst_proc = (void *)GetProcAddress(module, "ClassInstall");
3837 if (classinst_proc)
3839 TRACE("Calling class installer %p.\n", classinst_proc);
3840 ret = classinst_proc(function, devinfo, device_data);
3841 TRACE("Class installer %p returned %#x.\n", classinst_proc, ret);
3843 FreeLibrary(module);
3846 heap_free(path);
3848 RegCloseKey(class_key);
3851 if (ret == ERROR_DI_DO_DEFAULT)
3853 switch (function)
3855 case DIF_REGISTERDEVICE:
3856 return SetupDiRegisterDeviceInfo(devinfo, device_data, 0, NULL, NULL, NULL);
3857 case DIF_REMOVE:
3858 return SetupDiRemoveDevice(devinfo, device_data);
3859 case DIF_SELECTBESTCOMPATDRV:
3860 return SetupDiSelectBestCompatDrv(devinfo, device_data);
3861 case DIF_REGISTER_COINSTALLERS:
3862 return SetupDiRegisterCoDeviceInstallers(devinfo, device_data);
3863 case DIF_INSTALLDEVICEFILES:
3864 return SetupDiInstallDriverFiles(devinfo, device_data);
3865 case DIF_INSTALLINTERFACES:
3866 return SetupDiInstallDeviceInterfaces(devinfo, device_data);
3867 case DIF_INSTALLDEVICE:
3868 return SetupDiInstallDevice(devinfo, device_data);
3869 case DIF_FINISHINSTALL_ACTION:
3870 case DIF_PROPERTYCHANGE:
3871 case DIF_SELECTDEVICE:
3872 case DIF_UNREMOVE:
3873 FIXME("Unhandled function %#x.\n", function);
3877 if (ret) SetLastError(ret);
3878 return !ret;
3881 /***********************************************************************
3882 * SetupDiGetDeviceInstallParamsW (SETUPAPI.@)
3884 BOOL WINAPI SetupDiGetDeviceInstallParamsW(HDEVINFO devinfo,
3885 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_W *params)
3887 struct device *device;
3889 TRACE("devinfo %p, device_data %p, params %p.\n", devinfo, device_data, params);
3891 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
3893 SetLastError(ERROR_INVALID_USER_BUFFER);
3894 return FALSE;
3897 if (!(device = get_device(devinfo, device_data)))
3898 return FALSE;
3900 *params = device->params;
3902 return TRUE;
3905 /***********************************************************************
3906 * SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
3908 BOOL WINAPI SetupDiGetDeviceInstallParamsA(HDEVINFO devinfo,
3909 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_A *params)
3911 SP_DEVINSTALL_PARAMS_W paramsW;
3912 BOOL ret;
3914 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
3916 SetLastError(ERROR_INVALID_USER_BUFFER);
3917 return FALSE;
3920 paramsW.cbSize = sizeof(paramsW);
3921 ret = SetupDiGetDeviceInstallParamsW(devinfo, device_data, &paramsW);
3922 params->Flags = paramsW.Flags;
3923 params->FlagsEx = paramsW.FlagsEx;
3924 params->hwndParent = paramsW.hwndParent;
3925 params->InstallMsgHandler = paramsW.InstallMsgHandler;
3926 params->InstallMsgHandlerContext = paramsW.InstallMsgHandlerContext;
3927 params->FileQueue = paramsW.FileQueue;
3928 params->ClassInstallReserved = paramsW.ClassInstallReserved;
3929 params->Reserved = paramsW.Reserved;
3930 WideCharToMultiByte(CP_ACP, 0, paramsW.DriverPath, -1, params->DriverPath, sizeof(params->DriverPath), NULL, NULL);
3932 return ret;
3935 /***********************************************************************
3936 * SetupDiSetDeviceInstallParamsA (SETUPAPI.@)
3938 BOOL WINAPI SetupDiSetDeviceInstallParamsA(HDEVINFO devinfo,
3939 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_A *params)
3941 SP_DEVINSTALL_PARAMS_W paramsW;
3943 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
3945 SetLastError(ERROR_INVALID_USER_BUFFER);
3946 return FALSE;
3949 paramsW.cbSize = sizeof(paramsW);
3950 paramsW.Flags = params->Flags;
3951 paramsW.FlagsEx = params->FlagsEx;
3952 paramsW.hwndParent = params->hwndParent;
3953 paramsW.InstallMsgHandler = params->InstallMsgHandler;
3954 paramsW.InstallMsgHandlerContext = params->InstallMsgHandlerContext;
3955 paramsW.FileQueue = params->FileQueue;
3956 paramsW.ClassInstallReserved = params->ClassInstallReserved;
3957 paramsW.Reserved = params->Reserved;
3958 MultiByteToWideChar(CP_ACP, 0, params->DriverPath, -1, paramsW.DriverPath, ARRAY_SIZE(paramsW.DriverPath));
3960 return SetupDiSetDeviceInstallParamsW(devinfo, device_data, &paramsW);
3963 /***********************************************************************
3964 * SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
3966 BOOL WINAPI SetupDiSetDeviceInstallParamsW(HDEVINFO devinfo,
3967 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_W *params)
3969 struct device *device;
3971 TRACE("devinfo %p, device_data %p, params %p.\n", devinfo, device_data, params);
3973 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
3975 SetLastError(ERROR_INVALID_USER_BUFFER);
3976 return FALSE;
3979 if (!(device = get_device(devinfo, device_data)))
3980 return FALSE;
3982 device->params = *params;
3984 return TRUE;
3987 BOOL WINAPI SetupDiSetDevicePropertyW(HDEVINFO devinfo, PSP_DEVINFO_DATA device_data, const DEVPROPKEY *key,
3988 DEVPROPTYPE type, const BYTE *buffer, DWORD size, DWORD flags)
3990 static const WCHAR propertiesW[] = {'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's', 0};
3991 static const WCHAR formatW[] = {'\\', '%', '0', '4', 'X', 0};
3992 struct device *device;
3993 HKEY properties_hkey, property_hkey;
3994 WCHAR property_hkey_path[44];
3995 LSTATUS ls;
3997 TRACE("%p %p %p %#x %p %d %#x\n", devinfo, device_data, key, type, buffer, size, flags);
3999 if (!(device = get_device(devinfo, device_data)))
4000 return FALSE;
4002 if (!key || !is_valid_property_type(type)
4003 || (buffer && !size && !(type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL))
4004 || (buffer && size && (type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL)))
4006 SetLastError(ERROR_INVALID_DATA);
4007 return FALSE;
4010 if (size && !buffer)
4012 SetLastError(ERROR_INVALID_USER_BUFFER);
4013 return FALSE;
4016 if (flags)
4018 SetLastError(ERROR_INVALID_FLAGS);
4019 return FALSE;
4022 ls = RegCreateKeyExW(device->key, propertiesW, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &properties_hkey, NULL);
4023 if (ls)
4025 SetLastError(ls);
4026 return FALSE;
4029 SETUPDI_GuidToString(&key->fmtid, property_hkey_path);
4030 swprintf(property_hkey_path + 38, ARRAY_SIZE(property_hkey_path) - 38, formatW, key->pid);
4032 if (type == DEVPROP_TYPE_EMPTY)
4034 ls = RegDeleteKeyW(properties_hkey, property_hkey_path);
4035 RegCloseKey(properties_hkey);
4036 SetLastError(ls == ERROR_FILE_NOT_FOUND ? ERROR_NOT_FOUND : ls);
4037 return !ls;
4039 else if (type == DEVPROP_TYPE_NULL)
4041 if (!(ls = RegOpenKeyW(properties_hkey, property_hkey_path, &property_hkey)))
4043 ls = RegDeleteValueW(property_hkey, NULL);
4044 RegCloseKey(property_hkey);
4047 RegCloseKey(properties_hkey);
4048 SetLastError(ls == ERROR_FILE_NOT_FOUND ? ERROR_NOT_FOUND : ls);
4049 return !ls;
4051 else
4053 if (!(ls = RegCreateKeyExW(properties_hkey, property_hkey_path, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL,
4054 &property_hkey, NULL)))
4056 ls = RegSetValueExW(property_hkey, NULL, 0, 0xffff0000 | (0xffff & type), buffer, size);
4057 RegCloseKey(property_hkey);
4060 RegCloseKey(properties_hkey);
4061 SetLastError(ls);
4062 return !ls;
4066 /***********************************************************************
4067 * SetupDiOpenDevRegKey (SETUPAPI.@)
4069 HKEY WINAPI SetupDiOpenDevRegKey(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4070 DWORD Scope, DWORD HwProfile, DWORD KeyType, REGSAM samDesired)
4072 struct device *device;
4073 HKEY key = INVALID_HANDLE_VALUE;
4074 LONG l;
4076 TRACE("devinfo %p, device_data %p, scope %d, profile %d, type %d, access %#x.\n",
4077 devinfo, device_data, Scope, HwProfile, KeyType, samDesired);
4079 if (!(device = get_device(devinfo, device_data)))
4080 return INVALID_HANDLE_VALUE;
4082 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
4084 SetLastError(ERROR_INVALID_FLAGS);
4085 return INVALID_HANDLE_VALUE;
4087 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
4089 SetLastError(ERROR_INVALID_FLAGS);
4090 return INVALID_HANDLE_VALUE;
4093 if (device->phantom)
4095 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
4096 return INVALID_HANDLE_VALUE;
4098 if (Scope != DICS_FLAG_GLOBAL)
4099 FIXME("unimplemented for scope %d\n", Scope);
4100 switch (KeyType)
4102 case DIREG_DEV:
4103 l = RegOpenKeyExW(device->key, DeviceParameters, 0, samDesired, &key);
4104 break;
4105 case DIREG_DRV:
4106 l = open_driver_key(device, samDesired, &key);
4107 break;
4108 default:
4109 FIXME("Unhandled type %#x.\n", KeyType);
4110 l = ERROR_CALL_NOT_IMPLEMENTED;
4112 SetLastError(l == ERROR_FILE_NOT_FOUND ? ERROR_KEY_DOES_NOT_EXIST : l);
4113 return l ? INVALID_HANDLE_VALUE : key;
4116 /***********************************************************************
4117 * SetupDiDeleteDevRegKey (SETUPAPI.@)
4119 BOOL WINAPI SetupDiDeleteDevRegKey(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4120 DWORD Scope, DWORD HwProfile, DWORD KeyType)
4122 struct device *device;
4123 LONG l;
4125 TRACE("devinfo %p, device_data %p, scope %d, profile %d, type %d.\n",
4126 devinfo, device_data, Scope, HwProfile, KeyType);
4128 if (!(device = get_device(devinfo, device_data)))
4129 return FALSE;
4131 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
4133 SetLastError(ERROR_INVALID_FLAGS);
4134 return FALSE;
4136 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV && KeyType != DIREG_BOTH)
4138 SetLastError(ERROR_INVALID_FLAGS);
4139 return FALSE;
4142 if (device->phantom)
4144 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
4145 return FALSE;
4147 if (Scope != DICS_FLAG_GLOBAL)
4148 FIXME("unimplemented for scope %d\n", Scope);
4149 switch (KeyType)
4151 case DIREG_DRV:
4152 l = delete_driver_key(device);
4153 break;
4154 case DIREG_BOTH:
4155 if ((l = delete_driver_key(device)))
4156 break;
4157 /* fall through */
4158 case DIREG_DEV:
4159 l = RegDeleteKeyW(device->key, DeviceParameters);
4160 break;
4161 default:
4162 FIXME("Unhandled type %#x.\n", KeyType);
4163 l = ERROR_CALL_NOT_IMPLEMENTED;
4165 SetLastError(l);
4166 return !l;
4169 /***********************************************************************
4170 * CM_Get_Device_IDA (SETUPAPI.@)
4172 CONFIGRET WINAPI CM_Get_Device_IDA(DEVINST devnode, char *buffer, ULONG len, ULONG flags)
4174 struct device *device = get_devnode_device(devnode);
4176 TRACE("%u, %p, %u, %#x\n", devnode, buffer, len, flags);
4178 if (!device)
4179 return CR_NO_SUCH_DEVINST;
4181 WideCharToMultiByte(CP_ACP, 0, device->instanceId, -1, buffer, len, 0, 0);
4182 TRACE("Returning %s\n", debugstr_a(buffer));
4183 return CR_SUCCESS;
4186 /***********************************************************************
4187 * CM_Get_Device_IDW (SETUPAPI.@)
4189 CONFIGRET WINAPI CM_Get_Device_IDW(DEVINST devnode, WCHAR *buffer, ULONG len, ULONG flags)
4191 struct device *device = get_devnode_device(devnode);
4193 TRACE("%u, %p, %u, %#x\n", devnode, buffer, len, flags);
4195 if (!device)
4196 return CR_NO_SUCH_DEVINST;
4198 lstrcpynW(buffer, device->instanceId, len);
4199 TRACE("Returning %s\n", debugstr_w(buffer));
4200 return CR_SUCCESS;
4203 /***********************************************************************
4204 * CM_Get_Device_ID_Size (SETUPAPI.@)
4206 CONFIGRET WINAPI CM_Get_Device_ID_Size(ULONG *len, DEVINST devnode, ULONG flags)
4208 struct device *device = get_devnode_device(devnode);
4210 TRACE("%p, %u, %#x\n", len, devnode, flags);
4212 if (!device)
4213 return CR_NO_SUCH_DEVINST;
4215 *len = lstrlenW(device->instanceId);
4216 return CR_SUCCESS;
4219 /***********************************************************************
4220 * SetupDiGetINFClassA (SETUPAPI.@)
4222 BOOL WINAPI SetupDiGetINFClassA(PCSTR inf, LPGUID class_guid, PSTR class_name,
4223 DWORD size, PDWORD required_size)
4225 BOOL retval;
4226 DWORD required_sizeA, required_sizeW;
4227 PWSTR class_nameW = NULL;
4228 UNICODE_STRING infW;
4230 if (inf)
4232 if (!RtlCreateUnicodeStringFromAsciiz(&infW, inf))
4234 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4235 return FALSE;
4238 else
4239 infW.Buffer = NULL;
4241 if (class_name && size)
4243 if (!(class_nameW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR))))
4245 RtlFreeUnicodeString(&infW);
4246 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4247 return FALSE;
4251 retval = SetupDiGetINFClassW(infW.Buffer, class_guid, class_nameW, size, &required_sizeW);
4253 if (retval)
4255 required_sizeA = WideCharToMultiByte( CP_ACP, 0, class_nameW, required_sizeW,
4256 class_name, size, NULL, NULL);
4258 if(required_size) *required_size = required_sizeA;
4260 else
4261 if(required_size) *required_size = required_sizeW;
4263 HeapFree(GetProcessHeap(), 0, class_nameW);
4264 RtlFreeUnicodeString(&infW);
4265 return retval;
4268 /***********************************************************************
4269 * SetupDiGetINFClassW (SETUPAPI.@)
4271 BOOL WINAPI SetupDiGetINFClassW(PCWSTR inf, LPGUID class_guid, PWSTR class_name,
4272 DWORD size, PDWORD required_size)
4274 BOOL have_guid, have_name;
4275 DWORD dret;
4276 WCHAR buffer[MAX_PATH];
4278 if (!inf)
4280 SetLastError(ERROR_INVALID_PARAMETER);
4281 return FALSE;
4284 if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(inf))
4286 FIXME("%s not found. Searching via DevicePath not implemented\n", debugstr_w(inf));
4287 SetLastError(ERROR_FILE_NOT_FOUND);
4288 return FALSE;
4291 if (!class_guid || !class_name || !size)
4293 SetLastError(ERROR_INVALID_PARAMETER);
4294 return FALSE;
4297 if (!GetPrivateProfileStringW(Version, Signature, NULL, buffer, MAX_PATH, inf))
4298 return FALSE;
4300 if (lstrcmpiW(buffer, Chicago) && lstrcmpiW(buffer, WindowsNT))
4301 return FALSE;
4303 buffer[0] = '\0';
4304 have_guid = 0 < GetPrivateProfileStringW(Version, ClassGUID, NULL, buffer, MAX_PATH, inf);
4305 if (have_guid)
4307 buffer[lstrlenW(buffer)-1] = 0;
4308 if (RPC_S_OK != UuidFromStringW(buffer + 1, class_guid))
4310 FIXME("failed to convert \"%s\" into a guid\n", debugstr_w(buffer));
4311 SetLastError(ERROR_INVALID_PARAMETER);
4312 return FALSE;
4316 buffer[0] = '\0';
4317 dret = GetPrivateProfileStringW(Version, Class, NULL, buffer, MAX_PATH, inf);
4318 have_name = 0 < dret;
4320 if (dret >= MAX_PATH -1) FIXME("buffer might be too small\n");
4321 if (have_guid && !have_name)
4323 class_name[0] = '\0';
4324 FIXME("class name lookup via guid not implemented\n");
4327 if (have_name)
4329 if (dret < size) lstrcpyW(class_name, buffer);
4330 else
4332 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4333 have_name = FALSE;
4337 if (required_size) *required_size = dret + ((dret) ? 1 : 0);
4339 return (have_guid || have_name);
4342 static LSTATUS get_device_property(struct device *device, const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type,
4343 BYTE *prop_buff, DWORD prop_buff_size, DWORD *required_size, DWORD flags)
4345 WCHAR key_path[55] = L"Properties\\";
4346 HKEY hkey;
4347 DWORD value_type;
4348 DWORD value_size = 0;
4349 LSTATUS ls;
4351 if (!prop_key)
4352 return ERROR_INVALID_DATA;
4354 if (!prop_type || (!prop_buff && prop_buff_size))
4355 return ERROR_INVALID_USER_BUFFER;
4357 if (flags)
4358 return ERROR_INVALID_FLAGS;
4360 SETUPDI_GuidToString(&prop_key->fmtid, key_path + 11);
4361 swprintf(key_path + 49, ARRAY_SIZE(key_path) - 49, L"\\%04X", prop_key->pid);
4363 ls = RegOpenKeyExW(device->key, key_path, 0, KEY_QUERY_VALUE, &hkey);
4364 if (!ls)
4366 value_size = prop_buff_size;
4367 ls = RegQueryValueExW(hkey, NULL, NULL, &value_type, prop_buff, &value_size);
4368 RegCloseKey(hkey);
4371 switch (ls)
4373 case NO_ERROR:
4374 case ERROR_MORE_DATA:
4375 *prop_type = 0xffff & value_type;
4376 ls = (ls == ERROR_MORE_DATA || !prop_buff) ? ERROR_INSUFFICIENT_BUFFER : NO_ERROR;
4377 break;
4378 case ERROR_FILE_NOT_FOUND:
4379 *prop_type = DEVPROP_TYPE_EMPTY;
4380 value_size = 0;
4381 ls = ERROR_NOT_FOUND;
4382 break;
4383 default:
4384 *prop_type = DEVPROP_TYPE_EMPTY;
4385 value_size = 0;
4386 FIXME("Unhandled error %#x\n", ls);
4387 break;
4390 if (required_size)
4391 *required_size = value_size;
4393 return ls;
4396 /***********************************************************************
4397 * SetupDiGetDevicePropertyW (SETUPAPI.@)
4399 BOOL WINAPI SetupDiGetDevicePropertyW(HDEVINFO devinfo, PSP_DEVINFO_DATA device_data,
4400 const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type, BYTE *prop_buff,
4401 DWORD prop_buff_size, DWORD *required_size, DWORD flags)
4403 struct device *device;
4404 LSTATUS ls;
4406 TRACE("%p, %p, %p, %p, %p, %d, %p, %#x\n", devinfo, device_data, prop_key, prop_type, prop_buff, prop_buff_size,
4407 required_size, flags);
4409 if (!(device = get_device(devinfo, device_data)))
4410 return FALSE;
4412 ls = get_device_property(device, prop_key, prop_type, prop_buff, prop_buff_size, required_size, flags);
4414 SetLastError(ls);
4415 return !ls;
4418 /***********************************************************************
4419 * CM_Get_DevNode_Property_ExW (SETUPAPI.@)
4421 CONFIGRET WINAPI CM_Get_DevNode_Property_ExW(DEVINST devnode, const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type,
4422 BYTE *prop_buff, ULONG *prop_buff_size, ULONG flags, HMACHINE machine)
4424 struct device *device = get_devnode_device(devnode);
4425 LSTATUS ls;
4427 TRACE("%u, %p, %p, %p, %p, %#x, %p\n", devnode, prop_key, prop_type, prop_buff, prop_buff_size,
4428 flags, machine);
4430 if (machine)
4431 return CR_MACHINE_UNAVAILABLE;
4433 if (!device)
4434 return CR_NO_SUCH_DEVINST;
4436 if (!prop_buff_size)
4437 return CR_INVALID_POINTER;
4439 ls = get_device_property(device, prop_key, prop_type, prop_buff, *prop_buff_size, prop_buff_size, flags);
4440 switch (ls)
4442 case NO_ERROR:
4443 return CR_SUCCESS;
4444 case ERROR_INVALID_DATA:
4445 return CR_INVALID_DATA;
4446 case ERROR_INVALID_USER_BUFFER:
4447 return CR_INVALID_POINTER;
4448 case ERROR_INVALID_FLAGS:
4449 return CR_INVALID_FLAG;
4450 case ERROR_INSUFFICIENT_BUFFER:
4451 return CR_BUFFER_SMALL;
4452 case ERROR_NOT_FOUND:
4453 return CR_NO_SUCH_VALUE;
4455 return CR_FAILURE;
4458 /***********************************************************************
4459 * CM_Get_DevNode_PropertyW (SETUPAPI.@)
4461 CONFIGRET WINAPI CM_Get_DevNode_PropertyW(DEVINST dev, const DEVPROPKEY *key, DEVPROPTYPE *type,
4462 PVOID buf, PULONG len, ULONG flags)
4464 return CM_Get_DevNode_Property_ExW(dev, key, type, buf, len, flags, NULL);
4467 /***********************************************************************
4468 * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
4470 BOOL WINAPI SetupDiInstallDeviceInterfaces(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4472 WCHAR section_ext[LINE_LEN], iface_section[LINE_LEN], refstr[LINE_LEN], guidstr[39];
4473 UINT install_flags = SPINST_ALL;
4474 struct device_iface *iface;
4475 struct device *device;
4476 struct driver *driver;
4477 void *callback_ctx;
4478 GUID iface_guid;
4479 INFCONTEXT ctx;
4480 HKEY iface_key;
4481 HINF hinf;
4482 LONG l;
4484 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
4486 if (!(device = get_device(devinfo, device_data)))
4487 return FALSE;
4489 if (!(driver = device->selected_driver))
4491 ERR("No driver selected for device %p.\n", devinfo);
4492 SetLastError(ERROR_NO_DRIVER_SELECTED);
4493 return FALSE;
4496 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4497 return FALSE;
4499 SetupDiGetActualSectionToInstallW(hinf, driver->section, section_ext, ARRAY_SIZE(section_ext), NULL, NULL);
4501 if (device->params.Flags & DI_NOFILECOPY)
4502 install_flags &= ~SPINST_FILES;
4504 callback_ctx = SetupInitDefaultQueueCallback(NULL);
4506 lstrcatW(section_ext, dotInterfaces);
4507 if (SetupFindFirstLineW(hinf, section_ext, AddInterface, &ctx))
4509 do {
4510 SetupGetStringFieldW(&ctx, 1, guidstr, ARRAY_SIZE(guidstr), NULL);
4511 SetupGetStringFieldW(&ctx, 2, refstr, ARRAY_SIZE(refstr), NULL);
4512 guidstr[37] = 0;
4513 UuidFromStringW(&guidstr[1], &iface_guid);
4515 if (!(iface = SETUPDI_CreateDeviceInterface(device, &iface_guid, refstr)))
4517 ERR("Failed to create device interface, error %#x.\n", GetLastError());
4518 continue;
4521 if ((l = create_iface_key(iface, KEY_ALL_ACCESS, &iface_key)))
4523 ERR("Failed to create interface key, error %u.\n", l);
4524 continue;
4527 SetupGetStringFieldW(&ctx, 3, iface_section, ARRAY_SIZE(iface_section), NULL);
4528 SetupInstallFromInfSectionW(NULL, hinf, iface_section, install_flags, iface_key,
4529 NULL, SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
4531 RegCloseKey(iface_key);
4532 } while (SetupFindNextMatchLineW(&ctx, AddInterface, &ctx));
4535 SetupTermDefaultQueueCallback(callback_ctx);
4537 SetupCloseInfFile(hinf);
4538 return TRUE;
4541 /***********************************************************************
4542 * SetupDiRegisterCoDeviceInstallers (SETUPAPI.@)
4544 BOOL WINAPI SetupDiRegisterCoDeviceInstallers(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4546 static const WCHAR coinstallersW[] = {'.','C','o','I','n','s','t','a','l','l','e','r','s',0};
4547 WCHAR coinst_key_ext[LINE_LEN];
4548 struct device *device;
4549 struct driver *driver;
4550 void *callback_ctx;
4551 HKEY driver_key;
4552 HINF hinf;
4553 LONG l;
4555 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
4557 if (!(device = get_device(devinfo, device_data)))
4558 return FALSE;
4560 if (!(driver = device->selected_driver))
4562 ERR("No driver selected for device %p.\n", devinfo);
4563 SetLastError(ERROR_NO_DRIVER_SELECTED);
4564 return FALSE;
4567 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4568 return FALSE;
4570 SetupDiGetActualSectionToInstallW(hinf, driver->section, coinst_key_ext, ARRAY_SIZE(coinst_key_ext), NULL, NULL);
4571 lstrcatW(coinst_key_ext, coinstallersW);
4573 if ((l = create_driver_key(device, &driver_key)))
4575 SetLastError(l);
4576 SetupCloseInfFile(hinf);
4577 return FALSE;
4580 callback_ctx = SetupInitDefaultQueueCallback(NULL);
4581 SetupInstallFromInfSectionW(NULL, hinf, coinst_key_ext, SPINST_ALL, driver_key, NULL,
4582 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
4583 SetupTermDefaultQueueCallback(callback_ctx);
4585 RegCloseKey(driver_key);
4586 SetupCloseInfFile(hinf);
4587 return TRUE;
4590 /* Check whether the given hardware or compatible ID matches any of the device's
4591 * own hardware or compatible IDs. */
4592 static BOOL device_matches_id(const struct device *device, const WCHAR *id_type, const WCHAR *id,
4593 DWORD *driver_rank)
4595 WCHAR *device_ids;
4596 const WCHAR *p;
4597 DWORD i, size;
4599 if (!RegGetValueW(device->key, NULL, id_type, RRF_RT_REG_MULTI_SZ, NULL, NULL, &size))
4601 device_ids = heap_alloc(size);
4602 if (!RegGetValueW(device->key, NULL, id_type, RRF_RT_REG_MULTI_SZ, NULL, device_ids, &size))
4604 for (p = device_ids, i = 0; *p; p += lstrlenW(p) + 1, i++)
4606 if (!wcsicmp(p, id))
4608 *driver_rank += min(i, 0xff);
4609 heap_free(device_ids);
4610 return TRUE;
4614 heap_free(device_ids);
4617 return FALSE;
4620 static BOOL version_is_compatible(const WCHAR *version)
4622 const WCHAR *machine_ext = NtPlatformExtension + 1, *p;
4623 size_t len = lstrlenW(version);
4624 BOOL wow64;
4626 /* We are only concerned with architecture. */
4627 if ((p = wcschr(version, '.')))
4628 len = p - version;
4630 if (!wcsnicmp(version, NtExtension + 1, len))
4631 return TRUE;
4633 if (IsWow64Process(GetCurrentProcess(), &wow64) && wow64)
4635 #ifdef __i386__
4636 static const WCHAR wow_ext[] = {'N','T','a','m','d','6','4',0};
4637 machine_ext = wow_ext;
4638 #elif defined(__arm__)
4639 static const WCHAR wow_ext[] = {'N','T','a','r','m','6','4',0};
4640 machine_ext = wow_ext;
4641 #endif
4644 return !wcsnicmp(version, machine_ext, len);
4647 static void enum_compat_drivers_from_file(struct device *device, const WCHAR *path)
4649 static const WCHAR manufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4650 WCHAR mfg_key[LINE_LEN], id[MAX_DEVICE_ID_LEN], version[MAX_DEVICE_ID_LEN];
4651 DWORD i, j, k, driver_count = device->driver_count;
4652 struct driver driver, *drivers = device->drivers;
4653 INFCONTEXT ctx;
4654 BOOL found;
4655 HINF hinf;
4657 TRACE("Enumerating drivers from %s.\n", debugstr_w(path));
4659 if ((hinf = SetupOpenInfFileW(path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4660 return;
4662 lstrcpyW(driver.inf_path, path);
4664 for (i = 0; SetupGetLineByIndexW(hinf, manufacturerW, i, &ctx); ++i)
4666 SetupGetStringFieldW(&ctx, 0, driver.manufacturer, ARRAY_SIZE(driver.manufacturer), NULL);
4667 if (!SetupGetStringFieldW(&ctx, 1, mfg_key, ARRAY_SIZE(mfg_key), NULL))
4668 lstrcpyW(mfg_key, driver.manufacturer);
4670 if (SetupGetFieldCount(&ctx) >= 2)
4672 BOOL compatible = FALSE;
4673 for (j = 2; SetupGetStringFieldW(&ctx, j, version, ARRAY_SIZE(version), NULL); ++j)
4675 if (version_is_compatible(version))
4677 compatible = TRUE;
4678 break;
4681 if (!compatible)
4682 continue;
4685 if (!SetupDiGetActualSectionToInstallW(hinf, mfg_key, driver.mfg_key,
4686 ARRAY_SIZE(driver.mfg_key), NULL, NULL))
4688 WARN("Failed to find section for %s, skipping.\n", debugstr_w(mfg_key));
4689 continue;
4692 for (j = 0; SetupGetLineByIndexW(hinf, driver.mfg_key, j, &ctx); ++j)
4694 driver.rank = 0;
4695 for (k = 2, found = FALSE; SetupGetStringFieldW(&ctx, k, id, ARRAY_SIZE(id), NULL); ++k)
4697 if ((found = device_matches_id(device, HardwareId, id, &driver.rank))) break;
4698 driver.rank += 0x2000;
4699 if ((found = device_matches_id(device, CompatibleIDs, id, &driver.rank))) break;
4700 driver.rank = 0x1000 + min(0x0100 * (k - 2), 0xf00);
4703 if (found)
4705 SetupGetStringFieldW(&ctx, 0, driver.description, ARRAY_SIZE(driver.description), NULL);
4706 SetupGetStringFieldW(&ctx, 1, driver.section, ARRAY_SIZE(driver.section), NULL);
4708 TRACE("Found compatible driver: rank %#x manufacturer %s, desc %s.\n",
4709 driver.rank, debugstr_w(driver.manufacturer), debugstr_w(driver.description));
4711 driver_count++;
4712 drivers = heap_realloc(drivers, driver_count * sizeof(*drivers));
4713 drivers[driver_count - 1] = driver;
4718 SetupCloseInfFile(hinf);
4720 device->drivers = drivers;
4721 device->driver_count = driver_count;
4724 /***********************************************************************
4725 * SetupDiBuildDriverInfoList (SETUPAPI.@)
4727 BOOL WINAPI SetupDiBuildDriverInfoList(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD type)
4729 struct device *device;
4731 TRACE("devinfo %p, device_data %p, type %#x.\n", devinfo, device_data, type);
4733 if (type != SPDIT_COMPATDRIVER)
4735 FIXME("Unhandled type %#x.\n", type);
4736 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4737 return FALSE;
4740 if (!(device = get_device(devinfo, device_data)))
4741 return FALSE;
4743 if (device->params.Flags & DI_ENUMSINGLEINF)
4745 enum_compat_drivers_from_file(device, device->params.DriverPath);
4747 else
4749 static const WCHAR default_path[] = {'C',':','/','w','i','n','d','o','w','s','/','i','n','f',0};
4750 static const WCHAR wildcardW[] = {'*',0};
4751 WCHAR dir[MAX_PATH], file[MAX_PATH];
4752 WIN32_FIND_DATAW find_data;
4753 HANDLE find_handle;
4755 if (device->params.DriverPath[0])
4756 lstrcpyW(dir, device->params.DriverPath);
4757 else
4758 lstrcpyW(dir, default_path);
4759 lstrcatW(dir, backslashW);
4760 lstrcatW(dir, wildcardW);
4762 TRACE("Searching for drivers in %s.\n", debugstr_w(dir));
4764 if ((find_handle = FindFirstFileW(dir, &find_data)) != INVALID_HANDLE_VALUE)
4768 lstrcpyW(file, dir);
4769 lstrcpyW(file + lstrlenW(file) - 1, find_data.cFileName);
4770 enum_compat_drivers_from_file(device, file);
4771 } while (FindNextFileW(find_handle, &find_data));
4773 FindClose(find_handle);
4777 if (device->driver_count)
4779 WCHAR classname[MAX_CLASS_NAME_LEN], guidstr[39];
4780 GUID class;
4782 if (SetupDiGetINFClassW(device->drivers[0].inf_path, &class, classname, ARRAY_SIZE(classname), NULL))
4784 device_data->ClassGuid = device->class = class;
4785 SETUPDI_GuidToString(&class, guidstr);
4786 RegSetValueExW(device->key, L"ClassGUID", 0, REG_SZ, (BYTE *)guidstr, sizeof(guidstr));
4787 RegSetValueExW(device->key, L"Class", 0, REG_SZ, (BYTE *)classname, wcslen(classname) * sizeof(WCHAR));
4791 return TRUE;
4794 static BOOL copy_driver_data(SP_DRVINFO_DATA_W *data, const struct driver *driver)
4796 INFCONTEXT ctx;
4797 HINF hinf;
4799 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4800 return FALSE;
4802 data->ProviderName[0] = 0;
4803 if (SetupFindFirstLineW(hinf, L"Version", L"Provider", &ctx))
4804 SetupGetStringFieldW(&ctx, 1, data->ProviderName, ARRAY_SIZE(data->ProviderName), NULL);
4805 wcscpy(data->Description, driver->description);
4806 wcscpy(data->MfgName, driver->manufacturer);
4807 data->DriverType = SPDIT_COMPATDRIVER;
4808 data->Reserved = (ULONG_PTR)driver;
4810 SetupCloseInfFile(hinf);
4812 return TRUE;
4815 static void driver_data_wtoa(SP_DRVINFO_DATA_A *a, const SP_DRVINFO_DATA_W *w)
4817 a->DriverType = w->DriverType;
4818 a->Reserved = w->Reserved;
4819 WideCharToMultiByte(CP_ACP, 0, w->Description, -1, a->Description, sizeof(a->Description), NULL, NULL);
4820 WideCharToMultiByte(CP_ACP, 0, w->MfgName, -1, a->MfgName, sizeof(a->MfgName), NULL, NULL);
4821 WideCharToMultiByte(CP_ACP, 0, w->ProviderName, -1, a->ProviderName, sizeof(a->ProviderName), NULL, NULL);
4824 /***********************************************************************
4825 * SetupDiEnumDriverInfoW (SETUPAPI.@)
4827 BOOL WINAPI SetupDiEnumDriverInfoW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4828 DWORD type, DWORD index, SP_DRVINFO_DATA_W *driver_data)
4830 struct device *device;
4832 TRACE("devinfo %p, device_data %p, type %#x, index %u, driver_data %p.\n",
4833 devinfo, device_data, type, index, driver_data);
4835 if (type != SPDIT_COMPATDRIVER)
4837 FIXME("Unhandled type %#x.\n", type);
4838 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4839 return FALSE;
4842 if (!(device = get_device(devinfo, device_data)))
4843 return FALSE;
4845 if (index >= device->driver_count)
4847 SetLastError(ERROR_NO_MORE_ITEMS);
4848 return FALSE;
4851 return copy_driver_data(driver_data, &device->drivers[index]);
4854 /***********************************************************************
4855 * SetupDiEnumDriverInfoA (SETUPAPI.@)
4857 BOOL WINAPI SetupDiEnumDriverInfoA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4858 DWORD type, DWORD index, SP_DRVINFO_DATA_A *driver_data)
4860 SP_DRVINFO_DATA_W driver_dataW;
4861 BOOL ret;
4863 driver_dataW.cbSize = sizeof(driver_dataW);
4864 ret = SetupDiEnumDriverInfoW(devinfo, device_data, type, index, &driver_dataW);
4865 if (ret) driver_data_wtoa(driver_data, &driver_dataW);
4867 return ret;
4870 /***********************************************************************
4871 * SetupDiSelectBestCompatDrv (SETUPAPI.@)
4873 BOOL WINAPI SetupDiSelectBestCompatDrv(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4875 struct device *device;
4876 struct driver *best;
4877 DWORD i;
4879 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
4881 if (!(device = get_device(devinfo, device_data)))
4882 return FALSE;
4884 if (!device->driver_count)
4886 WARN("No compatible drivers were enumerated for device %s.\n", debugstr_w(device->instanceId));
4887 SetLastError(ERROR_NO_COMPAT_DRIVERS);
4888 return FALSE;
4891 best = device->drivers;
4892 for (i = 1; i < device->driver_count; ++i)
4894 if (device->drivers[i].rank >= best->rank) continue;
4895 best = device->drivers + i;
4898 TRACE("selected driver: rank %#x manufacturer %s, desc %s.\n",
4899 best->rank, debugstr_w(best->manufacturer), debugstr_w(best->description));
4901 device->selected_driver = best;
4902 return TRUE;
4905 /***********************************************************************
4906 * SetupDiGetSelectedDriverW (SETUPAPI.@)
4908 BOOL WINAPI SetupDiGetSelectedDriverW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, SP_DRVINFO_DATA_W *driver_data)
4910 struct device *device;
4912 TRACE("devinfo %p, device_data %p, driver_data %p.\n", devinfo, device_data, driver_data);
4914 if (!(device = get_device(devinfo, device_data)))
4915 return FALSE;
4917 if (!device->selected_driver)
4919 SetLastError(ERROR_NO_DRIVER_SELECTED);
4920 return FALSE;
4923 return copy_driver_data(driver_data, device->selected_driver);
4926 /***********************************************************************
4927 * SetupDiGetSelectedDriverA (SETUPAPI.@)
4929 BOOL WINAPI SetupDiGetSelectedDriverA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, SP_DRVINFO_DATA_A *driver_data)
4931 SP_DRVINFO_DATA_W driver_dataW;
4932 BOOL ret;
4934 driver_dataW.cbSize = sizeof(driver_dataW);
4935 if ((ret = SetupDiGetSelectedDriverW(devinfo, device_data, &driver_dataW)))
4936 driver_data_wtoa(driver_data, &driver_dataW);
4937 return ret;
4940 /***********************************************************************
4941 * SetupDiGetDriverInfoDetailW (SETUPAPI.@)
4943 BOOL WINAPI SetupDiGetDriverInfoDetailW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4944 SP_DRVINFO_DATA_W *driver_data, SP_DRVINFO_DETAIL_DATA_W *detail_data, const DWORD size, DWORD *ret_size)
4946 struct driver *driver = (struct driver *)driver_data->Reserved;
4947 DWORD size_needed, i, id_size = 1;
4948 WCHAR id[MAX_DEVICE_ID_LEN];
4949 INFCONTEXT ctx;
4950 HANDLE file;
4951 HINF hinf;
4953 TRACE("devinfo %p, device_data %p, driver_data %p, detail_data %p, size %u, ret_size %p.\n",
4954 devinfo, device_data, driver_data, detail_data, size, ret_size);
4956 if ((detail_data || size) && size < sizeof(SP_DRVINFO_DETAIL_DATA_W))
4958 SetLastError(ERROR_INVALID_USER_BUFFER);
4959 return FALSE;
4962 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4963 return FALSE;
4965 SetupFindFirstLineW(hinf, driver->mfg_key, driver->description, &ctx);
4966 for (i = 2; SetupGetStringFieldW(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
4967 id_size += wcslen(id) + 1;
4969 size_needed = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID[id_size]);
4970 if (ret_size)
4971 *ret_size = size_needed;
4972 if (!detail_data)
4973 return TRUE;
4975 detail_data->CompatIDsLength = detail_data->CompatIDsOffset = 0;
4976 detail_data->HardwareID[0] = 0;
4978 if (size >= size_needed)
4980 id_size = 0;
4981 for (i = 2; SetupGetStringFieldW(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
4983 wcscpy(&detail_data->HardwareID[id_size], id);
4984 if (i == 3)
4985 detail_data->CompatIDsOffset = id_size;
4986 id_size += wcslen(id) + 1;
4988 detail_data->HardwareID[id_size++] = 0;
4989 if (i > 3)
4990 detail_data->CompatIDsLength = id_size - detail_data->CompatIDsOffset;
4993 SetupCloseInfFile(hinf);
4995 if ((file = CreateFileW(driver->inf_path, 0, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
4996 return FALSE;
4997 GetFileTime(file, NULL, NULL, &detail_data->InfDate);
4998 CloseHandle(file);
5000 wcscpy(detail_data->SectionName, driver->section);
5001 wcscpy(detail_data->InfFileName, driver->inf_path);
5002 wcscpy(detail_data->DrvDescription, driver->description);
5004 if (size < size_needed)
5006 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5007 return FALSE;
5010 return TRUE;
5013 /***********************************************************************
5014 * SetupDiGetDriverInfoDetailA (SETUPAPI.@)
5016 BOOL WINAPI SetupDiGetDriverInfoDetailA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
5017 SP_DRVINFO_DATA_A *driver_data, SP_DRVINFO_DETAIL_DATA_A *detail_data, const DWORD size, DWORD *ret_size)
5019 struct driver *driver = (struct driver *)driver_data->Reserved;
5020 DWORD size_needed, i, id_size = 1;
5021 char id[MAX_DEVICE_ID_LEN];
5022 INFCONTEXT ctx;
5023 HANDLE file;
5024 HINF hinf;
5026 TRACE("devinfo %p, device_data %p, driver_data %p, detail_data %p, size %u, ret_size %p.\n",
5027 devinfo, device_data, driver_data, detail_data, size, ret_size);
5029 if ((detail_data || size) && size < sizeof(SP_DRVINFO_DETAIL_DATA_A))
5031 SetLastError(ERROR_INVALID_USER_BUFFER);
5032 return FALSE;
5035 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
5036 return FALSE;
5038 SetupFindFirstLineW(hinf, driver->mfg_key, driver->description, &ctx);
5039 for (i = 2; SetupGetStringFieldA(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
5040 id_size += strlen(id) + 1;
5042 size_needed = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID[id_size]);
5043 if (ret_size)
5044 *ret_size = size_needed;
5045 if (!detail_data)
5047 SetupCloseInfFile(hinf);
5048 return TRUE;
5051 detail_data->CompatIDsLength = detail_data->CompatIDsOffset = 0;
5052 detail_data->HardwareID[0] = 0;
5054 if (size >= size_needed)
5056 id_size = 0;
5057 for (i = 2; SetupGetStringFieldA(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
5059 strcpy(&detail_data->HardwareID[id_size], id);
5060 if (i == 3)
5061 detail_data->CompatIDsOffset = id_size;
5062 id_size += strlen(id) + 1;
5064 detail_data->HardwareID[id_size++] = 0;
5065 if (i > 3)
5066 detail_data->CompatIDsLength = id_size - detail_data->CompatIDsOffset;
5069 SetupCloseInfFile(hinf);
5071 if ((file = CreateFileW(driver->inf_path, 0, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
5072 return FALSE;
5073 GetFileTime(file, NULL, NULL, &detail_data->InfDate);
5074 CloseHandle(file);
5076 WideCharToMultiByte(CP_ACP, 0, driver->section, -1, detail_data->SectionName,
5077 sizeof(detail_data->SectionName), NULL, NULL);
5078 WideCharToMultiByte(CP_ACP, 0, driver->inf_path, -1, detail_data->InfFileName,
5079 sizeof(detail_data->InfFileName), NULL, NULL);
5080 WideCharToMultiByte(CP_ACP, 0, driver->description, -1, detail_data->DrvDescription,
5081 sizeof(detail_data->InfFileName), NULL, NULL);
5083 if (size < size_needed)
5085 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5086 return FALSE;
5089 return TRUE;
5092 /***********************************************************************
5093 * SetupDiInstallDriverFiles (SETUPAPI.@)
5095 BOOL WINAPI SetupDiInstallDriverFiles(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
5097 WCHAR section[LINE_LEN], section_ext[LINE_LEN], iface_section[LINE_LEN];
5098 struct device *device;
5099 struct driver *driver;
5100 void *callback_ctx;
5101 INFCONTEXT ctx;
5102 HINF hinf;
5104 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
5106 if (!(device = get_device(devinfo, device_data)))
5107 return FALSE;
5109 if (!(driver = device->selected_driver))
5111 ERR("No driver selected for device %p.\n", devinfo);
5112 SetLastError(ERROR_NO_DRIVER_SELECTED);
5113 return FALSE;
5116 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
5117 return FALSE;
5119 SetupFindFirstLineW(hinf, driver->mfg_key, driver->description, &ctx);
5120 SetupGetStringFieldW(&ctx, 1, section, ARRAY_SIZE(section), NULL);
5121 SetupDiGetActualSectionToInstallW(hinf, section, section_ext, ARRAY_SIZE(section_ext), NULL, NULL);
5123 callback_ctx = SetupInitDefaultQueueCallback(NULL);
5125 SetupInstallFromInfSectionW(NULL, hinf, section_ext, SPINST_FILES, NULL, NULL,
5126 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5128 lstrcatW(section_ext, dotInterfaces);
5129 if (SetupFindFirstLineW(hinf, section_ext, AddInterface, &ctx))
5131 do {
5132 SetupGetStringFieldW(&ctx, 3, iface_section, ARRAY_SIZE(iface_section), NULL);
5133 SetupInstallFromInfSectionW(NULL, hinf, iface_section, SPINST_FILES, NULL, NULL,
5134 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5135 } while (SetupFindNextMatchLineW(&ctx, AddInterface, &ctx));
5138 SetupTermDefaultQueueCallback(callback_ctx);
5140 SetupCloseInfFile(hinf);
5141 return TRUE;
5144 /***********************************************************************
5145 * SetupDiInstallDevice (SETUPAPI.@)
5147 BOOL WINAPI SetupDiInstallDevice(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
5149 static const WCHAR infpathW[] = {'I','n','f','P','a','t','h',0};
5150 static const WCHAR infsectionW[] = {'I','n','f','S','e','c','t','i','o','n',0};
5151 static const WCHAR infsectionextW[] = {'I','n','f','S','e','c','t','i','o','n','E','x','t',0};
5152 static const WCHAR dothwW[] = {'.','H','W',0};
5153 static const WCHAR dotservicesW[] = {'.','S','e','r','v','i','c','e','s',0};
5154 static const WCHAR addserviceW[] = {'A','d','d','S','e','r','v','i','c','e',0};
5155 static const WCHAR rootW[] = {'r','o','o','t','\\',0};
5156 WCHAR section_ext[LINE_LEN], subsection[LINE_LEN], inf_path[MAX_PATH], *extptr, *filepart;
5157 UINT install_flags = SPINST_ALL;
5158 HKEY driver_key, device_key;
5159 SC_HANDLE manager, service;
5160 WCHAR svc_name[LINE_LEN];
5161 struct device *device;
5162 struct driver *driver;
5163 void *callback_ctx;
5164 INFCONTEXT ctx;
5165 HINF hinf;
5166 LONG l;
5168 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
5170 if (!(device = get_device(devinfo, device_data)))
5171 return FALSE;
5173 if (!(driver = device->selected_driver))
5175 ERR("No driver selected for device %p.\n", devinfo);
5176 SetLastError(ERROR_NO_DRIVER_SELECTED);
5177 return FALSE;
5180 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
5181 return FALSE;
5183 RegSetValueExW(device->key, L"DeviceDesc", 0, REG_SZ, (BYTE *)driver->description,
5184 wcslen(driver->description) * sizeof(WCHAR));
5186 SetupDiGetActualSectionToInstallW(hinf, driver->section, section_ext, ARRAY_SIZE(section_ext), NULL, &extptr);
5188 if ((l = create_driver_key(device, &driver_key)))
5190 SetLastError(l);
5191 SetupCloseInfFile(hinf);
5192 return FALSE;
5195 if ((l = RegCreateKeyExW(device->key, DeviceParameters, 0, NULL, 0,
5196 KEY_READ | KEY_WRITE, NULL, &device_key, NULL)))
5198 SetLastError(l);
5199 RegCloseKey(driver_key);
5200 SetupCloseInfFile(hinf);
5201 return FALSE;
5204 if (device->params.Flags & DI_NOFILECOPY)
5205 install_flags &= ~SPINST_FILES;
5207 callback_ctx = SetupInitDefaultQueueCallback(NULL);
5209 SetupInstallFromInfSectionW(NULL, hinf, section_ext, install_flags, driver_key, NULL,
5210 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5212 lstrcpyW(subsection, section_ext);
5213 lstrcatW(subsection, dothwW);
5215 SetupInstallFromInfSectionW(NULL, hinf, subsection, install_flags, device_key, NULL,
5216 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5218 lstrcpyW(subsection, section_ext);
5219 lstrcatW(subsection, dotservicesW);
5220 SetupInstallServicesFromInfSectionW(hinf, subsection, 0);
5222 svc_name[0] = 0;
5223 if (SetupFindFirstLineW(hinf, subsection, addserviceW, &ctx))
5227 INT flags;
5229 if (SetupGetIntField(&ctx, 2, &flags) && (flags & SPSVCINST_ASSOCSERVICE))
5231 if (SetupGetStringFieldW(&ctx, 1, svc_name, ARRAY_SIZE(svc_name), NULL) && svc_name[0])
5232 RegSetValueExW(device->key, Service, 0, REG_SZ, (BYTE *)svc_name, lstrlenW(svc_name) * sizeof(WCHAR));
5233 break;
5235 } while (SetupFindNextMatchLineW(&ctx, addserviceW, &ctx));
5238 SetupTermDefaultQueueCallback(callback_ctx);
5239 SetupCloseInfFile(hinf);
5241 SetupCopyOEMInfW(driver->inf_path, NULL, SPOST_NONE, 0, inf_path, ARRAY_SIZE(inf_path), NULL, &filepart);
5242 TRACE("Copied INF file %s to %s.\n", debugstr_w(driver->inf_path), debugstr_w(inf_path));
5244 RegSetValueExW(driver_key, infpathW, 0, REG_SZ, (BYTE *)filepart, lstrlenW(filepart) * sizeof(WCHAR));
5245 RegSetValueExW(driver_key, infsectionW, 0, REG_SZ, (BYTE *)driver->section, lstrlenW(driver->section) * sizeof(WCHAR));
5246 if (extptr)
5247 RegSetValueExW(driver_key, infsectionextW, 0, REG_SZ, (BYTE *)extptr, lstrlenW(extptr) * sizeof(WCHAR));
5249 RegCloseKey(device_key);
5250 RegCloseKey(driver_key);
5252 if (!wcsnicmp(device->instanceId, rootW, lstrlenW(rootW)) && svc_name[0]
5253 && (manager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT)))
5255 if ((service = OpenServiceW(manager, svc_name, SERVICE_START | SERVICE_USER_DEFINED_CONTROL)))
5257 SERVICE_STATUS status;
5259 if (!StartServiceW(service, 0, NULL) && GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5261 ERR("Failed to start service %s for device %s, error %u.\n",
5262 debugstr_w(svc_name), debugstr_w(device->instanceId), GetLastError());
5264 if (!ControlService(service, SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES, &status))
5266 ERR("Failed to control service %s for device %s, error %u.\n",
5267 debugstr_w(svc_name), debugstr_w(device->instanceId), GetLastError());
5269 CloseServiceHandle(service);
5271 else
5272 ERR("Failed to open service %s for device %s.\n", debugstr_w(svc_name), debugstr_w(device->instanceId));
5273 CloseServiceHandle(manager);
5276 return TRUE;