mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +00:00
5111 lines
124 KiB
C
5111 lines
124 KiB
C
/*
|
|
* ReactOS kernel
|
|
* Copyright (C) 2005 ReactOS Team
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* FILE: base/services/umpnpmgr/rpcserver.c
|
|
* PURPOSE: RPC server
|
|
* PROGRAMMER: Eric Kohl (eric.kohl@reactos.org)
|
|
* Hervé Poussineau (hpoussin@reactos.org)
|
|
* Colin Finck (colin@reactos.org)
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include "precomp.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
|
|
/* GLOBALS ******************************************************************/
|
|
|
|
static WCHAR szRootDeviceInstanceID[] = L"HTREE\\ROOT\\0";
|
|
|
|
LIST_ENTRY NotificationListHead;
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
DWORD WINAPI
|
|
RpcServerThread(LPVOID lpParameter)
|
|
{
|
|
RPC_STATUS Status;
|
|
BOOLEAN RegisteredProtSeq = FALSE;
|
|
|
|
UNREFERENCED_PARAMETER(lpParameter);
|
|
|
|
DPRINT("RpcServerThread() called\n");
|
|
|
|
InitializeListHead(&NotificationListHead);
|
|
|
|
#if 0
|
|
/* 2k/XP/2k3-compatible protocol sequence/endpoint */
|
|
Status = RpcServerUseProtseqEpW(L"ncacn_np",
|
|
20,
|
|
L"\\pipe\\ntsvcs",
|
|
NULL); // Security descriptor
|
|
if (Status == RPC_S_OK)
|
|
RegisteredProtSeq = TRUE;
|
|
else
|
|
DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
|
|
#endif
|
|
|
|
/* Vista/7-compatible protocol sequence/endpoint */
|
|
Status = RpcServerUseProtseqEpW(L"ncacn_np",
|
|
20,
|
|
L"\\pipe\\plugplay",
|
|
NULL); // Security descriptor
|
|
if (Status == RPC_S_OK)
|
|
RegisteredProtSeq = TRUE;
|
|
else
|
|
DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
|
|
|
|
/* Make sure there's a usable endpoint */
|
|
if (RegisteredProtSeq == FALSE)
|
|
return 0;
|
|
|
|
Status = RpcServerRegisterIf(pnp_v1_0_s_ifspec,
|
|
NULL,
|
|
NULL);
|
|
if (Status != RPC_S_OK)
|
|
{
|
|
DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status);
|
|
return 0;
|
|
}
|
|
|
|
Status = RpcServerListen(1,
|
|
20,
|
|
FALSE);
|
|
if (Status != RPC_S_OK)
|
|
{
|
|
DPRINT1("RpcServerListen() failed (Status %lx)\n", Status);
|
|
return 0;
|
|
}
|
|
|
|
/* ROS HACK (this should never happen...) */
|
|
DPRINT1("*** Other devices won't be installed correctly. If something\n");
|
|
DPRINT1("*** doesn't work, try to reboot to get a new chance.\n");
|
|
|
|
DPRINT("RpcServerThread() done\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
|
|
{
|
|
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
|
|
}
|
|
|
|
|
|
void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, ptr);
|
|
}
|
|
|
|
|
|
static CONFIGRET WINAPI
|
|
NtStatusToCrError(NTSTATUS Status)
|
|
{
|
|
switch (Status)
|
|
{
|
|
case STATUS_NOT_IMPLEMENTED:
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
|
|
case STATUS_INVALID_PARAMETER:
|
|
return CR_INVALID_DATA;
|
|
|
|
case STATUS_NO_SUCH_DEVICE:
|
|
return CR_NO_SUCH_DEVINST;
|
|
|
|
case STATUS_ACCESS_DENIED:
|
|
return CR_ACCESS_DENIED;
|
|
|
|
case STATUS_BUFFER_TOO_SMALL:
|
|
return CR_BUFFER_SMALL;
|
|
|
|
case STATUS_OBJECT_NAME_NOT_FOUND:
|
|
return CR_NO_SUCH_VALUE;
|
|
|
|
default:
|
|
return CR_FAILURE;
|
|
}
|
|
}
|
|
|
|
|
|
static VOID
|
|
SplitDeviceInstanceID(IN LPWSTR pszDeviceInstanceID,
|
|
OUT LPWSTR pszEnumerator,
|
|
OUT LPWSTR pszDevice,
|
|
OUT LPWSTR pszInstance)
|
|
{
|
|
WCHAR szLocalDeviceInstanceID[MAX_DEVICE_ID_LEN];
|
|
LPWSTR lpEnumerator = NULL;
|
|
LPWSTR lpDevice = NULL;
|
|
LPWSTR lpInstance = NULL;
|
|
LPWSTR ptr;
|
|
|
|
wcscpy(szLocalDeviceInstanceID, pszDeviceInstanceID);
|
|
|
|
*pszEnumerator = 0;
|
|
*pszDevice = 0;
|
|
*pszInstance = 0;
|
|
|
|
lpEnumerator = szLocalDeviceInstanceID;
|
|
|
|
ptr = wcschr(lpEnumerator, L'\\');
|
|
if (ptr != NULL)
|
|
{
|
|
*ptr = 0;
|
|
lpDevice = ++ptr;
|
|
|
|
ptr = wcschr(lpDevice, L'\\');
|
|
if (ptr != NULL)
|
|
{
|
|
*ptr = 0;
|
|
lpInstance = ++ptr;
|
|
}
|
|
}
|
|
|
|
if (lpEnumerator != NULL)
|
|
wcscpy(pszEnumerator, lpEnumerator);
|
|
|
|
if (lpDevice != NULL)
|
|
wcscpy(pszDevice, lpDevice);
|
|
|
|
if (lpInstance != NULL)
|
|
wcscpy(pszInstance, lpInstance);
|
|
}
|
|
|
|
|
|
static
|
|
CONFIGRET
|
|
ClearDeviceStatus(
|
|
_In_ LPWSTR pszDeviceID,
|
|
_In_ DWORD ulStatus,
|
|
_In_ DWORD ulProblem)
|
|
{
|
|
PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT1("ClearDeviceStatus(%S 0x%lx 0x%lx)\n",
|
|
pszDeviceID, ulStatus, ulProblem);
|
|
|
|
RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
|
|
pszDeviceID);
|
|
PlugPlayData.Operation = PNP_CLEAR_DEVICE_STATUS;
|
|
PlugPlayData.DeviceStatus = ulStatus;
|
|
PlugPlayData.DeviceProblem = ulProblem;
|
|
|
|
Status = NtPlugPlayControl(PlugPlayControlDeviceStatus,
|
|
(PVOID)&PlugPlayData,
|
|
sizeof(PLUGPLAY_CONTROL_STATUS_DATA));
|
|
if (!NT_SUCCESS(Status))
|
|
ret = NtStatusToCrError(Status);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static
|
|
CONFIGRET
|
|
GetDeviceStatus(
|
|
_In_ LPWSTR pszDeviceID,
|
|
_Out_ DWORD *pulStatus,
|
|
_Out_ DWORD *pulProblem)
|
|
{
|
|
PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("GetDeviceStatus(%S %p %p)\n",
|
|
pszDeviceID, pulStatus, pulProblem);
|
|
|
|
RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
|
|
pszDeviceID);
|
|
PlugPlayData.Operation = PNP_GET_DEVICE_STATUS;
|
|
|
|
Status = NtPlugPlayControl(PlugPlayControlDeviceStatus,
|
|
(PVOID)&PlugPlayData,
|
|
sizeof(PLUGPLAY_CONTROL_STATUS_DATA));
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
*pulStatus = PlugPlayData.DeviceStatus;
|
|
*pulProblem = PlugPlayData.DeviceProblem;
|
|
}
|
|
else
|
|
{
|
|
ret = NtStatusToCrError(Status);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static
|
|
CONFIGRET
|
|
SetDeviceStatus(
|
|
_In_ LPWSTR pszDeviceID,
|
|
_In_ DWORD ulStatus,
|
|
_In_ DWORD ulProblem)
|
|
{
|
|
PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT1("SetDeviceStatus(%S 0x%lx 0x%lx)\n",
|
|
pszDeviceID, ulStatus, ulProblem);
|
|
|
|
RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
|
|
pszDeviceID);
|
|
PlugPlayData.Operation = PNP_SET_DEVICE_STATUS;
|
|
PlugPlayData.DeviceStatus = ulStatus;
|
|
PlugPlayData.DeviceProblem = ulProblem;
|
|
|
|
Status = NtPlugPlayControl(PlugPlayControlDeviceStatus,
|
|
(PVOID)&PlugPlayData,
|
|
sizeof(PLUGPLAY_CONTROL_STATUS_DATA));
|
|
if (!NT_SUCCESS(Status))
|
|
ret = NtStatusToCrError(Status);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static
|
|
CONFIGRET
|
|
DisableDeviceInstance(
|
|
_In_ LPWSTR pszDeviceInstance,
|
|
_Inout_opt_ PPNP_VETO_TYPE pVetoType,
|
|
_Inout_opt_ LPWSTR pszVetoName,
|
|
_In_ DWORD ulNameLength)
|
|
{
|
|
PLUGPLAY_CONTROL_QUERY_REMOVE_DATA QueryRemoveData;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT1("DisableDeviceInstance(%S %p %p %lu)\n",
|
|
pszDeviceInstance, pVetoType, pszVetoName, ulNameLength);
|
|
|
|
RtlInitUnicodeString(&QueryRemoveData.DeviceInstance,
|
|
pszDeviceInstance);
|
|
|
|
QueryRemoveData.Flags = 0;
|
|
QueryRemoveData.VetoType = 0;
|
|
QueryRemoveData.VetoName = pszVetoName;
|
|
QueryRemoveData.NameLength = ulNameLength;
|
|
|
|
Status = NtPlugPlayControl(PlugPlayControlQueryAndRemoveDevice,
|
|
&QueryRemoveData,
|
|
sizeof(PLUGPLAY_CONTROL_QUERY_REMOVE_DATA));
|
|
if (Status == STATUS_NO_SUCH_DEVICE)
|
|
{
|
|
ret = CR_INVALID_DEVNODE;
|
|
}
|
|
else if (Status == STATUS_PLUGPLAY_QUERY_VETOED)
|
|
{
|
|
if (pVetoType != NULL)
|
|
*pVetoType = QueryRemoveData.VetoType;
|
|
|
|
ret = CR_REMOVE_VETOED;
|
|
}
|
|
else if (!NT_SUCCESS(Status))
|
|
{
|
|
ret = NtStatusToCrError(Status);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static
|
|
BOOL
|
|
IsValidDeviceInstanceID(
|
|
_In_ PWSTR pszDeviceInstanceID)
|
|
{
|
|
INT nPartLength[3] = {0, 0, 0};
|
|
INT nLength = 0, nParts = 0;
|
|
PWCHAR p;
|
|
|
|
DPRINT("IsValidDeviceInstanceID(%S)\n",
|
|
pszDeviceInstanceID);
|
|
|
|
if (pszDeviceInstanceID == NULL)
|
|
{
|
|
DPRINT("Device instance ID is NULL!\n");
|
|
return FALSE;
|
|
}
|
|
|
|
p = pszDeviceInstanceID;
|
|
while (*p != UNICODE_NULL)
|
|
{
|
|
if (*p == L'\\')
|
|
{
|
|
nParts++;
|
|
if (nParts >= 3)
|
|
{
|
|
DPRINT("Too many separators: %d\n", nParts);
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nPartLength[nParts]++;
|
|
}
|
|
|
|
nLength++;
|
|
if (nLength >= MAX_DEVICE_ID_LEN)
|
|
{
|
|
DPRINT("Too long: %d\n", nLength);
|
|
return FALSE;
|
|
}
|
|
|
|
p++;
|
|
}
|
|
|
|
if (nParts != 2)
|
|
{
|
|
DPRINT("Invalid number of separtors: %d\n", nParts);
|
|
return FALSE;
|
|
}
|
|
|
|
if ((nPartLength[0] == 0) ||
|
|
(nPartLength[1] == 0) ||
|
|
(nPartLength[2] == 0))
|
|
{
|
|
DPRINT("Invalid part lengths: %d %d %d\n",
|
|
nPartLength[0], nPartLength[1], nPartLength[2]);
|
|
return FALSE;
|
|
}
|
|
|
|
DPRINT("Valid device instance ID!\n");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static
|
|
BOOL
|
|
IsRootDeviceInstanceID(
|
|
_In_ PWSTR pszDeviceInstanceID)
|
|
{
|
|
if (_wcsicmp(pszDeviceInstanceID, szRootDeviceInstanceID) == 0)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static
|
|
BOOL
|
|
IsPresentDeviceInstanceID(
|
|
_In_ LPWSTR pszDeviceInstanceID)
|
|
{
|
|
DWORD ulStatus, ulProblem;
|
|
|
|
return (GetDeviceStatus(pszDeviceInstanceID, &ulStatus, &ulProblem) == CR_SUCCESS);
|
|
}
|
|
|
|
|
|
static
|
|
CONFIGRET
|
|
OpenConfigurationKey(
|
|
_In_ LPCWSTR pszDeviceID,
|
|
_In_ DWORD ulLogConfType,
|
|
_Out_ PHKEY phKey)
|
|
{
|
|
WCHAR szKeyName[MAX_PATH];
|
|
PCWSTR pszSubKeyName;
|
|
HKEY hInstanceKey;
|
|
DWORD dwError;
|
|
|
|
/* Build the full device instance key name */
|
|
wcscpy(szKeyName, L"System\\CurrentControlSet\\Enum\\");
|
|
wcscat(szKeyName, pszDeviceID);
|
|
|
|
/* Open the device instance key */
|
|
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
szKeyName,
|
|
0,
|
|
KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY,
|
|
&hInstanceKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
return CR_INVALID_DEVINST;
|
|
|
|
switch (ulLogConfType)
|
|
{
|
|
case BOOT_LOG_CONF:
|
|
case BASIC_LOG_CONF:
|
|
pszSubKeyName = L"LogConf";
|
|
break;
|
|
|
|
case ALLOC_LOG_CONF:
|
|
case FILTERED_LOG_CONF:
|
|
pszSubKeyName = L"Control";
|
|
break;
|
|
|
|
default:
|
|
DPRINT1("Unsupported configuration type!\n");
|
|
return CR_FAILURE;
|
|
}
|
|
|
|
/* Create or open the LogConf key */
|
|
dwError = RegCreateKeyExW(hInstanceKey,
|
|
pszSubKeyName,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
phKey,
|
|
NULL);
|
|
|
|
/* Close the device instance key */
|
|
RegCloseKey(hInstanceKey);
|
|
|
|
if (dwError != ERROR_SUCCESS)
|
|
return CR_REGISTRY_ERROR;
|
|
|
|
return CR_SUCCESS;
|
|
}
|
|
|
|
|
|
static
|
|
CONFIGRET
|
|
GetConfigurationData(
|
|
_In_ HKEY hKey,
|
|
_In_ ULONG ulLogConfType,
|
|
_Out_ PULONG pulRegDataType,
|
|
_Out_ PULONG pulDataSize,
|
|
_Out_ LPBYTE *ppBuffer)
|
|
{
|
|
LPCWSTR pszValueName;
|
|
|
|
switch (ulLogConfType)
|
|
{
|
|
case BOOT_LOG_CONF:
|
|
pszValueName = L"BootConfig";
|
|
*pulRegDataType = REG_RESOURCE_LIST;
|
|
break;
|
|
|
|
case ALLOC_LOG_CONF:
|
|
pszValueName = L"AllocConfig";
|
|
*pulRegDataType = REG_RESOURCE_LIST;
|
|
break;
|
|
|
|
case FORCED_LOG_CONF:
|
|
pszValueName = L"ForcedConfig";
|
|
*pulRegDataType = REG_RESOURCE_LIST;
|
|
break;
|
|
|
|
case FILTERED_LOG_CONF:
|
|
pszValueName = L"FilteredConfigVector";
|
|
*pulRegDataType = REG_RESOURCE_REQUIREMENTS_LIST;
|
|
break;
|
|
|
|
case BASIC_LOG_CONF:
|
|
pszValueName = L"BasicConfigVector";
|
|
*pulRegDataType = REG_RESOURCE_REQUIREMENTS_LIST;
|
|
break;
|
|
|
|
case OVERRIDE_LOG_CONF:
|
|
pszValueName = L"OverrideConfigVector";
|
|
*pulRegDataType = REG_RESOURCE_REQUIREMENTS_LIST;
|
|
break;
|
|
|
|
default:
|
|
DPRINT1("Unsupported configuration type!\n");
|
|
return CR_FAILURE;
|
|
}
|
|
|
|
/* Get the configuration data size */
|
|
if (RegQueryValueExW(hKey,
|
|
pszValueName,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
pulDataSize) != ERROR_SUCCESS)
|
|
{
|
|
return CR_INVALID_LOG_CONF;
|
|
}
|
|
|
|
/* Allocate the buffer */
|
|
*ppBuffer = HeapAlloc(GetProcessHeap(), 0, *pulDataSize);
|
|
if (*ppBuffer == NULL)
|
|
{
|
|
return CR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
/* Retrieve the configuration data */
|
|
if (RegQueryValueExW(hKey,
|
|
pszValueName,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)*ppBuffer,
|
|
pulDataSize) != ERROR_SUCCESS)
|
|
{
|
|
return CR_INVALID_LOG_CONF;
|
|
}
|
|
|
|
return CR_SUCCESS;
|
|
}
|
|
|
|
|
|
static
|
|
BOOL
|
|
IsCallerInteractive(
|
|
_In_ handle_t hBinding)
|
|
{
|
|
SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
|
|
HANDLE hToken;
|
|
PSID pInteractiveSid = NULL;
|
|
BOOL bInteractive = FALSE;
|
|
RPC_STATUS RpcStatus;
|
|
|
|
DPRINT("IsCallerInteractive(%p)\n", hBinding);
|
|
|
|
/* Allocate an interactive user sid */
|
|
if (!AllocateAndInitializeSid(&NtAuthority,
|
|
1,
|
|
SECURITY_INTERACTIVE_RID,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
&pInteractiveSid))
|
|
{
|
|
DPRINT1("AllocateAndInitializeSid failed\n");
|
|
return FALSE;
|
|
}
|
|
|
|
/* Impersonate the client */
|
|
RpcStatus = RpcImpersonateClient(hBinding);
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
DPRINT1("RpcImpersonateClient failed (Status 0x%08lx)\n", RpcStatus);
|
|
goto done;
|
|
}
|
|
|
|
/* Open the thread token and check for interactive user membership */
|
|
if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken))
|
|
{
|
|
CheckTokenMembership(hToken, pInteractiveSid, &bInteractive);
|
|
CloseHandle(hToken);
|
|
}
|
|
|
|
/* Revert the impersonation */
|
|
RpcRevertToSelf();
|
|
|
|
done:
|
|
if (pInteractiveSid)
|
|
FreeSid(pInteractiveSid);
|
|
|
|
return bInteractive;
|
|
}
|
|
|
|
|
|
VOID
|
|
__RPC_USER
|
|
PNP_NOTIFY_HANDLE_rundown(
|
|
PNP_NOTIFY_HANDLE pHandle)
|
|
{
|
|
DPRINT1("PNP_NOTIFY_HANDLE_rundown(%p)\n", pHandle);
|
|
}
|
|
|
|
|
|
/* PUBLIC FUNCTIONS **********************************************************/
|
|
|
|
/* Function 0 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_Disconnect(
|
|
handle_t hBinding)
|
|
{
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
return CR_SUCCESS;
|
|
}
|
|
|
|
|
|
/* Function 1 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_Connect(
|
|
handle_t hBinding)
|
|
{
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
return CR_SUCCESS;
|
|
}
|
|
|
|
|
|
/* Function 2 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetVersion(
|
|
handle_t hBinding,
|
|
WORD *pVersion)
|
|
{
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
|
|
DPRINT("PNP_GetVersion(%p %p)\n",
|
|
hBinding, pVersion);
|
|
|
|
*pVersion = CONFIGMG_VERSION;
|
|
|
|
return CR_SUCCESS;
|
|
}
|
|
|
|
|
|
/* Function 3 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetGlobalState(
|
|
handle_t hBinding,
|
|
DWORD *pulState,
|
|
DWORD ulFlags)
|
|
{
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
|
|
DPRINT("PNP_GetGlobalState(%p %p 0x%08lx)\n",
|
|
hBinding, pulState, ulFlags);
|
|
|
|
if (ulFlags != 0)
|
|
return CR_INVALID_FLAG;
|
|
|
|
*pulState = CM_GLOBAL_STATE_CAN_DO_UI | CM_GLOBAL_STATE_SERVICES_AVAILABLE;
|
|
|
|
if (g_ShuttingDown)
|
|
*pulState |= CM_GLOBAL_STATE_SHUTTING_DOWN;
|
|
|
|
return CR_SUCCESS;
|
|
}
|
|
|
|
|
|
/* Function 4 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_InitDetection(
|
|
handle_t hBinding)
|
|
{
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
|
|
DPRINT("PNP_InitDetection(%p)\n",
|
|
hBinding);
|
|
|
|
return CR_SUCCESS;
|
|
}
|
|
|
|
|
|
/* Function 5 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_ReportLogOn(
|
|
handle_t hBinding,
|
|
BOOL Admin,
|
|
DWORD ProcessId)
|
|
{
|
|
DWORD ReturnValue = CR_FAILURE;
|
|
HANDLE hProcess = NULL;
|
|
|
|
UNREFERENCED_PARAMETER(Admin);
|
|
|
|
DPRINT("PNP_ReportLogOn(%p %u, %u)\n",
|
|
hBinding, Admin, ProcessId);
|
|
|
|
/* Fail, if the caller is not an interactive user */
|
|
if (!IsCallerInteractive(hBinding))
|
|
goto cleanup;
|
|
|
|
/* Get the users token */
|
|
hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, ProcessId);
|
|
|
|
if (!hProcess)
|
|
{
|
|
DPRINT1("OpenProcess failed with error %u\n", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
if (hUserToken)
|
|
{
|
|
CloseHandle(hUserToken);
|
|
hUserToken = NULL;
|
|
}
|
|
|
|
if (!OpenProcessToken(hProcess, TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY, &hUserToken))
|
|
{
|
|
DPRINT1("OpenProcessToken failed with error %u\n", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Trigger the installer thread */
|
|
if (hInstallEvent)
|
|
SetEvent(hInstallEvent);
|
|
|
|
ReturnValue = CR_SUCCESS;
|
|
|
|
cleanup:
|
|
if (hProcess)
|
|
CloseHandle(hProcess);
|
|
|
|
return ReturnValue;
|
|
}
|
|
|
|
|
|
/* Function 6 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_ValidateDeviceInstance(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceID,
|
|
DWORD ulFlags)
|
|
{
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
HKEY hDeviceKey = NULL;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
UNREFERENCED_PARAMETER(ulFlags);
|
|
|
|
DPRINT("PNP_ValidateDeviceInstance(%p %S 0x%08lx)\n",
|
|
hBinding, pDeviceID, ulFlags);
|
|
|
|
if (!IsValidDeviceInstanceID(pDeviceID))
|
|
return CR_INVALID_DEVINST;
|
|
|
|
if (RegOpenKeyExW(hEnumKey,
|
|
pDeviceID,
|
|
0,
|
|
KEY_READ,
|
|
&hDeviceKey))
|
|
{
|
|
DPRINT("Could not open the Device Key!\n");
|
|
ret = CR_NO_SUCH_DEVNODE;
|
|
goto Done;
|
|
}
|
|
|
|
/* FIXME: add more tests */
|
|
|
|
Done:
|
|
if (hDeviceKey != NULL)
|
|
RegCloseKey(hDeviceKey);
|
|
|
|
DPRINT("PNP_ValidateDeviceInstance() done (returns %lx)\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 7 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetRootDeviceInstance(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceID,
|
|
PNP_RPC_STRING_LEN ulLength)
|
|
{
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
|
|
DPRINT("PNP_GetRootDeviceInstance(%p %S %lu)\n",
|
|
hBinding, pDeviceID, ulLength);
|
|
|
|
if (!pDeviceID)
|
|
{
|
|
ret = CR_INVALID_POINTER;
|
|
goto Done;
|
|
}
|
|
|
|
if (ulLength < lstrlenW(szRootDeviceInstanceID) + 1)
|
|
{
|
|
ret = CR_BUFFER_SMALL;
|
|
goto Done;
|
|
}
|
|
|
|
lstrcpyW(pDeviceID,
|
|
szRootDeviceInstanceID);
|
|
|
|
Done:
|
|
DPRINT("PNP_GetRootDeviceInstance() done (returns %lx)\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 8 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetRelatedDeviceInstance(
|
|
handle_t hBinding,
|
|
DWORD ulRelationship,
|
|
LPWSTR pDeviceID,
|
|
LPWSTR pRelatedDeviceId,
|
|
PNP_RPC_STRING_LEN *pulLength,
|
|
DWORD ulFlags)
|
|
{
|
|
PLUGPLAY_CONTROL_RELATED_DEVICE_DATA PlugPlayData;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
NTSTATUS Status;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
UNREFERENCED_PARAMETER(ulFlags);
|
|
|
|
DPRINT("PNP_GetRelatedDeviceInstance(%p %lu %S %p %p 0x%lx)\n",
|
|
hBinding, ulRelationship, pDeviceID, pRelatedDeviceId,
|
|
pulLength, ulFlags);
|
|
|
|
if (!IsValidDeviceInstanceID(pDeviceID))
|
|
return CR_INVALID_DEVINST;
|
|
|
|
if (ulRelationship == PNP_GET_PARENT_DEVICE_INSTANCE)
|
|
{
|
|
/* The root device does not have a parent */
|
|
if (IsRootDeviceInstanceID(pDeviceID))
|
|
return CR_NO_SUCH_DEVINST;
|
|
|
|
/* Return the root device for non existing devices */
|
|
if (!IsPresentDeviceInstanceID(pDeviceID))
|
|
{
|
|
if ((wcslen(szRootDeviceInstanceID) + 1) > *pulLength)
|
|
{
|
|
*pulLength = wcslen(szRootDeviceInstanceID) + 1;
|
|
return CR_BUFFER_SMALL;
|
|
}
|
|
|
|
wcscpy(pRelatedDeviceId, szRootDeviceInstanceID);
|
|
*pulLength = wcslen(szRootDeviceInstanceID) + 1;
|
|
return CR_SUCCESS;
|
|
}
|
|
}
|
|
else if (ulRelationship == PNP_GET_SIBLING_DEVICE_INSTANCE)
|
|
{
|
|
/* The root device does not have siblings */
|
|
if (IsRootDeviceInstanceID(pDeviceID))
|
|
return CR_NO_SUCH_DEVINST;
|
|
}
|
|
|
|
RtlInitUnicodeString(&PlugPlayData.TargetDeviceInstance,
|
|
pDeviceID);
|
|
|
|
PlugPlayData.Relation = ulRelationship;
|
|
|
|
PlugPlayData.RelatedDeviceInstanceLength = *pulLength;
|
|
PlugPlayData.RelatedDeviceInstance = pRelatedDeviceId;
|
|
|
|
Status = NtPlugPlayControl(PlugPlayControlGetRelatedDevice,
|
|
(PVOID)&PlugPlayData,
|
|
sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA));
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ret = NtStatusToCrError(Status);
|
|
}
|
|
|
|
DPRINT("PNP_GetRelatedDeviceInstance() done (returns %lx)\n", ret);
|
|
if (ret == CR_SUCCESS)
|
|
{
|
|
DPRINT("RelatedDevice: %wZ\n", &PlugPlayData.RelatedDeviceInstance);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 9 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_EnumerateSubKeys(
|
|
handle_t hBinding,
|
|
DWORD ulBranch,
|
|
DWORD ulIndex,
|
|
LPWSTR Buffer,
|
|
PNP_RPC_STRING_LEN ulLength,
|
|
PNP_RPC_STRING_LEN *pulRequiredLen,
|
|
DWORD ulFlags)
|
|
{
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
HKEY hKey;
|
|
DWORD dwError;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
UNREFERENCED_PARAMETER(ulFlags);
|
|
|
|
DPRINT("PNP_EnumerateSubKeys(%p %lu %lu %p %lu %p 0x%08lx)\n",
|
|
hBinding, ulBranch, ulIndex, Buffer, ulLength,
|
|
pulRequiredLen, ulFlags);
|
|
|
|
switch (ulBranch)
|
|
{
|
|
case PNP_ENUMERATOR_SUBKEYS:
|
|
hKey = hEnumKey;
|
|
break;
|
|
|
|
case PNP_CLASS_SUBKEYS:
|
|
hKey = hClassKey;
|
|
break;
|
|
|
|
default:
|
|
return CR_FAILURE;
|
|
}
|
|
|
|
*pulRequiredLen = ulLength;
|
|
dwError = RegEnumKeyExW(hKey,
|
|
ulIndex,
|
|
Buffer,
|
|
pulRequiredLen,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
ret = (dwError == ERROR_NO_MORE_ITEMS) ? CR_NO_SUCH_VALUE : CR_FAILURE;
|
|
}
|
|
else
|
|
{
|
|
(*pulRequiredLen)++;
|
|
}
|
|
|
|
DPRINT("PNP_EnumerateSubKeys() done (returns %lx)\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static
|
|
CONFIGRET
|
|
GetRelationsInstanceList(
|
|
_In_ PWSTR pszDevice,
|
|
_In_ DWORD ulFlags,
|
|
_Inout_ PWSTR pszBuffer,
|
|
_Inout_ PDWORD pulLength)
|
|
{
|
|
PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA PlugPlayData;
|
|
NTSTATUS Status;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
|
|
pszDevice);
|
|
|
|
if (ulFlags & CM_GETIDLIST_FILTER_BUSRELATIONS)
|
|
{
|
|
PlugPlayData.Relations = 3;
|
|
}
|
|
else if (ulFlags & CM_GETIDLIST_FILTER_POWERRELATIONS)
|
|
{
|
|
PlugPlayData.Relations = 2;
|
|
}
|
|
else if (ulFlags & CM_GETIDLIST_FILTER_REMOVALRELATIONS)
|
|
{
|
|
PlugPlayData.Relations = 1;
|
|
}
|
|
else if (ulFlags & CM_GETIDLIST_FILTER_EJECTRELATIONS)
|
|
{
|
|
PlugPlayData.Relations = 0;
|
|
}
|
|
|
|
PlugPlayData.BufferSize = *pulLength * sizeof(WCHAR);
|
|
PlugPlayData.Buffer = pszBuffer;
|
|
|
|
Status = NtPlugPlayControl(PlugPlayControlQueryDeviceRelations,
|
|
(PVOID)&PlugPlayData,
|
|
sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA));
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
*pulLength = PlugPlayData.BufferSize / sizeof(WCHAR);
|
|
}
|
|
else
|
|
{
|
|
ret = NtStatusToCrError(Status);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static
|
|
CONFIGRET
|
|
GetServiceInstanceList(
|
|
_In_ PWSTR pszService,
|
|
_Inout_ PWSTR pszBuffer,
|
|
_Inout_ PDWORD pulLength)
|
|
{
|
|
WCHAR szPathBuffer[512];
|
|
WCHAR szName[16];
|
|
HKEY hServicesKey = NULL, hServiceKey = NULL, hEnumKey = NULL;
|
|
DWORD dwValues, dwSize, dwIndex, dwUsedLength, dwPathLength;
|
|
DWORD dwError;
|
|
PWSTR pPtr;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
/* Open the device key */
|
|
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
L"System\\CurrentControlSet\\Services",
|
|
0,
|
|
KEY_READ,
|
|
&hServicesKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPRINT("Failed to open the services key (Error %lu)\n", dwError);
|
|
return CR_REGISTRY_ERROR;
|
|
}
|
|
|
|
dwError = RegOpenKeyExW(hServicesKey,
|
|
pszService,
|
|
0,
|
|
KEY_READ,
|
|
&hServiceKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPRINT("Failed to open the service key (Error %lu)\n", dwError);
|
|
ret = CR_REGISTRY_ERROR;
|
|
goto Done;
|
|
}
|
|
|
|
dwError = RegOpenKeyExW(hServiceKey,
|
|
L"Enum",
|
|
0,
|
|
KEY_READ,
|
|
&hEnumKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPRINT("Failed to open the service enum key (Error %lu)\n", dwError);
|
|
ret = CR_REGISTRY_ERROR;
|
|
goto Done;
|
|
}
|
|
|
|
/* Retrieve the number of device instances */
|
|
dwSize = sizeof(DWORD);
|
|
dwError = RegQueryValueExW(hEnumKey,
|
|
L"Count",
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)&dwValues,
|
|
&dwSize);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPRINT("RegQueryValueExW failed (Error %lu)\n", dwError);
|
|
dwValues = 1;
|
|
}
|
|
|
|
DPRINT("dwValues %lu\n", dwValues);
|
|
|
|
dwUsedLength = 0;
|
|
pPtr = pszBuffer;
|
|
|
|
for (dwIndex = 0; dwIndex < dwValues; dwIndex++)
|
|
{
|
|
wsprintf(szName, L"%lu", dwIndex);
|
|
|
|
dwSize = sizeof(szPathBuffer);
|
|
dwError = RegQueryValueExW(hEnumKey,
|
|
szName,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)szPathBuffer,
|
|
&dwSize);
|
|
if (dwError != ERROR_SUCCESS)
|
|
break;
|
|
|
|
DPRINT("Path: %S\n", szPathBuffer);
|
|
|
|
dwPathLength = wcslen(szPathBuffer) + 1;
|
|
if (dwUsedLength + dwPathLength + 1 > *pulLength)
|
|
{
|
|
ret = CR_BUFFER_SMALL;
|
|
break;
|
|
}
|
|
|
|
wcscpy(pPtr, szPathBuffer);
|
|
dwUsedLength += dwPathLength;
|
|
pPtr += dwPathLength;
|
|
|
|
*pPtr = UNICODE_NULL;
|
|
}
|
|
|
|
Done:
|
|
if (hEnumKey != NULL)
|
|
RegCloseKey(hEnumKey);
|
|
|
|
if (hServiceKey != NULL)
|
|
RegCloseKey(hServiceKey);
|
|
|
|
if (hServicesKey != NULL)
|
|
RegCloseKey(hServicesKey);
|
|
|
|
if (ret == CR_SUCCESS)
|
|
*pulLength = dwUsedLength + 1;
|
|
else
|
|
*pulLength = 0;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static
|
|
CONFIGRET
|
|
GetDeviceInstanceList(
|
|
_In_ PWSTR pszDevice,
|
|
_Inout_ PWSTR pszBuffer,
|
|
_Inout_ PDWORD pulLength)
|
|
{
|
|
WCHAR szInstanceBuffer[MAX_DEVICE_ID_LEN];
|
|
WCHAR szPathBuffer[512];
|
|
HKEY hDeviceKey;
|
|
DWORD dwInstanceLength, dwPathLength, dwUsedLength;
|
|
DWORD dwIndex, dwError;
|
|
PWSTR pPtr;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
/* Open the device key */
|
|
dwError = RegOpenKeyExW(hEnumKey,
|
|
pszDevice,
|
|
0,
|
|
KEY_ENUMERATE_SUB_KEYS,
|
|
&hDeviceKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPRINT("Failed to open the device key (Error %lu)\n", dwError);
|
|
return CR_REGISTRY_ERROR;
|
|
}
|
|
|
|
dwUsedLength = 0;
|
|
pPtr = pszBuffer;
|
|
|
|
for (dwIndex = 0; ; dwIndex++)
|
|
{
|
|
dwInstanceLength = MAX_DEVICE_ID_LEN;
|
|
dwError = RegEnumKeyExW(hDeviceKey,
|
|
dwIndex,
|
|
szInstanceBuffer,
|
|
&dwInstanceLength,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
if (dwError != ERROR_SUCCESS)
|
|
break;
|
|
|
|
wsprintf(szPathBuffer, L"%s\\%s", pszDevice, szInstanceBuffer);
|
|
DPRINT("Path: %S\n", szPathBuffer);
|
|
|
|
dwPathLength = wcslen(szPathBuffer) + 1;
|
|
if (dwUsedLength + dwPathLength + 1 > *pulLength)
|
|
{
|
|
ret = CR_BUFFER_SMALL;
|
|
break;
|
|
}
|
|
|
|
wcscpy(pPtr, szPathBuffer);
|
|
dwUsedLength += dwPathLength;
|
|
pPtr += dwPathLength;
|
|
|
|
*pPtr = UNICODE_NULL;
|
|
}
|
|
|
|
RegCloseKey(hDeviceKey);
|
|
|
|
if (ret == CR_SUCCESS)
|
|
*pulLength = dwUsedLength + 1;
|
|
else
|
|
*pulLength = 0;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
CONFIGRET
|
|
GetEnumeratorInstanceList(
|
|
_In_ PWSTR pszEnumerator,
|
|
_Inout_ PWSTR pszBuffer,
|
|
_Inout_ PDWORD pulLength)
|
|
{
|
|
WCHAR szDeviceBuffer[MAX_DEVICE_ID_LEN];
|
|
WCHAR szPathBuffer[512];
|
|
HKEY hEnumeratorKey;
|
|
PWSTR pPtr;
|
|
DWORD dwIndex, dwDeviceLength, dwUsedLength, dwRemainingLength, dwPathLength;
|
|
DWORD dwError;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
/* Open the enumerator key */
|
|
dwError = RegOpenKeyExW(hEnumKey,
|
|
pszEnumerator,
|
|
0,
|
|
KEY_ENUMERATE_SUB_KEYS,
|
|
&hEnumeratorKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPRINT("Failed to open the enumerator key (Error %lu)\n", dwError);
|
|
return CR_REGISTRY_ERROR;
|
|
}
|
|
|
|
dwUsedLength = 0;
|
|
dwRemainingLength = *pulLength;
|
|
pPtr = pszBuffer;
|
|
|
|
for (dwIndex = 0; ; dwIndex++)
|
|
{
|
|
dwDeviceLength = MAX_DEVICE_ID_LEN;
|
|
dwError = RegEnumKeyExW(hEnumeratorKey,
|
|
dwIndex,
|
|
szDeviceBuffer,
|
|
&dwDeviceLength,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
if (dwError != ERROR_SUCCESS)
|
|
break;
|
|
|
|
wsprintf(szPathBuffer, L"%s\\%s", pszEnumerator, szDeviceBuffer);
|
|
DPRINT("Path: %S\n", szPathBuffer);
|
|
|
|
dwPathLength = dwRemainingLength;
|
|
ret = GetDeviceInstanceList(szPathBuffer,
|
|
pPtr,
|
|
&dwPathLength);
|
|
if (ret != CR_SUCCESS)
|
|
break;
|
|
|
|
dwUsedLength += dwPathLength - 1;
|
|
dwRemainingLength -= dwPathLength - 1;
|
|
pPtr += dwPathLength - 1;
|
|
}
|
|
|
|
RegCloseKey(hEnumeratorKey);
|
|
|
|
if (ret == CR_SUCCESS)
|
|
*pulLength = dwUsedLength + 1;
|
|
else
|
|
*pulLength = 0;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static
|
|
CONFIGRET
|
|
GetAllInstanceList(
|
|
_Inout_ PWSTR pszBuffer,
|
|
_Inout_ PDWORD pulLength)
|
|
{
|
|
WCHAR szEnumeratorBuffer[MAX_DEVICE_ID_LEN];
|
|
PWSTR pPtr;
|
|
DWORD dwIndex, dwEnumeratorLength, dwUsedLength, dwRemainingLength, dwPathLength;
|
|
DWORD dwError;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
dwUsedLength = 0;
|
|
dwRemainingLength = *pulLength;
|
|
pPtr = pszBuffer;
|
|
|
|
for (dwIndex = 0; ; dwIndex++)
|
|
{
|
|
dwEnumeratorLength = MAX_DEVICE_ID_LEN;
|
|
dwError = RegEnumKeyExW(hEnumKey,
|
|
dwIndex,
|
|
szEnumeratorBuffer,
|
|
&dwEnumeratorLength,
|
|
NULL, NULL, NULL, NULL);
|
|
if (dwError != ERROR_SUCCESS)
|
|
break;
|
|
|
|
dwPathLength = dwRemainingLength;
|
|
ret = GetEnumeratorInstanceList(szEnumeratorBuffer,
|
|
pPtr,
|
|
&dwPathLength);
|
|
if (ret != CR_SUCCESS)
|
|
break;
|
|
|
|
dwUsedLength += dwPathLength - 1;
|
|
dwRemainingLength -= dwPathLength - 1;
|
|
pPtr += dwPathLength - 1;
|
|
}
|
|
|
|
if (ret == CR_SUCCESS)
|
|
*pulLength = dwUsedLength + 1;
|
|
else
|
|
*pulLength = 0;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 10 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetDeviceList(
|
|
handle_t hBinding,
|
|
LPWSTR pszFilter,
|
|
LPWSTR Buffer,
|
|
PNP_RPC_STRING_LEN *pulLength,
|
|
DWORD ulFlags)
|
|
{
|
|
WCHAR szEnumerator[MAX_DEVICE_ID_LEN];
|
|
WCHAR szDevice[MAX_DEVICE_ID_LEN];
|
|
WCHAR szInstance[MAX_DEVICE_ID_LEN];
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
DPRINT("PNP_GetDeviceList(%p %S %p %p 0x%08lx)\n",
|
|
hBinding, pszFilter, Buffer, pulLength, ulFlags);
|
|
|
|
if (ulFlags & ~CM_GETIDLIST_FILTER_BITS)
|
|
return CR_INVALID_FLAG;
|
|
|
|
if (pulLength == NULL)
|
|
return CR_INVALID_POINTER;
|
|
|
|
if ((ulFlags != CM_GETIDLIST_FILTER_NONE) &&
|
|
(pszFilter == NULL))
|
|
return CR_INVALID_POINTER;
|
|
|
|
if (ulFlags &
|
|
(CM_GETIDLIST_FILTER_BUSRELATIONS |
|
|
CM_GETIDLIST_FILTER_POWERRELATIONS |
|
|
CM_GETIDLIST_FILTER_REMOVALRELATIONS |
|
|
CM_GETIDLIST_FILTER_EJECTRELATIONS))
|
|
{
|
|
ret = GetRelationsInstanceList(pszFilter,
|
|
ulFlags,
|
|
Buffer,
|
|
pulLength);
|
|
}
|
|
else if (ulFlags & CM_GETIDLIST_FILTER_SERVICE)
|
|
{
|
|
ret = GetServiceInstanceList(pszFilter,
|
|
Buffer,
|
|
pulLength);
|
|
}
|
|
else if (ulFlags & CM_GETIDLIST_FILTER_ENUMERATOR)
|
|
{
|
|
SplitDeviceInstanceID(pszFilter,
|
|
szEnumerator,
|
|
szDevice,
|
|
szInstance);
|
|
|
|
if (*szEnumerator != UNICODE_NULL && *szDevice != UNICODE_NULL)
|
|
{
|
|
ret = GetDeviceInstanceList(pszFilter,
|
|
Buffer,
|
|
pulLength);
|
|
}
|
|
else
|
|
{
|
|
ret = GetEnumeratorInstanceList(pszFilter,
|
|
Buffer,
|
|
pulLength);
|
|
}
|
|
}
|
|
else /* CM_GETIDLIST_FILTER_NONE */
|
|
{
|
|
ret = GetAllInstanceList(Buffer,
|
|
pulLength);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static
|
|
CONFIGRET
|
|
GetRelationsInstanceListSize(
|
|
_In_ PWSTR pszDevice,
|
|
_In_ DWORD ulFlags,
|
|
_Inout_ PDWORD pulLength)
|
|
{
|
|
PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA PlugPlayData;
|
|
NTSTATUS Status;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
|
|
pszDevice);
|
|
|
|
if (ulFlags & CM_GETIDLIST_FILTER_BUSRELATIONS)
|
|
{
|
|
PlugPlayData.Relations = 3;
|
|
}
|
|
else if (ulFlags & CM_GETIDLIST_FILTER_POWERRELATIONS)
|
|
{
|
|
PlugPlayData.Relations = 2;
|
|
}
|
|
else if (ulFlags & CM_GETIDLIST_FILTER_REMOVALRELATIONS)
|
|
{
|
|
PlugPlayData.Relations = 1;
|
|
}
|
|
else if (ulFlags & CM_GETIDLIST_FILTER_EJECTRELATIONS)
|
|
{
|
|
PlugPlayData.Relations = 0;
|
|
}
|
|
|
|
PlugPlayData.BufferSize = 0;
|
|
PlugPlayData.Buffer = NULL;
|
|
|
|
Status = NtPlugPlayControl(PlugPlayControlQueryDeviceRelations,
|
|
(PVOID)&PlugPlayData,
|
|
sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA));
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
*pulLength = PlugPlayData.BufferSize / sizeof(WCHAR);
|
|
}
|
|
else
|
|
{
|
|
ret = NtStatusToCrError(Status);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static
|
|
CONFIGRET
|
|
GetServiceInstanceListSize(
|
|
_In_ PWSTR pszService,
|
|
_Out_ PDWORD pulLength)
|
|
{
|
|
HKEY hServicesKey = NULL, hServiceKey = NULL, hEnumKey = NULL;
|
|
DWORD dwValues, dwMaxValueLength, dwSize;
|
|
DWORD dwError;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
/* Open the device key */
|
|
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
L"System\\CurrentControlSet\\Services",
|
|
0,
|
|
KEY_READ,
|
|
&hServicesKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPRINT("Failed to open the services key (Error %lu)\n", dwError);
|
|
return CR_REGISTRY_ERROR;
|
|
}
|
|
|
|
dwError = RegOpenKeyExW(hServicesKey,
|
|
pszService,
|
|
0,
|
|
KEY_READ,
|
|
&hServiceKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPRINT("Failed to open the service key (Error %lu)\n", dwError);
|
|
ret = CR_REGISTRY_ERROR;
|
|
goto Done;
|
|
}
|
|
|
|
dwError = RegOpenKeyExW(hServiceKey,
|
|
L"Enum",
|
|
0,
|
|
KEY_READ,
|
|
&hEnumKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPRINT("Failed to open the service enum key (Error %lu)\n", dwError);
|
|
ret = CR_REGISTRY_ERROR;
|
|
goto Done;
|
|
}
|
|
|
|
/* Retrieve the number of device instances */
|
|
dwSize = sizeof(DWORD);
|
|
dwError = RegQueryValueExW(hEnumKey,
|
|
L"Count",
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)&dwValues,
|
|
&dwSize);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPRINT("RegQueryValueExW failed (Error %lu)\n", dwError);
|
|
dwValues = 1;
|
|
}
|
|
|
|
/* Retrieve the maximum instance name length */
|
|
dwError = RegQueryInfoKeyW(hEnumKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&dwMaxValueLength,
|
|
NULL,
|
|
NULL);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPRINT("RegQueryInfoKeyW failed (Error %lu)\n", dwError);
|
|
dwMaxValueLength = MAX_DEVICE_ID_LEN;
|
|
}
|
|
|
|
DPRINT("dwValues %lu dwMaxValueLength %lu\n", dwValues, dwMaxValueLength / sizeof(WCHAR));
|
|
|
|
/* Return the largest possible buffer size */
|
|
*pulLength = dwValues * dwMaxValueLength / sizeof(WCHAR) + 2;
|
|
|
|
Done:
|
|
if (hEnumKey != NULL)
|
|
RegCloseKey(hEnumKey);
|
|
|
|
if (hServiceKey != NULL)
|
|
RegCloseKey(hServiceKey);
|
|
|
|
if (hServicesKey != NULL)
|
|
RegCloseKey(hServicesKey);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static
|
|
CONFIGRET
|
|
GetDeviceInstanceListSize(
|
|
_In_ LPCWSTR pszDevice,
|
|
_Out_ PULONG pulLength)
|
|
{
|
|
HKEY hDeviceKey;
|
|
DWORD dwSubKeys, dwMaxSubKeyLength;
|
|
DWORD dwError;
|
|
|
|
/* Open the device key */
|
|
dwError = RegOpenKeyExW(hEnumKey,
|
|
pszDevice,
|
|
0,
|
|
KEY_READ,
|
|
&hDeviceKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPRINT("Failed to open the device key (Error %lu)\n", dwError);
|
|
return CR_REGISTRY_ERROR;
|
|
}
|
|
|
|
/* Retrieve the number of device instances and the maximum name length */
|
|
dwError = RegQueryInfoKeyW(hDeviceKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&dwSubKeys,
|
|
&dwMaxSubKeyLength,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPRINT("RegQueryInfoKeyW failed (Error %lu)\n", dwError);
|
|
dwSubKeys = 0;
|
|
dwMaxSubKeyLength = 0;
|
|
}
|
|
|
|
/* Close the device key */
|
|
RegCloseKey(hDeviceKey);
|
|
|
|
/* Return the largest possible buffer size */
|
|
*pulLength = dwSubKeys * (wcslen(pszDevice) + 1 + dwMaxSubKeyLength + 1);
|
|
|
|
return CR_SUCCESS;
|
|
}
|
|
|
|
|
|
static
|
|
CONFIGRET
|
|
GetEnumeratorInstanceListSize(
|
|
_In_ LPCWSTR pszEnumerator,
|
|
_Out_ PULONG pulLength)
|
|
{
|
|
WCHAR szDeviceBuffer[MAX_DEVICE_ID_LEN];
|
|
WCHAR szPathBuffer[512];
|
|
HKEY hEnumeratorKey;
|
|
DWORD dwIndex, dwDeviceLength, dwBufferLength;
|
|
DWORD dwError;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
*pulLength = 0;
|
|
|
|
/* Open the enumerator key */
|
|
dwError = RegOpenKeyExW(hEnumKey,
|
|
pszEnumerator,
|
|
0,
|
|
KEY_ENUMERATE_SUB_KEYS,
|
|
&hEnumeratorKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPRINT("Failed to open the enumerator key (Error %lu)\n", dwError);
|
|
return CR_REGISTRY_ERROR;
|
|
}
|
|
|
|
for (dwIndex = 0; ; dwIndex++)
|
|
{
|
|
dwDeviceLength = MAX_DEVICE_ID_LEN;
|
|
dwError = RegEnumKeyExW(hEnumeratorKey,
|
|
dwIndex,
|
|
szDeviceBuffer,
|
|
&dwDeviceLength,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
if (dwError != ERROR_SUCCESS)
|
|
break;
|
|
|
|
wsprintf(szPathBuffer, L"%s\\%s", pszEnumerator, szDeviceBuffer);
|
|
DPRINT("Path: %S\n", szPathBuffer);
|
|
|
|
ret = GetDeviceInstanceListSize(szPathBuffer, &dwBufferLength);
|
|
if (ret != CR_SUCCESS)
|
|
{
|
|
*pulLength = 0;
|
|
break;
|
|
}
|
|
|
|
*pulLength += dwBufferLength;
|
|
}
|
|
|
|
/* Close the enumerator key */
|
|
RegCloseKey(hEnumeratorKey);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static
|
|
CONFIGRET
|
|
GetAllInstanceListSize(
|
|
_Out_ PULONG pulLength)
|
|
{
|
|
WCHAR szEnumeratorBuffer[MAX_DEVICE_ID_LEN];
|
|
DWORD dwIndex, dwEnumeratorLength, dwBufferLength;
|
|
DWORD dwError;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
for (dwIndex = 0; ; dwIndex++)
|
|
{
|
|
dwEnumeratorLength = MAX_DEVICE_ID_LEN;
|
|
dwError = RegEnumKeyExW(hEnumKey,
|
|
dwIndex,
|
|
szEnumeratorBuffer,
|
|
&dwEnumeratorLength,
|
|
NULL, NULL, NULL, NULL);
|
|
if (dwError != ERROR_SUCCESS)
|
|
break;
|
|
|
|
/* Get the size of all device instances for the enumerator */
|
|
ret = GetEnumeratorInstanceListSize(szEnumeratorBuffer,
|
|
&dwBufferLength);
|
|
if (ret != CR_SUCCESS)
|
|
break;
|
|
|
|
*pulLength += dwBufferLength;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 11 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetDeviceListSize(
|
|
handle_t hBinding,
|
|
LPWSTR pszFilter,
|
|
PNP_RPC_BUFFER_SIZE *pulLength,
|
|
DWORD ulFlags)
|
|
{
|
|
WCHAR szEnumerator[MAX_DEVICE_ID_LEN];
|
|
WCHAR szDevice[MAX_DEVICE_ID_LEN];
|
|
WCHAR szInstance[MAX_DEVICE_ID_LEN];
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
DPRINT("PNP_GetDeviceListSize(%p %S %p 0x%08lx)\n",
|
|
hBinding, pszFilter, pulLength, ulFlags);
|
|
|
|
if (ulFlags & ~CM_GETIDLIST_FILTER_BITS)
|
|
return CR_INVALID_FLAG;
|
|
|
|
if (pulLength == NULL)
|
|
return CR_INVALID_POINTER;
|
|
|
|
if ((ulFlags != CM_GETIDLIST_FILTER_NONE) &&
|
|
(pszFilter == NULL))
|
|
return CR_INVALID_POINTER;
|
|
|
|
*pulLength = 0;
|
|
|
|
if (ulFlags &
|
|
(CM_GETIDLIST_FILTER_BUSRELATIONS |
|
|
CM_GETIDLIST_FILTER_POWERRELATIONS |
|
|
CM_GETIDLIST_FILTER_REMOVALRELATIONS |
|
|
CM_GETIDLIST_FILTER_EJECTRELATIONS))
|
|
{
|
|
ret = GetRelationsInstanceListSize(pszFilter,
|
|
ulFlags,
|
|
pulLength);
|
|
}
|
|
else if (ulFlags & CM_GETIDLIST_FILTER_SERVICE)
|
|
{
|
|
ret = GetServiceInstanceListSize(pszFilter,
|
|
pulLength);
|
|
}
|
|
else if (ulFlags & CM_GETIDLIST_FILTER_ENUMERATOR)
|
|
{
|
|
SplitDeviceInstanceID(pszFilter,
|
|
szEnumerator,
|
|
szDevice,
|
|
szInstance);
|
|
|
|
if (*szEnumerator != UNICODE_NULL && *szDevice != UNICODE_NULL)
|
|
{
|
|
ret = GetDeviceInstanceListSize(pszFilter,
|
|
pulLength);
|
|
}
|
|
else
|
|
{
|
|
ret = GetEnumeratorInstanceListSize(pszFilter,
|
|
pulLength);
|
|
}
|
|
}
|
|
else /* CM_GETIDLIST_FILTER_NONE */
|
|
{
|
|
ret = GetAllInstanceListSize(pulLength);
|
|
}
|
|
|
|
/* Add one character for the terminating double UNICODE_NULL */
|
|
if (ret == CR_SUCCESS)
|
|
(*pulLength) += 1;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 12 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetDepth(
|
|
handle_t hBinding,
|
|
LPWSTR pszDeviceID,
|
|
DWORD *pulDepth,
|
|
DWORD ulFlags)
|
|
{
|
|
PLUGPLAY_CONTROL_DEPTH_DATA PlugPlayData;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
NTSTATUS Status;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
UNREFERENCED_PARAMETER(ulFlags);
|
|
|
|
DPRINT("PNP_GetDepth(%p %S %p 0x%08lx)\n",
|
|
hBinding, pszDeviceID, pulDepth, ulFlags);
|
|
|
|
if (!IsValidDeviceInstanceID(pszDeviceID))
|
|
return CR_INVALID_DEVINST;
|
|
|
|
RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
|
|
pszDeviceID);
|
|
|
|
Status = NtPlugPlayControl(PlugPlayControlGetDeviceDepth,
|
|
(PVOID)&PlugPlayData,
|
|
sizeof(PLUGPLAY_CONTROL_DEPTH_DATA));
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
*pulDepth = PlugPlayData.Depth;
|
|
}
|
|
else
|
|
{
|
|
ret = NtStatusToCrError(Status);
|
|
}
|
|
|
|
DPRINT("PNP_GetDepth() done (returns %lx)\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 13 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetDeviceRegProp(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceID,
|
|
DWORD ulProperty,
|
|
DWORD *pulRegDataType,
|
|
BYTE *Buffer,
|
|
PNP_PROP_SIZE *pulTransferLen,
|
|
PNP_PROP_SIZE *pulLength,
|
|
DWORD ulFlags)
|
|
{
|
|
PLUGPLAY_CONTROL_PROPERTY_DATA PlugPlayData;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
LPWSTR lpValueName = NULL;
|
|
HKEY hKey = NULL;
|
|
LONG lError;
|
|
NTSTATUS Status;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
|
|
DPRINT("PNP_GetDeviceRegProp(%p %S %lu %p %p %p %p 0x%08lx)\n",
|
|
hBinding, pDeviceID, ulProperty, pulRegDataType, Buffer,
|
|
pulTransferLen, pulLength, ulFlags);
|
|
|
|
if (pulTransferLen == NULL || pulLength == NULL)
|
|
{
|
|
ret = CR_INVALID_POINTER;
|
|
goto done;
|
|
}
|
|
|
|
if (ulFlags != 0)
|
|
{
|
|
ret = CR_INVALID_FLAG;
|
|
goto done;
|
|
}
|
|
|
|
/* Check pDeviceID */
|
|
if (!IsValidDeviceInstanceID(pDeviceID))
|
|
{
|
|
ret = CR_INVALID_DEVINST;
|
|
goto done;
|
|
}
|
|
|
|
if (*pulLength < *pulTransferLen)
|
|
*pulLength = *pulTransferLen;
|
|
|
|
*pulTransferLen = 0;
|
|
|
|
switch (ulProperty)
|
|
{
|
|
case CM_DRP_DEVICEDESC:
|
|
lpValueName = L"DeviceDesc";
|
|
break;
|
|
|
|
case CM_DRP_HARDWAREID:
|
|
lpValueName = L"HardwareID";
|
|
break;
|
|
|
|
case CM_DRP_COMPATIBLEIDS:
|
|
lpValueName = L"CompatibleIDs";
|
|
break;
|
|
|
|
case CM_DRP_SERVICE:
|
|
lpValueName = L"Service";
|
|
break;
|
|
|
|
case CM_DRP_CLASS:
|
|
lpValueName = L"Class";
|
|
break;
|
|
|
|
case CM_DRP_CLASSGUID:
|
|
lpValueName = L"ClassGUID";
|
|
break;
|
|
|
|
case CM_DRP_DRIVER:
|
|
lpValueName = L"Driver";
|
|
break;
|
|
|
|
case CM_DRP_CONFIGFLAGS:
|
|
lpValueName = L"ConfigFlags";
|
|
break;
|
|
|
|
case CM_DRP_MFG:
|
|
lpValueName = L"Mfg";
|
|
break;
|
|
|
|
case CM_DRP_FRIENDLYNAME:
|
|
lpValueName = L"FriendlyName";
|
|
break;
|
|
|
|
case CM_DRP_LOCATION_INFORMATION:
|
|
lpValueName = L"LocationInformation";
|
|
break;
|
|
|
|
case CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME:
|
|
PlugPlayData.Property = PNP_PROPERTY_PHYSICAL_DEVICE_OBJECT_NAME;
|
|
*pulRegDataType = REG_SZ;
|
|
break;
|
|
|
|
case CM_DRP_CAPABILITIES:
|
|
lpValueName = L"Capabilities";
|
|
break;
|
|
|
|
case CM_DRP_UI_NUMBER:
|
|
PlugPlayData.Property = PNP_PROPERTY_UI_NUMBER;
|
|
break;
|
|
|
|
case CM_DRP_UPPERFILTERS:
|
|
lpValueName = L"UpperFilters";
|
|
break;
|
|
|
|
case CM_DRP_LOWERFILTERS:
|
|
lpValueName = L"LowerFilters";
|
|
break;
|
|
|
|
case CM_DRP_BUSTYPEGUID:
|
|
PlugPlayData.Property = PNP_PROPERTY_BUSTYPEGUID;
|
|
*pulRegDataType = REG_BINARY;
|
|
break;
|
|
|
|
case CM_DRP_LEGACYBUSTYPE:
|
|
PlugPlayData.Property = PNP_PROPERTY_LEGACYBUSTYPE;
|
|
*pulRegDataType = REG_DWORD;
|
|
break;
|
|
|
|
case CM_DRP_BUSNUMBER:
|
|
PlugPlayData.Property = PNP_PROPERTY_BUSNUMBER;
|
|
*pulRegDataType = REG_DWORD;
|
|
break;
|
|
|
|
case CM_DRP_ENUMERATOR_NAME:
|
|
PlugPlayData.Property = PNP_PROPERTY_ENUMERATOR_NAME;
|
|
*pulRegDataType = REG_SZ;
|
|
break;
|
|
|
|
case CM_DRP_SECURITY:
|
|
lpValueName = L"Security";
|
|
break;
|
|
|
|
case CM_DRP_DEVTYPE:
|
|
lpValueName = L"DeviceType";
|
|
break;
|
|
|
|
case CM_DRP_EXCLUSIVE:
|
|
lpValueName = L"Exclusive";
|
|
break;
|
|
|
|
case CM_DRP_CHARACTERISTICS:
|
|
lpValueName = L"DeviceCharacteristics";
|
|
break;
|
|
|
|
case CM_DRP_ADDRESS:
|
|
PlugPlayData.Property = PNP_PROPERTY_ADDRESS;
|
|
*pulRegDataType = REG_DWORD;
|
|
break;
|
|
|
|
case CM_DRP_UI_NUMBER_DESC_FORMAT:
|
|
lpValueName = L"UINumberDescFormat";
|
|
break;
|
|
|
|
case CM_DRP_DEVICE_POWER_DATA:
|
|
PlugPlayData.Property = PNP_PROPERTY_POWER_DATA;
|
|
*pulRegDataType = REG_BINARY;
|
|
break;
|
|
|
|
case CM_DRP_REMOVAL_POLICY:
|
|
PlugPlayData.Property = PNP_PROPERTY_REMOVAL_POLICY;
|
|
*pulRegDataType = REG_DWORD;
|
|
break;
|
|
|
|
case CM_DRP_REMOVAL_POLICY_HW_DEFAULT:
|
|
PlugPlayData.Property = PNP_PROPERTY_REMOVAL_POLICY_HARDWARE_DEFAULT;
|
|
*pulRegDataType = REG_DWORD;
|
|
break;
|
|
|
|
case CM_DRP_REMOVAL_POLICY_OVERRIDE:
|
|
lpValueName = L"RemovalPolicy";
|
|
*pulRegDataType = REG_DWORD;
|
|
break;
|
|
|
|
case CM_DRP_INSTALL_STATE:
|
|
PlugPlayData.Property = PNP_PROPERTY_INSTALL_STATE;
|
|
*pulRegDataType = REG_DWORD;
|
|
break;
|
|
|
|
#if (WINVER >= _WIN32_WINNT_WS03)
|
|
case CM_DRP_LOCATION_PATHS:
|
|
PlugPlayData.Property = PNP_PROPERTY_LOCATION_PATHS;
|
|
*pulRegDataType = REG_MULTI_SZ;
|
|
break;
|
|
#endif
|
|
|
|
#if (WINVER >= _WIN32_WINNT_WIN7)
|
|
case CM_DRP_BASE_CONTAINERID:
|
|
PlugPlayData.Property = PNP_PROPERTY_CONTAINERID;
|
|
*pulRegDataType = REG_SZ;
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
ret = CR_INVALID_PROPERTY;
|
|
goto done;
|
|
}
|
|
|
|
DPRINT("Value name: %S\n", lpValueName);
|
|
|
|
if (lpValueName)
|
|
{
|
|
/* Retrieve information from the Registry */
|
|
lError = RegOpenKeyExW(hEnumKey,
|
|
pDeviceID,
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hKey);
|
|
if (lError != ERROR_SUCCESS)
|
|
{
|
|
hKey = NULL;
|
|
*pulLength = 0;
|
|
ret = CR_INVALID_DEVNODE;
|
|
goto done;
|
|
}
|
|
|
|
lError = RegQueryValueExW(hKey,
|
|
lpValueName,
|
|
NULL,
|
|
pulRegDataType,
|
|
Buffer,
|
|
pulLength);
|
|
if (lError != ERROR_SUCCESS)
|
|
{
|
|
if (lError == ERROR_MORE_DATA)
|
|
{
|
|
ret = CR_BUFFER_SMALL;
|
|
}
|
|
else
|
|
{
|
|
*pulLength = 0;
|
|
ret = CR_NO_SUCH_VALUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Retrieve information from the Device Node */
|
|
RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
|
|
pDeviceID);
|
|
PlugPlayData.Buffer = Buffer;
|
|
PlugPlayData.BufferSize = *pulLength;
|
|
|
|
Status = NtPlugPlayControl(PlugPlayControlProperty,
|
|
(PVOID)&PlugPlayData,
|
|
sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA));
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
*pulLength = PlugPlayData.BufferSize;
|
|
}
|
|
else
|
|
{
|
|
ret = NtStatusToCrError(Status);
|
|
}
|
|
}
|
|
|
|
done:
|
|
if (pulTransferLen)
|
|
*pulTransferLen = (ret == CR_SUCCESS) ? *pulLength : 0;
|
|
|
|
if (hKey != NULL)
|
|
RegCloseKey(hKey);
|
|
|
|
DPRINT("PNP_GetDeviceRegProp() done (returns %lx)\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 14 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_SetDeviceRegProp(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceId,
|
|
DWORD ulProperty,
|
|
DWORD ulDataType,
|
|
BYTE *Buffer,
|
|
PNP_PROP_SIZE ulLength,
|
|
DWORD ulFlags)
|
|
{
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
LPWSTR lpValueName = NULL;
|
|
HKEY hKey = 0;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
UNREFERENCED_PARAMETER(ulFlags);
|
|
|
|
DPRINT("PNP_SetDeviceRegProp(%p %S %lu %lu %p %lu 0x%08lx)\n",
|
|
hBinding, pDeviceId, ulProperty, ulDataType, Buffer,
|
|
ulLength, ulFlags);
|
|
|
|
if (!IsValidDeviceInstanceID(pDeviceId))
|
|
return CR_INVALID_DEVINST;
|
|
|
|
switch (ulProperty)
|
|
{
|
|
case CM_DRP_DEVICEDESC:
|
|
lpValueName = L"DeviceDesc";
|
|
break;
|
|
|
|
case CM_DRP_HARDWAREID:
|
|
lpValueName = L"HardwareID";
|
|
break;
|
|
|
|
case CM_DRP_COMPATIBLEIDS:
|
|
lpValueName = L"CompatibleIDs";
|
|
break;
|
|
|
|
case CM_DRP_SERVICE:
|
|
lpValueName = L"Service";
|
|
break;
|
|
|
|
case CM_DRP_CLASS:
|
|
lpValueName = L"Class";
|
|
break;
|
|
|
|
case CM_DRP_CLASSGUID:
|
|
lpValueName = L"ClassGUID";
|
|
break;
|
|
|
|
case CM_DRP_DRIVER:
|
|
lpValueName = L"Driver";
|
|
break;
|
|
|
|
case CM_DRP_CONFIGFLAGS:
|
|
lpValueName = L"ConfigFlags";
|
|
break;
|
|
|
|
case CM_DRP_MFG:
|
|
lpValueName = L"Mfg";
|
|
break;
|
|
|
|
case CM_DRP_FRIENDLYNAME:
|
|
lpValueName = L"FriendlyName";
|
|
break;
|
|
|
|
case CM_DRP_LOCATION_INFORMATION:
|
|
lpValueName = L"LocationInformation";
|
|
break;
|
|
|
|
case CM_DRP_UPPERFILTERS:
|
|
lpValueName = L"UpperFilters";
|
|
break;
|
|
|
|
case CM_DRP_LOWERFILTERS:
|
|
lpValueName = L"LowerFilters";
|
|
break;
|
|
|
|
case CM_DRP_SECURITY:
|
|
lpValueName = L"Security";
|
|
break;
|
|
|
|
case CM_DRP_DEVTYPE:
|
|
lpValueName = L"DeviceType";
|
|
break;
|
|
|
|
case CM_DRP_EXCLUSIVE:
|
|
lpValueName = L"Exclusive";
|
|
break;
|
|
|
|
case CM_DRP_CHARACTERISTICS:
|
|
lpValueName = L"DeviceCharacteristics";
|
|
break;
|
|
|
|
case CM_DRP_UI_NUMBER_DESC_FORMAT:
|
|
lpValueName = L"UINumberDescFormat";
|
|
break;
|
|
|
|
case CM_DRP_REMOVAL_POLICY_OVERRIDE:
|
|
lpValueName = L"RemovalPolicy";
|
|
break;
|
|
|
|
default:
|
|
return CR_INVALID_PROPERTY;
|
|
}
|
|
|
|
DPRINT("Value name: %S\n", lpValueName);
|
|
|
|
if (RegOpenKeyExW(hEnumKey,
|
|
pDeviceId,
|
|
0,
|
|
KEY_SET_VALUE,
|
|
&hKey))
|
|
return CR_INVALID_DEVNODE;
|
|
|
|
if (ulLength == 0)
|
|
{
|
|
if (RegDeleteValueW(hKey,
|
|
lpValueName))
|
|
ret = CR_REGISTRY_ERROR;
|
|
}
|
|
else
|
|
{
|
|
if (RegSetValueExW(hKey,
|
|
lpValueName,
|
|
0,
|
|
ulDataType,
|
|
Buffer,
|
|
ulLength))
|
|
ret = CR_REGISTRY_ERROR;
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
DPRINT("PNP_SetDeviceRegProp() done (returns %lx)\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 15 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetClassInstance(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceId,
|
|
LPWSTR pszClassInstance,
|
|
PNP_RPC_STRING_LEN ulLength)
|
|
{
|
|
WCHAR szClassGuid[40];
|
|
WCHAR szClassInstance[5];
|
|
HKEY hDeviceClassKey = NULL;
|
|
HKEY hClassInstanceKey;
|
|
ULONG ulTransferLength, ulDataLength;
|
|
DWORD dwDataType, dwDisposition, i;
|
|
DWORD dwError;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
DPRINT("PNP_GetClassInstance(%p %S %p %lu)\n",
|
|
hBinding, pDeviceId, pszClassInstance, ulLength);
|
|
|
|
if (!IsValidDeviceInstanceID(pDeviceId))
|
|
return CR_INVALID_DEVINST;
|
|
|
|
ulTransferLength = ulLength;
|
|
ret = PNP_GetDeviceRegProp(hBinding,
|
|
pDeviceId,
|
|
CM_DRP_DRIVER,
|
|
&dwDataType,
|
|
(BYTE *)pszClassInstance,
|
|
&ulTransferLength,
|
|
&ulLength,
|
|
0);
|
|
if (ret == CR_SUCCESS)
|
|
return ret;
|
|
|
|
ulTransferLength = sizeof(szClassGuid);
|
|
ulDataLength = sizeof(szClassGuid);
|
|
ret = PNP_GetDeviceRegProp(hBinding,
|
|
pDeviceId,
|
|
CM_DRP_CLASSGUID,
|
|
&dwDataType,
|
|
(BYTE *)szClassGuid,
|
|
&ulTransferLength,
|
|
&ulDataLength,
|
|
0);
|
|
if (ret != CR_SUCCESS)
|
|
{
|
|
DPRINT1("PNP_GetDeviceRegProp() failed (Error %lu)\n", ret);
|
|
goto done;
|
|
}
|
|
|
|
dwError = RegOpenKeyExW(hClassKey,
|
|
szClassGuid,
|
|
0,
|
|
KEY_READ,
|
|
&hDeviceClassKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("RegOpenKeyExW() failed (Error %lu)\n", dwError);
|
|
ret = CR_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
for (i = 0; i < 10000; i++)
|
|
{
|
|
wsprintf(szClassInstance, L"%04lu", i);
|
|
|
|
dwError = RegCreateKeyExW(hDeviceClassKey,
|
|
szClassInstance,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hClassInstanceKey,
|
|
&dwDisposition);
|
|
if (dwError == ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hClassInstanceKey);
|
|
|
|
if (dwDisposition == REG_CREATED_NEW_KEY)
|
|
{
|
|
wsprintf(pszClassInstance,
|
|
L"%s\\%s",
|
|
szClassGuid,
|
|
szClassInstance);
|
|
|
|
ulDataLength = (wcslen(pszClassInstance) + 1) * sizeof(WCHAR);
|
|
ret = PNP_SetDeviceRegProp(hBinding,
|
|
pDeviceId,
|
|
CM_DRP_DRIVER,
|
|
REG_SZ,
|
|
(BYTE *)pszClassInstance,
|
|
ulDataLength,
|
|
0);
|
|
if (ret != CR_SUCCESS)
|
|
{
|
|
DPRINT1("PNP_SetDeviceRegProp() failed (Error %lu)\n", ret);
|
|
RegDeleteKeyW(hDeviceClassKey,
|
|
szClassInstance);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
done:
|
|
if (hDeviceClassKey != NULL)
|
|
RegCloseKey(hDeviceClassKey);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 16 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_CreateKey(
|
|
handle_t hBinding,
|
|
LPWSTR pszSubKey,
|
|
DWORD samDesired,
|
|
DWORD ulFlags)
|
|
{
|
|
HKEY hDeviceKey = NULL, hParametersKey = NULL;
|
|
DWORD dwError;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
UNREFERENCED_PARAMETER(samDesired);
|
|
|
|
DPRINT("PNP_CreateKey(%p %S 0x%lx 0x%08lx)\n",
|
|
hBinding, pszSubKey, samDesired, ulFlags);
|
|
|
|
if (ulFlags != 0)
|
|
return CR_INVALID_FLAG;
|
|
|
|
if (!IsValidDeviceInstanceID(pszSubKey))
|
|
return CR_INVALID_DEVINST;
|
|
|
|
dwError = RegOpenKeyExW(hEnumKey,
|
|
pszSubKey,
|
|
0,
|
|
KEY_WRITE,
|
|
&hDeviceKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
ret = CR_INVALID_DEVNODE;
|
|
goto done;
|
|
}
|
|
|
|
dwError = RegCreateKeyExW(hDeviceKey,
|
|
L"Device Parameters",
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hParametersKey,
|
|
NULL);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
ret = CR_REGISTRY_ERROR;
|
|
goto done;
|
|
}
|
|
|
|
/* FIXME: Set key security */
|
|
|
|
done:
|
|
if (hParametersKey != NULL)
|
|
RegCloseKey(hParametersKey);
|
|
|
|
if (hDeviceKey != NULL)
|
|
RegCloseKey(hDeviceKey);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 17 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_DeleteRegistryKey(
|
|
handle_t hBinding,
|
|
LPWSTR pszDeviceID,
|
|
LPWSTR pszParentKey,
|
|
LPWSTR pszChildKey,
|
|
DWORD ulFlags)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 18 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetClassCount(
|
|
handle_t hBinding,
|
|
DWORD *pulClassCount,
|
|
DWORD ulFlags)
|
|
{
|
|
HKEY hKey;
|
|
DWORD dwError;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
UNREFERENCED_PARAMETER(ulFlags);
|
|
|
|
DPRINT("PNP_GetClassCount(%p %p 0x%08lx)\n",
|
|
hBinding, pulClassCount, ulFlags);
|
|
|
|
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
REGSTR_PATH_CLASS,
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
return CR_INVALID_DATA;
|
|
|
|
dwError = RegQueryInfoKeyW(hKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
pulClassCount,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
RegCloseKey(hKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
return CR_INVALID_DATA;
|
|
|
|
return CR_SUCCESS;
|
|
}
|
|
|
|
|
|
/* Function 19 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetClassName(
|
|
handle_t hBinding,
|
|
LPWSTR pszClassGuid,
|
|
LPWSTR Buffer,
|
|
PNP_RPC_STRING_LEN *pulLength,
|
|
DWORD ulFlags)
|
|
{
|
|
WCHAR szKeyName[MAX_PATH];
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
HKEY hKey;
|
|
DWORD dwSize;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
UNREFERENCED_PARAMETER(ulFlags);
|
|
|
|
DPRINT("PNP_GetClassName(%p %S %p %p 0x%08lx)\n",
|
|
hBinding, pszClassGuid, Buffer, pulLength, ulFlags);
|
|
|
|
lstrcpyW(szKeyName, L"System\\CurrentControlSet\\Control\\Class\\");
|
|
if (lstrlenW(pszClassGuid) + 1 < sizeof(szKeyName)/sizeof(WCHAR)-(lstrlenW(szKeyName) * sizeof(WCHAR)))
|
|
lstrcatW(szKeyName, pszClassGuid);
|
|
else
|
|
return CR_INVALID_DATA;
|
|
|
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
szKeyName,
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hKey))
|
|
return CR_REGISTRY_ERROR;
|
|
|
|
dwSize = *pulLength * sizeof(WCHAR);
|
|
if (RegQueryValueExW(hKey,
|
|
L"Class",
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)Buffer,
|
|
&dwSize))
|
|
{
|
|
*pulLength = 0;
|
|
ret = CR_REGISTRY_ERROR;
|
|
}
|
|
else
|
|
{
|
|
*pulLength = dwSize / sizeof(WCHAR);
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
DPRINT("PNP_GetClassName() done (returns %lx)\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 20 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_DeleteClassKey(
|
|
handle_t hBinding,
|
|
LPWSTR pszClassGuid,
|
|
DWORD ulFlags)
|
|
{
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
|
|
DPRINT("PNP_DeleteClassKey(%p %S 0x%08lx)\n",
|
|
hBinding, pszClassGuid, ulFlags);
|
|
|
|
if (ulFlags & CM_DELETE_CLASS_SUBKEYS)
|
|
{
|
|
if (SHDeleteKeyW(hClassKey, pszClassGuid) != ERROR_SUCCESS)
|
|
ret = CR_REGISTRY_ERROR;
|
|
}
|
|
else
|
|
{
|
|
if (RegDeleteKeyW(hClassKey, pszClassGuid) != ERROR_SUCCESS)
|
|
ret = CR_REGISTRY_ERROR;
|
|
}
|
|
|
|
DPRINT("PNP_DeleteClassKey() done (returns %lx)\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 21 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetInterfaceDeviceAlias(
|
|
handle_t hBinding,
|
|
LPWSTR pszInterfaceDevice,
|
|
GUID *AliasInterfaceGuid,
|
|
LPWSTR pszAliasInterfaceDevice,
|
|
PNP_RPC_STRING_LEN *pulLength,
|
|
PNP_RPC_STRING_LEN *pulTransferLen,
|
|
DWORD ulFlags)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 22 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetInterfaceDeviceList(
|
|
handle_t hBinding,
|
|
GUID *InterfaceGuid,
|
|
LPWSTR pszDeviceID,
|
|
BYTE *Buffer,
|
|
PNP_RPC_BUFFER_SIZE *pulLength,
|
|
DWORD ulFlags)
|
|
{
|
|
NTSTATUS Status;
|
|
PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA PlugPlayData;
|
|
DWORD ret = CR_SUCCESS;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
|
|
DPRINT("PNP_GetInterfaceDeviceList(%p %p %S %p %p 0x%08lx)\n",
|
|
hBinding, InterfaceGuid, pszDeviceID, Buffer, pulLength, ulFlags);
|
|
|
|
if (!IsValidDeviceInstanceID(pszDeviceID))
|
|
return CR_INVALID_DEVINST;
|
|
|
|
RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
|
|
pszDeviceID);
|
|
|
|
PlugPlayData.Flags = ulFlags;
|
|
PlugPlayData.FilterGuid = InterfaceGuid;
|
|
PlugPlayData.Buffer = Buffer;
|
|
PlugPlayData.BufferSize = *pulLength;
|
|
|
|
Status = NtPlugPlayControl(PlugPlayControlGetInterfaceDeviceList,
|
|
(PVOID)&PlugPlayData,
|
|
sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA));
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
*pulLength = PlugPlayData.BufferSize;
|
|
}
|
|
else
|
|
{
|
|
ret = NtStatusToCrError(Status);
|
|
}
|
|
|
|
DPRINT("PNP_GetInterfaceDeviceList() done (returns %lx)\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 23 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetInterfaceDeviceListSize(
|
|
handle_t hBinding,
|
|
PNP_RPC_BUFFER_SIZE *pulLen,
|
|
GUID *InterfaceGuid,
|
|
LPWSTR pszDeviceID,
|
|
DWORD ulFlags)
|
|
{
|
|
NTSTATUS Status;
|
|
PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA PlugPlayData;
|
|
DWORD ret = CR_SUCCESS;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
|
|
DPRINT("PNP_GetInterfaceDeviceListSize(%p %p %p %S 0x%08lx)\n",
|
|
hBinding, pulLen, InterfaceGuid, pszDeviceID, ulFlags);
|
|
|
|
if (!IsValidDeviceInstanceID(pszDeviceID))
|
|
return CR_INVALID_DEVINST;
|
|
|
|
RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
|
|
pszDeviceID);
|
|
|
|
PlugPlayData.FilterGuid = InterfaceGuid;
|
|
PlugPlayData.Buffer = NULL;
|
|
PlugPlayData.BufferSize = 0;
|
|
PlugPlayData.Flags = ulFlags;
|
|
|
|
Status = NtPlugPlayControl(PlugPlayControlGetInterfaceDeviceList,
|
|
(PVOID)&PlugPlayData,
|
|
sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA));
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
*pulLen = PlugPlayData.BufferSize;
|
|
}
|
|
else
|
|
{
|
|
ret = NtStatusToCrError(Status);
|
|
}
|
|
|
|
DPRINT("PNP_GetInterfaceDeviceListSize() done (returns %lx)\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 24 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_RegisterDeviceClassAssociation(
|
|
handle_t hBinding,
|
|
LPWSTR pszDeviceID,
|
|
GUID *InterfaceGuid,
|
|
LPWSTR pszReference,
|
|
LPWSTR pszSymLink,
|
|
PNP_RPC_STRING_LEN *pulLength,
|
|
PNP_RPC_STRING_LEN *pulTransferLen,
|
|
DWORD ulFlags)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 25 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_UnregisterDeviceClassAssociation(
|
|
handle_t hBinding,
|
|
LPWSTR pszInterfaceDevice,
|
|
DWORD ulFlags)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 26 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetClassRegProp(
|
|
handle_t hBinding,
|
|
LPWSTR pszClassGuid,
|
|
DWORD ulProperty,
|
|
DWORD *pulRegDataType,
|
|
BYTE *Buffer,
|
|
PNP_RPC_STRING_LEN *pulTransferLen,
|
|
PNP_RPC_STRING_LEN *pulLength,
|
|
DWORD ulFlags)
|
|
{
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
LPWSTR lpValueName = NULL;
|
|
HKEY hInstKey = NULL;
|
|
HKEY hPropKey = NULL;
|
|
LONG lError;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
|
|
DPRINT("PNP_GetClassRegProp(%p %S %lu %p %p %p %p 0x%08lx)\n",
|
|
hBinding, pszClassGuid, ulProperty, pulRegDataType,
|
|
Buffer, pulTransferLen, pulLength, ulFlags);
|
|
|
|
if (pulTransferLen == NULL || pulLength == NULL)
|
|
{
|
|
ret = CR_INVALID_POINTER;
|
|
goto done;
|
|
}
|
|
|
|
if (ulFlags != 0)
|
|
{
|
|
ret = CR_INVALID_FLAG;
|
|
goto done;
|
|
}
|
|
|
|
if (*pulLength < *pulTransferLen)
|
|
*pulLength = *pulTransferLen;
|
|
|
|
*pulTransferLen = 0;
|
|
|
|
switch (ulProperty)
|
|
{
|
|
case CM_CRP_SECURITY:
|
|
lpValueName = L"Security";
|
|
break;
|
|
|
|
case CM_CRP_DEVTYPE:
|
|
lpValueName = L"DeviceType";
|
|
break;
|
|
|
|
case CM_CRP_EXCLUSIVE:
|
|
lpValueName = L"Exclusive";
|
|
break;
|
|
|
|
case CM_CRP_CHARACTERISTICS:
|
|
lpValueName = L"DeviceCharacteristics";
|
|
break;
|
|
|
|
default:
|
|
ret = CR_INVALID_PROPERTY;
|
|
goto done;
|
|
}
|
|
|
|
DPRINT("Value name: %S\n", lpValueName);
|
|
|
|
lError = RegOpenKeyExW(hClassKey,
|
|
pszClassGuid,
|
|
0,
|
|
KEY_READ,
|
|
&hInstKey);
|
|
if (lError != ERROR_SUCCESS)
|
|
{
|
|
*pulLength = 0;
|
|
ret = CR_NO_SUCH_REGISTRY_KEY;
|
|
goto done;
|
|
}
|
|
|
|
lError = RegOpenKeyExW(hInstKey,
|
|
L"Properties",
|
|
0,
|
|
KEY_READ,
|
|
&hPropKey);
|
|
if (lError != ERROR_SUCCESS)
|
|
{
|
|
*pulLength = 0;
|
|
ret = CR_NO_SUCH_REGISTRY_KEY;
|
|
goto done;
|
|
}
|
|
|
|
lError = RegQueryValueExW(hPropKey,
|
|
lpValueName,
|
|
NULL,
|
|
pulRegDataType,
|
|
Buffer,
|
|
pulLength);
|
|
if (lError != ERROR_SUCCESS)
|
|
{
|
|
if (lError == ERROR_MORE_DATA)
|
|
{
|
|
ret = CR_BUFFER_SMALL;
|
|
}
|
|
else
|
|
{
|
|
*pulLength = 0;
|
|
ret = CR_NO_SUCH_VALUE;
|
|
}
|
|
}
|
|
|
|
done:
|
|
if (ret == CR_SUCCESS)
|
|
*pulTransferLen = *pulLength;
|
|
|
|
if (hPropKey != NULL)
|
|
RegCloseKey(hPropKey);
|
|
|
|
if (hInstKey != NULL)
|
|
RegCloseKey(hInstKey);
|
|
|
|
DPRINT("PNP_GetClassRegProp() done (returns %lx)\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 27 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_SetClassRegProp(
|
|
handle_t hBinding,
|
|
LPWSTR pszClassGuid,
|
|
DWORD ulProperty,
|
|
DWORD ulDataType,
|
|
BYTE *Buffer,
|
|
PNP_PROP_SIZE ulLength,
|
|
DWORD ulFlags)
|
|
{
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
LPWSTR lpValueName = NULL;
|
|
HKEY hInstKey = 0;
|
|
HKEY hPropKey = 0;
|
|
LONG lError;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
|
|
DPRINT("PNP_SetClassRegProp(%p %S %lu %lu %p %lu 0x%08lx)\n",
|
|
hBinding, pszClassGuid, ulProperty, ulDataType,
|
|
Buffer, ulLength, ulFlags);
|
|
|
|
if (ulFlags != 0)
|
|
return CR_INVALID_FLAG;
|
|
|
|
switch (ulProperty)
|
|
{
|
|
case CM_CRP_SECURITY:
|
|
lpValueName = L"Security";
|
|
break;
|
|
|
|
case CM_CRP_DEVTYPE:
|
|
lpValueName = L"DeviceType";
|
|
break;
|
|
|
|
case CM_CRP_EXCLUSIVE:
|
|
lpValueName = L"Exclusive";
|
|
break;
|
|
|
|
case CM_CRP_CHARACTERISTICS:
|
|
lpValueName = L"DeviceCharacteristics";
|
|
break;
|
|
|
|
default:
|
|
return CR_INVALID_PROPERTY;
|
|
}
|
|
|
|
lError = RegOpenKeyExW(hClassKey,
|
|
pszClassGuid,
|
|
0,
|
|
KEY_WRITE,
|
|
&hInstKey);
|
|
if (lError != ERROR_SUCCESS)
|
|
{
|
|
ret = CR_NO_SUCH_REGISTRY_KEY;
|
|
goto done;
|
|
}
|
|
|
|
/* FIXME: Set security descriptor */
|
|
lError = RegCreateKeyExW(hInstKey,
|
|
L"Properties",
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hPropKey,
|
|
NULL);
|
|
if (lError != ERROR_SUCCESS)
|
|
{
|
|
ret = CR_REGISTRY_ERROR;
|
|
goto done;
|
|
}
|
|
|
|
if (ulLength == 0)
|
|
{
|
|
if (RegDeleteValueW(hPropKey,
|
|
lpValueName))
|
|
ret = CR_REGISTRY_ERROR;
|
|
}
|
|
else
|
|
{
|
|
if (RegSetValueExW(hPropKey,
|
|
lpValueName,
|
|
0,
|
|
ulDataType,
|
|
Buffer,
|
|
ulLength))
|
|
ret = CR_REGISTRY_ERROR;
|
|
}
|
|
|
|
done:
|
|
if (hPropKey != NULL)
|
|
RegCloseKey(hPropKey);
|
|
|
|
if (hInstKey != NULL)
|
|
RegCloseKey(hInstKey);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static
|
|
CONFIGRET
|
|
CreateDeviceInstance(
|
|
_In_ LPWSTR pszDeviceID,
|
|
_In_ BOOL bPhantomDevice)
|
|
{
|
|
WCHAR szEnumerator[MAX_DEVICE_ID_LEN];
|
|
WCHAR szDevice[MAX_DEVICE_ID_LEN];
|
|
WCHAR szInstance[MAX_DEVICE_ID_LEN];
|
|
HKEY hKeyEnumerator;
|
|
HKEY hKeyDevice;
|
|
HKEY hKeyInstance;
|
|
HKEY hKeyControl;
|
|
LONG lError;
|
|
|
|
/* Split the instance ID */
|
|
SplitDeviceInstanceID(pszDeviceID,
|
|
szEnumerator,
|
|
szDevice,
|
|
szInstance);
|
|
|
|
/* Open or create the enumerator key */
|
|
lError = RegCreateKeyExW(hEnumKey,
|
|
szEnumerator,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKeyEnumerator,
|
|
NULL);
|
|
if (lError != ERROR_SUCCESS)
|
|
{
|
|
return CR_REGISTRY_ERROR;
|
|
}
|
|
|
|
/* Open or create the device key */
|
|
lError = RegCreateKeyExW(hKeyEnumerator,
|
|
szDevice,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKeyDevice,
|
|
NULL);
|
|
|
|
/* Close the enumerator key */
|
|
RegCloseKey(hKeyEnumerator);
|
|
|
|
if (lError != ERROR_SUCCESS)
|
|
{
|
|
return CR_REGISTRY_ERROR;
|
|
}
|
|
|
|
/* Try to open the instance key and fail if it exists */
|
|
lError = RegOpenKeyExW(hKeyDevice,
|
|
szInstance,
|
|
0,
|
|
KEY_SET_VALUE,
|
|
&hKeyInstance);
|
|
if (lError == ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Instance %S already exists!\n", szInstance);
|
|
RegCloseKey(hKeyInstance);
|
|
RegCloseKey(hKeyDevice);
|
|
return CR_ALREADY_SUCH_DEVINST;
|
|
}
|
|
|
|
/* Create a new instance key */
|
|
lError = RegCreateKeyExW(hKeyDevice,
|
|
szInstance,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKeyInstance,
|
|
NULL);
|
|
|
|
/* Close the device key */
|
|
RegCloseKey(hKeyDevice);
|
|
|
|
if (lError != ERROR_SUCCESS)
|
|
{
|
|
return CR_REGISTRY_ERROR;
|
|
}
|
|
|
|
if (bPhantomDevice)
|
|
{
|
|
DWORD dwPhantomValue = 1;
|
|
RegSetValueExW(hKeyInstance,
|
|
L"Phantom",
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&dwPhantomValue,
|
|
sizeof(dwPhantomValue));
|
|
}
|
|
|
|
/* Create the 'Control' sub key */
|
|
lError = RegCreateKeyExW(hKeyInstance,
|
|
L"Control",
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKeyControl,
|
|
NULL);
|
|
if (lError == ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hKeyControl);
|
|
}
|
|
|
|
RegCloseKey(hKeyInstance);
|
|
|
|
return (lError == ERROR_SUCCESS) ? CR_SUCCESS : CR_REGISTRY_ERROR;
|
|
}
|
|
|
|
|
|
static
|
|
CONFIGRET
|
|
GenerateDeviceID(
|
|
_Inout_ LPWSTR pszDeviceID,
|
|
_In_ PNP_RPC_STRING_LEN ulLength)
|
|
{
|
|
WCHAR szGeneratedInstance[MAX_DEVICE_ID_LEN];
|
|
HKEY hKey;
|
|
DWORD dwInstanceNumber;
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
/* Fail, if the device name contains backslashes */
|
|
if (wcschr(pszDeviceID, L'\\') != NULL)
|
|
return CR_INVALID_DEVICE_ID;
|
|
|
|
/* Generated ID is: Root\<Device ID>\<Instance number> */
|
|
dwInstanceNumber = 0;
|
|
while (dwError == ERROR_SUCCESS)
|
|
{
|
|
if (dwInstanceNumber >= 10000)
|
|
return CR_FAILURE;
|
|
|
|
swprintf(szGeneratedInstance, L"Root\\%ls\\%04lu",
|
|
pszDeviceID, dwInstanceNumber);
|
|
|
|
/* Try to open the enum key of the device instance */
|
|
dwError = RegOpenKeyEx(hEnumKey, szGeneratedInstance, 0, KEY_QUERY_VALUE, &hKey);
|
|
if (dwError == ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hKey);
|
|
dwInstanceNumber++;
|
|
}
|
|
}
|
|
|
|
/* pszDeviceID is an out parameter too for generated IDs */
|
|
if (wcslen(szGeneratedInstance) > ulLength)
|
|
{
|
|
ret = CR_BUFFER_SMALL;
|
|
}
|
|
else
|
|
{
|
|
wcscpy(pszDeviceID, szGeneratedInstance);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 28 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_CreateDevInst(
|
|
handle_t hBinding,
|
|
LPWSTR pszDeviceID,
|
|
LPWSTR pszParentDeviceID,
|
|
PNP_RPC_STRING_LEN ulLength,
|
|
DWORD ulFlags)
|
|
{
|
|
PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData;
|
|
HKEY hKey = NULL;
|
|
DWORD dwSize, dwPhantom;
|
|
NTSTATUS Status;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
DPRINT("PNP_CreateDevInst(%p %S %S %lu 0x%08lx)\n",
|
|
hBinding, pszParentDeviceID, pszDeviceID, ulLength, ulFlags);
|
|
|
|
if (ulFlags & ~CM_CREATE_DEVNODE_BITS)
|
|
return CR_INVALID_FLAG;
|
|
|
|
if (pszDeviceID == NULL || pszParentDeviceID == NULL)
|
|
return CR_INVALID_POINTER;
|
|
|
|
/* Fail, if the parent device is not the root device */
|
|
if (!IsRootDeviceInstanceID(pszParentDeviceID))
|
|
return CR_INVALID_DEVINST;
|
|
|
|
if (ulFlags & CM_CREATE_DEVNODE_GENERATE_ID)
|
|
{
|
|
ret = GenerateDeviceID(pszDeviceID,
|
|
ulLength);
|
|
if (ret != CR_SUCCESS)
|
|
return ret;
|
|
}
|
|
|
|
/* Try to open the device instance key */
|
|
RegOpenKeyEx(hEnumKey, pszDeviceID, 0, KEY_READ | KEY_WRITE, &hKey);
|
|
|
|
if (ulFlags & CM_CREATE_DEVNODE_PHANTOM)
|
|
{
|
|
/* Fail, if the device already exists */
|
|
if (hKey != NULL)
|
|
{
|
|
ret = CR_ALREADY_SUCH_DEVINST;
|
|
goto done;
|
|
}
|
|
|
|
/* Create the phantom device instance */
|
|
ret = CreateDeviceInstance(pszDeviceID, TRUE);
|
|
}
|
|
else
|
|
{
|
|
/* Fail, if the device exists and is present */
|
|
if ((hKey != NULL) && (IsPresentDeviceInstanceID(pszDeviceID)))
|
|
{
|
|
ret = CR_ALREADY_SUCH_DEVINST;
|
|
goto done;
|
|
}
|
|
|
|
/* If it does not already exist ... */
|
|
if (hKey == NULL)
|
|
{
|
|
/* Create the device instance */
|
|
ret = CreateDeviceInstance(pszDeviceID, FALSE);
|
|
|
|
/* Open the device instance key */
|
|
RegOpenKeyEx(hEnumKey, pszDeviceID, 0, KEY_READ | KEY_WRITE, &hKey);
|
|
}
|
|
|
|
/* Create a device node for the device */
|
|
RtlInitUnicodeString(&ControlData.DeviceInstance, pszDeviceID);
|
|
Status = NtPlugPlayControl(PlugPlayControlInitializeDevice,
|
|
&ControlData,
|
|
sizeof(ControlData));
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ret = CR_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
/* If the device is a phantom device, turn it into a normal device */
|
|
if (hKey != NULL)
|
|
{
|
|
dwPhantom = 0;
|
|
dwSize = sizeof(DWORD);
|
|
RegQueryValueEx(hKey, L"Phantom", NULL, NULL, (PBYTE)&dwPhantom, &dwSize);
|
|
|
|
if (dwPhantom != 0)
|
|
RegDeleteValue(hKey, L"Phantom");
|
|
}
|
|
}
|
|
|
|
done:
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
DPRINT("PNP_CreateDevInst() done (returns %lx)\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static CONFIGRET
|
|
SetupDeviceInstance(
|
|
_In_ LPWSTR pszDeviceInstance,
|
|
_In_ DWORD ulMinorAction)
|
|
{
|
|
PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData;
|
|
HKEY hDeviceKey = NULL;
|
|
DWORD dwDisableCount, dwSize;
|
|
DWORD ulStatus, ulProblem;
|
|
DWORD dwError;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT1("SetupDeviceInstance(%S 0x%08lx)\n",
|
|
pszDeviceInstance, ulMinorAction);
|
|
|
|
if (IsRootDeviceInstanceID(pszDeviceInstance))
|
|
return CR_INVALID_DEVINST;
|
|
|
|
if (ulMinorAction & ~CM_SETUP_BITS)
|
|
return CR_INVALID_FLAG;
|
|
|
|
if ((ulMinorAction == CM_SETUP_DOWNLOAD) ||
|
|
(ulMinorAction == CM_SETUP_WRITE_LOG_CONFS))
|
|
return CR_SUCCESS;
|
|
|
|
dwError = RegOpenKeyExW(hEnumKey,
|
|
pszDeviceInstance,
|
|
0,
|
|
KEY_READ,
|
|
&hDeviceKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
return CR_INVALID_DEVNODE;
|
|
|
|
dwSize = sizeof(dwDisableCount);
|
|
dwError = RegQueryValueExW(hDeviceKey,
|
|
L"DisableCount",
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)&dwDisableCount,
|
|
&dwSize);
|
|
if ((dwError == ERROR_SUCCESS) &&
|
|
(dwDisableCount > 0))
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
GetDeviceStatus(pszDeviceInstance,
|
|
&ulStatus,
|
|
&ulProblem);
|
|
|
|
if (ulStatus & DN_STARTED)
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
if (ulStatus & DN_HAS_PROBLEM)
|
|
{
|
|
ret = ClearDeviceStatus(pszDeviceInstance,
|
|
DN_HAS_PROBLEM,
|
|
ulProblem);
|
|
}
|
|
|
|
if (ret != CR_SUCCESS)
|
|
goto done;
|
|
|
|
/* Start the device */
|
|
RtlInitUnicodeString(&ControlData.DeviceInstance,
|
|
pszDeviceInstance);
|
|
Status = NtPlugPlayControl(PlugPlayControlStartDevice,
|
|
&ControlData,
|
|
sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA));
|
|
if (!NT_SUCCESS(Status))
|
|
ret = NtStatusToCrError(Status);
|
|
|
|
done:
|
|
if (hDeviceKey != NULL)
|
|
RegCloseKey(hDeviceKey);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static CONFIGRET
|
|
EnableDeviceInstance(
|
|
_In_ LPWSTR pszDeviceInstance)
|
|
{
|
|
PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("Enable device instance %S\n", pszDeviceInstance);
|
|
|
|
RtlInitUnicodeString(&ControlData.DeviceInstance, pszDeviceInstance);
|
|
Status = NtPlugPlayControl(PlugPlayControlStartDevice, &ControlData, sizeof(ControlData));
|
|
if (!NT_SUCCESS(Status))
|
|
ret = NtStatusToCrError(Status);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static CONFIGRET
|
|
ReenumerateDeviceInstance(
|
|
_In_ LPWSTR pszDeviceInstance,
|
|
_In_ ULONG ulMinorAction)
|
|
{
|
|
PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA EnumerateDeviceData;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT1("ReenumerateDeviceInstance(%S 0x%08lx)\n",
|
|
pszDeviceInstance, ulMinorAction);
|
|
|
|
if (ulMinorAction & ~CM_REENUMERATE_BITS)
|
|
return CR_INVALID_FLAG;
|
|
|
|
if (ulMinorAction & CM_REENUMERATE_RETRY_INSTALLATION)
|
|
{
|
|
DPRINT1("CM_REENUMERATE_RETRY_INSTALLATION not implemented!\n");
|
|
}
|
|
|
|
RtlInitUnicodeString(&EnumerateDeviceData.DeviceInstance,
|
|
pszDeviceInstance);
|
|
EnumerateDeviceData.Flags = 0;
|
|
|
|
Status = NtPlugPlayControl(PlugPlayControlEnumerateDevice,
|
|
&EnumerateDeviceData,
|
|
sizeof(PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA));
|
|
if (!NT_SUCCESS(Status))
|
|
ret = NtStatusToCrError(Status);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 29 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_DeviceInstanceAction(
|
|
handle_t hBinding,
|
|
DWORD ulMajorAction,
|
|
DWORD ulMinorAction,
|
|
LPWSTR pszDeviceInstance1,
|
|
LPWSTR pszDeviceInstance2)
|
|
{
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
|
|
DPRINT("PNP_DeviceInstanceAction(%p %lu 0x%08lx %S %S)\n",
|
|
hBinding, ulMajorAction, ulMinorAction,
|
|
pszDeviceInstance1, pszDeviceInstance2);
|
|
|
|
switch (ulMajorAction)
|
|
{
|
|
case PNP_DEVINST_SETUP:
|
|
ret = SetupDeviceInstance(pszDeviceInstance1,
|
|
ulMinorAction);
|
|
break;
|
|
|
|
case PNP_DEVINST_ENABLE:
|
|
ret = EnableDeviceInstance(pszDeviceInstance1);
|
|
break;
|
|
|
|
case PNP_DEVINST_REENUMERATE:
|
|
ret = ReenumerateDeviceInstance(pszDeviceInstance1,
|
|
ulMinorAction);
|
|
break;
|
|
|
|
default:
|
|
DPRINT1("Unknown device action %lu: not implemented\n", ulMajorAction);
|
|
ret = CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
DPRINT("PNP_DeviceInstanceAction() done (returns %lx)\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 30 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetDeviceStatus(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceID,
|
|
DWORD *pulStatus,
|
|
DWORD *pulProblem,
|
|
DWORD ulFlags)
|
|
{
|
|
DWORD ulDataType, ulTransferLength, ulLength;
|
|
DWORD ulCapabilities, ulConfigFlags;
|
|
CONFIGRET ret;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
UNREFERENCED_PARAMETER(ulFlags);
|
|
|
|
DPRINT("PNP_GetDeviceStatus(%p %S %p %p 0x%08lx)\n",
|
|
hBinding, pDeviceID, pulStatus, pulProblem, ulFlags);
|
|
|
|
if (ulFlags != 0)
|
|
return CR_INVALID_FLAG;
|
|
|
|
if ((pulStatus == NULL) || (pulProblem == NULL))
|
|
return CR_INVALID_POINTER;
|
|
|
|
if (!IsValidDeviceInstanceID(pDeviceID))
|
|
return CR_INVALID_DEVINST;
|
|
|
|
ret = GetDeviceStatus(pDeviceID, pulStatus, pulProblem);
|
|
if (ret != CR_SUCCESS)
|
|
return ret;
|
|
|
|
/* Check for DN_REMOVABLE */
|
|
ulTransferLength = sizeof(ulCapabilities);
|
|
ulLength = sizeof(ulCapabilities);
|
|
ret = PNP_GetDeviceRegProp(NULL,
|
|
pDeviceID,
|
|
CM_DRP_CAPABILITIES,
|
|
&ulDataType,
|
|
(PBYTE)&ulCapabilities,
|
|
&ulTransferLength,
|
|
&ulLength,
|
|
0);
|
|
if (ret != CR_SUCCESS)
|
|
ulCapabilities = 0;
|
|
|
|
if (ulCapabilities & CM_DEVCAP_REMOVABLE)
|
|
*pulStatus |= DN_REMOVABLE;
|
|
|
|
/* Check for DN_MANUAL */
|
|
ulTransferLength = sizeof(ulConfigFlags);
|
|
ulLength = sizeof(ulConfigFlags);
|
|
ret = PNP_GetDeviceRegProp(NULL,
|
|
pDeviceID,
|
|
CM_DRP_CONFIGFLAGS,
|
|
&ulDataType,
|
|
(PBYTE)&ulConfigFlags,
|
|
&ulTransferLength,
|
|
&ulLength,
|
|
0);
|
|
if (ret != CR_SUCCESS)
|
|
ulConfigFlags = 0;
|
|
|
|
if (ulConfigFlags & CONFIGFLAG_MANUAL_INSTALL)
|
|
*pulStatus |= DN_MANUAL;
|
|
|
|
/* Check for failed install */
|
|
if (((*pulStatus & DN_HAS_PROBLEM) == 0) && (ulConfigFlags & CONFIGFLAG_FAILEDINSTALL))
|
|
{
|
|
*pulStatus |= DN_HAS_PROBLEM;
|
|
*pulProblem = CM_PROB_FAILED_INSTALL;
|
|
}
|
|
|
|
return CR_SUCCESS;
|
|
}
|
|
|
|
|
|
/* Function 31 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_SetDeviceProblem(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceID,
|
|
DWORD ulProblem,
|
|
DWORD ulFlags)
|
|
{
|
|
ULONG ulOldStatus, ulOldProblem;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
|
|
DPRINT1("PNP_SetDeviceProblem(%p %S %lu 0x%08lx)\n",
|
|
hBinding, pDeviceID, ulProblem, ulFlags);
|
|
|
|
if (ulFlags & ~CM_SET_DEVNODE_PROBLEM_BITS)
|
|
return CR_INVALID_FLAG;
|
|
|
|
if (!IsValidDeviceInstanceID(pDeviceID))
|
|
return CR_INVALID_DEVINST;
|
|
|
|
ret = GetDeviceStatus(pDeviceID,
|
|
&ulOldStatus,
|
|
&ulOldProblem);
|
|
if (ret != CR_SUCCESS)
|
|
return ret;
|
|
|
|
if (((ulFlags & CM_SET_DEVNODE_PROBLEM_OVERRIDE) == 0) &&
|
|
(ulOldProblem != 0) &&
|
|
(ulOldProblem != ulProblem))
|
|
{
|
|
return CR_FAILURE;
|
|
}
|
|
|
|
if (ulProblem == 0)
|
|
{
|
|
ret = ClearDeviceStatus(pDeviceID,
|
|
DN_HAS_PROBLEM,
|
|
ulOldProblem);
|
|
}
|
|
else
|
|
{
|
|
ret = SetDeviceStatus(pDeviceID,
|
|
DN_HAS_PROBLEM,
|
|
ulProblem);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 32 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_DisableDevInst(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceID,
|
|
PPNP_VETO_TYPE pVetoType,
|
|
LPWSTR pszVetoName,
|
|
DWORD ulNameLength,
|
|
DWORD ulFlags)
|
|
{
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
|
|
DPRINT1("PNP_DisableDevInst(%p %S %p %p %lu 0x%08lx)\n",
|
|
hBinding, pDeviceID, pVetoType, pszVetoName, ulNameLength, ulFlags);
|
|
|
|
if (ulFlags & ~CM_DISABLE_BITS)
|
|
return CR_INVALID_FLAG;
|
|
|
|
if (!IsValidDeviceInstanceID(pDeviceID) ||
|
|
IsRootDeviceInstanceID(pDeviceID))
|
|
return CR_INVALID_DEVINST;
|
|
|
|
return DisableDeviceInstance(pDeviceID,
|
|
pVetoType,
|
|
pszVetoName,
|
|
ulNameLength);
|
|
}
|
|
|
|
|
|
/* Function 33 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_UninstallDevInst(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceID,
|
|
DWORD ulFlags)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
static BOOL
|
|
CheckForDeviceId(LPWSTR lpDeviceIdList,
|
|
LPWSTR lpDeviceId)
|
|
{
|
|
LPWSTR lpPtr;
|
|
DWORD dwLength;
|
|
|
|
lpPtr = lpDeviceIdList;
|
|
while (*lpPtr != 0)
|
|
{
|
|
dwLength = wcslen(lpPtr);
|
|
if (0 == _wcsicmp(lpPtr, lpDeviceId))
|
|
return TRUE;
|
|
|
|
lpPtr += (dwLength + 1);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static VOID
|
|
AppendDeviceId(LPWSTR lpDeviceIdList,
|
|
LPDWORD lpDeviceIdListSize,
|
|
LPWSTR lpDeviceId)
|
|
{
|
|
DWORD dwLen;
|
|
DWORD dwPos;
|
|
|
|
dwLen = wcslen(lpDeviceId);
|
|
dwPos = (*lpDeviceIdListSize / sizeof(WCHAR)) - 1;
|
|
|
|
wcscpy(&lpDeviceIdList[dwPos], lpDeviceId);
|
|
|
|
dwPos += (dwLen + 1);
|
|
|
|
lpDeviceIdList[dwPos] = 0;
|
|
|
|
*lpDeviceIdListSize = dwPos * sizeof(WCHAR);
|
|
}
|
|
|
|
|
|
/* Function 34 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_AddID(
|
|
handle_t hBinding,
|
|
LPWSTR pszDeviceID,
|
|
LPWSTR pszID,
|
|
DWORD ulFlags)
|
|
{
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
HKEY hDeviceKey;
|
|
LPWSTR pszSubKey;
|
|
DWORD dwDeviceIdListSize;
|
|
DWORD dwNewDeviceIdSize;
|
|
WCHAR * pszDeviceIdList = NULL;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
|
|
DPRINT("PNP_AddID(%p %S %S 0x%08lx)\n",
|
|
hBinding, pszDeviceID, pszID, ulFlags);
|
|
|
|
if (RegOpenKeyExW(hEnumKey,
|
|
pszDeviceID,
|
|
0,
|
|
KEY_QUERY_VALUE | KEY_SET_VALUE,
|
|
&hDeviceKey) != ERROR_SUCCESS)
|
|
{
|
|
DPRINT("Failed to open the device key!\n");
|
|
return CR_INVALID_DEVNODE;
|
|
}
|
|
|
|
pszSubKey = (ulFlags & CM_ADD_ID_COMPATIBLE) ? L"CompatibleIDs" : L"HardwareID";
|
|
|
|
if (RegQueryValueExW(hDeviceKey,
|
|
pszSubKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&dwDeviceIdListSize) != ERROR_SUCCESS)
|
|
{
|
|
DPRINT("Failed to query the desired ID string!\n");
|
|
ret = CR_REGISTRY_ERROR;
|
|
goto Done;
|
|
}
|
|
|
|
dwNewDeviceIdSize = lstrlenW(pszDeviceID);
|
|
if (!dwNewDeviceIdSize)
|
|
{
|
|
ret = CR_INVALID_POINTER;
|
|
goto Done;
|
|
}
|
|
|
|
dwDeviceIdListSize += (dwNewDeviceIdSize + 2) * sizeof(WCHAR);
|
|
|
|
pszDeviceIdList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDeviceIdListSize);
|
|
if (!pszDeviceIdList)
|
|
{
|
|
DPRINT("Failed to allocate memory for the desired ID string!\n");
|
|
ret = CR_OUT_OF_MEMORY;
|
|
goto Done;
|
|
}
|
|
|
|
if (RegQueryValueExW(hDeviceKey,
|
|
pszSubKey,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)pszDeviceIdList,
|
|
&dwDeviceIdListSize) != ERROR_SUCCESS)
|
|
{
|
|
DPRINT("Failed to query the desired ID string!\n");
|
|
ret = CR_REGISTRY_ERROR;
|
|
goto Done;
|
|
}
|
|
|
|
/* Check whether the device ID is already in use */
|
|
if (CheckForDeviceId(pszDeviceIdList, pszDeviceID))
|
|
{
|
|
DPRINT("Device ID was found in the ID string!\n");
|
|
ret = CR_SUCCESS;
|
|
goto Done;
|
|
}
|
|
|
|
/* Append the Device ID */
|
|
AppendDeviceId(pszDeviceIdList, &dwDeviceIdListSize, pszID);
|
|
|
|
if (RegSetValueExW(hDeviceKey,
|
|
pszSubKey,
|
|
0,
|
|
REG_MULTI_SZ,
|
|
(LPBYTE)pszDeviceIdList,
|
|
dwDeviceIdListSize) != ERROR_SUCCESS)
|
|
{
|
|
DPRINT("Failed to set the desired ID string!\n");
|
|
ret = CR_REGISTRY_ERROR;
|
|
}
|
|
|
|
Done:
|
|
RegCloseKey(hDeviceKey);
|
|
if (pszDeviceIdList)
|
|
HeapFree(GetProcessHeap(), 0, pszDeviceIdList);
|
|
|
|
DPRINT("PNP_AddID() done (returns %lx)\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 35 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_RegisterDriver(
|
|
handle_t hBinding,
|
|
LPWSTR pszDeviceID,
|
|
DWORD ulFlags)
|
|
{
|
|
DPRINT("PNP_RegisterDriver(%p %S 0x%lx)\n",
|
|
hBinding, pszDeviceID, ulFlags);
|
|
|
|
if (ulFlags & ~CM_REGISTER_DEVICE_DRIVER_BITS)
|
|
return CR_INVALID_FLAG;
|
|
|
|
if (!IsValidDeviceInstanceID(pszDeviceID))
|
|
return CR_INVALID_DEVINST;
|
|
|
|
SetDeviceStatus(pszDeviceID, 0, 0);
|
|
|
|
return CR_SUCCESS;
|
|
}
|
|
|
|
|
|
/* Function 36 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_QueryRemove(
|
|
handle_t hBinding,
|
|
LPWSTR pszDeviceID,
|
|
PPNP_VETO_TYPE pVetoType,
|
|
LPWSTR pszVetoName,
|
|
DWORD ulNameLength,
|
|
DWORD ulFlags)
|
|
{
|
|
PLUGPLAY_CONTROL_QUERY_REMOVE_DATA PlugPlayData;
|
|
NTSTATUS Status;
|
|
DWORD ret = CR_SUCCESS;
|
|
|
|
DPRINT1("PNP_QueryRemove(%p %S %p %p %lu 0x%lx)\n",
|
|
hBinding, pszDeviceID, pVetoType, pszVetoName,
|
|
ulNameLength, ulFlags);
|
|
|
|
if (ulFlags & ~CM_REMOVE_BITS)
|
|
return CR_INVALID_FLAG;
|
|
|
|
if (!IsValidDeviceInstanceID(pszDeviceID) ||
|
|
IsRootDeviceInstanceID(pszDeviceID))
|
|
return CR_INVALID_DEVINST;
|
|
|
|
if (pVetoType != NULL)
|
|
*pVetoType = PNP_VetoTypeUnknown;
|
|
|
|
if (pszVetoName != NULL && ulNameLength > 0)
|
|
*pszVetoName = UNICODE_NULL;
|
|
|
|
RtlZeroMemory(&PlugPlayData, sizeof(PlugPlayData));
|
|
RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
|
|
pszDeviceID);
|
|
PlugPlayData.VetoName = pszVetoName;
|
|
PlugPlayData.NameLength = ulNameLength;
|
|
// PlugPlayData.Flags =
|
|
|
|
Status = NtPlugPlayControl(PlugPlayControlQueryAndRemoveDevice,
|
|
&PlugPlayData,
|
|
sizeof(PlugPlayData));
|
|
if (!NT_SUCCESS(Status))
|
|
ret = NtStatusToCrError(Status);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 37 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_RequestDeviceEject(
|
|
handle_t hBinding,
|
|
LPWSTR pszDeviceID,
|
|
PPNP_VETO_TYPE pVetoType,
|
|
LPWSTR pszVetoName,
|
|
DWORD ulNameLength,
|
|
DWORD ulFlags)
|
|
{
|
|
PLUGPLAY_CONTROL_QUERY_REMOVE_DATA PlugPlayData;
|
|
NTSTATUS Status;
|
|
DWORD ret = CR_SUCCESS;
|
|
|
|
DPRINT1("PNP_RequestDeviceEject(%p %S %p %p %lu 0x%lx)\n",
|
|
hBinding, pszDeviceID, pVetoType, pszVetoName,
|
|
ulNameLength, ulFlags);
|
|
|
|
if (ulFlags != 0)
|
|
return CR_INVALID_FLAG;
|
|
|
|
if (!IsValidDeviceInstanceID(pszDeviceID))
|
|
return CR_INVALID_DEVINST;
|
|
|
|
if (pVetoType != NULL)
|
|
*pVetoType = PNP_VetoTypeUnknown;
|
|
|
|
if (pszVetoName != NULL && ulNameLength > 0)
|
|
*pszVetoName = UNICODE_NULL;
|
|
|
|
RtlZeroMemory(&PlugPlayData, sizeof(PlugPlayData));
|
|
RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
|
|
pszDeviceID);
|
|
PlugPlayData.VetoName = pszVetoName;
|
|
PlugPlayData.NameLength = ulNameLength;
|
|
// PlugPlayData.Flags =
|
|
|
|
Status = NtPlugPlayControl(PlugPlayControlQueryAndRemoveDevice,
|
|
&PlugPlayData,
|
|
sizeof(PlugPlayData));
|
|
if (!NT_SUCCESS(Status))
|
|
ret = NtStatusToCrError(Status);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 38 */
|
|
CONFIGRET
|
|
WINAPI
|
|
PNP_IsDockStationPresent(
|
|
handle_t hBinding,
|
|
BOOL *Present)
|
|
{
|
|
HKEY hKey;
|
|
DWORD dwType;
|
|
DWORD dwValue;
|
|
DWORD dwSize;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
|
|
DPRINT1("PNP_IsDockStationPresent(%p %p)\n",
|
|
hBinding, Present);
|
|
|
|
*Present = FALSE;
|
|
|
|
if (RegOpenKeyExW(HKEY_CURRENT_CONFIG,
|
|
L"CurrentDockInfo",
|
|
0,
|
|
KEY_READ,
|
|
&hKey) != ERROR_SUCCESS)
|
|
return CR_REGISTRY_ERROR;
|
|
|
|
dwSize = sizeof(DWORD);
|
|
if (RegQueryValueExW(hKey,
|
|
L"DockingState",
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)&dwValue,
|
|
&dwSize) != ERROR_SUCCESS)
|
|
ret = CR_REGISTRY_ERROR;
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
if (ret == CR_SUCCESS)
|
|
{
|
|
if (dwType != REG_DWORD || dwSize != sizeof(DWORD))
|
|
{
|
|
ret = CR_REGISTRY_ERROR;
|
|
}
|
|
else if (dwValue != 0)
|
|
{
|
|
*Present = TRUE;
|
|
}
|
|
}
|
|
|
|
DPRINT1("PNP_IsDockStationPresent() done (returns %lx)\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 39 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_RequestEjectPC(
|
|
handle_t hBinding)
|
|
{
|
|
WCHAR szDockDeviceInstance[MAX_DEVICE_ID_LEN];
|
|
PLUGPLAY_CONTROL_RETRIEVE_DOCK_DATA DockData;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("PNP_RequestEjectPC(%p)\n", hBinding);
|
|
|
|
/* Retrieve the dock device */
|
|
DockData.DeviceInstanceLength = ARRAYSIZE(szDockDeviceInstance);
|
|
DockData.DeviceInstance = szDockDeviceInstance;
|
|
|
|
Status = NtPlugPlayControl(PlugPlayControlRetrieveDock,
|
|
&DockData,
|
|
sizeof(DockData));
|
|
if (!NT_SUCCESS(Status))
|
|
return NtStatusToCrError(Status);
|
|
|
|
/* Eject the dock device */
|
|
return PNP_RequestDeviceEject(hBinding,
|
|
szDockDeviceInstance,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
0);
|
|
}
|
|
|
|
|
|
/* Function 40 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_HwProfFlags(
|
|
handle_t hBinding,
|
|
DWORD ulAction,
|
|
LPWSTR pDeviceID,
|
|
DWORD ulConfig,
|
|
DWORD *pulValue,
|
|
PPNP_VETO_TYPE pVetoType,
|
|
LPWSTR pszVetoName,
|
|
DWORD ulNameLength,
|
|
DWORD ulFlags)
|
|
{
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
WCHAR szKeyName[MAX_PATH];
|
|
HKEY hKey;
|
|
HKEY hDeviceKey;
|
|
DWORD dwSize;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
|
|
DPRINT("PNP_HwProfFlags() called\n");
|
|
|
|
if (!IsValidDeviceInstanceID(pDeviceID))
|
|
return CR_INVALID_DEVINST;
|
|
|
|
if (ulConfig == 0)
|
|
{
|
|
wcscpy(szKeyName,
|
|
L"System\\CurrentControlSet\\HardwareProfiles\\Current\\System\\CurrentControlSet\\Enum");
|
|
}
|
|
else
|
|
{
|
|
swprintf(szKeyName,
|
|
L"System\\CurrentControlSet\\HardwareProfiles\\%04lu\\System\\CurrentControlSet\\Enum",
|
|
ulConfig);
|
|
}
|
|
|
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
szKeyName,
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hKey) != ERROR_SUCCESS)
|
|
return CR_REGISTRY_ERROR;
|
|
|
|
if (ulAction == PNP_GET_HWPROFFLAGS)
|
|
{
|
|
if (RegOpenKeyExW(hKey,
|
|
pDeviceID,
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hDeviceKey) != ERROR_SUCCESS)
|
|
{
|
|
*pulValue = 0;
|
|
}
|
|
else
|
|
{
|
|
dwSize = sizeof(DWORD);
|
|
if (RegQueryValueExW(hDeviceKey,
|
|
L"CSConfigFlags",
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)pulValue,
|
|
&dwSize) != ERROR_SUCCESS)
|
|
{
|
|
*pulValue = 0;
|
|
}
|
|
|
|
RegCloseKey(hDeviceKey);
|
|
}
|
|
}
|
|
else if (ulAction == PNP_SET_HWPROFFLAGS)
|
|
{
|
|
/* FIXME: not implemented yet */
|
|
ret = CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 41 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetHwProfInfo(
|
|
handle_t hBinding,
|
|
DWORD ulIndex,
|
|
HWPROFILEINFO *pHWProfileInfo,
|
|
DWORD ulProfileInfoSize,
|
|
DWORD ulFlags)
|
|
{
|
|
WCHAR szProfileName[5];
|
|
HKEY hKeyConfig = NULL;
|
|
HKEY hKeyProfiles = NULL;
|
|
HKEY hKeyProfile = NULL;
|
|
DWORD dwDisposition;
|
|
DWORD dwSize;
|
|
LONG lError;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
|
|
DPRINT("PNP_GetHwProfInfo() called\n");
|
|
|
|
if (ulProfileInfoSize == 0)
|
|
{
|
|
ret = CR_INVALID_DATA;
|
|
goto done;
|
|
}
|
|
|
|
if (ulFlags != 0)
|
|
{
|
|
ret = CR_INVALID_FLAG;
|
|
goto done;
|
|
}
|
|
|
|
/* Initialize the profile information */
|
|
pHWProfileInfo->HWPI_ulHWProfile = 0;
|
|
pHWProfileInfo->HWPI_szFriendlyName[0] = 0;
|
|
pHWProfileInfo->HWPI_dwFlags = 0;
|
|
|
|
/* Open the 'IDConfigDB' key */
|
|
lError = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
|
|
L"System\\CurrentControlSet\\Control\\IDConfigDB",
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_QUERY_VALUE,
|
|
NULL,
|
|
&hKeyConfig,
|
|
&dwDisposition);
|
|
if (lError != ERROR_SUCCESS)
|
|
{
|
|
ret = CR_REGISTRY_ERROR;
|
|
goto done;
|
|
}
|
|
|
|
/* Open the 'Hardware Profiles' subkey */
|
|
lError = RegCreateKeyExW(hKeyConfig,
|
|
L"Hardware Profiles",
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
|
|
NULL,
|
|
&hKeyProfiles,
|
|
&dwDisposition);
|
|
if (lError != ERROR_SUCCESS)
|
|
{
|
|
ret = CR_REGISTRY_ERROR;
|
|
goto done;
|
|
}
|
|
|
|
if (ulIndex == (ULONG)-1)
|
|
{
|
|
dwSize = sizeof(ULONG);
|
|
lError = RegQueryValueExW(hKeyConfig,
|
|
L"CurrentConfig",
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)&pHWProfileInfo->HWPI_ulHWProfile,
|
|
&dwSize);
|
|
if (lError != ERROR_SUCCESS)
|
|
{
|
|
pHWProfileInfo->HWPI_ulHWProfile = 0;
|
|
ret = CR_REGISTRY_ERROR;
|
|
goto done;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* FIXME: not implemented yet */
|
|
ret = CR_CALL_NOT_IMPLEMENTED;
|
|
goto done;
|
|
}
|
|
|
|
swprintf(szProfileName, L"%04lu", pHWProfileInfo->HWPI_ulHWProfile);
|
|
|
|
lError = RegOpenKeyExW(hKeyProfiles,
|
|
szProfileName,
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hKeyProfile);
|
|
if (lError != ERROR_SUCCESS)
|
|
{
|
|
ret = CR_REGISTRY_ERROR;
|
|
goto done;
|
|
}
|
|
|
|
dwSize = sizeof(pHWProfileInfo->HWPI_szFriendlyName);
|
|
lError = RegQueryValueExW(hKeyProfile,
|
|
L"FriendlyName",
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)&pHWProfileInfo->HWPI_szFriendlyName,
|
|
&dwSize);
|
|
if (lError != ERROR_SUCCESS)
|
|
{
|
|
ret = CR_REGISTRY_ERROR;
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
if (hKeyProfile != NULL)
|
|
RegCloseKey(hKeyProfile);
|
|
|
|
if (hKeyProfiles != NULL)
|
|
RegCloseKey(hKeyProfiles);
|
|
|
|
if (hKeyConfig != NULL)
|
|
RegCloseKey(hKeyConfig);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 42 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_AddEmptyLogConf(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceID,
|
|
DWORD ulPriority,
|
|
DWORD *pulLogConfTag,
|
|
DWORD ulFlags)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 43 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_FreeLogConf(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceID,
|
|
DWORD ulLogConfType,
|
|
DWORD ulLogConfTag,
|
|
DWORD ulFlags)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 44 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetFirstLogConf(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceID,
|
|
DWORD ulLogConfType,
|
|
DWORD *pulLogConfTag,
|
|
DWORD ulFlags)
|
|
{
|
|
HKEY hConfigKey = NULL;
|
|
DWORD RegDataType = 0;
|
|
ULONG ulDataSize = 0;
|
|
LPBYTE lpData = NULL;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
DPRINT("PNP_GetFirstLogConf(%p %S %lu %p 0x%08lx)\n",
|
|
hBinding, pDeviceID, ulLogConfType, pulLogConfTag, ulFlags);
|
|
|
|
if (pulLogConfTag == NULL)
|
|
return CR_INVALID_POINTER;
|
|
|
|
*pulLogConfTag = (DWORD)0;
|
|
|
|
if (ulFlags & ~LOG_CONF_BITS)
|
|
return CR_INVALID_FLAG;
|
|
|
|
if (!IsValidDeviceInstanceID(pDeviceID))
|
|
return CR_INVALID_DEVINST;
|
|
|
|
ret = OpenConfigurationKey(pDeviceID,
|
|
ulLogConfType,
|
|
&hConfigKey);
|
|
if (ret != CR_SUCCESS)
|
|
{
|
|
DPRINT1("OpenConfigurationKey() failed (Error %lu)\n", ret);
|
|
ret = CR_NO_MORE_LOG_CONF;
|
|
goto done;
|
|
}
|
|
|
|
ret = GetConfigurationData(hConfigKey,
|
|
ulLogConfType,
|
|
&RegDataType,
|
|
&ulDataSize,
|
|
&lpData);
|
|
if (ret != CR_SUCCESS)
|
|
{
|
|
DPRINT1("GetConfigurationData() failed (Error %lu)\n", ret);
|
|
ret = CR_NO_MORE_LOG_CONF;
|
|
goto done;
|
|
}
|
|
|
|
DPRINT1("Data size %lu\n", ulDataSize);
|
|
if (ulDataSize == 0 || lpData == NULL)
|
|
{
|
|
DPRINT1("No config data available!\n");
|
|
ret = CR_NO_MORE_LOG_CONF;
|
|
goto done;
|
|
}
|
|
|
|
/* Get the first tag */
|
|
if (RegDataType == REG_RESOURCE_LIST)
|
|
{
|
|
DPRINT("REG_RESOURCE_LIST->Count %lu\n", ((PCM_RESOURCE_LIST)lpData)->Count);
|
|
|
|
/* Fail, if we do not have any resource */
|
|
if (((PCM_RESOURCE_LIST)lpData)->Count == 0)
|
|
{
|
|
DPRINT1("No resource descriptors!\n");
|
|
ret = CR_NO_MORE_LOG_CONF;
|
|
goto done;
|
|
}
|
|
}
|
|
else if (RegDataType == REG_RESOURCE_REQUIREMENTS_LIST)
|
|
{
|
|
DPRINT("REG_RESOURCE_REQUIREMENTS_LIST->AlternativeLists %lu\n",
|
|
((PIO_RESOURCE_REQUIREMENTS_LIST)lpData)->AlternativeLists);
|
|
|
|
/* Fail, if we do not have any requirements */
|
|
if (((PIO_RESOURCE_REQUIREMENTS_LIST)lpData)->AlternativeLists == 0)
|
|
{
|
|
ret = CR_NO_MORE_LOG_CONF;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
done:
|
|
if (lpData != NULL)
|
|
HeapFree(GetProcessHeap(), 0, lpData);
|
|
|
|
if (hConfigKey != NULL)
|
|
RegCloseKey(hConfigKey);
|
|
|
|
DPRINT("PNP_GetFirstLogConf() returns %lu\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 45 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetNextLogConf(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceID,
|
|
DWORD ulLogConfType,
|
|
DWORD ulCurrentTag,
|
|
DWORD *pulNextTag,
|
|
DWORD ulFlags)
|
|
{
|
|
HKEY hConfigKey = NULL;
|
|
DWORD RegDataType = 0;
|
|
ULONG ulDataSize = 0;
|
|
LPBYTE lpData = NULL;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
DPRINT("PNP_GetNextLogConf(%p %S %lu %ul %p 0x%08lx)\n",
|
|
hBinding, pDeviceID, ulLogConfType, ulCurrentTag, pulNextTag, ulFlags);
|
|
|
|
if (pulNextTag == NULL)
|
|
return CR_INVALID_POINTER;
|
|
|
|
*pulNextTag = (DWORD)0;
|
|
|
|
if (ulFlags != 0)
|
|
return CR_INVALID_FLAG;
|
|
|
|
if (!IsValidDeviceInstanceID(pDeviceID))
|
|
return CR_INVALID_DEVINST;
|
|
|
|
ret = OpenConfigurationKey(pDeviceID,
|
|
ulLogConfType,
|
|
&hConfigKey);
|
|
if (ret != CR_SUCCESS)
|
|
{
|
|
DPRINT1("OpenConfigurationKey() failed (Error %lu)\n", ret);
|
|
ret = CR_NO_MORE_LOG_CONF;
|
|
goto done;
|
|
}
|
|
|
|
ret = GetConfigurationData(hConfigKey,
|
|
ulLogConfType,
|
|
&RegDataType,
|
|
&ulDataSize,
|
|
&lpData);
|
|
if (ret != CR_SUCCESS)
|
|
{
|
|
DPRINT1("GetConfigurationData() failed (Error %lu)\n", ret);
|
|
ret = CR_NO_MORE_LOG_CONF;
|
|
goto done;
|
|
}
|
|
|
|
DPRINT("Data size %lu\n", ulDataSize);
|
|
|
|
if (ulDataSize == 0 || lpData == NULL)
|
|
{
|
|
DPRINT1("No config data available!\n");
|
|
ret = CR_NO_MORE_LOG_CONF;
|
|
goto done;
|
|
}
|
|
|
|
/* Check if the next entry is available */
|
|
if (RegDataType == REG_RESOURCE_LIST)
|
|
{
|
|
DPRINT("REG_RESOURCE_LIST->Count %lu\n", ((PCM_RESOURCE_LIST)lpData)->Count);
|
|
|
|
/* Fail, if we are beyond the end of the list */
|
|
if (ulCurrentTag >= ((PCM_RESOURCE_LIST)lpData)->Count)
|
|
{
|
|
ret = CR_INVALID_LOG_CONF;
|
|
goto done;
|
|
}
|
|
|
|
/* Indicate that we reached the end of the list */
|
|
if (ulCurrentTag == ((PCM_RESOURCE_LIST)lpData)->Count - 1)
|
|
{
|
|
ret = CR_NO_MORE_LOG_CONF;
|
|
goto done;
|
|
}
|
|
}
|
|
else if (RegDataType == REG_RESOURCE_REQUIREMENTS_LIST)
|
|
{
|
|
DPRINT("REG_RESOURCE_REQUIREMENTS_LIST->AlternativeLists %lu\n",
|
|
((PIO_RESOURCE_REQUIREMENTS_LIST)lpData)->AlternativeLists);
|
|
|
|
/* Fail, if we are beyond the end of the list */
|
|
if (ulCurrentTag >= ((PIO_RESOURCE_REQUIREMENTS_LIST)lpData)->AlternativeLists)
|
|
{
|
|
ret = CR_INVALID_LOG_CONF;
|
|
goto done;
|
|
}
|
|
|
|
/* Indicate that we reached the end of the list */
|
|
if (ulCurrentTag == ((PIO_RESOURCE_REQUIREMENTS_LIST)lpData)->AlternativeLists - 1)
|
|
{
|
|
ret = CR_NO_MORE_LOG_CONF;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
/* Return the next tag value */
|
|
*pulNextTag = ulCurrentTag + 1;
|
|
|
|
done:
|
|
if (lpData != NULL)
|
|
HeapFree(GetProcessHeap(), 0, lpData);
|
|
|
|
if (hConfigKey != NULL)
|
|
RegCloseKey(hConfigKey);
|
|
|
|
DPRINT("PNP_GetNextLogConf() returns %lu\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 46 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetLogConfPriority(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceID,
|
|
DWORD ulType,
|
|
DWORD ulTag,
|
|
DWORD *pPriority,
|
|
DWORD ulFlags)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 47 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_AddResDes(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceID,
|
|
DWORD ulLogConfTag,
|
|
DWORD ulLogConfType,
|
|
RESOURCEID ResourceID,
|
|
DWORD *pulResourceTag,
|
|
BYTE *ResourceData,
|
|
PNP_RPC_BUFFER_SIZE ResourceLen,
|
|
DWORD ulFlags)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 48 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_FreeResDes(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceID,
|
|
DWORD ulLogConfTag,
|
|
DWORD ulLogConfType,
|
|
RESOURCEID ResourceID,
|
|
DWORD ulResourceTag,
|
|
DWORD *pulPreviousResType,
|
|
DWORD *pulPreviousResTag,
|
|
DWORD ulFlags)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 49 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetNextResDes(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceID,
|
|
DWORD ulLogConfTag,
|
|
DWORD ulLogConfType,
|
|
RESOURCEID ResourceID,
|
|
DWORD ulResourceTag,
|
|
DWORD *pulNextResType,
|
|
DWORD *pulNextResTag,
|
|
DWORD ulFlags)
|
|
{
|
|
HKEY hConfigKey = NULL;
|
|
DWORD RegDataType = 0;
|
|
ULONG ulDataSize = 0;
|
|
LPBYTE lpData = NULL;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
DPRINT1("PNP_GetNextResDes(%p %S 0x%lx %lu %lu %ul %p %p 0x%08lx)\n",
|
|
hBinding, pDeviceID, ulLogConfTag, ulLogConfType, ResourceID,
|
|
ulResourceTag, pulNextResType, pulNextResTag, ulFlags);
|
|
|
|
if (pulNextResType == NULL)
|
|
return CR_INVALID_POINTER;
|
|
|
|
*pulNextResType = 0;
|
|
|
|
if (ulFlags != 0)
|
|
return CR_INVALID_FLAG;
|
|
|
|
if (!IsValidDeviceInstanceID(pDeviceID))
|
|
return CR_INVALID_DEVINST;
|
|
|
|
ret = OpenConfigurationKey(pDeviceID,
|
|
ulLogConfType,
|
|
&hConfigKey);
|
|
if (ret != CR_SUCCESS)
|
|
{
|
|
DPRINT1("OpenConfigurationKey() failed (Error %lu)\n", ret);
|
|
ret = CR_NO_MORE_LOG_CONF;
|
|
goto done;
|
|
}
|
|
|
|
ret = GetConfigurationData(hConfigKey,
|
|
ulLogConfType,
|
|
&RegDataType,
|
|
&ulDataSize,
|
|
&lpData);
|
|
if (ret != CR_SUCCESS)
|
|
{
|
|
DPRINT1("GetConfigurationData() failed (Error %lu)\n", ret);
|
|
ret = CR_NO_MORE_LOG_CONF;
|
|
goto done;
|
|
}
|
|
|
|
DPRINT1("Data size %lu\n", ulDataSize);
|
|
|
|
if (ulDataSize == 0 || lpData == NULL)
|
|
{
|
|
DPRINT1("No config data available!\n");
|
|
ret = CR_NO_MORE_LOG_CONF;
|
|
goto done;
|
|
}
|
|
|
|
/* Get the next resource descriptor */
|
|
if (RegDataType == REG_RESOURCE_LIST)
|
|
{
|
|
DPRINT1("FIXME: REG_RESOURCE_LIST\n");
|
|
/* FIXME */
|
|
ret = CR_NO_MORE_LOG_CONF;
|
|
goto done;
|
|
}
|
|
else if (RegDataType == REG_RESOURCE_REQUIREMENTS_LIST)
|
|
{
|
|
DPRINT1("FIXME: REG_RESOURCE_REQUIREMENTS_LIST\n");
|
|
/* FIXME */
|
|
ret = CR_NO_MORE_LOG_CONF;
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
if (lpData != NULL)
|
|
HeapFree(GetProcessHeap(), 0, lpData);
|
|
|
|
if (hConfigKey != NULL)
|
|
RegCloseKey(hConfigKey);
|
|
|
|
DPRINT1("PNP_GetNextResDes() returns %lu\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 50 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetResDesData(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceID,
|
|
DWORD ulLogConfTag,
|
|
DWORD ulLogConfType,
|
|
RESOURCEID ResourceID,
|
|
DWORD ulResourceTag,
|
|
BYTE *Buffer,
|
|
PNP_RPC_BUFFER_SIZE BufferLen,
|
|
DWORD ulFlags)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 51 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetResDesDataSize(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceID,
|
|
DWORD ulLogConfTag,
|
|
DWORD ulLogConfType,
|
|
RESOURCEID ResourceID,
|
|
DWORD ulResourceTag,
|
|
DWORD *pulSize,
|
|
DWORD ulFlags)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 52 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_ModifyResDes(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceID,
|
|
DWORD ulLogConfTag,
|
|
DWORD ulLogConfType,
|
|
RESOURCEID CurrentResourceID,
|
|
RESOURCEID NewResourceID,
|
|
DWORD ulResourceTag,
|
|
BYTE *ResourceData,
|
|
PNP_RPC_BUFFER_SIZE ResourceLen,
|
|
DWORD ulFlags)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 53 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_DetectResourceConflict(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceID,
|
|
RESOURCEID ResourceID,
|
|
BYTE *ResourceData,
|
|
PNP_RPC_BUFFER_SIZE ResourceLen,
|
|
BOOL *pbConflictDetected,
|
|
DWORD ulFlags)
|
|
{
|
|
DPRINT("PNP_DetectResourceConflict()\n");
|
|
|
|
if (pbConflictDetected != NULL)
|
|
*pbConflictDetected = FALSE;
|
|
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 54 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_QueryResConfList(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceID,
|
|
RESOURCEID ResourceID,
|
|
BYTE *ResourceData,
|
|
PNP_RPC_BUFFER_SIZE ResourceLen,
|
|
BYTE *Buffer,
|
|
PNP_RPC_BUFFER_SIZE BufferLen,
|
|
DWORD ulFlags)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 55 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_SetHwProf(
|
|
handle_t hBinding,
|
|
DWORD ulHardwareProfile,
|
|
DWORD ulFlags)
|
|
{
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 56 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_QueryArbitratorFreeData(
|
|
handle_t hBinding,
|
|
BYTE *pData,
|
|
DWORD DataLen,
|
|
LPWSTR pDeviceID,
|
|
RESOURCEID ResourceID,
|
|
DWORD ulFlags)
|
|
{
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 57 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_QueryArbitratorFreeSize(
|
|
handle_t hBinding,
|
|
DWORD *pulSize,
|
|
LPWSTR pDeviceID,
|
|
RESOURCEID ResourceID,
|
|
DWORD ulFlags)
|
|
{
|
|
if (pulSize != NULL)
|
|
*pulSize = 0;
|
|
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 58 */
|
|
CONFIGRET
|
|
WINAPI
|
|
PNP_RunDetection(
|
|
handle_t hBinding,
|
|
DWORD ulFlags)
|
|
{
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 59 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_RegisterNotification(
|
|
handle_t hBinding,
|
|
DWORD_PTR hRecipient,
|
|
LPWSTR pszName,
|
|
BYTE *pNotificationFilter,
|
|
DWORD ulNotificationFilterSize,
|
|
DWORD ulFlags,
|
|
PNP_NOTIFY_HANDLE *pNotifyHandle,
|
|
DWORD ulProcessId,
|
|
DWORD *pulUnknown9)
|
|
{
|
|
PDEV_BROADCAST_DEVICEINTERFACE_W pBroadcastDeviceInterface;
|
|
PDEV_BROADCAST_HANDLE pBroadcastDeviceHandle;
|
|
PNOTIFY_ENTRY pNotifyData = NULL;
|
|
|
|
DPRINT1("PNP_RegisterNotification(%p %p '%S' %p %lu 0x%lx %p %lx %p)\n",
|
|
hBinding, hRecipient, pszName, pNotificationFilter,
|
|
ulNotificationFilterSize, ulFlags, pNotifyHandle, ulProcessId, pulUnknown9);
|
|
|
|
if (pNotifyHandle == NULL)
|
|
return CR_INVALID_POINTER;
|
|
|
|
*pNotifyHandle = NULL;
|
|
|
|
if (pNotificationFilter == NULL ||
|
|
pulUnknown9 == NULL)
|
|
return CR_INVALID_POINTER;
|
|
|
|
if (ulFlags & ~0x7)
|
|
return CR_INVALID_FLAG;
|
|
|
|
if ((ulNotificationFilterSize < sizeof(DEV_BROADCAST_HDR)) ||
|
|
(((PDEV_BROADCAST_HDR)pNotificationFilter)->dbch_size < sizeof(DEV_BROADCAST_HDR)))
|
|
return CR_INVALID_DATA;
|
|
|
|
if (((PDEV_BROADCAST_HDR)pNotificationFilter)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
|
|
{
|
|
DPRINT1("DBT_DEVTYP_DEVICEINTERFACE\n");
|
|
pBroadcastDeviceInterface = (PDEV_BROADCAST_DEVICEINTERFACE_W)pNotificationFilter;
|
|
|
|
if ((ulNotificationFilterSize < sizeof(DEV_BROADCAST_DEVICEINTERFACE_W)) ||
|
|
(pBroadcastDeviceInterface->dbcc_size < sizeof(DEV_BROADCAST_DEVICEINTERFACE_W)))
|
|
return CR_INVALID_DATA;
|
|
|
|
pNotifyData = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NOTIFY_ENTRY));
|
|
if (pNotifyData == NULL)
|
|
return CR_OUT_OF_MEMORY;
|
|
|
|
if (pszName != NULL)
|
|
{
|
|
pNotifyData->pszName = RtlAllocateHeap(GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
(wcslen(pszName) + 1) * sizeof(WCHAR));
|
|
if (pNotifyData->pszName == NULL)
|
|
{
|
|
RtlFreeHeap(GetProcessHeap(), 0, pNotifyData);
|
|
return CR_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
|
|
/* Add the entry to the notification list */
|
|
InsertTailList(&NotificationListHead, &pNotifyData->ListEntry);
|
|
|
|
DPRINT("pNotifyData: %p\n", pNotifyData);
|
|
*pNotifyHandle = (PNP_NOTIFY_HANDLE)pNotifyData;
|
|
}
|
|
else if (((PDEV_BROADCAST_HDR)pNotificationFilter)->dbch_devicetype == DBT_DEVTYP_HANDLE)
|
|
{
|
|
DPRINT1("DBT_DEVTYP_HANDLE\n");
|
|
pBroadcastDeviceHandle = (PDEV_BROADCAST_HANDLE)pNotificationFilter;
|
|
|
|
if ((ulNotificationFilterSize < sizeof(DEV_BROADCAST_HANDLE)) ||
|
|
(pBroadcastDeviceHandle->dbch_size < sizeof(DEV_BROADCAST_HANDLE)))
|
|
return CR_INVALID_DATA;
|
|
|
|
if (ulFlags & DEVICE_NOTIFY_ALL_INTERFACE_CLASSES)
|
|
return CR_INVALID_FLAG;
|
|
}
|
|
else
|
|
{
|
|
DPRINT1("Invalid device type %lu\n", ((PDEV_BROADCAST_HDR)pNotificationFilter)->dbch_devicetype);
|
|
return CR_INVALID_DATA;
|
|
}
|
|
|
|
return CR_SUCCESS;
|
|
}
|
|
|
|
|
|
/* Function 60 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_UnregisterNotification(
|
|
handle_t hBinding,
|
|
PNP_NOTIFY_HANDLE *pNotifyHandle)
|
|
{
|
|
PNOTIFY_ENTRY pEntry;
|
|
|
|
DPRINT1("PNP_UnregisterNotification(%p %p)\n",
|
|
hBinding, pNotifyHandle);
|
|
|
|
pEntry = (PNOTIFY_ENTRY)*pNotifyHandle;
|
|
if (pEntry == NULL)
|
|
return CR_INVALID_DATA;
|
|
|
|
RemoveEntryList(&pEntry->ListEntry);
|
|
if (pEntry->pszName)
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, pEntry->pszName);
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, pEntry);
|
|
*pNotifyHandle = NULL;
|
|
|
|
return CR_SUCCESS;
|
|
}
|
|
|
|
|
|
/* Function 61 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetCustomDevProp(
|
|
handle_t hBinding,
|
|
LPWSTR pDeviceID,
|
|
LPWSTR CustomPropName,
|
|
DWORD *pulRegDataType,
|
|
BYTE *Buffer,
|
|
PNP_RPC_STRING_LEN *pulTransferLen,
|
|
PNP_RPC_STRING_LEN *pulLength,
|
|
DWORD ulFlags)
|
|
{
|
|
HKEY hDeviceKey = NULL;
|
|
HKEY hParamKey = NULL;
|
|
LONG lError;
|
|
CONFIGRET ret = CR_SUCCESS;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
|
|
DPRINT("PNP_GetCustomDevProp() called\n");
|
|
|
|
if (pulTransferLen == NULL || pulLength == NULL)
|
|
{
|
|
ret = CR_INVALID_POINTER;
|
|
goto done;
|
|
}
|
|
|
|
if (ulFlags & ~CM_CUSTOMDEVPROP_BITS)
|
|
{
|
|
ret = CR_INVALID_FLAG;
|
|
goto done;
|
|
}
|
|
|
|
if (!IsValidDeviceInstanceID(pDeviceID))
|
|
return CR_INVALID_DEVINST;
|
|
|
|
if (*pulLength < *pulTransferLen)
|
|
*pulLength = *pulTransferLen;
|
|
|
|
*pulTransferLen = 0;
|
|
|
|
lError = RegOpenKeyExW(hEnumKey,
|
|
pDeviceID,
|
|
0,
|
|
KEY_READ,
|
|
&hDeviceKey);
|
|
if (lError != ERROR_SUCCESS)
|
|
{
|
|
ret = CR_REGISTRY_ERROR;
|
|
goto done;
|
|
}
|
|
|
|
lError = RegOpenKeyExW(hDeviceKey,
|
|
L"Device Parameters",
|
|
0,
|
|
KEY_READ,
|
|
&hParamKey);
|
|
if (lError != ERROR_SUCCESS)
|
|
{
|
|
ret = CR_REGISTRY_ERROR;
|
|
goto done;
|
|
}
|
|
|
|
lError = RegQueryValueExW(hParamKey,
|
|
CustomPropName,
|
|
NULL,
|
|
pulRegDataType,
|
|
Buffer,
|
|
pulLength);
|
|
if (lError != ERROR_SUCCESS)
|
|
{
|
|
if (lError == ERROR_MORE_DATA)
|
|
{
|
|
ret = CR_BUFFER_SMALL;
|
|
}
|
|
else
|
|
{
|
|
*pulLength = 0;
|
|
ret = CR_NO_SUCH_VALUE;
|
|
}
|
|
}
|
|
|
|
done:
|
|
if (ret == CR_SUCCESS)
|
|
*pulTransferLen = *pulLength;
|
|
|
|
if (hParamKey != NULL)
|
|
RegCloseKey(hParamKey);
|
|
|
|
if (hDeviceKey != NULL)
|
|
RegCloseKey(hDeviceKey);
|
|
|
|
DPRINT("PNP_GetCustomDevProp() done (returns %lx)\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Function 62 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetVersionInternal(
|
|
handle_t hBinding,
|
|
WORD *pwVersion)
|
|
{
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
|
|
*pwVersion = WINVER;
|
|
return CR_SUCCESS;
|
|
}
|
|
|
|
|
|
/* Function 63 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetBlockedDriverInfo(
|
|
handle_t hBinding,
|
|
BYTE *Buffer,
|
|
PNP_RPC_BUFFER_SIZE *pulTransferLen,
|
|
PNP_RPC_BUFFER_SIZE *pulLength,
|
|
DWORD ulFlags)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 64 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetServerSideDeviceInstallFlags(
|
|
handle_t hBinding,
|
|
DWORD *pulSSDIFlags,
|
|
DWORD ulFlags)
|
|
{
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
|
|
DPRINT1("PNP_GetServerSideDeviceInstallFlags(%p %p %lu)\n",
|
|
hBinding, pulSSDIFlags, ulFlags);
|
|
|
|
if (pulSSDIFlags == NULL)
|
|
return CR_INVALID_POINTER;
|
|
|
|
if (ulFlags != 0)
|
|
return CR_INVALID_FLAG;
|
|
|
|
/* FIXME */
|
|
*pulSSDIFlags = 0;
|
|
|
|
return CR_SUCCESS;
|
|
}
|
|
|
|
|
|
/* Function 65 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetObjectPropKeys(
|
|
handle_t hBinding,
|
|
LPWSTR ObjectName,
|
|
DWORD ObjectType,
|
|
LPWSTR PropertyCultureName,
|
|
PNP_PROP_COUNT *PropertyCount,
|
|
PNP_PROP_COUNT *TransferLen,
|
|
DEVPROPKEY *PropertyKeys,
|
|
DWORD Flags)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 66 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_GetObjectProp(
|
|
handle_t hBinding,
|
|
LPWSTR ObjectName,
|
|
DWORD ObjectType,
|
|
LPWSTR PropertyCultureName,
|
|
const DEVPROPKEY *PropertyKey,
|
|
DEVPROPTYPE *PropertyType,
|
|
PNP_PROP_SIZE *PropertySize,
|
|
PNP_PROP_SIZE *TransferLen,
|
|
BYTE *PropertyBuffer,
|
|
DWORD Flags)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 67 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_SetObjectProp(
|
|
handle_t hBinding,
|
|
LPWSTR ObjectName,
|
|
DWORD ObjectType,
|
|
LPWSTR PropertyCultureName,
|
|
const DEVPROPKEY *PropertyKey,
|
|
DEVPROPTYPE PropertyType,
|
|
PNP_PROP_SIZE PropertySize,
|
|
BYTE *PropertyBuffer,
|
|
DWORD Flags)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 68 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_InstallDevInst(
|
|
handle_t hBinding)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 69 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_ApplyPowerSettings(
|
|
handle_t hBinding)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 70 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_DriverStoreAddDriverPackage(
|
|
handle_t hBinding)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 71 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_DriverStoreDeleteDriverPackage(
|
|
handle_t hBinding)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 72 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_RegisterServiceNotification(
|
|
handle_t hBinding)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 73 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_SetActiveService(
|
|
handle_t hBinding,
|
|
LPWSTR pszFilter,
|
|
DWORD ulFlags)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/* Function 74 */
|
|
DWORD
|
|
WINAPI
|
|
PNP_DeleteServiceDevices(
|
|
handle_t hBinding)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
}
|