/* GLOBALS ******************************************************************/
-static VOID CALLBACK
-ServiceMain(DWORD argc, LPTSTR *argv);
-
-static SERVICE_TABLE_ENTRY ServiceTable[2] =
+static VOID CALLBACK ServiceMain(DWORD argc, LPWSTR *argv);
+static WCHAR ServiceName[] = L"PlugPlay";
+static SERVICE_TABLE_ENTRYW ServiceTable[] =
{
- {TEXT("PlugPlay"), ServiceMain},
+ {ServiceName, ServiceMain},
{NULL, NULL}
};
+static SERVICE_STATUS_HANDLE ServiceStatusHandle;
+static SERVICE_STATUS ServiceStatus;
+
static WCHAR szRootDeviceId[] = L"HTREE\\ROOT\\0";
static HKEY hEnumKey = NULL;
RpcServerThread(LPVOID lpParameter)
{
RPC_STATUS Status;
+ BOOLEAN RegisteredProtSeq = FALSE;
UNREFERENCED_PARAMETER(lpParameter);
DPRINT("RpcServerThread() called\n");
+#if 0
+ /* XP-compatible protocol sequence/endpoint */
Status = RpcServerUseProtseqEpW(L"ncacn_np",
20,
- L"\\pipe\\umpnpmgr",
+ L"\\pipe\\ntsvcs",
NULL); // Security descriptor
- if (Status != RPC_S_OK)
- {
+ if (Status == RPC_S_OK)
+ RegisteredProtSeq = TRUE;
+ else
DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
+#endif
+
+ /* Vista-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,
handle_t hBinding)
{
UNREFERENCED_PARAMETER(hBinding);
- UNIMPLEMENTED;
- return CR_CALL_NOT_IMPLEMENTED;
+ return CR_SUCCESS;
}
handle_t hBinding)
{
UNREFERENCED_PARAMETER(hBinding);
- UNIMPLEMENTED;
- return CR_CALL_NOT_IMPLEMENTED;
+ return CR_SUCCESS;
}
PLUGPLAY_CONTROL_PROPERTY_DATA PlugPlayData;
CONFIGRET ret = CR_SUCCESS;
LPWSTR lpValueName = NULL;
- HKEY hKey = 0;
+ HKEY hKey = NULL;
+ LONG lError;
NTSTATUS Status;
UNREFERENCED_PARAMETER(hBinding);
- UNREFERENCED_PARAMETER(ulFlags);
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 = NULL;
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:
+ lpValueName = NULL;
+ break;
+
+ case CM_DRP_UI_NUMBER_DESC_FORMAT:
+ lpValueName = L"UINumberDescFormat";
+ break;
+
+ case CM_DRP_DEVICE_POWER_DATA:
+ lpValueName = NULL;
+ break;
+
+ case CM_DRP_REMOVAL_POLICY:
+ lpValueName = NULL;
+ break;
+
+ case CM_DRP_REMOVAL_POLICY_HW_DEFAULT:
+ lpValueName = NULL;
+ break;
+
+ case CM_DRP_REMOVAL_POLICY_OVERRIDE:
+ lpValueName = L"RemovalPolicy";
+ break;
+
+ case CM_DRP_INSTALL_STATE:
+ lpValueName = NULL;
+ break;
+
+#if (WINVER >= _WIN32_WINNT_WS03)
+ case CM_DRP_LOCATION_PATHS:
+ lpValueName = NULL;
+ break;
+#endif
+
+#if (WINVER >= _WIN32_WINNT_WIN7)
+ case CM_DRP_BASE_CONTAINERID:
+ lpValueName = NULL;
+ break;
+#endif
+
default:
- return CR_INVALID_PROPERTY;
+ ret = CR_INVALID_PROPERTY;
+ goto done;
}
DPRINT("Value name: %S\n", lpValueName);
if (lpValueName)
{
/* Retrieve information from the Registry */
- if (RegOpenKeyExW(hEnumKey,
- pDeviceID,
- 0,
- KEY_ALL_ACCESS,
- &hKey))
- return CR_INVALID_DEVNODE;
-
- if (RegQueryValueExW(hKey,
- lpValueName,
- NULL,
- pulRegDataType,
- Buffer,
- pulLength))
- ret = CR_REGISTRY_ERROR;
-
- /* FIXME: Check buffer size */
+ lError = RegOpenKeyExW(hEnumKey,
+ pDeviceID,
+ 0,
+ KEY_QUERY_VALUE,
+ &hKey);
+ if (lError != ERROR_SUCCESS)
+ {
+ hKey = NULL;
+ *pulLength = 0;
+ ret = CR_INVALID_DEVNODE;
+ goto done;
+ }
- RegCloseKey(hKey);
+ lError = RegQueryValueExW(hKey,
+ lpValueName,
+ NULL,
+ pulRegDataType,
+ Buffer,
+ pulLength);
+ if (lError == ERROR_MORE_DATA)
+ {
+ ret = CR_BUFFER_SMALL;
+ }
+ else
+ {
+ *pulLength = 0;
+ ret = CR_NO_SUCH_VALUE;
+ }
}
else
{
switch (ulProperty)
{
-#if 0
case CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME:
- PlugPlayData.Property = DevicePropertyPhysicalDeviceObjectName;
+ PlugPlayData.Property = 0xb; // DevicePropertyPhysicalDeviceObjectName;
break;
case CM_DRP_UI_NUMBER:
- PlugPlayData.Property = DevicePropertyUINumber;
+ PlugPlayData.Property = 0x11; // DevicePropertyUINumber;
break;
case CM_DRP_BUSTYPEGUID:
- PlugPlayData.Property = DevicePropertyBusTypeGuid;
+ PlugPlayData.Property = 0xc; // DevicePropertyBusTypeGuid;
break;
case CM_DRP_LEGACYBUSTYPE:
- PlugPlayData.Property = DevicePropertyLegacyBusType;
+ PlugPlayData.Property = 0xd; // DevicePropertyLegacyBusType;
break;
case CM_DRP_BUSNUMBER:
- PlugPlayData.Property = DevicePropertyBusNumber;
+ PlugPlayData.Property = 0xe; // DevicePropertyBusNumber;
break;
-#endif
case CM_DRP_ENUMERATOR_NAME:
- PlugPlayData.Property = 15; //DevicePropertyEnumeratorName;
+ PlugPlayData.Property = 0xf; // DevicePropertyEnumeratorName;
+ break;
+
+ case CM_DRP_ADDRESS:
+ PlugPlayData.Property = 0x10; // DevicePropertyAddress;
break;
+#if 0
+ /* FIXME: This property is not supported by IoGetDeviceProperty */
+ case CM_DRP_DEVICE_POWER_DATA:
+#endif
+
+ case CM_DRP_REMOVAL_POLICY:
+ PlugPlayData.Property = 0x12; // DevicePropertyRemovalPolicy
+ break;
+
+#if 0
+ /* FIXME: This property is not supported by IoGetDeviceProperty */
+ case CM_DRP_REMOVAL_POLICY_HW_DEFAULT:
+#endif
+
+ case CM_DRP_INSTALL_STATE:
+ PlugPlayData.Property = 0x12; // DevicePropertyInstallState;
+ break;
+
+#if 0
+ /* FIXME: This property is not supported by IoGetDeviceProperty */
+#if (WINVER >= _WIN32_WINNT_WS03)
+ case CM_DRP_LOCATION_PATHS:
+#endif
+#endif
+
+#if (WINVER >= _WIN32_WINNT_WIN7)
+ case CM_DRP_BASE_CONTAINERID:
+ PlugPlayData.Property = 0x16; // DevicePropertyContainerID;
+ break;
+#endif
+
default:
return CR_INVALID_PROPERTY;
}
}
}
+done:;
+ *pulTransferLen = (ret != CR_SUCCESS) ? 0 : *pulLength;
+
+ if (hKey != NULL)
+ RegCloseKey(hKey);
+
DPRINT("PNP_GetDeviceRegProp() done (returns %lx)\n", ret);
return ret;
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;
}
if (RegOpenKeyExW(hEnumKey,
pDeviceId,
0,
- KEY_ALL_ACCESS, /* FIXME: so much? */
+ KEY_SET_VALUE,
&hKey))
return CR_INVALID_DEVNODE;
}
+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 PNP_CreateDevInst(
handle_t hBinding,
PNP_RPC_STRING_LEN ulLength,
DWORD ulFlags)
{
- UNIMPLEMENTED;
- return CR_CALL_NOT_IMPLEMENTED;
+ CONFIGRET ret = CR_SUCCESS;
+
+ DPRINT("PNP_CreateDevInst: %S\n", pszDeviceID);
+
+ if (ulFlags & CM_CREATE_DEVNODE_GENERATE_ID)
+ {
+ /* FIXME */
+ DPRINT1("CM_CREATE_DEVNODE_GENERATE_ID support not implemented yet!\n", ret);
+ ret = CR_CALL_NOT_IMPLEMENTED;
+ goto done;
+ }
+
+ /* Create the device instance */
+ ret = CreateDeviceInstance(pszDeviceID);
+
+done:;
+ DPRINT("PNP_CreateDevInst() done (returns %lx)\n", ret);
+
+ return ret;
}
/* Function 56 */
DWORD PNP_QueryArbitratorFreeData(
- handle_t hBinding)
+ handle_t hBinding,
+ BYTE *pData,
+ DWORD DataLen,
+ LPWSTR pDeviceID,
+ RESOURCEID ResourceID,
+ DWORD ulFlags)
{
UNIMPLEMENTED;
return CR_CALL_NOT_IMPLEMENTED;
/* Function 57 */
DWORD PNP_QueryArbitratorFreeSize(
- handle_t hBinding)
+ handle_t hBinding,
+ DWORD *pulSize,
+ LPWSTR pDeviceID,
+ RESOURCEID ResourceID,
+ DWORD ulFlags)
{
UNIMPLEMENTED;
return CR_CALL_NOT_IMPLEMENTED;
handle_t hBinding,
DWORD ulFlags)
{
- UNIMPLEMENTED;
return CR_CALL_NOT_IMPLEMENTED;
}
static BOOL
InstallDevice(PCWSTR DeviceInstance, BOOL ShowWizard)
{
- PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData;
- NTSTATUS Status;
BOOL DeviceInstalled = FALSE;
DWORD BytesWritten;
DWORD Value;
PROCESS_INFORMATION ProcessInfo;
STARTUPINFOW StartupInfo;
UUID RandomUuid;
+ HKEY DeviceKey;
/* The following lengths are constant (see below), they cannot overflow */
WCHAR CommandLine[116];
ZeroMemory(&ProcessInfo, sizeof(ProcessInfo));
- RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
- DeviceInstance);
- PlugPlayData.Operation = 0; /* Get status */
-
- /* Get device status */
- Status = NtPlugPlayControl(PlugPlayControlDeviceStatus,
- (PVOID)&PlugPlayData,
- sizeof(PLUGPLAY_CONTROL_STATUS_DATA));
- if (!NT_SUCCESS(Status))
+ if (RegOpenKeyExW(hEnumKey,
+ DeviceInstance,
+ 0,
+ KEY_QUERY_VALUE,
+ &DeviceKey) == ERROR_SUCCESS)
{
- DPRINT1("NtPlugPlayControl('%S') failed with status 0x%08lx\n", DeviceInstance, Status);
- return FALSE;
- }
+ if (RegQueryValueExW(DeviceKey,
+ L"ClassGUID",
+ NULL,
+ NULL,
+ NULL,
+ NULL) == ERROR_SUCCESS)
+ {
+ DPRINT("No need to install: %S\n", DeviceInstance);
+ RegCloseKey(DeviceKey);
+ return TRUE;
+ }
- if ((PlugPlayData.DeviceStatus & (DNF_STARTED | DNF_START_FAILED)) != 0)
- {
- /* Device is already started, or disabled due to some problem. Don't install it */
- DPRINT("No need to install '%S'\n", DeviceInstance);
- return TRUE;
+ RegCloseKey(DeviceKey);
}
+ DPRINT1("Installing: %S\n", DeviceInstance);
+
/* Create a random UUID for the named pipe */
UuidCreate(&RandomUuid);
swprintf(UuidString, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
if(ProcessInfo.hThread)
CloseHandle(ProcessInfo.hThread);
+ DPRINT1("Success? %d\n", DeviceInstalled);
+
return DeviceInstalled;
}
DWORD len;
DWORD DeviceIdLength;
- DPRINT("Device enumerated: %S\n", PnpEvent->TargetDevice.DeviceIds);
+ DPRINT1("Device enumerated: %S\n", PnpEvent->TargetDevice.DeviceIds);
DeviceIdLength = lstrlenW(PnpEvent->TargetDevice.DeviceIds);
if (DeviceIdLength)
}
else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_ARRIVAL, &RpcStatus))
{
- DPRINT("Device arrival: %S\n", PnpEvent->TargetDevice.DeviceIds);
+ DPRINT1("Device arrival: %S\n", PnpEvent->TargetDevice.DeviceIds);
/* FIXME: ? */
}
else
}
+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");
+ 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");
+ UpdateServiceStatus(SERVICE_STOPPED);
+ return ERROR_SUCCESS;
+
+ default :
+ DPRINT1(" Control %lu received\n");
+ return ERROR_CALL_NOT_IMPLEMENTED;
+ }
+}
+
+
static VOID CALLBACK
ServiceMain(DWORD argc, LPTSTR *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,
if (hThread != NULL)
CloseHandle(hThread);
+ UpdateServiceStatus(SERVICE_RUNNING);
+
DPRINT("ServiceMain() done\n");
}