Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

896 lines
26 KiB

//---------------------------------------------------------------------------
//
// Module: notify.cpp
//
// Description:
//
//
//@@BEGIN_MSINTERNAL
// Development Team:
// Mike McLaughlin
//
// History: Date Author Comment
//
// To Do: Date Author Comment
//
//@@END_MSINTERNAL
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (c) 1996-1999 Microsoft Corporation. All Rights Reserved.
//
//---------------------------------------------------------------------------
#include "common.h"
//
// Include safe string library for safe string manipulation.
//
#define STRSAFE_NO_DEPRECATE // Use safe and unsafe functions interchangeably.
#include "strsafe.h"
#define DEVICE_NAME_TAG L"\\\\?\\"
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
CONST GUID *apguidCategories[] = {
&KSCATEGORY_AUDIO,
&KSCATEGORY_AUDIO_GFX,
&KSCATEGORY_TOPOLOGY,
&KSCATEGORY_BRIDGE,
&KSCATEGORY_RENDER,
&KSCATEGORY_CAPTURE,
&KSCATEGORY_MIXER,
&KSCATEGORY_DATATRANSFORM,
&KSCATEGORY_ACOUSTIC_ECHO_CANCEL,
&KSCATEGORY_INTERFACETRANSFORM,
&KSCATEGORY_MEDIUMTRANSFORM,
&KSCATEGORY_DATACOMPRESSOR,
&KSCATEGORY_DATADECOMPRESSOR,
&KSCATEGORY_COMMUNICATIONSTRANSFORM,
&KSCATEGORY_SPLITTER,
&KSCATEGORY_AUDIO_SPLITTER,
&KSCATEGORY_SYNTHESIZER,
&KSCATEGORY_DRM_DESCRAMBLE,
&KSCATEGORY_MICROPHONE_ARRAY_PROCESSOR,
};
ULONG aulFilterType[] = {
FILTER_TYPE_AUDIO,
FILTER_TYPE_GFX,
FILTER_TYPE_TOPOLOGY,
FILTER_TYPE_BRIDGE,
FILTER_TYPE_RENDERER,
FILTER_TYPE_CAPTURER,
FILTER_TYPE_MIXER,
FILTER_TYPE_DATA_TRANSFORM,
FILTER_TYPE_AEC,
FILTER_TYPE_INTERFACE_TRANSFORM,
FILTER_TYPE_MEDIUM_TRANSFORM,
FILTER_TYPE_DATA_TRANSFORM,
FILTER_TYPE_DATA_TRANSFORM,
FILTER_TYPE_COMMUNICATION_TRANSFORM,
FILTER_TYPE_SPLITTER,
FILTER_TYPE_SPLITTER,
FILTER_TYPE_SYNTHESIZER,
FILTER_TYPE_DRM_DESCRAMBLE,
FILTER_TYPE_MIC_ARRAY_PROCESSOR,
};
PVOID pNotificationHandle = NULL;
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
NTSTATUS
RegisterForPlugPlayNotifications(
)
{
NTSTATUS Status;
DPF(50, "RegisterForPlugPlayNotifications");
ASSERT(gpDeviceInstance != NULL);
ASSERT(gpDeviceInstance->pPhysicalDeviceObject != NULL);
Status = IoRegisterPlugPlayNotification(
EventCategoryDeviceInterfaceChange,
PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
(LPGUID)&KSCATEGORY_AUDIO,
gpDeviceInstance->pPhysicalDeviceObject->DriverObject,
(NTSTATUS (*)(PVOID, PVOID)) AudioDeviceInterfaceNotification,
NULL,
&pNotificationHandle);
if(!NT_SUCCESS(Status)) {
Trap();
goto exit;
}
exit:
return(Status);
}
VOID
UnregisterForPlugPlayNotifications(
)
{
if(pNotificationHandle != NULL) {
IoUnregisterPlugPlayNotification(pNotificationHandle);
}
}
VOID
DecrementAddRemoveCount(
)
{
if(InterlockedDecrement(&glPendingAddDelete) == 0) {
DPF(50, "DecrementAddRemoveCount: sending event");
KsGenerateEventList(
NULL,
KSEVENT_SYSAUDIO_ADDREMOVE_DEVICE,
&gEventQueue,
KSEVENTS_SPINLOCK,
&gEventLock);
}
}
NTSTATUS
AddFilterWorker(
PWSTR pwstrDeviceInterface,
PVOID pReference
)
{
AddFilter(pwstrDeviceInterface, NULL);
ExFreePool(pwstrDeviceInterface);
DecrementAddRemoveCount();
// Dereference sysaudio PDO.
KsDereferenceSoftwareBusObject(gpDeviceInstance->pDeviceHeader);
return(STATUS_SUCCESS);
}
NTSTATUS
DeleteFilterWorker(
PWSTR pwstrDeviceInterface,
PVOID pReference
)
{
DeleteFilter(pwstrDeviceInterface);
ExFreePool(pwstrDeviceInterface);
DecrementAddRemoveCount();
// Dereference sysaudio PDO.
KsDereferenceSoftwareBusObject(gpDeviceInstance->pDeviceHeader);
return(STATUS_SUCCESS);
}
NTSTATUS
AudioDeviceInterfaceNotification(
IN PDEVICE_INTERFACE_CHANGE_NOTIFICATION pNotification,
IN PVOID Context
)
{
NTSTATUS Status = STATUS_SUCCESS;
PWSTR pwstrDeviceInterface;
DPF1(50, "AudioDeviceInterfaceNotification: (%s)",
DbgUnicode2Sz(pNotification->SymbolicLinkName->Buffer));
//
// SECURITY NOTE:
// We trust the Buffer, because it is passed to us as part of notification
// from PnP subsystem.
//
pwstrDeviceInterface = (PWSTR)
ExAllocatePoolWithTag(
PagedPool,
(wcslen(pNotification->SymbolicLinkName->Buffer) + 1) * sizeof(WCHAR),
POOLTAG_SYSA);
if(pwstrDeviceInterface == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
// The notification sends null terminated unicode strings
wcscpy(pwstrDeviceInterface, pNotification->SymbolicLinkName->Buffer);
if(IsEqualGUID(&pNotification->Event, &GUID_DEVICE_INTERFACE_ARRIVAL)) {
//
// Keep a reference so that SWENUM does not REMOVE the device
// when the Worker thread is running.
// If the thread is scheduled successfully, it will remove the reference
// when exiting.
//
Status = KsReferenceSoftwareBusObject(gpDeviceInstance->pDeviceHeader);
if(!NT_SUCCESS(Status)) {
goto exit;
}
InterlockedIncrement(&glPendingAddDelete);
Status = QueueWorkList(
(UTIL_PFN)AddFilterWorker,
pwstrDeviceInterface,
NULL);
if (!NT_SUCCESS(Status)) {
KsDereferenceSoftwareBusObject(gpDeviceInstance->pDeviceHeader);
}
}
else if(IsEqualGUID(&pNotification->Event, &GUID_DEVICE_INTERFACE_REMOVAL)) {
//
// Keep a reference so that SWENUM does not REMOVE the device
// when the Worker thread is running.
// If the thread is scheduled successfully, it will remove the reference
// when exiting.
//
Status = KsReferenceSoftwareBusObject(gpDeviceInstance->pDeviceHeader);
if(!NT_SUCCESS(Status)) {
goto exit;
}
InterlockedIncrement(&glPendingAddDelete);
Status = QueueWorkList(
(UTIL_PFN)DeleteFilterWorker,
pwstrDeviceInterface,
NULL);
if (!NT_SUCCESS(Status)) {
KsDereferenceSoftwareBusObject(gpDeviceInstance->pDeviceHeader);
}
}
else {
//
// SECURITY NOTE:
// Sysaudio is registering only for EventCategoryDeviceInterfaceChange.
// This should send ARRIVAL and REMOVAL.
// If anything else comes up, we will return SUCCESS.
// However we are making sure that pwstrDeviceInterface is not leaked.
//
if (pwstrDeviceInterface) {
ExFreePool(pwstrDeviceInterface);
pwstrDeviceInterface = NULL;
}
}
exit:
if (!NT_SUCCESS(Status))
{
if (pwstrDeviceInterface) {
ExFreePool(pwstrDeviceInterface);
pwstrDeviceInterface = NULL;
}
}
return(Status);
}
NTSTATUS
AddFilter(
PWSTR pwstrDeviceInterface,
PFILTER_NODE *ppFilterNode // if !NULL, physical connection addfilter
)
{
PFILTER_NODE pFilterNodeDuplicate = NULL;
PFILTER_NODE pFilterNode = NULL;
UNICODE_STRING ustrFilterName;
UNICODE_STRING ustrAliasName;
UNICODE_STRING ustrName;
NTSTATUS Status;
ULONG fulType;
int i;
DPF1(50, "AddFilter: (%s)", DbgUnicode2Sz(pwstrDeviceInterface));
fulType = 0;
RtlInitUnicodeString(&ustrFilterName, pwstrDeviceInterface);
//
// For each Interface in apguidCategories, get interface alias of
// the new device. Check for duplicate interfaces.
//
for(i = 0; i < SIZEOF_ARRAY(apguidCategories); i++) {
Status = IoGetDeviceInterfaceAlias(
&ustrFilterName,
apguidCategories[i],
&ustrAliasName);
if(NT_SUCCESS(Status)) {
HANDLE hAlias;
Status = OpenDevice(ustrAliasName.Buffer, &hAlias);
if(NT_SUCCESS(Status)) {
DPF2(100, "AddFilter: alias (%s) aulFilterType %08x",
DbgUnicode2Sz(ustrAliasName.Buffer),
aulFilterType[i]);
fulType |= aulFilterType[i];
ZwClose(hAlias);
if(pFilterNodeDuplicate == NULL) {
FOR_EACH_LIST_ITEM(gplstFilterNode, pFilterNode) {
if(pFilterNode->GetDeviceInterface() == NULL) {
continue;
}
RtlInitUnicodeString(
&ustrName,
pFilterNode->GetDeviceInterface());
if(RtlEqualUnicodeString(
&ustrAliasName,
&ustrName,
TRUE)) {
DPF(50, "AddFilter: dup");
pFilterNodeDuplicate = pFilterNode;
break;
}
} END_EACH_LIST_ITEM
}
}
else {
DPF1(10, "AddFilter: OpenDevice FAILED on alias (%s)",
DbgUnicode2Sz(ustrAliasName.Buffer));
}
RtlFreeUnicodeString(&ustrAliasName);
}
}
pFilterNode = pFilterNodeDuplicate;
Status = STATUS_SUCCESS;
//
// Create a new Filter_Node if this is not a duplicate.
//
if(pFilterNodeDuplicate == NULL) {
pFilterNode = new FILTER_NODE(fulType);
if(pFilterNode == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
Trap();
goto exit;
}
Status = pFilterNode->Create(pwstrDeviceInterface);
if(!NT_SUCCESS(Status)) {
goto exit;
}
Status = pFilterNode->DuplicateForCapture();
if(!NT_SUCCESS(Status)) {
goto exit;
}
DPF1(50, "AddFilter: new CFilterNode fulType %08x", fulType);
}
//
// If this is called from Interface Notification Callback,
// create a new DeviceNode for the new FilterNode.
//
if(ppFilterNode == NULL) {
if(pFilterNode->GetType() & FILTER_TYPE_ENDPOINT) {
//
// Check if a DeviceNode has already been created for
// this FilterNode.
//
if (NULL != pFilterNodeDuplicate &&
NULL != pFilterNodeDuplicate->pDeviceNode) {
DPF1(5, "Duplicate FilterNode %X. Skip DeviceNode Create",
pFilterNode);
}
else {
pFilterNode->pDeviceNode = new DEVICE_NODE;
if(pFilterNode->pDeviceNode == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
Trap();
goto exit;
}
Status = pFilterNode->pDeviceNode->Create(pFilterNode);
if(!NT_SUCCESS(Status)) {
goto exit;
}
}
}
else {
DPF(50, "AddFilter: DestroyAllGraphs");
DestroyAllGraphs();
}
}
exit:
if(!NT_SUCCESS(Status)) {
DPF2(5, "AddFilter: FAILED (%s) %08x",
DbgUnicode2Sz(pwstrDeviceInterface),
Status);
if(pFilterNode != NULL && pFilterNodeDuplicate == NULL) {
delete pFilterNode;
pFilterNode = NULL;
}
}
if(ppFilterNode != NULL) {
*ppFilterNode = pFilterNode;
}
return(Status);
}
NTSTATUS
DeleteFilter(
PWSTR pwstrDeviceInterface
)
{
UNICODE_STRING ustrFilterName;
UNICODE_STRING ustrAliasName;
UNICODE_STRING ustrName;
PFILTER_NODE pFilterNode;
NTSTATUS Status;
int i;
DPF1(50, "DeleteFilter: (%s)", DbgUnicode2Sz(pwstrDeviceInterface));
RtlInitUnicodeString(&ustrFilterName, pwstrDeviceInterface);
//
// First delete all filter nodes which have the device interface which is
// going away
//
FOR_EACH_LIST_ITEM_DELETE(gplstFilterNode, pFilterNode) {
if(pFilterNode->GetDeviceInterface() == NULL) {
continue;
}
RtlInitUnicodeString(
&ustrName,
pFilterNode->GetDeviceInterface());
if(RtlEqualUnicodeString(
&ustrFilterName,
&ustrName,
TRUE)) {
delete pFilterNode;
DELETE_LIST_ITEM(gplstFilterNode);
}
} END_EACH_LIST_ITEM
for(i = 0; i < SIZEOF_ARRAY(apguidCategories); i++) {
//
// According to PnP group, it is perfectly safe to ask for aliases
// during removal. The interface itself will be enabled or disabled. But
// we will still get the correct aliases.
//
Status = IoGetDeviceInterfaceAlias(
&ustrFilterName,
apguidCategories[i],
&ustrAliasName);
if(NT_SUCCESS(Status)) {
FOR_EACH_LIST_ITEM_DELETE(gplstFilterNode, pFilterNode) {
if(pFilterNode->GetDeviceInterface() == NULL) {
continue;
}
RtlInitUnicodeString(
&ustrName,
pFilterNode->GetDeviceInterface());
if(RtlEqualUnicodeString(
&ustrAliasName,
&ustrName,
TRUE)) {
delete pFilterNode;
DELETE_LIST_ITEM(gplstFilterNode);
}
} END_EACH_LIST_ITEM
RtlFreeUnicodeString(&ustrAliasName);
}
}
return(STATUS_SUCCESS);
}
#define GFX_VERBOSE_LEVEL 50
//=============================================================================
// Assumptions:
// - SysaudioGfx.ulType has been already validated.
//
NTSTATUS AddGfx(
PSYSAUDIO_GFX pSysaudioGfx,
ULONG cbMaxLength
)
{
NTSTATUS Status;
PFILE_OBJECT pFileObject;
PFILTER_NODE pFilterNode;
ULONG Flags;
PWSTR pwstrDeviceName;
ULONG GfxOrderBase, GfxOrderCeiling;
ASSERT(pSysaudioGfx);
pFileObject = NULL;
pwstrDeviceName = NULL;
pFilterNode = NULL;
GfxOrderBase = GfxOrderCeiling = 0;
DPF1(GFX_VERBOSE_LEVEL, "AddGfx :: Request to add Gfx %x", pSysaudioGfx);
DPF1(GFX_VERBOSE_LEVEL, " hGfx = %x", pSysaudioGfx->hGfx);
DPF1(GFX_VERBOSE_LEVEL, " ulOrder = %x", pSysaudioGfx->ulOrder);
DPF1(GFX_VERBOSE_LEVEL, " ulType = %x", pSysaudioGfx->ulType);
DPF1(GFX_VERBOSE_LEVEL, " Flags = %x", pSysaudioGfx->ulFlags);
//
// Setup GFX Order's base & ceiling for future usage
//
if (pSysaudioGfx->ulType == GFX_DEVICETYPE_RENDER) {
GfxOrderBase = ORDER_RENDER_GFX_FIRST;
GfxOrderCeiling = ORDER_RENDER_GFX_LAST;
}
if (pSysaudioGfx->ulType == GFX_DEVICETYPE_CAPTURE) {
GfxOrderBase = ORDER_CAPTURE_GFX_FIRST;
GfxOrderCeiling = ORDER_CAPTURE_GFX_LAST;
}
ASSERT(GfxOrderBase);
ASSERT(GfxOrderCeiling);
//
// validate that order is within range
//
if (pSysaudioGfx->ulOrder >= (GfxOrderCeiling - GfxOrderBase)) {
Status = STATUS_INVALID_PARAMETER;
Trap();
goto exit;
}
//
// Allocate a Filter Node for the new GFX
//
pFilterNode = new FILTER_NODE(FILTER_TYPE_GFX);
if(pFilterNode == NULL) {
Trap();
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
pFilterNode->SetRenderCaptureFlags(pSysaudioGfx->ulType);
//
// Copy the Device Name (on which the gfx needs to be attached) into a local
// copy for our own use
//
Status = SafeCopyDeviceName(
(PWSTR) ((CHAR *) pSysaudioGfx + pSysaudioGfx->ulDeviceNameOffset),
cbMaxLength,
&pwstrDeviceName);
if (!NT_SUCCESS(Status)) {
goto exit;
}
DPF1(GFX_VERBOSE_LEVEL, " On DI = %s", DbgUnicode2Sz(pwstrDeviceName));
//
// Make sure that there are no other GFXes with the same order on this device
//
if ((FindGfx(pFilterNode,
0, // wild card for handle
pwstrDeviceName,
pSysaudioGfx->ulOrder+GfxOrderBase))) {
delete [] pwstrDeviceName;
Status = STATUS_INVALID_PARAMETER;
goto exit;
}
//
// Get the FileObject of the GFX for future use
// SECURITY NOTE:
// The handle is coming from UserMode. So we have to specify UserMode.
// Also we are explicitly interested in FileObjects. The rest should be
// rejected.
//
Status = ObReferenceObjectByHandle(
pSysaudioGfx->hGfx,
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
*IoFileObjectType,
UserMode,
(PVOID*)&pFileObject,
NULL);
if (!NT_SUCCESS(Status) || NULL == pFileObject) {
DPF1(GFX_VERBOSE_LEVEL, "AddGfx :: ObReference failed %x", Status);
delete [] pwstrDeviceName;
goto exit;
}
//
// Add the device name string to global memory to be freed
//
Status = pFilterNode->lstFreeMem.AddList(pwstrDeviceName);
if(!NT_SUCCESS(Status)) {
Trap();
delete [] pwstrDeviceName;
goto exit;
}
//
// Indicate that this Gfx needs be loaded only on the device pointed to be
// pwstrDeviceName
//
Status = pFilterNode->AddDeviceInterfaceMatch(pwstrDeviceName);
if(!NT_SUCCESS(Status)) {
Trap();
delete [] pwstrDeviceName;
goto exit;
}
//
// Set the Gfx order in the filter node
//
pFilterNode->SetOrder(pSysaudioGfx->ulOrder+GfxOrderBase);
//
// Profile the GFX and create pin infos, logical filter nodes etc
//
Status = pFilterNode->ProfileFilter(pFileObject);
if(!NT_SUCCESS(Status)) {
Trap();
goto exit;
}
//
// Fix the GFX glitching problem. Send the property blindly to GFX
// filter. KS will handle the property.
// Failures are not important, ignore them.
//
SetKsFrameHolding(pFileObject);
exit:
if(!NT_SUCCESS(Status)) {
DPF1(GFX_VERBOSE_LEVEL, "AddGfx :: Failed, Status = %x", Status);
if(pFilterNode != NULL) {
delete pFilterNode;
pFilterNode = NULL;
}
if(pFileObject != NULL) {
ObDereferenceObject(pFileObject);
}
}
else {
DPF1(GFX_VERBOSE_LEVEL, "AddGfx :: Added GFX FilterNode %x", pFilterNode);
DPF1(GFX_VERBOSE_LEVEL, " order = %x", pFilterNode->GetOrder());
DPF1(GFX_VERBOSE_LEVEL, " type = %x", pFilterNode->GetType());
DPF1(GFX_VERBOSE_LEVEL, " flags = %x", pFilterNode->GetFlags());
//
// Setup file handle details for later use of
// the user mode handle passed in
//
pFilterNode->SetFileDetails(pSysaudioGfx->hGfx,
pFileObject,
PsGetCurrentProcess());
//
// Force a rebuild of graph nodes
//
DestroyAllGraphs();
}
return(Status);
}
//=============================================================================
// Assumptions:
// - SysaudioGfx.ulType has been already validated.
//
NTSTATUS RemoveGfx(
PSYSAUDIO_GFX pSysaudioGfx,
ULONG cbMaxLength
)
{
NTSTATUS Status;
PFILTER_NODE pFilterNode;
PWSTR pwstrDeviceName;
ULONG GfxOrderBase, GfxOrderCeiling;
pFilterNode = NULL;
GfxOrderBase = GfxOrderCeiling = 0;
pwstrDeviceName = NULL;
DPF1(GFX_VERBOSE_LEVEL, "RemoveGfx :: Request to remove Gfx %x", pSysaudioGfx);
DPF1(GFX_VERBOSE_LEVEL, " hGfx = %x", pSysaudioGfx->hGfx);
DPF1(GFX_VERBOSE_LEVEL, " ulOrder = %x", pSysaudioGfx->ulOrder);
DPF1(GFX_VERBOSE_LEVEL, " ulType = %x", pSysaudioGfx->ulType);
DPF1(GFX_VERBOSE_LEVEL, " Flags = %x", pSysaudioGfx->ulFlags);
//
// Setup GFX Order's base & ceiling for future usage
//
if (pSysaudioGfx->ulType == GFX_DEVICETYPE_RENDER) {
GfxOrderBase = ORDER_RENDER_GFX_FIRST;
GfxOrderCeiling = ORDER_RENDER_GFX_LAST;
}
if (pSysaudioGfx->ulType == GFX_DEVICETYPE_CAPTURE ) {
GfxOrderBase = ORDER_CAPTURE_GFX_FIRST;
GfxOrderCeiling = ORDER_CAPTURE_GFX_LAST;
}
ASSERT(GfxOrderBase);
ASSERT(GfxOrderCeiling);
//
// Copy the Device Name (on which the gfx needs to be attached) into a local copy for our own use
//
Status = SafeCopyDeviceName(
(PWSTR) ((CHAR *) pSysaudioGfx + pSysaudioGfx->ulDeviceNameOffset),
cbMaxLength,
&pwstrDeviceName);
if (!NT_SUCCESS(Status)) {
goto exit;
}
DPF1(GFX_VERBOSE_LEVEL, " On DI = %s", DbgUnicode2Sz(pwstrDeviceName));
//
// Find the FilterNode for the Gfx
//
if ((pFilterNode = FindGfx(NULL,
pSysaudioGfx->hGfx,
pwstrDeviceName,
pSysaudioGfx->ulOrder+GfxOrderBase)) == NULL) {
Status = STATUS_INVALID_PARAMETER;
goto exit;
}
//
// Should we validate the FileHandle Value?
//
//
// Dereference the file object
//
pFilterNode->ClearFileDetails();
exit:
if(!NT_SUCCESS(Status)) {
DPF1(GFX_VERBOSE_LEVEL, "RemoveGfx :: Failed, Status = %x", Status);
Trap();
}
else {
delete pFilterNode;
}
delete pwstrDeviceName;
return(Status);
}
PFILTER_NODE
FindGfx(
PFILTER_NODE pnewFilterNode,
HANDLE hGfx,
PWSTR pwstrDeviceName,
ULONG GfxOrder
)
{
PFILTER_NODE pFilterNode;
ULONG DeviceCount;
UNICODE_STRING usInDevice, usfnDevice;
PWSTR pwstr;
DPF2(90, "FindGfx:: Looking for GFX with order = %x attached to %s)", GfxOrder, DbgUnicode2Sz(pwstrDeviceName));
FOR_EACH_LIST_ITEM(gplstFilterNode, pFilterNode) {
//
// Skip the one we just added
//
if (pFilterNode == pnewFilterNode) {
continue;
}
//
// Check whether this pFilterNode matches the Gfx we are looking for
//
if (pFilterNode->DoesGfxMatch(hGfx, pwstrDeviceName, GfxOrder)) {
return (pFilterNode);
}
} END_EACH_LIST_ITEM
return(NULL);
}
//=============================================================================
//
// Copies a UNICODE DeviceName to a new location. The source string is coming
// from user mode.
// There are assumptions in the code that the size should be greater than 4
// characters. (see DEVICE_NAME_TAG)
// Caller must make sure that this is BUFFERRED IO.
//
NTSTATUS
SafeCopyDeviceName(
PWSTR pwstrDeviceName,
ULONG cbMaxLength,
PWSTR *String
)
{
NTSTATUS ntStatus;
ULONG cchLength;
PWSTR pwstrString = NULL;
*String = NULL;
//
// SECURITY_NOTE:
// pwstrDeviceName points to a NULL-terminated UNICODE string.
// The string is coming from user mode, through BUFFERRED IO. So try/
// except is not necessary. Also Probe would not catch any errors.
// The IRP OutputBufferLength limits, the size of the string.
//
if (S_OK !=
StringCchLength(pwstrDeviceName, (size_t) cbMaxLength / sizeof(WCHAR), (size_t *) &cchLength))
{
DPF(5, "SafeCopyDeviceName: DeviceName is not zero-terminated.");
ntStatus = STATUS_INVALID_PARAMETER;
goto exit;
}
//
// SECURITY NOTE:
// There are assumptions further in the code about DeviceName string.
// Make sure those assumptions hold.
// One assumption is that DeviceName should be greater than 4
// characters.
//
if (cchLength <= wcslen(DEVICE_NAME_TAG)) {
DPF(5, "SafeCopyDeviceName: DeviceName is not well-formed");
ntStatus = STATUS_INVALID_PARAMETER;
goto exit;
}
pwstrString = new(WCHAR[cchLength + 1]) ;
if(pwstrString == NULL) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
//
// SECURITY NOTE:
// Note that Length does not include the terminating NULL.
// Use n version of string copy in case the buffer changes.
// Also make sure that the string is NULL terminated.
//
wcsncpy(pwstrString, pwstrDeviceName, cchLength);
pwstrString[cchLength] = UNICODE_NULL;
ntStatus = STATUS_SUCCESS;
exit:
*String = pwstrString;
return ntStatus;
}
NTSTATUS
GetFilterTypeFromGuid(
IN LPGUID pguid,
OUT PULONG pfulType
)
{
int i;
for(i = 0; i < SIZEOF_ARRAY(apguidCategories); i++) {
if (memcmp (apguidCategories[i], pguid, sizeof(GUID)) == 0) {
*pfulType |= aulFilterType[i];
return(STATUS_SUCCESS);
}
}
return(STATUS_INVALID_DEVICE_REQUEST);
}
//---------------------------------------------------------------------------
// End of File: notify.cpp
//---------------------------------------------------------------------------