2

I'm trying to get the names of each of my monitors using DEVMODE.dmDeviceName:

dmDeviceName
A zero-terminated character array that specifies the "friendly" name of the printer or display; for example, "PCL/HP LaserJet" in the case of PCL/HP LaserJet. This string is unique among device drivers. Note that this name may be truncated to fit in the dmDeviceName array.

I'm using the following code:

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

But for every monitor, the name is printed as just c. All other information from DEVMODE seems to print ok. What's going wrong?

fredley
  • 32,953
  • 42
  • 145
  • 236

2 Answers2

4

Most likely you are using the Unicode version of the structure and thus are passing wide characters to printf. Since you use a format string that implies char data there is a mis-match.

The UTF-16 encoding results in every other byte being 0 for characters in the ASCII range and so printf thinks that the second byte of the first two byte character is actually a null-terminator.

This is the sort of problem that you get with printf which of course has no type-safety. Since you are using C++ it's probably worth switching to iostream based I/O.

However, if you want to use ANSI text, as you indicate in a comment, then the simplest solution is to use the ANSI DEVMODEA version of the struct and the corresponding A versions of the API functions, e.g. EnumDisplaySettingsA, DeviceCapabilitiesA.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Hmm, when using EnumDisplaySettingsA I get `cannot convert parameter 1 from 'WCHAR *' to 'LPCSTR'`, where parameter 1 is monitorInfo.szDevice, retrieved using `GetMonitorInfo`. – fredley Oct 17 '11 at 11:27
  • 1
    It's all or nothing. You need `GetMonitorInfoA` as well as `EnumDisplaySettingsA`. Of course, you could just switch your project config to ANSI. For background read this: http://msdn.microsoft.com/en-us/library/dd374089(VS.85).aspx – David Heffernan Oct 17 '11 at 11:35
  • The API to convert wide to ANSI is [`WideCharToMultiByte()`](http://msdn.microsoft.com/en-us/library/dd374130(VS.85).aspx). It's not the simplest to use so if you can call the ANSI APIs instead then you'll find thing easier. – David Heffernan Oct 17 '11 at 11:49
  • Using your suggestion of switching to `A` suffixed methods, I've now got `printf("%s",currMode.dmDeviceName)` outputting `cdd`! – fredley Oct 17 '11 at 11:57
  • 1
    I'm hoping that `cdd` is what you are looking for! – David Heffernan Oct 17 '11 at 11:59
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/4322/discussion-between-fredley-and-david-heffernan) – fredley Oct 17 '11 at 12:01
  • 1
    I've just call `EnumDisplaySettings` and I also see a device name of cdd. Don't ask me what that means, but I'm pretty confident that you are getting the right value from the system. – David Heffernan Oct 17 '11 at 12:16
  • The damn "cdd", very strange combination of characters (maybe an acronym?) that lead us to confusion and to investigate why, because it seems a bad output string since the documentation says it should return a "Friendly name" (like "PCL/HP LaserJet"), but "cdd" is not friendly in any way. However, if we all are getting the same "cdd" then I think that is the right return value. – ElektroStudios Apr 11 '21 at 14:12
  • I suspect the "cdd" stands for "Canonical Display Driver" (there's a system file in Windows called cdd.dll that is the canonical display driver). If anyone knows otherwise, please correct me. – Scott Smith Jul 29 '21 at 05:45
2

dmDeviceName is TCHAR[] so if you're compiling for unicode, the first wide character will be interpreted as a 'c' followed by a zero terminator.

You will need to convert it to ascii or use unicode capable printing routines.

Yngve Hammersland
  • 1,634
  • 2
  • 14
  • 28