//--------------------------------------------------------------------------- // // Module: shi.cpp // // Description: // // Shingle Instance Class // //@@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 WCHAR cwstrFilterTypeName[] = KSSTRING_Filter; const WCHAR cwstrPlaybackShingleName[] = L"PLAYBACK"; const WCHAR cwstrRecordShingleName[] = L"RECORD"; const WCHAR cwstrMidiShingleName[] = L"MIDI"; const WCHAR cwstrMixerShingleName[] = L"MIXER"; #ifdef DEBUG const WCHAR cwstrPinsShingleName[] = L"PINS"; #endif PSHINGLE_INSTANCE apShingleInstance[] = { NULL, // KSPROPERTY_SYSAUDIO_NORMAL_DEFAULT NULL, // KSPROPERTY_SYSAUDIO_PLAYBACK_DEFAULT NULL, // KSPROPERTY_SYSAUDIO_RECORD_DEFAULT NULL, // KSPROPERTY_SYSAUDIO_MIDI_DEFAULT NULL, // KSPROPERTY_SYSAUDIO_MIXER_DEFAULT #ifdef DEBUG NULL, #endif }; ULONG aulFlags[] = { FLAGS_COMBINE_PINS | GN_FLAGS_PLAYBACK | GN_FLAGS_RECORD | GN_FLAGS_MIDI, FLAGS_COMBINE_PINS | GN_FLAGS_PLAYBACK, FLAGS_COMBINE_PINS | GN_FLAGS_RECORD, FLAGS_COMBINE_PINS | GN_FLAGS_MIDI, FLAGS_MIXER_TOPOLOGY | GN_FLAGS_PLAYBACK | GN_FLAGS_RECORD | GN_FLAGS_MIDI, #ifdef DEBUG GN_FLAGS_PLAYBACK, #endif }; PCWSTR apcwstrReference[] = { cwstrFilterTypeName, cwstrPlaybackShingleName, cwstrRecordShingleName, cwstrMidiShingleName, cwstrMixerShingleName, #ifdef DEBUG cwstrPinsShingleName, #endif }; //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- NTSTATUS CShingleInstance::InitializeShingle( ) { NTSTATUS Status = STATUS_SUCCESS; int i; for(i = 0; i < SIZEOF_ARRAY(apShingleInstance); i++) { apShingleInstance[i] = new SHINGLE_INSTANCE(aulFlags[i]); if(apShingleInstance[i] == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } Status = apShingleInstance[i]->CreateCreateItem(apcwstrReference[i]); if(!NT_SUCCESS(Status)) { goto exit; } } Status = QueueWorkList( CShingleInstance::InitializeShingleWorker, NULL, NULL); if(!NT_SUCCESS(Status)) { goto exit; } exit: if(!NT_SUCCESS(Status)) { UninitializeShingle(); } return(Status); } VOID CShingleInstance::UninitializeShingle( ) { int i; for(i = 0; i < SIZEOF_ARRAY(apShingleInstance); i++) { delete apShingleInstance[i]; apShingleInstance[i] = NULL; } } NTSTATUS CShingleInstance::InitializeShingleWorker( PVOID pReference1, PVOID pReference2 ) { NTSTATUS Status; Status = apShingleInstance[KSPROPERTY_SYSAUDIO_PLAYBACK_DEFAULT]->Create( NULL, (LPGUID)&KSCATEGORY_PREFERRED_WAVEOUT_DEVICE); if(!NT_SUCCESS(Status)) { goto exit; } Status = apShingleInstance[KSPROPERTY_SYSAUDIO_RECORD_DEFAULT]->Create( NULL, (LPGUID)&KSCATEGORY_PREFERRED_WAVEIN_DEVICE); if(!NT_SUCCESS(Status)) { goto exit; } Status = apShingleInstance[KSPROPERTY_SYSAUDIO_MIDI_DEFAULT]->Create( NULL, (LPGUID)&KSCATEGORY_PREFERRED_MIDIOUT_DEVICE); if(!NT_SUCCESS(Status)) { goto exit; } exit: return(Status); } //--------------------------------------------------------------------------- CShingleInstance::CShingleInstance( ULONG ulFlags ) { this->ulFlags = ulFlags; } CShingleInstance::~CShingleInstance( ) { PKSOBJECT_CREATE_ITEM pCreateItem; DPF1(60, "~CShingleInstance: %08x", this); ASSERT(this != NULL); Assert(this); DestroyDeviceInterface(); FOR_EACH_LIST_ITEM(&lstCreateItem, pCreateItem) { DestroyCreateItem(pCreateItem); } END_EACH_LIST_ITEM } NTSTATUS CShingleInstance::Create( IN PDEVICE_NODE pDeviceNode, IN LPGUID pguidClass ) { NTSTATUS Status = STATUS_SUCCESS; static ULONG cShingles = 0; this->pDeviceNode = pDeviceNode; // // SECURITY NOTE: ALPERS // I am not going to switch to strsafe.h just for this. // This almost has no risk. cShingles represent the number of // ShingleInstances that have been created. In order for this to overflow // cShingles has to be larger than 999999. // swprintf(wstrReference, L"SAD%d", cShingles++); Status = CreateCreateItem(wstrReference); if(!NT_SUCCESS(Status)) { goto exit; } Status = CreateDeviceInterface(pguidClass, wstrReference); if(!NT_SUCCESS(Status)) { goto exit; } DPF2(60, "CShingleInstance::Create: %08x DN: %08x", this, pDeviceNode); exit: return(Status); } NTSTATUS CShingleInstance::SetDeviceNode( IN PDEVICE_NODE pDeviceNode ) { NTSTATUS Status = STATUS_SUCCESS; DisableDeviceInterface(); this->pDeviceNode = pDeviceNode; Status = EnableDeviceInterface(); if(!NT_SUCCESS(Status)) { goto exit; } DPF2(60, "CShingleInstance::SetDeviceNode: %08x DN: %08x", this, pDeviceNode); exit: return(Status); } NTSTATUS CShingleInstance::CreateCreateItem( IN PCWSTR pcwstrReference ) { PKSOBJECT_CREATE_ITEM pCreateItem = NULL; NTSTATUS Status = STATUS_SUCCESS; // // SECURITY NOTE: // The new operator allocates memory and fills it with zeros. // Therefore the SECURITY_DESCRIPTOR of KSOBJECT_CREATE_ITEM will // be NULL. // That's OK, because we want to apply default security to this object. // pCreateItem = new KSOBJECT_CREATE_ITEM; if(pCreateItem == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } pCreateItem->Create = CFilterInstance::FilterDispatchCreate; pCreateItem->Context = this; RtlInitUnicodeString(&pCreateItem->ObjectClass, pcwstrReference); Status = KsAllocateObjectCreateItem( gpDeviceInstance->pDeviceHeader, pCreateItem, FALSE, NULL); if(!NT_SUCCESS(Status)) { // // This is used in DestroyCreateItem to determine if it is necessary // to call KsFreeObjectCreateItem. // pCreateItem->ObjectClass.Buffer = NULL; goto exit; } Status = lstCreateItem.AddList(pCreateItem); if(!NT_SUCCESS(Status)) { goto exit; } DPF3(60, "CSHI::CreateItem SHI %08x CI %08x %s", this, pCreateItem, DbgUnicode2Sz((PWSTR)pcwstrReference)); exit: if(!NT_SUCCESS(Status)) { DestroyCreateItem(pCreateItem); } return(Status); } ENUMFUNC CShingleInstance::DestroyCreateItem( IN PKSOBJECT_CREATE_ITEM pCreateItem ) { if(pCreateItem != NULL) { if(pCreateItem->ObjectClass.Buffer != NULL) { KsFreeObjectCreateItem( gpDeviceInstance->pDeviceHeader, &pCreateItem->ObjectClass); } delete pCreateItem; } return(STATUS_CONTINUE); } NTSTATUS CShingleInstance::CreateDeviceInterface( IN LPGUID pguidClass, IN PCWSTR pcwstrReference ) { UNICODE_STRING ustrReference; NTSTATUS Status = STATUS_SUCCESS; ASSERT(gpDeviceInstance != NULL); ASSERT(gpDeviceInstance->pPhysicalDeviceObject != NULL); ASSERT(gpDeviceInstance->pDeviceHeader != NULL); ASSERT(this->ustrSymbolicLinkName.Buffer == NULL); RtlInitUnicodeString(&ustrReference, pcwstrReference); Status = IoRegisterDeviceInterface( gpDeviceInstance->pPhysicalDeviceObject, pguidClass, &ustrReference, &this->ustrSymbolicLinkName); if(!NT_SUCCESS(Status)) { goto exit; } Status = EnableDeviceInterface(); if(!NT_SUCCESS(Status)) { goto exit; } DPF3(60, "CSHI::CreateDeviceInterface: %08x %s %s", this, DbgGuid2Sz(pguidClass), DbgUnicode2Sz(this->ustrSymbolicLinkName.Buffer)); exit: return(Status); } NTSTATUS CShingleInstance::EnableDeviceInterface( ) { NTSTATUS Status = STATUS_SUCCESS; PWSTR pwstrFriendlyName = L""; UNICODE_STRING ustrValueName; UNICODE_STRING ustrValue; HANDLE hkey = NULL; if(this->ustrSymbolicLinkName.Buffer == NULL) { ASSERT(NT_SUCCESS(Status)); goto exit; } // // Put the proxy's CLSID in the new device interface // Status = IoOpenDeviceInterfaceRegistryKey( &this->ustrSymbolicLinkName, STANDARD_RIGHTS_ALL, &hkey); if(!NT_SUCCESS(Status)) { goto exit; } RtlInitUnicodeString(&ustrValueName, L"CLSID"); RtlInitUnicodeString(&ustrValue, L"{17CCA71B-ECD7-11D0-B908-00A0C9223196}"); Status = ZwSetValueKey( hkey, &ustrValueName, 0, REG_SZ, ustrValue.Buffer, ustrValue.Length); if(!NT_SUCCESS(Status)) { goto exit; } // // Set the friendly name into the new device interface // if(pDeviceNode != NULL) { Assert(pDeviceNode); if(pDeviceNode->GetFriendlyName() != NULL) { pwstrFriendlyName = pDeviceNode->GetFriendlyName(); } else { DPF(5, "CSHI::EnableDeviceInterface no friendly name"); } } RtlInitUnicodeString(&ustrValueName, L"FriendlyName"); Status = ZwSetValueKey( hkey, &ustrValueName, 0, REG_SZ, pwstrFriendlyName, (wcslen(pwstrFriendlyName) * sizeof(WCHAR)) + sizeof(UNICODE_NULL)); if(!NT_SUCCESS(Status)) { goto exit; } Status = IoSetDeviceInterfaceState(&this->ustrSymbolicLinkName, TRUE); if(!NT_SUCCESS(Status)) { goto exit; } DPF2(60, "CSHI::EnableDeviceInterface: %08x %s", this, DbgUnicode2Sz(this->ustrSymbolicLinkName.Buffer)); exit: if(hkey != NULL) { ZwClose(hkey); } return(Status); } VOID CShingleInstance::DisableDeviceInterface( ) { Assert(this); DPF1(60, "CSHI::DisableDeviceInterface %08x", this); if(this->ustrSymbolicLinkName.Buffer != NULL) { DPF1(60, "CSHI::DisableDeviceInterface %s", DbgUnicode2Sz(this->ustrSymbolicLinkName.Buffer)); IoSetDeviceInterfaceState(&this->ustrSymbolicLinkName, FALSE); } } VOID CShingleInstance::DestroyDeviceInterface( ) { DisableDeviceInterface(); RtlFreeUnicodeString(&this->ustrSymbolicLinkName); this->ustrSymbolicLinkName.Buffer = NULL; } //---------------------------------------------------------------------------