|
|
//---------------------------------------------------------------------------
//
// 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"
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
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, #ifdef KSCATEGORY_DRM_DESCRAMBLE
&KSCATEGORY_DRM_DESCRAMBLE, #endif
#ifdef KSCATEGORY_MICROPHONE_ARRAY_PROCESSOR
&KSCATEGORY_MICROPHONE_ARRAY_PROCESSOR, #endif
};
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, #ifdef KSCATEGORY_DRM_DESCRAMBLE
FILTER_TYPE_DRM_DESCRAMBLE, #endif
#ifdef KSCATEGORY_MICROPHONE_ARRAY_PROCESSOR
FILTER_TYPE_MIC_ARRAY_PROCESSOR, #endif
};
PVOID pNotificationHandle = NULL; PVOID pNotificationHandle2 = 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; } //
// For compatibility with Intel AEC which isn't registered in the AUDIO
// category, sysaudio needs to hook the AEC category.
//
Status = IoRegisterPlugPlayNotification( EventCategoryDeviceInterfaceChange, PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, (LPGUID)&KSCATEGORY_ACOUSTIC_ECHO_CANCEL, gpDeviceInstance->pPhysicalDeviceObject->DriverObject, (NTSTATUS (*)(PVOID, PVOID))AudioDeviceInterfaceNotification, NULL, &pNotificationHandle2);
if(!NT_SUCCESS(Status)) { Trap(); goto exit; } exit: return(Status); }
VOID UnregisterForPlugPlayNotifications( ) { if(pNotificationHandle != NULL) { IoUnregisterPlugPlayNotification(pNotificationHandle); } if(pNotificationHandle2 != NULL) { IoUnregisterPlugPlayNotification(pNotificationHandle2); } }
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 FDO.
ObDereferenceObject(gpDeviceInstance->pFunctionalDeviceObject);
return(STATUS_SUCCESS); }
NTSTATUS DeleteFilterWorker( PWSTR pwstrDeviceInterface, PVOID pReference ) { DeleteFilter(pwstrDeviceInterface); ExFreePool(pwstrDeviceInterface); DecrementAddRemoveCount();
// Dereference sysaudio FDO.
ObDereferenceObject(gpDeviceInstance->pFunctionalDeviceObject); 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), 'ASYS');
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 PnP does not REMOVE the device
// when the Worker thread is running.
// If the thread is scheduled successfully, it will remove the reference
// when exiting.
//
ObReferenceObject(gpDeviceInstance->pFunctionalDeviceObject);
InterlockedIncrement(&glPendingAddDelete); Status = QueueWorkList( (UTIL_PFN)AddFilterWorker, pwstrDeviceInterface, NULL); if (!NT_SUCCESS(Status)) { ObDereferenceObject(gpDeviceInstance->pFunctionalDeviceObject); } } else if(IsEqualGUID(&pNotification->Event, &GUID_DEVICE_INTERFACE_REMOVAL)) { //
// Keep a reference so that PnP does not REMOVE the device
// when the Worker thread is running.
// If the thread is scheduled successfully, it will remove the reference
// when exiting.
//
ObReferenceObject(gpDeviceInstance->pFunctionalDeviceObject);
InterlockedIncrement(&glPendingAddDelete); Status = QueueWorkList( (UTIL_PFN)DeleteFilterWorker, pwstrDeviceInterface, NULL); if (!NT_SUCCESS(Status)) { ObDereferenceObject(gpDeviceInstance->pFunctionalDeviceObject); } } 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.
//
ExFreePool(pwstrDeviceInterface); }
exit: if (!NT_SUCCESS(Status)) { ExFreePool(pwstrDeviceInterface); } 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
NTSTATUS AddGfx( PSYSAUDIO_GFX pSysaudioGfx ) { NTSTATUS Status; PFILE_OBJECT pFileObject; PFILTER_NODE pFilterNode; ULONG Flags; PWSTR pwstrDeviceName; ULONG Length; ULONG GfxOrderBase, GfxOrderCeiling;
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);
//
// validate type to be Capture or Render (use public include file!!!)
//
if ((pSysaudioGfx->ulType != GFX_DEVICETYPE_RENDER) && (pSysaudioGfx->ulType != GFX_DEVICETYPE_CAPTURE)) { Trap(); Status = STATUS_INVALID_PARAMETER; goto exit; }
//
// 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 = SafeCopyStringFromOffset(pSysaudioGfx, pSysaudioGfx->ulDeviceNameOffset, &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
//
Status = ObReferenceObjectByHandle( pSysaudioGfx->hGfx, GENERIC_READ | GENERIC_WRITE, NULL, KernelMode, (PVOID*)&pFileObject, NULL);
if (!NT_SUCCESS(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(); 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); }
NTSTATUS RemoveGfx( PSYSAUDIO_GFX pSysaudioGfx ) { NTSTATUS Status; PFILE_OBJECT pFileObject=NULL; PFILTER_NODE pFilterNode; ULONG Flags; PWSTR pwstrDeviceName; ULONG Length; ULONG GfxOrderBase, GfxOrderCeiling;
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);
//
// validate type to be Capture or Render (use public include file!!!)
//
if ((pSysaudioGfx->ulType != GFX_DEVICETYPE_RENDER) && (pSysaudioGfx->ulType != GFX_DEVICETYPE_CAPTURE)) { Trap(); Status = STATUS_INVALID_PARAMETER; goto exit; }
//
// 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 = SafeCopyStringFromOffset(pSysaudioGfx, pSysaudioGfx->ulDeviceNameOffset, &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
//
Status = 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); }
NTSTATUS SafeCopyStringFromOffset( PVOID pBasePointer, ULONG Offset, PWSTR *String ) { ULONG Length; PWSTR pwstrString = NULL;
*String = NULL;
__try { Length = wcslen( (PWSTR)(((CHAR *)pBasePointer)+Offset)) + 1; pwstrString = new(WCHAR[Length]) ;
if(pwstrString == NULL) { return(STATUS_INSUFFICIENT_RESOURCES); } wcscpy(pwstrString,(PWSTR)(((CHAR *)pBasePointer)+Offset)); } __except (EXCEPTION_EXECUTE_HANDLER) { Trap(); delete [] pwstrString; return(STATUS_INVALID_PARAMETER); } *String = pwstrString; return(STATUS_SUCCESS); }
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
//---------------------------------------------------------------------------
|