在德尔福中使用 EnumDisplayDevices 打印显示器的名称



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

我试图将以下用c++编写的示例转换为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://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.

您正在混合ANSI和Unicode。

EnumDisplayDevices功能有两个版本:

  • EnumDisplayDevicesA,它是(传统的(ANSI
  • EnumDisplayDevicesW,它是Unicode

您调用的是ANSI版本EnumDisplayDevicesA,但使用的是Unicode版本的DISPLAY_DEVICE。因此,您需要使用EnumDisplayDevicesW

API函数同时存在于W和A版本中的现象在Windows API中随处可见,因此以上说明非常普遍。

因为这种编码不匹配而获得中文文本的事实也是众所周知的。


说了这么多,你根本不需要自己声明EnumDisplayDevices。您所需要的一切都已经存在于Delphi RTL的Windows.pas单元中,就像我两天前向您展示的那样:

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

最新更新