setupapi: Use the "section" and "description" fields directly in more places.
[wine.git] / dlls / setupapi / devinst.c
bloba21959a262aa1c8a9af8c68e2afdfe7e95cefb96
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>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winnt.h"
26 #include "winreg.h"
27 #include "winternl.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winnls.h"
31 #include "winsvc.h"
32 #include "setupapi.h"
33 #include "wine/debug.h"
34 #include "wine/heap.h"
35 #include "wine/list.h"
36 #include "cfgmgr32.h"
37 #include "winioctl.h"
38 #include "rpc.h"
39 #include "rpcdce.h"
40 #include "cguid.h"
42 #include "setupapi_private.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
47 /* Unicode constants */
48 static const WCHAR Chicago[] = {'$','C','h','i','c','a','g','o','$',0};
49 static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0};
50 static const WCHAR Class[] = {'C','l','a','s','s',0};
51 static const WCHAR ClassInstall32[] = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
52 static const WCHAR NoDisplayClass[] = {'N','o','D','i','s','p','l','a','y','C','l','a','s','s',0};
53 static const WCHAR NoInstallClass[] = {'N','o','I','n','s','t','a','l','l','C','l','a','s','s',0};
54 static const WCHAR NoUseClass[] = {'N','o','U','s','e','C','l','a','s','s',0};
55 static const WCHAR NtExtension[] = {'.','N','T',0};
56 #ifdef __i386__
57 static const WCHAR NtPlatformExtension[] = {'.','N','T','x','8','6',0};
58 #elif defined(__x86_64__)
59 static const WCHAR NtPlatformExtension[] = {'.','N','T','a','m','d','6','4',0};
60 #elif defined(__arm__)
61 static const WCHAR NtPlatformExtension[] = {'.','N','T','a','r','m',0};
62 #elif defined(__aarch64__)
63 static const WCHAR NtPlatformExtension[] = {'.','N','T','a','r','m','6','4',0};
64 #endif
65 static const WCHAR Signature[] = {'S','i','g','n','a','t','u','r','e',0};
66 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
67 static const WCHAR WinExtension[] = {'.','W','i','n',0};
68 static const WCHAR WindowsNT[] = {'$','W','i','n','d','o','w','s',' ','N','T','$',0};
70 /* Registry key and value names */
71 static const WCHAR ControlClass[] = {'S','y','s','t','e','m','\\',
72 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
73 'C','o','n','t','r','o','l','\\',
74 'C','l','a','s','s',0};
76 static const WCHAR DeviceClasses[] = {'S','y','s','t','e','m','\\',
77 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
78 'C','o','n','t','r','o','l','\\',
79 'D','e','v','i','c','e','C','l','a','s','s','e','s',0};
80 static const WCHAR Enum[] = {'S','y','s','t','e','m','\\',
81 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
82 'E','n','u','m',0};
83 static const WCHAR DeviceDesc[] = {'D','e','v','i','c','e','D','e','s','c',0};
84 static const WCHAR DeviceInstance[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
85 static const WCHAR DeviceParameters[] = {'D','e','v','i','c','e',' ','P','a','r','a','m','e','t','e','r','s',0};
86 static const WCHAR HardwareId[] = {'H','a','r','d','w','a','r','e','I','D',0};
87 static const WCHAR CompatibleIDs[] = {'C','o','m','p','a','t','i','b','l','e','I','d','s',0};
88 static const WCHAR Service[] = {'S','e','r','v','i','c','e',0};
89 static const WCHAR Driver[] = {'D','r','i','v','e','r',0};
90 static const WCHAR ConfigFlags[] = {'C','o','n','f','i','g','F','l','a','g','s',0};
91 static const WCHAR Mfg[] = {'M','f','g',0};
92 static const WCHAR FriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
93 static const WCHAR LocationInformation[] = {'L','o','c','a','t','i','o','n','I','n','f','o','r','m','a','t','i','o','n',0};
94 static const WCHAR Capabilities[] = {'C','a','p','a','b','i','l','i','t','i','e','s',0};
95 static const WCHAR UINumber[] = {'U','I','N','u','m','b','e','r',0};
96 static const WCHAR UpperFilters[] = {'U','p','p','e','r','F','i','l','t','e','r','s',0};
97 static const WCHAR LowerFilters[] = {'L','o','w','e','r','F','i','l','t','e','r','s',0};
98 static const WCHAR Phantom[] = {'P','h','a','n','t','o','m',0};
99 static const WCHAR SymbolicLink[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
100 static const WCHAR Control[] = {'C','o','n','t','r','o','l',0};
101 static const WCHAR Linked[] = {'L','i','n','k','e','d',0};
102 static const WCHAR dotInterfaces[] = {'.','I','n','t','e','r','f','a','c','e','s',0};
103 static const WCHAR AddInterface[] = {'A','d','d','I','n','t','e','r','f','a','c','e',0};
104 static const WCHAR backslashW[] = {'\\',0};
105 static const WCHAR emptyW[] = {0};
107 struct driver
109 WCHAR inf_path[MAX_PATH];
110 WCHAR manufacturer[LINE_LEN];
111 WCHAR mfg_key[LINE_LEN];
112 WCHAR description[LINE_LEN];
113 WCHAR section[LINE_LEN];
116 /* is used to identify if a DeviceInfoSet pointer is
117 valid or not */
118 #define SETUP_DEVICE_INFO_SET_MAGIC 0xd00ff056
120 struct DeviceInfoSet
122 DWORD magic; /* if is equal to SETUP_DEVICE_INFO_SET_MAGIC struct is okay */
123 GUID ClassGuid;
124 HWND hwndParent;
125 struct list devices;
128 struct device
130 struct DeviceInfoSet *set;
131 HKEY key;
132 BOOL phantom;
133 WCHAR *instanceId;
134 struct list interfaces;
135 GUID class;
136 DEVINST devnode;
137 struct list entry;
138 BOOL removed;
139 SP_DEVINSTALL_PARAMS_W params;
140 struct driver *drivers;
141 unsigned int driver_count;
142 struct driver *selected_driver;
145 struct device_iface
147 WCHAR *refstr;
148 WCHAR *symlink;
149 struct device *device;
150 GUID class;
151 DWORD flags;
152 HKEY class_key;
153 HKEY refstr_key;
154 struct list entry;
157 static struct DeviceInfoSet *get_device_set(HDEVINFO devinfo)
159 struct DeviceInfoSet *set = devinfo;
161 if (!devinfo || devinfo == INVALID_HANDLE_VALUE || set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
163 SetLastError(ERROR_INVALID_HANDLE);
164 return NULL;
167 return set;
170 static struct device *get_device(HDEVINFO devinfo, const SP_DEVINFO_DATA *data)
172 struct DeviceInfoSet *set;
173 struct device *device;
175 if (!(set = get_device_set(devinfo)))
176 return FALSE;
178 if (!data || data->cbSize != sizeof(*data) || !data->Reserved)
180 SetLastError(ERROR_INVALID_PARAMETER);
181 return NULL;
184 device = (struct device *)data->Reserved;
186 if (device->set != set)
188 SetLastError(ERROR_INVALID_PARAMETER);
189 return NULL;
192 if (device->removed)
194 SetLastError(ERROR_NO_SUCH_DEVINST);
195 return NULL;
198 return device;
201 static struct device_iface *get_device_iface(HDEVINFO devinfo, const SP_DEVICE_INTERFACE_DATA *data)
203 if (!get_device_set(devinfo))
204 return FALSE;
206 if (!data || data->cbSize != sizeof(*data) || !data->Reserved)
208 SetLastError(ERROR_INVALID_PARAMETER);
209 return NULL;
212 return (struct device_iface *)data->Reserved;
215 static inline void copy_device_data(SP_DEVINFO_DATA *data, const struct device *device)
217 data->ClassGuid = device->class;
218 data->DevInst = device->devnode;
219 data->Reserved = (ULONG_PTR)device;
222 static inline void copy_device_iface_data(SP_DEVICE_INTERFACE_DATA *data,
223 const struct device_iface *iface)
225 data->InterfaceClassGuid = iface->class;
226 data->Flags = iface->flags;
227 data->Reserved = (ULONG_PTR)iface;
230 static struct device **devnode_table;
231 static unsigned int devnode_table_size;
233 static DEVINST alloc_devnode(struct device *device)
235 unsigned int i;
237 for (i = 0; i < devnode_table_size; ++i)
239 if (!devnode_table[i])
240 break;
243 if (i == devnode_table_size)
245 if (devnode_table)
247 devnode_table_size *= 2;
248 devnode_table = heap_realloc_zero(devnode_table,
249 devnode_table_size * sizeof(*devnode_table));
251 else
253 devnode_table_size = 256;
254 devnode_table = heap_alloc_zero(devnode_table_size * sizeof(*devnode_table));
258 devnode_table[i] = device;
259 return i;
262 static void free_devnode(DEVINST devnode)
264 devnode_table[devnode] = NULL;
267 static struct device *get_devnode_device(DEVINST devnode)
269 if (devnode < devnode_table_size)
270 return devnode_table[devnode];
272 WARN("device node %u not found\n", devnode);
273 return NULL;
276 static void SETUPDI_GuidToString(const GUID *guid, LPWSTR guidStr)
278 static const WCHAR fmt[] = {'{','%','0','8','X','-','%','0','4','X','-',
279 '%','0','4','X','-','%','0','2','X','%','0','2','X','-','%','0','2',
280 'X','%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X','%',
281 '0','2','X','}',0};
283 swprintf(guidStr, 39, fmt, guid->Data1, guid->Data2, guid->Data3,
284 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
285 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
288 static WCHAR *get_iface_key_path(struct device_iface *iface)
290 static const WCHAR slashW[] = {'\\',0};
291 WCHAR *path, *ptr;
292 size_t len = lstrlenW(DeviceClasses) + 1 + 38 + 1 + lstrlenW(iface->symlink);
294 if (!(path = heap_alloc((len + 1) * sizeof(WCHAR))))
296 SetLastError(ERROR_OUTOFMEMORY);
297 return NULL;
300 lstrcpyW(path, DeviceClasses);
301 lstrcatW(path, slashW);
302 SETUPDI_GuidToString(&iface->class, path + lstrlenW(path));
303 lstrcatW(path, slashW);
304 ptr = path + lstrlenW(path);
305 lstrcatW(path, iface->symlink);
306 if (lstrlenW(iface->symlink) > 3)
307 ptr[0] = ptr[1] = ptr[3] = '#';
309 ptr = wcschr(ptr, '\\');
310 if (ptr) *ptr = 0;
312 return path;
315 static WCHAR *get_refstr_key_path(struct device_iface *iface)
317 static const WCHAR hashW[] = {'#',0};
318 static const WCHAR slashW[] = {'\\',0};
319 WCHAR *path, *ptr;
320 size_t len = lstrlenW(DeviceClasses) + 1 + 38 + 1 + lstrlenW(iface->symlink) + 1 + 1;
322 if (iface->refstr)
323 len += lstrlenW(iface->refstr);
325 if (!(path = heap_alloc((len + 1) * sizeof(WCHAR))))
327 SetLastError(ERROR_OUTOFMEMORY);
328 return NULL;
331 lstrcpyW(path, DeviceClasses);
332 lstrcatW(path, slashW);
333 SETUPDI_GuidToString(&iface->class, path + lstrlenW(path));
334 lstrcatW(path, slashW);
335 ptr = path + lstrlenW(path);
336 lstrcatW(path, iface->symlink);
337 if (lstrlenW(iface->symlink) > 3)
338 ptr[0] = ptr[1] = ptr[3] = '#';
340 ptr = wcschr(ptr, '\\');
341 if (ptr) *ptr = 0;
343 lstrcatW(path, slashW);
344 lstrcatW(path, hashW);
346 if (iface->refstr)
347 lstrcatW(path, iface->refstr);
349 return path;
352 static BOOL is_valid_property_type(DEVPROPTYPE prop_type)
354 DWORD type = prop_type & DEVPROP_MASK_TYPE;
355 DWORD typemod = prop_type & DEVPROP_MASK_TYPEMOD;
357 if (type > MAX_DEVPROP_TYPE)
358 return FALSE;
359 if (typemod > MAX_DEVPROP_TYPEMOD)
360 return FALSE;
362 if (typemod == DEVPROP_TYPEMOD_ARRAY
363 && (type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL || type == DEVPROP_TYPE_STRING
364 || type == DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING))
365 return FALSE;
367 if (typemod == DEVPROP_TYPEMOD_LIST
368 && !(type == DEVPROP_TYPE_STRING || type == DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING))
369 return FALSE;
371 return TRUE;
374 static LPWSTR SETUPDI_CreateSymbolicLinkPath(LPCWSTR instanceId,
375 const GUID *InterfaceClassGuid, LPCWSTR ReferenceString)
377 static const WCHAR fmt[] = {'\\','\\','?','\\','%','s','#','%','s',0};
378 WCHAR guidStr[39];
379 DWORD len;
380 LPWSTR ret;
382 SETUPDI_GuidToString(InterfaceClassGuid, guidStr);
383 /* omit length of format specifiers, but include NULL terminator: */
384 len = lstrlenW(fmt) - 4 + 1;
385 len += lstrlenW(instanceId) + lstrlenW(guidStr);
386 if (ReferenceString && *ReferenceString)
388 /* space for a hash between string and reference string: */
389 len += lstrlenW(ReferenceString) + 1;
391 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
392 if (ret)
394 int printed = swprintf(ret, len, fmt, instanceId, guidStr);
395 LPWSTR ptr;
397 /* replace '\\' with '#' after the "\\\\?\\" beginning */
398 for (ptr = wcschr(ret + 4, '\\'); ptr; ptr = wcschr(ptr + 1, '\\'))
399 *ptr = '#';
400 if (ReferenceString && *ReferenceString)
402 ret[printed] = '\\';
403 lstrcpyW(ret + printed + 1, ReferenceString);
406 return ret;
409 static BOOL is_linked(HKEY key)
411 DWORD linked, type, size;
412 HKEY control_key;
413 BOOL ret = FALSE;
415 if (!RegOpenKeyW(key, Control, &control_key))
417 size = sizeof(DWORD);
418 if (!RegQueryValueExW(control_key, Linked, NULL, &type, (BYTE *)&linked, &size)
419 && type == REG_DWORD && linked)
420 ret = TRUE;
422 RegCloseKey(control_key);
425 return ret;
428 static struct device_iface *SETUPDI_CreateDeviceInterface(struct device *device,
429 const GUID *class, const WCHAR *refstr)
431 struct device_iface *iface = NULL;
432 WCHAR *refstr2 = NULL, *symlink = NULL, *path = NULL;
433 HKEY key;
434 LONG ret;
436 TRACE("%p %s %s\n", device, debugstr_guid(class), debugstr_w(refstr));
438 /* check if it already exists */
439 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
441 if (IsEqualGUID(&iface->class, class) && !lstrcmpiW(iface->refstr, refstr))
442 return iface;
445 iface = heap_alloc(sizeof(*iface));
446 symlink = SETUPDI_CreateSymbolicLinkPath(device->instanceId, class, refstr);
448 if (!iface || !symlink)
450 SetLastError(ERROR_OUTOFMEMORY);
451 goto err;
454 if (refstr && !(refstr2 = strdupW(refstr)))
456 SetLastError(ERROR_OUTOFMEMORY);
457 goto err;
459 iface->refstr = refstr2;
460 iface->symlink = symlink;
461 iface->device = device;
462 iface->class = *class;
463 iface->flags = 0;
465 if (!(path = get_iface_key_path(iface)))
467 SetLastError(ERROR_OUTOFMEMORY);
468 goto err;
471 if ((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, path, &key)))
473 SetLastError(ret);
474 goto err;
476 RegSetValueExW(key, DeviceInstance, 0, REG_SZ, (BYTE *)device->instanceId,
477 lstrlenW(device->instanceId) * sizeof(WCHAR));
478 heap_free(path);
480 iface->class_key = key;
482 if (!(path = get_refstr_key_path(iface)))
484 SetLastError(ERROR_OUTOFMEMORY);
485 goto err;
488 if ((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, path, &key)))
490 SetLastError(ret);
491 goto err;
493 RegSetValueExW(key, SymbolicLink, 0, REG_SZ, (BYTE *)iface->symlink,
494 lstrlenW(iface->symlink) * sizeof(WCHAR));
496 if (is_linked(key))
497 iface->flags |= SPINT_ACTIVE;
499 heap_free(path);
501 iface->refstr_key = key;
503 list_add_tail(&device->interfaces, &iface->entry);
504 return iface;
506 err:
507 heap_free(iface);
508 heap_free(refstr2);
509 heap_free(symlink);
510 heap_free(path);
511 return NULL;
514 static BOOL SETUPDI_SetInterfaceSymbolicLink(struct device_iface *iface,
515 const WCHAR *symlink)
517 heap_free(iface->symlink);
518 if ((iface->symlink = strdupW(symlink)))
519 return TRUE;
520 return FALSE;
523 static HKEY SETUPDI_CreateDevKey(struct device *device)
525 HKEY enumKey, key = INVALID_HANDLE_VALUE;
526 LONG l;
528 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_ALL_ACCESS,
529 NULL, &enumKey, NULL);
530 if (!l)
532 RegCreateKeyExW(enumKey, device->instanceId, 0, NULL, 0,
533 KEY_READ | KEY_WRITE, NULL, &key, NULL);
534 RegCloseKey(enumKey);
536 return key;
539 static LONG open_driver_key(struct device *device, REGSAM access, HKEY *key)
541 HKEY class_key;
542 WCHAR path[50];
543 DWORD size = sizeof(path);
544 LONG l;
546 if ((l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, ControlClass, 0, NULL, 0,
547 KEY_CREATE_SUB_KEY, NULL, &class_key, NULL)))
549 ERR("Failed to open driver class root key, error %u.\n", l);
550 return l;
553 if (!(l = RegGetValueW(device->key, NULL, Driver, RRF_RT_REG_SZ, NULL, path, &size)))
555 if (!(l = RegOpenKeyExW(class_key, path, 0, access, key)))
557 RegCloseKey(class_key);
558 return l;
560 ERR("Failed to open driver key, error %u.\n", l);
563 RegCloseKey(class_key);
564 return l;
567 static LONG create_driver_key(struct device *device, HKEY *key)
569 static const WCHAR formatW[] = {'%','0','4','u',0};
570 static const WCHAR slash[] = { '\\',0 };
571 unsigned int i = 0;
572 WCHAR path[50];
573 HKEY class_key;
574 DWORD dispos;
575 LONG l;
577 if (!open_driver_key(device, KEY_READ | KEY_WRITE, key))
578 return ERROR_SUCCESS;
580 if ((l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, ControlClass, 0, NULL, 0,
581 KEY_CREATE_SUB_KEY, NULL, &class_key, NULL)))
583 ERR("Failed to open driver class root key, error %u.\n", l);
584 return l;
587 SETUPDI_GuidToString(&device->class, path);
588 lstrcatW(path, slash);
589 /* Allocate a new driver key, by finding the first integer value that's not
590 * already taken. */
591 for (;;)
593 swprintf(path + 39, ARRAY_SIZE(path) - 39, formatW, i++);
594 if ((l = RegCreateKeyExW(class_key, path, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, key, &dispos)))
595 break;
596 else if (dispos == REG_CREATED_NEW_KEY)
598 RegSetValueExW(device->key, Driver, 0, REG_SZ, (BYTE *)path, lstrlenW(path) * sizeof(WCHAR));
599 RegCloseKey(class_key);
600 return ERROR_SUCCESS;
602 RegCloseKey(*key);
604 ERR("Failed to create driver key, error %u.\n", l);
605 RegCloseKey(class_key);
606 return l;
609 static LONG delete_driver_key(struct device *device)
611 HKEY key;
612 LONG l;
614 if (!(l = open_driver_key(device, KEY_READ | KEY_WRITE, &key)))
616 l = RegDeleteKeyW(key, emptyW);
617 RegCloseKey(key);
620 return l;
623 struct PropertyMapEntry
625 DWORD regType;
626 LPCSTR nameA;
627 LPCWSTR nameW;
630 static const struct PropertyMapEntry PropertyMap[] = {
631 { REG_SZ, "DeviceDesc", DeviceDesc },
632 { REG_MULTI_SZ, "HardwareId", HardwareId },
633 { REG_MULTI_SZ, "CompatibleIDs", CompatibleIDs },
634 { 0, NULL, NULL }, /* SPDRP_UNUSED0 */
635 { REG_SZ, "Service", Service },
636 { 0, NULL, NULL }, /* SPDRP_UNUSED1 */
637 { 0, NULL, NULL }, /* SPDRP_UNUSED2 */
638 { REG_SZ, "Class", Class },
639 { REG_SZ, "ClassGUID", ClassGUID },
640 { REG_SZ, "Driver", Driver },
641 { REG_DWORD, "ConfigFlags", ConfigFlags },
642 { REG_SZ, "Mfg", Mfg },
643 { REG_SZ, "FriendlyName", FriendlyName },
644 { REG_SZ, "LocationInformation", LocationInformation },
645 { 0, NULL, NULL }, /* SPDRP_PHYSICAL_DEVICE_OBJECT_NAME */
646 { REG_DWORD, "Capabilities", Capabilities },
647 { REG_DWORD, "UINumber", UINumber },
648 { REG_MULTI_SZ, "UpperFilters", UpperFilters },
649 { REG_MULTI_SZ, "LowerFilters", LowerFilters },
652 static BOOL SETUPDI_SetDeviceRegistryPropertyW(struct device *device,
653 DWORD prop, const BYTE *buffer, DWORD size)
655 if (prop < ARRAY_SIZE(PropertyMap) && PropertyMap[prop].nameW)
657 LONG ret = RegSetValueExW(device->key, PropertyMap[prop].nameW, 0,
658 PropertyMap[prop].regType, buffer, size);
659 if (!ret)
660 return TRUE;
662 SetLastError(ret);
664 return FALSE;
667 static void remove_device_iface(struct device_iface *iface)
669 RegDeleteTreeW(iface->refstr_key, NULL);
670 RegDeleteKeyW(iface->refstr_key, emptyW);
671 RegCloseKey(iface->refstr_key);
672 iface->refstr_key = NULL;
673 /* Also remove the class key if it's empty. */
674 RegDeleteKeyW(iface->class_key, emptyW);
675 RegCloseKey(iface->class_key);
676 iface->class_key = NULL;
677 iface->flags |= SPINT_REMOVED;
680 static void delete_device_iface(struct device_iface *iface)
682 list_remove(&iface->entry);
683 RegCloseKey(iface->refstr_key);
684 RegCloseKey(iface->class_key);
685 heap_free(iface->refstr);
686 heap_free(iface->symlink);
687 heap_free(iface);
690 static void remove_device(struct device *device)
692 WCHAR id[MAX_DEVICE_ID_LEN], *p;
693 struct device_iface *iface;
694 HKEY enum_key;
696 delete_driver_key(device);
698 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
700 remove_device_iface(iface);
703 RegDeleteTreeW(device->key, NULL);
704 RegDeleteKeyW(device->key, emptyW);
706 /* delete all empty parents of the key */
707 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, 0, &enum_key))
709 lstrcpyW(id, device->instanceId);
711 while ((p = wcsrchr(id, '\\')))
713 *p = 0;
714 RegDeleteKeyW(enum_key, id);
717 RegCloseKey(enum_key);
720 RegCloseKey(device->key);
721 device->key = NULL;
722 device->removed = TRUE;
725 static void delete_device(struct device *device)
727 struct device_iface *iface, *next;
728 SP_DEVINFO_DATA device_data;
730 device_data.cbSize = sizeof(device_data);
731 copy_device_data(&device_data, device);
732 SetupDiCallClassInstaller(DIF_DESTROYPRIVATEDATA, device->set, &device_data);
734 if (device->phantom)
735 remove_device(device);
737 RegCloseKey(device->key);
738 heap_free(device->instanceId);
740 LIST_FOR_EACH_ENTRY_SAFE(iface, next, &device->interfaces,
741 struct device_iface, entry)
743 delete_device_iface(iface);
745 free_devnode(device->devnode);
746 list_remove(&device->entry);
747 heap_free(device);
750 /* Create a new device, or return a device already in the set. */
751 static struct device *create_device(struct DeviceInfoSet *set,
752 const GUID *class, const WCHAR *instanceid, BOOL phantom)
754 const DWORD one = 1;
755 struct device *device;
756 WCHAR guidstr[MAX_GUID_STRING_LEN];
757 WCHAR class_name[MAX_CLASS_NAME_LEN];
758 DWORD size;
760 TRACE("%p, %s, %s, %d\n", set, debugstr_guid(class),
761 debugstr_w(instanceid), phantom);
763 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
765 if (!wcsicmp(instanceid, device->instanceId))
767 TRACE("Found device %p already in set.\n", device);
768 return device;
772 if (!(device = heap_alloc_zero(sizeof(*device))))
774 SetLastError(ERROR_OUTOFMEMORY);
775 return NULL;
778 if (!(device->instanceId = strdupW(instanceid)))
780 SetLastError(ERROR_OUTOFMEMORY);
781 heap_free(device);
782 return NULL;
785 wcsupr(device->instanceId);
786 device->set = set;
787 device->key = SETUPDI_CreateDevKey(device);
788 device->phantom = phantom;
789 list_init(&device->interfaces);
790 device->class = *class;
791 device->devnode = alloc_devnode(device);
792 device->removed = FALSE;
793 list_add_tail(&set->devices, &device->entry);
794 device->params.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
796 if (phantom)
797 RegSetValueExW(device->key, Phantom, 0, REG_DWORD, (const BYTE *)&one, sizeof(one));
799 SETUPDI_GuidToString(class, guidstr);
800 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_CLASSGUID,
801 (const BYTE *)guidstr, sizeof(guidstr));
803 if (SetupDiClassNameFromGuidW(class, class_name, ARRAY_SIZE(class_name), NULL))
805 size = (lstrlenW(class_name) + 1) * sizeof(WCHAR);
806 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_CLASS, (const BYTE *)class_name, size);
809 TRACE("Created new device %p.\n", device);
810 return device;
813 /***********************************************************************
814 * SetupDiBuildClassInfoList (SETUPAPI.@)
816 * Returns a list of setup class GUIDs that identify the classes
817 * that are installed on a local machine.
819 * PARAMS
820 * Flags [I] control exclusion of classes from the list.
821 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
822 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
823 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
825 * RETURNS
826 * Success: TRUE.
827 * Failure: FALSE.
829 BOOL WINAPI SetupDiBuildClassInfoList(
830 DWORD Flags,
831 LPGUID ClassGuidList,
832 DWORD ClassGuidListSize,
833 PDWORD RequiredSize)
835 TRACE("\n");
836 return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
837 ClassGuidListSize, RequiredSize,
838 NULL, NULL);
841 /***********************************************************************
842 * SetupDiBuildClassInfoListExA (SETUPAPI.@)
844 * Returns a list of setup class GUIDs that identify the classes
845 * that are installed on a local or remote machine.
847 * PARAMS
848 * Flags [I] control exclusion of classes from the list.
849 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
850 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
851 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
852 * MachineName [I] name of a remote machine.
853 * Reserved [I] must be NULL.
855 * RETURNS
856 * Success: TRUE.
857 * Failure: FALSE.
859 BOOL WINAPI SetupDiBuildClassInfoListExA(
860 DWORD Flags,
861 LPGUID ClassGuidList,
862 DWORD ClassGuidListSize,
863 PDWORD RequiredSize,
864 LPCSTR MachineName,
865 PVOID Reserved)
867 LPWSTR MachineNameW = NULL;
868 BOOL bResult;
870 TRACE("\n");
872 if (MachineName)
874 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
875 if (MachineNameW == NULL) return FALSE;
878 bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
879 ClassGuidListSize, RequiredSize,
880 MachineNameW, Reserved);
882 MyFree(MachineNameW);
884 return bResult;
887 /***********************************************************************
888 * SetupDiBuildClassInfoListExW (SETUPAPI.@)
890 * Returns a list of setup class GUIDs that identify the classes
891 * that are installed on a local or remote machine.
893 * PARAMS
894 * Flags [I] control exclusion of classes from the list.
895 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
896 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
897 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
898 * MachineName [I] name of a remote machine.
899 * Reserved [I] must be NULL.
901 * RETURNS
902 * Success: TRUE.
903 * Failure: FALSE.
905 BOOL WINAPI SetupDiBuildClassInfoListExW(
906 DWORD Flags,
907 LPGUID ClassGuidList,
908 DWORD ClassGuidListSize,
909 PDWORD RequiredSize,
910 LPCWSTR MachineName,
911 PVOID Reserved)
913 WCHAR szKeyName[40];
914 HKEY hClassesKey;
915 HKEY hClassKey;
916 DWORD dwLength;
917 DWORD dwIndex;
918 LONG lError;
919 DWORD dwGuidListIndex = 0;
921 TRACE("\n");
923 if (RequiredSize != NULL)
924 *RequiredSize = 0;
926 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
927 KEY_ALL_ACCESS,
928 DIOCR_INSTALLER,
929 MachineName,
930 Reserved);
931 if (hClassesKey == INVALID_HANDLE_VALUE)
933 return FALSE;
936 for (dwIndex = 0; ; dwIndex++)
938 dwLength = 40;
939 lError = RegEnumKeyExW(hClassesKey,
940 dwIndex,
941 szKeyName,
942 &dwLength,
943 NULL,
944 NULL,
945 NULL,
946 NULL);
947 TRACE("RegEnumKeyExW() returns %d\n", lError);
948 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
950 TRACE("Key name: %p\n", szKeyName);
952 if (RegOpenKeyExW(hClassesKey,
953 szKeyName,
955 KEY_ALL_ACCESS,
956 &hClassKey))
958 RegCloseKey(hClassesKey);
959 return FALSE;
962 if (!RegQueryValueExW(hClassKey,
963 NoUseClass,
964 NULL,
965 NULL,
966 NULL,
967 NULL))
969 TRACE("'NoUseClass' value found!\n");
970 RegCloseKey(hClassKey);
971 continue;
974 if ((Flags & DIBCI_NOINSTALLCLASS) &&
975 (!RegQueryValueExW(hClassKey,
976 NoInstallClass,
977 NULL,
978 NULL,
979 NULL,
980 NULL)))
982 TRACE("'NoInstallClass' value found!\n");
983 RegCloseKey(hClassKey);
984 continue;
987 if ((Flags & DIBCI_NODISPLAYCLASS) &&
988 (!RegQueryValueExW(hClassKey,
989 NoDisplayClass,
990 NULL,
991 NULL,
992 NULL,
993 NULL)))
995 TRACE("'NoDisplayClass' value found!\n");
996 RegCloseKey(hClassKey);
997 continue;
1000 RegCloseKey(hClassKey);
1002 TRACE("Guid: %p\n", szKeyName);
1003 if (dwGuidListIndex < ClassGuidListSize)
1005 if (szKeyName[0] == '{' && szKeyName[37] == '}')
1007 szKeyName[37] = 0;
1009 TRACE("Guid: %p\n", &szKeyName[1]);
1011 UuidFromStringW(&szKeyName[1],
1012 &ClassGuidList[dwGuidListIndex]);
1015 dwGuidListIndex++;
1018 if (lError != ERROR_SUCCESS)
1019 break;
1022 RegCloseKey(hClassesKey);
1024 if (RequiredSize != NULL)
1025 *RequiredSize = dwGuidListIndex;
1027 if (ClassGuidListSize < dwGuidListIndex)
1029 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1030 return FALSE;
1033 return TRUE;
1036 /***********************************************************************
1037 * SetupDiClassGuidsFromNameA (SETUPAPI.@)
1039 BOOL WINAPI SetupDiClassGuidsFromNameA(
1040 LPCSTR ClassName,
1041 LPGUID ClassGuidList,
1042 DWORD ClassGuidListSize,
1043 PDWORD RequiredSize)
1045 return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
1046 ClassGuidListSize, RequiredSize,
1047 NULL, NULL);
1050 /***********************************************************************
1051 * SetupDiClassGuidsFromNameW (SETUPAPI.@)
1053 BOOL WINAPI SetupDiClassGuidsFromNameW(
1054 LPCWSTR ClassName,
1055 LPGUID ClassGuidList,
1056 DWORD ClassGuidListSize,
1057 PDWORD RequiredSize)
1059 return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
1060 ClassGuidListSize, RequiredSize,
1061 NULL, NULL);
1064 /***********************************************************************
1065 * SetupDiClassGuidsFromNameExA (SETUPAPI.@)
1067 BOOL WINAPI SetupDiClassGuidsFromNameExA(
1068 LPCSTR ClassName,
1069 LPGUID ClassGuidList,
1070 DWORD ClassGuidListSize,
1071 PDWORD RequiredSize,
1072 LPCSTR MachineName,
1073 PVOID Reserved)
1075 LPWSTR ClassNameW = NULL;
1076 LPWSTR MachineNameW = NULL;
1077 BOOL bResult;
1079 ClassNameW = MultiByteToUnicode(ClassName, CP_ACP);
1080 if (ClassNameW == NULL)
1081 return FALSE;
1083 if (MachineName)
1085 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1086 if (MachineNameW == NULL)
1088 MyFree(ClassNameW);
1089 return FALSE;
1093 bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
1094 ClassGuidListSize, RequiredSize,
1095 MachineNameW, Reserved);
1097 MyFree(MachineNameW);
1098 MyFree(ClassNameW);
1100 return bResult;
1103 /***********************************************************************
1104 * SetupDiClassGuidsFromNameExW (SETUPAPI.@)
1106 BOOL WINAPI SetupDiClassGuidsFromNameExW(
1107 LPCWSTR ClassName,
1108 LPGUID ClassGuidList,
1109 DWORD ClassGuidListSize,
1110 PDWORD RequiredSize,
1111 LPCWSTR MachineName,
1112 PVOID Reserved)
1114 WCHAR szKeyName[40];
1115 WCHAR szClassName[256];
1116 HKEY hClassesKey;
1117 HKEY hClassKey;
1118 DWORD dwLength;
1119 DWORD dwIndex;
1120 LONG lError;
1121 DWORD dwGuidListIndex = 0;
1123 if (RequiredSize != NULL)
1124 *RequiredSize = 0;
1126 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
1127 KEY_ALL_ACCESS,
1128 DIOCR_INSTALLER,
1129 MachineName,
1130 Reserved);
1131 if (hClassesKey == INVALID_HANDLE_VALUE)
1133 return FALSE;
1136 for (dwIndex = 0; ; dwIndex++)
1138 dwLength = ARRAY_SIZE(szKeyName);
1139 lError = RegEnumKeyExW(hClassesKey,
1140 dwIndex,
1141 szKeyName,
1142 &dwLength,
1143 NULL,
1144 NULL,
1145 NULL,
1146 NULL);
1147 TRACE("RegEnumKeyExW() returns %d\n", lError);
1148 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
1150 TRACE("Key name: %p\n", szKeyName);
1152 if (RegOpenKeyExW(hClassesKey,
1153 szKeyName,
1155 KEY_ALL_ACCESS,
1156 &hClassKey))
1158 RegCloseKey(hClassesKey);
1159 return FALSE;
1162 dwLength = sizeof(szClassName);
1163 if (!RegQueryValueExW(hClassKey,
1164 Class,
1165 NULL,
1166 NULL,
1167 (LPBYTE)szClassName,
1168 &dwLength))
1170 TRACE("Class name: %p\n", szClassName);
1172 if (wcsicmp(szClassName, ClassName) == 0)
1174 TRACE("Found matching class name\n");
1176 TRACE("Guid: %p\n", szKeyName);
1177 if (dwGuidListIndex < ClassGuidListSize)
1179 if (szKeyName[0] == '{' && szKeyName[37] == '}')
1181 szKeyName[37] = 0;
1183 TRACE("Guid: %p\n", &szKeyName[1]);
1185 UuidFromStringW(&szKeyName[1],
1186 &ClassGuidList[dwGuidListIndex]);
1189 dwGuidListIndex++;
1193 RegCloseKey(hClassKey);
1196 if (lError != ERROR_SUCCESS)
1197 break;
1200 RegCloseKey(hClassesKey);
1202 if (RequiredSize != NULL)
1203 *RequiredSize = dwGuidListIndex;
1205 if (ClassGuidListSize < dwGuidListIndex)
1207 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1208 return FALSE;
1211 return TRUE;
1214 /***********************************************************************
1215 * SetupDiClassNameFromGuidA (SETUPAPI.@)
1217 BOOL WINAPI SetupDiClassNameFromGuidA(
1218 const GUID* ClassGuid,
1219 PSTR ClassName,
1220 DWORD ClassNameSize,
1221 PDWORD RequiredSize)
1223 return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
1224 ClassNameSize, RequiredSize,
1225 NULL, NULL);
1228 /***********************************************************************
1229 * SetupDiClassNameFromGuidW (SETUPAPI.@)
1231 BOOL WINAPI SetupDiClassNameFromGuidW(
1232 const GUID* ClassGuid,
1233 PWSTR ClassName,
1234 DWORD ClassNameSize,
1235 PDWORD RequiredSize)
1237 return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
1238 ClassNameSize, RequiredSize,
1239 NULL, NULL);
1242 /***********************************************************************
1243 * SetupDiClassNameFromGuidExA (SETUPAPI.@)
1245 BOOL WINAPI SetupDiClassNameFromGuidExA(
1246 const GUID* ClassGuid,
1247 PSTR ClassName,
1248 DWORD ClassNameSize,
1249 PDWORD RequiredSize,
1250 PCSTR MachineName,
1251 PVOID Reserved)
1253 WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
1254 LPWSTR MachineNameW = NULL;
1255 BOOL ret;
1257 if (MachineName)
1258 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1259 ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
1260 NULL, MachineNameW, Reserved);
1261 if (ret)
1263 int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
1264 ClassNameSize, NULL, NULL);
1266 if (!ClassNameSize && RequiredSize)
1267 *RequiredSize = len;
1269 MyFree(MachineNameW);
1270 return ret;
1273 /***********************************************************************
1274 * SetupDiClassNameFromGuidExW (SETUPAPI.@)
1276 BOOL WINAPI SetupDiClassNameFromGuidExW(
1277 const GUID* ClassGuid,
1278 PWSTR ClassName,
1279 DWORD ClassNameSize,
1280 PDWORD RequiredSize,
1281 PCWSTR MachineName,
1282 PVOID Reserved)
1284 HKEY hKey;
1285 DWORD dwLength;
1287 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
1288 KEY_ALL_ACCESS,
1289 DIOCR_INSTALLER,
1290 MachineName,
1291 Reserved);
1292 if (hKey == INVALID_HANDLE_VALUE)
1294 return FALSE;
1297 if (RequiredSize != NULL)
1299 dwLength = 0;
1300 if (RegQueryValueExW(hKey,
1301 Class,
1302 NULL,
1303 NULL,
1304 NULL,
1305 &dwLength))
1307 RegCloseKey(hKey);
1308 return FALSE;
1311 *RequiredSize = dwLength / sizeof(WCHAR);
1314 dwLength = ClassNameSize * sizeof(WCHAR);
1315 if (RegQueryValueExW(hKey,
1316 Class,
1317 NULL,
1318 NULL,
1319 (LPBYTE)ClassName,
1320 &dwLength))
1322 RegCloseKey(hKey);
1323 return FALSE;
1326 RegCloseKey(hKey);
1328 return TRUE;
1331 /***********************************************************************
1332 * SetupDiCreateDeviceInfoList (SETUPAPI.@)
1334 HDEVINFO WINAPI
1335 SetupDiCreateDeviceInfoList(const GUID *ClassGuid,
1336 HWND hwndParent)
1338 return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
1341 /***********************************************************************
1342 * SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
1344 HDEVINFO WINAPI
1345 SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
1346 HWND hwndParent,
1347 PCSTR MachineName,
1348 PVOID Reserved)
1350 LPWSTR MachineNameW = NULL;
1351 HDEVINFO hDevInfo;
1353 TRACE("\n");
1355 if (MachineName)
1357 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1358 if (MachineNameW == NULL)
1359 return INVALID_HANDLE_VALUE;
1362 hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
1363 MachineNameW, Reserved);
1365 MyFree(MachineNameW);
1367 return hDevInfo;
1370 /***********************************************************************
1371 * SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
1373 * Create an empty DeviceInfoSet list.
1375 * PARAMS
1376 * ClassGuid [I] if not NULL only devices with GUID ClassGuid are associated
1377 * with this list.
1378 * hwndParent [I] hwnd needed for interface related actions.
1379 * MachineName [I] name of machine to create empty DeviceInfoSet list, if NULL
1380 * local registry will be used.
1381 * Reserved [I] must be NULL
1383 * RETURNS
1384 * Success: empty list.
1385 * Failure: INVALID_HANDLE_VALUE.
1387 HDEVINFO WINAPI
1388 SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
1389 HWND hwndParent,
1390 PCWSTR MachineName,
1391 PVOID Reserved)
1393 struct DeviceInfoSet *list = NULL;
1394 DWORD size = sizeof(struct DeviceInfoSet);
1396 TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
1397 debugstr_w(MachineName), Reserved);
1399 if (MachineName && *MachineName)
1401 FIXME("remote support is not implemented\n");
1402 SetLastError(ERROR_INVALID_MACHINENAME);
1403 return INVALID_HANDLE_VALUE;
1406 if (Reserved != NULL)
1408 SetLastError(ERROR_INVALID_PARAMETER);
1409 return INVALID_HANDLE_VALUE;
1412 list = HeapAlloc(GetProcessHeap(), 0, size);
1413 if (!list)
1415 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1416 return INVALID_HANDLE_VALUE;
1419 list->magic = SETUP_DEVICE_INFO_SET_MAGIC;
1420 list->hwndParent = hwndParent;
1421 memcpy(&list->ClassGuid,
1422 ClassGuid ? ClassGuid : &GUID_NULL,
1423 sizeof(list->ClassGuid));
1424 list_init(&list->devices);
1426 return list;
1429 /***********************************************************************
1430 * SetupDiCreateDevRegKeyA (SETUPAPI.@)
1432 HKEY WINAPI SetupDiCreateDevRegKeyA(
1433 HDEVINFO DeviceInfoSet,
1434 PSP_DEVINFO_DATA DeviceInfoData,
1435 DWORD Scope,
1436 DWORD HwProfile,
1437 DWORD KeyType,
1438 HINF InfHandle,
1439 PCSTR InfSectionName)
1441 PWSTR InfSectionNameW = NULL;
1442 HKEY key;
1444 TRACE("%p %p %d %d %d %p %s\n", DeviceInfoSet, DeviceInfoData, Scope,
1445 HwProfile, KeyType, InfHandle, debugstr_a(InfSectionName));
1447 if (InfHandle)
1449 if (!InfSectionName)
1451 SetLastError(ERROR_INVALID_PARAMETER);
1452 return INVALID_HANDLE_VALUE;
1454 else
1456 InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
1457 if (InfSectionNameW == NULL) return INVALID_HANDLE_VALUE;
1460 key = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, Scope,
1461 HwProfile, KeyType, InfHandle, InfSectionNameW);
1462 MyFree(InfSectionNameW);
1463 return key;
1466 /***********************************************************************
1467 * SetupDiCreateDevRegKeyW (SETUPAPI.@)
1469 HKEY WINAPI SetupDiCreateDevRegKeyW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD Scope,
1470 DWORD HwProfile, DWORD KeyType, HINF InfHandle, const WCHAR *InfSectionName)
1472 struct device *device;
1473 HKEY key = INVALID_HANDLE_VALUE;
1474 LONG l;
1476 TRACE("devinfo %p, device_data %p, scope %d, profile %d, type %d, inf_handle %p, inf_section %s.\n",
1477 devinfo, device_data, Scope, HwProfile, KeyType, InfHandle, debugstr_w(InfSectionName));
1479 if (!(device = get_device(devinfo, device_data)))
1480 return INVALID_HANDLE_VALUE;
1482 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
1484 SetLastError(ERROR_INVALID_FLAGS);
1485 return INVALID_HANDLE_VALUE;
1487 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
1489 SetLastError(ERROR_INVALID_FLAGS);
1490 return INVALID_HANDLE_VALUE;
1492 if (device->phantom)
1494 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
1495 return INVALID_HANDLE_VALUE;
1497 if (Scope != DICS_FLAG_GLOBAL)
1498 FIXME("unimplemented for scope %d\n", Scope);
1499 switch (KeyType)
1501 case DIREG_DEV:
1502 l = RegCreateKeyExW(device->key, DeviceParameters, 0, NULL, 0,
1503 KEY_READ | KEY_WRITE, NULL, &key, NULL);
1504 break;
1505 case DIREG_DRV:
1506 l = create_driver_key(device, &key);
1507 break;
1508 default:
1509 FIXME("Unhandled type %#x.\n", KeyType);
1510 l = ERROR_CALL_NOT_IMPLEMENTED;
1512 if (InfHandle)
1513 SetupInstallFromInfSectionW(NULL, InfHandle, InfSectionName, SPINST_ALL,
1514 NULL, NULL, SP_COPY_NEWER_ONLY, NULL, NULL, devinfo, device_data);
1515 SetLastError(l);
1516 return l ? INVALID_HANDLE_VALUE : key;
1519 /***********************************************************************
1520 * SetupDiCreateDeviceInfoA (SETUPAPI.@)
1522 BOOL WINAPI SetupDiCreateDeviceInfoA(HDEVINFO DeviceInfoSet, const char *name,
1523 const GUID *ClassGuid, PCSTR DeviceDescription, HWND hwndParent, DWORD CreationFlags,
1524 PSP_DEVINFO_DATA DeviceInfoData)
1526 WCHAR nameW[MAX_DEVICE_ID_LEN];
1527 BOOL ret = FALSE;
1528 LPWSTR DeviceDescriptionW = NULL;
1530 if (!name || strlen(name) >= MAX_DEVICE_ID_LEN)
1532 SetLastError(ERROR_INVALID_DEVINST_NAME);
1533 return FALSE;
1536 MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, ARRAY_SIZE(nameW));
1538 if (DeviceDescription)
1540 DeviceDescriptionW = MultiByteToUnicode(DeviceDescription, CP_ACP);
1541 if (DeviceDescriptionW == NULL)
1542 return FALSE;
1545 ret = SetupDiCreateDeviceInfoW(DeviceInfoSet, nameW, ClassGuid, DeviceDescriptionW,
1546 hwndParent, CreationFlags, DeviceInfoData);
1548 MyFree(DeviceDescriptionW);
1550 return ret;
1553 /***********************************************************************
1554 * SetupDiCreateDeviceInfoW (SETUPAPI.@)
1556 BOOL WINAPI SetupDiCreateDeviceInfoW(HDEVINFO devinfo, const WCHAR *name, const GUID *class,
1557 const WCHAR *description, HWND parent, DWORD flags, SP_DEVINFO_DATA *device_data)
1559 WCHAR id[MAX_DEVICE_ID_LEN];
1560 struct DeviceInfoSet *set;
1561 HKEY enum_hkey;
1562 HKEY instance_hkey;
1563 struct device *device;
1564 LONG l;
1566 TRACE("devinfo %p, name %s, class %s, description %s, hwnd %p, flags %#x, device_data %p.\n",
1567 devinfo, debugstr_w(name), debugstr_guid(class), debugstr_w(description),
1568 parent, flags, device_data);
1570 if (!name || lstrlenW(name) >= MAX_DEVICE_ID_LEN)
1572 SetLastError(ERROR_INVALID_DEVINST_NAME);
1573 return FALSE;
1576 if (!(set = get_device_set(devinfo)))
1577 return FALSE;
1579 if (!class)
1581 SetLastError(ERROR_INVALID_PARAMETER);
1582 return FALSE;
1585 if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) && !IsEqualGUID(class, &set->ClassGuid))
1587 SetLastError(ERROR_CLASS_MISMATCH);
1588 return FALSE;
1590 if ((flags & DICD_GENERATE_ID))
1592 static const WCHAR formatW[] = {'R','O','O','T','\\','%','s','\\','%','0','4','u',0};
1593 unsigned int instance_id;
1595 if (wcschr(name, '\\'))
1597 SetLastError(ERROR_INVALID_DEVINST_NAME);
1598 return FALSE;
1601 for (instance_id = 0; ; ++instance_id)
1603 if (swprintf(id, ARRAY_SIZE(id), formatW, name, instance_id) == -1)
1605 SetLastError(ERROR_INVALID_DEVINST_NAME);
1606 return FALSE;
1609 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL, &enum_hkey, NULL);
1610 if (!(l = RegOpenKeyExW(enum_hkey, id, 0, KEY_READ, &instance_hkey)))
1611 RegCloseKey(instance_hkey);
1612 if (l == ERROR_FILE_NOT_FOUND)
1613 break;
1614 RegCloseKey(enum_hkey);
1617 else
1619 /* Check if instance is already in registry */
1620 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL, &enum_hkey, NULL);
1621 if (!RegOpenKeyExW(enum_hkey, name, 0, KEY_READ, &instance_hkey))
1623 RegCloseKey(instance_hkey);
1624 RegCloseKey(enum_hkey);
1625 SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
1626 return FALSE;
1628 RegCloseKey(enum_hkey);
1630 /* Check if instance is already in set */
1631 lstrcpyW(id, name);
1632 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
1634 if (!lstrcmpiW(name, device->instanceId))
1636 SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
1637 return FALSE;
1642 if (!(device = create_device(set, class, id, TRUE)))
1643 return FALSE;
1645 if (description)
1647 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_DEVICEDESC,
1648 (const BYTE *)description, lstrlenW(description) * sizeof(WCHAR));
1651 if (device_data)
1653 if (device_data->cbSize != sizeof(SP_DEVINFO_DATA))
1655 SetLastError(ERROR_INVALID_USER_BUFFER);
1656 return FALSE;
1658 else
1659 copy_device_data(device_data, device);
1662 return TRUE;
1665 /***********************************************************************
1666 * SetupDiRegisterDeviceInfo (SETUPAPI.@)
1668 BOOL WINAPI SetupDiRegisterDeviceInfo(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD flags,
1669 PSP_DETSIG_CMPPROC compare_proc, void *context, SP_DEVINFO_DATA *duplicate_data)
1671 struct device *device;
1673 TRACE("devinfo %p, data %p, flags %#x, compare_proc %p, context %p, duplicate_data %p.\n",
1674 devinfo, device_data, flags, compare_proc, context, duplicate_data);
1676 if (!(device = get_device(devinfo, device_data)))
1677 return FALSE;
1679 if (device->phantom)
1681 device->phantom = FALSE;
1682 RegDeleteValueW(device->key, Phantom);
1684 return TRUE;
1687 /***********************************************************************
1688 * SetupDiRemoveDevice (SETUPAPI.@)
1690 BOOL WINAPI SetupDiRemoveDevice(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
1692 struct device *device;
1694 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
1696 if (!(device = get_device(devinfo, device_data)))
1697 return FALSE;
1699 remove_device(device);
1701 return TRUE;
1704 /***********************************************************************
1705 * SetupDiDeleteDeviceInfo (SETUPAPI.@)
1707 BOOL WINAPI SetupDiDeleteDeviceInfo(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
1709 struct device *device;
1711 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
1713 if (!(device = get_device(devinfo, device_data)))
1714 return FALSE;
1716 delete_device(device);
1718 return TRUE;
1721 /***********************************************************************
1722 * SetupDiRemoveDeviceInterface (SETUPAPI.@)
1724 BOOL WINAPI SetupDiRemoveDeviceInterface(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data)
1726 struct device_iface *iface;
1728 TRACE("devinfo %p, iface_data %p.\n", devinfo, iface_data);
1730 if (!(iface = get_device_iface(devinfo, iface_data)))
1731 return FALSE;
1733 remove_device_iface(iface);
1735 return TRUE;
1738 /***********************************************************************
1739 * SetupDiDeleteDeviceInterfaceData (SETUPAPI.@)
1741 BOOL WINAPI SetupDiDeleteDeviceInterfaceData(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data)
1743 struct device_iface *iface;
1745 TRACE("devinfo %p, iface_data %p.\n", devinfo, iface_data);
1747 if (!(iface = get_device_iface(devinfo, iface_data)))
1748 return FALSE;
1750 delete_device_iface(iface);
1752 return TRUE;
1755 /***********************************************************************
1756 * SetupDiEnumDeviceInfo (SETUPAPI.@)
1758 BOOL WINAPI DECLSPEC_HOTPATCH SetupDiEnumDeviceInfo(HDEVINFO devinfo, DWORD index, SP_DEVINFO_DATA *device_data)
1760 struct DeviceInfoSet *set;
1761 struct device *device;
1762 DWORD i = 0;
1764 TRACE("devinfo %p, index %d, device_data %p\n", devinfo, index, device_data);
1766 if (!(set = get_device_set(devinfo)))
1767 return FALSE;
1769 if (!device_data)
1771 SetLastError(ERROR_INVALID_PARAMETER);
1772 return FALSE;
1775 if (device_data->cbSize != sizeof(SP_DEVINFO_DATA))
1777 SetLastError(ERROR_INVALID_USER_BUFFER);
1778 return FALSE;
1781 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
1783 if (i++ == index)
1785 copy_device_data(device_data, device);
1786 return TRUE;
1790 SetLastError(ERROR_NO_MORE_ITEMS);
1791 return FALSE;
1794 /***********************************************************************
1795 * SetupDiGetDeviceInstanceIdA (SETUPAPI.@)
1797 BOOL WINAPI SetupDiGetDeviceInstanceIdA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
1798 char *id, DWORD size, DWORD *needed)
1800 WCHAR idW[MAX_DEVICE_ID_LEN];
1802 TRACE("devinfo %p, device_data %p, id %p, size %d, needed %p.\n",
1803 devinfo, device_data, id, size, needed);
1805 if (!SetupDiGetDeviceInstanceIdW(devinfo, device_data, idW, ARRAY_SIZE(idW), NULL))
1806 return FALSE;
1808 if (needed)
1809 *needed = WideCharToMultiByte(CP_ACP, 0, idW, -1, NULL, 0, NULL, NULL);
1811 if (size && WideCharToMultiByte(CP_ACP, 0, idW, -1, id, size, NULL, NULL))
1812 return TRUE;
1814 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1815 return FALSE;
1818 /***********************************************************************
1819 * SetupDiGetDeviceInstanceIdW (SETUPAPI.@)
1821 BOOL WINAPI SetupDiGetDeviceInstanceIdW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
1822 WCHAR *DeviceInstanceId, DWORD DeviceInstanceIdSize, DWORD *RequiredSize)
1824 struct device *device;
1826 TRACE("devinfo %p, device_data %p, DeviceInstanceId %p, DeviceInstanceIdSize %d, RequiredSize %p.\n",
1827 devinfo, device_data, DeviceInstanceId, DeviceInstanceIdSize, RequiredSize);
1829 if (!(device = get_device(devinfo, device_data)))
1830 return FALSE;
1832 TRACE("instance ID: %s\n", debugstr_w(device->instanceId));
1833 if (DeviceInstanceIdSize < lstrlenW(device->instanceId) + 1)
1835 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1836 if (RequiredSize)
1837 *RequiredSize = lstrlenW(device->instanceId) + 1;
1838 return FALSE;
1840 lstrcpyW(DeviceInstanceId, device->instanceId);
1841 if (RequiredSize)
1842 *RequiredSize = lstrlenW(device->instanceId) + 1;
1843 return TRUE;
1846 /***********************************************************************
1847 * SetupDiGetActualSectionToInstallA (SETUPAPI.@)
1849 BOOL WINAPI SetupDiGetActualSectionToInstallA(HINF hinf, const char *section,
1850 char *section_ext, DWORD size, DWORD *needed, char **extptr)
1852 WCHAR sectionW[LINE_LEN], section_extW[LINE_LEN], *extptrW;
1853 BOOL ret;
1855 MultiByteToWideChar(CP_ACP, 0, section, -1, sectionW, ARRAY_SIZE(sectionW));
1857 ret = SetupDiGetActualSectionToInstallW(hinf, sectionW, section_extW,
1858 ARRAY_SIZE(section_extW), NULL, &extptrW);
1859 if (ret)
1861 if (needed)
1862 *needed = WideCharToMultiByte(CP_ACP, 0, section_extW, -1, NULL, 0, NULL, NULL);
1864 if (section_ext)
1865 ret = !!WideCharToMultiByte(CP_ACP, 0, section_extW, -1, section_ext, size, NULL, NULL);
1867 if (extptr)
1869 if (extptrW)
1870 *extptr = section_ext + WideCharToMultiByte(CP_ACP, 0, section_extW,
1871 extptrW - section_extW, NULL, 0, NULL, NULL);
1872 else
1873 *extptr = NULL;
1877 return ret;
1880 /***********************************************************************
1881 * SetupDiGetActualSectionToInstallW (SETUPAPI.@)
1883 BOOL WINAPI SetupDiGetActualSectionToInstallW(
1884 HINF InfHandle,
1885 PCWSTR InfSectionName,
1886 PWSTR InfSectionWithExt,
1887 DWORD InfSectionWithExtSize,
1888 PDWORD RequiredSize,
1889 PWSTR *Extension)
1891 WCHAR szBuffer[MAX_PATH];
1892 DWORD dwLength;
1893 DWORD dwFullLength;
1894 LONG lLineCount = -1;
1896 lstrcpyW(szBuffer, InfSectionName);
1897 dwLength = lstrlenW(szBuffer);
1899 if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
1901 /* Test section name with '.NTx86' extension */
1902 lstrcpyW(&szBuffer[dwLength], NtPlatformExtension);
1903 lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
1905 if (lLineCount == -1)
1907 /* Test section name with '.NT' extension */
1908 lstrcpyW(&szBuffer[dwLength], NtExtension);
1909 lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
1912 else
1914 /* Test section name with '.Win' extension */
1915 lstrcpyW(&szBuffer[dwLength], WinExtension);
1916 lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
1919 if (lLineCount == -1)
1920 szBuffer[dwLength] = 0;
1922 dwFullLength = lstrlenW(szBuffer);
1924 if (InfSectionWithExt != NULL && InfSectionWithExtSize != 0)
1926 if (InfSectionWithExtSize < (dwFullLength + 1))
1928 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1929 return FALSE;
1932 lstrcpyW(InfSectionWithExt, szBuffer);
1933 if (Extension != NULL)
1935 *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
1939 if (RequiredSize != NULL)
1941 *RequiredSize = dwFullLength + 1;
1944 return TRUE;
1947 /***********************************************************************
1948 * SetupDiGetClassDescriptionA (SETUPAPI.@)
1950 BOOL WINAPI SetupDiGetClassDescriptionA(
1951 const GUID* ClassGuid,
1952 PSTR ClassDescription,
1953 DWORD ClassDescriptionSize,
1954 PDWORD RequiredSize)
1956 return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
1957 ClassDescriptionSize,
1958 RequiredSize, NULL, NULL);
1961 /***********************************************************************
1962 * SetupDiGetClassDescriptionW (SETUPAPI.@)
1964 BOOL WINAPI SetupDiGetClassDescriptionW(
1965 const GUID* ClassGuid,
1966 PWSTR ClassDescription,
1967 DWORD ClassDescriptionSize,
1968 PDWORD RequiredSize)
1970 return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
1971 ClassDescriptionSize,
1972 RequiredSize, NULL, NULL);
1975 /***********************************************************************
1976 * SetupDiGetClassDescriptionExA (SETUPAPI.@)
1978 BOOL WINAPI SetupDiGetClassDescriptionExA(
1979 const GUID* ClassGuid,
1980 PSTR ClassDescription,
1981 DWORD ClassDescriptionSize,
1982 PDWORD RequiredSize,
1983 PCSTR MachineName,
1984 PVOID Reserved)
1986 HKEY hKey;
1987 DWORD dwLength;
1988 BOOL ret;
1990 hKey = SetupDiOpenClassRegKeyExA(ClassGuid,
1991 KEY_ALL_ACCESS,
1992 DIOCR_INSTALLER,
1993 MachineName,
1994 Reserved);
1995 if (hKey == INVALID_HANDLE_VALUE)
1997 WARN("SetupDiOpenClassRegKeyExA() failed (Error %u)\n", GetLastError());
1998 return FALSE;
2001 dwLength = ClassDescriptionSize;
2002 ret = !RegQueryValueExA( hKey, NULL, NULL, NULL,
2003 (LPBYTE)ClassDescription, &dwLength );
2004 if (RequiredSize) *RequiredSize = dwLength;
2005 RegCloseKey(hKey);
2006 return ret;
2009 /***********************************************************************
2010 * SetupDiGetClassDescriptionExW (SETUPAPI.@)
2012 BOOL WINAPI SetupDiGetClassDescriptionExW(
2013 const GUID* ClassGuid,
2014 PWSTR ClassDescription,
2015 DWORD ClassDescriptionSize,
2016 PDWORD RequiredSize,
2017 PCWSTR MachineName,
2018 PVOID Reserved)
2020 HKEY hKey;
2021 DWORD dwLength;
2022 BOOL ret;
2024 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
2025 KEY_ALL_ACCESS,
2026 DIOCR_INSTALLER,
2027 MachineName,
2028 Reserved);
2029 if (hKey == INVALID_HANDLE_VALUE)
2031 WARN("SetupDiOpenClassRegKeyExW() failed (Error %u)\n", GetLastError());
2032 return FALSE;
2035 dwLength = ClassDescriptionSize * sizeof(WCHAR);
2036 ret = !RegQueryValueExW( hKey, NULL, NULL, NULL,
2037 (LPBYTE)ClassDescription, &dwLength );
2038 if (RequiredSize) *RequiredSize = dwLength / sizeof(WCHAR);
2039 RegCloseKey(hKey);
2040 return ret;
2043 /***********************************************************************
2044 * SetupDiGetClassDevsA (SETUPAPI.@)
2046 HDEVINFO WINAPI SetupDiGetClassDevsA(const GUID *class, LPCSTR enumstr, HWND parent, DWORD flags)
2048 HDEVINFO ret;
2049 LPWSTR enumstrW = NULL;
2051 if (enumstr)
2053 int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
2054 enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2055 if (!enumstrW)
2057 ret = INVALID_HANDLE_VALUE;
2058 goto end;
2060 MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
2062 ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, NULL, NULL,
2063 NULL);
2064 HeapFree(GetProcessHeap(), 0, enumstrW);
2066 end:
2067 return ret;
2070 /***********************************************************************
2071 * SetupDiGetClassDevsExA (SETUPAPI.@)
2073 HDEVINFO WINAPI SetupDiGetClassDevsExA(
2074 const GUID *class,
2075 PCSTR enumstr,
2076 HWND parent,
2077 DWORD flags,
2078 HDEVINFO deviceset,
2079 PCSTR machine,
2080 PVOID reserved)
2082 HDEVINFO ret;
2083 LPWSTR enumstrW = NULL, machineW = NULL;
2085 if (enumstr)
2087 int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
2088 enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2089 if (!enumstrW)
2091 ret = INVALID_HANDLE_VALUE;
2092 goto end;
2094 MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
2096 if (machine)
2098 int len = MultiByteToWideChar(CP_ACP, 0, machine, -1, NULL, 0);
2099 machineW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2100 if (!machineW)
2102 HeapFree(GetProcessHeap(), 0, enumstrW);
2103 ret = INVALID_HANDLE_VALUE;
2104 goto end;
2106 MultiByteToWideChar(CP_ACP, 0, machine, -1, machineW, len);
2108 ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset,
2109 machineW, reserved);
2110 HeapFree(GetProcessHeap(), 0, enumstrW);
2111 HeapFree(GetProcessHeap(), 0, machineW);
2113 end:
2114 return ret;
2117 static void SETUPDI_AddDeviceInterfaces(struct device *device, HKEY key,
2118 const GUID *guid, DWORD flags)
2120 DWORD i, len;
2121 WCHAR subKeyName[MAX_PATH];
2122 LONG l = ERROR_SUCCESS;
2124 for (i = 0; !l; i++)
2126 len = ARRAY_SIZE(subKeyName);
2127 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2128 if (!l)
2130 HKEY subKey;
2131 struct device_iface *iface;
2133 if (*subKeyName == '#')
2135 /* The subkey name is the reference string, with a '#' prepended */
2136 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2137 if (!l)
2139 WCHAR symbolicLink[MAX_PATH];
2140 DWORD dataType;
2142 if (!(flags & DIGCF_PRESENT) || is_linked(subKey))
2144 iface = SETUPDI_CreateDeviceInterface(device, guid, subKeyName + 1);
2146 len = sizeof(symbolicLink);
2147 l = RegQueryValueExW(subKey, SymbolicLink, NULL, &dataType,
2148 (BYTE *)symbolicLink, &len);
2149 if (!l && dataType == REG_SZ)
2150 SETUPDI_SetInterfaceSymbolicLink(iface, symbolicLink);
2151 RegCloseKey(subKey);
2155 /* Allow enumeration to continue */
2156 l = ERROR_SUCCESS;
2159 /* FIXME: find and add all the device's interfaces to the device */
2162 static void SETUPDI_EnumerateMatchingInterfaces(HDEVINFO DeviceInfoSet,
2163 HKEY key, const GUID *guid, const WCHAR *enumstr, DWORD flags)
2165 struct DeviceInfoSet *set = DeviceInfoSet;
2166 DWORD i, len;
2167 WCHAR subKeyName[MAX_PATH];
2168 LONG l;
2169 HKEY enumKey = INVALID_HANDLE_VALUE;
2171 TRACE("%s\n", debugstr_w(enumstr));
2173 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL,
2174 &enumKey, NULL);
2175 for (i = 0; !l; i++)
2177 len = ARRAY_SIZE(subKeyName);
2178 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2179 if (!l)
2181 HKEY subKey;
2183 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2184 if (!l)
2186 WCHAR deviceInst[MAX_PATH * 3];
2187 DWORD dataType;
2189 len = sizeof(deviceInst);
2190 l = RegQueryValueExW(subKey, DeviceInstance, NULL, &dataType,
2191 (BYTE *)deviceInst, &len);
2192 if (!l && dataType == REG_SZ)
2194 TRACE("found instance ID %s\n", debugstr_w(deviceInst));
2195 if (!enumstr || !lstrcmpiW(enumstr, deviceInst))
2197 HKEY deviceKey;
2199 l = RegOpenKeyExW(enumKey, deviceInst, 0, KEY_READ,
2200 &deviceKey);
2201 if (!l)
2203 WCHAR deviceClassStr[40];
2205 len = sizeof(deviceClassStr);
2206 l = RegQueryValueExW(deviceKey, ClassGUID, NULL,
2207 &dataType, (BYTE *)deviceClassStr, &len);
2208 if (!l && dataType == REG_SZ &&
2209 deviceClassStr[0] == '{' &&
2210 deviceClassStr[37] == '}')
2212 GUID deviceClass;
2213 struct device *device;
2215 deviceClassStr[37] = 0;
2216 UuidFromStringW(&deviceClassStr[1],
2217 &deviceClass);
2218 if ((device = create_device(set, &deviceClass, deviceInst, FALSE)))
2219 SETUPDI_AddDeviceInterfaces(device, subKey, guid, flags);
2221 RegCloseKey(deviceKey);
2225 RegCloseKey(subKey);
2227 /* Allow enumeration to continue */
2228 l = ERROR_SUCCESS;
2231 if (enumKey != INVALID_HANDLE_VALUE)
2232 RegCloseKey(enumKey);
2235 static void SETUPDI_EnumerateInterfaces(HDEVINFO DeviceInfoSet,
2236 const GUID *guid, LPCWSTR enumstr, DWORD flags)
2238 HKEY interfacesKey = SetupDiOpenClassRegKeyExW(guid, KEY_READ,
2239 DIOCR_INTERFACE, NULL, NULL);
2241 TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(guid),
2242 debugstr_w(enumstr), flags);
2244 if (interfacesKey != INVALID_HANDLE_VALUE)
2246 if (flags & DIGCF_ALLCLASSES)
2248 DWORD i, len;
2249 WCHAR interfaceGuidStr[40];
2250 LONG l = ERROR_SUCCESS;
2252 for (i = 0; !l; i++)
2254 len = ARRAY_SIZE(interfaceGuidStr);
2255 l = RegEnumKeyExW(interfacesKey, i, interfaceGuidStr, &len,
2256 NULL, NULL, NULL, NULL);
2257 if (!l)
2259 if (interfaceGuidStr[0] == '{' &&
2260 interfaceGuidStr[37] == '}')
2262 HKEY interfaceKey;
2263 GUID interfaceGuid;
2265 interfaceGuidStr[37] = 0;
2266 UuidFromStringW(&interfaceGuidStr[1], &interfaceGuid);
2267 interfaceGuidStr[37] = '}';
2268 interfaceGuidStr[38] = 0;
2269 l = RegOpenKeyExW(interfacesKey, interfaceGuidStr, 0,
2270 KEY_READ, &interfaceKey);
2271 if (!l)
2273 SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
2274 interfaceKey, &interfaceGuid, enumstr, flags);
2275 RegCloseKey(interfaceKey);
2281 else
2283 /* In this case, SetupDiOpenClassRegKeyExW opened the specific
2284 * interface's key, so just pass that long
2286 SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
2287 interfacesKey, guid, enumstr, flags);
2289 RegCloseKey(interfacesKey);
2293 static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set,
2294 LPCWSTR enumerator, LPCWSTR deviceName, HKEY deviceKey,
2295 const GUID *class, DWORD flags)
2297 WCHAR id[MAX_DEVICE_ID_LEN];
2298 DWORD i, len;
2299 WCHAR deviceInstance[MAX_PATH];
2300 LONG l = ERROR_SUCCESS;
2302 TRACE("%s %s\n", debugstr_w(enumerator), debugstr_w(deviceName));
2304 for (i = 0; !l; i++)
2306 len = ARRAY_SIZE(deviceInstance);
2307 l = RegEnumKeyExW(deviceKey, i, deviceInstance, &len, NULL, NULL, NULL,
2308 NULL);
2309 if (!l)
2311 HKEY subKey;
2313 l = RegOpenKeyExW(deviceKey, deviceInstance, 0, KEY_READ, &subKey);
2314 if (!l)
2316 WCHAR classGuid[40];
2317 DWORD dataType;
2319 len = sizeof(classGuid);
2320 l = RegQueryValueExW(subKey, ClassGUID, NULL, &dataType,
2321 (BYTE *)classGuid, &len);
2322 if (!l && dataType == REG_SZ)
2324 if (classGuid[0] == '{' && classGuid[37] == '}')
2326 GUID deviceClass;
2328 classGuid[37] = 0;
2329 UuidFromStringW(&classGuid[1], &deviceClass);
2330 if ((flags & DIGCF_ALLCLASSES) ||
2331 IsEqualGUID(class, &deviceClass))
2333 static const WCHAR fmt[] =
2334 {'%','s','\\','%','s','\\','%','s',0};
2336 if (swprintf(id, ARRAY_SIZE(id), fmt, enumerator,
2337 deviceName, deviceInstance) != -1)
2339 create_device(set, &deviceClass, id, FALSE);
2344 RegCloseKey(subKey);
2346 /* Allow enumeration to continue */
2347 l = ERROR_SUCCESS;
2352 static void SETUPDI_EnumerateMatchingDevices(HDEVINFO DeviceInfoSet,
2353 LPCWSTR parent, HKEY key, const GUID *class, DWORD flags)
2355 struct DeviceInfoSet *set = DeviceInfoSet;
2356 DWORD i, len;
2357 WCHAR subKeyName[MAX_PATH];
2358 LONG l = ERROR_SUCCESS;
2360 TRACE("%s\n", debugstr_w(parent));
2362 for (i = 0; !l; i++)
2364 len = ARRAY_SIZE(subKeyName);
2365 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2366 if (!l)
2368 HKEY subKey;
2370 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2371 if (!l)
2373 TRACE("%s\n", debugstr_w(subKeyName));
2374 SETUPDI_EnumerateMatchingDeviceInstances(set, parent,
2375 subKeyName, subKey, class, flags);
2376 RegCloseKey(subKey);
2378 /* Allow enumeration to continue */
2379 l = ERROR_SUCCESS;
2384 static void SETUPDI_EnumerateDevices(HDEVINFO DeviceInfoSet, const GUID *class,
2385 LPCWSTR enumstr, DWORD flags)
2387 HKEY enumKey;
2388 LONG l;
2390 TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(class),
2391 debugstr_w(enumstr), flags);
2393 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL,
2394 &enumKey, NULL);
2395 if (enumKey != INVALID_HANDLE_VALUE)
2397 if (enumstr)
2399 HKEY enumStrKey;
2401 l = RegOpenKeyExW(enumKey, enumstr, 0, KEY_READ,
2402 &enumStrKey);
2403 if (!l)
2405 WCHAR *bus, *device;
2407 if (!wcschr(enumstr, '\\'))
2409 SETUPDI_EnumerateMatchingDevices(DeviceInfoSet, enumstr, enumStrKey, class, flags);
2411 else if ((bus = strdupW(enumstr)))
2413 device = wcschr(bus, '\\');
2414 *device++ = 0;
2416 SETUPDI_EnumerateMatchingDeviceInstances(DeviceInfoSet, bus, device, enumStrKey, class, flags);
2417 HeapFree(GetProcessHeap(), 0, bus);
2420 RegCloseKey(enumStrKey);
2423 else
2425 DWORD i, len;
2426 WCHAR subKeyName[MAX_PATH];
2428 l = ERROR_SUCCESS;
2429 for (i = 0; !l; i++)
2431 len = ARRAY_SIZE(subKeyName);
2432 l = RegEnumKeyExW(enumKey, i, subKeyName, &len, NULL,
2433 NULL, NULL, NULL);
2434 if (!l)
2436 HKEY subKey;
2438 l = RegOpenKeyExW(enumKey, subKeyName, 0, KEY_READ,
2439 &subKey);
2440 if (!l)
2442 SETUPDI_EnumerateMatchingDevices(DeviceInfoSet,
2443 subKeyName, subKey, class, flags);
2444 RegCloseKey(subKey);
2446 /* Allow enumeration to continue */
2447 l = ERROR_SUCCESS;
2451 RegCloseKey(enumKey);
2455 /***********************************************************************
2456 * SetupDiGetClassDevsW (SETUPAPI.@)
2458 HDEVINFO WINAPI SetupDiGetClassDevsW(const GUID *class, LPCWSTR enumstr, HWND parent, DWORD flags)
2460 return SetupDiGetClassDevsExW(class, enumstr, parent, flags, NULL, NULL,
2461 NULL);
2464 /***********************************************************************
2465 * SetupDiGetClassDevsExW (SETUPAPI.@)
2467 HDEVINFO WINAPI SetupDiGetClassDevsExW(const GUID *class, PCWSTR enumstr, HWND parent, DWORD flags,
2468 HDEVINFO deviceset, PCWSTR machine, void *reserved)
2470 static const DWORD unsupportedFlags = DIGCF_DEFAULT | DIGCF_PROFILE;
2471 HDEVINFO set;
2473 TRACE("%s %s %p 0x%08x %p %s %p\n", debugstr_guid(class),
2474 debugstr_w(enumstr), parent, flags, deviceset, debugstr_w(machine),
2475 reserved);
2477 if (!(flags & DIGCF_ALLCLASSES) && !class)
2479 SetLastError(ERROR_INVALID_PARAMETER);
2480 return INVALID_HANDLE_VALUE;
2482 if (flags & DIGCF_ALLCLASSES)
2483 class = NULL;
2485 if (flags & unsupportedFlags)
2486 WARN("unsupported flags %08x\n", flags & unsupportedFlags);
2487 if (deviceset)
2488 set = deviceset;
2489 else
2490 set = SetupDiCreateDeviceInfoListExW((flags & DIGCF_DEVICEINTERFACE) ? NULL : class, parent, machine, reserved);
2491 if (set != INVALID_HANDLE_VALUE)
2493 if (machine && *machine)
2494 FIXME("%s: unimplemented for remote machines\n",
2495 debugstr_w(machine));
2496 else if (flags & DIGCF_DEVICEINTERFACE)
2497 SETUPDI_EnumerateInterfaces(set, class, enumstr, flags);
2498 else
2499 SETUPDI_EnumerateDevices(set, class, enumstr, flags);
2501 return set;
2504 /***********************************************************************
2505 * SetupDiGetDeviceInfoListDetailA (SETUPAPI.@)
2507 BOOL WINAPI SetupDiGetDeviceInfoListDetailA(HDEVINFO devinfo, SP_DEVINFO_LIST_DETAIL_DATA_A *DevInfoData)
2509 struct DeviceInfoSet *set;
2511 TRACE("devinfo %p, detail_data %p.\n", devinfo, DevInfoData);
2513 if (!(set = get_device_set(devinfo)))
2514 return FALSE;
2516 if (!DevInfoData ||
2517 DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_A))
2519 SetLastError(ERROR_INVALID_PARAMETER);
2520 return FALSE;
2522 DevInfoData->ClassGuid = set->ClassGuid;
2523 DevInfoData->RemoteMachineHandle = NULL;
2524 DevInfoData->RemoteMachineName[0] = '\0';
2525 return TRUE;
2528 /***********************************************************************
2529 * SetupDiGetDeviceInfoListDetailW (SETUPAPI.@)
2531 BOOL WINAPI SetupDiGetDeviceInfoListDetailW(HDEVINFO devinfo, SP_DEVINFO_LIST_DETAIL_DATA_W *DevInfoData)
2533 struct DeviceInfoSet *set;
2535 TRACE("devinfo %p, detail_data %p.\n", devinfo, DevInfoData);
2537 if (!(set = get_device_set(devinfo)))
2538 return FALSE;
2540 if (!DevInfoData ||
2541 DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W))
2543 SetLastError(ERROR_INVALID_PARAMETER);
2544 return FALSE;
2546 DevInfoData->ClassGuid = set->ClassGuid;
2547 DevInfoData->RemoteMachineHandle = NULL;
2548 DevInfoData->RemoteMachineName[0] = '\0';
2549 return TRUE;
2552 /***********************************************************************
2553 * SetupDiCreateDeviceInterfaceA (SETUPAPI.@)
2555 BOOL WINAPI SetupDiCreateDeviceInterfaceA(
2556 HDEVINFO DeviceInfoSet,
2557 PSP_DEVINFO_DATA DeviceInfoData,
2558 const GUID *InterfaceClassGuid,
2559 PCSTR ReferenceString,
2560 DWORD CreationFlags,
2561 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2563 BOOL ret;
2564 LPWSTR ReferenceStringW = NULL;
2566 TRACE("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
2567 debugstr_guid(InterfaceClassGuid), debugstr_a(ReferenceString),
2568 CreationFlags, DeviceInterfaceData);
2570 if (ReferenceString)
2572 ReferenceStringW = MultiByteToUnicode(ReferenceString, CP_ACP);
2573 if (ReferenceStringW == NULL) return FALSE;
2576 ret = SetupDiCreateDeviceInterfaceW(DeviceInfoSet, DeviceInfoData,
2577 InterfaceClassGuid, ReferenceStringW, CreationFlags,
2578 DeviceInterfaceData);
2580 MyFree(ReferenceStringW);
2582 return ret;
2585 /***********************************************************************
2586 * SetupDiCreateDeviceInterfaceW (SETUPAPI.@)
2588 BOOL WINAPI SetupDiCreateDeviceInterfaceW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
2589 const GUID *class, const WCHAR *refstr, DWORD flags, SP_DEVICE_INTERFACE_DATA *iface_data)
2591 struct device *device;
2592 struct device_iface *iface;
2594 TRACE("devinfo %p, device_data %p, class %s, refstr %s, flags %#x, iface_data %p.\n",
2595 devinfo, device_data, debugstr_guid(class), debugstr_w(refstr), flags, iface_data);
2597 if (!(device = get_device(devinfo, device_data)))
2598 return FALSE;
2600 if (!class)
2602 SetLastError(ERROR_INVALID_USER_BUFFER);
2603 return FALSE;
2606 if (!(iface = SETUPDI_CreateDeviceInterface(device, class, refstr)))
2607 return FALSE;
2609 if (iface_data)
2611 if (iface_data->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2613 SetLastError(ERROR_INVALID_USER_BUFFER);
2614 return FALSE;
2617 copy_device_iface_data(iface_data, iface);
2619 return TRUE;
2622 /***********************************************************************
2623 * SetupDiCreateDeviceInterfaceRegKeyA (SETUPAPI.@)
2625 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyA(
2626 HDEVINFO DeviceInfoSet,
2627 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2628 DWORD Reserved,
2629 REGSAM samDesired,
2630 HINF InfHandle,
2631 PCSTR InfSectionName)
2633 HKEY key;
2634 PWSTR InfSectionNameW = NULL;
2636 TRACE("%p %p %d %08x %p %p\n", DeviceInfoSet, DeviceInterfaceData, Reserved,
2637 samDesired, InfHandle, InfSectionName);
2638 if (InfHandle)
2640 if (!InfSectionName)
2642 SetLastError(ERROR_INVALID_PARAMETER);
2643 return INVALID_HANDLE_VALUE;
2645 InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
2646 if (!InfSectionNameW)
2647 return INVALID_HANDLE_VALUE;
2649 key = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet,
2650 DeviceInterfaceData, Reserved, samDesired, InfHandle,
2651 InfSectionNameW);
2652 MyFree(InfSectionNameW);
2653 return key;
2656 static LONG create_iface_key(const struct device_iface *iface, REGSAM access, HKEY *key)
2658 return RegCreateKeyExW(iface->refstr_key, DeviceParameters, 0, NULL, 0, access, NULL, key, NULL);
2661 /***********************************************************************
2662 * SetupDiCreateDeviceInterfaceRegKeyW (SETUPAPI.@)
2664 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyW(HDEVINFO devinfo,
2665 SP_DEVICE_INTERFACE_DATA *iface_data, DWORD reserved, REGSAM access,
2666 HINF hinf, const WCHAR *section)
2668 struct device_iface *iface;
2669 HKEY params_key;
2670 LONG ret;
2672 TRACE("devinfo %p, iface_data %p, reserved %d, access %#x, hinf %p, section %s.\n",
2673 devinfo, iface_data, reserved, access, hinf, debugstr_w(section));
2675 if (!(iface = get_device_iface(devinfo, iface_data)))
2676 return INVALID_HANDLE_VALUE;
2678 if (hinf && !section)
2680 SetLastError(ERROR_INVALID_PARAMETER);
2681 return INVALID_HANDLE_VALUE;
2684 ret = create_iface_key(iface, access, &params_key);
2685 if (ret)
2687 SetLastError(ret);
2688 return INVALID_HANDLE_VALUE;
2691 return params_key;
2694 /***********************************************************************
2695 * SetupDiDeleteDeviceInterfaceRegKey (SETUPAPI.@)
2697 BOOL WINAPI SetupDiDeleteDeviceInterfaceRegKey(HDEVINFO devinfo,
2698 SP_DEVICE_INTERFACE_DATA *iface_data, DWORD reserved)
2700 struct device_iface *iface;
2701 LONG ret;
2703 TRACE("devinfo %p, iface_data %p, reserved %d.\n", devinfo, iface_data, reserved);
2705 if (!(iface = get_device_iface(devinfo, iface_data)))
2706 return FALSE;
2708 ret = RegDeleteKeyW(iface->refstr_key, DeviceParameters);
2709 if (ret)
2711 SetLastError(ret);
2712 return FALSE;
2715 return TRUE;
2718 /***********************************************************************
2719 * SetupDiEnumDeviceInterfaces (SETUPAPI.@)
2721 * PARAMS
2722 * DeviceInfoSet [I] Set of devices from which to enumerate
2723 * interfaces
2724 * DeviceInfoData [I] (Optional) If specified, a specific device
2725 * instance from which to enumerate interfaces.
2726 * If it isn't specified, all interfaces for all
2727 * devices in the set are enumerated.
2728 * InterfaceClassGuid [I] The interface class to enumerate.
2729 * MemberIndex [I] An index of the interface instance to enumerate.
2730 * A caller should start with MemberIndex set to 0,
2731 * and continue until the function fails with
2732 * ERROR_NO_MORE_ITEMS.
2733 * DeviceInterfaceData [I/O] Returns an enumerated interface. Its cbSize
2734 * member must be set to
2735 * sizeof(SP_DEVICE_INTERFACE_DATA).
2737 * RETURNS
2738 * Success: non-zero value.
2739 * Failure: FALSE. Call GetLastError() for more info.
2741 BOOL WINAPI SetupDiEnumDeviceInterfaces(HDEVINFO devinfo,
2742 SP_DEVINFO_DATA *device_data, const GUID *class, DWORD index,
2743 SP_DEVICE_INTERFACE_DATA *iface_data)
2745 struct DeviceInfoSet *set;
2746 struct device *device;
2747 struct device_iface *iface;
2748 DWORD i = 0;
2750 TRACE("devinfo %p, device_data %p, class %s, index %u, iface_data %p.\n",
2751 devinfo, device_data, debugstr_guid(class), index, iface_data);
2753 if (!iface_data || iface_data->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2755 SetLastError(ERROR_INVALID_PARAMETER);
2756 return FALSE;
2759 /* In case application fails to check return value, clear output */
2760 memset(iface_data, 0, sizeof(*iface_data));
2761 iface_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
2763 if (device_data)
2765 if (!(device = get_device(devinfo, device_data)))
2766 return FALSE;
2768 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
2770 if (IsEqualGUID(&iface->class, class))
2772 if (i == index)
2774 copy_device_iface_data(iface_data, iface);
2775 return TRUE;
2777 i++;
2781 else
2783 if (!(set = get_device_set(devinfo)))
2784 return FALSE;
2786 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
2788 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
2790 if (IsEqualGUID(&iface->class, class))
2792 if (i == index)
2794 copy_device_iface_data(iface_data, iface);
2795 return TRUE;
2797 i++;
2803 SetLastError(ERROR_NO_MORE_ITEMS);
2804 return FALSE;
2807 /***********************************************************************
2808 * SetupDiDestroyDeviceInfoList (SETUPAPI.@)
2810 * Destroy a DeviceInfoList and free all used memory of the list.
2812 * PARAMS
2813 * devinfo [I] DeviceInfoList pointer to list to destroy
2815 * RETURNS
2816 * Success: non zero value.
2817 * Failure: zero value.
2819 BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
2821 struct DeviceInfoSet *set;
2822 struct device *device, *device2;
2824 TRACE("devinfo %p.\n", devinfo);
2826 if (!(set = get_device_set(devinfo)))
2827 return FALSE;
2829 LIST_FOR_EACH_ENTRY_SAFE(device, device2, &set->devices, struct device, entry)
2831 delete_device(device);
2833 heap_free(set);
2835 return TRUE;
2838 /***********************************************************************
2839 * SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
2841 BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data,
2842 SP_DEVICE_INTERFACE_DETAIL_DATA_A *DeviceInterfaceDetailData,
2843 DWORD DeviceInterfaceDetailDataSize, DWORD *RequiredSize, SP_DEVINFO_DATA *device_data)
2845 struct device_iface *iface;
2846 DWORD bytesNeeded = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath[1]);
2847 BOOL ret = FALSE;
2849 TRACE("devinfo %p, iface_data %p, detail_data %p, size %d, needed %p, device_data %p.\n",
2850 devinfo, iface_data, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize,
2851 RequiredSize, device_data);
2853 if (!(iface = get_device_iface(devinfo, iface_data)))
2854 return FALSE;
2856 if (DeviceInterfaceDetailData &&
2857 DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A))
2859 SetLastError(ERROR_INVALID_USER_BUFFER);
2860 return FALSE;
2862 if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
2864 SetLastError(ERROR_INVALID_USER_BUFFER);
2865 return FALSE;
2868 if (iface->symlink)
2869 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, iface->symlink, -1,
2870 NULL, 0, NULL, NULL);
2871 if (DeviceInterfaceDetailDataSize >= bytesNeeded)
2873 if (iface->symlink)
2874 WideCharToMultiByte(CP_ACP, 0, iface->symlink, -1,
2875 DeviceInterfaceDetailData->DevicePath,
2876 DeviceInterfaceDetailDataSize -
2877 offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
2878 NULL, NULL);
2879 else
2880 DeviceInterfaceDetailData->DevicePath[0] = '\0';
2882 ret = TRUE;
2884 else
2886 if (RequiredSize)
2887 *RequiredSize = bytesNeeded;
2888 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2891 if (device_data && device_data->cbSize == sizeof(SP_DEVINFO_DATA))
2892 copy_device_data(device_data, iface->device);
2894 return ret;
2897 /***********************************************************************
2898 * SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
2900 BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data,
2901 SP_DEVICE_INTERFACE_DETAIL_DATA_W *DeviceInterfaceDetailData,
2902 DWORD DeviceInterfaceDetailDataSize, DWORD *RequiredSize, SP_DEVINFO_DATA *device_data)
2904 struct device_iface *iface;
2905 DWORD bytesNeeded = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
2906 + sizeof(WCHAR); /* include NULL terminator */
2907 BOOL ret = FALSE;
2909 TRACE("devinfo %p, iface_data %p, detail_data %p, size %d, needed %p, device_data %p.\n",
2910 devinfo, iface_data, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize,
2911 RequiredSize, device_data);
2913 if (!(iface = get_device_iface(devinfo, iface_data)))
2914 return FALSE;
2916 if (DeviceInterfaceDetailData && (DeviceInterfaceDetailData->cbSize <
2917 offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR) ||
2918 DeviceInterfaceDetailData->cbSize > sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W)))
2920 SetLastError(ERROR_INVALID_USER_BUFFER);
2921 return FALSE;
2923 if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
2925 SetLastError(ERROR_INVALID_USER_BUFFER);
2926 return FALSE;
2929 if (iface->symlink)
2930 bytesNeeded += sizeof(WCHAR) * lstrlenW(iface->symlink);
2931 if (DeviceInterfaceDetailDataSize >= bytesNeeded)
2933 if (iface->symlink)
2934 lstrcpyW(DeviceInterfaceDetailData->DevicePath, iface->symlink);
2935 else
2936 DeviceInterfaceDetailData->DevicePath[0] = '\0';
2938 ret = TRUE;
2940 else
2942 if (RequiredSize)
2943 *RequiredSize = bytesNeeded;
2944 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2947 if (device_data && device_data->cbSize == sizeof(SP_DEVINFO_DATA))
2948 copy_device_data(device_data, iface->device);
2950 return ret;
2953 /***********************************************************************
2954 * SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
2956 BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(HDEVINFO devinfo,
2957 SP_DEVINFO_DATA *device_data, DWORD Property, DWORD *PropertyRegDataType,
2958 BYTE *PropertyBuffer, DWORD PropertyBufferSize, DWORD *RequiredSize)
2960 BOOL ret = FALSE;
2961 struct device *device;
2963 TRACE("devinfo %p, device_data %p, property %d, type %p, buffer %p, size %d, required %p\n",
2964 devinfo, device_data, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize);
2966 if (!(device = get_device(devinfo, device_data)))
2967 return FALSE;
2969 if (PropertyBufferSize && PropertyBuffer == NULL)
2971 SetLastError(ERROR_INVALID_DATA);
2972 return FALSE;
2975 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameA)
2977 DWORD size = PropertyBufferSize;
2978 LONG l = RegQueryValueExA(device->key, PropertyMap[Property].nameA,
2979 NULL, PropertyRegDataType, PropertyBuffer, &size);
2981 if (l == ERROR_FILE_NOT_FOUND)
2982 SetLastError(ERROR_INVALID_DATA);
2983 else if (l == ERROR_MORE_DATA || !PropertyBufferSize)
2984 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2985 else if (!l)
2986 ret = TRUE;
2987 else
2988 SetLastError(l);
2989 if (RequiredSize)
2990 *RequiredSize = size;
2992 return ret;
2995 /***********************************************************************
2996 * SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
2998 BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(HDEVINFO devinfo,
2999 SP_DEVINFO_DATA *device_data, DWORD Property, DWORD *PropertyRegDataType,
3000 BYTE *PropertyBuffer, DWORD PropertyBufferSize, DWORD *RequiredSize)
3002 BOOL ret = FALSE;
3003 struct device *device;
3005 TRACE("devinfo %p, device_data %p, prop %d, type %p, buffer %p, size %d, required %p\n",
3006 devinfo, device_data, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize);
3008 if (!(device = get_device(devinfo, device_data)))
3009 return FALSE;
3011 if (PropertyBufferSize && PropertyBuffer == NULL)
3013 SetLastError(ERROR_INVALID_DATA);
3014 return FALSE;
3017 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameW)
3019 DWORD size = PropertyBufferSize;
3020 LONG l = RegQueryValueExW(device->key, PropertyMap[Property].nameW,
3021 NULL, PropertyRegDataType, PropertyBuffer, &size);
3023 if (l == ERROR_FILE_NOT_FOUND)
3024 SetLastError(ERROR_INVALID_DATA);
3025 else if (l == ERROR_MORE_DATA || !PropertyBufferSize)
3026 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3027 else if (!l)
3028 ret = TRUE;
3029 else
3030 SetLastError(l);
3031 if (RequiredSize)
3032 *RequiredSize = size;
3034 return ret;
3037 /***********************************************************************
3038 * SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
3040 BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
3041 DWORD Property, const BYTE *PropertyBuffer, DWORD PropertyBufferSize)
3043 BOOL ret = FALSE;
3044 struct device *device;
3046 TRACE("devinfo %p, device_data %p, prop %d, buffer %p, size %d.\n",
3047 devinfo, device_data, Property, PropertyBuffer, PropertyBufferSize);
3049 if (!(device = get_device(devinfo, device_data)))
3050 return FALSE;
3052 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameA)
3054 LONG l = RegSetValueExA(device->key, PropertyMap[Property].nameA, 0,
3055 PropertyMap[Property].regType, PropertyBuffer,
3056 PropertyBufferSize);
3057 if (!l)
3058 ret = TRUE;
3059 else
3060 SetLastError(l);
3062 return ret;
3065 /***********************************************************************
3066 * SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
3068 BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(HDEVINFO devinfo,
3069 SP_DEVINFO_DATA *device_data, DWORD prop, const BYTE *buffer, DWORD size)
3071 struct device *device;
3073 TRACE("devinfo %p, device_data %p, prop %d, buffer %p, size %d.\n",
3074 devinfo, device_data, prop, buffer, size);
3076 if (!(device = get_device(devinfo, device_data)))
3077 return FALSE;
3079 return SETUPDI_SetDeviceRegistryPropertyW(device, prop, buffer, size);
3082 /***********************************************************************
3083 * SetupDiInstallClassA (SETUPAPI.@)
3085 BOOL WINAPI SetupDiInstallClassA(
3086 HWND hwndParent,
3087 PCSTR InfFileName,
3088 DWORD Flags,
3089 HSPFILEQ FileQueue)
3091 UNICODE_STRING FileNameW;
3092 BOOL Result;
3094 if (!InfFileName)
3096 SetLastError(ERROR_INVALID_PARAMETER);
3097 return FALSE;
3099 if (!RtlCreateUnicodeStringFromAsciiz(&FileNameW, InfFileName))
3101 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3102 return FALSE;
3105 Result = SetupDiInstallClassW(hwndParent, FileNameW.Buffer, Flags, FileQueue);
3107 RtlFreeUnicodeString(&FileNameW);
3109 return Result;
3112 static HKEY CreateClassKey(HINF hInf)
3114 static const WCHAR slash[] = { '\\',0 };
3115 WCHAR FullBuffer[MAX_PATH];
3116 WCHAR Buffer[MAX_PATH];
3117 DWORD RequiredSize;
3118 HKEY hClassKey;
3120 if (!SetupGetLineTextW(NULL,
3121 hInf,
3122 Version,
3123 ClassGUID,
3124 Buffer,
3125 MAX_PATH,
3126 &RequiredSize))
3128 return INVALID_HANDLE_VALUE;
3131 lstrcpyW(FullBuffer, ControlClass);
3132 lstrcatW(FullBuffer, slash);
3133 lstrcatW(FullBuffer, Buffer);
3135 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3136 FullBuffer,
3138 KEY_ALL_ACCESS,
3139 &hClassKey))
3141 if (!SetupGetLineTextW(NULL,
3142 hInf,
3143 Version,
3144 Class,
3145 Buffer,
3146 MAX_PATH,
3147 &RequiredSize))
3149 return INVALID_HANDLE_VALUE;
3152 if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
3153 FullBuffer,
3155 NULL,
3156 REG_OPTION_NON_VOLATILE,
3157 KEY_ALL_ACCESS,
3158 NULL,
3159 &hClassKey,
3160 NULL))
3162 return INVALID_HANDLE_VALUE;
3167 if (RegSetValueExW(hClassKey,
3168 Class,
3170 REG_SZ,
3171 (LPBYTE)Buffer,
3172 RequiredSize * sizeof(WCHAR)))
3174 RegCloseKey(hClassKey);
3175 RegDeleteKeyW(HKEY_LOCAL_MACHINE,
3176 FullBuffer);
3177 return INVALID_HANDLE_VALUE;
3180 return hClassKey;
3183 /***********************************************************************
3184 * SetupDiInstallClassW (SETUPAPI.@)
3186 BOOL WINAPI SetupDiInstallClassW(
3187 HWND hwndParent,
3188 PCWSTR InfFileName,
3189 DWORD Flags,
3190 HSPFILEQ FileQueue)
3192 WCHAR SectionName[MAX_PATH];
3193 DWORD SectionNameLength = 0;
3194 HINF hInf;
3195 BOOL bFileQueueCreated = FALSE;
3196 HKEY hClassKey;
3199 FIXME("\n");
3201 if (!InfFileName)
3203 SetLastError(ERROR_INVALID_PARAMETER);
3204 return FALSE;
3206 if ((Flags & DI_NOVCP) && (FileQueue == NULL || FileQueue == INVALID_HANDLE_VALUE))
3208 SetLastError(ERROR_INVALID_PARAMETER);
3209 return FALSE;
3212 /* Open the .inf file */
3213 hInf = SetupOpenInfFileW(InfFileName,
3214 NULL,
3215 INF_STYLE_WIN4,
3216 NULL);
3217 if (hInf == INVALID_HANDLE_VALUE)
3220 return FALSE;
3223 /* Create or open the class registry key 'HKLM\\CurrentControlSet\\Class\\{GUID}' */
3224 hClassKey = CreateClassKey(hInf);
3225 if (hClassKey == INVALID_HANDLE_VALUE)
3227 SetupCloseInfFile(hInf);
3228 return FALSE;
3232 /* Try to append a layout file */
3233 SetupOpenAppendInfFileW(NULL, hInf, NULL);
3235 /* Retrieve the actual section name */
3236 SetupDiGetActualSectionToInstallW(hInf,
3237 ClassInstall32,
3238 SectionName,
3239 MAX_PATH,
3240 &SectionNameLength,
3241 NULL);
3243 #if 0
3244 if (!(Flags & DI_NOVCP))
3246 FileQueue = SetupOpenFileQueue();
3247 if (FileQueue == INVALID_HANDLE_VALUE)
3249 SetupCloseInfFile(hInf);
3250 return FALSE;
3253 bFileQueueCreated = TRUE;
3256 #endif
3258 SetupInstallFromInfSectionW(NULL,
3259 hInf,
3260 SectionName,
3261 SPINST_COPYINF | SPINST_FILES | SPINST_REGISTRY,
3262 hClassKey,
3263 NULL,
3265 NULL,
3266 NULL,
3267 INVALID_HANDLE_VALUE,
3268 NULL);
3270 /* FIXME: More code! */
3272 if (bFileQueueCreated)
3273 SetupCloseFileQueue(FileQueue);
3275 SetupCloseInfFile(hInf);
3277 return TRUE;
3281 /***********************************************************************
3282 * SetupDiOpenClassRegKey (SETUPAPI.@)
3284 HKEY WINAPI SetupDiOpenClassRegKey(
3285 const GUID* ClassGuid,
3286 REGSAM samDesired)
3288 return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3289 DIOCR_INSTALLER, NULL, NULL);
3293 /***********************************************************************
3294 * SetupDiOpenClassRegKeyExA (SETUPAPI.@)
3296 HKEY WINAPI SetupDiOpenClassRegKeyExA(
3297 const GUID* ClassGuid,
3298 REGSAM samDesired,
3299 DWORD Flags,
3300 PCSTR MachineName,
3301 PVOID Reserved)
3303 PWSTR MachineNameW = NULL;
3304 HKEY hKey;
3306 TRACE("\n");
3308 if (MachineName)
3310 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
3311 if (MachineNameW == NULL)
3312 return INVALID_HANDLE_VALUE;
3315 hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3316 Flags, MachineNameW, Reserved);
3318 MyFree(MachineNameW);
3320 return hKey;
3324 /***********************************************************************
3325 * SetupDiOpenClassRegKeyExW (SETUPAPI.@)
3327 HKEY WINAPI SetupDiOpenClassRegKeyExW(
3328 const GUID* ClassGuid,
3329 REGSAM samDesired,
3330 DWORD Flags,
3331 PCWSTR MachineName,
3332 PVOID Reserved)
3334 HKEY hClassesKey;
3335 HKEY key;
3336 LPCWSTR lpKeyName;
3337 LONG l;
3339 if (MachineName && *MachineName)
3341 FIXME("Remote access not supported yet!\n");
3342 return INVALID_HANDLE_VALUE;
3345 if (Flags == DIOCR_INSTALLER)
3347 lpKeyName = ControlClass;
3349 else if (Flags == DIOCR_INTERFACE)
3351 lpKeyName = DeviceClasses;
3353 else
3355 ERR("Invalid Flags parameter!\n");
3356 SetLastError(ERROR_INVALID_PARAMETER);
3357 return INVALID_HANDLE_VALUE;
3360 if (!ClassGuid)
3362 if ((l = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3363 lpKeyName,
3365 samDesired,
3366 &hClassesKey)))
3368 SetLastError(l);
3369 hClassesKey = INVALID_HANDLE_VALUE;
3371 key = hClassesKey;
3373 else
3375 WCHAR bracedGuidString[39];
3377 SETUPDI_GuidToString(ClassGuid, bracedGuidString);
3379 if (!(l = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3380 lpKeyName,
3382 samDesired,
3383 &hClassesKey)))
3385 if ((l = RegOpenKeyExW(hClassesKey,
3386 bracedGuidString,
3388 samDesired,
3389 &key)))
3391 SetLastError(l);
3392 key = INVALID_HANDLE_VALUE;
3394 RegCloseKey(hClassesKey);
3396 else
3398 SetLastError(l);
3399 key = INVALID_HANDLE_VALUE;
3402 return key;
3405 /***********************************************************************
3406 * SetupDiOpenDeviceInfoA (SETUPAPI.@)
3408 BOOL WINAPI SetupDiOpenDeviceInfoA(HDEVINFO devinfo, PCSTR instance_id, HWND hwnd_parent, DWORD flags,
3409 PSP_DEVINFO_DATA device_data)
3411 WCHAR instance_idW[MAX_DEVICE_ID_LEN];
3413 TRACE("%p %s %p 0x%08x %p\n", devinfo, debugstr_a(instance_id), hwnd_parent, flags, device_data);
3415 if (!instance_id || strlen(instance_id) >= MAX_DEVICE_ID_LEN)
3417 SetLastError(ERROR_INVALID_PARAMETER);
3418 return FALSE;
3421 MultiByteToWideChar(CP_ACP, 0, instance_id, -1, instance_idW, ARRAY_SIZE(instance_idW));
3422 return SetupDiOpenDeviceInfoW(devinfo, instance_idW, hwnd_parent, flags, device_data);
3425 /***********************************************************************
3426 * SetupDiOpenDeviceInfoW (SETUPAPI.@)
3428 BOOL WINAPI SetupDiOpenDeviceInfoW(HDEVINFO devinfo, PCWSTR instance_id, HWND hwnd_parent, DWORD flags,
3429 PSP_DEVINFO_DATA device_data)
3431 struct DeviceInfoSet *set;
3432 struct device *device;
3433 WCHAR classW[40];
3434 GUID guid;
3435 HKEY enumKey = NULL;
3436 HKEY instanceKey = NULL;
3437 DWORD phantom;
3438 DWORD size;
3439 DWORD error = ERROR_NO_SUCH_DEVINST;
3441 TRACE("%p %s %p 0x%08x %p\n", devinfo, debugstr_w(instance_id), hwnd_parent, flags, device_data);
3443 if (!(set = get_device_set(devinfo)))
3444 return FALSE;
3446 if (!instance_id)
3448 SetLastError(ERROR_INVALID_PARAMETER);
3449 return FALSE;
3452 if (hwnd_parent)
3453 FIXME("hwnd_parent unsupported\n");
3455 if (flags)
3456 FIXME("flags unsupported: 0x%08x\n", flags);
3458 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &enumKey, NULL);
3459 /* Instance needs to be already existent in registry, if not, report ERROR_NO_SUCH_DEVINST */
3460 if (RegOpenKeyExW(enumKey, instance_id, 0, KEY_READ, &instanceKey))
3461 goto done;
3463 /* If it's an unregistered instance, aka phantom instance, report ERROR_NO_SUCH_DEVINST */
3464 size = sizeof(phantom);
3465 if (!RegQueryValueExW(instanceKey, Phantom, NULL, NULL, (BYTE *)&phantom, &size))
3466 goto done;
3468 /* Check class GUID */
3469 size = sizeof(classW);
3470 if (RegQueryValueExW(instanceKey, ClassGUID, NULL, NULL, (BYTE *)classW, &size))
3471 goto done;
3473 classW[37] = 0;
3474 UuidFromStringW(&classW[1], &guid);
3476 if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) && !IsEqualGUID(&guid, &set->ClassGuid))
3478 error = ERROR_CLASS_MISMATCH;
3479 goto done;
3482 if (!(device = create_device(set, &guid, instance_id, FALSE)))
3483 goto done;
3485 if (!device_data || device_data->cbSize == sizeof(SP_DEVINFO_DATA))
3487 if (device_data)
3488 copy_device_data(device_data, device);
3489 error = NO_ERROR;
3491 else
3492 error = ERROR_INVALID_USER_BUFFER;
3494 done:
3495 RegCloseKey(instanceKey);
3496 RegCloseKey(enumKey);
3497 SetLastError(error);
3498 return !error;
3501 /***********************************************************************
3502 * SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
3504 BOOL WINAPI SetupDiOpenDeviceInterfaceW(
3505 HDEVINFO DeviceInfoSet,
3506 PCWSTR DevicePath,
3507 DWORD OpenFlags,
3508 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3510 FIXME("%p %s %08x %p\n",
3511 DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
3512 return FALSE;
3515 /***********************************************************************
3516 * SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
3518 BOOL WINAPI SetupDiOpenDeviceInterfaceA(
3519 HDEVINFO DeviceInfoSet,
3520 PCSTR DevicePath,
3521 DWORD OpenFlags,
3522 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3524 FIXME("%p %s %08x %p\n", DeviceInfoSet,
3525 debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
3526 return FALSE;
3529 /***********************************************************************
3530 * SetupDiOpenDeviceInterfaceRegKey (SETUPAPI.@)
3532 HKEY WINAPI SetupDiOpenDeviceInterfaceRegKey(HDEVINFO devinfo, PSP_DEVICE_INTERFACE_DATA iface_data,
3533 DWORD reserved, REGSAM access)
3535 struct device_iface *iface;
3536 LSTATUS lr;
3537 HKEY key;
3539 TRACE("devinfo %p, iface_data %p, reserved %d, access %#x.\n", devinfo, iface_data, reserved, access);
3541 if (!(iface = get_device_iface(devinfo, iface_data)))
3542 return INVALID_HANDLE_VALUE;
3544 lr = RegOpenKeyExW(iface->refstr_key, DeviceParameters, 0, access, &key);
3545 if (lr)
3547 SetLastError(lr);
3548 return INVALID_HANDLE_VALUE;
3551 return key;
3554 /***********************************************************************
3555 * SetupDiSetClassInstallParamsA (SETUPAPI.@)
3557 BOOL WINAPI SetupDiSetClassInstallParamsA(
3558 HDEVINFO DeviceInfoSet,
3559 PSP_DEVINFO_DATA DeviceInfoData,
3560 PSP_CLASSINSTALL_HEADER ClassInstallParams,
3561 DWORD ClassInstallParamsSize)
3563 FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
3564 ClassInstallParams->InstallFunction, ClassInstallParamsSize);
3565 return FALSE;
3568 /***********************************************************************
3569 * SetupDiSetClassInstallParamsW (SETUPAPI.@)
3571 BOOL WINAPI SetupDiSetClassInstallParamsW(
3572 HDEVINFO DeviceInfoSet,
3573 PSP_DEVINFO_DATA DeviceInfoData,
3574 PSP_CLASSINSTALL_HEADER ClassInstallParams,
3575 DWORD ClassInstallParamsSize)
3577 FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
3578 ClassInstallParams->InstallFunction, ClassInstallParamsSize);
3579 return FALSE;
3582 static BOOL call_coinstallers(WCHAR *list, DI_FUNCTION function, HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
3584 DWORD (CALLBACK *coinst_proc)(DI_FUNCTION, HDEVINFO, SP_DEVINFO_DATA *, COINSTALLER_CONTEXT_DATA *);
3585 COINSTALLER_CONTEXT_DATA coinst_ctx;
3586 WCHAR *p, *procnameW;
3587 HMODULE module;
3588 char *procname;
3589 DWORD ret;
3591 for (p = list; *p; p += lstrlenW(p) + 1)
3593 TRACE("Found co-installer %s.\n", debugstr_w(p));
3594 if ((procnameW = wcschr(p, ',')))
3595 *procnameW = 0;
3597 if ((module = LoadLibraryExW(p, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32)))
3599 if (procnameW)
3601 procname = strdupWtoA(procnameW + 1);
3602 coinst_proc = (void *)GetProcAddress(module, procname);
3603 heap_free(procname);
3605 else
3606 coinst_proc = (void *)GetProcAddress(module, "CoDeviceInstall");
3607 if (coinst_proc)
3609 memset(&coinst_ctx, 0, sizeof(coinst_ctx));
3610 TRACE("Calling co-installer %p.\n", coinst_proc);
3611 ret = coinst_proc(function, devinfo, device_data, &coinst_ctx);
3612 TRACE("Co-installer %p returned %#x.\n", coinst_proc, ret);
3613 if (ret == ERROR_DI_POSTPROCESSING_REQUIRED)
3614 FIXME("Co-installer postprocessing not implemented.\n");
3615 else if (ret)
3617 ERR("Co-installer returned error %#x.\n", ret);
3618 FreeLibrary(module);
3619 SetLastError(ret);
3620 return FALSE;
3623 FreeLibrary(module);
3627 return TRUE;
3630 /***********************************************************************
3631 * SetupDiCallClassInstaller (SETUPAPI.@)
3633 BOOL WINAPI SetupDiCallClassInstaller(DI_FUNCTION function, HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
3635 static const WCHAR class_coinst_pathW[] = {'S','y','s','t','e','m',
3636 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
3637 '\\','C','o','n','t','r','o','l',
3638 '\\','C','o','D','e','v','i','c','e','I','n','s','t','a','l','l','e','r','s',0};
3639 static const WCHAR coinstallers32W[] = {'C','o','I','n','s','t','a','l','l','e','r','s','3','2',0};
3640 static const WCHAR installer32W[] = {'I','n','s','t','a','l','l','e','r','3','2',0};
3641 DWORD (CALLBACK *classinst_proc)(DI_FUNCTION, HDEVINFO, SP_DEVINFO_DATA *);
3642 DWORD ret = ERROR_DI_DO_DEFAULT;
3643 HKEY class_key, coinst_key;
3644 WCHAR *path, *procnameW;
3645 struct device *device;
3646 WCHAR guidstr[39];
3647 BOOL coret = TRUE;
3648 HMODULE module;
3649 char *procname;
3650 DWORD size;
3652 TRACE("function %#x, devinfo %p, device_data %p.\n", function, devinfo, device_data);
3654 if (!(device = get_device(devinfo, device_data)))
3655 return FALSE;
3657 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, class_coinst_pathW, 0, KEY_READ, &coinst_key))
3659 SETUPDI_GuidToString(&device->class, guidstr);
3660 if (!RegGetValueW(coinst_key, NULL, guidstr, RRF_RT_REG_MULTI_SZ, NULL, NULL, &size))
3662 path = heap_alloc(size);
3663 if (!RegGetValueW(coinst_key, NULL, guidstr, RRF_RT_REG_MULTI_SZ, NULL, path, &size))
3664 coret = call_coinstallers(path, function, devinfo, device_data);
3665 heap_free(path);
3667 RegCloseKey(coinst_key);
3670 if (!coret)
3671 return FALSE;
3673 if (!open_driver_key(device, KEY_READ, &coinst_key))
3675 if (!RegGetValueW(coinst_key, NULL, coinstallers32W, RRF_RT_REG_MULTI_SZ, NULL, NULL, &size))
3677 path = heap_alloc(size);
3678 if (!RegGetValueW(coinst_key, NULL, coinstallers32W, RRF_RT_REG_MULTI_SZ, NULL, path, &size))
3679 coret = call_coinstallers(path, function, devinfo, device_data);
3680 heap_free(path);
3682 RegCloseKey(coinst_key);
3685 if ((class_key = SetupDiOpenClassRegKey(&device->class, KEY_READ)) != INVALID_HANDLE_VALUE)
3687 if (!RegGetValueW(class_key, NULL, installer32W, RRF_RT_REG_SZ, NULL, NULL, &size))
3689 path = heap_alloc(size);
3690 if (!RegGetValueW(class_key, NULL, installer32W, RRF_RT_REG_SZ, NULL, path, &size))
3692 TRACE("Found class installer %s.\n", debugstr_w(path));
3693 if ((procnameW = wcschr(path, ',')))
3694 *procnameW = 0;
3696 if ((module = LoadLibraryExW(path, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32)))
3698 if (procnameW)
3700 procname = strdupWtoA(procnameW + 1);
3701 classinst_proc = (void *)GetProcAddress(module, procname);
3702 heap_free(procname);
3704 else
3705 classinst_proc = (void *)GetProcAddress(module, "ClassInstall");
3706 if (classinst_proc)
3708 TRACE("Calling class installer %p.\n", classinst_proc);
3709 ret = classinst_proc(function, devinfo, device_data);
3710 TRACE("Class installer %p returned %#x.\n", classinst_proc, ret);
3712 FreeLibrary(module);
3715 heap_free(path);
3717 RegCloseKey(class_key);
3720 if (ret == ERROR_DI_DO_DEFAULT)
3722 switch (function)
3724 case DIF_REGISTERDEVICE:
3725 return SetupDiRegisterDeviceInfo(devinfo, device_data, 0, NULL, NULL, NULL);
3726 case DIF_REMOVE:
3727 return SetupDiRemoveDevice(devinfo, device_data);
3728 case DIF_SELECTBESTCOMPATDRV:
3729 return SetupDiSelectBestCompatDrv(devinfo, device_data);
3730 case DIF_REGISTER_COINSTALLERS:
3731 return SetupDiRegisterCoDeviceInstallers(devinfo, device_data);
3732 case DIF_INSTALLDEVICEFILES:
3733 return SetupDiInstallDriverFiles(devinfo, device_data);
3734 case DIF_INSTALLINTERFACES:
3735 return SetupDiInstallDeviceInterfaces(devinfo, device_data);
3736 case DIF_INSTALLDEVICE:
3737 return SetupDiInstallDevice(devinfo, device_data);
3738 case DIF_FINISHINSTALL_ACTION:
3739 case DIF_PROPERTYCHANGE:
3740 case DIF_SELECTDEVICE:
3741 case DIF_UNREMOVE:
3742 FIXME("Unhandled function %#x.\n", function);
3746 if (ret) SetLastError(ret);
3747 return !ret;
3750 /***********************************************************************
3751 * SetupDiGetDeviceInstallParamsW (SETUPAPI.@)
3753 BOOL WINAPI SetupDiGetDeviceInstallParamsW(HDEVINFO devinfo,
3754 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_W *params)
3756 struct device *device;
3758 TRACE("devinfo %p, device_data %p, params %p.\n", devinfo, device_data, params);
3760 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
3762 SetLastError(ERROR_INVALID_USER_BUFFER);
3763 return FALSE;
3766 if (!(device = get_device(devinfo, device_data)))
3767 return FALSE;
3769 *params = device->params;
3771 return TRUE;
3774 /***********************************************************************
3775 * SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
3777 BOOL WINAPI SetupDiGetDeviceInstallParamsA(HDEVINFO devinfo,
3778 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_A *params)
3780 SP_DEVINSTALL_PARAMS_W paramsW;
3781 BOOL ret;
3783 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
3785 SetLastError(ERROR_INVALID_USER_BUFFER);
3786 return FALSE;
3789 paramsW.cbSize = sizeof(paramsW);
3790 ret = SetupDiGetDeviceInstallParamsW(devinfo, device_data, &paramsW);
3791 params->Flags = paramsW.Flags;
3792 params->FlagsEx = paramsW.FlagsEx;
3793 params->hwndParent = paramsW.hwndParent;
3794 params->InstallMsgHandler = paramsW.InstallMsgHandler;
3795 params->InstallMsgHandlerContext = paramsW.InstallMsgHandlerContext;
3796 params->FileQueue = paramsW.FileQueue;
3797 params->ClassInstallReserved = paramsW.ClassInstallReserved;
3798 params->Reserved = paramsW.Reserved;
3799 WideCharToMultiByte(CP_ACP, 0, paramsW.DriverPath, -1, params->DriverPath, sizeof(params->DriverPath), NULL, NULL);
3801 return ret;
3804 /***********************************************************************
3805 * SetupDiSetDeviceInstallParamsA (SETUPAPI.@)
3807 BOOL WINAPI SetupDiSetDeviceInstallParamsA(HDEVINFO devinfo,
3808 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_A *params)
3810 SP_DEVINSTALL_PARAMS_W paramsW;
3812 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
3814 SetLastError(ERROR_INVALID_USER_BUFFER);
3815 return FALSE;
3818 paramsW.cbSize = sizeof(paramsW);
3819 paramsW.Flags = params->Flags;
3820 paramsW.FlagsEx = params->FlagsEx;
3821 paramsW.hwndParent = params->hwndParent;
3822 paramsW.InstallMsgHandler = params->InstallMsgHandler;
3823 paramsW.InstallMsgHandlerContext = params->InstallMsgHandlerContext;
3824 paramsW.FileQueue = params->FileQueue;
3825 paramsW.ClassInstallReserved = params->ClassInstallReserved;
3826 paramsW.Reserved = params->Reserved;
3827 MultiByteToWideChar(CP_ACP, 0, params->DriverPath, -1, paramsW.DriverPath, ARRAY_SIZE(paramsW.DriverPath));
3829 return SetupDiSetDeviceInstallParamsW(devinfo, device_data, &paramsW);
3832 /***********************************************************************
3833 * SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
3835 BOOL WINAPI SetupDiSetDeviceInstallParamsW(HDEVINFO devinfo,
3836 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_W *params)
3838 struct device *device;
3840 TRACE("devinfo %p, device_data %p, params %p.\n", devinfo, device_data, params);
3842 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
3844 SetLastError(ERROR_INVALID_USER_BUFFER);
3845 return FALSE;
3848 if (!(device = get_device(devinfo, device_data)))
3849 return FALSE;
3851 device->params = *params;
3853 return TRUE;
3856 BOOL WINAPI SetupDiSetDevicePropertyW(HDEVINFO devinfo, PSP_DEVINFO_DATA device_data, const DEVPROPKEY *key,
3857 DEVPROPTYPE type, const BYTE *buffer, DWORD size, DWORD flags)
3859 static const WCHAR propertiesW[] = {'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's', 0};
3860 static const WCHAR formatW[] = {'\\', '%', '0', '4', 'X', 0};
3861 struct device *device;
3862 HKEY properties_hkey, property_hkey;
3863 WCHAR property_hkey_path[44];
3864 LSTATUS ls;
3866 TRACE("%p %p %p %#x %p %d %#x\n", devinfo, device_data, key, type, buffer, size, flags);
3868 if (!(device = get_device(devinfo, device_data)))
3869 return FALSE;
3871 if (!key || !is_valid_property_type(type)
3872 || (buffer && !size && !(type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL))
3873 || (buffer && size && (type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL)))
3875 SetLastError(ERROR_INVALID_DATA);
3876 return FALSE;
3879 if (size && !buffer)
3881 SetLastError(ERROR_INVALID_USER_BUFFER);
3882 return FALSE;
3885 if (flags)
3887 SetLastError(ERROR_INVALID_FLAGS);
3888 return FALSE;
3891 ls = RegCreateKeyExW(device->key, propertiesW, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &properties_hkey, NULL);
3892 if (ls)
3894 SetLastError(ls);
3895 return FALSE;
3898 SETUPDI_GuidToString(&key->fmtid, property_hkey_path);
3899 swprintf(property_hkey_path + 38, ARRAY_SIZE(property_hkey_path) - 38, formatW, key->pid);
3901 if (type == DEVPROP_TYPE_EMPTY)
3903 ls = RegDeleteKeyW(properties_hkey, property_hkey_path);
3904 RegCloseKey(properties_hkey);
3905 SetLastError(ls == ERROR_FILE_NOT_FOUND ? ERROR_NOT_FOUND : ls);
3906 return !ls;
3908 else if (type == DEVPROP_TYPE_NULL)
3910 if (!(ls = RegOpenKeyW(properties_hkey, property_hkey_path, &property_hkey)))
3912 ls = RegDeleteValueW(property_hkey, NULL);
3913 RegCloseKey(property_hkey);
3916 RegCloseKey(properties_hkey);
3917 SetLastError(ls == ERROR_FILE_NOT_FOUND ? ERROR_NOT_FOUND : ls);
3918 return !ls;
3920 else
3922 if (!(ls = RegCreateKeyExW(properties_hkey, property_hkey_path, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL,
3923 &property_hkey, NULL)))
3925 ls = RegSetValueExW(property_hkey, NULL, 0, 0xffff0000 | (0xffff & type), buffer, size);
3926 RegCloseKey(property_hkey);
3929 RegCloseKey(properties_hkey);
3930 SetLastError(ls);
3931 return !ls;
3935 /***********************************************************************
3936 * SetupDiOpenDevRegKey (SETUPAPI.@)
3938 HKEY WINAPI SetupDiOpenDevRegKey(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
3939 DWORD Scope, DWORD HwProfile, DWORD KeyType, REGSAM samDesired)
3941 struct device *device;
3942 HKEY key = INVALID_HANDLE_VALUE;
3943 LONG l;
3945 TRACE("devinfo %p, device_data %p, scope %d, profile %d, type %d, access %#x.\n",
3946 devinfo, device_data, Scope, HwProfile, KeyType, samDesired);
3948 if (!(device = get_device(devinfo, device_data)))
3949 return INVALID_HANDLE_VALUE;
3951 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
3953 SetLastError(ERROR_INVALID_FLAGS);
3954 return INVALID_HANDLE_VALUE;
3956 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
3958 SetLastError(ERROR_INVALID_FLAGS);
3959 return INVALID_HANDLE_VALUE;
3962 if (device->phantom)
3964 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
3965 return INVALID_HANDLE_VALUE;
3967 if (Scope != DICS_FLAG_GLOBAL)
3968 FIXME("unimplemented for scope %d\n", Scope);
3969 switch (KeyType)
3971 case DIREG_DEV:
3972 l = RegOpenKeyExW(device->key, DeviceParameters, 0, samDesired, &key);
3973 break;
3974 case DIREG_DRV:
3975 l = open_driver_key(device, samDesired, &key);
3976 break;
3977 default:
3978 FIXME("Unhandled type %#x.\n", KeyType);
3979 l = ERROR_CALL_NOT_IMPLEMENTED;
3981 SetLastError(l == ERROR_FILE_NOT_FOUND ? ERROR_KEY_DOES_NOT_EXIST : l);
3982 return l ? INVALID_HANDLE_VALUE : key;
3985 /***********************************************************************
3986 * SetupDiDeleteDevRegKey (SETUPAPI.@)
3988 BOOL WINAPI SetupDiDeleteDevRegKey(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
3989 DWORD Scope, DWORD HwProfile, DWORD KeyType)
3991 struct device *device;
3992 LONG l;
3994 TRACE("devinfo %p, device_data %p, scope %d, profile %d, type %d.\n",
3995 devinfo, device_data, Scope, HwProfile, KeyType);
3997 if (!(device = get_device(devinfo, device_data)))
3998 return FALSE;
4000 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
4002 SetLastError(ERROR_INVALID_FLAGS);
4003 return FALSE;
4005 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV && KeyType != DIREG_BOTH)
4007 SetLastError(ERROR_INVALID_FLAGS);
4008 return FALSE;
4011 if (device->phantom)
4013 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
4014 return FALSE;
4016 if (Scope != DICS_FLAG_GLOBAL)
4017 FIXME("unimplemented for scope %d\n", Scope);
4018 switch (KeyType)
4020 case DIREG_DRV:
4021 l = delete_driver_key(device);
4022 break;
4023 case DIREG_BOTH:
4024 if ((l = delete_driver_key(device)))
4025 break;
4026 /* fall through */
4027 case DIREG_DEV:
4028 l = RegDeleteKeyW(device->key, DeviceParameters);
4029 break;
4030 default:
4031 FIXME("Unhandled type %#x.\n", KeyType);
4032 l = ERROR_CALL_NOT_IMPLEMENTED;
4034 SetLastError(l);
4035 return !l;
4038 /***********************************************************************
4039 * CM_Get_Device_IDA (SETUPAPI.@)
4041 CONFIGRET WINAPI CM_Get_Device_IDA(DEVINST devnode, char *buffer, ULONG len, ULONG flags)
4043 struct device *device = get_devnode_device(devnode);
4045 TRACE("%u, %p, %u, %#x\n", devnode, buffer, len, flags);
4047 if (!device)
4048 return CR_NO_SUCH_DEVINST;
4050 WideCharToMultiByte(CP_ACP, 0, device->instanceId, -1, buffer, len, 0, 0);
4051 TRACE("Returning %s\n", debugstr_a(buffer));
4052 return CR_SUCCESS;
4055 /***********************************************************************
4056 * CM_Get_Device_IDW (SETUPAPI.@)
4058 CONFIGRET WINAPI CM_Get_Device_IDW(DEVINST devnode, WCHAR *buffer, ULONG len, ULONG flags)
4060 struct device *device = get_devnode_device(devnode);
4062 TRACE("%u, %p, %u, %#x\n", devnode, buffer, len, flags);
4064 if (!device)
4065 return CR_NO_SUCH_DEVINST;
4067 lstrcpynW(buffer, device->instanceId, len);
4068 TRACE("Returning %s\n", debugstr_w(buffer));
4069 return CR_SUCCESS;
4072 /***********************************************************************
4073 * CM_Get_Device_ID_Size (SETUPAPI.@)
4075 CONFIGRET WINAPI CM_Get_Device_ID_Size(ULONG *len, DEVINST devnode, ULONG flags)
4077 struct device *device = get_devnode_device(devnode);
4079 TRACE("%p, %u, %#x\n", len, devnode, flags);
4081 if (!device)
4082 return CR_NO_SUCH_DEVINST;
4084 *len = lstrlenW(device->instanceId);
4085 return CR_SUCCESS;
4088 /***********************************************************************
4089 * SetupDiGetINFClassA (SETUPAPI.@)
4091 BOOL WINAPI SetupDiGetINFClassA(PCSTR inf, LPGUID class_guid, PSTR class_name,
4092 DWORD size, PDWORD required_size)
4094 BOOL retval;
4095 DWORD required_sizeA, required_sizeW;
4096 PWSTR class_nameW = NULL;
4097 UNICODE_STRING infW;
4099 if (inf)
4101 if (!RtlCreateUnicodeStringFromAsciiz(&infW, inf))
4103 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4104 return FALSE;
4107 else
4108 infW.Buffer = NULL;
4110 if (class_name && size)
4112 if (!(class_nameW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR))))
4114 RtlFreeUnicodeString(&infW);
4115 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4116 return FALSE;
4120 retval = SetupDiGetINFClassW(infW.Buffer, class_guid, class_nameW, size, &required_sizeW);
4122 if (retval)
4124 required_sizeA = WideCharToMultiByte( CP_ACP, 0, class_nameW, required_sizeW,
4125 class_name, size, NULL, NULL);
4127 if(required_size) *required_size = required_sizeA;
4129 else
4130 if(required_size) *required_size = required_sizeW;
4132 HeapFree(GetProcessHeap(), 0, class_nameW);
4133 RtlFreeUnicodeString(&infW);
4134 return retval;
4137 /***********************************************************************
4138 * SetupDiGetINFClassW (SETUPAPI.@)
4140 BOOL WINAPI SetupDiGetINFClassW(PCWSTR inf, LPGUID class_guid, PWSTR class_name,
4141 DWORD size, PDWORD required_size)
4143 BOOL have_guid, have_name;
4144 DWORD dret;
4145 WCHAR buffer[MAX_PATH];
4147 if (!inf)
4149 SetLastError(ERROR_INVALID_PARAMETER);
4150 return FALSE;
4153 if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(inf))
4155 FIXME("%s not found. Searching via DevicePath not implemented\n", debugstr_w(inf));
4156 SetLastError(ERROR_FILE_NOT_FOUND);
4157 return FALSE;
4160 if (!class_guid || !class_name || !size)
4162 SetLastError(ERROR_INVALID_PARAMETER);
4163 return FALSE;
4166 if (!GetPrivateProfileStringW(Version, Signature, NULL, buffer, MAX_PATH, inf))
4167 return FALSE;
4169 if (lstrcmpiW(buffer, Chicago) && lstrcmpiW(buffer, WindowsNT))
4170 return FALSE;
4172 buffer[0] = '\0';
4173 have_guid = 0 < GetPrivateProfileStringW(Version, ClassGUID, NULL, buffer, MAX_PATH, inf);
4174 if (have_guid)
4176 buffer[lstrlenW(buffer)-1] = 0;
4177 if (RPC_S_OK != UuidFromStringW(buffer + 1, class_guid))
4179 FIXME("failed to convert \"%s\" into a guid\n", debugstr_w(buffer));
4180 SetLastError(ERROR_INVALID_PARAMETER);
4181 return FALSE;
4185 buffer[0] = '\0';
4186 dret = GetPrivateProfileStringW(Version, Class, NULL, buffer, MAX_PATH, inf);
4187 have_name = 0 < dret;
4189 if (dret >= MAX_PATH -1) FIXME("buffer might be too small\n");
4190 if (have_guid && !have_name) FIXME("class name lookup via guid not implemented\n");
4192 if (have_name)
4194 if (dret < size) lstrcpyW(class_name, buffer);
4195 else
4197 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4198 have_name = FALSE;
4202 if (required_size) *required_size = dret + ((dret) ? 1 : 0);
4204 return (have_guid || have_name);
4207 static LSTATUS get_device_property(struct device *device, const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type,
4208 BYTE *prop_buff, DWORD prop_buff_size, DWORD *required_size, DWORD flags)
4210 WCHAR key_path[55] = L"Properties\\";
4211 HKEY hkey;
4212 DWORD value_type;
4213 DWORD value_size = 0;
4214 LSTATUS ls;
4216 if (!prop_key)
4217 return ERROR_INVALID_DATA;
4219 if (!prop_type || (!prop_buff && prop_buff_size))
4220 return ERROR_INVALID_USER_BUFFER;
4222 if (flags)
4223 return ERROR_INVALID_FLAGS;
4225 SETUPDI_GuidToString(&prop_key->fmtid, key_path + 11);
4226 swprintf(key_path + 49, ARRAY_SIZE(key_path) - 49, L"\\%04X", prop_key->pid);
4228 ls = RegOpenKeyExW(device->key, key_path, 0, KEY_QUERY_VALUE, &hkey);
4229 if (!ls)
4231 value_size = prop_buff_size;
4232 ls = RegQueryValueExW(hkey, NULL, NULL, &value_type, prop_buff, &value_size);
4235 switch (ls)
4237 case NO_ERROR:
4238 case ERROR_MORE_DATA:
4239 *prop_type = 0xffff & value_type;
4240 ls = (ls == ERROR_MORE_DATA || !prop_buff) ? ERROR_INSUFFICIENT_BUFFER : NO_ERROR;
4241 break;
4242 case ERROR_FILE_NOT_FOUND:
4243 *prop_type = DEVPROP_TYPE_EMPTY;
4244 value_size = 0;
4245 ls = ERROR_NOT_FOUND;
4246 break;
4247 default:
4248 *prop_type = DEVPROP_TYPE_EMPTY;
4249 value_size = 0;
4250 FIXME("Unhandled error %#x\n", ls);
4251 break;
4254 if (required_size)
4255 *required_size = value_size;
4257 return ls;
4260 /***********************************************************************
4261 * SetupDiGetDevicePropertyW (SETUPAPI.@)
4263 BOOL WINAPI SetupDiGetDevicePropertyW(HDEVINFO devinfo, PSP_DEVINFO_DATA device_data,
4264 const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type, BYTE *prop_buff,
4265 DWORD prop_buff_size, DWORD *required_size, DWORD flags)
4267 struct device *device;
4268 LSTATUS ls;
4270 TRACE("%p, %p, %p, %p, %p, %d, %p, %#x\n", devinfo, device_data, prop_key, prop_type, prop_buff, prop_buff_size,
4271 required_size, flags);
4273 if (!(device = get_device(devinfo, device_data)))
4274 return FALSE;
4276 ls = get_device_property(device, prop_key, prop_type, prop_buff, prop_buff_size, required_size, flags);
4278 SetLastError(ls);
4279 return !ls;
4282 /***********************************************************************
4283 * CM_Get_DevNode_Property_ExW (SETUPAPI.@)
4285 CONFIGRET WINAPI CM_Get_DevNode_Property_ExW(DEVINST devnode, const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type,
4286 BYTE *prop_buff, ULONG *prop_buff_size, ULONG flags, HMACHINE machine)
4288 struct device *device = get_devnode_device(devnode);
4289 LSTATUS ls;
4291 TRACE("%u, %p, %p, %p, %p, %#x, %p\n", devnode, prop_key, prop_type, prop_buff, prop_buff_size,
4292 flags, machine);
4294 if (machine)
4295 return CR_MACHINE_UNAVAILABLE;
4297 if (!device)
4298 return CR_NO_SUCH_DEVINST;
4300 if (!prop_buff_size)
4301 return CR_INVALID_POINTER;
4303 ls = get_device_property(device, prop_key, prop_type, prop_buff, *prop_buff_size, prop_buff_size, flags);
4304 switch (ls)
4306 case NO_ERROR:
4307 return CR_SUCCESS;
4308 case ERROR_INVALID_DATA:
4309 return CR_INVALID_DATA;
4310 case ERROR_INVALID_USER_BUFFER:
4311 return CR_INVALID_POINTER;
4312 case ERROR_INVALID_FLAGS:
4313 return CR_INVALID_FLAG;
4314 case ERROR_INSUFFICIENT_BUFFER:
4315 return CR_BUFFER_SMALL;
4316 case ERROR_NOT_FOUND:
4317 return CR_NO_SUCH_VALUE;
4319 return CR_FAILURE;
4322 /***********************************************************************
4323 * CM_Get_DevNode_PropertyW (SETUPAPI.@)
4325 CONFIGRET WINAPI CM_Get_DevNode_PropertyW(DEVINST dev, const DEVPROPKEY *key, DEVPROPTYPE *type,
4326 PVOID buf, PULONG len, ULONG flags)
4328 return CM_Get_DevNode_Property_ExW(dev, key, type, buf, len, flags, NULL);
4331 /***********************************************************************
4332 * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
4334 BOOL WINAPI SetupDiInstallDeviceInterfaces(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4336 WCHAR section_ext[LINE_LEN], iface_section[LINE_LEN], refstr[LINE_LEN], guidstr[39];
4337 UINT install_flags = SPINST_ALL;
4338 struct device_iface *iface;
4339 struct device *device;
4340 struct driver *driver;
4341 void *callback_ctx;
4342 GUID iface_guid;
4343 INFCONTEXT ctx;
4344 HKEY iface_key;
4345 HINF hinf;
4346 LONG l;
4348 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
4350 if (!(device = get_device(devinfo, device_data)))
4351 return FALSE;
4353 if (!(driver = device->selected_driver))
4355 ERR("No driver selected for device %p.\n", devinfo);
4356 SetLastError(ERROR_NO_DRIVER_SELECTED);
4357 return FALSE;
4360 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4361 return FALSE;
4363 SetupDiGetActualSectionToInstallW(hinf, driver->section, section_ext, ARRAY_SIZE(section_ext), NULL, NULL);
4365 if (device->params.Flags & DI_NOFILECOPY)
4366 install_flags &= ~SPINST_FILES;
4368 callback_ctx = SetupInitDefaultQueueCallback(NULL);
4370 lstrcatW(section_ext, dotInterfaces);
4371 if (SetupFindFirstLineW(hinf, section_ext, AddInterface, &ctx))
4373 do {
4374 SetupGetStringFieldW(&ctx, 1, guidstr, ARRAY_SIZE(guidstr), NULL);
4375 SetupGetStringFieldW(&ctx, 2, refstr, ARRAY_SIZE(refstr), NULL);
4376 guidstr[37] = 0;
4377 UuidFromStringW(&guidstr[1], &iface_guid);
4379 if (!(iface = SETUPDI_CreateDeviceInterface(device, &iface_guid, refstr)))
4381 ERR("Failed to create device interface, error %#x.\n", GetLastError());
4382 continue;
4385 if ((l = create_iface_key(iface, KEY_ALL_ACCESS, &iface_key)))
4387 ERR("Failed to create interface key, error %u.\n", l);
4388 continue;
4391 SetupGetStringFieldW(&ctx, 3, iface_section, ARRAY_SIZE(iface_section), NULL);
4392 SetupInstallFromInfSectionW(NULL, hinf, iface_section, install_flags, iface_key,
4393 NULL, SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
4395 RegCloseKey(iface_key);
4396 } while (SetupFindNextMatchLineW(&ctx, AddInterface, &ctx));
4399 SetupTermDefaultQueueCallback(callback_ctx);
4401 SetupCloseInfFile(hinf);
4402 return TRUE;
4405 /***********************************************************************
4406 * SetupDiRegisterCoDeviceInstallers (SETUPAPI.@)
4408 BOOL WINAPI SetupDiRegisterCoDeviceInstallers(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4410 static const WCHAR coinstallersW[] = {'.','C','o','I','n','s','t','a','l','l','e','r','s',0};
4411 WCHAR coinst_key_ext[LINE_LEN];
4412 struct device *device;
4413 struct driver *driver;
4414 void *callback_ctx;
4415 HKEY driver_key;
4416 HINF hinf;
4417 LONG l;
4419 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
4421 if (!(device = get_device(devinfo, device_data)))
4422 return FALSE;
4424 if (!(driver = device->selected_driver))
4426 ERR("No driver selected for device %p.\n", devinfo);
4427 SetLastError(ERROR_NO_DRIVER_SELECTED);
4428 return FALSE;
4431 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4432 return FALSE;
4434 SetupDiGetActualSectionToInstallW(hinf, driver->section, coinst_key_ext, ARRAY_SIZE(coinst_key_ext), NULL, NULL);
4435 lstrcatW(coinst_key_ext, coinstallersW);
4437 if ((l = create_driver_key(device, &driver_key)))
4439 SetLastError(l);
4440 SetupCloseInfFile(hinf);
4441 return FALSE;
4444 callback_ctx = SetupInitDefaultQueueCallback(NULL);
4445 SetupInstallFromInfSectionW(NULL, hinf, coinst_key_ext, SPINST_ALL, driver_key, NULL,
4446 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
4447 SetupTermDefaultQueueCallback(callback_ctx);
4449 RegCloseKey(driver_key);
4450 SetupCloseInfFile(hinf);
4451 return TRUE;
4454 /* Check whether the given hardware or compatible ID matches any of the device's
4455 * own hardware or compatible IDs. */
4456 static BOOL device_matches_id(const struct device *device, const WCHAR *id_type, const WCHAR *id)
4458 WCHAR *device_ids;
4459 const WCHAR *p;
4460 DWORD size;
4462 if (!RegGetValueW(device->key, NULL, id_type, RRF_RT_REG_MULTI_SZ, NULL, NULL, &size))
4464 device_ids = heap_alloc(size);
4465 if (!RegGetValueW(device->key, NULL, id_type, RRF_RT_REG_MULTI_SZ, NULL, device_ids, &size))
4467 for (p = device_ids; *p; p += lstrlenW(p) + 1)
4469 if (!wcsicmp(p, id))
4471 heap_free(device_ids);
4472 return TRUE;
4476 heap_free(device_ids);
4479 return FALSE;
4482 static BOOL version_is_compatible(const WCHAR *version)
4484 const WCHAR *machine_ext = NtPlatformExtension + 1, *p;
4485 size_t len = lstrlenW(version);
4486 BOOL wow64;
4488 /* We are only concerned with architecture. */
4489 if ((p = wcschr(version, '.')))
4490 len = p - version;
4492 if (!wcsnicmp(version, NtExtension + 1, len))
4493 return TRUE;
4495 if (IsWow64Process(GetCurrentProcess(), &wow64) && wow64)
4497 #ifdef __i386__
4498 static const WCHAR wow_ext[] = {'N','T','a','m','d','6','4',0};
4499 machine_ext = wow_ext;
4500 #elif defined(__arm__)
4501 static const WCHAR wow_ext[] = {'N','T','a','r','m','6','4',0};
4502 machine_ext = wow_ext;
4503 #endif
4506 return !wcsnicmp(version, machine_ext, len);
4509 static void enum_compat_drivers_from_file(struct device *device, const WCHAR *path)
4511 static const WCHAR manufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4512 WCHAR mfg_name[LINE_LEN], mfg_key[LINE_LEN], mfg_key_ext[LINE_LEN], id[MAX_DEVICE_ID_LEN], version[MAX_DEVICE_ID_LEN];
4513 INFCONTEXT ctx;
4514 DWORD i, j, k;
4515 HINF hinf;
4517 TRACE("Enumerating drivers from %s.\n", debugstr_w(path));
4519 if ((hinf = SetupOpenInfFileW(path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4520 return;
4522 for (i = 0; SetupGetLineByIndexW(hinf, manufacturerW, i, &ctx); ++i)
4524 SetupGetStringFieldW(&ctx, 0, mfg_name, ARRAY_SIZE(mfg_name), NULL);
4525 if (!SetupGetStringFieldW(&ctx, 1, mfg_key, ARRAY_SIZE(mfg_key), NULL))
4526 lstrcpyW(mfg_key, mfg_name);
4528 if (SetupGetFieldCount(&ctx) >= 2)
4530 BOOL compatible = FALSE;
4531 for (j = 2; SetupGetStringFieldW(&ctx, j, version, ARRAY_SIZE(version), NULL); ++j)
4533 if (version_is_compatible(version))
4535 compatible = TRUE;
4536 break;
4539 if (!compatible)
4540 continue;
4543 if (!SetupDiGetActualSectionToInstallW(hinf, mfg_key, mfg_key_ext, ARRAY_SIZE(mfg_key_ext), NULL, NULL))
4545 WARN("Failed to find section for %s, skipping.\n", debugstr_w(mfg_key));
4546 continue;
4549 for (j = 0; SetupGetLineByIndexW(hinf, mfg_key_ext, j, &ctx); ++j)
4551 for (k = 2; SetupGetStringFieldW(&ctx, k, id, ARRAY_SIZE(id), NULL); ++k)
4553 if (device_matches_id(device, HardwareId, id) || device_matches_id(device, CompatibleIDs, id))
4555 unsigned int count = ++device->driver_count;
4557 device->drivers = heap_realloc(device->drivers, count * sizeof(*device->drivers));
4558 lstrcpyW(device->drivers[count - 1].inf_path, path);
4559 lstrcpyW(device->drivers[count - 1].manufacturer, mfg_name);
4560 lstrcpyW(device->drivers[count - 1].mfg_key, mfg_key_ext);
4561 SetupGetStringFieldW(&ctx, 0, device->drivers[count - 1].description,
4562 ARRAY_SIZE(device->drivers[count - 1].description), NULL);
4563 SetupGetStringFieldW(&ctx, 1, device->drivers[count - 1].section,
4564 ARRAY_SIZE(device->drivers[count - 1].section), NULL);
4566 TRACE("Found compatible driver: manufacturer %s, desc %s.\n",
4567 debugstr_w(mfg_name), debugstr_w(device->drivers[count - 1].description));
4573 SetupCloseInfFile(hinf);
4576 /***********************************************************************
4577 * SetupDiBuildDriverInfoList (SETUPAPI.@)
4579 BOOL WINAPI SetupDiBuildDriverInfoList(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD type)
4581 struct device *device;
4583 TRACE("devinfo %p, device_data %p, type %#x.\n", devinfo, device_data, type);
4585 if (type != SPDIT_COMPATDRIVER)
4587 FIXME("Unhandled type %#x.\n", type);
4588 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4589 return FALSE;
4592 if (!(device = get_device(devinfo, device_data)))
4593 return FALSE;
4595 if (device->params.Flags & DI_ENUMSINGLEINF)
4597 enum_compat_drivers_from_file(device, device->params.DriverPath);
4599 else
4601 static const WCHAR default_path[] = {'C',':','/','w','i','n','d','o','w','s','/','i','n','f',0};
4602 static const WCHAR wildcardW[] = {'*',0};
4603 WCHAR dir[MAX_PATH], file[MAX_PATH];
4604 WIN32_FIND_DATAW find_data;
4605 HANDLE find_handle;
4607 if (device->params.DriverPath[0])
4608 lstrcpyW(dir, device->params.DriverPath);
4609 else
4610 lstrcpyW(dir, default_path);
4611 lstrcatW(dir, backslashW);
4612 lstrcatW(dir, wildcardW);
4614 TRACE("Searching for drivers in %s.\n", debugstr_w(dir));
4616 if ((find_handle = FindFirstFileW(dir, &find_data)) != INVALID_HANDLE_VALUE)
4620 lstrcpyW(file, dir);
4621 lstrcpyW(file + lstrlenW(file) - 1, find_data.cFileName);
4622 enum_compat_drivers_from_file(device, file);
4623 } while (FindNextFileW(find_handle, &find_data));
4625 FindClose(find_handle);
4629 if (device->driver_count)
4631 WCHAR classname[MAX_CLASS_NAME_LEN], guidstr[39];
4632 GUID class;
4634 if (SetupDiGetINFClassW(device->drivers[0].inf_path, &class, classname, ARRAY_SIZE(classname), NULL))
4636 device_data->ClassGuid = device->class = class;
4637 SETUPDI_GuidToString(&class, guidstr);
4638 RegSetValueExW(device->key, L"ClassGUID", 0, REG_SZ, (BYTE *)guidstr, sizeof(guidstr));
4639 RegSetValueExW(device->key, L"Class", 0, REG_SZ, (BYTE *)classname, wcslen(classname) * sizeof(WCHAR));
4643 return TRUE;
4646 static BOOL copy_driver_data(SP_DRVINFO_DATA_W *data, const struct driver *driver)
4648 INFCONTEXT ctx;
4649 HINF hinf;
4651 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4652 return FALSE;
4654 data->ProviderName[0] = 0;
4655 if (SetupFindFirstLineW(hinf, L"Version", L"Provider", &ctx))
4656 SetupGetStringFieldW(&ctx, 1, data->ProviderName, ARRAY_SIZE(data->ProviderName), NULL);
4657 wcscpy(data->Description, driver->description);
4658 wcscpy(data->MfgName, driver->manufacturer);
4659 data->DriverType = SPDIT_COMPATDRIVER;
4660 data->Reserved = (ULONG_PTR)driver;
4662 SetupCloseInfFile(hinf);
4664 return TRUE;
4667 static void driver_data_wtoa(SP_DRVINFO_DATA_A *a, const SP_DRVINFO_DATA_W *w)
4669 a->DriverType = w->DriverType;
4670 a->Reserved = w->Reserved;
4671 WideCharToMultiByte(CP_ACP, 0, w->Description, -1, a->Description, sizeof(a->Description), NULL, NULL);
4672 WideCharToMultiByte(CP_ACP, 0, w->MfgName, -1, a->MfgName, sizeof(a->MfgName), NULL, NULL);
4673 WideCharToMultiByte(CP_ACP, 0, w->ProviderName, -1, a->ProviderName, sizeof(a->ProviderName), NULL, NULL);
4676 /***********************************************************************
4677 * SetupDiEnumDriverInfoW (SETUPAPI.@)
4679 BOOL WINAPI SetupDiEnumDriverInfoW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4680 DWORD type, DWORD index, SP_DRVINFO_DATA_W *driver_data)
4682 struct device *device;
4684 TRACE("devinfo %p, device_data %p, type %#x, index %u, driver_data %p.\n",
4685 devinfo, device_data, type, index, driver_data);
4687 if (type != SPDIT_COMPATDRIVER)
4689 FIXME("Unhandled type %#x.\n", type);
4690 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4691 return FALSE;
4694 if (!(device = get_device(devinfo, device_data)))
4695 return FALSE;
4697 if (index >= device->driver_count)
4699 SetLastError(ERROR_NO_MORE_ITEMS);
4700 return FALSE;
4703 return copy_driver_data(driver_data, &device->drivers[index]);
4706 /***********************************************************************
4707 * SetupDiEnumDriverInfoA (SETUPAPI.@)
4709 BOOL WINAPI SetupDiEnumDriverInfoA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4710 DWORD type, DWORD index, SP_DRVINFO_DATA_A *driver_data)
4712 SP_DRVINFO_DATA_W driver_dataW;
4713 BOOL ret;
4715 driver_dataW.cbSize = sizeof(driver_dataW);
4716 ret = SetupDiEnumDriverInfoW(devinfo, device_data, type, index, &driver_dataW);
4717 driver_data_wtoa(driver_data, &driver_dataW);
4718 return ret;
4721 /***********************************************************************
4722 * SetupDiSelectBestCompatDrv (SETUPAPI.@)
4724 BOOL WINAPI SetupDiSelectBestCompatDrv(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4726 struct device *device;
4728 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
4730 if (!(device = get_device(devinfo, device_data)))
4731 return FALSE;
4733 if (!device->driver_count)
4735 ERR("No compatible drivers were enumerated for device %s.\n", debugstr_w(device->instanceId));
4736 SetLastError(ERROR_NO_COMPAT_DRIVERS);
4737 return FALSE;
4740 WARN("Semi-stub, selecting the first available driver.\n");
4742 device->selected_driver = &device->drivers[0];
4744 return TRUE;
4747 /***********************************************************************
4748 * SetupDiGetSelectedDriverW (SETUPAPI.@)
4750 BOOL WINAPI SetupDiGetSelectedDriverW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, SP_DRVINFO_DATA_W *driver_data)
4752 struct device *device;
4754 TRACE("devinfo %p, device_data %p, driver_data %p.\n", devinfo, device_data, driver_data);
4756 if (!(device = get_device(devinfo, device_data)))
4757 return FALSE;
4759 if (!device->selected_driver)
4761 SetLastError(ERROR_NO_DRIVER_SELECTED);
4762 return FALSE;
4765 return copy_driver_data(driver_data, device->selected_driver);
4768 /***********************************************************************
4769 * SetupDiGetSelectedDriverA (SETUPAPI.@)
4771 BOOL WINAPI SetupDiGetSelectedDriverA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, SP_DRVINFO_DATA_A *driver_data)
4773 SP_DRVINFO_DATA_W driver_dataW;
4774 BOOL ret;
4776 driver_dataW.cbSize = sizeof(driver_dataW);
4777 if ((ret = SetupDiGetSelectedDriverW(devinfo, device_data, &driver_dataW)))
4778 driver_data_wtoa(driver_data, &driver_dataW);
4779 return ret;
4782 /***********************************************************************
4783 * SetupDiGetDriverInfoDetailW (SETUPAPI.@)
4785 BOOL WINAPI SetupDiGetDriverInfoDetailW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4786 SP_DRVINFO_DATA_W *driver_data, SP_DRVINFO_DETAIL_DATA_W *detail_data, const DWORD size, DWORD *ret_size)
4788 struct driver *driver = (struct driver *)driver_data->Reserved;
4789 DWORD size_needed, i, id_size = 1;
4790 WCHAR id[MAX_DEVICE_ID_LEN];
4791 INFCONTEXT ctx;
4792 HANDLE file;
4793 HINF hinf;
4795 TRACE("devinfo %p, device_data %p, driver_data %p, detail_data %p, size %u, ret_size %p.\n",
4796 devinfo, device_data, driver_data, detail_data, size, ret_size);
4798 if ((detail_data || size) && size < sizeof(SP_DRVINFO_DETAIL_DATA_W))
4800 SetLastError(ERROR_INVALID_USER_BUFFER);
4801 return FALSE;
4804 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4805 return FALSE;
4807 SetupFindFirstLineW(hinf, driver->mfg_key, driver->description, &ctx);
4808 for (i = 2; SetupGetStringFieldW(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
4809 id_size += wcslen(id) + 1;
4811 size_needed = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID[id_size]);
4812 if (ret_size)
4813 *ret_size = size_needed;
4814 if (!detail_data)
4815 return TRUE;
4817 detail_data->CompatIDsLength = detail_data->CompatIDsOffset = 0;
4818 detail_data->HardwareID[0] = 0;
4820 if (size >= size_needed)
4822 id_size = 0;
4823 for (i = 2; SetupGetStringFieldW(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
4825 wcscpy(&detail_data->HardwareID[id_size], id);
4826 if (i == 3)
4827 detail_data->CompatIDsOffset = id_size;
4828 id_size += wcslen(id) + 1;
4830 detail_data->HardwareID[id_size++] = 0;
4831 if (i > 3)
4832 detail_data->CompatIDsLength = id_size - detail_data->CompatIDsOffset;
4835 SetupCloseInfFile(hinf);
4837 if ((file = CreateFileW(driver->inf_path, 0, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
4838 return FALSE;
4839 GetFileTime(file, NULL, NULL, &detail_data->InfDate);
4840 CloseHandle(file);
4842 wcscpy(detail_data->SectionName, driver->section);
4843 wcscpy(detail_data->InfFileName, driver->inf_path);
4844 wcscpy(detail_data->DrvDescription, driver->description);
4846 if (size < size_needed)
4848 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4849 return FALSE;
4852 return TRUE;
4855 /***********************************************************************
4856 * SetupDiGetDriverInfoDetailA (SETUPAPI.@)
4858 BOOL WINAPI SetupDiGetDriverInfoDetailA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4859 SP_DRVINFO_DATA_A *driver_data, SP_DRVINFO_DETAIL_DATA_A *detail_data, const DWORD size, DWORD *ret_size)
4861 struct driver *driver = (struct driver *)driver_data->Reserved;
4862 DWORD size_needed, i, id_size = 1;
4863 char id[MAX_DEVICE_ID_LEN];
4864 INFCONTEXT ctx;
4865 HANDLE file;
4866 HINF hinf;
4868 TRACE("devinfo %p, device_data %p, driver_data %p, detail_data %p, size %u, ret_size %p.\n",
4869 devinfo, device_data, driver_data, detail_data, size, ret_size);
4871 if ((detail_data || size) && size < sizeof(SP_DRVINFO_DETAIL_DATA_A))
4873 SetLastError(ERROR_INVALID_USER_BUFFER);
4874 return FALSE;
4877 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4878 return FALSE;
4880 SetupFindFirstLineW(hinf, driver->mfg_key, driver->description, &ctx);
4881 for (i = 2; SetupGetStringFieldA(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
4882 id_size += strlen(id) + 1;
4884 size_needed = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID[id_size]);
4885 if (ret_size)
4886 *ret_size = size_needed;
4887 if (!detail_data)
4888 return TRUE;
4890 detail_data->CompatIDsLength = detail_data->CompatIDsOffset = 0;
4891 detail_data->HardwareID[0] = 0;
4893 if (size >= size_needed)
4895 id_size = 0;
4896 for (i = 2; SetupGetStringFieldA(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
4898 strcpy(&detail_data->HardwareID[id_size], id);
4899 if (i == 3)
4900 detail_data->CompatIDsOffset = id_size;
4901 id_size += strlen(id) + 1;
4903 detail_data->HardwareID[id_size++] = 0;
4904 if (i > 3)
4905 detail_data->CompatIDsLength = id_size - detail_data->CompatIDsOffset;
4908 SetupCloseInfFile(hinf);
4910 if ((file = CreateFileW(driver->inf_path, 0, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
4911 return FALSE;
4912 GetFileTime(file, NULL, NULL, &detail_data->InfDate);
4913 CloseHandle(file);
4915 WideCharToMultiByte(CP_ACP, 0, driver->section, -1, detail_data->SectionName,
4916 sizeof(detail_data->SectionName), NULL, NULL);
4917 WideCharToMultiByte(CP_ACP, 0, driver->inf_path, -1, detail_data->InfFileName,
4918 sizeof(detail_data->InfFileName), NULL, NULL);
4919 WideCharToMultiByte(CP_ACP, 0, driver->description, -1, detail_data->DrvDescription,
4920 sizeof(detail_data->InfFileName), NULL, NULL);
4922 if (size < size_needed)
4924 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4925 return FALSE;
4928 return TRUE;
4931 /***********************************************************************
4932 * SetupDiInstallDriverFiles (SETUPAPI.@)
4934 BOOL WINAPI SetupDiInstallDriverFiles(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4936 WCHAR section[LINE_LEN], section_ext[LINE_LEN], iface_section[LINE_LEN];
4937 struct device *device;
4938 struct driver *driver;
4939 void *callback_ctx;
4940 INFCONTEXT ctx;
4941 HINF hinf;
4943 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
4945 if (!(device = get_device(devinfo, device_data)))
4946 return FALSE;
4948 if (!(driver = device->selected_driver))
4950 ERR("No driver selected for device %p.\n", devinfo);
4951 SetLastError(ERROR_NO_DRIVER_SELECTED);
4952 return FALSE;
4955 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4956 return FALSE;
4958 SetupFindFirstLineW(hinf, driver->mfg_key, driver->description, &ctx);
4959 SetupGetStringFieldW(&ctx, 1, section, ARRAY_SIZE(section), NULL);
4960 SetupDiGetActualSectionToInstallW(hinf, section, section_ext, ARRAY_SIZE(section_ext), NULL, NULL);
4962 callback_ctx = SetupInitDefaultQueueCallback(NULL);
4964 SetupInstallFromInfSectionW(NULL, hinf, section_ext, SPINST_FILES, NULL, NULL,
4965 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
4967 lstrcatW(section_ext, dotInterfaces);
4968 if (SetupFindFirstLineW(hinf, section_ext, AddInterface, &ctx))
4970 do {
4971 SetupGetStringFieldW(&ctx, 3, iface_section, ARRAY_SIZE(iface_section), NULL);
4972 SetupInstallFromInfSectionW(NULL, hinf, iface_section, SPINST_FILES, NULL, NULL,
4973 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
4974 } while (SetupFindNextMatchLineW(&ctx, AddInterface, &ctx));
4977 SetupTermDefaultQueueCallback(callback_ctx);
4979 SetupCloseInfFile(hinf);
4980 return TRUE;
4983 /***********************************************************************
4984 * SetupDiInstallDevice (SETUPAPI.@)
4986 BOOL WINAPI SetupDiInstallDevice(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4988 static const WCHAR infpathW[] = {'I','n','f','P','a','t','h',0};
4989 static const WCHAR infsectionW[] = {'I','n','f','S','e','c','t','i','o','n',0};
4990 static const WCHAR infsectionextW[] = {'I','n','f','S','e','c','t','i','o','n','E','x','t',0};
4991 static const WCHAR dothwW[] = {'.','H','W',0};
4992 static const WCHAR dotservicesW[] = {'.','S','e','r','v','i','c','e','s',0};
4993 static const WCHAR addserviceW[] = {'A','d','d','S','e','r','v','i','c','e',0};
4994 static const WCHAR rootW[] = {'r','o','o','t','\\',0};
4995 WCHAR section[LINE_LEN], section_ext[LINE_LEN], subsection[LINE_LEN], inf_path[MAX_PATH], *extptr, *filepart;
4996 UINT install_flags = SPINST_ALL;
4997 HKEY driver_key, device_key;
4998 SC_HANDLE manager, service;
4999 WCHAR svc_name[LINE_LEN];
5000 struct device *device;
5001 struct driver *driver;
5002 void *callback_ctx;
5003 INFCONTEXT ctx;
5004 HINF hinf;
5005 LONG l;
5007 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
5009 if (!(device = get_device(devinfo, device_data)))
5010 return FALSE;
5012 if (!(driver = device->selected_driver))
5014 ERR("No driver selected for device %p.\n", devinfo);
5015 SetLastError(ERROR_NO_DRIVER_SELECTED);
5016 return FALSE;
5019 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
5020 return FALSE;
5022 RegSetValueExW(device->key, L"DeviceDesc", 0, REG_SZ, (BYTE *)driver->description,
5023 wcslen(driver->description) * sizeof(WCHAR));
5025 SetupDiGetActualSectionToInstallW(hinf, driver->section, section_ext, ARRAY_SIZE(section_ext), NULL, &extptr);
5027 if ((l = create_driver_key(device, &driver_key)))
5029 SetLastError(l);
5030 SetupCloseInfFile(hinf);
5031 return FALSE;
5034 if ((l = RegCreateKeyExW(device->key, DeviceParameters, 0, NULL, 0,
5035 KEY_READ | KEY_WRITE, NULL, &device_key, NULL)))
5037 SetLastError(l);
5038 RegCloseKey(driver_key);
5039 SetupCloseInfFile(hinf);
5040 return FALSE;
5043 if (device->params.Flags & DI_NOFILECOPY)
5044 install_flags &= ~SPINST_FILES;
5046 callback_ctx = SetupInitDefaultQueueCallback(NULL);
5048 SetupInstallFromInfSectionW(NULL, hinf, section_ext, install_flags, driver_key, NULL,
5049 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5051 lstrcpyW(subsection, section_ext);
5052 lstrcatW(subsection, dothwW);
5054 SetupInstallFromInfSectionW(NULL, hinf, subsection, install_flags, device_key, NULL,
5055 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5057 lstrcpyW(subsection, section_ext);
5058 lstrcatW(subsection, dotservicesW);
5059 SetupInstallServicesFromInfSectionW(hinf, subsection, 0);
5061 svc_name[0] = 0;
5062 if (SetupFindFirstLineW(hinf, subsection, addserviceW, &ctx))
5066 INT flags;
5068 if (SetupGetIntField(&ctx, 2, &flags) && (flags & SPSVCINST_ASSOCSERVICE))
5070 if (SetupGetStringFieldW(&ctx, 1, svc_name, ARRAY_SIZE(svc_name), NULL) && svc_name[0])
5071 RegSetValueExW(device->key, Service, 0, REG_SZ, (BYTE *)svc_name, lstrlenW(svc_name) * sizeof(WCHAR));
5072 break;
5074 } while (SetupFindNextMatchLineW(&ctx, addserviceW, &ctx));
5077 SetupTermDefaultQueueCallback(callback_ctx);
5078 SetupCloseInfFile(hinf);
5080 SetupCopyOEMInfW(driver->inf_path, NULL, SPOST_NONE, 0, inf_path, ARRAY_SIZE(inf_path), NULL, &filepart);
5081 TRACE("Copied INF file %s to %s.\n", debugstr_w(driver->inf_path), debugstr_w(inf_path));
5083 RegSetValueExW(driver_key, infpathW, 0, REG_SZ, (BYTE *)filepart, lstrlenW(filepart) * sizeof(WCHAR));
5084 RegSetValueExW(driver_key, infsectionW, 0, REG_SZ, (BYTE *)section, lstrlenW(section) * sizeof(WCHAR));
5085 if (extptr)
5086 RegSetValueExW(driver_key, infsectionextW, 0, REG_SZ, (BYTE *)extptr, lstrlenW(extptr) * sizeof(WCHAR));
5088 RegCloseKey(device_key);
5089 RegCloseKey(driver_key);
5091 if (!wcsnicmp(device->instanceId, rootW, lstrlenW(rootW)) && svc_name[0]
5092 && (manager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT)))
5094 if ((service = OpenServiceW(manager, svc_name, SERVICE_START)))
5096 if (!StartServiceW(service, 0, NULL) && GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5098 ERR("Failed to start service %s for device %s, error %u.\n",
5099 debugstr_w(svc_name), debugstr_w(device->instanceId), GetLastError());
5101 CloseServiceHandle(service);
5103 else
5104 ERR("Failed to open service %s for device %s.\n", debugstr_w(svc_name), debugstr_w(device->instanceId));
5105 CloseServiceHandle(manager);
5108 return TRUE;