dmDeviceName — это просто ‘c’

#c #winapi #dev-mode

#c #по WinAPI #режим разработки #winapi

Вопрос:

Я пытаюсь получить имена каждого из моих мониторов, используя DEVMODE.dmDeviceName :

dmDeviceName Имя устройства
Массив символов с нулевым завершением, который задает «понятное» имя принтера или дисплея; например, «PCL/HP LaserJet» в случае PCL/HP LaserJet. Эта строка уникальна среди драйверов устройств. Обратите внимание, что это имя может быть усечено, чтобы поместиться в массив dmDeviceName.

Я использую следующий код:

 log.printf("Device Name: %s",currDevMode.dmDeviceName);
  

Но для каждого монитора название печатается как просто c . Вся остальная информация из DEVMODE, похоже, печатается нормально. Что происходит не так?

Ответ №1:

Скорее всего, вы используете версию структуры в Юникоде и, таким образом, передаете широкие символы printf . Поскольку вы используете строку формата, которая подразумевает char данные, существует несоответствие.

Кодировка UTF-16 приводит к тому, что каждый второй байт равен 0 для символов в диапазоне ASCII, и поэтому printf считается, что второй байт первого двухбайтового символа на самом деле является нулевым ограничителем.

Это та проблема, с которой вы сталкиваетесь printf , которая, конечно, не имеет безопасности типов. Поскольку вы используете C , вероятно, стоит переключиться на iostream ввод-вывод на основе.

Однако, если вы хотите использовать текст ANSI, как вы указали в комментарии, то самым простым решением является использование DEVMODEA версии структуры ANSI и соответствующих A версий функций API, например EnumDisplaySettingsA , DeviceCapabilitiesA .

Комментарии:

1. Хм, при использовании EnumDisplaySettingsA я получаю cannot convert parameter 1 from 'WCHAR *' to 'LPCSTR' , где параметром 1 является monitorInfo.szDevice, полученный с помощью GetMonitorInfo .

2. Это все или ничего. Вам нужно GetMonitorInfoA так же, как EnumDisplaySettingsA . Конечно, вы могли бы просто переключить конфигурацию вашего проекта на ANSI. Для справки прочитайте это: msdn.microsoft.com/en-us/library/dd374089 (VS.85).aspx

3. API для преобразования wide в ANSI является WideCharToMultiByte() . Это не самый простой в использовании, поэтому, если вы можете вместо этого вызвать ANSI API, вам будет проще.

4. Я надеюсь, что это cdd то, что вы ищете!

5. Я только что позвонил EnumDisplaySettings , и я также вижу имя устройства cdd. Не спрашивайте меня, что это значит, но я почти уверен, что вы получаете правильное значение от системы.

Ответ №2:

dmDeviceName TCHAR[] поэтому, если вы компилируете для unicode, первый широкий символ будет интерпретироваться как ‘c’, за которым следует нулевой ограничитель.

Вам нужно будет преобразовать его в ascii или использовать процедуры печати с поддержкой unicode.

Комментарии:

1. Как бы мне преобразовать его в ascii? Я не могу изменить способ log работы.

2. @fredley Я рассмотрел это в заключительных абзацах моего ответа.