Logo Search packages:      
Sourcecode: wine version File versions

loader.c

/* 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 Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include "dmloader_private.h"

WINE_DEFAULT_DEBUG_CHANNEL(dmloader);

static HRESULT DMUSIC_InitLoaderSettings (LPDIRECTMUSICLOADER8 iface);
static HRESULT DMUSIC_GetLoaderSettings (LPDIRECTMUSICLOADER8 iface, REFGUID pClassID, WCHAR* wszSearchPath, LPBOOL pbCache);
static HRESULT DMUSIC_SetLoaderSettings (LPDIRECTMUSICLOADER8 iface, REFGUID pClassID, WCHAR* wszSearchPath, LPBOOL pbCache);

static HRESULT 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) pDst->guidClass = pSrc->guidClass;
      if (pSrc->dwValidData & DMUS_OBJ_OBJECT) pDst->guidObject = pSrc->guidObject;
      if (pSrc->dwValidData & DMUS_OBJ_DATE) pDst->ftDate = pSrc->ftDate;
      if (pSrc->dwValidData & DMUS_OBJ_VERSION) pDst->vVersion = pSrc->vVersion;
      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;
}


static BOOL 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;
}

/*****************************************************************************
 * IDirectMusicLoaderImpl implementation
 */
/* IUnknown/IDirectMusicLoader(8) part: */

static 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)) {
            IDirectMusicLoader_AddRef (iface);
            *ppobj = This;
            return S_OK;
      }
      
      WARN(": not found\n");
      return E_NOINTERFACE;
}

static ULONG WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_AddRef (LPDIRECTMUSICLOADER8 iface) {
      ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
      TRACE("(%p): AddRef from %d\n", This, This->dwRef);
      return InterlockedIncrement (&This->dwRef);
}

static ULONG WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_Release (LPDIRECTMUSICLOADER8 iface) {
      ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
      
      DWORD dwRef = InterlockedDecrement (&This->dwRef);
      TRACE("(%p): ReleaseRef to %d\n", This, This->dwRef);
      if (dwRef == 0) {
            /* firstly, release the cache */
            IDirectMusicLoader8_ClearCache (iface, &GUID_DirectMusicAllTypes);
            /* FIXME: release all allocated entries */
            /* destroy critical section */
            /*This->CritSect.DebugInfo->Spare[0] = 0;
              DeleteCriticalSection (&This->CritSect); */
            HeapFree (GetProcessHeap(), 0, This);

            /* decrease number of instances */
            InterlockedDecrement (&dwDirectMusicLoader);
      }
      
      return dwRef;
}

static 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\n", 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 file stream\n");
                  return result;
            }
            result = IDirectMusicLoaderFileStream_Attach (pStream, wszFileName, iface);
            if (FAILED(result)) {
                  ERR(": could not attach stream to file\n");
                  IStream_Release (pStream);
                  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, iface);
            if (FAILED(result)) {
                  ERR(": could not attach stream to resource\n");
                  IStream_Release (pStream);
                  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, iface);
            if (FAILED(result)) {
                  ERR(": failed to attach stream\n");
                  IStream_Release (pStream);
                  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\n  - 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;
}

static 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;
      HRESULT hr;

      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 */
            hr = DMUSIC_CreateDirectMusicLoaderFileStream ((LPVOID*)&pStream);
            if (FAILED(hr)) {
                  ERR(": could not create file stream\n");
                  return DMUS_E_LOADER_FAILEDOPEN;
            }
            /* attach stream */
            hr = IDirectMusicLoaderFileStream_Attach (pStream, wszFileName, iface);
            if (FAILED(hr)) {
                  ERR(": could not attach stream to file\n");
                  IStream_Release (pStream);
                  return DMUS_E_LOADER_FAILEDOPEN;
            }
      }
      else if (pDesc->dwValidData & DMUS_OBJ_STREAM) {      
            /* create stream */
            hr = DMUSIC_CreateDirectMusicLoaderGenericStream ((LPVOID*)&pStream);
            if (FAILED(hr)) {
                  ERR(": could not create generic stream\n");
                  return DMUS_E_LOADER_FAILEDOPEN;
            }
            /* attach stream */
            hr = IDirectMusicLoaderGenericStream_Attach (pStream, pDesc->pStream, iface);
            if (FAILED(hr)) {
                  ERR(": could not attach stream\n");
                  IStream_Release (pStream);
                  return DMUS_E_LOADER_FAILEDOPEN;
            }
      }
      else if (pDesc->dwValidData & DMUS_OBJ_MEMORY) {
            /* create stream */
            hr = DMUSIC_CreateDirectMusicLoaderResourceStream ((LPVOID*)&pStream);
            if (FAILED(hr)) {
                  ERR(": could not create resource stream\n");
                  return DMUS_E_LOADER_FAILEDOPEN;
            }
            /* attach stream */
            hr = IDirectMusicLoaderResourceStream_Attach (pStream, pDesc->pbMemData, pDesc->llMemLength, 0, iface);
            if (FAILED(hr)) {
                  ERR(": could not attach stream to resource\n");
                  IStream_Release (pStream);
                  return DMUS_E_LOADER_FAILEDOPEN;
            }
      }
      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;
}

static 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);
}

static 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;
            Desc.guidClass = *rguidClass;
            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);
}

static 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;
}

static 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\n", 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;
}

static 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;
}

static 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);
}

static 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, %d, %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) {
                        *pDesc = pObjectEntry->Desc;
                        /* 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;
}

static void WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_CollectGarbage (LPDIRECTMUSICLOADER8 iface) {
      ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface);
      FIXME("(%p): stub\n", This);
}

static 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;
}

static 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 */
      ObjDesc.guidClass = *rguidClassID;
      /* 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);
}

static const 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
};

/* help function for DMUSIC_SetDefaultDLS */
static HRESULT 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, (LPBYTE) 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;
}

/* 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 = 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->CritSect.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectMusicLoaderImpl.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;
      Desc.guidClass = CLSID_DirectMusicCollection;
      Desc.guidObject = GUID_DefaultGMCollection;
      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);
}

/* help function for retrieval of search path and caching option for certain class */
static HRESULT 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 */
static HRESULT 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;
}

static HRESULT 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));
            pNewSetting->guidClass = *classes[i];
            strcpyW (pNewSetting->wszSearchPath, wszCurrent);
            pNewSetting->bCache = TRUE;
            list_add_tail (This->pClassSettings, &pNewSetting->entry);
      }

      return S_OK;
}

Generated by  Doxygen 1.6.0   Back to index