1 /* IDirectMusicLoader8 Implementation
3 * Copyright (C) 2003 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.
26 #include "wine/debug.h"
27 #include "wine/unicode.h"
30 #include "dmloader_private.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(dmloader);
34 HRESULT WINAPI DMUSIC_GetDefaultGMPath (WCHAR wszPath[MAX_PATH]);
36 /* IDirectMusicLoader8 IUnknown part: */
37 HRESULT WINAPI IDirectMusicLoader8Impl_QueryInterface (LPDIRECTMUSICLOADER8 iface, REFIID riid, LPVOID *ppobj)
39 ICOM_THIS(IDirectMusicLoader8Impl,iface);
41 if (IsEqualIID (riid, &IID_IUnknown) ||
42 IsEqualIID (riid, &IID_IDirectMusicLoader) ||
43 IsEqualIID (riid, &IID_IDirectMusicLoader8)) {
44 IDirectMusicLoader8Impl_AddRef(iface);
49 WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
53 ULONG WINAPI IDirectMusicLoader8Impl_AddRef (LPDIRECTMUSICLOADER8 iface)
55 ICOM_THIS(IDirectMusicLoader8Impl,iface);
56 TRACE("(%p) : AddRef from %ld\n", This, This->ref);
60 ULONG WINAPI IDirectMusicLoader8Impl_Release (LPDIRECTMUSICLOADER8 iface)
62 ICOM_THIS(IDirectMusicLoader8Impl,iface);
63 ULONG ref = --This->ref;
64 TRACE("(%p) : ReleaseRef to %ld\n", This, This->ref);
66 HeapFree(GetProcessHeap(), 0, This);
71 /* IDirectMusicLoader8 IDirectMusicLoader part: */
72 HRESULT WINAPI IDirectMusicLoader8Impl_GetObject (LPDIRECTMUSICLOADER8 iface, LPDMUS_OBJECTDESC pDesc, REFIID riid, LPVOID* ppv)
74 IDirectMusicObject* pObject;
75 ICOM_THIS(IDirectMusicLoader8Impl,iface);
77 struct list *listEntry;
78 DMUS_PRIVATE_CACHE_ENTRY *cacheEntry;
79 LPDMUS_PRIVATE_CACHE_ENTRY newEntry;
81 TRACE("(%p, %p(dwValidData:0x%08lx), %s, %p)\n", This, pDesc, pDesc->dwValidData, debugstr_guid(riid), ppv);
83 TRACE("looking up cache...\n");
85 LIST_FOR_EACH (listEntry, &This->CacheList) {
86 cacheEntry = LIST_ENTRY( listEntry, DMUS_PRIVATE_CACHE_ENTRY, entry );
88 if ((pDesc->dwValidData & DMUS_OBJ_OBJECT) || (pDesc->dwValidData & DMUS_OBJ_FILENAME)) {
89 if (pDesc->dwValidData & DMUS_OBJ_OBJECT) {
90 if (IsEqualGUID (&cacheEntry->guidObject, &pDesc->guidObject)) {
91 TRACE(": found it by GUID\n");
92 if (cacheEntry->pObject)
93 return IDirectMusicObject_QueryInterface ((LPDIRECTMUSICOBJECT) cacheEntry->pObject, riid, ppv);
96 if (pDesc->dwValidData & DMUS_OBJ_FILENAME) {
97 if (cacheEntry->wzFileName && !strncmpW (pDesc->wszFileName, cacheEntry->wzFileName, MAX_PATH)) {
98 TRACE(": found it by FileName\n");
99 if (cacheEntry->pObject)
100 return IDirectMusicObject_QueryInterface ((LPDIRECTMUSICOBJECT) cacheEntry->pObject, riid, ppv);
103 } else if (pDesc->dwValidData & DMUS_OBJ_NAME) {
105 * Usually search by name (for example main procedure name for scripts) after containers loading
106 * TODO: container loading code
108 TRACE(" comparing %s with cached %s (file:%s)\n", debugstr_w (pDesc->wszName), debugstr_w (cacheEntry->wzName), debugstr_w(cacheEntry->wzFileName));
109 if (cacheEntry->wzName && !strncmpW (pDesc->wszName, cacheEntry->wzName, 256)) {
110 TRACE(": found it by Name\n");
111 if (NULL != cacheEntry->pObject)
112 return IDirectMusicObject_QueryInterface ((LPDIRECTMUSICOBJECT) cacheEntry->pObject, riid, ppv);
117 /* object doesn't exist in cache... guess we'll have to load it */
118 TRACE(": object does not exist in cache\n");
119 if (pDesc->dwValidData & DMUS_OBJ_LOADED) {
120 ERR("Wanted a on-memory (cached) entry, but not found. Active Hack (waiting for Load code)\n");
121 /* ugly hack waiting for Load impl */
122 result = CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*) &pObject);
123 if (SUCCEEDED(result)) {
124 /* add object to cache */
125 result = IDirectMusicObject_QueryInterface (pObject, riid, ppv);
126 if (SUCCEEDED(result)) {
127 newEntry = (LPDMUS_PRIVATE_CACHE_ENTRY) HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_CACHE_ENTRY));
128 if (pDesc->dwValidData & DMUS_OBJ_NAME)
129 strncpyW (newEntry->wzName, pDesc->wszName, 256);
130 newEntry->pObject = pObject;
131 list_add_tail (&This->CacheList, &newEntry->entry);
132 TRACE(": filled in cache entry\n");
134 IDirectMusicObject_Release(pObject);
144 if (!(pDesc->dwValidData & DMUS_OBJ_CLASS)) {
145 WARN("guidClass not valid but needed. What they want to do ?\n");
147 return DMUS_E_LOADER_NOCLASSID;
149 result = CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*) &pObject);
150 if (FAILED(result)) return result;
151 if (pDesc->dwValidData & DMUS_OBJ_FILENAME) {
152 /* load object from file */
153 WCHAR wzFileName[MAX_PATH];
154 ILoaderStream* pStream;
155 IPersistStream* pPersistStream = NULL;
156 /* if it's full path, don't add search directory path, otherwise do */
157 if (pDesc->dwValidData & DMUS_OBJ_FULLPATH) {
158 lstrcpyW(wzFileName, pDesc->wszFileName);
161 lstrcpyW(wzFileName, This->wzSearchPath);
162 p = wzFileName + lstrlenW(wzFileName);
163 if (p > wzFileName && p[-1] != '\\') *p++ = '\\';
164 strcpyW(p, pDesc->wszFileName);
166 TRACE(": loading from file (%s)\n", debugstr_w(wzFileName));
168 result = DMUSIC_CreateLoaderStream ((LPSTREAM*) &pStream);
169 if (FAILED(result)) return result;
171 result = ILoaderStream_Attach (pStream, wzFileName, (LPDIRECTMUSICLOADER) iface);
172 if (FAILED(result)) return result;
174 result = IDirectMusicObject_QueryInterface (pObject, &IID_IPersistStream, (LPVOID*) &pPersistStream);
175 if (FAILED(result)) return result;
177 result = IPersistStream_Load (pPersistStream, (LPSTREAM) pStream);
178 if (FAILED(result)) return result;
180 ILoaderStream_IStream_Release ((LPSTREAM) pStream);
181 IPersistStream_Release (pPersistStream);
182 } else if (pDesc->dwValidData & DMUS_OBJ_STREAM) {
183 /* load object from stream */
184 IStream* pClonedStream = NULL;
185 IPersistStream* pPersistStream = NULL;
187 TRACE(": loading from stream\n");
188 result = IDirectMusicObject_QueryInterface (pObject, &IID_IPersistStream, (LPVOID*) &pPersistStream);
189 if (FAILED(result)) return result;
191 result = IStream_Clone (pDesc->pStream, &pClonedStream);
192 if (FAILED(result)) return result;
194 result = IPersistStream_Load (pPersistStream, pClonedStream);
195 if (FAILED(result)) return result;
197 IPersistStream_Release (pPersistStream);
198 IStream_Release (pClonedStream);
199 } else if (pDesc->dwValidData & DMUS_OBJ_OBJECT) {
200 /* load object by GUID */
201 TRACE(": loading by GUID (only default DLS supported)\n");
202 if (IsEqualGUID (&pDesc->guidObject, &GUID_DefaultGMCollection)) {
203 WCHAR wzFileName[MAX_PATH];
204 IPersistStream *pPersistStream = NULL;
205 ILoaderStream* pStream;
206 if (FAILED(DMUSIC_GetDefaultGMPath (wzFileName)))
208 /* load object from file */
209 result = DMUSIC_CreateLoaderStream ((LPSTREAM*) &pStream);
210 if (FAILED(result)) return result;
212 result = ILoaderStream_Attach (pStream, wzFileName, (LPDIRECTMUSICLOADER) iface);
213 if (FAILED(result)) return result;
215 result = IDirectMusicObject_QueryInterface (pObject, &IID_IPersistStream, (LPVOID*) &pPersistStream);
216 if (FAILED(result)) return result;
218 result = IPersistStream_Load (pPersistStream, (LPSTREAM) pStream);
219 if (FAILED(result)) return result;
221 ILoaderStream_IStream_Release ((LPSTREAM) pStream);
222 IPersistStream_Release (pPersistStream);
227 /* nowhere to load from */
228 FIXME(": unknown/unsupported way of loading\n");
231 /* add object to cache */
232 newEntry = (LPDMUS_PRIVATE_CACHE_ENTRY) HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_CACHE_ENTRY));
233 if (pDesc->dwValidData & DMUS_OBJ_OBJECT)
234 memcpy (&newEntry->guidObject, &pDesc->guidObject, sizeof (pDesc->guidObject));
235 if (pDesc->dwValidData & DMUS_OBJ_FILENAME)
236 strncpyW (newEntry->wzFileName, pDesc->wszFileName, MAX_PATH);
238 newEntry->pObject = pObject;
239 list_add_tail (&This->CacheList, &newEntry->entry);
240 TRACE(": filled in cache entry\n");
242 /* for debug purposes (e.g. to check if all files are cached) */
245 LIST_FOR_EACH (listEntry, &This->CacheList) {
247 cacheEntry = LIST_ENTRY( listEntry, DMUS_PRIVATE_CACHE_ENTRY, entry );
248 TRACE("Entry nr. %i: GUID = %s, FileName = %s\n", i, debugstr_guid (&cacheEntry->guidObject), debugstr_w (cacheEntry->wzFileName));
252 return IDirectMusicObject_QueryInterface (pObject, riid, ppv);
255 HRESULT WINAPI IDirectMusicLoader8Impl_SetObject (LPDIRECTMUSICLOADER8 iface, LPDMUS_OBJECTDESC pDesc)
257 ICOM_THIS(IDirectMusicLoader8Impl,iface);
259 FIXME("(%p, %p): stub\n", This, pDesc);
264 HRESULT WINAPI IDirectMusicLoader8Impl_SetSearchDirectory (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, WCHAR* pwzPath, BOOL fClear)
266 ICOM_THIS(IDirectMusicLoader8Impl,iface);
268 TRACE("(%p, %s, %s, %d)\n", This, debugstr_guid(rguidClass), debugstr_w(pwzPath), fClear);
269 if (0 == strncmpW(This->wzSearchPath, pwzPath, MAX_PATH)) {
272 strncpyW(This->wzSearchPath, pwzPath, MAX_PATH);
277 HRESULT WINAPI IDirectMusicLoader8Impl_ScanDirectory (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, WCHAR* pwzFileExtension, WCHAR* pwzScanFileName)
279 ICOM_THIS(IDirectMusicLoader8Impl,iface);
281 FIXME("(%p, %s, %p, %p): stub\n", This, debugstr_guid(rguidClass), pwzFileExtension, pwzScanFileName);
286 HRESULT WINAPI IDirectMusicLoader8Impl_CacheObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject)
288 ICOM_THIS(IDirectMusicLoader8Impl,iface);
290 FIXME("(%p, %p): stub\n", This, pObject);
295 HRESULT WINAPI IDirectMusicLoader8Impl_ReleaseObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject)
297 ICOM_THIS(IDirectMusicLoader8Impl,iface);
299 FIXME("(%p, %p): stub\n", This, pObject);
304 HRESULT WINAPI IDirectMusicLoader8Impl_ClearCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass)
306 ICOM_THIS(IDirectMusicLoader8Impl,iface);
308 FIXME("(%p, %s): stub\n", This, debugstr_guid(rguidClass));
313 HRESULT WINAPI IDirectMusicLoader8Impl_EnableCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, BOOL fEnable)
315 ICOM_THIS(IDirectMusicLoader8Impl,iface);
317 FIXME("(%p, %s, %d): stub\n", This, debugstr_guid(rguidClass), fEnable);
322 HRESULT WINAPI IDirectMusicLoader8Impl_EnumObject (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, DWORD dwIndex, LPDMUS_OBJECTDESC pDesc)
324 ICOM_THIS(IDirectMusicLoader8Impl,iface);
326 FIXME("(%p, %s, %ld, %p): stub\n", This, debugstr_guid(rguidClass), dwIndex, pDesc);
331 /* IDirectMusicLoader8 Interface part follow: */
332 void WINAPI IDirectMusicLoader8Impl_CollectGarbage (LPDIRECTMUSICLOADER8 iface)
334 ICOM_THIS(IDirectMusicLoader8Impl,iface);
336 FIXME("(%p): stub\n", This);
339 HRESULT WINAPI IDirectMusicLoader8Impl_ReleaseObjectByUnknown (LPDIRECTMUSICLOADER8 iface, IUnknown* pObject)
341 ICOM_THIS(IDirectMusicLoader8Impl,iface);
343 FIXME("(%p, %p): stub\n", This, pObject);
348 HRESULT WINAPI IDirectMusicLoader8Impl_LoadObjectFromFile (LPDIRECTMUSICLOADER8 iface,
349 REFGUID rguidClassID,
350 REFIID iidInterfaceID,
354 ICOM_THIS(IDirectMusicLoader8Impl,iface);
355 DMUS_OBJECTDESC ObjDesc;
357 TRACE("(%p, %s, %s, %s, %p): wrapping to IDirectMusicLoader8Impl_GetObject\n", This, debugstr_guid(rguidClassID), debugstr_guid(iidInterfaceID), debugstr_w(pwzFilePath), ppObject);
359 ObjDesc.dwSize = sizeof(DMUS_OBJECTDESC);
360 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 */
361 ObjDesc.guidClass = *rguidClassID;
362 /* OK, MSDN says that search order is the following:
363 - current directory (DONE)
364 - windows search path (FIXME: how do I get that?)
365 - loader's search path (DONE)
367 /* search in current directory */
368 if (!SearchPathW (NULL, pwzFilePath, NULL,
369 sizeof(ObjDesc.wszFileName)/sizeof(WCHAR), ObjDesc.wszFileName, NULL) &&
370 /* search in loader's search path */
371 !SearchPathW (This->wzSearchPath, pwzFilePath, NULL,
372 sizeof(ObjDesc.wszFileName)/sizeof(WCHAR), ObjDesc.wszFileName, NULL))
374 /* cannot find file */
375 TRACE("cannot find file\n");
376 return DMUS_E_LOADER_FAILEDOPEN;
379 TRACE("full file path = %s\n", debugstr_w (ObjDesc.wszFileName));
381 return IDirectMusicLoader8Impl_GetObject (iface, &ObjDesc, iidInterfaceID, ppObject);
384 ICOM_VTABLE(IDirectMusicLoader8) DirectMusicLoader8_Vtbl =
386 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
387 IDirectMusicLoader8Impl_QueryInterface,
388 IDirectMusicLoader8Impl_AddRef,
389 IDirectMusicLoader8Impl_Release,
390 IDirectMusicLoader8Impl_GetObject,
391 IDirectMusicLoader8Impl_SetObject,
392 IDirectMusicLoader8Impl_SetSearchDirectory,
393 IDirectMusicLoader8Impl_ScanDirectory,
394 IDirectMusicLoader8Impl_CacheObject,
395 IDirectMusicLoader8Impl_ReleaseObject,
396 IDirectMusicLoader8Impl_ClearCache,
397 IDirectMusicLoader8Impl_EnableCache,
398 IDirectMusicLoader8Impl_EnumObject,
399 IDirectMusicLoader8Impl_CollectGarbage,
400 IDirectMusicLoader8Impl_ReleaseObjectByUnknown,
401 IDirectMusicLoader8Impl_LoadObjectFromFile
404 /* for ClassFactory */
405 HRESULT WINAPI DMUSIC_CreateDirectMusicLoader (LPCGUID lpcGUID, LPDIRECTMUSICLOADER8 *ppDMLoad, LPUNKNOWN pUnkOuter)
407 IDirectMusicLoader8Impl *dmloader;
409 TRACE("(%p,%p,%p)\n",lpcGUID, ppDMLoad, pUnkOuter);
410 if (IsEqualIID (lpcGUID, &IID_IDirectMusicLoader) ||
411 IsEqualIID (lpcGUID, &IID_IDirectMusicLoader8)) {
412 dmloader = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoader8Impl));
413 if (NULL == dmloader) {
414 *ppDMLoad = (LPDIRECTMUSICLOADER8)NULL;
415 return E_OUTOFMEMORY;
417 dmloader->lpVtbl = &DirectMusicLoader8_Vtbl;
419 MultiByteToWideChar (CP_ACP, 0, ".\\", -1, dmloader->wzSearchPath, MAX_PATH);
420 list_init (&dmloader->CacheList);
421 *ppDMLoad = (LPDIRECTMUSICLOADER8)dmloader;
425 WARN("No interface found\n");
426 return E_NOINTERFACE;
429 /* help function for IDirectMusicLoader8Impl_GetObject */
430 HRESULT WINAPI DMUSIC_GetDefaultGMPath (WCHAR wszPath[MAX_PATH])
433 DWORD returnType, sizeOfReturnBuffer = MAX_PATH;
434 char szPath[MAX_PATH];
436 if ((RegOpenKeyExA (HKEY_LOCAL_MACHINE, "Software\\Microsoft\\DirectMusic" , 0, KEY_READ, &hkDM) != ERROR_SUCCESS) ||
437 (RegQueryValueExA (hkDM, "GMFilePath", NULL, &returnType, szPath, &sizeOfReturnBuffer) != ERROR_SUCCESS)) {
438 WARN(": registry entry missing\n" );
441 /* FIXME: Check return types to ensure we're interpreting data right */
442 MultiByteToWideChar (CP_ACP, 0, szPath, -1, wszPath, MAX_PATH);