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;
44 pDst->dwValidData |= pSrc->dwValidData;
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))
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);
84 WARN(": not found\n");
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);
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);
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 */
119 LPWINE_LOADER_ENTRY pObjectEntry = NULL;
121 IPersistStream* pPersistStream = NULL;
123 LPDIRECTMUSICOBJECT pObject;
124 DMUS_OBJECTDESC GotDesc;
127 TRACE("(%p, %p, %s, %p): pDesc:\n%s\n", This, pDesc, debugstr_dmguid(riid), ppv, debugstr_DMUS_OBJECTDESC(pDesc));
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");
133 return DMUS_E_LOADER_NOCLASSID;
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;
150 if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) {
151 TRACE(": already loaded\n");
152 return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv);
154 TRACE(": not loaded yet\n");
155 pObjectEntry = pExistingEntry;
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);
166 TRACE(": not loaded yet\n");
167 pObjectEntry = pExistingEntry;
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);
179 TRACE(": not loaded yet\n");
180 pObjectEntry = pExistingEntry;
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);
191 TRACE(": not loaded yet\n");
192 pObjectEntry = pExistingEntry;
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);
203 TRACE(": not loaded yet\n");
204 pObjectEntry = pExistingEntry;
209 /* basically, if we found alias, we use its descriptor to load...
210 else we use info we were given */
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? */
220 TRACE(": no cache/alias entry found for requested object\n");
223 if (pDesc->dwValidData & DMUS_OBJ_URL) {
224 TRACE(": loading from URLs not supported yet\n");
225 return DMUS_E_LOADER_FORMATNOTSUPPORTED;
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];
233 if (pDesc->dwValidData & DMUS_OBJ_FULLPATH) {
234 lstrcpyW(wszFileName, pDesc->wszFileName);
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);
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");
250 result = IDirectMusicLoaderFileStream_Attach (pStream, wszFileName, iface);
251 if (FAILED(result)) {
252 ERR(": could not attach stream to file\n");
253 IStream_Release (pStream);
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");
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);
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");
282 result = IDirectMusicLoaderGenericStream_Attach (pStream, pDesc->pStream, iface);
283 if (FAILED(result)) {
284 ERR(": failed to attach stream\n");
285 IStream_Release (pStream);
289 /* nowhere to load from */
290 FIXME(": unknown/unsupported way of loading\n");
291 return DMUS_E_LOADER_NOFILENAME; /* test shows this is returned */
295 result = CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject);
296 if (FAILED(result)) {
297 ERR(": could not create object\n");
300 /* acquire PersistStream interface */
301 result = IDirectMusicObject_QueryInterface (pObject, &IID_IPersistStream, (LPVOID*)&pPersistStream);
302 if (FAILED(result)) {
303 ERR("failed to Query\n");
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*/;
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);
320 if (FAILED(result)) {
321 ERR(": failed to get descriptor\n");
324 /* release all loading related stuff */
325 IStream_Release (pStream);
326 IPersistStream_Release (pPersistStream);
328 /* add object to cache/overwrite existing info (if cache is enabled) */
329 DMUSIC_GetLoaderSettings (iface, &pDesc->guidClass, NULL, &bCache);
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);
339 DMUSIC_CopyDescriptor (&pObjectEntry->Desc, &GotDesc);
340 pObjectEntry->pObject = pObject;
341 pObjectEntry->bInvalidDefaultDLS = FALSE;
343 TRACE(": filled in cache entry\n");
344 } else TRACE(": caching disabled\n");
347 /* for debug purposes (e.g. to check if all files are cached) */
348 TRACE("*** Loader's cache ***\n");
350 LIST_FOR_EACH (pEntry, This->pObjects) {
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);
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 */
367 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_SetObject (LPDIRECTMUSICLOADER8 iface, LPDMUS_OBJECTDESC pDesc) {
368 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
370 LPDIRECTMUSICOBJECT pObject;
371 DMUS_OBJECTDESC Desc;
373 LPWINE_LOADER_ENTRY pObjectEntry, pNewEntry;
376 TRACE("(%p, %p): pDesc:\n%s\n", This, pDesc, debugstr_DMUS_OBJECTDESC(pDesc));
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];
384 if (pDesc->dwValidData & DMUS_OBJ_FULLPATH) {
385 lstrcpyW(wszFileName, pDesc->wszFileName);
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);
396 hr = DMUSIC_CreateDirectMusicLoaderFileStream ((LPVOID*)&pStream);
398 ERR(": could not create file stream\n");
399 return DMUS_E_LOADER_FAILEDOPEN;
402 hr = IDirectMusicLoaderFileStream_Attach (pStream, wszFileName, iface);
404 ERR(": could not attach stream to file\n");
405 IStream_Release (pStream);
406 return DMUS_E_LOADER_FAILEDOPEN;
409 else if (pDesc->dwValidData & DMUS_OBJ_STREAM) {
411 hr = DMUSIC_CreateDirectMusicLoaderGenericStream ((LPVOID*)&pStream);
413 ERR(": could not create generic stream\n");
414 return DMUS_E_LOADER_FAILEDOPEN;
417 hr = IDirectMusicLoaderGenericStream_Attach (pStream, pDesc->pStream, iface);
419 ERR(": could not attach stream\n");
420 IStream_Release (pStream);
421 return DMUS_E_LOADER_FAILEDOPEN;
424 else if (pDesc->dwValidData & DMUS_OBJ_MEMORY) {
426 hr = DMUSIC_CreateDirectMusicLoaderResourceStream ((LPVOID*)&pStream);
428 ERR(": could not create resource stream\n");
429 return DMUS_E_LOADER_FAILEDOPEN;
432 hr = IDirectMusicLoaderResourceStream_Attach (pStream, pDesc->pbMemData, pDesc->llMemLength, 0, iface);
434 ERR(": could not attach stream to resource\n");
435 IStream_Release (pStream);
436 return DMUS_E_LOADER_FAILEDOPEN;
440 ERR(": no way to get additional info\n");
441 return DMUS_E_LOADER_FAILEDOPEN;
445 CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject);
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);
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;
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);
464 /* release everything */
465 IDirectMusicObject_Release (pObject);
466 IStream_Release (pStream);
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");
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);
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)) {
498 /* FIXME: check if path is valid; else return DMUS_E_LOADER_BADPATH */
499 return DMUSIC_SetLoaderSettings (iface, rguidClass, pwzPath, NULL);
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;
506 WCHAR wszSearchString[MAX_PATH];
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;
516 /* get search path for given class */
517 DMUSIC_GetLoaderSettings (iface, rguidClass, wszSearchString, NULL);
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);
525 TRACE(": search string: %s\n", debugstr_w(wszSearchString));
527 hSearch = FindFirstFileW (wszSearchString, &FileData);
528 if (hSearch == INVALID_HANDLE_VALUE) {
529 TRACE(": no files found\n");
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);
542 if (!FindNextFileW (hSearch, &FileData)) {
543 if (GetLastError () == ERROR_NO_MORE_FILES) {
544 TRACE(": search completed\n");
547 ERR(": could not get next file\n");
556 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_CacheObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject) {
557 DMUS_OBJECTDESC Desc;
558 HRESULT result = DMUS_E_LOADER_OBJECTNOTFOUND;
560 LPWINE_LOADER_ENTRY pObjectEntry = NULL;
562 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
563 TRACE("(%p, %p)\n", This, pObject);
566 DM_STRUCT_INIT(&Desc);
567 IDirectMusicObject_GetDescriptor (pObject, &Desc);
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)
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)
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)
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)
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)
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);
636 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ReleaseObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject) {
637 DMUS_OBJECTDESC Desc;
639 LPWINE_LOADER_ENTRY pObjectEntry = NULL;
640 HRESULT result = S_FALSE;
642 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
643 TRACE("(%p, %p)\n", This, pObject);
645 if(!pObject) return E_POINTER;
648 DM_STRUCT_INIT(&Desc);
649 IDirectMusicObject_GetDescriptor (pObject, &Desc);
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));
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");
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");
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");
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");
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;
701 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ClearCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass) {
703 LPWINE_LOADER_ENTRY pObjectEntry;
704 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
705 TRACE("(%p, %s)\n", This, debugstr_dmguid(rguidClass));
707 LIST_FOR_EACH (pEntry, This->pObjects) {
708 pObjectEntry = LIST_ENTRY (pEntry, WINE_LOADER_ENTRY, entry);
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);
720 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_EnableCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, BOOL fEnable) {
721 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
723 TRACE("(%p, %s, %d)\n", This, debugstr_dmguid(rguidClass), fEnable);
724 DMUSIC_GetLoaderSettings (iface, rguidClass, NULL, &bCurrent);
725 if (bCurrent == fEnable)
728 return DMUSIC_SetLoaderSettings (iface, rguidClass, NULL, &fEnable);
731 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_EnumObject (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, DWORD dwIndex, LPDMUS_OBJECTDESC pDesc) {
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);
738 DM_STRUCT_INIT(pDesc);
740 LIST_FOR_EACH (pEntry, This->pObjects) {
741 pObjectEntry = LIST_ENTRY (pEntry, WINE_LOADER_ENTRY, entry);
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;
757 TRACE(": not found\n");
761 static void WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_CollectGarbage (LPDIRECTMUSICLOADER8 iface) {
762 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
763 FIXME("(%p): stub\n", This);
766 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ReleaseObjectByUnknown (LPDIRECTMUSICLOADER8 iface, IUnknown* pObject) {
767 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
769 LPDIRECTMUSICOBJECT pObjectInterface;
771 TRACE("(%p, %p)\n", This, pObject);
773 if (IsBadReadPtr (pObject, sizeof(LPUNKNOWN))) {
774 ERR(": pObject bad write pointer\n");
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);
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];
792 TRACE("(%p, %s, %s, %s, %p): wrapping to IDirectMusicLoaderImpl_GetObject\n", This, debugstr_dmguid(rguidClassID), debugstr_dmguid(iidInterfaceID), debugstr_w(pwzFilePath), ppObject);
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)
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;
812 TRACE(": full file path = %s\n", debugstr_w (ObjDesc.wszFileName));
814 return IDirectMusicLoaderImpl_IDirectMusicLoader_GetObject (iface, &ObjDesc, iidInterfaceID, ppObject);
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
835 /* help function for DMUSIC_SetDefaultDLS */
836 static HRESULT DMUSIC_GetDefaultGMPath (WCHAR wszPath[MAX_PATH]) {
838 DWORD returnType, sizeOfReturnBuffer = MAX_PATH;
839 char szPath[MAX_PATH];
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" );
846 /* FIXME: Check return types to ensure we're interpreting data right */
847 MultiByteToWideChar (CP_ACP, 0, szPath, -1, wszPath, MAX_PATH);
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;
859 TRACE("(%s, %p, %p)\n", debugstr_dmguid(lpcGUID), ppobj, pUnkOuter);
860 obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoaderImpl));
863 return E_OUTOFMEMORY;
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);
874 obj->pClassSettings = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(struct list));
875 list_init (obj->pClassSettings);
876 DMUSIC_InitLoaderSettings ((LPDIRECTMUSICLOADER8)obj);
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;
898 return IDirectMusicLoaderImpl_IDirectMusicLoader_QueryInterface ((LPDIRECTMUSICLOADER8)obj, lpcGUID, ppobj);
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);
905 TRACE(": (%p, %s, %p, %p)\n", This, debugstr_dmguid(pClassID), wszSearchPath, pbCache);
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)) {
911 strcpyW(wszSearchPath, pOptionEntry->wszSearchPath);
913 *pbCache = pOptionEntry->bCache;
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);
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);
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)) {
934 strcpyW(pOptionEntry->wszSearchPath, wszSearchPath);
936 pOptionEntry->bCache = *pbCache;
944 static HRESULT DMUSIC_InitLoaderSettings (LPDIRECTMUSICLOADER8 iface) {
945 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
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
963 WCHAR wszCurrent[MAX_PATH];
965 TRACE(": (%p)\n", This);
966 GetCurrentDirectoryW (MAX_PATH, wszCurrent);
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);