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 WINAPI DMUSIC_SetLoaderSettings (LPDIRECTMUSICLOADER8 iface, REFGUID pClassID, WCHAR* wszSearchPath, LPBOOL pbCache);
26 /*****************************************************************************
27 * IDirectMusicLoaderImpl implementation
29 /* IUnknown/IDirectMusicLoader(8) part: */
30 static ULONG WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_AddRef (LPDIRECTMUSICLOADER8 iface);
32 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_QueryInterface (LPDIRECTMUSICLOADER8 iface, REFIID riid, LPVOID *ppobj) {
33 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
35 TRACE("(%p, %s, %p)\n",This, debugstr_dmguid(riid), ppobj);
36 if (IsEqualIID (riid, &IID_IUnknown) ||
37 IsEqualIID (riid, &IID_IDirectMusicLoader) ||
38 IsEqualIID (riid, &IID_IDirectMusicLoader8)) {
39 IDirectMusicLoaderImpl_IDirectMusicLoader_AddRef (iface);
44 WARN(": not found\n");
48 static ULONG WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_AddRef (LPDIRECTMUSICLOADER8 iface) {
49 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
50 TRACE("(%p): AddRef from %d\n", This, This->dwRef);
51 return InterlockedIncrement (&This->dwRef);
54 static ULONG WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_Release (LPDIRECTMUSICLOADER8 iface) {
55 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
57 DWORD dwRef = InterlockedDecrement (&This->dwRef);
58 TRACE("(%p): ReleaseRef to %d\n", This, This->dwRef);
60 DMUSIC_DestroyDirectMusicLoaderImpl (iface);
61 HeapFree (GetProcessHeap(), 0, This);
67 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_GetObject (LPDIRECTMUSICLOADER8 iface, LPDMUS_OBJECTDESC pDesc, REFIID riid, LPVOID* ppv) {
68 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
69 HRESULT result = S_OK;
70 HRESULT ret = S_OK; /* used at the end of function, to determine whether everything went OK */
73 LPWINE_LOADER_ENTRY pObjectEntry = NULL;
75 IPersistStream* pPersistStream = NULL;
77 LPDIRECTMUSICOBJECT pObject;
78 DMUS_OBJECTDESC GotDesc;
81 TRACE("(%p, %p, %s, %p): pDesc:\n%s\n", This, pDesc, debugstr_dmguid(riid), ppv, debugstr_DMUS_OBJECTDESC(pDesc));
83 /* sometimes it happens that guidClass is missing... which is a BadThingTM */
84 if (!(pDesc->dwValidData & DMUS_OBJ_CLASS)) {
85 ERR(": guidClass not valid but needed\n");
87 return DMUS_E_LOADER_NOCLASSID;
90 /* OK, first we iterate thru the list of objects we know about; these are either loaded (GetObject, LoadObjectFromFile)
91 or set via SetObject; */
92 TRACE(": looking if we have object in the cache or if it can be found via alias\n");
93 LIST_FOR_EACH(pEntry, This->pObjects) {
94 LPWINE_LOADER_ENTRY pExistingEntry = LIST_ENTRY(pEntry, WINE_LOADER_ENTRY, entry);
95 if ((pDesc->dwValidData & DMUS_OBJ_OBJECT) &&
96 (pExistingEntry->Desc.dwValidData & DMUS_OBJ_OBJECT) &&
97 IsEqualGUID (&pDesc->guidObject, &pExistingEntry->Desc.guidObject)) {
98 TRACE(": found it by object GUID\n");
99 /* I suppose such stuff can happen only when GUID for object is given (GUID_DefaultGMCollection) */
100 if (pExistingEntry->bInvalidDefaultDLS) {
101 TRACE(": found faulty default DLS collection... enabling M$ compliant behaviour\n");
102 return DMUS_E_LOADER_NOFILENAME;
104 if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) {
105 TRACE(": already loaded\n");
106 return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv);
108 TRACE(": not loaded yet\n");
109 pObjectEntry = pExistingEntry;
112 else if ((pDesc->dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) &&
113 (pExistingEntry->Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) &&
114 !strncmpW (pDesc->wszFileName, pExistingEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) {
115 TRACE(": found it by fullpath filename\n");
116 if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) {
117 TRACE(": already loaded\n");
118 return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv);
120 TRACE(": not loaded yet\n");
121 pObjectEntry = pExistingEntry;
124 else if ((pDesc->dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) &&
125 (pExistingEntry->Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) &&
126 !strncmpW (pDesc->wszName, pExistingEntry->Desc.wszName, DMUS_MAX_NAME) &&
127 !strncmpW (pDesc->wszCategory, pExistingEntry->Desc.wszCategory, DMUS_MAX_CATEGORY)) {
128 TRACE(": found it by name and category\n");
129 if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) {
130 TRACE(": already loaded\n");
131 return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv);
133 TRACE(": not loaded yet\n");
134 pObjectEntry = pExistingEntry;
137 else if ((pDesc->dwValidData & DMUS_OBJ_NAME) &&
138 (pExistingEntry->Desc.dwValidData & DMUS_OBJ_NAME) &&
139 !strncmpW (pDesc->wszName, pExistingEntry->Desc.wszName, DMUS_MAX_NAME)) {
140 TRACE(": found it by name\n");
141 if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) {
142 TRACE(": already loaded\n");
143 return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv);
145 TRACE(": not loaded yet\n");
146 pObjectEntry = pExistingEntry;
149 else if ((pDesc->dwValidData & DMUS_OBJ_FILENAME) &&
150 (pExistingEntry->Desc.dwValidData & DMUS_OBJ_FILENAME) &&
151 !strncmpW (pDesc->wszFileName, pExistingEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) {
152 TRACE(": found it by filename\n");
153 if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) {
154 TRACE(": already loaded\n");
155 return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv);
157 TRACE(": not loaded yet\n");
158 pObjectEntry = pExistingEntry;
163 /* basically, if we found alias, we use its descriptor to load...
164 else we use info we were given */
166 TRACE(": found alias entry for requested object... using stored info\n");
167 /* I think in certain cases it can happen that entry's descriptor lacks info
168 where to load from (e.g.: if we loaded from stream and then released object
169 from cache; then only it's CLSID, GUID and perhaps name are left); so just
170 overwrite info entry has (since it ought to be 100% correct) */
171 DMUSIC_CopyDescriptor (pDesc, &pObjectEntry->Desc);
172 /*pDesc = &pObjectEntry->Desc; */ /* FIXME: is this OK? */
174 TRACE(": no cache/alias entry found for requested object\n");
177 if (pDesc->dwValidData & DMUS_OBJ_URL) {
178 TRACE(": loading from URLs not supported yet\n");
179 return DMUS_E_LOADER_FORMATNOTSUPPORTED;
181 else if (pDesc->dwValidData & DMUS_OBJ_FILENAME) {
182 /* load object from file */
183 /* generate filename; if it's full path, don't add search
184 directory path, otherwise do */
185 WCHAR wszFileName[MAX_PATH];
187 if (pDesc->dwValidData & DMUS_OBJ_FULLPATH) {
188 lstrcpyW(wszFileName, pDesc->wszFileName);
190 WCHAR *p, wszSearchPath[MAX_PATH];
191 DMUSIC_GetLoaderSettings (iface, &pDesc->guidClass, wszSearchPath, NULL);
192 lstrcpyW(wszFileName, wszSearchPath);
193 p = wszFileName + lstrlenW(wszFileName);
194 if (p > wszFileName && p[-1] != '\\') *p++ = '\\';
195 strcpyW(p, pDesc->wszFileName);
197 TRACE(": loading from file (%s)\n", debugstr_w(wszFileName));
198 /* create stream and associate it with file */
199 result = DMUSIC_CreateDirectMusicLoaderFileStream ((LPVOID*)&pStream);
200 if (FAILED(result)) {
201 ERR(": could not create file stream\n");
204 result = IDirectMusicLoaderFileStream_Attach (pStream, wszFileName, iface);
205 if (FAILED(result)) {
206 ERR(": could not attach stream to file\n");
207 IStream_Release (pStream);
211 else if (pDesc->dwValidData & DMUS_OBJ_MEMORY) {
212 /* load object from resource */
213 TRACE(": loading from resource\n");
214 /* create stream and associate it with given resource */
215 result = DMUSIC_CreateDirectMusicLoaderResourceStream ((LPVOID*)&pStream);
216 if (FAILED(result)) {
217 ERR(": could not create resource stream\n");
220 result = IDirectMusicLoaderResourceStream_Attach (pStream, pDesc->pbMemData, pDesc->llMemLength, 0, iface);
221 if (FAILED(result)) {
222 ERR(": could not attach stream to resource\n");
223 IStream_Release (pStream);
227 else if (pDesc->dwValidData & DMUS_OBJ_STREAM) {
228 /* load object from stream */
229 TRACE(": loading from stream\n");
230 /* create universal stream and associate it with given one */
231 result = DMUSIC_CreateDirectMusicLoaderGenericStream ((LPVOID*)&pStream);
232 if (FAILED(result)) {
233 ERR(": could not create generic stream\n");
236 result = IDirectMusicLoaderGenericStream_Attach (pStream, pDesc->pStream, iface);
237 if (FAILED(result)) {
238 ERR(": failed to attach stream\n");
239 IStream_Release (pStream);
243 /* nowhere to load from */
244 FIXME(": unknown/unsupported way of loading\n");
245 return DMUS_E_LOADER_NOFILENAME; /* test shows this is returned */
249 result = CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject);
250 if (FAILED(result)) {
251 ERR(": could not create object\n");
254 /* acquire PersistStream interface */
255 result = IDirectMusicObject_QueryInterface (pObject, &IID_IPersistStream, (LPVOID*)&pPersistStream);
256 if (FAILED(result)) {
257 ERR("failed to Query\n");
261 result = IPersistStream_Load (pPersistStream, pStream);
262 if (result != S_OK) {
263 WARN(": failed to (completely) load object (%s)\n", debugstr_dmreturn(result));
264 ret = DMUS_S_PARTIALLOAD /*result*/;
267 DM_STRUCT_INIT(&GotDesc);
268 result = IDirectMusicObject_GetDescriptor (pObject, &GotDesc);
269 /* set filename (if we loaded via filename) */
270 if (pDesc->dwValidData & DMUS_OBJ_FILENAME) {
271 GotDesc.dwValidData |= (pDesc->dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH));
272 strcpyW (GotDesc.wszFileName, pDesc->wszFileName);
274 if (FAILED(result)) {
275 ERR(": failed to get descriptor\n");
278 /* release all loading related stuff */
279 IStream_Release (pStream);
280 IPersistStream_Release (pPersistStream);
282 /* add object to cache/overwrite existing info (if cache is enabled) */
283 DMUSIC_GetLoaderSettings (iface, &pDesc->guidClass, NULL, &bCache);
286 pObjectEntry = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(WINE_LOADER_ENTRY));
287 DM_STRUCT_INIT(&pObjectEntry->Desc);
289 DMUSIC_CopyDescriptor (&pObjectEntry->Desc, &GotDesc);
290 pObjectEntry->pObject = pObject;
291 pObjectEntry->bInvalidDefaultDLS = FALSE;
293 list_add_head (This->pObjects, &pObjectEntry->entry);
296 DMUSIC_CopyDescriptor (&pObjectEntry->Desc, &GotDesc);
297 pObjectEntry->pObject = pObject;
298 pObjectEntry->bInvalidDefaultDLS = FALSE;
301 TRACE(": filled in cache entry\n");
302 } else TRACE(": caching disabled\n");
305 /* for debug purposes (e.g. to check if all files are cached) */
306 TRACE("*** Loader's cache ***\n");
308 LIST_FOR_EACH (pEntry, This->pObjects) {
310 pObjectEntry = LIST_ENTRY(pEntry, WINE_LOADER_ENTRY, entry);
311 TRACE(": entry nr. %i:\n%s\n - bInvalidDefaultDLS = %i\n - pObject = %p\n", i, debugstr_DMUS_OBJECTDESC(&pObjectEntry->Desc), pObjectEntry->bInvalidDefaultDLS, pObjectEntry->pObject);
315 result = IDirectMusicObject_QueryInterface (pObject, riid, ppv);
316 if (!bCache) IDirectMusicObject_Release (pObject); /* since loader's reference is not needed */
317 /* if there was trouble with loading, and if no other error occurred,
318 we should return DMUS_S_PARTIALLOAD; else, error is returned */
325 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_SetObject (LPDIRECTMUSICLOADER8 iface, LPDMUS_OBJECTDESC pDesc) {
326 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
328 LPDIRECTMUSICOBJECT pObject;
329 DMUS_OBJECTDESC Desc;
331 LPWINE_LOADER_ENTRY pObjectEntry, pNewEntry;
334 TRACE("(%p, %p): pDesc:\n%s\n", This, pDesc, debugstr_DMUS_OBJECTDESC(pDesc));
336 /* create stream and load additional info from it */
337 if (pDesc->dwValidData & DMUS_OBJ_FILENAME) {
338 /* generate filename; if it's full path, don't add search
339 directory path, otherwise do */
340 WCHAR wszFileName[MAX_PATH];
342 if (pDesc->dwValidData & DMUS_OBJ_FULLPATH) {
343 lstrcpyW(wszFileName, pDesc->wszFileName);
346 WCHAR wszSearchPath[MAX_PATH];
347 DMUSIC_GetLoaderSettings (iface, &pDesc->guidClass, wszSearchPath, NULL);
348 lstrcpyW(wszFileName, wszSearchPath);
349 p = wszFileName + lstrlenW(wszFileName);
350 if (p > wszFileName && p[-1] != '\\') *p++ = '\\';
351 strcpyW(p, pDesc->wszFileName);
354 hr = DMUSIC_CreateDirectMusicLoaderFileStream ((LPVOID*)&pStream);
356 ERR(": could not create file stream\n");
357 return DMUS_E_LOADER_FAILEDOPEN;
360 hr = IDirectMusicLoaderFileStream_Attach (pStream, wszFileName, iface);
362 ERR(": could not attach stream to file\n");
363 IStream_Release (pStream);
364 return DMUS_E_LOADER_FAILEDOPEN;
367 else if (pDesc->dwValidData & DMUS_OBJ_STREAM) {
369 hr = DMUSIC_CreateDirectMusicLoaderGenericStream ((LPVOID*)&pStream);
371 ERR(": could not create generic stream\n");
372 return DMUS_E_LOADER_FAILEDOPEN;
375 hr = IDirectMusicLoaderGenericStream_Attach (pStream, pDesc->pStream, iface);
377 ERR(": could not attach stream\n");
378 IStream_Release (pStream);
379 return DMUS_E_LOADER_FAILEDOPEN;
382 else if (pDesc->dwValidData & DMUS_OBJ_MEMORY) {
384 hr = DMUSIC_CreateDirectMusicLoaderResourceStream ((LPVOID*)&pStream);
386 ERR(": could not create resource stream\n");
387 return DMUS_E_LOADER_FAILEDOPEN;
390 hr = IDirectMusicLoaderResourceStream_Attach (pStream, pDesc->pbMemData, pDesc->llMemLength, 0, iface);
392 ERR(": could not attach stream to resource\n");
393 IStream_Release (pStream);
394 return DMUS_E_LOADER_FAILEDOPEN;
398 ERR(": no way to get additional info\n");
399 return DMUS_E_LOADER_FAILEDOPEN;
403 CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject);
405 /* *sigh*... some ms objects have lousy implementation of ParseDescriptor that clears input descriptor :( */
406 #ifdef NOW_WE_ARE_FREE
407 /* parse descriptor: we actually use input descriptor; fields that aren't available from stream remain,
408 otherwise real info is set */
409 IDirectMusicObject_ParseDescriptor (pObject, pStream, pDesc);
411 /* hmph... due to some trouble I had with certain tests, we store current position and then set it back */
412 DM_STRUCT_INIT(&Desc);
413 if (FAILED(IDirectMusicObject_ParseDescriptor (pObject, pStream, &Desc))) {
414 ERR(": couldn't parse descriptor\n");
415 return DMUS_E_LOADER_FORMATNOTSUPPORTED;
418 /* copy elements from parsed descriptor into input descriptor; this sets new info, overwriting if necessary,
419 but leaves info that's provided by input and not available from stream */
420 DMUSIC_CopyDescriptor (pDesc, &Desc);
422 /* release everything */
423 IDirectMusicObject_Release (pObject);
424 IStream_Release (pStream);
426 /* sometimes it happens that twisted programs call SetObject for same object twice...
427 in such cases, native loader returns S_OK and does nothing... a sound plan */
428 LIST_FOR_EACH (pEntry, This->pObjects) {
429 pObjectEntry = LIST_ENTRY (pEntry, WINE_LOADER_ENTRY, entry);
430 if (!memcmp (&pObjectEntry->Desc, pDesc, sizeof(DMUS_OBJECTDESC))) {
431 TRACE(": exacly same entry already exists\n");
437 TRACE(": adding alias entry with following info: \n%s\n", debugstr_DMUS_OBJECTDESC(pDesc));
438 pNewEntry = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(WINE_LOADER_ENTRY));
439 /* use this function instead of pure memcpy due to streams (memcpy just copies pointer),
440 which is basically used further by app that called SetDescriptor... better safety than exception */
441 DMUSIC_CopyDescriptor (&pNewEntry->Desc, pDesc);
442 list_add_head (This->pObjects, &pNewEntry->entry);
447 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_SetSearchDirectory (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, WCHAR* pwzPath, BOOL fClear) {
448 WCHAR wszCurrentPath[MAX_PATH];
449 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
450 TRACE("(%p, %s, %s, %d)\n", This, debugstr_dmguid(rguidClass), debugstr_w(pwzPath), fClear);
451 FIXME(": fClear ignored\n");
452 DMUSIC_GetLoaderSettings (iface, rguidClass, wszCurrentPath, NULL);
453 if (!strncmpW(wszCurrentPath, pwzPath, MAX_PATH)) {
456 /* FIXME: check if path is valid; else return DMUS_E_LOADER_BADPATH */
457 return DMUSIC_SetLoaderSettings (iface, rguidClass, pwzPath, NULL);
460 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ScanDirectory (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, WCHAR* pwzFileExtension, WCHAR* pwzScanFileName) {
461 static const WCHAR wszAny[] = {'*',0};
462 WIN32_FIND_DATAW FileData;
464 WCHAR wszSearchString[MAX_PATH];
467 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
468 TRACE("(%p, %s, %p, %p)\n", This, debugstr_dmguid(rguidClass), pwzFileExtension, pwzScanFileName);
469 if (IsEqualGUID (rguidClass, &GUID_DirectMusicAllTypes) || !DMUSIC_IsValidLoadableClass(rguidClass)) {
470 ERR(": rguidClass invalid CLSID\n");
471 return REGDB_E_CLASSNOTREG;
474 /* get search path for given class */
475 DMUSIC_GetLoaderSettings (iface, rguidClass, wszSearchString, NULL);
477 p = wszSearchString + lstrlenW(wszSearchString);
478 if (p > wszSearchString && p[-1] != '\\') *p++ = '\\';
479 *p++ = '*'; /* any file */
480 if (strcmpW (pwzFileExtension, wszAny)) *p++ = '.'; /* if we have actual extension, put a dot */
481 strcpyW (p, pwzFileExtension);
483 TRACE(": search string: %s\n", debugstr_w(wszSearchString));
485 hSearch = FindFirstFileW (wszSearchString, &FileData);
486 if (hSearch == INVALID_HANDLE_VALUE) {
487 TRACE(": no files found\n");
492 DMUS_OBJECTDESC Desc;
493 DM_STRUCT_INIT(&Desc);
494 Desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_DATE;
495 memcpy (&Desc.guidClass, rguidClass, sizeof(GUID));
496 strcpyW (Desc.wszFileName, FileData.cFileName);
497 FileTimeToLocalFileTime (&FileData.ftCreationTime, &Desc.ftDate);
498 IDirectMusicLoader8_SetObject (iface, &Desc);
500 if (!FindNextFileW (hSearch, &FileData)) {
501 if (GetLastError () == ERROR_NO_MORE_FILES) {
502 TRACE(": search completed\n");
505 ERR(": could not get next file\n");
514 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_CacheObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject) {
515 DMUS_OBJECTDESC Desc;
516 HRESULT result = DMUS_E_LOADER_OBJECTNOTFOUND;
518 LPWINE_LOADER_ENTRY pObjectEntry = NULL;
520 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
521 TRACE("(%p, %p)\n", This, pObject);
524 DM_STRUCT_INIT(&Desc);
525 IDirectMusicObject_GetDescriptor (pObject, &Desc);
527 /* now iterate thru list and check if we have alias (without object), corresponding
528 to descriptor of input object */
529 LIST_FOR_EACH(pEntry, This->pObjects) {
530 pObjectEntry = LIST_ENTRY(pEntry, WINE_LOADER_ENTRY, entry);
531 if ((Desc.dwValidData & DMUS_OBJ_OBJECT) &&
532 (pObjectEntry->Desc.dwValidData & DMUS_OBJ_OBJECT) &&
533 IsEqualGUID (&Desc.guidObject, &pObjectEntry->Desc.guidObject)) {
534 TRACE(": found it by object GUID\n");
535 if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject)
541 else if ((Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) &&
542 (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) &&
543 !strncmpW (Desc.wszFileName, pObjectEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) {
544 TRACE(": found it by fullpath filename\n");
545 if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject)
551 else if ((Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) &&
552 (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) &&
553 !strncmpW (Desc.wszName, pObjectEntry->Desc.wszName, DMUS_MAX_NAME) &&
554 !strncmpW (Desc.wszCategory, pObjectEntry->Desc.wszCategory, DMUS_MAX_CATEGORY)) {
555 TRACE(": found it by name and category\n");
556 if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject)
562 else if ((Desc.dwValidData & DMUS_OBJ_NAME) &&
563 (pObjectEntry->Desc.dwValidData & DMUS_OBJ_NAME) &&
564 !strncmpW (Desc.wszName, pObjectEntry->Desc.wszName, DMUS_MAX_NAME)) {
565 TRACE(": found it by name\n");
566 if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject)
572 else if ((Desc.dwValidData & DMUS_OBJ_FILENAME) &&
573 (pObjectEntry->Desc.dwValidData & DMUS_OBJ_FILENAME) &&
574 !strncmpW (Desc.wszFileName, pObjectEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) {
575 TRACE(": found it by filename\n");
576 if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject)
584 /* if we found such alias, then set everything */
585 if (result == S_OK) {
586 pObjectEntry->Desc.dwValidData &= DMUS_OBJ_LOADED;
587 pObjectEntry->pObject = pObject;
588 IDirectMusicObject_AddRef (pObjectEntry->pObject);
594 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ReleaseObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject) {
595 DMUS_OBJECTDESC Desc;
597 LPWINE_LOADER_ENTRY pObjectEntry = NULL;
598 HRESULT result = S_FALSE;
600 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
601 TRACE("(%p, %p)\n", This, pObject);
604 DM_STRUCT_INIT(&Desc);
605 IDirectMusicObject_GetDescriptor (pObject, &Desc);
607 /* iterate thru the list of objects we know about; check only those with DMUS_OBJ_LOADED */
608 TRACE(": looking for the object in cache\n");
609 LIST_FOR_EACH(pEntry, This->pObjects) {
610 pObjectEntry = LIST_ENTRY(pEntry, WINE_LOADER_ENTRY, entry);
611 if ((Desc.dwValidData & DMUS_OBJ_OBJECT) &&
612 (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_OBJECT | DMUS_OBJ_LOADED)) &&
613 IsEqualGUID (&Desc.guidObject, &pObjectEntry->Desc.guidObject)) {
614 TRACE(": found it by object GUID\n%s\n", debugstr_DMUS_OBJECTDESC(&pObjectEntry->Desc));
618 else if ((Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) &&
619 (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_LOADED)) &&
620 !strncmpW (Desc.wszFileName, pObjectEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) {
621 TRACE(": found it by fullpath filename\n");
625 else if ((Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) &&
626 (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY | DMUS_OBJ_LOADED)) &&
627 !strncmpW (Desc.wszName, pObjectEntry->Desc.wszName, DMUS_MAX_NAME) &&
628 !strncmpW (Desc.wszCategory, pObjectEntry->Desc.wszCategory, DMUS_MAX_CATEGORY)) {
629 TRACE(": found it by name and category\n");
633 else if ((Desc.dwValidData & DMUS_OBJ_NAME) &&
634 (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_LOADED)) &&
635 !strncmpW (Desc.wszName, pObjectEntry->Desc.wszName, DMUS_MAX_NAME)) {
636 TRACE(": found it by name\n");
640 else if ((Desc.dwValidData & DMUS_OBJ_FILENAME) &&
641 (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_LOADED)) &&
642 !strncmpW (Desc.wszFileName, pObjectEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) {
643 TRACE(": found it by filename\n");
648 if (result == S_OK) {
649 /*TRACE(": releasing: \n%s - bInvalidDefaultDLS = %i\n - pObject = %p\n", debugstr_DMUS_OBJECTDESC(&pObjectEntry->Desc), pObjectEntry->bInvalidDefaultDLS, pObjectEntry->pObject); */
650 IDirectMusicObject_Release (pObjectEntry->pObject);
651 pObjectEntry->pObject = NULL;
652 pObjectEntry->Desc.dwValidData &= ~DMUS_OBJ_LOADED;
657 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ClearCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass) {
659 LPWINE_LOADER_ENTRY pObjectEntry;
660 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
661 TRACE("(%p, %s)\n", This, debugstr_dmguid(rguidClass));
663 LIST_FOR_EACH (pEntry, This->pObjects) {
664 pObjectEntry = LIST_ENTRY (pEntry, WINE_LOADER_ENTRY, entry);
666 if ((IsEqualGUID (rguidClass, &GUID_DirectMusicAllTypes) || IsEqualGUID (rguidClass, &pObjectEntry->Desc.guidClass)) &&
667 (pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED)) {
668 /* basically, wrap to ReleaseObject for each object found */
669 IDirectMusicLoader8_ReleaseObject (iface, pObjectEntry->pObject);
676 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_EnableCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, BOOL fEnable) {
677 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
679 TRACE("(%p, %s, %d)\n", This, debugstr_dmguid(rguidClass), fEnable);
680 DMUSIC_GetLoaderSettings (iface, rguidClass, NULL, &bCurrent);
681 if (bCurrent == fEnable)
684 return DMUSIC_SetLoaderSettings (iface, rguidClass, NULL, &fEnable);
687 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_EnumObject (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, DWORD dwIndex, LPDMUS_OBJECTDESC pDesc) {
690 LPWINE_LOADER_ENTRY pObjectEntry;
691 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
692 TRACE("(%p, %s, %d, %p)\n", This, debugstr_dmguid(rguidClass), dwIndex, pDesc);
694 DM_STRUCT_INIT(pDesc);
696 LIST_FOR_EACH (pEntry, This->pObjects) {
697 pObjectEntry = LIST_ENTRY (pEntry, WINE_LOADER_ENTRY, entry);
699 if (IsEqualGUID (rguidClass, &GUID_DirectMusicAllTypes) || IsEqualGUID (rguidClass, &pObjectEntry->Desc.guidClass)) {
700 if (dwCount == dwIndex) {
701 memcpy (pDesc, &pObjectEntry->Desc, sizeof(DMUS_OBJECTDESC));
702 /* we aren't supposed to reveal this info */
703 pDesc->dwValidData &= ~(DMUS_OBJ_MEMORY | DMUS_OBJ_STREAM);
704 pDesc->pbMemData = NULL;
705 pDesc->llMemLength = 0;
706 pDesc->pStream = NULL;
713 TRACE(": not found\n");
717 static void WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_CollectGarbage (LPDIRECTMUSICLOADER8 iface) {
718 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
719 FIXME("(%p): stub\n", This);
722 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ReleaseObjectByUnknown (LPDIRECTMUSICLOADER8 iface, IUnknown* pObject) {
723 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
725 LPDIRECTMUSICOBJECT pObjectInterface;
727 TRACE("(%p, %p)\n", This, pObject);
729 if (IsBadReadPtr (pObject, sizeof(LPUNKNOWN))) {
730 ERR(": pObject bad write pointer\n");
733 /* we simply get IDirectMusicObject interface */
734 result = IUnknown_QueryInterface (pObject, &IID_IDirectMusicObject, (LPVOID*)&pObjectInterface);
735 if (FAILED(result)) return result;
736 /* and release it in old-fashioned way */
737 result = IDirectMusicLoader8_ReleaseObject (iface, pObjectInterface);
738 IDirectMusicObject_Release (pObjectInterface);
743 static HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_LoadObjectFromFile (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClassID, REFIID iidInterfaceID, WCHAR* pwzFilePath, void** ppObject) {
744 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
745 DMUS_OBJECTDESC ObjDesc;
746 WCHAR wszLoaderSearchPath[MAX_PATH];
748 TRACE("(%p, %s, %s, %s, %p): wrapping to IDirectMusicLoaderImpl_GetObject\n", This, debugstr_dmguid(rguidClassID), debugstr_dmguid(iidInterfaceID), debugstr_w(pwzFilePath), ppObject);
750 DM_STRUCT_INIT(&ObjDesc);
751 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 */
752 memcpy (&ObjDesc.guidClass, rguidClassID, sizeof(CLSID));
753 /* OK, MSDN says that search order is the following:
754 - current directory (DONE)
755 - windows search path (FIXME: how do I get that?)
756 - loader's search path (DONE)
758 DMUSIC_GetLoaderSettings (iface, rguidClassID, wszLoaderSearchPath, NULL);
759 /* search in current directory */
760 if (!SearchPathW (NULL, pwzFilePath, NULL, sizeof(ObjDesc.wszFileName)/sizeof(WCHAR), ObjDesc.wszFileName, NULL) &&
761 /* search in loader's search path */
762 !SearchPathW (wszLoaderSearchPath, pwzFilePath, NULL, sizeof(ObjDesc.wszFileName)/sizeof(WCHAR), ObjDesc.wszFileName, NULL)) {
763 /* cannot find file */
764 TRACE(": cannot find file\n");
765 return DMUS_E_LOADER_FAILEDOPEN;
768 TRACE(": full file path = %s\n", debugstr_w (ObjDesc.wszFileName));
770 return IDirectMusicLoaderImpl_IDirectMusicLoader_GetObject (iface, &ObjDesc, iidInterfaceID, ppObject);
773 static const IDirectMusicLoader8Vtbl DirectMusicLoader_Loader_Vtbl = {
774 IDirectMusicLoaderImpl_IDirectMusicLoader_QueryInterface,
775 IDirectMusicLoaderImpl_IDirectMusicLoader_AddRef,
776 IDirectMusicLoaderImpl_IDirectMusicLoader_Release,
777 IDirectMusicLoaderImpl_IDirectMusicLoader_GetObject,
778 IDirectMusicLoaderImpl_IDirectMusicLoader_SetObject,
779 IDirectMusicLoaderImpl_IDirectMusicLoader_SetSearchDirectory,
780 IDirectMusicLoaderImpl_IDirectMusicLoader_ScanDirectory,
781 IDirectMusicLoaderImpl_IDirectMusicLoader_CacheObject,
782 IDirectMusicLoaderImpl_IDirectMusicLoader_ReleaseObject,
783 IDirectMusicLoaderImpl_IDirectMusicLoader_ClearCache,
784 IDirectMusicLoaderImpl_IDirectMusicLoader_EnableCache,
785 IDirectMusicLoaderImpl_IDirectMusicLoader_EnumObject,
786 IDirectMusicLoaderImpl_IDirectMusicLoader_CollectGarbage,
787 IDirectMusicLoaderImpl_IDirectMusicLoader_ReleaseObjectByUnknown,
788 IDirectMusicLoaderImpl_IDirectMusicLoader_LoadObjectFromFile
791 /* for ClassFactory */
792 HRESULT WINAPI DMUSIC_CreateDirectMusicLoaderImpl (LPCGUID lpcGUID, LPVOID *ppobj, LPUNKNOWN pUnkOuter) {
793 IDirectMusicLoaderImpl *obj;
794 DMUS_OBJECTDESC Desc;
795 LPWINE_LOADER_ENTRY pDefaultDLSEntry;
798 TRACE("(%s, %p, %p)\n", debugstr_dmguid(lpcGUID), ppobj, pUnkOuter);
799 obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoaderImpl));
801 *ppobj = (LPDIRECTMUSICLOADER8)NULL;
802 return E_OUTOFMEMORY;
804 obj->LoaderVtbl = &DirectMusicLoader_Loader_Vtbl;
805 obj->dwRef = 0; /* will be inited with QueryInterface */
806 /* init critical section */
807 /* init cache/alias list */
808 /*InitializeCriticalSection (&obj->CritSect);
809 obj->CritSect.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectMusicLoaderImpl.CritSect"); */
810 obj->pObjects = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(struct list));
811 list_init (obj->pObjects);
813 obj->pClassSettings = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(struct list));
814 list_init (obj->pClassSettings);
815 DMUSIC_InitLoaderSettings ((LPDIRECTMUSICLOADER8)obj);
817 /* set default DLS collection (via SetObject... so that loading via DMUS_OBJ_OBJECT is possible) */
818 DM_STRUCT_INIT(&Desc);
819 Desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_OBJECT;
820 memcpy (&Desc.guidClass, &CLSID_DirectMusicCollection, sizeof(CLSID));
821 memcpy (&Desc.guidObject, &GUID_DefaultGMCollection, sizeof(GUID));
822 DMUSIC_GetDefaultGMPath (Desc.wszFileName);
823 IDirectMusicLoader_SetObject ((LPDIRECTMUSICLOADER8)obj, &Desc);
824 /* and now the workaroundTM for "invalid" default DLS; basically,
825 my tests showed that if GUID chunk is present in default DLS
826 collection, loader treats it as "invalid" and returns
827 DMUS_E_LOADER_NOFILENAME for all requests for it; basically, we check
828 if out input guidObject was overwritten */
829 pEntry = list_head (obj->pObjects);
830 pDefaultDLSEntry = LIST_ENTRY (pEntry, WINE_LOADER_ENTRY, entry);
831 if (!IsEqualGUID(&Desc.guidObject, &GUID_DefaultGMCollection)) {
832 pDefaultDLSEntry->bInvalidDefaultDLS = TRUE;
835 /* increase number of instances */
836 InterlockedIncrement (&dwDirectMusicLoader);
838 return IDirectMusicLoaderImpl_IDirectMusicLoader_QueryInterface ((LPDIRECTMUSICLOADER8)obj, lpcGUID, ppobj);
841 HRESULT WINAPI DMUSIC_DestroyDirectMusicLoaderImpl (LPDIRECTMUSICLOADER8 iface) {
842 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
844 TRACE("(%p)\n", This);
846 /* firstly, release the cache */
847 IDirectMusicLoader8_ClearCache (iface, &GUID_DirectMusicAllTypes);
848 /* FIXME: release all allocated entries */
849 /* destroy critical section */
850 /*This->CritSect.DebugInfo->Spare[0] = 0;
851 DeleteCriticalSection (&This->CritSect); */
853 /* decrease number of instances */
854 InterlockedDecrement (&dwDirectMusicLoader);
859 /* help function for DMUSIC_SetDefaultDLS */
860 HRESULT WINAPI DMUSIC_GetDefaultGMPath (WCHAR wszPath[MAX_PATH]) {
862 DWORD returnType, sizeOfReturnBuffer = MAX_PATH;
863 char szPath[MAX_PATH];
865 if ((RegOpenKeyExA (HKEY_LOCAL_MACHINE, "Software\\Microsoft\\DirectMusic" , 0, KEY_READ, &hkDM) != ERROR_SUCCESS) ||
866 (RegQueryValueExA (hkDM, "GMFilePath", NULL, &returnType, (LPBYTE) szPath, &sizeOfReturnBuffer) != ERROR_SUCCESS)) {
867 WARN(": registry entry missing\n" );
870 /* FIXME: Check return types to ensure we're interpreting data right */
871 MultiByteToWideChar (CP_ACP, 0, szPath, -1, wszPath, MAX_PATH);
876 /* help function for retrieval of search path and caching option for certain class */
877 HRESULT WINAPI DMUSIC_GetLoaderSettings (LPDIRECTMUSICLOADER8 iface, REFGUID pClassID, WCHAR* wszSearchPath, LPBOOL pbCache) {
878 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
880 TRACE(": (%p, %s, %p, %p)\n", This, debugstr_dmguid(pClassID), wszSearchPath, pbCache);
882 LIST_FOR_EACH(pEntry, This->pClassSettings) {
883 LPWINE_LOADER_OPTION pOptionEntry = LIST_ENTRY(pEntry, WINE_LOADER_OPTION, entry);
884 if (IsEqualCLSID (pClassID, &pOptionEntry->guidClass)) {
886 strcpyW(wszSearchPath, pOptionEntry->wszSearchPath);
888 *pbCache = pOptionEntry->bCache;
895 /* help function for setting search path and caching option for certain class */
896 static HRESULT WINAPI DMUSIC_SetLoaderSettings (LPDIRECTMUSICLOADER8 iface, REFGUID pClassID, WCHAR* wszSearchPath, LPBOOL pbCache) {
897 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
899 HRESULT result = S_FALSE; /* in case pClassID != GUID_DirectMusicAllTypes and not a valid CLSID */
900 TRACE(": (%p, %s, %p, %p)\n", This, debugstr_dmguid(pClassID), wszSearchPath, pbCache);
902 LIST_FOR_EACH(pEntry, This->pClassSettings) {
903 LPWINE_LOADER_OPTION pOptionEntry = LIST_ENTRY(pEntry, WINE_LOADER_OPTION, entry);
904 /* well, either we have GUID_DirectMusicAllTypes and need to set it to all,
905 or specific CLSID is given and we set it only to it */
906 if (IsEqualGUID (pClassID, &GUID_DirectMusicAllTypes) ||
907 IsEqualCLSID (pClassID, &pOptionEntry->guidClass)) {
909 strcpyW(pOptionEntry->wszSearchPath, wszSearchPath);
911 pOptionEntry->bCache = *pbCache;
919 HRESULT WINAPI DMUSIC_InitLoaderSettings (LPDIRECTMUSICLOADER8 iface) {
920 ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
922 /* hard-coded list of classes */
923 static REFCLSID classes[] = {
924 &CLSID_DirectMusicAudioPathConfig,
925 &CLSID_DirectMusicBand,
926 &CLSID_DirectMusicContainer,
927 &CLSID_DirectMusicCollection,
928 &CLSID_DirectMusicChordMap,
929 &CLSID_DirectMusicSegment,
930 &CLSID_DirectMusicScript,
931 &CLSID_DirectMusicSong,
932 &CLSID_DirectMusicStyle,
933 &CLSID_DirectMusicGraph,
934 &CLSID_DirectSoundWave
938 WCHAR wszCurrent[MAX_PATH];
940 TRACE(": (%p)\n", This);
941 GetCurrentDirectoryW (MAX_PATH, wszCurrent);
943 for (i = 0; i < sizeof(classes)/sizeof(REFCLSID); i++) {
944 LPWINE_LOADER_OPTION pNewSetting = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(WINE_LOADER_OPTION));
945 memcpy (&pNewSetting->guidClass, classes[i], sizeof(CLSID));
946 strcpyW (pNewSetting->wszSearchPath, wszCurrent);
947 pNewSetting->bCache = TRUE;
948 list_add_tail (This->pClassSettings, &pNewSetting->entry);
954 HRESULT WINAPI DMUSIC_CopyDescriptor (LPDMUS_OBJECTDESC pDst, LPDMUS_OBJECTDESC pSrc) {
955 TRACE(": copy \n%s", debugstr_DMUS_OBJECTDESC(pSrc));
956 /* copy field by field */
957 if (pSrc->dwValidData & DMUS_OBJ_CLASS) memcpy (&pDst->guidClass, &pSrc->guidClass, sizeof(CLSID));
958 if (pSrc->dwValidData & DMUS_OBJ_OBJECT) memcpy (&pDst->guidObject, &pSrc->guidObject, sizeof(GUID));
959 if (pSrc->dwValidData & DMUS_OBJ_DATE) memcpy (&pDst->ftDate, &pSrc->ftDate, sizeof(FILETIME));
960 if (pSrc->dwValidData & DMUS_OBJ_VERSION) memcpy (&pDst->vVersion, &pSrc->vVersion, sizeof(DMUS_VERSION));
961 if (pSrc->dwValidData & DMUS_OBJ_NAME) strcpyW (pDst->wszName, pSrc->wszName);
962 if (pSrc->dwValidData & DMUS_OBJ_CATEGORY) strcpyW (pDst->wszCategory, pSrc->wszCategory);
963 if (pSrc->dwValidData & DMUS_OBJ_FILENAME) strcpyW (pDst->wszFileName, pSrc->wszFileName);
964 if (pSrc->dwValidData & DMUS_OBJ_STREAM) IStream_Clone (pSrc->pStream, &pDst->pStream);
965 if (pSrc->dwValidData & DMUS_OBJ_MEMORY) {
966 pDst->pbMemData = pSrc->pbMemData;
967 pDst->llMemLength = pSrc->llMemLength;
970 pDst->dwValidData |= pSrc->dwValidData;
974 BOOL WINAPI DMUSIC_IsValidLoadableClass (REFCLSID pClassID) {
975 if (IsEqualCLSID(pClassID, &CLSID_DirectMusicAudioPathConfig) ||
976 IsEqualCLSID(pClassID, &CLSID_DirectMusicBand) ||
977 IsEqualCLSID(pClassID, &CLSID_DirectMusicContainer) ||
978 IsEqualCLSID(pClassID, &CLSID_DirectMusicCollection) ||
979 IsEqualCLSID(pClassID, &CLSID_DirectMusicChordMap) ||
980 IsEqualCLSID(pClassID, &CLSID_DirectMusicSegment) ||
981 IsEqualCLSID(pClassID, &CLSID_DirectMusicScript) ||
982 IsEqualCLSID(pClassID, &CLSID_DirectMusicSong) ||
983 IsEqualCLSID(pClassID, &CLSID_DirectMusicStyle) ||
984 IsEqualCLSID(pClassID, &CLSID_DirectMusicGraph) ||
985 IsEqualCLSID(pClassID, &CLSID_DirectSoundWave) ||
986 IsEqualCLSID(pClassID, &GUID_DirectMusicAllTypes))