[PATCH v2 1/2] ntoskrnl.exe: Implement IoRegisterDeviceInterface
v2: use setupapi functions as suggested by Zebediah Figura Signed-off-by: Aric Stewart <aric(a)codeweavers.com> --- dlls/ntoskrnl.exe/Makefile.in | 2 +- dlls/ntoskrnl.exe/ntoskrnl.c | 125 ++++++++++++++++++++++++++++++++++++ dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 2 +- include/ddk/wdm.h | 1 + 4 files changed, 128 insertions(+), 2 deletions(-)
On 03/10/18 10:02, Aric Stewart wrote:
+static NTSTATUS get_instance_id(DEVICE_OBJECT *device, WCHAR **instance_id) +{ + WCHAR *id, *ptr; + NTSTATUS status; + + status = get_device_id( device, BusQueryInstanceID, &id ); + if (status != STATUS_SUCCESS) + { + FIXME( "failed to get device ID\n" ); + return status; + }
Would ERR be more appropriate?
+ + struprW( id ); + ptr = strchrW( id, '\\' ); + + while (ptr) + { + *ptr = '#'; + ptr = strchrW( id,'\\' ); + }
Stylistic choice, perhaps, but maybe this would be simpler? while ((ptr = strchrW( id, '\\' ))) *ptr = '#';
+ + *instance_id = id; + return STATUS_SUCCESS; +} + + +/***************************************************** + * IoRegisterDeviceInterface(NTOSKRNL.EXE.@) + */ +NTSTATUS WINAPI IoRegisterDeviceInterface(DEVICE_OBJECT *device, const GUID *class_guid, UNICODE_STRING *reference_string, UNICODE_STRING *symbolic_link) +{ + WCHAR *instance_id; + NTSTATUS status = STATUS_SUCCESS; + HDEVINFO infoset; + WCHAR *referenceW = NULL; + SP_DEVINFO_DATA devInfo; + SP_DEVICE_INTERFACE_DATA infoData; + SP_DEVICE_INTERFACE_DETAIL_DATA_W *data; + BOOL rc; + + TRACE( "(%p, %s, %s, %p)\n", device, debugstr_guid(class_guid), debugstr_us(reference_string), symbolic_link ); + + if (reference_string != NULL) + referenceW = reference_string->Buffer; + + infoset = SetupDiGetClassDevsW(class_guid, referenceW, NULL, DIGCF_DEVICEINTERFACE); + + status = get_instance_id( device, &instance_id ); + if (status != STATUS_SUCCESS) + { + ERR( "Failed to generate Instance ID\n" ); + return status; + } + + devInfo.cbSize = sizeof(devInfo); + rc = SetupDiCreateDeviceInfoW( infoset, instance_id, class_guid, NULL, NULL, 0, &devInfo ); + if (rc == 0) + { + if (GetLastError() == ERROR_DEVINST_ALREADY_EXISTS) + { + DWORD required; + DWORD index = 0; + DWORD size = strlenW(instance_id) + 2; + WCHAR *id = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); + do + { + rc = SetupDiEnumDeviceInfo( infoset, index, &devInfo ); + if (IsEqualGUID(&devInfo.ClassGuid, class_guid)) + { + BOOL check; + check = SetupDiGetDeviceInstanceIdW(infoset, &devInfo, id, size, &required); + if (check && strcmpW(id, instance_id) == 0) + break; + } + index++; + } while (rc);
I guess it maybe shouldn't block this patch, but it would be good to implement SetupDiOpenDeviceInfo() at some point; it would result in much cleaner code on both sides.
+ + HeapFree(GetProcessHeap(), 0, id); + if (!rc) + { + ERR( "Failed to find Device\n" ); + HeapFree( GetProcessHeap(), 0, instance_id ); + return STATUS_UNSUCCESSFUL; + } + } + else + { + ERR( "Failed to Create Device\n" ); + HeapFree( GetProcessHeap(), 0, instance_id ); + return STATUS_UNSUCCESSFUL; + } + } + HeapFree( GetProcessHeap(), 0, instance_id ); + + infoData.cbSize = sizeof(infoData); + rc = SetupDiCreateDeviceInterfaceW(infoset, &devInfo, class_guid, NULL, 0, &infoData); + if (!rc) + { + ERR("Failed to create device interface\n"); + return STATUS_UNSUCCESSFUL; + } + + data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY , sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + 1000);
This seems kind of ugly; can't we just call it twice?
+ data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); + + rc = SetupDiGetDeviceInterfaceDetailW(infoset, &infoData, data, 500, NULL, NULL); + if (!rc) + { + ERR("Failed Get device details\n"); + return STATUS_UNSUCCESSFUL; + } + + data->DevicePath[1] = '?'; + ERR("Device path %s\n",debugstr_w(data->DevicePath));
Leftover debug string?
+ + if (symbolic_link) + RtlCreateUnicodeString( symbolic_link, data->DevicePath); + + HeapFree( GetProcessHeap(), 0, data ); + + return status; +} + + /*********************************************************************** * IoRegisterDriverReinitialization (NTOSKRNL.EXE.@) */ diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec index 422d575926..1a6139de61 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec +++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec @@ -428,7 +428,7 @@ @ stub IoReadPartitionTableEx @ stub IoReadTransferCount @ stub IoRegisterBootDriverReinitialization -@ stub IoRegisterDeviceInterface +@ stdcall IoRegisterDeviceInterface(ptr ptr ptr ptr) @ stdcall IoRegisterDriverReinitialization(ptr ptr ptr) @ stdcall IoRegisterFileSystem(ptr) @ stub IoRegisterFsRegistrationChange diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h index 0cd1673dbe..cd057d5a9f 100644 --- a/include/ddk/wdm.h +++ b/include/ddk/wdm.h @@ -1405,6 +1405,7 @@ PDEVICE_OBJECT WINAPI IoGetRelatedDeviceObject(PFILE_OBJECT); void WINAPI IoInitializeIrp(IRP*,USHORT,CCHAR); VOID WINAPI IoInitializeRemoveLockEx(PIO_REMOVE_LOCK,ULONG,ULONG,ULONG,ULONG); void WINAPI IoInvalidateDeviceRelations(PDEVICE_OBJECT,DEVICE_RELATION_TYPE); +NTSTATUS WINAPI IoRegisterDeviceInterface(PDEVICE_OBJECT,const GUID*,PUNICODE_STRING,PUNICODE_STRING); void WINAPI IoReleaseCancelSpinLock(KIRQL); NTSTATUS WINAPI IoSetDeviceInterfaceState(UNICODE_STRING*,BOOLEAN); NTSTATUS WINAPI IoWMIRegistrationControl(PDEVICE_OBJECT,ULONG);
participants (2)
-
Aric Stewart -
Zebediah Figura