1538 lines
40 KiB
C
1538 lines
40 KiB
C
/*
|
|
* SetupAPI device installer
|
|
*
|
|
* Copyright 2000 Andreas Mohr for CodeWeavers
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "wine/port.h"
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "winnt.h"
|
|
#include "winreg.h"
|
|
#include "winternl.h"
|
|
#include "wingdi.h"
|
|
#include "winuser.h"
|
|
#include "winnls.h"
|
|
#include "setupapi.h"
|
|
#include "wine/debug.h"
|
|
#include "wine/unicode.h"
|
|
#include "cfgmgr32.h"
|
|
#include "initguid.h"
|
|
#include "winioctl.h"
|
|
#include "rpc.h"
|
|
#include "rpcdce.h"
|
|
|
|
#include "setupapi_private.h"
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
|
|
|
|
/* Unicode constants */
|
|
static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0};
|
|
static const WCHAR Class[] = {'C','l','a','s','s',0};
|
|
static const WCHAR ClassInstall32[] = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
|
|
static const WCHAR NoDisplayClass[] = {'N','o','D','i','s','p','l','a','y','C','l','a','s','s',0};
|
|
static const WCHAR NoInstallClass[] = {'N','o','I','s','t','a','l','l','C','l','a','s','s',0};
|
|
static const WCHAR NoUseClass[] = {'N','o','U','s','e','C','l','a','s','s',0};
|
|
static const WCHAR NtExtension[] = {'.','N','T',0};
|
|
static const WCHAR NtPlatformExtension[] = {'.','N','T','x','8','6',0};
|
|
static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
|
|
static const WCHAR WinExtension[] = {'.','W','i','n',0};
|
|
|
|
/* Registry key and value names */
|
|
static const WCHAR ControlClass[] = {'S','y','s','t','e','m','\\',
|
|
'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
|
|
'C','o','n','t','r','o','l','\\',
|
|
'C','l','a','s','s',0};
|
|
|
|
static const WCHAR DeviceClasses[] = {'S','y','s','t','e','m','\\',
|
|
'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
|
|
'C','o','n','t','r','o','l','\\',
|
|
'D','e','v','i','c','e','C','l','a','s','s','e','s',0};
|
|
|
|
/***********************************************************************
|
|
* SetupDiBuildClassInfoList (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiBuildClassInfoList(
|
|
DWORD Flags,
|
|
LPGUID ClassGuidList,
|
|
DWORD ClassGuidListSize,
|
|
PDWORD RequiredSize)
|
|
{
|
|
TRACE("\n");
|
|
return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
|
|
ClassGuidListSize, RequiredSize,
|
|
NULL, NULL);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiBuildClassInfoListExA (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiBuildClassInfoListExA(
|
|
DWORD Flags,
|
|
LPGUID ClassGuidList,
|
|
DWORD ClassGuidListSize,
|
|
PDWORD RequiredSize,
|
|
LPCSTR MachineName,
|
|
PVOID Reserved)
|
|
{
|
|
LPWSTR MachineNameW = NULL;
|
|
BOOL bResult;
|
|
|
|
TRACE("\n");
|
|
|
|
if (MachineName)
|
|
{
|
|
MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
|
|
if (MachineNameW == NULL) return FALSE;
|
|
}
|
|
|
|
bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
|
|
ClassGuidListSize, RequiredSize,
|
|
MachineNameW, Reserved);
|
|
|
|
if (MachineNameW)
|
|
MyFree(MachineNameW);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiBuildClassInfoListExW (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiBuildClassInfoListExW(
|
|
DWORD Flags,
|
|
LPGUID ClassGuidList,
|
|
DWORD ClassGuidListSize,
|
|
PDWORD RequiredSize,
|
|
LPCWSTR MachineName,
|
|
PVOID Reserved)
|
|
{
|
|
WCHAR szKeyName[40];
|
|
HKEY hClassesKey;
|
|
HKEY hClassKey;
|
|
DWORD dwLength;
|
|
DWORD dwIndex;
|
|
LONG lError;
|
|
DWORD dwGuidListIndex = 0;
|
|
|
|
TRACE("\n");
|
|
|
|
if (RequiredSize != NULL)
|
|
*RequiredSize = 0;
|
|
|
|
hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
|
|
KEY_ALL_ACCESS,
|
|
DIOCR_INSTALLER,
|
|
MachineName,
|
|
Reserved);
|
|
if (hClassesKey == INVALID_HANDLE_VALUE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
for (dwIndex = 0; ; dwIndex++)
|
|
{
|
|
dwLength = 40;
|
|
lError = RegEnumKeyExW(hClassesKey,
|
|
dwIndex,
|
|
szKeyName,
|
|
&dwLength,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
TRACE("RegEnumKeyExW() returns %ld\n", lError);
|
|
if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
|
|
{
|
|
TRACE("Key name: %p\n", szKeyName);
|
|
|
|
if (RegOpenKeyExW(hClassesKey,
|
|
szKeyName,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hClassKey))
|
|
{
|
|
RegCloseKey(hClassesKey);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!RegQueryValueExW(hClassKey,
|
|
NoUseClass,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
TRACE("'NoUseClass' value found!\n");
|
|
RegCloseKey(hClassKey);
|
|
continue;
|
|
}
|
|
|
|
if ((Flags & DIBCI_NOINSTALLCLASS) &&
|
|
(!RegQueryValueExW(hClassKey,
|
|
NoInstallClass,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL)))
|
|
{
|
|
TRACE("'NoInstallClass' value found!\n");
|
|
RegCloseKey(hClassKey);
|
|
continue;
|
|
}
|
|
|
|
if ((Flags & DIBCI_NODISPLAYCLASS) &&
|
|
(!RegQueryValueExW(hClassKey,
|
|
NoDisplayClass,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL)))
|
|
{
|
|
TRACE("'NoDisplayClass' value found!\n");
|
|
RegCloseKey(hClassKey);
|
|
continue;
|
|
}
|
|
|
|
RegCloseKey(hClassKey);
|
|
|
|
TRACE("Guid: %p\n", szKeyName);
|
|
if (dwGuidListIndex < ClassGuidListSize)
|
|
{
|
|
if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
|
|
{
|
|
szKeyName[37] = 0;
|
|
}
|
|
TRACE("Guid: %p\n", &szKeyName[1]);
|
|
|
|
UuidFromStringW(&szKeyName[1],
|
|
&ClassGuidList[dwGuidListIndex]);
|
|
}
|
|
|
|
dwGuidListIndex++;
|
|
}
|
|
|
|
if (lError != ERROR_SUCCESS)
|
|
break;
|
|
}
|
|
|
|
RegCloseKey(hClassesKey);
|
|
|
|
if (RequiredSize != NULL)
|
|
*RequiredSize = dwGuidListIndex;
|
|
|
|
if (ClassGuidListSize < dwGuidListIndex)
|
|
{
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiClassGuidsFromNameA (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiClassGuidsFromNameA(
|
|
LPCSTR ClassName,
|
|
LPGUID ClassGuidList,
|
|
DWORD ClassGuidListSize,
|
|
PDWORD RequiredSize)
|
|
{
|
|
return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
|
|
ClassGuidListSize, RequiredSize,
|
|
NULL, NULL);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiClassGuidsFromNameW (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiClassGuidsFromNameW(
|
|
LPCWSTR ClassName,
|
|
LPGUID ClassGuidList,
|
|
DWORD ClassGuidListSize,
|
|
PDWORD RequiredSize)
|
|
{
|
|
return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
|
|
ClassGuidListSize, RequiredSize,
|
|
NULL, NULL);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiClassGuidsFromNameExA (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiClassGuidsFromNameExA(
|
|
LPCSTR ClassName,
|
|
LPGUID ClassGuidList,
|
|
DWORD ClassGuidListSize,
|
|
PDWORD RequiredSize,
|
|
LPCSTR MachineName,
|
|
PVOID Reserved)
|
|
{
|
|
LPWSTR ClassNameW = NULL;
|
|
LPWSTR MachineNameW = NULL;
|
|
BOOL bResult;
|
|
|
|
FIXME("\n");
|
|
|
|
ClassNameW = MultiByteToUnicode(ClassName, CP_ACP);
|
|
if (ClassNameW == NULL)
|
|
return FALSE;
|
|
|
|
if (MachineNameW)
|
|
{
|
|
MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
|
|
if (MachineNameW == NULL)
|
|
{
|
|
MyFree(ClassNameW);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
|
|
ClassGuidListSize, RequiredSize,
|
|
MachineNameW, Reserved);
|
|
|
|
if (MachineNameW)
|
|
MyFree(MachineNameW);
|
|
|
|
MyFree(ClassNameW);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiClassGuidsFromNameExW (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiClassGuidsFromNameExW(
|
|
LPCWSTR ClassName,
|
|
LPGUID ClassGuidList,
|
|
DWORD ClassGuidListSize,
|
|
PDWORD RequiredSize,
|
|
LPCWSTR MachineName,
|
|
PVOID Reserved)
|
|
{
|
|
WCHAR szKeyName[40];
|
|
WCHAR szClassName[256];
|
|
HKEY hClassesKey;
|
|
HKEY hClassKey;
|
|
DWORD dwLength;
|
|
DWORD dwIndex;
|
|
LONG lError;
|
|
DWORD dwGuidListIndex = 0;
|
|
|
|
if (RequiredSize != NULL)
|
|
*RequiredSize = 0;
|
|
|
|
hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
|
|
KEY_ALL_ACCESS,
|
|
DIOCR_INSTALLER,
|
|
MachineName,
|
|
Reserved);
|
|
if (hClassesKey == INVALID_HANDLE_VALUE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
for (dwIndex = 0; ; dwIndex++)
|
|
{
|
|
dwLength = 40;
|
|
lError = RegEnumKeyExW(hClassesKey,
|
|
dwIndex,
|
|
szKeyName,
|
|
&dwLength,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
TRACE("RegEnumKeyExW() returns %ld\n", lError);
|
|
if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
|
|
{
|
|
TRACE("Key name: %p\n", szKeyName);
|
|
|
|
if (RegOpenKeyExW(hClassesKey,
|
|
szKeyName,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hClassKey))
|
|
{
|
|
RegCloseKey(hClassesKey);
|
|
return FALSE;
|
|
}
|
|
|
|
dwLength = 256 * sizeof(WCHAR);
|
|
if (!RegQueryValueExW(hClassKey,
|
|
Class,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)szClassName,
|
|
&dwLength))
|
|
{
|
|
TRACE("Class name: %p\n", szClassName);
|
|
|
|
if (strcmpiW(szClassName, ClassName) == 0)
|
|
{
|
|
TRACE("Found matching class name\n");
|
|
|
|
TRACE("Guid: %p\n", szKeyName);
|
|
if (dwGuidListIndex < ClassGuidListSize)
|
|
{
|
|
if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
|
|
{
|
|
szKeyName[37] = 0;
|
|
}
|
|
TRACE("Guid: %p\n", &szKeyName[1]);
|
|
|
|
UuidFromStringW(&szKeyName[1],
|
|
&ClassGuidList[dwGuidListIndex]);
|
|
}
|
|
|
|
dwGuidListIndex++;
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hClassKey);
|
|
}
|
|
|
|
if (lError != ERROR_SUCCESS)
|
|
break;
|
|
}
|
|
|
|
RegCloseKey(hClassesKey);
|
|
|
|
if (RequiredSize != NULL)
|
|
*RequiredSize = dwGuidListIndex;
|
|
|
|
if (ClassGuidListSize < dwGuidListIndex)
|
|
{
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiClassNameFromGuidA (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiClassNameFromGuidA(
|
|
const GUID* ClassGuid,
|
|
PSTR ClassName,
|
|
DWORD ClassNameSize,
|
|
PDWORD RequiredSize)
|
|
{
|
|
return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
|
|
ClassNameSize, RequiredSize,
|
|
NULL, NULL);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiClassNameFromGuidW (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiClassNameFromGuidW(
|
|
const GUID* ClassGuid,
|
|
PWSTR ClassName,
|
|
DWORD ClassNameSize,
|
|
PDWORD RequiredSize)
|
|
{
|
|
return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
|
|
ClassNameSize, RequiredSize,
|
|
NULL, NULL);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiClassNameFromGuidExA (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiClassNameFromGuidExA(
|
|
const GUID* ClassGuid,
|
|
PSTR ClassName,
|
|
DWORD ClassNameSize,
|
|
PDWORD RequiredSize,
|
|
PCSTR MachineName,
|
|
PVOID Reserved)
|
|
{
|
|
WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
|
|
LPWSTR MachineNameW = NULL;
|
|
BOOL ret;
|
|
|
|
if (MachineName)
|
|
MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
|
|
ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
|
|
NULL, MachineNameW, Reserved);
|
|
if (ret)
|
|
{
|
|
int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
|
|
ClassNameSize, NULL, NULL);
|
|
|
|
if (!ClassNameSize && RequiredSize)
|
|
*RequiredSize = len;
|
|
}
|
|
MyFree(MachineNameW);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiClassNameFromGuidExW (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiClassNameFromGuidExW(
|
|
const GUID* ClassGuid,
|
|
PWSTR ClassName,
|
|
DWORD ClassNameSize,
|
|
PDWORD RequiredSize,
|
|
PCWSTR MachineName,
|
|
PVOID Reserved)
|
|
{
|
|
HKEY hKey;
|
|
DWORD dwLength;
|
|
|
|
hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
|
|
KEY_ALL_ACCESS,
|
|
DIOCR_INSTALLER,
|
|
MachineName,
|
|
Reserved);
|
|
if (hKey == INVALID_HANDLE_VALUE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (RequiredSize != NULL)
|
|
{
|
|
dwLength = 0;
|
|
if (RegQueryValueExW(hKey,
|
|
Class,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&dwLength))
|
|
{
|
|
RegCloseKey(hKey);
|
|
return FALSE;
|
|
}
|
|
|
|
*RequiredSize = dwLength / sizeof(WCHAR);
|
|
}
|
|
|
|
dwLength = ClassNameSize * sizeof(WCHAR);
|
|
if (RegQueryValueExW(hKey,
|
|
Class,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)ClassName,
|
|
&dwLength))
|
|
{
|
|
RegCloseKey(hKey);
|
|
return FALSE;
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiCreateDeviceInfoList (SETUPAPI.@)
|
|
*/
|
|
HDEVINFO WINAPI
|
|
SetupDiCreateDeviceInfoList(const GUID *ClassGuid,
|
|
HWND hwndParent)
|
|
{
|
|
return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
|
|
*/
|
|
HDEVINFO WINAPI
|
|
SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
|
|
HWND hwndParent,
|
|
PCSTR MachineName,
|
|
PVOID Reserved)
|
|
{
|
|
LPWSTR MachineNameW = NULL;
|
|
HDEVINFO hDevInfo;
|
|
|
|
TRACE("\n");
|
|
|
|
if (MachineName)
|
|
{
|
|
MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
|
|
if (MachineNameW == NULL)
|
|
return (HDEVINFO)INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
|
|
MachineNameW, Reserved);
|
|
|
|
if (MachineNameW)
|
|
MyFree(MachineNameW);
|
|
|
|
return hDevInfo;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
|
|
*/
|
|
HDEVINFO WINAPI
|
|
SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
|
|
HWND hwndParent,
|
|
PCWSTR MachineName,
|
|
PVOID Reserved)
|
|
{
|
|
FIXME("\n");
|
|
return (HDEVINFO)INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiEnumDeviceInfo (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiEnumDeviceInfo(
|
|
HDEVINFO devinfo,
|
|
DWORD index,
|
|
PSP_DEVINFO_DATA info)
|
|
{
|
|
FIXME("%p %ld %p\n", devinfo, index, info);
|
|
|
|
if(info==NULL)
|
|
return FALSE;
|
|
if(info->cbSize < sizeof(*info))
|
|
return FALSE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetActualSectionToInstallA (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiGetActualSectionToInstallA(
|
|
HINF InfHandle,
|
|
PCSTR InfSectionName,
|
|
PSTR InfSectionWithExt,
|
|
DWORD InfSectionWithExtSize,
|
|
PDWORD RequiredSize,
|
|
PSTR *Extension)
|
|
{
|
|
FIXME("\n");
|
|
return FALSE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetActualSectionToInstallW (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiGetActualSectionToInstallW(
|
|
HINF InfHandle,
|
|
PCWSTR InfSectionName,
|
|
PWSTR InfSectionWithExt,
|
|
DWORD InfSectionWithExtSize,
|
|
PDWORD RequiredSize,
|
|
PWSTR *Extension)
|
|
{
|
|
WCHAR szBuffer[MAX_PATH];
|
|
DWORD dwLength;
|
|
DWORD dwFullLength;
|
|
LONG lLineCount = -1;
|
|
|
|
lstrcpyW(szBuffer, InfSectionName);
|
|
dwLength = lstrlenW(szBuffer);
|
|
|
|
if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
|
|
{
|
|
/* Test section name with '.NTx86' extension */
|
|
lstrcpyW(&szBuffer[dwLength], NtPlatformExtension);
|
|
lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
|
|
|
|
if (lLineCount == -1)
|
|
{
|
|
/* Test section name with '.NT' extension */
|
|
lstrcpyW(&szBuffer[dwLength], NtExtension);
|
|
lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Test section name with '.Win' extension */
|
|
lstrcpyW(&szBuffer[dwLength], WinExtension);
|
|
lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
|
|
}
|
|
|
|
if (lLineCount == -1)
|
|
{
|
|
/* Test section name without extension */
|
|
szBuffer[dwLength] = 0;
|
|
lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
|
|
}
|
|
|
|
if (lLineCount == -1)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
dwFullLength = lstrlenW(szBuffer);
|
|
|
|
if (InfSectionWithExt != NULL && InfSectionWithExtSize != 0)
|
|
{
|
|
if (InfSectionWithExtSize < (dwFullLength + 1))
|
|
{
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
lstrcpyW(InfSectionWithExt, szBuffer);
|
|
if (Extension != NULL)
|
|
{
|
|
*Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
|
|
}
|
|
}
|
|
|
|
if (RequiredSize != NULL)
|
|
{
|
|
*RequiredSize = dwFullLength + 1;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetClassDescriptionA (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiGetClassDescriptionA(
|
|
const GUID* ClassGuid,
|
|
PSTR ClassDescription,
|
|
DWORD ClassDescriptionSize,
|
|
PDWORD RequiredSize)
|
|
{
|
|
return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
|
|
ClassDescriptionSize,
|
|
RequiredSize, NULL, NULL);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetClassDescriptionW (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiGetClassDescriptionW(
|
|
const GUID* ClassGuid,
|
|
PWSTR ClassDescription,
|
|
DWORD ClassDescriptionSize,
|
|
PDWORD RequiredSize)
|
|
{
|
|
return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
|
|
ClassDescriptionSize,
|
|
RequiredSize, NULL, NULL);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetClassDescriptionExA (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiGetClassDescriptionExA(
|
|
const GUID* ClassGuid,
|
|
PSTR ClassDescription,
|
|
DWORD ClassDescriptionSize,
|
|
PDWORD RequiredSize,
|
|
PCSTR MachineName,
|
|
PVOID Reserved)
|
|
{
|
|
FIXME("\n");
|
|
return FALSE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetClassDescriptionExW (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiGetClassDescriptionExW(
|
|
const GUID* ClassGuid,
|
|
PWSTR ClassDescription,
|
|
DWORD ClassDescriptionSize,
|
|
PDWORD RequiredSize,
|
|
PCWSTR MachineName,
|
|
PVOID Reserved)
|
|
{
|
|
HKEY hKey;
|
|
DWORD dwLength;
|
|
|
|
hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
|
|
KEY_ALL_ACCESS,
|
|
DIOCR_INSTALLER,
|
|
MachineName,
|
|
Reserved);
|
|
if (hKey == INVALID_HANDLE_VALUE)
|
|
{
|
|
WARN("SetupDiOpenClassRegKeyExW() failed (Error %lu)\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
if (RequiredSize != NULL)
|
|
{
|
|
dwLength = 0;
|
|
if (RegQueryValueExW(hKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&dwLength))
|
|
{
|
|
RegCloseKey(hKey);
|
|
return FALSE;
|
|
}
|
|
|
|
*RequiredSize = dwLength / sizeof(WCHAR);
|
|
}
|
|
|
|
dwLength = ClassDescriptionSize * sizeof(WCHAR);
|
|
if (RegQueryValueExW(hKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)ClassDescription,
|
|
&dwLength))
|
|
{
|
|
RegCloseKey(hKey);
|
|
return FALSE;
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetClassDevsA (SETUPAPI.@)
|
|
*/
|
|
HDEVINFO WINAPI SetupDiGetClassDevsA(
|
|
CONST GUID *class,
|
|
LPCSTR enumstr,
|
|
HWND parent,
|
|
DWORD flags)
|
|
{
|
|
HDEVINFO ret;
|
|
LPWSTR enumstrW = NULL;
|
|
|
|
if (enumstr)
|
|
{
|
|
int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
|
|
enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
|
if (!enumstrW)
|
|
{
|
|
ret = (HDEVINFO)INVALID_HANDLE_VALUE;
|
|
goto end;
|
|
}
|
|
MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
|
|
}
|
|
ret = SetupDiGetClassDevsW(class, enumstrW, parent, flags);
|
|
HeapFree(GetProcessHeap(), 0, enumstrW);
|
|
|
|
end:
|
|
return ret;
|
|
}
|
|
|
|
#define SETUP_SERIAL_PORT_MAGIC 0xd00ff055
|
|
|
|
typedef struct _SerialPortName
|
|
{
|
|
WCHAR name[5];
|
|
} SerialPortName;
|
|
|
|
typedef struct _SerialPortList
|
|
{
|
|
DWORD magic;
|
|
UINT numPorts;
|
|
SerialPortName names[1];
|
|
} SerialPortList;
|
|
|
|
static HDEVINFO SETUP_CreateSerialDeviceList(void)
|
|
{
|
|
static const size_t initialSize = 100;
|
|
size_t size;
|
|
WCHAR buf[initialSize];
|
|
LPWSTR devices;
|
|
HDEVINFO ret;
|
|
BOOL failed = FALSE;
|
|
|
|
devices = buf;
|
|
size = initialSize;
|
|
do {
|
|
if (QueryDosDeviceW(NULL, devices, size) == 0)
|
|
{
|
|
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
size *= 2;
|
|
if (devices != buf)
|
|
HeapFree(GetProcessHeap(), 0, devices);
|
|
devices = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
|
|
if (!devices)
|
|
failed = TRUE;
|
|
else
|
|
*devices = 0;
|
|
}
|
|
else
|
|
failed = TRUE;
|
|
}
|
|
} while (!*devices && !failed);
|
|
if (!failed)
|
|
{
|
|
static const WCHAR comW[] = { 'C','O','M',0 };
|
|
LPWSTR ptr;
|
|
UINT numSerialPorts = 0;
|
|
SerialPortList *list;
|
|
|
|
for (ptr = devices; *ptr; ptr += strlenW(ptr) + 1)
|
|
{
|
|
if (!strncmpW(comW, ptr, sizeof(comW) / sizeof(comW[0]) - 1))
|
|
numSerialPorts++;
|
|
}
|
|
list = HeapAlloc(GetProcessHeap(), 0, sizeof(SerialPortList) +
|
|
numSerialPorts ? (numSerialPorts - 1) * sizeof(SerialPortName) : 0);
|
|
if (list)
|
|
{
|
|
list->magic = SETUP_SERIAL_PORT_MAGIC;
|
|
list->numPorts = 0;
|
|
for (ptr = devices; *ptr; ptr += strlenW(ptr) + 1)
|
|
{
|
|
if (!strncmpW(comW, ptr, sizeof(comW) / sizeof(comW[0]) - 1))
|
|
{
|
|
lstrcpynW(list->names[list->numPorts].name, ptr,
|
|
sizeof(list->names[list->numPorts].name) /
|
|
sizeof(list->names[list->numPorts].name[0]));
|
|
TRACE("Adding %s to list\n",
|
|
debugstr_w(list->names[list->numPorts].name));
|
|
list->numPorts++;
|
|
}
|
|
}
|
|
TRACE("list->numPorts is %d\n", list->numPorts);
|
|
}
|
|
ret = (HDEVINFO)list;
|
|
}
|
|
else
|
|
ret = (HDEVINFO)INVALID_HANDLE_VALUE;
|
|
if (devices != buf)
|
|
HeapFree(GetProcessHeap(), 0, devices);
|
|
TRACE("returning %p\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetClassDevsW (SETUPAPI.@)
|
|
*/
|
|
HDEVINFO WINAPI SetupDiGetClassDevsW(
|
|
CONST GUID *class,
|
|
LPCWSTR enumstr,
|
|
HWND parent,
|
|
DWORD flags)
|
|
{
|
|
HDEVINFO ret = (HDEVINFO)INVALID_HANDLE_VALUE;
|
|
|
|
TRACE("%s %s %p 0x%08lx\n", debugstr_guid(class), debugstr_w(enumstr),
|
|
parent, flags);
|
|
|
|
if (enumstr)
|
|
FIXME(": unimplemented for enumerator strings (%s)\n",
|
|
debugstr_w(enumstr));
|
|
else if (flags & DIGCF_ALLCLASSES)
|
|
FIXME(": unimplemented for DIGCF_ALLCLASSES\n");
|
|
else
|
|
{
|
|
if (IsEqualIID(class, &GUID_DEVINTERFACE_COMPORT))
|
|
ret = SETUP_CreateSerialDeviceList();
|
|
else if (IsEqualIID(class, &GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR))
|
|
ret = SETUP_CreateSerialDeviceList();
|
|
else
|
|
FIXME("(%s): stub\n", debugstr_guid(class));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiEnumDeviceInterfaces (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiEnumDeviceInterfaces(
|
|
HDEVINFO DeviceInfoSet,
|
|
PSP_DEVINFO_DATA DeviceInfoData,
|
|
CONST GUID * InterfaceClassGuid,
|
|
DWORD MemberIndex,
|
|
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
|
|
{
|
|
BOOL ret = FALSE;
|
|
|
|
TRACE("%p, %p, %s, 0x%08lx, %p\n", DeviceInfoSet, DeviceInfoData,
|
|
debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData);
|
|
if (!DeviceInterfaceData)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (DeviceInfoData)
|
|
FIXME(": unimplemented with PSP_DEVINFO_DATA set\n");
|
|
else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
|
|
{
|
|
/* FIXME: this assumes the only possible enumeration is of serial
|
|
* ports.
|
|
*/
|
|
SerialPortList *list = (SerialPortList *)DeviceInfoSet;
|
|
|
|
if (list->magic == SETUP_SERIAL_PORT_MAGIC)
|
|
{
|
|
if (MemberIndex >= list->numPorts)
|
|
SetLastError(ERROR_NO_MORE_ITEMS);
|
|
else
|
|
{
|
|
DeviceInterfaceData->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
|
memcpy(&DeviceInterfaceData->InterfaceClassGuid,
|
|
&GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR,
|
|
sizeof(DeviceInterfaceData->InterfaceClassGuid));
|
|
DeviceInterfaceData->Flags = 0;
|
|
/* Note: this appears to be dangerous, passing a private
|
|
* pointer a heap-allocated datum to the caller. However, the
|
|
* expected lifetime of the device data is the same as the
|
|
* HDEVINFO; once that is closed, the data are no longer valid.
|
|
*/
|
|
DeviceInterfaceData->Reserved =
|
|
(ULONG_PTR)&list->names[MemberIndex].name;
|
|
ret = TRUE;
|
|
}
|
|
}
|
|
else
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
}
|
|
else
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiDestroyDeviceInfoList (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
|
|
{
|
|
BOOL ret = FALSE;
|
|
|
|
TRACE("%p\n", devinfo);
|
|
if (devinfo && devinfo != (HDEVINFO)INVALID_HANDLE_VALUE)
|
|
{
|
|
/* FIXME: this assumes the only possible enumeration is of serial
|
|
* ports.
|
|
*/
|
|
SerialPortList *list = (SerialPortList *)devinfo;
|
|
|
|
if (list->magic == SETUP_SERIAL_PORT_MAGIC)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, list);
|
|
ret = TRUE;
|
|
}
|
|
else
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
}
|
|
else
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(
|
|
HDEVINFO DeviceInfoSet,
|
|
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
|
|
PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
|
|
DWORD DeviceInterfaceDetailDataSize,
|
|
PDWORD RequiredSize,
|
|
PSP_DEVINFO_DATA DeviceInfoData)
|
|
{
|
|
BOOL ret = FALSE;
|
|
|
|
TRACE("(%p, %p, %p, %ld, %p, %p)\n", DeviceInfoSet,
|
|
DeviceInterfaceData, DeviceInterfaceDetailData,
|
|
DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
|
|
if (!DeviceInterfaceData)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if ((DeviceInterfaceDetailDataSize && !DeviceInterfaceDetailData) ||
|
|
(DeviceInterfaceDetailData && !DeviceInterfaceDetailDataSize))
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
|
|
{
|
|
/* FIXME: this assumes the only possible enumeration is of serial
|
|
* ports.
|
|
*/
|
|
SerialPortList *list = (SerialPortList *)DeviceInfoSet;
|
|
|
|
if (list->magic == SETUP_SERIAL_PORT_MAGIC)
|
|
{
|
|
LPCWSTR devName = (LPCWSTR)DeviceInterfaceData->Reserved;
|
|
DWORD sizeRequired = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A) +
|
|
lstrlenW(devName);
|
|
|
|
if (sizeRequired > DeviceInterfaceDetailDataSize)
|
|
{
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
if (RequiredSize)
|
|
*RequiredSize = sizeRequired;
|
|
}
|
|
else
|
|
{
|
|
LPSTR dst = DeviceInterfaceDetailData->DevicePath;
|
|
LPCWSTR src = devName;
|
|
|
|
/* MSDN claims cbSize must be set by the caller, but it lies */
|
|
DeviceInterfaceDetailData->cbSize =
|
|
sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
|
|
for ( ; *src; src++, dst++)
|
|
*dst = *src;
|
|
*dst = '\0';
|
|
TRACE("DevicePath is %s\n",
|
|
debugstr_a(DeviceInterfaceDetailData->DevicePath));
|
|
if (DeviceInfoData)
|
|
{
|
|
DeviceInfoData->cbSize = sizeof(SP_DEVINFO_DATA);
|
|
memcpy(&DeviceInfoData->ClassGuid,
|
|
&GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR,
|
|
sizeof(DeviceInfoData->ClassGuid));
|
|
DeviceInfoData->DevInst = 0;
|
|
DeviceInfoData->Reserved = (ULONG_PTR)devName;
|
|
}
|
|
ret = TRUE;
|
|
}
|
|
}
|
|
else
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
}
|
|
else
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
TRACE("Returning %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
|
|
HDEVINFO DeviceInfoSet,
|
|
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
|
|
PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
|
|
DWORD DeviceInterfaceDetailDataSize,
|
|
PDWORD RequiredSize,
|
|
PSP_DEVINFO_DATA DeviceInfoData)
|
|
{
|
|
FIXME("(%p, %p, %p, %ld, %p, %p): stub\n", DeviceInfoSet,
|
|
DeviceInterfaceData, DeviceInterfaceDetailData,
|
|
DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
|
|
return FALSE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(
|
|
HDEVINFO devinfo,
|
|
PSP_DEVINFO_DATA DeviceInfoData,
|
|
DWORD Property,
|
|
PDWORD PropertyRegDataType,
|
|
PBYTE PropertyBuffer,
|
|
DWORD PropertyBufferSize,
|
|
PDWORD RequiredSize)
|
|
{
|
|
FIXME("%04lx %p %ld %p %p %ld %p\n", (DWORD)devinfo, DeviceInfoData,
|
|
Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
|
|
RequiredSize);
|
|
return FALSE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiInstallClassA (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiInstallClassA(
|
|
HWND hwndParent,
|
|
PCSTR InfFileName,
|
|
DWORD Flags,
|
|
HSPFILEQ FileQueue)
|
|
{
|
|
UNICODE_STRING FileNameW;
|
|
BOOL Result;
|
|
|
|
if (!RtlCreateUnicodeStringFromAsciiz(&FileNameW, InfFileName))
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
Result = SetupDiInstallClassW(hwndParent, FileNameW.Buffer, Flags, FileQueue);
|
|
|
|
RtlFreeUnicodeString(&FileNameW);
|
|
|
|
return Result;
|
|
}
|
|
|
|
static HKEY CreateClassKey(HINF hInf)
|
|
{
|
|
WCHAR FullBuffer[MAX_PATH];
|
|
WCHAR Buffer[MAX_PATH];
|
|
DWORD RequiredSize;
|
|
HKEY hClassKey;
|
|
|
|
if (!SetupGetLineTextW(NULL,
|
|
hInf,
|
|
Version,
|
|
ClassGUID,
|
|
Buffer,
|
|
MAX_PATH,
|
|
&RequiredSize))
|
|
{
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
lstrcpyW(FullBuffer, ControlClass);
|
|
lstrcatW(FullBuffer, Buffer);
|
|
|
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
FullBuffer,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hClassKey))
|
|
{
|
|
if (!SetupGetLineTextW(NULL,
|
|
hInf,
|
|
Version,
|
|
Class,
|
|
Buffer,
|
|
MAX_PATH,
|
|
&RequiredSize))
|
|
{
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
|
|
FullBuffer,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hClassKey,
|
|
NULL))
|
|
{
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
}
|
|
|
|
if (RegSetValueExW(hClassKey,
|
|
Class,
|
|
0,
|
|
REG_SZ,
|
|
(LPBYTE)Buffer,
|
|
RequiredSize * sizeof(WCHAR)))
|
|
{
|
|
RegCloseKey(hClassKey);
|
|
RegDeleteKeyW(HKEY_LOCAL_MACHINE,
|
|
FullBuffer);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
return hClassKey;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiInstallClassW (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiInstallClassW(
|
|
HWND hwndParent,
|
|
PCWSTR InfFileName,
|
|
DWORD Flags,
|
|
HSPFILEQ FileQueue)
|
|
{
|
|
WCHAR SectionName[MAX_PATH];
|
|
DWORD SectionNameLength = 0;
|
|
HINF hInf;
|
|
BOOL bFileQueueCreated = FALSE;
|
|
HKEY hClassKey;
|
|
|
|
|
|
FIXME("\n");
|
|
|
|
if ((Flags & DI_NOVCP) && (FileQueue == NULL || FileQueue == INVALID_HANDLE_VALUE))
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Open the .inf file */
|
|
hInf = SetupOpenInfFileW(InfFileName,
|
|
NULL,
|
|
INF_STYLE_WIN4,
|
|
NULL);
|
|
if (hInf == INVALID_HANDLE_VALUE)
|
|
{
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* Create or open the class registry key 'HKLM\\CurrentControlSet\\Class\\{GUID}' */
|
|
hClassKey = CreateClassKey(hInf);
|
|
if (hClassKey == INVALID_HANDLE_VALUE)
|
|
{
|
|
SetupCloseInfFile(hInf);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/* Try to append a layout file */
|
|
#if 0
|
|
SetupOpenAppendInfFileW(NULL, hInf, NULL);
|
|
#endif
|
|
|
|
/* Retrieve the actual section name */
|
|
SetupDiGetActualSectionToInstallW(hInf,
|
|
ClassInstall32,
|
|
SectionName,
|
|
MAX_PATH,
|
|
&SectionNameLength,
|
|
NULL);
|
|
|
|
#if 0
|
|
if (!(Flags & DI_NOVCP))
|
|
{
|
|
FileQueue = SetupOpenFileQueue();
|
|
if (FileQueue == INVALID_HANDLE_VALUE)
|
|
{
|
|
SetupCloseInfFile(hInf);
|
|
return FALSE;
|
|
}
|
|
|
|
bFileQueueCreated = TRUE;
|
|
|
|
}
|
|
#endif
|
|
|
|
SetupInstallFromInfSectionW(NULL,
|
|
hInf,
|
|
SectionName,
|
|
SPINST_REGISTRY,
|
|
hClassKey,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
INVALID_HANDLE_VALUE,
|
|
NULL);
|
|
|
|
/* FIXME: More code! */
|
|
|
|
if (bFileQueueCreated)
|
|
SetupCloseFileQueue(FileQueue);
|
|
|
|
SetupCloseInfFile(hInf);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* SetupDiOpenClassRegKey (SETUPAPI.@)
|
|
*/
|
|
HKEY WINAPI SetupDiOpenClassRegKey(
|
|
const GUID* ClassGuid,
|
|
REGSAM samDesired)
|
|
{
|
|
return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
|
|
DIOCR_INSTALLER, NULL, NULL);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* SetupDiOpenClassRegKeyExA (SETUPAPI.@)
|
|
*/
|
|
HKEY WINAPI SetupDiOpenClassRegKeyExA(
|
|
const GUID* ClassGuid,
|
|
REGSAM samDesired,
|
|
DWORD Flags,
|
|
PCSTR MachineName,
|
|
PVOID Reserved)
|
|
{
|
|
PWSTR MachineNameW = NULL;
|
|
HKEY hKey;
|
|
|
|
TRACE("\n");
|
|
|
|
if (MachineName)
|
|
{
|
|
MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
|
|
if (MachineNameW == NULL)
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
|
|
Flags, MachineNameW, Reserved);
|
|
|
|
if (MachineNameW)
|
|
MyFree(MachineNameW);
|
|
|
|
return hKey;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* SetupDiOpenClassRegKeyExW (SETUPAPI.@)
|
|
*/
|
|
HKEY WINAPI SetupDiOpenClassRegKeyExW(
|
|
const GUID* ClassGuid,
|
|
REGSAM samDesired,
|
|
DWORD Flags,
|
|
PCWSTR MachineName,
|
|
PVOID Reserved)
|
|
{
|
|
LPWSTR lpGuidString;
|
|
HKEY hClassesKey;
|
|
HKEY hClassKey;
|
|
LPCWSTR lpKeyName;
|
|
|
|
if (MachineName != NULL)
|
|
{
|
|
FIXME("Remote access not supported yet!\n");
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if (Flags == DIOCR_INSTALLER)
|
|
{
|
|
lpKeyName = ControlClass;
|
|
}
|
|
else if (Flags == DIOCR_INTERFACE)
|
|
{
|
|
lpKeyName = DeviceClasses;
|
|
}
|
|
else
|
|
{
|
|
ERR("Invalid Flags parameter!\n");
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
lpKeyName,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hClassesKey))
|
|
{
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if (ClassGuid == NULL)
|
|
return hClassesKey;
|
|
|
|
if (UuidToStringW((UUID*)ClassGuid, &lpGuidString) != RPC_S_OK)
|
|
{
|
|
RegCloseKey(hClassesKey);
|
|
return FALSE;
|
|
}
|
|
|
|
if (RegOpenKeyExW(hClassesKey,
|
|
lpGuidString,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hClassKey))
|
|
{
|
|
RpcStringFreeW(&lpGuidString);
|
|
RegCloseKey(hClassesKey);
|
|
return FALSE;
|
|
}
|
|
|
|
RpcStringFreeW(&lpGuidString);
|
|
RegCloseKey(hClassesKey);
|
|
|
|
return hClassKey;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiOpenDeviceInterfaceW(
|
|
HDEVINFO DeviceInfoSet,
|
|
PCWSTR DevicePath,
|
|
DWORD OpenFlags,
|
|
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
|
|
{
|
|
FIXME("%p %s %08lx %p\n",
|
|
DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
|
|
return FALSE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiOpenDeviceInterfaceA(
|
|
HDEVINFO DeviceInfoSet,
|
|
PCSTR DevicePath,
|
|
DWORD OpenFlags,
|
|
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
|
|
{
|
|
FIXME("%p %s %08lx %p\n", DeviceInfoSet,
|
|
debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
|
|
return FALSE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiSetClassInstallParamsA (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiSetClassInstallParamsA(
|
|
HDEVINFO DeviceInfoSet,
|
|
PSP_DEVINFO_DATA DeviceInfoData,
|
|
PSP_CLASSINSTALL_HEADER ClassInstallParams,
|
|
DWORD ClassInstallParamsSize)
|
|
{
|
|
FIXME("%p %p %x %lu\n",DeviceInfoSet, DeviceInfoData,
|
|
ClassInstallParams->InstallFunction, ClassInstallParamsSize);
|
|
return FALSE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiCallClassInstaller (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiCallClassInstaller(
|
|
DI_FUNCTION InstallFunction,
|
|
HDEVINFO DeviceInfoSet,
|
|
PSP_DEVINFO_DATA DeviceInfoData)
|
|
{
|
|
FIXME("%d %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
|
|
return FALSE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
|
|
*/
|
|
BOOL WINAPI SetupDiGetDeviceInstallParamsA(
|
|
HDEVINFO DeviceInfoSet,
|
|
PSP_DEVINFO_DATA DeviceInfoData,
|
|
PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
|
|
{
|
|
FIXME("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
|
|
return FALSE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SetupDiOpenDevRegKey (SETUPAPI.@)
|
|
*/
|
|
HKEY WINAPI SetupDiOpenDevRegKey(
|
|
HDEVINFO DeviceInfoSet,
|
|
PSP_DEVINFO_DATA DeviceInfoData,
|
|
DWORD Scope,
|
|
DWORD HwProfile,
|
|
DWORD KeyType,
|
|
REGSAM samDesired)
|
|
{
|
|
FIXME("%p %p %ld %ld %ld %lx\n", DeviceInfoSet, DeviceInfoData,
|
|
Scope, HwProfile, KeyType, samDesired);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|