webservices: Add support for union types in the writer.
[wine.git] / dlls / dmloader / loader.c
blob41418b8d3ea3e85bf9b9e827bb5d7ea776e12a9b
1 /*
2 * IDirectMusicLoaderImpl
4 * Copyright (C) 2003-2004 Rok Mandeljc
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "dmloader_private.h"
23 WINE_DEFAULT_DEBUG_CHANNEL(dmloader);
25 static inline IDirectMusicLoaderImpl* impl_from_IDirectMusicLoader8(IDirectMusicLoader8 *iface)
27 return CONTAINING_RECORD(iface, IDirectMusicLoaderImpl, IDirectMusicLoader8_iface);
30 static HRESULT DMUSIC_InitLoaderSettings(IDirectMusicLoader8 *iface);
31 static HRESULT DMUSIC_GetLoaderSettings(IDirectMusicLoader8 *iface, REFGUID class_id, WCHAR *search_path, BOOL *cache);
32 static HRESULT DMUSIC_SetLoaderSettings(IDirectMusicLoader8 *iface, REFGUID class_id, WCHAR *search_path, BOOL *cache);
34 static HRESULT DMUSIC_CopyDescriptor(DMUS_OBJECTDESC *pDst, DMUS_OBJECTDESC *pSrc)
36 if (TRACE_ON(dmloader))
37 dump_DMUS_OBJECTDESC(pSrc);
39 /* copy field by field */
40 if (pSrc->dwValidData & DMUS_OBJ_CLASS) pDst->guidClass = pSrc->guidClass;
41 if (pSrc->dwValidData & DMUS_OBJ_OBJECT) pDst->guidObject = pSrc->guidObject;
42 if (pSrc->dwValidData & DMUS_OBJ_DATE) pDst->ftDate = pSrc->ftDate;
43 if (pSrc->dwValidData & DMUS_OBJ_VERSION) pDst->vVersion = pSrc->vVersion;
44 if (pSrc->dwValidData & DMUS_OBJ_NAME) strcpyW (pDst->wszName, pSrc->wszName);
45 if (pSrc->dwValidData & DMUS_OBJ_CATEGORY) strcpyW (pDst->wszCategory, pSrc->wszCategory);
46 if (pSrc->dwValidData & DMUS_OBJ_FILENAME) strcpyW (pDst->wszFileName, pSrc->wszFileName);
47 if (pSrc->dwValidData & DMUS_OBJ_STREAM) IStream_Clone (pSrc->pStream, &pDst->pStream);
48 if (pSrc->dwValidData & DMUS_OBJ_MEMORY) {
49 pDst->pbMemData = pSrc->pbMemData;
50 pDst->llMemLength = pSrc->llMemLength;
52 /* set flags */
53 pDst->dwValidData |= pSrc->dwValidData;
54 return S_OK;
58 static BOOL DMUSIC_IsValidLoadableClass (REFCLSID pClassID) {
59 if (IsEqualCLSID(pClassID, &CLSID_DirectMusicAudioPathConfig) ||
60 IsEqualCLSID(pClassID, &CLSID_DirectMusicBand) ||
61 IsEqualCLSID(pClassID, &CLSID_DirectMusicContainer) ||
62 IsEqualCLSID(pClassID, &CLSID_DirectMusicCollection) ||
63 IsEqualCLSID(pClassID, &CLSID_DirectMusicChordMap) ||
64 IsEqualCLSID(pClassID, &CLSID_DirectMusicSegment) ||
65 IsEqualCLSID(pClassID, &CLSID_DirectMusicScript) ||
66 IsEqualCLSID(pClassID, &CLSID_DirectMusicSong) ||
67 IsEqualCLSID(pClassID, &CLSID_DirectMusicStyle) ||
68 IsEqualCLSID(pClassID, &CLSID_DirectMusicGraph) ||
69 IsEqualCLSID(pClassID, &CLSID_DirectSoundWave) ||
70 IsEqualCLSID(pClassID, &GUID_DirectMusicAllTypes))
71 return TRUE;
72 else
73 return FALSE;
76 /*****************************************************************************
77 * IDirectMusicLoaderImpl implementation
79 /* IUnknown/IDirectMusicLoader(8) part: */
81 static HRESULT WINAPI IDirectMusicLoaderImpl_QueryInterface(IDirectMusicLoader8 *iface, REFIID riid, void **ppobj)
83 IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface);
85 TRACE("(%p, %s, %p)\n",This, debugstr_dmguid(riid), ppobj);
86 if (IsEqualIID (riid, &IID_IUnknown) ||
87 IsEqualIID (riid, &IID_IDirectMusicLoader) ||
88 IsEqualIID (riid, &IID_IDirectMusicLoader8)) {
89 IDirectMusicLoader_AddRef (iface);
90 *ppobj = This;
91 return S_OK;
94 WARN(": not found\n");
95 return E_NOINTERFACE;
98 static ULONG WINAPI IDirectMusicLoaderImpl_AddRef(IDirectMusicLoader8 *iface)
100 IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface);
101 ULONG ref = InterlockedIncrement(&This->ref);
103 TRACE("(%p)->(): new ref = %u\n", iface, ref);
105 return ref;
108 static ULONG WINAPI IDirectMusicLoaderImpl_Release(IDirectMusicLoader8 *iface)
110 IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface);
111 ULONG ref = InterlockedDecrement(&This->ref);
113 TRACE("(%p)->(): new ref = %u\n", iface, ref);
115 if (!ref) {
116 /* Firstly, release the cache */
117 IDirectMusicLoader8_ClearCache(iface, &GUID_DirectMusicAllTypes);
118 /* FIXME: Release all allocated entries */
119 HeapFree(GetProcessHeap(), 0, This);
120 unlock_module();
123 return ref;
126 static HRESULT WINAPI IDirectMusicLoaderImpl_GetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDESC *pDesc, REFIID riid, void **ppv)
128 IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface);
129 HRESULT result = S_OK;
130 HRESULT ret = S_OK; /* used at the end of function, to determine whether everything went OK */
132 struct list *pEntry;
133 LPWINE_LOADER_ENTRY pObjectEntry = NULL;
134 LPSTREAM pStream;
135 IPersistStream* pPersistStream = NULL;
137 LPDIRECTMUSICOBJECT pObject;
138 DMUS_OBJECTDESC GotDesc;
139 BOOL bCache;
141 TRACE("(%p)->(%p, %s, %p)\n", This, pDesc, debugstr_dmguid(riid), ppv);
143 if (TRACE_ON(dmloader))
144 dump_DMUS_OBJECTDESC(pDesc);
146 /* sometimes it happens that guidClass is missing... which is a BadThingTM */
147 if (!(pDesc->dwValidData & DMUS_OBJ_CLASS)) {
148 ERR(": guidClass not valid but needed\n");
149 *ppv = NULL;
150 return DMUS_E_LOADER_NOCLASSID;
153 /* OK, first we iterate through the list of objects we know about; these are either loaded (GetObject, LoadObjectFromFile)
154 or set via SetObject; */
155 TRACE(": looking if we have object in the cache or if it can be found via alias\n");
156 LIST_FOR_EACH(pEntry, This->pObjects) {
157 LPWINE_LOADER_ENTRY pExistingEntry = LIST_ENTRY(pEntry, WINE_LOADER_ENTRY, entry);
158 if ((pDesc->dwValidData & DMUS_OBJ_OBJECT) &&
159 (pExistingEntry->Desc.dwValidData & DMUS_OBJ_OBJECT) &&
160 IsEqualGUID (&pDesc->guidObject, &pExistingEntry->Desc.guidObject)) {
161 TRACE(": found it by object GUID\n");
162 /* I suppose such stuff can happen only when GUID for object is given (GUID_DefaultGMCollection) */
163 if (pExistingEntry->bInvalidDefaultDLS) {
164 TRACE(": found faulty default DLS collection... enabling M$ compliant behaviour\n");
165 return DMUS_E_LOADER_NOFILENAME;
167 if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) {
168 TRACE(": already loaded\n");
169 return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv);
170 } else {
171 TRACE(": not loaded yet\n");
172 pObjectEntry = pExistingEntry;
175 else if ((pDesc->dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) &&
176 (pExistingEntry->Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) &&
177 !strncmpW (pDesc->wszFileName, pExistingEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) {
178 TRACE(": found it by fullpath filename\n");
179 if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) {
180 TRACE(": already loaded\n");
181 return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv);
182 } else {
183 TRACE(": not loaded yet\n");
184 pObjectEntry = pExistingEntry;
187 else if ((pDesc->dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) &&
188 (pExistingEntry->Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) &&
189 !strncmpW (pDesc->wszName, pExistingEntry->Desc.wszName, DMUS_MAX_NAME) &&
190 !strncmpW (pDesc->wszCategory, pExistingEntry->Desc.wszCategory, DMUS_MAX_CATEGORY)) {
191 TRACE(": found it by name and category\n");
192 if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) {
193 TRACE(": already loaded\n");
194 return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv);
195 } else {
196 TRACE(": not loaded yet\n");
197 pObjectEntry = pExistingEntry;
200 else if ((pDesc->dwValidData & DMUS_OBJ_NAME) &&
201 (pExistingEntry->Desc.dwValidData & DMUS_OBJ_NAME) &&
202 !strncmpW (pDesc->wszName, pExistingEntry->Desc.wszName, DMUS_MAX_NAME)) {
203 TRACE(": found it by name\n");
204 if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) {
205 TRACE(": already loaded\n");
206 return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv);
207 } else {
208 TRACE(": not loaded yet\n");
209 pObjectEntry = pExistingEntry;
212 else if ((pDesc->dwValidData & DMUS_OBJ_FILENAME) &&
213 (pExistingEntry->Desc.dwValidData & DMUS_OBJ_FILENAME) &&
214 !strncmpW (pDesc->wszFileName, pExistingEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) {
215 TRACE(": found it by filename\n");
216 if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) {
217 TRACE(": already loaded\n");
218 return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv);
219 } else {
220 TRACE(": not loaded yet\n");
221 pObjectEntry = pExistingEntry;
226 /* basically, if we found alias, we use its descriptor to load...
227 else we use info we were given */
228 if (pObjectEntry) {
229 TRACE(": found alias entry for requested object... using stored info\n");
230 /* I think in certain cases it can happen that entry's descriptor lacks info about
231 where to load from (e.g.: if we loaded from stream and then released object
232 from cache; then only its CLSID, GUID and perhaps name are left); so just
233 overwrite whatever info the entry has (since it ought to be 100% correct) */
234 DMUSIC_CopyDescriptor (pDesc, &pObjectEntry->Desc);
235 /*pDesc = &pObjectEntry->Desc; */ /* FIXME: is this OK? */
236 } else {
237 TRACE(": no cache/alias entry found for requested object\n");
240 if (pDesc->dwValidData & DMUS_OBJ_URL) {
241 TRACE(": loading from URLs not supported yet\n");
242 return DMUS_E_LOADER_FORMATNOTSUPPORTED;
244 else if (pDesc->dwValidData & DMUS_OBJ_FILENAME) {
245 /* load object from file */
246 /* generate filename; if it's full path, don't add search
247 directory path, otherwise do */
248 WCHAR wszFileName[MAX_PATH];
250 if (pDesc->dwValidData & DMUS_OBJ_FULLPATH) {
251 lstrcpyW(wszFileName, pDesc->wszFileName);
252 } else {
253 WCHAR *p, wszSearchPath[MAX_PATH];
254 DMUSIC_GetLoaderSettings (iface, &pDesc->guidClass, wszSearchPath, NULL);
255 lstrcpyW(wszFileName, wszSearchPath);
256 p = wszFileName + lstrlenW(wszFileName);
257 if (p > wszFileName && p[-1] != '\\') *p++ = '\\';
258 strcpyW(p, pDesc->wszFileName);
260 TRACE(": loading from file (%s)\n", debugstr_w(wszFileName));
261 /* create stream and associate it with file */
262 result = DMUSIC_CreateDirectMusicLoaderFileStream ((LPVOID*)&pStream);
263 if (FAILED(result)) {
264 ERR(": could not create file stream\n");
265 return result;
267 result = IDirectMusicLoaderFileStream_Attach (pStream, wszFileName, iface);
268 if (FAILED(result)) {
269 ERR(": could not attach stream to file\n");
270 IStream_Release (pStream);
271 return result;
274 else if (pDesc->dwValidData & DMUS_OBJ_MEMORY) {
275 /* load object from resource */
276 TRACE(": loading from resource\n");
277 /* create stream and associate it with given resource */
278 result = DMUSIC_CreateDirectMusicLoaderResourceStream ((LPVOID*)&pStream);
279 if (FAILED(result)) {
280 ERR(": could not create resource stream\n");
281 return result;
283 result = IDirectMusicLoaderResourceStream_Attach (pStream, pDesc->pbMemData, pDesc->llMemLength, 0, iface);
284 if (FAILED(result)) {
285 ERR(": could not attach stream to resource\n");
286 IStream_Release (pStream);
287 return result;
290 else if (pDesc->dwValidData & DMUS_OBJ_STREAM) {
291 /* load object from stream */
292 TRACE(": loading from stream\n");
293 /* create universal stream and associate it with given one */
294 result = DMUSIC_CreateDirectMusicLoaderGenericStream ((LPVOID*)&pStream);
295 if (FAILED(result)) {
296 ERR(": could not create generic stream\n");
297 return result;
299 result = IDirectMusicLoaderGenericStream_Attach (pStream, pDesc->pStream, iface);
300 if (FAILED(result)) {
301 ERR(": failed to attach stream\n");
302 IStream_Release (pStream);
303 return result;
305 } else {
306 /* nowhere to load from */
307 FIXME(": unknown/unsupported way of loading\n");
308 return DMUS_E_LOADER_NOFILENAME; /* test shows this is returned */
311 /* create object */
312 result = CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject);
313 if (FAILED(result)) {
314 ERR(": could not create object\n");
315 return result;
317 /* acquire PersistStream interface */
318 result = IDirectMusicObject_QueryInterface (pObject, &IID_IPersistStream, (LPVOID*)&pPersistStream);
319 if (FAILED(result)) {
320 ERR("failed to Query\n");
321 return result;
323 /* load */
324 result = IPersistStream_Load (pPersistStream, pStream);
325 if (result != S_OK) {
326 WARN(": failed to (completely) load object (%s)\n", debugstr_dmreturn(result));
327 return result;
329 /* get descriptor */
330 DM_STRUCT_INIT(&GotDesc);
331 result = IDirectMusicObject_GetDescriptor (pObject, &GotDesc);
332 /* set filename (if we loaded via filename) */
333 if (pDesc->dwValidData & DMUS_OBJ_FILENAME) {
334 GotDesc.dwValidData |= (pDesc->dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH));
335 strcpyW (GotDesc.wszFileName, pDesc->wszFileName);
337 if (FAILED(result)) {
338 ERR(": failed to get descriptor\n");
339 return result;
341 /* release all loading related stuff */
342 IStream_Release (pStream);
343 IPersistStream_Release (pPersistStream);
345 /* add object to cache/overwrite existing info (if cache is enabled) */
346 DMUSIC_GetLoaderSettings (iface, &pDesc->guidClass, NULL, &bCache);
347 if (bCache) {
348 if (!pObjectEntry) {
349 pObjectEntry = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(WINE_LOADER_ENTRY));
350 DM_STRUCT_INIT(&pObjectEntry->Desc);
351 DMUSIC_CopyDescriptor (&pObjectEntry->Desc, &GotDesc);
352 pObjectEntry->pObject = pObject;
353 pObjectEntry->bInvalidDefaultDLS = FALSE;
354 list_add_head (This->pObjects, &pObjectEntry->entry);
355 } else {
356 DMUSIC_CopyDescriptor (&pObjectEntry->Desc, &GotDesc);
357 pObjectEntry->pObject = pObject;
358 pObjectEntry->bInvalidDefaultDLS = FALSE;
360 TRACE(": filled in cache entry\n");
361 } else TRACE(": caching disabled\n");
363 #if 0
364 /* for debug purposes (e.g. to check if all files are cached) */
365 TRACE("*** Loader's cache ***\n");
366 int i = 0;
367 LIST_FOR_EACH (pEntry, This->pObjects) {
368 i++;
369 pObjectEntry = LIST_ENTRY(pEntry, WINE_LOADER_ENTRY, entry);
370 TRACE(": entry nr. %i:\n%s\n - bInvalidDefaultDLS = %i\n - pObject = %p\n", i, debugstr_DMUS_OBJECTDESC(&pObjectEntry->Desc), pObjectEntry->bInvalidDefaultDLS, pObjectEntry->pObject);
372 #endif
374 result = IDirectMusicObject_QueryInterface (pObject, riid, ppv);
375 if (!bCache) IDirectMusicObject_Release (pObject); /* since loader's reference is not needed */
376 /* if there was trouble with loading, and if no other error occurred,
377 we should return DMUS_S_PARTIALLOAD; else, error is returned */
378 if (result == S_OK)
379 return ret;
380 else
381 return result;
384 static HRESULT WINAPI IDirectMusicLoaderImpl_SetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDESC *pDesc)
386 IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface);
387 LPSTREAM pStream;
388 LPDIRECTMUSICOBJECT pObject;
389 DMUS_OBJECTDESC Desc;
390 struct list *pEntry;
391 LPWINE_LOADER_ENTRY pObjectEntry, pNewEntry;
392 HRESULT hr;
394 TRACE("(%p)->(%p)\n", This, pDesc);
396 if (TRACE_ON(dmloader))
397 dump_DMUS_OBJECTDESC(pDesc);
399 /* create stream and load additional info from it */
400 if (pDesc->dwValidData & DMUS_OBJ_FILENAME) {
401 /* generate filename; if it's full path, don't add search
402 directory path, otherwise do */
403 WCHAR wszFileName[MAX_PATH];
405 if (pDesc->dwValidData & DMUS_OBJ_FULLPATH) {
406 lstrcpyW(wszFileName, pDesc->wszFileName);
407 } else {
408 WCHAR *p;
409 WCHAR wszSearchPath[MAX_PATH];
410 DMUSIC_GetLoaderSettings (iface, &pDesc->guidClass, wszSearchPath, NULL);
411 lstrcpyW(wszFileName, wszSearchPath);
412 p = wszFileName + lstrlenW(wszFileName);
413 if (p > wszFileName && p[-1] != '\\') *p++ = '\\';
414 strcpyW(p, pDesc->wszFileName);
416 /* create stream */
417 hr = DMUSIC_CreateDirectMusicLoaderFileStream ((LPVOID*)&pStream);
418 if (FAILED(hr)) {
419 ERR(": could not create file stream\n");
420 return DMUS_E_LOADER_FAILEDOPEN;
422 /* attach stream */
423 hr = IDirectMusicLoaderFileStream_Attach (pStream, wszFileName, iface);
424 if (FAILED(hr)) {
425 ERR(": could not attach stream to file %s, make sure it exists\n", debugstr_w(wszFileName));
426 IStream_Release (pStream);
427 return DMUS_E_LOADER_FAILEDOPEN;
430 else if (pDesc->dwValidData & DMUS_OBJ_STREAM) {
431 /* create stream */
432 hr = DMUSIC_CreateDirectMusicLoaderGenericStream ((LPVOID*)&pStream);
433 if (FAILED(hr)) {
434 ERR(": could not create generic stream\n");
435 return DMUS_E_LOADER_FAILEDOPEN;
437 /* attach stream */
438 hr = IDirectMusicLoaderGenericStream_Attach (pStream, pDesc->pStream, iface);
439 if (FAILED(hr)) {
440 ERR(": could not attach stream\n");
441 IStream_Release (pStream);
442 return DMUS_E_LOADER_FAILEDOPEN;
445 else if (pDesc->dwValidData & DMUS_OBJ_MEMORY) {
446 /* create stream */
447 hr = DMUSIC_CreateDirectMusicLoaderResourceStream ((LPVOID*)&pStream);
448 if (FAILED(hr)) {
449 ERR(": could not create resource stream\n");
450 return DMUS_E_LOADER_FAILEDOPEN;
452 /* attach stream */
453 hr = IDirectMusicLoaderResourceStream_Attach (pStream, pDesc->pbMemData, pDesc->llMemLength, 0, iface);
454 if (FAILED(hr)) {
455 ERR(": could not attach stream to resource\n");
456 IStream_Release (pStream);
457 return DMUS_E_LOADER_FAILEDOPEN;
460 else {
461 ERR(": no way to get additional info\n");
462 return DMUS_E_LOADER_FAILEDOPEN;
465 /* create object */
466 hr = CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject);
467 if (FAILED(hr)) {
468 ERR("Object creation of %s failed 0x%08x\n", debugstr_guid(&pDesc->guidClass),hr);
469 return DMUS_E_LOADER_FAILEDOPEN;
472 /* *sigh*... some ms objects have lousy implementation of ParseDescriptor that clears input descriptor :( */
473 #ifdef NOW_WE_ARE_FREE
474 /* parse descriptor: we actually use input descriptor; fields that aren't available from stream remain,
475 otherwise real info is set */
476 IDirectMusicObject_ParseDescriptor (pObject, pStream, pDesc);
477 #endif
478 /* hmph... due to some trouble I had with certain tests, we store current position and then set it back */
479 DM_STRUCT_INIT(&Desc);
480 if (FAILED(IDirectMusicObject_ParseDescriptor (pObject, pStream, &Desc))) {
481 ERR(": couldn't parse descriptor\n");
482 return DMUS_E_LOADER_FORMATNOTSUPPORTED;
485 /* copy elements from parsed descriptor into input descriptor; this sets new info, overwriting if necessary,
486 but leaves info that's provided by input and not available from stream */
487 DMUSIC_CopyDescriptor (pDesc, &Desc);
489 /* release everything */
490 IDirectMusicObject_Release (pObject);
491 IStream_Release (pStream);
493 /* sometimes it happens that twisted programs call SetObject for same object twice...
494 in such cases, native loader returns S_OK and does nothing... a sound plan */
495 LIST_FOR_EACH (pEntry, This->pObjects) {
496 pObjectEntry = LIST_ENTRY (pEntry, WINE_LOADER_ENTRY, entry);
497 if (!memcmp (&pObjectEntry->Desc, pDesc, sizeof(DMUS_OBJECTDESC))) {
498 TRACE(": exactly same entry already exists\n");
499 return S_OK;
503 /* add new entry */
504 TRACE(": adding alias entry with following info:\n");
505 if (TRACE_ON(dmloader))
506 dump_DMUS_OBJECTDESC(pDesc);
507 pNewEntry = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(WINE_LOADER_ENTRY));
508 /* use this function instead of pure memcpy due to streams (memcpy just copies pointer),
509 which is basically used further by app that called SetDescriptor... better safety than exception */
510 DMUSIC_CopyDescriptor (&pNewEntry->Desc, pDesc);
511 list_add_head (This->pObjects, &pNewEntry->entry);
513 return S_OK;
516 static HRESULT WINAPI IDirectMusicLoaderImpl_SetSearchDirectory(IDirectMusicLoader8 *iface,
517 REFGUID class, WCHAR *path, BOOL clear)
519 IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface);
520 WCHAR current_path[MAX_PATH];
521 DWORD attr;
523 TRACE("(%p, %s, %s, %d)\n", This, debugstr_dmguid(class), debugstr_w(path), clear);
525 attr = GetFileAttributesW(path);
526 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
527 return DMUS_E_LOADER_BADPATH;
529 if (clear)
530 FIXME("clear flag ignored\n");
532 DMUSIC_GetLoaderSettings(iface, class, current_path, NULL);
533 if (!strncmpW(current_path, path, MAX_PATH))
534 return S_FALSE;
536 return DMUSIC_SetLoaderSettings(iface, class, path, NULL);
539 static HRESULT WINAPI IDirectMusicLoaderImpl_ScanDirectory(IDirectMusicLoader8 *iface, REFGUID rguidClass, WCHAR *pwzFileExtension, WCHAR *pwzScanFileName)
541 IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface);
542 static const WCHAR wszAny[] = {'*',0};
543 WIN32_FIND_DATAW FileData;
544 HANDLE hSearch;
545 WCHAR wszSearchString[MAX_PATH];
546 WCHAR *p;
547 HRESULT result;
548 TRACE("(%p, %s, %s, %s)\n", This, debugstr_dmguid(rguidClass), debugstr_w(pwzFileExtension),
549 debugstr_w(pwzScanFileName));
550 if (IsEqualGUID (rguidClass, &GUID_DirectMusicAllTypes) || !DMUSIC_IsValidLoadableClass(rguidClass)) {
551 ERR(": rguidClass invalid CLSID\n");
552 return REGDB_E_CLASSNOTREG;
555 if (!pwzFileExtension)
556 return S_FALSE;
558 /* get search path for given class */
559 DMUSIC_GetLoaderSettings (iface, rguidClass, wszSearchString, NULL);
561 p = wszSearchString + lstrlenW(wszSearchString);
562 if (p > wszSearchString && p[-1] != '\\') *p++ = '\\';
563 *p++ = '*'; /* any file */
564 if (strcmpW (pwzFileExtension, wszAny)) *p++ = '.'; /* if we have actual extension, put a dot */
565 strcpyW (p, pwzFileExtension);
567 TRACE(": search string: %s\n", debugstr_w(wszSearchString));
569 hSearch = FindFirstFileW (wszSearchString, &FileData);
570 if (hSearch == INVALID_HANDLE_VALUE) {
571 TRACE(": no files found\n");
572 return S_FALSE;
575 do {
576 DMUS_OBJECTDESC Desc;
577 DM_STRUCT_INIT(&Desc);
578 Desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_DATE;
579 Desc.guidClass = *rguidClass;
580 strcpyW (Desc.wszFileName, FileData.cFileName);
581 FileTimeToLocalFileTime (&FileData.ftCreationTime, &Desc.ftDate);
582 IDirectMusicLoader8_SetObject (iface, &Desc);
584 if (!FindNextFileW (hSearch, &FileData)) {
585 if (GetLastError () == ERROR_NO_MORE_FILES) {
586 TRACE(": search completed\n");
587 result = S_OK;
588 } else {
589 ERR(": could not get next file\n");
590 result = E_FAIL;
592 FindClose (hSearch);
593 return result;
595 } while (1);
598 static HRESULT WINAPI IDirectMusicLoaderImpl_CacheObject(IDirectMusicLoader8 *iface, IDirectMusicObject *pObject)
600 IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface);
601 DMUS_OBJECTDESC Desc;
602 HRESULT result = DMUS_E_LOADER_OBJECTNOTFOUND;
603 struct list *pEntry;
604 LPWINE_LOADER_ENTRY pObjectEntry = NULL;
606 TRACE("(%p, %p)\n", This, pObject);
608 /* get descriptor */
609 DM_STRUCT_INIT(&Desc);
610 IDirectMusicObject_GetDescriptor (pObject, &Desc);
612 /* now iterate through the list and check if we have an alias (without object), corresponding
613 to the descriptor of the input object */
614 LIST_FOR_EACH(pEntry, This->pObjects) {
615 pObjectEntry = LIST_ENTRY(pEntry, WINE_LOADER_ENTRY, entry);
616 if ((Desc.dwValidData & DMUS_OBJ_OBJECT) &&
617 (pObjectEntry->Desc.dwValidData & DMUS_OBJ_OBJECT) &&
618 IsEqualGUID (&Desc.guidObject, &pObjectEntry->Desc.guidObject)) {
619 TRACE(": found it by object GUID\n");
620 if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject)
621 result = S_FALSE;
622 else
623 result = S_OK;
624 break;
626 else if ((Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) &&
627 (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) &&
628 !strncmpW (Desc.wszFileName, pObjectEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) {
629 TRACE(": found it by fullpath filename\n");
630 if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject)
631 result = S_FALSE;
632 else
633 result = S_OK;
634 break;
636 else if ((Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) &&
637 (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) &&
638 !strncmpW (Desc.wszName, pObjectEntry->Desc.wszName, DMUS_MAX_NAME) &&
639 !strncmpW (Desc.wszCategory, pObjectEntry->Desc.wszCategory, DMUS_MAX_CATEGORY)) {
640 TRACE(": found it by name and category\n");
641 if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject)
642 result = S_FALSE;
643 else
644 result = S_OK;
645 break;
647 else if ((Desc.dwValidData & DMUS_OBJ_NAME) &&
648 (pObjectEntry->Desc.dwValidData & DMUS_OBJ_NAME) &&
649 !strncmpW (Desc.wszName, pObjectEntry->Desc.wszName, DMUS_MAX_NAME)) {
650 TRACE(": found it by name\n");
651 if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject)
652 result = S_FALSE;
653 else
654 result = S_OK;
655 break;
657 else if ((Desc.dwValidData & DMUS_OBJ_FILENAME) &&
658 (pObjectEntry->Desc.dwValidData & DMUS_OBJ_FILENAME) &&
659 !strncmpW (Desc.wszFileName, pObjectEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) {
660 TRACE(": found it by filename\n");
661 if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject)
662 result = S_FALSE;
663 else
664 result = S_OK;
665 break;
669 /* if we found such alias, then set everything */
670 if (result == S_OK) {
671 pObjectEntry->Desc.dwValidData &= DMUS_OBJ_LOADED;
672 pObjectEntry->pObject = pObject;
673 IDirectMusicObject_AddRef (pObjectEntry->pObject);
676 return result;
679 static HRESULT WINAPI IDirectMusicLoaderImpl_ReleaseObject(IDirectMusicLoader8 *iface, IDirectMusicObject *pObject)
681 IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface);
682 DMUS_OBJECTDESC Desc;
683 struct list *pEntry;
684 LPWINE_LOADER_ENTRY pObjectEntry = NULL;
685 HRESULT result = S_FALSE;
687 TRACE("(%p, %p)\n", This, pObject);
689 if(!pObject) return E_POINTER;
691 /* get descriptor */
692 DM_STRUCT_INIT(&Desc);
693 IDirectMusicObject_GetDescriptor (pObject, &Desc);
695 /* iterate through the list of objects we know about; check only those with DMUS_OBJ_LOADED */
696 TRACE(": looking for the object in cache\n");
697 LIST_FOR_EACH(pEntry, This->pObjects) {
698 pObjectEntry = LIST_ENTRY(pEntry, WINE_LOADER_ENTRY, entry);
699 if ((Desc.dwValidData & DMUS_OBJ_OBJECT) &&
700 (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_OBJECT | DMUS_OBJ_LOADED)) &&
701 IsEqualGUID (&Desc.guidObject, &pObjectEntry->Desc.guidObject)) {
702 TRACE(": found it by object GUID\n");
703 if (TRACE_ON(dmloader))
704 dump_DMUS_OBJECTDESC(&pObjectEntry->Desc);
705 result = S_OK;
706 break;
708 else if ((Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) &&
709 (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_LOADED)) &&
710 !strncmpW (Desc.wszFileName, pObjectEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) {
711 TRACE(": found it by fullpath filename\n");
712 result = S_OK;
713 break;
715 else if ((Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) &&
716 (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY | DMUS_OBJ_LOADED)) &&
717 !strncmpW (Desc.wszName, pObjectEntry->Desc.wszName, DMUS_MAX_NAME) &&
718 !strncmpW (Desc.wszCategory, pObjectEntry->Desc.wszCategory, DMUS_MAX_CATEGORY)) {
719 TRACE(": found it by name and category\n");
720 result = S_OK;
721 break;
723 else if ((Desc.dwValidData & DMUS_OBJ_NAME) &&
724 (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_LOADED)) &&
725 !strncmpW (Desc.wszName, pObjectEntry->Desc.wszName, DMUS_MAX_NAME)) {
726 TRACE(": found it by name\n");
727 result = S_OK;
728 break;
730 else if ((Desc.dwValidData & DMUS_OBJ_FILENAME) &&
731 (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_LOADED)) &&
732 !strncmpW (Desc.wszFileName, pObjectEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) {
733 TRACE(": found it by filename\n");
734 result = S_OK;
735 break;
738 if (result == S_OK) {
739 /*TRACE(": releasing:\n%s - bInvalidDefaultDLS = %i\n - pObject = %p\n", debugstr_DMUS_OBJECTDESC(&pObjectEntry->Desc), pObjectEntry->bInvalidDefaultDLS, pObjectEntry->pObject); */
740 IDirectMusicObject_Release (pObjectEntry->pObject);
741 pObjectEntry->pObject = NULL;
742 pObjectEntry->Desc.dwValidData &= ~DMUS_OBJ_LOADED;
744 return result;
747 static HRESULT WINAPI IDirectMusicLoaderImpl_ClearCache(IDirectMusicLoader8 *iface, REFGUID rguidClass)
749 IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface);
750 struct list *pEntry;
751 LPWINE_LOADER_ENTRY pObjectEntry;
752 TRACE("(%p, %s)\n", This, debugstr_dmguid(rguidClass));
754 LIST_FOR_EACH (pEntry, This->pObjects) {
755 pObjectEntry = LIST_ENTRY (pEntry, WINE_LOADER_ENTRY, entry);
757 if ((IsEqualGUID (rguidClass, &GUID_DirectMusicAllTypes) || IsEqualGUID (rguidClass, &pObjectEntry->Desc.guidClass)) &&
758 (pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED)) {
759 /* basically, wrap to ReleaseObject for each object found */
760 IDirectMusicLoader8_ReleaseObject (iface, pObjectEntry->pObject);
764 return S_OK;
767 static HRESULT WINAPI IDirectMusicLoaderImpl_EnableCache(IDirectMusicLoader8 *iface, REFGUID rguidClass, BOOL fEnable)
769 IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface);
770 BOOL bCurrent;
771 TRACE("(%p, %s, %d)\n", This, debugstr_dmguid(rguidClass), fEnable);
772 DMUSIC_GetLoaderSettings (iface, rguidClass, NULL, &bCurrent);
773 if (bCurrent == fEnable)
774 return S_FALSE;
775 else
776 return DMUSIC_SetLoaderSettings (iface, rguidClass, NULL, &fEnable);
779 static HRESULT WINAPI IDirectMusicLoaderImpl_EnumObject(IDirectMusicLoader8 *iface, REFGUID rguidClass, DWORD dwIndex, DMUS_OBJECTDESC *pDesc)
781 IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface);
782 DWORD dwCount = 0;
783 struct list *pEntry;
784 LPWINE_LOADER_ENTRY pObjectEntry;
785 TRACE("(%p, %s, %d, %p)\n", This, debugstr_dmguid(rguidClass), dwIndex, pDesc);
787 DM_STRUCT_INIT(pDesc);
789 LIST_FOR_EACH (pEntry, This->pObjects) {
790 pObjectEntry = LIST_ENTRY (pEntry, WINE_LOADER_ENTRY, entry);
792 if (IsEqualGUID (rguidClass, &GUID_DirectMusicAllTypes) || IsEqualGUID (rguidClass, &pObjectEntry->Desc.guidClass)) {
793 if (dwCount == dwIndex) {
794 *pDesc = pObjectEntry->Desc;
795 /* we aren't supposed to reveal this info */
796 pDesc->dwValidData &= ~(DMUS_OBJ_MEMORY | DMUS_OBJ_STREAM);
797 pDesc->pbMemData = NULL;
798 pDesc->llMemLength = 0;
799 pDesc->pStream = NULL;
800 return S_OK;
802 dwCount++;
806 TRACE(": not found\n");
807 return S_FALSE;
810 static void WINAPI IDirectMusicLoaderImpl_CollectGarbage(IDirectMusicLoader8 *iface)
812 FIXME("(%p)->(): stub\n", iface);
815 static HRESULT WINAPI IDirectMusicLoaderImpl_ReleaseObjectByUnknown(IDirectMusicLoader8 *iface, IUnknown *pObject)
817 IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface);
818 HRESULT result;
819 LPDIRECTMUSICOBJECT pObjectInterface;
821 TRACE("(%p, %p)\n", This, pObject);
823 if (IsBadReadPtr (pObject, sizeof(*pObject))) {
824 ERR(": pObject bad write pointer\n");
825 return E_POINTER;
827 /* we simply get IDirectMusicObject interface */
828 result = IUnknown_QueryInterface (pObject, &IID_IDirectMusicObject, (LPVOID*)&pObjectInterface);
829 if (FAILED(result)) return result;
830 /* and release it in old-fashioned way */
831 result = IDirectMusicLoader8_ReleaseObject (iface, pObjectInterface);
832 IDirectMusicObject_Release (pObjectInterface);
834 return result;
837 static HRESULT WINAPI IDirectMusicLoaderImpl_LoadObjectFromFile(IDirectMusicLoader8 *iface, REFGUID rguidClassID, REFIID iidInterfaceID, WCHAR *pwzFilePath, void **ppObject)
839 IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface);
840 DMUS_OBJECTDESC ObjDesc;
841 WCHAR wszLoaderSearchPath[MAX_PATH];
843 TRACE("(%p, %s, %s, %s, %p): wrapping to IDirectMusicLoaderImpl_GetObject\n", This, debugstr_dmguid(rguidClassID), debugstr_dmguid(iidInterfaceID), debugstr_w(pwzFilePath), ppObject);
845 DM_STRUCT_INIT(&ObjDesc);
846 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 */
847 ObjDesc.guidClass = *rguidClassID;
848 /* OK, MSDN says that search order is the following:
849 - current directory (DONE)
850 - windows search path (FIXME: how do I get that?)
851 - loader's search path (DONE)
853 DMUSIC_GetLoaderSettings (iface, rguidClassID, wszLoaderSearchPath, NULL);
854 /* search in current directory */
855 if (!SearchPathW (NULL, pwzFilePath, NULL, sizeof(ObjDesc.wszFileName)/sizeof(WCHAR), ObjDesc.wszFileName, NULL) &&
856 /* search in loader's search path */
857 !SearchPathW (wszLoaderSearchPath, pwzFilePath, NULL, sizeof(ObjDesc.wszFileName)/sizeof(WCHAR), ObjDesc.wszFileName, NULL)) {
858 /* cannot find file */
859 TRACE(": cannot find file\n");
860 return DMUS_E_LOADER_FAILEDOPEN;
863 TRACE(": full file path = %s\n", debugstr_w (ObjDesc.wszFileName));
865 return IDirectMusicLoader_GetObject(iface, &ObjDesc, iidInterfaceID, ppObject);
868 static const IDirectMusicLoader8Vtbl DirectMusicLoader_Loader_Vtbl = {
869 IDirectMusicLoaderImpl_QueryInterface,
870 IDirectMusicLoaderImpl_AddRef,
871 IDirectMusicLoaderImpl_Release,
872 IDirectMusicLoaderImpl_GetObject,
873 IDirectMusicLoaderImpl_SetObject,
874 IDirectMusicLoaderImpl_SetSearchDirectory,
875 IDirectMusicLoaderImpl_ScanDirectory,
876 IDirectMusicLoaderImpl_CacheObject,
877 IDirectMusicLoaderImpl_ReleaseObject,
878 IDirectMusicLoaderImpl_ClearCache,
879 IDirectMusicLoaderImpl_EnableCache,
880 IDirectMusicLoaderImpl_EnumObject,
881 IDirectMusicLoaderImpl_CollectGarbage,
882 IDirectMusicLoaderImpl_ReleaseObjectByUnknown,
883 IDirectMusicLoaderImpl_LoadObjectFromFile
886 /* help function for DMUSIC_SetDefaultDLS */
887 static HRESULT DMUSIC_GetDefaultGMPath (WCHAR wszPath[MAX_PATH]) {
888 HKEY hkDM;
889 DWORD returnType, sizeOfReturnBuffer = MAX_PATH;
890 char szPath[MAX_PATH];
892 if ((RegOpenKeyExA (HKEY_LOCAL_MACHINE, "Software\\Microsoft\\DirectMusic" , 0, KEY_READ, &hkDM) != ERROR_SUCCESS) ||
893 (RegQueryValueExA (hkDM, "GMFilePath", NULL, &returnType, (LPBYTE) szPath, &sizeOfReturnBuffer) != ERROR_SUCCESS)) {
894 WARN(": registry entry missing\n" );
895 return E_FAIL;
897 /* FIXME: Check return types to ensure we're interpreting data right */
898 MultiByteToWideChar (CP_ACP, 0, szPath, -1, wszPath, MAX_PATH);
900 return S_OK;
903 /* for ClassFactory */
904 HRESULT WINAPI create_dmloader(REFIID lpcGUID, void **ppobj)
906 IDirectMusicLoaderImpl *obj;
907 DMUS_OBJECTDESC Desc;
908 LPWINE_LOADER_ENTRY pDefaultDLSEntry;
909 struct list *pEntry;
911 TRACE("(%s, %p)\n", debugstr_dmguid(lpcGUID), ppobj);
912 obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoaderImpl));
913 if (NULL == obj) {
914 *ppobj = NULL;
915 return E_OUTOFMEMORY;
917 obj->IDirectMusicLoader8_iface.lpVtbl = &DirectMusicLoader_Loader_Vtbl;
918 obj->ref = 0; /* Will be inited with QueryInterface */
919 /* init cache/alias list */
920 obj->pObjects = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(struct list));
921 list_init (obj->pObjects);
922 /* init settings */
923 obj->pClassSettings = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(struct list));
924 list_init (obj->pClassSettings);
925 DMUSIC_InitLoaderSettings(&obj->IDirectMusicLoader8_iface);
927 /* set default DLS collection (via SetObject... so that loading via DMUS_OBJ_OBJECT is possible) */
928 DM_STRUCT_INIT(&Desc);
929 Desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_OBJECT;
930 Desc.guidClass = CLSID_DirectMusicCollection;
931 Desc.guidObject = GUID_DefaultGMCollection;
932 DMUSIC_GetDefaultGMPath (Desc.wszFileName);
933 IDirectMusicLoader_SetObject(&obj->IDirectMusicLoader8_iface, &Desc);
934 /* and now the workaroundTM for "invalid" default DLS; basically,
935 my tests showed that if GUID chunk is present in default DLS
936 collection, loader treats it as "invalid" and returns
937 DMUS_E_LOADER_NOFILENAME for all requests for it; basically, we check
938 if out input guidObject was overwritten */
939 pEntry = list_head (obj->pObjects);
940 pDefaultDLSEntry = LIST_ENTRY (pEntry, WINE_LOADER_ENTRY, entry);
941 if (!IsEqualGUID(&Desc.guidObject, &GUID_DefaultGMCollection)) {
942 pDefaultDLSEntry->bInvalidDefaultDLS = TRUE;
945 lock_module();
947 return IDirectMusicLoader_QueryInterface(&obj->IDirectMusicLoader8_iface, lpcGUID, ppobj);
950 /* help function for retrieval of search path and caching option for certain class */
951 static HRESULT DMUSIC_GetLoaderSettings(IDirectMusicLoader8 *iface, REFGUID pClassID, WCHAR *wszSearchPath, BOOL *pbCache)
953 IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface);
954 struct list *pEntry;
955 TRACE(": (%p, %s, %p, %p)\n", This, debugstr_dmguid(pClassID), wszSearchPath, pbCache);
957 LIST_FOR_EACH(pEntry, This->pClassSettings) {
958 LPWINE_LOADER_OPTION pOptionEntry = LIST_ENTRY(pEntry, WINE_LOADER_OPTION, entry);
959 if (IsEqualCLSID (pClassID, &pOptionEntry->guidClass)) {
960 if (wszSearchPath)
961 strcpyW(wszSearchPath, pOptionEntry->wszSearchPath);
962 if (pbCache)
963 *pbCache = pOptionEntry->bCache;
964 return S_OK;
967 return S_FALSE;
970 /* help function for setting search path and caching option for certain class */
971 static HRESULT DMUSIC_SetLoaderSettings(IDirectMusicLoader8 *iface, REFGUID pClassID, WCHAR *wszSearchPath, BOOL *pbCache)
973 IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface);
974 struct list *pEntry;
975 HRESULT result = S_FALSE; /* in case pClassID != GUID_DirectMusicAllTypes and not a valid CLSID */
976 TRACE(": (%p, %s, %p, %p)\n", This, debugstr_dmguid(pClassID), wszSearchPath, pbCache);
978 LIST_FOR_EACH(pEntry, This->pClassSettings) {
979 LPWINE_LOADER_OPTION pOptionEntry = LIST_ENTRY(pEntry, WINE_LOADER_OPTION, entry);
980 /* well, either we have GUID_DirectMusicAllTypes and need to set it to all,
981 or specific CLSID is given and we set it only to it */
982 if (IsEqualGUID (pClassID, &GUID_DirectMusicAllTypes) ||
983 IsEqualCLSID (pClassID, &pOptionEntry->guidClass)) {
984 if (wszSearchPath)
985 strcpyW(pOptionEntry->wszSearchPath, wszSearchPath);
986 if (pbCache)
987 pOptionEntry->bCache = *pbCache;
988 result = S_OK;
992 return result;
995 static HRESULT DMUSIC_InitLoaderSettings(IDirectMusicLoader8 *iface)
997 IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface);
999 /* hard-coded list of classes */
1000 static REFCLSID classes[] = {
1001 &CLSID_DirectMusicAudioPathConfig,
1002 &CLSID_DirectMusicBand,
1003 &CLSID_DirectMusicContainer,
1004 &CLSID_DirectMusicCollection,
1005 &CLSID_DirectMusicChordMap,
1006 &CLSID_DirectMusicSegment,
1007 &CLSID_DirectMusicScript,
1008 &CLSID_DirectMusicSong,
1009 &CLSID_DirectMusicStyle,
1010 &CLSID_DirectMusicGraph,
1011 &CLSID_DirectSoundWave
1014 unsigned int i;
1015 WCHAR wszCurrent[MAX_PATH];
1017 TRACE(": (%p)\n", This);
1018 GetCurrentDirectoryW (MAX_PATH, wszCurrent);
1020 for (i = 0; i < sizeof(classes)/sizeof(REFCLSID); i++) {
1021 LPWINE_LOADER_OPTION pNewSetting = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(WINE_LOADER_OPTION));
1022 pNewSetting->guidClass = *classes[i];
1023 strcpyW (pNewSetting->wszSearchPath, wszCurrent);
1024 pNewSetting->bCache = TRUE;
1025 list_add_tail (This->pClassSettings, &pNewSetting->entry);
1028 return S_OK;