Index: /trunk/src/VBox/Devices/Audio/DrvHostDSound.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DrvHostDSound.cpp	(revision 86574)
+++ /trunk/src/VBox/Devices/Audio/DrvHostDSound.cpp	(revision 86575)
@@ -1611,27 +1611,123 @@
             PDSOUNDDEV pDSoundDev = (PDSOUNDDEV)pDev->pvData;
 
-            if (pGUID)
+            if (pGUID) /* pGUID == NULL means default device. */
                 memcpy(&pDSoundDev->Guid, pGUID, sizeof(GUID));
 
-            LPDIRECTSOUND8 pDS;
-            HRESULT hr = directSoundPlayInterfaceCreate(pGUID, &pDS);
+            rc = DrvAudioHlpDeviceEnumAdd(pDevEnm, pDev);
+
+            /* Note: Querying the actual device information will be done at some 
+             *       later point in time outside this enumeration callback to prevent
+             *       DSound hangs. */
+        }
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    if (RT_FAILURE(rc))
+    {
+        LogRel(("DSound: Error enumeration playback device '%ls', rc=%Rrc\n", pwszDescription, rc));
+        return FALSE; /* Abort enumeration. */
+    }
+
+    return TRUE;
+}
+
+/**
+ * Callback for the capture device enumeration.
+ *
+ * @return  TRUE if continuing enumeration, FALSE if not.
+ * @param   pGUID               Pointer to GUID of enumerated device. Can be NULL.
+ * @param   pwszDescription     Pointer to (friendly) description of enumerated device.
+ * @param   pwszModule          Pointer to module name of enumerated device.
+ * @param   lpContext           Pointer to PDSOUNDENUMCBCTX context for storing the enumerated information.
+ */
+static BOOL CALLBACK dsoundDevicesEnumCbCapture(LPGUID pGUID, LPCWSTR pwszDescription, LPCWSTR pwszModule, PVOID lpContext)
+{
+    RT_NOREF(pwszModule);
+
+    PDSOUNDENUMCBCTX pEnumCtx = (PDSOUNDENUMCBCTX )lpContext;
+    AssertPtrReturn(pEnumCtx , FALSE);
+
+    PPDMAUDIODEVICEENUM pDevEnm = pEnumCtx->pDevEnm;
+    AssertPtrReturn(pDevEnm, FALSE);
+
+    /* pGUID can be NULL for default device(s). */
+    AssertPtrReturn(pwszDescription, FALSE);
+    /* Do not care about pwszModule. */
+
+    int rc;
+
+    PPDMAUDIODEVICE pDev = DrvAudioHlpDeviceAlloc(sizeof(DSOUNDDEV));
+    if (pDev)
+    {
+        pDev->enmUsage = PDMAUDIODIR_IN;
+        pDev->enmType  = PDMAUDIODEVICETYPE_BUILTIN;
+
+        char *pszName;
+        rc = RTUtf16ToUtf8(pwszDescription, &pszName);
+        if (RT_SUCCESS(rc))
+        {
+            RTStrCopy(pDev->szName, sizeof(pDev->szName), pszName);
+            RTStrFree(pszName);
+
+            PDSOUNDDEV pDSoundDev = (PDSOUNDDEV)pDev->pvData;
+
+            if (pGUID) /* pGUID == NULL means default capture device. */
+                memcpy(&pDSoundDev->Guid, pGUID, sizeof(GUID));
+
+            rc = DrvAudioHlpDeviceEnumAdd(pDevEnm, pDev);
+
+            /* Note: Querying the actual device information will be done at some 
+             *       later point in time outside this enumeration callback to prevent
+             *       DSound hangs. */
+        }
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    if (RT_FAILURE(rc))
+    {
+        LogRel(("DSound: Error enumeration capture device '%ls', rc=%Rrc\n", pwszDescription, rc));
+        return FALSE; /* Abort enumeration. */
+    }
+
+    return TRUE;
+}
+
+/**
+ * Qqueries information for a given (DirectSound) device.
+ *
+ * @returns VBox status code.
+ * @param   pThis               Host audio driver instance.
+ * @param   pDev                Audio device to query information for.
+ */
+static int dsoundDeviceQueryInfo(PDRVHOSTDSOUND pThis, PPDMAUDIODEVICE pDev)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    AssertPtrReturn(pDev,  VERR_INVALID_POINTER);
+
+    PDSOUNDDEV pDSoundDev = (PDSOUNDDEV)pDev->pvData;
+    AssertPtr(pDSoundDev);
+
+    int rc;
+
+    if (pDev->enmUsage == PDMAUDIODIR_OUT)
+    {
+        LPDIRECTSOUND8 pDS;
+        HRESULT hr = directSoundPlayInterfaceCreate(&pDSoundDev->Guid, &pDS);
+        if (SUCCEEDED(hr))
+        {
+            DSCAPS DSCaps;
+            RT_ZERO(DSCaps);
+            DSCaps.dwSize = sizeof(DSCAPS);
+            hr = IDirectSound_GetCaps(pDS, &DSCaps);
             if (SUCCEEDED(hr))
             {
-                do
+                pDev->cMaxOutputChannels = DSCaps.dwFlags & DSCAPS_PRIMARYSTEREO ? 2 : 1;
+
+                DWORD dwSpeakerCfg;
+                hr = IDirectSound_GetSpeakerConfig(pDS, &dwSpeakerCfg);
+                if (SUCCEEDED(hr))
                 {
-                    DSCAPS DSCaps;
-                    RT_ZERO(DSCaps);
-                    DSCaps.dwSize = sizeof(DSCAPS);
-                    hr = IDirectSound_GetCaps(pDS, &DSCaps);
-                    if (FAILED(hr))
-                        break;
-
-                    pDev->cMaxOutputChannels = DSCaps.dwFlags & DSCAPS_PRIMARYSTEREO ? 2 : 1;
-
-                    DWORD dwSpeakerCfg;
-                    hr = IDirectSound_GetSpeakerConfig(pDS, &dwSpeakerCfg);
-                    if (FAILED(hr))
-                        break;
-
                     unsigned uSpeakerCount = 0;
                     switch (DSSPEAKER_CONFIG(dwSpeakerCfg))
@@ -1652,110 +1748,53 @@
                         pDev->cMaxOutputChannels = uSpeakerCount;
 
-                } while (0);
-
-                directSoundPlayInterfaceDestroy(pDS);
-
+                    rc = VINF_SUCCESS;
+                }
+                else
+                {
+                    LogRel(("DSound: Error retrieving playback device speaker config, hr=%Rhrc\n", hr));
+                    rc = VERR_ACCESS_DENIED; /** @todo Fudge! */
+                }
+            }
+            else
+            {
+                LogRel(("DSound: Error retrieving playback device capabilities, hr=%Rhrc\n", hr));
+                rc = VERR_ACCESS_DENIED; /** @todo Fudge! */
+            }
+
+            directSoundPlayInterfaceDestroy(pDS);
+        }
+        else
+            rc = VERR_GENERAL_FAILURE;
+    }
+    else if (pDev->enmUsage == PDMAUDIODIR_IN)
+    {
+        LPDIRECTSOUNDCAPTURE8 pDSC;
+        HRESULT hr = directSoundCaptureInterfaceCreate(&pDSoundDev->Guid, &pDSC);
+        if (SUCCEEDED(hr))
+        {
+            DSCCAPS DSCCaps;
+            RT_ZERO(DSCCaps);
+            DSCCaps.dwSize = sizeof(DSCCAPS);
+            hr = IDirectSoundCapture_GetCaps(pDSC, &DSCCaps);
+            if (SUCCEEDED(hr))
+            {
+                pDev->cMaxInputChannels = DSCCaps.dwChannels;
                 rc = VINF_SUCCESS;
             }
             else
-                rc = VERR_GENERAL_FAILURE;
-
-            if (RT_SUCCESS(rc))
-                rc = DrvAudioHlpDeviceEnumAdd(pDevEnm, pDev);
-        }
+            {
+                LogRel(("DSound: Error retrieving capture device capabilities, hr=%Rhrc\n", hr));
+                rc = VERR_ACCESS_DENIED; /** @todo Fudge! */
+            }
+
+            directSoundCaptureInterfaceDestroy(pDSC);
+        }
+        else
+            rc = VERR_GENERAL_FAILURE;
     }
     else
-        rc = VERR_NO_MEMORY;
-
-    if (RT_FAILURE(rc))
-    {
-        LogRel(("DSound: Error enumeration playback device '%ls', rc=%Rrc\n", pwszDescription, rc));
-        return FALSE; /* Abort enumeration. */
-    }
-
-    return TRUE;
-}
-
-/**
- * Callback for the capture device enumeration.
- *
- * @return  TRUE if continuing enumeration, FALSE if not.
- * @param   pGUID               Pointer to GUID of enumerated device. Can be NULL.
- * @param   pwszDescription     Pointer to (friendly) description of enumerated device.
- * @param   pwszModule          Pointer to module name of enumerated device.
- * @param   lpContext           Pointer to PDSOUNDENUMCBCTX context for storing the enumerated information.
- */
-static BOOL CALLBACK dsoundDevicesEnumCbCapture(LPGUID pGUID, LPCWSTR pwszDescription, LPCWSTR pwszModule, PVOID lpContext)
-{
-    RT_NOREF(pwszModule);
-
-    PDSOUNDENUMCBCTX pEnumCtx = (PDSOUNDENUMCBCTX )lpContext;
-    AssertPtrReturn(pEnumCtx , FALSE);
-
-    PPDMAUDIODEVICEENUM pDevEnm = pEnumCtx->pDevEnm;
-    AssertPtrReturn(pDevEnm, FALSE);
-
-    /* pGUID can be NULL for default device(s). */
-    AssertPtrReturn(pwszDescription, FALSE);
-    /* Do not care about pwszModule. */
-
-    int rc;
-
-    PPDMAUDIODEVICE pDev = DrvAudioHlpDeviceAlloc(sizeof(DSOUNDDEV));
-    if (pDev)
-    {
-        pDev->enmUsage = PDMAUDIODIR_IN;
-        pDev->enmType  = PDMAUDIODEVICETYPE_BUILTIN;
-
-        char *pszName;
-        rc = RTUtf16ToUtf8(pwszDescription, &pszName);
-        if (RT_SUCCESS(rc))
-        {
-            RTStrCopy(pDev->szName, sizeof(pDev->szName), pszName);
-            RTStrFree(pszName);
-
-            PDSOUNDDEV pDSoundDev = (PDSOUNDDEV)pDev->pvData;
-
-            if (pGUID)
-                memcpy(&pDSoundDev->Guid, pGUID, sizeof(GUID));
-
-            LPDIRECTSOUNDCAPTURE8 pDSC;
-            HRESULT hr = directSoundCaptureInterfaceCreate(pGUID, &pDSC);
-            if (SUCCEEDED(hr))
-            {
-                do
-                {
-                    DSCCAPS DSCCaps;
-                    RT_ZERO(DSCCaps);
-                    DSCCaps.dwSize = sizeof(DSCCAPS);
-                    hr = IDirectSoundCapture_GetCaps(pDSC, &DSCCaps);
-                    if (FAILED(hr))
-                        break;
-
-                    pDev->cMaxInputChannels = DSCCaps.dwChannels;
-
-                } while (0);
-
-                directSoundCaptureInterfaceDestroy(pDSC);
-
-                rc = VINF_SUCCESS;
-            }
-            else
-                rc = VERR_GENERAL_FAILURE;
-
-            if (RT_SUCCESS(rc))
-                rc = DrvAudioHlpDeviceEnumAdd(pDevEnm, pDev);
-        }
-    }
-    else
-        rc = VERR_NO_MEMORY;
-
-    if (RT_FAILURE(rc))
-    {
-        LogRel(("DSound: Error enumeration capture device '%ls', rc=%Rrc\n", pwszDescription, rc));
-        return FALSE; /* Abort enumeration. */
-    }
-
-    return TRUE;
+        AssertFailedStmt(rc = VERR_NOT_SUPPORTED);
+
+    return rc;
 }
 
@@ -1769,5 +1808,6 @@
 static int dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PPDMAUDIODEVICEENUM pDevEnm)
 {
-    AssertPtrReturn(pThis,    VERR_INVALID_POINTER);
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
 
     DSLOG(("DSound: Enumerating devices ...\n"));
@@ -1781,8 +1821,13 @@
         EnumCtx.pDevEnm = pDevEnm;
 
+        /*
+         * Enumerate playback devices.
+         */
         PFNDIRECTSOUNDENUMERATEW pfnDirectSoundEnumerateW = NULL;
         rc = RTLdrGetSymbol(hDSound, "DirectSoundEnumerateW", (void**)&pfnDirectSoundEnumerateW);
         if (RT_SUCCESS(rc))
         {
+            DSLOG(("DSound: Enumerating playback devices ...\n"));
+
             HRESULT hr = pfnDirectSoundEnumerateW(&dsoundDevicesEnumCbPlayback, &EnumCtx);
             if (FAILED(hr))
@@ -1792,8 +1837,13 @@
             LogRel(("DSound: Error starting to enumerate host playback devices: %Rrc\n", rc));
 
+        /*
+         * Enumerate capture devices.
+         */
         PFNDIRECTSOUNDCAPTUREENUMERATEW pfnDirectSoundCaptureEnumerateW = NULL;
         rc = RTLdrGetSymbol(hDSound, "DirectSoundCaptureEnumerateW", (void**)&pfnDirectSoundCaptureEnumerateW);
         if (RT_SUCCESS(rc))
         {
+            DSLOG(("DSound: Enumerating capture devices ...\n"));
+
             HRESULT hr = pfnDirectSoundCaptureEnumerateW(&dsoundDevicesEnumCbCapture, &EnumCtx);
             if (FAILED(hr))
@@ -1803,4 +1853,11 @@
             LogRel(("DSound: Error starting to enumerate host capture devices: %Rrc\n", rc));
 
+        /*
+         * Query Information from all enumerated devices.
+         */
+        PPDMAUDIODEVICE pDev;
+        RTListForEach(&pDevEnm->lstDevices, pDev, PDMAUDIODEVICE, Node)
+            /* ignore rc */ dsoundDeviceQueryInfo(pThis, pDev);
+
         RTLdrClose(hDSound);
     }
@@ -1808,5 +1865,5 @@
     {
         /* No dsound.dll on this system. */
-        LogRel(("DSound: Could not load dsound.dll: %Rrc\n", rc));
+        LogRel(("DSound: Could not load dsound.dll for enumerating devices: %Rrc\n", rc));
     }
 
