user32/tests: Test pending redraw state with owner-drawn list box.
[wine.git] / dlls / setupapi / devinst.c
blob91001976edde0c493bf25cb0a757c751e9447405
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 TRACE("Failed to open driver key, error %u.\n", l);
566 RegCloseKey(class_key);
567 return l;
570 static LONG create_driver_key(struct device *device, HKEY *key)
572 static const WCHAR formatW[] = {'%','0','4','u',0};
573 static const WCHAR slash[] = { '\\',0 };
574 unsigned int i = 0;
575 WCHAR path[50];
576 HKEY class_key;
577 DWORD dispos;
578 LONG l;
580 if (!open_driver_key(device, KEY_READ | KEY_WRITE, key))
581 return ERROR_SUCCESS;
583 if ((l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, ControlClass, 0, NULL, 0,
584 KEY_CREATE_SUB_KEY, NULL, &class_key, NULL)))
586 ERR("Failed to open driver class root key, error %u.\n", l);
587 return l;
590 SETUPDI_GuidToString(&device->class, path);
591 lstrcatW(path, slash);
592 /* Allocate a new driver key, by finding the first integer value that's not
593 * already taken. */
594 for (;;)
596 swprintf(path + 39, ARRAY_SIZE(path) - 39, formatW, i++);
597 if ((l = RegCreateKeyExW(class_key, path, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, key, &dispos)))
598 break;
599 else if (dispos == REG_CREATED_NEW_KEY)
601 RegSetValueExW(device->key, Driver, 0, REG_SZ, (BYTE *)path, lstrlenW(path) * sizeof(WCHAR));
602 RegCloseKey(class_key);
603 return ERROR_SUCCESS;
605 RegCloseKey(*key);
607 ERR("Failed to create driver key, error %u.\n", l);
608 RegCloseKey(class_key);
609 return l;
612 static LONG delete_driver_key(struct device *device)
614 HKEY key;
615 LONG l;
617 if (!(l = open_driver_key(device, KEY_READ | KEY_WRITE, &key)))
619 l = RegDeleteKeyW(key, emptyW);
620 RegCloseKey(key);
623 return l;
626 struct PropertyMapEntry
628 DWORD regType;
629 LPCSTR nameA;
630 LPCWSTR nameW;
633 static const struct PropertyMapEntry PropertyMap[] = {
634 { REG_SZ, "DeviceDesc", DeviceDesc },
635 { REG_MULTI_SZ, "HardwareId", HardwareId },
636 { REG_MULTI_SZ, "CompatibleIDs", CompatibleIDs },
637 { 0, NULL, NULL }, /* SPDRP_UNUSED0 */
638 { REG_SZ, "Service", Service },
639 { 0, NULL, NULL }, /* SPDRP_UNUSED1 */
640 { 0, NULL, NULL }, /* SPDRP_UNUSED2 */
641 { REG_SZ, "Class", Class },
642 { REG_SZ, "ClassGUID", ClassGUID },
643 { REG_SZ, "Driver", Driver },
644 { REG_DWORD, "ConfigFlags", ConfigFlags },
645 { REG_SZ, "Mfg", Mfg },
646 { REG_SZ, "FriendlyName", FriendlyName },
647 { REG_SZ, "LocationInformation", LocationInformation },
648 { 0, NULL, NULL }, /* SPDRP_PHYSICAL_DEVICE_OBJECT_NAME */
649 { REG_DWORD, "Capabilities", Capabilities },
650 { REG_DWORD, "UINumber", UINumber },
651 { REG_MULTI_SZ, "UpperFilters", UpperFilters },
652 { REG_MULTI_SZ, "LowerFilters", LowerFilters },
655 static BOOL SETUPDI_SetDeviceRegistryPropertyW(struct device *device,
656 DWORD prop, const BYTE *buffer, DWORD size)
658 if (prop < ARRAY_SIZE(PropertyMap) && PropertyMap[prop].nameW)
660 LONG ret = RegSetValueExW(device->key, PropertyMap[prop].nameW, 0,
661 PropertyMap[prop].regType, buffer, size);
662 if (!ret)
663 return TRUE;
665 SetLastError(ret);
667 return FALSE;
670 static void remove_device_iface(struct device_iface *iface)
672 RegDeleteTreeW(iface->refstr_key, NULL);
673 RegDeleteKeyW(iface->refstr_key, emptyW);
674 RegCloseKey(iface->refstr_key);
675 iface->refstr_key = NULL;
676 /* Also remove the class key if it's empty. */
677 RegDeleteKeyW(iface->class_key, emptyW);
678 RegCloseKey(iface->class_key);
679 iface->class_key = NULL;
680 iface->flags |= SPINT_REMOVED;
683 static void delete_device_iface(struct device_iface *iface)
685 list_remove(&iface->entry);
686 RegCloseKey(iface->refstr_key);
687 RegCloseKey(iface->class_key);
688 heap_free(iface->refstr);
689 heap_free(iface->symlink);
690 heap_free(iface);
693 /* remove all interfaces associated with the device, including those not
694 * enumerated in the set */
695 static void remove_all_device_ifaces(struct device *device)
697 HKEY classes_key;
698 DWORD i, len;
699 LONG ret;
701 if ((ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, DeviceClasses, 0, KEY_READ, &classes_key)))
703 WARN("Failed to open classes key, error %u.\n", ret);
704 return;
707 for (i = 0; ; ++i)
709 WCHAR class_name[40];
710 HKEY class_key;
711 DWORD j;
713 len = ARRAY_SIZE(class_name);
714 if ((ret = RegEnumKeyExW(classes_key, i, class_name, &len, NULL, NULL, NULL, NULL)))
716 if (ret != ERROR_NO_MORE_ITEMS) ERR("Failed to enumerate classes, error %u.\n", ret);
717 break;
720 if ((ret = RegOpenKeyExW(classes_key, class_name, 0, KEY_READ, &class_key)))
722 ERR("Failed to open class %s, error %u.\n", debugstr_w(class_name), ret);
723 continue;
726 for (j = 0; ; ++j)
728 WCHAR iface_name[MAX_DEVICE_ID_LEN + 39], device_name[MAX_DEVICE_ID_LEN];
729 HKEY iface_key;
731 len = ARRAY_SIZE(iface_name);
732 if ((ret = RegEnumKeyExW(class_key, j, iface_name, &len, NULL, NULL, NULL, NULL)))
734 if (ret != ERROR_NO_MORE_ITEMS) ERR("Failed to enumerate interfaces, error %u.\n", ret);
735 break;
738 if ((ret = RegOpenKeyExW(class_key, iface_name, 0, KEY_ALL_ACCESS, &iface_key)))
740 ERR("Failed to open interface %s, error %u.\n", debugstr_w(iface_name), ret);
741 continue;
744 len = sizeof(device_name);
745 if ((ret = RegQueryValueExW(iface_key, L"DeviceInstance", NULL, NULL, (BYTE *)device_name, &len)))
747 ERR("Failed to query device instance, error %u.\n", ret);
748 RegCloseKey(iface_key);
749 continue;
752 if (!wcsicmp(device_name, device->instanceId))
754 if ((ret = RegDeleteTreeW(iface_key, NULL)))
755 ERR("Failed to delete interface %s subkeys, error %u.\n", debugstr_w(iface_name), ret);
756 if ((ret = RegDeleteKeyW(iface_key, L"")))
757 ERR("Failed to delete interface %s, error %u.\n", debugstr_w(iface_name), ret);
760 RegCloseKey(iface_key);
762 RegCloseKey(class_key);
765 RegCloseKey(classes_key);
768 static void remove_device(struct device *device)
770 WCHAR id[MAX_DEVICE_ID_LEN], *p;
771 struct device_iface *iface;
772 HKEY enum_key;
774 delete_driver_key(device);
776 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
778 remove_device_iface(iface);
781 RegDeleteTreeW(device->key, NULL);
782 RegDeleteKeyW(device->key, emptyW);
784 /* delete all empty parents of the key */
785 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, 0, &enum_key))
787 lstrcpyW(id, device->instanceId);
789 while ((p = wcsrchr(id, '\\')))
791 *p = 0;
792 RegDeleteKeyW(enum_key, id);
795 RegCloseKey(enum_key);
798 RegCloseKey(device->key);
799 device->key = NULL;
800 device->removed = TRUE;
803 static void delete_device(struct device *device)
805 struct device_iface *iface, *next;
806 SP_DEVINFO_DATA device_data;
808 device_data.cbSize = sizeof(device_data);
809 copy_device_data(&device_data, device);
810 SetupDiCallClassInstaller(DIF_DESTROYPRIVATEDATA, device->set, &device_data);
812 if (device->phantom)
814 remove_device(device);
815 remove_all_device_ifaces(device);
818 RegCloseKey(device->key);
819 heap_free(device->instanceId);
820 heap_free(device->drivers);
822 LIST_FOR_EACH_ENTRY_SAFE(iface, next, &device->interfaces,
823 struct device_iface, entry)
825 delete_device_iface(iface);
827 free_devnode(device->devnode);
828 list_remove(&device->entry);
829 heap_free(device);
832 /* Create a new device, or return a device already in the set. */
833 static struct device *create_device(struct DeviceInfoSet *set,
834 const GUID *class, const WCHAR *instanceid, BOOL phantom)
836 const DWORD one = 1;
837 struct device *device;
838 WCHAR guidstr[MAX_GUID_STRING_LEN];
839 WCHAR class_name[MAX_CLASS_NAME_LEN];
840 DWORD size;
842 TRACE("%p, %s, %s, %d\n", set, debugstr_guid(class),
843 debugstr_w(instanceid), phantom);
845 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
847 if (!wcsicmp(instanceid, device->instanceId))
849 TRACE("Found device %p already in set.\n", device);
850 return device;
854 if (!(device = heap_alloc_zero(sizeof(*device))))
856 SetLastError(ERROR_OUTOFMEMORY);
857 return NULL;
860 if (!(device->instanceId = strdupW(instanceid)))
862 SetLastError(ERROR_OUTOFMEMORY);
863 heap_free(device);
864 return NULL;
867 wcsupr(device->instanceId);
868 device->set = set;
869 device->key = SETUPDI_CreateDevKey(device);
870 device->phantom = phantom;
871 list_init(&device->interfaces);
872 device->class = *class;
873 device->devnode = alloc_devnode(device);
874 device->removed = FALSE;
875 list_add_tail(&set->devices, &device->entry);
876 device->params.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
878 if (phantom)
879 RegSetValueExW(device->key, Phantom, 0, REG_DWORD, (const BYTE *)&one, sizeof(one));
881 SETUPDI_GuidToString(class, guidstr);
882 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_CLASSGUID,
883 (const BYTE *)guidstr, sizeof(guidstr));
885 if (SetupDiClassNameFromGuidW(class, class_name, ARRAY_SIZE(class_name), NULL))
887 size = (lstrlenW(class_name) + 1) * sizeof(WCHAR);
888 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_CLASS, (const BYTE *)class_name, size);
891 TRACE("Created new device %p.\n", device);
892 return device;
895 /***********************************************************************
896 * SetupDiBuildClassInfoList (SETUPAPI.@)
898 * Returns a list of setup class GUIDs that identify the classes
899 * that are installed on a local machine.
901 * PARAMS
902 * Flags [I] control exclusion of classes from the list.
903 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
904 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
905 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
907 * RETURNS
908 * Success: TRUE.
909 * Failure: FALSE.
911 BOOL WINAPI SetupDiBuildClassInfoList(
912 DWORD Flags,
913 LPGUID ClassGuidList,
914 DWORD ClassGuidListSize,
915 PDWORD RequiredSize)
917 TRACE("\n");
918 return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
919 ClassGuidListSize, RequiredSize,
920 NULL, NULL);
923 /***********************************************************************
924 * SetupDiBuildClassInfoListExA (SETUPAPI.@)
926 * Returns a list of setup class GUIDs that identify the classes
927 * that are installed on a local or remote machine.
929 * PARAMS
930 * Flags [I] control exclusion of classes from the list.
931 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
932 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
933 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
934 * MachineName [I] name of a remote machine.
935 * Reserved [I] must be NULL.
937 * RETURNS
938 * Success: TRUE.
939 * Failure: FALSE.
941 BOOL WINAPI SetupDiBuildClassInfoListExA(
942 DWORD Flags,
943 LPGUID ClassGuidList,
944 DWORD ClassGuidListSize,
945 PDWORD RequiredSize,
946 LPCSTR MachineName,
947 PVOID Reserved)
949 LPWSTR MachineNameW = NULL;
950 BOOL bResult;
952 TRACE("\n");
954 if (MachineName)
956 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
957 if (MachineNameW == NULL) return FALSE;
960 bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
961 ClassGuidListSize, RequiredSize,
962 MachineNameW, Reserved);
964 MyFree(MachineNameW);
966 return bResult;
969 /***********************************************************************
970 * SetupDiBuildClassInfoListExW (SETUPAPI.@)
972 * Returns a list of setup class GUIDs that identify the classes
973 * that are installed on a local or remote machine.
975 * PARAMS
976 * Flags [I] control exclusion of classes from the list.
977 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
978 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
979 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
980 * MachineName [I] name of a remote machine.
981 * Reserved [I] must be NULL.
983 * RETURNS
984 * Success: TRUE.
985 * Failure: FALSE.
987 BOOL WINAPI SetupDiBuildClassInfoListExW(
988 DWORD Flags,
989 LPGUID ClassGuidList,
990 DWORD ClassGuidListSize,
991 PDWORD RequiredSize,
992 LPCWSTR MachineName,
993 PVOID Reserved)
995 WCHAR szKeyName[40];
996 HKEY hClassesKey;
997 HKEY hClassKey;
998 DWORD dwLength;
999 DWORD dwIndex;
1000 LONG lError;
1001 DWORD dwGuidListIndex = 0;
1003 TRACE("\n");
1005 if (RequiredSize != NULL)
1006 *RequiredSize = 0;
1008 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
1009 KEY_ALL_ACCESS,
1010 DIOCR_INSTALLER,
1011 MachineName,
1012 Reserved);
1013 if (hClassesKey == INVALID_HANDLE_VALUE)
1015 return FALSE;
1018 for (dwIndex = 0; ; dwIndex++)
1020 dwLength = 40;
1021 lError = RegEnumKeyExW(hClassesKey,
1022 dwIndex,
1023 szKeyName,
1024 &dwLength,
1025 NULL,
1026 NULL,
1027 NULL,
1028 NULL);
1029 TRACE("RegEnumKeyExW() returns %d\n", lError);
1030 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
1032 TRACE("Key name: %p\n", szKeyName);
1034 if (RegOpenKeyExW(hClassesKey,
1035 szKeyName,
1037 KEY_ALL_ACCESS,
1038 &hClassKey))
1040 RegCloseKey(hClassesKey);
1041 return FALSE;
1044 if (!RegQueryValueExW(hClassKey,
1045 NoUseClass,
1046 NULL,
1047 NULL,
1048 NULL,
1049 NULL))
1051 TRACE("'NoUseClass' value found!\n");
1052 RegCloseKey(hClassKey);
1053 continue;
1056 if ((Flags & DIBCI_NOINSTALLCLASS) &&
1057 (!RegQueryValueExW(hClassKey,
1058 NoInstallClass,
1059 NULL,
1060 NULL,
1061 NULL,
1062 NULL)))
1064 TRACE("'NoInstallClass' value found!\n");
1065 RegCloseKey(hClassKey);
1066 continue;
1069 if ((Flags & DIBCI_NODISPLAYCLASS) &&
1070 (!RegQueryValueExW(hClassKey,
1071 NoDisplayClass,
1072 NULL,
1073 NULL,
1074 NULL,
1075 NULL)))
1077 TRACE("'NoDisplayClass' value found!\n");
1078 RegCloseKey(hClassKey);
1079 continue;
1082 RegCloseKey(hClassKey);
1084 TRACE("Guid: %p\n", szKeyName);
1085 if (dwGuidListIndex < ClassGuidListSize)
1087 if (szKeyName[0] == '{' && szKeyName[37] == '}')
1089 szKeyName[37] = 0;
1091 TRACE("Guid: %p\n", &szKeyName[1]);
1093 UuidFromStringW(&szKeyName[1],
1094 &ClassGuidList[dwGuidListIndex]);
1097 dwGuidListIndex++;
1100 if (lError != ERROR_SUCCESS)
1101 break;
1104 RegCloseKey(hClassesKey);
1106 if (RequiredSize != NULL)
1107 *RequiredSize = dwGuidListIndex;
1109 if (ClassGuidListSize < dwGuidListIndex)
1111 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1112 return FALSE;
1115 return TRUE;
1118 /***********************************************************************
1119 * SetupDiClassGuidsFromNameA (SETUPAPI.@)
1121 BOOL WINAPI SetupDiClassGuidsFromNameA(
1122 LPCSTR ClassName,
1123 LPGUID ClassGuidList,
1124 DWORD ClassGuidListSize,
1125 PDWORD RequiredSize)
1127 return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
1128 ClassGuidListSize, RequiredSize,
1129 NULL, NULL);
1132 /***********************************************************************
1133 * SetupDiClassGuidsFromNameW (SETUPAPI.@)
1135 BOOL WINAPI SetupDiClassGuidsFromNameW(
1136 LPCWSTR ClassName,
1137 LPGUID ClassGuidList,
1138 DWORD ClassGuidListSize,
1139 PDWORD RequiredSize)
1141 return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
1142 ClassGuidListSize, RequiredSize,
1143 NULL, NULL);
1146 /***********************************************************************
1147 * SetupDiClassGuidsFromNameExA (SETUPAPI.@)
1149 BOOL WINAPI SetupDiClassGuidsFromNameExA(
1150 LPCSTR ClassName,
1151 LPGUID ClassGuidList,
1152 DWORD ClassGuidListSize,
1153 PDWORD RequiredSize,
1154 LPCSTR MachineName,
1155 PVOID Reserved)
1157 LPWSTR ClassNameW = NULL;
1158 LPWSTR MachineNameW = NULL;
1159 BOOL bResult;
1161 ClassNameW = MultiByteToUnicode(ClassName, CP_ACP);
1162 if (ClassNameW == NULL)
1163 return FALSE;
1165 if (MachineName)
1167 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1168 if (MachineNameW == NULL)
1170 MyFree(ClassNameW);
1171 return FALSE;
1175 bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
1176 ClassGuidListSize, RequiredSize,
1177 MachineNameW, Reserved);
1179 MyFree(MachineNameW);
1180 MyFree(ClassNameW);
1182 return bResult;
1185 /***********************************************************************
1186 * SetupDiClassGuidsFromNameExW (SETUPAPI.@)
1188 BOOL WINAPI SetupDiClassGuidsFromNameExW(
1189 LPCWSTR ClassName,
1190 LPGUID ClassGuidList,
1191 DWORD ClassGuidListSize,
1192 PDWORD RequiredSize,
1193 LPCWSTR MachineName,
1194 PVOID Reserved)
1196 WCHAR szKeyName[40];
1197 WCHAR szClassName[256];
1198 HKEY hClassesKey;
1199 HKEY hClassKey;
1200 DWORD dwLength;
1201 DWORD dwIndex;
1202 LONG lError;
1203 DWORD dwGuidListIndex = 0;
1205 if (RequiredSize != NULL)
1206 *RequiredSize = 0;
1208 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
1209 KEY_ALL_ACCESS,
1210 DIOCR_INSTALLER,
1211 MachineName,
1212 Reserved);
1213 if (hClassesKey == INVALID_HANDLE_VALUE)
1215 return FALSE;
1218 for (dwIndex = 0; ; dwIndex++)
1220 dwLength = ARRAY_SIZE(szKeyName);
1221 lError = RegEnumKeyExW(hClassesKey,
1222 dwIndex,
1223 szKeyName,
1224 &dwLength,
1225 NULL,
1226 NULL,
1227 NULL,
1228 NULL);
1229 TRACE("RegEnumKeyExW() returns %d\n", lError);
1230 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
1232 TRACE("Key name: %p\n", szKeyName);
1234 if (RegOpenKeyExW(hClassesKey,
1235 szKeyName,
1237 KEY_ALL_ACCESS,
1238 &hClassKey))
1240 RegCloseKey(hClassesKey);
1241 return FALSE;
1244 dwLength = sizeof(szClassName);
1245 if (!RegQueryValueExW(hClassKey,
1246 Class,
1247 NULL,
1248 NULL,
1249 (LPBYTE)szClassName,
1250 &dwLength))
1252 TRACE("Class name: %p\n", szClassName);
1254 if (wcsicmp(szClassName, ClassName) == 0)
1256 TRACE("Found matching class name\n");
1258 TRACE("Guid: %p\n", szKeyName);
1259 if (dwGuidListIndex < ClassGuidListSize)
1261 if (szKeyName[0] == '{' && szKeyName[37] == '}')
1263 szKeyName[37] = 0;
1265 TRACE("Guid: %p\n", &szKeyName[1]);
1267 UuidFromStringW(&szKeyName[1],
1268 &ClassGuidList[dwGuidListIndex]);
1271 dwGuidListIndex++;
1275 RegCloseKey(hClassKey);
1278 if (lError != ERROR_SUCCESS)
1279 break;
1282 RegCloseKey(hClassesKey);
1284 if (RequiredSize != NULL)
1285 *RequiredSize = dwGuidListIndex;
1287 if (ClassGuidListSize < dwGuidListIndex)
1289 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1290 return FALSE;
1293 return TRUE;
1296 /***********************************************************************
1297 * SetupDiClassNameFromGuidA (SETUPAPI.@)
1299 BOOL WINAPI SetupDiClassNameFromGuidA(
1300 const GUID* ClassGuid,
1301 PSTR ClassName,
1302 DWORD ClassNameSize,
1303 PDWORD RequiredSize)
1305 return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
1306 ClassNameSize, RequiredSize,
1307 NULL, NULL);
1310 /***********************************************************************
1311 * SetupDiClassNameFromGuidW (SETUPAPI.@)
1313 BOOL WINAPI SetupDiClassNameFromGuidW(
1314 const GUID* ClassGuid,
1315 PWSTR ClassName,
1316 DWORD ClassNameSize,
1317 PDWORD RequiredSize)
1319 return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
1320 ClassNameSize, RequiredSize,
1321 NULL, NULL);
1324 /***********************************************************************
1325 * SetupDiClassNameFromGuidExA (SETUPAPI.@)
1327 BOOL WINAPI SetupDiClassNameFromGuidExA(
1328 const GUID* ClassGuid,
1329 PSTR ClassName,
1330 DWORD ClassNameSize,
1331 PDWORD RequiredSize,
1332 PCSTR MachineName,
1333 PVOID Reserved)
1335 WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
1336 LPWSTR MachineNameW = NULL;
1337 BOOL ret;
1339 if (MachineName)
1340 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1341 ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
1342 NULL, MachineNameW, Reserved);
1343 if (ret)
1345 int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
1346 ClassNameSize, NULL, NULL);
1348 if (!ClassNameSize && RequiredSize)
1349 *RequiredSize = len;
1351 MyFree(MachineNameW);
1352 return ret;
1355 /***********************************************************************
1356 * SetupDiClassNameFromGuidExW (SETUPAPI.@)
1358 BOOL WINAPI SetupDiClassNameFromGuidExW(
1359 const GUID* ClassGuid,
1360 PWSTR ClassName,
1361 DWORD ClassNameSize,
1362 PDWORD RequiredSize,
1363 PCWSTR MachineName,
1364 PVOID Reserved)
1366 HKEY hKey;
1367 DWORD dwLength;
1369 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
1370 KEY_ALL_ACCESS,
1371 DIOCR_INSTALLER,
1372 MachineName,
1373 Reserved);
1374 if (hKey == INVALID_HANDLE_VALUE)
1376 return FALSE;
1379 if (RequiredSize != NULL)
1381 dwLength = 0;
1382 if (RegQueryValueExW(hKey,
1383 Class,
1384 NULL,
1385 NULL,
1386 NULL,
1387 &dwLength))
1389 RegCloseKey(hKey);
1390 return FALSE;
1393 *RequiredSize = dwLength / sizeof(WCHAR);
1396 dwLength = ClassNameSize * sizeof(WCHAR);
1397 if (RegQueryValueExW(hKey,
1398 Class,
1399 NULL,
1400 NULL,
1401 (LPBYTE)ClassName,
1402 &dwLength))
1404 RegCloseKey(hKey);
1405 return FALSE;
1408 RegCloseKey(hKey);
1410 return TRUE;
1413 /***********************************************************************
1414 * SetupDiCreateDeviceInfoList (SETUPAPI.@)
1416 HDEVINFO WINAPI
1417 SetupDiCreateDeviceInfoList(const GUID *ClassGuid,
1418 HWND hwndParent)
1420 return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
1423 /***********************************************************************
1424 * SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
1426 HDEVINFO WINAPI
1427 SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
1428 HWND hwndParent,
1429 PCSTR MachineName,
1430 PVOID Reserved)
1432 LPWSTR MachineNameW = NULL;
1433 HDEVINFO hDevInfo;
1435 TRACE("\n");
1437 if (MachineName)
1439 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1440 if (MachineNameW == NULL)
1441 return INVALID_HANDLE_VALUE;
1444 hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
1445 MachineNameW, Reserved);
1447 MyFree(MachineNameW);
1449 return hDevInfo;
1452 /***********************************************************************
1453 * SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
1455 * Create an empty DeviceInfoSet list.
1457 * PARAMS
1458 * ClassGuid [I] if not NULL only devices with GUID ClassGuid are associated
1459 * with this list.
1460 * hwndParent [I] hwnd needed for interface related actions.
1461 * MachineName [I] name of machine to create empty DeviceInfoSet list, if NULL
1462 * local registry will be used.
1463 * Reserved [I] must be NULL
1465 * RETURNS
1466 * Success: empty list.
1467 * Failure: INVALID_HANDLE_VALUE.
1469 HDEVINFO WINAPI
1470 SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
1471 HWND hwndParent,
1472 PCWSTR MachineName,
1473 PVOID Reserved)
1475 struct DeviceInfoSet *list = NULL;
1476 DWORD size = sizeof(struct DeviceInfoSet);
1478 TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
1479 debugstr_w(MachineName), Reserved);
1481 if (MachineName && *MachineName)
1483 FIXME("remote support is not implemented\n");
1484 SetLastError(ERROR_INVALID_MACHINENAME);
1485 return INVALID_HANDLE_VALUE;
1488 if (Reserved != NULL)
1490 SetLastError(ERROR_INVALID_PARAMETER);
1491 return INVALID_HANDLE_VALUE;
1494 list = HeapAlloc(GetProcessHeap(), 0, size);
1495 if (!list)
1497 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1498 return INVALID_HANDLE_VALUE;
1501 list->magic = SETUP_DEVICE_INFO_SET_MAGIC;
1502 list->hwndParent = hwndParent;
1503 memcpy(&list->ClassGuid,
1504 ClassGuid ? ClassGuid : &GUID_NULL,
1505 sizeof(list->ClassGuid));
1506 list_init(&list->devices);
1508 return list;
1511 /***********************************************************************
1512 * SetupDiCreateDevRegKeyA (SETUPAPI.@)
1514 HKEY WINAPI SetupDiCreateDevRegKeyA(
1515 HDEVINFO DeviceInfoSet,
1516 PSP_DEVINFO_DATA DeviceInfoData,
1517 DWORD Scope,
1518 DWORD HwProfile,
1519 DWORD KeyType,
1520 HINF InfHandle,
1521 PCSTR InfSectionName)
1523 PWSTR InfSectionNameW = NULL;
1524 HKEY key;
1526 TRACE("%p %p %d %d %d %p %s\n", DeviceInfoSet, DeviceInfoData, Scope,
1527 HwProfile, KeyType, InfHandle, debugstr_a(InfSectionName));
1529 if (InfHandle)
1531 if (!InfSectionName)
1533 SetLastError(ERROR_INVALID_PARAMETER);
1534 return INVALID_HANDLE_VALUE;
1536 else
1538 InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
1539 if (InfSectionNameW == NULL) return INVALID_HANDLE_VALUE;
1542 key = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, Scope,
1543 HwProfile, KeyType, InfHandle, InfSectionNameW);
1544 MyFree(InfSectionNameW);
1545 return key;
1548 /***********************************************************************
1549 * SetupDiCreateDevRegKeyW (SETUPAPI.@)
1551 HKEY WINAPI SetupDiCreateDevRegKeyW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD Scope,
1552 DWORD HwProfile, DWORD KeyType, HINF InfHandle, const WCHAR *InfSectionName)
1554 struct device *device;
1555 HKEY key = INVALID_HANDLE_VALUE;
1556 LONG l;
1558 TRACE("devinfo %p, device_data %p, scope %d, profile %d, type %d, inf_handle %p, inf_section %s.\n",
1559 devinfo, device_data, Scope, HwProfile, KeyType, InfHandle, debugstr_w(InfSectionName));
1561 if (!(device = get_device(devinfo, device_data)))
1562 return INVALID_HANDLE_VALUE;
1564 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
1566 SetLastError(ERROR_INVALID_FLAGS);
1567 return INVALID_HANDLE_VALUE;
1569 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
1571 SetLastError(ERROR_INVALID_FLAGS);
1572 return INVALID_HANDLE_VALUE;
1574 if (device->phantom)
1576 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
1577 return INVALID_HANDLE_VALUE;
1579 if (Scope != DICS_FLAG_GLOBAL)
1580 FIXME("unimplemented for scope %d\n", Scope);
1581 switch (KeyType)
1583 case DIREG_DEV:
1584 l = RegCreateKeyExW(device->key, DeviceParameters, 0, NULL, 0,
1585 KEY_READ | KEY_WRITE, NULL, &key, NULL);
1586 break;
1587 case DIREG_DRV:
1588 l = create_driver_key(device, &key);
1589 break;
1590 default:
1591 FIXME("Unhandled type %#x.\n", KeyType);
1592 l = ERROR_CALL_NOT_IMPLEMENTED;
1594 if (InfHandle)
1595 SetupInstallFromInfSectionW(NULL, InfHandle, InfSectionName, SPINST_ALL,
1596 NULL, NULL, SP_COPY_NEWER_ONLY, NULL, NULL, devinfo, device_data);
1597 SetLastError(l);
1598 return l ? INVALID_HANDLE_VALUE : key;
1601 /***********************************************************************
1602 * SetupDiCreateDeviceInfoA (SETUPAPI.@)
1604 BOOL WINAPI SetupDiCreateDeviceInfoA(HDEVINFO DeviceInfoSet, const char *name,
1605 const GUID *ClassGuid, PCSTR DeviceDescription, HWND hwndParent, DWORD CreationFlags,
1606 PSP_DEVINFO_DATA DeviceInfoData)
1608 WCHAR nameW[MAX_DEVICE_ID_LEN];
1609 BOOL ret = FALSE;
1610 LPWSTR DeviceDescriptionW = NULL;
1612 if (!name || strlen(name) >= MAX_DEVICE_ID_LEN)
1614 SetLastError(ERROR_INVALID_DEVINST_NAME);
1615 return FALSE;
1618 MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, ARRAY_SIZE(nameW));
1620 if (DeviceDescription)
1622 DeviceDescriptionW = MultiByteToUnicode(DeviceDescription, CP_ACP);
1623 if (DeviceDescriptionW == NULL)
1624 return FALSE;
1627 ret = SetupDiCreateDeviceInfoW(DeviceInfoSet, nameW, ClassGuid, DeviceDescriptionW,
1628 hwndParent, CreationFlags, DeviceInfoData);
1630 MyFree(DeviceDescriptionW);
1632 return ret;
1635 /***********************************************************************
1636 * SetupDiCreateDeviceInfoW (SETUPAPI.@)
1638 BOOL WINAPI SetupDiCreateDeviceInfoW(HDEVINFO devinfo, const WCHAR *name, const GUID *class,
1639 const WCHAR *description, HWND parent, DWORD flags, SP_DEVINFO_DATA *device_data)
1641 WCHAR id[MAX_DEVICE_ID_LEN];
1642 struct DeviceInfoSet *set;
1643 HKEY enum_hkey;
1644 HKEY instance_hkey;
1645 struct device *device;
1646 LONG l;
1648 TRACE("devinfo %p, name %s, class %s, description %s, hwnd %p, flags %#x, device_data %p.\n",
1649 devinfo, debugstr_w(name), debugstr_guid(class), debugstr_w(description),
1650 parent, flags, device_data);
1652 if (!name || lstrlenW(name) >= MAX_DEVICE_ID_LEN)
1654 SetLastError(ERROR_INVALID_DEVINST_NAME);
1655 return FALSE;
1658 if (!(set = get_device_set(devinfo)))
1659 return FALSE;
1661 if (!class)
1663 SetLastError(ERROR_INVALID_PARAMETER);
1664 return FALSE;
1667 if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) && !IsEqualGUID(class, &set->ClassGuid))
1669 SetLastError(ERROR_CLASS_MISMATCH);
1670 return FALSE;
1672 if ((flags & DICD_GENERATE_ID))
1674 static const WCHAR formatW[] = {'R','O','O','T','\\','%','s','\\','%','0','4','u',0};
1675 unsigned int instance_id;
1677 if (wcschr(name, '\\'))
1679 SetLastError(ERROR_INVALID_DEVINST_NAME);
1680 return FALSE;
1683 for (instance_id = 0; ; ++instance_id)
1685 if (swprintf(id, ARRAY_SIZE(id), formatW, name, instance_id) == -1)
1687 SetLastError(ERROR_INVALID_DEVINST_NAME);
1688 return FALSE;
1691 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL, &enum_hkey, NULL);
1692 if (!(l = RegOpenKeyExW(enum_hkey, id, 0, KEY_READ, &instance_hkey)))
1693 RegCloseKey(instance_hkey);
1694 if (l == ERROR_FILE_NOT_FOUND)
1695 break;
1696 RegCloseKey(enum_hkey);
1699 else
1701 /* Check if instance is already in registry */
1702 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL, &enum_hkey, NULL);
1703 if (!RegOpenKeyExW(enum_hkey, name, 0, KEY_READ, &instance_hkey))
1705 RegCloseKey(instance_hkey);
1706 RegCloseKey(enum_hkey);
1707 SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
1708 return FALSE;
1710 RegCloseKey(enum_hkey);
1712 /* Check if instance is already in set */
1713 lstrcpyW(id, name);
1714 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
1716 if (!lstrcmpiW(name, device->instanceId))
1718 SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
1719 return FALSE;
1724 if (!(device = create_device(set, class, id, TRUE)))
1725 return FALSE;
1727 if (description)
1729 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_DEVICEDESC,
1730 (const BYTE *)description, lstrlenW(description) * sizeof(WCHAR));
1733 if (device_data)
1735 if (device_data->cbSize != sizeof(SP_DEVINFO_DATA))
1737 SetLastError(ERROR_INVALID_USER_BUFFER);
1738 return FALSE;
1740 else
1741 copy_device_data(device_data, device);
1744 return TRUE;
1747 /***********************************************************************
1748 * SetupDiRegisterDeviceInfo (SETUPAPI.@)
1750 BOOL WINAPI SetupDiRegisterDeviceInfo(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD flags,
1751 PSP_DETSIG_CMPPROC compare_proc, void *context, SP_DEVINFO_DATA *duplicate_data)
1753 struct device *device;
1755 TRACE("devinfo %p, data %p, flags %#x, compare_proc %p, context %p, duplicate_data %p.\n",
1756 devinfo, device_data, flags, compare_proc, context, duplicate_data);
1758 if (!(device = get_device(devinfo, device_data)))
1759 return FALSE;
1761 if (device->phantom)
1763 device->phantom = FALSE;
1764 RegDeleteValueW(device->key, Phantom);
1766 return TRUE;
1769 /***********************************************************************
1770 * SetupDiRemoveDevice (SETUPAPI.@)
1772 BOOL WINAPI SetupDiRemoveDevice(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
1774 SC_HANDLE manager = NULL, service = NULL;
1775 struct device *device;
1776 WCHAR *service_name = NULL;
1777 DWORD size;
1779 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
1781 if (!(device = get_device(devinfo, device_data)))
1782 return FALSE;
1784 if (!(manager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT)))
1785 return FALSE;
1787 if (!RegGetValueW(device->key, NULL, L"Service", RRF_RT_REG_SZ, NULL, NULL, &size))
1789 service_name = malloc(size);
1790 if (!RegGetValueW(device->key, NULL, L"Service", RRF_RT_REG_SZ, NULL, service_name, &size))
1791 service = OpenServiceW(manager, service_name, SERVICE_USER_DEFINED_CONTROL);
1794 remove_device(device);
1796 if (service)
1798 SERVICE_STATUS status;
1799 if (!ControlService(service, SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES, &status))
1800 ERR("Failed to control service %s, error %u.\n", debugstr_w(service_name), GetLastError());
1801 CloseServiceHandle(service);
1803 CloseServiceHandle(manager);
1805 free(service_name);
1807 remove_all_device_ifaces(device);
1809 return TRUE;
1812 /***********************************************************************
1813 * SetupDiDeleteDeviceInfo (SETUPAPI.@)
1815 BOOL WINAPI SetupDiDeleteDeviceInfo(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
1817 struct device *device;
1819 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
1821 if (!(device = get_device(devinfo, device_data)))
1822 return FALSE;
1824 delete_device(device);
1826 return TRUE;
1829 /***********************************************************************
1830 * SetupDiRemoveDeviceInterface (SETUPAPI.@)
1832 BOOL WINAPI SetupDiRemoveDeviceInterface(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data)
1834 struct device_iface *iface;
1836 TRACE("devinfo %p, iface_data %p.\n", devinfo, iface_data);
1838 if (!(iface = get_device_iface(devinfo, iface_data)))
1839 return FALSE;
1841 remove_device_iface(iface);
1843 return TRUE;
1846 /***********************************************************************
1847 * SetupDiDeleteDeviceInterfaceData (SETUPAPI.@)
1849 BOOL WINAPI SetupDiDeleteDeviceInterfaceData(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data)
1851 struct device_iface *iface;
1853 TRACE("devinfo %p, iface_data %p.\n", devinfo, iface_data);
1855 if (!(iface = get_device_iface(devinfo, iface_data)))
1856 return FALSE;
1858 delete_device_iface(iface);
1860 return TRUE;
1863 /***********************************************************************
1864 * SetupDiEnumDeviceInfo (SETUPAPI.@)
1866 BOOL WINAPI DECLSPEC_HOTPATCH SetupDiEnumDeviceInfo(HDEVINFO devinfo, DWORD index, SP_DEVINFO_DATA *device_data)
1868 struct DeviceInfoSet *set;
1869 struct device *device;
1870 DWORD i = 0;
1872 TRACE("devinfo %p, index %d, device_data %p\n", devinfo, index, device_data);
1874 if (!(set = get_device_set(devinfo)))
1875 return FALSE;
1877 if (!device_data)
1879 SetLastError(ERROR_INVALID_PARAMETER);
1880 return FALSE;
1883 if (device_data->cbSize != sizeof(SP_DEVINFO_DATA))
1885 SetLastError(ERROR_INVALID_USER_BUFFER);
1886 return FALSE;
1889 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
1891 if (i++ == index)
1893 copy_device_data(device_data, device);
1894 return TRUE;
1898 SetLastError(ERROR_NO_MORE_ITEMS);
1899 return FALSE;
1902 /***********************************************************************
1903 * SetupDiGetDeviceInstanceIdA (SETUPAPI.@)
1905 BOOL WINAPI SetupDiGetDeviceInstanceIdA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
1906 char *id, DWORD size, DWORD *needed)
1908 WCHAR idW[MAX_DEVICE_ID_LEN];
1910 TRACE("devinfo %p, device_data %p, id %p, size %d, needed %p.\n",
1911 devinfo, device_data, id, size, needed);
1913 if (!SetupDiGetDeviceInstanceIdW(devinfo, device_data, idW, ARRAY_SIZE(idW), NULL))
1914 return FALSE;
1916 if (needed)
1917 *needed = WideCharToMultiByte(CP_ACP, 0, idW, -1, NULL, 0, NULL, NULL);
1919 if (size && WideCharToMultiByte(CP_ACP, 0, idW, -1, id, size, NULL, NULL))
1920 return TRUE;
1922 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1923 return FALSE;
1926 /***********************************************************************
1927 * SetupDiGetDeviceInstanceIdW (SETUPAPI.@)
1929 BOOL WINAPI SetupDiGetDeviceInstanceIdW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
1930 WCHAR *DeviceInstanceId, DWORD DeviceInstanceIdSize, DWORD *RequiredSize)
1932 struct device *device;
1934 TRACE("devinfo %p, device_data %p, DeviceInstanceId %p, DeviceInstanceIdSize %d, RequiredSize %p.\n",
1935 devinfo, device_data, DeviceInstanceId, DeviceInstanceIdSize, RequiredSize);
1937 if (!(device = get_device(devinfo, device_data)))
1938 return FALSE;
1940 TRACE("instance ID: %s\n", debugstr_w(device->instanceId));
1941 if (DeviceInstanceIdSize < lstrlenW(device->instanceId) + 1)
1943 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1944 if (RequiredSize)
1945 *RequiredSize = lstrlenW(device->instanceId) + 1;
1946 return FALSE;
1948 lstrcpyW(DeviceInstanceId, device->instanceId);
1949 if (RequiredSize)
1950 *RequiredSize = lstrlenW(device->instanceId) + 1;
1951 return TRUE;
1954 /***********************************************************************
1955 * SetupDiGetActualSectionToInstallExA (SETUPAPI.@)
1957 BOOL WINAPI SetupDiGetActualSectionToInstallExA(HINF hinf, const char *section, SP_ALTPLATFORM_INFO *altplatform,
1958 char *section_ext, DWORD size, DWORD *needed, char **extptr, void *reserved)
1960 WCHAR sectionW[LINE_LEN], section_extW[LINE_LEN], *extptrW;
1961 BOOL ret;
1963 MultiByteToWideChar(CP_ACP, 0, section, -1, sectionW, ARRAY_SIZE(sectionW));
1965 ret = SetupDiGetActualSectionToInstallExW(hinf, sectionW, altplatform, section_extW,
1966 ARRAY_SIZE(section_extW), NULL, &extptrW, reserved);
1967 if (ret)
1969 if (needed)
1970 *needed = WideCharToMultiByte(CP_ACP, 0, section_extW, -1, NULL, 0, NULL, NULL);
1972 if (section_ext)
1973 ret = !!WideCharToMultiByte(CP_ACP, 0, section_extW, -1, section_ext, size, NULL, NULL);
1975 if (extptr)
1977 if (extptrW)
1978 *extptr = section_ext + WideCharToMultiByte(CP_ACP, 0, section_extW,
1979 extptrW - section_extW, NULL, 0, NULL, NULL);
1980 else
1981 *extptr = NULL;
1985 return ret;
1988 /***********************************************************************
1989 * SetupDiGetActualSectionToInstallA (SETUPAPI.@)
1991 BOOL WINAPI SetupDiGetActualSectionToInstallA(HINF hinf, const char *section, char *section_ext,
1992 DWORD size, DWORD *needed, char **extptr)
1994 return SetupDiGetActualSectionToInstallExA(hinf, section, NULL, section_ext, size,
1995 needed, extptr, NULL);
1998 /***********************************************************************
1999 * SetupDiGetActualSectionToInstallExW (SETUPAPI.@)
2001 BOOL WINAPI SetupDiGetActualSectionToInstallExW(HINF hinf, const WCHAR *section, SP_ALTPLATFORM_INFO *altplatform,
2002 WCHAR *section_ext, DWORD size, DWORD *needed, WCHAR **extptr, void *reserved)
2004 WCHAR buffer[MAX_PATH];
2005 DWORD len;
2006 DWORD full_len;
2007 LONG line_count = -1;
2009 TRACE("hinf %p, section %s, altplatform %p, ext %p, size %d, needed %p, extptr %p, reserved %p.\n",
2010 hinf, debugstr_w(section), altplatform, section_ext, size, needed, extptr, reserved);
2012 if (altplatform)
2013 FIXME("SP_ALTPLATFORM_INFO unsupported\n");
2015 lstrcpyW(buffer, section);
2016 len = lstrlenW(buffer);
2018 if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
2020 /* Test section name with '.NTx86' extension */
2021 lstrcpyW(&buffer[len], NtPlatformExtension);
2022 line_count = SetupGetLineCountW(hinf, buffer);
2024 if (line_count == -1)
2026 /* Test section name with '.NT' extension */
2027 lstrcpyW(&buffer[len], NtExtension);
2028 line_count = SetupGetLineCountW(hinf, buffer);
2031 else
2033 /* Test section name with '.Win' extension */
2034 lstrcpyW(&buffer[len], WinExtension);
2035 line_count = SetupGetLineCountW(hinf, buffer);
2038 if (line_count == -1)
2039 buffer[len] = 0;
2041 full_len = lstrlenW(buffer);
2043 if (section_ext != NULL && size != 0)
2045 if (size < (full_len + 1))
2047 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2048 return FALSE;
2051 lstrcpyW(section_ext, buffer);
2052 if (extptr != NULL)
2054 *extptr = (len == full_len) ? NULL : &section_ext[len];
2058 if (needed != NULL)
2060 *needed = full_len + 1;
2063 return TRUE;
2066 /***********************************************************************
2067 * SetupDiGetActualSectionToInstallW (SETUPAPI.@)
2069 BOOL WINAPI SetupDiGetActualSectionToInstallW(HINF hinf, const WCHAR *section, WCHAR *section_ext,
2070 DWORD size, DWORD *needed, WCHAR **extptr)
2072 return SetupDiGetActualSectionToInstallExW(hinf, section, NULL, section_ext, size,
2073 needed, extptr, NULL);
2076 /***********************************************************************
2077 * SetupDiGetClassDescriptionA (SETUPAPI.@)
2079 BOOL WINAPI SetupDiGetClassDescriptionA(
2080 const GUID* ClassGuid,
2081 PSTR ClassDescription,
2082 DWORD ClassDescriptionSize,
2083 PDWORD RequiredSize)
2085 return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
2086 ClassDescriptionSize,
2087 RequiredSize, NULL, NULL);
2090 /***********************************************************************
2091 * SetupDiGetClassDescriptionW (SETUPAPI.@)
2093 BOOL WINAPI SetupDiGetClassDescriptionW(
2094 const GUID* ClassGuid,
2095 PWSTR ClassDescription,
2096 DWORD ClassDescriptionSize,
2097 PDWORD RequiredSize)
2099 return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
2100 ClassDescriptionSize,
2101 RequiredSize, NULL, NULL);
2104 /***********************************************************************
2105 * SetupDiGetClassDescriptionExA (SETUPAPI.@)
2107 BOOL WINAPI SetupDiGetClassDescriptionExA(
2108 const GUID* ClassGuid,
2109 PSTR ClassDescription,
2110 DWORD ClassDescriptionSize,
2111 PDWORD RequiredSize,
2112 PCSTR MachineName,
2113 PVOID Reserved)
2115 HKEY hKey;
2116 DWORD dwLength;
2117 BOOL ret;
2119 hKey = SetupDiOpenClassRegKeyExA(ClassGuid,
2120 KEY_ALL_ACCESS,
2121 DIOCR_INSTALLER,
2122 MachineName,
2123 Reserved);
2124 if (hKey == INVALID_HANDLE_VALUE)
2126 WARN("SetupDiOpenClassRegKeyExA() failed (Error %u)\n", GetLastError());
2127 return FALSE;
2130 dwLength = ClassDescriptionSize;
2131 ret = !RegQueryValueExA( hKey, NULL, NULL, NULL,
2132 (LPBYTE)ClassDescription, &dwLength );
2133 if (RequiredSize) *RequiredSize = dwLength;
2134 RegCloseKey(hKey);
2135 return ret;
2138 /***********************************************************************
2139 * SetupDiGetClassDescriptionExW (SETUPAPI.@)
2141 BOOL WINAPI SetupDiGetClassDescriptionExW(
2142 const GUID* ClassGuid,
2143 PWSTR ClassDescription,
2144 DWORD ClassDescriptionSize,
2145 PDWORD RequiredSize,
2146 PCWSTR MachineName,
2147 PVOID Reserved)
2149 HKEY hKey;
2150 DWORD dwLength;
2151 BOOL ret;
2153 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
2154 KEY_ALL_ACCESS,
2155 DIOCR_INSTALLER,
2156 MachineName,
2157 Reserved);
2158 if (hKey == INVALID_HANDLE_VALUE)
2160 WARN("SetupDiOpenClassRegKeyExW() failed (Error %u)\n", GetLastError());
2161 return FALSE;
2164 dwLength = ClassDescriptionSize * sizeof(WCHAR);
2165 ret = !RegQueryValueExW( hKey, NULL, NULL, NULL,
2166 (LPBYTE)ClassDescription, &dwLength );
2167 if (RequiredSize) *RequiredSize = dwLength / sizeof(WCHAR);
2168 RegCloseKey(hKey);
2169 return ret;
2172 /***********************************************************************
2173 * SetupDiGetClassDevsA (SETUPAPI.@)
2175 HDEVINFO WINAPI SetupDiGetClassDevsA(const GUID *class, LPCSTR enumstr, HWND parent, DWORD flags)
2177 HDEVINFO ret;
2178 LPWSTR enumstrW = NULL;
2180 if (enumstr)
2182 int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
2183 enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2184 if (!enumstrW)
2186 ret = INVALID_HANDLE_VALUE;
2187 goto end;
2189 MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
2191 ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, NULL, NULL,
2192 NULL);
2193 HeapFree(GetProcessHeap(), 0, enumstrW);
2195 end:
2196 return ret;
2199 /***********************************************************************
2200 * SetupDiGetClassDevsExA (SETUPAPI.@)
2202 HDEVINFO WINAPI SetupDiGetClassDevsExA(
2203 const GUID *class,
2204 PCSTR enumstr,
2205 HWND parent,
2206 DWORD flags,
2207 HDEVINFO deviceset,
2208 PCSTR machine,
2209 PVOID reserved)
2211 HDEVINFO ret;
2212 LPWSTR enumstrW = NULL, machineW = NULL;
2214 if (enumstr)
2216 int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
2217 enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2218 if (!enumstrW)
2220 ret = INVALID_HANDLE_VALUE;
2221 goto end;
2223 MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
2225 if (machine)
2227 int len = MultiByteToWideChar(CP_ACP, 0, machine, -1, NULL, 0);
2228 machineW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2229 if (!machineW)
2231 HeapFree(GetProcessHeap(), 0, enumstrW);
2232 ret = INVALID_HANDLE_VALUE;
2233 goto end;
2235 MultiByteToWideChar(CP_ACP, 0, machine, -1, machineW, len);
2237 ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset,
2238 machineW, reserved);
2239 HeapFree(GetProcessHeap(), 0, enumstrW);
2240 HeapFree(GetProcessHeap(), 0, machineW);
2242 end:
2243 return ret;
2246 static void SETUPDI_AddDeviceInterfaces(struct device *device, HKEY key,
2247 const GUID *guid, DWORD flags)
2249 DWORD i, len;
2250 WCHAR subKeyName[MAX_PATH];
2251 LONG l = ERROR_SUCCESS;
2253 for (i = 0; !l; i++)
2255 len = ARRAY_SIZE(subKeyName);
2256 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2257 if (!l)
2259 HKEY subKey;
2260 struct device_iface *iface;
2262 if (*subKeyName == '#')
2264 /* The subkey name is the reference string, with a '#' prepended */
2265 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2266 if (!l)
2268 WCHAR symbolicLink[MAX_PATH];
2269 DWORD dataType;
2271 if (!(flags & DIGCF_PRESENT) || is_linked(subKey))
2273 iface = SETUPDI_CreateDeviceInterface(device, guid, subKeyName + 1);
2275 len = sizeof(symbolicLink);
2276 l = RegQueryValueExW(subKey, SymbolicLink, NULL, &dataType,
2277 (BYTE *)symbolicLink, &len);
2278 if (!l && dataType == REG_SZ)
2279 SETUPDI_SetInterfaceSymbolicLink(iface, symbolicLink);
2280 RegCloseKey(subKey);
2284 /* Allow enumeration to continue */
2285 l = ERROR_SUCCESS;
2288 /* FIXME: find and add all the device's interfaces to the device */
2291 static void SETUPDI_EnumerateMatchingInterfaces(HDEVINFO DeviceInfoSet,
2292 HKEY key, const GUID *guid, const WCHAR *enumstr, DWORD flags)
2294 struct DeviceInfoSet *set = DeviceInfoSet;
2295 DWORD i, len;
2296 WCHAR subKeyName[MAX_PATH];
2297 LONG l;
2298 HKEY enumKey = INVALID_HANDLE_VALUE;
2300 TRACE("%s\n", debugstr_w(enumstr));
2302 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL,
2303 &enumKey, NULL);
2304 for (i = 0; !l; i++)
2306 len = ARRAY_SIZE(subKeyName);
2307 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2308 if (!l)
2310 HKEY subKey;
2312 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2313 if (!l)
2315 WCHAR deviceInst[MAX_PATH * 3];
2316 DWORD dataType;
2318 len = sizeof(deviceInst);
2319 l = RegQueryValueExW(subKey, DeviceInstance, NULL, &dataType,
2320 (BYTE *)deviceInst, &len);
2321 if (!l && dataType == REG_SZ)
2323 TRACE("found instance ID %s\n", debugstr_w(deviceInst));
2324 if (!enumstr || !lstrcmpiW(enumstr, deviceInst))
2326 HKEY deviceKey;
2328 l = RegOpenKeyExW(enumKey, deviceInst, 0, KEY_READ,
2329 &deviceKey);
2330 if (!l)
2332 WCHAR deviceClassStr[40];
2334 len = sizeof(deviceClassStr);
2335 l = RegQueryValueExW(deviceKey, ClassGUID, NULL,
2336 &dataType, (BYTE *)deviceClassStr, &len);
2337 if (!l && dataType == REG_SZ &&
2338 deviceClassStr[0] == '{' &&
2339 deviceClassStr[37] == '}')
2341 GUID deviceClass;
2342 struct device *device;
2344 deviceClassStr[37] = 0;
2345 UuidFromStringW(&deviceClassStr[1],
2346 &deviceClass);
2347 if ((device = create_device(set, &deviceClass, deviceInst, FALSE)))
2348 SETUPDI_AddDeviceInterfaces(device, subKey, guid, flags);
2350 RegCloseKey(deviceKey);
2354 RegCloseKey(subKey);
2356 /* Allow enumeration to continue */
2357 l = ERROR_SUCCESS;
2360 if (enumKey != INVALID_HANDLE_VALUE)
2361 RegCloseKey(enumKey);
2364 static void SETUPDI_EnumerateInterfaces(HDEVINFO DeviceInfoSet,
2365 const GUID *guid, LPCWSTR enumstr, DWORD flags)
2367 HKEY interfacesKey = SetupDiOpenClassRegKeyExW(guid, KEY_READ,
2368 DIOCR_INTERFACE, NULL, NULL);
2370 TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(guid),
2371 debugstr_w(enumstr), flags);
2373 if (interfacesKey != INVALID_HANDLE_VALUE)
2375 if (flags & DIGCF_ALLCLASSES)
2377 DWORD i, len;
2378 WCHAR interfaceGuidStr[40];
2379 LONG l = ERROR_SUCCESS;
2381 for (i = 0; !l; i++)
2383 len = ARRAY_SIZE(interfaceGuidStr);
2384 l = RegEnumKeyExW(interfacesKey, i, interfaceGuidStr, &len,
2385 NULL, NULL, NULL, NULL);
2386 if (!l)
2388 if (interfaceGuidStr[0] == '{' &&
2389 interfaceGuidStr[37] == '}')
2391 HKEY interfaceKey;
2392 GUID interfaceGuid;
2394 interfaceGuidStr[37] = 0;
2395 UuidFromStringW(&interfaceGuidStr[1], &interfaceGuid);
2396 interfaceGuidStr[37] = '}';
2397 interfaceGuidStr[38] = 0;
2398 l = RegOpenKeyExW(interfacesKey, interfaceGuidStr, 0,
2399 KEY_READ, &interfaceKey);
2400 if (!l)
2402 SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
2403 interfaceKey, &interfaceGuid, enumstr, flags);
2404 RegCloseKey(interfaceKey);
2410 else
2412 /* In this case, SetupDiOpenClassRegKeyExW opened the specific
2413 * interface's key, so just pass that long
2415 SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
2416 interfacesKey, guid, enumstr, flags);
2418 RegCloseKey(interfacesKey);
2422 static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set,
2423 LPCWSTR enumerator, LPCWSTR deviceName, HKEY deviceKey,
2424 const GUID *class, DWORD flags)
2426 WCHAR id[MAX_DEVICE_ID_LEN];
2427 DWORD i, len;
2428 WCHAR deviceInstance[MAX_PATH];
2429 LONG l = ERROR_SUCCESS;
2431 TRACE("%s %s\n", debugstr_w(enumerator), debugstr_w(deviceName));
2433 for (i = 0; !l; i++)
2435 len = ARRAY_SIZE(deviceInstance);
2436 l = RegEnumKeyExW(deviceKey, i, deviceInstance, &len, NULL, NULL, NULL,
2437 NULL);
2438 if (!l)
2440 HKEY subKey;
2442 l = RegOpenKeyExW(deviceKey, deviceInstance, 0, KEY_READ, &subKey);
2443 if (!l)
2445 WCHAR classGuid[40];
2446 DWORD dataType;
2448 len = sizeof(classGuid);
2449 l = RegQueryValueExW(subKey, ClassGUID, NULL, &dataType,
2450 (BYTE *)classGuid, &len);
2451 if (!l && dataType == REG_SZ)
2453 if (classGuid[0] == '{' && classGuid[37] == '}')
2455 GUID deviceClass;
2457 classGuid[37] = 0;
2458 UuidFromStringW(&classGuid[1], &deviceClass);
2459 if ((flags & DIGCF_ALLCLASSES) ||
2460 IsEqualGUID(class, &deviceClass))
2462 static const WCHAR fmt[] =
2463 {'%','s','\\','%','s','\\','%','s',0};
2465 if (swprintf(id, ARRAY_SIZE(id), fmt, enumerator,
2466 deviceName, deviceInstance) != -1)
2468 create_device(set, &deviceClass, id, FALSE);
2473 RegCloseKey(subKey);
2475 /* Allow enumeration to continue */
2476 l = ERROR_SUCCESS;
2481 static void SETUPDI_EnumerateMatchingDevices(HDEVINFO DeviceInfoSet,
2482 LPCWSTR parent, HKEY key, const GUID *class, DWORD flags)
2484 struct DeviceInfoSet *set = DeviceInfoSet;
2485 DWORD i, len;
2486 WCHAR subKeyName[MAX_PATH];
2487 LONG l = ERROR_SUCCESS;
2489 TRACE("%s\n", debugstr_w(parent));
2491 for (i = 0; !l; i++)
2493 len = ARRAY_SIZE(subKeyName);
2494 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2495 if (!l)
2497 HKEY subKey;
2499 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2500 if (!l)
2502 TRACE("%s\n", debugstr_w(subKeyName));
2503 SETUPDI_EnumerateMatchingDeviceInstances(set, parent,
2504 subKeyName, subKey, class, flags);
2505 RegCloseKey(subKey);
2507 /* Allow enumeration to continue */
2508 l = ERROR_SUCCESS;
2513 static void SETUPDI_EnumerateDevices(HDEVINFO DeviceInfoSet, const GUID *class,
2514 LPCWSTR enumstr, DWORD flags)
2516 HKEY enumKey;
2517 LONG l;
2519 TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(class),
2520 debugstr_w(enumstr), flags);
2522 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL,
2523 &enumKey, NULL);
2524 if (enumKey != INVALID_HANDLE_VALUE)
2526 if (enumstr)
2528 HKEY enumStrKey;
2530 l = RegOpenKeyExW(enumKey, enumstr, 0, KEY_READ,
2531 &enumStrKey);
2532 if (!l)
2534 WCHAR *bus, *device;
2536 if (!wcschr(enumstr, '\\'))
2538 SETUPDI_EnumerateMatchingDevices(DeviceInfoSet, enumstr, enumStrKey, class, flags);
2540 else if ((bus = strdupW(enumstr)))
2542 device = wcschr(bus, '\\');
2543 *device++ = 0;
2545 SETUPDI_EnumerateMatchingDeviceInstances(DeviceInfoSet, bus, device, enumStrKey, class, flags);
2546 HeapFree(GetProcessHeap(), 0, bus);
2549 RegCloseKey(enumStrKey);
2552 else
2554 DWORD i, len;
2555 WCHAR subKeyName[MAX_PATH];
2557 l = ERROR_SUCCESS;
2558 for (i = 0; !l; i++)
2560 len = ARRAY_SIZE(subKeyName);
2561 l = RegEnumKeyExW(enumKey, i, subKeyName, &len, NULL,
2562 NULL, NULL, NULL);
2563 if (!l)
2565 HKEY subKey;
2567 l = RegOpenKeyExW(enumKey, subKeyName, 0, KEY_READ,
2568 &subKey);
2569 if (!l)
2571 SETUPDI_EnumerateMatchingDevices(DeviceInfoSet,
2572 subKeyName, subKey, class, flags);
2573 RegCloseKey(subKey);
2575 /* Allow enumeration to continue */
2576 l = ERROR_SUCCESS;
2580 RegCloseKey(enumKey);
2584 /***********************************************************************
2585 * SetupDiGetClassDevsW (SETUPAPI.@)
2587 HDEVINFO WINAPI SetupDiGetClassDevsW(const GUID *class, LPCWSTR enumstr, HWND parent, DWORD flags)
2589 return SetupDiGetClassDevsExW(class, enumstr, parent, flags, NULL, NULL,
2590 NULL);
2593 /***********************************************************************
2594 * SetupDiGetClassDevsExW (SETUPAPI.@)
2596 HDEVINFO WINAPI SetupDiGetClassDevsExW(const GUID *class, PCWSTR enumstr, HWND parent, DWORD flags,
2597 HDEVINFO deviceset, PCWSTR machine, void *reserved)
2599 static const DWORD unsupportedFlags = DIGCF_DEFAULT | DIGCF_PROFILE;
2600 HDEVINFO set;
2602 TRACE("%s %s %p 0x%08x %p %s %p\n", debugstr_guid(class),
2603 debugstr_w(enumstr), parent, flags, deviceset, debugstr_w(machine),
2604 reserved);
2606 if (!(flags & DIGCF_ALLCLASSES) && !class)
2608 SetLastError(ERROR_INVALID_PARAMETER);
2609 return INVALID_HANDLE_VALUE;
2611 if (flags & DIGCF_ALLCLASSES)
2612 class = NULL;
2614 if (flags & unsupportedFlags)
2615 WARN("unsupported flags %08x\n", flags & unsupportedFlags);
2616 if (deviceset)
2617 set = deviceset;
2618 else
2619 set = SetupDiCreateDeviceInfoListExW((flags & DIGCF_DEVICEINTERFACE) ? NULL : class, parent, machine, reserved);
2620 if (set != INVALID_HANDLE_VALUE)
2622 if (machine && *machine)
2623 FIXME("%s: unimplemented for remote machines\n",
2624 debugstr_w(machine));
2625 else if (flags & DIGCF_DEVICEINTERFACE)
2626 SETUPDI_EnumerateInterfaces(set, class, enumstr, flags);
2627 else
2628 SETUPDI_EnumerateDevices(set, class, enumstr, flags);
2630 return set;
2633 /***********************************************************************
2634 * SetupDiGetDeviceInfoListDetailA (SETUPAPI.@)
2636 BOOL WINAPI SetupDiGetDeviceInfoListDetailA(HDEVINFO devinfo, SP_DEVINFO_LIST_DETAIL_DATA_A *DevInfoData)
2638 struct DeviceInfoSet *set;
2640 TRACE("devinfo %p, detail_data %p.\n", devinfo, DevInfoData);
2642 if (!(set = get_device_set(devinfo)))
2643 return FALSE;
2645 if (!DevInfoData ||
2646 DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_A))
2648 SetLastError(ERROR_INVALID_PARAMETER);
2649 return FALSE;
2651 DevInfoData->ClassGuid = set->ClassGuid;
2652 DevInfoData->RemoteMachineHandle = NULL;
2653 DevInfoData->RemoteMachineName[0] = '\0';
2654 return TRUE;
2657 /***********************************************************************
2658 * SetupDiGetDeviceInfoListDetailW (SETUPAPI.@)
2660 BOOL WINAPI SetupDiGetDeviceInfoListDetailW(HDEVINFO devinfo, SP_DEVINFO_LIST_DETAIL_DATA_W *DevInfoData)
2662 struct DeviceInfoSet *set;
2664 TRACE("devinfo %p, detail_data %p.\n", devinfo, DevInfoData);
2666 if (!(set = get_device_set(devinfo)))
2667 return FALSE;
2669 if (!DevInfoData ||
2670 DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W))
2672 SetLastError(ERROR_INVALID_PARAMETER);
2673 return FALSE;
2675 DevInfoData->ClassGuid = set->ClassGuid;
2676 DevInfoData->RemoteMachineHandle = NULL;
2677 DevInfoData->RemoteMachineName[0] = '\0';
2678 return TRUE;
2681 /***********************************************************************
2682 * SetupDiCreateDeviceInterfaceA (SETUPAPI.@)
2684 BOOL WINAPI SetupDiCreateDeviceInterfaceA(
2685 HDEVINFO DeviceInfoSet,
2686 PSP_DEVINFO_DATA DeviceInfoData,
2687 const GUID *InterfaceClassGuid,
2688 PCSTR ReferenceString,
2689 DWORD CreationFlags,
2690 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2692 BOOL ret;
2693 LPWSTR ReferenceStringW = NULL;
2695 TRACE("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
2696 debugstr_guid(InterfaceClassGuid), debugstr_a(ReferenceString),
2697 CreationFlags, DeviceInterfaceData);
2699 if (ReferenceString)
2701 ReferenceStringW = MultiByteToUnicode(ReferenceString, CP_ACP);
2702 if (ReferenceStringW == NULL) return FALSE;
2705 ret = SetupDiCreateDeviceInterfaceW(DeviceInfoSet, DeviceInfoData,
2706 InterfaceClassGuid, ReferenceStringW, CreationFlags,
2707 DeviceInterfaceData);
2709 MyFree(ReferenceStringW);
2711 return ret;
2714 /***********************************************************************
2715 * SetupDiCreateDeviceInterfaceW (SETUPAPI.@)
2717 BOOL WINAPI SetupDiCreateDeviceInterfaceW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
2718 const GUID *class, const WCHAR *refstr, DWORD flags, SP_DEVICE_INTERFACE_DATA *iface_data)
2720 struct device *device;
2721 struct device_iface *iface;
2723 TRACE("devinfo %p, device_data %p, class %s, refstr %s, flags %#x, iface_data %p.\n",
2724 devinfo, device_data, debugstr_guid(class), debugstr_w(refstr), flags, iface_data);
2726 if (!(device = get_device(devinfo, device_data)))
2727 return FALSE;
2729 if (!class)
2731 SetLastError(ERROR_INVALID_USER_BUFFER);
2732 return FALSE;
2735 if (!(iface = SETUPDI_CreateDeviceInterface(device, class, refstr)))
2736 return FALSE;
2738 if (iface_data)
2740 if (iface_data->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2742 SetLastError(ERROR_INVALID_USER_BUFFER);
2743 return FALSE;
2746 copy_device_iface_data(iface_data, iface);
2748 return TRUE;
2751 /***********************************************************************
2752 * SetupDiCreateDeviceInterfaceRegKeyA (SETUPAPI.@)
2754 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyA(
2755 HDEVINFO DeviceInfoSet,
2756 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2757 DWORD Reserved,
2758 REGSAM samDesired,
2759 HINF InfHandle,
2760 PCSTR InfSectionName)
2762 HKEY key;
2763 PWSTR InfSectionNameW = NULL;
2765 TRACE("%p %p %d %08x %p %p\n", DeviceInfoSet, DeviceInterfaceData, Reserved,
2766 samDesired, InfHandle, InfSectionName);
2767 if (InfHandle)
2769 if (!InfSectionName)
2771 SetLastError(ERROR_INVALID_PARAMETER);
2772 return INVALID_HANDLE_VALUE;
2774 InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
2775 if (!InfSectionNameW)
2776 return INVALID_HANDLE_VALUE;
2778 key = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet,
2779 DeviceInterfaceData, Reserved, samDesired, InfHandle,
2780 InfSectionNameW);
2781 MyFree(InfSectionNameW);
2782 return key;
2785 static LONG create_iface_key(const struct device_iface *iface, REGSAM access, HKEY *key)
2787 return RegCreateKeyExW(iface->refstr_key, DeviceParameters, 0, NULL, 0, access, NULL, key, NULL);
2790 /***********************************************************************
2791 * SetupDiCreateDeviceInterfaceRegKeyW (SETUPAPI.@)
2793 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyW(HDEVINFO devinfo,
2794 SP_DEVICE_INTERFACE_DATA *iface_data, DWORD reserved, REGSAM access,
2795 HINF hinf, const WCHAR *section)
2797 struct device_iface *iface;
2798 HKEY params_key;
2799 LONG ret;
2801 TRACE("devinfo %p, iface_data %p, reserved %d, access %#x, hinf %p, section %s.\n",
2802 devinfo, iface_data, reserved, access, hinf, debugstr_w(section));
2804 if (!(iface = get_device_iface(devinfo, iface_data)))
2805 return INVALID_HANDLE_VALUE;
2807 if (hinf && !section)
2809 SetLastError(ERROR_INVALID_PARAMETER);
2810 return INVALID_HANDLE_VALUE;
2813 ret = create_iface_key(iface, access, &params_key);
2814 if (ret)
2816 SetLastError(ret);
2817 return INVALID_HANDLE_VALUE;
2820 return params_key;
2823 /***********************************************************************
2824 * SetupDiDeleteDeviceInterfaceRegKey (SETUPAPI.@)
2826 BOOL WINAPI SetupDiDeleteDeviceInterfaceRegKey(HDEVINFO devinfo,
2827 SP_DEVICE_INTERFACE_DATA *iface_data, DWORD reserved)
2829 struct device_iface *iface;
2830 LONG ret;
2832 TRACE("devinfo %p, iface_data %p, reserved %d.\n", devinfo, iface_data, reserved);
2834 if (!(iface = get_device_iface(devinfo, iface_data)))
2835 return FALSE;
2837 ret = RegDeleteKeyW(iface->refstr_key, DeviceParameters);
2838 if (ret)
2840 SetLastError(ret);
2841 return FALSE;
2844 return TRUE;
2847 /***********************************************************************
2848 * SetupDiEnumDeviceInterfaces (SETUPAPI.@)
2850 * PARAMS
2851 * DeviceInfoSet [I] Set of devices from which to enumerate
2852 * interfaces
2853 * DeviceInfoData [I] (Optional) If specified, a specific device
2854 * instance from which to enumerate interfaces.
2855 * If it isn't specified, all interfaces for all
2856 * devices in the set are enumerated.
2857 * InterfaceClassGuid [I] The interface class to enumerate.
2858 * MemberIndex [I] An index of the interface instance to enumerate.
2859 * A caller should start with MemberIndex set to 0,
2860 * and continue until the function fails with
2861 * ERROR_NO_MORE_ITEMS.
2862 * DeviceInterfaceData [I/O] Returns an enumerated interface. Its cbSize
2863 * member must be set to
2864 * sizeof(SP_DEVICE_INTERFACE_DATA).
2866 * RETURNS
2867 * Success: non-zero value.
2868 * Failure: FALSE. Call GetLastError() for more info.
2870 BOOL WINAPI SetupDiEnumDeviceInterfaces(HDEVINFO devinfo,
2871 SP_DEVINFO_DATA *device_data, const GUID *class, DWORD index,
2872 SP_DEVICE_INTERFACE_DATA *iface_data)
2874 struct DeviceInfoSet *set;
2875 struct device *device;
2876 struct device_iface *iface;
2877 DWORD i = 0;
2879 TRACE("devinfo %p, device_data %p, class %s, index %u, iface_data %p.\n",
2880 devinfo, device_data, debugstr_guid(class), index, iface_data);
2882 if (!iface_data || iface_data->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2884 SetLastError(ERROR_INVALID_PARAMETER);
2885 return FALSE;
2888 /* In case application fails to check return value, clear output */
2889 memset(iface_data, 0, sizeof(*iface_data));
2890 iface_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
2892 if (device_data)
2894 if (!(device = get_device(devinfo, device_data)))
2895 return FALSE;
2897 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
2899 if (IsEqualGUID(&iface->class, class))
2901 if (i == index)
2903 copy_device_iface_data(iface_data, iface);
2904 return TRUE;
2906 i++;
2910 else
2912 if (!(set = get_device_set(devinfo)))
2913 return FALSE;
2915 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
2917 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
2919 if (IsEqualGUID(&iface->class, class))
2921 if (i == index)
2923 copy_device_iface_data(iface_data, iface);
2924 return TRUE;
2926 i++;
2932 SetLastError(ERROR_NO_MORE_ITEMS);
2933 return FALSE;
2936 /***********************************************************************
2937 * SetupDiDestroyDeviceInfoList (SETUPAPI.@)
2939 * Destroy a DeviceInfoList and free all used memory of the list.
2941 * PARAMS
2942 * devinfo [I] DeviceInfoList pointer to list to destroy
2944 * RETURNS
2945 * Success: non zero value.
2946 * Failure: zero value.
2948 BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
2950 struct DeviceInfoSet *set;
2951 struct device *device, *device2;
2953 TRACE("devinfo %p.\n", devinfo);
2955 if (!(set = get_device_set(devinfo)))
2956 return FALSE;
2958 LIST_FOR_EACH_ENTRY_SAFE(device, device2, &set->devices, struct device, entry)
2960 delete_device(device);
2962 heap_free(set);
2964 SetLastError(ERROR_SUCCESS);
2965 return TRUE;
2968 /***********************************************************************
2969 * SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
2971 BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data,
2972 SP_DEVICE_INTERFACE_DETAIL_DATA_A *DeviceInterfaceDetailData,
2973 DWORD DeviceInterfaceDetailDataSize, DWORD *RequiredSize, SP_DEVINFO_DATA *device_data)
2975 struct device_iface *iface;
2976 DWORD bytesNeeded = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath[1]);
2977 BOOL ret = FALSE;
2979 TRACE("devinfo %p, iface_data %p, detail_data %p, size %d, needed %p, device_data %p.\n",
2980 devinfo, iface_data, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize,
2981 RequiredSize, device_data);
2983 if (!(iface = get_device_iface(devinfo, iface_data)))
2984 return FALSE;
2986 if (DeviceInterfaceDetailData &&
2987 DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A))
2989 SetLastError(ERROR_INVALID_USER_BUFFER);
2990 return FALSE;
2992 if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
2994 SetLastError(ERROR_INVALID_USER_BUFFER);
2995 return FALSE;
2998 if (iface->symlink)
2999 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, iface->symlink, -1,
3000 NULL, 0, NULL, NULL);
3001 if (DeviceInterfaceDetailDataSize >= bytesNeeded)
3003 if (iface->symlink)
3004 WideCharToMultiByte(CP_ACP, 0, iface->symlink, -1,
3005 DeviceInterfaceDetailData->DevicePath,
3006 DeviceInterfaceDetailDataSize -
3007 offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
3008 NULL, NULL);
3009 else
3010 DeviceInterfaceDetailData->DevicePath[0] = '\0';
3012 ret = TRUE;
3014 else
3016 if (RequiredSize)
3017 *RequiredSize = bytesNeeded;
3018 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3021 if (device_data && device_data->cbSize == sizeof(SP_DEVINFO_DATA))
3022 copy_device_data(device_data, iface->device);
3024 return ret;
3027 /***********************************************************************
3028 * SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
3030 BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data,
3031 SP_DEVICE_INTERFACE_DETAIL_DATA_W *DeviceInterfaceDetailData,
3032 DWORD DeviceInterfaceDetailDataSize, DWORD *RequiredSize, SP_DEVINFO_DATA *device_data)
3034 struct device_iface *iface;
3035 DWORD bytesNeeded = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
3036 + sizeof(WCHAR); /* include NULL terminator */
3037 BOOL ret = FALSE;
3039 TRACE("devinfo %p, iface_data %p, detail_data %p, size %d, needed %p, device_data %p.\n",
3040 devinfo, iface_data, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize,
3041 RequiredSize, device_data);
3043 if (!(iface = get_device_iface(devinfo, iface_data)))
3044 return FALSE;
3046 if (DeviceInterfaceDetailData && (DeviceInterfaceDetailData->cbSize <
3047 offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR) ||
3048 DeviceInterfaceDetailData->cbSize > sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W)))
3050 SetLastError(ERROR_INVALID_USER_BUFFER);
3051 return FALSE;
3053 if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
3055 SetLastError(ERROR_INVALID_USER_BUFFER);
3056 return FALSE;
3059 if (iface->symlink)
3060 bytesNeeded += sizeof(WCHAR) * lstrlenW(iface->symlink);
3061 if (DeviceInterfaceDetailDataSize >= bytesNeeded)
3063 if (iface->symlink)
3064 lstrcpyW(DeviceInterfaceDetailData->DevicePath, iface->symlink);
3065 else
3066 DeviceInterfaceDetailData->DevicePath[0] = '\0';
3068 ret = TRUE;
3070 else
3072 if (RequiredSize)
3073 *RequiredSize = bytesNeeded;
3074 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3077 if (device_data && device_data->cbSize == sizeof(SP_DEVINFO_DATA))
3078 copy_device_data(device_data, iface->device);
3080 return ret;
3083 /***********************************************************************
3084 * SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
3086 BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(HDEVINFO devinfo,
3087 SP_DEVINFO_DATA *device_data, DWORD Property, DWORD *PropertyRegDataType,
3088 BYTE *PropertyBuffer, DWORD PropertyBufferSize, DWORD *RequiredSize)
3090 BOOL ret = FALSE;
3091 struct device *device;
3093 TRACE("devinfo %p, device_data %p, property %d, type %p, buffer %p, size %d, required %p\n",
3094 devinfo, device_data, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize);
3096 if (!(device = get_device(devinfo, device_data)))
3097 return FALSE;
3099 if (PropertyBufferSize && PropertyBuffer == NULL)
3101 SetLastError(ERROR_INVALID_DATA);
3102 return FALSE;
3105 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameA)
3107 DWORD size = PropertyBufferSize;
3108 LONG l = RegQueryValueExA(device->key, PropertyMap[Property].nameA,
3109 NULL, PropertyRegDataType, PropertyBuffer, &size);
3111 if (l == ERROR_FILE_NOT_FOUND)
3112 SetLastError(ERROR_INVALID_DATA);
3113 else if (l == ERROR_MORE_DATA || !PropertyBufferSize)
3114 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3115 else if (!l)
3116 ret = TRUE;
3117 else
3118 SetLastError(l);
3119 if (RequiredSize)
3120 *RequiredSize = size;
3122 return ret;
3125 /***********************************************************************
3126 * SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
3128 BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(HDEVINFO devinfo,
3129 SP_DEVINFO_DATA *device_data, DWORD Property, DWORD *PropertyRegDataType,
3130 BYTE *PropertyBuffer, DWORD PropertyBufferSize, DWORD *RequiredSize)
3132 BOOL ret = FALSE;
3133 struct device *device;
3135 TRACE("devinfo %p, device_data %p, prop %d, type %p, buffer %p, size %d, required %p\n",
3136 devinfo, device_data, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize);
3138 if (!(device = get_device(devinfo, device_data)))
3139 return FALSE;
3141 if (PropertyBufferSize && PropertyBuffer == NULL)
3143 SetLastError(ERROR_INVALID_DATA);
3144 return FALSE;
3147 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameW)
3149 DWORD size = PropertyBufferSize;
3150 LONG l = RegQueryValueExW(device->key, PropertyMap[Property].nameW,
3151 NULL, PropertyRegDataType, PropertyBuffer, &size);
3153 if (l == ERROR_FILE_NOT_FOUND)
3154 SetLastError(ERROR_INVALID_DATA);
3155 else if (l == ERROR_MORE_DATA || !PropertyBufferSize)
3156 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3157 else if (!l)
3158 ret = TRUE;
3159 else
3160 SetLastError(l);
3161 if (RequiredSize)
3162 *RequiredSize = size;
3164 return ret;
3167 /***********************************************************************
3168 * SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
3170 BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
3171 DWORD Property, const BYTE *PropertyBuffer, DWORD PropertyBufferSize)
3173 BOOL ret = FALSE;
3174 struct device *device;
3176 TRACE("devinfo %p, device_data %p, prop %d, buffer %p, size %d.\n",
3177 devinfo, device_data, Property, PropertyBuffer, PropertyBufferSize);
3179 if (!(device = get_device(devinfo, device_data)))
3180 return FALSE;
3182 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameA)
3184 LONG l = RegSetValueExA(device->key, PropertyMap[Property].nameA, 0,
3185 PropertyMap[Property].regType, PropertyBuffer,
3186 PropertyBufferSize);
3187 if (!l)
3188 ret = TRUE;
3189 else
3190 SetLastError(l);
3192 return ret;
3195 /***********************************************************************
3196 * SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
3198 BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(HDEVINFO devinfo,
3199 SP_DEVINFO_DATA *device_data, DWORD prop, const BYTE *buffer, DWORD size)
3201 struct device *device;
3203 TRACE("devinfo %p, device_data %p, prop %d, buffer %p, size %d.\n",
3204 devinfo, device_data, prop, buffer, size);
3206 if (!(device = get_device(devinfo, device_data)))
3207 return FALSE;
3209 return SETUPDI_SetDeviceRegistryPropertyW(device, prop, buffer, size);
3212 /***********************************************************************
3213 * SetupDiInstallClassA (SETUPAPI.@)
3215 BOOL WINAPI SetupDiInstallClassA(
3216 HWND hwndParent,
3217 PCSTR InfFileName,
3218 DWORD Flags,
3219 HSPFILEQ FileQueue)
3221 UNICODE_STRING FileNameW;
3222 BOOL Result;
3224 if (!InfFileName)
3226 SetLastError(ERROR_INVALID_PARAMETER);
3227 return FALSE;
3229 if (!RtlCreateUnicodeStringFromAsciiz(&FileNameW, InfFileName))
3231 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3232 return FALSE;
3235 Result = SetupDiInstallClassW(hwndParent, FileNameW.Buffer, Flags, FileQueue);
3237 RtlFreeUnicodeString(&FileNameW);
3239 return Result;
3242 static HKEY CreateClassKey(HINF hInf)
3244 static const WCHAR slash[] = { '\\',0 };
3245 WCHAR FullBuffer[MAX_PATH];
3246 WCHAR Buffer[MAX_PATH];
3247 DWORD RequiredSize;
3248 HKEY hClassKey;
3250 if (!SetupGetLineTextW(NULL,
3251 hInf,
3252 Version,
3253 ClassGUID,
3254 Buffer,
3255 MAX_PATH,
3256 &RequiredSize))
3258 return INVALID_HANDLE_VALUE;
3261 lstrcpyW(FullBuffer, ControlClass);
3262 lstrcatW(FullBuffer, slash);
3263 lstrcatW(FullBuffer, Buffer);
3265 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3266 FullBuffer,
3268 KEY_ALL_ACCESS,
3269 &hClassKey))
3271 if (!SetupGetLineTextW(NULL,
3272 hInf,
3273 Version,
3274 Class,
3275 Buffer,
3276 MAX_PATH,
3277 &RequiredSize))
3279 return INVALID_HANDLE_VALUE;
3282 if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
3283 FullBuffer,
3285 NULL,
3286 REG_OPTION_NON_VOLATILE,
3287 KEY_ALL_ACCESS,
3288 NULL,
3289 &hClassKey,
3290 NULL))
3292 return INVALID_HANDLE_VALUE;
3297 if (RegSetValueExW(hClassKey,
3298 Class,
3300 REG_SZ,
3301 (LPBYTE)Buffer,
3302 RequiredSize * sizeof(WCHAR)))
3304 RegCloseKey(hClassKey);
3305 RegDeleteKeyW(HKEY_LOCAL_MACHINE,
3306 FullBuffer);
3307 return INVALID_HANDLE_VALUE;
3310 return hClassKey;
3313 /***********************************************************************
3314 * SetupDiInstallClassW (SETUPAPI.@)
3316 BOOL WINAPI SetupDiInstallClassW(
3317 HWND hwndParent,
3318 PCWSTR InfFileName,
3319 DWORD Flags,
3320 HSPFILEQ FileQueue)
3322 WCHAR SectionName[MAX_PATH];
3323 DWORD SectionNameLength = 0;
3324 HINF hInf;
3325 BOOL bFileQueueCreated = FALSE;
3326 HKEY hClassKey;
3329 FIXME("\n");
3331 if (!InfFileName)
3333 SetLastError(ERROR_INVALID_PARAMETER);
3334 return FALSE;
3336 if ((Flags & DI_NOVCP) && (FileQueue == NULL || FileQueue == INVALID_HANDLE_VALUE))
3338 SetLastError(ERROR_INVALID_PARAMETER);
3339 return FALSE;
3342 /* Open the .inf file */
3343 hInf = SetupOpenInfFileW(InfFileName,
3344 NULL,
3345 INF_STYLE_WIN4,
3346 NULL);
3347 if (hInf == INVALID_HANDLE_VALUE)
3350 return FALSE;
3353 /* Create or open the class registry key 'HKLM\\CurrentControlSet\\Class\\{GUID}' */
3354 hClassKey = CreateClassKey(hInf);
3355 if (hClassKey == INVALID_HANDLE_VALUE)
3357 SetupCloseInfFile(hInf);
3358 return FALSE;
3362 /* Try to append a layout file */
3363 SetupOpenAppendInfFileW(NULL, hInf, NULL);
3365 /* Retrieve the actual section name */
3366 SetupDiGetActualSectionToInstallW(hInf,
3367 ClassInstall32,
3368 SectionName,
3369 MAX_PATH,
3370 &SectionNameLength,
3371 NULL);
3373 #if 0
3374 if (!(Flags & DI_NOVCP))
3376 FileQueue = SetupOpenFileQueue();
3377 if (FileQueue == INVALID_HANDLE_VALUE)
3379 SetupCloseInfFile(hInf);
3380 return FALSE;
3383 bFileQueueCreated = TRUE;
3386 #endif
3388 SetupInstallFromInfSectionW(NULL,
3389 hInf,
3390 SectionName,
3391 SPINST_COPYINF | SPINST_FILES | SPINST_REGISTRY,
3392 hClassKey,
3393 NULL,
3395 NULL,
3396 NULL,
3397 INVALID_HANDLE_VALUE,
3398 NULL);
3400 /* FIXME: More code! */
3402 if (bFileQueueCreated)
3403 SetupCloseFileQueue(FileQueue);
3405 SetupCloseInfFile(hInf);
3407 return TRUE;
3411 /***********************************************************************
3412 * SetupDiOpenClassRegKey (SETUPAPI.@)
3414 HKEY WINAPI SetupDiOpenClassRegKey(
3415 const GUID* ClassGuid,
3416 REGSAM samDesired)
3418 return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3419 DIOCR_INSTALLER, NULL, NULL);
3423 /***********************************************************************
3424 * SetupDiOpenClassRegKeyExA (SETUPAPI.@)
3426 HKEY WINAPI SetupDiOpenClassRegKeyExA(
3427 const GUID* ClassGuid,
3428 REGSAM samDesired,
3429 DWORD Flags,
3430 PCSTR MachineName,
3431 PVOID Reserved)
3433 PWSTR MachineNameW = NULL;
3434 HKEY hKey;
3436 TRACE("\n");
3438 if (MachineName)
3440 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
3441 if (MachineNameW == NULL)
3442 return INVALID_HANDLE_VALUE;
3445 hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3446 Flags, MachineNameW, Reserved);
3448 MyFree(MachineNameW);
3450 return hKey;
3454 /***********************************************************************
3455 * SetupDiOpenClassRegKeyExW (SETUPAPI.@)
3457 HKEY WINAPI SetupDiOpenClassRegKeyExW(
3458 const GUID* ClassGuid,
3459 REGSAM samDesired,
3460 DWORD Flags,
3461 PCWSTR MachineName,
3462 PVOID Reserved)
3464 HKEY hClassesKey;
3465 HKEY key;
3466 LPCWSTR lpKeyName;
3467 LONG l;
3469 if (MachineName && *MachineName)
3471 FIXME("Remote access not supported yet!\n");
3472 return INVALID_HANDLE_VALUE;
3475 if (Flags == DIOCR_INSTALLER)
3477 lpKeyName = ControlClass;
3479 else if (Flags == DIOCR_INTERFACE)
3481 lpKeyName = DeviceClasses;
3483 else
3485 ERR("Invalid Flags parameter!\n");
3486 SetLastError(ERROR_INVALID_PARAMETER);
3487 return INVALID_HANDLE_VALUE;
3490 if (!ClassGuid)
3492 if ((l = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3493 lpKeyName,
3495 samDesired,
3496 &hClassesKey)))
3498 SetLastError(l);
3499 hClassesKey = INVALID_HANDLE_VALUE;
3501 key = hClassesKey;
3503 else
3505 WCHAR bracedGuidString[39];
3507 SETUPDI_GuidToString(ClassGuid, bracedGuidString);
3509 if (!(l = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3510 lpKeyName,
3512 samDesired,
3513 &hClassesKey)))
3515 if ((l = RegOpenKeyExW(hClassesKey,
3516 bracedGuidString,
3518 samDesired,
3519 &key)))
3521 SetLastError(l);
3522 key = INVALID_HANDLE_VALUE;
3524 RegCloseKey(hClassesKey);
3526 else
3528 SetLastError(l);
3529 key = INVALID_HANDLE_VALUE;
3532 return key;
3535 /***********************************************************************
3536 * SetupDiOpenDeviceInfoA (SETUPAPI.@)
3538 BOOL WINAPI SetupDiOpenDeviceInfoA(HDEVINFO devinfo, PCSTR instance_id, HWND hwnd_parent, DWORD flags,
3539 PSP_DEVINFO_DATA device_data)
3541 WCHAR instance_idW[MAX_DEVICE_ID_LEN];
3543 TRACE("%p %s %p 0x%08x %p\n", devinfo, debugstr_a(instance_id), hwnd_parent, flags, device_data);
3545 if (!instance_id || strlen(instance_id) >= MAX_DEVICE_ID_LEN)
3547 SetLastError(ERROR_INVALID_PARAMETER);
3548 return FALSE;
3551 MultiByteToWideChar(CP_ACP, 0, instance_id, -1, instance_idW, ARRAY_SIZE(instance_idW));
3552 return SetupDiOpenDeviceInfoW(devinfo, instance_idW, hwnd_parent, flags, device_data);
3555 /***********************************************************************
3556 * SetupDiOpenDeviceInfoW (SETUPAPI.@)
3558 BOOL WINAPI SetupDiOpenDeviceInfoW(HDEVINFO devinfo, PCWSTR instance_id, HWND hwnd_parent, DWORD flags,
3559 PSP_DEVINFO_DATA device_data)
3561 struct DeviceInfoSet *set;
3562 struct device *device;
3563 WCHAR classW[40];
3564 GUID guid;
3565 HKEY enumKey = NULL;
3566 HKEY instanceKey = NULL;
3567 DWORD phantom;
3568 DWORD size;
3569 DWORD error = ERROR_NO_SUCH_DEVINST;
3571 TRACE("%p %s %p 0x%08x %p\n", devinfo, debugstr_w(instance_id), hwnd_parent, flags, device_data);
3573 if (!(set = get_device_set(devinfo)))
3574 return FALSE;
3576 if (!instance_id)
3578 SetLastError(ERROR_INVALID_PARAMETER);
3579 return FALSE;
3582 if (hwnd_parent)
3583 FIXME("hwnd_parent unsupported\n");
3585 if (flags)
3586 FIXME("flags unsupported: 0x%08x\n", flags);
3588 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &enumKey, NULL);
3589 /* Instance needs to be already existent in registry, if not, report ERROR_NO_SUCH_DEVINST */
3590 if (RegOpenKeyExW(enumKey, instance_id, 0, KEY_READ, &instanceKey))
3591 goto done;
3593 /* If it's an unregistered instance, aka phantom instance, report ERROR_NO_SUCH_DEVINST */
3594 size = sizeof(phantom);
3595 if (!RegQueryValueExW(instanceKey, Phantom, NULL, NULL, (BYTE *)&phantom, &size))
3596 goto done;
3598 /* Check class GUID */
3599 size = sizeof(classW);
3600 if (RegQueryValueExW(instanceKey, ClassGUID, NULL, NULL, (BYTE *)classW, &size))
3601 goto done;
3603 classW[37] = 0;
3604 UuidFromStringW(&classW[1], &guid);
3606 if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) && !IsEqualGUID(&guid, &set->ClassGuid))
3608 error = ERROR_CLASS_MISMATCH;
3609 goto done;
3612 if (!(device = create_device(set, &guid, instance_id, FALSE)))
3613 goto done;
3615 if (!device_data || device_data->cbSize == sizeof(SP_DEVINFO_DATA))
3617 if (device_data)
3618 copy_device_data(device_data, device);
3619 error = NO_ERROR;
3621 else
3622 error = ERROR_INVALID_USER_BUFFER;
3624 done:
3625 RegCloseKey(instanceKey);
3626 RegCloseKey(enumKey);
3627 SetLastError(error);
3628 return !error;
3631 /***********************************************************************
3632 * SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
3634 BOOL WINAPI SetupDiOpenDeviceInterfaceW(
3635 HDEVINFO DeviceInfoSet,
3636 PCWSTR DevicePath,
3637 DWORD OpenFlags,
3638 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3640 FIXME("%p %s %08x %p\n",
3641 DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
3642 return FALSE;
3645 /***********************************************************************
3646 * SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
3648 BOOL WINAPI SetupDiOpenDeviceInterfaceA(
3649 HDEVINFO DeviceInfoSet,
3650 PCSTR DevicePath,
3651 DWORD OpenFlags,
3652 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3654 FIXME("%p %s %08x %p\n", DeviceInfoSet,
3655 debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
3656 return FALSE;
3659 /***********************************************************************
3660 * SetupDiOpenDeviceInterfaceRegKey (SETUPAPI.@)
3662 HKEY WINAPI SetupDiOpenDeviceInterfaceRegKey(HDEVINFO devinfo, PSP_DEVICE_INTERFACE_DATA iface_data,
3663 DWORD reserved, REGSAM access)
3665 struct device_iface *iface;
3666 LSTATUS lr;
3667 HKEY key;
3669 TRACE("devinfo %p, iface_data %p, reserved %d, access %#x.\n", devinfo, iface_data, reserved, access);
3671 if (!(iface = get_device_iface(devinfo, iface_data)))
3672 return INVALID_HANDLE_VALUE;
3674 lr = RegOpenKeyExW(iface->refstr_key, DeviceParameters, 0, access, &key);
3675 if (lr)
3677 SetLastError(lr);
3678 return INVALID_HANDLE_VALUE;
3681 return key;
3684 /***********************************************************************
3685 * SetupDiSetClassInstallParamsA (SETUPAPI.@)
3687 BOOL WINAPI SetupDiSetClassInstallParamsA(
3688 HDEVINFO DeviceInfoSet,
3689 PSP_DEVINFO_DATA DeviceInfoData,
3690 PSP_CLASSINSTALL_HEADER ClassInstallParams,
3691 DWORD ClassInstallParamsSize)
3693 FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
3694 ClassInstallParams->InstallFunction, ClassInstallParamsSize);
3695 return FALSE;
3698 /***********************************************************************
3699 * SetupDiSetClassInstallParamsW (SETUPAPI.@)
3701 BOOL WINAPI SetupDiSetClassInstallParamsW(
3702 HDEVINFO DeviceInfoSet,
3703 PSP_DEVINFO_DATA DeviceInfoData,
3704 PSP_CLASSINSTALL_HEADER ClassInstallParams,
3705 DWORD ClassInstallParamsSize)
3707 FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
3708 ClassInstallParams->InstallFunction, ClassInstallParamsSize);
3709 return FALSE;
3712 static BOOL call_coinstallers(WCHAR *list, DI_FUNCTION function, HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
3714 DWORD (CALLBACK *coinst_proc)(DI_FUNCTION, HDEVINFO, SP_DEVINFO_DATA *, COINSTALLER_CONTEXT_DATA *);
3715 COINSTALLER_CONTEXT_DATA coinst_ctx;
3716 WCHAR *p, *procnameW;
3717 HMODULE module;
3718 char *procname;
3719 DWORD ret;
3721 for (p = list; *p; p += lstrlenW(p) + 1)
3723 TRACE("Found co-installer %s.\n", debugstr_w(p));
3724 if ((procnameW = wcschr(p, ',')))
3725 *procnameW = 0;
3727 if ((module = LoadLibraryExW(p, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32)))
3729 if (procnameW)
3731 procname = strdupWtoA(procnameW + 1);
3732 coinst_proc = (void *)GetProcAddress(module, procname);
3733 heap_free(procname);
3735 else
3736 coinst_proc = (void *)GetProcAddress(module, "CoDeviceInstall");
3737 if (coinst_proc)
3739 memset(&coinst_ctx, 0, sizeof(coinst_ctx));
3740 TRACE("Calling co-installer %p.\n", coinst_proc);
3741 ret = coinst_proc(function, devinfo, device_data, &coinst_ctx);
3742 TRACE("Co-installer %p returned %#x.\n", coinst_proc, ret);
3743 if (ret == ERROR_DI_POSTPROCESSING_REQUIRED)
3744 FIXME("Co-installer postprocessing not implemented.\n");
3745 else if (ret)
3747 ERR("Co-installer returned error %#x.\n", ret);
3748 FreeLibrary(module);
3749 SetLastError(ret);
3750 return FALSE;
3753 FreeLibrary(module);
3757 return TRUE;
3760 /***********************************************************************
3761 * SetupDiCallClassInstaller (SETUPAPI.@)
3763 BOOL WINAPI SetupDiCallClassInstaller(DI_FUNCTION function, HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
3765 static const WCHAR class_coinst_pathW[] = {'S','y','s','t','e','m',
3766 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
3767 '\\','C','o','n','t','r','o','l',
3768 '\\','C','o','D','e','v','i','c','e','I','n','s','t','a','l','l','e','r','s',0};
3769 static const WCHAR coinstallers32W[] = {'C','o','I','n','s','t','a','l','l','e','r','s','3','2',0};
3770 static const WCHAR installer32W[] = {'I','n','s','t','a','l','l','e','r','3','2',0};
3771 DWORD (CALLBACK *classinst_proc)(DI_FUNCTION, HDEVINFO, SP_DEVINFO_DATA *);
3772 DWORD ret = ERROR_DI_DO_DEFAULT;
3773 HKEY class_key, coinst_key;
3774 WCHAR *path, *procnameW;
3775 struct device *device;
3776 WCHAR guidstr[39];
3777 BOOL coret = TRUE;
3778 HMODULE module;
3779 char *procname;
3780 DWORD size;
3782 TRACE("function %#x, devinfo %p, device_data %p.\n", function, devinfo, device_data);
3784 if (!(device = get_device(devinfo, device_data)))
3785 return FALSE;
3787 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, class_coinst_pathW, 0, KEY_READ, &coinst_key))
3789 SETUPDI_GuidToString(&device->class, guidstr);
3790 if (!RegGetValueW(coinst_key, NULL, guidstr, RRF_RT_REG_MULTI_SZ, NULL, NULL, &size))
3792 path = heap_alloc(size);
3793 if (!RegGetValueW(coinst_key, NULL, guidstr, RRF_RT_REG_MULTI_SZ, NULL, path, &size))
3794 coret = call_coinstallers(path, function, devinfo, device_data);
3795 heap_free(path);
3797 RegCloseKey(coinst_key);
3800 if (!coret)
3801 return FALSE;
3803 if (!open_driver_key(device, KEY_READ, &coinst_key))
3805 if (!RegGetValueW(coinst_key, NULL, coinstallers32W, RRF_RT_REG_MULTI_SZ, NULL, NULL, &size))
3807 path = heap_alloc(size);
3808 if (!RegGetValueW(coinst_key, NULL, coinstallers32W, RRF_RT_REG_MULTI_SZ, NULL, path, &size))
3809 coret = call_coinstallers(path, function, devinfo, device_data);
3810 heap_free(path);
3812 RegCloseKey(coinst_key);
3815 if ((class_key = SetupDiOpenClassRegKey(&device->class, KEY_READ)) != INVALID_HANDLE_VALUE)
3817 if (!RegGetValueW(class_key, NULL, installer32W, RRF_RT_REG_SZ, NULL, NULL, &size))
3819 path = heap_alloc(size);
3820 if (!RegGetValueW(class_key, NULL, installer32W, RRF_RT_REG_SZ, NULL, path, &size))
3822 TRACE("Found class installer %s.\n", debugstr_w(path));
3823 if ((procnameW = wcschr(path, ',')))
3824 *procnameW = 0;
3826 if ((module = LoadLibraryExW(path, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32)))
3828 if (procnameW)
3830 procname = strdupWtoA(procnameW + 1);
3831 classinst_proc = (void *)GetProcAddress(module, procname);
3832 heap_free(procname);
3834 else
3835 classinst_proc = (void *)GetProcAddress(module, "ClassInstall");
3836 if (classinst_proc)
3838 TRACE("Calling class installer %p.\n", classinst_proc);
3839 ret = classinst_proc(function, devinfo, device_data);
3840 TRACE("Class installer %p returned %#x.\n", classinst_proc, ret);
3842 FreeLibrary(module);
3845 heap_free(path);
3847 RegCloseKey(class_key);
3850 if (ret == ERROR_DI_DO_DEFAULT)
3852 switch (function)
3854 case DIF_REGISTERDEVICE:
3855 return SetupDiRegisterDeviceInfo(devinfo, device_data, 0, NULL, NULL, NULL);
3856 case DIF_REMOVE:
3857 return SetupDiRemoveDevice(devinfo, device_data);
3858 case DIF_SELECTBESTCOMPATDRV:
3859 return SetupDiSelectBestCompatDrv(devinfo, device_data);
3860 case DIF_REGISTER_COINSTALLERS:
3861 return SetupDiRegisterCoDeviceInstallers(devinfo, device_data);
3862 case DIF_INSTALLDEVICEFILES:
3863 return SetupDiInstallDriverFiles(devinfo, device_data);
3864 case DIF_INSTALLINTERFACES:
3865 return SetupDiInstallDeviceInterfaces(devinfo, device_data);
3866 case DIF_INSTALLDEVICE:
3867 return SetupDiInstallDevice(devinfo, device_data);
3868 case DIF_FINISHINSTALL_ACTION:
3869 case DIF_PROPERTYCHANGE:
3870 case DIF_SELECTDEVICE:
3871 case DIF_UNREMOVE:
3872 FIXME("Unhandled function %#x.\n", function);
3876 if (ret) SetLastError(ret);
3877 return !ret;
3880 /***********************************************************************
3881 * SetupDiGetDeviceInstallParamsW (SETUPAPI.@)
3883 BOOL WINAPI SetupDiGetDeviceInstallParamsW(HDEVINFO devinfo,
3884 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_W *params)
3886 struct device *device;
3888 TRACE("devinfo %p, device_data %p, params %p.\n", devinfo, device_data, params);
3890 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
3892 SetLastError(ERROR_INVALID_USER_BUFFER);
3893 return FALSE;
3896 if (!(device = get_device(devinfo, device_data)))
3897 return FALSE;
3899 *params = device->params;
3901 return TRUE;
3904 /***********************************************************************
3905 * SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
3907 BOOL WINAPI SetupDiGetDeviceInstallParamsA(HDEVINFO devinfo,
3908 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_A *params)
3910 SP_DEVINSTALL_PARAMS_W paramsW;
3911 BOOL ret;
3913 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
3915 SetLastError(ERROR_INVALID_USER_BUFFER);
3916 return FALSE;
3919 paramsW.cbSize = sizeof(paramsW);
3920 ret = SetupDiGetDeviceInstallParamsW(devinfo, device_data, &paramsW);
3921 params->Flags = paramsW.Flags;
3922 params->FlagsEx = paramsW.FlagsEx;
3923 params->hwndParent = paramsW.hwndParent;
3924 params->InstallMsgHandler = paramsW.InstallMsgHandler;
3925 params->InstallMsgHandlerContext = paramsW.InstallMsgHandlerContext;
3926 params->FileQueue = paramsW.FileQueue;
3927 params->ClassInstallReserved = paramsW.ClassInstallReserved;
3928 params->Reserved = paramsW.Reserved;
3929 WideCharToMultiByte(CP_ACP, 0, paramsW.DriverPath, -1, params->DriverPath, sizeof(params->DriverPath), NULL, NULL);
3931 return ret;
3934 /***********************************************************************
3935 * SetupDiSetDeviceInstallParamsA (SETUPAPI.@)
3937 BOOL WINAPI SetupDiSetDeviceInstallParamsA(HDEVINFO devinfo,
3938 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_A *params)
3940 SP_DEVINSTALL_PARAMS_W paramsW;
3942 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
3944 SetLastError(ERROR_INVALID_USER_BUFFER);
3945 return FALSE;
3948 paramsW.cbSize = sizeof(paramsW);
3949 paramsW.Flags = params->Flags;
3950 paramsW.FlagsEx = params->FlagsEx;
3951 paramsW.hwndParent = params->hwndParent;
3952 paramsW.InstallMsgHandler = params->InstallMsgHandler;
3953 paramsW.InstallMsgHandlerContext = params->InstallMsgHandlerContext;
3954 paramsW.FileQueue = params->FileQueue;
3955 paramsW.ClassInstallReserved = params->ClassInstallReserved;
3956 paramsW.Reserved = params->Reserved;
3957 MultiByteToWideChar(CP_ACP, 0, params->DriverPath, -1, paramsW.DriverPath, ARRAY_SIZE(paramsW.DriverPath));
3959 return SetupDiSetDeviceInstallParamsW(devinfo, device_data, &paramsW);
3962 /***********************************************************************
3963 * SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
3965 BOOL WINAPI SetupDiSetDeviceInstallParamsW(HDEVINFO devinfo,
3966 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_W *params)
3968 struct device *device;
3970 TRACE("devinfo %p, device_data %p, params %p.\n", devinfo, device_data, params);
3972 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
3974 SetLastError(ERROR_INVALID_USER_BUFFER);
3975 return FALSE;
3978 if (!(device = get_device(devinfo, device_data)))
3979 return FALSE;
3981 device->params = *params;
3983 return TRUE;
3986 BOOL WINAPI SetupDiSetDevicePropertyW(HDEVINFO devinfo, PSP_DEVINFO_DATA device_data, const DEVPROPKEY *key,
3987 DEVPROPTYPE type, const BYTE *buffer, DWORD size, DWORD flags)
3989 static const WCHAR propertiesW[] = {'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's', 0};
3990 static const WCHAR formatW[] = {'\\', '%', '0', '4', 'X', 0};
3991 struct device *device;
3992 HKEY properties_hkey, property_hkey;
3993 WCHAR property_hkey_path[44];
3994 LSTATUS ls;
3996 TRACE("%p %p %p %#x %p %d %#x\n", devinfo, device_data, key, type, buffer, size, flags);
3998 if (!(device = get_device(devinfo, device_data)))
3999 return FALSE;
4001 if (!key || !is_valid_property_type(type)
4002 || (buffer && !size && !(type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL))
4003 || (buffer && size && (type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL)))
4005 SetLastError(ERROR_INVALID_DATA);
4006 return FALSE;
4009 if (size && !buffer)
4011 SetLastError(ERROR_INVALID_USER_BUFFER);
4012 return FALSE;
4015 if (flags)
4017 SetLastError(ERROR_INVALID_FLAGS);
4018 return FALSE;
4021 ls = RegCreateKeyExW(device->key, propertiesW, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &properties_hkey, NULL);
4022 if (ls)
4024 SetLastError(ls);
4025 return FALSE;
4028 SETUPDI_GuidToString(&key->fmtid, property_hkey_path);
4029 swprintf(property_hkey_path + 38, ARRAY_SIZE(property_hkey_path) - 38, formatW, key->pid);
4031 if (type == DEVPROP_TYPE_EMPTY)
4033 ls = RegDeleteKeyW(properties_hkey, property_hkey_path);
4034 RegCloseKey(properties_hkey);
4035 SetLastError(ls == ERROR_FILE_NOT_FOUND ? ERROR_NOT_FOUND : ls);
4036 return !ls;
4038 else if (type == DEVPROP_TYPE_NULL)
4040 if (!(ls = RegOpenKeyW(properties_hkey, property_hkey_path, &property_hkey)))
4042 ls = RegDeleteValueW(property_hkey, NULL);
4043 RegCloseKey(property_hkey);
4046 RegCloseKey(properties_hkey);
4047 SetLastError(ls == ERROR_FILE_NOT_FOUND ? ERROR_NOT_FOUND : ls);
4048 return !ls;
4050 else
4052 if (!(ls = RegCreateKeyExW(properties_hkey, property_hkey_path, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL,
4053 &property_hkey, NULL)))
4055 ls = RegSetValueExW(property_hkey, NULL, 0, 0xffff0000 | (0xffff & type), buffer, size);
4056 RegCloseKey(property_hkey);
4059 RegCloseKey(properties_hkey);
4060 SetLastError(ls);
4061 return !ls;
4065 /***********************************************************************
4066 * SetupDiOpenDevRegKey (SETUPAPI.@)
4068 HKEY WINAPI SetupDiOpenDevRegKey(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4069 DWORD Scope, DWORD HwProfile, DWORD KeyType, REGSAM samDesired)
4071 struct device *device;
4072 HKEY key = INVALID_HANDLE_VALUE;
4073 LONG l;
4075 TRACE("devinfo %p, device_data %p, scope %d, profile %d, type %d, access %#x.\n",
4076 devinfo, device_data, Scope, HwProfile, KeyType, samDesired);
4078 if (!(device = get_device(devinfo, device_data)))
4079 return INVALID_HANDLE_VALUE;
4081 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
4083 SetLastError(ERROR_INVALID_FLAGS);
4084 return INVALID_HANDLE_VALUE;
4086 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
4088 SetLastError(ERROR_INVALID_FLAGS);
4089 return INVALID_HANDLE_VALUE;
4092 if (device->phantom)
4094 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
4095 return INVALID_HANDLE_VALUE;
4097 if (Scope != DICS_FLAG_GLOBAL)
4098 FIXME("unimplemented for scope %d\n", Scope);
4099 switch (KeyType)
4101 case DIREG_DEV:
4102 l = RegOpenKeyExW(device->key, DeviceParameters, 0, samDesired, &key);
4103 break;
4104 case DIREG_DRV:
4105 l = open_driver_key(device, samDesired, &key);
4106 break;
4107 default:
4108 FIXME("Unhandled type %#x.\n", KeyType);
4109 l = ERROR_CALL_NOT_IMPLEMENTED;
4111 SetLastError(l == ERROR_FILE_NOT_FOUND ? ERROR_KEY_DOES_NOT_EXIST : l);
4112 return l ? INVALID_HANDLE_VALUE : key;
4115 /***********************************************************************
4116 * SetupDiDeleteDevRegKey (SETUPAPI.@)
4118 BOOL WINAPI SetupDiDeleteDevRegKey(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4119 DWORD Scope, DWORD HwProfile, DWORD KeyType)
4121 struct device *device;
4122 LONG l;
4124 TRACE("devinfo %p, device_data %p, scope %d, profile %d, type %d.\n",
4125 devinfo, device_data, Scope, HwProfile, KeyType);
4127 if (!(device = get_device(devinfo, device_data)))
4128 return FALSE;
4130 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
4132 SetLastError(ERROR_INVALID_FLAGS);
4133 return FALSE;
4135 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV && KeyType != DIREG_BOTH)
4137 SetLastError(ERROR_INVALID_FLAGS);
4138 return FALSE;
4141 if (device->phantom)
4143 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
4144 return FALSE;
4146 if (Scope != DICS_FLAG_GLOBAL)
4147 FIXME("unimplemented for scope %d\n", Scope);
4148 switch (KeyType)
4150 case DIREG_DRV:
4151 l = delete_driver_key(device);
4152 break;
4153 case DIREG_BOTH:
4154 if ((l = delete_driver_key(device)))
4155 break;
4156 /* fall through */
4157 case DIREG_DEV:
4158 l = RegDeleteKeyW(device->key, DeviceParameters);
4159 break;
4160 default:
4161 FIXME("Unhandled type %#x.\n", KeyType);
4162 l = ERROR_CALL_NOT_IMPLEMENTED;
4164 SetLastError(l);
4165 return !l;
4168 /***********************************************************************
4169 * CM_Get_Device_IDA (SETUPAPI.@)
4171 CONFIGRET WINAPI CM_Get_Device_IDA(DEVINST devnode, char *buffer, ULONG len, ULONG flags)
4173 struct device *device = get_devnode_device(devnode);
4175 TRACE("%u, %p, %u, %#x\n", devnode, buffer, len, flags);
4177 if (!device)
4178 return CR_NO_SUCH_DEVINST;
4180 WideCharToMultiByte(CP_ACP, 0, device->instanceId, -1, buffer, len, 0, 0);
4181 TRACE("Returning %s\n", debugstr_a(buffer));
4182 return CR_SUCCESS;
4185 /***********************************************************************
4186 * CM_Get_Device_IDW (SETUPAPI.@)
4188 CONFIGRET WINAPI CM_Get_Device_IDW(DEVINST devnode, WCHAR *buffer, ULONG len, ULONG flags)
4190 struct device *device = get_devnode_device(devnode);
4192 TRACE("%u, %p, %u, %#x\n", devnode, buffer, len, flags);
4194 if (!device)
4195 return CR_NO_SUCH_DEVINST;
4197 lstrcpynW(buffer, device->instanceId, len);
4198 TRACE("Returning %s\n", debugstr_w(buffer));
4199 return CR_SUCCESS;
4202 /***********************************************************************
4203 * CM_Get_Device_ID_Size (SETUPAPI.@)
4205 CONFIGRET WINAPI CM_Get_Device_ID_Size(ULONG *len, DEVINST devnode, ULONG flags)
4207 struct device *device = get_devnode_device(devnode);
4209 TRACE("%p, %u, %#x\n", len, devnode, flags);
4211 if (!device)
4212 return CR_NO_SUCH_DEVINST;
4214 *len = lstrlenW(device->instanceId);
4215 return CR_SUCCESS;
4218 /***********************************************************************
4219 * SetupDiGetINFClassA (SETUPAPI.@)
4221 BOOL WINAPI SetupDiGetINFClassA(PCSTR inf, LPGUID class_guid, PSTR class_name,
4222 DWORD size, PDWORD required_size)
4224 BOOL retval;
4225 DWORD required_sizeA, required_sizeW;
4226 PWSTR class_nameW = NULL;
4227 UNICODE_STRING infW;
4229 if (inf)
4231 if (!RtlCreateUnicodeStringFromAsciiz(&infW, inf))
4233 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4234 return FALSE;
4237 else
4238 infW.Buffer = NULL;
4240 if (class_name && size)
4242 if (!(class_nameW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR))))
4244 RtlFreeUnicodeString(&infW);
4245 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4246 return FALSE;
4250 retval = SetupDiGetINFClassW(infW.Buffer, class_guid, class_nameW, size, &required_sizeW);
4252 if (retval)
4254 required_sizeA = WideCharToMultiByte( CP_ACP, 0, class_nameW, required_sizeW,
4255 class_name, size, NULL, NULL);
4257 if(required_size) *required_size = required_sizeA;
4259 else
4260 if(required_size) *required_size = required_sizeW;
4262 HeapFree(GetProcessHeap(), 0, class_nameW);
4263 RtlFreeUnicodeString(&infW);
4264 return retval;
4267 /***********************************************************************
4268 * SetupDiGetINFClassW (SETUPAPI.@)
4270 BOOL WINAPI SetupDiGetINFClassW(PCWSTR inf, LPGUID class_guid, PWSTR class_name,
4271 DWORD size, PDWORD required_size)
4273 BOOL have_guid, have_name;
4274 DWORD dret;
4275 WCHAR buffer[MAX_PATH];
4277 if (!inf)
4279 SetLastError(ERROR_INVALID_PARAMETER);
4280 return FALSE;
4283 if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(inf))
4285 FIXME("%s not found. Searching via DevicePath not implemented\n", debugstr_w(inf));
4286 SetLastError(ERROR_FILE_NOT_FOUND);
4287 return FALSE;
4290 if (!class_guid || !class_name || !size)
4292 SetLastError(ERROR_INVALID_PARAMETER);
4293 return FALSE;
4296 if (!GetPrivateProfileStringW(Version, Signature, NULL, buffer, MAX_PATH, inf))
4297 return FALSE;
4299 if (lstrcmpiW(buffer, Chicago) && lstrcmpiW(buffer, WindowsNT))
4300 return FALSE;
4302 buffer[0] = '\0';
4303 have_guid = 0 < GetPrivateProfileStringW(Version, ClassGUID, NULL, buffer, MAX_PATH, inf);
4304 if (have_guid)
4306 buffer[lstrlenW(buffer)-1] = 0;
4307 if (RPC_S_OK != UuidFromStringW(buffer + 1, class_guid))
4309 FIXME("failed to convert \"%s\" into a guid\n", debugstr_w(buffer));
4310 SetLastError(ERROR_INVALID_PARAMETER);
4311 return FALSE;
4315 buffer[0] = '\0';
4316 dret = GetPrivateProfileStringW(Version, Class, NULL, buffer, MAX_PATH, inf);
4317 have_name = 0 < dret;
4319 if (dret >= MAX_PATH -1) FIXME("buffer might be too small\n");
4320 if (have_guid && !have_name)
4322 class_name[0] = '\0';
4323 FIXME("class name lookup via guid not implemented\n");
4326 if (have_name)
4328 if (dret < size) lstrcpyW(class_name, buffer);
4329 else
4331 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4332 have_name = FALSE;
4336 if (required_size) *required_size = dret + ((dret) ? 1 : 0);
4338 return (have_guid || have_name);
4341 static LSTATUS get_device_property(struct device *device, const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type,
4342 BYTE *prop_buff, DWORD prop_buff_size, DWORD *required_size, DWORD flags)
4344 WCHAR key_path[55] = L"Properties\\";
4345 HKEY hkey;
4346 DWORD value_type;
4347 DWORD value_size = 0;
4348 LSTATUS ls;
4350 if (!prop_key)
4351 return ERROR_INVALID_DATA;
4353 if (!prop_type || (!prop_buff && prop_buff_size))
4354 return ERROR_INVALID_USER_BUFFER;
4356 if (flags)
4357 return ERROR_INVALID_FLAGS;
4359 SETUPDI_GuidToString(&prop_key->fmtid, key_path + 11);
4360 swprintf(key_path + 49, ARRAY_SIZE(key_path) - 49, L"\\%04X", prop_key->pid);
4362 ls = RegOpenKeyExW(device->key, key_path, 0, KEY_QUERY_VALUE, &hkey);
4363 if (!ls)
4365 value_size = prop_buff_size;
4366 ls = RegQueryValueExW(hkey, NULL, NULL, &value_type, prop_buff, &value_size);
4367 RegCloseKey(hkey);
4370 switch (ls)
4372 case NO_ERROR:
4373 case ERROR_MORE_DATA:
4374 *prop_type = 0xffff & value_type;
4375 ls = (ls == ERROR_MORE_DATA || !prop_buff) ? ERROR_INSUFFICIENT_BUFFER : NO_ERROR;
4376 break;
4377 case ERROR_FILE_NOT_FOUND:
4378 *prop_type = DEVPROP_TYPE_EMPTY;
4379 value_size = 0;
4380 ls = ERROR_NOT_FOUND;
4381 break;
4382 default:
4383 *prop_type = DEVPROP_TYPE_EMPTY;
4384 value_size = 0;
4385 FIXME("Unhandled error %#x\n", ls);
4386 break;
4389 if (required_size)
4390 *required_size = value_size;
4392 return ls;
4395 /***********************************************************************
4396 * SetupDiGetDevicePropertyW (SETUPAPI.@)
4398 BOOL WINAPI SetupDiGetDevicePropertyW(HDEVINFO devinfo, PSP_DEVINFO_DATA device_data,
4399 const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type, BYTE *prop_buff,
4400 DWORD prop_buff_size, DWORD *required_size, DWORD flags)
4402 struct device *device;
4403 LSTATUS ls;
4405 TRACE("%p, %p, %p, %p, %p, %d, %p, %#x\n", devinfo, device_data, prop_key, prop_type, prop_buff, prop_buff_size,
4406 required_size, flags);
4408 if (!(device = get_device(devinfo, device_data)))
4409 return FALSE;
4411 ls = get_device_property(device, prop_key, prop_type, prop_buff, prop_buff_size, required_size, flags);
4413 SetLastError(ls);
4414 return !ls;
4417 /***********************************************************************
4418 * CM_Get_DevNode_Property_ExW (SETUPAPI.@)
4420 CONFIGRET WINAPI CM_Get_DevNode_Property_ExW(DEVINST devnode, const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type,
4421 BYTE *prop_buff, ULONG *prop_buff_size, ULONG flags, HMACHINE machine)
4423 struct device *device = get_devnode_device(devnode);
4424 LSTATUS ls;
4426 TRACE("%u, %p, %p, %p, %p, %#x, %p\n", devnode, prop_key, prop_type, prop_buff, prop_buff_size,
4427 flags, machine);
4429 if (machine)
4430 return CR_MACHINE_UNAVAILABLE;
4432 if (!device)
4433 return CR_NO_SUCH_DEVINST;
4435 if (!prop_buff_size)
4436 return CR_INVALID_POINTER;
4438 ls = get_device_property(device, prop_key, prop_type, prop_buff, *prop_buff_size, prop_buff_size, flags);
4439 switch (ls)
4441 case NO_ERROR:
4442 return CR_SUCCESS;
4443 case ERROR_INVALID_DATA:
4444 return CR_INVALID_DATA;
4445 case ERROR_INVALID_USER_BUFFER:
4446 return CR_INVALID_POINTER;
4447 case ERROR_INVALID_FLAGS:
4448 return CR_INVALID_FLAG;
4449 case ERROR_INSUFFICIENT_BUFFER:
4450 return CR_BUFFER_SMALL;
4451 case ERROR_NOT_FOUND:
4452 return CR_NO_SUCH_VALUE;
4454 return CR_FAILURE;
4457 /***********************************************************************
4458 * CM_Get_DevNode_PropertyW (SETUPAPI.@)
4460 CONFIGRET WINAPI CM_Get_DevNode_PropertyW(DEVINST dev, const DEVPROPKEY *key, DEVPROPTYPE *type,
4461 PVOID buf, PULONG len, ULONG flags)
4463 return CM_Get_DevNode_Property_ExW(dev, key, type, buf, len, flags, NULL);
4466 /***********************************************************************
4467 * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
4469 BOOL WINAPI SetupDiInstallDeviceInterfaces(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4471 WCHAR section_ext[LINE_LEN], iface_section[LINE_LEN], refstr[LINE_LEN], guidstr[39];
4472 UINT install_flags = SPINST_ALL;
4473 struct device_iface *iface;
4474 struct device *device;
4475 struct driver *driver;
4476 void *callback_ctx;
4477 GUID iface_guid;
4478 INFCONTEXT ctx;
4479 HKEY iface_key;
4480 HINF hinf;
4481 LONG l;
4483 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
4485 if (!(device = get_device(devinfo, device_data)))
4486 return FALSE;
4488 if (!(driver = device->selected_driver))
4490 ERR("No driver selected for device %p.\n", devinfo);
4491 SetLastError(ERROR_NO_DRIVER_SELECTED);
4492 return FALSE;
4495 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4496 return FALSE;
4498 SetupDiGetActualSectionToInstallW(hinf, driver->section, section_ext, ARRAY_SIZE(section_ext), NULL, NULL);
4500 if (device->params.Flags & DI_NOFILECOPY)
4501 install_flags &= ~SPINST_FILES;
4503 callback_ctx = SetupInitDefaultQueueCallback(NULL);
4505 lstrcatW(section_ext, dotInterfaces);
4506 if (SetupFindFirstLineW(hinf, section_ext, AddInterface, &ctx))
4508 do {
4509 SetupGetStringFieldW(&ctx, 1, guidstr, ARRAY_SIZE(guidstr), NULL);
4510 SetupGetStringFieldW(&ctx, 2, refstr, ARRAY_SIZE(refstr), NULL);
4511 guidstr[37] = 0;
4512 UuidFromStringW(&guidstr[1], &iface_guid);
4514 if (!(iface = SETUPDI_CreateDeviceInterface(device, &iface_guid, refstr)))
4516 ERR("Failed to create device interface, error %#x.\n", GetLastError());
4517 continue;
4520 if ((l = create_iface_key(iface, KEY_ALL_ACCESS, &iface_key)))
4522 ERR("Failed to create interface key, error %u.\n", l);
4523 continue;
4526 SetupGetStringFieldW(&ctx, 3, iface_section, ARRAY_SIZE(iface_section), NULL);
4527 SetupInstallFromInfSectionW(NULL, hinf, iface_section, install_flags, iface_key,
4528 NULL, SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
4530 RegCloseKey(iface_key);
4531 } while (SetupFindNextMatchLineW(&ctx, AddInterface, &ctx));
4534 SetupTermDefaultQueueCallback(callback_ctx);
4536 SetupCloseInfFile(hinf);
4537 return TRUE;
4540 /***********************************************************************
4541 * SetupDiRegisterCoDeviceInstallers (SETUPAPI.@)
4543 BOOL WINAPI SetupDiRegisterCoDeviceInstallers(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4545 static const WCHAR coinstallersW[] = {'.','C','o','I','n','s','t','a','l','l','e','r','s',0};
4546 WCHAR coinst_key_ext[LINE_LEN];
4547 struct device *device;
4548 struct driver *driver;
4549 void *callback_ctx;
4550 HKEY driver_key;
4551 HINF hinf;
4552 LONG l;
4554 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
4556 if (!(device = get_device(devinfo, device_data)))
4557 return FALSE;
4559 if (!(driver = device->selected_driver))
4561 ERR("No driver selected for device %p.\n", devinfo);
4562 SetLastError(ERROR_NO_DRIVER_SELECTED);
4563 return FALSE;
4566 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4567 return FALSE;
4569 SetupDiGetActualSectionToInstallW(hinf, driver->section, coinst_key_ext, ARRAY_SIZE(coinst_key_ext), NULL, NULL);
4570 lstrcatW(coinst_key_ext, coinstallersW);
4572 if ((l = create_driver_key(device, &driver_key)))
4574 SetLastError(l);
4575 SetupCloseInfFile(hinf);
4576 return FALSE;
4579 callback_ctx = SetupInitDefaultQueueCallback(NULL);
4580 SetupInstallFromInfSectionW(NULL, hinf, coinst_key_ext, SPINST_ALL, driver_key, NULL,
4581 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
4582 SetupTermDefaultQueueCallback(callback_ctx);
4584 RegCloseKey(driver_key);
4585 SetupCloseInfFile(hinf);
4586 return TRUE;
4589 /* Check whether the given hardware or compatible ID matches any of the device's
4590 * own hardware or compatible IDs. */
4591 static BOOL device_matches_id(const struct device *device, const WCHAR *id_type, const WCHAR *id)
4593 WCHAR *device_ids;
4594 const WCHAR *p;
4595 DWORD size;
4597 if (!RegGetValueW(device->key, NULL, id_type, RRF_RT_REG_MULTI_SZ, NULL, NULL, &size))
4599 device_ids = heap_alloc(size);
4600 if (!RegGetValueW(device->key, NULL, id_type, RRF_RT_REG_MULTI_SZ, NULL, device_ids, &size))
4602 for (p = device_ids; *p; p += lstrlenW(p) + 1)
4604 if (!wcsicmp(p, id))
4606 heap_free(device_ids);
4607 return TRUE;
4611 heap_free(device_ids);
4614 return FALSE;
4617 static BOOL version_is_compatible(const WCHAR *version)
4619 const WCHAR *machine_ext = NtPlatformExtension + 1, *p;
4620 size_t len = lstrlenW(version);
4621 BOOL wow64;
4623 /* We are only concerned with architecture. */
4624 if ((p = wcschr(version, '.')))
4625 len = p - version;
4627 if (!wcsnicmp(version, NtExtension + 1, len))
4628 return TRUE;
4630 if (IsWow64Process(GetCurrentProcess(), &wow64) && wow64)
4632 #ifdef __i386__
4633 static const WCHAR wow_ext[] = {'N','T','a','m','d','6','4',0};
4634 machine_ext = wow_ext;
4635 #elif defined(__arm__)
4636 static const WCHAR wow_ext[] = {'N','T','a','r','m','6','4',0};
4637 machine_ext = wow_ext;
4638 #endif
4641 return !wcsnicmp(version, machine_ext, len);
4644 static void enum_compat_drivers_from_file(struct device *device, const WCHAR *path)
4646 static const WCHAR manufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4647 WCHAR mfg_name[LINE_LEN], mfg_key[LINE_LEN], mfg_key_ext[LINE_LEN], id[MAX_DEVICE_ID_LEN], version[MAX_DEVICE_ID_LEN];
4648 INFCONTEXT ctx;
4649 DWORD i, j, k;
4650 HINF hinf;
4652 TRACE("Enumerating drivers from %s.\n", debugstr_w(path));
4654 if ((hinf = SetupOpenInfFileW(path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4655 return;
4657 for (i = 0; SetupGetLineByIndexW(hinf, manufacturerW, i, &ctx); ++i)
4659 SetupGetStringFieldW(&ctx, 0, mfg_name, ARRAY_SIZE(mfg_name), NULL);
4660 if (!SetupGetStringFieldW(&ctx, 1, mfg_key, ARRAY_SIZE(mfg_key), NULL))
4661 lstrcpyW(mfg_key, mfg_name);
4663 if (SetupGetFieldCount(&ctx) >= 2)
4665 BOOL compatible = FALSE;
4666 for (j = 2; SetupGetStringFieldW(&ctx, j, version, ARRAY_SIZE(version), NULL); ++j)
4668 if (version_is_compatible(version))
4670 compatible = TRUE;
4671 break;
4674 if (!compatible)
4675 continue;
4678 if (!SetupDiGetActualSectionToInstallW(hinf, mfg_key, mfg_key_ext, ARRAY_SIZE(mfg_key_ext), NULL, NULL))
4680 WARN("Failed to find section for %s, skipping.\n", debugstr_w(mfg_key));
4681 continue;
4684 for (j = 0; SetupGetLineByIndexW(hinf, mfg_key_ext, j, &ctx); ++j)
4686 for (k = 2; SetupGetStringFieldW(&ctx, k, id, ARRAY_SIZE(id), NULL); ++k)
4688 if (device_matches_id(device, HardwareId, id) || device_matches_id(device, CompatibleIDs, id))
4690 unsigned int count = ++device->driver_count;
4692 device->drivers = heap_realloc(device->drivers, count * sizeof(*device->drivers));
4693 lstrcpyW(device->drivers[count - 1].inf_path, path);
4694 lstrcpyW(device->drivers[count - 1].manufacturer, mfg_name);
4695 lstrcpyW(device->drivers[count - 1].mfg_key, mfg_key_ext);
4696 SetupGetStringFieldW(&ctx, 0, device->drivers[count - 1].description,
4697 ARRAY_SIZE(device->drivers[count - 1].description), NULL);
4698 SetupGetStringFieldW(&ctx, 1, device->drivers[count - 1].section,
4699 ARRAY_SIZE(device->drivers[count - 1].section), NULL);
4701 TRACE("Found compatible driver: manufacturer %s, desc %s.\n",
4702 debugstr_w(mfg_name), debugstr_w(device->drivers[count - 1].description));
4708 SetupCloseInfFile(hinf);
4711 /***********************************************************************
4712 * SetupDiBuildDriverInfoList (SETUPAPI.@)
4714 BOOL WINAPI SetupDiBuildDriverInfoList(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD type)
4716 struct device *device;
4718 TRACE("devinfo %p, device_data %p, type %#x.\n", devinfo, device_data, type);
4720 if (type != SPDIT_COMPATDRIVER)
4722 FIXME("Unhandled type %#x.\n", type);
4723 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4724 return FALSE;
4727 if (!(device = get_device(devinfo, device_data)))
4728 return FALSE;
4730 if (device->params.Flags & DI_ENUMSINGLEINF)
4732 enum_compat_drivers_from_file(device, device->params.DriverPath);
4734 else
4736 static const WCHAR default_path[] = {'C',':','/','w','i','n','d','o','w','s','/','i','n','f',0};
4737 static const WCHAR wildcardW[] = {'*',0};
4738 WCHAR dir[MAX_PATH], file[MAX_PATH];
4739 WIN32_FIND_DATAW find_data;
4740 HANDLE find_handle;
4742 if (device->params.DriverPath[0])
4743 lstrcpyW(dir, device->params.DriverPath);
4744 else
4745 lstrcpyW(dir, default_path);
4746 lstrcatW(dir, backslashW);
4747 lstrcatW(dir, wildcardW);
4749 TRACE("Searching for drivers in %s.\n", debugstr_w(dir));
4751 if ((find_handle = FindFirstFileW(dir, &find_data)) != INVALID_HANDLE_VALUE)
4755 lstrcpyW(file, dir);
4756 lstrcpyW(file + lstrlenW(file) - 1, find_data.cFileName);
4757 enum_compat_drivers_from_file(device, file);
4758 } while (FindNextFileW(find_handle, &find_data));
4760 FindClose(find_handle);
4764 if (device->driver_count)
4766 WCHAR classname[MAX_CLASS_NAME_LEN], guidstr[39];
4767 GUID class;
4769 if (SetupDiGetINFClassW(device->drivers[0].inf_path, &class, classname, ARRAY_SIZE(classname), NULL))
4771 device_data->ClassGuid = device->class = class;
4772 SETUPDI_GuidToString(&class, guidstr);
4773 RegSetValueExW(device->key, L"ClassGUID", 0, REG_SZ, (BYTE *)guidstr, sizeof(guidstr));
4774 RegSetValueExW(device->key, L"Class", 0, REG_SZ, (BYTE *)classname, wcslen(classname) * sizeof(WCHAR));
4778 return TRUE;
4781 static BOOL copy_driver_data(SP_DRVINFO_DATA_W *data, const struct driver *driver)
4783 INFCONTEXT ctx;
4784 HINF hinf;
4786 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4787 return FALSE;
4789 data->ProviderName[0] = 0;
4790 if (SetupFindFirstLineW(hinf, L"Version", L"Provider", &ctx))
4791 SetupGetStringFieldW(&ctx, 1, data->ProviderName, ARRAY_SIZE(data->ProviderName), NULL);
4792 wcscpy(data->Description, driver->description);
4793 wcscpy(data->MfgName, driver->manufacturer);
4794 data->DriverType = SPDIT_COMPATDRIVER;
4795 data->Reserved = (ULONG_PTR)driver;
4797 SetupCloseInfFile(hinf);
4799 return TRUE;
4802 static void driver_data_wtoa(SP_DRVINFO_DATA_A *a, const SP_DRVINFO_DATA_W *w)
4804 a->DriverType = w->DriverType;
4805 a->Reserved = w->Reserved;
4806 WideCharToMultiByte(CP_ACP, 0, w->Description, -1, a->Description, sizeof(a->Description), NULL, NULL);
4807 WideCharToMultiByte(CP_ACP, 0, w->MfgName, -1, a->MfgName, sizeof(a->MfgName), NULL, NULL);
4808 WideCharToMultiByte(CP_ACP, 0, w->ProviderName, -1, a->ProviderName, sizeof(a->ProviderName), NULL, NULL);
4811 /***********************************************************************
4812 * SetupDiEnumDriverInfoW (SETUPAPI.@)
4814 BOOL WINAPI SetupDiEnumDriverInfoW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4815 DWORD type, DWORD index, SP_DRVINFO_DATA_W *driver_data)
4817 struct device *device;
4819 TRACE("devinfo %p, device_data %p, type %#x, index %u, driver_data %p.\n",
4820 devinfo, device_data, type, index, driver_data);
4822 if (type != SPDIT_COMPATDRIVER)
4824 FIXME("Unhandled type %#x.\n", type);
4825 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4826 return FALSE;
4829 if (!(device = get_device(devinfo, device_data)))
4830 return FALSE;
4832 if (index >= device->driver_count)
4834 SetLastError(ERROR_NO_MORE_ITEMS);
4835 return FALSE;
4838 return copy_driver_data(driver_data, &device->drivers[index]);
4841 /***********************************************************************
4842 * SetupDiEnumDriverInfoA (SETUPAPI.@)
4844 BOOL WINAPI SetupDiEnumDriverInfoA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4845 DWORD type, DWORD index, SP_DRVINFO_DATA_A *driver_data)
4847 SP_DRVINFO_DATA_W driver_dataW;
4848 BOOL ret;
4850 driver_dataW.cbSize = sizeof(driver_dataW);
4851 ret = SetupDiEnumDriverInfoW(devinfo, device_data, type, index, &driver_dataW);
4852 if (ret) driver_data_wtoa(driver_data, &driver_dataW);
4854 return ret;
4857 /***********************************************************************
4858 * SetupDiSelectBestCompatDrv (SETUPAPI.@)
4860 BOOL WINAPI SetupDiSelectBestCompatDrv(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4862 struct device *device;
4864 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
4866 if (!(device = get_device(devinfo, device_data)))
4867 return FALSE;
4869 if (!device->driver_count)
4871 WARN("No compatible drivers were enumerated for device %s.\n", debugstr_w(device->instanceId));
4872 SetLastError(ERROR_NO_COMPAT_DRIVERS);
4873 return FALSE;
4876 WARN("Semi-stub, selecting the first available driver.\n");
4878 device->selected_driver = &device->drivers[0];
4880 return TRUE;
4883 /***********************************************************************
4884 * SetupDiGetSelectedDriverW (SETUPAPI.@)
4886 BOOL WINAPI SetupDiGetSelectedDriverW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, SP_DRVINFO_DATA_W *driver_data)
4888 struct device *device;
4890 TRACE("devinfo %p, device_data %p, driver_data %p.\n", devinfo, device_data, driver_data);
4892 if (!(device = get_device(devinfo, device_data)))
4893 return FALSE;
4895 if (!device->selected_driver)
4897 SetLastError(ERROR_NO_DRIVER_SELECTED);
4898 return FALSE;
4901 return copy_driver_data(driver_data, device->selected_driver);
4904 /***********************************************************************
4905 * SetupDiGetSelectedDriverA (SETUPAPI.@)
4907 BOOL WINAPI SetupDiGetSelectedDriverA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, SP_DRVINFO_DATA_A *driver_data)
4909 SP_DRVINFO_DATA_W driver_dataW;
4910 BOOL ret;
4912 driver_dataW.cbSize = sizeof(driver_dataW);
4913 if ((ret = SetupDiGetSelectedDriverW(devinfo, device_data, &driver_dataW)))
4914 driver_data_wtoa(driver_data, &driver_dataW);
4915 return ret;
4918 /***********************************************************************
4919 * SetupDiGetDriverInfoDetailW (SETUPAPI.@)
4921 BOOL WINAPI SetupDiGetDriverInfoDetailW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4922 SP_DRVINFO_DATA_W *driver_data, SP_DRVINFO_DETAIL_DATA_W *detail_data, const DWORD size, DWORD *ret_size)
4924 struct driver *driver = (struct driver *)driver_data->Reserved;
4925 DWORD size_needed, i, id_size = 1;
4926 WCHAR id[MAX_DEVICE_ID_LEN];
4927 INFCONTEXT ctx;
4928 HANDLE file;
4929 HINF hinf;
4931 TRACE("devinfo %p, device_data %p, driver_data %p, detail_data %p, size %u, ret_size %p.\n",
4932 devinfo, device_data, driver_data, detail_data, size, ret_size);
4934 if ((detail_data || size) && size < sizeof(SP_DRVINFO_DETAIL_DATA_W))
4936 SetLastError(ERROR_INVALID_USER_BUFFER);
4937 return FALSE;
4940 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4941 return FALSE;
4943 SetupFindFirstLineW(hinf, driver->mfg_key, driver->description, &ctx);
4944 for (i = 2; SetupGetStringFieldW(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
4945 id_size += wcslen(id) + 1;
4947 size_needed = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID[id_size]);
4948 if (ret_size)
4949 *ret_size = size_needed;
4950 if (!detail_data)
4951 return TRUE;
4953 detail_data->CompatIDsLength = detail_data->CompatIDsOffset = 0;
4954 detail_data->HardwareID[0] = 0;
4956 if (size >= size_needed)
4958 id_size = 0;
4959 for (i = 2; SetupGetStringFieldW(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
4961 wcscpy(&detail_data->HardwareID[id_size], id);
4962 if (i == 3)
4963 detail_data->CompatIDsOffset = id_size;
4964 id_size += wcslen(id) + 1;
4966 detail_data->HardwareID[id_size++] = 0;
4967 if (i > 3)
4968 detail_data->CompatIDsLength = id_size - detail_data->CompatIDsOffset;
4971 SetupCloseInfFile(hinf);
4973 if ((file = CreateFileW(driver->inf_path, 0, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
4974 return FALSE;
4975 GetFileTime(file, NULL, NULL, &detail_data->InfDate);
4976 CloseHandle(file);
4978 wcscpy(detail_data->SectionName, driver->section);
4979 wcscpy(detail_data->InfFileName, driver->inf_path);
4980 wcscpy(detail_data->DrvDescription, driver->description);
4982 if (size < size_needed)
4984 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4985 return FALSE;
4988 return TRUE;
4991 /***********************************************************************
4992 * SetupDiGetDriverInfoDetailA (SETUPAPI.@)
4994 BOOL WINAPI SetupDiGetDriverInfoDetailA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4995 SP_DRVINFO_DATA_A *driver_data, SP_DRVINFO_DETAIL_DATA_A *detail_data, const DWORD size, DWORD *ret_size)
4997 struct driver *driver = (struct driver *)driver_data->Reserved;
4998 DWORD size_needed, i, id_size = 1;
4999 char id[MAX_DEVICE_ID_LEN];
5000 INFCONTEXT ctx;
5001 HANDLE file;
5002 HINF hinf;
5004 TRACE("devinfo %p, device_data %p, driver_data %p, detail_data %p, size %u, ret_size %p.\n",
5005 devinfo, device_data, driver_data, detail_data, size, ret_size);
5007 if ((detail_data || size) && size < sizeof(SP_DRVINFO_DETAIL_DATA_A))
5009 SetLastError(ERROR_INVALID_USER_BUFFER);
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 for (i = 2; SetupGetStringFieldA(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
5018 id_size += strlen(id) + 1;
5020 size_needed = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID[id_size]);
5021 if (ret_size)
5022 *ret_size = size_needed;
5023 if (!detail_data)
5025 SetupCloseInfFile(hinf);
5026 return TRUE;
5029 detail_data->CompatIDsLength = detail_data->CompatIDsOffset = 0;
5030 detail_data->HardwareID[0] = 0;
5032 if (size >= size_needed)
5034 id_size = 0;
5035 for (i = 2; SetupGetStringFieldA(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
5037 strcpy(&detail_data->HardwareID[id_size], id);
5038 if (i == 3)
5039 detail_data->CompatIDsOffset = id_size;
5040 id_size += strlen(id) + 1;
5042 detail_data->HardwareID[id_size++] = 0;
5043 if (i > 3)
5044 detail_data->CompatIDsLength = id_size - detail_data->CompatIDsOffset;
5047 SetupCloseInfFile(hinf);
5049 if ((file = CreateFileW(driver->inf_path, 0, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
5050 return FALSE;
5051 GetFileTime(file, NULL, NULL, &detail_data->InfDate);
5052 CloseHandle(file);
5054 WideCharToMultiByte(CP_ACP, 0, driver->section, -1, detail_data->SectionName,
5055 sizeof(detail_data->SectionName), NULL, NULL);
5056 WideCharToMultiByte(CP_ACP, 0, driver->inf_path, -1, detail_data->InfFileName,
5057 sizeof(detail_data->InfFileName), NULL, NULL);
5058 WideCharToMultiByte(CP_ACP, 0, driver->description, -1, detail_data->DrvDescription,
5059 sizeof(detail_data->InfFileName), NULL, NULL);
5061 if (size < size_needed)
5063 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5064 return FALSE;
5067 return TRUE;
5070 /***********************************************************************
5071 * SetupDiInstallDriverFiles (SETUPAPI.@)
5073 BOOL WINAPI SetupDiInstallDriverFiles(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
5075 WCHAR section[LINE_LEN], section_ext[LINE_LEN], iface_section[LINE_LEN];
5076 struct device *device;
5077 struct driver *driver;
5078 void *callback_ctx;
5079 INFCONTEXT ctx;
5080 HINF hinf;
5082 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
5084 if (!(device = get_device(devinfo, device_data)))
5085 return FALSE;
5087 if (!(driver = device->selected_driver))
5089 ERR("No driver selected for device %p.\n", devinfo);
5090 SetLastError(ERROR_NO_DRIVER_SELECTED);
5091 return FALSE;
5094 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
5095 return FALSE;
5097 SetupFindFirstLineW(hinf, driver->mfg_key, driver->description, &ctx);
5098 SetupGetStringFieldW(&ctx, 1, section, ARRAY_SIZE(section), NULL);
5099 SetupDiGetActualSectionToInstallW(hinf, section, section_ext, ARRAY_SIZE(section_ext), NULL, NULL);
5101 callback_ctx = SetupInitDefaultQueueCallback(NULL);
5103 SetupInstallFromInfSectionW(NULL, hinf, section_ext, SPINST_FILES, NULL, NULL,
5104 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5106 lstrcatW(section_ext, dotInterfaces);
5107 if (SetupFindFirstLineW(hinf, section_ext, AddInterface, &ctx))
5109 do {
5110 SetupGetStringFieldW(&ctx, 3, iface_section, ARRAY_SIZE(iface_section), NULL);
5111 SetupInstallFromInfSectionW(NULL, hinf, iface_section, SPINST_FILES, NULL, NULL,
5112 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5113 } while (SetupFindNextMatchLineW(&ctx, AddInterface, &ctx));
5116 SetupTermDefaultQueueCallback(callback_ctx);
5118 SetupCloseInfFile(hinf);
5119 return TRUE;
5122 /***********************************************************************
5123 * SetupDiInstallDevice (SETUPAPI.@)
5125 BOOL WINAPI SetupDiInstallDevice(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
5127 static const WCHAR infpathW[] = {'I','n','f','P','a','t','h',0};
5128 static const WCHAR infsectionW[] = {'I','n','f','S','e','c','t','i','o','n',0};
5129 static const WCHAR infsectionextW[] = {'I','n','f','S','e','c','t','i','o','n','E','x','t',0};
5130 static const WCHAR dothwW[] = {'.','H','W',0};
5131 static const WCHAR dotservicesW[] = {'.','S','e','r','v','i','c','e','s',0};
5132 static const WCHAR addserviceW[] = {'A','d','d','S','e','r','v','i','c','e',0};
5133 static const WCHAR rootW[] = {'r','o','o','t','\\',0};
5134 WCHAR section_ext[LINE_LEN], subsection[LINE_LEN], inf_path[MAX_PATH], *extptr, *filepart;
5135 UINT install_flags = SPINST_ALL;
5136 HKEY driver_key, device_key;
5137 SC_HANDLE manager, service;
5138 WCHAR svc_name[LINE_LEN];
5139 struct device *device;
5140 struct driver *driver;
5141 void *callback_ctx;
5142 INFCONTEXT ctx;
5143 HINF hinf;
5144 LONG l;
5146 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
5148 if (!(device = get_device(devinfo, device_data)))
5149 return FALSE;
5151 if (!(driver = device->selected_driver))
5153 ERR("No driver selected for device %p.\n", devinfo);
5154 SetLastError(ERROR_NO_DRIVER_SELECTED);
5155 return FALSE;
5158 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
5159 return FALSE;
5161 RegSetValueExW(device->key, L"DeviceDesc", 0, REG_SZ, (BYTE *)driver->description,
5162 wcslen(driver->description) * sizeof(WCHAR));
5164 SetupDiGetActualSectionToInstallW(hinf, driver->section, section_ext, ARRAY_SIZE(section_ext), NULL, &extptr);
5166 if ((l = create_driver_key(device, &driver_key)))
5168 SetLastError(l);
5169 SetupCloseInfFile(hinf);
5170 return FALSE;
5173 if ((l = RegCreateKeyExW(device->key, DeviceParameters, 0, NULL, 0,
5174 KEY_READ | KEY_WRITE, NULL, &device_key, NULL)))
5176 SetLastError(l);
5177 RegCloseKey(driver_key);
5178 SetupCloseInfFile(hinf);
5179 return FALSE;
5182 if (device->params.Flags & DI_NOFILECOPY)
5183 install_flags &= ~SPINST_FILES;
5185 callback_ctx = SetupInitDefaultQueueCallback(NULL);
5187 SetupInstallFromInfSectionW(NULL, hinf, section_ext, install_flags, driver_key, NULL,
5188 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5190 lstrcpyW(subsection, section_ext);
5191 lstrcatW(subsection, dothwW);
5193 SetupInstallFromInfSectionW(NULL, hinf, subsection, install_flags, device_key, NULL,
5194 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5196 lstrcpyW(subsection, section_ext);
5197 lstrcatW(subsection, dotservicesW);
5198 SetupInstallServicesFromInfSectionW(hinf, subsection, 0);
5200 svc_name[0] = 0;
5201 if (SetupFindFirstLineW(hinf, subsection, addserviceW, &ctx))
5205 INT flags;
5207 if (SetupGetIntField(&ctx, 2, &flags) && (flags & SPSVCINST_ASSOCSERVICE))
5209 if (SetupGetStringFieldW(&ctx, 1, svc_name, ARRAY_SIZE(svc_name), NULL) && svc_name[0])
5210 RegSetValueExW(device->key, Service, 0, REG_SZ, (BYTE *)svc_name, lstrlenW(svc_name) * sizeof(WCHAR));
5211 break;
5213 } while (SetupFindNextMatchLineW(&ctx, addserviceW, &ctx));
5216 SetupTermDefaultQueueCallback(callback_ctx);
5217 SetupCloseInfFile(hinf);
5219 SetupCopyOEMInfW(driver->inf_path, NULL, SPOST_NONE, 0, inf_path, ARRAY_SIZE(inf_path), NULL, &filepart);
5220 TRACE("Copied INF file %s to %s.\n", debugstr_w(driver->inf_path), debugstr_w(inf_path));
5222 RegSetValueExW(driver_key, infpathW, 0, REG_SZ, (BYTE *)filepart, lstrlenW(filepart) * sizeof(WCHAR));
5223 RegSetValueExW(driver_key, infsectionW, 0, REG_SZ, (BYTE *)driver->section, lstrlenW(driver->section) * sizeof(WCHAR));
5224 if (extptr)
5225 RegSetValueExW(driver_key, infsectionextW, 0, REG_SZ, (BYTE *)extptr, lstrlenW(extptr) * sizeof(WCHAR));
5227 RegCloseKey(device_key);
5228 RegCloseKey(driver_key);
5230 if (!wcsnicmp(device->instanceId, rootW, lstrlenW(rootW)) && svc_name[0]
5231 && (manager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT)))
5233 if ((service = OpenServiceW(manager, svc_name, SERVICE_START | SERVICE_USER_DEFINED_CONTROL)))
5235 SERVICE_STATUS status;
5237 if (!StartServiceW(service, 0, NULL) && GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5239 ERR("Failed to start service %s for device %s, error %u.\n",
5240 debugstr_w(svc_name), debugstr_w(device->instanceId), GetLastError());
5242 if (!ControlService(service, SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES, &status))
5244 ERR("Failed to control service %s for device %s, error %u.\n",
5245 debugstr_w(svc_name), debugstr_w(device->instanceId), GetLastError());
5247 CloseServiceHandle(service);
5249 else
5250 ERR("Failed to open service %s for device %s.\n", debugstr_w(svc_name), debugstr_w(device->instanceId));
5251 CloseServiceHandle(manager);
5254 return TRUE;