- scripts sub-containers loading
[wine/multimedia.git] / dlls / dmloader / loader.c
bloba3f3a0e7649f579f0d61a25cd4cf28a1713077a8
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);
35 *ppobj = This;
36 return S_OK;
39 WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ppobj);
40 return E_NOINTERFACE;
43 ULONG WINAPI IDirectMusicLoader8Impl_AddRef (LPDIRECTMUSICLOADER8 iface) {
44 ICOM_THIS(IDirectMusicLoader8Impl,iface);
45 TRACE("(%p): AddRef from %ld\n", This, This->ref);
46 return ++(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);
53 if (ref == 0) {
54 HeapFree(GetProcessHeap(), 0, This);
56 return ref;
59 /* IDirectMusicLoader8 IDirectMusicLoader part: */
60 HRESULT WINAPI IDirectMusicLoader8Impl_GetObject (LPDIRECTMUSICLOADER8 iface, LPDMUS_OBJECTDESC pDesc, REFIID riid, LPVOID* ppv) {
61 ICOM_THIS(IDirectMusicLoader8Impl,iface);
62 HRESULT result = 0;
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:
156 1. DMUS_OBJ_OBJECT
157 2. DMUS_OBJ_MEMORY (FIXME)
158 3. DMUS_OBJ_FILENAME & DMUS_OBJ_FULLPATH
159 4. DMUS_OBJ_NAME & DMUS_OBJ_CATEGORY
160 5. DMUS_OBJ_NAME
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");
202 *ppv = NULL;
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;
212 LPSTREAM pStream;
213 IPersistStream* pPersistStream = NULL;
215 if (pDesc->dwValidData & DMUS_OBJ_FULLPATH) {
216 lstrcpyW(wzFileName, pDesc->wszFileName);
217 } else {
218 WCHAR *p;
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");
229 return result;
231 result = ILoaderStream_Attach (pStream, wzFileName, (LPDIRECTMUSICLOADER)iface);
232 if (FAILED(result)) {
233 ERR(": could not attach stream to file\n");
234 return result;
236 /* create object */
237 result = CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject);
238 if (FAILED(result)) {
239 ERR(": could not create object\n");
240 return result;
242 /* acquire PersistStream interface */
243 result = IDirectMusicObject_QueryInterface (pObject, &IID_IPersistStream, (LPVOID*)&pPersistStream);
244 if (FAILED(result)) {
245 ERR("failed to Query\n");
246 return result;
248 /* load */
249 result = IPersistStream_Load (pPersistStream, pStream);
250 if (FAILED(result)) {
251 ERR(": failed to load object\n");
252 return result;
254 /* get descriptor */
255 DM_STRUCT_INIT(&GotDesc);
256 result = IDirectMusicObject_GetDescriptor (pObject, &GotDesc);
257 if (FAILED(result)) {
258 ERR(": failed to get descriptor\n");
259 return result;
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 */
264 /* set descriptor */
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");
280 return result;
282 /* create object */
283 result = CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject);
284 if (FAILED(result)) {
285 ERR(": could not create object\n");
286 return result;
288 /* acquire PersistStream interface */
289 result = IDirectMusicObject_QueryInterface (pObject, &IID_IPersistStream, (LPVOID*)&pPersistStream);
290 if (FAILED(result)) {
291 ERR(": could not acquire IPersistStream\n");
292 return result;
294 /* load */
295 result = IPersistStream_Load (pPersistStream, pClonedStream);
296 if (FAILED(result)) {
297 ERR(": failed to load object\n");
298 return result;
300 /* get descriptor */
301 DM_STRUCT_INIT(&GotDesc);
302 result = IDirectMusicObject_GetDescriptor (pObject, &GotDesc);
303 if (FAILED(result)) {
304 ERR(": failed to get descriptor\n");
305 return result;
307 /* now set the "missing" info */
308 GotDesc.dwValidData |= DMUS_OBJ_LOADED; /* only missing data with streams */
309 /* set descriptor */
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
322 * behaviour:
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
335 * -cheers, Rok
337 WCHAR wzFileName[DMUS_MAX_FILENAME];
338 LPSTREAM pStream;
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");
349 return E_FAIL;
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");
356 return result;
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");
362 return result;
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");
369 return result;
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");
376 return result;
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");
384 return result;
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");
413 return result;
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");
420 return result;
422 /* load */
423 TRACE(": loading object..\n");
424 result = IPersistStream_Load (pPersistStream, pStream);
425 if (FAILED(result)) {
426 ERR(": failed to load object\n");
427 return result;
429 /* get descriptor */
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");
435 return result;
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 */
442 /* set descriptor */
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);
449 } else {
450 return E_FAIL;
452 } else {
453 /* nowhere to load from */
454 FIXME(": unknown/unsupported way of loading\n");
455 return E_FAIL;
458 /* add object to cache */
459 newEntry = (LPDMUS_PRIVATE_CACHE_ENTRY) HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_CACHE_ENTRY));
460 if (pObject) {
461 newEntry->pObject = pObject;
462 newEntry->bIsFaultyDLS = FALSE;
464 list_add_tail (&This->CacheList, &newEntry->entry);
465 TRACE(": filled in cache entry\n");
467 #if 0
468 /* for debug purposes (e.g. to check if all files are cached) */
469 TRACE("*** Loader's cache ***\n");
470 int i = 0;
471 LIST_FOR_EACH (listEntry, &This->CacheList) {
472 i++;
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));
479 } else {
480 TRACE(": faulty DLS collection\n");
483 #endif
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];
500 LPSTREAM pStream;
501 IDirectMusicObject* pObject;
503 if (pDesc->dwValidData & DMUS_OBJ_FULLPATH) {
504 lstrcpyW(wzFileName, pDesc->wszFileName);
505 } else {
506 WCHAR *p;
507 lstrcpyW(wzFileName, This->wzSearchPath);
508 p = wzFileName + lstrlenW(wzFileName);
509 if (p > wzFileName && p[-1] != '\\') *p++ = '\\';
510 strcpyW(p, pDesc->wszFileName);
512 /* create stream */
513 DMUSIC_CreateLoaderStream ((LPVOID*) &pStream);
514 /* attach stream */
515 ILoaderStream_Attach (pStream, wzFileName, (LPDIRECTMUSICLOADER)iface);
516 /* create object */
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) {
526 /* clone stream */
527 LPSTREAM pStream = NULL;
528 IDirectMusicObject* pObject;
530 IStream_Clone (pDesc->pStream, &pStream);
531 /* create object */
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);
540 else {
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 */
561 /* add new entry */
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);
568 return S_OK;
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)) {
575 return S_FALSE;
577 strncpyW(This->wzSearchPath, pwzPath, MAX_PATH);
578 return S_OK;
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);
584 return S_OK;
587 HRESULT WINAPI IDirectMusicLoader8Impl_CacheObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject) {
588 ICOM_THIS(IDirectMusicLoader8Impl,iface);
589 FIXME("(%p, %p): stub\n", This, pObject);
590 return S_OK;
593 HRESULT WINAPI IDirectMusicLoader8Impl_ReleaseObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject) {
594 ICOM_THIS(IDirectMusicLoader8Impl,iface);
595 FIXME("(%p, %p): stub\n", This, pObject);
596 return S_OK;
599 HRESULT WINAPI IDirectMusicLoader8Impl_ClearCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass) {
600 ICOM_THIS(IDirectMusicLoader8Impl,iface);
601 FIXME("(%p, %s): stub\n", This, debugstr_dmguid(rguidClass));
602 return S_OK;
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);
608 return S_OK;
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);
614 return S_FALSE;
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);
626 return S_OK;
629 HRESULT WINAPI IDirectMusicLoader8Impl_LoadObjectFromFile (LPDIRECTMUSICLOADER8 iface,
630 REFGUID rguidClassID,
631 REFIID iidInterfaceID,
632 WCHAR* pwzFilePath,
633 void** ppObject) {
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));
689 if (NULL == obj) {
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]) {
704 HKEY hkDM;
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" );
711 return E_FAIL;
713 /* FIXME: Check return types to ensure we're interpreting data right */
714 MultiByteToWideChar (CP_ACP, 0, szPath, -1, wszPath, MAX_PATH);
716 return S_OK;