//--------------------------------------------------------------------------- // // 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 cwstrDefaultDevicePath[] = REGSTR_PATH_MULTIMEDIA_AUDIO_DEFAULT_DEVICE; const WCHAR cwstrDefaultMidiDevicePath[] = REGSTR_PATH_MULTIMEDIA_MIDI_DEFAULT_DEVICE; const WCHAR cwstrPlayback[] = REGSTR_VAL_DEFAULT_PLAYBACK_DEVICE; const WCHAR cwstrRecord[] = REGSTR_VAL_DEFAULT_RECORD_DEVICE; const WCHAR cwstrMidi[] = REGSTR_VAL_DEFAULT_MIDI_DEVICE; 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 apcwstrRegistryPath[] = { NULL, cwstrDefaultDevicePath, cwstrDefaultDevicePath, cwstrDefaultMidiDevicePath, NULL, #ifdef DEBUG cwstrDefaultDevicePath, #endif }; PCWSTR apcwstrRegistryValue[] = { NULL, cwstrPlayback, cwstrRecord, cwstrMidi, NULL, #ifdef DEBUG cwstrPlayback, #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], apcwstrRegistryPath[i], apcwstrRegistryValue[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, PCWSTR pcwstrRegistryPath, PCWSTR pcwstrRegistryValue ) { this->ulFlags = ulFlags; this->pcwstrRegistryPath = pcwstrRegistryPath; this->pcwstrRegistryValue = pcwstrRegistryValue; } 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; 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; 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)) { 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; } //--------------------------------------------------------------------------- #ifdef DEBUG ENUMFUNC CShingleInstance::Dump() { PKSOBJECT_CREATE_ITEM pCreateItem; dprintf("SHI: %08x DN %08x ulFlags %08x\n", this, pDeviceNode, ulFlags); if(ulDebugFlags & (DEBUG_FLAGS_VERBOSE | DEBUG_FLAGS_OBJECT)) { dprintf(" lstCreateItem:"); FOR_EACH_LIST_ITEM(&lstCreateItem, pCreateItem) { dprintf(" %08x", pCreateItem); } END_EACH_LIST_ITEM dprintf("\n"); dprintf(" %s\n", DbgUnicode2Sz(ustrSymbolicLinkName.Buffer)); dprintf(" %s\n", DbgUnicode2Sz((PWSTR)pcwstrRegistryPath)); dprintf(" %s\n", DbgUnicode2Sz((PWSTR)pcwstrRegistryValue)); } return(STATUS_CONTINUE); } #endif