Solved

How do I identify monitor device display settings?

Posted on 2010-08-26
8
1,857 Views
Last Modified: 2013-11-05
Hi experts. How can I detect monitor display setting?
I know basic monitor information from TScreen object.
I want to find monitor index detected by windows os.

See following image:  I have 3 monitors. (1 LCD[primary], 2 USB type)
1st monior index: 1
2nd monitor index: 3
3rd monitor index: 4

How do I find that number 1,3,4 and it's additional information?


win-display-settings.jpg
0
Comment
Question by:byungho
8 Comments
 
LVL 14

Expert Comment

by:systan
ID: 33539323
try;
message WM_DEVMODECHANGE;
0
 
LVL 13

Expert Comment

by:aflarin
ID: 33539346
try this code:

procedure TForm1.Button1Click(Sender: TObject);
const
  EDD_GET_DEVICE_INTERFACE_NAME = 1;
  DISPLAY_DEVICE_ACTIVE = 1;
var
  d: TDisplayDevice;
  i: Integer;
begin
  for i:= 0 to Screen.MonitorCount do
  begin
    d.cb:= sizeof(d);
    if EnumDisplayDevices( nil, i, d, EDD_GET_DEVICE_INTERFACE_NAME) then
    begin
      Memo1.Lines.Add( 'Monitor ' + IntToStr(i) );
      Memo1.Lines.Add( d.DeviceName );
      Memo1.Lines.Add( d.DeviceString );
      if (d.StateFlags and DISPLAY_DEVICE_ACTIVE) =0 then
        Memo1.Lines.Add( 'Monitor isn''t active' );
      Memo1.Lines.Add('');
    end;
  end;
end;
0
 
LVL 13

Expert Comment

by:aflarin
ID: 33539385
What kind of additional information about display would you like to receive?

Here is the improved above code with information about display resolution and color depth:

procedure TForm1.Button1Click(Sender: TObject);
const
  EDD_GET_DEVICE_INTERFACE_NAME = 1;
  DISPLAY_DEVICE_ACTIVE = 1;
  ENUM_CURRENT_SETTINGS: DWORD = DWORD(-1);
var
  d: TDisplayDevice;
  i: Integer;
  DevMode: TDevMode;
begin
  for i:= 0 to Screen.MonitorCount do
  begin
    d.cb:= sizeof(d);
    if EnumDisplayDevices( nil, i, d, EDD_GET_DEVICE_INTERFACE_NAME) then
    begin
      Memo1.Lines.Add( 'Monitor ' + IntToStr(i) );
      if (d.StateFlags and DISPLAY_DEVICE_ACTIVE) =0 then
        Memo1.Lines.Add( 'Monitor isn''t active' );
      Memo1.Lines.Add( d.DeviceName );
      Memo1.Lines.Add( d.DeviceString );
      if EnumDisplaySettings( d.DeviceName, ENUM_CURRENT_SETTINGS, DevMode ) then
      begin
        Memo1.Lines.Add( Format( 'Resolution %d x %d', [DevMode.dmPelsWidth, DevMode.dmPelsHeight]) );
        Memo1.Lines.Add( Format( 'Bits per pixels %d', [DevMode.dmBitsPerPel]) );
      end;

      Memo1.Lines.Add('');
    end;
  end;
end;
0
Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
LVL 37

Expert Comment

by:Geert Gruwez
ID: 33539404
here are some functions which get monitor information

i found them in this site:
http://www.koders.com/delphi/fidFCB5BAEE89BE2E945279E13B48A6801746A8946A.aspx?s=hook


Screen.Monitors[I] is TMonitor object > also has a lot of information
function UsingMultipleMonitors: Boolean;
{ Returns True if the system has more than one display monitor configured. }
var
  NumMonitors: Integer;
begin
  NumMonitors := GetSystemMetrics(80 {SM_CMONITORS});
  Result := (NumMonitors <> 0) and (NumMonitors <> 1);
  { ^ NumMonitors will be zero if not running Win98, NT 5, or later }
end;

type
  HMONITOR = type Integer;
  PMonitorInfoA = ^TMonitorInfoA;
  TMonitorInfoA = record
    cbSize: DWORD;
    rcMonitor: TRect;
    rcWork: TRect;
    dwFlags: DWORD;
  end;
const
  MONITOR_DEFAULTTONEAREST = $2;
type
  TMultiMonApis = record
    funcMonitorFromRect: function(lprcScreenCoords: PRect; dwFlags: DWORD): HMONITOR; stdcall;
    funcMonitorFromPoint: function(ptScreenCoords: TPoint; dwFlags: DWORD): HMONITOR; stdcall;
    funcMonitorFromWindow: function(hWnd: HWND; dwFlags: DWORD): HMONITOR; stdcall;
    funcGetMonitorInfoA: function(hMonitor: HMONITOR; lpMonitorInfo: PMonitorInfoA): BOOL; stdcall;
  end;

{ Under D4 I could be using the MultiMon unit for the multiple monitor
  function imports, but its stubs for MonitorFromRect and MonitorFromPoint
  are seriously bugged... So I chose to avoid the MultiMon unit entirely. }

function InitMultiMonApis(var Apis: TMultiMonApis): Boolean;
var
  User32Handle: THandle;
begin
  User32Handle := GetModuleHandle(user32);
  Apis.funcMonitorFromRect := GetProcAddress(User32Handle, 'MonitorFromRect');
  Apis.funcMonitorFromPoint := GetProcAddress(User32Handle, 'MonitorFromPoint');
  Apis.funcMonitorFromWindow := GetProcAddress(User32Handle, 'MonitorFromWindow');
  Apis.funcGetMonitorInfoA := GetProcAddress(User32Handle, 'GetMonitorInfoA');
  Result := Assigned(Apis.funcMonitorFromRect) and
    Assigned(Apis.funcMonitorFromPoint) and Assigned(Apis.funcGetMonitorInfoA);
end;

function GetRectOfMonitorContainingRect(const R: TRect;
  const WorkArea: Boolean): TRect;
{ Returns the work area of the monitor which the rectangle R intersects with
  the most, or the monitor nearest R if no monitors intersect. }
var
  Apis: TMultiMonApis;
  M: HMONITOR;
  MonitorInfo: TMonitorInfoA;
begin
  if UsingMultipleMonitors and InitMultiMonApis(Apis) then begin
    M := Apis.funcMonitorFromRect(@R, MONITOR_DEFAULTTONEAREST);
    MonitorInfo.cbSize := SizeOf(MonitorInfo);
    if Apis.funcGetMonitorInfoA(M, @MonitorInfo) then begin
      if not WorkArea then
        Result := MonitorInfo.rcMonitor
      else
        Result := MonitorInfo.rcWork;
      Exit;
    end;
  end;
  Result := GetRectOfPrimaryMonitor(WorkArea);
end;

function GetRectOfMonitorContainingPoint(const P: TPoint;
  const WorkArea: Boolean): TRect;
{ Returns the screen area of the monitor containing the point P, or the monitor
  nearest P if P isn't in any monitor's work area. }
var
  Apis: TMultiMonApis;
  M: HMONITOR;
  MonitorInfo: TMonitorInfoA;
begin
  if UsingMultipleMonitors and InitMultiMonApis(Apis) then begin
    M := Apis.funcMonitorFromPoint(P, MONITOR_DEFAULTTONEAREST);
    MonitorInfo.cbSize := SizeOf(MonitorInfo);
    if Apis.funcGetMonitorInfoA(M, @MonitorInfo) then begin
      if not WorkArea then
        Result := MonitorInfo.rcMonitor
      else
        Result := MonitorInfo.rcWork;
      Exit;
    end;
  end;
  Result := GetRectOfPrimaryMonitor(WorkArea);
end;

function GetRectOfMonitorContainingWindow(const W: HWND;
  const WorkArea: Boolean): TRect;
var
  Apis: TMultiMonApis;
  M: HMONITOR;
  MonitorInfo: TMonitorInfoA;
begin
  if UsingMultipleMonitors and InitMultiMonApis(Apis) then begin
    M := Apis.funcMonitorFromWindow(W, MONITOR_DEFAULTTONEAREST);
    MonitorInfo.cbSize := SizeOf(MonitorInfo);
    if Apis.funcGetMonitorInfoA(M, @MonitorInfo) then begin
      if not WorkArea then
        Result := MonitorInfo.rcMonitor
      else
        Result := MonitorInfo.rcWork;
      Exit;
    end;
  end;
  Result := GetRectOfPrimaryMonitor(WorkArea);
end;

Open in new window

0
 

Author Comment

by:byungho
ID: 33539840
to aflarin//  Additional information is BoundsRect (Left, Top, Right,Bottom)
0
 
LVL 13

Accepted Solution

by:
aflarin earned 500 total points
ID: 33540002
ok, here is it:

procedure TForm1.Button2Click(Sender: TObject);
type
  TDeviceMode2 = packed record
    dmDeviceName: array[0..CCHDEVICENAME - 1] of AnsiChar;
    dmSpecVersion: Word;
    dmDriverVersion: Word;
    dmSize: Word;
    dmDriverExtra: Word;
    dmFields: DWORD;
    dmPosition: TPoint;
    dmDisplayOrientation: DWORD;
    dmDisplayFixedOutput: DWORD;
    dmColor: SHORT;
    dmDuplex: SHORT;
    dmYResolution: SHORT;
    dmTTOption: SHORT;
    dmCollate: SHORT;
    dmFormName: array[0..CCHFORMNAME - 1] of AnsiChar;
    dmLogPixels: Word;
    dmBitsPerPel: DWORD;
    dmPelsWidth: DWORD;
    dmPelsHeight: DWORD;
    dmDisplayFlags: DWORD;
    dmDisplayFrequency: DWORD;
    dmICMMethod: DWORD;
    dmICMIntent: DWORD;
    dmMediaType: DWORD;
    dmDitherType: DWORD;
    dmICCManufacturer: DWORD;
    dmICCModel: DWORD;
    dmPanningWidth: DWORD;
    dmPanningHeight: DWORD;
  end;

const
  EDD_GET_DEVICE_INTERFACE_NAME = 1;
  DISPLAY_DEVICE_ACTIVE = 1;
  ENUM_CURRENT_SETTINGS: DWORD = DWORD(-1);
var
  d: TDisplayDevice;
  i: Integer;
  DevMode: TDevMode;
begin
  for i:= 0 to Screen.MonitorCount do
  begin
    d.cb:= sizeof(d);
    if EnumDisplayDevices( nil, i, d, EDD_GET_DEVICE_INTERFACE_NAME) then
    begin
      Memo1.Lines.Add( 'Monitor ' + IntToStr(i) );
      if (d.StateFlags and DISPLAY_DEVICE_ACTIVE) =0 then
        Memo1.Lines.Add( 'Monitor isn''t active' );
      Memo1.Lines.Add( d.DeviceName );
      Memo1.Lines.Add( d.DeviceString );
      if EnumDisplaySettings( d.DeviceName, ENUM_CURRENT_SETTINGS, DevMode ) then
      begin
        Memo1.Lines.Add( Format( 'Resolution %d x %d', [DevMode.dmPelsWidth, DevMode.dmPelsHeight]) );
        Memo1.Lines.Add( Format( 'Bits per pixels %d', [DevMode.dmBitsPerPel]) );

        Memo1.Lines.Add( Format( 'Rect %d, %d, %d, %d', [TDeviceMode2(DevMode).dmPosition.X, TDeviceMode2(DevMode).dmPosition.Y, TDeviceMode2(DevMode).dmPosition.X+DevMode.dmPelsWidth, TDeviceMode2(DevMode).dmPosition.Y+DevMode.dmPelsHeight ]) );

      end;

      Memo1.Lines.Add('');
    end;
  end;
end;
0
 
LVL 37

Expert Comment

by:Geert Gruwez
ID: 33540108
why make it so difficult ?

procedure TForm1.ShowInMemo(aMemo: TMemo; I: integer; aRect: TRect);
begin
  aMemo.Lines.Add(Format('Index: %d; Left: %d; Top: %d; Right: %d; Bottom: %d',
    [I, aRect.Left, a.Rect.Top, aRect.Right, aRect.Bottom]));
end;

procedure TForm1.Button1Click(Sender: TObject);
var 
  I: Integer;
  m: TMonitor;
begin
  for I := 0 to Screen.MonitorCount - 1 do
  begin
    m := Screen.Monitors[I];
    ShowInMemo(Memo1, I, m.BoundsRect);
  end;
end;

Open in new window

0
 
LVL 13

Expert Comment

by:aflarin
ID: 33540220
>> why make it so difficult ?

because the index of TMonitor (in TScreen) is not the same as the OS monitor number.

btw, don't think it's difficult :)
0

Featured Post

Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Two types of users will appreciate AOMEI Backupper Pro: 1 - Those with PCIe drives (and haven't found cloning software that works on them). 2 - Those who want a fast clone of their boot drive (no re-boots needed) and it can clone your drive wh…
This video shows how to use Hyena, from SystemTools Software, to bulk import 100 user accounts from an external text file. View in 1080p for best video quality.

831 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question