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.
454 lines
11 KiB
454 lines
11 KiB
//---------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|