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