ntdll: Reimplement DbgPrint* using DBG_PRINTEXCEPTION_C.
[wine.git] / dlls / dmusic / dmobject.c
blob9ea31ab32a6b9aed8b4f8d5d3d7cc8994fb4d8a4
1 /*
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
23 #define COBJMACROS
24 #include <assert.h>
25 #include "objbase.h"
26 #include "dmusici.h"
27 #include "dmusicf.h"
28 #include "dmusics.h"
29 #include "dmobject.h"
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) {
37 unsigned int i;
38 #define X(guid) { &guid, #guid }
39 static const struct {
40 const GUID *guid;
41 const char *name;
42 } guids[] = {
43 /* CLSIDs */
44 X(CLSID_AudioVBScript),
45 X(CLSID_DirectMusic),
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),
94 /* IIDs */
95 X(IID_IDirectMusic),
96 X(IID_IDirectMusic2),
97 X(IID_IDirectMusic8),
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),
135 X(IID_IUnknown),
136 X(IID_IPersistStream),
137 X(IID_IStream),
138 X(IID_IClassFactory),
139 /* GUIDs */
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),
147 X(GUID_BandParam),
148 X(GUID_ChordParam),
149 X(GUID_CommandParam),
150 X(GUID_CommandParam2),
151 X(GUID_CommandParamNext),
152 X(GUID_IDirectMusicBand),
153 X(GUID_IDirectMusicChordMap),
154 X(GUID_IDirectMusicStyle),
155 X(GUID_MuteParam),
156 X(GUID_Play_Marker),
157 X(GUID_RhythmParam),
158 X(GUID_TempoParam),
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),
166 X(GUID_Download),
167 X(GUID_DownloadToAudioPath),
168 X(GUID_Enable_Auto_Download),
169 X(GUID_EnableTempo),
170 X(GUID_EnableTimeSig),
171 X(GUID_IgnoreBankSelectForGM),
172 X(GUID_SeedVariations),
173 X(GUID_StandardMIDIFile),
174 X(GUID_Unload),
175 X(GUID_UnloadFromAudioPath),
176 X(GUID_Variations),
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),
187 X(GUID_Buffer_Mono),
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)
210 #undef X
212 if (!id)
213 return "(null)";
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))
225 return;
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);
232 X(DMUS_OBJ_OBJECT);
233 X(DMUS_OBJ_CLASS);
234 X(DMUS_OBJ_NAME);
235 X(DMUS_OBJ_CATEGORY);
236 X(DMUS_OBJ_FILENAME);
237 X(DMUS_OBJ_FULLPATH);
238 X(DMUS_OBJ_URL);
239 X(DMUS_OBJ_VERSION);
240 X(DMUS_OBJ_DATE);
241 X(DMUS_OBJ_LOADED);
242 X(DMUS_OBJ_MEMORY);
243 X(DMUS_OBJ_STREAM);
244 TRACE_(dmfile)(")\n");
245 #undef X
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) {
253 SYSTEMTIME time;
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 = "";
283 if (!chunk)
284 return "(null)";
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)
292 ULONG read;
293 HRESULT hr;
295 hr = IStream_Read(stream, data, size, &read);
296 if (FAILED(hr))
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);
301 return E_FAIL;
304 return hr;
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;
311 HRESULT hr;
313 hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, &chunk->offset);
314 if (FAILED(hr))
315 return hr;
316 assert(!(chunk->offset.QuadPart & 1));
317 if (chunk->parent) {
318 p_end = chunk->parent->offset.QuadPart + CHUNK_HDR_SIZE + ((chunk->parent->size + 1) & ~1);
319 if (chunk->offset.QuadPart == p_end)
320 return S_FALSE;
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));
325 return E_FAIL;
329 hr = stream_read(stream, chunk, CHUNK_HDR_SIZE);
330 if (hr != S_OK)
331 return hr;
332 if (chunk->parent) {
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));
337 return E_FAIL;
341 if (chunk->id == FOURCC_LIST || chunk->id == FOURCC_RIFF) {
342 hr = stream_read(stream, &chunk->type, sizeof(FOURCC));
343 if (hr != S_OK)
344 return hr != S_FALSE ? hr : E_FAIL;
347 TRACE_(dmfile)("Returning %s\n", debugstr_chunk(chunk));
349 return S_OK;
352 HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk)
354 LARGE_INTEGER end;
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)
363 HRESULT hr;
365 if (chunk->id) {
366 hr = stream_skip_chunk(stream, chunk);
367 if (FAILED(hr))
368 return hr;
371 return stream_get_chunk(stream, chunk);
374 HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
375 ULONG size)
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);
381 return E_FAIL;
383 return stream_read(stream, data, size);
386 HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
387 ULONG size)
389 ULONG len;
390 HRESULT hr;
392 hr = IStream_Read(stream, str, min(chunk->size, size), &len);
393 if (FAILED(hr))
394 return hr;
396 /* Don't assume the string is properly zero terminated */
397 str[min(len, size - 1)] = 0;
399 if (len < chunk->size)
400 return S_FALSE;
401 return S_OK;
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,
413 void **ret_iface)
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);
438 if (!desc)
439 return E_POINTER;
441 memcpy(desc, &This->desc, This->desc.dwSize);
443 return S_OK;
446 HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface,
447 DMUS_OBJECTDESC *desc)
449 struct dmobject *This = impl_from_IDirectMusicObject(iface);
450 HRESULT ret = S_OK;
452 TRACE("(%p, %p)\n", iface, desc);
454 if (!desc)
455 return E_POINTER;
457 /* Immutable property */
458 if (desc->dwValidData & DMUS_OBJ_CLASS)
460 desc->dwValidData &= ~DMUS_OBJ_CLASS;
461 ret = S_FALSE;
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;
485 return ret;
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];
494 ULONG len;
495 HRESULT hr = E_FAIL;
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);
501 if (SUCCEEDED(hr)) {
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};
523 HRESULT hr;
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) {
531 switch (chunk.id) {
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;
536 break;
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;
541 break;
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;
546 break;
547 case FOURCC_LIST:
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);
552 break;
555 TRACE("Found %#x\n", desc->dwValidData);
557 return hr;
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,
567 void **ret_iface)
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);
591 if (!class)
592 return E_POINTER;
594 *class = This->desc.guidClass;
596 return S_OK;
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);
603 return E_NOTIMPL;
606 HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface)
608 TRACE("(%p): method not implemented, always returning S_FALSE\n", iface);
609 return S_FALSE;
612 HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream,
613 BOOL clear_dirty)
615 TRACE("(%p, %p, %d): method not implemented\n", iface, stream, clear_dirty);
616 return E_NOTIMPL;
619 HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, ULARGE_INTEGER *size)
621 TRACE("(%p, %p): method not implemented\n", iface, size);
622 return E_NOTIMPL;
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;