reactos/base/services/umpnpmgr/umpnpmgr.c

3864 lines
91 KiB
C

/*
* ReactOS kernel
* Copyright (C) 2005 ReactOS Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: base/services/umpnpmgr/umpnpmgr.c
* PURPOSE: User-mode Plug and Play manager
* PROGRAMMER: Eric Kohl (eric.kohl@reactos.org)
* Hervé Poussineau (hpoussin@reactos.org)
* Colin Finck (colin@reactos.org)
*/
/* INCLUDES *****************************************************************/
//#define HAVE_SLIST_ENTRY_IMPLEMENTED
#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>
#define NDEBUG
#include <debug.h>
/* GLOBALS ******************************************************************/
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;
#ifdef HAVE_SLIST_ENTRY_IMPLEMENTED
static SLIST_HEADER DeviceInstallListHead;
#else
static LIST_ENTRY DeviceInstallListHead;
#endif
static HANDLE hDeviceInstallListNotEmpty;
typedef struct
{
#ifdef HAVE_SLIST_ENTRY_IMPLEMENTED
SLIST_ENTRY ListEntry;
#else
LIST_ENTRY ListEntry;
#endif
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;
}
}
/* 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;
}
/* Function 10 */
DWORD
WINAPI
PNP_GetDeviceList(
handle_t hBinding,
LPWSTR pszFilter,
LPWSTR Buffer,
PNP_RPC_STRING_LEN *pulLength,
DWORD ulFlags)
{
PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA PlugPlayData;
CONFIGRET ret = CR_SUCCESS;
NTSTATUS Status;
DPRINT("PNP_GetDeviceList() called\n");
if (ulFlags & ~CM_GETIDLIST_FILTER_BITS)
return CR_INVALID_FLAG;
if (pulLength == NULL || pszFilter == NULL)
return CR_INVALID_POINTER;
// if (Buffer == NULL)
// return CR_INVALID_POINTER;
if (ulFlags &
(CM_GETIDLIST_FILTER_BUSRELATIONS |
CM_GETIDLIST_FILTER_POWERRELATIONS |
CM_GETIDLIST_FILTER_REMOVALRELATIONS |
CM_GETIDLIST_FILTER_EJECTRELATIONS))
{
RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
pszFilter);
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 = Buffer;
Status = NtPlugPlayControl(PlugPlayControlQueryDeviceRelations,
(PVOID)&PlugPlayData,
sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA));
if (NT_SUCCESS(Status))
{
*pulLength = PlugPlayData.BufferSize / sizeof(WCHAR);
}
else
{
ret = NtStatusToCrError(Status);
}
}
else if (ulFlags & CM_GETIDLIST_FILTER_SERVICE)
{
ret = CR_CALL_NOT_IMPLEMENTED;
}
else if (ulFlags & CM_GETIDLIST_FILTER_ENUMERATOR)
{
ret = CR_CALL_NOT_IMPLEMENTED;
}
else /* CM_GETIDLIST_FILTER_NONE */
{
ret = CR_CALL_NOT_IMPLEMENTED;
}
return ret;
}
/* Function 11 */
DWORD
WINAPI
PNP_GetDeviceListSize(
handle_t hBinding,
LPWSTR pszFilter,
PNP_RPC_BUFFER_SIZE *pulLength,
DWORD ulFlags)
{
PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA PlugPlayData;
CONFIGRET ret = CR_SUCCESS;
NTSTATUS Status;
DPRINT("PNP_GetDeviceListSize() called\n");
if (ulFlags & ~CM_GETIDLIST_FILTER_BITS)
return CR_INVALID_FLAG;
if (pulLength == NULL || 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))
{
RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
pszFilter);
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);
}
}
else if (ulFlags & CM_GETIDLIST_FILTER_SERVICE)
{
ret = CR_CALL_NOT_IMPLEMENTED;
}
else if (ulFlags & CM_GETIDLIST_FILTER_ENUMERATOR)
{
ret = CR_CALL_NOT_IMPLEMENTED;
}
else /* CM_GETIDLIST_FILTER_NONE */
{
ret = CR_CALL_NOT_IMPLEMENTED;
}
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 VOID
SplitDeviceInstanceID(IN LPWSTR pszDeviceInstanceID,
OUT LPWSTR pszEnumerator,
OUT LPWSTR pszDevice,
OUT LPWSTR pszInstance)
{
WCHAR szLocalDeviceInstanceID[MAX_DEVICE_ID_LEN];
LPWSTR lpEnumerator = NULL;
LPWSTR lpDevice = NULL;
LPWSTR lpInstance = NULL;
LPWSTR ptr;
wcscpy(szLocalDeviceInstanceID, pszDeviceInstanceID);
*pszEnumerator = 0;
*pszDevice = 0;
*pszInstance = 0;
lpEnumerator = szLocalDeviceInstanceID;
ptr = wcschr(lpEnumerator, L'\\');
if (ptr != NULL)
{
*ptr = 0;
lpDevice = ++ptr;
ptr = wcschr(lpDevice, L'\\');
if (ptr != NULL)
{
*ptr = 0;
lpInstance = ++ptr;
}
}
if (lpEnumerator != NULL)
wcscpy(pszEnumerator, lpEnumerator);
if (lpDevice != NULL)
wcscpy(pszDevice, lpDevice);
if (lpInstance != NULL)
wcscpy(pszInstance, lpInstance);
}
static CONFIGRET
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)
{
UNIMPLEMENTED;
return CR_CALL_NOT_IMPLEMENTED;
}
/* Function 57 */
DWORD
WINAPI
PNP_QueryArbitratorFreeSize(
handle_t hBinding,
DWORD *pulSize,
LPWSTR pDeviceID,
RESOURCEID ResourceID,
DWORD ulFlags)
{
UNIMPLEMENTED;
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)
{
#ifdef HAVE_SLIST_ENTRY_IMPLEMENTED
PSLIST_ENTRY ListEntry;
#else
PLIST_ENTRY ListEntry;
#endif
DeviceInstallParams* Params;
BOOL showWizard;
UNREFERENCED_PARAMETER(lpParameter);
WaitForSingleObject(hInstallEvent, INFINITE);
showWizard = !SetupIsActive() && !IsConsoleBoot();
while (TRUE)
{
#ifdef HAVE_SLIST_ENTRY_IMPLEMENTED
ListEntry = InterlockedPopEntrySList(&DeviceInstallListHead);
#else
if ((BOOL)IsListEmpty(&DeviceInstallListHead))
ListEntry = NULL;
else
ListEntry = RemoveHeadList(&DeviceInstallListHead);
#endif
if (ListEntry == NULL)
{
SetEvent(hNoPendingInstalls);
WaitForSingleObject(hDeviceInstallListNotEmpty, INFINITE);
}
else
{
ResetEvent(hNoPendingInstalls);
Params = CONTAINING_RECORD(ListEntry, DeviceInstallParams, ListEntry);
InstallDevice(Params->DeviceIds, showWizard);
}
}
return 0;
}
static DWORD WINAPI
PnpEventThread(LPVOID lpParameter)
{
PPLUGPLAY_EVENT_BLOCK PnpEvent;
ULONG PnpEventSize;
NTSTATUS Status;
RPC_STATUS RpcStatus;
UNREFERENCED_PARAMETER(lpParameter);
PnpEventSize = 0x1000;
PnpEvent = HeapAlloc(GetProcessHeap(), 0, PnpEventSize);
if (PnpEvent == NULL)
return ERROR_OUTOFMEMORY;
for (;;)
{
DPRINT("Calling NtGetPlugPlayEvent()\n");
/* Wait for the next pnp event */
Status = NtGetPlugPlayEvent(0, 0, PnpEvent, PnpEventSize);
/* Resize the buffer for the PnP event if it's too small. */
if (Status == STATUS_BUFFER_TOO_SMALL)
{
PnpEventSize += 0x400;
HeapFree(GetProcessHeap(), 0, PnpEvent);
PnpEvent = HeapAlloc(GetProcessHeap(), 0, PnpEventSize);
if (PnpEvent == NULL)
return ERROR_OUTOFMEMORY;
continue;
}
if (!NT_SUCCESS(Status))
{
DPRINT("NtGetPlugPlayEvent() failed (Status %lx)\n", Status);
break;
}
/* Process the pnp event */
DPRINT("Received PnP Event\n");
if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_ENUMERATED, &RpcStatus))
{
DeviceInstallParams* Params;
DWORD len;
DWORD DeviceIdLength;
DPRINT("Device enumerated: %S\n", PnpEvent->TargetDevice.DeviceIds);
DeviceIdLength = lstrlenW(PnpEvent->TargetDevice.DeviceIds);
if (DeviceIdLength)
{
/* Queue device install (will be dequeued by DeviceInstallThread */
len = FIELD_OFFSET(DeviceInstallParams, DeviceIds) + (DeviceIdLength + 1) * sizeof(WCHAR);
Params = HeapAlloc(GetProcessHeap(), 0, len);
if (Params)
{
wcscpy(Params->DeviceIds, PnpEvent->TargetDevice.DeviceIds);
#ifdef HAVE_SLIST_ENTRY_IMPLEMENTED
InterlockedPushEntrySList(&DeviceInstallListHead, &Params->ListEntry);
#else
InsertTailList(&DeviceInstallListHead, &Params->ListEntry);
#endif
SetEvent(hDeviceInstallListNotEmpty);
}
}
}
else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_ARRIVAL, &RpcStatus))
{
// DWORD dwRecipient;
DPRINT("Device arrival: %S\n", PnpEvent->TargetDevice.DeviceIds);
// dwRecipient = BSM_ALLDESKTOPS | BSM_APPLICATIONS;
// BroadcastSystemMessageW(BSF_POSTMESSAGE,
// &dwRecipient,
// WM_DEVICECHANGE,
// DBT_DEVNODES_CHANGED,
// 0);
SendMessageW(HWND_BROADCAST, WM_DEVICECHANGE, DBT_DEVNODES_CHANGED, 0);
}
else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_EJECT_VETOED, &RpcStatus))
{
DPRINT1("Eject vetoed: %S\n", PnpEvent->TargetDevice.DeviceIds);
}
else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_KERNEL_INITIATED_EJECT, &RpcStatus))
{
DPRINT1("Kernel initiated eject: %S\n", PnpEvent->TargetDevice.DeviceIds);
}
else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_SAFE_REMOVAL, &RpcStatus))
{
// DWORD dwRecipient;
DPRINT1("Safe removal: %S\n", PnpEvent->TargetDevice.DeviceIds);
// dwRecipient = BSM_ALLDESKTOPS | BSM_APPLICATIONS;
// BroadcastSystemMessageW(BSF_POSTMESSAGE,
// &dwRecipient,
// WM_DEVICECHANGE,
// DBT_DEVNODES_CHANGED,
// 0);
SendMessageW(HWND_BROADCAST, WM_DEVICECHANGE, DBT_DEVNODES_CHANGED, 0);
}
else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_SURPRISE_REMOVAL, &RpcStatus))
{
// DWORD dwRecipient;
DPRINT1("Surprise removal: %S\n", PnpEvent->TargetDevice.DeviceIds);
// dwRecipient = BSM_ALLDESKTOPS | BSM_APPLICATIONS;
// BroadcastSystemMessageW(BSF_POSTMESSAGE,
// &dwRecipient,
// WM_DEVICECHANGE,
// DBT_DEVNODES_CHANGED,
// 0);
SendMessageW(HWND_BROADCAST, WM_DEVICECHANGE, DBT_DEVNODES_CHANGED, 0);
}
else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_REMOVAL_VETOED, &RpcStatus))
{
DPRINT1("Removal vetoed: %S\n", PnpEvent->TargetDevice.DeviceIds);
}
else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_REMOVE_PENDING, &RpcStatus))
{
DPRINT1("Removal pending: %S\n", PnpEvent->TargetDevice.DeviceIds);
}
else
{
DPRINT1("Unknown event, GUID {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
PnpEvent->EventGuid.Data1, PnpEvent->EventGuid.Data2, PnpEvent->EventGuid.Data3,
PnpEvent->EventGuid.Data4[0], PnpEvent->EventGuid.Data4[1], PnpEvent->EventGuid.Data4[2],
PnpEvent->EventGuid.Data4[3], PnpEvent->EventGuid.Data4[4], PnpEvent->EventGuid.Data4[5],
PnpEvent->EventGuid.Data4[6], PnpEvent->EventGuid.Data4[7]);
}
/* Dequeue the current pnp event and signal the next one */
NtPlugPlayControl(PlugPlayControlUserResponse, NULL, 0);
}
HeapFree(GetProcessHeap(), 0, PnpEvent);
return ERROR_SUCCESS;
}
static VOID
UpdateServiceStatus(DWORD dwState)
{
ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ServiceStatus.dwCurrentState = dwState;
ServiceStatus.dwControlsAccepted = 0;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
if (dwState == SERVICE_START_PENDING ||
dwState == SERVICE_STOP_PENDING ||
dwState == SERVICE_PAUSE_PENDING ||
dwState == SERVICE_CONTINUE_PENDING)
ServiceStatus.dwWaitHint = 10000;
else
ServiceStatus.dwWaitHint = 0;
SetServiceStatus(ServiceStatusHandle,
&ServiceStatus);
}
static DWORD WINAPI
ServiceControlHandler(DWORD dwControl,
DWORD dwEventType,
LPVOID lpEventData,
LPVOID lpContext)
{
DPRINT1("ServiceControlHandler() called\n");
switch (dwControl)
{
case SERVICE_CONTROL_STOP:
DPRINT1(" SERVICE_CONTROL_STOP received\n");
/* Stop listening to RPC Messages */
RpcMgmtStopServerListening(NULL);
UpdateServiceStatus(SERVICE_STOPPED);
return ERROR_SUCCESS;
case SERVICE_CONTROL_PAUSE:
DPRINT1(" SERVICE_CONTROL_PAUSE received\n");
UpdateServiceStatus(SERVICE_PAUSED);
return ERROR_SUCCESS;
case SERVICE_CONTROL_CONTINUE:
DPRINT1(" SERVICE_CONTROL_CONTINUE received\n");
UpdateServiceStatus(SERVICE_RUNNING);
return ERROR_SUCCESS;
case SERVICE_CONTROL_INTERROGATE:
DPRINT1(" SERVICE_CONTROL_INTERROGATE received\n");
SetServiceStatus(ServiceStatusHandle,
&ServiceStatus);
return ERROR_SUCCESS;
case SERVICE_CONTROL_SHUTDOWN:
DPRINT1(" SERVICE_CONTROL_SHUTDOWN received\n");
/* Stop listening to RPC Messages */
RpcMgmtStopServerListening(NULL);
UpdateServiceStatus(SERVICE_STOPPED);
return ERROR_SUCCESS;
default :
DPRINT1(" Control %lu received\n", dwControl);
return ERROR_CALL_NOT_IMPLEMENTED;
}
}
VOID WINAPI
ServiceMain(DWORD argc, LPTSTR *argv)
{
HANDLE hThread;
DWORD dwThreadId;
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
DPRINT("ServiceMain() called\n");
ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
ServiceControlHandler,
NULL);
if (!ServiceStatusHandle)
{
DPRINT1("RegisterServiceCtrlHandlerExW() failed! (Error %lu)\n", GetLastError());
return;
}
UpdateServiceStatus(SERVICE_START_PENDING);
hThread = CreateThread(NULL,
0,
PnpEventThread,
NULL,
0,
&dwThreadId);
if (hThread != NULL)
CloseHandle(hThread);
hThread = CreateThread(NULL,
0,
RpcServerThread,
NULL,
0,
&dwThreadId);
if (hThread != NULL)
CloseHandle(hThread);
hThread = CreateThread(NULL,
0,
DeviceInstallThread,
NULL,
0,
&dwThreadId);
if (hThread != NULL)
CloseHandle(hThread);
UpdateServiceStatus(SERVICE_RUNNING);
DPRINT("ServiceMain() done\n");
}
static DWORD
InitializePnPManager(VOID)
{
BOOLEAN OldValue;
DWORD dwError;
DPRINT("UMPNPMGR: InitializePnPManager() started\n");
/* We need this privilege for using CreateProcessAsUserW */
RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, TRUE, FALSE, &OldValue);
hInstallEvent = CreateEventW(NULL, TRUE, SetupIsActive()/*FALSE*/, NULL);
if (hInstallEvent == NULL)
{
dwError = GetLastError();
DPRINT1("Could not create the Install Event! (Error %lu)\n", dwError);
return dwError;
}
hDeviceInstallListNotEmpty = CreateEventW(NULL, FALSE, FALSE, NULL);
if (hDeviceInstallListNotEmpty == NULL)
{
dwError = GetLastError();
DPRINT1("Could not create the Event! (Error %lu)\n", dwError);
return dwError;
}
hNoPendingInstalls = CreateEventW(NULL,
TRUE,
FALSE,
L"Global\\PnP_No_Pending_Install_Events");
if (hNoPendingInstalls == NULL)
{
dwError = GetLastError();
DPRINT1("Could not create the Event! (Error %lu)\n", dwError);
return dwError;
}
#ifdef HAVE_SLIST_ENTRY_IMPLEMENTED
InitializeSListHead(&DeviceInstallListHead);
#else
InitializeListHead(&DeviceInstallListHead);
#endif
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"System\\CurrentControlSet\\Enum",
0,
KEY_ALL_ACCESS,
&hEnumKey);
if (dwError != ERROR_SUCCESS)
{
DPRINT1("Could not open the Enum Key! (Error %lu)\n", dwError);
return dwError;
}
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"System\\CurrentControlSet\\Control\\Class",
0,
KEY_ALL_ACCESS,
&hClassKey);
if (dwError != ERROR_SUCCESS)
{
DPRINT1("Could not open the Class Key! (Error %lu)\n", dwError);
return dwError;
}
DPRINT("UMPNPMGR: InitializePnPManager() done\n");
return 0;
}
BOOL WINAPI
DllMain(HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hinstDLL);
InitializePnPManager();
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
/* EOF */