2005-07-01 23:26:01 +00:00
|
|
|
|
/*
|
|
|
|
|
* SetupAPI device installer
|
|
|
|
|
*
|
|
|
|
|
* Copyright 2000 Andreas Mohr for CodeWeavers
|
2005-07-06 22:47:23 +00:00
|
|
|
|
* 2005 Herv<EFBFBD> Poussineau (hpoussin@reactos.com)
|
2005-07-01 23:26:01 +00:00
|
|
|
|
*
|
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
#include "wine/port.h"
|
2005-07-04 21:54:36 +00:00
|
|
|
|
|
2005-07-01 23:26:01 +00:00
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
|
2005-10-08 15:52:14 +00:00
|
|
|
|
#include <windows.h>
|
2005-07-01 23:26:01 +00:00
|
|
|
|
#include "setupapi.h"
|
|
|
|
|
#include "wine/debug.h"
|
|
|
|
|
#include "wine/unicode.h"
|
|
|
|
|
#include "cfgmgr32.h"
|
|
|
|
|
#include "initguid.h"
|
2005-10-08 15:52:14 +00:00
|
|
|
|
#define NTOS_MODE_USER
|
|
|
|
|
#include <ndk/ntndk.h>
|
2005-07-01 23:26:01 +00:00
|
|
|
|
|
|
|
|
|
#include "setupapi_private.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
|
|
|
|
|
|
|
|
|
|
/* Unicode constants */
|
|
|
|
|
static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0};
|
|
|
|
|
static const WCHAR Class[] = {'C','l','a','s','s',0};
|
|
|
|
|
static const WCHAR ClassInstall32[] = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
|
2005-07-07 16:32:34 +00:00
|
|
|
|
static const WCHAR DeviceInstance[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
|
2005-07-01 23:26:01 +00:00
|
|
|
|
static const WCHAR NoDisplayClass[] = {'N','o','D','i','s','p','l','a','y','C','l','a','s','s',0};
|
|
|
|
|
static const WCHAR NoInstallClass[] = {'N','o','I','s','t','a','l','l','C','l','a','s','s',0};
|
|
|
|
|
static const WCHAR NoUseClass[] = {'N','o','U','s','e','C','l','a','s','s',0};
|
|
|
|
|
static const WCHAR NtExtension[] = {'.','N','T',0};
|
|
|
|
|
static const WCHAR NtPlatformExtension[] = {'.','N','T','x','8','6',0};
|
2005-07-17 15:57:41 +00:00
|
|
|
|
static const WCHAR SymbolicLink[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
|
2005-07-01 23:26:01 +00:00
|
|
|
|
static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
|
|
|
|
|
static const WCHAR WinExtension[] = {'.','W','i','n',0};
|
|
|
|
|
|
|
|
|
|
/* Registry key and value names */
|
|
|
|
|
static const WCHAR ControlClass[] = {'S','y','s','t','e','m','\\',
|
|
|
|
|
'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
|
|
|
|
|
'C','o','n','t','r','o','l','\\',
|
|
|
|
|
'C','l','a','s','s',0};
|
|
|
|
|
|
|
|
|
|
static const WCHAR DeviceClasses[] = {'S','y','s','t','e','m','\\',
|
|
|
|
|
'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
|
|
|
|
|
'C','o','n','t','r','o','l','\\',
|
|
|
|
|
'D','e','v','i','c','e','C','l','a','s','s','e','s',0};
|
|
|
|
|
|
2005-07-07 16:32:34 +00:00
|
|
|
|
static const WCHAR EnumKeyName[] = {'S','y','s','t','e','m','\\',
|
|
|
|
|
'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
|
|
|
|
|
'E','n','u','m',0};
|
|
|
|
|
|
2005-07-05 08:48:43 +00:00
|
|
|
|
|
2005-08-08 16:06:52 +00:00
|
|
|
|
/* FIXME: header mess */
|
|
|
|
|
DEFINE_GUID(GUID_NULL,
|
|
|
|
|
0x00000000L, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
|
2005-08-12 19:03:35 +00:00
|
|
|
|
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);
|
2005-08-08 16:06:52 +00:00
|
|
|
|
|
|
|
|
|
#define SETUP_DEV_INFO_SET_MAGIC 0xd00ff057
|
|
|
|
|
|
2005-08-12 19:03:35 +00:00
|
|
|
|
struct CoInstallerElement
|
|
|
|
|
{
|
|
|
|
|
LIST_ENTRY ListEntry;
|
|
|
|
|
|
2005-10-13 10:55:16 +00:00
|
|
|
|
HMODULE Module;
|
2005-08-12 19:03:35 +00:00
|
|
|
|
COINSTALLER_PROC Function;
|
|
|
|
|
BOOL DoPostProcessing;
|
|
|
|
|
PVOID PrivateData;
|
|
|
|
|
};
|
|
|
|
|
|
2005-08-09 20:12:35 +00:00
|
|
|
|
struct DeviceInterface /* Element of DeviceInfoElement.InterfaceListHead */
|
2005-07-05 08:48:43 +00:00
|
|
|
|
{
|
2005-08-08 16:06:52 +00:00
|
|
|
|
LIST_ENTRY ListEntry;
|
2005-07-05 08:48:43 +00:00
|
|
|
|
|
2005-08-09 20:12:35 +00:00
|
|
|
|
struct DeviceInfoElement* DeviceInfo;
|
2005-08-08 16:06:52 +00:00
|
|
|
|
GUID InterfaceClassGuid;
|
2005-08-09 20:12:35 +00:00
|
|
|
|
|
2005-08-08 16:06:52 +00:00
|
|
|
|
|
|
|
|
|
/* SPINT_ACTIVE : the interface is active/enabled
|
|
|
|
|
* SPINT_DEFAULT: the interface is the default interface for the device class FIXME???
|
|
|
|
|
* SPINT_REMOVED: the interface is removed
|
|
|
|
|
*/
|
|
|
|
|
DWORD Flags;
|
|
|
|
|
|
|
|
|
|
WCHAR SymbolicLink[0]; /* \\?\ACPI#PNP0501#4&2658d0a0&0#{GUID} */
|
|
|
|
|
};
|
|
|
|
|
|
2005-10-24 09:16:34 +00:00
|
|
|
|
/* We don't want to open the .inf file to read only one information in it, so keep a handle to it once it
|
|
|
|
|
* has been already loaded once. Keep also a reference counter */
|
|
|
|
|
struct InfFileDetails
|
|
|
|
|
{
|
|
|
|
|
HINF hInf;
|
|
|
|
|
ULONG References;
|
|
|
|
|
};
|
|
|
|
|
|
2005-08-08 16:06:52 +00:00
|
|
|
|
struct DriverInfoElement /* Element of DeviceInfoSet.DriverListHead and DeviceInfoElement.DriverListHead */
|
|
|
|
|
{
|
|
|
|
|
LIST_ENTRY ListEntry;
|
|
|
|
|
|
2005-08-27 14:59:22 +00:00
|
|
|
|
DWORD DriverRank;
|
2005-08-08 16:06:52 +00:00
|
|
|
|
SP_DRVINFO_DATA_V2_W Info;
|
2005-10-22 16:25:48 +00:00
|
|
|
|
SP_DRVINFO_DETAIL_DATA_W Details;
|
2005-10-13 10:55:16 +00:00
|
|
|
|
GUID ClassGuid;
|
2005-10-06 22:47:13 +00:00
|
|
|
|
LPWSTR MatchingId;
|
2005-10-24 09:16:34 +00:00
|
|
|
|
struct InfFileDetails *InfFileDetails;
|
2005-08-08 16:06:52 +00:00
|
|
|
|
};
|
2005-07-05 08:48:43 +00:00
|
|
|
|
|
2005-08-08 16:06:52 +00:00
|
|
|
|
struct DeviceInfoElement /* Element of DeviceInfoSet.ListHead */
|
2005-07-05 08:48:43 +00:00
|
|
|
|
{
|
2005-08-08 16:06:52 +00:00
|
|
|
|
LIST_ENTRY ListEntry;
|
|
|
|
|
|
2005-10-21 10:13:26 +00:00
|
|
|
|
/* Reserved Field points to a struct DriverInfoElement */
|
|
|
|
|
SP_DEVINSTALL_PARAMS_W InstallParams;
|
|
|
|
|
|
2005-08-08 16:06:52 +00:00
|
|
|
|
/* Information about devnode:
|
|
|
|
|
* - DeviceName:
|
|
|
|
|
* "Root\*PNP0501" for example.
|
|
|
|
|
* It doesn't contain the unique ID for the device
|
|
|
|
|
* (points into the Data field at the end of the structure)
|
|
|
|
|
* WARNING: no NULL char exist between DeviceName and UniqueId
|
|
|
|
|
* in Data field!
|
|
|
|
|
* - UniqueId
|
|
|
|
|
* "5&1be2108e&0" or "0000"
|
|
|
|
|
* If DICD_GENERATE_ID is specified in creation flags,
|
|
|
|
|
* this unique ID is autogenerated using 4 digits, base 10
|
|
|
|
|
* (points into the Data field at the end of the structure)
|
|
|
|
|
* - DeviceDescription
|
|
|
|
|
* String which identifies the device. Can be NULL. If not NULL,
|
|
|
|
|
* points into the Data field at the end of the structure
|
|
|
|
|
* - ClassGuid
|
|
|
|
|
* Identifies the class of this device. FIXME: can it be GUID_NULL?
|
|
|
|
|
* - CreationFlags
|
|
|
|
|
* Is a combination of:
|
|
|
|
|
* - DICD_GENERATE_ID
|
|
|
|
|
* the unique ID needs to be generated
|
|
|
|
|
* - DICD_INHERIT_CLASSDRVS
|
|
|
|
|
* inherit driver of the device info set (== same pointer)
|
|
|
|
|
*/
|
|
|
|
|
PCWSTR DeviceName;
|
|
|
|
|
PCWSTR UniqueId;
|
|
|
|
|
PCWSTR DeviceDescription;
|
|
|
|
|
GUID ClassGuid;
|
|
|
|
|
DWORD CreationFlags;
|
|
|
|
|
|
|
|
|
|
/* If CreationFlags contains DICD_INHERIT_CLASSDRVS, this list is invalid */
|
|
|
|
|
/* If the driver is not searched/detected, this list is empty */
|
|
|
|
|
LIST_ENTRY DriverListHead; /* List of struct DriverInfoElement */
|
|
|
|
|
|
|
|
|
|
/* List of interfaces implemented by this device */
|
2005-08-09 20:12:35 +00:00
|
|
|
|
LIST_ENTRY InterfaceListHead; /* List of struct DeviceInterface */
|
2005-08-08 16:06:52 +00:00
|
|
|
|
|
|
|
|
|
WCHAR Data[0];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct DeviceInfoSet /* HDEVINFO */
|
|
|
|
|
{
|
|
|
|
|
DWORD magic; /* SETUP_DEV_INFO_SET_MAGIC */
|
|
|
|
|
GUID ClassGuid; /* If != GUID_NULL, only devices of this class can be in the device info set */
|
2005-07-05 08:48:43 +00:00
|
|
|
|
HKEY HKLM; /* Local or distant HKEY_LOCAL_MACHINE registry key */
|
|
|
|
|
|
2005-10-21 10:13:26 +00:00
|
|
|
|
/* Reserved Field points to a struct DriverInfoElement */
|
|
|
|
|
SP_DEVINSTALL_PARAMS_W InstallParams;
|
2005-08-08 16:06:52 +00:00
|
|
|
|
|
|
|
|
|
/* If the driver is not searched/detected, this list is empty */
|
|
|
|
|
LIST_ENTRY DriverListHead; /* List of struct DriverInfoElement */
|
|
|
|
|
|
|
|
|
|
LIST_ENTRY ListHead; /* List of struct DeviceInfoElement */
|
|
|
|
|
};
|
2005-07-05 08:48:43 +00:00
|
|
|
|
|
2005-07-01 23:26:01 +00:00
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiBuildClassInfoList (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiBuildClassInfoList(
|
|
|
|
|
DWORD Flags,
|
|
|
|
|
LPGUID ClassGuidList,
|
|
|
|
|
DWORD ClassGuidListSize,
|
|
|
|
|
PDWORD RequiredSize)
|
|
|
|
|
{
|
|
|
|
|
TRACE("\n");
|
|
|
|
|
return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
|
|
|
|
|
ClassGuidListSize, RequiredSize,
|
|
|
|
|
NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiBuildClassInfoListExA (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiBuildClassInfoListExA(
|
|
|
|
|
DWORD Flags,
|
|
|
|
|
LPGUID ClassGuidList,
|
|
|
|
|
DWORD ClassGuidListSize,
|
|
|
|
|
PDWORD RequiredSize,
|
|
|
|
|
LPCSTR MachineName,
|
|
|
|
|
PVOID Reserved)
|
|
|
|
|
{
|
|
|
|
|
LPWSTR MachineNameW = NULL;
|
|
|
|
|
BOOL bResult;
|
|
|
|
|
|
|
|
|
|
TRACE("\n");
|
|
|
|
|
|
|
|
|
|
if (MachineName)
|
|
|
|
|
{
|
|
|
|
|
MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
|
|
|
|
|
if (MachineNameW == NULL) return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
|
|
|
|
|
ClassGuidListSize, RequiredSize,
|
|
|
|
|
MachineNameW, Reserved);
|
|
|
|
|
|
|
|
|
|
if (MachineNameW)
|
|
|
|
|
MyFree(MachineNameW);
|
|
|
|
|
|
|
|
|
|
return bResult;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiBuildClassInfoListExW (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiBuildClassInfoListExW(
|
|
|
|
|
DWORD Flags,
|
|
|
|
|
LPGUID ClassGuidList,
|
|
|
|
|
DWORD ClassGuidListSize,
|
|
|
|
|
PDWORD RequiredSize,
|
|
|
|
|
LPCWSTR MachineName,
|
|
|
|
|
PVOID Reserved)
|
|
|
|
|
{
|
2005-07-06 21:32:16 +00:00
|
|
|
|
WCHAR szKeyName[MAX_GUID_STRING_LEN + 1];
|
2005-07-01 23:26:01 +00:00
|
|
|
|
HKEY hClassesKey;
|
|
|
|
|
HKEY hClassKey;
|
|
|
|
|
DWORD dwLength;
|
|
|
|
|
DWORD dwIndex;
|
|
|
|
|
LONG lError;
|
|
|
|
|
DWORD dwGuidListIndex = 0;
|
|
|
|
|
|
|
|
|
|
TRACE("\n");
|
|
|
|
|
|
|
|
|
|
if (RequiredSize != NULL)
|
|
|
|
|
*RequiredSize = 0;
|
|
|
|
|
|
|
|
|
|
hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
|
|
|
|
|
KEY_ALL_ACCESS,
|
|
|
|
|
DIOCR_INSTALLER,
|
|
|
|
|
MachineName,
|
|
|
|
|
Reserved);
|
|
|
|
|
if (hClassesKey == INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (dwIndex = 0; ; dwIndex++)
|
|
|
|
|
{
|
2005-07-06 21:32:16 +00:00
|
|
|
|
dwLength = MAX_GUID_STRING_LEN + 1;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
lError = RegEnumKeyExW(hClassesKey,
|
|
|
|
|
dwIndex,
|
|
|
|
|
szKeyName,
|
|
|
|
|
&dwLength,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL);
|
|
|
|
|
TRACE("RegEnumKeyExW() returns %ld\n", lError);
|
|
|
|
|
if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
|
|
|
|
|
{
|
|
|
|
|
TRACE("Key name: %p\n", szKeyName);
|
|
|
|
|
|
|
|
|
|
if (RegOpenKeyExW(hClassesKey,
|
|
|
|
|
szKeyName,
|
|
|
|
|
0,
|
|
|
|
|
KEY_ALL_ACCESS,
|
|
|
|
|
&hClassKey))
|
|
|
|
|
{
|
|
|
|
|
RegCloseKey(hClassesKey);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!RegQueryValueExW(hClassKey,
|
|
|
|
|
NoUseClass,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL))
|
|
|
|
|
{
|
|
|
|
|
TRACE("'NoUseClass' value found!\n");
|
|
|
|
|
RegCloseKey(hClassKey);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((Flags & DIBCI_NOINSTALLCLASS) &&
|
|
|
|
|
(!RegQueryValueExW(hClassKey,
|
|
|
|
|
NoInstallClass,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL)))
|
|
|
|
|
{
|
|
|
|
|
TRACE("'NoInstallClass' value found!\n");
|
|
|
|
|
RegCloseKey(hClassKey);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((Flags & DIBCI_NODISPLAYCLASS) &&
|
|
|
|
|
(!RegQueryValueExW(hClassKey,
|
|
|
|
|
NoDisplayClass,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL)))
|
|
|
|
|
{
|
|
|
|
|
TRACE("'NoDisplayClass' value found!\n");
|
|
|
|
|
RegCloseKey(hClassKey);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RegCloseKey(hClassKey);
|
|
|
|
|
|
|
|
|
|
TRACE("Guid: %p\n", szKeyName);
|
|
|
|
|
if (dwGuidListIndex < ClassGuidListSize)
|
|
|
|
|
{
|
|
|
|
|
if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
|
|
|
|
|
{
|
|
|
|
|
szKeyName[37] = 0;
|
|
|
|
|
}
|
|
|
|
|
TRACE("Guid: %p\n", &szKeyName[1]);
|
|
|
|
|
|
|
|
|
|
UuidFromStringW(&szKeyName[1],
|
|
|
|
|
&ClassGuidList[dwGuidListIndex]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dwGuidListIndex++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lError != ERROR_SUCCESS)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RegCloseKey(hClassesKey);
|
|
|
|
|
|
|
|
|
|
if (RequiredSize != NULL)
|
|
|
|
|
*RequiredSize = dwGuidListIndex;
|
|
|
|
|
|
|
|
|
|
if (ClassGuidListSize < dwGuidListIndex)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiClassGuidsFromNameA (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiClassGuidsFromNameA(
|
|
|
|
|
LPCSTR ClassName,
|
|
|
|
|
LPGUID ClassGuidList,
|
|
|
|
|
DWORD ClassGuidListSize,
|
|
|
|
|
PDWORD RequiredSize)
|
|
|
|
|
{
|
|
|
|
|
return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
|
|
|
|
|
ClassGuidListSize, RequiredSize,
|
|
|
|
|
NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiClassGuidsFromNameW (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiClassGuidsFromNameW(
|
|
|
|
|
LPCWSTR ClassName,
|
|
|
|
|
LPGUID ClassGuidList,
|
|
|
|
|
DWORD ClassGuidListSize,
|
|
|
|
|
PDWORD RequiredSize)
|
|
|
|
|
{
|
|
|
|
|
return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
|
|
|
|
|
ClassGuidListSize, RequiredSize,
|
|
|
|
|
NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiClassGuidsFromNameExA (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiClassGuidsFromNameExA(
|
|
|
|
|
LPCSTR ClassName,
|
|
|
|
|
LPGUID ClassGuidList,
|
|
|
|
|
DWORD ClassGuidListSize,
|
|
|
|
|
PDWORD RequiredSize,
|
|
|
|
|
LPCSTR MachineName,
|
|
|
|
|
PVOID Reserved)
|
|
|
|
|
{
|
|
|
|
|
LPWSTR ClassNameW = NULL;
|
|
|
|
|
LPWSTR MachineNameW = NULL;
|
|
|
|
|
BOOL bResult;
|
|
|
|
|
|
2005-07-03 13:46:33 +00:00
|
|
|
|
TRACE("\n");
|
2005-07-01 23:26:01 +00:00
|
|
|
|
|
|
|
|
|
ClassNameW = MultiByteToUnicode(ClassName, CP_ACP);
|
|
|
|
|
if (ClassNameW == NULL)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (MachineNameW)
|
|
|
|
|
{
|
|
|
|
|
MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
|
|
|
|
|
if (MachineNameW == NULL)
|
|
|
|
|
{
|
|
|
|
|
MyFree(ClassNameW);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
|
|
|
|
|
ClassGuidListSize, RequiredSize,
|
|
|
|
|
MachineNameW, Reserved);
|
|
|
|
|
|
|
|
|
|
if (MachineNameW)
|
|
|
|
|
MyFree(MachineNameW);
|
|
|
|
|
|
|
|
|
|
MyFree(ClassNameW);
|
|
|
|
|
|
|
|
|
|
return bResult;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiClassGuidsFromNameExW (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiClassGuidsFromNameExW(
|
|
|
|
|
LPCWSTR ClassName,
|
|
|
|
|
LPGUID ClassGuidList,
|
|
|
|
|
DWORD ClassGuidListSize,
|
|
|
|
|
PDWORD RequiredSize,
|
|
|
|
|
LPCWSTR MachineName,
|
|
|
|
|
PVOID Reserved)
|
|
|
|
|
{
|
2005-07-06 21:32:16 +00:00
|
|
|
|
WCHAR szKeyName[MAX_GUID_STRING_LEN + 1];
|
2005-07-01 23:26:01 +00:00
|
|
|
|
WCHAR szClassName[256];
|
|
|
|
|
HKEY hClassesKey;
|
|
|
|
|
HKEY hClassKey;
|
|
|
|
|
DWORD dwLength;
|
|
|
|
|
DWORD dwIndex;
|
|
|
|
|
LONG lError;
|
|
|
|
|
DWORD dwGuidListIndex = 0;
|
|
|
|
|
|
|
|
|
|
if (RequiredSize != NULL)
|
|
|
|
|
*RequiredSize = 0;
|
|
|
|
|
|
|
|
|
|
hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
|
2005-07-05 08:48:43 +00:00
|
|
|
|
KEY_ENUMERATE_SUB_KEYS,
|
2005-07-01 23:26:01 +00:00
|
|
|
|
DIOCR_INSTALLER,
|
|
|
|
|
MachineName,
|
|
|
|
|
Reserved);
|
|
|
|
|
if (hClassesKey == INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (dwIndex = 0; ; dwIndex++)
|
|
|
|
|
{
|
2005-07-06 21:32:16 +00:00
|
|
|
|
dwLength = MAX_GUID_STRING_LEN + 1;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
lError = RegEnumKeyExW(hClassesKey,
|
|
|
|
|
dwIndex,
|
|
|
|
|
szKeyName,
|
|
|
|
|
&dwLength,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL);
|
|
|
|
|
TRACE("RegEnumKeyExW() returns %ld\n", lError);
|
|
|
|
|
if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
|
|
|
|
|
{
|
|
|
|
|
TRACE("Key name: %p\n", szKeyName);
|
|
|
|
|
|
|
|
|
|
if (RegOpenKeyExW(hClassesKey,
|
|
|
|
|
szKeyName,
|
|
|
|
|
0,
|
2005-07-05 08:48:43 +00:00
|
|
|
|
KEY_QUERY_VALUE,
|
2005-07-01 23:26:01 +00:00
|
|
|
|
&hClassKey))
|
|
|
|
|
{
|
|
|
|
|
RegCloseKey(hClassesKey);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dwLength = 256 * sizeof(WCHAR);
|
|
|
|
|
if (!RegQueryValueExW(hClassKey,
|
|
|
|
|
Class,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
(LPBYTE)szClassName,
|
|
|
|
|
&dwLength))
|
|
|
|
|
{
|
|
|
|
|
TRACE("Class name: %p\n", szClassName);
|
|
|
|
|
|
|
|
|
|
if (strcmpiW(szClassName, ClassName) == 0)
|
|
|
|
|
{
|
|
|
|
|
TRACE("Found matching class name\n");
|
|
|
|
|
|
|
|
|
|
TRACE("Guid: %p\n", szKeyName);
|
|
|
|
|
if (dwGuidListIndex < ClassGuidListSize)
|
|
|
|
|
{
|
|
|
|
|
if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
|
|
|
|
|
{
|
|
|
|
|
szKeyName[37] = 0;
|
|
|
|
|
}
|
|
|
|
|
TRACE("Guid: %p\n", &szKeyName[1]);
|
|
|
|
|
|
|
|
|
|
UuidFromStringW(&szKeyName[1],
|
|
|
|
|
&ClassGuidList[dwGuidListIndex]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dwGuidListIndex++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RegCloseKey(hClassKey);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lError != ERROR_SUCCESS)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RegCloseKey(hClassesKey);
|
|
|
|
|
|
|
|
|
|
if (RequiredSize != NULL)
|
|
|
|
|
*RequiredSize = dwGuidListIndex;
|
|
|
|
|
|
|
|
|
|
if (ClassGuidListSize < dwGuidListIndex)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiClassNameFromGuidA (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiClassNameFromGuidA(
|
|
|
|
|
const GUID* ClassGuid,
|
|
|
|
|
PSTR ClassName,
|
|
|
|
|
DWORD ClassNameSize,
|
|
|
|
|
PDWORD RequiredSize)
|
|
|
|
|
{
|
|
|
|
|
return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
|
|
|
|
|
ClassNameSize, RequiredSize,
|
|
|
|
|
NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiClassNameFromGuidW (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiClassNameFromGuidW(
|
|
|
|
|
const GUID* ClassGuid,
|
|
|
|
|
PWSTR ClassName,
|
|
|
|
|
DWORD ClassNameSize,
|
|
|
|
|
PDWORD RequiredSize)
|
|
|
|
|
{
|
|
|
|
|
return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
|
|
|
|
|
ClassNameSize, RequiredSize,
|
|
|
|
|
NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiClassNameFromGuidExA (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiClassNameFromGuidExA(
|
|
|
|
|
const GUID* ClassGuid,
|
|
|
|
|
PSTR ClassName,
|
|
|
|
|
DWORD ClassNameSize,
|
|
|
|
|
PDWORD RequiredSize,
|
|
|
|
|
PCSTR MachineName,
|
|
|
|
|
PVOID Reserved)
|
|
|
|
|
{
|
|
|
|
|
WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
|
|
|
|
|
LPWSTR MachineNameW = NULL;
|
|
|
|
|
BOOL ret;
|
|
|
|
|
|
|
|
|
|
if (MachineName)
|
|
|
|
|
MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
|
|
|
|
|
ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
|
|
|
|
|
NULL, MachineNameW, Reserved);
|
|
|
|
|
if (ret)
|
|
|
|
|
{
|
|
|
|
|
int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
|
|
|
|
|
ClassNameSize, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
if (!ClassNameSize && RequiredSize)
|
|
|
|
|
*RequiredSize = len;
|
|
|
|
|
}
|
|
|
|
|
MyFree(MachineNameW);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiClassNameFromGuidExW (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiClassNameFromGuidExW(
|
|
|
|
|
const GUID* ClassGuid,
|
|
|
|
|
PWSTR ClassName,
|
|
|
|
|
DWORD ClassNameSize,
|
|
|
|
|
PDWORD RequiredSize,
|
|
|
|
|
PCWSTR MachineName,
|
|
|
|
|
PVOID Reserved)
|
|
|
|
|
{
|
|
|
|
|
HKEY hKey;
|
|
|
|
|
DWORD dwLength;
|
2005-07-05 08:48:43 +00:00
|
|
|
|
LONG rc;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
|
|
|
|
|
hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
|
2005-07-05 08:48:43 +00:00
|
|
|
|
KEY_QUERY_VALUE,
|
2005-07-01 23:26:01 +00:00
|
|
|
|
DIOCR_INSTALLER,
|
|
|
|
|
MachineName,
|
|
|
|
|
Reserved);
|
|
|
|
|
if (hKey == INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (RequiredSize != NULL)
|
|
|
|
|
{
|
|
|
|
|
dwLength = 0;
|
2005-07-05 08:48:43 +00:00
|
|
|
|
rc = RegQueryValueExW(hKey,
|
2005-07-01 23:26:01 +00:00
|
|
|
|
Class,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
2005-07-05 08:48:43 +00:00
|
|
|
|
&dwLength);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
2005-07-01 23:26:01 +00:00
|
|
|
|
{
|
2005-07-05 08:48:43 +00:00
|
|
|
|
SetLastError(rc);
|
2005-07-01 23:26:01 +00:00
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*RequiredSize = dwLength / sizeof(WCHAR);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dwLength = ClassNameSize * sizeof(WCHAR);
|
2005-07-05 08:48:43 +00:00
|
|
|
|
rc = RegQueryValueExW(hKey,
|
2005-07-01 23:26:01 +00:00
|
|
|
|
Class,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
(LPBYTE)ClassName,
|
2005-07-05 08:48:43 +00:00
|
|
|
|
&dwLength);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
2005-07-01 23:26:01 +00:00
|
|
|
|
{
|
2005-07-05 08:48:43 +00:00
|
|
|
|
SetLastError(rc);
|
2005-07-01 23:26:01 +00:00
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiCreateDeviceInfoList (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
HDEVINFO WINAPI
|
|
|
|
|
SetupDiCreateDeviceInfoList(const GUID *ClassGuid,
|
|
|
|
|
HWND hwndParent)
|
|
|
|
|
{
|
|
|
|
|
return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
HDEVINFO WINAPI
|
|
|
|
|
SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
|
|
|
|
|
HWND hwndParent,
|
|
|
|
|
PCSTR MachineName,
|
|
|
|
|
PVOID Reserved)
|
|
|
|
|
{
|
|
|
|
|
LPWSTR MachineNameW = NULL;
|
|
|
|
|
HDEVINFO hDevInfo;
|
|
|
|
|
|
2005-08-08 16:06:52 +00:00
|
|
|
|
TRACE("%p %p %s %p\n", ClassGuid, hwndParent, MachineName, Reserved);
|
2005-07-01 23:26:01 +00:00
|
|
|
|
|
|
|
|
|
if (MachineName)
|
|
|
|
|
{
|
|
|
|
|
MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
|
|
|
|
|
if (MachineNameW == NULL)
|
|
|
|
|
return (HDEVINFO)INVALID_HANDLE_VALUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
|
|
|
|
|
MachineNameW, Reserved);
|
|
|
|
|
|
|
|
|
|
if (MachineNameW)
|
|
|
|
|
MyFree(MachineNameW);
|
|
|
|
|
|
|
|
|
|
return hDevInfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
HDEVINFO WINAPI
|
|
|
|
|
SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
|
|
|
|
|
HWND hwndParent,
|
|
|
|
|
PCWSTR MachineName,
|
|
|
|
|
PVOID Reserved)
|
|
|
|
|
{
|
2005-08-08 16:06:52 +00:00
|
|
|
|
struct DeviceInfoSet *list;
|
2005-07-06 22:47:23 +00:00
|
|
|
|
DWORD rc;
|
2005-07-05 08:48:43 +00:00
|
|
|
|
|
2005-08-08 16:06:52 +00:00
|
|
|
|
TRACE("%p %p %S %p\n", ClassGuid, hwndParent, MachineName, Reserved);
|
2005-07-05 08:48:43 +00:00
|
|
|
|
|
2005-08-08 16:06:52 +00:00
|
|
|
|
list = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInfoSet));
|
2005-07-05 08:48:43 +00:00
|
|
|
|
if (!list)
|
2005-07-06 21:32:16 +00:00
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
2005-07-05 08:48:43 +00:00
|
|
|
|
return (HDEVINFO)INVALID_HANDLE_VALUE;
|
2005-07-06 21:32:16 +00:00
|
|
|
|
}
|
2005-10-21 10:13:26 +00:00
|
|
|
|
memset(list, 0, sizeof(struct DeviceInfoSet));
|
2005-07-05 08:48:43 +00:00
|
|
|
|
|
2005-08-08 16:06:52 +00:00
|
|
|
|
list->magic = SETUP_DEV_INFO_SET_MAGIC;
|
|
|
|
|
memcpy(
|
|
|
|
|
&list->ClassGuid,
|
|
|
|
|
ClassGuid ? ClassGuid : &GUID_NULL,
|
|
|
|
|
sizeof(list->ClassGuid));
|
2005-10-21 10:13:26 +00:00
|
|
|
|
list->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
|
|
|
|
|
list->InstallParams.Flags |= DI_CLASSINSTALLPARAMS;
|
|
|
|
|
list->InstallParams.hwndParent = hwndParent;
|
2005-07-06 22:47:23 +00:00
|
|
|
|
if (MachineName)
|
2005-07-24 17:21:26 +00:00
|
|
|
|
{
|
2005-07-06 22:47:23 +00:00
|
|
|
|
rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &list->HKLM);
|
2005-07-24 17:21:26 +00:00
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(rc);
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, list);
|
|
|
|
|
return (HDEVINFO)INVALID_HANDLE_VALUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-07-06 22:47:23 +00:00
|
|
|
|
else
|
2005-07-05 08:48:43 +00:00
|
|
|
|
{
|
2005-07-24 17:21:26 +00:00
|
|
|
|
list->HKLM = HKEY_LOCAL_MACHINE;
|
2005-07-05 08:48:43 +00:00
|
|
|
|
}
|
2005-08-08 16:06:52 +00:00
|
|
|
|
InitializeListHead(&list->DriverListHead);
|
2005-07-05 08:48:43 +00:00
|
|
|
|
InitializeListHead(&list->ListHead);
|
|
|
|
|
return (HDEVINFO)list;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiEnumDeviceInfo (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiEnumDeviceInfo(
|
2005-07-05 08:48:43 +00:00
|
|
|
|
HDEVINFO DeviceInfoSet,
|
|
|
|
|
DWORD MemberIndex,
|
|
|
|
|
PSP_DEVINFO_DATA DeviceInfoData)
|
2005-07-01 23:26:01 +00:00
|
|
|
|
{
|
2005-07-05 08:48:43 +00:00
|
|
|
|
BOOL ret = FALSE;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
|
2005-07-05 08:48:43 +00:00
|
|
|
|
TRACE("%p, 0x%08lx, %p\n", DeviceInfoSet, MemberIndex, DeviceInfoData);
|
|
|
|
|
if (!DeviceInfoData)
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
2005-08-08 16:06:52 +00:00
|
|
|
|
struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
|
2005-07-05 08:48:43 +00:00
|
|
|
|
|
2005-08-08 16:06:52 +00:00
|
|
|
|
if (list->magic != SETUP_DEV_INFO_SET_MAGIC)
|
2005-07-05 08:48:43 +00:00
|
|
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
|
|
|
else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
|
2005-07-06 21:32:16 +00:00
|
|
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
2005-07-05 08:48:43 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
PLIST_ENTRY ItemList = list->ListHead.Flink;
|
2005-08-08 16:06:52 +00:00
|
|
|
|
while (ItemList != &list->ListHead && MemberIndex-- > 0)
|
2005-07-05 08:48:43 +00:00
|
|
|
|
ItemList = ItemList->Flink;
|
2005-08-08 16:06:52 +00:00
|
|
|
|
if (ItemList == &list->ListHead)
|
|
|
|
|
SetLastError(ERROR_NO_MORE_ITEMS);
|
|
|
|
|
else
|
2005-07-06 21:32:16 +00:00
|
|
|
|
{
|
2005-08-08 16:06:52 +00:00
|
|
|
|
struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)ItemList;
|
2005-07-06 21:32:16 +00:00
|
|
|
|
memcpy(&DeviceInfoData->ClassGuid,
|
2005-08-08 16:06:52 +00:00
|
|
|
|
&DevInfo->ClassGuid,
|
2005-07-06 21:32:16 +00:00
|
|
|
|
sizeof(GUID));
|
|
|
|
|
DeviceInfoData->DevInst = 0; /* FIXME */
|
2005-07-18 07:17:53 +00:00
|
|
|
|
/* Note: this appears to be dangerous, passing a private
|
|
|
|
|
* pointer a heap-allocated datum to the caller. However, the
|
|
|
|
|
* expected lifetime of the device data is the same as the
|
|
|
|
|
* HDEVINFO; once that is closed, the data are no longer valid.
|
|
|
|
|
*/
|
|
|
|
|
DeviceInfoData->Reserved = (ULONG_PTR)DevInfo;
|
2005-07-06 21:32:16 +00:00
|
|
|
|
ret = TRUE;
|
|
|
|
|
}
|
2005-07-05 08:48:43 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
|
|
|
return ret;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiGetActualSectionToInstallA (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiGetActualSectionToInstallA(
|
|
|
|
|
HINF InfHandle,
|
|
|
|
|
PCSTR InfSectionName,
|
|
|
|
|
PSTR InfSectionWithExt,
|
|
|
|
|
DWORD InfSectionWithExtSize,
|
|
|
|
|
PDWORD RequiredSize,
|
|
|
|
|
PSTR *Extension)
|
|
|
|
|
{
|
2005-07-03 13:46:33 +00:00
|
|
|
|
LPWSTR InfSectionNameW = NULL;
|
|
|
|
|
PWSTR InfSectionWithExtW = NULL;
|
|
|
|
|
PWSTR ExtensionW;
|
2005-08-01 09:23:13 +00:00
|
|
|
|
BOOL bResult = FALSE;
|
2005-07-03 13:46:33 +00:00
|
|
|
|
|
|
|
|
|
TRACE("\n");
|
|
|
|
|
|
|
|
|
|
if (InfSectionName)
|
|
|
|
|
{
|
|
|
|
|
InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
|
|
|
|
|
if (InfSectionNameW == NULL) goto end;
|
|
|
|
|
}
|
|
|
|
|
if (InfSectionWithExt)
|
|
|
|
|
{
|
|
|
|
|
InfSectionWithExtW = HeapAlloc(GetProcessHeap(), 0, InfSectionWithExtSize * sizeof(WCHAR));
|
|
|
|
|
if (InfSectionWithExtW == NULL) goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bResult = SetupDiGetActualSectionToInstallW(InfHandle, InfSectionNameW,
|
|
|
|
|
InfSectionWithExt ? InfSectionNameW : NULL,
|
|
|
|
|
InfSectionWithExtSize, RequiredSize,
|
|
|
|
|
Extension ? &ExtensionW : NULL);
|
|
|
|
|
|
2005-07-05 08:48:43 +00:00
|
|
|
|
if (bResult && InfSectionWithExt)
|
2005-07-03 13:46:33 +00:00
|
|
|
|
{
|
2005-07-05 08:48:43 +00:00
|
|
|
|
bResult = WideCharToMultiByte(CP_ACP, 0, InfSectionWithExtW, -1, InfSectionWithExt,
|
|
|
|
|
InfSectionWithExtSize, NULL, NULL) != 0;
|
2005-07-03 13:46:33 +00:00
|
|
|
|
}
|
2005-07-05 08:48:43 +00:00
|
|
|
|
if (bResult && Extension)
|
2005-07-03 13:46:33 +00:00
|
|
|
|
{
|
|
|
|
|
if (ExtensionW == NULL)
|
|
|
|
|
*Extension = NULL;
|
|
|
|
|
else
|
|
|
|
|
*Extension = &InfSectionWithExt[ExtensionW - InfSectionWithExtW];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
if (InfSectionNameW) MyFree(InfSectionNameW);
|
|
|
|
|
if (InfSectionWithExtW) HeapFree(GetProcessHeap(), 0, InfSectionWithExtW);
|
|
|
|
|
|
|
|
|
|
return bResult;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiGetActualSectionToInstallW (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiGetActualSectionToInstallW(
|
|
|
|
|
HINF InfHandle,
|
|
|
|
|
PCWSTR InfSectionName,
|
|
|
|
|
PWSTR InfSectionWithExt,
|
|
|
|
|
DWORD InfSectionWithExtSize,
|
|
|
|
|
PDWORD RequiredSize,
|
|
|
|
|
PWSTR *Extension)
|
|
|
|
|
{
|
|
|
|
|
WCHAR szBuffer[MAX_PATH];
|
|
|
|
|
DWORD dwLength;
|
|
|
|
|
DWORD dwFullLength;
|
|
|
|
|
LONG lLineCount = -1;
|
|
|
|
|
|
|
|
|
|
lstrcpyW(szBuffer, InfSectionName);
|
|
|
|
|
dwLength = lstrlenW(szBuffer);
|
|
|
|
|
|
|
|
|
|
if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
|
|
|
|
|
{
|
|
|
|
|
/* Test section name with '.NTx86' extension */
|
|
|
|
|
lstrcpyW(&szBuffer[dwLength], NtPlatformExtension);
|
|
|
|
|
lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
|
|
|
|
|
|
|
|
|
|
if (lLineCount == -1)
|
|
|
|
|
{
|
|
|
|
|
/* Test section name with '.NT' extension */
|
|
|
|
|
lstrcpyW(&szBuffer[dwLength], NtExtension);
|
|
|
|
|
lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Test section name with '.Win' extension */
|
|
|
|
|
lstrcpyW(&szBuffer[dwLength], WinExtension);
|
|
|
|
|
lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lLineCount == -1)
|
|
|
|
|
{
|
|
|
|
|
/* Test section name without extension */
|
|
|
|
|
szBuffer[dwLength] = 0;
|
|
|
|
|
lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lLineCount == -1)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dwFullLength = lstrlenW(szBuffer);
|
|
|
|
|
|
|
|
|
|
if (InfSectionWithExt != NULL && InfSectionWithExtSize != 0)
|
|
|
|
|
{
|
|
|
|
|
if (InfSectionWithExtSize < (dwFullLength + 1))
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lstrcpyW(InfSectionWithExt, szBuffer);
|
|
|
|
|
if (Extension != NULL)
|
|
|
|
|
{
|
|
|
|
|
*Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (RequiredSize != NULL)
|
|
|
|
|
{
|
|
|
|
|
*RequiredSize = dwFullLength + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiGetClassDescriptionA (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiGetClassDescriptionA(
|
|
|
|
|
const GUID* ClassGuid,
|
|
|
|
|
PSTR ClassDescription,
|
|
|
|
|
DWORD ClassDescriptionSize,
|
|
|
|
|
PDWORD RequiredSize)
|
|
|
|
|
{
|
|
|
|
|
return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
|
|
|
|
|
ClassDescriptionSize,
|
|
|
|
|
RequiredSize, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiGetClassDescriptionW (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiGetClassDescriptionW(
|
|
|
|
|
const GUID* ClassGuid,
|
|
|
|
|
PWSTR ClassDescription,
|
|
|
|
|
DWORD ClassDescriptionSize,
|
|
|
|
|
PDWORD RequiredSize)
|
|
|
|
|
{
|
|
|
|
|
return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
|
|
|
|
|
ClassDescriptionSize,
|
|
|
|
|
RequiredSize, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiGetClassDescriptionExA (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiGetClassDescriptionExA(
|
|
|
|
|
const GUID* ClassGuid,
|
|
|
|
|
PSTR ClassDescription,
|
|
|
|
|
DWORD ClassDescriptionSize,
|
|
|
|
|
PDWORD RequiredSize,
|
|
|
|
|
PCSTR MachineName,
|
|
|
|
|
PVOID Reserved)
|
|
|
|
|
{
|
2005-07-05 13:15:10 +00:00
|
|
|
|
PWCHAR ClassDescriptionW;
|
|
|
|
|
LPWSTR MachineNameW = NULL;
|
|
|
|
|
BOOL ret;
|
|
|
|
|
|
|
|
|
|
TRACE("\n");
|
|
|
|
|
if (ClassDescriptionSize > 0)
|
|
|
|
|
{
|
|
|
|
|
ClassDescriptionW = HeapAlloc(GetProcessHeap(), 0, ClassDescriptionSize * sizeof(WCHAR));
|
|
|
|
|
if (!ClassDescriptionW)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
|
ret = FALSE;
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-08-01 09:23:13 +00:00
|
|
|
|
else
|
|
|
|
|
ClassDescriptionW = NULL;
|
2005-07-05 13:15:10 +00:00
|
|
|
|
|
|
|
|
|
if (MachineName)
|
|
|
|
|
{
|
|
|
|
|
MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
|
|
|
|
|
if (!MachineNameW)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
|
ret = FALSE;
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = SetupDiGetClassDescriptionExW(ClassGuid, ClassDescriptionW, ClassDescriptionSize * sizeof(WCHAR),
|
|
|
|
|
NULL, MachineNameW, Reserved);
|
|
|
|
|
if (ret)
|
|
|
|
|
{
|
|
|
|
|
int len = WideCharToMultiByte(CP_ACP, 0, ClassDescriptionW, -1, ClassDescription,
|
|
|
|
|
ClassDescriptionSize, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
if (!ClassDescriptionSize && RequiredSize)
|
|
|
|
|
*RequiredSize = len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, ClassDescriptionW);
|
|
|
|
|
MyFree(MachineNameW);
|
|
|
|
|
return ret;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiGetClassDescriptionExW (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiGetClassDescriptionExW(
|
|
|
|
|
const GUID* ClassGuid,
|
|
|
|
|
PWSTR ClassDescription,
|
|
|
|
|
DWORD ClassDescriptionSize,
|
|
|
|
|
PDWORD RequiredSize,
|
|
|
|
|
PCWSTR MachineName,
|
|
|
|
|
PVOID Reserved)
|
|
|
|
|
{
|
|
|
|
|
HKEY hKey;
|
|
|
|
|
DWORD dwLength;
|
|
|
|
|
|
|
|
|
|
hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
|
|
|
|
|
KEY_ALL_ACCESS,
|
|
|
|
|
DIOCR_INSTALLER,
|
|
|
|
|
MachineName,
|
|
|
|
|
Reserved);
|
|
|
|
|
if (hKey == INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
|
|
|
|
WARN("SetupDiOpenClassRegKeyExW() failed (Error %lu)\n", GetLastError());
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (RequiredSize != NULL)
|
|
|
|
|
{
|
|
|
|
|
dwLength = 0;
|
|
|
|
|
if (RegQueryValueExW(hKey,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
&dwLength))
|
|
|
|
|
{
|
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*RequiredSize = dwLength / sizeof(WCHAR);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dwLength = ClassDescriptionSize * sizeof(WCHAR);
|
|
|
|
|
if (RegQueryValueExW(hKey,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
(LPBYTE)ClassDescription,
|
|
|
|
|
&dwLength))
|
|
|
|
|
{
|
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiGetClassDevsA (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
HDEVINFO WINAPI SetupDiGetClassDevsA(
|
|
|
|
|
CONST GUID *class,
|
|
|
|
|
LPCSTR enumstr,
|
|
|
|
|
HWND parent,
|
|
|
|
|
DWORD flags)
|
2005-07-05 12:59:14 +00:00
|
|
|
|
{
|
|
|
|
|
return SetupDiGetClassDevsExA(class, enumstr, parent,
|
2005-07-05 14:00:33 +00:00
|
|
|
|
flags, NULL, NULL, NULL);
|
2005-07-05 12:59:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiGetClassDevsW (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
HDEVINFO WINAPI SetupDiGetClassDevsW(
|
|
|
|
|
CONST GUID *class,
|
|
|
|
|
LPCWSTR enumstr,
|
|
|
|
|
HWND parent,
|
|
|
|
|
DWORD flags)
|
|
|
|
|
{
|
|
|
|
|
return SetupDiGetClassDevsExW(class, enumstr, parent,
|
2005-07-05 14:00:33 +00:00
|
|
|
|
flags, NULL, NULL, NULL);
|
2005-07-05 12:59:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiGetClassDevsExA (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
HDEVINFO WINAPI SetupDiGetClassDevsExA(
|
|
|
|
|
CONST GUID *class,
|
|
|
|
|
LPCSTR enumstr,
|
|
|
|
|
HWND parent,
|
|
|
|
|
DWORD flags,
|
2005-07-05 14:00:33 +00:00
|
|
|
|
HDEVINFO deviceset,
|
2005-07-05 12:59:14 +00:00
|
|
|
|
LPCSTR machine,
|
|
|
|
|
PVOID reserved)
|
2005-07-01 23:26:01 +00:00
|
|
|
|
{
|
|
|
|
|
HDEVINFO ret;
|
|
|
|
|
LPWSTR enumstrW = NULL;
|
2005-07-05 12:59:14 +00:00
|
|
|
|
LPWSTR machineW = NULL;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
|
|
|
|
|
if (enumstr)
|
|
|
|
|
{
|
|
|
|
|
int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
|
|
|
|
|
enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
|
|
|
|
if (!enumstrW)
|
|
|
|
|
{
|
|
|
|
|
ret = (HDEVINFO)INVALID_HANDLE_VALUE;
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
|
|
|
|
|
}
|
2005-07-05 12:59:14 +00:00
|
|
|
|
if (machine)
|
|
|
|
|
{
|
|
|
|
|
int len = MultiByteToWideChar(CP_ACP, 0, machine, -1, NULL, 0);
|
|
|
|
|
machineW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
|
|
|
|
if (!machineW)
|
|
|
|
|
{
|
|
|
|
|
ret = (HDEVINFO)INVALID_HANDLE_VALUE;
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
MultiByteToWideChar(CP_ACP, 0, machine, -1, machineW, len);
|
|
|
|
|
}
|
2005-07-05 14:00:33 +00:00
|
|
|
|
ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset, machineW, reserved);
|
2005-07-01 23:26:01 +00:00
|
|
|
|
|
|
|
|
|
end:
|
2005-07-05 12:59:14 +00:00
|
|
|
|
HeapFree(GetProcessHeap(), 0, enumstrW);
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, machineW);
|
2005-07-01 23:26:01 +00:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-09 16:13:50 +00:00
|
|
|
|
static BOOL
|
|
|
|
|
CreateDeviceInfoElement(
|
|
|
|
|
IN LPCWSTR InstancePath,
|
2005-10-13 10:55:16 +00:00
|
|
|
|
IN LPCGUID pClassGuid,
|
2005-08-09 16:13:50 +00:00
|
|
|
|
OUT struct DeviceInfoElement **pDeviceInfo)
|
|
|
|
|
{
|
2005-10-21 10:13:26 +00:00
|
|
|
|
DWORD size;
|
2005-08-09 16:13:50 +00:00
|
|
|
|
struct DeviceInfoElement *deviceInfo;
|
|
|
|
|
|
|
|
|
|
*pDeviceInfo = NULL;
|
|
|
|
|
|
2005-10-21 10:13:26 +00:00
|
|
|
|
size = sizeof(struct DeviceInfoElement) + (wcslen(InstancePath) + 1) * sizeof(WCHAR);
|
|
|
|
|
deviceInfo = HeapAlloc(GetProcessHeap(), 0, size);
|
2005-08-09 16:13:50 +00:00
|
|
|
|
if (!deviceInfo)
|
|
|
|
|
{
|
2005-08-09 20:12:35 +00:00
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
2005-08-09 16:13:50 +00:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2005-10-21 10:13:26 +00:00
|
|
|
|
memset(deviceInfo, 0, size);
|
|
|
|
|
deviceInfo->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
|
2005-08-09 16:13:50 +00:00
|
|
|
|
wcscpy(deviceInfo->Data, InstancePath);
|
|
|
|
|
deviceInfo->DeviceName = deviceInfo->Data;
|
|
|
|
|
deviceInfo->UniqueId = wcsrchr(deviceInfo->Data, '\\');
|
|
|
|
|
deviceInfo->DeviceDescription = NULL;
|
|
|
|
|
memcpy(&deviceInfo->ClassGuid, pClassGuid, sizeof(GUID));
|
|
|
|
|
deviceInfo->CreationFlags = 0;
|
|
|
|
|
InitializeListHead(&deviceInfo->DriverListHead);
|
2005-08-09 20:12:35 +00:00
|
|
|
|
InitializeListHead(&deviceInfo->InterfaceListHead);
|
2005-08-09 16:13:50 +00:00
|
|
|
|
|
|
|
|
|
*pDeviceInfo = deviceInfo;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-09 20:12:35 +00:00
|
|
|
|
static BOOL
|
|
|
|
|
CreateDeviceInterface(
|
|
|
|
|
IN struct DeviceInfoElement* deviceInfo,
|
|
|
|
|
IN LPCWSTR SymbolicLink,
|
|
|
|
|
IN LPCGUID pInterfaceGuid,
|
|
|
|
|
OUT struct DeviceInterface **pDeviceInterface)
|
|
|
|
|
{
|
|
|
|
|
struct DeviceInterface *deviceInterface;
|
|
|
|
|
|
|
|
|
|
*pDeviceInterface = NULL;
|
|
|
|
|
|
|
|
|
|
deviceInterface = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInterface) + (wcslen(SymbolicLink) + 1) * sizeof(WCHAR));
|
|
|
|
|
if (!deviceInterface)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
deviceInterface->DeviceInfo = deviceInfo;
|
|
|
|
|
wcscpy(deviceInterface->SymbolicLink, SymbolicLink);
|
|
|
|
|
deviceInterface->Flags = 0; /* FIXME */
|
|
|
|
|
memcpy(&deviceInterface->InterfaceClassGuid, pInterfaceGuid, sizeof(GUID));
|
|
|
|
|
|
|
|
|
|
*pDeviceInterface = deviceInterface;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2005-07-18 07:17:53 +00:00
|
|
|
|
static LONG SETUP_CreateDevListFromEnumerator(
|
2005-08-08 16:06:52 +00:00
|
|
|
|
struct DeviceInfoSet *list,
|
2005-07-18 07:17:53 +00:00
|
|
|
|
LPCGUID pClassGuid OPTIONAL,
|
|
|
|
|
LPCWSTR Enumerator,
|
|
|
|
|
HKEY hEnumeratorKey) /* handle to Enumerator registry key */
|
2005-07-05 08:48:43 +00:00
|
|
|
|
{
|
2005-07-18 07:17:53 +00:00
|
|
|
|
HKEY hDeviceIdKey, hInstanceIdKey;
|
|
|
|
|
WCHAR KeyBuffer[MAX_PATH];
|
|
|
|
|
WCHAR InstancePath[MAX_PATH];
|
|
|
|
|
LPWSTR pEndOfInstancePath; /* Pointer into InstancePath buffer */
|
2005-08-08 16:06:52 +00:00
|
|
|
|
struct DeviceInfoElement *deviceInfo;
|
2005-07-18 07:17:53 +00:00
|
|
|
|
DWORD i = 0, j;
|
|
|
|
|
DWORD dwLength, dwRegType;
|
|
|
|
|
DWORD rc;
|
|
|
|
|
|
|
|
|
|
/* Enumerate device IDs (subkeys of hEnumeratorKey) */
|
|
|
|
|
while (TRUE)
|
|
|
|
|
{
|
|
|
|
|
dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
|
|
|
|
|
rc = RegEnumKeyExW(hEnumeratorKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
|
|
|
|
|
if (rc == ERROR_NO_MORE_ITEMS)
|
|
|
|
|
break;
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
return rc;
|
|
|
|
|
i++;
|
|
|
|
|
|
|
|
|
|
/* Open device id sub key */
|
|
|
|
|
rc = RegOpenKeyExW(hEnumeratorKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hDeviceIdKey);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
return rc;
|
|
|
|
|
wcscpy(InstancePath, Enumerator);
|
|
|
|
|
wcscat(InstancePath, L"\\");
|
|
|
|
|
wcscat(InstancePath, KeyBuffer);
|
|
|
|
|
wcscat(InstancePath, L"\\");
|
|
|
|
|
pEndOfInstancePath = &InstancePath[wcslen(InstancePath)];
|
|
|
|
|
|
|
|
|
|
/* Enumerate instance IDs (subkeys of hDeviceIdKey) */
|
|
|
|
|
j = 0;
|
|
|
|
|
while (TRUE)
|
|
|
|
|
{
|
2005-08-12 19:00:04 +00:00
|
|
|
|
GUID KeyGuid;
|
|
|
|
|
|
2005-07-18 07:17:53 +00:00
|
|
|
|
dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
|
|
|
|
|
rc = RegEnumKeyExW(hDeviceIdKey, j, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
|
|
|
|
|
if (rc == ERROR_NO_MORE_ITEMS)
|
|
|
|
|
break;
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
RegCloseKey(hDeviceIdKey);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
j++;
|
|
|
|
|
|
|
|
|
|
/* Open instance id sub key */
|
|
|
|
|
rc = RegOpenKeyExW(hDeviceIdKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hInstanceIdKey);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
RegCloseKey(hDeviceIdKey);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
2005-07-24 17:21:26 +00:00
|
|
|
|
*pEndOfInstancePath = '\0';
|
2005-07-18 07:17:53 +00:00
|
|
|
|
wcscat(InstancePath, KeyBuffer);
|
|
|
|
|
|
|
|
|
|
/* Read ClassGUID value */
|
2005-07-24 17:21:26 +00:00
|
|
|
|
dwLength = sizeof(KeyBuffer) - sizeof(WCHAR);
|
2005-07-18 07:17:53 +00:00
|
|
|
|
rc = RegQueryValueExW(hInstanceIdKey, ClassGUID, NULL, &dwRegType, (LPBYTE)KeyBuffer, &dwLength);
|
|
|
|
|
RegCloseKey(hInstanceIdKey);
|
|
|
|
|
if (rc == ERROR_FILE_NOT_FOUND)
|
|
|
|
|
{
|
2005-07-24 17:21:26 +00:00
|
|
|
|
if (pClassGuid)
|
2005-07-18 07:17:53 +00:00
|
|
|
|
/* Skip this bad entry as we can't verify it */
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
RegCloseKey(hDeviceIdKey);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
else if (dwRegType != REG_SZ)
|
|
|
|
|
{
|
|
|
|
|
RegCloseKey(hDeviceIdKey);
|
|
|
|
|
return ERROR_GEN_FAILURE;
|
|
|
|
|
}
|
2005-08-12 19:00:04 +00:00
|
|
|
|
|
|
|
|
|
KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */
|
|
|
|
|
if (UuidFromStringW(&KeyBuffer[1], &KeyGuid) != RPC_S_OK)
|
2005-07-18 07:17:53 +00:00
|
|
|
|
{
|
2005-08-12 19:00:04 +00:00
|
|
|
|
RegCloseKey(hDeviceIdKey);
|
|
|
|
|
return GetLastError();
|
|
|
|
|
}
|
|
|
|
|
if (pClassGuid && !IsEqualIID(&KeyGuid, pClassGuid))
|
|
|
|
|
{
|
|
|
|
|
/* Skip this entry as it is not the right device class */
|
|
|
|
|
continue;
|
2005-07-18 07:17:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add the entry to the list */
|
2005-08-12 19:00:04 +00:00
|
|
|
|
if (!CreateDeviceInfoElement(InstancePath, &KeyGuid, &deviceInfo))
|
2005-07-18 07:17:53 +00:00
|
|
|
|
{
|
|
|
|
|
RegCloseKey(hDeviceIdKey);
|
2005-08-09 16:13:50 +00:00
|
|
|
|
return GetLastError();
|
2005-07-18 07:17:53 +00:00
|
|
|
|
}
|
2005-08-08 16:06:52 +00:00
|
|
|
|
TRACE("Adding '%S' to device info set %p\n", InstancePath, list);
|
|
|
|
|
InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
|
2005-07-18 07:17:53 +00:00
|
|
|
|
}
|
|
|
|
|
RegCloseKey(hDeviceIdKey);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static LONG SETUP_CreateDevList(
|
2005-08-08 16:06:52 +00:00
|
|
|
|
struct DeviceInfoSet *list,
|
2005-07-18 07:17:53 +00:00
|
|
|
|
PCWSTR MachineName OPTIONAL,
|
|
|
|
|
LPGUID class OPTIONAL,
|
|
|
|
|
PCWSTR Enumerator OPTIONAL)
|
|
|
|
|
{
|
|
|
|
|
HKEY HKLM, hEnumKey, hEnumeratorKey;
|
|
|
|
|
WCHAR KeyBuffer[MAX_PATH];
|
2005-07-05 08:48:43 +00:00
|
|
|
|
DWORD i;
|
2005-07-18 07:17:53 +00:00
|
|
|
|
DWORD dwLength;
|
|
|
|
|
DWORD rc;
|
2005-07-05 08:48:43 +00:00
|
|
|
|
|
2005-07-24 17:21:26 +00:00
|
|
|
|
if (IsEqualIID(class, &GUID_NULL))
|
2005-07-18 07:17:53 +00:00
|
|
|
|
class = NULL;
|
2005-07-06 21:32:16 +00:00
|
|
|
|
|
2005-07-18 07:17:53 +00:00
|
|
|
|
/* Open Enum key */
|
|
|
|
|
if (MachineName != NULL)
|
2005-07-05 08:48:43 +00:00
|
|
|
|
{
|
2005-07-18 07:17:53 +00:00
|
|
|
|
rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
return rc;
|
2005-07-05 08:48:43 +00:00
|
|
|
|
}
|
2005-07-18 07:17:53 +00:00
|
|
|
|
else
|
|
|
|
|
HKLM = HKEY_LOCAL_MACHINE;
|
|
|
|
|
|
|
|
|
|
rc = RegOpenKeyExW(HKLM,
|
|
|
|
|
EnumKeyName,
|
|
|
|
|
0,
|
|
|
|
|
KEY_ENUMERATE_SUB_KEYS,
|
|
|
|
|
&hEnumKey);
|
|
|
|
|
if (MachineName != NULL) RegCloseKey(HKLM);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
return rc;
|
2005-07-05 08:48:43 +00:00
|
|
|
|
|
2005-07-18 07:17:53 +00:00
|
|
|
|
/* If enumerator is provided, call directly SETUP_CreateDevListFromEnumerator.
|
|
|
|
|
* Else, enumerate all enumerators all call SETUP_CreateDevListFromEnumerator
|
|
|
|
|
* for each one.
|
|
|
|
|
*/
|
|
|
|
|
if (Enumerator)
|
2005-07-05 08:48:43 +00:00
|
|
|
|
{
|
2005-07-18 07:17:53 +00:00
|
|
|
|
rc = RegOpenKeyExW(
|
|
|
|
|
hEnumKey,
|
|
|
|
|
Enumerator,
|
|
|
|
|
0,
|
|
|
|
|
KEY_ENUMERATE_SUB_KEYS,
|
|
|
|
|
&hEnumeratorKey);
|
|
|
|
|
RegCloseKey(hEnumKey);
|
2005-07-05 08:48:43 +00:00
|
|
|
|
if (rc != ERROR_SUCCESS)
|
2005-07-18 07:17:53 +00:00
|
|
|
|
return rc;
|
2005-07-24 17:21:26 +00:00
|
|
|
|
rc = SETUP_CreateDevListFromEnumerator(list, class, Enumerator, hEnumeratorKey);
|
2005-07-18 07:17:53 +00:00
|
|
|
|
RegCloseKey(hEnumeratorKey);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Enumerate enumerators */
|
|
|
|
|
i = 0;
|
|
|
|
|
while (TRUE)
|
2005-07-05 08:48:43 +00:00
|
|
|
|
{
|
2005-07-18 07:17:53 +00:00
|
|
|
|
dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
|
|
|
|
|
rc = RegEnumKeyExW(hEnumKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
|
|
|
|
|
if (rc == ERROR_NO_MORE_ITEMS)
|
|
|
|
|
break;
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
RegCloseKey(hEnumKey);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
i++;
|
|
|
|
|
|
|
|
|
|
/* Open sub key */
|
|
|
|
|
rc = RegOpenKeyExW(hEnumKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hEnumeratorKey);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
RegCloseKey(hEnumKey);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Call SETUP_CreateDevListFromEnumerator */
|
2005-07-24 17:21:26 +00:00
|
|
|
|
rc = SETUP_CreateDevListFromEnumerator(list, class, KeyBuffer, hEnumeratorKey);
|
2005-07-18 07:17:53 +00:00
|
|
|
|
RegCloseKey(hEnumeratorKey);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
RegCloseKey(hEnumKey);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
2005-07-05 08:48:43 +00:00
|
|
|
|
}
|
2005-07-18 07:17:53 +00:00
|
|
|
|
RegCloseKey(hEnumKey);
|
|
|
|
|
return ERROR_SUCCESS;
|
2005-07-05 08:48:43 +00:00
|
|
|
|
}
|
2005-07-06 21:32:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-08-09 20:12:35 +00:00
|
|
|
|
#ifndef __REACTOS__
|
2005-07-07 16:32:34 +00:00
|
|
|
|
static LONG SETUP_CreateSerialDeviceList(
|
2005-08-08 16:06:52 +00:00
|
|
|
|
struct DeviceInfoSet *list,
|
2005-07-07 16:32:34 +00:00
|
|
|
|
PCWSTR MachineName,
|
|
|
|
|
LPGUID InterfaceGuid,
|
|
|
|
|
PCWSTR DeviceInstanceW)
|
|
|
|
|
{
|
|
|
|
|
static const size_t initialSize = 100;
|
|
|
|
|
size_t size;
|
|
|
|
|
WCHAR buf[initialSize];
|
|
|
|
|
LPWSTR devices;
|
|
|
|
|
static const WCHAR devicePrefixW[] = { 'C','O','M',0 };
|
|
|
|
|
LPWSTR ptr;
|
2005-08-09 20:12:35 +00:00
|
|
|
|
struct DeviceInfoElement *deviceInfo;
|
2005-07-07 16:32:34 +00:00
|
|
|
|
|
|
|
|
|
if (MachineName)
|
|
|
|
|
WARN("'MachineName' is ignored on Wine!\n");
|
2005-07-17 15:57:41 +00:00
|
|
|
|
if (DeviceInstanceW)
|
2005-07-07 16:32:34 +00:00
|
|
|
|
WARN("'DeviceInstanceW' can't be set on Wine!\n");
|
|
|
|
|
|
|
|
|
|
devices = buf;
|
|
|
|
|
size = initialSize;
|
|
|
|
|
while (TRUE)
|
|
|
|
|
{
|
|
|
|
|
if (QueryDosDeviceW(NULL, devices, size) != 0)
|
|
|
|
|
break;
|
|
|
|
|
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
|
|
|
{
|
|
|
|
|
size *= 2;
|
|
|
|
|
if (devices != buf)
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, devices);
|
|
|
|
|
devices = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
|
|
|
|
|
if (!devices)
|
2005-08-09 20:12:35 +00:00
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
2005-07-24 17:21:26 +00:00
|
|
|
|
*devices = '\0';
|
2005-07-07 16:32:34 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (devices != buf)
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, devices);
|
|
|
|
|
return GetLastError();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 'devices' is a MULTI_SZ string */
|
|
|
|
|
for (ptr = devices; *ptr; ptr += strlenW(ptr) + 1)
|
|
|
|
|
{
|
|
|
|
|
if (strncmpW(devicePrefixW, ptr, sizeof(devicePrefixW) / sizeof(devicePrefixW[0]) - 1) == 0)
|
|
|
|
|
{
|
|
|
|
|
/* We have found a device */
|
2005-08-09 20:12:35 +00:00
|
|
|
|
struct DeviceInterface *interfaceInfo;
|
2005-07-07 16:32:34 +00:00
|
|
|
|
TRACE("Adding %s to list\n", debugstr_w(ptr));
|
2005-08-09 20:12:35 +00:00
|
|
|
|
/* Step 1. Create a device info element */
|
|
|
|
|
if (!CreateDeviceInfoElement(ptr, &GUID_SERENUM_BUS_ENUMERATOR, &deviceInfo))
|
2005-07-07 16:32:34 +00:00
|
|
|
|
{
|
|
|
|
|
if (devices != buf)
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, devices);
|
2005-08-09 20:12:35 +00:00
|
|
|
|
return GetLastError();
|
2005-07-07 16:32:34 +00:00
|
|
|
|
}
|
2005-08-09 20:12:35 +00:00
|
|
|
|
InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
|
|
|
|
|
|
|
|
|
|
/* Step 2. Create an interface list for this element */
|
|
|
|
|
if (!CreateDeviceInterface(deviceInfo, ptr, InterfaceGuid, &interfaceInfo))
|
|
|
|
|
{
|
|
|
|
|
if (devices != buf)
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, devices);
|
|
|
|
|
return GetLastError();
|
|
|
|
|
}
|
|
|
|
|
InsertTailList(&deviceInfo->InterfaceListHead, &interfaceInfo->ListEntry);
|
2005-07-07 16:32:34 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (devices != buf)
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, devices);
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-09 20:12:35 +00:00
|
|
|
|
#else /* __REACTOS__ */
|
2005-07-07 16:32:34 +00:00
|
|
|
|
|
2005-07-06 21:32:16 +00:00
|
|
|
|
static LONG SETUP_CreateInterfaceList(
|
2005-08-08 16:06:52 +00:00
|
|
|
|
struct DeviceInfoSet *list,
|
2005-07-06 21:32:16 +00:00
|
|
|
|
PCWSTR MachineName,
|
|
|
|
|
LPGUID InterfaceGuid,
|
2005-07-07 16:32:34 +00:00
|
|
|
|
PCWSTR DeviceInstanceW /* OPTIONAL */)
|
2005-07-06 21:32:16 +00:00
|
|
|
|
{
|
2005-07-17 15:57:41 +00:00
|
|
|
|
HKEY hInterfaceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
|
|
|
|
|
HKEY hDeviceInstanceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath} */
|
|
|
|
|
HKEY hReferenceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath}\#{ReferenceString} */
|
|
|
|
|
HKEY hEnumKey; /* HKLM\SYSTEM\CurrentControlSet\Enum */
|
|
|
|
|
HKEY hKey; /* HKLM\SYSTEM\CurrentControlSet\Enum\{Instance\Path} */
|
2005-07-06 21:32:16 +00:00
|
|
|
|
LONG rc;
|
|
|
|
|
WCHAR KeyBuffer[max(MAX_PATH, MAX_GUID_STRING_LEN) + 1];
|
2005-07-17 15:57:41 +00:00
|
|
|
|
PWSTR InstancePath;
|
|
|
|
|
DWORD i, j;
|
|
|
|
|
DWORD dwLength, dwInstancePathLength;
|
|
|
|
|
DWORD dwRegType;
|
|
|
|
|
GUID ClassGuid;
|
2005-08-09 20:12:35 +00:00
|
|
|
|
struct DeviceInfoElement *deviceInfo;
|
2005-07-06 21:32:16 +00:00
|
|
|
|
|
|
|
|
|
/* Open registry key related to this interface */
|
|
|
|
|
hInterfaceKey = SetupDiOpenClassRegKeyExW(InterfaceGuid, KEY_ENUMERATE_SUB_KEYS, DIOCR_INTERFACE, MachineName, NULL);
|
|
|
|
|
if (hInterfaceKey == INVALID_HANDLE_VALUE)
|
|
|
|
|
return GetLastError();
|
|
|
|
|
|
2005-07-17 15:57:41 +00:00
|
|
|
|
/* Enumerate sub keys of hInterfaceKey */
|
2005-07-06 21:32:16 +00:00
|
|
|
|
i = 0;
|
|
|
|
|
while (TRUE)
|
|
|
|
|
{
|
|
|
|
|
dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
|
|
|
|
|
rc = RegEnumKeyExW(hInterfaceKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
|
|
|
|
|
if (rc == ERROR_NO_MORE_ITEMS)
|
|
|
|
|
break;
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
RegCloseKey(hInterfaceKey);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
i++;
|
|
|
|
|
|
|
|
|
|
/* Open sub key */
|
2005-07-18 07:17:53 +00:00
|
|
|
|
rc = RegOpenKeyExW(hInterfaceKey, KeyBuffer, 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hDeviceInstanceKey);
|
2005-07-06 21:32:16 +00:00
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
RegCloseKey(hInterfaceKey);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2005-07-17 15:57:41 +00:00
|
|
|
|
/* Read DeviceInstance */
|
|
|
|
|
rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, &dwRegType, NULL, &dwInstancePathLength);
|
2005-07-06 21:32:16 +00:00
|
|
|
|
if (rc != ERROR_SUCCESS )
|
|
|
|
|
{
|
2005-07-17 15:57:41 +00:00
|
|
|
|
RegCloseKey(hDeviceInstanceKey);
|
2005-07-06 21:32:16 +00:00
|
|
|
|
RegCloseKey(hInterfaceKey);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
if (dwRegType != REG_SZ)
|
|
|
|
|
{
|
2005-07-17 15:57:41 +00:00
|
|
|
|
RegCloseKey(hDeviceInstanceKey);
|
2005-07-06 21:32:16 +00:00
|
|
|
|
RegCloseKey(hInterfaceKey);
|
|
|
|
|
return ERROR_GEN_FAILURE;
|
|
|
|
|
}
|
2005-07-24 17:21:26 +00:00
|
|
|
|
InstancePath = HeapAlloc(GetProcessHeap(), 0, dwInstancePathLength + sizeof(WCHAR));
|
2005-07-17 15:57:41 +00:00
|
|
|
|
if (!InstancePath)
|
2005-07-06 21:32:16 +00:00
|
|
|
|
{
|
2005-07-17 15:57:41 +00:00
|
|
|
|
RegCloseKey(hDeviceInstanceKey);
|
2005-07-06 21:32:16 +00:00
|
|
|
|
RegCloseKey(hInterfaceKey);
|
2005-08-09 20:12:35 +00:00
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
2005-07-06 21:32:16 +00:00
|
|
|
|
}
|
2005-07-17 15:57:41 +00:00
|
|
|
|
rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, NULL, (LPBYTE)InstancePath, &dwInstancePathLength);
|
2005-07-06 21:32:16 +00:00
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
2005-07-17 15:57:41 +00:00
|
|
|
|
HeapFree(GetProcessHeap(), 0, InstancePath);
|
|
|
|
|
RegCloseKey(hDeviceInstanceKey);
|
2005-07-06 21:32:16 +00:00
|
|
|
|
RegCloseKey(hInterfaceKey);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
2005-07-24 17:21:26 +00:00
|
|
|
|
InstancePath[dwInstancePathLength / sizeof(WCHAR)] = '\0';
|
2005-07-17 15:57:41 +00:00
|
|
|
|
TRACE("DeviceInstance %s\n", debugstr_w(InstancePath));
|
2005-07-06 21:32:16 +00:00
|
|
|
|
|
2005-07-07 16:32:34 +00:00
|
|
|
|
if (DeviceInstanceW)
|
2005-07-06 21:32:16 +00:00
|
|
|
|
{
|
|
|
|
|
/* Check if device enumerator is not the right one */
|
2005-07-17 15:57:41 +00:00
|
|
|
|
if (wcscmp(DeviceInstanceW, InstancePath) != 0)
|
2005-07-06 21:32:16 +00:00
|
|
|
|
{
|
2005-07-17 15:57:41 +00:00
|
|
|
|
HeapFree(GetProcessHeap(), 0, InstancePath);
|
|
|
|
|
RegCloseKey(hDeviceInstanceKey);
|
2005-07-06 21:32:16 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Find class GUID associated to the device instance */
|
2005-07-18 07:17:53 +00:00
|
|
|
|
rc = RegOpenKeyExW(
|
2005-07-06 21:32:16 +00:00
|
|
|
|
HKEY_LOCAL_MACHINE,
|
2005-07-07 16:32:34 +00:00
|
|
|
|
EnumKeyName,
|
2005-07-06 21:32:16 +00:00
|
|
|
|
0, /* Options */
|
|
|
|
|
KEY_ENUMERATE_SUB_KEYS,
|
|
|
|
|
&hEnumKey);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
2005-07-17 15:57:41 +00:00
|
|
|
|
HeapFree(GetProcessHeap(), 0, InstancePath);
|
|
|
|
|
RegCloseKey(hDeviceInstanceKey);
|
2005-07-06 21:32:16 +00:00
|
|
|
|
RegCloseKey(hInterfaceKey);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
2005-07-18 07:17:53 +00:00
|
|
|
|
rc = RegOpenKeyExW(
|
2005-07-06 21:32:16 +00:00
|
|
|
|
hEnumKey,
|
2005-07-17 15:57:41 +00:00
|
|
|
|
InstancePath,
|
2005-07-06 21:32:16 +00:00
|
|
|
|
0, /* Options */
|
|
|
|
|
KEY_QUERY_VALUE,
|
|
|
|
|
&hKey);
|
|
|
|
|
RegCloseKey(hEnumKey);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
2005-07-17 15:57:41 +00:00
|
|
|
|
HeapFree(GetProcessHeap(), 0, InstancePath);
|
|
|
|
|
RegCloseKey(hDeviceInstanceKey);
|
2005-07-06 21:32:16 +00:00
|
|
|
|
RegCloseKey(hInterfaceKey);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
2005-07-24 17:21:26 +00:00
|
|
|
|
dwLength = sizeof(KeyBuffer) - sizeof(WCHAR);
|
2005-07-07 16:32:34 +00:00
|
|
|
|
rc = RegQueryValueExW(hKey, ClassGUID, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
|
2005-07-17 15:57:41 +00:00
|
|
|
|
RegCloseKey(hKey);
|
2005-07-06 21:32:16 +00:00
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
2005-07-17 15:57:41 +00:00
|
|
|
|
HeapFree(GetProcessHeap(), 0, InstancePath);
|
|
|
|
|
RegCloseKey(hDeviceInstanceKey);
|
2005-07-06 21:32:16 +00:00
|
|
|
|
RegCloseKey(hInterfaceKey);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
2005-07-24 17:21:26 +00:00
|
|
|
|
KeyBuffer[dwLength / sizeof(WCHAR)] = '\0';
|
|
|
|
|
KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */
|
2005-07-17 15:57:41 +00:00
|
|
|
|
if (UuidFromStringW(&KeyBuffer[1], &ClassGuid) != RPC_S_OK)
|
2005-07-06 21:32:16 +00:00
|
|
|
|
{
|
2005-07-17 15:57:41 +00:00
|
|
|
|
HeapFree(GetProcessHeap(), 0, InstancePath);
|
|
|
|
|
RegCloseKey(hDeviceInstanceKey);
|
|
|
|
|
RegCloseKey(hInterfaceKey);
|
2005-07-06 21:32:16 +00:00
|
|
|
|
return ERROR_GEN_FAILURE;
|
|
|
|
|
}
|
2005-07-17 15:57:41 +00:00
|
|
|
|
TRACE("ClassGUID %s\n", debugstr_guid(&ClassGuid));
|
2005-07-05 08:48:43 +00:00
|
|
|
|
|
2005-07-17 15:57:41 +00:00
|
|
|
|
/* If current device doesn't match the list GUID (if any), skip this entry */
|
|
|
|
|
if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, &ClassGuid))
|
|
|
|
|
{
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, InstancePath);
|
|
|
|
|
RegCloseKey(hDeviceInstanceKey);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Enumerate subkeys of hDeviceInstanceKey (ie "#ReferenceString" in IoRegisterDeviceInterface). Skip entries that don't start with '#' */
|
|
|
|
|
j = 0;
|
|
|
|
|
while (TRUE)
|
2005-07-06 21:32:16 +00:00
|
|
|
|
{
|
2005-08-09 20:12:35 +00:00
|
|
|
|
LPWSTR pSymbolicLink;
|
|
|
|
|
struct DeviceInterface *interfaceInfo;
|
|
|
|
|
|
2005-07-17 15:57:41 +00:00
|
|
|
|
dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
|
|
|
|
|
rc = RegEnumKeyExW(hDeviceInstanceKey, j, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
|
|
|
|
|
if (rc == ERROR_NO_MORE_ITEMS)
|
|
|
|
|
break;
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, InstancePath);
|
|
|
|
|
RegCloseKey(hDeviceInstanceKey);
|
|
|
|
|
RegCloseKey(hInterfaceKey);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
j++;
|
|
|
|
|
if (KeyBuffer[0] != '#')
|
|
|
|
|
/* This entry doesn't represent an interesting entry */
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* Open sub key */
|
2005-07-18 07:17:53 +00:00
|
|
|
|
rc = RegOpenKeyExW(hDeviceInstanceKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hReferenceKey);
|
2005-07-17 15:57:41 +00:00
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
RegCloseKey(hDeviceInstanceKey);
|
|
|
|
|
RegCloseKey(hInterfaceKey);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read SymbolicLink value */
|
|
|
|
|
rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, &dwRegType, NULL, &dwLength);
|
|
|
|
|
if (rc != ERROR_SUCCESS )
|
|
|
|
|
{
|
|
|
|
|
RegCloseKey(hReferenceKey);
|
|
|
|
|
RegCloseKey(hDeviceInstanceKey);
|
|
|
|
|
RegCloseKey(hInterfaceKey);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
if (dwRegType != REG_SZ)
|
|
|
|
|
{
|
|
|
|
|
RegCloseKey(hReferenceKey);
|
|
|
|
|
RegCloseKey(hDeviceInstanceKey);
|
|
|
|
|
RegCloseKey(hInterfaceKey);
|
|
|
|
|
return ERROR_GEN_FAILURE;
|
|
|
|
|
}
|
2005-08-09 20:12:35 +00:00
|
|
|
|
|
|
|
|
|
/* We have found a device */
|
|
|
|
|
/* Step 1. Create a device info element */
|
|
|
|
|
if (!CreateDeviceInfoElement(InstancePath, &ClassGuid, &deviceInfo))
|
|
|
|
|
{
|
|
|
|
|
RegCloseKey(hReferenceKey);
|
|
|
|
|
RegCloseKey(hDeviceInstanceKey);
|
|
|
|
|
RegCloseKey(hInterfaceKey);
|
|
|
|
|
return GetLastError();
|
|
|
|
|
}
|
|
|
|
|
TRACE("Adding device %s to list\n", debugstr_w(InstancePath));
|
|
|
|
|
InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
|
|
|
|
|
|
|
|
|
|
/* Step 2. Create an interface list for this element */
|
|
|
|
|
pSymbolicLink = HeapAlloc(GetProcessHeap(), 0, (dwLength + 1) * sizeof(WCHAR));
|
|
|
|
|
if (!pSymbolicLink)
|
2005-07-17 15:57:41 +00:00
|
|
|
|
{
|
|
|
|
|
RegCloseKey(hReferenceKey);
|
|
|
|
|
RegCloseKey(hDeviceInstanceKey);
|
|
|
|
|
RegCloseKey(hInterfaceKey);
|
2005-08-09 20:12:35 +00:00
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
2005-07-17 15:57:41 +00:00
|
|
|
|
}
|
2005-08-09 20:12:35 +00:00
|
|
|
|
rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, NULL, (LPBYTE)pSymbolicLink, &dwLength);
|
|
|
|
|
pSymbolicLink[dwLength / sizeof(WCHAR)] = '\0';
|
2005-07-17 15:57:41 +00:00
|
|
|
|
RegCloseKey(hReferenceKey);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
2005-08-09 20:12:35 +00:00
|
|
|
|
HeapFree(GetProcessHeap(), 0, pSymbolicLink);
|
2005-07-17 15:57:41 +00:00
|
|
|
|
RegCloseKey(hDeviceInstanceKey);
|
|
|
|
|
RegCloseKey(hInterfaceKey);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
2005-08-09 20:12:35 +00:00
|
|
|
|
if (!CreateDeviceInterface(deviceInfo, pSymbolicLink, InterfaceGuid, &interfaceInfo))
|
|
|
|
|
{
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, pSymbolicLink);
|
|
|
|
|
RegCloseKey(hDeviceInstanceKey);
|
|
|
|
|
RegCloseKey(hInterfaceKey);
|
|
|
|
|
return GetLastError();
|
|
|
|
|
}
|
|
|
|
|
TRACE("Adding interface %s to list\n", debugstr_w(pSymbolicLink));
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, pSymbolicLink);
|
|
|
|
|
InsertTailList(&deviceInfo->InterfaceListHead, &interfaceInfo->ListEntry);
|
2005-07-06 21:32:16 +00:00
|
|
|
|
}
|
2005-07-17 15:57:41 +00:00
|
|
|
|
RegCloseKey(hDeviceInstanceKey);
|
2005-07-06 21:32:16 +00:00
|
|
|
|
}
|
|
|
|
|
RegCloseKey(hInterfaceKey);
|
|
|
|
|
return ERROR_SUCCESS;
|
2005-07-05 08:48:43 +00:00
|
|
|
|
}
|
2005-08-09 20:12:35 +00:00
|
|
|
|
#endif /* __REACTOS__ */
|
2005-07-01 23:26:01 +00:00
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
2005-07-05 12:59:14 +00:00
|
|
|
|
* SetupDiGetClassDevsExW (SETUPAPI.@)
|
2005-07-01 23:26:01 +00:00
|
|
|
|
*/
|
2005-07-05 12:59:14 +00:00
|
|
|
|
HDEVINFO WINAPI SetupDiGetClassDevsExW(
|
2005-07-01 23:26:01 +00:00
|
|
|
|
CONST GUID *class,
|
|
|
|
|
LPCWSTR enumstr,
|
|
|
|
|
HWND parent,
|
2005-07-05 12:59:14 +00:00
|
|
|
|
DWORD flags,
|
2005-07-05 14:00:33 +00:00
|
|
|
|
HDEVINFO deviceset,
|
2005-07-05 12:59:14 +00:00
|
|
|
|
LPCWSTR machine,
|
|
|
|
|
PVOID reserved)
|
2005-07-01 23:26:01 +00:00
|
|
|
|
{
|
2005-07-06 21:32:16 +00:00
|
|
|
|
HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
|
2005-08-08 16:06:52 +00:00
|
|
|
|
struct DeviceInfoSet *list;
|
2005-07-06 21:32:16 +00:00
|
|
|
|
LPGUID pClassGuid;
|
|
|
|
|
LONG rc;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
|
2005-07-05 14:00:33 +00:00
|
|
|
|
TRACE("%s %s %p 0x%08lx %p %s %p\n", debugstr_guid(class), debugstr_w(enumstr),
|
|
|
|
|
parent, flags, deviceset, debugstr_w(machine), reserved);
|
2005-07-01 23:26:01 +00:00
|
|
|
|
|
2005-07-06 21:32:16 +00:00
|
|
|
|
/* Create the deviceset if not set */
|
|
|
|
|
if (deviceset)
|
|
|
|
|
{
|
2005-08-08 16:06:52 +00:00
|
|
|
|
list = (struct DeviceInfoSet *)deviceset;
|
|
|
|
|
if (list->magic != SETUP_DEV_INFO_SET_MAGIC)
|
2005-07-06 21:32:16 +00:00
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
|
}
|
|
|
|
|
hDeviceInfo = deviceset;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
hDeviceInfo = SetupDiCreateDeviceInfoListExW(
|
|
|
|
|
flags & DIGCF_DEVICEINTERFACE ? NULL : class,
|
|
|
|
|
NULL, machine, NULL);
|
|
|
|
|
if (hDeviceInfo == INVALID_HANDLE_VALUE)
|
|
|
|
|
return INVALID_HANDLE_VALUE;
|
2005-08-08 16:06:52 +00:00
|
|
|
|
list = (struct DeviceInfoSet *)hDeviceInfo;
|
2005-07-06 21:32:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
|
|
|
|
|
pClassGuid = NULL;
|
|
|
|
|
else
|
|
|
|
|
pClassGuid = &list->ClassGuid;
|
|
|
|
|
|
2005-07-05 08:48:43 +00:00
|
|
|
|
if (flags & DIGCF_PRESENT)
|
|
|
|
|
FIXME(": flag DIGCF_PRESENT ignored\n");
|
|
|
|
|
if (flags & DIGCF_PROFILE)
|
|
|
|
|
FIXME(": flag DIGCF_PROFILE ignored\n");
|
|
|
|
|
|
2005-07-06 21:32:16 +00:00
|
|
|
|
if (flags & DIGCF_ALLCLASSES)
|
|
|
|
|
{
|
2005-07-18 07:17:53 +00:00
|
|
|
|
rc = SETUP_CreateDevList(list, machine, pClassGuid, enumstr);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
2005-07-06 21:32:16 +00:00
|
|
|
|
{
|
2005-07-18 07:17:53 +00:00
|
|
|
|
SetLastError(rc);
|
2005-07-06 21:32:16 +00:00
|
|
|
|
if (!deviceset)
|
|
|
|
|
SetupDiDestroyDeviceInfoList(hDeviceInfo);
|
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
|
}
|
|
|
|
|
return hDeviceInfo;
|
|
|
|
|
}
|
2005-07-05 08:48:43 +00:00
|
|
|
|
else if (flags & DIGCF_DEVICEINTERFACE)
|
2005-07-01 23:26:01 +00:00
|
|
|
|
{
|
2005-07-06 21:32:16 +00:00
|
|
|
|
if (class == NULL)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
if (!deviceset)
|
|
|
|
|
SetupDiDestroyDeviceInfoList(hDeviceInfo);
|
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-09 20:12:35 +00:00
|
|
|
|
#ifndef __REACTOS__
|
2005-07-06 21:32:16 +00:00
|
|
|
|
/* Special case: find serial ports by calling QueryDosDevice */
|
2005-07-07 16:32:34 +00:00
|
|
|
|
if (IsEqualIID(class, &GUID_DEVINTERFACE_COMPORT))
|
|
|
|
|
rc = SETUP_CreateSerialDeviceList(list, machine, (LPGUID)class, enumstr);
|
|
|
|
|
if (IsEqualIID(class, &GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR))
|
|
|
|
|
rc = SETUP_CreateSerialDeviceList(list, machine, (LPGUID)class, enumstr);
|
|
|
|
|
else
|
2005-07-05 08:48:43 +00:00
|
|
|
|
{
|
2005-07-07 16:32:34 +00:00
|
|
|
|
ERR("Wine can only enumerate serial devices at the moment!\n");
|
|
|
|
|
rc = ERROR_INVALID_PARAMETER;
|
2005-07-05 08:48:43 +00:00
|
|
|
|
}
|
2005-08-09 20:12:35 +00:00
|
|
|
|
#else /* __REACTOS__ */
|
2005-07-06 21:32:16 +00:00
|
|
|
|
rc = SETUP_CreateInterfaceList(list, machine, (LPGUID)class, enumstr);
|
2005-08-09 20:12:35 +00:00
|
|
|
|
#endif /* __REACTOS__ */
|
2005-07-06 21:32:16 +00:00
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(rc);
|
|
|
|
|
if (!deviceset)
|
|
|
|
|
SetupDiDestroyDeviceInfoList(hDeviceInfo);
|
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
|
}
|
|
|
|
|
return hDeviceInfo;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2005-07-18 07:17:53 +00:00
|
|
|
|
rc = SETUP_CreateDevList(list, machine, (LPGUID)class, enumstr);
|
2005-07-06 21:32:16 +00:00
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(rc);
|
|
|
|
|
if (!deviceset)
|
|
|
|
|
SetupDiDestroyDeviceInfoList(hDeviceInfo);
|
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
|
}
|
|
|
|
|
return hDeviceInfo;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiEnumDeviceInterfaces (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiEnumDeviceInterfaces(
|
|
|
|
|
HDEVINFO DeviceInfoSet,
|
|
|
|
|
PSP_DEVINFO_DATA DeviceInfoData,
|
|
|
|
|
CONST GUID * InterfaceClassGuid,
|
|
|
|
|
DWORD MemberIndex,
|
|
|
|
|
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
|
|
|
|
|
{
|
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
|
2005-08-09 20:12:35 +00:00
|
|
|
|
TRACE("%p, %p, %s, %ld, %p\n", DeviceInfoSet, DeviceInfoData,
|
2005-07-01 23:26:01 +00:00
|
|
|
|
debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData);
|
2005-07-07 16:32:34 +00:00
|
|
|
|
|
2005-07-01 23:26:01 +00:00
|
|
|
|
if (!DeviceInterfaceData)
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
2005-07-07 16:32:34 +00:00
|
|
|
|
else if (DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
|
|
|
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
2005-07-01 23:26:01 +00:00
|
|
|
|
else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
2005-08-08 16:06:52 +00:00
|
|
|
|
struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
|
2005-08-08 16:06:52 +00:00
|
|
|
|
if (list->magic == SETUP_DEV_INFO_SET_MAGIC)
|
2005-07-01 23:26:01 +00:00
|
|
|
|
{
|
2005-08-08 16:06:52 +00:00
|
|
|
|
PLIST_ENTRY ItemList = list->ListHead.Flink;
|
|
|
|
|
BOOL Found = FALSE;
|
|
|
|
|
while (ItemList != &list->ListHead && !Found)
|
2005-07-01 23:26:01 +00:00
|
|
|
|
{
|
2005-08-08 16:06:52 +00:00
|
|
|
|
PLIST_ENTRY InterfaceListEntry;
|
|
|
|
|
struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)ItemList;
|
|
|
|
|
if (DeviceInfoData && (struct DeviceInfoElement *)DeviceInfoData->Reserved != DevInfo)
|
|
|
|
|
{
|
|
|
|
|
/* We are not searching for this element */
|
2005-07-05 08:48:43 +00:00
|
|
|
|
ItemList = ItemList->Flink;
|
2005-08-08 16:06:52 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2005-08-09 20:12:35 +00:00
|
|
|
|
InterfaceListEntry = DevInfo->InterfaceListHead.Flink;
|
|
|
|
|
while (InterfaceListEntry != &DevInfo->InterfaceListHead && !Found)
|
2005-07-06 21:32:16 +00:00
|
|
|
|
{
|
2005-08-08 16:06:52 +00:00
|
|
|
|
struct DeviceInterface *DevItf = (struct DeviceInterface *)InterfaceListEntry;
|
|
|
|
|
if (!IsEqualIID(&DevItf->InterfaceClassGuid, InterfaceClassGuid))
|
|
|
|
|
{
|
|
|
|
|
InterfaceListEntry = InterfaceListEntry->Flink;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (MemberIndex-- == 0)
|
|
|
|
|
{
|
|
|
|
|
/* return this item */
|
|
|
|
|
memcpy(&DeviceInterfaceData->InterfaceClassGuid,
|
|
|
|
|
&DevItf->InterfaceClassGuid,
|
|
|
|
|
sizeof(GUID));
|
|
|
|
|
DeviceInterfaceData->Flags = 0; /* FIXME */
|
|
|
|
|
/* Note: this appears to be dangerous, passing a private
|
|
|
|
|
* pointer a heap-allocated datum to the caller. However, the
|
|
|
|
|
* expected lifetime of the device data is the same as the
|
|
|
|
|
* HDEVINFO; once that is closed, the data are no longer valid.
|
|
|
|
|
*/
|
|
|
|
|
DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
|
|
|
|
|
Found = TRUE;
|
|
|
|
|
}
|
2005-08-09 20:12:35 +00:00
|
|
|
|
InterfaceListEntry = InterfaceListEntry->Flink;
|
2005-07-06 21:32:16 +00:00
|
|
|
|
}
|
2005-08-08 16:06:52 +00:00
|
|
|
|
ItemList = ItemList->Flink;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
}
|
2005-08-08 16:06:52 +00:00
|
|
|
|
if (!Found)
|
|
|
|
|
SetLastError(ERROR_NO_MORE_ITEMS);
|
|
|
|
|
else
|
|
|
|
|
ret = TRUE;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2005-10-24 09:39:53 +00:00
|
|
|
|
static VOID ReferenceInfFile(struct InfFileDetails* infFile)
|
|
|
|
|
{
|
|
|
|
|
InterlockedIncrement(&infFile->References);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static VOID DereferenceInfFile(struct InfFileDetails* infFile)
|
2005-10-24 09:16:34 +00:00
|
|
|
|
{
|
2005-10-24 09:39:53 +00:00
|
|
|
|
if (InterlockedDecrement(&infFile->References) == 0)
|
2005-10-24 09:16:34 +00:00
|
|
|
|
{
|
2005-10-24 09:39:53 +00:00
|
|
|
|
SetupCloseInfFile(infFile->hInf);
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, infFile);
|
2005-10-24 09:16:34 +00:00
|
|
|
|
}
|
2005-10-24 09:39:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOL DestroyDriverInfoElement(struct DriverInfoElement* driverInfo)
|
|
|
|
|
{
|
|
|
|
|
DereferenceInfFile(driverInfo->InfFileDetails);
|
2005-10-24 09:16:34 +00:00
|
|
|
|
HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId);
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, driverInfo);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOL DestroyDeviceInfoElement(struct DeviceInfoElement* deviceInfo)
|
|
|
|
|
{
|
|
|
|
|
PLIST_ENTRY ListEntry;
|
|
|
|
|
struct DriverInfoElement *driverInfo;
|
|
|
|
|
|
|
|
|
|
while (!IsListEmpty(&deviceInfo->DriverListHead))
|
|
|
|
|
{
|
|
|
|
|
ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
|
|
|
|
|
driverInfo = (struct DriverInfoElement *)ListEntry;
|
|
|
|
|
if (!DestroyDriverInfoElement(driverInfo))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
while (!IsListEmpty(&deviceInfo->InterfaceListHead))
|
|
|
|
|
{
|
|
|
|
|
ListEntry = RemoveHeadList(&deviceInfo->InterfaceListHead);
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, ListEntry);
|
|
|
|
|
}
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, deviceInfo);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOL DestroyDeviceInfoSet(struct DeviceInfoSet* list)
|
|
|
|
|
{
|
|
|
|
|
PLIST_ENTRY ListEntry;
|
|
|
|
|
struct DeviceInfoElement *deviceInfo;
|
|
|
|
|
|
|
|
|
|
while (!IsListEmpty(&list->ListHead))
|
|
|
|
|
{
|
|
|
|
|
ListEntry = RemoveHeadList(&list->ListHead);
|
|
|
|
|
deviceInfo = (struct DeviceInfoElement *)ListEntry;
|
|
|
|
|
if (!DestroyDeviceInfoElement(deviceInfo))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (list->HKLM != HKEY_LOCAL_MACHINE)
|
|
|
|
|
RegCloseKey(list->HKLM);
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, list);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2005-07-01 23:26:01 +00:00
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiDestroyDeviceInfoList (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
|
|
|
|
|
{
|
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
|
|
|
|
|
TRACE("%p\n", devinfo);
|
|
|
|
|
if (devinfo && devinfo != (HDEVINFO)INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
2005-08-08 16:06:52 +00:00
|
|
|
|
struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
|
2005-08-08 16:06:52 +00:00
|
|
|
|
if (list->magic == SETUP_DEV_INFO_SET_MAGIC)
|
2005-10-24 09:16:34 +00:00
|
|
|
|
ret = DestroyDeviceInfoSet(list);
|
2005-07-01 23:26:01 +00:00
|
|
|
|
else
|
|
|
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
2005-08-09 20:12:35 +00:00
|
|
|
|
|
|
|
|
|
TRACE("Returning %d\n", ret);
|
2005-07-01 23:26:01 +00:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(
|
|
|
|
|
HDEVINFO DeviceInfoSet,
|
|
|
|
|
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
|
|
|
|
|
PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
|
|
|
|
|
DWORD DeviceInterfaceDetailDataSize,
|
|
|
|
|
PDWORD RequiredSize,
|
|
|
|
|
PSP_DEVINFO_DATA DeviceInfoData)
|
|
|
|
|
{
|
2005-07-17 15:57:41 +00:00
|
|
|
|
PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailDataW = NULL;
|
|
|
|
|
DWORD sizeW = 0, sizeA;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
|
|
|
|
|
TRACE("(%p, %p, %p, %ld, %p, %p)\n", DeviceInfoSet,
|
2005-07-17 15:57:41 +00:00
|
|
|
|
DeviceInterfaceData, DeviceInterfaceDetailData,
|
|
|
|
|
DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
|
|
|
|
|
|
|
|
|
|
if (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A))
|
|
|
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
|
|
|
else if (DeviceInterfaceDetailData == NULL && DeviceInterfaceDetailDataSize != 0)
|
2005-07-01 23:26:01 +00:00
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
2005-07-17 15:57:41 +00:00
|
|
|
|
else if (DeviceInterfaceDetailData != NULL && DeviceInterfaceDetailDataSize < FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + 1)
|
2005-07-01 23:26:01 +00:00
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
2005-07-17 15:57:41 +00:00
|
|
|
|
else
|
2005-07-01 23:26:01 +00:00
|
|
|
|
{
|
2005-07-17 15:57:41 +00:00
|
|
|
|
if (DeviceInterfaceDetailData != NULL)
|
2005-07-01 23:26:01 +00:00
|
|
|
|
{
|
2005-07-17 15:57:41 +00:00
|
|
|
|
sizeW = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
|
|
|
|
|
+ (DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath)) * sizeof(WCHAR);
|
|
|
|
|
DeviceInterfaceDetailDataW = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)HeapAlloc(GetProcessHeap(), 0, sizeW);
|
|
|
|
|
if (!DeviceInterfaceDetailDataW)
|
2005-07-01 23:26:01 +00:00
|
|
|
|
{
|
2005-07-17 15:57:41 +00:00
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
2005-07-01 23:26:01 +00:00
|
|
|
|
}
|
2005-07-17 15:57:41 +00:00
|
|
|
|
}
|
|
|
|
|
if (!DeviceInterfaceDetailData || (DeviceInterfaceDetailData && DeviceInterfaceDetailDataW))
|
|
|
|
|
{
|
|
|
|
|
DeviceInterfaceDetailDataW->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
|
|
|
|
|
ret = SetupDiGetDeviceInterfaceDetailW(
|
|
|
|
|
DeviceInfoSet,
|
|
|
|
|
DeviceInterfaceData,
|
|
|
|
|
DeviceInterfaceDetailDataW,
|
|
|
|
|
sizeW,
|
|
|
|
|
&sizeW,
|
|
|
|
|
DeviceInfoData);
|
|
|
|
|
sizeA = (sizeW - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)) / sizeof(WCHAR)
|
|
|
|
|
+ FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath);
|
|
|
|
|
if (RequiredSize)
|
|
|
|
|
*RequiredSize = sizeA;
|
|
|
|
|
if (ret && DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize <= sizeA)
|
2005-07-01 23:26:01 +00:00
|
|
|
|
{
|
2005-07-17 15:57:41 +00:00
|
|
|
|
if (!WideCharToMultiByte(
|
|
|
|
|
CP_ACP, 0,
|
|
|
|
|
DeviceInterfaceDetailDataW->DevicePath, -1,
|
|
|
|
|
DeviceInterfaceDetailData->DevicePath, DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
|
|
|
|
|
NULL, NULL))
|
2005-07-01 23:26:01 +00:00
|
|
|
|
{
|
2005-07-17 15:57:41 +00:00
|
|
|
|
ret = FALSE;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-07-17 15:57:41 +00:00
|
|
|
|
HeapFree(GetProcessHeap(), 0, DeviceInterfaceDetailDataW);
|
2005-07-01 23:26:01 +00:00
|
|
|
|
}
|
2005-07-17 15:57:41 +00:00
|
|
|
|
|
2005-07-01 23:26:01 +00:00
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
|
|
|
|
|
HDEVINFO DeviceInfoSet,
|
|
|
|
|
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
|
|
|
|
|
PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
|
|
|
|
|
DWORD DeviceInterfaceDetailDataSize,
|
|
|
|
|
PDWORD RequiredSize,
|
|
|
|
|
PSP_DEVINFO_DATA DeviceInfoData)
|
|
|
|
|
{
|
2005-07-17 15:57:41 +00:00
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
|
|
|
|
|
TRACE("(%p, %p, %p, %ld, %p, %p): stub\n", DeviceInfoSet,
|
|
|
|
|
DeviceInterfaceData, DeviceInterfaceDetailData,
|
|
|
|
|
DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
|
|
|
|
|
|
|
|
|
|
if (!DeviceInfoSet || !DeviceInterfaceData)
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
|
|
|
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
2005-08-08 16:06:52 +00:00
|
|
|
|
else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
|
2005-07-17 15:57:41 +00:00
|
|
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
|
|
|
else if (DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
|
|
|
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
|
|
|
else if (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W))
|
|
|
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
|
|
|
else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
|
|
|
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
|
|
|
else if (DeviceInterfaceDetailData == NULL && DeviceInterfaceDetailDataSize != 0)
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
2005-07-24 17:21:26 +00:00
|
|
|
|
else if (DeviceInterfaceDetailData != NULL && DeviceInterfaceDetailDataSize < FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR))
|
2005-07-17 15:57:41 +00:00
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
else
|
|
|
|
|
{
|
2005-08-09 20:12:35 +00:00
|
|
|
|
struct DeviceInterface *deviceInterface = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
|
|
|
|
|
LPCWSTR devName = deviceInterface->SymbolicLink;
|
2005-07-17 15:57:41 +00:00
|
|
|
|
DWORD sizeRequired = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) +
|
2005-08-09 20:12:35 +00:00
|
|
|
|
(lstrlenW(devName) + 1) * sizeof(WCHAR);
|
2005-07-17 15:57:41 +00:00
|
|
|
|
|
|
|
|
|
if (sizeRequired > DeviceInterfaceDetailDataSize)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
|
if (RequiredSize)
|
|
|
|
|
*RequiredSize = sizeRequired;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
wcscpy(DeviceInterfaceDetailData->DevicePath, devName);
|
|
|
|
|
TRACE("DevicePath is %s\n", debugstr_w(DeviceInterfaceDetailData->DevicePath));
|
|
|
|
|
if (DeviceInfoData)
|
|
|
|
|
{
|
|
|
|
|
memcpy(&DeviceInfoData->ClassGuid,
|
2005-08-09 20:12:35 +00:00
|
|
|
|
&deviceInterface->DeviceInfo->ClassGuid,
|
2005-07-17 15:57:41 +00:00
|
|
|
|
sizeof(GUID));
|
|
|
|
|
DeviceInfoData->DevInst = 0; /* FIXME */
|
2005-07-18 07:17:53 +00:00
|
|
|
|
/* Note: this appears to be dangerous, passing a private
|
|
|
|
|
* pointer a heap-allocated datum to the caller. However, the
|
|
|
|
|
* expected lifetime of the device data is the same as the
|
|
|
|
|
* HDEVINFO; once that is closed, the data are no longer valid.
|
|
|
|
|
*/
|
2005-08-09 20:12:35 +00:00
|
|
|
|
DeviceInfoData->Reserved = (ULONG_PTR)deviceInterface->DeviceInfo;
|
2005-07-17 15:57:41 +00:00
|
|
|
|
}
|
|
|
|
|
ret = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
|
|
|
return ret;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(
|
|
|
|
|
HDEVINFO devinfo,
|
|
|
|
|
PSP_DEVINFO_DATA DeviceInfoData,
|
|
|
|
|
DWORD Property,
|
|
|
|
|
PDWORD PropertyRegDataType,
|
|
|
|
|
PBYTE PropertyBuffer,
|
|
|
|
|
DWORD PropertyBufferSize,
|
|
|
|
|
PDWORD RequiredSize)
|
2005-07-03 20:19:55 +00:00
|
|
|
|
{
|
|
|
|
|
BOOL bResult;
|
|
|
|
|
BOOL bIsStringProperty;
|
|
|
|
|
DWORD RegType;
|
|
|
|
|
DWORD RequiredSizeA, RequiredSizeW;
|
|
|
|
|
DWORD PropertyBufferSizeW;
|
|
|
|
|
PBYTE PropertyBufferW;
|
|
|
|
|
|
2005-10-12 08:14:56 +00:00
|
|
|
|
TRACE("%p %p %ld %p %p %ld %p\n", devinfo, DeviceInfoData,
|
2005-07-03 20:19:55 +00:00
|
|
|
|
Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
|
|
|
|
|
RequiredSize);
|
|
|
|
|
|
|
|
|
|
PropertyBufferSizeW = PropertyBufferSize * 2;
|
|
|
|
|
PropertyBufferW = HeapAlloc(GetProcessHeap(), 0, PropertyBufferSizeW);
|
|
|
|
|
|
|
|
|
|
bResult = SetupDiGetDeviceRegistryPropertyW(
|
|
|
|
|
devinfo,
|
|
|
|
|
DeviceInfoData,
|
|
|
|
|
Property,
|
|
|
|
|
&RegType,
|
|
|
|
|
PropertyBufferW,
|
|
|
|
|
PropertyBufferSizeW,
|
|
|
|
|
&RequiredSizeW);
|
|
|
|
|
|
2005-10-21 23:40:09 +00:00
|
|
|
|
if (bResult || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
2005-10-12 08:14:56 +00:00
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2005-07-03 20:19:55 +00:00
|
|
|
|
if (!bResult)
|
2005-07-18 07:17:53 +00:00
|
|
|
|
{
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, PropertyBufferW);
|
2005-07-03 20:19:55 +00:00
|
|
|
|
return bResult;
|
2005-07-18 07:17:53 +00:00
|
|
|
|
}
|
2005-07-03 20:19:55 +00:00
|
|
|
|
|
|
|
|
|
if (RequiredSizeA <= PropertyBufferSize)
|
|
|
|
|
{
|
|
|
|
|
if (bIsStringProperty && PropertyBufferSize > 0)
|
|
|
|
|
{
|
2005-08-01 09:23:13 +00:00
|
|
|
|
if (WideCharToMultiByte(CP_ACP, 0, (LPWSTR)PropertyBufferW, RequiredSizeW / sizeof(WCHAR), (LPSTR)PropertyBuffer, PropertyBufferSize, NULL, NULL) == 0)
|
2005-07-03 20:19:55 +00:00
|
|
|
|
{
|
|
|
|
|
/* Last error is already set by WideCharToMultiByte */
|
|
|
|
|
bResult = FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
memcpy(PropertyBuffer, PropertyBufferW, RequiredSizeA);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
|
bResult = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2005-07-18 07:17:53 +00:00
|
|
|
|
HeapFree(GetProcessHeap(), 0, PropertyBufferW);
|
2005-07-03 20:19:55 +00:00
|
|
|
|
return bResult;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
|
2005-07-18 07:17:53 +00:00
|
|
|
|
HDEVINFO DeviceInfoSet,
|
2005-07-03 20:19:55 +00:00
|
|
|
|
PSP_DEVINFO_DATA DeviceInfoData,
|
|
|
|
|
DWORD Property,
|
|
|
|
|
PDWORD PropertyRegDataType,
|
|
|
|
|
PBYTE PropertyBuffer,
|
|
|
|
|
DWORD PropertyBufferSize,
|
|
|
|
|
PDWORD RequiredSize)
|
2005-07-01 23:26:01 +00:00
|
|
|
|
{
|
2005-07-18 07:17:53 +00:00
|
|
|
|
HKEY hEnumKey, hKey;
|
|
|
|
|
DWORD rc;
|
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
|
|
|
|
|
TRACE("%p %p %ld %p %p %ld %p\n", DeviceInfoSet, DeviceInfoData,
|
2005-07-01 23:26:01 +00:00
|
|
|
|
Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
|
|
|
|
|
RequiredSize);
|
2005-07-18 07:17:53 +00:00
|
|
|
|
|
|
|
|
|
if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
|
|
|
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
2005-08-08 16:06:52 +00:00
|
|
|
|
else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
|
2005-07-18 07:17:53 +00:00
|
|
|
|
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
|
|
|
|
|
{
|
2005-08-08 16:06:52 +00:00
|
|
|
|
struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
|
|
|
|
|
struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
|
2005-07-18 07:17:53 +00:00
|
|
|
|
|
|
|
|
|
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:
|
2005-10-23 12:41:54 +00:00
|
|
|
|
case SPDRP_UI_NUMBER_DESC_FORMAT:
|
2005-07-18 07:17:53 +00:00
|
|
|
|
case SPDRP_UPPERFILTERS:
|
|
|
|
|
{
|
2005-08-01 09:23:13 +00:00
|
|
|
|
LPCWSTR RegistryPropertyName;
|
|
|
|
|
DWORD BufferSize;
|
|
|
|
|
|
2005-07-18 07:17:53 +00:00
|
|
|
|
switch (Property)
|
|
|
|
|
{
|
|
|
|
|
case SPDRP_CAPABILITIES:
|
|
|
|
|
RegistryPropertyName = L"Capabilities"; break;
|
|
|
|
|
case SPDRP_CLASS:
|
|
|
|
|
RegistryPropertyName = L"Class"; break;
|
|
|
|
|
case SPDRP_CLASSGUID:
|
|
|
|
|
RegistryPropertyName = L"ClassGUID"; break;
|
|
|
|
|
case SPDRP_COMPATIBLEIDS:
|
|
|
|
|
RegistryPropertyName = L"CompatibleIDs"; break;
|
|
|
|
|
case SPDRP_CONFIGFLAGS:
|
|
|
|
|
RegistryPropertyName = L"ConfigFlags"; break;
|
|
|
|
|
case SPDRP_DEVICEDESC:
|
|
|
|
|
RegistryPropertyName = L"DeviceDesc"; break;
|
|
|
|
|
case SPDRP_DRIVER:
|
|
|
|
|
RegistryPropertyName = L"Driver"; break;
|
|
|
|
|
case SPDRP_FRIENDLYNAME:
|
|
|
|
|
RegistryPropertyName = L"FriendlyName"; break;
|
|
|
|
|
case SPDRP_HARDWAREID:
|
|
|
|
|
RegistryPropertyName = L"HardwareID"; break;
|
|
|
|
|
case SPDRP_LOCATION_INFORMATION:
|
|
|
|
|
RegistryPropertyName = L"LocationInformation"; break;
|
|
|
|
|
case SPDRP_LOWERFILTERS:
|
|
|
|
|
RegistryPropertyName = L"LowerFilters"; break;
|
|
|
|
|
case SPDRP_MFG:
|
|
|
|
|
RegistryPropertyName = L"Mfg"; break;
|
|
|
|
|
case SPDRP_SECURITY:
|
|
|
|
|
RegistryPropertyName = L"Security"; break;
|
|
|
|
|
case SPDRP_SERVICE:
|
|
|
|
|
RegistryPropertyName = L"Service"; break;
|
|
|
|
|
case SPDRP_UI_NUMBER:
|
|
|
|
|
RegistryPropertyName = L"UINumber"; break;
|
2005-10-23 12:41:54 +00:00
|
|
|
|
case SPDRP_UI_NUMBER_DESC_FORMAT:
|
|
|
|
|
RegistryPropertyName = L"UINumberDescFormat"; break;
|
2005-07-18 07:17:53 +00:00
|
|
|
|
case SPDRP_UPPERFILTERS:
|
|
|
|
|
RegistryPropertyName = L"UpperFilters"; break;
|
|
|
|
|
default:
|
|
|
|
|
/* Should not happen */
|
2005-08-01 09:23:13 +00:00
|
|
|
|
RegistryPropertyName = NULL; break;
|
2005-07-18 07:17:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Open registry key name */
|
|
|
|
|
rc = RegOpenKeyExW(
|
|
|
|
|
list->HKLM,
|
|
|
|
|
EnumKeyName,
|
|
|
|
|
0, /* Options */
|
|
|
|
|
KEY_ENUMERATE_SUB_KEYS,
|
|
|
|
|
&hEnumKey);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(rc);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
rc = RegOpenKeyExW(
|
|
|
|
|
hEnumKey,
|
2005-08-08 16:06:52 +00:00
|
|
|
|
DevInfo->Data,
|
2005-07-18 07:17:53 +00:00
|
|
|
|
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;
|
2005-10-21 23:40:09 +00:00
|
|
|
|
switch(rc) {
|
|
|
|
|
case ERROR_SUCCESS:
|
|
|
|
|
ret = TRUE;
|
|
|
|
|
break;
|
2005-10-22 16:25:48 +00:00
|
|
|
|
case ERROR_MORE_DATA:
|
2005-10-21 23:40:09 +00:00
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
2005-10-22 16:25:48 +00:00
|
|
|
|
break;
|
2005-10-21 23:40:09 +00:00
|
|
|
|
default:
|
|
|
|
|
SetLastError(rc);
|
|
|
|
|
}
|
2005-07-18 07:17:53 +00:00
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case SPDRP_PHYSICAL_DEVICE_OBJECT_NAME:
|
|
|
|
|
{
|
2005-08-08 16:06:52 +00:00
|
|
|
|
DWORD required = (wcslen(DevInfo->Data) + 1) * sizeof(WCHAR);
|
2005-07-18 07:17:53 +00:00
|
|
|
|
|
|
|
|
|
if (PropertyRegDataType)
|
|
|
|
|
*PropertyRegDataType = REG_SZ;
|
|
|
|
|
if (RequiredSize)
|
|
|
|
|
*RequiredSize = required;
|
|
|
|
|
if (PropertyBufferSize >= required)
|
|
|
|
|
{
|
2005-08-08 16:06:52 +00:00
|
|
|
|
wcscpy((LPWSTR)PropertyBuffer, DevInfo->Data);
|
2005-07-18 07:17:53 +00:00
|
|
|
|
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:
|
|
|
|
|
{
|
|
|
|
|
FIXME("Property 0x%lx not implemented\n", Property);
|
|
|
|
|
SetLastError(ERROR_NOT_SUPPORTED);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
|
|
|
return ret;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-10-23 12:41:54 +00:00
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(
|
|
|
|
|
IN HDEVINFO DeviceInfoSet,
|
|
|
|
|
IN OUT PSP_DEVINFO_DATA DeviceInfoData,
|
|
|
|
|
IN DWORD Property,
|
|
|
|
|
IN CONST BYTE *PropertyBuffer,
|
|
|
|
|
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,
|
|
|
|
|
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 = L"CompatibleIDs";
|
|
|
|
|
RegistryDataType = REG_MULTI_SZ;
|
|
|
|
|
break;
|
|
|
|
|
case SPDRP_CONFIGFLAGS:
|
|
|
|
|
RegistryPropertyName = L"ConfigFlags";
|
|
|
|
|
RegistryDataType = REG_DWORD;
|
|
|
|
|
break;
|
|
|
|
|
case SPDRP_FRIENDLYNAME:
|
|
|
|
|
RegistryPropertyName = L"FriendlyName";
|
|
|
|
|
RegistryDataType = REG_SZ;
|
|
|
|
|
break;
|
|
|
|
|
case SPDRP_HARDWAREID:
|
|
|
|
|
RegistryPropertyName = L"HardwareID";
|
|
|
|
|
RegistryDataType = REG_MULTI_SZ;
|
|
|
|
|
break;
|
|
|
|
|
case SPDRP_LOCATION_INFORMATION:
|
|
|
|
|
RegistryPropertyName = L"LocationInformation";
|
|
|
|
|
RegistryDataType = REG_SZ;
|
|
|
|
|
break;
|
|
|
|
|
case SPDRP_LOWERFILTERS:
|
|
|
|
|
RegistryPropertyName = L"LowerFilters";
|
|
|
|
|
RegistryDataType = REG_MULTI_SZ;
|
|
|
|
|
break;
|
|
|
|
|
case SPDRP_SECURITY:
|
|
|
|
|
RegistryPropertyName = L"Security";
|
|
|
|
|
RegistryDataType = REG_BINARY;
|
|
|
|
|
break;
|
|
|
|
|
case SPDRP_SERVICE:
|
|
|
|
|
RegistryPropertyName = L"Service";
|
|
|
|
|
RegistryDataType = REG_SZ;
|
|
|
|
|
break;
|
|
|
|
|
case SPDRP_UI_NUMBER_DESC_FORMAT:
|
|
|
|
|
RegistryPropertyName = L"UINumberDescFormat";
|
|
|
|
|
RegistryDataType = REG_SZ;
|
|
|
|
|
break;
|
|
|
|
|
case SPDRP_UPPERFILTERS:
|
|
|
|
|
RegistryPropertyName = L"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:
|
|
|
|
|
{
|
|
|
|
|
FIXME("Property 0x%lx not implemented\n", Property);
|
|
|
|
|
SetLastError(ERROR_NOT_SUPPORTED);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2005-07-03 20:19:55 +00:00
|
|
|
|
|
2005-07-01 23:26:01 +00:00
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiInstallClassA (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiInstallClassA(
|
|
|
|
|
HWND hwndParent,
|
|
|
|
|
PCSTR InfFileName,
|
|
|
|
|
DWORD Flags,
|
|
|
|
|
HSPFILEQ FileQueue)
|
|
|
|
|
{
|
|
|
|
|
UNICODE_STRING FileNameW;
|
|
|
|
|
BOOL Result;
|
|
|
|
|
|
|
|
|
|
if (!RtlCreateUnicodeStringFromAsciiz(&FileNameW, InfFileName))
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Result = SetupDiInstallClassW(hwndParent, FileNameW.Buffer, Flags, FileQueue);
|
|
|
|
|
|
|
|
|
|
RtlFreeUnicodeString(&FileNameW);
|
|
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static HKEY CreateClassKey(HINF hInf)
|
|
|
|
|
{
|
|
|
|
|
WCHAR FullBuffer[MAX_PATH];
|
|
|
|
|
WCHAR Buffer[MAX_PATH];
|
|
|
|
|
DWORD RequiredSize;
|
|
|
|
|
HKEY hClassKey;
|
|
|
|
|
|
|
|
|
|
Buffer[0] = '\\';
|
|
|
|
|
if (!SetupGetLineTextW(NULL,
|
|
|
|
|
hInf,
|
|
|
|
|
Version,
|
|
|
|
|
ClassGUID,
|
|
|
|
|
&Buffer[1],
|
|
|
|
|
MAX_PATH - 1,
|
|
|
|
|
&RequiredSize))
|
|
|
|
|
{
|
2005-07-04 21:54:36 +00:00
|
|
|
|
return INVALID_HANDLE_VALUE;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lstrcpyW(FullBuffer, ControlClass);
|
|
|
|
|
lstrcatW(FullBuffer, Buffer);
|
|
|
|
|
|
2005-07-04 21:54:36 +00:00
|
|
|
|
|
|
|
|
|
if (!SetupGetLineTextW(NULL,
|
2005-07-01 23:26:01 +00:00
|
|
|
|
hInf,
|
|
|
|
|
Version,
|
|
|
|
|
Class,
|
|
|
|
|
Buffer,
|
|
|
|
|
MAX_PATH,
|
|
|
|
|
&RequiredSize))
|
2005-07-04 21:54:36 +00:00
|
|
|
|
{
|
|
|
|
|
RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
|
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
|
}
|
2005-07-01 23:26:01 +00:00
|
|
|
|
|
2005-07-04 21:54:36 +00:00
|
|
|
|
if (ERROR_SUCCESS != RegCreateKeyExW(HKEY_LOCAL_MACHINE,
|
2005-07-01 23:26:01 +00:00
|
|
|
|
FullBuffer,
|
|
|
|
|
0,
|
|
|
|
|
NULL,
|
|
|
|
|
REG_OPTION_NON_VOLATILE,
|
|
|
|
|
KEY_ALL_ACCESS,
|
|
|
|
|
NULL,
|
|
|
|
|
&hClassKey,
|
2005-07-04 21:54:36 +00:00
|
|
|
|
NULL))
|
|
|
|
|
{
|
|
|
|
|
RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
|
|
|
|
|
return INVALID_HANDLE_VALUE;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-07-04 21:54:36 +00:00
|
|
|
|
if (ERROR_SUCCESS != RegSetValueExW(hClassKey,
|
2005-07-01 23:26:01 +00:00
|
|
|
|
Class,
|
|
|
|
|
0,
|
|
|
|
|
REG_SZ,
|
|
|
|
|
(LPBYTE)Buffer,
|
2005-07-04 21:54:36 +00:00
|
|
|
|
RequiredSize * sizeof(WCHAR)))
|
2005-07-01 23:26:01 +00:00
|
|
|
|
{
|
2005-07-04 21:54:36 +00:00
|
|
|
|
RegCloseKey(hClassKey);
|
|
|
|
|
RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
|
|
|
|
|
return INVALID_HANDLE_VALUE;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return hClassKey;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiInstallClassW (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiInstallClassW(
|
|
|
|
|
HWND hwndParent,
|
|
|
|
|
PCWSTR InfFileName,
|
|
|
|
|
DWORD Flags,
|
|
|
|
|
HSPFILEQ FileQueue)
|
|
|
|
|
{
|
|
|
|
|
WCHAR SectionName[MAX_PATH];
|
|
|
|
|
DWORD SectionNameLength = 0;
|
|
|
|
|
HINF hInf;
|
|
|
|
|
BOOL bFileQueueCreated = FALSE;
|
|
|
|
|
HKEY hClassKey;
|
|
|
|
|
|
|
|
|
|
FIXME("not fully implemented\n");
|
|
|
|
|
|
|
|
|
|
if ((Flags & DI_NOVCP) && (FileQueue == NULL || FileQueue == INVALID_HANDLE_VALUE))
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Open the .inf file */
|
|
|
|
|
hInf = SetupOpenInfFileW(InfFileName,
|
|
|
|
|
NULL,
|
|
|
|
|
INF_STYLE_WIN4,
|
|
|
|
|
NULL);
|
|
|
|
|
if (hInf == INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Create or open the class registry key 'HKLM\\CurrentControlSet\\Class\\{GUID}' */
|
|
|
|
|
hClassKey = CreateClassKey(hInf);
|
|
|
|
|
if (hClassKey == INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
|
|
|
|
SetupCloseInfFile(hInf);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2005-07-04 22:22:22 +00:00
|
|
|
|
|
2005-07-01 23:26:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Try to append a layout file */
|
|
|
|
|
#if 0
|
|
|
|
|
SetupOpenAppendInfFileW(NULL, hInf, NULL);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Retrieve the actual section name */
|
|
|
|
|
SetupDiGetActualSectionToInstallW(hInf,
|
|
|
|
|
ClassInstall32,
|
|
|
|
|
SectionName,
|
|
|
|
|
MAX_PATH,
|
|
|
|
|
&SectionNameLength,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
if (!(Flags & DI_NOVCP))
|
|
|
|
|
{
|
|
|
|
|
FileQueue = SetupOpenFileQueue();
|
|
|
|
|
if (FileQueue == INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
|
|
|
|
SetupCloseInfFile(hInf);
|
2005-07-04 22:22:22 +00:00
|
|
|
|
RegCloseKey(hClassKey);
|
2005-07-01 23:26:01 +00:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bFileQueueCreated = TRUE;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
SetupInstallFromInfSectionW(NULL,
|
|
|
|
|
hInf,
|
|
|
|
|
SectionName,
|
|
|
|
|
SPINST_REGISTRY,
|
|
|
|
|
hClassKey,
|
|
|
|
|
NULL,
|
|
|
|
|
0,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
INVALID_HANDLE_VALUE,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
/* FIXME: More code! */
|
|
|
|
|
|
|
|
|
|
if (bFileQueueCreated)
|
|
|
|
|
SetupCloseFileQueue(FileQueue);
|
|
|
|
|
|
|
|
|
|
SetupCloseInfFile(hInf);
|
|
|
|
|
|
2005-07-04 22:22:22 +00:00
|
|
|
|
RegCloseKey(hClassKey);
|
2005-07-01 23:26:01 +00:00
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiOpenClassRegKey (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
HKEY WINAPI SetupDiOpenClassRegKey(
|
|
|
|
|
const GUID* ClassGuid,
|
|
|
|
|
REGSAM samDesired)
|
|
|
|
|
{
|
|
|
|
|
return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
|
|
|
|
|
DIOCR_INSTALLER, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiOpenClassRegKeyExA (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
HKEY WINAPI SetupDiOpenClassRegKeyExA(
|
|
|
|
|
const GUID* ClassGuid,
|
|
|
|
|
REGSAM samDesired,
|
|
|
|
|
DWORD Flags,
|
|
|
|
|
PCSTR MachineName,
|
|
|
|
|
PVOID Reserved)
|
|
|
|
|
{
|
|
|
|
|
PWSTR MachineNameW = NULL;
|
|
|
|
|
HKEY hKey;
|
|
|
|
|
|
|
|
|
|
TRACE("\n");
|
|
|
|
|
|
|
|
|
|
if (MachineName)
|
|
|
|
|
{
|
|
|
|
|
MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
|
|
|
|
|
if (MachineNameW == NULL)
|
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
|
|
|
|
|
Flags, MachineNameW, Reserved);
|
|
|
|
|
|
|
|
|
|
if (MachineNameW)
|
|
|
|
|
MyFree(MachineNameW);
|
|
|
|
|
|
|
|
|
|
return hKey;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiOpenClassRegKeyExW (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
HKEY WINAPI SetupDiOpenClassRegKeyExW(
|
|
|
|
|
const GUID* ClassGuid,
|
|
|
|
|
REGSAM samDesired,
|
|
|
|
|
DWORD Flags,
|
|
|
|
|
PCWSTR MachineName,
|
|
|
|
|
PVOID Reserved)
|
|
|
|
|
{
|
|
|
|
|
LPWSTR lpGuidString;
|
2005-07-03 13:46:33 +00:00
|
|
|
|
LPWSTR lpFullGuidString;
|
|
|
|
|
DWORD dwLength;
|
2005-07-06 22:47:23 +00:00
|
|
|
|
HKEY HKLM;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
HKEY hClassesKey;
|
|
|
|
|
HKEY hClassKey;
|
2005-07-06 22:47:23 +00:00
|
|
|
|
DWORD rc;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
LPCWSTR lpKeyName;
|
|
|
|
|
|
|
|
|
|
if (Flags == DIOCR_INSTALLER)
|
|
|
|
|
{
|
|
|
|
|
lpKeyName = ControlClass;
|
|
|
|
|
}
|
|
|
|
|
else if (Flags == DIOCR_INTERFACE)
|
|
|
|
|
{
|
|
|
|
|
lpKeyName = DeviceClasses;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ERR("Invalid Flags parameter!\n");
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
|
}
|
|
|
|
|
|
2005-07-06 22:47:23 +00:00
|
|
|
|
if (MachineName != NULL)
|
|
|
|
|
{
|
|
|
|
|
rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(rc);
|
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
HKLM = HKEY_LOCAL_MACHINE;
|
|
|
|
|
|
|
|
|
|
rc = RegOpenKeyExW(HKLM,
|
2005-07-01 23:26:01 +00:00
|
|
|
|
lpKeyName,
|
|
|
|
|
0,
|
|
|
|
|
KEY_ALL_ACCESS,
|
2005-07-06 22:47:23 +00:00
|
|
|
|
&hClassesKey);
|
|
|
|
|
if (MachineName != NULL) RegCloseKey(HKLM);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
2005-07-01 23:26:01 +00:00
|
|
|
|
{
|
2005-07-06 22:47:23 +00:00
|
|
|
|
SetLastError(rc);
|
2005-07-01 23:26:01 +00:00
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ClassGuid == NULL)
|
|
|
|
|
return hClassesKey;
|
|
|
|
|
|
|
|
|
|
if (UuidToStringW((UUID*)ClassGuid, &lpGuidString) != RPC_S_OK)
|
|
|
|
|
{
|
2005-07-06 22:47:23 +00:00
|
|
|
|
SetLastError(ERROR_GEN_FAILURE);
|
2005-07-01 23:26:01 +00:00
|
|
|
|
RegCloseKey(hClassesKey);
|
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
|
}
|
|
|
|
|
|
2005-07-03 13:46:33 +00:00
|
|
|
|
dwLength = lstrlenW(lpGuidString);
|
|
|
|
|
lpFullGuidString = HeapAlloc(GetProcessHeap(), 0, (dwLength + 3) * sizeof(WCHAR));
|
|
|
|
|
if (!lpFullGuidString)
|
|
|
|
|
{
|
2005-08-09 20:12:35 +00:00
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
2005-07-03 13:46:33 +00:00
|
|
|
|
RpcStringFreeW(&lpGuidString);
|
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
|
}
|
|
|
|
|
lpFullGuidString[0] = '{';
|
|
|
|
|
memcpy(&lpFullGuidString[1], lpGuidString, dwLength * sizeof(WCHAR));
|
|
|
|
|
lpFullGuidString[dwLength + 1] = '}';
|
2005-07-24 17:21:26 +00:00
|
|
|
|
lpFullGuidString[dwLength + 2] = '\0';
|
2005-07-03 13:46:33 +00:00
|
|
|
|
RpcStringFreeW(&lpGuidString);
|
|
|
|
|
|
2005-07-06 22:47:23 +00:00
|
|
|
|
rc = RegOpenKeyExW(hClassesKey,
|
2005-07-03 13:46:33 +00:00
|
|
|
|
lpFullGuidString,
|
2005-07-01 23:26:01 +00:00
|
|
|
|
0,
|
|
|
|
|
KEY_ALL_ACCESS,
|
2005-07-06 22:47:23 +00:00
|
|
|
|
&hClassKey);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
2005-07-01 23:26:01 +00:00
|
|
|
|
{
|
2005-07-06 22:47:23 +00:00
|
|
|
|
SetLastError(rc);
|
2005-07-03 13:46:33 +00:00
|
|
|
|
HeapFree(GetProcessHeap(), 0, lpFullGuidString);
|
2005-07-01 23:26:01 +00:00
|
|
|
|
RegCloseKey(hClassesKey);
|
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
|
}
|
|
|
|
|
|
2005-07-03 13:46:33 +00:00
|
|
|
|
HeapFree(GetProcessHeap(), 0, lpFullGuidString);
|
2005-07-01 23:26:01 +00:00
|
|
|
|
RegCloseKey(hClassesKey);
|
|
|
|
|
|
|
|
|
|
return hClassKey;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiOpenDeviceInterfaceW(
|
|
|
|
|
HDEVINFO DeviceInfoSet,
|
|
|
|
|
PCWSTR DevicePath,
|
|
|
|
|
DWORD OpenFlags,
|
|
|
|
|
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
|
|
|
|
|
{
|
|
|
|
|
FIXME("%p %s %08lx %p\n",
|
|
|
|
|
DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiOpenDeviceInterfaceA(
|
|
|
|
|
HDEVINFO DeviceInfoSet,
|
|
|
|
|
PCSTR DevicePath,
|
|
|
|
|
DWORD OpenFlags,
|
|
|
|
|
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
|
|
|
|
|
{
|
2005-10-13 10:55:16 +00:00
|
|
|
|
LPWSTR DevicePathW = NULL;
|
|
|
|
|
BOOL bResult;
|
|
|
|
|
|
|
|
|
|
TRACE("%p %s %08lx %p\n", DeviceInfoSet, debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
|
|
|
|
|
|
|
|
|
|
DevicePathW = MultiByteToUnicode(DevicePath, CP_ACP);
|
|
|
|
|
if (DevicePathW == NULL)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
bResult = SetupDiOpenDeviceInterfaceW(DeviceInfoSet,
|
|
|
|
|
DevicePathW, OpenFlags, DeviceInterfaceData);
|
|
|
|
|
|
|
|
|
|
MyFree(DevicePathW);
|
|
|
|
|
|
|
|
|
|
return bResult;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiSetClassInstallParamsA (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiSetClassInstallParamsA(
|
|
|
|
|
HDEVINFO DeviceInfoSet,
|
|
|
|
|
PSP_DEVINFO_DATA DeviceInfoData,
|
|
|
|
|
PSP_CLASSINSTALL_HEADER ClassInstallParams,
|
|
|
|
|
DWORD ClassInstallParamsSize)
|
|
|
|
|
{
|
|
|
|
|
FIXME("%p %p %x %lu\n",DeviceInfoSet, DeviceInfoData,
|
|
|
|
|
ClassInstallParams->InstallFunction, ClassInstallParamsSize);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2005-10-13 10:55:16 +00:00
|
|
|
|
static DWORD
|
|
|
|
|
GetFunctionPointer(
|
|
|
|
|
IN PWSTR InstallerName,
|
|
|
|
|
OUT HMODULE* ModulePointer,
|
|
|
|
|
OUT PVOID* FunctionPointer)
|
|
|
|
|
{
|
|
|
|
|
HMODULE hModule = NULL;
|
|
|
|
|
LPSTR FunctionNameA = NULL;
|
|
|
|
|
PWCHAR Comma;
|
|
|
|
|
DWORD rc;
|
|
|
|
|
|
|
|
|
|
*ModulePointer = NULL;
|
|
|
|
|
*FunctionPointer = NULL;
|
|
|
|
|
|
|
|
|
|
Comma = strchrW(InstallerName, ',');
|
|
|
|
|
if (!Comma)
|
|
|
|
|
{
|
|
|
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* W->A conversion for function name */
|
|
|
|
|
FunctionNameA = UnicodeToMultiByte(Comma + 1, CP_ACP);
|
|
|
|
|
if (!FunctionNameA)
|
|
|
|
|
{
|
|
|
|
|
rc = GetLastError();
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Load library */
|
|
|
|
|
*Comma = '\0';
|
|
|
|
|
hModule = LoadLibraryW(InstallerName);
|
|
|
|
|
*Comma = ',';
|
|
|
|
|
if (!hModule)
|
|
|
|
|
{
|
|
|
|
|
rc = GetLastError();
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Search function */
|
|
|
|
|
*FunctionPointer = GetProcAddress(hModule, FunctionNameA);
|
|
|
|
|
if (!*FunctionPointer)
|
|
|
|
|
{
|
|
|
|
|
rc = GetLastError();
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*ModulePointer = hModule;
|
|
|
|
|
rc = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
|
if (rc != ERROR_SUCCESS && hModule)
|
|
|
|
|
FreeLibrary(hModule);
|
|
|
|
|
MyFree(FunctionNameA);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static DWORD
|
|
|
|
|
FreeFunctionPointer(
|
|
|
|
|
IN HMODULE ModulePointer,
|
|
|
|
|
IN PVOID FunctionPointer)
|
|
|
|
|
{
|
|
|
|
|
if (ModulePointer == NULL)
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
if (FreeLibrary(ModulePointer))
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
else
|
|
|
|
|
return GetLastError();
|
|
|
|
|
}
|
|
|
|
|
|
2005-07-01 23:26:01 +00:00
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiCallClassInstaller (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiCallClassInstaller(
|
2005-08-12 19:03:35 +00:00
|
|
|
|
IN DI_FUNCTION InstallFunction,
|
|
|
|
|
IN HDEVINFO DeviceInfoSet,
|
|
|
|
|
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
|
2005-07-01 23:26:01 +00:00
|
|
|
|
{
|
2005-08-12 19:03:35 +00:00
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
|
|
|
|
|
TRACE("%ld %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
|
|
|
|
|
{
|
2005-10-21 10:13:26 +00:00
|
|
|
|
SP_DEVINSTALL_PARAMS_W InstallParams;
|
2005-08-12 19:03:35 +00:00
|
|
|
|
#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_ALLOW_INSTALL:
|
|
|
|
|
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_REGISTER_COINSTALLERS:
|
|
|
|
|
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
|
|
|
|
|
DefaultHandler = SetupDiRegisterCoDeviceInstallers;
|
|
|
|
|
break;
|
|
|
|
|
case DIF_SELECTBESTCOMPATDRV:
|
|
|
|
|
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
|
|
|
|
|
DefaultHandler = SetupDiSelectBestCompatDrv;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
FIXME("Install function %ld not implemented\n", InstallFunction);
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
}
|
|
|
|
|
|
2005-10-21 10:13:26 +00:00
|
|
|
|
InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
|
|
|
|
|
if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
|
|
|
|
|
/* Don't process this call, as a parameter is invalid */
|
|
|
|
|
CanHandle = 0;
|
|
|
|
|
|
2005-08-12 19:03:35 +00:00
|
|
|
|
if (CanHandle != 0)
|
|
|
|
|
{
|
|
|
|
|
LIST_ENTRY ClassCoInstallersListHead;
|
|
|
|
|
LIST_ENTRY DeviceCoInstallersListHead;
|
2005-10-14 18:09:17 +00:00
|
|
|
|
HMODULE ClassInstallerLibrary = NULL;
|
2005-08-12 19:03:35 +00:00
|
|
|
|
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);
|
|
|
|
|
|
2005-10-06 22:47:13 +00:00
|
|
|
|
if (CanHandle & DEVICE_COINSTALLER)
|
2005-08-12 19:03:35 +00:00
|
|
|
|
{
|
2005-10-06 22:47:13 +00:00
|
|
|
|
FIXME("Doesn't use Device co-installers at the moment\n");
|
2005-08-12 19:03:35 +00:00
|
|
|
|
}
|
2005-10-06 22:47:13 +00:00
|
|
|
|
if (CanHandle & CLASS_COINSTALLER)
|
2005-08-12 19:03:35 +00:00
|
|
|
|
{
|
|
|
|
|
rc = RegOpenKeyEx(
|
|
|
|
|
HKEY_LOCAL_MACHINE,
|
|
|
|
|
L"SYSTEM\\CurrentControlSet\\Control\\CoDeviceInstallers",
|
|
|
|
|
0, /* Options */
|
|
|
|
|
KEY_QUERY_VALUE,
|
|
|
|
|
&hKey);
|
|
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
LPWSTR lpGuidString;
|
|
|
|
|
if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) == RPC_S_OK)
|
|
|
|
|
{
|
2005-10-12 08:14:56 +00:00
|
|
|
|
rc = RegQueryValueExW(hKey, lpGuidString, NULL, &dwRegType, NULL, &dwLength);
|
2005-08-12 19:03:35 +00:00
|
|
|
|
if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
|
|
|
|
|
{
|
|
|
|
|
LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
|
|
|
|
|
if (KeyBuffer != NULL)
|
|
|
|
|
{
|
2005-10-12 08:14:56 +00:00
|
|
|
|
rc = RegQueryValueExW(hKey, lpGuidString, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
|
2005-08-12 19:03:35 +00:00
|
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
LPCWSTR ptr;
|
|
|
|
|
for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
|
|
|
|
|
{
|
2005-10-06 22:47:13 +00:00
|
|
|
|
/* Add coinstaller to ClassCoInstallersListHead list */
|
|
|
|
|
FIXME("Class coinstaller is '%S'. UNIMPLEMENTED!\n", ptr);
|
2005-08-12 19:03:35 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, KeyBuffer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
RpcStringFreeW(&lpGuidString);
|
|
|
|
|
}
|
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-10-21 10:13:26 +00:00
|
|
|
|
if ((CanHandle & CLASS_INSTALLER) && !(InstallParams.FlagsEx & DI_FLAGSEX_CI_FAILED))
|
2005-08-12 19:03:35 +00:00
|
|
|
|
{
|
|
|
|
|
hKey = SetupDiOpenClassRegKey(&DeviceInfoData->ClassGuid, KEY_QUERY_VALUE);
|
|
|
|
|
if (hKey != INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
|
|
|
|
rc = RegQueryValueExW(hKey, L"Installer32", NULL, &dwRegType, NULL, &dwLength);
|
|
|
|
|
if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
|
|
|
|
|
{
|
|
|
|
|
LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
|
|
|
|
|
if (KeyBuffer != NULL)
|
|
|
|
|
{
|
|
|
|
|
rc = RegQueryValueExW(hKey, L"Installer32", NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
|
|
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
|
{
|
2005-10-13 10:55:16 +00:00
|
|
|
|
/* Get ClassInstaller function pointer */
|
2005-10-21 10:13:26 +00:00
|
|
|
|
if (GetFunctionPointer(KeyBuffer, &ClassInstallerLibrary, (PVOID*)&ClassInstaller) != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
InstallParams.FlagsEx |= DI_FLAGSEX_CI_FAILED;
|
|
|
|
|
SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
|
|
|
|
|
}
|
2005-08-12 19:03:35 +00:00
|
|
|
|
}
|
|
|
|
|
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 = (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 = (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)
|
2005-10-13 10:55:16 +00:00
|
|
|
|
{
|
2005-08-12 19:03:35 +00:00
|
|
|
|
rc = (*ClassInstaller)(InstallFunction, DeviceInfoSet, DeviceInfoData);
|
2005-10-13 10:55:16 +00:00
|
|
|
|
FreeFunctionPointer(ClassInstallerLibrary, ClassInstaller);
|
|
|
|
|
}
|
2005-08-12 19:03:35 +00:00
|
|
|
|
else
|
|
|
|
|
rc = ERROR_DI_DO_DEFAULT;
|
|
|
|
|
|
|
|
|
|
/* Call default handler */
|
|
|
|
|
if (rc == ERROR_DI_DO_DEFAULT)
|
|
|
|
|
{
|
2005-10-21 10:13:26 +00:00
|
|
|
|
if (DefaultHandler && !(InstallParams.Flags & DI_NODI_DEFAULTACTION))
|
2005-08-12 19:03:35 +00:00
|
|
|
|
{
|
|
|
|
|
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 = (struct CoInstallerElement *)ListEntry;
|
|
|
|
|
if (coinstaller->DoPostProcessing)
|
|
|
|
|
{
|
|
|
|
|
Context.InstallResult = rc;
|
|
|
|
|
Context.PrivateData = coinstaller->PrivateData;
|
|
|
|
|
rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
|
|
|
|
|
}
|
2005-10-13 10:55:16 +00:00
|
|
|
|
FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
|
2005-08-12 19:03:35 +00:00
|
|
|
|
ListEntry = ListEntry->Flink;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Call Device co-installers that required postprocessing */
|
|
|
|
|
ListEntry = DeviceCoInstallersListHead.Flink;
|
|
|
|
|
while (ListEntry != &DeviceCoInstallersListHead)
|
|
|
|
|
{
|
|
|
|
|
struct CoInstallerElement *coinstaller = (struct CoInstallerElement *)ListEntry;
|
|
|
|
|
if (coinstaller->DoPostProcessing)
|
|
|
|
|
{
|
|
|
|
|
Context.InstallResult = rc;
|
|
|
|
|
Context.PrivateData = coinstaller->PrivateData;
|
|
|
|
|
rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
|
|
|
|
|
}
|
2005-10-13 10:55:16 +00:00
|
|
|
|
FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
|
2005-08-12 19:03:35 +00:00
|
|
|
|
ListEntry = ListEntry->Flink;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Free allocated memory */
|
|
|
|
|
while (!IsListEmpty(&ClassCoInstallersListHead))
|
|
|
|
|
{
|
|
|
|
|
ListEntry = RemoveHeadList(&ClassCoInstallersListHead);
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, ListEntry);
|
|
|
|
|
}
|
|
|
|
|
while (!IsListEmpty(&DeviceCoInstallersListHead))
|
|
|
|
|
{
|
|
|
|
|
ListEntry = RemoveHeadList(&DeviceCoInstallersListHead);
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, ListEntry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = (rc == NO_ERROR);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
|
|
|
return ret;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiGetDeviceInstallParamsA(
|
2005-08-12 19:03:35 +00:00
|
|
|
|
IN HDEVINFO DeviceInfoSet,
|
|
|
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
|
|
|
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,
|
|
|
|
|
OUT PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
|
2005-07-01 23:26:01 +00:00
|
|
|
|
{
|
2005-10-21 10:13:26 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiSetDeviceInstallParamsW(
|
|
|
|
|
IN HDEVINFO DeviceInfoSet,
|
|
|
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
|
PSP_DEVINSTALL_PARAMS_W Destination;
|
|
|
|
|
|
|
|
|
|
/* FIXME: Validate parameters */
|
|
|
|
|
|
|
|
|
|
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;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-10-14 16:53:18 +00:00
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiCreateDevRegKey (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 hClassKey = INVALID_HANDLE_VALUE;
|
|
|
|
|
HKEY hDeviceKey = INVALID_HANDLE_VALUE;
|
|
|
|
|
HKEY hKey = INVALID_HANDLE_VALUE;
|
|
|
|
|
|
|
|
|
|
if (Scope == DICS_FLAG_CONFIGSPECIFIC)
|
|
|
|
|
{
|
|
|
|
|
FIXME("DICS_FLAG_CONFIGSPECIFIC case unimplemented\n");
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (KeyType == DIREG_DEV)
|
|
|
|
|
{
|
|
|
|
|
FIXME("DIREG_DEV case unimplemented\n");
|
|
|
|
|
}
|
|
|
|
|
else /* KeyType == DIREG_DRV */
|
|
|
|
|
{
|
|
|
|
|
if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) != RPC_S_OK)
|
|
|
|
|
goto cleanup;
|
|
|
|
|
/* The driver key is in HKLM\System\CurrentControlSet\Control\Class\{GUID}\Index */
|
|
|
|
|
DriverKey = HeapAlloc(GetProcessHeap(), 0, (wcslen(lpGuidString) + 7) * sizeof(WCHAR) + sizeof(UNICODE_STRING));
|
|
|
|
|
if (!DriverKey)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
wcscpy(DriverKey, L"{");
|
|
|
|
|
wcscat(DriverKey, lpGuidString);
|
|
|
|
|
wcscat(DriverKey, L"}\\");
|
|
|
|
|
pDeviceInstance = &DriverKey[wcslen(DriverKey)];
|
|
|
|
|
rc = RegOpenKeyExW(list->HKLM,
|
|
|
|
|
ControlClass,
|
|
|
|
|
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,
|
2005-10-23 11:35:58 +00:00
|
|
|
|
#if _WIN32_WINNT >= 0x502
|
2005-10-14 16:53:18 +00:00
|
|
|
|
KEY_READ | KEY_WRITE,
|
2005-10-23 11:35:58 +00:00
|
|
|
|
#else
|
|
|
|
|
KEY_ALL_ACCESS,
|
|
|
|
|
#endif
|
2005-10-14 16:53:18 +00:00
|
|
|
|
NULL,
|
|
|
|
|
&hKey,
|
|
|
|
|
&Disposition);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(rc);
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
if (Disposition == REG_CREATED_NEW_KEY)
|
|
|
|
|
break;
|
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
|
hKey = INVALID_HANDLE_VALUE;
|
|
|
|
|
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, L"Driver", 0, REG_SZ, (const BYTE *)DriverKey, (wcslen(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 (hClassKey != INVALID_HANDLE_VALUE)
|
|
|
|
|
RegCloseKey(hClassKey);
|
|
|
|
|
if (hDeviceKey != INVALID_HANDLE_VALUE)
|
|
|
|
|
RegCloseKey(hDeviceKey);
|
|
|
|
|
if (hKey != INVALID_HANDLE_VALUE && hKey != ret)
|
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TRACE("Returning 0x%p\n", ret);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2005-07-01 23:26:01 +00:00
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiOpenDevRegKey (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
HKEY WINAPI SetupDiOpenDevRegKey(
|
|
|
|
|
HDEVINFO DeviceInfoSet,
|
|
|
|
|
PSP_DEVINFO_DATA DeviceInfoData,
|
|
|
|
|
DWORD Scope,
|
|
|
|
|
DWORD HwProfile,
|
|
|
|
|
DWORD KeyType,
|
|
|
|
|
REGSAM samDesired)
|
|
|
|
|
{
|
2005-10-14 16:53:18 +00:00
|
|
|
|
struct DeviceInfoSet *list;
|
|
|
|
|
HKEY ret = INVALID_HANDLE_VALUE;
|
|
|
|
|
|
|
|
|
|
TRACE("%p %p %lu %lu %lu 0x%lx\n", DeviceInfoSet, DeviceInfoData,
|
2005-07-01 23:26:01 +00:00
|
|
|
|
Scope, HwProfile, KeyType, samDesired);
|
2005-10-14 16:53:18 +00:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
|
HKEY hKey = INVALID_HANDLE_VALUE;
|
|
|
|
|
HKEY hRootKey = INVALID_HANDLE_VALUE;
|
|
|
|
|
struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
|
|
|
|
|
LPWSTR DriverKey = NULL;
|
|
|
|
|
DWORD dwLength = 0;
|
|
|
|
|
DWORD dwRegType;
|
|
|
|
|
DWORD rc;
|
|
|
|
|
|
|
|
|
|
if (Scope == DICS_FLAG_CONFIGSPECIFIC)
|
|
|
|
|
{
|
|
|
|
|
FIXME("DICS_FLAG_CONFIGSPECIFIC case unimplemented\n");
|
|
|
|
|
}
|
|
|
|
|
else /* Scope == DICS_FLAG_GLOBAL */
|
|
|
|
|
{
|
|
|
|
|
rc = RegOpenKeyExW(
|
|
|
|
|
list->HKLM,
|
|
|
|
|
EnumKeyName,
|
|
|
|
|
0, /* Options */
|
|
|
|
|
KEY_ENUMERATE_SUB_KEYS,
|
|
|
|
|
&hRootKey);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(rc);
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
rc = RegOpenKeyExW(
|
|
|
|
|
hRootKey,
|
|
|
|
|
deviceInfo->DeviceName,
|
|
|
|
|
0, /* Options */
|
|
|
|
|
KeyType == DIREG_DEV ? samDesired : KEY_QUERY_VALUE,
|
|
|
|
|
&hKey);
|
|
|
|
|
RegCloseKey(hRootKey);
|
|
|
|
|
hRootKey = INVALID_HANDLE_VALUE;
|
|
|
|
|
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, L"Driver", NULL, &dwRegType, NULL, &dwLength);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(rc);
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
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, L"Driver", NULL, &dwRegType, (LPBYTE)DriverKey, &dwLength);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(rc);
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
|
hKey = INVALID_HANDLE_VALUE;
|
|
|
|
|
/* Need to open the driver key */
|
|
|
|
|
rc = RegOpenKeyExW(
|
|
|
|
|
list->HKLM,
|
|
|
|
|
ControlClass,
|
|
|
|
|
0, /* Options */
|
|
|
|
|
KEY_ENUMERATE_SUB_KEYS,
|
|
|
|
|
&hRootKey);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(rc);
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
rc = RegOpenKeyExW(
|
|
|
|
|
hRootKey,
|
|
|
|
|
DriverKey,
|
|
|
|
|
0, /* Options */
|
|
|
|
|
samDesired,
|
|
|
|
|
&hKey);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(rc);
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
ret = hKey;
|
|
|
|
|
}
|
|
|
|
|
cleanup:
|
|
|
|
|
if (hRootKey != INVALID_HANDLE_VALUE)
|
|
|
|
|
RegCloseKey(hRootKey);
|
|
|
|
|
if (hKey != INVALID_HANDLE_VALUE && hKey != ret)
|
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TRACE("Returning 0x%p\n", ret);
|
|
|
|
|
return ret;
|
2005-07-01 23:26:01 +00:00
|
|
|
|
}
|
2005-07-03 13:46:33 +00:00
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiCreateDeviceInfoA (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI SetupDiCreateDeviceInfoA(
|
|
|
|
|
HDEVINFO DeviceInfoSet,
|
|
|
|
|
PCSTR DeviceName,
|
2005-08-07 13:06:30 +00:00
|
|
|
|
CONST GUID *ClassGuid,
|
2005-07-03 13:46:33 +00:00
|
|
|
|
PCSTR DeviceDescription,
|
|
|
|
|
HWND hwndParent,
|
|
|
|
|
DWORD CreationFlags,
|
|
|
|
|
PSP_DEVINFO_DATA DeviceInfoData)
|
|
|
|
|
{
|
|
|
|
|
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(
|
|
|
|
|
HDEVINFO DeviceInfoSet,
|
|
|
|
|
PCWSTR DeviceName,
|
2005-08-07 13:06:30 +00:00
|
|
|
|
CONST GUID *ClassGuid,
|
2005-07-03 13:46:33 +00:00
|
|
|
|
PCWSTR DeviceDescription,
|
|
|
|
|
HWND hwndParent,
|
|
|
|
|
DWORD CreationFlags,
|
|
|
|
|
PSP_DEVINFO_DATA DeviceInfoData)
|
|
|
|
|
{
|
2005-08-08 16:09:48 +00:00
|
|
|
|
struct DeviceInfoSet *list;
|
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
|
|
|
|
|
TRACE("%p %S %s %S %p %lx %p\n", DeviceInfoSet, DeviceName,
|
|
|
|
|
debugstr_guid(ClassGuid), 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_PARAMETER);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SP_DEVINFO_DATA DevInfo;
|
|
|
|
|
|
|
|
|
|
if (CreationFlags & DICD_GENERATE_ID)
|
|
|
|
|
{
|
|
|
|
|
/* Generate a new unique ID for this device */
|
|
|
|
|
SetLastError(ERROR_GEN_FAILURE);
|
|
|
|
|
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;
|
|
|
|
|
|
2005-08-12 19:00:04 +00:00
|
|
|
|
/* FIXME: ClassGuid can be NULL */
|
2005-08-09 20:12:35 +00:00
|
|
|
|
if (CreateDeviceInfoElement(DeviceName, ClassGuid, &deviceInfo))
|
2005-08-08 16:09:48 +00:00
|
|
|
|
{
|
|
|
|
|
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 = 0; /* FIXME */
|
|
|
|
|
DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
|
|
|
|
|
ret = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* Helper functions for SetupDiBuildDriverInfoList
|
|
|
|
|
*/
|
|
|
|
|
static BOOL
|
|
|
|
|
AddDriverToList(
|
|
|
|
|
IN PLIST_ENTRY DriverListHead,
|
|
|
|
|
IN DWORD DriverType, /* SPDIT_CLASSDRIVER or SPDIT_COMPATDRIVER */
|
2005-10-13 10:55:16 +00:00
|
|
|
|
IN LPGUID ClassGuid,
|
2005-08-08 16:09:48 +00:00
|
|
|
|
IN INFCONTEXT ContextDevice,
|
2005-10-24 09:16:34 +00:00
|
|
|
|
IN struct InfFileDetails *InfFileDetails,
|
2005-08-08 16:09:48 +00:00
|
|
|
|
IN LPCWSTR InfFile,
|
|
|
|
|
IN LPCWSTR ProviderName,
|
|
|
|
|
IN LPCWSTR ManufacturerName,
|
2005-10-06 22:47:13 +00:00
|
|
|
|
IN LPCWSTR MatchingId,
|
2005-08-08 16:09:48 +00:00
|
|
|
|
FILETIME DriverDate,
|
|
|
|
|
DWORDLONG DriverVersion,
|
2005-08-09 16:13:50 +00:00
|
|
|
|
IN DWORD Rank)
|
2005-08-08 16:09:48 +00:00
|
|
|
|
{
|
2005-10-06 22:47:13 +00:00
|
|
|
|
struct DriverInfoElement *driverInfo = NULL;
|
2005-10-22 16:25:48 +00:00
|
|
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
2005-08-08 16:09:48 +00:00
|
|
|
|
DWORD RequiredSize = 128; /* Initial buffer size */
|
|
|
|
|
BOOL Result = FALSE;
|
2005-08-27 14:59:22 +00:00
|
|
|
|
PLIST_ENTRY PreviousEntry;
|
2005-08-08 16:09:48 +00:00
|
|
|
|
LPWSTR InfInstallSection = NULL;
|
2005-10-06 22:47:13 +00:00
|
|
|
|
BOOL ret = FALSE;
|
2005-08-08 16:09:48 +00:00
|
|
|
|
|
|
|
|
|
driverInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DriverInfoElement));
|
|
|
|
|
if (!driverInfo)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
2005-10-06 22:47:13 +00:00
|
|
|
|
goto cleanup;
|
2005-08-08 16:09:48 +00:00
|
|
|
|
}
|
2005-10-06 22:47:13 +00:00
|
|
|
|
memset(driverInfo, 0, sizeof(struct DriverInfoElement));
|
2005-08-08 16:09:48 +00:00
|
|
|
|
|
2005-10-22 16:25:48 +00:00
|
|
|
|
driverInfo->Details.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
|
|
|
|
|
driverInfo->Details.Reserved = (ULONG_PTR)driverInfo;
|
|
|
|
|
|
|
|
|
|
/* Copy InfFileName field */
|
2005-10-23 10:40:25 +00:00
|
|
|
|
wcsncpy(driverInfo->Details.InfFileName, InfFile, MAX_PATH - 1);
|
|
|
|
|
driverInfo->Details.InfFileName[MAX_PATH - 1] = '\0';
|
2005-10-22 16:25:48 +00:00
|
|
|
|
|
|
|
|
|
/* Fill InfDate field */
|
|
|
|
|
/* FIXME: hFile = CreateFile(driverInfo->Details.InfFileName,
|
|
|
|
|
GENERIC_READ, FILE_SHARE_READ,
|
|
|
|
|
NULL, OPEN_EXISTING, 0, NULL);
|
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
|
|
|
goto cleanup;
|
|
|
|
|
Result = GetFileTime(hFile, NULL, NULL, &driverInfo->Details.InfDate);
|
|
|
|
|
if (!Result)
|
|
|
|
|
goto cleanup;*/
|
|
|
|
|
|
|
|
|
|
/* Fill SectionName field */
|
|
|
|
|
Result = SetupGetStringFieldW(
|
|
|
|
|
&ContextDevice,
|
|
|
|
|
1,
|
|
|
|
|
driverInfo->Details.SectionName, LINE_LEN,
|
|
|
|
|
NULL);
|
2005-09-25 21:18:27 +00:00
|
|
|
|
if (!Result)
|
2005-10-06 22:47:13 +00:00
|
|
|
|
goto cleanup;
|
2005-09-25 21:18:27 +00:00
|
|
|
|
|
2005-10-22 16:25:48 +00:00
|
|
|
|
/* Fill DrvDescription field */
|
|
|
|
|
Result = SetupGetStringFieldW(
|
|
|
|
|
&ContextDevice,
|
|
|
|
|
0, /* Field index */
|
|
|
|
|
driverInfo->Details.DrvDescription, LINE_LEN,
|
|
|
|
|
NULL);
|
2005-09-25 21:18:27 +00:00
|
|
|
|
|
2005-10-06 22:47:13 +00:00
|
|
|
|
/* Copy MatchingId information */
|
|
|
|
|
driverInfo->MatchingId = HeapAlloc(GetProcessHeap(), 0, (wcslen(MatchingId) + 1) * sizeof(WCHAR));
|
|
|
|
|
if (!driverInfo->MatchingId)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
RtlCopyMemory(driverInfo->MatchingId, MatchingId, (wcslen(MatchingId) + 1) * sizeof(WCHAR));
|
|
|
|
|
|
|
|
|
|
/* Get inf install section */
|
2005-08-08 16:09:48 +00:00
|
|
|
|
Result = FALSE;
|
|
|
|
|
RequiredSize = 128; /* Initial buffer size */
|
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
|
while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
|
|
|
{
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, InfInstallSection);
|
|
|
|
|
InfInstallSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
|
|
|
|
|
if (!InfInstallSection)
|
2005-10-06 22:47:13 +00:00
|
|
|
|
goto cleanup;
|
2005-08-08 16:09:48 +00:00
|
|
|
|
Result = SetupGetStringFieldW(
|
|
|
|
|
&ContextDevice,
|
|
|
|
|
1, /* Field index */
|
|
|
|
|
InfInstallSection, RequiredSize,
|
|
|
|
|
&RequiredSize);
|
|
|
|
|
}
|
|
|
|
|
if (!Result)
|
2005-10-06 22:47:13 +00:00
|
|
|
|
goto cleanup;
|
2005-08-08 16:09:48 +00:00
|
|
|
|
|
2005-08-09 16:13:50 +00:00
|
|
|
|
TRACE("Adding driver '%S' [%S/%S] (Rank 0x%lx)\n",
|
2005-10-22 16:25:48 +00:00
|
|
|
|
driverInfo->Details.DrvDescription, InfFile, InfInstallSection, Rank);
|
2005-08-08 16:09:48 +00:00
|
|
|
|
|
2005-08-27 14:59:22 +00:00
|
|
|
|
driverInfo->DriverRank = Rank;
|
2005-10-13 10:55:16 +00:00
|
|
|
|
memcpy(&driverInfo->ClassGuid, ClassGuid, sizeof(GUID));
|
2005-08-08 16:09:48 +00:00
|
|
|
|
driverInfo->Info.DriverType = DriverType;
|
|
|
|
|
driverInfo->Info.Reserved = (ULONG_PTR)driverInfo;
|
2005-10-22 16:25:48 +00:00
|
|
|
|
wcsncpy(driverInfo->Info.Description, driverInfo->Details.DrvDescription, LINE_LEN - 1);
|
2005-08-08 16:09:48 +00:00
|
|
|
|
driverInfo->Info.Description[LINE_LEN - 1] = '\0';
|
|
|
|
|
wcsncpy(driverInfo->Info.MfgName, ManufacturerName, LINE_LEN - 1);
|
|
|
|
|
driverInfo->Info.MfgName[LINE_LEN - 1] = '\0';
|
|
|
|
|
if (ProviderName)
|
|
|
|
|
{
|
|
|
|
|
wcsncpy(driverInfo->Info.ProviderName, ProviderName, LINE_LEN - 1);
|
|
|
|
|
driverInfo->Info.ProviderName[LINE_LEN - 1] = '\0';
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
driverInfo->Info.ProviderName[0] = '\0';
|
|
|
|
|
driverInfo->Info.DriverDate = DriverDate;
|
|
|
|
|
driverInfo->Info.DriverVersion = DriverVersion;
|
2005-10-24 09:39:53 +00:00
|
|
|
|
ReferenceInfFile(InfFileDetails);
|
2005-10-24 09:16:34 +00:00
|
|
|
|
driverInfo->InfFileDetails = InfFileDetails;
|
2005-08-27 14:59:22 +00:00
|
|
|
|
|
|
|
|
|
/* Insert current driver in driver list, according to its rank */
|
|
|
|
|
PreviousEntry = DriverListHead->Flink;
|
|
|
|
|
while (PreviousEntry != DriverListHead)
|
|
|
|
|
{
|
|
|
|
|
if (((struct DriverInfoElement *)PreviousEntry)->DriverRank >= Rank)
|
|
|
|
|
{
|
|
|
|
|
/* Insert before the current item */
|
|
|
|
|
InsertHeadList(PreviousEntry, &driverInfo->ListEntry);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (PreviousEntry == DriverListHead)
|
|
|
|
|
{
|
|
|
|
|
/* Insert at the end of the list */
|
|
|
|
|
InsertTailList(DriverListHead, &driverInfo->ListEntry);
|
|
|
|
|
}
|
2005-08-08 16:09:48 +00:00
|
|
|
|
|
2005-10-06 22:47:13 +00:00
|
|
|
|
ret = TRUE;
|
|
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
|
if (!ret)
|
|
|
|
|
{
|
|
|
|
|
if (driverInfo)
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId);
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, driverInfo);
|
|
|
|
|
}
|
2005-10-22 16:25:48 +00:00
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
|
|
|
CloseHandle(hFile);
|
2005-08-08 16:09:48 +00:00
|
|
|
|
HeapFree(GetProcessHeap(), 0, InfInstallSection);
|
2005-10-06 22:47:13 +00:00
|
|
|
|
|
|
|
|
|
return ret;
|
2005-08-08 16:09:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOL
|
|
|
|
|
GetVersionInformationFromInfFile(
|
|
|
|
|
IN HINF hInf,
|
|
|
|
|
OUT LPGUID ClassGuid,
|
|
|
|
|
OUT LPWSTR* pProviderName,
|
|
|
|
|
OUT FILETIME* DriverDate,
|
|
|
|
|
OUT DWORDLONG* DriverVersion)
|
|
|
|
|
{
|
|
|
|
|
DWORD RequiredSize;
|
|
|
|
|
WCHAR guidW[MAX_GUID_STRING_LEN + 1];
|
2005-10-06 22:47:13 +00:00
|
|
|
|
LPWSTR DriverVer = NULL;
|
2005-08-08 16:09:48 +00:00
|
|
|
|
LPWSTR ProviderName = NULL;
|
2005-10-06 22:47:13 +00:00
|
|
|
|
LPWSTR pComma; /* Points into DriverVer */
|
|
|
|
|
LPWSTR pVersion = NULL; /* Points into DriverVer */
|
|
|
|
|
SYSTEMTIME SystemTime;
|
2005-08-08 16:09:48 +00:00
|
|
|
|
BOOL Result;
|
2005-10-06 22:47:13 +00:00
|
|
|
|
BOOL ret = FALSE; /* Final result */
|
2005-08-08 16:09:48 +00:00
|
|
|
|
|
2005-10-06 22:47:13 +00:00
|
|
|
|
/* Get class Guid */
|
2005-08-08 16:09:48 +00:00
|
|
|
|
if (!SetupGetLineTextW(
|
|
|
|
|
NULL, /* Context */
|
|
|
|
|
hInf,
|
|
|
|
|
L"Version", L"ClassGUID",
|
|
|
|
|
guidW, sizeof(guidW),
|
|
|
|
|
NULL /* Required size */))
|
|
|
|
|
{
|
2005-10-06 22:47:13 +00:00
|
|
|
|
goto cleanup;
|
2005-08-08 16:09:48 +00:00
|
|
|
|
}
|
|
|
|
|
guidW[37] = '\0'; /* Replace the } by a NULL character */
|
|
|
|
|
if (UuidFromStringW(&guidW[1], ClassGuid) != RPC_S_OK)
|
|
|
|
|
{
|
2005-10-06 22:47:13 +00:00
|
|
|
|
SetLastError(ERROR_GEN_FAILURE);
|
|
|
|
|
goto cleanup;
|
2005-08-08 16:09:48 +00:00
|
|
|
|
}
|
2005-10-06 22:47:13 +00:00
|
|
|
|
|
|
|
|
|
/* Get provider name */
|
2005-08-08 16:09:48 +00:00
|
|
|
|
Result = SetupGetLineTextW(
|
|
|
|
|
NULL, /* Context */
|
|
|
|
|
hInf, L"Version", L"Provider",
|
|
|
|
|
NULL, 0,
|
|
|
|
|
&RequiredSize);
|
2005-10-06 22:47:13 +00:00
|
|
|
|
if (Result)
|
2005-08-08 16:09:48 +00:00
|
|
|
|
{
|
2005-10-06 22:47:13 +00:00
|
|
|
|
/* We know know the needed buffer size */
|
2005-08-08 16:09:48 +00:00
|
|
|
|
ProviderName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
|
|
|
|
|
if (!ProviderName)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
2005-10-06 22:47:13 +00:00
|
|
|
|
goto cleanup;
|
2005-08-08 16:09:48 +00:00
|
|
|
|
}
|
|
|
|
|
Result = SetupGetLineTextW(
|
|
|
|
|
NULL, /* Context */
|
|
|
|
|
hInf, L"Version", L"Provider",
|
|
|
|
|
ProviderName, RequiredSize,
|
|
|
|
|
&RequiredSize);
|
|
|
|
|
}
|
2005-10-06 22:47:13 +00:00
|
|
|
|
if (!Result)
|
|
|
|
|
goto cleanup;
|
|
|
|
|
*pProviderName = ProviderName;
|
|
|
|
|
|
|
|
|
|
/* Read the "DriverVer" value */
|
|
|
|
|
Result = SetupGetLineTextW(
|
|
|
|
|
NULL, /* Context */
|
|
|
|
|
hInf, L"Version", L"DriverVer",
|
|
|
|
|
NULL, 0,
|
|
|
|
|
&RequiredSize);
|
|
|
|
|
if (Result)
|
|
|
|
|
{
|
|
|
|
|
/* We know know the needed buffer size */
|
|
|
|
|
DriverVer = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
|
|
|
|
|
if (!DriverVer)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
Result = SetupGetLineTextW(
|
|
|
|
|
NULL, /* Context */
|
|
|
|
|
hInf, L"Version", L"DriverVer",
|
|
|
|
|
DriverVer, RequiredSize,
|
|
|
|
|
&RequiredSize);
|
|
|
|
|
}
|
|
|
|
|
if (!Result)
|
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
|
|
/* Get driver date and driver version, by analyzing the "DriverVer" value */
|
|
|
|
|
pComma = wcschr(DriverVer, ',');
|
|
|
|
|
if (pComma != NULL)
|
|
|
|
|
{
|
|
|
|
|
*pComma = UNICODE_NULL;
|
|
|
|
|
pVersion = pComma + 1;
|
|
|
|
|
}
|
|
|
|
|
/* Get driver date version. Invalid date = 00/00/00 */
|
|
|
|
|
memset(DriverDate, 0, sizeof(FILETIME));
|
|
|
|
|
if (wcslen(DriverVer) == 10
|
|
|
|
|
&& (DriverVer[2] == '-' || DriverVer[2] == '/')
|
|
|
|
|
&& (DriverVer[5] == '-' || DriverVer[5] == '/'))
|
|
|
|
|
{
|
|
|
|
|
memset(&SystemTime, 0, sizeof(SYSTEMTIME));
|
|
|
|
|
DriverVer[2] = DriverVer[5] = UNICODE_NULL;
|
|
|
|
|
SystemTime.wMonth = ((DriverVer[0] - '0') * 10) + DriverVer[1] - '0';
|
|
|
|
|
SystemTime.wDay = ((DriverVer[3] - '0') * 10) + DriverVer[4] - '0';
|
|
|
|
|
SystemTime.wYear = ((DriverVer[6] - '0') * 1000) + ((DriverVer[7] - '0') * 100) + ((DriverVer[8] - '0') * 10) + DriverVer[9] - '0';
|
|
|
|
|
SystemTimeToFileTime(&SystemTime, DriverDate);
|
|
|
|
|
}
|
|
|
|
|
/* Get driver version. Invalid version = 0.0.0.0 */
|
2005-09-26 11:14:34 +00:00
|
|
|
|
*DriverVersion = 0;
|
2005-10-06 22:47:13 +00:00
|
|
|
|
/* FIXME: use pVersion to fill DriverVersion variable */
|
2005-08-08 16:09:48 +00:00
|
|
|
|
|
2005-10-06 22:47:13 +00:00
|
|
|
|
ret = TRUE;
|
|
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
|
if (!ret)
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, ProviderName);
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, DriverVer);
|
|
|
|
|
|
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
|
|
|
return ret;
|
2005-08-08 16:09:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiBuildDriverInfoList (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI
|
|
|
|
|
SetupDiBuildDriverInfoList(
|
|
|
|
|
IN HDEVINFO DeviceInfoSet,
|
|
|
|
|
IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
|
|
|
|
|
IN DWORD DriverType)
|
|
|
|
|
{
|
|
|
|
|
struct DeviceInfoSet *list;
|
2005-10-21 10:13:26 +00:00
|
|
|
|
SP_DEVINSTALL_PARAMS_W InstallParams;
|
2005-08-08 16:09:48 +00:00
|
|
|
|
PVOID Buffer = NULL;
|
2005-10-24 09:16:34 +00:00
|
|
|
|
struct InfFileDetails *currentInfFileDetails = NULL;
|
2005-08-08 16:09:48 +00:00
|
|
|
|
LPWSTR ProviderName = NULL;
|
|
|
|
|
LPWSTR ManufacturerName = NULL;
|
2005-10-23 10:40:25 +00:00
|
|
|
|
WCHAR ManufacturerSection[LINE_LEN + 1];
|
2005-08-08 16:09:48 +00:00
|
|
|
|
LPWSTR HardwareIDs = NULL;
|
|
|
|
|
LPWSTR CompatibleIDs = NULL;
|
|
|
|
|
FILETIME DriverDate;
|
2005-10-06 23:04:00 +00:00
|
|
|
|
DWORDLONG DriverVersion = 0;
|
2005-08-08 16:09:48 +00:00
|
|
|
|
DWORD RequiredSize;
|
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
|
|
|
|
|
TRACE("%p %p %ld\n", DeviceInfoSet, DeviceInfoData, DriverType);
|
|
|
|
|
|
|
|
|
|
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->HKLM != HKEY_LOCAL_MACHINE)
|
|
|
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
|
|
|
else if (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER)
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
else if (DriverType == SPDIT_CLASSDRIVER && DeviceInfoData)
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData)
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
|
|
|
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
|
|
|
else
|
|
|
|
|
{
|
2005-10-21 10:13:26 +00:00
|
|
|
|
BOOL Result;
|
|
|
|
|
|
|
|
|
|
InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
|
|
|
|
|
Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
|
|
|
|
|
if (!Result)
|
|
|
|
|
goto done;
|
2005-08-08 16:09:48 +00:00
|
|
|
|
|
|
|
|
|
if (DriverType == SPDIT_COMPATDRIVER)
|
|
|
|
|
{
|
|
|
|
|
/* Get hardware IDs list */
|
|
|
|
|
Result = FALSE;
|
|
|
|
|
RequiredSize = 512; /* Initial buffer size */
|
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
|
while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
|
|
|
{
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, HardwareIDs);
|
2005-09-02 18:51:32 +00:00
|
|
|
|
HardwareIDs = HeapAlloc(GetProcessHeap(), 0, RequiredSize);
|
2005-08-08 16:09:48 +00:00
|
|
|
|
if (!HardwareIDs)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
Result = SetupDiGetDeviceRegistryPropertyW(
|
|
|
|
|
DeviceInfoSet,
|
|
|
|
|
DeviceInfoData,
|
|
|
|
|
SPDRP_HARDWAREID,
|
|
|
|
|
NULL,
|
|
|
|
|
(PBYTE)HardwareIDs,
|
|
|
|
|
RequiredSize,
|
|
|
|
|
&RequiredSize);
|
|
|
|
|
}
|
|
|
|
|
if (!Result)
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
|
|
/* Get compatible IDs list */
|
|
|
|
|
Result = FALSE;
|
|
|
|
|
RequiredSize = 512; /* Initial buffer size */
|
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
|
while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
|
|
|
{
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, CompatibleIDs);
|
2005-09-02 18:51:32 +00:00
|
|
|
|
CompatibleIDs = HeapAlloc(GetProcessHeap(), 0, RequiredSize);
|
2005-08-08 16:09:48 +00:00
|
|
|
|
if (!CompatibleIDs)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
Result = SetupDiGetDeviceRegistryPropertyW(
|
|
|
|
|
DeviceInfoSet,
|
|
|
|
|
DeviceInfoData,
|
|
|
|
|
SPDRP_COMPATIBLEIDS,
|
|
|
|
|
NULL,
|
|
|
|
|
(PBYTE)CompatibleIDs,
|
|
|
|
|
RequiredSize,
|
|
|
|
|
&RequiredSize);
|
|
|
|
|
if (!Result && GetLastError() == ERROR_FILE_NOT_FOUND)
|
|
|
|
|
{
|
|
|
|
|
/* No compatible ID for this device */
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, CompatibleIDs);
|
|
|
|
|
CompatibleIDs = NULL;
|
|
|
|
|
Result = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!Result)
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Enumerate .inf files */
|
|
|
|
|
Result = FALSE;
|
|
|
|
|
RequiredSize = 32768; /* Initial buffer size */
|
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
|
while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
|
|
|
{
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, Buffer);
|
|
|
|
|
Buffer = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
|
|
|
|
|
if (!Buffer)
|
|
|
|
|
{
|
|
|
|
|
Result = FALSE;
|
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
Result = SetupGetInfFileListW(
|
2005-10-21 10:13:26 +00:00
|
|
|
|
*InstallParams.DriverPath ? InstallParams.DriverPath : NULL,
|
2005-08-08 16:09:48 +00:00
|
|
|
|
INF_STYLE_WIN4,
|
|
|
|
|
Buffer, RequiredSize,
|
|
|
|
|
&RequiredSize);
|
|
|
|
|
}
|
|
|
|
|
if (Result)
|
|
|
|
|
{
|
|
|
|
|
LPCWSTR filename;
|
2005-08-09 16:13:50 +00:00
|
|
|
|
|
2005-08-08 16:09:48 +00:00
|
|
|
|
for (filename = (LPCWSTR)Buffer; *filename; filename += wcslen(filename) + 1)
|
|
|
|
|
{
|
|
|
|
|
INFCONTEXT ContextManufacturer, ContextDevice;
|
|
|
|
|
GUID ClassGuid;
|
|
|
|
|
TRACE("Opening file %S\n", filename);
|
|
|
|
|
|
2005-10-24 09:16:34 +00:00
|
|
|
|
currentInfFileDetails = HeapAlloc(GetProcessHeap(), 0, sizeof(struct InfFileDetails));
|
|
|
|
|
if (!currentInfFileDetails)
|
|
|
|
|
continue;
|
|
|
|
|
memset(currentInfFileDetails, 0, sizeof(struct InfFileDetails));
|
|
|
|
|
|
|
|
|
|
currentInfFileDetails->hInf = SetupOpenInfFileW(filename, NULL, INF_STYLE_WIN4, NULL);
|
2005-10-24 09:39:53 +00:00
|
|
|
|
ReferenceInfFile(currentInfFileDetails);
|
2005-10-24 09:16:34 +00:00
|
|
|
|
if (currentInfFileDetails->hInf == INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, currentInfFileDetails);
|
|
|
|
|
currentInfFileDetails = NULL;
|
2005-08-08 16:09:48 +00:00
|
|
|
|
continue;
|
2005-10-24 09:16:34 +00:00
|
|
|
|
}
|
2005-08-08 16:09:48 +00:00
|
|
|
|
|
|
|
|
|
if (!GetVersionInformationFromInfFile(
|
2005-10-24 09:16:34 +00:00
|
|
|
|
currentInfFileDetails->hInf,
|
2005-08-08 16:09:48 +00:00
|
|
|
|
&ClassGuid,
|
|
|
|
|
&ProviderName,
|
|
|
|
|
&DriverDate,
|
|
|
|
|
&DriverVersion))
|
|
|
|
|
{
|
2005-10-24 09:16:34 +00:00
|
|
|
|
SetupCloseInfFile(currentInfFileDetails->hInf);
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, currentInfFileDetails->hInf);
|
|
|
|
|
currentInfFileDetails = NULL;
|
2005-08-08 16:09:48 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (DriverType == SPDIT_CLASSDRIVER)
|
|
|
|
|
{
|
|
|
|
|
/* Check if the ClassGuid in this .inf file is corresponding with our needs */
|
|
|
|
|
if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, &ClassGuid))
|
|
|
|
|
{
|
2005-09-26 11:14:34 +00:00
|
|
|
|
goto next;
|
2005-08-08 16:09:48 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get the manufacturers list */
|
2005-10-24 09:16:34 +00:00
|
|
|
|
Result = SetupFindFirstLineW(currentInfFileDetails->hInf, L"Manufacturer", NULL, &ContextManufacturer);
|
2005-08-08 16:09:48 +00:00
|
|
|
|
while (Result)
|
|
|
|
|
{
|
|
|
|
|
Result = SetupGetStringFieldW(
|
|
|
|
|
&ContextManufacturer,
|
|
|
|
|
0, /* Field index */
|
|
|
|
|
NULL, 0,
|
|
|
|
|
&RequiredSize);
|
2005-08-23 17:38:14 +00:00
|
|
|
|
if (Result)
|
2005-08-08 16:09:48 +00:00
|
|
|
|
{
|
2005-08-23 17:38:14 +00:00
|
|
|
|
/* We got the needed size for the buffer */
|
2005-08-08 16:09:48 +00:00
|
|
|
|
ManufacturerName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
|
|
|
|
|
if (!ManufacturerName)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
Result = SetupGetStringFieldW(
|
|
|
|
|
&ContextManufacturer,
|
|
|
|
|
0, /* Field index */
|
|
|
|
|
ManufacturerName, RequiredSize,
|
|
|
|
|
&RequiredSize);
|
|
|
|
|
}
|
2005-10-23 10:40:25 +00:00
|
|
|
|
/* Get manufacturer section name */
|
2005-08-08 16:09:48 +00:00
|
|
|
|
Result = SetupGetStringFieldW(
|
|
|
|
|
&ContextManufacturer,
|
|
|
|
|
1, /* Field index */
|
2005-10-23 10:40:25 +00:00
|
|
|
|
ManufacturerSection, LINE_LEN,
|
2005-08-08 16:09:48 +00:00
|
|
|
|
&RequiredSize);
|
2005-08-23 17:38:14 +00:00
|
|
|
|
if (Result)
|
2005-08-08 16:09:48 +00:00
|
|
|
|
{
|
2005-10-23 10:40:25 +00:00
|
|
|
|
ManufacturerSection[RequiredSize] = 0; /* Final NULL char */
|
|
|
|
|
/* Add (possible) extension to manufacturer section name */
|
|
|
|
|
Result = SetupDiGetActualSectionToInstallW(
|
2005-10-24 09:16:34 +00:00
|
|
|
|
currentInfFileDetails->hInf, ManufacturerSection, ManufacturerSection, LINE_LEN, NULL, NULL);
|
2005-10-23 10:40:25 +00:00
|
|
|
|
if (Result)
|
2005-08-08 16:09:48 +00:00
|
|
|
|
{
|
2005-10-23 10:40:25 +00:00
|
|
|
|
TRACE("Enumerating devices in manufacturer %S\n", ManufacturerSection);
|
2005-10-24 09:16:34 +00:00
|
|
|
|
Result = SetupFindFirstLineW(currentInfFileDetails->hInf, ManufacturerSection, NULL, &ContextDevice);
|
2005-08-08 16:09:48 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
while (Result)
|
|
|
|
|
{
|
|
|
|
|
if (DriverType == SPDIT_CLASSDRIVER)
|
|
|
|
|
{
|
|
|
|
|
/* FIXME: read [ControlFlags] / ExcludeFromSelect */
|
|
|
|
|
if (!AddDriverToList(
|
|
|
|
|
&list->DriverListHead,
|
|
|
|
|
DriverType,
|
2005-10-13 10:55:16 +00:00
|
|
|
|
&ClassGuid,
|
2005-08-08 16:09:48 +00:00
|
|
|
|
ContextDevice,
|
2005-10-24 09:16:34 +00:00
|
|
|
|
currentInfFileDetails,
|
2005-08-08 16:09:48 +00:00
|
|
|
|
filename,
|
|
|
|
|
ProviderName,
|
|
|
|
|
ManufacturerName,
|
2005-10-06 22:47:13 +00:00
|
|
|
|
NULL,
|
2005-08-08 16:09:48 +00:00
|
|
|
|
DriverDate, DriverVersion,
|
2005-08-09 16:13:50 +00:00
|
|
|
|
0))
|
2005-08-08 16:09:48 +00:00
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else /* DriverType = SPDIT_COMPATDRIVER */
|
|
|
|
|
{
|
|
|
|
|
/* 1. Get all fields */
|
|
|
|
|
DWORD FieldCount = SetupGetFieldCount(&ContextDevice);
|
|
|
|
|
DWORD DriverRank;
|
|
|
|
|
DWORD i;
|
|
|
|
|
LPCWSTR currentId;
|
|
|
|
|
BOOL DriverAlreadyAdded;
|
|
|
|
|
|
|
|
|
|
for (i = 2; i <= FieldCount; i++)
|
|
|
|
|
{
|
|
|
|
|
LPWSTR DeviceId = NULL;
|
|
|
|
|
Result = FALSE;
|
|
|
|
|
RequiredSize = 128; /* Initial buffer size */
|
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
|
while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
|
|
|
{
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, DeviceId);
|
|
|
|
|
DeviceId = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
|
|
|
|
|
if (!DeviceId)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
Result = SetupGetStringFieldW(
|
|
|
|
|
&ContextDevice,
|
|
|
|
|
i,
|
|
|
|
|
DeviceId, RequiredSize,
|
|
|
|
|
&RequiredSize);
|
|
|
|
|
}
|
|
|
|
|
if (!Result)
|
|
|
|
|
{
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, DeviceId);
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
DriverAlreadyAdded = FALSE;
|
2005-08-09 16:13:50 +00:00
|
|
|
|
for (DriverRank = 0, currentId = (LPCWSTR)HardwareIDs; !DriverAlreadyAdded && *currentId; currentId += wcslen(currentId) + 1, DriverRank++)
|
2005-08-08 16:09:48 +00:00
|
|
|
|
{
|
|
|
|
|
if (wcscmp(DeviceId, currentId) == 0)
|
|
|
|
|
{
|
|
|
|
|
AddDriverToList(
|
|
|
|
|
&((struct DeviceInfoElement *)DeviceInfoData->Reserved)->DriverListHead,
|
|
|
|
|
DriverType,
|
2005-10-13 10:55:16 +00:00
|
|
|
|
&ClassGuid,
|
2005-08-08 16:09:48 +00:00
|
|
|
|
ContextDevice,
|
2005-10-24 09:16:34 +00:00
|
|
|
|
currentInfFileDetails,
|
2005-08-08 16:09:48 +00:00
|
|
|
|
filename,
|
|
|
|
|
ProviderName,
|
|
|
|
|
ManufacturerName,
|
2005-10-06 22:47:13 +00:00
|
|
|
|
currentId,
|
2005-08-08 16:09:48 +00:00
|
|
|
|
DriverDate, DriverVersion,
|
2005-08-09 16:13:50 +00:00
|
|
|
|
DriverRank + (i == 2 ? 0 : 0x1000 + i - 3));
|
2005-08-08 16:09:48 +00:00
|
|
|
|
DriverAlreadyAdded = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (CompatibleIDs)
|
|
|
|
|
{
|
2005-08-09 16:13:50 +00:00
|
|
|
|
for (DriverRank = 0, currentId = (LPCWSTR)CompatibleIDs; !DriverAlreadyAdded && *currentId; currentId += wcslen(currentId) + 1, DriverRank++)
|
2005-08-08 16:09:48 +00:00
|
|
|
|
{
|
|
|
|
|
if (wcscmp(DeviceId, currentId) == 0)
|
|
|
|
|
{
|
|
|
|
|
AddDriverToList(
|
|
|
|
|
&((struct DeviceInfoElement *)DeviceInfoData->Reserved)->DriverListHead,
|
|
|
|
|
DriverType,
|
2005-10-13 10:55:16 +00:00
|
|
|
|
&ClassGuid,
|
2005-08-08 16:09:48 +00:00
|
|
|
|
ContextDevice,
|
2005-10-24 09:16:34 +00:00
|
|
|
|
currentInfFileDetails,
|
2005-08-08 16:09:48 +00:00
|
|
|
|
filename,
|
|
|
|
|
ProviderName,
|
|
|
|
|
ManufacturerName,
|
2005-10-06 22:47:13 +00:00
|
|
|
|
currentId,
|
2005-08-08 16:09:48 +00:00
|
|
|
|
DriverDate, DriverVersion,
|
2005-08-09 16:13:50 +00:00
|
|
|
|
DriverRank + (i == 2 ? 0x2000 : 0x3000 + i - 3));
|
2005-08-08 16:09:48 +00:00
|
|
|
|
DriverAlreadyAdded = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, DeviceId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Result = SetupFindNextLine(&ContextDevice, &ContextDevice);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, ManufacturerName);
|
2005-10-23 10:40:25 +00:00
|
|
|
|
ManufacturerName = NULL;
|
2005-08-08 16:09:48 +00:00
|
|
|
|
Result = SetupFindNextLine(&ContextManufacturer, &ContextManufacturer);
|
|
|
|
|
}
|
2005-09-26 11:14:34 +00:00
|
|
|
|
|
|
|
|
|
ret = TRUE;
|
|
|
|
|
next:
|
2005-08-08 16:09:48 +00:00
|
|
|
|
HeapFree(GetProcessHeap(), 0, ProviderName);
|
|
|
|
|
ProviderName = NULL;
|
|
|
|
|
|
2005-10-24 09:39:53 +00:00
|
|
|
|
DereferenceInfFile(currentInfFileDetails);
|
|
|
|
|
currentInfFileDetails = NULL;
|
2005-08-08 16:09:48 +00:00
|
|
|
|
}
|
|
|
|
|
ret = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
done:
|
2005-08-09 16:13:50 +00:00
|
|
|
|
if (ret)
|
|
|
|
|
{
|
|
|
|
|
if (DeviceInfoData)
|
|
|
|
|
{
|
2005-10-21 10:13:26 +00:00
|
|
|
|
InstallParams.Flags |= DI_DIDCOMPAT;
|
|
|
|
|
InstallParams.FlagsEx |= DI_FLAGSEX_DIDCOMPATINFO;
|
2005-08-09 16:13:50 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2005-10-21 10:13:26 +00:00
|
|
|
|
{
|
|
|
|
|
InstallParams.Flags |= DI_DIDCLASS;
|
|
|
|
|
InstallParams.FlagsEx |= DI_FLAGSEX_DIDINFOLIST;
|
|
|
|
|
}
|
|
|
|
|
ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
|
2005-08-09 16:13:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-08-08 16:09:48 +00:00
|
|
|
|
HeapFree(GetProcessHeap(), 0, ProviderName);
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, ManufacturerName);
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, HardwareIDs);
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, CompatibleIDs);
|
2005-10-24 09:39:53 +00:00
|
|
|
|
if (currentInfFileDetails)
|
|
|
|
|
DereferenceInfFile(currentInfFileDetails);
|
2005-08-08 16:09:48 +00:00
|
|
|
|
HeapFree(GetProcessHeap(), 0, Buffer);
|
2005-08-09 16:13:50 +00:00
|
|
|
|
|
2005-08-08 16:09:48 +00:00
|
|
|
|
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_GEN_FAILURE);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiDestroyDriverInfoList (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI
|
|
|
|
|
SetupDiDestroyDriverInfoList(
|
|
|
|
|
IN HDEVINFO DeviceInfoSet,
|
|
|
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
|
|
|
IN DWORD DriverType)
|
|
|
|
|
{
|
2005-10-16 10:46:22 +00:00
|
|
|
|
struct DeviceInfoSet *list;
|
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
|
2005-08-08 16:09:48 +00:00
|
|
|
|
TRACE("%p %p 0x%lx\n", DeviceInfoSet, DeviceInfoData, DriverType);
|
|
|
|
|
|
2005-10-16 10:46:22 +00:00
|
|
|
|
if (!DeviceInfoSet)
|
|
|
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
|
|
|
else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
|
|
|
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
|
|
|
else if (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER)
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData)
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
|
|
|
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
PLIST_ENTRY ListEntry;
|
|
|
|
|
struct DriverInfoElement *driverInfo;
|
2005-10-21 10:13:26 +00:00
|
|
|
|
SP_DEVINSTALL_PARAMS_W InstallParams;
|
|
|
|
|
|
|
|
|
|
InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
|
|
|
|
|
if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
|
|
|
|
|
goto done;
|
2005-10-16 10:46:22 +00:00
|
|
|
|
|
|
|
|
|
if (!DeviceInfoData)
|
2005-10-21 10:13:26 +00:00
|
|
|
|
/* Fall back to destroying class driver list */
|
2005-10-16 10:46:22 +00:00
|
|
|
|
DriverType = SPDIT_CLASSDRIVER;
|
|
|
|
|
if (DriverType == SPDIT_CLASSDRIVER)
|
|
|
|
|
{
|
2005-10-21 10:13:26 +00:00
|
|
|
|
if (!(InstallParams.Flags & DI_DIDCLASS))
|
2005-10-16 10:46:22 +00:00
|
|
|
|
/* The list was not created */
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
else if (DriverType == SPDIT_COMPATDRIVER)
|
|
|
|
|
{
|
2005-10-21 10:13:26 +00:00
|
|
|
|
if (!(InstallParams.Flags & DI_DIDCOMPAT))
|
2005-10-16 10:46:22 +00:00
|
|
|
|
/* The list was not created */
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (DriverType == SPDIT_CLASSDRIVER)
|
|
|
|
|
{
|
|
|
|
|
while (!IsListEmpty(&list->DriverListHead))
|
|
|
|
|
{
|
|
|
|
|
ListEntry = RemoveHeadList(&list->DriverListHead);
|
|
|
|
|
driverInfo = (struct DriverInfoElement *)ListEntry;
|
2005-10-24 09:16:34 +00:00
|
|
|
|
DestroyDriverInfoElement(driverInfo);
|
2005-10-16 10:46:22 +00:00
|
|
|
|
}
|
2005-10-21 10:13:26 +00:00
|
|
|
|
InstallParams.Reserved = 0;
|
|
|
|
|
InstallParams.Flags &= ~(DI_DIDCLASS | DI_MULTMFGS);
|
|
|
|
|
InstallParams.FlagsEx &= ~DI_FLAGSEX_DIDINFOLIST;
|
|
|
|
|
ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParams);
|
2005-10-16 10:46:22 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2005-10-21 10:13:26 +00:00
|
|
|
|
SP_DEVINSTALL_PARAMS_W InstallParamsSet;
|
|
|
|
|
struct DeviceInfoElement *deviceInfo;
|
|
|
|
|
|
|
|
|
|
InstallParamsSet.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
|
|
|
|
|
if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParamsSet))
|
|
|
|
|
goto done;
|
|
|
|
|
deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
|
2005-10-16 10:46:22 +00:00
|
|
|
|
while (!IsListEmpty(&deviceInfo->DriverListHead))
|
|
|
|
|
{
|
|
|
|
|
ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
|
|
|
|
|
driverInfo = (struct DriverInfoElement *)ListEntry;
|
2005-10-21 10:13:26 +00:00
|
|
|
|
if ((PVOID)InstallParamsSet.Reserved == driverInfo)
|
|
|
|
|
{
|
|
|
|
|
InstallParamsSet.Reserved = 0;
|
|
|
|
|
SetupDiSetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParamsSet);
|
|
|
|
|
}
|
2005-10-24 09:16:34 +00:00
|
|
|
|
DestroyDriverInfoElement(driverInfo);
|
2005-10-16 10:46:22 +00:00
|
|
|
|
}
|
2005-10-21 10:13:26 +00:00
|
|
|
|
InstallParams.Reserved = 0;
|
|
|
|
|
InstallParams.Flags &= ~DI_DIDCOMPAT;
|
|
|
|
|
InstallParams.FlagsEx &= ~DI_FLAGSEX_DIDCOMPATINFO;
|
|
|
|
|
ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
|
2005-10-16 10:46:22 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
|
|
|
return ret;
|
2005-07-03 13:46:33 +00:00
|
|
|
|
}
|
2005-08-08 16:09:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* 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;
|
|
|
|
|
DWORD rc;
|
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
|
|
|
|
|
TRACE("%p %S %p %lx %p\n", DeviceInfoSet, 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_PARAMETER);
|
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2005-08-12 19:00:04 +00:00
|
|
|
|
/* good one found */
|
2005-08-08 16:09:48 +00:00
|
|
|
|
ret = TRUE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Open supposed registry key */
|
|
|
|
|
rc = RegOpenKeyExW(
|
|
|
|
|
list->HKLM,
|
|
|
|
|
EnumKeyName,
|
|
|
|
|
0, /* Options */
|
|
|
|
|
KEY_ENUMERATE_SUB_KEYS,
|
|
|
|
|
&hEnumKey);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(rc);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
rc = RegOpenKeyExW(
|
|
|
|
|
hEnumKey,
|
|
|
|
|
DeviceInstanceId,
|
|
|
|
|
0, /* Options */
|
|
|
|
|
KEY_QUERY_VALUE,
|
|
|
|
|
&hKey);
|
|
|
|
|
RegCloseKey(hEnumKey);
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(rc);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-12 19:00:04 +00:00
|
|
|
|
/* FIXME: GUID_NULL is not allowed */
|
2005-08-09 16:13:50 +00:00
|
|
|
|
if (!CreateDeviceInfoElement(DeviceInstanceId, &GUID_NULL /* FIXME */, &deviceInfo))
|
2005-08-08 16:09:48 +00:00
|
|
|
|
{
|
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
|
|
|
|
|
|
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
|
ret = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ret && deviceInfo && DeviceInfoData)
|
|
|
|
|
{
|
|
|
|
|
memcpy(&DeviceInfoData->ClassGuid, &deviceInfo->ClassGuid, sizeof(GUID));
|
|
|
|
|
DeviceInfoData->DevInst = 0; /* FIXME */
|
|
|
|
|
DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiEnumDriverInfoA (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI
|
|
|
|
|
SetupDiEnumDriverInfoA(
|
|
|
|
|
IN HDEVINFO DeviceInfoSet,
|
|
|
|
|
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
|
|
|
|
|
IN DWORD DriverType,
|
|
|
|
|
IN DWORD MemberIndex,
|
|
|
|
|
OUT PSP_DRVINFO_DATA_A DriverInfoData)
|
|
|
|
|
{
|
|
|
|
|
SP_DRVINFO_DATA_V2_W driverInfoData2W;
|
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
|
|
|
|
|
TRACE("%p %p 0x%lx %ld %p\n", DeviceInfoSet, DeviceInfoData,
|
|
|
|
|
DriverType, MemberIndex, DriverInfoData);
|
|
|
|
|
|
|
|
|
|
if (DriverInfoData == NULL)
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_A) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_A))
|
|
|
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
driverInfoData2W.cbSize = sizeof(SP_DRVINFO_DATA_V2_W);
|
|
|
|
|
ret = SetupDiEnumDriverInfoW(DeviceInfoSet, DeviceInfoData,
|
|
|
|
|
DriverType, MemberIndex, &driverInfoData2W);
|
|
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
|
{
|
|
|
|
|
/* Do W->A conversion */
|
|
|
|
|
DriverInfoData->DriverType = driverInfoData2W.DriverType;
|
|
|
|
|
DriverInfoData->Reserved = driverInfoData2W.Reserved;
|
|
|
|
|
if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.Description, -1,
|
|
|
|
|
DriverInfoData->Description, LINE_LEN, NULL, NULL) == 0)
|
|
|
|
|
{
|
|
|
|
|
DriverInfoData->Description[0] = '\0';
|
|
|
|
|
ret = FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.MfgName, -1,
|
|
|
|
|
DriverInfoData->MfgName, LINE_LEN, NULL, NULL) == 0)
|
|
|
|
|
{
|
|
|
|
|
DriverInfoData->MfgName[0] = '\0';
|
|
|
|
|
ret = FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.ProviderName, -1,
|
|
|
|
|
DriverInfoData->ProviderName, LINE_LEN, NULL, NULL) == 0)
|
|
|
|
|
{
|
|
|
|
|
DriverInfoData->ProviderName[0] = '\0';
|
|
|
|
|
ret = FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V2_A))
|
|
|
|
|
{
|
|
|
|
|
/* Copy more fields */
|
|
|
|
|
DriverInfoData->DriverDate = driverInfoData2W.DriverDate;
|
|
|
|
|
DriverInfoData->DriverVersion = driverInfoData2W.DriverVersion;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiEnumDriverInfoW (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI
|
|
|
|
|
SetupDiEnumDriverInfoW(
|
|
|
|
|
IN HDEVINFO DeviceInfoSet,
|
|
|
|
|
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
|
|
|
|
|
IN DWORD DriverType,
|
|
|
|
|
IN DWORD MemberIndex,
|
|
|
|
|
OUT PSP_DRVINFO_DATA_W DriverInfoData)
|
|
|
|
|
{
|
|
|
|
|
PLIST_ENTRY ListHead;
|
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
|
|
|
|
|
TRACE("%p %p 0x%lx %ld %p\n", DeviceInfoSet, DeviceInfoData,
|
|
|
|
|
DriverType, MemberIndex, DriverInfoData);
|
|
|
|
|
|
|
|
|
|
if (!DeviceInfoSet || !DriverInfoData)
|
|
|
|
|
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 (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER)
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
else if (DriverType == SPDIT_CLASSDRIVER && DeviceInfoData)
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData)
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
|
|
|
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
struct DeviceInfoElement *devInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
|
|
|
|
|
PLIST_ENTRY ItemList;
|
|
|
|
|
if (DriverType == SPDIT_CLASSDRIVER ||
|
|
|
|
|
devInfo->CreationFlags & DICD_INHERIT_CLASSDRVS)
|
|
|
|
|
{
|
|
|
|
|
ListHead = &((struct DeviceInfoSet *)DeviceInfoSet)->DriverListHead;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ListHead = &devInfo->DriverListHead;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ItemList = ListHead->Flink;
|
|
|
|
|
while (ItemList != ListHead && MemberIndex-- > 0)
|
|
|
|
|
ItemList = ItemList->Flink;
|
|
|
|
|
if (ItemList == ListHead)
|
|
|
|
|
SetLastError(ERROR_NO_MORE_ITEMS);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
struct DriverInfoElement *DrvInfo = (struct DriverInfoElement *)ItemList;
|
|
|
|
|
|
|
|
|
|
memcpy(
|
2005-08-12 19:00:04 +00:00
|
|
|
|
&DriverInfoData->DriverType,
|
|
|
|
|
&DrvInfo->Info.DriverType,
|
|
|
|
|
DriverInfoData->cbSize - FIELD_OFFSET(SP_DRVINFO_DATA_W, DriverType));
|
2005-08-08 16:09:48 +00:00
|
|
|
|
ret = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2005-08-09 16:13:50 +00:00
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiGetSelectedDriverW (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI
|
|
|
|
|
SetupDiGetSelectedDriverW(
|
|
|
|
|
IN HDEVINFO DeviceInfoSet,
|
|
|
|
|
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
|
|
|
|
|
OUT PSP_DRVINFO_DATA_W DriverInfoData)
|
|
|
|
|
{
|
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
|
|
|
|
|
TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DriverInfoData);
|
|
|
|
|
|
|
|
|
|
if (!DeviceInfoSet || !DriverInfoData)
|
|
|
|
|
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 if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
|
|
|
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
|
|
|
else
|
|
|
|
|
{
|
2005-10-21 10:13:26 +00:00
|
|
|
|
SP_DEVINSTALL_PARAMS InstallParams;
|
2005-08-09 16:13:50 +00:00
|
|
|
|
|
2005-10-21 10:13:26 +00:00
|
|
|
|
InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
|
|
|
|
|
if (SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
|
2005-08-09 16:13:50 +00:00
|
|
|
|
{
|
2005-10-21 10:13:26 +00:00
|
|
|
|
struct DriverInfoElement *driverInfo;
|
|
|
|
|
driverInfo = (struct DriverInfoElement *)InstallParams.Reserved;
|
|
|
|
|
if (driverInfo == NULL)
|
|
|
|
|
SetLastError(ERROR_NO_DRIVER_SELECTED);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
memcpy(
|
|
|
|
|
&DriverInfoData->DriverType,
|
|
|
|
|
&driverInfo->Info.DriverType,
|
|
|
|
|
DriverInfoData->cbSize - FIELD_OFFSET(SP_DRVINFO_DATA_W, DriverType));
|
|
|
|
|
ret = TRUE;
|
|
|
|
|
}
|
2005-08-09 16:13:50 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiSetSelectedDriverW (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI
|
|
|
|
|
SetupDiSetSelectedDriverW(
|
|
|
|
|
IN HDEVINFO DeviceInfoSet,
|
|
|
|
|
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
|
|
|
|
|
IN OUT PSP_DRVINFO_DATA_W DriverInfoData OPTIONAL)
|
|
|
|
|
{
|
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
|
|
|
|
|
TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DriverInfoData);
|
|
|
|
|
|
|
|
|
|
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 if (DriverInfoData && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
|
|
|
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
struct DriverInfoElement **pDriverInfo;
|
|
|
|
|
PLIST_ENTRY ListHead, ItemList;
|
|
|
|
|
|
|
|
|
|
if (DeviceInfoData)
|
|
|
|
|
{
|
2005-10-21 10:13:26 +00:00
|
|
|
|
pDriverInfo = (struct DriverInfoElement **)&((struct DeviceInfoElement *)DeviceInfoData->Reserved)->InstallParams.Reserved;
|
2005-08-09 16:13:50 +00:00
|
|
|
|
ListHead = &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->DriverListHead;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2005-10-21 10:13:26 +00:00
|
|
|
|
pDriverInfo = (struct DriverInfoElement **)&((struct DeviceInfoSet *)DeviceInfoSet)->InstallParams.Reserved;
|
2005-08-09 16:13:50 +00:00
|
|
|
|
ListHead = &((struct DeviceInfoSet *)DeviceInfoSet)->DriverListHead;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!DriverInfoData)
|
|
|
|
|
{
|
|
|
|
|
*pDriverInfo = NULL;
|
|
|
|
|
ret = TRUE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Search selected driver in list */
|
|
|
|
|
ItemList = ListHead->Flink;
|
|
|
|
|
while (ItemList != ListHead)
|
|
|
|
|
{
|
|
|
|
|
if (DriverInfoData->Reserved != 0)
|
|
|
|
|
{
|
|
|
|
|
if (DriverInfoData->Reserved == (ULONG_PTR)ItemList)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* The caller wants to compare only DriverType, Description and ProviderName fields */
|
|
|
|
|
struct DriverInfoElement *driverInfo = (struct DriverInfoElement *)ItemList;
|
|
|
|
|
if (driverInfo->Info.DriverType == DriverInfoData->DriverType
|
|
|
|
|
&& wcscmp(driverInfo->Info.Description, DriverInfoData->Description) == 0
|
|
|
|
|
&& wcscmp(driverInfo->Info.ProviderName, DriverInfoData->ProviderName) == 0)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ItemList == ListHead)
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
*pDriverInfo = (struct DriverInfoElement *)ItemList;
|
|
|
|
|
DriverInfoData->Reserved = (ULONG_PTR)ItemList;
|
|
|
|
|
ret = TRUE;
|
2005-08-27 14:59:22 +00:00
|
|
|
|
TRACE("Choosing driver whose rank is 0x%lx\n",
|
|
|
|
|
((struct DriverInfoElement *)ItemList)->DriverRank);
|
2005-10-13 10:55:16 +00:00
|
|
|
|
if (DeviceInfoData)
|
|
|
|
|
memcpy(&DeviceInfoData->ClassGuid, &(*pDriverInfo)->ClassGuid, sizeof(GUID));
|
2005-08-09 16:13:50 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2005-08-12 19:03:35 +00:00
|
|
|
|
|
2005-10-22 16:25:48 +00:00
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiGetDriverInfoDetailA (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI
|
|
|
|
|
SetupDiGetDriverInfoDetailA(
|
|
|
|
|
IN HDEVINFO DeviceInfoSet,
|
|
|
|
|
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
|
|
|
|
|
IN PSP_DRVINFO_DATA_A DriverInfoData,
|
|
|
|
|
OUT PSP_DRVINFO_DETAIL_DATA_A DriverInfoDetailData OPTIONAL,
|
|
|
|
|
IN DWORD DriverInfoDetailDataSize,
|
|
|
|
|
OUT PDWORD RequiredSize OPTIONAL)
|
|
|
|
|
{
|
2005-10-22 20:12:42 +00:00
|
|
|
|
SP_DRVINFO_DATA_V2_W DriverInfoDataW;
|
|
|
|
|
PSP_DRVINFO_DETAIL_DATA_W DriverInfoDetailDataW = NULL;
|
|
|
|
|
DWORD BufSize = 0;
|
|
|
|
|
DWORD HardwareIDLen = 0;
|
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
|
|
|
|
|
/* do some sanity checks, the unicode version might do more thorough checks */
|
|
|
|
|
if (DriverInfoData == NULL ||
|
|
|
|
|
(DriverInfoDetailData == NULL && DriverInfoDetailDataSize != 0) ||
|
|
|
|
|
(DriverInfoDetailData != NULL &&
|
|
|
|
|
(DriverInfoDetailDataSize < FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID) + sizeof(CHAR) ||
|
|
|
|
|
DriverInfoDetailData->cbSize != sizeof(SP_DRVINFO_DETAIL_DATA_A))))
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
goto Cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* make sure we support both versions of the SP_DRVINFO_DATA structure */
|
|
|
|
|
if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V1_A))
|
|
|
|
|
{
|
|
|
|
|
DriverInfoDataW.cbSize = sizeof(SP_DRVINFO_DATA_V1_W);
|
|
|
|
|
}
|
|
|
|
|
else if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V2_A))
|
|
|
|
|
{
|
|
|
|
|
DriverInfoDataW.cbSize = sizeof(SP_DRVINFO_DATA_V2_W);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
goto Cleanup;
|
|
|
|
|
}
|
|
|
|
|
DriverInfoDataW.DriverType = DriverInfoData->DriverType;
|
|
|
|
|
DriverInfoDataW.Reserved = DriverInfoData->Reserved;
|
|
|
|
|
|
|
|
|
|
/* convert the strings to unicode */
|
|
|
|
|
if (MultiByteToWideChar(CP_ACP,
|
|
|
|
|
0,
|
|
|
|
|
DriverInfoData->Description,
|
|
|
|
|
LINE_LEN,
|
|
|
|
|
DriverInfoDataW.Description,
|
|
|
|
|
LINE_LEN) &&
|
|
|
|
|
MultiByteToWideChar(CP_ACP,
|
|
|
|
|
0,
|
|
|
|
|
DriverInfoData->MfgName,
|
|
|
|
|
LINE_LEN,
|
|
|
|
|
DriverInfoDataW.MfgName,
|
|
|
|
|
LINE_LEN) &&
|
|
|
|
|
MultiByteToWideChar(CP_ACP,
|
|
|
|
|
0,
|
|
|
|
|
DriverInfoData->ProviderName,
|
|
|
|
|
LINE_LEN,
|
|
|
|
|
DriverInfoDataW.ProviderName,
|
|
|
|
|
LINE_LEN))
|
|
|
|
|
{
|
|
|
|
|
if (DriverInfoDataW.cbSize == sizeof(SP_DRVINFO_DATA_V2_W))
|
|
|
|
|
{
|
|
|
|
|
DriverInfoDataW.DriverDate = ((PSP_DRVINFO_DATA_V2_A)DriverInfoData)->DriverDate;
|
|
|
|
|
DriverInfoDataW.DriverVersion = ((PSP_DRVINFO_DATA_V2_A)DriverInfoData)->DriverVersion;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (DriverInfoDetailData != NULL)
|
|
|
|
|
{
|
|
|
|
|
/* calculate the unicode buffer size from the ansi buffer size */
|
|
|
|
|
HardwareIDLen = DriverInfoDetailDataSize - FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID);
|
|
|
|
|
BufSize = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID) +
|
|
|
|
|
(HardwareIDLen * sizeof(WCHAR));
|
|
|
|
|
|
|
|
|
|
DriverInfoDetailDataW = MyMalloc(BufSize);
|
|
|
|
|
if (DriverInfoDetailDataW == NULL)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
|
goto Cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* initialize the buffer */
|
|
|
|
|
ZeroMemory(DriverInfoDetailDataW,
|
|
|
|
|
BufSize);
|
|
|
|
|
DriverInfoDetailDataW->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* call the unicode version */
|
|
|
|
|
ret = SetupDiGetDriverInfoDetailW(DeviceInfoSet,
|
|
|
|
|
DeviceInfoData,
|
|
|
|
|
&DriverInfoDataW,
|
|
|
|
|
DriverInfoDetailDataW,
|
|
|
|
|
BufSize,
|
|
|
|
|
RequiredSize);
|
|
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
|
{
|
|
|
|
|
if (DriverInfoDetailDataW != NULL)
|
|
|
|
|
{
|
|
|
|
|
/* convert the SP_DRVINFO_DETAIL_DATA_W structure to ansi */
|
|
|
|
|
DriverInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_A);
|
|
|
|
|
DriverInfoDetailData->InfDate = DriverInfoDetailDataW->InfDate;
|
|
|
|
|
DriverInfoDetailData->Reserved = DriverInfoDetailDataW->Reserved;
|
|
|
|
|
if (WideCharToMultiByte(CP_ACP,
|
|
|
|
|
0,
|
|
|
|
|
DriverInfoDetailDataW->SectionName,
|
|
|
|
|
LINE_LEN,
|
|
|
|
|
DriverInfoDetailData->SectionName,
|
|
|
|
|
LINE_LEN,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL) &&
|
|
|
|
|
WideCharToMultiByte(CP_ACP,
|
|
|
|
|
0,
|
|
|
|
|
DriverInfoDetailDataW->InfFileName,
|
|
|
|
|
MAX_PATH,
|
|
|
|
|
DriverInfoDetailData->InfFileName,
|
|
|
|
|
MAX_PATH,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL) &&
|
|
|
|
|
WideCharToMultiByte(CP_ACP,
|
|
|
|
|
0,
|
|
|
|
|
DriverInfoDetailDataW->DrvDescription,
|
|
|
|
|
LINE_LEN,
|
|
|
|
|
DriverInfoDetailData->DrvDescription,
|
|
|
|
|
LINE_LEN,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL) &&
|
|
|
|
|
WideCharToMultiByte(CP_ACP,
|
|
|
|
|
0,
|
|
|
|
|
DriverInfoDetailDataW->HardwareID,
|
|
|
|
|
HardwareIDLen,
|
|
|
|
|
DriverInfoDetailData->HardwareID,
|
|
|
|
|
HardwareIDLen,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL))
|
|
|
|
|
{
|
|
|
|
|
DWORD len, cnt = 0;
|
|
|
|
|
DWORD hwidlen = HardwareIDLen;
|
|
|
|
|
CHAR *s = DriverInfoDetailData->HardwareID;
|
|
|
|
|
|
|
|
|
|
/* count the strings in the list */
|
|
|
|
|
while (*s != '\0')
|
|
|
|
|
{
|
|
|
|
|
len = lstrlenA(s) + 1;
|
|
|
|
|
if (hwidlen > len)
|
|
|
|
|
{
|
|
|
|
|
cnt++;
|
|
|
|
|
s += len;
|
|
|
|
|
hwidlen -= len;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* looks like the string list wasn't terminated... */
|
|
|
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
|
|
|
ret = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* make sure CompatIDsOffset points to the second string in the
|
|
|
|
|
list, if present */
|
|
|
|
|
if (cnt > 1)
|
|
|
|
|
{
|
|
|
|
|
DriverInfoDetailData->CompatIDsOffset = lstrlenA(DriverInfoDetailData->HardwareID) + 1;
|
|
|
|
|
DriverInfoDetailData->CompatIDsLength = (DWORD)(s - DriverInfoDetailData->HardwareID) -
|
|
|
|
|
DriverInfoDetailData->CompatIDsOffset + 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DriverInfoDetailData->CompatIDsOffset = 0;
|
|
|
|
|
DriverInfoDetailData->CompatIDsLength = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ret = FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (RequiredSize != NULL)
|
|
|
|
|
{
|
|
|
|
|
*RequiredSize = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID) +
|
|
|
|
|
(((*RequiredSize) - FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID)) / sizeof(WCHAR));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
|
if (DriverInfoDetailDataW != NULL)
|
|
|
|
|
{
|
|
|
|
|
MyFree(DriverInfoDetailDataW);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
2005-10-22 16:25:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiGetDriverInfoDetailW (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI
|
|
|
|
|
SetupDiGetDriverInfoDetailW(
|
|
|
|
|
IN HDEVINFO DeviceInfoSet,
|
|
|
|
|
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
|
|
|
|
|
IN PSP_DRVINFO_DATA_W DriverInfoData,
|
|
|
|
|
OUT PSP_DRVINFO_DETAIL_DATA_W DriverInfoDetailData OPTIONAL,
|
|
|
|
|
IN DWORD DriverInfoDetailDataSize,
|
|
|
|
|
OUT PDWORD RequiredSize OPTIONAL)
|
|
|
|
|
{
|
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
|
|
|
|
|
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 if (!DriverInfoData)
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
else if (!DriverInfoDetailData && DriverInfoDetailDataSize != 0)
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
else if (DriverInfoDetailData && DriverInfoDetailDataSize < sizeof(SP_DRVINFO_DETAIL_DATA_W))
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
else if (DriverInfoDetailData && DriverInfoDetailData->cbSize != sizeof(SP_DRVINFO_DETAIL_DATA_W))
|
|
|
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
|
|
|
else if (DriverInfoDetailData && DriverInfoDetailData->Reserved == 0)
|
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
struct DriverInfoElement *driverInfoElement;
|
|
|
|
|
driverInfoElement = (struct DriverInfoElement *)DriverInfoData->Reserved;
|
|
|
|
|
|
|
|
|
|
memcpy(
|
|
|
|
|
DriverInfoDetailData,
|
|
|
|
|
&driverInfoElement->Details,
|
|
|
|
|
driverInfoElement->Details.cbSize);
|
|
|
|
|
/* FIXME: copy HardwareIDs/CompatibleIDs if buffer is big enough
|
|
|
|
|
* Don't forget to set CompatIDsOffset and CompatIDsLength fields.
|
|
|
|
|
*/
|
|
|
|
|
ret = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-12 19:03:35 +00:00
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiSelectBestCompatDrv (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI
|
|
|
|
|
SetupDiSelectBestCompatDrv(
|
|
|
|
|
IN HDEVINFO DeviceInfoSet,
|
|
|
|
|
IN PSP_DEVINFO_DATA DeviceInfoData)
|
|
|
|
|
{
|
|
|
|
|
SP_DRVINFO_DATA_W drvInfoData;
|
|
|
|
|
BOOL ret;
|
|
|
|
|
|
|
|
|
|
TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
|
|
|
|
|
|
2005-08-27 14:59:22 +00:00
|
|
|
|
/* Drivers are sorted by rank in the driver list, so
|
|
|
|
|
* the first driver in the list is the best one.
|
|
|
|
|
*/
|
2005-08-12 19:03:35 +00:00
|
|
|
|
drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA_W);
|
|
|
|
|
ret = SetupDiEnumDriverInfoW(
|
|
|
|
|
DeviceInfoSet,
|
|
|
|
|
DeviceInfoData,
|
|
|
|
|
SPDIT_COMPATDRIVER,
|
|
|
|
|
0, /* Member index */
|
|
|
|
|
&drvInfoData);
|
|
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
|
{
|
|
|
|
|
ret = SetupDiSetSelectedDriverW(
|
|
|
|
|
DeviceInfoSet,
|
|
|
|
|
DeviceInfoData,
|
|
|
|
|
&drvInfoData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiInstallDriverFiles (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI
|
|
|
|
|
SetupDiInstallDriverFiles(
|
|
|
|
|
IN HDEVINFO DeviceInfoSet,
|
|
|
|
|
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
|
|
|
|
|
{
|
2005-09-25 21:18:27 +00:00
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
|
2005-08-12 19:03:35 +00:00
|
|
|
|
TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
|
|
|
|
|
|
2005-09-25 21:18:27 +00:00
|
|
|
|
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);
|
2005-10-21 10:13:26 +00:00
|
|
|
|
else if (DeviceInfoData && ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->InstallParams.Reserved == 0)
|
|
|
|
|
SetLastError(ERROR_NO_DRIVER_SELECTED);
|
|
|
|
|
else if (!DeviceInfoData && ((struct DeviceInfoSet *)DeviceInfoSet)->InstallParams.Reserved == 0)
|
|
|
|
|
SetLastError(ERROR_NO_DRIVER_SELECTED);
|
2005-09-25 21:18:27 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2005-10-21 10:13:26 +00:00
|
|
|
|
SP_DEVINSTALL_PARAMS_W InstallParams;
|
|
|
|
|
struct DriverInfoElement *SelectedDriver;
|
|
|
|
|
WCHAR SectionName[MAX_PATH];
|
|
|
|
|
DWORD SectionNameLength = 0;
|
|
|
|
|
|
|
|
|
|
InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
|
|
|
|
|
ret = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
|
|
|
|
|
if (!ret)
|
|
|
|
|
goto cleanup;
|
2005-09-25 21:18:27 +00:00
|
|
|
|
|
2005-10-21 10:13:26 +00:00
|
|
|
|
SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
|
|
|
|
|
if (!SelectedDriver)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_NO_DRIVER_SELECTED);
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
2005-10-24 09:16:34 +00:00
|
|
|
|
ret = SetupDiGetActualSectionToInstallW(
|
|
|
|
|
SelectedDriver->InfFileDetails->hInf,
|
|
|
|
|
SelectedDriver->Details.SectionName,
|
2005-10-21 10:13:26 +00:00
|
|
|
|
SectionName, MAX_PATH, &SectionNameLength, NULL);
|
|
|
|
|
if (!ret)
|
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
|
|
if (InstallParams.InstallMsgHandler)
|
2005-09-25 21:18:27 +00:00
|
|
|
|
{
|
2005-10-24 09:16:34 +00:00
|
|
|
|
ret = SetupInstallFromInfSectionW(InstallParams.hwndParent,
|
|
|
|
|
SelectedDriver->InfFileDetails->hInf, SectionName,
|
2005-10-21 10:13:26 +00:00
|
|
|
|
SPINST_FILES, NULL, NULL, SP_COPY_NEWER,
|
|
|
|
|
InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext,
|
|
|
|
|
DeviceInfoSet, DeviceInfoData);
|
2005-09-25 21:18:27 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2005-10-21 10:13:26 +00:00
|
|
|
|
PVOID callback_context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
|
2005-10-24 09:16:34 +00:00
|
|
|
|
ret = SetupInstallFromInfSectionW(InstallParams.hwndParent,
|
|
|
|
|
SelectedDriver->InfFileDetails->hInf, SectionName,
|
2005-10-21 10:13:26 +00:00
|
|
|
|
SPINST_FILES, NULL, NULL, SP_COPY_NEWER,
|
|
|
|
|
SetupDefaultQueueCallbackW, callback_context,
|
|
|
|
|
DeviceInfoSet, DeviceInfoData);
|
|
|
|
|
SetupTermDefaultQueueCallback(callback_context);
|
2005-09-25 21:18:27 +00:00
|
|
|
|
}
|
2005-10-21 10:13:26 +00:00
|
|
|
|
cleanup:
|
|
|
|
|
if (ret)
|
|
|
|
|
{
|
|
|
|
|
InstallParams.Flags |= DI_NOFILECOPY;
|
|
|
|
|
ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
|
2005-09-25 21:18:27 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
|
|
|
return ret;
|
2005-08-12 19:03:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiRegisterCoDeviceInstallers (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI
|
|
|
|
|
SetupDiRegisterCoDeviceInstallers(
|
|
|
|
|
IN HDEVINFO DeviceInfoSet,
|
|
|
|
|
IN PSP_DEVINFO_DATA DeviceInfoData)
|
|
|
|
|
{
|
|
|
|
|
TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
|
|
|
|
|
|
|
|
|
|
FIXME("SetupDiRegisterCoDeviceInstallers not implemented. Doing nothing\n");
|
|
|
|
|
//SetLastError(ERROR_GEN_FAILURE);
|
|
|
|
|
//return FALSE;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiInstallDeviceInterfaces (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI
|
|
|
|
|
SetupDiInstallDeviceInterfaces(
|
|
|
|
|
IN HDEVINFO DeviceInfoSet,
|
|
|
|
|
IN PSP_DEVINFO_DATA DeviceInfoData)
|
|
|
|
|
{
|
|
|
|
|
TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
|
|
|
|
|
|
|
|
|
|
FIXME("SetupDiInstallDeviceInterfaces not implemented. Doing nothing\n");
|
|
|
|
|
//SetLastError(ERROR_GEN_FAILURE);
|
|
|
|
|
//return FALSE;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SetupDiInstallDevice (SETUPAPI.@)
|
|
|
|
|
*/
|
|
|
|
|
BOOL WINAPI
|
|
|
|
|
SetupDiInstallDevice(
|
|
|
|
|
IN HDEVINFO DeviceInfoSet,
|
|
|
|
|
IN PSP_DEVINFO_DATA DeviceInfoData)
|
|
|
|
|
{
|
2005-09-26 11:39:24 +00:00
|
|
|
|
struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
|
2005-10-21 10:13:26 +00:00
|
|
|
|
SP_DEVINSTALL_PARAMS_W InstallParams;
|
|
|
|
|
struct DriverInfoElement *SelectedDriver;
|
2005-09-26 11:39:24 +00:00
|
|
|
|
SYSTEMTIME DriverDate;
|
|
|
|
|
WCHAR SectionName[MAX_PATH];
|
2005-10-06 22:47:13 +00:00
|
|
|
|
WCHAR Buffer[32];
|
2005-09-26 11:39:24 +00:00
|
|
|
|
DWORD SectionNameLength = 0;
|
|
|
|
|
BOOL Result = FALSE;
|
|
|
|
|
INFCONTEXT ContextService;
|
2005-09-26 11:43:14 +00:00
|
|
|
|
INT Flags;
|
2005-10-21 10:13:26 +00:00
|
|
|
|
ULONG DoAction;
|
2005-09-26 11:39:24 +00:00
|
|
|
|
DWORD RequiredSize;
|
|
|
|
|
LPCWSTR AssociatedService = NULL;
|
2005-09-27 08:52:17 +00:00
|
|
|
|
LPWSTR pSectionName = NULL;
|
2005-10-24 09:16:34 +00:00
|
|
|
|
WCHAR ClassName[MAX_CLASS_NAME_LEN];
|
2005-10-06 22:47:13 +00:00
|
|
|
|
GUID ClassGuid;
|
|
|
|
|
LPWSTR lpGuidString = NULL, lpFullGuidString = NULL;
|
2005-09-26 11:39:24 +00:00
|
|
|
|
BOOL RebootRequired = FALSE;
|
2005-10-14 16:53:18 +00:00
|
|
|
|
HKEY hKey = INVALID_HANDLE_VALUE;
|
2005-10-06 22:47:13 +00:00
|
|
|
|
HKEY hClassKey = INVALID_HANDLE_VALUE;
|
2005-09-26 11:39:24 +00:00
|
|
|
|
LONG rc;
|
2005-10-06 09:55:10 +00:00
|
|
|
|
BOOL ret = FALSE; /* Return value */
|
2005-09-26 11:39:24 +00:00
|
|
|
|
|
2005-08-12 19:03:35 +00:00
|
|
|
|
TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
|
|
|
|
|
|
2005-09-26 11:39:24 +00:00
|
|
|
|
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;
|
2005-08-12 19:03:35 +00:00
|
|
|
|
|
2005-09-26 11:39:24 +00:00
|
|
|
|
if (!Result)
|
|
|
|
|
{
|
|
|
|
|
/* One parameter is bad */
|
2005-10-06 09:55:10 +00:00
|
|
|
|
goto cleanup;
|
2005-09-26 11:39:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-10-21 10:13:26 +00:00
|
|
|
|
InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
|
|
|
|
|
Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
|
|
|
|
|
if (!Result)
|
|
|
|
|
goto cleanup;
|
2005-09-26 11:39:24 +00:00
|
|
|
|
|
2005-10-21 10:13:26 +00:00
|
|
|
|
if (InstallParams.FlagsEx & DI_FLAGSEX_SETFAILEDINSTALL)
|
2005-09-27 08:52:17 +00:00
|
|
|
|
{
|
2005-10-21 10:13:26 +00:00
|
|
|
|
/* FIXME: set FAILEDINSTALL in ConfigFlags registry value */
|
|
|
|
|
goto cleanup;
|
2005-09-27 08:52:17 +00:00
|
|
|
|
}
|
2005-10-21 10:13:26 +00:00
|
|
|
|
|
|
|
|
|
SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
|
|
|
|
|
if (SelectedDriver == NULL)
|
2005-09-27 08:52:17 +00:00
|
|
|
|
{
|
2005-10-21 10:13:26 +00:00
|
|
|
|
SetLastError(ERROR_NO_DRIVER_SELECTED);
|
|
|
|
|
goto cleanup;
|
2005-09-27 08:52:17 +00:00
|
|
|
|
}
|
2005-09-26 11:39:24 +00:00
|
|
|
|
|
2005-10-21 10:13:26 +00:00
|
|
|
|
FileTimeToSystemTime(&SelectedDriver->Info.DriverDate, &DriverDate);
|
|
|
|
|
|
2005-10-24 09:16:34 +00:00
|
|
|
|
Result = SetupDiGetActualSectionToInstallW(
|
|
|
|
|
SelectedDriver->InfFileDetails->hInf,
|
|
|
|
|
SelectedDriver->Details.SectionName,
|
2005-09-26 11:39:24 +00:00
|
|
|
|
SectionName, MAX_PATH, &SectionNameLength, NULL);
|
|
|
|
|
if (!Result || SectionNameLength > MAX_PATH - 9)
|
2005-10-06 09:55:10 +00:00
|
|
|
|
goto cleanup;
|
2005-09-27 08:52:17 +00:00
|
|
|
|
pSectionName = &SectionName[wcslen(SectionName)];
|
2005-09-26 11:39:24 +00:00
|
|
|
|
|
2005-10-06 22:47:13 +00:00
|
|
|
|
/* Get information from [Version] section */
|
2005-10-24 09:16:34 +00:00
|
|
|
|
if (!SetupDiGetINFClassW(SelectedDriver->Details.InfFileName, &ClassGuid, ClassName, MAX_CLASS_NAME_LEN, &RequiredSize))
|
|
|
|
|
goto cleanup;
|
2005-10-06 22:47:13 +00:00
|
|
|
|
/* 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';
|
|
|
|
|
|
2005-10-14 16:53:18 +00:00
|
|
|
|
/* Open/Create driver key information */
|
2005-10-23 11:35:58 +00:00
|
|
|
|
#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
|
2005-10-14 16:53:18 +00:00
|
|
|
|
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)
|
2005-10-06 22:47:13 +00:00
|
|
|
|
goto cleanup;
|
|
|
|
|
|
2005-10-14 18:09:17 +00:00
|
|
|
|
/* Install main section */
|
2005-10-21 10:13:26 +00:00
|
|
|
|
DoAction = SPINST_REGISTRY;
|
|
|
|
|
if (!(InstallParams.Flags & DI_NOFILECOPY))
|
|
|
|
|
DoAction |= SPINST_FILES;
|
2005-10-14 18:09:17 +00:00
|
|
|
|
/* Files have already been copied in SetupDiInstallDriverFiles.
|
|
|
|
|
* Process only registry entries. */
|
|
|
|
|
*pSectionName = '\0';
|
2005-10-24 09:16:34 +00:00
|
|
|
|
Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
|
|
|
|
|
SelectedDriver->InfFileDetails->hInf, SectionName,
|
2005-10-21 10:13:26 +00:00
|
|
|
|
DoAction, hKey, NULL, SP_COPY_NEWER,
|
|
|
|
|
InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext,
|
|
|
|
|
DeviceInfoSet, DeviceInfoData);
|
2005-10-14 18:09:17 +00:00
|
|
|
|
if (!Result)
|
|
|
|
|
goto cleanup;
|
2005-10-21 10:13:26 +00:00
|
|
|
|
if (!(InstallParams.Flags & DI_NOFILECOPY) && !(InstallParams.Flags & DI_NOVCP))
|
|
|
|
|
{
|
|
|
|
|
Result = SetupCommitFileQueueW(InstallParams.hwndParent,
|
|
|
|
|
InstallParams.FileQueue,
|
|
|
|
|
InstallParams.InstallMsgHandler,
|
|
|
|
|
InstallParams.InstallMsgHandlerContext);
|
|
|
|
|
}
|
|
|
|
|
InstallParams.Flags |= DI_NOFILECOPY;
|
|
|
|
|
SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
|
2005-10-14 18:09:17 +00:00
|
|
|
|
|
2005-09-26 11:39:24 +00:00
|
|
|
|
/* Write information to driver key */
|
2005-10-06 22:47:13 +00:00
|
|
|
|
*pSectionName = UNICODE_NULL;
|
|
|
|
|
TRACE("Write information to driver key\n");
|
|
|
|
|
TRACE("DriverDate : '%u-%u-%u'\n", DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
|
2005-10-21 10:13:26 +00:00
|
|
|
|
TRACE("DriverDesc : '%S'\n", SelectedDriver->Info.Description);
|
|
|
|
|
TRACE("DriverVersion : '%u.%u.%u.%u'\n", SelectedDriver->Info.DriverVersion & 0xff, (SelectedDriver->Info.DriverVersion >> 8) & 0xff, (SelectedDriver->Info.DriverVersion >> 16) & 0xff, (SelectedDriver->Info.DriverVersion >> 24) & 0xff);
|
2005-10-22 16:25:48 +00:00
|
|
|
|
TRACE("InfPath : '%S'\n", SelectedDriver->Details.InfFileName);
|
|
|
|
|
TRACE("InfSection : '%S'\n", SelectedDriver->Details.SectionName);
|
|
|
|
|
TRACE("InfSectionExt : '%S'\n", &SectionName[wcslen(SelectedDriver->Details.SectionName)]);
|
2005-10-21 10:13:26 +00:00
|
|
|
|
TRACE("MatchingDeviceId: '%S'\n", SelectedDriver->MatchingId);
|
|
|
|
|
TRACE("ProviderName : '%S'\n", SelectedDriver->Info.ProviderName);
|
2005-10-06 22:47:13 +00:00
|
|
|
|
swprintf(Buffer, L"%u-%u-%u", DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
|
|
|
|
|
rc = RegSetValueEx(hKey, L"DriverDate", 0, REG_SZ, (const BYTE *)Buffer, (wcslen(Buffer) + 1) * sizeof(WCHAR));
|
|
|
|
|
if (rc == ERROR_SUCCESS)
|
2005-10-21 10:13:26 +00:00
|
|
|
|
rc = RegSetValueEx(hKey, L"DriverDateData", 0, REG_BINARY, (const BYTE *)&SelectedDriver->Info.DriverDate, sizeof(FILETIME));
|
2005-10-06 22:47:13 +00:00
|
|
|
|
if (rc == ERROR_SUCCESS)
|
2005-10-21 10:13:26 +00:00
|
|
|
|
rc = RegSetValueEx(hKey, L"DriverDesc", 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (wcslen(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
|
2005-10-06 22:47:13 +00:00
|
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
|
{
|
2005-10-21 10:13:26 +00:00
|
|
|
|
swprintf(Buffer, L"%u.%u.%u.%u", SelectedDriver->Info.DriverVersion & 0xff, (SelectedDriver->Info.DriverVersion >> 8) & 0xff, (SelectedDriver->Info.DriverVersion >> 16) & 0xff, (SelectedDriver->Info.DriverVersion >> 24) & 0xff);
|
2005-10-06 22:47:13 +00:00
|
|
|
|
rc = RegSetValueEx(hKey, L"DriverVersion", 0, REG_SZ, (const BYTE *)Buffer, (wcslen(Buffer) + 1) * sizeof(WCHAR));
|
|
|
|
|
}
|
|
|
|
|
if (rc == ERROR_SUCCESS)
|
2005-10-22 16:25:48 +00:00
|
|
|
|
rc = RegSetValueEx(hKey, L"InfPath", 0, REG_SZ, (const BYTE *)SelectedDriver->Details.InfFileName, (wcslen(SelectedDriver->Details.InfFileName) + 1) * sizeof(WCHAR));
|
2005-10-06 22:47:13 +00:00
|
|
|
|
if (rc == ERROR_SUCCESS)
|
2005-10-22 16:25:48 +00:00
|
|
|
|
rc = RegSetValueEx(hKey, L"InfSection", 0, REG_SZ, (const BYTE *)SelectedDriver->Details.SectionName, (wcslen(SelectedDriver->Details.SectionName) + 1) * sizeof(WCHAR));
|
2005-10-06 22:47:13 +00:00
|
|
|
|
if (rc == ERROR_SUCCESS)
|
2005-10-22 16:25:48 +00:00
|
|
|
|
rc = RegSetValueEx(hKey, L"InfSectionExt", 0, REG_SZ, (const BYTE *)&SectionName[wcslen(SelectedDriver->Details.SectionName)], (wcslen(SectionName) - wcslen(SelectedDriver->Details.SectionName) + 1) * sizeof(WCHAR));
|
2005-10-06 22:47:13 +00:00
|
|
|
|
if (rc == ERROR_SUCCESS)
|
2005-10-21 10:13:26 +00:00
|
|
|
|
rc = RegSetValueEx(hKey, L"MatchingDeviceId", 0, REG_SZ, (const BYTE *)SelectedDriver->MatchingId, (wcslen(SelectedDriver->MatchingId) + 1) * sizeof(WCHAR));
|
2005-10-06 22:47:13 +00:00
|
|
|
|
if (rc == ERROR_SUCCESS)
|
2005-10-21 10:13:26 +00:00
|
|
|
|
rc = RegSetValueEx(hKey, L"ProviderName", 0, REG_SZ, (const BYTE *)SelectedDriver->Info.ProviderName, (wcslen(SelectedDriver->Info.ProviderName) + 1) * sizeof(WCHAR));
|
2005-10-06 22:47:13 +00:00
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(rc);
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
|
hKey = INVALID_HANDLE_VALUE;
|
2005-09-26 11:39:24 +00:00
|
|
|
|
|
2005-10-21 10:13:26 +00:00
|
|
|
|
/* FIXME: Process .LogConfigOverride section */
|
|
|
|
|
|
2005-09-27 08:52:17 +00:00
|
|
|
|
/* Install .Services section */
|
|
|
|
|
wcscpy(pSectionName, L".Services");
|
2005-10-24 09:16:34 +00:00
|
|
|
|
Result = SetupFindFirstLineW(SelectedDriver->InfFileDetails->hInf, SectionName, NULL, &ContextService);
|
2005-09-26 11:39:24 +00:00
|
|
|
|
while (Result)
|
|
|
|
|
{
|
|
|
|
|
LPWSTR ServiceName = NULL;
|
|
|
|
|
LPWSTR ServiceSection = NULL;
|
|
|
|
|
|
|
|
|
|
Result = SetupGetStringFieldW(
|
|
|
|
|
&ContextService,
|
|
|
|
|
1, /* Field index */
|
|
|
|
|
NULL, 0,
|
|
|
|
|
&RequiredSize);
|
|
|
|
|
if (!Result)
|
2005-10-06 09:55:10 +00:00
|
|
|
|
goto nextfile;
|
2005-09-26 11:39:24 +00:00
|
|
|
|
if (RequiredSize > 0)
|
|
|
|
|
{
|
|
|
|
|
/* We got the needed size for the buffer */
|
|
|
|
|
ServiceName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
|
|
|
|
|
if (!ServiceName)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
2005-10-06 09:55:10 +00:00
|
|
|
|
goto nextfile;
|
2005-09-26 11:39:24 +00:00
|
|
|
|
}
|
|
|
|
|
Result = SetupGetStringFieldW(
|
|
|
|
|
&ContextService,
|
|
|
|
|
1, /* Field index */
|
|
|
|
|
ServiceName, RequiredSize,
|
|
|
|
|
&RequiredSize);
|
|
|
|
|
if (!Result)
|
2005-10-06 09:55:10 +00:00
|
|
|
|
goto nextfile;
|
2005-09-26 11:39:24 +00:00
|
|
|
|
}
|
|
|
|
|
Result = SetupGetIntField(
|
|
|
|
|
&ContextService,
|
|
|
|
|
2, /* Field index */
|
|
|
|
|
&Flags);
|
|
|
|
|
if (!Result)
|
|
|
|
|
{
|
|
|
|
|
/* The field may be empty. Ignore the error */
|
|
|
|
|
Flags = 0;
|
|
|
|
|
}
|
|
|
|
|
Result = SetupGetStringFieldW(
|
|
|
|
|
&ContextService,
|
|
|
|
|
3, /* Field index */
|
|
|
|
|
NULL, 0,
|
|
|
|
|
&RequiredSize);
|
|
|
|
|
if (!Result)
|
2005-10-06 09:55:10 +00:00
|
|
|
|
goto nextfile;
|
2005-09-26 11:39:24 +00:00
|
|
|
|
if (RequiredSize > 0)
|
|
|
|
|
{
|
|
|
|
|
/* We got the needed size for the buffer */
|
|
|
|
|
ServiceSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
|
|
|
|
|
if (!ServiceSection)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
2005-10-06 09:55:10 +00:00
|
|
|
|
goto nextfile;
|
2005-09-26 11:39:24 +00:00
|
|
|
|
}
|
|
|
|
|
Result = SetupGetStringFieldW(
|
|
|
|
|
&ContextService,
|
|
|
|
|
3, /* Field index */
|
|
|
|
|
ServiceSection, RequiredSize,
|
2005-10-24 09:16:34 +00:00
|
|
|
|
&RequiredSize);
|
2005-09-26 11:39:24 +00:00
|
|
|
|
if (!Result)
|
2005-10-24 09:16:34 +00:00
|
|
|
|
goto nextfile;
|
2005-09-26 11:39:24 +00:00
|
|
|
|
}
|
|
|
|
|
SetLastError(ERROR_SUCCESS);
|
2005-10-24 09:16:34 +00:00
|
|
|
|
Result = SetupInstallServicesFromInfSectionExW(
|
|
|
|
|
SelectedDriver->InfFileDetails->hInf,
|
|
|
|
|
ServiceSection, Flags, DeviceInfoSet, DeviceInfoData, ServiceName, NULL);
|
2005-09-26 11:39:24 +00:00
|
|
|
|
if (Result && (Flags & SPSVCINST_ASSOCSERVICE))
|
|
|
|
|
{
|
|
|
|
|
AssociatedService = ServiceName;
|
|
|
|
|
ServiceName = NULL;
|
|
|
|
|
if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED)
|
|
|
|
|
RebootRequired = TRUE;
|
|
|
|
|
}
|
2005-10-06 09:55:10 +00:00
|
|
|
|
nextfile:
|
2005-09-26 11:39:24 +00:00
|
|
|
|
HeapFree(GetProcessHeap(), 0, ServiceName);
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, ServiceSection);
|
|
|
|
|
if (!Result)
|
2005-10-06 09:55:10 +00:00
|
|
|
|
goto cleanup;
|
2005-09-26 11:39:24 +00:00
|
|
|
|
Result = SetupFindNextLine(&ContextService, &ContextService);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Copy .inf file to Inf\ directory */
|
|
|
|
|
FIXME("FIXME: Copy .inf file to Inf\\ directory\n"); /* SetupCopyOEMInf */
|
|
|
|
|
|
2005-10-14 16:53:18 +00:00
|
|
|
|
/* Open device registry key */
|
|
|
|
|
hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE);
|
|
|
|
|
if (hKey == INVALID_HANDLE_VALUE)
|
|
|
|
|
goto cleanup;
|
2005-09-27 08:52:17 +00:00
|
|
|
|
|
|
|
|
|
/* Install .HW section */
|
|
|
|
|
wcscpy(pSectionName, L".HW");
|
2005-10-24 09:16:34 +00:00
|
|
|
|
Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
|
|
|
|
|
SelectedDriver->InfFileDetails->hInf, SectionName,
|
2005-09-27 08:52:17 +00:00
|
|
|
|
SPINST_REGISTRY, hKey, NULL, 0,
|
2005-10-21 10:13:26 +00:00
|
|
|
|
InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext,
|
|
|
|
|
DeviceInfoSet, DeviceInfoData);
|
2005-09-27 08:52:17 +00:00
|
|
|
|
if (!Result)
|
2005-10-06 09:55:10 +00:00
|
|
|
|
goto cleanup;
|
2005-09-27 08:52:17 +00:00
|
|
|
|
|
|
|
|
|
/* Write information to enum key */
|
2005-10-06 22:47:13 +00:00
|
|
|
|
TRACE("Write information to enum key\n");
|
2005-09-27 08:52:17 +00:00
|
|
|
|
TRACE("Service : '%S'\n", AssociatedService);
|
2005-10-06 22:47:13 +00:00
|
|
|
|
TRACE("Class : '%S'\n", ClassName);
|
|
|
|
|
TRACE("ClassGUID : '%S'\n", lpFullGuidString);
|
2005-10-21 10:13:26 +00:00
|
|
|
|
TRACE("DeviceDesc : '%S'\n", SelectedDriver->Info.Description);
|
|
|
|
|
TRACE("Mfg : '%S'\n", SelectedDriver->Info.MfgName);
|
2005-09-26 11:39:24 +00:00
|
|
|
|
rc = RegSetValueEx(hKey, L"Service", 0, REG_SZ, (const BYTE *)AssociatedService, (wcslen(AssociatedService) + 1) * sizeof(WCHAR));
|
2005-10-06 22:47:13 +00:00
|
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
|
rc = RegSetValueEx(hKey, L"Class", 0, REG_SZ, (const BYTE *)ClassName, (wcslen(ClassName) + 1) * sizeof(WCHAR));
|
|
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
|
rc = RegSetValueEx(hKey, L"ClassGUID", 0, REG_SZ, (const BYTE *)lpFullGuidString, (wcslen(lpFullGuidString) + 1) * sizeof(WCHAR));
|
2005-09-26 11:39:24 +00:00
|
|
|
|
if (rc == ERROR_SUCCESS)
|
2005-10-21 10:13:26 +00:00
|
|
|
|
rc = RegSetValueEx(hKey, L"DeviceDesc", 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (wcslen(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
|
2005-09-26 11:39:24 +00:00
|
|
|
|
if (rc == ERROR_SUCCESS)
|
2005-10-21 10:13:26 +00:00
|
|
|
|
rc = RegSetValueEx(hKey, L"Mfg", 0, REG_SZ, (const BYTE *)SelectedDriver->Info.MfgName, (wcslen(SelectedDriver->Info.MfgName) + 1) * sizeof(WCHAR));
|
2005-09-26 11:39:24 +00:00
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(rc);
|
2005-10-06 09:55:10 +00:00
|
|
|
|
goto cleanup;
|
2005-09-26 11:39:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-10-08 15:52:14 +00:00
|
|
|
|
/* Start the device */
|
2005-10-21 10:13:26 +00:00
|
|
|
|
if (!RebootRequired && !(InstallParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT | DI_DONOTCALLCONFIGMG)))
|
2005-10-08 15:52:14 +00:00
|
|
|
|
{
|
|
|
|
|
PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData;
|
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
RtlInitUnicodeString(&ResetDeviceData.DeviceInstance, DevInfo->DeviceName);
|
|
|
|
|
Status = NtPlugPlayControl(PlugPlayControlResetDevice, &ResetDeviceData, sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA));
|
|
|
|
|
ret = NT_SUCCESS(Status);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
ret = TRUE;
|
2005-10-06 09:55:10 +00:00
|
|
|
|
|
|
|
|
|
cleanup:
|
2005-09-26 11:39:24 +00:00
|
|
|
|
/* End of installation */
|
2005-10-06 22:47:13 +00:00
|
|
|
|
if (hClassKey != INVALID_HANDLE_VALUE)
|
|
|
|
|
RegCloseKey(hClassKey);
|
2005-10-06 09:55:10 +00:00
|
|
|
|
if (hKey != INVALID_HANDLE_VALUE)
|
|
|
|
|
RegCloseKey(hKey);
|
2005-10-06 22:47:13 +00:00
|
|
|
|
if (lpGuidString)
|
|
|
|
|
RpcStringFreeW(&lpGuidString);
|
2005-09-26 11:39:24 +00:00
|
|
|
|
HeapFree(GetProcessHeap(), 0, (LPWSTR)AssociatedService);
|
2005-10-06 22:47:13 +00:00
|
|
|
|
HeapFree(GetProcessHeap(), 0, lpFullGuidString);
|
2005-10-06 09:55:10 +00:00
|
|
|
|
|
|
|
|
|
TRACE("Returning %d\n", ret);
|
|
|
|
|
return ret;
|
2005-08-12 19:03:35 +00:00
|
|
|
|
}
|