xref: /reactos/dll/directx/wine/dmusic/dmusic.c (revision c1cf2ac3)
1 /*
2  * IDirectMusic8 Implementation
3  *
4  * Copyright (C) 2003-2004 Rok Mandeljc
5  * Copyright (C) 2012 Christian Costa
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include <stdio.h>
23 
24 #include "dmusic_private.h"
25 #include "wine/heap.h"
26 
27 WINE_DEFAULT_DEBUG_CHANNEL(dmusic);
28 
29 struct master_clock {
30     IReferenceClock IReferenceClock_iface;
31     LONG ref;
32     double freq;
33     REFERENCE_TIME last_time;
34 };
35 
impl_from_IReferenceClock(IReferenceClock * iface)36 static inline struct master_clock *impl_from_IReferenceClock(IReferenceClock *iface)
37 {
38     return CONTAINING_RECORD(iface, struct master_clock, IReferenceClock_iface);
39 }
40 
master_IReferenceClock_QueryInterface(IReferenceClock * iface,REFIID riid,void ** ret_iface)41 static HRESULT WINAPI master_IReferenceClock_QueryInterface(IReferenceClock *iface, REFIID riid,
42         void **ret_iface)
43 {
44     TRACE("(%p, %s, %p)\n", iface, debugstr_dmguid(riid), ret_iface);
45 
46     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IReferenceClock))
47         *ret_iface = iface;
48     else {
49         WARN("no interface for %s\n", debugstr_dmguid(riid));
50         *ret_iface = NULL;
51         return E_NOINTERFACE;
52     }
53 
54     IReferenceClock_AddRef(iface);
55 
56     return S_OK;
57 }
58 
master_IReferenceClock_AddRef(IReferenceClock * iface)59 static ULONG WINAPI master_IReferenceClock_AddRef(IReferenceClock *iface)
60 {
61     struct master_clock *This = impl_from_IReferenceClock(iface);
62     ULONG ref = InterlockedIncrement(&This->ref);
63 
64     TRACE("(%p) ref = %u\n", iface, ref);
65 
66     return ref;
67 }
68 
master_IReferenceClock_Release(IReferenceClock * iface)69 static ULONG WINAPI master_IReferenceClock_Release(IReferenceClock *iface)
70 {
71     struct master_clock *This = impl_from_IReferenceClock(iface);
72     ULONG ref = InterlockedDecrement(&This->ref);
73 
74     TRACE("(%p) ref = %u\n", iface, ref);
75 
76     if (!ref)
77         heap_free(This);
78 
79     return ref;
80 }
81 
master_IReferenceClock_GetTime(IReferenceClock * iface,REFERENCE_TIME * time)82 static HRESULT WINAPI master_IReferenceClock_GetTime(IReferenceClock *iface,
83         REFERENCE_TIME *time)
84 {
85     struct master_clock *This = impl_from_IReferenceClock(iface);
86     LARGE_INTEGER counter;
87     HRESULT hr;
88 
89     TRACE("(%p, %p)\n", iface, time);
90 
91     QueryPerformanceCounter(&counter);
92     *time = counter.QuadPart * This->freq;
93     hr = (*time == This->last_time) ? S_FALSE : S_OK;
94     This->last_time = *time;
95 
96     return hr;
97 }
98 
master_IReferenceClock_AdviseTime(IReferenceClock * iface,REFERENCE_TIME base,REFERENCE_TIME offset,HANDLE event,DWORD * cookie)99 static HRESULT WINAPI master_IReferenceClock_AdviseTime(IReferenceClock *iface,
100         REFERENCE_TIME base, REFERENCE_TIME offset, HANDLE event, DWORD *cookie)
101 {
102     TRACE("(%p, %s, %s, %p, %p): method not implemented\n", iface, wine_dbgstr_longlong(base),
103             wine_dbgstr_longlong(offset), event, cookie);
104     return E_NOTIMPL;
105 }
106 
master_IReferenceClock_AdvisePeriodic(IReferenceClock * iface,REFERENCE_TIME start,REFERENCE_TIME period,HANDLE semaphore,DWORD * cookie)107 static HRESULT WINAPI master_IReferenceClock_AdvisePeriodic(IReferenceClock *iface,
108         REFERENCE_TIME start, REFERENCE_TIME period, HANDLE semaphore, DWORD *cookie)
109 {
110     TRACE("(%p, %s, %s, %p, %p): method not implemented\n", iface, wine_dbgstr_longlong(start),
111             wine_dbgstr_longlong(period), semaphore, cookie);
112     return E_NOTIMPL;
113 }
114 
master_IReferenceClock_Unadvise(IReferenceClock * iface,DWORD cookie)115 static HRESULT WINAPI master_IReferenceClock_Unadvise(IReferenceClock *iface, DWORD cookie)
116 {
117     TRACE("(%p, %#x): method not implemented\n", iface, cookie);
118     return E_NOTIMPL;
119 }
120 
121 static const IReferenceClockVtbl master_clock_vtbl = {
122     master_IReferenceClock_QueryInterface,
123     master_IReferenceClock_AddRef,
124     master_IReferenceClock_Release,
125     master_IReferenceClock_GetTime,
126     master_IReferenceClock_AdviseTime,
127     master_IReferenceClock_AdvisePeriodic,
128     master_IReferenceClock_Unadvise,
129 };
130 
master_clock_create(IReferenceClock ** clock)131 static HRESULT master_clock_create(IReferenceClock **clock)
132 {
133     struct master_clock *obj;
134     LARGE_INTEGER freq;
135 
136     TRACE("(%p)\n", clock);
137 
138     if (!(obj = heap_alloc_zero(sizeof(*obj))))
139         return E_OUTOFMEMORY;
140 
141     obj->IReferenceClock_iface.lpVtbl = &master_clock_vtbl;
142     obj->ref = 1;
143     QueryPerformanceFrequency(&freq);
144     obj->freq = 10000000.0 / freq.QuadPart;
145 
146     *clock = &obj->IReferenceClock_iface;
147 
148     return S_OK;
149 }
150 
impl_from_IDirectMusic8(IDirectMusic8 * iface)151 static inline IDirectMusic8Impl *impl_from_IDirectMusic8(IDirectMusic8 *iface)
152 {
153     return CONTAINING_RECORD(iface, IDirectMusic8Impl, IDirectMusic8_iface);
154 }
155 
156 /* IDirectMusic8Impl IUnknown part: */
IDirectMusic8Impl_QueryInterface(LPDIRECTMUSIC8 iface,REFIID riid,LPVOID * ret_iface)157 static HRESULT WINAPI IDirectMusic8Impl_QueryInterface(LPDIRECTMUSIC8 iface, REFIID riid, LPVOID *ret_iface)
158 {
159     IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
160 
161     TRACE("(%p)->(%s, %p)\n", iface, debugstr_dmguid(riid), ret_iface);
162 
163     if (IsEqualIID (riid, &IID_IUnknown) ||
164         IsEqualIID (riid, &IID_IDirectMusic) ||
165         IsEqualIID (riid, &IID_IDirectMusic2) ||
166         IsEqualIID (riid, &IID_IDirectMusic8))
167     {
168         IDirectMusic8_AddRef(iface);
169         *ret_iface = iface;
170         return S_OK;
171     }
172 
173     *ret_iface = NULL;
174 
175     WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ret_iface);
176 
177     return E_NOINTERFACE;
178 }
179 
IDirectMusic8Impl_AddRef(LPDIRECTMUSIC8 iface)180 static ULONG WINAPI IDirectMusic8Impl_AddRef(LPDIRECTMUSIC8 iface)
181 {
182     IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
183     ULONG ref = InterlockedIncrement(&This->ref);
184 
185     TRACE("(%p)->(): new ref = %u\n", This, ref);
186 
187     return ref;
188 }
189 
IDirectMusic8Impl_Release(LPDIRECTMUSIC8 iface)190 static ULONG WINAPI IDirectMusic8Impl_Release(LPDIRECTMUSIC8 iface)
191 {
192     IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
193     ULONG ref = InterlockedDecrement(&This->ref);
194 
195     TRACE("(%p)->(): new ref = %u\n", This, ref);
196 
197     if (!ref) {
198         IReferenceClock_Release(This->master_clock);
199         if (This->dsound)
200             IDirectSound_Release(This->dsound);
201         HeapFree(GetProcessHeap(), 0, This->system_ports);
202         HeapFree(GetProcessHeap(), 0, This->ports);
203         HeapFree(GetProcessHeap(), 0, This);
204         DMUSIC_UnlockModule();
205     }
206 
207     return ref;
208 }
209 
210 /* IDirectMusic8Impl IDirectMusic part: */
IDirectMusic8Impl_EnumPort(LPDIRECTMUSIC8 iface,DWORD index,LPDMUS_PORTCAPS port_caps)211 static HRESULT WINAPI IDirectMusic8Impl_EnumPort(LPDIRECTMUSIC8 iface, DWORD index, LPDMUS_PORTCAPS port_caps)
212 {
213     IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
214 
215     TRACE("(%p, %d, %p)\n", This, index, port_caps);
216 
217     if (!port_caps)
218         return E_POINTER;
219 
220     if (index >= This->num_system_ports)
221         return S_FALSE;
222 
223     *port_caps = This->system_ports[index].caps;
224 
225     return S_OK;
226 }
227 
IDirectMusic8Impl_CreateMusicBuffer(LPDIRECTMUSIC8 iface,LPDMUS_BUFFERDESC buffer_desc,LPDIRECTMUSICBUFFER * buffer,LPUNKNOWN unkouter)228 static HRESULT WINAPI IDirectMusic8Impl_CreateMusicBuffer(LPDIRECTMUSIC8 iface, LPDMUS_BUFFERDESC buffer_desc, LPDIRECTMUSICBUFFER* buffer, LPUNKNOWN unkouter)
229 {
230     IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
231 
232     TRACE("(%p)->(%p, %p, %p)\n", This, buffer_desc, buffer, unkouter);
233 
234     if (unkouter)
235         return CLASS_E_NOAGGREGATION;
236 
237     if (!buffer_desc || !buffer)
238         return E_POINTER;
239 
240     return DMUSIC_CreateDirectMusicBufferImpl(buffer_desc, (LPVOID)buffer);
241 }
242 
IDirectMusic8Impl_CreatePort(LPDIRECTMUSIC8 iface,REFCLSID rclsid_port,LPDMUS_PORTPARAMS port_params,LPDIRECTMUSICPORT * port,LPUNKNOWN unkouter)243 static HRESULT WINAPI IDirectMusic8Impl_CreatePort(LPDIRECTMUSIC8 iface, REFCLSID rclsid_port, LPDMUS_PORTPARAMS port_params, LPDIRECTMUSICPORT* port, LPUNKNOWN unkouter)
244 {
245     IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
246     int i;
247     DMUS_PORTCAPS port_caps;
248     IDirectMusicPort* new_port = NULL;
249     HRESULT hr;
250     GUID default_port;
251     const GUID *request_port = rclsid_port;
252 
253     TRACE("(%p)->(%s, %p, %p, %p)\n", This, debugstr_dmguid(rclsid_port), port_params, port, unkouter);
254 
255     if (!rclsid_port || !port)
256         return E_POINTER;
257     if (!port_params)
258         return E_INVALIDARG;
259     if (unkouter)
260         return CLASS_E_NOAGGREGATION;
261     if (!This->dsound)
262         return DMUS_E_DSOUND_NOT_SET;
263 
264     if (TRACE_ON(dmusic))
265         dump_DMUS_PORTPARAMS(port_params);
266 
267     ZeroMemory(&port_caps, sizeof(DMUS_PORTCAPS));
268     port_caps.dwSize = sizeof(DMUS_PORTCAPS);
269 
270     if (IsEqualGUID(request_port, &GUID_NULL)) {
271         hr = IDirectMusic8_GetDefaultPort(iface, &default_port);
272         if(FAILED(hr))
273             return hr;
274         request_port = &default_port;
275     }
276 
277     for (i = 0; S_FALSE != IDirectMusic8Impl_EnumPort(iface, i, &port_caps); i++) {
278         if (IsEqualCLSID(request_port, &port_caps.guidPort)) {
279             hr = This->system_ports[i].create(This, port_params, &port_caps, &new_port);
280             if (FAILED(hr)) {
281                  *port = NULL;
282                  return hr;
283             }
284             This->num_ports++;
285             if (!This->ports)
286                 This->ports = HeapAlloc(GetProcessHeap(), 0,
287                         sizeof(*This->ports) * This->num_ports);
288             else
289                 This->ports = HeapReAlloc(GetProcessHeap(), 0, This->ports,
290                         sizeof(*This->ports) * This->num_ports);
291             This->ports[This->num_ports - 1] = new_port;
292             *port = new_port;
293             return S_OK;
294         }
295     }
296 
297     return E_NOINTERFACE;
298 }
299 
dmusic_remove_port(IDirectMusic8Impl * dmusic,IDirectMusicPort * port)300 void dmusic_remove_port(IDirectMusic8Impl *dmusic, IDirectMusicPort *port)
301 {
302     BOOL found = FALSE;
303     int i;
304 
305     TRACE("Removing port %p.\n", port);
306 
307     for (i = 0; i < dmusic->num_ports; i++)
308     {
309         if (dmusic->ports[i] == port) {
310             found = TRUE;
311             break;
312         }
313     }
314 
315     if (!found)
316     {
317         ERR("Port %p not found in ports array.\n", port);
318         return;
319     }
320 
321     if (!--dmusic->num_ports) {
322         HeapFree(GetProcessHeap(), 0, dmusic->ports);
323         dmusic->ports = NULL;
324         return;
325     }
326 
327     memmove(&dmusic->ports[i], &dmusic->ports[i + 1],
328             (dmusic->num_ports - i) * sizeof(*dmusic->ports));
329     dmusic->ports = HeapReAlloc(GetProcessHeap(), 0, dmusic->ports,
330             sizeof(*dmusic->ports) * dmusic->num_ports);
331 }
332 
IDirectMusic8Impl_EnumMasterClock(LPDIRECTMUSIC8 iface,DWORD index,LPDMUS_CLOCKINFO clock_info)333 static HRESULT WINAPI IDirectMusic8Impl_EnumMasterClock(LPDIRECTMUSIC8 iface, DWORD index, LPDMUS_CLOCKINFO clock_info)
334 {
335     TRACE("(%p)->(%d, %p)\n", iface, index, clock_info);
336 
337     if (!clock_info)
338         return E_POINTER;
339 
340     if (index > 1)
341         return S_FALSE;
342 
343     if (!index)
344     {
345         static const GUID guid_system_clock = { 0x58d58419, 0x71b4, 0x11d1, { 0xa7, 0x4c, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12 } };
346         static const WCHAR name_system_clock[] = { 'S','y','s','t','e','m',' ','C','l','o','c','k',0 };
347 
348         clock_info->ctType = 0;
349         clock_info->guidClock = guid_system_clock;
350         lstrcpyW(clock_info->wszDescription, name_system_clock);
351     }
352     else
353     {
354         static const GUID guid_dsound_clock = { 0x58d58420, 0x71b4, 0x11d1, { 0xa7, 0x4c, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12 } };
355         static const WCHAR name_dsound_clock[] = { 'D','i','r','e','c','t','S','o','u','n','d',' ','C','l','o','c','k',0 };
356 
357         clock_info->ctType = 0;
358         clock_info->guidClock = guid_dsound_clock;
359         lstrcpyW(clock_info->wszDescription, name_dsound_clock);
360     }
361 
362     return S_OK;
363 }
364 
IDirectMusic8Impl_GetMasterClock(LPDIRECTMUSIC8 iface,LPGUID guid_clock,IReferenceClock ** reference_clock)365 static HRESULT WINAPI IDirectMusic8Impl_GetMasterClock(LPDIRECTMUSIC8 iface, LPGUID guid_clock, IReferenceClock** reference_clock)
366 {
367     IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
368 
369     TRACE("(%p)->(%p, %p)\n", This, guid_clock, reference_clock);
370 
371     if (guid_clock)
372         *guid_clock = GUID_NULL;
373     if (reference_clock) {
374         *reference_clock = This->master_clock;
375         IReferenceClock_AddRef(*reference_clock);
376     }
377 
378     return S_OK;
379 }
380 
IDirectMusic8Impl_SetMasterClock(LPDIRECTMUSIC8 iface,REFGUID rguidClock)381 static HRESULT WINAPI IDirectMusic8Impl_SetMasterClock(LPDIRECTMUSIC8 iface, REFGUID rguidClock)
382 {
383     IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
384 
385     FIXME("(%p)->(%s): stub\n", This, debugstr_dmguid(rguidClock));
386 
387     return S_OK;
388 }
389 
IDirectMusic8Impl_Activate(LPDIRECTMUSIC8 iface,BOOL enable)390 static HRESULT WINAPI IDirectMusic8Impl_Activate(LPDIRECTMUSIC8 iface, BOOL enable)
391 {
392     IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
393     int i;
394     HRESULT hr;
395 
396     TRACE("(%p)->(%u)\n", This, enable);
397 
398     for (i = 0; i < This->num_ports; i++)
399     {
400         hr = IDirectMusicPort_Activate(This->ports[i], enable);
401         if (FAILED(hr))
402             return hr;
403     }
404 
405     return S_OK;
406 }
407 
IDirectMusic8Impl_GetDefaultPort(LPDIRECTMUSIC8 iface,LPGUID guid_port)408 static HRESULT WINAPI IDirectMusic8Impl_GetDefaultPort(LPDIRECTMUSIC8 iface, LPGUID guid_port)
409 {
410     IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
411     HKEY hkGUID;
412     DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
413     char returnBuffer[51];
414     GUID defaultPortGUID;
415     WCHAR buff[51];
416 
417     TRACE("(%p)->(%p)\n", This, guid_port);
418 
419     if ((RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\DirectMusic\\Defaults" , 0, KEY_READ, &hkGUID) != ERROR_SUCCESS) ||
420         (RegQueryValueExA(hkGUID, "DefaultOutputPort", NULL, &returnTypeGUID, (LPBYTE)returnBuffer, &sizeOfReturnBuffer) != ERROR_SUCCESS))
421     {
422         WARN(": registry entry missing\n" );
423         *guid_port = CLSID_DirectMusicSynth;
424         return S_OK;
425     }
426     /* FIXME: Check return types to ensure we're interpreting data right */
427     MultiByteToWideChar(CP_ACP, 0, returnBuffer, -1, buff, ARRAY_SIZE(buff));
428     CLSIDFromString(buff, &defaultPortGUID);
429     *guid_port = defaultPortGUID;
430 
431     return S_OK;
432 }
433 
IDirectMusic8Impl_SetDirectSound(IDirectMusic8 * iface,IDirectSound * dsound,HWND hwnd)434 static HRESULT WINAPI IDirectMusic8Impl_SetDirectSound(IDirectMusic8 *iface, IDirectSound *dsound,
435         HWND hwnd)
436 {
437     IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
438     HRESULT hr;
439     int i;
440 
441     TRACE("(%p)->(%p, %p)\n", This, dsound, hwnd);
442 
443     for (i = 0; i < This->num_ports; i++)
444     {
445         hr = IDirectMusicPort_SetDirectSound(This->ports[i], NULL, NULL);
446         if (FAILED(hr))
447             return hr;
448     }
449 
450     if (This->dsound)
451         IDirectSound_Release(This->dsound);
452 
453     if (!dsound) {
454         hr = DirectSoundCreate8(NULL, (IDirectSound8 **)&This->dsound, NULL);
455         if (FAILED(hr))
456             return hr;
457         hr = IDirectSound_SetCooperativeLevel(This->dsound, hwnd ? hwnd : GetForegroundWindow(),
458                 DSSCL_PRIORITY);
459         if (FAILED(hr)) {
460             IDirectSound_Release(This->dsound);
461             This->dsound = NULL;
462         }
463         return hr;
464     }
465 
466     IDirectSound_AddRef(dsound);
467     This->dsound = dsound;
468 
469     return S_OK;
470 }
471 
IDirectMusic8Impl_SetExternalMasterClock(LPDIRECTMUSIC8 iface,IReferenceClock * clock)472 static HRESULT WINAPI IDirectMusic8Impl_SetExternalMasterClock(LPDIRECTMUSIC8 iface, IReferenceClock* clock)
473 {
474     IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
475 
476     FIXME("(%p)->(%p): stub\n", This, clock);
477 
478     return S_OK;
479 }
480 
481 static const IDirectMusic8Vtbl DirectMusic8_Vtbl = {
482     IDirectMusic8Impl_QueryInterface,
483     IDirectMusic8Impl_AddRef,
484     IDirectMusic8Impl_Release,
485     IDirectMusic8Impl_EnumPort,
486     IDirectMusic8Impl_CreateMusicBuffer,
487     IDirectMusic8Impl_CreatePort,
488     IDirectMusic8Impl_EnumMasterClock,
489     IDirectMusic8Impl_GetMasterClock,
490     IDirectMusic8Impl_SetMasterClock,
491     IDirectMusic8Impl_Activate,
492     IDirectMusic8Impl_GetDefaultPort,
493     IDirectMusic8Impl_SetDirectSound,
494     IDirectMusic8Impl_SetExternalMasterClock
495 };
496 
create_system_ports_list(IDirectMusic8Impl * object)497 static void create_system_ports_list(IDirectMusic8Impl* object)
498 {
499     static const WCHAR emulated[] = {' ','[','E','m','u','l','a','t','e','d',']',0};
500     port_info * port;
501     ULONG nb_ports;
502     ULONG nb_midi_out;
503     ULONG nb_midi_in;
504     MIDIOUTCAPSW caps_out;
505     MIDIINCAPSW caps_in;
506     IDirectMusicSynth8* synth;
507     HRESULT hr;
508     ULONG i;
509 
510     TRACE("(%p)\n", object);
511 
512     /* NOTE:
513        - it seems some native versions get the rest of devices through dmusic32.EnumLegacyDevices...*sigh*...which is undocumented
514        - should we enum wave devices ? Native does not seem to
515     */
516 
517     nb_midi_out = midiOutGetNumDevs();
518     nb_midi_in = midiInGetNumDevs();
519     nb_ports = 1 /* midi mapper */ + nb_midi_out + nb_midi_in + 1 /* synth port */;
520 
521     port = object->system_ports = HeapAlloc(GetProcessHeap(), 0, nb_ports * sizeof(port_info));
522     if (!object->system_ports)
523         return;
524 
525     /* Fill common port caps for all winmm ports */
526     for (i = 0; i < (nb_ports - 1 /* synth port*/); i++)
527     {
528         object->system_ports[i].caps.dwSize = sizeof(DMUS_PORTCAPS);
529         object->system_ports[i].caps.dwType = DMUS_PORT_WINMM_DRIVER;
530         object->system_ports[i].caps.dwMemorySize = 0;
531         object->system_ports[i].caps.dwMaxChannelGroups = 1;
532         object->system_ports[i].caps.dwMaxVoices = 0;
533         object->system_ports[i].caps.dwMaxAudioChannels = 0;
534         object->system_ports[i].caps.dwEffectFlags = DMUS_EFFECT_NONE;
535         /* Fake port GUID */
536         object->system_ports[i].caps.guidPort = IID_IUnknown;
537         object->system_ports[i].caps.guidPort.Data1 = i + 1;
538     }
539 
540     /* Fill midi mapper port info */
541     port->device = MIDI_MAPPER;
542     port->create = midi_out_port_create;
543     midiOutGetDevCapsW(MIDI_MAPPER, &caps_out, sizeof(caps_out));
544     lstrcpyW(port->caps.wszDescription, caps_out.szPname);
545     lstrcatW(port->caps.wszDescription, emulated);
546     port->caps.dwFlags = DMUS_PC_SHAREABLE;
547     port->caps.dwClass = DMUS_PC_OUTPUTCLASS;
548     port++;
549 
550     /* Fill midi out port info */
551     for (i = 0; i < nb_midi_out; i++)
552     {
553         port->device = i;
554         port->create = midi_out_port_create;
555         midiOutGetDevCapsW(i, &caps_out, sizeof(caps_out));
556         lstrcpyW(port->caps.wszDescription, caps_out.szPname);
557         lstrcatW(port->caps.wszDescription, emulated);
558         port->caps.dwFlags = DMUS_PC_SHAREABLE | DMUS_PC_EXTERNAL;
559         port->caps.dwClass = DMUS_PC_OUTPUTCLASS;
560         port++;
561     }
562 
563     /* Fill midi in port info */
564     for (i = 0; i < nb_midi_in; i++)
565     {
566         port->device = i;
567         port->create = midi_in_port_create;
568         midiInGetDevCapsW(i, &caps_in, sizeof(caps_in));
569         lstrcpyW(port->caps.wszDescription, caps_in.szPname);
570         lstrcatW(port->caps.wszDescription, emulated);
571         port->caps.dwFlags = DMUS_PC_EXTERNAL;
572         port->caps.dwClass = DMUS_PC_INPUTCLASS;
573         port++;
574     }
575 
576     /* Fill synth port info */
577     port->create = synth_port_create;
578     hr = CoCreateInstance(&CLSID_DirectMusicSynth, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicSynth8, (void**)&synth);
579     if (SUCCEEDED(hr))
580     {
581         port->caps.dwSize = sizeof(port->caps);
582         hr = IDirectMusicSynth8_GetPortCaps(synth, &port->caps);
583         IDirectMusicSynth8_Release(synth);
584     }
585     if (FAILED(hr))
586         nb_ports--;
587 
588     object->num_system_ports = nb_ports;
589 }
590 
591 /* For ClassFactory */
DMUSIC_CreateDirectMusicImpl(LPCGUID riid,LPVOID * ret_iface,LPUNKNOWN unkouter)592 HRESULT WINAPI DMUSIC_CreateDirectMusicImpl(LPCGUID riid, LPVOID* ret_iface, LPUNKNOWN unkouter)
593 {
594     IDirectMusic8Impl *dmusic;
595     HRESULT ret;
596 
597     TRACE("(%s, %p, %p)\n", debugstr_guid(riid), ret_iface, unkouter);
598 
599     *ret_iface = NULL;
600     if (unkouter)
601         return CLASS_E_NOAGGREGATION;
602 
603     dmusic = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusic8Impl));
604     if (!dmusic)
605         return E_OUTOFMEMORY;
606 
607     dmusic->IDirectMusic8_iface.lpVtbl = &DirectMusic8_Vtbl;
608     dmusic->ref = 1;
609     ret = master_clock_create(&dmusic->master_clock);
610     if (FAILED(ret)) {
611         HeapFree(GetProcessHeap(), 0, dmusic);
612         return ret;
613     }
614 
615     create_system_ports_list(dmusic);
616 
617     DMUSIC_LockModule();
618     ret = IDirectMusic8Impl_QueryInterface(&dmusic->IDirectMusic8_iface, riid, ret_iface);
619     IDirectMusic8_Release(&dmusic->IDirectMusic8_iface);
620 
621     return ret;
622 }
623