2 * Base IDirectMusicObject Implementation
3 * Keep in sync with the master in dlls/dmusic/dmobject.c
5 * Copyright (C) 2003-2004 Rok Mandeljc
6 * Copyright (C) 2014 Michael Stefaniuc
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(dmobj
);
33 WINE_DECLARE_DEBUG_CHANNEL(dmfile
);
35 /* Debugging helpers */
36 const char *debugstr_dmguid(const GUID
*id
) {
38 #define X(guid) { &guid, #guid }
44 X(CLSID_AudioVBScript
),
46 X(CLSID_DirectMusicAudioPathConfig
),
47 X(CLSID_DirectMusicAuditionTrack
),
48 X(CLSID_DirectMusicBand
),
49 X(CLSID_DirectMusicBandTrack
),
50 X(CLSID_DirectMusicChordMapTrack
),
51 X(CLSID_DirectMusicChordMap
),
52 X(CLSID_DirectMusicChordTrack
),
53 X(CLSID_DirectMusicCollection
),
54 X(CLSID_DirectMusicCommandTrack
),
55 X(CLSID_DirectMusicComposer
),
56 X(CLSID_DirectMusicContainer
),
57 X(CLSID_DirectMusicGraph
),
58 X(CLSID_DirectMusicLoader
),
59 X(CLSID_DirectMusicLyricsTrack
),
60 X(CLSID_DirectMusicMarkerTrack
),
61 X(CLSID_DirectMusicMelodyFormulationTrack
),
62 X(CLSID_DirectMusicMotifTrack
),
63 X(CLSID_DirectMusicMuteTrack
),
64 X(CLSID_DirectMusicParamControlTrack
),
65 X(CLSID_DirectMusicPatternTrack
),
66 X(CLSID_DirectMusicPerformance
),
67 X(CLSID_DirectMusicScript
),
68 X(CLSID_DirectMusicScriptAutoImpSegment
),
69 X(CLSID_DirectMusicScriptAutoImpPerformance
),
70 X(CLSID_DirectMusicScriptAutoImpSegmentState
),
71 X(CLSID_DirectMusicScriptAutoImpAudioPathConfig
),
72 X(CLSID_DirectMusicScriptAutoImpAudioPath
),
73 X(CLSID_DirectMusicScriptAutoImpSong
),
74 X(CLSID_DirectMusicScriptSourceCodeLoader
),
75 X(CLSID_DirectMusicScriptTrack
),
76 X(CLSID_DirectMusicSection
),
77 X(CLSID_DirectMusicSegment
),
78 X(CLSID_DirectMusicSegmentState
),
79 X(CLSID_DirectMusicSegmentTriggerTrack
),
80 X(CLSID_DirectMusicSegTriggerTrack
),
81 X(CLSID_DirectMusicSeqTrack
),
82 X(CLSID_DirectMusicSignPostTrack
),
83 X(CLSID_DirectMusicSong
),
84 X(CLSID_DirectMusicStyle
),
85 X(CLSID_DirectMusicStyleTrack
),
86 X(CLSID_DirectMusicSynth
),
87 X(CLSID_DirectMusicSynthSink
),
88 X(CLSID_DirectMusicSysExTrack
),
89 X(CLSID_DirectMusicTemplate
),
90 X(CLSID_DirectMusicTempoTrack
),
91 X(CLSID_DirectMusicTimeSigTrack
),
92 X(CLSID_DirectMusicWaveTrack
),
93 X(CLSID_DirectSoundWave
),
98 X(IID_IDirectMusicAudioPath
),
99 X(IID_IDirectMusicBand
),
100 X(IID_IDirectMusicBuffer
),
101 X(IID_IDirectMusicChordMap
),
102 X(IID_IDirectMusicCollection
),
103 X(IID_IDirectMusicComposer
),
104 X(IID_IDirectMusicContainer
),
105 X(IID_IDirectMusicDownload
),
106 X(IID_IDirectMusicDownloadedInstrument
),
107 X(IID_IDirectMusicGetLoader
),
108 X(IID_IDirectMusicGraph
),
109 X(IID_IDirectMusicInstrument
),
110 X(IID_IDirectMusicLoader
),
111 X(IID_IDirectMusicLoader8
),
112 X(IID_IDirectMusicObject
),
113 X(IID_IDirectMusicPatternTrack
),
114 X(IID_IDirectMusicPerformance
),
115 X(IID_IDirectMusicPerformance2
),
116 X(IID_IDirectMusicPerformance8
),
117 X(IID_IDirectMusicPort
),
118 X(IID_IDirectMusicPortDownload
),
119 X(IID_IDirectMusicScript
),
120 X(IID_IDirectMusicSegment
),
121 X(IID_IDirectMusicSegment2
),
122 X(IID_IDirectMusicSegment8
),
123 X(IID_IDirectMusicSegmentState
),
124 X(IID_IDirectMusicSegmentState8
),
125 X(IID_IDirectMusicStyle
),
126 X(IID_IDirectMusicStyle8
),
127 X(IID_IDirectMusicSynth
),
128 X(IID_IDirectMusicSynth8
),
129 X(IID_IDirectMusicSynthSink
),
130 X(IID_IDirectMusicThru
),
131 X(IID_IDirectMusicTool
),
132 X(IID_IDirectMusicTool8
),
133 X(IID_IDirectMusicTrack
),
134 X(IID_IDirectMusicTrack8
),
136 X(IID_IPersistStream
),
138 X(IID_IClassFactory
),
140 X(GUID_DirectMusicAllTypes
),
141 X(GUID_NOTIFICATION_CHORD
),
142 X(GUID_NOTIFICATION_COMMAND
),
143 X(GUID_NOTIFICATION_MEASUREANDBEAT
),
144 X(GUID_NOTIFICATION_PERFORMANCE
),
145 X(GUID_NOTIFICATION_RECOMPOSE
),
146 X(GUID_NOTIFICATION_SEGMENT
),
149 X(GUID_CommandParam
),
150 X(GUID_CommandParam2
),
151 X(GUID_CommandParamNext
),
152 X(GUID_IDirectMusicBand
),
153 X(GUID_IDirectMusicChordMap
),
154 X(GUID_IDirectMusicStyle
),
159 X(GUID_TimeSignature
),
160 X(GUID_Valid_Start_Time
),
161 X(GUID_Clear_All_Bands
),
162 X(GUID_ConnectToDLSCollection
),
163 X(GUID_Disable_Auto_Download
),
164 X(GUID_DisableTempo
),
165 X(GUID_DisableTimeSig
),
167 X(GUID_DownloadToAudioPath
),
168 X(GUID_Enable_Auto_Download
),
170 X(GUID_EnableTimeSig
),
171 X(GUID_IgnoreBankSelectForGM
),
172 X(GUID_SeedVariations
),
173 X(GUID_StandardMIDIFile
),
175 X(GUID_UnloadFromAudioPath
),
177 X(GUID_PerfMasterTempo
),
178 X(GUID_PerfMasterVolume
),
179 X(GUID_PerfMasterGrooveLevel
),
180 X(GUID_PerfAutoDownload
),
181 X(GUID_DefaultGMCollection
),
182 X(GUID_Synth_Default
),
183 X(GUID_Buffer_Reverb
),
184 X(GUID_Buffer_EnvReverb
),
185 X(GUID_Buffer_Stereo
),
186 X(GUID_Buffer_3D_Dry
),
188 X(GUID_DMUS_PROP_GM_Hardware
),
189 X(GUID_DMUS_PROP_GS_Capable
),
190 X(GUID_DMUS_PROP_GS_Hardware
),
191 X(GUID_DMUS_PROP_DLS1
),
192 X(GUID_DMUS_PROP_DLS2
),
193 X(GUID_DMUS_PROP_Effects
),
194 X(GUID_DMUS_PROP_INSTRUMENT2
),
195 X(GUID_DMUS_PROP_LegacyCaps
),
196 X(GUID_DMUS_PROP_MemorySize
),
197 X(GUID_DMUS_PROP_SampleMemorySize
),
198 X(GUID_DMUS_PROP_SamplePlaybackRate
),
199 X(GUID_DMUS_PROP_SetSynthSink
),
200 X(GUID_DMUS_PROP_SinkUsesDSound
),
201 X(GUID_DMUS_PROP_SynthSink_DSOUND
),
202 X(GUID_DMUS_PROP_SynthSink_WAVE
),
203 X(GUID_DMUS_PROP_Volume
),
204 X(GUID_DMUS_PROP_WavesReverb
),
205 X(GUID_DMUS_PROP_WriteLatency
),
206 X(GUID_DMUS_PROP_WritePeriod
),
207 X(GUID_DMUS_PROP_XG_Capable
),
208 X(GUID_DMUS_PROP_XG_Hardware
)
215 for (i
= 0; i
< ARRAY_SIZE(guids
); i
++)
216 if (IsEqualGUID(id
, guids
[i
].guid
))
217 return guids
[i
].name
;
219 return debugstr_guid(id
);
222 void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC
*desc
)
224 if (!desc
|| !TRACE_ON(dmfile
))
227 TRACE_(dmfile
)("DMUS_OBJECTDESC (%p):", desc
);
228 TRACE_(dmfile
)(" - dwSize = %u\n", desc
->dwSize
);
230 #define X(flag) if (desc->dwValidData & flag) TRACE_(dmfile)(#flag " ")
231 TRACE_(dmfile
)(" - dwValidData = %#08x ( ", desc
->dwValidData
);
235 X(DMUS_OBJ_CATEGORY
);
236 X(DMUS_OBJ_FILENAME
);
237 X(DMUS_OBJ_FULLPATH
);
244 TRACE_(dmfile
)(")\n");
247 if (desc
->dwValidData
& DMUS_OBJ_CLASS
)
248 TRACE_(dmfile
)(" - guidClass = %s\n", debugstr_dmguid(&desc
->guidClass
));
249 if (desc
->dwValidData
& DMUS_OBJ_OBJECT
)
250 TRACE_(dmfile
)(" - guidObject = %s\n", debugstr_guid(&desc
->guidObject
));
252 if (desc
->dwValidData
& DMUS_OBJ_DATE
) {
254 FileTimeToSystemTime(&desc
->ftDate
, &time
);
255 TRACE_(dmfile
)(" - ftDate = \'%04u-%02u-%02u %02u:%02u:%02u\'\n",
256 time
.wYear
, time
.wMonth
, time
.wDay
, time
.wHour
, time
.wMinute
, time
.wSecond
);
258 if (desc
->dwValidData
& DMUS_OBJ_VERSION
)
259 TRACE_(dmfile
)(" - vVersion = \'%u,%u,%u,%u\'\n",
260 HIWORD(desc
->vVersion
.dwVersionMS
), LOWORD(desc
->vVersion
.dwVersionMS
),
261 HIWORD(desc
->vVersion
.dwVersionLS
), LOWORD(desc
->vVersion
.dwVersionLS
));
262 if (desc
->dwValidData
& DMUS_OBJ_NAME
)
263 TRACE_(dmfile
)(" - wszName = %s\n", debugstr_w(desc
->wszName
));
264 if (desc
->dwValidData
& DMUS_OBJ_CATEGORY
)
265 TRACE_(dmfile
)(" - wszCategory = %s\n", debugstr_w(desc
->wszCategory
));
266 if (desc
->dwValidData
& DMUS_OBJ_FILENAME
)
267 TRACE_(dmfile
)(" - wszFileName = %s\n", debugstr_w(desc
->wszFileName
));
268 if (desc
->dwValidData
& DMUS_OBJ_MEMORY
)
269 TRACE_(dmfile
)(" - llMemLength = 0x%s - pbMemData = %p\n",
270 wine_dbgstr_longlong(desc
->llMemLength
), desc
->pbMemData
);
271 if (desc
->dwValidData
& DMUS_OBJ_STREAM
)
272 TRACE_(dmfile
)(" - pStream = %p\n", desc
->pStream
);
276 /* RIFF format parsing */
277 #define CHUNK_HDR_SIZE (sizeof(FOURCC) + sizeof(DWORD))
279 const char *debugstr_chunk(const struct chunk_entry
*chunk
)
281 const char *type
= "";
285 if (chunk
->id
== FOURCC_RIFF
|| chunk
->id
== FOURCC_LIST
)
286 type
= wine_dbg_sprintf("type %s, ", debugstr_fourcc(chunk
->type
));
287 return wine_dbg_sprintf("%s chunk, %ssize %u", debugstr_fourcc(chunk
->id
), type
, chunk
->size
);
290 static HRESULT
stream_read(IStream
*stream
, void *data
, ULONG size
)
295 hr
= IStream_Read(stream
, data
, size
, &read
);
297 TRACE_(dmfile
)("IStream_Read failed: %08x\n", hr
);
298 else if (!read
&& read
< size
) {
299 /* All or nothing: Handle a partial read due to end of stream as an error */
300 TRACE_(dmfile
)("Short read: %u < %u\n", read
, size
);
307 HRESULT
stream_get_chunk(IStream
*stream
, struct chunk_entry
*chunk
)
309 static const LARGE_INTEGER zero
;
310 ULONGLONG ck_end
= 0, p_end
= 0;
313 hr
= IStream_Seek(stream
, zero
, STREAM_SEEK_CUR
, &chunk
->offset
);
316 assert(!(chunk
->offset
.QuadPart
& 1));
318 p_end
= chunk
->parent
->offset
.QuadPart
+ CHUNK_HDR_SIZE
+ ((chunk
->parent
->size
+ 1) & ~1);
319 if (chunk
->offset
.QuadPart
== p_end
)
321 ck_end
= chunk
->offset
.QuadPart
+ CHUNK_HDR_SIZE
;
322 if (ck_end
> p_end
) {
323 WARN_(dmfile
)("No space for sub-chunk header in parent chunk: ends at offset %s > %s\n",
324 wine_dbgstr_longlong(ck_end
), wine_dbgstr_longlong(p_end
));
329 hr
= stream_read(stream
, chunk
, CHUNK_HDR_SIZE
);
333 ck_end
+= (chunk
->size
+ 1) & ~1;
334 if (ck_end
> p_end
) {
335 WARN_(dmfile
)("No space for sub-chunk data in parent chunk: ends at offset %s > %s\n",
336 wine_dbgstr_longlong(ck_end
), wine_dbgstr_longlong(p_end
));
341 if (chunk
->id
== FOURCC_LIST
|| chunk
->id
== FOURCC_RIFF
) {
342 hr
= stream_read(stream
, &chunk
->type
, sizeof(FOURCC
));
344 return hr
!= S_FALSE
? hr
: E_FAIL
;
347 TRACE_(dmfile
)("Returning %s\n", debugstr_chunk(chunk
));
352 HRESULT
stream_skip_chunk(IStream
*stream
, struct chunk_entry
*chunk
)
356 end
.QuadPart
= (chunk
->offset
.QuadPart
+ CHUNK_HDR_SIZE
+ chunk
->size
+ 1) & ~(ULONGLONG
)1;
358 return IStream_Seek(stream
, end
, STREAM_SEEK_SET
, NULL
);
361 HRESULT
stream_next_chunk(IStream
*stream
, struct chunk_entry
*chunk
)
366 hr
= stream_skip_chunk(stream
, chunk
);
371 return stream_get_chunk(stream
, chunk
);
374 HRESULT
stream_chunk_get_data(IStream
*stream
, const struct chunk_entry
*chunk
, void *data
,
377 if (chunk
->size
!= size
) {
378 WARN_(dmfile
)("Chunk %s (size %u, offset %s) doesn't contains the expected data size %u\n",
379 debugstr_fourcc(chunk
->id
), chunk
->size
,
380 wine_dbgstr_longlong(chunk
->offset
.QuadPart
), size
);
383 return stream_read(stream
, data
, size
);
386 HRESULT
stream_chunk_get_wstr(IStream
*stream
, const struct chunk_entry
*chunk
, WCHAR
*str
,
392 hr
= IStream_Read(stream
, str
, min(chunk
->size
, size
), &len
);
396 /* Don't assume the string is properly zero terminated */
397 str
[min(len
, size
- 1)] = 0;
399 if (len
< chunk
->size
)
406 /* Generic IDirectMusicObject methods */
407 static inline struct dmobject
*impl_from_IDirectMusicObject(IDirectMusicObject
*iface
)
409 return CONTAINING_RECORD(iface
, struct dmobject
, IDirectMusicObject_iface
);
412 HRESULT WINAPI
dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject
*iface
, REFIID riid
,
415 struct dmobject
*This
= impl_from_IDirectMusicObject(iface
);
416 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ret_iface
);
419 ULONG WINAPI
dmobj_IDirectMusicObject_AddRef(IDirectMusicObject
*iface
)
421 struct dmobject
*This
= impl_from_IDirectMusicObject(iface
);
422 return IUnknown_AddRef(This
->outer_unk
);
425 ULONG WINAPI
dmobj_IDirectMusicObject_Release(IDirectMusicObject
*iface
)
427 struct dmobject
*This
= impl_from_IDirectMusicObject(iface
);
428 return IUnknown_Release(This
->outer_unk
);
431 HRESULT WINAPI
dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject
*iface
,
432 DMUS_OBJECTDESC
*desc
)
434 struct dmobject
*This
= impl_from_IDirectMusicObject(iface
);
436 TRACE("(%p/%p)->(%p)\n", iface
, This
, desc
);
441 memcpy(desc
, &This
->desc
, This
->desc
.dwSize
);
446 HRESULT WINAPI
dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject
*iface
,
447 DMUS_OBJECTDESC
*desc
)
449 struct dmobject
*This
= impl_from_IDirectMusicObject(iface
);
452 TRACE("(%p, %p)\n", iface
, desc
);
457 /* Immutable property */
458 if (desc
->dwValidData
& DMUS_OBJ_CLASS
)
460 desc
->dwValidData
&= ~DMUS_OBJ_CLASS
;
463 /* Set only valid fields */
464 if (desc
->dwValidData
& DMUS_OBJ_OBJECT
)
465 This
->desc
.guidObject
= desc
->guidObject
;
466 if (desc
->dwValidData
& DMUS_OBJ_NAME
)
467 lstrcpynW(This
->desc
.wszName
, desc
->wszName
, DMUS_MAX_NAME
);
468 if (desc
->dwValidData
& DMUS_OBJ_CATEGORY
)
469 lstrcpynW(This
->desc
.wszCategory
, desc
->wszCategory
, DMUS_MAX_CATEGORY
);
470 if (desc
->dwValidData
& DMUS_OBJ_FILENAME
)
471 lstrcpynW(This
->desc
.wszFileName
, desc
->wszFileName
, DMUS_MAX_FILENAME
);
472 if (desc
->dwValidData
& DMUS_OBJ_VERSION
)
473 This
->desc
.vVersion
= desc
->vVersion
;
474 if (desc
->dwValidData
& DMUS_OBJ_DATE
)
475 This
->desc
.ftDate
= desc
->ftDate
;
476 if (desc
->dwValidData
& DMUS_OBJ_MEMORY
) {
477 This
->desc
.llMemLength
= desc
->llMemLength
;
478 memcpy(This
->desc
.pbMemData
, desc
->pbMemData
, desc
->llMemLength
);
480 if (desc
->dwValidData
& DMUS_OBJ_STREAM
)
481 IStream_Clone(desc
->pStream
, &This
->desc
.pStream
);
483 This
->desc
.dwValidData
|= desc
->dwValidData
;
488 /* Helper for IDirectMusicObject::ParseDescriptor */
489 static inline void info_get_name(IStream
*stream
, const struct chunk_entry
*info
,
490 DMUS_OBJECTDESC
*desc
)
492 struct chunk_entry chunk
= {.parent
= info
};
493 char name
[DMUS_MAX_NAME
];
497 while (stream_next_chunk(stream
, &chunk
) == S_OK
)
498 if (chunk
.id
== mmioFOURCC('I','N','A','M'))
499 hr
= IStream_Read(stream
, name
, min(chunk
.size
, sizeof(name
)), &len
);
502 len
= MultiByteToWideChar(CP_ACP
, 0, name
, len
, desc
->wszName
, sizeof(desc
->wszName
));
503 desc
->wszName
[min(len
, sizeof(desc
->wszName
) - 1)] = 0;
504 desc
->dwValidData
|= DMUS_OBJ_NAME
;
508 static inline void unfo_get_name(IStream
*stream
, const struct chunk_entry
*unfo
,
509 DMUS_OBJECTDESC
*desc
, BOOL inam
)
511 struct chunk_entry chunk
= {.parent
= unfo
};
513 while (stream_next_chunk(stream
, &chunk
) == S_OK
)
514 if (chunk
.id
== DMUS_FOURCC_UNAM_CHUNK
|| (inam
&& chunk
.id
== mmioFOURCC('I','N','A','M')))
515 if (stream_chunk_get_wstr(stream
, &chunk
, desc
->wszName
, sizeof(desc
->wszName
)) == S_OK
)
516 desc
->dwValidData
|= DMUS_OBJ_NAME
;
519 HRESULT
dmobj_parsedescriptor(IStream
*stream
, const struct chunk_entry
*riff
,
520 DMUS_OBJECTDESC
*desc
, DWORD supported
)
522 struct chunk_entry chunk
= {.parent
= riff
};
525 TRACE("Looking for %#x in %p: %s\n", supported
, stream
, debugstr_chunk(riff
));
527 desc
->dwValidData
= 0;
528 desc
->dwSize
= sizeof(*desc
);
530 while ((hr
= stream_next_chunk(stream
, &chunk
)) == S_OK
) {
532 case DMUS_FOURCC_GUID_CHUNK
:
533 if ((supported
& DMUS_OBJ_OBJECT
) && stream_chunk_get_data(stream
, &chunk
,
534 &desc
->guidObject
, sizeof(desc
->guidObject
)) == S_OK
)
535 desc
->dwValidData
|= DMUS_OBJ_OBJECT
;
537 case DMUS_FOURCC_CATEGORY_CHUNK
:
538 if ((supported
& DMUS_OBJ_CATEGORY
) && stream_chunk_get_wstr(stream
, &chunk
,
539 desc
->wszCategory
, sizeof(desc
->wszCategory
)) == S_OK
)
540 desc
->dwValidData
|= DMUS_OBJ_CATEGORY
;
542 case DMUS_FOURCC_VERSION_CHUNK
:
543 if ((supported
& DMUS_OBJ_VERSION
) && stream_chunk_get_data(stream
, &chunk
,
544 &desc
->vVersion
, sizeof(desc
->vVersion
)) == S_OK
)
545 desc
->dwValidData
|= DMUS_OBJ_VERSION
;
548 if (chunk
.type
== DMUS_FOURCC_UNFO_LIST
&& (supported
& DMUS_OBJ_NAME
))
549 unfo_get_name(stream
, &chunk
, desc
, supported
& DMUS_OBJ_NAME_INAM
);
550 else if (chunk
.type
== DMUS_FOURCC_INFO_LIST
&& (supported
& DMUS_OBJ_NAME_INFO
))
551 info_get_name(stream
, &chunk
, desc
);
555 TRACE("Found %#x\n", desc
->dwValidData
);
560 /* Generic IPersistStream methods */
561 static inline struct dmobject
*impl_from_IPersistStream(IPersistStream
*iface
)
563 return CONTAINING_RECORD(iface
, struct dmobject
, IPersistStream_iface
);
566 HRESULT WINAPI
dmobj_IPersistStream_QueryInterface(IPersistStream
*iface
, REFIID riid
,
569 struct dmobject
*This
= impl_from_IPersistStream(iface
);
570 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ret_iface
);
573 ULONG WINAPI
dmobj_IPersistStream_AddRef(IPersistStream
*iface
)
575 struct dmobject
*This
= impl_from_IPersistStream(iface
);
576 return IUnknown_AddRef(This
->outer_unk
);
579 ULONG WINAPI
dmobj_IPersistStream_Release(IPersistStream
*iface
)
581 struct dmobject
*This
= impl_from_IPersistStream(iface
);
582 return IUnknown_Release(This
->outer_unk
);
585 HRESULT WINAPI
dmobj_IPersistStream_GetClassID(IPersistStream
*iface
, CLSID
*class)
587 struct dmobject
*This
= impl_from_IPersistStream(iface
);
589 TRACE("(%p, %p)\n", This
, class);
594 *class = This
->desc
.guidClass
;
599 /* IPersistStream methods not implemented in native */
600 HRESULT WINAPI
unimpl_IPersistStream_GetClassID(IPersistStream
*iface
, CLSID
*class)
602 TRACE("(%p, %p): method not implemented\n", iface
, class);
606 HRESULT WINAPI
unimpl_IPersistStream_IsDirty(IPersistStream
*iface
)
608 TRACE("(%p): method not implemented, always returning S_FALSE\n", iface
);
612 HRESULT WINAPI
unimpl_IPersistStream_Save(IPersistStream
*iface
, IStream
*stream
,
615 TRACE("(%p, %p, %d): method not implemented\n", iface
, stream
, clear_dirty
);
619 HRESULT WINAPI
unimpl_IPersistStream_GetSizeMax(IPersistStream
*iface
, ULARGE_INTEGER
*size
)
621 TRACE("(%p, %p): method not implemented\n", iface
, size
);
626 void dmobject_init(struct dmobject
*dmobj
, const GUID
*class, IUnknown
*outer_unk
)
628 dmobj
->outer_unk
= outer_unk
;
629 dmobj
->desc
.dwSize
= sizeof(dmobj
->desc
);
630 dmobj
->desc
.dwValidData
= DMUS_OBJ_CLASS
;
631 dmobj
->desc
.guidClass
= *class;