winspool: Initialize nt_ppd in add_printer_driver.
[wine.git] / dlls / setupapi / devinst.c
blobef7b4dccf0d24ba43c63219514f6a5c7f41ee504
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 ContainerId[] = {'C','o','n','t','a','i','n','e','r','I','d',0};
100 static const WCHAR Phantom[] = {'P','h','a','n','t','o','m',0};
101 static const WCHAR SymbolicLink[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
102 static const WCHAR Control[] = {'C','o','n','t','r','o','l',0};
103 static const WCHAR Linked[] = {'L','i','n','k','e','d',0};
104 static const WCHAR dotInterfaces[] = {'.','I','n','t','e','r','f','a','c','e','s',0};
105 static const WCHAR AddInterface[] = {'A','d','d','I','n','t','e','r','f','a','c','e',0};
106 static const WCHAR backslashW[] = {'\\',0};
107 static const WCHAR emptyW[] = {0};
109 #define SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES 128
111 struct driver
113 DWORD rank;
114 WCHAR inf_path[MAX_PATH];
115 WCHAR manufacturer[LINE_LEN];
116 WCHAR mfg_key[LINE_LEN];
117 WCHAR description[LINE_LEN];
118 WCHAR section[LINE_LEN];
121 /* is used to identify if a DeviceInfoSet pointer is
122 valid or not */
123 #define SETUP_DEVICE_INFO_SET_MAGIC 0xd00ff056
125 struct DeviceInfoSet
127 DWORD magic; /* if is equal to SETUP_DEVICE_INFO_SET_MAGIC struct is okay */
128 GUID ClassGuid;
129 HWND hwndParent;
130 struct list devices;
133 struct device
135 struct DeviceInfoSet *set;
136 HKEY key;
137 BOOL phantom;
138 WCHAR *instanceId;
139 struct list interfaces;
140 GUID class;
141 DEVINST devnode;
142 struct list entry;
143 BOOL removed;
144 SP_DEVINSTALL_PARAMS_W params;
145 struct driver *drivers;
146 unsigned int driver_count;
147 struct driver *selected_driver;
150 struct device_iface
152 WCHAR *refstr;
153 WCHAR *symlink;
154 struct device *device;
155 GUID class;
156 DWORD flags;
157 HKEY class_key;
158 HKEY refstr_key;
159 struct list entry;
162 static struct DeviceInfoSet *get_device_set(HDEVINFO devinfo)
164 struct DeviceInfoSet *set = devinfo;
166 if (!devinfo || devinfo == INVALID_HANDLE_VALUE || set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
168 SetLastError(ERROR_INVALID_HANDLE);
169 return NULL;
172 return set;
175 static struct device *get_device(HDEVINFO devinfo, const SP_DEVINFO_DATA *data)
177 struct DeviceInfoSet *set;
178 struct device *device;
180 if (!(set = get_device_set(devinfo)))
181 return FALSE;
183 if (!data || data->cbSize != sizeof(*data) || !data->Reserved)
185 SetLastError(ERROR_INVALID_PARAMETER);
186 return NULL;
189 device = (struct device *)data->Reserved;
191 if (device->set != set)
193 SetLastError(ERROR_INVALID_PARAMETER);
194 return NULL;
197 if (device->removed)
199 SetLastError(ERROR_NO_SUCH_DEVINST);
200 return NULL;
203 return device;
206 static struct device_iface *get_device_iface(HDEVINFO devinfo, const SP_DEVICE_INTERFACE_DATA *data)
208 if (!get_device_set(devinfo))
209 return FALSE;
211 if (!data || data->cbSize != sizeof(*data) || !data->Reserved)
213 SetLastError(ERROR_INVALID_PARAMETER);
214 return NULL;
217 return (struct device_iface *)data->Reserved;
220 static inline void copy_device_data(SP_DEVINFO_DATA *data, const struct device *device)
222 data->ClassGuid = device->class;
223 data->DevInst = device->devnode;
224 data->Reserved = (ULONG_PTR)device;
227 static inline void copy_device_iface_data(SP_DEVICE_INTERFACE_DATA *data,
228 const struct device_iface *iface)
230 data->InterfaceClassGuid = iface->class;
231 data->Flags = iface->flags;
232 data->Reserved = (ULONG_PTR)iface;
235 static struct device **devnode_table;
236 static unsigned int devnode_table_size;
238 static DEVINST alloc_devnode(struct device *device)
240 unsigned int i;
242 for (i = 0; i < devnode_table_size; ++i)
244 if (!devnode_table[i])
245 break;
248 if (i == devnode_table_size)
250 if (devnode_table)
252 devnode_table_size *= 2;
253 devnode_table = heap_realloc_zero(devnode_table,
254 devnode_table_size * sizeof(*devnode_table));
256 else
258 devnode_table_size = 256;
259 devnode_table = heap_alloc_zero(devnode_table_size * sizeof(*devnode_table));
263 devnode_table[i] = device;
264 return i;
267 static void free_devnode(DEVINST devnode)
269 devnode_table[devnode] = NULL;
272 static struct device *get_devnode_device(DEVINST devnode)
274 if (devnode < devnode_table_size)
275 return devnode_table[devnode];
277 WARN("device node %lu not found\n", devnode);
278 return NULL;
281 static void SETUPDI_GuidToString(const GUID *guid, LPWSTR guidStr)
283 static const WCHAR fmt[] = {'{','%','0','8','X','-','%','0','4','X','-',
284 '%','0','4','X','-','%','0','2','X','%','0','2','X','-','%','0','2',
285 'X','%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X','%',
286 '0','2','X','}',0};
288 swprintf(guidStr, 39, fmt, guid->Data1, guid->Data2, guid->Data3,
289 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
290 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
293 static WCHAR *get_iface_key_path(struct device_iface *iface)
295 static const WCHAR slashW[] = {'\\',0};
296 WCHAR *path, *ptr;
297 size_t len = lstrlenW(DeviceClasses) + 1 + 38 + 1 + lstrlenW(iface->symlink);
299 if (!(path = heap_alloc((len + 1) * sizeof(WCHAR))))
301 SetLastError(ERROR_OUTOFMEMORY);
302 return NULL;
305 lstrcpyW(path, DeviceClasses);
306 lstrcatW(path, slashW);
307 SETUPDI_GuidToString(&iface->class, path + lstrlenW(path));
308 lstrcatW(path, slashW);
309 ptr = path + lstrlenW(path);
310 lstrcatW(path, iface->symlink);
311 if (lstrlenW(iface->symlink) > 3)
312 ptr[0] = ptr[1] = ptr[3] = '#';
314 ptr = wcschr(ptr, '\\');
315 if (ptr) *ptr = 0;
317 return path;
320 static WCHAR *get_refstr_key_path(struct device_iface *iface)
322 static const WCHAR hashW[] = {'#',0};
323 static const WCHAR slashW[] = {'\\',0};
324 WCHAR *path, *ptr;
325 size_t len = lstrlenW(DeviceClasses) + 1 + 38 + 1 + lstrlenW(iface->symlink) + 1 + 1;
327 if (iface->refstr)
328 len += lstrlenW(iface->refstr);
330 if (!(path = heap_alloc((len + 1) * sizeof(WCHAR))))
332 SetLastError(ERROR_OUTOFMEMORY);
333 return NULL;
336 lstrcpyW(path, DeviceClasses);
337 lstrcatW(path, slashW);
338 SETUPDI_GuidToString(&iface->class, path + lstrlenW(path));
339 lstrcatW(path, slashW);
340 ptr = path + lstrlenW(path);
341 lstrcatW(path, iface->symlink);
342 if (lstrlenW(iface->symlink) > 3)
343 ptr[0] = ptr[1] = ptr[3] = '#';
345 ptr = wcschr(ptr, '\\');
346 if (ptr) *ptr = 0;
348 lstrcatW(path, slashW);
349 lstrcatW(path, hashW);
351 if (iface->refstr)
352 lstrcatW(path, iface->refstr);
354 return path;
357 static BOOL is_valid_property_type(DEVPROPTYPE prop_type)
359 DWORD type = prop_type & DEVPROP_MASK_TYPE;
360 DWORD typemod = prop_type & DEVPROP_MASK_TYPEMOD;
362 if (type > MAX_DEVPROP_TYPE)
363 return FALSE;
364 if (typemod > MAX_DEVPROP_TYPEMOD)
365 return FALSE;
367 if (typemod == DEVPROP_TYPEMOD_ARRAY
368 && (type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL || type == DEVPROP_TYPE_STRING
369 || type == DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING))
370 return FALSE;
372 if (typemod == DEVPROP_TYPEMOD_LIST
373 && !(type == DEVPROP_TYPE_STRING || type == DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING))
374 return FALSE;
376 return TRUE;
379 static LPWSTR SETUPDI_CreateSymbolicLinkPath(LPCWSTR instanceId,
380 const GUID *InterfaceClassGuid, LPCWSTR ReferenceString)
382 static const WCHAR fmt[] = {'\\','\\','?','\\','%','s','#','%','s',0};
383 WCHAR guidStr[39];
384 DWORD len;
385 LPWSTR ret;
387 SETUPDI_GuidToString(InterfaceClassGuid, guidStr);
388 /* omit length of format specifiers, but include NULL terminator: */
389 len = lstrlenW(fmt) - 4 + 1;
390 len += lstrlenW(instanceId) + lstrlenW(guidStr);
391 if (ReferenceString && *ReferenceString)
393 /* space for a hash between string and reference string: */
394 len += lstrlenW(ReferenceString) + 1;
396 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
397 if (ret)
399 int printed = swprintf(ret, len, fmt, instanceId, guidStr);
400 LPWSTR ptr;
402 /* replace '\\' with '#' after the "\\\\?\\" beginning */
403 for (ptr = wcschr(ret + 4, '\\'); ptr; ptr = wcschr(ptr + 1, '\\'))
404 *ptr = '#';
405 if (ReferenceString && *ReferenceString)
407 ret[printed] = '\\';
408 lstrcpyW(ret + printed + 1, ReferenceString);
412 CharLowerW(ret);
414 return ret;
417 static BOOL is_linked(HKEY key)
419 DWORD linked, type, size;
420 HKEY control_key;
421 BOOL ret = FALSE;
423 if (!RegOpenKeyW(key, Control, &control_key))
425 size = sizeof(DWORD);
426 if (!RegQueryValueExW(control_key, Linked, NULL, &type, (BYTE *)&linked, &size)
427 && type == REG_DWORD && linked)
428 ret = TRUE;
430 RegCloseKey(control_key);
433 return ret;
436 static struct device_iface *SETUPDI_CreateDeviceInterface(struct device *device,
437 const GUID *class, const WCHAR *refstr)
439 struct device_iface *iface = NULL;
440 WCHAR *refstr2 = NULL, *symlink = NULL, *path = NULL;
441 HKEY key;
442 LONG ret;
444 TRACE("%p %s %s\n", device, debugstr_guid(class), debugstr_w(refstr));
446 /* check if it already exists */
447 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
449 if (IsEqualGUID(&iface->class, class) && !lstrcmpiW(iface->refstr, refstr))
450 return iface;
453 iface = heap_alloc(sizeof(*iface));
454 symlink = SETUPDI_CreateSymbolicLinkPath(device->instanceId, class, refstr);
456 if (!iface || !symlink)
458 SetLastError(ERROR_OUTOFMEMORY);
459 goto err;
462 if (refstr && !(refstr2 = strdupW(refstr)))
464 SetLastError(ERROR_OUTOFMEMORY);
465 goto err;
467 iface->refstr = refstr2;
468 iface->symlink = symlink;
469 iface->device = device;
470 iface->class = *class;
471 iface->flags = 0;
473 if (!(path = get_iface_key_path(iface)))
475 SetLastError(ERROR_OUTOFMEMORY);
476 goto err;
479 if ((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, path, &key)))
481 SetLastError(ret);
482 goto err;
484 RegSetValueExW(key, DeviceInstance, 0, REG_SZ, (BYTE *)device->instanceId,
485 lstrlenW(device->instanceId) * sizeof(WCHAR));
486 heap_free(path);
488 iface->class_key = key;
490 if (!(path = get_refstr_key_path(iface)))
492 SetLastError(ERROR_OUTOFMEMORY);
493 goto err;
496 if ((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, path, &key)))
498 SetLastError(ret);
499 goto err;
501 RegSetValueExW(key, SymbolicLink, 0, REG_SZ, (BYTE *)iface->symlink,
502 lstrlenW(iface->symlink) * sizeof(WCHAR));
504 if (is_linked(key))
505 iface->flags |= SPINT_ACTIVE;
507 heap_free(path);
509 iface->refstr_key = key;
511 list_add_tail(&device->interfaces, &iface->entry);
512 return iface;
514 err:
515 heap_free(iface);
516 heap_free(refstr2);
517 heap_free(symlink);
518 heap_free(path);
519 return NULL;
522 static BOOL SETUPDI_SetInterfaceSymbolicLink(struct device_iface *iface,
523 const WCHAR *symlink)
525 heap_free(iface->symlink);
526 if ((iface->symlink = strdupW(symlink)))
527 return TRUE;
528 return FALSE;
531 static HKEY SETUPDI_CreateDevKey(struct device *device)
533 HKEY enumKey, key = INVALID_HANDLE_VALUE;
534 LONG l;
536 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_ALL_ACCESS,
537 NULL, &enumKey, NULL);
538 if (!l)
540 RegCreateKeyExW(enumKey, device->instanceId, 0, NULL, 0,
541 KEY_READ | KEY_WRITE, NULL, &key, NULL);
542 RegCloseKey(enumKey);
544 return key;
547 static LONG open_driver_key(struct device *device, REGSAM access, HKEY *key)
549 HKEY class_key;
550 WCHAR path[50];
551 DWORD size = sizeof(path);
552 LONG l;
554 if ((l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, ControlClass, 0, NULL, 0,
555 KEY_CREATE_SUB_KEY, NULL, &class_key, NULL)))
557 ERR("Failed to open driver class root key, error %lu.\n", l);
558 return l;
561 if (!(l = RegGetValueW(device->key, NULL, Driver, RRF_RT_REG_SZ, NULL, path, &size)))
563 if (!(l = RegOpenKeyExW(class_key, path, 0, access, key)))
565 RegCloseKey(class_key);
566 return l;
568 TRACE("Failed to open driver key, error %lu.\n", l);
571 RegCloseKey(class_key);
572 return l;
575 static LONG create_driver_key(struct device *device, HKEY *key)
577 static const WCHAR formatW[] = {'%','0','4','u',0};
578 static const WCHAR slash[] = { '\\',0 };
579 unsigned int i = 0;
580 WCHAR path[50];
581 HKEY class_key;
582 DWORD dispos;
583 LONG l;
585 if (!open_driver_key(device, KEY_READ | KEY_WRITE, key))
586 return ERROR_SUCCESS;
588 if ((l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, ControlClass, 0, NULL, 0,
589 KEY_CREATE_SUB_KEY, NULL, &class_key, NULL)))
591 ERR("Failed to open driver class root key, error %lu.\n", l);
592 return l;
595 SETUPDI_GuidToString(&device->class, path);
596 lstrcatW(path, slash);
597 /* Allocate a new driver key, by finding the first integer value that's not
598 * already taken. */
599 for (;;)
601 swprintf(path + 39, ARRAY_SIZE(path) - 39, formatW, i++);
602 if ((l = RegCreateKeyExW(class_key, path, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, key, &dispos)))
603 break;
604 else if (dispos == REG_CREATED_NEW_KEY)
606 RegSetValueExW(device->key, Driver, 0, REG_SZ, (BYTE *)path, lstrlenW(path) * sizeof(WCHAR));
607 RegCloseKey(class_key);
608 return ERROR_SUCCESS;
610 RegCloseKey(*key);
612 ERR("Failed to create driver key, error %lu.\n", l);
613 RegCloseKey(class_key);
614 return l;
617 static LONG delete_driver_key(struct device *device)
619 HKEY key;
620 LONG l;
622 if (!(l = open_driver_key(device, KEY_READ | KEY_WRITE, &key)))
624 l = RegDeleteKeyW(key, emptyW);
625 RegCloseKey(key);
628 return l;
631 struct PropertyMapEntry
633 DWORD regType;
634 LPCSTR nameA;
635 LPCWSTR nameW;
638 static const struct PropertyMapEntry PropertyMap[] = {
639 { REG_SZ, "DeviceDesc", DeviceDesc },
640 { REG_MULTI_SZ, "HardwareId", HardwareId },
641 { REG_MULTI_SZ, "CompatibleIDs", CompatibleIDs },
642 { 0, NULL, NULL }, /* SPDRP_UNUSED0 */
643 { REG_SZ, "Service", Service },
644 { 0, NULL, NULL }, /* SPDRP_UNUSED1 */
645 { 0, NULL, NULL }, /* SPDRP_UNUSED2 */
646 { REG_SZ, "Class", Class },
647 { REG_SZ, "ClassGUID", ClassGUID },
648 { REG_SZ, "Driver", Driver },
649 { REG_DWORD, "ConfigFlags", ConfigFlags },
650 { REG_SZ, "Mfg", Mfg },
651 { REG_SZ, "FriendlyName", FriendlyName },
652 { REG_SZ, "LocationInformation", LocationInformation },
653 { 0, NULL, NULL }, /* SPDRP_PHYSICAL_DEVICE_OBJECT_NAME */
654 { REG_DWORD, "Capabilities", Capabilities },
655 { REG_DWORD, "UINumber", UINumber },
656 { REG_MULTI_SZ, "UpperFilters", UpperFilters },
657 { REG_MULTI_SZ, "LowerFilters", LowerFilters },
658 [SPDRP_BASE_CONTAINERID] = { REG_SZ, "ContainerId", ContainerId },
661 static BOOL SETUPDI_SetDeviceRegistryPropertyW(struct device *device,
662 DWORD prop, const BYTE *buffer, DWORD size)
664 if (prop < ARRAY_SIZE(PropertyMap) && PropertyMap[prop].nameW)
666 LONG ret = RegSetValueExW(device->key, PropertyMap[prop].nameW, 0,
667 PropertyMap[prop].regType, buffer, size);
668 if (!ret)
669 return TRUE;
671 SetLastError(ret);
673 return FALSE;
676 static void remove_device_iface(struct device_iface *iface)
678 RegDeleteTreeW(iface->refstr_key, NULL);
679 RegDeleteKeyW(iface->refstr_key, emptyW);
680 RegCloseKey(iface->refstr_key);
681 iface->refstr_key = NULL;
682 /* Also remove the class key if it's empty. */
683 RegDeleteKeyW(iface->class_key, emptyW);
684 RegCloseKey(iface->class_key);
685 iface->class_key = NULL;
686 iface->flags |= SPINT_REMOVED;
689 static void delete_device_iface(struct device_iface *iface)
691 list_remove(&iface->entry);
692 RegCloseKey(iface->refstr_key);
693 RegCloseKey(iface->class_key);
694 heap_free(iface->refstr);
695 heap_free(iface->symlink);
696 heap_free(iface);
699 /* remove all interfaces associated with the device, including those not
700 * enumerated in the set */
701 static void remove_all_device_ifaces(struct device *device)
703 HKEY classes_key;
704 DWORD i, len;
705 LONG ret;
707 if ((ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, DeviceClasses, 0, KEY_READ, &classes_key)))
709 WARN("Failed to open classes key, error %lu.\n", ret);
710 return;
713 for (i = 0; ; ++i)
715 WCHAR class_name[40];
716 HKEY class_key;
717 DWORD j;
719 len = ARRAY_SIZE(class_name);
720 if ((ret = RegEnumKeyExW(classes_key, i, class_name, &len, NULL, NULL, NULL, NULL)))
722 if (ret != ERROR_NO_MORE_ITEMS) ERR("Failed to enumerate classes, error %lu.\n", ret);
723 break;
726 if ((ret = RegOpenKeyExW(classes_key, class_name, 0, KEY_READ, &class_key)))
728 ERR("Failed to open class %s, error %lu.\n", debugstr_w(class_name), ret);
729 continue;
732 for (j = 0; ; ++j)
734 WCHAR iface_name[MAX_DEVICE_ID_LEN + 39], device_name[MAX_DEVICE_ID_LEN];
735 HKEY iface_key;
737 len = ARRAY_SIZE(iface_name);
738 if ((ret = RegEnumKeyExW(class_key, j, iface_name, &len, NULL, NULL, NULL, NULL)))
740 if (ret != ERROR_NO_MORE_ITEMS) ERR("Failed to enumerate interfaces, error %lu.\n", ret);
741 break;
744 if ((ret = RegOpenKeyExW(class_key, iface_name, 0, KEY_ALL_ACCESS, &iface_key)))
746 ERR("Failed to open interface %s, error %lu.\n", debugstr_w(iface_name), ret);
747 continue;
750 len = sizeof(device_name);
751 if ((ret = RegQueryValueExW(iface_key, L"DeviceInstance", NULL, NULL, (BYTE *)device_name, &len)))
753 ERR("Failed to query device instance, error %lu.\n", ret);
754 RegCloseKey(iface_key);
755 continue;
758 if (!wcsicmp(device_name, device->instanceId))
760 if ((ret = RegDeleteTreeW(iface_key, NULL)))
761 ERR("Failed to delete interface %s subkeys, error %lu.\n", debugstr_w(iface_name), ret);
762 if ((ret = RegDeleteKeyW(iface_key, L"")))
763 ERR("Failed to delete interface %s, error %lu.\n", debugstr_w(iface_name), ret);
766 RegCloseKey(iface_key);
768 RegCloseKey(class_key);
771 RegCloseKey(classes_key);
774 static void remove_device(struct device *device)
776 WCHAR id[MAX_DEVICE_ID_LEN], *p;
777 struct device_iface *iface;
778 HKEY enum_key;
780 delete_driver_key(device);
782 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
784 remove_device_iface(iface);
787 RegDeleteTreeW(device->key, NULL);
788 RegDeleteKeyW(device->key, emptyW);
790 /* delete all empty parents of the key */
791 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, 0, &enum_key))
793 lstrcpyW(id, device->instanceId);
795 while ((p = wcsrchr(id, '\\')))
797 *p = 0;
798 RegDeleteKeyW(enum_key, id);
801 RegCloseKey(enum_key);
804 RegCloseKey(device->key);
805 device->key = NULL;
806 device->removed = TRUE;
809 static void delete_device(struct device *device)
811 struct device_iface *iface, *next;
812 SP_DEVINFO_DATA device_data;
814 device_data.cbSize = sizeof(device_data);
815 copy_device_data(&device_data, device);
816 SetupDiCallClassInstaller(DIF_DESTROYPRIVATEDATA, device->set, &device_data);
818 if (device->phantom)
820 remove_device(device);
821 remove_all_device_ifaces(device);
824 RegCloseKey(device->key);
825 heap_free(device->instanceId);
826 heap_free(device->drivers);
828 LIST_FOR_EACH_ENTRY_SAFE(iface, next, &device->interfaces,
829 struct device_iface, entry)
831 delete_device_iface(iface);
833 free_devnode(device->devnode);
834 list_remove(&device->entry);
835 heap_free(device);
838 /* Create a new device, or return a device already in the set. */
839 static struct device *create_device(struct DeviceInfoSet *set,
840 const GUID *class, const WCHAR *instanceid, BOOL phantom)
842 const DWORD one = 1;
843 struct device *device;
844 WCHAR guidstr[MAX_GUID_STRING_LEN];
845 WCHAR class_name[MAX_CLASS_NAME_LEN];
846 DWORD size;
848 TRACE("%p, %s, %s, %d\n", set, debugstr_guid(class),
849 debugstr_w(instanceid), phantom);
851 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
853 if (!wcsicmp(instanceid, device->instanceId))
855 TRACE("Found device %p already in set.\n", device);
856 return device;
860 if (!(device = heap_alloc_zero(sizeof(*device))))
862 SetLastError(ERROR_OUTOFMEMORY);
863 return NULL;
866 if (!(device->instanceId = strdupW(instanceid)))
868 SetLastError(ERROR_OUTOFMEMORY);
869 heap_free(device);
870 return NULL;
873 wcsupr(device->instanceId);
874 device->set = set;
875 device->key = SETUPDI_CreateDevKey(device);
876 device->phantom = phantom;
877 list_init(&device->interfaces);
878 device->class = *class;
879 device->devnode = alloc_devnode(device);
880 device->removed = FALSE;
881 list_add_tail(&set->devices, &device->entry);
882 device->params.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
884 if (phantom)
885 RegSetValueExW(device->key, Phantom, 0, REG_DWORD, (const BYTE *)&one, sizeof(one));
887 SETUPDI_GuidToString(class, guidstr);
888 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_CLASSGUID,
889 (const BYTE *)guidstr, sizeof(guidstr));
891 if (SetupDiClassNameFromGuidW(class, class_name, ARRAY_SIZE(class_name), NULL))
893 size = (lstrlenW(class_name) + 1) * sizeof(WCHAR);
894 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_CLASS, (const BYTE *)class_name, size);
897 TRACE("Created new device %p.\n", device);
898 return device;
901 /***********************************************************************
902 * SetupDiBuildClassInfoList (SETUPAPI.@)
904 * Returns a list of setup class GUIDs that identify the classes
905 * that are installed on a local machine.
907 * PARAMS
908 * Flags [I] control exclusion of classes from the list.
909 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
910 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
911 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
913 * RETURNS
914 * Success: TRUE.
915 * Failure: FALSE.
917 BOOL WINAPI SetupDiBuildClassInfoList(
918 DWORD Flags,
919 LPGUID ClassGuidList,
920 DWORD ClassGuidListSize,
921 PDWORD RequiredSize)
923 TRACE("\n");
924 return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
925 ClassGuidListSize, RequiredSize,
926 NULL, NULL);
929 /***********************************************************************
930 * SetupDiBuildClassInfoListExA (SETUPAPI.@)
932 * Returns a list of setup class GUIDs that identify the classes
933 * that are installed on a local or remote machine.
935 * PARAMS
936 * Flags [I] control exclusion of classes from the list.
937 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
938 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
939 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
940 * MachineName [I] name of a remote machine.
941 * Reserved [I] must be NULL.
943 * RETURNS
944 * Success: TRUE.
945 * Failure: FALSE.
947 BOOL WINAPI SetupDiBuildClassInfoListExA(
948 DWORD Flags,
949 LPGUID ClassGuidList,
950 DWORD ClassGuidListSize,
951 PDWORD RequiredSize,
952 LPCSTR MachineName,
953 PVOID Reserved)
955 LPWSTR MachineNameW = NULL;
956 BOOL bResult;
958 TRACE("\n");
960 if (MachineName)
962 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
963 if (MachineNameW == NULL) return FALSE;
966 bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
967 ClassGuidListSize, RequiredSize,
968 MachineNameW, Reserved);
970 MyFree(MachineNameW);
972 return bResult;
975 /***********************************************************************
976 * SetupDiBuildClassInfoListExW (SETUPAPI.@)
978 * Returns a list of setup class GUIDs that identify the classes
979 * that are installed on a local or remote machine.
981 * PARAMS
982 * Flags [I] control exclusion of classes from the list.
983 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
984 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
985 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
986 * MachineName [I] name of a remote machine.
987 * Reserved [I] must be NULL.
989 * RETURNS
990 * Success: TRUE.
991 * Failure: FALSE.
993 BOOL WINAPI SetupDiBuildClassInfoListExW(
994 DWORD Flags,
995 LPGUID ClassGuidList,
996 DWORD ClassGuidListSize,
997 PDWORD RequiredSize,
998 LPCWSTR MachineName,
999 PVOID Reserved)
1001 WCHAR szKeyName[40];
1002 HKEY hClassesKey;
1003 HKEY hClassKey;
1004 DWORD dwLength;
1005 DWORD dwIndex;
1006 LONG lError;
1007 DWORD dwGuidListIndex = 0;
1009 TRACE("\n");
1011 if (RequiredSize != NULL)
1012 *RequiredSize = 0;
1014 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
1015 KEY_ALL_ACCESS,
1016 DIOCR_INSTALLER,
1017 MachineName,
1018 Reserved);
1019 if (hClassesKey == INVALID_HANDLE_VALUE)
1021 return FALSE;
1024 for (dwIndex = 0; ; dwIndex++)
1026 dwLength = 40;
1027 lError = RegEnumKeyExW(hClassesKey,
1028 dwIndex,
1029 szKeyName,
1030 &dwLength,
1031 NULL,
1032 NULL,
1033 NULL,
1034 NULL);
1035 TRACE("RegEnumKeyExW() returns %ld\n", lError);
1036 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
1038 TRACE("Key name: %p\n", szKeyName);
1040 if (RegOpenKeyExW(hClassesKey,
1041 szKeyName,
1043 KEY_ALL_ACCESS,
1044 &hClassKey))
1046 RegCloseKey(hClassesKey);
1047 return FALSE;
1050 if (!RegQueryValueExW(hClassKey,
1051 NoUseClass,
1052 NULL,
1053 NULL,
1054 NULL,
1055 NULL))
1057 TRACE("'NoUseClass' value found!\n");
1058 RegCloseKey(hClassKey);
1059 continue;
1062 if ((Flags & DIBCI_NOINSTALLCLASS) &&
1063 (!RegQueryValueExW(hClassKey,
1064 NoInstallClass,
1065 NULL,
1066 NULL,
1067 NULL,
1068 NULL)))
1070 TRACE("'NoInstallClass' value found!\n");
1071 RegCloseKey(hClassKey);
1072 continue;
1075 if ((Flags & DIBCI_NODISPLAYCLASS) &&
1076 (!RegQueryValueExW(hClassKey,
1077 NoDisplayClass,
1078 NULL,
1079 NULL,
1080 NULL,
1081 NULL)))
1083 TRACE("'NoDisplayClass' value found!\n");
1084 RegCloseKey(hClassKey);
1085 continue;
1088 RegCloseKey(hClassKey);
1090 TRACE("Guid: %p\n", szKeyName);
1091 if (dwGuidListIndex < ClassGuidListSize)
1093 if (szKeyName[0] == '{' && szKeyName[37] == '}')
1095 szKeyName[37] = 0;
1097 TRACE("Guid: %p\n", &szKeyName[1]);
1099 UuidFromStringW(&szKeyName[1],
1100 &ClassGuidList[dwGuidListIndex]);
1103 dwGuidListIndex++;
1106 if (lError != ERROR_SUCCESS)
1107 break;
1110 RegCloseKey(hClassesKey);
1112 if (RequiredSize != NULL)
1113 *RequiredSize = dwGuidListIndex;
1115 if (ClassGuidListSize < dwGuidListIndex)
1117 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1118 return FALSE;
1121 return TRUE;
1124 /***********************************************************************
1125 * SetupDiClassGuidsFromNameA (SETUPAPI.@)
1127 BOOL WINAPI SetupDiClassGuidsFromNameA(
1128 LPCSTR ClassName,
1129 LPGUID ClassGuidList,
1130 DWORD ClassGuidListSize,
1131 PDWORD RequiredSize)
1133 return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
1134 ClassGuidListSize, RequiredSize,
1135 NULL, NULL);
1138 /***********************************************************************
1139 * SetupDiClassGuidsFromNameW (SETUPAPI.@)
1141 BOOL WINAPI SetupDiClassGuidsFromNameW(
1142 LPCWSTR ClassName,
1143 LPGUID ClassGuidList,
1144 DWORD ClassGuidListSize,
1145 PDWORD RequiredSize)
1147 return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
1148 ClassGuidListSize, RequiredSize,
1149 NULL, NULL);
1152 /***********************************************************************
1153 * SetupDiClassGuidsFromNameExA (SETUPAPI.@)
1155 BOOL WINAPI SetupDiClassGuidsFromNameExA(
1156 LPCSTR ClassName,
1157 LPGUID ClassGuidList,
1158 DWORD ClassGuidListSize,
1159 PDWORD RequiredSize,
1160 LPCSTR MachineName,
1161 PVOID Reserved)
1163 LPWSTR ClassNameW = NULL;
1164 LPWSTR MachineNameW = NULL;
1165 BOOL bResult;
1167 ClassNameW = MultiByteToUnicode(ClassName, CP_ACP);
1168 if (ClassNameW == NULL)
1169 return FALSE;
1171 if (MachineName)
1173 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1174 if (MachineNameW == NULL)
1176 MyFree(ClassNameW);
1177 return FALSE;
1181 bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
1182 ClassGuidListSize, RequiredSize,
1183 MachineNameW, Reserved);
1185 MyFree(MachineNameW);
1186 MyFree(ClassNameW);
1188 return bResult;
1191 /***********************************************************************
1192 * SetupDiClassGuidsFromNameExW (SETUPAPI.@)
1194 BOOL WINAPI SetupDiClassGuidsFromNameExW(
1195 LPCWSTR ClassName,
1196 LPGUID ClassGuidList,
1197 DWORD ClassGuidListSize,
1198 PDWORD RequiredSize,
1199 LPCWSTR MachineName,
1200 PVOID Reserved)
1202 WCHAR szKeyName[40];
1203 WCHAR szClassName[256];
1204 HKEY hClassesKey;
1205 HKEY hClassKey;
1206 DWORD dwLength;
1207 DWORD dwIndex;
1208 LONG lError;
1209 DWORD dwGuidListIndex = 0;
1211 if (RequiredSize != NULL)
1212 *RequiredSize = 0;
1214 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
1215 KEY_ALL_ACCESS,
1216 DIOCR_INSTALLER,
1217 MachineName,
1218 Reserved);
1219 if (hClassesKey == INVALID_HANDLE_VALUE)
1221 return FALSE;
1224 for (dwIndex = 0; ; dwIndex++)
1226 dwLength = ARRAY_SIZE(szKeyName);
1227 lError = RegEnumKeyExW(hClassesKey,
1228 dwIndex,
1229 szKeyName,
1230 &dwLength,
1231 NULL,
1232 NULL,
1233 NULL,
1234 NULL);
1235 TRACE("RegEnumKeyExW() returns %ld\n", lError);
1236 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
1238 TRACE("Key name: %p\n", szKeyName);
1240 if (RegOpenKeyExW(hClassesKey,
1241 szKeyName,
1243 KEY_ALL_ACCESS,
1244 &hClassKey))
1246 RegCloseKey(hClassesKey);
1247 return FALSE;
1250 dwLength = sizeof(szClassName);
1251 if (!RegQueryValueExW(hClassKey,
1252 Class,
1253 NULL,
1254 NULL,
1255 (LPBYTE)szClassName,
1256 &dwLength))
1258 TRACE("Class name: %p\n", szClassName);
1260 if (wcsicmp(szClassName, ClassName) == 0)
1262 TRACE("Found matching class name\n");
1264 TRACE("Guid: %p\n", szKeyName);
1265 if (dwGuidListIndex < ClassGuidListSize)
1267 if (szKeyName[0] == '{' && szKeyName[37] == '}')
1269 szKeyName[37] = 0;
1271 TRACE("Guid: %p\n", &szKeyName[1]);
1273 UuidFromStringW(&szKeyName[1],
1274 &ClassGuidList[dwGuidListIndex]);
1277 dwGuidListIndex++;
1281 RegCloseKey(hClassKey);
1284 if (lError != ERROR_SUCCESS)
1285 break;
1288 RegCloseKey(hClassesKey);
1290 if (RequiredSize != NULL)
1291 *RequiredSize = dwGuidListIndex;
1293 if (ClassGuidListSize < dwGuidListIndex)
1295 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1296 return FALSE;
1299 return TRUE;
1302 /***********************************************************************
1303 * SetupDiClassNameFromGuidA (SETUPAPI.@)
1305 BOOL WINAPI SetupDiClassNameFromGuidA(
1306 const GUID* ClassGuid,
1307 PSTR ClassName,
1308 DWORD ClassNameSize,
1309 PDWORD RequiredSize)
1311 return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
1312 ClassNameSize, RequiredSize,
1313 NULL, NULL);
1316 /***********************************************************************
1317 * SetupDiClassNameFromGuidW (SETUPAPI.@)
1319 BOOL WINAPI SetupDiClassNameFromGuidW(
1320 const GUID* ClassGuid,
1321 PWSTR ClassName,
1322 DWORD ClassNameSize,
1323 PDWORD RequiredSize)
1325 return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
1326 ClassNameSize, RequiredSize,
1327 NULL, NULL);
1330 /***********************************************************************
1331 * SetupDiClassNameFromGuidExA (SETUPAPI.@)
1333 BOOL WINAPI SetupDiClassNameFromGuidExA(
1334 const GUID* ClassGuid,
1335 PSTR ClassName,
1336 DWORD ClassNameSize,
1337 PDWORD RequiredSize,
1338 PCSTR MachineName,
1339 PVOID Reserved)
1341 WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
1342 LPWSTR MachineNameW = NULL;
1343 BOOL ret;
1345 if (MachineName)
1346 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1347 ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
1348 NULL, MachineNameW, Reserved);
1349 if (ret)
1351 int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
1352 ClassNameSize, NULL, NULL);
1354 if (!ClassNameSize && RequiredSize)
1355 *RequiredSize = len;
1357 MyFree(MachineNameW);
1358 return ret;
1361 /***********************************************************************
1362 * SetupDiClassNameFromGuidExW (SETUPAPI.@)
1364 BOOL WINAPI SetupDiClassNameFromGuidExW(
1365 const GUID* ClassGuid,
1366 PWSTR ClassName,
1367 DWORD ClassNameSize,
1368 PDWORD RequiredSize,
1369 PCWSTR MachineName,
1370 PVOID Reserved)
1372 HKEY hKey;
1373 DWORD dwLength;
1375 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
1376 KEY_ALL_ACCESS,
1377 DIOCR_INSTALLER,
1378 MachineName,
1379 Reserved);
1380 if (hKey == INVALID_HANDLE_VALUE)
1382 return FALSE;
1385 if (RequiredSize != NULL)
1387 dwLength = 0;
1388 if (RegQueryValueExW(hKey,
1389 Class,
1390 NULL,
1391 NULL,
1392 NULL,
1393 &dwLength))
1395 RegCloseKey(hKey);
1396 return FALSE;
1399 *RequiredSize = dwLength / sizeof(WCHAR);
1402 dwLength = ClassNameSize * sizeof(WCHAR);
1403 if (RegQueryValueExW(hKey,
1404 Class,
1405 NULL,
1406 NULL,
1407 (LPBYTE)ClassName,
1408 &dwLength))
1410 RegCloseKey(hKey);
1411 return FALSE;
1414 RegCloseKey(hKey);
1416 return TRUE;
1419 /***********************************************************************
1420 * SetupDiCreateDeviceInfoList (SETUPAPI.@)
1422 HDEVINFO WINAPI
1423 SetupDiCreateDeviceInfoList(const GUID *ClassGuid,
1424 HWND hwndParent)
1426 return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
1429 /***********************************************************************
1430 * SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
1432 HDEVINFO WINAPI
1433 SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
1434 HWND hwndParent,
1435 PCSTR MachineName,
1436 PVOID Reserved)
1438 LPWSTR MachineNameW = NULL;
1439 HDEVINFO hDevInfo;
1441 TRACE("\n");
1443 if (MachineName)
1445 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1446 if (MachineNameW == NULL)
1447 return INVALID_HANDLE_VALUE;
1450 hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
1451 MachineNameW, Reserved);
1453 MyFree(MachineNameW);
1455 return hDevInfo;
1458 /***********************************************************************
1459 * SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
1461 * Create an empty DeviceInfoSet list.
1463 * PARAMS
1464 * ClassGuid [I] if not NULL only devices with GUID ClassGuid are associated
1465 * with this list.
1466 * hwndParent [I] hwnd needed for interface related actions.
1467 * MachineName [I] name of machine to create empty DeviceInfoSet list, if NULL
1468 * local registry will be used.
1469 * Reserved [I] must be NULL
1471 * RETURNS
1472 * Success: empty list.
1473 * Failure: INVALID_HANDLE_VALUE.
1475 HDEVINFO WINAPI
1476 SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
1477 HWND hwndParent,
1478 PCWSTR MachineName,
1479 PVOID Reserved)
1481 struct DeviceInfoSet *list = NULL;
1482 DWORD size = sizeof(struct DeviceInfoSet);
1484 TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
1485 debugstr_w(MachineName), Reserved);
1487 if (MachineName && *MachineName)
1489 FIXME("remote support is not implemented\n");
1490 SetLastError(ERROR_INVALID_MACHINENAME);
1491 return INVALID_HANDLE_VALUE;
1494 if (Reserved != NULL)
1496 SetLastError(ERROR_INVALID_PARAMETER);
1497 return INVALID_HANDLE_VALUE;
1500 list = HeapAlloc(GetProcessHeap(), 0, size);
1501 if (!list)
1503 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1504 return INVALID_HANDLE_VALUE;
1507 list->magic = SETUP_DEVICE_INFO_SET_MAGIC;
1508 list->hwndParent = hwndParent;
1509 memcpy(&list->ClassGuid,
1510 ClassGuid ? ClassGuid : &GUID_NULL,
1511 sizeof(list->ClassGuid));
1512 list_init(&list->devices);
1514 return list;
1517 /***********************************************************************
1518 * SetupDiCreateDevRegKeyA (SETUPAPI.@)
1520 HKEY WINAPI SetupDiCreateDevRegKeyA(
1521 HDEVINFO DeviceInfoSet,
1522 PSP_DEVINFO_DATA DeviceInfoData,
1523 DWORD Scope,
1524 DWORD HwProfile,
1525 DWORD KeyType,
1526 HINF InfHandle,
1527 PCSTR InfSectionName)
1529 PWSTR InfSectionNameW = NULL;
1530 HKEY key;
1532 TRACE("%p %p %ld %ld %ld %p %s\n", DeviceInfoSet, DeviceInfoData, Scope,
1533 HwProfile, KeyType, InfHandle, debugstr_a(InfSectionName));
1535 if (InfHandle)
1537 if (!InfSectionName)
1539 SetLastError(ERROR_INVALID_PARAMETER);
1540 return INVALID_HANDLE_VALUE;
1542 else
1544 InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
1545 if (InfSectionNameW == NULL) return INVALID_HANDLE_VALUE;
1548 key = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, Scope,
1549 HwProfile, KeyType, InfHandle, InfSectionNameW);
1550 MyFree(InfSectionNameW);
1551 return key;
1554 /***********************************************************************
1555 * SetupDiCreateDevRegKeyW (SETUPAPI.@)
1557 HKEY WINAPI SetupDiCreateDevRegKeyW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD Scope,
1558 DWORD HwProfile, DWORD KeyType, HINF InfHandle, const WCHAR *InfSectionName)
1560 struct device *device;
1561 HKEY key = INVALID_HANDLE_VALUE;
1562 LONG l;
1564 TRACE("devinfo %p, device_data %p, scope %ld, profile %ld, type %ld, inf_handle %p, inf_section %s.\n",
1565 devinfo, device_data, Scope, HwProfile, KeyType, InfHandle, debugstr_w(InfSectionName));
1567 if (!(device = get_device(devinfo, device_data)))
1568 return INVALID_HANDLE_VALUE;
1570 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
1572 SetLastError(ERROR_INVALID_FLAGS);
1573 return INVALID_HANDLE_VALUE;
1575 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
1577 SetLastError(ERROR_INVALID_FLAGS);
1578 return INVALID_HANDLE_VALUE;
1580 if (device->phantom)
1582 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
1583 return INVALID_HANDLE_VALUE;
1585 if (Scope != DICS_FLAG_GLOBAL)
1586 FIXME("unimplemented for scope %ld\n", Scope);
1587 switch (KeyType)
1589 case DIREG_DEV:
1590 l = RegCreateKeyExW(device->key, DeviceParameters, 0, NULL, 0,
1591 KEY_READ | KEY_WRITE, NULL, &key, NULL);
1592 break;
1593 case DIREG_DRV:
1594 l = create_driver_key(device, &key);
1595 break;
1596 default:
1597 FIXME("Unhandled type %#lx.\n", KeyType);
1598 l = ERROR_CALL_NOT_IMPLEMENTED;
1600 if (InfHandle)
1601 SetupInstallFromInfSectionW(NULL, InfHandle, InfSectionName, SPINST_ALL,
1602 NULL, NULL, SP_COPY_NEWER_ONLY, NULL, NULL, devinfo, device_data);
1603 SetLastError(l);
1604 return l ? INVALID_HANDLE_VALUE : key;
1607 /***********************************************************************
1608 * SetupDiCreateDeviceInfoA (SETUPAPI.@)
1610 BOOL WINAPI SetupDiCreateDeviceInfoA(HDEVINFO DeviceInfoSet, const char *name,
1611 const GUID *ClassGuid, PCSTR DeviceDescription, HWND hwndParent, DWORD CreationFlags,
1612 PSP_DEVINFO_DATA DeviceInfoData)
1614 WCHAR nameW[MAX_DEVICE_ID_LEN];
1615 BOOL ret = FALSE;
1616 LPWSTR DeviceDescriptionW = NULL;
1618 if (!name || strlen(name) >= MAX_DEVICE_ID_LEN)
1620 SetLastError(ERROR_INVALID_DEVINST_NAME);
1621 return FALSE;
1624 MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, ARRAY_SIZE(nameW));
1626 if (DeviceDescription)
1628 DeviceDescriptionW = MultiByteToUnicode(DeviceDescription, CP_ACP);
1629 if (DeviceDescriptionW == NULL)
1630 return FALSE;
1633 ret = SetupDiCreateDeviceInfoW(DeviceInfoSet, nameW, ClassGuid, DeviceDescriptionW,
1634 hwndParent, CreationFlags, DeviceInfoData);
1636 MyFree(DeviceDescriptionW);
1638 return ret;
1641 /***********************************************************************
1642 * SetupDiCreateDeviceInfoW (SETUPAPI.@)
1644 BOOL WINAPI SetupDiCreateDeviceInfoW(HDEVINFO devinfo, const WCHAR *name, const GUID *class,
1645 const WCHAR *description, HWND parent, DWORD flags, SP_DEVINFO_DATA *device_data)
1647 WCHAR id[MAX_DEVICE_ID_LEN];
1648 struct DeviceInfoSet *set;
1649 HKEY enum_hkey;
1650 HKEY instance_hkey;
1651 struct device *device;
1652 LONG l;
1654 TRACE("devinfo %p, name %s, class %s, description %s, hwnd %p, flags %#lx, device_data %p.\n",
1655 devinfo, debugstr_w(name), debugstr_guid(class), debugstr_w(description),
1656 parent, flags, device_data);
1658 if (!name || lstrlenW(name) >= MAX_DEVICE_ID_LEN)
1660 SetLastError(ERROR_INVALID_DEVINST_NAME);
1661 return FALSE;
1664 if (!(set = get_device_set(devinfo)))
1665 return FALSE;
1667 if (!class)
1669 SetLastError(ERROR_INVALID_PARAMETER);
1670 return FALSE;
1673 if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) && !IsEqualGUID(class, &set->ClassGuid))
1675 SetLastError(ERROR_CLASS_MISMATCH);
1676 return FALSE;
1678 if ((flags & DICD_GENERATE_ID))
1680 static const WCHAR formatW[] = {'R','O','O','T','\\','%','s','\\','%','0','4','u',0};
1681 unsigned int instance_id;
1683 if (wcschr(name, '\\'))
1685 SetLastError(ERROR_INVALID_DEVINST_NAME);
1686 return FALSE;
1689 for (instance_id = 0; ; ++instance_id)
1691 if (swprintf(id, ARRAY_SIZE(id), formatW, name, instance_id) == -1)
1693 SetLastError(ERROR_INVALID_DEVINST_NAME);
1694 return FALSE;
1697 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL, &enum_hkey, NULL);
1698 if (!(l = RegOpenKeyExW(enum_hkey, id, 0, KEY_READ, &instance_hkey)))
1699 RegCloseKey(instance_hkey);
1700 if (l == ERROR_FILE_NOT_FOUND)
1701 break;
1702 RegCloseKey(enum_hkey);
1705 else
1707 /* Check if instance is already in registry */
1708 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL, &enum_hkey, NULL);
1709 if (!RegOpenKeyExW(enum_hkey, name, 0, KEY_READ, &instance_hkey))
1711 RegCloseKey(instance_hkey);
1712 RegCloseKey(enum_hkey);
1713 SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
1714 return FALSE;
1716 RegCloseKey(enum_hkey);
1718 /* Check if instance is already in set */
1719 lstrcpyW(id, name);
1720 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
1722 if (!lstrcmpiW(name, device->instanceId))
1724 SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
1725 return FALSE;
1730 if (!(device = create_device(set, class, id, TRUE)))
1731 return FALSE;
1733 if (description)
1735 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_DEVICEDESC,
1736 (const BYTE *)description, lstrlenW(description) * sizeof(WCHAR));
1739 if (device_data)
1741 if (device_data->cbSize != sizeof(SP_DEVINFO_DATA))
1743 SetLastError(ERROR_INVALID_USER_BUFFER);
1744 return FALSE;
1746 else
1747 copy_device_data(device_data, device);
1750 return TRUE;
1753 /***********************************************************************
1754 * SetupDiRegisterDeviceInfo (SETUPAPI.@)
1756 BOOL WINAPI SetupDiRegisterDeviceInfo(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD flags,
1757 PSP_DETSIG_CMPPROC compare_proc, void *context, SP_DEVINFO_DATA *duplicate_data)
1759 struct device *device;
1761 TRACE("devinfo %p, data %p, flags %#lx, compare_proc %p, context %p, duplicate_data %p.\n",
1762 devinfo, device_data, flags, compare_proc, context, duplicate_data);
1764 if (!(device = get_device(devinfo, device_data)))
1765 return FALSE;
1767 if (device->phantom)
1769 device->phantom = FALSE;
1770 RegDeleteValueW(device->key, Phantom);
1772 return TRUE;
1775 /***********************************************************************
1776 * SetupDiRemoveDevice (SETUPAPI.@)
1778 BOOL WINAPI SetupDiRemoveDevice(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
1780 SC_HANDLE manager = NULL, service = NULL;
1781 struct device *device;
1782 WCHAR *service_name = NULL;
1783 DWORD size;
1785 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
1787 if (!(device = get_device(devinfo, device_data)))
1788 return FALSE;
1790 if (!(manager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT)))
1791 return FALSE;
1793 if (!RegGetValueW(device->key, NULL, L"Service", RRF_RT_REG_SZ, NULL, NULL, &size))
1795 service_name = malloc(size);
1796 if (!RegGetValueW(device->key, NULL, L"Service", RRF_RT_REG_SZ, NULL, service_name, &size))
1797 service = OpenServiceW(manager, service_name, SERVICE_USER_DEFINED_CONTROL);
1800 remove_device(device);
1802 if (service)
1804 SERVICE_STATUS status;
1805 if (!ControlService(service, SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES, &status))
1806 ERR("Failed to control service %s, error %lu.\n", debugstr_w(service_name), GetLastError());
1807 CloseServiceHandle(service);
1809 CloseServiceHandle(manager);
1811 free(service_name);
1813 remove_all_device_ifaces(device);
1815 return TRUE;
1818 /***********************************************************************
1819 * SetupDiDeleteDeviceInfo (SETUPAPI.@)
1821 BOOL WINAPI SetupDiDeleteDeviceInfo(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
1823 struct device *device;
1825 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
1827 if (!(device = get_device(devinfo, device_data)))
1828 return FALSE;
1830 delete_device(device);
1832 return TRUE;
1835 /***********************************************************************
1836 * SetupDiRemoveDeviceInterface (SETUPAPI.@)
1838 BOOL WINAPI SetupDiRemoveDeviceInterface(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data)
1840 struct device_iface *iface;
1842 TRACE("devinfo %p, iface_data %p.\n", devinfo, iface_data);
1844 if (!(iface = get_device_iface(devinfo, iface_data)))
1845 return FALSE;
1847 remove_device_iface(iface);
1849 return TRUE;
1852 /***********************************************************************
1853 * SetupDiDeleteDeviceInterfaceData (SETUPAPI.@)
1855 BOOL WINAPI SetupDiDeleteDeviceInterfaceData(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data)
1857 struct device_iface *iface;
1859 TRACE("devinfo %p, iface_data %p.\n", devinfo, iface_data);
1861 if (!(iface = get_device_iface(devinfo, iface_data)))
1862 return FALSE;
1864 delete_device_iface(iface);
1866 return TRUE;
1869 /***********************************************************************
1870 * SetupDiEnumDeviceInfo (SETUPAPI.@)
1872 BOOL WINAPI DECLSPEC_HOTPATCH SetupDiEnumDeviceInfo(HDEVINFO devinfo, DWORD index, SP_DEVINFO_DATA *device_data)
1874 struct DeviceInfoSet *set;
1875 struct device *device;
1876 DWORD i = 0;
1878 TRACE("devinfo %p, index %ld, device_data %p\n", devinfo, index, device_data);
1880 if (!(set = get_device_set(devinfo)))
1881 return FALSE;
1883 if (!device_data)
1885 SetLastError(ERROR_INVALID_PARAMETER);
1886 return FALSE;
1889 if (device_data->cbSize != sizeof(SP_DEVINFO_DATA))
1891 SetLastError(ERROR_INVALID_USER_BUFFER);
1892 return FALSE;
1895 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
1897 if (i++ == index)
1899 copy_device_data(device_data, device);
1900 return TRUE;
1904 SetLastError(ERROR_NO_MORE_ITEMS);
1905 return FALSE;
1908 /***********************************************************************
1909 * SetupDiGetDeviceInstanceIdA (SETUPAPI.@)
1911 BOOL WINAPI SetupDiGetDeviceInstanceIdA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
1912 char *id, DWORD size, DWORD *needed)
1914 WCHAR idW[MAX_DEVICE_ID_LEN];
1916 TRACE("devinfo %p, device_data %p, id %p, size %ld, needed %p.\n",
1917 devinfo, device_data, id, size, needed);
1919 if (!SetupDiGetDeviceInstanceIdW(devinfo, device_data, idW, ARRAY_SIZE(idW), NULL))
1920 return FALSE;
1922 if (needed)
1923 *needed = WideCharToMultiByte(CP_ACP, 0, idW, -1, NULL, 0, NULL, NULL);
1925 if (size && WideCharToMultiByte(CP_ACP, 0, idW, -1, id, size, NULL, NULL))
1926 return TRUE;
1928 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1929 return FALSE;
1932 /***********************************************************************
1933 * SetupDiGetDeviceInstanceIdW (SETUPAPI.@)
1935 BOOL WINAPI SetupDiGetDeviceInstanceIdW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
1936 WCHAR *DeviceInstanceId, DWORD DeviceInstanceIdSize, DWORD *RequiredSize)
1938 struct device *device;
1940 TRACE("devinfo %p, device_data %p, DeviceInstanceId %p, DeviceInstanceIdSize %ld, RequiredSize %p.\n",
1941 devinfo, device_data, DeviceInstanceId, DeviceInstanceIdSize, RequiredSize);
1943 if (!(device = get_device(devinfo, device_data)))
1944 return FALSE;
1946 TRACE("instance ID: %s\n", debugstr_w(device->instanceId));
1947 if (DeviceInstanceIdSize < lstrlenW(device->instanceId) + 1)
1949 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1950 if (RequiredSize)
1951 *RequiredSize = lstrlenW(device->instanceId) + 1;
1952 return FALSE;
1954 lstrcpyW(DeviceInstanceId, device->instanceId);
1955 if (RequiredSize)
1956 *RequiredSize = lstrlenW(device->instanceId) + 1;
1957 return TRUE;
1960 /***********************************************************************
1961 * SetupDiGetActualSectionToInstallExA (SETUPAPI.@)
1963 BOOL WINAPI SetupDiGetActualSectionToInstallExA(HINF hinf, const char *section, SP_ALTPLATFORM_INFO *altplatform,
1964 char *section_ext, DWORD size, DWORD *needed, char **extptr, void *reserved)
1966 WCHAR sectionW[LINE_LEN], section_extW[LINE_LEN], *extptrW;
1967 BOOL ret;
1969 MultiByteToWideChar(CP_ACP, 0, section, -1, sectionW, ARRAY_SIZE(sectionW));
1971 ret = SetupDiGetActualSectionToInstallExW(hinf, sectionW, altplatform, section_extW,
1972 ARRAY_SIZE(section_extW), NULL, &extptrW, reserved);
1973 if (ret)
1975 if (needed)
1976 *needed = WideCharToMultiByte(CP_ACP, 0, section_extW, -1, NULL, 0, NULL, NULL);
1978 if (section_ext)
1979 ret = !!WideCharToMultiByte(CP_ACP, 0, section_extW, -1, section_ext, size, NULL, NULL);
1981 if (extptr)
1983 if (extptrW)
1984 *extptr = section_ext + WideCharToMultiByte(CP_ACP, 0, section_extW,
1985 extptrW - section_extW, NULL, 0, NULL, NULL);
1986 else
1987 *extptr = NULL;
1991 return ret;
1994 /***********************************************************************
1995 * SetupDiGetActualSectionToInstallA (SETUPAPI.@)
1997 BOOL WINAPI SetupDiGetActualSectionToInstallA(HINF hinf, const char *section, char *section_ext,
1998 DWORD size, DWORD *needed, char **extptr)
2000 return SetupDiGetActualSectionToInstallExA(hinf, section, NULL, section_ext, size,
2001 needed, extptr, NULL);
2004 /***********************************************************************
2005 * SetupDiGetActualSectionToInstallExW (SETUPAPI.@)
2007 BOOL WINAPI SetupDiGetActualSectionToInstallExW(HINF hinf, const WCHAR *section, SP_ALTPLATFORM_INFO *altplatform,
2008 WCHAR *section_ext, DWORD size, DWORD *needed, WCHAR **extptr, void *reserved)
2010 WCHAR buffer[MAX_PATH];
2011 DWORD len;
2012 DWORD full_len;
2013 LONG line_count = -1;
2015 TRACE("hinf %p, section %s, altplatform %p, ext %p, size %ld, needed %p, extptr %p, reserved %p.\n",
2016 hinf, debugstr_w(section), altplatform, section_ext, size, needed, extptr, reserved);
2018 if (altplatform)
2019 FIXME("SP_ALTPLATFORM_INFO unsupported\n");
2021 lstrcpyW(buffer, section);
2022 len = lstrlenW(buffer);
2024 if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
2026 /* Test section name with '.NTx86' extension */
2027 lstrcpyW(&buffer[len], NtPlatformExtension);
2028 line_count = SetupGetLineCountW(hinf, buffer);
2030 if (line_count == -1)
2032 /* Test section name with '.NT' extension */
2033 lstrcpyW(&buffer[len], NtExtension);
2034 line_count = SetupGetLineCountW(hinf, buffer);
2037 else
2039 /* Test section name with '.Win' extension */
2040 lstrcpyW(&buffer[len], WinExtension);
2041 line_count = SetupGetLineCountW(hinf, buffer);
2044 if (line_count == -1)
2045 buffer[len] = 0;
2047 full_len = lstrlenW(buffer);
2049 if (section_ext != NULL && size != 0)
2051 if (size < (full_len + 1))
2053 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2054 return FALSE;
2057 lstrcpyW(section_ext, buffer);
2058 if (extptr != NULL)
2060 *extptr = (len == full_len) ? NULL : &section_ext[len];
2064 if (needed != NULL)
2066 *needed = full_len + 1;
2069 return TRUE;
2072 /***********************************************************************
2073 * SetupDiGetActualSectionToInstallW (SETUPAPI.@)
2075 BOOL WINAPI SetupDiGetActualSectionToInstallW(HINF hinf, const WCHAR *section, WCHAR *section_ext,
2076 DWORD size, DWORD *needed, WCHAR **extptr)
2078 return SetupDiGetActualSectionToInstallExW(hinf, section, NULL, section_ext, size,
2079 needed, extptr, NULL);
2082 /***********************************************************************
2083 * SetupDiGetClassDescriptionA (SETUPAPI.@)
2085 BOOL WINAPI SetupDiGetClassDescriptionA(
2086 const GUID* ClassGuid,
2087 PSTR ClassDescription,
2088 DWORD ClassDescriptionSize,
2089 PDWORD RequiredSize)
2091 return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
2092 ClassDescriptionSize,
2093 RequiredSize, NULL, NULL);
2096 /***********************************************************************
2097 * SetupDiGetClassDescriptionW (SETUPAPI.@)
2099 BOOL WINAPI SetupDiGetClassDescriptionW(
2100 const GUID* ClassGuid,
2101 PWSTR ClassDescription,
2102 DWORD ClassDescriptionSize,
2103 PDWORD RequiredSize)
2105 return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
2106 ClassDescriptionSize,
2107 RequiredSize, NULL, NULL);
2110 /***********************************************************************
2111 * SetupDiGetClassDescriptionExA (SETUPAPI.@)
2113 BOOL WINAPI SetupDiGetClassDescriptionExA(
2114 const GUID* ClassGuid,
2115 PSTR ClassDescription,
2116 DWORD ClassDescriptionSize,
2117 PDWORD RequiredSize,
2118 PCSTR MachineName,
2119 PVOID Reserved)
2121 HKEY hKey;
2122 DWORD dwLength;
2123 BOOL ret;
2125 hKey = SetupDiOpenClassRegKeyExA(ClassGuid,
2126 KEY_ALL_ACCESS,
2127 DIOCR_INSTALLER,
2128 MachineName,
2129 Reserved);
2130 if (hKey == INVALID_HANDLE_VALUE)
2132 WARN("SetupDiOpenClassRegKeyExA() failed (Error %lu)\n", GetLastError());
2133 return FALSE;
2136 dwLength = ClassDescriptionSize;
2137 ret = !RegQueryValueExA( hKey, NULL, NULL, NULL,
2138 (LPBYTE)ClassDescription, &dwLength );
2139 if (RequiredSize) *RequiredSize = dwLength;
2140 RegCloseKey(hKey);
2141 return ret;
2144 /***********************************************************************
2145 * SetupDiGetClassDescriptionExW (SETUPAPI.@)
2147 BOOL WINAPI SetupDiGetClassDescriptionExW(
2148 const GUID* ClassGuid,
2149 PWSTR ClassDescription,
2150 DWORD ClassDescriptionSize,
2151 PDWORD RequiredSize,
2152 PCWSTR MachineName,
2153 PVOID Reserved)
2155 HKEY hKey;
2156 DWORD dwLength;
2157 BOOL ret;
2159 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
2160 KEY_ALL_ACCESS,
2161 DIOCR_INSTALLER,
2162 MachineName,
2163 Reserved);
2164 if (hKey == INVALID_HANDLE_VALUE)
2166 WARN("SetupDiOpenClassRegKeyExW() failed (Error %lu)\n", GetLastError());
2167 return FALSE;
2170 dwLength = ClassDescriptionSize * sizeof(WCHAR);
2171 ret = !RegQueryValueExW( hKey, NULL, NULL, NULL,
2172 (LPBYTE)ClassDescription, &dwLength );
2173 if (RequiredSize) *RequiredSize = dwLength / sizeof(WCHAR);
2174 RegCloseKey(hKey);
2175 return ret;
2178 /***********************************************************************
2179 * SetupDiGetClassDevsA (SETUPAPI.@)
2181 HDEVINFO WINAPI SetupDiGetClassDevsA(const GUID *class, LPCSTR enumstr, HWND parent, DWORD flags)
2183 HDEVINFO ret;
2184 LPWSTR enumstrW = NULL;
2186 if (enumstr)
2188 int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
2189 enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2190 if (!enumstrW)
2192 ret = INVALID_HANDLE_VALUE;
2193 goto end;
2195 MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
2197 ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, NULL, NULL,
2198 NULL);
2199 HeapFree(GetProcessHeap(), 0, enumstrW);
2201 end:
2202 return ret;
2205 /***********************************************************************
2206 * SetupDiGetClassDevsExA (SETUPAPI.@)
2208 HDEVINFO WINAPI SetupDiGetClassDevsExA(
2209 const GUID *class,
2210 PCSTR enumstr,
2211 HWND parent,
2212 DWORD flags,
2213 HDEVINFO deviceset,
2214 PCSTR machine,
2215 PVOID reserved)
2217 HDEVINFO ret;
2218 LPWSTR enumstrW = NULL, machineW = NULL;
2220 if (enumstr)
2222 int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
2223 enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2224 if (!enumstrW)
2226 ret = INVALID_HANDLE_VALUE;
2227 goto end;
2229 MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
2231 if (machine)
2233 int len = MultiByteToWideChar(CP_ACP, 0, machine, -1, NULL, 0);
2234 machineW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2235 if (!machineW)
2237 HeapFree(GetProcessHeap(), 0, enumstrW);
2238 ret = INVALID_HANDLE_VALUE;
2239 goto end;
2241 MultiByteToWideChar(CP_ACP, 0, machine, -1, machineW, len);
2243 ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset,
2244 machineW, reserved);
2245 HeapFree(GetProcessHeap(), 0, enumstrW);
2246 HeapFree(GetProcessHeap(), 0, machineW);
2248 end:
2249 return ret;
2252 static void SETUPDI_AddDeviceInterfaces(struct device *device, HKEY key,
2253 const GUID *guid, DWORD flags)
2255 DWORD i, len;
2256 WCHAR subKeyName[MAX_PATH];
2257 LONG l = ERROR_SUCCESS;
2259 for (i = 0; !l; i++)
2261 len = ARRAY_SIZE(subKeyName);
2262 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2263 if (!l)
2265 HKEY subKey;
2266 struct device_iface *iface;
2268 if (*subKeyName == '#')
2270 /* The subkey name is the reference string, with a '#' prepended */
2271 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2272 if (!l)
2274 WCHAR symbolicLink[MAX_PATH];
2275 DWORD dataType;
2277 if (!(flags & DIGCF_PRESENT) || is_linked(subKey))
2279 iface = SETUPDI_CreateDeviceInterface(device, guid, subKeyName + 1);
2281 len = sizeof(symbolicLink);
2282 l = RegQueryValueExW(subKey, SymbolicLink, NULL, &dataType,
2283 (BYTE *)symbolicLink, &len);
2284 if (!l && dataType == REG_SZ)
2285 SETUPDI_SetInterfaceSymbolicLink(iface, symbolicLink);
2287 RegCloseKey(subKey);
2290 /* Allow enumeration to continue */
2291 l = ERROR_SUCCESS;
2294 /* FIXME: find and add all the device's interfaces to the device */
2297 static void SETUPDI_EnumerateMatchingInterfaces(HDEVINFO DeviceInfoSet,
2298 HKEY key, const GUID *guid, const WCHAR *enumstr, DWORD flags)
2300 struct DeviceInfoSet *set = DeviceInfoSet;
2301 DWORD i, len;
2302 WCHAR subKeyName[MAX_PATH];
2303 LONG l;
2304 HKEY enumKey = INVALID_HANDLE_VALUE;
2306 TRACE("%s\n", debugstr_w(enumstr));
2308 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL,
2309 &enumKey, NULL);
2310 for (i = 0; !l; i++)
2312 len = ARRAY_SIZE(subKeyName);
2313 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2314 if (!l)
2316 HKEY subKey;
2318 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2319 if (!l)
2321 WCHAR deviceInst[MAX_PATH * 3];
2322 DWORD dataType;
2324 len = sizeof(deviceInst);
2325 l = RegQueryValueExW(subKey, DeviceInstance, NULL, &dataType,
2326 (BYTE *)deviceInst, &len);
2327 if (!l && dataType == REG_SZ)
2329 TRACE("found instance ID %s\n", debugstr_w(deviceInst));
2330 if (!enumstr || !lstrcmpiW(enumstr, deviceInst))
2332 HKEY deviceKey;
2334 l = RegOpenKeyExW(enumKey, deviceInst, 0, KEY_READ,
2335 &deviceKey);
2336 if (!l)
2338 WCHAR deviceClassStr[40];
2340 len = sizeof(deviceClassStr);
2341 l = RegQueryValueExW(deviceKey, ClassGUID, NULL,
2342 &dataType, (BYTE *)deviceClassStr, &len);
2343 if (!l && dataType == REG_SZ &&
2344 deviceClassStr[0] == '{' &&
2345 deviceClassStr[37] == '}')
2347 GUID deviceClass;
2348 struct device *device;
2350 deviceClassStr[37] = 0;
2351 UuidFromStringW(&deviceClassStr[1],
2352 &deviceClass);
2353 if ((device = create_device(set, &deviceClass, deviceInst, FALSE)))
2354 SETUPDI_AddDeviceInterfaces(device, subKey, guid, flags);
2356 RegCloseKey(deviceKey);
2360 RegCloseKey(subKey);
2362 /* Allow enumeration to continue */
2363 l = ERROR_SUCCESS;
2366 if (enumKey != INVALID_HANDLE_VALUE)
2367 RegCloseKey(enumKey);
2370 static void SETUPDI_EnumerateInterfaces(HDEVINFO DeviceInfoSet,
2371 const GUID *guid, LPCWSTR enumstr, DWORD flags)
2373 HKEY interfacesKey = SetupDiOpenClassRegKeyExW(guid, KEY_READ,
2374 DIOCR_INTERFACE, NULL, NULL);
2376 TRACE("%p, %s, %s, %08lx\n", DeviceInfoSet, debugstr_guid(guid),
2377 debugstr_w(enumstr), flags);
2379 if (interfacesKey != INVALID_HANDLE_VALUE)
2381 if (flags & DIGCF_ALLCLASSES)
2383 DWORD i, len;
2384 WCHAR interfaceGuidStr[40];
2385 LONG l = ERROR_SUCCESS;
2387 for (i = 0; !l; i++)
2389 len = ARRAY_SIZE(interfaceGuidStr);
2390 l = RegEnumKeyExW(interfacesKey, i, interfaceGuidStr, &len,
2391 NULL, NULL, NULL, NULL);
2392 if (!l)
2394 if (interfaceGuidStr[0] == '{' &&
2395 interfaceGuidStr[37] == '}')
2397 HKEY interfaceKey;
2398 GUID interfaceGuid;
2400 interfaceGuidStr[37] = 0;
2401 UuidFromStringW(&interfaceGuidStr[1], &interfaceGuid);
2402 interfaceGuidStr[37] = '}';
2403 interfaceGuidStr[38] = 0;
2404 l = RegOpenKeyExW(interfacesKey, interfaceGuidStr, 0,
2405 KEY_READ, &interfaceKey);
2406 if (!l)
2408 SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
2409 interfaceKey, &interfaceGuid, enumstr, flags);
2410 RegCloseKey(interfaceKey);
2416 else
2418 /* In this case, SetupDiOpenClassRegKeyExW opened the specific
2419 * interface's key, so just pass that long
2421 SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
2422 interfacesKey, guid, enumstr, flags);
2424 RegCloseKey(interfacesKey);
2428 static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set,
2429 LPCWSTR enumerator, LPCWSTR deviceName, HKEY deviceKey,
2430 const GUID *class, DWORD flags)
2432 WCHAR id[MAX_DEVICE_ID_LEN];
2433 DWORD i, len;
2434 WCHAR deviceInstance[MAX_PATH];
2435 LONG l = ERROR_SUCCESS;
2437 TRACE("%s %s\n", debugstr_w(enumerator), debugstr_w(deviceName));
2439 for (i = 0; !l; i++)
2441 len = ARRAY_SIZE(deviceInstance);
2442 l = RegEnumKeyExW(deviceKey, i, deviceInstance, &len, NULL, NULL, NULL,
2443 NULL);
2444 if (!l)
2446 HKEY subKey;
2448 l = RegOpenKeyExW(deviceKey, deviceInstance, 0, KEY_READ, &subKey);
2449 if (!l)
2451 WCHAR classGuid[40];
2452 DWORD dataType;
2454 len = sizeof(classGuid);
2455 l = RegQueryValueExW(subKey, ClassGUID, NULL, &dataType,
2456 (BYTE *)classGuid, &len);
2457 if (!l && dataType == REG_SZ)
2459 if (classGuid[0] == '{' && classGuid[37] == '}')
2461 GUID deviceClass;
2463 classGuid[37] = 0;
2464 UuidFromStringW(&classGuid[1], &deviceClass);
2465 if ((flags & DIGCF_ALLCLASSES) ||
2466 IsEqualGUID(class, &deviceClass))
2468 static const WCHAR fmt[] =
2469 {'%','s','\\','%','s','\\','%','s',0};
2471 if (swprintf(id, ARRAY_SIZE(id), fmt, enumerator,
2472 deviceName, deviceInstance) != -1)
2474 create_device(set, &deviceClass, id, FALSE);
2479 RegCloseKey(subKey);
2481 /* Allow enumeration to continue */
2482 l = ERROR_SUCCESS;
2487 static void SETUPDI_EnumerateMatchingDevices(HDEVINFO DeviceInfoSet,
2488 LPCWSTR parent, HKEY key, const GUID *class, DWORD flags)
2490 struct DeviceInfoSet *set = DeviceInfoSet;
2491 DWORD i, len;
2492 WCHAR subKeyName[MAX_PATH];
2493 LONG l = ERROR_SUCCESS;
2495 TRACE("%s\n", debugstr_w(parent));
2497 for (i = 0; !l; i++)
2499 len = ARRAY_SIZE(subKeyName);
2500 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2501 if (!l)
2503 HKEY subKey;
2505 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2506 if (!l)
2508 TRACE("%s\n", debugstr_w(subKeyName));
2509 SETUPDI_EnumerateMatchingDeviceInstances(set, parent,
2510 subKeyName, subKey, class, flags);
2511 RegCloseKey(subKey);
2513 /* Allow enumeration to continue */
2514 l = ERROR_SUCCESS;
2519 static void SETUPDI_EnumerateDevices(HDEVINFO DeviceInfoSet, const GUID *class,
2520 LPCWSTR enumstr, DWORD flags)
2522 HKEY enumKey;
2523 LONG l;
2525 TRACE("%p, %s, %s, %08lx\n", DeviceInfoSet, debugstr_guid(class),
2526 debugstr_w(enumstr), flags);
2528 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL,
2529 &enumKey, NULL);
2530 if (enumKey != INVALID_HANDLE_VALUE)
2532 if (enumstr)
2534 HKEY enumStrKey;
2536 l = RegOpenKeyExW(enumKey, enumstr, 0, KEY_READ,
2537 &enumStrKey);
2538 if (!l)
2540 WCHAR *bus, *device;
2542 if (!wcschr(enumstr, '\\'))
2544 SETUPDI_EnumerateMatchingDevices(DeviceInfoSet, enumstr, enumStrKey, class, flags);
2546 else if ((bus = strdupW(enumstr)))
2548 device = wcschr(bus, '\\');
2549 *device++ = 0;
2551 SETUPDI_EnumerateMatchingDeviceInstances(DeviceInfoSet, bus, device, enumStrKey, class, flags);
2552 HeapFree(GetProcessHeap(), 0, bus);
2555 RegCloseKey(enumStrKey);
2558 else
2560 DWORD i, len;
2561 WCHAR subKeyName[MAX_PATH];
2563 l = ERROR_SUCCESS;
2564 for (i = 0; !l; i++)
2566 len = ARRAY_SIZE(subKeyName);
2567 l = RegEnumKeyExW(enumKey, i, subKeyName, &len, NULL,
2568 NULL, NULL, NULL);
2569 if (!l)
2571 HKEY subKey;
2573 l = RegOpenKeyExW(enumKey, subKeyName, 0, KEY_READ,
2574 &subKey);
2575 if (!l)
2577 SETUPDI_EnumerateMatchingDevices(DeviceInfoSet,
2578 subKeyName, subKey, class, flags);
2579 RegCloseKey(subKey);
2581 /* Allow enumeration to continue */
2582 l = ERROR_SUCCESS;
2586 RegCloseKey(enumKey);
2590 /***********************************************************************
2591 * SetupDiGetClassDevsW (SETUPAPI.@)
2593 HDEVINFO WINAPI SetupDiGetClassDevsW(const GUID *class, LPCWSTR enumstr, HWND parent, DWORD flags)
2595 return SetupDiGetClassDevsExW(class, enumstr, parent, flags, NULL, NULL,
2596 NULL);
2599 /***********************************************************************
2600 * SetupDiGetClassDevsExW (SETUPAPI.@)
2602 HDEVINFO WINAPI SetupDiGetClassDevsExW(const GUID *class, PCWSTR enumstr, HWND parent, DWORD flags,
2603 HDEVINFO deviceset, PCWSTR machine, void *reserved)
2605 static const DWORD unsupportedFlags = DIGCF_DEFAULT | DIGCF_PROFILE;
2606 HDEVINFO set;
2608 TRACE("%s %s %p 0x%08lx %p %s %p\n", debugstr_guid(class),
2609 debugstr_w(enumstr), parent, flags, deviceset, debugstr_w(machine),
2610 reserved);
2612 if (!(flags & DIGCF_ALLCLASSES) && !class)
2614 SetLastError(ERROR_INVALID_PARAMETER);
2615 return INVALID_HANDLE_VALUE;
2617 if (flags & DIGCF_ALLCLASSES)
2618 class = NULL;
2620 if (flags & unsupportedFlags)
2621 WARN("unsupported flags %08lx\n", flags & unsupportedFlags);
2622 if (deviceset)
2623 set = deviceset;
2624 else
2625 set = SetupDiCreateDeviceInfoListExW((flags & DIGCF_DEVICEINTERFACE) ? NULL : class, parent, machine, reserved);
2626 if (set != INVALID_HANDLE_VALUE)
2628 if (machine && *machine)
2629 FIXME("%s: unimplemented for remote machines\n",
2630 debugstr_w(machine));
2631 else if (flags & DIGCF_DEVICEINTERFACE)
2632 SETUPDI_EnumerateInterfaces(set, class, enumstr, flags);
2633 else
2634 SETUPDI_EnumerateDevices(set, class, enumstr, flags);
2636 return set;
2639 /***********************************************************************
2640 * SetupDiGetDeviceInfoListDetailA (SETUPAPI.@)
2642 BOOL WINAPI SetupDiGetDeviceInfoListDetailA(HDEVINFO devinfo, SP_DEVINFO_LIST_DETAIL_DATA_A *DevInfoData)
2644 struct DeviceInfoSet *set;
2646 TRACE("devinfo %p, detail_data %p.\n", devinfo, DevInfoData);
2648 if (!(set = get_device_set(devinfo)))
2649 return FALSE;
2651 if (!DevInfoData ||
2652 DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_A))
2654 SetLastError(ERROR_INVALID_PARAMETER);
2655 return FALSE;
2657 DevInfoData->ClassGuid = set->ClassGuid;
2658 DevInfoData->RemoteMachineHandle = NULL;
2659 DevInfoData->RemoteMachineName[0] = '\0';
2660 return TRUE;
2663 /***********************************************************************
2664 * SetupDiGetDeviceInfoListDetailW (SETUPAPI.@)
2666 BOOL WINAPI SetupDiGetDeviceInfoListDetailW(HDEVINFO devinfo, SP_DEVINFO_LIST_DETAIL_DATA_W *DevInfoData)
2668 struct DeviceInfoSet *set;
2670 TRACE("devinfo %p, detail_data %p.\n", devinfo, DevInfoData);
2672 if (!(set = get_device_set(devinfo)))
2673 return FALSE;
2675 if (!DevInfoData ||
2676 DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W))
2678 SetLastError(ERROR_INVALID_PARAMETER);
2679 return FALSE;
2681 DevInfoData->ClassGuid = set->ClassGuid;
2682 DevInfoData->RemoteMachineHandle = NULL;
2683 DevInfoData->RemoteMachineName[0] = '\0';
2684 return TRUE;
2687 /***********************************************************************
2688 * SetupDiCreateDeviceInterfaceA (SETUPAPI.@)
2690 BOOL WINAPI SetupDiCreateDeviceInterfaceA(
2691 HDEVINFO DeviceInfoSet,
2692 PSP_DEVINFO_DATA DeviceInfoData,
2693 const GUID *InterfaceClassGuid,
2694 PCSTR ReferenceString,
2695 DWORD CreationFlags,
2696 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2698 BOOL ret;
2699 LPWSTR ReferenceStringW = NULL;
2701 TRACE("%p %p %s %s %08lx %p\n", DeviceInfoSet, DeviceInfoData,
2702 debugstr_guid(InterfaceClassGuid), debugstr_a(ReferenceString),
2703 CreationFlags, DeviceInterfaceData);
2705 if (ReferenceString)
2707 ReferenceStringW = MultiByteToUnicode(ReferenceString, CP_ACP);
2708 if (ReferenceStringW == NULL) return FALSE;
2711 ret = SetupDiCreateDeviceInterfaceW(DeviceInfoSet, DeviceInfoData,
2712 InterfaceClassGuid, ReferenceStringW, CreationFlags,
2713 DeviceInterfaceData);
2715 MyFree(ReferenceStringW);
2717 return ret;
2720 /***********************************************************************
2721 * SetupDiCreateDeviceInterfaceW (SETUPAPI.@)
2723 BOOL WINAPI SetupDiCreateDeviceInterfaceW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
2724 const GUID *class, const WCHAR *refstr, DWORD flags, SP_DEVICE_INTERFACE_DATA *iface_data)
2726 struct device *device;
2727 struct device_iface *iface;
2729 TRACE("devinfo %p, device_data %p, class %s, refstr %s, flags %#lx, iface_data %p.\n",
2730 devinfo, device_data, debugstr_guid(class), debugstr_w(refstr), flags, iface_data);
2732 if (!(device = get_device(devinfo, device_data)))
2733 return FALSE;
2735 if (!class)
2737 SetLastError(ERROR_INVALID_USER_BUFFER);
2738 return FALSE;
2741 if (!(iface = SETUPDI_CreateDeviceInterface(device, class, refstr)))
2742 return FALSE;
2744 if (iface_data)
2746 if (iface_data->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2748 SetLastError(ERROR_INVALID_USER_BUFFER);
2749 return FALSE;
2752 copy_device_iface_data(iface_data, iface);
2754 return TRUE;
2757 /***********************************************************************
2758 * SetupDiCreateDeviceInterfaceRegKeyA (SETUPAPI.@)
2760 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyA(
2761 HDEVINFO DeviceInfoSet,
2762 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2763 DWORD Reserved,
2764 REGSAM samDesired,
2765 HINF InfHandle,
2766 PCSTR InfSectionName)
2768 HKEY key;
2769 PWSTR InfSectionNameW = NULL;
2771 TRACE("%p %p %ld %08lx %p %p\n", DeviceInfoSet, DeviceInterfaceData, Reserved,
2772 samDesired, InfHandle, InfSectionName);
2773 if (InfHandle)
2775 if (!InfSectionName)
2777 SetLastError(ERROR_INVALID_PARAMETER);
2778 return INVALID_HANDLE_VALUE;
2780 InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
2781 if (!InfSectionNameW)
2782 return INVALID_HANDLE_VALUE;
2784 key = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet,
2785 DeviceInterfaceData, Reserved, samDesired, InfHandle,
2786 InfSectionNameW);
2787 MyFree(InfSectionNameW);
2788 return key;
2791 static LONG create_iface_key(const struct device_iface *iface, REGSAM access, HKEY *key)
2793 return RegCreateKeyExW(iface->refstr_key, DeviceParameters, 0, NULL, 0, access, NULL, key, NULL);
2796 /***********************************************************************
2797 * SetupDiCreateDeviceInterfaceRegKeyW (SETUPAPI.@)
2799 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyW(HDEVINFO devinfo,
2800 SP_DEVICE_INTERFACE_DATA *iface_data, DWORD reserved, REGSAM access,
2801 HINF hinf, const WCHAR *section)
2803 struct device_iface *iface;
2804 HKEY params_key;
2805 LONG ret;
2807 TRACE("devinfo %p, iface_data %p, reserved %ld, access %#lx, hinf %p, section %s.\n",
2808 devinfo, iface_data, reserved, access, hinf, debugstr_w(section));
2810 if (!(iface = get_device_iface(devinfo, iface_data)))
2811 return INVALID_HANDLE_VALUE;
2813 if (hinf && !section)
2815 SetLastError(ERROR_INVALID_PARAMETER);
2816 return INVALID_HANDLE_VALUE;
2819 ret = create_iface_key(iface, access, &params_key);
2820 if (ret)
2822 SetLastError(ret);
2823 return INVALID_HANDLE_VALUE;
2826 return params_key;
2829 /***********************************************************************
2830 * SetupDiDeleteDeviceInterfaceRegKey (SETUPAPI.@)
2832 BOOL WINAPI SetupDiDeleteDeviceInterfaceRegKey(HDEVINFO devinfo,
2833 SP_DEVICE_INTERFACE_DATA *iface_data, DWORD reserved)
2835 struct device_iface *iface;
2836 LONG ret;
2838 TRACE("devinfo %p, iface_data %p, reserved %ld.\n", devinfo, iface_data, reserved);
2840 if (!(iface = get_device_iface(devinfo, iface_data)))
2841 return FALSE;
2843 ret = RegDeleteKeyW(iface->refstr_key, DeviceParameters);
2844 if (ret)
2846 SetLastError(ret);
2847 return FALSE;
2850 return TRUE;
2853 /***********************************************************************
2854 * SetupDiEnumDeviceInterfaces (SETUPAPI.@)
2856 * PARAMS
2857 * DeviceInfoSet [I] Set of devices from which to enumerate
2858 * interfaces
2859 * DeviceInfoData [I] (Optional) If specified, a specific device
2860 * instance from which to enumerate interfaces.
2861 * If it isn't specified, all interfaces for all
2862 * devices in the set are enumerated.
2863 * InterfaceClassGuid [I] The interface class to enumerate.
2864 * MemberIndex [I] An index of the interface instance to enumerate.
2865 * A caller should start with MemberIndex set to 0,
2866 * and continue until the function fails with
2867 * ERROR_NO_MORE_ITEMS.
2868 * DeviceInterfaceData [I/O] Returns an enumerated interface. Its cbSize
2869 * member must be set to
2870 * sizeof(SP_DEVICE_INTERFACE_DATA).
2872 * RETURNS
2873 * Success: non-zero value.
2874 * Failure: FALSE. Call GetLastError() for more info.
2876 BOOL WINAPI SetupDiEnumDeviceInterfaces(HDEVINFO devinfo,
2877 SP_DEVINFO_DATA *device_data, const GUID *class, DWORD index,
2878 SP_DEVICE_INTERFACE_DATA *iface_data)
2880 struct DeviceInfoSet *set;
2881 struct device *device;
2882 struct device_iface *iface;
2883 DWORD i = 0;
2885 TRACE("devinfo %p, device_data %p, class %s, index %lu, iface_data %p.\n",
2886 devinfo, device_data, debugstr_guid(class), index, iface_data);
2888 if (!iface_data || iface_data->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2890 SetLastError(ERROR_INVALID_PARAMETER);
2891 return FALSE;
2894 /* In case application fails to check return value, clear output */
2895 memset(iface_data, 0, sizeof(*iface_data));
2896 iface_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
2898 if (device_data)
2900 if (!(device = get_device(devinfo, device_data)))
2901 return FALSE;
2903 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
2905 if (IsEqualGUID(&iface->class, class))
2907 if (i == index)
2909 copy_device_iface_data(iface_data, iface);
2910 return TRUE;
2912 i++;
2916 else
2918 if (!(set = get_device_set(devinfo)))
2919 return FALSE;
2921 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
2923 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
2925 if (IsEqualGUID(&iface->class, class))
2927 if (i == index)
2929 copy_device_iface_data(iface_data, iface);
2930 return TRUE;
2932 i++;
2938 SetLastError(ERROR_NO_MORE_ITEMS);
2939 return FALSE;
2942 /***********************************************************************
2943 * SetupDiDestroyDeviceInfoList (SETUPAPI.@)
2945 * Destroy a DeviceInfoList and free all used memory of the list.
2947 * PARAMS
2948 * devinfo [I] DeviceInfoList pointer to list to destroy
2950 * RETURNS
2951 * Success: non zero value.
2952 * Failure: zero value.
2954 BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
2956 struct DeviceInfoSet *set;
2957 struct device *device, *device2;
2959 TRACE("devinfo %p.\n", devinfo);
2961 if (!(set = get_device_set(devinfo)))
2962 return FALSE;
2964 LIST_FOR_EACH_ENTRY_SAFE(device, device2, &set->devices, struct device, entry)
2966 delete_device(device);
2968 heap_free(set);
2970 SetLastError(ERROR_SUCCESS);
2971 return TRUE;
2974 /***********************************************************************
2975 * SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
2977 BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data,
2978 SP_DEVICE_INTERFACE_DETAIL_DATA_A *DeviceInterfaceDetailData,
2979 DWORD DeviceInterfaceDetailDataSize, DWORD *ret_size, SP_DEVINFO_DATA *device_data)
2981 struct device_iface *iface;
2982 DWORD bytesNeeded = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath[1]);
2983 BOOL ret = FALSE;
2985 TRACE("devinfo %p, iface_data %p, detail_data %p, size %ld, ret_size %p, device_data %p.\n",
2986 devinfo, iface_data, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize,
2987 ret_size, device_data);
2989 if (!(iface = get_device_iface(devinfo, iface_data)))
2990 return FALSE;
2992 if (DeviceInterfaceDetailData &&
2993 DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A))
2995 SetLastError(ERROR_INVALID_USER_BUFFER);
2996 return FALSE;
2998 if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
3000 SetLastError(ERROR_INVALID_USER_BUFFER);
3001 return FALSE;
3004 if (iface->symlink)
3005 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, iface->symlink, -1,
3006 NULL, 0, NULL, NULL) - 1;
3008 if (ret_size)
3009 *ret_size = bytesNeeded;
3011 if (DeviceInterfaceDetailDataSize >= bytesNeeded)
3013 if (iface->symlink)
3014 WideCharToMultiByte(CP_ACP, 0, iface->symlink, -1,
3015 DeviceInterfaceDetailData->DevicePath,
3016 DeviceInterfaceDetailDataSize -
3017 offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
3018 NULL, NULL);
3019 else
3020 DeviceInterfaceDetailData->DevicePath[0] = '\0';
3022 ret = TRUE;
3024 else
3026 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3029 if (device_data && device_data->cbSize == sizeof(SP_DEVINFO_DATA))
3030 copy_device_data(device_data, iface->device);
3032 return ret;
3035 /***********************************************************************
3036 * SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
3038 BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data,
3039 SP_DEVICE_INTERFACE_DETAIL_DATA_W *DeviceInterfaceDetailData,
3040 DWORD DeviceInterfaceDetailDataSize, DWORD *ret_size, SP_DEVINFO_DATA *device_data)
3042 struct device_iface *iface;
3043 DWORD bytesNeeded = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
3044 + sizeof(WCHAR); /* include NULL terminator */
3045 BOOL ret = FALSE;
3047 TRACE("devinfo %p, iface_data %p, detail_data %p, size %ld, ret_size %p, device_data %p.\n",
3048 devinfo, iface_data, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize,
3049 ret_size, device_data);
3051 if (!(iface = get_device_iface(devinfo, iface_data)))
3052 return FALSE;
3054 if (DeviceInterfaceDetailData && (DeviceInterfaceDetailData->cbSize <
3055 offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR) ||
3056 DeviceInterfaceDetailData->cbSize > sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W)))
3058 SetLastError(ERROR_INVALID_USER_BUFFER);
3059 return FALSE;
3061 if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
3063 SetLastError(ERROR_INVALID_USER_BUFFER);
3064 return FALSE;
3067 if (iface->symlink)
3068 bytesNeeded += sizeof(WCHAR) * lstrlenW(iface->symlink);
3070 if (ret_size)
3071 *ret_size = bytesNeeded;
3073 if (DeviceInterfaceDetailDataSize >= bytesNeeded)
3075 if (iface->symlink)
3076 lstrcpyW(DeviceInterfaceDetailData->DevicePath, iface->symlink);
3077 else
3078 DeviceInterfaceDetailData->DevicePath[0] = '\0';
3080 ret = TRUE;
3082 else
3084 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3087 if (device_data && device_data->cbSize == sizeof(SP_DEVINFO_DATA))
3088 copy_device_data(device_data, iface->device);
3090 return ret;
3093 /***********************************************************************
3094 * SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
3096 BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(HDEVINFO devinfo,
3097 SP_DEVINFO_DATA *device_data, DWORD Property, DWORD *PropertyRegDataType,
3098 BYTE *PropertyBuffer, DWORD PropertyBufferSize, DWORD *RequiredSize)
3100 BOOL ret = FALSE;
3101 struct device *device;
3103 TRACE("devinfo %p, device_data %p, property %ld, type %p, buffer %p, size %ld, required %p\n",
3104 devinfo, device_data, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize);
3106 if (!(device = get_device(devinfo, device_data)))
3107 return FALSE;
3109 if (PropertyBufferSize && PropertyBuffer == NULL)
3111 SetLastError(ERROR_INVALID_DATA);
3112 return FALSE;
3115 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameA)
3117 DWORD size = PropertyBufferSize;
3118 LONG l = RegQueryValueExA(device->key, PropertyMap[Property].nameA,
3119 NULL, PropertyRegDataType, PropertyBuffer, &size);
3121 if (l == ERROR_FILE_NOT_FOUND)
3122 SetLastError(ERROR_INVALID_DATA);
3123 else if (l == ERROR_MORE_DATA || !PropertyBufferSize)
3124 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3125 else if (!l)
3126 ret = TRUE;
3127 else
3128 SetLastError(l);
3129 if (RequiredSize)
3130 *RequiredSize = size;
3132 return ret;
3135 /***********************************************************************
3136 * SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
3138 BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(HDEVINFO devinfo,
3139 SP_DEVINFO_DATA *device_data, DWORD Property, DWORD *PropertyRegDataType,
3140 BYTE *PropertyBuffer, DWORD PropertyBufferSize, DWORD *RequiredSize)
3142 BOOL ret = FALSE;
3143 struct device *device;
3145 TRACE("devinfo %p, device_data %p, prop %ld, type %p, buffer %p, size %ld, required %p\n",
3146 devinfo, device_data, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize);
3148 if (!(device = get_device(devinfo, device_data)))
3149 return FALSE;
3151 if (PropertyBufferSize && PropertyBuffer == NULL)
3153 SetLastError(ERROR_INVALID_DATA);
3154 return FALSE;
3157 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameW)
3159 DWORD size = PropertyBufferSize;
3160 LONG l = RegQueryValueExW(device->key, PropertyMap[Property].nameW,
3161 NULL, PropertyRegDataType, PropertyBuffer, &size);
3163 if (l == ERROR_FILE_NOT_FOUND)
3164 SetLastError(ERROR_INVALID_DATA);
3165 else if (l == ERROR_MORE_DATA || !PropertyBufferSize)
3166 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3167 else if (!l)
3168 ret = TRUE;
3169 else
3170 SetLastError(l);
3171 if (RequiredSize)
3172 *RequiredSize = size;
3174 return ret;
3177 /***********************************************************************
3178 * SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
3180 BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
3181 DWORD Property, const BYTE *PropertyBuffer, DWORD PropertyBufferSize)
3183 BOOL ret = FALSE;
3184 struct device *device;
3186 TRACE("devinfo %p, device_data %p, prop %ld, buffer %p, size %ld.\n",
3187 devinfo, device_data, Property, PropertyBuffer, PropertyBufferSize);
3189 if (!(device = get_device(devinfo, device_data)))
3190 return FALSE;
3192 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameA)
3194 LONG l = RegSetValueExA(device->key, PropertyMap[Property].nameA, 0,
3195 PropertyMap[Property].regType, PropertyBuffer,
3196 PropertyBufferSize);
3197 if (!l)
3198 ret = TRUE;
3199 else
3200 SetLastError(l);
3202 return ret;
3205 /***********************************************************************
3206 * SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
3208 BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(HDEVINFO devinfo,
3209 SP_DEVINFO_DATA *device_data, DWORD prop, const BYTE *buffer, DWORD size)
3211 struct device *device;
3213 TRACE("devinfo %p, device_data %p, prop %ld, buffer %p, size %ld.\n",
3214 devinfo, device_data, prop, buffer, size);
3216 if (!(device = get_device(devinfo, device_data)))
3217 return FALSE;
3219 return SETUPDI_SetDeviceRegistryPropertyW(device, prop, buffer, size);
3222 /***********************************************************************
3223 * SetupDiInstallClassA (SETUPAPI.@)
3225 BOOL WINAPI SetupDiInstallClassA(
3226 HWND hwndParent,
3227 PCSTR InfFileName,
3228 DWORD Flags,
3229 HSPFILEQ FileQueue)
3231 UNICODE_STRING FileNameW;
3232 BOOL Result;
3234 if (!InfFileName)
3236 SetLastError(ERROR_INVALID_PARAMETER);
3237 return FALSE;
3239 if (!RtlCreateUnicodeStringFromAsciiz(&FileNameW, InfFileName))
3241 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3242 return FALSE;
3245 Result = SetupDiInstallClassW(hwndParent, FileNameW.Buffer, Flags, FileQueue);
3247 RtlFreeUnicodeString(&FileNameW);
3249 return Result;
3252 static HKEY CreateClassKey(HINF hInf)
3254 static const WCHAR slash[] = { '\\',0 };
3255 WCHAR FullBuffer[MAX_PATH];
3256 WCHAR Buffer[MAX_PATH];
3257 DWORD RequiredSize;
3258 HKEY hClassKey;
3260 if (!SetupGetLineTextW(NULL,
3261 hInf,
3262 Version,
3263 ClassGUID,
3264 Buffer,
3265 MAX_PATH,
3266 &RequiredSize))
3268 return INVALID_HANDLE_VALUE;
3271 lstrcpyW(FullBuffer, ControlClass);
3272 lstrcatW(FullBuffer, slash);
3273 lstrcatW(FullBuffer, Buffer);
3275 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3276 FullBuffer,
3278 KEY_ALL_ACCESS,
3279 &hClassKey))
3281 if (!SetupGetLineTextW(NULL,
3282 hInf,
3283 Version,
3284 Class,
3285 Buffer,
3286 MAX_PATH,
3287 &RequiredSize))
3289 return INVALID_HANDLE_VALUE;
3292 if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
3293 FullBuffer,
3295 NULL,
3296 REG_OPTION_NON_VOLATILE,
3297 KEY_ALL_ACCESS,
3298 NULL,
3299 &hClassKey,
3300 NULL))
3302 return INVALID_HANDLE_VALUE;
3307 if (RegSetValueExW(hClassKey,
3308 Class,
3310 REG_SZ,
3311 (LPBYTE)Buffer,
3312 RequiredSize * sizeof(WCHAR)))
3314 RegCloseKey(hClassKey);
3315 RegDeleteKeyW(HKEY_LOCAL_MACHINE,
3316 FullBuffer);
3317 return INVALID_HANDLE_VALUE;
3320 return hClassKey;
3323 /***********************************************************************
3324 * SetupDiInstallClassW (SETUPAPI.@)
3326 BOOL WINAPI SetupDiInstallClassW(
3327 HWND hwndParent,
3328 PCWSTR InfFileName,
3329 DWORD Flags,
3330 HSPFILEQ FileQueue)
3332 WCHAR SectionName[MAX_PATH];
3333 DWORD SectionNameLength = 0;
3334 HINF hInf;
3335 BOOL bFileQueueCreated = FALSE;
3336 HKEY hClassKey;
3339 FIXME("\n");
3341 if (!InfFileName)
3343 SetLastError(ERROR_INVALID_PARAMETER);
3344 return FALSE;
3346 if ((Flags & DI_NOVCP) && (FileQueue == NULL || FileQueue == INVALID_HANDLE_VALUE))
3348 SetLastError(ERROR_INVALID_PARAMETER);
3349 return FALSE;
3352 /* Open the .inf file */
3353 hInf = SetupOpenInfFileW(InfFileName,
3354 NULL,
3355 INF_STYLE_WIN4,
3356 NULL);
3357 if (hInf == INVALID_HANDLE_VALUE)
3360 return FALSE;
3363 /* Create or open the class registry key 'HKLM\\CurrentControlSet\\Class\\{GUID}' */
3364 hClassKey = CreateClassKey(hInf);
3365 if (hClassKey == INVALID_HANDLE_VALUE)
3367 SetupCloseInfFile(hInf);
3368 return FALSE;
3372 /* Try to append a layout file */
3373 SetupOpenAppendInfFileW(NULL, hInf, NULL);
3375 /* Retrieve the actual section name */
3376 SetupDiGetActualSectionToInstallW(hInf,
3377 ClassInstall32,
3378 SectionName,
3379 MAX_PATH,
3380 &SectionNameLength,
3381 NULL);
3383 #if 0
3384 if (!(Flags & DI_NOVCP))
3386 FileQueue = SetupOpenFileQueue();
3387 if (FileQueue == INVALID_HANDLE_VALUE)
3389 SetupCloseInfFile(hInf);
3390 return FALSE;
3393 bFileQueueCreated = TRUE;
3396 #endif
3398 SetupInstallFromInfSectionW(NULL,
3399 hInf,
3400 SectionName,
3401 SPINST_COPYINF | SPINST_FILES | SPINST_REGISTRY,
3402 hClassKey,
3403 NULL,
3405 NULL,
3406 NULL,
3407 INVALID_HANDLE_VALUE,
3408 NULL);
3410 /* FIXME: More code! */
3412 if (bFileQueueCreated)
3413 SetupCloseFileQueue(FileQueue);
3415 SetupCloseInfFile(hInf);
3417 return TRUE;
3421 /***********************************************************************
3422 * SetupDiOpenClassRegKey (SETUPAPI.@)
3424 HKEY WINAPI SetupDiOpenClassRegKey(
3425 const GUID* ClassGuid,
3426 REGSAM samDesired)
3428 return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3429 DIOCR_INSTALLER, NULL, NULL);
3433 /***********************************************************************
3434 * SetupDiOpenClassRegKeyExA (SETUPAPI.@)
3436 HKEY WINAPI SetupDiOpenClassRegKeyExA(
3437 const GUID* ClassGuid,
3438 REGSAM samDesired,
3439 DWORD Flags,
3440 PCSTR MachineName,
3441 PVOID Reserved)
3443 PWSTR MachineNameW = NULL;
3444 HKEY hKey;
3446 TRACE("\n");
3448 if (MachineName)
3450 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
3451 if (MachineNameW == NULL)
3452 return INVALID_HANDLE_VALUE;
3455 hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3456 Flags, MachineNameW, Reserved);
3458 MyFree(MachineNameW);
3460 return hKey;
3464 /***********************************************************************
3465 * SetupDiOpenClassRegKeyExW (SETUPAPI.@)
3467 HKEY WINAPI SetupDiOpenClassRegKeyExW(
3468 const GUID* ClassGuid,
3469 REGSAM samDesired,
3470 DWORD Flags,
3471 PCWSTR MachineName,
3472 PVOID Reserved)
3474 HKEY hClassesKey;
3475 HKEY key;
3476 LPCWSTR lpKeyName;
3477 LONG l;
3479 if (MachineName && *MachineName)
3481 FIXME("Remote access not supported yet!\n");
3482 return INVALID_HANDLE_VALUE;
3485 if (Flags == DIOCR_INSTALLER)
3487 lpKeyName = ControlClass;
3489 else if (Flags == DIOCR_INTERFACE)
3491 lpKeyName = DeviceClasses;
3493 else
3495 ERR("Invalid Flags parameter!\n");
3496 SetLastError(ERROR_INVALID_PARAMETER);
3497 return INVALID_HANDLE_VALUE;
3500 if (!ClassGuid)
3502 if ((l = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3503 lpKeyName,
3505 samDesired,
3506 &hClassesKey)))
3508 SetLastError(l);
3509 hClassesKey = INVALID_HANDLE_VALUE;
3511 key = hClassesKey;
3513 else
3515 WCHAR bracedGuidString[39];
3517 SETUPDI_GuidToString(ClassGuid, bracedGuidString);
3519 if (!(l = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3520 lpKeyName,
3522 samDesired,
3523 &hClassesKey)))
3525 if ((l = RegOpenKeyExW(hClassesKey,
3526 bracedGuidString,
3528 samDesired,
3529 &key)))
3531 SetLastError(l);
3532 key = INVALID_HANDLE_VALUE;
3534 RegCloseKey(hClassesKey);
3536 else
3538 SetLastError(l);
3539 key = INVALID_HANDLE_VALUE;
3542 return key;
3545 /***********************************************************************
3546 * SetupDiOpenDeviceInfoA (SETUPAPI.@)
3548 BOOL WINAPI SetupDiOpenDeviceInfoA(HDEVINFO devinfo, PCSTR instance_id, HWND hwnd_parent, DWORD flags,
3549 PSP_DEVINFO_DATA device_data)
3551 WCHAR instance_idW[MAX_DEVICE_ID_LEN];
3553 TRACE("%p %s %p 0x%08lx %p\n", devinfo, debugstr_a(instance_id), hwnd_parent, flags, device_data);
3555 if (!instance_id || strlen(instance_id) >= MAX_DEVICE_ID_LEN)
3557 SetLastError(ERROR_INVALID_PARAMETER);
3558 return FALSE;
3561 MultiByteToWideChar(CP_ACP, 0, instance_id, -1, instance_idW, ARRAY_SIZE(instance_idW));
3562 return SetupDiOpenDeviceInfoW(devinfo, instance_idW, hwnd_parent, flags, device_data);
3565 /***********************************************************************
3566 * SetupDiOpenDeviceInfoW (SETUPAPI.@)
3568 BOOL WINAPI SetupDiOpenDeviceInfoW(HDEVINFO devinfo, PCWSTR instance_id, HWND hwnd_parent, DWORD flags,
3569 PSP_DEVINFO_DATA device_data)
3571 struct DeviceInfoSet *set;
3572 struct device *device;
3573 WCHAR classW[40];
3574 GUID guid;
3575 HKEY enumKey = NULL;
3576 HKEY instanceKey = NULL;
3577 DWORD phantom;
3578 DWORD size;
3579 DWORD error = ERROR_NO_SUCH_DEVINST;
3581 TRACE("%p %s %p 0x%08lx %p\n", devinfo, debugstr_w(instance_id), hwnd_parent, flags, device_data);
3583 if (!(set = get_device_set(devinfo)))
3584 return FALSE;
3586 if (!instance_id)
3588 SetLastError(ERROR_INVALID_PARAMETER);
3589 return FALSE;
3592 if (hwnd_parent)
3593 FIXME("hwnd_parent unsupported\n");
3595 if (flags)
3596 FIXME("flags unsupported: 0x%08lx\n", flags);
3598 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &enumKey, NULL);
3599 /* Instance needs to be already existent in registry, if not, report ERROR_NO_SUCH_DEVINST */
3600 if (RegOpenKeyExW(enumKey, instance_id, 0, KEY_READ, &instanceKey))
3601 goto done;
3603 /* If it's an unregistered instance, aka phantom instance, report ERROR_NO_SUCH_DEVINST */
3604 size = sizeof(phantom);
3605 if (!RegQueryValueExW(instanceKey, Phantom, NULL, NULL, (BYTE *)&phantom, &size))
3606 goto done;
3608 /* Check class GUID */
3609 size = sizeof(classW);
3610 if (RegQueryValueExW(instanceKey, ClassGUID, NULL, NULL, (BYTE *)classW, &size))
3611 goto done;
3613 classW[37] = 0;
3614 UuidFromStringW(&classW[1], &guid);
3616 if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) && !IsEqualGUID(&guid, &set->ClassGuid))
3618 error = ERROR_CLASS_MISMATCH;
3619 goto done;
3622 if (!(device = create_device(set, &guid, instance_id, FALSE)))
3623 goto done;
3625 if (!device_data || device_data->cbSize == sizeof(SP_DEVINFO_DATA))
3627 if (device_data)
3628 copy_device_data(device_data, device);
3629 error = NO_ERROR;
3631 else
3632 error = ERROR_INVALID_USER_BUFFER;
3634 done:
3635 RegCloseKey(instanceKey);
3636 RegCloseKey(enumKey);
3637 SetLastError(error);
3638 return !error;
3641 /***********************************************************************
3642 * SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
3644 BOOL WINAPI SetupDiOpenDeviceInterfaceW(
3645 HDEVINFO DeviceInfoSet,
3646 PCWSTR DevicePath,
3647 DWORD OpenFlags,
3648 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3650 FIXME("%p %s %08lx %p\n",
3651 DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
3652 return FALSE;
3655 /***********************************************************************
3656 * SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
3658 BOOL WINAPI SetupDiOpenDeviceInterfaceA(
3659 HDEVINFO DeviceInfoSet,
3660 PCSTR DevicePath,
3661 DWORD OpenFlags,
3662 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3664 FIXME("%p %s %08lx %p\n", DeviceInfoSet,
3665 debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
3666 return FALSE;
3669 /***********************************************************************
3670 * SetupDiOpenDeviceInterfaceRegKey (SETUPAPI.@)
3672 HKEY WINAPI SetupDiOpenDeviceInterfaceRegKey(HDEVINFO devinfo, PSP_DEVICE_INTERFACE_DATA iface_data,
3673 DWORD reserved, REGSAM access)
3675 struct device_iface *iface;
3676 LSTATUS lr;
3677 HKEY key;
3679 TRACE("devinfo %p, iface_data %p, reserved %ld, access %#lx.\n", devinfo, iface_data, reserved, access);
3681 if (!(iface = get_device_iface(devinfo, iface_data)))
3682 return INVALID_HANDLE_VALUE;
3684 lr = RegOpenKeyExW(iface->refstr_key, DeviceParameters, 0, access, &key);
3685 if (lr)
3687 SetLastError(lr);
3688 return INVALID_HANDLE_VALUE;
3691 return key;
3694 /***********************************************************************
3695 * SetupDiSetClassInstallParamsA (SETUPAPI.@)
3697 BOOL WINAPI SetupDiSetClassInstallParamsA(
3698 HDEVINFO DeviceInfoSet,
3699 PSP_DEVINFO_DATA DeviceInfoData,
3700 PSP_CLASSINSTALL_HEADER ClassInstallParams,
3701 DWORD ClassInstallParamsSize)
3703 FIXME("%p %p %x %lu\n",DeviceInfoSet, DeviceInfoData,
3704 ClassInstallParams->InstallFunction, ClassInstallParamsSize);
3705 return FALSE;
3708 /***********************************************************************
3709 * SetupDiSetClassInstallParamsW (SETUPAPI.@)
3711 BOOL WINAPI SetupDiSetClassInstallParamsW(
3712 HDEVINFO DeviceInfoSet,
3713 PSP_DEVINFO_DATA DeviceInfoData,
3714 PSP_CLASSINSTALL_HEADER ClassInstallParams,
3715 DWORD ClassInstallParamsSize)
3717 FIXME("%p %p %x %lu\n",DeviceInfoSet, DeviceInfoData,
3718 ClassInstallParams->InstallFunction, ClassInstallParamsSize);
3719 return FALSE;
3722 static BOOL call_coinstallers(WCHAR *list, DI_FUNCTION function, HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
3724 DWORD (CALLBACK *coinst_proc)(DI_FUNCTION, HDEVINFO, SP_DEVINFO_DATA *, COINSTALLER_CONTEXT_DATA *);
3725 COINSTALLER_CONTEXT_DATA coinst_ctx;
3726 WCHAR *p, *procnameW;
3727 HMODULE module;
3728 char *procname;
3729 DWORD ret;
3731 for (p = list; *p; p += lstrlenW(p) + 1)
3733 TRACE("Found co-installer %s.\n", debugstr_w(p));
3734 if ((procnameW = wcschr(p, ',')))
3735 *procnameW = 0;
3737 if ((module = LoadLibraryExW(p, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32)))
3739 if (procnameW)
3741 procname = strdupWtoA(procnameW + 1);
3742 coinst_proc = (void *)GetProcAddress(module, procname);
3743 heap_free(procname);
3745 else
3746 coinst_proc = (void *)GetProcAddress(module, "CoDeviceInstall");
3747 if (coinst_proc)
3749 memset(&coinst_ctx, 0, sizeof(coinst_ctx));
3750 TRACE("Calling co-installer %p.\n", coinst_proc);
3751 ret = coinst_proc(function, devinfo, device_data, &coinst_ctx);
3752 TRACE("Co-installer %p returned %#lx.\n", coinst_proc, ret);
3753 if (ret == ERROR_DI_POSTPROCESSING_REQUIRED)
3754 FIXME("Co-installer postprocessing not implemented.\n");
3755 else if (ret)
3757 ERR("Co-installer returned error %#lx.\n", ret);
3758 FreeLibrary(module);
3759 SetLastError(ret);
3760 return FALSE;
3763 FreeLibrary(module);
3767 return TRUE;
3770 /***********************************************************************
3771 * SetupDiCallClassInstaller (SETUPAPI.@)
3773 BOOL WINAPI SetupDiCallClassInstaller(DI_FUNCTION function, HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
3775 static const WCHAR class_coinst_pathW[] = {'S','y','s','t','e','m',
3776 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
3777 '\\','C','o','n','t','r','o','l',
3778 '\\','C','o','D','e','v','i','c','e','I','n','s','t','a','l','l','e','r','s',0};
3779 static const WCHAR coinstallers32W[] = {'C','o','I','n','s','t','a','l','l','e','r','s','3','2',0};
3780 static const WCHAR installer32W[] = {'I','n','s','t','a','l','l','e','r','3','2',0};
3781 DWORD (CALLBACK *classinst_proc)(DI_FUNCTION, HDEVINFO, SP_DEVINFO_DATA *);
3782 DWORD ret = ERROR_DI_DO_DEFAULT;
3783 HKEY class_key, coinst_key;
3784 WCHAR *path, *procnameW;
3785 struct device *device;
3786 WCHAR guidstr[39];
3787 BOOL coret = TRUE;
3788 HMODULE module;
3789 char *procname;
3790 DWORD size;
3792 TRACE("function %#x, devinfo %p, device_data %p.\n", function, devinfo, device_data);
3794 if (!(device = get_device(devinfo, device_data)))
3795 return FALSE;
3797 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, class_coinst_pathW, 0, KEY_READ, &coinst_key))
3799 SETUPDI_GuidToString(&device->class, guidstr);
3800 if (!RegGetValueW(coinst_key, NULL, guidstr, RRF_RT_REG_MULTI_SZ, NULL, NULL, &size))
3802 path = heap_alloc(size);
3803 if (!RegGetValueW(coinst_key, NULL, guidstr, RRF_RT_REG_MULTI_SZ, NULL, path, &size))
3804 coret = call_coinstallers(path, function, devinfo, device_data);
3805 heap_free(path);
3807 RegCloseKey(coinst_key);
3810 if (!coret)
3811 return FALSE;
3813 if (!open_driver_key(device, KEY_READ, &coinst_key))
3815 if (!RegGetValueW(coinst_key, NULL, coinstallers32W, RRF_RT_REG_MULTI_SZ, NULL, NULL, &size))
3817 path = heap_alloc(size);
3818 if (!RegGetValueW(coinst_key, NULL, coinstallers32W, RRF_RT_REG_MULTI_SZ, NULL, path, &size))
3819 coret = call_coinstallers(path, function, devinfo, device_data);
3820 heap_free(path);
3822 RegCloseKey(coinst_key);
3825 if ((class_key = SetupDiOpenClassRegKey(&device->class, KEY_READ)) != INVALID_HANDLE_VALUE)
3827 if (!RegGetValueW(class_key, NULL, installer32W, RRF_RT_REG_SZ, NULL, NULL, &size))
3829 path = heap_alloc(size);
3830 if (!RegGetValueW(class_key, NULL, installer32W, RRF_RT_REG_SZ, NULL, path, &size))
3832 TRACE("Found class installer %s.\n", debugstr_w(path));
3833 if ((procnameW = wcschr(path, ',')))
3834 *procnameW = 0;
3836 if ((module = LoadLibraryExW(path, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32)))
3838 if (procnameW)
3840 procname = strdupWtoA(procnameW + 1);
3841 classinst_proc = (void *)GetProcAddress(module, procname);
3842 heap_free(procname);
3844 else
3845 classinst_proc = (void *)GetProcAddress(module, "ClassInstall");
3846 if (classinst_proc)
3848 TRACE("Calling class installer %p.\n", classinst_proc);
3849 ret = classinst_proc(function, devinfo, device_data);
3850 TRACE("Class installer %p returned %#lx.\n", classinst_proc, ret);
3852 FreeLibrary(module);
3855 heap_free(path);
3857 RegCloseKey(class_key);
3860 if (ret == ERROR_DI_DO_DEFAULT)
3862 switch (function)
3864 case DIF_REGISTERDEVICE:
3865 return SetupDiRegisterDeviceInfo(devinfo, device_data, 0, NULL, NULL, NULL);
3866 case DIF_REMOVE:
3867 return SetupDiRemoveDevice(devinfo, device_data);
3868 case DIF_SELECTBESTCOMPATDRV:
3869 return SetupDiSelectBestCompatDrv(devinfo, device_data);
3870 case DIF_REGISTER_COINSTALLERS:
3871 return SetupDiRegisterCoDeviceInstallers(devinfo, device_data);
3872 case DIF_INSTALLDEVICEFILES:
3873 return SetupDiInstallDriverFiles(devinfo, device_data);
3874 case DIF_INSTALLINTERFACES:
3875 return SetupDiInstallDeviceInterfaces(devinfo, device_data);
3876 case DIF_INSTALLDEVICE:
3877 return SetupDiInstallDevice(devinfo, device_data);
3878 case DIF_FINISHINSTALL_ACTION:
3879 case DIF_PROPERTYCHANGE:
3880 case DIF_SELECTDEVICE:
3881 case DIF_UNREMOVE:
3882 FIXME("Unhandled function %#x.\n", function);
3886 if (ret) SetLastError(ret);
3887 return !ret;
3890 /***********************************************************************
3891 * SetupDiGetDeviceInstallParamsW (SETUPAPI.@)
3893 BOOL WINAPI SetupDiGetDeviceInstallParamsW(HDEVINFO devinfo,
3894 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_W *params)
3896 struct device *device;
3898 TRACE("devinfo %p, device_data %p, params %p.\n", devinfo, device_data, params);
3900 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
3902 SetLastError(ERROR_INVALID_USER_BUFFER);
3903 return FALSE;
3906 if (!(device = get_device(devinfo, device_data)))
3907 return FALSE;
3909 *params = device->params;
3911 return TRUE;
3914 /***********************************************************************
3915 * SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
3917 BOOL WINAPI SetupDiGetDeviceInstallParamsA(HDEVINFO devinfo,
3918 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_A *params)
3920 SP_DEVINSTALL_PARAMS_W paramsW;
3921 BOOL ret;
3923 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
3925 SetLastError(ERROR_INVALID_USER_BUFFER);
3926 return FALSE;
3929 paramsW.cbSize = sizeof(paramsW);
3930 ret = SetupDiGetDeviceInstallParamsW(devinfo, device_data, &paramsW);
3931 params->Flags = paramsW.Flags;
3932 params->FlagsEx = paramsW.FlagsEx;
3933 params->hwndParent = paramsW.hwndParent;
3934 params->InstallMsgHandler = paramsW.InstallMsgHandler;
3935 params->InstallMsgHandlerContext = paramsW.InstallMsgHandlerContext;
3936 params->FileQueue = paramsW.FileQueue;
3937 params->ClassInstallReserved = paramsW.ClassInstallReserved;
3938 params->Reserved = paramsW.Reserved;
3939 WideCharToMultiByte(CP_ACP, 0, paramsW.DriverPath, -1, params->DriverPath, sizeof(params->DriverPath), NULL, NULL);
3941 return ret;
3944 /***********************************************************************
3945 * SetupDiSetDeviceInstallParamsA (SETUPAPI.@)
3947 BOOL WINAPI SetupDiSetDeviceInstallParamsA(HDEVINFO devinfo,
3948 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_A *params)
3950 SP_DEVINSTALL_PARAMS_W paramsW;
3952 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
3954 SetLastError(ERROR_INVALID_USER_BUFFER);
3955 return FALSE;
3958 paramsW.cbSize = sizeof(paramsW);
3959 paramsW.Flags = params->Flags;
3960 paramsW.FlagsEx = params->FlagsEx;
3961 paramsW.hwndParent = params->hwndParent;
3962 paramsW.InstallMsgHandler = params->InstallMsgHandler;
3963 paramsW.InstallMsgHandlerContext = params->InstallMsgHandlerContext;
3964 paramsW.FileQueue = params->FileQueue;
3965 paramsW.ClassInstallReserved = params->ClassInstallReserved;
3966 paramsW.Reserved = params->Reserved;
3967 MultiByteToWideChar(CP_ACP, 0, params->DriverPath, -1, paramsW.DriverPath, ARRAY_SIZE(paramsW.DriverPath));
3969 return SetupDiSetDeviceInstallParamsW(devinfo, device_data, &paramsW);
3972 /***********************************************************************
3973 * SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
3975 BOOL WINAPI SetupDiSetDeviceInstallParamsW(HDEVINFO devinfo,
3976 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_W *params)
3978 struct device *device;
3980 TRACE("devinfo %p, device_data %p, params %p.\n", devinfo, device_data, params);
3982 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
3984 SetLastError(ERROR_INVALID_USER_BUFFER);
3985 return FALSE;
3988 if (!(device = get_device(devinfo, device_data)))
3989 return FALSE;
3991 device->params = *params;
3993 return TRUE;
3996 BOOL WINAPI SetupDiSetDevicePropertyW(HDEVINFO devinfo, PSP_DEVINFO_DATA device_data, const DEVPROPKEY *key,
3997 DEVPROPTYPE type, const BYTE *buffer, DWORD size, DWORD flags)
3999 static const WCHAR propertiesW[] = {'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's', 0};
4000 static const WCHAR formatW[] = {'\\', '%', '0', '4', 'X', 0};
4001 struct device *device;
4002 HKEY properties_hkey, property_hkey;
4003 WCHAR property_hkey_path[44];
4004 LSTATUS ls;
4006 TRACE("%p %p %p %#lx %p %ld %#lx\n", devinfo, device_data, key, type, buffer, size, flags);
4008 if (!(device = get_device(devinfo, device_data)))
4009 return FALSE;
4011 if (!key || !is_valid_property_type(type)
4012 || (buffer && !size && !(type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL))
4013 || (buffer && size && (type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL)))
4015 SetLastError(ERROR_INVALID_DATA);
4016 return FALSE;
4019 if (size && !buffer)
4021 SetLastError(ERROR_INVALID_USER_BUFFER);
4022 return FALSE;
4025 if (flags)
4027 SetLastError(ERROR_INVALID_FLAGS);
4028 return FALSE;
4031 ls = RegCreateKeyExW(device->key, propertiesW, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &properties_hkey, NULL);
4032 if (ls)
4034 SetLastError(ls);
4035 return FALSE;
4038 SETUPDI_GuidToString(&key->fmtid, property_hkey_path);
4039 swprintf(property_hkey_path + 38, ARRAY_SIZE(property_hkey_path) - 38, formatW, key->pid);
4041 if (type == DEVPROP_TYPE_EMPTY)
4043 ls = RegDeleteKeyW(properties_hkey, property_hkey_path);
4044 RegCloseKey(properties_hkey);
4045 SetLastError(ls == ERROR_FILE_NOT_FOUND ? ERROR_NOT_FOUND : ls);
4046 return !ls;
4048 else if (type == DEVPROP_TYPE_NULL)
4050 if (!(ls = RegOpenKeyW(properties_hkey, property_hkey_path, &property_hkey)))
4052 ls = RegDeleteValueW(property_hkey, NULL);
4053 RegCloseKey(property_hkey);
4056 RegCloseKey(properties_hkey);
4057 SetLastError(ls == ERROR_FILE_NOT_FOUND ? ERROR_NOT_FOUND : ls);
4058 return !ls;
4060 else
4062 if (!(ls = RegCreateKeyExW(properties_hkey, property_hkey_path, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL,
4063 &property_hkey, NULL)))
4065 ls = RegSetValueExW(property_hkey, NULL, 0, 0xffff0000 | (0xffff & type), buffer, size);
4066 RegCloseKey(property_hkey);
4069 RegCloseKey(properties_hkey);
4070 SetLastError(ls);
4071 return !ls;
4075 /***********************************************************************
4076 * SetupDiOpenDevRegKey (SETUPAPI.@)
4078 HKEY WINAPI SetupDiOpenDevRegKey(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4079 DWORD Scope, DWORD HwProfile, DWORD KeyType, REGSAM samDesired)
4081 struct device *device;
4082 HKEY key = INVALID_HANDLE_VALUE;
4083 LONG l;
4085 TRACE("devinfo %p, device_data %p, scope %ld, profile %ld, type %ld, access %#lx.\n",
4086 devinfo, device_data, Scope, HwProfile, KeyType, samDesired);
4088 if (!(device = get_device(devinfo, device_data)))
4089 return INVALID_HANDLE_VALUE;
4091 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
4093 SetLastError(ERROR_INVALID_FLAGS);
4094 return INVALID_HANDLE_VALUE;
4096 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
4098 SetLastError(ERROR_INVALID_FLAGS);
4099 return INVALID_HANDLE_VALUE;
4102 if (device->phantom)
4104 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
4105 return INVALID_HANDLE_VALUE;
4107 if (Scope != DICS_FLAG_GLOBAL)
4108 FIXME("unimplemented for scope %ld\n", Scope);
4109 switch (KeyType)
4111 case DIREG_DEV:
4112 l = RegOpenKeyExW(device->key, DeviceParameters, 0, samDesired, &key);
4113 break;
4114 case DIREG_DRV:
4115 l = open_driver_key(device, samDesired, &key);
4116 break;
4117 default:
4118 FIXME("Unhandled type %#lx.\n", KeyType);
4119 l = ERROR_CALL_NOT_IMPLEMENTED;
4121 SetLastError(l == ERROR_FILE_NOT_FOUND ? ERROR_KEY_DOES_NOT_EXIST : l);
4122 return l ? INVALID_HANDLE_VALUE : key;
4125 /***********************************************************************
4126 * SetupDiDeleteDevRegKey (SETUPAPI.@)
4128 BOOL WINAPI SetupDiDeleteDevRegKey(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4129 DWORD Scope, DWORD HwProfile, DWORD KeyType)
4131 struct device *device;
4132 LONG l;
4134 TRACE("devinfo %p, device_data %p, scope %ld, profile %ld, type %ld.\n",
4135 devinfo, device_data, Scope, HwProfile, KeyType);
4137 if (!(device = get_device(devinfo, device_data)))
4138 return FALSE;
4140 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
4142 SetLastError(ERROR_INVALID_FLAGS);
4143 return FALSE;
4145 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV && KeyType != DIREG_BOTH)
4147 SetLastError(ERROR_INVALID_FLAGS);
4148 return FALSE;
4151 if (device->phantom)
4153 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
4154 return FALSE;
4156 if (Scope != DICS_FLAG_GLOBAL)
4157 FIXME("unimplemented for scope %ld\n", Scope);
4158 switch (KeyType)
4160 case DIREG_DRV:
4161 l = delete_driver_key(device);
4162 break;
4163 case DIREG_BOTH:
4164 if ((l = delete_driver_key(device)))
4165 break;
4166 /* fall through */
4167 case DIREG_DEV:
4168 l = RegDeleteKeyW(device->key, DeviceParameters);
4169 break;
4170 default:
4171 FIXME("Unhandled type %#lx.\n", KeyType);
4172 l = ERROR_CALL_NOT_IMPLEMENTED;
4174 SetLastError(l);
4175 return !l;
4178 /***********************************************************************
4179 * CM_Get_Device_IDA (SETUPAPI.@)
4181 CONFIGRET WINAPI CM_Get_Device_IDA(DEVINST devnode, char *buffer, ULONG len, ULONG flags)
4183 struct device *device = get_devnode_device(devnode);
4185 TRACE("%lu, %p, %lu, %#lx\n", devnode, buffer, len, flags);
4187 if (!device)
4188 return CR_NO_SUCH_DEVINST;
4190 WideCharToMultiByte(CP_ACP, 0, device->instanceId, -1, buffer, len, 0, 0);
4191 TRACE("Returning %s\n", debugstr_a(buffer));
4192 return CR_SUCCESS;
4195 /***********************************************************************
4196 * CM_Get_Device_IDW (SETUPAPI.@)
4198 CONFIGRET WINAPI CM_Get_Device_IDW(DEVINST devnode, WCHAR *buffer, ULONG len, ULONG flags)
4200 struct device *device = get_devnode_device(devnode);
4202 TRACE("%lu, %p, %lu, %#lx\n", devnode, buffer, len, flags);
4204 if (!device)
4205 return CR_NO_SUCH_DEVINST;
4207 lstrcpynW(buffer, device->instanceId, len);
4208 TRACE("Returning %s\n", debugstr_w(buffer));
4209 return CR_SUCCESS;
4212 /***********************************************************************
4213 * CM_Get_Device_ID_Size (SETUPAPI.@)
4215 CONFIGRET WINAPI CM_Get_Device_ID_Size(ULONG *len, DEVINST devnode, ULONG flags)
4217 struct device *device = get_devnode_device(devnode);
4219 TRACE("%p, %lu, %#lx\n", len, devnode, flags);
4221 if (!device)
4222 return CR_NO_SUCH_DEVINST;
4224 *len = lstrlenW(device->instanceId);
4225 return CR_SUCCESS;
4228 /***********************************************************************
4229 * SetupDiGetINFClassA (SETUPAPI.@)
4231 BOOL WINAPI SetupDiGetINFClassA(PCSTR inf, LPGUID class_guid, PSTR class_name,
4232 DWORD size, PDWORD required_size)
4234 BOOL retval;
4235 DWORD required_sizeA, required_sizeW;
4236 PWSTR class_nameW = NULL;
4237 UNICODE_STRING infW;
4239 if (inf)
4241 if (!RtlCreateUnicodeStringFromAsciiz(&infW, inf))
4243 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4244 return FALSE;
4247 else
4248 infW.Buffer = NULL;
4250 if (class_name && size)
4252 if (!(class_nameW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR))))
4254 RtlFreeUnicodeString(&infW);
4255 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4256 return FALSE;
4260 retval = SetupDiGetINFClassW(infW.Buffer, class_guid, class_nameW, size, &required_sizeW);
4262 if (retval)
4264 required_sizeA = WideCharToMultiByte( CP_ACP, 0, class_nameW, required_sizeW,
4265 class_name, size, NULL, NULL);
4267 if(required_size) *required_size = required_sizeA;
4269 else
4270 if(required_size) *required_size = required_sizeW;
4272 HeapFree(GetProcessHeap(), 0, class_nameW);
4273 RtlFreeUnicodeString(&infW);
4274 return retval;
4277 /***********************************************************************
4278 * SetupDiGetINFClassW (SETUPAPI.@)
4280 BOOL WINAPI SetupDiGetINFClassW(PCWSTR inf, LPGUID class_guid, PWSTR class_name,
4281 DWORD size, PDWORD required_size)
4283 BOOL have_guid, have_name;
4284 DWORD dret;
4285 WCHAR buffer[MAX_PATH];
4287 if (!inf)
4289 SetLastError(ERROR_INVALID_PARAMETER);
4290 return FALSE;
4293 if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(inf))
4295 FIXME("%s not found. Searching via DevicePath not implemented\n", debugstr_w(inf));
4296 SetLastError(ERROR_FILE_NOT_FOUND);
4297 return FALSE;
4300 if (!class_guid || !class_name || !size)
4302 SetLastError(ERROR_INVALID_PARAMETER);
4303 return FALSE;
4306 if (!GetPrivateProfileStringW(Version, Signature, NULL, buffer, MAX_PATH, inf))
4307 return FALSE;
4309 if (lstrcmpiW(buffer, Chicago) && lstrcmpiW(buffer, WindowsNT))
4310 return FALSE;
4312 buffer[0] = '\0';
4313 have_guid = 0 < GetPrivateProfileStringW(Version, ClassGUID, NULL, buffer, MAX_PATH, inf);
4314 if (have_guid)
4316 buffer[lstrlenW(buffer)-1] = 0;
4317 if (RPC_S_OK != UuidFromStringW(buffer + 1, class_guid))
4319 FIXME("failed to convert \"%s\" into a guid\n", debugstr_w(buffer));
4320 SetLastError(ERROR_INVALID_PARAMETER);
4321 return FALSE;
4325 buffer[0] = '\0';
4326 dret = GetPrivateProfileStringW(Version, Class, NULL, buffer, MAX_PATH, inf);
4327 have_name = 0 < dret;
4329 if (dret >= MAX_PATH -1) FIXME("buffer might be too small\n");
4330 if (have_guid && !have_name)
4332 class_name[0] = '\0';
4333 FIXME("class name lookup via guid not implemented\n");
4336 if (have_name)
4338 if (dret < size) lstrcpyW(class_name, buffer);
4339 else
4341 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4342 have_name = FALSE;
4346 if (required_size) *required_size = dret + ((dret) ? 1 : 0);
4348 return (have_guid || have_name);
4351 static LSTATUS get_device_property(struct device *device, const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type,
4352 BYTE *prop_buff, DWORD prop_buff_size, DWORD *required_size, DWORD flags)
4354 WCHAR key_path[55] = L"Properties\\";
4355 HKEY hkey;
4356 DWORD value_type;
4357 DWORD value_size = 0;
4358 LSTATUS ls;
4360 if (!prop_key)
4361 return ERROR_INVALID_DATA;
4363 if (!prop_type || (!prop_buff && prop_buff_size))
4364 return ERROR_INVALID_USER_BUFFER;
4366 if (flags)
4367 return ERROR_INVALID_FLAGS;
4369 SETUPDI_GuidToString(&prop_key->fmtid, key_path + 11);
4370 swprintf(key_path + 49, ARRAY_SIZE(key_path) - 49, L"\\%04X", prop_key->pid);
4372 ls = RegOpenKeyExW(device->key, key_path, 0, KEY_QUERY_VALUE, &hkey);
4373 if (!ls)
4375 value_size = prop_buff_size;
4376 ls = RegQueryValueExW(hkey, NULL, NULL, &value_type, prop_buff, &value_size);
4377 RegCloseKey(hkey);
4380 switch (ls)
4382 case NO_ERROR:
4383 case ERROR_MORE_DATA:
4384 *prop_type = 0xffff & value_type;
4385 ls = (ls == ERROR_MORE_DATA || !prop_buff) ? ERROR_INSUFFICIENT_BUFFER : NO_ERROR;
4386 break;
4387 case ERROR_FILE_NOT_FOUND:
4388 *prop_type = DEVPROP_TYPE_EMPTY;
4389 value_size = 0;
4390 ls = ERROR_NOT_FOUND;
4391 break;
4392 default:
4393 *prop_type = DEVPROP_TYPE_EMPTY;
4394 value_size = 0;
4395 FIXME("Unhandled error %#lx\n", ls);
4396 break;
4399 if (required_size)
4400 *required_size = value_size;
4402 return ls;
4405 /***********************************************************************
4406 * SetupDiGetDevicePropertyW (SETUPAPI.@)
4408 BOOL WINAPI SetupDiGetDevicePropertyW(HDEVINFO devinfo, PSP_DEVINFO_DATA device_data,
4409 const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type, BYTE *prop_buff,
4410 DWORD prop_buff_size, DWORD *required_size, DWORD flags)
4412 struct device *device;
4413 LSTATUS ls;
4415 TRACE("%p, %p, %p, %p, %p, %ld, %p, %#lx\n", devinfo, device_data, prop_key, prop_type, prop_buff, prop_buff_size,
4416 required_size, flags);
4418 if (!(device = get_device(devinfo, device_data)))
4419 return FALSE;
4421 ls = get_device_property(device, prop_key, prop_type, prop_buff, prop_buff_size, required_size, flags);
4423 SetLastError(ls);
4424 return !ls;
4427 /***********************************************************************
4428 * CM_Get_DevNode_Property_ExW (SETUPAPI.@)
4430 CONFIGRET WINAPI CM_Get_DevNode_Property_ExW(DEVINST devnode, const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type,
4431 BYTE *prop_buff, ULONG *prop_buff_size, ULONG flags, HMACHINE machine)
4433 struct device *device = get_devnode_device(devnode);
4434 LSTATUS ls;
4436 TRACE("%lu, %p, %p, %p, %p, %#lx, %p\n", devnode, prop_key, prop_type, prop_buff, prop_buff_size,
4437 flags, machine);
4439 if (machine)
4440 return CR_MACHINE_UNAVAILABLE;
4442 if (!device)
4443 return CR_NO_SUCH_DEVINST;
4445 if (!prop_buff_size)
4446 return CR_INVALID_POINTER;
4448 ls = get_device_property(device, prop_key, prop_type, prop_buff, *prop_buff_size, prop_buff_size, flags);
4449 switch (ls)
4451 case NO_ERROR:
4452 return CR_SUCCESS;
4453 case ERROR_INVALID_DATA:
4454 return CR_INVALID_DATA;
4455 case ERROR_INVALID_USER_BUFFER:
4456 return CR_INVALID_POINTER;
4457 case ERROR_INVALID_FLAGS:
4458 return CR_INVALID_FLAG;
4459 case ERROR_INSUFFICIENT_BUFFER:
4460 return CR_BUFFER_SMALL;
4461 case ERROR_NOT_FOUND:
4462 return CR_NO_SUCH_VALUE;
4464 return CR_FAILURE;
4467 /***********************************************************************
4468 * CM_Get_DevNode_PropertyW (SETUPAPI.@)
4470 CONFIGRET WINAPI CM_Get_DevNode_PropertyW(DEVINST dev, const DEVPROPKEY *key, DEVPROPTYPE *type,
4471 PVOID buf, PULONG len, ULONG flags)
4473 return CM_Get_DevNode_Property_ExW(dev, key, type, buf, len, flags, NULL);
4476 /***********************************************************************
4477 * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
4479 BOOL WINAPI SetupDiInstallDeviceInterfaces(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4481 WCHAR section_ext[LINE_LEN], iface_section[LINE_LEN], refstr[LINE_LEN], guidstr[39];
4482 UINT install_flags = SPINST_ALL;
4483 struct device_iface *iface;
4484 struct device *device;
4485 struct driver *driver;
4486 void *callback_ctx;
4487 GUID iface_guid;
4488 INFCONTEXT ctx;
4489 HKEY iface_key;
4490 HINF hinf;
4491 LONG l;
4493 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
4495 if (!(device = get_device(devinfo, device_data)))
4496 return FALSE;
4498 if (!(driver = device->selected_driver))
4500 ERR("No driver selected for device %p.\n", devinfo);
4501 SetLastError(ERROR_NO_DRIVER_SELECTED);
4502 return FALSE;
4505 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4506 return FALSE;
4508 SetupDiGetActualSectionToInstallW(hinf, driver->section, section_ext, ARRAY_SIZE(section_ext), NULL, NULL);
4510 if (device->params.Flags & DI_NOFILECOPY)
4511 install_flags &= ~SPINST_FILES;
4513 callback_ctx = SetupInitDefaultQueueCallback(NULL);
4515 lstrcatW(section_ext, dotInterfaces);
4516 if (SetupFindFirstLineW(hinf, section_ext, AddInterface, &ctx))
4518 do {
4519 SetupGetStringFieldW(&ctx, 1, guidstr, ARRAY_SIZE(guidstr), NULL);
4520 SetupGetStringFieldW(&ctx, 2, refstr, ARRAY_SIZE(refstr), NULL);
4521 guidstr[37] = 0;
4522 UuidFromStringW(&guidstr[1], &iface_guid);
4524 if (!(iface = SETUPDI_CreateDeviceInterface(device, &iface_guid, refstr)))
4526 ERR("Failed to create device interface, error %#lx.\n", GetLastError());
4527 continue;
4530 if ((l = create_iface_key(iface, KEY_ALL_ACCESS, &iface_key)))
4532 ERR("Failed to create interface key, error %lu.\n", l);
4533 continue;
4536 SetupGetStringFieldW(&ctx, 3, iface_section, ARRAY_SIZE(iface_section), NULL);
4537 SetupInstallFromInfSectionW(NULL, hinf, iface_section, install_flags, iface_key,
4538 NULL, SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
4540 RegCloseKey(iface_key);
4541 } while (SetupFindNextMatchLineW(&ctx, AddInterface, &ctx));
4544 SetupTermDefaultQueueCallback(callback_ctx);
4546 SetupCloseInfFile(hinf);
4547 return TRUE;
4550 /***********************************************************************
4551 * SetupDiRegisterCoDeviceInstallers (SETUPAPI.@)
4553 BOOL WINAPI SetupDiRegisterCoDeviceInstallers(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4555 static const WCHAR coinstallersW[] = {'.','C','o','I','n','s','t','a','l','l','e','r','s',0};
4556 WCHAR coinst_key_ext[LINE_LEN];
4557 struct device *device;
4558 struct driver *driver;
4559 void *callback_ctx;
4560 HKEY driver_key;
4561 HINF hinf;
4562 LONG l;
4564 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
4566 if (!(device = get_device(devinfo, device_data)))
4567 return FALSE;
4569 if (!(driver = device->selected_driver))
4571 ERR("No driver selected for device %p.\n", devinfo);
4572 SetLastError(ERROR_NO_DRIVER_SELECTED);
4573 return FALSE;
4576 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4577 return FALSE;
4579 SetupDiGetActualSectionToInstallW(hinf, driver->section, coinst_key_ext, ARRAY_SIZE(coinst_key_ext), NULL, NULL);
4580 lstrcatW(coinst_key_ext, coinstallersW);
4582 if ((l = create_driver_key(device, &driver_key)))
4584 SetLastError(l);
4585 SetupCloseInfFile(hinf);
4586 return FALSE;
4589 callback_ctx = SetupInitDefaultQueueCallback(NULL);
4590 SetupInstallFromInfSectionW(NULL, hinf, coinst_key_ext, SPINST_ALL, driver_key, NULL,
4591 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
4592 SetupTermDefaultQueueCallback(callback_ctx);
4594 RegCloseKey(driver_key);
4595 SetupCloseInfFile(hinf);
4596 return TRUE;
4599 /* Check whether the given hardware or compatible ID matches any of the device's
4600 * own hardware or compatible IDs. */
4601 static BOOL device_matches_id(const struct device *device, const WCHAR *id_type, const WCHAR *id,
4602 DWORD *driver_rank)
4604 WCHAR *device_ids;
4605 const WCHAR *p;
4606 DWORD i, size;
4608 if (!RegGetValueW(device->key, NULL, id_type, RRF_RT_REG_MULTI_SZ, NULL, NULL, &size))
4610 device_ids = heap_alloc(size);
4611 if (!RegGetValueW(device->key, NULL, id_type, RRF_RT_REG_MULTI_SZ, NULL, device_ids, &size))
4613 for (p = device_ids, i = 0; *p; p += lstrlenW(p) + 1, i++)
4615 if (!wcsicmp(p, id))
4617 *driver_rank += min(i, 0xff);
4618 heap_free(device_ids);
4619 return TRUE;
4623 heap_free(device_ids);
4626 return FALSE;
4629 static BOOL version_is_compatible(const WCHAR *version)
4631 const WCHAR *machine_ext = NtPlatformExtension + 1, *p;
4632 size_t len = lstrlenW(version);
4633 BOOL wow64;
4635 /* We are only concerned with architecture. */
4636 if ((p = wcschr(version, '.')))
4637 len = p - version;
4639 if (!wcsnicmp(version, NtExtension + 1, len))
4640 return TRUE;
4642 if (IsWow64Process(GetCurrentProcess(), &wow64) && wow64)
4644 #ifdef __i386__
4645 static const WCHAR wow_ext[] = {'N','T','a','m','d','6','4',0};
4646 machine_ext = wow_ext;
4647 #elif defined(__arm__)
4648 static const WCHAR wow_ext[] = {'N','T','a','r','m','6','4',0};
4649 machine_ext = wow_ext;
4650 #endif
4653 return !wcsnicmp(version, machine_ext, len);
4656 static void enum_compat_drivers_from_file(struct device *device, const WCHAR *path)
4658 static const WCHAR manufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4659 WCHAR mfg_key[LINE_LEN], id[MAX_DEVICE_ID_LEN], version[MAX_DEVICE_ID_LEN];
4660 DWORD i, j, k, driver_count = device->driver_count;
4661 struct driver driver, *drivers = device->drivers;
4662 INFCONTEXT ctx;
4663 BOOL found;
4664 HINF hinf;
4666 TRACE("Enumerating drivers from %s.\n", debugstr_w(path));
4668 if ((hinf = SetupOpenInfFileW(path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4669 return;
4671 lstrcpyW(driver.inf_path, path);
4673 for (i = 0; SetupGetLineByIndexW(hinf, manufacturerW, i, &ctx); ++i)
4675 SetupGetStringFieldW(&ctx, 0, driver.manufacturer, ARRAY_SIZE(driver.manufacturer), NULL);
4676 if (!SetupGetStringFieldW(&ctx, 1, mfg_key, ARRAY_SIZE(mfg_key), NULL))
4677 lstrcpyW(mfg_key, driver.manufacturer);
4679 if (SetupGetFieldCount(&ctx) >= 2)
4681 BOOL compatible = FALSE;
4682 for (j = 2; SetupGetStringFieldW(&ctx, j, version, ARRAY_SIZE(version), NULL); ++j)
4684 if (version_is_compatible(version))
4686 compatible = TRUE;
4687 break;
4690 if (!compatible)
4691 continue;
4694 if (!SetupDiGetActualSectionToInstallW(hinf, mfg_key, driver.mfg_key,
4695 ARRAY_SIZE(driver.mfg_key), NULL, NULL))
4697 WARN("Failed to find section for %s, skipping.\n", debugstr_w(mfg_key));
4698 continue;
4701 for (j = 0; SetupGetLineByIndexW(hinf, driver.mfg_key, j, &ctx); ++j)
4703 driver.rank = 0;
4704 for (k = 2, found = FALSE; SetupGetStringFieldW(&ctx, k, id, ARRAY_SIZE(id), NULL); ++k)
4706 if ((found = device_matches_id(device, HardwareId, id, &driver.rank))) break;
4707 driver.rank += 0x2000;
4708 if ((found = device_matches_id(device, CompatibleIDs, id, &driver.rank))) break;
4709 driver.rank = 0x1000 + min(0x0100 * (k - 2), 0xf00);
4712 if (found)
4714 SetupGetStringFieldW(&ctx, 0, driver.description, ARRAY_SIZE(driver.description), NULL);
4715 SetupGetStringFieldW(&ctx, 1, driver.section, ARRAY_SIZE(driver.section), NULL);
4717 TRACE("Found compatible driver: rank %#lx manufacturer %s, desc %s.\n",
4718 driver.rank, debugstr_w(driver.manufacturer), debugstr_w(driver.description));
4720 driver_count++;
4721 drivers = heap_realloc(drivers, driver_count * sizeof(*drivers));
4722 drivers[driver_count - 1] = driver;
4727 SetupCloseInfFile(hinf);
4729 device->drivers = drivers;
4730 device->driver_count = driver_count;
4733 /***********************************************************************
4734 * SetupDiBuildDriverInfoList (SETUPAPI.@)
4736 BOOL WINAPI SetupDiBuildDriverInfoList(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD type)
4738 struct device *device;
4740 TRACE("devinfo %p, device_data %p, type %#lx.\n", devinfo, device_data, type);
4742 if (type != SPDIT_COMPATDRIVER)
4744 FIXME("Unhandled type %#lx.\n", type);
4745 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4746 return FALSE;
4749 if (!(device = get_device(devinfo, device_data)))
4750 return FALSE;
4752 if (device->params.Flags & DI_ENUMSINGLEINF)
4754 enum_compat_drivers_from_file(device, device->params.DriverPath);
4756 else
4758 static const WCHAR default_path[] = {'C',':','/','w','i','n','d','o','w','s','/','i','n','f',0};
4759 static const WCHAR wildcardW[] = {'*',0};
4760 WCHAR dir[MAX_PATH], file[MAX_PATH];
4761 WIN32_FIND_DATAW find_data;
4762 HANDLE find_handle;
4764 if (device->params.DriverPath[0])
4765 lstrcpyW(dir, device->params.DriverPath);
4766 else
4767 lstrcpyW(dir, default_path);
4768 lstrcatW(dir, backslashW);
4769 lstrcatW(dir, wildcardW);
4771 TRACE("Searching for drivers in %s.\n", debugstr_w(dir));
4773 if ((find_handle = FindFirstFileW(dir, &find_data)) != INVALID_HANDLE_VALUE)
4777 lstrcpyW(file, dir);
4778 lstrcpyW(file + lstrlenW(file) - 1, find_data.cFileName);
4779 enum_compat_drivers_from_file(device, file);
4780 } while (FindNextFileW(find_handle, &find_data));
4782 FindClose(find_handle);
4786 if (device->driver_count)
4788 WCHAR classname[MAX_CLASS_NAME_LEN], guidstr[39];
4789 GUID class;
4791 if (SetupDiGetINFClassW(device->drivers[0].inf_path, &class, classname, ARRAY_SIZE(classname), NULL))
4793 device_data->ClassGuid = device->class = class;
4794 SETUPDI_GuidToString(&class, guidstr);
4795 RegSetValueExW(device->key, L"ClassGUID", 0, REG_SZ, (BYTE *)guidstr, sizeof(guidstr));
4796 RegSetValueExW(device->key, L"Class", 0, REG_SZ, (BYTE *)classname, wcslen(classname) * sizeof(WCHAR));
4800 return TRUE;
4803 static BOOL copy_driver_data(SP_DRVINFO_DATA_W *data, const struct driver *driver)
4805 INFCONTEXT ctx;
4806 HINF hinf;
4808 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4809 return FALSE;
4811 data->ProviderName[0] = 0;
4812 if (SetupFindFirstLineW(hinf, L"Version", L"Provider", &ctx))
4813 SetupGetStringFieldW(&ctx, 1, data->ProviderName, ARRAY_SIZE(data->ProviderName), NULL);
4814 wcscpy(data->Description, driver->description);
4815 wcscpy(data->MfgName, driver->manufacturer);
4816 data->DriverType = SPDIT_COMPATDRIVER;
4817 data->Reserved = (ULONG_PTR)driver;
4819 SetupCloseInfFile(hinf);
4821 return TRUE;
4824 static void driver_data_wtoa(SP_DRVINFO_DATA_A *a, const SP_DRVINFO_DATA_W *w)
4826 a->DriverType = w->DriverType;
4827 a->Reserved = w->Reserved;
4828 WideCharToMultiByte(CP_ACP, 0, w->Description, -1, a->Description, sizeof(a->Description), NULL, NULL);
4829 WideCharToMultiByte(CP_ACP, 0, w->MfgName, -1, a->MfgName, sizeof(a->MfgName), NULL, NULL);
4830 WideCharToMultiByte(CP_ACP, 0, w->ProviderName, -1, a->ProviderName, sizeof(a->ProviderName), NULL, NULL);
4833 /***********************************************************************
4834 * SetupDiEnumDriverInfoW (SETUPAPI.@)
4836 BOOL WINAPI SetupDiEnumDriverInfoW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4837 DWORD type, DWORD index, SP_DRVINFO_DATA_W *driver_data)
4839 struct device *device;
4841 TRACE("devinfo %p, device_data %p, type %#lx, index %lu, driver_data %p.\n",
4842 devinfo, device_data, type, index, driver_data);
4844 if (type != SPDIT_COMPATDRIVER)
4846 FIXME("Unhandled type %#lx.\n", type);
4847 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4848 return FALSE;
4851 if (!(device = get_device(devinfo, device_data)))
4852 return FALSE;
4854 if (index >= device->driver_count)
4856 SetLastError(ERROR_NO_MORE_ITEMS);
4857 return FALSE;
4860 return copy_driver_data(driver_data, &device->drivers[index]);
4863 /***********************************************************************
4864 * SetupDiEnumDriverInfoA (SETUPAPI.@)
4866 BOOL WINAPI SetupDiEnumDriverInfoA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4867 DWORD type, DWORD index, SP_DRVINFO_DATA_A *driver_data)
4869 SP_DRVINFO_DATA_W driver_dataW;
4870 BOOL ret;
4872 driver_dataW.cbSize = sizeof(driver_dataW);
4873 ret = SetupDiEnumDriverInfoW(devinfo, device_data, type, index, &driver_dataW);
4874 if (ret) driver_data_wtoa(driver_data, &driver_dataW);
4876 return ret;
4879 /***********************************************************************
4880 * SetupDiSelectBestCompatDrv (SETUPAPI.@)
4882 BOOL WINAPI SetupDiSelectBestCompatDrv(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
4884 struct device *device;
4885 struct driver *best;
4886 DWORD i;
4888 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
4890 if (!(device = get_device(devinfo, device_data)))
4891 return FALSE;
4893 if (!device->driver_count)
4895 WARN("No compatible drivers were enumerated for device %s.\n", debugstr_w(device->instanceId));
4896 SetLastError(ERROR_NO_COMPAT_DRIVERS);
4897 return FALSE;
4900 best = device->drivers;
4901 for (i = 1; i < device->driver_count; ++i)
4903 if (device->drivers[i].rank >= best->rank) continue;
4904 best = device->drivers + i;
4907 TRACE("selected driver: rank %#lx manufacturer %s, desc %s.\n",
4908 best->rank, debugstr_w(best->manufacturer), debugstr_w(best->description));
4910 device->selected_driver = best;
4911 return TRUE;
4914 /***********************************************************************
4915 * SetupDiGetSelectedDriverW (SETUPAPI.@)
4917 BOOL WINAPI SetupDiGetSelectedDriverW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, SP_DRVINFO_DATA_W *driver_data)
4919 struct device *device;
4921 TRACE("devinfo %p, device_data %p, driver_data %p.\n", devinfo, device_data, driver_data);
4923 if (!(device = get_device(devinfo, device_data)))
4924 return FALSE;
4926 if (!device->selected_driver)
4928 SetLastError(ERROR_NO_DRIVER_SELECTED);
4929 return FALSE;
4932 return copy_driver_data(driver_data, device->selected_driver);
4935 /***********************************************************************
4936 * SetupDiGetSelectedDriverA (SETUPAPI.@)
4938 BOOL WINAPI SetupDiGetSelectedDriverA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, SP_DRVINFO_DATA_A *driver_data)
4940 SP_DRVINFO_DATA_W driver_dataW;
4941 BOOL ret;
4943 driver_dataW.cbSize = sizeof(driver_dataW);
4944 if ((ret = SetupDiGetSelectedDriverW(devinfo, device_data, &driver_dataW)))
4945 driver_data_wtoa(driver_data, &driver_dataW);
4946 return ret;
4949 /***********************************************************************
4950 * SetupDiGetDriverInfoDetailW (SETUPAPI.@)
4952 BOOL WINAPI SetupDiGetDriverInfoDetailW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
4953 SP_DRVINFO_DATA_W *driver_data, SP_DRVINFO_DETAIL_DATA_W *detail_data, const DWORD size, DWORD *ret_size)
4955 struct driver *driver = (struct driver *)driver_data->Reserved;
4956 DWORD size_needed, i, id_size = 1;
4957 WCHAR id[MAX_DEVICE_ID_LEN];
4958 INFCONTEXT ctx;
4959 HANDLE file;
4960 HINF hinf;
4962 TRACE("devinfo %p, device_data %p, driver_data %p, detail_data %p, size %lu, ret_size %p.\n",
4963 devinfo, device_data, driver_data, detail_data, size, ret_size);
4965 if ((detail_data || size) && size < sizeof(SP_DRVINFO_DETAIL_DATA_W))
4967 SetLastError(ERROR_INVALID_USER_BUFFER);
4968 return FALSE;
4971 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
4972 return FALSE;
4974 SetupFindFirstLineW(hinf, driver->mfg_key, driver->description, &ctx);
4975 for (i = 2; SetupGetStringFieldW(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
4976 id_size += wcslen(id) + 1;
4978 size_needed = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID[id_size]);
4979 if (ret_size)
4980 *ret_size = size_needed;
4981 if (!detail_data)
4982 return TRUE;
4984 detail_data->CompatIDsLength = detail_data->CompatIDsOffset = 0;
4985 detail_data->HardwareID[0] = 0;
4987 if (size >= size_needed)
4989 id_size = 0;
4990 for (i = 2; SetupGetStringFieldW(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
4992 wcscpy(&detail_data->HardwareID[id_size], id);
4993 if (i == 3)
4994 detail_data->CompatIDsOffset = id_size;
4995 id_size += wcslen(id) + 1;
4997 detail_data->HardwareID[id_size++] = 0;
4998 if (i > 3)
4999 detail_data->CompatIDsLength = id_size - detail_data->CompatIDsOffset;
5002 SetupCloseInfFile(hinf);
5004 if ((file = CreateFileW(driver->inf_path, 0, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
5005 return FALSE;
5006 GetFileTime(file, NULL, NULL, &detail_data->InfDate);
5007 CloseHandle(file);
5009 wcscpy(detail_data->SectionName, driver->section);
5010 wcscpy(detail_data->InfFileName, driver->inf_path);
5011 wcscpy(detail_data->DrvDescription, driver->description);
5013 if (size < size_needed)
5015 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5016 return FALSE;
5019 return TRUE;
5022 /***********************************************************************
5023 * SetupDiGetDriverInfoDetailA (SETUPAPI.@)
5025 BOOL WINAPI SetupDiGetDriverInfoDetailA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
5026 SP_DRVINFO_DATA_A *driver_data, SP_DRVINFO_DETAIL_DATA_A *detail_data, const DWORD size, DWORD *ret_size)
5028 struct driver *driver = (struct driver *)driver_data->Reserved;
5029 DWORD size_needed, i, id_size = 1;
5030 char id[MAX_DEVICE_ID_LEN];
5031 INFCONTEXT ctx;
5032 HANDLE file;
5033 HINF hinf;
5035 TRACE("devinfo %p, device_data %p, driver_data %p, detail_data %p, size %lu, ret_size %p.\n",
5036 devinfo, device_data, driver_data, detail_data, size, ret_size);
5038 if ((detail_data || size) && size < sizeof(SP_DRVINFO_DETAIL_DATA_A))
5040 SetLastError(ERROR_INVALID_USER_BUFFER);
5041 return FALSE;
5044 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
5045 return FALSE;
5047 SetupFindFirstLineW(hinf, driver->mfg_key, driver->description, &ctx);
5048 for (i = 2; SetupGetStringFieldA(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
5049 id_size += strlen(id) + 1;
5051 size_needed = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID[id_size]);
5052 if (ret_size)
5053 *ret_size = size_needed;
5054 if (!detail_data)
5056 SetupCloseInfFile(hinf);
5057 return TRUE;
5060 detail_data->CompatIDsLength = detail_data->CompatIDsOffset = 0;
5061 detail_data->HardwareID[0] = 0;
5063 if (size >= size_needed)
5065 id_size = 0;
5066 for (i = 2; SetupGetStringFieldA(&ctx, i, id, ARRAY_SIZE(id), NULL); ++i)
5068 strcpy(&detail_data->HardwareID[id_size], id);
5069 if (i == 3)
5070 detail_data->CompatIDsOffset = id_size;
5071 id_size += strlen(id) + 1;
5073 detail_data->HardwareID[id_size++] = 0;
5074 if (i > 3)
5075 detail_data->CompatIDsLength = id_size - detail_data->CompatIDsOffset;
5078 SetupCloseInfFile(hinf);
5080 if ((file = CreateFileW(driver->inf_path, 0, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
5081 return FALSE;
5082 GetFileTime(file, NULL, NULL, &detail_data->InfDate);
5083 CloseHandle(file);
5085 WideCharToMultiByte(CP_ACP, 0, driver->section, -1, detail_data->SectionName,
5086 sizeof(detail_data->SectionName), NULL, NULL);
5087 WideCharToMultiByte(CP_ACP, 0, driver->inf_path, -1, detail_data->InfFileName,
5088 sizeof(detail_data->InfFileName), NULL, NULL);
5089 WideCharToMultiByte(CP_ACP, 0, driver->description, -1, detail_data->DrvDescription,
5090 sizeof(detail_data->InfFileName), NULL, NULL);
5092 if (size < size_needed)
5094 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5095 return FALSE;
5098 return TRUE;
5101 /***********************************************************************
5102 * SetupDiInstallDriverFiles (SETUPAPI.@)
5104 BOOL WINAPI SetupDiInstallDriverFiles(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
5106 WCHAR section[LINE_LEN], section_ext[LINE_LEN], iface_section[LINE_LEN];
5107 struct device *device;
5108 struct driver *driver;
5109 void *callback_ctx;
5110 INFCONTEXT ctx;
5111 HINF hinf;
5113 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
5115 if (!(device = get_device(devinfo, device_data)))
5116 return FALSE;
5118 if (!(driver = device->selected_driver))
5120 ERR("No driver selected for device %p.\n", devinfo);
5121 SetLastError(ERROR_NO_DRIVER_SELECTED);
5122 return FALSE;
5125 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
5126 return FALSE;
5128 SetupFindFirstLineW(hinf, driver->mfg_key, driver->description, &ctx);
5129 SetupGetStringFieldW(&ctx, 1, section, ARRAY_SIZE(section), NULL);
5130 SetupDiGetActualSectionToInstallW(hinf, section, section_ext, ARRAY_SIZE(section_ext), NULL, NULL);
5132 callback_ctx = SetupInitDefaultQueueCallback(NULL);
5134 SetupInstallFromInfSectionW(NULL, hinf, section_ext, SPINST_FILES, NULL, NULL,
5135 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5137 lstrcatW(section_ext, dotInterfaces);
5138 if (SetupFindFirstLineW(hinf, section_ext, AddInterface, &ctx))
5140 do {
5141 SetupGetStringFieldW(&ctx, 3, iface_section, ARRAY_SIZE(iface_section), NULL);
5142 SetupInstallFromInfSectionW(NULL, hinf, iface_section, SPINST_FILES, NULL, NULL,
5143 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5144 } while (SetupFindNextMatchLineW(&ctx, AddInterface, &ctx));
5147 SetupTermDefaultQueueCallback(callback_ctx);
5149 SetupCloseInfFile(hinf);
5150 return TRUE;
5153 /***********************************************************************
5154 * SetupDiInstallDevice (SETUPAPI.@)
5156 BOOL WINAPI SetupDiInstallDevice(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
5158 static const WCHAR infpathW[] = {'I','n','f','P','a','t','h',0};
5159 static const WCHAR infsectionW[] = {'I','n','f','S','e','c','t','i','o','n',0};
5160 static const WCHAR infsectionextW[] = {'I','n','f','S','e','c','t','i','o','n','E','x','t',0};
5161 static const WCHAR dothwW[] = {'.','H','W',0};
5162 static const WCHAR dotservicesW[] = {'.','S','e','r','v','i','c','e','s',0};
5163 static const WCHAR addserviceW[] = {'A','d','d','S','e','r','v','i','c','e',0};
5164 static const WCHAR rootW[] = {'r','o','o','t','\\',0};
5165 WCHAR section_ext[LINE_LEN], subsection[LINE_LEN], inf_path[MAX_PATH], *extptr, *filepart;
5166 static const DWORD config_flags = 0;
5167 UINT install_flags = SPINST_ALL;
5168 HKEY driver_key, device_key;
5169 SC_HANDLE manager, service;
5170 WCHAR svc_name[LINE_LEN];
5171 struct device *device;
5172 struct driver *driver;
5173 void *callback_ctx;
5174 INFCONTEXT ctx;
5175 HINF hinf;
5176 LONG l;
5178 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
5180 if (!(device = get_device(devinfo, device_data)))
5181 return FALSE;
5183 if (!(driver = device->selected_driver))
5185 ERR("No driver selected for device %p.\n", devinfo);
5186 SetLastError(ERROR_NO_DRIVER_SELECTED);
5187 return FALSE;
5190 if ((hinf = SetupOpenInfFileW(driver->inf_path, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
5191 return FALSE;
5193 RegSetValueExW(device->key, L"DeviceDesc", 0, REG_SZ, (BYTE *)driver->description,
5194 wcslen(driver->description) * sizeof(WCHAR));
5196 SetupDiGetActualSectionToInstallW(hinf, driver->section, section_ext, ARRAY_SIZE(section_ext), NULL, &extptr);
5198 if ((l = create_driver_key(device, &driver_key)))
5200 SetLastError(l);
5201 SetupCloseInfFile(hinf);
5202 return FALSE;
5205 if ((l = RegCreateKeyExW(device->key, DeviceParameters, 0, NULL, 0,
5206 KEY_READ | KEY_WRITE, NULL, &device_key, NULL)))
5208 SetLastError(l);
5209 RegCloseKey(driver_key);
5210 SetupCloseInfFile(hinf);
5211 return FALSE;
5214 if (!SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_CONFIGFLAGS,
5215 (BYTE *)&config_flags, sizeof(config_flags)))
5216 ERR("Failed to set config flags, error %#lx.\n", GetLastError());
5218 if (device->params.Flags & DI_NOFILECOPY)
5219 install_flags &= ~SPINST_FILES;
5221 callback_ctx = SetupInitDefaultQueueCallback(NULL);
5223 SetupInstallFromInfSectionW(NULL, hinf, section_ext, install_flags, driver_key, NULL,
5224 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5226 lstrcpyW(subsection, section_ext);
5227 lstrcatW(subsection, dothwW);
5229 SetupInstallFromInfSectionW(NULL, hinf, subsection, install_flags, device_key, NULL,
5230 SP_COPY_NEWER_ONLY, SetupDefaultQueueCallbackW, callback_ctx, NULL, NULL);
5232 lstrcpyW(subsection, section_ext);
5233 lstrcatW(subsection, dotservicesW);
5234 SetupInstallServicesFromInfSectionW(hinf, subsection, 0);
5236 svc_name[0] = 0;
5237 if (SetupFindFirstLineW(hinf, subsection, addserviceW, &ctx))
5241 INT flags;
5243 if (SetupGetIntField(&ctx, 2, &flags) && (flags & SPSVCINST_ASSOCSERVICE))
5245 if (SetupGetStringFieldW(&ctx, 1, svc_name, ARRAY_SIZE(svc_name), NULL) && svc_name[0])
5246 RegSetValueExW(device->key, Service, 0, REG_SZ, (BYTE *)svc_name, lstrlenW(svc_name) * sizeof(WCHAR));
5247 break;
5249 } while (SetupFindNextMatchLineW(&ctx, addserviceW, &ctx));
5252 SetupTermDefaultQueueCallback(callback_ctx);
5253 SetupCloseInfFile(hinf);
5255 SetupCopyOEMInfW(driver->inf_path, NULL, SPOST_NONE, 0, inf_path, ARRAY_SIZE(inf_path), NULL, &filepart);
5256 TRACE("Copied INF file %s to %s.\n", debugstr_w(driver->inf_path), debugstr_w(inf_path));
5258 RegSetValueExW(driver_key, infpathW, 0, REG_SZ, (BYTE *)filepart, lstrlenW(filepart) * sizeof(WCHAR));
5259 RegSetValueExW(driver_key, infsectionW, 0, REG_SZ, (BYTE *)driver->section, lstrlenW(driver->section) * sizeof(WCHAR));
5260 if (extptr)
5261 RegSetValueExW(driver_key, infsectionextW, 0, REG_SZ, (BYTE *)extptr, lstrlenW(extptr) * sizeof(WCHAR));
5263 RegCloseKey(device_key);
5264 RegCloseKey(driver_key);
5266 if (!wcsnicmp(device->instanceId, rootW, lstrlenW(rootW)) && svc_name[0]
5267 && (manager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT)))
5269 if ((service = OpenServiceW(manager, svc_name, SERVICE_START | SERVICE_USER_DEFINED_CONTROL)))
5271 SERVICE_STATUS status;
5273 if (!StartServiceW(service, 0, NULL) && GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5275 ERR("Failed to start service %s for device %s, error %lu.\n",
5276 debugstr_w(svc_name), debugstr_w(device->instanceId), GetLastError());
5278 if (!ControlService(service, SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES, &status))
5280 ERR("Failed to control service %s for device %s, error %lu.\n",
5281 debugstr_w(svc_name), debugstr_w(device->instanceId), GetLastError());
5283 CloseServiceHandle(service);
5285 else
5286 ERR("Failed to open service %s for device %s.\n", debugstr_w(svc_name), debugstr_w(device->instanceId));
5287 CloseServiceHandle(manager);
5290 return TRUE;