【问题标题】:Print the monitor's name with EnumDisplayDevices in Delphi在 Delphi 中使用 EnumDisplayDevices 打印显示器的名称
【发布时间】:2021-06-23 10:38:28
【问题描述】:

我需要阅读一些关于通过EnumDisplayDevicesA 函数连接的监视器的信息。

我尝试将以下用c++编写的example转换为delphi,但是当我尝试从PDISPLAY_DEVICEA结构LDeviceName := LDisplayDevice.deviceName;读取设备名称时遇到问题,因为它只返回中文字符。 我认为这是与字符编码有关的问题,但我不知道如何解决。

我的源代码:

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://docs.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://docs.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.

【问题讨论】:

标签: delphi dll unicode


【解决方案1】:

您正在混合使用 ANSI 和 Unicode。

EnumDisplayDevices 函数存在两个版本:

您调用的是 ANSI 版本 EnumDisplayDevicesA,但使用的是 Unicode 版本的 DISPLAY_DEVICE。所以你需要改用EnumDisplayDevicesW

在Windows API中随处可见一个API函数在W和A版本中都存在的现象,所以上面的说明很笼统。

由于这种编码不匹配而得到中文文本的事实也是very well known


说了这么多,你根本不需要自己声明EnumDisplayDevices。你需要的一切都已经存在于 Delphi RTL 的 Windows.pas 单元中,就像我向你展示的 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.

请注意,MSDN 是这样说的:

winuser.h 头文件将 EnumDisplayDevices 定义为别名,它会根据 UNICODE 预处理器常量的定义自动选择此函数的 ANSI 或 Unicode 版本。

同样的评论适用于 Delphi RTL 的 Windows.pas

【讨论】:

  • 您好,感谢您的回答,是的,我按照您在另一个问题中的建议进行了尝试,但我无法使其正常工作(肯定是由于我缺乏经验)。所以一切都很完美,再次感谢您的宝贵时间
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-13
  • 2021-06-03
相关资源
最近更新 更多