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