Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Need to resolve HMONITOR --> deviceName (or deviceName --> HMONITOR) in windows

EDIT - See Update at end

This is for Delphi 7.0 Build 4.453

Summary

I need to be able to take the Handle property from a TMonitor object (an element in the Monitors array in the TScreen component) which is a HMONITOR, and turn it into the string you would use in calls to EnumDisplaySettings as the lpszDeviceName parameter.

(my end goal is to get a list of device settings from a given HMONITOR value, by passing the resolved lpszDeviceName into calls to EnumDisplaySettings).

Detailed Information

As mentioned above, the Screen.Monitors[x].Handle property is of type HMONITOR and is normally used to pass into the GetMonitorInfo function, which returns, geometry information, but no lpszDeviceName. (note: there is a TMonitorInfoEx structure that has a szDevice field, but it does not seem to get filled in on my system, even though i am setting the cbSize field to the appropriate size).

Alternatively, if i can use a szDeviceName to get the equivalent HMONITOR value, i could plug it into the following function, which would use it in a comparison (I have inserted a call to fictitious function called hMonitorFromDeviceName in the code below) to indicate how it would be used.

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;

Update

Thanks to David Heffernan, I have tested his solution, and here is a sample function to get the monitor name from a given handle:

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;
like image 612
unsynchronized Avatar asked Apr 01 '13 15:04

unsynchronized


1 Answers

I think that you must be calling GetMonitorInfo incorrectly. This code:

{$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.

produces this output on my machine:

\\.\DISPLAY1
\\.\DISPLAY2

I suspect that your call to GetMonitorInfo is failing in some way and perhaps you are not checking the return value for errors.


Having searched QualityCentral I suspect you have fallen victim to a known bug in older versions of Delphi: QC#3239. This is reported fixed in version 10.0.2124.6661 which is Delphi 2006.


Your comments confirm this diagnosis. To fix the problem you'll need a new TMonitorInfoEx definition. Here's one that will work on your pre-Unicode Delphi:

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

If you add that to the code above (before you declare the variables of course) then I believe it will resolve your problem.


As an interesting aside, even in XE3, these structs have not been translated correctly: QC#114460. Admittedly the error is rather benign as it only affects PMonitorInfoExA and TMonitorInfoExA, but the error caught me out whilst trying to solve the problem in this question!

like image 95
David Heffernan Avatar answered Nov 14 '22 23:11

David Heffernan