dmusic: Check errors in IDirectMusic8Impl_Activate and remove FIXME.
[wine] / dlls / dmusic / dmusic.c
1 /* IDirectMusic8 Implementation
2  *
3  * Copyright (C) 2003-2004 Rok Mandeljc
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19
20 #include <stdio.h>
21
22 #include "dmusic_private.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(dmusic);
25
26 static inline IDirectMusic8Impl *impl_from_IDirectMusic8(IDirectMusic8 *iface)
27 {
28     return CONTAINING_RECORD(iface, IDirectMusic8Impl, IDirectMusic8_iface);
29 }
30
31 /* IDirectMusic8Impl IUnknown part: */
32 static HRESULT WINAPI IDirectMusic8Impl_QueryInterface(LPDIRECTMUSIC8 iface, REFIID riid, LPVOID *ppobj)
33 {
34         IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
35         TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj);
36
37         if (IsEqualIID (riid, &IID_IUnknown) || 
38             IsEqualIID (riid, &IID_IDirectMusic) ||
39             IsEqualIID (riid, &IID_IDirectMusic2) ||
40             IsEqualIID (riid, &IID_IDirectMusic8)) {
41                 IUnknown_AddRef(iface);
42                 *ppobj = This;
43                 return S_OK;
44         }
45
46         WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ppobj);
47         return E_NOINTERFACE;
48 }
49
50 static ULONG WINAPI IDirectMusic8Impl_AddRef(LPDIRECTMUSIC8 iface)
51 {
52         IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
53         ULONG refCount = InterlockedIncrement(&This->ref);
54
55         TRACE("(%p)->(ref before=%u)\n", This, refCount - 1);
56
57         DMUSIC_LockModule();
58
59         return refCount;
60 }
61
62 static ULONG WINAPI IDirectMusic8Impl_Release(LPDIRECTMUSIC8 iface)
63 {
64         IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
65         ULONG refCount = InterlockedDecrement(&This->ref);
66
67         TRACE("(%p)->(ref before=%u)\n", This, refCount + 1);
68
69         if (!refCount) {
70                 HeapFree(GetProcessHeap(), 0, This->ppPorts);
71                 HeapFree(GetProcessHeap(), 0, This);
72         }
73
74         DMUSIC_UnlockModule();
75         
76         return refCount;
77 }
78
79 /* IDirectMusic8Impl IDirectMusic part: */
80 static HRESULT WINAPI IDirectMusic8Impl_EnumPort(LPDIRECTMUSIC8 iface, DWORD index, LPDMUS_PORTCAPS port_caps)
81 {
82     IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
83     ULONG nb_midi_out;
84     ULONG nb_midi_in;
85     const WCHAR emulated[] = {' ','[','E','m','u','l','a','t','e','d',']',0};
86
87     TRACE("(%p, %d, %p)\n", This, index, port_caps);
88
89     if (!port_caps)
90         return E_POINTER;
91
92     /* NOTE: It seems some native versions get the rest of devices through dmusic32.EnumLegacyDevices...*sigh*...which is undocumented */
93
94     /* NOTE: Should we enum wave devices ? Native does not seem to */
95
96     /* Fill common port caps for winmm ports */
97     port_caps->dwType = DMUS_PORT_WINMM_DRIVER;
98     port_caps->dwMemorySize = 0;
99     port_caps->dwMaxChannelGroups = 1;
100     port_caps->dwMaxVoices = 0;
101     port_caps->dwMaxAudioChannels = 0;
102     port_caps->dwEffectFlags = DMUS_EFFECT_NONE;
103     /* Fake port GUID */
104     port_caps->guidPort = IID_IUnknown;
105     port_caps->guidPort.Data1 = index + 1;
106
107     nb_midi_out = midiOutGetNumDevs();
108
109     if (index == 0)
110     {
111         MIDIOUTCAPSW caps;
112         midiOutGetDevCapsW(MIDI_MAPPER, &caps, sizeof(caps));
113         strcpyW(port_caps->wszDescription, caps.szPname);
114         strcatW(port_caps->wszDescription, emulated);
115         port_caps->dwFlags = DMUS_PC_SHAREABLE;
116         port_caps->dwClass = DMUS_PC_OUTPUTCLASS;
117         TRACE("Enumerating port: %s\n", debugstr_w(port_caps->wszDescription));
118         return S_OK;
119     }
120
121     if (index < (nb_midi_out + 1))
122     {
123         MIDIOUTCAPSW caps;
124         midiOutGetDevCapsW(index - 1, &caps, sizeof(caps));
125         strcpyW(port_caps->wszDescription, caps.szPname);
126         strcatW(port_caps->wszDescription, emulated);
127         port_caps->dwFlags = DMUS_PC_SHAREABLE | DMUS_PC_EXTERNAL;
128         port_caps->dwClass = DMUS_PC_OUTPUTCLASS;
129         TRACE("Enumerating port: %s\n", debugstr_w(port_caps->wszDescription));
130         return S_OK;
131     }
132
133     nb_midi_in = midiInGetNumDevs();
134
135     if (index < (nb_midi_in + nb_midi_out + 1))
136     {
137         MIDIINCAPSW caps;
138         midiInGetDevCapsW(index - nb_midi_out - 1, &caps, sizeof(caps));
139         strcpyW(port_caps->wszDescription, caps.szPname);
140         strcatW(port_caps->wszDescription, emulated);
141         port_caps->dwFlags = DMUS_PC_EXTERNAL;
142         port_caps->dwClass = DMUS_PC_INPUTCLASS;
143         TRACE("Enumerating port: %s\n", debugstr_w(port_caps->wszDescription));
144         return S_OK;
145     }
146
147     if (index == (nb_midi_in + nb_midi_out + 1))
148     {
149         IDirectMusicSynth8* synth = NULL;
150         HRESULT hr;
151         hr = CoCreateInstance(&CLSID_DirectMusicSynth, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicSynth8, (void**)&synth);
152         if (SUCCEEDED(hr))
153             hr = IDirectMusicSynth8_GetPortCaps(synth, port_caps);
154         if (SUCCEEDED(hr))
155             TRACE("Enumerating port: %s\n", debugstr_w(port_caps->wszDescription));
156         if (synth)
157             IDirectMusicSynth8_Release(synth);
158         return hr;
159     }
160
161     return S_FALSE;
162 }
163
164 static HRESULT WINAPI IDirectMusic8Impl_CreateMusicBuffer(LPDIRECTMUSIC8 iface, LPDMUS_BUFFERDESC pBufferDesc, LPDIRECTMUSICBUFFER* ppBuffer, LPUNKNOWN pUnkOuter)
165 {
166         IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
167
168         TRACE("(%p, %p, %p, %p)\n", This, pBufferDesc, ppBuffer, pUnkOuter);
169
170         if (pUnkOuter)
171                 return CLASS_E_NOAGGREGATION;
172
173         if (!pBufferDesc || !ppBuffer)
174                 return E_POINTER;
175
176         return DMUSIC_CreateDirectMusicBufferImpl(pBufferDesc, (LPVOID)ppBuffer);
177 }
178
179 static HRESULT WINAPI IDirectMusic8Impl_CreatePort(LPDIRECTMUSIC8 iface, REFCLSID rclsidPort, LPDMUS_PORTPARAMS pPortParams, LPDIRECTMUSICPORT* ppPort, LPUNKNOWN pUnkOuter)
180 {
181         IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
182         int i;
183         DMUS_PORTCAPS PortCaps;
184         IDirectMusicPort* pNewPort = NULL;
185         HRESULT hr;
186         GUID default_port;
187         const GUID *request_port = rclsidPort;
188
189         TRACE("(%p, %s, %p, %p, %p)\n", This, debugstr_dmguid(rclsidPort), pPortParams, ppPort, pUnkOuter);
190
191         if (TRACE_ON(dmusic))
192                 dump_DMUS_PORTPARAMS(pPortParams);
193
194         if (!rclsidPort)
195                 return E_POINTER;
196         if (!pPortParams)
197                 return E_INVALIDARG;
198         if (!ppPort)
199                 return E_POINTER;
200         if (pUnkOuter)
201                 return CLASS_E_NOAGGREGATION;
202
203         if (TRACE_ON(dmusic))
204                 dump_DMUS_PORTPARAMS(pPortParams);
205
206         ZeroMemory(&PortCaps, sizeof(DMUS_PORTCAPS));
207         PortCaps.dwSize = sizeof(DMUS_PORTCAPS);
208
209         if(IsEqualGUID(request_port, &GUID_NULL)){
210                 hr = IDirectMusic8_GetDefaultPort(iface, &default_port);
211                 if(FAILED(hr))
212                         return hr;
213                 request_port = &default_port;
214         }
215
216         for (i = 0; S_FALSE != IDirectMusic8Impl_EnumPort(iface, i, &PortCaps); i++) {
217                 if (IsEqualCLSID (request_port, &PortCaps.guidPort)) {
218                         hr = DMUSIC_CreateDirectMusicPortImpl(&IID_IDirectMusicPort, (LPVOID*) &pNewPort, (LPUNKNOWN) This, pPortParams, &PortCaps);
219                         if (FAILED(hr)) {
220                           *ppPort = NULL;
221                           return hr;
222                         }
223                         This->nrofports++;
224                         if (!This->ppPorts) This->ppPorts = HeapAlloc(GetProcessHeap(), 0, sizeof(LPDIRECTMUSICPORT) * This->nrofports);
225                         else This->ppPorts = HeapReAlloc(GetProcessHeap(), 0, This->ppPorts, sizeof(LPDIRECTMUSICPORT) * This->nrofports);
226                         This->ppPorts[This->nrofports - 1] = pNewPort;
227                         *ppPort = pNewPort;
228                         return S_OK;
229                 }
230         }
231         return E_NOINTERFACE;
232 }
233
234 static HRESULT WINAPI IDirectMusic8Impl_EnumMasterClock(LPDIRECTMUSIC8 iface, DWORD index, LPDMUS_CLOCKINFO clock_info)
235 {
236     TRACE("(%p)->(%d, %p)\n", iface, index, clock_info);
237
238     if (!clock_info)
239         return E_POINTER;
240
241     if (index > 1)
242         return S_FALSE;
243
244     if (!index)
245     {
246         static const GUID guid_system_clock = { 0x58d58419, 0x71b4, 0x11d1, { 0xa7, 0x4c, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12 } };
247         static const WCHAR name_system_clock[] = { 'S','y','s','t','e','m',' ','C','l','o','c','k',0 };
248
249         clock_info->ctType = 0;
250         clock_info->guidClock = guid_system_clock;
251         strcpyW(clock_info->wszDescription, name_system_clock);
252     }
253     else
254     {
255         static const GUID guid_dsound_clock = { 0x58d58420, 0x71b4, 0x11d1, { 0xa7, 0x4c, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12 } };
256         static const WCHAR name_dsound_clock[] = { 'D','i','r','e','c','t','S','o','u','n','d',' ','C','l','o','c','k',0 };
257
258         clock_info->ctType = 0;
259         clock_info->guidClock = guid_dsound_clock;
260         strcpyW(clock_info->wszDescription, name_dsound_clock);
261     }
262
263     return S_OK;
264 }
265
266 static HRESULT WINAPI IDirectMusic8Impl_GetMasterClock(LPDIRECTMUSIC8 iface, LPGUID pguidClock, IReferenceClock** ppReferenceClock)
267 {
268         IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
269
270         TRACE("(%p, %p, %p)\n", This, pguidClock, ppReferenceClock);
271         if (pguidClock)
272                 *pguidClock = This->pMasterClock->pClockInfo.guidClock;
273         if(ppReferenceClock)
274                 *ppReferenceClock = (IReferenceClock *)This->pMasterClock;
275
276         return S_OK;
277 }
278
279 static HRESULT WINAPI IDirectMusic8Impl_SetMasterClock(LPDIRECTMUSIC8 iface, REFGUID rguidClock)
280 {
281     IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
282
283     FIXME("(%p)->(%s): stub\n", This, debugstr_dmguid(rguidClock));
284
285     return S_OK;
286 }
287
288 static HRESULT WINAPI IDirectMusic8Impl_Activate(LPDIRECTMUSIC8 iface, BOOL enable)
289 {
290     IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
291     int i;
292     HRESULT hr;
293
294     TRACE("(%p)->(%u)\n", This, enable);
295
296     for (i = 0; i < This->nrofports; i++)
297     {
298         hr = IDirectMusicPort_Activate(This->ppPorts[i], enable);
299         if (FAILED(hr))
300             return hr;
301     }
302
303     return S_OK;
304 }
305
306 static HRESULT WINAPI IDirectMusic8Impl_GetDefaultPort(LPDIRECTMUSIC8 iface, LPGUID pguidPort)
307 {
308         IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
309         HKEY hkGUID;
310         DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
311         char returnBuffer[51];
312         GUID defaultPortGUID;
313         WCHAR buff[51];
314
315         TRACE("(%p, %p)\n", This, pguidPort);
316         if ((RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\DirectMusic\\Defaults" , 0, KEY_READ, &hkGUID) != ERROR_SUCCESS) || 
317             (RegQueryValueExA(hkGUID, "DefaultOutputPort", NULL, &returnTypeGUID, (LPBYTE)returnBuffer, &sizeOfReturnBuffer) != ERROR_SUCCESS))
318         {
319                 WARN(": registry entry missing\n" );
320                 *pguidPort = CLSID_DirectMusicSynth;
321                 return S_OK;
322         }
323         /* FIXME: Check return types to ensure we're interpreting data right */
324         MultiByteToWideChar(CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff) / sizeof(WCHAR));
325         CLSIDFromString(buff, &defaultPortGUID);
326         *pguidPort = defaultPortGUID;
327         
328         return S_OK;
329 }
330
331 static HRESULT WINAPI IDirectMusic8Impl_SetDirectSound(LPDIRECTMUSIC8 iface, LPDIRECTSOUND dsound, HWND wnd)
332 {
333     IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
334
335     FIXME("(%p)->(%p, %p): stub\n", This, dsound, wnd);
336
337     return S_OK;
338 }
339
340 static HRESULT WINAPI IDirectMusic8Impl_SetExternalMasterClock(LPDIRECTMUSIC8 iface, IReferenceClock* clock)
341 {
342     IDirectMusic8Impl *This = impl_from_IDirectMusic8(iface);
343
344     FIXME("(%p)->(%p): stub\n", This, clock);
345
346     return S_OK;
347 }
348
349 static const IDirectMusic8Vtbl DirectMusic8_Vtbl = {
350         IDirectMusic8Impl_QueryInterface,
351         IDirectMusic8Impl_AddRef,
352         IDirectMusic8Impl_Release,
353         IDirectMusic8Impl_EnumPort,
354         IDirectMusic8Impl_CreateMusicBuffer,
355         IDirectMusic8Impl_CreatePort,
356         IDirectMusic8Impl_EnumMasterClock,
357         IDirectMusic8Impl_GetMasterClock,
358         IDirectMusic8Impl_SetMasterClock,
359         IDirectMusic8Impl_Activate,
360         IDirectMusic8Impl_GetDefaultPort,
361         IDirectMusic8Impl_SetDirectSound,
362         IDirectMusic8Impl_SetExternalMasterClock
363 };
364
365 /* for ClassFactory */
366 HRESULT WINAPI DMUSIC_CreateDirectMusicImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter) {
367         IDirectMusic8Impl *dmusic;
368
369         TRACE("(%p,%p,%p)\n",lpcGUID, ppobj, pUnkOuter);
370
371         dmusic = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusic8Impl));
372         if (NULL == dmusic) {
373                 *ppobj = NULL;
374                 return E_OUTOFMEMORY;
375         }
376         dmusic->IDirectMusic8_iface.lpVtbl = &DirectMusic8_Vtbl;
377         dmusic->ref = 0; /* will be inited with QueryInterface */
378         dmusic->pMasterClock = NULL;
379         dmusic->ppPorts = NULL;
380         dmusic->nrofports = 0;
381         DMUSIC_CreateReferenceClockImpl (&IID_IReferenceClock, (LPVOID*)&dmusic->pMasterClock, NULL);
382         
383         return IDirectMusic8Impl_QueryInterface ((LPDIRECTMUSIC8)dmusic, lpcGUID, ppobj);
384 }