Release 8.16.
[wine.git] / dlls / dmstyle / tests / dmstyle.c
blob4b16cdad1a16129004379bdce87fe4b6845e3269
1 /*
2 * Copyright 2014 Michael Stefaniuc
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define COBJMACROS
21 #include <stdarg.h>
22 #include <windef.h>
23 #include <initguid.h>
24 #include <wine/test.h>
25 #include <ole2.h>
26 #include <dmusici.h>
27 #include <dmusicf.h>
29 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
31 static BOOL missing_dmstyle(void)
33 IDirectMusicStyle *dms;
34 HRESULT hr = CoCreateInstance(&CLSID_DirectMusicStyle, NULL, CLSCTX_INPROC_SERVER,
35 &IID_IDirectMusicStyle, (void**)&dms);
37 if (hr == S_OK && dms)
39 IDirectMusicStyle_Release(dms);
40 return FALSE;
42 return TRUE;
45 static void test_COM(void)
47 IDirectMusicStyle8 *dms8 = (IDirectMusicStyle8*)0xdeadbeef;
48 IDirectMusicObject *dmo;
49 IPersistStream *ps;
50 IUnknown *unk;
51 ULONG refcount;
52 HRESULT hr;
54 /* COM aggregation */
55 hr = CoCreateInstance(&CLSID_DirectMusicStyle, (IUnknown *)0xdeadbeef, CLSCTX_INPROC_SERVER,
56 &IID_IUnknown, (void**)&dms8);
57 ok(hr == CLASS_E_NOAGGREGATION,
58 "DirectMusicStyle8 create failed: %#lx, expected CLASS_E_NOAGGREGATION\n", hr);
59 ok(!dms8, "dms8 = %p\n", dms8);
61 /* Invalid RIID */
62 hr = CoCreateInstance(&CLSID_DirectMusicStyle, NULL, CLSCTX_INPROC_SERVER, &IID_IClassFactory,
63 (void**)&dms8);
64 ok(hr == E_NOINTERFACE, "DirectMusicStyle8 create failed: %#lx, expected E_NOINTERFACE\n", hr);
66 /* Same refcount for all DirectMusicStyle8 interfaces */
67 hr = CoCreateInstance(&CLSID_DirectMusicStyle, NULL, CLSCTX_INPROC_SERVER,
68 &IID_IDirectMusicStyle8, (void**)&dms8);
69 if (hr == E_NOINTERFACE) {
70 win_skip("Old version without IDirectMusicStyle8\n");
71 return;
73 ok(hr == S_OK, "DirectMusicStyle8 create failed: %#lx, expected S_OK\n", hr);
74 refcount = IDirectMusicStyle8_AddRef(dms8);
75 ok(refcount == 2, "refcount == %lu, expected 2\n", refcount);
77 hr = IDirectMusicStyle8_QueryInterface(dms8, &IID_IDirectMusicObject, (void**)&dmo);
78 ok(hr == S_OK, "QueryInterface for IID_IDirectMusicObject failed: %#lx\n", hr);
79 refcount = IDirectMusicObject_AddRef(dmo);
80 ok(refcount == 4, "refcount == %lu, expected 4\n", refcount);
81 refcount = IDirectMusicObject_Release(dmo);
83 hr = IDirectMusicStyle8_QueryInterface(dms8, &IID_IPersistStream, (void**)&ps);
84 ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
85 refcount = IPersistStream_AddRef(ps);
86 ok(refcount == 5, "refcount == %lu, expected 5\n", refcount);
87 refcount = IPersistStream_Release(ps);
89 hr = IDirectMusicStyle8_QueryInterface(dms8, &IID_IUnknown, (void**)&unk);
90 ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %#lx\n", hr);
91 refcount = IUnknown_AddRef(unk);
92 ok(refcount == 6, "refcount == %lu, expected 6\n", refcount);
93 refcount = IUnknown_Release(unk);
95 while (IDirectMusicStyle8_Release(dms8));
98 static void test_COM_section(void)
100 IDirectMusicObject *dmo = (IDirectMusicObject*)0xdeadbeef;
101 IPersistStream *ps;
102 IUnknown *unk;
103 ULONG refcount;
104 HRESULT hr;
106 /* COM aggregation */
107 hr = CoCreateInstance(&CLSID_DirectMusicSection, (IUnknown *)0xdeadbeef, CLSCTX_INPROC_SERVER,
108 &IID_IUnknown, (void**)&dmo);
109 ok(hr == CLASS_E_NOAGGREGATION,
110 "DirectMusicSection create failed: %#lx, expected CLASS_E_NOAGGREGATION\n", hr);
111 ok(!dmo, "dmo = %p\n", dmo);
113 /* Invalid RIID */
114 hr = CoCreateInstance(&CLSID_DirectMusicSection, NULL, CLSCTX_INPROC_SERVER, &IID_IClassFactory,
115 (void**)&dmo);
116 todo_wine ok(hr == E_NOINTERFACE,
117 "DirectMusicSection create failed: %#lx, expected E_NOINTERFACE\n", hr);
119 /* Same refcount for all DirectMusicObject interfaces */
120 hr = CoCreateInstance(&CLSID_DirectMusicSection, NULL, CLSCTX_INPROC_SERVER,
121 &IID_IDirectMusicObject, (void**)&dmo);
122 todo_wine ok(hr == S_OK, "DirectMusicSection create failed: %#lx, expected S_OK\n", hr);
123 if (hr != S_OK) {
124 skip("DirectMusicSection not implemented\n");
125 return;
127 refcount = IDirectMusicObject_AddRef(dmo);
128 ok(refcount == 2, "refcount == %lu, expected 2\n", refcount);
130 hr = IDirectMusicObject_QueryInterface(dmo, &IID_IPersistStream, (void**)&ps);
131 ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
132 refcount = IPersistStream_AddRef(ps);
133 ok(refcount == 4, "refcount == %lu, expected 4\n", refcount);
134 IPersistStream_Release(ps);
136 hr = IDirectMusicObject_QueryInterface(dmo, &IID_IUnknown, (void**)&unk);
137 ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %#lx\n", hr);
138 refcount = IUnknown_AddRef(unk);
139 ok(refcount == 5, "refcount == %lu, expected 5\n", refcount);
140 refcount = IUnknown_Release(unk);
142 while (IDirectMusicObject_Release(dmo));
145 static void test_COM_track(void)
147 IDirectMusicTrack8 *dmt8;
148 IPersistStream *ps;
149 IUnknown *unk;
150 ULONG refcount;
151 HRESULT hr;
152 #define X(class) &CLSID_ ## class, #class
153 const struct {
154 REFCLSID clsid;
155 const char *name;
156 } class[] = {
157 { X(DirectMusicAuditionTrack) },
158 { X(DirectMusicChordTrack) },
159 { X(DirectMusicCommandTrack) },
160 { X(DirectMusicMotifTrack) },
161 { X(DirectMusicMuteTrack) },
162 { X(DirectMusicStyleTrack) },
164 #undef X
165 unsigned int i;
167 for (i = 0; i < ARRAY_SIZE(class); i++) {
168 /* COM aggregation */
169 dmt8 = (IDirectMusicTrack8*)0xdeadbeef;
170 hr = CoCreateInstance(class[i].clsid, (IUnknown *)0xdeadbeef, CLSCTX_INPROC_SERVER, &IID_IUnknown,
171 (void**)&dmt8);
172 if (hr == REGDB_E_CLASSNOTREG) {
173 win_skip("%s not registered\n", class[i].name);
174 continue;
176 ok(hr == CLASS_E_NOAGGREGATION,
177 "%s create failed: %#lx, expected CLASS_E_NOAGGREGATION\n", class[i].name, hr);
178 ok(!dmt8, "dmt8 = %p\n", dmt8);
180 /* Invalid RIID */
181 hr = CoCreateInstance(class[i].clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject,
182 (void**)&dmt8);
183 ok(hr == E_NOINTERFACE, "%s create failed: %#lx, expected E_NOINTERFACE\n",
184 class[i].name, hr);
186 /* Same refcount for all DirectMusicTrack interfaces */
187 hr = CoCreateInstance(class[i].clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicTrack8,
188 (void**)&dmt8);
189 ok(hr == S_OK, "%s create failed: %#lx, expected S_OK\n", class[i].name, hr);
190 refcount = IDirectMusicTrack8_AddRef(dmt8);
191 ok(refcount == 2, "refcount == %lu, expected 2\n", refcount);
193 hr = IDirectMusicTrack8_QueryInterface(dmt8, &IID_IPersistStream, (void**)&ps);
194 ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
195 refcount = IPersistStream_AddRef(ps);
196 ok(refcount == 4, "refcount == %lu, expected 4\n", refcount);
197 IPersistStream_Release(ps);
199 hr = IDirectMusicTrack8_QueryInterface(dmt8, &IID_IUnknown, (void**)&unk);
200 ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %#lx\n", hr);
201 refcount = IUnknown_AddRef(unk);
202 ok(refcount == 5, "refcount == %lu, expected 5\n", refcount);
203 refcount = IUnknown_Release(unk);
205 while (IDirectMusicTrack8_Release(dmt8));
209 static void test_dmstyle(void)
211 IDirectMusicStyle *dms;
212 IPersistStream *ps;
213 CLSID class = { 0 };
214 ULARGE_INTEGER size;
215 HRESULT hr;
217 hr = CoCreateInstance(&CLSID_DirectMusicStyle, NULL, CLSCTX_INPROC_SERVER,
218 &IID_IDirectMusicStyle, (void**)&dms);
219 ok(hr == S_OK, "DirectMusicStyle create failed: %#lx, expected S_OK\n", hr);
221 /* IPersistStream */
222 hr = IDirectMusicStyle_QueryInterface(dms, &IID_IPersistStream, (void**)&ps);
223 ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
224 hr = IPersistStream_GetClassID(ps, &class);
225 ok(hr == S_OK, "IPersistStream_GetClassID failed: %#lx\n", hr);
226 ok(IsEqualGUID(&class, &CLSID_DirectMusicStyle),
227 "Expected class CLSID_DirectMusicStyle got %s\n", wine_dbgstr_guid(&class));
229 /* Unimplemented IPersistStream methods*/
230 hr = IPersistStream_IsDirty(ps);
231 ok(hr == S_FALSE, "IPersistStream_IsDirty failed: %#lx\n", hr);
232 hr = IPersistStream_GetSizeMax(ps, &size);
233 ok(hr == E_NOTIMPL, "IPersistStream_GetSizeMax failed: %#lx\n", hr);
234 hr = IPersistStream_Save(ps, NULL, TRUE);
235 ok(hr == E_NOTIMPL, "IPersistStream_Save failed: %#lx\n", hr);
237 while (IDirectMusicStyle_Release(dms));
240 static void expect_getparam(IDirectMusicTrack8 *track, REFGUID type, const char *name,
241 HRESULT expect)
243 HRESULT hr;
244 char buf[64] = { 0 };
246 hr = IDirectMusicTrack8_GetParam(track, type, 0, NULL, buf);
247 ok(hr == expect, "GetParam(%s) failed: %#lx, expected %#lx\n", name, hr, expect);
250 static void expect_setparam(IDirectMusicTrack8 *track, REFGUID type, const char *name,
251 HRESULT expect)
253 HRESULT hr;
255 hr = IDirectMusicTrack8_SetParam(track, type, 0, track);
256 ok(hr == expect, "SetParam(%s) failed: %#lx, expected %#lx\n", name, hr, expect);
259 static void test_track(void)
261 IDirectMusicTrack8 *dmt8;
262 IPersistStream *ps;
263 CLSID classid;
264 ULARGE_INTEGER size;
265 HRESULT hr;
266 #define X(guid) &guid, #guid
267 const struct {
268 REFGUID type;
269 const char *name;
270 } param_types[] = {
271 { X(GUID_BandParam) },
272 { X(GUID_ChordParam) },
273 { X(GUID_Clear_All_Bands) },
274 { X(GUID_CommandParam) },
275 { X(GUID_CommandParam2) },
276 { X(GUID_CommandParamNext) },
277 { X(GUID_ConnectToDLSCollection) },
278 { X(GUID_Disable_Auto_Download) },
279 { X(GUID_DisableTempo) },
280 { X(GUID_DisableTimeSig) },
281 { X(GUID_Download) },
282 { X(GUID_DownloadToAudioPath) },
283 { X(GUID_Enable_Auto_Download) },
284 { X(GUID_EnableTempo) },
285 { X(GUID_EnableTimeSig) },
286 { X(GUID_IDirectMusicBand) },
287 { X(GUID_IDirectMusicChordMap) },
288 { X(GUID_IDirectMusicStyle) },
289 { X(GUID_MuteParam) },
290 { X(GUID_Play_Marker) },
291 { X(GUID_RhythmParam) },
292 { X(GUID_SeedVariations) },
293 { X(GUID_StandardMIDIFile) },
294 { X(GUID_TempoParam) },
295 { X(GUID_TimeSignature) },
296 { X(GUID_Unload) },
297 { X(GUID_UnloadFromAudioPath) },
298 { X(GUID_Valid_Start_Time) },
299 { X(GUID_Variations) }
301 #undef X
302 #define X(class) &CLSID_ ## class, #class
303 const struct {
304 REFCLSID clsid;
305 const char *name;
306 BOOL has_save;
307 BOOL has_join;
308 /* bitfield with supported param types */
309 unsigned int has_params;
310 } class[] = {
311 { X(DirectMusicAuditionTrack), TRUE, FALSE, 0x18204200 },
312 { X(DirectMusicChordTrack), TRUE, TRUE, 0x100002 },
313 { X(DirectMusicCommandTrack), TRUE, TRUE, 0x38 },
314 { X(DirectMusicMotifTrack), FALSE, FALSE, 0x8204200 },
315 { X(DirectMusicMuteTrack), TRUE, FALSE, 0x40000 },
316 { X(DirectMusicStyleTrack), FALSE, TRUE, 0x1224200 },
318 #undef X
319 unsigned int i, j;
321 for (i = 0; i < ARRAY_SIZE(class); i++) {
322 trace("Testing %s\n", class[i].name);
323 hr = CoCreateInstance(class[i].clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicTrack8,
324 (void**)&dmt8);
325 ok(hr == S_OK, "%s create failed: %#lx, expected S_OK\n", class[i].name, hr);
327 /* IDirectMusicTrack8 */
328 hr = IDirectMusicTrack8_Init(dmt8, NULL);
329 todo_wine ok(hr == E_POINTER, "IDirectMusicTrack8_Init failed: %#lx\n", hr);
330 if (class[i].clsid != &CLSID_DirectMusicChordTrack &&
331 class[i].clsid != &CLSID_DirectMusicCommandTrack) {
332 /* Crashes on native */
333 hr = IDirectMusicTrack8_InitPlay(dmt8, NULL, NULL, NULL, 0, 0);
334 if (class[i].clsid == &CLSID_DirectMusicMuteTrack)
335 ok(hr == S_OK, "IDirectMusicTrack8_InitPlay failed: %#lx\n", hr);
336 else
337 todo_wine ok(hr == E_POINTER, "IDirectMusicTrack8_InitPlay failed: %#lx\n", hr);
340 hr = IDirectMusicTrack8_GetParam(dmt8, NULL, 0, NULL, NULL);
341 ok(hr == E_POINTER, "IDirectMusicTrack8_GetParam failed: %#lx\n", hr);
342 hr = IDirectMusicTrack8_SetParam(dmt8, NULL, 0, NULL);
343 ok(hr == E_POINTER, "IDirectMusicTrack8_SetParam failed: %#lx\n", hr);
345 hr = IDirectMusicTrack8_IsParamSupported(dmt8, NULL);
346 ok(hr == E_POINTER, "IDirectMusicTrack8_IsParamSupported failed: %#lx\n", hr);
347 for (j = 0; j < ARRAY_SIZE(param_types); j++) {
348 hr = IDirectMusicTrack8_IsParamSupported(dmt8, param_types[j].type);
349 if (class[i].has_params & (1 << j))
350 ok(hr == S_OK, "IsParamSupported(%s) failed: %#lx, expected S_OK\n",
351 param_types[j].name, hr);
352 else {
353 ok(hr == DMUS_E_TYPE_UNSUPPORTED,
354 "IsParamSupported(%s) failed: %#lx, expected DMUS_E_TYPE_UNSUPPORTED\n",
355 param_types[j].name, hr);
356 if (class[i].clsid == &CLSID_DirectMusicChordTrack) {
357 expect_setparam(dmt8, param_types[j].type, param_types[j].name,
358 DMUS_E_SET_UNSUPPORTED);
359 } else if (class[i].clsid == &CLSID_DirectMusicMuteTrack) {
360 expect_getparam(dmt8, param_types[j].type, param_types[j].name,
361 DMUS_E_TYPE_UNSUPPORTED);
362 expect_setparam(dmt8, param_types[j].type, param_types[j].name,
363 DMUS_E_TYPE_UNSUPPORTED);
364 } else {
365 expect_getparam(dmt8, param_types[j].type, param_types[j].name,
366 DMUS_E_GET_UNSUPPORTED);
367 expect_setparam(dmt8, param_types[j].type, param_types[j].name,
368 DMUS_E_SET_UNSUPPORTED);
373 /* GetParam / SetParam for IsParamSupported supported types */
374 if (class[i].clsid == &CLSID_DirectMusicAuditionTrack) {
375 expect_getparam(dmt8, &GUID_DisableTimeSig, "GUID_DisableTimeSig",
376 DMUS_E_GET_UNSUPPORTED);
377 expect_getparam(dmt8, &GUID_EnableTimeSig, "GUID_EnableTimeSig",
378 DMUS_E_GET_UNSUPPORTED);
379 expect_getparam(dmt8, &GUID_SeedVariations, "GUID_SeedVariations",
380 DMUS_E_GET_UNSUPPORTED);
381 expect_setparam(dmt8, &GUID_Valid_Start_Time, "GUID_Valid_Start_Time",
382 DMUS_E_SET_UNSUPPORTED);
383 expect_setparam(dmt8, &GUID_Variations, "GUID_Variations",
384 DMUS_E_SET_UNSUPPORTED);
385 } else if (class[i].clsid == &CLSID_DirectMusicChordTrack) {
386 expect_setparam(dmt8, &GUID_RhythmParam, "GUID_RhythmParam",
387 DMUS_E_SET_UNSUPPORTED);
388 } else if (class[i].clsid == &CLSID_DirectMusicCommandTrack) {
389 expect_setparam(dmt8, &GUID_CommandParam2, "GUID_CommandParam2",
390 DMUS_E_SET_UNSUPPORTED);
391 } else if (class[i].clsid == &CLSID_DirectMusicMotifTrack) {
392 expect_getparam(dmt8, &GUID_DisableTimeSig, "GUID_DisableTimeSig",
393 DMUS_E_GET_UNSUPPORTED);
394 expect_getparam(dmt8, &GUID_EnableTimeSig, "GUID_EnableTimeSig",
395 DMUS_E_GET_UNSUPPORTED);
396 expect_getparam(dmt8, &GUID_SeedVariations, "GUID_SeedVariations",
397 DMUS_E_GET_UNSUPPORTED);
398 expect_setparam(dmt8, &GUID_Valid_Start_Time, "GUID_Valid_Start_Time",
399 DMUS_E_SET_UNSUPPORTED);
400 } else if (class[i].clsid == &CLSID_DirectMusicStyleTrack) {
401 expect_getparam(dmt8, &GUID_DisableTimeSig, "GUID_DisableTimeSig",
402 DMUS_E_GET_UNSUPPORTED);
403 expect_getparam(dmt8, &GUID_EnableTimeSig, "GUID_EnableTimeSig",
404 DMUS_E_GET_UNSUPPORTED);
405 expect_getparam(dmt8, &GUID_SeedVariations, "GUID_SeedVariations",
406 DMUS_E_GET_UNSUPPORTED);
407 expect_setparam(dmt8, &GUID_TimeSignature, "GUID_TimeSignature",
408 DMUS_E_SET_UNSUPPORTED);
411 if (class[i].clsid == &CLSID_DirectMusicMuteTrack) {
412 hr = IDirectMusicTrack8_AddNotificationType(dmt8, NULL);
413 ok(hr == E_NOTIMPL, "IDirectMusicTrack8_AddNotificationType failed: %#lx\n", hr);
414 hr = IDirectMusicTrack8_RemoveNotificationType(dmt8, NULL);
415 ok(hr == E_NOTIMPL, "IDirectMusicTrack8_RemoveNotificationType failed: %#lx\n", hr);
416 } else todo_wine {
417 hr = IDirectMusicTrack8_AddNotificationType(dmt8, NULL);
418 ok(hr == E_POINTER, "IDirectMusicTrack8_AddNotificationType failed: %#lx\n", hr);
419 hr = IDirectMusicTrack8_RemoveNotificationType(dmt8, NULL);
420 ok(hr == E_POINTER, "IDirectMusicTrack8_RemoveNotificationType failed: %#lx\n", hr);
422 todo_wine {
423 hr = IDirectMusicTrack8_Clone(dmt8, 0, 0, NULL);
424 ok(hr == E_POINTER, "IDirectMusicTrack8_Clone failed: %#lx\n", hr);
425 hr = IDirectMusicTrack8_PlayEx(dmt8, NULL, 0, 0, 0, 0, NULL, NULL, 0);
426 ok(hr == E_POINTER, "IDirectMusicTrack8_PlayEx failed: %#lx\n", hr);
427 hr = IDirectMusicTrack8_GetParamEx(dmt8, NULL, 0, NULL, NULL, NULL, 0);
428 ok(hr == E_POINTER, "IDirectMusicTrack8_GetParamEx failed: %#lx\n", hr);
429 hr = IDirectMusicTrack8_SetParamEx(dmt8, NULL, 0, NULL, NULL, 0);
430 ok(hr == E_POINTER, "IDirectMusicTrack8_SetParamEx failed: %#lx\n", hr);
432 hr = IDirectMusicTrack8_Compose(dmt8, NULL, 0, NULL);
433 ok(hr == E_NOTIMPL, "IDirectMusicTrack8_Compose failed: %#lx\n", hr);
434 if (class[i].has_join) {
435 hr = IDirectMusicTrack8_Join(dmt8, NULL, 0, NULL, 0, NULL);
436 todo_wine ok(hr == E_POINTER, "IDirectMusicTrack8_Join failed: %#lx\n", hr);
437 } else {
438 hr = IDirectMusicTrack8_Join(dmt8, NULL, 0, NULL, 0, NULL);
439 ok(hr == E_NOTIMPL, "IDirectMusicTrack8_Join failed: %#lx\n", hr);
442 /* IPersistStream */
443 hr = IDirectMusicTrack8_QueryInterface(dmt8, &IID_IPersistStream, (void**)&ps);
444 ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
445 hr = IPersistStream_GetClassID(ps, &classid);
446 ok(hr == S_OK, "IPersistStream_GetClassID failed: %#lx\n", hr);
447 ok(IsEqualGUID(&classid, class[i].clsid),
448 "Expected class %s got %s\n", class[i].name, wine_dbgstr_guid(&classid));
449 hr = IPersistStream_IsDirty(ps);
450 ok(hr == S_FALSE, "IPersistStream_IsDirty failed: %#lx\n", hr);
452 hr = IPersistStream_GetSizeMax(ps, &size);
453 ok(hr == E_NOTIMPL, "IPersistStream_GetSizeMax failed: %#lx\n", hr);
455 hr = IPersistStream_Save(ps, NULL, TRUE);
456 if (class[i].has_save)
457 ok(hr == E_POINTER, "IPersistStream_Save failed: %#lx\n", hr);
458 else
459 ok(hr == E_NOTIMPL, "IPersistStream_Save failed: %#lx\n", hr);
461 while (IDirectMusicTrack8_Release(dmt8));
465 struct chunk {
466 FOURCC id;
467 DWORD size;
468 FOURCC type;
471 #define CHUNK_HDR_SIZE (sizeof(FOURCC) + sizeof(DWORD))
473 /* Generate a RIFF file format stream from an array of FOURCC ids.
474 RIFF and LIST need to be followed by the form type respectively list type,
475 followed by the chunks of the list and terminated with 0. */
476 static IStream *gen_riff_stream(const FOURCC *ids)
478 static const LARGE_INTEGER zero;
479 int level = -1;
480 DWORD *sizes[4]; /* Stack for the sizes of RIFF and LIST chunks */
481 char riff[1024];
482 char *p = riff;
483 struct chunk *ck;
484 IStream *stream;
486 do {
487 ck = (struct chunk *)p;
488 ck->id = *ids++;
489 switch (ck->id) {
490 case 0:
491 *sizes[level] = p - (char *)sizes[level] - sizeof(DWORD);
492 level--;
493 break;
494 case FOURCC_LIST:
495 case FOURCC_RIFF:
496 level++;
497 sizes[level] = &ck->size;
498 ck->type = *ids++;
499 p += sizeof(*ck);
500 break;
501 case DMUS_FOURCC_GUID_CHUNK:
502 ck->size = sizeof(GUID_NULL);
503 p += CHUNK_HDR_SIZE;
504 memcpy(p, &GUID_NULL, sizeof(GUID_NULL));
505 p += ck->size;
506 break;
507 case DMUS_FOURCC_VERSION_CHUNK:
509 DMUS_VERSION ver = {5, 8};
511 ck->size = sizeof(ver);
512 p += CHUNK_HDR_SIZE;
513 memcpy(p, &ver, sizeof(ver));
514 p += ck->size;
515 break;
517 default:
519 /* Just convert the FOURCC id to a WCHAR string */
520 WCHAR *s;
522 ck->size = 5 * sizeof(WCHAR);
523 p += CHUNK_HDR_SIZE;
524 s = (WCHAR *)p;
525 s[0] = (char)(ck->id);
526 s[1] = (char)(ck->id >> 8);
527 s[2] = (char)(ck->id >> 16);
528 s[3] = (char)(ck->id >> 24);
529 s[4] = 0;
530 p += ck->size;
533 } while (level >= 0);
535 ck = (struct chunk *)riff;
536 CreateStreamOnHGlobal(NULL, TRUE, &stream);
537 IStream_Write(stream, riff, ck->size + CHUNK_HDR_SIZE, NULL);
538 IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
540 return stream;
543 static void test_parsedescriptor(void)
545 IDirectMusicObject *dmo;
546 IStream *stream;
547 DMUS_OBJECTDESC desc = {0};
548 HRESULT hr;
549 DWORD valid;
550 const FOURCC alldesc[] =
552 FOURCC_RIFF, DMUS_FOURCC_STYLE_FORM, DMUS_FOURCC_CATEGORY_CHUNK, FOURCC_LIST,
553 DMUS_FOURCC_UNFO_LIST, DMUS_FOURCC_UNAM_CHUNK, DMUS_FOURCC_UCOP_CHUNK,
554 DMUS_FOURCC_UCMT_CHUNK, DMUS_FOURCC_USBJ_CHUNK, 0, DMUS_FOURCC_VERSION_CHUNK,
555 DMUS_FOURCC_GUID_CHUNK, 0
557 const FOURCC dupes[] =
559 FOURCC_RIFF, DMUS_FOURCC_STYLE_FORM, DMUS_FOURCC_CATEGORY_CHUNK, DMUS_FOURCC_CATEGORY_CHUNK,
560 DMUS_FOURCC_VERSION_CHUNK, DMUS_FOURCC_VERSION_CHUNK, DMUS_FOURCC_GUID_CHUNK,
561 DMUS_FOURCC_GUID_CHUNK, FOURCC_LIST, DMUS_FOURCC_UNFO_LIST, DMUS_FOURCC_UNAM_CHUNK, 0,
562 FOURCC_LIST, DMUS_FOURCC_UNFO_LIST, mmioFOURCC('I','N','A','M'), 0, 0
564 FOURCC empty[] = {FOURCC_RIFF, DMUS_FOURCC_STYLE_FORM, 0};
565 FOURCC inam[] =
567 FOURCC_RIFF, DMUS_FOURCC_STYLE_FORM, FOURCC_LIST, DMUS_FOURCC_UNFO_LIST,
568 mmioFOURCC('I','N','A','M'), 0, 0
571 hr = CoCreateInstance(&CLSID_DirectMusicStyle, NULL, CLSCTX_INPROC_SERVER,
572 &IID_IDirectMusicObject, (void **)&dmo);
573 ok(hr == S_OK, "DirectMusicStyle create failed: %#lx, expected S_OK\n", hr);
575 /* Nothing loaded */
576 hr = IDirectMusicObject_GetDescriptor(dmo, &desc);
577 ok(hr == S_OK, "GetDescriptor failed: %#lx, expected S_OK\n", hr);
578 ok(desc.dwValidData & DMUS_OBJ_CLASS, "Got valid data %#lx, expected DMUS_OBJ_CLASS\n",
579 desc.dwValidData);
580 ok(IsEqualGUID(&desc.guidClass, &CLSID_DirectMusicStyle),
581 "Got class guid %s, expected CLSID_DirectMusicStyle\n",
582 wine_dbgstr_guid(&desc.guidClass));
584 /* Empty RIFF stream */
585 stream = gen_riff_stream(empty);
586 memset(&desc, 0, sizeof(desc));
587 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
588 ok(hr == S_OK, "ParseDescriptor failed: %#lx, expected S_OK\n", hr);
589 ok(desc.dwValidData == DMUS_OBJ_CLASS, "Got valid data %#lx, expected DMUS_OBJ_CLASS\n",
590 desc.dwValidData);
591 ok(IsEqualGUID(&desc.guidClass, &CLSID_DirectMusicStyle),
592 "Got class guid %s, expected CLSID_DirectMusicStyle\n",
593 wine_dbgstr_guid(&desc.guidClass));
594 IStream_Release(stream);
596 /* NULL pointers */
597 memset(&desc, 0, sizeof(desc));
598 hr = IDirectMusicObject_ParseDescriptor(dmo, NULL, &desc);
599 ok(hr == E_POINTER, "ParseDescriptor failed: %#lx, expected E_POINTER\n", hr);
600 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, NULL);
601 ok(hr == E_POINTER, "ParseDescriptor failed: %#lx, expected E_POINTER\n", hr);
603 /* Wrong form */
604 empty[1] = DMUS_FOURCC_CONTAINER_FORM;
605 stream = gen_riff_stream(empty);
606 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
607 ok(hr == DMUS_E_CHUNKNOTFOUND,
608 "ParseDescriptor failed: %#lx, expected DMUS_E_CHUNKNOTFOUND\n", hr);
609 IStream_Release(stream);
611 /* All desc chunks, DMUS_OBJ_CATEGORY not supported */
612 stream = gen_riff_stream(alldesc);
613 memset(&desc, 0, sizeof(desc));
614 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
615 ok(hr == S_OK, "ParseDescriptor failed: %#lx, expected S_OK\n", hr);
616 valid = DMUS_OBJ_OBJECT|DMUS_OBJ_CLASS|DMUS_OBJ_NAME|DMUS_OBJ_VERSION;
617 ok(desc.dwValidData == valid, "Got valid data %#lx, expected %#lx\n", desc.dwValidData, valid);
618 ok(IsEqualGUID(&desc.guidClass, &CLSID_DirectMusicStyle),
619 "Got class guid %s, expected CLSID_DirectMusicStyle\n",
620 wine_dbgstr_guid(&desc.guidClass));
621 ok(IsEqualGUID(&desc.guidObject, &GUID_NULL), "Got object guid %s, expected GUID_NULL\n",
622 wine_dbgstr_guid(&desc.guidClass));
623 ok(!lstrcmpW(desc.wszName, L"UNAM"), "Got name '%s', expected 'UNAM'\n",
624 wine_dbgstr_w(desc.wszName));
625 IStream_Release(stream);
627 /* UNFO list with INAM */
628 inam[3] = DMUS_FOURCC_UNFO_LIST;
629 stream = gen_riff_stream(inam);
630 memset(&desc, 0, sizeof(desc));
631 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
632 ok(hr == S_OK, "ParseDescriptor failed: %#lx, expected S_OK\n", hr);
633 ok(desc.dwValidData == (DMUS_OBJ_CLASS | DMUS_OBJ_NAME),
634 "Got valid data %#lx, expected DMUS_OBJ_CLASS | DMUS_OBJ_NAME\n", desc.dwValidData);
635 ok(!lstrcmpW(desc.wszName, L"INAM"), "Got name '%s', expected 'INAM'\n",
636 wine_dbgstr_w(desc.wszName));
637 IStream_Release(stream);
639 /* INFO list with INAM */
640 inam[3] = DMUS_FOURCC_INFO_LIST;
641 stream = gen_riff_stream(inam);
642 memset(&desc, 0, sizeof(desc));
643 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
644 ok(hr == S_OK, "ParseDescriptor failed: %#lx, expected S_OK\n", hr);
645 ok(desc.dwValidData == DMUS_OBJ_CLASS, "Got valid data %#lx, expected DMUS_OBJ_CLASS\n",
646 desc.dwValidData);
647 IStream_Release(stream);
649 /* Duplicated chunks */
650 stream = gen_riff_stream(dupes);
651 memset(&desc, 0, sizeof(desc));
652 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
653 ok(hr == S_OK, "ParseDescriptor failed: %#lx, expected S_OK\n", hr);
654 valid = DMUS_OBJ_OBJECT|DMUS_OBJ_CLASS|DMUS_OBJ_NAME|DMUS_OBJ_VERSION;
655 ok(desc.dwValidData == valid, "Got valid data %#lx, expected %#lx\n", desc.dwValidData, valid);
656 ok(!lstrcmpW(desc.wszName, L"INAM"), "Got name '%s', expected 'INAM'\n",
657 wine_dbgstr_w(desc.wszName));
658 IStream_Release(stream);
660 IDirectMusicObject_Release(dmo);
663 START_TEST(dmstyle)
665 CoInitialize(NULL);
667 if (missing_dmstyle())
669 skip("dmstyle not available\n");
670 CoUninitialize();
671 return;
673 test_COM();
674 test_COM_section();
675 test_COM_track();
676 test_dmstyle();
677 test_track();
678 test_parsedescriptor();
680 CoUninitialize();