Added support for direct sound capture and a real direct sound capture
driver. Capture now works with some skipping. Full duplex does not but
I will be working on that next.

diff --git a/dlls/dsound/buffer.c b/dlls/dsound/buffer.c
index 2891cc5..161efd5 100644
--- a/dlls/dsound/buffer.c
+++ b/dlls/dsound/buffer.c
@@ -56,7 +56,11 @@
 	ICOM_THIS(IDirectSoundNotifyImpl,iface);
 
 	TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-	return IDirectSoundBuffer8_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb, riid, ppobj);
+	if (This->dsb)
+		return IDirectSoundBuffer8_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb, riid, ppobj);
+	else if (This->dscb)
+		return IDirectSoundCaptureBuffer8_QueryInterface((LPDIRECTSOUNDCAPTUREBUFFER8)This->dscb, riid, ppobj);
+	return DSERR_GENERIC;
 }
 
 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface) {
@@ -77,7 +81,10 @@
 
 	ref = InterlockedDecrement(&(This->ref));
 	if (!ref) {
-		IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)This->dsb);
+		if (This->dsb)
+			IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)This->dsb);
+		else if (This->dscb)
+			IDirectSoundCaptureBuffer_Release((LPDIRECTSOUNDCAPTUREBUFFER8)This->dscb);
 		HeapFree(GetProcessHeap(),0,This);
 		return 0;
 	}
@@ -96,17 +103,30 @@
 		    TRACE("notify at %ld to 0x%08lx\n",
                             notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
 	}
-	This->dsb->notifies = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->dsb->notifies,(This->dsb->nrofnotifies+howmuch)*sizeof(DSBPOSITIONNOTIFY));
-	memcpy(	This->dsb->notifies+This->dsb->nrofnotifies,
-		notify,
-		howmuch*sizeof(DSBPOSITIONNOTIFY)
-	);
-	This->dsb->nrofnotifies+=howmuch;
+	if (This->dsb) {
+		This->dsb->notifies = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->dsb->notifies,(This->dsb->nrofnotifies+howmuch)*sizeof(DSBPOSITIONNOTIFY));
+		memcpy(	This->dsb->notifies+This->dsb->nrofnotifies,
+			notify,
+			howmuch*sizeof(DSBPOSITIONNOTIFY)
+		);
+		This->dsb->nrofnotifies+=howmuch;
+	} else if (This->dscb) {
+		TRACE("notifies = %p, nrofnotifies = %d\n", This->dscb->notifies, This->dscb->nrofnotifies);
+		This->dscb->notifies = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->dscb->notifies,(This->dscb->nrofnotifies+howmuch)*sizeof(DSBPOSITIONNOTIFY));
+		memcpy(	This->dscb->notifies+This->dscb->nrofnotifies,
+			notify,
+			howmuch*sizeof(DSBPOSITIONNOTIFY)
+		);
+		This->dscb->nrofnotifies+=howmuch;
+		TRACE("notifies = %p, nrofnotifies = %d\n", This->dscb->notifies, This->dscb->nrofnotifies);
+	}
+	else
+		return DSERR_INVALIDPARAM;
 
 	return S_OK;
 }
 
-static ICOM_VTABLE(IDirectSoundNotify) dsnvt =
+ICOM_VTABLE(IDirectSoundNotify) dsnvt =
 {
 	ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
 	IDirectSoundNotifyImpl_QueryInterface,
@@ -798,6 +818,7 @@
 		dsn = (IDirectSoundNotifyImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn));
 		dsn->ref = 1;
 		dsn->dsb = This;
+		dsn->dscb = 0;
 		IDirectSoundBuffer8_AddRef(iface);
 		ICOM_VTBL(dsn) = &dsnvt;
 		*ppobj = (LPVOID)dsn;
@@ -815,7 +836,7 @@
 		return E_FAIL;
 	}
 
-        if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
+	if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
 		ERR("app requested IDirectSound3DListener on secondary buffer\n");
 		*ppobj = NULL;
 		return E_FAIL;
@@ -850,7 +871,7 @@
 	IDirectSoundBufferImpl_GetFormat,
 	IDirectSoundBufferImpl_GetVolume,
 	IDirectSoundBufferImpl_GetPan,
-        IDirectSoundBufferImpl_GetFrequency,
+	IDirectSoundBufferImpl_GetFrequency,
 	IDirectSoundBufferImpl_GetStatus,
 	IDirectSoundBufferImpl_Initialize,
 	IDirectSoundBufferImpl_Lock,
diff --git a/dlls/dsound/capture.c b/dlls/dsound/capture.c
index e7fc835..9e4cb1a 100644
--- a/dlls/dsound/capture.c
+++ b/dlls/dsound/capture.c
@@ -1,4 +1,4 @@
-/*  			DirectSoundCapture
+/*              DirectSoundCapture
  *
  * Copyright 1998 Marcus Meissner
  * Copyright 1998 Rob Riggs
@@ -20,7 +20,7 @@
  */
 /*
  * TODO:
- *	Implement DirectSoundCapture API
+ *    Implement DirectSoundCapture API
  */
 
 #include "config.h"
@@ -40,47 +40,23 @@
 #include "winuser.h"
 #include "winerror.h"
 #include "mmsystem.h"
+#include "mmddk.h"
+#include "winternl.h"
+#include "winnls.h"
 #include "wine/debug.h"
 #include "dsound.h"
+#include "dsdriver.h"
+#include "dsound_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
 
-/*****************************************************************************
- * Predeclare the interface implementation structures
- */
-typedef struct IDirectSoundCaptureImpl IDirectSoundCaptureImpl;
-typedef struct IDirectSoundCaptureBufferImpl IDirectSoundCaptureBufferImpl;
-
-
-/*****************************************************************************
- * IDirectSoundCapture implementation structure
- */
-struct IDirectSoundCaptureImpl
-{
-    /* IUnknown fields */
-    ICOM_VFIELD(IDirectSoundCapture);
-    DWORD                              ref;
-
-    /* IDirectSoundCaptureImpl fields */
-    CRITICAL_SECTION        lock;
-};
-
-/*****************************************************************************
- * IDirectSoundCapture implementation structure
- */
-struct IDirectSoundCaptureBufferImpl
-{
-    /* IUnknown fields */
-    ICOM_VFIELD(IDirectSoundCaptureBuffer8);
-    DWORD                              ref;
-
-    /* IDirectSoundCaptureBufferImpl fields */
-    CRITICAL_SECTION        lock;
-};
-
-
-static HRESULT DSOUND_CreateDirectSoundCapture( LPVOID* ppobj );
-static HRESULT DSOUND_CreateDirectSoundCaptureBuffer( LPCDSCBUFFERDESC lpcDSCBufferDesc, LPVOID* ppobj );
+static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(
+    LPDIRECTSOUNDCAPTURE iface,
+    LPCGUID lpcGUID );
+static HRESULT DSOUND_CreateDirectSoundCaptureBuffer(
+    IDirectSoundCaptureImpl *ipDSC, 
+    LPCDSCBUFFERDESC lpcDSCBufferDesc, 
+    LPVOID* ppobj );
 
 static ICOM_VTABLE(IDirectSoundCapture) dscvt;
 static ICOM_VTABLE(IDirectSoundCaptureBuffer8) dscbvt;
@@ -96,28 +72,62 @@
  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
  *             DSERR_OUTOFMEMORY
  */
-HRESULT WINAPI DirectSoundCaptureCreate8(
-	LPCGUID lpcGUID,
-	LPDIRECTSOUNDCAPTURE* lplpDSC,
-	LPUNKNOWN pUnkOuter )
+HRESULT WINAPI 
+DirectSoundCaptureCreate8(
+    LPCGUID lpcGUID,
+    LPDIRECTSOUNDCAPTURE* lplpDSC,
+    LPUNKNOWN pUnkOuter )
 {
-	TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), lplpDSC, pUnkOuter);
+    TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), lplpDSC, pUnkOuter);
 
-	if( pUnkOuter ) {
-		return DSERR_NOAGGREGATION;
-	}
+    if ( pUnkOuter ) {
+        TRACE("pUnkOuter != 0\n");
+        return DSERR_NOAGGREGATION;
+    }
 
-	/* Default device? */
-	if ( !lpcGUID ||
-	     IsEqualGUID(lpcGUID, &DSDEVID_DefaultCapture) ||
-	     IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoiceCapture) ) {
-		return DSOUND_CreateDirectSoundCapture( (LPVOID*)lplpDSC );
-	}
+    if ( !lplpDSC ) {
+        TRACE("invalid parameter: lplpDSC == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-	FIXME( "Unknown GUID %s\n", debugstr_guid(lpcGUID) );
-	*lplpDSC = NULL;
+    /* Default device? */
+    if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) ||
+        IsEqualGUID(lpcGUID, &DSDEVID_DefaultCapture) ||
+        IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoiceCapture) ) {
+        IDirectSoundCaptureImpl** ippDSC=(IDirectSoundCaptureImpl**)lplpDSC;
 
-	return DSERR_OUTOFMEMORY;
+        *ippDSC = (IDirectSoundCaptureImpl*)HeapAlloc(GetProcessHeap(),
+            HEAP_ZERO_MEMORY, sizeof(IDirectSoundCaptureImpl));
+
+        if (*ippDSC == NULL) {
+            TRACE("couldn't allocate memory\n");
+            return DSERR_OUTOFMEMORY;
+        }
+        else
+        {
+            ICOM_THIS(IDirectSoundCaptureImpl, *ippDSC);
+
+            This->ref = 1;
+            This->state = STATE_STOPPED;
+
+            if (lpcGUID)
+                This->guid = *lpcGUID;
+            else
+                This->guid = GUID_NULL;
+
+            InitializeCriticalSection( &(This->lock) );
+
+            ICOM_VTBL(This) = &dscvt;
+
+            /* FIXME: should this be defered because we can't return no driver ? */
+            return IDirectSoundCaptureImpl_Initialize( (LPDIRECTSOUNDCAPTURE)This, lpcGUID );
+        }
+    }
+
+    FIXME( "Unknown GUID %s\n", debugstr_guid(lpcGUID) );
+    *lplpDSC = NULL;
+
+    return DSERR_OUTOFMEMORY;
 }
 
 /***************************************************************************
@@ -129,18 +139,32 @@
  *    Success: DS_OK
  *    Failure: DSERR_INVALIDPARAM
  */
-HRESULT WINAPI DirectSoundCaptureEnumerateA(
-        LPDSENUMCALLBACKA lpDSEnumCallback,
-        LPVOID lpContext)
+HRESULT WINAPI 
+DirectSoundCaptureEnumerateA(
+    LPDSENUMCALLBACKA lpDSEnumCallback,
+    LPVOID lpContext)
 {
-	TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext );
+    WAVEINCAPSA wcaps;
+    unsigned devs, wid;
 
-	if ( lpDSEnumCallback )
-		lpDSEnumCallback(NULL,"WINE Primary Sound Capture Driver",
-                    "SoundCap",lpContext);
+    TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext );
 
+    if (lpDSEnumCallback == NULL) {
+        TRACE("invalid parameter\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-	return DS_OK;
+    devs = waveInGetNumDevs();
+    for (wid = 0; wid < devs; ++wid) {
+        waveInGetDevCapsA(wid, &wcaps, sizeof(wcaps));
+        if (lpDSEnumCallback) {
+            lpDSEnumCallback(NULL, "WINE Sound Capture Driver",
+                wcaps.szPname ,lpContext);
+            return DS_OK;
+        }
+    }
+
+    return DS_OK;
 }
 
 /***************************************************************************
@@ -152,388 +176,918 @@
  *    Success: DS_OK
  *    Failure: DSERR_INVALIDPARAM
  */
-HRESULT WINAPI DirectSoundCaptureEnumerateW(
-        LPDSENUMCALLBACKW lpDSEnumCallback,
-        LPVOID lpContext)
+HRESULT WINAPI 
+DirectSoundCaptureEnumerateW(
+    LPDSENUMCALLBACKW lpDSEnumCallback,
+    LPVOID lpContext)
 {
-        FIXME("(%p,%p):stub\n", lpDSEnumCallback, lpContext );
-        return DS_OK;
+    WAVEINCAPSW wcaps;
+    unsigned devs, wid;
+    WCHAR desc[MAXPNAMELEN];
+
+    TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext );
+
+    if (lpDSEnumCallback == NULL) {
+        TRACE("invalid parameter\n");
+        return DSERR_INVALIDPARAM;
+    }
+
+    devs = waveInGetNumDevs();
+    for (wid = 0; wid < devs; ++wid) {
+        waveInGetDevCapsW(wid, &wcaps, sizeof(wcaps));
+        if (lpDSEnumCallback) {
+            MultiByteToWideChar( CP_ACP, 0, "WINE Sound Capture Driver", -1, 
+                desc, sizeof(desc)/sizeof(WCHAR) );
+            lpDSEnumCallback(NULL, desc, wcaps.szPname ,lpContext);
+            return DS_OK;
+        }
+    }
+
+    return DS_OK;
 }
 
-static HRESULT
-DSOUND_CreateDirectSoundCapture( LPVOID* ppobj )
+static void CALLBACK 
+DSOUND_capture_callback(
+    HWAVEIN hwi, 
+    UINT msg, 
+    DWORD dwUser, 
+    DWORD dw1, 
+    DWORD dw2 )
 {
-	*ppobj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( IDirectSoundCaptureImpl ) );
+    IDirectSoundCaptureImpl* This = (IDirectSoundCaptureImpl*)dwUser;
+    TRACE("entering at %ld, msg=%08x\n", GetTickCount(), msg);
 
-	if ( *ppobj == NULL ) {
-		return DSERR_OUTOFMEMORY;
-	}
+    if (msg == MM_WIM_DATA) {
+        This->index = (This->index + 1) % This->capture_buffer->nrofnotifies;
+        waveInUnprepareHeader(hwi,&(This->pwave[This->index]),sizeof(WAVEHDR));
+        SetEvent(This->capture_buffer->notifies[This->index].hEventNotify);
+        waveInPrepareHeader(hwi,&(This->pwave[This->index]),sizeof(WAVEHDR));
+        waveInAddBuffer(hwi, &(This->pwave[This->index]), sizeof(WAVEHDR));
+    }
 
-	{
-		ICOM_THIS(IDirectSoundCaptureImpl,*ppobj);
-
-		This->ref = 1;
-		ICOM_VTBL(This) = &dscvt;
-
-		InitializeCriticalSection( &This->lock );
-	}
-
-	return S_OK;
+    TRACE("completed\n");
 }
 
 static HRESULT WINAPI
 IDirectSoundCaptureImpl_QueryInterface(
-	LPDIRECTSOUNDCAPTURE iface,
-	REFIID riid,
-	LPVOID* ppobj )
+    LPDIRECTSOUNDCAPTURE iface,
+    REFIID riid,
+    LPVOID* ppobj )
 {
-	ICOM_THIS(IDirectSoundCaptureImpl,iface);
+    ICOM_THIS(IDirectSoundCaptureImpl,iface);
+    TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
 
-	FIXME( "(%p)->(%s,%p): stub\n", This, debugstr_guid(riid), ppobj );
+    if (This->driver) 
+        return IDsCaptureDriver_QueryInterface(This->driver, riid, ppobj);
 
-	return E_FAIL;
+    return E_FAIL;
 }
 
 static ULONG WINAPI
 IDirectSoundCaptureImpl_AddRef( LPDIRECTSOUNDCAPTURE iface )
 {
-	ULONG uRef;
-        ICOM_THIS(IDirectSoundCaptureImpl,iface);
+    ULONG uRef;
+    ICOM_THIS(IDirectSoundCaptureImpl,iface);
 
-	EnterCriticalSection( &This->lock );
+    EnterCriticalSection( &This->lock );
 
-	TRACE( "(%p) was 0x%08lx\n", This, This->ref );
-	uRef = ++(This->ref);
+    TRACE( "(%p) was 0x%08lx\n", This, This->ref );
+    uRef = ++(This->ref);
 
-	LeaveCriticalSection( &This->lock );
+    if (This->driver) 
+        IDsCaptureDriver_AddRef(This->driver);
 
-        return uRef;
+    LeaveCriticalSection( &This->lock );
+
+    return uRef;
 }
 
 static ULONG WINAPI
 IDirectSoundCaptureImpl_Release( LPDIRECTSOUNDCAPTURE iface )
 {
-	ULONG uRef;
-	ICOM_THIS(IDirectSoundCaptureImpl,iface);
+    ULONG uRef;
+    ICOM_THIS(IDirectSoundCaptureImpl,iface);
 
-	EnterCriticalSection( &This->lock );
+    EnterCriticalSection( &This->lock );
 
-	TRACE( "(%p) was 0x%08lx\n", This, This->ref );
-	uRef = --(This->ref);
+    TRACE( "(%p) was 0x%08lx\n", This, This->ref );
+    uRef = --(This->ref);
 
-	LeaveCriticalSection( &This->lock );
+    LeaveCriticalSection( &This->lock );
 
-	if ( uRef == 0 ) {
-		DeleteCriticalSection( &This->lock );
-		HeapFree( GetProcessHeap(), 0, This );
-	}
+    if ( uRef == 0 ) {
+        TRACE("deleting object\n");
+        if (This->capture_buffer)
+            IDirectSoundCaptureBuffer8_Release(
+                (LPDIRECTSOUNDCAPTUREBUFFER8)This->capture_buffer);
 
-	return uRef;
+        if (This->driver) 
+            IDsDriver_Close(This->driver);
+        
+        if (This->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN) 
+            waveInClose(This->hwi);
+
+        if (This->driver)
+            IDsDriver_Release(This->driver);
+
+        DeleteCriticalSection( &This->lock );
+        HeapFree( GetProcessHeap(), 0, This );
+    }
+
+    return uRef;
 }
 
 static HRESULT WINAPI
 IDirectSoundCaptureImpl_CreateCaptureBuffer(
-	LPDIRECTSOUNDCAPTURE iface,
-	LPCDSCBUFFERDESC lpcDSCBufferDesc,
-	LPDIRECTSOUNDCAPTUREBUFFER* lplpDSCaptureBuffer,
-	LPUNKNOWN pUnk )
+    LPDIRECTSOUNDCAPTURE iface,
+    LPCDSCBUFFERDESC lpcDSCBufferDesc,
+    LPDIRECTSOUNDCAPTUREBUFFER* lplpDSCaptureBuffer,
+    LPUNKNOWN pUnk )
 {
-	HRESULT hr;
-	ICOM_THIS(IDirectSoundCaptureImpl,iface);
+    HRESULT hr;
+    ICOM_THIS(IDirectSoundCaptureImpl,iface);
 
-	TRACE( "(%p)->(%p,%p,%p)\n", This, lpcDSCBufferDesc, lplpDSCaptureBuffer, pUnk );
+    TRACE( "(%p,%p,%p,%p)\n", This, lpcDSCBufferDesc, lplpDSCaptureBuffer, 
+        pUnk );
 
-	if ( pUnk ) {
-		return DSERR_INVALIDPARAM;
-	}
+    if ( (This == NULL) || (lpcDSCBufferDesc== NULL) || 
+        (lplpDSCaptureBuffer == NULL) || pUnk ) {
+        TRACE("invalid parameters\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-	hr = DSOUND_CreateDirectSoundCaptureBuffer( lpcDSCBufferDesc, (LPVOID*)lplpDSCaptureBuffer );
+    /* FIXME: We can only have one buffer so what do we do here? */
+    if (This->capture_buffer) {
+            TRACE("already has buffer\n");
+            return DSERR_INVALIDPARAM;    /* DSERR_GENERIC ? */
+    }
 
-	return hr;
+    hr = DSOUND_CreateDirectSoundCaptureBuffer( This, lpcDSCBufferDesc, 
+        (LPVOID*)lplpDSCaptureBuffer );
+
+    return hr;
 }
 
 static HRESULT WINAPI
 IDirectSoundCaptureImpl_GetCaps(
-	LPDIRECTSOUNDCAPTURE iface,
-	LPDSCCAPS lpDSCCaps )
+    LPDIRECTSOUNDCAPTURE iface,
+    LPDSCCAPS lpDSCCaps )
 {
-        ICOM_THIS(IDirectSoundCaptureImpl,iface);
+    ICOM_THIS(IDirectSoundCaptureImpl,iface);
+    TRACE("(%p,%p)\n",This,lpDSCCaps);
 
-        FIXME( "(%p)->(%p): stub\n", This, lpDSCCaps );
+    if ( (lpDSCCaps== NULL) || (lpDSCCaps->dwSize != sizeof(*lpDSCCaps)) ) {
+        TRACE("invalid parameters\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-        return DS_OK;
+    if ( !(This->initialized) ) {
+        TRACE("not initialized\n");
+        return DSERR_UNINITIALIZED;
+    }
+
+    if ( (This->driver = 0) || (This->hwi == 0) ) {
+        TRACE("no driver\n");
+        return DSERR_NODRIVER;
+    }
+
+       lpDSCCaps->dwFlags = This->drvcaps.dwFlags;
+       lpDSCCaps->dwFormats = This->formats;
+       lpDSCCaps->dwChannels = This->channels;
+
+    TRACE("(flags=0x%08lx,format=0x%08lx,channels=%ld)\n",lpDSCCaps->dwFlags,
+        lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
+
+    return DS_OK;
 }
 
 static HRESULT WINAPI
 IDirectSoundCaptureImpl_Initialize(
-	LPDIRECTSOUNDCAPTURE iface,
-	LPCGUID lpcGUID )
+    LPDIRECTSOUNDCAPTURE iface,
+    LPCGUID lpcGUID )
 {
-        ICOM_THIS(IDirectSoundCaptureImpl,iface);
+    HRESULT err = DS_OK;
+    unsigned wid, widn;
+    ICOM_THIS(IDirectSoundCaptureImpl,iface);
+    TRACE("(%p)\n", This);
 
-        FIXME( "(%p)->(%p): stub\n", This, lpcGUID );
+    if (!This) {
+        TRACE("invalid parameter\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-        return DS_OK;
+    if (This->initialized) {
+        TRACE("already initialized\n");
+        return DSERR_ALREADYINITIALIZED;
+    }
+
+    widn = waveInGetNumDevs();
+
+    if (!widn) { 
+        TRACE("no audio devices found\n");
+        return DSERR_NODRIVER;
+    }
+
+    /* FIXME: should enumerate WINMM audio devices and find the one we want */
+    wid = 0;
+
+    err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDIFACE,(DWORD)&(This->driver),0));
+    if ( (err != DS_OK) && (err != DSERR_UNSUPPORTED) ) {
+        TRACE("waveInMessage failed; err=%lx\n",err);
+        return err;
+    }
+    err = DS_OK;
+
+    /* Get driver description */
+    if (This->driver) {
+        TRACE("using DirectSound driver\n");
+        IDsDriver_GetDriverDesc(This->driver, &(This->drvdesc));
+    } else {
+        TRACE("using WINMM\n");
+        /* if no DirectSound interface available, use WINMM API instead */
+        This->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | 
+            DSDDESC_DOMMSYSTEMSETFORMAT;
+        This->drvdesc.dnDevNode = wid; /* FIXME? */
+    }
+    
+    /* If the driver requests being opened through MMSYSTEM
+     * (which is recommended by the DDK), it is supposed to happen
+     * before the DirectSound interface is opened */
+    if (This->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
+    {
+        /* FIXME: is this right? */
+        This->drvdesc.dnDevNode = 0;
+
+#if 0    /* this returns an uninitialized structure so don't use */
+        /* query the wave format */
+        err = mmErr(waveInOpen(NULL, This->drvdesc.dnDevNode, &(This->wfx),
+            0, 0, WAVE_FORMAT_QUERY));
+#else                        
+        /* Set default wave format for waveInOpen */
+        This->wfx.wFormatTag    = WAVE_FORMAT_PCM;
+        /* We rely on the sound driver to return the actual sound format of
+         * the device if it does not support 22050x8x2 and is given the
+         * WAVE_DIRECTSOUND flag.
+         */
+        This->wfx.nSamplesPerSec = 22050;
+        This->wfx.wBitsPerSample = 8;
+        This->wfx.nChannels = 2;
+        This->wfx.nBlockAlign = This->wfx.wBitsPerSample * 
+            This->wfx.nChannels / 8;
+        This->wfx.nAvgBytesPerSec = This->wfx.nSamplesPerSec * 
+            This->wfx.nBlockAlign;
+        This->wfx.cbSize = 0;
+#endif
+        err = mmErr(waveInOpen(&(This->hwi),
+            This->drvdesc.dnDevNode, &(This->wfx),
+            (DWORD)DSOUND_capture_callback, (DWORD)This,
+            CALLBACK_FUNCTION | WAVE_DIRECTSOUND));
+    }
+
+    /* open the DirectSound driver if available */
+    if (This->driver && (err == DS_OK))
+        err = IDsDriver_Open(This->driver);
+
+    if (err == DS_OK) {
+        This->initialized = TRUE;
+
+        /* the driver is now open, so it's now allowed to call GetCaps */
+        if (This->driver) {
+            IDsDriver_GetCaps(This->driver,&(This->drvcaps));
+        } else if (This->hwi) {
+            WAVEINCAPSA    wic;
+            err = mmErr(waveInGetDevCapsA((UINT)This->hwi, &wic, sizeof(wic)));
+
+            if (err == DS_OK) {
+                This->drvcaps.dwFlags = 0;
+                strncpy(This->drvdesc.szDrvName, wic.szPname, 
+                    sizeof(This->drvdesc.szDrvName)); 
+
+                This->formats = wic.dwFormats;
+                This->channels = wic.wChannels;
+    
+                if (ds_emuldriver)
+                    This->drvcaps.dwFlags |= DSCCAPS_EMULDRIVER;
+            }
+        } else {
+            TRACE("no audio devices found\n");
+            return DSERR_NODRIVER;
+        }
+    }
+
+    return err;
 }
 
-
 static ICOM_VTABLE(IDirectSoundCapture) dscvt =
 {
-        ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
-        /* IUnknown methods */
-        IDirectSoundCaptureImpl_QueryInterface,
-        IDirectSoundCaptureImpl_AddRef,
-        IDirectSoundCaptureImpl_Release,
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    /* IUnknown methods */
+    IDirectSoundCaptureImpl_QueryInterface,
+    IDirectSoundCaptureImpl_AddRef,
+    IDirectSoundCaptureImpl_Release,
 
-        /* IDirectSoundCapture methods */
-        IDirectSoundCaptureImpl_CreateCaptureBuffer,
-        IDirectSoundCaptureImpl_GetCaps,
-        IDirectSoundCaptureImpl_Initialize
+    /* IDirectSoundCapture methods */
+    IDirectSoundCaptureImpl_CreateCaptureBuffer,
+    IDirectSoundCaptureImpl_GetCaps,
+    IDirectSoundCaptureImpl_Initialize
 };
 
 static HRESULT
-DSOUND_CreateDirectSoundCaptureBuffer( LPCDSCBUFFERDESC lpcDSCBufferDesc, LPVOID* ppobj )
+DSOUND_CreateDirectSoundCaptureBuffer(
+    IDirectSoundCaptureImpl *ipDSC, 
+    LPCDSCBUFFERDESC lpcDSCBufferDesc, 
+    LPVOID* ppobj )
 {
+    LPWAVEFORMATEX  wfex;
+    TRACE( "(%p,%p)\n", lpcDSCBufferDesc, ppobj );
 
-	FIXME( "(%p,%p): ignoring lpcDSCBufferDesc\n", lpcDSCBufferDesc, ppobj );
+    if ( (ipDSC == NULL) || (lpcDSCBufferDesc == NULL) || (ppobj == NULL) ) {
+        TRACE("invalid parameters\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-	*ppobj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( IDirectSoundCaptureBufferImpl ) );
+    if ( (lpcDSCBufferDesc->dwSize < sizeof(DSCBUFFERDESC)) || 
+        (lpcDSCBufferDesc->dwBufferBytes == 0) ||
+        (lpcDSCBufferDesc->lpwfxFormat == NULL) ) {
+        TRACE("invalid lpcDSCBufferDesc\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-	if ( *ppobj == NULL ) {
-		return DSERR_OUTOFMEMORY;
-	}
+    if ( !ipDSC->initialized ) {
+        TRACE("not initialized\n");
 
-	{
-		ICOM_THIS(IDirectSoundCaptureBufferImpl,*ppobj);
+        return DSERR_UNINITIALIZED;
+    }
 
-		This->ref = 1;
-		ICOM_VTBL(This) = &dscbvt;
+    if ( (ipDSC->driver == 0) && (ipDSC->hwi == 0) ) {
+        TRACE("no driver\n");
+        return DSERR_NODRIVER;
+    }
 
-		InitializeCriticalSection( &This->lock );
-	}
+    wfex = lpcDSCBufferDesc->lpwfxFormat;
 
-	return S_OK;
+    if (wfex) {
+        TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
+            "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
+            wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
+            wfex->nAvgBytesPerSec, wfex->nBlockAlign,
+            wfex->wBitsPerSample, wfex->cbSize);
+
+        if (wfex->cbSize == 0)
+            memcpy(&(ipDSC->wfx), wfex, sizeof(*wfex) + wfex->cbSize);
+        else {
+            ERR("non PCM formats not supported\n");
+            return DSERR_BADFORMAT; /* FIXME: DSERR_INVALIDPARAM ? */
+        }
+    } else {
+        TRACE("lpcDSCBufferDesc->lpwfxFormat == 0\n");
+        return DSERR_INVALIDPARAM; /* FIXME: DSERR_BADFORMAT ? */
+    }
+
+    *ppobj = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
+        sizeof(IDirectSoundCaptureBufferImpl));
+
+    if ( *ppobj == NULL ) {
+        TRACE("out of memory\n");
+        return DSERR_OUTOFMEMORY;
+    } else {
+        ICOM_THIS(IDirectSoundCaptureBufferImpl,*ppobj);
+
+        This->ref = 1;
+        This->dsound = ipDSC;
+        This->dsound->capture_buffer = This;
+
+        This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
+            lpcDSCBufferDesc->dwSize);
+        if (This->pdscbd)     
+            memcpy(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize);
+        else {
+            TRACE("no memory\n");
+            This->dsound->capture_buffer = 0;
+            HeapFree( GetProcessHeap(), 0, This );
+            *ppobj = NULL;
+            return DSERR_OUTOFMEMORY; 
+        }
+
+        ICOM_VTBL(This) = &dscbvt;
+
+        InitializeCriticalSection( &This->lock );
+    }
+
+    return DS_OK;
 }
 
-
 static HRESULT WINAPI
 IDirectSoundCaptureBufferImpl_QueryInterface(
-        LPDIRECTSOUNDCAPTUREBUFFER8 iface,
-        REFIID riid,
-        LPVOID* ppobj )
+    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
+    REFIID riid,
+    LPVOID* ppobj )
 {
-        ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
 
-        FIXME( "(%p)->(%s,%p): stub\n", This, debugstr_guid(riid), ppobj );
+    if (IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
+        IDirectSoundNotifyImpl  *dsn;
 
-        return E_FAIL;
+        dsn = (IDirectSoundNotifyImpl*)HeapAlloc(GetProcessHeap(),0,
+            sizeof(*dsn));
+        dsn->ref = 1;
+        dsn->dsb = 0;
+        dsn->dscb = This;
+        IDirectSoundCaptureBuffer8_AddRef(iface);
+        ICOM_VTBL(dsn) = &dsnvt;
+        *ppobj = (LPVOID)dsn;
+        return DS_OK;
+    }
+
+    FIXME("(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj);
+
+    return E_FAIL;
 }
 
 static ULONG WINAPI
 IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
 {
-        ULONG uRef;
-        ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    ULONG uRef;
+    ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    TRACE( "(%p)\n", This );
 
-        EnterCriticalSection( &This->lock );
+    EnterCriticalSection( &This->lock );
 
-	TRACE( "(%p) was 0x%08lx\n", This, This->ref );
-        uRef = ++(This->ref);
+    TRACE( "(%p) was 0x%08lx\n", This, This->ref );
+    uRef = ++(This->ref);
 
-        LeaveCriticalSection( &This->lock );
+    LeaveCriticalSection( &This->lock );
 
-        return uRef;
+    return uRef;
 }
 
 static ULONG WINAPI
 IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
 {
-        ULONG uRef;
-        ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    ULONG uRef;
+    ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    TRACE( "(%p)\n", This );
 
-        EnterCriticalSection( &This->lock );
+    EnterCriticalSection( &This->lock );
 
-	TRACE( "(%p) was 0x%08lx\n", This, This->ref );
-        uRef = --(This->ref);
+    TRACE( "(%p) was 0x%08lx\n", This, This->ref );
+    uRef = --(This->ref);
 
-        LeaveCriticalSection( &This->lock );
+    LeaveCriticalSection( &This->lock );
 
-        if ( uRef == 0 ) {
-		DeleteCriticalSection( &This->lock );
-                HeapFree( GetProcessHeap(), 0, This );
-        }
+    if ( uRef == 0 ) {
+        if (This->pdscbd)
+            HeapFree(GetProcessHeap(),0, This->pdscbd);
 
-        return uRef;
+        /* remove from IDirectSoundCaptureImpl */
+        if (This->dsound)
+            This->dsound->capture_buffer = NULL;
+        else
+            ERR("does not reference dsound\n");
+
+        if (This->notifies)
+            HeapFree(GetProcessHeap(),0, This->notifies);
+        
+        DeleteCriticalSection( &This->lock );
+        HeapFree( GetProcessHeap(), 0, This );
+    }
+
+    return uRef;
 }
 
 static HRESULT WINAPI
 IDirectSoundCaptureBufferImpl_GetCaps(
-        LPDIRECTSOUNDCAPTUREBUFFER8 iface,
-	LPDSCBCAPS lpDSCBCaps )
+    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
+    LPDSCBCAPS lpDSCBCaps )
 {
-	ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    TRACE( "(%p,%p)\n", This, lpDSCBCaps );
 
-	FIXME( "(%p)->(%p): stub\n", This, lpDSCBCaps );
+    if ( (This == NULL) || (lpDSCBCaps == NULL) ) {
+        TRACE("invalid parameters\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-	return DS_OK;
+    if ( (lpDSCBCaps->dwSize < sizeof(DSCBCAPS)) || (This->dsound == NULL) ) {
+        TRACE("invalid parameters\n");
+        return DSERR_INVALIDPARAM;
+    }
+
+    lpDSCBCaps->dwSize = sizeof(DSCBCAPS);
+    lpDSCBCaps->dwFlags = This->flags;
+    lpDSCBCaps->dwBufferBytes = This->pdscbd->dwBufferBytes;
+    lpDSCBCaps->dwReserved = 0;
+
+    return DS_OK;
 }
 
 static HRESULT WINAPI
 IDirectSoundCaptureBufferImpl_GetCurrentPosition(
-        LPDIRECTSOUNDCAPTUREBUFFER8 iface,
-	LPDWORD lpdwCapturePosition,
-	LPDWORD lpdwReadPosition )
+    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
+    LPDWORD lpdwCapturePosition,
+    LPDWORD lpdwReadPosition )
 {
-	ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    TRACE( "(%p,%p,%p)\n", This, lpdwCapturePosition, lpdwReadPosition );
 
-	FIXME( "(%p)->(%p,%p): stub\n", This, lpdwCapturePosition, lpdwReadPosition );
+    if ( (This == NULL) || (This->dsound == NULL) || 
+        (lpdwReadPosition == NULL) ) {
+        TRACE("invalid parameter\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-	return DS_OK;
+    if (This->dsound->driver) {
+        FIXME( "(%p,%p,%p): direct sound driver not supported\n", 
+            This, lpdwCapturePosition, lpdwReadPosition );
+        return DSERR_NODRIVER;
+    } else if (This->dsound->hwi) {
+        if (lpdwCapturePosition) {
+            MMTIME mtime;
+            mtime.wType = TIME_BYTES;
+            waveInGetPosition(This->dsound->hwi, &mtime, sizeof(mtime));
+            mtime.u.cb = mtime.u.cb % This->dsound->buflen;
+            *lpdwCapturePosition = mtime.u.cb;
+        }
+    
+        if (lpdwReadPosition) {
+            if (This->dsound->state == STATE_STARTING) { 
+                This->dsound->read_position = *lpdwCapturePosition;
+                This->dsound->state = STATE_CAPTURING;
+            } 
+            *lpdwReadPosition = This->dsound->read_position;
+        }
+    } else {
+        TRACE("no driver\n");
+        return DSERR_NODRIVER;
+    }
+    
+    return DS_OK;
 }
 
 static HRESULT WINAPI
 IDirectSoundCaptureBufferImpl_GetFormat(
-        LPDIRECTSOUNDCAPTUREBUFFER8 iface,
-	LPWAVEFORMATEX lpwfxFormat,
-	DWORD dwSizeAllocated,
-	LPDWORD lpdwSizeWritten )
+    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
+    LPWAVEFORMATEX lpwfxFormat,
+    DWORD dwSizeAllocated,
+    LPDWORD lpdwSizeWritten )
 {
-	ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    TRACE( "(%p,%p,0x%08lx,%p)\n", This, lpwfxFormat, dwSizeAllocated, 
+        lpdwSizeWritten );
 
-	FIXME( "(%p)->(%p,0x%08lx,%p): stub\n", This, lpwfxFormat, dwSizeAllocated, lpdwSizeWritten );
+    if ( (This == NULL) || (This->dsound == NULL) ) {
+        TRACE("invalid parameter\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-	return DS_OK;
+    /* FIXME: use real size for extended formats someday */
+    if (dwSizeAllocated > sizeof(This->dsound->wfx))
+        dwSizeAllocated = sizeof(This->dsound->wfx);
+    if (lpwfxFormat) { /* NULL is valid (just want size) */
+        memcpy(lpwfxFormat,&(This->dsound->wfx),dwSizeAllocated);
+        if (lpdwSizeWritten)
+            *lpdwSizeWritten = dwSizeAllocated;
+    } else {
+        if (lpdwSizeWritten)
+            *lpdwSizeWritten = sizeof(This->dsound->wfx);
+        else {
+            TRACE("invalid parameter\n");
+            return DSERR_INVALIDPARAM;
+        }
+    }
+
+    return DS_OK;
 }
 
 static HRESULT WINAPI
 IDirectSoundCaptureBufferImpl_GetStatus(
-        LPDIRECTSOUNDCAPTUREBUFFER8 iface,
-	LPDWORD lpdwStatus )
+    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
+    LPDWORD lpdwStatus )
 {
-	ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    TRACE( "(%p, %p)\n", This, lpdwStatus );
 
-	FIXME( "(%p)->(%p): stub\n", This, lpdwStatus );
+    if ( (This == NULL ) || (This->dsound == NULL) || (lpdwStatus == NULL) ) {
+        TRACE("invalid parameter\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-	return DS_OK;
+    *lpdwStatus = 0;
+    if ((This->dsound->state == STATE_STARTING) || 
+        (This->dsound->state == STATE_CAPTURING)) {
+        *lpdwStatus |= DSCBSTATUS_CAPTURING;
+        if (This->flags & DSCBSTART_LOOPING)
+            *lpdwStatus |= DSCBSTATUS_LOOPING;
+    }
+
+    return DS_OK;
 }
 
 static HRESULT WINAPI
 IDirectSoundCaptureBufferImpl_Initialize(
-        LPDIRECTSOUNDCAPTUREBUFFER8 iface,
-	LPDIRECTSOUNDCAPTURE lpDSC,
-	LPCDSCBUFFERDESC lpcDSCBDesc )
+    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
+    LPDIRECTSOUNDCAPTURE lpDSC,
+    LPCDSCBUFFERDESC lpcDSCBDesc )
 {
-	ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
 
-	FIXME( "(%p)->(%p,%p): stub\n", This, lpDSC, lpcDSCBDesc );
+    FIXME( "(%p,%p,%p): stub\n", This, lpDSC, lpcDSCBDesc );
 
-	return DS_OK;
+    return DS_OK;
 }
 
 static HRESULT WINAPI
 IDirectSoundCaptureBufferImpl_Lock(
-        LPDIRECTSOUNDCAPTUREBUFFER8 iface,
-	DWORD dwReadCusor,
-	DWORD dwReadBytes,
-	LPVOID* lplpvAudioPtr1,
-	LPDWORD lpdwAudioBytes1,
-	LPVOID* lplpvAudioPtr2,
-	LPDWORD lpdwAudioBytes2,
-	DWORD dwFlags )
+    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
+    DWORD dwReadCusor,
+    DWORD dwReadBytes,
+    LPVOID* lplpvAudioPtr1,
+    LPDWORD lpdwAudioBytes1,
+    LPVOID* lplpvAudioPtr2,
+    LPDWORD lpdwAudioBytes2,
+    DWORD dwFlags )
 {
-	ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    TRACE( "(%p,%08lu,%08lu,%p,%p,%p,%p,0x%08lx)\n", This, dwReadCusor,
+        dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2,
+        lpdwAudioBytes2, dwFlags );
 
-	FIXME( "(%p)->(%08lu,%08lu,%p,%p,%p,%p,0x%08lx): stub\n", This, dwReadCusor, dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2, lpdwAudioBytes2, dwFlags );
+    if ( (This == NULL) || (This->dsound == NULL) || (lplpvAudioPtr1 == NULL) ||
+        (lpdwAudioBytes1 == NULL) || (lplpvAudioPtr2 == NULL) || 
+        (lpdwAudioBytes2 == NULL) ) {
+        TRACE("invalid parameter\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-	return DS_OK;
+    if (This->dsound->driver) {
+        FIXME("direct sound driver not supported\n");
+        return DSERR_INVALIDCALL;    /* DSERR_NODRIVER ? */
+    } else if (This->dsound->hwi) {
+        *lplpvAudioPtr1 = This->dsound->buffer + dwReadCusor;
+        if ( (dwReadCusor + dwReadBytes) > This->dsound->buflen) {
+            *lpdwAudioBytes1 = This->dsound->buflen - dwReadCusor;
+            *lplpvAudioPtr2 = This->dsound->buffer;
+            *lpdwAudioBytes2 = dwReadBytes - *lpdwAudioBytes1;
+        } else {
+            *lpdwAudioBytes1 = dwReadBytes;
+            *lplpvAudioPtr2 = 0;
+            *lpdwAudioBytes2 = 0;
+        }
+    } else {
+        TRACE("invalid call\n");
+        return DSERR_INVALIDCALL;   /* DSERR_NODRIVER ? */
+    }
+
+    return DS_OK;
 }
 
 static HRESULT WINAPI
 IDirectSoundCaptureBufferImpl_Start(
-        LPDIRECTSOUNDCAPTUREBUFFER8 iface,
-	DWORD dwFlags )
+    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
+    DWORD dwFlags )
 {
-	ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    HRESULT err = DS_OK;
+    ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    TRACE( "(%p,0x%08lx)\n", This, dwFlags );
 
-	FIXME( "(%p)->(0x%08lx): stub\n", This, dwFlags );
+    if ( (This == NULL) || (dwFlags != DSCBSTART_LOOPING) || 
+        (This->dsound == NULL) ) {
+        TRACE("invalid parameter\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-	return DS_OK;
+    if ( (This->dsound->driver == 0) && (This->dsound->hwi == 0) ) {
+        TRACE("no driver\n");
+        return DSERR_NODRIVER;
+    }
+
+    EnterCriticalSection(&(This->lock));
+
+    This->flags = dwFlags;
+    if (This->dsound->state == STATE_STOPPED)
+        This->dsound->state = STATE_STARTING;
+    else if (This->dsound->state == STATE_STOPPING)
+        This->dsound->state = STATE_CAPTURING;
+
+    if (This->dsound->driver) {
+        FIXME("direct sound driver not supported\n");
+        LeaveCriticalSection(&(This->lock));
+        return DSERR_NODRIVER;
+    } else {
+        LPBYTE newbuf;
+        DWORD buflen;
+
+        IDirectSoundCaptureImpl* ipDSC = This->dsound;
+
+        /* FIXME: do this only if formats different */
+        err = mmErr(waveInClose(ipDSC->hwi));
+        if (err != DS_OK) {
+            TRACE("waveInClose failed\n");
+            return DSERR_GENERIC;
+        }
+
+        err = mmErr(waveInOpen(&(ipDSC->hwi),
+            ipDSC->drvdesc.dnDevNode, &(ipDSC->wfx),
+            (DWORD)DSOUND_capture_callback, (DWORD)ipDSC,
+            CALLBACK_FUNCTION | WAVE_DIRECTSOUND));
+        if (err != DS_OK) {
+            TRACE("waveInOpen failed\n");
+            return DSERR_GENERIC;
+        }
+
+        buflen = This->pdscbd->dwBufferBytes;
+        TRACE("desired buflen=%ld, old buffer=%p\n", buflen, ipDSC->buffer);
+        newbuf = (LPBYTE)HeapReAlloc(GetProcessHeap(),0,ipDSC->buffer,buflen);
+
+        if (newbuf == NULL) {
+            ERR("failed to allocate capture buffer\n");
+            err = DSERR_OUTOFMEMORY;
+            /* but the old buffer might still exist and must be re-prepared */
+        } else {
+            ipDSC->buffer = newbuf;
+            ipDSC->buflen = buflen;
+        }
+
+        if (ipDSC->buffer) {
+            unsigned c;
+
+            if (This->nrofnotifies)
+            {
+                /* prepare headers */
+                ipDSC->pwave = HeapReAlloc(GetProcessHeap(),0,ipDSC->pwave,
+                    This->nrofnotifies*sizeof(WAVEHDR));
+
+                for (c = 0; c < This->nrofnotifies; c++) {
+                    if (c == 0) {
+                        ipDSC->pwave[0].lpData = ipDSC->buffer;
+                        ipDSC->pwave[0].dwBufferLength = 
+                            This->notifies[0].dwOffset + 1;
+                    } else {
+                        ipDSC->pwave[c].lpData = ipDSC->buffer + 
+                            This->notifies[c-1].dwOffset + 1;
+                        ipDSC->pwave[c].dwBufferLength = 
+                            This->notifies[c].dwOffset - 
+                            This->notifies[c-1].dwOffset;
+                    }
+                    ipDSC->pwave[c].dwUser = (DWORD)ipDSC;
+                    ipDSC->pwave[c].dwFlags = 0;
+                    ipDSC->pwave[c].dwLoops = 0;
+                    err = mmErr(waveInPrepareHeader(ipDSC->hwi,
+                        &(ipDSC->pwave[c]),sizeof(WAVEHDR)));
+                    if (err != DS_OK) {
+                        while (c--)
+                            waveInUnprepareHeader(ipDSC->hwi,
+                                &(ipDSC->pwave[c]),sizeof(WAVEHDR));
+                        break;
+                    }
+#if 0
+                    err = mmErr(waveInAddBuffer(ipDSC->hwi, &(ipDSC->pwave[c]), 
+                        sizeof(WAVEHDR)));
+                    if (err != DS_OK) {
+                        while (c--)
+                            waveInUnprepareHeader(ipDSC->hwi,&(ipDSC->pwave[c]),
+                                sizeof(WAVEHDR));
+                        break;
+                    }
+#endif
+                }
+
+                memset(ipDSC->buffer, 
+                    (ipDSC->wfx.wBitsPerSample == 16) ? 0 : 128, ipDSC->buflen);
+            }
+        }
+
+        ipDSC->index = 0;
+        ipDSC->read_position = 0;
+        err = mmErr(waveInAddBuffer(ipDSC->hwi, &(ipDSC->pwave[ipDSC->index]),
+            sizeof(WAVEHDR)));
+        if (err == DS_OK)
+            err = mmErr(waveInStart(ipDSC->hwi));
+    }
+
+    if (err != DS_OK) {
+        FIXME("cleanup\n");
+        if (This->dsound->driver) {
+            FIXME("direct sound driver not supported\n");
+        }
+        if (This->dsound->hwi) {
+            waveInClose(This->dsound->hwi);
+        }
+        LeaveCriticalSection(&(This->lock));
+        return err;
+    }
+
+    LeaveCriticalSection(&(This->lock));
+
+    return DS_OK;
 }
 
 static HRESULT WINAPI
 IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
 {
-	ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    TRACE( "(%p)\n", This );
 
-	FIXME( "(%p): stub\n", This );
+    if ( (This == NULL) || (This->dsound == NULL) ) {
+        TRACE("invalid parameter\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-	return DS_OK;
+    if (This->dsound->driver) {
+        FIXME("direct sound driver not supported\n");
+        return DSERR_NODRIVER;
+    } else if (This->dsound->hwi) {
+        TRACE("stopping winmm\n");
+        waveInStop(This->dsound->hwi);
+    } else {
+        TRACE("no driver\n");
+        return DSERR_NODRIVER;
+    }
+
+    return DS_OK;
 }
 
 static HRESULT WINAPI
 IDirectSoundCaptureBufferImpl_Unlock(
-        LPDIRECTSOUNDCAPTUREBUFFER8 iface,
-	LPVOID lpvAudioPtr1,
-	DWORD dwAudioBytes1,
-	LPVOID lpvAudioPtr2,
-	DWORD dwAudioBytes2 )
+    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
+    LPVOID lpvAudioPtr1,
+    DWORD dwAudioBytes1,
+    LPVOID lpvAudioPtr2,
+    DWORD dwAudioBytes2 )
 {
-	ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    TRACE( "(%p,%p,%08lu,%p,%08lu)\n", This, lpvAudioPtr1, dwAudioBytes1, 
+        lpvAudioPtr2, dwAudioBytes2 );
 
-	FIXME( "(%p)->(%p,%08lu,%p,%08lu): stub\n", This, lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2 );
+    if ( (This == NULL) || (lpvAudioPtr1 == NULL) ) {
+        TRACE("invalid parameters\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-	return DS_OK;
+    if (This->dsound->driver) {
+        TRACE("direct sound driver not supported\n");
+        return DSERR_INVALIDCALL;
+    } else if (This->dsound->hwi) {
+        This->dsound->read_position = (This->dsound->read_position + 
+            (dwAudioBytes1 + dwAudioBytes2)) % This->dsound->buflen;
+    } else {
+        TRACE("invalid call\n");
+        return DSERR_INVALIDCALL;
+    }
+
+    return DS_OK;
 }
 
 static HRESULT WINAPI
 IDirectSoundCaptureBufferImpl_GetObjectInPath(
-        LPDIRECTSOUNDCAPTUREBUFFER8 iface,
-        REFGUID rguidObject,
-        DWORD dwIndex,
-        REFGUID rguidInterface,
-        LPVOID* ppObject )
+    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
+    REFGUID rguidObject,
+    DWORD dwIndex,
+    REFGUID rguidInterface,
+    LPVOID* ppObject )
 {
-	ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
 
-	FIXME( "(%p)->(%s,%lu,%s,%p): stub\n", This, debugstr_guid(rguidObject), dwIndex, debugstr_guid(rguidInterface), ppObject );
+    FIXME( "(%p,%s,%lu,%s,%p): stub\n", This, debugstr_guid(rguidObject), 
+        dwIndex, debugstr_guid(rguidInterface), ppObject );
 
-	return DS_OK;
+    return DS_OK;
 }
 
 static HRESULT WINAPI
 IDirectSoundCaptureBufferImpl_GetFXStatus(
-        LPDIRECTSOUNDCAPTUREBUFFER8 iface,
-        DWORD dwFXCount,
-        LPDWORD pdwFXStatus )
+    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
+    DWORD dwFXCount,
+    LPDWORD pdwFXStatus )
 {
-	ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
+    ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
 
-	FIXME( "(%p)->(%lu,%p): stub\n", This, dwFXCount, pdwFXStatus );
+    FIXME( "(%p,%lu,%p): stub\n", This, dwFXCount, pdwFXStatus );
 
-	return DS_OK;
+    return DS_OK;
 }
 
-
 static ICOM_VTABLE(IDirectSoundCaptureBuffer8) dscbvt =
 {
-        ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
-        /* IUnknown methods */
-        IDirectSoundCaptureBufferImpl_QueryInterface,
-        IDirectSoundCaptureBufferImpl_AddRef,
-        IDirectSoundCaptureBufferImpl_Release,
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    /* IUnknown methods */
+    IDirectSoundCaptureBufferImpl_QueryInterface,
+    IDirectSoundCaptureBufferImpl_AddRef,
+    IDirectSoundCaptureBufferImpl_Release,
 
-        /* IDirectSoundCaptureBuffer methods */
-        IDirectSoundCaptureBufferImpl_GetCaps,
-        IDirectSoundCaptureBufferImpl_GetCurrentPosition,
-        IDirectSoundCaptureBufferImpl_GetFormat,
-        IDirectSoundCaptureBufferImpl_GetStatus,
-        IDirectSoundCaptureBufferImpl_Initialize,
-        IDirectSoundCaptureBufferImpl_Lock,
-        IDirectSoundCaptureBufferImpl_Start,
-        IDirectSoundCaptureBufferImpl_Stop,
-        IDirectSoundCaptureBufferImpl_Unlock,
+    /* IDirectSoundCaptureBuffer methods */
+    IDirectSoundCaptureBufferImpl_GetCaps,
+    IDirectSoundCaptureBufferImpl_GetCurrentPosition,
+    IDirectSoundCaptureBufferImpl_GetFormat,
+    IDirectSoundCaptureBufferImpl_GetStatus,
+    IDirectSoundCaptureBufferImpl_Initialize,
+    IDirectSoundCaptureBufferImpl_Lock,
+    IDirectSoundCaptureBufferImpl_Start,
+    IDirectSoundCaptureBufferImpl_Stop,
+    IDirectSoundCaptureBufferImpl_Unlock,
 
-        /* IDirectSoundCaptureBuffer methods */
-        IDirectSoundCaptureBufferImpl_GetObjectInPath,
-        IDirectSoundCaptureBufferImpl_GetFXStatus
+    /* IDirectSoundCaptureBuffer methods */
+    IDirectSoundCaptureBufferImpl_GetObjectInPath,
+    IDirectSoundCaptureBufferImpl_GetFXStatus
 };
diff --git a/dlls/dsound/dsound_main.c b/dlls/dsound/dsound_main.c
index ccb9ac8..50d174e 100644
--- a/dlls/dsound/dsound_main.c
+++ b/dlls/dsound/dsound_main.c
@@ -83,7 +83,7 @@
 
 IDirectSoundImpl*	dsound = NULL;
 
-static HRESULT mmErr(UINT err)
+HRESULT mmErr(UINT err)
 {
 	switch(err) {
 	case MMSYSERR_NOERROR:
@@ -91,13 +91,18 @@
 	case MMSYSERR_ALLOCATED:
 		return DSERR_ALLOCATED;
 	case MMSYSERR_INVALHANDLE:
+	case WAVERR_STILLPLAYING:
 		return DSERR_GENERIC; /* FIXME */
 	case MMSYSERR_NODRIVER:
 		return DSERR_NODRIVER;
 	case MMSYSERR_NOMEM:
 		return DSERR_OUTOFMEMORY;
 	case MMSYSERR_INVALPARAM:
+	case WAVERR_BADFORMAT:
+	case WAVERR_UNPREPARED:
 		return DSERR_INVALIDPARAM;
+	case MMSYSERR_NOTSUPPORTED:
+		return DSERR_UNSUPPORTED;
 	default:
 		FIXME("Unknown MMSYS error %d\n",err);
 		return DSERR_GENERIC;
diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h
index ff91eec..f1ef984 100644
--- a/dlls/dsound/dsound_private.h
+++ b/dlls/dsound/dsound_private.h
@@ -37,6 +37,8 @@
  */
 typedef struct IDirectSoundImpl IDirectSoundImpl;
 typedef struct IDirectSoundBufferImpl IDirectSoundBufferImpl;
+typedef struct IDirectSoundCaptureImpl IDirectSoundCaptureImpl;
+typedef struct IDirectSoundCaptureBufferImpl IDirectSoundCaptureBufferImpl;
 typedef struct IDirectSoundNotifyImpl IDirectSoundNotifyImpl;
 typedef struct IDirectSound3DListenerImpl IDirectSound3DListenerImpl;
 typedef struct IDirectSound3DBufferImpl IDirectSound3DBufferImpl;
@@ -68,9 +70,9 @@
     int                         nrofbuffers;
     IDirectSoundBufferImpl**    buffers;
     IDirectSound3DListenerImpl*	listener;
-    RTL_RWLOCK			lock;
-    CRITICAL_SECTION		mixlock;
-    DSVOLUMEPAN			volpan;
+    RTL_RWLOCK                  lock;
+    CRITICAL_SECTION            mixlock;
+    DSVOLUMEPAN                 volpan;
 };
 
 /*****************************************************************************
@@ -126,6 +128,64 @@
 	LPDSBUFFERDESC dsbd);
 
 /*****************************************************************************
+ * IDirectSoundCapture implementation structure
+ */
+struct IDirectSoundCaptureImpl
+{
+    /* IUnknown fields */
+    ICOM_VFIELD(IDirectSoundCapture);
+    DWORD                              ref;
+
+    /* IDirectSoundCaptureImpl fields */
+	GUID                               guid;
+	BOOL                               initialized;
+
+	/* DirectSound driver stuff */
+	PIDSCDRIVER                        driver;
+	DSDRIVERDESC                       drvdesc;
+	DSDRIVERCAPS                       drvcaps;
+    PIDSDRIVERBUFFER                   hwbuf;
+
+	/* wave driver info */
+	HWAVEIN                            hwi;
+
+	/* more stuff */
+    LPBYTE                             buffer;
+    DWORD                              buflen;
+	DWORD                              read_position;
+
+	/* FIXME: this should be a pointer because it can be bigger */
+	WAVEFORMATEX                       wfx;
+
+	DWORD                              formats;
+	DWORD                              channels;
+	IDirectSoundCaptureBufferImpl*     capture_buffer;
+	DWORD                              state;
+    LPWAVEHDR                          pwave;
+	int                                index;
+    CRITICAL_SECTION                   lock;
+};
+
+/*****************************************************************************
+ * IDirectSoundCaptureBuffer implementation structure
+ */
+struct IDirectSoundCaptureBufferImpl
+{
+	/* IUnknown fields */
+	ICOM_VFIELD(IDirectSoundCaptureBuffer8);
+	DWORD                              ref;
+
+	/* IDirectSoundCaptureBufferImpl fields */
+	IDirectSoundCaptureImpl*           dsound;
+	CRITICAL_SECTION                   lock;
+	/* FIXME: don't need this */
+	LPDSCBUFFERDESC                    pdscbd;
+	LPDSBPOSITIONNOTIFY                notifies;
+	int                                nrofnotifies;
+	DWORD                              flags;
+};
+
+/*****************************************************************************
  * IDirectSoundNotify implementation structure
  */
 struct IDirectSoundNotifyImpl
@@ -134,7 +194,8 @@
     ICOM_VFIELD(IDirectSoundNotify);
     DWORD                            ref;
     /* IDirectSoundNotifyImpl fields */
-    IDirectSoundBufferImpl* dsb;
+    IDirectSoundBufferImpl*          dsb;
+	IDirectSoundCaptureBufferImpl*   dscb;
 };
 
 /*****************************************************************************
@@ -218,10 +279,11 @@
 void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2);
 void CALLBACK DSOUND_callback(HWAVEOUT hwo, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2);
 
-#define STATE_STOPPED  0
-#define STATE_STARTING 1
-#define STATE_PLAYING  2
-#define STATE_STOPPING 3
+#define STATE_STOPPED   0
+#define STATE_STARTING  1
+#define STATE_PLAYING   2
+#define STATE_CAPTURING 2
+#define STATE_STOPPING  3
 
 #define DSOUND_FREQSHIFT (14)
 
@@ -232,3 +294,6 @@
 	PIDSDRIVERBUFFER hwbuf;
 	DWORD state;
 };
+
+extern ICOM_VTABLE(IDirectSoundNotify) dsnvt;
+extern HRESULT mmErr(UINT err);
diff --git a/dlls/dsound/primary.c b/dlls/dsound/primary.c
index 570e7f2..887bf74 100644
--- a/dlls/dsound/primary.c
+++ b/dlls/dsound/primary.c
@@ -47,27 +47,6 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
 
-static HRESULT mmErr(UINT err)
-{
-	switch(err) {
-	case MMSYSERR_NOERROR:
-		return DS_OK;
-	case MMSYSERR_ALLOCATED:
-		return DSERR_ALLOCATED;
-	case MMSYSERR_INVALHANDLE:
-		return DSERR_GENERIC; /* FIXME */
-	case MMSYSERR_NODRIVER:
-		return DSERR_NODRIVER;
-	case MMSYSERR_NOMEM:
-		return DSERR_OUTOFMEMORY;
-	case MMSYSERR_INVALPARAM:
-		return DSERR_INVALIDPARAM;
-	default:
-		FIXME("Unknown MMSYS error %d\n",err);
-		return DSERR_GENERIC;
-	}
-}
-
 void DSOUND_RecalcPrimary(IDirectSoundImpl *This)
 {
 	DWORD sw;
diff --git a/dlls/dsound/tests/dsound.c b/dlls/dsound/tests/dsound.c
index 2be163a..dd54fce 100644
--- a/dlls/dsound/tests/dsound.c
+++ b/dlls/dsound/tests/dsound.c
@@ -22,9 +22,9 @@
 #include <stdlib.h>
 
 #include "wine/test.h"
+#include "wine/debug.h"
 #include "dsound.h"
 
-
 /* The time slice determines how often we will service the buffer and the
  * buffer will be four time slices long
  */
@@ -369,7 +369,7 @@
     WAVEFORMATEX wfx;
     DSCAPS dscaps;
 
-    trace("Testing %s - %s\n",lpcstrDescription,lpcstrModule);
+    trace("Testing %s - %s : %s\n",lpcstrDescription,lpcstrModule,wine_dbgstr_guid(lpGuid));
     rc=DirectSoundCreate(lpGuid,&dso,NULL);
     ok(rc==DS_OK,"DirectSoundCreate failed: 0x%lx\n",rc);
     if (rc!=DS_OK)
@@ -388,6 +388,12 @@
               dscaps.dwMaxSecondarySampleRate);
     }
 
+    /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
+    rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+    ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
     /* Testing the primary buffer */
     bufdesc.dwSize=sizeof(bufdesc);
     bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
@@ -402,6 +408,12 @@
         IDirectSoundBuffer_Release(dsbo);
     }
 
+    /* Set the CooperativeLevel back to normal */
+    rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
+    ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
     /* Testing secondary buffers */
     init_format(&wfx,11025,8,1);
     bufdesc.dwSize=sizeof(bufdesc);
@@ -446,7 +458,344 @@
     ok(rc==DS_OK,"DirectSoundEnumerate failed: %ld\n",rc);
 }
 
+#define NOTIFICATIONS    5
+
+typedef struct {
+    char* wave;
+    DWORD wave_len;
+
+    LPDIRECTSOUNDCAPTUREBUFFER dscbo;
+    LPWAVEFORMATEX wfx;
+    DSBPOSITIONNOTIFY posnotify[NOTIFICATIONS];
+    HANDLE event;
+    LPDIRECTSOUNDNOTIFY notify;
+
+    DWORD buffer_size;
+    DWORD read;
+    DWORD offset;
+
+    DWORD last_pos;
+} capture_state_t;
+
+static int capture_buffer_service(capture_state_t* state)
+{
+    HRESULT rc;
+    LPVOID ptr1,ptr2;
+    DWORD len1,len2;
+    DWORD capture_pos,read_pos;
+    LONG size;
+
+    rc=IDirectSoundCaptureBuffer_GetCurrentPosition(state->dscbo,&capture_pos,&read_pos);
+    ok(rc==DS_OK,"GetCurrentPosition failed: 0x%lx\n",rc);
+    if (rc!=DS_OK)
+        return 0;
+
+    size = state->wfx->nAvgBytesPerSec/NOTIFICATIONS;
+
+    rc=IDirectSoundCaptureBuffer_Lock(state->dscbo,state->offset,size,&ptr1,&len1,&ptr2,&len2,0);
+    ok(rc==DS_OK,"Lock failed: 0x%lx\n",rc);
+    if (rc!=DS_OK)
+        return 0;
+
+    rc=IDirectSoundCaptureBuffer_Unlock(state->dscbo,ptr1,len1,ptr2,len2);
+    ok(rc==DS_OK,"Unlock failed: 0x%lx\n",rc);
+    if (rc!=DS_OK)
+        return 0;
+
+    state->offset = (state->offset + size) % state->wfx->nAvgBytesPerSec;
+
+    return 1;
+}
+
+static void test_capture_buffer(LPDIRECTSOUNDCAPTURE dsco, LPDIRECTSOUNDCAPTUREBUFFER dscbo)
+{
+    HRESULT rc;
+    DSCBCAPS dscbcaps;
+    WAVEFORMATEX wfx;
+    DWORD size,status;
+    capture_state_t state;
+    int i;
+
+    /* Private dsound.dll: Error: Invalid caps pointer */
+    rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,0);
+    ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
+
+    /* Private dsound.dll: Error: Invalid caps pointer */
+    dscbcaps.dwSize=0;
+    rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,&dscbcaps);
+    ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
+
+    dscbcaps.dwSize=sizeof(dscbcaps);
+    rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,&dscbcaps);
+    ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc);
+    if (rc==DS_OK) {
+        trace("    Caps: size = %ld flags=0x%08lx buffer size=%ld\n",
+            dscbcaps.dwSize,dscbcaps.dwFlags,dscbcaps.dwBufferBytes);
+    }
+
+    /* Query the format size. Note that it may not match sizeof(wfx) */
+    /* Private dsound.dll: Error: Either pwfxFormat or pdwSizeWritten must be non-NULL */
+    rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,NULL,0,NULL);
+    ok(rc==DSERR_INVALIDPARAM,
+       "GetFormat should have returned an error: rc=0x%lx\n",rc);
+
+    size=0;
+    rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,NULL,0,&size);
+    ok(rc==DS_OK && size!=0,
+       "GetFormat should have returned the needed size: rc=0x%lx size=%ld\n",
+       rc,size);
+
+    rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,&wfx,sizeof(wfx),NULL);
+    ok(rc==DS_OK,"GetFormat failed: 0x%lx\n",rc);
+    if (rc==DS_OK) {
+        trace("    tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n",
+              wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
+              wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
+    }
+
+    /* Private dsound.dll: Error: Invalid status pointer */
+    rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,0);
+    ok(rc==DSERR_INVALIDPARAM,"GetStatus should have failed: 0x%lx\n",rc);
+
+    rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,&status);
+    ok(rc==DS_OK,"GetStatus failed: 0x%lx\n",rc);
+    if (rc==DS_OK) {
+        trace("    status=0x%04lx\n",status);
+    }
+
+    ZeroMemory(&state, sizeof(state));
+    state.dscbo=dscbo;
+    state.wfx=&wfx;
+    state.buffer_size=dscbcaps.dwBufferBytes;
+    state.event = CreateEvent( NULL, FALSE, FALSE, NULL );
+
+    /* FIXME: I couldn't get this to work in vc6. */
+{
+    GUID IID_IDirectSoundNotifyX = { 0xb0210783, 0x89cd, 0x11d0,{ 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16 } };
+    rc=IDirectSoundCapture_QueryInterface(dscbo,&IID_IDirectSoundNotifyX,(void **)&(state.notify));
+}
+    ok(rc==DS_OK,"QueryInterface failed: 0x%lx\n",rc);
+    if (rc!=DS_OK)
+        return;
+
+    for (i = 0; i < NOTIFICATIONS; i++) {
+        state.posnotify[i].dwOffset = (i * (dscbcaps.dwBufferBytes / NOTIFICATIONS)) + (dscbcaps.dwBufferBytes / NOTIFICATIONS) - 1;
+        state.posnotify[i].hEventNotify = state.event;
+    }
+
+    rc=IDirectSoundNotify_SetNotificationPositions(state.notify,NOTIFICATIONS,state.posnotify);
+    ok(rc==DS_OK,"SetNotificationPositions failed: 0x%lx\n",rc);
+    if (rc!=DS_OK)
+        return;
+
+    rc=IDirectSoundCaptureBuffer_Start(dscbo,DSCBSTART_LOOPING);
+    ok(rc==DS_OK,"Start: 0x%lx\n",rc);
+    if (rc!=DS_OK)
+        return;
+
+    rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,&status);
+    ok(rc==DS_OK,"GetStatus failed: 0x%lx\n",rc);
+    ok(status==(DSCBSTATUS_CAPTURING|DSCBSTATUS_LOOPING),
+       "GetStatus: bad status: %lx",status);
+    if (rc!=DS_OK)
+        return;
+
+    /* wait for the notifications */
+    for (i = 0; i < (NOTIFICATIONS * 2); i++) {
+        rc=MsgWaitForMultipleObjects( 1, &(state.event), FALSE, 100, QS_ALLEVENTS );
+        ok(rc==WAIT_OBJECT_0,"MsgWaitForMultipleObjects failed: 0x%lx\n",rc);
+        if (rc!=WAIT_OBJECT_0)
+            break;
+        if (!capture_buffer_service(&state))
+            break;
+    }
+
+    rc=IDirectSoundCaptureBuffer_Stop(dscbo);
+    ok(rc==DS_OK,"Stop: 0x%lx\n",rc);
+    if (rc!=DS_OK)
+        return;
+    rc=IDirectSoundCaptureBuffer_Release(dscbo);
+    ok(rc==DS_OK,"Release: 0x%lx\n",rc);
+    if (rc!=DS_OK)
+        return;
+}
+
+static BOOL WINAPI dscenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
+                                    LPCSTR lpcstrModule, LPVOID lpContext)
+{
+    HRESULT rc;
+    LPDIRECTSOUNDCAPTURE dsco=NULL;
+    LPDIRECTSOUNDCAPTUREBUFFER dscbo=NULL;
+    DSCBUFFERDESC bufdesc;
+    WAVEFORMATEX wfx;
+    DSCCAPS dsccaps;
+
+    /* Private dsound.dll: Error: Invalid interface buffer */
+    trace("Testing %s - %s : %s\n",lpcstrDescription,lpcstrModule,wine_dbgstr_guid(lpGuid));
+    rc=DirectSoundCaptureCreate(lpGuid,NULL,NULL);
+    ok(rc==DSERR_INVALIDPARAM,"DirectSoundCaptureCreate didn't fail: 0x%lx\n",rc);
+    if (rc==DS_OK)
+        IDirectSoundCapture_Release(dsco);
+
+    rc=DirectSoundCaptureCreate(lpGuid,&dsco,NULL);
+    ok(rc==DS_OK,"DirectSoundCaptureCreate failed: 0x%lx\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    /* Private dsound.dll: Error: Invalid caps buffer */
+    rc=IDirectSoundCapture_GetCaps(dsco,NULL);
+    ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
+
+    /* Private dsound.dll: Error: Invalid caps buffer */
+    dsccaps.dwSize=0;
+    rc=IDirectSoundCapture_GetCaps(dsco,&dsccaps);
+    ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
+
+    dsccaps.dwSize=sizeof(dsccaps);
+    rc=IDirectSoundCapture_GetCaps(dsco,&dsccaps);
+    ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc);
+    if (rc==DS_OK) {
+        trace("  DirectSoundCapture Caps: size=%ld flags=0x%08lx formats=%ld channels=%ld\n",
+              dsccaps.dwSize,dsccaps.dwFlags,dsccaps.dwFormats,dsccaps.dwChannels);
+    }
+
+    /* Private dsound.dll: Error: Invalid size */
+    /* Private dsound.dll: Error: Invalid capture buffer description */
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=0;
+    bufdesc.dwFlags=0;
+    bufdesc.dwBufferBytes=0;
+    bufdesc.dwReserved=0;
+    bufdesc.lpwfxFormat=NULL;
+    rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
+    ok(rc==DSERR_INVALIDPARAM,"CreateCaptureBuffer should have failed to create a capture buffer 0x%lx\n",rc);
+    if (rc==DS_OK) {
+        IDirectSoundCaptureBuffer_Release(dscbo);
+    }
+
+    /* Private dsound.dll: Error: Invalid buffer size */
+    /* Private dsound.dll: Error: Invalid capture buffer description */
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=0;
+    bufdesc.dwBufferBytes=0;
+    bufdesc.dwReserved=0;
+    bufdesc.lpwfxFormat=NULL;
+    rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
+    ok(rc==DSERR_INVALIDPARAM,"CreateCaptureBuffer should have failed to create a capture buffer 0x%lx\n",rc);
+    if (rc==DS_OK) {
+        IDirectSoundCaptureBuffer_Release(dscbo);
+    }
+
+    /* Private dsound.dll: Error: Invalid buffer size */
+    /* Private dsound.dll: Error: Invalid capture buffer description */
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    ZeroMemory(&wfx, sizeof(wfx));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=0;
+    bufdesc.dwBufferBytes=0;
+    bufdesc.dwReserved=0;
+    bufdesc.lpwfxFormat=&wfx;
+    rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
+    ok(rc==DSERR_INVALIDPARAM,"CreateCaptureBuffer should have failed to create a capture buffer 0x%lx\n",rc);
+    if (rc==DS_OK) {
+        IDirectSoundCaptureBuffer_Release(dscbo);
+    }
+
+    /* Private dsound.dll: Error: Invalid buffer size */
+    /* Private dsound.dll: Error: Invalid capture buffer description */
+    init_format(&wfx,11025,8,1);
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=0;
+    bufdesc.dwBufferBytes=0;
+    bufdesc.dwReserved=0;
+    bufdesc.lpwfxFormat=&wfx;
+    rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
+    ok(rc==DSERR_INVALIDPARAM,"CreateCaptureBuffer should have failed to create a capture buffer 0x%lx\n",rc);
+    if (rc==DS_OK) {
+        IDirectSoundCaptureBuffer_Release(dscbo);
+    }
+
+    init_format(&wfx,11025,8,1);
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=0;
+    bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec;
+    bufdesc.dwReserved=0;
+    bufdesc.lpwfxFormat=&wfx;
+    trace("  Testing the capture buffer at %ldx%dx%d\n",
+        wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels);
+    rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
+    ok(rc==DS_OK,"CreateCaptureBuffer failed to create a capture buffer 0x%lx\n",rc);
+    if (rc==DS_OK) {
+        test_capture_buffer(dsco, dscbo);
+        IDirectSoundCaptureBuffer_Release(dscbo);
+    }
+
+    init_format(&wfx,11025,8,1);
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSCBCAPS_WAVEMAPPED;
+    bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec;
+    bufdesc.dwReserved=0;
+    bufdesc.lpwfxFormat=&wfx;
+    trace("  Testing the capture buffer at %ldx%dx%d\n",
+        wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels);
+    rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
+    ok(rc==DS_OK,"CreateCaptureBuffer failed to create a capture buffer 0x%lx\n",rc);
+    if (rc==DS_OK) {
+        test_capture_buffer(dsco, dscbo);
+        IDirectSoundCaptureBuffer_Release(dscbo);
+    }
+
+    init_format(&wfx,11025,16,2);
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=0;
+    bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec;
+    bufdesc.dwReserved=0;
+    bufdesc.lpwfxFormat=&wfx;
+    trace("  Testing the capture buffer at %ldx%dx%d\n",
+        wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels);
+    rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
+    ok(rc==DS_OK,"CreateCaptureBuffer failed to create a capture buffer 0x%lx\n",rc);
+    if (rc==DS_OK) {
+        test_capture_buffer(dsco, dscbo);
+        IDirectSoundCaptureBuffer_Release(dscbo);
+    }
+
+    init_format(&wfx,11025,16,2);
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSCBCAPS_WAVEMAPPED;
+    bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec;
+    bufdesc.dwReserved=0;
+    bufdesc.lpwfxFormat=&wfx;
+    trace("  Testing the capture buffer at %ldx%dx%d\n",
+        wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels);
+    rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
+    ok(rc==DS_OK,"CreateCaptureBuffer failed to create a capture buffer 0x%lx\n",rc);
+    if (rc==DS_OK) {
+        test_capture_buffer(dsco, dscbo);
+        IDirectSoundCaptureBuffer_Release(dscbo);
+    }
+
+EXIT:
+    if (dsco!=NULL)
+        IDirectSoundCapture_Release(dsco);
+    return TRUE;
+}
+
+static void dsound_in_tests()
+{
+    HRESULT rc;
+    rc=DirectSoundCaptureEnumerateA(&dscenum_callback,NULL);
+    ok(rc==DS_OK,"DirectSoundCaptureEnumerate failed: %ld\n",rc);
+}
+
 START_TEST(dsound)
 {
     dsound_out_tests();
+    dsound_in_tests();
 }