include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / dmusic / tests / dmusic.c
blob3b2f7d9160ea315c703c041e89efd58d05e96c1d
1 /*
2 * Unit tests for dmusic functions
4 * Copyright (C) 2012 Christian Costa
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
23 #include <stdio.h>
25 #include "wine/test.h"
26 #include "uuids.h"
27 #include "ole2.h"
28 #include "initguid.h"
29 #include "dmusici.h"
30 #include "dmusicf.h"
31 #include "dmksctrl.h"
33 static ULONG get_refcount(void *iface)
35 IUnknown *unknown = iface;
36 IUnknown_AddRef(unknown);
37 return IUnknown_Release(unknown);
40 #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
41 static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported)
43 ULONG expect_ref = get_refcount(iface_ptr);
44 IUnknown *iface = iface_ptr;
45 HRESULT hr, expected;
46 IUnknown *unk;
48 expected = supported ? S_OK : E_NOINTERFACE;
49 hr = IUnknown_QueryInterface(iface, iid, (void **)&unk);
50 ok_(__FILE__, line)(hr == expected, "got hr %#lx, expected %#lx.\n", hr, expected);
51 if (SUCCEEDED(hr))
53 LONG ref = get_refcount(unk);
54 ok_(__FILE__, line)(ref == expect_ref + 1, "got %ld\n", ref);
55 IUnknown_Release(unk);
56 ref = get_refcount(iface_ptr);
57 ok_(__FILE__, line)(ref == expect_ref, "got %ld\n", ref);
61 static void stream_begin_chunk(IStream *stream, const char type[5], ULARGE_INTEGER *offset)
63 static const LARGE_INTEGER zero = {0};
64 HRESULT hr;
65 hr = IStream_Write(stream, type, 4, NULL);
66 ok(hr == S_OK, "got %#lx\n", hr);
67 hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, offset);
68 ok(hr == S_OK, "got %#lx\n", hr);
69 hr = IStream_Write(stream, "\0\0\0\0", 4, NULL);
70 ok(hr == S_OK, "got %#lx\n", hr);
73 static void stream_end_chunk(IStream *stream, ULARGE_INTEGER *offset)
75 static const LARGE_INTEGER zero = {0};
76 ULARGE_INTEGER position;
77 HRESULT hr;
78 UINT size;
79 hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, &position);
80 ok(hr == S_OK, "got %#lx\n", hr);
81 hr = IStream_Seek(stream, *(LARGE_INTEGER *)offset, STREAM_SEEK_SET, NULL);
82 ok(hr == S_OK, "got %#lx\n", hr);
83 size = position.QuadPart - offset->QuadPart - 4;
84 hr = IStream_Write(stream, &size, 4, NULL);
85 ok(hr == S_OK, "got %#lx\n", hr);
86 hr = IStream_Seek(stream, *(LARGE_INTEGER *)&position, STREAM_SEEK_SET, NULL);
87 ok(hr == S_OK, "got %#lx\n", hr);
88 hr = IStream_Write(stream, &zero, (position.QuadPart & 1), NULL);
89 ok(hr == S_OK, "got %#lx\n", hr);
92 #define CHUNK_BEGIN(stream, type) \
93 do { \
94 ULARGE_INTEGER __off; \
95 IStream *__stream = (stream); \
96 stream_begin_chunk(stream, type, &__off); \
99 #define CHUNK_RIFF(stream, form) \
100 do { \
101 ULARGE_INTEGER __off; \
102 IStream *__stream = (stream); \
103 stream_begin_chunk(stream, "RIFF", &__off); \
104 IStream_Write(stream, form, 4, NULL); \
107 #define CHUNK_LIST(stream, form) \
108 do { \
109 ULARGE_INTEGER __off; \
110 IStream *__stream = (stream); \
111 stream_begin_chunk(stream, "LIST", &__off); \
112 IStream_Write(stream, form, 4, NULL); \
115 #define CHUNK_END \
116 while (0); \
117 stream_end_chunk(__stream, &__off); \
118 } while (0)
120 #define CHUNK_DATA(stream, type, data) \
121 CHUNK_BEGIN(stream, type) \
123 IStream_Write((stream), &(data), sizeof(data), NULL); \
125 CHUNK_END
127 static BOOL compare_time(REFERENCE_TIME x, REFERENCE_TIME y, unsigned int max_diff)
129 REFERENCE_TIME diff = x > y ? x - y : y - x;
130 return diff <= max_diff;
133 static void test_dmusic(void)
135 IDirectMusic *dmusic = NULL;
136 HRESULT hr;
137 ULONG index = 0;
138 DMUS_PORTCAPS port_caps;
139 DMUS_PORTPARAMS port_params;
140 IDirectMusicPort *port = NULL;
142 hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusic, (LPVOID*)&dmusic);
143 ok(hr == S_OK, "Cannot create DirectMusic object: %#lx\n", hr);
145 port_params.dwSize = sizeof(port_params);
146 port_params.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS | DMUS_PORTPARAMS_AUDIOCHANNELS;
147 port_params.dwChannelGroups = 1;
148 port_params.dwAudioChannels = 2;
150 /* No port can be created before SetDirectSound is called */
151 hr = IDirectMusic_CreatePort(dmusic, &GUID_NULL, &port_params, &port, NULL);
152 ok(hr == DMUS_E_DSOUND_NOT_SET, "IDirectMusic_CreatePort returned: %#lx\n", hr);
154 hr = IDirectMusic_SetDirectSound(dmusic, NULL, NULL);
155 ok(hr == S_OK, "IDirectMusic_SetDirectSound returned: %#lx\n", hr);
157 /* Check wrong params */
158 hr = IDirectMusic_CreatePort(dmusic, &GUID_NULL, &port_params, &port, (IUnknown*)dmusic);
159 ok(hr == CLASS_E_NOAGGREGATION, "IDirectMusic_CreatePort returned: %#lx\n", hr);
160 hr = IDirectMusic_CreatePort(dmusic, NULL, &port_params, &port, NULL);
161 ok(hr == E_POINTER, "IDirectMusic_CreatePort returned: %#lx\n", hr);
162 hr = IDirectMusic_CreatePort(dmusic, &GUID_NULL, NULL, &port, NULL);
163 ok(hr == E_INVALIDARG, "IDirectMusic_CreatePort returned: %#lx\n", hr);
164 hr = IDirectMusic_CreatePort(dmusic, &GUID_NULL, &port_params, NULL, NULL);
165 ok(hr == E_POINTER, "IDirectMusic_CreatePort returned: %#lx\n", hr);
167 /* Test creation of default port with GUID_NULL */
168 hr = IDirectMusic_CreatePort(dmusic, &GUID_NULL, &port_params, &port, NULL);
169 ok(hr == S_OK, "IDirectMusic_CreatePort returned: %#lx\n", hr);
171 port_caps.dwSize = sizeof(port_caps);
172 while (IDirectMusic_EnumPort(dmusic, index, &port_caps) == S_OK)
174 ok(port_caps.dwSize == sizeof(port_caps), "DMUS_PORTCAPS dwSize member is wrong (%lu)\n", port_caps.dwSize);
175 trace("Port %lu:\n", index);
176 trace(" dwFlags = %lx\n", port_caps.dwFlags);
177 trace(" guidPort = %s\n", wine_dbgstr_guid(&port_caps.guidPort));
178 trace(" dwClass = %lu\n", port_caps.dwClass);
179 trace(" dwType = %lu\n", port_caps.dwType);
180 trace(" dwMemorySize = %lu\n", port_caps.dwMemorySize);
181 trace(" dwMaxChannelGroups = %lu\n", port_caps.dwMaxChannelGroups);
182 trace(" dwMaxVoices = %lu\n", port_caps.dwMaxVoices);
183 trace(" dwMaxAudioChannels = %lu\n", port_caps.dwMaxAudioChannels);
184 trace(" dwEffectFlags = %lx\n", port_caps.dwEffectFlags);
185 trace(" wszDescription = %s\n", wine_dbgstr_w(port_caps.wszDescription));
186 index++;
189 if (port)
190 IDirectMusicPort_Release(port);
191 IDirectMusic_Release(dmusic);
194 static void test_setdsound(void)
196 IDirectMusic *dmusic;
197 IDirectSound *dsound, *dsound2;
198 DMUS_PORTPARAMS params;
199 IDirectMusicPort *port = NULL;
200 HRESULT hr;
201 ULONG ref;
203 params.dwSize = sizeof(params);
204 params.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS | DMUS_PORTPARAMS_AUDIOCHANNELS;
205 params.dwChannelGroups = 1;
206 params.dwAudioChannels = 2;
208 /* Old dsound without SetCooperativeLevel() */
209 hr = DirectSoundCreate(NULL, &dsound, NULL);
210 if (hr == DSERR_NODRIVER ) {
211 skip("No driver\n");
212 return;
214 ok(hr == S_OK, "DirectSoundCreate failed: %#lx\n", hr);
215 hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusic8,
216 (void **)&dmusic);
217 ok(hr == S_OK, "DirectMusic create failed: %#lx\n", hr);
218 hr = IDirectMusic_SetDirectSound(dmusic, dsound, NULL);
219 ok(hr == S_OK, "SetDirectSound failed: %#lx\n", hr);
220 hr = IDirectMusic_CreatePort(dmusic, &GUID_NULL, &params, &port, NULL);
221 ok(hr == S_OK, "CreatePort returned: %#lx\n", hr);
222 IDirectMusicPort_Release(port);
223 IDirectMusic_Release(dmusic);
224 IDirectSound_Release(dsound);
226 /* dsound ref counting */
227 hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusic8,
228 (void **)&dmusic);
229 ok(hr == S_OK, "DirectMusic create failed: %#lx\n", hr);
230 hr = DirectSoundCreate8(NULL, (IDirectSound8 **)&dsound, NULL);
231 ok(hr == S_OK, "DirectSoundCreate failed: %#lx\n", hr);
232 hr = IDirectSound_SetCooperativeLevel(dsound, GetForegroundWindow(), DSSCL_PRIORITY);
233 ok(hr == S_OK, "SetCooperativeLevel failed: %#lx\n", hr);
234 hr = IDirectMusic_SetDirectSound(dmusic, dsound, NULL);
235 ok(hr == S_OK, "SetDirectSound failed: %#lx\n", hr);
236 ref = get_refcount(dsound);
237 ok(ref == 2, "dsound ref count got %ld expected 2\n", ref);
238 hr = IDirectMusic_CreatePort(dmusic, &GUID_NULL, &params, &port, NULL);
239 ok(hr == S_OK, "CreatePort returned: %#lx\n", hr);
240 ref = get_refcount(dsound);
241 ok(ref == 2, "dsound ref count got %ld expected 2\n", ref);
242 IDirectMusicPort_AddRef(port);
243 ref = IDirectMusicPort_Release(port);
244 ok(ref == 1, "port ref count got %ld expected 1\n", ref);
245 hr = IDirectMusicPort_Activate(port, TRUE);
246 ok(hr == S_OK, "Port Activate returned: %#lx\n", hr);
247 ref = get_refcount(dsound);
248 ok(ref == 4, "dsound ref count got %ld expected 4\n", ref);
249 IDirectMusicPort_AddRef(port);
250 ref = IDirectMusicPort_Release(port);
251 ok(ref == 1, "port ref count got %ld expected 1\n", ref);
253 /* Releasing dsound from dmusic */
254 hr = IDirectMusic_SetDirectSound(dmusic, NULL, NULL);
255 ok(hr == DMUS_E_DSOUND_ALREADY_SET, "SetDirectSound failed: %#lx\n", hr);
256 hr = IDirectMusicPort_Activate(port, FALSE);
257 ok(hr == S_OK, "Port Activate returned: %#lx\n", hr);
258 ref = get_refcount(dsound);
259 ok(ref == 2, "dsound ref count got %ld expected 2\n", ref);
260 hr = IDirectMusic_SetDirectSound(dmusic, NULL, NULL);
261 ok(hr == S_OK, "SetDirectSound failed: %#lx\n", hr);
262 ref = get_refcount(dsound);
263 ok(ref == 1, "dsound ref count got %ld expected 1\n", ref);
265 /* Setting the same dsound twice */
266 hr = IDirectMusic_SetDirectSound(dmusic, dsound, NULL);
267 ok(hr == S_OK, "SetDirectSound failed: %#lx\n", hr);
268 ref = get_refcount(dsound);
269 ok(ref == 2, "dsound ref count got %ld expected 2\n", ref);
270 hr = IDirectMusic_SetDirectSound(dmusic, dsound, NULL);
271 ok(hr == S_OK, "SetDirectSound failed: %#lx\n", hr);
272 ref = get_refcount(dsound);
273 ok(ref == 2, "dsound ref count got %ld expected 2\n", ref);
275 /* Replacing one dsound with another */
276 hr = DirectSoundCreate8(NULL, (IDirectSound8 **)&dsound2, NULL);
277 ok(hr == S_OK, "DirectSoundCreate failed: %#lx\n", hr);
278 hr = IDirectMusic_SetDirectSound(dmusic, dsound2, NULL);
279 ok(hr == S_OK, "SetDirectSound failed: %#lx\n", hr);
280 ref = get_refcount(dsound);
281 ok(ref == 1, "dsound ref count got %ld expected 1\n", ref);
282 ref = get_refcount(dsound2);
283 ok(ref == 2, "dsound2 ref count got %ld expected 2\n", ref);
285 /* Replacing the dsound in the port */
286 hr = IDirectMusicPort_SetDirectSound(port, dsound, NULL);
287 ok(hr == S_OK, "SetDirectSound failed: %#lx\n", hr);
288 ref = get_refcount(dsound);
289 ok(ref == 2, "dsound ref count got %ld expected 2\n", ref);
290 ref = get_refcount(dsound2);
291 ok(ref == 2, "dsound2 ref count got %ld expected 2\n", ref);
292 /* Setting the dsound again on the port will mess with the parent dmusic */
293 hr = IDirectMusicPort_SetDirectSound(port, dsound, NULL);
294 ok(hr == S_OK, "SetDirectSound failed: %#lx\n", hr);
295 ref = get_refcount(dsound);
296 ok(ref == 3, "dsound ref count got %ld expected 3\n", ref);
297 ref = get_refcount(dsound2);
298 ok(ref == 1, "dsound2 ref count got %ld expected 1\n", ref);
299 IDirectSound_AddRef(dsound2); /* Crash prevention */
300 hr = IDirectMusicPort_Activate(port, TRUE);
301 ok(hr == S_OK, "Activate returned: %#lx\n", hr);
302 ref = get_refcount(dsound);
303 ok(ref == 4, "dsound ref count got %ld expected 4\n", ref);
304 ref = get_refcount(dsound2);
305 ok(ref == 2, "dsound2 ref count got %ld expected 2\n", ref);
306 hr = IDirectMusicPort_Activate(port, TRUE);
307 ok(hr == S_FALSE, "Activate returned: %#lx\n", hr);
308 ref = get_refcount(dsound);
309 ok(ref == 4, "dsound ref count got %ld expected 4\n", ref);
310 ref = get_refcount(dsound2);
311 ok(ref == 2, "dsound2 ref count got %ld expected 2\n", ref);
313 /* Deactivating the port messes with the dsound refcount in the parent dmusic */
314 hr = IDirectMusicPort_Activate(port, FALSE);
315 ok(hr == S_OK, "Port Activate returned: %#lx\n", hr);
316 ref = get_refcount(dsound);
317 ok(ref == 3, "dsound ref count got %ld expected 3\n", ref);
318 ref = get_refcount(dsound2);
319 ok(ref == 1, "dsound2 ref count got %ld expected 1\n", ref);
320 hr = IDirectMusicPort_Activate(port, FALSE);
321 ok(hr == S_FALSE, "Port Activate returned: %#lx\n", hr);
322 ref = get_refcount(dsound);
323 ok(ref == 3, "dsound ref count got %ld expected 3\n", ref);
324 ref = get_refcount(dsound2);
325 ok(ref == 1, "dsound2 ref count got %ld expected 1\n", ref);
327 IDirectMusicPort_Release(port);
328 IDirectMusic_Release(dmusic);
329 while (IDirectSound_Release(dsound));
332 static void test_dmbuffer(void)
334 IDirectMusic *dmusic;
335 IDirectMusicBuffer *dmbuffer = NULL;
336 HRESULT hr;
337 DMUS_BUFFERDESC desc;
338 GUID format;
339 DWORD size;
340 DWORD bytes;
341 REFERENCE_TIME time;
342 LPBYTE data;
344 hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusic, (LPVOID*)&dmusic);
345 ok(hr == S_OK, "Cannot create DirectMusic object: %#lx\n", hr);
347 desc.dwSize = sizeof(DMUS_BUFFERDESC);
348 desc.dwFlags = 0;
349 desc.cbBuffer = 1023;
350 memcpy(&desc.guidBufferFormat, &GUID_NULL, sizeof(GUID));
352 hr = IDirectMusic_CreateMusicBuffer(dmusic, &desc, &dmbuffer, NULL);
353 ok(hr == S_OK, "IDirectMusic_CreateMusicBuffer returned %#lx\n", hr);
355 hr = IDirectMusicBuffer_GetBufferFormat(dmbuffer, &format);
356 ok(hr == S_OK, "IDirectMusicBuffer_GetBufferFormat returned %#lx\n", hr);
357 ok(IsEqualGUID(&format, &KSDATAFORMAT_SUBTYPE_MIDI), "Wrong format returned %s\n", wine_dbgstr_guid(&format));
358 hr = IDirectMusicBuffer_GetMaxBytes(dmbuffer, &size);
359 ok(hr == S_OK, "IDirectMusicBuffer_GetMaxBytes returned %#lx\n", hr);
360 ok(size == 1024, "Buffer size is %lu instead of 1024\n", size);
362 hr = IDirectMusicBuffer_GetStartTime(dmbuffer, &time);
363 ok(hr == DMUS_E_BUFFER_EMPTY, "IDirectMusicBuffer_GetStartTime returned %#lx\n", hr);
364 hr = IDirectMusicBuffer_SetStartTime(dmbuffer, 10);
365 ok(hr == S_OK, "IDirectMusicBuffer_GetStartTime returned %#lx\n", hr);
366 hr = IDirectMusicBuffer_GetStartTime(dmbuffer, &time);
367 ok(hr == DMUS_E_BUFFER_EMPTY, "IDirectMusicBuffer_GetStartTime returned %#lx\n", hr);
369 hr = IDirectMusicBuffer_PackStructured(dmbuffer, 20, 0, 0);
370 ok(hr == DMUS_E_INVALID_EVENT, "IDirectMusicBuffer_PackStructured returned %#lx\n", hr);
371 hr = IDirectMusicBuffer_PackStructured(dmbuffer, 20, 0, 0x000090); /* note on : chan 0, note 0 & vel 0 */
372 ok(hr == S_OK, "IDirectMusicBuffer_PackStructured returned %#lx\n", hr);
373 hr = IDirectMusicBuffer_PackStructured(dmbuffer, 30, 0, 0x000080); /* note off : chan 0, note 0 & vel 0 */
374 ok(hr == S_OK, "IDirectMusicBuffer_PackStructured returned %#lx\n", hr);
375 hr = IDirectMusicBuffer_GetUsedBytes(dmbuffer, &bytes);
376 ok(hr == S_OK, "IDirectMusicBuffer_GetUsedBytes returned %#lx\n", hr);
377 ok(bytes == 48, "Buffer size is %lu instead of 48\n", bytes);
379 hr = IDirectMusicBuffer_GetStartTime(dmbuffer, &time);
380 ok(hr == S_OK, "IDirectMusicBuffer_GetStartTime returned %#lx\n", hr);
381 ok(time == 20, "Buffer start time is wrong\n");
382 hr = IDirectMusicBuffer_SetStartTime(dmbuffer, 40);
383 ok(hr == S_OK, "IDirectMusicBuffer_GetStartTime returned %#lx\n", hr);
384 hr = IDirectMusicBuffer_GetStartTime(dmbuffer, &time);
385 ok(hr == S_OK, "IDirectMusicBuffer_GetStartTime returned %#lx\n", hr);
386 ok(time == 40, "Buffer start time is wrong\n");
388 hr = IDirectMusicBuffer_GetRawBufferPtr(dmbuffer, &data);
389 ok(hr == S_OK, "IDirectMusicBuffer_GetRawBufferPtr returned %#lx\n", hr);
390 if (hr == S_OK)
392 DMUS_EVENTHEADER* header;
393 DWORD message;
395 /* Check message 1 */
396 header = (DMUS_EVENTHEADER*)data;
397 data += sizeof(DMUS_EVENTHEADER);
398 ok(header->cbEvent == 3, "cbEvent is %lu instead of 3\n", header->cbEvent);
399 ok(header->dwChannelGroup == 0, "dwChannelGroup is %lu instead of 0\n", header->dwChannelGroup);
400 ok(header->rtDelta == 0, "rtDelta is %s instead of 0\n", wine_dbgstr_longlong(header->rtDelta));
401 ok(header->dwFlags == DMUS_EVENT_STRUCTURED, "dwFlags is %lx instead of %x\n", header->dwFlags, DMUS_EVENT_STRUCTURED);
402 message = *(DWORD*)data & 0xffffff; /* Only 3 bytes are relevant */
403 data += sizeof(DWORD);
404 ok(message == 0x000090, "Message is %0lx instead of 0x000090\n", message);
406 /* Check message 2 */
407 header = (DMUS_EVENTHEADER*)data;
408 data += sizeof(DMUS_EVENTHEADER);
409 ok(header->cbEvent == 3, "cbEvent is %lu instead of 3\n", header->cbEvent);
410 ok(header->dwChannelGroup == 0, "dwChannelGroup is %lu instead of 0\n", header->dwChannelGroup);
411 ok(header->rtDelta == 10, "rtDelta is %s instead of 0\n", wine_dbgstr_longlong(header->rtDelta));
412 ok(header->dwFlags == DMUS_EVENT_STRUCTURED, "dwFlags is %lx instead of %x\n", header->dwFlags, DMUS_EVENT_STRUCTURED);
413 message = *(DWORD*)data & 0xffffff; /* Only 3 bytes are relevant */
414 ok(message == 0x000080, "Message 2 is %0lx instead of 0x000080\n", message);
417 if (dmbuffer)
418 IDirectMusicBuffer_Release(dmbuffer);
419 IDirectMusic_Release(dmusic);
422 static void test_COM(void)
424 IDirectMusic8 *dm8 = (IDirectMusic8*)0xdeadbeef;
425 IDirectMusic *dm;
426 IUnknown *unk;
427 ULONG refcount;
428 HRESULT hr;
430 /* COM aggregation */
431 hr = CoCreateInstance(&CLSID_DirectMusic, (IUnknown *)0xdeadbeef, CLSCTX_INPROC_SERVER, &IID_IUnknown,
432 (void**)&dm8);
433 ok(hr == CLASS_E_NOAGGREGATION,
434 "DirectMusic8 create failed: %#lx, expected CLASS_E_NOAGGREGATION\n", hr);
435 ok(!dm8, "dm8 = %p\n", dm8);
437 /* Invalid RIID */
438 hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject,
439 (void**)&dm8);
440 ok(hr == E_NOINTERFACE, "DirectMusic8 create failed: %#lx, expected E_NOINTERFACE\n", hr);
442 /* Same refcount for DirectMusic and DirectMusic8 */
443 hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusic8,
444 (void**)&dm8);
445 if (hr == E_NOINTERFACE)
447 win_skip("DirectMusic too old (no IDirectMusic8)\n");
448 return;
450 ok(hr == S_OK, "DirectMusic8 create failed: %#lx, expected S_OK\n", hr);
451 refcount = IDirectMusic8_AddRef(dm8);
452 ok(refcount == 2, "refcount == %lu, expected 2\n", refcount);
454 hr = IDirectMusic8_QueryInterface(dm8, &IID_IDirectMusic, (void**)&dm);
455 ok(hr == S_OK, "QueryInterface for IID_IDirectMusic failed: %#lx\n", hr);
456 refcount = IDirectMusic_AddRef(dm);
457 ok(refcount == 4, "refcount == %lu, expected 4\n", refcount);
458 IDirectMusic_Release(dm);
460 hr = IDirectMusic8_QueryInterface(dm8, &IID_IUnknown, (void**)&unk);
461 ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %#lx\n", hr);
462 refcount = IUnknown_AddRef(unk);
463 ok(refcount == 5, "refcount == %lu, expected 5\n", refcount);
464 refcount = IUnknown_Release(unk);
466 ok(refcount == 4, "refcount == %lu, expected 4\n", refcount);
467 while (IDirectMusic8_Release(dm8));
470 static void test_COM_dmcoll(void)
472 IDirectMusicCollection *dmc = (IDirectMusicCollection*)0xdeadbeef;
473 IDirectMusicObject *dmo;
474 IPersistStream *ps;
475 IUnknown *unk;
476 ULONG refcount;
477 HRESULT hr;
479 /* COM aggregation */
480 hr = CoCreateInstance(&CLSID_DirectMusicCollection, (IUnknown *)0xdeadbeef, CLSCTX_INPROC_SERVER,
481 &IID_IUnknown, (void**)&dmc);
482 ok(hr == CLASS_E_NOAGGREGATION,
483 "DirectMusicCollection create failed: %#lx, expected CLASS_E_NOAGGREGATION\n", hr);
484 ok(!dmc, "dmc = %p\n", dmc);
486 /* Invalid RIID */
487 hr = CoCreateInstance(&CLSID_DirectMusicCollection, NULL, CLSCTX_INPROC_SERVER,
488 &IID_IClassFactory, (void**)&dmc);
489 ok(hr == E_NOINTERFACE, "DirectMusicCollection create failed: %#lx, expected E_NOINTERFACE\n", hr);
491 /* Same refcount for all DirectMusicCollection interfaces */
492 hr = CoCreateInstance(&CLSID_DirectMusicCollection, NULL, CLSCTX_INPROC_SERVER,
493 &IID_IDirectMusicCollection, (void**)&dmc);
494 ok(hr == S_OK, "DirectMusicCollection create failed: %#lx, expected S_OK\n", hr);
495 refcount = IDirectMusicCollection_AddRef(dmc);
496 ok(refcount == 2, "refcount == %lu, expected 2\n", refcount);
498 hr = IDirectMusicCollection_QueryInterface(dmc, &IID_IDirectMusicObject, (void**)&dmo);
499 ok(hr == S_OK, "QueryInterface for IID_IDirectMusicObject failed: %#lx\n", hr);
500 refcount = IDirectMusicObject_AddRef(dmo);
501 ok(refcount == 4, "refcount == %lu, expected 4\n", refcount);
502 refcount = IDirectMusicObject_Release(dmo);
504 hr = IDirectMusicCollection_QueryInterface(dmc, &IID_IPersistStream, (void**)&ps);
505 ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
506 refcount = IPersistStream_AddRef(ps);
507 ok(refcount == 5, "refcount == %lu, expected 5\n", refcount);
508 refcount = IPersistStream_Release(ps);
510 hr = IDirectMusicCollection_QueryInterface(dmc, &IID_IUnknown, (void**)&unk);
511 ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %#lx\n", hr);
512 refcount = IUnknown_AddRef(unk);
513 ok(refcount == 6, "refcount == %lu, expected 6\n", refcount);
514 refcount = IUnknown_Release(unk);
516 ok(refcount == 5, "refcount == %lu, expected 5\n", refcount);
517 while (IDirectMusicCollection_Release(dmc));
520 static void test_dmcoll(void)
522 IDirectMusicCollection *dmc;
523 IDirectMusicObject *dmo;
524 IPersistStream *ps;
525 DMUS_OBJECTDESC desc;
526 CLSID class;
527 ULARGE_INTEGER size;
528 HRESULT hr;
530 hr = CoCreateInstance(&CLSID_DirectMusicCollection, NULL, CLSCTX_INPROC_SERVER,
531 &IID_IDirectMusicCollection, (void**)&dmc);
532 ok(hr == S_OK, "DirectMusicCollection create failed: %#lx, expected S_OK\n", hr);
534 /* IDirectMusicObject */
535 hr = IDirectMusicCollection_QueryInterface(dmc, &IID_IDirectMusicObject, (void**)&dmo);
536 ok(hr == S_OK, "QueryInterface for IID_IDirectMusicObject failed: %#lx\n", hr);
537 hr = IDirectMusicObject_GetDescriptor(dmo, NULL);
538 ok(hr == E_POINTER, "IDirectMusicObject_GetDescriptor: expected E_POINTER, got %#lx\n", hr);
539 hr = IDirectMusicObject_SetDescriptor(dmo, NULL);
540 ok(hr == E_POINTER, "IDirectMusicObject_SetDescriptor: expected E_POINTER, got %#lx\n", hr);
541 ZeroMemory(&desc, sizeof(desc));
542 hr = IDirectMusicObject_GetDescriptor(dmo, &desc);
543 ok(hr == S_OK, "IDirectMusicObject_GetDescriptor failed: %#lx\n", hr);
544 ok(desc.dwValidData == DMUS_OBJ_CLASS,
545 "Fresh object has more valid data (%#lx) than DMUS_OBJ_CLASS\n", desc.dwValidData);
546 /* DMUS_OBJ_CLASS is immutable */
547 desc.dwValidData = DMUS_OBJ_CLASS;
548 hr = IDirectMusicObject_SetDescriptor(dmo, &desc);
549 ok(hr == S_FALSE , "IDirectMusicObject_SetDescriptor failed: %#lx\n", hr);
550 ok(!desc.dwValidData, "dwValidData wasn't cleared: %#lx\n", desc.dwValidData);
551 desc.dwValidData = DMUS_OBJ_CLASS;
552 desc.guidClass = CLSID_DirectMusicSegment;
553 hr = IDirectMusicObject_SetDescriptor(dmo, &desc);
554 ok(hr == S_FALSE && !desc.dwValidData, "IDirectMusicObject_SetDescriptor failed: %#lx\n", hr);
555 hr = IDirectMusicObject_GetDescriptor(dmo, &desc);
556 ok(hr == S_OK, "IDirectMusicObject_GetDescriptor failed: %#lx\n", hr);
557 ok(IsEqualGUID(&desc.guidClass, &CLSID_DirectMusicCollection),
558 "guidClass changed, should be CLSID_DirectMusicCollection\n");
560 /* Unimplemented IPersistStream methods*/
561 hr = IDirectMusicCollection_QueryInterface(dmc, &IID_IPersistStream, (void**)&ps);
562 ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr);
563 hr = IPersistStream_GetClassID(ps, &class);
564 ok(hr == E_NOTIMPL, "IPersistStream_GetClassID failed: %#lx\n", hr);
565 hr = IPersistStream_IsDirty(ps);
566 ok(hr == S_FALSE, "IPersistStream_IsDirty failed: %#lx\n", hr);
567 hr = IPersistStream_GetSizeMax(ps, &size);
568 ok(hr == E_NOTIMPL, "IPersistStream_GetSizeMax failed: %#lx\n", hr);
569 hr = IPersistStream_Save(ps, NULL, TRUE);
570 ok(hr == E_NOTIMPL, "IPersistStream_Save failed: %#lx\n", hr);
572 while (IDirectMusicCollection_Release(dmc));
575 static BOOL missing_dmusic(void)
577 IDirectMusic8 *dm;
578 HRESULT hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusic,
579 (void**)&dm);
581 if (hr == S_OK && dm)
583 IDirectMusic_Release(dm);
584 return FALSE;
586 return TRUE;
589 static IDirectMusicPort *create_synth_port(IDirectMusic **dmusic)
591 IDirectMusicPort *port = NULL;
592 DMUS_PORTPARAMS params;
593 HRESULT hr;
595 hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusic, (void **)dmusic);
596 ok(hr == S_OK, "Cannot create DirectMusic object: %#lx\n", hr);
598 params.dwSize = sizeof(params);
599 params.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS | DMUS_PORTPARAMS_AUDIOCHANNELS;
600 params.dwChannelGroups = 1;
601 params.dwAudioChannels = 2;
602 hr = IDirectMusic_SetDirectSound(*dmusic, NULL, NULL);
603 ok(hr == S_OK, "IDirectMusic_SetDirectSound failed: %#lx\n", hr);
604 hr = IDirectMusic_CreatePort(*dmusic, &GUID_NULL, &params, &port, NULL);
605 ok(hr == S_OK, "IDirectMusic_CreatePort failed: %#lx\n", hr);
607 return port;
610 static void test_COM_synthport(void)
612 IDirectMusic *dmusic;
613 IDirectMusicPort *port;
614 IDirectMusicPortDownload *dmpd;
615 IDirectMusicThru *dmt;
616 IKsControl *iksc;
617 IReferenceClock *clock;
618 IUnknown *unk;
619 ULONG refcount;
620 HRESULT hr;
622 port = create_synth_port(&dmusic);
624 /* Same refcount for all DirectMusicPort interfaces */
625 refcount = IDirectMusicPort_AddRef(port);
626 ok(refcount == 2, "refcount == %lu, expected 2\n", refcount);
628 hr = IDirectMusicPort_QueryInterface(port, &IID_IDirectMusicPortDownload, (void**)&dmpd);
629 ok(hr == S_OK, "QueryInterface for IID_IDirectMusicPortDownload failed: %#lx\n", hr);
630 refcount = IDirectMusicPortDownload_AddRef(dmpd);
631 ok(refcount == 4, "refcount == %lu, expected 4\n", refcount);
632 IDirectMusicPortDownload_Release(dmpd);
634 hr = IDirectMusicPort_QueryInterface(port, &IID_IKsControl, (void**)&iksc);
635 ok(hr == S_OK, "QueryInterface for IID_IKsControl failed: %#lx\n", hr);
636 refcount = IKsControl_AddRef(iksc);
637 ok(refcount == 5, "refcount == %lu, expected 5\n", refcount);
638 IKsControl_Release(iksc);
640 hr = IDirectMusicPort_QueryInterface(port, &IID_IUnknown, (void**)&unk);
641 ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %#lx\n", hr);
642 refcount = IUnknown_AddRef(unk);
643 ok(refcount == 6, "refcount == %lu, expected 6\n", refcount);
644 IUnknown_Release(unk);
646 /* Unsupported interface */
647 hr = IDirectMusicPort_QueryInterface(port, &IID_IDirectMusicThru, (void**)&dmt);
648 todo_wine ok(hr == E_NOINTERFACE, "QueryInterface for IID_IDirectMusicThru failed: %#lx\n", hr);
649 hr = IDirectMusicPort_QueryInterface(port, &IID_IReferenceClock, (void**)&clock);
650 ok(hr == E_NOINTERFACE, "QueryInterface for IID_IReferenceClock failed: %#lx\n", hr);
652 while (IDirectMusicPort_Release(port));
653 refcount = IDirectMusic_Release(dmusic);
654 ok(!refcount, "Got outstanding refcount %ld.\n", refcount);
657 struct chunk {
658 FOURCC id;
659 DWORD size;
660 FOURCC type;
663 #define CHUNK_HDR_SIZE (sizeof(FOURCC) + sizeof(DWORD))
665 /* Generate a RIFF file format stream from an array of FOURCC ids.
666 RIFF and LIST need to be followed by the form type respectively list type,
667 followed by the chunks of the list and terminated with 0. */
668 static IStream *gen_riff_stream(const FOURCC *ids)
670 static const LARGE_INTEGER zero;
671 int level = -1;
672 DWORD *sizes[4]; /* Stack for the sizes of RIFF and LIST chunks */
673 char riff[1024];
674 char *p = riff;
675 struct chunk *ck;
676 IStream *stream;
678 do {
679 ck = (struct chunk *)p;
680 ck->id = *ids++;
681 switch (ck->id) {
682 case 0:
683 *sizes[level] = p - (char *)sizes[level] - sizeof(DWORD);
684 level--;
685 break;
686 case FOURCC_LIST:
687 case FOURCC_RIFF:
688 level++;
689 sizes[level] = &ck->size;
690 ck->type = *ids++;
691 p += sizeof(*ck);
692 break;
693 case DMUS_FOURCC_GUID_CHUNK:
694 ck->size = sizeof(GUID_NULL);
695 p += CHUNK_HDR_SIZE;
696 memcpy(p, &GUID_NULL, sizeof(GUID_NULL));
697 p += ck->size;
698 break;
699 case DMUS_FOURCC_VERSION_CHUNK:
701 DMUS_VERSION ver = {5, 8};
703 ck->size = sizeof(ver);
704 p += CHUNK_HDR_SIZE;
705 memcpy(p, &ver, sizeof(ver));
706 p += ck->size;
707 break;
709 case mmioFOURCC('I','N','A','M'):
710 ck->size = 5;
711 p += CHUNK_HDR_SIZE;
712 strcpy(p, "INAM");
713 p += ck->size + 1; /* WORD aligned */
714 break;
715 default:
717 /* Just convert the FOURCC id to a WCHAR string */
718 WCHAR *s;
720 ck->size = 5 * sizeof(WCHAR);
721 p += CHUNK_HDR_SIZE;
722 s = (WCHAR *)p;
723 s[0] = (char)(ck->id);
724 s[1] = (char)(ck->id >> 8);
725 s[2] = (char)(ck->id >> 16);
726 s[3] = (char)(ck->id >> 24);
727 s[4] = 0;
728 p += ck->size;
731 } while (level >= 0);
733 ck = (struct chunk *)riff;
734 CreateStreamOnHGlobal(NULL, TRUE, &stream);
735 IStream_Write(stream, riff, ck->size + CHUNK_HDR_SIZE, NULL);
736 IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
738 return stream;
741 static void test_parsedescriptor(void)
743 IDirectMusicObject *dmo;
744 IStream *stream;
745 DMUS_OBJECTDESC desc = {0};
746 HRESULT hr;
747 const FOURCC alldesc[] =
749 FOURCC_RIFF, FOURCC_DLS, DMUS_FOURCC_CATEGORY_CHUNK, FOURCC_LIST,
750 DMUS_FOURCC_UNFO_LIST, DMUS_FOURCC_UNAM_CHUNK, DMUS_FOURCC_UCOP_CHUNK,
751 DMUS_FOURCC_UCMT_CHUNK, DMUS_FOURCC_USBJ_CHUNK, 0, DMUS_FOURCC_VERSION_CHUNK,
752 DMUS_FOURCC_GUID_CHUNK, 0
754 const FOURCC dupes[] =
756 FOURCC_RIFF, FOURCC_DLS, DMUS_FOURCC_CATEGORY_CHUNK, DMUS_FOURCC_CATEGORY_CHUNK,
757 DMUS_FOURCC_VERSION_CHUNK, DMUS_FOURCC_VERSION_CHUNK, DMUS_FOURCC_GUID_CHUNK,
758 DMUS_FOURCC_GUID_CHUNK, FOURCC_LIST, DMUS_FOURCC_INFO_LIST, mmioFOURCC('I','N','A','M'), 0,
759 FOURCC_LIST, DMUS_FOURCC_INFO_LIST, mmioFOURCC('I','N','A','M'), 0, 0
761 FOURCC empty[] = {FOURCC_RIFF, FOURCC_DLS, 0};
762 FOURCC inam[] =
764 FOURCC_RIFF, FOURCC_DLS, FOURCC_LIST, DMUS_FOURCC_UNFO_LIST,
765 mmioFOURCC('I','N','A','M'), 0, 0
768 hr = CoCreateInstance(&CLSID_DirectMusicCollection, NULL, CLSCTX_INPROC_SERVER,
769 &IID_IDirectMusicObject, (void **)&dmo);
770 ok(hr == S_OK, "DirectMusicCollection create failed: %#lx, expected S_OK\n", hr);
772 /* Nothing loaded */
773 hr = IDirectMusicObject_GetDescriptor(dmo, &desc);
774 ok(hr == S_OK, "GetDescriptor failed: %#lx, expected S_OK\n", hr);
775 ok(desc.dwValidData == DMUS_OBJ_CLASS, "Got valid data %#lx, expected DMUS_OBJ_OBJECT\n",
776 desc.dwValidData);
777 ok(IsEqualGUID(&desc.guidClass, &CLSID_DirectMusicCollection),
778 "Got class guid %s, expected CLSID_DirectMusicCollection\n",
779 wine_dbgstr_guid(&desc.guidClass));
781 /* Empty RIFF stream */
782 stream = gen_riff_stream(empty);
783 memset(&desc, 0, sizeof(desc));
784 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
785 ok(hr == S_OK, "ParseDescriptor failed: %#lx, expected S_OK\n", hr);
786 ok(desc.dwValidData == DMUS_OBJ_CLASS, "Got valid data %#lx, expected DMUS_OBJ_CLASS\n",
787 desc.dwValidData);
788 ok(IsEqualGUID(&desc.guidClass, &CLSID_DirectMusicCollection),
789 "Got class guid %s, expected CLSID_DirectMusicCollection\n",
790 wine_dbgstr_guid(&desc.guidClass));
791 IStream_Release(stream);
793 /* NULL pointers */
794 memset(&desc, 0, sizeof(desc));
795 hr = IDirectMusicObject_ParseDescriptor(dmo, NULL, &desc);
796 ok(hr == E_POINTER, "ParseDescriptor failed: %#lx, expected E_POINTER\n", hr);
797 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, NULL);
798 ok(hr == E_POINTER, "ParseDescriptor failed: %#lx, expected E_POINTER\n", hr);
800 /* Wrong form */
801 empty[1] = DMUS_FOURCC_CONTAINER_FORM;
802 stream = gen_riff_stream(empty);
803 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
804 ok(hr == DMUS_E_NOTADLSCOL, "ParseDescriptor failed: %#lx, expected DMUS_E_NOTADLSCOL\n", hr);
805 IStream_Release(stream);
807 /* All desc chunks */
808 stream = gen_riff_stream(alldesc);
809 memset(&desc, 0, sizeof(desc));
810 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
811 ok(hr == S_OK, "ParseDescriptor failed: %#lx, expected S_OK\n", hr);
812 ok(desc.dwValidData == (DMUS_OBJ_CLASS | DMUS_OBJ_VERSION),
813 "Got valid data %#lx, expected DMUS_OBJ_CLASS | DMUS_OBJ_VERSION\n", desc.dwValidData);
814 ok(IsEqualGUID(&desc.guidClass, &CLSID_DirectMusicCollection),
815 "Got class guid %s, expected CLSID_DirectMusicCollection\n",
816 wine_dbgstr_guid(&desc.guidClass));
817 ok(IsEqualGUID(&desc.guidObject, &GUID_NULL), "Got object guid %s, expected GUID_NULL\n",
818 wine_dbgstr_guid(&desc.guidClass));
819 ok(desc.vVersion.dwVersionMS == 5 && desc.vVersion.dwVersionLS == 8,
820 "Got version %lu.%lu, expected 5.8\n", desc.vVersion.dwVersionMS,
821 desc.vVersion.dwVersionLS);
822 IStream_Release(stream);
824 /* UNFO list with INAM */
825 inam[3] = DMUS_FOURCC_UNFO_LIST;
826 stream = gen_riff_stream(inam);
827 memset(&desc, 0, sizeof(desc));
828 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
829 ok(hr == S_OK, "ParseDescriptor failed: %#lx, expected S_OK\n", hr);
830 ok(desc.dwValidData == DMUS_OBJ_CLASS, "Got valid data %#lx, expected DMUS_OBJ_CLASS\n",
831 desc.dwValidData);
832 IStream_Release(stream);
834 /* INFO list with INAM */
835 inam[3] = DMUS_FOURCC_INFO_LIST;
836 stream = gen_riff_stream(inam);
837 memset(&desc, 0, sizeof(desc));
838 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
839 ok(hr == S_OK, "ParseDescriptor failed: %#lx, expected S_OK\n", hr);
840 ok(desc.dwValidData == (DMUS_OBJ_CLASS | DMUS_OBJ_NAME),
841 "Got valid data %#lx, expected DMUS_OBJ_CLASS | DMUS_OBJ_NAME\n", desc.dwValidData);
842 ok(!lstrcmpW(desc.wszName, L"INAM"), "Got name '%s', expected 'INAM'\n",
843 wine_dbgstr_w(desc.wszName));
844 IStream_Release(stream);
846 /* Duplicated chunks */
847 stream = gen_riff_stream(dupes);
848 memset(&desc, 0, sizeof(desc));
849 hr = IDirectMusicObject_ParseDescriptor(dmo, stream, &desc);
850 ok(hr == S_OK, "ParseDescriptor failed: %#lx, expected S_OK\n", hr);
851 ok(desc.dwValidData == (DMUS_OBJ_CLASS | DMUS_OBJ_NAME | DMUS_OBJ_VERSION),
852 "Got valid data %#lx, expected DMUS_OBJ_CLASS | DMUS_OBJ_NAME | DMUS_OBJ_VERSION\n",
853 desc.dwValidData);
854 ok(!lstrcmpW(desc.wszName, L"INAM"), "Got name '%s', expected 'INAM'\n",
855 wine_dbgstr_w(desc.wszName));
856 IStream_Release(stream);
858 IDirectMusicObject_Release(dmo);
861 static void test_master_clock(void)
863 static const GUID guid_system_clock = {0x58d58419, 0x71b4, 0x11d1, {0xa7, 0x4c, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12}};
864 static const GUID guid_dsound_clock = {0x58d58420, 0x71b4, 0x11d1, {0xa7, 0x4c, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12}};
865 IReferenceClock *clock, *clock2;
866 REFERENCE_TIME time1, time2;
867 LARGE_INTEGER counter, freq;
868 DMUS_CLOCKINFO clock_info;
869 IDirectMusic *dmusic;
870 DWORD_PTR cookie;
871 HRESULT hr;
872 ULONG ref;
873 GUID guid;
875 hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusic, (void **)&dmusic);
876 ok(hr == S_OK, "Got hr %#lx.\n", hr);
878 hr = IDirectMusic_GetMasterClock(dmusic, NULL, NULL);
879 ok(hr == S_OK, "Got hr %#lx.\n", hr);
881 memset(&guid, 0xcc, sizeof(guid));
882 hr = IDirectMusic_GetMasterClock(dmusic, &guid, NULL);
883 ok(hr == S_OK, "Got hr %#lx.\n", hr);
884 todo_wine ok(IsEqualGUID(&guid, &guid_system_clock), "Got guid %s.\n", wine_dbgstr_guid(&guid));
886 clock = (IReferenceClock *)0xdeadbeef;
887 hr = IDirectMusic_GetMasterClock(dmusic, NULL, &clock);
888 ok(hr == S_OK, "Got hr %#lx.\n", hr);
889 ok(clock && clock != (IReferenceClock *)0xdeadbeef, "Got clock %p.\n", clock);
891 hr = IDirectMusic_GetMasterClock(dmusic, NULL, &clock2);
892 ok(hr == S_OK, "Got hr %#lx.\n", hr);
893 ok(clock2 == clock, "Clocks didn't match.\n");
894 IReferenceClock_Release(clock2);
896 memset(&guid, 0xcc, sizeof(guid));
897 hr = IDirectMusic_GetMasterClock(dmusic, &guid, &clock2);
898 ok(hr == S_OK, "Got hr %#lx.\n", hr);
899 todo_wine ok(IsEqualGUID(&guid, &guid_system_clock), "Got guid %s.\n", wine_dbgstr_guid(&guid));
900 ok(clock2 == clock, "Clocks didn't match.\n");
901 IReferenceClock_Release(clock2);
903 QueryPerformanceFrequency(&freq);
904 QueryPerformanceCounter(&counter);
905 hr = IReferenceClock_GetTime(clock, &time1);
906 ok(hr == S_OK, "Got hr %#lx.\n", hr);
907 time2 = counter.QuadPart * 10000000.0 / freq.QuadPart;
908 ok(compare_time(time1, time2, 20 * 10000), "Expected about %s, got %s.\n",
909 wine_dbgstr_longlong(time2), wine_dbgstr_longlong(time1));
911 hr = IReferenceClock_GetTime(clock, &time2);
912 ok(hr == (time2 == time1 ? S_FALSE : S_OK), "Got hr %#lx.\n", hr);
914 Sleep(100);
915 hr = IReferenceClock_GetTime(clock, &time2);
916 ok(hr == S_OK, "Got hr %#lx.\n", hr);
917 ok(time2 - time1 > 80 * 10000, "Expected about %s, but got %s.\n",
918 wine_dbgstr_longlong(time1 + 100 * 10000), wine_dbgstr_longlong(time2));
920 hr = IReferenceClock_AdviseTime(clock, 0, 0, 0, &cookie);
921 ok(hr == E_NOTIMPL, "Got hr %#lx.\n", hr);
923 hr = IReferenceClock_AdvisePeriodic(clock, 0, 0, 0, &cookie);
924 ok(hr == E_NOTIMPL, "Got hr %#lx.\n", hr);
926 hr = IReferenceClock_Unadvise(clock, 0);
927 ok(hr == E_NOTIMPL, "Got hr %#lx.\n", hr);
929 IReferenceClock_Release(clock);
931 hr = IDirectMusic_EnumMasterClock(dmusic, 0, NULL);
932 todo_wine ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
934 memset(&clock_info, 0xcc, sizeof(DMUS_CLOCKINFO));
935 clock_info.dwSize = sizeof(DMUS_CLOCKINFO7);
936 hr = IDirectMusic_EnumMasterClock(dmusic, 0, &clock_info);
937 ok(hr == S_OK, "Got hr %#lx.\n", hr);
938 ok(clock_info.ctType == DMUS_CLOCK_SYSTEM, "Got type %#x.\n", clock_info.ctType);
939 ok(IsEqualGUID(&clock_info.guidClock, &guid_system_clock), "Got guid %s.\n",
940 wine_dbgstr_guid(&clock_info.guidClock));
941 ok(clock_info.dwFlags == 0xcccccccc, "Got flags %#lx.\n", clock_info.dwFlags);
943 memset(&clock_info, 0xcc, sizeof(DMUS_CLOCKINFO));
944 clock_info.dwSize = sizeof(DMUS_CLOCKINFO7);
945 hr = IDirectMusic_EnumMasterClock(dmusic, 1, &clock_info);
946 ok(hr == S_OK, "Got hr %#lx.\n", hr);
947 ok(clock_info.ctType == DMUS_CLOCK_SYSTEM, "Got type %#x.\n", clock_info.ctType);
948 ok(IsEqualGUID(&clock_info.guidClock, &guid_dsound_clock), "Got guid %s.\n",
949 wine_dbgstr_guid(&clock_info.guidClock));
950 ok(clock_info.dwFlags == 0xcccccccc, "Got flags %#lx.\n", clock_info.dwFlags);
952 memset(&clock_info, 0xcc, sizeof(DMUS_CLOCKINFO));
953 clock_info.dwSize = sizeof(DMUS_CLOCKINFO7);
954 hr = IDirectMusic_EnumMasterClock(dmusic, 2, &clock_info);
955 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
957 ref = IDirectMusic_Release(dmusic);
958 ok(!ref, "Got outstanding refcount %ld.\n", ref);
961 static void test_synthport(void)
963 IDirectMusic *dmusic;
964 IDirectMusicBuffer *buf;
965 IDirectMusicPort *port;
966 DMUS_BUFFERDESC desc;
967 DMUS_PORTCAPS caps;
968 WAVEFORMATEX fmt;
969 DWORD fmtsize, bufsize;
971 HRESULT hr;
973 port = create_synth_port(&dmusic);
975 /* Create a IDirectMusicPortBuffer */
976 desc.dwSize = sizeof(DMUS_BUFFERDESC);
977 desc.dwFlags = 0;
978 desc.cbBuffer = 1023;
979 memcpy(&desc.guidBufferFormat, &GUID_NULL, sizeof(GUID));
980 hr = IDirectMusic_CreateMusicBuffer(dmusic, &desc, &buf, NULL);
981 ok(hr == S_OK, "IDirectMusic_CreateMusicBuffer failed: %#lx\n", hr);
983 /* Unsupported methods */
984 hr = IDirectMusicPort_Read(port, NULL);
985 todo_wine ok(hr == E_POINTER, "Read returned: %#lx\n", hr);
986 hr = IDirectMusicPort_Read(port, buf);
987 ok(hr == E_NOTIMPL, "Read returned: %#lx\n", hr);
988 hr = IDirectMusicPort_SetReadNotificationHandle(port, NULL);
989 ok(hr == E_NOTIMPL, "SetReadNotificationHandle returned: %#lx\n", hr);
990 hr = IDirectMusicPort_Compact(port);
991 ok(hr == E_NOTIMPL, "Compact returned: %#lx\n", hr);
993 /* GetCaps */
994 hr = IDirectMusicPort_GetCaps(port, NULL);
995 ok(hr == E_INVALIDARG, "GetCaps failed: %#lx\n", hr);
996 memset(&caps, 0, sizeof(caps));
997 hr = IDirectMusicPort_GetCaps(port, &caps);
998 ok(hr == E_INVALIDARG, "GetCaps failed: %#lx\n", hr);
999 caps.dwSize = sizeof(caps);
1000 hr = IDirectMusicPort_GetCaps(port, &caps);
1001 ok(hr == S_OK, "GetCaps failed: %#lx\n", hr);
1002 ok(caps.dwSize == sizeof(caps), "dwSize was modified to %ld\n", caps.dwSize);
1003 ok(IsEqualGUID(&caps.guidPort, &CLSID_DirectMusicSynth), "Expected port guid CLSID_DirectMusicSynth, got %s\n",
1004 wine_dbgstr_guid(&caps.guidPort));
1005 ok(caps.dwClass == DMUS_PC_OUTPUTCLASS, "Got wrong dwClass: %#lx\n", caps.dwClass);
1006 ok(caps.dwType == DMUS_PORT_USER_MODE_SYNTH, "Got wrong dwType: %#lx\n", caps.dwType);
1007 ok(caps.dwFlags == (DMUS_PC_AUDIOPATH|DMUS_PC_DIRECTSOUND|DMUS_PC_DLS|DMUS_PC_DLS2|DMUS_PC_SOFTWARESYNTH|
1008 DMUS_PC_WAVE), "Unexpected dwFlags returned: %#lx\n", caps.dwFlags);
1009 ok(caps.dwMemorySize == DMUS_PC_SYSTEMMEMORY, "Got dwMemorySize: %#lx\n", caps.dwMemorySize);
1010 ok(caps.dwMaxChannelGroups == 1000, "Got dwMaxChannelGroups: %ld\n", caps.dwMaxChannelGroups);
1011 ok(caps.dwMaxVoices == 1000, "Got dwMaxVoices: %ld\n", caps.dwMaxVoices);
1012 ok(caps.dwMaxAudioChannels == 2, "Got dwMaxAudioChannels: %#lx\n", caps.dwMaxAudioChannels);
1013 ok(caps.dwEffectFlags == DMUS_EFFECT_REVERB, "Unexpected dwEffectFlags returned: %#lx\n", caps.dwEffectFlags);
1014 trace("Port wszDescription: %s\n", wine_dbgstr_w(caps.wszDescription));
1016 /* GetFormat */
1017 hr = IDirectMusicPort_GetFormat(port, NULL, NULL, NULL);
1018 ok(hr == E_POINTER, "GetFormat failed: %#lx\n", hr);
1019 hr = IDirectMusicPort_GetFormat(port, NULL, &fmtsize, NULL);
1020 ok(hr == S_OK, "GetFormat failed: %#lx\n", hr);
1021 ok(fmtsize == sizeof(fmt), "format size; %ld\n", fmtsize);
1022 fmtsize = 0;
1023 hr = IDirectMusicPort_GetFormat(port, &fmt, &fmtsize, NULL);
1024 ok(hr == S_OK, "GetFormat failed: %#lx\n", hr);
1025 ok(fmtsize == sizeof(fmt), "format size; %ld\n", fmtsize);
1026 hr = IDirectMusicPort_GetFormat(port, NULL, NULL, &bufsize);
1027 ok(hr == E_POINTER, "GetFormat failed: %#lx\n", hr);
1028 hr = IDirectMusicPort_GetFormat(port, NULL, &fmtsize, &bufsize);
1029 ok(hr == S_OK, "GetFormat failed: %#lx\n", hr);
1030 hr = IDirectMusicPort_GetFormat(port, &fmt, &fmtsize, &bufsize);
1031 ok(hr == S_OK, "GetFormat failed: %#lx\n", hr);
1032 ok(bufsize == fmt.nSamplesPerSec * fmt.nChannels * 4, "buffer size: %ld\n", bufsize);
1034 IDirectMusicPort_Release(port);
1035 IDirectMusic_Release(dmusic);
1038 static void test_port_download(void)
1040 struct wave_download
1042 DMUS_DOWNLOADINFO info;
1043 ULONG offsets[2];
1044 DMUS_WAVE wave;
1045 DMUS_WAVEDATA wave_data;
1048 static void *invalid_ptr = (void *)0xdeadbeef;
1049 IDirectMusicDownload *download, *tmp_download;
1050 struct wave_download *wave_download;
1051 IDirectMusicPortDownload *port;
1052 IDirectMusicPort *tmp_port;
1053 DWORD ids[4], append, size;
1054 IDirectMusic *dmusic;
1055 void *buffer;
1056 HRESULT hr;
1058 tmp_port = create_synth_port(&dmusic);
1059 hr = IDirectMusicPort_QueryInterface(tmp_port, &IID_IDirectMusicPortDownload, (void **)&port);
1060 ok(hr == S_OK, "got %#lx\n", hr);
1061 IDirectMusicPort_Release(tmp_port);
1063 /* GetBuffer only works with pre-allocated DLId */
1064 hr = IDirectMusicPortDownload_GetBuffer(port, 0, NULL);
1065 ok(hr == E_POINTER, "got %#lx\n", hr);
1066 hr = IDirectMusicPortDownload_GetBuffer(port, 0, &download);
1067 ok(hr == DMUS_E_INVALID_DOWNLOADID, "got %#lx\n", hr);
1068 hr = IDirectMusicPortDownload_GetBuffer(port, 0xdeadbeef, &download);
1069 ok(hr == DMUS_E_INVALID_DOWNLOADID, "got %#lx\n", hr);
1071 /* AllocateBuffer use the exact requested size */
1072 hr = IDirectMusicPortDownload_AllocateBuffer(port, 0, NULL);
1073 ok(hr == E_POINTER, "got %#lx\n", hr);
1074 hr = IDirectMusicPortDownload_AllocateBuffer(port, 0, &download);
1075 ok(hr == E_INVALIDARG, "got %#lx\n", hr);
1077 hr = IDirectMusicPortDownload_AllocateBuffer(port, 1, &download);
1078 ok(hr == S_OK, "got %#lx\n", hr);
1079 size = 0xdeadbeef;
1080 buffer = invalid_ptr;
1081 hr = IDirectMusicDownload_GetBuffer(download, &buffer, &size);
1082 ok(hr == S_OK, "got %#lx\n", hr);
1083 ok(size == 1, "got %#lx\n", size);
1084 ok(buffer != invalid_ptr, "got %p\n", buffer);
1085 IDirectMusicDownload_Release(download);
1087 /* GetDLId allocates the given number of slots and returns only the first */
1088 hr = IDirectMusicPortDownload_GetDLId(port, NULL, 0);
1089 ok(hr == E_POINTER, "got %#lx\n", hr);
1090 hr = IDirectMusicPortDownload_GetDLId(port, ids, 0);
1091 ok(hr == E_INVALIDARG, "got %#lx\n", hr);
1093 memset(ids, 0xcc, sizeof(ids));
1094 hr = IDirectMusicPortDownload_GetDLId(port, ids, 4);
1095 ok(hr == S_OK, "got %#lx\n", hr);
1096 ok(ids[0] == 0, "got %#lx\n", ids[0]);
1097 ok(ids[1] == 0xcccccccc, "got %#lx\n", ids[1]);
1099 /* GetBuffer looks up allocated ids to find downloaded buffers */
1100 hr = IDirectMusicPortDownload_GetBuffer(port, 2, &download);
1101 ok(hr == DMUS_E_NOT_DOWNLOADED_TO_PORT, "got %#lx\n", hr);
1103 hr = IDirectMusicPortDownload_GetAppend(port, NULL);
1104 todo_wine ok(hr == E_POINTER, "got %#lx\n", hr);
1105 append = 0xdeadbeef;
1106 hr = IDirectMusicPortDownload_GetAppend(port, &append);
1107 ok(hr == S_OK, "got %#lx\n", hr);
1108 todo_wine ok(append == 2, "got %#lx\n", append);
1110 /* test Download / Unload on invalid and valid buffers */
1112 download = invalid_ptr;
1113 hr = IDirectMusicPortDownload_AllocateBuffer(port, sizeof(struct wave_download), &download);
1114 ok(hr == S_OK, "got %#lx\n", hr);
1115 ok(download != invalid_ptr, "got %p\n", download);
1116 size = 0xdeadbeef;
1117 wave_download = invalid_ptr;
1118 hr = IDirectMusicDownload_GetBuffer(download, (void **)&wave_download, &size);
1119 ok(hr == S_OK, "got %#lx\n", hr);
1120 ok(size == sizeof(struct wave_download), "got %#lx\n", size);
1121 ok(wave_download != invalid_ptr, "got %p\n", wave_download);
1122 wave_download->info.cbSize = sizeof(struct wave_download);
1123 wave_download->info.dwDLId = 2;
1124 wave_download->info.dwDLType = 0;
1125 wave_download->info.dwNumOffsetTableEntries = 0;
1126 hr = IDirectMusicPortDownload_GetBuffer(port, 2, &tmp_download);
1127 ok(hr == DMUS_E_NOT_DOWNLOADED_TO_PORT, "got %#lx\n", hr);
1129 hr = IDirectMusicPortDownload_Download(port, NULL);
1130 ok(hr == E_POINTER, "got %#lx\n", hr);
1131 hr = IDirectMusicPortDownload_Download(port, download);
1132 todo_wine ok(hr == DMUS_E_UNKNOWNDOWNLOAD, "got %#lx\n", hr);
1134 wave_download->info.dwDLType = DMUS_DOWNLOADINFO_WAVE;
1135 wave_download->info.dwNumOffsetTableEntries = 2;
1136 wave_download->offsets[0] = offsetof(struct wave_download, wave);
1137 wave_download->offsets[1] = offsetof(struct wave_download, wave_data);
1138 wave_download->wave.WaveformatEx.wFormatTag = WAVE_FORMAT_PCM;
1139 wave_download->wave.WaveformatEx.nChannels = 1;
1140 wave_download->wave.WaveformatEx.nSamplesPerSec = 44100;
1141 wave_download->wave.WaveformatEx.nAvgBytesPerSec = 44100;
1142 wave_download->wave.WaveformatEx.nBlockAlign = 1;
1143 wave_download->wave.WaveformatEx.wBitsPerSample = 8;
1144 wave_download->wave.WaveformatEx.cbSize = 0;
1145 wave_download->wave.ulWaveDataIdx = 1;
1146 wave_download->wave.ulCopyrightIdx = 0;
1147 wave_download->wave.ulFirstExtCkIdx = 0;
1148 wave_download->wave_data.cbSize = 1;
1150 hr = IDirectMusicPortDownload_Download(port, download);
1151 ok(hr == S_OK, "got %#lx\n", hr);
1152 hr = IDirectMusicPortDownload_Download(port, download);
1153 ok(hr == DMUS_E_ALREADY_DOWNLOADED, "got %#lx\n", hr);
1155 tmp_download = invalid_ptr;
1156 hr = IDirectMusicPortDownload_GetBuffer(port, 2, &tmp_download);
1157 ok(hr == S_OK, "got %#lx\n", hr);
1158 ok(tmp_download == download, "got %p\n", tmp_download);
1159 IDirectMusicDownload_Release(tmp_download);
1161 hr = IDirectMusicPortDownload_Unload(port, NULL);
1162 ok(hr == E_POINTER, "got %#lx\n", hr);
1163 hr = IDirectMusicPortDownload_Unload(port, download);
1164 ok(hr == S_OK, "got %#lx\n", hr);
1166 hr = IDirectMusicPortDownload_GetBuffer(port, 2, &tmp_download);
1167 ok(hr == DMUS_E_NOT_DOWNLOADED_TO_PORT, "got %#lx\n", hr);
1169 hr = IDirectMusicPortDownload_Unload(port, download);
1170 ok(hr == S_OK, "got %#lx\n", hr);
1172 /* DLIds are never released */
1173 hr = IDirectMusicPortDownload_GetDLId(port, ids, 1);
1174 ok(hr == S_OK, "got %#lx\n", hr);
1175 ok(ids[0] == 4, "got %#lx\n", ids[0]);
1177 IDirectMusicDownload_Release(download);
1179 IDirectMusicPortDownload_Release(port);
1182 static void test_download_instrument(void)
1184 static const LARGE_INTEGER zero = {0};
1185 IDirectMusicDownloadedInstrument *downloaded;
1186 IDirectMusicCollection *collection;
1187 IDirectMusicInstrument *instrument, *tmp_instrument;
1188 IPersistStream *persist;
1189 IDirectMusicPort *port;
1190 IDirectMusic *dmusic;
1191 WCHAR name[MAX_PATH];
1192 IStream *stream;
1193 DWORD patch;
1194 HRESULT hr;
1196 port = create_synth_port(&dmusic);
1198 hr = CoCreateInstance(&CLSID_DirectMusicCollection, NULL, CLSCTX_INPROC_SERVER,
1199 &IID_IDirectMusicCollection, (void **)&collection);
1200 ok(hr == S_OK, "got %#lx\n", hr);
1202 hr = IDirectMusicCollection_QueryInterface(collection, &IID_IPersistStream, (void **)&persist);
1203 ok(hr == S_OK, "got %#lx\n", hr);
1204 hr = CreateStreamOnHGlobal(0, TRUE, &stream);
1205 ok(hr == S_OK, "got %#lx\n", hr);
1207 CHUNK_RIFF(stream, "DLS ")
1209 DLSHEADER colh = {.cInstruments = 1};
1210 struct
1212 POOLTABLE head;
1213 POOLCUE cues[1];
1214 } ptbl =
1216 .head = {.cbSize = sizeof(POOLTABLE), .cCues = ARRAY_SIZE(ptbl.cues)},
1217 .cues = {{.ulOffset = 0}}, /* offsets in wvpl */
1220 CHUNK_DATA(stream, "colh", colh);
1221 CHUNK_LIST(stream, "lins")
1223 CHUNK_LIST(stream, "ins ")
1225 INSTHEADER insh = {.cRegions = 1, .Locale = {.ulBank = 0x12, .ulInstrument = 0x34}};
1227 CHUNK_DATA(stream, "insh", insh);
1228 CHUNK_LIST(stream, "lrgn")
1230 CHUNK_LIST(stream, "rgn ")
1232 RGNHEADER rgnh =
1234 .RangeKey = {.usLow = 0, .usHigh = 127},
1235 .RangeVelocity = {.usLow = 1, .usHigh = 127},
1237 WAVELINK wlnk = {.ulChannel = 1, .ulTableIndex = 0};
1238 WSMPL wsmp = {.cbSize = sizeof(WSMPL)};
1240 CHUNK_DATA(stream, "rgnh", rgnh);
1241 CHUNK_DATA(stream, "wsmp", wsmp);
1242 CHUNK_DATA(stream, "wlnk", wlnk);
1244 CHUNK_END;
1246 CHUNK_END;
1248 CHUNK_LIST(stream, "lart")
1250 CONNECTIONLIST connections = {.cbSize = sizeof(connections)};
1251 CHUNK_DATA(stream, "art1", connections);
1253 CHUNK_END;
1255 CHUNK_END;
1257 CHUNK_END;
1258 CHUNK_DATA(stream, "ptbl", ptbl);
1259 CHUNK_LIST(stream, "wvpl")
1261 CHUNK_LIST(stream, "wave")
1263 WAVEFORMATEX fmt =
1265 .wFormatTag = WAVE_FORMAT_PCM,
1266 .nChannels = 1,
1267 .wBitsPerSample = 8,
1268 .nSamplesPerSec = 22050,
1269 .nAvgBytesPerSec = 22050,
1270 .nBlockAlign = 1,
1272 BYTE data[16] = {0};
1274 /* native returns DMUS_E_INVALIDOFFSET from DownloadInstrument if data is last */
1275 CHUNK_DATA(stream, "data", data);
1276 CHUNK_DATA(stream, "fmt ", fmt);
1278 CHUNK_END;
1280 CHUNK_END;
1282 CHUNK_END;
1284 hr = IStream_Seek(stream, zero, 0, NULL);
1285 ok(hr == S_OK, "got %#lx\n", hr);
1286 hr = IPersistStream_Load(persist, stream);
1287 ok(hr == S_OK, "got %#lx\n", hr);
1288 IPersistStream_Release(persist);
1289 IStream_Release(stream);
1291 patch = 0xdeadbeef;
1292 wcscpy(name, L"DeadBeef");
1293 hr = IDirectMusicCollection_EnumInstrument(collection, 0, &patch, name, ARRAY_SIZE(name));
1294 ok(hr == S_OK, "got %#lx\n", hr);
1295 ok(patch == 0x1234, "got %#lx\n", patch);
1296 ok(*name == 0, "got %s\n", debugstr_w(name));
1297 hr = IDirectMusicCollection_EnumInstrument(collection, 1, &patch, name, ARRAY_SIZE(name));
1298 ok(hr == S_FALSE, "got %#lx\n", hr);
1300 hr = IDirectMusicCollection_GetInstrument(collection, 0x1234, &instrument);
1301 ok(hr == S_OK, "got %#lx\n", hr);
1302 hr = IDirectMusicInstrument_GetPatch(instrument, &patch);
1303 ok(hr == S_OK, "got %#lx\n", hr);
1304 ok(patch == 0x1234, "got %#lx\n", patch);
1305 hr = IDirectMusicInstrument_SetPatch(instrument, 0x4321);
1306 ok(hr == S_OK, "got %#lx\n", hr);
1307 hr = IDirectMusicInstrument_GetPatch(instrument, &patch);
1308 ok(hr == S_OK, "got %#lx\n", hr);
1309 ok(patch == 0x4321, "got %#lx\n", patch);
1311 hr = IDirectMusicCollection_GetInstrument(collection, 0x1234, &tmp_instrument);
1312 ok(hr == S_OK, "got %#lx\n", hr);
1313 ok(instrument == tmp_instrument, "got %p\n", tmp_instrument);
1314 hr = IDirectMusicInstrument_GetPatch(tmp_instrument, &patch);
1315 ok(hr == S_OK, "got %#lx\n", hr);
1316 ok(patch == 0x4321, "got %#lx\n", patch);
1317 IDirectMusicInstrument_Release(tmp_instrument);
1319 check_interface(instrument, &IID_IDirectMusicObject, FALSE);
1320 check_interface(instrument, &IID_IDirectMusicDownload, FALSE);
1321 check_interface(instrument, &IID_IDirectMusicDownloadedInstrument, FALSE);
1323 hr = IDirectMusicPort_DownloadInstrument(port, instrument, &downloaded, NULL, 0);
1324 ok(hr == S_OK, "got %#lx\n", hr);
1326 check_interface(downloaded, &IID_IDirectMusicObject, FALSE);
1327 check_interface(downloaded, &IID_IDirectMusicDownload, FALSE);
1328 check_interface(downloaded, &IID_IDirectMusicInstrument, FALSE);
1330 hr = IDirectMusicPort_UnloadInstrument(port, downloaded);
1331 ok(hr == S_OK, "got %#lx\n", hr);
1332 IDirectMusicDownloadedInstrument_Release(downloaded);
1334 IDirectMusicInstrument_Release(instrument);
1336 IDirectMusicCollection_Release(collection);
1337 IDirectMusicPort_Release(port);
1338 IDirectMusic_Release(dmusic);
1341 struct result
1343 DWORD patch;
1344 WCHAR name[DMUS_MAX_NAME];
1347 static int __cdecl result_cmp(const void *a, const void *b)
1349 const struct result *ra = a, *rb = b;
1350 if (ra->patch != rb->patch) return ra->patch < rb->patch ? -1 : 1;
1351 return wcscmp(ra->name, rb->name);
1354 static void test_default_gm_collection(void)
1356 DMUS_OBJECTDESC desc =
1358 .dwSize = sizeof(DMUS_OBJECTDESC),
1359 .dwValidData = DMUS_OBJ_OBJECT | DMUS_OBJ_CLASS,
1360 .guidClass = CLSID_DirectMusicCollection,
1361 .guidObject = GUID_DefaultGMCollection,
1363 struct result expected[] =
1365 { 0, L"Piano 1 "},
1366 { 0x1, L"Piano 2 "},
1367 { 0x2, L"Piano 3 "},
1368 { 0x3, L"Honky-tonk "},
1369 { 0x4, L"E.Piano 1 "},
1370 { 0x5, L"E.Piano 2 "},
1371 { 0x6, L"Harpsichord "},
1372 { 0x7, L"Clav. "},
1373 { 0x8, L"Celesta "},
1374 { 0x9, L"Glockenspiel"},
1375 { 0xa, L"Music Box "},
1376 { 0xb, L"Vibraphone "},
1377 { 0xc, L"Marimba "},
1378 { 0xd, L"Xylophone "},
1379 { 0xe, L"Tubular-bell"},
1380 { 0xf, L"Santur "},
1381 { 0x10, L"Organ 1 "},
1382 { 0x11, L"Organ 2 "},
1383 { 0x12, L"Organ 3 "},
1384 { 0x13, L"Church Org.1"},
1385 { 0x14, L"Reed Organ "},
1386 { 0x15, L"Accordion Fr"},
1387 { 0x16, L"Harmonica "},
1388 { 0x17, L"Bandoneon "},
1389 { 0x18, L"Nylon-str.Gt"},
1390 { 0x19, L"Steel-str.Gt"},
1391 { 0x1a, L"Jazz Gt. "},
1392 { 0x1b, L"Clean Gt. "},
1393 { 0x1c, L"Muted Gt. "},
1394 { 0x1d, L"Overdrive Gt"},
1395 { 0x1e, L"DistortionGt"},
1396 { 0x1f, L"Gt.Harmonics"},
1397 { 0x20, L"Acoustic Bs."},
1398 { 0x21, L"Fingered Bs."},
1399 { 0x22, L"Picked Bs. "},
1400 { 0x23, L"Fretless Bs."},
1401 { 0x24, L"Slap Bass 1 "},
1402 { 0x25, L"Slap Bass 2 "},
1403 { 0x26, L"Synth Bass 1"},
1404 { 0x27, L"Synth Bass 2"},
1405 { 0x28, L"Violin "},
1406 { 0x29, L"Viola "},
1407 { 0x2a, L"Cello "},
1408 { 0x2b, L"Contrabass "},
1409 { 0x2c, L"Tremolo Str "},
1410 { 0x2d, L"PizzicatoStr"},
1411 { 0x2e, L"Harp "},
1412 { 0x2f, L"Timpani "},
1413 { 0x30, L"Strings "},
1414 { 0x31, L"Slow Strings"},
1415 { 0x32, L"Syn.Strings1"},
1416 { 0x33, L"Syn.Strings2"},
1417 { 0x34, L"Choir Aahs "},
1418 { 0x35, L"Voice Oohs "},
1419 { 0x36, L"SynVox "},
1420 { 0x37, L"OrchestraHit"},
1421 { 0x38, L"Trumpet "},
1422 { 0x39, L"Trombone "},
1423 { 0x3a, L"Tuba "},
1424 { 0x3b, L"MutedTrumpet"},
1425 { 0x3c, L"French Horns"},
1426 { 0x3d, L"Brass 1 "},
1427 { 0x3e, L"Synth Brass1"},
1428 { 0x3f, L"Synth Brass2"},
1429 { 0x40, L"Soprano Sax "},
1430 { 0x41, L"Alto Sax "},
1431 { 0x42, L"Tenor Sax "},
1432 { 0x43, L"Baritone Sax"},
1433 { 0x44, L"Oboe "},
1434 { 0x45, L"English Horn"},
1435 { 0x46, L"Bassoon "},
1436 { 0x47, L"Clarinet "},
1437 { 0x48, L"Piccolo "},
1438 { 0x49, L"Flute "},
1439 { 0x4a, L"Recorder "},
1440 { 0x4b, L"Pan Flute "},
1441 { 0x4c, L"Bottle Blow "},
1442 { 0x4d, L"Shakuhachi "},
1443 { 0x4e, L"Whistle "},
1444 { 0x4f, L"Ocarina "},
1445 { 0x50, L"Square Wave "},
1446 { 0x51, L"Saw Wave "},
1447 { 0x52, L"Syn.Calliope"},
1448 { 0x53, L"Chiffer Lead"},
1449 { 0x54, L"Charang "},
1450 { 0x55, L"Solo Vox "},
1451 { 0x56, L"5th Saw Wave"},
1452 { 0x57, L"Bass & Lead "},
1453 { 0x58, L"Fantasia "},
1454 { 0x59, L"Warm Pad "},
1455 { 0x5a, L"Polysynth "},
1456 { 0x5b, L"Space Voice "},
1457 { 0x5c, L"Bowed Glass "},
1458 { 0x5d, L"Metal Pad "},
1459 { 0x5e, L"Halo Pad "},
1460 { 0x5f, L"Sweep Pad "},
1461 { 0x60, L"Ice Rain "},
1462 { 0x61, L"Soundtrack "},
1463 { 0x62, L"Crystal "},
1464 { 0x63, L"Atmosphere "},
1465 { 0x64, L"Brightness "},
1466 { 0x65, L"Goblin "},
1467 { 0x66, L"Echo Drops "},
1468 { 0x67, L"Star Theme "},
1469 { 0x68, L"Sitar "},
1470 { 0x69, L"Banjo "},
1471 { 0x6a, L"Shamisen "},
1472 { 0x6b, L"Koto "},
1473 { 0x6c, L"Kalimba "},
1474 { 0x6d, L"Bagpipe "},
1475 { 0x6e, L"Fiddle "},
1476 { 0x6f, L"Shanai "},
1477 { 0x70, L"Tinkle Bell "},
1478 { 0x71, L"Agogo "},
1479 { 0x72, L"Steel Drums "},
1480 { 0x73, L"Woodblock "},
1481 { 0x74, L"Taiko "},
1482 { 0x75, L"Melo. Tom 1 "},
1483 { 0x76, L"Synth Drum "},
1484 { 0x77, L"Reverse Cym."},
1485 { 0x78, L"Gt.FretNoise"},
1486 { 0x79, L"Breath Noise"},
1487 { 0x7a, L"Seashore "},
1488 { 0x7b, L"Bird "},
1489 { 0x7c, L"Telephone 1 "},
1490 { 0x7d, L"Helicopter "},
1491 { 0x7e, L"Applause "},
1492 { 0x7f, L"Gun Shot "},
1493 { 0x10026, L"SynthBass101"},
1494 { 0x10039, L"Trombone 2 "},
1495 { 0x1003c, L"Fr.Horn 2 "},
1496 { 0x10050, L"Square "},
1497 { 0x10051, L"Saw "},
1498 { 0x10062, L"Syn Mallet "},
1499 { 0x10066, L"Echo Bell "},
1500 { 0x10068, L"Sitar 2 "},
1501 { 0x10078, L"Gt.Cut Noise"},
1502 { 0x10079, L"Fl.Key Click"},
1503 { 0x1007a, L"Rain "},
1504 { 0x1007b, L"Dog "},
1505 { 0x1007c, L"Telephone 2 "},
1506 { 0x1007d, L"Car-Engine "},
1507 { 0x1007e, L"Laughing "},
1508 { 0x1007f, L"Machine Gun "},
1509 { 0x20066, L"Echo Pan "},
1510 { 0x20078, L"String Slap "},
1511 { 0x2007a, L"Thunder "},
1512 { 0x2007b, L"Horse-Gallop"},
1513 { 0x2007c, L"DoorCreaking"},
1514 { 0x2007d, L"Car-Stop "},
1515 { 0x2007e, L"Screaming "},
1516 { 0x2007f, L"Lasergun "},
1517 { 0x3007a, L"Wind "},
1518 { 0x3007b, L"Bird 2 "},
1519 { 0x3007c, L"Door "},
1520 { 0x3007d, L"Car-Pass "},
1521 { 0x3007e, L"Punch "},
1522 { 0x3007f, L"Explosion "},
1523 { 0x4007a, L"Stream "},
1524 { 0x4007c, L"Scratch "},
1525 { 0x4007d, L"Car-Crash "},
1526 { 0x4007e, L"Heart Beat "},
1527 { 0x5007a, L"Bubble "},
1528 { 0x5007c, L"Wind Chimes "},
1529 { 0x5007d, L"Siren "},
1530 { 0x5007e, L"Footsteps "},
1531 { 0x6007d, L"Train "},
1532 { 0x7007d, L"Jetplane "},
1533 { 0x80000, L"Piano 1 "},
1534 { 0x80001, L"Piano 2 "},
1535 { 0x80002, L"Piano 3 "},
1536 { 0x80003, L"Honky-tonk "},
1537 { 0x80004, L"Detuned EP 1"},
1538 { 0x80005, L"Detuned EP 2"},
1539 { 0x80006, L"Coupled Hps."},
1540 { 0x8000b, L"Vibraphone "},
1541 { 0x8000c, L"Marimba "},
1542 { 0x8000e, L"Church Bell "},
1543 { 0x80010, L"Detuned Or.1"},
1544 { 0x80011, L"Detuned Or.2"},
1545 { 0x80013, L"Church Org.2"},
1546 { 0x80015, L"Accordion It"},
1547 { 0x80018, L"Ukulele "},
1548 { 0x80019, L"12-str.Gt "},
1549 { 0x8001a, L"Hawaiian Gt."},
1550 { 0x8001b, L"Chorus Gt. "},
1551 { 0x8001c, L"Funk Gt. "},
1552 { 0x8001e, L"Feedback Gt."},
1553 { 0x8001f, L"Gt. Feedback"},
1554 { 0x80026, L"Synth Bass 3"},
1555 { 0x80027, L"Synth Bass 4"},
1556 { 0x80028, L"Slow Violin "},
1557 { 0x80030, L"Orchestra "},
1558 { 0x80032, L"Syn.Strings3"},
1559 { 0x8003d, L"Brass 2 "},
1560 { 0x8003e, L"Synth Brass3"},
1561 { 0x8003f, L"Synth Brass4"},
1562 { 0x80050, L"Sine Wave "},
1563 { 0x80051, L"Doctor Solo "},
1564 { 0x8006b, L"Taisho Koto "},
1565 { 0x80073, L"Castanets "},
1566 { 0x80074, L"Concert BD "},
1567 { 0x80075, L"Melo. Tom 2 "},
1568 { 0x80076, L"808 Tom "},
1569 { 0x8007d, L"Starship "},
1570 { 0x9000e, L"Carillon "},
1571 { 0x90076, L"Elec Perc. "},
1572 { 0x9007d, L"Burst Noise "},
1573 { 0x100000, L"Piano 1d "},
1574 { 0x100004, L"E.Piano 1v "},
1575 { 0x100005, L"E.Piano 2v "},
1576 { 0x100006, L"Harpsichord "},
1577 { 0x100010, L"60's Organ 1"},
1578 { 0x100013, L"Church Org.3"},
1579 { 0x100018, L"Nylon Gt.o "},
1580 { 0x100019, L"Mandolin "},
1581 { 0x10001c, L"Funk Gt.2 "},
1582 { 0x100027, L"Rubber Bass "},
1583 { 0x10003e, L"AnalogBrass1"},
1584 { 0x10003f, L"AnalogBrass2"},
1585 { 0x180004, L"60's E.Piano"},
1586 { 0x180006, L"Harpsi.o "},
1587 { 0x200010, L"Organ 4 "},
1588 { 0x200011, L"Organ 5 "},
1589 { 0x200018, L"Nylon Gt.2 "},
1590 { 0x200034, L"Choir Aahs 2"},
1591 {0x80000000, L"Standard "},
1592 {0x80000008, L"Room "},
1593 {0x80000010, L"Power "},
1594 {0x80000018, L"Electronic "},
1595 {0x80000019, L"TR-808 "},
1596 {0x80000020, L"Jazz "},
1597 {0x80000028, L"Brush "},
1598 {0x80000030, L"Orchestra "},
1599 {0x80000038, L"SFX "},
1600 }, results[ARRAY_SIZE(expected) + 1];
1601 IDirectMusicCollection *collection;
1602 IDirectMusicLoader *loader;
1603 HRESULT hr;
1604 DWORD i;
1606 hr = CoCreateInstance(&CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC_SERVER,
1607 &IID_IDirectMusicLoader, (void**)&loader);
1608 ok(hr == S_OK, "got %#lx\n", hr);
1610 hr = IDirectMusicLoader_GetObject(loader, &desc, &IID_IDirectMusicCollection, (void **)&collection);
1611 if (hr == DMUS_E_LOADER_NOFILENAME)
1613 skip("Failed to open default GM collection, skipping tests. Missing system SoundFont?\n");
1614 goto skip_tests;
1616 ok(hr == S_OK, "got %#lx\n", hr);
1618 for (i = 0; hr == S_OK && i < ARRAY_SIZE(results); i++)
1620 results[i].patch = 0xdeadbeef;
1621 wcscpy(results[i].name, L"DeadBeef");
1622 hr = IDirectMusicCollection_EnumInstrument(collection, i, &results[i].patch,
1623 results[i].name, ARRAY_SIZE(results[i].name));
1625 if (hr == S_FALSE) i--;
1626 ok(hr == S_FALSE, "got %#lx\n", hr);
1627 ok(i > 0, "got %lu\n", i);
1628 todo_wine ok(i == ARRAY_SIZE(expected), "got %lu\n", i);
1630 qsort(results, i, sizeof(*results), result_cmp);
1632 while (i--)
1634 winetest_push_context("%lu", i);
1635 trace("got %#lx %s\n", results[i].patch, debugstr_w(results[i].name));
1636 todo_wine_if(expected[i].patch >= 128)
1637 ok(results[i].patch == expected[i].patch, "got %#lx\n", results[i].patch);
1638 /* system soundfont names are not very predictable, let's not check them */
1639 winetest_pop_context();
1642 IDirectMusicCollection_Release(collection);
1644 skip_tests:
1645 IDirectMusicLoader_Release(loader);
1648 START_TEST(dmusic)
1650 CoInitializeEx(NULL, COINIT_MULTITHREADED);
1652 if (missing_dmusic())
1654 skip("DirectMusic not available\n");
1655 CoUninitialize();
1656 return;
1658 test_COM();
1659 test_COM_dmcoll();
1660 test_COM_synthport();
1661 test_dmusic();
1662 test_setdsound();
1663 test_dmbuffer();
1664 test_dmcoll();
1665 test_parsedescriptor();
1666 test_master_clock();
1667 test_synthport();
1668 test_port_download();
1669 test_download_instrument();
1670 test_default_gm_collection();
1672 CoUninitialize();