setupapi: Implement SetupDiGetDeviceInstallParams().
[wine.git] / dlls / setupapi / devinst.c
blob8c919605ec685ddf63f9a64cf57c5738b1c775eb
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 "config.h"
22 #include "wine/port.h"
24 #include <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnt.h"
29 #include "winreg.h"
30 #include "winternl.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "winnls.h"
34 #include "setupapi.h"
35 #include "wine/debug.h"
36 #include "wine/heap.h"
37 #include "wine/list.h"
38 #include "wine/unicode.h"
39 #include "cfgmgr32.h"
40 #include "winioctl.h"
41 #include "rpc.h"
42 #include "rpcdce.h"
44 #include "setupapi_private.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
49 /* Unicode constants */
50 static const WCHAR Chicago[] = {'$','C','h','i','c','a','g','o','$',0};
51 static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0};
52 static const WCHAR Class[] = {'C','l','a','s','s',0};
53 static const WCHAR ClassInstall32[] = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
54 static const WCHAR NoDisplayClass[] = {'N','o','D','i','s','p','l','a','y','C','l','a','s','s',0};
55 static const WCHAR NoInstallClass[] = {'N','o','I','n','s','t','a','l','l','C','l','a','s','s',0};
56 static const WCHAR NoUseClass[] = {'N','o','U','s','e','C','l','a','s','s',0};
57 static const WCHAR NtExtension[] = {'.','N','T',0};
58 static const WCHAR NtPlatformExtension[] = {'.','N','T','x','8','6',0};
59 static const WCHAR Signature[] = {'S','i','g','n','a','t','u','r','e',0};
60 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
61 static const WCHAR WinExtension[] = {'.','W','i','n',0};
62 static const WCHAR WindowsNT[] = {'$','W','i','n','d','o','w','s',' ','N','T','$',0};
64 /* Registry key and value names */
65 static const WCHAR ControlClass[] = {'S','y','s','t','e','m','\\',
66 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
67 'C','o','n','t','r','o','l','\\',
68 'C','l','a','s','s',0};
70 static const WCHAR DeviceClasses[] = {'S','y','s','t','e','m','\\',
71 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
72 'C','o','n','t','r','o','l','\\',
73 'D','e','v','i','c','e','C','l','a','s','s','e','s',0};
74 static const WCHAR Enum[] = {'S','y','s','t','e','m','\\',
75 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
76 'E','n','u','m',0};
77 static const WCHAR DeviceDesc[] = {'D','e','v','i','c','e','D','e','s','c',0};
78 static const WCHAR DeviceInstance[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
79 static const WCHAR DeviceParameters[] = {'D','e','v','i','c','e',' ','P','a','r','a','m','e','t','e','r','s',0};
80 static const WCHAR HardwareId[] = {'H','a','r','d','w','a','r','e','I','D',0};
81 static const WCHAR CompatibleIDs[] = {'C','o','m','p','a','t','i','b','l','e','I','d','s',0};
82 static const WCHAR Service[] = {'S','e','r','v','i','c','e',0};
83 static const WCHAR Driver[] = {'D','r','i','v','e','r',0};
84 static const WCHAR ConfigFlags[] = {'C','o','n','f','i','g','F','l','a','g','s',0};
85 static const WCHAR Mfg[] = {'M','f','g',0};
86 static const WCHAR FriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
87 static const WCHAR LocationInformation[] = {'L','o','c','a','t','i','o','n','I','n','f','o','r','m','a','t','i','o','n',0};
88 static const WCHAR Capabilities[] = {'C','a','p','a','b','i','l','i','t','i','e','s',0};
89 static const WCHAR UINumber[] = {'U','I','N','u','m','b','e','r',0};
90 static const WCHAR UpperFilters[] = {'U','p','p','e','r','F','i','l','t','e','r','s',0};
91 static const WCHAR LowerFilters[] = {'L','o','w','e','r','F','i','l','t','e','r','s',0};
92 static const WCHAR Phantom[] = {'P','h','a','n','t','o','m',0};
93 static const WCHAR SymbolicLink[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
94 static const WCHAR Control[] = {'C','o','n','t','r','o','l',0};
95 static const WCHAR Linked[] = {'L','i','n','k','e','d',0};
96 static const WCHAR emptyW[] = {0};
98 /* is used to identify if a DeviceInfoSet pointer is
99 valid or not */
100 #define SETUP_DEVICE_INFO_SET_MAGIC 0xd00ff056
102 struct DeviceInfoSet
104 DWORD magic; /* if is equal to SETUP_DEVICE_INFO_SET_MAGIC struct is okay */
105 GUID ClassGuid;
106 HWND hwndParent;
107 struct list devices;
110 struct device
112 struct DeviceInfoSet *set;
113 HKEY key;
114 BOOL phantom;
115 WCHAR *instanceId;
116 struct list interfaces;
117 GUID class;
118 DEVINST devnode;
119 struct list entry;
120 BOOL removed;
121 SP_DEVINSTALL_PARAMS_W params;
124 struct device_iface
126 WCHAR *refstr;
127 WCHAR *symlink;
128 struct device *device;
129 GUID class;
130 DWORD flags;
131 HKEY class_key;
132 HKEY refstr_key;
133 struct list entry;
136 static struct DeviceInfoSet *get_device_set(HDEVINFO devinfo)
138 struct DeviceInfoSet *set = devinfo;
140 if (!devinfo || devinfo == INVALID_HANDLE_VALUE || set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
142 SetLastError(ERROR_INVALID_HANDLE);
143 return NULL;
146 return set;
149 static struct device *get_device(HDEVINFO devinfo, const SP_DEVINFO_DATA *data)
151 struct DeviceInfoSet *set;
152 struct device *device;
154 if (!(set = get_device_set(devinfo)))
155 return FALSE;
157 if (!data || data->cbSize != sizeof(*data) || !data->Reserved)
159 SetLastError(ERROR_INVALID_PARAMETER);
160 return NULL;
163 device = (struct device *)data->Reserved;
165 if (device->set != set)
167 SetLastError(ERROR_INVALID_PARAMETER);
168 return NULL;
171 if (device->removed)
173 SetLastError(ERROR_NO_SUCH_DEVINST);
174 return NULL;
177 return device;
180 static struct device_iface *get_device_iface(HDEVINFO devinfo, const SP_DEVICE_INTERFACE_DATA *data)
182 if (!get_device_set(devinfo))
183 return FALSE;
185 if (!data || data->cbSize != sizeof(*data) || !data->Reserved)
187 SetLastError(ERROR_INVALID_PARAMETER);
188 return NULL;
191 return (struct device_iface *)data->Reserved;
194 static inline void copy_device_data(SP_DEVINFO_DATA *data, const struct device *device)
196 data->ClassGuid = device->class;
197 data->DevInst = device->devnode;
198 data->Reserved = (ULONG_PTR)device;
201 static inline void copy_device_iface_data(SP_DEVICE_INTERFACE_DATA *data,
202 const struct device_iface *iface)
204 data->InterfaceClassGuid = iface->class;
205 data->Flags = iface->flags;
206 data->Reserved = (ULONG_PTR)iface;
209 static struct device **devnode_table;
210 static unsigned int devnode_table_size;
212 static DEVINST alloc_devnode(struct device *device)
214 unsigned int i;
216 for (i = 0; i < devnode_table_size; ++i)
218 if (!devnode_table[i])
219 break;
222 if (i == devnode_table_size)
224 if (devnode_table)
226 devnode_table_size *= 2;
227 devnode_table = heap_realloc_zero(devnode_table,
228 devnode_table_size * sizeof(*devnode_table));
230 else
232 devnode_table_size = 256;
233 devnode_table = heap_alloc_zero(devnode_table_size * sizeof(*devnode_table));
237 devnode_table[i] = device;
238 return i;
241 static void free_devnode(DEVINST devnode)
243 devnode_table[devnode] = NULL;
246 static struct device *get_devnode_device(DEVINST devnode)
248 if (devnode < devnode_table_size)
249 return devnode_table[devnode];
251 WARN("device node %u not found\n", devnode);
252 return NULL;
255 static void SETUPDI_GuidToString(const GUID *guid, LPWSTR guidStr)
257 static const WCHAR fmt[] = {'{','%','0','8','X','-','%','0','4','X','-',
258 '%','0','4','X','-','%','0','2','X','%','0','2','X','-','%','0','2',
259 'X','%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X','%',
260 '0','2','X','}',0};
262 sprintfW(guidStr, fmt, guid->Data1, guid->Data2, guid->Data3,
263 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
264 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
267 static WCHAR *get_iface_key_path(struct device_iface *iface)
269 static const WCHAR slashW[] = {'\\',0};
270 WCHAR *path, *ptr;
271 size_t len = strlenW(DeviceClasses) + 1 + 38 + 1 + strlenW(iface->symlink);
273 if (!(path = heap_alloc((len + 1) * sizeof(WCHAR))))
275 SetLastError(ERROR_OUTOFMEMORY);
276 return NULL;
279 strcpyW(path, DeviceClasses);
280 strcatW(path, slashW);
281 SETUPDI_GuidToString(&iface->class, path + strlenW(path));
282 strcatW(path, slashW);
283 ptr = path + strlenW(path);
284 strcatW(path, iface->symlink);
285 if (strlenW(iface->symlink) > 3)
286 ptr[0] = ptr[1] = ptr[3] = '#';
288 ptr = strchrW(ptr, '\\');
289 if (ptr) *ptr = 0;
291 return path;
294 static WCHAR *get_refstr_key_path(struct device_iface *iface)
296 static const WCHAR hashW[] = {'#',0};
297 static const WCHAR slashW[] = {'\\',0};
298 WCHAR *path, *ptr;
299 size_t len = strlenW(DeviceClasses) + 1 + 38 + 1 + strlenW(iface->symlink) + 1 + 1;
301 if (iface->refstr)
302 len += strlenW(iface->refstr);
304 if (!(path = heap_alloc((len + 1) * sizeof(WCHAR))))
306 SetLastError(ERROR_OUTOFMEMORY);
307 return NULL;
310 strcpyW(path, DeviceClasses);
311 strcatW(path, slashW);
312 SETUPDI_GuidToString(&iface->class, path + strlenW(path));
313 strcatW(path, slashW);
314 ptr = path + strlenW(path);
315 strcatW(path, iface->symlink);
316 if (strlenW(iface->symlink) > 3)
317 ptr[0] = ptr[1] = ptr[3] = '#';
319 ptr = strchrW(ptr, '\\');
320 if (ptr) *ptr = 0;
322 strcatW(path, slashW);
323 strcatW(path, hashW);
325 if (iface->refstr)
326 strcatW(path, iface->refstr);
328 return path;
331 static BOOL is_valid_property_type(DEVPROPTYPE prop_type)
333 DWORD type = prop_type & DEVPROP_MASK_TYPE;
334 DWORD typemod = prop_type & DEVPROP_MASK_TYPEMOD;
336 if (type > MAX_DEVPROP_TYPE)
337 return FALSE;
338 if (typemod > MAX_DEVPROP_TYPEMOD)
339 return FALSE;
341 if (typemod == DEVPROP_TYPEMOD_ARRAY
342 && (type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL || type == DEVPROP_TYPE_STRING
343 || type == DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING))
344 return FALSE;
346 if (typemod == DEVPROP_TYPEMOD_LIST
347 && !(type == DEVPROP_TYPE_STRING || type == DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING))
348 return FALSE;
350 return TRUE;
353 static LPWSTR SETUPDI_CreateSymbolicLinkPath(LPCWSTR instanceId,
354 const GUID *InterfaceClassGuid, LPCWSTR ReferenceString)
356 static const WCHAR fmt[] = {'\\','\\','?','\\','%','s','#','%','s',0};
357 WCHAR guidStr[39];
358 DWORD len;
359 LPWSTR ret;
361 SETUPDI_GuidToString(InterfaceClassGuid, guidStr);
362 /* omit length of format specifiers, but include NULL terminator: */
363 len = lstrlenW(fmt) - 4 + 1;
364 len += lstrlenW(instanceId) + lstrlenW(guidStr);
365 if (ReferenceString && *ReferenceString)
367 /* space for a hash between string and reference string: */
368 len += lstrlenW(ReferenceString) + 1;
370 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
371 if (ret)
373 int printed = sprintfW(ret, fmt, instanceId, guidStr);
374 LPWSTR ptr;
376 /* replace '\\' with '#' after the "\\\\?\\" beginning */
377 for (ptr = strchrW(ret + 4, '\\'); ptr; ptr = strchrW(ptr + 1, '\\'))
378 *ptr = '#';
379 if (ReferenceString && *ReferenceString)
381 ret[printed] = '\\';
382 lstrcpyW(ret + printed + 1, ReferenceString);
385 return ret;
388 static BOOL is_linked(HKEY key)
390 DWORD linked, type, size;
391 HKEY control_key;
392 BOOL ret = FALSE;
394 if (!RegOpenKeyW(key, Control, &control_key))
396 size = sizeof(DWORD);
397 if (!RegQueryValueExW(control_key, Linked, NULL, &type, (BYTE *)&linked, &size)
398 && type == REG_DWORD && linked)
399 ret = TRUE;
401 RegCloseKey(control_key);
404 return ret;
407 static struct device_iface *SETUPDI_CreateDeviceInterface(struct device *device,
408 const GUID *class, const WCHAR *refstr)
410 struct device_iface *iface = NULL;
411 WCHAR *refstr2 = NULL, *symlink = NULL, *path = NULL;
412 HKEY key;
413 LONG ret;
415 TRACE("%p %s %s\n", device, debugstr_guid(class), debugstr_w(refstr));
417 /* check if it already exists */
418 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
420 if (IsEqualGUID(&iface->class, class) && !lstrcmpiW(iface->refstr, refstr))
421 return iface;
424 iface = heap_alloc(sizeof(*iface));
425 symlink = SETUPDI_CreateSymbolicLinkPath(device->instanceId, class, refstr);
427 if (!iface || !symlink)
429 SetLastError(ERROR_OUTOFMEMORY);
430 goto err;
433 if (refstr && !(refstr2 = strdupW(refstr)))
435 SetLastError(ERROR_OUTOFMEMORY);
436 goto err;
438 iface->refstr = refstr2;
439 iface->symlink = symlink;
440 iface->device = device;
441 iface->class = *class;
442 iface->flags = 0;
444 if (!(path = get_iface_key_path(iface)))
446 SetLastError(ERROR_OUTOFMEMORY);
447 goto err;
450 if ((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, path, &key)))
452 SetLastError(ret);
453 goto err;
455 RegSetValueExW(key, DeviceInstance, 0, REG_SZ, (BYTE *)device->instanceId,
456 lstrlenW(device->instanceId) * sizeof(WCHAR));
457 heap_free(path);
459 iface->class_key = key;
461 if (!(path = get_refstr_key_path(iface)))
463 SetLastError(ERROR_OUTOFMEMORY);
464 goto err;
467 if ((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, path, &key)))
469 SetLastError(ret);
470 goto err;
472 RegSetValueExW(key, SymbolicLink, 0, REG_SZ, (BYTE *)iface->symlink,
473 lstrlenW(iface->symlink) * sizeof(WCHAR));
475 if (is_linked(key))
476 iface->flags |= SPINT_ACTIVE;
478 heap_free(path);
480 iface->refstr_key = key;
482 list_add_tail(&device->interfaces, &iface->entry);
483 return iface;
485 err:
486 heap_free(iface);
487 heap_free(refstr2);
488 heap_free(symlink);
489 heap_free(path);
490 return NULL;
493 static BOOL SETUPDI_SetInterfaceSymbolicLink(struct device_iface *iface,
494 const WCHAR *symlink)
496 heap_free(iface->symlink);
497 if ((iface->symlink = strdupW(symlink)))
498 return TRUE;
499 return FALSE;
502 static HKEY SETUPDI_CreateDevKey(struct device *device)
504 HKEY enumKey, key = INVALID_HANDLE_VALUE;
505 LONG l;
507 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_ALL_ACCESS,
508 NULL, &enumKey, NULL);
509 if (!l)
511 RegCreateKeyExW(enumKey, device->instanceId, 0, NULL, 0,
512 KEY_READ | KEY_WRITE, NULL, &key, NULL);
513 RegCloseKey(enumKey);
515 return key;
518 static LONG open_driver_key(struct device *device, REGSAM access, HKEY *key)
520 HKEY class_key;
521 WCHAR path[50];
522 DWORD size = sizeof(path);
523 LONG l;
525 if ((l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, ControlClass, 0, NULL, 0,
526 KEY_CREATE_SUB_KEY, NULL, &class_key, NULL)))
528 ERR("Failed to open driver class root key, error %u.\n", l);
529 return l;
532 if (!(l = RegGetValueW(device->key, NULL, Driver, RRF_RT_REG_SZ, NULL, path, &size)))
534 if (!(l = RegOpenKeyExW(class_key, path, 0, access, key)))
536 RegCloseKey(class_key);
537 return l;
539 ERR("Failed to open driver key, error %u.\n", l);
542 RegCloseKey(class_key);
543 return l;
546 static LONG create_driver_key(struct device *device, HKEY *key)
548 static const WCHAR formatW[] = {'%','0','4','u',0};
549 static const WCHAR slash[] = { '\\',0 };
550 unsigned int i = 0;
551 WCHAR path[50];
552 HKEY class_key;
553 DWORD dispos;
554 LONG l;
556 if (!open_driver_key(device, KEY_READ | KEY_WRITE, key))
557 return ERROR_SUCCESS;
559 if ((l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, ControlClass, 0, NULL, 0,
560 KEY_CREATE_SUB_KEY, NULL, &class_key, NULL)))
562 ERR("Failed to open driver class root key, error %u.\n", l);
563 return l;
566 SETUPDI_GuidToString(&device->class, path);
567 strcatW(path, slash);
568 /* Allocate a new driver key, by finding the first integer value that's not
569 * already taken. */
570 for (;;)
572 sprintfW(path + 39, formatW, i++);
573 if ((l = RegCreateKeyExW(class_key, path, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, key, &dispos)))
574 break;
575 else if (dispos == REG_CREATED_NEW_KEY)
577 RegSetValueExW(device->key, Driver, 0, REG_SZ, (BYTE *)path, strlenW(path) * sizeof(WCHAR));
578 RegCloseKey(class_key);
579 return ERROR_SUCCESS;
581 RegCloseKey(*key);
583 ERR("Failed to create driver key, error %u.\n", l);
584 RegCloseKey(class_key);
585 return l;
588 static LONG delete_driver_key(struct device *device)
590 HKEY key;
591 LONG l;
593 if (!(l = open_driver_key(device, KEY_READ | KEY_WRITE, &key)))
595 l = RegDeleteKeyW(key, emptyW);
596 RegCloseKey(key);
599 return l;
602 struct PropertyMapEntry
604 DWORD regType;
605 LPCSTR nameA;
606 LPCWSTR nameW;
609 static const struct PropertyMapEntry PropertyMap[] = {
610 { REG_SZ, "DeviceDesc", DeviceDesc },
611 { REG_MULTI_SZ, "HardwareId", HardwareId },
612 { REG_MULTI_SZ, "CompatibleIDs", CompatibleIDs },
613 { 0, NULL, NULL }, /* SPDRP_UNUSED0 */
614 { REG_SZ, "Service", Service },
615 { 0, NULL, NULL }, /* SPDRP_UNUSED1 */
616 { 0, NULL, NULL }, /* SPDRP_UNUSED2 */
617 { REG_SZ, "Class", Class },
618 { REG_SZ, "ClassGUID", ClassGUID },
619 { REG_SZ, "Driver", Driver },
620 { REG_DWORD, "ConfigFlags", ConfigFlags },
621 { REG_SZ, "Mfg", Mfg },
622 { REG_SZ, "FriendlyName", FriendlyName },
623 { REG_SZ, "LocationInformation", LocationInformation },
624 { 0, NULL, NULL }, /* SPDRP_PHYSICAL_DEVICE_OBJECT_NAME */
625 { REG_DWORD, "Capabilities", Capabilities },
626 { REG_DWORD, "UINumber", UINumber },
627 { REG_MULTI_SZ, "UpperFilters", UpperFilters },
628 { REG_MULTI_SZ, "LowerFilters", LowerFilters },
631 static BOOL SETUPDI_SetDeviceRegistryPropertyW(struct device *device,
632 DWORD prop, const BYTE *buffer, DWORD size)
634 if (prop < ARRAY_SIZE(PropertyMap) && PropertyMap[prop].nameW)
636 LONG ret = RegSetValueExW(device->key, PropertyMap[prop].nameW, 0,
637 PropertyMap[prop].regType, buffer, size);
638 if (!ret)
639 return TRUE;
641 SetLastError(ret);
643 return FALSE;
646 static void remove_device_iface(struct device_iface *iface)
648 RegDeleteTreeW(iface->refstr_key, NULL);
649 RegDeleteKeyW(iface->refstr_key, emptyW);
650 RegCloseKey(iface->refstr_key);
651 iface->refstr_key = NULL;
652 /* Also remove the class key if it's empty. */
653 RegDeleteKeyW(iface->class_key, emptyW);
654 RegCloseKey(iface->class_key);
655 iface->class_key = NULL;
656 iface->flags |= SPINT_REMOVED;
659 static void delete_device_iface(struct device_iface *iface)
661 list_remove(&iface->entry);
662 RegCloseKey(iface->refstr_key);
663 RegCloseKey(iface->class_key);
664 heap_free(iface->refstr);
665 heap_free(iface->symlink);
666 heap_free(iface);
669 static void remove_device(struct device *device)
671 WCHAR id[MAX_DEVICE_ID_LEN], *p;
672 struct device_iface *iface;
673 HKEY enum_key;
675 delete_driver_key(device);
677 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
679 remove_device_iface(iface);
682 RegDeleteTreeW(device->key, NULL);
683 RegDeleteKeyW(device->key, emptyW);
685 /* delete all empty parents of the key */
686 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, 0, &enum_key))
688 strcpyW(id, device->instanceId);
690 while ((p = strrchrW(id, '\\')))
692 *p = 0;
693 RegDeleteKeyW(enum_key, id);
696 RegCloseKey(enum_key);
699 RegCloseKey(device->key);
700 device->key = NULL;
701 device->removed = TRUE;
704 static void delete_device(struct device *device)
706 struct device_iface *iface, *next;
708 if (device->phantom)
709 remove_device(device);
711 RegCloseKey(device->key);
712 heap_free(device->instanceId);
714 LIST_FOR_EACH_ENTRY_SAFE(iface, next, &device->interfaces,
715 struct device_iface, entry)
717 delete_device_iface(iface);
719 free_devnode(device->devnode);
720 list_remove(&device->entry);
721 heap_free(device);
724 static struct device *SETUPDI_CreateDeviceInfo(struct DeviceInfoSet *set,
725 const GUID *class, const WCHAR *instanceid, BOOL phantom)
727 const DWORD one = 1;
728 struct device *device;
729 WCHAR guidstr[39];
731 TRACE("%p, %s, %s, %d\n", set, debugstr_guid(class),
732 debugstr_w(instanceid), phantom);
734 if (!(device = heap_alloc_zero(sizeof(*device))))
736 SetLastError(ERROR_OUTOFMEMORY);
737 return NULL;
740 if (!(device->instanceId = strdupW(instanceid)))
742 SetLastError(ERROR_OUTOFMEMORY);
743 heap_free(device);
744 return NULL;
747 struprW(device->instanceId);
748 device->set = set;
749 device->key = SETUPDI_CreateDevKey(device);
750 device->phantom = phantom;
751 list_init(&device->interfaces);
752 device->class = *class;
753 device->devnode = alloc_devnode(device);
754 device->removed = FALSE;
755 list_add_tail(&set->devices, &device->entry);
756 device->params.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
758 if (phantom)
759 RegSetValueExW(device->key, Phantom, 0, REG_DWORD, (const BYTE *)&one, sizeof(one));
761 SETUPDI_GuidToString(class, guidstr);
762 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_CLASSGUID,
763 (const BYTE *)guidstr, sizeof(guidstr));
764 return device;
767 /***********************************************************************
768 * SetupDiBuildClassInfoList (SETUPAPI.@)
770 * Returns a list of setup class GUIDs that identify the classes
771 * that are installed on a local machine.
773 * PARAMS
774 * Flags [I] control exclusion of classes from the list.
775 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
776 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
777 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
779 * RETURNS
780 * Success: TRUE.
781 * Failure: FALSE.
783 BOOL WINAPI SetupDiBuildClassInfoList(
784 DWORD Flags,
785 LPGUID ClassGuidList,
786 DWORD ClassGuidListSize,
787 PDWORD RequiredSize)
789 TRACE("\n");
790 return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
791 ClassGuidListSize, RequiredSize,
792 NULL, NULL);
795 /***********************************************************************
796 * SetupDiBuildClassInfoListExA (SETUPAPI.@)
798 * Returns a list of setup class GUIDs that identify the classes
799 * that are installed on a local or remote machine.
801 * PARAMS
802 * Flags [I] control exclusion of classes from the list.
803 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
804 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
805 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
806 * MachineName [I] name of a remote machine.
807 * Reserved [I] must be NULL.
809 * RETURNS
810 * Success: TRUE.
811 * Failure: FALSE.
813 BOOL WINAPI SetupDiBuildClassInfoListExA(
814 DWORD Flags,
815 LPGUID ClassGuidList,
816 DWORD ClassGuidListSize,
817 PDWORD RequiredSize,
818 LPCSTR MachineName,
819 PVOID Reserved)
821 LPWSTR MachineNameW = NULL;
822 BOOL bResult;
824 TRACE("\n");
826 if (MachineName)
828 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
829 if (MachineNameW == NULL) return FALSE;
832 bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
833 ClassGuidListSize, RequiredSize,
834 MachineNameW, Reserved);
836 MyFree(MachineNameW);
838 return bResult;
841 /***********************************************************************
842 * SetupDiBuildClassInfoListExW (SETUPAPI.@)
844 * Returns a list of setup class GUIDs that identify the classes
845 * that are installed on a local or remote machine.
847 * PARAMS
848 * Flags [I] control exclusion of classes from the list.
849 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
850 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
851 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
852 * MachineName [I] name of a remote machine.
853 * Reserved [I] must be NULL.
855 * RETURNS
856 * Success: TRUE.
857 * Failure: FALSE.
859 BOOL WINAPI SetupDiBuildClassInfoListExW(
860 DWORD Flags,
861 LPGUID ClassGuidList,
862 DWORD ClassGuidListSize,
863 PDWORD RequiredSize,
864 LPCWSTR MachineName,
865 PVOID Reserved)
867 WCHAR szKeyName[40];
868 HKEY hClassesKey;
869 HKEY hClassKey;
870 DWORD dwLength;
871 DWORD dwIndex;
872 LONG lError;
873 DWORD dwGuidListIndex = 0;
875 TRACE("\n");
877 if (RequiredSize != NULL)
878 *RequiredSize = 0;
880 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
881 KEY_ALL_ACCESS,
882 DIOCR_INSTALLER,
883 MachineName,
884 Reserved);
885 if (hClassesKey == INVALID_HANDLE_VALUE)
887 return FALSE;
890 for (dwIndex = 0; ; dwIndex++)
892 dwLength = 40;
893 lError = RegEnumKeyExW(hClassesKey,
894 dwIndex,
895 szKeyName,
896 &dwLength,
897 NULL,
898 NULL,
899 NULL,
900 NULL);
901 TRACE("RegEnumKeyExW() returns %d\n", lError);
902 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
904 TRACE("Key name: %p\n", szKeyName);
906 if (RegOpenKeyExW(hClassesKey,
907 szKeyName,
909 KEY_ALL_ACCESS,
910 &hClassKey))
912 RegCloseKey(hClassesKey);
913 return FALSE;
916 if (!RegQueryValueExW(hClassKey,
917 NoUseClass,
918 NULL,
919 NULL,
920 NULL,
921 NULL))
923 TRACE("'NoUseClass' value found!\n");
924 RegCloseKey(hClassKey);
925 continue;
928 if ((Flags & DIBCI_NOINSTALLCLASS) &&
929 (!RegQueryValueExW(hClassKey,
930 NoInstallClass,
931 NULL,
932 NULL,
933 NULL,
934 NULL)))
936 TRACE("'NoInstallClass' value found!\n");
937 RegCloseKey(hClassKey);
938 continue;
941 if ((Flags & DIBCI_NODISPLAYCLASS) &&
942 (!RegQueryValueExW(hClassKey,
943 NoDisplayClass,
944 NULL,
945 NULL,
946 NULL,
947 NULL)))
949 TRACE("'NoDisplayClass' value found!\n");
950 RegCloseKey(hClassKey);
951 continue;
954 RegCloseKey(hClassKey);
956 TRACE("Guid: %p\n", szKeyName);
957 if (dwGuidListIndex < ClassGuidListSize)
959 if (szKeyName[0] == '{' && szKeyName[37] == '}')
961 szKeyName[37] = 0;
963 TRACE("Guid: %p\n", &szKeyName[1]);
965 UuidFromStringW(&szKeyName[1],
966 &ClassGuidList[dwGuidListIndex]);
969 dwGuidListIndex++;
972 if (lError != ERROR_SUCCESS)
973 break;
976 RegCloseKey(hClassesKey);
978 if (RequiredSize != NULL)
979 *RequiredSize = dwGuidListIndex;
981 if (ClassGuidListSize < dwGuidListIndex)
983 SetLastError(ERROR_INSUFFICIENT_BUFFER);
984 return FALSE;
987 return TRUE;
990 /***********************************************************************
991 * SetupDiClassGuidsFromNameA (SETUPAPI.@)
993 BOOL WINAPI SetupDiClassGuidsFromNameA(
994 LPCSTR ClassName,
995 LPGUID ClassGuidList,
996 DWORD ClassGuidListSize,
997 PDWORD RequiredSize)
999 return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
1000 ClassGuidListSize, RequiredSize,
1001 NULL, NULL);
1004 /***********************************************************************
1005 * SetupDiClassGuidsFromNameW (SETUPAPI.@)
1007 BOOL WINAPI SetupDiClassGuidsFromNameW(
1008 LPCWSTR ClassName,
1009 LPGUID ClassGuidList,
1010 DWORD ClassGuidListSize,
1011 PDWORD RequiredSize)
1013 return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
1014 ClassGuidListSize, RequiredSize,
1015 NULL, NULL);
1018 /***********************************************************************
1019 * SetupDiClassGuidsFromNameExA (SETUPAPI.@)
1021 BOOL WINAPI SetupDiClassGuidsFromNameExA(
1022 LPCSTR ClassName,
1023 LPGUID ClassGuidList,
1024 DWORD ClassGuidListSize,
1025 PDWORD RequiredSize,
1026 LPCSTR MachineName,
1027 PVOID Reserved)
1029 LPWSTR ClassNameW = NULL;
1030 LPWSTR MachineNameW = NULL;
1031 BOOL bResult;
1033 ClassNameW = MultiByteToUnicode(ClassName, CP_ACP);
1034 if (ClassNameW == NULL)
1035 return FALSE;
1037 if (MachineName)
1039 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1040 if (MachineNameW == NULL)
1042 MyFree(ClassNameW);
1043 return FALSE;
1047 bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
1048 ClassGuidListSize, RequiredSize,
1049 MachineNameW, Reserved);
1051 MyFree(MachineNameW);
1052 MyFree(ClassNameW);
1054 return bResult;
1057 /***********************************************************************
1058 * SetupDiClassGuidsFromNameExW (SETUPAPI.@)
1060 BOOL WINAPI SetupDiClassGuidsFromNameExW(
1061 LPCWSTR ClassName,
1062 LPGUID ClassGuidList,
1063 DWORD ClassGuidListSize,
1064 PDWORD RequiredSize,
1065 LPCWSTR MachineName,
1066 PVOID Reserved)
1068 WCHAR szKeyName[40];
1069 WCHAR szClassName[256];
1070 HKEY hClassesKey;
1071 HKEY hClassKey;
1072 DWORD dwLength;
1073 DWORD dwIndex;
1074 LONG lError;
1075 DWORD dwGuidListIndex = 0;
1077 if (RequiredSize != NULL)
1078 *RequiredSize = 0;
1080 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
1081 KEY_ALL_ACCESS,
1082 DIOCR_INSTALLER,
1083 MachineName,
1084 Reserved);
1085 if (hClassesKey == INVALID_HANDLE_VALUE)
1087 return FALSE;
1090 for (dwIndex = 0; ; dwIndex++)
1092 dwLength = ARRAY_SIZE(szKeyName);
1093 lError = RegEnumKeyExW(hClassesKey,
1094 dwIndex,
1095 szKeyName,
1096 &dwLength,
1097 NULL,
1098 NULL,
1099 NULL,
1100 NULL);
1101 TRACE("RegEnumKeyExW() returns %d\n", lError);
1102 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
1104 TRACE("Key name: %p\n", szKeyName);
1106 if (RegOpenKeyExW(hClassesKey,
1107 szKeyName,
1109 KEY_ALL_ACCESS,
1110 &hClassKey))
1112 RegCloseKey(hClassesKey);
1113 return FALSE;
1116 dwLength = sizeof(szClassName);
1117 if (!RegQueryValueExW(hClassKey,
1118 Class,
1119 NULL,
1120 NULL,
1121 (LPBYTE)szClassName,
1122 &dwLength))
1124 TRACE("Class name: %p\n", szClassName);
1126 if (strcmpiW(szClassName, ClassName) == 0)
1128 TRACE("Found matching class name\n");
1130 TRACE("Guid: %p\n", szKeyName);
1131 if (dwGuidListIndex < ClassGuidListSize)
1133 if (szKeyName[0] == '{' && szKeyName[37] == '}')
1135 szKeyName[37] = 0;
1137 TRACE("Guid: %p\n", &szKeyName[1]);
1139 UuidFromStringW(&szKeyName[1],
1140 &ClassGuidList[dwGuidListIndex]);
1143 dwGuidListIndex++;
1147 RegCloseKey(hClassKey);
1150 if (lError != ERROR_SUCCESS)
1151 break;
1154 RegCloseKey(hClassesKey);
1156 if (RequiredSize != NULL)
1157 *RequiredSize = dwGuidListIndex;
1159 if (ClassGuidListSize < dwGuidListIndex)
1161 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1162 return FALSE;
1165 return TRUE;
1168 /***********************************************************************
1169 * SetupDiClassNameFromGuidA (SETUPAPI.@)
1171 BOOL WINAPI SetupDiClassNameFromGuidA(
1172 const GUID* ClassGuid,
1173 PSTR ClassName,
1174 DWORD ClassNameSize,
1175 PDWORD RequiredSize)
1177 return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
1178 ClassNameSize, RequiredSize,
1179 NULL, NULL);
1182 /***********************************************************************
1183 * SetupDiClassNameFromGuidW (SETUPAPI.@)
1185 BOOL WINAPI SetupDiClassNameFromGuidW(
1186 const GUID* ClassGuid,
1187 PWSTR ClassName,
1188 DWORD ClassNameSize,
1189 PDWORD RequiredSize)
1191 return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
1192 ClassNameSize, RequiredSize,
1193 NULL, NULL);
1196 /***********************************************************************
1197 * SetupDiClassNameFromGuidExA (SETUPAPI.@)
1199 BOOL WINAPI SetupDiClassNameFromGuidExA(
1200 const GUID* ClassGuid,
1201 PSTR ClassName,
1202 DWORD ClassNameSize,
1203 PDWORD RequiredSize,
1204 PCSTR MachineName,
1205 PVOID Reserved)
1207 WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
1208 LPWSTR MachineNameW = NULL;
1209 BOOL ret;
1211 if (MachineName)
1212 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1213 ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
1214 NULL, MachineNameW, Reserved);
1215 if (ret)
1217 int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
1218 ClassNameSize, NULL, NULL);
1220 if (!ClassNameSize && RequiredSize)
1221 *RequiredSize = len;
1223 MyFree(MachineNameW);
1224 return ret;
1227 /***********************************************************************
1228 * SetupDiClassNameFromGuidExW (SETUPAPI.@)
1230 BOOL WINAPI SetupDiClassNameFromGuidExW(
1231 const GUID* ClassGuid,
1232 PWSTR ClassName,
1233 DWORD ClassNameSize,
1234 PDWORD RequiredSize,
1235 PCWSTR MachineName,
1236 PVOID Reserved)
1238 HKEY hKey;
1239 DWORD dwLength;
1241 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
1242 KEY_ALL_ACCESS,
1243 DIOCR_INSTALLER,
1244 MachineName,
1245 Reserved);
1246 if (hKey == INVALID_HANDLE_VALUE)
1248 return FALSE;
1251 if (RequiredSize != NULL)
1253 dwLength = 0;
1254 if (RegQueryValueExW(hKey,
1255 Class,
1256 NULL,
1257 NULL,
1258 NULL,
1259 &dwLength))
1261 RegCloseKey(hKey);
1262 return FALSE;
1265 *RequiredSize = dwLength / sizeof(WCHAR);
1268 dwLength = ClassNameSize * sizeof(WCHAR);
1269 if (RegQueryValueExW(hKey,
1270 Class,
1271 NULL,
1272 NULL,
1273 (LPBYTE)ClassName,
1274 &dwLength))
1276 RegCloseKey(hKey);
1277 return FALSE;
1280 RegCloseKey(hKey);
1282 return TRUE;
1285 /***********************************************************************
1286 * SetupDiCreateDeviceInfoList (SETUPAPI.@)
1288 HDEVINFO WINAPI
1289 SetupDiCreateDeviceInfoList(const GUID *ClassGuid,
1290 HWND hwndParent)
1292 return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
1295 /***********************************************************************
1296 * SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
1298 HDEVINFO WINAPI
1299 SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
1300 HWND hwndParent,
1301 PCSTR MachineName,
1302 PVOID Reserved)
1304 LPWSTR MachineNameW = NULL;
1305 HDEVINFO hDevInfo;
1307 TRACE("\n");
1309 if (MachineName)
1311 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1312 if (MachineNameW == NULL)
1313 return INVALID_HANDLE_VALUE;
1316 hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
1317 MachineNameW, Reserved);
1319 MyFree(MachineNameW);
1321 return hDevInfo;
1324 /***********************************************************************
1325 * SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
1327 * Create an empty DeviceInfoSet list.
1329 * PARAMS
1330 * ClassGuid [I] if not NULL only devices with GUID ClassGuid are associated
1331 * with this list.
1332 * hwndParent [I] hwnd needed for interface related actions.
1333 * MachineName [I] name of machine to create empty DeviceInfoSet list, if NULL
1334 * local registry will be used.
1335 * Reserved [I] must be NULL
1337 * RETURNS
1338 * Success: empty list.
1339 * Failure: INVALID_HANDLE_VALUE.
1341 HDEVINFO WINAPI
1342 SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
1343 HWND hwndParent,
1344 PCWSTR MachineName,
1345 PVOID Reserved)
1347 struct DeviceInfoSet *list = NULL;
1348 DWORD size = sizeof(struct DeviceInfoSet);
1350 TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
1351 debugstr_w(MachineName), Reserved);
1353 if (MachineName && *MachineName)
1355 FIXME("remote support is not implemented\n");
1356 SetLastError(ERROR_INVALID_MACHINENAME);
1357 return INVALID_HANDLE_VALUE;
1360 if (Reserved != NULL)
1362 SetLastError(ERROR_INVALID_PARAMETER);
1363 return INVALID_HANDLE_VALUE;
1366 list = HeapAlloc(GetProcessHeap(), 0, size);
1367 if (!list)
1369 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1370 return INVALID_HANDLE_VALUE;
1373 list->magic = SETUP_DEVICE_INFO_SET_MAGIC;
1374 list->hwndParent = hwndParent;
1375 memcpy(&list->ClassGuid,
1376 ClassGuid ? ClassGuid : &GUID_NULL,
1377 sizeof(list->ClassGuid));
1378 list_init(&list->devices);
1380 return list;
1383 /***********************************************************************
1384 * SetupDiCreateDevRegKeyA (SETUPAPI.@)
1386 HKEY WINAPI SetupDiCreateDevRegKeyA(
1387 HDEVINFO DeviceInfoSet,
1388 PSP_DEVINFO_DATA DeviceInfoData,
1389 DWORD Scope,
1390 DWORD HwProfile,
1391 DWORD KeyType,
1392 HINF InfHandle,
1393 PCSTR InfSectionName)
1395 PWSTR InfSectionNameW = NULL;
1396 HKEY key;
1398 TRACE("%p %p %d %d %d %p %s\n", DeviceInfoSet, DeviceInfoData, Scope,
1399 HwProfile, KeyType, InfHandle, debugstr_a(InfSectionName));
1401 if (InfHandle)
1403 if (!InfSectionName)
1405 SetLastError(ERROR_INVALID_PARAMETER);
1406 return INVALID_HANDLE_VALUE;
1408 else
1410 InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
1411 if (InfSectionNameW == NULL) return INVALID_HANDLE_VALUE;
1414 key = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, Scope,
1415 HwProfile, KeyType, InfHandle, InfSectionNameW);
1416 MyFree(InfSectionNameW);
1417 return key;
1420 /***********************************************************************
1421 * SetupDiCreateDevRegKeyW (SETUPAPI.@)
1423 HKEY WINAPI SetupDiCreateDevRegKeyW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD Scope,
1424 DWORD HwProfile, DWORD KeyType, HINF InfHandle, const WCHAR *InfSectionName)
1426 struct device *device;
1427 HKEY key = INVALID_HANDLE_VALUE;
1428 LONG l;
1430 TRACE("devinfo %p, device_data %p, scope %d, profile %d, type %d, inf_handle %p, inf_section %s.\n",
1431 devinfo, device_data, Scope, HwProfile, KeyType, InfHandle, debugstr_w(InfSectionName));
1433 if (!(device = get_device(devinfo, device_data)))
1434 return INVALID_HANDLE_VALUE;
1436 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
1438 SetLastError(ERROR_INVALID_FLAGS);
1439 return INVALID_HANDLE_VALUE;
1441 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
1443 SetLastError(ERROR_INVALID_FLAGS);
1444 return INVALID_HANDLE_VALUE;
1446 if (device->phantom)
1448 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
1449 return INVALID_HANDLE_VALUE;
1451 if (Scope != DICS_FLAG_GLOBAL)
1452 FIXME("unimplemented for scope %d\n", Scope);
1453 switch (KeyType)
1455 case DIREG_DEV:
1456 l = RegCreateKeyExW(device->key, DeviceParameters, 0, NULL, 0,
1457 KEY_READ | KEY_WRITE, NULL, &key, NULL);
1458 break;
1459 case DIREG_DRV:
1460 l = create_driver_key(device, &key);
1461 break;
1462 default:
1463 FIXME("Unhandled type %#x.\n", KeyType);
1464 l = ERROR_CALL_NOT_IMPLEMENTED;
1466 if (InfHandle)
1467 SetupInstallFromInfSectionW(NULL, InfHandle, InfSectionName, SPINST_ALL,
1468 NULL, NULL, SP_COPY_NEWER_ONLY, NULL, NULL, devinfo, device_data);
1469 SetLastError(l);
1470 return l ? INVALID_HANDLE_VALUE : key;
1473 /***********************************************************************
1474 * SetupDiCreateDeviceInfoA (SETUPAPI.@)
1476 BOOL WINAPI SetupDiCreateDeviceInfoA(HDEVINFO DeviceInfoSet, const char *name,
1477 const GUID *ClassGuid, PCSTR DeviceDescription, HWND hwndParent, DWORD CreationFlags,
1478 PSP_DEVINFO_DATA DeviceInfoData)
1480 WCHAR nameW[MAX_DEVICE_ID_LEN];
1481 BOOL ret = FALSE;
1482 LPWSTR DeviceDescriptionW = NULL;
1484 if (!name || strlen(name) >= MAX_DEVICE_ID_LEN)
1486 SetLastError(ERROR_INVALID_DEVINST_NAME);
1487 return FALSE;
1490 MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, ARRAY_SIZE(nameW));
1492 if (DeviceDescription)
1494 DeviceDescriptionW = MultiByteToUnicode(DeviceDescription, CP_ACP);
1495 if (DeviceDescriptionW == NULL)
1496 return FALSE;
1499 ret = SetupDiCreateDeviceInfoW(DeviceInfoSet, nameW, ClassGuid, DeviceDescriptionW,
1500 hwndParent, CreationFlags, DeviceInfoData);
1502 MyFree(DeviceDescriptionW);
1504 return ret;
1507 /***********************************************************************
1508 * SetupDiCreateDeviceInfoW (SETUPAPI.@)
1510 BOOL WINAPI SetupDiCreateDeviceInfoW(HDEVINFO devinfo, const WCHAR *name, const GUID *class,
1511 const WCHAR *description, HWND parent, DWORD flags, SP_DEVINFO_DATA *device_data)
1513 WCHAR id[MAX_DEVICE_ID_LEN];
1514 struct DeviceInfoSet *set;
1515 HKEY enum_hkey;
1516 HKEY instance_hkey;
1517 struct device *device;
1518 LONG l;
1520 TRACE("devinfo %p, name %s, class %s, description %s, hwnd %p, flags %#x, device_data %p.\n",
1521 devinfo, debugstr_w(name), debugstr_guid(class), debugstr_w(description),
1522 parent, flags, device_data);
1524 if (!name || strlenW(name) >= MAX_DEVICE_ID_LEN)
1526 SetLastError(ERROR_INVALID_DEVINST_NAME);
1527 return FALSE;
1530 if (!(set = get_device_set(devinfo)))
1531 return FALSE;
1533 if (!class)
1535 SetLastError(ERROR_INVALID_PARAMETER);
1536 return FALSE;
1539 if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) && !IsEqualGUID(class, &set->ClassGuid))
1541 SetLastError(ERROR_CLASS_MISMATCH);
1542 return FALSE;
1544 if ((flags & DICD_GENERATE_ID))
1546 static const WCHAR formatW[] = {'R','O','O','T','\\','%','s','\\','%','0','4','u',0};
1547 unsigned int instance_id;
1549 if (strchrW(name, '\\'))
1551 SetLastError(ERROR_INVALID_DEVINST_NAME);
1552 return FALSE;
1555 for (instance_id = 0; ; ++instance_id)
1557 if (snprintfW(id, ARRAY_SIZE(id), formatW, name, instance_id) == -1)
1559 SetLastError(ERROR_INVALID_DEVINST_NAME);
1560 return FALSE;
1563 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL, &enum_hkey, NULL);
1564 if (!(l = RegOpenKeyExW(enum_hkey, id, 0, KEY_READ, &instance_hkey)))
1565 RegCloseKey(instance_hkey);
1566 if (l == ERROR_FILE_NOT_FOUND)
1567 break;
1568 RegCloseKey(enum_hkey);
1571 else
1573 /* Check if instance is already in registry */
1574 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL, &enum_hkey, NULL);
1575 if (!RegOpenKeyExW(enum_hkey, name, 0, KEY_READ, &instance_hkey))
1577 RegCloseKey(instance_hkey);
1578 RegCloseKey(enum_hkey);
1579 SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
1580 return FALSE;
1582 RegCloseKey(enum_hkey);
1584 /* Check if instance is already in set */
1585 strcpyW(id, name);
1586 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
1588 if (!lstrcmpiW(name, device->instanceId))
1590 SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
1591 return FALSE;
1596 if (!(device = SETUPDI_CreateDeviceInfo(set, class, id, TRUE)))
1597 return FALSE;
1599 if (description)
1601 SETUPDI_SetDeviceRegistryPropertyW(device, SPDRP_DEVICEDESC,
1602 (const BYTE *)description, lstrlenW(description) * sizeof(WCHAR));
1605 if (device_data)
1607 if (device_data->cbSize != sizeof(SP_DEVINFO_DATA))
1609 SetLastError(ERROR_INVALID_USER_BUFFER);
1610 return FALSE;
1612 else
1613 copy_device_data(device_data, device);
1616 return TRUE;
1619 /***********************************************************************
1620 * SetupDiRegisterDeviceInfo (SETUPAPI.@)
1622 BOOL WINAPI SetupDiRegisterDeviceInfo(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data, DWORD flags,
1623 PSP_DETSIG_CMPPROC compare_proc, void *context, SP_DEVINFO_DATA *duplicate_data)
1625 struct device *device;
1627 TRACE("devinfo %p, data %p, flags %#x, compare_proc %p, context %p, duplicate_data %p.\n",
1628 devinfo, device_data, flags, compare_proc, context, duplicate_data);
1630 if (!(device = get_device(devinfo, device_data)))
1631 return FALSE;
1633 if (device->phantom)
1635 device->phantom = FALSE;
1636 RegDeleteValueW(device->key, Phantom);
1638 return TRUE;
1641 /***********************************************************************
1642 * SetupDiRemoveDevice (SETUPAPI.@)
1644 BOOL WINAPI SetupDiRemoveDevice(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
1646 struct device *device;
1648 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
1650 if (!(device = get_device(devinfo, device_data)))
1651 return FALSE;
1653 remove_device(device);
1655 return TRUE;
1658 /***********************************************************************
1659 * SetupDiDeleteDeviceInfo (SETUPAPI.@)
1661 BOOL WINAPI SetupDiDeleteDeviceInfo(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data)
1663 struct device *device;
1665 TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
1667 if (!(device = get_device(devinfo, device_data)))
1668 return FALSE;
1670 delete_device(device);
1672 return TRUE;
1675 /***********************************************************************
1676 * SetupDiRemoveDeviceInterface (SETUPAPI.@)
1678 BOOL WINAPI SetupDiRemoveDeviceInterface(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data)
1680 struct device_iface *iface;
1682 TRACE("devinfo %p, iface_data %p.\n", devinfo, iface_data);
1684 if (!(iface = get_device_iface(devinfo, iface_data)))
1685 return FALSE;
1687 remove_device_iface(iface);
1689 return TRUE;
1692 /***********************************************************************
1693 * SetupDiDeleteDeviceInterfaceData (SETUPAPI.@)
1695 BOOL WINAPI SetupDiDeleteDeviceInterfaceData(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data)
1697 struct device_iface *iface;
1699 TRACE("devinfo %p, iface_data %p.\n", devinfo, iface_data);
1701 if (!(iface = get_device_iface(devinfo, iface_data)))
1702 return FALSE;
1704 delete_device_iface(iface);
1706 return TRUE;
1709 /***********************************************************************
1710 * SetupDiEnumDeviceInfo (SETUPAPI.@)
1712 BOOL WINAPI DECLSPEC_HOTPATCH SetupDiEnumDeviceInfo(HDEVINFO devinfo, DWORD index, SP_DEVINFO_DATA *device_data)
1714 struct DeviceInfoSet *set;
1715 struct device *device;
1716 DWORD i = 0;
1718 TRACE("devinfo %p, index %d, device_data %p\n", devinfo, index, device_data);
1720 if (!(set = get_device_set(devinfo)))
1721 return FALSE;
1723 if (!device_data)
1725 SetLastError(ERROR_INVALID_PARAMETER);
1726 return FALSE;
1729 if (device_data->cbSize != sizeof(SP_DEVINFO_DATA))
1731 SetLastError(ERROR_INVALID_USER_BUFFER);
1732 return FALSE;
1735 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
1737 if (i++ == index)
1739 copy_device_data(device_data, device);
1740 return TRUE;
1744 SetLastError(ERROR_NO_MORE_ITEMS);
1745 return FALSE;
1748 /***********************************************************************
1749 * SetupDiGetDeviceInstanceIdA (SETUPAPI.@)
1751 BOOL WINAPI SetupDiGetDeviceInstanceIdA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
1752 char *id, DWORD size, DWORD *needed)
1754 WCHAR idW[MAX_DEVICE_ID_LEN];
1756 TRACE("devinfo %p, device_data %p, id %p, size %d, needed %p.\n",
1757 devinfo, device_data, id, size, needed);
1759 if (!SetupDiGetDeviceInstanceIdW(devinfo, device_data, idW, ARRAY_SIZE(idW), NULL))
1760 return FALSE;
1762 if (needed)
1763 *needed = WideCharToMultiByte(CP_ACP, 0, idW, -1, NULL, 0, NULL, NULL);
1765 if (size && WideCharToMultiByte(CP_ACP, 0, idW, -1, id, size, NULL, NULL))
1766 return TRUE;
1768 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1769 return FALSE;
1772 /***********************************************************************
1773 * SetupDiGetDeviceInstanceIdW (SETUPAPI.@)
1775 BOOL WINAPI SetupDiGetDeviceInstanceIdW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
1776 WCHAR *DeviceInstanceId, DWORD DeviceInstanceIdSize, DWORD *RequiredSize)
1778 struct device *device;
1780 TRACE("devinfo %p, device_data %p, DeviceInstanceId %p, DeviceInstanceIdSize %d, RequiredSize %p.\n",
1781 devinfo, device_data, DeviceInstanceId, DeviceInstanceIdSize, RequiredSize);
1783 if (!(device = get_device(devinfo, device_data)))
1784 return FALSE;
1786 TRACE("instance ID: %s\n", debugstr_w(device->instanceId));
1787 if (DeviceInstanceIdSize < strlenW(device->instanceId) + 1)
1789 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1790 if (RequiredSize)
1791 *RequiredSize = lstrlenW(device->instanceId) + 1;
1792 return FALSE;
1794 lstrcpyW(DeviceInstanceId, device->instanceId);
1795 if (RequiredSize)
1796 *RequiredSize = lstrlenW(device->instanceId) + 1;
1797 return TRUE;
1800 /***********************************************************************
1801 * SetupDiGetActualSectionToInstallA (SETUPAPI.@)
1803 BOOL WINAPI SetupDiGetActualSectionToInstallA(
1804 HINF InfHandle,
1805 PCSTR InfSectionName,
1806 PSTR InfSectionWithExt,
1807 DWORD InfSectionWithExtSize,
1808 PDWORD RequiredSize,
1809 PSTR *Extension)
1811 FIXME("\n");
1812 return FALSE;
1815 /***********************************************************************
1816 * SetupDiGetActualSectionToInstallW (SETUPAPI.@)
1818 BOOL WINAPI SetupDiGetActualSectionToInstallW(
1819 HINF InfHandle,
1820 PCWSTR InfSectionName,
1821 PWSTR InfSectionWithExt,
1822 DWORD InfSectionWithExtSize,
1823 PDWORD RequiredSize,
1824 PWSTR *Extension)
1826 WCHAR szBuffer[MAX_PATH];
1827 DWORD dwLength;
1828 DWORD dwFullLength;
1829 LONG lLineCount = -1;
1831 lstrcpyW(szBuffer, InfSectionName);
1832 dwLength = lstrlenW(szBuffer);
1834 if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
1836 /* Test section name with '.NTx86' extension */
1837 lstrcpyW(&szBuffer[dwLength], NtPlatformExtension);
1838 lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
1840 if (lLineCount == -1)
1842 /* Test section name with '.NT' extension */
1843 lstrcpyW(&szBuffer[dwLength], NtExtension);
1844 lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
1847 else
1849 /* Test section name with '.Win' extension */
1850 lstrcpyW(&szBuffer[dwLength], WinExtension);
1851 lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
1854 if (lLineCount == -1)
1856 /* Test section name without extension */
1857 szBuffer[dwLength] = 0;
1858 lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
1861 if (lLineCount == -1)
1863 SetLastError(ERROR_INVALID_PARAMETER);
1864 return FALSE;
1867 dwFullLength = lstrlenW(szBuffer);
1869 if (InfSectionWithExt != NULL && InfSectionWithExtSize != 0)
1871 if (InfSectionWithExtSize < (dwFullLength + 1))
1873 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1874 return FALSE;
1877 lstrcpyW(InfSectionWithExt, szBuffer);
1878 if (Extension != NULL)
1880 *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
1884 if (RequiredSize != NULL)
1886 *RequiredSize = dwFullLength + 1;
1889 return TRUE;
1892 /***********************************************************************
1893 * SetupDiGetClassDescriptionA (SETUPAPI.@)
1895 BOOL WINAPI SetupDiGetClassDescriptionA(
1896 const GUID* ClassGuid,
1897 PSTR ClassDescription,
1898 DWORD ClassDescriptionSize,
1899 PDWORD RequiredSize)
1901 return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
1902 ClassDescriptionSize,
1903 RequiredSize, NULL, NULL);
1906 /***********************************************************************
1907 * SetupDiGetClassDescriptionW (SETUPAPI.@)
1909 BOOL WINAPI SetupDiGetClassDescriptionW(
1910 const GUID* ClassGuid,
1911 PWSTR ClassDescription,
1912 DWORD ClassDescriptionSize,
1913 PDWORD RequiredSize)
1915 return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
1916 ClassDescriptionSize,
1917 RequiredSize, NULL, NULL);
1920 /***********************************************************************
1921 * SetupDiGetClassDescriptionExA (SETUPAPI.@)
1923 BOOL WINAPI SetupDiGetClassDescriptionExA(
1924 const GUID* ClassGuid,
1925 PSTR ClassDescription,
1926 DWORD ClassDescriptionSize,
1927 PDWORD RequiredSize,
1928 PCSTR MachineName,
1929 PVOID Reserved)
1931 HKEY hKey;
1932 DWORD dwLength;
1933 BOOL ret;
1935 hKey = SetupDiOpenClassRegKeyExA(ClassGuid,
1936 KEY_ALL_ACCESS,
1937 DIOCR_INSTALLER,
1938 MachineName,
1939 Reserved);
1940 if (hKey == INVALID_HANDLE_VALUE)
1942 WARN("SetupDiOpenClassRegKeyExA() failed (Error %u)\n", GetLastError());
1943 return FALSE;
1946 dwLength = ClassDescriptionSize;
1947 ret = !RegQueryValueExA( hKey, NULL, NULL, NULL,
1948 (LPBYTE)ClassDescription, &dwLength );
1949 if (RequiredSize) *RequiredSize = dwLength;
1950 RegCloseKey(hKey);
1951 return ret;
1954 /***********************************************************************
1955 * SetupDiGetClassDescriptionExW (SETUPAPI.@)
1957 BOOL WINAPI SetupDiGetClassDescriptionExW(
1958 const GUID* ClassGuid,
1959 PWSTR ClassDescription,
1960 DWORD ClassDescriptionSize,
1961 PDWORD RequiredSize,
1962 PCWSTR MachineName,
1963 PVOID Reserved)
1965 HKEY hKey;
1966 DWORD dwLength;
1967 BOOL ret;
1969 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
1970 KEY_ALL_ACCESS,
1971 DIOCR_INSTALLER,
1972 MachineName,
1973 Reserved);
1974 if (hKey == INVALID_HANDLE_VALUE)
1976 WARN("SetupDiOpenClassRegKeyExW() failed (Error %u)\n", GetLastError());
1977 return FALSE;
1980 dwLength = ClassDescriptionSize * sizeof(WCHAR);
1981 ret = !RegQueryValueExW( hKey, NULL, NULL, NULL,
1982 (LPBYTE)ClassDescription, &dwLength );
1983 if (RequiredSize) *RequiredSize = dwLength / sizeof(WCHAR);
1984 RegCloseKey(hKey);
1985 return ret;
1988 /***********************************************************************
1989 * SetupDiGetClassDevsA (SETUPAPI.@)
1991 HDEVINFO WINAPI SetupDiGetClassDevsA(const GUID *class, LPCSTR enumstr, HWND parent, DWORD flags)
1993 HDEVINFO ret;
1994 LPWSTR enumstrW = NULL;
1996 if (enumstr)
1998 int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
1999 enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2000 if (!enumstrW)
2002 ret = INVALID_HANDLE_VALUE;
2003 goto end;
2005 MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
2007 ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, NULL, NULL,
2008 NULL);
2009 HeapFree(GetProcessHeap(), 0, enumstrW);
2011 end:
2012 return ret;
2015 /***********************************************************************
2016 * SetupDiGetClassDevsExA (SETUPAPI.@)
2018 HDEVINFO WINAPI SetupDiGetClassDevsExA(
2019 const GUID *class,
2020 PCSTR enumstr,
2021 HWND parent,
2022 DWORD flags,
2023 HDEVINFO deviceset,
2024 PCSTR machine,
2025 PVOID reserved)
2027 HDEVINFO ret;
2028 LPWSTR enumstrW = NULL, machineW = NULL;
2030 if (enumstr)
2032 int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
2033 enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2034 if (!enumstrW)
2036 ret = INVALID_HANDLE_VALUE;
2037 goto end;
2039 MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
2041 if (machine)
2043 int len = MultiByteToWideChar(CP_ACP, 0, machine, -1, NULL, 0);
2044 machineW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2045 if (!machineW)
2047 HeapFree(GetProcessHeap(), 0, enumstrW);
2048 ret = INVALID_HANDLE_VALUE;
2049 goto end;
2051 MultiByteToWideChar(CP_ACP, 0, machine, -1, machineW, len);
2053 ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset,
2054 machineW, reserved);
2055 HeapFree(GetProcessHeap(), 0, enumstrW);
2056 HeapFree(GetProcessHeap(), 0, machineW);
2058 end:
2059 return ret;
2062 static void SETUPDI_AddDeviceInterfaces(struct device *device, HKEY key,
2063 const GUID *guid, DWORD flags)
2065 DWORD i, len;
2066 WCHAR subKeyName[MAX_PATH];
2067 LONG l = ERROR_SUCCESS;
2069 for (i = 0; !l; i++)
2071 len = ARRAY_SIZE(subKeyName);
2072 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2073 if (!l)
2075 HKEY subKey;
2076 struct device_iface *iface;
2078 if (*subKeyName == '#')
2080 /* The subkey name is the reference string, with a '#' prepended */
2081 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2082 if (!l)
2084 WCHAR symbolicLink[MAX_PATH];
2085 DWORD dataType;
2087 if (!(flags & DIGCF_PRESENT) || is_linked(subKey))
2089 iface = SETUPDI_CreateDeviceInterface(device, guid, subKeyName + 1);
2091 len = sizeof(symbolicLink);
2092 l = RegQueryValueExW(subKey, SymbolicLink, NULL, &dataType,
2093 (BYTE *)symbolicLink, &len);
2094 if (!l && dataType == REG_SZ)
2095 SETUPDI_SetInterfaceSymbolicLink(iface, symbolicLink);
2096 RegCloseKey(subKey);
2100 /* Allow enumeration to continue */
2101 l = ERROR_SUCCESS;
2104 /* FIXME: find and add all the device's interfaces to the device */
2107 static void SETUPDI_EnumerateMatchingInterfaces(HDEVINFO DeviceInfoSet,
2108 HKEY key, const GUID *guid, const WCHAR *enumstr, DWORD flags)
2110 struct DeviceInfoSet *set = DeviceInfoSet;
2111 DWORD i, len;
2112 WCHAR subKeyName[MAX_PATH];
2113 LONG l;
2114 HKEY enumKey = INVALID_HANDLE_VALUE;
2116 TRACE("%s\n", debugstr_w(enumstr));
2118 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL,
2119 &enumKey, NULL);
2120 for (i = 0; !l; i++)
2122 len = ARRAY_SIZE(subKeyName);
2123 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2124 if (!l)
2126 HKEY subKey;
2128 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2129 if (!l)
2131 WCHAR deviceInst[MAX_PATH * 3];
2132 DWORD dataType;
2134 len = sizeof(deviceInst);
2135 l = RegQueryValueExW(subKey, DeviceInstance, NULL, &dataType,
2136 (BYTE *)deviceInst, &len);
2137 if (!l && dataType == REG_SZ)
2139 TRACE("found instance ID %s\n", debugstr_w(deviceInst));
2140 if (!enumstr || !lstrcmpiW(enumstr, deviceInst))
2142 HKEY deviceKey;
2144 l = RegOpenKeyExW(enumKey, deviceInst, 0, KEY_READ,
2145 &deviceKey);
2146 if (!l)
2148 WCHAR deviceClassStr[40];
2150 len = sizeof(deviceClassStr);
2151 l = RegQueryValueExW(deviceKey, ClassGUID, NULL,
2152 &dataType, (BYTE *)deviceClassStr, &len);
2153 if (!l && dataType == REG_SZ &&
2154 deviceClassStr[0] == '{' &&
2155 deviceClassStr[37] == '}')
2157 GUID deviceClass;
2158 struct device *device;
2160 deviceClassStr[37] = 0;
2161 UuidFromStringW(&deviceClassStr[1],
2162 &deviceClass);
2163 if ((device = SETUPDI_CreateDeviceInfo(set,
2164 &deviceClass, deviceInst, FALSE)))
2165 SETUPDI_AddDeviceInterfaces(device, subKey, guid, flags);
2167 RegCloseKey(deviceKey);
2171 RegCloseKey(subKey);
2173 /* Allow enumeration to continue */
2174 l = ERROR_SUCCESS;
2177 if (enumKey != INVALID_HANDLE_VALUE)
2178 RegCloseKey(enumKey);
2181 static void SETUPDI_EnumerateInterfaces(HDEVINFO DeviceInfoSet,
2182 const GUID *guid, LPCWSTR enumstr, DWORD flags)
2184 HKEY interfacesKey = SetupDiOpenClassRegKeyExW(guid, KEY_READ,
2185 DIOCR_INTERFACE, NULL, NULL);
2187 TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(guid),
2188 debugstr_w(enumstr), flags);
2190 if (interfacesKey != INVALID_HANDLE_VALUE)
2192 if (flags & DIGCF_ALLCLASSES)
2194 DWORD i, len;
2195 WCHAR interfaceGuidStr[40];
2196 LONG l = ERROR_SUCCESS;
2198 for (i = 0; !l; i++)
2200 len = ARRAY_SIZE(interfaceGuidStr);
2201 l = RegEnumKeyExW(interfacesKey, i, interfaceGuidStr, &len,
2202 NULL, NULL, NULL, NULL);
2203 if (!l)
2205 if (interfaceGuidStr[0] == '{' &&
2206 interfaceGuidStr[37] == '}')
2208 HKEY interfaceKey;
2209 GUID interfaceGuid;
2211 interfaceGuidStr[37] = 0;
2212 UuidFromStringW(&interfaceGuidStr[1], &interfaceGuid);
2213 interfaceGuidStr[37] = '}';
2214 interfaceGuidStr[38] = 0;
2215 l = RegOpenKeyExW(interfacesKey, interfaceGuidStr, 0,
2216 KEY_READ, &interfaceKey);
2217 if (!l)
2219 SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
2220 interfaceKey, &interfaceGuid, enumstr, flags);
2221 RegCloseKey(interfaceKey);
2227 else
2229 /* In this case, SetupDiOpenClassRegKeyExW opened the specific
2230 * interface's key, so just pass that long
2232 SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
2233 interfacesKey, guid, enumstr, flags);
2235 RegCloseKey(interfacesKey);
2239 static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set,
2240 LPCWSTR enumerator, LPCWSTR deviceName, HKEY deviceKey,
2241 const GUID *class, DWORD flags)
2243 WCHAR id[MAX_DEVICE_ID_LEN];
2244 DWORD i, len;
2245 WCHAR deviceInstance[MAX_PATH];
2246 LONG l = ERROR_SUCCESS;
2248 TRACE("%s %s\n", debugstr_w(enumerator), debugstr_w(deviceName));
2250 for (i = 0; !l; i++)
2252 len = ARRAY_SIZE(deviceInstance);
2253 l = RegEnumKeyExW(deviceKey, i, deviceInstance, &len, NULL, NULL, NULL,
2254 NULL);
2255 if (!l)
2257 HKEY subKey;
2259 l = RegOpenKeyExW(deviceKey, deviceInstance, 0, KEY_READ, &subKey);
2260 if (!l)
2262 WCHAR classGuid[40];
2263 DWORD dataType;
2265 len = sizeof(classGuid);
2266 l = RegQueryValueExW(subKey, ClassGUID, NULL, &dataType,
2267 (BYTE *)classGuid, &len);
2268 if (!l && dataType == REG_SZ)
2270 if (classGuid[0] == '{' && classGuid[37] == '}')
2272 GUID deviceClass;
2274 classGuid[37] = 0;
2275 UuidFromStringW(&classGuid[1], &deviceClass);
2276 if ((flags & DIGCF_ALLCLASSES) ||
2277 IsEqualGUID(class, &deviceClass))
2279 static const WCHAR fmt[] =
2280 {'%','s','\\','%','s','\\','%','s',0};
2282 if (snprintfW(id, ARRAY_SIZE(id), fmt, enumerator,
2283 deviceName, deviceInstance) != -1)
2285 SETUPDI_CreateDeviceInfo(set, &deviceClass, id, FALSE);
2290 RegCloseKey(subKey);
2292 /* Allow enumeration to continue */
2293 l = ERROR_SUCCESS;
2298 static void SETUPDI_EnumerateMatchingDevices(HDEVINFO DeviceInfoSet,
2299 LPCWSTR parent, HKEY key, const GUID *class, DWORD flags)
2301 struct DeviceInfoSet *set = DeviceInfoSet;
2302 DWORD i, len;
2303 WCHAR subKeyName[MAX_PATH];
2304 LONG l = ERROR_SUCCESS;
2306 TRACE("%s\n", debugstr_w(parent));
2308 for (i = 0; !l; i++)
2310 len = ARRAY_SIZE(subKeyName);
2311 l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2312 if (!l)
2314 HKEY subKey;
2316 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2317 if (!l)
2319 TRACE("%s\n", debugstr_w(subKeyName));
2320 SETUPDI_EnumerateMatchingDeviceInstances(set, parent,
2321 subKeyName, subKey, class, flags);
2322 RegCloseKey(subKey);
2324 /* Allow enumeration to continue */
2325 l = ERROR_SUCCESS;
2330 static void SETUPDI_EnumerateDevices(HDEVINFO DeviceInfoSet, const GUID *class,
2331 LPCWSTR enumstr, DWORD flags)
2333 HKEY enumKey;
2334 LONG l;
2336 TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(class),
2337 debugstr_w(enumstr), flags);
2339 l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL,
2340 &enumKey, NULL);
2341 if (enumKey != INVALID_HANDLE_VALUE)
2343 if (enumstr)
2345 HKEY enumStrKey;
2347 l = RegOpenKeyExW(enumKey, enumstr, 0, KEY_READ,
2348 &enumStrKey);
2349 if (!l)
2351 SETUPDI_EnumerateMatchingDevices(DeviceInfoSet, enumstr,
2352 enumStrKey, class, flags);
2353 RegCloseKey(enumStrKey);
2356 else
2358 DWORD i, len;
2359 WCHAR subKeyName[MAX_PATH];
2361 l = ERROR_SUCCESS;
2362 for (i = 0; !l; i++)
2364 len = ARRAY_SIZE(subKeyName);
2365 l = RegEnumKeyExW(enumKey, i, subKeyName, &len, NULL,
2366 NULL, NULL, NULL);
2367 if (!l)
2369 HKEY subKey;
2371 l = RegOpenKeyExW(enumKey, subKeyName, 0, KEY_READ,
2372 &subKey);
2373 if (!l)
2375 SETUPDI_EnumerateMatchingDevices(DeviceInfoSet,
2376 subKeyName, subKey, class, flags);
2377 RegCloseKey(subKey);
2379 /* Allow enumeration to continue */
2380 l = ERROR_SUCCESS;
2384 RegCloseKey(enumKey);
2388 /***********************************************************************
2389 * SetupDiGetClassDevsW (SETUPAPI.@)
2391 HDEVINFO WINAPI SetupDiGetClassDevsW(const GUID *class, LPCWSTR enumstr, HWND parent, DWORD flags)
2393 return SetupDiGetClassDevsExW(class, enumstr, parent, flags, NULL, NULL,
2394 NULL);
2397 /***********************************************************************
2398 * SetupDiGetClassDevsExW (SETUPAPI.@)
2400 HDEVINFO WINAPI SetupDiGetClassDevsExW(const GUID *class, PCWSTR enumstr, HWND parent, DWORD flags,
2401 HDEVINFO deviceset, PCWSTR machine, void *reserved)
2403 static const DWORD unsupportedFlags = DIGCF_DEFAULT | DIGCF_PROFILE;
2404 HDEVINFO set;
2406 TRACE("%s %s %p 0x%08x %p %s %p\n", debugstr_guid(class),
2407 debugstr_w(enumstr), parent, flags, deviceset, debugstr_w(machine),
2408 reserved);
2410 if (!(flags & DIGCF_ALLCLASSES) && !class)
2412 SetLastError(ERROR_INVALID_PARAMETER);
2413 return INVALID_HANDLE_VALUE;
2415 if (flags & unsupportedFlags)
2416 WARN("unsupported flags %08x\n", flags & unsupportedFlags);
2417 if (deviceset)
2418 set = deviceset;
2419 else
2420 set = SetupDiCreateDeviceInfoListExW(class, parent, machine, reserved);
2421 if (set != INVALID_HANDLE_VALUE)
2423 if (machine && *machine)
2424 FIXME("%s: unimplemented for remote machines\n",
2425 debugstr_w(machine));
2426 else if (flags & DIGCF_DEVICEINTERFACE)
2427 SETUPDI_EnumerateInterfaces(set, class, enumstr, flags);
2428 else
2429 SETUPDI_EnumerateDevices(set, class, enumstr, flags);
2431 return set;
2434 /***********************************************************************
2435 * SetupDiGetDeviceInfoListDetailA (SETUPAPI.@)
2437 BOOL WINAPI SetupDiGetDeviceInfoListDetailA(HDEVINFO devinfo, SP_DEVINFO_LIST_DETAIL_DATA_A *DevInfoData)
2439 struct DeviceInfoSet *set;
2441 TRACE("devinfo %p, detail_data %p.\n", devinfo, DevInfoData);
2443 if (!(set = get_device_set(devinfo)))
2444 return FALSE;
2446 if (!DevInfoData ||
2447 DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_A))
2449 SetLastError(ERROR_INVALID_PARAMETER);
2450 return FALSE;
2452 DevInfoData->ClassGuid = set->ClassGuid;
2453 DevInfoData->RemoteMachineHandle = NULL;
2454 DevInfoData->RemoteMachineName[0] = '\0';
2455 return TRUE;
2458 /***********************************************************************
2459 * SetupDiGetDeviceInfoListDetailW (SETUPAPI.@)
2461 BOOL WINAPI SetupDiGetDeviceInfoListDetailW(HDEVINFO devinfo, SP_DEVINFO_LIST_DETAIL_DATA_W *DevInfoData)
2463 struct DeviceInfoSet *set;
2465 TRACE("devinfo %p, detail_data %p.\n", devinfo, DevInfoData);
2467 if (!(set = get_device_set(devinfo)))
2468 return FALSE;
2470 if (!DevInfoData ||
2471 DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W))
2473 SetLastError(ERROR_INVALID_PARAMETER);
2474 return FALSE;
2476 DevInfoData->ClassGuid = set->ClassGuid;
2477 DevInfoData->RemoteMachineHandle = NULL;
2478 DevInfoData->RemoteMachineName[0] = '\0';
2479 return TRUE;
2482 /***********************************************************************
2483 * SetupDiCreateDeviceInterfaceA (SETUPAPI.@)
2485 BOOL WINAPI SetupDiCreateDeviceInterfaceA(
2486 HDEVINFO DeviceInfoSet,
2487 PSP_DEVINFO_DATA DeviceInfoData,
2488 const GUID *InterfaceClassGuid,
2489 PCSTR ReferenceString,
2490 DWORD CreationFlags,
2491 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2493 BOOL ret;
2494 LPWSTR ReferenceStringW = NULL;
2496 TRACE("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
2497 debugstr_guid(InterfaceClassGuid), debugstr_a(ReferenceString),
2498 CreationFlags, DeviceInterfaceData);
2500 if (ReferenceString)
2502 ReferenceStringW = MultiByteToUnicode(ReferenceString, CP_ACP);
2503 if (ReferenceStringW == NULL) return FALSE;
2506 ret = SetupDiCreateDeviceInterfaceW(DeviceInfoSet, DeviceInfoData,
2507 InterfaceClassGuid, ReferenceStringW, CreationFlags,
2508 DeviceInterfaceData);
2510 MyFree(ReferenceStringW);
2512 return ret;
2515 /***********************************************************************
2516 * SetupDiCreateDeviceInterfaceW (SETUPAPI.@)
2518 BOOL WINAPI SetupDiCreateDeviceInterfaceW(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
2519 const GUID *class, const WCHAR *refstr, DWORD flags, SP_DEVICE_INTERFACE_DATA *iface_data)
2521 struct device *device;
2522 struct device_iface *iface;
2524 TRACE("devinfo %p, device_data %p, class %s, refstr %s, flags %#x, iface_data %p.\n",
2525 devinfo, device_data, debugstr_guid(class), debugstr_w(refstr), flags, iface_data);
2527 if (!(device = get_device(devinfo, device_data)))
2528 return FALSE;
2530 if (!class)
2532 SetLastError(ERROR_INVALID_USER_BUFFER);
2533 return FALSE;
2536 if (!(iface = SETUPDI_CreateDeviceInterface(device, class, refstr)))
2537 return FALSE;
2539 if (iface_data)
2541 if (iface_data->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2543 SetLastError(ERROR_INVALID_USER_BUFFER);
2544 return FALSE;
2547 copy_device_iface_data(iface_data, iface);
2549 return TRUE;
2552 /***********************************************************************
2553 * SetupDiCreateDeviceInterfaceRegKeyA (SETUPAPI.@)
2555 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyA(
2556 HDEVINFO DeviceInfoSet,
2557 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2558 DWORD Reserved,
2559 REGSAM samDesired,
2560 HINF InfHandle,
2561 PCSTR InfSectionName)
2563 HKEY key;
2564 PWSTR InfSectionNameW = NULL;
2566 TRACE("%p %p %d %08x %p %p\n", DeviceInfoSet, DeviceInterfaceData, Reserved,
2567 samDesired, InfHandle, InfSectionName);
2568 if (InfHandle)
2570 if (!InfSectionName)
2572 SetLastError(ERROR_INVALID_PARAMETER);
2573 return INVALID_HANDLE_VALUE;
2575 InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
2576 if (!InfSectionNameW)
2577 return INVALID_HANDLE_VALUE;
2579 key = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet,
2580 DeviceInterfaceData, Reserved, samDesired, InfHandle,
2581 InfSectionNameW);
2582 MyFree(InfSectionNameW);
2583 return key;
2586 /***********************************************************************
2587 * SetupDiCreateDeviceInterfaceRegKeyW (SETUPAPI.@)
2589 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyW(HDEVINFO devinfo,
2590 SP_DEVICE_INTERFACE_DATA *iface_data, DWORD reserved, REGSAM access,
2591 HINF hinf, const WCHAR *section)
2593 struct device_iface *iface;
2594 HKEY params_key;
2595 LONG ret;
2597 TRACE("devinfo %p, iface_data %p, reserved %d, access %#x, hinf %p, section %s.\n",
2598 devinfo, iface_data, reserved, access, hinf, debugstr_w(section));
2600 if (!(iface = get_device_iface(devinfo, iface_data)))
2601 return INVALID_HANDLE_VALUE;
2603 if (hinf && !section)
2605 SetLastError(ERROR_INVALID_PARAMETER);
2606 return INVALID_HANDLE_VALUE;
2609 ret = RegCreateKeyExW(iface->refstr_key, DeviceParameters, 0, NULL, 0, access,
2610 NULL, &params_key, NULL);
2611 if (ret)
2613 SetLastError(ret);
2614 return INVALID_HANDLE_VALUE;
2617 return params_key;
2620 /***********************************************************************
2621 * SetupDiDeleteDeviceInterfaceRegKey (SETUPAPI.@)
2623 BOOL WINAPI SetupDiDeleteDeviceInterfaceRegKey(HDEVINFO devinfo,
2624 SP_DEVICE_INTERFACE_DATA *iface_data, DWORD reserved)
2626 struct device_iface *iface;
2627 LONG ret;
2629 TRACE("devinfo %p, iface_data %p, reserved %d.\n", devinfo, iface_data, reserved);
2631 if (!(iface = get_device_iface(devinfo, iface_data)))
2632 return FALSE;
2634 ret = RegDeleteKeyW(iface->refstr_key, DeviceParameters);
2635 if (ret)
2637 SetLastError(ret);
2638 return FALSE;
2641 return TRUE;
2644 /***********************************************************************
2645 * SetupDiEnumDeviceInterfaces (SETUPAPI.@)
2647 * PARAMS
2648 * DeviceInfoSet [I] Set of devices from which to enumerate
2649 * interfaces
2650 * DeviceInfoData [I] (Optional) If specified, a specific device
2651 * instance from which to enumerate interfaces.
2652 * If it isn't specified, all interfaces for all
2653 * devices in the set are enumerated.
2654 * InterfaceClassGuid [I] The interface class to enumerate.
2655 * MemberIndex [I] An index of the interface instance to enumerate.
2656 * A caller should start with MemberIndex set to 0,
2657 * and continue until the function fails with
2658 * ERROR_NO_MORE_ITEMS.
2659 * DeviceInterfaceData [I/O] Returns an enumerated interface. Its cbSize
2660 * member must be set to
2661 * sizeof(SP_DEVICE_INTERFACE_DATA).
2663 * RETURNS
2664 * Success: non-zero value.
2665 * Failure: FALSE. Call GetLastError() for more info.
2667 BOOL WINAPI SetupDiEnumDeviceInterfaces(HDEVINFO devinfo,
2668 SP_DEVINFO_DATA *device_data, const GUID *class, DWORD index,
2669 SP_DEVICE_INTERFACE_DATA *iface_data)
2671 struct DeviceInfoSet *set;
2672 struct device *device;
2673 struct device_iface *iface;
2674 DWORD i = 0;
2676 TRACE("devinfo %p, device_data %p, class %s, index %u, iface_data %p.\n",
2677 devinfo, device_data, debugstr_guid(class), index, iface_data);
2679 if (!iface_data || iface_data->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2681 SetLastError(ERROR_INVALID_PARAMETER);
2682 return FALSE;
2685 /* In case application fails to check return value, clear output */
2686 memset(iface_data, 0, sizeof(*iface_data));
2687 iface_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
2689 if (device_data)
2691 if (!(device = get_device(devinfo, device_data)))
2692 return FALSE;
2694 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
2696 if (IsEqualGUID(&iface->class, class))
2698 if (i == index)
2700 copy_device_iface_data(iface_data, iface);
2701 return TRUE;
2703 i++;
2707 else
2709 if (!(set = get_device_set(devinfo)))
2710 return FALSE;
2712 LIST_FOR_EACH_ENTRY(device, &set->devices, struct device, entry)
2714 LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry)
2716 if (IsEqualGUID(&iface->class, class))
2718 if (i == index)
2720 copy_device_iface_data(iface_data, iface);
2721 return TRUE;
2723 i++;
2729 SetLastError(ERROR_NO_MORE_ITEMS);
2730 return FALSE;
2733 /***********************************************************************
2734 * SetupDiDestroyDeviceInfoList (SETUPAPI.@)
2736 * Destroy a DeviceInfoList and free all used memory of the list.
2738 * PARAMS
2739 * devinfo [I] DeviceInfoList pointer to list to destroy
2741 * RETURNS
2742 * Success: non zero value.
2743 * Failure: zero value.
2745 BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
2747 struct DeviceInfoSet *set;
2748 struct device *device, *device2;
2750 TRACE("devinfo %p.\n", devinfo);
2752 if (!(set = get_device_set(devinfo)))
2753 return FALSE;
2755 LIST_FOR_EACH_ENTRY_SAFE(device, device2, &set->devices, struct device, entry)
2757 delete_device(device);
2759 heap_free(set);
2761 return TRUE;
2764 /***********************************************************************
2765 * SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
2767 BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data,
2768 SP_DEVICE_INTERFACE_DETAIL_DATA_A *DeviceInterfaceDetailData,
2769 DWORD DeviceInterfaceDetailDataSize, DWORD *RequiredSize, SP_DEVINFO_DATA *device_data)
2771 struct device_iface *iface;
2772 DWORD bytesNeeded = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath[1]);
2773 BOOL ret = FALSE;
2775 TRACE("devinfo %p, iface_data %p, detail_data %p, size %d, needed %p, device_data %p.\n",
2776 devinfo, iface_data, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize,
2777 RequiredSize, device_data);
2779 if (!(iface = get_device_iface(devinfo, iface_data)))
2780 return FALSE;
2782 if (DeviceInterfaceDetailData &&
2783 DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A))
2785 SetLastError(ERROR_INVALID_USER_BUFFER);
2786 return FALSE;
2788 if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
2790 SetLastError(ERROR_INVALID_USER_BUFFER);
2791 return FALSE;
2794 if (iface->symlink)
2795 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, iface->symlink, -1,
2796 NULL, 0, NULL, NULL);
2797 if (DeviceInterfaceDetailDataSize >= bytesNeeded)
2799 if (iface->symlink)
2800 WideCharToMultiByte(CP_ACP, 0, iface->symlink, -1,
2801 DeviceInterfaceDetailData->DevicePath,
2802 DeviceInterfaceDetailDataSize -
2803 offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
2804 NULL, NULL);
2805 else
2806 DeviceInterfaceDetailData->DevicePath[0] = '\0';
2808 ret = TRUE;
2810 else
2812 if (RequiredSize)
2813 *RequiredSize = bytesNeeded;
2814 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2817 if (device_data && device_data->cbSize == sizeof(SP_DEVINFO_DATA))
2818 copy_device_data(device_data, iface->device);
2820 return ret;
2823 /***********************************************************************
2824 * SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
2826 BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *iface_data,
2827 SP_DEVICE_INTERFACE_DETAIL_DATA_W *DeviceInterfaceDetailData,
2828 DWORD DeviceInterfaceDetailDataSize, DWORD *RequiredSize, SP_DEVINFO_DATA *device_data)
2830 struct device_iface *iface;
2831 DWORD bytesNeeded = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
2832 + sizeof(WCHAR); /* include NULL terminator */
2833 BOOL ret = FALSE;
2835 TRACE("devinfo %p, iface_data %p, detail_data %p, size %d, needed %p, device_data %p.\n",
2836 devinfo, iface_data, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize,
2837 RequiredSize, device_data);
2839 if (!(iface = get_device_iface(devinfo, iface_data)))
2840 return FALSE;
2842 if (DeviceInterfaceDetailData && (DeviceInterfaceDetailData->cbSize <
2843 offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR) ||
2844 DeviceInterfaceDetailData->cbSize > sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W)))
2846 SetLastError(ERROR_INVALID_USER_BUFFER);
2847 return FALSE;
2849 if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
2851 SetLastError(ERROR_INVALID_USER_BUFFER);
2852 return FALSE;
2855 if (iface->symlink)
2856 bytesNeeded += sizeof(WCHAR) * lstrlenW(iface->symlink);
2857 if (DeviceInterfaceDetailDataSize >= bytesNeeded)
2859 if (iface->symlink)
2860 lstrcpyW(DeviceInterfaceDetailData->DevicePath, iface->symlink);
2861 else
2862 DeviceInterfaceDetailData->DevicePath[0] = '\0';
2864 ret = TRUE;
2866 else
2868 if (RequiredSize)
2869 *RequiredSize = bytesNeeded;
2870 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2873 if (device_data && device_data->cbSize == sizeof(SP_DEVINFO_DATA))
2874 copy_device_data(device_data, iface->device);
2876 return ret;
2879 /***********************************************************************
2880 * SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
2882 BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(HDEVINFO devinfo,
2883 SP_DEVINFO_DATA *device_data, DWORD Property, DWORD *PropertyRegDataType,
2884 BYTE *PropertyBuffer, DWORD PropertyBufferSize, DWORD *RequiredSize)
2886 BOOL ret = FALSE;
2887 struct device *device;
2889 TRACE("devinfo %p, device_data %p, property %d, type %p, buffer %p, size %d, required %p\n",
2890 devinfo, device_data, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize);
2892 if (!(device = get_device(devinfo, device_data)))
2893 return FALSE;
2895 if (PropertyBufferSize && PropertyBuffer == NULL)
2897 SetLastError(ERROR_INVALID_DATA);
2898 return FALSE;
2901 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameA)
2903 DWORD size = PropertyBufferSize;
2904 LONG l = RegQueryValueExA(device->key, PropertyMap[Property].nameA,
2905 NULL, PropertyRegDataType, PropertyBuffer, &size);
2907 if (l == ERROR_FILE_NOT_FOUND)
2908 SetLastError(ERROR_INVALID_DATA);
2909 else if (l == ERROR_MORE_DATA || !PropertyBufferSize)
2910 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2911 else if (!l)
2912 ret = TRUE;
2913 else
2914 SetLastError(l);
2915 if (RequiredSize)
2916 *RequiredSize = size;
2918 return ret;
2921 /***********************************************************************
2922 * SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
2924 BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(HDEVINFO devinfo,
2925 SP_DEVINFO_DATA *device_data, DWORD Property, DWORD *PropertyRegDataType,
2926 BYTE *PropertyBuffer, DWORD PropertyBufferSize, DWORD *RequiredSize)
2928 BOOL ret = FALSE;
2929 struct device *device;
2931 TRACE("devinfo %p, device_data %p, prop %d, type %p, buffer %p, size %d, required %p\n",
2932 devinfo, device_data, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize);
2934 if (!(device = get_device(devinfo, device_data)))
2935 return FALSE;
2937 if (PropertyBufferSize && PropertyBuffer == NULL)
2939 SetLastError(ERROR_INVALID_DATA);
2940 return FALSE;
2943 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameW)
2945 DWORD size = PropertyBufferSize;
2946 LONG l = RegQueryValueExW(device->key, PropertyMap[Property].nameW,
2947 NULL, PropertyRegDataType, PropertyBuffer, &size);
2949 if (l == ERROR_FILE_NOT_FOUND)
2950 SetLastError(ERROR_INVALID_DATA);
2951 else if (l == ERROR_MORE_DATA || !PropertyBufferSize)
2952 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2953 else if (!l)
2954 ret = TRUE;
2955 else
2956 SetLastError(l);
2957 if (RequiredSize)
2958 *RequiredSize = size;
2960 return ret;
2963 /***********************************************************************
2964 * SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
2966 BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
2967 DWORD Property, const BYTE *PropertyBuffer, DWORD PropertyBufferSize)
2969 BOOL ret = FALSE;
2970 struct device *device;
2972 TRACE("devinfo %p, device_data %p, prop %d, buffer %p, size %d.\n",
2973 devinfo, device_data, Property, PropertyBuffer, PropertyBufferSize);
2975 if (!(device = get_device(devinfo, device_data)))
2976 return FALSE;
2978 if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameA)
2980 LONG l = RegSetValueExA(device->key, PropertyMap[Property].nameA, 0,
2981 PropertyMap[Property].regType, PropertyBuffer,
2982 PropertyBufferSize);
2983 if (!l)
2984 ret = TRUE;
2985 else
2986 SetLastError(l);
2988 return ret;
2991 /***********************************************************************
2992 * SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
2994 BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(HDEVINFO devinfo,
2995 SP_DEVINFO_DATA *device_data, DWORD prop, const BYTE *buffer, DWORD size)
2997 struct device *device;
2999 TRACE("devinfo %p, device_data %p, prop %d, buffer %p, size %d.\n",
3000 devinfo, device_data, prop, buffer, size);
3002 if (!(device = get_device(devinfo, device_data)))
3003 return FALSE;
3005 return SETUPDI_SetDeviceRegistryPropertyW(device, prop, buffer, size);
3008 /***********************************************************************
3009 * SetupDiInstallClassA (SETUPAPI.@)
3011 BOOL WINAPI SetupDiInstallClassA(
3012 HWND hwndParent,
3013 PCSTR InfFileName,
3014 DWORD Flags,
3015 HSPFILEQ FileQueue)
3017 UNICODE_STRING FileNameW;
3018 BOOL Result;
3020 if (!InfFileName)
3022 SetLastError(ERROR_INVALID_PARAMETER);
3023 return FALSE;
3025 if (!RtlCreateUnicodeStringFromAsciiz(&FileNameW, InfFileName))
3027 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3028 return FALSE;
3031 Result = SetupDiInstallClassW(hwndParent, FileNameW.Buffer, Flags, FileQueue);
3033 RtlFreeUnicodeString(&FileNameW);
3035 return Result;
3038 static HKEY CreateClassKey(HINF hInf)
3040 static const WCHAR slash[] = { '\\',0 };
3041 WCHAR FullBuffer[MAX_PATH];
3042 WCHAR Buffer[MAX_PATH];
3043 DWORD RequiredSize;
3044 HKEY hClassKey;
3046 if (!SetupGetLineTextW(NULL,
3047 hInf,
3048 Version,
3049 ClassGUID,
3050 Buffer,
3051 MAX_PATH,
3052 &RequiredSize))
3054 return INVALID_HANDLE_VALUE;
3057 lstrcpyW(FullBuffer, ControlClass);
3058 lstrcatW(FullBuffer, slash);
3059 lstrcatW(FullBuffer, Buffer);
3061 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3062 FullBuffer,
3064 KEY_ALL_ACCESS,
3065 &hClassKey))
3067 if (!SetupGetLineTextW(NULL,
3068 hInf,
3069 Version,
3070 Class,
3071 Buffer,
3072 MAX_PATH,
3073 &RequiredSize))
3075 return INVALID_HANDLE_VALUE;
3078 if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
3079 FullBuffer,
3081 NULL,
3082 REG_OPTION_NON_VOLATILE,
3083 KEY_ALL_ACCESS,
3084 NULL,
3085 &hClassKey,
3086 NULL))
3088 return INVALID_HANDLE_VALUE;
3093 if (RegSetValueExW(hClassKey,
3094 Class,
3096 REG_SZ,
3097 (LPBYTE)Buffer,
3098 RequiredSize * sizeof(WCHAR)))
3100 RegCloseKey(hClassKey);
3101 RegDeleteKeyW(HKEY_LOCAL_MACHINE,
3102 FullBuffer);
3103 return INVALID_HANDLE_VALUE;
3106 return hClassKey;
3109 /***********************************************************************
3110 * SetupDiInstallClassW (SETUPAPI.@)
3112 BOOL WINAPI SetupDiInstallClassW(
3113 HWND hwndParent,
3114 PCWSTR InfFileName,
3115 DWORD Flags,
3116 HSPFILEQ FileQueue)
3118 WCHAR SectionName[MAX_PATH];
3119 DWORD SectionNameLength = 0;
3120 HINF hInf;
3121 BOOL bFileQueueCreated = FALSE;
3122 HKEY hClassKey;
3125 FIXME("\n");
3127 if (!InfFileName)
3129 SetLastError(ERROR_INVALID_PARAMETER);
3130 return FALSE;
3132 if ((Flags & DI_NOVCP) && (FileQueue == NULL || FileQueue == INVALID_HANDLE_VALUE))
3134 SetLastError(ERROR_INVALID_PARAMETER);
3135 return FALSE;
3138 /* Open the .inf file */
3139 hInf = SetupOpenInfFileW(InfFileName,
3140 NULL,
3141 INF_STYLE_WIN4,
3142 NULL);
3143 if (hInf == INVALID_HANDLE_VALUE)
3146 return FALSE;
3149 /* Create or open the class registry key 'HKLM\\CurrentControlSet\\Class\\{GUID}' */
3150 hClassKey = CreateClassKey(hInf);
3151 if (hClassKey == INVALID_HANDLE_VALUE)
3153 SetupCloseInfFile(hInf);
3154 return FALSE;
3158 /* Try to append a layout file */
3159 SetupOpenAppendInfFileW(NULL, hInf, NULL);
3161 /* Retrieve the actual section name */
3162 SetupDiGetActualSectionToInstallW(hInf,
3163 ClassInstall32,
3164 SectionName,
3165 MAX_PATH,
3166 &SectionNameLength,
3167 NULL);
3169 #if 0
3170 if (!(Flags & DI_NOVCP))
3172 FileQueue = SetupOpenFileQueue();
3173 if (FileQueue == INVALID_HANDLE_VALUE)
3175 SetupCloseInfFile(hInf);
3176 return FALSE;
3179 bFileQueueCreated = TRUE;
3182 #endif
3184 SetupInstallFromInfSectionW(NULL,
3185 hInf,
3186 SectionName,
3187 SPINST_COPYINF | SPINST_FILES | SPINST_REGISTRY,
3188 hClassKey,
3189 NULL,
3191 NULL,
3192 NULL,
3193 INVALID_HANDLE_VALUE,
3194 NULL);
3196 /* FIXME: More code! */
3198 if (bFileQueueCreated)
3199 SetupCloseFileQueue(FileQueue);
3201 SetupCloseInfFile(hInf);
3203 return TRUE;
3207 /***********************************************************************
3208 * SetupDiOpenClassRegKey (SETUPAPI.@)
3210 HKEY WINAPI SetupDiOpenClassRegKey(
3211 const GUID* ClassGuid,
3212 REGSAM samDesired)
3214 return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3215 DIOCR_INSTALLER, NULL, NULL);
3219 /***********************************************************************
3220 * SetupDiOpenClassRegKeyExA (SETUPAPI.@)
3222 HKEY WINAPI SetupDiOpenClassRegKeyExA(
3223 const GUID* ClassGuid,
3224 REGSAM samDesired,
3225 DWORD Flags,
3226 PCSTR MachineName,
3227 PVOID Reserved)
3229 PWSTR MachineNameW = NULL;
3230 HKEY hKey;
3232 TRACE("\n");
3234 if (MachineName)
3236 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
3237 if (MachineNameW == NULL)
3238 return INVALID_HANDLE_VALUE;
3241 hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3242 Flags, MachineNameW, Reserved);
3244 MyFree(MachineNameW);
3246 return hKey;
3250 /***********************************************************************
3251 * SetupDiOpenClassRegKeyExW (SETUPAPI.@)
3253 HKEY WINAPI SetupDiOpenClassRegKeyExW(
3254 const GUID* ClassGuid,
3255 REGSAM samDesired,
3256 DWORD Flags,
3257 PCWSTR MachineName,
3258 PVOID Reserved)
3260 HKEY hClassesKey;
3261 HKEY key;
3262 LPCWSTR lpKeyName;
3263 LONG l;
3265 if (MachineName && *MachineName)
3267 FIXME("Remote access not supported yet!\n");
3268 return INVALID_HANDLE_VALUE;
3271 if (Flags == DIOCR_INSTALLER)
3273 lpKeyName = ControlClass;
3275 else if (Flags == DIOCR_INTERFACE)
3277 lpKeyName = DeviceClasses;
3279 else
3281 ERR("Invalid Flags parameter!\n");
3282 SetLastError(ERROR_INVALID_PARAMETER);
3283 return INVALID_HANDLE_VALUE;
3286 if (!ClassGuid)
3288 if ((l = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3289 lpKeyName,
3291 samDesired,
3292 &hClassesKey)))
3294 SetLastError(l);
3295 hClassesKey = INVALID_HANDLE_VALUE;
3297 key = hClassesKey;
3299 else
3301 WCHAR bracedGuidString[39];
3303 SETUPDI_GuidToString(ClassGuid, bracedGuidString);
3305 if (!(l = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3306 lpKeyName,
3308 samDesired,
3309 &hClassesKey)))
3311 if ((l = RegOpenKeyExW(hClassesKey,
3312 bracedGuidString,
3314 samDesired,
3315 &key)))
3317 SetLastError(l);
3318 key = INVALID_HANDLE_VALUE;
3320 RegCloseKey(hClassesKey);
3322 else
3324 SetLastError(l);
3325 key = INVALID_HANDLE_VALUE;
3328 return key;
3331 /***********************************************************************
3332 * SetupDiOpenDeviceInfoA (SETUPAPI.@)
3334 BOOL WINAPI SetupDiOpenDeviceInfoA(HDEVINFO devinfo, PCSTR instance_id, HWND hwnd_parent, DWORD flags,
3335 PSP_DEVINFO_DATA device_data)
3337 WCHAR instance_idW[MAX_DEVICE_ID_LEN];
3339 TRACE("%p %s %p 0x%08x %p\n", devinfo, debugstr_a(instance_id), hwnd_parent, flags, device_data);
3341 if (!instance_id || strlen(instance_id) >= MAX_DEVICE_ID_LEN)
3343 SetLastError(ERROR_INVALID_PARAMETER);
3344 return FALSE;
3347 MultiByteToWideChar(CP_ACP, 0, instance_id, -1, instance_idW, ARRAY_SIZE(instance_idW));
3348 return SetupDiOpenDeviceInfoW(devinfo, instance_idW, hwnd_parent, flags, device_data);
3351 /***********************************************************************
3352 * SetupDiOpenDeviceInfoW (SETUPAPI.@)
3354 BOOL WINAPI SetupDiOpenDeviceInfoW(HDEVINFO devinfo, PCWSTR instance_id, HWND hwnd_parent, DWORD flags,
3355 PSP_DEVINFO_DATA device_data)
3357 struct DeviceInfoSet *set;
3358 struct device *device = NULL, *enum_device;
3359 WCHAR classW[40];
3360 GUID guid;
3361 HKEY enumKey = NULL;
3362 HKEY instanceKey = NULL;
3363 DWORD phantom;
3364 DWORD size;
3365 DWORD error = ERROR_NO_SUCH_DEVINST;
3367 TRACE("%p %s %p 0x%08x %p\n", devinfo, debugstr_w(instance_id), hwnd_parent, flags, device_data);
3369 if (!(set = get_device_set(devinfo)))
3370 return FALSE;
3372 if (!instance_id)
3374 SetLastError(ERROR_INVALID_PARAMETER);
3375 return FALSE;
3378 if (hwnd_parent)
3379 FIXME("hwnd_parent unsupported\n");
3381 if (flags)
3382 FIXME("flags unsupported: 0x%08x\n", flags);
3384 RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &enumKey, NULL);
3385 /* Instance needs to be already existent in registry, if not, report ERROR_NO_SUCH_DEVINST */
3386 if (RegOpenKeyExW(enumKey, instance_id, 0, KEY_READ, &instanceKey))
3387 goto done;
3389 /* If it's an unregistered instance, aka phantom instance, report ERROR_NO_SUCH_DEVINST */
3390 size = sizeof(phantom);
3391 if (!RegQueryValueExW(instanceKey, Phantom, NULL, NULL, (BYTE *)&phantom, &size))
3392 goto done;
3394 /* Check class GUID */
3395 size = sizeof(classW);
3396 if (RegQueryValueExW(instanceKey, ClassGUID, NULL, NULL, (BYTE *)classW, &size))
3397 goto done;
3399 classW[37] = 0;
3400 UuidFromStringW(&classW[1], &guid);
3402 if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) && !IsEqualGUID(&guid, &set->ClassGuid))
3404 error = ERROR_CLASS_MISMATCH;
3405 goto done;
3408 /* If current set already contains a same instance, don't create new ones */
3409 LIST_FOR_EACH_ENTRY(enum_device, &set->devices, struct device, entry)
3411 if (!strcmpiW(instance_id, enum_device->instanceId))
3413 device = enum_device;
3414 break;
3418 if (!device && !(device = SETUPDI_CreateDeviceInfo(set, &guid, instance_id, FALSE)))
3419 goto done;
3421 if (!device_data || device_data->cbSize == sizeof(SP_DEVINFO_DATA))
3423 if (device_data)
3424 copy_device_data(device_data, device);
3425 error = NO_ERROR;
3427 else
3428 error = ERROR_INVALID_USER_BUFFER;
3430 done:
3431 RegCloseKey(instanceKey);
3432 RegCloseKey(enumKey);
3433 SetLastError(error);
3434 return !error;
3437 /***********************************************************************
3438 * SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
3440 BOOL WINAPI SetupDiOpenDeviceInterfaceW(
3441 HDEVINFO DeviceInfoSet,
3442 PCWSTR DevicePath,
3443 DWORD OpenFlags,
3444 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3446 FIXME("%p %s %08x %p\n",
3447 DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
3448 return FALSE;
3451 /***********************************************************************
3452 * SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
3454 BOOL WINAPI SetupDiOpenDeviceInterfaceA(
3455 HDEVINFO DeviceInfoSet,
3456 PCSTR DevicePath,
3457 DWORD OpenFlags,
3458 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3460 FIXME("%p %s %08x %p\n", DeviceInfoSet,
3461 debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
3462 return FALSE;
3465 /***********************************************************************
3466 * SetupDiSetClassInstallParamsA (SETUPAPI.@)
3468 BOOL WINAPI SetupDiSetClassInstallParamsA(
3469 HDEVINFO DeviceInfoSet,
3470 PSP_DEVINFO_DATA DeviceInfoData,
3471 PSP_CLASSINSTALL_HEADER ClassInstallParams,
3472 DWORD ClassInstallParamsSize)
3474 FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
3475 ClassInstallParams->InstallFunction, ClassInstallParamsSize);
3476 return FALSE;
3479 /***********************************************************************
3480 * SetupDiSetClassInstallParamsW (SETUPAPI.@)
3482 BOOL WINAPI SetupDiSetClassInstallParamsW(
3483 HDEVINFO DeviceInfoSet,
3484 PSP_DEVINFO_DATA DeviceInfoData,
3485 PSP_CLASSINSTALL_HEADER ClassInstallParams,
3486 DWORD ClassInstallParamsSize)
3488 FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
3489 ClassInstallParams->InstallFunction, ClassInstallParamsSize);
3490 return FALSE;
3493 /***********************************************************************
3494 * SetupDiCallClassInstaller (SETUPAPI.@)
3496 BOOL WINAPI SetupDiCallClassInstaller(
3497 DI_FUNCTION InstallFunction,
3498 HDEVINFO DeviceInfoSet,
3499 PSP_DEVINFO_DATA DeviceInfoData)
3501 FIXME("%d %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
3502 return FALSE;
3505 /***********************************************************************
3506 * SetupDiGetDeviceInstallParamsW (SETUPAPI.@)
3508 BOOL WINAPI SetupDiGetDeviceInstallParamsW(HDEVINFO devinfo,
3509 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_W *params)
3511 struct device *device;
3513 TRACE("devinfo %p, device_data %p, params %p.\n", devinfo, device_data, params);
3515 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
3517 SetLastError(ERROR_INVALID_USER_BUFFER);
3518 return FALSE;
3521 if (!(device = get_device(devinfo, device_data)))
3522 return FALSE;
3524 *params = device->params;
3526 return TRUE;
3529 /***********************************************************************
3530 * SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
3532 BOOL WINAPI SetupDiGetDeviceInstallParamsA(HDEVINFO devinfo,
3533 SP_DEVINFO_DATA *device_data, SP_DEVINSTALL_PARAMS_A *params)
3535 SP_DEVINSTALL_PARAMS_W paramsW;
3536 BOOL ret;
3538 if (params->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
3540 SetLastError(ERROR_INVALID_USER_BUFFER);
3541 return FALSE;
3544 paramsW.cbSize = sizeof(paramsW);
3545 ret = SetupDiGetDeviceInstallParamsW(devinfo, device_data, &paramsW);
3546 params->Flags = paramsW.Flags;
3547 params->FlagsEx = paramsW.FlagsEx;
3548 params->hwndParent = paramsW.hwndParent;
3549 params->InstallMsgHandler = paramsW.InstallMsgHandler;
3550 params->InstallMsgHandlerContext = paramsW.InstallMsgHandlerContext;
3551 params->FileQueue = paramsW.FileQueue;
3552 params->ClassInstallReserved = paramsW.ClassInstallReserved;
3553 params->Reserved = paramsW.Reserved;
3554 WideCharToMultiByte(CP_ACP, 0, paramsW.DriverPath, -1, params->DriverPath, sizeof(params->DriverPath), NULL, NULL);
3556 return ret;
3559 /***********************************************************************
3560 * SetupDiSetDeviceInstallParamsA (SETUPAPI.@)
3562 BOOL WINAPI SetupDiSetDeviceInstallParamsA(
3563 HDEVINFO DeviceInfoSet,
3564 PSP_DEVINFO_DATA DeviceInfoData,
3565 PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
3567 FIXME("(%p, %p, %p) stub\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
3569 return TRUE;
3572 /***********************************************************************
3573 * SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
3575 BOOL WINAPI SetupDiSetDeviceInstallParamsW(
3576 HDEVINFO DeviceInfoSet,
3577 PSP_DEVINFO_DATA DeviceInfoData,
3578 PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
3580 FIXME("(%p, %p, %p) stub\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
3582 return TRUE;
3585 BOOL WINAPI SetupDiSetDevicePropertyW(HDEVINFO devinfo, PSP_DEVINFO_DATA device_data, const DEVPROPKEY *key,
3586 DEVPROPTYPE type, const BYTE *buffer, DWORD size, DWORD flags)
3588 static const WCHAR propertiesW[] = {'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's', 0};
3589 static const WCHAR formatW[] = {'\\', '%', '0', '4', 'X', 0};
3590 struct device *device;
3591 HKEY properties_hkey, property_hkey;
3592 WCHAR property_hkey_path[44];
3593 LSTATUS ls;
3595 TRACE("%p %p %p %#x %p %d %#x\n", devinfo, device_data, key, type, buffer, size, flags);
3597 if (!(device = get_device(devinfo, device_data)))
3598 return FALSE;
3600 if (!key || !is_valid_property_type(type)
3601 || (buffer && !size && !(type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL))
3602 || (buffer && size && (type == DEVPROP_TYPE_EMPTY || type == DEVPROP_TYPE_NULL)))
3604 SetLastError(ERROR_INVALID_DATA);
3605 return FALSE;
3608 if (size && !buffer)
3610 SetLastError(ERROR_INVALID_USER_BUFFER);
3611 return FALSE;
3614 if (flags)
3616 SetLastError(ERROR_INVALID_FLAGS);
3617 return FALSE;
3620 ls = RegCreateKeyExW(device->key, propertiesW, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &properties_hkey, NULL);
3621 if (ls)
3623 SetLastError(ls);
3624 return FALSE;
3627 SETUPDI_GuidToString(&key->fmtid, property_hkey_path);
3628 sprintfW(property_hkey_path + 38, formatW, key->pid);
3630 if (type == DEVPROP_TYPE_EMPTY)
3632 ls = RegDeleteKeyW(properties_hkey, property_hkey_path);
3633 RegCloseKey(properties_hkey);
3634 SetLastError(ls == ERROR_FILE_NOT_FOUND ? ERROR_NOT_FOUND : ls);
3635 return !ls;
3637 else if (type == DEVPROP_TYPE_NULL)
3639 if (!(ls = RegOpenKeyW(properties_hkey, property_hkey_path, &property_hkey)))
3641 ls = RegDeleteValueW(property_hkey, NULL);
3642 RegCloseKey(property_hkey);
3645 RegCloseKey(properties_hkey);
3646 SetLastError(ls == ERROR_FILE_NOT_FOUND ? ERROR_NOT_FOUND : ls);
3647 return !ls;
3649 else
3651 if (!(ls = RegCreateKeyExW(properties_hkey, property_hkey_path, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL,
3652 &property_hkey, NULL)))
3654 ls = RegSetValueExW(property_hkey, NULL, 0, 0xffff0000 | (0xffff & type), buffer, size);
3655 RegCloseKey(property_hkey);
3658 RegCloseKey(properties_hkey);
3659 SetLastError(ls);
3660 return !ls;
3664 /***********************************************************************
3665 * SetupDiOpenDevRegKey (SETUPAPI.@)
3667 HKEY WINAPI SetupDiOpenDevRegKey(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
3668 DWORD Scope, DWORD HwProfile, DWORD KeyType, REGSAM samDesired)
3670 struct device *device;
3671 HKEY key = INVALID_HANDLE_VALUE;
3672 LONG l;
3674 TRACE("devinfo %p, device_data %p, scope %d, profile %d, type %d, access %#x.\n",
3675 devinfo, device_data, Scope, HwProfile, KeyType, samDesired);
3677 if (!(device = get_device(devinfo, device_data)))
3678 return INVALID_HANDLE_VALUE;
3680 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
3682 SetLastError(ERROR_INVALID_FLAGS);
3683 return INVALID_HANDLE_VALUE;
3685 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
3687 SetLastError(ERROR_INVALID_FLAGS);
3688 return INVALID_HANDLE_VALUE;
3691 if (device->phantom)
3693 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
3694 return INVALID_HANDLE_VALUE;
3696 if (Scope != DICS_FLAG_GLOBAL)
3697 FIXME("unimplemented for scope %d\n", Scope);
3698 switch (KeyType)
3700 case DIREG_DEV:
3701 l = RegOpenKeyExW(device->key, DeviceParameters, 0, samDesired, &key);
3702 break;
3703 case DIREG_DRV:
3704 l = open_driver_key(device, samDesired, &key);
3705 break;
3706 default:
3707 FIXME("Unhandled type %#x.\n", KeyType);
3708 l = ERROR_CALL_NOT_IMPLEMENTED;
3710 SetLastError(l == ERROR_FILE_NOT_FOUND ? ERROR_KEY_DOES_NOT_EXIST : l);
3711 return l ? INVALID_HANDLE_VALUE : key;
3714 /***********************************************************************
3715 * SetupDiDeleteDevRegKey (SETUPAPI.@)
3717 BOOL WINAPI SetupDiDeleteDevRegKey(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data,
3718 DWORD Scope, DWORD HwProfile, DWORD KeyType)
3720 struct device *device;
3721 LONG l;
3723 TRACE("devinfo %p, device_data %p, scope %d, profile %d, type %d.\n",
3724 devinfo, device_data, Scope, HwProfile, KeyType);
3726 if (!(device = get_device(devinfo, device_data)))
3727 return FALSE;
3729 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
3731 SetLastError(ERROR_INVALID_FLAGS);
3732 return FALSE;
3734 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV && KeyType != DIREG_BOTH)
3736 SetLastError(ERROR_INVALID_FLAGS);
3737 return FALSE;
3740 if (device->phantom)
3742 SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
3743 return FALSE;
3745 if (Scope != DICS_FLAG_GLOBAL)
3746 FIXME("unimplemented for scope %d\n", Scope);
3747 switch (KeyType)
3749 case DIREG_DRV:
3750 l = delete_driver_key(device);
3751 break;
3752 case DIREG_BOTH:
3753 if ((l = delete_driver_key(device)))
3754 break;
3755 /* fall through */
3756 case DIREG_DEV:
3757 l = RegDeleteKeyW(device->key, DeviceParameters);
3758 break;
3759 default:
3760 FIXME("Unhandled type %#x.\n", KeyType);
3761 l = ERROR_CALL_NOT_IMPLEMENTED;
3763 SetLastError(l);
3764 return !l;
3767 /***********************************************************************
3768 * CM_Get_Device_IDA (SETUPAPI.@)
3770 CONFIGRET WINAPI CM_Get_Device_IDA(DEVINST devnode, char *buffer, ULONG len, ULONG flags)
3772 struct device *device = get_devnode_device(devnode);
3774 TRACE("%u, %p, %u, %#x\n", devnode, buffer, len, flags);
3776 if (!device)
3777 return CR_NO_SUCH_DEVINST;
3779 WideCharToMultiByte(CP_ACP, 0, device->instanceId, -1, buffer, len, 0, 0);
3780 TRACE("Returning %s\n", debugstr_a(buffer));
3781 return CR_SUCCESS;
3784 /***********************************************************************
3785 * CM_Get_Device_IDW (SETUPAPI.@)
3787 CONFIGRET WINAPI CM_Get_Device_IDW(DEVINST devnode, WCHAR *buffer, ULONG len, ULONG flags)
3789 struct device *device = get_devnode_device(devnode);
3791 TRACE("%u, %p, %u, %#x\n", devnode, buffer, len, flags);
3793 if (!device)
3794 return CR_NO_SUCH_DEVINST;
3796 lstrcpynW(buffer, device->instanceId, len);
3797 TRACE("Returning %s\n", debugstr_w(buffer));
3798 return CR_SUCCESS;
3801 /***********************************************************************
3802 * CM_Get_Device_ID_Size (SETUPAPI.@)
3804 CONFIGRET WINAPI CM_Get_Device_ID_Size(ULONG *len, DEVINST devnode, ULONG flags)
3806 struct device *device = get_devnode_device(devnode);
3808 TRACE("%p, %u, %#x\n", len, devnode, flags);
3810 if (!device)
3811 return CR_NO_SUCH_DEVINST;
3813 *len = lstrlenW(device->instanceId);
3814 return CR_SUCCESS;
3817 /***********************************************************************
3818 * SetupDiGetINFClassA (SETUPAPI.@)
3820 BOOL WINAPI SetupDiGetINFClassA(PCSTR inf, LPGUID class_guid, PSTR class_name,
3821 DWORD size, PDWORD required_size)
3823 BOOL retval;
3824 DWORD required_sizeA, required_sizeW;
3825 PWSTR class_nameW = NULL;
3826 UNICODE_STRING infW;
3828 if (inf)
3830 if (!RtlCreateUnicodeStringFromAsciiz(&infW, inf))
3832 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3833 return FALSE;
3836 else
3837 infW.Buffer = NULL;
3839 if (class_name && size)
3841 if (!(class_nameW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR))))
3843 RtlFreeUnicodeString(&infW);
3844 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3845 return FALSE;
3849 retval = SetupDiGetINFClassW(infW.Buffer, class_guid, class_nameW, size, &required_sizeW);
3851 if (retval)
3853 required_sizeA = WideCharToMultiByte( CP_ACP, 0, class_nameW, required_sizeW,
3854 class_name, size, NULL, NULL);
3856 if(required_size) *required_size = required_sizeA;
3858 else
3859 if(required_size) *required_size = required_sizeW;
3861 HeapFree(GetProcessHeap(), 0, class_nameW);
3862 RtlFreeUnicodeString(&infW);
3863 return retval;
3866 /***********************************************************************
3867 * SetupDiGetINFClassW (SETUPAPI.@)
3869 BOOL WINAPI SetupDiGetINFClassW(PCWSTR inf, LPGUID class_guid, PWSTR class_name,
3870 DWORD size, PDWORD required_size)
3872 BOOL have_guid, have_name;
3873 DWORD dret;
3874 WCHAR buffer[MAX_PATH];
3876 if (!inf)
3878 SetLastError(ERROR_INVALID_PARAMETER);
3879 return FALSE;
3882 if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(inf))
3884 FIXME("%s not found. Searching via DevicePath not implemented\n", debugstr_w(inf));
3885 SetLastError(ERROR_FILE_NOT_FOUND);
3886 return FALSE;
3889 if (!class_guid || !class_name || !size)
3891 SetLastError(ERROR_INVALID_PARAMETER);
3892 return FALSE;
3895 if (!GetPrivateProfileStringW(Version, Signature, NULL, buffer, MAX_PATH, inf))
3896 return FALSE;
3898 if (lstrcmpiW(buffer, Chicago) && lstrcmpiW(buffer, WindowsNT))
3899 return FALSE;
3901 buffer[0] = '\0';
3902 have_guid = 0 < GetPrivateProfileStringW(Version, ClassGUID, NULL, buffer, MAX_PATH, inf);
3903 if (have_guid)
3905 buffer[lstrlenW(buffer)-1] = 0;
3906 if (RPC_S_OK != UuidFromStringW(buffer + 1, class_guid))
3908 FIXME("failed to convert \"%s\" into a guid\n", debugstr_w(buffer));
3909 SetLastError(ERROR_INVALID_PARAMETER);
3910 return FALSE;
3914 buffer[0] = '\0';
3915 dret = GetPrivateProfileStringW(Version, Class, NULL, buffer, MAX_PATH, inf);
3916 have_name = 0 < dret;
3918 if (dret >= MAX_PATH -1) FIXME("buffer might be too small\n");
3919 if (have_guid && !have_name) FIXME("class name lookup via guid not implemented\n");
3921 if (have_name)
3923 if (dret < size) lstrcpyW(class_name, buffer);
3924 else
3926 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3927 have_name = FALSE;
3931 if (required_size) *required_size = dret + ((dret) ? 1 : 0);
3933 return (have_guid || have_name);
3936 /***********************************************************************
3937 * SetupDiGetDevicePropertyW (SETUPAPI.@)
3939 BOOL WINAPI SetupDiGetDevicePropertyW(HDEVINFO devinfo, PSP_DEVINFO_DATA device_data,
3940 const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type, BYTE *prop_buff,
3941 DWORD prop_buff_size, DWORD *required_size, DWORD flags)
3943 static const WCHAR formatW[] = {'\\', '%', '0', '4', 'X', 0};
3944 WCHAR key_path[55] = {'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's', '\\'};
3945 HKEY hkey;
3946 DWORD value_type;
3947 DWORD value_size = 0;
3948 LSTATUS ls;
3949 struct device *device;
3951 TRACE("%p, %p, %p, %p, %p, %d, %p, %#x\n", devinfo, device_data, prop_key, prop_type, prop_buff, prop_buff_size,
3952 required_size, flags);
3954 if (!(device = get_device(devinfo, device_data)))
3955 return FALSE;
3957 if (!prop_key)
3959 SetLastError(ERROR_INVALID_DATA);
3960 return FALSE;
3963 if (!prop_type || (!prop_buff && prop_buff_size))
3965 SetLastError(ERROR_INVALID_USER_BUFFER);
3966 return FALSE;
3969 if (flags)
3971 SetLastError(ERROR_INVALID_FLAGS);
3972 return FALSE;
3975 SETUPDI_GuidToString(&prop_key->fmtid, key_path + 11);
3976 sprintfW(key_path + 49, formatW, prop_key->pid);
3978 ls = RegOpenKeyExW(device->key, key_path, 0, KEY_QUERY_VALUE, &hkey);
3979 if (!ls)
3981 value_size = prop_buff_size;
3982 ls = RegQueryValueExW(hkey, NULL, NULL, &value_type, prop_buff, &value_size);
3985 switch (ls)
3987 case NO_ERROR:
3988 case ERROR_MORE_DATA:
3989 *prop_type = 0xffff & value_type;
3990 ls = (ls == ERROR_MORE_DATA || !prop_buff) ? ERROR_INSUFFICIENT_BUFFER : NO_ERROR;
3991 break;
3992 case ERROR_FILE_NOT_FOUND:
3993 *prop_type = DEVPROP_TYPE_EMPTY;
3994 value_size = 0;
3995 ls = ERROR_NOT_FOUND;
3996 break;
3997 default:
3998 *prop_type = DEVPROP_TYPE_EMPTY;
3999 value_size = 0;
4000 FIXME("Unhandled error %#x\n", ls);
4001 break;
4004 if (required_size)
4005 *required_size = value_size;
4007 SetLastError(ls);
4008 return !ls;
4011 /***********************************************************************
4012 * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
4014 BOOL WINAPI SetupDiInstallDeviceInterfaces(HDEVINFO dev, PSP_DEVINFO_DATA info_data)
4016 FIXME("%p, %p stub\n", dev, info_data);
4018 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4019 return FALSE;
4022 /***********************************************************************
4023 * SetupDiRegisterCoDeviceInstallers (SETUPAPI.@)
4025 BOOL WINAPI SetupDiRegisterCoDeviceInstallers(HDEVINFO dev, PSP_DEVINFO_DATA info_data)
4027 FIXME("%p, %p stub\n", dev, info_data);
4029 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4030 return FALSE;