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 TRACE("(%p, %s, %p)\n",This
, debugstr_dmguid(riid
), ppobj
);
31 if (IsEqualIID (riid
, &IID_IUnknown
) ||
32 IsEqualIID (riid
, &IID_IDirectMusicLoader
) ||
33 IsEqualIID (riid
, &IID_IDirectMusicLoader8
)) {
34 IDirectMusicLoader8Impl_AddRef(iface
);
39 WARN("(%p, %s, %p): not found\n", This
, debugstr_dmguid(riid
), ppobj
);
43 ULONG WINAPI
IDirectMusicLoader8Impl_AddRef (LPDIRECTMUSICLOADER8 iface
) {
44 ICOM_THIS(IDirectMusicLoader8Impl
,iface
);
45 TRACE("(%p): AddRef from %ld\n", This
, This
->ref
);
49 ULONG WINAPI
IDirectMusicLoader8Impl_Release (LPDIRECTMUSICLOADER8 iface
) {
50 ICOM_THIS(IDirectMusicLoader8Impl
,iface
);
51 ULONG ref
= --This
->ref
;
52 TRACE("(%p): ReleaseRef to %ld\n", This
, This
->ref
);
54 HeapFree(GetProcessHeap(), 0, This
);
59 /* IDirectMusicLoader8 IDirectMusicLoader part: */
60 HRESULT WINAPI
IDirectMusicLoader8Impl_GetObject (LPDIRECTMUSICLOADER8 iface
, LPDMUS_OBJECTDESC pDesc
, REFIID riid
, LPVOID
* ppv
) {
61 ICOM_THIS(IDirectMusicLoader8Impl
,iface
);
63 struct list
*listEntry
;
64 LPDMUS_PRIVATE_ALIAS_ENTRY aliasEntry
;
65 DMUS_PRIVATE_CACHE_ENTRY
*cacheEntry
;
66 DMUS_OBJECTDESC CacheDesc
;
67 IDirectMusicObject
* pObject
;
68 LPDMUS_PRIVATE_CACHE_ENTRY newEntry
;
70 TRACE("(%p, %p, %s, %p): pDesc:\n%s\n", This
, pDesc
, debugstr_dmguid(riid
), ppv
, debugstr_DMUS_OBJECTDESC(pDesc
));
72 /* if I understand correctly, SetObject makes sort of aliases for entries in cache;
73 therefore I created alias list, which is similiar to cache list, and is used as resolver
74 (it maps let's say GUID to filename) */
75 TRACE(": looking for alias\n");
76 LIST_FOR_EACH (listEntry
, &This
->AliasList
) {
77 aliasEntry
= LIST_ENTRY(listEntry
, DMUS_PRIVATE_ALIAS_ENTRY
, entry
);
78 /* for the time being, we support only GUID/name mapping */
79 if ((aliasEntry
->pDesc
->dwValidData
& DMUS_OBJ_OBJECT
) && (pDesc
->dwValidData
& DMUS_OBJ_OBJECT
)
80 && IsEqualGUID (&aliasEntry
->pDesc
->guidObject
, &pDesc
->guidObject
)) {
81 TRACE(": found alias by GUID (%s)... mapping:\n", debugstr_dmguid(&aliasEntry
->pDesc
->guidObject
));
82 if ((aliasEntry
->pDesc
->dwValidData
& DMUS_OBJ_FILENAME
) && !(pDesc
->dwValidData
& DMUS_OBJ_FILENAME
)) {
83 TRACE(": - to filename (%s)\n", debugstr_w(aliasEntry
->pDesc
->wszFileName
));
84 pDesc
->dwValidData
|= DMUS_OBJ_FILENAME
;
85 pDesc
->dwValidData
|= (aliasEntry
->pDesc
->dwValidData
& DMUS_OBJ_FULLPATH
);
86 strncpyW (pDesc
->wszFileName
, aliasEntry
->pDesc
->wszFileName
, DMUS_MAX_FILENAME
);
88 if ((aliasEntry
->pDesc
->dwValidData
& DMUS_OBJ_NAME
) && !(pDesc
->dwValidData
& DMUS_OBJ_NAME
)) {
89 TRACE(": - to name (%s)\n", debugstr_w(aliasEntry
->pDesc
->wszName
));
90 pDesc
->dwValidData
|= DMUS_OBJ_NAME
;
91 strncpyW (pDesc
->wszName
, aliasEntry
->pDesc
->wszName
, DMUS_MAX_NAME
);
93 if ((aliasEntry
->pDesc
->dwValidData
& DMUS_OBJ_MEMORY
) && !(pDesc
->dwValidData
& DMUS_OBJ_MEMORY
)) {
94 TRACE(": - to memory location\n");
95 pDesc
->dwValidData
|= DMUS_OBJ_MEMORY
;
96 /* FIXME: is this correct? */
97 pDesc
->pbMemData
= aliasEntry
->pDesc
->pbMemData
;
98 pDesc
->llMemLength
= aliasEntry
->pDesc
->llMemLength
;
100 if ((aliasEntry
->pDesc
->dwValidData
& DMUS_OBJ_STREAM
) && !(pDesc
->dwValidData
& DMUS_OBJ_STREAM
)) {
101 TRACE(": - to stream\n");
102 pDesc
->dwValidData
|= DMUS_OBJ_STREAM
;
103 IStream_Clone (aliasEntry
->pDesc
->pStream
, &pDesc
->pStream
);
106 else if ((aliasEntry
->pDesc
->dwValidData
& DMUS_OBJ_NAME
) && (pDesc
->dwValidData
& DMUS_OBJ_NAME
)
107 && !strncmpW (aliasEntry
->pDesc
->wszName
, pDesc
->wszName
, DMUS_MAX_NAME
)) {
108 TRACE(": found alias by name (%s)... mapping:\n", debugstr_w(aliasEntry
->pDesc
->wszName
));
109 if ((aliasEntry
->pDesc
->dwValidData
& DMUS_OBJ_FILENAME
) && !(pDesc
->dwValidData
& DMUS_OBJ_FILENAME
)) {
110 TRACE(": - to filename (%s)\n", debugstr_w(aliasEntry
->pDesc
->wszFileName
));
111 pDesc
->dwValidData
|= DMUS_OBJ_FILENAME
;
112 pDesc
->dwValidData
|= (aliasEntry
->pDesc
->dwValidData
& DMUS_OBJ_FULLPATH
);
113 strncpyW (pDesc
->wszFileName
, aliasEntry
->pDesc
->wszFileName
, DMUS_MAX_FILENAME
);
115 if ((aliasEntry
->pDesc
->dwValidData
& DMUS_OBJ_OBJECT
) && !(pDesc
->dwValidData
& DMUS_OBJ_OBJECT
)) {
116 TRACE(": - to object GUID (%s)\n", debugstr_dmguid(&aliasEntry
->pDesc
->guidObject
));
117 pDesc
->dwValidData
|= DMUS_OBJ_OBJECT
;
118 memcpy (&pDesc
->guidObject
, &aliasEntry
->pDesc
->guidObject
, sizeof(GUID
));
120 if ((aliasEntry
->pDesc
->dwValidData
& DMUS_OBJ_MEMORY
) && !(pDesc
->dwValidData
& DMUS_OBJ_MEMORY
)) {
121 TRACE(": - to memory location\n");
122 pDesc
->dwValidData
|= DMUS_OBJ_MEMORY
;
123 /* FIXME: is this correct? */
124 pDesc
->pbMemData
= aliasEntry
->pDesc
->pbMemData
;
125 pDesc
->llMemLength
= aliasEntry
->pDesc
->llMemLength
;
127 if ((aliasEntry
->pDesc
->dwValidData
& DMUS_OBJ_STREAM
) && !(pDesc
->dwValidData
& DMUS_OBJ_STREAM
)) {
128 TRACE(": - to stream\n");
129 pDesc
->dwValidData
|= DMUS_OBJ_STREAM
;
130 IStream_Clone (aliasEntry
->pDesc
->pStream
, &pDesc
->pStream
);
133 /*else FIXME(": implement other types of mapping\n"); */
136 /* iterate through cache and check whether object has already been loaded */
137 TRACE(": looking up cache...\n");
138 DM_STRUCT_INIT(&CacheDesc
);
139 LIST_FOR_EACH (listEntry
, &This
->CacheList
) {
140 cacheEntry
= LIST_ENTRY(listEntry
, DMUS_PRIVATE_CACHE_ENTRY
, entry
);
141 /* first check whether cached object is "faulty" default dls collection;
142 * I don't think it's recongised by object descriptor, since it contains no
143 * data; it's not very elegant way, but it works :)
145 if (cacheEntry
->bIsFaultyDLS
== TRUE
) {
146 if ((pDesc
->dwValidData
& DMUS_OBJ_OBJECT
) && IsEqualGUID (&GUID_DefaultGMCollection
, &pDesc
->guidObject
)) {
147 TRACE(": found faulty default DLS collection... enabling M$ compliant behaviour\n");
148 return DMUS_E_LOADER_NOFILENAME
;
151 /* I think it shouldn't happen that pObject is NULL, but better be safe */
152 if (cacheEntry
->pObject
) {
153 DM_STRUCT_INIT(&CacheDesc
); /* prepare desc for reuse */
154 IDirectMusicObject_GetDescriptor (cacheEntry
->pObject
, &CacheDesc
);
155 /* according to MSDN, search order is:
157 2. DMUS_OBJ_MEMORY (FIXME)
158 3. DMUS_OBJ_FILENAME & DMUS_OBJ_FULLPATH
159 4. DMUS_OBJ_NAME & DMUS_OBJ_CATEGORY
161 6. DMUS_OBJ_FILENAME */
162 if ((pDesc
->dwValidData
& DMUS_OBJ_OBJECT
) && (CacheDesc
.dwValidData
& DMUS_OBJ_OBJECT
)
163 && IsEqualGUID (&pDesc
->guidObject
, &CacheDesc
.guidObject
)) {
164 TRACE(": found it by object GUID\n");
165 return IDirectMusicObject_QueryInterface (cacheEntry
->pObject
, riid
, ppv
);
167 if ((pDesc
->dwValidData
& DMUS_OBJ_MEMORY
) && (CacheDesc
.dwValidData
& DMUS_OBJ_MEMORY
)) {
168 FIXME(": DMUS_OBJ_MEMORY not supported yet\n");
170 if ((pDesc
->dwValidData
& DMUS_OBJ_FILENAME
) && (pDesc
->dwValidData
& DMUS_OBJ_FULLPATH
)
171 && (CacheDesc
.dwValidData
& DMUS_OBJ_FILENAME
) && (CacheDesc
.dwValidData
& DMUS_OBJ_FULLPATH
)
172 && !strncmpW (pDesc
->wszFileName
, CacheDesc
.wszFileName
, DMUS_MAX_FILENAME
)) {
173 TRACE(": found it by fullpath filename\n");
174 return IDirectMusicObject_QueryInterface (cacheEntry
->pObject
, riid
, ppv
);
176 if ((pDesc
->dwValidData
& DMUS_OBJ_NAME
) && (pDesc
->dwValidData
& DMUS_OBJ_CATEGORY
)
177 && (CacheDesc
.dwValidData
& DMUS_OBJ_NAME
) && (CacheDesc
.dwValidData
& DMUS_OBJ_CATEGORY
)
178 && !strncmpW (pDesc
->wszName
, CacheDesc
.wszName
, DMUS_MAX_NAME
)
179 && !strncmpW (pDesc
->wszCategory
, CacheDesc
.wszCategory
, DMUS_MAX_CATEGORY
)) {
180 TRACE(": found it by name and category\n");
181 return IDirectMusicObject_QueryInterface (cacheEntry
->pObject
, riid
, ppv
);
183 if ((pDesc
->dwValidData
& DMUS_OBJ_NAME
) && (CacheDesc
.dwValidData
& DMUS_OBJ_NAME
)
184 && !strncmpW (pDesc
->wszName
, CacheDesc
.wszName
, DMUS_MAX_NAME
)) {
185 TRACE(": found it by name\n");
186 return IDirectMusicObject_QueryInterface (cacheEntry
->pObject
, riid
, ppv
);
188 if ((pDesc
->dwValidData
& DMUS_OBJ_FILENAME
) && (CacheDesc
.dwValidData
& DMUS_OBJ_FILENAME
)
189 && !strncmpW (pDesc
->wszFileName
, CacheDesc
.wszFileName
, DMUS_MAX_FILENAME
)) {
190 TRACE(": found it by filename\n");
191 return IDirectMusicObject_QueryInterface (cacheEntry
->pObject
, riid
, ppv
);
196 /* object doesn't exist in cache... guess we'll have to load it */
197 TRACE(": object does not exist in cache\n");
199 /* sometimes it happens that guidClass is missing */
200 if (!(pDesc
->dwValidData
& DMUS_OBJ_CLASS
)) {
201 ERR(": guidClass not valid but needed\n");
203 return DMUS_E_LOADER_NOCLASSID
;
206 if (pDesc
->dwValidData
& DMUS_OBJ_FILENAME
) {
207 /* load object from file */
208 /* generate filename; if it's full path, don't add search
209 directory path, otherwise do */
210 WCHAR wzFileName
[MAX_PATH
];
211 DMUS_OBJECTDESC GotDesc
;
213 IPersistStream
* pPersistStream
= NULL
;
215 if (pDesc
->dwValidData
& DMUS_OBJ_FULLPATH
) {
216 lstrcpyW(wzFileName
, pDesc
->wszFileName
);
219 lstrcpyW(wzFileName
, This
->wzSearchPath
);
220 p
= wzFileName
+ lstrlenW(wzFileName
);
221 if (p
> wzFileName
&& p
[-1] != '\\') *p
++ = '\\';
222 strcpyW(p
, pDesc
->wszFileName
);
224 TRACE(": loading from file (%s)\n", debugstr_w(wzFileName
));
225 /* create stream and associate it with dls collection file */
226 result
= DMUSIC_CreateLoaderStream ((LPVOID
*)&pStream
);
227 if (FAILED(result
)) {
228 ERR(": could not create loader stream\n");
231 result
= ILoaderStream_Attach (pStream
, wzFileName
, (LPDIRECTMUSICLOADER
)iface
);
232 if (FAILED(result
)) {
233 ERR(": could not attach stream to file\n");
237 result
= CoCreateInstance (&pDesc
->guidClass
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IDirectMusicObject
, (LPVOID
*)&pObject
);
238 if (FAILED(result
)) {
239 ERR(": could not create object\n");
242 /* acquire PersistStream interface */
243 result
= IDirectMusicObject_QueryInterface (pObject
, &IID_IPersistStream
, (LPVOID
*)&pPersistStream
);
244 if (FAILED(result
)) {
245 ERR("failed to Query\n");
249 result
= IPersistStream_Load (pPersistStream
, pStream
);
250 if (FAILED(result
)) {
251 ERR(": failed to load object\n");
255 DM_STRUCT_INIT(&GotDesc
);
256 result
= IDirectMusicObject_GetDescriptor (pObject
, &GotDesc
);
257 if (FAILED(result
)) {
258 ERR(": failed to get descriptor\n");
261 /* now set the "missing" info (check comment at "Loading default DLS collection") */
262 GotDesc
.dwValidData
|= (DMUS_OBJ_FILENAME
| DMUS_OBJ_LOADED
); /* this time only these are missing */
263 strncpyW (GotDesc
.wszFileName
, pDesc
->wszFileName
, DMUS_MAX_FILENAME
); /* set wszFileName, even if futile */
265 IDirectMusicObject_SetDescriptor (pObject
, &GotDesc
);
266 /* release all loading related stuff */
267 IStream_Release (pStream
);
268 IPersistStream_Release (pPersistStream
);
270 else if (pDesc
->dwValidData
& DMUS_OBJ_STREAM
) {
271 LPSTREAM pClonedStream
= NULL
;
272 IPersistStream
* pPersistStream
= NULL
;
273 DMUS_OBJECTDESC GotDesc
;
274 /* load object from stream */
275 TRACE(": loading from stream\n");
276 /* clone stream, given in pDesc */
277 result
= IStream_Clone (pDesc
->pStream
, &pClonedStream
);
278 if (FAILED(result
)) {
279 ERR(": failed to clone stream\n");
283 result
= CoCreateInstance (&pDesc
->guidClass
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IDirectMusicObject
, (LPVOID
*)&pObject
);
284 if (FAILED(result
)) {
285 ERR(": could not create object\n");
288 /* acquire PersistStream interface */
289 result
= IDirectMusicObject_QueryInterface (pObject
, &IID_IPersistStream
, (LPVOID
*)&pPersistStream
);
290 if (FAILED(result
)) {
291 ERR(": could not acquire IPersistStream\n");
295 result
= IPersistStream_Load (pPersistStream
, pClonedStream
);
296 if (FAILED(result
)) {
297 ERR(": failed to load object\n");
301 DM_STRUCT_INIT(&GotDesc
);
302 result
= IDirectMusicObject_GetDescriptor (pObject
, &GotDesc
);
303 if (FAILED(result
)) {
304 ERR(": failed to get descriptor\n");
307 /* now set the "missing" info */
308 GotDesc
.dwValidData
|= DMUS_OBJ_LOADED
; /* only missing data with streams */
310 IDirectMusicObject_SetDescriptor (pObject
, &GotDesc
);
311 /* release all loading-related stuff */
312 IPersistStream_Release (pPersistStream
);
313 IStream_Release (pClonedStream
);
315 else if (pDesc
->dwValidData
& DMUS_OBJ_OBJECT
) {
316 /* load object by GUID */
317 TRACE(": loading by GUID (only default DLS supported)\n");
318 if (IsEqualGUID (&pDesc
->guidObject
, &GUID_DefaultGMCollection
)) {
319 /* Loading default DLS collection: *dirty* secret (TM)
320 * By mixing native and builtin loader and collection and
321 * various .dls files, I found out following undocumented
323 * - loader creates two instances of collection object
324 * - it calls ParseDescriptor on first, then releases it
325 * - then it checks returned descriptor; I'm not sure, but
326 * it seems that DMUS_OBJ_OBJECT is not present if DLS
327 * collection is indeed *real* one (gm.dls)
328 * - if above mentioned flag is not set, it creates another
329 * instance and loads it; it also gets descriptor and adds
330 * guidObject and wszFileName (even though this one cannot be
331 * set on native collection, or so it seems)
332 * => it seems to be sort of check whether given 'default
333 * DLS collection' is really one shipped with DX before
334 * actually loading it
337 WCHAR wzFileName
[DMUS_MAX_FILENAME
];
339 LPSTREAM pProbeStream
;
340 IDirectMusicObject
*pProbeObject
;
341 DMUS_OBJECTDESC ProbeDesc
;
342 DMUS_OBJECTDESC GotDesc
;
343 IPersistStream
*pPersistStream
= NULL
;
345 /* get the path for default collection */
346 TRACE(": getting default DLS collection path...\n");
347 if (FAILED(DMUSIC_GetDefaultGMPath (wzFileName
))) {
348 ERR(": could not get default collection path\n");
351 /* create stream and associate it with dls collection file */
352 TRACE(": creating stream...\n");
353 result
= DMUSIC_CreateLoaderStream ((LPVOID
*) &pStream
);
354 if (FAILED(result
)) {
355 ERR(": could not create loader stream\n");
358 TRACE(": attaching stream...\n");
359 result
= ILoaderStream_Attach (pStream
, wzFileName
, (LPDIRECTMUSICLOADER
)iface
);
360 if (FAILED(result
)) {
361 ERR(": could not attach stream to file\n");
364 /* now create a clone of stream for "probe" */
365 TRACE(": cloning stream (for probing)...\n");
366 result
= IStream_Clone (pStream
, &pProbeStream
);
367 if (FAILED(result
)) {
368 ERR(": could not clone stream\n");
371 /* create object for "probing" */
372 TRACE(": creating IDirectMusicObject (for probing)...\n");
373 result
= CoCreateInstance (&pDesc
->guidClass
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IDirectMusicObject
, (LPVOID
*) &pProbeObject
);
374 if (FAILED(result
)) {
375 ERR(": could not create object (for probing)\n");
378 /* get descriptor from stream */
379 TRACE(": parsing descriptor on probe stream...\n");
380 DM_STRUCT_INIT(&ProbeDesc
);
381 result
= IDirectMusicObject_ParseDescriptor (pProbeObject
, pProbeStream
, &ProbeDesc
);
382 if (FAILED(result
)) {
383 ERR(": could not parse descriptor\n");
386 /* release all probing-related stuff */
387 TRACE(": releasing probing-related stuff...\n");
388 IStream_Release (pProbeStream
);
389 IDirectMusicObject_Release (pProbeObject
);
390 /* now, if it happens by any chance that dls collection isn't *the one*
391 * TODO: - check if the way below is the appropriate one
393 if (ProbeDesc
.dwValidData
& DMUS_OBJ_OBJECT
) {
394 LPDMUS_PRIVATE_CACHE_ENTRY newEntry
;
395 WARN(": the default DLS collection is not the one shipped with DX\n");
396 /* my tests show that we return pointer to something or NULL, depending on + how
397 * input object was defined (therefore we probably don't return anything for object)
398 * and DMUS_E_LOADER_NOFILENAME as error code
399 * (I'd personally rather return DMUS_S_PARTIALLOAD, but I don't set rules)
401 newEntry
= (LPDMUS_PRIVATE_CACHE_ENTRY
) HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY
, sizeof(DMUS_PRIVATE_CACHE_ENTRY
));
402 newEntry
->pObject
= NULL
;
403 newEntry
->bIsFaultyDLS
= TRUE
; /* so that cache won't try to get descriptor */
404 list_add_tail (&This
->CacheList
, &newEntry
->entry
);
405 TRACE(": filled in cache entry\n");
406 return DMUS_E_LOADER_NOFILENAME
;
408 /* now the real loading... create object */
409 TRACE(": creating IDirectMusicObject (for loading)\n");
410 result
= CoCreateInstance (&pDesc
->guidClass
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IDirectMusicObject
, (LPVOID
*) &pObject
);
411 if (FAILED(result
)) {
412 ERR(": could not create object (for loading)\n");
415 /* acquire PersistStream interface */
416 TRACE(": getting IPersistStream on object...\n");
417 result
= IDirectMusicObject_QueryInterface (pObject
, &IID_IPersistStream
, (LPVOID
*) &pPersistStream
);
418 if (FAILED(result
)) {
419 ERR(": could not acquire IPersistStream\n");
423 TRACE(": loading object..\n");
424 result
= IPersistStream_Load (pPersistStream
, pStream
);
425 if (FAILED(result
)) {
426 ERR(": failed to load object\n");
430 TRACE(": getting descriptor of loaded object...\n");
431 DM_STRUCT_INIT(&GotDesc
);
432 result
= IDirectMusicObject_GetDescriptor (pObject
, &GotDesc
);
433 if (FAILED(result
)) {
434 ERR(": failed to get descriptor\n");
437 /* now set the "missing" info */
438 TRACE(": adding \"missing\" info...\n");
439 GotDesc
.dwValidData
|= (DMUS_OBJ_OBJECT
| DMUS_OBJ_FILENAME
| DMUS_OBJ_FULLPATH
| DMUS_OBJ_LOADED
);
440 memcpy (&GotDesc
.guidObject
, &pDesc
->guidObject
, sizeof(GUID
)); /* set guidObject */
441 strncpyW (GotDesc
.wszFileName
, wzFileName
, DMUS_MAX_FILENAME
); /* set wszFileName, even if futile */
443 TRACE(": setting descriptor\n");
444 IDirectMusicObject_SetDescriptor (pObject
, &GotDesc
);
445 /* release all loading related stuff */
446 TRACE(": releasing all loading-related stuff\n");
447 IStream_Release (pStream
);
448 IPersistStream_Release (pPersistStream
);
453 /* nowhere to load from */
454 FIXME(": unknown/unsupported way of loading\n");
458 /* add object to cache */
459 newEntry
= (LPDMUS_PRIVATE_CACHE_ENTRY
) HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY
, sizeof(DMUS_PRIVATE_CACHE_ENTRY
));
461 newEntry
->pObject
= pObject
;
462 newEntry
->bIsFaultyDLS
= FALSE
;
464 list_add_tail (&This
->CacheList
, &newEntry
->entry
);
465 TRACE(": filled in cache entry\n");
468 /* for debug purposes (e.g. to check if all files are cached) */
469 TRACE("*** Loader's cache ***\n");
471 LIST_FOR_EACH (listEntry
, &This
->CacheList
) {
473 TRACE("Entry nr. %i:\n", i
);
474 cacheEntry
= LIST_ENTRY(listEntry
, DMUS_PRIVATE_CACHE_ENTRY
, entry
);
475 if (cacheEntry
->bIsFaultyDLS
== FALSE
) {
476 DM_STRUCT_INIT(&CacheDesc
); /* prepare desc for reuse */
477 IDirectMusicObject_GetDescriptor (cacheEntry
->pObject
, &CacheDesc
);
478 TRACE(": %s\n", debugstr_DMUS_OBJECTDESC(&CacheDesc
));
480 TRACE(": faulty DLS collection\n");
485 return IDirectMusicObject_QueryInterface (pObject
, riid
, ppv
);
488 HRESULT WINAPI
IDirectMusicLoader8Impl_SetObject (LPDIRECTMUSICLOADER8 iface
, LPDMUS_OBJECTDESC pDesc
) {
489 ICOM_THIS(IDirectMusicLoader8Impl
,iface
);
490 DMUS_PRIVATE_ALIAS_ENTRY
*newEntry
;
491 DMUS_OBJECTDESC Desc
;
493 TRACE("(%p, %p): pDesc:\n%s\n", This
, pDesc
, debugstr_DMUS_OBJECTDESC(pDesc
));
495 /* create stream and load additional info from it */
496 if (pDesc
->dwValidData
& DMUS_OBJ_FILENAME
) {
497 /* generate filename; if it's full path, don't add search
498 directory path, otherwise do */
499 WCHAR wzFileName
[MAX_PATH
];
501 IDirectMusicObject
* pObject
;
503 if (pDesc
->dwValidData
& DMUS_OBJ_FULLPATH
) {
504 lstrcpyW(wzFileName
, pDesc
->wszFileName
);
507 lstrcpyW(wzFileName
, This
->wzSearchPath
);
508 p
= wzFileName
+ lstrlenW(wzFileName
);
509 if (p
> wzFileName
&& p
[-1] != '\\') *p
++ = '\\';
510 strcpyW(p
, pDesc
->wszFileName
);
513 DMUSIC_CreateLoaderStream ((LPVOID
*) &pStream
);
515 ILoaderStream_Attach (pStream
, wzFileName
, (LPDIRECTMUSICLOADER
)iface
);
517 CoCreateInstance (&pDesc
->guidClass
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IDirectMusicObject
, (LPVOID
*)&pObject
);
518 /* parse descriptor */
519 DM_STRUCT_INIT(&Desc
);
520 IDirectMusicObject_ParseDescriptor (pObject
, pStream
, &Desc
);
521 /* release everything */
522 IDirectMusicObject_Release (pObject
);
523 IStream_Release (pStream
);
525 else if (pDesc
->dwValidData
& DMUS_OBJ_STREAM
) {
527 LPSTREAM pStream
= NULL
;
528 IDirectMusicObject
* pObject
;
530 IStream_Clone (pDesc
->pStream
, &pStream
);
532 CoCreateInstance (&pDesc
->guidClass
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IDirectMusicObject
, (LPVOID
*)&pObject
);
533 /* parse descriptor */
534 DM_STRUCT_INIT(&Desc
);
535 IDirectMusicObject_ParseDescriptor (pObject
, pStream
, &Desc
);
536 /* release everything */
537 IDirectMusicObject_Release (pObject
);
538 IStream_Release (pStream
);
541 WARN(": no way to get additional info\n");
544 /* now set additional info... my tests show that existing fields should be overwritten */
545 if (Desc
.dwValidData
& DMUS_OBJ_OBJECT
)
546 memcpy (&pDesc
->guidObject
, &Desc
.guidObject
, sizeof(Desc
.guidObject
));
547 if (Desc
.dwValidData
& DMUS_OBJ_CLASS
)
548 memcpy (&pDesc
->guidClass
, &Desc
.guidClass
, sizeof(Desc
.guidClass
));
549 if (Desc
.dwValidData
& DMUS_OBJ_NAME
)
550 strncpyW (pDesc
->wszName
, Desc
.wszName
, DMUS_MAX_NAME
);
551 if (Desc
.dwValidData
& DMUS_OBJ_CATEGORY
)
552 strncpyW (pDesc
->wszCategory
, Desc
.wszCategory
, DMUS_MAX_CATEGORY
);
553 if (Desc
.dwValidData
& DMUS_OBJ_FILENAME
)
554 strncpyW (pDesc
->wszFileName
, Desc
.wszFileName
, DMUS_MAX_FILENAME
);
555 if (Desc
.dwValidData
& DMUS_OBJ_VERSION
)
556 memcpy (&pDesc
->vVersion
, &Desc
.vVersion
, sizeof(Desc
.vVersion
));
557 if (Desc
.dwValidData
& DMUS_OBJ_DATE
)
558 memcpy (&pDesc
->ftDate
, &Desc
.ftDate
, sizeof(Desc
.ftDate
));
559 pDesc
->dwValidData
|= Desc
.dwValidData
; /* add new flags */
562 TRACE(": adding alias entry with following info: \n%s\n", debugstr_DMUS_OBJECTDESC(pDesc
));
563 newEntry
= HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY
, sizeof(DMUS_PRIVATE_ALIAS_ENTRY
));
564 newEntry
->pDesc
= HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY
, sizeof(DMUS_OBJECTDESC
));
565 memcpy (newEntry
->pDesc
, pDesc
, sizeof(DMUS_OBJECTDESC
));
566 list_add_tail (&This
->AliasList
, &newEntry
->entry
);
571 HRESULT WINAPI
IDirectMusicLoader8Impl_SetSearchDirectory (LPDIRECTMUSICLOADER8 iface
, REFGUID rguidClass
, WCHAR
* pwzPath
, BOOL fClear
) {
572 ICOM_THIS(IDirectMusicLoader8Impl
,iface
);
573 TRACE("(%p, %s, %s, %d)\n", This
, debugstr_dmguid(rguidClass
), debugstr_w(pwzPath
), fClear
);
574 if (0 == strncmpW(This
->wzSearchPath
, pwzPath
, MAX_PATH
)) {
577 strncpyW(This
->wzSearchPath
, pwzPath
, MAX_PATH
);
581 HRESULT WINAPI
IDirectMusicLoader8Impl_ScanDirectory (LPDIRECTMUSICLOADER8 iface
, REFGUID rguidClass
, WCHAR
* pwzFileExtension
, WCHAR
* pwzScanFileName
) {
582 ICOM_THIS(IDirectMusicLoader8Impl
,iface
);
583 FIXME("(%p, %s, %p, %p): stub\n", This
, debugstr_dmguid(rguidClass
), pwzFileExtension
, pwzScanFileName
);
587 HRESULT WINAPI
IDirectMusicLoader8Impl_CacheObject (LPDIRECTMUSICLOADER8 iface
, IDirectMusicObject
* pObject
) {
588 ICOM_THIS(IDirectMusicLoader8Impl
,iface
);
589 FIXME("(%p, %p): stub\n", This
, pObject
);
593 HRESULT WINAPI
IDirectMusicLoader8Impl_ReleaseObject (LPDIRECTMUSICLOADER8 iface
, IDirectMusicObject
* pObject
) {
594 ICOM_THIS(IDirectMusicLoader8Impl
,iface
);
595 FIXME("(%p, %p): stub\n", This
, pObject
);
599 HRESULT WINAPI
IDirectMusicLoader8Impl_ClearCache (LPDIRECTMUSICLOADER8 iface
, REFGUID rguidClass
) {
600 ICOM_THIS(IDirectMusicLoader8Impl
,iface
);
601 FIXME("(%p, %s): stub\n", This
, debugstr_dmguid(rguidClass
));
605 HRESULT WINAPI
IDirectMusicLoader8Impl_EnableCache (LPDIRECTMUSICLOADER8 iface
, REFGUID rguidClass
, BOOL fEnable
) {
606 ICOM_THIS(IDirectMusicLoader8Impl
,iface
);
607 FIXME("(%p, %s, %d): stub\n", This
, debugstr_dmguid(rguidClass
), fEnable
);
611 HRESULT WINAPI
IDirectMusicLoader8Impl_EnumObject (LPDIRECTMUSICLOADER8 iface
, REFGUID rguidClass
, DWORD dwIndex
, LPDMUS_OBJECTDESC pDesc
) {
612 ICOM_THIS(IDirectMusicLoader8Impl
,iface
);
613 FIXME("(%p, %s, %ld, %p): stub\n", This
, debugstr_dmguid(rguidClass
), dwIndex
, pDesc
);
617 /* IDirectMusicLoader8 Interface part follow: */
618 void WINAPI
IDirectMusicLoader8Impl_CollectGarbage (LPDIRECTMUSICLOADER8 iface
) {
619 ICOM_THIS(IDirectMusicLoader8Impl
,iface
);
620 FIXME("(%p): stub\n", This
);
623 HRESULT WINAPI
IDirectMusicLoader8Impl_ReleaseObjectByUnknown (LPDIRECTMUSICLOADER8 iface
, IUnknown
* pObject
) {
624 ICOM_THIS(IDirectMusicLoader8Impl
,iface
);
625 FIXME("(%p, %p): stub\n", This
, pObject
);
629 HRESULT WINAPI
IDirectMusicLoader8Impl_LoadObjectFromFile (LPDIRECTMUSICLOADER8 iface
,
630 REFGUID rguidClassID
,
631 REFIID iidInterfaceID
,
634 ICOM_THIS(IDirectMusicLoader8Impl
,iface
);
635 DMUS_OBJECTDESC ObjDesc
;
637 TRACE("(%p, %s, %s, %s, %p): wrapping to IDirectMusicLoader8Impl_GetObject\n", This
, debugstr_dmguid(rguidClassID
), debugstr_dmguid(iidInterfaceID
), debugstr_w(pwzFilePath
), ppObject
);
639 ObjDesc
.dwSize
= sizeof(DMUS_OBJECTDESC
);
640 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 */
641 ObjDesc
.guidClass
= *rguidClassID
;
642 /* OK, MSDN says that search order is the following:
643 - current directory (DONE)
644 - windows search path (FIXME: how do I get that?)
645 - loader's search path (DONE)
647 /* search in current directory */
648 if (!SearchPathW (NULL
, pwzFilePath
, NULL
,
649 sizeof(ObjDesc
.wszFileName
)/sizeof(WCHAR
), ObjDesc
.wszFileName
, NULL
) &&
650 /* search in loader's search path */
651 !SearchPathW (This
->wzSearchPath
, pwzFilePath
, NULL
,
652 sizeof(ObjDesc
.wszFileName
)/sizeof(WCHAR
), ObjDesc
.wszFileName
, NULL
))
654 /* cannot find file */
655 TRACE("cannot find file\n");
656 return DMUS_E_LOADER_FAILEDOPEN
;
659 TRACE("full file path = %s\n", debugstr_w (ObjDesc
.wszFileName
));
661 return IDirectMusicLoader8Impl_GetObject (iface
, &ObjDesc
, iidInterfaceID
, ppObject
);
664 ICOM_VTABLE(IDirectMusicLoader8
) DirectMusicLoader8_Vtbl
= {
665 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
666 IDirectMusicLoader8Impl_QueryInterface
,
667 IDirectMusicLoader8Impl_AddRef
,
668 IDirectMusicLoader8Impl_Release
,
669 IDirectMusicLoader8Impl_GetObject
,
670 IDirectMusicLoader8Impl_SetObject
,
671 IDirectMusicLoader8Impl_SetSearchDirectory
,
672 IDirectMusicLoader8Impl_ScanDirectory
,
673 IDirectMusicLoader8Impl_CacheObject
,
674 IDirectMusicLoader8Impl_ReleaseObject
,
675 IDirectMusicLoader8Impl_ClearCache
,
676 IDirectMusicLoader8Impl_EnableCache
,
677 IDirectMusicLoader8Impl_EnumObject
,
678 IDirectMusicLoader8Impl_CollectGarbage
,
679 IDirectMusicLoader8Impl_ReleaseObjectByUnknown
,
680 IDirectMusicLoader8Impl_LoadObjectFromFile
683 /* for ClassFactory */
684 HRESULT WINAPI
DMUSIC_CreateDirectMusicLoaderImpl (LPCGUID lpcGUID
, LPVOID
*ppobj
, LPUNKNOWN pUnkOuter
) {
685 IDirectMusicLoader8Impl
*obj
;
687 TRACE("(%p,%p,%p)\n",lpcGUID
, ppobj
, pUnkOuter
);
688 obj
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IDirectMusicLoader8Impl
));
690 *ppobj
= (LPDIRECTMUSICLOADER8
)NULL
;
691 return E_OUTOFMEMORY
;
693 obj
->lpVtbl
= &DirectMusicLoader8_Vtbl
;
694 obj
->ref
= 0; /* will be inited with QueryInterface */
695 MultiByteToWideChar (CP_ACP
, 0, ".\\", -1, obj
->wzSearchPath
, MAX_PATH
);
696 list_init (&obj
->CacheList
);
697 list_init (&obj
->AliasList
);
699 return IDirectMusicLoader8Impl_QueryInterface ((LPDIRECTMUSICLOADER8
)obj
, lpcGUID
, ppobj
);
702 /* help function for IDirectMusicLoader8Impl_GetObject */
703 HRESULT WINAPI
DMUSIC_GetDefaultGMPath (WCHAR wszPath
[MAX_PATH
]) {
705 DWORD returnType
, sizeOfReturnBuffer
= MAX_PATH
;
706 char szPath
[MAX_PATH
];
708 if ((RegOpenKeyExA (HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\DirectMusic" , 0, KEY_READ
, &hkDM
) != ERROR_SUCCESS
) ||
709 (RegQueryValueExA (hkDM
, "GMFilePath", NULL
, &returnType
, szPath
, &sizeOfReturnBuffer
) != ERROR_SUCCESS
)) {
710 WARN(": registry entry missing\n" );
713 /* FIXME: Check return types to ensure we're interpreting data right */
714 MultiByteToWideChar (CP_ACP
, 0, szPath
, -1, wszPath
, MAX_PATH
);