windows-nt/Source/XPSP1/NT/multimedia/directx/dsound/dsvxd/dev.cpp

1084 lines
30 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
//--------------------------------------------------------------------------;
//
// File: dev.cpp
//
// Copyright (c) 1995-1997 Microsoft Corporation. All Rights Reserved.
//
// Abstract:
// Contains program related to managing the direct sound drivers and
// driver list.
//
// Contents:
//
// History:
// 06/15/95 FrankYe
//
//--------------------------------------------------------------------------;
#define WANTVXDWRAPS
#include <windows.h>
extern "C"
{
#include <vmm.h>
#include <vxdldr.h>
#include <vwin32.h>
#include <vxdwraps.h>
#include <configmg.h>
}
#define NODSOUNDWRAPS
#include <mmsystem.h>
#include <dsound.h>
#include <dsdrvi.h>
#include "dsvxd.h"
#include "dsvxdi.h"
#pragma warning(disable:4355) // 'this' : used in base member initializer list
#pragma VxD_PAGEABLE_CODE_SEG
#pragma VxD_PAGEABLE_DATA_SEG
VMMLIST gvmmlistDrivers = 0;
//==========================================================================;
//
// guid functions
// guidAlloc: gets guid from guid pool and returns pointer to it
// guidFree: returns guid to guid pool
//
//==========================================================================;
//--------------------------------------------------------------------------;
//
//
//--------------------------------------------------------------------------;
// TODO need more static guids. this is enough for now
GUID guidList[] = {
{ /* 3d0b92c0-abfc-11ce-a3b3-00aa004a9f0c */
0x3d0b92c0,
0xabfc,
0x11ce,
{0xa3, 0xb3, 0x00, 0xaa, 0x00, 0x4a, 0x9f, 0x0c}
},
{ /* 3d0b92c1-abfc-11ce-a3b3-00aa004a9f0c */
0x3d0b92c1,
0xabfc,
0x11ce,
{0xa3, 0xb3, 0x00, 0xaa, 0x00, 0x4a, 0x9f, 0x0c}
},
{ /* 3d0b92c2-abfc-11ce-a3b3-00aa004a9f0c */
0x3d0b92c2,
0xabfc,
0x11ce,
{0xa3, 0xb3, 0x00, 0xaa, 0x00, 0x4a, 0x9f, 0x0c}
},
{ /* 3d0b92c3-abfc-11ce-a3b3-00aa004a9f0c */
0x3d0b92c3,
0xabfc,
0x11ce,
{0xa3, 0xb3, 0x00, 0xaa, 0x00, 0x4a, 0x9f, 0x0c}
},
{ /* 3d0b92c4-abfc-11ce-a3b3-00aa004a9f0c */
0x3d0b92c4,
0xabfc,
0x11ce,
{0xa3, 0xb3, 0x00, 0xaa, 0x00, 0x4a, 0x9f, 0x0c}
},
{ /* 3d0b92c5-abfc-11ce-a3b3-00aa004a9f0c */
0x3d0b92c5,
0xabfc,
0x11ce,
{0xa3, 0xb3, 0x00, 0xaa, 0x00, 0x4a, 0x9f, 0x0c}
},
{ /* 3d0b92c6-abfc-11ce-a3b3-00aa004a9f0c */
0x3d0b92c6,
0xabfc,
0x11ce,
{0xa3, 0xb3, 0x00, 0xaa, 0x00, 0x4a, 0x9f, 0x0c}
},
{ /* 3d0b92c7-abfc-11ce-a3b3-00aa004a9f0c */
0x3d0b92c7,
0xabfc,
0x11ce,
{0xa3, 0xb3, 0x00, 0xaa, 0x00, 0x4a, 0x9f, 0x0c}
},
{ /* 3d0b92c8-abfc-11ce-a3b3-00aa004a9f0c */
0x3d0b92c8,
0xabfc,
0x11ce,
{0xa3, 0xb3, 0x00, 0xaa, 0x00, 0x4a, 0x9f, 0x0c}
},
{ /* 3d0b92c9-abfc-11ce-a3b3-00aa004a9f0c */
0x3d0b92c9,
0xabfc,
0x11ce,
{0xa3, 0xb3, 0x00, 0xaa, 0x00, 0x4a, 0x9f, 0x0c}
}
};
#define NUMGUIDS (sizeof(guidList) / sizeof(guidList[0]))
typedef struct tGUIDRECORD {
LPCGUID pGuid;
BOOL fAlloc;
UINT uAge;
} GUIDRECORD, *PGUIDRECORD;
PGUIDRECORD gpaGuidRec;
REFGUID GuidAlloc()
{
PGUIDRECORD pGuidRec;
PGUIDRECORD pGuidRecOldest;
UINT uAgeOldest;
int i;
pGuidRecOldest = NULL;
uAgeOldest = 0;
for (i=0; i<NUMGUIDS; i++) {
pGuidRec = &gpaGuidRec[i];
if (pGuidRec->fAlloc) continue;
if (pGuidRec->uAge++ >= uAgeOldest) {
pGuidRecOldest = pGuidRec;
uAgeOldest = pGuidRec->uAge;
}
}
if (NULL == pGuidRecOldest) {
BREAK(("Ran out of guids"));
return GUID_NULL;
} else {
pGuidRecOldest->fAlloc = TRUE;
return *(pGuidRecOldest->pGuid);
}
}
void GuidFree(REFGUID rGuid)
{
PGUIDRECORD pGuidRecMatch;
int i;
pGuidRecMatch = NULL;
for (i=0; i<NUMGUIDS; i++) {
if (IsEqualGUID(*gpaGuidRec[i].pGuid, rGuid)) {
//
// For debug, we go thru all guid records and assert if
// we match on more than just one. For retail, we break
// the loop as soon as we match one.
//
#ifdef DEBUG
if (pGuidRecMatch != NULL) ASSERT(FALSE);
pGuidRecMatch = &gpaGuidRec[i];
#else
pGuidRecMatch = &gpaGuidRec[i];
break;
#endif
}
}
ASSERT(NULL != pGuidRecMatch);
if (NULL == pGuidRecMatch) return; // defensive
pGuidRecMatch->fAlloc = FALSE;
pGuidRecMatch->uAge = 0;
return;
}
//==========================================================================;
//==========================================================================;
//
// CBuf_IDsDriverPropertySet class implementation
//
//==========================================================================;
//==========================================================================;
//--------------------------------------------------------------------------;
//
// Constructor
//
//--------------------------------------------------------------------------;
CBuf_IDsDriverPropertySet::CBuf_IDsDriverPropertySet(CBuf *pBuf)
{
m_cRef = 0;
m_pBuf = pBuf;
return;
}
//--------------------------------------------------------------------------;
//
// QueryInterface - delegates to CBuf
//
//--------------------------------------------------------------------------;
STDMETHODIMP CBuf_IDsDriverPropertySet::QueryInterface(REFIID riid, PVOID *ppv)
{
return m_pBuf->QueryInterface(riid, ppv);
}
//--------------------------------------------------------------------------;
//
// AddRef
// Maintains interface ref count, and delegates to CBuf to maintain
// total object ref count.
//
//--------------------------------------------------------------------------;
STDMETHODIMP_(ULONG) CBuf_IDsDriverPropertySet::AddRef(void)
{
ASSERT(m_cRef >= 0);
m_cRef++;
m_pBuf->AddRef();
return m_cRef;
}
//--------------------------------------------------------------------------;
//
// Release
// Maintains interface ref count. When interface ref count goes to 0
// then release the real driver's IDsDriverPropertySet interface. Also,
// delegate to CBuf in order to maintain total object ref count
//
//--------------------------------------------------------------------------;
STDMETHODIMP_(ULONG) CBuf_IDsDriverPropertySet::Release(void)
{
ASSERT(m_cRef > 0);
if (--m_cRef > 0) {
m_pBuf->Release();
return m_cRef;
}
m_pBuf->m_pIDsDriverPropertySet_Real->Release();
m_pBuf->m_pIDsDriverPropertySet_Real = NULL;
m_pBuf->Release();
return 0;
}
//--------------------------------------------------------------------------;
//
// Get, Set, QuerySupport
// If CBuf hasn't been deregistered, call real driver's
// IDsDriverPropertySet interface
//
//--------------------------------------------------------------------------;
STDMETHODIMP CBuf_IDsDriverPropertySet::Get(PDSPROPERTY pDsProperty,
PVOID pPropertyParams,
ULONG cbPropertyParams,
PVOID pPropertyData,
ULONG cbPropertyData,
PULONG pcbReturnedData)
{
if (m_pBuf->m_fDeregistered) return DSERR_NODRIVER;
return m_pBuf->m_pIDsDriverPropertySet_Real->Get(pDsProperty, pPropertyParams,
cbPropertyParams, pPropertyData, cbPropertyData, pcbReturnedData);
}
STDMETHODIMP CBuf_IDsDriverPropertySet::Set(PDSPROPERTY pDsProperty,
PVOID pPropertyParams,
ULONG cbPropertyParams,
PVOID pPropertyData,
ULONG cbPropertyData)
{
if (m_pBuf->m_fDeregistered) return DSERR_NODRIVER;
return m_pBuf->m_pIDsDriverPropertySet_Real->Set(pDsProperty, pPropertyParams, cbPropertyParams, pPropertyData, cbPropertyData);
}
STDMETHODIMP CBuf_IDsDriverPropertySet::QuerySupport(REFGUID PropertySetId,
ULONG PropertyId,
PULONG pSupport)
{
if (m_pBuf->m_fDeregistered) return DSERR_NODRIVER;
return m_pBuf->m_pIDsDriverPropertySet_Real->QuerySupport(PropertySetId, PropertyId, pSupport);
}
//==========================================================================;
//==========================================================================;
//
// CBuf class implementation
//
//==========================================================================;
//==========================================================================;
//--------------------------------------------------------------------------;
//
// CBuf new and delete operators
//
// We allocate these objects as nodes on a VMMLIST. New takes a VMMLIST
// as a parameter. We bump the size of the allocation enough to store the
// VMMLIST handle at the end of the object. The Delete operator gets the
// VMMLIST handle from the end of the storage that was allocated for the
// object, and uses that hande to deallocate the list node. The objects
// are also attached to and removed from the list as they are created and
// deleted.
//
//--------------------------------------------------------------------------;
//--------------------------------------------------------------------------;
//
//
//
//--------------------------------------------------------------------------;
void* CBuf::operator new(size_t size, VMMLIST list)
{
PVOID pv;
pv = List_Allocate(list);
if (pv) {
memset(pv, 0x00, size);
*(VMMLIST*)((PBYTE)pv + size) = list;
List_Attach_Tail(list, pv);
}
return pv;
}
//--------------------------------------------------------------------------;
//
//
//
//--------------------------------------------------------------------------;
void CBuf::operator delete(void * pv, size_t size)
{
VMMLIST list;
list = *(VMMLIST*)((PBYTE)pv + size);
ASSERT(list);
List_Remove(list, pv);
List_Deallocate(list, pv);
}
//--------------------------------------------------------------------------;
//
// Constructor
// Initializes its contained CBuf_IDsDriverPropertySet interface
// implementation.
//
//--------------------------------------------------------------------------;
CBuf::CBuf(void)
: m_IDsDriverPropertySet(this)
{
return;
}
//--------------------------------------------------------------------------;
//
// CreateList
// Static class method. It simpley creates a VMMLIST
// to be used to create/delete CBuf objects.
//
//--------------------------------------------------------------------------;
VMMLIST CBuf::CreateList(void)
{
return List_Create(LF_ALLOC_ERROR, sizeof(CBuf) + sizeof(VMMLIST));
}
//--------------------------------------------------------------------------;
//
// DeleteList
// Static class method. Destroys a VMMLIST that was used to
// create/destroy CBuf objects.
//
//--------------------------------------------------------------------------;
void CBuf::DestroyList(VMMLIST list)
{
ASSERT(!List_Get_First(list));
List_Destroy(list);
}
//--------------------------------------------------------------------------;
//
// CreateBuf
// Static class method. Creates a CBuf object given the creating CDrv
// object, the VMMLIST to be used to create the CBuf, and a pointer to the
// IDsDriverBuffer interface on the real driver buffer to be contained by
// the CBuf object.
//
//--------------------------------------------------------------------------;
HRESULT CBuf::CreateBuf(CDrv *pDrv, VMMLIST list, IDsDriverBuffer *pIDsDriverBuffer_Real, IDsDriverBuffer **ppIDsDriverBuffer)
{
CBuf *pBuf;
*ppIDsDriverBuffer = NULL;
pBuf = new(list) CBuf;
if (!pBuf) return E_OUTOFMEMORY;
pBuf->m_pDrv = pDrv;
pBuf->m_pIDsDriverBuffer_Real = pIDsDriverBuffer_Real;
pBuf->AddRef();
*ppIDsDriverBuffer = (IDsDriverBuffer*)pBuf;
return S_OK;
}
//--------------------------------------------------------------------------;
//
// DeregisterBuffers
// Static class method. Given a VMMLIST containing CBuf objects, this method
// walks the list marking each of the CBuf objects as deregistered.
//
//--------------------------------------------------------------------------;
void CBuf::DeregisterBuffers(VMMLIST list)
{
CBuf *pBuf;
for ( pBuf = (CBuf*)List_Get_First(list);
pBuf;
pBuf = (CBuf*)List_Get_Next(list, pBuf) )
{
pBuf->m_fDeregistered = TRUE;
}
return;
}
//--------------------------------------------------------------------------;
//
// QueryInterface
// When querying for IUnknown or IDsDriverBuffer, just return this
// object. If querying for IDsDriverPropertySet, then we need to query
// the real driver buffer for this interface, if we haven't already.
//
//--------------------------------------------------------------------------;
STDMETHODIMP CBuf::QueryInterface(REFIID riid, LPVOID *ppv)
{
HRESULT hr;
*ppv = NULL;
if (IID_IUnknown == riid || IID_IDsDriverBuffer == riid) {
*ppv = (IDsDriverBuffer*)this;
} else if (IID_IDsDriverPropertySet == riid) {
if (!m_pIDsDriverPropertySet_Real) {
// don't have the interface from the driver so try to get it
hr = m_pIDsDriverBuffer_Real->QueryInterface(riid, (PVOID*)&m_pIDsDriverPropertySet_Real);
if (FAILED(hr) && m_pIDsDriverPropertySet_Real) {
// TODO: RPF(Driver is stupic cuz it failed QI but set *ppv)
m_pIDsDriverPropertySet_Real = NULL;
}
}
if (m_pIDsDriverPropertySet_Real) {
*ppv = &m_IDsDriverPropertySet;
}
}
if (NULL == *ppv) return E_NOINTERFACE;
((LPUNKNOWN)*ppv)->AddRef();
return S_OK;
}
//--------------------------------------------------------------------------;
//
// AddRef
//
//--------------------------------------------------------------------------;
STDMETHODIMP_(ULONG) CBuf::AddRef(void)
{
m_cRef++;
m_pDrv->AddRef();
return m_cRef;
}
//--------------------------------------------------------------------------;
//
// Release
// When the ref count goes to zero, then we release the real driver
// buffer's IDsDriverBuffer interface. We always release the CDrv object
// that created this CBuf, too, since we the CDrv lifetime brackets the
// CBuf lifetime.
//
//--------------------------------------------------------------------------;
STDMETHODIMP_(ULONG) CBuf::Release(void)
{
CDrv *pDrv;
pDrv = m_pDrv;
m_cRef--;
if (0 == m_cRef) {
DRVCALL(("IDsDriverBuffer(%008X)->Release()", m_pIDsDriverBuffer_Real));
m_pIDsDriverBuffer_Real->Release();
delete this;
pDrv->Release();
return 0;
}
pDrv->Release();
return m_cRef;
}
//--------------------------------------------------------------------------;
//
// IDsDriverBuffer methods
// Return error if the real driver has deregistered, otherwise
// call the real driver's buffer's interface
//
//--------------------------------------------------------------------------;
STDMETHODIMP CBuf::GetPosition(PDWORD pdwPlay, PDWORD pdwWrite)
{
if (m_fDeregistered) return DSERR_NODRIVER;
DRVCALL(("IDsDriverBuffer(%08Xh)->GetPosition(%08Xh, %08Xh)", m_pIDsDriverBuffer_Real, pdwPlay, pdwWrite));
return m_pIDsDriverBuffer_Real->GetPosition(pdwPlay, pdwWrite);
}
STDMETHODIMP CBuf::Lock(LPVOID *ppvAudio1,
LPDWORD pdwLen1, LPVOID *ppvAudio2,
LPDWORD pdwLen2, DWORD dwWritePosition,
DWORD dwWriteLen, DWORD dwFlags)
{
if (m_fDeregistered) return DSERR_NODRIVER;
DRVCALL(("IDsDriverBuffer(%08Xh)->Lock(%08Xh, %08Xh, %08Xh, %08Xh, %08Xh, %08Xh, %08Xh)",
m_pIDsDriverBuffer_Real, ppvAudio1, pdwLen1, ppvAudio2,
pdwLen2,dwWritePosition, dwWriteLen, dwFlags));
return m_pIDsDriverBuffer_Real->Lock(ppvAudio1, pdwLen1, ppvAudio2, pdwLen2,
dwWritePosition, dwWriteLen, dwFlags);
}
STDMETHODIMP CBuf::Play(DWORD dw1, DWORD dw2, DWORD dwFlags)
{
if (m_fDeregistered) return DSERR_NODRIVER;
DRVCALL(("IDsDriverBuffer(%08Xh)->Play(%08Xh, %08Xh, %08Xh)", dw1, dw2, dwFlags));
return m_pIDsDriverBuffer_Real->Play(dw1, dw2, dwFlags);
}
STDMETHODIMP CBuf::SetFormat(LPWAVEFORMATEX pwfx)
{
if (m_fDeregistered) return DSERR_NODRIVER;
DRVCALL(("IDsDriverBuffer(%08Xh)->SetFormat(%08Xh)", m_pIDsDriverBuffer_Real, pwfx));
return m_pIDsDriverBuffer_Real->SetFormat(pwfx);
}
STDMETHODIMP CBuf::SetFrequency(DWORD dwFrequency)
{
if (m_fDeregistered) return DSERR_NODRIVER;
DRVCALL(("IDsDriverBuffer(%08Xh)->SetFrequency(%08Xh)", m_pIDsDriverBuffer_Real, dwFrequency));
return m_pIDsDriverBuffer_Real->SetFrequency(dwFrequency);
}
STDMETHODIMP CBuf::SetPosition(DWORD dwPosition)
{
if (m_fDeregistered) return DSERR_NODRIVER;
DRVCALL(("IDsDriverBuffer(%08Xh)->SetPosition(%08Xh)", m_pIDsDriverBuffer_Real, dwPosition));
return m_pIDsDriverBuffer_Real->SetPosition(dwPosition);
}
STDMETHODIMP CBuf::SetVolumePan(PDSVOLUMEPAN pDsVolumePan)
{
if (m_fDeregistered) return DSERR_NODRIVER;
DRVCALL(("IDsDriverBuffer(%08Xh)->SetVolumePan(%08Xh)", m_pIDsDriverBuffer_Real, pDsVolumePan));
return m_pIDsDriverBuffer_Real->SetVolumePan(pDsVolumePan);
}
STDMETHODIMP CBuf::Stop(void)
{
if (m_fDeregistered) return DSERR_NODRIVER;
DRVCALL(("IDsDriverBuffer(%08Xh)->Stop()", m_pIDsDriverBuffer_Real));
return m_pIDsDriverBuffer_Real->Stop();
}
STDMETHODIMP CBuf::Unlock(LPVOID pvAudio1,
DWORD dwLen1, LPVOID pvAudio2,
DWORD dwLen2)
{
if (m_fDeregistered) return DSERR_NODRIVER;
DRVCALL(("IDsDriverBuffer(%08Xh)->Unlock(%08Xh, %08Xh, %08Xh, %08Xh)",
m_pIDsDriverBuffer_Real, pvAudio1, dwLen1, pvAudio2, dwLen2));
return m_pIDsDriverBuffer_Real->Unlock(pvAudio1, dwLen1, pvAudio2, dwLen2);
}
STDMETHODIMP_(BOOL) CBuf::IsDeregistered(void)
{
return m_fDeregistered;
}
STDMETHODIMP_(IDsDriverBuffer*) CBuf::GetRealDsDriverBuffer(void)
{
return m_pIDsDriverBuffer_Real;
}
//==========================================================================;
//==========================================================================;
//
// CDrv class implementation
//
//==========================================================================;
//==========================================================================;
//--------------------------------------------------------------------------;
//
// CDrv new and delete operators
// These allocate the CDrv objects on a VMMLIST whose handle
// has gobal scope (thus we don't need to same VMMLIST handle trickery
// as we use the new/delete operators for the CBuf class).
//
//--------------------------------------------------------------------------;
void* CDrv::operator new(size_t size)
{
PVOID pv;
ASSERT(0 != gvmmlistDrivers);
pv = List_Allocate(gvmmlistDrivers);
if (NULL != pv) memset(pv, 0x00, size);
return pv;
}
void CDrv::operator delete(void * pv)
{
List_Deallocate(gvmmlistDrivers, pv);
}
//==========================================================================;
//
// CDrv class methods
//
//==========================================================================;
HRESULT CDrv::CreateAndRegisterDriver(IDsDriver *pIDsDriver)
{
CDrv *pDrv;
HRESULT hr;
pDrv = new CDrv;
if (pDrv) {
pDrv->m_cRef=0;
pDrv->m_cOpen = 0;
pDrv->m_fDeregistered = FALSE;
pDrv->m_pIDsDriver_Real = pIDsDriver;
pDrv->m_listBuffers = CBuf::CreateList();
if (pDrv->m_listBuffers) {
pDrv->m_guidDriver = GuidAlloc();
if (!IsEqualGUID(GUID_NULL, pDrv->m_guidDriver)) {
List_Attach_Tail(gvmmlistDrivers, pDrv);
pDrv->AddRef();
hr = S_OK;
} else {
hr = DSERR_GENERIC;
}
if (FAILED(hr)) {
CBuf::DestroyList(pDrv->m_listBuffers);
}
} else {
hr = E_OUTOFMEMORY;
}
if (FAILED(hr)) {
delete pDrv;
}
} else {
hr = E_OUTOFMEMORY;
}
return hr;
}
HRESULT CDrv::DeregisterDriver(IDsDriver *pIDsDriver)
{
CDrv *pDrv;
ASSERT(0 != gvmmlistDrivers);
pDrv = FindFromIDsDriver(pIDsDriver);
if (NULL == pDrv) {
BREAK(("Tried to deregister a driver that's not registered"));
return DSERR_INVALIDPARAM;
}
if (0 != pDrv->m_cOpen) {
DPF(("warning: driver deregistered while it was open"));
}
CBuf::DeregisterBuffers(pDrv->m_listBuffers);
pDrv->m_fDeregistered = TRUE;
pDrv->Release();
return S_OK;
}
//--------------------------------------------------------------------------;
//
// CDrv::GetNextDescFromGuid
//
// Gets the driver description of the next driver after the one having
// the specified GUID
//
// Entry:
//
// Returns (HRESULT):
//
// Notes:
//
//--------------------------------------------------------------------------;
HRESULT CDrv::GetNextDescFromGuid(LPCGUID pGuidLast, LPGUID pGuid, PDSDRIVERDESC pDrvDesc)
{
CDrv *pDrv;
DSVAL dsv;
ASSERT(gvmmlistDrivers);
if ((NULL == pGuidLast) || IsEqualGUID(GUID_NULL, *pGuidLast)) {
pDrv = (CDrv*)List_Get_First(gvmmlistDrivers);
} else {
pDrv = FindFromGuid(*pGuidLast);
if (NULL != pDrv) {
pDrv = (CDrv*)List_Get_Next(gvmmlistDrivers, pDrv);
}
}
if (NULL == pDrv) return DSERR_NODRIVER;
*pGuid = pDrv->m_guidDriver;
dsv = pDrv->GetDriverDesc(pDrvDesc);
return dsv;
}
HRESULT CDrv::GetDescFromGuid(REFGUID rguidDriver, PDSDRIVERDESC pDrvDesc)
{
CDrv *pDrv;
DSVAL dsv;
ASSERT(gvmmlistDrivers);
pDrv = FindFromGuid(rguidDriver);
if (NULL == pDrv) return DSERR_NODRIVER;
dsv = pDrv->GetDriverDesc(pDrvDesc);
return dsv;
}
HRESULT CDrv::OpenFromGuid(REFGUID refGuid, IDsDriver **ppIDsDriver)
{
CDrv *pDrv;
HRESULT hr;
*ppIDsDriver = NULL;
pDrv = FindFromGuid(refGuid);
if (pDrv) {
hr = pDrv->Open();
if (SUCCEEDED(hr)) {
*ppIDsDriver = pDrv;
}
} else {
hr = DSERR_NODRIVER;
}
return hr;
}
CDrv* CDrv::FindFromIDsDriver(IDsDriver *pIDsDriver)
{
CDrv *pDrv;
ASSERT(gvmmlistDrivers);
pDrv = (CDrv*)List_Get_First(gvmmlistDrivers);
while ((NULL != pDrv) && (pDrv->m_pIDsDriver_Real != pIDsDriver)) {
pDrv = (CDrv*)List_Get_Next(gvmmlistDrivers, pDrv);
}
return pDrv;
}
CDrv* CDrv::FindFromGuid(REFGUID riid)
{
CDrv *pDrv;
ASSERT(gvmmlistDrivers);
pDrv = (CDrv*)List_Get_First(gvmmlistDrivers);
while ((NULL != pDrv) && (!IsEqualGUID(riid, pDrv->m_guidDriver))) {
pDrv = (CDrv*)List_Get_Next(gvmmlistDrivers, pDrv);
}
return pDrv;
}
//==========================================================================;
//
// COM interface implementations
//
//==========================================================================;
STDMETHODIMP CDrv::QueryInterface(REFIID riid, PVOID* ppv)
{
*ppv = NULL;
if ((IID_IUnknown == riid) || (IID_IDsDriver == riid))
*ppv = this;
if (NULL == *ppv)
return E_NOINTERFACE;
((LPUNKNOWN)*ppv)->AddRef();
return NOERROR;
}
STDMETHODIMP_(ULONG) CDrv::AddRef(void)
{
ASSERT(m_cRef >= 0);
return ++m_cRef;
}
STDMETHODIMP_(ULONG) CDrv::Release(void)
{
ASSERT(m_cRef > 0);
if (0 >= --m_cRef) {
ASSERT(gvmmlistDrivers);
List_Remove(gvmmlistDrivers, this);
GuidFree(m_guidDriver);
ASSERT(m_listBuffers);
ASSERT(!List_Get_First(m_listBuffers));
CBuf::DestroyList(m_listBuffers);
m_listBuffers = NULL;
delete this;
return 0;
} else {
return m_cRef;
}
}
STDMETHODIMP CDrv::GetDriverDesc(PDSDRIVERDESC pDsDriverDesc)
{
if (m_fDeregistered) return DSERR_NODRIVER;
DRVCALL(("IDsDriver(%08Xh)->GetDriverDesc(%08Xh)", m_pIDsDriver_Real, pDsDriverDesc));
return m_pIDsDriver_Real->GetDriverDesc(pDsDriverDesc);
}
STDMETHODIMP CDrv::Open(void)
{
HRESULT hr;
ASSERT(0 == m_cOpen);
if (m_fDeregistered) return DSERR_NODRIVER;
DRVCALL(("IDsDriver(%08Xh)->Open()", m_pIDsDriver_Real));
hr = m_pIDsDriver_Real->Open();
if (SUCCEEDED(hr)) {
m_cOpen++;
AddRef();
}
return hr;
}
STDMETHODIMP CDrv::Close(void)
{
HRESULT hr;
ASSERT(m_cOpen > 0);
m_cOpen--;
if (m_fDeregistered) {
DPF(("driver must have deregistered while open"));
Release();
return NOERROR;
}
DRVCALL(("IDsDriver(%08Xh)->Close()", m_pIDsDriver_Real));
hr = m_pIDsDriver_Real->Close();
if (SUCCEEDED(hr)) Release();
// Warning: _this_ object may have been destroyed by
// the above calls to Release();
return hr;
}
STDMETHODIMP CDrv::GetCaps(PDSDRIVERCAPS pDsDriverCaps)
{
if (m_fDeregistered) {
return DSERR_NODRIVER;
} else {
DRVCALL(("IDsDriver(%08Xh)->GetCaps(%08Xh)", m_pIDsDriver_Real, pDsDriverCaps));
return m_pIDsDriver_Real->GetCaps(pDsDriverCaps);
}
}
STDMETHODIMP CDrv::CreateSoundBuffer(LPWAVEFORMATEX pwfx,
DWORD dwFlags,
DWORD dwCardAddress,
LPDWORD pdwcbBufferSize,
LPBYTE *ppbBuffer,
LPVOID *ppv)
{
LPWAVEFORMATEX pwfxKernel;
int cbwfx;
IDsDriverBuffer *pIDsDriverBuffer_Real;
HRESULT hr;
*ppv = NULL;
if (m_fDeregistered) {
return DSERR_NODRIVER;
}
//
// Note that some drivers (mwave) appear to access the WAVEFORMATEX
// structure from another thread. So, we must guarantee that the
// this structure is in the global heap before passing it to the
// driver. As a side effect, this code also ensures that a full
// WAVEFORMATEX structure is passed to the driver, not just a
// PCMWAVEFORMAT. I seem to recall some drivers always expecting
// a full WAVEFORMATEX structure, but I'm not sure.
//
if (WAVE_FORMAT_PCM == pwfx->wFormatTag) {
cbwfx = sizeof(PCMWAVEFORMAT);
} else {
cbwfx = sizeof(WAVEFORMATEX) + pwfx->cbSize;
}
pwfxKernel = (LPWAVEFORMATEX)_HeapAllocate(max(cbwfx, sizeof(WAVEFORMATEX)), HEAPZEROINIT | HEAPSWAP);
if (pwfxKernel) {
memcpy(pwfxKernel, pwfx, cbwfx);
DRVCALL(("IDsDriver(%08Xh)->CreateSoundBuffer(%08X, %08X, %08X, %08X, %08X, %08X)",
m_pIDsDriver_Real, pwfx, dwFlags, dwCardAddress, pdwcbBufferSize, ppbBuffer, &pIDsDriverBuffer_Real));
hr = m_pIDsDriver_Real->CreateSoundBuffer(pwfxKernel, dwFlags, dwCardAddress, pdwcbBufferSize,
ppbBuffer, (PVOID*)&pIDsDriverBuffer_Real);
if (SUCCEEDED(hr)) {
hr = CBuf::CreateBuf(this, m_listBuffers, pIDsDriverBuffer_Real, (IDsDriverBuffer**)ppv);
if (FAILED(hr)) {
pIDsDriverBuffer_Real->Release();
ASSERT(NULL == *ppv);
}
}
_HeapFree(pwfxKernel, 0);
} else {
hr = E_OUTOFMEMORY;
}
return hr;
}
STDMETHODIMP CDrv::DuplicateSoundBuffer(PIDSDRIVERBUFFER pIDsDriverBuffer, LPVOID *ppv)
{
IDsDriverBuffer *pIDsDriverBufferDup_Real;
HRESULT hr;
*ppv = NULL;
if (m_fDeregistered) {
return DSERR_NODRIVER;
}
DRVCALL(("IDsDriver(%08Xh)->DuplicateSoundBuffer(...)", m_pIDsDriver_Real));
hr = m_pIDsDriver_Real->DuplicateSoundBuffer(((CBuf*)pIDsDriverBuffer)->GetRealDsDriverBuffer(), (PVOID*)&pIDsDriverBufferDup_Real);
if (SUCCEEDED(hr)) {
hr = CBuf::CreateBuf(this, m_listBuffers, pIDsDriverBufferDup_Real, (IDsDriverBuffer**)ppv);
if (FAILED(hr)) {
DRVCALL(("IDsDriver(%08Xh)->Release()", m_pIDsDriver_Real));
pIDsDriverBufferDup_Real->Release();
ASSERT(NULL == *ppv);
}
}
return hr;
}
//==========================================================================;
//
// DSOUND_RegisterDeviceDriver
// DSOUND_DeregisterDeviceDriver
//
// These services are called by a direct sound driver when the driver
// initializes or terminates to register/deregister itself as a direct
// sound driver. Typcially, these would be called from
// within the driver's PnP CONFIG_START and CONFIG_STOP handlers.
//
// Entry:
// PIDSDRIVER pIDsDriver: pointer to the driver's interface
//
// DWORD dwFlags: reserved, caller should set to 0
//
// Returns (DSVAL):
//
// Notes:
// We maintain a list of drivers using the VMM List_* services. Each node
// of the list is a DSDRV structure. During registration, a list node is
// created and insterted into the list. The pIDsDriver member is initialized
// with a pointer to the driver's interface. When deregistering, the node
// is marked as deregistered. If there are no open instances on the driver,
// then the node is removed from the list.
//
//==========================================================================;
HRESULT SERVICE DSOUND_RegisterDeviceDriver(PIDSDRIVER pIDsDriver, DWORD dwFlags)
{
DPF(("DSOUND_RegisterDeviceDriver(%08Xh, %08Xh)", pIDsDriver, dwFlags));
return CDrv::CreateAndRegisterDriver(pIDsDriver);
}
HRESULT SERVICE DSOUND_DeregisterDeviceDriver(PIDSDRIVER pIDsDriver, DWORD dwFlags)
{
DPF(("DSOUND_DeregisterDeviceDriver(%08Xh, %08Xh)", pIDsDriver, dwFlags));
return CDrv::DeregisterDriver(pIDsDriver);
}
//==========================================================================;
//
// VxD CONTROL routines for drv
//
//==========================================================================;
int ctrlDrvInit()
{
int i;
gvmmlistDrivers = List_Create(LF_ALLOC_ERROR, sizeof(CDrv));
if (0 == gvmmlistDrivers) return 0;
gpaGuidRec = (PGUIDRECORD)_HeapAllocate( NUMGUIDS*sizeof(gpaGuidRec[0]), HEAPZEROINIT );
if (NULL == gpaGuidRec) {
List_Destroy(gvmmlistDrivers);
gvmmlistDrivers = 0;
return 0;
}
for (i=0; i<NUMGUIDS; i++)
gpaGuidRec[i].pGuid = &guidList[i];
return 1;
}
int ctrlDrvExit()
{
if (NULL != gpaGuidRec) {
_HeapFree(gpaGuidRec, 0);
gpaGuidRec = NULL;
}
if (0 != gvmmlistDrivers) {
List_Destroy(gvmmlistDrivers);
gvmmlistDrivers = 0;
}
return 1;
}