mirror of
https://github.com/reactos/reactos.git
synced 2024-09-12 13:54:41 +00:00
3534 lines
120 KiB
C
3534 lines
120 KiB
C
/*
|
|
* SetupAPI device installer
|
|
*
|
|
* Copyright 2000 Andreas Mohr for CodeWeavers
|
|
* 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
|
|
*
|
|
* 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 "setupapi_private.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
|
|
|
|
/* Unicode constants */
|
|
static const WCHAR BackSlash[] = {'\\',0};
|
|
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 DotCoInstallers[] = {'.','C','o','I','n','s','t','a','l','l','e','r','s',0};
|
|
static const WCHAR DotHW[] = {'.','H','W',0};
|
|
static const WCHAR DotServices[] = {'.','S','e','r','v','i','c','e','s',0};
|
|
static const WCHAR InfDirectory[] = {'i','n','f','\\',0};
|
|
|
|
static const WCHAR REGSTR_DRIVER_DATE[] = {'D','r','i','v','e','r','D','a','t','e',0};
|
|
static const WCHAR REGSTR_DRIVER_DATE_DATA[] = {'D','r','i','v','e','r','D','a','t','e','D','a','t','a',0};
|
|
static const WCHAR REGSTR_DRIVER_VERSION[] = {'D','r','i','v','e','r','V','e','r','s','i','o','n',0};
|
|
static const WCHAR REGSTR_SECURITY[] = {'S','e','c','u','r','i','t','y',0};
|
|
static const WCHAR REGSTR_UI_NUMBER_DESC_FORMAT[] = {'U','I','N','u','m','b','e','r','D','e','s','c','F','o','r','m','a','t',0};
|
|
|
|
typedef DWORD
|
|
(CALLBACK* CLASS_INSTALL_PROC) (
|
|
IN DI_FUNCTION InstallFunction,
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL);
|
|
typedef BOOL
|
|
(WINAPI* DEFAULT_CLASS_INSTALL_PROC) (
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN OUT PSP_DEVINFO_DATA DeviceInfoData);
|
|
typedef DWORD
|
|
(CALLBACK* COINSTALLER_PROC) (
|
|
IN DI_FUNCTION InstallFunction,
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
|
|
IN OUT PCOINSTALLER_CONTEXT_DATA Context);
|
|
|
|
struct CoInstallerElement
|
|
{
|
|
LIST_ENTRY ListEntry;
|
|
|
|
HMODULE Module;
|
|
COINSTALLER_PROC Function;
|
|
BOOL DoPostProcessing;
|
|
PVOID PrivateData;
|
|
};
|
|
|
|
struct GetSectionCallbackInfo
|
|
{
|
|
PSP_ALTPLATFORM_INFO PlatformInfo;
|
|
BYTE ProductType;
|
|
WORD SuiteMask;
|
|
DWORD PrefixLength;
|
|
WCHAR BestSection[LINE_LEN + 1];
|
|
DWORD BestScore1, BestScore2, BestScore3, BestScore4, BestScore5;
|
|
};
|
|
|
|
|
|
/***********************************************************************
|
|
* SetupDiCreateDeviceInfoList (SETUPAPI.@)
|
|
*/
|
|
HDEVINFO WINAPI
|
|
SetupDiCreateDeviceInfoList(
|
|
IN CONST GUID *ClassGuid OPTIONAL,
|
|
IN HWND hwndParent OPTIONAL)
|
|
{
|
|
return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
|
|
*/
|
|
HDEVINFO WINAPI
|
|
SetupDiCreateDeviceInfoListExA(
|
|
IN CONST GUID *ClassGuid OPTIONAL,
|
|
IN HWND hwndParent OPTIONAL,
|
|
IN PCSTR MachineName OPTIONAL,
|
|
IN PVOID Reserved)
|
|
{
|
|
LPWSTR MachineNameW = NULL;
|
|
HDEVINFO hDevInfo;
|
|
|
|
TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
|
|
debugstr_a(MachineName), Reserved);
|
|
|
|
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;
|
|
}
|
|
|
|
static DWORD
|
|
GetErrorCodeFromCrCode(const IN CONFIGRET cr)
|
|
{
|
|
switch (cr)
|
|
{
|
|
case CR_ACCESS_DENIED: return ERROR_ACCESS_DENIED;
|
|
case CR_BUFFER_SMALL: return ERROR_INSUFFICIENT_BUFFER;
|
|
case CR_CALL_NOT_IMPLEMENTED: return ERROR_CALL_NOT_IMPLEMENTED;
|
|
case CR_FAILURE: return ERROR_GEN_FAILURE;
|
|
case CR_INVALID_DATA: return ERROR_INVALID_USER_BUFFER;
|
|
case CR_INVALID_DEVICE_ID: return ERROR_INVALID_PARAMETER;
|
|
case CR_INVALID_MACHINENAME: return ERROR_INVALID_COMPUTERNAME;
|
|
case CR_INVALID_DEVNODE: return ERROR_INVALID_PARAMETER;
|
|
case CR_INVALID_FLAG: return ERROR_INVALID_FLAGS;
|
|
case CR_INVALID_POINTER: return ERROR_INVALID_PARAMETER;
|
|
case CR_INVALID_PROPERTY: return ERROR_INVALID_PARAMETER;
|
|
case CR_NO_SUCH_DEVNODE: return ERROR_FILE_NOT_FOUND;
|
|
case CR_NO_SUCH_REGISTRY_KEY: return ERROR_FILE_NOT_FOUND;
|
|
case CR_NO_SUCH_VALUE: return ERROR_FILE_NOT_FOUND;
|
|
case CR_OUT_OF_MEMORY: return ERROR_NOT_ENOUGH_MEMORY;
|
|
case CR_REGISTRY_ERROR: return ERROR_GEN_FAILURE;
|
|
case CR_SUCCESS: return ERROR_SUCCESS;
|
|
default: return ERROR_GEN_FAILURE;
|
|
}
|
|
|
|
/* Does not happen */
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
|
|
*/
|
|
HDEVINFO WINAPI
|
|
SetupDiCreateDeviceInfoListExW(
|
|
IN CONST GUID *ClassGuid OPTIONAL,
|
|
IN HWND hwndParent OPTIONAL,
|
|
IN PCWSTR MachineName OPTIONAL,
|
|
IN PVOID Reserved)
|
|
{
|
|
struct DeviceInfoSet *list;
|
|
LPWSTR UNCServerName = NULL;
|
|
DWORD size;
|
|
DWORD rc;
|
|
//CONFIGRET cr;
|
|
HDEVINFO ret = (HDEVINFO)INVALID_HANDLE_VALUE;;
|
|
|
|
TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
|
|
debugstr_w(MachineName), Reserved);
|
|
|
|
size = FIELD_OFFSET(struct DeviceInfoSet, szData);
|
|
if (MachineName)
|
|
size += (strlenW(MachineName) + 3) * sizeof(WCHAR);
|
|
list = HeapAlloc(GetProcessHeap(), 0, size);
|
|
if (!list)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto cleanup;
|
|
}
|
|
memset(list, 0, sizeof(struct DeviceInfoSet));
|
|
|
|
list->magic = SETUP_DEV_INFO_SET_MAGIC;
|
|
memcpy(
|
|
&list->ClassGuid,
|
|
ClassGuid ? ClassGuid : &GUID_NULL,
|
|
sizeof(list->ClassGuid));
|
|
list->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
|
|
list->InstallParams.Flags |= DI_CLASSINSTALLPARAMS;
|
|
list->InstallParams.hwndParent = hwndParent;
|
|
if (MachineName)
|
|
{
|
|
rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &list->HKLM);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
goto cleanup;
|
|
}
|
|
UNCServerName = HeapAlloc(GetProcessHeap(), 0, (strlenW(MachineName) + 3) * sizeof(WCHAR));
|
|
if (!UNCServerName)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto cleanup;
|
|
}
|
|
|
|
strcpyW(UNCServerName + 2, MachineName);
|
|
list->szData[0] = list->szData[1] = '\\';
|
|
strcpyW(list->szData + 2, MachineName);
|
|
list->MachineName = list->szData;
|
|
}
|
|
else
|
|
{
|
|
DWORD Size = MAX_PATH;
|
|
list->HKLM = HKEY_LOCAL_MACHINE;
|
|
UNCServerName = HeapAlloc(GetProcessHeap(), 0, (MAX_PATH + 2) * sizeof(WCHAR));
|
|
if (!UNCServerName)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto cleanup;
|
|
}
|
|
if (!GetComputerNameW(UNCServerName + 2, &Size))
|
|
goto cleanup;
|
|
list->MachineName = NULL;
|
|
}
|
|
#if 0
|
|
UNCServerName[0] = UNCServerName[1] = '\\';
|
|
cr = CM_Connect_MachineW(UNCServerName, &list->hMachine);
|
|
if (cr != CR_SUCCESS)
|
|
{
|
|
SetLastError(GetErrorCodeFromCrCode(cr));
|
|
goto cleanup;
|
|
}
|
|
#endif
|
|
InitializeListHead(&list->DriverListHead);
|
|
InitializeListHead(&list->ListHead);
|
|
|
|
ret = (HDEVINFO)list;
|
|
|
|
cleanup:
|
|
if (ret == INVALID_HANDLE_VALUE)
|
|
{
|
|
if (list)
|
|
{
|
|
if (list->HKLM != NULL && list->HKLM != HKEY_LOCAL_MACHINE)
|
|
RegCloseKey(list->HKLM);
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, list);
|
|
}
|
|
if (UNCServerName)
|
|
HeapFree(GetProcessHeap(), 0, UNCServerName);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiEnumDeviceInfo (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiEnumDeviceInfo(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN DWORD MemberIndex,
|
|
OUT PSP_DEVINFO_DATA DeviceInfoData)
|
|
{
|
|
BOOL ret = FALSE;
|
|
|
|
TRACE("%p, 0x%08lx, %p\n", DeviceInfoSet, MemberIndex, DeviceInfoData);
|
|
if (!DeviceInfoData)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
|
|
{
|
|
struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
|
|
|
|
if (list->magic != SETUP_DEV_INFO_SET_MAGIC)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
else
|
|
{
|
|
PLIST_ENTRY ItemList = list->ListHead.Flink;
|
|
while (ItemList != &list->ListHead && MemberIndex-- > 0)
|
|
ItemList = ItemList->Flink;
|
|
if (ItemList == &list->ListHead)
|
|
SetLastError(ERROR_NO_MORE_ITEMS);
|
|
else
|
|
{
|
|
struct DeviceInfoElement *DevInfo = CONTAINING_RECORD(ItemList, struct DeviceInfoElement, ListEntry);
|
|
memcpy(&DeviceInfoData->ClassGuid,
|
|
&DevInfo->ClassGuid,
|
|
sizeof(GUID));
|
|
DeviceInfoData->DevInst = DevInfo->dnDevInst;
|
|
DeviceInfoData->Reserved = (ULONG_PTR)DevInfo;
|
|
ret = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetActualSectionToInstallA (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiGetActualSectionToInstallA(
|
|
IN HINF InfHandle,
|
|
IN PCSTR InfSectionName,
|
|
OUT PSTR InfSectionWithExt OPTIONAL,
|
|
IN DWORD InfSectionWithExtSize,
|
|
OUT PDWORD RequiredSize OPTIONAL,
|
|
OUT PSTR *Extension OPTIONAL)
|
|
{
|
|
return SetupDiGetActualSectionToInstallExA(InfHandle, InfSectionName,
|
|
NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize,
|
|
Extension, NULL);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetActualSectionToInstallW (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiGetActualSectionToInstallW(
|
|
IN HINF InfHandle,
|
|
IN PCWSTR InfSectionName,
|
|
OUT PWSTR InfSectionWithExt OPTIONAL,
|
|
IN DWORD InfSectionWithExtSize,
|
|
OUT PDWORD RequiredSize OPTIONAL,
|
|
OUT PWSTR *Extension OPTIONAL)
|
|
{
|
|
return SetupDiGetActualSectionToInstallExW(InfHandle, InfSectionName,
|
|
NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize,
|
|
Extension, NULL);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetActualSectionToInstallExA (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiGetActualSectionToInstallExA(
|
|
IN HINF InfHandle,
|
|
IN PCSTR InfSectionName,
|
|
IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL,
|
|
OUT PSTR InfSectionWithExt OPTIONAL,
|
|
IN DWORD InfSectionWithExtSize,
|
|
OUT PDWORD RequiredSize OPTIONAL,
|
|
OUT PSTR* Extension OPTIONAL,
|
|
IN PVOID Reserved)
|
|
{
|
|
LPWSTR InfSectionNameW = NULL;
|
|
LPWSTR InfSectionWithExtW = NULL;
|
|
PWSTR ExtensionW;
|
|
BOOL bResult = FALSE;
|
|
|
|
TRACE("\n");
|
|
|
|
if (InfSectionName)
|
|
{
|
|
InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
|
|
if (InfSectionNameW == NULL)
|
|
goto cleanup;
|
|
}
|
|
if (InfSectionWithExt)
|
|
{
|
|
InfSectionWithExtW = MyMalloc(InfSectionWithExtSize * sizeof(WCHAR));
|
|
if (InfSectionWithExtW == NULL)
|
|
goto cleanup;
|
|
}
|
|
|
|
bResult = SetupDiGetActualSectionToInstallExW(
|
|
InfHandle, InfSectionNameW, AlternatePlatformInfo,
|
|
InfSectionWithExt ? InfSectionWithExtW : NULL,
|
|
InfSectionWithExtSize,
|
|
RequiredSize,
|
|
Extension ? &ExtensionW : NULL,
|
|
Reserved);
|
|
|
|
if (bResult && InfSectionWithExt)
|
|
{
|
|
bResult = WideCharToMultiByte(CP_ACP, 0, InfSectionWithExtW, -1, InfSectionWithExt,
|
|
InfSectionWithExtSize, NULL, NULL) != 0;
|
|
}
|
|
if (bResult && Extension)
|
|
{
|
|
if (ExtensionW == NULL)
|
|
*Extension = NULL;
|
|
else
|
|
*Extension = &InfSectionWithExt[ExtensionW - InfSectionWithExtW];
|
|
}
|
|
|
|
cleanup:
|
|
MyFree(InfSectionNameW);
|
|
MyFree(InfSectionWithExtW);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
/* Lower scores are best ones */
|
|
static BOOL
|
|
CheckSectionValid(
|
|
IN LPCWSTR SectionName,
|
|
IN PSP_ALTPLATFORM_INFO PlatformInfo,
|
|
IN BYTE ProductType,
|
|
IN WORD SuiteMask,
|
|
OUT PDWORD ScorePlatform,
|
|
OUT PDWORD ScoreMajorVersion,
|
|
OUT PDWORD ScoreMinorVersion,
|
|
OUT PDWORD ScoreProductType,
|
|
OUT PDWORD ScoreSuiteMask)
|
|
{
|
|
LPWSTR Section = NULL;
|
|
LPCWSTR pExtensionPlatform, pExtensionArchitecture;
|
|
LPWSTR Fields[6];
|
|
DWORD i;
|
|
BOOL ret = FALSE;
|
|
|
|
static const WCHAR ExtensionPlatformNone[] = {'.',0};
|
|
static const WCHAR ExtensionPlatformNT[] = {'.','N','T',0};
|
|
static const WCHAR ExtensionPlatformWindows[] = {'.','W','i','n',0};
|
|
|
|
static const WCHAR ExtensionArchitectureNone[] = {0};
|
|
static const WCHAR ExtensionArchitecturealpha[] = {'a','l','p','h','a',0};
|
|
static const WCHAR ExtensionArchitectureamd64[] = {'a','m','d','6','4',0};
|
|
static const WCHAR ExtensionArchitectureia64[] = {'i','a','6','4',0};
|
|
static const WCHAR ExtensionArchitecturemips[] = {'m','i','p','s',0};
|
|
static const WCHAR ExtensionArchitectureppc[] = {'p','p','c',0};
|
|
static const WCHAR ExtensionArchitecturex86[] = {'x','8','6',0};
|
|
|
|
TRACE("%s %p 0x%x 0x%x\n",
|
|
debugstr_w(SectionName), PlatformInfo, ProductType, SuiteMask);
|
|
|
|
*ScorePlatform = *ScoreMajorVersion = *ScoreMinorVersion = *ScoreProductType = *ScoreSuiteMask = 0;
|
|
|
|
Section = DuplicateString(SectionName);
|
|
if (!Section)
|
|
{
|
|
TRACE("DuplicateString() failed\n");
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Set various extensions values */
|
|
switch (PlatformInfo->Platform)
|
|
{
|
|
case VER_PLATFORM_WIN32_WINDOWS:
|
|
pExtensionPlatform = ExtensionPlatformWindows;
|
|
break;
|
|
case VER_PLATFORM_WIN32_NT:
|
|
pExtensionPlatform = ExtensionPlatformNT;
|
|
break;
|
|
default:
|
|
ERR("Unkown platform 0x%lx\n", PlatformInfo->Platform);
|
|
pExtensionPlatform = ExtensionPlatformNone;
|
|
break;
|
|
}
|
|
switch (PlatformInfo->ProcessorArchitecture)
|
|
{
|
|
case PROCESSOR_ARCHITECTURE_ALPHA:
|
|
pExtensionArchitecture = ExtensionArchitecturealpha;
|
|
break;
|
|
case PROCESSOR_ARCHITECTURE_AMD64:
|
|
pExtensionArchitecture = ExtensionArchitectureamd64;
|
|
break;
|
|
case PROCESSOR_ARCHITECTURE_IA64:
|
|
pExtensionArchitecture = ExtensionArchitectureia64;
|
|
break;
|
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
|
pExtensionArchitecture = ExtensionArchitecturex86;
|
|
break;
|
|
case PROCESSOR_ARCHITECTURE_MIPS:
|
|
pExtensionArchitecture = ExtensionArchitecturemips;
|
|
break;
|
|
case PROCESSOR_ARCHITECTURE_PPC:
|
|
pExtensionArchitecture = ExtensionArchitectureppc;
|
|
break;
|
|
default:
|
|
ERR("Unknown processor architecture 0x%x\n", PlatformInfo->ProcessorArchitecture);
|
|
case PROCESSOR_ARCHITECTURE_UNKNOWN:
|
|
pExtensionArchitecture = ExtensionArchitectureNone;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Field[0] Platform
|
|
* Field[1] Architecture
|
|
* Field[2] Major version
|
|
* Field[3] Minor version
|
|
* Field[4] Product type
|
|
* Field[5] Suite mask
|
|
* Remark: lastests fields may be NULL if the information is not provided
|
|
*/
|
|
Fields[0] = Section;
|
|
if (Fields[0] == NULL)
|
|
{
|
|
TRACE("No extension found\n");
|
|
*ScorePlatform = *ScoreMajorVersion = *ScoreMinorVersion = *ScoreProductType = *ScoreSuiteMask = ULONG_MAX;
|
|
ret = TRUE;
|
|
goto cleanup;
|
|
}
|
|
Fields[1] = Fields[0] + 1;
|
|
Fields[2] = Fields[3] = Fields[4] = Fields[5] = NULL;
|
|
for (i = 2; Fields[i - 1] != NULL && i < 6; i++)
|
|
{
|
|
Fields[i] = wcschr(Fields[i - 1], '.');
|
|
if (Fields[i])
|
|
{
|
|
Fields[i]++;
|
|
*(Fields[i] - 1) = L'\0';
|
|
}
|
|
}
|
|
/* Take care of first 2 fields */
|
|
if (strncmpiW(Fields[0], ExtensionPlatformWindows, strlenW(ExtensionPlatformWindows)) == 0)
|
|
{
|
|
if (PlatformInfo->Platform != VER_PLATFORM_WIN32_WINDOWS)
|
|
{
|
|
TRACE("Mismatch on platform field\n");
|
|
goto cleanup;
|
|
}
|
|
Fields[1] += wcslen(ExtensionPlatformWindows) - 1;
|
|
}
|
|
else if (strncmpiW(Fields[0], ExtensionPlatformNT, strlenW(ExtensionPlatformNT)) == 0)
|
|
{
|
|
if (PlatformInfo->Platform != VER_PLATFORM_WIN32_NT)
|
|
{
|
|
TRACE("Mismatch on platform field\n");
|
|
goto cleanup;
|
|
}
|
|
Fields[1] += wcslen(ExtensionPlatformNT) - 1;
|
|
}
|
|
else
|
|
{
|
|
/* No platform specified */
|
|
*ScorePlatform |= 0x02;
|
|
}
|
|
if (strcmpiW(Fields[1], ExtensionArchitectureNone) == 0)
|
|
{
|
|
/* No architecture specified */
|
|
*ScorePlatform |= 0x01;
|
|
}
|
|
else if (strcmpiW(Fields[1], pExtensionArchitecture) != 0)
|
|
{
|
|
TRACE("Mismatch on architecture field ('%s' and '%s')\n",
|
|
debugstr_w(Fields[1]), debugstr_w(pExtensionArchitecture));
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Check if informations are matching */
|
|
if (Fields[2] && *Fields[2])
|
|
{
|
|
DWORD MajorVersion, MinorVersion = 0;
|
|
MajorVersion = strtoulW(Fields[2], NULL, 0);
|
|
if ((MajorVersion == 0 || MajorVersion == ULONG_MAX) &&
|
|
(errno == ERANGE || errno == EINVAL))
|
|
{
|
|
TRACE("Wrong MajorVersion ('%s')\n", debugstr_w(Fields[2]));
|
|
goto cleanup;
|
|
}
|
|
if (Fields[3] && *Fields[3])
|
|
{
|
|
MinorVersion = strtoulW(Fields[3], NULL, 0);
|
|
if ((MinorVersion == 0 || MinorVersion == ULONG_MAX) &&
|
|
(errno == ERANGE || errno == EINVAL))
|
|
{
|
|
TRACE("Wrong MinorVersion ('%s')\n", debugstr_w(Fields[3]));
|
|
goto cleanup;
|
|
}
|
|
}
|
|
if (PlatformInfo->MajorVersion < MajorVersion ||
|
|
(PlatformInfo->MajorVersion == MajorVersion && PlatformInfo->MinorVersion < MinorVersion))
|
|
{
|
|
TRACE("Mismatch on version field (%lu.%lu and %lu.%lu)\n",
|
|
MajorVersion, MinorVersion, PlatformInfo->MajorVersion, PlatformInfo->MinorVersion);
|
|
goto cleanup;
|
|
}
|
|
*ScoreMajorVersion = MajorVersion - PlatformInfo->MajorVersion;
|
|
if (MajorVersion == PlatformInfo->MajorVersion)
|
|
*ScoreMinorVersion = MinorVersion - PlatformInfo->MinorVersion;
|
|
else
|
|
*ScoreMinorVersion = MinorVersion;
|
|
}
|
|
else if (Fields[3] && *Fields[3])
|
|
{
|
|
TRACE("Minor version found without major version\n");
|
|
goto cleanup;
|
|
}
|
|
else
|
|
{
|
|
*ScoreMajorVersion = PlatformInfo->MajorVersion;
|
|
*ScoreMinorVersion = PlatformInfo->MinorVersion;
|
|
}
|
|
|
|
if (Fields[4] && *Fields[4])
|
|
{
|
|
DWORD CurrentProductType;
|
|
CurrentProductType = strtoulW(Fields[4], NULL, 0);
|
|
if ((CurrentProductType == 0 || CurrentProductType == ULONG_MAX) &&
|
|
(errno == ERANGE || errno == EINVAL))
|
|
{
|
|
TRACE("Wrong Product type ('%s')\n", debugstr_w(Fields[4]));
|
|
goto cleanup;
|
|
}
|
|
if (CurrentProductType != ProductType)
|
|
{
|
|
TRACE("Mismatch on product type (0x%08lx and 0x%08x)\n",
|
|
CurrentProductType, ProductType);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
else
|
|
*ScoreProductType = 1;
|
|
|
|
if (Fields[5] && *Fields[5])
|
|
{
|
|
DWORD CurrentSuiteMask;
|
|
CurrentSuiteMask = strtoulW(Fields[5], NULL, 0);
|
|
if ((CurrentSuiteMask == 0 || CurrentSuiteMask == ULONG_MAX) &&
|
|
(errno == ERANGE || errno == EINVAL))
|
|
{
|
|
TRACE("Wrong Suite mask ('%s')\n", debugstr_w(Fields[5]));
|
|
goto cleanup;
|
|
}
|
|
if ((CurrentSuiteMask & ~SuiteMask) != 0)
|
|
{
|
|
TRACE("Mismatch on suite mask (0x%08lx and 0x%08x)\n",
|
|
CurrentSuiteMask, SuiteMask);
|
|
goto cleanup;
|
|
}
|
|
*ScoreSuiteMask = SuiteMask & ~CurrentSuiteMask;
|
|
}
|
|
else
|
|
*ScoreSuiteMask = SuiteMask;
|
|
|
|
ret = TRUE;
|
|
|
|
cleanup:
|
|
MyFree(Section);
|
|
return ret;
|
|
}
|
|
|
|
static BOOL
|
|
GetSectionCallback(
|
|
IN LPCWSTR SectionName,
|
|
IN PVOID Context)
|
|
{
|
|
struct GetSectionCallbackInfo *info = Context;
|
|
DWORD Score1, Score2, Score3, Score4, Score5;
|
|
BOOL ret;
|
|
|
|
if (SectionName[info->PrefixLength] != '.')
|
|
return TRUE;
|
|
|
|
ret = CheckSectionValid(
|
|
&SectionName[info->PrefixLength],
|
|
info->PlatformInfo,
|
|
info->ProductType,
|
|
info->SuiteMask,
|
|
&Score1, &Score2, &Score3, &Score4, &Score5);
|
|
if (!ret)
|
|
{
|
|
TRACE("Section %s not compatible\n", debugstr_w(SectionName));
|
|
return TRUE;
|
|
}
|
|
if (Score1 > info->BestScore1) goto done;
|
|
if (Score1 < info->BestScore1) goto bettersection;
|
|
if (Score2 > info->BestScore2) goto done;
|
|
if (Score2 < info->BestScore2) goto bettersection;
|
|
if (Score3 > info->BestScore3) goto done;
|
|
if (Score3 < info->BestScore3) goto bettersection;
|
|
if (Score4 > info->BestScore4) goto done;
|
|
if (Score4 < info->BestScore4) goto bettersection;
|
|
if (Score5 > info->BestScore5) goto done;
|
|
if (Score5 < info->BestScore5) goto bettersection;
|
|
goto done;
|
|
|
|
bettersection:
|
|
strcpyW(info->BestSection, SectionName);
|
|
info->BestScore1 = Score1;
|
|
info->BestScore2 = Score2;
|
|
info->BestScore3 = Score3;
|
|
info->BestScore4 = Score4;
|
|
info->BestScore5 = Score5;
|
|
|
|
done:
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetActualSectionToInstallExW (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiGetActualSectionToInstallExW(
|
|
IN HINF InfHandle,
|
|
IN PCWSTR InfSectionName,
|
|
IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL,
|
|
OUT PWSTR InfSectionWithExt OPTIONAL,
|
|
IN DWORD InfSectionWithExtSize,
|
|
OUT PDWORD RequiredSize OPTIONAL,
|
|
OUT PWSTR* Extension OPTIONAL,
|
|
IN PVOID Reserved)
|
|
{
|
|
BOOL ret = FALSE;
|
|
|
|
TRACE("%p %s %p %p %lu %p %p %p\n", InfHandle, debugstr_w(InfSectionName),
|
|
AlternatePlatformInfo, InfSectionWithExt, InfSectionWithExtSize,
|
|
RequiredSize, Extension, Reserved);
|
|
|
|
if (!InfHandle || InfHandle == (HINF)INVALID_HANDLE_VALUE)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (!InfSectionName)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (AlternatePlatformInfo && AlternatePlatformInfo->cbSize != sizeof(SP_ALTPLATFORM_INFO))
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
else if (Reserved != NULL)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else
|
|
{
|
|
static SP_ALTPLATFORM_INFO CurrentPlatform = { 0, };
|
|
static BYTE CurrentProductType = 0;
|
|
static WORD CurrentSuiteMask = 0;
|
|
PSP_ALTPLATFORM_INFO pPlatformInfo = &CurrentPlatform;
|
|
struct GetSectionCallbackInfo CallbackInfo;
|
|
DWORD dwFullLength;
|
|
BYTE ProductType;
|
|
WORD SuiteMask;
|
|
|
|
/* Fill platform info if needed */
|
|
if (AlternatePlatformInfo)
|
|
{
|
|
pPlatformInfo = AlternatePlatformInfo;
|
|
ProductType = 0;
|
|
SuiteMask = 0;
|
|
}
|
|
else
|
|
{
|
|
if (CurrentPlatform.cbSize != sizeof(SP_ALTPLATFORM_INFO))
|
|
{
|
|
/* That's the first time we go here. We need to fill in the structure */
|
|
OSVERSIONINFOEX VersionInfo;
|
|
SYSTEM_INFO SystemInfo;
|
|
VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
|
ret = GetVersionEx((POSVERSIONINFO)&VersionInfo);
|
|
if (!ret)
|
|
goto done;
|
|
GetSystemInfo(&SystemInfo);
|
|
CurrentPlatform.cbSize = sizeof(SP_ALTPLATFORM_INFO);
|
|
CurrentPlatform.Platform = VersionInfo.dwPlatformId;
|
|
CurrentPlatform.MajorVersion = VersionInfo.dwMajorVersion;
|
|
CurrentPlatform.MinorVersion = VersionInfo.dwMinorVersion;
|
|
CurrentPlatform.ProcessorArchitecture = SystemInfo.wProcessorArchitecture;
|
|
CurrentPlatform.Reserved = 0;
|
|
CurrentProductType = VersionInfo.wProductType;
|
|
CurrentSuiteMask = VersionInfo.wSuiteMask;
|
|
}
|
|
ProductType = CurrentProductType;
|
|
SuiteMask = CurrentSuiteMask;
|
|
}
|
|
|
|
CallbackInfo.PlatformInfo = pPlatformInfo;
|
|
CallbackInfo.ProductType = ProductType;
|
|
CallbackInfo.SuiteMask = SuiteMask;
|
|
CallbackInfo.PrefixLength = strlenW(InfSectionName);
|
|
CallbackInfo.BestScore1 = ULONG_MAX;
|
|
CallbackInfo.BestScore2 = ULONG_MAX;
|
|
CallbackInfo.BestScore3 = ULONG_MAX;
|
|
CallbackInfo.BestScore4 = ULONG_MAX;
|
|
CallbackInfo.BestScore5 = ULONG_MAX;
|
|
strcpyW(CallbackInfo.BestSection, InfSectionName);
|
|
if (!EnumerateSectionsStartingWith(
|
|
InfHandle,
|
|
InfSectionName,
|
|
GetSectionCallback,
|
|
&CallbackInfo))
|
|
{
|
|
SetLastError(ERROR_GEN_FAILURE);
|
|
goto done;
|
|
}
|
|
|
|
dwFullLength = lstrlenW(CallbackInfo.BestSection);
|
|
if (RequiredSize != NULL)
|
|
*RequiredSize = dwFullLength + 1;
|
|
|
|
if (InfSectionWithExtSize > 0)
|
|
{
|
|
if (InfSectionWithExtSize < dwFullLength + 1)
|
|
{
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
goto done;
|
|
}
|
|
strcpyW(InfSectionWithExt, CallbackInfo.BestSection);
|
|
if (Extension)
|
|
{
|
|
DWORD dwLength = lstrlenW(InfSectionName);
|
|
*Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
|
|
}
|
|
}
|
|
|
|
ret = TRUE;
|
|
}
|
|
|
|
done:
|
|
TRACE("Returning %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CreateDeviceInfoElement(
|
|
IN struct DeviceInfoSet *list,
|
|
IN LPCWSTR InstancePath,
|
|
IN LPCGUID pClassGuid,
|
|
OUT struct DeviceInfoElement **pDeviceInfo)
|
|
{
|
|
DWORD size;
|
|
CONFIGRET cr;
|
|
struct DeviceInfoElement *deviceInfo;
|
|
|
|
*pDeviceInfo = NULL;
|
|
|
|
size = FIELD_OFFSET(struct DeviceInfoElement, Data) + (strlenW(InstancePath) + 1) * sizeof(WCHAR);
|
|
deviceInfo = HeapAlloc(GetProcessHeap(), 0, size);
|
|
if (!deviceInfo)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
memset(deviceInfo, 0, size);
|
|
|
|
cr = CM_Locate_DevNode_ExW(&deviceInfo->dnDevInst, (DEVINSTID_W)InstancePath, CM_LOCATE_DEVNODE_PHANTOM, list->hMachine);
|
|
if (cr != CR_SUCCESS)
|
|
{
|
|
SetLastError(GetErrorCodeFromCrCode(cr));
|
|
return FALSE;
|
|
}
|
|
|
|
deviceInfo->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
|
|
strcpyW(deviceInfo->Data, InstancePath);
|
|
deviceInfo->DeviceName = deviceInfo->Data;
|
|
deviceInfo->UniqueId = strrchrW(deviceInfo->Data, '\\');
|
|
deviceInfo->DeviceDescription = NULL;
|
|
memcpy(&deviceInfo->ClassGuid, pClassGuid, sizeof(GUID));
|
|
deviceInfo->CreationFlags = 0;
|
|
InitializeListHead(&deviceInfo->DriverListHead);
|
|
InitializeListHead(&deviceInfo->InterfaceListHead);
|
|
|
|
*pDeviceInfo = deviceInfo;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static BOOL
|
|
DestroyClassInstallParams(struct ClassInstallParams* installParams)
|
|
{
|
|
return HeapFree(GetProcessHeap(), 0, installParams->PropChange);
|
|
}
|
|
|
|
static BOOL
|
|
DestroyDeviceInfoElement(struct DeviceInfoElement* deviceInfo)
|
|
{
|
|
PLIST_ENTRY ListEntry;
|
|
struct DriverInfoElement *driverInfo;
|
|
struct DeviceInterface *deviceInterface;
|
|
|
|
while (!IsListEmpty(&deviceInfo->DriverListHead))
|
|
{
|
|
ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
|
|
driverInfo = CONTAINING_RECORD(ListEntry, struct DriverInfoElement, ListEntry);
|
|
if (!DestroyDriverInfoElement(driverInfo))
|
|
return FALSE;
|
|
}
|
|
while (!IsListEmpty(&deviceInfo->InterfaceListHead))
|
|
{
|
|
ListEntry = RemoveHeadList(&deviceInfo->InterfaceListHead);
|
|
deviceInterface = CONTAINING_RECORD(ListEntry, struct DeviceInterface, ListEntry);
|
|
if (!DestroyDeviceInterface(deviceInterface))
|
|
return FALSE;
|
|
}
|
|
DestroyClassInstallParams(&deviceInfo->ClassInstallParams);
|
|
return HeapFree(GetProcessHeap(), 0, deviceInfo);
|
|
}
|
|
|
|
static BOOL
|
|
DestroyDeviceInfoSet(struct DeviceInfoSet* list)
|
|
{
|
|
PLIST_ENTRY ListEntry;
|
|
struct DeviceInfoElement *deviceInfo;
|
|
|
|
while (!IsListEmpty(&list->ListHead))
|
|
{
|
|
ListEntry = RemoveHeadList(&list->ListHead);
|
|
deviceInfo = CONTAINING_RECORD(ListEntry, struct DeviceInfoElement, ListEntry);
|
|
if (!DestroyDeviceInfoElement(deviceInfo))
|
|
return FALSE;
|
|
}
|
|
if (list->HKLM != HKEY_LOCAL_MACHINE)
|
|
RegCloseKey(list->HKLM);
|
|
CM_Disconnect_Machine(list->hMachine);
|
|
DestroyClassInstallParams(&list->ClassInstallParams);
|
|
return HeapFree(GetProcessHeap(), 0, list);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiDestroyDeviceInfoList (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiDestroyDeviceInfoList(
|
|
IN HDEVINFO DeviceInfoSet)
|
|
{
|
|
BOOL ret = FALSE;
|
|
|
|
TRACE("%p\n", DeviceInfoSet);
|
|
if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
|
|
{
|
|
struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
|
|
|
|
if (list->magic == SETUP_DEV_INFO_SET_MAGIC)
|
|
ret = DestroyDeviceInfoSet(list);
|
|
else
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
}
|
|
else
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiGetDeviceRegistryPropertyA(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN DWORD Property,
|
|
OUT PDWORD PropertyRegDataType OPTIONAL,
|
|
OUT PBYTE PropertyBuffer OPTIONAL,
|
|
IN DWORD PropertyBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL)
|
|
{
|
|
BOOL bResult;
|
|
BOOL bIsStringProperty;
|
|
DWORD RegType;
|
|
DWORD RequiredSizeA, RequiredSizeW;
|
|
DWORD PropertyBufferSizeW = 0;
|
|
PBYTE PropertyBufferW = NULL;
|
|
|
|
TRACE("%p %p %ld %p %p %ld %p\n", DeviceInfoSet, DeviceInfoData,
|
|
Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
|
|
RequiredSize);
|
|
|
|
if (PropertyBufferSize != 0)
|
|
{
|
|
PropertyBufferSizeW = PropertyBufferSize * 2;
|
|
PropertyBufferW = HeapAlloc(GetProcessHeap(), 0, PropertyBufferSizeW);
|
|
if (!PropertyBufferW)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
bResult = SetupDiGetDeviceRegistryPropertyW(
|
|
DeviceInfoSet,
|
|
DeviceInfoData,
|
|
Property,
|
|
&RegType,
|
|
PropertyBufferW,
|
|
PropertyBufferSizeW,
|
|
&RequiredSizeW);
|
|
|
|
if (bResult || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
bIsStringProperty = (RegType == REG_SZ || RegType == REG_MULTI_SZ || RegType == REG_EXPAND_SZ);
|
|
|
|
if (bIsStringProperty)
|
|
RequiredSizeA = RequiredSizeW / sizeof(WCHAR);
|
|
else
|
|
RequiredSizeA = RequiredSizeW;
|
|
if (RequiredSize)
|
|
*RequiredSize = RequiredSizeA;
|
|
if (PropertyRegDataType)
|
|
*PropertyRegDataType = RegType;
|
|
}
|
|
|
|
if (!bResult)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, PropertyBufferW);
|
|
return bResult;
|
|
}
|
|
|
|
if (RequiredSizeA <= PropertyBufferSize)
|
|
{
|
|
if (bIsStringProperty && PropertyBufferSize > 0)
|
|
{
|
|
if (WideCharToMultiByte(CP_ACP, 0, (LPWSTR)PropertyBufferW, RequiredSizeW / sizeof(WCHAR), (LPSTR)PropertyBuffer, PropertyBufferSize, NULL, NULL) == 0)
|
|
{
|
|
/* Last error is already set by WideCharToMultiByte */
|
|
bResult = FALSE;
|
|
}
|
|
}
|
|
else
|
|
memcpy(PropertyBuffer, PropertyBufferW, RequiredSizeA);
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
bResult = FALSE;
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, PropertyBufferW);
|
|
return bResult;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiGetDeviceRegistryPropertyW(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN DWORD Property,
|
|
OUT PDWORD PropertyRegDataType OPTIONAL,
|
|
OUT PBYTE PropertyBuffer OPTIONAL,
|
|
IN DWORD PropertyBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL)
|
|
{
|
|
HKEY hEnumKey, hKey;
|
|
DWORD rc;
|
|
BOOL ret = FALSE;
|
|
|
|
TRACE("%p %p %ld %p %p %ld %p\n", DeviceInfoSet, DeviceInfoData,
|
|
Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
|
|
RequiredSize);
|
|
|
|
if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (!DeviceInfoData)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
else if (Property >= SPDRP_MAXIMUM_PROPERTY)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else
|
|
{
|
|
struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
|
|
struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
|
|
|
|
switch (Property)
|
|
{
|
|
case SPDRP_CAPABILITIES:
|
|
case SPDRP_CLASS:
|
|
case SPDRP_CLASSGUID:
|
|
case SPDRP_COMPATIBLEIDS:
|
|
case SPDRP_CONFIGFLAGS:
|
|
case SPDRP_DEVICEDESC:
|
|
case SPDRP_DRIVER:
|
|
case SPDRP_FRIENDLYNAME:
|
|
case SPDRP_HARDWAREID:
|
|
case SPDRP_LOCATION_INFORMATION:
|
|
case SPDRP_LOWERFILTERS:
|
|
case SPDRP_MFG:
|
|
case SPDRP_SECURITY:
|
|
case SPDRP_SERVICE:
|
|
case SPDRP_UI_NUMBER:
|
|
case SPDRP_UI_NUMBER_DESC_FORMAT:
|
|
case SPDRP_UPPERFILTERS:
|
|
{
|
|
LPCWSTR RegistryPropertyName;
|
|
DWORD BufferSize;
|
|
|
|
switch (Property)
|
|
{
|
|
case SPDRP_CAPABILITIES:
|
|
RegistryPropertyName = REGSTR_VAL_CAPABILITIES; break;
|
|
case SPDRP_CLASS:
|
|
RegistryPropertyName = REGSTR_VAL_CLASS; break;
|
|
case SPDRP_CLASSGUID:
|
|
RegistryPropertyName = REGSTR_VAL_CLASSGUID; break;
|
|
case SPDRP_COMPATIBLEIDS:
|
|
RegistryPropertyName = REGSTR_VAL_COMPATIBLEIDS; break;
|
|
case SPDRP_CONFIGFLAGS:
|
|
RegistryPropertyName = REGSTR_VAL_CONFIGFLAGS; break;
|
|
case SPDRP_DEVICEDESC:
|
|
RegistryPropertyName = REGSTR_VAL_DEVDESC; break;
|
|
case SPDRP_DRIVER:
|
|
RegistryPropertyName = REGSTR_VAL_DRIVER; break;
|
|
case SPDRP_FRIENDLYNAME:
|
|
RegistryPropertyName = REGSTR_VAL_FRIENDLYNAME; break;
|
|
case SPDRP_HARDWAREID:
|
|
RegistryPropertyName = REGSTR_VAL_HARDWAREID; break;
|
|
case SPDRP_LOCATION_INFORMATION:
|
|
RegistryPropertyName = REGSTR_VAL_LOCATION_INFORMATION; break;
|
|
case SPDRP_LOWERFILTERS:
|
|
RegistryPropertyName = REGSTR_VAL_LOWERFILTERS; break;
|
|
case SPDRP_MFG:
|
|
RegistryPropertyName = REGSTR_VAL_MFG; break;
|
|
case SPDRP_SECURITY:
|
|
RegistryPropertyName = REGSTR_SECURITY; break;
|
|
case SPDRP_SERVICE:
|
|
RegistryPropertyName = REGSTR_VAL_SERVICE; break;
|
|
case SPDRP_UI_NUMBER:
|
|
RegistryPropertyName = REGSTR_VAL_UI_NUMBER; break;
|
|
case SPDRP_UI_NUMBER_DESC_FORMAT:
|
|
RegistryPropertyName = REGSTR_UI_NUMBER_DESC_FORMAT; break;
|
|
case SPDRP_UPPERFILTERS:
|
|
RegistryPropertyName = REGSTR_VAL_UPPERFILTERS; break;
|
|
default:
|
|
/* Should not happen */
|
|
RegistryPropertyName = NULL; break;
|
|
}
|
|
|
|
/* Open registry key name */
|
|
rc = RegOpenKeyExW(
|
|
list->HKLM,
|
|
REGSTR_PATH_SYSTEMENUM,
|
|
0, /* Options */
|
|
0,
|
|
&hEnumKey);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
break;
|
|
}
|
|
rc = RegOpenKeyExW(
|
|
hEnumKey,
|
|
DevInfo->Data,
|
|
0, /* Options */
|
|
KEY_QUERY_VALUE,
|
|
&hKey);
|
|
RegCloseKey(hEnumKey);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
break;
|
|
}
|
|
/* Read registry entry */
|
|
BufferSize = PropertyBufferSize;
|
|
rc = RegQueryValueExW(
|
|
hKey,
|
|
RegistryPropertyName,
|
|
NULL, /* Reserved */
|
|
PropertyRegDataType,
|
|
PropertyBuffer,
|
|
&BufferSize);
|
|
if (RequiredSize)
|
|
*RequiredSize = BufferSize;
|
|
switch(rc) {
|
|
case ERROR_SUCCESS:
|
|
if (PropertyBuffer != NULL || BufferSize == 0)
|
|
ret = TRUE;
|
|
else
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
break;
|
|
case ERROR_MORE_DATA:
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
break;
|
|
default:
|
|
SetLastError(rc);
|
|
}
|
|
RegCloseKey(hKey);
|
|
break;
|
|
}
|
|
|
|
case SPDRP_PHYSICAL_DEVICE_OBJECT_NAME:
|
|
{
|
|
DWORD required = (strlenW(DevInfo->Data) + 1) * sizeof(WCHAR);
|
|
|
|
if (PropertyRegDataType)
|
|
*PropertyRegDataType = REG_SZ;
|
|
if (RequiredSize)
|
|
*RequiredSize = required;
|
|
if (PropertyBufferSize >= required)
|
|
{
|
|
strcpyW((LPWSTR)PropertyBuffer, DevInfo->Data);
|
|
ret = TRUE;
|
|
}
|
|
else
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
break;
|
|
}
|
|
|
|
/*case SPDRP_BUSTYPEGUID:
|
|
case SPDRP_LEGACYBUSTYPE:
|
|
case SPDRP_BUSNUMBER:
|
|
case SPDRP_ENUMERATOR_NAME:
|
|
case SPDRP_SECURITY_SDS:
|
|
case SPDRP_DEVTYPE:
|
|
case SPDRP_EXCLUSIVE:
|
|
case SPDRP_CHARACTERISTICS:
|
|
case SPDRP_ADDRESS:
|
|
case SPDRP_DEVICE_POWER_DATA:*/
|
|
#if (WINVER >= 0x501)
|
|
/*case SPDRP_REMOVAL_POLICY:
|
|
case SPDRP_REMOVAL_POLICY_HW_DEFAULT:
|
|
case SPDRP_REMOVAL_POLICY_OVERRIDE:
|
|
case SPDRP_INSTALL_STATE:*/
|
|
#endif
|
|
|
|
default:
|
|
{
|
|
ERR("Property 0x%lx not implemented\n", Property);
|
|
SetLastError(ERROR_NOT_SUPPORTED);
|
|
}
|
|
}
|
|
}
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiSetDeviceRegistryPropertyA(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN OUT PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN DWORD Property,
|
|
IN CONST BYTE *PropertyBuffer OPTIONAL,
|
|
IN DWORD PropertyBufferSize)
|
|
{
|
|
FIXME("%p %p 0x%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
|
|
Property, PropertyBuffer, PropertyBufferSize);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return FALSE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiSetDeviceRegistryPropertyW(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN OUT PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN DWORD Property,
|
|
IN CONST BYTE *PropertyBuffer OPTIONAL,
|
|
IN DWORD PropertyBufferSize)
|
|
{
|
|
struct DeviceInfoSet *list;
|
|
BOOL ret = FALSE;
|
|
|
|
TRACE("%p %p 0x%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
|
|
Property, PropertyBuffer, PropertyBufferSize);
|
|
|
|
if (!DeviceInfoSet)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (!DeviceInfoData)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
else
|
|
{
|
|
switch (Property)
|
|
{
|
|
case SPDRP_COMPATIBLEIDS:
|
|
case SPDRP_CONFIGFLAGS:
|
|
case SPDRP_FRIENDLYNAME:
|
|
case SPDRP_HARDWAREID:
|
|
case SPDRP_LOCATION_INFORMATION:
|
|
case SPDRP_LOWERFILTERS:
|
|
case SPDRP_SECURITY:
|
|
case SPDRP_SERVICE:
|
|
case SPDRP_UI_NUMBER_DESC_FORMAT:
|
|
case SPDRP_UPPERFILTERS:
|
|
{
|
|
LPCWSTR RegistryPropertyName;
|
|
DWORD RegistryDataType;
|
|
HKEY hKey;
|
|
LONG rc;
|
|
|
|
switch (Property)
|
|
{
|
|
case SPDRP_COMPATIBLEIDS:
|
|
RegistryPropertyName = REGSTR_VAL_COMPATIBLEIDS;
|
|
RegistryDataType = REG_MULTI_SZ;
|
|
break;
|
|
case SPDRP_CONFIGFLAGS:
|
|
RegistryPropertyName = REGSTR_VAL_CONFIGFLAGS;
|
|
RegistryDataType = REG_DWORD;
|
|
break;
|
|
case SPDRP_FRIENDLYNAME:
|
|
RegistryPropertyName = REGSTR_VAL_FRIENDLYNAME;
|
|
RegistryDataType = REG_SZ;
|
|
break;
|
|
case SPDRP_HARDWAREID:
|
|
RegistryPropertyName = REGSTR_VAL_HARDWAREID;
|
|
RegistryDataType = REG_MULTI_SZ;
|
|
break;
|
|
case SPDRP_LOCATION_INFORMATION:
|
|
RegistryPropertyName = REGSTR_VAL_LOCATION_INFORMATION;
|
|
RegistryDataType = REG_SZ;
|
|
break;
|
|
case SPDRP_LOWERFILTERS:
|
|
RegistryPropertyName = REGSTR_VAL_LOWERFILTERS;
|
|
RegistryDataType = REG_MULTI_SZ;
|
|
break;
|
|
case SPDRP_SECURITY:
|
|
RegistryPropertyName = REGSTR_SECURITY;
|
|
RegistryDataType = REG_BINARY;
|
|
break;
|
|
case SPDRP_SERVICE:
|
|
RegistryPropertyName = REGSTR_VAL_SERVICE;
|
|
RegistryDataType = REG_SZ;
|
|
break;
|
|
case SPDRP_UI_NUMBER_DESC_FORMAT:
|
|
RegistryPropertyName = REGSTR_UI_NUMBER_DESC_FORMAT;
|
|
RegistryDataType = REG_SZ;
|
|
break;
|
|
case SPDRP_UPPERFILTERS:
|
|
RegistryPropertyName = REGSTR_VAL_UPPERFILTERS;
|
|
RegistryDataType = REG_MULTI_SZ;
|
|
break;
|
|
default:
|
|
/* Should not happen */
|
|
RegistryPropertyName = NULL;
|
|
RegistryDataType = REG_BINARY;
|
|
break;
|
|
}
|
|
/* Open device registry key */
|
|
hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE);
|
|
if (hKey != INVALID_HANDLE_VALUE)
|
|
{
|
|
/* Write new data */
|
|
rc = RegSetValueExW(
|
|
hKey,
|
|
RegistryPropertyName,
|
|
0, /* Reserved */
|
|
RegistryDataType,
|
|
PropertyBuffer,
|
|
PropertyBufferSize);
|
|
if (rc == ERROR_SUCCESS)
|
|
ret = TRUE;
|
|
else
|
|
SetLastError(rc);
|
|
RegCloseKey(hKey);
|
|
}
|
|
break;
|
|
}
|
|
|
|
/*case SPDRP_CHARACTERISTICS:
|
|
case SPDRP_DEVTYPE:
|
|
case SPDRP_EXCLUSIVE:*/
|
|
#if (WINVER >= 0x501)
|
|
//case SPDRP_REMOVAL_POLICY_OVERRIDE:
|
|
#endif
|
|
//case SPDRP_SECURITY_SDS:
|
|
|
|
default:
|
|
{
|
|
ERR("Property 0x%lx not implemented\n", Property);
|
|
SetLastError(ERROR_NOT_SUPPORTED);
|
|
}
|
|
}
|
|
}
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static BOOL WINAPI
|
|
IntSetupDiRegisterDeviceInfo(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN OUT PSP_DEVINFO_DATA DeviceInfoData)
|
|
{
|
|
return SetupDiRegisterDeviceInfo(DeviceInfoSet, DeviceInfoData, 0, NULL, NULL, NULL);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiCallClassInstaller (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiCallClassInstaller(
|
|
IN DI_FUNCTION InstallFunction,
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
|
|
{
|
|
BOOL ret = FALSE;
|
|
|
|
TRACE("%u %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
|
|
|
|
if (!DeviceInfoSet)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (((struct DeviceInfoSet *)DeviceInfoSet)->HKLM != HKEY_LOCAL_MACHINE)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
else
|
|
{
|
|
SP_DEVINSTALL_PARAMS_W InstallParams;
|
|
#define CLASS_COINSTALLER 0x1
|
|
#define DEVICE_COINSTALLER 0x2
|
|
#define CLASS_INSTALLER 0x4
|
|
UCHAR CanHandle = 0;
|
|
DEFAULT_CLASS_INSTALL_PROC DefaultHandler = NULL;
|
|
|
|
switch (InstallFunction)
|
|
{
|
|
case DIF_ADDPROPERTYPAGE_ADVANCED:
|
|
CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
|
|
break;
|
|
case DIF_ADDREMOTEPROPERTYPAGE_ADVANCED:
|
|
CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
|
|
break;
|
|
case DIF_ALLOW_INSTALL:
|
|
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
|
|
break;
|
|
case DIF_DETECT:
|
|
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
|
|
break;
|
|
case DIF_DESTROYPRIVATEDATA:
|
|
CanHandle = CLASS_INSTALLER;
|
|
break;
|
|
case DIF_INSTALLDEVICE:
|
|
CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
|
|
DefaultHandler = SetupDiInstallDevice;
|
|
break;
|
|
case DIF_INSTALLDEVICEFILES:
|
|
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
|
|
DefaultHandler = SetupDiInstallDriverFiles;
|
|
break;
|
|
case DIF_INSTALLINTERFACES:
|
|
CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
|
|
DefaultHandler = SetupDiInstallDeviceInterfaces;
|
|
break;
|
|
case DIF_NEWDEVICEWIZARD_FINISHINSTALL:
|
|
CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
|
|
break;
|
|
case DIF_NEWDEVICEWIZARD_POSTANALYZE:
|
|
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
|
|
break;
|
|
case DIF_NEWDEVICEWIZARD_PREANALYZE:
|
|
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
|
|
break;
|
|
case DIF_NEWDEVICEWIZARD_PRESELECT:
|
|
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
|
|
break;
|
|
case DIF_NEWDEVICEWIZARD_SELECT:
|
|
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
|
|
break;
|
|
case DIF_POWERMESSAGEWAKE:
|
|
CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
|
|
break;
|
|
case DIF_PROPERTYCHANGE:
|
|
CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
|
|
DefaultHandler = SetupDiChangeState;
|
|
break;
|
|
case DIF_REGISTER_COINSTALLERS:
|
|
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
|
|
DefaultHandler = SetupDiRegisterCoDeviceInstallers;
|
|
break;
|
|
case DIF_REGISTERDEVICE:
|
|
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
|
|
DefaultHandler = IntSetupDiRegisterDeviceInfo;
|
|
break;
|
|
case DIF_REMOVE:
|
|
CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
|
|
DefaultHandler = SetupDiRemoveDevice;
|
|
break;
|
|
case DIF_SELECTBESTCOMPATDRV:
|
|
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
|
|
DefaultHandler = SetupDiSelectBestCompatDrv;
|
|
break;
|
|
case DIF_SELECTDEVICE:
|
|
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
|
|
DefaultHandler = SetupDiSelectDevice;
|
|
break;
|
|
case DIF_TROUBLESHOOTER:
|
|
CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
|
|
break;
|
|
case DIF_UNREMOVE:
|
|
CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
|
|
DefaultHandler = SetupDiUnremoveDevice;
|
|
break;
|
|
default:
|
|
ERR("Install function %u not supported\n", InstallFunction);
|
|
SetLastError(ERROR_NOT_SUPPORTED);
|
|
}
|
|
|
|
InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
|
|
if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
|
|
/* Don't process this call, as a parameter is invalid */
|
|
CanHandle = 0;
|
|
|
|
if (CanHandle != 0)
|
|
{
|
|
LIST_ENTRY ClassCoInstallersListHead;
|
|
LIST_ENTRY DeviceCoInstallersListHead;
|
|
HMODULE ClassInstallerLibrary = NULL;
|
|
CLASS_INSTALL_PROC ClassInstaller = NULL;
|
|
COINSTALLER_CONTEXT_DATA Context;
|
|
PLIST_ENTRY ListEntry;
|
|
HKEY hKey;
|
|
DWORD dwRegType, dwLength;
|
|
DWORD rc = NO_ERROR;
|
|
|
|
InitializeListHead(&ClassCoInstallersListHead);
|
|
InitializeListHead(&DeviceCoInstallersListHead);
|
|
|
|
if (CanHandle & DEVICE_COINSTALLER)
|
|
{
|
|
hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
|
|
if (hKey != INVALID_HANDLE_VALUE)
|
|
{
|
|
rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, &dwRegType, NULL, &dwLength);
|
|
if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
|
|
{
|
|
LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
|
|
if (KeyBuffer != NULL)
|
|
{
|
|
rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
|
|
if (rc == ERROR_SUCCESS)
|
|
{
|
|
LPWSTR ptr;
|
|
for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
|
|
{
|
|
/* Add coinstaller to DeviceCoInstallersListHead list */
|
|
struct CoInstallerElement *coinstaller;
|
|
TRACE("Got device coinstaller '%s'\n", debugstr_w(ptr));
|
|
coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
|
|
if (!coinstaller)
|
|
continue;
|
|
memset(coinstaller, 0, sizeof(struct CoInstallerElement));
|
|
if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
|
|
InsertTailList(&DeviceCoInstallersListHead, &coinstaller->ListEntry);
|
|
else
|
|
HeapFree(GetProcessHeap(), 0, coinstaller);
|
|
}
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, KeyBuffer);
|
|
}
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
if (CanHandle & CLASS_COINSTALLER)
|
|
{
|
|
rc = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
REGSTR_PATH_CODEVICEINSTALLERS,
|
|
0, /* Options */
|
|
KEY_QUERY_VALUE,
|
|
&hKey);
|
|
if (rc == ERROR_SUCCESS)
|
|
{
|
|
LPWSTR lpGuidString;
|
|
if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) == RPC_S_OK)
|
|
{
|
|
rc = RegQueryValueExW(hKey, lpGuidString, NULL, &dwRegType, NULL, &dwLength);
|
|
if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
|
|
{
|
|
LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
|
|
if (KeyBuffer != NULL)
|
|
{
|
|
rc = RegQueryValueExW(hKey, lpGuidString, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
|
|
if (rc == ERROR_SUCCESS)
|
|
{
|
|
LPWSTR ptr;
|
|
for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
|
|
{
|
|
/* Add coinstaller to ClassCoInstallersListHead list */
|
|
struct CoInstallerElement *coinstaller;
|
|
TRACE("Got class coinstaller '%s'\n", debugstr_w(ptr));
|
|
coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
|
|
if (!coinstaller)
|
|
continue;
|
|
memset(coinstaller, 0, sizeof(struct CoInstallerElement));
|
|
if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
|
|
InsertTailList(&ClassCoInstallersListHead, &coinstaller->ListEntry);
|
|
else
|
|
HeapFree(GetProcessHeap(), 0, coinstaller);
|
|
}
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, KeyBuffer);
|
|
}
|
|
}
|
|
RpcStringFreeW(&lpGuidString);
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
if ((CanHandle & CLASS_INSTALLER) && !(InstallParams.FlagsEx & DI_FLAGSEX_CI_FAILED))
|
|
{
|
|
hKey = SetupDiOpenClassRegKey(&DeviceInfoData->ClassGuid, KEY_QUERY_VALUE);
|
|
if (hKey != INVALID_HANDLE_VALUE)
|
|
{
|
|
rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength);
|
|
if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
|
|
{
|
|
LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
|
|
if (KeyBuffer != NULL)
|
|
{
|
|
rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
|
|
if (rc == ERROR_SUCCESS)
|
|
{
|
|
/* Get ClassInstaller function pointer */
|
|
TRACE("Got class installer '%s'\n", debugstr_w(KeyBuffer));
|
|
if (GetFunctionPointer(KeyBuffer, &ClassInstallerLibrary, (PVOID*)&ClassInstaller) != ERROR_SUCCESS)
|
|
{
|
|
InstallParams.FlagsEx |= DI_FLAGSEX_CI_FAILED;
|
|
SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
|
|
}
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, KeyBuffer);
|
|
}
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
|
|
/* Call Class co-installers */
|
|
Context.PostProcessing = FALSE;
|
|
rc = NO_ERROR;
|
|
ListEntry = ClassCoInstallersListHead.Flink;
|
|
while (rc == NO_ERROR && ListEntry != &ClassCoInstallersListHead)
|
|
{
|
|
struct CoInstallerElement *coinstaller;
|
|
coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
|
|
rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
|
|
coinstaller->PrivateData = Context.PrivateData;
|
|
if (rc == ERROR_DI_POSTPROCESSING_REQUIRED)
|
|
{
|
|
coinstaller->DoPostProcessing = TRUE;
|
|
rc = NO_ERROR;
|
|
}
|
|
ListEntry = ListEntry->Flink;
|
|
}
|
|
|
|
/* Call Device co-installers */
|
|
ListEntry = DeviceCoInstallersListHead.Flink;
|
|
while (rc == NO_ERROR && ListEntry != &DeviceCoInstallersListHead)
|
|
{
|
|
struct CoInstallerElement *coinstaller;
|
|
coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
|
|
rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
|
|
coinstaller->PrivateData = Context.PrivateData;
|
|
if (rc == ERROR_DI_POSTPROCESSING_REQUIRED)
|
|
{
|
|
coinstaller->DoPostProcessing = TRUE;
|
|
rc = NO_ERROR;
|
|
}
|
|
ListEntry = ListEntry->Flink;
|
|
}
|
|
|
|
/* Call Class installer */
|
|
if (ClassInstaller)
|
|
{
|
|
rc = (*ClassInstaller)(InstallFunction, DeviceInfoSet, DeviceInfoData);
|
|
FreeFunctionPointer(ClassInstallerLibrary, ClassInstaller);
|
|
}
|
|
else
|
|
rc = ERROR_DI_DO_DEFAULT;
|
|
|
|
/* Call default handler */
|
|
if (rc == ERROR_DI_DO_DEFAULT)
|
|
{
|
|
if (DefaultHandler && !(InstallParams.Flags & DI_NODI_DEFAULTACTION))
|
|
{
|
|
if ((*DefaultHandler)(DeviceInfoSet, DeviceInfoData))
|
|
rc = NO_ERROR;
|
|
else
|
|
rc = GetLastError();
|
|
}
|
|
else
|
|
rc = NO_ERROR;
|
|
}
|
|
|
|
/* Call Class co-installers that required postprocessing */
|
|
Context.PostProcessing = TRUE;
|
|
ListEntry = ClassCoInstallersListHead.Flink;
|
|
while (ListEntry != &ClassCoInstallersListHead)
|
|
{
|
|
struct CoInstallerElement *coinstaller;
|
|
coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
|
|
if (coinstaller->DoPostProcessing)
|
|
{
|
|
Context.InstallResult = rc;
|
|
Context.PrivateData = coinstaller->PrivateData;
|
|
rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
|
|
}
|
|
FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
|
|
ListEntry = ListEntry->Flink;
|
|
}
|
|
|
|
/* Call Device co-installers that required postprocessing */
|
|
ListEntry = DeviceCoInstallersListHead.Flink;
|
|
while (ListEntry != &DeviceCoInstallersListHead)
|
|
{
|
|
struct CoInstallerElement *coinstaller;
|
|
coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
|
|
if (coinstaller->DoPostProcessing)
|
|
{
|
|
Context.InstallResult = rc;
|
|
Context.PrivateData = coinstaller->PrivateData;
|
|
rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
|
|
}
|
|
FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
|
|
ListEntry = ListEntry->Flink;
|
|
}
|
|
|
|
/* Free allocated memory */
|
|
while (!IsListEmpty(&ClassCoInstallersListHead))
|
|
{
|
|
ListEntry = RemoveHeadList(&ClassCoInstallersListHead);
|
|
HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry));
|
|
}
|
|
while (!IsListEmpty(&DeviceCoInstallersListHead))
|
|
{
|
|
ListEntry = RemoveHeadList(&DeviceCoInstallersListHead);
|
|
HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry));
|
|
}
|
|
|
|
ret = (rc == NO_ERROR);
|
|
}
|
|
}
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetDeviceInfoListClass (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiGetDeviceInfoListClass(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
OUT LPGUID ClassGuid)
|
|
{
|
|
struct DeviceInfoSet *list;
|
|
BOOL ret = FALSE;
|
|
|
|
TRACE("%p %p\n", DeviceInfoSet, ClassGuid);
|
|
|
|
if (!DeviceInfoSet)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
|
|
SetLastError(ERROR_NO_ASSOCIATED_CLASS);
|
|
else
|
|
{
|
|
memcpy(&ClassGuid, &list->ClassGuid, sizeof(GUID));
|
|
|
|
ret = TRUE;
|
|
}
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetDeviceInfoListDetailW (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiGetDeviceInfoListDetailW(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
OUT PSP_DEVINFO_LIST_DETAIL_DATA_W DeviceInfoListDetailData)
|
|
{
|
|
struct DeviceInfoSet *list;
|
|
BOOL ret = FALSE;
|
|
|
|
TRACE("%p %p\n", DeviceInfoSet, DeviceInfoListDetailData);
|
|
|
|
if (!DeviceInfoSet)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (!DeviceInfoListDetailData)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (DeviceInfoListDetailData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W))
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
else
|
|
{
|
|
memcpy(
|
|
&DeviceInfoListDetailData->ClassGuid,
|
|
&list->ClassGuid,
|
|
sizeof(GUID));
|
|
DeviceInfoListDetailData->RemoteMachineHandle = list->hMachine;
|
|
if (list->MachineName)
|
|
strcpyW(DeviceInfoListDetailData->RemoteMachineName, list->MachineName + 2);
|
|
else
|
|
DeviceInfoListDetailData->RemoteMachineName[0] = 0;
|
|
|
|
ret = TRUE;
|
|
}
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiGetDeviceInstallParamsA(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
|
|
OUT PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
|
|
{
|
|
SP_DEVINSTALL_PARAMS_W deviceInstallParamsW;
|
|
BOOL ret = FALSE;
|
|
|
|
TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
|
|
|
|
if (DeviceInstallParams == NULL)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
else
|
|
{
|
|
deviceInstallParamsW.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
|
|
ret = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &deviceInstallParamsW);
|
|
|
|
if (ret)
|
|
{
|
|
/* Do W->A conversion */
|
|
memcpy(
|
|
DeviceInstallParams,
|
|
&deviceInstallParamsW,
|
|
FIELD_OFFSET(SP_DEVINSTALL_PARAMS_W, DriverPath));
|
|
if (WideCharToMultiByte(CP_ACP, 0, deviceInstallParamsW.DriverPath, -1,
|
|
DeviceInstallParams->DriverPath, MAX_PATH, NULL, NULL) == 0)
|
|
{
|
|
DeviceInstallParams->DriverPath[0] = '\0';
|
|
ret = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetDeviceInstallParamsW (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiGetDeviceInstallParamsW(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
|
|
OUT PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
|
|
{
|
|
struct DeviceInfoSet *list;
|
|
BOOL ret = FALSE;
|
|
|
|
TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
|
|
|
|
if (!DeviceInfoSet)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
else if (!DeviceInstallParams)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
else
|
|
{
|
|
PSP_DEVINSTALL_PARAMS_W Source;
|
|
|
|
if (DeviceInfoData)
|
|
Source = &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->InstallParams;
|
|
else
|
|
Source = &list->InstallParams;
|
|
memcpy(DeviceInstallParams, Source, Source->cbSize);
|
|
ret = TRUE;
|
|
}
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
static BOOL
|
|
CheckDeviceInstallParameters(
|
|
IN PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
|
|
{
|
|
DWORD SupportedFlags =
|
|
DI_NOVCP | /* 0x00000008 */
|
|
DI_DIDCOMPAT | /* 0x00000010 */
|
|
DI_DIDCLASS | /* 0x00000020 */
|
|
DI_NEEDRESTART | /* 0x00000080 */
|
|
DI_NEEDREBOOT | /* 0x00000100 */
|
|
DI_RESOURCEPAGE_ADDED | /* 0x00002000 */
|
|
DI_PROPERTIES_CHANGE | /* 0x00004000 */
|
|
DI_ENUMSINGLEINF | /* 0x00010000 */
|
|
DI_DONOTCALLCONFIGMG | /* 0x00020000 */
|
|
DI_CLASSINSTALLPARAMS | /* 0x00100000 */
|
|
DI_NODI_DEFAULTACTION | /* 0x00200000 */
|
|
DI_QUIETINSTALL | /* 0x00800000 */
|
|
DI_NOFILECOPY | /* 0x01000000 */
|
|
DI_DRIVERPAGE_ADDED; /* 0x04000000 */
|
|
DWORD SupportedFlagsEx =
|
|
DI_FLAGSEX_CI_FAILED | /* 0x00000004 */
|
|
DI_FLAGSEX_DIDINFOLIST | /* 0x00000010 */
|
|
DI_FLAGSEX_DIDCOMPATINFO | /* 0x00000020 */
|
|
DI_FLAGSEX_ALLOWEXCLUDEDDRVS | /* 0x00000800 */
|
|
DI_FLAGSEX_NO_DRVREG_MODIFY; /* 0x00008000 */
|
|
BOOL ret = FALSE;
|
|
|
|
/* FIXME: add support for more flags */
|
|
|
|
/* FIXME: DI_CLASSINSTALLPARAMS flag is not correctly used.
|
|
* It should be checked before accessing to other values
|
|
* of the SP_DEVINSTALL_PARAMS structure */
|
|
|
|
if (DeviceInstallParams->Flags & ~SupportedFlags)
|
|
{
|
|
FIXME("Unknown Flags: 0x%08lx\n", DeviceInstallParams->Flags & ~SupportedFlags);
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
}
|
|
else if (DeviceInstallParams->FlagsEx & ~SupportedFlagsEx)
|
|
{
|
|
FIXME("Unknown FlagsEx: 0x%08lx\n", DeviceInstallParams->FlagsEx & ~SupportedFlagsEx);
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
}
|
|
else if ((DeviceInstallParams->Flags & DI_NOVCP)
|
|
&& (DeviceInstallParams->FileQueue == NULL || DeviceInstallParams->FileQueue == (HSPFILEQ)INVALID_HANDLE_VALUE))
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
else
|
|
{
|
|
/* FIXME: check Reserved field */
|
|
ret = TRUE;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiSetDeviceInstallParamsW(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
|
|
IN PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
|
|
{
|
|
struct DeviceInfoSet *list;
|
|
BOOL ret = FALSE;
|
|
|
|
TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
|
|
|
|
if (!DeviceInfoSet)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
else if (!DeviceInstallParams)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
else if (CheckDeviceInstallParameters(DeviceInstallParams))
|
|
{
|
|
PSP_DEVINSTALL_PARAMS_W Destination;
|
|
|
|
if (DeviceInfoData)
|
|
Destination = &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->InstallParams;
|
|
else
|
|
Destination = &list->InstallParams;
|
|
memcpy(Destination, DeviceInstallParams, DeviceInstallParams->cbSize);
|
|
ret = TRUE;
|
|
}
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetDeviceInstanceIdA(SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiGetDeviceInstanceIdA(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
OUT PSTR DeviceInstanceId OPTIONAL,
|
|
IN DWORD DeviceInstanceIdSize,
|
|
OUT PDWORD RequiredSize OPTIONAL)
|
|
{
|
|
PWSTR DeviceInstanceIdW = NULL;
|
|
BOOL ret = FALSE;
|
|
|
|
TRACE("%p %p %p %lu %p\n", DeviceInfoSet, DeviceInfoData,
|
|
DeviceInstanceId, DeviceInstanceIdSize, RequiredSize);
|
|
|
|
if (!DeviceInstanceId && DeviceInstanceIdSize > 0)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else
|
|
{
|
|
if (DeviceInstanceIdSize != 0)
|
|
{
|
|
DeviceInstanceIdW = MyMalloc(DeviceInstanceIdSize * sizeof(WCHAR));
|
|
if (DeviceInstanceIdW == NULL)
|
|
return FALSE;
|
|
}
|
|
|
|
ret = SetupDiGetDeviceInstanceIdW(DeviceInfoSet, DeviceInfoData,
|
|
DeviceInstanceIdW, DeviceInstanceIdSize,
|
|
RequiredSize);
|
|
|
|
if (ret && DeviceInstanceIdW != NULL)
|
|
{
|
|
if (WideCharToMultiByte(CP_ACP, 0, DeviceInstanceIdW, -1,
|
|
DeviceInstanceId, DeviceInstanceIdSize, NULL, NULL) == 0)
|
|
{
|
|
DeviceInstanceId[0] = '\0';
|
|
ret = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetDeviceInstanceIdW(SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiGetDeviceInstanceIdW(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
OUT PWSTR DeviceInstanceId OPTIONAL,
|
|
IN DWORD DeviceInstanceIdSize,
|
|
OUT PDWORD RequiredSize OPTIONAL)
|
|
{
|
|
BOOL ret = FALSE;
|
|
|
|
TRACE("%p %p %p %lu %p\n", DeviceInfoSet, DeviceInfoData,
|
|
DeviceInstanceId, DeviceInstanceIdSize, RequiredSize);
|
|
|
|
if (!DeviceInfoSet)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (!DeviceInfoData)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
else if (!DeviceInstanceId && DeviceInstanceIdSize > 0)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (DeviceInstanceId && DeviceInstanceIdSize == 0)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else
|
|
{
|
|
struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
|
|
DWORD required;
|
|
|
|
required = (strlenW(DevInfo->DeviceName) + 1) * sizeof(WCHAR);
|
|
if (RequiredSize)
|
|
*RequiredSize = required;
|
|
|
|
if (required <= DeviceInstanceIdSize)
|
|
{
|
|
strcpyW(DeviceInstanceId, DevInfo->DeviceName);
|
|
ret = TRUE;
|
|
}
|
|
else
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* SetupDiCreateDevRegKeyA (SETUPAPI.@)
|
|
*/
|
|
HKEY WINAPI
|
|
SetupDiCreateDevRegKeyA(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN DWORD Scope,
|
|
IN DWORD HwProfile,
|
|
IN DWORD KeyType,
|
|
IN HINF InfHandle OPTIONAL,
|
|
IN PCSTR InfSectionName OPTIONAL)
|
|
{
|
|
PCWSTR InfSectionNameW = NULL;
|
|
HKEY ret = INVALID_HANDLE_VALUE;
|
|
|
|
if (InfSectionName)
|
|
{
|
|
InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
|
|
if (InfSectionNameW == NULL) return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
ret = SetupDiCreateDevRegKeyW(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
Scope,
|
|
HwProfile,
|
|
KeyType,
|
|
InfHandle,
|
|
InfSectionNameW);
|
|
|
|
if (InfSectionNameW != NULL)
|
|
MyFree((PVOID)InfSectionNameW);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static HKEY
|
|
OpenHardwareProfileKey(
|
|
IN HKEY HKLM,
|
|
IN DWORD HwProfile,
|
|
IN DWORD samDesired)
|
|
{
|
|
HKEY hHWProfilesKey = NULL;
|
|
HKEY hHWProfileKey = NULL;
|
|
HKEY ret = INVALID_HANDLE_VALUE;
|
|
LONG rc;
|
|
|
|
rc = RegOpenKeyExW(HKLM,
|
|
REGSTR_PATH_HWPROFILES,
|
|
0,
|
|
0,
|
|
&hHWProfilesKey);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
goto cleanup;
|
|
}
|
|
if (HwProfile == 0)
|
|
{
|
|
rc = RegOpenKeyExW(
|
|
hHWProfilesKey,
|
|
REGSTR_KEY_CURRENT,
|
|
0,
|
|
KEY_CREATE_SUB_KEY,
|
|
&hHWProfileKey);
|
|
}
|
|
else
|
|
{
|
|
WCHAR subKey[5];
|
|
snprintfW(subKey, 4, L"%04lu", HwProfile);
|
|
subKey[4] = '\0';
|
|
rc = RegOpenKeyExW(
|
|
hHWProfilesKey,
|
|
subKey,
|
|
0,
|
|
KEY_CREATE_SUB_KEY,
|
|
&hHWProfileKey);
|
|
}
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
goto cleanup;
|
|
}
|
|
ret = hHWProfileKey;
|
|
|
|
cleanup:
|
|
if (hHWProfilesKey != NULL)
|
|
RegCloseKey(hHWProfilesKey);
|
|
if (hHWProfileKey != NULL && hHWProfileKey != ret)
|
|
RegCloseKey(hHWProfileKey);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiCreateDevRegKeyW (SETUPAPI.@)
|
|
*/
|
|
HKEY WINAPI
|
|
SetupDiCreateDevRegKeyW(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN DWORD Scope,
|
|
IN DWORD HwProfile,
|
|
IN DWORD KeyType,
|
|
IN HINF InfHandle OPTIONAL,
|
|
IN PCWSTR InfSectionName OPTIONAL)
|
|
{
|
|
struct DeviceInfoSet *list;
|
|
HKEY ret = INVALID_HANDLE_VALUE;
|
|
|
|
TRACE("%p %p %lu %lu %lu %p %s\n", DeviceInfoSet, DeviceInfoData,
|
|
Scope, HwProfile, KeyType, InfHandle, debugstr_w(InfSectionName));
|
|
|
|
if (!DeviceInfoSet)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (!DeviceInfoData)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
else if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (InfHandle && !InfSectionName)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (!InfHandle && InfSectionName)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else
|
|
{
|
|
LPWSTR lpGuidString = NULL;
|
|
LPWSTR DriverKey = NULL; /* {GUID}\Index */
|
|
LPWSTR pDeviceInstance; /* Points into DriverKey, on the Index field */
|
|
DWORD Index; /* Index used in the DriverKey name */
|
|
DWORD rc;
|
|
HKEY hHWProfileKey = INVALID_HANDLE_VALUE;
|
|
HKEY hEnumKey = NULL;
|
|
HKEY hClassKey = NULL;
|
|
HKEY hDeviceKey = INVALID_HANDLE_VALUE;
|
|
HKEY hKey = NULL;
|
|
HKEY RootKey;
|
|
|
|
if (Scope == DICS_FLAG_GLOBAL)
|
|
RootKey = list->HKLM;
|
|
else /* Scope == DICS_FLAG_CONFIGSPECIFIC */
|
|
{
|
|
hHWProfileKey = OpenHardwareProfileKey(list->HKLM, HwProfile, KEY_CREATE_SUB_KEY);
|
|
if (hHWProfileKey == INVALID_HANDLE_VALUE)
|
|
goto cleanup;
|
|
RootKey = hHWProfileKey;
|
|
}
|
|
|
|
if (KeyType == DIREG_DEV)
|
|
{
|
|
struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
|
|
|
|
rc = RegCreateKeyExW(
|
|
RootKey,
|
|
REGSTR_PATH_SYSTEMENUM,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_CREATE_SUB_KEY,
|
|
NULL,
|
|
&hEnumKey,
|
|
NULL);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
goto cleanup;
|
|
}
|
|
rc = RegCreateKeyExW(
|
|
hEnumKey,
|
|
deviceInfo->DeviceName,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
#if _WIN32_WINNT >= 0x502
|
|
KEY_READ | KEY_WRITE,
|
|
#else
|
|
KEY_ALL_ACCESS,
|
|
#endif
|
|
NULL,
|
|
&hKey,
|
|
NULL);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
else /* KeyType == DIREG_DRV */
|
|
{
|
|
if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) != RPC_S_OK)
|
|
goto cleanup;
|
|
/* The driver key is in \System\CurrentControlSet\Control\Class\{GUID}\Index */
|
|
DriverKey = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpGuidString) + 7) * sizeof(WCHAR) + sizeof(UNICODE_STRING));
|
|
if (!DriverKey)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto cleanup;
|
|
}
|
|
strcpyW(DriverKey, L"{");
|
|
strcatW(DriverKey, lpGuidString);
|
|
strcatW(DriverKey, L"}\\");
|
|
pDeviceInstance = &DriverKey[strlenW(DriverKey)];
|
|
rc = RegOpenKeyExW(RootKey,
|
|
REGSTR_PATH_CLASS_NT,
|
|
0,
|
|
KEY_CREATE_SUB_KEY,
|
|
&hClassKey);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Try all values for Index between 0 and 9999 */
|
|
Index = 0;
|
|
while (Index <= 9999)
|
|
{
|
|
DWORD Disposition;
|
|
wsprintf(pDeviceInstance, L"%04lu", Index);
|
|
rc = RegCreateKeyEx(hClassKey,
|
|
DriverKey,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
#if _WIN32_WINNT >= 0x502
|
|
KEY_READ | KEY_WRITE,
|
|
#else
|
|
KEY_ALL_ACCESS,
|
|
#endif
|
|
NULL,
|
|
&hKey,
|
|
&Disposition);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
goto cleanup;
|
|
}
|
|
if (Disposition == REG_CREATED_NEW_KEY)
|
|
break;
|
|
RegCloseKey(hKey);
|
|
hKey = NULL;
|
|
Index++;
|
|
}
|
|
if (Index > 9999)
|
|
{
|
|
/* Unable to create more than 9999 devices within the same class */
|
|
SetLastError(ERROR_GEN_FAILURE);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Open device key, to write Driver value */
|
|
hDeviceKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, Scope, HwProfile, DIREG_DEV, KEY_SET_VALUE);
|
|
if (hDeviceKey == INVALID_HANDLE_VALUE)
|
|
goto cleanup;
|
|
rc = RegSetValueEx(hDeviceKey, REGSTR_VAL_DRIVER, 0, REG_SZ, (const BYTE *)DriverKey, (strlenW(DriverKey) + 1) * sizeof(WCHAR));
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
/* Do installation of the specified section */
|
|
if (InfHandle)
|
|
{
|
|
FIXME("Need to install section %s in file %p\n",
|
|
debugstr_w(InfSectionName), InfHandle);
|
|
}
|
|
ret = hKey;
|
|
|
|
cleanup:
|
|
if (lpGuidString)
|
|
RpcStringFreeW(&lpGuidString);
|
|
HeapFree(GetProcessHeap(), 0, DriverKey);
|
|
if (hHWProfileKey != INVALID_HANDLE_VALUE)
|
|
RegCloseKey(hHWProfileKey);
|
|
if (hEnumKey != NULL)
|
|
RegCloseKey(hEnumKey);
|
|
if (hClassKey != NULL)
|
|
RegCloseKey(hClassKey);
|
|
if (hDeviceKey != INVALID_HANDLE_VALUE)
|
|
RegCloseKey(hDeviceKey);
|
|
if (hKey != NULL && hKey != ret)
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
TRACE("Returning 0x%p\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiOpenDevRegKey (SETUPAPI.@)
|
|
*/
|
|
HKEY WINAPI
|
|
SetupDiOpenDevRegKey(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN DWORD Scope,
|
|
IN DWORD HwProfile,
|
|
IN DWORD KeyType,
|
|
IN REGSAM samDesired)
|
|
{
|
|
struct DeviceInfoSet *list;
|
|
HKEY ret = INVALID_HANDLE_VALUE;
|
|
|
|
TRACE("%p %p %lu %lu %lu 0x%lx\n", DeviceInfoSet, DeviceInfoData,
|
|
Scope, HwProfile, KeyType, samDesired);
|
|
|
|
if (!DeviceInfoSet)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (!DeviceInfoData)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
else if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else
|
|
{
|
|
struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
|
|
LPWSTR DriverKey = NULL;
|
|
DWORD dwLength = 0;
|
|
DWORD dwRegType;
|
|
DWORD rc;
|
|
HKEY hHWProfileKey = INVALID_HANDLE_VALUE;
|
|
HKEY hEnumKey = NULL;
|
|
HKEY hKey = NULL;
|
|
HKEY RootKey;
|
|
|
|
if (Scope == DICS_FLAG_GLOBAL)
|
|
RootKey = list->HKLM;
|
|
else /* Scope == DICS_FLAG_CONFIGSPECIFIC */
|
|
{
|
|
hHWProfileKey = OpenHardwareProfileKey(list->HKLM, HwProfile, 0);
|
|
if (hHWProfileKey == INVALID_HANDLE_VALUE)
|
|
goto cleanup;
|
|
RootKey = hHWProfileKey;
|
|
}
|
|
|
|
rc = RegOpenKeyExW(
|
|
RootKey,
|
|
REGSTR_PATH_SYSTEMENUM,
|
|
0, /* Options */
|
|
0,
|
|
&hEnumKey);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
goto cleanup;
|
|
}
|
|
rc = RegOpenKeyExW(
|
|
hEnumKey,
|
|
deviceInfo->DeviceName,
|
|
0, /* Options */
|
|
KeyType == DIREG_DEV ? samDesired : KEY_QUERY_VALUE,
|
|
&hKey);
|
|
RegCloseKey(hEnumKey);
|
|
hEnumKey = NULL;
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
goto cleanup;
|
|
}
|
|
if (KeyType == DIREG_DEV)
|
|
{
|
|
/* We're done. Just return the hKey handle */
|
|
ret = hKey;
|
|
goto cleanup;
|
|
}
|
|
/* Read the 'Driver' key */
|
|
rc = RegQueryValueExW(hKey, REGSTR_VAL_DRIVER, NULL, &dwRegType, NULL, &dwLength);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
goto cleanup;
|
|
}
|
|
else if (dwRegType != REG_SZ)
|
|
{
|
|
SetLastError(ERROR_GEN_FAILURE);
|
|
goto cleanup;
|
|
}
|
|
DriverKey = HeapAlloc(GetProcessHeap(), 0, dwLength);
|
|
if (!DriverKey)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto cleanup;
|
|
}
|
|
rc = RegQueryValueExW(hKey, REGSTR_VAL_DRIVER, NULL, &dwRegType, (LPBYTE)DriverKey, &dwLength);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
goto cleanup;
|
|
}
|
|
RegCloseKey(hKey);
|
|
hKey = NULL;
|
|
/* Need to open the driver key */
|
|
rc = RegOpenKeyExW(
|
|
RootKey,
|
|
REGSTR_PATH_CLASS_NT,
|
|
0, /* Options */
|
|
0,
|
|
&hEnumKey);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
goto cleanup;
|
|
}
|
|
rc = RegOpenKeyExW(
|
|
hEnumKey,
|
|
DriverKey,
|
|
0, /* Options */
|
|
samDesired,
|
|
&hKey);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
goto cleanup;
|
|
}
|
|
ret = hKey;
|
|
|
|
cleanup:
|
|
if (hHWProfileKey != INVALID_HANDLE_VALUE)
|
|
RegCloseKey(hHWProfileKey);
|
|
if (hEnumKey != NULL)
|
|
RegCloseKey(hEnumKey);
|
|
if (hKey != NULL && hKey != ret)
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
TRACE("Returning 0x%p\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiCreateDeviceInfoA (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiCreateDeviceInfoA(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PCSTR DeviceName,
|
|
IN CONST GUID *ClassGuid,
|
|
IN PCSTR DeviceDescription OPTIONAL,
|
|
IN HWND hwndParent OPTIONAL,
|
|
IN DWORD CreationFlags,
|
|
OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
|
|
{
|
|
LPWSTR DeviceNameW = NULL;
|
|
LPWSTR DeviceDescriptionW = NULL;
|
|
BOOL bResult;
|
|
|
|
TRACE("\n");
|
|
|
|
if (DeviceName)
|
|
{
|
|
DeviceNameW = MultiByteToUnicode(DeviceName, CP_ACP);
|
|
if (DeviceNameW == NULL) return FALSE;
|
|
}
|
|
if (DeviceDescription)
|
|
{
|
|
DeviceDescriptionW = MultiByteToUnicode(DeviceDescription, CP_ACP);
|
|
if (DeviceDescriptionW == NULL)
|
|
{
|
|
if (DeviceNameW) MyFree(DeviceNameW);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
bResult = SetupDiCreateDeviceInfoW(DeviceInfoSet, DeviceNameW,
|
|
ClassGuid, DeviceDescriptionW,
|
|
hwndParent, CreationFlags,
|
|
DeviceInfoData);
|
|
|
|
if (DeviceNameW) MyFree(DeviceNameW);
|
|
if (DeviceDescriptionW) MyFree(DeviceDescriptionW);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiCreateDeviceInfoW (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiCreateDeviceInfoW(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PCWSTR DeviceName,
|
|
IN CONST GUID *ClassGuid,
|
|
IN PCWSTR DeviceDescription OPTIONAL,
|
|
IN HWND hwndParent OPTIONAL,
|
|
IN DWORD CreationFlags,
|
|
OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
|
|
{
|
|
struct DeviceInfoSet *list;
|
|
BOOL ret = FALSE;
|
|
|
|
TRACE("%p %s %s %s %p %lx %p\n", DeviceInfoSet, debugstr_w(DeviceName),
|
|
debugstr_guid(ClassGuid), debugstr_w(DeviceDescription),
|
|
hwndParent, CreationFlags, DeviceInfoData);
|
|
|
|
if (!DeviceInfoSet)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (!ClassGuid)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, ClassGuid))
|
|
SetLastError(ERROR_CLASS_MISMATCH);
|
|
else if (CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS))
|
|
{
|
|
TRACE("Unknown flags: 0x%08lx\n", CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS));
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
}
|
|
else
|
|
{
|
|
SP_DEVINFO_DATA DevInfo;
|
|
|
|
if (CreationFlags & DICD_GENERATE_ID)
|
|
{
|
|
/* Generate a new unique ID for this device */
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
FIXME("not implemented\n");
|
|
}
|
|
else
|
|
{
|
|
/* Device name is fully qualified. Try to open it */
|
|
BOOL rc;
|
|
|
|
DevInfo.cbSize = sizeof(SP_DEVINFO_DATA);
|
|
rc = SetupDiOpenDeviceInfoW(
|
|
DeviceInfoSet,
|
|
DeviceName,
|
|
NULL, /* hwndParent */
|
|
CreationFlags & DICD_INHERIT_CLASSDRVS ? DIOD_INHERIT_CLASSDRVS : 0,
|
|
&DevInfo);
|
|
|
|
if (rc)
|
|
{
|
|
/* SetupDiOpenDeviceInfoW has already added
|
|
* the device info to the device info set
|
|
*/
|
|
SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
|
|
}
|
|
else if (GetLastError() == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
struct DeviceInfoElement *deviceInfo;
|
|
|
|
if (CreateDeviceInfoElement(list, DeviceName, ClassGuid, &deviceInfo))
|
|
{
|
|
InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
|
|
|
|
if (!DeviceInfoData)
|
|
ret = TRUE;
|
|
else
|
|
{
|
|
if (DeviceInfoData->cbSize != sizeof(PSP_DEVINFO_DATA))
|
|
{
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
}
|
|
else
|
|
{
|
|
memcpy(&DeviceInfoData->ClassGuid, ClassGuid, sizeof(GUID));
|
|
DeviceInfoData->DevInst = deviceInfo->dnDevInst;
|
|
DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
|
|
ret = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* SetupDiDeleteDeviceInfo (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiDeleteDeviceInfo(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData)
|
|
{
|
|
TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
|
|
|
|
FIXME("not implemented\n");
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* SetupDiOpenDeviceInfoA (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiOpenDeviceInfoA(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PCSTR DeviceInstanceId,
|
|
IN HWND hwndParent OPTIONAL,
|
|
IN DWORD OpenFlags,
|
|
OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
|
|
{
|
|
LPWSTR DeviceInstanceIdW = NULL;
|
|
BOOL bResult;
|
|
|
|
TRACE("%p %s %p %lx %p\n", DeviceInfoSet, DeviceInstanceId, hwndParent, OpenFlags, DeviceInfoData);
|
|
|
|
DeviceInstanceIdW = MultiByteToUnicode(DeviceInstanceId, CP_ACP);
|
|
if (DeviceInstanceIdW == NULL)
|
|
return FALSE;
|
|
|
|
bResult = SetupDiOpenDeviceInfoW(DeviceInfoSet,
|
|
DeviceInstanceIdW, hwndParent, OpenFlags, DeviceInfoData);
|
|
|
|
MyFree(DeviceInstanceIdW);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* SetupDiOpenDeviceInfoW (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiOpenDeviceInfoW(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PCWSTR DeviceInstanceId,
|
|
IN HWND hwndParent OPTIONAL,
|
|
IN DWORD OpenFlags,
|
|
OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
|
|
{
|
|
struct DeviceInfoSet *list;
|
|
HKEY hEnumKey, hKey = NULL;
|
|
DWORD rc;
|
|
BOOL ret = FALSE;
|
|
|
|
TRACE("%p %s %p %lx %p\n",
|
|
DeviceInfoSet, debugstr_w(DeviceInstanceId),
|
|
hwndParent, OpenFlags, DeviceInfoData);
|
|
|
|
if (OpenFlags & DIOD_CANCEL_REMOVE)
|
|
FIXME("DIOD_CANCEL_REMOVE flag not implemented\n");
|
|
|
|
if (!DeviceInfoSet)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (!DeviceInstanceId)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS))
|
|
{
|
|
TRACE("Unknown flags: 0x%08lx\n", OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS));
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
}
|
|
else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
else
|
|
{
|
|
struct DeviceInfoElement *deviceInfo = NULL;
|
|
/* Search if device already exists in DeviceInfoSet.
|
|
* If yes, return the existing element
|
|
* If no, create a new element using informations in registry
|
|
*/
|
|
PLIST_ENTRY ItemList = list->ListHead.Flink;
|
|
while (ItemList != &list->ListHead)
|
|
{
|
|
// TODO
|
|
//if (good one)
|
|
// break;
|
|
FIXME("not implemented\n");
|
|
ItemList = ItemList->Flink;
|
|
}
|
|
|
|
if (deviceInfo)
|
|
{
|
|
/* good one found */
|
|
ret = TRUE;
|
|
}
|
|
else
|
|
{
|
|
/* Open supposed registry key */
|
|
rc = RegOpenKeyExW(
|
|
list->HKLM,
|
|
REGSTR_PATH_SYSTEMENUM,
|
|
0, /* Options */
|
|
0,
|
|
&hEnumKey);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
goto cleanup;
|
|
}
|
|
rc = RegOpenKeyExW(
|
|
hEnumKey,
|
|
DeviceInstanceId,
|
|
0, /* Options */
|
|
KEY_QUERY_VALUE,
|
|
&hKey);
|
|
RegCloseKey(hEnumKey);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
if (rc == ERROR_FILE_NOT_FOUND)
|
|
rc = ERROR_NO_SUCH_DEVINST;
|
|
SetLastError(rc);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* FIXME: try to get ClassGUID from registry, instead of
|
|
* sending GUID_NULL to CreateDeviceInfoElement
|
|
*/
|
|
if (!CreateDeviceInfoElement(list, DeviceInstanceId, &GUID_NULL, &deviceInfo))
|
|
goto cleanup;
|
|
InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
|
|
|
|
ret = TRUE;
|
|
}
|
|
|
|
if (ret && deviceInfo && DeviceInfoData)
|
|
{
|
|
memcpy(&DeviceInfoData->ClassGuid, &deviceInfo->ClassGuid, sizeof(GUID));
|
|
DeviceInfoData->DevInst = deviceInfo->dnDevInst;
|
|
DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
if (hKey != NULL)
|
|
RegCloseKey(hKey);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetSelectedDevice (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiGetSelectedDevice(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
OUT PSP_DEVINFO_DATA DeviceInfoData)
|
|
{
|
|
struct DeviceInfoSet *list;
|
|
BOOL ret = FALSE;
|
|
|
|
TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
|
|
|
|
if (!DeviceInfoSet)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (list->SelectedDevice == NULL)
|
|
SetLastError(ERROR_NO_DEVICE_SELECTED);
|
|
else if (!DeviceInfoData)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
else
|
|
{
|
|
memcpy(&DeviceInfoData->ClassGuid,
|
|
&list->SelectedDevice->ClassGuid,
|
|
sizeof(GUID));
|
|
DeviceInfoData->DevInst = list->SelectedDevice->dnDevInst;
|
|
DeviceInfoData->Reserved = (ULONG_PTR)list->SelectedDevice;
|
|
ret = TRUE;
|
|
}
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* SetupDiSetSelectedDevice (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiSetSelectedDevice(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData)
|
|
{
|
|
struct DeviceInfoSet *list;
|
|
BOOL ret = FALSE;
|
|
|
|
TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
|
|
|
|
if (!DeviceInfoSet)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (!DeviceInfoData)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
else if (DeviceInfoData->Reserved == 0)
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
else
|
|
{
|
|
list->SelectedDevice = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
|
|
ret = TRUE;
|
|
}
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Return the current hardware profile id, or -1 if error */
|
|
static DWORD
|
|
GetCurrentHwProfile(
|
|
IN HDEVINFO DeviceInfoSet)
|
|
{
|
|
HKEY hKey = NULL;
|
|
DWORD dwRegType, dwLength;
|
|
DWORD hwProfile;
|
|
LONG rc;
|
|
DWORD ret = (DWORD)-1;
|
|
|
|
rc = RegOpenKeyExW(
|
|
((struct DeviceInfoSet *)DeviceInfoSet)->HKLM,
|
|
REGSTR_PATH_IDCONFIGDB,
|
|
0, /* Options */
|
|
KEY_QUERY_VALUE,
|
|
&hKey);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
goto cleanup;
|
|
}
|
|
|
|
dwLength = sizeof(DWORD);
|
|
rc = RegQueryValueExW(
|
|
hKey,
|
|
REGSTR_VAL_CURRENTCONFIG,
|
|
NULL,
|
|
&dwRegType,
|
|
(LPBYTE)&hwProfile, &dwLength);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
goto cleanup;
|
|
}
|
|
else if (dwRegType != REG_DWORD || dwLength != sizeof(DWORD))
|
|
{
|
|
SetLastError(ERROR_GEN_FAILURE);
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = hwProfile;
|
|
|
|
cleanup:
|
|
if (hKey != NULL)
|
|
RegCloseKey(hKey);
|
|
|
|
return hwProfile;
|
|
}
|
|
|
|
static BOOL
|
|
ResetDevice(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData)
|
|
{
|
|
#ifndef __WINESRC__
|
|
PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData;
|
|
struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
|
|
NTSTATUS Status;
|
|
|
|
if (((struct DeviceInfoSet *)DeviceInfoSet)->HKLM != HKEY_LOCAL_MACHINE)
|
|
{
|
|
/* At the moment, I only know how to start local devices */
|
|
SetLastError(ERROR_INVALID_COMPUTERNAME);
|
|
return FALSE;
|
|
}
|
|
|
|
RtlInitUnicodeString(&ResetDeviceData.DeviceInstance, deviceInfo->DeviceName);
|
|
Status = NtPlugPlayControl(PlugPlayControlResetDevice, &ResetDeviceData, sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA));
|
|
SetLastError(RtlNtStatusToDosError(Status));
|
|
return NT_SUCCESS(Status);
|
|
#else
|
|
FIXME("Stub: ResetDevice(%p %p)\n", DeviceInfoSet, DeviceInfoData);
|
|
return TRUE;
|
|
#endif
|
|
}
|
|
|
|
static BOOL StopDevice(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData)
|
|
{
|
|
FIXME("Stub: StopDevice(%p %p)\n", DeviceInfoSet, DeviceInfoData);
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiChangeState (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiChangeState(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN OUT PSP_DEVINFO_DATA DeviceInfoData)
|
|
{
|
|
PSP_PROPCHANGE_PARAMS PropChange;
|
|
HKEY hKey = INVALID_HANDLE_VALUE;
|
|
LPCWSTR RegistryValueName;
|
|
DWORD dwConfigFlags, dwLength, dwRegType;
|
|
LONG rc;
|
|
BOOL ret = FALSE;
|
|
|
|
TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
|
|
|
|
if (!DeviceInfoData)
|
|
PropChange = ((struct DeviceInfoSet *)DeviceInfoSet)->ClassInstallParams.PropChange;
|
|
else
|
|
PropChange = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->ClassInstallParams.PropChange;
|
|
if (!PropChange)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (PropChange->Scope == DICS_FLAG_GLOBAL)
|
|
RegistryValueName = REGSTR_VAL_CONFIGFLAGS;
|
|
else
|
|
RegistryValueName = REGSTR_VAL_CSCONFIGFLAGS;
|
|
|
|
switch (PropChange->StateChange)
|
|
{
|
|
case DICS_ENABLE:
|
|
case DICS_DISABLE:
|
|
{
|
|
/* Enable/disable device in registry */
|
|
hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, PropChange->Scope, PropChange->HwProfile, DIREG_DEV, KEY_QUERY_VALUE | KEY_SET_VALUE);
|
|
if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
|
|
hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, PropChange->Scope, PropChange->HwProfile, DIREG_DEV, NULL, NULL);
|
|
if (hKey == INVALID_HANDLE_VALUE)
|
|
break;
|
|
dwLength = sizeof(DWORD);
|
|
rc = RegQueryValueExW(
|
|
hKey,
|
|
RegistryValueName,
|
|
NULL,
|
|
&dwRegType,
|
|
(LPBYTE)&dwConfigFlags, &dwLength);
|
|
if (rc == ERROR_FILE_NOT_FOUND)
|
|
dwConfigFlags = 0;
|
|
else if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
goto cleanup;
|
|
}
|
|
else if (dwRegType != REG_DWORD || dwLength != sizeof(DWORD))
|
|
{
|
|
SetLastError(ERROR_GEN_FAILURE);
|
|
goto cleanup;
|
|
}
|
|
if (PropChange->StateChange == DICS_ENABLE)
|
|
dwConfigFlags &= ~(PropChange->Scope == DICS_FLAG_GLOBAL ? CONFIGFLAG_DISABLED : CSCONFIGFLAG_DISABLED);
|
|
else
|
|
dwConfigFlags |= (PropChange->Scope == DICS_FLAG_GLOBAL ? CONFIGFLAG_DISABLED : CSCONFIGFLAG_DISABLED);
|
|
rc = RegSetValueEx(
|
|
hKey,
|
|
RegistryValueName,
|
|
0,
|
|
REG_DWORD,
|
|
(LPBYTE)&dwConfigFlags, sizeof(DWORD));
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Enable/disable device if needed */
|
|
if (PropChange->Scope == DICS_FLAG_GLOBAL
|
|
|| PropChange->HwProfile == 0
|
|
|| PropChange->HwProfile == GetCurrentHwProfile(DeviceInfoSet))
|
|
{
|
|
if (PropChange->StateChange == DICS_ENABLE)
|
|
ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
|
|
else
|
|
ret = StopDevice(DeviceInfoSet, DeviceInfoData);
|
|
}
|
|
else
|
|
ret = TRUE;
|
|
break;
|
|
}
|
|
case DICS_PROPCHANGE:
|
|
{
|
|
ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
ERR("Unknown StateChange 0x%lx\n", PropChange->StateChange);
|
|
SetLastError(ERROR_NOT_SUPPORTED);
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
if (hKey != INVALID_HANDLE_VALUE)
|
|
RegCloseKey(hKey);
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiSelectDevice (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiSelectDevice(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
|
|
{
|
|
FIXME("%p %p\n", DeviceInfoSet, DeviceInfoData);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* SetupDiRegisterCoDeviceInstallers (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiRegisterCoDeviceInstallers(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData)
|
|
{
|
|
BOOL ret = FALSE; /* Return value */
|
|
|
|
TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
|
|
|
|
if (!DeviceInfoSet)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (!DeviceInfoData)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
else
|
|
{
|
|
SP_DEVINSTALL_PARAMS_W InstallParams;
|
|
struct DriverInfoElement *SelectedDriver;
|
|
BOOL Result;
|
|
DWORD DoAction;
|
|
WCHAR SectionName[MAX_PATH];
|
|
DWORD SectionNameLength = 0;
|
|
HKEY hKey = INVALID_HANDLE_VALUE;
|
|
PVOID Context = NULL;
|
|
|
|
InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
|
|
Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
|
|
if (!Result)
|
|
goto cleanup;
|
|
|
|
SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
|
|
if (SelectedDriver == NULL)
|
|
{
|
|
SetLastError(ERROR_NO_DRIVER_SELECTED);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Get .CoInstallers section name */
|
|
Result = SetupDiGetActualSectionToInstallW(
|
|
SelectedDriver->InfFileDetails->hInf,
|
|
SelectedDriver->Details.SectionName,
|
|
SectionName, MAX_PATH, &SectionNameLength, NULL);
|
|
if (!Result || SectionNameLength > MAX_PATH - strlenW(DotCoInstallers) - 1)
|
|
goto cleanup;
|
|
lstrcatW(SectionName, DotCoInstallers);
|
|
|
|
/* Open/Create driver key information */
|
|
#if _WIN32_WINNT >= 0x502
|
|
hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE);
|
|
#else
|
|
hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
|
|
#endif
|
|
if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
|
|
hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
|
|
if (hKey == INVALID_HANDLE_VALUE)
|
|
goto cleanup;
|
|
|
|
/* Install .CoInstallers section */
|
|
DoAction = SPINST_REGISTRY;
|
|
if (!(InstallParams.Flags & DI_NOFILECOPY))
|
|
{
|
|
DoAction |= SPINST_FILES;
|
|
Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
|
|
if (!Context)
|
|
goto cleanup;
|
|
}
|
|
Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
|
|
SelectedDriver->InfFileDetails->hInf, SectionName,
|
|
DoAction, hKey, SelectedDriver->InfFileDetails->DirectoryName, SP_COPY_NEWER,
|
|
SetupDefaultQueueCallback, Context,
|
|
DeviceInfoSet, DeviceInfoData);
|
|
if (!Result)
|
|
goto cleanup;
|
|
|
|
ret = TRUE;
|
|
|
|
cleanup:
|
|
if (Context)
|
|
SetupTermDefaultQueueCallback(Context);
|
|
if (hKey != INVALID_HANDLE_VALUE)
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
static BOOL
|
|
InfIsFromOEMLocation(
|
|
IN PCWSTR FullName,
|
|
OUT LPBOOL IsOEMLocation)
|
|
{
|
|
PWCHAR last;
|
|
|
|
last = strrchrW(FullName, '\\');
|
|
if (!last)
|
|
{
|
|
/* No directory specified */
|
|
*IsOEMLocation = FALSE;
|
|
}
|
|
else
|
|
{
|
|
LPWSTR Windir;
|
|
UINT ret;
|
|
|
|
Windir = MyMalloc((MAX_PATH + 1 + strlenW(InfDirectory)) * sizeof(WCHAR));
|
|
if (!Windir)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
ret = GetSystemWindowsDirectoryW(Windir, MAX_PATH);
|
|
if (ret == 0 || ret > MAX_PATH)
|
|
{
|
|
MyFree(Windir);
|
|
SetLastError(ERROR_GEN_FAILURE);
|
|
return FALSE;
|
|
}
|
|
if (*Windir && Windir[strlenW(Windir) - 1] != '\\')
|
|
strcatW(Windir, BackSlash);
|
|
strcatW(Windir, InfDirectory);
|
|
|
|
if (strncmpiW(FullName, Windir, last - FullName) == 0)
|
|
{
|
|
/* The path is %SYSTEMROOT%\Inf */
|
|
*IsOEMLocation = FALSE;
|
|
}
|
|
else
|
|
{
|
|
/* The file is in another place */
|
|
*IsOEMLocation = TRUE;
|
|
}
|
|
MyFree(Windir);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiInstallDevice (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI
|
|
SetupDiInstallDevice(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN OUT PSP_DEVINFO_DATA DeviceInfoData)
|
|
{
|
|
SP_DEVINSTALL_PARAMS_W InstallParams;
|
|
struct DriverInfoElement *SelectedDriver;
|
|
SYSTEMTIME DriverDate;
|
|
WCHAR SectionName[MAX_PATH];
|
|
WCHAR Buffer[32];
|
|
DWORD SectionNameLength = 0;
|
|
BOOL Result = FALSE;
|
|
ULONG DoAction;
|
|
DWORD RequiredSize;
|
|
LPWSTR pSectionName = NULL;
|
|
WCHAR ClassName[MAX_CLASS_NAME_LEN];
|
|
GUID ClassGuid;
|
|
LPWSTR lpGuidString = NULL, lpFullGuidString = NULL;
|
|
BOOL RebootRequired = FALSE;
|
|
HKEY hKey = INVALID_HANDLE_VALUE;
|
|
BOOL NeedtoCopyFile;
|
|
LARGE_INTEGER fullVersion;
|
|
LONG rc;
|
|
PVOID Context = NULL;
|
|
BOOL ret = FALSE; /* Return value */
|
|
|
|
TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
|
|
|
|
if (!DeviceInfoSet)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
else
|
|
Result = TRUE;
|
|
|
|
if (!Result)
|
|
{
|
|
/* One parameter is bad */
|
|
goto cleanup;
|
|
}
|
|
|
|
InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
|
|
Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
|
|
if (!Result)
|
|
goto cleanup;
|
|
|
|
if (InstallParams.FlagsEx & DI_FLAGSEX_SETFAILEDINSTALL)
|
|
{
|
|
/* Set FAILEDINSTALL in ConfigFlags registry value */
|
|
DWORD ConfigFlags, regType;
|
|
Result = SetupDiGetDeviceRegistryPropertyW(
|
|
DeviceInfoSet,
|
|
DeviceInfoData,
|
|
SPDRP_CONFIGFLAGS,
|
|
®Type,
|
|
(PBYTE)&ConfigFlags,
|
|
sizeof(ConfigFlags),
|
|
NULL);
|
|
if (!Result || regType != REG_DWORD)
|
|
{
|
|
SetLastError(ERROR_GEN_FAILURE);
|
|
goto cleanup;
|
|
}
|
|
ConfigFlags |= DNF_DISABLED;
|
|
Result = SetupDiSetDeviceRegistryPropertyW(
|
|
DeviceInfoSet,
|
|
DeviceInfoData,
|
|
SPDRP_CONFIGFLAGS,
|
|
(PBYTE)&ConfigFlags,
|
|
sizeof(ConfigFlags));
|
|
if (!Result)
|
|
{
|
|
SetLastError(ERROR_GEN_FAILURE);
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = TRUE;
|
|
goto cleanup;
|
|
}
|
|
|
|
SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
|
|
if (SelectedDriver == NULL)
|
|
{
|
|
SetLastError(ERROR_NO_DRIVER_SELECTED);
|
|
goto cleanup;
|
|
}
|
|
|
|
FileTimeToSystemTime(&SelectedDriver->Info.DriverDate, &DriverDate);
|
|
|
|
Result = SetupDiGetActualSectionToInstallW(
|
|
SelectedDriver->InfFileDetails->hInf,
|
|
SelectedDriver->Details.SectionName,
|
|
SectionName, MAX_PATH, &SectionNameLength, NULL);
|
|
if (!Result || SectionNameLength > MAX_PATH - strlenW(DotServices))
|
|
goto cleanup;
|
|
pSectionName = &SectionName[strlenW(SectionName)];
|
|
|
|
/* Get information from [Version] section */
|
|
if (!SetupDiGetINFClassW(SelectedDriver->Details.InfFileName, &ClassGuid, ClassName, MAX_CLASS_NAME_LEN, &RequiredSize))
|
|
goto cleanup;
|
|
/* Format ClassGuid to a string */
|
|
if (UuidToStringW((UUID*)&ClassGuid, &lpGuidString) != RPC_S_OK)
|
|
goto cleanup;
|
|
RequiredSize = lstrlenW(lpGuidString);
|
|
lpFullGuidString = HeapAlloc(GetProcessHeap(), 0, (RequiredSize + 3) * sizeof(WCHAR));
|
|
if (!lpFullGuidString)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto cleanup;
|
|
}
|
|
lpFullGuidString[0] = '{';
|
|
memcpy(&lpFullGuidString[1], lpGuidString, RequiredSize * sizeof(WCHAR));
|
|
lpFullGuidString[RequiredSize + 1] = '}';
|
|
lpFullGuidString[RequiredSize + 2] = '\0';
|
|
|
|
/* Copy .inf file to Inf\ directory (if needed) */
|
|
Result = InfIsFromOEMLocation(SelectedDriver->Details.InfFileName, &NeedtoCopyFile);
|
|
if (!Result)
|
|
goto cleanup;
|
|
if (NeedtoCopyFile)
|
|
{
|
|
WCHAR NewFileName[MAX_PATH];
|
|
struct InfFileDetails *newInfFileDetails;
|
|
Result = SetupCopyOEMInfW(
|
|
SelectedDriver->Details.InfFileName,
|
|
NULL,
|
|
SPOST_NONE,
|
|
SP_COPY_NOOVERWRITE,
|
|
NewFileName, MAX_PATH,
|
|
NULL,
|
|
NULL);
|
|
if (!Result)
|
|
goto cleanup;
|
|
/* Create a new struct InfFileDetails, and set it to
|
|
* SelectedDriver->InfFileDetails, to release use of
|
|
* current InfFile */
|
|
newInfFileDetails = CreateInfFileDetails(NewFileName);
|
|
if (!newInfFileDetails)
|
|
goto cleanup;
|
|
DereferenceInfFile(SelectedDriver->InfFileDetails);
|
|
SelectedDriver->InfFileDetails = newInfFileDetails;
|
|
strcpyW(SelectedDriver->Details.InfFileName, NewFileName);
|
|
}
|
|
|
|
/* Open/Create driver key information */
|
|
#if _WIN32_WINNT >= 0x502
|
|
hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE);
|
|
#else
|
|
hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
|
|
#endif
|
|
if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
|
|
hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
|
|
if (hKey == INVALID_HANDLE_VALUE)
|
|
goto cleanup;
|
|
|
|
/* Install main section */
|
|
DoAction = 0;
|
|
if (!(InstallParams.FlagsEx & DI_FLAGSEX_NO_DRVREG_MODIFY))
|
|
DoAction |= SPINST_REGISTRY;
|
|
if (!(InstallParams.Flags & DI_NOFILECOPY))
|
|
{
|
|
DoAction |= SPINST_FILES;
|
|
Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
|
|
if (!Context)
|
|
goto cleanup;
|
|
}
|
|
*pSectionName = '\0';
|
|
Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
|
|
SelectedDriver->InfFileDetails->hInf, SectionName,
|
|
DoAction, hKey, SelectedDriver->InfFileDetails->DirectoryName, SP_COPY_NEWER,
|
|
SetupDefaultQueueCallback, Context,
|
|
DeviceInfoSet, DeviceInfoData);
|
|
if (!Result)
|
|
goto cleanup;
|
|
InstallParams.Flags |= DI_NOFILECOPY;
|
|
SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
|
|
|
|
/* Write information to driver key */
|
|
*pSectionName = UNICODE_NULL;
|
|
memcpy(&fullVersion, &SelectedDriver->Info.DriverVersion, sizeof(LARGE_INTEGER));
|
|
TRACE("Write information to driver key\n");
|
|
TRACE("DriverDate : '%u-%u-%u'\n", DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
|
|
TRACE("DriverDesc : '%s'\n", debugstr_w(SelectedDriver->Info.Description));
|
|
TRACE("DriverVersion : '%u.%u.%u.%u'\n", fullVersion.HighPart >> 16, fullVersion.HighPart & 0xffff, fullVersion.LowPart >> 16, fullVersion.LowPart & 0xffff);
|
|
TRACE("InfPath : '%s'\n", debugstr_w(SelectedDriver->InfFileDetails->FileName));
|
|
TRACE("InfSection : '%s'\n", debugstr_w(SelectedDriver->Details.SectionName));
|
|
TRACE("InfSectionExt : '%s'\n", debugstr_w(&SectionName[strlenW(SelectedDriver->Details.SectionName)]));
|
|
TRACE("MatchingDeviceId: '%s'\n", debugstr_w(SelectedDriver->MatchingId));
|
|
TRACE("ProviderName : '%s'\n", debugstr_w(SelectedDriver->Info.ProviderName));
|
|
sprintfW(Buffer, L"%u-%u-%u", DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
|
|
rc = RegSetValueEx(hKey, REGSTR_DRIVER_DATE, 0, REG_SZ, (const BYTE *)Buffer, (strlenW(Buffer) + 1) * sizeof(WCHAR));
|
|
if (rc == ERROR_SUCCESS)
|
|
rc = RegSetValueEx(hKey, REGSTR_DRIVER_DATE_DATA, 0, REG_BINARY, (const BYTE *)&SelectedDriver->Info.DriverDate, sizeof(FILETIME));
|
|
if (rc == ERROR_SUCCESS)
|
|
rc = RegSetValueEx(hKey, REGSTR_VAL_DRVDESC, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (strlenW(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
|
|
if (rc == ERROR_SUCCESS)
|
|
{
|
|
sprintfW(Buffer, L"%u.%u.%u.%u", fullVersion.HighPart >> 16, fullVersion.HighPart & 0xffff, fullVersion.LowPart >> 16, fullVersion.LowPart & 0xffff);
|
|
rc = RegSetValueEx(hKey, REGSTR_DRIVER_VERSION, 0, REG_SZ, (const BYTE *)Buffer, (strlenW(Buffer) + 1) * sizeof(WCHAR));
|
|
}
|
|
if (rc == ERROR_SUCCESS)
|
|
rc = RegSetValueEx(hKey, REGSTR_VAL_INFPATH, 0, REG_SZ, (const BYTE *)SelectedDriver->InfFileDetails->FileName, (strlenW(SelectedDriver->InfFileDetails->FileName) + 1) * sizeof(WCHAR));
|
|
if (rc == ERROR_SUCCESS)
|
|
rc = RegSetValueEx(hKey, REGSTR_VAL_INFSECTION, 0, REG_SZ, (const BYTE *)SelectedDriver->Details.SectionName, (strlenW(SelectedDriver->Details.SectionName) + 1) * sizeof(WCHAR));
|
|
if (rc == ERROR_SUCCESS)
|
|
rc = RegSetValueEx(hKey, REGSTR_VAL_INFSECTIONEXT, 0, REG_SZ, (const BYTE *)&SectionName[strlenW(SelectedDriver->Details.SectionName)], (strlenW(SectionName) - strlenW(SelectedDriver->Details.SectionName) + 1) * sizeof(WCHAR));
|
|
if (rc == ERROR_SUCCESS)
|
|
rc = RegSetValueEx(hKey, REGSTR_VAL_MATCHINGDEVID, 0, REG_SZ, (const BYTE *)SelectedDriver->MatchingId, (strlenW(SelectedDriver->MatchingId) + 1) * sizeof(WCHAR));
|
|
if (rc == ERROR_SUCCESS)
|
|
rc = RegSetValueEx(hKey, REGSTR_VAL_PROVIDER_NAME, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.ProviderName, (strlenW(SelectedDriver->Info.ProviderName) + 1) * sizeof(WCHAR));
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
goto cleanup;
|
|
}
|
|
RegCloseKey(hKey);
|
|
hKey = INVALID_HANDLE_VALUE;
|
|
|
|
/* FIXME: Process .LogConfigOverride section */
|
|
|
|
/* Install .Services section */
|
|
strcpyW(pSectionName, DotServices);
|
|
Result = SetupInstallServicesFromInfSectionExW(
|
|
SelectedDriver->InfFileDetails->hInf,
|
|
SectionName,
|
|
0,
|
|
DeviceInfoSet,
|
|
DeviceInfoData,
|
|
NULL,
|
|
NULL);
|
|
if (!Result)
|
|
goto cleanup;
|
|
if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED)
|
|
RebootRequired = TRUE;
|
|
|
|
/* Open device registry key */
|
|
hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE);
|
|
if (hKey == INVALID_HANDLE_VALUE)
|
|
goto cleanup;
|
|
|
|
/* Install .HW section */
|
|
DoAction = 0;
|
|
if (!(InstallParams.FlagsEx & DI_FLAGSEX_NO_DRVREG_MODIFY))
|
|
DoAction |= SPINST_REGISTRY;
|
|
strcpyW(pSectionName, DotHW);
|
|
Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
|
|
SelectedDriver->InfFileDetails->hInf, SectionName,
|
|
DoAction, hKey, NULL, 0,
|
|
NULL, NULL,
|
|
DeviceInfoSet, DeviceInfoData);
|
|
if (!Result)
|
|
goto cleanup;
|
|
|
|
/* Write information to enum key */
|
|
TRACE("Write information to enum key\n");
|
|
TRACE("Class : '%s'\n", debugstr_w(ClassName));
|
|
TRACE("ClassGUID : '%s'\n", debugstr_w(lpFullGuidString));
|
|
TRACE("DeviceDesc : '%s'\n", debugstr_w(SelectedDriver->Info.Description));
|
|
TRACE("Mfg : '%s'\n", debugstr_w(SelectedDriver->Info.MfgName));
|
|
rc = RegSetValueEx(hKey, REGSTR_VAL_CLASS, 0, REG_SZ, (const BYTE *)ClassName, (strlenW(ClassName) + 1) * sizeof(WCHAR));
|
|
if (rc == ERROR_SUCCESS)
|
|
rc = RegSetValueEx(hKey, REGSTR_VAL_CLASSGUID, 0, REG_SZ, (const BYTE *)lpFullGuidString, (strlenW(lpFullGuidString) + 1) * sizeof(WCHAR));
|
|
if (rc == ERROR_SUCCESS)
|
|
rc = RegSetValueEx(hKey, REGSTR_VAL_DEVDESC, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (strlenW(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
|
|
if (rc == ERROR_SUCCESS)
|
|
rc = RegSetValueEx(hKey, REGSTR_VAL_MFG, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.MfgName, (strlenW(SelectedDriver->Info.MfgName) + 1) * sizeof(WCHAR));
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(rc);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Start the device */
|
|
if (!RebootRequired && !(InstallParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT | DI_DONOTCALLCONFIGMG)))
|
|
ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
|
|
else
|
|
ret = TRUE;
|
|
|
|
cleanup:
|
|
/* End of installation */
|
|
if (hKey != INVALID_HANDLE_VALUE)
|
|
RegCloseKey(hKey);
|
|
if (lpGuidString)
|
|
RpcStringFreeW(&lpGuidString);
|
|
HeapFree(GetProcessHeap(), 0, lpFullGuidString);
|
|
if (Context)
|
|
SetupTermDefaultQueueCallback(Context);
|
|
TRACE("Returning %d\n", ret);
|
|
return ret;
|
|
}
|