windows-nt/Source/XPSP1/NT/multimedia/directx/dmusic/dmime/dmgraph.cpp
2020-09-26 16:20:57 +08:00

1055 lines
31 KiB
C++

// Copyright (c) 1998-2001 Microsoft Corporation
// DMGraph.cpp : Implementation of CGraph
#include "dmime.h"
#include "DMGraph.h"
#include "dmusicc.h"
#include "dmusici.h"
#include "dmusicf.h"
#include "..\shared\dmstrm.h"
#include "..\shared\validp.h"
#include "dls1.h"
#include "debug.h"
#include "..\shared\Validate.h"
#include <strsafe.h>
#define ASSERT assert
CGraph::CGraph()
{
m_cRef = 1;
memset(&m_guidObject,0,sizeof(m_guidObject));
m_dwValidData = DMUS_OBJ_CLASS; // upon creation, only this data is valid
memset(&m_ftDate, 0,sizeof(m_ftDate));
memset(&m_vVersion, 0,sizeof(m_vVersion));
memset(m_wszName, 0, sizeof(WCHAR) * DMUS_MAX_NAME);
memset(m_wszCategory, 0, sizeof(WCHAR) * DMUS_MAX_CATEGORY);
memset(m_wszFileName, 0, sizeof(WCHAR) * DMUS_MAX_FILENAME);
InitializeCriticalSection(&m_CrSec);
InterlockedIncrement(&g_cComponent);
}
CGraph::~CGraph()
{
Shutdown(); // shouldn't be needed, but doesn't hurt
DeleteCriticalSection(&m_CrSec);
InterlockedDecrement(&g_cComponent);
}
STDMETHODIMP CGraph::QueryInterface(
const IID &iid, // @parm Interface to query for
void **ppv) // @parm The requested interface will be returned here
{
V_INAME(CGraph::QueryInterface);
V_PTRPTR_WRITE(ppv);
V_REFGUID(iid);
if (iid == IID_IUnknown || iid == IID_IDirectMusicGraph || iid == IID_IDirectMusicGraph8)
{
*ppv = static_cast<IDirectMusicGraph8*>(this);
}
else if (iid == IID_CGraph)
{
*ppv = static_cast<CGraph*>(this);
}
else if (iid == IID_IDirectMusicObject)
{
*ppv = static_cast<IDirectMusicObject*>(this);
}
else if (iid == IID_IPersistStream)
{
*ppv = static_cast<IPersistStream*>(this);
}
else if (iid == IID_IGraphClone)
{
*ppv = static_cast<IGraphClone*>(this);
}
else
{
*ppv = NULL;
Trace(4,"Warning: Request to query unknown interface on ToolGraph object\n");
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(this)->AddRef();
return S_OK;
}
// @method:(INTERNAL) HRESULT | IDirectMusicGraph | AddRef | Standard AddRef implementation for <i IDirectMusicGraph>
//
// @rdesc Returns the new reference count for this object.
//
STDMETHODIMP_(ULONG) CGraph::AddRef()
{
return InterlockedIncrement(&m_cRef);
}
// @method:(INTERNAL) HRESULT | IDirectMusicGraph | Release | Standard Release implementation for <i IDirectMusicGraph>
//
// @rdesc Returns the new reference count for this object.
//
STDMETHODIMP_(ULONG) CGraph::Release()
{
if (!InterlockedDecrement(&m_cRef))
{
delete this;
return 0;
}
return m_cRef;
}
/*
Made internal 9/25/98
method HRESULT | IDirectMusicGraph | Shutdown |
Shuts down the graph. This must be called when the graph is no longer needed,
in order to release the tools and other memory. A call to Release is not
sufficient, because there is circular referencing between the graph and the tools.
However, only the segment, performance, or whatever owns the graph
should call this function.
rvalue S_OK | Success.
rvalue S_FALSE | Success, but didn't need to do anything.
*/
HRESULT STDMETHODCALLTYPE CGraph::Shutdown()
{
// release all Tools
CToolRef* pObj;
HRESULT hr = S_OK;
EnterCriticalSection(&m_CrSec);
if( IsEmpty() )
{
hr = S_FALSE;
}
else
{
while( pObj = RemoveHead() )
{
delete pObj;
}
}
LeaveCriticalSection(&m_CrSec);
return hr;
}
HRESULT CGraph::InsertTool(
IDirectMusicTool *pTool,
DWORD *pdwPChannels,
DWORD cPChannels,
LONG lIndex,
GUID *pguidClassID)
{
HRESULT hr = S_OK;
EnterCriticalSection(&m_CrSec);
CToolRef* pToolRef;
// make sure that this Tool instance isn't already in the Graph
for( pToolRef = GetHead(); pToolRef; pToolRef = pToolRef->GetNext() )
{
if( pTool == pToolRef->m_pTool )
{
LeaveCriticalSection(&m_CrSec);
Trace(1,"Error: Multiple install of the same tool in a graph\n");
return DMUS_E_ALREADY_EXISTS;
}
}
// insert this Tool instance into the Graph
pToolRef = new CToolRef;
if( pToolRef )
{
DWORD dwTemp;
DWORD* pdwArray = NULL;
pToolRef->m_pTool = pTool;
pTool->AddRef();
pTool->Init(this);
dwTemp = 0;
IDirectMusicTool8 *pTool8;
if (SUCCEEDED(pTool->QueryInterface(IID_IDirectMusicTool8,(void **) &pTool8)))
{
pToolRef->m_fSupportsClone = TRUE;
pTool8->Release();
}
if (pguidClassID)
{
pToolRef->m_guidClassID = *pguidClassID;
}
else
{
IPersistStream *pPersist;
if (SUCCEEDED(pTool->QueryInterface(IID_IPersistStream,(void **) &pPersist)))
{
pPersist->GetClassID(&pToolRef->m_guidClassID);
pPersist->Release();
}
}
pTool->GetMsgDeliveryType(&dwTemp);
if( (dwTemp != DMUS_PMSGF_TOOL_IMMEDIATE) && (dwTemp != DMUS_PMSGF_TOOL_QUEUE) && (dwTemp != DMUS_PMSGF_TOOL_ATTIME) )
{
dwTemp = DMUS_PMSGF_TOOL_IMMEDIATE;
}
pToolRef->m_dwQueue = dwTemp;
if( FAILED( pTool->GetMediaTypeArraySize(&dwTemp)))
{
dwTemp = 0;
}
pToolRef->m_dwMTArraySize = dwTemp;
if( dwTemp )
{
pdwArray = new DWORD[dwTemp];
if( pdwArray )
{
HRESULT hrTemp = pTool->GetMediaTypes( &pdwArray, dwTemp );
if( hrTemp == E_NOTIMPL )
{
delete [] pdwArray;
pToolRef->m_dwMTArraySize = 0;
}
else
{
pToolRef->m_pdwMediaTypes = pdwArray;
}
}
else
{
delete pToolRef;
LeaveCriticalSection(&m_CrSec);
return E_OUTOFMEMORY;
}
}
if( pdwPChannels )
{
pToolRef->m_pdwPChannels = new DWORD[cPChannels];
if( pToolRef->m_pdwPChannels )
{
memcpy( pToolRef->m_pdwPChannels, pdwPChannels, sizeof(DWORD) * cPChannels );
pToolRef->m_dwPCArraySize = cPChannels;
}
else
{
delete pToolRef;
LeaveCriticalSection(&m_CrSec);
return E_OUTOFMEMORY;
}
}
if (lIndex < 0)
{
lIndex += AList::GetCount(); // Make index be offset from end.
}
CToolRef *pNext = GetItem(lIndex);
if (pNext)
{
InsertBefore(pNext,pToolRef);
}
else
{
AList::AddTail(pToolRef);
}
}
else
{
hr = E_OUTOFMEMORY;
}
LeaveCriticalSection(&m_CrSec);
return hr;
}
HRESULT STDMETHODCALLTYPE CGraph::InsertTool(
IDirectMusicTool *pTool, // @parm The Tool to insert.
DWORD *pdwPChannels, // @parm An array of which PChannels to place the tool in. These are
// id's which are converted to MIDI Channel + Port on output. If the
// tool accepts messages on all PChannels, this is NULL. <p cPChannels>
// is the count of how many this array points to.
DWORD cPChannels, // @parm Count of how many PChannels are pointed to by <p pdwPChannels>.
LONG lIndex) // @parm At what position to place the tool. This is an index from either the start
// of the current tool list or, working backwards from the end (in which case, it is
// a negative number.) If <p lIndex> is out of range, the Tool will be placed at
// the very beginning or end of the Tool list. 0 is the beginning. To place a Tool
// at the end of the list, use a number for <p lIndex> that is larger than the number
// of tools in the current tool list.
{
V_INAME(IDirectMusicGraph::InsertTool);
V_INTERFACE(pTool);
V_BUFPTR_READ_OPT(pdwPChannels, sizeof(DWORD) * cPChannels);
return InsertTool(pTool,pdwPChannels,cPChannels,lIndex,NULL);
}
HRESULT CGraph::GetObjectInPath( DWORD dwPChannel,REFGUID guidObject,
DWORD dwIndex,REFGUID iidInterface, void ** ppObject)
{
V_INAME(IDirectMusicGraph::GetObjectInPath);
V_PTRPTR_WRITE(ppObject);
HRESULT hr = DMUS_E_NOT_FOUND;
CToolRef* pPlace;
if( !IsEmpty() )
{
pPlace = NULL;
// search for the tool
EnterCriticalSection(&m_CrSec);
for( pPlace = GetHead(); pPlace;
pPlace = pPlace->GetNext() )
{
if ((guidObject == pPlace->m_guidClassID) || (guidObject == GUID_All_Objects))
{
BOOL fFound = (!pPlace->m_pdwPChannels || (dwPChannel >= DMUS_PCHANNEL_ALL));
if( !fFound )
{
DWORD cCount;
// scan through the array of PChannels to see if this one
// supports dwPChannel
for( cCount = 0; cCount < pPlace->m_dwPCArraySize; cCount++)
{
if( dwPChannel == pPlace->m_pdwPChannels[cCount] )
{
fFound = TRUE;
// yep, it supports it
break;
}
}
}
if (fFound)
{
if (!dwIndex)
{
break;
}
else
{
dwIndex--;
}
}
}
}
if( pPlace )
{
hr = pPlace->m_pTool->QueryInterface(iidInterface,ppObject);
}
LeaveCriticalSection(&m_CrSec);
}
#ifdef DBG
if (hr == DMUS_E_NOT_FOUND)
{
Trace(1,"Error: Requested Tool not found in Graph\n");
}
#endif
return hr;
}
/*
@method HRESULT | IDirectMusicGraph | GetTool |
Returns the Tool at the specified index.
@rvalue DMUS_E_NOT_FOUND | Unable to find a Tool at the position described.
@rvalue E_POINTER | ppTool is NULL or invalid.
@rvalue S_OK | Success.
@comm The retrieved tool is AddRef'd by this call, so be sure to Release it.
*/
HRESULT STDMETHODCALLTYPE CGraph::GetTool(
DWORD dwIndex, // @parm The index, from the beginning and starting at 0,
// at which to retrieve the Tool from the Graph.
IDirectMusicTool **ppTool) // @parm The <i IDirectMusicTool> pointer to use
// for returning the requested tool.
{
V_INAME(IDirectMusicGraph::GetTool);
V_PTRPTR_WRITE(ppTool);
CToolRef* pPlace;
HRESULT hr = S_OK;
if( IsEmpty() )
{
Trace(1,"Error: GetTool failed because the Tool Graph is empty\n");
return DMUS_E_NOT_FOUND;
}
pPlace = NULL;
// search for the indexed tool
EnterCriticalSection(&m_CrSec);
for( pPlace = GetHead(); ( dwIndex > 0 ) && pPlace;
pPlace = pPlace->GetNext() )
{
dwIndex--;
}
if( NULL == pPlace )
{
hr = DMUS_E_NOT_FOUND;
}
else
{
*ppTool = pPlace->m_pTool;
(*ppTool)->AddRef();
}
LeaveCriticalSection(&m_CrSec);
return hr;
}
/*
@method HRESULT | IDirectMusicGraph | RemoveTool |
Removes the Tool from the Graph.
@rvalue DMUS_E_NOT_FOUND | The specified Tool is not in the Graph.
@rvalue E_POINTER | pTool is NULL or invalid.
@rvalue S_OK | Success.
@comm The Tool is removed from the Graph, and the Graph's reference on the Tool
object is released.
*/
HRESULT STDMETHODCALLTYPE CGraph::RemoveTool(
IDirectMusicTool *pTool) // @parm The <i IDirectMusicTool> pointer of the Tool to remove.
{
V_INAME(IDirectMusicGraph::RemoveTool);
V_INTERFACE(pTool);
CToolRef* pPlace;
HRESULT hr = S_OK;
EnterCriticalSection(&m_CrSec);
// search for the tool
for( pPlace = GetHead(); pPlace; pPlace = pPlace->GetNext() )
{
if( pPlace->m_pTool == pTool )
break;
}
if( NULL == pPlace )
{
Trace(1,"Error: RemoveTool - Tool not in Graph.\n");
hr = DMUS_E_NOT_FOUND;
}
else
{
AList::Remove(pPlace);
delete pPlace;
}
LeaveCriticalSection(&m_CrSec);
return hr;
}
STDMETHODIMP CGraph::Clone(IDirectMusicGraph **ppGraph)
{
V_INAME(IDirectMusicGraph::Clone);
V_PTRPTR_WRITE(ppGraph);
HRESULT hr = E_OUTOFMEMORY;
EnterCriticalSection(&m_CrSec);
CGraph *pNew = new CGraph;
if (pNew)
{
pNew->m_dwValidData = m_dwValidData;
pNew->m_ftDate = m_ftDate;
pNew->m_guidObject = m_guidObject;
pNew->m_vVersion = m_vVersion;
StringCchCopyW(pNew->m_wszCategory, DMUS_MAX_CATEGORY, m_wszCategory);
StringCchCopyW(pNew->m_wszFileName, DMUS_MAX_FILENAME, m_wszFileName);
StringCchCopyW(pNew->m_wszName, DMUS_MAX_NAME, m_wszName);
CToolRef *pSource = GetHead();
CToolRef *pDest;
for (;pSource;pSource = pSource->GetNext())
{
pDest = new CToolRef;
if (pDest)
{
pNew->AList::AddTail(pDest);
pDest->m_dwMTArraySize = pSource->m_dwMTArraySize;
pDest->m_dwPCArraySize = pSource->m_dwPCArraySize;
pDest->m_dwQueue = pSource->m_dwQueue;
pDest->m_fSupportsClone = pSource->m_fSupportsClone;
pDest->m_guidClassID = pSource->m_guidClassID;
if (pSource->m_dwMTArraySize)
{
pDest->m_pdwMediaTypes = new DWORD[pSource->m_dwMTArraySize];
if (pDest->m_pdwMediaTypes)
{
memcpy(pDest->m_pdwMediaTypes,pSource->m_pdwMediaTypes,
sizeof(DWORD)*pDest->m_dwMTArraySize);
}
else
{
pDest->m_dwMTArraySize = 0;
}
}
else
{
pDest->m_pdwMediaTypes = NULL;
}
if (pSource->m_dwPCArraySize)
{
pDest->m_pdwPChannels = new DWORD[pSource->m_dwPCArraySize];
if (pDest->m_pdwPChannels)
{
memcpy(pDest->m_pdwPChannels,pSource->m_pdwPChannels,
sizeof(DWORD)*pDest->m_dwPCArraySize);
}
else
{
pDest->m_dwPCArraySize = 0;
}
}
else
{
pDest->m_pdwPChannels = NULL;
}
if (pSource->m_pTool)
{
if (pDest->m_fSupportsClone)
{
IDirectMusicTool8 *pTool8 = (IDirectMusicTool8 *) pSource->m_pTool;
pTool8->Clone(&pDest->m_pTool);
}
else
{
pDest->m_pTool = pSource->m_pTool;
pDest->m_pTool->AddRef();
}
}
}
else
{
delete pNew;
pNew = NULL;
break;
}
}
}
*ppGraph = (IDirectMusicGraph *) pNew;
if (pNew) hr = S_OK;
LeaveCriticalSection(&m_CrSec);
return hr;
}
// returns TRUE if dwType is supported by pToolRef
inline BOOL CGraph::CheckType( DWORD dwType, CToolRef* pToolRef )
{
BOOL fReturn = FALSE;
if( pToolRef->m_dwMTArraySize == 0 )
{
fReturn = TRUE; // supports all types
}
else
{
DWORD dw;
ASSERT( pToolRef->m_pdwMediaTypes );
for( dw = 0; dw < pToolRef->m_dwMTArraySize; dw++ )
{
if( dwType == pToolRef->m_pdwMediaTypes[dw] )
{
fReturn = TRUE;
break;
}
}
}
return fReturn;
}
HRESULT STDMETHODCALLTYPE CGraph::StampPMsg(
DMUS_PMSG* pPMsg) // @parm The message to stamp.
{
V_INAME(IDirectMusicGraph::StampPMsg);
V_BUFPTR_WRITE(pPMsg, sizeof(DMUS_PMSG));
HRESULT hr = S_OK;
if( NULL == pPMsg )
{
return E_INVALIDARG;
}
EnterCriticalSection(&m_CrSec);
CToolRef* pPlace = GetHead();
IDirectMusicTool* pPriorTool;
DWORD dwType;
DWORD dwPChannel;
pPriorTool = pPMsg->pTool;
dwType = pPMsg->dwType;
dwPChannel = pPMsg->dwPChannel;
if( pPriorTool )
{
for( ; pPlace; pPlace = pPlace->GetNext() )
{
if( pPriorTool == pPlace->m_pTool )
{
pPlace = pPlace->GetNext();
break;
}
}
}
BOOL fFound = FALSE;
for( ; pPlace ; pPlace = pPlace->GetNext() )
{
if( CheckType(dwType, pPlace) )
{
if( !pPlace->m_pdwPChannels || (dwPChannel >= DMUS_PCHANNEL_BROADCAST_GROUPS))
{
// supports all tracks, or requested channel is broadcast.
break;
}
DWORD cCount;
// scan through the array of PChannels to see if this one
// supports dwPChannel
for( cCount = 0; cCount < pPlace->m_dwPCArraySize; cCount++)
{
if( dwPChannel == pPlace->m_pdwPChannels[cCount] )
{
fFound = TRUE;
// yep, it supports it
break;
}
}
}
if (fFound) break;
}
// release the current tool
if( pPMsg->pTool )
{
pPMsg->pTool->Release();
pPMsg->pTool = NULL;
}
if( NULL == pPlace )
{
hr = DMUS_S_LAST_TOOL;
}
else
{
// if there is no graph pointer, set it to this
if( NULL == pPMsg->pGraph )
{
pPMsg->pGraph = this;
AddRef();
}
// set to the new tool and addref
if (pPlace->m_pTool) // Just in case, the ptool sometimes goes away in debugging situations after a long break.
{
pPMsg->pTool = pPlace->m_pTool;
pPMsg->pTool->AddRef();
}
// set the event's queue type
pPMsg->dwFlags &= ~(DMUS_PMSGF_TOOL_IMMEDIATE | DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_ATTIME);
pPMsg->dwFlags |= pPlace->m_dwQueue;
}
LeaveCriticalSection(&m_CrSec);
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// IPersist
HRESULT CGraph::GetClassID( CLSID* pClassID )
{
V_INAME(CGraph::GetClassID);
V_PTR_WRITE(pClassID, CLSID);
*pClassID = CLSID_DirectMusicGraph;
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// IPersistStream functions
HRESULT CGraph::IsDirty()
{
return S_FALSE;
}
HRESULT CGraph::Load( IStream* pIStream )
{
V_INAME(IPersistStream::Load);
V_INTERFACE(pIStream);
CRiffParser Parser(pIStream);
RIFFIO ckMain;
HRESULT hr = S_OK;
Parser.EnterList(&ckMain);
if (Parser.NextChunk(&hr) && (ckMain.fccType == DMUS_FOURCC_TOOLGRAPH_FORM))
{
Shutdown(); // Clear out the tools that are currently in the graph.
hr = Load(&Parser);
}
else
{
Trace(1,"Error: Unknown file format when parsing Tool Graph\n");
hr = DMUS_E_DESCEND_CHUNK_FAIL;
}
return hr;
}
HRESULT CGraph::Load(CRiffParser *pParser)
{
RIFFIO ckNext;
RIFFIO ckChild;
HRESULT hr = S_OK;
pParser->EnterList(&ckNext);
while(pParser->NextChunk(&hr))
{
switch(ckNext.ckid)
{
case DMUS_FOURCC_GUID_CHUNK:
hr = pParser->Read( &m_guidObject, sizeof(GUID) );
m_dwValidData |= DMUS_OBJ_OBJECT;
break;
case DMUS_FOURCC_VERSION_CHUNK:
hr = pParser->Read( &m_vVersion, sizeof(DMUS_VERSION) );
m_dwValidData |= DMUS_OBJ_VERSION;
break;
case DMUS_FOURCC_CATEGORY_CHUNK:
hr = pParser->Read( &m_wszCategory, sizeof(WCHAR)*DMUS_MAX_CATEGORY );
m_wszCategory[DMUS_MAX_CATEGORY-1] = '\0';
m_dwValidData |= DMUS_OBJ_CATEGORY;
break;
case DMUS_FOURCC_DATE_CHUNK:
hr = pParser->Read( &m_ftDate, sizeof(FILETIME) );
m_dwValidData |= DMUS_OBJ_DATE;
break;
case FOURCC_LIST:
switch(ckNext.fccType)
{
case DMUS_FOURCC_UNFO_LIST:
pParser->EnterList(&ckChild);
while (pParser->NextChunk(&hr))
{
if ( ckChild.ckid == DMUS_FOURCC_UNAM_CHUNK)
{
hr = pParser->Read(&m_wszName, sizeof(m_wszName));
m_wszName[DMUS_MAX_NAME-1] = '\0';
m_dwValidData |= DMUS_OBJ_NAME;
}
}
pParser->LeaveList();
break;
case DMUS_FOURCC_TOOL_LIST:
pParser->EnterList(&ckChild);
while(pParser->NextChunk(&hr))
{
if ((ckChild.ckid == FOURCC_RIFF) &&
(ckChild.fccType == DMUS_FOURCC_TOOL_FORM))
{
hr = LoadTool(pParser);
}
}
pParser->LeaveList();
break;
}
break;
}
}
pParser->LeaveList();
return hr;
}
HRESULT CGraph::LoadTool(CRiffParser *pParser)
{
RIFFIO ckNext;
DWORD cbSize;
DMUS_IO_TOOL_HEADER ioDMToolHdr;
DWORD *pdwPChannels = NULL;
HRESULT hr = S_OK;
pParser->EnterList(&ckNext);
if (pParser->NextChunk(&hr))
{
if(ckNext.ckid != DMUS_FOURCC_TOOL_CHUNK)
{
pParser->LeaveList();
Trace(1,"Error: Tool header chunk not first in tool list.\n");
return DMUS_E_TOOL_HDR_NOT_FIRST_CK;
}
hr = pParser->Read(&ioDMToolHdr, sizeof(DMUS_IO_TOOL_HEADER));
if(ioDMToolHdr.ckid == 0 && ioDMToolHdr.fccType == NULL)
{
pParser->LeaveList();
Trace(1,"Error: Invalid Tool header.\n");
return DMUS_E_INVALID_TOOL_HDR;
}
if(ioDMToolHdr.cPChannels)
{
pdwPChannels = new DWORD[ioDMToolHdr.cPChannels];
// subtract 1 from cPChannels, because 1 element is actually stored
// in the ioDMToolHdr array.
cbSize = (ioDMToolHdr.cPChannels - 1) * sizeof(DWORD);
if(pdwPChannels)
{
pdwPChannels[0] = ioDMToolHdr.dwPChannels[0];
if( cbSize )
{
hr = pParser->Read(&pdwPChannels[1], cbSize);
if(FAILED(hr))
{
delete [] pdwPChannels;
pdwPChannels = NULL;
pParser->LeaveList();
Trace(1,"Error: File read error loading Tool.\n");
return DMUS_E_CANNOTREAD;
}
}
}
else
{
hr = E_OUTOFMEMORY;
}
}
}
else
{
pParser->LeaveList();
Trace(1,"Error reading Tool chunk - not RIFF format.\n");
hr = DMUS_E_DESCEND_CHUNK_FAIL;
}
while (pParser->NextChunk(&hr))
{
if((((ckNext.ckid == FOURCC_LIST) || (ckNext.ckid == FOURCC_RIFF))
&& ckNext.fccType == ioDMToolHdr.fccType) ||
(ckNext.ckid == ioDMToolHdr.ckid))
{
pParser->SeekBack();
hr = CreateTool(ioDMToolHdr, pParser->GetStream(), pdwPChannels);
pParser->SeekForward();
}
}
pParser->LeaveList();
if( pdwPChannels )
{
delete [] pdwPChannels;
pdwPChannels = NULL;
}
return hr;
}
HRESULT CGraph::CreateTool(DMUS_IO_TOOL_HEADER ioDMToolHdr, IStream *pStream, DWORD *pdwPChannels)
{
assert(pStream);
IDirectMusicTool* pDMTool = NULL;
HRESULT hr = CoCreateInstance(ioDMToolHdr.guidClassID,
NULL,
CLSCTX_INPROC,
IID_IDirectMusicTool,
(void**)&pDMTool);
IPersistStream *pIPersistStream = NULL;
if(SUCCEEDED(hr))
{
hr = pDMTool->QueryInterface(IID_IPersistStream, (void **)&pIPersistStream);
}
else
{
Trace(1,"Error creating tool for loading\n");
}
if(SUCCEEDED(hr))
{
hr = pIPersistStream->Load(pStream);
if (FAILED(hr))
{
Trace(1,"Error loading data into tool\n");
}
}
if(SUCCEEDED(hr))
{
hr = InsertTool(pDMTool, pdwPChannels, ioDMToolHdr.cPChannels, ioDMToolHdr.lIndex, &ioDMToolHdr.guidClassID);
}
if(pIPersistStream)
{
pIPersistStream->Release();
}
if(pDMTool)
{
pDMTool->Release();
}
return hr;
}
HRESULT CGraph::Save( IStream* pIStream, BOOL fClearDirty )
{
return E_NOTIMPL;
}
HRESULT CGraph::GetSizeMax( ULARGE_INTEGER FAR* pcbSize )
{
return E_NOTIMPL;
}
/////////////////////////////////////////////////////////////////////////////
// IDirectMusicObject
STDMETHODIMP CGraph::GetDescriptor(LPDMUS_OBJECTDESC pDesc)
{
// Argument validation
V_INAME(CGraph::GetDescriptor);
V_STRUCTPTR_WRITE(pDesc, DMUS_OBJECTDESC);
memset( pDesc, 0, sizeof(DMUS_OBJECTDESC));
pDesc->dwSize = sizeof(DMUS_OBJECTDESC);
pDesc->guidClass = CLSID_DirectMusicGraph;
pDesc->guidObject = m_guidObject;
pDesc->ftDate = m_ftDate;
pDesc->vVersion = m_vVersion;
StringCchCopyW( pDesc->wszName, DMUS_MAX_NAME, m_wszName);
StringCchCopyW( pDesc->wszCategory, DMUS_MAX_CATEGORY, m_wszCategory);
StringCchCopyW( pDesc->wszFileName, DMUS_MAX_FILENAME, m_wszFileName);
pDesc->dwValidData = ( m_dwValidData | DMUS_OBJ_CLASS );
return S_OK;
}
STDMETHODIMP CGraph::SetDescriptor(LPDMUS_OBJECTDESC pDesc)
{
// Argument validation
V_INAME(CGraph::SetDescriptor);
V_STRUCTPTR_READ(pDesc, DMUS_OBJECTDESC);
HRESULT hr = E_INVALIDARG;
DWORD dw = 0;
if( pDesc->dwSize >= sizeof(DMUS_OBJECTDESC) )
{
if( pDesc->dwValidData & DMUS_OBJ_OBJECT )
{
m_guidObject = pDesc->guidObject;
dw |= DMUS_OBJ_OBJECT;
}
if( pDesc->dwValidData & DMUS_OBJ_NAME )
{
StringCchCopyW(m_wszName, DMUS_MAX_NAME, pDesc->wszName);
dw |= DMUS_OBJ_NAME;
}
if( pDesc->dwValidData & DMUS_OBJ_CATEGORY )
{
StringCchCopyW(m_wszCategory, DMUS_MAX_CATEGORY, pDesc->wszCategory);
dw |= DMUS_OBJ_CATEGORY;
}
if( ( pDesc->dwValidData & DMUS_OBJ_FILENAME ) ||
( pDesc->dwValidData & DMUS_OBJ_FULLPATH ) )
{
StringCchCopyW(m_wszFileName, DMUS_MAX_FILENAME, pDesc->wszFileName);
dw |= (pDesc->dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH));
}
if( pDesc->dwValidData & DMUS_OBJ_VERSION )
{
m_vVersion = pDesc->vVersion;
dw |= DMUS_OBJ_VERSION;
}
if( pDesc->dwValidData & DMUS_OBJ_DATE )
{
m_ftDate = pDesc->ftDate;
dw |= DMUS_OBJ_DATE;
}
m_dwValidData |= dw;
if( pDesc->dwValidData & (~dw) )
{
Trace(2,"Warning: ToolGraph::SetDescriptor was not able to handle all passed fields, dwValidData bits %lx.\n",pDesc->dwValidData & (~dw));
hr = S_FALSE; // there were extra fields we didn't parse;
pDesc->dwValidData = dw;
}
else
{
hr = S_OK;
}
}
else
{
Trace(1,"Error: Size of descriptor too large for Tool Graph to parse.\n");
}
return hr;
}
STDMETHODIMP CGraph::ParseDescriptor(LPSTREAM pIStream, LPDMUS_OBJECTDESC pDesc)
{
V_INAME(CGraph::ParseDescriptor);
V_INTERFACE(pIStream);
V_STRUCTPTR_WRITE(pDesc, DMUS_OBJECTDESC);
CRiffParser Parser(pIStream);
RIFFIO ckMain;
RIFFIO ckNext;
RIFFIO ckUNFO;
HRESULT hr = S_OK;
DWORD dwValidData;
Parser.EnterList(&ckMain);
if (Parser.NextChunk(&hr) && (ckMain.fccType == DMUS_FOURCC_TOOLGRAPH_FORM))
{
dwValidData = DMUS_OBJ_CLASS;
pDesc->guidClass = CLSID_DirectMusicGraph;
Parser.EnterList(&ckNext);
while(Parser.NextChunk(&hr))
{
switch(ckNext.ckid)
{
case DMUS_FOURCC_GUID_CHUNK:
hr = Parser.Read( &pDesc->guidObject, sizeof(GUID) );
dwValidData |= DMUS_OBJ_OBJECT;
break;
case DMUS_FOURCC_VERSION_CHUNK:
hr = Parser.Read( &pDesc->vVersion, sizeof(DMUS_VERSION) );
dwValidData |= DMUS_OBJ_VERSION;
break;
case DMUS_FOURCC_CATEGORY_CHUNK:
hr = Parser.Read( &pDesc->wszCategory, sizeof(pDesc->wszCategory) );
pDesc->wszCategory[DMUS_MAX_CATEGORY-1] = '\0';
dwValidData |= DMUS_OBJ_CATEGORY;
break;
case DMUS_FOURCC_DATE_CHUNK:
hr = Parser.Read( &pDesc->ftDate, sizeof(FILETIME) );
dwValidData |= DMUS_OBJ_DATE;
break;
case FOURCC_LIST:
switch(ckNext.fccType)
{
case DMUS_FOURCC_UNFO_LIST:
Parser.EnterList(&ckUNFO);
while (Parser.NextChunk(&hr))
{
if (ckUNFO.ckid == DMUS_FOURCC_UNAM_CHUNK)
{
hr = Parser.Read(&pDesc->wszName, sizeof(pDesc->wszName));
pDesc->wszName[DMUS_MAX_NAME-1] = '\0';
dwValidData |= DMUS_OBJ_NAME;
}
}
Parser.LeaveList();
break;
}
break;
}
}
Parser.LeaveList();
}
else
{
Trace(1,"Error: Parsing Tool Graph - invalid file format\n");
hr = DMUS_E_CHUNKNOTFOUND;
}
if (SUCCEEDED(hr))
{
pDesc->dwValidData = dwValidData;
}
return hr;
}
void CGraphList::Clear()
{
CGraph *pGraph;
while (pGraph = RemoveHead())
{
pGraph->Release();
}
}