Перечисление описаний устройств 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);