1 /* IDirectMusicLoader8 Implementation
3 * Copyright (C) 2003-2004 Rok Mandeljc
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (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
13 * GNU Library General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #include "dmloader_private.h"
22 WINE_DEFAULT_DEBUG_CHANNEL(dmloader);
24 HRESULT WINAPI DMUSIC_GetDefaultGMPath (WCHAR wszPath[MAX_PATH]);
26 /* IDirectMusicLoader8 IUnknown part: */
27 HRESULT WINAPI IDirectMusicLoader8Impl_QueryInterface (LPDIRECTMUSICLOADER8 iface, REFIID riid, LPVOID *ppobj) {
28 ICOM_THIS(IDirectMusicLoader8Impl,iface);
30 if (IsEqualIID (riid, &IID_IUnknown) ||
31 IsEqualIID (riid, &IID_IDirectMusicLoader) ||
32 IsEqualIID (riid, &IID_IDirectMusicLoader8)) {
33 IDirectMusicLoader8Impl_AddRef(iface);
38 WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
42 ULONG WINAPI IDirectMusicLoader8Impl_AddRef (LPDIRECTMUSICLOADER8 iface) {
43 ICOM_THIS(IDirectMusicLoader8Impl,iface);
44 TRACE("(%p) : AddRef from %ld\n", This, This->ref);
48 ULONG WINAPI IDirectMusicLoader8Impl_Release (LPDIRECTMUSICLOADER8 iface) {
49 ICOM_THIS(IDirectMusicLoader8Impl,iface);
50 ULONG ref = --This->ref;
51 TRACE("(%p) : ReleaseRef to %ld\n", This, This->ref);
53 HeapFree(GetProcessHeap(), 0, This);
58 /* IDirectMusicLoader8 IDirectMusicLoader part: */
59 HRESULT WINAPI IDirectMusicLoader8Impl_GetObject (LPDIRECTMUSICLOADER8 iface, LPDMUS_OBJECTDESC pDesc, REFIID riid, LPVOID* ppv) {
60 ICOM_THIS(IDirectMusicLoader8Impl,iface);
62 struct list *listEntry;
63 LPDMUS_PRIVATE_ALIAS_ENTRY aliasEntry;
64 DMUS_PRIVATE_CACHE_ENTRY *cacheEntry;
65 DMUS_OBJECTDESC CacheDesc;
66 IDirectMusicObject* pObject;
67 LPDMUS_PRIVATE_CACHE_ENTRY newEntry;
69 TRACE("(%p, %p, %s, %p): pDesc:\n", This, pDesc, debugstr_guid(riid), ppv);
70 if (TRACE_ON(dmloader))
71 DMUSIC_dump_DMUS_OBJECTDESC(pDesc);
73 /* if I understand correctly, SetObject makes sort of aliases for entries in cache;
74 therefore I created alias list, which is similiar to cache list, and is used as resolver
75 (it maps let's say GUID to filename) */
76 TRACE(": looking for alias\n");
77 LIST_FOR_EACH (listEntry, &This->AliasList) {
78 aliasEntry = LIST_ENTRY(listEntry, DMUS_PRIVATE_ALIAS_ENTRY, entry);
79 /* for the time being, we support only GUID/name mapping */
80 if ((aliasEntry->pDesc->dwValidData & DMUS_OBJ_OBJECT) && (pDesc->dwValidData & DMUS_OBJ_OBJECT)
81 && IsEqualGUID (&aliasEntry->pDesc->guidObject, &pDesc->guidObject)) {
82 TRACE(": found alias by GUID (%s)... mapping:\n", debugstr_guid(&aliasEntry->pDesc->guidObject));
83 if ((aliasEntry->pDesc->dwValidData & DMUS_OBJ_FILENAME) && !(pDesc->dwValidData & DMUS_OBJ_FILENAME)) {
84 TRACE(": - to filename (%s)\n", debugstr_w(aliasEntry->pDesc->wszFileName));
85 pDesc->dwValidData |= DMUS_OBJ_FILENAME;
86 pDesc->dwValidData |= (aliasEntry->pDesc->dwValidData & DMUS_OBJ_FULLPATH);
87 strncpyW (pDesc->wszFileName, aliasEntry->pDesc->wszFileName, DMUS_MAX_FILENAME);
89 if ((aliasEntry->pDesc->dwValidData & DMUS_OBJ_NAME) && !(pDesc->dwValidData & DMUS_OBJ_NAME)) {
90 TRACE(": - to name (%s)\n", debugstr_w(aliasEntry->pDesc->wszName));
91 pDesc->dwValidData |= DMUS_OBJ_NAME;
92 strncpyW (pDesc->wszName, aliasEntry->pDesc->wszName, DMUS_MAX_NAME);
94 if ((aliasEntry->pDesc->dwValidData & DMUS_OBJ_MEMORY) && !(pDesc->dwValidData & DMUS_OBJ_MEMORY)) {
95 TRACE(": - to memory location\n");
96 pDesc->dwValidData |= DMUS_OBJ_MEMORY;
97 /* FIXME: is this correct? */
98 pDesc->pbMemData = aliasEntry->pDesc->pbMemData;
99 pDesc->llMemLength = aliasEntry->pDesc->llMemLength;
101 if ((aliasEntry->pDesc->dwValidData & DMUS_OBJ_STREAM) && !(pDesc->dwValidData & DMUS_OBJ_STREAM)) {
102 TRACE(": - to stream\n");
103 pDesc->dwValidData |= DMUS_OBJ_STREAM;
104 IStream_Clone (aliasEntry->pDesc->pStream, &pDesc->pStream);
107 else if ((aliasEntry->pDesc->dwValidData & DMUS_OBJ_NAME) && (pDesc->dwValidData & DMUS_OBJ_NAME)
108 && !strncmpW (aliasEntry->pDesc->wszName, pDesc->wszName, DMUS_MAX_NAME)) {
109 TRACE(": found alias by name (%s)... mapping:\n", debugstr_w(aliasEntry->pDesc->wszName));
110 if ((aliasEntry->pDesc->dwValidData & DMUS_OBJ_FILENAME) && !(pDesc->dwValidData & DMUS_OBJ_FILENAME)) {
111 TRACE(": - to filename (%s)\n", debugstr_w(aliasEntry->pDesc->wszFileName));
112 pDesc->dwValidData |= DMUS_OBJ_FILENAME;
113 pDesc->dwValidData |= (aliasEntry->pDesc->dwValidData & DMUS_OBJ_FULLPATH);
114 strncpyW (pDesc->wszFileName, aliasEntry->pDesc->wszFileName, DMUS_MAX_FILENAME);
116 if ((aliasEntry->pDesc->dwValidData & DMUS_OBJ_OBJECT) && !(pDesc->dwValidData & DMUS_OBJ_OBJECT)) {
117 TRACE(": - to object GUID (%s)\n", debugstr_guid(&aliasEntry->pDesc->guidObject));
118 pDesc->dwValidData |= DMUS_OBJ_OBJECT;
119 memcpy (&pDesc->guidObject, &aliasEntry->pDesc->guidObject, sizeof(GUID));
121 if ((aliasEntry->pDesc->dwValidData & DMUS_OBJ_MEMORY) && !(pDesc->dwValidData & DMUS_OBJ_MEMORY)) {
122 TRACE(": - to memory location\n");
123 pDesc->dwValidData |= DMUS_OBJ_MEMORY;
124 /* FIXME: is this correct? */
125 pDesc->pbMemData = aliasEntry->pDesc->pbMemData;
126 pDesc->llMemLength = aliasEntry->pDesc->llMemLength;
128 if ((aliasEntry->pDesc->dwValidData & DMUS_OBJ_STREAM) && !(pDesc->dwValidData & DMUS_OBJ_STREAM)) {
129 TRACE(": - to stream\n");
130 pDesc->dwValidData |= DMUS_OBJ_STREAM;
131 IStream_Clone (aliasEntry->pDesc->pStream, &pDesc->pStream);
134 /*else FIXME(": implement other types of mapping\n"); */
137 /* iterate through cache and check whether object has already been loaded */
138 TRACE(": looking up cache...\n");
139 DM_STRUCT_INIT(&CacheDesc);
140 LIST_FOR_EACH (listEntry, &This->CacheList) {
141 cacheEntry = LIST_ENTRY(listEntry, DMUS_PRIVATE_CACHE_ENTRY, entry);
142 /* first check whether cached object is "faulty" default dls collection;
143 * I don't think it's recongised by object descriptor, since it contains no
144 * data; it's not very elegant way, but it works :)
146 if (cacheEntry->bIsFaultyDLS == TRUE) {
147 if ((pDesc->dwValidData & DMUS_OBJ_OBJECT) && IsEqualGUID (&GUID_DefaultGMCollection, &pDesc->guidObject)) {
148 TRACE(": found faulty default DLS collection... enabling M$ compliant behaviour\n");
149 return DMUS_E_LOADER_NOFILENAME;
152 /* I think it shouldn't happen that pObject is NULL, but better be safe */
153 if (cacheEntry->pObject) {
154 DM_STRUCT_INIT(&CacheDesc); /* prepare desc for reuse */
155 IDirectMusicObject_GetDescriptor (cacheEntry->pObject, &CacheDesc);
156 /* according to MSDN, search order is:
158 2. DMUS_OBJ_MEMORY (FIXME)
159 3. DMUS_OBJ_FILENAME & DMUS_OBJ_FULLPATH
160 4. DMUS_OBJ_NAME & DMUS_OBJ_CATEGORY
162 6. DMUS_OBJ_FILENAME */
163 if ((pDesc->dwValidData & DMUS_OBJ_OBJECT) && (CacheDesc.dwValidData & DMUS_OBJ_OBJECT)
164 && IsEqualGUID (&pDesc->guidObject, &CacheDesc.guidObject)) {
165 TRACE(": found it by object GUID\n");
166 return IDirectMusicObject_QueryInterface (cacheEntry->pObject, riid, ppv);
168 if ((pDesc->dwValidData & DMUS_OBJ_MEMORY) && (CacheDesc.dwValidData & DMUS_OBJ_MEMORY)) {
169 FIXME(": DMUS_OBJ_MEMORY not supported yet\n");
171 if ((pDesc->dwValidData & DMUS_OBJ_FILENAME) && (pDesc->dwValidData & DMUS_OBJ_FULLPATH)
172 && (CacheDesc.dwValidData & DMUS_OBJ_FILENAME) && (CacheDesc.dwValidData & DMUS_OBJ_FULLPATH)
173 && !strncmpW (pDesc->wszFileName, CacheDesc.wszFileName, DMUS_MAX_FILENAME)) {
174 TRACE(": found it by fullpath filename\n");
175 return IDirectMusicObject_QueryInterface (cacheEntry->pObject, riid, ppv);
177 if ((pDesc->dwValidData & DMUS_OBJ_NAME) && (pDesc->dwValidData & DMUS_OBJ_CATEGORY)
178 && (CacheDesc.dwValidData & DMUS_OBJ_NAME) && (CacheDesc.dwValidData & DMUS_OBJ_CATEGORY)
179 && !strncmpW (pDesc->wszName, CacheDesc.wszName, DMUS_MAX_NAME)
180 && !strncmpW (pDesc->wszCategory, CacheDesc.wszCategory, DMUS_MAX_CATEGORY)) {
181 TRACE(": found it by name and category\n");
182 return IDirectMusicObject_QueryInterface (cacheEntry->pObject, riid, ppv);
184 if ((pDesc->dwValidData & DMUS_OBJ_NAME) && (CacheDesc.dwValidData & DMUS_OBJ_NAME)
185 && !strncmpW (pDesc->wszName, CacheDesc.wszName, DMUS_MAX_NAME)) {
186 TRACE(": found it by name\n");
187 return IDirectMusicObject_QueryInterface (cacheEntry->pObject, riid, ppv);
189 if ((pDesc->dwValidData & DMUS_OBJ_FILENAME) && (CacheDesc.dwValidData & DMUS_OBJ_FILENAME)
190 && !strncmpW (pDesc->wszFileName, CacheDesc.wszFileName, DMUS_MAX_FILENAME)) {
191 TRACE(": found it by filename\n");
192 return IDirectMusicObject_QueryInterface (cacheEntry->pObject, riid, ppv);
197 /* object doesn't exist in cache... guess we'll have to load it */
198 TRACE(": object does not exist in cache\n");
200 /* sometimes it happens that guidClass is missing */
201 if (!(pDesc->dwValidData & DMUS_OBJ_CLASS)) {
202 ERR(": guidClass not valid but needed\n");
204 return DMUS_E_LOADER_NOCLASSID;
207 if (pDesc->dwValidData & DMUS_OBJ_FILENAME) {
208 /* load object from file */
209 /* generate filename; if it's full path, don't add search
210 directory path, otherwise do */
211 WCHAR wzFileName[MAX_PATH];
212 DMUS_OBJECTDESC GotDesc;
214 IPersistStream* pPersistStream = NULL;
216 if (pDesc->dwValidData & DMUS_OBJ_FULLPATH) {
217 lstrcpyW(wzFileName, pDesc->wszFileName);
220 lstrcpyW(wzFileName, This->wzSearchPath);
221 p = wzFileName + lstrlenW(wzFileName);
222 if (p > wzFileName && p[-1] != '\\') *p++ = '\\';
223 strcpyW(p, pDesc->wszFileName);
225 TRACE(": loading from file (%s)\n", debugstr_w(wzFileName));
226 /* create stream and associate it with dls collection file */
227 result = DMUSIC_CreateLoaderStream ((LPVOID*)&pStream);
228 if (FAILED(result)) {
229 ERR(": could not create loader stream\n");
232 result = ILoaderStream_Attach (pStream, wzFileName, (LPDIRECTMUSICLOADER)iface);
233 if (FAILED(result)) {
234 ERR(": could not attach stream to file\n");
238 result = CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject);
239 if (FAILED(result)) {
240 ERR(": could not create object\n");
243 /* acquire PersistStream interface */
244 result = IDirectMusicObject_QueryInterface (pObject, &IID_IPersistStream, (LPVOID*)&pPersistStream);
245 if (FAILED(result)) {
246 ERR("failed to Query\n");
250 result = IPersistStream_Load (pPersistStream, pStream);
251 if (FAILED(result)) {
252 ERR(": failed to load object\n");
256 DM_STRUCT_INIT(&GotDesc);
257 result = IDirectMusicObject_GetDescriptor (pObject, &GotDesc);
258 if (FAILED(result)) {
259 ERR(": failed to get descriptor\n");
262 /* now set the "missing" info (check comment at "Loading default DLS collection") */
263 GotDesc.dwValidData |= (DMUS_OBJ_FILENAME | DMUS_OBJ_LOADED); /* this time only these are missing */
264 strncpyW (GotDesc.wszFileName, pDesc->wszFileName, DMUS_MAX_FILENAME); /* set wszFileName, even if futile */
266 IDirectMusicObject_SetDescriptor (pObject, &GotDesc);
267 /* release all loading related stuff */
268 IStream_Release (pStream);
269 IPersistStream_Release (pPersistStream);
271 else if (pDesc->dwValidData & DMUS_OBJ_STREAM) {
272 LPSTREAM pClonedStream = NULL;
273 IPersistStream* pPersistStream = NULL;
274 DMUS_OBJECTDESC GotDesc;
275 /* load object from stream */
276 TRACE(": loading from stream\n");
277 /* clone stream, given in pDesc */
278 result = IStream_Clone (pDesc->pStream, &pClonedStream);
279 if (FAILED(result)) {
280 ERR(": failed to clone stream\n");
284 result = CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject);
285 if (FAILED(result)) {
286 ERR(": could not create object\n");
289 /* acquire PersistStream interface */
290 result = IDirectMusicObject_QueryInterface (pObject, &IID_IPersistStream, (LPVOID*)&pPersistStream);
291 if (FAILED(result)) {
292 ERR(": could not acquire IPersistStream\n");
296 result = IPersistStream_Load (pPersistStream, pClonedStream);
297 if (FAILED(result)) {
298 ERR(": failed to load object\n");
302 DM_STRUCT_INIT(&GotDesc);
303 result = IDirectMusicObject_GetDescriptor (pObject, &GotDesc);
304 if (FAILED(result)) {
305 ERR(": failed to get descriptor\n");
308 /* now set the "missing" info */
309 GotDesc.dwValidData |= DMUS_OBJ_LOADED; /* only missing data with streams */
311 IDirectMusicObject_SetDescriptor (pObject, &GotDesc);
312 /* release all loading-related stuff */
313 IPersistStream_Release (pPersistStream);
314 IStream_Release (pClonedStream);
316 else if (pDesc->dwValidData & DMUS_OBJ_OBJECT) {
317 /* load object by GUID */
318 TRACE(": loading by GUID (only default DLS supported)\n");
319 if (IsEqualGUID (&pDesc->guidObject, &GUID_DefaultGMCollection)) {
320 /* Loading default DLS collection: *dirty* secret (TM)
321 * By mixing native and builtin loader and collection and
322 * various .dls files, I found out following undocumented
324 * - loader creates two instances of collection object
325 * - it calls ParseDescriptor on first, then releases it
326 * - then it checks returned descriptor; I'm not sure, but
327 * it seems that DMUS_OBJ_OBJECT is not present if DLS
328 * collection is indeed *real* one (gm.dls)
329 * - if above mentioned flag is not set, it creates another
330 * instance and loads it; it also gets descriptor and adds
331 * guidObject and wszFileName (even though this one cannot be
332 * set on native collection, or so it seems)
333 * => it seems to be sort of check whether given 'default
334 * DLS collection' is really one shipped with DX before
335 * actually loading it
338 WCHAR wzFileName[DMUS_MAX_FILENAME];
340 LPSTREAM pProbeStream;
341 IDirectMusicObject *pProbeObject;
342 DMUS_OBJECTDESC ProbeDesc;
343 DMUS_OBJECTDESC GotDesc;
344 IPersistStream *pPersistStream = NULL;
346 /* get the path for default collection */
347 TRACE(": getting default DLS collection path...\n");
348 if (FAILED(DMUSIC_GetDefaultGMPath (wzFileName))) {
349 ERR(": could not get default collection path\n");
352 /* create stream and associate it with dls collection file */
353 TRACE(": creating stream...\n");
354 result = DMUSIC_CreateLoaderStream ((LPVOID*) &pStream);
355 if (FAILED(result)) {
356 ERR(": could not create loader stream\n");
359 TRACE(": attaching stream...\n");
360 result = ILoaderStream_Attach (pStream, wzFileName, (LPDIRECTMUSICLOADER)iface);
361 if (FAILED(result)) {
362 ERR(": could not attach stream to file\n");
365 /* now create a clone of stream for "probe" */
366 TRACE(": cloning stream (for probing)...\n");
367 result = IStream_Clone (pStream, &pProbeStream);
368 if (FAILED(result)) {
369 ERR(": could not clone stream\n");
372 /* create object for "probing" */
373 TRACE(": creating IDirectMusicObject (for probing)...\n");
374 result = CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*) &pProbeObject);
375 if (FAILED(result)) {
376 ERR(": could not create object (for probing)\n");
379 /* get descriptor from stream */
380 TRACE(": parsing descriptor on probe stream...\n");
381 DM_STRUCT_INIT(&ProbeDesc);
382 result = IDirectMusicObject_ParseDescriptor (pProbeObject, pProbeStream, &ProbeDesc);
383 if (FAILED(result)) {
384 ERR(": could not parse descriptor\n");
387 /* release all probing-related stuff */
388 TRACE(": releasing probing-related stuff...\n");
389 IStream_Release (pProbeStream);
390 IDirectMusicObject_Release (pProbeObject);
391 /* now, if it happens by any chance that dls collection isn't *the one*
392 * TODO: - check if the way below is the appropriate one
394 if (ProbeDesc.dwValidData & DMUS_OBJ_OBJECT) {
395 LPDMUS_PRIVATE_CACHE_ENTRY newEntry;
396 WARN(": the default DLS collection is not the one shipped with DX\n");
397 /* my tests show that we return pointer to something or NULL, depending on + how
398 * input object was defined (therefore we probably don't return anything for object)
399 * and DMUS_E_LOADER_NOFILENAME as error code
400 * (I'd personally rather return DMUS_S_PARTIALLOAD, but I don't set rules)
402 newEntry = (LPDMUS_PRIVATE_CACHE_ENTRY) HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_CACHE_ENTRY));
403 newEntry->pObject = NULL;
404 newEntry->bIsFaultyDLS = TRUE; /* so that cache won't try to get descriptor */
405 list_add_tail (&This->CacheList, &newEntry->entry);
406 TRACE(": filled in cache entry\n");
407 return DMUS_E_LOADER_NOFILENAME;
409 /* now the real loading... create object */
410 TRACE(": creating IDirectMusicObject (for loading)\n");
411 result = CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*) &pObject);
412 if (FAILED(result)) {
413 ERR(": could not create object (for loading)\n");
416 /* acquire PersistStream interface */
417 TRACE(": getting IPersistStream on object...\n");
418 result = IDirectMusicObject_QueryInterface (pObject, &IID_IPersistStream, (LPVOID*) &pPersistStream);
419 if (FAILED(result)) {
420 ERR(": could not acquire IPersistStream\n");
424 TRACE(": loading object..\n");
425 result = IPersistStream_Load (pPersistStream, pStream);
426 if (FAILED(result)) {
427 ERR(": failed to load object\n");
431 TRACE(": getting descriptor of loaded object...\n");
432 DM_STRUCT_INIT(&GotDesc);
433 result = IDirectMusicObject_GetDescriptor (pObject, &GotDesc);
434 if (FAILED(result)) {
435 ERR(": failed to get descriptor\n");
438 /* now set the "missing" info */
439 TRACE(": adding \"missing\" info...\n");
440 GotDesc.dwValidData |= (DMUS_OBJ_OBJECT | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_LOADED);
441 memcpy (&GotDesc.guidObject, &pDesc->guidObject, sizeof(GUID)); /* set guidObject */
442 strncpyW (GotDesc.wszFileName, wzFileName, DMUS_MAX_FILENAME); /* set wszFileName, even if futile */
444 TRACE(": setting descriptor\n");
445 IDirectMusicObject_SetDescriptor (pObject, &GotDesc);
446 /* release all loading related stuff */
447 TRACE(": releasing all loading-related stuff\n");
448 IStream_Release (pStream);
449 IPersistStream_Release (pPersistStream);
454 /* nowhere to load from */
455 FIXME(": unknown/unsupported way of loading\n");
459 /* add object to cache */
460 newEntry = (LPDMUS_PRIVATE_CACHE_ENTRY) HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_CACHE_ENTRY));
462 newEntry->pObject = pObject;
463 newEntry->bIsFaultyDLS = FALSE;
465 list_add_tail (&This->CacheList, &newEntry->entry);
466 TRACE(": filled in cache entry\n");
469 /* for debug purposes (e.g. to check if all files are cached) */
470 TRACE("*** Loader's cache ***\n");
472 LIST_FOR_EACH (listEntry, &This->CacheList) {
474 TRACE("Entry nr. %i:\n", i);
475 cacheEntry = LIST_ENTRY(listEntry, DMUS_PRIVATE_CACHE_ENTRY, entry);
476 if (cacheEntry->bIsFaultyDLS == FALSE) {
477 DM_STRUCT_INIT(&CacheDesc); /* prepare desc for reuse */
478 IDirectMusicObject_GetDescriptor (cacheEntry->pObject, &CacheDesc);
479 DMUSIC_dump_DMUS_OBJECTDESC(&CacheDesc);
481 DPRINTF("faulty DLS collection\n");
486 return IDirectMusicObject_QueryInterface (pObject, riid, ppv);
489 HRESULT WINAPI IDirectMusicLoader8Impl_SetObject (LPDIRECTMUSICLOADER8 iface, LPDMUS_OBJECTDESC pDesc) {
490 ICOM_THIS(IDirectMusicLoader8Impl,iface);
491 DMUS_PRIVATE_ALIAS_ENTRY *newEntry;
492 DMUS_OBJECTDESC Desc;
494 TRACE("(%p, %p): pDesc:\n", This, pDesc);
495 if (TRACE_ON(dmloader))
496 DMUSIC_dump_DMUS_OBJECTDESC(pDesc);
498 /* create stream and load additional info from it */
499 if (pDesc->dwValidData & DMUS_OBJ_FILENAME) {
500 /* generate filename; if it's full path, don't add search
501 directory path, otherwise do */
502 WCHAR wzFileName[MAX_PATH];
504 IDirectMusicObject* pObject;
506 if (pDesc->dwValidData & DMUS_OBJ_FULLPATH) {
507 lstrcpyW(wzFileName, pDesc->wszFileName);
510 lstrcpyW(wzFileName, This->wzSearchPath);
511 p = wzFileName + lstrlenW(wzFileName);
512 if (p > wzFileName && p[-1] != '\\') *p++ = '\\';
513 strcpyW(p, pDesc->wszFileName);
516 DMUSIC_CreateLoaderStream ((LPVOID*) &pStream);
518 ILoaderStream_Attach (pStream, wzFileName, (LPDIRECTMUSICLOADER)iface);
520 CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject);
521 /* parse descriptor */
522 DM_STRUCT_INIT(&Desc);
523 IDirectMusicObject_ParseDescriptor (pObject, pStream, &Desc);
524 /* release everything */
525 IDirectMusicObject_Release (pObject);
526 IStream_Release (pStream);
528 else if (pDesc->dwValidData & DMUS_OBJ_STREAM) {
530 LPSTREAM pStream = NULL;
531 IDirectMusicObject* pObject;
533 IStream_Clone (pDesc->pStream, &pStream);
535 CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject);
536 /* parse descriptor */
537 DM_STRUCT_INIT(&Desc);
538 IDirectMusicObject_ParseDescriptor (pObject, pStream, &Desc);
539 /* release everything */
540 IDirectMusicObject_Release (pObject);
541 IStream_Release (pStream);
544 WARN(": no way to get additional info\n");
547 /* now set additional info... my tests show that existing fields should be overwritten */
548 if (Desc.dwValidData & DMUS_OBJ_OBJECT)
549 memcpy (&pDesc->guidObject, &Desc.guidObject, sizeof(Desc.guidObject));
550 if (Desc.dwValidData & DMUS_OBJ_CLASS)
551 memcpy (&pDesc->guidClass, &Desc.guidClass, sizeof(Desc.guidClass));
552 if (Desc.dwValidData & DMUS_OBJ_NAME)
553 strncpyW (pDesc->wszName, Desc.wszName, DMUS_MAX_NAME);
554 if (Desc.dwValidData & DMUS_OBJ_CATEGORY)
555 strncpyW (pDesc->wszCategory, Desc.wszCategory, DMUS_MAX_CATEGORY);
556 if (Desc.dwValidData & DMUS_OBJ_FILENAME)
557 strncpyW (pDesc->wszFileName, Desc.wszFileName, DMUS_MAX_FILENAME);
558 if (Desc.dwValidData & DMUS_OBJ_VERSION)
559 memcpy (&pDesc->vVersion, &Desc.vVersion, sizeof(Desc.vVersion));
560 if (Desc.dwValidData & DMUS_OBJ_DATE)
561 memcpy (&pDesc->ftDate, &Desc.ftDate, sizeof(Desc.ftDate));
562 pDesc->dwValidData |= Desc.dwValidData; /* add new flags */
565 TRACE(": adding alias entry with following info:\n");
566 if (TRACE_ON(dmloader))
567 DMUSIC_dump_DMUS_OBJECTDESC(pDesc);
568 newEntry = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_ALIAS_ENTRY));
569 newEntry->pDesc = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_OBJECTDESC));
570 memcpy (newEntry->pDesc, pDesc, sizeof(DMUS_OBJECTDESC));
571 list_add_tail (&This->AliasList, &newEntry->entry);
576 HRESULT WINAPI IDirectMusicLoader8Impl_SetSearchDirectory (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, WCHAR* pwzPath, BOOL fClear) {
577 ICOM_THIS(IDirectMusicLoader8Impl,iface);
578 TRACE("(%p, %s, %s, %d)\n", This, debugstr_guid(rguidClass), debugstr_w(pwzPath), fClear);
579 if (0 == strncmpW(This->wzSearchPath, pwzPath, MAX_PATH)) {
582 strncpyW(This->wzSearchPath, pwzPath, MAX_PATH);
586 HRESULT WINAPI IDirectMusicLoader8Impl_ScanDirectory (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, WCHAR* pwzFileExtension, WCHAR* pwzScanFileName) {
587 ICOM_THIS(IDirectMusicLoader8Impl,iface);
588 FIXME("(%p, %s, %p, %p): stub\n", This, debugstr_guid(rguidClass), pwzFileExtension, pwzScanFileName);
592 HRESULT WINAPI IDirectMusicLoader8Impl_CacheObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject) {
593 ICOM_THIS(IDirectMusicLoader8Impl,iface);
594 FIXME("(%p, %p): stub\n", This, pObject);
598 HRESULT WINAPI IDirectMusicLoader8Impl_ReleaseObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject) {
599 ICOM_THIS(IDirectMusicLoader8Impl,iface);
600 FIXME("(%p, %p): stub\n", This, pObject);
604 HRESULT WINAPI IDirectMusicLoader8Impl_ClearCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass) {
605 ICOM_THIS(IDirectMusicLoader8Impl,iface);
606 FIXME("(%p, %s): stub\n", This, debugstr_guid(rguidClass));
610 HRESULT WINAPI IDirectMusicLoader8Impl_EnableCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, BOOL fEnable) {
611 ICOM_THIS(IDirectMusicLoader8Impl,iface);
612 FIXME("(%p, %s, %d): stub\n", This, debugstr_guid(rguidClass), fEnable);
616 HRESULT WINAPI IDirectMusicLoader8Impl_EnumObject (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, DWORD dwIndex, LPDMUS_OBJECTDESC pDesc) {
617 ICOM_THIS(IDirectMusicLoader8Impl,iface);
618 FIXME("(%p, %s, %ld, %p): stub\n", This, debugstr_guid(rguidClass), dwIndex, pDesc);
622 /* IDirectMusicLoader8 Interface part follow: */
623 void WINAPI IDirectMusicLoader8Impl_CollectGarbage (LPDIRECTMUSICLOADER8 iface) {
624 ICOM_THIS(IDirectMusicLoader8Impl,iface);
625 FIXME("(%p): stub\n", This);
628 HRESULT WINAPI IDirectMusicLoader8Impl_ReleaseObjectByUnknown (LPDIRECTMUSICLOADER8 iface, IUnknown* pObject) {
629 ICOM_THIS(IDirectMusicLoader8Impl,iface);
630 FIXME("(%p, %p): stub\n", This, pObject);
634 HRESULT WINAPI IDirectMusicLoader8Impl_LoadObjectFromFile (LPDIRECTMUSICLOADER8 iface,
635 REFGUID rguidClassID,
636 REFIID iidInterfaceID,
639 ICOM_THIS(IDirectMusicLoader8Impl,iface);
640 DMUS_OBJECTDESC ObjDesc;
642 TRACE("(%p, %s, %s, %s, %p): wrapping to IDirectMusicLoader8Impl_GetObject\n", This, debugstr_guid(rguidClassID), debugstr_guid(iidInterfaceID), debugstr_w(pwzFilePath), ppObject);
644 ObjDesc.dwSize = sizeof(DMUS_OBJECTDESC);
645 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 */
646 ObjDesc.guidClass = *rguidClassID;
647 /* OK, MSDN says that search order is the following:
648 - current directory (DONE)
649 - windows search path (FIXME: how do I get that?)
650 - loader's search path (DONE)
652 /* search in current directory */
653 if (!SearchPathW (NULL, pwzFilePath, NULL,
654 sizeof(ObjDesc.wszFileName)/sizeof(WCHAR), ObjDesc.wszFileName, NULL) &&
655 /* search in loader's search path */
656 !SearchPathW (This->wzSearchPath, pwzFilePath, NULL,
657 sizeof(ObjDesc.wszFileName)/sizeof(WCHAR), ObjDesc.wszFileName, NULL))
659 /* cannot find file */
660 TRACE("cannot find file\n");
661 return DMUS_E_LOADER_FAILEDOPEN;
664 TRACE("full file path = %s\n", debugstr_w (ObjDesc.wszFileName));
666 return IDirectMusicLoader8Impl_GetObject (iface, &ObjDesc, iidInterfaceID, ppObject);
669 ICOM_VTABLE(IDirectMusicLoader8) DirectMusicLoader8_Vtbl = {
670 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
671 IDirectMusicLoader8Impl_QueryInterface,
672 IDirectMusicLoader8Impl_AddRef,
673 IDirectMusicLoader8Impl_Release,
674 IDirectMusicLoader8Impl_GetObject,
675 IDirectMusicLoader8Impl_SetObject,
676 IDirectMusicLoader8Impl_SetSearchDirectory,
677 IDirectMusicLoader8Impl_ScanDirectory,
678 IDirectMusicLoader8Impl_CacheObject,
679 IDirectMusicLoader8Impl_ReleaseObject,
680 IDirectMusicLoader8Impl_ClearCache,
681 IDirectMusicLoader8Impl_EnableCache,
682 IDirectMusicLoader8Impl_EnumObject,
683 IDirectMusicLoader8Impl_CollectGarbage,
684 IDirectMusicLoader8Impl_ReleaseObjectByUnknown,
685 IDirectMusicLoader8Impl_LoadObjectFromFile
688 /* for ClassFactory */
689 HRESULT WINAPI DMUSIC_CreateDirectMusicLoaderImpl (LPCGUID lpcGUID, LPVOID *ppobj, LPUNKNOWN pUnkOuter) {
690 IDirectMusicLoader8Impl *obj;
692 TRACE("(%p,%p,%p)\n",lpcGUID, ppobj, pUnkOuter);
693 obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoader8Impl));
695 *ppobj = (LPDIRECTMUSICLOADER8)NULL;
696 return E_OUTOFMEMORY;
698 obj->lpVtbl = &DirectMusicLoader8_Vtbl;
699 obj->ref = 0; /* will be inited with QueryInterface */
700 MultiByteToWideChar (CP_ACP, 0, ".\\", -1, obj->wzSearchPath, MAX_PATH);
701 list_init (&obj->CacheList);
702 list_init (&obj->AliasList);
704 return IDirectMusicLoader8Impl_QueryInterface ((LPDIRECTMUSICLOADER8)obj, lpcGUID, ppobj);
707 /* help function for IDirectMusicLoader8Impl_GetObject */
708 HRESULT WINAPI DMUSIC_GetDefaultGMPath (WCHAR wszPath[MAX_PATH]) {
710 DWORD returnType, sizeOfReturnBuffer = MAX_PATH;
711 char szPath[MAX_PATH];
713 if ((RegOpenKeyExA (HKEY_LOCAL_MACHINE, "Software\\Microsoft\\DirectMusic" , 0, KEY_READ, &hkDM) != ERROR_SUCCESS) ||
714 (RegQueryValueExA (hkDM, "GMFilePath", NULL, &returnType, szPath, &sizeOfReturnBuffer) != ERROR_SUCCESS)) {
715 WARN(": registry entry missing\n" );
718 /* FIXME: Check return types to ensure we're interpreting data right */
719 MultiByteToWideChar (CP_ACP, 0, szPath, -1, wszPath, MAX_PATH);