strmbase: do not lock in BaseOutputPinImpl_GetDeliveryBuffer the MemInputPin will...
[wine] / dlls / dmusic / collection.c
1 /* IDirectMusicCollection Implementation
2  *
3  * Copyright (C) 2003-2004 Rok Mandeljc
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19
20 #include "dmusic_private.h"
21
22 WINE_DEFAULT_DEBUG_CHANNEL(dmusic);
23 WINE_DECLARE_DEBUG_CHANNEL(dmfile);
24
25 static ULONG WINAPI IDirectMusicCollectionImpl_IUnknown_AddRef (LPUNKNOWN iface);
26 static ULONG WINAPI IDirectMusicCollectionImpl_IDirectMusicCollection_AddRef (LPDIRECTMUSICCOLLECTION iface);
27 static ULONG WINAPI IDirectMusicCollectionImpl_IDirectMusicObject_AddRef (LPDIRECTMUSICOBJECT iface);
28 static ULONG WINAPI IDirectMusicCollectionImpl_IPersistStream_AddRef (LPPERSISTSTREAM iface);
29
30 /*****************************************************************************
31  * IDirectMusicCollectionImpl implementation
32  */
33 /* IDirectMusicCollectionImpl IUnknown part: */
34 static HRESULT WINAPI IDirectMusicCollectionImpl_IUnknown_QueryInterface (LPUNKNOWN iface, REFIID riid, LPVOID *ppobj) {
35         ICOM_THIS_MULTI(IDirectMusicCollectionImpl, UnknownVtbl, iface);
36         TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj);
37
38         if (IsEqualIID (riid, &IID_IUnknown)) {
39                 *ppobj = &This->UnknownVtbl;
40                 IDirectMusicCollectionImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
41                 return S_OK;    
42         } else if (IsEqualIID (riid, &IID_IDirectMusicCollection)) {
43                 *ppobj = &This->CollectionVtbl;
44                 IDirectMusicCollectionImpl_IDirectMusicCollection_AddRef ((LPDIRECTMUSICCOLLECTION)&This->CollectionVtbl);
45                 return S_OK;
46         } else if (IsEqualIID (riid, &IID_IDirectMusicObject)) {
47                 *ppobj = &This->ObjectVtbl;
48                 IDirectMusicCollectionImpl_IDirectMusicObject_AddRef ((LPDIRECTMUSICOBJECT)&This->ObjectVtbl);          
49                 return S_OK;
50         } else if (IsEqualIID (riid, &IID_IPersistStream)) {
51                 *ppobj = &This->PersistStreamVtbl;
52                 IDirectMusicCollectionImpl_IPersistStream_AddRef ((LPPERSISTSTREAM)&This->PersistStreamVtbl);           
53                 return S_OK;
54         }
55         
56         WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ppobj);
57         return E_NOINTERFACE;
58 }
59
60 static ULONG WINAPI IDirectMusicCollectionImpl_IUnknown_AddRef (LPUNKNOWN iface) {
61         ICOM_THIS_MULTI(IDirectMusicCollectionImpl, UnknownVtbl, iface);
62         ULONG refCount = InterlockedIncrement(&This->ref);
63
64         TRACE("(%p)->(ref before=%u)\n", This, refCount - 1);
65
66         DMUSIC_LockModule();
67
68         return refCount;
69 }
70
71 static ULONG WINAPI IDirectMusicCollectionImpl_IUnknown_Release (LPUNKNOWN iface) {
72         ICOM_THIS_MULTI(IDirectMusicCollectionImpl, UnknownVtbl, iface);
73         ULONG refCount = InterlockedDecrement(&This->ref);
74
75         TRACE("(%p)->(ref before=%u)\n", This, refCount + 1);
76
77         if (!refCount) {
78                 HeapFree(GetProcessHeap(), 0, This);
79         }
80
81         DMUSIC_UnlockModule();
82
83         return refCount;
84 }
85
86 static const IUnknownVtbl DirectMusicCollection_Unknown_Vtbl = {
87         IDirectMusicCollectionImpl_IUnknown_QueryInterface,
88         IDirectMusicCollectionImpl_IUnknown_AddRef,
89         IDirectMusicCollectionImpl_IUnknown_Release
90 };
91
92 /* IDirectMusicCollectionImpl IDirectMusicCollection part: */
93 static HRESULT WINAPI IDirectMusicCollectionImpl_IDirectMusicCollection_QueryInterface (LPDIRECTMUSICCOLLECTION iface, REFIID riid, LPVOID *ppobj) {
94         ICOM_THIS_MULTI(IDirectMusicCollectionImpl, CollectionVtbl, iface);
95         return IDirectMusicCollectionImpl_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj);
96 }
97
98 static ULONG WINAPI IDirectMusicCollectionImpl_IDirectMusicCollection_AddRef (LPDIRECTMUSICCOLLECTION iface) {
99         ICOM_THIS_MULTI(IDirectMusicCollectionImpl, CollectionVtbl, iface);
100         return IDirectMusicCollectionImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
101 }
102
103 static ULONG WINAPI IDirectMusicCollectionImpl_IDirectMusicCollection_Release (LPDIRECTMUSICCOLLECTION iface) {
104         ICOM_THIS_MULTI(IDirectMusicCollectionImpl, CollectionVtbl, iface);
105         return IDirectMusicCollectionImpl_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl);
106 }
107
108 /* IDirectMusicCollection Interface follow: */
109 static HRESULT WINAPI IDirectMusicCollectionImpl_IDirectMusicCollection_GetInstrument (LPDIRECTMUSICCOLLECTION iface, DWORD dwPatch, IDirectMusicInstrument** ppInstrument) {
110         ICOM_THIS_MULTI(IDirectMusicCollectionImpl, CollectionVtbl, iface);
111         DMUS_PRIVATE_INSTRUMENTENTRY *tmpEntry;
112         struct list *listEntry;
113         DWORD dwInstPatch;
114
115         TRACE("(%p, %d, %p)\n", This, dwPatch, ppInstrument);
116         
117         LIST_FOR_EACH (listEntry, &This->Instruments) {
118                 tmpEntry = LIST_ENTRY(listEntry, DMUS_PRIVATE_INSTRUMENTENTRY, entry);
119                 IDirectMusicInstrument_GetPatch (tmpEntry->pInstrument, &dwInstPatch);
120                 if (dwPatch == dwInstPatch) {
121                         *ppInstrument = tmpEntry->pInstrument;
122                         IDirectMusicInstrument_AddRef (tmpEntry->pInstrument);
123                         IDirectMusicInstrumentImpl_Custom_Load (tmpEntry->pInstrument, This->pStm); /* load instrument before returning it */
124                         TRACE(": returning instrument %p\n", *ppInstrument);
125                         return S_OK;
126                 }
127                         
128         }
129         TRACE(": instrument not found\n");
130         
131         return DMUS_E_INVALIDPATCH;
132 }
133
134 static HRESULT WINAPI IDirectMusicCollectionImpl_IDirectMusicCollection_EnumInstrument (LPDIRECTMUSICCOLLECTION iface, DWORD dwIndex, DWORD* pdwPatch, LPWSTR pwszName, DWORD dwNameLen) {
135         ICOM_THIS_MULTI(IDirectMusicCollectionImpl, CollectionVtbl, iface);
136         unsigned int r = 0;
137         DMUS_PRIVATE_INSTRUMENTENTRY *tmpEntry;
138         struct list *listEntry;
139        DWORD dwLen;
140                 
141         TRACE("(%p, %d, %p, %p, %d)\n", This, dwIndex, pdwPatch, pwszName, dwNameLen);
142         LIST_FOR_EACH (listEntry, &This->Instruments) {
143                 tmpEntry = LIST_ENTRY(listEntry, DMUS_PRIVATE_INSTRUMENTENTRY, entry);
144                 if (r == dwIndex) {
145                         IDirectMusicInstrumentImpl *pInstrument = impl_from_IDirectMusicInstrument(tmpEntry->pInstrument);
146                         IDirectMusicInstrument_GetPatch (tmpEntry->pInstrument, pdwPatch);
147                        if (pwszName) {
148                                dwLen = min(strlenW(pInstrument->wszName),dwNameLen-1);
149                                memcpy (pwszName, pInstrument->wszName, dwLen * sizeof(WCHAR));
150                                pwszName[dwLen] = '\0';
151                        }
152                         return S_OK;
153                 }
154                 r++;            
155         }
156         
157         return S_FALSE;
158 }
159
160 static const IDirectMusicCollectionVtbl DirectMusicCollection_Collection_Vtbl = {
161         IDirectMusicCollectionImpl_IDirectMusicCollection_QueryInterface,
162         IDirectMusicCollectionImpl_IDirectMusicCollection_AddRef,
163         IDirectMusicCollectionImpl_IDirectMusicCollection_Release,
164         IDirectMusicCollectionImpl_IDirectMusicCollection_GetInstrument,
165         IDirectMusicCollectionImpl_IDirectMusicCollection_EnumInstrument
166 };
167
168 /* IDirectMusicCollectionImpl IDirectMusicObject part: */
169 static HRESULT WINAPI IDirectMusicCollectionImpl_IDirectMusicObject_QueryInterface (LPDIRECTMUSICOBJECT iface, REFIID riid, LPVOID *ppobj) {
170         ICOM_THIS_MULTI(IDirectMusicCollectionImpl, ObjectVtbl, iface);
171         return IDirectMusicCollectionImpl_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj);
172 }
173
174 static ULONG WINAPI IDirectMusicCollectionImpl_IDirectMusicObject_AddRef (LPDIRECTMUSICOBJECT iface) {
175         ICOM_THIS_MULTI(IDirectMusicCollectionImpl, ObjectVtbl, iface);
176         return IDirectMusicCollectionImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
177 }
178
179 static ULONG WINAPI IDirectMusicCollectionImpl_IDirectMusicObject_Release (LPDIRECTMUSICOBJECT iface) {
180         ICOM_THIS_MULTI(IDirectMusicCollectionImpl, ObjectVtbl, iface);
181         return IDirectMusicCollectionImpl_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl);
182 }
183
184 static HRESULT WINAPI IDirectMusicCollectionImpl_IDirectMusicObject_GetDescriptor (LPDIRECTMUSICOBJECT iface, LPDMUS_OBJECTDESC pDesc) {
185         ICOM_THIS_MULTI(IDirectMusicCollectionImpl, ObjectVtbl, iface);
186         TRACE("(%p, %p)\n", This, pDesc);
187         /* I think we shouldn't return pointer here since then values can be changed; it'd be a mess */
188         memcpy (pDesc, This->pDesc, This->pDesc->dwSize);
189         return S_OK;
190 }
191
192 static HRESULT WINAPI IDirectMusicCollectionImpl_IDirectMusicObject_SetDescriptor(LPDIRECTMUSICOBJECT iface, LPDMUS_OBJECTDESC pDesc)
193 {
194         ICOM_THIS_MULTI(IDirectMusicCollectionImpl, ObjectVtbl, iface);
195
196         TRACE("(%p, %p)\n", iface, pDesc);
197
198         if (!pDesc)
199                 return E_POINTER;
200
201         if (TRACE_ON(dmusic))
202         {
203                 TRACE("Setting descriptor:\n");
204                 dump_DMUS_OBJECTDESC(pDesc);
205         }
206
207         /* According to MSDN, we should copy only given values, not whole struct */     
208         if (pDesc->dwValidData & DMUS_OBJ_OBJECT)
209                 This->pDesc->guidObject = pDesc->guidObject;
210         if (pDesc->dwValidData & DMUS_OBJ_CLASS)
211                 This->pDesc->guidClass = pDesc->guidClass;
212         if (pDesc->dwValidData & DMUS_OBJ_NAME)
213                lstrcpynW(This->pDesc->wszName, pDesc->wszName, DMUS_MAX_NAME);
214         if (pDesc->dwValidData & DMUS_OBJ_CATEGORY)
215                lstrcpynW(This->pDesc->wszCategory, pDesc->wszCategory, DMUS_MAX_CATEGORY);
216         if (pDesc->dwValidData & DMUS_OBJ_FILENAME)
217                lstrcpynW(This->pDesc->wszFileName, pDesc->wszFileName, DMUS_MAX_FILENAME);
218         if (pDesc->dwValidData & DMUS_OBJ_VERSION)
219                 This->pDesc->vVersion = pDesc->vVersion;
220         if (pDesc->dwValidData & DMUS_OBJ_DATE)
221                 This->pDesc->ftDate = pDesc->ftDate;
222         if (pDesc->dwValidData & DMUS_OBJ_MEMORY) {
223                 This->pDesc->llMemLength = pDesc->llMemLength;
224                 memcpy (This->pDesc->pbMemData, pDesc->pbMemData, pDesc->llMemLength);
225         }
226         if (pDesc->dwValidData & DMUS_OBJ_STREAM) {
227                 /* according to MSDN, we copy the stream */
228                 IStream_Clone (pDesc->pStream, &This->pDesc->pStream);  
229         }
230         
231         /* add new flags */
232         This->pDesc->dwValidData |= pDesc->dwValidData;
233
234         return S_OK;
235 }
236
237 static HRESULT read_from_stream(IStream *stream, void *data, ULONG size)
238 {
239     ULONG read;
240     HRESULT hr;
241
242     hr = IStream_Read(stream, data, size, &read);
243     if (FAILED(hr)) {
244         TRACE("IStream_Read failed: %08x\n", hr);
245         return hr;
246     }
247     if (read < size) {
248         TRACE("Didn't read full chunk: %u < %u\n", read, size);
249         return E_FAIL;
250     }
251
252     return S_OK;
253 }
254
255 static HRESULT WINAPI IDirectMusicCollectionImpl_IDirectMusicObject_ParseDescriptor(LPDIRECTMUSICOBJECT iface, LPSTREAM stream, LPDMUS_OBJECTDESC desc)
256 {
257     ICOM_THIS_MULTI(IDirectMusicCollectionImpl, ObjectVtbl, iface);
258     DMUS_PRIVATE_CHUNK chunk;
259     DWORD StreamSize, StreamCount, ListSize[1], ListCount[1];
260     LARGE_INTEGER liMove; /* used when skipping chunks */
261     HRESULT hr;
262
263     TRACE("(%p)->(%p, %p)\n", This, stream, desc);
264
265     /* FIXME: should this be determined from stream? */
266     desc->dwValidData |= DMUS_OBJ_CLASS;
267     desc->guidClass = CLSID_DirectMusicCollection;
268
269     hr = read_from_stream(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD));
270     if (FAILED(hr))
271         return hr;
272     TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
273
274     if (chunk.fccID != FOURCC_RIFF) {
275         TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
276         liMove.QuadPart = chunk.dwSize;
277         IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
278         return DMUS_E_INVALIDFILE;
279     }
280
281     hr = read_from_stream(stream, &chunk.fccID, sizeof(FOURCC));
282     if (FAILED(hr))
283         return hr;
284     TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(chunk.fccID));
285     StreamSize = chunk.dwSize - sizeof(FOURCC);
286
287     if (chunk.fccID != mmioFOURCC('D','L','S',' ')) {
288         TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
289         liMove.QuadPart = StreamSize;
290         IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
291         return E_FAIL;
292     }
293
294     StreamCount = 0;
295     TRACE_(dmfile)(": collection form\n");
296
297     do {
298         hr = read_from_stream(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD));
299         if (FAILED(hr))
300             return hr;
301         StreamCount += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
302         TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
303         switch (chunk.fccID) {
304             case FOURCC_DLID:
305                 TRACE_(dmfile)(": GUID chunk\n");
306                 desc->dwValidData |= DMUS_OBJ_OBJECT;
307                 hr = read_from_stream(stream, &desc->guidObject, chunk.dwSize);
308                 if (FAILED(hr))
309                     return hr;
310                 break;
311
312             case DMUS_FOURCC_VERSION_CHUNK:
313                 TRACE_(dmfile)(": version chunk\n");
314                 desc->dwValidData |= DMUS_OBJ_VERSION;
315                 hr = read_from_stream(stream, &desc->vVersion, chunk.dwSize);
316                 if (FAILED(hr))
317                     return hr;
318                 break;
319
320             case DMUS_FOURCC_CATEGORY_CHUNK:
321                 TRACE_(dmfile)(": category chunk\n");
322                 desc->dwValidData |= DMUS_OBJ_CATEGORY;
323                 hr = read_from_stream(stream, desc->wszCategory, chunk.dwSize);
324                 if (FAILED(hr))
325                     return hr;
326                 break;
327
328             case FOURCC_LIST:
329                 hr = read_from_stream(stream, &chunk.fccID, sizeof(FOURCC));
330                 if (FAILED(hr))
331                     return hr;
332                 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID));
333                 ListSize[0] = chunk.dwSize - sizeof(FOURCC);
334                 ListCount[0] = 0;
335                 switch (chunk.fccID) {
336                     /* pure INFO list, such can be found in dls collections */
337                     case mmioFOURCC('I','N','F','O'):
338                         TRACE_(dmfile)(": INFO list\n");
339                         do {
340                             hr = read_from_stream(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD));
341                             if (FAILED(hr))
342                                 return hr;
343                             ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
344                             TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
345                             switch (chunk.fccID) {
346                                 case mmioFOURCC('I','N','A','M'): {
347                                     CHAR szName[DMUS_MAX_NAME];
348                                     TRACE_(dmfile)(": name chunk\n");
349                                     desc->dwValidData |= DMUS_OBJ_NAME;
350                                     hr = read_from_stream(stream, szName, chunk.dwSize);
351                                     if (FAILED(hr))
352                                         return hr;
353                                     MultiByteToWideChar (CP_ACP, 0, szName, -1, desc->wszName, DMUS_MAX_NAME);
354                                     if (even_or_odd(chunk.dwSize)) {
355                                         ListCount[0]++;
356                                         liMove.QuadPart = 1;
357                                         IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
358                                     }
359                                     break;
360                                 }
361
362                                 case mmioFOURCC('I','A','R','T'):
363                                     TRACE_(dmfile)(": artist chunk (ignored)\n");
364                                     if (even_or_odd(chunk.dwSize)) {
365                                         ListCount[0]++;
366                                         chunk.dwSize++;
367                                     }
368                                     liMove.QuadPart = chunk.dwSize;
369                                     IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
370                                     break;
371
372                                 case mmioFOURCC('I','C','O','P'):
373                                     TRACE_(dmfile)(": copyright chunk (ignored)\n");
374                                     if (even_or_odd(chunk.dwSize)) {
375                                         ListCount[0]++;
376                                         chunk.dwSize++;
377                                     }
378                                     liMove.QuadPart = chunk.dwSize;
379                                     IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
380                                     break;
381
382                                 case mmioFOURCC('I','S','B','J'):
383                                     TRACE_(dmfile)(": subject chunk (ignored)\n");
384                                     if (even_or_odd(chunk.dwSize)) {
385                                         ListCount[0]++;
386                                         chunk.dwSize++;
387                                     }
388                                     liMove.QuadPart = chunk.dwSize;
389                                     IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
390                                     break;
391
392                                 case mmioFOURCC('I','C','M','T'):
393                                     TRACE_(dmfile)(": comment chunk (ignored)\n");
394                                     if (even_or_odd(chunk.dwSize)) {
395                                         ListCount[0]++;
396                                         chunk.dwSize++;
397                                     liMove.QuadPart = chunk.dwSize;
398                                     IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
399                                     break;
400                                 }
401
402                                 default:
403                                     TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
404                                     if (even_or_odd(chunk.dwSize)) {
405                                         ListCount[0] ++;
406                                         chunk.dwSize++;
407                                     }
408                                     liMove.QuadPart = chunk.dwSize;
409                                     IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
410                                     break;
411                             }
412                             TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
413                          } while (ListCount[0] < ListSize[0]);
414                          break;
415
416                      default:
417                          TRACE_(dmfile)(": unknown (skipping)\n");
418                          liMove.QuadPart = chunk.dwSize - sizeof(FOURCC);
419                          IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
420                          break;
421                  }
422                  break;
423
424             default:
425                 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
426                 liMove.QuadPart = chunk.dwSize;
427                 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
428                 break;
429         }
430         TRACE_(dmfile)(": StreamCount[0] = %d < StreamSize[0] = %d\n", StreamCount, StreamSize);
431     } while (StreamCount < StreamSize);
432
433     TRACE_(dmfile)(": reading finished\n");
434
435     if (TRACE_ON(dmusic)) {
436         TRACE("Returning descriptor:\n");
437         dump_DMUS_OBJECTDESC(desc);
438     }
439
440     return S_OK;
441 }
442
443 static const IDirectMusicObjectVtbl DirectMusicCollection_Object_Vtbl = {
444         IDirectMusicCollectionImpl_IDirectMusicObject_QueryInterface,
445         IDirectMusicCollectionImpl_IDirectMusicObject_AddRef,
446         IDirectMusicCollectionImpl_IDirectMusicObject_Release,
447         IDirectMusicCollectionImpl_IDirectMusicObject_GetDescriptor,
448         IDirectMusicCollectionImpl_IDirectMusicObject_SetDescriptor,
449         IDirectMusicCollectionImpl_IDirectMusicObject_ParseDescriptor
450 };
451
452 /* IDirectMusicCollectionImpl IPersistStream part: */
453 static HRESULT WINAPI IDirectMusicCollectionImpl_IPersistStream_QueryInterface (LPPERSISTSTREAM iface, REFIID riid, LPVOID *ppobj) {
454         ICOM_THIS_MULTI(IDirectMusicCollectionImpl, PersistStreamVtbl, iface);
455         return IDirectMusicCollectionImpl_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj);
456 }
457
458 static ULONG WINAPI IDirectMusicCollectionImpl_IPersistStream_AddRef (LPPERSISTSTREAM iface) {
459         ICOM_THIS_MULTI(IDirectMusicCollectionImpl, PersistStreamVtbl, iface);
460         return IDirectMusicCollectionImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
461 }
462
463 static ULONG WINAPI IDirectMusicCollectionImpl_IPersistStream_Release (LPPERSISTSTREAM iface) {
464         ICOM_THIS_MULTI(IDirectMusicCollectionImpl, PersistStreamVtbl, iface);
465         return IDirectMusicCollectionImpl_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl);
466 }
467
468 static HRESULT WINAPI IDirectMusicCollectionImpl_IPersistStream_GetClassID (LPPERSISTSTREAM iface, CLSID* pClassID) {
469         return E_NOTIMPL;
470 }
471
472 static HRESULT WINAPI IDirectMusicCollectionImpl_IPersistStream_IsDirty (LPPERSISTSTREAM iface) {
473         return E_NOTIMPL;
474 }
475
476 static HRESULT WINAPI IDirectMusicCollectionImpl_IPersistStream_Load (LPPERSISTSTREAM iface, IStream* pStm) {
477         ICOM_THIS_MULTI(IDirectMusicCollectionImpl, PersistStreamVtbl, iface);
478
479         DMUS_PRIVATE_CHUNK Chunk;
480         DWORD StreamSize, StreamCount, ListSize[3], ListCount[3];
481         LARGE_INTEGER liMove; /* used when skipping chunks */
482         ULARGE_INTEGER dlibCollectionPosition, dlibInstrumentPosition, dlibWavePoolPosition;
483         
484         IStream_AddRef (pStm); /* add count for later references */
485         liMove.QuadPart = 0;
486         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, &dlibCollectionPosition); /* store offset, in case it'll be needed later */
487         This->liCollectionPosition.QuadPart = dlibCollectionPosition.QuadPart;
488         This->pStm = pStm;
489         
490         IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
491         TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
492         switch (Chunk.fccID) {  
493                 case FOURCC_RIFF: {
494                         IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);                                
495                         TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(Chunk.fccID));
496                         StreamSize = Chunk.dwSize - sizeof(FOURCC);
497                         StreamCount = 0;
498                         switch (Chunk.fccID) {
499                                 case FOURCC_DLS: {
500                                         TRACE_(dmfile)(": collection form\n");
501                                         do {
502                                                 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
503                                                 StreamCount += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
504                                                 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
505                                                 switch (Chunk.fccID) {
506                                                         case FOURCC_COLH: {
507                                                                 TRACE_(dmfile)(": collection header chunk\n");
508                                                                 This->pHeader = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, Chunk.dwSize);
509                                                                 IStream_Read (pStm, This->pHeader, Chunk.dwSize, NULL);
510                                                                 break;                                                          
511                                                         }
512                                                         case FOURCC_DLID: {
513                                                                 TRACE_(dmfile)(": DLID (GUID) chunk\n");
514                                                                 This->pDesc->dwValidData |= DMUS_OBJ_OBJECT;
515                                                                 IStream_Read (pStm, &This->pDesc->guidObject, Chunk.dwSize, NULL);
516                                                                 break;
517                                                         }
518                                                         case FOURCC_VERS: {
519                                                                 TRACE_(dmfile)(": version chunk\n");
520                                                                 This->pDesc->dwValidData |= DMUS_OBJ_VERSION;
521                                                                 IStream_Read (pStm, &This->pDesc->vVersion, Chunk.dwSize, NULL);
522                                                                 break;
523                                                         }
524                                                         case FOURCC_PTBL: {
525                                                                 TRACE_(dmfile)(": pool table chunk\n");
526                                                                 This->pPoolTable = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(POOLTABLE));
527                                                                 IStream_Read (pStm, This->pPoolTable, sizeof(POOLTABLE), NULL);
528                                                                 Chunk.dwSize -= sizeof(POOLTABLE);
529                                                                 This->pPoolCues = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, This->pPoolTable->cCues*sizeof(POOLCUE));
530                                                                 IStream_Read (pStm, This->pPoolCues, Chunk.dwSize, NULL);
531                                                                 break;
532                                                         }
533                                                         case FOURCC_LIST: {
534                                                                 IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);                                
535                                                                 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
536                                                                 ListSize[0] = Chunk.dwSize - sizeof(FOURCC);
537                                                                 ListCount[0] = 0;
538                                                                 switch (Chunk.fccID) {
539                                                                         case mmioFOURCC('I','N','F','O'): {
540                                                                                 TRACE_(dmfile)(": INFO list\n");
541                                                                                 do {
542                                                                                         IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
543                                                                                         ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
544                                                                                         TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
545                                                                                         switch (Chunk.fccID) {
546                                                                                                 case mmioFOURCC('I','N','A','M'): {
547                                                                                                         CHAR szName[DMUS_MAX_NAME];
548                                                                                                         TRACE_(dmfile)(": name chunk\n");
549                                                                                                         This->pDesc->dwValidData |= DMUS_OBJ_NAME;
550                                                                                                         IStream_Read (pStm, szName, Chunk.dwSize, NULL);
551                                                                                                         MultiByteToWideChar (CP_ACP, 0, szName, -1, This->pDesc->wszName, DMUS_MAX_NAME);
552                                                                                                         if (even_or_odd(Chunk.dwSize)) {
553                                                                                                                 ListCount[0] ++;
554                                                                                                                 liMove.QuadPart = 1;
555                                                                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
556                                                                                                         }
557                                                                                                         break;
558                                                                                                 }
559                                                                                                 case mmioFOURCC('I','A','R','T'): {
560                                                                                                         TRACE_(dmfile)(": artist chunk (ignored)\n");
561                                                                                                         if (even_or_odd(Chunk.dwSize)) {
562                                                                                                                 ListCount[0] ++;
563                                                                                                                 Chunk.dwSize++;
564                                                                                                         }
565                                                                                                         liMove.QuadPart = Chunk.dwSize;
566                                                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
567                                                                                                         break;
568                                                                                                 }
569                                                                                                 case mmioFOURCC('I','C','O','P'): {
570                                                                                                         TRACE_(dmfile)(": copyright chunk\n");
571                                                                                                         This->szCopyright = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, Chunk.dwSize);
572                                                                                                         IStream_Read (pStm, This->szCopyright, Chunk.dwSize, NULL);
573                                                                                                         if (even_or_odd(Chunk.dwSize)) {
574                                                                                                                 ListCount[0] ++;
575                                                                                                                 liMove.QuadPart = 1;
576                                                                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
577                                                                                                         }
578                                                                                                         break;
579                                                                                                 }
580                                                                                                 case mmioFOURCC('I','S','B','J'): {
581                                                                                                         TRACE_(dmfile)(": subject chunk (ignored)\n");
582                                                                                                         if (even_or_odd(Chunk.dwSize)) {
583                                                                                                                 ListCount[0] ++;
584                                                                                                                 Chunk.dwSize++;
585                                                                                                         }
586                                                                                                         liMove.QuadPart = Chunk.dwSize;
587                                                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
588                                                                                                         break;
589                                                                                                 }
590                                                                                                 case mmioFOURCC('I','C','M','T'): {
591                                                                                                         TRACE_(dmfile)(": comment chunk (ignored)\n");
592                                                                                                         if (even_or_odd(Chunk.dwSize)) {
593                                                                                                                 ListCount[0] ++;
594                                                                                                                 Chunk.dwSize++;
595                                                                                                         }
596                                                                                                         liMove.QuadPart = Chunk.dwSize;
597                                                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
598                                                                                                         break;
599                                                                                                 }
600                                                                                                 default: {
601                                                                                                         TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
602                                                                                                         if (even_or_odd(Chunk.dwSize)) {
603                                                                                                                 ListCount[0] ++;
604                                                                                                                 Chunk.dwSize++;
605                                                                                                         }
606                                                                                                         liMove.QuadPart = Chunk.dwSize;
607                                                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
608                                                                                                         break;                                          
609                                                                                                 }
610                                                                                         }
611                                                                                         TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
612                                                                                 } while (ListCount[0] < ListSize[0]);
613                                                                                 break;
614                                                                         }
615                                                                         case FOURCC_WVPL: {
616                                                                                 TRACE_(dmfile)(": wave pool list (mark & skip)\n");
617                                                                                 liMove.QuadPart = 0;
618                                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, &dlibWavePoolPosition); /* store position */
619                                                                                 This->liWavePoolTablePosition.QuadPart = dlibWavePoolPosition.QuadPart;
620                                                                                 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
621                                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
622                                                                                 break;  
623                                                                         }
624                                                                         case FOURCC_LINS: {
625                                                                                 TRACE_(dmfile)(": instruments list\n");
626                                                                                 do {
627                                                                                         IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
628                                                                                         ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
629                                                                                         TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
630                                                                                         switch (Chunk.fccID) {
631                                                                                                 case FOURCC_LIST: {
632                                                                                                         IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);                                
633                                                                                                         TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
634                                                                                                         ListSize[1] = Chunk.dwSize - sizeof(FOURCC);
635                                                                                                         ListCount[1] = 0;                                                                                                       
636                                                                                                         switch (Chunk.fccID) {
637                                                                                                                 case FOURCC_INS: {
638                                                                                                                         LPDMUS_PRIVATE_INSTRUMENTENTRY pNewInstrument = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_INSTRUMENTENTRY));
639                                                                                                                         TRACE_(dmfile)(": instrument list\n");
640                                                                                                                         DMUSIC_CreateDirectMusicInstrumentImpl (&IID_IDirectMusicInstrument, (LPVOID*)&pNewInstrument->pInstrument, NULL); /* only way to create this one... even M$ does it discretely */
641                                                                                                                         {
642                                                                                                                             IDirectMusicInstrumentImpl *pInstrument = impl_from_IDirectMusicInstrument(pNewInstrument->pInstrument);
643                                                                                                                             liMove.QuadPart = 0;
644                                                                                                                             IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, &dlibInstrumentPosition);
645                                                                                                                             pInstrument->liInstrumentPosition.QuadPart = dlibInstrumentPosition.QuadPart - (2*sizeof(FOURCC) + sizeof(DWORD)); /* store offset, it'll be needed later */
646
647                                                                                                                             do {
648                                                                                                                                 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
649                                                                                                                                 ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
650                                                                                                                                 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
651                                                                                                                                 switch (Chunk.fccID) {
652                                                                                                                                         case FOURCC_INSH: {
653                                                                                                                                                 TRACE_(dmfile)(": instrument header chunk\n");
654                                                                                                                                                 pInstrument->pHeader = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, Chunk.dwSize);
655                                                                                                                                                 IStream_Read (pStm, pInstrument->pHeader, Chunk.dwSize, NULL);
656                                                                                                                                                 break;  
657                                                                                                                                         }
658                                                                                                                                         case FOURCC_DLID: {
659                                                                                                                                                 TRACE_(dmfile)(": DLID (GUID) chunk\n");
660                                                                                                                                                 pInstrument->pInstrumentID = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, Chunk.dwSize);
661                                                                                                                                                 IStream_Read (pStm, pInstrument->pInstrumentID, Chunk.dwSize, NULL);
662                                                                                                                                                 break;
663                                                                                                                                         }
664                                                                                                                                         case FOURCC_LIST: {
665                                                                                                                                                 IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);                                
666                                                                                                                                                 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
667                                                                                                                                                 ListSize[2] = Chunk.dwSize - sizeof(FOURCC);
668                                                                                                                                                 ListCount[2] = 0;
669                                                                                                                                                 switch (Chunk.fccID) {
670                                                                                                                                                         default: {
671                                                                                                                                                                 TRACE_(dmfile)(": unknown (skipping)\n");
672                                                                                                                                                                 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
673                                                                                                                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
674                                                                                                                                                                 break;                                          
675                                                                                                                                                         }
676                                                                                                                                                 }
677                                                                                                                                                 break;
678                                                                                                                                         }                               
679                                                                                                                                         default: {
680                                                                                                                                                 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
681                                                                                                                                                 liMove.QuadPart = Chunk.dwSize;
682                                                                                                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
683                                                                                                                                                 break;                                          
684                                                                                                                                         }
685                                                                                                                                 }
686                                                                                                                                 TRACE_(dmfile)(": ListCount[1] = %d < ListSize[1] = %d\n", ListCount[1], ListSize[1]);
687                                                                                                                             } while (ListCount[1] < ListSize[1]);
688                                                                                                                             /* DEBUG: dumps whole instrument object tree: */
689                                                                                                                             if (TRACE_ON(dmusic)) {
690                                                                                                                                 TRACE("*** IDirectMusicInstrument (%p) ***\n", pInstrument);
691                                                                                                                                 if (pInstrument->pInstrumentID)
692                                                                                                                                         TRACE(" - GUID = %s\n", debugstr_dmguid(pInstrument->pInstrumentID));
693                                                                                                                                 
694                                                                                                                                 TRACE(" - Instrument header:\n");
695                                                                                                                                 TRACE("    - cRegions: %d\n", pInstrument->pHeader->cRegions);
696                                                                                                                                 TRACE("    - Locale:\n");
697                                                                                                                                 TRACE("       - ulBank: %d\n", pInstrument->pHeader->Locale.ulBank);
698                                                                                                                                 TRACE("       - ulInstrument: %d\n", pInstrument->pHeader->Locale.ulInstrument);
699                                                                                                                                 TRACE("       => dwPatch: %d\n", MIDILOCALE2Patch(&pInstrument->pHeader->Locale));
700                                                                                                                             }
701                                                                                                                             list_add_tail (&This->Instruments, &pNewInstrument->entry);
702                                                                                                                         }
703                                                                                                                         break;
704                                                                                                                 }
705                                                                                                         }
706                                                                                                         break;
707                                                                                                 }
708                                                                                                 default: {
709                                                                                                         TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
710                                                                                                         liMove.QuadPart = Chunk.dwSize;
711                                                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
712                                                                                                         break;                                          
713                                                                                                 }
714                                                                                         }
715                                                                                         TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
716                                                                                 } while (ListCount[0] < ListSize[0]);
717                                                                                 break;
718                                                                         }
719                                                                         default: {
720                                                                                 TRACE_(dmfile)(": unknown (skipping)\n");
721                                                                                 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
722                                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
723                                                                                 break;                                          
724                                                                         }
725                                                                 }
726                                                                 break;
727                                                         }       
728                                                         default: {
729                                                                 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
730                                                                 liMove.QuadPart = Chunk.dwSize;
731                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
732                                                                 break;                                          
733                                                         }
734                                                 }
735                                                 TRACE_(dmfile)(": StreamCount = %d < StreamSize = %d\n", StreamCount, StreamSize);
736                                         } while (StreamCount < StreamSize);
737                                         break;
738                                 }
739                                 default: {
740                                         TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
741                                         liMove.QuadPart = StreamSize;
742                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
743                                         return E_FAIL;
744                                 }
745                         }
746                         TRACE_(dmfile)(": reading finished\n");
747                         break;
748                 }
749                 default: {
750                         TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
751                         liMove.QuadPart = Chunk.dwSize;
752                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
753                         return E_FAIL;
754                 }
755         }
756
757         /* DEBUG: dumps whole collection object tree: */
758         if (TRACE_ON(dmusic)) {
759                 int r = 0;
760                 DMUS_PRIVATE_INSTRUMENTENTRY *tmpEntry;
761                 struct list *listEntry;
762
763                 TRACE("*** IDirectMusicCollection (%p) ***\n", This->CollectionVtbl);
764                 if (This->pDesc->dwValidData & DMUS_OBJ_OBJECT)
765                         TRACE(" - GUID = %s\n", debugstr_dmguid(&This->pDesc->guidObject));
766                 if (This->pDesc->dwValidData & DMUS_OBJ_VERSION)
767                         TRACE(" - Version = %i,%i,%i,%i\n", (This->pDesc->vVersion.dwVersionMS >> 8) & 0x0000FFFF, This->pDesc->vVersion.dwVersionMS & 0x0000FFFF,
768                                 (This->pDesc->vVersion.dwVersionLS >> 8) & 0x0000FFFF, This->pDesc->vVersion.dwVersionLS & 0x0000FFFF);
769                 if (This->pDesc->dwValidData & DMUS_OBJ_NAME)
770                         TRACE(" - Name = %s\n", debugstr_w(This->pDesc->wszName));
771                 
772                 TRACE(" - Collection header:\n");
773                 TRACE("    - cInstruments: %d\n", This->pHeader->cInstruments);
774                 TRACE(" - Instruments:\n");
775                 
776                 LIST_FOR_EACH (listEntry, &This->Instruments) {
777                         tmpEntry = LIST_ENTRY( listEntry, DMUS_PRIVATE_INSTRUMENTENTRY, entry );
778                         TRACE("    - Instrument[%i]: %p\n", r, tmpEntry->pInstrument);
779                         r++;
780                 }
781         }
782         
783         return S_OK;
784 }
785
786 static HRESULT WINAPI IDirectMusicCollectionImpl_IPersistStream_Save (LPPERSISTSTREAM iface, IStream* pStm, BOOL fClearDirty) {
787         return E_NOTIMPL;
788 }
789
790 static HRESULT WINAPI IDirectMusicCollectionImpl_IPersistStream_GetSizeMax (LPPERSISTSTREAM iface, ULARGE_INTEGER* pcbSize) {
791         return E_NOTIMPL;
792 }
793
794 static const IPersistStreamVtbl DirectMusicCollection_PersistStream_Vtbl = {
795         IDirectMusicCollectionImpl_IPersistStream_QueryInterface,
796         IDirectMusicCollectionImpl_IPersistStream_AddRef,
797         IDirectMusicCollectionImpl_IPersistStream_Release,
798         IDirectMusicCollectionImpl_IPersistStream_GetClassID,
799         IDirectMusicCollectionImpl_IPersistStream_IsDirty,
800         IDirectMusicCollectionImpl_IPersistStream_Load,
801         IDirectMusicCollectionImpl_IPersistStream_Save,
802         IDirectMusicCollectionImpl_IPersistStream_GetSizeMax
803 };
804
805
806 /* for ClassFactory */
807 HRESULT WINAPI DMUSIC_CreateDirectMusicCollectionImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter) {
808         IDirectMusicCollectionImpl* obj;
809         
810         obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicCollectionImpl));
811         if (NULL == obj) {
812                 *ppobj = NULL;
813                 return E_OUTOFMEMORY;
814         }
815         obj->UnknownVtbl = &DirectMusicCollection_Unknown_Vtbl;
816         obj->CollectionVtbl = &DirectMusicCollection_Collection_Vtbl;
817         obj->ObjectVtbl = &DirectMusicCollection_Object_Vtbl;
818         obj->PersistStreamVtbl = &DirectMusicCollection_PersistStream_Vtbl;
819         obj->pDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DMUS_OBJECTDESC));
820         DM_STRUCT_INIT(obj->pDesc);
821         obj->pDesc->dwValidData |= DMUS_OBJ_CLASS;
822         obj->pDesc->guidClass = CLSID_DirectMusicCollection;
823         obj->ref = 0; /* will be inited by QueryInterface */
824         list_init (&obj->Instruments);
825
826         return IDirectMusicCollectionImpl_IUnknown_QueryInterface ((LPUNKNOWN)&obj->UnknownVtbl, lpcGUID, ppobj);
827 }