delphi - 在 Delphi 中使用 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://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.
解决方案
您正在混合 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
.
推荐阅读
- elasticsearch - 如何在 ElasticSearch 中构建索引
- go - Golang Mutation with a list as a param variable (GRAPHQL)
- java - 试图制作一个随机数的变量,但出现错误。谁能告诉我怎么了?
- numpy - 在python中乘以多维数组
- r - 如何将剪贴蒙版应用于ggplot中的geom?
- c# - 关闭对继承我的配置的 Web 作业的跟踪
- java - 如何在 OS X 上正确创建 C++ 目标文件 (.o)?
- ios - Interface Builder 中的“查看方式”问题
- javascript - 是否有纯 CSS 解决方案将浮动元素的兄弟元素的大小调整到其父元素中的全部剩余高度(无绝对定位)?
- java - Java 微服务