/* * 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 #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; }