gdi32/tests: Add some tests for the behavior of a printer DC.
[wine] / dlls / dsound / duplex.c
1 /*              DirectSoundFullDuplex
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998 Rob Riggs
5  * Copyright 2000-2001 TransGaming Technologies, Inc.
6  * Copyright 2005 Robert Reif
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include <stdarg.h>
24
25 #define NONAMELESSSTRUCT
26 #define NONAMELESSUNION
27 #define COBJMACROS
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "mmsystem.h"
32 #include "mmddk.h"
33 #include "winternl.h"
34 #include "wine/debug.h"
35 #include "dsound.h"
36 #include "dsound_private.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
39
40 /*****************************************************************************
41  * IDirectSoundFullDuplex implementation structure
42  */
43 typedef struct IDirectSoundFullDuplexImpl
44 {
45     /* IUnknown fields */
46     const IDirectSoundFullDuplexVtbl *lpVtbl;
47     LONG                              ref;
48
49     /* IDirectSoundFullDuplexImpl fields */
50     IDirectSound8                    *renderer_device;
51     IDirectSoundCapture              *capture_device;
52
53     LPUNKNOWN                         pUnknown;
54     LPDIRECTSOUND8                    pDS8;
55     LPDIRECTSOUNDCAPTURE              pDSC;
56 } IDirectSoundFullDuplexImpl;
57
58 typedef struct IDirectSoundFullDuplex_IUnknown {
59     const IUnknownVtbl         *lpVtbl;
60     LONG                        ref;
61     IDirectSoundFullDuplexImpl *pdsfd;
62 } IDirectSoundFullDuplex_IUnknown;
63
64 typedef struct IDirectSoundFullDuplex_IDirectSound8 {
65     const IDirectSound8Vtbl    *lpVtbl;
66     LONG                        ref;
67     IDirectSoundFullDuplexImpl *pdsfd;
68 } IDirectSoundFullDuplex_IDirectSound8;
69
70 typedef struct IDirectSoundFullDuplex_IDirectSoundCapture {
71     const IDirectSoundCaptureVtbl *lpVtbl;
72     LONG                           ref;
73     IDirectSoundFullDuplexImpl    *pdsfd;
74 } IDirectSoundFullDuplex_IDirectSoundCapture;
75
76 /*******************************************************************************
77  * IUnknown
78  */
79 static HRESULT WINAPI IDirectSoundFullDuplex_IUnknown_QueryInterface(
80     LPUNKNOWN iface,
81     REFIID riid,
82     LPVOID * ppobj)
83 {
84     IDirectSoundFullDuplex_IUnknown *This = (IDirectSoundFullDuplex_IUnknown *)iface;
85     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
86     return IDirectSoundFullDuplex_QueryInterface((LPDIRECTSOUNDFULLDUPLEX)This->pdsfd, riid, ppobj);
87 }
88
89 static ULONG WINAPI IDirectSoundFullDuplex_IUnknown_AddRef(
90     LPUNKNOWN iface)
91 {
92     IDirectSoundFullDuplex_IUnknown *This = (IDirectSoundFullDuplex_IUnknown *)iface;
93     ULONG ref = InterlockedIncrement(&(This->ref));
94     TRACE("(%p) ref was %d\n", This, ref - 1);
95     return ref;
96 }
97
98 static ULONG WINAPI IDirectSoundFullDuplex_IUnknown_Release(
99     LPUNKNOWN iface)
100 {
101     IDirectSoundFullDuplex_IUnknown *This = (IDirectSoundFullDuplex_IUnknown *)iface;
102     ULONG ref = InterlockedDecrement(&(This->ref));
103     TRACE("(%p) ref was %d\n", This, ref + 1);
104     if (!ref) {
105         This->pdsfd->pUnknown = NULL;
106         HeapFree(GetProcessHeap(), 0, This);
107         TRACE("(%p) released\n", This);
108     }
109     return ref;
110 }
111
112 static const IUnknownVtbl DirectSoundFullDuplex_Unknown_Vtbl =
113 {
114     IDirectSoundFullDuplex_IUnknown_QueryInterface,
115     IDirectSoundFullDuplex_IUnknown_AddRef,
116     IDirectSoundFullDuplex_IUnknown_Release
117 };
118
119 static HRESULT IDirectSoundFullDuplex_IUnknown_Create(
120     LPDIRECTSOUNDFULLDUPLEX pdsfd,
121     LPUNKNOWN * ppunk)
122 {
123     IDirectSoundFullDuplex_IUnknown * pdsfdunk;
124     TRACE("(%p,%p)\n",pdsfd,ppunk);
125
126     if (pdsfd == NULL) {
127         ERR("invalid parameter: pdsfd == NULL\n");
128         return DSERR_INVALIDPARAM;
129     }
130
131     if (ppunk == NULL) {
132         ERR("invalid parameter: ppunk == NULL\n");
133         return DSERR_INVALIDPARAM;
134     }
135
136     pdsfdunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsfdunk));
137     if (pdsfdunk == NULL) {
138         WARN("out of memory\n");
139         *ppunk = NULL;
140         return DSERR_OUTOFMEMORY;
141     }
142
143     pdsfdunk->lpVtbl = &DirectSoundFullDuplex_Unknown_Vtbl;
144     pdsfdunk->ref = 0;
145     pdsfdunk->pdsfd = (IDirectSoundFullDuplexImpl *)pdsfd;
146
147     *ppunk = (LPUNKNOWN)pdsfdunk;
148
149     return DS_OK;
150 }
151
152 /*******************************************************************************
153  * IDirectSoundFullDuplex_IDirectSound8
154  */
155 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_QueryInterface(
156     LPDIRECTSOUND8 iface,
157     REFIID riid,
158     LPVOID * ppobj)
159 {
160     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
161     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
162     return IDirectSoundFullDuplex_QueryInterface((LPDIRECTSOUNDFULLDUPLEX)This->pdsfd, riid, ppobj);
163 }
164
165 static ULONG WINAPI IDirectSoundFullDuplex_IDirectSound8_AddRef(
166     LPDIRECTSOUND8 iface)
167 {
168     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
169     ULONG ref = InterlockedIncrement(&(This->ref));
170     TRACE("(%p) ref was %d\n", This, ref - 1);
171     return ref;
172 }
173
174 static ULONG WINAPI IDirectSoundFullDuplex_IDirectSound8_Release(
175     LPDIRECTSOUND8 iface)
176 {
177     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
178     ULONG ref = InterlockedDecrement(&(This->ref));
179     TRACE("(%p) ref was %d\n", This, ref + 1);
180     if (!ref) {
181         This->pdsfd->pDS8 = NULL;
182         HeapFree(GetProcessHeap(), 0, This);
183         TRACE("(%p) released\n", This);
184     }
185     return ref;
186 }
187
188 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_CreateSoundBuffer(
189     LPDIRECTSOUND8 iface,
190     LPCDSBUFFERDESC dsbd,
191     LPLPDIRECTSOUNDBUFFER ppdsb,
192     LPUNKNOWN lpunk)
193 {
194     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
195     TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
196     return IDirectSound8_CreateSoundBuffer(This->pdsfd->renderer_device,dsbd,ppdsb,lpunk);
197 }
198
199 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_GetCaps(
200     LPDIRECTSOUND8 iface,
201     LPDSCAPS lpDSCaps)
202 {
203     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
204     TRACE("(%p,%p)\n",This,lpDSCaps);
205     return IDirectSound8_GetCaps(This->pdsfd->renderer_device, lpDSCaps);
206 }
207
208 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_DuplicateSoundBuffer(
209     LPDIRECTSOUND8 iface,
210     LPDIRECTSOUNDBUFFER psb,
211     LPLPDIRECTSOUNDBUFFER ppdsb)
212 {
213     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
214     TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
215     return IDirectSound8_DuplicateSoundBuffer(This->pdsfd->renderer_device,psb,ppdsb);
216 }
217
218 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_SetCooperativeLevel(
219     LPDIRECTSOUND8 iface,
220     HWND hwnd,
221     DWORD level)
222 {
223     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
224     TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
225     return IDirectSound8_SetCooperativeLevel(This->pdsfd->renderer_device,hwnd,level);
226 }
227
228 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_Compact(
229     LPDIRECTSOUND8 iface)
230 {
231     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
232     TRACE("(%p)\n", This);
233     return IDirectSound8_Compact(This->pdsfd->renderer_device);
234 }
235
236 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_GetSpeakerConfig(
237     LPDIRECTSOUND8 iface,
238     LPDWORD lpdwSpeakerConfig)
239 {
240     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
241     TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
242     return IDirectSound8_GetSpeakerConfig(This->pdsfd->renderer_device,lpdwSpeakerConfig);
243 }
244
245 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_SetSpeakerConfig(
246     LPDIRECTSOUND8 iface,
247     DWORD config)
248 {
249     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
250     TRACE("(%p,0x%08x)\n",This,config);
251     return IDirectSound8_SetSpeakerConfig(This->pdsfd->renderer_device,config);
252 }
253
254 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_Initialize(
255     LPDIRECTSOUND8 iface,
256     LPCGUID lpcGuid)
257 {
258     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
259     TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
260     return IDirectSound8_Initialize(This->pdsfd->renderer_device,lpcGuid);
261 }
262
263 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_VerifyCertification(
264     LPDIRECTSOUND8 iface,
265     DWORD *cert)
266 {
267     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
268     TRACE("(%p, %p)\n", This, cert);
269     return IDirectSound8_VerifyCertification(This->pdsfd->renderer_device,cert);
270 }
271
272 static const IDirectSound8Vtbl DirectSoundFullDuplex_DirectSound8_Vtbl =
273 {
274     IDirectSoundFullDuplex_IDirectSound8_QueryInterface,
275     IDirectSoundFullDuplex_IDirectSound8_AddRef,
276     IDirectSoundFullDuplex_IDirectSound8_Release,
277     IDirectSoundFullDuplex_IDirectSound8_CreateSoundBuffer,
278     IDirectSoundFullDuplex_IDirectSound8_GetCaps,
279     IDirectSoundFullDuplex_IDirectSound8_DuplicateSoundBuffer,
280     IDirectSoundFullDuplex_IDirectSound8_SetCooperativeLevel,
281     IDirectSoundFullDuplex_IDirectSound8_Compact,
282     IDirectSoundFullDuplex_IDirectSound8_GetSpeakerConfig,
283     IDirectSoundFullDuplex_IDirectSound8_SetSpeakerConfig,
284     IDirectSoundFullDuplex_IDirectSound8_Initialize,
285     IDirectSoundFullDuplex_IDirectSound8_VerifyCertification
286 };
287
288 static HRESULT IDirectSoundFullDuplex_IDirectSound8_Create(
289     LPDIRECTSOUNDFULLDUPLEX pdsfd,
290     LPDIRECTSOUND8 * ppds8)
291 {
292     IDirectSoundFullDuplex_IDirectSound8 * pdsfdds8;
293     TRACE("(%p,%p)\n",pdsfd,ppds8);
294
295     if (pdsfd == NULL) {
296         ERR("invalid parameter: pdsfd == NULL\n");
297         return DSERR_INVALIDPARAM;
298     }
299
300     if (ppds8 == NULL) {
301         ERR("invalid parameter: ppds8 == NULL\n");
302         return DSERR_INVALIDPARAM;
303     }
304
305     if (((IDirectSoundFullDuplexImpl*)pdsfd)->renderer_device == NULL) {
306         WARN("not initialized\n");
307         *ppds8 = NULL;
308         return DSERR_UNINITIALIZED;
309     }
310
311     pdsfdds8 = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsfdds8));
312     if (pdsfdds8 == NULL) {
313         WARN("out of memory\n");
314         *ppds8 = NULL;
315         return DSERR_OUTOFMEMORY;
316     }
317
318     pdsfdds8->lpVtbl = &DirectSoundFullDuplex_DirectSound8_Vtbl;
319     pdsfdds8->ref = 0;
320     pdsfdds8->pdsfd = (IDirectSoundFullDuplexImpl *)pdsfd;
321
322     *ppds8 = (LPDIRECTSOUND8)pdsfdds8;
323
324     return DS_OK;
325 }
326
327 /*******************************************************************************
328  * IDirectSoundFullDuplex_IDirectSoundCapture
329  */
330 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_QueryInterface(
331     LPDIRECTSOUNDCAPTURE iface,
332     REFIID riid,
333     LPVOID * ppobj)
334 {
335     IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
336     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
337     return IDirectSoundFullDuplex_QueryInterface((LPDIRECTSOUNDFULLDUPLEX)This->pdsfd, riid, ppobj);
338 }
339
340 static ULONG WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_AddRef(
341     LPDIRECTSOUNDCAPTURE iface)
342 {
343     IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
344     ULONG ref = InterlockedIncrement(&(This->ref));
345     TRACE("(%p) ref was %d\n", This, ref - 1);
346     return ref;
347 }
348
349 static ULONG WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_Release(
350     LPDIRECTSOUNDCAPTURE iface)
351 {
352     IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
353     ULONG ref = InterlockedDecrement(&(This->ref));
354     TRACE("(%p) ref was %d\n", This, ref + 1);
355     if (!ref) {
356         This->pdsfd->pDSC = NULL;
357         HeapFree(GetProcessHeap(), 0, This);
358         TRACE("(%p) released\n", This);
359     }
360     return ref;
361 }
362
363 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_CreateCaptureBuffer(
364     LPDIRECTSOUNDCAPTURE iface,
365     LPCDSCBUFFERDESC lpcDSCBufferDesc,
366     LPDIRECTSOUNDCAPTUREBUFFER* lplpDSCaptureBuffer,
367     LPUNKNOWN pUnk)
368 {
369     IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
370     TRACE("(%p,%p,%p,%p)\n",This,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
371     return IDirectSoundCapture_CreateCaptureBuffer(This->pdsfd->capture_device,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
372 }
373
374 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_GetCaps(
375     LPDIRECTSOUNDCAPTURE iface,
376     LPDSCCAPS lpDSCCaps)
377 {
378     IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
379     TRACE("(%p,%p)\n",This,lpDSCCaps);
380     return IDirectSoundCapture_GetCaps(This->pdsfd->capture_device, lpDSCCaps);
381 }
382
383 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_Initialize(
384     LPDIRECTSOUNDCAPTURE iface,
385     LPCGUID lpcGUID)
386 {
387     IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
388     TRACE("(%p, %s)\n", This, debugstr_guid(lpcGUID));
389     return IDirectSoundCapture_Initialize(This->pdsfd->capture_device,lpcGUID);
390 }
391
392 static const IDirectSoundCaptureVtbl DirectSoundFullDuplex_DirectSoundCapture_Vtbl =
393 {
394     IDirectSoundFullDuplex_IDirectSoundCapture_QueryInterface,
395     IDirectSoundFullDuplex_IDirectSoundCapture_AddRef,
396     IDirectSoundFullDuplex_IDirectSoundCapture_Release,
397     IDirectSoundFullDuplex_IDirectSoundCapture_CreateCaptureBuffer,
398     IDirectSoundFullDuplex_IDirectSoundCapture_GetCaps,
399     IDirectSoundFullDuplex_IDirectSoundCapture_Initialize
400 };
401
402 static HRESULT IDirectSoundFullDuplex_IDirectSoundCapture_Create(
403     LPDIRECTSOUNDFULLDUPLEX pdsfd,
404     LPDIRECTSOUNDCAPTURE8 * ppdsc8)
405 {
406     IDirectSoundFullDuplex_IDirectSoundCapture * pdsfddsc;
407     TRACE("(%p,%p)\n",pdsfd,ppdsc8);
408
409     if (pdsfd == NULL) {
410         ERR("invalid parameter: pdsfd == NULL\n");
411         return DSERR_INVALIDPARAM;
412     }
413
414     if (ppdsc8 == NULL) {
415         ERR("invalid parameter: ppdsc8 == NULL\n");
416         return DSERR_INVALIDPARAM;
417     }
418
419     if (((IDirectSoundFullDuplexImpl*)pdsfd)->capture_device == NULL) {
420         WARN("not initialized\n");
421         *ppdsc8 = NULL;
422         return DSERR_UNINITIALIZED;
423     }
424
425     pdsfddsc = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsfddsc));
426     if (pdsfddsc == NULL) {
427         WARN("out of memory\n");
428         *ppdsc8 = NULL;
429         return DSERR_OUTOFMEMORY;
430     }
431
432     pdsfddsc->lpVtbl = &DirectSoundFullDuplex_DirectSoundCapture_Vtbl;
433     pdsfddsc->ref = 0;
434     pdsfddsc->pdsfd = (IDirectSoundFullDuplexImpl *)pdsfd;
435
436     *ppdsc8 = (LPDIRECTSOUNDCAPTURE)pdsfddsc;
437
438     return DS_OK;
439 }
440
441 /***************************************************************************
442  * IDirectSoundFullDuplexImpl
443  */
444 static ULONG WINAPI
445 IDirectSoundFullDuplexImpl_AddRef( LPDIRECTSOUNDFULLDUPLEX iface )
446 {
447     IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
448     ULONG ref = InterlockedIncrement(&(This->ref));
449     TRACE("(%p) ref was %d\n", This, ref - 1);
450     return ref;
451 }
452
453 static HRESULT WINAPI
454 IDirectSoundFullDuplexImpl_QueryInterface(
455     LPDIRECTSOUNDFULLDUPLEX iface,
456     REFIID riid,
457     LPVOID* ppobj )
458 {
459     IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
460     TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
461
462     if (ppobj == NULL) {
463         WARN("invalid parameter\n");
464         return E_INVALIDARG;
465     }
466
467     *ppobj = NULL;
468
469     if (IsEqualIID(riid, &IID_IUnknown)) {
470         if (!This->pUnknown) {
471             IDirectSoundFullDuplex_IUnknown_Create(iface, &This->pUnknown);
472             if (!This->pUnknown) {
473                 WARN("IDirectSoundFullDuplex_IUnknown_Create() failed\n");
474                 *ppobj = NULL;
475                 return E_NOINTERFACE;
476             }
477         }
478         IDirectSoundFullDuplex_IUnknown_AddRef(This->pUnknown);
479         *ppobj = This->pUnknown;
480         return S_OK;
481     } else if (IsEqualIID(riid, &IID_IDirectSoundFullDuplex)) {
482         IDirectSoundFullDuplexImpl_AddRef(iface);
483         *ppobj = This;
484         return S_OK;
485     } else if (IsEqualIID(riid, &IID_IDirectSound)
486                || IsEqualIID(riid, &IID_IDirectSound8)) {
487         if (!This->pDS8) {
488             IDirectSoundFullDuplex_IDirectSound8_Create(iface, &This->pDS8);
489             if (!This->pDS8) {
490                 WARN("IDirectSoundFullDuplex_IDirectSound8_Create() failed\n");
491                 *ppobj = NULL;
492                 return E_NOINTERFACE;
493             }
494         }
495         IDirectSoundFullDuplex_IDirectSound8_AddRef(This->pDS8);
496         *ppobj = This->pDS8;
497         return S_OK;
498     } else if (IsEqualIID(riid, &IID_IDirectSoundCapture)) {
499         if (!This->pDSC) {
500             IDirectSoundFullDuplex_IDirectSoundCapture_Create(iface, &This->pDSC);
501             if (!This->pDSC) {
502                 WARN("IDirectSoundFullDuplex_IDirectSoundCapture_Create() failed\n");
503                 *ppobj = NULL;
504                 return E_NOINTERFACE;
505             }
506         }
507         IDirectSoundFullDuplex_IDirectSoundCapture_AddRef(This->pDSC);
508         *ppobj = This->pDSC;
509         return S_OK;
510     }
511
512     return E_NOINTERFACE;
513 }
514
515 static ULONG WINAPI
516 IDirectSoundFullDuplexImpl_Release( LPDIRECTSOUNDFULLDUPLEX iface )
517 {
518     IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
519     ULONG ref = InterlockedDecrement(&(This->ref));
520     TRACE("(%p) ref was %d\n", This, ref - 1);
521
522     if (!ref) {
523         if (This->capture_device)
524             IDirectSoundCapture_Release(This->capture_device);
525         if (This->renderer_device)
526             IDirectSound_Release(This->renderer_device);
527         HeapFree( GetProcessHeap(), 0, This );
528         TRACE("(%p) released\n", This);
529     }
530     return ref;
531 }
532
533 static HRESULT WINAPI
534 IDirectSoundFullDuplexImpl_Initialize(
535     LPDIRECTSOUNDFULLDUPLEX iface,
536     LPCGUID pCaptureGuid,
537     LPCGUID pRendererGuid,
538     LPCDSCBUFFERDESC lpDscBufferDesc,
539     LPCDSBUFFERDESC lpDsBufferDesc,
540     HWND hWnd,
541     DWORD dwLevel,
542     LPLPDIRECTSOUNDCAPTUREBUFFER8 lplpDirectSoundCaptureBuffer8,
543     LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer8 )
544 {
545     HRESULT hr;
546     IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
547
548     TRACE("(%p,%s,%s,%p,%p,%p,%x,%p,%p)\n", This,
549         debugstr_guid(pCaptureGuid), debugstr_guid(pRendererGuid),
550         lpDscBufferDesc, lpDsBufferDesc, hWnd, dwLevel,
551         lplpDirectSoundCaptureBuffer8, lplpDirectSoundBuffer8);
552
553     if (This->renderer_device != NULL || This->capture_device != NULL) {
554         WARN("already initialized\n");
555         *lplpDirectSoundCaptureBuffer8 = NULL;
556         *lplpDirectSoundBuffer8 = NULL;
557         return DSERR_ALREADYINITIALIZED;
558     }
559
560     hr = DSOUND_Create8(&IID_IDirectSound8, &This->renderer_device);
561     if (SUCCEEDED(hr))
562         hr = IDirectSound_Initialize(This->renderer_device, pRendererGuid);
563     if (hr != DS_OK) {
564         WARN("DirectSoundDevice_Initialize() failed\n");
565         *lplpDirectSoundCaptureBuffer8 = NULL;
566         *lplpDirectSoundBuffer8 = NULL;
567         return hr;
568     }
569
570     IDirectSound8_SetCooperativeLevel(This->renderer_device, hWnd, dwLevel);
571
572     hr = IDirectSound8_CreateSoundBuffer(This->renderer_device, lpDsBufferDesc,
573         (IDirectSoundBuffer**)lplpDirectSoundBuffer8, NULL);
574     if (hr != DS_OK) {
575         WARN("IDirectSoundBufferImpl_Create() failed\n");
576         *lplpDirectSoundCaptureBuffer8 = NULL;
577         *lplpDirectSoundBuffer8 = NULL;
578         return hr;
579     }
580
581     hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture8, &This->capture_device);
582     if (SUCCEEDED(hr))
583         hr = IDirectSoundCapture_Initialize(This->capture_device, pCaptureGuid);
584     if (hr != DS_OK) {
585         WARN("DirectSoundCaptureDevice_Initialize() failed\n");
586         *lplpDirectSoundCaptureBuffer8 = NULL;
587         *lplpDirectSoundBuffer8 = NULL;
588         return hr;
589     }
590
591     hr = IDirectSoundCapture_CreateCaptureBuffer(This->capture_device,
592         lpDscBufferDesc,
593         (IDirectSoundCaptureBuffer**)lplpDirectSoundCaptureBuffer8,
594         NULL);
595     if (hr != DS_OK) {
596         WARN("IDirectSoundCaptureBufferImpl_Create() failed\n");
597         *lplpDirectSoundCaptureBuffer8 = NULL;
598         *lplpDirectSoundBuffer8 = NULL;
599         return hr;
600     }
601
602     return hr;
603 }
604
605 static const IDirectSoundFullDuplexVtbl dsfdvt =
606 {
607     /* IUnknown methods */
608     IDirectSoundFullDuplexImpl_QueryInterface,
609     IDirectSoundFullDuplexImpl_AddRef,
610     IDirectSoundFullDuplexImpl_Release,
611
612     /* IDirectSoundFullDuplex methods */
613     IDirectSoundFullDuplexImpl_Initialize
614 };
615
616 HRESULT DSOUND_FullDuplexCreate(
617     REFIID riid,
618     LPDIRECTSOUNDFULLDUPLEX* ppDSFD)
619 {
620     IDirectSoundFullDuplexImpl *This = NULL;
621     TRACE("(%s, %p)\n", debugstr_guid(riid), ppDSFD);
622
623     if (ppDSFD == NULL) {
624         WARN("invalid parameter: ppDSFD == NULL\n");
625         return DSERR_INVALIDPARAM;
626     }
627
628     if (!IsEqualIID(riid, &IID_IUnknown) &&
629         !IsEqualIID(riid, &IID_IDirectSoundFullDuplex)) {
630         *ppDSFD = 0;
631         return E_NOINTERFACE;
632     }
633
634     /* Get dsound configuration */
635     setup_dsound_options();
636
637     This = HeapAlloc(GetProcessHeap(),
638         HEAP_ZERO_MEMORY, sizeof(IDirectSoundFullDuplexImpl));
639
640     if (This == NULL) {
641         WARN("out of memory\n");
642         *ppDSFD = NULL;
643         return DSERR_OUTOFMEMORY;
644     }
645
646     This->lpVtbl = &dsfdvt;
647     This->ref = 1;
648     This->capture_device = NULL;
649     This->renderer_device = NULL;
650
651     *ppDSFD = (LPDIRECTSOUNDFULLDUPLEX)This;
652
653     return DS_OK;
654 }
655
656 /***************************************************************************
657  * DirectSoundFullDuplexCreate [DSOUND.10]
658  *
659  * Create and initialize a DirectSoundFullDuplex interface.
660  *
661  * PARAMS
662  *    pcGuidCaptureDevice [I] Address of sound capture device GUID.
663  *    pcGuidRenderDevice  [I] Address of sound render device GUID.
664  *    pcDSCBufferDesc     [I] Address of capture buffer description.
665  *    pcDSBufferDesc      [I] Address of  render buffer description.
666  *    hWnd                [I] Handle to application window.
667  *    dwLevel             [I] Cooperative level.
668  *    ppDSFD              [O] Address where full duplex interface returned.
669  *    ppDSCBuffer8        [0] Address where capture buffer interface returned.
670  *    ppDSBuffer8         [0] Address where render buffer interface returned.
671  *    pUnkOuter           [I] Must be NULL.
672  *
673  * RETURNS
674  *    Success: DS_OK
675  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
676  *             DSERR_OUTOFMEMORY DSERR_INVALIDCALL DSERR_NODRIVER
677  */
678 HRESULT WINAPI
679 DirectSoundFullDuplexCreate(
680     LPCGUID pcGuidCaptureDevice,
681     LPCGUID pcGuidRenderDevice,
682     LPCDSCBUFFERDESC pcDSCBufferDesc,
683     LPCDSBUFFERDESC pcDSBufferDesc,
684     HWND hWnd,
685     DWORD dwLevel,
686     LPDIRECTSOUNDFULLDUPLEX *ppDSFD,
687     LPDIRECTSOUNDCAPTUREBUFFER8 *ppDSCBuffer8,
688     LPDIRECTSOUNDBUFFER8 *ppDSBuffer8,
689     LPUNKNOWN pUnkOuter)
690 {
691     HRESULT hres;
692     IDirectSoundFullDuplexImpl *This = NULL;
693     TRACE("(%s,%s,%p,%p,%p,%x,%p,%p,%p,%p)\n",
694         debugstr_guid(pcGuidCaptureDevice), debugstr_guid(pcGuidRenderDevice),
695         pcDSCBufferDesc, pcDSBufferDesc, hWnd, dwLevel, ppDSFD, ppDSCBuffer8,
696         ppDSBuffer8, pUnkOuter);
697
698     if (pUnkOuter) {
699         WARN("pUnkOuter != 0\n");
700         *ppDSFD = NULL;
701         return DSERR_NOAGGREGATION;
702     }
703
704     if (pcDSCBufferDesc == NULL) {
705         WARN("invalid parameter: pcDSCBufferDesc == NULL\n");
706         *ppDSFD = NULL;
707         return DSERR_INVALIDPARAM;
708     }
709
710     if (pcDSBufferDesc == NULL) {
711         WARN("invalid parameter: pcDSBufferDesc == NULL\n");
712         *ppDSFD = NULL;
713         return DSERR_INVALIDPARAM;
714     }
715
716     if (ppDSFD == NULL) {
717         WARN("invalid parameter: ppDSFD == NULL\n");
718         return DSERR_INVALIDPARAM;
719     }
720
721     if (ppDSCBuffer8 == NULL) {
722         WARN("invalid parameter: ppDSCBuffer8 == NULL\n");
723         *ppDSFD = NULL;
724         return DSERR_INVALIDPARAM;
725     }
726
727     if (ppDSBuffer8 == NULL) {
728         WARN("invalid parameter: ppDSBuffer8 == NULL\n");
729         *ppDSFD = NULL;
730         return DSERR_INVALIDPARAM;
731     }
732
733     hres = DSOUND_FullDuplexCreate(&IID_IDirectSoundFullDuplex, (LPDIRECTSOUNDFULLDUPLEX*)&This);
734     if (FAILED(hres)) return hres;
735
736     hres = IDirectSoundFullDuplexImpl_Initialize((LPDIRECTSOUNDFULLDUPLEX)This,
737                                                  pcGuidCaptureDevice,
738                                                  pcGuidRenderDevice,
739                                                  pcDSCBufferDesc,
740                                                  pcDSBufferDesc,
741                                                  hWnd, dwLevel, ppDSCBuffer8,
742                                                  ppDSBuffer8);
743     if (hres != DS_OK) {
744         IUnknown_Release((LPDIRECTSOUNDFULLDUPLEX)This);
745         WARN("IDirectSoundFullDuplexImpl_Initialize failed\n");
746         *ppDSFD = NULL;
747     } else
748         *ppDSFD = (LPDIRECTSOUNDFULLDUPLEX)This;
749
750     return hres;
751 }