[UMPNPMGR] Split the monolithic monster: service, rpc and installer.
authorEric Kohl <eric.kohl@reactos.org>
Thu, 30 May 2019 09:48:29 +0000 (11:48 +0200)
committerEric Kohl <eric.kohl@reactos.org>
Thu, 30 May 2019 09:48:29 +0000 (11:48 +0200)
base/services/umpnpmgr/CMakeLists.txt
base/services/umpnpmgr/install.c [new file with mode: 0644]
base/services/umpnpmgr/precomp.h [new file with mode: 0644]
base/services/umpnpmgr/rpcserver.c [new file with mode: 0644]
base/services/umpnpmgr/umpnpmgr.c

index 4248d0e..7c344f9 100644 (file)
@@ -4,6 +4,8 @@ add_rpc_files(server ${REACTOS_SOURCE_DIR}/sdk/include/reactos/idl/pnp.idl)
 spec2def(umpnpmgr.dll umpnpmgr.spec ADD_IMPORTLIB)
 
 add_library(umpnpmgr MODULE
+    install.c
+    rpcserver.c
     umpnpmgr.c
     umpnpmgr.rc
     ${CMAKE_CURRENT_BINARY_DIR}/pnp_s.c
diff --git a/base/services/umpnpmgr/install.c b/base/services/umpnpmgr/install.c
new file mode 100644 (file)
index 0000000..2f3bdfd
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ *  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/install.c
+ * PURPOSE:          Device installer
+ * 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 ******************************************************************/
+
+HANDLE hUserToken = NULL;
+HANDLE hInstallEvent = NULL;
+HANDLE hNoPendingInstalls = NULL;
+
+SLIST_HEADER DeviceInstallListHead;
+HANDLE hDeviceInstallListNotEmpty;
+
+
+/* FUNCTIONS *****************************************************************/
+
+static BOOL
+InstallDevice(PCWSTR DeviceInstance, BOOL ShowWizard)
+{
+    BOOL DeviceInstalled = FALSE;
+    DWORD BytesWritten;
+    DWORD Value;
+    HANDLE hInstallEvent;
+    HANDLE hPipe = INVALID_HANDLE_VALUE;
+    LPVOID Environment = NULL;
+    PROCESS_INFORMATION ProcessInfo;
+    STARTUPINFOW StartupInfo;
+    UUID RandomUuid;
+    HKEY DeviceKey;
+
+    /* The following lengths are constant (see below), they cannot overflow */
+    WCHAR CommandLine[116];
+    WCHAR InstallEventName[73];
+    WCHAR PipeName[74];
+    WCHAR UuidString[39];
+
+    DPRINT("InstallDevice(%S, %d)\n", DeviceInstance, ShowWizard);
+
+    ZeroMemory(&ProcessInfo, sizeof(ProcessInfo));
+
+    if (RegOpenKeyExW(hEnumKey,
+                      DeviceInstance,
+                      0,
+                      KEY_QUERY_VALUE,
+                      &DeviceKey) == ERROR_SUCCESS)
+    {
+        if (RegQueryValueExW(DeviceKey,
+                             L"Class",
+                             NULL,
+                             NULL,
+                             NULL,
+                             NULL) == ERROR_SUCCESS)
+        {
+            DPRINT("No need to install: %S\n", DeviceInstance);
+            RegCloseKey(DeviceKey);
+            return TRUE;
+        }
+
+        BytesWritten = sizeof(DWORD);
+        if (RegQueryValueExW(DeviceKey,
+                             L"ConfigFlags",
+                             NULL,
+                             NULL,
+                             (PBYTE)&Value,
+                             &BytesWritten) == ERROR_SUCCESS)
+        {
+            if (Value & CONFIGFLAG_FAILEDINSTALL)
+            {
+                DPRINT("No need to install: %S\n", DeviceInstance);
+                RegCloseKey(DeviceKey);
+                return TRUE;
+            }
+        }
+
+        RegCloseKey(DeviceKey);
+    }
+
+    DPRINT1("Installing: %S\n", DeviceInstance);
+
+    /* Create a random UUID for the named pipe & event*/
+    UuidCreate(&RandomUuid);
+    swprintf(UuidString, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
+        RandomUuid.Data1, RandomUuid.Data2, RandomUuid.Data3,
+        RandomUuid.Data4[0], RandomUuid.Data4[1], RandomUuid.Data4[2],
+        RandomUuid.Data4[3], RandomUuid.Data4[4], RandomUuid.Data4[5],
+        RandomUuid.Data4[6], RandomUuid.Data4[7]);
+
+    /* Create the event */
+    wcscpy(InstallEventName, L"Global\\PNP_Device_Install_Event_0.");
+    wcscat(InstallEventName, UuidString);
+    hInstallEvent = CreateEventW(NULL, TRUE, FALSE, InstallEventName);
+    if (!hInstallEvent)
+    {
+        DPRINT1("CreateEventW('%ls') failed with error %lu\n", InstallEventName, GetLastError());
+        goto cleanup;
+    }
+
+    /* Create the named pipe */
+    wcscpy(PipeName, L"\\\\.\\pipe\\PNP_Device_Install_Pipe_0.");
+    wcscat(PipeName, UuidString);
+    hPipe = CreateNamedPipeW(PipeName, PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE, 1, 512, 512, 0, NULL);
+    if (hPipe == INVALID_HANDLE_VALUE)
+    {
+        DPRINT1("CreateNamedPipeW failed with error %u\n", GetLastError());
+        goto cleanup;
+    }
+
+    /* Launch rundll32 to call ClientSideInstallW */
+    wcscpy(CommandLine, L"rundll32.exe newdev.dll,ClientSideInstall ");
+    wcscat(CommandLine, PipeName);
+
+    ZeroMemory(&StartupInfo, sizeof(StartupInfo));
+    StartupInfo.cb = sizeof(StartupInfo);
+
+    if (hUserToken)
+    {
+        /* newdev has to run under the environment of the current user */
+        if (!CreateEnvironmentBlock(&Environment, hUserToken, FALSE))
+        {
+            DPRINT1("CreateEnvironmentBlock failed with error %d\n", GetLastError());
+            goto cleanup;
+        }
+
+        if (!CreateProcessAsUserW(hUserToken, NULL, CommandLine, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, Environment, NULL, &StartupInfo, &ProcessInfo))
+        {
+            DPRINT1("CreateProcessAsUserW failed with error %u\n", GetLastError());
+            goto cleanup;
+        }
+    }
+    else
+    {
+        /* FIXME: This is probably not correct, I guess newdev should never be run with SYSTEM privileges.
+
+           Still, we currently do that in 2nd stage setup and probably Console mode as well, so allow it here.
+           (ShowWizard is only set to FALSE for these two modes) */
+        ASSERT(!ShowWizard);
+
+        if (!CreateProcessW(NULL, CommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &ProcessInfo))
+        {
+            DPRINT1("CreateProcessW failed with error %u\n", GetLastError());
+            goto cleanup;
+        }
+    }
+
+    /* Wait for the function to connect to our pipe */
+    if (!ConnectNamedPipe(hPipe, NULL))
+    {
+        if (GetLastError() != ERROR_PIPE_CONNECTED)
+        {
+            DPRINT1("ConnectNamedPipe failed with error %u\n", GetLastError());
+            goto cleanup;
+        }
+    }
+
+    /* Pass the data. The following output is partly compatible to Windows XP SP2 (researched using a modified newdev.dll to log this stuff) */
+    Value = sizeof(InstallEventName);
+    WriteFile(hPipe, &Value, sizeof(Value), &BytesWritten, NULL);
+    WriteFile(hPipe, InstallEventName, Value, &BytesWritten, NULL);
+
+    /* I couldn't figure out what the following value means under WinXP. It's usually 0 in my tests, but was also 5 once.
+       Therefore the following line is entirely ReactOS-specific. We use the value here to pass the ShowWizard variable. */
+    WriteFile(hPipe, &ShowWizard, sizeof(ShowWizard), &BytesWritten, NULL);
+
+    Value = (wcslen(DeviceInstance) + 1) * sizeof(WCHAR);
+    WriteFile(hPipe, &Value, sizeof(Value), &BytesWritten, NULL);
+    WriteFile(hPipe, DeviceInstance, Value, &BytesWritten, NULL);
+
+    /* Wait for newdev.dll to finish processing */
+    WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
+
+    /* If the event got signalled, this is success */
+    DeviceInstalled = WaitForSingleObject(hInstallEvent, 0) == WAIT_OBJECT_0;
+
+cleanup:
+    if (hInstallEvent)
+        CloseHandle(hInstallEvent);
+
+    if (hPipe != INVALID_HANDLE_VALUE)
+        CloseHandle(hPipe);
+
+    if (Environment)
+        DestroyEnvironmentBlock(Environment);
+
+    if (ProcessInfo.hProcess)
+        CloseHandle(ProcessInfo.hProcess);
+
+    if (ProcessInfo.hThread)
+        CloseHandle(ProcessInfo.hThread);
+
+    if (!DeviceInstalled)
+    {
+        DPRINT1("InstallDevice failed for DeviceInstance '%ws'\n", DeviceInstance);
+    }
+
+    return DeviceInstalled;
+}
+
+
+static LONG
+ReadRegSzKey(
+    IN HKEY hKey,
+    IN LPCWSTR pszKey,
+    OUT LPWSTR* pValue)
+{
+    LONG rc;
+    DWORD dwType;
+    DWORD cbData = 0;
+    LPWSTR Value;
+
+    if (!pValue)
+        return ERROR_INVALID_PARAMETER;
+
+    *pValue = NULL;
+    rc = RegQueryValueExW(hKey, pszKey, NULL, &dwType, NULL, &cbData);
+    if (rc != ERROR_SUCCESS)
+        return rc;
+    if (dwType != REG_SZ)
+        return ERROR_FILE_NOT_FOUND;
+    Value = HeapAlloc(GetProcessHeap(), 0, cbData + sizeof(WCHAR));
+    if (!Value)
+        return ERROR_NOT_ENOUGH_MEMORY;
+    rc = RegQueryValueExW(hKey, pszKey, NULL, NULL, (LPBYTE)Value, &cbData);
+    if (rc != ERROR_SUCCESS)
+    {
+        HeapFree(GetProcessHeap(), 0, Value);
+        return rc;
+    }
+    /* NULL-terminate the string */
+    Value[cbData / sizeof(WCHAR)] = '\0';
+
+    *pValue = Value;
+    return ERROR_SUCCESS;
+}
+
+
+BOOL
+SetupIsActive(VOID)
+{
+    HKEY hKey = NULL;
+    DWORD regType, active, size;
+    LONG rc;
+    BOOL ret = FALSE;
+
+    rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\Setup", 0, KEY_QUERY_VALUE, &hKey);
+    if (rc != ERROR_SUCCESS)
+        goto cleanup;
+
+    size = sizeof(DWORD);
+    rc = RegQueryValueExW(hKey, L"SystemSetupInProgress", NULL, &regType, (LPBYTE)&active, &size);
+    if (rc != ERROR_SUCCESS)
+        goto cleanup;
+    if (regType != REG_DWORD || size != sizeof(DWORD))
+        goto cleanup;
+
+    ret = (active != 0);
+
+cleanup:
+    if (hKey != NULL)
+        RegCloseKey(hKey);
+
+    DPRINT("System setup in progress? %S\n", ret ? L"YES" : L"NO");
+
+    return ret;
+}
+
+
+static BOOL
+IsConsoleBoot(VOID)
+{
+    HKEY ControlKey = NULL;
+    LPWSTR SystemStartOptions = NULL;
+    LPWSTR CurrentOption, NextOption; /* Pointers into SystemStartOptions */
+    BOOL ConsoleBoot = FALSE;
+    LONG rc;
+
+    rc = RegOpenKeyExW(
+        HKEY_LOCAL_MACHINE,
+        L"SYSTEM\\CurrentControlSet\\Control",
+        0,
+        KEY_QUERY_VALUE,
+        &ControlKey);
+
+    rc = ReadRegSzKey(ControlKey, L"SystemStartOptions", &SystemStartOptions);
+    if (rc != ERROR_SUCCESS)
+        goto cleanup;
+
+    /* Check for CONSOLE switch in SystemStartOptions */
+    CurrentOption = SystemStartOptions;
+    while (CurrentOption)
+    {
+        NextOption = wcschr(CurrentOption, L' ');
+        if (NextOption)
+            *NextOption = L'\0';
+        if (_wcsicmp(CurrentOption, L"CONSOLE") == 0)
+        {
+            DPRINT("Found %S. Switching to console boot\n", CurrentOption);
+            ConsoleBoot = TRUE;
+            goto cleanup;
+        }
+        CurrentOption = NextOption ? NextOption + 1 : NULL;
+    }
+
+cleanup:
+    if (ControlKey != NULL)
+        RegCloseKey(ControlKey);
+    HeapFree(GetProcessHeap(), 0, SystemStartOptions);
+    return ConsoleBoot;
+}
+
+
+/* Loop to install all queued devices installations */
+DWORD
+WINAPI
+DeviceInstallThread(LPVOID lpParameter)
+{
+    PSLIST_ENTRY ListEntry;
+    DeviceInstallParams* Params;
+    BOOL showWizard;
+
+    UNREFERENCED_PARAMETER(lpParameter);
+
+    WaitForSingleObject(hInstallEvent, INFINITE);
+
+    showWizard = !SetupIsActive() && !IsConsoleBoot();
+
+    while (TRUE)
+    {
+        ListEntry = InterlockedPopEntrySList(&DeviceInstallListHead);
+
+        if (ListEntry == NULL)
+        {
+            SetEvent(hNoPendingInstalls);
+            WaitForSingleObject(hDeviceInstallListNotEmpty, INFINITE);
+        }
+        else
+        {
+            ResetEvent(hNoPendingInstalls);
+            Params = CONTAINING_RECORD(ListEntry, DeviceInstallParams, ListEntry);
+            InstallDevice(Params->DeviceIds, showWizard);
+            HeapFree(GetProcessHeap(), 0, Params);
+        }
+    }
+
+    return 0;
+}
diff --git a/base/services/umpnpmgr/precomp.h b/base/services/umpnpmgr/precomp.h
new file mode 100644 (file)
index 0000000..3c51aa4
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * COPYRIGHT:        See COPYING in the top level directory
+ * PROJECT:          ReactOS kernel
+ * FILE:             base/services/umpnpmgr/install.c
+ * PURPOSE:          Device installer
+ * PROGRAMMER:       Eric Kohl (eric.kohl@reactos.org)
+ *                   Hervé Poussineau (hpoussin@reactos.org)
+ *                   Colin Finck (colin@reactos.org)
+ */
+
+#ifndef _UMPNPMGR_PCH_
+#define _UMPNPMGR_PCH_
+
+#define WIN32_NO_STATUS
+#define _INC_WINDOWS
+#define COM_NO_WINDOWS_H
+#include <stdarg.h>
+#include <windef.h>
+#include <winbase.h>
+#include <winreg.h>
+#include <winsvc.h>
+#include <winuser.h>
+#include <dbt.h>
+#include <stdio.h>
+#include <cmfuncs.h>
+#include <rtlfuncs.h>
+#include <setypes.h>
+#include <umpnpmgr/sysguid.h>
+#include <cfgmgr32.h>
+#include <regstr.h>
+#include <userenv.h>
+#include <shlwapi.h>
+#include <pnp_s.h>
+
+
+typedef struct
+{
+    SLIST_ENTRY ListEntry;
+    WCHAR DeviceIds[1];
+} DeviceInstallParams;
+
+
+/* install.c */
+
+extern HANDLE hUserToken;
+extern HANDLE hInstallEvent;
+extern HANDLE hNoPendingInstalls;
+
+extern SLIST_HEADER DeviceInstallListHead;
+extern HANDLE hDeviceInstallListNotEmpty;
+
+BOOL
+SetupIsActive(VOID);
+
+DWORD
+WINAPI
+DeviceInstallThread(
+    LPVOID lpParameter);
+
+
+/* rpcserver.c */
+
+DWORD
+WINAPI
+RpcServerThread(
+    LPVOID lpParameter);
+
+
+/* umpnpmgr.c */
+
+extern HKEY hEnumKey;
+extern HKEY hClassKey;
+
+
+#endif /* _UMPNPMGR_PCH_ */
\ No newline at end of file
diff --git a/base/services/umpnpmgr/rpcserver.c b/base/services/umpnpmgr/rpcserver.c
new file mode 100644 (file)
index 0000000..2d0c02d
--- /dev/null
@@ -0,0 +1,3762 @@
+/*
+ *  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 szRootDeviceId[] = L"HTREE\\ROOT\\0";
+
+
+/* FUNCTIONS *****************************************************************/
+
+DWORD WINAPI
+RpcServerThread(LPVOID lpParameter)
+{
+    RPC_STATUS Status;
+    BOOLEAN RegisteredProtSeq = FALSE;
+
+    UNREFERENCED_PARAMETER(lpParameter);
+
+    DPRINT("RpcServerThread() called\n");
+
+#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);
+}
+
+
+/* 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);
+
+    *pVersion = 0x0400;
+    return CR_SUCCESS;
+}
+
+
+/* Function 3 */
+DWORD
+WINAPI
+PNP_GetGlobalState(
+    handle_t hBinding,
+    DWORD *pulState,
+    DWORD ulFlags)
+{
+    UNREFERENCED_PARAMETER(hBinding);
+    UNREFERENCED_PARAMETER(ulFlags);
+
+    *pulState = CM_GLOBAL_STATE_CAN_DO_UI | CM_GLOBAL_STATE_SERVICES_AVAILABLE;
+    return CR_SUCCESS;
+}
+
+
+/* Function 4 */
+DWORD
+WINAPI
+PNP_InitDetection(
+    handle_t hBinding)
+{
+    UNREFERENCED_PARAMETER(hBinding);
+
+    DPRINT("PNP_InitDetection() called\n");
+    return CR_SUCCESS;
+}
+
+
+/* Function 5 */
+DWORD
+WINAPI
+PNP_ReportLogOn(
+    handle_t hBinding,
+    BOOL Admin,
+    DWORD ProcessId)
+{
+    DWORD ReturnValue = CR_FAILURE;
+    HANDLE hProcess;
+
+    UNREFERENCED_PARAMETER(hBinding);
+    UNREFERENCED_PARAMETER(Admin);
+
+    DPRINT("PNP_ReportLogOn(%u, %u) called\n", Admin, ProcessId);
+
+    /* 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(%S %lx) called\n",
+           pDeviceID, ulFlags);
+
+    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() called\n");
+
+    if (!pDeviceID)
+    {
+        ret = CR_INVALID_POINTER;
+        goto Done;
+    }
+    if (ulLength < lstrlenW(szRootDeviceId) + 1)
+    {
+        ret = CR_BUFFER_SMALL;
+        goto Done;
+    }
+
+    lstrcpyW(pDeviceID,
+             szRootDeviceId);
+
+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() called\n");
+    DPRINT("  Relationship %ld\n", ulRelationship);
+    DPRINT("  DeviceId %S\n", pDeviceID);
+
+    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() called\n");
+
+    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() called\n");
+
+    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%lx)\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() called\n");
+
+    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() called\n");
+
+    if (pulTransferLen == NULL || pulLength == NULL)
+    {
+        ret = CR_INVALID_POINTER;
+        goto done;
+    }
+
+    if (ulFlags != 0)
+    {
+        ret = CR_INVALID_FLAG;
+        goto done;
+    }
+
+    /* FIXME: Check pDeviceID */
+
+    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;
+            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;
+            break;
+
+        case CM_DRP_LEGACYBUSTYPE:
+            PlugPlayData.Property = PNP_PROPERTY_LEGACYBUSTYPE;
+            break;
+
+        case CM_DRP_BUSNUMBER:
+            PlugPlayData.Property = PNP_PROPERTY_BUSNUMBER;
+            break;
+
+        case CM_DRP_ENUMERATOR_NAME:
+            PlugPlayData.Property = PNP_PROPERTY_ENUMERATOR_NAME;
+            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;
+            break;
+
+        case CM_DRP_UI_NUMBER_DESC_FORMAT:
+            lpValueName = L"UINumberDescFormat";
+            break;
+
+        case CM_DRP_DEVICE_POWER_DATA:
+            PlugPlayData.Property = PNP_PROPERTY_POWER_DATA;
+            break;
+
+        case CM_DRP_REMOVAL_POLICY:
+            PlugPlayData.Property = PNP_PROPERTY_REMOVAL_POLICY;
+            break;
+
+        case CM_DRP_REMOVAL_POLICY_HW_DEFAULT:
+            PlugPlayData.Property = PNP_PROPERTY_REMOVAL_POLICY_HARDWARE_DEFAULT;
+            break;
+
+        case CM_DRP_REMOVAL_POLICY_OVERRIDE:
+            lpValueName = L"RemovalPolicy";
+            break;
+
+        case CM_DRP_INSTALL_STATE:
+            PlugPlayData.Property = PNP_PROPERTY_INSTALL_STATE;
+            break;
+
+#if (WINVER >= _WIN32_WINNT_WS03)
+        case CM_DRP_LOCATION_PATHS:
+            PlugPlayData.Property = PNP_PROPERTY_LOCATION_PATHS;
+            break;
+#endif
+
+#if (WINVER >= _WIN32_WINNT_WIN7)
+        case CM_DRP_BASE_CONTAINERID:
+            PlugPlayData.Property = PNP_PROPERTY_CONTAINERID;
+            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() called\n");
+
+    DPRINT("DeviceId: %S\n", pDeviceId);
+    DPRINT("Property: %lu\n", ulProperty);
+    DPRINT("DataType: %lu\n", ulDataType);
+    DPRINT("Length: %lu\n", ulLength);
+
+    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)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 16 */
+DWORD
+WINAPI
+PNP_CreateKey(
+    handle_t hBinding,
+    LPWSTR pszSubKey,
+    DWORD samDesired,
+    DWORD ulFlags)
+{
+    HKEY hKey = 0;
+
+    if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
+                        pszSubKey,
+                        0,
+                        NULL,
+                        0,
+                        KEY_ALL_ACCESS,
+                        NULL,
+                        &hKey,
+                        NULL))
+        return CR_REGISTRY_ERROR;
+
+    /* FIXME: Set security key */
+
+    RegCloseKey(hKey);
+
+    return CR_SUCCESS;
+}
+
+
+/* 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);
+
+    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() called\n");
+
+    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_GetClassName(%S, %lx) called\n", 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);
+
+    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_GetInterfaceDeviceListSize() 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() called\n");
+
+    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() called\n");
+
+    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() called\n");
+
+    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(LPWSTR pszDeviceID)
+{
+    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;
+    }
+
+    /* 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;
+}
+
+
+/* Function 28 */
+DWORD
+WINAPI
+PNP_CreateDevInst(
+    handle_t hBinding,
+    LPWSTR pszDeviceID,
+    LPWSTR pszParentDeviceID,
+    PNP_RPC_STRING_LEN ulLength,
+    DWORD ulFlags)
+{
+    CONFIGRET ret = CR_SUCCESS;
+
+    DPRINT("PNP_CreateDevInst: %S\n", pszDeviceID);
+
+    if (ulFlags & CM_CREATE_DEVNODE_GENERATE_ID)
+    {
+        WCHAR szGeneratedInstance[MAX_DEVICE_ID_LEN];
+        DWORD dwInstanceNumber;
+
+        /* Generated ID is: Root\<Device ID>\<Instance number> */
+        dwInstanceNumber = 0;
+        do
+        {
+            swprintf(szGeneratedInstance, L"Root\\%ls\\%04lu",
+                     pszDeviceID, dwInstanceNumber);
+
+            /* Try to create a device instance with this ID */
+            ret = CreateDeviceInstance(szGeneratedInstance);
+
+            dwInstanceNumber++;
+        }
+        while (ret == CR_ALREADY_SUCH_DEVINST);
+
+        if (ret == CR_SUCCESS)
+        {
+            /* pszDeviceID is an out parameter too for generated IDs */
+            if (wcslen(szGeneratedInstance) > ulLength)
+            {
+                ret = CR_BUFFER_SMALL;
+            }
+            else
+            {
+                wcscpy(pszDeviceID, szGeneratedInstance);
+            }
+        }
+    }
+    else
+    {
+        /* Create the device instance */
+        ret = CreateDeviceInstance(pszDeviceID);
+    }
+
+    DPRINT("PNP_CreateDevInst() done (returns %lx)\n", ret);
+
+    return ret;
+}
+
+
+static CONFIGRET
+MoveDeviceInstance(LPWSTR pszDeviceInstanceDestination,
+                   LPWSTR pszDeviceInstanceSource)
+{
+    DPRINT("MoveDeviceInstance: not implemented\n");
+    /* FIXME */
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+static CONFIGRET
+SetupDeviceInstance(LPWSTR pszDeviceInstance,
+                    DWORD ulFlags)
+{
+    DPRINT("SetupDeviceInstance: not implemented\n");
+    /* FIXME */
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+static CONFIGRET
+EnableDeviceInstance(LPWSTR pszDeviceInstance)
+{
+    PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData;
+    CONFIGRET ret = CR_SUCCESS;
+    NTSTATUS Status;
+
+    DPRINT("Enable device instance %S\n", pszDeviceInstance);
+
+    RtlInitUnicodeString(&ResetDeviceData.DeviceInstance, pszDeviceInstance);
+    Status = NtPlugPlayControl(PlugPlayControlResetDevice, &ResetDeviceData, sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA));
+    if (!NT_SUCCESS(Status))
+        ret = NtStatusToCrError(Status);
+
+    return ret;
+}
+
+
+static CONFIGRET
+DisableDeviceInstance(LPWSTR pszDeviceInstance)
+{
+    DPRINT("DisableDeviceInstance: not implemented\n");
+    /* FIXME */
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+static CONFIGRET
+ReenumerateDeviceInstance(
+    _In_ LPWSTR pszDeviceInstance,
+    _In_ ULONG ulFlags)
+{
+    PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA EnumerateDeviceData;
+    CONFIGRET ret = CR_SUCCESS;
+    NTSTATUS Status;
+
+    DPRINT1("ReenumerateDeviceInstance(%S 0x%08lx)\n",
+           pszDeviceInstance, ulFlags);
+
+    if (ulFlags & ~CM_REENUMERATE_BITS)
+        return CR_INVALID_FLAG;
+
+    if (ulFlags & 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 ulAction,
+    DWORD ulFlags,
+    LPWSTR pszDeviceInstance1,
+    LPWSTR pszDeviceInstance2)
+{
+    CONFIGRET ret = CR_SUCCESS;
+
+    UNREFERENCED_PARAMETER(hBinding);
+
+    DPRINT("PNP_DeviceInstanceAction() called\n");
+
+    switch (ulAction)
+    {
+        case PNP_DEVINST_MOVE:
+            ret = MoveDeviceInstance(pszDeviceInstance1,
+                                     pszDeviceInstance2);
+            break;
+
+        case PNP_DEVINST_SETUP:
+            ret = SetupDeviceInstance(pszDeviceInstance1,
+                                      ulFlags);
+            break;
+
+        case PNP_DEVINST_ENABLE:
+            ret = EnableDeviceInstance(pszDeviceInstance1);
+            break;
+
+        case PNP_DEVINST_DISABLE:
+            ret = DisableDeviceInstance(pszDeviceInstance1);
+            break;
+
+        case PNP_DEVINST_REENUMERATE:
+            ret = ReenumerateDeviceInstance(pszDeviceInstance1,
+                                            ulFlags);
+            break;
+
+        default:
+            DPRINT1("Unknown device action %lu: not implemented\n", ulAction);
+            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)
+{
+    PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData;
+    CONFIGRET ret = CR_SUCCESS;
+    NTSTATUS Status;
+
+    UNREFERENCED_PARAMETER(hBinding);
+    UNREFERENCED_PARAMETER(ulFlags);
+
+    DPRINT("PNP_GetDeviceStatus() called\n");
+
+    RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
+                         pDeviceID);
+    PlugPlayData.Operation = 0; /* Get 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);
+    }
+
+    DPRINT("PNP_GetDeviceStatus() done (returns %lx)\n", ret);
+
+    return ret;
+}
+
+
+/* Function 31 */
+DWORD
+WINAPI
+PNP_SetDeviceProblem(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    DWORD ulProblem,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 32 */
+DWORD
+WINAPI
+PNP_DisableDevInst(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    PPNP_VETO_TYPE pVetoType,
+    LPWSTR pszVetoName,
+    DWORD ulNameLength,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+/* 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() called\n");
+    DPRINT("  DeviceInstance: %S\n", pszDeviceID);
+    DPRINT("  DeviceId: %S\n", pszID);
+    DPRINT("  Flags: %lx\n", 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)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 36 */
+DWORD
+WINAPI
+PNP_QueryRemove(
+    handle_t hBinding,
+    LPWSTR pszDeviceID,
+    PPNP_VETO_TYPE pVetoType,
+    LPWSTR pszVetoName,
+    DWORD ulNameLength,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 37 */
+DWORD
+WINAPI
+PNP_RequestDeviceEject(
+    handle_t hBinding,
+    LPWSTR pszDeviceID,
+    PPNP_VETO_TYPE pVetoType,
+    LPWSTR pszVetoName,
+    DWORD ulNameLength,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* 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() called\n");
+
+    *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)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* 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 (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)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 45 */
+DWORD
+WINAPI
+PNP_GetNextLogConf(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    DWORD ulLogConfType,
+    DWORD ulCurrentTag,
+    DWORD *pulNextTag,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* 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)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* 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)
+{
+    UNIMPLEMENTED;
+    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 ulFlags,
+    DWORD *pulNotify)
+{
+#if 0
+    PNOTIFY_DATA pNotifyData;
+#endif
+
+    DPRINT1("PNP_RegisterNotification(%p 0x%lx %p)\n",
+           hBinding, ulFlags, pulNotify);
+
+#if 0
+    pNotifyData = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NOTIFY_DATA));
+    if (pNotifyData == NULL)
+        return CR_OUT_OF_MEMORY;
+
+    *pulNotify = (DWORD)pNotifyData;
+#endif
+
+    *pulNotify = 1;
+
+    return CR_SUCCESS;
+}
+
+
+/* Function 60 */
+DWORD
+WINAPI
+PNP_UnregisterNotification(
+    handle_t hBinding,
+    DWORD ulNotify)
+{
+    DPRINT1("PNP_UnregisterNotification(%p 0x%lx)\n",
+           hBinding, ulNotify);
+
+#if 0
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+#endif
+
+    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 (*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 = 0x501;
+    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;
+}
index 4248879..e26fa2f 100644 (file)
 
 /* INCLUDES *****************************************************************/
 
-#define WIN32_NO_STATUS
-#define _INC_WINDOWS
-#define COM_NO_WINDOWS_H
-#include <stdarg.h>
-#include <windef.h>
-#include <winbase.h>
-#include <winreg.h>
-#include <winsvc.h>
-#include <winuser.h>
-#include <dbt.h>
-#include <stdio.h>
-#include <cmfuncs.h>
-#include <rtlfuncs.h>
-#include <setypes.h>
-#include <umpnpmgr/sysguid.h>
-#include <cfgmgr32.h>
-#include <regstr.h>
-#include <userenv.h>
-#include <shlwapi.h>
-#include <pnp_s.h>
+#include "precomp.h"
 
 #define NDEBUG
 #include <debug.h>
 
+
 /* GLOBALS ******************************************************************/
 
 static WCHAR ServiceName[] = L"PlugPlay";
@@ -59,4077 +41,12 @@ static WCHAR ServiceName[] = L"PlugPlay";
 static SERVICE_STATUS_HANDLE ServiceStatusHandle;
 static SERVICE_STATUS ServiceStatus;
 
-static WCHAR szRootDeviceId[] = L"HTREE\\ROOT\\0";
-
-static HKEY hEnumKey = NULL;
-static HKEY hClassKey = NULL;
-
-static HANDLE hUserToken = NULL;
-static HANDLE hInstallEvent = NULL;
-static HANDLE hNoPendingInstalls = NULL;
-
-static SLIST_HEADER DeviceInstallListHead;
-static HANDLE hDeviceInstallListNotEmpty;
+HKEY hEnumKey = NULL;
+HKEY hClassKey = NULL;
 
-typedef struct
-{
-    SLIST_ENTRY ListEntry;
-    WCHAR DeviceIds[1];
-} DeviceInstallParams;
 
 /* FUNCTIONS *****************************************************************/
 
-static DWORD WINAPI
-RpcServerThread(LPVOID lpParameter)
-{
-    RPC_STATUS Status;
-    BOOLEAN RegisteredProtSeq = FALSE;
-
-    UNREFERENCED_PARAMETER(lpParameter);
-
-    DPRINT("RpcServerThread() called\n");
-
-#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);
-}
-
-
-/* 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);
-
-    *pVersion = 0x0400;
-    return CR_SUCCESS;
-}
-
-
-/* Function 3 */
-DWORD
-WINAPI
-PNP_GetGlobalState(
-    handle_t hBinding,
-    DWORD *pulState,
-    DWORD ulFlags)
-{
-    UNREFERENCED_PARAMETER(hBinding);
-    UNREFERENCED_PARAMETER(ulFlags);
-
-    *pulState = CM_GLOBAL_STATE_CAN_DO_UI | CM_GLOBAL_STATE_SERVICES_AVAILABLE;
-    return CR_SUCCESS;
-}
-
-
-/* Function 4 */
-DWORD
-WINAPI
-PNP_InitDetection(
-    handle_t hBinding)
-{
-    UNREFERENCED_PARAMETER(hBinding);
-
-    DPRINT("PNP_InitDetection() called\n");
-    return CR_SUCCESS;
-}
-
-
-/* Function 5 */
-DWORD
-WINAPI
-PNP_ReportLogOn(
-    handle_t hBinding,
-    BOOL Admin,
-    DWORD ProcessId)
-{
-    DWORD ReturnValue = CR_FAILURE;
-    HANDLE hProcess;
-
-    UNREFERENCED_PARAMETER(hBinding);
-    UNREFERENCED_PARAMETER(Admin);
-
-    DPRINT("PNP_ReportLogOn(%u, %u) called\n", Admin, ProcessId);
-
-    /* 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(%S %lx) called\n",
-           pDeviceID, ulFlags);
-
-    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() called\n");
-
-    if (!pDeviceID)
-    {
-        ret = CR_INVALID_POINTER;
-        goto Done;
-    }
-    if (ulLength < lstrlenW(szRootDeviceId) + 1)
-    {
-        ret = CR_BUFFER_SMALL;
-        goto Done;
-    }
-
-    lstrcpyW(pDeviceID,
-             szRootDeviceId);
-
-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() called\n");
-    DPRINT("  Relationship %ld\n", ulRelationship);
-    DPRINT("  DeviceId %S\n", pDeviceID);
-
-    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() called\n");
-
-    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() called\n");
-
-    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%lx)\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() called\n");
-
-    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() called\n");
-
-    if (pulTransferLen == NULL || pulLength == NULL)
-    {
-        ret = CR_INVALID_POINTER;
-        goto done;
-    }
-
-    if (ulFlags != 0)
-    {
-        ret = CR_INVALID_FLAG;
-        goto done;
-    }
-
-    /* FIXME: Check pDeviceID */
-
-    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;
-            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;
-            break;
-
-        case CM_DRP_LEGACYBUSTYPE:
-            PlugPlayData.Property = PNP_PROPERTY_LEGACYBUSTYPE;
-            break;
-
-        case CM_DRP_BUSNUMBER:
-            PlugPlayData.Property = PNP_PROPERTY_BUSNUMBER;
-            break;
-
-        case CM_DRP_ENUMERATOR_NAME:
-            PlugPlayData.Property = PNP_PROPERTY_ENUMERATOR_NAME;
-            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;
-            break;
-
-        case CM_DRP_UI_NUMBER_DESC_FORMAT:
-            lpValueName = L"UINumberDescFormat";
-            break;
-
-        case CM_DRP_DEVICE_POWER_DATA:
-            PlugPlayData.Property = PNP_PROPERTY_POWER_DATA;
-            break;
-
-        case CM_DRP_REMOVAL_POLICY:
-            PlugPlayData.Property = PNP_PROPERTY_REMOVAL_POLICY;
-            break;
-
-        case CM_DRP_REMOVAL_POLICY_HW_DEFAULT:
-            PlugPlayData.Property = PNP_PROPERTY_REMOVAL_POLICY_HARDWARE_DEFAULT;
-            break;
-
-        case CM_DRP_REMOVAL_POLICY_OVERRIDE:
-            lpValueName = L"RemovalPolicy";
-            break;
-
-        case CM_DRP_INSTALL_STATE:
-            PlugPlayData.Property = PNP_PROPERTY_INSTALL_STATE;
-            break;
-
-#if (WINVER >= _WIN32_WINNT_WS03)
-        case CM_DRP_LOCATION_PATHS:
-            PlugPlayData.Property = PNP_PROPERTY_LOCATION_PATHS;
-            break;
-#endif
-
-#if (WINVER >= _WIN32_WINNT_WIN7)
-        case CM_DRP_BASE_CONTAINERID:
-            PlugPlayData.Property = PNP_PROPERTY_CONTAINERID;
-            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() called\n");
-
-    DPRINT("DeviceId: %S\n", pDeviceId);
-    DPRINT("Property: %lu\n", ulProperty);
-    DPRINT("DataType: %lu\n", ulDataType);
-    DPRINT("Length: %lu\n", ulLength);
-
-    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)
-{
-    UNIMPLEMENTED;
-    return CR_CALL_NOT_IMPLEMENTED;
-}
-
-
-/* Function 16 */
-DWORD
-WINAPI
-PNP_CreateKey(
-    handle_t hBinding,
-    LPWSTR pszSubKey,
-    DWORD samDesired,
-    DWORD ulFlags)
-{
-    HKEY hKey = 0;
-
-    if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
-                        pszSubKey,
-                        0,
-                        NULL,
-                        0,
-                        KEY_ALL_ACCESS,
-                        NULL,
-                        &hKey,
-                        NULL))
-        return CR_REGISTRY_ERROR;
-
-    /* FIXME: Set security key */
-
-    RegCloseKey(hKey);
-
-    return CR_SUCCESS;
-}
-
-
-/* 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);
-
-    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() called\n");
-
-    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_GetClassName(%S, %lx) called\n", 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);
-
-    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_GetInterfaceDeviceListSize() 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() called\n");
-
-    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() called\n");
-
-    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() called\n");
-
-    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(LPWSTR pszDeviceID)
-{
-    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;
-    }
-
-    /* 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;
-}
-
-
-/* Function 28 */
-DWORD
-WINAPI
-PNP_CreateDevInst(
-    handle_t hBinding,
-    LPWSTR pszDeviceID,
-    LPWSTR pszParentDeviceID,
-    PNP_RPC_STRING_LEN ulLength,
-    DWORD ulFlags)
-{
-    CONFIGRET ret = CR_SUCCESS;
-
-    DPRINT("PNP_CreateDevInst: %S\n", pszDeviceID);
-
-    if (ulFlags & CM_CREATE_DEVNODE_GENERATE_ID)
-    {
-        WCHAR szGeneratedInstance[MAX_DEVICE_ID_LEN];
-        DWORD dwInstanceNumber;
-
-        /* Generated ID is: Root\<Device ID>\<Instance number> */
-        dwInstanceNumber = 0;
-        do
-        {
-            swprintf(szGeneratedInstance, L"Root\\%ls\\%04lu",
-                     pszDeviceID, dwInstanceNumber);
-
-            /* Try to create a device instance with this ID */
-            ret = CreateDeviceInstance(szGeneratedInstance);
-
-            dwInstanceNumber++;
-        }
-        while (ret == CR_ALREADY_SUCH_DEVINST);
-
-        if (ret == CR_SUCCESS)
-        {
-            /* pszDeviceID is an out parameter too for generated IDs */
-            if (wcslen(szGeneratedInstance) > ulLength)
-            {
-                ret = CR_BUFFER_SMALL;
-            }
-            else
-            {
-                wcscpy(pszDeviceID, szGeneratedInstance);
-            }
-        }
-    }
-    else
-    {
-        /* Create the device instance */
-        ret = CreateDeviceInstance(pszDeviceID);
-    }
-
-    DPRINT("PNP_CreateDevInst() done (returns %lx)\n", ret);
-
-    return ret;
-}
-
-
-static CONFIGRET
-MoveDeviceInstance(LPWSTR pszDeviceInstanceDestination,
-                   LPWSTR pszDeviceInstanceSource)
-{
-    DPRINT("MoveDeviceInstance: not implemented\n");
-    /* FIXME */
-    return CR_CALL_NOT_IMPLEMENTED;
-}
-
-
-static CONFIGRET
-SetupDeviceInstance(LPWSTR pszDeviceInstance,
-                    DWORD ulFlags)
-{
-    DPRINT("SetupDeviceInstance: not implemented\n");
-    /* FIXME */
-    return CR_CALL_NOT_IMPLEMENTED;
-}
-
-
-static CONFIGRET
-EnableDeviceInstance(LPWSTR pszDeviceInstance)
-{
-    PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData;
-    CONFIGRET ret = CR_SUCCESS;
-    NTSTATUS Status;
-
-    DPRINT("Enable device instance %S\n", pszDeviceInstance);
-
-    RtlInitUnicodeString(&ResetDeviceData.DeviceInstance, pszDeviceInstance);
-    Status = NtPlugPlayControl(PlugPlayControlResetDevice, &ResetDeviceData, sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA));
-    if (!NT_SUCCESS(Status))
-        ret = NtStatusToCrError(Status);
-
-    return ret;
-}
-
-
-static CONFIGRET
-DisableDeviceInstance(LPWSTR pszDeviceInstance)
-{
-    DPRINT("DisableDeviceInstance: not implemented\n");
-    /* FIXME */
-    return CR_CALL_NOT_IMPLEMENTED;
-}
-
-
-static CONFIGRET
-ReenumerateDeviceInstance(
-    _In_ LPWSTR pszDeviceInstance,
-    _In_ ULONG ulFlags)
-{
-    PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA EnumerateDeviceData;
-    CONFIGRET ret = CR_SUCCESS;
-    NTSTATUS Status;
-
-    DPRINT1("ReenumerateDeviceInstance(%S 0x%08lx)\n",
-           pszDeviceInstance, ulFlags);
-
-    if (ulFlags & ~CM_REENUMERATE_BITS)
-        return CR_INVALID_FLAG;
-
-    if (ulFlags & 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 ulAction,
-    DWORD ulFlags,
-    LPWSTR pszDeviceInstance1,
-    LPWSTR pszDeviceInstance2)
-{
-    CONFIGRET ret = CR_SUCCESS;
-
-    UNREFERENCED_PARAMETER(hBinding);
-
-    DPRINT("PNP_DeviceInstanceAction() called\n");
-
-    switch (ulAction)
-    {
-        case PNP_DEVINST_MOVE:
-            ret = MoveDeviceInstance(pszDeviceInstance1,
-                                     pszDeviceInstance2);
-            break;
-
-        case PNP_DEVINST_SETUP:
-            ret = SetupDeviceInstance(pszDeviceInstance1,
-                                      ulFlags);
-            break;
-
-        case PNP_DEVINST_ENABLE:
-            ret = EnableDeviceInstance(pszDeviceInstance1);
-            break;
-
-        case PNP_DEVINST_DISABLE:
-            ret = DisableDeviceInstance(pszDeviceInstance1);
-            break;
-
-        case PNP_DEVINST_REENUMERATE:
-            ret = ReenumerateDeviceInstance(pszDeviceInstance1,
-                                            ulFlags);
-            break;
-
-        default:
-            DPRINT1("Unknown device action %lu: not implemented\n", ulAction);
-            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)
-{
-    PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData;
-    CONFIGRET ret = CR_SUCCESS;
-    NTSTATUS Status;
-
-    UNREFERENCED_PARAMETER(hBinding);
-    UNREFERENCED_PARAMETER(ulFlags);
-
-    DPRINT("PNP_GetDeviceStatus() called\n");
-
-    RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
-                         pDeviceID);
-    PlugPlayData.Operation = 0; /* Get 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);
-    }
-
-    DPRINT("PNP_GetDeviceStatus() done (returns %lx)\n", ret);
-
-    return ret;
-}
-
-
-/* Function 31 */
-DWORD
-WINAPI
-PNP_SetDeviceProblem(
-    handle_t hBinding,
-    LPWSTR pDeviceID,
-    DWORD ulProblem,
-    DWORD ulFlags)
-{
-    UNIMPLEMENTED;
-    return CR_CALL_NOT_IMPLEMENTED;
-}
-
-
-/* Function 32 */
-DWORD
-WINAPI
-PNP_DisableDevInst(
-    handle_t hBinding,
-    LPWSTR pDeviceID,
-    PPNP_VETO_TYPE pVetoType,
-    LPWSTR pszVetoName,
-    DWORD ulNameLength,
-    DWORD ulFlags)
-{
-    UNIMPLEMENTED;
-    return CR_CALL_NOT_IMPLEMENTED;
-}
-
-/* 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() called\n");
-    DPRINT("  DeviceInstance: %S\n", pszDeviceID);
-    DPRINT("  DeviceId: %S\n", pszID);
-    DPRINT("  Flags: %lx\n", 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)
-{
-    UNIMPLEMENTED;
-    return CR_CALL_NOT_IMPLEMENTED;
-}
-
-
-/* Function 36 */
-DWORD
-WINAPI
-PNP_QueryRemove(
-    handle_t hBinding,
-    LPWSTR pszDeviceID,
-    PPNP_VETO_TYPE pVetoType,
-    LPWSTR pszVetoName,
-    DWORD ulNameLength,
-    DWORD ulFlags)
-{
-    UNIMPLEMENTED;
-    return CR_CALL_NOT_IMPLEMENTED;
-}
-
-
-/* Function 37 */
-DWORD
-WINAPI
-PNP_RequestDeviceEject(
-    handle_t hBinding,
-    LPWSTR pszDeviceID,
-    PPNP_VETO_TYPE pVetoType,
-    LPWSTR pszVetoName,
-    DWORD ulNameLength,
-    DWORD ulFlags)
-{
-    UNIMPLEMENTED;
-    return CR_CALL_NOT_IMPLEMENTED;
-}
-
-
-/* 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() called\n");
-
-    *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)
-{
-    UNIMPLEMENTED;
-    return CR_CALL_NOT_IMPLEMENTED;
-}
-
-
-/* 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 (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)
-{
-    UNIMPLEMENTED;
-    return CR_CALL_NOT_IMPLEMENTED;
-}
-
-
-/* Function 45 */
-DWORD
-WINAPI
-PNP_GetNextLogConf(
-    handle_t hBinding,
-    LPWSTR pDeviceID,
-    DWORD ulLogConfType,
-    DWORD ulCurrentTag,
-    DWORD *pulNextTag,
-    DWORD ulFlags)
-{
-    UNIMPLEMENTED;
-    return CR_CALL_NOT_IMPLEMENTED;
-}
-
-
-/* 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)
-{
-    UNIMPLEMENTED;
-    return CR_CALL_NOT_IMPLEMENTED;
-}
-
-
-/* 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)
-{
-    UNIMPLEMENTED;
-    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 ulFlags,
-    DWORD *pulNotify)
-{
-#if 0
-    PNOTIFY_DATA pNotifyData;
-#endif
-
-    DPRINT1("PNP_RegisterNotification(%p 0x%lx %p)\n",
-           hBinding, ulFlags, pulNotify);
-
-#if 0
-    pNotifyData = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NOTIFY_DATA));
-    if (pNotifyData == NULL)
-        return CR_OUT_OF_MEMORY;
-
-    *pulNotify = (DWORD)pNotifyData;
-#endif
-
-    *pulNotify = 1;
-
-    return CR_SUCCESS;
-}
-
-
-/* Function 60 */
-DWORD
-WINAPI
-PNP_UnregisterNotification(
-    handle_t hBinding,
-    DWORD ulNotify)
-{
-    DPRINT1("PNP_UnregisterNotification(%p 0x%lx)\n",
-           hBinding, ulNotify);
-
-#if 0
-    UNIMPLEMENTED;
-    return CR_CALL_NOT_IMPLEMENTED;
-#endif
-
-    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 (*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 = 0x501;
-    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;
-}
-
-
-static BOOL
-InstallDevice(PCWSTR DeviceInstance, BOOL ShowWizard)
-{
-    BOOL DeviceInstalled = FALSE;
-    DWORD BytesWritten;
-    DWORD Value;
-    HANDLE hInstallEvent;
-    HANDLE hPipe = INVALID_HANDLE_VALUE;
-    LPVOID Environment = NULL;
-    PROCESS_INFORMATION ProcessInfo;
-    STARTUPINFOW StartupInfo;
-    UUID RandomUuid;
-    HKEY DeviceKey;
-
-    /* The following lengths are constant (see below), they cannot overflow */
-    WCHAR CommandLine[116];
-    WCHAR InstallEventName[73];
-    WCHAR PipeName[74];
-    WCHAR UuidString[39];
-
-    DPRINT("InstallDevice(%S, %d)\n", DeviceInstance, ShowWizard);
-
-    ZeroMemory(&ProcessInfo, sizeof(ProcessInfo));
-
-    if (RegOpenKeyExW(hEnumKey,
-                      DeviceInstance,
-                      0,
-                      KEY_QUERY_VALUE,
-                      &DeviceKey) == ERROR_SUCCESS)
-    {
-        if (RegQueryValueExW(DeviceKey,
-                             L"Class",
-                             NULL,
-                             NULL,
-                             NULL,
-                             NULL) == ERROR_SUCCESS)
-        {
-            DPRINT("No need to install: %S\n", DeviceInstance);
-            RegCloseKey(DeviceKey);
-            return TRUE;
-        }
-
-        BytesWritten = sizeof(DWORD);
-        if (RegQueryValueExW(DeviceKey,
-                             L"ConfigFlags",
-                             NULL,
-                             NULL,
-                             (PBYTE)&Value,
-                             &BytesWritten) == ERROR_SUCCESS)
-        {
-            if (Value & CONFIGFLAG_FAILEDINSTALL)
-            {
-                DPRINT("No need to install: %S\n", DeviceInstance);
-                RegCloseKey(DeviceKey);
-                return TRUE;
-            }
-        }
-
-        RegCloseKey(DeviceKey);
-    }
-
-    DPRINT1("Installing: %S\n", DeviceInstance);
-
-    /* Create a random UUID for the named pipe & event*/
-    UuidCreate(&RandomUuid);
-    swprintf(UuidString, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
-        RandomUuid.Data1, RandomUuid.Data2, RandomUuid.Data3,
-        RandomUuid.Data4[0], RandomUuid.Data4[1], RandomUuid.Data4[2],
-        RandomUuid.Data4[3], RandomUuid.Data4[4], RandomUuid.Data4[5],
-        RandomUuid.Data4[6], RandomUuid.Data4[7]);
-
-    /* Create the event */
-    wcscpy(InstallEventName, L"Global\\PNP_Device_Install_Event_0.");
-    wcscat(InstallEventName, UuidString);
-    hInstallEvent = CreateEventW(NULL, TRUE, FALSE, InstallEventName);
-    if (!hInstallEvent)
-    {
-        DPRINT1("CreateEventW('%ls') failed with error %lu\n", InstallEventName, GetLastError());
-        goto cleanup;
-    }
-
-    /* Create the named pipe */
-    wcscpy(PipeName, L"\\\\.\\pipe\\PNP_Device_Install_Pipe_0.");
-    wcscat(PipeName, UuidString);
-    hPipe = CreateNamedPipeW(PipeName, PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE, 1, 512, 512, 0, NULL);
-    if (hPipe == INVALID_HANDLE_VALUE)
-    {
-        DPRINT1("CreateNamedPipeW failed with error %u\n", GetLastError());
-        goto cleanup;
-    }
-
-    /* Launch rundll32 to call ClientSideInstallW */
-    wcscpy(CommandLine, L"rundll32.exe newdev.dll,ClientSideInstall ");
-    wcscat(CommandLine, PipeName);
-
-    ZeroMemory(&StartupInfo, sizeof(StartupInfo));
-    StartupInfo.cb = sizeof(StartupInfo);
-
-    if (hUserToken)
-    {
-        /* newdev has to run under the environment of the current user */
-        if (!CreateEnvironmentBlock(&Environment, hUserToken, FALSE))
-        {
-            DPRINT1("CreateEnvironmentBlock failed with error %d\n", GetLastError());
-            goto cleanup;
-        }
-
-        if (!CreateProcessAsUserW(hUserToken, NULL, CommandLine, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, Environment, NULL, &StartupInfo, &ProcessInfo))
-        {
-            DPRINT1("CreateProcessAsUserW failed with error %u\n", GetLastError());
-            goto cleanup;
-        }
-    }
-    else
-    {
-        /* FIXME: This is probably not correct, I guess newdev should never be run with SYSTEM privileges.
-
-           Still, we currently do that in 2nd stage setup and probably Console mode as well, so allow it here.
-           (ShowWizard is only set to FALSE for these two modes) */
-        ASSERT(!ShowWizard);
-
-        if (!CreateProcessW(NULL, CommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &ProcessInfo))
-        {
-            DPRINT1("CreateProcessW failed with error %u\n", GetLastError());
-            goto cleanup;
-        }
-    }
-
-    /* Wait for the function to connect to our pipe */
-    if (!ConnectNamedPipe(hPipe, NULL))
-    {
-        if (GetLastError() != ERROR_PIPE_CONNECTED)
-        {
-            DPRINT1("ConnectNamedPipe failed with error %u\n", GetLastError());
-            goto cleanup;
-        }
-    }
-
-    /* Pass the data. The following output is partly compatible to Windows XP SP2 (researched using a modified newdev.dll to log this stuff) */
-    Value = sizeof(InstallEventName);
-    WriteFile(hPipe, &Value, sizeof(Value), &BytesWritten, NULL);
-    WriteFile(hPipe, InstallEventName, Value, &BytesWritten, NULL);
-
-    /* I couldn't figure out what the following value means under WinXP. It's usually 0 in my tests, but was also 5 once.
-       Therefore the following line is entirely ReactOS-specific. We use the value here to pass the ShowWizard variable. */
-    WriteFile(hPipe, &ShowWizard, sizeof(ShowWizard), &BytesWritten, NULL);
-
-    Value = (wcslen(DeviceInstance) + 1) * sizeof(WCHAR);
-    WriteFile(hPipe, &Value, sizeof(Value), &BytesWritten, NULL);
-    WriteFile(hPipe, DeviceInstance, Value, &BytesWritten, NULL);
-
-    /* Wait for newdev.dll to finish processing */
-    WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
-
-    /* If the event got signalled, this is success */
-    DeviceInstalled = WaitForSingleObject(hInstallEvent, 0) == WAIT_OBJECT_0;
-
-cleanup:
-    if (hInstallEvent)
-        CloseHandle(hInstallEvent);
-
-    if (hPipe != INVALID_HANDLE_VALUE)
-        CloseHandle(hPipe);
-
-    if (Environment)
-        DestroyEnvironmentBlock(Environment);
-
-    if (ProcessInfo.hProcess)
-        CloseHandle(ProcessInfo.hProcess);
-
-    if (ProcessInfo.hThread)
-        CloseHandle(ProcessInfo.hThread);
-
-    if (!DeviceInstalled)
-    {
-        DPRINT1("InstallDevice failed for DeviceInstance '%ws'\n", DeviceInstance);
-    }
-
-    return DeviceInstalled;
-}
-
-
-static LONG
-ReadRegSzKey(
-    IN HKEY hKey,
-    IN LPCWSTR pszKey,
-    OUT LPWSTR* pValue)
-{
-    LONG rc;
-    DWORD dwType;
-    DWORD cbData = 0;
-    LPWSTR Value;
-
-    if (!pValue)
-        return ERROR_INVALID_PARAMETER;
-
-    *pValue = NULL;
-    rc = RegQueryValueExW(hKey, pszKey, NULL, &dwType, NULL, &cbData);
-    if (rc != ERROR_SUCCESS)
-        return rc;
-    if (dwType != REG_SZ)
-        return ERROR_FILE_NOT_FOUND;
-    Value = HeapAlloc(GetProcessHeap(), 0, cbData + sizeof(WCHAR));
-    if (!Value)
-        return ERROR_NOT_ENOUGH_MEMORY;
-    rc = RegQueryValueExW(hKey, pszKey, NULL, NULL, (LPBYTE)Value, &cbData);
-    if (rc != ERROR_SUCCESS)
-    {
-        HeapFree(GetProcessHeap(), 0, Value);
-        return rc;
-    }
-    /* NULL-terminate the string */
-    Value[cbData / sizeof(WCHAR)] = '\0';
-
-    *pValue = Value;
-    return ERROR_SUCCESS;
-}
-
-
-static BOOL
-SetupIsActive(VOID)
-{
-    HKEY hKey = NULL;
-    DWORD regType, active, size;
-    LONG rc;
-    BOOL ret = FALSE;
-
-    rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\Setup", 0, KEY_QUERY_VALUE, &hKey);
-    if (rc != ERROR_SUCCESS)
-        goto cleanup;
-
-    size = sizeof(DWORD);
-    rc = RegQueryValueExW(hKey, L"SystemSetupInProgress", NULL, &regType, (LPBYTE)&active, &size);
-    if (rc != ERROR_SUCCESS)
-        goto cleanup;
-    if (regType != REG_DWORD || size != sizeof(DWORD))
-        goto cleanup;
-
-    ret = (active != 0);
-
-cleanup:
-    if (hKey != NULL)
-        RegCloseKey(hKey);
-
-    DPRINT("System setup in progress? %S\n", ret ? L"YES" : L"NO");
-
-    return ret;
-}
-
-
-static BOOL
-IsConsoleBoot(VOID)
-{
-    HKEY ControlKey = NULL;
-    LPWSTR SystemStartOptions = NULL;
-    LPWSTR CurrentOption, NextOption; /* Pointers into SystemStartOptions */
-    BOOL ConsoleBoot = FALSE;
-    LONG rc;
-
-    rc = RegOpenKeyExW(
-        HKEY_LOCAL_MACHINE,
-        L"SYSTEM\\CurrentControlSet\\Control",
-        0,
-        KEY_QUERY_VALUE,
-        &ControlKey);
-
-    rc = ReadRegSzKey(ControlKey, L"SystemStartOptions", &SystemStartOptions);
-    if (rc != ERROR_SUCCESS)
-        goto cleanup;
-
-    /* Check for CONSOLE switch in SystemStartOptions */
-    CurrentOption = SystemStartOptions;
-    while (CurrentOption)
-    {
-        NextOption = wcschr(CurrentOption, L' ');
-        if (NextOption)
-            *NextOption = L'\0';
-        if (_wcsicmp(CurrentOption, L"CONSOLE") == 0)
-        {
-            DPRINT("Found %S. Switching to console boot\n", CurrentOption);
-            ConsoleBoot = TRUE;
-            goto cleanup;
-        }
-        CurrentOption = NextOption ? NextOption + 1 : NULL;
-    }
-
-cleanup:
-    if (ControlKey != NULL)
-        RegCloseKey(ControlKey);
-    HeapFree(GetProcessHeap(), 0, SystemStartOptions);
-    return ConsoleBoot;
-}
-
-
-/* Loop to install all queued devices installations */
-static DWORD WINAPI
-DeviceInstallThread(LPVOID lpParameter)
-{
-    PSLIST_ENTRY ListEntry;
-    DeviceInstallParams* Params;
-    BOOL showWizard;
-
-    UNREFERENCED_PARAMETER(lpParameter);
-
-    WaitForSingleObject(hInstallEvent, INFINITE);
-
-    showWizard = !SetupIsActive() && !IsConsoleBoot();
-
-    while (TRUE)
-    {
-        ListEntry = InterlockedPopEntrySList(&DeviceInstallListHead);
-
-        if (ListEntry == NULL)
-        {
-            SetEvent(hNoPendingInstalls);
-            WaitForSingleObject(hDeviceInstallListNotEmpty, INFINITE);
-        }
-        else
-        {
-            ResetEvent(hNoPendingInstalls);
-            Params = CONTAINING_RECORD(ListEntry, DeviceInstallParams, ListEntry);
-            InstallDevice(Params->DeviceIds, showWizard);
-            HeapFree(GetProcessHeap(), 0, Params);
-        }
-    }
-
-    return 0;
-}
-
-
 static DWORD WINAPI
 PnpEventThread(LPVOID lpParameter)
 {