6

编辑- 见最后更新

这是针对 Delphi 7.0 Build 4.453

概括

我需要能够从作为 HMONITOR 的 TMonitor 对象(TScreen 组件中的 Monitors 数组中的一个元素)获取 Handle 属性,并将其转换为您将在调用EnumDisplaySettings 时用作 lpszDeviceName 参数的字符串。

(我的最终目标是通过将解析的 lpszDeviceName 传递给对 EnumDisplaySettings 的调用,从给定的 HMONITOR 值中获取设备设置列表)。

详细资料

如上所述,Screen.Monitors[x].Handle 属性是 HMONITOR 类型,通常用于传递给GetMonitorInfo函数,该函数返回几何信息,但没有 lpszDeviceName。(注意:有一个TMonitorInfoEx结构,它有一个 szDevice 字段,但它似乎没有在我的系统上填写,即使我将 cbSize 字段设置为适当的大小)。

或者,如果我可以使用 szDeviceName 来获得等效的 HMONITOR 值,我可以将其插入以下函数,该函数将在比较中使用它(我在下面的代码中插入了对名为hMonitorFromDeviceName的虚构函数的调用)来指示如何它会被使用。

function GetMonitorDeviceName(hmon : HMONITOR) : string;
var
  DispDev : TDisplayDevice;
  deviceName : string;
  nDeviceIndex : integer;
begin
  Result := '';

  FillChar(DispDev, sizeof(DispDev),0);
  DispDev.cb := sizeof(DispDev);

  nDeviceIndex := 0;
  while (EnumDisplayDevices(nil, nDeviceIndex, DispDev, 0)) do
  begin

     if ( hMonitorFromDeviceName(DispDev.DeviceString) = hmon ) then
     begin
        Result := StrPas(DispDev.DeviceString);
        exit;
     end;

     inc(nDeviceIndex);

  end;
end;

更新

感谢 David Heffernan,我已经测试了他的解决方案,下面是一个示例函数,用于从给定句柄中获取监视器名称:

function GetMonitorName(hmon : HMONITOR) : string;
type
  TMonitorInfoEx = record
    cbSize: DWORD;
    rcMonitor: TRect;
    rcWork: TRect;
    dwFlags: DWORD;
    szDevice: array[0..CCHDEVICENAME - 1] of AnsiChar;
end;
var
  DispDev : TDisplayDevice;
  deviceName : string;
   monInfo : TMonitorInfoEx;
begin
  Result := '';

  monInfo.cbSize := sizeof(monInfo);
  if GetMonitorInfo(hmon,@monInfo) then
  begin

    DispDev.cb := sizeof(DispDev);
     EnumDisplayDevices(@monInfo.szDevice, 0, DispDev, 0);
     Result := StrPas(DispDev.DeviceString);

  end;
end;
4

1 回答 1

7

我想你一定是打错了GetMonitorInfo。这段代码:

{$APPTYPE CONSOLE}

uses
  SysUtils, MultiMon, Windows, Forms;

var
  i: Integer;
  MonitorInfo: TMonitorInfoEx;
begin
  MonitorInfo.cbSize := SizeOf(MonitorInfo);
  for i := 0 to Screen.MonitorCount-1 do
  begin
    if not GetMonitorInfo(Screen.Monitors[i].Handle, @MonitorInfo) then
      RaiseLastOSError;
    Writeln(MonitorInfo.szDevice);
  end;
  Readln;
end.

在我的机器上产生这个输出:

\\.\DISPLAY1
\\.\DISPLAY2

我怀疑您的调用以GetMonitorInfo某种方式失败,也许您没有检查返回值是否有错误。


搜索 QualityCentral 后,我怀​​疑您已成为旧版本 Delphi 中已知错误的受害者:QC#3239。据报道,这是在 Delphi 2006 版本 10.0.2124.6661 中修复的。


您的评论证实了这一诊断。要解决这个问题,您需要一个新的TMonitorInfoEx定义。这是一个适用于您的 pre-Unicode Delphi 的方法:

type
  TMonitorInfoEx = record
    cbSize: DWORD;
    rcMonitor: TRect;
    rcWork: TRect;
    dwFlags: DWORD;
    szDevice: array[0..CCHDEVICENAME - 1] of AnsiChar;
  end;

如果您将其添加到上面的代码中(当然是在声明变量之前),那么我相信它会解决您的问题。


有趣的是,即使在 XE3 中,这些结构也没有被正确翻译:QC#114460。诚然,这个错误是相当良性的,因为它只影响PMonitorInfoExAand TMonitorInfoExA,但在试图解决这个问题的问题时,这个错误让我发现了!

于 2013-04-01T15:38:24.353 回答