wined3d: Pass a wined3d_device_context to wined3d_cs_emit_blt_sub_resource().
[wine/zf.git] / dlls / setupapi / devinst.c
blob8f826c302508da096b0bafdac45b14ba920aefbe
1 /*
2 * SetupAPI device installer
4 * Copyright 2000 Andreas Mohr for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdlib.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winnt.h"
27 #include "winreg.h"
28 #include "winternl.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "winnls.h"
32 #include "winsvc.h"
33 #include "setupapi.h"
34 #include "wine/debug.h"
35 #include "wine/heap.h"
36 #include "wine/list.h"
37 #include "cfgmgr32.h"
38 #include "winioctl.h"
39 #include "rpc.h"
40 #include "rpcdce.h"
41 #include "cguid.h"
43 #include "setupapi_private.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
48 /* Unicode constants */
49 static const WCHAR Chicago[] = {'$','C','h','i','c','a','g','o','$',0};
50 static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0};
51 static const WCHAR Class[] = {'C','l','a','s','s',0};
52 static const WCHAR ClassInstall32[] = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
53 static const WCHAR NoDisplayClass[] = {'N','o','D','i','s','p','l','a','y','C','l','a','s','s',0};
54 static const WCHAR NoInstallClass[] = {'N','o','I','n','s','t','a','l','l','C','l','a','s','s',0};
55 static const WCHAR NoUseClass[] = {'N','o','U','s','e','C','l','a','s','s',0};
56 static const WCHAR NtExtension[] = {'.','N','T',0};
57 #ifdef __i386__
58 static const WCHAR NtPlatformExtension[] = {'.','N','T','x','8','6',0};
59 #elif defined(__x86_64__)
60 static const WCHAR NtPlatformExtension[] = {'.','N','T','a','m','d','6','4',0};
61 #elif defined(__arm__)
62 static const WCHAR NtPlatformExtension[] = {'.','N','T','a','r','m',0};
63 #elif defined(__aarch64__)
64 static const WCHAR NtPlatformExtension[] = {'.','N','T','a','r','m','6','4',0};
65 #endif
66 static const WCHAR Signature[] = {'S','i','g','n','a','t','u','r','e',0};
67 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
68 static const WCHAR WinExtension[] = {'.','W','i','n',0};
69 static const WCHAR WindowsNT[] = {'$','W','i','n','d','o','w','s',' ','N','T','$',0};
71 /* Registry key and value names */
72 static const WCHAR ControlClass[] = {'S','y','s','t','e','m','\\',
73 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
74 'C','o','n','t','r','o','l','\\',
75 'C','l','a','s','s',0};
77 static const WCHAR DeviceClasses[] = {'S','y','s','t','e','m','\\',
78 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
79 'C','o','n','t','r','o','l','\\',
80 'D','e','v','i','c','e','C','l','a','s','s','e','s',0};
81 static const WCHAR Enum[] = {'S','y','s','t','e','m','\\',
82 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
83 'E','n','u','m',0};
84 static const WCHAR DeviceDesc[] = {'D','e','v','i','c','e','D','e','s','c',0};
85 static const WCHAR DeviceInstance[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
86 static const WCHAR DeviceParameters[] = {'D','e','v','i','c','e',' ','P','a','r','a','m','e','t','e','r','s',0};
87 static const WCHAR HardwareId[] = {'H','a','r','d','w','a','r','e','I','D',0};
88 static const WCHAR CompatibleIDs[] = {'C','o','m','p','a','t','i','b','l','e','I','d','s',0};
89 static const WCHAR Service[] = {'S','e','r','v','i','c','e',0};
90 static const WCHAR Driver[] = {'D','r','i','v','e','r',0};
91 static const WCHAR ConfigFlags[] = {'C','o','n','f','i','g','F','l','a','g','s',0};
92 static const WCHAR Mfg[] = {'M','f','g',0};
93 static const WCHAR FriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
94 static const WCHAR LocationInformation[] = {'L','o','c','a','t','i','o','n','I','n','f','o','r','m','a','t','i','o','n',0};
95 static const WCHAR Capabilities[] = {'C','a','p','a','b','i','l','i','t','i','e','s',0};
96 static const WCHAR UINumber[] = {'U','I','N','u','m','b','e','r',0};
97 static const WCHAR UpperFilters[] = {'U','p','p','e','r','F','i','l','t','e','r','s',0};
98 static const WCHAR LowerFilters[] = {'L','o','w','e','r','F','i','l','t','e','r','s',0};
99 static const WCHAR Phantom[] = {'P','h','a','n','t','o','m',0};
100 static const WCHAR SymbolicLink[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
101 static const WCHAR Control[] = {'C','o','n','t','r','o','l',0};
102 static const WCHAR Linked[] = {'L','i','n','k','e','d',0};
103 static const WCHAR dotInterfaces[] = {'.','I','n','t','e','r','f','a','c','e','s',0};
104 static const WCHAR AddInterface[] = {'A','d','d','I','n','t','e','r','f','a','c','e',0};
105 static const WCHAR backslashW[] = {'\\',0};
106 static const WCHAR emptyW[] = {0};
108 #define SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES 128
110 struct driver
112 WCHAR inf_path[MAX_PATH];
113 WCHAR manufacturer[LINE_LEN];
114 WCHAR mfg_key[LINE_LEN];
115 WCHAR description[LINE_LEN];
116 WCHAR section[LINE_LEN];
119 /* is used to identify if a DeviceInfoSet pointer is
120 valid or not */
121 #define SETUP_DEVICE_INFO_SET_MAGIC 0xd00ff056
123 struct DeviceInfoSet
125 DWORD magic; /* if is equal to SETUP_DEVICE_INFO_SET_MAGIC struct is okay */
126 GUID ClassGuid;
127 HWND hwndParent;
128 struct list devices;
131 struct device
133 struct DeviceInfoSet *set;
134 HKEY key;
135 BOOL phantom;
136 WCHAR *instanceId;
137 struct list interfaces;
138 GUID class;
139 DEVINST devnode;
140 struct list entry;
141 BOOL removed;
142 SP_DEVINSTALL_PARAMS_W params;
143 struct driver *drivers;
144 unsigned int driver_count;
145 struct driver *selected_driver;
148 struct device_iface
150 WCHAR *refstr;
151 WCHAR *symlink;
152 struct device *device;
153 GUID class;
154 DWORD flags;
155 HKEY class_key;
156 HKEY refstr_key;
157 struct list entry;
160 static struct DeviceInfoSet *get_device_set(HDEVINFO devinfo)
162 struct DeviceInfoSet *set = devinfo;
164 if (!devinfo || devinfo == INVALID_HANDLE_VALUE || set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
166 SetLastError(ERROR_INVALID_HANDLE);
167 return NULL;
170 return set;
173 static struct device *get_device(HDEVINFO devinfo, const SP_DEVINFO_DATA *data)
175 struct DeviceInfoSet *set;
176 struct device *device;
178 if (!(set = get_device_set(devinfo)))
179 return FALSE;
181 if (!data || data->cbSize != sizeof(*data) || !data->Reserved)
183 SetLastError(ERROR_INVALID_PARAMETER);
184 return NULL;
187 device = (struct device *)data->Reserved;
189 if (device->set != set)
191 SetLastError(ERROR_INVALID_PARAMETER);
192 return NULL;
195 if (device->removed)
197 SetLastError(ERROR_NO_SUCH_DEVINST);
198 return NULL;
201 return device;
204 static struct device_iface *get_device_iface(HDEVINFO devinfo, const SP_DEVICE_INTERFACE_DATA *data)
206 if (!get_device_set(devinfo))
207 return FALSE;
209 if (!data || data->cbSize != sizeof(*data) || !data->Reserved)
211 SetLastError(ERROR_INVALID_PARAMETER);
212 return NULL;
215 return (struct device_iface *)data->Reserved;
218 static inline void copy_device_data(SP_DEVINFO_DATA *data, const struct device *device)
220 data->ClassGuid = device->class;
221 data->DevInst = device->devnode;
222 data->Reserved = (ULONG_PTR)device;
225 static inline void copy_device_iface_data(SP_DEVICE_INTERFACE_DATA *data,
226 const struct device_iface *iface)
228 data->InterfaceClassGuid = iface->class;
229 data->Flags = iface->flags;
230 data->Reserved = (ULONG_PTR)iface;
233 static struct device **devnode_table;
234 static unsigned int devnode_table_size;
236 static DEVINST alloc_devnode(struct device *device)
238 unsigned int i;
240 for (i = 0; i < devnode_table_size; ++i)
242 if (!devnode_table[i])
243 break;
246 if (i == devnode_table_size)
248 if (devnode_table)
250 devnode_table_size *= 2;
251 devnode_table = heap_realloc_zero(devnode_table,
252 devnode_table_size * sizeof(*devnode_table));
254 else
256 devnode_table_size = 256;
257 devnode_table = heap_alloc_zero(devnode_table_size * sizeof(*devnode_table));
261 devnode_table[i] = device;
262 return i;
265 static void free_devnode(DEVINST devnode)
267 devnode_table[devnode] = NULL;
270 static struct device *get_devnode_device(DEVINST devnode)
272 if (devnode < devnode_table_size)
273 return devnode_table[devnode];
275 WARN("device node %u not found\n", devnode);
276 return NULL;
279 static void SETUPDI_GuidToString(const GUID *guid, LPWSTR guidStr)
281 static const WCHAR fmt[] = {'{','%','0','8','X','-','%','0','4','X','-',
282 '%','0','4','X','-','%','0','2','X','%','0','2','X','-','%','0','2',
283 'X','%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X','%',
284 '0','2','X','}',0};
286 swprintf(guidStr, 39, fmt, guid->Data1, guid->Data2, guid->Data3,
287 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
288 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
291 static WCHAR *get_iface_key_path(struct device_iface *iface)
293 static const WCHAR slashW[] = {'\\',0};
294 WCHAR *path, *ptr;
295 size_t len = lstrlenW(DeviceClasses) + 1 + 38 + 1 + lstrlenW(iface->symlink);
297 if (!(path = heap_alloc((len + 1) * sizeof(WCHAR))))
299 SetLastError(ERROR_OUTOFMEMORY);
300 return NULL;
303 lstrcpyW(path, DeviceClasses);
304 lstrcatW(path, slashW);
305 SETUPDI_GuidToString(&iface->class, path + lstrlenW(path));
306 lstrcatW(path, slashW);
307 ptr = path + lstrlenW(path);
308 lstrcatW(path, iface->symlink);
309 if (lstrlenW(iface->symlink) > 3)
310 ptr[0] = ptr[1] = ptr[3] = '#';
312 ptr = wcschr(ptr, '\\');
313 if (ptr) *ptr = 0;
315 return path;
318 static WCHAR *get_refstr_key_path(struct device_iface *iface)
320 static const WCHAR hashW[] = {'#',0};
321 static const WCHAR slashW[] = {'\\',0};
322 WCHAR *path, *ptr;
323 size_t len = lstrlenW(DeviceClasses) + 1 + 38 + 1 + lstrlenW(iface->symlink) + 1 + 1;
325 if (iface->refstr)
326 len += lstrlenW(iface->refstr);
328 if (!(path = heap_alloc((len + 1) * sizeof(WCHAR))))
330 SetLastError(ERROR_OUTOFMEMORY);
331 return NULL;
334 lstrcpyW(path, DeviceClasses);
335 lstrcatW(path, slashW);
336 SETUPDI_GuidToString(&iface->class, path + lstrlenW(path));
337 lstrcatW(path, slashW);
338 ptr = path + lstrlenW(path);
339 lstrcatW(path, iface->symlink);
340 if (lstrlenW(iface->symlink) > 3)
341 ptr[0] = ptr[1] = ptr[3] = '#';
343 ptr = wcschr(ptr, '\\');
344 if (ptr) *ptr = 0;
346 lstrcatW(path, slashW);
347 lstrcatW(path, hashW);
349 if (iface->refstr)
350 lstrcatW(path, iface->refstr);
352 return path;
355 static BOOL is_valid_property_type(DEVPROPTYPE prop_type)
357 DWORD type = prop_type & DEVPROP_MASK_TYPE;
358 DWORD typemod = prop_type & DEVPROP_MASK_TYPEMOD;
360 if (type > MAX_DEVPROP_TYPE)
361 return FALSE;
362 if (typemod > MAX_DEVPROP_TYPEMOD)
363 return FALSE;
365 if (typemod == DEVPROP_TYPEMOD_ARRAY
366 && (type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL || type == DEVPROP_TYPE_STRING
367 || type == DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING))
368 return FALSE;
370 if (typemod == DEVPROP_TYPEMOD_LIST
371 && !(type == DEVPROP_TYPE_STRING || type == DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING))
372 return FALSE;
374 return TRUE;
377 static LPWSTR SETUPDI_CreateSymbolicLinkPath(LPCWSTR instanceId,
378 const GUID *InterfaceClassGuid, LPCWSTR ReferenceString)
380 static const WCHAR fmt[] = {'\\','\\','?','\\','%','s','#','%','s',0};
381 WCHAR guidStr[39];
382 DWORD len;
383 LPWSTR ret;
385 SETUPDI_GuidToString(InterfaceClassGuid, guidStr);
386 /* omit length of format specifiers, but include NULL terminator: */
387 len = lstrlenW(fmt) - 4 + 1;
388 len += lstrlenW(instanceId) + lstrlenW(guidStr);
389 if (ReferenceString && *ReferenceString)
391 /* space for a hash between string and reference string: */
392 len += lstrlenW(ReferenceString) + 1;
394 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
395 if (ret)
397 int printed = swprintf(ret, len, fmt, instanceId, guidStr);
398 LPWSTR ptr;
400 /* replace '\\' with '#' after the "\\\\?\\" beginning */
401 for (ptr = wcschr(ret + 4, '\\'); ptr; ptr = wcschr(ptr + 1, '\\'))
402 *ptr = '#';
403 if (ReferenceString && *ReferenceString)
405 ret[printed] = '\\';
406 lstrcpyW(ret + printed + 1, ReferenceString);
409 return ret;
412 static BOOL is_linked(HKEY key)
414 DWORD linked, type, size;
415 HKEY control_key;
416 BOOL ret = FALSE;
418 if (!RegOpenKeyW(key, Control, &control_key))
420 size = sizeof(DWORD);
421 if (!RegQueryValueExW(control_key, Linked, NULL, &type, (BYTE *)&linked, &size)
422 && type == REG_DWORD && linked)
423 ret = TRUE;
425 RegCloseKey(control_key);
428 return ret;
431 static struct device_iface *SETUPDI_CreateDeviceInterface(struct device *device,
432 const GUID *class, const WCHAR *refstr)
434 struct device_iface *iface = NULL;
435 WCHAR *refstr2 = NULL, *symlink = NULL, *path = NULL;
436 HKEY key;
437 LONG ret;
439 TRACE("%p %s %s\n", device, debugstr_guid(class), debugstr_w(refstr));
441 /* check if it already exists */
442 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
444 if (IsEqualGUID(&iface->class, class) && !lstrcmpiW(iface->refstr, refstr))
445 return iface;
448 iface = heap_alloc(sizeof(*iface));
449 symlink = SETUPDI_CreateSymbolicLinkPath(device->instanceId, class, refstr);
451 if (!iface || !symlink)
453 SetLastError(ERROR_OUTOFMEMORY);
454 goto err;
457 if (refstr && !(refstr2 = strdupW(refstr)))
459 SetLastError(ERROR_OUTOFMEMORY);
460 goto err;
462 iface->refstr = refstr2;
463 iface->symlink = symlink;
464 iface->device = device;
465 iface->class = *class;
466 iface->flags = 0;
468 if (!(path = get_iface_key_path(iface)))
470 SetLastError(ERROR_OUTOFMEMORY);
471 goto err;
474 if ((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, path, &key)))
476 SetLastError(ret);
477 goto err;
479 RegSetValueExW(key, DeviceInstance, 0, REG_SZ, (BYTE *)device->instanceId,
480 lstrlenW(device->instanceId) * sizeof(WCHAR));
481 heap_free(path);
483 iface->class_key = key;
485 if (!(path = get_refstr_key_path(iface)))
487 SetLastError(ERROR_OUTOFMEMORY);
488 goto err;
491 if ((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, path, &key)))
493 SetLastError(ret);
494 goto err;
496 RegSetValueExW(key, SymbolicLink, 0, REG_SZ, (BYTE *)iface->symlink,
497 lstrlenW(iface->symlink) * sizeof(WCHAR));
499 if (is_linked(key))
500 iface->flags |= SPINT_ACTIVE;
502 heap_free(path);
504 iface->refstr_key = key;
506 list_add_tail(&device->interfaces, &iface->entry);
507 return iface;
509 err:
510 heap_free(iface);
511 heap_free(refstr2);
512 heap_free(symlink);
513 heap_free(path);
514 return NULL;
517 static BOOL SETUPDI_SetInterfaceSymbolicLink(struct device_iface *iface,
518 const WCHAR *symlink)
520 heap_free(iface->symlink);
521 if ((iface->symlink = strdupW(symlink)))
522 return TRUE;
523 return FALSE;
526 static HKEY SETUPDI_CreateDevKey(struct device *device)
528 HKEY enumKey, key = INVALID_HANDLE_VALUE;
529 LONG l;
531 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_ALL_ACCESS,
532 NULL, &enumKey, NULL);
533 if (!l)
535 RegCreateKeyExW(enumKey, device->instanceId, 0, NULL, 0,
536 KEY_READ | KEY_WRITE, NULL, &key, NULL);
537 RegCloseKey(enumKey);
539 return key;
542 static LONG open_driver_key(struct device *device, REGSAM access, HKEY *key)
544 HKEY class_key;
545 WCHAR path[50];
546 DWORD size = sizeof(path);
547 LONG l;
549 if ((l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, ControlClass, 0, NULL, 0,
550 KEY_CREATE_SUB_KEY, NULL, &class_key, NULL)))
552 ERR("Failed to open driver class root key, error %u.\n", l);
553 return l;
556 if (!(l = RegGetValueW(device->key, NULL, Driver, RRF_RT_REG_SZ, NULL, path, &size)))
558 if (!(l = RegOpenKeyExW(class_key, path, 0, access, key)))
560 RegCloseKey(class_key);
561 return l;
563 ERR("Failed to open driver key, error %u.\n", l);
566 RegCloseKey(class_key);
567 return l;
570 static LONG create_driver_key(struct device *device, HKEY *key)
572 static const WCHAR formatW[] = {'%','0','4','u',0};
573 static const WCHAR slash[] = { '\\',0 };
574 unsigned int i = 0;
575 WCHAR path[50];
576 HKEY class_key;
577 DWORD dispos;
578 LONG l;
580 if (!open_driver_key(device, KEY_READ | KEY_WRITE, key))
581 return ERROR_SUCCESS;
583 if ((l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, ControlClass, 0, NULL, 0,
584 KEY_CREATE_SUB_KEY, NULL, &class_key, NULL)))
586 ERR("Failed to open driver class root key, error %u.\n", l);
587 return l;
590 SETUPDI_GuidToString(&device->class, path);
591 lstrcatW(path, slash);
592 /* Allocate a new driver key, by finding the first integer value that's not
593 * already taken. */
594 for (;;)
596 swprintf(path + 39, ARRAY_SIZE(path) - 39, formatW, i++);
597 if ((l = RegCreateKeyExW(class_key, path, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, key, &dispos)))
598 break;
599 else if (dispos == REG_CREATED_NEW_KEY)
601 RegSetValueExW(device->key, Driver, 0, REG_SZ, (BYTE *)path, lstrlenW(path) * sizeof(WCHAR));
602 RegCloseKey(class_key);
603 return ERROR_SUCCESS;
605 RegCloseKey(*key);
607 ERR("Failed to create driver key, error %u.\n", l);
608 RegCloseKey(class_key);
609 return l;
612 static LONG delete_driver_key(struct device *device)
614 HKEY key;
615 LONG l;
617 if (!(l = open_driver_key(device, KEY_READ | KEY_WRITE, &key)))
619 l = RegDeleteKeyW(key, emptyW);
620 RegCloseKey(key);
623 return l;
626 struct PropertyMapEntry
628 DWORD regType;
629 LPCSTR nameA;
630 LPCWSTR nameW;
633 static const struct PropertyMapEntry PropertyMap[] = {
634 { REG_SZ, "DeviceDesc", DeviceDesc },
635 { REG_MULTI_SZ, "HardwareId", HardwareId },
636 { REG_MULTI_SZ, "CompatibleIDs", CompatibleIDs },
637 { 0, NULL, NULL }, /* SPDRP_UNUSED0 */
638 { REG_SZ, "Service", Service },
639 { 0, NULL, NULL }, /* SPDRP_UNUSED1 */
640 { 0, NULL, NULL }, /* SPDRP_UNUSED2 */
641 { REG_SZ, "Class", Class },
642 { REG_SZ, "ClassGUID", ClassGUID },
643 { REG_SZ, "Driver", Driver },
644 { REG_DWORD, "ConfigFlags", ConfigFlags },
645 { REG_SZ, "Mfg", Mfg },
646 { REG_SZ, "FriendlyName", FriendlyName },
647 { REG_SZ, "LocationInformation", LocationInformation },
648 { 0, NULL, NULL }, /* SPDRP_PHYSICAL_DEVICE_OBJECT_NAME */
649 { REG_DWORD, "Capabilities", Capabilities },
650 { REG_DWORD, "UINumber", UINumber },
651 { REG_MULTI_SZ, "UpperFilters", UpperFilters },
652 { REG_MULTI_SZ, "LowerFilters", LowerFilters },
655 static BOOL SETUPDI_SetDeviceRegistryPropertyW(struct device *device,
656 DWORD prop, const BYTE *buffer, DWORD size)
658 if (prop < ARRAY_SIZE(PropertyMap) && PropertyMap[prop].nameW)
660 LONG ret = RegSetValueExW(device->key, PropertyMap[prop].nameW, 0,
661 PropertyMap[prop].regType, buffer, size);
662 if (!ret)
663 return TRUE;
665 SetLastError(ret);
667 return FALSE;
670 static void remove_device_iface(struct device_iface *iface)
672 RegDeleteTreeW(iface->refstr_key, NULL);
673 RegDeleteKeyW(iface->refstr_key, emptyW);
674 RegCloseKey(iface->refstr_key);
675 iface->refstr_key = NULL;
676 /* Also remove the class key if it's empty. */
677 RegDeleteKeyW(iface->class_key, emptyW);
678 RegCloseKey(iface->class_key);
679 iface->class_key = NULL;
680 iface->flags |= SPINT_REMOVED;
683 static void delete_device_iface(struct device_iface *iface)
685 list_remove(&iface->entry);
686 RegCloseKey(iface->refstr_key);
687 RegCloseKey(iface->class_key);
688 heap_free(iface->refstr);
689 heap_free(iface->symlink);
690 heap_free(iface);
693 static void remove_device(struct device *device)
695 WCHAR id[MAX_DEVICE_ID_LEN], *p;
696 struct device_iface *iface;
697 HKEY enum_key;
699 delete_driver_key(device);
701 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
703 remove_device_iface(iface);
706 RegDeleteTreeW(device->key, NULL);
707 RegDeleteKeyW(device->key, emptyW);
709 /* delete all empty parents of the key */
710 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, 0, &enum_key))
712 lstrcpyW(id, device->instanceId);
714 while ((p = wcsrchr(id, '\\')))
716 *p = 0;
717 RegDeleteKeyW(enum_key, id);
720 RegCloseKey(enum_key);
723 RegCloseKey(device->key);
724 device->key = NULL;
725 device->removed = TRUE;
728 static void delete_device(struct device *device)
730 struct device_iface *iface, *next;
731 SP_DEVINFO_DATA device_data;
733 device_data.cbSize = sizeof(device_data);
734 copy_device_data(&device_data, device);
735 SetupDiCallClassInstaller(DIF_DESTROYPRIVATEDATA, device->set, &device_data);
737 if (device->phantom)
738 remove_device(device);
740 RegCloseKey(device->key);
741 heap_free(device->instanceId);
742 heap_free(device->drivers);
744 LIST_FOR_EACH_ENTRY_SAFE(iface, next, &device->interfaces,
745 struct device_iface, entry)
747 delete_device_iface(iface);
749 free_devnode(device->devnode);
750 list_remove(&device->entry);
751 heap_free(device);
754 /* Create a new device, or return a device already in the set. */
755 static struct device *create_device(struct DeviceInfoSet *set,
756 const GUID *class, const WCHAR *instanceid, BOOL phantom)
758 const DWORD one = 1;
759 struct device *device;
760 WCHAR guidstr[MAX_GUID_STRING_LEN];
761 WCHAR class_name[MAX_CLASS_NAME_LEN];
762 DWORD size;
764 TRACE("%p, %s, %s, %d\n", set, debugstr_guid(class),
765 debugstr_w(instanceid), phantom);
767 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
769 if (!wcsicmp(instanceid, device->instanceId))
771 TRACE("Found device %p already in set.\n", device);
772 return device;
776 if (!(device = heap_alloc_zero(sizeof(*device))))
778 SetLastError(ERROR_OUTOFMEMORY);
779 return NULL;
782 if (!(device->instanceId = strdupW(instanceid)))
784 SetLastError(ERROR_OUTOFMEMORY);
785 heap_free(device);
786 return NULL;
789 wcsupr(device->instanceId);
790 device->set = set;
791 device->key = SETUPDI_CreateDevKey(device);
792 device->phantom = phantom;
793 list_init(&device->interfaces);
794 device->class = *class;
795 device->devnode = alloc_devnode(device);
796 device->removed = FALSE;
797 list_add_tail(&set->devices, &device->entry);
798 device->params.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
800 if (phantom)
801 RegSetValueExW(device->key, Phantom, 0, REG_DWORD, (const BYTE *)&one, sizeof(one));
803 SETUPDI_GuidToString(class, guidstr);
804 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_CLASSGUID,
805 (const BYTE *)guidstr, sizeof(guidstr));
807 if (SetupDiClassNameFromGuidW(class, class_name, ARRAY_SIZE(class_name), NULL))
809 size = (lstrlenW(class_name) + 1) * sizeof(WCHAR);
810 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_CLASS, (const BYTE *)class_name, size);
813 TRACE("Created new device %p.\n", device);
814 return device;
817 /***********************************************************************
818 * SetupDiBuildClassInfoList (SETUPAPI.@)
820 * Returns a list of setup class GUIDs that identify the classes
821 * that are installed on a local machine.
823 * PARAMS
824 * Flags [I] control exclusion of classes from the list.
825 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
826 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
827 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
829 * RETURNS
830 * Success: TRUE.
831 * Failure: FALSE.
833 BOOL WINAPI SetupDiBuildClassInfoList(
834 DWORD Flags,
835 LPGUID ClassGuidList,
836 DWORD ClassGuidListSize,
837 PDWORD RequiredSize)
839 TRACE("\n");
840 return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
841 ClassGuidListSize, RequiredSize,
842 NULL, NULL);
845 /***********************************************************************
846 * SetupDiBuildClassInfoListExA (SETUPAPI.@)
848 * Returns a list of setup class GUIDs that identify the classes
849 * that are installed on a local or remote machine.
851 * PARAMS
852 * Flags [I] control exclusion of classes from the list.
853 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
854 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
855 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
856 * MachineName [I] name of a remote machine.
857 * Reserved [I] must be NULL.
859 * RETURNS
860 * Success: TRUE.
861 * Failure: FALSE.
863 BOOL WINAPI SetupDiBuildClassInfoListExA(
864 DWORD Flags,
865 LPGUID ClassGuidList,
866 DWORD ClassGuidListSize,
867 PDWORD RequiredSize,
868 LPCSTR MachineName,
869 PVOID Reserved)
871 LPWSTR MachineNameW = NULL;
872 BOOL bResult;
874 TRACE("\n");
876 if (MachineName)
878 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
879 if (MachineNameW == NULL) return FALSE;
882 bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
883 ClassGuidListSize, RequiredSize,
884 MachineNameW, Reserved);
886 MyFree(MachineNameW);
888 return bResult;
891 /***********************************************************************
892 * SetupDiBuildClassInfoListExW (SETUPAPI.@)
894 * Returns a list of setup class GUIDs that identify the classes
895 * that are installed on a local or remote machine.
897 * PARAMS
898 * Flags [I] control exclusion of classes from the list.
899 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
900 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
901 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
902 * MachineName [I] name of a remote machine.
903 * Reserved [I] must be NULL.
905 * RETURNS
906 * Success: TRUE.
907 * Failure: FALSE.
909 BOOL WINAPI SetupDiBuildClassInfoListExW(
910 DWORD Flags,
911 LPGUID ClassGuidList,
912 DWORD ClassGuidListSize,
913 PDWORD RequiredSize,
914 LPCWSTR MachineName,
915 PVOID Reserved)
917 WCHAR szKeyName[40];
918 HKEY hClassesKey;
919 HKEY hClassKey;
920 DWORD dwLength;
921 DWORD dwIndex;
922 LONG lError;
923 DWORD dwGuidListIndex = 0;
925 TRACE("\n");
927 if (RequiredSize != NULL)
928 *RequiredSize = 0;
930 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
931 KEY_ALL_ACCESS,
932 DIOCR_INSTALLER,
933 MachineName,
934 Reserved);
935 if (hClassesKey == INVALID_HANDLE_VALUE)
937 return FALSE;
940 for (dwIndex = 0; ; dwIndex++)
942 dwLength = 40;
943 lError = RegEnumKeyExW(hClassesKey,
944 dwIndex,
945 szKeyName,
946 &dwLength,
947 NULL,
948 NULL,
949 NULL,
950 NULL);
951 TRACE("RegEnumKeyExW() returns %d\n", lError);
952 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
954 TRACE("Key name: %p\n", szKeyName);
956 if (RegOpenKeyExW(hClassesKey,
957 szKeyName,
959 KEY_ALL_ACCESS,
960 &hClassKey))
962 RegCloseKey(hClassesKey);
963 return FALSE;
966 if (!RegQueryValueExW(hClassKey,
967 NoUseClass,
968 NULL,
969 NULL,
970 NULL,
971 NULL))
973 TRACE("'NoUseClass' value found!\n");
974 RegCloseKey(hClassKey);
975 continue;
978 if ((Flags & DIBCI_NOINSTALLCLASS) &&
979 (!RegQueryValueExW(hClassKey,
980 NoInstallClass,
981 NULL,
982 NULL,
983 NULL,
984 NULL)))
986 TRACE("'NoInstallClass' value found!\n");
987 RegCloseKey(hClassKey);
988 continue;
991 if ((Flags & DIBCI_NODISPLAYCLASS) &&
992 (!RegQueryValueExW(hClassKey,
993 NoDisplayClass,
994 NULL,
995 NULL,
996 NULL,
997 NULL)))
999 TRACE("'NoDisplayClass' value found!\n");
1000 RegCloseKey(hClassKey);
1001 continue;
1004 RegCloseKey(hClassKey);
1006 TRACE("Guid: %p\n", szKeyName);
1007 if (dwGuidListIndex < ClassGuidListSize)
1009 if (szKeyName[0] == '{' && szKeyName[37] == '}')
1011 szKeyName[37] = 0;
1013 TRACE("Guid: %p\n", &szKeyName[1]);
1015 UuidFromStringW(&szKeyName[1],
1016 &ClassGuidList[dwGuidListIndex]);
1019 dwGuidListIndex++;
1022 if (lError != ERROR_SUCCESS)
1023 break;
1026 RegCloseKey(hClassesKey);
1028 if (RequiredSize != NULL)
1029 *RequiredSize = dwGuidListIndex;
1031 if (ClassGuidListSize < dwGuidListIndex)
1033 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1034 return FALSE;
1037 return TRUE;
1040 /***********************************************************************
1041 * SetupDiClassGuidsFromNameA (SETUPAPI.@)
1043 BOOL WINAPI SetupDiClassGuidsFromNameA(
1044 LPCSTR ClassName,
1045 LPGUID ClassGuidList,
1046 DWORD ClassGuidListSize,
1047 PDWORD RequiredSize)
1049 return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
1050 ClassGuidListSize, RequiredSize,
1051 NULL, NULL);
1054 /***********************************************************************
1055 * SetupDiClassGuidsFromNameW (SETUPAPI.@)
1057 BOOL WINAPI SetupDiClassGuidsFromNameW(
1058 LPCWSTR ClassName,
1059 LPGUID ClassGuidList,
1060 DWORD ClassGuidListSize,
1061 PDWORD RequiredSize)
1063 return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
1064 ClassGuidListSize, RequiredSize,
1065 NULL, NULL);
1068 /***********************************************************************
1069 * SetupDiClassGuidsFromNameExA (SETUPAPI.@)
1071 BOOL WINAPI SetupDiClassGuidsFromNameExA(
1072 LPCSTR ClassName,
1073 LPGUID ClassGuidList,
1074 DWORD ClassGuidListSize,
1075 PDWORD RequiredSize,
1076 LPCSTR MachineName,
1077 PVOID Reserved)
1079 LPWSTR ClassNameW = NULL;
1080 LPWSTR MachineNameW = NULL;
1081 BOOL bResult;
1083 ClassNameW = MultiByteToUnicode(ClassName, CP_ACP);
1084 if (ClassNameW == NULL)
1085 return FALSE;
1087 if (MachineName)
1089 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1090 if (MachineNameW == NULL)
1092 MyFree(ClassNameW);
1093 return FALSE;
1097 bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
1098 ClassGuidListSize, RequiredSize,
1099 MachineNameW, Reserved);
1101 MyFree(MachineNameW);
1102 MyFree(ClassNameW);
1104 return bResult;
1107 /***********************************************************************
1108 * SetupDiClassGuidsFromNameExW (SETUPAPI.@)
1110 BOOL WINAPI SetupDiClassGuidsFromNameExW(
1111 LPCWSTR ClassName,
1112 LPGUID ClassGuidList,
1113 DWORD ClassGuidListSize,
1114 PDWORD RequiredSize,
1115 LPCWSTR MachineName,
1116 PVOID Reserved)
1118 WCHAR szKeyName[40];
1119 WCHAR szClassName[256];
1120 HKEY hClassesKey;
1121 HKEY hClassKey;
1122 DWORD dwLength;
1123 DWORD dwIndex;
1124 LONG lError;
1125 DWORD dwGuidListIndex = 0;
1127 if (RequiredSize != NULL)
1128 *RequiredSize = 0;
1130 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
1131 KEY_ALL_ACCESS,
1132 DIOCR_INSTALLER,
1133 MachineName,
1134 Reserved);
1135 if (hClassesKey == INVALID_HANDLE_VALUE)
1137 return FALSE;
1140 for (dwIndex = 0; ; dwIndex++)
1142 dwLength = ARRAY_SIZE(szKeyName);
1143 lError = RegEnumKeyExW(hClassesKey,
1144 dwIndex,
1145 szKeyName,
1146 &dwLength,
1147 NULL,
1148 NULL,
1149 NULL,
1150 NULL);
1151 TRACE("RegEnumKeyExW() returns %d\n", lError);
1152 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
1154 TRACE("Key name: %p\n", szKeyName);
1156 if (RegOpenKeyExW(hClassesKey,
1157 szKeyName,
1159 KEY_ALL_ACCESS,
1160 &hClassKey))
1162 RegCloseKey(hClassesKey);
1163 return FALSE;
1166 dwLength = sizeof(szClassName);
1167 if (!RegQueryValueExW(hClassKey,
1168 Class,
1169 NULL,
1170 NULL,
1171 (LPBYTE)szClassName,
1172 &dwLength))
1174 TRACE("Class name: %p\n", szClassName);
1176 if (wcsicmp(szClassName, ClassName) == 0)
1178 TRACE("Found matching class name\n");
1180 TRACE("Guid: %p\n", szKeyName);
1181 if (dwGuidListIndex < ClassGuidListSize)
1183 if (szKeyName[0] == '{' && szKeyName[37] == '}')
1185 szKeyName[37] = 0;
1187 TRACE("Guid: %p\n", &szKeyName[1]);
1189 UuidFromStringW(&szKeyName[1],
1190 &ClassGuidList[dwGuidListIndex]);
1193 dwGuidListIndex++;
1197 RegCloseKey(hClassKey);
1200 if (lError != ERROR_SUCCESS)
1201 break;
1204 RegCloseKey(hClassesKey);
1206 if (RequiredSize != NULL)
1207 *RequiredSize = dwGuidListIndex;
1209 if (ClassGuidListSize < dwGuidListIndex)
1211 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1212 return FALSE;
1215 return TRUE;
1218 /***********************************************************************
1219 * SetupDiClassNameFromGuidA (SETUPAPI.@)
1221 BOOL WINAPI SetupDiClassNameFromGuidA(
1222 const GUID* ClassGuid,
1223 PSTR ClassName,
1224 DWORD ClassNameSize,
1225 PDWORD RequiredSize)
1227 return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
1228 ClassNameSize, RequiredSize,
1229 NULL, NULL);
1232 /***********************************************************************
1233 * SetupDiClassNameFromGuidW (SETUPAPI.@)
1235 BOOL WINAPI SetupDiClassNameFromGuidW(
1236 const GUID* ClassGuid,
1237 PWSTR ClassName,
1238 DWORD ClassNameSize,
1239 PDWORD RequiredSize)
1241 return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
1242 ClassNameSize, RequiredSize,
1243 NULL, NULL);
1246 /***********************************************************************
1247 * SetupDiClassNameFromGuidExA (SETUPAPI.@)
1249 BOOL WINAPI SetupDiClassNameFromGuidExA(
1250 const GUID* ClassGuid,
1251 PSTR ClassName,
1252 DWORD ClassNameSize,
1253 PDWORD RequiredSize,
1254 PCSTR MachineName,
1255 PVOID Reserved)
1257 WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
1258 LPWSTR MachineNameW = NULL;
1259 BOOL ret;
1261 if (MachineName)
1262 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1263 ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
1264 NULL, MachineNameW, Reserved);
1265 if (ret)
1267 int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
1268 ClassNameSize, NULL, NULL);
1270 if (!ClassNameSize && RequiredSize)
1271 *RequiredSize = len;
1273 MyFree(MachineNameW);
1274 return ret;
1277 /***********************************************************************
1278 * SetupDiClassNameFromGuidExW (SETUPAPI.@)
1280 BOOL WINAPI SetupDiClassNameFromGuidExW(
1281 const GUID* ClassGuid,
1282 PWSTR ClassName,
1283 DWORD ClassNameSize,
1284 PDWORD RequiredSize,
1285 PCWSTR MachineName,
1286 PVOID Reserved)
1288 HKEY hKey;
1289 DWORD dwLength;
1291 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
1292 KEY_ALL_ACCESS,
1293 DIOCR_INSTALLER,
1294 MachineName,
1295 Reserved);
1296 if (hKey == INVALID_HANDLE_VALUE)
1298 return FALSE;
1301 if (RequiredSize != NULL)
1303 dwLength = 0;
1304 if (RegQueryValueExW(hKey,
1305 Class,
1306 NULL,
1307 NULL,
1308 NULL,
1309 &dwLength))
1311 RegCloseKey(hKey);
1312 return FALSE;
1315 *RequiredSize = dwLength / sizeof(WCHAR);
1318 dwLength = ClassNameSize * sizeof(WCHAR);
1319 if (RegQueryValueExW(hKey,
1320 Class,
1321 NULL,
1322 NULL,
1323 (LPBYTE)ClassName,
1324 &dwLength))
1326 RegCloseKey(hKey);
1327 return FALSE;
1330 RegCloseKey(hKey);
1332 return TRUE;
1335 /***********************************************************************
1336 * SetupDiCreateDeviceInfoList (SETUPAPI.@)
1338 HDEVINFO WINAPI
1339 SetupDiCreateDeviceInfoList(const GUID *ClassGuid,
1340 HWND hwndParent)
1342 return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
1345 /***********************************************************************
1346 * SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
1348 HDEVINFO WINAPI
1349 SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
1350 HWND hwndParent,
1351 PCSTR MachineName,
1352 PVOID Reserved)
1354 LPWSTR MachineNameW = NULL;
1355 HDEVINFO hDevInfo;
1357 TRACE("\n");
1359 if (MachineName)
1361 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1362 if (MachineNameW == NULL)
1363 return INVALID_HANDLE_VALUE;
1366 hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
1367 MachineNameW, Reserved);
1369 MyFree(MachineNameW);
1371 return hDevInfo;
1374 /***********************************************************************
1375 * SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
1377 * Create an empty DeviceInfoSet list.
1379 * PARAMS
1380 * ClassGuid [I] if not NULL only devices with GUID ClassGuid are associated
1381 * with this list.
1382 * hwndParent [I] hwnd needed for interface related actions.
1383 * MachineName [I] name of machine to create empty DeviceInfoSet list, if NULL
1384 * local registry will be used.
1385 * Reserved [I] must be NULL
1387 * RETURNS
1388 * Success: empty list.
1389 * Failure: INVALID_HANDLE_VALUE.
1391 HDEVINFO WINAPI
1392 SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
1393 HWND hwndParent,
1394 PCWSTR MachineName,
1395 PVOID Reserved)
1397 struct DeviceInfoSet *list = NULL;
1398 DWORD size = sizeof(struct DeviceInfoSet);
1400 TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
1401 debugstr_w(MachineName), Reserved);
1403 if (MachineName && *MachineName)
1405 FIXME("remote support is not implemented\n");
1406 SetLastError(ERROR_INVALID_MACHINENAME);
1407 return INVALID_HANDLE_VALUE;
1410 if (Reserved != NULL)
1412 SetLastError(ERROR_INVALID_PARAMETER);
1413 return INVALID_HANDLE_VALUE;
1416 list = HeapAlloc(GetProcessHeap(), 0, size);
1417 if (!list)
1419 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1420 return INVALID_HANDLE_VALUE;
1423 list->magic = SETUP_DEVICE_INFO_SET_MAGIC;
1424 list->hwndParent = hwndParent;
1425 memcpy(&list->ClassGuid,
1426 ClassGuid ? ClassGuid : &GUID_NULL,
1427 sizeof(list->ClassGuid));
1428 list_init(&list->devices);
1430 return list;
1433 /***********************************************************************
1434 * SetupDiCreateDevRegKeyA (SETUPAPI.@)
1436 HKEY WINAPI SetupDiCreateDevRegKeyA(
1437 HDEVINFO DeviceInfoSet,
1438 PSP_DEVINFO_DATA DeviceInfoData,
1439 DWORD Scope,
1440 DWORD HwProfile,
1441 DWORD KeyType,
1442 HINF InfHandle,
1443 PCSTR InfSectionName)
1445 PWSTR InfSectionNameW = NULL;
1446 HKEY key;
1448 TRACE("%p %p %d %d %d %p %s\n", DeviceInfoSet, DeviceInfoData, Scope,
1449 HwProfile, KeyType, InfHandle, debugstr_a(InfSectionName));
1451 if (InfHandle)
1453 if (!InfSectionName)
1455 SetLastError(ERROR_INVALID_PARAMETER);
1456 return INVALID_HANDLE_VALUE;
1458 else
1460 InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
1461 if (InfSectionNameW == NULL) return INVALID_HANDLE_VALUE;
1464 key = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, Scope,
1465 HwProfile, KeyType, InfHandle, InfSectionNameW);
1466 MyFree(InfSectionNameW);
1467 return key;
1470 /***********************************************************************
1471 * SetupDiCreateDevRegKeyW (SETUPAPI.@)
1473 HKEY WINAPI SetupDiCreateDevRegKeyW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD Scope,
1474 DWORD HwProfile, DWORD KeyType, HINF InfHandle, const WCHAR *InfSectionName)
1476 struct device *device;
1477 HKEY key = INVALID_HANDLE_VALUE;
1478 LONG l;
1480 TRACE("devinfo %p, device_data %p, scope %d, profile %d, type %d, inf_handle %p, inf_section %s.\n",
1481 devinfo, device_data, Scope, HwProfile, KeyType, InfHandle, debugstr_w(InfSectionName));
1483 if (!(device = get_device(devinfo, device_data)))
1484 return INVALID_HANDLE_VALUE;
1486 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
1488 SetLastError(ERROR_INVALID_FLAGS);
1489 return INVALID_HANDLE_VALUE;
1491 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
1493 SetLastError(ERROR_INVALID_FLAGS);
1494 return INVALID_HANDLE_VALUE;
1496 if (device->phantom)
1498 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
1499 return INVALID_HANDLE_VALUE;
1501 if (Scope != DICS_FLAG_GLOBAL)
1502 FIXME("unimplemented for scope %d\n", Scope);
1503 switch (KeyType)
1505 case DIREG_DEV:
1506 l = RegCreateKeyExW(device->key, DeviceParameters, 0, NULL, 0,
1507 KEY_READ | KEY_WRITE, NULL, &key, NULL);
1508 break;
1509 case DIREG_DRV:
1510 l = create_driver_key(device, &key);
1511 break;
1512 default:
1513 FIXME("Unhandled type %#x.\n", KeyType);
1514 l = ERROR_CALL_NOT_IMPLEMENTED;
1516 if (InfHandle)
1517 SetupInstallFromInfSectionW(NULL, InfHandle, InfSectionName, SPINST_ALL,
1518 NULL, NULL, SP_COPY_NEWER_ONLY, NULL, NULL, devinfo, device_data);
1519 SetLastError(l);
1520 return l ? INVALID_HANDLE_VALUE : key;
1523 /***********************************************************************
1524 * SetupDiCreateDeviceInfoA (SETUPAPI.@)
1526 BOOL WINAPI SetupDiCreateDeviceInfoA(HDEVINFO DeviceInfoSet, const char *name,
1527 const GUID *ClassGuid, PCSTR DeviceDescription, HWND hwndParent, DWORD CreationFlags,
1528 PSP_DEVINFO_DATA DeviceInfoData)
1530 WCHAR nameW[MAX_DEVICE_ID_LEN];
1531 BOOL ret = FALSE;
1532 LPWSTR DeviceDescriptionW = NULL;
1534 if (!name || strlen(name) >= MAX_DEVICE_ID_LEN)
1536 SetLastError(ERROR_INVALID_DEVINST_NAME);
1537 return FALSE;
1540 MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, ARRAY_SIZE(nameW));
1542 if (DeviceDescription)
1544 DeviceDescriptionW = MultiByteToUnicode(DeviceDescription, CP_ACP);
1545 if (DeviceDescriptionW == NULL)
1546 return FALSE;
1549 ret = SetupDiCreateDeviceInfoW(DeviceInfoSet, nameW, ClassGuid, DeviceDescriptionW,
1550 hwndParent, CreationFlags, DeviceInfoData);
1552 MyFree(DeviceDescriptionW);
1554 return ret;
1557 /***********************************************************************
1558 * SetupDiCreateDeviceInfoW (SETUPAPI.@)
1560 BOOL WINAPI SetupDiCreateDeviceInfoW(HDEVINFO devinfo, const WCHAR *name, const GUID *class,
1561 const WCHAR *description, HWND parent, DWORD flags, SP_DEVINFO_DATA *device_data)
1563 WCHAR id[MAX_DEVICE_ID_LEN];
1564 struct DeviceInfoSet *set;
1565 HKEY enum_hkey;
1566 HKEY instance_hkey;
1567 struct device *device;
1568 LONG l;
1570 TRACE("devinfo %p, name %s, class %s, description %s, hwnd %p, flags %#x, device_data %p.\n",
1571 devinfo, debugstr_w(name), debugstr_guid(class), debugstr_w(description),
1572 parent, flags, device_data);
1574 if (!name || lstrlenW(name) >= MAX_DEVICE_ID_LEN)
1576 SetLastError(ERROR_INVALID_DEVINST_NAME);
1577 return FALSE;
1580 if (!(set = get_device_set(devinfo)))
1581 return FALSE;
1583 if (!class)
1585 SetLastError(ERROR_INVALID_PARAMETER);
1586 return FALSE;
1589 if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) && !IsEqualGUID(class, &set->ClassGuid))
1591 SetLastError(ERROR_CLASS_MISMATCH);
1592 return FALSE;
1594 if ((flags & DICD_GENERATE_ID))
1596 static const WCHAR formatW[] = {'R','O','O','T','\\','%','s','\\','%','0','4','u',0};
1597 unsigned int instance_id;
1599 if (wcschr(name, '\\'))
1601 SetLastError(ERROR_INVALID_DEVINST_NAME);
1602 return FALSE;
1605 for (instance_id = 0; ; ++instance_id)
1607 if (swprintf(id, ARRAY_SIZE(id), formatW, name, instance_id) == -1)
1609 SetLastError(ERROR_INVALID_DEVINST_NAME);
1610 return FALSE;
1613 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL, &enum_hkey, NULL);
1614 if (!(l = RegOpenKeyExW(enum_hkey, id, 0, KEY_READ, &instance_hkey)))
1615 RegCloseKey(instance_hkey);
1616 if (l == ERROR_FILE_NOT_FOUND)
1617 break;
1618 RegCloseKey(enum_hkey);
1621 else
1623 /* Check if instance is already in registry */
1624 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL, &enum_hkey, NULL);
1625 if (!RegOpenKeyExW(enum_hkey, name, 0, KEY_READ, &instance_hkey))
1627 RegCloseKey(instance_hkey);
1628 RegCloseKey(enum_hkey);
1629 SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
1630 return FALSE;
1632 RegCloseKey(enum_hkey);
1634 /* Check if instance is already in set */
1635 lstrcpyW(id, name);
1636 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
1638 if (!lstrcmpiW(name, device->instanceId))
1640 SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
1641 return FALSE;
1646 if (!(device = create_device(set, class, id, TRUE)))
1647 return FALSE;
1649 if (description)
1651 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_DEVICEDESC,
1652 (const BYTE *)description, lstrlenW(description) * sizeof(WCHAR));
1655 if (device_data)
1657 if (device_data->cbSize != sizeof(SP_DEVINFO_DATA))
1659 SetLastError(ERROR_INVALID_USER_BUFFER);
1660 return FALSE;
1662 else
1663 copy_device_data(device_data, device);
1666 return TRUE;
1669 /***********************************************************************
1670 * SetupDiRegisterDeviceInfo (SETUPAPI.@)
1672 BOOL WINAPI SetupDiRegisterDeviceInfo(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD flags,
1673 PSP_DETSIG_CMPPROC compare_proc, void *context, SP_DEVINFO_DATA *duplicate_data)
1675 struct device *device;
1677 TRACE("devinfo %p, data %p, flags %#x, compare_proc %p, context %p, duplicate_data %p.\n",
1678 devinfo, device_data, flags, compare_proc, context, duplicate_data);
1680 if (!(device = get_device(devinfo, device_data)))
1681 return FALSE;
1683 if (device->phantom)
1685 device->phantom = FALSE;
1686 RegDeleteValueW(device->key, Phantom);
1688 return TRUE;
1691 /***********************************************************************
1692 * SetupDiRemoveDevice (SETUPAPI.@)
1694 BOOL WINAPI SetupDiRemoveDevice(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
1696 SC_HANDLE manager = NULL, service = NULL;
1697 struct device *device;
1698 WCHAR *service_name;
1699 DWORD size;
1701 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
1703 if (!(device = get_device(devinfo, device_data)))
1704 return FALSE;
1706 if (!(manager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT)))
1707 return FALSE;
1709 if (!RegGetValueW(device->key, NULL, L"Service", RRF_RT_REG_SZ, NULL, NULL, &size))
1711 service_name = malloc(size);
1712 if (!RegGetValueW(device->key, NULL, L"Service", RRF_RT_REG_SZ, NULL, service_name, &size))
1713 service = OpenServiceW(manager, service_name, SERVICE_USER_DEFINED_CONTROL);
1714 free(service_name);
1717 remove_device(device);
1719 if (service)
1721 SERVICE_STATUS status;
1722 if (!ControlService(service, SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES, &status))
1723 ERR("Failed to control service %s, error %u.\n", debugstr_w(service_name), GetLastError());
1724 CloseServiceHandle(service);
1726 CloseServiceHandle(manager);
1728 return TRUE;
1731 /***********************************************************************
1732 * SetupDiDeleteDeviceInfo (SETUPAPI.@)
1734 BOOL WINAPI SetupDiDeleteDeviceInfo(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
1736 struct device *device;
1738 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
1740 if (!(device = get_device(devinfo, device_data)))
1741 return FALSE;
1743 delete_device(device);
1745 return TRUE;
1748 /***********************************************************************
1749 * SetupDiRemoveDeviceInterface (SETUPAPI.@)
1751 BOOL WINAPI SetupDiRemoveDeviceInterface(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data)
1753 struct device_iface *iface;
1755 TRACE("devinfo %p, iface_data %p.\n", devinfo, iface_data);
1757 if (!(iface = get_device_iface(devinfo, iface_data)))
1758 return FALSE;
1760 remove_device_iface(iface);
1762 return TRUE;
1765 /***********************************************************************
1766 * SetupDiDeleteDeviceInterfaceData (SETUPAPI.@)
1768 BOOL WINAPI SetupDiDeleteDeviceInterfaceData(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data)
1770 struct device_iface *iface;
1772 TRACE("devinfo %p, iface_data %p.\n", devinfo, iface_data);
1774 if (!(iface = get_device_iface(devinfo, iface_data)))
1775 return FALSE;
1777 delete_device_iface(iface);
1779 return TRUE;
1782 /***********************************************************************
1783 * SetupDiEnumDeviceInfo (SETUPAPI.@)
1785 BOOL WINAPI DECLSPEC_HOTPATCH SetupDiEnumDeviceInfo(HDEVINFO devinfo, DWORD index, SP_DEVINFO_DATA *device_data)
1787 struct DeviceInfoSet *set;
1788 struct device *device;
1789 DWORD i = 0;
1791 TRACE("devinfo %p, index %d, device_data %p\n", devinfo, index, device_data);
1793 if (!(set = get_device_set(devinfo)))
1794 return FALSE;
1796 if (!device_data)
1798 SetLastError(ERROR_INVALID_PARAMETER);
1799 return FALSE;
1802 if (device_data->cbSize != sizeof(SP_DEVINFO_DATA))
1804 SetLastError(ERROR_INVALID_USER_BUFFER);
1805 return FALSE;
1808 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
1810 if (i++ == index)
1812 copy_device_data(device_data, device);
1813 return TRUE;
1817 SetLastError(ERROR_NO_MORE_ITEMS);
1818 return FALSE;
1821 /***********************************************************************
1822 * SetupDiGetDeviceInstanceIdA (SETUPAPI.@)
1824 BOOL WINAPI SetupDiGetDeviceInstanceIdA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
1825 char *id, DWORD size, DWORD *needed)
1827 WCHAR idW[MAX_DEVICE_ID_LEN];
1829 TRACE("devinfo %p, device_data %p, id %p, size %d, needed %p.\n",
1830 devinfo, device_data, id, size, needed);
1832 if (!SetupDiGetDeviceInstanceIdW(devinfo, device_data, idW, ARRAY_SIZE(idW), NULL))
1833 return FALSE;
1835 if (needed)
1836 *needed = WideCharToMultiByte(CP_ACP, 0, idW, -1, NULL, 0, NULL, NULL);
1838 if (size && WideCharToMultiByte(CP_ACP, 0, idW, -1, id, size, NULL, NULL))
1839 return TRUE;
1841 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1842 return FALSE;
1845 /***********************************************************************
1846 * SetupDiGetDeviceInstanceIdW (SETUPAPI.@)
1848 BOOL WINAPI SetupDiGetDeviceInstanceIdW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
1849 WCHAR *DeviceInstanceId, DWORD DeviceInstanceIdSize, DWORD *RequiredSize)
1851 struct device *device;
1853 TRACE("devinfo %p, device_data %p, DeviceInstanceId %p, DeviceInstanceIdSize %d, RequiredSize %p.\n",
1854 devinfo, device_data, DeviceInstanceId, DeviceInstanceIdSize, RequiredSize);
1856 if (!(device = get_device(devinfo, device_data)))
1857 return FALSE;
1859 TRACE("instance ID: %s\n", debugstr_w(device->instanceId));
1860 if (DeviceInstanceIdSize < lstrlenW(device->instanceId) + 1)
1862 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1863 if (RequiredSize)
1864 *RequiredSize = lstrlenW(device->instanceId) + 1;
1865 return FALSE;
1867 lstrcpyW(DeviceInstanceId, device->instanceId);
1868 if (RequiredSize)
1869 *RequiredSize = lstrlenW(device->instanceId) + 1;
1870 return TRUE;
1873 /***********************************************************************
1874 * SetupDiGetActualSectionToInstallExA (SETUPAPI.@)
1876 BOOL WINAPI SetupDiGetActualSectionToInstallExA(HINF hinf, const char *section, SP_ALTPLATFORM_INFO *altplatform,
1877 char *section_ext, DWORD size, DWORD *needed, char **extptr, void *reserved)
1879 WCHAR sectionW[LINE_LEN], section_extW[LINE_LEN], *extptrW;
1880 BOOL ret;
1882 MultiByteToWideChar(CP_ACP, 0, section, -1, sectionW, ARRAY_SIZE(sectionW));
1884 ret = SetupDiGetActualSectionToInstallExW(hinf, sectionW, altplatform, section_extW,
1885 ARRAY_SIZE(section_extW), NULL, &extptrW, reserved);
1886 if (ret)
1888 if (needed)
1889 *needed = WideCharToMultiByte(CP_ACP, 0, section_extW, -1, NULL, 0, NULL, NULL);
1891 if (section_ext)
1892 ret = !!WideCharToMultiByte(CP_ACP, 0, section_extW, -1, section_ext, size, NULL, NULL);
1894 if (extptr)
1896 if (extptrW)
1897 *extptr = section_ext + WideCharToMultiByte(CP_ACP, 0, section_extW,
1898 extptrW - section_extW, NULL, 0, NULL, NULL);
1899 else
1900 *extptr = NULL;
1904 return ret;
1907 /***********************************************************************
1908 * SetupDiGetActualSectionToInstallA (SETUPAPI.@)
1910 BOOL WINAPI SetupDiGetActualSectionToInstallA(HINF hinf, const char *section, char *section_ext,
1911 DWORD size, DWORD *needed, char **extptr)
1913 return SetupDiGetActualSectionToInstallExA(hinf, section, NULL, section_ext, size,
1914 needed, extptr, NULL);
1917 /***********************************************************************
1918 * SetupDiGetActualSectionToInstallExW (SETUPAPI.@)
1920 BOOL WINAPI SetupDiGetActualSectionToInstallExW(HINF hinf, const WCHAR *section, SP_ALTPLATFORM_INFO *altplatform,
1921 WCHAR *section_ext, DWORD size, DWORD *needed, WCHAR **extptr, void *reserved)
1923 WCHAR buffer[MAX_PATH];
1924 DWORD len;
1925 DWORD full_len;
1926 LONG line_count = -1;
1928 TRACE("hinf %p, section %s, altplatform %p, ext %p, size %d, needed %p, extptr %p, reserved %p.\n",
1929 hinf, debugstr_w(section), altplatform, section_ext, size, needed, extptr, reserved);
1931 if (altplatform)
1932 FIXME("SP_ALTPLATFORM_INFO unsupported\n");
1934 lstrcpyW(buffer, section);
1935 len = lstrlenW(buffer);
1937 if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
1939 /* Test section name with '.NTx86' extension */
1940 lstrcpyW(&buffer[len], NtPlatformExtension);
1941 line_count = SetupGetLineCountW(hinf, buffer);
1943 if (line_count == -1)
1945 /* Test section name with '.NT' extension */
1946 lstrcpyW(&buffer[len], NtExtension);
1947 line_count = SetupGetLineCountW(hinf, buffer);
1950 else
1952 /* Test section name with '.Win' extension */
1953 lstrcpyW(&buffer[len], WinExtension);
1954 line_count = SetupGetLineCountW(hinf, buffer);
1957 if (line_count == -1)
1958 buffer[len] = 0;
1960 full_len = lstrlenW(buffer);
1962 if (section_ext != NULL && size != 0)
1964 if (size < (full_len + 1))
1966 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1967 return FALSE;
1970 lstrcpyW(section_ext, buffer);
1971 if (extptr != NULL)
1973 *extptr = (len == full_len) ? NULL : &section_ext[len];
1977 if (needed != NULL)
1979 *needed = full_len + 1;
1982 return TRUE;
1985 /***********************************************************************
1986 * SetupDiGetActualSectionToInstallW (SETUPAPI.@)
1988 BOOL WINAPI SetupDiGetActualSectionToInstallW(HINF hinf, const WCHAR *section, WCHAR *section_ext,
1989 DWORD size, DWORD *needed, WCHAR **extptr)
1991 return SetupDiGetActualSectionToInstallExW(hinf, section, NULL, section_ext, size,
1992 needed, extptr, NULL);
1995 /***********************************************************************
1996 * SetupDiGetClassDescriptionA (SETUPAPI.@)
1998 BOOL WINAPI SetupDiGetClassDescriptionA(
1999 const GUID* ClassGuid,
2000 PSTR ClassDescription,
2001 DWORD ClassDescriptionSize,
2002 PDWORD RequiredSize)
2004 return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
2005 ClassDescriptionSize,
2006 RequiredSize, NULL, NULL);
2009 /***********************************************************************
2010 * SetupDiGetClassDescriptionW (SETUPAPI.@)
2012 BOOL WINAPI SetupDiGetClassDescriptionW(
2013 const GUID* ClassGuid,
2014 PWSTR ClassDescription,
2015 DWORD ClassDescriptionSize,
2016 PDWORD RequiredSize)
2018 return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
2019 ClassDescriptionSize,
2020 RequiredSize, NULL, NULL);
2023 /***********************************************************************
2024 * SetupDiGetClassDescriptionExA (SETUPAPI.@)
2026 BOOL WINAPI SetupDiGetClassDescriptionExA(
2027 const GUID* ClassGuid,
2028 PSTR ClassDescription,
2029 DWORD ClassDescriptionSize,
2030 PDWORD RequiredSize,
2031 PCSTR MachineName,
2032 PVOID Reserved)
2034 HKEY hKey;
2035 DWORD dwLength;
2036 BOOL ret;
2038 hKey = SetupDiOpenClassRegKeyExA(ClassGuid,
2039 KEY_ALL_ACCESS,
2040 DIOCR_INSTALLER,
2041 MachineName,
2042 Reserved);
2043 if (hKey == INVALID_HANDLE_VALUE)
2045 WARN("SetupDiOpenClassRegKeyExA() failed (Error %u)\n", GetLastError());
2046 return FALSE;
2049 dwLength = ClassDescriptionSize;
2050 ret = !RegQueryValueExA( hKey, NULL, NULL, NULL,
2051 (LPBYTE)ClassDescription, &dwLength );
2052 if (RequiredSize) *RequiredSize = dwLength;
2053 RegCloseKey(hKey);
2054 return ret;
2057 /***********************************************************************
2058 * SetupDiGetClassDescriptionExW (SETUPAPI.@)
2060 BOOL WINAPI SetupDiGetClassDescriptionExW(
2061 const GUID* ClassGuid,
2062 PWSTR ClassDescription,
2063 DWORD ClassDescriptionSize,
2064 PDWORD RequiredSize,
2065 PCWSTR MachineName,
2066 PVOID Reserved)
2068 HKEY hKey;
2069 DWORD dwLength;
2070 BOOL ret;
2072 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
2073 KEY_ALL_ACCESS,
2074 DIOCR_INSTALLER,
2075 MachineName,
2076 Reserved);
2077 if (hKey == INVALID_HANDLE_VALUE)
2079 WARN("SetupDiOpenClassRegKeyExW() failed (Error %u)\n", GetLastError());
2080 return FALSE;
2083 dwLength = ClassDescriptionSize * sizeof(WCHAR);
2084 ret = !RegQueryValueExW( hKey, NULL, NULL, NULL,
2085 (LPBYTE)ClassDescription, &dwLength );
2086 if (RequiredSize) *RequiredSize = dwLength / sizeof(WCHAR);
2087 RegCloseKey(hKey);
2088 return ret;
2091 /***********************************************************************
2092 * SetupDiGetClassDevsA (SETUPAPI.@)
2094 HDEVINFO WINAPI SetupDiGetClassDevsA(const GUID *class, LPCSTR enumstr, HWND parent, DWORD flags)
2096 HDEVINFO ret;
2097 LPWSTR enumstrW = NULL;
2099 if (enumstr)
2101 int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
2102 enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2103 if (!enumstrW)
2105 ret = INVALID_HANDLE_VALUE;
2106 goto end;
2108 MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
2110 ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, NULL, NULL,
2111 NULL);
2112 HeapFree(GetProcessHeap(), 0, enumstrW);
2114 end:
2115 return ret;
2118 /***********************************************************************
2119 * SetupDiGetClassDevsExA (SETUPAPI.@)
2121 HDEVINFO WINAPI SetupDiGetClassDevsExA(
2122 const GUID *class,
2123 PCSTR enumstr,
2124 HWND parent,
2125 DWORD flags,
2126 HDEVINFO deviceset,
2127 PCSTR machine,
2128 PVOID reserved)
2130 HDEVINFO ret;
2131 LPWSTR enumstrW = NULL, machineW = NULL;
2133 if (enumstr)
2135 int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
2136 enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2137 if (!enumstrW)
2139 ret = INVALID_HANDLE_VALUE;
2140 goto end;
2142 MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
2144 if (machine)
2146 int len = MultiByteToWideChar(CP_ACP, 0, machine, -1, NULL, 0);
2147 machineW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2148 if (!machineW)
2150 HeapFree(GetProcessHeap(), 0, enumstrW);
2151 ret = INVALID_HANDLE_VALUE;
2152 goto end;
2154 MultiByteToWideChar(CP_ACP, 0, machine, -1, machineW, len);
2156 ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset,
2157 machineW, reserved);
2158 HeapFree(GetProcessHeap(), 0, enumstrW);
2159 HeapFree(GetProcessHeap(), 0, machineW);
2161 end:
2162 return ret;
2165 static void SETUPDI_AddDeviceInterfaces(struct device *device, HKEY key,
2166 const GUID *guid, DWORD flags)
2168 DWORD i, len;
2169 WCHAR subKeyName[MAX_PATH];
2170 LONG l = ERROR_SUCCESS;
2172 for (i = 0; !l; i++)
2174 len = ARRAY_SIZE(subKeyName);
2175 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2176 if (!l)
2178 HKEY subKey;
2179 struct device_iface *iface;
2181 if (*subKeyName == '#')
2183 /* The subkey name is the reference string, with a '#' prepended */
2184 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2185 if (!l)
2187 WCHAR symbolicLink[MAX_PATH];
2188 DWORD dataType;
2190 if (!(flags & DIGCF_PRESENT) || is_linked(subKey))
2192 iface = SETUPDI_CreateDeviceInterface(device, guid, subKeyName + 1);
2194 len = sizeof(symbolicLink);
2195 l = RegQueryValueExW(subKey, SymbolicLink, NULL, &dataType,
2196 (BYTE *)symbolicLink, &len);
2197 if (!l && dataType == REG_SZ)
2198 SETUPDI_SetInterfaceSymbolicLink(iface, symbolicLink);
2199 RegCloseKey(subKey);
2203 /* Allow enumeration to continue */
2204 l = ERROR_SUCCESS;
2207 /* FIXME: find and add all the device's interfaces to the device */
2210 static void SETUPDI_EnumerateMatchingInterfaces(HDEVINFO DeviceInfoSet,
2211 HKEY key, const GUID *guid, const WCHAR *enumstr, DWORD flags)
2213 struct DeviceInfoSet *set = DeviceInfoSet;
2214 DWORD i, len;
2215 WCHAR subKeyName[MAX_PATH];
2216 LONG l;
2217 HKEY enumKey = INVALID_HANDLE_VALUE;
2219 TRACE("%s\n", debugstr_w(enumstr));
2221 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL,
2222 &enumKey, NULL);
2223 for (i = 0; !l; i++)
2225 len = ARRAY_SIZE(subKeyName);
2226 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2227 if (!l)
2229 HKEY subKey;
2231 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2232 if (!l)
2234 WCHAR deviceInst[MAX_PATH * 3];
2235 DWORD dataType;
2237 len = sizeof(deviceInst);
2238 l = RegQueryValueExW(subKey, DeviceInstance, NULL, &dataType,
2239 (BYTE *)deviceInst, &len);
2240 if (!l && dataType == REG_SZ)
2242 TRACE("found instance ID %s\n", debugstr_w(deviceInst));
2243 if (!enumstr || !lstrcmpiW(enumstr, deviceInst))
2245 HKEY deviceKey;
2247 l = RegOpenKeyExW(enumKey, deviceInst, 0, KEY_READ,
2248 &deviceKey);
2249 if (!l)
2251 WCHAR deviceClassStr[40];
2253 len = sizeof(deviceClassStr);
2254 l = RegQueryValueExW(deviceKey, ClassGUID, NULL,
2255 &dataType, (BYTE *)deviceClassStr, &len);
2256 if (!l && dataType == REG_SZ &&
2257 deviceClassStr[0] == '{' &&
2258 deviceClassStr[37] == '}')
2260 GUID deviceClass;
2261 struct device *device;
2263 deviceClassStr[37] = 0;
2264 UuidFromStringW(&deviceClassStr[1],
2265 &deviceClass);
2266 if ((device = create_device(set, &deviceClass, deviceInst, FALSE)))
2267 SETUPDI_AddDeviceInterfaces(device, subKey, guid, flags);
2269 RegCloseKey(deviceKey);
2273 RegCloseKey(subKey);
2275 /* Allow enumeration to continue */
2276 l = ERROR_SUCCESS;
2279 if (enumKey != INVALID_HANDLE_VALUE)
2280 RegCloseKey(enumKey);
2283 static void SETUPDI_EnumerateInterfaces(HDEVINFO DeviceInfoSet,
2284 const GUID *guid, LPCWSTR enumstr, DWORD flags)
2286 HKEY interfacesKey = SetupDiOpenClassRegKeyExW(guid, KEY_READ,
2287 DIOCR_INTERFACE, NULL, NULL);
2289 TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(guid),
2290 debugstr_w(enumstr), flags);
2292 if (interfacesKey != INVALID_HANDLE_VALUE)
2294 if (flags & DIGCF_ALLCLASSES)
2296 DWORD i, len;
2297 WCHAR interfaceGuidStr[40];
2298 LONG l = ERROR_SUCCESS;
2300 for (i = 0; !l; i++)
2302 len = ARRAY_SIZE(interfaceGuidStr);
2303 l = RegEnumKeyExW(interfacesKey, i, interfaceGuidStr, &len,
2304 NULL, NULL, NULL, NULL);
2305 if (!l)
2307 if (interfaceGuidStr[0] == '{' &&
2308 interfaceGuidStr[37] == '}')
2310 HKEY interfaceKey;
2311 GUID interfaceGuid;
2313 interfaceGuidStr[37] = 0;
2314 UuidFromStringW(&interfaceGuidStr[1], &interfaceGuid);
2315 interfaceGuidStr[37] = '}';
2316 interfaceGuidStr[38] = 0;
2317 l = RegOpenKeyExW(interfacesKey, interfaceGuidStr, 0,
2318 KEY_READ, &interfaceKey);
2319 if (!l)
2321 SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
2322 interfaceKey, &interfaceGuid, enumstr, flags);
2323 RegCloseKey(interfaceKey);
2329 else
2331 /* In this case, SetupDiOpenClassRegKeyExW opened the specific
2332 * interface's key, so just pass that long
2334 SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
2335 interfacesKey, guid, enumstr, flags);
2337 RegCloseKey(interfacesKey);
2341 static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set,
2342 LPCWSTR enumerator, LPCWSTR deviceName, HKEY deviceKey,
2343 const GUID *class, DWORD flags)
2345 WCHAR id[MAX_DEVICE_ID_LEN];
2346 DWORD i, len;
2347 WCHAR deviceInstance[MAX_PATH];
2348 LONG l = ERROR_SUCCESS;
2350 TRACE("%s %s\n", debugstr_w(enumerator), debugstr_w(deviceName));
2352 for (i = 0; !l; i++)
2354 len = ARRAY_SIZE(deviceInstance);
2355 l = RegEnumKeyExW(deviceKey, i, deviceInstance, &len, NULL, NULL, NULL,
2356 NULL);
2357 if (!l)
2359 HKEY subKey;
2361 l = RegOpenKeyExW(deviceKey, deviceInstance, 0, KEY_READ, &subKey);
2362 if (!l)
2364 WCHAR classGuid[40];
2365 DWORD dataType;
2367 len = sizeof(classGuid);
2368 l = RegQueryValueExW(subKey, ClassGUID, NULL, &dataType,
2369 (BYTE *)classGuid, &len);
2370 if (!l && dataType == REG_SZ)
2372 if (classGuid[0] == '{' && classGuid[37] == '}')
2374 GUID deviceClass;
2376 classGuid[37] = 0;
2377 UuidFromStringW(&classGuid[1], &deviceClass);
2378 if ((flags & DIGCF_ALLCLASSES) ||
2379 IsEqualGUID(class, &deviceClass))
2381 static const WCHAR fmt[] =
2382 {'%','s','\\','%','s','\\','%','s',0};
2384 if (swprintf(id, ARRAY_SIZE(id), fmt, enumerator,
2385 deviceName, deviceInstance) != -1)
2387 create_device(set, &deviceClass, id, FALSE);
2392 RegCloseKey(subKey);
2394 /* Allow enumeration to continue */
2395 l = ERROR_SUCCESS;
2400 static void SETUPDI_EnumerateMatchingDevices(HDEVINFO DeviceInfoSet,
2401 LPCWSTR parent, HKEY key, const GUID *class, DWORD flags)
2403 struct DeviceInfoSet *set = DeviceInfoSet;
2404 DWORD i, len;
2405 WCHAR subKeyName[MAX_PATH];
2406 LONG l = ERROR_SUCCESS;
2408 TRACE("%s\n", debugstr_w(parent));
2410 for (i = 0; !l; i++)
2412 len = ARRAY_SIZE(subKeyName);
2413 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2414 if (!l)
2416 HKEY subKey;
2418 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2419 if (!l)
2421 TRACE("%s\n", debugstr_w(subKeyName));
2422 SETUPDI_EnumerateMatchingDeviceInstances(set, parent,
2423 subKeyName, subKey, class, flags);
2424 RegCloseKey(subKey);
2426 /* Allow enumeration to continue */
2427 l = ERROR_SUCCESS;
2432 static void SETUPDI_EnumerateDevices(HDEVINFO DeviceInfoSet, const GUID *class,
2433 LPCWSTR enumstr, DWORD flags)
2435 HKEY enumKey;
2436 LONG l;
2438 TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(class),
2439 debugstr_w(enumstr), flags);
2441 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL,
2442 &enumKey, NULL);
2443 if (enumKey != INVALID_HANDLE_VALUE)
2445 if (enumstr)
2447 HKEY enumStrKey;
2449 l = RegOpenKeyExW(enumKey, enumstr, 0, KEY_READ,
2450 &enumStrKey);
2451 if (!l)
2453 WCHAR *bus, *device;
2455 if (!wcschr(enumstr, '\\'))
2457 SETUPDI_EnumerateMatchingDevices(DeviceInfoSet, enumstr, enumStrKey, class, flags);
2459 else if ((bus = strdupW(enumstr)))
2461 device = wcschr(bus, '\\');
2462 *device++ = 0;
2464 SETUPDI_EnumerateMatchingDeviceInstances(DeviceInfoSet, bus, device, enumStrKey, class, flags);
2465 HeapFree(GetProcessHeap(), 0, bus);
2468 RegCloseKey(enumStrKey);
2471 else
2473 DWORD i, len;
2474 WCHAR subKeyName[MAX_PATH];
2476 l = ERROR_SUCCESS;
2477 for (i = 0; !l; i++)
2479 len = ARRAY_SIZE(subKeyName);
2480 l = RegEnumKeyExW(enumKey, i, subKeyName, &len, NULL,
2481 NULL, NULL, NULL);
2482 if (!l)
2484 HKEY subKey;
2486 l = RegOpenKeyExW(enumKey, subKeyName, 0, KEY_READ,
2487 &subKey);
2488 if (!l)
2490 SETUPDI_EnumerateMatchingDevices(DeviceInfoSet,
2491 subKeyName, subKey, class, flags);
2492 RegCloseKey(subKey);
2494 /* Allow enumeration to continue */
2495 l = ERROR_SUCCESS;
2499 RegCloseKey(enumKey);
2503 /***********************************************************************
2504 * SetupDiGetClassDevsW (SETUPAPI.@)
2506 HDEVINFO WINAPI SetupDiGetClassDevsW(const GUID *class, LPCWSTR enumstr, HWND parent, DWORD flags)
2508 return SetupDiGetClassDevsExW(class, enumstr, parent, flags, NULL, NULL,
2509 NULL);
2512 /***********************************************************************
2513 * SetupDiGetClassDevsExW (SETUPAPI.@)
2515 HDEVINFO WINAPI SetupDiGetClassDevsExW(const GUID *class, PCWSTR enumstr, HWND parent, DWORD flags,
2516 HDEVINFO deviceset, PCWSTR machine, void *reserved)
2518 static const DWORD unsupportedFlags = DIGCF_DEFAULT | DIGCF_PROFILE;
2519 HDEVINFO set;
2521 TRACE("%s %s %p 0x%08x %p %s %p\n", debugstr_guid(class),
2522 debugstr_w(enumstr), parent, flags, deviceset, debugstr_w(machine),
2523 reserved);
2525 if (!(flags & DIGCF_ALLCLASSES) && !class)
2527 SetLastError(ERROR_INVALID_PARAMETER);
2528 return INVALID_HANDLE_VALUE;
2530 if (flags & DIGCF_ALLCLASSES)
2531 class = NULL;
2533 if (flags & unsupportedFlags)
2534 WARN("unsupported flags %08x\n", flags & unsupportedFlags);
2535 if (deviceset)
2536 set = deviceset;
2537 else
2538 set = SetupDiCreateDeviceInfoListExW((flags & DIGCF_DEVICEINTERFACE) ? NULL : class, parent, machine, reserved);
2539 if (set != INVALID_HANDLE_VALUE)
2541 if (machine && *machine)
2542 FIXME("%s: unimplemented for remote machines\n",
2543 debugstr_w(machine));
2544 else if (flags & DIGCF_DEVICEINTERFACE)
2545 SETUPDI_EnumerateInterfaces(set, class, enumstr, flags);
2546 else
2547 SETUPDI_EnumerateDevices(set, class, enumstr, flags);
2549 return set;
2552 /***********************************************************************
2553 * SetupDiGetDeviceInfoListDetailA (SETUPAPI.@)
2555 BOOL WINAPI SetupDiGetDeviceInfoListDetailA(HDEVINFO devinfo, SP_DEVINFO_LIST_DETAIL_DATA_A *DevInfoData)
2557 struct DeviceInfoSet *set;
2559 TRACE("devinfo %p, detail_data %p.\n", devinfo, DevInfoData);
2561 if (!(set = get_device_set(devinfo)))
2562 return FALSE;
2564 if (!DevInfoData ||
2565 DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_A))
2567 SetLastError(ERROR_INVALID_PARAMETER);
2568 return FALSE;
2570 DevInfoData->ClassGuid = set->ClassGuid;
2571 DevInfoData->RemoteMachineHandle = NULL;
2572 DevInfoData->RemoteMachineName[0] = '\0';
2573 return TRUE;
2576 /***********************************************************************
2577 * SetupDiGetDeviceInfoListDetailW (SETUPAPI.@)
2579 BOOL WINAPI SetupDiGetDeviceInfoListDetailW(HDEVINFO devinfo, SP_DEVINFO_LIST_DETAIL_DATA_W *DevInfoData)
2581 struct DeviceInfoSet *set;
2583 TRACE("devinfo %p, detail_data %p.\n", devinfo, DevInfoData);
2585 if (!(set = get_device_set(devinfo)))
2586 return FALSE;
2588 if (!DevInfoData ||
2589 DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W))
2591 SetLastError(ERROR_INVALID_PARAMETER);
2592 return FALSE;
2594 DevInfoData->ClassGuid = set->ClassGuid;
2595 DevInfoData->RemoteMachineHandle = NULL;
2596 DevInfoData->RemoteMachineName[0] = '\0';
2597 return TRUE;
2600 /***********************************************************************
2601 * SetupDiCreateDeviceInterfaceA (SETUPAPI.@)
2603 BOOL WINAPI SetupDiCreateDeviceInterfaceA(
2604 HDEVINFO DeviceInfoSet,
2605 PSP_DEVINFO_DATA DeviceInfoData,
2606 const GUID *InterfaceClassGuid,
2607 PCSTR ReferenceString,
2608 DWORD CreationFlags,
2609 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2611 BOOL ret;
2612 LPWSTR ReferenceStringW = NULL;
2614 TRACE("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
2615 debugstr_guid(InterfaceClassGuid), debugstr_a(ReferenceString),
2616 CreationFlags, DeviceInterfaceData);
2618 if (ReferenceString)
2620 ReferenceStringW = MultiByteToUnicode(ReferenceString, CP_ACP);
2621 if (ReferenceStringW == NULL) return FALSE;
2624 ret = SetupDiCreateDeviceInterfaceW(DeviceInfoSet, DeviceInfoData,
2625 InterfaceClassGuid, ReferenceStringW, CreationFlags,
2626 DeviceInterfaceData);
2628 MyFree(ReferenceStringW);
2630 return ret;
2633 /***********************************************************************
2634 * SetupDiCreateDeviceInterfaceW (SETUPAPI.@)
2636 BOOL WINAPI SetupDiCreateDeviceInterfaceW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
2637 const GUID *class, const WCHAR *refstr, DWORD flags, SP_DEVICE_INTERFACE_DATA *iface_data)
2639 struct device *device;
2640 struct device_iface *iface;
2642 TRACE("devinfo %p, device_data %p, class %s, refstr %s, flags %#x, iface_data %p.\n",
2643 devinfo, device_data, debugstr_guid(class), debugstr_w(refstr), flags, iface_data);
2645 if (!(device = get_device(devinfo, device_data)))
2646 return FALSE;
2648 if (!class)
2650 SetLastError(ERROR_INVALID_USER_BUFFER);
2651 return FALSE;
2654 if (!(iface = SETUPDI_CreateDeviceInterface(device, class, refstr)))
2655 return FALSE;
2657 if (iface_data)
2659 if (iface_data->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2661 SetLastError(ERROR_INVALID_USER_BUFFER);
2662 return FALSE;
2665 copy_device_iface_data(iface_data, iface);
2667 return TRUE;
2670 /***********************************************************************
2671 * SetupDiCreateDeviceInterfaceRegKeyA (SETUPAPI.@)
2673 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyA(
2674 HDEVINFO DeviceInfoSet,
2675 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2676 DWORD Reserved,
2677 REGSAM samDesired,
2678 HINF InfHandle,
2679 PCSTR InfSectionName)
2681 HKEY key;
2682 PWSTR InfSectionNameW = NULL;
2684 TRACE("%p %p %d %08x %p %p\n", DeviceInfoSet, DeviceInterfaceData, Reserved,
2685 samDesired, InfHandle, InfSectionName);
2686 if (InfHandle)
2688 if (!InfSectionName)
2690 SetLastError(ERROR_INVALID_PARAMETER);
2691 return INVALID_HANDLE_VALUE;
2693 InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
2694 if (!InfSectionNameW)
2695 return INVALID_HANDLE_VALUE;
2697 key = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet,
2698 DeviceInterfaceData, Reserved, samDesired, InfHandle,
2699 InfSectionNameW);
2700 MyFree(InfSectionNameW);
2701 return key;
2704 static LONG create_iface_key(const struct device_iface *iface, REGSAM access, HKEY *key)
2706 return RegCreateKeyExW(iface->refstr_key, DeviceParameters, 0, NULL, 0, access, NULL, key, NULL);
2709 /***********************************************************************
2710 * SetupDiCreateDeviceInterfaceRegKeyW (SETUPAPI.@)
2712 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyW(HDEVINFO devinfo,
2713 SP_DEVICE_INTERFACE_DATA *iface_data, DWORD reserved, REGSAM access,
2714 HINF hinf, const WCHAR *section)
2716 struct device_iface *iface;
2717 HKEY params_key;
2718 LONG ret;
2720 TRACE("devinfo %p, iface_data %p, reserved %d, access %#x, hinf %p, section %s.\n",
2721 devinfo, iface_data, reserved, access, hinf, debugstr_w(section));
2723 if (!(iface = get_device_iface(devinfo, iface_data)))
2724 return INVALID_HANDLE_VALUE;
2726 if (hinf && !section)
2728 SetLastError(ERROR_INVALID_PARAMETER);
2729 return INVALID_HANDLE_VALUE;
2732 ret = create_iface_key(iface, access, &params_key);
2733 if (ret)
2735 SetLastError(ret);
2736 return INVALID_HANDLE_VALUE;
2739 return params_key;
2742 /***********************************************************************
2743 * SetupDiDeleteDeviceInterfaceRegKey (SETUPAPI.@)
2745 BOOL WINAPI SetupDiDeleteDeviceInterfaceRegKey(HDEVINFO devinfo,
2746 SP_DEVICE_INTERFACE_DATA *iface_data, DWORD reserved)
2748 struct device_iface *iface;
2749 LONG ret;
2751 TRACE("devinfo %p, iface_data %p, reserved %d.\n", devinfo, iface_data, reserved);
2753 if (!(iface = get_device_iface(devinfo, iface_data)))
2754 return FALSE;
2756 ret = RegDeleteKeyW(iface->refstr_key, DeviceParameters);
2757 if (ret)
2759 SetLastError(ret);
2760 return FALSE;
2763 return TRUE;
2766 /***********************************************************************
2767 * SetupDiEnumDeviceInterfaces (SETUPAPI.@)
2769 * PARAMS
2770 * DeviceInfoSet [I] Set of devices from which to enumerate
2771 * interfaces
2772 * DeviceInfoData [I] (Optional) If specified, a specific device
2773 * instance from which to enumerate interfaces.
2774 * If it isn't specified, all interfaces for all
2775 * devices in the set are enumerated.
2776 * InterfaceClassGuid [I] The interface class to enumerate.
2777 * MemberIndex [I] An index of the interface instance to enumerate.
2778 * A caller should start with MemberIndex set to 0,
2779 * and continue until the function fails with
2780 * ERROR_NO_MORE_ITEMS.
2781 * DeviceInterfaceData [I/O] Returns an enumerated interface. Its cbSize
2782 * member must be set to
2783 * sizeof(SP_DEVICE_INTERFACE_DATA).
2785 * RETURNS
2786 * Success: non-zero value.
2787 * Failure: FALSE. Call GetLastError() for more info.
2789 BOOL WINAPI SetupDiEnumDeviceInterfaces(HDEVINFO devinfo,
2790 SP_DEVINFO_DATA *device_data, const GUID *class, DWORD index,
2791 SP_DEVICE_INTERFACE_DATA *iface_data)
2793 struct DeviceInfoSet *set;
2794 struct device *device;
2795 struct device_iface *iface;
2796 DWORD i = 0;
2798 TRACE("devinfo %p, device_data %p, class %s, index %u, iface_data %p.\n",
2799 devinfo, device_data, debugstr_guid(class), index, iface_data);
2801 if (!iface_data || iface_data->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2803 SetLastError(ERROR_INVALID_PARAMETER);
2804 return FALSE;
2807 /* In case application fails to check return value, clear output */
2808 memset(iface_data, 0, sizeof(*iface_data));
2809 iface_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
2811 if (device_data)
2813 if (!(device = get_device(devinfo, device_data)))
2814 return FALSE;
2816 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
2818 if (IsEqualGUID(&iface->class, class))
2820 if (i == index)
2822 copy_device_iface_data(iface_data, iface);
2823 return TRUE;
2825 i++;
2829 else
2831 if (!(set = get_device_set(devinfo)))
2832 return FALSE;
2834 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
2836 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
2838 if (IsEqualGUID(&iface->class, class))
2840 if (i == index)
2842 copy_device_iface_data(iface_data, iface);
2843 return TRUE;
2845 i++;
2851 SetLastError(ERROR_NO_MORE_ITEMS);
2852 return FALSE;
2855 /***********************************************************************
2856 * SetupDiDestroyDeviceInfoList (SETUPAPI.@)
2858 * Destroy a DeviceInfoList and free all used memory of the list.
2860 * PARAMS
2861 * devinfo [I] DeviceInfoList pointer to list to destroy
2863 * RETURNS
2864 * Success: non zero value.
2865 * Failure: zero value.
2867 BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
2869 struct DeviceInfoSet *set;
2870 struct device *device, *device2;
2872 TRACE("devinfo %p.\n", devinfo);
2874 if (!(set = get_device_set(devinfo)))
2875 return FALSE;
2877 LIST_FOR_EACH_ENTRY_SAFE(device, device2, &set->devices, struct device, entry)
2879 delete_device(device);
2881 heap_free(set);
2883 SetLastError(ERROR_SUCCESS);
2884 return TRUE;
2887 /***********************************************************************
2888 * SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
2890 BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data,
2891 SP_DEVICE_INTERFACE_DETAIL_DATA_A *DeviceInterfaceDetailData,
2892 DWORD DeviceInterfaceDetailDataSize, DWORD *RequiredSize, SP_DEVINFO_DATA *device_data)
2894 struct device_iface *iface;
2895 DWORD bytesNeeded = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath[1]);
2896 BOOL ret = FALSE;
2898 TRACE("devinfo %p, iface_data %p, detail_data %p, size %d, needed %p, device_data %p.\n",
2899 devinfo, iface_data, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize,
2900 RequiredSize, device_data);
2902 if (!(iface = get_device_iface(devinfo, iface_data)))
2903 return FALSE;
2905 if (DeviceInterfaceDetailData &&
2906 DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A))
2908 SetLastError(ERROR_INVALID_USER_BUFFER);
2909 return FALSE;
2911 if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
2913 SetLastError(ERROR_INVALID_USER_BUFFER);
2914 return FALSE;
2917 if (iface->symlink)
2918 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, iface->symlink, -1,
2919 NULL, 0, NULL, NULL);
2920 if (DeviceInterfaceDetailDataSize >= bytesNeeded)
2922 if (iface->symlink)
2923 WideCharToMultiByte(CP_ACP, 0, iface->symlink, -1,
2924 DeviceInterfaceDetailData->DevicePath,
2925 DeviceInterfaceDetailDataSize -
2926 offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
2927 NULL, NULL);
2928 else
2929 DeviceInterfaceDetailData->DevicePath[0] = '\0';
2931 ret = TRUE;
2933 else
2935 if (RequiredSize)
2936 *RequiredSize = bytesNeeded;
2937 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2940 if (device_data && device_data->cbSize == sizeof(SP_DEVINFO_DATA))
2941 copy_device_data(device_data, iface->device);
2943 return ret;
2946 /***********************************************************************
2947 * SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
2949 BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data,
2950 SP_DEVICE_INTERFACE_DETAIL_DATA_W *DeviceInterfaceDetailData,
2951 DWORD DeviceInterfaceDetailDataSize, DWORD *RequiredSize, SP_DEVINFO_DATA *device_data)
2953 struct device_iface *iface;
2954 DWORD bytesNeeded = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
2955 + sizeof(WCHAR); /* include NULL terminator */
2956 BOOL ret = FALSE;
2958 TRACE("devinfo %p, iface_data %p, detail_data %p, size %d, needed %p, device_data %p.\n",
2959 devinfo, iface_data, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize,
2960 RequiredSize, device_data);
2962 if (!(iface = get_device_iface(devinfo, iface_data)))
2963 return FALSE;
2965 if (DeviceInterfaceDetailData && (DeviceInterfaceDetailData->cbSize <
2966 offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR) ||
2967 DeviceInterfaceDetailData->cbSize > sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W)))
2969 SetLastError(ERROR_INVALID_USER_BUFFER);
2970 return FALSE;
2972 if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
2974 SetLastError(ERROR_INVALID_USER_BUFFER);
2975 return FALSE;
2978 if (iface->symlink)
2979 bytesNeeded += sizeof(WCHAR) * lstrlenW(iface->symlink);
2980 if (DeviceInterfaceDetailDataSize >= bytesNeeded)
2982 if (iface->symlink)
2983 lstrcpyW(DeviceInterfaceDetailData->DevicePath, iface->symlink);
2984 else
2985 DeviceInterfaceDetailData->DevicePath[0] = '\0';
2987 ret = TRUE;
2989 else
2991 if (RequiredSize)
2992 *RequiredSize = bytesNeeded;
2993 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2996 if (device_data && device_data->cbSize == sizeof(SP_DEVINFO_DATA))
2997 copy_device_data(device_data, iface->device);
2999 return ret;
3002 /***********************************************************************
3003 * SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
3005 BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(HDEVINFO devinfo,
3006 SP_DEVINFO_DATA *device_data, DWORD Property, DWORD *PropertyRegDataType,
3007 BYTE *PropertyBuffer, DWORD PropertyBufferSize, DWORD *RequiredSize)
3009 BOOL ret = FALSE;
3010 struct device *device;
3012 TRACE("devinfo %p, device_data %p, property %d, type %p, buffer %p, size %d, required %p\n",
3013 devinfo, device_data, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize);
3015 if (!(device = get_device(devinfo, device_data)))
3016 return FALSE;
3018 if (PropertyBufferSize && PropertyBuffer == NULL)
3020 SetLastError(ERROR_INVALID_DATA);
3021 return FALSE;
3024 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameA)
3026 DWORD size = PropertyBufferSize;
3027 LONG l = RegQueryValueExA(device->key, PropertyMap[Property].nameA,
3028 NULL, PropertyRegDataType, PropertyBuffer, &size);
3030 if (l == ERROR_FILE_NOT_FOUND)
3031 SetLastError(ERROR_INVALID_DATA);
3032 else if (l == ERROR_MORE_DATA || !PropertyBufferSize)
3033 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3034 else if (!l)
3035 ret = TRUE;
3036 else
3037 SetLastError(l);
3038 if (RequiredSize)
3039 *RequiredSize = size;
3041 return ret;
3044 /***********************************************************************
3045 * SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
3047 BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(HDEVINFO devinfo,
3048 SP_DEVINFO_DATA *device_data, DWORD Property, DWORD *PropertyRegDataType,
3049 BYTE *PropertyBuffer, DWORD PropertyBufferSize, DWORD *RequiredSize)
3051 BOOL ret = FALSE;
3052 struct device *device;
3054 TRACE("devinfo %p, device_data %p, prop %d, type %p, buffer %p, size %d, required %p\n",
3055 devinfo, device_data, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize);
3057 if (!(device = get_device(devinfo, device_data)))
3058 return FALSE;
3060 if (PropertyBufferSize && PropertyBuffer == NULL)
3062 SetLastError(ERROR_INVALID_DATA);
3063 return FALSE;
3066 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameW)
3068 DWORD size = PropertyBufferSize;
3069 LONG l = RegQueryValueExW(device->key, PropertyMap[Property].nameW,
3070 NULL, PropertyRegDataType, PropertyBuffer, &size);
3072 if (l == ERROR_FILE_NOT_FOUND)
3073 SetLastError(ERROR_INVALID_DATA);
3074 else if (l == ERROR_MORE_DATA || !PropertyBufferSize)
3075 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3076 else if (!l)
3077 ret = TRUE;
3078 else
3079 SetLastError(l);
3080 if (RequiredSize)
3081 *RequiredSize = size;
3083 return ret;
3086 /***********************************************************************
3087 * SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
3089 BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
3090 DWORD Property, const BYTE *PropertyBuffer, DWORD PropertyBufferSize)
3092 BOOL ret = FALSE;
3093 struct device *device;
3095 TRACE("devinfo %p, device_data %p, prop %d, buffer %p, size %d.\n",
3096 devinfo, device_data, Property, PropertyBuffer, PropertyBufferSize);
3098 if (!(device = get_device(devinfo, device_data)))
3099 return FALSE;
3101 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameA)
3103 LONG l = RegSetValueExA(device->key, PropertyMap[Property].nameA, 0,
3104 PropertyMap[Property].regType, PropertyBuffer,
3105 PropertyBufferSize);
3106 if (!l)
3107 ret = TRUE;
3108 else
3109 SetLastError(l);
3111 return ret;
3114 /***********************************************************************
3115 * SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
3117 BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(HDEVINFO devinfo,
3118 SP_DEVINFO_DATA *device_data, DWORD prop, const BYTE *buffer, DWORD size)
3120 struct device *device;
3122 TRACE("devinfo %p, device_data %p, prop %d, buffer %p, size %d.\n",
3123 devinfo, device_data, prop, buffer, size);
3125 if (!(device = get_device(devinfo, device_data)))
3126 return FALSE;
3128 return SETUPDI_SetDeviceRegistryPropertyW(device, prop, buffer, size);
3131 /***********************************************************************
3132 * SetupDiInstallClassA (SETUPAPI.@)
3134 BOOL WINAPI SetupDiInstallClassA(
3135 HWND hwndParent,
3136 PCSTR InfFileName,
3137 DWORD Flags,
3138 HSPFILEQ FileQueue)
3140 UNICODE_STRING FileNameW;
3141 BOOL Result;
3143 if (!InfFileName)
3145 SetLastError(ERROR_INVALID_PARAMETER);
3146 return FALSE;
3148 if (!RtlCreateUnicodeStringFromAsciiz(&FileNameW, InfFileName))
3150 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3151 return FALSE;
3154 Result = SetupDiInstallClassW(hwndParent, FileNameW.Buffer, Flags, FileQueue);
3156 RtlFreeUnicodeString(&FileNameW);
3158 return Result;
3161 static HKEY CreateClassKey(HINF hInf)
3163 static const WCHAR slash[] = { '\\',0 };
3164 WCHAR FullBuffer[MAX_PATH];
3165 WCHAR Buffer[MAX_PATH];
3166 DWORD RequiredSize;
3167 HKEY hClassKey;
3169 if (!SetupGetLineTextW(NULL,
3170 hInf,
3171 Version,
3172 ClassGUID,
3173 Buffer,
3174 MAX_PATH,
3175 &RequiredSize))
3177 return INVALID_HANDLE_VALUE;
3180 lstrcpyW(FullBuffer, ControlClass);
3181 lstrcatW(FullBuffer, slash);
3182 lstrcatW(FullBuffer, Buffer);
3184 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3185 FullBuffer,
3187 KEY_ALL_ACCESS,
3188 &hClassKey))
3190 if (!SetupGetLineTextW(NULL,
3191 hInf,
3192 Version,
3193 Class,
3194 Buffer,
3195 MAX_PATH,
3196 &RequiredSize))
3198 return INVALID_HANDLE_VALUE;
3201 if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
3202 FullBuffer,
3204 NULL,
3205 REG_OPTION_NON_VOLATILE,
3206 KEY_ALL_ACCESS,
3207 NULL,
3208 &hClassKey,
3209 NULL))
3211 return INVALID_HANDLE_VALUE;
3216 if (RegSetValueExW(hClassKey,
3217 Class,
3219 REG_SZ,
3220 (LPBYTE)Buffer,
3221 RequiredSize * sizeof(WCHAR)))
3223 RegCloseKey(hClassKey);
3224 RegDeleteKeyW(HKEY_LOCAL_MACHINE,
3225 FullBuffer);
3226 return INVALID_HANDLE_VALUE;
3229 return hClassKey;
3232 /***********************************************************************
3233 * SetupDiInstallClassW (SETUPAPI.@)
3235 BOOL WINAPI SetupDiInstallClassW(
3236 HWND hwndParent,
3237 PCWSTR InfFileName,
3238 DWORD Flags,
3239 HSPFILEQ FileQueue)
3241 WCHAR SectionName[MAX_PATH];
3242 DWORD SectionNameLength = 0;
3243 HINF hInf;
3244 BOOL bFileQueueCreated = FALSE;
3245 HKEY hClassKey;
3248 FIXME("\n");
3250 if (!InfFileName)
3252 SetLastError(ERROR_INVALID_PARAMETER);
3253 return FALSE;
3255 if ((Flags & DI_NOVCP) && (FileQueue == NULL || FileQueue == INVALID_HANDLE_VALUE))
3257 SetLastError(ERROR_INVALID_PARAMETER);
3258 return FALSE;
3261 /* Open the .inf file */
3262 hInf = SetupOpenInfFileW(InfFileName,
3263 NULL,
3264 INF_STYLE_WIN4,
3265 NULL);
3266 if (hInf == INVALID_HANDLE_VALUE)
3269 return FALSE;
3272 /* Create or open the class registry key 'HKLM\\CurrentControlSet\\Class\\{GUID}' */
3273 hClassKey = CreateClassKey(hInf);
3274 if (hClassKey == INVALID_HANDLE_VALUE)
3276 SetupCloseInfFile(hInf);
3277 return FALSE;
3281 /* Try to append a layout file */
3282 SetupOpenAppendInfFileW(NULL, hInf, NULL);
3284 /* Retrieve the actual section name */
3285 SetupDiGetActualSectionToInstallW(hInf,
3286 ClassInstall32,
3287 SectionName,
3288 MAX_PATH,
3289 &SectionNameLength,
3290 NULL);
3292 #if 0
3293 if (!(Flags & DI_NOVCP))
3295 FileQueue = SetupOpenFileQueue();
3296 if (FileQueue == INVALID_HANDLE_VALUE)
3298 SetupCloseInfFile(hInf);
3299 return FALSE;
3302 bFileQueueCreated = TRUE;
3305 #endif
3307 SetupInstallFromInfSectionW(NULL,
3308 hInf,
3309 SectionName,
3310 SPINST_COPYINF | SPINST_FILES | SPINST_REGISTRY,
3311 hClassKey,
3312 NULL,
3314 NULL,
3315 NULL,
3316 INVALID_HANDLE_VALUE,
3317 NULL);
3319 /* FIXME: More code! */
3321 if (bFileQueueCreated)
3322 SetupCloseFileQueue(FileQueue);
3324 SetupCloseInfFile(hInf);
3326 return TRUE;
3330 /***********************************************************************
3331 * SetupDiOpenClassRegKey (SETUPAPI.@)
3333 HKEY WINAPI SetupDiOpenClassRegKey(
3334 const GUID* ClassGuid,
3335 REGSAM samDesired)
3337 return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3338 DIOCR_INSTALLER, NULL, NULL);
3342 /***********************************************************************
3343 * SetupDiOpenClassRegKeyExA (SETUPAPI.@)
3345 HKEY WINAPI SetupDiOpenClassRegKeyExA(
3346 const GUID* ClassGuid,
3347 REGSAM samDesired,
3348 DWORD Flags,
3349 PCSTR MachineName,
3350 PVOID Reserved)
3352 PWSTR MachineNameW = NULL;
3353 HKEY hKey;
3355 TRACE("\n");
3357 if (MachineName)
3359 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
3360 if (MachineNameW == NULL)
3361 return INVALID_HANDLE_VALUE;
3364 hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3365 Flags, MachineNameW, Reserved);
3367 MyFree(MachineNameW);
3369 return hKey;
3373 /***********************************************************************
3374 * SetupDiOpenClassRegKeyExW (SETUPAPI.@)
3376 HKEY WINAPI SetupDiOpenClassRegKeyExW(
3377 const GUID* ClassGuid,
3378 REGSAM samDesired,
3379 DWORD Flags,
3380 PCWSTR MachineName,
3381 PVOID Reserved)
3383 HKEY hClassesKey;
3384 HKEY key;
3385 LPCWSTR lpKeyName;
3386 LONG l;
3388 if (MachineName && *MachineName)
3390 FIXME("Remote access not supported yet!\n");
3391 return INVALID_HANDLE_VALUE;
3394 if (Flags == DIOCR_INSTALLER)
3396 lpKeyName = ControlClass;
3398 else if (Flags == DIOCR_INTERFACE)
3400 lpKeyName = DeviceClasses;
3402 else
3404 ERR("Invalid Flags parameter!\n");
3405 SetLastError(ERROR_INVALID_PARAMETER);
3406 return INVALID_HANDLE_VALUE;
3409 if (!ClassGuid)
3411 if ((l = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3412 lpKeyName,
3414 samDesired,
3415 &hClassesKey)))
3417 SetLastError(l);
3418 hClassesKey = INVALID_HANDLE_VALUE;
3420 key = hClassesKey;
3422 else
3424 WCHAR bracedGuidString[39];
3426 SETUPDI_GuidToString(ClassGuid, bracedGuidString);
3428 if (!(l = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3429 lpKeyName,
3431 samDesired,
3432 &hClassesKey)))
3434 if ((l = RegOpenKeyExW(hClassesKey,
3435 bracedGuidString,
3437 samDesired,
3438 &key)))
3440 SetLastError(l);
3441 key = INVALID_HANDLE_VALUE;
3443 RegCloseKey(hClassesKey);
3445 else
3447 SetLastError(l);
3448 key = INVALID_HANDLE_VALUE;
3451 return key;
3454 /***********************************************************************
3455 * SetupDiOpenDeviceInfoA (SETUPAPI.@)
3457 BOOL WINAPI SetupDiOpenDeviceInfoA(HDEVINFO devinfo, PCSTR instance_id, HWND hwnd_parent, DWORD flags,
3458 PSP_DEVINFO_DATA device_data)
3460 WCHAR instance_idW[MAX_DEVICE_ID_LEN];
3462 TRACE("%p %s %p 0x%08x %p\n", devinfo, debugstr_a(instance_id), hwnd_parent, flags, device_data);
3464 if (!instance_id || strlen(instance_id) >= MAX_DEVICE_ID_LEN)
3466 SetLastError(ERROR_INVALID_PARAMETER);
3467 return FALSE;
3470 MultiByteToWideChar(CP_ACP, 0, instance_id, -1, instance_idW, ARRAY_SIZE(instance_idW));
3471 return SetupDiOpenDeviceInfoW(devinfo, instance_idW, hwnd_parent, flags, device_data);
3474 /***********************************************************************
3475 * SetupDiOpenDeviceInfoW (SETUPAPI.@)
3477 BOOL WINAPI SetupDiOpenDeviceInfoW(HDEVINFO devinfo, PCWSTR instance_id, HWND hwnd_parent, DWORD flags,
3478 PSP_DEVINFO_DATA device_data)
3480 struct DeviceInfoSet *set;
3481 struct device *device;
3482 WCHAR classW[40];
3483 GUID guid;
3484 HKEY enumKey = NULL;
3485 HKEY instanceKey = NULL;
3486 DWORD phantom;
3487 DWORD size;
3488 DWORD error = ERROR_NO_SUCH_DEVINST;
3490 TRACE("%p %s %p 0x%08x %p\n", devinfo, debugstr_w(instance_id), hwnd_parent, flags, device_data);
3492 if (!(set = get_device_set(devinfo)))
3493 return FALSE;
3495 if (!instance_id)
3497 SetLastError(ERROR_INVALID_PARAMETER);
3498 return FALSE;
3501 if (hwnd_parent)
3502 FIXME("hwnd_parent unsupported\n");
3504 if (flags)
3505 FIXME("flags unsupported: 0x%08x\n", flags);
3507 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &enumKey, NULL);
3508 /* Instance needs to be already existent in registry, if not, report ERROR_NO_SUCH_DEVINST */
3509 if (RegOpenKeyExW(enumKey, instance_id, 0, KEY_READ, &instanceKey))
3510 goto done;
3512 /* If it's an unregistered instance, aka phantom instance, report ERROR_NO_SUCH_DEVINST */
3513 size = sizeof(phantom);
3514 if (!RegQueryValueExW(instanceKey, Phantom, NULL, NULL, (BYTE *)&phantom, &size))
3515 goto done;
3517 /* Check class GUID */
3518 size = sizeof(classW);
3519 if (RegQueryValueExW(instanceKey, ClassGUID, NULL, NULL, (BYTE *)classW, &size))
3520 goto done;
3522 classW[37] = 0;
3523 UuidFromStringW(&classW[1], &guid);
3525 if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) && !IsEqualGUID(&guid, &set->ClassGuid))
3527 error = ERROR_CLASS_MISMATCH;
3528 goto done;
3531 if (!(device = create_device(set, &guid, instance_id, FALSE)))
3532 goto done;
3534 if (!device_data || device_data->cbSize == sizeof(SP_DEVINFO_DATA))
3536 if (device_data)
3537 copy_device_data(device_data, device);
3538 error = NO_ERROR;
3540 else
3541 error = ERROR_INVALID_USER_BUFFER;
3543 done:
3544 RegCloseKey(instanceKey);
3545 RegCloseKey(enumKey);
3546 SetLastError(error);
3547 return !error;
3550 /***********************************************************************
3551 * SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
3553 BOOL WINAPI SetupDiOpenDeviceInterfaceW(
3554 HDEVINFO DeviceInfoSet,
3555 PCWSTR DevicePath,
3556 DWORD OpenFlags,
3557 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3559 FIXME("%p %s %08x %p\n",
3560 DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
3561 return FALSE;
3564 /***********************************************************************
3565 * SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
3567 BOOL WINAPI SetupDiOpenDeviceInterfaceA(
3568 HDEVINFO DeviceInfoSet,
3569 PCSTR DevicePath,
3570 DWORD OpenFlags,
3571 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3573 FIXME("%p %s %08x %p\n", DeviceInfoSet,
3574 debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
3575 return FALSE;
3578 /***********************************************************************
3579 * SetupDiOpenDeviceInterfaceRegKey (SETUPAPI.@)
3581 HKEY WINAPI SetupDiOpenDeviceInterfaceRegKey(HDEVINFO devinfo, PSP_DEVICE_INTERFACE_DATA iface_data,
3582 DWORD reserved, REGSAM access)
3584 struct device_iface *iface;
3585 LSTATUS lr;
3586 HKEY key;
3588 TRACE("devinfo %p, iface_data %p, reserved %d, access %#x.\n", devinfo, iface_data, reserved, access);
3590 if (!(iface = get_device_iface(devinfo, iface_data)))
3591 return INVALID_HANDLE_VALUE;
3593 lr = RegOpenKeyExW(iface->refstr_key, DeviceParameters, 0, access, &key);
3594 if (lr)
3596 SetLastError(lr);
3597 return INVALID_HANDLE_VALUE;
3600 return key;
3603 /***********************************************************************
3604 * SetupDiSetClassInstallParamsA (SETUPAPI.@)
3606 BOOL WINAPI SetupDiSetClassInstallParamsA(
3607 HDEVINFO DeviceInfoSet,
3608 PSP_DEVINFO_DATA DeviceInfoData,
3609 PSP_CLASSINSTALL_HEADER ClassInstallParams,
3610 DWORD ClassInstallParamsSize)
3612 FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
3613 ClassInstallParams->InstallFunction, ClassInstallParamsSize);
3614 return FALSE;
3617 /***********************************************************************
3618 * SetupDiSetClassInstallParamsW (SETUPAPI.@)
3620 BOOL WINAPI SetupDiSetClassInstallParamsW(
3621 HDEVINFO DeviceInfoSet,
3622 PSP_DEVINFO_DATA DeviceInfoData,
3623 PSP_CLASSINSTALL_HEADER ClassInstallParams,
3624 DWORD ClassInstallParamsSize)
3626 FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
3627 ClassInstallParams->InstallFunction, ClassInstallParamsSize);
3628 return FALSE;
3631 static BOOL call_coinstallers(WCHAR *list, DI_FUNCTION function, HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
3633 DWORD (CALLBACK *coinst_proc)(DI_FUNCTION, HDEVINFO, SP_DEVINFO_DATA *, COINSTALLER_CONTEXT_DATA *);
3634 COINSTALLER_CONTEXT_DATA coinst_ctx;
3635 WCHAR *p, *procnameW;
3636 HMODULE module;
3637 char *procname;
3638 DWORD ret;
3640 for (p = list; *p; p += lstrlenW(p) + 1)
3642 TRACE("Found co-installer %s.\n", debugstr_w(p));
3643 if ((procnameW = wcschr(p, ',')))
3644 *procnameW = 0;
3646 if ((module = LoadLibraryExW(p, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32)))
3648 if (procnameW)
3650 procname = strdupWtoA(procnameW + 1);
3651 coinst_proc = (void *)GetProcAddress(module, procname);
3652 heap_free(procname);
3654 else
3655 coinst_proc = (void *)GetProcAddress(module, "CoDeviceInstall");
3656 if (coinst_proc)
3658 memset(&coinst_ctx, 0, sizeof(coinst_ctx));
3659 TRACE("Calling co-installer %p.\n", coinst_proc);
3660 ret = coinst_proc(function, devinfo, device_data, &coinst_ctx);
3661 TRACE("Co-installer %p returned %#x.\n", coinst_proc, ret);
3662 if (ret == ERROR_DI_POSTPROCESSING_REQUIRED)
3663 FIXME("Co-installer postprocessing not implemented.\n");
3664 else if (ret)
3666 ERR("Co-installer returned error %#x.\n", ret);
3667 FreeLibrary(module);
3668 SetLastError(ret);
3669 return FALSE;
3672 FreeLibrary(module);
3676 return TRUE;
3679 /***********************************************************************
3680 * SetupDiCallClassInstaller (SETUPAPI.@)
3682 BOOL WINAPI SetupDiCallClassInstaller(DI_FUNCTION function, HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
3684 static const WCHAR class_coinst_pathW[] = {'S','y','s','t','e','m',
3685 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
3686 '\\','C','o','n','t','r','o','l',
3687 '\\','C','o','D','e','v','i','c','e','I','n','s','t','a','l','l','e','r','s',0};
3688 static const WCHAR coinstallers32W[] = {'C','o','I','n','s','t','a','l','l','e','r','s','3','2',0};
3689 static const WCHAR installer32W[] = {'I','n','s','t','a','l','l','e','r','3','2',0};
3690 DWORD (CALLBACK *classinst_proc)(DI_FUNCTION, HDEVINFO, SP_DEVINFO_DATA *);
3691 DWORD ret = ERROR_DI_DO_DEFAULT;
3692 HKEY class_key, coinst_key;
3693 WCHAR *path, *procnameW;
3694 struct device *device;
3695 WCHAR guidstr[39];
3696 BOOL coret = TRUE;
3697 HMODULE module;
3698 char *procname;
3699 DWORD size;
3701 TRACE("function %#x, devinfo %p, device_data %p.\n", function, devinfo, device_data);
3703 if (!(device = get_device(devinfo, device_data)))
3704 return FALSE;
3706 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, class_coinst_pathW, 0, KEY_READ, &coinst_key))
3708 SETUPDI_GuidToString(&device->class, guidstr);
3709 if (!RegGetValueW(coinst_key, NULL, guidstr, RRF_RT_REG_MULTI_SZ, NULL, NULL, &size))
3711 path = heap_alloc(size);
3712 if (!RegGetValueW(coinst_key, NULL, guidstr, RRF_RT_REG_MULTI_SZ, NULL, path, &size))
3713 coret = call_coinstallers(path, function, devinfo, device_data);
3714 heap_free(path);
3716 RegCloseKey(coinst_key);
3719 if (!coret)
3720 return FALSE;
3722 if (!open_driver_key(device, KEY_READ, &coinst_key))
3724 if (!RegGetValueW(coinst_key, NULL, coinstallers32W, RRF_RT_REG_MULTI_SZ, NULL, NULL, &size))
3726 path = heap_alloc(size);
3727 if (!RegGetValueW(coinst_key, NULL, coinstallers32W, RRF_RT_REG_MULTI_SZ, NULL, path, &size))
3728 coret = call_coinstallers(path, function, devinfo, device_data);
3729 heap_free(path);
3731 RegCloseKey(coinst_key);
3734 if ((class_key = SetupDiOpenClassRegKey(&device->class, KEY_READ)) != INVALID_HANDLE_VALUE)
3736 if (!RegGetValueW(class_key, NULL, installer32W, RRF_RT_REG_SZ, NULL, NULL, &size))
3738 path = heap_alloc(size);
3739 if (!RegGetValueW(class_key, NULL, installer32W, RRF_RT_REG_SZ, NULL, path, &size))
3741 TRACE("Found class installer %s.\n", debugstr_w(path));
3742 if ((procnameW = wcschr(path, ',')))
3743 *procnameW = 0;
3745 if ((module = LoadLibraryExW(path, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32)))
3747 if (procnameW)
3749 procname = strdupWtoA(procnameW + 1);
3750 classinst_proc = (void *)GetProcAddress(module, procname);
3751 heap_free(procname);
3753 else
3754 classinst_proc = (void *)GetProcAddress(module, "ClassInstall");
3755 if (classinst_proc)
3757 TRACE("Calling class installer %p.\n", classinst_proc);
3758 ret = classinst_proc(function, devinfo, device_data);
3759 TRACE("Class installer %p returned %#x.\n", classinst_proc, ret);
3761 FreeLibrary(module);
3764 heap_free(path);
3766 RegCloseKey(class_key);
3769 if (ret == ERROR_DI_DO_DEFAULT)
3771 switch (function)
3773 case DIF_REGISTERDEVICE:
3774 return SetupDiRegisterDeviceInfo(devinfo, device_data, 0, NULL, NULL, NULL);
3775 case DIF_REMOVE:
3776 return SetupDiRemoveDevice(devinfo, device_data);
3777 case DIF_SELECTBESTCOMPATDRV:
3778 return SetupDiSelectBestCompatDrv(devinfo, device_data);
3779 case DIF_REGISTER_COINSTALLERS:
3780 return SetupDiRegisterCoDeviceInstallers(devinfo, device_data);
3781 case DIF_INSTALLDEVICEFILES:
3782 return SetupDiInstallDriverFiles(devinfo, device_data);
3783 case DIF_INSTALLINTERFACES:
3784 return SetupDiInstallDeviceInterfaces(devinfo, device_data);
3785 case DIF_INSTALLDEVICE:
3786 return SetupDiInstallDevice(devinfo, device_data);
3787 case DIF_FINISHINSTALL_ACTION:
3788 case DIF_PROPERTYCHANGE:
3789 case DIF_SELECTDEVICE:
3790 case DIF_UNREMOVE:
3791 FIXME("Unhandled function %#x.\n", function);
3795 if (ret) SetLastError(ret);
3796 return !ret;
3799 /***********************************************************************
3800 * SetupDiGetDeviceInstallParamsW (SETUPAPI.@)
3802 BOOL WINAPI SetupDiGetDeviceInstallParamsW(HDEVINFO devinfo,
3803 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_W *params)
3805 struct device *device;
3807 TRACE("devinfo %p, device_data %p, params %p.\n", devinfo, device_data, params);
3809 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
3811 SetLastError(ERROR_INVALID_USER_BUFFER);
3812 return FALSE;
3815 if (!(device = get_device(devinfo, device_data)))
3816 return FALSE;
3818 *params = device->params;
3820 return TRUE;
3823 /***********************************************************************
3824 * SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
3826 BOOL WINAPI SetupDiGetDeviceInstallParamsA(HDEVINFO devinfo,
3827 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_A *params)
3829 SP_DEVINSTALL_PARAMS_W paramsW;
3830 BOOL ret;
3832 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
3834 SetLastError(ERROR_INVALID_USER_BUFFER);
3835 return FALSE;
3838 paramsW.cbSize = sizeof(paramsW);
3839 ret = SetupDiGetDeviceInstallParamsW(devinfo, device_data, &paramsW);
3840 params->Flags = paramsW.Flags;
3841 params->FlagsEx = paramsW.FlagsEx;
3842 params->hwndParent = paramsW.hwndParent;
3843 params->InstallMsgHandler = paramsW.InstallMsgHandler;
3844 params->InstallMsgHandlerContext = paramsW.InstallMsgHandlerContext;
3845 params->FileQueue = paramsW.FileQueue;
3846 params->ClassInstallReserved = paramsW.ClassInstallReserved;
3847 params->Reserved = paramsW.Reserved;
3848 WideCharToMultiByte(CP_ACP, 0, paramsW.DriverPath, -1, params->DriverPath, sizeof(params->DriverPath), NULL, NULL);
3850 return ret;
3853 /***********************************************************************
3854 * SetupDiSetDeviceInstallParamsA (SETUPAPI.@)
3856 BOOL WINAPI SetupDiSetDeviceInstallParamsA(HDEVINFO devinfo,
3857 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_A *params)
3859 SP_DEVINSTALL_PARAMS_W paramsW;
3861 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
3863 SetLastError(ERROR_INVALID_USER_BUFFER);
3864 return FALSE;
3867 paramsW.cbSize = sizeof(paramsW);
3868 paramsW.Flags = params->Flags;
3869 paramsW.FlagsEx = params->FlagsEx;
3870 paramsW.hwndParent = params->hwndParent;
3871 paramsW.InstallMsgHandler = params->InstallMsgHandler;
3872 paramsW.InstallMsgHandlerContext = params->InstallMsgHandlerContext;
3873 paramsW.FileQueue = params->FileQueue;
3874 paramsW.ClassInstallReserved = params->ClassInstallReserved;
3875 paramsW.Reserved = params->Reserved;
3876 MultiByteToWideChar(CP_ACP, 0, params->DriverPath, -1, paramsW.DriverPath, ARRAY_SIZE(paramsW.DriverPath));
3878 return SetupDiSetDeviceInstallParamsW(devinfo, device_data, &paramsW);
3881 /***********************************************************************
3882 * SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
3884 BOOL WINAPI SetupDiSetDeviceInstallParamsW(HDEVINFO devinfo,
3885 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_W *params)
3887 struct device *device;
3889 TRACE("devinfo %p, device_data %p, params %p.\n", devinfo, device_data, params);
3891 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
3893 SetLastError(ERROR_INVALID_USER_BUFFER);
3894 return FALSE;
3897 if (!(device = get_device(devinfo, device_data)))
3898 return FALSE;
3900 device->params = *params;
3902 return TRUE;
3905 BOOL WINAPI SetupDiSetDevicePropertyW(HDEVINFO devinfo, PSP_DEVINFO_DATA device_data, const DEVPROPKEY *key,
3906 DEVPROPTYPE type, const BYTE *buffer, DWORD size, DWORD flags)
3908 static const WCHAR propertiesW[] = {'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's', 0};
3909 static const WCHAR formatW[] = {'\\', '%', '0', '4', 'X', 0};
3910 struct device *device;
3911 HKEY properties_hkey, property_hkey;
3912 WCHAR property_hkey_path[44];
3913 LSTATUS ls;
3915 TRACE("%p %p %p %#x %p %d %#x\n", devinfo, device_data, key, type, buffer, size, flags);
3917 if (!(device = get_device(devinfo, device_data)))
3918 return FALSE;
3920 if (!key || !is_valid_property_type(type)
3921 || (buffer && !size && !(type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL))
3922 || (buffer && size && (type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL)))
3924 SetLastError(ERROR_INVALID_DATA);
3925 return FALSE;
3928 if (size && !buffer)
3930 SetLastError(ERROR_INVALID_USER_BUFFER);
3931 return FALSE;
3934 if (flags)
3936 SetLastError(ERROR_INVALID_FLAGS);
3937 return FALSE;
3940 ls = RegCreateKeyExW(device->key, propertiesW, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &properties_hkey, NULL);
3941 if (ls)
3943 SetLastError(ls);
3944 return FALSE;
3947 SETUPDI_GuidToString(&key->fmtid, property_hkey_path);
3948 swprintf(property_hkey_path + 38, ARRAY_SIZE(property_hkey_path) - 38, formatW, key->pid);
3950 if (type == DEVPROP_TYPE_EMPTY)
3952 ls = RegDeleteKeyW(properties_hkey, property_hkey_path);
3953 RegCloseKey(properties_hkey);
3954 SetLastError(ls == ERROR_FILE_NOT_FOUND ? ERROR_NOT_FOUND : ls);
3955 return !ls;
3957 else if (type == DEVPROP_TYPE_NULL)
3959 if (!(ls = RegOpenKeyW(properties_hkey, property_hkey_path, &property_hkey)))
3961 ls = RegDeleteValueW(property_hkey, NULL);
3962 RegCloseKey(property_hkey);
3965 RegCloseKey(properties_hkey);
3966 SetLastError(ls == ERROR_FILE_NOT_FOUND ? ERROR_NOT_FOUND : ls);
3967 return !ls;
3969 else
3971 if (!(ls = RegCreateKeyExW(properties_hkey, property_hkey_path, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL,
3972 &property_hkey, NULL)))
3974 ls = RegSetValueExW(property_hkey, NULL, 0, 0xffff0000 | (0xffff & type), buffer, size);
3975 RegCloseKey(property_hkey);
3978 RegCloseKey(properties_hkey);
3979 SetLastError(ls);
3980 return !ls;
3984 /***********************************************************************
3985 * SetupDiOpenDevRegKey (SETUPAPI.@)
3987 HKEY WINAPI SetupDiOpenDevRegKey(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
3988 DWORD Scope, DWORD HwProfile, DWORD KeyType, REGSAM samDesired)
3990 struct device *device;
3991 HKEY key = INVALID_HANDLE_VALUE;
3992 LONG l;
3994 TRACE("devinfo %p, device_data %p, scope %d, profile %d, type %d, access %#x.\n",
3995 devinfo, device_data, Scope, HwProfile, KeyType, samDesired);
3997 if (!(device = get_device(devinfo, device_data)))
3998 return INVALID_HANDLE_VALUE;
4000 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
4002 SetLastError(ERROR_INVALID_FLAGS);
4003 return INVALID_HANDLE_VALUE;
4005 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
4007 SetLastError(ERROR_INVALID_FLAGS);
4008 return INVALID_HANDLE_VALUE;
4011 if (device->phantom)
4013 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
4014 return INVALID_HANDLE_VALUE;
4016 if (Scope != DICS_FLAG_GLOBAL)
4017 FIXME("unimplemented for scope %d\n", Scope);
4018 switch (KeyType)
4020 case DIREG_DEV:
4021 l = RegOpenKeyExW(device->key, DeviceParameters, 0, samDesired, &key);
4022 break;
4023 case DIREG_DRV:
4024 l = open_driver_key(device, samDesired, &key);
4025 break;
4026 default:
4027 FIXME("Unhandled type %#x.\n", KeyType);
4028 l = ERROR_CALL_NOT_IMPLEMENTED;
4030 SetLastError(l == ERROR_FILE_NOT_FOUND ? ERROR_KEY_DOES_NOT_EXIST : l);
4031 return l ? INVALID_HANDLE_VALUE : key;
4034 /***********************************************************************
4035 * SetupDiDeleteDevRegKey (SETUPAPI.@)
4037 BOOL WINAPI SetupDiDeleteDevRegKey(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4038 DWORD Scope, DWORD HwProfile, DWORD KeyType)
4040 struct device *device;
4041 LONG l;
4043 TRACE("devinfo %p, device_data %p, scope %d, profile %d, type %d.\n",
4044 devinfo, device_data, Scope, HwProfile, KeyType);
4046 if (!(device = get_device(devinfo, device_data)))
4047 return FALSE;
4049 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
4051 SetLastError(ERROR_INVALID_FLAGS);
4052 return FALSE;
4054 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV && KeyType != DIREG_BOTH)
4056 SetLastError(ERROR_INVALID_FLAGS);
4057 return FALSE;
4060 if (device->phantom)
4062 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
4063 return FALSE;
4065 if (Scope != DICS_FLAG_GLOBAL)
4066 FIXME("unimplemented for scope %d\n", Scope);
4067 switch (KeyType)
4069 case DIREG_DRV:
4070 l = delete_driver_key(device);
4071 break;
4072 case DIREG_BOTH:
4073 if ((l = delete_driver_key(device)))
4074 break;
4075 /* fall through */
4076 case DIREG_DEV:
4077 l = RegDeleteKeyW(device->key, DeviceParameters);
4078 break;
4079 default:
4080 FIXME("Unhandled type %#x.\n", KeyType);
4081 l = ERROR_CALL_NOT_IMPLEMENTED;
4083 SetLastError(l);
4084 return !l;
4087 /***********************************************************************
4088 * CM_Get_Device_IDA (SETUPAPI.@)
4090 CONFIGRET WINAPI CM_Get_Device_IDA(DEVINST devnode, char *buffer, ULONG len, ULONG flags)
4092 struct device *device = get_devnode_device(devnode);
4094 TRACE("%u, %p, %u, %#x\n", devnode, buffer, len, flags);
4096 if (!device)
4097 return CR_NO_SUCH_DEVINST;
4099 WideCharToMultiByte(CP_ACP, 0, device->instanceId, -1, buffer, len, 0, 0);
4100 TRACE("Returning %s\n", debugstr_a(buffer));
4101 return CR_SUCCESS;
4104 /***********************************************************************
4105 * CM_Get_Device_IDW (SETUPAPI.@)
4107 CONFIGRET WINAPI CM_Get_Device_IDW(DEVINST devnode, WCHAR *buffer, ULONG len, ULONG flags)
4109 struct device *device = get_devnode_device(devnode);
4111 TRACE("%u, %p, %u, %#x\n", devnode, buffer, len, flags);
4113 if (!device)
4114 return CR_NO_SUCH_DEVINST;
4116 lstrcpynW(buffer, device->instanceId, len);
4117 TRACE("Returning %s\n", debugstr_w(buffer));
4118 return CR_SUCCESS;
4121 /***********************************************************************
4122 * CM_Get_Device_ID_Size (SETUPAPI.@)
4124 CONFIGRET WINAPI CM_Get_Device_ID_Size(ULONG *len, DEVINST devnode, ULONG flags)
4126 struct device *device = get_devnode_device(devnode);
4128 TRACE("%p, %u, %#x\n", len, devnode, flags);
4130 if (!device)
4131 return CR_NO_SUCH_DEVINST;
4133 *len = lstrlenW(device->instanceId);
4134 return CR_SUCCESS;
4137 /***********************************************************************
4138 * SetupDiGetINFClassA (SETUPAPI.@)
4140 BOOL WINAPI SetupDiGetINFClassA(PCSTR inf, LPGUID class_guid, PSTR class_name,
4141 DWORD size, PDWORD required_size)
4143 BOOL retval;
4144 DWORD required_sizeA, required_sizeW;
4145 PWSTR class_nameW = NULL;
4146 UNICODE_STRING infW;
4148 if (inf)
4150 if (!RtlCreateUnicodeStringFromAsciiz(&infW, inf))
4152 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4153 return FALSE;
4156 else
4157 infW.Buffer = NULL;
4159 if (class_name && size)
4161 if (!(class_nameW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR))))
4163 RtlFreeUnicodeString(&infW);
4164 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4165 return FALSE;
4169 retval = SetupDiGetINFClassW(infW.Buffer, class_guid, class_nameW, size, &required_sizeW);
4171 if (retval)
4173 required_sizeA = WideCharToMultiByte( CP_ACP, 0, class_nameW, required_sizeW,
4174 class_name, size, NULL, NULL);
4176 if(required_size) *required_size = required_sizeA;
4178 else
4179 if(required_size) *required_size = required_sizeW;
4181 HeapFree(GetProcessHeap(), 0, class_nameW);
4182 RtlFreeUnicodeString(&infW);
4183 return retval;
4186 /***********************************************************************
4187 * SetupDiGetINFClassW (SETUPAPI.@)
4189 BOOL WINAPI SetupDiGetINFClassW(PCWSTR inf, LPGUID class_guid, PWSTR class_name,
4190 DWORD size, PDWORD required_size)
4192 BOOL have_guid, have_name;
4193 DWORD dret;
4194 WCHAR buffer[MAX_PATH];
4196 if (!inf)
4198 SetLastError(ERROR_INVALID_PARAMETER);
4199 return FALSE;
4202 if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(inf))
4204 FIXME("%s not found. Searching via DevicePath not implemented\n", debugstr_w(inf));
4205 SetLastError(ERROR_FILE_NOT_FOUND);
4206 return FALSE;
4209 if (!class_guid || !class_name || !size)
4211 SetLastError(ERROR_INVALID_PARAMETER);
4212 return FALSE;
4215 if (!GetPrivateProfileStringW(Version, Signature, NULL, buffer, MAX_PATH, inf))
4216 return FALSE;
4218 if (lstrcmpiW(buffer, Chicago) && lstrcmpiW(buffer, WindowsNT))
4219 return FALSE;
4221 buffer[0] = '\0';
4222 have_guid = 0 < GetPrivateProfileStringW(Version, ClassGUID, NULL, buffer, MAX_PATH, inf);
4223 if (have_guid)
4225 buffer[lstrlenW(buffer)-1] = 0;
4226 if (RPC_S_OK != UuidFromStringW(buffer + 1, class_guid))
4228 FIXME("failed to convert \"%s\" into a guid\n", debugstr_w(buffer));
4229 SetLastError(ERROR_INVALID_PARAMETER);
4230 return FALSE;
4234 buffer[0] = '\0';
4235 dret = GetPrivateProfileStringW(Version, Class, NULL, buffer, MAX_PATH, inf);
4236 have_name = 0 < dret;
4238 if (dret >= MAX_PATH -1) FIXME("buffer might be too small\n");
4239 if (have_guid && !have_name)
4241 class_name[0] = '\0';
4242 FIXME("class name lookup via guid not implemented\n");
4245 if (have_name)
4247 if (dret < size) lstrcpyW(class_name, buffer);
4248 else
4250 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4251 have_name = FALSE;
4255 if (required_size) *required_size = dret + ((dret) ? 1 : 0);
4257 return (have_guid || have_name);
4260 static LSTATUS get_device_property(struct device *device, const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type,
4261 BYTE *prop_buff, DWORD prop_buff_size, DWORD *required_size, DWORD flags)
4263 WCHAR key_path[55] = L"Properties\\";
4264 HKEY hkey;
4265 DWORD value_type;
4266 DWORD value_size = 0;
4267 LSTATUS ls;
4269 if (!prop_key)
4270 return ERROR_INVALID_DATA;
4272 if (!prop_type || (!prop_buff && prop_buff_size))
4273 return ERROR_INVALID_USER_BUFFER;
4275 if (flags)
4276 return ERROR_INVALID_FLAGS;
4278 SETUPDI_GuidToString(&prop_key->fmtid, key_path + 11);
4279 swprintf(key_path + 49, ARRAY_SIZE(key_path) - 49, L"\\%04X", prop_key->pid);
4281 ls = RegOpenKeyExW(device->key, key_path, 0, KEY_QUERY_VALUE, &hkey);
4282 if (!ls)
4284 value_size = prop_buff_size;
4285 ls = RegQueryValueExW(hkey, NULL, NULL, &value_type, prop_buff, &value_size);
4286 RegCloseKey(hkey);
4289 switch (ls)
4291 case NO_ERROR:
4292 case ERROR_MORE_DATA:
4293 *prop_type = 0xffff & value_type;
4294 ls = (ls == ERROR_MORE_DATA || !prop_buff) ? ERROR_INSUFFICIENT_BUFFER : NO_ERROR;
4295 break;
4296 case ERROR_FILE_NOT_FOUND:
4297 *prop_type = DEVPROP_TYPE_EMPTY;
4298 value_size = 0;
4299 ls = ERROR_NOT_FOUND;
4300 break;
4301 default:
4302 *prop_type = DEVPROP_TYPE_EMPTY;
4303 value_size = 0;
4304 FIXME("Unhandled error %#x\n", ls);
4305 break;
4308 if (required_size)
4309 *required_size = value_size;
4311 return ls;
4314 /***********************************************************************
4315 * SetupDiGetDevicePropertyW (SETUPAPI.@)
4317 BOOL WINAPI SetupDiGetDevicePropertyW(HDEVINFO devinfo, PSP_DEVINFO_DATA device_data,
4318 const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type, BYTE *prop_buff,
4319 DWORD prop_buff_size, DWORD *required_size, DWORD flags)
4321 struct device *device;
4322 LSTATUS ls;
4324 TRACE("%p, %p, %p, %p, %p, %d, %p, %#x\n", devinfo, device_data, prop_key, prop_type, prop_buff, prop_buff_size,
4325 required_size, flags);
4327 if (!(device = get_device(devinfo, device_data)))
4328 return FALSE;
4330 ls = get_device_property(device, prop_key, prop_type, prop_buff, prop_buff_size, required_size, flags);
4332 SetLastError(ls);
4333 return !ls;
4336 /***********************************************************************
4337 * CM_Get_DevNode_Property_ExW (SETUPAPI.@)
4339 CONFIGRET WINAPI CM_Get_DevNode_Property_ExW(DEVINST devnode, const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type,
4340 BYTE *prop_buff, ULONG *prop_buff_size, ULONG flags, HMACHINE machine)
4342 struct device *device = get_devnode_device(devnode);
4343 LSTATUS ls;
4345 TRACE("%u, %p, %p, %p, %p, %#x, %p\n", devnode, prop_key, prop_type, prop_buff, prop_buff_size,
4346 flags, machine);
4348 if (machine)
4349 return CR_MACHINE_UNAVAILABLE;
4351 if (!device)
4352 return CR_NO_SUCH_DEVINST;
4354 if (!prop_buff_size)
4355 return CR_INVALID_POINTER;
4357 ls = get_device_property(device, prop_key, prop_type, prop_buff, *prop_buff_size, prop_buff_size, flags);
4358 switch (ls)
4360 case NO_ERROR:
4361 return CR_SUCCESS;
4362 case ERROR_INVALID_DATA:
4363 return CR_INVALID_DATA;
4364 case ERROR_INVALID_USER_BUFFER:
4365 return CR_INVALID_POINTER;
4366 case ERROR_INVALID_FLAGS:
4367 return CR_INVALID_FLAG;
4368 case ERROR_INSUFFICIENT_BUFFER:
4369 return CR_BUFFER_SMALL;
4370 case ERROR_NOT_FOUND:
4371 return CR_NO_SUCH_VALUE;
4373 return CR_FAILURE;
4376 /***********************************************************************
4377 * CM_Get_DevNode_PropertyW (SETUPAPI.@)
4379 CONFIGRET WINAPI CM_Get_DevNode_PropertyW(DEVINST dev, const DEVPROPKEY *key, DEVPROPTYPE *type,
4380 PVOID buf, PULONG len, ULONG flags)
4382 return CM_Get_DevNode_Property_ExW(dev, key, type, buf, len, flags, NULL);
4385 /***********************************************************************
4386 * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
4388 BOOL WINAPI SetupDiInstallDeviceInterfaces(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4390 WCHAR section_ext[LINE_LEN], iface_section[LINE_LEN], refstr[LINE_LEN], guidstr[39];
4391 UINT install_flags = SPINST_ALL;
4392 struct device_iface *iface;
4393 struct device *device;
4394 struct driver *driver;
4395 void *callback_ctx;
4396 GUID iface_guid;
4397 INFCONTEXT ctx;
4398 HKEY iface_key;
4399 HINF hinf;
4400 LONG l;
4402 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
4404 if (!(device = get_device(devinfo, device_data)))
4405 return FALSE;
4407 if (!(driver = device->selected_driver))
4409 ERR("No driver selected for device %p.\n", devinfo);
4410 SetLastError(ERROR_NO_DRIVER_SELECTED);
4411 return FALSE;
4414 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4415 return FALSE;
4417 SetupDiGetActualSectionToInstallW(hinf, driver->section, section_ext, ARRAY_SIZE(section_ext), NULL, NULL);
4419 if (device->params.Flags & DI_NOFILECOPY)
4420 install_flags &= ~SPINST_FILES;
4422 callback_ctx = SetupInitDefaultQueueCallback(NULL);
4424 lstrcatW(section_ext, dotInterfaces);
4425 if (SetupFindFirstLineW(hinf, section_ext, AddInterface, &ctx))
4427 do {
4428 SetupGetStringFieldW(&ctx, 1, guidstr, ARRAY_SIZE(guidstr), NULL);
4429 SetupGetStringFieldW(&ctx, 2, refstr, ARRAY_SIZE(refstr), NULL);
4430 guidstr[37] = 0;
4431 UuidFromStringW(&guidstr[1], &iface_guid);
4433 if (!(iface = SETUPDI_CreateDeviceInterface(device, &iface_guid, refstr)))
4435 ERR("Failed to create device interface, error %#x.\n", GetLastError());
4436 continue;
4439 if ((l = create_iface_key(iface, KEY_ALL_ACCESS, &iface_key)))
4441 ERR("Failed to create interface key, error %u.\n", l);
4442 continue;
4445 SetupGetStringFieldW(&ctx, 3, iface_section, ARRAY_SIZE(iface_section), NULL);
4446 SetupInstallFromInfSectionW(NULL, hinf, iface_section, install_flags, iface_key,
4447 NULL, SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
4449 RegCloseKey(iface_key);
4450 } while (SetupFindNextMatchLineW(&ctx, AddInterface, &ctx));
4453 SetupTermDefaultQueueCallback(callback_ctx);
4455 SetupCloseInfFile(hinf);
4456 return TRUE;
4459 /***********************************************************************
4460 * SetupDiRegisterCoDeviceInstallers (SETUPAPI.@)
4462 BOOL WINAPI SetupDiRegisterCoDeviceInstallers(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4464 static const WCHAR coinstallersW[] = {'.','C','o','I','n','s','t','a','l','l','e','r','s',0};
4465 WCHAR coinst_key_ext[LINE_LEN];
4466 struct device *device;
4467 struct driver *driver;
4468 void *callback_ctx;
4469 HKEY driver_key;
4470 HINF hinf;
4471 LONG l;
4473 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
4475 if (!(device = get_device(devinfo, device_data)))
4476 return FALSE;
4478 if (!(driver = device->selected_driver))
4480 ERR("No driver selected for device %p.\n", devinfo);
4481 SetLastError(ERROR_NO_DRIVER_SELECTED);
4482 return FALSE;
4485 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4486 return FALSE;
4488 SetupDiGetActualSectionToInstallW(hinf, driver->section, coinst_key_ext, ARRAY_SIZE(coinst_key_ext), NULL, NULL);
4489 lstrcatW(coinst_key_ext, coinstallersW);
4491 if ((l = create_driver_key(device, &driver_key)))
4493 SetLastError(l);
4494 SetupCloseInfFile(hinf);
4495 return FALSE;
4498 callback_ctx = SetupInitDefaultQueueCallback(NULL);
4499 SetupInstallFromInfSectionW(NULL, hinf, coinst_key_ext, SPINST_ALL, driver_key, NULL,
4500 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
4501 SetupTermDefaultQueueCallback(callback_ctx);
4503 RegCloseKey(driver_key);
4504 SetupCloseInfFile(hinf);
4505 return TRUE;
4508 /* Check whether the given hardware or compatible ID matches any of the device's
4509 * own hardware or compatible IDs. */
4510 static BOOL device_matches_id(const struct device *device, const WCHAR *id_type, const WCHAR *id)
4512 WCHAR *device_ids;
4513 const WCHAR *p;
4514 DWORD size;
4516 if (!RegGetValueW(device->key, NULL, id_type, RRF_RT_REG_MULTI_SZ, NULL, NULL, &size))
4518 device_ids = heap_alloc(size);
4519 if (!RegGetValueW(device->key, NULL, id_type, RRF_RT_REG_MULTI_SZ, NULL, device_ids, &size))
4521 for (p = device_ids; *p; p += lstrlenW(p) + 1)
4523 if (!wcsicmp(p, id))
4525 heap_free(device_ids);
4526 return TRUE;
4530 heap_free(device_ids);
4533 return FALSE;
4536 static BOOL version_is_compatible(const WCHAR *version)
4538 const WCHAR *machine_ext = NtPlatformExtension + 1, *p;
4539 size_t len = lstrlenW(version);
4540 BOOL wow64;
4542 /* We are only concerned with architecture. */
4543 if ((p = wcschr(version, '.')))
4544 len = p - version;
4546 if (!wcsnicmp(version, NtExtension + 1, len))
4547 return TRUE;
4549 if (IsWow64Process(GetCurrentProcess(), &wow64) && wow64)
4551 #ifdef __i386__
4552 static const WCHAR wow_ext[] = {'N','T','a','m','d','6','4',0};
4553 machine_ext = wow_ext;
4554 #elif defined(__arm__)
4555 static const WCHAR wow_ext[] = {'N','T','a','r','m','6','4',0};
4556 machine_ext = wow_ext;
4557 #endif
4560 return !wcsnicmp(version, machine_ext, len);
4563 static void enum_compat_drivers_from_file(struct device *device, const WCHAR *path)
4565 static const WCHAR manufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4566 WCHAR mfg_name[LINE_LEN], mfg_key[LINE_LEN], mfg_key_ext[LINE_LEN], id[MAX_DEVICE_ID_LEN], version[MAX_DEVICE_ID_LEN];
4567 INFCONTEXT ctx;
4568 DWORD i, j, k;
4569 HINF hinf;
4571 TRACE("Enumerating drivers from %s.\n", debugstr_w(path));
4573 if ((hinf = SetupOpenInfFileW(path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4574 return;
4576 for (i = 0; SetupGetLineByIndexW(hinf, manufacturerW, i, &ctx); ++i)
4578 SetupGetStringFieldW(&ctx, 0, mfg_name, ARRAY_SIZE(mfg_name), NULL);
4579 if (!SetupGetStringFieldW(&ctx, 1, mfg_key, ARRAY_SIZE(mfg_key), NULL))
4580 lstrcpyW(mfg_key, mfg_name);
4582 if (SetupGetFieldCount(&ctx) >= 2)
4584 BOOL compatible = FALSE;
4585 for (j = 2; SetupGetStringFieldW(&ctx, j, version, ARRAY_SIZE(version), NULL); ++j)
4587 if (version_is_compatible(version))
4589 compatible = TRUE;
4590 break;
4593 if (!compatible)
4594 continue;
4597 if (!SetupDiGetActualSectionToInstallW(hinf, mfg_key, mfg_key_ext, ARRAY_SIZE(mfg_key_ext), NULL, NULL))
4599 WARN("Failed to find section for %s, skipping.\n", debugstr_w(mfg_key));
4600 continue;
4603 for (j = 0; SetupGetLineByIndexW(hinf, mfg_key_ext, j, &ctx); ++j)
4605 for (k = 2; SetupGetStringFieldW(&ctx, k, id, ARRAY_SIZE(id), NULL); ++k)
4607 if (device_matches_id(device, HardwareId, id) || device_matches_id(device, CompatibleIDs, id))
4609 unsigned int count = ++device->driver_count;
4611 device->drivers = heap_realloc(device->drivers, count * sizeof(*device->drivers));
4612 lstrcpyW(device->drivers[count - 1].inf_path, path);
4613 lstrcpyW(device->drivers[count - 1].manufacturer, mfg_name);
4614 lstrcpyW(device->drivers[count - 1].mfg_key, mfg_key_ext);
4615 SetupGetStringFieldW(&ctx, 0, device->drivers[count - 1].description,
4616 ARRAY_SIZE(device->drivers[count - 1].description), NULL);
4617 SetupGetStringFieldW(&ctx, 1, device->drivers[count - 1].section,
4618 ARRAY_SIZE(device->drivers[count - 1].section), NULL);
4620 TRACE("Found compatible driver: manufacturer %s, desc %s.\n",
4621 debugstr_w(mfg_name), debugstr_w(device->drivers[count - 1].description));
4627 SetupCloseInfFile(hinf);
4630 /***********************************************************************
4631 * SetupDiBuildDriverInfoList (SETUPAPI.@)
4633 BOOL WINAPI SetupDiBuildDriverInfoList(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD type)
4635 struct device *device;
4637 TRACE("devinfo %p, device_data %p, type %#x.\n", devinfo, device_data, type);
4639 if (type != SPDIT_COMPATDRIVER)
4641 FIXME("Unhandled type %#x.\n", type);
4642 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4643 return FALSE;
4646 if (!(device = get_device(devinfo, device_data)))
4647 return FALSE;
4649 if (device->params.Flags & DI_ENUMSINGLEINF)
4651 enum_compat_drivers_from_file(device, device->params.DriverPath);
4653 else
4655 static const WCHAR default_path[] = {'C',':','/','w','i','n','d','o','w','s','/','i','n','f',0};
4656 static const WCHAR wildcardW[] = {'*',0};
4657 WCHAR dir[MAX_PATH], file[MAX_PATH];
4658 WIN32_FIND_DATAW find_data;
4659 HANDLE find_handle;
4661 if (device->params.DriverPath[0])
4662 lstrcpyW(dir, device->params.DriverPath);
4663 else
4664 lstrcpyW(dir, default_path);
4665 lstrcatW(dir, backslashW);
4666 lstrcatW(dir, wildcardW);
4668 TRACE("Searching for drivers in %s.\n", debugstr_w(dir));
4670 if ((find_handle = FindFirstFileW(dir, &find_data)) != INVALID_HANDLE_VALUE)
4674 lstrcpyW(file, dir);
4675 lstrcpyW(file + lstrlenW(file) - 1, find_data.cFileName);
4676 enum_compat_drivers_from_file(device, file);
4677 } while (FindNextFileW(find_handle, &find_data));
4679 FindClose(find_handle);
4683 if (device->driver_count)
4685 WCHAR classname[MAX_CLASS_NAME_LEN], guidstr[39];
4686 GUID class;
4688 if (SetupDiGetINFClassW(device->drivers[0].inf_path, &class, classname, ARRAY_SIZE(classname), NULL))
4690 device_data->ClassGuid = device->class = class;
4691 SETUPDI_GuidToString(&class, guidstr);
4692 RegSetValueExW(device->key, L"ClassGUID", 0, REG_SZ, (BYTE *)guidstr, sizeof(guidstr));
4693 RegSetValueExW(device->key, L"Class", 0, REG_SZ, (BYTE *)classname, wcslen(classname) * sizeof(WCHAR));
4697 return TRUE;
4700 static BOOL copy_driver_data(SP_DRVINFO_DATA_W *data, const struct driver *driver)
4702 INFCONTEXT ctx;
4703 HINF hinf;
4705 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4706 return FALSE;
4708 data->ProviderName[0] = 0;
4709 if (SetupFindFirstLineW(hinf, L"Version", L"Provider", &ctx))
4710 SetupGetStringFieldW(&ctx, 1, data->ProviderName, ARRAY_SIZE(data->ProviderName), NULL);
4711 wcscpy(data->Description, driver->description);
4712 wcscpy(data->MfgName, driver->manufacturer);
4713 data->DriverType = SPDIT_COMPATDRIVER;
4714 data->Reserved = (ULONG_PTR)driver;
4716 SetupCloseInfFile(hinf);
4718 return TRUE;
4721 static void driver_data_wtoa(SP_DRVINFO_DATA_A *a, const SP_DRVINFO_DATA_W *w)
4723 a->DriverType = w->DriverType;
4724 a->Reserved = w->Reserved;
4725 WideCharToMultiByte(CP_ACP, 0, w->Description, -1, a->Description, sizeof(a->Description), NULL, NULL);
4726 WideCharToMultiByte(CP_ACP, 0, w->MfgName, -1, a->MfgName, sizeof(a->MfgName), NULL, NULL);
4727 WideCharToMultiByte(CP_ACP, 0, w->ProviderName, -1, a->ProviderName, sizeof(a->ProviderName), NULL, NULL);
4730 /***********************************************************************
4731 * SetupDiEnumDriverInfoW (SETUPAPI.@)
4733 BOOL WINAPI SetupDiEnumDriverInfoW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4734 DWORD type, DWORD index, SP_DRVINFO_DATA_W *driver_data)
4736 struct device *device;
4738 TRACE("devinfo %p, device_data %p, type %#x, index %u, driver_data %p.\n",
4739 devinfo, device_data, type, index, driver_data);
4741 if (type != SPDIT_COMPATDRIVER)
4743 FIXME("Unhandled type %#x.\n", type);
4744 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4745 return FALSE;
4748 if (!(device = get_device(devinfo, device_data)))
4749 return FALSE;
4751 if (index >= device->driver_count)
4753 SetLastError(ERROR_NO_MORE_ITEMS);
4754 return FALSE;
4757 return copy_driver_data(driver_data, &device->drivers[index]);
4760 /***********************************************************************
4761 * SetupDiEnumDriverInfoA (SETUPAPI.@)
4763 BOOL WINAPI SetupDiEnumDriverInfoA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4764 DWORD type, DWORD index, SP_DRVINFO_DATA_A *driver_data)
4766 SP_DRVINFO_DATA_W driver_dataW;
4767 BOOL ret;
4769 driver_dataW.cbSize = sizeof(driver_dataW);
4770 ret = SetupDiEnumDriverInfoW(devinfo, device_data, type, index, &driver_dataW);
4771 if (ret) driver_data_wtoa(driver_data, &driver_dataW);
4773 return ret;
4776 /***********************************************************************
4777 * SetupDiSelectBestCompatDrv (SETUPAPI.@)
4779 BOOL WINAPI SetupDiSelectBestCompatDrv(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4781 struct device *device;
4783 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
4785 if (!(device = get_device(devinfo, device_data)))
4786 return FALSE;
4788 if (!device->driver_count)
4790 WARN("No compatible drivers were enumerated for device %s.\n", debugstr_w(device->instanceId));
4791 SetLastError(ERROR_NO_COMPAT_DRIVERS);
4792 return FALSE;
4795 WARN("Semi-stub, selecting the first available driver.\n");
4797 device->selected_driver = &device->drivers[0];
4799 return TRUE;
4802 /***********************************************************************
4803 * SetupDiGetSelectedDriverW (SETUPAPI.@)
4805 BOOL WINAPI SetupDiGetSelectedDriverW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, SP_DRVINFO_DATA_W *driver_data)
4807 struct device *device;
4809 TRACE("devinfo %p, device_data %p, driver_data %p.\n", devinfo, device_data, driver_data);
4811 if (!(device = get_device(devinfo, device_data)))
4812 return FALSE;
4814 if (!device->selected_driver)
4816 SetLastError(ERROR_NO_DRIVER_SELECTED);
4817 return FALSE;
4820 return copy_driver_data(driver_data, device->selected_driver);
4823 /***********************************************************************
4824 * SetupDiGetSelectedDriverA (SETUPAPI.@)
4826 BOOL WINAPI SetupDiGetSelectedDriverA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, SP_DRVINFO_DATA_A *driver_data)
4828 SP_DRVINFO_DATA_W driver_dataW;
4829 BOOL ret;
4831 driver_dataW.cbSize = sizeof(driver_dataW);
4832 if ((ret = SetupDiGetSelectedDriverW(devinfo, device_data, &driver_dataW)))
4833 driver_data_wtoa(driver_data, &driver_dataW);
4834 return ret;
4837 /***********************************************************************
4838 * SetupDiGetDriverInfoDetailW (SETUPAPI.@)
4840 BOOL WINAPI SetupDiGetDriverInfoDetailW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4841 SP_DRVINFO_DATA_W *driver_data, SP_DRVINFO_DETAIL_DATA_W *detail_data, const DWORD size, DWORD *ret_size)
4843 struct driver *driver = (struct driver *)driver_data->Reserved;
4844 DWORD size_needed, i, id_size = 1;
4845 WCHAR id[MAX_DEVICE_ID_LEN];
4846 INFCONTEXT ctx;
4847 HANDLE file;
4848 HINF hinf;
4850 TRACE("devinfo %p, device_data %p, driver_data %p, detail_data %p, size %u, ret_size %p.\n",
4851 devinfo, device_data, driver_data, detail_data, size, ret_size);
4853 if ((detail_data || size) && size < sizeof(SP_DRVINFO_DETAIL_DATA_W))
4855 SetLastError(ERROR_INVALID_USER_BUFFER);
4856 return FALSE;
4859 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4860 return FALSE;
4862 SetupFindFirstLineW(hinf, driver->mfg_key, driver->description, &ctx);
4863 for (i = 2; SetupGetStringFieldW(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
4864 id_size += wcslen(id) + 1;
4866 size_needed = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID[id_size]);
4867 if (ret_size)
4868 *ret_size = size_needed;
4869 if (!detail_data)
4870 return TRUE;
4872 detail_data->CompatIDsLength = detail_data->CompatIDsOffset = 0;
4873 detail_data->HardwareID[0] = 0;
4875 if (size >= size_needed)
4877 id_size = 0;
4878 for (i = 2; SetupGetStringFieldW(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
4880 wcscpy(&detail_data->HardwareID[id_size], id);
4881 if (i == 3)
4882 detail_data->CompatIDsOffset = id_size;
4883 id_size += wcslen(id) + 1;
4885 detail_data->HardwareID[id_size++] = 0;
4886 if (i > 3)
4887 detail_data->CompatIDsLength = id_size - detail_data->CompatIDsOffset;
4890 SetupCloseInfFile(hinf);
4892 if ((file = CreateFileW(driver->inf_path, 0, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
4893 return FALSE;
4894 GetFileTime(file, NULL, NULL, &detail_data->InfDate);
4895 CloseHandle(file);
4897 wcscpy(detail_data->SectionName, driver->section);
4898 wcscpy(detail_data->InfFileName, driver->inf_path);
4899 wcscpy(detail_data->DrvDescription, driver->description);
4901 if (size < size_needed)
4903 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4904 return FALSE;
4907 return TRUE;
4910 /***********************************************************************
4911 * SetupDiGetDriverInfoDetailA (SETUPAPI.@)
4913 BOOL WINAPI SetupDiGetDriverInfoDetailA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4914 SP_DRVINFO_DATA_A *driver_data, SP_DRVINFO_DETAIL_DATA_A *detail_data, const DWORD size, DWORD *ret_size)
4916 struct driver *driver = (struct driver *)driver_data->Reserved;
4917 DWORD size_needed, i, id_size = 1;
4918 char id[MAX_DEVICE_ID_LEN];
4919 INFCONTEXT ctx;
4920 HANDLE file;
4921 HINF hinf;
4923 TRACE("devinfo %p, device_data %p, driver_data %p, detail_data %p, size %u, ret_size %p.\n",
4924 devinfo, device_data, driver_data, detail_data, size, ret_size);
4926 if ((detail_data || size) && size < sizeof(SP_DRVINFO_DETAIL_DATA_A))
4928 SetLastError(ERROR_INVALID_USER_BUFFER);
4929 return FALSE;
4932 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4933 return FALSE;
4935 SetupFindFirstLineW(hinf, driver->mfg_key, driver->description, &ctx);
4936 for (i = 2; SetupGetStringFieldA(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
4937 id_size += strlen(id) + 1;
4939 size_needed = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID[id_size]);
4940 if (ret_size)
4941 *ret_size = size_needed;
4942 if (!detail_data)
4944 SetupCloseInfFile(hinf);
4945 return TRUE;
4948 detail_data->CompatIDsLength = detail_data->CompatIDsOffset = 0;
4949 detail_data->HardwareID[0] = 0;
4951 if (size >= size_needed)
4953 id_size = 0;
4954 for (i = 2; SetupGetStringFieldA(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
4956 strcpy(&detail_data->HardwareID[id_size], id);
4957 if (i == 3)
4958 detail_data->CompatIDsOffset = id_size;
4959 id_size += strlen(id) + 1;
4961 detail_data->HardwareID[id_size++] = 0;
4962 if (i > 3)
4963 detail_data->CompatIDsLength = id_size - detail_data->CompatIDsOffset;
4966 SetupCloseInfFile(hinf);
4968 if ((file = CreateFileW(driver->inf_path, 0, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
4969 return FALSE;
4970 GetFileTime(file, NULL, NULL, &detail_data->InfDate);
4971 CloseHandle(file);
4973 WideCharToMultiByte(CP_ACP, 0, driver->section, -1, detail_data->SectionName,
4974 sizeof(detail_data->SectionName), NULL, NULL);
4975 WideCharToMultiByte(CP_ACP, 0, driver->inf_path, -1, detail_data->InfFileName,
4976 sizeof(detail_data->InfFileName), NULL, NULL);
4977 WideCharToMultiByte(CP_ACP, 0, driver->description, -1, detail_data->DrvDescription,
4978 sizeof(detail_data->InfFileName), NULL, NULL);
4980 if (size < size_needed)
4982 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4983 return FALSE;
4986 return TRUE;
4989 /***********************************************************************
4990 * SetupDiInstallDriverFiles (SETUPAPI.@)
4992 BOOL WINAPI SetupDiInstallDriverFiles(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4994 WCHAR section[LINE_LEN], section_ext[LINE_LEN], iface_section[LINE_LEN];
4995 struct device *device;
4996 struct driver *driver;
4997 void *callback_ctx;
4998 INFCONTEXT ctx;
4999 HINF hinf;
5001 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
5003 if (!(device = get_device(devinfo, device_data)))
5004 return FALSE;
5006 if (!(driver = device->selected_driver))
5008 ERR("No driver selected for device %p.\n", devinfo);
5009 SetLastError(ERROR_NO_DRIVER_SELECTED);
5010 return FALSE;
5013 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
5014 return FALSE;
5016 SetupFindFirstLineW(hinf, driver->mfg_key, driver->description, &ctx);
5017 SetupGetStringFieldW(&ctx, 1, section, ARRAY_SIZE(section), NULL);
5018 SetupDiGetActualSectionToInstallW(hinf, section, section_ext, ARRAY_SIZE(section_ext), NULL, NULL);
5020 callback_ctx = SetupInitDefaultQueueCallback(NULL);
5022 SetupInstallFromInfSectionW(NULL, hinf, section_ext, SPINST_FILES, NULL, NULL,
5023 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5025 lstrcatW(section_ext, dotInterfaces);
5026 if (SetupFindFirstLineW(hinf, section_ext, AddInterface, &ctx))
5028 do {
5029 SetupGetStringFieldW(&ctx, 3, iface_section, ARRAY_SIZE(iface_section), NULL);
5030 SetupInstallFromInfSectionW(NULL, hinf, iface_section, SPINST_FILES, NULL, NULL,
5031 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5032 } while (SetupFindNextMatchLineW(&ctx, AddInterface, &ctx));
5035 SetupTermDefaultQueueCallback(callback_ctx);
5037 SetupCloseInfFile(hinf);
5038 return TRUE;
5041 /***********************************************************************
5042 * SetupDiInstallDevice (SETUPAPI.@)
5044 BOOL WINAPI SetupDiInstallDevice(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
5046 static const WCHAR infpathW[] = {'I','n','f','P','a','t','h',0};
5047 static const WCHAR infsectionW[] = {'I','n','f','S','e','c','t','i','o','n',0};
5048 static const WCHAR infsectionextW[] = {'I','n','f','S','e','c','t','i','o','n','E','x','t',0};
5049 static const WCHAR dothwW[] = {'.','H','W',0};
5050 static const WCHAR dotservicesW[] = {'.','S','e','r','v','i','c','e','s',0};
5051 static const WCHAR addserviceW[] = {'A','d','d','S','e','r','v','i','c','e',0};
5052 static const WCHAR rootW[] = {'r','o','o','t','\\',0};
5053 WCHAR section_ext[LINE_LEN], subsection[LINE_LEN], inf_path[MAX_PATH], *extptr, *filepart;
5054 UINT install_flags = SPINST_ALL;
5055 HKEY driver_key, device_key;
5056 SC_HANDLE manager, service;
5057 WCHAR svc_name[LINE_LEN];
5058 struct device *device;
5059 struct driver *driver;
5060 void *callback_ctx;
5061 INFCONTEXT ctx;
5062 HINF hinf;
5063 LONG l;
5065 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
5067 if (!(device = get_device(devinfo, device_data)))
5068 return FALSE;
5070 if (!(driver = device->selected_driver))
5072 ERR("No driver selected for device %p.\n", devinfo);
5073 SetLastError(ERROR_NO_DRIVER_SELECTED);
5074 return FALSE;
5077 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
5078 return FALSE;
5080 RegSetValueExW(device->key, L"DeviceDesc", 0, REG_SZ, (BYTE *)driver->description,
5081 wcslen(driver->description) * sizeof(WCHAR));
5083 SetupDiGetActualSectionToInstallW(hinf, driver->section, section_ext, ARRAY_SIZE(section_ext), NULL, &extptr);
5085 if ((l = create_driver_key(device, &driver_key)))
5087 SetLastError(l);
5088 SetupCloseInfFile(hinf);
5089 return FALSE;
5092 if ((l = RegCreateKeyExW(device->key, DeviceParameters, 0, NULL, 0,
5093 KEY_READ | KEY_WRITE, NULL, &device_key, NULL)))
5095 SetLastError(l);
5096 RegCloseKey(driver_key);
5097 SetupCloseInfFile(hinf);
5098 return FALSE;
5101 if (device->params.Flags & DI_NOFILECOPY)
5102 install_flags &= ~SPINST_FILES;
5104 callback_ctx = SetupInitDefaultQueueCallback(NULL);
5106 SetupInstallFromInfSectionW(NULL, hinf, section_ext, install_flags, driver_key, NULL,
5107 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5109 lstrcpyW(subsection, section_ext);
5110 lstrcatW(subsection, dothwW);
5112 SetupInstallFromInfSectionW(NULL, hinf, subsection, install_flags, device_key, NULL,
5113 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5115 lstrcpyW(subsection, section_ext);
5116 lstrcatW(subsection, dotservicesW);
5117 SetupInstallServicesFromInfSectionW(hinf, subsection, 0);
5119 svc_name[0] = 0;
5120 if (SetupFindFirstLineW(hinf, subsection, addserviceW, &ctx))
5124 INT flags;
5126 if (SetupGetIntField(&ctx, 2, &flags) && (flags & SPSVCINST_ASSOCSERVICE))
5128 if (SetupGetStringFieldW(&ctx, 1, svc_name, ARRAY_SIZE(svc_name), NULL) && svc_name[0])
5129 RegSetValueExW(device->key, Service, 0, REG_SZ, (BYTE *)svc_name, lstrlenW(svc_name) * sizeof(WCHAR));
5130 break;
5132 } while (SetupFindNextMatchLineW(&ctx, addserviceW, &ctx));
5135 SetupTermDefaultQueueCallback(callback_ctx);
5136 SetupCloseInfFile(hinf);
5138 SetupCopyOEMInfW(driver->inf_path, NULL, SPOST_NONE, 0, inf_path, ARRAY_SIZE(inf_path), NULL, &filepart);
5139 TRACE("Copied INF file %s to %s.\n", debugstr_w(driver->inf_path), debugstr_w(inf_path));
5141 RegSetValueExW(driver_key, infpathW, 0, REG_SZ, (BYTE *)filepart, lstrlenW(filepart) * sizeof(WCHAR));
5142 RegSetValueExW(driver_key, infsectionW, 0, REG_SZ, (BYTE *)driver->section, lstrlenW(driver->section) * sizeof(WCHAR));
5143 if (extptr)
5144 RegSetValueExW(driver_key, infsectionextW, 0, REG_SZ, (BYTE *)extptr, lstrlenW(extptr) * sizeof(WCHAR));
5146 RegCloseKey(device_key);
5147 RegCloseKey(driver_key);
5149 if (!wcsnicmp(device->instanceId, rootW, lstrlenW(rootW)) && svc_name[0]
5150 && (manager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT)))
5152 if ((service = OpenServiceW(manager, svc_name, SERVICE_START | SERVICE_USER_DEFINED_CONTROL)))
5154 SERVICE_STATUS status;
5156 if (!StartServiceW(service, 0, NULL) && GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5158 ERR("Failed to start service %s for device %s, error %u.\n",
5159 debugstr_w(svc_name), debugstr_w(device->instanceId), GetLastError());
5161 if (!ControlService(service, SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES, &status))
5163 ERR("Failed to control service %s for device %s, error %u.\n",
5164 debugstr_w(svc_name), debugstr_w(device->instanceId), GetLastError());
5166 CloseServiceHandle(service);
5168 else
5169 ERR("Failed to open service %s for device %s.\n", debugstr_w(svc_name), debugstr_w(device->instanceId));
5170 CloseServiceHandle(manager);
5173 return TRUE;