277 lines
7.1 KiB
C
277 lines
7.1 KiB
C
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1998 - 1998
|
|
//
|
|
// File: test.c
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
//
|
|
// This file contains functions that are used for testing the ParClass driver.
|
|
//
|
|
// This file differs from debug.c in that these functions may
|
|
// also be available in a fre build
|
|
//
|
|
|
|
#include "pch.h"
|
|
#include "test.h"
|
|
|
|
NTSTATUS
|
|
MfSendPnpIrp(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIO_STACK_LOCATION Location,
|
|
OUT PULONG_PTR Information OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This builds and send a pnp irp to a device.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - The a device in the device stack the irp is to be sent to -
|
|
the top of the device stack is always found and the irp sent there first.
|
|
|
|
Location - The initial stack location to use - contains the IRP minor code
|
|
and any parameters
|
|
|
|
Information - If provided contains the final value of the irps information
|
|
field.
|
|
|
|
Return Value:
|
|
|
|
The final status of the completed irp or an error if the irp couldn't be sent
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
PIRP irp = NULL;
|
|
PIO_STACK_LOCATION irpStack;
|
|
PDEVICE_OBJECT targetDevice = NULL;
|
|
KEVENT irpCompleted;
|
|
IO_STATUS_BLOCK statusBlock;
|
|
|
|
ASSERT(Location->MajorFunction == IRP_MJ_PNP);
|
|
|
|
//
|
|
// Find out where we are sending the irp
|
|
//
|
|
|
|
targetDevice = IoGetAttachedDeviceReference(DeviceObject);
|
|
|
|
//
|
|
// Get an IRP
|
|
//
|
|
|
|
KeInitializeEvent(&irpCompleted, SynchronizationEvent, FALSE);
|
|
|
|
irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
|
|
targetDevice,
|
|
NULL, // Buffer
|
|
0, // Length
|
|
0, // StartingOffset
|
|
&irpCompleted,
|
|
&statusBlock
|
|
);
|
|
|
|
|
|
if (!irp) {
|
|
goto cleanup;
|
|
}
|
|
|
|
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
irp->IoStatus.Information = 0;
|
|
|
|
//
|
|
// Initialize the stack location
|
|
//
|
|
|
|
irpStack = IoGetNextIrpStackLocation(irp);
|
|
|
|
ASSERT(irpStack->MajorFunction == IRP_MJ_PNP);
|
|
|
|
irpStack->MinorFunction = Location->MinorFunction;
|
|
irpStack->Parameters = Location->Parameters;
|
|
|
|
//
|
|
// Call the driver and wait for completion
|
|
//
|
|
|
|
status = IoCallDriver(targetDevice, irp);
|
|
|
|
if (status == STATUS_PENDING) {
|
|
|
|
KeWaitForSingleObject(&irpCompleted, Executive, KernelMode, FALSE, NULL);
|
|
status = statusBlock.Status;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Return the information
|
|
//
|
|
|
|
if (ARGUMENT_PRESENT(Information)) {
|
|
*Information = statusBlock.Information;
|
|
}
|
|
|
|
ObDereferenceObject(targetDevice);
|
|
|
|
ASSERT(status == STATUS_PENDING || status == statusBlock.Status);
|
|
|
|
return statusBlock.Status;
|
|
|
|
cleanup:
|
|
|
|
if (targetDevice) {
|
|
ObDereferenceObject(targetDevice);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
regTst(PDEVICE_OBJECT PortDeviceObject) {
|
|
NTSTATUS status;
|
|
PIRP irp;
|
|
PDEVICE_OBJECT pdo;
|
|
IO_STACK_LOCATION request;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
ULONG_PTR info;
|
|
HANDLE handle;
|
|
PKEY_VALUE_FULL_INFORMATION buffer;
|
|
ULONG bufferLength;
|
|
ULONG resultLength;
|
|
PWSTR valueNameWstr;
|
|
UNICODE_STRING valueName;
|
|
PWSTR portName;
|
|
|
|
|
|
|
|
///
|
|
|
|
// RtlZeroMemory(&request, sizeof(IO_STACK_LOCATION));
|
|
|
|
request.MajorFunction = IRP_MJ_PNP;
|
|
request.MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
|
|
request.Parameters.QueryDeviceRelations.Type = TargetDeviceRelation;
|
|
|
|
status = MfSendPnpIrp(PortDeviceObject, &request, &info);
|
|
if( !NT_SUCCESS(status) ) {
|
|
return;
|
|
}
|
|
|
|
pdo = ((PDEVICE_RELATIONS)info)->Objects[0];
|
|
ExFreePool((PVOID)info);
|
|
|
|
if( !pdo ) {
|
|
// NULL pdo?, bail out
|
|
return;
|
|
}
|
|
|
|
status = IoOpenDeviceRegistryKey(pdo, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_ALL, &handle);
|
|
|
|
if( !NT_SUCCESS(status) ) {
|
|
// unable to open key, bail out
|
|
return;
|
|
}
|
|
|
|
//
|
|
// we have a handle to the registry key
|
|
//
|
|
// loop trying to read registry value until either we succeed or
|
|
// we get a hard failure, grow the result buffer as needed
|
|
//
|
|
|
|
bufferLength = 0; // we will ask how large a buffer we need
|
|
buffer = NULL;
|
|
valueNameWstr = L"PortName";
|
|
RtlInitUnicodeString(&valueName, valueNameWstr);
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
|
|
while(status == STATUS_BUFFER_TOO_SMALL) {
|
|
|
|
status = ZwQueryValueKey(handle,
|
|
&valueName,
|
|
KeyValueFullInformation,
|
|
buffer,
|
|
bufferLength,
|
|
&resultLength);
|
|
|
|
if(status == STATUS_BUFFER_TOO_SMALL) {
|
|
//
|
|
// buffer too small, free it and allocate a larger buffer
|
|
//
|
|
if(buffer) ExFreePool(buffer);
|
|
buffer = ExAllocatePool(PagedPool, resultLength);
|
|
bufferLength = resultLength;
|
|
if(!buffer) {
|
|
// unable to allocate pool, clean up and exit
|
|
ZwClose(handle);
|
|
return;
|
|
}
|
|
}
|
|
|
|
} // end while BUFFER_TOO_SMALL
|
|
|
|
//
|
|
// query is complete
|
|
//
|
|
|
|
|
|
// write something new as a test
|
|
{
|
|
UNICODE_STRING unicodeName;
|
|
ULONG data=0x0fa305ff;
|
|
RtlInitUnicodeString(&unicodeName, L"TestNameOKtoDelete");
|
|
status = ZwSetValueKey(handle, &unicodeName, 0, REG_DWORD, &data, sizeof(ULONG));
|
|
// ParDumpV( ("ZwSetValueKey returned status=%x\n", status) );
|
|
}
|
|
|
|
|
|
// no longer need the handle so close it
|
|
ZwClose(handle);
|
|
|
|
// check the status of our query
|
|
if( !NT_SUCCESS(status) ) {
|
|
if(buffer) ExFreePool(buffer);
|
|
return;
|
|
}
|
|
|
|
// sanity check our result
|
|
if( (buffer->Type != REG_SZ) || (!buffer->DataLength) ) {
|
|
// ParDumpV( (" - either bogus PortName data type or zero length\n", status) );
|
|
ExFreePool(buffer); // query succeeded, so we know we have a buffer
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// result looks ok, copy PortName to its own allocation of the proper size
|
|
// and return a pointer to it
|
|
//
|
|
|
|
portName = ExAllocatePool(PagedPool, buffer->DataLength);
|
|
if(!portName) {
|
|
// unable to allocate pool, clean up and exit
|
|
// ParDumpV( (" - unable to allocate pool to hold PortName(SymbolicLinkName)\n") );
|
|
ExFreePool(buffer);
|
|
return;
|
|
}
|
|
|
|
RtlCopyMemory(portName, (PUCHAR)buffer + buffer->DataOffset, buffer->DataLength);
|
|
|
|
// ParDumpV( ("fred: PortName== <%S>\n",portName) );
|
|
|
|
ExFreePool(portName);
|
|
ExFreePool(buffer);
|
|
}
|