| /* IDirectMusicLoaderImpl |
| * |
| * Copyright (C) 2003-2004 Rok Mandeljc |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| */ |
| |
| #include "dmloader_private.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(dmloader); |
| |
| /***************************************************************************** |
| * IDirectMusicLoaderImpl implementation |
| */ |
| /* IUnknown/IDirectMusicLoader(8) part: */ |
| HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_QueryInterface (LPDIRECTMUSICLOADER8 iface, REFIID riid, LPVOID *ppobj) { |
| ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); |
| |
| TRACE("(%p, %s, %p)\n",This, debugstr_dmguid(riid), ppobj); |
| if (IsEqualIID (riid, &IID_IUnknown) || |
| IsEqualIID (riid, &IID_IDirectMusicLoader) || |
| IsEqualIID (riid, &IID_IDirectMusicLoader8)) { |
| IDirectMusicLoaderImpl_IDirectMusicLoader_AddRef (iface); |
| *ppobj = This; |
| return S_OK; |
| } |
| |
| WARN(": not found\n"); |
| return E_NOINTERFACE; |
| } |
| |
| ULONG WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_AddRef (LPDIRECTMUSICLOADER8 iface) { |
| ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); |
| TRACE("(%p): AddRef from %ld\n", This, This->dwRef); |
| return InterlockedIncrement (&This->dwRef); |
| } |
| |
| ULONG WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_Release (LPDIRECTMUSICLOADER8 iface) { |
| ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); |
| |
| DWORD dwRef = InterlockedDecrement (&This->dwRef); |
| TRACE("(%p): ReleaseRef to %ld\n", This, This->dwRef); |
| if (dwRef == 0) { |
| DMUSIC_DestroyDirectMusicLoaderImpl (iface); |
| HeapFree (GetProcessHeap(), 0, This); |
| } |
| |
| return dwRef; |
| } |
| |
| HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_GetObject (LPDIRECTMUSICLOADER8 iface, LPDMUS_OBJECTDESC pDesc, REFIID riid, LPVOID* ppv) { |
| ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); |
| HRESULT result = S_OK; |
| HRESULT ret = S_OK; /* used at the end of function, to determine whether everything went OK */ |
| |
| struct list *pEntry; |
| LPWINE_LOADER_ENTRY pObjectEntry = NULL; |
| LPSTREAM pStream; |
| IPersistStream* pPersistStream = NULL; |
| |
| LPDIRECTMUSICOBJECT pObject; |
| DMUS_OBJECTDESC GotDesc; |
| BOOL bCache; |
| |
| TRACE("(%p, %p, %s, %p): pDesc:\n%s", This, pDesc, debugstr_dmguid(riid), ppv, debugstr_DMUS_OBJECTDESC(pDesc)); |
| |
| /* sometimes it happens that guidClass is missing... which is a BadThingTM */ |
| if (!(pDesc->dwValidData & DMUS_OBJ_CLASS)) { |
| ERR(": guidClass not valid but needed\n"); |
| *ppv = NULL; |
| return DMUS_E_LOADER_NOCLASSID; |
| } |
| |
| /* OK, first we iterate thru the list of objects we know about; these are either loaded (GetObject, LoadObjectFromFile) |
| or set via SetObject; */ |
| TRACE(": looking if we have object in the cache or if it can be found via alias\n"); |
| LIST_FOR_EACH(pEntry, This->pObjects) { |
| LPWINE_LOADER_ENTRY pExistingEntry = LIST_ENTRY(pEntry, WINE_LOADER_ENTRY, entry); |
| if ((pDesc->dwValidData & DMUS_OBJ_OBJECT) && |
| (pExistingEntry->Desc.dwValidData & DMUS_OBJ_OBJECT) && |
| IsEqualGUID (&pDesc->guidObject, &pExistingEntry->Desc.guidObject)) { |
| TRACE(": found it by object GUID\n"); |
| /* I suppose such stuff can happen only when GUID for object is given (GUID_DefaultGMCollection) */ |
| if (pExistingEntry->bInvalidDefaultDLS) { |
| TRACE(": found faulty default DLS collection... enabling M$ compliant behaviour\n"); |
| return DMUS_E_LOADER_NOFILENAME; |
| } |
| if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) { |
| TRACE(": already loaded\n"); |
| return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv); |
| } else { |
| TRACE(": not loaded yet\n"); |
| pObjectEntry = pExistingEntry; |
| } |
| } |
| else if ((pDesc->dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) && |
| (pExistingEntry->Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) && |
| !strncmpW (pDesc->wszFileName, pExistingEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) { |
| TRACE(": found it by fullpath filename\n"); |
| if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) { |
| TRACE(": already loaded\n"); |
| return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv); |
| } else { |
| TRACE(": not loaded yet\n"); |
| pObjectEntry = pExistingEntry; |
| } |
| } |
| else if ((pDesc->dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) && |
| (pExistingEntry->Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) && |
| !strncmpW (pDesc->wszName, pExistingEntry->Desc.wszName, DMUS_MAX_NAME) && |
| !strncmpW (pDesc->wszCategory, pExistingEntry->Desc.wszCategory, DMUS_MAX_CATEGORY)) { |
| TRACE(": found it by name and category\n"); |
| if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) { |
| TRACE(": already loaded\n"); |
| return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv); |
| } else { |
| TRACE(": not loaded yet\n"); |
| pObjectEntry = pExistingEntry; |
| } |
| } |
| else if ((pDesc->dwValidData & DMUS_OBJ_NAME) && |
| (pExistingEntry->Desc.dwValidData & DMUS_OBJ_NAME) && |
| !strncmpW (pDesc->wszName, pExistingEntry->Desc.wszName, DMUS_MAX_NAME)) { |
| TRACE(": found it by name\n"); |
| if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) { |
| TRACE(": already loaded\n"); |
| return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv); |
| } else { |
| TRACE(": not loaded yet\n"); |
| pObjectEntry = pExistingEntry; |
| } |
| } |
| else if ((pDesc->dwValidData & DMUS_OBJ_FILENAME) && |
| (pExistingEntry->Desc.dwValidData & DMUS_OBJ_FILENAME) && |
| !strncmpW (pDesc->wszFileName, pExistingEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) { |
| TRACE(": found it by filename\n"); |
| if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) { |
| TRACE(": already loaded\n"); |
| return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv); |
| } else { |
| TRACE(": not loaded yet\n"); |
| pObjectEntry = pExistingEntry; |
| } |
| } |
| } |
| |
| /* basically, if we found alias, we use its descriptor to load... |
| else we use info we were given */ |
| if (pObjectEntry) { |
| TRACE(": found alias entry for requested object... using stored info\n"); |
| /* I think in certain cases it can happen that entry's descriptor lacks info |
| where to load from (e.g.: if we loaded from stream and then released object |
| from cache; then only it's CLSID, GUID and perhaps name are left); so just |
| overwrite info entry has (since it ought to be 100% correct) */ |
| DMUSIC_CopyDescriptor (pDesc, &pObjectEntry->Desc); |
| /*pDesc = &pObjectEntry->Desc; */ /* FIXME: is this OK? */ |
| } else { |
| TRACE(": no cache/alias entry found for requested object\n"); |
| } |
| |
| if (pDesc->dwValidData & DMUS_OBJ_URL) { |
| TRACE(": loading from URLs not supported yet\n"); |
| return DMUS_E_LOADER_FORMATNOTSUPPORTED; |
| } |
| else if (pDesc->dwValidData & DMUS_OBJ_FILENAME) { |
| /* load object from file */ |
| /* generate filename; if it's full path, don't add search |
| directory path, otherwise do */ |
| WCHAR wszFileName[MAX_PATH]; |
| |
| if (pDesc->dwValidData & DMUS_OBJ_FULLPATH) { |
| lstrcpyW(wszFileName, pDesc->wszFileName); |
| } else { |
| WCHAR *p, wszSearchPath[MAX_PATH]; |
| DMUSIC_GetLoaderSettings (iface, &pDesc->guidClass, wszSearchPath, NULL); |
| lstrcpyW(wszFileName, wszSearchPath); |
| p = wszFileName + lstrlenW(wszFileName); |
| if (p > wszFileName && p[-1] != '\\') *p++ = '\\'; |
| strcpyW(p, pDesc->wszFileName); |
| } |
| TRACE(": loading from file (%s)\n", debugstr_w(wszFileName)); |
| /* create stream and associate it with file */ |
| result = DMUSIC_CreateDirectMusicLoaderFileStream ((LPVOID*)&pStream); |
| if (FAILED(result)) { |
| ERR(": could not create loader stream\n"); |
| return result; |
| } |
| result = IDirectMusicLoaderFileStream_Attach (pStream, wszFileName, (LPDIRECTMUSICLOADER)iface); |
| if (FAILED(result)) { |
| ERR(": could not attach stream to file\n"); |
| return result; |
| } |
| |
| } |
| else if (pDesc->dwValidData & DMUS_OBJ_MEMORY) { |
| /* load object from resource */ |
| TRACE(": loading from resource\n"); |
| /* create stream and associate it with given resource */ |
| result = DMUSIC_CreateDirectMusicLoaderResourceStream ((LPVOID*)&pStream); |
| if (FAILED(result)) { |
| ERR(": could not create resource stream\n"); |
| return result; |
| } |
| result = IDirectMusicLoaderResourceStream_Attach (pStream, pDesc->pbMemData, pDesc->llMemLength, 0, (LPDIRECTMUSICLOADER)iface); |
| if (FAILED(result)) { |
| ERR(": could not attach stream to resource\n"); |
| return result; |
| } |
| } |
| else if (pDesc->dwValidData & DMUS_OBJ_STREAM) { |
| /* load object from stream */ |
| TRACE(": loading from stream\n"); |
| /* create universal stream and associate it with given one */ |
| result = DMUSIC_CreateDirectMusicLoaderGenericStream ((LPVOID*)&pStream); |
| if (FAILED(result)) { |
| ERR(": could not create generic stream\n"); |
| return result; |
| } |
| result = IDirectMusicLoaderGenericStream_Attach (pStream, pDesc->pStream, (LPDIRECTMUSICLOADER)iface); |
| if (FAILED(result)) { |
| ERR(": failed to attach stream\n"); |
| return result; |
| } |
| } else { |
| /* nowhere to load from */ |
| FIXME(": unknown/unsupported way of loading\n"); |
| return DMUS_E_LOADER_NOFILENAME; /* test shows this is returned */ |
| } |
| |
| /* create object */ |
| result = CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject); |
| if (FAILED(result)) { |
| ERR(": could not create object\n"); |
| return result; |
| } |
| /* acquire PersistStream interface */ |
| result = IDirectMusicObject_QueryInterface (pObject, &IID_IPersistStream, (LPVOID*)&pPersistStream); |
| if (FAILED(result)) { |
| ERR("failed to Query\n"); |
| return result; |
| } |
| /* load */ |
| result = IPersistStream_Load (pPersistStream, pStream); |
| if (result != S_OK) { |
| WARN(": failed to (completely) load object (%s)\n", debugstr_dmreturn(result)); |
| ret = DMUS_S_PARTIALLOAD /*result*/; |
| } |
| /* get descriptor */ |
| DM_STRUCT_INIT(&GotDesc); |
| result = IDirectMusicObject_GetDescriptor (pObject, &GotDesc); |
| /* set filename (if we loaded via filename) */ |
| if (pDesc->dwValidData & DMUS_OBJ_FILENAME) { |
| GotDesc.dwValidData |= (pDesc->dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)); |
| strcpyW (GotDesc.wszFileName, pDesc->wszFileName); |
| } |
| if (FAILED(result)) { |
| ERR(": failed to get descriptor\n"); |
| return result; |
| } |
| /* release all loading related stuff */ |
| IStream_Release (pStream); |
| IPersistStream_Release (pPersistStream); |
| |
| /* add object to cache/overwrite existing info (if cache is enabled) */ |
| DMUSIC_GetLoaderSettings (iface, &pDesc->guidClass, NULL, &bCache); |
| if (bCache) { |
| if (!pObjectEntry) { |
| pObjectEntry = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(WINE_LOADER_ENTRY)); |
| DM_STRUCT_INIT(&pObjectEntry->Desc); |
| if (pObject) { |
| DMUSIC_CopyDescriptor (&pObjectEntry->Desc, &GotDesc); |
| pObjectEntry->pObject = pObject; |
| pObjectEntry->bInvalidDefaultDLS = FALSE; |
| } |
| list_add_head (This->pObjects, &pObjectEntry->entry); |
| } else { |
| if (pObject) { |
| DMUSIC_CopyDescriptor (&pObjectEntry->Desc, &GotDesc); |
| pObjectEntry->pObject = pObject; |
| pObjectEntry->bInvalidDefaultDLS = FALSE; |
| } |
| } |
| TRACE(": filled in cache entry\n"); |
| } else TRACE(": caching disabled\n"); |
| |
| #if 0 |
| /* for debug purposes (e.g. to check if all files are cached) */ |
| TRACE("*** Loader's cache ***\n"); |
| int i = 0; |
| LIST_FOR_EACH (pEntry, This->pObjects) { |
| i++; |
| pObjectEntry = LIST_ENTRY(pEntry, WINE_LOADER_ENTRY, entry); |
| TRACE(": entry nr. %i:\n%s - bInvalidDefaultDLS = %i\n - pObject = %p\n", i, debugstr_DMUS_OBJECTDESC(&pObjectEntry->Desc), pObjectEntry->bInvalidDefaultDLS, pObjectEntry->pObject); |
| } |
| #endif |
| |
| result = IDirectMusicObject_QueryInterface (pObject, riid, ppv); |
| if (!bCache) IDirectMusicObject_Release (pObject); /* since loader's reference is not needed */ |
| /* if there was trouble with loading, and if no other error occurred, |
| we should return DMUS_S_PARTIALLOAD; else, error is returned */ |
| if (result == S_OK) |
| return ret; |
| else |
| return result; |
| } |
| |
| HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_SetObject (LPDIRECTMUSICLOADER8 iface, LPDMUS_OBJECTDESC pDesc) { |
| ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); |
| LPSTREAM pStream; |
| LPDIRECTMUSICOBJECT pObject; |
| DMUS_OBJECTDESC Desc; |
| struct list *pEntry; |
| LPWINE_LOADER_ENTRY pObjectEntry, pNewEntry; |
| |
| TRACE("(%p, %p): pDesc:\n%s\n", This, pDesc, debugstr_DMUS_OBJECTDESC(pDesc)); |
| |
| /* create stream and load additional info from it */ |
| if (pDesc->dwValidData & DMUS_OBJ_FILENAME) { |
| /* generate filename; if it's full path, don't add search |
| directory path, otherwise do */ |
| WCHAR wszFileName[MAX_PATH]; |
| |
| if (pDesc->dwValidData & DMUS_OBJ_FULLPATH) { |
| lstrcpyW(wszFileName, pDesc->wszFileName); |
| } else { |
| WCHAR *p; |
| WCHAR wszSearchPath[MAX_PATH]; |
| DMUSIC_GetLoaderSettings (iface, &pDesc->guidClass, wszSearchPath, NULL); |
| lstrcpyW(wszFileName, wszSearchPath); |
| p = wszFileName + lstrlenW(wszFileName); |
| if (p > wszFileName && p[-1] != '\\') *p++ = '\\'; |
| strcpyW(p, pDesc->wszFileName); |
| } |
| /* create stream */ |
| DMUSIC_CreateDirectMusicLoaderFileStream ((LPVOID*)&pStream); |
| /* attach stream */ |
| IDirectMusicLoaderFileStream_Attach (pStream, wszFileName, (LPDIRECTMUSICLOADER)iface); |
| } |
| else if (pDesc->dwValidData & DMUS_OBJ_STREAM) { |
| /* create stream */ |
| DMUSIC_CreateDirectMusicLoaderGenericStream ((LPVOID*)&pStream); |
| /* attach stream */ |
| IDirectMusicLoaderGenericStream_Attach (pStream, pDesc->pStream, (LPDIRECTMUSICLOADER)iface); |
| } |
| else if (pDesc->dwValidData & DMUS_OBJ_MEMORY) { |
| /* create stream */ |
| DMUSIC_CreateDirectMusicLoaderResourceStream ((LPVOID*)&pStream); |
| /* attach stream */ |
| IDirectMusicLoaderResourceStream_Attach (pStream, pDesc->pbMemData, pDesc->llMemLength, 0, (LPDIRECTMUSICLOADER)iface); |
| } |
| else { |
| ERR(": no way to get additional info\n"); |
| return DMUS_E_LOADER_FAILEDOPEN; |
| } |
| |
| /* create object */ |
| CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject); |
| |
| /* *sigh*... some ms objects have lousy implementation of ParseDescriptor that clears input descriptor :( */ |
| #ifdef NOW_WE_ARE_FREE |
| /* parse descriptor: we actually use input descriptor; fields that aren't available from stream remain, |
| otherwise real info is set */ |
| IDirectMusicObject_ParseDescriptor (pObject, pStream, pDesc); |
| #endif |
| /* hmph... due to some trouble I had with certain tests, we store current position and then set it back */ |
| DM_STRUCT_INIT(&Desc); |
| if (FAILED(IDirectMusicObject_ParseDescriptor (pObject, pStream, &Desc))) { |
| ERR(": couldn't parse descriptor\n"); |
| return DMUS_E_LOADER_FORMATNOTSUPPORTED; |
| } |
| |
| /* copy elements from parsed descriptor into input descriptor; this sets new info, overwriting if necessary, |
| but leaves info that's provided by input and not available from stream */ |
| DMUSIC_CopyDescriptor (pDesc, &Desc); |
| |
| /* release everything */ |
| IDirectMusicObject_Release (pObject); |
| IStream_Release (pStream); |
| |
| /* sometimes it happens that twisted programs call SetObject for same object twice... |
| in such cases, native loader returns S_OK and does nothing... a sound plan */ |
| LIST_FOR_EACH (pEntry, This->pObjects) { |
| pObjectEntry = LIST_ENTRY (pEntry, WINE_LOADER_ENTRY, entry); |
| if (!memcmp (&pObjectEntry->Desc, pDesc, sizeof(DMUS_OBJECTDESC))) { |
| TRACE(": exacly same entry already exists\n"); |
| return S_OK; |
| } |
| } |
| |
| /* add new entry */ |
| TRACE(": adding alias entry with following info: \n%s\n", debugstr_DMUS_OBJECTDESC(pDesc)); |
| pNewEntry = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(WINE_LOADER_ENTRY)); |
| /* use this function instead of pure memcpy due to streams (memcpy just copies pointer), |
| which is basically used further by app that called SetDescriptor... better safety than exception */ |
| DMUSIC_CopyDescriptor (&pNewEntry->Desc, pDesc); |
| list_add_head (This->pObjects, &pNewEntry->entry); |
| |
| return S_OK; |
| } |
| |
| HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_SetSearchDirectory (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, WCHAR* pwzPath, BOOL fClear) { |
| WCHAR wszCurrentPath[MAX_PATH]; |
| ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); |
| TRACE("(%p, %s, %s, %d)\n", This, debugstr_dmguid(rguidClass), debugstr_w(pwzPath), fClear); |
| FIXME(": fClear ignored\n"); |
| DMUSIC_GetLoaderSettings (iface, rguidClass, wszCurrentPath, NULL); |
| if (!strncmpW(wszCurrentPath, pwzPath, MAX_PATH)) { |
| return S_FALSE; |
| } |
| /* FIXME: check if path is valid; else return DMUS_E_LOADER_BADPATH */ |
| return DMUSIC_SetLoaderSettings (iface, rguidClass, pwzPath, NULL); |
| } |
| |
| HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ScanDirectory (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, WCHAR* pwzFileExtension, WCHAR* pwzScanFileName) { |
| static const WCHAR wszAny[] = {'*',0}; |
| WIN32_FIND_DATAW FileData; |
| HANDLE hSearch; |
| WCHAR wszSearchString[MAX_PATH]; |
| WCHAR *p; |
| HRESULT result; |
| ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); |
| TRACE("(%p, %s, %p, %p)\n", This, debugstr_dmguid(rguidClass), pwzFileExtension, pwzScanFileName); |
| if (IsEqualGUID (rguidClass, &GUID_DirectMusicAllTypes) || !DMUSIC_IsValidLoadableClass(rguidClass)) { |
| ERR(": rguidClass invalid CLSID\n"); |
| return REGDB_E_CLASSNOTREG; |
| } |
| |
| /* get search path for given class */ |
| DMUSIC_GetLoaderSettings (iface, rguidClass, wszSearchString, NULL); |
| |
| p = wszSearchString + lstrlenW(wszSearchString); |
| if (p > wszSearchString && p[-1] != '\\') *p++ = '\\'; |
| *p++ = '*'; /* any file */ |
| if (strcmpW (pwzFileExtension, wszAny)) *p++ = '.'; /* if we have actual extension, put a dot */ |
| strcpyW (p, pwzFileExtension); |
| |
| TRACE(": search string: %s\n", debugstr_w(wszSearchString)); |
| |
| hSearch = FindFirstFileW (wszSearchString, &FileData); |
| if (hSearch == INVALID_HANDLE_VALUE) { |
| TRACE(": no files found\n"); |
| return S_FALSE; |
| } |
| |
| do { |
| DMUS_OBJECTDESC Desc; |
| DM_STRUCT_INIT(&Desc); |
| Desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_DATE; |
| memcpy (&Desc.guidClass, rguidClass, sizeof(GUID)); |
| strcpyW (Desc.wszFileName, FileData.cFileName); |
| FileTimeToLocalFileTime (&FileData.ftCreationTime, &Desc.ftDate); |
| IDirectMusicLoader8_SetObject (iface, &Desc); |
| |
| if (!FindNextFileW (hSearch, &FileData)) { |
| if (GetLastError () == ERROR_NO_MORE_FILES) { |
| TRACE(": search completed\n"); |
| result = S_OK; |
| } else { |
| ERR(": could not get next file\n"); |
| result = E_FAIL; |
| } |
| FindClose (hSearch); |
| return result; |
| } |
| } while (1); |
| } |
| |
| HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_CacheObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject) { |
| DMUS_OBJECTDESC Desc; |
| HRESULT result = DMUS_E_LOADER_OBJECTNOTFOUND; |
| struct list *pEntry; |
| LPWINE_LOADER_ENTRY pObjectEntry = NULL; |
| |
| ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); |
| TRACE("(%p, %p)\n", This, pObject); |
| |
| /* get descriptor */ |
| DM_STRUCT_INIT(&Desc); |
| IDirectMusicObject_GetDescriptor (pObject, &Desc); |
| |
| /* now iterate thru list and check if we have alias (without object), corresponding |
| to descriptor of input object */ |
| LIST_FOR_EACH(pEntry, This->pObjects) { |
| pObjectEntry = LIST_ENTRY(pEntry, WINE_LOADER_ENTRY, entry); |
| if ((Desc.dwValidData & DMUS_OBJ_OBJECT) && |
| (pObjectEntry->Desc.dwValidData & DMUS_OBJ_OBJECT) && |
| IsEqualGUID (&Desc.guidObject, &pObjectEntry->Desc.guidObject)) { |
| TRACE(": found it by object GUID\n"); |
| if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject) |
| result = S_FALSE; |
| else |
| result = S_OK; |
| break; |
| } |
| else if ((Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) && |
| (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) && |
| !strncmpW (Desc.wszFileName, pObjectEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) { |
| TRACE(": found it by fullpath filename\n"); |
| if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject) |
| result = S_FALSE; |
| else |
| result = S_OK; |
| break; |
| } |
| else if ((Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) && |
| (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) && |
| !strncmpW (Desc.wszName, pObjectEntry->Desc.wszName, DMUS_MAX_NAME) && |
| !strncmpW (Desc.wszCategory, pObjectEntry->Desc.wszCategory, DMUS_MAX_CATEGORY)) { |
| TRACE(": found it by name and category\n"); |
| if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject) |
| result = S_FALSE; |
| else |
| result = S_OK; |
| break; |
| } |
| else if ((Desc.dwValidData & DMUS_OBJ_NAME) && |
| (pObjectEntry->Desc.dwValidData & DMUS_OBJ_NAME) && |
| !strncmpW (Desc.wszName, pObjectEntry->Desc.wszName, DMUS_MAX_NAME)) { |
| TRACE(": found it by name\n"); |
| if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject) |
| result = S_FALSE; |
| else |
| result = S_OK; |
| break; |
| } |
| else if ((Desc.dwValidData & DMUS_OBJ_FILENAME) && |
| (pObjectEntry->Desc.dwValidData & DMUS_OBJ_FILENAME) && |
| !strncmpW (Desc.wszFileName, pObjectEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) { |
| TRACE(": found it by filename\n"); |
| if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject) |
| result = S_FALSE; |
| else |
| result = S_OK; |
| break; |
| } |
| } |
| |
| /* if we found such alias, then set everything */ |
| if (result == S_OK) { |
| pObjectEntry->Desc.dwValidData &= DMUS_OBJ_LOADED; |
| pObjectEntry->pObject = pObject; |
| IDirectMusicObject_AddRef (pObjectEntry->pObject); |
| } |
| |
| return result; |
| } |
| |
| HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ReleaseObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject) { |
| DMUS_OBJECTDESC Desc; |
| struct list *pEntry; |
| LPWINE_LOADER_ENTRY pObjectEntry = NULL; |
| HRESULT result = S_FALSE; |
| |
| ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); |
| TRACE("(%p, %p)\n", This, pObject); |
| |
| /* get descriptor */ |
| DM_STRUCT_INIT(&Desc); |
| IDirectMusicObject_GetDescriptor (pObject, &Desc); |
| |
| /* iterate thru the list of objects we know about; check only those with DMUS_OBJ_LOADED */ |
| TRACE(": looking for the object in cache\n"); |
| LIST_FOR_EACH(pEntry, This->pObjects) { |
| pObjectEntry = LIST_ENTRY(pEntry, WINE_LOADER_ENTRY, entry); |
| if ((Desc.dwValidData & DMUS_OBJ_OBJECT) && |
| (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_OBJECT | DMUS_OBJ_LOADED)) && |
| IsEqualGUID (&Desc.guidObject, &pObjectEntry->Desc.guidObject)) { |
| TRACE(": found it by object GUID\n%s", debugstr_DMUS_OBJECTDESC(&pObjectEntry->Desc)); |
| result = S_OK; |
| break; |
| } |
| else if ((Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) && |
| (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_LOADED)) && |
| !strncmpW (Desc.wszFileName, pObjectEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) { |
| TRACE(": found it by fullpath filename\n"); |
| result = S_OK; |
| break; |
| } |
| else if ((Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) && |
| (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY | DMUS_OBJ_LOADED)) && |
| !strncmpW (Desc.wszName, pObjectEntry->Desc.wszName, DMUS_MAX_NAME) && |
| !strncmpW (Desc.wszCategory, pObjectEntry->Desc.wszCategory, DMUS_MAX_CATEGORY)) { |
| TRACE(": found it by name and category\n"); |
| result = S_OK; |
| break; |
| } |
| else if ((Desc.dwValidData & DMUS_OBJ_NAME) && |
| (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_LOADED)) && |
| !strncmpW (Desc.wszName, pObjectEntry->Desc.wszName, DMUS_MAX_NAME)) { |
| TRACE(": found it by name\n"); |
| result = S_OK; |
| break; |
| } |
| else if ((Desc.dwValidData & DMUS_OBJ_FILENAME) && |
| (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_LOADED)) && |
| !strncmpW (Desc.wszFileName, pObjectEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) { |
| TRACE(": found it by filename\n"); |
| result = S_OK; |
| break; |
| } |
| } |
| if (result == S_OK) { |
| /*TRACE(": releasing: \n%s - bInvalidDefaultDLS = %i\n - pObject = %p\n", debugstr_DMUS_OBJECTDESC(&pObjectEntry->Desc), pObjectEntry->bInvalidDefaultDLS, pObjectEntry->pObject); */ |
| IDirectMusicObject_Release (pObjectEntry->pObject); |
| pObjectEntry->pObject = NULL; |
| pObjectEntry->Desc.dwValidData &= ~DMUS_OBJ_LOADED; |
| } |
| return result; |
| } |
| |
| HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ClearCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass) { |
| struct list *pEntry; |
| LPWINE_LOADER_ENTRY pObjectEntry; |
| ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); |
| TRACE("(%p, %s)\n", This, debugstr_dmguid(rguidClass)); |
| |
| LIST_FOR_EACH (pEntry, This->pObjects) { |
| pObjectEntry = LIST_ENTRY (pEntry, WINE_LOADER_ENTRY, entry); |
| |
| if ((IsEqualGUID (rguidClass, &GUID_DirectMusicAllTypes) || IsEqualGUID (rguidClass, &pObjectEntry->Desc.guidClass)) && |
| (pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED)) { |
| /* basically, wrap to ReleaseObject for each object found */ |
| IDirectMusicLoader8_ReleaseObject (iface, pObjectEntry->pObject); |
| } |
| } |
| |
| return S_OK; |
| } |
| |
| HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_EnableCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, BOOL fEnable) { |
| ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); |
| BOOL bCurrent; |
| TRACE("(%p, %s, %d)\n", This, debugstr_dmguid(rguidClass), fEnable); |
| DMUSIC_GetLoaderSettings (iface, rguidClass, NULL, &bCurrent); |
| if (bCurrent == fEnable) |
| return S_FALSE; |
| else |
| return DMUSIC_SetLoaderSettings (iface, rguidClass, NULL, &fEnable); |
| } |
| |
| HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_EnumObject (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, DWORD dwIndex, LPDMUS_OBJECTDESC pDesc) { |
| DWORD dwCount = 0; |
| struct list *pEntry; |
| LPWINE_LOADER_ENTRY pObjectEntry; |
| ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); |
| TRACE("(%p, %s, %ld, %p)\n", This, debugstr_dmguid(rguidClass), dwIndex, pDesc); |
| |
| DM_STRUCT_INIT(pDesc); |
| |
| LIST_FOR_EACH (pEntry, This->pObjects) { |
| pObjectEntry = LIST_ENTRY (pEntry, WINE_LOADER_ENTRY, entry); |
| |
| if (IsEqualGUID (rguidClass, &GUID_DirectMusicAllTypes) || IsEqualGUID (rguidClass, &pObjectEntry->Desc.guidClass)) { |
| if (dwCount == dwIndex) { |
| memcpy (pDesc, &pObjectEntry->Desc, sizeof(DMUS_OBJECTDESC)); |
| /* we aren't supposed to reveal this info */ |
| pDesc->dwValidData &= ~(DMUS_OBJ_MEMORY | DMUS_OBJ_STREAM); |
| pDesc->pbMemData = NULL; |
| pDesc->llMemLength = 0; |
| pDesc->pStream = NULL; |
| return S_OK; |
| } |
| dwCount++; |
| } |
| } |
| |
| TRACE(": not found\n"); |
| return S_FALSE; |
| } |
| |
| void WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_CollectGarbage (LPDIRECTMUSICLOADER8 iface) { |
| ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); |
| FIXME("(%p): stub\n", This); |
| } |
| |
| HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ReleaseObjectByUnknown (LPDIRECTMUSICLOADER8 iface, IUnknown* pObject) { |
| ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); |
| HRESULT result; |
| LPDIRECTMUSICOBJECT pObjectInterface; |
| |
| TRACE("(%p, %p)\n", This, pObject); |
| |
| if (IsBadReadPtr (pObject, sizeof(LPUNKNOWN))) { |
| ERR(": pObject bad write pointer\n"); |
| return E_POINTER; |
| } |
| /* we simply get IDirectMusicObject interface */ |
| result = IUnknown_QueryInterface (pObject, &IID_IDirectMusicObject, (LPVOID*)&pObjectInterface); |
| if (FAILED(result)) return result; |
| /* and release it in old-fashioned way */ |
| result = IDirectMusicLoader8_ReleaseObject (iface, pObjectInterface); |
| IDirectMusicObject_Release (pObjectInterface); |
| |
| return result; |
| } |
| |
| HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_LoadObjectFromFile (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClassID, REFIID iidInterfaceID, WCHAR* pwzFilePath, void** ppObject) { |
| ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); |
| DMUS_OBJECTDESC ObjDesc; |
| WCHAR wszLoaderSearchPath[MAX_PATH]; |
| |
| TRACE("(%p, %s, %s, %s, %p): wrapping to IDirectMusicLoaderImpl_GetObject\n", This, debugstr_dmguid(rguidClassID), debugstr_dmguid(iidInterfaceID), debugstr_w(pwzFilePath), ppObject); |
| |
| DM_STRUCT_INIT(&ObjDesc); |
| 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 */ |
| memcpy (&ObjDesc.guidClass, rguidClassID, sizeof(CLSID)); |
| /* OK, MSDN says that search order is the following: |
| - current directory (DONE) |
| - windows search path (FIXME: how do I get that?) |
| - loader's search path (DONE) |
| */ |
| DMUSIC_GetLoaderSettings (iface, rguidClassID, wszLoaderSearchPath, NULL); |
| /* search in current directory */ |
| if (!SearchPathW (NULL, pwzFilePath, NULL, sizeof(ObjDesc.wszFileName)/sizeof(WCHAR), ObjDesc.wszFileName, NULL) && |
| /* search in loader's search path */ |
| !SearchPathW (wszLoaderSearchPath, pwzFilePath, NULL, sizeof(ObjDesc.wszFileName)/sizeof(WCHAR), ObjDesc.wszFileName, NULL)) { |
| /* cannot find file */ |
| TRACE(": cannot find file\n"); |
| return DMUS_E_LOADER_FAILEDOPEN; |
| } |
| |
| TRACE(": full file path = %s\n", debugstr_w (ObjDesc.wszFileName)); |
| |
| return IDirectMusicLoaderImpl_IDirectMusicLoader_GetObject (iface, &ObjDesc, iidInterfaceID, ppObject); |
| } |
| |
| IDirectMusicLoader8Vtbl DirectMusicLoader_Loader_Vtbl = { |
| IDirectMusicLoaderImpl_IDirectMusicLoader_QueryInterface, |
| IDirectMusicLoaderImpl_IDirectMusicLoader_AddRef, |
| IDirectMusicLoaderImpl_IDirectMusicLoader_Release, |
| IDirectMusicLoaderImpl_IDirectMusicLoader_GetObject, |
| IDirectMusicLoaderImpl_IDirectMusicLoader_SetObject, |
| IDirectMusicLoaderImpl_IDirectMusicLoader_SetSearchDirectory, |
| IDirectMusicLoaderImpl_IDirectMusicLoader_ScanDirectory, |
| IDirectMusicLoaderImpl_IDirectMusicLoader_CacheObject, |
| IDirectMusicLoaderImpl_IDirectMusicLoader_ReleaseObject, |
| IDirectMusicLoaderImpl_IDirectMusicLoader_ClearCache, |
| IDirectMusicLoaderImpl_IDirectMusicLoader_EnableCache, |
| IDirectMusicLoaderImpl_IDirectMusicLoader_EnumObject, |
| IDirectMusicLoaderImpl_IDirectMusicLoader_CollectGarbage, |
| IDirectMusicLoaderImpl_IDirectMusicLoader_ReleaseObjectByUnknown, |
| IDirectMusicLoaderImpl_IDirectMusicLoader_LoadObjectFromFile |
| }; |
| |
| /* for ClassFactory */ |
| HRESULT WINAPI DMUSIC_CreateDirectMusicLoaderImpl (LPCGUID lpcGUID, LPVOID *ppobj, LPUNKNOWN pUnkOuter) { |
| IDirectMusicLoaderImpl *obj; |
| DMUS_OBJECTDESC Desc; |
| LPWINE_LOADER_ENTRY pDefaultDLSEntry; |
| struct list *pEntry; |
| |
| TRACE("(%s, %p, %p)\n", debugstr_dmguid(lpcGUID), ppobj, pUnkOuter); |
| obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoaderImpl)); |
| if (NULL == obj) { |
| *ppobj = (LPDIRECTMUSICLOADER8)NULL; |
| return E_OUTOFMEMORY; |
| } |
| obj->LoaderVtbl = &DirectMusicLoader_Loader_Vtbl; |
| obj->dwRef = 0; /* will be inited with QueryInterface */ |
| /* init critical section */ |
| /* init cache/alias list */ |
| /*InitializeCriticalSection (&obj->CritSect); */ |
| obj->pObjects = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(struct list)); |
| list_init (obj->pObjects); |
| /* init settings */ |
| obj->pClassSettings = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(struct list)); |
| list_init (obj->pClassSettings); |
| DMUSIC_InitLoaderSettings ((LPDIRECTMUSICLOADER8)obj); |
| |
| /* set default DLS collection (via SetObject... so that loading via DMUS_OBJ_OBJECT is possible) */ |
| DM_STRUCT_INIT(&Desc); |
| Desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_OBJECT; |
| memcpy (&Desc.guidClass, &CLSID_DirectMusicCollection, sizeof(CLSID)); |
| memcpy (&Desc.guidObject, &GUID_DefaultGMCollection, sizeof(GUID)); |
| DMUSIC_GetDefaultGMPath (Desc.wszFileName); |
| IDirectMusicLoader_SetObject ((LPDIRECTMUSICLOADER8)obj, &Desc); |
| /* and now the workaroundTM for "invalid" default DLS; basically, |
| my tests showed that if GUID chunk is present in default DLS |
| collection, loader treats it as "invalid" and returns |
| DMUS_E_LOADER_NOFILENAME for all requests for it; basically, we check |
| if out input guidObject was overwritten */ |
| pEntry = list_head (obj->pObjects); |
| pDefaultDLSEntry = LIST_ENTRY (pEntry, WINE_LOADER_ENTRY, entry); |
| if (!IsEqualGUID(&Desc.guidObject, &GUID_DefaultGMCollection)) { |
| pDefaultDLSEntry->bInvalidDefaultDLS = TRUE; |
| } |
| |
| /* increase number of instances */ |
| InterlockedIncrement (&dwDirectMusicLoader); |
| |
| return IDirectMusicLoaderImpl_IDirectMusicLoader_QueryInterface ((LPDIRECTMUSICLOADER8)obj, lpcGUID, ppobj); |
| } |
| |
| HRESULT WINAPI DMUSIC_DestroyDirectMusicLoaderImpl (LPDIRECTMUSICLOADER8 iface) { |
| ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); |
| |
| TRACE("(%p)\n", This); |
| |
| /* firstly, release the cache */ |
| IDirectMusicLoader8_ClearCache (iface, &GUID_DirectMusicAllTypes); |
| /* FIXME: release all allocated entries */ |
| /* destroy critical section */ |
| /*DeleteCriticalSection (&This->CritSect); */ |
| |
| /* decrease number of instances */ |
| InterlockedDecrement (&dwDirectMusicLoader); |
| |
| return S_OK; |
| } |
| |
| /* help function for DMUSIC_SetDefaultDLS */ |
| HRESULT WINAPI DMUSIC_GetDefaultGMPath (WCHAR wszPath[MAX_PATH]) { |
| HKEY hkDM; |
| DWORD returnType, sizeOfReturnBuffer = MAX_PATH; |
| char szPath[MAX_PATH]; |
| |
| if ((RegOpenKeyExA (HKEY_LOCAL_MACHINE, "Software\\Microsoft\\DirectMusic" , 0, KEY_READ, &hkDM) != ERROR_SUCCESS) || |
| (RegQueryValueExA (hkDM, "GMFilePath", NULL, &returnType, szPath, &sizeOfReturnBuffer) != ERROR_SUCCESS)) { |
| WARN(": registry entry missing\n" ); |
| return E_FAIL; |
| } |
| /* FIXME: Check return types to ensure we're interpreting data right */ |
| MultiByteToWideChar (CP_ACP, 0, szPath, -1, wszPath, MAX_PATH); |
| |
| return S_OK; |
| } |
| |
| /* help function for retrieval of search path and caching option for certain class */ |
| HRESULT WINAPI DMUSIC_GetLoaderSettings (LPDIRECTMUSICLOADER8 iface, REFGUID pClassID, WCHAR* wszSearchPath, LPBOOL pbCache) { |
| ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); |
| struct list *pEntry; |
| TRACE(": (%p, %s, %p, %p)\n", This, debugstr_dmguid(pClassID), wszSearchPath, pbCache); |
| |
| LIST_FOR_EACH(pEntry, This->pClassSettings) { |
| LPWINE_LOADER_OPTION pOptionEntry = LIST_ENTRY(pEntry, WINE_LOADER_OPTION, entry); |
| if (IsEqualCLSID (pClassID, &pOptionEntry->guidClass)) { |
| if (wszSearchPath) |
| strcpyW(wszSearchPath, pOptionEntry->wszSearchPath); |
| if (pbCache) |
| *pbCache = pOptionEntry->bCache; |
| return S_OK; |
| } |
| } |
| return S_FALSE; |
| } |
| |
| /* help function for setting search path and caching option for certain class */ |
| HRESULT WINAPI DMUSIC_SetLoaderSettings (LPDIRECTMUSICLOADER8 iface, REFGUID pClassID, WCHAR* wszSearchPath, LPBOOL pbCache) { |
| ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); |
| struct list *pEntry; |
| HRESULT result = S_FALSE; /* in case pClassID != GUID_DirectMusicAllTypes and not a valid CLSID */ |
| TRACE(": (%p, %s, %p, %p)\n", This, debugstr_dmguid(pClassID), wszSearchPath, pbCache); |
| |
| LIST_FOR_EACH(pEntry, This->pClassSettings) { |
| LPWINE_LOADER_OPTION pOptionEntry = LIST_ENTRY(pEntry, WINE_LOADER_OPTION, entry); |
| /* well, either we have GUID_DirectMusicAllTypes and need to set it to all, |
| or specific CLSID is given and we set it only to it */ |
| if (IsEqualGUID (pClassID, &GUID_DirectMusicAllTypes) || |
| IsEqualCLSID (pClassID, &pOptionEntry->guidClass)) { |
| if (wszSearchPath) |
| strcpyW(pOptionEntry->wszSearchPath, wszSearchPath); |
| if (pbCache) |
| pOptionEntry->bCache = *pbCache; |
| result = S_OK; |
| } |
| } |
| |
| return result; |
| } |
| |
| HRESULT WINAPI DMUSIC_InitLoaderSettings (LPDIRECTMUSICLOADER8 iface) { |
| ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); |
| |
| /* hard-coded list of classes */ |
| static REFCLSID classes[] = { |
| &CLSID_DirectMusicAudioPathConfig, |
| &CLSID_DirectMusicBand, |
| &CLSID_DirectMusicContainer, |
| &CLSID_DirectMusicCollection, |
| &CLSID_DirectMusicChordMap, |
| &CLSID_DirectMusicSegment, |
| &CLSID_DirectMusicScript, |
| &CLSID_DirectMusicSong, |
| &CLSID_DirectMusicStyle, |
| &CLSID_DirectMusicGraph, |
| &CLSID_DirectSoundWave |
| }; |
| |
| unsigned int i; |
| WCHAR wszCurrent[MAX_PATH]; |
| |
| TRACE(": (%p)\n", This); |
| GetCurrentDirectoryW (MAX_PATH, wszCurrent); |
| |
| for (i = 0; i < sizeof(classes)/sizeof(REFCLSID); i++) { |
| LPWINE_LOADER_OPTION pNewSetting = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(WINE_LOADER_OPTION)); |
| memcpy (&pNewSetting->guidClass, classes[i], sizeof(CLSID)); |
| strcpyW (pNewSetting->wszSearchPath, wszCurrent); |
| pNewSetting->bCache = TRUE; |
| list_add_tail (This->pClassSettings, &pNewSetting->entry); |
| } |
| |
| return S_OK; |
| } |
| |
| HRESULT WINAPI DMUSIC_CopyDescriptor (LPDMUS_OBJECTDESC pDst, LPDMUS_OBJECTDESC pSrc) { |
| TRACE(": copy \n%s", debugstr_DMUS_OBJECTDESC(pSrc)); |
| /* copy field by field */ |
| if (pSrc->dwValidData & DMUS_OBJ_CLASS) memcpy (&pDst->guidClass, &pSrc->guidClass, sizeof(CLSID)); |
| if (pSrc->dwValidData & DMUS_OBJ_OBJECT) memcpy (&pDst->guidObject, &pSrc->guidObject, sizeof(GUID)); |
| if (pSrc->dwValidData & DMUS_OBJ_DATE) memcpy (&pDst->ftDate, &pSrc->ftDate, sizeof(FILETIME)); |
| if (pSrc->dwValidData & DMUS_OBJ_VERSION) memcpy (&pDst->vVersion, &pSrc->vVersion, sizeof(DMUS_VERSION)); |
| if (pSrc->dwValidData & DMUS_OBJ_NAME) strcpyW (pDst->wszName, pSrc->wszName); |
| if (pSrc->dwValidData & DMUS_OBJ_CATEGORY) strcpyW (pDst->wszCategory, pSrc->wszCategory); |
| if (pSrc->dwValidData & DMUS_OBJ_FILENAME) strcpyW (pDst->wszFileName, pSrc->wszFileName); |
| if (pSrc->dwValidData & DMUS_OBJ_STREAM) IStream_Clone (pSrc->pStream, &pDst->pStream); |
| if (pSrc->dwValidData & DMUS_OBJ_MEMORY) { |
| pDst->pbMemData = pSrc->pbMemData; |
| pDst->llMemLength = pSrc->llMemLength; |
| } |
| /* set flags */ |
| pDst->dwValidData |= pSrc->dwValidData; |
| return S_OK; |
| } |
| |
| BOOL WINAPI DMUSIC_IsValidLoadableClass (REFCLSID pClassID) { |
| if (IsEqualCLSID(pClassID, &CLSID_DirectMusicAudioPathConfig) || |
| IsEqualCLSID(pClassID, &CLSID_DirectMusicBand) || |
| IsEqualCLSID(pClassID, &CLSID_DirectMusicContainer) || |
| IsEqualCLSID(pClassID, &CLSID_DirectMusicCollection) || |
| IsEqualCLSID(pClassID, &CLSID_DirectMusicChordMap) || |
| IsEqualCLSID(pClassID, &CLSID_DirectMusicSegment) || |
| IsEqualCLSID(pClassID, &CLSID_DirectMusicScript) || |
| IsEqualCLSID(pClassID, &CLSID_DirectMusicSong) || |
| IsEqualCLSID(pClassID, &CLSID_DirectMusicStyle) || |
| IsEqualCLSID(pClassID, &CLSID_DirectMusicGraph) || |
| IsEqualCLSID(pClassID, &CLSID_DirectSoundWave) || |
| IsEqualCLSID(pClassID, &GUID_DirectMusicAllTypes)) |
| return TRUE; |
| else |
| return FALSE; |
| } |