2 * SetupAPI device installer
4 * Copyright 2000 Andreas Mohr for CodeWeavers
5 * 2005 Hervé Poussineau (hpoussin@reactos.com)
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "wine/port.h"
36 #include "wine/debug.h"
37 #include "wine/unicode.h"
44 #include "setupapi_private.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(setupapi
);
49 /* Unicode constants */
50 static const WCHAR ClassGUID
[] = {'C','l','a','s','s','G','U','I','D',0};
51 static const WCHAR Class
[] = {'C','l','a','s','s',0};
52 static const WCHAR ClassInstall32
[] = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
53 static const WCHAR DeviceInstance
[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',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','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 SymbolicLink
[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
60 static const WCHAR Version
[] = {'V','e','r','s','i','o','n',0};
61 static const WCHAR WinExtension
[] = {'.','W','i','n',0};
63 /* Registry key and value names */
64 static const WCHAR ControlClass
[] = {'S','y','s','t','e','m','\\',
65 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
66 'C','o','n','t','r','o','l','\\',
67 'C','l','a','s','s',0};
69 static const WCHAR DeviceClasses
[] = {'S','y','s','t','e','m','\\',
70 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
71 'C','o','n','t','r','o','l','\\',
72 'D','e','v','i','c','e','C','l','a','s','s','e','s',0};
74 static const WCHAR EnumKeyName
[] = {'S','y','s','t','e','m','\\',
75 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
79 typedef struct _DeviceInfo
82 BOOL IsDevice
; /* This entry is a device or an interface */
88 WCHAR RegistryKey
[0]; /* "0000", "0001"... */
95 /* Pointer into Data field. Contains something like */
96 /* "ACPI\PNP0501\4&2658d0a0&0" */
99 /* Pointer into Data field. Contains something like
100 * "\\?\ACPI#PNP0501#4&2658d0a0&0#{GUID}", or "COMx" for WINE */
107 #define SETUP_DEV_INFO_LIST_MAGIC 0xd00ff056
109 typedef struct _DeviceInfoList
112 GUID ClassGuid
; /* Only devices related of this class are in the device list */
114 HKEY HKLM
; /* Local or distant HKEY_LOCAL_MACHINE registry key */
115 DWORD numberOfEntries
;
119 /* FIXME: header mess */
120 DEFINE_GUID(GUID_NULL
,
121 0x00000000L
, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
123 /***********************************************************************
124 * SetupDiBuildClassInfoList (SETUPAPI.@)
126 BOOL WINAPI
SetupDiBuildClassInfoList(
128 LPGUID ClassGuidList
,
129 DWORD ClassGuidListSize
,
133 return SetupDiBuildClassInfoListExW(Flags
, ClassGuidList
,
134 ClassGuidListSize
, RequiredSize
,
138 /***********************************************************************
139 * SetupDiBuildClassInfoListExA (SETUPAPI.@)
141 BOOL WINAPI
SetupDiBuildClassInfoListExA(
143 LPGUID ClassGuidList
,
144 DWORD ClassGuidListSize
,
149 LPWSTR MachineNameW
= NULL
;
156 MachineNameW
= MultiByteToUnicode(MachineName
, CP_ACP
);
157 if (MachineNameW
== NULL
) return FALSE
;
160 bResult
= SetupDiBuildClassInfoListExW(Flags
, ClassGuidList
,
161 ClassGuidListSize
, RequiredSize
,
162 MachineNameW
, Reserved
);
165 MyFree(MachineNameW
);
170 /***********************************************************************
171 * SetupDiBuildClassInfoListExW (SETUPAPI.@)
173 BOOL WINAPI
SetupDiBuildClassInfoListExW(
175 LPGUID ClassGuidList
,
176 DWORD ClassGuidListSize
,
181 WCHAR szKeyName
[MAX_GUID_STRING_LEN
+ 1];
187 DWORD dwGuidListIndex
= 0;
191 if (RequiredSize
!= NULL
)
194 hClassesKey
= SetupDiOpenClassRegKeyExW(NULL
,
199 if (hClassesKey
== INVALID_HANDLE_VALUE
)
204 for (dwIndex
= 0; ; dwIndex
++)
206 dwLength
= MAX_GUID_STRING_LEN
+ 1;
207 lError
= RegEnumKeyExW(hClassesKey
,
215 TRACE("RegEnumKeyExW() returns %ld\n", lError
);
216 if (lError
== ERROR_SUCCESS
|| lError
== ERROR_MORE_DATA
)
218 TRACE("Key name: %p\n", szKeyName
);
220 if (RegOpenKeyExW(hClassesKey
,
226 RegCloseKey(hClassesKey
);
230 if (!RegQueryValueExW(hClassKey
,
237 TRACE("'NoUseClass' value found!\n");
238 RegCloseKey(hClassKey
);
242 if ((Flags
& DIBCI_NOINSTALLCLASS
) &&
243 (!RegQueryValueExW(hClassKey
,
250 TRACE("'NoInstallClass' value found!\n");
251 RegCloseKey(hClassKey
);
255 if ((Flags
& DIBCI_NODISPLAYCLASS
) &&
256 (!RegQueryValueExW(hClassKey
,
263 TRACE("'NoDisplayClass' value found!\n");
264 RegCloseKey(hClassKey
);
268 RegCloseKey(hClassKey
);
270 TRACE("Guid: %p\n", szKeyName
);
271 if (dwGuidListIndex
< ClassGuidListSize
)
273 if (szKeyName
[0] == L
'{' && szKeyName
[37] == L
'}')
277 TRACE("Guid: %p\n", &szKeyName
[1]);
279 UuidFromStringW(&szKeyName
[1],
280 &ClassGuidList
[dwGuidListIndex
]);
286 if (lError
!= ERROR_SUCCESS
)
290 RegCloseKey(hClassesKey
);
292 if (RequiredSize
!= NULL
)
293 *RequiredSize
= dwGuidListIndex
;
295 if (ClassGuidListSize
< dwGuidListIndex
)
297 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
304 /***********************************************************************
305 * SetupDiClassGuidsFromNameA (SETUPAPI.@)
307 BOOL WINAPI
SetupDiClassGuidsFromNameA(
309 LPGUID ClassGuidList
,
310 DWORD ClassGuidListSize
,
313 return SetupDiClassGuidsFromNameExA(ClassName
, ClassGuidList
,
314 ClassGuidListSize
, RequiredSize
,
318 /***********************************************************************
319 * SetupDiClassGuidsFromNameW (SETUPAPI.@)
321 BOOL WINAPI
SetupDiClassGuidsFromNameW(
323 LPGUID ClassGuidList
,
324 DWORD ClassGuidListSize
,
327 return SetupDiClassGuidsFromNameExW(ClassName
, ClassGuidList
,
328 ClassGuidListSize
, RequiredSize
,
332 /***********************************************************************
333 * SetupDiClassGuidsFromNameExA (SETUPAPI.@)
335 BOOL WINAPI
SetupDiClassGuidsFromNameExA(
337 LPGUID ClassGuidList
,
338 DWORD ClassGuidListSize
,
343 LPWSTR ClassNameW
= NULL
;
344 LPWSTR MachineNameW
= NULL
;
349 ClassNameW
= MultiByteToUnicode(ClassName
, CP_ACP
);
350 if (ClassNameW
== NULL
)
355 MachineNameW
= MultiByteToUnicode(MachineName
, CP_ACP
);
356 if (MachineNameW
== NULL
)
363 bResult
= SetupDiClassGuidsFromNameExW(ClassNameW
, ClassGuidList
,
364 ClassGuidListSize
, RequiredSize
,
365 MachineNameW
, Reserved
);
368 MyFree(MachineNameW
);
375 /***********************************************************************
376 * SetupDiClassGuidsFromNameExW (SETUPAPI.@)
378 BOOL WINAPI
SetupDiClassGuidsFromNameExW(
380 LPGUID ClassGuidList
,
381 DWORD ClassGuidListSize
,
386 WCHAR szKeyName
[MAX_GUID_STRING_LEN
+ 1];
387 WCHAR szClassName
[256];
393 DWORD dwGuidListIndex
= 0;
395 if (RequiredSize
!= NULL
)
398 hClassesKey
= SetupDiOpenClassRegKeyExW(NULL
,
399 KEY_ENUMERATE_SUB_KEYS
,
403 if (hClassesKey
== INVALID_HANDLE_VALUE
)
408 for (dwIndex
= 0; ; dwIndex
++)
410 dwLength
= MAX_GUID_STRING_LEN
+ 1;
411 lError
= RegEnumKeyExW(hClassesKey
,
419 TRACE("RegEnumKeyExW() returns %ld\n", lError
);
420 if (lError
== ERROR_SUCCESS
|| lError
== ERROR_MORE_DATA
)
422 TRACE("Key name: %p\n", szKeyName
);
424 if (RegOpenKeyExW(hClassesKey
,
430 RegCloseKey(hClassesKey
);
434 dwLength
= 256 * sizeof(WCHAR
);
435 if (!RegQueryValueExW(hClassKey
,
442 TRACE("Class name: %p\n", szClassName
);
444 if (strcmpiW(szClassName
, ClassName
) == 0)
446 TRACE("Found matching class name\n");
448 TRACE("Guid: %p\n", szKeyName
);
449 if (dwGuidListIndex
< ClassGuidListSize
)
451 if (szKeyName
[0] == L
'{' && szKeyName
[37] == L
'}')
455 TRACE("Guid: %p\n", &szKeyName
[1]);
457 UuidFromStringW(&szKeyName
[1],
458 &ClassGuidList
[dwGuidListIndex
]);
465 RegCloseKey(hClassKey
);
468 if (lError
!= ERROR_SUCCESS
)
472 RegCloseKey(hClassesKey
);
474 if (RequiredSize
!= NULL
)
475 *RequiredSize
= dwGuidListIndex
;
477 if (ClassGuidListSize
< dwGuidListIndex
)
479 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
486 /***********************************************************************
487 * SetupDiClassNameFromGuidA (SETUPAPI.@)
489 BOOL WINAPI
SetupDiClassNameFromGuidA(
490 const GUID
* ClassGuid
,
495 return SetupDiClassNameFromGuidExA(ClassGuid
, ClassName
,
496 ClassNameSize
, RequiredSize
,
500 /***********************************************************************
501 * SetupDiClassNameFromGuidW (SETUPAPI.@)
503 BOOL WINAPI
SetupDiClassNameFromGuidW(
504 const GUID
* ClassGuid
,
509 return SetupDiClassNameFromGuidExW(ClassGuid
, ClassName
,
510 ClassNameSize
, RequiredSize
,
514 /***********************************************************************
515 * SetupDiClassNameFromGuidExA (SETUPAPI.@)
517 BOOL WINAPI
SetupDiClassNameFromGuidExA(
518 const GUID
* ClassGuid
,
525 WCHAR ClassNameW
[MAX_CLASS_NAME_LEN
];
526 LPWSTR MachineNameW
= NULL
;
530 MachineNameW
= MultiByteToUnicode(MachineName
, CP_ACP
);
531 ret
= SetupDiClassNameFromGuidExW(ClassGuid
, ClassNameW
, MAX_CLASS_NAME_LEN
,
532 NULL
, MachineNameW
, Reserved
);
535 int len
= WideCharToMultiByte(CP_ACP
, 0, ClassNameW
, -1, ClassName
,
536 ClassNameSize
, NULL
, NULL
);
538 if (!ClassNameSize
&& RequiredSize
)
541 MyFree(MachineNameW
);
545 /***********************************************************************
546 * SetupDiClassNameFromGuidExW (SETUPAPI.@)
548 BOOL WINAPI
SetupDiClassNameFromGuidExW(
549 const GUID
* ClassGuid
,
560 hKey
= SetupDiOpenClassRegKeyExW(ClassGuid
,
565 if (hKey
== INVALID_HANDLE_VALUE
)
570 if (RequiredSize
!= NULL
)
573 rc
= RegQueryValueExW(hKey
,
579 if (rc
!= ERROR_SUCCESS
)
586 *RequiredSize
= dwLength
/ sizeof(WCHAR
);
589 dwLength
= ClassNameSize
* sizeof(WCHAR
);
590 rc
= RegQueryValueExW(hKey
,
596 if (rc
!= ERROR_SUCCESS
)
608 /***********************************************************************
609 * SetupDiCreateDeviceInfoList (SETUPAPI.@)
612 SetupDiCreateDeviceInfoList(const GUID
*ClassGuid
,
615 return SetupDiCreateDeviceInfoListExW(ClassGuid
, hwndParent
, NULL
, NULL
);
618 /***********************************************************************
619 * SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
622 SetupDiCreateDeviceInfoListExA(const GUID
*ClassGuid
,
627 LPWSTR MachineNameW
= NULL
;
634 MachineNameW
= MultiByteToUnicode(MachineName
, CP_ACP
);
635 if (MachineNameW
== NULL
)
636 return (HDEVINFO
)INVALID_HANDLE_VALUE
;
639 hDevInfo
= SetupDiCreateDeviceInfoListExW(ClassGuid
, hwndParent
,
640 MachineNameW
, Reserved
);
643 MyFree(MachineNameW
);
648 /***********************************************************************
649 * SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
652 SetupDiCreateDeviceInfoListExW(const GUID
*ClassGuid
,
657 DeviceInfoList
* list
;
660 TRACE("%p %p %p %p\n", ClassGuid
, hwndParent
, MachineName
, Reserved
);
662 list
= HeapAlloc(GetProcessHeap(), 0, sizeof(DeviceInfoList
));
665 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
666 return (HDEVINFO
)INVALID_HANDLE_VALUE
;
669 list
->magic
= SETUP_DEV_INFO_LIST_MAGIC
;
670 list
->hWnd
= hwndParent
;
671 list
->numberOfEntries
= 0;
673 rc
= RegConnectRegistryW(MachineName
, HKEY_LOCAL_MACHINE
, &list
->HKLM
);
675 rc
= RegOpenKey(HKEY_LOCAL_MACHINE
, NULL
, &list
->HKLM
);
676 if (rc
!= ERROR_SUCCESS
)
679 HeapFree(GetProcessHeap(), 0, list
);
680 return (HDEVINFO
)INVALID_HANDLE_VALUE
;
684 ClassGuid
? ClassGuid
: &GUID_NULL
,
685 sizeof(list
->ClassGuid
));
686 InitializeListHead(&list
->ListHead
);
687 return (HDEVINFO
)list
;
690 /***********************************************************************
691 * SetupDiEnumDeviceInfo (SETUPAPI.@)
693 BOOL WINAPI
SetupDiEnumDeviceInfo(
694 HDEVINFO DeviceInfoSet
,
696 PSP_DEVINFO_DATA DeviceInfoData
)
700 TRACE("%p, 0x%08lx, %p\n", DeviceInfoSet
, MemberIndex
, DeviceInfoData
);
702 SetLastError(ERROR_INVALID_PARAMETER
);
703 else if (DeviceInfoSet
&& DeviceInfoSet
!= (HDEVINFO
)INVALID_HANDLE_VALUE
)
705 DeviceInfoList
*list
= (DeviceInfoList
*)DeviceInfoSet
;
707 if (list
->magic
!= SETUP_DEV_INFO_LIST_MAGIC
)
708 SetLastError(ERROR_INVALID_HANDLE
);
709 else if (DeviceInfoData
->cbSize
!= sizeof(SP_DEVINFO_DATA
))
710 SetLastError(ERROR_INVALID_USER_BUFFER
);
711 else if (MemberIndex
>= list
->numberOfEntries
)
712 SetLastError(ERROR_NO_MORE_ITEMS
);
715 PLIST_ENTRY ItemList
= list
->ListHead
.Flink
;
717 while (MemberIndex
-- > 0)
718 ItemList
= ItemList
->Flink
;
719 DevInfo
= (DeviceInfo
*)ItemList
;
720 if (DevInfo
->IsDevice
)
722 memcpy(&DeviceInfoData
->ClassGuid
,
723 &DevInfo
->Device
.ClassGuid
,
725 DeviceInfoData
->DevInst
= 0; /* FIXME */
726 DeviceInfoData
->Reserved
= (ULONG_PTR
)0;
731 SetLastError(ERROR_INVALID_PARAMETER
);
736 SetLastError(ERROR_INVALID_HANDLE
);
740 /***********************************************************************
741 * SetupDiGetActualSectionToInstallA (SETUPAPI.@)
743 BOOL WINAPI
SetupDiGetActualSectionToInstallA(
745 PCSTR InfSectionName
,
746 PSTR InfSectionWithExt
,
747 DWORD InfSectionWithExtSize
,
751 LPWSTR InfSectionNameW
= NULL
;
752 PWSTR InfSectionWithExtW
= NULL
;
760 InfSectionNameW
= MultiByteToUnicode(InfSectionName
, CP_ACP
);
761 if (InfSectionNameW
== NULL
) goto end
;
763 if (InfSectionWithExt
)
765 InfSectionWithExtW
= HeapAlloc(GetProcessHeap(), 0, InfSectionWithExtSize
* sizeof(WCHAR
));
766 if (InfSectionWithExtW
== NULL
) goto end
;
769 bResult
= SetupDiGetActualSectionToInstallW(InfHandle
, InfSectionNameW
,
770 InfSectionWithExt
? InfSectionNameW
: NULL
,
771 InfSectionWithExtSize
, RequiredSize
,
772 Extension
? &ExtensionW
: NULL
);
774 if (bResult
&& InfSectionWithExt
)
776 bResult
= WideCharToMultiByte(CP_ACP
, 0, InfSectionWithExtW
, -1, InfSectionWithExt
,
777 InfSectionWithExtSize
, NULL
, NULL
) != 0;
779 if (bResult
&& Extension
)
781 if (ExtensionW
== NULL
)
784 *Extension
= &InfSectionWithExt
[ExtensionW
- InfSectionWithExtW
];
788 if (InfSectionNameW
) MyFree(InfSectionNameW
);
789 if (InfSectionWithExtW
) HeapFree(GetProcessHeap(), 0, InfSectionWithExtW
);
794 /***********************************************************************
795 * SetupDiGetActualSectionToInstallW (SETUPAPI.@)
797 BOOL WINAPI
SetupDiGetActualSectionToInstallW(
799 PCWSTR InfSectionName
,
800 PWSTR InfSectionWithExt
,
801 DWORD InfSectionWithExtSize
,
805 WCHAR szBuffer
[MAX_PATH
];
808 LONG lLineCount
= -1;
810 lstrcpyW(szBuffer
, InfSectionName
);
811 dwLength
= lstrlenW(szBuffer
);
813 if (OsVersionInfo
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)
815 /* Test section name with '.NTx86' extension */
816 lstrcpyW(&szBuffer
[dwLength
], NtPlatformExtension
);
817 lLineCount
= SetupGetLineCountW(InfHandle
, szBuffer
);
819 if (lLineCount
== -1)
821 /* Test section name with '.NT' extension */
822 lstrcpyW(&szBuffer
[dwLength
], NtExtension
);
823 lLineCount
= SetupGetLineCountW(InfHandle
, szBuffer
);
828 /* Test section name with '.Win' extension */
829 lstrcpyW(&szBuffer
[dwLength
], WinExtension
);
830 lLineCount
= SetupGetLineCountW(InfHandle
, szBuffer
);
833 if (lLineCount
== -1)
835 /* Test section name without extension */
836 szBuffer
[dwLength
] = 0;
837 lLineCount
= SetupGetLineCountW(InfHandle
, szBuffer
);
840 if (lLineCount
== -1)
842 SetLastError(ERROR_INVALID_PARAMETER
);
846 dwFullLength
= lstrlenW(szBuffer
);
848 if (InfSectionWithExt
!= NULL
&& InfSectionWithExtSize
!= 0)
850 if (InfSectionWithExtSize
< (dwFullLength
+ 1))
852 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
856 lstrcpyW(InfSectionWithExt
, szBuffer
);
857 if (Extension
!= NULL
)
859 *Extension
= (dwLength
== dwFullLength
) ? NULL
: &InfSectionWithExt
[dwLength
];
863 if (RequiredSize
!= NULL
)
865 *RequiredSize
= dwFullLength
+ 1;
871 /***********************************************************************
872 * SetupDiGetClassDescriptionA (SETUPAPI.@)
874 BOOL WINAPI
SetupDiGetClassDescriptionA(
875 const GUID
* ClassGuid
,
876 PSTR ClassDescription
,
877 DWORD ClassDescriptionSize
,
880 return SetupDiGetClassDescriptionExA(ClassGuid
, ClassDescription
,
881 ClassDescriptionSize
,
882 RequiredSize
, NULL
, NULL
);
885 /***********************************************************************
886 * SetupDiGetClassDescriptionW (SETUPAPI.@)
888 BOOL WINAPI
SetupDiGetClassDescriptionW(
889 const GUID
* ClassGuid
,
890 PWSTR ClassDescription
,
891 DWORD ClassDescriptionSize
,
894 return SetupDiGetClassDescriptionExW(ClassGuid
, ClassDescription
,
895 ClassDescriptionSize
,
896 RequiredSize
, NULL
, NULL
);
899 /***********************************************************************
900 * SetupDiGetClassDescriptionExA (SETUPAPI.@)
902 BOOL WINAPI
SetupDiGetClassDescriptionExA(
903 const GUID
* ClassGuid
,
904 PSTR ClassDescription
,
905 DWORD ClassDescriptionSize
,
910 PWCHAR ClassDescriptionW
;
911 LPWSTR MachineNameW
= NULL
;
915 if (ClassDescriptionSize
> 0)
917 ClassDescriptionW
= HeapAlloc(GetProcessHeap(), 0, ClassDescriptionSize
* sizeof(WCHAR
));
918 if (!ClassDescriptionW
)
920 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
928 MachineNameW
= MultiByteToUnicode(MachineName
, CP_ACP
);
931 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
937 ret
= SetupDiGetClassDescriptionExW(ClassGuid
, ClassDescriptionW
, ClassDescriptionSize
* sizeof(WCHAR
),
938 NULL
, MachineNameW
, Reserved
);
941 int len
= WideCharToMultiByte(CP_ACP
, 0, ClassDescriptionW
, -1, ClassDescription
,
942 ClassDescriptionSize
, NULL
, NULL
);
944 if (!ClassDescriptionSize
&& RequiredSize
)
949 HeapFree(GetProcessHeap(), 0, ClassDescriptionW
);
950 MyFree(MachineNameW
);
954 /***********************************************************************
955 * SetupDiGetClassDescriptionExW (SETUPAPI.@)
957 BOOL WINAPI
SetupDiGetClassDescriptionExW(
958 const GUID
* ClassGuid
,
959 PWSTR ClassDescription
,
960 DWORD ClassDescriptionSize
,
968 hKey
= SetupDiOpenClassRegKeyExW(ClassGuid
,
973 if (hKey
== INVALID_HANDLE_VALUE
)
975 WARN("SetupDiOpenClassRegKeyExW() failed (Error %lu)\n", GetLastError());
979 if (RequiredSize
!= NULL
)
982 if (RegQueryValueExW(hKey
,
993 *RequiredSize
= dwLength
/ sizeof(WCHAR
);
996 dwLength
= ClassDescriptionSize
* sizeof(WCHAR
);
997 if (RegQueryValueExW(hKey
,
1001 (LPBYTE
)ClassDescription
,
1013 /***********************************************************************
1014 * SetupDiGetClassDevsA (SETUPAPI.@)
1016 HDEVINFO WINAPI
SetupDiGetClassDevsA(
1022 return SetupDiGetClassDevsExA(class, enumstr
, parent
,
1023 flags
, NULL
, NULL
, NULL
);
1026 /***********************************************************************
1027 * SetupDiGetClassDevsW (SETUPAPI.@)
1029 HDEVINFO WINAPI
SetupDiGetClassDevsW(
1035 return SetupDiGetClassDevsExW(class, enumstr
, parent
,
1036 flags
, NULL
, NULL
, NULL
);
1039 /***********************************************************************
1040 * SetupDiGetClassDevsExA (SETUPAPI.@)
1042 HDEVINFO WINAPI
SetupDiGetClassDevsExA(
1052 LPWSTR enumstrW
= NULL
;
1053 LPWSTR machineW
= NULL
;
1057 int len
= MultiByteToWideChar(CP_ACP
, 0, enumstr
, -1, NULL
, 0);
1058 enumstrW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1061 ret
= (HDEVINFO
)INVALID_HANDLE_VALUE
;
1064 MultiByteToWideChar(CP_ACP
, 0, enumstr
, -1, enumstrW
, len
);
1068 int len
= MultiByteToWideChar(CP_ACP
, 0, machine
, -1, NULL
, 0);
1069 machineW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1072 ret
= (HDEVINFO
)INVALID_HANDLE_VALUE
;
1075 MultiByteToWideChar(CP_ACP
, 0, machine
, -1, machineW
, len
);
1077 ret
= SetupDiGetClassDevsExW(class, enumstrW
, parent
, flags
, deviceset
, machineW
, reserved
);
1080 HeapFree(GetProcessHeap(), 0, enumstrW
);
1081 HeapFree(GetProcessHeap(), 0, machineW
);
1085 static LONG
SETUP_CreateDevListFromClass(
1086 DeviceInfoList
*list
,
1093 DWORD subKeys
= 0, maxSubKey
;
1094 DeviceInfo
* deviceInfo
;
1097 KeyClass
= SetupDiOpenClassRegKeyExW(class, KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, DIOCR_INSTALLER
, MachineName
, NULL
);
1098 if (KeyClass
== INVALID_HANDLE_VALUE
)
1099 return GetLastError();
1102 FIXME("Enumerator parameter ignored\n");
1104 rc
= RegQueryInfoKeyW(
1110 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1111 if (rc
!= ERROR_SUCCESS
)
1113 RegCloseKey(KeyClass
);
1117 for (i
= 0; i
< subKeys
; i
++)
1119 deviceInfo
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DeviceInfo
, Device
.RegistryKey
) + maxSubKey
* sizeof(WCHAR
));
1122 RegCloseKey(KeyClass
);
1123 return ERROR_NO_SYSTEM_RESOURCES
;
1125 rc
= RegEnumKeyW(KeyClass
, i
, &deviceInfo
->Device
.RegistryKey
[0], maxSubKey
);
1126 if (rc
== ERROR_NO_MORE_ITEMS
)
1128 if (rc
!= ERROR_SUCCESS
)
1130 RegCloseKey(KeyClass
);
1133 deviceInfo
->IsDevice
= TRUE
;
1134 memcpy(&deviceInfo
->Device
.ClassGuid
, class, sizeof(GUID
));
1135 InsertTailList(&list
->ListHead
, &deviceInfo
->ItemEntry
);
1136 list
->numberOfEntries
++;
1139 RegCloseKey(KeyClass
);
1140 return ERROR_SUCCESS
;
1144 static LONG
SETUP_CreateSerialDeviceList(
1145 DeviceInfoList
*list
,
1147 LPGUID InterfaceGuid
,
1148 PCWSTR DeviceInstanceW
)
1150 static const size_t initialSize
= 100;
1152 WCHAR buf
[initialSize
];
1154 static const WCHAR devicePrefixW
[] = { 'C','O','M',0 };
1156 DeviceInfo
*deviceInfo
;
1159 WARN("'MachineName' is ignored on Wine!\n");
1160 if (DeviceInstanceW
)
1161 WARN("'DeviceInstanceW' can't be set on Wine!\n");
1167 if (QueryDosDeviceW(NULL
, devices
, size
) != 0)
1169 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
1173 HeapFree(GetProcessHeap(), 0, devices
);
1174 devices
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
1176 return ERROR_NO_SYSTEM_RESOURCES
;
1177 *devices
= UNICODE_NULL
;
1182 HeapFree(GetProcessHeap(), 0, devices
);
1183 return GetLastError();
1187 /* 'devices' is a MULTI_SZ string */
1188 for (ptr
= devices
; *ptr
; ptr
+= strlenW(ptr
) + 1)
1190 if (strncmpW(devicePrefixW
, ptr
, sizeof(devicePrefixW
) / sizeof(devicePrefixW
[0]) - 1) == 0)
1192 /* We have found a device */
1193 TRACE("Adding %s to list\n", debugstr_w(ptr
));
1194 deviceInfo
= HeapAlloc(GetProcessHeap(), 0,
1195 FIELD_OFFSET(DeviceInfo
, Interface
.Data
) + strlenW(ptr
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1199 HeapFree(GetProcessHeap(), 0, devices
);
1200 return ERROR_NO_SYSTEM_RESOURCES
;
1202 deviceInfo
->IsDevice
= FALSE
;
1203 deviceInfo
->Interface
.pSymbolicLink
= &deviceInfo
->Interface
.Data
[0];
1204 memcpy(&deviceInfo
->Interface
.InterfaceGuid
, InterfaceGuid
, sizeof(GUID
));
1205 wcscpy(deviceInfo
->Interface
.pSymbolicLink
, ptr
);
1206 InsertTailList(&list
->ListHead
, &deviceInfo
->ItemEntry
);
1207 list
->numberOfEntries
++;
1211 HeapFree(GetProcessHeap(), 0, devices
);
1212 return ERROR_SUCCESS
;
1215 #else /* __WINE__ */
1217 static LONG
SETUP_CreateInterfaceList(
1218 DeviceInfoList
*list
,
1220 LPGUID InterfaceGuid
,
1221 PCWSTR DeviceInstanceW
/* OPTIONAL */)
1223 HKEY hInterfaceKey
; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
1224 HKEY hDeviceInstanceKey
; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath} */
1225 HKEY hReferenceKey
; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath}\#{ReferenceString} */
1226 HKEY hEnumKey
; /* HKLM\SYSTEM\CurrentControlSet\Enum */
1227 HKEY hKey
; /* HKLM\SYSTEM\CurrentControlSet\Enum\{Instance\Path} */
1229 WCHAR KeyBuffer
[max(MAX_PATH
, MAX_GUID_STRING_LEN
) + 1];
1232 DWORD dwLength
, dwInstancePathLength
;
1235 DeviceInfo
*deviceInfo
;
1237 /* Open registry key related to this interface */
1238 hInterfaceKey
= SetupDiOpenClassRegKeyExW(InterfaceGuid
, KEY_ENUMERATE_SUB_KEYS
, DIOCR_INTERFACE
, MachineName
, NULL
);
1239 if (hInterfaceKey
== INVALID_HANDLE_VALUE
)
1240 return GetLastError();
1242 /* Enumerate sub keys of hInterfaceKey */
1246 dwLength
= sizeof(KeyBuffer
) / sizeof(KeyBuffer
[0]);
1247 rc
= RegEnumKeyExW(hInterfaceKey
, i
, KeyBuffer
, &dwLength
, NULL
, NULL
, NULL
, NULL
);
1248 if (rc
== ERROR_NO_MORE_ITEMS
)
1250 if (rc
!= ERROR_SUCCESS
)
1252 RegCloseKey(hInterfaceKey
);
1258 rc
= RegOpenKeyEx(hInterfaceKey
, KeyBuffer
, 0, KEY_QUERY_VALUE
| KEY_ENUMERATE_SUB_KEYS
, &hDeviceInstanceKey
);
1259 if (rc
!= ERROR_SUCCESS
)
1261 RegCloseKey(hInterfaceKey
);
1265 /* Read DeviceInstance */
1266 rc
= RegQueryValueExW(hDeviceInstanceKey
, DeviceInstance
, NULL
, &dwRegType
, NULL
, &dwInstancePathLength
);
1267 if (rc
!= ERROR_SUCCESS
)
1269 RegCloseKey(hDeviceInstanceKey
);
1270 RegCloseKey(hInterfaceKey
);
1273 if (dwRegType
!= REG_SZ
)
1275 RegCloseKey(hDeviceInstanceKey
);
1276 RegCloseKey(hInterfaceKey
);
1277 return ERROR_GEN_FAILURE
;
1279 InstancePath
= HeapAlloc(GetProcessHeap(), 0, dwInstancePathLength
+ sizeof(UNICODE_NULL
));
1282 RegCloseKey(hDeviceInstanceKey
);
1283 RegCloseKey(hInterfaceKey
);
1284 return ERROR_NO_SYSTEM_RESOURCES
;
1286 rc
= RegQueryValueExW(hDeviceInstanceKey
, DeviceInstance
, NULL
, NULL
, (LPBYTE
)InstancePath
, &dwInstancePathLength
);
1287 if (rc
!= ERROR_SUCCESS
)
1289 HeapFree(GetProcessHeap(), 0, InstancePath
);
1290 RegCloseKey(hDeviceInstanceKey
);
1291 RegCloseKey(hInterfaceKey
);
1294 InstancePath
[dwInstancePathLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1295 TRACE("DeviceInstance %s\n", debugstr_w(InstancePath
));
1297 if (DeviceInstanceW
)
1299 /* Check if device enumerator is not the right one */
1300 if (wcscmp(DeviceInstanceW
, InstancePath
) != 0)
1302 HeapFree(GetProcessHeap(), 0, InstancePath
);
1303 RegCloseKey(hDeviceInstanceKey
);
1308 /* Find class GUID associated to the device instance */
1313 KEY_ENUMERATE_SUB_KEYS
,
1315 if (rc
!= ERROR_SUCCESS
)
1317 HeapFree(GetProcessHeap(), 0, InstancePath
);
1318 RegCloseKey(hDeviceInstanceKey
);
1319 RegCloseKey(hInterfaceKey
);
1328 RegCloseKey(hEnumKey
);
1329 if (rc
!= ERROR_SUCCESS
)
1331 HeapFree(GetProcessHeap(), 0, InstancePath
);
1332 RegCloseKey(hDeviceInstanceKey
);
1333 RegCloseKey(hInterfaceKey
);
1336 dwLength
= sizeof(KeyBuffer
) - sizeof(UNICODE_NULL
);
1337 rc
= RegQueryValueExW(hKey
, ClassGUID
, NULL
, NULL
, (LPBYTE
)KeyBuffer
, &dwLength
);
1339 if (rc
!= ERROR_SUCCESS
)
1341 HeapFree(GetProcessHeap(), 0, InstancePath
);
1342 RegCloseKey(hDeviceInstanceKey
);
1343 RegCloseKey(hInterfaceKey
);
1346 KeyBuffer
[dwLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1347 KeyBuffer
[37] = UNICODE_NULL
; /* Replace the } by a NULL character */
1348 if (UuidFromStringW(&KeyBuffer
[1], &ClassGuid
) != RPC_S_OK
)
1350 HeapFree(GetProcessHeap(), 0, InstancePath
);
1351 RegCloseKey(hDeviceInstanceKey
);
1352 RegCloseKey(hInterfaceKey
);
1353 return ERROR_GEN_FAILURE
;
1355 TRACE("ClassGUID %s\n", debugstr_guid(&ClassGuid
));
1357 /* If current device doesn't match the list GUID (if any), skip this entry */
1358 if (!IsEqualIID(&list
->ClassGuid
, &GUID_NULL
) && !IsEqualIID(&list
->ClassGuid
, &ClassGuid
))
1360 HeapFree(GetProcessHeap(), 0, InstancePath
);
1361 RegCloseKey(hDeviceInstanceKey
);
1365 /* Enumerate subkeys of hDeviceInstanceKey (ie "#ReferenceString" in IoRegisterDeviceInterface). Skip entries that don't start with '#' */
1369 dwLength
= sizeof(KeyBuffer
) / sizeof(KeyBuffer
[0]);
1370 rc
= RegEnumKeyExW(hDeviceInstanceKey
, j
, KeyBuffer
, &dwLength
, NULL
, NULL
, NULL
, NULL
);
1371 if (rc
== ERROR_NO_MORE_ITEMS
)
1373 if (rc
!= ERROR_SUCCESS
)
1375 HeapFree(GetProcessHeap(), 0, InstancePath
);
1376 RegCloseKey(hDeviceInstanceKey
);
1377 RegCloseKey(hInterfaceKey
);
1381 if (KeyBuffer
[0] != '#')
1382 /* This entry doesn't represent an interesting entry */
1386 rc
= RegOpenKeyEx(hDeviceInstanceKey
, KeyBuffer
, 0, KEY_QUERY_VALUE
, &hReferenceKey
);
1387 if (rc
!= ERROR_SUCCESS
)
1389 RegCloseKey(hDeviceInstanceKey
);
1390 RegCloseKey(hInterfaceKey
);
1394 /* Read SymbolicLink value */
1395 rc
= RegQueryValueExW(hReferenceKey
, SymbolicLink
, NULL
, &dwRegType
, NULL
, &dwLength
);
1396 if (rc
!= ERROR_SUCCESS
)
1398 RegCloseKey(hReferenceKey
);
1399 RegCloseKey(hDeviceInstanceKey
);
1400 RegCloseKey(hInterfaceKey
);
1403 if (dwRegType
!= REG_SZ
)
1405 RegCloseKey(hReferenceKey
);
1406 RegCloseKey(hDeviceInstanceKey
);
1407 RegCloseKey(hInterfaceKey
);
1408 return ERROR_GEN_FAILURE
;
1410 deviceInfo
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DeviceInfo
, Interface
.Data
) + dwInstancePathLength
+ sizeof(UNICODE_NULL
) + dwLength
+ sizeof(UNICODE_NULL
));
1413 RegCloseKey(hReferenceKey
);
1414 RegCloseKey(hDeviceInstanceKey
);
1415 RegCloseKey(hInterfaceKey
);
1416 return ERROR_NO_SYSTEM_RESOURCES
;
1418 deviceInfo
->Interface
.pInstancePath
= &deviceInfo
->Interface
.Data
[0];
1419 deviceInfo
->Interface
.pSymbolicLink
= &deviceInfo
->Interface
.Data
[dwInstancePathLength
+ 1];
1420 rc
= RegQueryValueExW(hReferenceKey
, SymbolicLink
, NULL
, NULL
, (LPBYTE
)deviceInfo
->Interface
.pSymbolicLink
, &dwLength
);
1421 RegCloseKey(hReferenceKey
);
1422 if (rc
!= ERROR_SUCCESS
)
1424 HeapFree(GetProcessHeap(), 0, deviceInfo
);
1425 RegCloseKey(hDeviceInstanceKey
);
1426 RegCloseKey(hInterfaceKey
);
1429 deviceInfo
->Interface
.pSymbolicLink
[dwLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1430 TRACE("Symbolic link %s\n", debugstr_w(deviceInfo
->Interface
.pSymbolicLink
));
1432 /* Add this entry to the list */
1433 TRACE("Entry found\n");
1434 deviceInfo
->IsDevice
= FALSE
;
1436 &deviceInfo
->Interface
.InterfaceGuid
,
1438 sizeof(deviceInfo
->Interface
.InterfaceGuid
));
1439 wcscpy(deviceInfo
->Interface
.pInstancePath
, InstancePath
);
1440 InsertTailList(&list
->ListHead
, &deviceInfo
->ItemEntry
);
1441 list
->numberOfEntries
++;
1443 RegCloseKey(hDeviceInstanceKey
);
1445 RegCloseKey(hInterfaceKey
);
1446 return ERROR_SUCCESS
;
1448 #endif /* __WINE__ */
1450 /***********************************************************************
1451 * SetupDiGetClassDevsExW (SETUPAPI.@)
1453 HDEVINFO WINAPI
SetupDiGetClassDevsExW(
1462 HDEVINFO hDeviceInfo
= INVALID_HANDLE_VALUE
;
1463 DeviceInfoList
*list
;
1465 LPGUID ClassGuidList
;
1470 TRACE("%s %s %p 0x%08lx %p %s %p\n", debugstr_guid(class), debugstr_w(enumstr
),
1471 parent
, flags
, deviceset
, debugstr_w(machine
), reserved
);
1473 /* Create the deviceset if not set */
1476 list
= (DeviceInfoList
*)deviceset
;
1477 if (list
->magic
!= SETUP_DEV_INFO_LIST_MAGIC
)
1479 SetLastError(ERROR_INVALID_HANDLE
);
1480 return INVALID_HANDLE_VALUE
;
1482 hDeviceInfo
= deviceset
;
1486 hDeviceInfo
= SetupDiCreateDeviceInfoListExW(
1487 flags
& DIGCF_DEVICEINTERFACE
? NULL
: class,
1488 NULL
, machine
, NULL
);
1489 if (hDeviceInfo
== INVALID_HANDLE_VALUE
)
1490 return INVALID_HANDLE_VALUE
;
1491 list
= (DeviceInfoList
*)hDeviceInfo
;
1494 if (IsEqualIID(&list
->ClassGuid
, &GUID_NULL
))
1497 pClassGuid
= &list
->ClassGuid
;
1499 if (flags
& DIGCF_PRESENT
)
1500 FIXME(": flag DIGCF_PRESENT ignored\n");
1501 if (flags
& DIGCF_PROFILE
)
1502 FIXME(": flag DIGCF_PROFILE ignored\n");
1504 if (flags
& DIGCF_ALLCLASSES
)
1506 /* Get list of device classes */
1507 SetupDiBuildClassInfoList(0, NULL
, 0, &RequiredSize
);
1508 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
1511 SetupDiDestroyDeviceInfoList(hDeviceInfo
);
1512 return INVALID_HANDLE_VALUE
;
1514 ClassGuidList
= HeapAlloc(GetProcessHeap(), 0, RequiredSize
* sizeof(GUID
));
1518 SetupDiDestroyDeviceInfoList(hDeviceInfo
);
1519 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1520 return INVALID_HANDLE_VALUE
;
1522 if (!SetupDiBuildClassInfoListExW(0, ClassGuidList
, RequiredSize
, &RequiredSize
, machine
, NULL
))
1524 HeapFree(GetProcessHeap(), 0, ClassGuidList
);
1526 SetupDiDestroyDeviceInfoList(hDeviceInfo
);
1527 return INVALID_HANDLE_VALUE
;
1530 /* Enumerate devices in each device class */
1531 for (i
= 0; i
< RequiredSize
; i
++)
1533 if (pClassGuid
== NULL
|| IsEqualIID(pClassGuid
, &ClassGuidList
[i
]))
1535 rc
= SETUP_CreateDevListFromClass(list
, machine
, &ClassGuidList
[i
], enumstr
);
1536 if (rc
!= ERROR_SUCCESS
)
1538 HeapFree(GetProcessHeap(), 0, ClassGuidList
);
1541 SetupDiDestroyDeviceInfoList(hDeviceInfo
);
1542 return INVALID_HANDLE_VALUE
;
1546 HeapFree(GetProcessHeap(), 0, ClassGuidList
);
1549 else if (flags
& DIGCF_DEVICEINTERFACE
)
1553 SetLastError(ERROR_INVALID_PARAMETER
);
1555 SetupDiDestroyDeviceInfoList(hDeviceInfo
);
1556 return INVALID_HANDLE_VALUE
;
1560 /* Special case: find serial ports by calling QueryDosDevice */
1561 if (IsEqualIID(class, &GUID_DEVINTERFACE_COMPORT
))
1562 rc
= SETUP_CreateSerialDeviceList(list
, machine
, (LPGUID
)class, enumstr
);
1563 if (IsEqualIID(class, &GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR
))
1564 rc
= SETUP_CreateSerialDeviceList(list
, machine
, (LPGUID
)class, enumstr
);
1567 ERR("Wine can only enumerate serial devices at the moment!\n");
1568 rc
= ERROR_INVALID_PARAMETER
;
1570 #else /* __WINE__ */
1571 rc
= SETUP_CreateInterfaceList(list
, machine
, (LPGUID
)class, enumstr
);
1572 #endif /* __WINE__ */
1573 if (rc
!= ERROR_SUCCESS
)
1577 SetupDiDestroyDeviceInfoList(hDeviceInfo
);
1578 return INVALID_HANDLE_VALUE
;
1584 rc
= SETUP_CreateDevListFromClass(list
, machine
, (LPGUID
)class, enumstr
);
1585 if (rc
!= ERROR_SUCCESS
)
1589 SetupDiDestroyDeviceInfoList(hDeviceInfo
);
1590 return INVALID_HANDLE_VALUE
;
1596 /***********************************************************************
1597 * SetupDiEnumDeviceInterfaces (SETUPAPI.@)
1599 BOOL WINAPI
SetupDiEnumDeviceInterfaces(
1600 HDEVINFO DeviceInfoSet
,
1601 PSP_DEVINFO_DATA DeviceInfoData
,
1602 CONST GUID
* InterfaceClassGuid
,
1604 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData
)
1608 TRACE("%p, %p, %s, 0x%08lx, %p\n", DeviceInfoSet
, DeviceInfoData
,
1609 debugstr_guid(InterfaceClassGuid
), MemberIndex
, DeviceInterfaceData
);
1611 FIXME(": unimplemented with PSP_DEVINFO_DATA set\n");
1613 if (!DeviceInterfaceData
)
1614 SetLastError(ERROR_INVALID_PARAMETER
);
1615 else if (DeviceInterfaceData
->cbSize
!= sizeof(SP_DEVICE_INTERFACE_DATA
))
1616 SetLastError(ERROR_INVALID_USER_BUFFER
);
1617 else if (DeviceInfoSet
&& DeviceInfoSet
!= (HDEVINFO
)INVALID_HANDLE_VALUE
)
1619 DeviceInfoList
*list
= (DeviceInfoList
*)DeviceInfoSet
;
1621 if (list
->magic
== SETUP_DEV_INFO_LIST_MAGIC
)
1623 if (MemberIndex
>= list
->numberOfEntries
)
1624 SetLastError(ERROR_NO_MORE_ITEMS
);
1627 PLIST_ENTRY ItemList
= list
->ListHead
.Flink
;
1628 DeviceInfo
* DevInfo
;
1629 while (MemberIndex
-- > 0)
1630 ItemList
= ItemList
->Flink
;
1631 DevInfo
= (DeviceInfo
*)ItemList
;
1633 if (!DevInfo
->IsDevice
)
1635 memcpy(&DeviceInterfaceData
->InterfaceClassGuid
,
1636 &DevInfo
->Interface
.InterfaceGuid
,
1637 sizeof(DeviceInterfaceData
->InterfaceClassGuid
));
1638 DeviceInterfaceData
->Flags
= 0; /* FIXME */
1639 /* Note: this appears to be dangerous, passing a private
1640 * pointer a heap-allocated datum to the caller. However, the
1641 * expected lifetime of the device data is the same as the
1642 * HDEVINFO; once that is closed, the data are no longer valid.
1644 DeviceInterfaceData
->Reserved
= (ULONG_PTR
)DevInfo
;
1649 SetLastError(ERROR_INVALID_PARAMETER
);
1654 SetLastError(ERROR_INVALID_HANDLE
);
1657 SetLastError(ERROR_INVALID_HANDLE
);
1661 /***********************************************************************
1662 * SetupDiDestroyDeviceInfoList (SETUPAPI.@)
1664 BOOL WINAPI
SetupDiDestroyDeviceInfoList(HDEVINFO devinfo
)
1668 TRACE("%p\n", devinfo
);
1669 if (devinfo
&& devinfo
!= (HDEVINFO
)INVALID_HANDLE_VALUE
)
1671 DeviceInfoList
*list
= (DeviceInfoList
*)devinfo
;
1673 if (list
->magic
== SETUP_DEV_INFO_LIST_MAGIC
)
1675 PLIST_ENTRY ListEntry
;
1676 while (!IsListEmpty(&list
->ListHead
))
1678 ListEntry
= RemoveHeadList(&list
->ListHead
);
1679 HeapFree(GetProcessHeap(), 0, ListEntry
);
1681 RegCloseKey(list
->HKLM
);
1682 HeapFree(GetProcessHeap(), 0, list
);
1686 SetLastError(ERROR_INVALID_HANDLE
);
1689 SetLastError(ERROR_INVALID_HANDLE
);
1693 /***********************************************************************
1694 * SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
1696 BOOL WINAPI
SetupDiGetDeviceInterfaceDetailA(
1697 HDEVINFO DeviceInfoSet
,
1698 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData
,
1699 PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData
,
1700 DWORD DeviceInterfaceDetailDataSize
,
1701 PDWORD RequiredSize
,
1702 PSP_DEVINFO_DATA DeviceInfoData
)
1704 PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailDataW
= NULL
;
1705 DWORD sizeW
= 0, sizeA
;
1708 TRACE("(%p, %p, %p, %ld, %p, %p)\n", DeviceInfoSet
,
1709 DeviceInterfaceData
, DeviceInterfaceDetailData
,
1710 DeviceInterfaceDetailDataSize
, RequiredSize
, DeviceInfoData
);
1712 if (DeviceInterfaceDetailData
->cbSize
!= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A
))
1713 SetLastError(ERROR_INVALID_USER_BUFFER
);
1714 else if (DeviceInterfaceDetailData
== NULL
&& DeviceInterfaceDetailDataSize
!= 0)
1715 SetLastError(ERROR_INVALID_PARAMETER
);
1716 else if (DeviceInterfaceDetailData
!= NULL
&& DeviceInterfaceDetailDataSize
< FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A
, DevicePath
) + 1)
1717 SetLastError(ERROR_INVALID_PARAMETER
);
1720 if (DeviceInterfaceDetailData
!= NULL
)
1722 sizeW
= FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W
, DevicePath
)
1723 + (DeviceInterfaceDetailDataSize
- FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A
, DevicePath
)) * sizeof(WCHAR
);
1724 DeviceInterfaceDetailDataW
= (PSP_DEVICE_INTERFACE_DETAIL_DATA_W
)HeapAlloc(GetProcessHeap(), 0, sizeW
);
1725 if (!DeviceInterfaceDetailDataW
)
1727 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1730 if (!DeviceInterfaceDetailData
|| (DeviceInterfaceDetailData
&& DeviceInterfaceDetailDataW
))
1732 DeviceInterfaceDetailDataW
->cbSize
= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W
);
1733 ret
= SetupDiGetDeviceInterfaceDetailW(
1735 DeviceInterfaceData
,
1736 DeviceInterfaceDetailDataW
,
1740 sizeA
= (sizeW
- FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W
, DevicePath
)) / sizeof(WCHAR
)
1741 + FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A
, DevicePath
);
1743 *RequiredSize
= sizeA
;
1744 if (ret
&& DeviceInterfaceDetailData
&& DeviceInterfaceDetailDataSize
<= sizeA
)
1746 if (!WideCharToMultiByte(
1748 DeviceInterfaceDetailDataW
->DevicePath
, -1,
1749 DeviceInterfaceDetailData
->DevicePath
, DeviceInterfaceDetailDataSize
- FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A
, DevicePath
),
1756 HeapFree(GetProcessHeap(), 0, DeviceInterfaceDetailDataW
);
1759 TRACE("Returning %d\n", ret
);
1763 /***********************************************************************
1764 * SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
1766 BOOL WINAPI
SetupDiGetDeviceInterfaceDetailW(
1767 HDEVINFO DeviceInfoSet
,
1768 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData
,
1769 PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData
,
1770 DWORD DeviceInterfaceDetailDataSize
,
1771 PDWORD RequiredSize
,
1772 PSP_DEVINFO_DATA DeviceInfoData
)
1776 TRACE("(%p, %p, %p, %ld, %p, %p): stub\n", DeviceInfoSet
,
1777 DeviceInterfaceData
, DeviceInterfaceDetailData
,
1778 DeviceInterfaceDetailDataSize
, RequiredSize
, DeviceInfoData
);
1780 if (!DeviceInfoSet
|| !DeviceInterfaceData
)
1781 SetLastError(ERROR_INVALID_PARAMETER
);
1782 else if (DeviceInfoSet
== (HDEVINFO
)INVALID_HANDLE_VALUE
)
1783 SetLastError(ERROR_INVALID_HANDLE
);
1784 else if (((DeviceInfoList
*)DeviceInfoSet
)->magic
!= SETUP_DEV_INFO_LIST_MAGIC
)
1785 SetLastError(ERROR_INVALID_HANDLE
);
1786 else if (DeviceInterfaceData
->cbSize
!= sizeof(SP_DEVICE_INTERFACE_DATA
))
1787 SetLastError(ERROR_INVALID_USER_BUFFER
);
1788 else if (DeviceInterfaceDetailData
->cbSize
!= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W
))
1789 SetLastError(ERROR_INVALID_USER_BUFFER
);
1790 else if (DeviceInfoData
&& DeviceInfoData
->cbSize
!= sizeof(SP_DEVINFO_DATA
))
1791 SetLastError(ERROR_INVALID_USER_BUFFER
);
1792 else if (DeviceInterfaceDetailData
== NULL
&& DeviceInterfaceDetailDataSize
!= 0)
1793 SetLastError(ERROR_INVALID_PARAMETER
);
1794 else if (DeviceInterfaceDetailData
!= NULL
&& DeviceInterfaceDetailDataSize
< FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W
, DevicePath
) + sizeof(UNICODE_NULL
))
1795 SetLastError(ERROR_INVALID_PARAMETER
);
1798 DeviceInfo
*deviceInfo
= (DeviceInfo
*)DeviceInterfaceData
->Reserved
;
1799 LPCWSTR devName
= deviceInfo
->Interface
.pSymbolicLink
;
1800 DWORD sizeRequired
= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W
) +
1803 if (sizeRequired
> DeviceInterfaceDetailDataSize
)
1805 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1807 *RequiredSize
= sizeRequired
;
1811 wcscpy(DeviceInterfaceDetailData
->DevicePath
, devName
);
1812 TRACE("DevicePath is %s\n", debugstr_w(DeviceInterfaceDetailData
->DevicePath
));
1815 memcpy(&DeviceInfoData
->ClassGuid
,
1816 &deviceInfo
->Interface
.ClassGuid
,
1818 DeviceInfoData
->DevInst
= 0; /* FIXME */
1819 DeviceInfoData
->Reserved
= (ULONG_PTR
)0;
1825 TRACE("Returning %d\n", ret
);
1829 /***********************************************************************
1830 * SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
1832 BOOL WINAPI
SetupDiGetDeviceRegistryPropertyA(
1834 PSP_DEVINFO_DATA DeviceInfoData
,
1836 PDWORD PropertyRegDataType
,
1837 PBYTE PropertyBuffer
,
1838 DWORD PropertyBufferSize
,
1839 PDWORD RequiredSize
)
1842 BOOL bIsStringProperty
;
1844 DWORD RequiredSizeA
, RequiredSizeW
;
1845 DWORD PropertyBufferSizeW
;
1846 PBYTE PropertyBufferW
;
1848 TRACE("%04lx %p %ld %p %p %ld %p\n", (DWORD
)devinfo
, DeviceInfoData
,
1849 Property
, PropertyRegDataType
, PropertyBuffer
, PropertyBufferSize
,
1852 PropertyBufferSizeW
= PropertyBufferSize
* 2;
1853 PropertyBufferW
= HeapAlloc(GetProcessHeap(), 0, PropertyBufferSizeW
);
1855 bResult
= SetupDiGetDeviceRegistryPropertyW(
1861 PropertyBufferSizeW
,
1864 HeapFree(GetProcessHeap(), 0, PropertyBufferW
);
1869 bIsStringProperty
= (RegType
== REG_SZ
|| RegType
== REG_MULTI_SZ
);
1871 if (bIsStringProperty
)
1872 RequiredSizeA
= RequiredSizeW
/ sizeof(WCHAR
);
1874 RequiredSizeA
= RequiredSizeW
;
1876 if (RequiredSizeA
<= PropertyBufferSize
)
1878 if (bIsStringProperty
&& PropertyBufferSize
> 0)
1880 if (WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)PropertyBufferW
, RequiredSizeW
/ sizeof(WCHAR
), PropertyBuffer
, PropertyBufferSize
, NULL
, NULL
) == 0)
1882 /* Last error is already set by WideCharToMultiByte */
1887 memcpy(PropertyBuffer
, PropertyBufferW
, RequiredSizeA
);
1891 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1895 if (PropertyRegDataType
)
1896 *PropertyRegDataType
= RegType
;
1898 *RequiredSize
= RequiredSizeA
;
1902 /***********************************************************************
1903 * SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
1905 BOOL WINAPI
SetupDiGetDeviceRegistryPropertyW(
1907 PSP_DEVINFO_DATA DeviceInfoData
,
1909 PDWORD PropertyRegDataType
,
1910 PBYTE PropertyBuffer
,
1911 DWORD PropertyBufferSize
,
1912 PDWORD RequiredSize
)
1914 FIXME("%04lx %p %ld %p %p %ld %p\n", (DWORD
)devinfo
, DeviceInfoData
,
1915 Property
, PropertyRegDataType
, PropertyBuffer
, PropertyBufferSize
,
1917 SetLastError(ERROR_GEN_FAILURE
);
1922 /***********************************************************************
1923 * SetupDiInstallClassA (SETUPAPI.@)
1925 BOOL WINAPI
SetupDiInstallClassA(
1931 UNICODE_STRING FileNameW
;
1934 if (!RtlCreateUnicodeStringFromAsciiz(&FileNameW
, InfFileName
))
1936 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1940 Result
= SetupDiInstallClassW(hwndParent
, FileNameW
.Buffer
, Flags
, FileQueue
);
1942 RtlFreeUnicodeString(&FileNameW
);
1947 static HKEY
CreateClassKey(HINF hInf
)
1949 WCHAR FullBuffer
[MAX_PATH
];
1950 WCHAR Buffer
[MAX_PATH
];
1955 if (!SetupGetLineTextW(NULL
,
1963 return INVALID_HANDLE_VALUE
;
1966 lstrcpyW(FullBuffer
, ControlClass
);
1967 lstrcatW(FullBuffer
, Buffer
);
1970 if (!SetupGetLineTextW(NULL
,
1978 RegDeleteKeyW(HKEY_LOCAL_MACHINE
, FullBuffer
);
1979 return INVALID_HANDLE_VALUE
;
1982 if (ERROR_SUCCESS
!= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
1986 REG_OPTION_NON_VOLATILE
,
1992 RegDeleteKeyW(HKEY_LOCAL_MACHINE
, FullBuffer
);
1993 return INVALID_HANDLE_VALUE
;
1996 if (ERROR_SUCCESS
!= RegSetValueExW(hClassKey
,
2001 RequiredSize
* sizeof(WCHAR
)))
2003 RegCloseKey(hClassKey
);
2004 RegDeleteKeyW(HKEY_LOCAL_MACHINE
, FullBuffer
);
2005 return INVALID_HANDLE_VALUE
;
2011 /***********************************************************************
2012 * SetupDiInstallClassW (SETUPAPI.@)
2014 BOOL WINAPI
SetupDiInstallClassW(
2020 WCHAR SectionName
[MAX_PATH
];
2021 DWORD SectionNameLength
= 0;
2023 BOOL bFileQueueCreated
= FALSE
;
2026 FIXME("not fully implemented\n");
2028 if ((Flags
& DI_NOVCP
) && (FileQueue
== NULL
|| FileQueue
== INVALID_HANDLE_VALUE
))
2030 SetLastError(ERROR_INVALID_PARAMETER
);
2034 /* Open the .inf file */
2035 hInf
= SetupOpenInfFileW(InfFileName
,
2039 if (hInf
== INVALID_HANDLE_VALUE
)
2045 /* Create or open the class registry key 'HKLM\\CurrentControlSet\\Class\\{GUID}' */
2046 hClassKey
= CreateClassKey(hInf
);
2047 if (hClassKey
== INVALID_HANDLE_VALUE
)
2049 SetupCloseInfFile(hInf
);
2055 /* Try to append a layout file */
2057 SetupOpenAppendInfFileW(NULL
, hInf
, NULL
);
2060 /* Retrieve the actual section name */
2061 SetupDiGetActualSectionToInstallW(hInf
,
2069 if (!(Flags
& DI_NOVCP
))
2071 FileQueue
= SetupOpenFileQueue();
2072 if (FileQueue
== INVALID_HANDLE_VALUE
)
2074 SetupCloseInfFile(hInf
);
2075 RegCloseKey(hClassKey
);
2079 bFileQueueCreated
= TRUE
;
2084 SetupInstallFromInfSectionW(NULL
,
2093 INVALID_HANDLE_VALUE
,
2096 /* FIXME: More code! */
2098 if (bFileQueueCreated
)
2099 SetupCloseFileQueue(FileQueue
);
2101 SetupCloseInfFile(hInf
);
2103 RegCloseKey(hClassKey
);
2108 /***********************************************************************
2109 * SetupDiOpenClassRegKey (SETUPAPI.@)
2111 HKEY WINAPI
SetupDiOpenClassRegKey(
2112 const GUID
* ClassGuid
,
2115 return SetupDiOpenClassRegKeyExW(ClassGuid
, samDesired
,
2116 DIOCR_INSTALLER
, NULL
, NULL
);
2120 /***********************************************************************
2121 * SetupDiOpenClassRegKeyExA (SETUPAPI.@)
2123 HKEY WINAPI
SetupDiOpenClassRegKeyExA(
2124 const GUID
* ClassGuid
,
2130 PWSTR MachineNameW
= NULL
;
2137 MachineNameW
= MultiByteToUnicode(MachineName
, CP_ACP
);
2138 if (MachineNameW
== NULL
)
2139 return INVALID_HANDLE_VALUE
;
2142 hKey
= SetupDiOpenClassRegKeyExW(ClassGuid
, samDesired
,
2143 Flags
, MachineNameW
, Reserved
);
2146 MyFree(MachineNameW
);
2152 /***********************************************************************
2153 * SetupDiOpenClassRegKeyExW (SETUPAPI.@)
2155 HKEY WINAPI
SetupDiOpenClassRegKeyExW(
2156 const GUID
* ClassGuid
,
2162 LPWSTR lpGuidString
;
2163 LPWSTR lpFullGuidString
;
2171 if (Flags
== DIOCR_INSTALLER
)
2173 lpKeyName
= ControlClass
;
2175 else if (Flags
== DIOCR_INTERFACE
)
2177 lpKeyName
= DeviceClasses
;
2181 ERR("Invalid Flags parameter!\n");
2182 SetLastError(ERROR_INVALID_PARAMETER
);
2183 return INVALID_HANDLE_VALUE
;
2186 if (MachineName
!= NULL
)
2188 rc
= RegConnectRegistryW(MachineName
, HKEY_LOCAL_MACHINE
, &HKLM
);
2189 if (rc
!= ERROR_SUCCESS
)
2192 return INVALID_HANDLE_VALUE
;
2196 HKLM
= HKEY_LOCAL_MACHINE
;
2198 rc
= RegOpenKeyExW(HKLM
,
2203 if (MachineName
!= NULL
) RegCloseKey(HKLM
);
2204 if (rc
!= ERROR_SUCCESS
)
2207 return INVALID_HANDLE_VALUE
;
2210 if (ClassGuid
== NULL
)
2213 if (UuidToStringW((UUID
*)ClassGuid
, &lpGuidString
) != RPC_S_OK
)
2215 SetLastError(ERROR_GEN_FAILURE
);
2216 RegCloseKey(hClassesKey
);
2217 return INVALID_HANDLE_VALUE
;
2220 dwLength
= lstrlenW(lpGuidString
);
2221 lpFullGuidString
= HeapAlloc(GetProcessHeap(), 0, (dwLength
+ 3) * sizeof(WCHAR
));
2222 if (!lpFullGuidString
)
2224 SetLastError(ERROR_NO_SYSTEM_RESOURCES
);
2225 RpcStringFreeW(&lpGuidString
);
2226 return INVALID_HANDLE_VALUE
;
2228 lpFullGuidString
[0] = '{';
2229 memcpy(&lpFullGuidString
[1], lpGuidString
, dwLength
* sizeof(WCHAR
));
2230 lpFullGuidString
[dwLength
+ 1] = '}';
2231 lpFullGuidString
[dwLength
+ 2] = UNICODE_NULL
;
2232 RpcStringFreeW(&lpGuidString
);
2234 rc
= RegOpenKeyExW(hClassesKey
,
2239 if (rc
!= ERROR_SUCCESS
)
2242 HeapFree(GetProcessHeap(), 0, lpFullGuidString
);
2243 RegCloseKey(hClassesKey
);
2244 return INVALID_HANDLE_VALUE
;
2247 HeapFree(GetProcessHeap(), 0, lpFullGuidString
);
2248 RegCloseKey(hClassesKey
);
2253 /***********************************************************************
2254 * SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
2256 BOOL WINAPI
SetupDiOpenDeviceInterfaceW(
2257 HDEVINFO DeviceInfoSet
,
2260 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData
)
2262 FIXME("%p %s %08lx %p\n",
2263 DeviceInfoSet
, debugstr_w(DevicePath
), OpenFlags
, DeviceInterfaceData
);
2267 /***********************************************************************
2268 * SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
2270 BOOL WINAPI
SetupDiOpenDeviceInterfaceA(
2271 HDEVINFO DeviceInfoSet
,
2274 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData
)
2276 FIXME("%p %s %08lx %p\n", DeviceInfoSet
,
2277 debugstr_a(DevicePath
), OpenFlags
, DeviceInterfaceData
);
2281 /***********************************************************************
2282 * SetupDiSetClassInstallParamsA (SETUPAPI.@)
2284 BOOL WINAPI
SetupDiSetClassInstallParamsA(
2285 HDEVINFO DeviceInfoSet
,
2286 PSP_DEVINFO_DATA DeviceInfoData
,
2287 PSP_CLASSINSTALL_HEADER ClassInstallParams
,
2288 DWORD ClassInstallParamsSize
)
2290 FIXME("%p %p %x %lu\n",DeviceInfoSet
, DeviceInfoData
,
2291 ClassInstallParams
->InstallFunction
, ClassInstallParamsSize
);
2295 /***********************************************************************
2296 * SetupDiCallClassInstaller (SETUPAPI.@)
2298 BOOL WINAPI
SetupDiCallClassInstaller(
2299 DWORD InstallFunction
,
2300 HDEVINFO DeviceInfoSet
,
2301 PSP_DEVINFO_DATA DeviceInfoData
)
2303 FIXME("%ld %p %p\n", InstallFunction
, DeviceInfoSet
, DeviceInfoData
);
2307 /***********************************************************************
2308 * SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
2310 BOOL WINAPI
SetupDiGetDeviceInstallParamsA(
2311 HDEVINFO DeviceInfoSet
,
2312 PSP_DEVINFO_DATA DeviceInfoData
,
2313 PSP_DEVINSTALL_PARAMS_A DeviceInstallParams
)
2315 FIXME("%p %p %p\n", DeviceInfoSet
, DeviceInfoData
, DeviceInstallParams
);
2319 /***********************************************************************
2320 * SetupDiOpenDevRegKey (SETUPAPI.@)
2322 HKEY WINAPI
SetupDiOpenDevRegKey(
2323 HDEVINFO DeviceInfoSet
,
2324 PSP_DEVINFO_DATA DeviceInfoData
,
2330 FIXME("%p %p %ld %ld %ld %lx\n", DeviceInfoSet
, DeviceInfoData
,
2331 Scope
, HwProfile
, KeyType
, samDesired
);
2332 return INVALID_HANDLE_VALUE
;
2335 /***********************************************************************
2336 * SetupDiCreateDeviceInfoA (SETUPAPI.@)
2338 BOOL WINAPI
SetupDiCreateDeviceInfoA(
2339 HDEVINFO DeviceInfoSet
,
2342 PCSTR DeviceDescription
,
2344 DWORD CreationFlags
,
2345 PSP_DEVINFO_DATA DeviceInfoData
)
2347 LPWSTR DeviceNameW
= NULL
;
2348 LPWSTR DeviceDescriptionW
= NULL
;
2355 DeviceNameW
= MultiByteToUnicode(DeviceName
, CP_ACP
);
2356 if (DeviceNameW
== NULL
) return FALSE
;
2358 if (DeviceDescription
)
2360 DeviceDescriptionW
= MultiByteToUnicode(DeviceDescription
, CP_ACP
);
2361 if (DeviceDescriptionW
== NULL
)
2363 if (DeviceNameW
) MyFree(DeviceNameW
);
2368 bResult
= SetupDiCreateDeviceInfoW(DeviceInfoSet
, DeviceNameW
,
2369 ClassGuid
, DeviceDescriptionW
,
2370 hwndParent
, CreationFlags
,
2373 if (DeviceNameW
) MyFree(DeviceNameW
);
2374 if (DeviceDescriptionW
) MyFree(DeviceDescriptionW
);
2379 /***********************************************************************
2380 * SetupDiCreateDeviceInfoW (SETUPAPI.@)
2382 BOOL WINAPI
SetupDiCreateDeviceInfoW(
2383 HDEVINFO DeviceInfoSet
,
2386 PCWSTR DeviceDescription
,
2388 DWORD CreationFlags
,
2389 PSP_DEVINFO_DATA DeviceInfoData
)
2391 FIXME("%p %s %s %s %p %lx %p\n", DeviceInfoSet
, debugstr_w(DeviceName
),
2392 debugstr_guid(ClassGuid
), debugstr_w(DeviceDescription
), hwndParent
,
2393 CreationFlags
, DeviceInfoData
);