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