|  | /* | 
|  | * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 "ddk/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}; | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              SetupDiBuildClassInfoList  (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiBuildClassInfoList( | 
|  | DWORD Flags, | 
|  | LPGUID ClassGuidList, | 
|  | DWORD ClassGuidListSize, | 
|  | PDWORD RequiredSize) | 
|  | { | 
|  | TRACE("\n"); | 
|  | return SetupDiBuildClassInfoListExW(Flags, ClassGuidList, | 
|  | ClassGuidListSize, RequiredSize, | 
|  | NULL, NULL); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              SetupDiBuildClassInfoListExA  (SETUPAPI.@) | 
|  | */ | 
|  | 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); | 
|  |  | 
|  | if (MachineNameW) | 
|  | MyFree(MachineNameW); | 
|  |  | 
|  | return bResult; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiBuildClassInfoListExW  (SETUPAPI.@) | 
|  | */ | 
|  | 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 %ld\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 (MachineNameW) | 
|  | { | 
|  | MachineNameW = MultiByteToUnicode(MachineName, CP_ACP); | 
|  | if (MachineNameW == NULL) | 
|  | { | 
|  | MyFree(ClassNameW); | 
|  | return FALSE; | 
|  | } | 
|  | } | 
|  |  | 
|  | bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList, | 
|  | ClassGuidListSize, RequiredSize, | 
|  | MachineNameW, Reserved); | 
|  |  | 
|  | if (MachineNameW) | 
|  | 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 %ld\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); | 
|  |  | 
|  | if (MachineNameW) | 
|  | MyFree(MachineNameW); | 
|  |  | 
|  | return hDevInfo; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiCreateDeviceInfoListExW (SETUPAPI.@) | 
|  | */ | 
|  | HDEVINFO WINAPI | 
|  | SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid, | 
|  | HWND hwndParent, | 
|  | PCWSTR MachineName, | 
|  | PVOID Reserved) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return (HDEVINFO)INVALID_HANDLE_VALUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiEnumDeviceInfo (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiEnumDeviceInfo( | 
|  | HDEVINFO  devinfo, | 
|  | DWORD  index, | 
|  | PSP_DEVINFO_DATA info) | 
|  | { | 
|  | FIXME("%p %ld %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 %lu)\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; | 
|  | } | 
|  |  | 
|  | #define SETUP_SERIAL_PORT_MAGIC 0xd00ff055 | 
|  |  | 
|  | typedef struct _SerialPortName | 
|  | { | 
|  | WCHAR name[5]; | 
|  | } SerialPortName; | 
|  |  | 
|  | typedef struct _SerialPortList | 
|  | { | 
|  | DWORD magic; | 
|  | UINT  numPorts; | 
|  | SerialPortName names[1]; | 
|  | } SerialPortList; | 
|  |  | 
|  | static HDEVINFO SETUP_CreateSerialDeviceList(void) | 
|  | { | 
|  | static const size_t initialSize = 100; | 
|  | size_t size; | 
|  | WCHAR buf[initialSize]; | 
|  | LPWSTR devices; | 
|  | HDEVINFO ret; | 
|  | BOOL failed = FALSE; | 
|  |  | 
|  | devices = buf; | 
|  | size = initialSize; | 
|  | do { | 
|  | if (QueryDosDeviceW(NULL, devices, size) == 0) | 
|  | { | 
|  | if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) | 
|  | { | 
|  | size *= 2; | 
|  | if (devices != buf) | 
|  | HeapFree(GetProcessHeap(), 0, devices); | 
|  | devices = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); | 
|  | if (!devices) | 
|  | failed = TRUE; | 
|  | else | 
|  | *devices = 0; | 
|  | } | 
|  | else | 
|  | failed = TRUE; | 
|  | } | 
|  | } while (!*devices && !failed); | 
|  | if (!failed) | 
|  | { | 
|  | static const WCHAR comW[] = { 'C','O','M',0 }; | 
|  | LPWSTR ptr; | 
|  | UINT numSerialPorts = 0; | 
|  | SerialPortList *list; | 
|  |  | 
|  | for (ptr = devices; *ptr; ptr += strlenW(ptr) + 1) | 
|  | { | 
|  | if (!strncmpW(comW, ptr, sizeof(comW) / sizeof(comW[0]) - 1)) | 
|  | numSerialPorts++; | 
|  | } | 
|  | list = HeapAlloc(GetProcessHeap(), 0, sizeof(SerialPortList) + | 
|  | numSerialPorts ? (numSerialPorts - 1) * sizeof(SerialPortName) : 0); | 
|  | if (list) | 
|  | { | 
|  | list->magic = SETUP_SERIAL_PORT_MAGIC; | 
|  | list->numPorts = 0; | 
|  | for (ptr = devices; *ptr; ptr += strlenW(ptr) + 1) | 
|  | { | 
|  | if (!strncmpW(comW, ptr, sizeof(comW) / sizeof(comW[0]) - 1)) | 
|  | { | 
|  | lstrcpynW(list->names[list->numPorts].name, ptr, | 
|  | sizeof(list->names[list->numPorts].name) / | 
|  | sizeof(list->names[list->numPorts].name[0])); | 
|  | TRACE("Adding %s to list\n", | 
|  | debugstr_w(list->names[list->numPorts].name)); | 
|  | list->numPorts++; | 
|  | } | 
|  | } | 
|  | TRACE("list->numPorts is %d\n", list->numPorts); | 
|  | } | 
|  | ret = (HDEVINFO)list; | 
|  | } | 
|  | else | 
|  | ret = (HDEVINFO)INVALID_HANDLE_VALUE; | 
|  | if (devices != buf) | 
|  | HeapFree(GetProcessHeap(), 0, devices); | 
|  | TRACE("returning %p\n", ret); | 
|  | 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%08lx\n", debugstr_guid(class), debugstr_w(enumstr), | 
|  | parent, flags); | 
|  |  | 
|  | if (enumstr) | 
|  | FIXME(": unimplemented for enumerator strings (%s)\n", | 
|  | debugstr_w(enumstr)); | 
|  | else if (flags & DIGCF_ALLCLASSES) | 
|  | FIXME(": unimplemented for DIGCF_ALLCLASSES\n"); | 
|  | else | 
|  | { | 
|  | if (IsEqualIID(class, &GUID_DEVINTERFACE_COMPORT)) | 
|  | ret = SETUP_CreateSerialDeviceList(); | 
|  | else if (IsEqualIID(class, &GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR)) | 
|  | ret = SETUP_CreateSerialDeviceList(); | 
|  | else | 
|  | FIXME("(%s): stub\n", debugstr_guid(class)); | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiEnumDeviceInterfaces (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiEnumDeviceInterfaces( | 
|  | HDEVINFO DeviceInfoSet, | 
|  | PSP_DEVINFO_DATA DeviceInfoData, | 
|  | CONST GUID * InterfaceClassGuid, | 
|  | DWORD MemberIndex, | 
|  | PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  |  | 
|  | TRACE("%p, %p, %s, 0x%08lx, %p\n", DeviceInfoSet, DeviceInfoData, | 
|  | debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData); | 
|  | if (!DeviceInterfaceData) | 
|  | SetLastError(ERROR_INVALID_PARAMETER); | 
|  | else if (DeviceInfoData) | 
|  | FIXME(": unimplemented with PSP_DEVINFO_DATA set\n"); | 
|  | else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE) | 
|  | { | 
|  | /* FIXME: this assumes the only possible enumeration is of serial | 
|  | * ports. | 
|  | */ | 
|  | SerialPortList *list = (SerialPortList *)DeviceInfoSet; | 
|  |  | 
|  | if (list->magic == SETUP_SERIAL_PORT_MAGIC) | 
|  | { | 
|  | if (MemberIndex >= list->numPorts) | 
|  | SetLastError(ERROR_NO_MORE_ITEMS); | 
|  | else | 
|  | { | 
|  | DeviceInterfaceData->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); | 
|  | memcpy(&DeviceInterfaceData->InterfaceClassGuid, | 
|  | &GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR, | 
|  | sizeof(DeviceInterfaceData->InterfaceClassGuid)); | 
|  | DeviceInterfaceData->Flags = 0; | 
|  | /* Note: this appears to be dangerous, passing a private | 
|  | * pointer a heap-allocated datum to the caller.  However, the | 
|  | * expected lifetime of the device data is the same as the | 
|  | * HDEVINFO; once that is closed, the data are no longer valid. | 
|  | */ | 
|  | DeviceInterfaceData->Reserved = | 
|  | (ULONG_PTR)&list->names[MemberIndex].name; | 
|  | ret = TRUE; | 
|  | } | 
|  | } | 
|  | else | 
|  | SetLastError(ERROR_INVALID_HANDLE); | 
|  | } | 
|  | else | 
|  | SetLastError(ERROR_INVALID_HANDLE); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiDestroyDeviceInfoList (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  |  | 
|  | TRACE("%p\n", devinfo); | 
|  | if (devinfo && devinfo != (HDEVINFO)INVALID_HANDLE_VALUE) | 
|  | { | 
|  | /* FIXME: this assumes the only possible enumeration is of serial | 
|  | * ports. | 
|  | */ | 
|  | SerialPortList *list = (SerialPortList *)devinfo; | 
|  |  | 
|  | if (list->magic == SETUP_SERIAL_PORT_MAGIC) | 
|  | { | 
|  | HeapFree(GetProcessHeap(), 0, list); | 
|  | ret = TRUE; | 
|  | } | 
|  | else | 
|  | SetLastError(ERROR_INVALID_HANDLE); | 
|  | } | 
|  | else | 
|  | 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; | 
|  |  | 
|  | TRACE("(%p, %p, %p, %ld, %p, %p)\n", DeviceInfoSet, | 
|  | DeviceInterfaceData, DeviceInterfaceDetailData, | 
|  | DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData); | 
|  | if (!DeviceInterfaceData) | 
|  | SetLastError(ERROR_INVALID_PARAMETER); | 
|  | else if ((DeviceInterfaceDetailDataSize && !DeviceInterfaceDetailData) || | 
|  | (DeviceInterfaceDetailData && !DeviceInterfaceDetailDataSize)) | 
|  | SetLastError(ERROR_INVALID_PARAMETER); | 
|  | else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE) | 
|  | { | 
|  | /* FIXME: this assumes the only possible enumeration is of serial | 
|  | * ports. | 
|  | */ | 
|  | SerialPortList *list = (SerialPortList *)DeviceInfoSet; | 
|  |  | 
|  | if (list->magic == SETUP_SERIAL_PORT_MAGIC) | 
|  | { | 
|  | LPCWSTR devName = (LPCWSTR)DeviceInterfaceData->Reserved; | 
|  | DWORD sizeRequired = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A) + | 
|  | lstrlenW(devName); | 
|  |  | 
|  | if (sizeRequired > DeviceInterfaceDetailDataSize) | 
|  | { | 
|  | SetLastError(ERROR_INSUFFICIENT_BUFFER); | 
|  | if (RequiredSize) | 
|  | *RequiredSize = sizeRequired; | 
|  | } | 
|  | else | 
|  | { | 
|  | LPSTR dst = DeviceInterfaceDetailData->DevicePath; | 
|  | LPCWSTR src = devName; | 
|  |  | 
|  | /* MSDN claims cbSize must be set by the caller, but it lies */ | 
|  | DeviceInterfaceDetailData->cbSize = | 
|  | sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); | 
|  | for ( ; *src; src++, dst++) | 
|  | *dst = *src; | 
|  | *dst = '\0'; | 
|  | TRACE("DevicePath is %s\n", | 
|  | debugstr_a(DeviceInterfaceDetailData->DevicePath)); | 
|  | if (DeviceInfoData) | 
|  | { | 
|  | DeviceInfoData->cbSize = sizeof(SP_DEVINFO_DATA); | 
|  | memcpy(&DeviceInfoData->ClassGuid, | 
|  | &GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR, | 
|  | sizeof(DeviceInfoData->ClassGuid)); | 
|  | DeviceInfoData->DevInst = 0; | 
|  | DeviceInfoData->Reserved = (ULONG_PTR)devName; | 
|  | } | 
|  | ret = TRUE; | 
|  | } | 
|  | } | 
|  | else | 
|  | SetLastError(ERROR_INVALID_HANDLE); | 
|  | } | 
|  | else | 
|  | SetLastError(ERROR_INVALID_HANDLE); | 
|  | TRACE("Returning %d\n", ret); | 
|  | 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, %ld, %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("%04lx %p %ld %p %p %ld %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); | 
|  |  | 
|  | if (MachineNameW) | 
|  | MyFree(MachineNameW); | 
|  |  | 
|  | return hKey; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiOpenClassRegKeyExW  (SETUPAPI.@) | 
|  | */ | 
|  | HKEY WINAPI SetupDiOpenClassRegKeyExW( | 
|  | const GUID* ClassGuid, | 
|  | REGSAM samDesired, | 
|  | DWORD Flags, | 
|  | PCWSTR MachineName, | 
|  | PVOID Reserved) | 
|  | { | 
|  | LPWSTR lpGuidString; | 
|  | 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 FALSE; | 
|  | } | 
|  |  | 
|  | if (RegOpenKeyExW(hClassesKey, | 
|  | lpGuidString, | 
|  | 0, | 
|  | KEY_ALL_ACCESS, | 
|  | &hClassKey)) | 
|  | { | 
|  | RpcStringFreeW(&lpGuidString); | 
|  | RegCloseKey(hClassesKey); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | RpcStringFreeW(&lpGuidString); | 
|  | RegCloseKey(hClassesKey); | 
|  |  | 
|  | return hClassKey; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		SetupDiOpenDeviceInterfaceW (SETUPAPI.@) | 
|  | */ | 
|  | BOOL WINAPI SetupDiOpenDeviceInterfaceW( | 
|  | HDEVINFO DeviceInfoSet, | 
|  | PCWSTR DevicePath, | 
|  | DWORD OpenFlags, | 
|  | PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData) | 
|  | { | 
|  | FIXME("%p %s %08lx %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 %08lx %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 %lu\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 %ld %ld %ld %lx\n", DeviceInfoSet, DeviceInfoData, | 
|  | Scope, HwProfile, KeyType, samDesired); | 
|  | return INVALID_HANDLE_VALUE; | 
|  | } |