1

I need to read some information regarding the monitors connected through the EnumDisplayDevicesA function.

I tried to convert the following example written in c++ to delphi, but I have a problem when I try to read the device name from the PDISPLAY_DEVICEA structure LDeviceName := LDisplayDevice.deviceName; as it only returns Chinese characters. I think it is a problem related to character encoding but I don't know how to fix it.

My source code:

program Monitor;

{$APPTYPE CONSOLE}
uses
  System.SysUtils;

const
  user32 = 'user32.dll';

type
  LONG = LongInt;

  BOOL = LongBool;

  PDISPLAY_DEVICE = ^DISPLAY_DEVICE;

  LPCSTR = array[0..128 - 1] of WideChar;

  PLPCSTR = ^LPCSTR;

  //https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-display_devicea
  DISPLAY_DEVICE = packed record
    cb: Cardinal;
    deviceName: array[0..32 - 1] of WideChar;
    deviceString: array[0..128 - 1] of WideChar;
    stateFlags: Cardinal;
    deviceID: array[0..128 - 1] of WideChar;
    deviceKey: array[0..128 - 1] of WideChar;
  end;

//https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumdisplaydevicesa
function EnumDisplayDevicesA(APCSTR: PLPCSTR; iDevNum: Cardinal; PDISPLAY_DEVICEA: PDISPLAY_DEVICE; dwFlags: Cardinal): BOOL; stdcall; external user32;

procedure PrintMonitorNames();
var
  LDisplayDevice: DISPLAY_DEVICE;
  LDeviceIndex: Integer;
  LMonitorIndex: Integer;
  LDeviceName: string;
begin
  LDisplayDevice.cb := Sizeof(LDisplayDevice);
  LDeviceIndex := 0;
  while EnumDisplayDevicesA(nil, LDeviceIndex, @LDisplayDevice, 0) do
  begin
    LDeviceName := LDisplayDevice.deviceName;
    Writeln('Device name: ' + LDeviceName);
    LMonitorIndex := 0;
    while EnumDisplayDevicesA(@LDeviceName, LMonitorIndex, @LDisplayDevice, 0) do
    begin
      Writeln(StrPas(LDisplayDevice.deviceName) + ' ' + StrPas(LDisplayDevice.deviceString));
      Inc(LMonitorIndex);
    end;
    Inc(LDeviceIndex);
  end;
end;

var
  LDummy: string;

begin
  Writeln('START');
  PrintMonitorNames();
  Writeln('FINISH');
  Readln(LDummy);
end.

Matteo Pasini
  • 1,787
  • 3
  • 13
  • 26
  • 2
    That `LPCSTR` definition is outright wrong, see [C versus Delphi](https://stackoverflow.com/a/14941367/4299358) and [MS Docs](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/f8d4fe46-6be8-44c9-8823-615a21d17a61). In short: it's a `PChar`. – AmigoJack Jun 23 '21 at 14:35

1 Answers1

3

You are mixing ANSI and Unicode.

The EnumDisplayDevices function exists in two versions:

You are calling the ANSI version EnumDisplayDevicesA, but are using a Unicode version of DISPLAY_DEVICE. So you need to use EnumDisplayDevicesW instead.

This phenomenon that an API function exists in both W and A versions is present everywhere in the Windows API, so the above remarks are very general.

The fact that you get Chinese text because of this encoding mismatch is also very well known.


Having said all this, you don't need to declare EnumDisplayDevices yourself at all. Everything you need is already present in the Delphi RTL's Windows.pas unit, just like I showed you two days ago:

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  Winapi.Windows;

begin

  var dd, md: TDisplayDevice;

  FillChar(dd, SizeOf(dd), 0);
  dd.cb := SizeOf(dd);
  FillChar(md, SizeOf(md), 0);
  md.cb := SizeOf(md);
  var i := 0;
  while EnumDisplayDevices(nil, i, dd, 0) do
  begin
    var j := 0;
    while EnumDisplayDevices(@dd.DeviceName[0], j, md, 0) do
    begin
      Writeln(md.DeviceString);
      Inc(j);
    end;
    Inc(i);
  end;

  Readln;

end.

Notice that MSDN says this:

The winuser.h header defines EnumDisplayDevices as an alias which automatically selects the ANSI or Unicode version of this function based on the definition of the UNICODE preprocessor constant.

The same remarks applies to the Delphi RTL's Windows.pas.

Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
  • Hi, thanks for the answer, yes I tried as you advised me in the other question but I couldn't get it to work (surely due to my lack of experience). So everything works perfectly, thank you again for your time – Matteo Pasini Jun 23 '21 at 10:52