reactos/base/services/umpnpmgr/rpcserver.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;
}