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