Search code examples
cvisual-studiowinapioutputdebugstring

Enumerating DirectSound device descriptions results in unnecessary question marks


I'm Enumerating all DirectSound output devices and storing their descriptions for later use during the runtime of my process. When I use OutputDebugStringW to check the results, I get the correct name of the device, but it's appended with unnecessary question marks. IE this...

BOOL CALLBACK AudioPrivate::DSEnumProc(LPGUID lpGUID,
                                       LPCWSTR lpszDesc,
                                       LPCWSTR lpszDevName,
                                       LPVOID lpData) {
    pDeviceInfo[nDevices].lpGUID = lpGUID;
    pDeviceInfo[nDevices].lpszDesc = new WCHAR[wcslen(lpszDesc)];
    pDeviceInfo[nDevices].lpszDevName = new WCHAR[wcslen(lpszDevName)];

    ZeroMemory(pDeviceInfo[nDevices].lpszDesc, sizeof(WCHAR) * wcslen(lpszDesc));
    ZeroMemory(pDeviceInfo[nDevices].lpszDevName, sizeof(WCHAR) * wcslen(lpszDevName));

    memcpy(pDeviceInfo[nDevices].lpszDesc, lpszDesc, sizeof(WCHAR) * wcslen(lpszDesc));
    memcpy(pDeviceInfo[nDevices].lpszDevName, lpszDevName, sizeof(WCHAR) * wcslen(lpszDevName));

    OutputDebugStringW(L"\n");
    OutputDebugStringW(pDeviceInfo[nDevices].lpszDesc);
    OutputDebugStringW(L"\n");
    OutputDebugStringW(pDeviceInfo[nDevices].lpszDevName);
    OutputDebugStringW(L"\n");

    //vs
    OutputDebugString(L"\n");
    OutputDebugStringW(lpszDesc);
    OutputDebugStringW(L"\n");
    OutputDebugStringW(lpszDevName);
    OutputDebugStringW(L"\n");

    nDevices++;

    return TRUE;
}

...results in this:

Primary Sound Driver????????????
????????

Primary Sound Driver



Speakers (Conexant SmartAudio HD)???????????
{0.0.0.00000000}.{0698bbc7-d0ba-4445-a5a7-a63b625c4298}?????????

Speakers (Conexant SmartAudio HD)
{0.0.0.00000000}.{0698bbc7-d0ba-4445-a5a7-a63b625c4298}

I'm nulling out the memory to my own strings, so this should only happen if the strings provided by the Enum Proc have these question marks in them, but as demonstrated they do not. Why is this happening?


Solution

  • You have to reserve space for string terminator (NULL character too), this line will allocate space for string only, without terminator:

    pDeviceInfo[nDevices].lpszDesc = new WCHAR[wcslen(lpszDesc)];
    

    This because wcslen() returns string length without terminator (see reference). Just change to (for all strings, of course):

    pDeviceInfo[nDevices].lpszDesc = new WCHAR[wcslen(lpszDesc) + 1];
    pDeviceInfo[nDevices].lpszDevName = new WCHAR[wcslen(lpszDevName) + 1];
    

    And:

    ZeroMemory(pDeviceInfo[nDevices].lpszDesc, sizeof(WCHAR) * (wcslen(lpszDesc) + 1));
    ZeroMemory(pDeviceInfo[nDevices].lpszDevName, sizeof(WCHAR) * (wcslen(lpszDevName) + 1));