Question

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?

Was it helpful?

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));

OTHER TIPS

I think the culprit hides here:

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

The string is UNICODE, but still handled as a C string, so it needs a '\0' terminator to work.

You must allocate one more WCHAR to provide enough space for that terminator.

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

The ZeroMemory becomes unnecessary if you replace memcpy with wcscpy

When you're at it, you could probably save you the hassle by using wcsdup or _wcsdup :

pDeviceInfo[nDevices].lpszDesc = wcsdup (lpszDesc);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top