- add dsound winetest
authorKamil Hornicek <kamil.hornicek@reactos.org>
Mon, 2 Nov 2009 19:19:39 +0000 (19:19 +0000)
committerKamil Hornicek <kamil.hornicek@reactos.org>
Mon, 2 Nov 2009 19:19:39 +0000 (19:19 +0000)
svn path=/trunk/; revision=43918

rostests/winetests/dsound/capture.c [new file with mode: 0644]
rostests/winetests/dsound/ds3d.c [new file with mode: 0644]
rostests/winetests/dsound/ds3d8.c [new file with mode: 0644]
rostests/winetests/dsound/dsound.c [new file with mode: 0644]
rostests/winetests/dsound/dsound.rbuild [new file with mode: 0644]
rostests/winetests/dsound/dsound8.c [new file with mode: 0644]
rostests/winetests/dsound/dsound_test.h [new file with mode: 0644]
rostests/winetests/dsound/duplex.c [new file with mode: 0644]
rostests/winetests/dsound/propset.c [new file with mode: 0644]
rostests/winetests/dsound/testlist.c [new file with mode: 0644]

diff --git a/rostests/winetests/dsound/capture.c b/rostests/winetests/dsound/capture.c
new file mode 100644 (file)
index 0000000..87a5a59
--- /dev/null
@@ -0,0 +1,709 @@
+/*
+ * Unit tests for capture functions
+ *
+ * Copyright (c) 2002 Francois Gouget
+ * Copyright (c) 2003 Robert Reif
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdio.h>
+#include "initguid.h"
+#include "windows.h"
+#include "wine/test.h"
+#include "dsound.h"
+#include "mmreg.h"
+#include "dsconf.h"
+
+#include "dsound_test.h"
+
+#define NOTIFICATIONS    5
+
+static HRESULT (WINAPI *pDirectSoundCaptureCreate)(LPCGUID,LPDIRECTSOUNDCAPTURE*,LPUNKNOWN)=NULL;
+static HRESULT (WINAPI *pDirectSoundCaptureEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL;
+
+static const char * get_format_str(WORD format)
+{
+    static char msg[32];
+#define WAVE_FORMAT(f) case f: return #f
+    switch (format) {
+    WAVE_FORMAT(WAVE_FORMAT_PCM);
+    WAVE_FORMAT(WAVE_FORMAT_ADPCM);
+    WAVE_FORMAT(WAVE_FORMAT_IBM_CVSD);
+    WAVE_FORMAT(WAVE_FORMAT_ALAW);
+    WAVE_FORMAT(WAVE_FORMAT_MULAW);
+    WAVE_FORMAT(WAVE_FORMAT_OKI_ADPCM);
+    WAVE_FORMAT(WAVE_FORMAT_IMA_ADPCM);
+    WAVE_FORMAT(WAVE_FORMAT_MEDIASPACE_ADPCM);
+    WAVE_FORMAT(WAVE_FORMAT_SIERRA_ADPCM);
+    WAVE_FORMAT(WAVE_FORMAT_G723_ADPCM);
+    WAVE_FORMAT(WAVE_FORMAT_DIGISTD);
+    WAVE_FORMAT(WAVE_FORMAT_DIGIFIX);
+    WAVE_FORMAT(WAVE_FORMAT_DIALOGIC_OKI_ADPCM);
+    WAVE_FORMAT(WAVE_FORMAT_YAMAHA_ADPCM);
+    WAVE_FORMAT(WAVE_FORMAT_SONARC);
+    WAVE_FORMAT(WAVE_FORMAT_DSPGROUP_TRUESPEECH);
+    WAVE_FORMAT(WAVE_FORMAT_ECHOSC1);
+    WAVE_FORMAT(WAVE_FORMAT_AUDIOFILE_AF36);
+    WAVE_FORMAT(WAVE_FORMAT_APTX);
+    WAVE_FORMAT(WAVE_FORMAT_AUDIOFILE_AF10);
+    WAVE_FORMAT(WAVE_FORMAT_DOLBY_AC2);
+    WAVE_FORMAT(WAVE_FORMAT_GSM610);
+    WAVE_FORMAT(WAVE_FORMAT_ANTEX_ADPCME);
+    WAVE_FORMAT(WAVE_FORMAT_CONTROL_RES_VQLPC);
+    WAVE_FORMAT(WAVE_FORMAT_DIGIREAL);
+    WAVE_FORMAT(WAVE_FORMAT_DIGIADPCM);
+    WAVE_FORMAT(WAVE_FORMAT_CONTROL_RES_CR10);
+    WAVE_FORMAT(WAVE_FORMAT_NMS_VBXADPCM);
+    WAVE_FORMAT(WAVE_FORMAT_G721_ADPCM);
+    WAVE_FORMAT(WAVE_FORMAT_MPEG);
+    WAVE_FORMAT(WAVE_FORMAT_MPEGLAYER3);
+    WAVE_FORMAT(WAVE_FORMAT_CREATIVE_ADPCM);
+    WAVE_FORMAT(WAVE_FORMAT_CREATIVE_FASTSPEECH8);
+    WAVE_FORMAT(WAVE_FORMAT_CREATIVE_FASTSPEECH10);
+    WAVE_FORMAT(WAVE_FORMAT_FM_TOWNS_SND);
+    WAVE_FORMAT(WAVE_FORMAT_OLIGSM);
+    WAVE_FORMAT(WAVE_FORMAT_OLIADPCM);
+    WAVE_FORMAT(WAVE_FORMAT_OLICELP);
+    WAVE_FORMAT(WAVE_FORMAT_OLISBC);
+    WAVE_FORMAT(WAVE_FORMAT_OLIOPR);
+    WAVE_FORMAT(WAVE_FORMAT_DEVELOPMENT);
+    WAVE_FORMAT(WAVE_FORMAT_EXTENSIBLE);
+    }
+#undef WAVE_FORMAT
+    sprintf(msg, "Unknown(0x%04x)", format);
+    return msg;
+}
+
+const char * format_string(const WAVEFORMATEX* wfx)
+{
+    static char str[64];
+
+    sprintf(str, "%5dx%2dx%d %s",
+       wfx->nSamplesPerSec, wfx->wBitsPerSample, wfx->nChannels,
+        get_format_str(wfx->wFormatTag));
+
+    return str;
+}
+
+static void IDirectSoundCapture_test(LPDIRECTSOUNDCAPTURE dsco,
+                                     BOOL initialized, LPCGUID lpGuid)
+{
+    HRESULT rc;
+    DSCCAPS dsccaps;
+    int ref;
+    IUnknown * unknown;
+    IDirectSoundCapture * dsc;
+
+    /* Try to Query for objects */
+    rc=IDirectSoundCapture_QueryInterface(dsco, &IID_IUnknown,
+                                          (LPVOID*)&unknown);
+    ok(rc==DS_OK, "IDirectSoundCapture_QueryInterface(IID_IUnknown) "
+       "failed: %08x\n", rc);
+    if (rc==DS_OK)
+        IDirectSoundCapture_Release(unknown);
+
+    rc=IDirectSoundCapture_QueryInterface(dsco, &IID_IDirectSoundCapture,
+                                          (LPVOID*)&dsc);
+    ok(rc==DS_OK, "IDirectSoundCapture_QueryInterface(IID_IDirectSoundCapture) "
+       "failed: %08x\n", rc);
+    if (rc==DS_OK)
+        IDirectSoundCapture_Release(dsc);
+
+    if (initialized == FALSE) {
+        /* try uninitialized object */
+        rc=IDirectSoundCapture_GetCaps(dsco,0);
+        ok(rc==DSERR_UNINITIALIZED||rc==E_INVALIDARG,
+           "IDirectSoundCapture_GetCaps(NULL) should have returned "
+           "DSERR_UNINITIALIZED or E_INVALIDARG, returned: %08x\n", rc);
+
+        rc=IDirectSoundCapture_GetCaps(dsco, &dsccaps);
+        ok(rc==DSERR_UNINITIALIZED,"IDirectSoundCapture_GetCaps() "
+           "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc);
+
+        rc=IDirectSoundCapture_Initialize(dsco, lpGuid);
+        ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||
+           rc==E_FAIL||rc==E_INVALIDARG,
+           "IDirectSoundCapture_Initialize() failed: %08x\n", rc);
+        if (rc==DSERR_NODRIVER||rc==E_INVALIDARG) {
+            trace("  No Driver\n");
+            goto EXIT;
+        } else if (rc==E_FAIL) {
+            trace("  No Device\n");
+            goto EXIT;
+        } else if (rc==DSERR_ALLOCATED) {
+            trace("  Already In Use\n");
+            goto EXIT;
+        }
+    }
+
+    rc=IDirectSoundCapture_Initialize(dsco, lpGuid);
+    ok(rc==DSERR_ALREADYINITIALIZED, "IDirectSoundCapture_Initialize() "
+       "should have returned DSERR_ALREADYINITIALIZED: %08x\n", rc);
+
+    /* DSOUND: Error: Invalid caps buffer */
+    rc=IDirectSoundCapture_GetCaps(dsco, 0);
+    ok(rc==DSERR_INVALIDPARAM, "IDirectSoundCapture_GetCaps(NULL) "
+       "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+
+    ZeroMemory(&dsccaps, sizeof(dsccaps));
+
+    /* DSOUND: Error: Invalid caps buffer */
+    rc=IDirectSound_GetCaps(dsco, &dsccaps);
+    ok(rc==DSERR_INVALIDPARAM, "IDirectSound_GetCaps() "
+       "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+
+    dsccaps.dwSize=sizeof(dsccaps);
+
+    /* DSOUND: Running on a certified driver */
+    rc=IDirectSoundCapture_GetCaps(dsco, &dsccaps);
+    ok(rc==DS_OK, "IDirectSoundCapture_GetCaps() failed: %08x\n", rc);
+
+EXIT:
+    ref=IDirectSoundCapture_Release(dsco);
+    ok(ref==0, "IDirectSoundCapture_Release() has %d references, "
+       "should have 0\n", ref);
+}
+
+static void IDirectSoundCapture_tests(void)
+{
+    HRESULT rc;
+    LPDIRECTSOUNDCAPTURE dsco=NULL;
+    LPCLASSFACTORY cf=NULL;
+
+    trace("Testing IDirectSoundCapture\n");
+
+    rc=CoGetClassObject(&CLSID_DirectSoundCapture, CLSCTX_INPROC_SERVER, NULL,
+                        &IID_IClassFactory, (void**)&cf);
+    ok(rc==S_OK,"CoGetClassObject(CLSID_DirectSoundCapture, IID_IClassFactory) "
+       "failed: %08x\n", rc);
+
+    rc=CoGetClassObject(&CLSID_DirectSoundCapture, CLSCTX_INPROC_SERVER, NULL,
+                        &IID_IUnknown, (void**)&cf);
+    ok(rc==S_OK,"CoGetClassObject(CLSID_DirectSoundCapture, IID_IUnknown) "
+       "failed: %08x\n", rc);
+
+    /* try the COM class factory method of creation with no device specified */
+    rc=CoCreateInstance(&CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER,
+                        &IID_IDirectSoundCapture, (void**)&dsco);
+    ok(rc==S_OK||rc==REGDB_E_CLASSNOTREG,"CoCreateInstance(CLSID_DirectSoundCapture) failed: %08x\n", rc);
+    if (rc==REGDB_E_CLASSNOTREG) {
+        trace("  Class Not Registered\n");
+        return;
+    }
+    if (dsco)
+        IDirectSoundCapture_test(dsco, FALSE, NULL);
+
+    /* try the COM class factory method of creation with default capture
+     * device specified */
+    rc=CoCreateInstance(&CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER,
+                        &IID_IDirectSoundCapture, (void**)&dsco);
+    ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSoundCapture) failed: %08x\n", rc);
+    if (dsco)
+        IDirectSoundCapture_test(dsco, FALSE, &DSDEVID_DefaultCapture);
+
+    /* try the COM class factory method of creation with default voice
+     * capture device specified */
+    rc=CoCreateInstance(&CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER,
+                        &IID_IDirectSoundCapture, (void**)&dsco);
+    ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSoundCapture) failed: %08x\n", rc);
+    if (dsco)
+        IDirectSoundCapture_test(dsco, FALSE, &DSDEVID_DefaultVoiceCapture);
+
+    /* try the COM class factory method of creation with a bad
+     * IID specified */
+    rc=CoCreateInstance(&CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER,
+                        &CLSID_DirectSoundPrivate, (void**)&dsco);
+    ok(rc==E_NOINTERFACE,
+       "CoCreateInstance(CLSID_DirectSoundCapture,CLSID_DirectSoundPrivate) "
+       "should have failed: %08x\n",rc);
+
+    /* try with no device specified */
+    rc=pDirectSoundCaptureCreate(NULL,&dsco,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
+       "DirectSoundCaptureCreate(NULL) failed: %08x\n",rc);
+    if (rc==S_OK && dsco)
+        IDirectSoundCapture_test(dsco, TRUE, NULL);
+
+    /* try with default capture device specified */
+    rc=pDirectSoundCaptureCreate(&DSDEVID_DefaultCapture,&dsco,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
+       "DirectSoundCaptureCreate(DSDEVID_DefaultCapture) failed: %08x\n", rc);
+    if (rc==DS_OK && dsco)
+        IDirectSoundCapture_test(dsco, TRUE, NULL);
+
+    /* try with default voice capture device specified */
+    rc=pDirectSoundCaptureCreate(&DSDEVID_DefaultVoiceCapture,&dsco,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
+       "DirectSoundCaptureCreate(DSDEVID_DefaultVoiceCapture) failed: %08x\n", rc);
+    if (rc==DS_OK && dsco)
+        IDirectSoundCapture_test(dsco, TRUE, NULL);
+
+    /* try with a bad device specified */
+    rc=pDirectSoundCaptureCreate(&DSDEVID_DefaultVoicePlayback,&dsco,NULL);
+    ok(rc==DSERR_NODRIVER,
+       "DirectSoundCaptureCreate(DSDEVID_DefaultVoicePlatback) "
+       "should have failed: %08x\n",rc);
+    if (rc==DS_OK && dsco)
+        IDirectSoundCapture_Release(dsco);
+}
+
+typedef struct {
+    char* wave;
+    DWORD wave_len;
+
+    LPDIRECTSOUNDCAPTUREBUFFER dscbo;
+    LPWAVEFORMATEX wfx;
+    DSBPOSITIONNOTIFY posnotify[NOTIFICATIONS];
+    HANDLE event[NOTIFICATIONS];
+    LPDIRECTSOUNDNOTIFY notify;
+
+    DWORD buffer_size;
+    DWORD read;
+    DWORD offset;
+    DWORD size;
+
+    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;
+
+    rc=IDirectSoundCaptureBuffer_GetCurrentPosition(state->dscbo,&capture_pos,
+                                                    &read_pos);
+    ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetCurrentPosition() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+       return 0;
+
+    rc=IDirectSoundCaptureBuffer_Lock(state->dscbo,state->offset,state->size,
+                                      &ptr1,&len1,&ptr2,&len2,0);
+    ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Lock() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+       return 0;
+
+    rc=IDirectSoundCaptureBuffer_Unlock(state->dscbo,ptr1,len1,ptr2,len2);
+    ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Unlock() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+       return 0;
+
+    state->offset = (state->offset + state->size) % state->buffer_size;
+
+    return 1;
+}
+
+static void test_capture_buffer(LPDIRECTSOUNDCAPTURE dsco,
+                               LPDIRECTSOUNDCAPTUREBUFFER dscbo, int record)
+{
+    HRESULT rc;
+    DSCBCAPS dscbcaps;
+    WAVEFORMATEX wfx;
+    DWORD size,status;
+    capture_state_t state;
+    int i, ref;
+
+    /* Private dsound.dll: Error: Invalid caps pointer */
+    rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,0);
+    ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCaptureBuffer_GetCaps() should "
+       "have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+
+    /* Private dsound.dll: Error: Invalid caps pointer */
+    dscbcaps.dwSize=0;
+    rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,&dscbcaps);
+    ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCaptureBuffer_GetCaps() should "
+       "have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+
+    dscbcaps.dwSize=sizeof(dscbcaps);
+    rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,&dscbcaps);
+    ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetCaps() failed: %08x\n", rc);
+    if (rc==DS_OK && winetest_debug > 1) {
+       trace("    Caps: size = %d flags=0x%08x buffer size=%d\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,"IDirectSoundCaptureBuffer_GetFormat() should "
+       "have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+
+    size=0;
+    rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,NULL,0,&size);
+    ok(rc==DS_OK && size!=0,"IDirectSoundCaptureBuffer_GetFormat() should "
+       "have returned the needed size: rc=%08x, size=%d\n", rc,size);
+
+    rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,&wfx,sizeof(wfx),NULL);
+    ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetFormat() failed: %08x\n", rc);
+    if (rc==DS_OK && winetest_debug > 1) {
+       trace("    Format: tag=0x%04x %dx%dx%d avg.B/s=%d 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,"IDirectSoundCaptureBuffer_GetStatus() should "
+       "have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+
+    rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,&status);
+    ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetStatus() failed: %08x\n", rc);
+    if (rc==DS_OK && winetest_debug > 1) {
+       trace("    Status=0x%04x\n",status);
+    }
+
+    ZeroMemory(&state, sizeof(state));
+    state.dscbo=dscbo;
+    state.wfx=&wfx;
+    state.buffer_size = dscbcaps.dwBufferBytes;
+    for (i = 0; i < NOTIFICATIONS; i++)
+       state.event[i] = CreateEvent( NULL, FALSE, FALSE, NULL );
+    state.size = dscbcaps.dwBufferBytes / NOTIFICATIONS;
+
+    rc=IDirectSoundCaptureBuffer_QueryInterface(dscbo,&IID_IDirectSoundNotify,
+                                                (void **)&(state.notify));
+    ok((rc==DS_OK)&&(state.notify!=NULL),
+       "IDirectSoundCaptureBuffer_QueryInterface() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+       return;
+
+    for (i = 0; i < NOTIFICATIONS; i++) {
+       state.posnotify[i].dwOffset = (i * state.size) + state.size - 1;
+       state.posnotify[i].hEventNotify = state.event[i];
+    }
+
+    rc=IDirectSoundNotify_SetNotificationPositions(state.notify,NOTIFICATIONS,
+                                                   state.posnotify);
+    ok(rc==DS_OK,"IDirectSoundNotify_SetNotificationPositions() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+       return;
+
+    ref=IDirectSoundNotify_Release(state.notify);
+    ok(ref==0,"IDirectSoundNotify_Release(): has %d references, should have "
+       "0\n",ref);
+    if (ref!=0)
+       return;
+
+    if (record) {
+       rc=IDirectSoundCaptureBuffer_Start(dscbo,DSCBSTART_LOOPING);
+       ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Start() failed: %08x\n", rc);
+       if (rc!=DS_OK)
+           return;
+
+       rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,&status);
+       ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetStatus() failed: %08x\n", rc);
+       ok(status==(DSCBSTATUS_CAPTURING|DSCBSTATUS_LOOPING),
+           "GetStatus: bad status: %x\n",status);
+       if (rc!=DS_OK)
+           return;
+
+       /* wait for the notifications */
+       for (i = 0; i < (NOTIFICATIONS * 2); i++) {
+           rc=WaitForMultipleObjects(NOTIFICATIONS,state.event,FALSE,3000);
+           ok(rc==(WAIT_OBJECT_0+(i%NOTIFICATIONS)),
+               "WaitForMultipleObjects failed: 0x%x\n",rc);
+           if (rc!=(WAIT_OBJECT_0+(i%NOTIFICATIONS))) {
+               ok((rc==WAIT_TIMEOUT)||(rc==WAIT_FAILED),
+                   "Wrong notification: should be %d, got %d\n",
+                   i%NOTIFICATIONS,rc-WAIT_OBJECT_0);
+           }
+           if (!capture_buffer_service(&state))
+               break;
+       }
+
+       rc=IDirectSoundCaptureBuffer_Stop(dscbo);
+       ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Stop() failed: %08x\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;
+    DWORD f;
+    int ref;
+
+    /* Private dsound.dll: Error: Invalid interface buffer */
+    trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule);
+    rc=pDirectSoundCaptureCreate(lpGuid,NULL,NULL);
+    ok(rc==DSERR_INVALIDPARAM,"DirectSoundCaptureCreate() should have "
+       "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+    rc=pDirectSoundCaptureCreate(lpGuid,&dsco,NULL);
+    ok((rc==DS_OK)||(rc==DSERR_NODRIVER)||(rc==E_FAIL)||(rc==DSERR_ALLOCATED),
+       "DirectSoundCaptureCreate() failed: %08x\n",rc);
+    if (rc!=DS_OK) {
+        if (rc==DSERR_NODRIVER)
+            trace("  No Driver\n");
+        else if (rc==E_FAIL)
+            trace("  No Device\n");
+        else if (rc==DSERR_ALLOCATED)
+            trace("  Already In Use\n");
+       goto EXIT;
+    }
+
+    /* Private dsound.dll: Error: Invalid caps buffer */
+    rc=IDirectSoundCapture_GetCaps(dsco,NULL);
+    ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_GetCaps() should have "
+       "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+    /* Private dsound.dll: Error: Invalid caps buffer */
+    dsccaps.dwSize=0;
+    rc=IDirectSoundCapture_GetCaps(dsco,&dsccaps);
+    ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_GetCaps() should have "
+       "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+    dsccaps.dwSize=sizeof(dsccaps);
+    rc=IDirectSoundCapture_GetCaps(dsco,&dsccaps);
+    ok(rc==DS_OK,"IDirectSoundCapture_GetCaps() failed: %08x\n", rc);
+    if (rc==DS_OK && winetest_debug > 1) {
+       trace("  Caps: size=%d flags=0x%08x formats=%05x channels=%d\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,"IDirectSoundCapture_CreateCaptureBuffer() "
+       "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+    if (rc==DS_OK) {
+       ref=IDirectSoundCaptureBuffer_Release(dscbo);
+       ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, "
+           "should have 0\n",ref);
+    }
+
+    /* 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,"IDirectSoundCapture_CreateCaptureBuffer() "
+       "should have returned DSERR_INVALIDPARAM, returned %08x\n", rc);
+    if (rc==DS_OK) {
+       ref=IDirectSoundCaptureBuffer_Release(dscbo);
+       ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, "
+           "should have 0\n",ref);
+    }
+
+    /* 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,"IDirectSoundCapture_CreateCaptureBuffer() "
+       "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+    if (rc==DS_OK) {
+       ref=IDirectSoundCaptureBuffer_Release(dscbo);
+       ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, "
+           "should have 0\n",ref);
+    }
+
+    /* Private dsound.dll: Error: Invalid buffer size */
+    /* Private dsound.dll: Error: Invalid capture buffer description */
+    init_format(&wfx,WAVE_FORMAT_PCM,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,"IDirectSoundCapture_CreateCaptureBuffer() "
+       "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+    if (rc==DS_OK) {
+       ref=IDirectSoundCaptureBuffer_Release(dscbo);
+       ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, "
+           "should have 0\n",ref);
+    }
+
+    for (f=0;f<NB_FORMATS;f++) {
+       dscbo=NULL;
+       init_format(&wfx,WAVE_FORMAT_PCM,formats[f][0],formats[f][1],
+                    formats[f][2]);
+       ZeroMemory(&bufdesc, sizeof(bufdesc));
+       bufdesc.dwSize=sizeof(bufdesc);
+       bufdesc.dwFlags=0;
+       bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec;
+       bufdesc.dwReserved=0;
+       bufdesc.lpwfxFormat=&wfx;
+        if (winetest_interactive)
+           trace("  Testing the capture buffer at %s\n", format_string(&wfx));
+       rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
+       ok(((rc==DS_OK)&&(dscbo!=NULL))
+           || rc==DSERR_BADFORMAT || rc==DSERR_INVALIDCALL || rc==DSERR_NODRIVER
+           || rc==DSERR_ALLOCATED || rc==E_INVALIDARG || rc==E_FAIL,
+           "IDirectSoundCapture_CreateCaptureBuffer() failed to create a "
+           "%s capture buffer: %08x\n",format_string(&wfx),rc);
+       if (rc==DS_OK) {
+           test_capture_buffer(dsco, dscbo, winetest_interactive);
+           ref=IDirectSoundCaptureBuffer_Release(dscbo);
+           ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, "
+               "should have 0\n",ref);
+       } else if (rc==DSERR_BADFORMAT) {
+            ok(!(dsccaps.dwFormats & formats[f][3]),
+               "IDirectSoundCapture_CreateCaptureBuffer() failed to create a "
+               "capture buffer: format listed as supported but using it failed\n");
+            if (!(dsccaps.dwFormats & formats[f][3]))
+                trace("  Format not supported: %s\n", format_string(&wfx));
+        } else if (rc==DSERR_NODRIVER) {
+            trace("  No Driver\n");
+        } else if (rc==DSERR_ALLOCATED) {
+            trace("  Already In Use\n");
+        } else if (rc==E_INVALIDARG) { /* try the old version struct */
+            DSCBUFFERDESC1 bufdesc1;
+           ZeroMemory(&bufdesc1, sizeof(bufdesc1));
+           bufdesc1.dwSize=sizeof(bufdesc1);
+           bufdesc1.dwFlags=0;
+           bufdesc1.dwBufferBytes=wfx.nAvgBytesPerSec;
+           bufdesc1.dwReserved=0;
+           bufdesc1.lpwfxFormat=&wfx;
+           rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,
+                (DSCBUFFERDESC*)&bufdesc1,&dscbo,NULL);
+            ok(rc==DS_OK || broken(rc==DSERR_INVALIDPARAM),
+               "IDirectSoundCapture_CreateCaptureBuffer() failed to create a "
+               "%s capture buffer: %08x\n",format_string(&wfx), rc);
+            if (rc==DSERR_INVALIDPARAM) {
+                skip("broken driver\n");
+                goto EXIT;
+            }
+            if (rc==DS_OK) {
+               test_capture_buffer(dsco, dscbo, winetest_interactive);
+               ref=IDirectSoundCaptureBuffer_Release(dscbo);
+               ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d "
+                   "references, should have 0\n",ref);
+            }
+        } else if (rc==E_FAIL) {
+            /* WAVE_FORMAT_PCM only allows 8 and 16 bits per sample, so only
+             * report a failure if the bits per sample is 8 or 16
+             */
+            if (wfx.wBitsPerSample == 8 || wfx.wBitsPerSample == 16)
+                ok(FALSE,"Should not fail for 8 or 16 bits per sample\n");
+        }
+    }
+
+    /* try a non PCM format */
+    if (0)
+    {
+    /* FIXME: Why is this commented out? */
+    init_format(&wfx,WAVE_FORMAT_MULAW,8000,8,1);
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSCBCAPS_WAVEMAPPED;
+    bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec;
+    bufdesc.dwReserved=0;
+    bufdesc.lpwfxFormat=&wfx;
+    if (winetest_interactive)
+        trace("  Testing the capture buffer at %s\n", format_string(&wfx));
+    rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
+    ok((rc==DS_OK)&&(dscbo!=NULL),"IDirectSoundCapture_CreateCaptureBuffer() "
+       "failed to create a capture buffer: %08x\n",rc);
+    if ((rc==DS_OK)&&(dscbo!=NULL)) {
+       test_capture_buffer(dsco, dscbo, winetest_interactive);
+       ref=IDirectSoundCaptureBuffer_Release(dscbo);
+       ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, "
+           "should have 0\n",ref);
+    }
+    }
+
+    /* Try an invalid format to test error handling */
+    if (0)
+    {
+    /* FIXME: Remove this test altogether? */
+    init_format(&wfx,WAVE_FORMAT_PCM,2000000,16,2);
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSCBCAPS_WAVEMAPPED;
+    bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec;
+    bufdesc.dwReserved=0;
+    bufdesc.lpwfxFormat=&wfx;
+    if (winetest_interactive)
+        trace("  Testing the capture buffer at %s\n", format_string(&wfx));
+    rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
+    ok(rc!=DS_OK,"IDirectSoundCapture_CreateCaptureBuffer() should have failed "
+       "at 2 MHz %08x\n",rc);
+    }
+
+EXIT:
+    if (dsco!=NULL) {
+       ref=IDirectSoundCapture_Release(dsco);
+       ok(ref==0,"IDirectSoundCapture_Release() has %d references, should "
+           "have 0\n",ref);
+    }
+
+    return TRUE;
+}
+
+static void capture_tests(void)
+{
+    HRESULT rc;
+    rc=pDirectSoundCaptureEnumerateA(&dscenum_callback,NULL);
+    ok(rc==DS_OK,"DirectSoundCaptureEnumerateA() failed: %08x\n", rc);
+}
+
+START_TEST(capture)
+{
+    HMODULE hDsound;
+
+    CoInitialize(NULL);
+
+    hDsound = LoadLibrary("dsound.dll");
+    if (hDsound)
+    {
+
+        pDirectSoundCaptureCreate=(void*)GetProcAddress(hDsound,
+            "DirectSoundCaptureCreate");
+        pDirectSoundCaptureEnumerateA=(void*)GetProcAddress(hDsound,
+            "DirectSoundCaptureEnumerateA");
+        if (pDirectSoundCaptureCreate && pDirectSoundCaptureEnumerateA)
+        {
+            IDirectSoundCapture_tests();
+            capture_tests();
+        }
+        else
+            skip("capture test skipped\n");
+
+        FreeLibrary(hDsound);
+    }
+    else
+        skip("dsound.dll not found!\n");
+
+    CoUninitialize();
+}
diff --git a/rostests/winetests/dsound/ds3d.c b/rostests/winetests/dsound/ds3d.c
new file mode 100644 (file)
index 0000000..71ff2ab
--- /dev/null
@@ -0,0 +1,1297 @@
+/*
+ * Tests the panning and 3D functions of DirectSound
+ *
+ * Part of this test involves playing test tones. But this only makes
+ * sense if someone is going to carefully listen to it, and would only
+ * bother everyone else.
+ * So this is only done if the test is being run in interactive mode.
+ *
+ * Copyright (c) 2002-2004 Francois Gouget
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <windows.h>
+
+#include <math.h>
+
+#include "wine/test.h"
+#include "dsound.h"
+#include "mmreg.h"
+#include "dsound_test.h"
+
+#define PI 3.14159265358979323846
+
+
+static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL;
+static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID,LPDIRECTSOUND*,
+    LPUNKNOWN)=NULL;
+
+char* wave_generate_la(WAVEFORMATEX* wfx, double duration, DWORD* size)
+{
+    int i;
+    int nb_samples;
+    char* buf;
+    char* b;
+
+    nb_samples=(int)(duration*wfx->nSamplesPerSec);
+    *size=nb_samples*wfx->nBlockAlign;
+    b=buf=HeapAlloc(GetProcessHeap(), 0, *size);
+    for (i=0;i<nb_samples;i++) {
+        double y=sin(440.0*2*PI*i/wfx->nSamplesPerSec);
+        if (wfx->wBitsPerSample==8) {
+            unsigned char sample=(unsigned char)((double)127.5*(y+1.0));
+            *b++=sample;
+            if (wfx->nChannels==2)
+                *b++=sample;
+        } else if (wfx->wBitsPerSample == 16) {
+            signed short sample=(signed short)((double)32767.5*y-0.5);
+            b[0]=sample & 0xff;
+            b[1]=sample >> 8;
+            b+=2;
+            if (wfx->nChannels==2) {
+                b[0]=sample & 0xff;
+                b[1]=sample >> 8;
+                b+=2;
+            }
+        } else if (wfx->wBitsPerSample == 24) {
+            signed int sample=(signed int)((double)8388607.5*y-0.5);
+            b[0]=sample & 0xff;
+            b[1]=(sample >> 8)&0xff;
+            b[2]=sample >> 16;
+            b+=3;
+            if (wfx->nChannels==2) {
+                b[0]=sample & 0xff;
+                b[1]=(sample >> 8)&0xff;
+                b[2]=sample >> 16;
+                b+=3;
+            }
+        } else if (wfx->wBitsPerSample == 32) {
+            signed int sample=(signed int)((double)2147483647.5*y-0.5);
+            b[0]=sample & 0xff;
+            b[1]=(sample >> 8)&0xff;
+            b[2]=(sample >> 16)&0xff;
+            b[3]=sample >> 24;
+            b+=4;
+            if (wfx->nChannels==2) {
+                b[0]=sample & 0xff;
+                b[1]=(sample >> 8)&0xff;
+                b[2]=(sample >> 16)&0xff;
+                b[3]=sample >> 24;
+                b+=4;
+            }
+        }
+    }
+    return buf;
+}
+
+const char * getDSBCAPS(DWORD xmask) {
+    static struct {
+        DWORD   mask;
+        const char    *name;
+    } flags[] = {
+#define FE(x) { x, #x },
+        FE(DSBCAPS_PRIMARYBUFFER)
+        FE(DSBCAPS_STATIC)
+        FE(DSBCAPS_LOCHARDWARE)
+        FE(DSBCAPS_LOCSOFTWARE)
+        FE(DSBCAPS_CTRL3D)
+        FE(DSBCAPS_CTRLFREQUENCY)
+        FE(DSBCAPS_CTRLPAN)
+        FE(DSBCAPS_CTRLVOLUME)
+        FE(DSBCAPS_CTRLPOSITIONNOTIFY)
+        FE(DSBCAPS_STICKYFOCUS)
+        FE(DSBCAPS_GLOBALFOCUS)
+        FE(DSBCAPS_GETCURRENTPOSITION2)
+        FE(DSBCAPS_MUTE3DATMAXDISTANCE)
+#undef FE
+    };
+    static char buffer[512];
+    unsigned int i;
+    BOOL first = TRUE;
+
+    buffer[0] = 0;
+
+    for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++) {
+        if ((flags[i].mask & xmask) == flags[i].mask) {
+            if (first)
+                first = FALSE;
+            else
+                strcat(buffer, "|");
+            strcat(buffer, flags[i].name);
+        }
+    }
+
+    return buffer;
+}
+
+HWND get_hwnd(void)
+{
+    HWND hwnd=GetForegroundWindow();
+    if (!hwnd)
+        hwnd=GetDesktopWindow();
+    return hwnd;
+}
+
+void init_format(WAVEFORMATEX* wfx, int format, int rate, int depth,
+                 int channels)
+{
+    wfx->wFormatTag=format;
+    wfx->nChannels=channels;
+    wfx->wBitsPerSample=depth;
+    wfx->nSamplesPerSec=rate;
+    wfx->nBlockAlign=wfx->nChannels*wfx->wBitsPerSample/8;
+    /* FIXME: Shouldn't this test be if (format!=WAVE_FORMAT_PCM) */
+    if (wfx->nBlockAlign==0)
+    {
+        /* align compressed formats to byte boundary */
+        wfx->nBlockAlign=1;
+    }
+    wfx->nAvgBytesPerSec=wfx->nSamplesPerSec*wfx->nBlockAlign;
+    wfx->cbSize=0;
+}
+
+typedef struct {
+    char* wave;
+    DWORD wave_len;
+
+    LPDIRECTSOUNDBUFFER dsbo;
+    LPWAVEFORMATEX wfx;
+    DWORD buffer_size;
+    DWORD written;
+    DWORD played;
+    DWORD offset;
+} play_state_t;
+
+static int buffer_refill(play_state_t* state, DWORD size)
+{
+    LPVOID ptr1,ptr2;
+    DWORD len1,len2;
+    HRESULT rc;
+
+    if (size>state->wave_len-state->written)
+        size=state->wave_len-state->written;
+
+    /* some broken apps like Navyfield mistakenly pass NULL for a ppValue */
+    rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size,
+                               &ptr1,NULL,&ptr2,&len2,0);
+    ok(rc==DSERR_INVALIDPARAM,"expected %08x got %08x\n",DSERR_INVALIDPARAM, rc);
+    rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size,
+                               &ptr1,&len1,&ptr2,&len2,0);
+    ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        return -1;
+
+    memcpy(ptr1,state->wave+state->written,len1);
+    state->written+=len1;
+    if (ptr2!=NULL) {
+        memcpy(ptr2,state->wave+state->written,len2);
+        state->written+=len2;
+    }
+    state->offset=state->written % state->buffer_size;
+    /* some apps blindly pass &ptr1 instead of ptr1 */
+    rc=IDirectSoundBuffer_Unlock(state->dsbo,&ptr1,len1,ptr2,len2);
+    ok(rc==DSERR_INVALIDPARAM, "IDDirectSoundBuffer_Unlock(): expected %08x got %08x, %p %p\n",DSERR_INVALIDPARAM, rc, &ptr1, ptr1);
+    rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2);
+    ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        return -1;
+    return size;
+}
+
+static int buffer_silence(play_state_t* state, DWORD size)
+{
+    LPVOID ptr1,ptr2;
+    DWORD len1,len2;
+    HRESULT rc;
+    BYTE s;
+
+    rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size,
+                               &ptr1,&len1,&ptr2,&len2,0);
+    ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        return -1;
+
+    s=(state->wfx->wBitsPerSample==8?0x80:0);
+    memset(ptr1,s,len1);
+    if (ptr2!=NULL) {
+        memset(ptr2,s,len2);
+    }
+    state->offset=(state->offset+size) % state->buffer_size;
+    rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2);
+    ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        return -1;
+    return size;
+}
+
+static int buffer_service(play_state_t* state)
+{
+    DWORD last_play_pos,play_pos,buf_free;
+    HRESULT rc;
+
+    rc=IDirectSoundBuffer_GetCurrentPosition(state->dsbo,&play_pos,NULL);
+    ok(rc==DS_OK,"IDirectSoundBuffer_GetCurrentPosition() failed: %08x\n", rc);
+    if (rc!=DS_OK) {
+        goto STOP;
+    }
+
+    /* Update the amount played */
+    last_play_pos=state->played % state->buffer_size;
+    if (play_pos<last_play_pos)
+        state->played+=state->buffer_size-last_play_pos+play_pos;
+    else
+        state->played+=play_pos-last_play_pos;
+
+    if (winetest_debug > 1)
+        trace("buf size=%d last_play_pos=%d play_pos=%d played=%d / %d\n",
+              state->buffer_size,last_play_pos,play_pos,state->played,
+              state->wave_len);
+
+    if (state->played>state->wave_len)
+    {
+        /* Everything has been played */
+        goto STOP;
+    }
+
+    /* Refill the buffer */
+    if (state->offset<=play_pos)
+        buf_free=play_pos-state->offset;
+    else
+        buf_free=state->buffer_size-state->offset+play_pos;
+
+    if (winetest_debug > 1)
+        trace("offset=%d free=%d written=%d / %d\n",
+              state->offset,buf_free,state->written,state->wave_len);
+    if (buf_free==0)
+        return 1;
+
+    if (state->written<state->wave_len)
+    {
+        int w=buffer_refill(state,buf_free);
+        if (w==-1)
+            goto STOP;
+        buf_free-=w;
+        if (state->written==state->wave_len && winetest_debug > 1)
+            trace("last sound byte at %d\n",
+                  (state->written % state->buffer_size));
+    }
+
+    if (buf_free>0) {
+        /* Fill with silence */
+        if (winetest_debug > 1)
+            trace("writing %d bytes of silence\n",buf_free);
+        if (buffer_silence(state,buf_free)==-1)
+            goto STOP;
+    }
+    return 1;
+
+STOP:
+    if (winetest_debug > 1)
+        trace("stopping playback\n");
+    rc=IDirectSoundBuffer_Stop(state->dsbo);
+    ok(rc==DS_OK,"IDirectSoundBuffer_Stop() failed: %08x\n", rc);
+    return 0;
+}
+
+void test_buffer(LPDIRECTSOUND dso, LPDIRECTSOUNDBUFFER *dsbo,
+                 BOOL is_primary, BOOL set_volume, LONG volume,
+                 BOOL set_pan, LONG pan, BOOL play, double duration,
+                 BOOL buffer3d, LPDIRECTSOUND3DLISTENER listener,
+                 BOOL move_listener, BOOL move_sound,
+                 BOOL set_frequency, DWORD frequency)
+{
+    HRESULT rc;
+    DSBCAPS dsbcaps;
+    WAVEFORMATEX wfx,wfx2;
+    DWORD size,status,freq;
+    int ref;
+
+    if (set_frequency) {
+        rc=IDirectSoundBuffer_SetFrequency(*dsbo,frequency);
+        ok(rc==DS_OK||rc==DSERR_CONTROLUNAVAIL,
+           "IDirectSoundBuffer_SetFrequency() failed to set frequency %08x\n",rc);
+        if (rc!=DS_OK)
+            return;
+    }
+
+    /* DSOUND: Error: Invalid caps pointer */
+    rc=IDirectSoundBuffer_GetCaps(*dsbo,0);
+    ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have "
+       "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+    ZeroMemory(&dsbcaps, sizeof(dsbcaps));
+
+    /* DSOUND: Error: Invalid caps pointer */
+    rc=IDirectSoundBuffer_GetCaps(*dsbo,&dsbcaps);
+    ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have "
+       "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+    dsbcaps.dwSize=sizeof(dsbcaps);
+    rc=IDirectSoundBuffer_GetCaps(*dsbo,&dsbcaps);
+    ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() failed: %08x\n", rc);
+    if (rc==DS_OK && winetest_debug > 1) {
+        trace("    Caps: flags=0x%08x size=%d\n",dsbcaps.dwFlags,
+              dsbcaps.dwBufferBytes);
+    }
+
+    /* Query the format size. */
+    size=0;
+    rc=IDirectSoundBuffer_GetFormat(*dsbo,NULL,0,&size);
+    ok(rc==DS_OK && size!=0,"IDirectSoundBuffer_GetFormat() should have "
+       "returned the needed size: rc=%08x size=%d\n",rc,size);
+
+    ok(size == sizeof(WAVEFORMATEX) || size == sizeof(WAVEFORMATEXTENSIBLE),
+       "Expected a correct structure size, got %d\n", size);
+
+    if (size == sizeof(WAVEFORMATEX)) {
+        rc=IDirectSoundBuffer_GetFormat(*dsbo,&wfx,size,NULL);
+    }
+    else if (size == sizeof(WAVEFORMATEXTENSIBLE)) {
+        WAVEFORMATEXTENSIBLE wfxe;
+        rc=IDirectSoundBuffer_GetFormat(*dsbo,(WAVEFORMATEX*)&wfxe,size,NULL);
+        wfx = wfxe.Format;
+    }
+    ok(rc==DS_OK,
+        "IDirectSoundBuffer_GetFormat() failed: %08x\n", rc);
+    if (rc==DS_OK && winetest_debug > 1) {
+        trace("    Format: %s tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n",
+              is_primary ? "Primary" : "Secondary",
+              wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
+              wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
+    }
+
+    /* DSOUND: Error: Invalid frequency buffer */
+    rc=IDirectSoundBuffer_GetFrequency(*dsbo,0);
+    ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetFrequency() should have "
+       "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+    /* DSOUND: Error: Primary buffers don't support CTRLFREQUENCY */
+    rc=IDirectSoundBuffer_GetFrequency(*dsbo,&freq);
+    ok((rc==DS_OK && !is_primary) || (rc==DSERR_CONTROLUNAVAIL&&is_primary) ||
+       (rc==DSERR_CONTROLUNAVAIL&&!(dsbcaps.dwFlags&DSBCAPS_CTRLFREQUENCY)),
+       "IDirectSoundBuffer_GetFrequency() failed: %08x\n",rc);
+    if (rc==DS_OK) {
+        DWORD f = set_frequency?frequency:wfx.nSamplesPerSec;
+        ok(freq==f,"The frequency returned by GetFrequency "
+           "%d does not match the format %d\n",freq,f);
+    }
+
+    /* DSOUND: Error: Invalid status pointer */
+    rc=IDirectSoundBuffer_GetStatus(*dsbo,0);
+    ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetStatus() should have "
+       "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+    rc=IDirectSoundBuffer_GetStatus(*dsbo,&status);
+    ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %08x\n", rc);
+    ok(status==0,"status=0x%x instead of 0\n",status);
+
+    if (is_primary) {
+        DSBCAPS new_dsbcaps;
+        /* We must call SetCooperativeLevel to be allowed to call SetFormat */
+        /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
+        rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+        ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc);
+        if (rc!=DS_OK)
+            return;
+
+        /* DSOUND: Error: Invalid format pointer */
+        rc=IDirectSoundBuffer_SetFormat(*dsbo,0);
+        ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_SetFormat() should have "
+           "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+        init_format(&wfx2,WAVE_FORMAT_PCM,11025,16,2);
+        rc=IDirectSoundBuffer_SetFormat(*dsbo,&wfx2);
+        ok(rc==DS_OK,"IDirectSoundBuffer_SetFormat(%s) failed: %08x\n",
+           format_string(&wfx2), rc);
+
+        /* There is no guarantee that SetFormat will actually change the
+        * format to what we asked for. It depends on what the soundcard
+        * supports. So we must re-query the format.
+        */
+        rc=IDirectSoundBuffer_GetFormat(*dsbo,&wfx,sizeof(wfx),NULL);
+        ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %08x\n", rc);
+        if (rc==DS_OK &&
+            (wfx.wFormatTag!=wfx2.wFormatTag ||
+             wfx.nSamplesPerSec!=wfx2.nSamplesPerSec ||
+             wfx.wBitsPerSample!=wfx2.wBitsPerSample ||
+             wfx.nChannels!=wfx2.nChannels)) {
+            trace("Requested format tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n",
+                  wfx2.wFormatTag,wfx2.nSamplesPerSec,wfx2.wBitsPerSample,
+                  wfx2.nChannels,wfx2.nAvgBytesPerSec,wfx2.nBlockAlign);
+            trace("Got tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n",
+                  wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
+                  wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
+        }
+
+        ZeroMemory(&new_dsbcaps, sizeof(new_dsbcaps));
+        new_dsbcaps.dwSize = sizeof(new_dsbcaps);
+        rc=IDirectSoundBuffer_GetCaps(*dsbo,&new_dsbcaps);
+        ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() failed: %08x\n", rc);
+        if (rc==DS_OK && winetest_debug > 1) {
+            trace("    new Caps: flags=0x%08x size=%d\n",new_dsbcaps.dwFlags,
+                  new_dsbcaps.dwBufferBytes);
+        }
+
+        /* Check for primary buffer size change */
+        ok(new_dsbcaps.dwBufferBytes == dsbcaps.dwBufferBytes,
+           "    buffer size changed after SetFormat() - "
+           "previous size was %u, current size is %u\n",
+           dsbcaps.dwBufferBytes, new_dsbcaps.dwBufferBytes);
+        dsbcaps.dwBufferBytes = new_dsbcaps.dwBufferBytes;
+
+        /* Check for primary buffer flags change */
+        ok(new_dsbcaps.dwFlags == dsbcaps.dwFlags,
+           "    flags changed after SetFormat() - "
+           "previous flags were %08x, current flags are %08x\n",
+           dsbcaps.dwFlags, new_dsbcaps.dwFlags);
+
+        /* Set the CooperativeLevel back to normal */
+        /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
+        rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
+        ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n",rc);
+    }
+
+    if (play) {
+        play_state_t state;
+        DS3DLISTENER listener_param;
+        LPDIRECTSOUND3DBUFFER buffer=NULL;
+        DS3DBUFFER buffer_param;
+        DWORD start_time,now;
+        LPVOID buffer1;
+        DWORD length1;
+
+        if (winetest_interactive) {
+            if (set_frequency)
+                trace("    Playing %g second 440Hz tone at %dx%dx%d with a "
+                      "frequency of %d (%dHz)\n", duration,
+                      wfx.nSamplesPerSec, wfx.wBitsPerSample, wfx.nChannels,
+                      frequency, (440 * frequency) / wfx.nSamplesPerSec);
+            else
+                trace("    Playing %g second 440Hz tone at %dx%dx%d\n", duration,
+                      wfx.nSamplesPerSec, wfx.wBitsPerSample, wfx.nChannels);
+        }
+
+        if (is_primary) {
+            /* We must call SetCooperativeLevel to be allowed to call Lock */
+            /* DSOUND: Setting DirectSound cooperative level to
+             * DSSCL_WRITEPRIMARY */
+            rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),
+                                                DSSCL_WRITEPRIMARY);
+            ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_WRITEPRIMARY) "
+               "failed: %08x\n",rc);
+            if (rc!=DS_OK)
+                return;
+        }
+        if (buffer3d) {
+            LPDIRECTSOUNDBUFFER temp_buffer;
+
+            rc=IDirectSoundBuffer_QueryInterface(*dsbo,&IID_IDirectSound3DBuffer,
+                                                 (LPVOID *)&buffer);
+            ok(rc==DS_OK,"IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc);
+            if (rc!=DS_OK)
+                return;
+
+            /* check the COM interface */
+            rc=IDirectSoundBuffer_QueryInterface(*dsbo, &IID_IDirectSoundBuffer,
+                                                 (LPVOID *)&temp_buffer);
+            ok(rc==DS_OK && temp_buffer!=NULL,
+               "IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc);
+            ok(temp_buffer==*dsbo,"COM interface broken: %p != %p\n",
+               temp_buffer,*dsbo);
+            ref=IDirectSoundBuffer_Release(temp_buffer);
+            ok(ref==1,"IDirectSoundBuffer_Release() has %d references, "
+               "should have 1\n",ref);
+
+            temp_buffer=NULL;
+            rc=IDirectSound3DBuffer_QueryInterface(*dsbo,
+                                                   &IID_IDirectSoundBuffer,
+                                                   (LPVOID *)&temp_buffer);
+            ok(rc==DS_OK && temp_buffer!=NULL,
+               "IDirectSound3DBuffer_QueryInterface() failed: %08x\n", rc);
+            ok(temp_buffer==*dsbo,"COM interface broken: %p != %p\n",
+               temp_buffer,*dsbo);
+            ref=IDirectSoundBuffer_Release(temp_buffer);
+            ok(ref==1,"IDirectSoundBuffer_Release() has %d references, "
+               "should have 1\n",ref);
+
+            ref=IDirectSoundBuffer_Release(*dsbo);
+            ok(ref==0,"IDirectSoundBuffer_Release() has %d references, "
+               "should have 0\n",ref);
+
+            rc=IDirectSound3DBuffer_QueryInterface(buffer,
+                                                   &IID_IDirectSoundBuffer,
+                                                   (LPVOID *)dsbo);
+            ok(rc==DS_OK && *dsbo!=NULL,"IDirectSound3DBuffer_QueryInterface() "
+               "failed: %08x\n",rc);
+
+            /* DSOUND: Error: Invalid buffer */
+            rc=IDirectSound3DBuffer_GetAllParameters(buffer,0);
+            ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() "
+               "failed: %08x\n",rc);
+
+            ZeroMemory(&buffer_param, sizeof(buffer_param));
+
+            /* DSOUND: Error: Invalid buffer */
+            rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param);
+            ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() "
+               "failed: %08x\n",rc);
+
+            buffer_param.dwSize=sizeof(buffer_param);
+            rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param);
+            ok(rc==DS_OK,"IDirectSound3DBuffer_GetAllParameters() failed: %08x\n", rc);
+        }
+        if (set_volume) {
+            if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) {
+                LONG val;
+                rc=IDirectSoundBuffer_GetVolume(*dsbo,&val);
+                ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %08x\n", rc);
+
+                rc=IDirectSoundBuffer_SetVolume(*dsbo,volume);
+                ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume() failed: %08x\n", rc);
+            } else {
+                /* DSOUND: Error: Buffer does not have CTRLVOLUME */
+                rc=IDirectSoundBuffer_GetVolume(*dsbo,&volume);
+                ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetVolume() "
+                   "should have returned DSERR_CONTROLUNAVAIL, returned: %08x\n", rc);
+            }
+        }
+
+        if (set_pan) {
+            if (dsbcaps.dwFlags & DSBCAPS_CTRLPAN) {
+                LONG val;
+                rc=IDirectSoundBuffer_GetPan(*dsbo,&val);
+                ok(rc==DS_OK,"IDirectSoundBuffer_GetPan() failed: %08x\n", rc);
+
+                rc=IDirectSoundBuffer_SetPan(*dsbo,pan);
+                ok(rc==DS_OK,"IDirectSoundBuffer_SetPan() failed: %08x\n", rc);
+            } else {
+                /* DSOUND: Error: Buffer does not have CTRLPAN */
+                rc=IDirectSoundBuffer_GetPan(*dsbo,&pan);
+                ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetPan() "
+                   "should have returned DSERR_CONTROLUNAVAIL, returned: %08x\n", rc);
+            }
+        }
+
+        /* try an offset past the end of the buffer */
+        rc = IDirectSoundBuffer_Lock(*dsbo, dsbcaps.dwBufferBytes, 0, &buffer1,
+                                      &length1, NULL, NULL,
+                                      DSBLOCK_ENTIREBUFFER);
+        ok(rc==DSERR_INVALIDPARAM, "IDirectSoundBuffer_Lock() should have "
+           "returned DSERR_INVALIDPARAM, returned %08x\n", rc);
+
+        /* try a size larger than the buffer */
+        rc = IDirectSoundBuffer_Lock(*dsbo, 0, dsbcaps.dwBufferBytes + 1,
+                                     &buffer1, &length1, NULL, NULL,
+                                     DSBLOCK_FROMWRITECURSOR);
+        ok(rc==DSERR_INVALIDPARAM, "IDirectSoundBuffer_Lock() should have "
+           "returned DSERR_INVALIDPARAM, returned %08x\n", rc);
+
+        if (set_frequency)
+            state.wave=wave_generate_la(&wfx,(duration*frequency)/wfx.nSamplesPerSec,&state.wave_len);
+        else
+            state.wave=wave_generate_la(&wfx,duration,&state.wave_len);
+
+        state.dsbo=*dsbo;
+        state.wfx=&wfx;
+        state.buffer_size=dsbcaps.dwBufferBytes;
+        state.played=state.written=state.offset=0;
+        buffer_refill(&state,state.buffer_size);
+
+        rc=IDirectSoundBuffer_Play(*dsbo,0,0,DSBPLAY_LOOPING);
+        ok(rc==DS_OK,"IDirectSoundBuffer_Play() failed: %08x\n", rc);
+
+        rc=IDirectSoundBuffer_GetStatus(*dsbo,&status);
+        ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %08x\n", rc);
+        ok(status==(DSBSTATUS_PLAYING|DSBSTATUS_LOOPING),
+           "GetStatus: bad status: %x\n",status);
+
+        if (listener) {
+            ZeroMemory(&listener_param,sizeof(listener_param));
+            listener_param.dwSize=sizeof(listener_param);
+            rc=IDirectSound3DListener_GetAllParameters(listener,
+                                                       &listener_param);
+            ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() "
+               "failed: %08x\n",rc);
+            if (move_listener) {
+                listener_param.vPosition.x = -5.0f;
+                listener_param.vVelocity.x = (float)(10.0/duration);
+            }
+            rc=IDirectSound3DListener_SetAllParameters(listener,
+                                                       &listener_param,
+                                                       DS3D_IMMEDIATE);
+            ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: %08x\n", rc);
+        }
+        if (buffer3d) {
+            if (move_sound) {
+                buffer_param.vPosition.x = 100.0f;
+                buffer_param.vVelocity.x = (float)(-200.0/duration);
+            }
+            buffer_param.flMinDistance = 10;
+            rc=IDirectSound3DBuffer_SetAllParameters(buffer,&buffer_param,
+                                                     DS3D_IMMEDIATE);
+            ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %08x\n", rc);
+        }
+
+        start_time=GetTickCount();
+        while (buffer_service(&state)) {
+            WaitForSingleObject(GetCurrentProcess(),TIME_SLICE);
+            now=GetTickCount();
+            if (listener && move_listener) {
+                listener_param.vPosition.x = (float)(-5.0+10.0*(now-start_time)/1000/duration);
+                if (winetest_debug>2)
+                    trace("listener position=%g\n",listener_param.vPosition.x);
+                rc=IDirectSound3DListener_SetPosition(listener,
+                    listener_param.vPosition.x,listener_param.vPosition.y,
+                    listener_param.vPosition.z,DS3D_IMMEDIATE);
+                ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: %08x\n",rc);
+            }
+            if (buffer3d && move_sound) {
+                buffer_param.vPosition.x = (float)(100-200.0*(now-start_time)/1000/duration);
+                if (winetest_debug>2)
+                    trace("sound position=%g\n",buffer_param.vPosition.x);
+                rc=IDirectSound3DBuffer_SetPosition(buffer,
+                    buffer_param.vPosition.x,buffer_param.vPosition.y,
+                    buffer_param.vPosition.z,DS3D_IMMEDIATE);
+                ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %08x\n", rc);
+            }
+        }
+        /* Check the sound duration was within 10% of the expected value */
+        now=GetTickCount();
+        ok(fabs(1000*duration-now+start_time)<=100*duration,
+           "The sound played for %d ms instead of %g ms\n",
+           now-start_time,1000*duration);
+
+        HeapFree(GetProcessHeap(), 0, state.wave);
+        if (is_primary) {
+            /* Set the CooperativeLevel back to normal */
+            /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
+            rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
+            ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) "
+               "failed: %08x\n",rc);
+        }
+        if (buffer3d) {
+            ref=IDirectSound3DBuffer_Release(buffer);
+            ok(ref==0,"IDirectSound3DBuffer_Release() has %d references, "
+               "should have 0\n",ref);
+        }
+    }
+}
+
+static HRESULT test_secondary(LPGUID lpGuid, int play,
+                              int has_3d, int has_3dbuffer,
+                              int has_listener, int has_duplicate,
+                              int move_listener, int move_sound)
+{
+    HRESULT rc;
+    LPDIRECTSOUND dso=NULL;
+    LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL;
+    LPDIRECTSOUND3DLISTENER listener=NULL;
+    DSBUFFERDESC bufdesc;
+    WAVEFORMATEX wfx, wfx1;
+    int ref;
+
+    /* Create the DirectSound object */
+    rc=pDirectSoundCreate(lpGuid,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        return rc;
+
+    /* We must call SetCooperativeLevel before creating primary buffer */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
+    rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+    ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
+    if (has_3d)
+        bufdesc.dwFlags|=DSBCAPS_CTRL3D;
+    else
+        bufdesc.dwFlags|=(DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN);
+    rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+    ok((rc==DS_OK && primary!=NULL) || (rc==DSERR_CONTROLUNAVAIL),
+       "IDirectSound_CreateSoundBuffer() failed to create a %sprimary buffer: %08x\n",has_3d?"3D ":"", rc);
+    if (rc==DSERR_CONTROLUNAVAIL)
+        trace("  No Primary\n");
+    else if (rc==DS_OK && primary!=NULL) {
+        rc=IDirectSoundBuffer_GetFormat(primary,&wfx1,sizeof(wfx1),NULL);
+        ok(rc==DS_OK,"IDirectSoundBuffer8_Getformat() failed: %08x\n", rc);
+        if (rc!=DS_OK)
+            goto EXIT1;
+
+        if (has_listener) {
+            rc=IDirectSoundBuffer_QueryInterface(primary,
+                                                 &IID_IDirectSound3DListener,
+                                                 (void **)&listener);
+            ok(rc==DS_OK && listener!=NULL,
+               "IDirectSoundBuffer_QueryInterface() failed to get a 3D listener: %08x\n",rc);
+            ref=IDirectSoundBuffer_Release(primary);
+            ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
+               "should have 0\n",ref);
+            if (rc==DS_OK && listener!=NULL) {
+                DS3DLISTENER listener_param;
+                ZeroMemory(&listener_param,sizeof(listener_param));
+                /* DSOUND: Error: Invalid buffer */
+                rc=IDirectSound3DListener_GetAllParameters(listener,0);
+                ok(rc==DSERR_INVALIDPARAM,
+                   "IDirectSound3dListener_GetAllParameters() should have "
+                   "returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+
+                /* DSOUND: Error: Invalid buffer */
+                rc=IDirectSound3DListener_GetAllParameters(listener,
+                                                           &listener_param);
+                ok(rc==DSERR_INVALIDPARAM,
+                   "IDirectSound3dListener_GetAllParameters() should have "
+                   "returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+
+                listener_param.dwSize=sizeof(listener_param);
+                rc=IDirectSound3DListener_GetAllParameters(listener,
+                                                           &listener_param);
+                ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() "
+                   "failed: %08x\n",rc);
+            } else {
+                ok(listener==NULL, "IDirectSoundBuffer_QueryInterface() "
+                   "failed but returned a listener anyway\n");
+                ok(rc!=DS_OK, "IDirectSoundBuffer_QueryInterface() succeeded "
+                   "but returned a NULL listener\n");
+                if (listener) {
+                    ref=IDirectSound3DListener_Release(listener);
+                    ok(ref==0,"IDirectSound3dListener_Release() listener has "
+                       "%d references, should have 0\n",ref);
+                }
+                goto EXIT2;
+            }
+        }
+
+        init_format(&wfx,WAVE_FORMAT_PCM,22050,16,2);
+        secondary=NULL;
+        ZeroMemory(&bufdesc, sizeof(bufdesc));
+        bufdesc.dwSize=sizeof(bufdesc);
+        bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;
+        if (has_3d)
+            bufdesc.dwFlags|=DSBCAPS_CTRL3D;
+        else
+            bufdesc.dwFlags|=
+                (DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN);
+        bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000,
+                                    wfx.nBlockAlign);
+        bufdesc.lpwfxFormat=&wfx;
+        if (winetest_interactive) {
+            trace("  Testing a %s%ssecondary buffer %s%s%s%sat %dx%dx%d "
+                  "with a primary buffer at %dx%dx%d\n",
+                  has_3dbuffer?"3D ":"",
+                  has_duplicate?"duplicated ":"",
+                  listener!=NULL||move_sound?"with ":"",
+                  move_listener?"moving ":"",
+                  listener!=NULL?"listener ":"",
+                  listener&&move_sound?"and moving sound ":move_sound?
+                  "moving sound ":"",
+                  wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels,
+                  wfx1.nSamplesPerSec,wfx1.wBitsPerSample,wfx1.nChannels);
+        }
+        rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+        ok(rc==DS_OK && secondary!=NULL,"IDirectSound_CreateSoundBuffer() "
+           "failed to create a %s%ssecondary buffer %s%s%s%sat %dx%dx%d (%s): %08x\n",
+           has_3dbuffer?"3D ":"", has_duplicate?"duplicated ":"",
+           listener!=NULL||move_sound?"with ":"", move_listener?"moving ":"",
+           listener!=NULL?"listener ":"",
+           listener&&move_sound?"and moving sound ":move_sound?
+           "moving sound ":"",
+           wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels,
+           getDSBCAPS(bufdesc.dwFlags),rc);
+        if (rc==DS_OK && secondary!=NULL) {
+            if (!has_3d) {
+                LONG refvol,vol,refpan,pan;
+
+                /* Check the initial secondary buffer's volume and pan */
+                rc=IDirectSoundBuffer_GetVolume(secondary,&vol);
+                ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(secondary) failed: %08x\n",rc);
+                ok(vol==0,"wrong volume for a new secondary buffer: %d\n",vol);
+                rc=IDirectSoundBuffer_GetPan(secondary,&pan);
+                ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(secondary) failed: %08x\n",rc);
+                ok(pan==0,"wrong pan for a new secondary buffer: %d\n",pan);
+
+                /* Check that changing the secondary buffer's volume and pan
+                 * does not impact the primary buffer's volume and pan
+                 */
+                rc=IDirectSoundBuffer_GetVolume(primary,&refvol);
+                ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(primary) failed: %08x\n",rc);
+                rc=IDirectSoundBuffer_GetPan(primary,&refpan);
+                ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: %08x\n", rc);
+
+                rc=IDirectSoundBuffer_SetVolume(secondary,-1000);
+                ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: %08x\n",rc);
+                rc=IDirectSoundBuffer_GetVolume(secondary,&vol);
+                ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: %08x\n",rc);
+                ok(vol==-1000,"secondary: wrong volume %d instead of -1000\n",
+                   vol);
+                rc=IDirectSoundBuffer_SetPan(secondary,-1000);
+                ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: %08x\n",rc);
+                rc=IDirectSoundBuffer_GetPan(secondary,&pan);
+                ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: %08x\n",rc);
+                ok(pan==-1000,"secondary: wrong pan %d instead of -1000\n",
+                   pan);
+
+                rc=IDirectSoundBuffer_GetVolume(primary,&vol);
+                ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(primary) failed: %08x\n",rc);
+                ok(vol==refvol,"The primary volume changed from %d to %d\n",
+                   refvol,vol);
+                rc=IDirectSoundBuffer_GetPan(primary,&pan);
+                ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: %08x\n", rc);
+                ok(pan==refpan,"The primary pan changed from %d to %d\n",
+                   refpan,pan);
+
+                rc=IDirectSoundBuffer_SetVolume(secondary,0);
+                ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: %08x\n",rc);
+                rc=IDirectSoundBuffer_SetPan(secondary,0);
+                ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: %08x\n",rc);
+            }
+            if (has_duplicate) {
+                LPDIRECTSOUNDBUFFER duplicated=NULL;
+
+                /* DSOUND: Error: Invalid source buffer */
+                rc=IDirectSound_DuplicateSoundBuffer(dso,0,0);
+                ok(rc==DSERR_INVALIDPARAM,
+                   "IDirectSound_DuplicateSoundBuffer() should have returned "
+                   "DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+                /* DSOUND: Error: Invalid dest buffer */
+                rc=IDirectSound_DuplicateSoundBuffer(dso,secondary,0);
+                ok(rc==DSERR_INVALIDPARAM,
+                   "IDirectSound_DuplicateSoundBuffer() should have returned "
+                   "DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+                /* DSOUND: Error: Invalid source buffer */
+                rc=IDirectSound_DuplicateSoundBuffer(dso,0,&duplicated);
+                ok(rc==DSERR_INVALIDPARAM,
+                  "IDirectSound_DuplicateSoundBuffer() should have returned "
+                  "DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+                duplicated=NULL;
+                rc=IDirectSound_DuplicateSoundBuffer(dso,secondary,
+                                                     &duplicated);
+                ok(rc==DS_OK && duplicated!=NULL,
+                   "IDirectSound_DuplicateSoundBuffer() failed to duplicate "
+                   "a secondary buffer: %08x\n",rc);
+
+                if (rc==DS_OK && duplicated!=NULL) {
+                    ref=IDirectSoundBuffer_Release(secondary);
+                    ok(ref==0,"IDirectSoundBuffer_Release() secondary has %d "
+                      "references, should have 0\n",ref);
+                    secondary=duplicated;
+                }
+            }
+
+            if (rc==DS_OK && secondary!=NULL) {
+                double duration;
+                duration=(move_listener || move_sound?4.0:1.0);
+                test_buffer(dso,&secondary,0,FALSE,0,FALSE,0,
+                            winetest_interactive,duration,has_3dbuffer,
+                            listener,move_listener,move_sound,FALSE,0);
+                ref=IDirectSoundBuffer_Release(secondary);
+                ok(ref==0,"IDirectSoundBuffer_Release() %s has %d references, "
+                   "should have 0\n",has_duplicate?"duplicated":"secondary",
+                   ref);
+            }
+        }
+EXIT1:
+        if (has_listener) {
+            ref=IDirectSound3DListener_Release(listener);
+            ok(ref==0,"IDirectSound3dListener_Release() listener has %d "
+               "references, should have 0\n",ref);
+        } else {
+            ref=IDirectSoundBuffer_Release(primary);
+            ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
+               "should have 0\n",ref);
+        }
+    } else {
+        ok(primary==NULL,"IDirectSound_CreateSoundBuffer(primary) failed "
+           "but primary created anyway\n");
+        ok(rc!=DS_OK,"IDirectSound_CreateSoundBuffer(primary) succeeded "
+           "but primary not created\n");
+        if (primary) {
+            ref=IDirectSoundBuffer_Release(primary);
+            ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
+               "should have 0\n",ref);
+        }
+    }
+EXIT2:
+    /* Set the CooperativeLevel back to normal */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
+    rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
+    ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n", rc);
+
+EXIT:
+    ref=IDirectSound_Release(dso);
+    ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
+    if (ref!=0)
+        return DSERR_GENERIC;
+
+    return rc;
+}
+
+static HRESULT test_for_driver(LPGUID lpGuid)
+{
+    HRESULT rc;
+    LPDIRECTSOUND dso=NULL;
+    int ref;
+
+    /* Create the DirectSound object */
+    rc=pDirectSoundCreate(lpGuid,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
+       "DirectSoundCreate() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        return rc;
+
+    ref=IDirectSound_Release(dso);
+    ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
+    if (ref!=0)
+        return DSERR_GENERIC;
+
+    return rc;
+}
+
+static HRESULT test_primary(LPGUID lpGuid)
+{
+    HRESULT rc;
+    LPDIRECTSOUND dso=NULL;
+    LPDIRECTSOUNDBUFFER primary=NULL;
+    DSBUFFERDESC bufdesc;
+    DSCAPS dscaps;
+    int ref, i;
+
+    /* Create the DirectSound object */
+    rc=pDirectSoundCreate(lpGuid,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        return rc;
+
+    /* Get the device capabilities */
+    ZeroMemory(&dscaps, sizeof(dscaps));
+    dscaps.dwSize=sizeof(dscaps);
+    rc=IDirectSound_GetCaps(dso,&dscaps);
+    ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
+    rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+    ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    /* Testing the primary buffer */
+    primary=NULL;
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN;
+    rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+    ok((rc==DS_OK && primary!=NULL) || (rc==DSERR_CONTROLUNAVAIL),
+       "IDirectSound_CreateSoundBuffer() failed to create a primary buffer: %08x\n",rc);
+    if (rc==DSERR_CONTROLUNAVAIL)
+        trace("  No Primary\n");
+    else if (rc==DS_OK && primary!=NULL) {
+        test_buffer(dso,&primary,1,TRUE,0,TRUE,0,winetest_interactive &&
+                    !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,NULL,0,0,
+                    FALSE,0);
+        if (winetest_interactive) {
+            LONG volume,pan;
+
+            volume = DSBVOLUME_MAX;
+            for (i = 0; i < 6; i++) {
+                test_buffer(dso,&primary,1,TRUE,volume,TRUE,0,
+                            winetest_interactive &&
+                            !(dscaps.dwFlags & DSCAPS_EMULDRIVER),
+                            1.0,0,NULL,0,0,FALSE,0);
+                volume -= ((DSBVOLUME_MAX-DSBVOLUME_MIN) / 40);
+            }
+
+            pan = DSBPAN_LEFT;
+            for (i = 0; i < 7; i++) {
+                test_buffer(dso,&primary,1,TRUE,0,TRUE,pan,
+                            winetest_interactive &&
+                            !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0,FALSE,0);
+                pan += ((DSBPAN_RIGHT-DSBPAN_LEFT) / 6);
+            }
+        }
+        ref=IDirectSoundBuffer_Release(primary);
+        ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
+           "should have 0\n",ref);
+    }
+
+    /* Set the CooperativeLevel back to normal */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
+    rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
+    ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n", rc);
+
+EXIT:
+    ref=IDirectSound_Release(dso);
+    ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
+    if (ref!=0)
+        return DSERR_GENERIC;
+
+    return rc;
+}
+
+static HRESULT test_primary_3d(LPGUID lpGuid)
+{
+    HRESULT rc;
+    LPDIRECTSOUND dso=NULL;
+    LPDIRECTSOUNDBUFFER primary=NULL;
+    DSBUFFERDESC bufdesc;
+    DSCAPS dscaps;
+    int ref;
+
+    /* Create the DirectSound object */
+    rc=pDirectSoundCreate(lpGuid,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        return rc;
+
+    /* Get the device capabilities */
+    ZeroMemory(&dscaps, sizeof(dscaps));
+    dscaps.dwSize=sizeof(dscaps);
+    rc=IDirectSound_GetCaps(dso,&dscaps);
+    ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
+    rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+    ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    primary=NULL;
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
+    rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+    ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() failed "
+       "to create a primary buffer: %08x\n",rc);
+    if (rc==DS_OK && primary!=NULL) {
+        ref=IDirectSoundBuffer_Release(primary);
+        ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
+           "should have 0\n",ref);
+        primary=NULL;
+        ZeroMemory(&bufdesc, sizeof(bufdesc));
+        bufdesc.dwSize=sizeof(bufdesc);
+        bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D;
+        rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+        ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() "
+           "failed to create a 3D primary buffer: %08x\n",rc);
+        if (rc==DS_OK && primary!=NULL) {
+            test_buffer(dso,&primary,1,FALSE,0,FALSE,0,winetest_interactive &&
+                        !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0,
+                        FALSE,0);
+            ref=IDirectSoundBuffer_Release(primary);
+            ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
+               "should have 0\n",ref);
+        }
+    }
+    /* Set the CooperativeLevel back to normal */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
+    rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
+    ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n", rc);
+
+EXIT:
+    ref=IDirectSound_Release(dso);
+    ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
+    if (ref!=0)
+        return DSERR_GENERIC;
+
+    return rc;
+}
+
+static HRESULT test_primary_3d_with_listener(LPGUID lpGuid)
+{
+    HRESULT rc;
+    LPDIRECTSOUND dso=NULL;
+    LPDIRECTSOUNDBUFFER primary=NULL;
+    DSBUFFERDESC bufdesc;
+    DSCAPS dscaps;
+    int ref;
+
+    /* Create the DirectSound object */
+    rc=pDirectSoundCreate(lpGuid,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        return rc;
+
+    /* Get the device capabilities */
+    ZeroMemory(&dscaps, sizeof(dscaps));
+    dscaps.dwSize=sizeof(dscaps);
+    rc=IDirectSound_GetCaps(dso,&dscaps);
+    ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
+    rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+    ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+    primary=NULL;
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D;
+    rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+    ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() failed "
+       "to create a 3D primary buffer: %08x\n",rc);
+    if (rc==DS_OK && primary!=NULL) {
+        LPDIRECTSOUND3DLISTENER listener=NULL;
+        rc=IDirectSoundBuffer_QueryInterface(primary,
+            &IID_IDirectSound3DListener,(void **)&listener);
+        ok(rc==DS_OK && listener!=NULL,"IDirectSoundBuffer_QueryInterface() "
+           "failed to get a 3D listener: %08x\n",rc);
+        if (rc==DS_OK && listener!=NULL) {
+            LPDIRECTSOUNDBUFFER temp_buffer=NULL;
+
+            /* Checking the COM interface */
+            rc=IDirectSoundBuffer_QueryInterface(primary,
+                &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer);
+            ok(rc==DS_OK && temp_buffer!=NULL,
+               "IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc);
+            ok(temp_buffer==primary,
+               "COM interface broken: %p != %p\n",
+               temp_buffer,primary);
+            if (rc==DS_OK && temp_buffer!=NULL) {
+                ref=IDirectSoundBuffer_Release(temp_buffer);
+                ok(ref==1,"IDirectSoundBuffer_Release() has %d references, "
+                   "should have 1\n",ref);
+
+                temp_buffer=NULL;
+                rc=IDirectSound3DListener_QueryInterface(listener,
+                    &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer);
+                ok(rc==DS_OK && temp_buffer!=NULL,
+                   "IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc);
+                ok(temp_buffer==primary,
+                   "COM interface broken: %p != %p\n",
+                   temp_buffer,primary);
+                ref=IDirectSoundBuffer_Release(temp_buffer);
+                ok(ref==1,"IDirectSoundBuffer_Release() has %d references, "
+                   "should have 1\n",ref);
+
+                /* Testing the buffer */
+                test_buffer(dso,&primary,1,FALSE,0,FALSE,0,
+                            winetest_interactive &&
+                            !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,
+                            listener,0,0,FALSE,0);
+            }
+
+            /* Testing the reference counting */
+            ref=IDirectSound3DListener_Release(listener);
+            ok(ref==0,"IDirectSound3DListener_Release() listener has %d "
+               "references, should have 0\n",ref);
+        }
+
+        /* Testing the reference counting */
+        ref=IDirectSoundBuffer_Release(primary);
+        ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
+           "should have 0\n",ref);
+    }
+
+EXIT:
+    ref=IDirectSound_Release(dso);
+    ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
+    if (ref!=0)
+return DSERR_GENERIC;
+
+    return rc;
+}
+
+static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
+                                   LPCSTR lpcstrModule, LPVOID lpContext)
+{
+    HRESULT rc;
+    trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule);
+
+    rc = test_for_driver(lpGuid);
+    if (rc == DSERR_NODRIVER) {
+        trace("  No Driver\n");
+        return 1;
+    } else if (rc == DSERR_ALLOCATED) {
+        trace("  Already In Use\n");
+        return 1;
+    } else if (rc == E_FAIL) {
+        trace("  No Device\n");
+        return 1;
+    }
+
+    trace("  Testing the primary buffer\n");
+    test_primary(lpGuid);
+
+    trace("  Testing 3D primary buffer\n");
+    test_primary_3d(lpGuid);
+
+    trace("  Testing 3D primary buffer with listener\n");
+    test_primary_3d_with_listener(lpGuid);
+
+    /* Testing secondary buffers */
+    test_secondary(lpGuid,winetest_interactive,0,0,0,0,0,0);
+    test_secondary(lpGuid,winetest_interactive,0,0,0,1,0,0);
+
+    /* Testing 3D secondary buffers */
+    test_secondary(lpGuid,winetest_interactive,1,0,0,0,0,0);
+    test_secondary(lpGuid,winetest_interactive,1,1,0,0,0,0);
+    test_secondary(lpGuid,winetest_interactive,1,1,0,1,0,0);
+    test_secondary(lpGuid,winetest_interactive,1,0,1,0,0,0);
+    test_secondary(lpGuid,winetest_interactive,1,0,1,1,0,0);
+    test_secondary(lpGuid,winetest_interactive,1,1,1,0,0,0);
+    test_secondary(lpGuid,winetest_interactive,1,1,1,1,0,0);
+    test_secondary(lpGuid,winetest_interactive,1,1,1,0,1,0);
+    test_secondary(lpGuid,winetest_interactive,1,1,1,0,0,1);
+    test_secondary(lpGuid,winetest_interactive,1,1,1,0,1,1);
+
+    return 1;
+}
+
+static void ds3d_tests(void)
+{
+    HRESULT rc;
+    rc=pDirectSoundEnumerateA(&dsenum_callback,NULL);
+    ok(rc==DS_OK,"DirectSoundEnumerateA() failed: %08x\n",rc);
+}
+
+START_TEST(ds3d)
+{
+    HMODULE hDsound;
+
+    CoInitialize(NULL);
+
+    hDsound = LoadLibrary("dsound.dll");
+    if (hDsound)
+    {
+
+        pDirectSoundEnumerateA = (void*)GetProcAddress(hDsound,
+            "DirectSoundEnumerateA");
+        pDirectSoundCreate = (void*)GetProcAddress(hDsound,
+            "DirectSoundCreate");
+
+        ds3d_tests();
+
+        FreeLibrary(hDsound);
+    }
+    else
+        skip("dsound.dll not found!\n");
+
+    CoUninitialize();
+}
diff --git a/rostests/winetests/dsound/ds3d8.c b/rostests/winetests/dsound/ds3d8.c
new file mode 100644 (file)
index 0000000..8ad428d
--- /dev/null
@@ -0,0 +1,1154 @@
+/*
+ * Tests the panning and 3D functions of DirectSound
+ *
+ * Part of this test involves playing test tones. But this only makes
+ * sense if someone is going to carefully listen to it, and would only
+ * bother everyone else.
+ * So this is only done if the test is being run in interactive mode.
+ *
+ * Copyright (c) 2002-2004 Francois Gouget
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <windows.h>
+
+#include <math.h>
+
+#include "wine/test.h"
+#include "dsound.h"
+#include "mmreg.h"
+#include "dsound_test.h"
+
+static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL;
+static HRESULT (WINAPI *pDirectSoundCreate8)(LPCGUID,LPDIRECTSOUND8*,LPUNKNOWN)=NULL;
+
+typedef struct {
+    char* wave;
+    DWORD wave_len;
+
+    LPDIRECTSOUNDBUFFER dsbo;
+    LPWAVEFORMATEX wfx;
+    DWORD buffer_size;
+    DWORD written;
+    DWORD played;
+    DWORD offset;
+} play_state_t;
+
+static int buffer_refill8(play_state_t* state, DWORD size)
+{
+    LPVOID ptr1,ptr2;
+    DWORD len1,len2;
+    HRESULT rc;
+
+    if (size>state->wave_len-state->written)
+        size=state->wave_len-state->written;
+
+    rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size,
+                               &ptr1,&len1,&ptr2,&len2,0);
+    ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        return -1;
+
+    memcpy(ptr1,state->wave+state->written,len1);
+    state->written+=len1;
+    if (ptr2!=NULL) {
+        memcpy(ptr2,state->wave+state->written,len2);
+        state->written+=len2;
+    }
+    state->offset=state->written % state->buffer_size;
+    rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2);
+    ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        return -1;
+    return size;
+}
+
+static int buffer_silence8(play_state_t* state, DWORD size)
+{
+    LPVOID ptr1,ptr2;
+    DWORD len1,len2;
+    HRESULT rc;
+    BYTE s;
+
+    rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size,
+                               &ptr1,&len1,&ptr2,&len2,0);
+    ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        return -1;
+
+    s=(state->wfx->wBitsPerSample==8?0x80:0);
+    memset(ptr1,s,len1);
+    if (ptr2!=NULL) {
+        memset(ptr2,s,len2);
+    }
+    state->offset=(state->offset+size) % state->buffer_size;
+    rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2);
+    ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        return -1;
+    return size;
+}
+
+static int buffer_service8(play_state_t* state)
+{
+    DWORD last_play_pos,play_pos,buf_free;
+    HRESULT rc;
+
+    rc=IDirectSoundBuffer_GetCurrentPosition(state->dsbo,&play_pos,NULL);
+    ok(rc==DS_OK,"IDirectSoundBuffer_GetCurrentPosition() failed: %08x\n", rc);
+    if (rc!=DS_OK) {
+        goto STOP;
+    }
+
+    /* Update the amount played */
+    last_play_pos=state->played % state->buffer_size;
+    if (play_pos<last_play_pos)
+        state->played+=state->buffer_size-last_play_pos+play_pos;
+    else
+        state->played+=play_pos-last_play_pos;
+
+    if (winetest_debug > 1)
+        trace("buf size=%d last_play_pos=%d play_pos=%d played=%d / %d\n",
+              state->buffer_size,last_play_pos,play_pos,state->played,
+              state->wave_len);
+
+    if (state->played>state->wave_len)
+    {
+        /* Everything has been played */
+        goto STOP;
+    }
+
+    /* Refill the buffer */
+    if (state->offset<=play_pos)
+        buf_free=play_pos-state->offset;
+    else
+        buf_free=state->buffer_size-state->offset+play_pos;
+
+    if (winetest_debug > 1)
+        trace("offset=%d free=%d written=%d / %d\n",
+              state->offset,buf_free,state->written,state->wave_len);
+    if (buf_free==0)
+        return 1;
+
+    if (state->written<state->wave_len)
+    {
+        int w=buffer_refill8(state,buf_free);
+        if (w==-1)
+            goto STOP;
+        buf_free-=w;
+        if (state->written==state->wave_len && winetest_debug > 1)
+            trace("last sound byte at %d\n",
+                  (state->written % state->buffer_size));
+    }
+
+    if (buf_free>0) {
+        /* Fill with silence */
+        if (winetest_debug > 1)
+            trace("writing %d bytes of silence\n",buf_free);
+        if (buffer_silence8(state,buf_free)==-1)
+            goto STOP;
+    }
+    return 1;
+
+STOP:
+    if (winetest_debug > 1)
+        trace("stopping playback\n");
+    rc=IDirectSoundBuffer_Stop(state->dsbo);
+    ok(rc==DS_OK,"IDirectSoundBuffer_Stop() failed: %08x\n", rc);
+    return 0;
+}
+
+void test_buffer8(LPDIRECTSOUND8 dso, LPDIRECTSOUNDBUFFER * dsbo,
+                  BOOL is_primary, BOOL set_volume, LONG volume,
+                  BOOL set_pan, LONG pan, BOOL play, double duration,
+                  BOOL buffer3d, LPDIRECTSOUND3DLISTENER listener,
+                  BOOL move_listener, BOOL move_sound)
+{
+    HRESULT rc;
+    DSBCAPS dsbcaps;
+    WAVEFORMATEX wfx,wfx2;
+    DWORD size,status,freq;
+    int ref;
+
+    /* DSOUND: Error: Invalid caps pointer */
+    rc=IDirectSoundBuffer_GetCaps(*dsbo,0);
+    ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have "
+       "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+    ZeroMemory(&dsbcaps, sizeof(dsbcaps));
+
+    /* DSOUND: Error: Invalid caps pointer */
+    rc=IDirectSoundBuffer_GetCaps(*dsbo,&dsbcaps);
+    ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have "
+       "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+    dsbcaps.dwSize=sizeof(dsbcaps);
+    rc=IDirectSoundBuffer_GetCaps(*dsbo,&dsbcaps);
+    ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() failed: %08x\n", rc);
+    if (rc==DS_OK && winetest_debug > 1) {
+        trace("    Caps: flags=0x%08x size=%d\n",dsbcaps.dwFlags,
+              dsbcaps.dwBufferBytes);
+    }
+
+    /* Query the format size. */
+    size=0;
+    rc=IDirectSoundBuffer_GetFormat(*dsbo,NULL,0,&size);
+    ok(rc==DS_OK && size!=0,"IDirectSoundBuffer_GetFormat() should have "
+       "returned the needed size: rc=%08x size=%d\n",rc,size);
+
+    ok(size == sizeof(WAVEFORMATEX) || size == sizeof(WAVEFORMATEXTENSIBLE),
+       "Expected a correct structure size, got %d\n", size);
+
+    if (size == sizeof(WAVEFORMATEX)) {
+        rc=IDirectSoundBuffer_GetFormat(*dsbo,&wfx,size,NULL);
+    } else if (size == sizeof(WAVEFORMATEXTENSIBLE)) {
+        WAVEFORMATEXTENSIBLE wfxe;
+        rc=IDirectSoundBuffer_GetFormat(*dsbo,(WAVEFORMATEX*)&wfxe,size,NULL);
+        wfx = wfxe.Format;
+    }
+    ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %08x\n", rc);
+    if (rc==DS_OK && winetest_debug > 1) {
+        trace("    Format: %s tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n",
+              is_primary ? "Primary" : "Secondary",
+              wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
+              wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
+    }
+
+    /* DSOUND: Error: Invalid frequency buffer */
+    rc=IDirectSoundBuffer_GetFrequency(*dsbo,0);
+    ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetFrequency() should have "
+       "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+    /* DSOUND: Error: Primary buffers don't support CTRLFREQUENCY */
+    rc=IDirectSoundBuffer_GetFrequency(*dsbo,&freq);
+    ok((rc==DS_OK && !is_primary) || (rc==DSERR_CONTROLUNAVAIL&&is_primary) ||
+       (rc==DSERR_CONTROLUNAVAIL&&!(dsbcaps.dwFlags&DSBCAPS_CTRLFREQUENCY)),
+       "IDirectSoundBuffer_GetFrequency() failed: %08x\n",rc);
+    if (rc==DS_OK) {
+        ok(freq==wfx.nSamplesPerSec,"The frequency returned by GetFrequency "
+           "%d does not match the format %d\n",freq,wfx.nSamplesPerSec);
+    }
+
+    /* DSOUND: Error: Invalid status pointer */
+    rc=IDirectSoundBuffer_GetStatus(*dsbo,0);
+    ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetStatus() should have "
+       "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+    rc=IDirectSoundBuffer_GetStatus(*dsbo,&status);
+    ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %08x\n", rc);
+    ok(status==0,"status=0x%x instead of 0\n",status);
+
+    if (is_primary) {
+        DSBCAPS new_dsbcaps;
+        /* We must call SetCooperativeLevel to be allowed to call SetFormat */
+        /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
+        rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+        ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_PRIORITY) "
+           "failed: %08x\n",rc);
+        if (rc!=DS_OK)
+            return;
+
+        /* DSOUND: Error: Invalid format pointer */
+        rc=IDirectSoundBuffer_SetFormat(*dsbo,0);
+        ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_SetFormat() should have "
+           "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+        init_format(&wfx2,WAVE_FORMAT_PCM,11025,16,2);
+        rc=IDirectSoundBuffer_SetFormat(*dsbo,&wfx2);
+        ok(rc==DS_OK,"IDirectSoundBuffer_SetFormat(%s) failed: %08x\n",
+           format_string(&wfx2), rc);
+
+        /* There is no guarantee that SetFormat will actually change the
+        * format to what we asked for. It depends on what the soundcard
+        * supports. So we must re-query the format.
+        */
+        rc=IDirectSoundBuffer_GetFormat(*dsbo,&wfx,sizeof(wfx),NULL);
+        ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %08x\n", rc);
+        if (rc==DS_OK &&
+            (wfx.wFormatTag!=wfx2.wFormatTag ||
+             wfx.nSamplesPerSec!=wfx2.nSamplesPerSec ||
+             wfx.wBitsPerSample!=wfx2.wBitsPerSample ||
+             wfx.nChannels!=wfx2.nChannels)) {
+            trace("Requested format tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n",
+                  wfx2.wFormatTag,wfx2.nSamplesPerSec,wfx2.wBitsPerSample,
+                  wfx2.nChannels,wfx2.nAvgBytesPerSec,wfx2.nBlockAlign);
+            trace("Got tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n",
+                  wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
+                  wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
+        }
+
+        ZeroMemory(&new_dsbcaps, sizeof(new_dsbcaps));
+        new_dsbcaps.dwSize = sizeof(new_dsbcaps);
+        rc=IDirectSoundBuffer_GetCaps(*dsbo,&new_dsbcaps);
+        ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() failed: %08x\n", rc);
+        if (rc==DS_OK && winetest_debug > 1) {
+            trace("    new Caps: flags=0x%08x size=%d\n",new_dsbcaps.dwFlags,
+                  new_dsbcaps.dwBufferBytes);
+        }
+
+        /* Check for primary buffer size change */
+        ok(new_dsbcaps.dwBufferBytes == dsbcaps.dwBufferBytes,
+           "    buffer size changed after SetFormat() - "
+           "previous size was %u, current size is %u\n",
+           dsbcaps.dwBufferBytes, new_dsbcaps.dwBufferBytes);
+        dsbcaps.dwBufferBytes = new_dsbcaps.dwBufferBytes;
+
+        /* Check for primary buffer flags change */
+        ok(new_dsbcaps.dwFlags == dsbcaps.dwFlags,
+           "    flags changed after SetFormat() - "
+           "previous flags were %08x, current flags are %08x\n",
+           dsbcaps.dwFlags, new_dsbcaps.dwFlags);
+
+        /* Set the CooperativeLevel back to normal */
+        /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
+        rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
+        ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) "
+           "failed: %08x\n",rc);
+    }
+
+    if (play) {
+        play_state_t state;
+        DS3DLISTENER listener_param;
+        LPDIRECTSOUND3DBUFFER buffer=NULL;
+        DS3DBUFFER buffer_param;
+        DWORD start_time,now;
+        LPVOID buffer1;
+        DWORD length1;
+
+        if (winetest_interactive) {
+            trace("    Playing %g second 440Hz tone at %dx%dx%d\n", duration,
+                  wfx.nSamplesPerSec, wfx.wBitsPerSample,wfx.nChannels);
+        }
+
+        if (is_primary) {
+            /* We must call SetCooperativeLevel to be allowed to call Lock */
+            /* DSOUND: Setting DirectSound cooperative level to
+             * DSSCL_WRITEPRIMARY */
+            rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),
+                                                 DSSCL_WRITEPRIMARY);
+            ok(rc==DS_OK,
+               "IDirectSound8_SetCooperativeLevel(DSSCL_WRITEPRIMARY) failed: %08x\n",rc);
+            if (rc!=DS_OK)
+                return;
+        }
+        if (buffer3d) {
+            LPDIRECTSOUNDBUFFER temp_buffer;
+
+            rc=IDirectSoundBuffer_QueryInterface(*dsbo,&IID_IDirectSound3DBuffer,
+                                                 (LPVOID *)&buffer);
+            ok(rc==DS_OK,"IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc);
+            if (rc!=DS_OK)
+                return;
+
+            /* check the COM interface */
+            rc=IDirectSoundBuffer_QueryInterface(*dsbo, &IID_IDirectSoundBuffer,
+                                                 (LPVOID *)&temp_buffer);
+            ok(rc==DS_OK && temp_buffer!=NULL,
+               "IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc);
+            ok(temp_buffer==*dsbo,"COM interface broken: %p != %p\n",
+               temp_buffer,*dsbo);
+            ref=IDirectSoundBuffer_Release(temp_buffer);
+            ok(ref==1,"IDirectSoundBuffer_Release() has %d references, "
+               "should have 1\n",ref);
+
+            temp_buffer=NULL;
+            rc=IDirectSound3DBuffer_QueryInterface(*dsbo, &IID_IDirectSoundBuffer,
+                                                   (LPVOID *)&temp_buffer);
+            ok(rc==DS_OK && temp_buffer!=NULL,
+               "IDirectSound3DBuffer_QueryInterface() failed: %08x\n", rc);
+            ok(temp_buffer==*dsbo,"COM interface broken: %p != %p\n",
+               temp_buffer,*dsbo);
+            ref=IDirectSoundBuffer_Release(temp_buffer);
+            ok(ref==1,"IDirectSoundBuffer_Release() has %d references, "
+               "should have 1\n",ref);
+
+            ref=IDirectSoundBuffer_Release(*dsbo);
+            ok(ref==0,"IDirectSoundBuffer_Release() has %d references, "
+               "should have 0\n",ref);
+
+            rc=IDirectSound3DBuffer_QueryInterface(buffer,
+                                                   &IID_IDirectSoundBuffer,
+                                                   (LPVOID *)dsbo);
+            ok(rc==DS_OK && *dsbo!=NULL,"IDirectSound3DBuffer_QueryInterface() "
+               "failed: %08x\n",rc);
+
+            /* DSOUND: Error: Invalid buffer */
+            rc=IDirectSound3DBuffer_GetAllParameters(buffer,0);
+            ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() "
+               "failed: %08x\n",rc);
+
+            ZeroMemory(&buffer_param, sizeof(buffer_param));
+
+            /* DSOUND: Error: Invalid buffer */
+            rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param);
+            ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() "
+               "failed: %08x\n",rc);
+
+            buffer_param.dwSize=sizeof(buffer_param);
+            rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param);
+            ok(rc==DS_OK,"IDirectSound3DBuffer_GetAllParameters() failed: %08x\n", rc);
+        }
+        if (set_volume) {
+            if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) {
+                LONG val;
+                rc=IDirectSoundBuffer_GetVolume(*dsbo,&val);
+                ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %08x\n", rc);
+
+                rc=IDirectSoundBuffer_SetVolume(*dsbo,volume);
+                ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume() failed: %08x\n", rc);
+            } else {
+                /* DSOUND: Error: Buffer does not have CTRLVOLUME */
+                rc=IDirectSoundBuffer_GetVolume(*dsbo,&volume);
+                ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetVolume() "
+                   "should have returned DSERR_CONTROLUNAVAIL, returned: %08x\n", rc);
+            }
+        }
+
+        if (set_pan) {
+            if (dsbcaps.dwFlags & DSBCAPS_CTRLPAN) {
+                LONG val;
+                rc=IDirectSoundBuffer_GetPan(*dsbo,&val);
+                ok(rc==DS_OK,"IDirectSoundBuffer_GetPan() failed: %08x\n", rc);
+
+                rc=IDirectSoundBuffer_SetPan(*dsbo,pan);
+                ok(rc==DS_OK,"IDirectSoundBuffer_SetPan() failed: %08x\n", rc);
+            } else {
+                /* DSOUND: Error: Buffer does not have CTRLPAN */
+                rc=IDirectSoundBuffer_GetPan(*dsbo,&pan);
+                ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetPan() "
+                   "should have returned DSERR_CONTROLUNAVAIL, returned: %08x\n", rc);
+            }
+        }
+
+        /* try an offset past the end of the buffer */
+        rc = IDirectSoundBuffer_Lock(*dsbo, dsbcaps.dwBufferBytes, 0, &buffer1,
+                                      &length1, NULL, NULL,
+                                      DSBLOCK_ENTIREBUFFER);
+        ok(rc==DSERR_INVALIDPARAM, "IDirectSoundBuffer_Lock() should have "
+           "returned DSERR_INVALIDPARAM, returned %08x\n", rc);
+
+        /* try a size larger than the buffer */
+        rc = IDirectSoundBuffer_Lock(*dsbo, 0, dsbcaps.dwBufferBytes + 1,
+                                     &buffer1, &length1, NULL, NULL,
+                                     DSBLOCK_FROMWRITECURSOR);
+        ok(rc==DSERR_INVALIDPARAM, "IDirectSoundBuffer_Lock() should have "
+           "returned DSERR_INVALIDPARAM, returned %08x\n", rc);
+
+        state.wave=wave_generate_la(&wfx,duration,&state.wave_len);
+
+        state.dsbo=*dsbo;
+        state.wfx=&wfx;
+        state.buffer_size=dsbcaps.dwBufferBytes;
+        state.played=state.written=state.offset=0;
+        buffer_refill8(&state,state.buffer_size);
+
+        rc=IDirectSoundBuffer_Play(*dsbo,0,0,DSBPLAY_LOOPING);
+        ok(rc==DS_OK,"IDirectSoundBuffer_Play() failed: %08x\n", rc);
+
+        rc=IDirectSoundBuffer_GetStatus(*dsbo,&status);
+        ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %08x\n", rc);
+        ok(status==(DSBSTATUS_PLAYING|DSBSTATUS_LOOPING),
+           "GetStatus: bad status: %x\n",status);
+
+        if (listener) {
+            ZeroMemory(&listener_param,sizeof(listener_param));
+            listener_param.dwSize=sizeof(listener_param);
+            rc=IDirectSound3DListener_GetAllParameters(listener,&listener_param);
+            ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() "
+               "failed: %08x\n",rc);
+            if (move_listener) {
+                listener_param.vPosition.x = -5.0f;
+                listener_param.vVelocity.x = (float)(10.0/duration);
+            }
+            rc=IDirectSound3DListener_SetAllParameters(listener,
+                                                       &listener_param,
+                                                       DS3D_IMMEDIATE);
+            ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: %08x\n", rc);
+        }
+        if (buffer3d) {
+            if (move_sound) {
+                buffer_param.vPosition.x = 100.0f;
+                buffer_param.vVelocity.x = (float)(-200.0/duration);
+            }
+            buffer_param.flMinDistance = 10;
+            rc=IDirectSound3DBuffer_SetAllParameters(buffer,&buffer_param,
+                                                     DS3D_IMMEDIATE);
+            ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %08x\n", rc);
+        }
+
+        start_time=GetTickCount();
+        while (buffer_service8(&state)) {
+            WaitForSingleObject(GetCurrentProcess(),TIME_SLICE);
+            now=GetTickCount();
+            if (listener && move_listener) {
+                listener_param.vPosition.x = (float)(-5.0+10.0*(now-start_time)/1000/duration);
+                if (winetest_debug>2)
+                    trace("listener position=%g\n",listener_param.vPosition.x);
+                rc=IDirectSound3DListener_SetPosition(listener,
+                    listener_param.vPosition.x,listener_param.vPosition.y,
+                    listener_param.vPosition.z,DS3D_IMMEDIATE);
+                ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: %08x\n",rc);
+            }
+            if (buffer3d && move_sound) {
+                buffer_param.vPosition.x = (float)(100-200.0*(now-start_time)/1000/duration);
+                if (winetest_debug>2)
+                    trace("sound position=%g\n",buffer_param.vPosition.x);
+                rc=IDirectSound3DBuffer_SetPosition(buffer,
+                    buffer_param.vPosition.x,buffer_param.vPosition.y,
+                    buffer_param.vPosition.z,DS3D_IMMEDIATE);
+                ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %08x\n", rc);
+            }
+        }
+        /* Check the sound duration was within 10% of the expected value */
+        now=GetTickCount();
+        ok(fabs(1000*duration-now+start_time)<=100*duration,
+           "The sound played for %d ms instead of %g ms\n",
+           now-start_time,1000*duration);
+
+        HeapFree(GetProcessHeap(), 0, state.wave);
+        if (is_primary) {
+            /* Set the CooperativeLevel back to normal */
+            /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
+            rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
+            ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) "
+               "failed: %08x\n",rc);
+        }
+        if (buffer3d) {
+            ref=IDirectSound3DBuffer_Release(buffer);
+            ok(ref==0,"IDirectSound3DBuffer_Release() has %d references, "
+               "should have 0\n",ref);
+        }
+    }
+}
+
+static HRESULT test_secondary8(LPGUID lpGuid, int play,
+                               int has_3d, int has_3dbuffer,
+                               int has_listener, int has_duplicate,
+                               int move_listener, int move_sound)
+{
+    HRESULT rc;
+    LPDIRECTSOUND8 dso=NULL;
+    LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL;
+    LPDIRECTSOUND3DLISTENER listener=NULL;
+    DSBUFFERDESC bufdesc;
+    WAVEFORMATEX wfx, wfx1;
+    int ref;
+
+    /* Create the DirectSound object */
+    rc=pDirectSoundCreate8(lpGuid,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate8() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        return rc;
+
+    /* We must call SetCooperativeLevel before creating primary buffer */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
+    rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+    ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
+    if (has_3d)
+        bufdesc.dwFlags|=DSBCAPS_CTRL3D;
+    else
+        bufdesc.dwFlags|=(DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN);
+    rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+    ok((rc==DS_OK && primary!=NULL) || (rc == DSERR_CONTROLUNAVAIL),
+       "IDirectSound8_CreateSoundBuffer() failed to create a %sprimary buffer: %08x\n",has_3d?"3D ":"", rc);
+    if (rc == DSERR_CONTROLUNAVAIL)
+        trace("  No Primary\n");
+    else if (rc==DS_OK && primary!=NULL) {
+        rc=IDirectSoundBuffer_GetFormat(primary,&wfx1,sizeof(wfx1),NULL);
+        ok(rc==DS_OK,"IDirectSoundBuffer8_Getformat() failed: %08x\n", rc);
+        if (rc!=DS_OK)
+            goto EXIT1;
+
+        if (has_listener) {
+            rc=IDirectSoundBuffer_QueryInterface(primary,
+                                                 &IID_IDirectSound3DListener,
+                                                 (void **)&listener);
+            ok(rc==DS_OK && listener!=NULL,
+               "IDirectSoundBuffer_QueryInterface() failed to get a 3D "
+               "listener %08x\n",rc);
+            ref=IDirectSoundBuffer_Release(primary);
+            ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
+               "should have 0\n",ref);
+            if (rc==DS_OK && listener!=NULL) {
+                DS3DLISTENER listener_param;
+                ZeroMemory(&listener_param,sizeof(listener_param));
+                /* DSOUND: Error: Invalid buffer */
+                rc=IDirectSound3DListener_GetAllParameters(listener,0);
+                ok(rc==DSERR_INVALIDPARAM,
+                   "IDirectSound3dListener_GetAllParameters() should have "
+                   "returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+
+                /* DSOUND: Error: Invalid buffer */
+                rc=IDirectSound3DListener_GetAllParameters(listener,
+                                                           &listener_param);
+                ok(rc==DSERR_INVALIDPARAM,
+                   "IDirectSound3dListener_GetAllParameters() should have "
+                   "returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+
+                listener_param.dwSize=sizeof(listener_param);
+                rc=IDirectSound3DListener_GetAllParameters(listener,
+                                                           &listener_param);
+                ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() "
+                   "failed: %08x\n",rc);
+            } else {
+                ok(listener==NULL, "IDirectSoundBuffer_QueryInterface() "
+                   "failed but returned a listener anyway\n");
+                ok(rc!=DS_OK, "IDirectSoundBuffer_QueryInterface() succeeded "
+                   "but returned a NULL listener\n");
+                if (listener) {
+                    ref=IDirectSound3DListener_Release(listener);
+                    ok(ref==0,"IDirectSound3dListener_Release() listener has "
+                       "%d references, should have 0\n",ref);
+                }
+                goto EXIT2;
+            }
+        }
+
+        init_format(&wfx,WAVE_FORMAT_PCM,22050,16,2);
+        secondary=NULL;
+        ZeroMemory(&bufdesc, sizeof(bufdesc));
+        bufdesc.dwSize=sizeof(bufdesc);
+        bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;
+        if (has_3d)
+            bufdesc.dwFlags|=DSBCAPS_CTRL3D;
+        else
+            bufdesc.dwFlags|=
+                (DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN);
+        bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000,
+                                    wfx.nBlockAlign);
+        bufdesc.lpwfxFormat=&wfx;
+        if (has_3d) {
+            /* a stereo 3D buffer should fail */
+            rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            ok(rc==DSERR_INVALIDPARAM,
+               "IDirectSound8_CreateSoundBuffer(secondary) should have "
+               "returned DSERR_INVALIDPARAM, returned %08x\n", rc);
+            if (secondary)
+                ref=IDirectSoundBuffer_Release(secondary);
+            init_format(&wfx,WAVE_FORMAT_PCM,22050,16,1);
+        }
+
+        if (winetest_interactive) {
+            trace("  Testing a %s%ssecondary buffer %s%s%s%sat %dx%dx%d "
+                  "with a primary buffer at %dx%dx%d\n",
+                  has_3dbuffer?"3D ":"",
+                  has_duplicate?"duplicated ":"",
+                  listener!=NULL||move_sound?"with ":"",
+                  move_listener?"moving ":"",
+                  listener!=NULL?"listener ":"",
+                  listener&&move_sound?"and moving sound ":move_sound?
+                  "moving sound ":"",
+                  wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels,
+                  wfx1.nSamplesPerSec,wfx1.wBitsPerSample,wfx1.nChannels);
+        }
+        rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+        ok(rc==DS_OK && secondary!=NULL,"IDirectSound8_CreateSoundBuffer() "
+           "failed to create a %s%ssecondary buffer %s%s%s%sat %dx%dx%d (%s): %08x\n",
+           has_3dbuffer?"3D ":"", has_duplicate?"duplicated ":"",
+           listener!=NULL||move_sound?"with ":"", move_listener?"moving ":"",
+           listener!=NULL?"listener ":"",
+           listener&&move_sound?"and moving sound ":move_sound?
+           "moving sound ":"",
+           wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels,
+           getDSBCAPS(bufdesc.dwFlags),rc);
+        if (rc==DS_OK && secondary!=NULL) {
+            if (!has_3d) {
+                LONG refvol,vol,refpan,pan;
+
+                /* Check the initial secondary buffer's volume and pan */
+                rc=IDirectSoundBuffer_GetVolume(secondary,&vol);
+                ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(secondary) failed: %08x\n",rc);
+                ok(vol==0,"wrong volume for a new secondary buffer: %d\n",vol);
+                rc=IDirectSoundBuffer_GetPan(secondary,&pan);
+                ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(secondary) failed: %08x\n",rc);
+                ok(pan==0,"wrong pan for a new secondary buffer: %d\n",pan);
+
+                /* Check that changing the secondary buffer's volume and pan
+                 * does not impact the primary buffer's volume and pan
+                 */
+                rc=IDirectSoundBuffer_GetVolume(primary,&refvol);
+                ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(primary) failed: %08x\n",rc);
+                rc=IDirectSoundBuffer_GetPan(primary,&refpan);
+                ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: %08x\n",rc);
+
+                rc=IDirectSoundBuffer_SetVolume(secondary,-1000);
+                ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: %08x\n",rc);
+                rc=IDirectSoundBuffer_GetVolume(secondary,&vol);
+                ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: %08x\n",rc);
+                ok(vol==-1000,"secondary: wrong volume %d instead of -1000\n",
+                   vol);
+                rc=IDirectSoundBuffer_SetPan(secondary,-1000);
+                ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: %08x\n",rc);
+                rc=IDirectSoundBuffer_GetPan(secondary,&pan);
+                ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: %08x\n",rc);
+                ok(pan==-1000,"secondary: wrong pan %d instead of -1000\n",
+                   pan);
+
+                rc=IDirectSoundBuffer_GetVolume(primary,&vol);
+                ok(rc==DS_OK,"IDirectSoundBuffer_`GetVolume(primary) failed: i%08x\n",rc);
+                ok(vol==refvol,"The primary volume changed from %d to %d\n",
+                   refvol,vol);
+                rc=IDirectSoundBuffer_GetPan(primary,&pan);
+                ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: %08x\n",rc);
+                ok(pan==refpan,"The primary pan changed from %d to %d\n",
+                   refpan,pan);
+
+                rc=IDirectSoundBuffer_SetVolume(secondary,0);
+                ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: %08x\n",rc);
+                rc=IDirectSoundBuffer_SetPan(secondary,0);
+                ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: %08x\n",rc);
+            }
+            if (has_duplicate) {
+                LPDIRECTSOUNDBUFFER duplicated=NULL;
+
+                /* DSOUND: Error: Invalid source buffer */
+                rc=IDirectSound8_DuplicateSoundBuffer(dso,0,0);
+                ok(rc==DSERR_INVALIDPARAM,
+                   "IDirectSound8_DuplicateSoundBuffer() should have returned "
+                   "DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+                /* DSOUND: Error: Invalid dest buffer */
+                rc=IDirectSound8_DuplicateSoundBuffer(dso,secondary,0);
+                ok(rc==DSERR_INVALIDPARAM,
+                   "IDirectSound8_DuplicateSoundBuffer() should have returned "
+                   "DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+                /* DSOUND: Error: Invalid source buffer */
+                rc=IDirectSound8_DuplicateSoundBuffer(dso,0,&duplicated);
+                ok(rc==DSERR_INVALIDPARAM,
+                   "IDirectSound8_DuplicateSoundBuffer() should have returned "
+                   "DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+                duplicated=NULL;
+                rc=IDirectSound8_DuplicateSoundBuffer(dso,secondary,
+                                                      &duplicated);
+                ok(rc==DS_OK && duplicated!=NULL,
+                   "IDirectSound8_DuplicateSoundBuffer() failed to duplicate "
+                   "a secondary buffer: %08x\n",rc);
+
+                if (rc==DS_OK && duplicated!=NULL) {
+                    ref=IDirectSoundBuffer_Release(secondary);
+                    ok(ref==0,"IDirectSoundBuffer_Release() secondary has %d "
+                       "references, should have 0\n",ref);
+                    secondary=duplicated;
+                }
+            }
+
+            if (rc==DS_OK && secondary!=NULL) {
+                double duration;
+                duration=(move_listener || move_sound?4.0:1.0);
+                test_buffer8(dso,&secondary,0,FALSE,0,FALSE,0,
+                             winetest_interactive,duration,has_3dbuffer,
+                             listener,move_listener,move_sound);
+                ref=IDirectSoundBuffer_Release(secondary);
+                ok(ref==0,"IDirectSoundBuffer_Release() %s has %d references, "
+                   "should have 0\n",has_duplicate?"duplicated":"secondary",
+                   ref);
+            }
+        }
+EXIT1:
+        if (has_listener) {
+            if (listener) {
+                ref=IDirectSound3DListener_Release(listener);
+                ok(ref==0,"IDirectSound3dListener_Release() listener has %d "
+                   "references, should have 0\n",ref);
+            }
+        } else {
+            ref=IDirectSoundBuffer_Release(primary);
+            ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
+               "should have 0\n",ref);
+        }
+    } else {
+        ok(primary==NULL,"IDirectSound8_CreateSoundBuffer(primary) failed "
+           "but primary created anyway\n");
+        ok(rc!=DS_OK,"IDirectSound8_CreateSoundBuffer(primary) succeeded "
+           "but primary not created\n");
+        if (primary) {
+            ref=IDirectSoundBuffer_Release(primary);
+            ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
+               "should have 0\n",ref);
+        }
+    }
+EXIT2:
+    /* Set the CooperativeLevel back to normal */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
+    rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
+    ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n",rc);
+
+EXIT:
+    ref=IDirectSound8_Release(dso);
+    ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref);
+    if (ref!=0)
+        return DSERR_GENERIC;
+
+    return rc;
+}
+
+static HRESULT test_for_driver8(LPGUID lpGuid)
+{
+    HRESULT rc;
+    LPDIRECTSOUND8 dso=NULL;
+    int ref;
+
+    /* Create the DirectSound object */
+    rc=pDirectSoundCreate8(lpGuid,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
+       "DirectSoundCreate8() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        return rc;
+
+    ref=IDirectSound8_Release(dso);
+    ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref);
+    if (ref!=0)
+        return DSERR_GENERIC;
+
+    return rc;
+}
+
+static HRESULT test_primary8(LPGUID lpGuid)
+{
+    HRESULT rc;
+    LPDIRECTSOUND8 dso=NULL;
+    LPDIRECTSOUNDBUFFER primary=NULL;
+    DSBUFFERDESC bufdesc;
+    DSCAPS dscaps;
+    int ref, i;
+
+    /* Create the DirectSound object */
+    rc=pDirectSoundCreate8(lpGuid,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate8() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        return rc;
+
+    /* Get the device capabilities */
+    ZeroMemory(&dscaps, sizeof(dscaps));
+    dscaps.dwSize=sizeof(dscaps);
+    rc=IDirectSound8_GetCaps(dso,&dscaps);
+    ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
+    rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+    ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    /* Testing the primary buffer */
+    primary=NULL;
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN;
+    rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+    ok((rc==DS_OK && primary!=NULL) || (rc == DSERR_CONTROLUNAVAIL),
+       "IDirectSound8_CreateSoundBuffer() failed to create a primary buffer: %08x\n",rc);
+    if (rc == DSERR_CONTROLUNAVAIL)
+        trace("  No Primary\n");
+    else if (rc==DS_OK && primary!=NULL) {
+        test_buffer8(dso,&primary,1,TRUE,0,TRUE,0,winetest_interactive &&
+                     !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,NULL,0,0);
+        if (winetest_interactive) {
+            LONG volume,pan;
+
+            volume = DSBVOLUME_MAX;
+            for (i = 0; i < 6; i++) {
+                test_buffer8(dso,&primary,1,TRUE,volume,TRUE,0,
+                             winetest_interactive &&
+                             !(dscaps.dwFlags & DSCAPS_EMULDRIVER),
+                             1.0,0,NULL,0,0);
+                volume -= ((DSBVOLUME_MAX-DSBVOLUME_MIN) / 40);
+            }
+
+            pan = DSBPAN_LEFT;
+            for (i = 0; i < 7; i++) {
+                test_buffer8(dso,&primary,1,TRUE,0,TRUE,pan,
+                             winetest_interactive &&
+                             !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0);
+                pan += ((DSBPAN_RIGHT-DSBPAN_LEFT) / 6);
+            }
+        }
+        ref=IDirectSoundBuffer_Release(primary);
+        ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
+           "should have 0\n",ref);
+    }
+
+    /* Set the CooperativeLevel back to normal */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
+    rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
+    ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n",rc);
+
+EXIT:
+    ref=IDirectSound8_Release(dso);
+    ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref);
+    if (ref!=0)
+        return DSERR_GENERIC;
+
+    return rc;
+}
+
+static HRESULT test_primary_3d8(LPGUID lpGuid)
+{
+    HRESULT rc;
+    LPDIRECTSOUND8 dso=NULL;
+    LPDIRECTSOUNDBUFFER primary=NULL;
+    DSBUFFERDESC bufdesc;
+    DSCAPS dscaps;
+    int ref;
+
+    /* Create the DirectSound object */
+    rc=pDirectSoundCreate8(lpGuid,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate8() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        return rc;
+
+    /* Get the device capabilities */
+    ZeroMemory(&dscaps, sizeof(dscaps));
+    dscaps.dwSize=sizeof(dscaps);
+    rc=IDirectSound8_GetCaps(dso,&dscaps);
+    ok(rc==DS_OK,"IDirectSound8_GetCaps failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
+    rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+    ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    primary=NULL;
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
+    rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+    ok(rc==DS_OK && primary!=NULL,"IDirectSound8_CreateSoundBuffer() failed "
+       "to create a primary buffer: %08x\n",rc);
+    if (rc==DS_OK && primary!=NULL) {
+        ref=IDirectSoundBuffer_Release(primary);
+        ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
+           "should have 0\n",ref);
+        primary=NULL;
+        ZeroMemory(&bufdesc, sizeof(bufdesc));
+        bufdesc.dwSize=sizeof(bufdesc);
+        bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D;
+        rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+        ok(rc==DS_OK && primary!=NULL,"IDirectSound8_CreateSoundBuffer() "
+           "failed to create a 3D primary buffer: %08x\n",rc);
+        if (rc==DS_OK && primary!=NULL) {
+            test_buffer8(dso,&primary,1,FALSE,0,FALSE,0,
+                         winetest_interactive &&
+                         !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0);
+            ref=IDirectSoundBuffer_Release(primary);
+            ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
+               "should have 0\n",ref);
+        }
+    }
+    /* Set the CooperativeLevel back to normal */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
+    rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
+    ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n",rc);
+
+EXIT:
+    ref=IDirectSound8_Release(dso);
+    ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref);
+    if (ref!=0)
+        return DSERR_GENERIC;
+
+    return rc;
+}
+
+static HRESULT test_primary_3d_with_listener8(LPGUID lpGuid)
+{
+    HRESULT rc;
+    LPDIRECTSOUND8 dso=NULL;
+    LPDIRECTSOUNDBUFFER primary=NULL;
+    DSBUFFERDESC bufdesc;
+    DSCAPS dscaps;
+    int ref;
+
+    /* Create the DirectSound object */
+    rc=pDirectSoundCreate8(lpGuid,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate8() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        return rc;
+
+    /* Get the device capabilities */
+    ZeroMemory(&dscaps, sizeof(dscaps));
+    dscaps.dwSize=sizeof(dscaps);
+    rc=IDirectSound8_GetCaps(dso,&dscaps);
+    ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
+    rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+    ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+    primary=NULL;
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D;
+    rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+    ok(rc==DS_OK && primary!=NULL,"IDirectSound8_CreateSoundBuffer() failed "
+       "to create a 3D primary buffer %08x\n",rc);
+    if (rc==DS_OK && primary!=NULL) {
+        LPDIRECTSOUND3DLISTENER listener=NULL;
+        rc=IDirectSoundBuffer_QueryInterface(primary,
+                                             &IID_IDirectSound3DListener,
+                                             (void **)&listener);
+        ok(rc==DS_OK && listener!=NULL,"IDirectSoundBuffer_QueryInterface() "
+           "failed to get a 3D listener: %08x\n",rc);
+        if (rc==DS_OK && listener!=NULL) {
+            LPDIRECTSOUNDBUFFER temp_buffer=NULL;
+
+            /* Checking the COM interface */
+            rc=IDirectSoundBuffer_QueryInterface(primary,
+                                                 &IID_IDirectSoundBuffer,
+                                                 (LPVOID *)&temp_buffer);
+            ok(rc==DS_OK && temp_buffer!=NULL,
+               "IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc);
+            ok(temp_buffer==primary,"COM interface broken: %p != %p\n",temp_buffer,primary);
+            if (rc==DS_OK && temp_buffer!=NULL) {
+                ref=IDirectSoundBuffer_Release(temp_buffer);
+                ok(ref==1,"IDirectSoundBuffer_Release() has %d references, "
+                   "should have 1\n",ref);
+
+                temp_buffer=NULL;
+                rc=IDirectSound3DListener_QueryInterface(listener,
+                    &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer);
+                ok(rc==DS_OK && temp_buffer!=NULL,
+                   "IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc);
+                ok(temp_buffer==primary,"COM interface broken: %p != %p\n",temp_buffer,primary);
+                ref=IDirectSoundBuffer_Release(temp_buffer);
+                ok(ref==1,"IDirectSoundBuffer_Release() has %d references, "
+                   "should have 1\n",ref);
+
+                /* Testing the buffer */
+                test_buffer8(dso,&primary,1,FALSE,0,FALSE,0,
+                             winetest_interactive &&
+                             !(dscaps.dwFlags & DSCAPS_EMULDRIVER),
+                             1.0,0,listener,0,0);
+            }
+
+            /* Testing the reference counting */
+            ref=IDirectSound3DListener_Release(listener);
+            ok(ref==0,"IDirectSound3DListener_Release() listener has %d "
+               "references, should have 0\n",ref);
+        }
+
+        /* Testing the reference counting */
+        ref=IDirectSoundBuffer_Release(primary);
+        ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
+           "should have 0\n",ref);
+    }
+
+EXIT:
+    ref=IDirectSound8_Release(dso);
+    ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref);
+    if (ref!=0)
+return DSERR_GENERIC;
+
+    return rc;
+}
+
+static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
+                                   LPCSTR lpcstrModule, LPVOID lpContext)
+{
+    HRESULT rc;
+    trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule);
+
+    rc = test_for_driver8(lpGuid);
+    if (rc == DSERR_NODRIVER) {
+        trace("  No Driver\n");
+        return 1;
+    } else if (rc == DSERR_ALLOCATED) {
+        trace("  Already In Use\n");
+        return 1;
+    } else if (rc == E_FAIL) {
+        trace("  No Device\n");
+        return 1;
+    }
+
+    trace("  Testing the primary buffer\n");
+    test_primary8(lpGuid);
+
+    trace("  Testing 3D primary buffer\n");
+    test_primary_3d8(lpGuid);
+
+    trace("  Testing 3D primary buffer with listener\n");
+    test_primary_3d_with_listener8(lpGuid);
+
+    /* Testing secondary buffers */
+    test_secondary8(lpGuid,winetest_interactive,0,0,0,0,0,0);
+    test_secondary8(lpGuid,winetest_interactive,0,0,0,1,0,0);
+
+    /* Testing 3D secondary buffers */
+    test_secondary8(lpGuid,winetest_interactive,1,0,0,0,0,0);
+    test_secondary8(lpGuid,winetest_interactive,1,1,0,0,0,0);
+    test_secondary8(lpGuid,winetest_interactive,1,1,0,1,0,0);
+    test_secondary8(lpGuid,winetest_interactive,1,0,1,0,0,0);
+    test_secondary8(lpGuid,winetest_interactive,1,0,1,1,0,0);
+    test_secondary8(lpGuid,winetest_interactive,1,1,1,0,0,0);
+    test_secondary8(lpGuid,winetest_interactive,1,1,1,1,0,0);
+    test_secondary8(lpGuid,winetest_interactive,1,1,1,0,1,0);
+    test_secondary8(lpGuid,winetest_interactive,1,1,1,0,0,1);
+    test_secondary8(lpGuid,winetest_interactive,1,1,1,0,1,1);
+
+    return 1;
+}
+
+static void ds3d8_tests(void)
+{
+    HRESULT rc;
+    rc=pDirectSoundEnumerateA(&dsenum_callback,NULL);
+    ok(rc==DS_OK,"DirectSoundEnumerateA() failed: %08x\n",rc);
+}
+
+START_TEST(ds3d8)
+{
+    HMODULE hDsound;
+
+    CoInitialize(NULL);
+
+    hDsound = LoadLibrary("dsound.dll");
+    if (hDsound)
+    {
+
+        pDirectSoundEnumerateA = (void*)GetProcAddress(hDsound,
+            "DirectSoundEnumerateA");
+        pDirectSoundCreate8 = (void*)GetProcAddress(hDsound,
+            "DirectSoundCreate8");
+        if (pDirectSoundCreate8)
+            ds3d8_tests();
+        else
+            skip("ds3d8 test skipped\n");
+
+        FreeLibrary(hDsound);
+    }
+    else
+        skip("dsound.dll not found!\n");
+
+    CoUninitialize();
+}
diff --git a/rostests/winetests/dsound/dsound.c b/rostests/winetests/dsound/dsound.c
new file mode 100644 (file)
index 0000000..114dbb6
--- /dev/null
@@ -0,0 +1,1103 @@
+/*
+ * Tests basic sound playback in DirectSound.
+ * In particular we test each standard Windows sound format to make sure
+ * we handle the sound card/driver quirks correctly.
+ *
+ * Part of this test involves playing test tones. But this only makes
+ * sense if someone is going to carefully listen to it, and would only
+ * bother everyone else.
+ * So this is only done if the test is being run in interactive mode.
+ *
+ * Copyright (c) 2002-2004 Francois Gouget
+ * Copyright (c) 2007 Maarten Lankhorst
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <windows.h>
+
+#include "wine/test.h"
+#include "dsound.h"
+#include "dsconf.h"
+#include "mmreg.h"
+#include "initguid.h"
+#include "ks.h"
+#include "ksmedia.h"
+
+#include "dsound_test.h"
+
+DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
+
+static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL;
+static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID,LPDIRECTSOUND*,
+    LPUNKNOWN)=NULL;
+
+static BOOL gotdx8;
+
+static void IDirectSound_test(LPDIRECTSOUND dso, BOOL initialized,
+                              LPCGUID lpGuid)
+{
+    HRESULT rc;
+    DSCAPS dscaps;
+    int ref;
+    IUnknown * unknown;
+    IDirectSound * ds;
+    IDirectSound8 * ds8;
+    DWORD speaker_config, new_speaker_config;
+
+    /* Try to Query for objects */
+    rc=IDirectSound_QueryInterface(dso,&IID_IUnknown,(LPVOID*)&unknown);
+    ok(rc==DS_OK,"IDirectSound_QueryInterface(IID_IUnknown) failed: %08x\n", rc);
+    if (rc==DS_OK)
+        IDirectSound_Release(unknown);
+
+    rc=IDirectSound_QueryInterface(dso,&IID_IDirectSound,(LPVOID*)&ds);
+    ok(rc==DS_OK,"IDirectSound_QueryInterface(IID_IDirectSound) failed: %08x\n", rc);
+    if (rc==DS_OK)
+        IDirectSound_Release(ds);
+
+    rc=IDirectSound_QueryInterface(dso,&IID_IDirectSound8,(LPVOID*)&ds8);
+    ok(rc==E_NOINTERFACE,"IDirectSound_QueryInterface(IID_IDirectSound8) "
+       "should have failed: %08x\n",rc);
+    if (rc==DS_OK)
+        IDirectSound8_Release(ds8);
+
+    if (initialized == FALSE) {
+        /* try uninitialized object */
+        rc=IDirectSound_GetCaps(dso,0);
+        ok(rc==DSERR_UNINITIALIZED,"IDirectSound_GetCaps(NULL) "
+           "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc);
+
+        rc=IDirectSound_GetCaps(dso,&dscaps);
+        ok(rc==DSERR_UNINITIALIZED,"IDirectSound_GetCaps() "
+           "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc);
+
+        rc=IDirectSound_Compact(dso);
+        ok(rc==DSERR_UNINITIALIZED,"IDirectSound_Compact() "
+           "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc);
+
+        rc=IDirectSound_GetSpeakerConfig(dso,&speaker_config);
+        ok(rc==DSERR_UNINITIALIZED,"IDirectSound_GetSpeakerConfig() "
+           "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc);
+
+        rc=IDirectSound_Initialize(dso,lpGuid);
+        ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
+           "IDirectSound_Initialize() failed: %08x\n",rc);
+        if (rc==DSERR_NODRIVER) {
+            trace("  No Driver\n");
+            goto EXIT;
+        } else if (rc==E_FAIL) {
+            trace("  No Device\n");
+            goto EXIT;
+        } else if (rc==DSERR_ALLOCATED) {
+            trace("  Already In Use\n");
+            goto EXIT;
+        }
+    }
+
+    rc=IDirectSound_Initialize(dso,lpGuid);
+    ok(rc==DSERR_ALREADYINITIALIZED, "IDirectSound_Initialize() "
+       "should have returned DSERR_ALREADYINITIALIZED: %08x\n", rc);
+
+    /* DSOUND: Error: Invalid caps buffer */
+    rc=IDirectSound_GetCaps(dso,0);
+    ok(rc==DSERR_INVALIDPARAM,"IDirectSound_GetCaps(NULL) "
+       "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+
+    ZeroMemory(&dscaps, sizeof(dscaps));
+
+    /* DSOUND: Error: Invalid caps buffer */
+    rc=IDirectSound_GetCaps(dso,&dscaps);
+    ok(rc==DSERR_INVALIDPARAM,"IDirectSound_GetCaps() "
+       "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+
+    dscaps.dwSize=sizeof(dscaps);
+
+    /* DSOUND: Running on a certified driver */
+    rc=IDirectSound_GetCaps(dso,&dscaps);
+    ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %08x\n",rc);
+
+    rc=IDirectSound_Compact(dso);
+    ok(rc==DSERR_PRIOLEVELNEEDED,"IDirectSound_Compact() failed: %08x\n", rc);
+
+    rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+    ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %08x\n", rc);
+
+    rc=IDirectSound_Compact(dso);
+    ok(rc==DS_OK,"IDirectSound_Compact() failed: %08x\n",rc);
+
+    rc=IDirectSound_GetSpeakerConfig(dso,0);
+    ok(rc==DSERR_INVALIDPARAM,"IDirectSound_GetSpeakerConfig(NULL) "
+       "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+
+    rc=IDirectSound_GetSpeakerConfig(dso,&speaker_config);
+    ok(rc==DS_OK,"IDirectSound_GetSpeakerConfig() failed: %08x\n", rc);
+
+    speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO,
+                                        DSSPEAKER_GEOMETRY_WIDE);
+    rc=IDirectSound_SetSpeakerConfig(dso,speaker_config);
+    ok(rc==DS_OK,"IDirectSound_SetSpeakerConfig() failed: %08x\n", rc);
+    if (rc==DS_OK) {
+        rc=IDirectSound_GetSpeakerConfig(dso,&new_speaker_config);
+        ok(rc==DS_OK,"IDirectSound_GetSpeakerConfig() failed: %08x\n", rc);
+        if (rc==DS_OK && speaker_config!=new_speaker_config)
+               trace("IDirectSound_GetSpeakerConfig() failed to set speaker "
+               "config: expected 0x%08x, got 0x%08x\n",
+               speaker_config,new_speaker_config);
+    }
+
+EXIT:
+    ref=IDirectSound_Release(dso);
+    ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
+}
+
+static void IDirectSound_tests(void)
+{
+    HRESULT rc;
+    LPDIRECTSOUND dso=NULL;
+    LPCLASSFACTORY cf=NULL;
+
+    trace("Testing IDirectSound\n");
+
+    rc=CoGetClassObject(&CLSID_DirectSound, CLSCTX_INPROC_SERVER, NULL,
+                        &IID_IClassFactory, (void**)&cf);
+    ok(rc==S_OK,"CoGetClassObject(CLSID_DirectSound, IID_IClassFactory) "
+       "failed: %08x\n", rc);
+
+    rc=CoGetClassObject(&CLSID_DirectSound, CLSCTX_INPROC_SERVER, NULL,
+                        &IID_IUnknown, (void**)&cf);
+    ok(rc==S_OK,"CoGetClassObject(CLSID_DirectSound, IID_IUnknown) "
+       "failed: %08x\n", rc);
+
+    /* try the COM class factory method of creation with no device specified */
+    rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER,
+                        &IID_IDirectSound, (void**)&dso);
+    ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %08x\n", rc);
+    if (dso)
+        IDirectSound_test(dso, FALSE, NULL);
+
+    /* try the COM class factory method of creation with default playback
+     * device specified */
+    rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER,
+                        &IID_IDirectSound, (void**)&dso);
+    ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %08x\n", rc);
+    if (dso)
+        IDirectSound_test(dso, FALSE, &DSDEVID_DefaultPlayback);
+
+    /* try the COM class factory method of creation with default voice
+     * playback device specified */
+    rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER,
+                        &IID_IDirectSound, (void**)&dso);
+    ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %08x\n", rc);
+    if (dso)
+        IDirectSound_test(dso, FALSE, &DSDEVID_DefaultVoicePlayback);
+
+    /* try the COM class factory method of creation with a bad
+     * IID specified */
+    rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER,
+                        &CLSID_DirectSoundPrivate, (void**)&dso);
+    ok(rc==E_NOINTERFACE,
+       "CoCreateInstance(CLSID_DirectSound,CLSID_DirectSoundPrivate) "
+       "should have failed: %08x\n",rc);
+
+    /* try the COM class factory method of creation with a bad
+     * GUID and IID specified */
+    rc=CoCreateInstance(&CLSID_DirectSoundPrivate, NULL, CLSCTX_INPROC_SERVER,
+                        &IID_IDirectSound, (void**)&dso);
+    ok(rc==REGDB_E_CLASSNOTREG,
+       "CoCreateInstance(CLSID_DirectSoundPrivate,IID_IDirectSound) "
+       "should have failed: %08x\n",rc);
+
+    /* try with no device specified */
+    rc=pDirectSoundCreate(NULL,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
+       "DirectSoundCreate(NULL) failed: %08x\n",rc);
+    if (rc==S_OK && dso)
+        IDirectSound_test(dso, TRUE, NULL);
+
+    /* try with default playback device specified */
+    rc=pDirectSoundCreate(&DSDEVID_DefaultPlayback,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
+       "DirectSoundCreate(DSDEVID_DefaultPlayback) failed: %08x\n", rc);
+    if (rc==DS_OK && dso)
+        IDirectSound_test(dso, TRUE, NULL);
+
+    /* try with default voice playback device specified */
+    rc=pDirectSoundCreate(&DSDEVID_DefaultVoicePlayback,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
+       "DirectSoundCreate(DSDEVID_DefaultVoicePlayback) failed: %08x\n", rc);
+    if (rc==DS_OK && dso)
+        IDirectSound_test(dso, TRUE, NULL);
+
+    /* try with a bad device specified */
+    rc=pDirectSoundCreate(&DSDEVID_DefaultVoiceCapture,&dso,NULL);
+    ok(rc==DSERR_NODRIVER,"DirectSoundCreate(DSDEVID_DefaultVoiceCapture) "
+       "should have failed: %08x\n",rc);
+    if (rc==DS_OK && dso)
+        IDirectSound_Release(dso);
+}
+
+static HRESULT test_dsound(LPGUID lpGuid)
+{
+    HRESULT rc;
+    LPDIRECTSOUND dso=NULL;
+    int ref;
+
+    /* DSOUND: Error: Invalid interface buffer */
+    rc=pDirectSoundCreate(lpGuid,0,NULL);
+    ok(rc==DSERR_INVALIDPARAM,"DirectSoundCreate() should have returned "
+       "DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+    /* Create the DirectSound object */
+    rc=pDirectSoundCreate(lpGuid,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
+       "DirectSoundCreate() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        return rc;
+
+    /* Try the enumerated device */
+    IDirectSound_test(dso, TRUE, lpGuid);
+
+    /* Try the COM class factory method of creation with enumerated device */
+    rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER,
+                        &IID_IDirectSound, (void**)&dso);
+    ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %08x\n", rc);
+    if (dso)
+        IDirectSound_test(dso, FALSE, lpGuid);
+
+    /* Create a DirectSound object */
+    rc=pDirectSoundCreate(lpGuid,&dso,NULL);
+    ok(rc==DS_OK,"DirectSoundCreate() failed: %08x\n",rc);
+    if (rc==DS_OK) {
+        LPDIRECTSOUND dso1=NULL;
+
+        /* Create a second DirectSound object */
+        rc=pDirectSoundCreate(lpGuid,&dso1,NULL);
+        ok(rc==DS_OK,"DirectSoundCreate() failed: %08x\n",rc);
+        if (rc==DS_OK) {
+            /* Release the second DirectSound object */
+            ref=IDirectSound_Release(dso1);
+            ok(ref==0,"IDirectSound_Release() has %d references, should have "
+               "0\n",ref);
+            ok(dso!=dso1,"DirectSound objects should be unique: dso=%p,dso1=%p\n",dso,dso1);
+        }
+
+        /* Release the first DirectSound object */
+        ref=IDirectSound_Release(dso);
+        ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",
+           ref);
+        if (ref!=0)
+            return DSERR_GENERIC;
+    } else
+        return rc;
+
+    /* Create a DirectSound object */
+    rc=pDirectSoundCreate(lpGuid,&dso,NULL);
+    ok(rc==DS_OK,"DirectSoundCreate() failed: %08x\n",rc);
+    if (rc==DS_OK) {
+        LPDIRECTSOUNDBUFFER secondary;
+        DSBUFFERDESC bufdesc;
+        WAVEFORMATEX wfx;
+
+        init_format(&wfx,WAVE_FORMAT_PCM,11025,8,1);
+        ZeroMemory(&bufdesc, sizeof(bufdesc));
+        bufdesc.dwSize=sizeof(bufdesc);
+        bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRL3D;
+        bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000,
+                                    wfx.nBlockAlign);
+        bufdesc.lpwfxFormat=&wfx;
+        rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+        ok(rc==DS_OK && secondary!=NULL,
+           "IDirectSound_CreateSoundBuffer() failed to create a secondary "
+           "buffer %08x\n",rc);
+        if (rc==DS_OK && secondary!=NULL) {
+            LPDIRECTSOUND3DBUFFER buffer3d;
+            rc=IDirectSound_QueryInterface(secondary, &IID_IDirectSound3DBuffer,
+                                           (void **)&buffer3d);
+            ok(rc==DS_OK && buffer3d!=NULL,"IDirectSound_QueryInterface() "
+               "failed: %08x\n",rc);
+            if (rc==DS_OK && buffer3d!=NULL) {
+                ref=IDirectSound3DBuffer_AddRef(buffer3d);
+                ok(ref==2,"IDirectSound3DBuffer_AddRef() has %d references, "
+                   "should have 2\n",ref);
+            }
+            ref=IDirectSoundBuffer_AddRef(secondary);
+            ok(ref==2,"IDirectSoundBuffer_AddRef() has %d references, "
+               "should have 2\n",ref);
+        }
+        /* release with buffer */
+        ref=IDirectSound_Release(dso);
+        ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",
+           ref);
+        if (ref!=0)
+            return DSERR_GENERIC;
+    } else
+        return rc;
+
+    return DS_OK;
+}
+
+static HRESULT test_primary(LPGUID lpGuid)
+{
+    HRESULT rc;
+    LPDIRECTSOUND dso=NULL;
+    LPDIRECTSOUNDBUFFER primary=NULL,second=NULL,third=NULL;
+    DSBUFFERDESC bufdesc;
+    DSCAPS dscaps;
+    WAVEFORMATEX wfx;
+    int ref;
+
+    /* Create the DirectSound object */
+    rc=pDirectSoundCreate(lpGuid,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED,
+       "DirectSoundCreate() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        return rc;
+
+    /* Get the device capabilities */
+    ZeroMemory(&dscaps, sizeof(dscaps));
+    dscaps.dwSize=sizeof(dscaps);
+    rc=IDirectSound_GetCaps(dso,&dscaps);
+    ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    /* DSOUND: Error: Invalid buffer description pointer */
+    rc=IDirectSound_CreateSoundBuffer(dso,0,0,NULL);
+    ok(rc==DSERR_INVALIDPARAM,
+       "IDirectSound_CreateSoundBuffer() should have failed: %08x\n", rc);
+
+    /* DSOUND: Error: NULL pointer is invalid */
+    /* DSOUND: Error: Invalid buffer description pointer */
+    rc=IDirectSound_CreateSoundBuffer(dso,0,&primary,NULL);
+    ok(rc==DSERR_INVALIDPARAM && primary==0,
+       "IDirectSound_CreateSoundBuffer() should have failed: rc=%08x,"
+       "dsbo=%p\n",rc,primary);
+
+    /* DSOUND: Error: Invalid size */
+    /* DSOUND: Error: Invalid buffer description */
+    primary=NULL;
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc)-1;
+    rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+    ok(rc==DSERR_INVALIDPARAM && primary==0,
+       "IDirectSound_CreateSoundBuffer() should have failed: rc=%08x,"
+       "primary=%p\n",rc,primary);
+
+    /* DSOUND: Error: DSBCAPS_PRIMARYBUFFER flag with non-NULL lpwfxFormat */
+    /* DSOUND: Error: Invalid buffer description pointer */
+    primary=NULL;
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
+    bufdesc.lpwfxFormat=&wfx;
+    rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+    ok(rc==DSERR_INVALIDPARAM && primary==0,
+       "IDirectSound_CreateSoundBuffer() should have failed: rc=%08x,"
+       "primary=%p\n",rc,primary);
+
+    /* DSOUND: Error: No DSBCAPS_PRIMARYBUFFER flag with NULL lpwfxFormat */
+    /* DSOUND: Error: Invalid buffer description pointer */
+    primary=NULL;
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=0;
+    bufdesc.lpwfxFormat=NULL;
+    rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+    ok(rc==DSERR_INVALIDPARAM && primary==0,
+       "IDirectSound_CreateSoundBuffer() should have failed: rc=%08x,"
+       "primary=%p\n",rc,primary);
+
+    /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
+    rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+    ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    /* Testing the primary buffer */
+    primary=NULL;
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME;
+    bufdesc.lpwfxFormat = &wfx;
+    init_format(&wfx,WAVE_FORMAT_PCM,11025,8,2);
+    rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+    ok(rc==DSERR_INVALIDPARAM,"IDirectSound_CreateSoundBuffer() should have "
+       "returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+    if (rc==DS_OK && primary!=NULL)
+        IDirectSoundBuffer_Release(primary);
+
+    primary=NULL;
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME;
+    rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+    ok((rc==DS_OK && primary!=NULL) || (rc==DSERR_CONTROLUNAVAIL),
+       "IDirectSound_CreateSoundBuffer() failed to create a primary buffer: %08x\n",rc);
+    if (rc==DSERR_CONTROLUNAVAIL)
+        trace("  No Primary\n");
+    else if (rc==DS_OK && primary!=NULL) {
+        LONG vol;
+
+        /* Try to create a second primary buffer */
+        /* DSOUND: Error: The primary buffer already exists.
+         * Any changes made to the buffer description will be ignored. */
+        rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&second,NULL);
+        ok(rc==DS_OK && second==primary,
+           "IDirectSound_CreateSoundBuffer() should have returned original "
+           "primary buffer: %08x\n",rc);
+        ref=IDirectSoundBuffer_Release(second);
+        ok(ref==1,"IDirectSoundBuffer_Release() primary has %d references, "
+           "should have 1\n",ref);
+
+        /* Try to duplicate a primary buffer */
+        /* DSOUND: Error: Can't duplicate primary buffers */
+        rc=IDirectSound_DuplicateSoundBuffer(dso,primary,&third);
+        /* rc=0x88780032 */
+        ok(rc!=DS_OK,"IDirectSound_DuplicateSoundBuffer() primary buffer "
+           "should have failed %08x\n",rc);
+
+        rc=IDirectSoundBuffer_GetVolume(primary,&vol);
+        ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %08x\n", rc);
+
+        if (winetest_interactive) {
+            trace("Playing a 5 seconds reference tone at the current "
+                  "volume.\n");
+            if (rc==DS_OK)
+                trace("(the current volume is %d according to DirectSound)\n",
+                      vol);
+            trace("All subsequent tones should be identical to this one.\n");
+            trace("Listen for stutter, changes in pitch, volume, etc.\n");
+        }
+        test_buffer(dso,&primary,1,FALSE,0,FALSE,0,winetest_interactive &&
+                    !(dscaps.dwFlags & DSCAPS_EMULDRIVER),5.0,0,0,0,0,FALSE,0);
+
+        ref=IDirectSoundBuffer_Release(primary);
+        ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
+           "should have 0\n",ref);
+    }
+
+    /* Set the CooperativeLevel back to normal */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
+    rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
+    ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %08x\n", rc);
+
+EXIT:
+    ref=IDirectSound_Release(dso);
+    ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
+    if (ref!=0)
+        return DSERR_GENERIC;
+
+    return rc;
+}
+
+/*
+ * Test the primary buffer at different formats while keeping the
+ * secondary buffer at a constant format.
+ */
+static HRESULT test_primary_secondary(LPGUID lpGuid)
+{
+    HRESULT rc;
+    LPDIRECTSOUND dso=NULL;
+    LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL;
+    DSBUFFERDESC bufdesc;
+    DSCAPS dscaps;
+    WAVEFORMATEX wfx, wfx2;
+    int f,ref;
+
+    /* Create the DirectSound object */
+    rc=pDirectSoundCreate(lpGuid,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED,
+       "DirectSoundCreate() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        return rc;
+
+    /* Get the device capabilities */
+    ZeroMemory(&dscaps, sizeof(dscaps));
+    dscaps.dwSize=sizeof(dscaps);
+    rc=IDirectSound_GetCaps(dso,&dscaps);
+    ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    /* We must call SetCooperativeLevel before creating primary buffer */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
+    rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+    ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
+    rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+    ok(rc==DS_OK && primary!=NULL,
+       "IDirectSound_CreateSoundBuffer() failed to create a primary buffer %08x\n",rc);
+
+    if (rc==DS_OK && primary!=NULL) {
+        for (f=0;f<NB_FORMATS;f++) {
+            /* We must call SetCooperativeLevel to be allowed to call
+             * SetFormat */
+            /* DSOUND: Setting DirectSound cooperative level to
+             * DSSCL_PRIORITY */
+            rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+            ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %08x\n", rc);
+            if (rc!=DS_OK)
+                goto EXIT;
+
+            init_format(&wfx,WAVE_FORMAT_PCM,formats[f][0],formats[f][1],
+                        formats[f][2]);
+            wfx2=wfx;
+            rc=IDirectSoundBuffer_SetFormat(primary,&wfx);
+
+            if (wfx.wBitsPerSample <= 16)
+                ok(rc==DS_OK,"IDirectSoundBuffer_SetFormat(%s) failed: %08x\n",
+                   format_string(&wfx), rc);
+            else
+                ok(rc==DS_OK || rc == E_INVALIDARG, "SetFormat (%s) failed: %08x\n",
+                   format_string(&wfx), rc);
+
+            /* There is no guarantee that SetFormat will actually change the
+             * format to what we asked for. It depends on what the soundcard
+             * supports. So we must re-query the format.
+             */
+            rc=IDirectSoundBuffer_GetFormat(primary,&wfx,sizeof(wfx),NULL);
+            ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %08x\n", rc);
+            if (rc==DS_OK &&
+                (wfx.wFormatTag!=wfx2.wFormatTag ||
+                 wfx.nSamplesPerSec!=wfx2.nSamplesPerSec ||
+                 wfx.wBitsPerSample!=wfx2.wBitsPerSample ||
+                 wfx.nChannels!=wfx2.nChannels)) {
+                trace("Requested primary format tag=0x%04x %dx%dx%d "
+                      "avg.B/s=%d align=%d\n",
+                      wfx2.wFormatTag,wfx2.nSamplesPerSec,wfx2.wBitsPerSample,
+                      wfx2.nChannels,wfx2.nAvgBytesPerSec,wfx2.nBlockAlign);
+                trace("Got tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n",
+                      wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
+                      wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
+            }
+
+            /* Set the CooperativeLevel back to normal */
+            /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
+            rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
+            ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %08x\n", rc);
+
+            init_format(&wfx2,WAVE_FORMAT_PCM,11025,16,2);
+
+            secondary=NULL;
+            ZeroMemory(&bufdesc, sizeof(bufdesc));
+            bufdesc.dwSize=sizeof(bufdesc);
+            bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;
+            bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000,
+                                        wfx.nBlockAlign);
+            bufdesc.lpwfxFormat=&wfx2;
+            if (winetest_interactive) {
+                trace("  Testing a primary buffer at %dx%dx%d with a "
+                      "secondary buffer at %dx%dx%d\n",
+                      wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels,
+                      wfx2.nSamplesPerSec,wfx2.wBitsPerSample,wfx2.nChannels);
+            }
+            rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            ok(rc==DS_OK && secondary!=NULL,
+               "IDirectSound_CreateSoundBuffer() failed to create a secondary buffer %08x\n",rc);
+
+            if (rc==DS_OK && secondary!=NULL) {
+                test_buffer(dso,&secondary,0,FALSE,0,FALSE,0,
+                            winetest_interactive,1.0,0,NULL,0,0,FALSE,0);
+
+                ref=IDirectSoundBuffer_Release(secondary);
+                ok(ref==0,"IDirectSoundBuffer_Release() has %d references, "
+                   "should have 0\n",ref);
+            }
+        }
+
+        ref=IDirectSoundBuffer_Release(primary);
+        ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
+           "should have 0\n",ref);
+    }
+
+    /* Set the CooperativeLevel back to normal */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
+    rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
+    ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %08x\n", rc);
+
+EXIT:
+    ref=IDirectSound_Release(dso);
+    ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
+    if (ref!=0)
+        return DSERR_GENERIC;
+
+    return rc;
+}
+
+static HRESULT test_secondary(LPGUID lpGuid)
+{
+    HRESULT rc;
+    LPDIRECTSOUND dso=NULL;
+    LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL;
+    DSBUFFERDESC bufdesc;
+    DSCAPS dscaps;
+    WAVEFORMATEX wfx, wfx1;
+    DWORD f;
+    int ref;
+
+    /* Create the DirectSound object */
+    rc=pDirectSoundCreate(lpGuid,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED,
+       "DirectSoundCreate() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        return rc;
+
+    /* Get the device capabilities */
+    ZeroMemory(&dscaps, sizeof(dscaps));
+    dscaps.dwSize=sizeof(dscaps);
+    rc=IDirectSound_GetCaps(dso,&dscaps);
+    ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    /* We must call SetCooperativeLevel before creating primary buffer */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
+    rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+    ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
+    rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+    ok(rc==DS_OK && primary!=NULL,
+       "IDirectSound_CreateSoundBuffer() failed to create a primary buffer %08x\n",rc);
+
+    if (rc==DS_OK && primary!=NULL) {
+        rc=IDirectSoundBuffer_GetFormat(primary,&wfx1,sizeof(wfx1),NULL);
+        ok(rc==DS_OK,"IDirectSoundBuffer8_Getformat() failed: %08x\n", rc);
+        if (rc!=DS_OK)
+            goto EXIT1;
+
+        for (f=0;f<NB_FORMATS;f++) {
+            WAVEFORMATEXTENSIBLE wfxe;
+            init_format(&wfx,WAVE_FORMAT_PCM,formats[f][0],formats[f][1],
+                        formats[f][2]);
+            secondary=NULL;
+            ZeroMemory(&bufdesc, sizeof(bufdesc));
+            bufdesc.dwSize=sizeof(bufdesc);
+            bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;
+            bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000,
+                                        wfx.nBlockAlign);
+            rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            ok(rc==DSERR_INVALIDPARAM,"IDirectSound_CreateSoundBuffer() "
+               "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+            if (rc==DS_OK && secondary!=NULL)
+                IDirectSoundBuffer_Release(secondary);
+
+            secondary=NULL;
+            ZeroMemory(&bufdesc, sizeof(bufdesc));
+            bufdesc.dwSize=sizeof(bufdesc);
+            bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;
+            bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000,
+                                        wfx.nBlockAlign);
+            bufdesc.lpwfxFormat=&wfx;
+            rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            if (gotdx8 || wfx.wBitsPerSample <= 16)
+            {
+                if (wfx.wBitsPerSample > 16)
+                    ok(((rc == DSERR_CONTROLUNAVAIL || rc == DSERR_INVALIDCALL || rc == DSERR_INVALIDPARAM /* 2003 */) && !secondary)
+                        || rc == DS_OK, /* driver dependent? */
+                        "IDirectSound_CreateSoundBuffer() "
+                        "should have returned (DSERR_CONTROLUNAVAIL or DSERR_INVALIDCALL) "
+                        "and NULL, returned: %08x %p\n", rc, secondary);
+                else
+                    ok(rc==DS_OK && secondary!=NULL,
+                        "IDirectSound_CreateSoundBuffer() failed to create a secondary buffer %08x\n",rc);
+            }
+            else
+                ok(rc==E_INVALIDARG, "Creating %d bpp buffer on dx < 8 returned: %p %08x\n",
+                   wfx.wBitsPerSample, secondary, rc);
+
+            if (!gotdx8)
+            {
+                skip("Not doing the WAVE_FORMAT_EXTENSIBLE tests\n");
+                /* Apparently they succeed with bogus values,
+                 * which means that older dsound doesn't look at them
+                 */
+                goto no_wfe;
+            }
+
+            if (secondary)
+                IDirectSoundBuffer_Release(secondary);
+            secondary = NULL;
+
+            bufdesc.lpwfxFormat=(WAVEFORMATEX*)&wfxe;
+            wfxe.Format = wfx;
+            wfxe.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+            wfxe.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+            wfxe.Format.cbSize = 1;
+            wfxe.Samples.wValidBitsPerSample = wfx.wBitsPerSample;
+            wfxe.dwChannelMask = (wfx.nChannels == 1 ? KSAUDIO_SPEAKER_MONO : KSAUDIO_SPEAKER_STEREO);
+
+            rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            ok((rc==DSERR_INVALIDPARAM || rc==DSERR_INVALIDCALL /* 2003 */) && !secondary,
+                "IDirectSound_CreateSoundBuffer() returned: %08x %p\n",
+                rc, secondary);
+            if (secondary)
+            {
+                IDirectSoundBuffer_Release(secondary);
+                secondary=NULL;
+            }
+
+            wfxe.Format.cbSize = sizeof(wfxe) - sizeof(wfx) + 1;
+
+            rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            ok(((rc==DSERR_CONTROLUNAVAIL || rc==DSERR_INVALIDCALL || rc==DSERR_INVALIDPARAM)
+                && !secondary)
+               || rc==DS_OK, /* 2003 / 2008 */
+                "IDirectSound_CreateSoundBuffer() returned: %08x %p\n",
+                rc, secondary);
+            if (secondary)
+            {
+                IDirectSoundBuffer_Release(secondary);
+                secondary=NULL;
+            }
+
+            wfxe.Format.cbSize = sizeof(wfxe) - sizeof(wfx);
+            wfxe.SubFormat = GUID_NULL;
+            rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            ok((rc==DSERR_INVALIDPARAM || rc==DSERR_INVALIDCALL) && !secondary,
+                "IDirectSound_CreateSoundBuffer() returned: %08x %p\n",
+                rc, secondary);
+            if (secondary)
+            {
+                IDirectSoundBuffer_Release(secondary);
+                secondary=NULL;
+            }
+            wfxe.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+
+            ++wfxe.Samples.wValidBitsPerSample;
+            rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            ok(rc==DSERR_INVALIDPARAM && !secondary,
+                "IDirectSound_CreateSoundBuffer() returned: %08x %p\n",
+                rc, secondary);
+            if (secondary)
+            {
+                IDirectSoundBuffer_Release(secondary);
+                secondary=NULL;
+            }
+            --wfxe.Samples.wValidBitsPerSample;
+
+            wfxe.Samples.wValidBitsPerSample = 0;
+            rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            ok(rc==DS_OK && secondary,
+                "IDirectSound_CreateSoundBuffer() returned: %08x %p\n",
+                rc, secondary);
+            if (secondary)
+            {
+                IDirectSoundBuffer_Release(secondary);
+                secondary=NULL;
+            }
+            wfxe.Samples.wValidBitsPerSample = wfxe.Format.wBitsPerSample;
+
+            rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            ok(rc==DS_OK && secondary!=NULL,
+                "IDirectSound_CreateSoundBuffer() failed to create a secondary buffer %08x\n",rc);
+
+no_wfe:
+            if (rc==DS_OK && secondary!=NULL) {
+                if (winetest_interactive) {
+                    trace("  Testing a secondary buffer at %dx%dx%d "
+                        "with a primary buffer at %dx%dx%d\n",
+                        wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels,
+                        wfx1.nSamplesPerSec,wfx1.wBitsPerSample,wfx1.nChannels);
+                }
+                test_buffer(dso,&secondary,0,FALSE,0,FALSE,0,
+                            winetest_interactive,1.0,0,NULL,0,0,FALSE,0);
+
+                ref=IDirectSoundBuffer_Release(secondary);
+                ok(ref==0,"IDirectSoundBuffer_Release() has %d references, "
+                   "should have 0\n",ref);
+            }
+        }
+EXIT1:
+        ref=IDirectSoundBuffer_Release(primary);
+        ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
+           "should have 0\n",ref);
+    }
+
+    /* Set the CooperativeLevel back to normal */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
+    rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
+    ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %08x\n", rc);
+
+EXIT:
+    ref=IDirectSound_Release(dso);
+    ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
+    if (ref!=0)
+        return DSERR_GENERIC;
+
+    return rc;
+}
+
+static HRESULT test_block_align(LPGUID lpGuid)
+{
+    HRESULT rc;
+    LPDIRECTSOUND dso=NULL;
+    LPDIRECTSOUNDBUFFER secondary=NULL;
+    DSBUFFERDESC bufdesc;
+    DSBCAPS dsbcaps;
+    WAVEFORMATEX wfx;
+    DWORD pos, pos2;
+    int ref;
+
+    /* Create the DirectSound object */
+    rc=pDirectSoundCreate(lpGuid,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED,
+       "DirectSoundCreate() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        return rc;
+
+    init_format(&wfx,WAVE_FORMAT_PCM,11025,16,2);
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;
+    bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec + 1;
+    bufdesc.lpwfxFormat=&wfx;
+    rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+    ok(rc==DS_OK,"IDirectSound_CreateSoundBuffer() "
+       "should have returned DS_OK, returned: %08x\n", rc);
+
+    if (rc==DS_OK && secondary!=NULL) {
+        ZeroMemory(&dsbcaps, sizeof(dsbcaps));
+        dsbcaps.dwSize = sizeof(dsbcaps);
+        rc=IDirectSoundBuffer_GetCaps(secondary,&dsbcaps);
+        ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() should have returned DS_OK, "
+           "returned: %08x\n", rc);
+        if (rc==DS_OK && wfx.nBlockAlign > 1)
+        {
+            ok(dsbcaps.dwBufferBytes==(wfx.nAvgBytesPerSec + wfx.nBlockAlign),
+               "Buffer size not a multiple of nBlockAlign: requested %d, "
+               "got %d, should be %d\n", bufdesc.dwBufferBytes,
+               dsbcaps.dwBufferBytes, wfx.nAvgBytesPerSec + wfx.nBlockAlign);
+
+            rc = IDirectSoundBuffer_SetCurrentPosition(secondary, 0);
+            ok(rc == DS_OK, "Could not set position to 0: %08x\n", rc);
+            rc = IDirectSoundBuffer_GetCurrentPosition(secondary, &pos, NULL);
+            ok(rc == DS_OK, "Could not get position: %08x\n", rc);
+            rc = IDirectSoundBuffer_SetCurrentPosition(secondary, 1);
+            ok(rc == DS_OK, "Could not set position to 1: %08x\n", rc);
+            rc = IDirectSoundBuffer_GetCurrentPosition(secondary, &pos2, NULL);
+            ok(rc == DS_OK, "Could not get new position: %08x\n", rc);
+            ok(pos == pos2, "Positions not the same! Old position: %d, new position: %d\n", pos, pos2);
+        }
+        ref=IDirectSoundBuffer_Release(secondary);
+        ok(ref==0,"IDirectSoundBuffer_Release() secondary has %d references, "
+           "should have 0\n",ref);
+    }
+
+    ref=IDirectSound_Release(dso);
+    ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
+    if (ref!=0)
+        return DSERR_GENERIC;
+
+    return rc;
+}
+
+static struct fmt {
+    int bits;
+    int channels;
+} fmts[] = { { 8, 1 }, { 8, 2 }, { 16, 1 }, {16, 2 } };
+
+static HRESULT test_frequency(LPGUID lpGuid)
+{
+    HRESULT rc;
+    LPDIRECTSOUND dso=NULL;
+    LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL;
+    DSBUFFERDESC bufdesc;
+    DSCAPS dscaps;
+    WAVEFORMATEX wfx, wfx1;
+    DWORD f, r;
+    int ref;
+    int rates[] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100,
+                    48000, 96000 };
+
+    /* Create the DirectSound object */
+    rc=pDirectSoundCreate(lpGuid,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED,
+       "DirectSoundCreate() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        return rc;
+
+    /* Get the device capabilities */
+    ZeroMemory(&dscaps, sizeof(dscaps));
+    dscaps.dwSize=sizeof(dscaps);
+    rc=IDirectSound_GetCaps(dso,&dscaps);
+    ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    /* We must call SetCooperativeLevel before creating primary buffer */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
+    rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+    ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
+    rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+    ok(rc==DS_OK && primary!=NULL,
+       "IDirectSound_CreateSoundBuffer() failed to create a primary buffer %08x\n",rc);
+
+    if (rc==DS_OK && primary!=NULL) {
+        rc=IDirectSoundBuffer_GetFormat(primary,&wfx1,sizeof(wfx1),NULL);
+        ok(rc==DS_OK,"IDirectSoundBuffer8_Getformat() failed: %08x\n", rc);
+        if (rc!=DS_OK)
+            goto EXIT1;
+
+        for (f=0;f<sizeof(fmts)/sizeof(fmts[0]);f++) {
+        for (r=0;r<sizeof(rates)/sizeof(rates[0]);r++) {
+            init_format(&wfx,WAVE_FORMAT_PCM,11025,fmts[f].bits,
+                        fmts[f].channels);
+            secondary=NULL;
+            ZeroMemory(&bufdesc, sizeof(bufdesc));
+            bufdesc.dwSize=sizeof(bufdesc);
+            bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_CTRLFREQUENCY;
+            bufdesc.dwBufferBytes=align((wfx.nAvgBytesPerSec*rates[r]/11025)*
+                                        BUFFER_LEN/1000,wfx.nBlockAlign);
+            bufdesc.lpwfxFormat=&wfx;
+            if (winetest_interactive) {
+                trace("  Testing a secondary buffer at %dx%dx%d "
+                      "with a primary buffer at %dx%dx%d\n",
+                      wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels,
+                      wfx1.nSamplesPerSec,wfx1.wBitsPerSample,wfx1.nChannels);
+            }
+            rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            ok(rc==DS_OK && secondary!=NULL,
+               "IDirectSound_CreateSoundBuffer() failed to create a secondary buffer %08x\n",rc);
+
+            if (rc==DS_OK && secondary!=NULL) {
+                test_buffer(dso,&secondary,0,FALSE,0,FALSE,0,
+                            winetest_interactive,1.0,0,NULL,0,0,TRUE,rates[r]);
+
+                ref=IDirectSoundBuffer_Release(secondary);
+                ok(ref==0,"IDirectSoundBuffer_Release() has %d references, "
+                   "should have 0\n",ref);
+            }
+        }
+        }
+EXIT1:
+        ref=IDirectSoundBuffer_Release(primary);
+        ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
+           "should have 0\n",ref);
+    }
+
+    /* Set the CooperativeLevel back to normal */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
+    rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
+    ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %08x\n", rc);
+
+EXIT:
+    ref=IDirectSound_Release(dso);
+    ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
+    if (ref!=0)
+        return DSERR_GENERIC;
+
+    return rc;
+}
+
+static unsigned int number;
+
+static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
+                                   LPCSTR lpcstrModule, LPVOID lpContext)
+{
+    HRESULT rc;
+    trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule);
+
+    /* Don't test the primary device */
+    if (!number++)
+    {
+        ok (!lpcstrModule[0], "lpcstrModule(%s) != NULL\n", lpcstrModule);
+        return 1;
+    }
+
+    rc = test_dsound(lpGuid);
+    if (rc == DSERR_NODRIVER)
+        trace("  No Driver\n");
+    else if (rc == DSERR_ALLOCATED)
+        trace("  Already In Use\n");
+    else if (rc == E_FAIL)
+        trace("  No Device\n");
+    else {
+        test_block_align(lpGuid);
+        test_primary(lpGuid);
+        test_primary_secondary(lpGuid);
+        test_secondary(lpGuid);
+        test_frequency(lpGuid);
+    }
+
+    return 1;
+}
+
+static void dsound_tests(void)
+{
+    HRESULT rc;
+    rc=pDirectSoundEnumerateA(&dsenum_callback,NULL);
+    ok(rc==DS_OK,"DirectSoundEnumerateA() failed: %08x\n",rc);
+}
+
+START_TEST(dsound)
+{
+    HMODULE hDsound;
+
+    CoInitialize(NULL);
+
+    hDsound = LoadLibrary("dsound.dll");
+    if (hDsound)
+    {
+        BOOL ret;
+
+        ok( FreeLibrary(hDsound), "FreeLibrary(1) returned %d\n", GetLastError());
+        SetLastError(0xdeadbeef);
+        ret = FreeLibrary(hDsound);
+        ok( ret ||
+            broken(!ret && GetLastError() == ERROR_MOD_NOT_FOUND) || /* NT4 */
+            broken(!ret && GetLastError() == ERROR_INVALID_HANDLE),  /* Win9x */
+            "FreeLibrary(2) returned %d\n", GetLastError());
+        ok(!FreeLibrary(hDsound), "DirectSound DLL still loaded\n");
+    }
+
+    hDsound = LoadLibrary("dsound.dll");
+    if (hDsound)
+    {
+
+        pDirectSoundEnumerateA = (void*)GetProcAddress(hDsound,
+            "DirectSoundEnumerateA");
+        pDirectSoundCreate = (void*)GetProcAddress(hDsound,
+            "DirectSoundCreate");
+
+        gotdx8 = !!GetProcAddress(hDsound, "DirectSoundCreate8");
+
+        IDirectSound_tests();
+        dsound_tests();
+
+        FreeLibrary(hDsound);
+    }
+    else
+        skip("dsound.dll not found!\n");
+
+    CoUninitialize();
+}
diff --git a/rostests/winetests/dsound/dsound.rbuild b/rostests/winetests/dsound/dsound.rbuild
new file mode 100644 (file)
index 0000000..57c10b5
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
+<group>
+<module name="dsound_winetest" type="win32cui" installbase="bin" installname="dsound_winetest.exe" allowwarnings="true">
+       <include base="dsound_winetest">.</include>
+       <define name="__ROS_LONG64__" />
+       <library>wine</library>
+       <library>uuid</library>
+       <library>dsound</library>
+       <library>dxguid</library>
+       <library>ole32</library>
+       <library>user32</library>
+       <file>capture.c</file>
+       <file>ds3d8.c</file>
+       <file>ds3d.c</file>
+       <file>dsound8.c</file>
+       <file>dsound.c</file>
+       <file>duplex.c</file>
+       <file>propset.c</file>
+       <file>testlist.c</file>
+</module>
+</group>
diff --git a/rostests/winetests/dsound/dsound8.c b/rostests/winetests/dsound/dsound8.c
new file mode 100644 (file)
index 0000000..a2b16d8
--- /dev/null
@@ -0,0 +1,940 @@
+/*
+ * Tests basic sound playback in DirectSound.
+ * In particular we test each standard Windows sound format to make sure
+ * we handle the sound card/driver quirks correctly.
+ *
+ * Part of this test involves playing test tones. But this only makes
+ * sense if someone is going to carefully listen to it, and would only
+ * bother everyone else.
+ * So this is only done if the test is being run in interactive mode.
+ *
+ * Copyright (c) 2002-2004 Francois Gouget
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <windows.h>
+#include <stdio.h>
+
+#include "wine/test.h"
+#include "dsound.h"
+#include "dsconf.h"
+#include "mmreg.h"
+#include "ks.h"
+#include "ksmedia.h"
+
+#include "dsound_test.h"
+
+static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL;
+static HRESULT (WINAPI *pDirectSoundCreate8)(LPCGUID,LPDIRECTSOUND8*,LPUNKNOWN)=NULL;
+
+int align(int length, int align)
+{
+    return (length / align) * align;
+}
+
+static void IDirectSound8_test(LPDIRECTSOUND8 dso, BOOL initialized,
+                               LPCGUID lpGuid)
+{
+    HRESULT rc;
+    DSCAPS dscaps;
+    int ref;
+    IUnknown * unknown;
+    IDirectSound * ds;
+    IDirectSound8 * ds8;
+    DWORD speaker_config, new_speaker_config;
+    DWORD certified;
+
+    /* Try to Query for objects */
+    rc=IDirectSound8_QueryInterface(dso,&IID_IUnknown,(LPVOID*)&unknown);
+    ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IUnknown) failed: %08x\n", rc);
+    if (rc==DS_OK)
+        IDirectSound8_Release(unknown);
+
+    rc=IDirectSound8_QueryInterface(dso,&IID_IDirectSound,(LPVOID*)&ds);
+    ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IDirectSound) failed: %08x\n", rc);
+    if (rc==DS_OK)
+        IDirectSound_Release(ds);
+
+    rc=IDirectSound8_QueryInterface(dso,&IID_IDirectSound8,(LPVOID*)&ds8);
+    ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IDirectSound8) "
+       "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+    if (rc==DS_OK)
+        IDirectSound8_Release(ds8);
+
+    if (initialized == FALSE) {
+        /* try uninitialized object */
+        rc=IDirectSound8_GetCaps(dso,0);
+        ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_GetCaps(NULL) "
+           "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc);
+
+        rc=IDirectSound8_GetCaps(dso,&dscaps);
+        ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_GetCaps() "
+           "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc);
+
+        rc=IDirectSound8_Compact(dso);
+        ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_Compact() "
+           "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc);
+
+        rc=IDirectSound8_GetSpeakerConfig(dso,&speaker_config);
+        ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_GetSpeakerConfig() "
+           "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc);
+
+        rc=IDirectSound8_VerifyCertification(dso, &certified);
+        ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_VerifyCertification() "
+           "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc);
+
+        rc=IDirectSound8_Initialize(dso,lpGuid);
+        ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
+           "IDirectSound8_Initialize() failed: %08x\n",rc);
+        if (rc==DSERR_NODRIVER) {
+            trace("  No Driver\n");
+            goto EXIT;
+        } else if (rc==E_FAIL) {
+            trace("  No Device\n");
+            goto EXIT;
+        } else if (rc==DSERR_ALLOCATED) {
+            trace("  Already In Use\n");
+            goto EXIT;
+        }
+    }
+
+    rc=IDirectSound8_Initialize(dso,lpGuid);
+    ok(rc==DSERR_ALREADYINITIALIZED, "IDirectSound8_Initialize() "
+       "should have returned DSERR_ALREADYINITIALIZED: %08x\n", rc);
+
+    /* DSOUND: Error: Invalid caps buffer */
+    rc=IDirectSound8_GetCaps(dso,0);
+    ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_GetCaps() "
+       "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+
+    ZeroMemory(&dscaps, sizeof(dscaps));
+
+    /* DSOUND: Error: Invalid caps buffer */
+    rc=IDirectSound8_GetCaps(dso,&dscaps);
+    ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_GetCaps() "
+       "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+
+    dscaps.dwSize=sizeof(dscaps);
+
+    /* DSOUND: Running on a certified driver */
+    rc=IDirectSound8_GetCaps(dso,&dscaps);
+    ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %08x\n",rc);
+
+    rc=IDirectSound8_Compact(dso);
+    ok(rc==DSERR_PRIOLEVELNEEDED,"IDirectSound8_Compact() failed: %08x\n", rc);
+
+    rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+    ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc);
+
+    rc=IDirectSound8_Compact(dso);
+    ok(rc==DS_OK,"IDirectSound8_Compact() failed: %08x\n",rc);
+
+    rc=IDirectSound8_GetSpeakerConfig(dso,0);
+    ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_GetSpeakerConfig(NULL) "
+       "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+
+    rc=IDirectSound8_GetSpeakerConfig(dso,&speaker_config);
+    ok(rc==DS_OK,"IDirectSound8_GetSpeakerConfig() failed: %08x\n", rc);
+
+    speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO,
+                                        DSSPEAKER_GEOMETRY_WIDE);
+    rc=IDirectSound8_SetSpeakerConfig(dso,speaker_config);
+    ok(rc==DS_OK,"IDirectSound8_SetSpeakerConfig() failed: %08x\n", rc);
+    if (rc==DS_OK) {
+        rc=IDirectSound8_GetSpeakerConfig(dso,&new_speaker_config);
+        ok(rc==DS_OK,"IDirectSound8_GetSpeakerConfig() failed: %08x\n", rc);
+        if (rc==DS_OK && speaker_config!=new_speaker_config)
+               trace("IDirectSound8_GetSpeakerConfig() failed to set speaker "
+               "config: expected 0x%08x, got 0x%08x\n",
+               speaker_config,new_speaker_config);
+    }
+
+    rc=IDirectSound8_VerifyCertification(dso, &certified);
+    ok(rc==DS_OK||rc==E_NOTIMPL,"IDirectSound8_VerifyCertification() failed: %08x\n", rc);
+
+EXIT:
+    ref=IDirectSound8_Release(dso);
+    ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref);
+}
+
+static void IDirectSound8_tests(void)
+{
+    HRESULT rc;
+    LPDIRECTSOUND8 dso=NULL;
+    LPCLASSFACTORY cf=NULL;
+
+    trace("Testing IDirectSound8\n");
+
+    rc=CoGetClassObject(&CLSID_DirectSound8, CLSCTX_INPROC_SERVER, NULL,
+                        &IID_IClassFactory, (void**)&cf);
+    ok(rc==S_OK,"CoGetClassObject(CLSID_DirectSound8, IID_IClassFactory) "
+       "failed: %08x\n", rc);
+
+    rc=CoGetClassObject(&CLSID_DirectSound8, CLSCTX_INPROC_SERVER, NULL,
+                        &IID_IUnknown, (void**)&cf);
+    ok(rc==S_OK,"CoGetClassObject(CLSID_DirectSound8, IID_IUnknown) "
+       "failed: %08x\n", rc);
+
+    /* try the COM class factory method of creation with no device specified */
+    rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER,
+                        &IID_IDirectSound8, (void**)&dso);
+    ok(rc==S_OK||rc==REGDB_E_CLASSNOTREG,"CoCreateInstance() failed: %08x\n", rc);
+    if (rc==REGDB_E_CLASSNOTREG) {
+        trace("  Class Not Registered\n");
+        return;
+    }
+    if (dso)
+        IDirectSound8_test(dso, FALSE, NULL);
+
+    /* try the COM class factory method of creation with default playback
+     *  device specified */
+    rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER,
+                        &IID_IDirectSound8, (void**)&dso);
+    ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound8) failed: %08x\n", rc);
+    if (dso)
+        IDirectSound8_test(dso, FALSE, &DSDEVID_DefaultPlayback);
+
+    /* try the COM class factory method of creation with default voice
+     * playback device specified */
+    rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER,
+                        &IID_IDirectSound8, (void**)&dso);
+    ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound8) failed: %08x\n", rc);
+    if (dso)
+        IDirectSound8_test(dso, FALSE, &DSDEVID_DefaultVoicePlayback);
+
+    /* try the COM class factory method of creation with a bad
+     * IID specified */
+    rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER,
+                        &CLSID_DirectSoundPrivate, (void**)&dso);
+    ok(rc==E_NOINTERFACE,
+       "CoCreateInstance(CLSID_DirectSound8,CLSID_DirectSoundPrivate) "
+       "should have failed: %08x\n",rc);
+
+    /* try the COM class factory method of creation with a bad
+     * GUID and IID specified */
+    rc=CoCreateInstance(&CLSID_DirectSoundPrivate, NULL, CLSCTX_INPROC_SERVER,
+                        &IID_IDirectSound8, (void**)&dso);
+    ok(rc==REGDB_E_CLASSNOTREG,
+       "CoCreateInstance(CLSID_DirectSoundPrivate,IID_IDirectSound8) "
+       "should have failed: %08x\n",rc);
+
+    /* try with no device specified */
+    rc=pDirectSoundCreate8(NULL,&dso,NULL);
+    ok(rc==S_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
+       "DirectSoundCreate8() failed: %08x\n",rc);
+    if (rc==DS_OK && dso)
+        IDirectSound8_test(dso, TRUE, NULL);
+
+    /* try with default playback device specified */
+    rc=pDirectSoundCreate8(&DSDEVID_DefaultPlayback,&dso,NULL);
+    ok(rc==S_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
+       "DirectSoundCreate8() failed: %08x\n",rc);
+    if (rc==DS_OK && dso)
+        IDirectSound8_test(dso, TRUE, NULL);
+
+    /* try with default voice playback device specified */
+    rc=pDirectSoundCreate8(&DSDEVID_DefaultVoicePlayback,&dso,NULL);
+    ok(rc==S_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
+       "DirectSoundCreate8() failed: %08x\n",rc);
+    if (rc==DS_OK && dso)
+        IDirectSound8_test(dso, TRUE, NULL);
+
+    /* try with a bad device specified */
+    rc=pDirectSoundCreate8(&DSDEVID_DefaultVoiceCapture,&dso,NULL);
+    ok(rc==DSERR_NODRIVER,"DirectSoundCreate8(DSDEVID_DefaultVoiceCapture) "
+       "should have failed: %08x\n",rc);
+}
+
+static HRESULT test_dsound8(LPGUID lpGuid)
+{
+    HRESULT rc;
+    LPDIRECTSOUND8 dso=NULL;
+    int ref;
+
+    /* DSOUND: Error: Invalid interface buffer */
+    rc=pDirectSoundCreate8(lpGuid,0,NULL);
+    ok(rc==DSERR_INVALIDPARAM,"DirectSoundCreate8() should have returned "
+       "DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+    /* Create the DirectSound8 object */
+    rc=pDirectSoundCreate8(lpGuid,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
+       "DirectSoundCreate8() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        return rc;
+
+    /* Try the enumerated device */
+    IDirectSound8_test(dso, TRUE, lpGuid);
+
+    /* Try the COM class factory method of creation with enumerated device */
+    rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER,
+                        &IID_IDirectSound8, (void**)&dso);
+    ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %08x\n", rc);
+    if (dso)
+        IDirectSound8_test(dso, FALSE, lpGuid);
+
+    /* Create a DirectSound8 object */
+    rc=pDirectSoundCreate8(lpGuid,&dso,NULL);
+    ok(rc==DS_OK,"DirectSoundCreate8() failed: %08x\n",rc);
+    if (rc==DS_OK) {
+        LPDIRECTSOUND8 dso1=NULL;
+
+        /* Create a second DirectSound8 object */
+        rc=pDirectSoundCreate8(lpGuid,&dso1,NULL);
+        ok(rc==DS_OK,"DirectSoundCreate8() failed: %08x\n",rc);
+        if (rc==DS_OK) {
+            /* Release the second DirectSound8 object */
+            ref=IDirectSound8_Release(dso1);
+            ok(ref==0,"IDirectSound8_Release() has %d references, "
+               "should have 0\n",ref);
+            ok(dso!=dso1,"DirectSound8 objects should be unique: "
+               "dso=%p,dso1=%p\n",dso,dso1);
+        }
+
+        /* Release the first DirectSound8 object */
+        ref=IDirectSound8_Release(dso);
+        ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",
+           ref);
+        if (ref!=0)
+            return DSERR_GENERIC;
+    } else
+        return rc;
+
+    /* Create a DirectSound8 object */
+    rc=pDirectSoundCreate8(lpGuid,&dso,NULL);
+    ok(rc==DS_OK,"DirectSoundCreate8() failed: %08x\n",rc);
+    if (rc==DS_OK) {
+        LPDIRECTSOUNDBUFFER secondary;
+        DSBUFFERDESC bufdesc;
+        WAVEFORMATEX wfx;
+
+        init_format(&wfx,WAVE_FORMAT_PCM,11025,8,1);
+        ZeroMemory(&bufdesc, sizeof(bufdesc));
+        bufdesc.dwSize=sizeof(bufdesc);
+        bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRL3D;
+        bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000,
+                                    wfx.nBlockAlign);
+        bufdesc.lpwfxFormat=&wfx;
+        rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+        ok(rc==DS_OK && secondary!=NULL,
+           "IDirectSound8_CreateSoundBuffer() failed to create a secondary "
+           "buffer: %08x\n",rc);
+        if (rc==DS_OK && secondary!=NULL) {
+            LPDIRECTSOUND3DBUFFER buffer3d;
+            LPDIRECTSOUNDBUFFER8 buffer8;
+            rc=IDirectSound8_QueryInterface(secondary,
+                                            &IID_IDirectSound3DBuffer,
+                                            (void **)&buffer3d);
+            ok(rc==DS_OK && buffer3d!=NULL,
+               "IDirectSound8_QueryInterface() failed: %08x\n", rc);
+            if (rc==DS_OK && buffer3d!=NULL) {
+                ref=IDirectSound3DBuffer_AddRef(buffer3d);
+                ok(ref==2,"IDirectSound3DBuffer_AddRef() has %d references, "
+                   "should have 2\n",ref);
+            }
+            rc=IDirectSound8_QueryInterface(secondary,
+                                            &IID_IDirectSoundBuffer8,
+                                            (void **)&buffer8);
+            if (rc==DS_OK && buffer8!=NULL) {
+                ref=IDirectSoundBuffer8_AddRef(buffer8);
+                ok(ref==3,"IDirectSoundBuffer8_AddRef() has %d references, "
+                   "should have 3\n",ref);
+            }
+            ref=IDirectSoundBuffer_AddRef(secondary);
+            ok(ref==4,"IDirectSoundBuffer_AddRef() has %d references, "
+               "should have 4\n",ref);
+        }
+        /* release with buffer */
+        ref=IDirectSound8_Release(dso);
+        ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",
+           ref);
+        if (ref!=0)
+            return DSERR_GENERIC;
+    } else
+        return rc;
+
+    return DS_OK;
+}
+
+static HRESULT test_primary8(LPGUID lpGuid)
+{
+    HRESULT rc;
+    LPDIRECTSOUND8 dso=NULL;
+    LPDIRECTSOUNDBUFFER primary=NULL,second=NULL,third=NULL;
+    LPDIRECTSOUNDBUFFER8 pb8 = NULL;
+    DSBUFFERDESC bufdesc;
+    DSCAPS dscaps;
+    WAVEFORMATEX wfx;
+    int ref;
+
+    /* Create the DirectSound object */
+    rc=pDirectSoundCreate8(lpGuid,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED,
+       "DirectSoundCreate8() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        return rc;
+
+    /* Get the device capabilities */
+    ZeroMemory(&dscaps, sizeof(dscaps));
+    dscaps.dwSize=sizeof(dscaps);
+    rc=IDirectSound8_GetCaps(dso,&dscaps);
+    ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    /* DSOUND: Error: Invalid buffer description pointer */
+    rc=IDirectSound8_CreateSoundBuffer(dso,0,0,NULL);
+    ok(rc==DSERR_INVALIDPARAM,
+       "IDirectSound8_CreateSoundBuffer should have returned "
+       "DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+    /* DSOUND: Error: Invalid buffer description pointer */
+    rc=IDirectSound8_CreateSoundBuffer(dso,0,&primary,NULL);
+    ok(rc==DSERR_INVALIDPARAM && primary==0,
+       "IDirectSound8_CreateSoundBuffer() should have returned "
+       "DSERR_INVALIDPARAM, returned: rc=%08x,dsbo=%p\n",
+       rc,primary);
+
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize = sizeof(DSBUFFERDESC);
+
+    /* DSOUND: Error: Invalid dsound buffer interface pointer */
+    rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,0,NULL);
+    ok(rc==DSERR_INVALIDPARAM && primary==0,
+       "IDirectSound8_CreateSoundBuffer() should have failed: rc=%08x,"
+       "dsbo=%p\n",rc,primary);
+
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+
+    /* DSOUND: Error: Invalid size */
+    /* DSOUND: Error: Invalid buffer description */
+    rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+    ok(rc==DSERR_INVALIDPARAM && primary==0,
+       "IDirectSound8_CreateSoundBuffer() should have failed: rc=%08x,"
+       "primary=%p\n",rc,primary);
+
+    /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
+    rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+    ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    /* Testing the primary buffer */
+    primary=NULL;
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME;
+    bufdesc.lpwfxFormat = &wfx;
+    init_format(&wfx,WAVE_FORMAT_PCM,11025,8,2);
+    rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+    ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_CreateSoundBuffer() should have "
+       "returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+    if (rc==DS_OK && primary!=NULL)
+        IDirectSoundBuffer_Release(primary);
+
+    primary=NULL;
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME;
+    rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+    ok((rc==DS_OK && primary!=NULL) || (rc==DSERR_CONTROLUNAVAIL),
+       "IDirectSound8_CreateSoundBuffer() failed to create a primary buffer: "
+       "%08x\n",rc);
+    if (rc==DSERR_CONTROLUNAVAIL)
+        trace("  No Primary\n");
+    else if (rc==DS_OK && primary!=NULL) {
+        LONG vol;
+
+        /* Try to create a second primary buffer */
+        /* DSOUND: Error: The primary buffer already exists.
+         * Any changes made to the buffer description will be ignored. */
+        rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&second,NULL);
+        ok(rc==DS_OK && second==primary,
+           "IDirectSound8_CreateSoundBuffer() should have returned original "
+           "primary buffer: %08x\n",rc);
+        ref=IDirectSoundBuffer_Release(second);
+        ok(ref==1,"IDirectSoundBuffer_Release() primary has %d references, "
+           "should have 1\n",ref);
+
+        /* Try to duplicate a primary buffer */
+        /* DSOUND: Error: Can't duplicate primary buffers */
+        rc=IDirectSound8_DuplicateSoundBuffer(dso,primary,&third);
+        /* rc=0x88780032 */
+        ok(rc!=DS_OK,"IDirectSound8_DuplicateSoundBuffer() primary buffer "
+           "should have failed %08x\n",rc);
+
+        /* Primary buffers don't have an IDirectSoundBuffer8 */
+        rc = IDirectSoundBuffer_QueryInterface(primary, &IID_IDirectSoundBuffer8, (LPVOID*)&pb8);
+        ok(FAILED(rc), "Primary buffer does have an IDirectSoundBuffer8: %08x\n", rc);
+
+        rc=IDirectSoundBuffer_GetVolume(primary,&vol);
+        ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %08x\n", rc);
+
+        if (winetest_interactive) {
+            trace("Playing a 5 seconds reference tone at the current volume.\n");
+            if (rc==DS_OK)
+                trace("(the current volume is %d according to DirectSound)\n",
+                      vol);
+            trace("All subsequent tones should be identical to this one.\n");
+            trace("Listen for stutter, changes in pitch, volume, etc.\n");
+        }
+        test_buffer8(dso,&primary,1,FALSE,0,FALSE,0,winetest_interactive &&
+                     !(dscaps.dwFlags & DSCAPS_EMULDRIVER),5.0,0,0,0,0);
+
+        ref=IDirectSoundBuffer_Release(primary);
+        ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
+           "should have 0\n",ref);
+    }
+
+    /* Set the CooperativeLevel back to normal */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
+    rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
+    ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc);
+
+EXIT:
+    ref=IDirectSound8_Release(dso);
+    ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref);
+    if (ref!=0)
+        return DSERR_GENERIC;
+
+    return rc;
+}
+
+/*
+ * Test the primary buffer at different formats while keeping the
+ * secondary buffer at a constant format.
+ */
+static HRESULT test_primary_secondary8(LPGUID lpGuid)
+{
+    HRESULT rc;
+    LPDIRECTSOUND8 dso=NULL;
+    LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL;
+    DSBUFFERDESC bufdesc;
+    DSCAPS dscaps;
+    WAVEFORMATEX wfx, wfx2;
+    int ref;
+    unsigned int f;
+
+    /* Create the DirectSound object */
+    rc=pDirectSoundCreate8(lpGuid,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED,
+       "DirectSoundCreate8() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        return rc;
+
+    /* Get the device capabilities */
+    ZeroMemory(&dscaps, sizeof(dscaps));
+    dscaps.dwSize=sizeof(dscaps);
+    rc=IDirectSound8_GetCaps(dso,&dscaps);
+    ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    /* We must call SetCooperativeLevel before creating primary buffer */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
+    rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+    ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
+    rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+    ok(rc==DS_OK && primary!=NULL,
+       "IDirectSound8_CreateSoundBuffer() failed to create a primary buffer "
+       "%08x\n",rc);
+
+    if (rc==DS_OK && primary!=NULL) {
+        for (f=0;f<NB_FORMATS;f++) {
+            /* We must call SetCooperativeLevel to be allowed to call
+             * SetFormat */
+            /* DSOUND: Setting DirectSound cooperative level to
+             * DSSCL_PRIORITY */
+            rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+            ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc);
+            if (rc!=DS_OK)
+                goto EXIT;
+
+            init_format(&wfx,WAVE_FORMAT_PCM,formats[f][0],formats[f][1],
+                        formats[f][2]);
+            wfx2=wfx;
+            rc=IDirectSoundBuffer_SetFormat(primary,&wfx);
+            ok(rc==DS_OK
+               || rc==DSERR_INVALIDPARAM, /* 2003 */
+               "IDirectSoundBuffer_SetFormat(%s) failed: %08x\n",
+               format_string(&wfx), rc);
+
+            /* There is no guarantee that SetFormat will actually change the
+             * format to what we asked for. It depends on what the soundcard
+             * supports. So we must re-query the format.
+             */
+            rc=IDirectSoundBuffer_GetFormat(primary,&wfx,sizeof(wfx),NULL);
+            ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %08x\n", rc);
+            if (rc==DS_OK &&
+                (wfx.wFormatTag!=wfx2.wFormatTag ||
+                 wfx.nSamplesPerSec!=wfx2.nSamplesPerSec ||
+                 wfx.wBitsPerSample!=wfx2.wBitsPerSample ||
+                 wfx.nChannels!=wfx2.nChannels)) {
+                trace("Requested primary format tag=0x%04x %dx%dx%d "
+                      "avg.B/s=%d align=%d\n",
+                      wfx2.wFormatTag,wfx2.nSamplesPerSec,wfx2.wBitsPerSample,
+                      wfx2.nChannels,wfx2.nAvgBytesPerSec,wfx2.nBlockAlign);
+                trace("Got tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n",
+                      wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
+                      wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
+            }
+
+            /* Set the CooperativeLevel back to normal */
+            /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
+            rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
+            ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc);
+
+            init_format(&wfx2,WAVE_FORMAT_PCM,11025,16,2);
+
+            secondary=NULL;
+            ZeroMemory(&bufdesc, sizeof(bufdesc));
+            bufdesc.dwSize=sizeof(bufdesc);
+            bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;
+            bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000,
+                                        wfx.nBlockAlign);
+            bufdesc.lpwfxFormat=&wfx2;
+            if (winetest_interactive) {
+                trace("  Testing a primary buffer at %dx%dx%d with a "
+                      "secondary buffer at %dx%dx%d\n",
+                      wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels,
+                      wfx2.nSamplesPerSec,wfx2.wBitsPerSample,wfx2.nChannels);
+            }
+            rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            ok(rc==DS_OK && secondary!=NULL,
+               "IDirectSound_CreateSoundBuffer() failed to create a secondary "
+               "buffer %08x\n",rc);
+
+            if (rc==DS_OK && secondary!=NULL) {
+                test_buffer8(dso,&secondary,0,FALSE,0,FALSE,0,
+                             winetest_interactive,1.0,0,NULL,0,0);
+
+                ref=IDirectSoundBuffer_Release(secondary);
+                ok(ref==0,"IDirectSoundBuffer_Release() has %d references, "
+                   "should have 0\n",ref);
+            }
+        }
+
+        ref=IDirectSoundBuffer_Release(primary);
+        ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
+           "should have 0\n",ref);
+    }
+
+    /* Set the CooperativeLevel back to normal */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
+    rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
+    ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc);
+
+EXIT:
+    ref=IDirectSound8_Release(dso);
+    ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref);
+    if (ref!=0)
+        return DSERR_GENERIC;
+
+    return rc;
+}
+
+static HRESULT test_secondary8(LPGUID lpGuid)
+{
+    HRESULT rc;
+    LPDIRECTSOUND8 dso=NULL;
+    LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL;
+    DSBUFFERDESC bufdesc;
+    DSCAPS dscaps;
+    WAVEFORMATEX wfx, wfx1;
+    DWORD f;
+    int ref;
+
+    /* Create the DirectSound object */
+    rc=pDirectSoundCreate8(lpGuid,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED,
+       "DirectSoundCreate8() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        return rc;
+
+    /* Get the device capabilities */
+    ZeroMemory(&dscaps, sizeof(dscaps));
+    dscaps.dwSize=sizeof(dscaps);
+    rc=IDirectSound8_GetCaps(dso,&dscaps);
+    ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %08x\n",rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    /* We must call SetCooperativeLevel before creating primary buffer */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
+    rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+    ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
+    rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+    ok(rc==DS_OK && primary!=NULL,
+       "IDirectSound8_CreateSoundBuffer() failed to create a primary buffer "
+       "%08x\n",rc);
+
+    if (rc==DS_OK && primary!=NULL) {
+        rc=IDirectSoundBuffer_GetFormat(primary,&wfx1,sizeof(wfx1),NULL);
+        ok(rc==DS_OK,"IDirectSoundBuffer8_Getformat() failed: %08x\n", rc);
+        if (rc!=DS_OK)
+            goto EXIT1;
+
+        for (f=0;f<NB_FORMATS;f++) {
+            WAVEFORMATEXTENSIBLE wfxe;
+            init_format(&wfx,WAVE_FORMAT_PCM,formats[f][0],formats[f][1],
+                        formats[f][2]);
+            secondary=NULL;
+            ZeroMemory(&bufdesc, sizeof(bufdesc));
+            bufdesc.dwSize=sizeof(bufdesc);
+            bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;
+            bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000,
+                                        wfx.nBlockAlign);
+            rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_CreateSoundBuffer() "
+               "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
+            if (rc==DS_OK && secondary!=NULL)
+                IDirectSoundBuffer_Release(secondary);
+
+            secondary=NULL;
+            ZeroMemory(&bufdesc, sizeof(bufdesc));
+            bufdesc.dwSize=sizeof(bufdesc);
+            bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;
+            bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000,
+                                        wfx.nBlockAlign);
+            bufdesc.lpwfxFormat=&wfx;
+            rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            if (wfx.wBitsPerSample != 8 && wfx.wBitsPerSample != 16)
+                ok(((rc == DSERR_CONTROLUNAVAIL || rc == DSERR_INVALIDCALL || rc == DSERR_INVALIDPARAM /* 2003 */) && !secondary)
+                    || rc == DS_OK, /* driver dependent? */
+                    "IDirectSound_CreateSoundBuffer() "
+                    "should have returned (DSERR_CONTROLUNAVAIL or DSERR_INVALIDCALL) "
+                    "and NULL, returned: %08x %p\n", rc, secondary);
+            else
+                ok(rc==DS_OK && secondary!=NULL,
+                    "IDirectSound_CreateSoundBuffer() failed to create a secondary "
+                    "buffer %08x\n",rc);
+            if (secondary)
+                IDirectSoundBuffer_Release(secondary);
+            secondary = NULL;
+
+            bufdesc.lpwfxFormat=(WAVEFORMATEX*)&wfxe;
+            wfxe.Format = wfx;
+            wfxe.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+            wfxe.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+            wfxe.Format.cbSize = 1;
+            wfxe.Samples.wValidBitsPerSample = wfx.wBitsPerSample;
+            wfxe.dwChannelMask = (wfx.nChannels == 1 ? KSAUDIO_SPEAKER_MONO : KSAUDIO_SPEAKER_STEREO);
+
+            rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            ok(rc==DSERR_INVALIDPARAM && !secondary,
+                "IDirectSound_CreateSoundBuffer() returned: %08x %p\n",
+                rc, secondary);
+            if (secondary)
+            {
+                IDirectSoundBuffer_Release(secondary);
+                secondary=NULL;
+            }
+
+            wfxe.Format.cbSize = sizeof(wfxe) - sizeof(wfx) + 1;
+
+            rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            ok(((rc==DSERR_CONTROLUNAVAIL || rc==DSERR_INVALIDCALL /* 2003 */) && !secondary)
+                || rc==DS_OK /* driver dependent? */,
+                "IDirectSound_CreateSoundBuffer() returned: %08x %p\n",
+                rc, secondary);
+            if (secondary)
+            {
+                IDirectSoundBuffer_Release(secondary);
+                secondary=NULL;
+            }
+
+            wfxe.Format.cbSize = sizeof(wfxe) - sizeof(wfx);
+            wfxe.SubFormat = GUID_NULL;
+            rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            ok((rc==DSERR_INVALIDPARAM || rc==DSERR_INVALIDCALL) && !secondary,
+                "IDirectSound_CreateSoundBuffer() returned: %08x %p\n",
+                rc, secondary);
+            if (secondary)
+            {
+                IDirectSoundBuffer_Release(secondary);
+                secondary=NULL;
+            }
+
+            wfxe.Format.cbSize = sizeof(wfxe);
+            rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            ok((rc==DSERR_CONTROLUNAVAIL || rc==DSERR_INVALIDCALL || rc==E_INVALIDARG) && !secondary,
+                "IDirectSound_CreateSoundBuffer() returned: %08x %p\n",
+                rc, secondary);
+            if (secondary)
+            {
+                IDirectSoundBuffer_Release(secondary);
+                secondary=NULL;
+            }
+
+            wfxe.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+            rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            ok(rc==DS_OK && secondary,
+                "IDirectSound_CreateSoundBuffer() returned: %08x %p\n",
+                rc, secondary);
+            if (secondary)
+            {
+                IDirectSoundBuffer_Release(secondary);
+                secondary=NULL;
+            }
+
+            wfxe.Format.cbSize = sizeof(wfxe) + 1;
+            rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            ok(((rc==DSERR_CONTROLUNAVAIL || rc==DSERR_INVALIDCALL /* 2003 */) && !secondary)
+                || rc==DS_OK /* driver dependent? */,
+                "IDirectSound_CreateSoundBuffer() returned: %08x %p\n",
+                rc, secondary);
+            if (secondary)
+            {
+                IDirectSoundBuffer_Release(secondary);
+                secondary=NULL;
+            }
+
+            wfxe.Format.cbSize = sizeof(wfxe) - sizeof(wfx);
+            ++wfxe.Samples.wValidBitsPerSample;
+            rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            ok(rc==DSERR_INVALIDPARAM && !secondary,
+                "IDirectSound_CreateSoundBuffer() returned: %08x %p\n",
+                rc, secondary);
+            if (secondary)
+            {
+                IDirectSoundBuffer_Release(secondary);
+                secondary=NULL;
+            }
+            --wfxe.Samples.wValidBitsPerSample;
+
+            wfxe.Samples.wValidBitsPerSample = 0;
+            rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            ok(rc==DS_OK && secondary,
+                "IDirectSound_CreateSoundBuffer() returned: %08x %p\n",
+                rc, secondary);
+            if (secondary)
+            {
+                IDirectSoundBuffer_Release(secondary);
+                secondary=NULL;
+            }
+            wfxe.Samples.wValidBitsPerSample = wfxe.Format.wBitsPerSample;
+
+            rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+            ok(rc==DS_OK && secondary!=NULL,
+                "IDirectSound_CreateSoundBuffer() failed to create a secondary "
+                "buffer %08x\n",rc);
+
+            if (rc==DS_OK && secondary!=NULL) {
+                if (winetest_interactive) {
+                    trace("  Testing a secondary buffer at %dx%dx%d "
+                        "with a primary buffer at %dx%dx%d\n",
+                        wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels,
+                        wfx1.nSamplesPerSec,wfx1.wBitsPerSample,wfx1.nChannels);
+                }
+                test_buffer8(dso,&secondary,0,FALSE,0,FALSE,0,
+                             winetest_interactive,1.0,0,NULL,0,0);
+
+                ref=IDirectSoundBuffer_Release(secondary);
+                ok(ref==0,"IDirectSoundBuffer_Release() has %d references, "
+                   "should have 0\n",ref);
+            }
+        }
+EXIT1:
+        ref=IDirectSoundBuffer_Release(primary);
+        ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
+           "should have 0\n",ref);
+    }
+
+    /* Set the CooperativeLevel back to normal */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
+    rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
+    ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc);
+
+EXIT:
+    ref=IDirectSound8_Release(dso);
+    ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref);
+    if (ref!=0)
+        return DSERR_GENERIC;
+
+    return rc;
+}
+
+static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
+                                   LPCSTR lpcstrModule, LPVOID lpContext)
+{
+    HRESULT rc;
+    trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule);
+    rc = test_dsound8(lpGuid);
+    if (rc == DSERR_NODRIVER)
+        trace("  No Driver\n");
+    else if (rc == DSERR_ALLOCATED)
+        trace("  Already In Use\n");
+    else if (rc == E_FAIL)
+        trace("  No Device\n");
+    else {
+        test_primary8(lpGuid);
+        test_primary_secondary8(lpGuid);
+        test_secondary8(lpGuid);
+    }
+
+    return 1;
+}
+
+static void dsound8_tests(void)
+{
+    HRESULT rc;
+    rc=pDirectSoundEnumerateA(&dsenum_callback,NULL);
+    ok(rc==DS_OK,"DirectSoundEnumerateA() failed: %08x\n",rc);
+}
+
+
+START_TEST(dsound8)
+{
+    HMODULE hDsound;
+
+    CoInitialize(NULL);
+
+    hDsound = LoadLibrary("dsound.dll");
+    if (hDsound)
+    {
+
+        pDirectSoundEnumerateA = (void*)GetProcAddress(hDsound,
+            "DirectSoundEnumerateA");
+        pDirectSoundCreate8 = (void*)GetProcAddress(hDsound,
+            "DirectSoundCreate8");
+        if (pDirectSoundCreate8)
+        {
+            IDirectSound8_tests();
+            dsound8_tests();
+        }
+        else
+            skip("dsound8 test skipped\n");
+
+        FreeLibrary(hDsound);
+    }
+    else
+        skip("dsound.dll not found!\n");
+
+    CoUninitialize();
+}
diff --git a/rostests/winetests/dsound/dsound_test.h b/rostests/winetests/dsound/dsound_test.h
new file mode 100644 (file)
index 0000000..b09c98b
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Unit tests for dsound functions
+ *
+ * Copyright (c) 2004 Francois Gouget
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+static const unsigned int formats[][4]={
+    { 8000,  8, 1, 0 },
+    { 8000,  8, 2, 0 },
+    { 8000, 16, 1, 0 },
+    { 8000, 16, 2, 0 },
+    { 8000, 24, 1, 0 },
+    { 8000, 24, 2, 0 },
+    { 8000, 32, 1, 0 },
+    { 8000, 32, 2, 0 },
+    {11025,  8, 1, WAVE_FORMAT_1M08 },
+    {11025,  8, 2, WAVE_FORMAT_1S08 },
+    {11025, 16, 1, WAVE_FORMAT_1M16 },
+    {11025, 16, 2, WAVE_FORMAT_1S16 },
+    {11025, 24, 1, 0 },
+    {11025, 24, 2, 0 },
+    {11025, 32, 1, 0 },
+    {11025, 32, 2, 0 },
+    {22050,  8, 1, WAVE_FORMAT_2M08 },
+    {22050,  8, 2, WAVE_FORMAT_2S08 },
+    {22050, 16, 1, WAVE_FORMAT_2M16 },
+    {22050, 16, 2, WAVE_FORMAT_2S16 },
+    {22050, 24, 1, 0 },
+    {22050, 24, 2, 0 },
+    {22050, 32, 1, 0 },
+    {22050, 32, 2, 0 },
+    {44100,  8, 1, WAVE_FORMAT_4M08 },
+    {44100,  8, 2, WAVE_FORMAT_4S08 },
+    {44100, 16, 1, WAVE_FORMAT_4M16 },
+    {44100, 16, 2, WAVE_FORMAT_4S16 },
+    {44100, 24, 1, 0 },
+    {44100, 24, 2, 0 },
+    {44100, 32, 1, 0 },
+    {44100, 32, 2, 0 },
+    {48000,  8, 1, WAVE_FORMAT_48M08 },
+    {48000,  8, 2, WAVE_FORMAT_48S08 },
+    {48000, 16, 1, WAVE_FORMAT_48M16 },
+    {48000, 16, 2, WAVE_FORMAT_48S16 },
+    {48000, 24, 1, 0 },
+    {48000, 24, 2, 0 },
+    {48000, 32, 1, 0 },
+    {48000, 32, 2, 0 },
+    {96000,  8, 1, WAVE_FORMAT_96M08 },
+    {96000,  8, 2, WAVE_FORMAT_96S08 },
+    {96000, 16, 1, WAVE_FORMAT_96M16 },
+    {96000, 16, 2, WAVE_FORMAT_96S16 },
+    {96000, 24, 1, 0 },
+    {96000, 24, 2, 0 },
+    {96000, 32, 1, 0 },
+    {96000, 32, 2, 0 }
+};
+#define NB_FORMATS (sizeof(formats)/sizeof(*formats))
+
+/* The time slice determines how often we will service the buffer */
+#define TIME_SLICE     31
+#define BUFFER_LEN    400
+
+extern char* wave_generate_la(WAVEFORMATEX*,double,DWORD*);
+extern HWND get_hwnd(void);
+extern void init_format(WAVEFORMATEX*,int,int,int,int);
+extern void test_buffer(LPDIRECTSOUND,LPDIRECTSOUNDBUFFER*,
+                        BOOL,BOOL,LONG,BOOL,LONG,BOOL,double,BOOL,
+                        LPDIRECTSOUND3DLISTENER,BOOL,BOOL,BOOL,DWORD);
+extern void test_buffer8(LPDIRECTSOUND8,LPDIRECTSOUNDBUFFER*,
+                         BOOL,BOOL,LONG,BOOL,LONG,BOOL,double,BOOL,
+                         LPDIRECTSOUND3DLISTENER,BOOL,BOOL);
+extern const char * getDSBCAPS(DWORD xmask);
+extern int align(int length, int align);
+extern const char * format_string(const WAVEFORMATEX* wfx);
diff --git a/rostests/winetests/dsound/duplex.c b/rostests/winetests/dsound/duplex.c
new file mode 100644 (file)
index 0000000..11fb2a7
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * Unit tests for duplex functions
+ *
+ * Copyright (c) 2006 Robert Reif
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <windows.h>
+
+#include <stdio.h>
+
+#include "wine/test.h"
+#include "dsound.h"
+#include "mmreg.h"
+#include "dsconf.h"
+
+#include "dsound_test.h"
+
+static HRESULT (WINAPI *pDirectSoundFullDuplexCreate)(LPCGUID, LPCGUID,
+    LPCDSCBUFFERDESC, LPCDSBUFFERDESC, HWND, DWORD, LPDIRECTSOUNDFULLDUPLEX *,
+    LPDIRECTSOUNDCAPTUREBUFFER8*, LPDIRECTSOUNDBUFFER8*, LPUNKNOWN)=NULL;
+
+static void IDirectSoundFullDuplex_test(LPDIRECTSOUNDFULLDUPLEX dsfdo,
+                                        BOOL initialized, LPCGUID lpGuidCapture,
+                                        LPCGUID lpGuidRender)
+{
+    HRESULT rc;
+    int ref;
+    IUnknown * unknown;
+    IDirectSound * ds;
+    IDirectSound8 * ds8;
+    IDirectSoundCapture * dsc;
+    IDirectSoundFullDuplex * dsfd;
+
+    /* Try to Query for objects */
+    rc=IDirectSoundFullDuplex_QueryInterface(dsfdo,&IID_IUnknown,(LPVOID*)&unknown);
+    ok(rc==DS_OK,"IDirectSoundFullDuplex_QueryInterface(IID_IUnknown) failed: %08x\n", rc);
+    if (rc==DS_OK) {
+        ref=IDirectSoundFullDuplex_Release(unknown);
+        ok(ref==0, "IDirectSoundFullDuplex_Release() has %d references, "
+           "should have 0\n", ref);
+    }
+
+    rc=IDirectSoundFullDuplex_QueryInterface(dsfdo,&IID_IDirectSound,(LPVOID*)&ds);
+    ok(rc==(initialized?DS_OK:E_NOINTERFACE),"IDirectSoundFullDuplex_QueryInterface(IID_IDirectSound) failed: %08x\n", rc);
+    if (rc==DS_OK) {
+        ref=IDirectSound_Release(ds);
+        ok(ref==0, "IDirectSound_Release() has %d references, "
+           "should have 0\n", ref);
+    }
+
+    rc=IDirectSoundFullDuplex_QueryInterface(dsfdo,&IID_IDirectSound8,(LPVOID*)&ds8);
+    ok(rc==(initialized?DS_OK:E_NOINTERFACE),"IDirectSoundFullDuplex_QueryInterface(IID_IDirectSound8) "
+       "failed: %08x\n",rc);
+    if (rc==DS_OK) {
+        IDirectSoundFullDuplex * dsfd1;
+        rc=IDirectSound8_QueryInterface(ds8,&IID_IDirectSoundFullDuplex,(LPVOID*)&dsfd1);
+        ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IDirectSoundFullDuplex) "
+           "failed: %08x\n",rc);
+        if (rc==DS_OK) {
+            ref=IDirectSoundFullDuplex_Release(dsfd1);
+            ok(ref==1, "IDirectSoundFullDuplex_Release() has %d references, "
+               "should have 1\n", ref);
+        }
+        ref=IDirectSound8_Release(ds8);
+        ok(ref==0, "IDirectSound8_Release() has %d references, "
+           "should have 0\n", ref);
+    }
+
+    rc=IDirectSoundFullDuplex_QueryInterface(dsfdo,&IID_IDirectSoundCapture,(LPVOID*)&dsc);
+    ok(rc==(initialized?DS_OK:E_NOINTERFACE),"IDirectSoundFullDuplex_QueryInterface(IID_IDirectSoundCapture) "
+       "failed: %08x\n",rc);
+    if (rc==DS_OK) {
+        ref=IDirectSoundCapture_Release(dsc);
+        ok(ref==0, "IDirectSoundCapture_Release() has %d references, "
+           "should have 0\n", ref);
+    }
+
+    rc=IDirectSoundFullDuplex_QueryInterface(dsfdo,&IID_IDirectSoundFullDuplex,(LPVOID*)&dsfd);
+    ok(rc==DS_OK,"IDirectSoundFullDuplex_QueryInterface(IID_IDirectSoundFullDuplex) "
+       "failed: %08x\n",rc);
+    if (rc==DS_OK) {
+        ok (dsfdo==dsfd, "different interfaces\n");
+        ref=IDirectSound8_Release(dsfd);
+    }
+
+    ref=IDirectSoundFullDuplex_Release(dsfdo);
+    ok(ref==0, "IDirectSoundFullDuplex_Release() has %d references, "
+       "should have 0\n", ref);
+}
+
+static void IDirectSoundFullDuplex_tests(void)
+{
+    HRESULT rc;
+    LPDIRECTSOUNDFULLDUPLEX dsfdo = NULL;
+    DSCBUFFERDESC DSCBufferDesc;
+    DSBUFFERDESC DSBufferDesc;
+    LPDIRECTSOUNDCAPTUREBUFFER8 pDSCBuffer8;
+    LPDIRECTSOUNDBUFFER8 pDSBuffer8;
+    WAVEFORMATEX wfex;
+
+    trace("Testing IDirectSoundFullDuplex\n");
+
+    /* try the COM class factory method of creation with no devices specified */
+    rc=CoCreateInstance(&CLSID_DirectSoundFullDuplex, NULL,
+                        CLSCTX_INPROC_SERVER, &IID_IDirectSoundFullDuplex,
+                        (void**)&dsfdo);
+    ok(rc==S_OK||rc==REGDB_E_CLASSNOTREG||rc==CLASS_E_CLASSNOTAVAILABLE,
+       "CoCreateInstance(CLSID_DirectSoundFullDuplex) failed: 0x%08x\n", rc);
+    if (rc==REGDB_E_CLASSNOTREG) {
+        trace("  Class Not Registered\n");
+        return;
+    } else if (rc==CLASS_E_CLASSNOTAVAILABLE) {
+        trace("  Class Not Available\n");
+        return;
+    }
+    if (dsfdo)
+        IDirectSoundFullDuplex_test(dsfdo, FALSE, NULL, NULL);
+
+    /* try the COM class factory method of creation with default devices
+     * specified */
+    rc=CoCreateInstance(&CLSID_DirectSoundFullDuplex, NULL,
+                        CLSCTX_INPROC_SERVER, &IID_IDirectSoundFullDuplex,
+                        (void**)&dsfdo);
+    ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSoundFullDuplex) failed: 0x%08x\n", rc);
+    if (dsfdo)
+        IDirectSoundFullDuplex_test(dsfdo, FALSE, &DSDEVID_DefaultCapture,
+                                    &DSDEVID_DefaultPlayback);
+
+    /* try the COM class factory method of creation with default voice
+     * devices specified */
+    rc=CoCreateInstance(&CLSID_DirectSoundFullDuplex, NULL,
+                        CLSCTX_INPROC_SERVER, &IID_IDirectSoundFullDuplex,
+                        (void**)&dsfdo);
+    ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSoundFullDuplex) failed: 0x%08x\n", rc);
+    if (dsfdo)
+        IDirectSoundFullDuplex_test(dsfdo, FALSE, &DSDEVID_DefaultVoiceCapture,
+                                    &DSDEVID_DefaultVoicePlayback);
+
+    /* try the COM class factory method of creation with a bad
+     * IID specified */
+    rc=CoCreateInstance(&CLSID_DirectSoundFullDuplex, NULL,
+                        CLSCTX_INPROC_SERVER, &CLSID_DirectSoundPrivate,
+                        (void**)&dsfdo);
+    ok(rc==E_NOINTERFACE,
+       "CoCreateInstance(CLSID_DirectSoundFullDuplex,CLSID_DirectSoundPrivate) "
+       "should have failed: 0x%08x\n", rc);
+
+    ZeroMemory(&wfex, sizeof(wfex));
+    wfex.wFormatTag = WAVE_FORMAT_PCM;
+    wfex.nChannels = 1;
+    wfex.nSamplesPerSec = 8000;
+    wfex.wBitsPerSample = 16;
+    wfex.nBlockAlign = (wfex.wBitsPerSample * wfex.nChannels) / 8;
+    wfex.nAvgBytesPerSec = wfex.nSamplesPerSec * wfex.nBlockAlign;
+
+    ZeroMemory(&DSCBufferDesc, sizeof(DSCBufferDesc));
+    DSCBufferDesc.dwSize = sizeof(DSCBufferDesc);
+    DSCBufferDesc.dwFlags = DSCBCAPS_WAVEMAPPED;
+    DSCBufferDesc.dwBufferBytes = 8192;
+    DSCBufferDesc.lpwfxFormat = &wfex;
+
+    ZeroMemory(&DSBufferDesc, sizeof(DSBufferDesc));
+    DSBufferDesc.dwSize = sizeof(DSBufferDesc);
+    DSBufferDesc.dwFlags = DSBCAPS_GLOBALFOCUS;
+    DSBufferDesc.dwBufferBytes = 8192;
+    DSBufferDesc.lpwfxFormat = &wfex;
+
+    /* try with no device specified */
+    rc=pDirectSoundFullDuplexCreate(NULL,NULL,&DSCBufferDesc,&DSBufferDesc,
+                                    get_hwnd(),DSSCL_EXCLUSIVE ,&dsfdo,&pDSCBuffer8,
+                                    &pDSBuffer8,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL||rc==DSERR_INVALIDCALL,
+       "DirectSoundFullDuplexCreate(NULL,NULL) failed: %08x\n",rc);
+    if (rc==S_OK && dsfdo)
+        IDirectSoundFullDuplex_test(dsfdo, TRUE, NULL, NULL);
+
+    /* try with default devices specified */
+    rc=pDirectSoundFullDuplexCreate(&DSDEVID_DefaultCapture,
+                                    &DSDEVID_DefaultPlayback,&DSCBufferDesc,
+                                    &DSBufferDesc,get_hwnd(),DSSCL_EXCLUSIVE,&dsfdo,
+                                    &pDSCBuffer8,&pDSBuffer8,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL||rc==DSERR_INVALIDCALL,
+       "DirectSoundFullDuplexCreate(DSDEVID_DefaultCapture,"
+       "DSDEVID_DefaultPlayback) failed: %08x\n", rc);
+    if (rc==DS_OK && dsfdo)
+        IDirectSoundFullDuplex_test(dsfdo, TRUE, NULL, NULL);
+
+    /* try with default voice devices specified */
+    rc=pDirectSoundFullDuplexCreate(&DSDEVID_DefaultVoiceCapture,
+                                    &DSDEVID_DefaultVoicePlayback,
+                                    &DSCBufferDesc,&DSBufferDesc,get_hwnd(),DSSCL_EXCLUSIVE,
+                                    &dsfdo,&pDSCBuffer8,&pDSBuffer8,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL||rc==DSERR_INVALIDCALL,
+       "DirectSoundFullDuplexCreate(DSDEVID_DefaultVoiceCapture,"
+       "DSDEVID_DefaultVoicePlayback) failed: %08x\n", rc);
+    if (rc==DS_OK && dsfdo)
+        IDirectSoundFullDuplex_test(dsfdo, TRUE, NULL, NULL);
+
+    /* try with bad devices specified */
+    rc=pDirectSoundFullDuplexCreate(&DSDEVID_DefaultVoicePlayback,
+                                    &DSDEVID_DefaultVoiceCapture,
+                                    &DSCBufferDesc,&DSBufferDesc,get_hwnd(),DSSCL_EXCLUSIVE,
+                                    &dsfdo,&pDSCBuffer8,&pDSBuffer8,NULL);
+    ok(rc==DSERR_NODRIVER||rc==DSERR_INVALIDCALL,
+       "DirectSoundFullDuplexCreate(DSDEVID_DefaultVoicePlayback,"
+       "DSDEVID_DefaultVoiceCapture) should have failed: %08x\n", rc);
+    if (rc==DS_OK && dsfdo)
+        IDirectSoundFullDuplex_Release(dsfdo);
+}
+
+START_TEST(duplex)
+{
+    HMODULE hDsound;
+
+    CoInitialize(NULL);
+
+    hDsound = LoadLibrary("dsound.dll");
+    if (hDsound)
+    {
+
+        pDirectSoundFullDuplexCreate=(void*)GetProcAddress(hDsound,
+            "DirectSoundFullDuplexCreate");
+        if (pDirectSoundFullDuplexCreate)
+            IDirectSoundFullDuplex_tests();
+        else
+            skip("duplex test skipped\n");
+
+        FreeLibrary(hDsound);
+    }
+    else
+        skip("dsound.dll not found!\n");
+
+    CoUninitialize();
+}
diff --git a/rostests/winetests/dsound/propset.c b/rostests/winetests/dsound/propset.c
new file mode 100644 (file)
index 0000000..70a8e0d
--- /dev/null
@@ -0,0 +1,748 @@
+/*
+ * Unit tests for CLSID_DirectSoundPrivate property set functions
+ * (used by dxdiag)
+ *
+ * Copyright (c) 2003 Robert Reif
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+#include <windows.h>
+
+#include "wine/test.h"
+#include "dsound.h"
+#include "dsconf.h"
+
+#include "dsound_test.h"
+
+#ifndef DSBCAPS_CTRLDEFAULT
+#define DSBCAPS_CTRLDEFAULT \
+        DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLPAN|DSBCAPS_CTRLVOLUME
+#endif
+
+#include "initguid.h"
+
+DEFINE_GUID(DSPROPSETID_VoiceManager,
+            0x62A69BAE,0xDF9D,0x11D1,0x99,0xA6,0x00,0xC0,0x4F,0xC9,0x9D,0x46);
+DEFINE_GUID(DSPROPSETID_EAX20_ListenerProperties,
+            0x306a6a8,0xb224,0x11d2,0x99,0xe5,0x0,0x0,0xe8,0xd8,0xc7,0x22);
+DEFINE_GUID(DSPROPSETID_EAX20_BufferProperties,
+            0x306a6a7,0xb224,0x11d2,0x99,0xe5,0x0,0x0,0xe8,0xd8,0xc7,0x22);
+DEFINE_GUID(DSPROPSETID_I3DL2_ListenerProperties,
+            0xDA0F0520,0x300A,0x11D3,0x8A,0x2B,0x00,0x60,0x97,0x0D,0xB0,0x11);
+DEFINE_GUID(DSPROPSETID_I3DL2_BufferProperties,
+            0xDA0F0521,0x300A,0x11D3,0x8A,0x2B,0x00,0x60,0x97,0x0D,0xB0,0x11);
+DEFINE_GUID(DSPROPSETID_ZOOMFX_BufferProperties,
+            0xCD5368E0,0x3450,0x11D3,0x8B,0x6E,0x00,0x10,0x5A,0x9B,0x7B,0xBC);
+
+static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL;
+static HRESULT (WINAPI *pDllGetClassObject)(REFCLSID,REFIID,LPVOID*)=NULL;
+static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID,LPDIRECTSOUND*,
+    LPUNKNOWN)=NULL;
+static HRESULT (WINAPI *pDirectSoundCreate8)(LPCGUID,LPDIRECTSOUND8*,
+    LPUNKNOWN)=NULL;
+static HRESULT (WINAPI *pDirectSoundCaptureCreate)(LPCGUID,
+    LPDIRECTSOUNDCAPTURE*,LPUNKNOWN)=NULL;
+static HRESULT (WINAPI *pDirectSoundCaptureCreate8)(LPCGUID,
+    LPDIRECTSOUNDCAPTURE8*,LPUNKNOWN)=NULL;
+static HRESULT (WINAPI *pDirectSoundFullDuplexCreate)(LPCGUID,LPCGUID,
+    LPCDSCBUFFERDESC,LPCDSBUFFERDESC,HWND,DWORD,LPDIRECTSOUNDFULLDUPLEX*,
+    LPDIRECTSOUNDCAPTUREBUFFER8*,LPDIRECTSOUNDBUFFER8*,LPUNKNOWN)=NULL;
+
+static BOOL CALLBACK callback(PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA data,
+                       LPVOID context)
+{
+    trace("  found device:\n");
+    trace("    Type: %s\n",
+          data->Type == DIRECTSOUNDDEVICE_TYPE_EMULATED ? "Emulated" :
+          data->Type == DIRECTSOUNDDEVICE_TYPE_VXD ? "VxD" :
+          data->Type == DIRECTSOUNDDEVICE_TYPE_WDM ? "WDM" : "Unknown");
+    trace("    DataFlow: %s\n",
+          data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ? "Render" :
+          data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ?
+          "Capture" : "Unknown");
+    trace("    DeviceId: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
+          data->DeviceId.Data1,data->DeviceId.Data2,data->DeviceId.Data3,
+          data->DeviceId.Data4[0],data->DeviceId.Data4[1],
+          data->DeviceId.Data4[2],data->DeviceId.Data4[3],
+          data->DeviceId.Data4[4],data->DeviceId.Data4[5],
+          data->DeviceId.Data4[6],data->DeviceId.Data4[7]);
+    trace("    Description: %s\n", data->Description);
+    trace("    Module: %s\n", data->Module);
+    trace("    Interface: %s\n", data->Interface);
+    trace("    WaveDeviceId: %d\n", data->WaveDeviceId);
+
+    return TRUE;
+}
+
+static BOOL CALLBACK callback1(PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1_DATA data,
+                        LPVOID context)
+{
+    char descriptionA[0x100];
+    char moduleA[MAX_PATH];
+
+    trace("  found device:\n");
+    trace("    Type: %s\n",
+          data->Type == DIRECTSOUNDDEVICE_TYPE_EMULATED ? "Emulated" :
+          data->Type == DIRECTSOUNDDEVICE_TYPE_VXD ? "VxD" :
+          data->Type == DIRECTSOUNDDEVICE_TYPE_WDM ? "WDM" : "Unknown");
+    trace("    DataFlow: %s\n",
+          data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ? "Render" :
+          data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ?
+          "Capture" : "Unknown");
+    trace("    DeviceId: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
+          data->DeviceId.Data1,data->DeviceId.Data2,data->DeviceId.Data3,
+          data->DeviceId.Data4[0],data->DeviceId.Data4[1],
+          data->DeviceId.Data4[2],data->DeviceId.Data4[3],
+          data->DeviceId.Data4[4],data->DeviceId.Data4[5],
+          data->DeviceId.Data4[6],data->DeviceId.Data4[7]);
+    trace("    DescriptionA: %s\n", data->DescriptionA);
+    WideCharToMultiByte(CP_ACP, 0, data->DescriptionW, -1, descriptionA, sizeof(descriptionA), NULL, NULL);
+    trace("    DescriptionW: %s\n", descriptionA);
+    trace("    ModuleA: %s\n", data->ModuleA);
+    WideCharToMultiByte(CP_ACP, 0, data->ModuleW, -1, moduleA, sizeof(moduleA), NULL, NULL);
+    trace("    ModuleW: %s\n", moduleA);
+    trace("    WaveDeviceId: %d\n", data->WaveDeviceId);
+
+    return TRUE;
+}
+
+static BOOL CALLBACK callbackA(PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A_DATA data,
+                        LPVOID context)
+{
+    trace("  found device:\n");
+    trace("    Type: %s\n",
+          data->Type == DIRECTSOUNDDEVICE_TYPE_EMULATED ? "Emulated" :
+          data->Type == DIRECTSOUNDDEVICE_TYPE_VXD ? "VxD" :
+          data->Type == DIRECTSOUNDDEVICE_TYPE_WDM ? "WDM" : "Unknown");
+    trace("    DataFlow: %s\n",
+          data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ? "Render" :
+          data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ?
+          "Capture" : "Unknown");
+    trace("    DeviceId: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
+          data->DeviceId.Data1,data->DeviceId.Data2,data->DeviceId.Data3,
+          data->DeviceId.Data4[0],data->DeviceId.Data4[1],
+          data->DeviceId.Data4[2],data->DeviceId.Data4[3],
+          data->DeviceId.Data4[4],data->DeviceId.Data4[5],
+          data->DeviceId.Data4[6],data->DeviceId.Data4[7]);
+    trace("    Description: %s\n", data->Description);
+    trace("    Module: %s\n", data->Module);
+    trace("    Interface: %s\n", data->Interface);
+    trace("    WaveDeviceId: %d\n", data->WaveDeviceId);
+
+    return TRUE;
+}
+
+static BOOL CALLBACK callbackW(PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W_DATA data,
+                        LPVOID context)
+{
+    char descriptionA[0x100];
+    char moduleA[MAX_PATH];
+    char interfaceA[MAX_PATH];
+
+    trace("found device:\n");
+    trace("\tType: %s\n",
+          data->Type == DIRECTSOUNDDEVICE_TYPE_EMULATED ? "Emulated" :
+          data->Type == DIRECTSOUNDDEVICE_TYPE_VXD ? "VxD" :
+          data->Type == DIRECTSOUNDDEVICE_TYPE_WDM ? "WDM" : "Unknown");
+    trace("\tDataFlow: %s\n",
+          data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ? "Render" :
+          data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ?
+          "Capture" : "Unknown");
+    trace("\tDeviceId: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
+          data->DeviceId.Data1,data->DeviceId.Data2,data->DeviceId.Data3,
+          data->DeviceId.Data4[0],data->DeviceId.Data4[1],
+          data->DeviceId.Data4[2],data->DeviceId.Data4[3],
+          data->DeviceId.Data4[4],data->DeviceId.Data4[5],
+          data->DeviceId.Data4[6],data->DeviceId.Data4[7]);
+    WideCharToMultiByte(CP_ACP, 0, data->Description, -1, descriptionA, sizeof(descriptionA), NULL, NULL);
+    WideCharToMultiByte(CP_ACP, 0, data->Module, -1, moduleA, sizeof(moduleA), NULL, NULL);
+    WideCharToMultiByte(CP_ACP, 0, data->Interface, -1, interfaceA, sizeof(interfaceA), NULL, NULL);
+    trace("\tDescription: %s\n", descriptionA);
+    trace("\tModule: %s\n", moduleA);
+    trace("\tInterface: %s\n", interfaceA);
+    trace("\tWaveDeviceId: %d\n", data->WaveDeviceId);
+
+    return TRUE;
+}
+
+static void propset_private_tests(void)
+{
+    HRESULT rc;
+    IClassFactory * pcf;
+    IKsPropertySet * pps;
+    ULONG support;
+
+    /* try direct sound first */
+    /* DSOUND: Error: Invalid interface buffer */
+    rc = (pDllGetClassObject)(&CLSID_DirectSound, &IID_IClassFactory, NULL);
+    ok(rc==DSERR_INVALIDPARAM,"DllGetClassObject(CLSID_DirectSound, "
+       "IID_IClassFactory) should have returned DSERR_INVALIDPARAM, "
+       "returned: %08x\n",rc);
+
+    rc = (pDllGetClassObject)(&CLSID_DirectSound, &IID_IDirectSound, (void **)(&pcf));
+    ok(rc==E_NOINTERFACE,"DllGetClassObject(CLSID_DirectSound, "
+       "IID_IDirectSound) should have returned E_NOINTERFACE, "
+       "returned: %08x\n",rc);
+
+    rc = (pDllGetClassObject)(&CLSID_DirectSound, &IID_IUnknown, (void **)(&pcf));
+    ok(rc==DS_OK,"DllGetClassObject(CLSID_DirectSound, "
+       "IID_IUnknown) failed: %08x\n",rc);
+
+    rc = (pDllGetClassObject)(&CLSID_DirectSound, &IID_IClassFactory, (void **)(&pcf));
+    ok(pcf!=0, "DllGetClassObject(CLSID_DirectSound, IID_IClassFactory) "
+       "failed: %08x\n",rc);
+    if (pcf==0)
+        return;
+
+    /* direct sound doesn't have an IKsPropertySet */
+    /* DSOUND: Error: Invalid interface buffer */
+    rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet,
+                                     NULL);
+    ok(rc==DSERR_INVALIDPARAM, "CreateInstance(IID_IKsPropertySet) should have "
+       "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
+
+    rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet,
+                                     (void **)(&pps));
+    ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have "
+       "returned E_NOINTERFACE, returned: %08x\n",rc);
+
+    /* and the direct sound 8 version */
+    if (pDirectSoundCreate8) {
+        rc = (pDllGetClassObject)(&CLSID_DirectSound8, &IID_IClassFactory, (void **)(&pcf));
+        ok(pcf!=0, "DllGetClassObject(CLSID_DirectSound8, IID_IClassFactory) "
+           "failed: %08x\n",rc);
+        if (pcf==0)
+            return;
+
+        /* direct sound 8 doesn't have an IKsPropertySet */
+        rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet,
+                                         (void **)(&pps));
+        ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have "
+           "returned E_NOINTERFACE, returned: %08x\n",rc);
+    }
+
+    /* try direct sound capture next */
+    if (pDirectSoundCaptureCreate) {
+        rc = (pDllGetClassObject)(&CLSID_DirectSoundCapture, &IID_IClassFactory,
+                     (void **)(&pcf));
+        ok(pcf!=0, "DllGetClassObject(CLSID_DirectSoundCapture, IID_IClassFactory) "
+           "failed: %08x\n",rc);
+        if (pcf==0)
+            return;
+
+        /* direct sound capture doesn't have an IKsPropertySet */
+        rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet,
+                                         (void **)(&pps));
+        ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have "
+           "returned E_NOINTERFACE,returned: %08x\n",rc);
+    }
+
+    /* and the direct sound capture 8 version */
+    if (pDirectSoundCaptureCreate8) {
+        rc = (pDllGetClassObject)(&CLSID_DirectSoundCapture8, &IID_IClassFactory,
+                     (void **)(&pcf));
+        ok(pcf!=0, "DllGetClassObject(CLSID_DirectSoundCapture8, "
+           "IID_IClassFactory) failed: %08x\n",rc);
+        if (pcf==0)
+            return;
+
+        /* direct sound capture 8 doesn't have an IKsPropertySet */
+        rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet,
+                                         (void **)(&pps));
+        ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have "
+           "returned E_NOINTERFACE, returned: %08x\n",rc);
+    }
+
+    /* try direct sound full duplex next */
+    if (pDirectSoundFullDuplexCreate) {
+        rc = (pDllGetClassObject)(&CLSID_DirectSoundFullDuplex, &IID_IClassFactory,
+                     (void **)(&pcf));
+        ok(pcf!=0, "DllGetClassObject(CLSID_DirectSoundFullDuplex, "
+           "IID_IClassFactory) failed: %08x\n",rc);
+        if (pcf==0)
+            return;
+
+        /* direct sound full duplex doesn't have an IKsPropertySet */
+        rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet,
+                                         (void **)(&pps));
+        ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have "
+           "returned NOINTERFACE, returned: %08x\n",rc);
+    }
+
+    /* try direct sound private last */
+    rc = (pDllGetClassObject)(&CLSID_DirectSoundPrivate, &IID_IClassFactory,
+                 (void **)(&pcf));
+
+    /* some early versions of Direct Sound do not have this */
+    if (rc==CLASS_E_CLASSNOTAVAILABLE)
+        return;
+
+    /* direct sound private does have an IKsPropertySet */
+    rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet,
+                                     (void **)(&pps));
+    ok(rc==DS_OK, "CreateInstance(IID_IKsPropertySet) failed: %08x\n",
+       rc);
+    if (rc!=DS_OK)
+        return;
+
+    /* test generic DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION */
+    rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice,
+                                   DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION,
+                                   &support);
+    ok(rc==DS_OK||rc==E_INVALIDARG,
+       "QuerySupport(DSPROPSETID_DirectSoundDevice, "
+       "DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION) failed: %08x\n",
+       rc);
+    if (rc!=DS_OK) {
+        if (rc==E_INVALIDARG)
+            trace("  Not Supported\n");
+        return;
+    }
+
+    ok(support & KSPROPERTY_SUPPORT_GET,
+       "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION: "
+       "support = 0x%x\n",support);
+    ok(!(support & KSPROPERTY_SUPPORT_SET),
+       "Shouldn't be able to set DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION: "
+       "support = 0x%x\n",support);
+
+    /* test DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1 */
+    rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice,
+                                   DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1,
+                                   &support);
+    ok(rc==DS_OK||rc==E_INVALIDARG,
+       "QuerySupport(DSPROPSETID_DirectSoundDevice, "
+       "DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1) failed: %08x\n",
+       rc);
+    if (rc!=DS_OK) {
+        if (rc==E_INVALIDARG)
+            trace("  Not Supported\n");
+        return;
+    }
+
+    ok(support & KSPROPERTY_SUPPORT_GET,
+       "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1: "
+       "support = 0x%x\n",support);
+    ok(!(support & KSPROPERTY_SUPPORT_SET),
+       "Shouldn't be able to set DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1: "
+       "support = 0x%x\n",support);
+
+    /* test DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A */
+    rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice,
+                                   DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A,
+                                   &support);
+    ok(rc==DS_OK||rc==E_INVALIDARG,
+       "QuerySupport(DSPROPSETID_DirectSoundDevice, "
+       "DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A) failed: %08x\n",
+       rc);
+    if (rc!=DS_OK) {
+        if (rc==E_INVALIDARG)
+            trace("  Not Supported\n");
+        return;
+    }
+
+    ok(support & KSPROPERTY_SUPPORT_GET,
+       "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A: "
+       "support = 0x%x\n",support);
+    ok(!(support & KSPROPERTY_SUPPORT_SET),
+       "Shouldn't be able to set DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A: "
+       "support = 0x%x\n",support);
+
+    /* test DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W */
+    rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice,
+                                   DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W,
+                                   &support);
+    ok(rc==DS_OK||rc==E_INVALIDARG,
+       "QuerySupport(DSPROPSETID_DirectSoundDevice, "
+       "DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W) failed: %08x\n",
+       rc);
+    if (rc!=DS_OK) {
+        if (rc==E_INVALIDARG)
+            trace("  Not Supported\n");
+        return;
+    }
+
+    ok(support & KSPROPERTY_SUPPORT_GET,
+       "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W: "
+       "support = 0x%x\n",support);
+    ok(!(support & KSPROPERTY_SUPPORT_SET),
+       "Shouldn't be able to set DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W: "
+       "support = 0x%x\n",support);
+
+    /* test generic DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING */
+    rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice,
+        DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING, &support);
+    ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, "
+       "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING) failed: %08x\n",
+       rc);
+    if (rc!=DS_OK)
+        return;
+
+    ok(support & KSPROPERTY_SUPPORT_GET,
+       "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING: "
+       "support = 0x%x\n",support);
+    ok(!(support & KSPROPERTY_SUPPORT_SET), "Shouldn't be able to set "
+       "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING: support = "
+       "0x%x\n",support);
+
+    /* test DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A */
+    rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice,
+        DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A, &support);
+    ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, "
+       "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A) failed: %08x\n",
+       rc);
+    if (rc!=DS_OK)
+        return;
+
+    ok(support & KSPROPERTY_SUPPORT_GET,
+       "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A: "
+       "support = 0x%x\n",support);
+    ok(!(support & KSPROPERTY_SUPPORT_SET), "Shouldn't be able to set "
+       "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A: support = "
+       "0x%x\n",support);
+
+    /* test DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W */
+    rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice,
+        DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W, &support);
+    ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, "
+       "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W) failed: %08x\n",
+       rc);
+    if (rc!=DS_OK)
+        return;
+
+    ok(support & KSPROPERTY_SUPPORT_GET,
+       "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W: "
+       "support = 0x%x\n",support);
+    ok(!(support & KSPROPERTY_SUPPORT_SET), "Shouldn't be able to set "
+       "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W: support = "
+       "0x%x\n",support);
+
+    /* test generic DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE */
+    trace("*** Testing DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE ***\n");
+    rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice,
+                                   DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE,
+                                   &support);
+    ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, "
+       "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE) failed: %08x\n",
+       rc);
+    if (rc!=DS_OK)
+        return;
+
+    ok(support & KSPROPERTY_SUPPORT_GET,
+       "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE: "
+       "support = 0x%x\n",support);
+    ok(!(support & KSPROPERTY_SUPPORT_SET),"Shouldn't be able to set "
+       "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE: support = 0x%x\n",support);
+
+    if (support & KSPROPERTY_SUPPORT_GET) {
+        DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_DATA data;
+        ULONG bytes;
+
+        data.Callback = callback;
+        data.Context = 0;
+
+        rc = IKsPropertySet_Get(pps, &DSPROPSETID_DirectSoundDevice,
+                              DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE,
+                              NULL, 0, &data, sizeof(data), &bytes);
+        ok(rc==DS_OK, "Couldn't enumerate: 0x%x\n",rc);
+    }
+
+    /* test DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1 */
+    trace("*** Testing DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1 ***\n");
+    rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice,
+                                   DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1,
+                                   &support);
+    ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, "
+       "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1) failed: %08x\n",
+       rc);
+    if (rc!=DS_OK)
+        return;
+
+    ok(support & KSPROPERTY_SUPPORT_GET,
+       "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1: "
+       "support = 0x%x\n",support);
+    ok(!(support & KSPROPERTY_SUPPORT_SET),"Shouldn't be able to set "
+       "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1: support = 0x%x\n",support);
+
+    if (support & KSPROPERTY_SUPPORT_GET) {
+        DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1_DATA data;
+        ULONG bytes;
+
+        data.Callback = callback1;
+        data.Context = 0;
+
+        rc = IKsPropertySet_Get(pps, &DSPROPSETID_DirectSoundDevice,
+                              DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1,
+                              NULL, 0, &data, sizeof(data), &bytes);
+        ok(rc==DS_OK, "Couldn't enumerate: 0x%x\n",rc);
+    }
+
+    /* test DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A */
+    trace("*** Testing DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A ***\n");
+    rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice,
+                                   DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A,
+                                   &support);
+    ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, "
+       "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A) failed: %08x\n",
+       rc);
+    if (rc!=DS_OK)
+        return;
+
+    ok(support & KSPROPERTY_SUPPORT_GET,
+       "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A: "
+       "support = 0x%x\n",support);
+    ok(!(support & KSPROPERTY_SUPPORT_SET),"Shouldn't be able to set "
+       "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A: support = 0x%x\n",support);
+
+    if (support & KSPROPERTY_SUPPORT_GET) {
+        DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A_DATA data;
+        ULONG bytes;
+
+        data.Callback = callbackA;
+        data.Context = 0;
+
+        rc = IKsPropertySet_Get(pps, &DSPROPSETID_DirectSoundDevice,
+                              DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A,
+                              NULL, 0, &data, sizeof(data), &bytes);
+        ok(rc==DS_OK, "Couldn't enumerate: 0x%x\n",rc);
+    }
+
+    /* test DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W */
+    trace("*** Testing DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W ***\n");
+    rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice,
+                                   DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W,
+                                   &support);
+    ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, "
+       "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W) failed: %08x\n",
+       rc);
+    if (rc!=DS_OK)
+        return;
+
+    ok(support & KSPROPERTY_SUPPORT_GET,
+       "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W: "
+       "support = 0x%x\n",support);
+    ok(!(support & KSPROPERTY_SUPPORT_SET),"Shouldn't be able to set "
+       "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W: support = 0x%x\n",support);
+
+    if (support & KSPROPERTY_SUPPORT_GET) {
+        DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W_DATA data;
+        ULONG bytes;
+
+        data.Callback = callbackW;
+        data.Context = 0;
+
+        rc = IKsPropertySet_Get(pps, &DSPROPSETID_DirectSoundDevice,
+                              DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W,
+                              NULL, 0, &data, sizeof(data), &bytes);
+        ok(rc==DS_OK, "Couldn't enumerate: 0x%x\n",rc);
+    }
+}
+
+static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
+                                   LPCSTR lpcstrModule, LPVOID lpContext)
+{
+    HRESULT rc;
+    LPDIRECTSOUND dso=NULL;
+    LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL;
+    DSBUFFERDESC bufdesc;
+    WAVEFORMATEX wfx;
+    int ref;
+
+    trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule);
+
+    rc=pDirectSoundCreate(lpGuid,&dso,NULL);
+    ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
+       "DirectSoundCreate() failed: %08x\n",rc);
+    if (rc!=DS_OK) {
+        if (rc==DSERR_NODRIVER)
+            trace("  No Driver\n");
+        else if (rc == DSERR_ALLOCATED)
+            trace("  Already In Use\n");
+        else if (rc == E_FAIL)
+            trace("  No Device\n");
+        goto EXIT;
+    }
+
+    /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
+    /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
+    rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
+    ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %08x\n",
+       rc);
+    if (rc!=DS_OK)
+        goto EXIT;
+
+    /* Testing 3D buffers */
+    primary=NULL;
+    ZeroMemory(&bufdesc, sizeof(bufdesc));
+    bufdesc.dwSize=sizeof(bufdesc);
+    bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_LOCHARDWARE|DSBCAPS_CTRL3D;
+    rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
+    ok((rc==DS_OK&&primary!=NULL)
+       || broken(rc==DSERR_INVALIDPARAM),
+       "IDirectSound_CreateSoundBuffer() failed to "
+       "create a hardware 3D primary buffer: %08x\n",rc);
+    if(rc==DSERR_INVALIDPARAM) {
+       skip("broken driver\n");
+       goto EXIT;
+    }
+    if (rc==DS_OK&&primary!=NULL) {
+        ZeroMemory(&wfx, sizeof(wfx));
+        wfx.wFormatTag=WAVE_FORMAT_PCM;
+        wfx.nChannels=1;
+        wfx.wBitsPerSample=16;
+        wfx.nSamplesPerSec=44100;
+        wfx.nBlockAlign=wfx.nChannels*wfx.wBitsPerSample/8;
+        wfx.nAvgBytesPerSec=wfx.nSamplesPerSec*wfx.nBlockAlign;
+        ZeroMemory(&bufdesc, sizeof(bufdesc));
+        bufdesc.dwSize=sizeof(bufdesc);
+        bufdesc.dwFlags=DSBCAPS_CTRLDEFAULT|DSBCAPS_GETCURRENTPOSITION2;
+        bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec;
+        bufdesc.lpwfxFormat=&wfx;
+        trace("  Testing a secondary buffer at %dx%dx%d\n",
+            wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels);
+        rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
+        ok(rc==DS_OK&&secondary!=NULL,"IDirectSound_CreateSoundBuffer() "
+           "failed to create a secondary buffer: %08x\n",rc);
+        if (rc==DS_OK&&secondary!=NULL) {
+            IKsPropertySet * pPropertySet=NULL;
+            rc=IDirectSoundBuffer_QueryInterface(secondary,
+                                                 &IID_IKsPropertySet,
+                                                 (void **)&pPropertySet);
+            /* it's not an error for this to fail */
+            if(rc==DS_OK) {
+                ULONG ulTypeSupport;
+                trace("  Supports property sets\n");
+                /* it's not an error for these to fail */
+                rc=IKsPropertySet_QuerySupport(pPropertySet,
+                                               &DSPROPSETID_VoiceManager,
+                                               0,&ulTypeSupport);
+                if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET|
+                                                KSPROPERTY_SUPPORT_SET)))
+                    trace("    DSPROPSETID_VoiceManager supported\n");
+                else
+                    trace("    DSPROPSETID_VoiceManager not supported\n");
+                rc=IKsPropertySet_QuerySupport(pPropertySet,
+                    &DSPROPSETID_EAX20_ListenerProperties,0,&ulTypeSupport);
+                if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET|
+                    KSPROPERTY_SUPPORT_SET)))
+                    trace("    DSPROPSETID_EAX20_ListenerProperties "
+                          "supported\n");
+                else
+                    trace("    DSPROPSETID_EAX20_ListenerProperties not "
+                          "supported\n");
+                rc=IKsPropertySet_QuerySupport(pPropertySet,
+                    &DSPROPSETID_EAX20_BufferProperties,0,&ulTypeSupport);
+                if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET|
+                    KSPROPERTY_SUPPORT_SET)))
+                    trace("    DSPROPSETID_EAX20_BufferProperties supported\n");
+                else
+                    trace("    DSPROPSETID_EAX20_BufferProperties not "
+                          "supported\n");
+                rc=IKsPropertySet_QuerySupport(pPropertySet,
+                    &DSPROPSETID_I3DL2_ListenerProperties,0,&ulTypeSupport);
+                if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET|
+                    KSPROPERTY_SUPPORT_SET)))
+                    trace("    DSPROPSETID_I3DL2_ListenerProperties "
+                          "supported\n");
+                else
+                    trace("    DSPROPSETID_I3DL2_ListenerProperties not "
+                          "supported\n");
+                rc=IKsPropertySet_QuerySupport(pPropertySet,
+                    &DSPROPSETID_I3DL2_BufferProperties,0,&ulTypeSupport);
+                if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET|
+                    KSPROPERTY_SUPPORT_SET)))
+                    trace("    DSPROPSETID_I3DL2_BufferProperties supported\n");
+                else
+                    trace("    DSPROPSETID_I3DL2_BufferProperties not "
+                          "supported\n");
+                rc=IKsPropertySet_QuerySupport(pPropertySet,
+                    &DSPROPSETID_ZOOMFX_BufferProperties,0,&ulTypeSupport);
+                if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET|
+                    KSPROPERTY_SUPPORT_SET)))
+                    trace("    DSPROPSETID_ZOOMFX_BufferProperties "
+                          "supported\n");
+                else
+                    trace("    DSPROPSETID_ZOOMFX_BufferProperties not "
+                          "supported\n");
+                ref=IKsPropertySet_Release(pPropertySet);
+                /* try a few common ones */
+                ok(ref==0,"IKsPropertySet_Release() secondary has %d "
+                   "references, should have 0\n",ref);
+            } else
+                trace("  Doesn't support property sets\n");
+
+            ref=IDirectSoundBuffer_Release(secondary);
+            ok(ref==0,"IDirectSoundBuffer_Release() secondary has %d "
+               "references, should have 0\n",ref);
+        }
+
+        ref=IDirectSoundBuffer_Release(primary);
+        ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
+           "should have 0\n",ref);
+    }
+
+EXIT:
+    if (dso!=NULL) {
+        ref=IDirectSound_Release(dso);
+        ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",
+           ref);
+    }
+    return 1;
+}
+
+static void propset_buffer_tests(void)
+{
+    HRESULT rc;
+    rc=pDirectSoundEnumerateA(&dsenum_callback,NULL);
+    ok(rc==DS_OK,"DirectSoundEnumerateA() failed: %08x\n",rc);
+}
+
+START_TEST(propset)
+{
+    HMODULE hDsound;
+
+    CoInitialize(NULL);
+
+    hDsound = LoadLibrary("dsound.dll");
+    if (hDsound)
+    {
+
+        pDirectSoundEnumerateA = (void*)GetProcAddress(hDsound,
+            "DirectSoundEnumerateA");
+        pDllGetClassObject = (void *)GetProcAddress(hDsound,
+            "DllGetClassObject");
+        pDirectSoundCreate = (void*)GetProcAddress(hDsound,
+            "DirectSoundCreate");
+        pDirectSoundCreate8 = (void*)GetProcAddress(hDsound,
+            "DirectSoundCreate8");
+        pDirectSoundCaptureCreate=(void*)GetProcAddress(hDsound,
+            "DirectSoundCaptureCreate");
+        pDirectSoundCaptureCreate8=(void*)GetProcAddress(hDsound,
+            "DirectSoundCaptureCreate8");
+        pDirectSoundFullDuplexCreate=(void*)GetProcAddress(hDsound,
+            "DirectSoundFullDuplexCreate");
+
+        propset_private_tests();
+        propset_buffer_tests();
+
+        FreeLibrary(hDsound);
+    }
+    else
+        skip("dsound.dll not found!\n");
+
+    CoUninitialize();
+}
diff --git a/rostests/winetests/dsound/testlist.c b/rostests/winetests/dsound/testlist.c
new file mode 100644 (file)
index 0000000..2afeb2f
--- /dev/null
@@ -0,0 +1,27 @@
+/* Automatically generated file; DO NOT EDIT!! */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#define STANDALONE
+#include "wine/test.h"
+
+extern void func_capture(void);
+extern void func_ds3d8(void);
+extern void func_ds3d(void);
+extern void func_dsound8(void);
+extern void func_dsound(void);
+extern void func_duplex(void);
+extern void func_propset(void);
+
+const struct test winetest_testlist[] =
+{
+    { "capture", func_capture },
+    { "ds3d8", func_ds3d8 },
+    { "ds3d", func_ds3d },
+    { "dsound8", func_dsound8 },
+    { "dsound", func_dsound },
+    { "duplex", func_duplex },
+    { "propset", func_propset },
+    { 0, 0 }
+};