//--------------------------------------------------------------------------- // // 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 //---------------------------------------------------------------------------