Fix subclassing to support nested messages.
[wine] / dlls / dsound / capture.c
1 /*              DirectSoundCapture
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998 Rob Riggs
5  * Copyright 2000-2001 TransGaming Technologies, Inc.
6  *
7  * This library 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 library 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 library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 /*
22  * TODO:
23  *      Implement DirectSoundFullDuplex support.
24  *      Implement FX support.
25  */
26
27 #include "config.h"
28 #include <assert.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <sys/types.h>
32 #include <sys/fcntl.h>
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include "windef.h"
40 #include "winbase.h"
41 #include "wingdi.h"
42 #include "winuser.h"
43 #include "winerror.h"
44 #include "mmsystem.h"
45 #include "mmddk.h"
46 #include "winreg.h"
47 #include "winternl.h"
48 #include "winnls.h"
49 #include "wine/debug.h"
50 #include "dsound.h"
51 #include "dsdriver.h"
52 #include "dsound_private.h"
53
54 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
55
56 static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(
57     LPDIRECTSOUNDCAPTURE iface,
58     LPCGUID lpcGUID );
59 static ULONG WINAPI IDirectSoundCaptureImpl_Release( 
60     LPDIRECTSOUNDCAPTURE iface );
61 static ULONG WINAPI IDirectSoundCaptureBufferImpl_Release( 
62     LPDIRECTSOUNDCAPTUREBUFFER8 iface );
63 static HRESULT DSOUND_CreateDirectSoundCaptureBuffer(
64     IDirectSoundCaptureImpl *ipDSC, 
65     LPCDSCBUFFERDESC lpcDSCBufferDesc, 
66     LPVOID* ppobj );
67 static HRESULT WINAPI IDirectSoundFullDuplexImpl_Initialize(
68     LPDIRECTSOUNDFULLDUPLEX iface,
69     LPCGUID pCaptureGuid,
70     LPCGUID pRendererGuid,
71     LPCDSCBUFFERDESC lpDscBufferDesc,
72     LPCDSBUFFERDESC lpDsBufferDesc,
73     HWND hWnd,
74     DWORD dwLevel,
75     LPLPDIRECTSOUNDCAPTUREBUFFER8 lplpDirectSoundCaptureBuffer8,
76     LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer8 );
77
78 static ICOM_VTABLE(IDirectSoundCapture) dscvt;
79 static ICOM_VTABLE(IDirectSoundCaptureBuffer8) dscbvt;
80 static ICOM_VTABLE(IDirectSoundFullDuplex) dsfdvt;
81
82 static IDirectSoundCaptureImpl*       dsound_capture = NULL;
83
84 static const char * captureStateString[] = {
85     "STATE_STOPPED",
86     "STATE_STARTING",
87     "STATE_CAPTURING",
88     "STATE_STOPPING"
89 };
90
91 /***************************************************************************
92  * DirectSoundCaptureCreate [DSOUND.6]
93  *
94  * Create and initialize a DirectSoundCapture interface.
95  *
96  * PARAMS
97  *    lpcGUID   [I] Address of the GUID that identifies the sound capture device.
98  *    lplpDSC   [O] Address of a variable to receive the interface pointer.
99  *    pUnkOuter [I] Must be NULL.
100  *
101  * RETURNS
102  *    Success: DS_OK
103  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
104  *             DSERR_OUTOFMEMORY
105  *
106  * NOTES
107  *    lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
108  *    or NULL for the default device or DSDEVID_DefaultCapture or 
109  *    DSDEVID_DefaultVoiceCapture.
110  *
111  *    DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
112  */
113 HRESULT WINAPI 
114 DirectSoundCaptureCreate8(
115     LPCGUID lpcGUID,
116     LPDIRECTSOUNDCAPTURE* lplpDSC,
117     LPUNKNOWN pUnkOuter )
118 {
119     IDirectSoundCaptureImpl** ippDSC=(IDirectSoundCaptureImpl**)lplpDSC;
120     TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), lplpDSC, pUnkOuter);
121
122     if ( pUnkOuter ) {
123         WARN("invalid parameter: pUnkOuter != NULL\n");
124         return DSERR_NOAGGREGATION;
125     }
126
127     if ( !lplpDSC ) {
128         WARN("invalid parameter: lplpDSC == NULL\n");
129         return DSERR_INVALIDPARAM;
130     }
131
132     /* Default device? */
133     if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) ) 
134         lpcGUID = &DSDEVID_DefaultCapture;
135
136     *ippDSC = (IDirectSoundCaptureImpl*)HeapAlloc(GetProcessHeap(),
137         HEAP_ZERO_MEMORY, sizeof(IDirectSoundCaptureImpl));
138
139     if (*ippDSC == NULL) {
140         WARN("out of memory\n");
141         return DSERR_OUTOFMEMORY;
142     } else {
143         ICOM_THIS(IDirectSoundCaptureImpl, *ippDSC);
144
145         This->ref = 1;
146         This->state = STATE_STOPPED;
147
148         InitializeCriticalSection( &(This->lock) );
149
150         This->lpVtbl = &dscvt;
151         dsound_capture = This;
152
153         if (GetDeviceID(lpcGUID, &This->guid) == DS_OK) {
154             HRESULT     hres; 
155             hres = IDirectSoundCaptureImpl_Initialize( (LPDIRECTSOUNDCAPTURE)This, &This->guid);
156             if (hres != DS_OK)
157                 WARN("IDirectSoundCaptureImpl_Initialize failed\n");
158             return hres;
159         }
160     }
161     WARN("invalid GUID: %s\n", debugstr_guid(lpcGUID));
162     return DSERR_INVALIDPARAM;
163 }
164
165 /***************************************************************************
166  * DirectSoundCaptureEnumerateA [DSOUND.7]
167  *
168  * Enumerate all DirectSound drivers installed in the system.
169  *
170  * PARAMS
171  *    lpDSEnumCallback  [I] Address of callback function.
172  *    lpContext         [I] Address of user defined context passed to callback function.
173  *
174  * RETURNS
175  *    Success: DS_OK
176  *    Failure: DSERR_INVALIDPARAM
177  */
178 HRESULT WINAPI 
179 DirectSoundCaptureEnumerateA(
180     LPDSENUMCALLBACKA lpDSEnumCallback,
181     LPVOID lpContext)
182 {
183     unsigned devs, wid;
184     DSDRIVERDESC desc;
185     GUID guid;
186     int err;
187
188     TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext );
189
190     if (lpDSEnumCallback == NULL) {
191         WARN("invalid parameter: lpDSEnumCallback == NULL\n");
192         return DSERR_INVALIDPARAM;
193     }
194
195     devs = waveInGetNumDevs();
196     if (devs > 0) {
197         if (GetDeviceID(&DSDEVID_DefaultCapture, &guid) == DS_OK) {
198             GUID temp;
199             for (wid = 0; wid < devs; ++wid) {
200                 err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDGUID,(DWORD)&temp,0));
201                 if (err == DS_OK) {
202                     if (IsEqualGUID( &guid, &temp ) ) {
203                         err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0));
204                         if (err == DS_OK) {
205                             TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n",
206                                 "Primary Sound Capture Driver",desc.szDrvName,lpContext);
207                             if (lpDSEnumCallback(NULL, "Primary Sound Capture Driver", desc.szDrvName, lpContext) == FALSE)
208                                 return DS_OK;
209                         }
210                     }
211                 }
212             }
213         }
214     }
215
216     for (wid = 0; wid < devs; ++wid) {
217         err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0));
218         if (err == DS_OK) {
219             err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDGUID,(DWORD)&guid,0));
220             if (err == DS_OK) {
221                 TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
222                     debugstr_guid(&guid),desc.szDesc,desc.szDrvName,lpContext);
223                 if (lpDSEnumCallback(&guid, desc.szDesc, desc.szDrvName, lpContext) == FALSE)
224                     return DS_OK;
225             }
226         } 
227     }
228
229     return DS_OK;
230 }
231
232 /***************************************************************************
233  * DirectSoundCaptureEnumerateW [DSOUND.8]
234  *
235  * Enumerate all DirectSound drivers installed in the system.
236  *
237  * PARAMS
238  *    lpDSEnumCallback  [I] Address of callback function.
239  *    lpContext         [I] Address of user defined context passed to callback function.
240  *
241  * RETURNS
242  *    Success: DS_OK
243  *    Failure: DSERR_INVALIDPARAM
244  */
245 HRESULT WINAPI 
246 DirectSoundCaptureEnumerateW(
247     LPDSENUMCALLBACKW lpDSEnumCallback,
248     LPVOID lpContext)
249 {
250     unsigned devs, wid;
251     DSDRIVERDESC desc;
252     GUID guid;
253     int err;
254     WCHAR wDesc[MAXPNAMELEN];
255     WCHAR wName[MAXPNAMELEN];
256
257     TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext );
258
259     if (lpDSEnumCallback == NULL) {
260         WARN("invalid parameter: lpDSEnumCallback == NULL\n");
261         return DSERR_INVALIDPARAM;
262     }
263
264     devs = waveInGetNumDevs();
265     if (devs > 0) {
266         if (GetDeviceID(&DSDEVID_DefaultCapture, &guid) == DS_OK) {
267             GUID temp;
268             for (wid = 0; wid < devs; ++wid) {
269                 err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDGUID,(DWORD)&temp,0));
270                 if (err == DS_OK) {
271                     if (IsEqualGUID( &guid, &temp ) ) {
272                         err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0));
273                         if (err == DS_OK) {
274                             TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n",
275                                 "Primary Sound Capture Driver",desc.szDrvName,lpContext);
276                             MultiByteToWideChar( CP_ACP, 0, "Primary Sound Capture Driver", -1, 
277                                 wDesc, sizeof(wDesc)/sizeof(WCHAR) );
278                             MultiByteToWideChar( CP_ACP, 0, desc.szDrvName, -1, 
279                                 wName, sizeof(wName)/sizeof(WCHAR) );
280                             if (lpDSEnumCallback(NULL, wDesc, wName, lpContext) == FALSE)
281                                 return DS_OK;
282                         }
283                     }
284                 }
285             }
286         }
287     }
288
289     for (wid = 0; wid < devs; ++wid) {
290         err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0));
291         if (err == DS_OK) {
292             err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDGUID,(DWORD)&guid,0));
293             if (err == DS_OK) {
294                 TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
295                     debugstr_guid(&DSDEVID_DefaultCapture),desc.szDesc,desc.szDrvName,lpContext);
296                 MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, 
297                     wDesc, sizeof(wDesc)/sizeof(WCHAR) );
298                 MultiByteToWideChar( CP_ACP, 0, desc.szDrvName, -1, 
299                     wName, sizeof(wName)/sizeof(WCHAR) );
300                 if (lpDSEnumCallback((LPGUID)&DSDEVID_DefaultCapture, wDesc, wName, lpContext) == FALSE)
301                     return DS_OK;
302             }
303         } 
304     }
305
306     return DS_OK;
307 }
308
309 static void CALLBACK 
310 DSOUND_capture_callback(
311     HWAVEIN hwi, 
312     UINT msg, 
313     DWORD dwUser, 
314     DWORD dw1, 
315     DWORD dw2 )
316 {
317     IDirectSoundCaptureImpl* This = (IDirectSoundCaptureImpl*)dwUser;
318     TRACE("(%p,%08x(%s),%08lx,%08lx,%08lx) entering at %ld\n",hwi,msg,
319         msg == MM_WIM_OPEN ? "MM_WIM_OPEN" : msg == MM_WIM_CLOSE ? "MM_WIM_CLOSE" :
320         msg == MM_WIM_DATA ? "MM_WIM_DATA" : "UNKNOWN",dwUser,dw1,dw2,GetTickCount());
321
322     if (msg == MM_WIM_DATA) {
323         EnterCriticalSection( &(This->lock) );
324         TRACE("DirectSoundCapture msg=MM_WIM_DATA, old This->state=%s, old This->index=%d\n",
325             captureStateString[This->state],This->index);
326         if (This->state != STATE_STOPPED) {
327             int index = This->index;
328             if (This->state == STATE_STARTING) { 
329                 MMTIME mtime;
330                 mtime.wType = TIME_BYTES;
331                 waveInGetPosition(This->hwi, &mtime, sizeof(mtime));
332                 TRACE("mtime.u.cb=%ld,This->buflen=%ld\n", mtime.u.cb, This->buflen);
333                 mtime.u.cb = mtime.u.cb % This->buflen;
334                 This->read_position = mtime.u.cb;
335                 This->state = STATE_CAPTURING;
336             }
337             waveInUnprepareHeader(hwi,&(This->pwave[This->index]),sizeof(WAVEHDR));
338             if (This->capture_buffer->nrofnotifies)
339                 SetEvent(This->capture_buffer->notifies[This->index].hEventNotify);
340             This->index = (This->index + 1) % This->nrofpwaves;
341             if ( (This->index == 0) && !(This->capture_buffer->flags & DSCBSTART_LOOPING) ) {
342                 TRACE("end of buffer\n");
343                 This->state = STATE_STOPPED;
344             } else {
345                 if (This->state == STATE_CAPTURING) {
346                     waveInPrepareHeader(hwi,&(This->pwave[index]),sizeof(WAVEHDR));
347                     waveInAddBuffer(hwi, &(This->pwave[index]), sizeof(WAVEHDR));
348                 } else if (This->state == STATE_STOPPING) {
349                     TRACE("stopping\n");
350                     This->state = STATE_STOPPED;
351                 }
352             }
353         }
354         TRACE("DirectSoundCapture new This->state=%s, new This->index=%d\n",
355             captureStateString[This->state],This->index);
356         LeaveCriticalSection( &(This->lock) );
357     }
358
359     TRACE("completed\n");
360 }
361
362 static HRESULT WINAPI
363 IDirectSoundCaptureImpl_QueryInterface(
364     LPDIRECTSOUNDCAPTURE iface,
365     REFIID riid,
366     LPVOID* ppobj )
367 {
368     ICOM_THIS(IDirectSoundCaptureImpl,iface);
369     TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
370
371     if (ppobj == NULL) {
372         WARN("invalid parameter\n");
373         return E_INVALIDARG;
374     }
375
376     *ppobj = NULL;
377
378     if (This->driver) {
379         HRESULT hres; 
380         hres = IDsCaptureDriver_QueryInterface(This->driver, riid, ppobj);
381         if (hres != DS_OK)
382             WARN("IDsCaptureDriver_QueryInterface failed\n");
383         return hres;
384     }
385
386     WARN("unsupported riid: %s\n", debugstr_guid(riid));
387     return E_FAIL;
388 }
389
390 static ULONG WINAPI
391 IDirectSoundCaptureImpl_AddRef( LPDIRECTSOUNDCAPTURE iface )
392 {
393     ULONG uRef;
394     ICOM_THIS(IDirectSoundCaptureImpl,iface);
395     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
396
397     EnterCriticalSection( &(This->lock) );
398     uRef = ++(This->ref);
399
400     if (This->driver) 
401         IDsCaptureDriver_AddRef(This->driver);
402
403     LeaveCriticalSection( &(This->lock) );
404
405     return uRef;
406 }
407
408 static ULONG WINAPI
409 IDirectSoundCaptureImpl_Release( LPDIRECTSOUNDCAPTURE iface )
410 {
411     ULONG uRef;
412     ICOM_THIS(IDirectSoundCaptureImpl,iface);
413     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
414
415     EnterCriticalSection( &(This->lock) );
416
417     uRef = --(This->ref);
418
419     LeaveCriticalSection( &(This->lock) );
420
421     if ( uRef == 0 ) {
422         TRACE("deleting object\n");
423         if (This->driver) { 
424             IDsCaptureDriver_Close(This->driver);
425             IDsCaptureDriver_Release(This->driver);
426         }
427
428         if (This->capture_buffer)
429             IDirectSoundCaptureBufferImpl_Release(
430                 (LPDIRECTSOUNDCAPTUREBUFFER8) This->capture_buffer);
431
432         if (This->pwfx)
433             HeapFree(GetProcessHeap(), 0, This->pwfx);
434
435         DeleteCriticalSection( &(This->lock) );
436         HeapFree( GetProcessHeap(), 0, This );
437         dsound_capture = NULL;
438         TRACE("(%p) released\n",This);
439     }
440
441     return uRef;
442 }
443
444 static HRESULT WINAPI
445 IDirectSoundCaptureImpl_CreateCaptureBuffer(
446     LPDIRECTSOUNDCAPTURE iface,
447     LPCDSCBUFFERDESC lpcDSCBufferDesc,
448     LPDIRECTSOUNDCAPTUREBUFFER* lplpDSCaptureBuffer,
449     LPUNKNOWN pUnk )
450 {
451     HRESULT hr;
452     ICOM_THIS(IDirectSoundCaptureImpl,iface);
453
454     TRACE( "(%p,%p,%p,%p)\n",This,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk );
455
456     if (This == NULL) {
457         WARN("invalid parameter: This == NULL\n");
458         return DSERR_INVALIDPARAM;
459     }
460
461     if (lpcDSCBufferDesc == NULL) {
462         WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
463         return DSERR_INVALIDPARAM;
464     }
465
466     if (lplpDSCaptureBuffer == NULL) {
467         WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
468         return DSERR_INVALIDPARAM;
469     }
470
471     if (pUnk != NULL) {
472         WARN("invalid parameter: pUnk != NULL\n");
473         return DSERR_INVALIDPARAM;
474     }
475
476     /* FIXME: We can only have one buffer so what do we do here? */
477     if (This->capture_buffer) {
478         WARN("lnvalid parameter: already has buffer\n");
479         return DSERR_INVALIDPARAM;    /* DSERR_GENERIC ? */
480     }
481
482     hr = DSOUND_CreateDirectSoundCaptureBuffer( This, lpcDSCBufferDesc, 
483         (LPVOID*)lplpDSCaptureBuffer );
484
485     if (hr != DS_OK)
486         WARN("DSOUND_CreateDirectSoundCaptureBuffer failed\n");
487
488     return hr;
489 }
490
491 static HRESULT WINAPI
492 IDirectSoundCaptureImpl_GetCaps(
493     LPDIRECTSOUNDCAPTURE iface,
494     LPDSCCAPS lpDSCCaps )
495 {
496     ICOM_THIS(IDirectSoundCaptureImpl,iface);
497     TRACE("(%p,%p)\n",This,lpDSCCaps);
498
499     if (lpDSCCaps== NULL) {
500         WARN("invalid parameter: lpDSCCaps== NULL\n");
501         return DSERR_INVALIDPARAM;
502     }
503
504     if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
505         WARN("invalid parameter: lpDSCCaps->dwSize = %ld < %d\n", 
506             lpDSCCaps->dwSize, sizeof(*lpDSCCaps));
507         return DSERR_INVALIDPARAM;
508     }
509
510     if ( !(This->initialized) ) {
511         WARN("not initialized\n");
512         return DSERR_UNINITIALIZED;
513     }
514
515     lpDSCCaps->dwFlags = This->drvcaps.dwFlags;
516     lpDSCCaps->dwFormats = This->drvcaps.dwFormats;
517     lpDSCCaps->dwChannels = This->drvcaps.dwChannels;
518
519     TRACE("(flags=0x%08lx,format=0x%08lx,channels=%ld)\n",lpDSCCaps->dwFlags,
520         lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
521
522     return DS_OK;
523 }
524
525 static HRESULT WINAPI
526 IDirectSoundCaptureImpl_Initialize(
527     LPDIRECTSOUNDCAPTURE iface,
528     LPCGUID lpcGUID )
529 {
530     HRESULT err = DSERR_INVALIDPARAM;
531     unsigned wid, widn;
532     ICOM_THIS(IDirectSoundCaptureImpl,iface);
533     TRACE("(%p)\n", This);
534
535     if (!This) {
536         WARN("invalid parameter: This == NULL\n");
537         return DSERR_INVALIDPARAM;
538     }
539
540     if (This->initialized) {
541         WARN("already initialized\n");
542         return DSERR_ALREADYINITIALIZED;
543     }
544
545     widn = waveInGetNumDevs();
546
547     if (!widn) { 
548         WARN("no audio devices found\n");
549         return DSERR_NODRIVER;
550     }
551
552     /* Get dsound configuration */
553     setup_dsound_options();
554
555     /* enumerate WINMM audio devices and find the one we want */
556     for (wid=0; wid<widn; wid++) {
557         GUID guid;
558         err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDGUID,(DWORD)(&guid),0));
559         if (err != DS_OK) {
560             WARN("waveInMessage failed; err=%lx\n",err);
561             return err;
562         }
563         if (IsEqualGUID( lpcGUID, &guid) ) {
564             err = DS_OK;
565             break;
566         }
567     }
568
569     if (err != DS_OK) {
570         WARN("invalid parameter\n");
571         return DSERR_INVALIDPARAM;
572     }
573
574     err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDIFACE,(DWORD)&(This->driver),0));
575     if ( (err != DS_OK) && (err != DSERR_UNSUPPORTED) ) {
576         WARN("waveInMessage failed; err=%lx\n",err);
577         return err;
578     }
579     err = DS_OK;
580
581     /* Disable the direct sound driver to force emulation if requested. */
582     if (ds_hw_accel == DS_HW_ACCEL_EMULATION)
583         This->driver = NULL;
584
585     /* Get driver description */
586     if (This->driver) {
587         TRACE("using DirectSound driver\n");
588         err = IDsCaptureDriver_GetDriverDesc(This->driver, &(This->drvdesc));
589         if (err != DS_OK) {
590             WARN("IDsCaptureDriver_GetDriverDesc failed\n");
591             return err;
592         }
593     } else {
594         TRACE("using WINMM\n");
595         /* if no DirectSound interface available, use WINMM API instead */
596         This->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | 
597             DSDDESC_DOMMSYSTEMSETFORMAT;
598     }
599
600     This->drvdesc.dnDevNode = wid;
601     
602     /* open the DirectSound driver if available */
603     if (This->driver && (err == DS_OK))
604         err = IDsCaptureDriver_Open(This->driver);
605
606     if (err == DS_OK) {
607         This->initialized = TRUE;
608
609         /* the driver is now open, so it's now allowed to call GetCaps */
610         if (This->driver) {
611             This->drvcaps.dwSize = sizeof(This->drvcaps);
612             err = IDsCaptureDriver_GetCaps(This->driver,&(This->drvcaps));
613             if (err != DS_OK) {
614                 WARN("IDsCaptureDriver_GetCaps failed\n");
615                 return err;
616             }
617         } else /*if (This->hwi)*/ {
618             WAVEINCAPSA    wic;
619             err = mmErr(waveInGetDevCapsA((UINT)This->drvdesc.dnDevNode, &wic, sizeof(wic)));
620
621             if (err == DS_OK) {
622                 This->drvcaps.dwFlags = 0;
623                 strncpy(This->drvdesc.szDrvName, wic.szPname, 
624                     sizeof(This->drvdesc.szDrvName)); 
625
626                 This->drvcaps.dwFlags |= DSCCAPS_EMULDRIVER;
627                 This->drvcaps.dwFormats = wic.dwFormats;
628                 This->drvcaps.dwChannels = wic.wChannels;
629             }
630         }
631     }
632
633     return err;
634 }
635
636 static ICOM_VTABLE(IDirectSoundCapture) dscvt =
637 {
638     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
639     /* IUnknown methods */
640     IDirectSoundCaptureImpl_QueryInterface,
641     IDirectSoundCaptureImpl_AddRef,
642     IDirectSoundCaptureImpl_Release,
643
644     /* IDirectSoundCapture methods */
645     IDirectSoundCaptureImpl_CreateCaptureBuffer,
646     IDirectSoundCaptureImpl_GetCaps,
647     IDirectSoundCaptureImpl_Initialize
648 };
649
650 static HRESULT
651 DSOUND_CreateDirectSoundCaptureBuffer(
652     IDirectSoundCaptureImpl *ipDSC, 
653     LPCDSCBUFFERDESC lpcDSCBufferDesc, 
654     LPVOID* ppobj )
655 {
656     LPWAVEFORMATEX  wfex;
657     TRACE( "(%p,%p)\n", lpcDSCBufferDesc, ppobj );
658
659     if (ipDSC == NULL) {
660         WARN("invalid parameter: ipDSC == NULL\n");
661         return DSERR_INVALIDPARAM;
662     }
663
664     if (lpcDSCBufferDesc == NULL) {
665         WARN("invalid parameter: lpcDSCBufferDesc == NULL\n");
666         return DSERR_INVALIDPARAM;
667     }
668
669     if (ppobj == NULL) {
670         WARN("invalid parameter: ppobj == NULL\n");
671         return DSERR_INVALIDPARAM;
672     }
673
674     if ( (lpcDSCBufferDesc->dwSize < sizeof(DSCBUFFERDESC)) || 
675         (lpcDSCBufferDesc->dwBufferBytes == 0) ||
676         (lpcDSCBufferDesc->lpwfxFormat == NULL) ) {
677         WARN("invalid lpcDSCBufferDesc\n");
678         *ppobj = NULL;
679         return DSERR_INVALIDPARAM;
680     }
681
682     if ( !ipDSC->initialized ) {
683         WARN("not initialized\n");
684         *ppobj = NULL;
685         return DSERR_UNINITIALIZED;
686     }
687
688     wfex = lpcDSCBufferDesc->lpwfxFormat;
689
690     if (wfex) {
691         TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
692             "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
693             wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
694             wfex->nAvgBytesPerSec, wfex->nBlockAlign,
695             wfex->wBitsPerSample, wfex->cbSize);
696
697         if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
698             ipDSC->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX));
699             memcpy(ipDSC->pwfx, wfex, sizeof(WAVEFORMATEX));
700             ipDSC->pwfx->cbSize = 0;
701         } else {
702             ipDSC->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX)+wfex->cbSize);
703             memcpy(ipDSC->pwfx, wfex, sizeof(WAVEFORMATEX)+wfex->cbSize);
704         }
705     } else {
706         WARN("lpcDSCBufferDesc->lpwfxFormat == 0\n");
707         *ppobj = NULL;
708         return DSERR_INVALIDPARAM; /* FIXME: DSERR_BADFORMAT ? */
709     }
710
711     *ppobj = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
712         sizeof(IDirectSoundCaptureBufferImpl));
713
714     if ( *ppobj == NULL ) {
715         WARN("out of memory\n");
716         *ppobj = NULL;
717         return DSERR_OUTOFMEMORY;
718     } else {
719         HRESULT err = DS_OK;
720         ICOM_THIS(IDirectSoundCaptureBufferImpl,*ppobj);
721
722         This->ref = 1;
723         This->dsound = ipDSC;
724         This->dsound->capture_buffer = This;
725         This->notify = NULL;
726         This->nrofnotifies = 0;
727         This->hwnotify = NULL;
728
729         This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
730             lpcDSCBufferDesc->dwSize);
731         if (This->pdscbd)     
732             memcpy(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize);
733         else {
734             WARN("no memory\n");
735             This->dsound->capture_buffer = 0;
736             HeapFree( GetProcessHeap(), 0, This );
737             *ppobj = NULL;
738             return DSERR_OUTOFMEMORY; 
739         }
740
741         This->lpVtbl = &dscbvt;
742
743         if (ipDSC->driver) {
744             err = IDsCaptureDriver_CreateCaptureBuffer(ipDSC->driver, 
745                 ipDSC->pwfx,0,0,&(ipDSC->buflen),&(ipDSC->buffer),(LPVOID*)&(ipDSC->hwbuf));
746             if (err != DS_OK) {
747                 WARN("IDsCaptureDriver_CreateCaptureBuffer failed\n");
748                 This->dsound->capture_buffer = 0;
749                 HeapFree( GetProcessHeap(), 0, This );
750                 *ppobj = NULL;
751                 return err;
752             }
753         } else {
754             LPBYTE newbuf;
755             DWORD buflen;
756             DWORD flags = CALLBACK_FUNCTION;
757             if (ds_hw_accel != DS_HW_ACCEL_EMULATION)
758                 flags |= WAVE_DIRECTSOUND;
759             err = mmErr(waveInOpen(&(ipDSC->hwi),
760                 ipDSC->drvdesc.dnDevNode, ipDSC->pwfx,
761                 (DWORD)DSOUND_capture_callback, (DWORD)ipDSC, flags));
762             if (err != DS_OK) {
763                 WARN("waveInOpen failed\n");
764                 This->dsound->capture_buffer = 0;
765                 HeapFree( GetProcessHeap(), 0, This );
766                 *ppobj = NULL;
767                 return err;
768             }
769
770             buflen = lpcDSCBufferDesc->dwBufferBytes;
771             TRACE("desired buflen=%ld, old buffer=%p\n", buflen, ipDSC->buffer);
772             if (ipDSC->buffer)
773                 newbuf = (LPBYTE)HeapReAlloc(GetProcessHeap(),0,ipDSC->buffer,buflen);
774             else
775                 newbuf = (LPBYTE)HeapAlloc(GetProcessHeap(),0,buflen);      
776             if (newbuf == NULL) {
777                 WARN("failed to allocate capture buffer\n");
778                 err = DSERR_OUTOFMEMORY;
779                 /* but the old buffer might still exist and must be re-prepared */
780             } else {
781                 ipDSC->buffer = newbuf;
782                 ipDSC->buflen = buflen;
783             }
784         }
785     }
786
787     TRACE("returning DS_OK\n");
788     return DS_OK;
789 }
790
791 /*******************************************************************************
792  *              IDirectSoundCaptureNotify
793  */
794 static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_QueryInterface(
795     LPDIRECTSOUNDNOTIFY iface,
796     REFIID riid,
797     LPVOID *ppobj)
798 {
799     ICOM_THIS(IDirectSoundCaptureNotifyImpl,iface);
800     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
801
802     if (This->dscb == NULL) {
803         WARN("invalid parameter\n");
804         return E_INVALIDARG;
805     }
806
807     return IDirectSoundCaptureBuffer_QueryInterface((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb, riid, ppobj);
808 }
809
810 static ULONG WINAPI IDirectSoundCaptureNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface)
811 {
812     ICOM_THIS(IDirectSoundCaptureNotifyImpl,iface);
813     DWORD ref;
814
815     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
816
817     ref = InterlockedIncrement(&(This->ref));
818     return ref;
819 }
820
821 static ULONG WINAPI IDirectSoundCaptureNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface)
822 {
823     ICOM_THIS(IDirectSoundCaptureNotifyImpl,iface);
824     DWORD ref;
825
826     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
827
828     ref = InterlockedDecrement(&(This->ref));
829     if (ref == 0) {
830         This->dscb->notify=NULL;
831         IDirectSoundCaptureBuffer_Release((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb);
832         HeapFree(GetProcessHeap(),0,This);
833         TRACE("(%p) released\n",This);
834     }
835     return ref;
836 }
837
838 static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_SetNotificationPositions(
839     LPDIRECTSOUNDNOTIFY iface,
840     DWORD howmuch,
841     LPCDSBPOSITIONNOTIFY notify)
842 {
843     ICOM_THIS(IDirectSoundCaptureNotifyImpl,iface);
844     TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
845
846     if (notify == NULL) {
847         WARN("invalid parameter: notify == NULL\n");
848         return DSERR_INVALIDPARAM;
849     }
850
851     if (TRACE_ON(dsound)) {
852         int     i;
853         for (i=0;i<howmuch;i++)
854             TRACE("notify at %ld to 0x%08lx\n",
855             notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
856     }
857
858     if (This->dscb->hwnotify) {
859         HRESULT hres;
860         hres = IDsDriverNotify_SetNotificationPositions(This->dscb->hwnotify, howmuch, notify);
861         if (hres != DS_OK)
862             WARN("IDsDriverNotify_SetNotificationPositions failed\n");
863         return hres;
864     } else {
865         /* Make an internal copy of the caller-supplied array.
866          * Replace the existing copy if one is already present. */
867         if (This->dscb->notifies)
868             This->dscb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 
869                 This->dscb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
870         else
871             This->dscb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 
872                 howmuch * sizeof(DSBPOSITIONNOTIFY));
873
874         if (This->dscb->notifies == NULL) {
875             WARN("out of memory\n");
876             return DSERR_OUTOFMEMORY;
877         }
878         memcpy(This->dscb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
879         This->dscb->nrofnotifies = howmuch;
880     }
881
882     return S_OK;
883 }
884
885 ICOM_VTABLE(IDirectSoundNotify) dscnvt =
886 {
887     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
888     IDirectSoundCaptureNotifyImpl_QueryInterface,
889     IDirectSoundCaptureNotifyImpl_AddRef,
890     IDirectSoundCaptureNotifyImpl_Release,
891     IDirectSoundCaptureNotifyImpl_SetNotificationPositions,
892 };
893
894 HRESULT WINAPI IDirectSoundCaptureNotifyImpl_Create(
895     IDirectSoundCaptureBufferImpl *dscb,
896     IDirectSoundCaptureNotifyImpl **pdscn)
897 {
898     IDirectSoundCaptureNotifyImpl * dscn;
899     TRACE("(%p,%p)\n",dscb,pdscn);
900
901     dscn = (IDirectSoundCaptureNotifyImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dscn));
902
903     if (dscn == NULL) {
904         WARN("out of memory\n");
905         return DSERR_OUTOFMEMORY;
906     }
907
908     dscn->ref = 0;
909     dscn->lpVtbl = &dscnvt;
910     dscn->dscb = dscb;
911     dscb->notify = dscn;
912     IDirectSoundCaptureBuffer_AddRef((LPDIRECTSOUNDCAPTUREBUFFER)dscb);
913
914     *pdscn = dscn;
915     return DS_OK;
916 }
917
918 /*******************************************************************************
919  *              IDirectSoundCaptureBuffer
920  */
921 static HRESULT WINAPI
922 IDirectSoundCaptureBufferImpl_QueryInterface(
923     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
924     REFIID riid,
925     LPVOID* ppobj )
926 {
927     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
928     HRESULT hres;
929     TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
930
931     if (ppobj == NULL) {
932         WARN("invalid parameter\n");
933         return E_INVALIDARG;
934     }
935
936     *ppobj = NULL;
937
938     if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ||
939          IsEqualGUID( &IID_IDirectSoundNotify8, riid ) ) {
940         if (!This->notify)
941             hres = IDirectSoundCaptureNotifyImpl_Create(This, &This->notify);
942         if (This->notify) {
943             if (This->dsound->hwbuf) {
944                 hres = IDsCaptureDriverBuffer_QueryInterface(This->dsound->hwbuf, 
945                     &IID_IDsDriverNotify, (LPVOID*)&(This->hwnotify));
946                 if (hres != DS_OK) {
947                     WARN("IDsCaptureDriverBuffer_QueryInterface failed\n");
948                     *ppobj = 0;
949                     return hres;
950                 }
951             }
952
953             IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
954             *ppobj = (LPVOID)This->notify;
955             return DS_OK;
956         }
957
958         WARN("IID_IDirectSoundNotify\n");
959         return E_FAIL;
960     }
961
962     if ( IsEqualGUID( &IID_IDirectSoundCaptureBuffer, riid ) ||
963          IsEqualGUID( &IID_IDirectSoundCaptureBuffer8, riid ) ) {
964         IDirectSoundCaptureBuffer8_AddRef(iface);
965         *ppobj = This;
966         return NO_ERROR;
967     }
968
969     FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
970     return E_NOINTERFACE;
971 }
972
973 static ULONG WINAPI
974 IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
975 {
976     ULONG uRef;
977     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
978     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
979
980     assert(This->dsound);
981
982     EnterCriticalSection( &(This->dsound->lock) );
983
984     uRef = ++(This->ref);
985
986     LeaveCriticalSection( &(This->dsound->lock) );
987
988     return uRef;
989 }
990
991 static ULONG WINAPI
992 IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
993 {
994     ULONG uRef;
995     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
996     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
997
998     assert(This->dsound);
999
1000     EnterCriticalSection( &(This->dsound->lock) );
1001
1002     uRef = --(This->ref);
1003
1004     LeaveCriticalSection( &(This->dsound->lock) );
1005
1006     if ( uRef == 0 ) {
1007         TRACE("deleting object\n");
1008         if (This->pdscbd)
1009             HeapFree(GetProcessHeap(),0, This->pdscbd);
1010
1011         if (This->dsound->hwi) {
1012             waveInReset(This->dsound->hwi);
1013             waveInClose(This->dsound->hwi);
1014             if (This->dsound->pwave) {
1015                 HeapFree(GetProcessHeap(),0, This->dsound->pwave);
1016                 This->dsound->pwave = 0;
1017             }
1018             This->dsound->hwi = 0;
1019         }
1020
1021         if (This->dsound->hwbuf) 
1022             IDsCaptureDriverBuffer_Release(This->dsound->hwbuf);
1023
1024         /* remove from IDirectSoundCaptureImpl */
1025         if (This->dsound)
1026             This->dsound->capture_buffer = NULL;
1027         else
1028             ERR("does not reference dsound\n");
1029
1030         if (This->notify)
1031             IDirectSoundNotify_Release((LPDIRECTSOUNDNOTIFY)This->notify);
1032         
1033         if (This->notifies != NULL)
1034                 HeapFree(GetProcessHeap(), 0, This->notifies);
1035
1036         HeapFree( GetProcessHeap(), 0, This );
1037         TRACE("(%p) released\n",This);
1038     }
1039
1040     return uRef;
1041 }
1042
1043 static HRESULT WINAPI
1044 IDirectSoundCaptureBufferImpl_GetCaps(
1045     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1046     LPDSCBCAPS lpDSCBCaps )
1047 {
1048     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1049     TRACE( "(%p,%p)\n", This, lpDSCBCaps );
1050
1051     if (This == NULL) {
1052         WARN("invalid parameter: This == NULL\n");
1053         return DSERR_INVALIDPARAM;
1054     }
1055
1056     if (lpDSCBCaps == NULL) {
1057         WARN("invalid parameter: lpDSCBCaps == NULL\n");
1058         return DSERR_INVALIDPARAM;
1059     }
1060
1061     if (lpDSCBCaps->dwSize < sizeof(DSCBCAPS)) {
1062         WARN("invalid parameter: lpDSCBCaps->dwSize = %ld < %d\n", 
1063             lpDSCBCaps->dwSize, sizeof(DSCBCAPS));
1064         return DSERR_INVALIDPARAM;
1065     }
1066
1067     if (This->dsound == NULL) {
1068         WARN("invalid parameter: This->dsound == NULL\n");
1069         return DSERR_INVALIDPARAM;
1070     }
1071
1072     lpDSCBCaps->dwSize = sizeof(DSCBCAPS);
1073     lpDSCBCaps->dwFlags = This->flags;
1074     lpDSCBCaps->dwBufferBytes = This->pdscbd->dwBufferBytes;
1075     lpDSCBCaps->dwReserved = 0;
1076
1077     TRACE("returning DS_OK\n");
1078     return DS_OK;
1079 }
1080
1081 static HRESULT WINAPI
1082 IDirectSoundCaptureBufferImpl_GetCurrentPosition(
1083     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1084     LPDWORD lpdwCapturePosition,
1085     LPDWORD lpdwReadPosition )
1086 {
1087     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1088     TRACE( "(%p,%p,%p)\n", This, lpdwCapturePosition, lpdwReadPosition );
1089
1090     if (This == NULL) {
1091         WARN("invalid parameter: This == NULL\n");
1092         return DSERR_INVALIDPARAM;
1093     }
1094
1095     if (This->dsound == NULL) {
1096         WARN("invalid parameter: This->dsound == NULL\n");
1097         return DSERR_INVALIDPARAM;
1098     }
1099
1100     if (This->dsound->driver) {
1101         HRESULT hres;
1102         hres = IDsCaptureDriverBuffer_GetPosition(This->dsound->hwbuf, lpdwCapturePosition, lpdwReadPosition );
1103         if (hres != DS_OK) {
1104             WARN("IDsCaptureDriverBuffer_GetPosition failed\n");
1105             return hres;
1106         }
1107     } else if (This->dsound->hwi) {
1108         EnterCriticalSection(&(This->dsound->lock));
1109         TRACE("old This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1110         if (lpdwCapturePosition) {
1111             MMTIME mtime;
1112             mtime.wType = TIME_BYTES;
1113             waveInGetPosition(This->dsound->hwi, &mtime, sizeof(mtime));
1114             TRACE("mtime.u.cb=%ld,This->dsound->buflen=%ld\n", mtime.u.cb, 
1115                 This->dsound->buflen);
1116             mtime.u.cb = mtime.u.cb % This->dsound->buflen;
1117             *lpdwCapturePosition = mtime.u.cb;
1118         }
1119     
1120         if (lpdwReadPosition) {
1121             if (This->dsound->state == STATE_STARTING) { 
1122                 if (lpdwCapturePosition)
1123                     This->dsound->read_position = *lpdwCapturePosition;
1124                 This->dsound->state = STATE_CAPTURING;
1125             } 
1126             *lpdwReadPosition = This->dsound->read_position;
1127         }
1128         TRACE("new This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1129         LeaveCriticalSection(&(This->dsound->lock));
1130         if (lpdwCapturePosition) TRACE("*lpdwCapturePosition=%ld\n",*lpdwCapturePosition);
1131         if (lpdwReadPosition) TRACE("*lpdwReadPosition=%ld\n",*lpdwReadPosition);
1132     } else {
1133         WARN("no driver\n");
1134         return DSERR_NODRIVER;
1135     }
1136     
1137     TRACE("returning DS_OK\n");
1138     return DS_OK;
1139 }
1140
1141 static HRESULT WINAPI
1142 IDirectSoundCaptureBufferImpl_GetFormat(
1143     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1144     LPWAVEFORMATEX lpwfxFormat,
1145     DWORD dwSizeAllocated,
1146     LPDWORD lpdwSizeWritten )
1147 {
1148     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1149     TRACE( "(%p,%p,0x%08lx,%p)\n", This, lpwfxFormat, dwSizeAllocated, 
1150         lpdwSizeWritten );
1151
1152     if (This == NULL) {
1153         WARN("invalid parameter: This == NULL\n");
1154         return DSERR_INVALIDPARAM;
1155     }
1156
1157     if (This->dsound == NULL) {
1158         WARN("invalid parameter: This->dsound == NULL\n");
1159         return DSERR_INVALIDPARAM;
1160     }
1161
1162     if (dwSizeAllocated > (sizeof(WAVEFORMATEX) + This->dsound->pwfx->cbSize))
1163         dwSizeAllocated = sizeof(WAVEFORMATEX) + This->dsound->pwfx->cbSize;
1164
1165     if (lpwfxFormat) { /* NULL is valid (just want size) */
1166         memcpy(lpwfxFormat, This->dsound->pwfx, dwSizeAllocated);
1167         if (lpdwSizeWritten)
1168             *lpdwSizeWritten = dwSizeAllocated;
1169     } else {
1170         if (lpdwSizeWritten)
1171             *lpdwSizeWritten = sizeof(WAVEFORMATEX) + This->dsound->pwfx->cbSize;
1172         else {
1173             TRACE("invalid parameter: lpdwSizeWritten = NULL\n");
1174             return DSERR_INVALIDPARAM;
1175         }
1176     }
1177
1178     TRACE("returning DS_OK\n");
1179     return DS_OK;
1180 }
1181
1182 static HRESULT WINAPI
1183 IDirectSoundCaptureBufferImpl_GetStatus(
1184     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1185     LPDWORD lpdwStatus )
1186 {
1187     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1188     TRACE( "(%p, %p), thread is %04lx\n", This, lpdwStatus, GetCurrentThreadId() );
1189
1190     if (This == NULL) {
1191         WARN("invalid parameter: This == NULL\n");
1192         return DSERR_INVALIDPARAM;
1193     }
1194
1195     if (This->dsound == NULL) {
1196         WARN("invalid parameter: This->dsound == NULL\n");
1197         return DSERR_INVALIDPARAM;
1198     }
1199
1200     if (lpdwStatus == NULL) {
1201         WARN("invalid parameter: lpdwStatus == NULL\n");
1202         return DSERR_INVALIDPARAM;
1203     }
1204
1205     *lpdwStatus = 0;
1206     EnterCriticalSection(&(This->dsound->lock));
1207
1208     TRACE("old This->dsound->state=%s, old lpdwStatus=%08lx\n",
1209         captureStateString[This->dsound->state],*lpdwStatus);
1210     if ((This->dsound->state == STATE_STARTING) || 
1211         (This->dsound->state == STATE_CAPTURING)) {
1212         *lpdwStatus |= DSCBSTATUS_CAPTURING;
1213         if (This->flags & DSCBSTART_LOOPING)
1214             *lpdwStatus |= DSCBSTATUS_LOOPING;
1215     }
1216     TRACE("new This->dsound->state=%s, new lpdwStatus=%08lx\n",
1217         captureStateString[This->dsound->state],*lpdwStatus);
1218     LeaveCriticalSection(&(This->dsound->lock));
1219
1220     TRACE("status=%lx\n", *lpdwStatus);
1221     TRACE("returning DS_OK\n");
1222     return DS_OK;
1223 }
1224
1225 static HRESULT WINAPI
1226 IDirectSoundCaptureBufferImpl_Initialize(
1227     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1228     LPDIRECTSOUNDCAPTURE lpDSC,
1229     LPCDSCBUFFERDESC lpcDSCBDesc )
1230 {
1231     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1232
1233     FIXME( "(%p,%p,%p): stub\n", This, lpDSC, lpcDSCBDesc );
1234
1235     return DS_OK;
1236 }
1237
1238 static HRESULT WINAPI
1239 IDirectSoundCaptureBufferImpl_Lock(
1240     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1241     DWORD dwReadCusor,
1242     DWORD dwReadBytes,
1243     LPVOID* lplpvAudioPtr1,
1244     LPDWORD lpdwAudioBytes1,
1245     LPVOID* lplpvAudioPtr2,
1246     LPDWORD lpdwAudioBytes2,
1247     DWORD dwFlags )
1248 {
1249     HRESULT err = DS_OK;
1250     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1251     TRACE( "(%p,%08lu,%08lu,%p,%p,%p,%p,0x%08lx) at %ld\n", This, dwReadCusor,
1252         dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2,
1253         lpdwAudioBytes2, dwFlags, GetTickCount() );
1254
1255     if (This == NULL) {
1256         WARN("invalid parameter: This == NULL\n");
1257         return DSERR_INVALIDPARAM;
1258     }
1259
1260     if (This->dsound == NULL) {
1261         WARN("invalid parameter: This->dsound == NULL\n");
1262         return DSERR_INVALIDPARAM;
1263     }
1264
1265     if (lplpvAudioPtr1 == NULL) {
1266         WARN("invalid parameter: lplpvAudioPtr1 == NULL\n");
1267         return DSERR_INVALIDPARAM;
1268     }
1269
1270     if (lpdwAudioBytes1 == NULL) {
1271         WARN("invalid parameter: lpdwAudioBytes1 == NULL\n");
1272         return DSERR_INVALIDPARAM;
1273     }
1274
1275     EnterCriticalSection(&(This->dsound->lock));
1276
1277     if (This->dsound->driver) {
1278         err = IDsCaptureDriverBuffer_Lock(This->dsound->hwbuf, lplpvAudioPtr1, 
1279                                            lpdwAudioBytes1, lplpvAudioPtr2, lpdwAudioBytes2,
1280                                            dwReadCusor, dwReadBytes, dwFlags);
1281         if (err != DS_OK)
1282             WARN("IDsCaptureDriverBuffer_Lock failed\n");
1283     } else if (This->dsound->hwi) {
1284         *lplpvAudioPtr1 = This->dsound->buffer + dwReadCusor;
1285         if ( (dwReadCusor + dwReadBytes) > This->dsound->buflen) {
1286             *lpdwAudioBytes1 = This->dsound->buflen - dwReadCusor;
1287             if (lplpvAudioPtr2)
1288                 *lplpvAudioPtr2 = This->dsound->buffer;
1289             if (lpdwAudioBytes2)
1290                 *lpdwAudioBytes2 = dwReadBytes - *lpdwAudioBytes1;
1291         } else {
1292             *lpdwAudioBytes1 = dwReadBytes;
1293             if (lplpvAudioPtr2)
1294                 *lplpvAudioPtr2 = 0;
1295             if (lpdwAudioBytes2)
1296                 *lpdwAudioBytes2 = 0;
1297         }
1298     } else {
1299         TRACE("invalid call\n");
1300         err = DSERR_INVALIDCALL;   /* DSERR_NODRIVER ? */
1301     }
1302
1303     LeaveCriticalSection(&(This->dsound->lock));
1304
1305     return err;
1306 }
1307
1308 static HRESULT WINAPI
1309 IDirectSoundCaptureBufferImpl_Start(
1310     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1311     DWORD dwFlags )
1312 {
1313     HRESULT err = DS_OK;
1314     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1315     TRACE( "(%p,0x%08lx)\n", This, dwFlags );
1316
1317     if (This == NULL) {
1318         WARN("invalid parameter: This == NULL\n");
1319         return DSERR_INVALIDPARAM;
1320     }
1321
1322     if (This->dsound == NULL) {
1323         WARN("invalid parameter: This->dsound == NULL\n");
1324         return DSERR_INVALIDPARAM;
1325     }
1326
1327     if ( (This->dsound->driver == 0) && (This->dsound->hwi == 0) ) {
1328         WARN("no driver\n");
1329         return DSERR_NODRIVER;
1330     }
1331
1332     EnterCriticalSection(&(This->dsound->lock));
1333
1334     This->flags = dwFlags;
1335     TRACE("old This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1336     if (This->dsound->state == STATE_STOPPED)
1337         This->dsound->state = STATE_STARTING;
1338     else if (This->dsound->state == STATE_STOPPING)
1339         This->dsound->state = STATE_CAPTURING;
1340     TRACE("new This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1341
1342     LeaveCriticalSection(&(This->dsound->lock));
1343
1344     if (This->dsound->driver) {
1345         err = IDsCaptureDriverBuffer_Start(This->dsound->hwbuf, dwFlags);
1346         if (err != DS_OK)
1347             WARN("IDsCaptureDriverBuffer_Start failed\n");
1348         return err;
1349     } else {
1350         IDirectSoundCaptureImpl* ipDSC = This->dsound;
1351
1352         if (ipDSC->buffer) {
1353             if (This->nrofnotifies) {
1354                 unsigned c;
1355
1356                 ipDSC->nrofpwaves = This->nrofnotifies;
1357                 TRACE("nrofnotifies=%d\n", This->nrofnotifies);
1358
1359                 /* prepare headers */
1360                 if (ipDSC->pwave)
1361                     ipDSC->pwave = HeapReAlloc(GetProcessHeap(),0,ipDSC->pwave,
1362                         ipDSC->nrofpwaves*sizeof(WAVEHDR));
1363                 else 
1364                     ipDSC->pwave = HeapAlloc(GetProcessHeap(),0,
1365                         ipDSC->nrofpwaves*sizeof(WAVEHDR));
1366
1367                 for (c = 0; c < ipDSC->nrofpwaves; c++) {
1368                     if (c == 0) {
1369                         ipDSC->pwave[0].lpData = ipDSC->buffer;
1370                         ipDSC->pwave[0].dwBufferLength = 
1371                             This->notifies[0].dwOffset + 1;
1372                     } else {
1373                         ipDSC->pwave[c].lpData = ipDSC->buffer + 
1374                             This->notifies[c-1].dwOffset + 1;
1375                         ipDSC->pwave[c].dwBufferLength = 
1376                             This->notifies[c].dwOffset - 
1377                             This->notifies[c-1].dwOffset;
1378                     }
1379                     ipDSC->pwave[c].dwUser = (DWORD)ipDSC;
1380                     ipDSC->pwave[c].dwFlags = 0;
1381                     ipDSC->pwave[c].dwLoops = 0;
1382                     err = mmErr(waveInPrepareHeader(ipDSC->hwi,
1383                         &(ipDSC->pwave[c]),sizeof(WAVEHDR)));
1384                     if (err != DS_OK) {
1385                         while (c--)
1386                             waveInUnprepareHeader(ipDSC->hwi,
1387                                 &(ipDSC->pwave[c]),sizeof(WAVEHDR));
1388                         break;
1389                     }
1390
1391                     err = mmErr(waveInAddBuffer(ipDSC->hwi, 
1392                         &(ipDSC->pwave[c]), sizeof(WAVEHDR)));
1393                     if (err != DS_OK) {
1394                         while (c--)
1395                             waveInUnprepareHeader(ipDSC->hwi,
1396                                 &(ipDSC->pwave[c]),sizeof(WAVEHDR));
1397                         break;
1398                     }
1399                 }
1400
1401                 memset(ipDSC->buffer, 
1402                     (ipDSC->pwfx->wBitsPerSample == 8) ? 128 : 0, ipDSC->buflen);
1403             } else {
1404                 TRACE("no notifiers specified\n");
1405                 /* no notifiers specified so just create a single default header */
1406                 ipDSC->nrofpwaves = 1;
1407                 if (ipDSC->pwave)
1408                     ipDSC->pwave = HeapReAlloc(GetProcessHeap(),0,ipDSC->pwave,sizeof(WAVEHDR));
1409                 else
1410                     ipDSC->pwave = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEHDR));
1411
1412                 ipDSC->pwave[0].lpData = ipDSC->buffer;
1413                 ipDSC->pwave[0].dwBufferLength = ipDSC->buflen; 
1414                 ipDSC->pwave[0].dwUser = (DWORD)ipDSC;
1415                 ipDSC->pwave[0].dwFlags = 0;
1416                 ipDSC->pwave[0].dwLoops = 0;
1417
1418                 err = mmErr(waveInPrepareHeader(ipDSC->hwi,
1419                     &(ipDSC->pwave[0]),sizeof(WAVEHDR)));
1420                 if (err != DS_OK) {
1421                     WARN("waveInPrepareHeader failed\n");
1422                     waveInUnprepareHeader(ipDSC->hwi,
1423                         &(ipDSC->pwave[0]),sizeof(WAVEHDR));
1424                 }
1425                 err = mmErr(waveInAddBuffer(ipDSC->hwi, 
1426                     &(ipDSC->pwave[0]), sizeof(WAVEHDR)));
1427                 if (err != DS_OK) {
1428                     waveInUnprepareHeader(ipDSC->hwi,
1429                         &(ipDSC->pwave[0]),sizeof(WAVEHDR));
1430                 }
1431             }
1432         }
1433
1434         ipDSC->index = 0;
1435         ipDSC->read_position = 0;
1436
1437         if (err == DS_OK) {
1438             /* start filling the first buffer */
1439             err = mmErr(waveInStart(ipDSC->hwi));
1440         }
1441     }
1442
1443     if (err != DS_OK) {
1444         WARN("calling waveInClose because of error\n");
1445         waveInClose(This->dsound->hwi);
1446         This->dsound->hwi = 0;
1447     }
1448
1449     TRACE("returning %ld\n", err);
1450     return err;
1451 }
1452
1453 static HRESULT WINAPI
1454 IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
1455 {
1456     HRESULT err = DS_OK;
1457     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1458     TRACE( "(%p)\n", This );
1459
1460     if (This == NULL) {
1461         WARN("invalid parameter: This == NULL\n");
1462         return DSERR_INVALIDPARAM;
1463     }
1464
1465     if (This->dsound == NULL) {
1466         WARN("invalid parameter: This->dsound == NULL\n");
1467         return DSERR_INVALIDPARAM;
1468     }
1469
1470     EnterCriticalSection(&(This->dsound->lock));
1471
1472     TRACE("old This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1473     if (This->dsound->state == STATE_CAPTURING)
1474         This->dsound->state = STATE_STOPPING;
1475     else if (This->dsound->state == STATE_STARTING)
1476         This->dsound->state = STATE_STOPPED;
1477     TRACE("new This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1478
1479     LeaveCriticalSection(&(This->dsound->lock));
1480
1481     if (This->dsound->driver) {
1482         err = IDsCaptureDriverBuffer_Stop(This->dsound->hwbuf);
1483         if (err == DSERR_BUFFERLOST) {
1484             /* Wine-only: the driver wants us to reopen the device */
1485             IDsCaptureDriverBuffer_Release(This->dsound->hwbuf);
1486             err = IDsCaptureDriver_CreateCaptureBuffer(This->dsound->driver,
1487                 This->dsound->pwfx,0,0,&(This->dsound->buflen),&(This->dsound->buffer),
1488                 (LPVOID*)&(This->dsound->hwbuf));
1489             if (err != DS_OK) {
1490                 WARN("IDsCaptureDriver_CreateCaptureBuffer failed\n");
1491                 This->dsound->hwbuf = 0;
1492             }
1493         } else if (err != DS_OK) 
1494             WARN("IDsCaptureDriverBuffer_Stop failed\n");
1495     } else if (This->dsound->hwi) {
1496         err = waveInStop(This->dsound->hwi);
1497     } else {
1498         WARN("no driver\n");
1499         err = DSERR_NODRIVER;
1500     }
1501
1502     TRACE( "(%p) returning 0x%08lx\n", This,err);
1503     return err;
1504 }
1505
1506 static HRESULT WINAPI
1507 IDirectSoundCaptureBufferImpl_Unlock(
1508     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1509     LPVOID lpvAudioPtr1,
1510     DWORD dwAudioBytes1,
1511     LPVOID lpvAudioPtr2,
1512     DWORD dwAudioBytes2 )
1513 {
1514     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1515     TRACE( "(%p,%p,%08lu,%p,%08lu)\n", This, lpvAudioPtr1, dwAudioBytes1, 
1516         lpvAudioPtr2, dwAudioBytes2 );
1517
1518     if (This == NULL) {
1519         WARN("invalid parameter: This == NULL\n");
1520         return DSERR_INVALIDPARAM;
1521     }
1522
1523     if (lpvAudioPtr1 == NULL) {
1524         WARN("invalid parameter: lpvAudioPtr1 == NULL\n");
1525         return DSERR_INVALIDPARAM;
1526     }
1527
1528     if (This->dsound->driver) {
1529         HRESULT hres;
1530         hres = IDsCaptureDriverBuffer_Unlock(This->dsound->hwbuf, lpvAudioPtr1, 
1531                                            dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
1532         if (hres != DS_OK)
1533             WARN("IDsCaptureDriverBuffer_Unlock failed\n");
1534         return hres;
1535     } else if (This->dsound->hwi) {
1536         This->dsound->read_position = (This->dsound->read_position + 
1537             (dwAudioBytes1 + dwAudioBytes2)) % This->dsound->buflen;
1538     } else {
1539         WARN("invalid call\n");
1540         return DSERR_INVALIDCALL;
1541     }
1542
1543     return DS_OK;
1544 }
1545
1546 static HRESULT WINAPI
1547 IDirectSoundCaptureBufferImpl_GetObjectInPath(
1548     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1549     REFGUID rguidObject,
1550     DWORD dwIndex,
1551     REFGUID rguidInterface,
1552     LPVOID* ppObject )
1553 {
1554     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1555
1556     FIXME( "(%p,%s,%lu,%s,%p): stub\n", This, debugstr_guid(rguidObject), 
1557         dwIndex, debugstr_guid(rguidInterface), ppObject );
1558
1559     return DS_OK;
1560 }
1561
1562 static HRESULT WINAPI
1563 IDirectSoundCaptureBufferImpl_GetFXStatus(
1564     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1565     DWORD dwFXCount,
1566     LPDWORD pdwFXStatus )
1567 {
1568     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1569
1570     FIXME( "(%p,%lu,%p): stub\n", This, dwFXCount, pdwFXStatus );
1571
1572     return DS_OK;
1573 }
1574
1575 static ICOM_VTABLE(IDirectSoundCaptureBuffer8) dscbvt =
1576 {
1577     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1578     /* IUnknown methods */
1579     IDirectSoundCaptureBufferImpl_QueryInterface,
1580     IDirectSoundCaptureBufferImpl_AddRef,
1581     IDirectSoundCaptureBufferImpl_Release,
1582
1583     /* IDirectSoundCaptureBuffer methods */
1584     IDirectSoundCaptureBufferImpl_GetCaps,
1585     IDirectSoundCaptureBufferImpl_GetCurrentPosition,
1586     IDirectSoundCaptureBufferImpl_GetFormat,
1587     IDirectSoundCaptureBufferImpl_GetStatus,
1588     IDirectSoundCaptureBufferImpl_Initialize,
1589     IDirectSoundCaptureBufferImpl_Lock,
1590     IDirectSoundCaptureBufferImpl_Start,
1591     IDirectSoundCaptureBufferImpl_Stop,
1592     IDirectSoundCaptureBufferImpl_Unlock,
1593
1594     /* IDirectSoundCaptureBuffer methods */
1595     IDirectSoundCaptureBufferImpl_GetObjectInPath,
1596     IDirectSoundCaptureBufferImpl_GetFXStatus
1597 };
1598
1599 /*******************************************************************************
1600  * DirectSoundCapture ClassFactory
1601  */
1602
1603 static HRESULT WINAPI
1604 DSCCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) 
1605 {
1606     ICOM_THIS(IClassFactoryImpl,iface);
1607
1608     FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
1609     return E_NOINTERFACE;
1610 }
1611
1612 static ULONG WINAPI
1613 DSCCF_AddRef(LPCLASSFACTORY iface)
1614 {
1615     ICOM_THIS(IClassFactoryImpl,iface);
1616     TRACE("(%p) ref was %ld\n", This, This->ref);
1617     return ++(This->ref);
1618 }
1619
1620 static ULONG WINAPI 
1621 DSCCF_Release(LPCLASSFACTORY iface)
1622 {
1623     ICOM_THIS(IClassFactoryImpl,iface);
1624     /* static class, won't be  freed */
1625     TRACE("(%p) ref was %ld\n", This, This->ref);
1626     return --(This->ref);
1627 }
1628
1629 static HRESULT WINAPI 
1630 DSCCF_CreateInstance(
1631         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj )
1632 {
1633     ICOM_THIS(IClassFactoryImpl,iface);
1634     TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1635
1636     if (ppobj == NULL) {
1637         WARN("invalid parameter\n");
1638         return E_INVALIDARG;
1639     }
1640
1641     *ppobj = NULL;
1642
1643     if ( IsEqualGUID( &IID_IDirectSoundCapture, riid ) ||
1644          IsEqualGUID( &IID_IDirectSoundCapture8, riid ) ) {
1645         return DirectSoundCaptureCreate8(0,(LPDIRECTSOUNDCAPTURE8*)ppobj,pOuter);
1646     }
1647
1648     WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); 
1649     return E_NOINTERFACE;
1650 }
1651
1652 static HRESULT WINAPI 
1653 DSCCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
1654 {
1655     ICOM_THIS(IClassFactoryImpl,iface);
1656     FIXME("(%p)->(%d),stub!\n",This,dolock);
1657     return S_OK;
1658 }
1659
1660 static ICOM_VTABLE(IClassFactory) DSCCF_Vtbl =
1661 {
1662     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1663     DSCCF_QueryInterface,
1664     DSCCF_AddRef,
1665     DSCCF_Release,
1666     DSCCF_CreateInstance,
1667     DSCCF_LockServer
1668 };
1669
1670 IClassFactoryImpl DSOUND_CAPTURE_CF = { &DSCCF_Vtbl, 1 };
1671
1672 /***************************************************************************
1673  * DirectSoundFullDuplexCreate8 [DSOUND.10]
1674  *
1675  * Create and initialize a DirectSoundFullDuplex interface.
1676  *
1677  * PARAMS
1678  *    pcGuidCaptureDevice [I] Address of sound capture device GUID. 
1679  *    pcGuidRenderDevice  [I] Address of sound render device GUID.
1680  *    pcDSCBufferDesc     [I] Address of capture buffer description.
1681  *    pcDSBufferDesc      [I] Address of  render buffer description.
1682  *    hWnd                [I] Handle to application window.
1683  *    dwLevel             [I] Cooperative level.
1684  *    ppDSFD              [O] Address where full duplex interface returned.
1685  *    ppDSCBuffer8        [0] Address where capture buffer interface returned.
1686  *    ppDSBuffer8         [0] Address where render buffer interface returned.
1687  *    pUnkOuter           [I] Must be NULL.
1688  *
1689  * RETURNS
1690  *    Success: DS_OK
1691  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1692  *             DSERR_OUTOFMEMORY DSERR_INVALIDCALL DSERR_NODRIVER
1693  */
1694 HRESULT WINAPI 
1695 DirectSoundFullDuplexCreate8(
1696     LPCGUID pcGuidCaptureDevice,
1697     LPCGUID pcGuidRenderDevice,
1698     LPCDSCBUFFERDESC pcDSCBufferDesc,
1699     LPCDSBUFFERDESC pcDSBufferDesc,
1700     HWND hWnd,
1701     DWORD dwLevel,
1702     LPDIRECTSOUNDFULLDUPLEX *ppDSFD,
1703     LPDIRECTSOUNDCAPTUREBUFFER8 *ppDSCBuffer8,
1704     LPDIRECTSOUNDBUFFER8 *ppDSBuffer8,
1705     LPUNKNOWN pUnkOuter)
1706 {
1707     IDirectSoundFullDuplexImpl** ippDSFD=(IDirectSoundFullDuplexImpl**)ppDSFD;
1708     TRACE("(%s,%s,%p,%p,%lx,%lx,%p,%p,%p,%p)\n", debugstr_guid(pcGuidCaptureDevice), 
1709         debugstr_guid(pcGuidRenderDevice), pcDSCBufferDesc, pcDSBufferDesc,
1710         (DWORD)hWnd, dwLevel, ppDSFD, ppDSCBuffer8, ppDSBuffer8, pUnkOuter);
1711
1712     if ( pUnkOuter ) {
1713         WARN("pUnkOuter != 0\n");
1714         return DSERR_NOAGGREGATION;
1715     }
1716
1717     *ippDSFD = (IDirectSoundFullDuplexImpl*)HeapAlloc(GetProcessHeap(),
1718         HEAP_ZERO_MEMORY, sizeof(IDirectSoundFullDuplexImpl));
1719
1720     if (*ippDSFD == NULL) {
1721         WARN("out of memory\n");
1722         return DSERR_OUTOFMEMORY;
1723     } else {
1724         HRESULT hres;
1725         ICOM_THIS(IDirectSoundFullDuplexImpl, *ippDSFD);
1726
1727         This->ref = 1;
1728         This->lpVtbl = &dsfdvt;
1729
1730         InitializeCriticalSection( &(This->lock) );
1731
1732         hres = IDirectSoundFullDuplexImpl_Initialize( (LPDIRECTSOUNDFULLDUPLEX)This,
1733                                                       pcGuidCaptureDevice, pcGuidRenderDevice,
1734                                                       pcDSCBufferDesc, pcDSBufferDesc,
1735                                                       hWnd, dwLevel, ppDSCBuffer8, ppDSBuffer8);
1736         if (hres != DS_OK)
1737             WARN("IDirectSoundFullDuplexImpl_Initialize failed\n");
1738         return hres;
1739     }
1740
1741     return DSERR_GENERIC;
1742 }
1743
1744 static HRESULT WINAPI
1745 IDirectSoundFullDuplexImpl_QueryInterface(
1746     LPDIRECTSOUNDFULLDUPLEX iface,
1747     REFIID riid,
1748     LPVOID* ppobj )
1749 {
1750     ICOM_THIS(IDirectSoundFullDuplexImpl,iface);
1751     TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
1752
1753     if (ppobj == NULL) {
1754         WARN("invalid parameter\n");
1755         return E_INVALIDARG;
1756     }
1757
1758     *ppobj = NULL;
1759     return E_NOINTERFACE;
1760 }
1761
1762 static ULONG WINAPI
1763 IDirectSoundFullDuplexImpl_AddRef( LPDIRECTSOUNDFULLDUPLEX iface )
1764 {
1765     ULONG uRef;
1766     ICOM_THIS(IDirectSoundFullDuplexImpl,iface);
1767     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
1768
1769     EnterCriticalSection( &(This->lock) );
1770
1771     uRef = ++(This->ref);
1772
1773     LeaveCriticalSection( &(This->lock) );
1774
1775     return uRef;
1776 }
1777
1778 static ULONG WINAPI
1779 IDirectSoundFullDuplexImpl_Release( LPDIRECTSOUNDFULLDUPLEX iface )
1780 {
1781     ULONG uRef;
1782     ICOM_THIS(IDirectSoundFullDuplexImpl,iface);
1783     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
1784
1785     EnterCriticalSection( &(This->lock) );
1786
1787     uRef = --(This->ref);
1788
1789     LeaveCriticalSection( &(This->lock) );
1790
1791     if ( uRef == 0 ) {
1792         DeleteCriticalSection( &(This->lock) );
1793         HeapFree( GetProcessHeap(), 0, This );
1794         TRACE("(%p) released\n",This);
1795     }
1796
1797     return uRef;
1798 }
1799
1800 static HRESULT WINAPI
1801 IDirectSoundFullDuplexImpl_Initialize(
1802     LPDIRECTSOUNDFULLDUPLEX iface,
1803     LPCGUID pCaptureGuid,
1804     LPCGUID pRendererGuid,
1805     LPCDSCBUFFERDESC lpDscBufferDesc,
1806     LPCDSBUFFERDESC lpDsBufferDesc,
1807     HWND hWnd,
1808     DWORD dwLevel,
1809     LPLPDIRECTSOUNDCAPTUREBUFFER8 lplpDirectSoundCaptureBuffer8,
1810     LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer8 )
1811 {
1812     ICOM_THIS(IDirectSoundFullDuplexImpl,iface);
1813     IDirectSoundCaptureBufferImpl** ippdscb=(IDirectSoundCaptureBufferImpl**)lplpDirectSoundCaptureBuffer8;
1814     IDirectSoundBufferImpl** ippdsc=(IDirectSoundBufferImpl**)lplpDirectSoundBuffer8;
1815
1816     FIXME( "(%p,%s,%s,%p,%p,%lx,%lx,%p,%p) stub!\n", This, debugstr_guid(pCaptureGuid), 
1817         debugstr_guid(pRendererGuid), lpDscBufferDesc, lpDsBufferDesc, (DWORD)hWnd, dwLevel,
1818         ippdscb, ippdsc);
1819
1820     return E_FAIL;
1821 }
1822
1823 static ICOM_VTABLE(IDirectSoundFullDuplex) dsfdvt =
1824 {
1825     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1826     /* IUnknown methods */
1827     IDirectSoundFullDuplexImpl_QueryInterface,
1828     IDirectSoundFullDuplexImpl_AddRef,
1829     IDirectSoundFullDuplexImpl_Release,
1830
1831     /* IDirectSoundFullDuplex methods */
1832     IDirectSoundFullDuplexImpl_Initialize
1833 };
1834
1835 /*******************************************************************************
1836  * DirectSoundFullDuplex ClassFactory
1837  */
1838
1839 static HRESULT WINAPI
1840 DSFDCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
1841 {
1842     ICOM_THIS(IClassFactoryImpl,iface);
1843
1844     FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
1845     return E_NOINTERFACE;
1846 }
1847
1848 static ULONG WINAPI
1849 DSFDCF_AddRef(LPCLASSFACTORY iface)
1850 {
1851     ICOM_THIS(IClassFactoryImpl,iface);
1852     TRACE("(%p) ref was %ld\n", This, This->ref);
1853     return ++(This->ref);
1854 }
1855
1856 static ULONG WINAPI 
1857 DSFDCF_Release(LPCLASSFACTORY iface) 
1858 {
1859     ICOM_THIS(IClassFactoryImpl,iface);
1860     /* static class, won't be  freed */
1861     TRACE("(%p) ref was %ld\n", This, This->ref);
1862     return --(This->ref);
1863 }
1864
1865 static HRESULT WINAPI 
1866 DSFDCF_CreateInstance(
1867     LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj )
1868 {
1869     ICOM_THIS(IClassFactoryImpl,iface);
1870
1871     TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1872
1873     if (ppobj == NULL) {
1874         WARN("invalid parameter\n");
1875         return E_INVALIDARG;
1876     }
1877
1878     *ppobj = NULL;
1879
1880     if ( IsEqualGUID( &IID_IDirectSoundFullDuplex, riid ) ) {
1881         /* FIXME: how do we do this one ? */
1882         FIXME("not implemented\n");
1883         return E_NOINTERFACE;
1884     }
1885
1886     WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); 
1887     return E_NOINTERFACE;
1888 }
1889
1890 static HRESULT WINAPI 
1891 DSFDCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
1892 {
1893     ICOM_THIS(IClassFactoryImpl,iface);
1894     FIXME("(%p)->(%d),stub!\n",This,dolock);
1895     return S_OK;
1896 }
1897
1898 static ICOM_VTABLE(IClassFactory) DSFDCF_Vtbl =
1899 {
1900     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1901     DSFDCF_QueryInterface,
1902     DSFDCF_AddRef,
1903     DSFDCF_Release,
1904     DSFDCF_CreateInstance,
1905     DSFDCF_LockServer
1906 };
1907
1908 IClassFactoryImpl DSOUND_FULLDUPLEX_CF = { &DSFDCF_Vtbl, 1 };