text: /* IDirectMusicSegTriggerTrack Implementation
   *
   * Copyright (C) 2003-2004 Rok Mandeljc
   * Copyright (C) 2003-2004 Raphael Junqueira
   *
   * 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 "dmime_private.h"
  #include "dmobject.h"
  
  WINE_DEFAULT_DEBUG_CHANNEL(dmime);
  WINE_DECLARE_DEBUG_CHANNEL(dmfile);
  
  /*****************************************************************************
   * IDirectMusicSegTriggerTrack implementation
   */
  typedef struct IDirectMusicSegTriggerTrack {
      IDirectMusicTrack8 IDirectMusicTrack8_iface;
      struct dmobject dmobj;/* IPersistStream only */
      LONG ref;
      struct list Items;
  } IDirectMusicSegTriggerTrack;
  
  /* IDirectMusicSegTriggerTrack IDirectMusicTrack8 part: */
  static inline IDirectMusicSegTriggerTrack *impl_from_IDirectMusicTrack8(IDirectMusicTrack8 *iface)
  {
      return CONTAINING_RECORD(iface, IDirectMusicSegTriggerTrack, IDirectMusicTrack8_iface);
  }
  
  static HRESULT WINAPI IDirectMusicTrack8Impl_QueryInterface(IDirectMusicTrack8 *iface, REFIID riid,
          void **ret_iface)
  {
      IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
  
      TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ret_iface);
  
      *ret_iface = NULL;
  
      if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectMusicTrack) ||
              IsEqualIID(riid, &IID_IDirectMusicTrack8))
          *ret_iface = iface;
      else if (IsEqualIID(riid, &IID_IPersistStream))
          *ret_iface = &This->dmobj.IPersistStream_iface;
      else {
          WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ret_iface);
          return E_NOINTERFACE;
      }
  
      IUnknown_AddRef((IUnknown*)*ret_iface);
      return S_OK;
  }
  
  static ULONG WINAPI IDirectMusicTrack8Impl_AddRef(IDirectMusicTrack8 *iface)
  {
      IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
      LONG ref = InterlockedIncrement(&This->ref);
  
      TRACE("(%p) ref=%d\n", This, ref);
  
      return ref;
  }
  
  static ULONG WINAPI IDirectMusicTrack8Impl_Release(IDirectMusicTrack8 *iface)
  {
      IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
      LONG ref = InterlockedDecrement(&This->ref);
  
      TRACE("(%p) ref=%d\n", This, ref);
  
      if (!ref) {
          HeapFree(GetProcessHeap(), 0, This);
          DMIME_UnlockModule();
      }
  
      return ref;
  }
  
  static HRESULT WINAPI IDirectMusicTrack8Impl_Init(IDirectMusicTrack8 *iface,
          IDirectMusicSegment *pSegment)
  {
          IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
  	FIXME("(%p, %p): stub\n", This, pSegment);
  	return S_OK;
  }
  
  static HRESULT WINAPI IDirectMusicTrack8Impl_InitPlay(IDirectMusicTrack8 *iface,
          IDirectMusicSegmentState *pSegmentState, IDirectMusicPerformance *pPerformance,
          void **ppStateData, DWORD dwVirtualTrack8ID, DWORD dwFlags)
  {
          IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
  	FIXME("(%p, %p, %p, %p, %d, %d): stub\n", This, pSegmentState, pPerformance, ppStateData, dwVirtualTrack8ID, dwFlags);
  	return S_OK;
  }
  
  static HRESULT WINAPI IDirectMusicTrack8Impl_EndPlay(IDirectMusicTrack8 *iface, void *pStateData)
  {
          IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
  	FIXME("(%p, %p): stub\n", This, pStateData);
  	return S_OK;
  }
  
  static HRESULT WINAPI IDirectMusicTrack8Impl_Play(IDirectMusicTrack8 *iface, void *pStateData,
          MUSIC_TIME mtStart, MUSIC_TIME mtEnd, MUSIC_TIME mtOffset, DWORD dwFlags,
          IDirectMusicPerformance *pPerf, IDirectMusicSegmentState *pSegSt, DWORD dwVirtualID)
  {
          IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
  	FIXME("(%p, %p, %d, %d, %d, %d, %p, %p, %d): stub\n", This, pStateData, mtStart, mtEnd, mtOffset, dwFlags, pPerf, pSegSt, dwVirtualID);
  	return S_OK;
  }
  
  static HRESULT WINAPI IDirectMusicTrack8Impl_GetParam(IDirectMusicTrack8 *iface, REFGUID rguidType,
          MUSIC_TIME mtTime, MUSIC_TIME *pmtNext, void *pParam)
  {
          IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
  	FIXME("(%p, %s, %d, %p, %p): stub\n", This, debugstr_dmguid(rguidType), mtTime, pmtNext, pParam);
  	return S_OK;
  }
  
  static HRESULT WINAPI IDirectMusicTrack8Impl_SetParam(IDirectMusicTrack8 *iface, REFGUID rguidType,
          MUSIC_TIME mtTime, void *pParam)
  {
          IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
  	FIXME("(%p, %s, %d, %p): stub\n", This, debugstr_dmguid(rguidType), mtTime, pParam);
  	return S_OK;
  }
  
  static HRESULT WINAPI IDirectMusicTrack8Impl_IsParamSupported(IDirectMusicTrack8 *iface,
          REFGUID rguidType)
  {
          IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
  
  	TRACE("(%p, %s)\n", This, debugstr_dmguid(rguidType));
  	/* didn't find any params */
  	TRACE("param unsupported\n");
  	return DMUS_E_TYPE_UNSUPPORTED;
  }
  
  static HRESULT WINAPI IDirectMusicTrack8Impl_AddNotificationType(IDirectMusicTrack8 *iface,
          REFGUID notiftype)
  {
      IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
  
      TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype));
      return E_NOTIMPL;
  }
  
  static HRESULT WINAPI IDirectMusicTrack8Impl_RemoveNotificationType(IDirectMusicTrack8 *iface,
          REFGUID notiftype)
  {
      IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
  
      TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype));
      return E_NOTIMPL;
  }
  
  static HRESULT WINAPI IDirectMusicTrack8Impl_Clone(IDirectMusicTrack8 *iface, MUSIC_TIME mtStart,
          MUSIC_TIME mtEnd, IDirectMusicTrack **ppTrack)
  {
          IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
  	FIXME("(%p, %d, %d, %p): stub\n", This, mtStart, mtEnd, ppTrack);
  	return S_OK;
  }
  
  static HRESULT WINAPI IDirectMusicTrack8Impl_PlayEx(IDirectMusicTrack8 *iface, void *pStateData,
          REFERENCE_TIME rtStart, REFERENCE_TIME rtEnd, REFERENCE_TIME rtOffset, DWORD dwFlags,
          IDirectMusicPerformance *pPerf, IDirectMusicSegmentState *pSegSt, DWORD dwVirtualID)
  {
          IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
  	FIXME("(%p, %p, 0x%s, 0x%s, 0x%s, %d, %p, %p, %d): stub\n", This, pStateData, wine_dbgstr_longlong(rtStart),
  	    wine_dbgstr_longlong(rtEnd), wine_dbgstr_longlong(rtOffset), dwFlags, pPerf, pSegSt, dwVirtualID);
  	return S_OK;
  }
  
  static HRESULT WINAPI IDirectMusicTrack8Impl_GetParamEx(IDirectMusicTrack8 *iface,
          REFGUID rguidType, REFERENCE_TIME rtTime, REFERENCE_TIME *prtNext, void *pParam,
          void *pStateData, DWORD dwFlags)
  {
          IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
  	FIXME("(%p, %s, 0x%s, %p, %p, %p, %d): stub\n", This, debugstr_dmguid(rguidType),
  	    wine_dbgstr_longlong(rtTime), prtNext, pParam, pStateData, dwFlags);
  	return S_OK;
  }
  
  static HRESULT WINAPI IDirectMusicTrack8Impl_SetParamEx(IDirectMusicTrack8 *iface,
          REFGUID rguidType, REFERENCE_TIME rtTime, void *pParam, void *pStateData, DWORD dwFlags)
  {
          IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
  	FIXME("(%p, %s, 0x%s, %p, %p, %d): stub\n", This, debugstr_dmguid(rguidType),
  	    wine_dbgstr_longlong(rtTime), pParam, pStateData, dwFlags);
  	return S_OK;
  }
  
  static HRESULT WINAPI IDirectMusicTrack8Impl_Compose(IDirectMusicTrack8 *iface, IUnknown *context,
          DWORD trackgroup, IDirectMusicTrack **track)
  {
      IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
  
      TRACE("(%p, %p, %d, %p): method not implemented\n", This, context, trackgroup, track);
      return E_NOTIMPL;
  }
  
  static HRESULT WINAPI IDirectMusicTrack8Impl_Join(IDirectMusicTrack8 *iface,
          IDirectMusicTrack *newtrack, MUSIC_TIME join, IUnknown *context, DWORD trackgroup,
          IDirectMusicTrack **resulttrack)
  {
      IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
      TRACE("(%p, %p, %d, %p, %d, %p): method not implemented\n", This, newtrack, join, context,
              trackgroup, resulttrack);
      return E_NOTIMPL;
  }
  
  static const IDirectMusicTrack8Vtbl dmtrack8_vtbl = {
      IDirectMusicTrack8Impl_QueryInterface,
      IDirectMusicTrack8Impl_AddRef,
      IDirectMusicTrack8Impl_Release,
      IDirectMusicTrack8Impl_Init,
      IDirectMusicTrack8Impl_InitPlay,
      IDirectMusicTrack8Impl_EndPlay,
      IDirectMusicTrack8Impl_Play,
      IDirectMusicTrack8Impl_GetParam,
      IDirectMusicTrack8Impl_SetParam,
      IDirectMusicTrack8Impl_IsParamSupported,
      IDirectMusicTrack8Impl_AddNotificationType,
      IDirectMusicTrack8Impl_RemoveNotificationType,
      IDirectMusicTrack8Impl_Clone,
      IDirectMusicTrack8Impl_PlayEx,
      IDirectMusicTrack8Impl_GetParamEx,
      IDirectMusicTrack8Impl_SetParamEx,
      IDirectMusicTrack8Impl_Compose,
      IDirectMusicTrack8Impl_Join
  };
  
  static HRESULT parse_segment(IDirectMusicSegTriggerTrack *This, DMUS_PRIVATE_CHUNK *pChunk,
          IStream *pStm)
  {
    DMUS_PRIVATE_CHUNK Chunk;
    DWORD ListSize[3], ListCount[3];
    LARGE_INTEGER liMove; /* used when skipping chunks */
    HRESULT hr;
  
    IDirectMusicObject* pObject = NULL;
    LPDMUS_PRIVATE_SEGMENT_ITEM pNewItem = NULL;
  
    if (pChunk->fccID != DMUS_FOURCC_SEGMENT_LIST) {
      ERR_(dmfile)(": %s chunk should be a SEGMENT list\n", debugstr_fourcc (pChunk->fccID));
      return E_FAIL;
    }
  
    ListSize[0] = pChunk->dwSize - sizeof(FOURCC);
    ListCount[0] = 0;
  
    do {
      IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
      ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
      TRACE_(dmfile)(": %s chunk (size = %d)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
      switch (Chunk.fccID) { 
      case DMUS_FOURCC_SEGMENTITEM_CHUNK: {
        TRACE_(dmfile)(": segment item chunk\n"); 
        /** alloc new item entry */
        pNewItem = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_SEGMENT_ITEM));
        if (!pNewItem)
          return  E_OUTOFMEMORY;
  
        IStream_Read (pStm, &pNewItem->header, sizeof(DMUS_IO_SEGMENT_ITEM_HEADER), NULL);
        TRACE_(dmfile)(" - lTimePhysical: %u\n", pNewItem->header.lTimeLogical);
        TRACE_(dmfile)(" - lTimePhysical: %u\n", pNewItem->header.lTimePhysical);
        TRACE_(dmfile)(" - dwPlayFlags: 0x%08x\n", pNewItem->header.dwPlayFlags);
        TRACE_(dmfile)(" - dwFlags: 0x%08x\n", pNewItem->header.dwFlags);
        list_add_tail (&This->Items, &pNewItem->entry);
        break;
      }
      case DMUS_FOURCC_SEGMENTITEMNAME_CHUNK: {
        TRACE_(dmfile)(": segment item name chunk\n");
        if (!pNewItem) {
  	ERR(": pNewItem not allocated, bad chunk order?\n");
  	return E_FAIL;
        }
        IStream_Read (pStm, pNewItem->wszName, Chunk.dwSize, NULL);
        TRACE_(dmfile)(" - name: %s\n", debugstr_w(pNewItem->wszName));
        break;
      }
      case FOURCC_LIST: {
        IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
        TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
        ListSize[1] = Chunk.dwSize - sizeof(FOURCC);
        ListCount[1] = 0;
        switch (Chunk.fccID) { 
        case DMUS_FOURCC_REF_LIST: {
  	FIXME_(dmfile)(": DMRF (DM References) list\n");
          hr = IDirectMusicUtils_IPersistStream_ParseReference(&This->dmobj.IPersistStream_iface,
                  &Chunk, pStm, &pObject);
  	if (FAILED(hr)) {
  	  ERR(": could not load Reference\n");
  	  return hr;
  	}
          if (!pNewItem) {
  	  ERR(": pNewItem not allocated, bad chunk order?\n");
  	  return E_FAIL;
          }
  	pNewItem->pObject = pObject;
  	break;						
        }
        default: {
  	TRACE_(dmfile)(": unknown (skipping)\n");
  	liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
  	IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
  	break;						
        }
        }	
        break;
      }
      default: {
        TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
        liMove.QuadPart = Chunk.dwSize;
        IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
        break;						
      }
      }
      TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
    } while (ListCount[0] < ListSize[0]);
    
    return S_OK;
  }
  
  static HRESULT parse_segments_list(IDirectMusicSegTriggerTrack *This, DMUS_PRIVATE_CHUNK *pChunk,
          IStream *pStm)
  {
    HRESULT hr = E_FAIL;
    DMUS_PRIVATE_CHUNK Chunk;
    DWORD ListSize[3], ListCount[3];
    LARGE_INTEGER liMove; /* used when skipping chunks */
  
    if (pChunk->fccID != DMUS_FOURCC_SEGMENTS_LIST) {
      ERR_(dmfile)(": %s chunk should be a SEGMENTS list\n", debugstr_fourcc (pChunk->fccID));
      return E_FAIL;
    }
  
    ListSize[0] = pChunk->dwSize - sizeof(FOURCC);
    ListCount[0] = 0;
  
    do {
      IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
      ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
      TRACE_(dmfile)(": %s chunk (size = %d)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
      switch (Chunk.fccID) { 
      case FOURCC_LIST: {
        IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
        TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
        ListSize[1] = Chunk.dwSize - sizeof(FOURCC);
        ListCount[1] = 0;
        switch (Chunk.fccID) { 
        case DMUS_FOURCC_SEGMENT_LIST: {
  	TRACE_(dmfile)(": SEGMENT list\n"); 
          hr = parse_segment(This, &Chunk, pStm);
  	if (FAILED(hr)) return hr;	
  	break;
        }
        default: {
  	TRACE_(dmfile)(": unknown (skipping)\n");
  	liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
  	IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
  	break;						
        }
        }	
        break;
      }
      default: {
        TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
        liMove.QuadPart = Chunk.dwSize;
        IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
        break;						
      }
      }
      TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
    } while (ListCount[0] < ListSize[0]);
    
    return S_OK;
  }
  
  static HRESULT parse_seqtrack_list(IDirectMusicSegTriggerTrack *This, DMUS_PRIVATE_CHUNK *pChunk,
          IStream *pStm)
  {
    HRESULT hr = E_FAIL;
    DMUS_PRIVATE_CHUNK Chunk;
    DWORD ListSize[3], ListCount[3];
    LARGE_INTEGER liMove; /* used when skipping chunks */
  
    if (pChunk->fccID != DMUS_FOURCC_SEGTRACK_LIST) {
      ERR_(dmfile)(": %s chunk should be a SEGTRACK list\n", debugstr_fourcc (pChunk->fccID));
      return E_FAIL;
    }  
  
    ListSize[0] = pChunk->dwSize - sizeof(FOURCC);
    ListCount[0] = 0;
  
    do {
      IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
      ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
      TRACE_(dmfile)(": %s chunk (size = %d)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
      switch (Chunk.fccID) { 
      case DMUS_FOURCC_SEGTRACK_CHUNK: {
        TRACE_(dmfile)(": segment trigger track chunk\n");
        liMove.QuadPart = Chunk.dwSize;
        IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
        break;
      }
      case FOURCC_LIST: {
        IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
        TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
        ListSize[1] = Chunk.dwSize - sizeof(FOURCC);
        ListCount[1] = 0;
        switch (Chunk.fccID) { 
        case DMUS_FOURCC_SEGMENTS_LIST: {
  	TRACE_(dmfile)(": SEGMENTS list\n"); 
          hr = parse_segments_list(This, &Chunk, pStm);
  	if (FAILED(hr)) return hr;
  	break;
        }
        default: {
  	TRACE_(dmfile)(": unknown (skipping)\n");
  	liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
  	IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
  	break;						
        }
        }	
        break;
      }
      default: {
        TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
        liMove.QuadPart = Chunk.dwSize;
        IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
        break;						
      }
      }
      TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
    } while (ListCount[0] < ListSize[0]);
  
    return S_OK;
  }
  
  static inline IDirectMusicSegTriggerTrack *impl_from_IPersistStream(IPersistStream *iface)
  {
      return CONTAINING_RECORD(iface, IDirectMusicSegTriggerTrack, dmobj.IPersistStream_iface);
  }
  
  static HRESULT WINAPI IPersistStreamImpl_Load(IPersistStream *iface, IStream *pStm)
  {
    IDirectMusicSegTriggerTrack *This = impl_from_IPersistStream(iface);
    DMUS_PRIVATE_CHUNK Chunk;
    LARGE_INTEGER liMove;
    HRESULT hr;
  
    TRACE("(%p, %p): Loading\n", This, pStm);
    
    IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
    TRACE_(dmfile)(": %s chunk (size = %d)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
    switch (Chunk.fccID) {	
    case FOURCC_LIST: {
      IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
      TRACE_(dmfile)(": %s chunk (size = %d)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
      switch (Chunk.fccID) {
      case DMUS_FOURCC_SEGTRACK_LIST: {
        TRACE_(dmfile)(": segment trigger track list\n");
        hr = parse_seqtrack_list(This, &Chunk, pStm);
        if (FAILED(hr)) return hr;
        break;    
      }
      default: {
        TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
        liMove.QuadPart = Chunk.dwSize;
        IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
        return E_FAIL;
      }
      }
      TRACE_(dmfile)(": reading finished\n");
      break;
    }
    default: {
      TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
      liMove.QuadPart = Chunk.dwSize;
      IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
      return E_FAIL;
    }
    }  
  
    return S_OK;
  }
  
  static const IPersistStreamVtbl persiststream_vtbl = {
      dmobj_IPersistStream_QueryInterface,
      dmobj_IPersistStream_AddRef,
      dmobj_IPersistStream_Release,
      dmobj_IPersistStream_GetClassID,
      unimpl_IPersistStream_IsDirty,
      IPersistStreamImpl_Load,
      unimpl_IPersistStream_Save,
      unimpl_IPersistStream_GetSizeMax
  };
  
  /* for ClassFactory */
  HRESULT WINAPI create_dmsegtriggertrack(REFIID lpcGUID, void **ppobj)
  {
      IDirectMusicSegTriggerTrack *track;
      HRESULT hr;
  
      track = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*track));
      if (!track) {
          *ppobj = NULL;
          return E_OUTOFMEMORY;
      }
      track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl;
      track->ref = 1;
      dmobject_init(&track->dmobj, &CLSID_DirectMusicSegTriggerTrack,
                    (IUnknown *)&track->IDirectMusicTrack8_iface);
      track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl;
      list_init(&track->Items);
  
      DMIME_LockModule();
      hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj);
      IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface);
  
      return hr;
  }
  