wined3d: Make the device parameter to wined3d_surface_depth_blt_fbo() const.
[wine] / dlls / dmloader / loader.c
1 /* IDirectMusicLoaderImpl
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 "dmloader_private.h"
21
22 WINE_DEFAULT_DEBUG_CHANNEL(dmloader);
23
24 static HRESULT DMUSIC_InitLoaderSettings (LPDIRECTMUSICLOADER8 iface);
25 static HRESULT DMUSIC_GetLoaderSettings (LPDIRECTMUSICLOADER8 iface, REFGUID pClassID, WCHAR* wszSearchPath, LPBOOL pbCache);
26 static HRESULT DMUSIC_SetLoaderSettings (LPDIRECTMUSICLOADER8 iface, REFGUID pClassID, WCHAR* wszSearchPath, LPBOOL pbCache);
27
28 static HRESULT DMUSIC_CopyDescriptor (LPDMUS_OBJECTDESC pDst, LPDMUS_OBJECTDESC pSrc) {
29         TRACE(": copy\n%s\n", debugstr_DMUS_OBJECTDESC(pSrc));
30         /* copy field by field */
31         if (pSrc->dwValidData & DMUS_OBJ_CLASS) pDst->guidClass = pSrc->guidClass;
32         if (pSrc->dwValidData & DMUS_OBJ_OBJECT) pDst->guidObject = pSrc->guidObject;
33         if (pSrc->dwValidData & DMUS_OBJ_DATE) pDst->ftDate = pSrc->ftDate;
34         if (pSrc->dwValidData & DMUS_OBJ_VERSION) pDst->vVersion = pSrc->vVersion;
35         if (pSrc->dwValidData & DMUS_OBJ_NAME) strcpyW (pDst->wszName, pSrc->wszName);
36         if (pSrc->dwValidData & DMUS_OBJ_CATEGORY) strcpyW (pDst->wszCategory, pSrc->wszCategory);
37         if (pSrc->dwValidData & DMUS_OBJ_FILENAME) strcpyW (pDst->wszFileName, pSrc->wszFileName);
38         if (pSrc->dwValidData & DMUS_OBJ_STREAM) IStream_Clone (pSrc->pStream, &pDst->pStream);
39         if (pSrc->dwValidData & DMUS_OBJ_MEMORY) {
40                 pDst->pbMemData = pSrc->pbMemData;
41                 pDst->llMemLength = pSrc->llMemLength;
42         }
43         /* set flags */
44         pDst->dwValidData |= pSrc->dwValidData;
45         return S_OK;
46 }
47
48
49 static BOOL DMUSIC_IsValidLoadableClass (REFCLSID pClassID) {
50         if (IsEqualCLSID(pClassID, &CLSID_DirectMusicAudioPathConfig) ||
51                 IsEqualCLSID(pClassID, &CLSID_DirectMusicBand) ||
52                 IsEqualCLSID(pClassID, &CLSID_DirectMusicContainer) ||
53                 IsEqualCLSID(pClassID, &CLSID_DirectMusicCollection) ||
54                 IsEqualCLSID(pClassID, &CLSID_DirectMusicChordMap) ||
55                 IsEqualCLSID(pClassID, &CLSID_DirectMusicSegment) ||
56                 IsEqualCLSID(pClassID, &CLSID_DirectMusicScript) ||
57                 IsEqualCLSID(pClassID, &CLSID_DirectMusicSong) ||
58                 IsEqualCLSID(pClassID, &CLSID_DirectMusicStyle) ||
59                 IsEqualCLSID(pClassID, &CLSID_DirectMusicGraph) ||
60                 IsEqualCLSID(pClassID, &CLSID_DirectSoundWave) ||
61                 IsEqualCLSID(pClassID, &GUID_DirectMusicAllTypes))
62                 return TRUE;
63         else
64                 return FALSE;
65 }
66
67 /*****************************************************************************
68  * IDirectMusicLoaderImpl implementation
69  */
70 /* IUnknown/IDirectMusicLoader(8) part: */
71
72 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_QueryInterface (LPDIRECTMUSICLOADER8 iface, REFIID riid, LPVOID *ppobj) {
73         ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
74
75         TRACE("(%p, %s, %p)\n",This, debugstr_dmguid(riid), ppobj);
76         if (IsEqualIID (riid, &IID_IUnknown) || 
77             IsEqualIID (riid, &IID_IDirectMusicLoader) ||
78             IsEqualIID (riid, &IID_IDirectMusicLoader8)) {
79                 IDirectMusicLoader_AddRef (iface);
80                 *ppobj = This;
81                 return S_OK;
82         }
83         
84         WARN(": not found\n");
85         return E_NOINTERFACE;
86 }
87
88 static ULONG WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_AddRef (LPDIRECTMUSICLOADER8 iface) {
89         ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
90         TRACE("(%p): AddRef from %d\n", This, This->dwRef);
91         return InterlockedIncrement (&This->dwRef);
92 }
93
94 static ULONG WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_Release (LPDIRECTMUSICLOADER8 iface) {
95         ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
96         
97         DWORD dwRef = InterlockedDecrement (&This->dwRef);
98         TRACE("(%p): ReleaseRef to %d\n", This, This->dwRef);
99         if (dwRef == 0) {
100             /* firstly, release the cache */
101             IDirectMusicLoader8_ClearCache (iface, &GUID_DirectMusicAllTypes);
102             /* FIXME: release all allocated entries */
103             /* destroy critical section */
104             /*This->CritSect.DebugInfo->Spare[0] = 0;
105               DeleteCriticalSection (&This->CritSect); */
106             HeapFree (GetProcessHeap(), 0, This);
107             unlock_module();
108         }
109
110         return dwRef;
111 }
112
113 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_GetObject (LPDIRECTMUSICLOADER8 iface, LPDMUS_OBJECTDESC pDesc, REFIID riid, LPVOID* ppv) {
114         ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
115         HRESULT result = S_OK;
116         HRESULT ret = S_OK; /* used at the end of function, to determine whether everything went OK */
117         
118         struct list *pEntry;
119         LPWINE_LOADER_ENTRY pObjectEntry = NULL;
120         LPSTREAM pStream;
121         IPersistStream* pPersistStream = NULL;
122
123         LPDIRECTMUSICOBJECT pObject;
124         DMUS_OBJECTDESC GotDesc;
125         BOOL bCache;
126
127         TRACE("(%p, %p, %s, %p): pDesc:\n%s\n", This, pDesc, debugstr_dmguid(riid), ppv, debugstr_DMUS_OBJECTDESC(pDesc));
128         
129         /* sometimes it happens that guidClass is missing... which is a BadThingTM */
130         if (!(pDesc->dwValidData & DMUS_OBJ_CLASS)) {
131           ERR(": guidClass not valid but needed\n");
132           *ppv = NULL;
133           return DMUS_E_LOADER_NOCLASSID;
134         }
135         
136         /* OK, first we iterate thru the list of objects we know about; these are either loaded (GetObject, LoadObjectFromFile)
137            or set via SetObject; */
138         TRACE(": looking if we have object in the cache or if it can be found via alias\n");
139         LIST_FOR_EACH(pEntry, This->pObjects) {
140                 LPWINE_LOADER_ENTRY pExistingEntry = LIST_ENTRY(pEntry, WINE_LOADER_ENTRY, entry);
141                 if ((pDesc->dwValidData & DMUS_OBJ_OBJECT) &&
142                         (pExistingEntry->Desc.dwValidData & DMUS_OBJ_OBJECT) &&
143                         IsEqualGUID (&pDesc->guidObject, &pExistingEntry->Desc.guidObject)) {
144                         TRACE(": found it by object GUID\n");
145                         /* I suppose such stuff can happen only when GUID for object is given (GUID_DefaultGMCollection) */
146                         if (pExistingEntry->bInvalidDefaultDLS) {
147                                 TRACE(": found faulty default DLS collection... enabling M$ compliant behaviour\n");
148                                 return DMUS_E_LOADER_NOFILENAME;        
149                         }
150                         if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) {
151                                 TRACE(": already loaded\n");
152                                 return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv);
153                         } else {
154                                 TRACE(": not loaded yet\n");
155                                 pObjectEntry = pExistingEntry;
156                         }
157                 }
158                 else if ((pDesc->dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) &&
159                                 (pExistingEntry->Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) &&
160                                 !strncmpW (pDesc->wszFileName, pExistingEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) {
161                         TRACE(": found it by fullpath filename\n");
162                         if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) {
163                                 TRACE(": already loaded\n");
164                                 return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv);
165                         } else {
166                                 TRACE(": not loaded yet\n");
167                                 pObjectEntry = pExistingEntry;
168                         }
169                 }
170                 else if ((pDesc->dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) &&
171                                 (pExistingEntry->Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) &&
172                                 !strncmpW (pDesc->wszName, pExistingEntry->Desc.wszName, DMUS_MAX_NAME) &&
173                                 !strncmpW (pDesc->wszCategory, pExistingEntry->Desc.wszCategory, DMUS_MAX_CATEGORY)) {
174                         TRACE(": found it by name and category\n");
175                         if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) {
176                                 TRACE(": already loaded\n");
177                                 return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv);
178                         } else {
179                                 TRACE(": not loaded yet\n");
180                                 pObjectEntry = pExistingEntry;
181                         }
182                 }
183                 else if ((pDesc->dwValidData & DMUS_OBJ_NAME) &&
184                                 (pExistingEntry->Desc.dwValidData & DMUS_OBJ_NAME) &&
185                                 !strncmpW (pDesc->wszName, pExistingEntry->Desc.wszName, DMUS_MAX_NAME)) {
186                         TRACE(": found it by name\n");
187                         if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) {
188                                 TRACE(": already loaded\n");
189                                 return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv);
190                         } else {
191                                 TRACE(": not loaded yet\n");
192                                 pObjectEntry = pExistingEntry;
193                         }
194                 }
195                 else if ((pDesc->dwValidData & DMUS_OBJ_FILENAME) &&
196                                 (pExistingEntry->Desc.dwValidData & DMUS_OBJ_FILENAME) &&
197                                 !strncmpW (pDesc->wszFileName, pExistingEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) {
198                         TRACE(": found it by filename\n");                              
199                         if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) {
200                                 TRACE(": already loaded\n");
201                                 return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv);
202                         } else {
203                                 TRACE(": not loaded yet\n");
204                                 pObjectEntry = pExistingEntry;
205                         }
206                 }
207         }
208         
209         /* basically, if we found alias, we use its descriptor to load...
210            else we use info we were given */
211         if (pObjectEntry) {
212                 TRACE(": found alias entry for requested object... using stored info\n");
213                 /* I think in certain cases it can happen that entry's descriptor lacks info about
214                    where to load from (e.g.: if we loaded from stream and then released object
215                    from cache; then only its CLSID, GUID and perhaps name are left); so just
216                    overwrite whatever info the entry has (since it ought to be 100% correct) */
217                 DMUSIC_CopyDescriptor (pDesc, &pObjectEntry->Desc);
218                 /*pDesc = &pObjectEntry->Desc; */ /* FIXME: is this OK? */
219         } else {
220                 TRACE(": no cache/alias entry found for requested object\n");
221         }
222         
223         if (pDesc->dwValidData & DMUS_OBJ_URL) {
224                 TRACE(": loading from URLs not supported yet\n");
225                 return DMUS_E_LOADER_FORMATNOTSUPPORTED;
226         }
227         else if (pDesc->dwValidData & DMUS_OBJ_FILENAME) {
228                 /* load object from file */
229                 /* generate filename; if it's full path, don't add search 
230                    directory path, otherwise do */
231                 WCHAR wszFileName[MAX_PATH];
232
233                 if (pDesc->dwValidData & DMUS_OBJ_FULLPATH) {
234                         lstrcpyW(wszFileName, pDesc->wszFileName);
235                 } else {
236                         WCHAR *p, wszSearchPath[MAX_PATH];
237                         DMUSIC_GetLoaderSettings (iface, &pDesc->guidClass, wszSearchPath, NULL);
238                         lstrcpyW(wszFileName, wszSearchPath);
239                         p = wszFileName + lstrlenW(wszFileName);
240                         if (p > wszFileName && p[-1] != '\\') *p++ = '\\';
241                         strcpyW(p, pDesc->wszFileName);
242                 }
243                 TRACE(": loading from file (%s)\n", debugstr_w(wszFileName));
244                 /* create stream and associate it with file */                  
245                 result = DMUSIC_CreateDirectMusicLoaderFileStream ((LPVOID*)&pStream);
246                 if (FAILED(result)) {
247                         ERR(": could not create file stream\n");
248                         return result;
249                 }
250                 result = IDirectMusicLoaderFileStream_Attach (pStream, wszFileName, iface);
251                 if (FAILED(result)) {
252                         ERR(": could not attach stream to file\n");
253                         IStream_Release (pStream);
254                         return result;
255                 }
256         }
257         else if (pDesc->dwValidData & DMUS_OBJ_MEMORY) {
258                 /* load object from resource */
259                 TRACE(": loading from resource\n");
260                 /* create stream and associate it with given resource */                        
261                 result = DMUSIC_CreateDirectMusicLoaderResourceStream ((LPVOID*)&pStream);
262                 if (FAILED(result)) {
263                         ERR(": could not create resource stream\n");
264                         return result;
265                 }
266                 result = IDirectMusicLoaderResourceStream_Attach (pStream, pDesc->pbMemData, pDesc->llMemLength, 0, iface);
267                 if (FAILED(result)) {
268                         ERR(": could not attach stream to resource\n");
269                         IStream_Release (pStream);
270                         return result;
271                 }
272         }
273         else if (pDesc->dwValidData & DMUS_OBJ_STREAM) {
274                 /* load object from stream */
275                 TRACE(": loading from stream\n");
276                 /* create universal stream and associate it with given one */                   
277                 result = DMUSIC_CreateDirectMusicLoaderGenericStream ((LPVOID*)&pStream);
278                 if (FAILED(result)) {
279                         ERR(": could not create generic stream\n");
280                         return result;
281                 }
282                 result = IDirectMusicLoaderGenericStream_Attach (pStream, pDesc->pStream, iface);
283                 if (FAILED(result)) {
284                         ERR(": failed to attach stream\n");
285                         IStream_Release (pStream);
286                         return result;
287                 }
288         } else {
289                 /* nowhere to load from */
290                 FIXME(": unknown/unsupported way of loading\n");
291                 return DMUS_E_LOADER_NOFILENAME; /* test shows this is returned */
292         }
293
294         /* create object */
295         result = CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject);
296         if (FAILED(result)) {
297                 ERR(": could not create object\n");
298                 return result;
299         }
300         /* acquire PersistStream interface */
301         result = IDirectMusicObject_QueryInterface (pObject, &IID_IPersistStream, (LPVOID*)&pPersistStream);
302         if (FAILED(result)) {
303                 ERR("failed to Query\n");
304                 return result;
305         }
306         /* load */
307         result = IPersistStream_Load (pPersistStream, pStream);
308         if (result != S_OK) {
309                 WARN(": failed to (completely) load object (%s)\n", debugstr_dmreturn(result));
310                 ret = DMUS_S_PARTIALLOAD /*result*/;
311         }
312         /* get descriptor */
313         DM_STRUCT_INIT(&GotDesc);
314         result = IDirectMusicObject_GetDescriptor (pObject, &GotDesc);
315         /* set filename (if we loaded via filename) */
316         if (pDesc->dwValidData & DMUS_OBJ_FILENAME) {
317                 GotDesc.dwValidData |= (pDesc->dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH));
318                 strcpyW (GotDesc.wszFileName, pDesc->wszFileName);
319         }
320         if (FAILED(result)) {
321                 ERR(": failed to get descriptor\n");
322                 return result;
323         }
324         /* release all loading related stuff */
325         IStream_Release (pStream);
326         IPersistStream_Release (pPersistStream);        
327                 
328         /* add object to cache/overwrite existing info (if cache is enabled) */
329         DMUSIC_GetLoaderSettings (iface, &pDesc->guidClass, NULL, &bCache);
330         if (bCache) {
331                 if (!pObjectEntry) {
332                         pObjectEntry = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(WINE_LOADER_ENTRY));
333                         DM_STRUCT_INIT(&pObjectEntry->Desc);
334                         DMUSIC_CopyDescriptor (&pObjectEntry->Desc, &GotDesc);
335                         pObjectEntry->pObject = pObject;
336                         pObjectEntry->bInvalidDefaultDLS = FALSE;
337                         list_add_head (This->pObjects, &pObjectEntry->entry);
338                 } else {
339                         DMUSIC_CopyDescriptor (&pObjectEntry->Desc, &GotDesc);
340                         pObjectEntry->pObject = pObject;
341                         pObjectEntry->bInvalidDefaultDLS = FALSE;
342                 }
343                 TRACE(": filled in cache entry\n");
344         } else TRACE(": caching disabled\n");
345
346 #if 0
347         /* for debug purposes (e.g. to check if all files are cached) */
348         TRACE("*** Loader's cache ***\n");
349         int i = 0;
350         LIST_FOR_EACH (pEntry, This->pObjects) {
351                 i++;
352                 pObjectEntry = LIST_ENTRY(pEntry, WINE_LOADER_ENTRY, entry);
353                 TRACE(": entry nr. %i:\n%s\n  - bInvalidDefaultDLS = %i\n  - pObject = %p\n", i, debugstr_DMUS_OBJECTDESC(&pObjectEntry->Desc), pObjectEntry->bInvalidDefaultDLS, pObjectEntry->pObject);
354         }
355 #endif
356         
357         result = IDirectMusicObject_QueryInterface (pObject, riid, ppv);
358         if (!bCache) IDirectMusicObject_Release (pObject); /* since loader's reference is not needed */
359         /* if there was trouble with loading, and if no other error occurred,
360            we should return DMUS_S_PARTIALLOAD; else, error is returned */
361         if (result == S_OK)
362                 return ret;
363         else
364                 return result;
365 }
366
367 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_SetObject (LPDIRECTMUSICLOADER8 iface, LPDMUS_OBJECTDESC pDesc) {
368         ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
369         LPSTREAM pStream;
370         LPDIRECTMUSICOBJECT pObject;
371         DMUS_OBJECTDESC Desc;
372         struct list *pEntry;
373         LPWINE_LOADER_ENTRY pObjectEntry, pNewEntry;
374         HRESULT hr;
375
376         TRACE("(%p, %p): pDesc:\n%s\n", This, pDesc, debugstr_DMUS_OBJECTDESC(pDesc));
377
378         /* create stream and load additional info from it */
379         if (pDesc->dwValidData & DMUS_OBJ_FILENAME) {
380                 /* generate filename; if it's full path, don't add search 
381                    directory path, otherwise do */
382                 WCHAR wszFileName[MAX_PATH];
383
384                 if (pDesc->dwValidData & DMUS_OBJ_FULLPATH) {
385                         lstrcpyW(wszFileName, pDesc->wszFileName);
386                 } else {
387                         WCHAR *p;
388                         WCHAR wszSearchPath[MAX_PATH];
389                         DMUSIC_GetLoaderSettings (iface, &pDesc->guidClass, wszSearchPath, NULL);
390                         lstrcpyW(wszFileName, wszSearchPath);
391                         p = wszFileName + lstrlenW(wszFileName);
392                         if (p > wszFileName && p[-1] != '\\') *p++ = '\\';
393                         strcpyW(p, pDesc->wszFileName);
394                 }
395                 /* create stream */
396                 hr = DMUSIC_CreateDirectMusicLoaderFileStream ((LPVOID*)&pStream);
397                 if (FAILED(hr)) {
398                         ERR(": could not create file stream\n");
399                         return DMUS_E_LOADER_FAILEDOPEN;
400                 }
401                 /* attach stream */
402                 hr = IDirectMusicLoaderFileStream_Attach (pStream, wszFileName, iface);
403                 if (FAILED(hr)) {
404                         ERR(": could not attach stream to file\n");
405                         IStream_Release (pStream);
406                         return DMUS_E_LOADER_FAILEDOPEN;
407                 }
408         }
409         else if (pDesc->dwValidData & DMUS_OBJ_STREAM) {        
410                 /* create stream */
411                 hr = DMUSIC_CreateDirectMusicLoaderGenericStream ((LPVOID*)&pStream);
412                 if (FAILED(hr)) {
413                         ERR(": could not create generic stream\n");
414                         return DMUS_E_LOADER_FAILEDOPEN;
415                 }
416                 /* attach stream */
417                 hr = IDirectMusicLoaderGenericStream_Attach (pStream, pDesc->pStream, iface);
418                 if (FAILED(hr)) {
419                         ERR(": could not attach stream\n");
420                         IStream_Release (pStream);
421                         return DMUS_E_LOADER_FAILEDOPEN;
422                 }
423         }
424         else if (pDesc->dwValidData & DMUS_OBJ_MEMORY) {
425                 /* create stream */
426                 hr = DMUSIC_CreateDirectMusicLoaderResourceStream ((LPVOID*)&pStream);
427                 if (FAILED(hr)) {
428                         ERR(": could not create resource stream\n");
429                         return DMUS_E_LOADER_FAILEDOPEN;
430                 }
431                 /* attach stream */
432                 hr = IDirectMusicLoaderResourceStream_Attach (pStream, pDesc->pbMemData, pDesc->llMemLength, 0, iface);
433                 if (FAILED(hr)) {
434                         ERR(": could not attach stream to resource\n");
435                         IStream_Release (pStream);
436                         return DMUS_E_LOADER_FAILEDOPEN;
437                 }
438         }
439         else {
440                 ERR(": no way to get additional info\n");
441                 return DMUS_E_LOADER_FAILEDOPEN;
442         }
443
444         /* create object */
445         CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject);
446
447         /* *sigh*... some ms objects have lousy implementation of ParseDescriptor that clears input descriptor :( */
448 #ifdef NOW_WE_ARE_FREE
449         /* parse descriptor: we actually use input descriptor; fields that aren't available from stream remain,
450            otherwise real info is set */
451          IDirectMusicObject_ParseDescriptor (pObject, pStream, pDesc);
452 #endif
453         /* hmph... due to some trouble I had with certain tests, we store current position and then set it back */
454         DM_STRUCT_INIT(&Desc);
455         if (FAILED(IDirectMusicObject_ParseDescriptor (pObject, pStream, &Desc))) {
456                 ERR(": couldn't parse descriptor\n");
457                 return DMUS_E_LOADER_FORMATNOTSUPPORTED;
458         }
459
460         /* copy elements from parsed descriptor into input descriptor; this sets new info, overwriting if necessary,
461            but leaves info that's provided by input and not available from stream */    
462         DMUSIC_CopyDescriptor (pDesc, &Desc);
463         
464         /* release everything */
465         IDirectMusicObject_Release (pObject);
466         IStream_Release (pStream);      
467         
468         /* sometimes it happens that twisted programs call SetObject for same object twice...
469            in such cases, native loader returns S_OK and does nothing... a sound plan */
470         LIST_FOR_EACH (pEntry, This->pObjects) {
471                 pObjectEntry = LIST_ENTRY (pEntry, WINE_LOADER_ENTRY, entry);
472                 if (!memcmp (&pObjectEntry->Desc, pDesc, sizeof(DMUS_OBJECTDESC))) {
473                         TRACE(": exactly same entry already exists\n");
474                         return S_OK;
475                 }
476         }               
477         
478         /* add new entry */
479         TRACE(": adding alias entry with following info:\n%s\n", debugstr_DMUS_OBJECTDESC(pDesc));
480         pNewEntry = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(WINE_LOADER_ENTRY));
481         /* use this function instead of pure memcpy due to streams (memcpy just copies pointer), 
482            which is basically used further by app that called SetDescriptor... better safety than exception */
483         DMUSIC_CopyDescriptor (&pNewEntry->Desc, pDesc);
484         list_add_head (This->pObjects, &pNewEntry->entry);
485
486         return S_OK;
487 }
488
489 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_SetSearchDirectory (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, WCHAR* pwzPath, BOOL fClear) {
490         WCHAR wszCurrentPath[MAX_PATH];
491         ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
492         TRACE("(%p, %s, %s, %d)\n", This, debugstr_dmguid(rguidClass), debugstr_w(pwzPath), fClear);
493         FIXME(": fClear ignored\n");
494         DMUSIC_GetLoaderSettings (iface, rguidClass, wszCurrentPath, NULL);
495         if (!strncmpW(wszCurrentPath, pwzPath, MAX_PATH)) {
496           return S_FALSE;
497         }
498         /* FIXME: check if path is valid; else return DMUS_E_LOADER_BADPATH */
499         return DMUSIC_SetLoaderSettings (iface, rguidClass, pwzPath, NULL);
500 }
501
502 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ScanDirectory (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, WCHAR* pwzFileExtension, WCHAR* pwzScanFileName) {
503         static const WCHAR wszAny[] = {'*',0};
504         WIN32_FIND_DATAW FileData;
505         HANDLE hSearch;
506         WCHAR wszSearchString[MAX_PATH];
507         WCHAR *p;
508         HRESULT result;
509         ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
510         TRACE("(%p, %s, %p, %p)\n", This, debugstr_dmguid(rguidClass), pwzFileExtension, pwzScanFileName);
511         if (IsEqualGUID (rguidClass, &GUID_DirectMusicAllTypes) || !DMUSIC_IsValidLoadableClass(rguidClass)) {
512                 ERR(": rguidClass invalid CLSID\n");
513                 return REGDB_E_CLASSNOTREG;
514         }
515         
516         /* get search path for given class */
517         DMUSIC_GetLoaderSettings (iface, rguidClass, wszSearchString, NULL);
518         
519         p = wszSearchString + lstrlenW(wszSearchString);
520         if (p > wszSearchString && p[-1] != '\\') *p++ = '\\';
521         *p++ = '*'; /* any file */
522         if (strcmpW (pwzFileExtension, wszAny)) *p++ = '.'; /* if we have actual extension, put a dot */
523         strcpyW (p, pwzFileExtension);
524         
525         TRACE(": search string: %s\n", debugstr_w(wszSearchString));
526         
527         hSearch = FindFirstFileW (wszSearchString, &FileData);
528         if (hSearch == INVALID_HANDLE_VALUE) {
529                 TRACE(": no files found\n");
530                 return S_FALSE;
531         }
532         
533         do {
534                 DMUS_OBJECTDESC Desc;
535                 DM_STRUCT_INIT(&Desc);
536                 Desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_DATE;
537                 Desc.guidClass = *rguidClass;
538                 strcpyW (Desc.wszFileName, FileData.cFileName);
539                 FileTimeToLocalFileTime (&FileData.ftCreationTime, &Desc.ftDate);
540                 IDirectMusicLoader8_SetObject (iface, &Desc);
541                 
542                 if (!FindNextFileW (hSearch, &FileData)) {
543                         if (GetLastError () == ERROR_NO_MORE_FILES) {
544                                 TRACE(": search completed\n");
545                                 result = S_OK;
546                         } else {
547                                 ERR(": could not get next file\n");
548                                 result = E_FAIL;
549                         }
550                         FindClose (hSearch);
551                         return result;
552                 }
553         } while (1);
554 }
555
556 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_CacheObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject) {
557         DMUS_OBJECTDESC Desc;
558         HRESULT result = DMUS_E_LOADER_OBJECTNOTFOUND;
559         struct list *pEntry;
560         LPWINE_LOADER_ENTRY  pObjectEntry = NULL;
561
562         ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
563         TRACE("(%p, %p)\n", This, pObject);
564         
565         /* get descriptor */
566         DM_STRUCT_INIT(&Desc);
567         IDirectMusicObject_GetDescriptor (pObject, &Desc);
568         
569         /* now iterate thru list and check if we have alias (without object), corresponding
570            to descriptor of input object */
571         LIST_FOR_EACH(pEntry, This->pObjects) {
572                 pObjectEntry = LIST_ENTRY(pEntry, WINE_LOADER_ENTRY, entry);
573                 if ((Desc.dwValidData & DMUS_OBJ_OBJECT) &&
574                         (pObjectEntry->Desc.dwValidData & DMUS_OBJ_OBJECT) &&
575                         IsEqualGUID (&Desc.guidObject, &pObjectEntry->Desc.guidObject)) {
576                         TRACE(": found it by object GUID\n");
577                         if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject)
578                                 result = S_FALSE;
579                         else
580                                 result = S_OK;
581                         break;
582                 }
583                 else if ((Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) &&
584                                 (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) &&
585                                 !strncmpW (Desc.wszFileName, pObjectEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) {
586                         TRACE(": found it by fullpath filename\n");
587                         if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject)
588                                 result = S_FALSE;
589                         else
590                                 result = S_OK;
591                         break;
592                 }
593                 else if ((Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) &&
594                                 (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) &&
595                                 !strncmpW (Desc.wszName, pObjectEntry->Desc.wszName, DMUS_MAX_NAME) &&
596                                 !strncmpW (Desc.wszCategory, pObjectEntry->Desc.wszCategory, DMUS_MAX_CATEGORY)) {
597                         TRACE(": found it by name and category\n");
598                         if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject)
599                                 result = S_FALSE;
600                         else
601                                 result = S_OK;
602                         break;
603                 }
604                 else if ((Desc.dwValidData & DMUS_OBJ_NAME) &&
605                                 (pObjectEntry->Desc.dwValidData & DMUS_OBJ_NAME) &&
606                                 !strncmpW (Desc.wszName, pObjectEntry->Desc.wszName, DMUS_MAX_NAME)) {
607                         TRACE(": found it by name\n");
608                         if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject)
609                                 result = S_FALSE;
610                         else
611                                 result = S_OK;
612                         break;
613                 }
614                 else if ((Desc.dwValidData & DMUS_OBJ_FILENAME) &&
615                                 (pObjectEntry->Desc.dwValidData & DMUS_OBJ_FILENAME) &&
616                                 !strncmpW (Desc.wszFileName, pObjectEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) {
617                         TRACE(": found it by filename\n");                              
618                         if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject)
619                                 result = S_FALSE;
620                         else
621                                 result = S_OK;
622                         break;
623                 }
624         }
625         
626         /* if we found such alias, then set everything */
627         if (result == S_OK) {
628                 pObjectEntry->Desc.dwValidData &= DMUS_OBJ_LOADED;
629                 pObjectEntry->pObject = pObject;
630                 IDirectMusicObject_AddRef (pObjectEntry->pObject);
631         }
632         
633         return result;
634 }
635
636 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ReleaseObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject) {
637         DMUS_OBJECTDESC Desc;
638         struct list *pEntry;
639         LPWINE_LOADER_ENTRY pObjectEntry = NULL;
640         HRESULT result = S_FALSE;
641
642         ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
643         TRACE("(%p, %p)\n", This, pObject);
644         
645         if(!pObject) return E_POINTER;
646
647         /* get descriptor */
648         DM_STRUCT_INIT(&Desc);
649         IDirectMusicObject_GetDescriptor (pObject, &Desc);
650         
651         /* iterate thru the list of objects we know about; check only those with DMUS_OBJ_LOADED */
652         TRACE(": looking for the object in cache\n");
653         LIST_FOR_EACH(pEntry, This->pObjects) {
654                 pObjectEntry = LIST_ENTRY(pEntry, WINE_LOADER_ENTRY, entry);
655                 if ((Desc.dwValidData & DMUS_OBJ_OBJECT) &&
656                         (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_OBJECT | DMUS_OBJ_LOADED)) &&
657                         IsEqualGUID (&Desc.guidObject, &pObjectEntry->Desc.guidObject)) {
658                         TRACE(": found it by object GUID\n%s\n", debugstr_DMUS_OBJECTDESC(&pObjectEntry->Desc));
659                         result = S_OK;
660                         break;
661                 }
662                 else if ((Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) &&
663                                 (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_LOADED)) &&
664                                 !strncmpW (Desc.wszFileName, pObjectEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) {
665                         TRACE(": found it by fullpath filename\n");
666                         result = S_OK;                  
667                         break;
668                 }
669                 else if ((Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) &&
670                                 (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY | DMUS_OBJ_LOADED)) &&
671                                 !strncmpW (Desc.wszName, pObjectEntry->Desc.wszName, DMUS_MAX_NAME) &&
672                                 !strncmpW (Desc.wszCategory, pObjectEntry->Desc.wszCategory, DMUS_MAX_CATEGORY)) {
673                         TRACE(": found it by name and category\n");
674                         result = S_OK;                  
675                         break;
676                 }
677                 else if ((Desc.dwValidData & DMUS_OBJ_NAME) &&
678                                 (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_LOADED)) &&
679                                 !strncmpW (Desc.wszName, pObjectEntry->Desc.wszName, DMUS_MAX_NAME)) {
680                         TRACE(": found it by name\n");
681                         result = S_OK;
682                         break;
683                 }
684                 else if ((Desc.dwValidData & DMUS_OBJ_FILENAME) &&
685                                 (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_LOADED)) &&
686                                 !strncmpW (Desc.wszFileName, pObjectEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) {
687                         TRACE(": found it by filename\n");
688                         result = S_OK;                  
689                         break;
690                 }
691         }
692         if (result == S_OK) {
693                 /*TRACE(": releasing:\n%s  - bInvalidDefaultDLS = %i\n  - pObject = %p\n", debugstr_DMUS_OBJECTDESC(&pObjectEntry->Desc), pObjectEntry->bInvalidDefaultDLS, pObjectEntry->pObject); */
694                 IDirectMusicObject_Release (pObjectEntry->pObject);
695                 pObjectEntry->pObject = NULL;
696                 pObjectEntry->Desc.dwValidData &= ~DMUS_OBJ_LOADED;
697         } 
698         return result;
699 }
700
701 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ClearCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass) {
702         struct list *pEntry;
703         LPWINE_LOADER_ENTRY pObjectEntry;
704         ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
705         TRACE("(%p, %s)\n", This, debugstr_dmguid(rguidClass));
706         
707         LIST_FOR_EACH (pEntry, This->pObjects) {
708                 pObjectEntry = LIST_ENTRY (pEntry, WINE_LOADER_ENTRY, entry);
709                 
710                 if ((IsEqualGUID (rguidClass, &GUID_DirectMusicAllTypes) || IsEqualGUID (rguidClass, &pObjectEntry->Desc.guidClass)) &&
711                         (pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED)) {
712                         /* basically, wrap to ReleaseObject for each object found */
713                         IDirectMusicLoader8_ReleaseObject (iface, pObjectEntry->pObject);
714                 }
715         }
716         
717         return S_OK;
718 }
719
720 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_EnableCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, BOOL fEnable) {
721         ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
722         BOOL bCurrent;
723         TRACE("(%p, %s, %d)\n", This, debugstr_dmguid(rguidClass), fEnable);
724         DMUSIC_GetLoaderSettings (iface, rguidClass, NULL, &bCurrent);
725         if (bCurrent == fEnable)
726                 return S_FALSE;
727         else
728                 return DMUSIC_SetLoaderSettings (iface, rguidClass, NULL, &fEnable);
729 }
730
731 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_EnumObject (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, DWORD dwIndex, LPDMUS_OBJECTDESC pDesc) {
732         DWORD dwCount = 0;
733         struct list *pEntry;
734         LPWINE_LOADER_ENTRY pObjectEntry;
735         ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
736         TRACE("(%p, %s, %d, %p)\n", This, debugstr_dmguid(rguidClass), dwIndex, pDesc);
737
738         DM_STRUCT_INIT(pDesc);
739
740         LIST_FOR_EACH (pEntry, This->pObjects) {
741                 pObjectEntry = LIST_ENTRY (pEntry, WINE_LOADER_ENTRY, entry);
742
743                 if (IsEqualGUID (rguidClass, &GUID_DirectMusicAllTypes) || IsEqualGUID (rguidClass, &pObjectEntry->Desc.guidClass)) {
744                         if (dwCount == dwIndex) {
745                                 *pDesc = pObjectEntry->Desc;
746                                 /* we aren't supposed to reveal this info */
747                                 pDesc->dwValidData &= ~(DMUS_OBJ_MEMORY | DMUS_OBJ_STREAM);
748                                 pDesc->pbMemData = NULL;
749                                 pDesc->llMemLength = 0;
750                                 pDesc->pStream = NULL;
751                                 return S_OK;
752                         }
753                         dwCount++;
754                 }
755         }
756         
757         TRACE(": not found\n"); 
758         return S_FALSE;
759 }
760
761 static void WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_CollectGarbage (LPDIRECTMUSICLOADER8 iface) {
762         ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
763         FIXME("(%p): stub\n", This);
764 }
765
766 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ReleaseObjectByUnknown (LPDIRECTMUSICLOADER8 iface, IUnknown* pObject) {
767         ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
768         HRESULT result;
769         LPDIRECTMUSICOBJECT pObjectInterface;
770         
771         TRACE("(%p, %p)\n", This, pObject);
772         
773         if (IsBadReadPtr (pObject, sizeof(LPUNKNOWN))) {
774                 ERR(": pObject bad write pointer\n");
775                 return E_POINTER;
776         }
777         /* we simply get IDirectMusicObject interface */
778         result = IUnknown_QueryInterface (pObject, &IID_IDirectMusicObject, (LPVOID*)&pObjectInterface);
779         if (FAILED(result)) return result;
780         /* and release it in old-fashioned way */
781         result = IDirectMusicLoader8_ReleaseObject (iface, pObjectInterface);
782         IDirectMusicObject_Release (pObjectInterface);
783         
784         return result;
785 }
786
787 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_LoadObjectFromFile (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClassID, REFIID iidInterfaceID, WCHAR* pwzFilePath, void** ppObject) {
788         ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
789         DMUS_OBJECTDESC ObjDesc;
790         WCHAR wszLoaderSearchPath[MAX_PATH];
791
792         TRACE("(%p, %s, %s, %s, %p): wrapping to IDirectMusicLoaderImpl_GetObject\n", This, debugstr_dmguid(rguidClassID), debugstr_dmguid(iidInterfaceID), debugstr_w(pwzFilePath), ppObject);
793
794         DM_STRUCT_INIT(&ObjDesc);       
795         ObjDesc.dwValidData = DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_CLASS; /* I believe I've read somewhere in MSDN that this function requires either full path or relative path */
796         ObjDesc.guidClass = *rguidClassID;
797         /* OK, MSDN says that search order is the following:
798             - current directory (DONE)
799             - windows search path (FIXME: how do I get that?)
800             - loader's search path (DONE)
801         */
802         DMUSIC_GetLoaderSettings (iface, rguidClassID, wszLoaderSearchPath, NULL);
803     /* search in current directory */
804         if (!SearchPathW (NULL, pwzFilePath, NULL, sizeof(ObjDesc.wszFileName)/sizeof(WCHAR), ObjDesc.wszFileName, NULL) &&
805         /* search in loader's search path */
806                 !SearchPathW (wszLoaderSearchPath, pwzFilePath, NULL, sizeof(ObjDesc.wszFileName)/sizeof(WCHAR), ObjDesc.wszFileName, NULL)) {
807                 /* cannot find file */
808                 TRACE(": cannot find file\n");
809                 return DMUS_E_LOADER_FAILEDOPEN;
810         }
811         
812         TRACE(": full file path = %s\n", debugstr_w (ObjDesc.wszFileName));
813         
814         return IDirectMusicLoaderImpl_IDirectMusicLoader_GetObject (iface, &ObjDesc, iidInterfaceID, ppObject);
815 }
816
817 static const IDirectMusicLoader8Vtbl DirectMusicLoader_Loader_Vtbl = {
818         IDirectMusicLoaderImpl_IDirectMusicLoader_QueryInterface,
819         IDirectMusicLoaderImpl_IDirectMusicLoader_AddRef,
820         IDirectMusicLoaderImpl_IDirectMusicLoader_Release,
821         IDirectMusicLoaderImpl_IDirectMusicLoader_GetObject,
822         IDirectMusicLoaderImpl_IDirectMusicLoader_SetObject,
823         IDirectMusicLoaderImpl_IDirectMusicLoader_SetSearchDirectory,
824         IDirectMusicLoaderImpl_IDirectMusicLoader_ScanDirectory,
825         IDirectMusicLoaderImpl_IDirectMusicLoader_CacheObject,
826         IDirectMusicLoaderImpl_IDirectMusicLoader_ReleaseObject,
827         IDirectMusicLoaderImpl_IDirectMusicLoader_ClearCache,
828         IDirectMusicLoaderImpl_IDirectMusicLoader_EnableCache,
829         IDirectMusicLoaderImpl_IDirectMusicLoader_EnumObject,
830         IDirectMusicLoaderImpl_IDirectMusicLoader_CollectGarbage,
831         IDirectMusicLoaderImpl_IDirectMusicLoader_ReleaseObjectByUnknown,
832         IDirectMusicLoaderImpl_IDirectMusicLoader_LoadObjectFromFile
833 };
834
835 /* help function for DMUSIC_SetDefaultDLS */
836 static HRESULT DMUSIC_GetDefaultGMPath (WCHAR wszPath[MAX_PATH]) {
837         HKEY hkDM;
838         DWORD returnType, sizeOfReturnBuffer = MAX_PATH;
839         char szPath[MAX_PATH];
840
841         if ((RegOpenKeyExA (HKEY_LOCAL_MACHINE, "Software\\Microsoft\\DirectMusic" , 0, KEY_READ, &hkDM) != ERROR_SUCCESS) ||
842             (RegQueryValueExA (hkDM, "GMFilePath", NULL, &returnType, (LPBYTE) szPath, &sizeOfReturnBuffer) != ERROR_SUCCESS)) {
843                 WARN(": registry entry missing\n" );
844                 return E_FAIL;
845         }
846         /* FIXME: Check return types to ensure we're interpreting data right */
847         MultiByteToWideChar (CP_ACP, 0, szPath, -1, wszPath, MAX_PATH);
848
849         return S_OK;
850 }
851
852 /* for ClassFactory */
853 HRESULT WINAPI DMUSIC_CreateDirectMusicLoaderImpl (LPCGUID lpcGUID, LPVOID *ppobj, LPUNKNOWN pUnkOuter) {
854         IDirectMusicLoaderImpl *obj;
855         DMUS_OBJECTDESC Desc;
856         LPWINE_LOADER_ENTRY pDefaultDLSEntry;
857         struct list *pEntry;
858
859         TRACE("(%s, %p, %p)\n", debugstr_dmguid(lpcGUID), ppobj, pUnkOuter);
860         obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoaderImpl));
861         if (NULL == obj) {
862                 *ppobj = NULL;
863                 return E_OUTOFMEMORY;
864         }
865         obj->LoaderVtbl = &DirectMusicLoader_Loader_Vtbl;
866         obj->dwRef = 0; /* will be inited with QueryInterface */
867         /* init critical section */
868         /* init cache/alias list */
869         /*InitializeCriticalSection (&obj->CritSect);
870         obj->CritSect.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectMusicLoaderImpl.CritSect"); */
871         obj->pObjects = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(struct list));
872         list_init (obj->pObjects);
873         /* init settings */
874         obj->pClassSettings = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(struct list));
875         list_init (obj->pClassSettings);
876         DMUSIC_InitLoaderSettings ((LPDIRECTMUSICLOADER8)obj);
877
878         /* set default DLS collection (via SetObject... so that loading via DMUS_OBJ_OBJECT is possible) */
879         DM_STRUCT_INIT(&Desc);
880         Desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_OBJECT;
881         Desc.guidClass = CLSID_DirectMusicCollection;
882         Desc.guidObject = GUID_DefaultGMCollection;
883         DMUSIC_GetDefaultGMPath (Desc.wszFileName);
884         IDirectMusicLoader_SetObject ((LPDIRECTMUSICLOADER8)obj, &Desc);
885         /* and now the workaroundTM for "invalid" default DLS; basically, 
886            my tests showed that if GUID chunk is present in default DLS 
887            collection, loader treats it as "invalid" and returns 
888            DMUS_E_LOADER_NOFILENAME for all requests for it; basically, we check 
889            if out input guidObject was overwritten */
890         pEntry = list_head (obj->pObjects);
891         pDefaultDLSEntry = LIST_ENTRY (pEntry, WINE_LOADER_ENTRY, entry);
892         if (!IsEqualGUID(&Desc.guidObject, &GUID_DefaultGMCollection)) {
893                 pDefaultDLSEntry->bInvalidDefaultDLS = TRUE;
894         }
895
896         lock_module();
897
898         return IDirectMusicLoaderImpl_IDirectMusicLoader_QueryInterface ((LPDIRECTMUSICLOADER8)obj, lpcGUID, ppobj);
899 }
900
901 /* help function for retrieval of search path and caching option for certain class */
902 static HRESULT DMUSIC_GetLoaderSettings (LPDIRECTMUSICLOADER8 iface, REFGUID pClassID, WCHAR* wszSearchPath, LPBOOL pbCache) {
903         ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
904         struct list *pEntry;
905         TRACE(": (%p, %s, %p, %p)\n", This, debugstr_dmguid(pClassID), wszSearchPath, pbCache);
906         
907         LIST_FOR_EACH(pEntry, This->pClassSettings) {
908                 LPWINE_LOADER_OPTION pOptionEntry = LIST_ENTRY(pEntry, WINE_LOADER_OPTION, entry);
909                 if (IsEqualCLSID (pClassID, &pOptionEntry->guidClass)) {
910                         if (wszSearchPath)
911                                 strcpyW(wszSearchPath, pOptionEntry->wszSearchPath);
912                         if (pbCache)
913                                 *pbCache = pOptionEntry->bCache;
914                         return S_OK;
915                 }
916         }
917         return S_FALSE;
918 }
919
920 /* help function for setting search path and caching option for certain class */
921 static HRESULT DMUSIC_SetLoaderSettings (LPDIRECTMUSICLOADER8 iface, REFGUID pClassID, WCHAR* wszSearchPath, LPBOOL pbCache) {
922         ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
923         struct list *pEntry;
924         HRESULT result = S_FALSE; /* in case pClassID != GUID_DirectMusicAllTypes and not a valid CLSID */
925         TRACE(": (%p, %s, %p, %p)\n", This, debugstr_dmguid(pClassID), wszSearchPath, pbCache);
926         
927         LIST_FOR_EACH(pEntry, This->pClassSettings) {
928                 LPWINE_LOADER_OPTION pOptionEntry = LIST_ENTRY(pEntry, WINE_LOADER_OPTION, entry);
929                 /* well, either we have GUID_DirectMusicAllTypes and need to set it to all,
930                    or specific CLSID is given and we set it only to it */
931                 if (IsEqualGUID (pClassID, &GUID_DirectMusicAllTypes) ||
932                         IsEqualCLSID (pClassID, &pOptionEntry->guidClass)) {
933                         if (wszSearchPath)
934                                 strcpyW(pOptionEntry->wszSearchPath, wszSearchPath);
935                         if (pbCache)
936                                 pOptionEntry->bCache = *pbCache;
937                         result = S_OK;
938                 }
939         }
940
941         return result;
942 }
943
944 static HRESULT DMUSIC_InitLoaderSettings (LPDIRECTMUSICLOADER8 iface) {
945         ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
946         
947         /* hard-coded list of classes */
948         static REFCLSID classes[] = {
949                 &CLSID_DirectMusicAudioPathConfig,
950                 &CLSID_DirectMusicBand,
951                 &CLSID_DirectMusicContainer,
952                 &CLSID_DirectMusicCollection,
953                 &CLSID_DirectMusicChordMap,
954                 &CLSID_DirectMusicSegment,
955                 &CLSID_DirectMusicScript,
956                 &CLSID_DirectMusicSong,
957                 &CLSID_DirectMusicStyle,
958                 &CLSID_DirectMusicGraph,
959                 &CLSID_DirectSoundWave
960         };
961         
962         unsigned int i;
963         WCHAR wszCurrent[MAX_PATH];
964
965         TRACE(": (%p)\n", This);
966         GetCurrentDirectoryW (MAX_PATH, wszCurrent);
967
968         for (i = 0; i < sizeof(classes)/sizeof(REFCLSID); i++) {
969                 LPWINE_LOADER_OPTION pNewSetting = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(WINE_LOADER_OPTION));
970                 pNewSetting->guidClass = *classes[i];
971                 strcpyW (pNewSetting->wszSearchPath, wszCurrent);
972                 pNewSetting->bCache = TRUE;
973                 list_add_tail (This->pClassSettings, &pNewSetting->entry);
974         }
975
976         return S_OK;
977 }