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