Перечисление описаний устройств DirectSound приводит к ненужным знакам вопроса

Я перечисляю все устройства вывода DirectSound и сохраняю их описания для последующего использования во время выполнения моего процесса. Когда я использую OutputDebugStringW для проверки результатов, я получаю правильное имя устройства, но к нему добавляются ненужные знаки вопроса. IE это...

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

... результаты в этом:

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}

Я обнуляю память для своих собственных строк, так что это должно происходить только в том случае, если в строках, предоставленных Enum Proc, есть эти знаки вопроса, но, как продемонстрировано, их нет. Почему это происходит?

2 ответа

Решение

Вы должны зарезервировать место для ограничителя строки (символ NULL тоже), эта строка будет выделять место только для строки без терминатора:

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

Это потому что wcslen() возвращает длину строки без терминатора (см. ссылку). Просто измените на (для всех строк, конечно):

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

А также:

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

Я думаю, что виновник скрывается здесь:

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

Строка UNICODE, но все еще обрабатывается как строка C, поэтому для ее работы требуется терминатор '\0'.

Вы должны выделить еще один WCHAR, чтобы обеспечить достаточно места для этого терминатора.

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

ZeroMemory становится ненужным, если вы замените memcpy с wcscpy

Когда вы на это, вы могли бы, вероятно, избавить вас от хлопот, используя wcsdup или же _wcsdup:

pDeviceInfo[nDevices].lpszDesc = wcsdup (lpszDesc);
Другие вопросы по тегам