blob: fbf6ded37d83a8c9940a70783b2945f70e9638fd [file] [log] [blame]
/*
* 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;
}