|  | /* | 
|  | * SetupAPI device installer | 
|  | * | 
|  | * Copyright 2000 Andreas Mohr for CodeWeavers | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include "wine/port.h" | 
|  |  | 
|  | #include <stdarg.h> | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "winnt.h" | 
|  | #include "winreg.h" | 
|  | #include "winternl.h" | 
|  | #include "wingdi.h" | 
|  | #include "winuser.h" | 
|  | #include "winnls.h" | 
|  | #include "setupapi.h" | 
|  | #include "wine/debug.h" | 
|  | #include "wine/unicode.h" | 
|  | #include "cfgmgr32.h" | 
|  | #include "initguid.h" | 
|  | #include "winioctl.h" | 
|  | #include "rpc.h" | 
|  | #include "rpcdce.h" | 
|  |  | 
|  | #include "setupapi_private.h" | 
|  |  | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(setupapi); | 
|  |  | 
|  | /* Unicode constants */ | 
|  | static const WCHAR ClassGUID[]  = {'C','l','a','s','s','G','U','I','D',0}; | 
|  | static const WCHAR Class[]  = {'C','l','a','s','s',0}; | 
|  | static const WCHAR ClassInstall32[]  = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0}; | 
|  | static const WCHAR NoDisplayClass[]  = {'N','o','D','i','s','p','l','a','y','C','l','a','s','s',0}; | 
|  | static const WCHAR NoInstallClass[]  = {'N','o','I','s','t','a','l','l','C','l','a','s','s',0}; | 
|  | static const WCHAR NoUseClass[]  = {'N','o','U','s','e','C','l','a','s','s',0}; | 
|  | static const WCHAR NtExtension[]  = {'.','N','T',0}; | 
|  | static const WCHAR NtPlatformExtension[]  = {'.','N','T','x','8','6',0}; | 
|  | static const WCHAR Version[]  = {'V','e','r','s','i','o','n',0}; | 
|  | static const WCHAR WinExtension[]  = {'.','W','i','n',0}; | 
|  |  | 
|  | /* Registry key and value names */ | 
|  | static const WCHAR ControlClass[] = {'S','y','s','t','e','m','\\', | 
|  | 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', | 
|  | 'C','o','n','t','r','o','l','\\', | 
|  | 'C','l','a','s','s',0}; | 
|  |  | 
|  | static const WCHAR DeviceClasses[] = {'S','y','s','t','e','m','\\', | 
|  | 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', | 
|  | 'C','o','n','t','r','o','l','\\', | 
|  | 'D','e','v','i','c','e','C','l','a','s','s','e','s',0}; | 
|  |  | 
|  | /* is used to identify if a DeviceInfoSet pointer is | 
|  | valid or not */ | 
|  | #define SETUP_DEVICE_INFO_SET_MAGIC 0xd00ff056 | 
|  |  | 
|  | struct DeviceInfoSet | 
|  | { | 
|  | DWORD magic;        /* if is equal to SETUP_DEVICE_INFO_SET_MAGIC struct is okay */ | 
|  | GUID ClassGuid; | 
|  | HWND hwndParent; | 
|  | }; | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              SetupDiBuildClassInfoList  (SETUPAPI.@) | 
|  | * | 
|  | * Returns a list of setup class GUIDs that identify the classes | 
|  | * that are installed on a local machine. | 
|  | * | 
|  | * PARAMS | 
|  | *   Flags [I] control exclusion of classes from the list. | 
|  | *   ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs. | 
|  | *   ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList). | 
|  | *   RequiredSize [O] pointer, which receives the number of GUIDs that are returned. | 
|  | * | 
|  | * RETURNS | 
|  | *   Success: TRUE. | 
|  | *   Failure: FALSE. | 
|  | */ | 
|  | BOOL WINAPI SetupDiBuildClassInfoList( | 
|  | DWORD Flags, | 
|  | LPGUID ClassGuidList, | 
|  | DWORD ClassGuidListSize, | 
|  | PDWORD RequiredSize) | 
|  | { | 
|  | TRACE("\n"); | 
|  | return SetupDiBuildClassInfoListExW(Flags, ClassGuidList, | 
|  | ClassGuidListSize, RequiredSize, | 
|  | NULL, NULL); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              SetupDiBuildClassInfoListExA  (SETUPAPI.@) | 
|  | * | 
|  | * Returns a list of setup class GUIDs that identify the classes | 
|  | * that are installed on a local or remote macine. | 
|  | * | 
|  | * PARAMS | 
|  | *   Flags [I] control exclusion of classes from the list. | 
|  | *   ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs. | 
|  | *   ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList). | 
|  | *   RequiredSize [O] pointer, which receives the number of GUIDs that are returned. | 
|  | *   MachineName [I] name of a remote machine. | 
|  | *   Reserved [I] must be NULL. | 
|  | * | 
|  | * RETURNS | 
|  | *   Success: TRUE. | 
|  | *   Failure: FALSE. | 
|  | */ | 
|  | BOOL WINAPI SetupDiBuildClassInfoListExA( | 
|  | DWORD Flags, | 
|  | LPGUID ClassGuidList, | 
|  | DWORD ClassGuidListSize, | 
|  | PDWORD RequiredSize, | 
|  | LPCSTR MachineName, | 
|  | PVOID Reserved) | 
|  | { | 
|  | LPWSTR MachineNameW = NULL; | 
|  | BOOL bResult; | 
|  |  | 
|  | TRACE("\n"); | 
|  |  | 
|  | if (MachineName) | 
|  | { | 
|  | MachineNameW = MultiByteToUnicode(MachineName, CP_ACP); | 
|  | if (MachineNameW == NULL) return FALSE; | 
|  | } | 
|  |  | 
|  | bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList, | 
|  | ClassGuidListSize, RequiredSize, | 
|  | MachineNameW, Reserved); | 
|  |  | 
|  | MyFree(MachineNameW); | 
|  |  | 
|  | return bResult; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              SetupDiBuildClassInfoListExW  (SETUPAPI.@) | 
|  | * | 
|  | * Returns a list of setup class GUIDs that identify the classes | 
|  | * that are installed on a local or remote macine. | 
|  | * | 
|  | * PARAMS | 
|  | *   Flags [I] control exclusion of classes from the list. | 
|  | *   ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs. | 
|  | *   ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList). | 
|  | *   RequiredSize [O] pointer, which receives the number of GUIDs that are returned. | 
|  | *   MachineName [I] name of a remote machine. | 
|  | *   Reserved [I] must be NULL. | 
|  | * | 
|  | * RETURNS | 
|  | *   Success: TRUE. | 
|  | *   Failure: FALSE. | 
|  | */ | 
|  | BOOL WINAPI SetupDiBuildClassInfoListExW( | 
|  | DWORD Flags, | 
|  | LPGUID ClassGuidList, | 
|  | DWORD ClassGuidListSize, | 
|  | PDWORD RequiredSize, | 
|  | LPCWSTR MachineName, | 
|  | PVOID Reserved) | 
|  | { | 
|  | WCHAR szKeyName[40]; | 
|  | HKEY hClassesKey; | 
|  | HKEY hClassKey; | 
|  | DWORD dwLength; | 
|  | DWORD dwIndex; | 
|  | LONG lError; | 
|  | DWORD dwGuidListIndex = 0; | 
|  |  | 
|  | TRACE("\n"); | 
|  |  | 
|  | if (RequiredSize != NULL) | 
|  | *RequiredSize = 0; | 
|  |  | 
|  | hClassesKey = SetupDiOpenClassRegKeyExW(NULL, | 
|  | KEY_ALL_ACCESS, | 
|  | DIOCR_INSTALLER, | 
|  | MachineName, | 
|  | Reserved); | 
|  | if (hClassesKey == INVALID_HANDLE_VALUE) | 
|  | { | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | for (dwIndex = 0; ; dwIndex++) | 
|  | { | 
|  | dwLength = 40; | 
|  | lError = RegEnumKeyExW(hClassesKey, | 
|  | dwIndex, | 
|  | szKeyName, | 
|  | &dwLength, | 
|  | NULL, | 
|  | NULL, | 
|  | NULL, | 
|  | NULL); | 
|  | TRACE("RegEnumKeyExW() returns %d\n", lError); | 
|  | if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA) | 
|  | { | 
|  | TRACE("Key name: %p\n", szKeyName); | 
|  |  | 
|  | if (RegOpenKeyExW(hClassesKey, | 
|  | szKeyName, | 
|  | 0, | 
|  | KEY_ALL_ACCESS, | 
|  | &hClassKey)) | 
|  | { | 
|  | RegCloseKey(hClassesKey); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | if (!RegQueryValueExW(hClassKey, | 
|  | NoUseClass, | 
|  | NULL, | 
|  | NULL, | 
|  | NULL, | 
|  | NULL)) | 
|  | { | 
|  | TRACE("'NoUseClass' value found!\n"); | 
|  | RegCloseKey(hClassKey); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if ((Flags & DIBCI_NOINSTALLCLASS) && | 
|  | (!RegQueryValueExW(hClassKey, | 
|  | NoInstallClass, | 
|  | NULL, | 
|  | NULL, | 
|  | NULL, | 
|  | NULL))) | 
|  | { | 
|  | TRACE("'NoInstallClass' value found!\n"); | 
|  | RegCloseKey(hClassKey); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if ((Flags & DIBCI_NODISPLAYCLASS) && | 
|  | (!RegQueryValueExW(hClassKey, | 
|  | NoDisplayClass, | 
|  | NULL, | 
|  | NULL, | 
|  | NULL, | 
|  | NULL))) | 
|  | { | 
|  | TRACE("'NoDisplayClass' value found!\n"); | 
|  | RegCloseKey(hClassKey); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | RegCloseKey(hClassKey); | 
|  |  | 
|  | TRACE("Guid: %p\n", szKeyName); | 
|  | if (dwGuidListIndex < ClassGuidListSize) | 
|  | { | 
|  | if (szKeyName[0] == L'{' && szKeyName[37] == L'}') | 
|  | { | 
|  | szKeyName[37] = 0; | 
|  | } | 
|  | TRACE("Guid: %p\n", &szKeyName[1]); | 
|  |  | 
|  | UuidFromStringW(&szKeyName[1], | 
|  | &ClassGuidList[dwGuidListIndex]); | 
|  | } | 
|  |  | 
|  | dwGuidListIndex++; | 
|  | } | 
|  |  | 
|  | if (lError != ERROR_SUCCESS) | 
|  | break; | 
|  | } | 
|  |  | 
|  | RegCloseKey(hClassesKey); | 
|  |  | 
|  | if (RequiredSize != NULL) | 
|  | *RequiredSize = dwGuidListIndex; | 
|  |  | 
|  | if (ClassGuidListSize < dwGuidListIndex) | 
|  | { | 
|  | SetLastError(ERROR_INSUFFICIENT_BUFFER); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiClassGuidsFromNameA  (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiClassGuidsFromNameA( | 
|  | LPCSTR ClassName, | 
|  | LPGUID ClassGuidList, | 
|  | DWORD ClassGuidListSize, | 
|  | PDWORD RequiredSize) | 
|  | { | 
|  | return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList, | 
|  | ClassGuidListSize, RequiredSize, | 
|  | NULL, NULL); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiClassGuidsFromNameW  (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiClassGuidsFromNameW( | 
|  | LPCWSTR ClassName, | 
|  | LPGUID ClassGuidList, | 
|  | DWORD ClassGuidListSize, | 
|  | PDWORD RequiredSize) | 
|  | { | 
|  | return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList, | 
|  | ClassGuidListSize, RequiredSize, | 
|  | NULL, NULL); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiClassGuidsFromNameExA  (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiClassGuidsFromNameExA( | 
|  | LPCSTR ClassName, | 
|  | LPGUID ClassGuidList, | 
|  | DWORD ClassGuidListSize, | 
|  | PDWORD RequiredSize, | 
|  | LPCSTR MachineName, | 
|  | PVOID Reserved) | 
|  | { | 
|  | LPWSTR ClassNameW = NULL; | 
|  | LPWSTR MachineNameW = NULL; | 
|  | BOOL bResult; | 
|  |  | 
|  | FIXME("\n"); | 
|  |  | 
|  | ClassNameW = MultiByteToUnicode(ClassName, CP_ACP); | 
|  | if (ClassNameW == NULL) | 
|  | return FALSE; | 
|  |  | 
|  | if (MachineName) | 
|  | { | 
|  | MachineNameW = MultiByteToUnicode(MachineName, CP_ACP); | 
|  | if (MachineNameW == NULL) | 
|  | { | 
|  | MyFree(ClassNameW); | 
|  | return FALSE; | 
|  | } | 
|  | } | 
|  |  | 
|  | bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList, | 
|  | ClassGuidListSize, RequiredSize, | 
|  | MachineNameW, Reserved); | 
|  |  | 
|  | MyFree(MachineNameW); | 
|  | MyFree(ClassNameW); | 
|  |  | 
|  | return bResult; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiClassGuidsFromNameExW  (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiClassGuidsFromNameExW( | 
|  | LPCWSTR ClassName, | 
|  | LPGUID ClassGuidList, | 
|  | DWORD ClassGuidListSize, | 
|  | PDWORD RequiredSize, | 
|  | LPCWSTR MachineName, | 
|  | PVOID Reserved) | 
|  | { | 
|  | WCHAR szKeyName[40]; | 
|  | WCHAR szClassName[256]; | 
|  | HKEY hClassesKey; | 
|  | HKEY hClassKey; | 
|  | DWORD dwLength; | 
|  | DWORD dwIndex; | 
|  | LONG lError; | 
|  | DWORD dwGuidListIndex = 0; | 
|  |  | 
|  | if (RequiredSize != NULL) | 
|  | *RequiredSize = 0; | 
|  |  | 
|  | hClassesKey = SetupDiOpenClassRegKeyExW(NULL, | 
|  | KEY_ALL_ACCESS, | 
|  | DIOCR_INSTALLER, | 
|  | MachineName, | 
|  | Reserved); | 
|  | if (hClassesKey == INVALID_HANDLE_VALUE) | 
|  | { | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | for (dwIndex = 0; ; dwIndex++) | 
|  | { | 
|  | dwLength = 40; | 
|  | lError = RegEnumKeyExW(hClassesKey, | 
|  | dwIndex, | 
|  | szKeyName, | 
|  | &dwLength, | 
|  | NULL, | 
|  | NULL, | 
|  | NULL, | 
|  | NULL); | 
|  | TRACE("RegEnumKeyExW() returns %d\n", lError); | 
|  | if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA) | 
|  | { | 
|  | TRACE("Key name: %p\n", szKeyName); | 
|  |  | 
|  | if (RegOpenKeyExW(hClassesKey, | 
|  | szKeyName, | 
|  | 0, | 
|  | KEY_ALL_ACCESS, | 
|  | &hClassKey)) | 
|  | { | 
|  | RegCloseKey(hClassesKey); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | dwLength = 256 * sizeof(WCHAR); | 
|  | if (!RegQueryValueExW(hClassKey, | 
|  | Class, | 
|  | NULL, | 
|  | NULL, | 
|  | (LPBYTE)szClassName, | 
|  | &dwLength)) | 
|  | { | 
|  | TRACE("Class name: %p\n", szClassName); | 
|  |  | 
|  | if (strcmpiW(szClassName, ClassName) == 0) | 
|  | { | 
|  | TRACE("Found matching class name\n"); | 
|  |  | 
|  | TRACE("Guid: %p\n", szKeyName); | 
|  | if (dwGuidListIndex < ClassGuidListSize) | 
|  | { | 
|  | if (szKeyName[0] == L'{' && szKeyName[37] == L'}') | 
|  | { | 
|  | szKeyName[37] = 0; | 
|  | } | 
|  | TRACE("Guid: %p\n", &szKeyName[1]); | 
|  |  | 
|  | UuidFromStringW(&szKeyName[1], | 
|  | &ClassGuidList[dwGuidListIndex]); | 
|  | } | 
|  |  | 
|  | dwGuidListIndex++; | 
|  | } | 
|  | } | 
|  |  | 
|  | RegCloseKey(hClassKey); | 
|  | } | 
|  |  | 
|  | if (lError != ERROR_SUCCESS) | 
|  | break; | 
|  | } | 
|  |  | 
|  | RegCloseKey(hClassesKey); | 
|  |  | 
|  | if (RequiredSize != NULL) | 
|  | *RequiredSize = dwGuidListIndex; | 
|  |  | 
|  | if (ClassGuidListSize < dwGuidListIndex) | 
|  | { | 
|  | SetLastError(ERROR_INSUFFICIENT_BUFFER); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              SetupDiClassNameFromGuidA  (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiClassNameFromGuidA( | 
|  | const GUID* ClassGuid, | 
|  | PSTR ClassName, | 
|  | DWORD ClassNameSize, | 
|  | PDWORD RequiredSize) | 
|  | { | 
|  | return SetupDiClassNameFromGuidExA(ClassGuid, ClassName, | 
|  | ClassNameSize, RequiredSize, | 
|  | NULL, NULL); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              SetupDiClassNameFromGuidW  (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiClassNameFromGuidW( | 
|  | const GUID* ClassGuid, | 
|  | PWSTR ClassName, | 
|  | DWORD ClassNameSize, | 
|  | PDWORD RequiredSize) | 
|  | { | 
|  | return SetupDiClassNameFromGuidExW(ClassGuid, ClassName, | 
|  | ClassNameSize, RequiredSize, | 
|  | NULL, NULL); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              SetupDiClassNameFromGuidExA  (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiClassNameFromGuidExA( | 
|  | const GUID* ClassGuid, | 
|  | PSTR ClassName, | 
|  | DWORD ClassNameSize, | 
|  | PDWORD RequiredSize, | 
|  | PCSTR MachineName, | 
|  | PVOID Reserved) | 
|  | { | 
|  | WCHAR ClassNameW[MAX_CLASS_NAME_LEN]; | 
|  | LPWSTR MachineNameW = NULL; | 
|  | BOOL ret; | 
|  |  | 
|  | if (MachineName) | 
|  | MachineNameW = MultiByteToUnicode(MachineName, CP_ACP); | 
|  | ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN, | 
|  | NULL, MachineNameW, Reserved); | 
|  | if (ret) | 
|  | { | 
|  | int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName, | 
|  | ClassNameSize, NULL, NULL); | 
|  |  | 
|  | if (!ClassNameSize && RequiredSize) | 
|  | *RequiredSize = len; | 
|  | } | 
|  | MyFree(MachineNameW); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiClassNameFromGuidExW  (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiClassNameFromGuidExW( | 
|  | const GUID* ClassGuid, | 
|  | PWSTR ClassName, | 
|  | DWORD ClassNameSize, | 
|  | PDWORD RequiredSize, | 
|  | PCWSTR MachineName, | 
|  | PVOID Reserved) | 
|  | { | 
|  | HKEY hKey; | 
|  | DWORD dwLength; | 
|  |  | 
|  | hKey = SetupDiOpenClassRegKeyExW(ClassGuid, | 
|  | KEY_ALL_ACCESS, | 
|  | DIOCR_INSTALLER, | 
|  | MachineName, | 
|  | Reserved); | 
|  | if (hKey == INVALID_HANDLE_VALUE) | 
|  | { | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | if (RequiredSize != NULL) | 
|  | { | 
|  | dwLength = 0; | 
|  | if (RegQueryValueExW(hKey, | 
|  | Class, | 
|  | NULL, | 
|  | NULL, | 
|  | NULL, | 
|  | &dwLength)) | 
|  | { | 
|  | RegCloseKey(hKey); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | *RequiredSize = dwLength / sizeof(WCHAR); | 
|  | } | 
|  |  | 
|  | dwLength = ClassNameSize * sizeof(WCHAR); | 
|  | if (RegQueryValueExW(hKey, | 
|  | Class, | 
|  | NULL, | 
|  | NULL, | 
|  | (LPBYTE)ClassName, | 
|  | &dwLength)) | 
|  | { | 
|  | RegCloseKey(hKey); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | RegCloseKey(hKey); | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiCreateDeviceInfoList (SETUPAPI.@) | 
|  | */ | 
|  | HDEVINFO WINAPI | 
|  | SetupDiCreateDeviceInfoList(const GUID *ClassGuid, | 
|  | HWND hwndParent) | 
|  | { | 
|  | return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiCreateDeviceInfoListExA (SETUPAPI.@) | 
|  | */ | 
|  | HDEVINFO WINAPI | 
|  | SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid, | 
|  | HWND hwndParent, | 
|  | PCSTR MachineName, | 
|  | PVOID Reserved) | 
|  | { | 
|  | LPWSTR MachineNameW = NULL; | 
|  | HDEVINFO hDevInfo; | 
|  |  | 
|  | TRACE("\n"); | 
|  |  | 
|  | if (MachineName) | 
|  | { | 
|  | MachineNameW = MultiByteToUnicode(MachineName, CP_ACP); | 
|  | if (MachineNameW == NULL) | 
|  | return (HDEVINFO)INVALID_HANDLE_VALUE; | 
|  | } | 
|  |  | 
|  | hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, | 
|  | MachineNameW, Reserved); | 
|  |  | 
|  | MyFree(MachineNameW); | 
|  |  | 
|  | return hDevInfo; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiCreateDeviceInfoListExW (SETUPAPI.@) | 
|  | * | 
|  | * Create an empty DeviceInfoSet list. | 
|  | * | 
|  | * PARAMS | 
|  | *   ClassGuid [I] if not NULL only devices with GUID ClcassGuid are associated | 
|  | *                 with this list. | 
|  | *   hwndParent [I] hwnd needed for interface related actions. | 
|  | *   MachineName [I] name of machine to create emtpy DeviceInfoSet list, if NULL | 
|  | *                   local regestry will be used. | 
|  | *   Reserved [I] must be NULL | 
|  | * | 
|  | * RETURNS | 
|  | *   Success: empty list. | 
|  | *   Failure: INVALID_HANDLE_VALUE. | 
|  | */ | 
|  | HDEVINFO WINAPI | 
|  | SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid, | 
|  | HWND hwndParent, | 
|  | PCWSTR MachineName, | 
|  | PVOID Reserved) | 
|  | { | 
|  | struct DeviceInfoSet *list = NULL; | 
|  | DWORD size = sizeof(struct DeviceInfoSet); | 
|  |  | 
|  | TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent, | 
|  | debugstr_w(MachineName), Reserved); | 
|  |  | 
|  | if (MachineName != NULL) | 
|  | { | 
|  | FIXME("remote support is not implemented\n"); | 
|  | SetLastError(ERROR_INVALID_MACHINENAME); | 
|  | return (HDEVINFO)INVALID_HANDLE_VALUE; | 
|  | } | 
|  |  | 
|  | if (Reserved != NULL) | 
|  | { | 
|  | SetLastError(ERROR_INVALID_PARAMETER); | 
|  | return (HDEVINFO)INVALID_HANDLE_VALUE; | 
|  | } | 
|  |  | 
|  | list = HeapAlloc(GetProcessHeap(), 0, size); | 
|  | if (!list) | 
|  | { | 
|  | SetLastError(ERROR_NOT_ENOUGH_MEMORY); | 
|  | return (HDEVINFO)INVALID_HANDLE_VALUE; | 
|  | } | 
|  |  | 
|  | list->magic = SETUP_DEVICE_INFO_SET_MAGIC; | 
|  | list->hwndParent = hwndParent; | 
|  | memcpy(&list->ClassGuid, | 
|  | ClassGuid ? ClassGuid : &GUID_NULL, | 
|  | sizeof(list->ClassGuid)); | 
|  |  | 
|  | return (HDEVINFO)list; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              SetupDiCreateDeviceInfoA (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiCreateDeviceInfoA( | 
|  | HDEVINFO DeviceInfoSet, | 
|  | PCSTR DeviceName, | 
|  | CONST GUID *ClassGuid, | 
|  | PCSTR DeviceDescription, | 
|  | HWND hwndParent, | 
|  | DWORD CreationFlags, | 
|  | PSP_DEVINFO_DATA DeviceInfoData) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  | LPWSTR DeviceNameW = NULL; | 
|  | LPWSTR DeviceDescriptionW = NULL; | 
|  |  | 
|  | if (DeviceName) | 
|  | { | 
|  | DeviceNameW = MultiByteToUnicode(DeviceName, CP_ACP); | 
|  | if (DeviceNameW == NULL) return FALSE; | 
|  | } | 
|  | if (DeviceDescription) | 
|  | { | 
|  | DeviceDescriptionW = MultiByteToUnicode(DeviceDescription, CP_ACP); | 
|  | if (DeviceDescriptionW == NULL) | 
|  | { | 
|  | MyFree(DeviceNameW); | 
|  | return FALSE; | 
|  | } | 
|  | } | 
|  |  | 
|  | ret = SetupDiCreateDeviceInfoW(DeviceInfoSet, DeviceNameW, ClassGuid, DeviceDescriptionW, | 
|  | hwndParent, CreationFlags, DeviceInfoData); | 
|  |  | 
|  | MyFree(DeviceNameW); | 
|  | MyFree(DeviceDescriptionW); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              SetupDiCreateDeviceInfoW (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiCreateDeviceInfoW( | 
|  | HDEVINFO DeviceInfoSet, | 
|  | PCWSTR DeviceName, | 
|  | CONST GUID *ClassGuid, | 
|  | PCWSTR DeviceDescription, | 
|  | HWND hwndParent, | 
|  | DWORD CreationFlags, | 
|  | PSP_DEVINFO_DATA DeviceInfoData) | 
|  | { | 
|  | TRACE("%p %s %s %s %p %x %p\n", DeviceInfoSet, debugstr_w(DeviceName), | 
|  | debugstr_guid(ClassGuid), debugstr_w(DeviceDescription), | 
|  | hwndParent, CreationFlags, DeviceInfoData); | 
|  |  | 
|  | FIXME("stub\n"); | 
|  |  | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiEnumDeviceInfo (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiEnumDeviceInfo( | 
|  | HDEVINFO  devinfo, | 
|  | DWORD  index, | 
|  | PSP_DEVINFO_DATA info) | 
|  | { | 
|  | FIXME("%p %d %p\n", devinfo, index, info); | 
|  |  | 
|  | if(info==NULL) | 
|  | return FALSE; | 
|  | if(info->cbSize < sizeof(*info)) | 
|  | return FALSE; | 
|  |  | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiGetActualSectionToInstallA (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiGetActualSectionToInstallA( | 
|  | HINF InfHandle, | 
|  | PCSTR InfSectionName, | 
|  | PSTR InfSectionWithExt, | 
|  | DWORD InfSectionWithExtSize, | 
|  | PDWORD RequiredSize, | 
|  | PSTR *Extension) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiGetActualSectionToInstallW (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiGetActualSectionToInstallW( | 
|  | HINF InfHandle, | 
|  | PCWSTR InfSectionName, | 
|  | PWSTR InfSectionWithExt, | 
|  | DWORD InfSectionWithExtSize, | 
|  | PDWORD RequiredSize, | 
|  | PWSTR *Extension) | 
|  | { | 
|  | WCHAR szBuffer[MAX_PATH]; | 
|  | DWORD dwLength; | 
|  | DWORD dwFullLength; | 
|  | LONG lLineCount = -1; | 
|  |  | 
|  | lstrcpyW(szBuffer, InfSectionName); | 
|  | dwLength = lstrlenW(szBuffer); | 
|  |  | 
|  | if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) | 
|  | { | 
|  | /* Test section name with '.NTx86' extension */ | 
|  | lstrcpyW(&szBuffer[dwLength], NtPlatformExtension); | 
|  | lLineCount = SetupGetLineCountW(InfHandle, szBuffer); | 
|  |  | 
|  | if (lLineCount == -1) | 
|  | { | 
|  | /* Test section name with '.NT' extension */ | 
|  | lstrcpyW(&szBuffer[dwLength], NtExtension); | 
|  | lLineCount = SetupGetLineCountW(InfHandle, szBuffer); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Test section name with '.Win' extension */ | 
|  | lstrcpyW(&szBuffer[dwLength], WinExtension); | 
|  | lLineCount = SetupGetLineCountW(InfHandle, szBuffer); | 
|  | } | 
|  |  | 
|  | if (lLineCount == -1) | 
|  | { | 
|  | /* Test section name without extension */ | 
|  | szBuffer[dwLength] = 0; | 
|  | lLineCount = SetupGetLineCountW(InfHandle, szBuffer); | 
|  | } | 
|  |  | 
|  | if (lLineCount == -1) | 
|  | { | 
|  | SetLastError(ERROR_INVALID_PARAMETER); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | dwFullLength = lstrlenW(szBuffer); | 
|  |  | 
|  | if (InfSectionWithExt != NULL && InfSectionWithExtSize != 0) | 
|  | { | 
|  | if (InfSectionWithExtSize < (dwFullLength + 1)) | 
|  | { | 
|  | SetLastError(ERROR_INSUFFICIENT_BUFFER); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | lstrcpyW(InfSectionWithExt, szBuffer); | 
|  | if (Extension != NULL) | 
|  | { | 
|  | *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength]; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (RequiredSize != NULL) | 
|  | { | 
|  | *RequiredSize = dwFullLength + 1; | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiGetClassDescriptionA  (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiGetClassDescriptionA( | 
|  | const GUID* ClassGuid, | 
|  | PSTR ClassDescription, | 
|  | DWORD ClassDescriptionSize, | 
|  | PDWORD RequiredSize) | 
|  | { | 
|  | return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription, | 
|  | ClassDescriptionSize, | 
|  | RequiredSize, NULL, NULL); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiGetClassDescriptionW  (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiGetClassDescriptionW( | 
|  | const GUID* ClassGuid, | 
|  | PWSTR ClassDescription, | 
|  | DWORD ClassDescriptionSize, | 
|  | PDWORD RequiredSize) | 
|  | { | 
|  | return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription, | 
|  | ClassDescriptionSize, | 
|  | RequiredSize, NULL, NULL); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiGetClassDescriptionExA  (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiGetClassDescriptionExA( | 
|  | const GUID* ClassGuid, | 
|  | PSTR ClassDescription, | 
|  | DWORD ClassDescriptionSize, | 
|  | PDWORD RequiredSize, | 
|  | PCSTR MachineName, | 
|  | PVOID Reserved) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiGetClassDescriptionExW  (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiGetClassDescriptionExW( | 
|  | const GUID* ClassGuid, | 
|  | PWSTR ClassDescription, | 
|  | DWORD ClassDescriptionSize, | 
|  | PDWORD RequiredSize, | 
|  | PCWSTR MachineName, | 
|  | PVOID Reserved) | 
|  | { | 
|  | HKEY hKey; | 
|  | DWORD dwLength; | 
|  |  | 
|  | hKey = SetupDiOpenClassRegKeyExW(ClassGuid, | 
|  | KEY_ALL_ACCESS, | 
|  | DIOCR_INSTALLER, | 
|  | MachineName, | 
|  | Reserved); | 
|  | if (hKey == INVALID_HANDLE_VALUE) | 
|  | { | 
|  | WARN("SetupDiOpenClassRegKeyExW() failed (Error %u)\n", GetLastError()); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | if (RequiredSize != NULL) | 
|  | { | 
|  | dwLength = 0; | 
|  | if (RegQueryValueExW(hKey, | 
|  | NULL, | 
|  | NULL, | 
|  | NULL, | 
|  | NULL, | 
|  | &dwLength)) | 
|  | { | 
|  | RegCloseKey(hKey); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | *RequiredSize = dwLength / sizeof(WCHAR); | 
|  | } | 
|  |  | 
|  | dwLength = ClassDescriptionSize * sizeof(WCHAR); | 
|  | if (RegQueryValueExW(hKey, | 
|  | NULL, | 
|  | NULL, | 
|  | NULL, | 
|  | (LPBYTE)ClassDescription, | 
|  | &dwLength)) | 
|  | { | 
|  | RegCloseKey(hKey); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | RegCloseKey(hKey); | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiGetClassDevsA (SETUPAPI.@) | 
|  | */ | 
|  | HDEVINFO WINAPI SetupDiGetClassDevsA( | 
|  | CONST GUID *class, | 
|  | LPCSTR enumstr, | 
|  | HWND parent, | 
|  | DWORD flags) | 
|  | { | 
|  | HDEVINFO ret; | 
|  | LPWSTR enumstrW = NULL; | 
|  |  | 
|  | if (enumstr) | 
|  | { | 
|  | int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0); | 
|  | enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); | 
|  | if (!enumstrW) | 
|  | { | 
|  | ret = (HDEVINFO)INVALID_HANDLE_VALUE; | 
|  | goto end; | 
|  | } | 
|  | MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len); | 
|  | } | 
|  | ret = SetupDiGetClassDevsW(class, enumstrW, parent, flags); | 
|  | HeapFree(GetProcessHeap(), 0, enumstrW); | 
|  |  | 
|  | end: | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiGetClassDevsW (SETUPAPI.@) | 
|  | */ | 
|  | HDEVINFO WINAPI SetupDiGetClassDevsW( | 
|  | CONST GUID *class, | 
|  | LPCWSTR enumstr, | 
|  | HWND parent, | 
|  | DWORD flags) | 
|  | { | 
|  | HDEVINFO ret = (HDEVINFO)INVALID_HANDLE_VALUE; | 
|  |  | 
|  | TRACE("%s %s %p 0x%08x\n", debugstr_guid(class), debugstr_w(enumstr), | 
|  | parent, flags); | 
|  |  | 
|  | if(flags & DIGCF_DEVICEINTERFACE) | 
|  | { | 
|  | if(!class) | 
|  | SetLastError(ERROR_INVALID_PARAMETER); | 
|  | else | 
|  | { | 
|  | /* WinXP always succeeds, returns empty list for unknown classes */ | 
|  | FIXME(": returning empty list\n"); | 
|  | ret = SetupDiCreateDeviceInfoList(class, parent); | 
|  | } | 
|  | } | 
|  | else if (enumstr) | 
|  | FIXME(": unimplemented for enumerator strings (%s)\n", | 
|  | debugstr_w(enumstr)); | 
|  | else if (flags & DIGCF_ALLCLASSES) | 
|  | FIXME(": unimplemented for DIGCF_ALLCLASSES\n"); | 
|  | else | 
|  | { | 
|  | FIXME("(%s): stub\n", debugstr_guid(class)); | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              SetupDiGetClassDevsExW (SETUPAPI.@) | 
|  | */ | 
|  | HDEVINFO WINAPI SetupDiGetClassDevsExW( | 
|  | CONST GUID *class, | 
|  | PCWSTR enumstr, | 
|  | HWND parent, | 
|  | DWORD flags, | 
|  | HDEVINFO deviceset, | 
|  | PCWSTR machine, | 
|  | PVOID reserved) | 
|  | { | 
|  | FIXME("stub\n"); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiEnumDeviceInterfaces (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiEnumDeviceInterfaces( | 
|  | HDEVINFO devinfo, | 
|  | PSP_DEVINFO_DATA DeviceInfoData, | 
|  | CONST GUID * InterfaceClassGuid, | 
|  | DWORD MemberIndex, | 
|  | PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  |  | 
|  | FIXME("%p, %p, %s, 0x%08x, %p\n", devinfo, DeviceInfoData, | 
|  | debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData); | 
|  |  | 
|  | if (devinfo && devinfo != (HDEVINFO)INVALID_HANDLE_VALUE) | 
|  | { | 
|  | struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo; | 
|  | if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC) | 
|  | SetLastError(ERROR_NO_MORE_ITEMS); | 
|  | else | 
|  | SetLastError(ERROR_INVALID_HANDLE); | 
|  | } | 
|  | else | 
|  | SetLastError(ERROR_INVALID_HANDLE); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiDestroyDeviceInfoList (SETUPAPI.@) | 
|  | * | 
|  | * Destroy a DeviceInfoList and free all used memory of the list. | 
|  | * | 
|  | * PARAMS | 
|  | *   devinfo [I] DeviceInfoList pointer to list to destroy | 
|  | * | 
|  | * RETURNS | 
|  | *   Success: non zero value. | 
|  | *   Failure: zero value. | 
|  | */ | 
|  | BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  |  | 
|  | TRACE("%p\n", devinfo); | 
|  | if (devinfo && devinfo != (HDEVINFO)INVALID_HANDLE_VALUE) | 
|  | { | 
|  | struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo; | 
|  |  | 
|  | if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC) | 
|  | { | 
|  | HeapFree(GetProcessHeap(), 0, list); | 
|  | ret = TRUE; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (ret == FALSE) | 
|  | SetLastError(ERROR_INVALID_HANDLE); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiGetDeviceInterfaceDetailA( | 
|  | HDEVINFO DeviceInfoSet, | 
|  | PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, | 
|  | PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData, | 
|  | DWORD DeviceInterfaceDetailDataSize, | 
|  | PDWORD RequiredSize, | 
|  | PSP_DEVINFO_DATA DeviceInfoData) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  |  | 
|  | FIXME("(%p, %p, %p, %d, %p, %p)\n", DeviceInfoSet, | 
|  | DeviceInterfaceData, DeviceInterfaceDetailData, | 
|  | DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData); | 
|  |  | 
|  | SetLastError(ERROR_INVALID_HANDLE); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiGetDeviceInterfaceDetailW( | 
|  | HDEVINFO DeviceInfoSet, | 
|  | PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, | 
|  | PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData, | 
|  | DWORD DeviceInterfaceDetailDataSize, | 
|  | PDWORD RequiredSize, | 
|  | PSP_DEVINFO_DATA DeviceInfoData) | 
|  | { | 
|  | FIXME("(%p, %p, %p, %d, %p, %p): stub\n", DeviceInfoSet, | 
|  | DeviceInterfaceData, DeviceInterfaceDetailData, | 
|  | DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiGetDeviceRegistryPropertyA( | 
|  | HDEVINFO  devinfo, | 
|  | PSP_DEVINFO_DATA  DeviceInfoData, | 
|  | DWORD   Property, | 
|  | PDWORD  PropertyRegDataType, | 
|  | PBYTE   PropertyBuffer, | 
|  | DWORD   PropertyBufferSize, | 
|  | PDWORD  RequiredSize) | 
|  | { | 
|  | FIXME("%04x %p %d %p %p %d %p\n", (DWORD)devinfo, DeviceInfoData, | 
|  | Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, | 
|  | RequiredSize); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiInstallClassA (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiInstallClassA( | 
|  | HWND hwndParent, | 
|  | PCSTR InfFileName, | 
|  | DWORD Flags, | 
|  | HSPFILEQ FileQueue) | 
|  | { | 
|  | UNICODE_STRING FileNameW; | 
|  | BOOL Result; | 
|  |  | 
|  | if (!RtlCreateUnicodeStringFromAsciiz(&FileNameW, InfFileName)) | 
|  | { | 
|  | SetLastError(ERROR_NOT_ENOUGH_MEMORY); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | Result = SetupDiInstallClassW(hwndParent, FileNameW.Buffer, Flags, FileQueue); | 
|  |  | 
|  | RtlFreeUnicodeString(&FileNameW); | 
|  |  | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | static HKEY CreateClassKey(HINF hInf) | 
|  | { | 
|  | WCHAR FullBuffer[MAX_PATH]; | 
|  | WCHAR Buffer[MAX_PATH]; | 
|  | DWORD RequiredSize; | 
|  | HKEY hClassKey; | 
|  |  | 
|  | if (!SetupGetLineTextW(NULL, | 
|  | hInf, | 
|  | Version, | 
|  | ClassGUID, | 
|  | Buffer, | 
|  | MAX_PATH, | 
|  | &RequiredSize)) | 
|  | { | 
|  | return INVALID_HANDLE_VALUE; | 
|  | } | 
|  |  | 
|  | lstrcpyW(FullBuffer, ControlClass); | 
|  | lstrcatW(FullBuffer, Buffer); | 
|  |  | 
|  | if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, | 
|  | FullBuffer, | 
|  | 0, | 
|  | KEY_ALL_ACCESS, | 
|  | &hClassKey)) | 
|  | { | 
|  | if (!SetupGetLineTextW(NULL, | 
|  | hInf, | 
|  | Version, | 
|  | Class, | 
|  | Buffer, | 
|  | MAX_PATH, | 
|  | &RequiredSize)) | 
|  | { | 
|  | return INVALID_HANDLE_VALUE; | 
|  | } | 
|  |  | 
|  | if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, | 
|  | FullBuffer, | 
|  | 0, | 
|  | NULL, | 
|  | REG_OPTION_NON_VOLATILE, | 
|  | KEY_ALL_ACCESS, | 
|  | NULL, | 
|  | &hClassKey, | 
|  | NULL)) | 
|  | { | 
|  | return INVALID_HANDLE_VALUE; | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | if (RegSetValueExW(hClassKey, | 
|  | Class, | 
|  | 0, | 
|  | REG_SZ, | 
|  | (LPBYTE)Buffer, | 
|  | RequiredSize * sizeof(WCHAR))) | 
|  | { | 
|  | RegCloseKey(hClassKey); | 
|  | RegDeleteKeyW(HKEY_LOCAL_MACHINE, | 
|  | FullBuffer); | 
|  | return INVALID_HANDLE_VALUE; | 
|  | } | 
|  |  | 
|  | return hClassKey; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiInstallClassW (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiInstallClassW( | 
|  | HWND hwndParent, | 
|  | PCWSTR InfFileName, | 
|  | DWORD Flags, | 
|  | HSPFILEQ FileQueue) | 
|  | { | 
|  | WCHAR SectionName[MAX_PATH]; | 
|  | DWORD SectionNameLength = 0; | 
|  | HINF hInf; | 
|  | BOOL bFileQueueCreated = FALSE; | 
|  | HKEY hClassKey; | 
|  |  | 
|  |  | 
|  | FIXME("\n"); | 
|  |  | 
|  | if ((Flags & DI_NOVCP) && (FileQueue == NULL || FileQueue == INVALID_HANDLE_VALUE)) | 
|  | { | 
|  | SetLastError(ERROR_INVALID_PARAMETER); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /* Open the .inf file */ | 
|  | hInf = SetupOpenInfFileW(InfFileName, | 
|  | NULL, | 
|  | INF_STYLE_WIN4, | 
|  | NULL); | 
|  | if (hInf == INVALID_HANDLE_VALUE) | 
|  | { | 
|  |  | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /* Create or open the class registry key 'HKLM\\CurrentControlSet\\Class\\{GUID}' */ | 
|  | hClassKey = CreateClassKey(hInf); | 
|  | if (hClassKey == INVALID_HANDLE_VALUE) | 
|  | { | 
|  | SetupCloseInfFile(hInf); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Try to append a layout file */ | 
|  | #if 0 | 
|  | SetupOpenAppendInfFileW(NULL, hInf, NULL); | 
|  | #endif | 
|  |  | 
|  | /* Retrieve the actual section name */ | 
|  | SetupDiGetActualSectionToInstallW(hInf, | 
|  | ClassInstall32, | 
|  | SectionName, | 
|  | MAX_PATH, | 
|  | &SectionNameLength, | 
|  | NULL); | 
|  |  | 
|  | #if 0 | 
|  | if (!(Flags & DI_NOVCP)) | 
|  | { | 
|  | FileQueue = SetupOpenFileQueue(); | 
|  | if (FileQueue == INVALID_HANDLE_VALUE) | 
|  | { | 
|  | SetupCloseInfFile(hInf); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | bFileQueueCreated = TRUE; | 
|  |  | 
|  | } | 
|  | #endif | 
|  |  | 
|  | SetupInstallFromInfSectionW(NULL, | 
|  | hInf, | 
|  | SectionName, | 
|  | SPINST_REGISTRY, | 
|  | hClassKey, | 
|  | NULL, | 
|  | 0, | 
|  | NULL, | 
|  | NULL, | 
|  | INVALID_HANDLE_VALUE, | 
|  | NULL); | 
|  |  | 
|  | /* FIXME: More code! */ | 
|  |  | 
|  | if (bFileQueueCreated) | 
|  | SetupCloseFileQueue(FileQueue); | 
|  |  | 
|  | SetupCloseInfFile(hInf); | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiOpenClassRegKey  (SETUPAPI.@) | 
|  | */ | 
|  | HKEY WINAPI SetupDiOpenClassRegKey( | 
|  | const GUID* ClassGuid, | 
|  | REGSAM samDesired) | 
|  | { | 
|  | return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired, | 
|  | DIOCR_INSTALLER, NULL, NULL); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiOpenClassRegKeyExA  (SETUPAPI.@) | 
|  | */ | 
|  | HKEY WINAPI SetupDiOpenClassRegKeyExA( | 
|  | const GUID* ClassGuid, | 
|  | REGSAM samDesired, | 
|  | DWORD Flags, | 
|  | PCSTR MachineName, | 
|  | PVOID Reserved) | 
|  | { | 
|  | PWSTR MachineNameW = NULL; | 
|  | HKEY hKey; | 
|  |  | 
|  | TRACE("\n"); | 
|  |  | 
|  | if (MachineName) | 
|  | { | 
|  | MachineNameW = MultiByteToUnicode(MachineName, CP_ACP); | 
|  | if (MachineNameW == NULL) | 
|  | return INVALID_HANDLE_VALUE; | 
|  | } | 
|  |  | 
|  | hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired, | 
|  | Flags, MachineNameW, Reserved); | 
|  |  | 
|  | MyFree(MachineNameW); | 
|  |  | 
|  | return hKey; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiOpenClassRegKeyExW  (SETUPAPI.@) | 
|  | */ | 
|  | HKEY WINAPI SetupDiOpenClassRegKeyExW( | 
|  | const GUID* ClassGuid, | 
|  | REGSAM samDesired, | 
|  | DWORD Flags, | 
|  | PCWSTR MachineName, | 
|  | PVOID Reserved) | 
|  | { | 
|  | LPWSTR lpGuidString; | 
|  | WCHAR bracedGuidString[39]; | 
|  | HKEY hClassesKey; | 
|  | HKEY hClassKey; | 
|  | LPCWSTR lpKeyName; | 
|  |  | 
|  | if (MachineName != NULL) | 
|  | { | 
|  | FIXME("Remote access not supported yet!\n"); | 
|  | return INVALID_HANDLE_VALUE; | 
|  | } | 
|  |  | 
|  | if (Flags == DIOCR_INSTALLER) | 
|  | { | 
|  | lpKeyName = ControlClass; | 
|  | } | 
|  | else if (Flags == DIOCR_INTERFACE) | 
|  | { | 
|  | lpKeyName = DeviceClasses; | 
|  | } | 
|  | else | 
|  | { | 
|  | ERR("Invalid Flags parameter!\n"); | 
|  | SetLastError(ERROR_INVALID_PARAMETER); | 
|  | return INVALID_HANDLE_VALUE; | 
|  | } | 
|  |  | 
|  | if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, | 
|  | lpKeyName, | 
|  | 0, | 
|  | KEY_ALL_ACCESS, | 
|  | &hClassesKey)) | 
|  | { | 
|  | return INVALID_HANDLE_VALUE; | 
|  | } | 
|  |  | 
|  | if (ClassGuid == NULL) | 
|  | return hClassesKey; | 
|  |  | 
|  | if (UuidToStringW((UUID*)ClassGuid, &lpGuidString) != RPC_S_OK) | 
|  | { | 
|  | RegCloseKey(hClassesKey); | 
|  | return INVALID_HANDLE_VALUE; | 
|  | } | 
|  | bracedGuidString[0] = '{'; | 
|  | memcpy(&bracedGuidString[1], lpGuidString, 36*sizeof(WCHAR)); | 
|  | bracedGuidString[37] = '}'; | 
|  | bracedGuidString[38] = 0; | 
|  | RpcStringFreeW(&lpGuidString); | 
|  |  | 
|  | if (RegOpenKeyExW(hClassesKey, | 
|  | bracedGuidString, | 
|  | 0, | 
|  | KEY_ALL_ACCESS, | 
|  | &hClassKey)) | 
|  | { | 
|  | RegCloseKey(hClassesKey); | 
|  | return INVALID_HANDLE_VALUE; | 
|  | } | 
|  |  | 
|  | RegCloseKey(hClassesKey); | 
|  |  | 
|  | return hClassKey; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiOpenDeviceInterfaceW (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiOpenDeviceInterfaceW( | 
|  | HDEVINFO DeviceInfoSet, | 
|  | PCWSTR DevicePath, | 
|  | DWORD OpenFlags, | 
|  | PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData) | 
|  | { | 
|  | FIXME("%p %s %08x %p\n", | 
|  | DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiOpenDeviceInterfaceA (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiOpenDeviceInterfaceA( | 
|  | HDEVINFO DeviceInfoSet, | 
|  | PCSTR DevicePath, | 
|  | DWORD OpenFlags, | 
|  | PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData) | 
|  | { | 
|  | FIXME("%p %s %08x %p\n", DeviceInfoSet, | 
|  | debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiSetClassInstallParamsA (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiSetClassInstallParamsA( | 
|  | HDEVINFO  DeviceInfoSet, | 
|  | PSP_DEVINFO_DATA DeviceInfoData, | 
|  | PSP_CLASSINSTALL_HEADER ClassInstallParams, | 
|  | DWORD ClassInstallParamsSize) | 
|  | { | 
|  | FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData, | 
|  | ClassInstallParams->InstallFunction, ClassInstallParamsSize); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiCallClassInstaller (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiCallClassInstaller( | 
|  | DI_FUNCTION InstallFunction, | 
|  | HDEVINFO DeviceInfoSet, | 
|  | PSP_DEVINFO_DATA DeviceInfoData) | 
|  | { | 
|  | FIXME("%d %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiGetDeviceInstallParamsA (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiGetDeviceInstallParamsA( | 
|  | HDEVINFO DeviceInfoSet, | 
|  | PSP_DEVINFO_DATA DeviceInfoData, | 
|  | PSP_DEVINSTALL_PARAMS_A DeviceInstallParams) | 
|  | { | 
|  | FIXME("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiOpenDevRegKey (SETUPAPI.@) | 
|  | */ | 
|  | HKEY WINAPI SetupDiOpenDevRegKey( | 
|  | HDEVINFO DeviceInfoSet, | 
|  | PSP_DEVINFO_DATA DeviceInfoData, | 
|  | DWORD Scope, | 
|  | DWORD HwProfile, | 
|  | DWORD KeyType, | 
|  | REGSAM samDesired) | 
|  | { | 
|  | FIXME("%p %p %d %d %d %x\n", DeviceInfoSet, DeviceInfoData, | 
|  | Scope, HwProfile, KeyType, samDesired); | 
|  | return INVALID_HANDLE_VALUE; | 
|  | } |