rasapi32: Update spec file.
[wine/zf.git] / dlls / dmusic / collection.c
blob13d5ce868d3e88ea8e8dc719c14b4d85b952c778
1 /*
2 * IDirectMusicCollection Implementation
4 * Copyright (C) 2003-2004 Rok Mandeljc
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "dmusic_private.h"
22 #include "dmobject.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(dmusic);
25 WINE_DECLARE_DEBUG_CHANNEL(dmfile);
27 /*****************************************************************************
28 * IDirectMusicCollectionImpl implementation
30 typedef struct IDirectMusicCollectionImpl {
31 IDirectMusicCollection IDirectMusicCollection_iface;
32 struct dmobject dmobj;
33 LONG ref;
34 /* IDirectMusicCollectionImpl fields */
35 IStream *pStm; /* stream from which we load collection and later instruments */
36 LARGE_INTEGER liCollectionPosition; /* offset in a stream where collection was loaded from */
37 LARGE_INTEGER liWavePoolTablePosition; /* offset in a stream where wave pool table can be found */
38 CHAR *szCopyright; /* FIXME: should probably be placed somewhere else */
39 DLSHEADER *pHeader;
40 /* pool table */
41 POOLTABLE *pPoolTable;
42 POOLCUE *pPoolCues;
43 /* instruments */
44 struct list Instruments;
45 } IDirectMusicCollectionImpl;
47 static inline IDirectMusicCollectionImpl *impl_from_IDirectMusicCollection(IDirectMusicCollection *iface)
49 return CONTAINING_RECORD(iface, IDirectMusicCollectionImpl, IDirectMusicCollection_iface);
52 static inline IDirectMusicCollectionImpl *impl_from_IPersistStream(IPersistStream *iface)
54 return CONTAINING_RECORD(iface, IDirectMusicCollectionImpl, dmobj.IPersistStream_iface);
57 /* IDirectMusicCollectionImpl IUnknown part: */
58 static HRESULT WINAPI IDirectMusicCollectionImpl_QueryInterface(IDirectMusicCollection *iface,
59 REFIID riid, void **ret_iface)
61 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
63 TRACE("(%p/%p)->(%s, %p)\n", iface, This, debugstr_dmguid(riid), ret_iface);
65 *ret_iface = NULL;
67 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectMusicCollection))
68 *ret_iface = iface;
69 else if (IsEqualIID(riid, &IID_IDirectMusicObject))
70 *ret_iface = &This->dmobj.IDirectMusicObject_iface;
71 else if (IsEqualIID(riid, &IID_IPersistStream))
72 *ret_iface = &This->dmobj.IPersistStream_iface;
73 else
75 WARN("(%p/%p)->(%s, %p): not found\n", iface, This, debugstr_dmguid(riid), ret_iface);
76 return E_NOINTERFACE;
79 IUnknown_AddRef((IUnknown*)*ret_iface);
80 return S_OK;
83 static ULONG WINAPI IDirectMusicCollectionImpl_AddRef(IDirectMusicCollection *iface)
85 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
86 ULONG ref = InterlockedIncrement(&This->ref);
88 TRACE("(%p/%p)->(): new ref = %u\n", iface, This, ref);
90 return ref;
93 static ULONG WINAPI IDirectMusicCollectionImpl_Release(IDirectMusicCollection *iface)
95 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
96 ULONG ref = InterlockedDecrement(&This->ref);
98 TRACE("(%p/%p)->(): new ref = %u\n", iface, This, ref);
100 if (!ref) {
101 HeapFree(GetProcessHeap(), 0, This);
102 DMUSIC_UnlockModule();
105 return ref;
108 /* IDirectMusicCollection Interface follows: */
109 static HRESULT WINAPI IDirectMusicCollectionImpl_GetInstrument(IDirectMusicCollection *iface,
110 DWORD patch, IDirectMusicInstrument **instrument)
112 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
113 DMUS_PRIVATE_INSTRUMENTENTRY *inst_entry;
114 struct list *list_entry;
115 DWORD inst_patch;
117 TRACE("(%p/%p)->(%u, %p)\n", iface, This, patch, instrument);
119 LIST_FOR_EACH(list_entry, &This->Instruments) {
120 inst_entry = LIST_ENTRY(list_entry, DMUS_PRIVATE_INSTRUMENTENTRY, entry);
121 IDirectMusicInstrument_GetPatch(inst_entry->pInstrument, &inst_patch);
122 if (patch == inst_patch) {
123 *instrument = inst_entry->pInstrument;
124 IDirectMusicInstrument_AddRef(inst_entry->pInstrument);
125 IDirectMusicInstrumentImpl_CustomLoad(inst_entry->pInstrument, This->pStm);
126 TRACE(": returning instrument %p\n", *instrument);
127 return S_OK;
131 TRACE(": instrument not found\n");
133 return DMUS_E_INVALIDPATCH;
136 static HRESULT WINAPI IDirectMusicCollectionImpl_EnumInstrument(IDirectMusicCollection *iface,
137 DWORD index, DWORD *patch, LPWSTR name, DWORD name_length)
139 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
140 DWORD i = 0;
141 DMUS_PRIVATE_INSTRUMENTENTRY *inst_entry;
142 struct list *list_entry;
143 DWORD length;
145 TRACE("(%p/%p)->(%d, %p, %p, %d)\n", iface, This, index, patch, name, name_length);
147 LIST_FOR_EACH(list_entry, &This->Instruments) {
148 inst_entry = LIST_ENTRY(list_entry, DMUS_PRIVATE_INSTRUMENTENTRY, entry);
149 if (i == index) {
150 IDirectMusicInstrumentImpl *instrument = impl_from_IDirectMusicInstrument(inst_entry->pInstrument);
151 IDirectMusicInstrument_GetPatch(inst_entry->pInstrument, patch);
152 if (name) {
153 length = min(lstrlenW(instrument->wszName), name_length - 1);
154 memcpy(name, instrument->wszName, length * sizeof(WCHAR));
155 name[length] = '\0';
157 return S_OK;
159 i++;
162 return S_FALSE;
165 static const IDirectMusicCollectionVtbl DirectMusicCollection_Collection_Vtbl = {
166 IDirectMusicCollectionImpl_QueryInterface,
167 IDirectMusicCollectionImpl_AddRef,
168 IDirectMusicCollectionImpl_Release,
169 IDirectMusicCollectionImpl_GetInstrument,
170 IDirectMusicCollectionImpl_EnumInstrument
173 /* IDirectMusicCollectionImpl IDirectMusicObject part: */
174 static HRESULT WINAPI col_IDirectMusicObject_ParseDescriptor(IDirectMusicObject *iface,
175 IStream *stream, DMUS_OBJECTDESC *desc)
177 struct chunk_entry riff = {0};
178 HRESULT hr;
180 TRACE("(%p, %p, %p)\n", iface, stream, desc);
182 if (!stream || !desc)
183 return E_POINTER;
185 if ((hr = stream_get_chunk(stream, &riff)) != S_OK)
186 return hr;
187 if (riff.id != FOURCC_RIFF || riff.type != FOURCC_DLS) {
188 TRACE("loading failed: unexpected %s\n", debugstr_chunk(&riff));
189 stream_skip_chunk(stream, &riff);
190 return DMUS_E_NOTADLSCOL;
193 hr = dmobj_parsedescriptor(stream, &riff, desc, DMUS_OBJ_NAME_INFO|DMUS_OBJ_VERSION);
194 if (FAILED(hr))
195 return hr;
197 desc->guidClass = CLSID_DirectMusicCollection;
198 desc->dwValidData |= DMUS_OBJ_CLASS;
200 TRACE("returning descriptor:\n");
201 dump_DMUS_OBJECTDESC(desc);
202 return S_OK;
205 static const IDirectMusicObjectVtbl dmobject_vtbl = {
206 dmobj_IDirectMusicObject_QueryInterface,
207 dmobj_IDirectMusicObject_AddRef,
208 dmobj_IDirectMusicObject_Release,
209 dmobj_IDirectMusicObject_GetDescriptor,
210 dmobj_IDirectMusicObject_SetDescriptor,
211 col_IDirectMusicObject_ParseDescriptor
214 /* IDirectMusicCollectionImpl IPersistStream part: */
215 static HRESULT WINAPI IPersistStreamImpl_Load(IPersistStream *iface,
216 IStream *stream)
218 IDirectMusicCollectionImpl *This = impl_from_IPersistStream(iface);
219 DMUS_PRIVATE_CHUNK chunk;
220 DWORD StreamSize, StreamCount, ListSize[2], ListCount[2];
221 LARGE_INTEGER liMove; /* used when skipping chunks */
222 ULARGE_INTEGER dlibCollectionPosition, dlibInstrumentPosition, dlibWavePoolPosition;
224 IStream_AddRef(stream); /* add count for later references */
225 liMove.QuadPart = 0;
226 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &dlibCollectionPosition); /* store offset, in case it'll be needed later */
227 This->liCollectionPosition.QuadPart = dlibCollectionPosition.QuadPart;
228 This->pStm = stream;
230 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL);
231 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
233 if (chunk.fccID != FOURCC_RIFF) {
234 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
235 liMove.QuadPart = chunk.dwSize;
236 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
237 return E_FAIL;
240 IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL);
241 TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(chunk.fccID));
242 StreamSize = chunk.dwSize - sizeof(FOURCC);
243 StreamCount = 0;
245 if (chunk.fccID != FOURCC_DLS) {
246 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
247 liMove.QuadPart = StreamSize;
248 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
249 return E_FAIL;
252 TRACE_(dmfile)(": collection form\n");
253 do {
254 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL);
255 StreamCount += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
256 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
257 switch (chunk.fccID) {
258 case FOURCC_COLH: {
259 TRACE_(dmfile)(": collection header chunk\n");
260 This->pHeader = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, chunk.dwSize);
261 IStream_Read(stream, This->pHeader, chunk.dwSize, NULL);
262 break;
264 case FOURCC_DLID: {
265 TRACE_(dmfile)(": DLID (GUID) chunk\n");
266 This->dmobj.desc.dwValidData |= DMUS_OBJ_OBJECT;
267 IStream_Read(stream, &This->dmobj.desc.guidObject, chunk.dwSize, NULL);
268 break;
270 case FOURCC_VERS: {
271 TRACE_(dmfile)(": version chunk\n");
272 This->dmobj.desc.dwValidData |= DMUS_OBJ_VERSION;
273 IStream_Read(stream, &This->dmobj.desc.vVersion, chunk.dwSize, NULL);
274 break;
276 case FOURCC_PTBL: {
277 TRACE_(dmfile)(": pool table chunk\n");
278 This->pPoolTable = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(POOLTABLE));
279 IStream_Read(stream, This->pPoolTable, sizeof(POOLTABLE), NULL);
280 chunk.dwSize -= sizeof(POOLTABLE);
281 This->pPoolCues = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pPoolTable->cCues * sizeof(POOLCUE));
282 IStream_Read(stream, This->pPoolCues, chunk.dwSize, NULL);
283 break;
285 case FOURCC_LIST: {
286 IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL);
287 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID));
288 ListSize[0] = chunk.dwSize - sizeof(FOURCC);
289 ListCount[0] = 0;
290 switch (chunk.fccID) {
291 case DMUS_FOURCC_INFO_LIST: {
292 TRACE_(dmfile)(": INFO list\n");
293 do {
294 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL);
295 ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
296 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
297 switch (chunk.fccID) {
298 case mmioFOURCC('I','N','A','M'): {
299 CHAR szName[DMUS_MAX_NAME];
300 TRACE_(dmfile)(": name chunk\n");
301 This->dmobj.desc.dwValidData |= DMUS_OBJ_NAME;
302 IStream_Read(stream, szName, chunk.dwSize, NULL);
303 MultiByteToWideChar(CP_ACP, 0, szName, -1, This->dmobj.desc.wszName, DMUS_MAX_NAME);
304 if (even_or_odd(chunk.dwSize)) {
305 ListCount[0]++;
306 liMove.QuadPart = 1;
307 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
309 break;
311 case mmioFOURCC('I','A','R','T'): {
312 TRACE_(dmfile)(": artist chunk (ignored)\n");
313 if (even_or_odd(chunk.dwSize)) {
314 ListCount[0]++;
315 chunk.dwSize++;
317 liMove.QuadPart = chunk.dwSize;
318 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
319 break;
321 case mmioFOURCC('I','C','O','P'): {
322 TRACE_(dmfile)(": copyright chunk\n");
323 This->szCopyright = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, chunk.dwSize);
324 IStream_Read(stream, This->szCopyright, chunk.dwSize, NULL);
325 if (even_or_odd(chunk.dwSize)) {
326 ListCount[0]++;
327 liMove.QuadPart = 1;
328 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
330 break;
332 case mmioFOURCC('I','S','B','J'): {
333 TRACE_(dmfile)(": subject chunk (ignored)\n");
334 if (even_or_odd(chunk.dwSize)) {
335 ListCount[0]++;
336 chunk.dwSize++;
338 liMove.QuadPart = chunk.dwSize;
339 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
340 break;
342 case mmioFOURCC('I','C','M','T'): {
343 TRACE_(dmfile)(": comment chunk (ignored)\n");
344 if (even_or_odd(chunk.dwSize)) {
345 ListCount[0]++;
346 chunk.dwSize++;
348 liMove.QuadPart = chunk.dwSize;
349 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
350 break;
352 default: {
353 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
354 if (even_or_odd(chunk.dwSize)) {
355 ListCount[0]++;
356 chunk.dwSize++;
358 liMove.QuadPart = chunk.dwSize;
359 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
360 break;
363 TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
364 } while (ListCount[0] < ListSize[0]);
365 break;
367 case FOURCC_WVPL: {
368 TRACE_(dmfile)(": wave pool list (mark & skip)\n");
369 liMove.QuadPart = 0;
370 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &dlibWavePoolPosition); /* store position */
371 This->liWavePoolTablePosition.QuadPart = dlibWavePoolPosition.QuadPart;
372 liMove.QuadPart = chunk.dwSize - sizeof(FOURCC);
373 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
374 break;
376 case FOURCC_LINS: {
377 TRACE_(dmfile)(": instruments list\n");
378 do {
379 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL);
380 ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
381 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
382 switch (chunk.fccID) {
383 case FOURCC_LIST: {
384 IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL);
385 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID));
386 ListSize[1] = chunk.dwSize - sizeof(FOURCC);
387 ListCount[1] = 0;
388 switch (chunk.fccID) {
389 case FOURCC_INS: {
390 LPDMUS_PRIVATE_INSTRUMENTENTRY new_instrument = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_INSTRUMENTENTRY));
391 TRACE_(dmfile)(": instrument list\n");
392 /* Only way to create this one... even M$ does it discretely */
393 DMUSIC_CreateDirectMusicInstrumentImpl(&IID_IDirectMusicInstrument, (void**)&new_instrument->pInstrument, NULL);
395 IDirectMusicInstrumentImpl *instrument = impl_from_IDirectMusicInstrument(new_instrument->pInstrument);
396 /* Store offset and length, they will be needed when loading the instrument */
397 liMove.QuadPart = 0;
398 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &dlibInstrumentPosition);
399 instrument->liInstrumentPosition.QuadPart = dlibInstrumentPosition.QuadPart;
400 instrument->length = ListSize[1];
401 do {
402 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL);
403 ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
404 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
405 switch (chunk.fccID) {
406 case FOURCC_INSH: {
407 TRACE_(dmfile)(": instrument header chunk\n");
408 IStream_Read(stream, &instrument->header, chunk.dwSize, NULL);
409 break;
411 case FOURCC_DLID: {
412 TRACE_(dmfile)(": DLID (GUID) chunk\n");
413 IStream_Read(stream, &instrument->id, chunk.dwSize, NULL);
414 break;
416 case FOURCC_LIST: {
417 IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL);
418 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID));
419 switch (chunk.fccID) {
420 default: {
421 TRACE_(dmfile)(": unknown (skipping)\n");
422 liMove.QuadPart = chunk.dwSize - sizeof(FOURCC);
423 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
424 break;
427 break;
429 default: {
430 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
431 liMove.QuadPart = chunk.dwSize;
432 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
433 break;
436 TRACE_(dmfile)(": ListCount[1] = %d < ListSize[1] = %d\n", ListCount[1], ListSize[1]);
437 } while (ListCount[1] < ListSize[1]);
438 /* DEBUG: dumps whole instrument object tree: */
439 if (TRACE_ON(dmusic)) {
440 TRACE("*** IDirectMusicInstrument (%p) ***\n", instrument);
441 if (!IsEqualGUID(&instrument->id, &GUID_NULL))
442 TRACE(" - GUID = %s\n", debugstr_dmguid(&instrument->id));
443 TRACE(" - Instrument header:\n");
444 TRACE(" - cRegions: %d\n", instrument->header.cRegions);
445 TRACE(" - Locale:\n");
446 TRACE(" - ulBank: %d\n", instrument->header.Locale.ulBank);
447 TRACE(" - ulInstrument: %d\n", instrument->header.Locale.ulInstrument);
448 TRACE(" => dwPatch: %d\n", MIDILOCALE2Patch(&instrument->header.Locale));
450 list_add_tail(&This->Instruments, &new_instrument->entry);
452 break;
455 break;
457 default: {
458 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
459 liMove.QuadPart = chunk.dwSize;
460 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
461 break;
464 TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
465 } while (ListCount[0] < ListSize[0]);
466 break;
468 default: {
469 TRACE_(dmfile)(": unknown (skipping)\n");
470 liMove.QuadPart = chunk.dwSize - sizeof(FOURCC);
471 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
472 break;
475 break;
477 default: {
478 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
479 liMove.QuadPart = chunk.dwSize;
480 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
481 break;
484 TRACE_(dmfile)(": StreamCount = %d < StreamSize = %d\n", StreamCount, StreamSize);
485 } while (StreamCount < StreamSize);
487 TRACE_(dmfile)(": reading finished\n");
490 /* DEBUG: dumps whole collection object tree: */
491 if (TRACE_ON(dmusic)) {
492 int r = 0;
493 DMUS_PRIVATE_INSTRUMENTENTRY *tmpEntry;
494 struct list *listEntry;
496 TRACE("*** IDirectMusicCollection (%p) ***\n", &This->IDirectMusicCollection_iface);
497 dump_DMUS_OBJECTDESC(&This->dmobj.desc);
499 TRACE(" - Collection header:\n");
500 TRACE(" - cInstruments: %d\n", This->pHeader->cInstruments);
501 TRACE(" - Instruments:\n");
503 LIST_FOR_EACH(listEntry, &This->Instruments) {
504 tmpEntry = LIST_ENTRY( listEntry, DMUS_PRIVATE_INSTRUMENTENTRY, entry );
505 TRACE(" - Instrument[%i]: %p\n", r, tmpEntry->pInstrument);
506 r++;
510 return S_OK;
513 static const IPersistStreamVtbl persiststream_vtbl = {
514 dmobj_IPersistStream_QueryInterface,
515 dmobj_IPersistStream_AddRef,
516 dmobj_IPersistStream_Release,
517 unimpl_IPersistStream_GetClassID,
518 unimpl_IPersistStream_IsDirty,
519 IPersistStreamImpl_Load,
520 unimpl_IPersistStream_Save,
521 unimpl_IPersistStream_GetSizeMax
525 HRESULT WINAPI DMUSIC_CreateDirectMusicCollectionImpl(LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter)
527 IDirectMusicCollectionImpl* obj;
528 HRESULT hr;
530 *ppobj = NULL;
531 if (pUnkOuter)
532 return CLASS_E_NOAGGREGATION;
534 obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicCollectionImpl));
535 if (!obj)
536 return E_OUTOFMEMORY;
538 obj->IDirectMusicCollection_iface.lpVtbl = &DirectMusicCollection_Collection_Vtbl;
539 obj->ref = 1;
540 dmobject_init(&obj->dmobj, &CLSID_DirectMusicCollection,
541 (IUnknown*)&obj->IDirectMusicCollection_iface);
542 obj->dmobj.IDirectMusicObject_iface.lpVtbl = &dmobject_vtbl;
543 obj->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl;
545 list_init (&obj->Instruments);
547 DMUSIC_LockModule();
548 hr = IDirectMusicCollection_QueryInterface(&obj->IDirectMusicCollection_iface, lpcGUID, ppobj);
549 IDirectMusicCollection_Release(&obj->IDirectMusicCollection_iface);
551 return hr;