{ *********************************************************************** }
{                                                                         }
{ Translated Header File                                                  }
{ Part of the Delphi Visual Component Library                             }
{                                                                         }
{ Original Header File Copyright (c) 1985-2004 Microsoft Corporation      }
{  All Rights Reserved.                                                   }
{                                                                         }
{ Translation Copyright (c) 1995-2004 Borland Software Corporation        }
{                                                                         }
{ *********************************************************************** }

unit Borland.Vcl.MultiMon platform;

{$ALIGN 1}

(*
 * MultiMon unit provides access to the new MultiMonitor
 * APIs provided in Win98 and NT5 and greater.  For
 * backwards compatibility, the new APIs are stubbed out
 * here for older Win32 OS systems.
 *)

interface

uses
  System.Runtime.InteropServices, Windows;

const
  { GetSystemMetrics() codes }
  SM_XVIRTUALSCREEN = 76;
  SM_YVIRTUALSCREEN = 77;
  SM_CXVIRTUALSCREEN = 78;
  SM_CYVIRTUALSCREEN = 79;
  SM_CMONITORS = 80;
  SM_SAMEDISPLAYFORMAT = 81;
  SM_CMETRICS = 83;

type
  HMONITOR = type Integer;

const
  MONITOR_DEFAULTTONULL = $0;
  MONITOR_DEFAULTTOPRIMARY = $1;
  MONITOR_DEFAULTTONEAREST = $2;
  MONITORINFOF_PRIMARY = $1;

const
  CCHDEVICENAME = 32;

type
  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
  tagMONITORINFO = record
    cbSize: DWORD;
    rcMonitor: TRect;
    rcWork: TRect;
    dwFlags: DWORD;
  end;
  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  tagMONITORINFOA = record
    cbSize: DWORD;
    rcMonitor: TRect;
    rcWork: TRect;
    dwFlags: DWORD;
  end;
  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
  tagMONITORINFOW = record
    cbSize: DWORD;
    rcMonitor: TRect;
    rcWork: TRect;
    dwFlags: DWORD;
  end;
  MONITORINFO = tagMONITORINFO;
  MONITORINFOA = tagMONITORINFOA;
  MONITORINFOW = tagMONITORINFOW;
  TMonitorInfo = tagMONITORINFO;
  TMonitorInfoA = tagMONITORINFOA;
  TMonitorInfoW = tagMONITORINFOW;

  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
  tagMONITORINFOEX = record
    cbSize: DWORD;
    rcMonitor: TRect;
    rcWork: TRect;
    dwFlags: DWORD;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=CCHDEVICENAME)]
    szDevice: string;
  end;
  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  tagMONITORINFOEXA = record
    cbSize: DWORD;
    rcMonitor: TRect;
    rcWork: TRect;
    dwFlags: DWORD;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=CCHDEVICENAME)]
    szDevice: string;
  end;
  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
  tagMONITORINFOEXW = record
    cbSize: DWORD;
    rcMonitor: TRect;
    rcWork: TRect;
    dwFlags: DWORD;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=CCHDEVICENAME)]
    szDevice: string;
  end;
  MONITORINFOEX = tagMONITORINFOEX;
  MONITORINFOEXA = tagMONITORINFOEXA;
  MONITORINFOEXW = tagMONITORINFOEXW;
  TMonitorInfoEx = tagMONITORINFOEX;
  TMonitorInfoExA = tagMONITORINFOEXA;
  TMonitorInfoExW = tagMONITORINFOEXW;

  TMonitorEnumProc = function(hm: HMONITOR; dc: HDC; const r: TRect; l: LPARAM): Boolean;

function GetSystemMetrics(nIndex: Integer): Integer;
function MonitorFromWindow(hWnd: HWND; dwFlags: DWORD): HMONITOR;
function MonitorFromRect(const lprcScreenCoords: TRect; dwFlags: DWORD): HMONITOR;
function MonitorFromPoint(ptScreenCoords: TPoint; dwFlags: DWORD): HMONITOR;
function GetMonitorInfo(hMonitor: HMONITOR; var lpMonitorInfo: TMonitorInfo): Boolean; overload;
function GetMonitorInfo(hMonitor: HMONITOR; var lpMonitorInfo: TMonitorInfoEx): Boolean; overload;
function GetMonitorInfoA(hMonitor: HMONITOR; var lpMonitorInfo: TMonitorInfoA): Boolean;
function GetMonitorInfoW(hMonitor: HMONITOR; var lpMonitorInfo: TMonitorInfoW): Boolean;
function EnumDisplayMonitors(hdc: HDC; const lprcIntersect: TRect;
  lpfnEnumProc: TMonitorEnumProc; lData: LPARAM): Boolean; overload;
function EnumDisplayMonitors(hdc: HDC; lprcIntersect: IntPtr;
  lpfnEnumProc: TMonitorEnumProc; lData: LPARAM): Boolean; overload;

implementation

const
  xPRIMARY_MONITOR = HMONITOR($12340042);
  sUser32 = 'USER32.DLL';

var
  User32Dll: THandle;
  MMAvailable: Boolean;

[DllImport(sUser32, CharSet = CharSet.Ansi, SetLastError = True, EntryPoint = 'MonitorEnumProc')]
function _MonitorEnumProc(hm: HMONITOR; dc: HDC; const r: TRect; l: LPARAM): Boolean; external;
[DllImport(sUser32, CharSet = CharSet.Ansi, SetLastError = True, EntryPoint = 'GetSystemMetrics')]
function _GetSystemMetrics(nIndex: Integer): Integer; external;
[DllImport(sUser32, CharSet = CharSet.Ansi, SetLastError = True, EntryPoint = 'MonitorFromWindow')]
function _MonitorFromWindow(hWnd: HWND; dwFlags: DWORD): HMONITOR; external;
[DllImport(sUser32, CharSet = CharSet.Ansi, SetLastError = True, EntryPoint = 'MonitorFromRect')]
function _MonitorFromRect(const lprcScreenCoords: TRect; dwFlags: DWORD): HMONITOR; external;
[DllImport(sUser32, CharSet = CharSet.Ansi, SetLastError = True, EntryPoint = 'MonitorFromPoint')]
function _MonitorFromPoint(ptScreenCoords: TPoint; dwFlags: DWORD): HMONITOR; external;
[DllImport(sUser32, CharSet = CharSet.Auto, SetLastError = True, EntryPoint = 'GetMonitorInfo')]
function _GetMonitorInfo(hMonitor: HMONITOR; var lpMonitorInfo: TMonitorInfo): Boolean; overload; external;
[DllImport(sUser32, CharSet = CharSet.Auto, SetLastError = True, EntryPoint = 'GetMonitorInfo')]
function _GetMonitorInfo(hMonitor: HMONITOR; var lpMonitorInfo: TMonitorInfoEx): Boolean; overload; external;
[DllImport(sUser32, CharSet = CharSet.Ansi, SetLastError = True, EntryPoint = 'GetMonitorInfoA')]
function _GetMonitorInfoA(hMonitor: HMONITOR; var lpMonitorInfo: TMonitorInfoA): Boolean; external;
[DllImport(sUser32, CharSet = CharSet.Unicode, SetLastError = True, EntryPoint = 'GetMonitorInfoW')]
function _GetMonitorInfoW(hMonitor: HMONITOR; var lpMonitorInfo: TMonitorInfoW): Boolean; external;
[DllImport(sUser32, CharSet = CharSet.Ansi, SetLastError = True, EntryPoint = 'EnumDisplayMonitors')]
function _EnumDisplayMonitors(hdc: HDC; const lprcIntersect: TRect;
  lpfnEnumProc: TMonitorEnumProc; lData: LPARAM): Boolean; overload; external;
[DllImport(sUser32, CharSet = CharSet.Ansi, SetLastError = True, EntryPoint = 'EnumDisplayMonitors')]
function _EnumDisplayMonitors(hdc: HDC; lprcIntersect: IntPtr;
  lpfnEnumProc: TMonitorEnumProc; lData: LPARAM): Boolean; overload; external;


function GetSystemMetrics(nIndex: Integer): Integer;
begin
  if MMAvailable then
    Result := _GetSystemMetrics(nIndex)
  else
  begin
    Result := -1;
    case nIndex of
      SM_CMONITORS,
      SM_SAMEDISPLAYFORMAT:
        Result := 1;
      SM_XVIRTUALSCREEN,
      SM_YVIRTUALSCREEN:
        Result := 0;
      SM_CXVIRTUALSCREEN:
        nIndex := SM_CXSCREEN;
      SM_CYVIRTUALSCREEN:
        nIndex := SM_CYSCREEN;
    end;
    if Result = -1 then
      Result := Windows.GetSystemMetrics(nIndex);
  end;
end;

function MonitorFromRect(const lprcScreenCoords: TRect; dwFlags: DWORD): HMONITOR;
begin
  if MMAvailable then
    Result := _MonitorFromRect(lprcScreenCoords, dwFlags)
  else
  begin
    Result := 0;
    if Boolean(dwFlags and (MONITOR_DEFAULTTOPRIMARY or MONITOR_DEFAULTTONEAREST)) or
      (lprcScreenCoords.Right > 0) and
      (lprcScreenCoords.Bottom > 0) and
      (lprcScreenCoords.Left < GetSystemMetrics(SM_CXSCREEN)) and
      (lprcScreenCoords.Top < GetSystemMetrics(SM_CYSCREEN)) then
        Result := xPRIMARY_MONITOR;
  end;
end;

function MonitorFromWindow(hWnd: HWND; dwFlags: DWORD): HMONITOR;
var
  wp: TWindowPlacement;
begin
  if MMAvailable then
    Result := _MonitorFromWindow(hWnd, dwFlags)
  else
  begin
    if Boolean(dwFlags and (MONITOR_DEFAULTTOPRIMARY or MONITOR_DEFAULTTONEAREST)) then
      Result := xPRIMARY_MONITOR
    else
    begin
      if IsIconic(hWnd) then
        GetWindowPlacement(hWnd, wp)
      else
        GetWindowRect(hWnd, wp.rcNormalPosition);
      Result := MonitorFromRect(wp.rcNormalPosition, dwFlags);
    end;
  end;
end;

function MonitorFromPoint(ptScreenCoords: TPoint; dwFlags: DWORD): HMONITOR;
begin
  if MMAvailable then
    Result := _MonitorFromPoint(ptScreenCoords, dwFlags)
  else
  begin
    Result := 0;
    if Boolean(dwFlags and (MONITOR_DEFAULTTOPRIMARY or MONITOR_DEFAULTTONEAREST)) or
      (ptScreenCoords.X >= 0) and
      (ptScreenCoords.X < GetSystemMetrics(SM_CXSCREEN)) and
      (ptScreenCoords.Y >= 0 ) and
      (ptScreenCoords.Y < GetSystemMetrics(SM_CYSCREEN)) then
        Result := xPRIMARY_MONITOR;
  end;
end;

function GetMonitorInfo(hMonitor: HMONITOR; var lpMonitorInfo: TMonitorInfo): Boolean;
var
  rcWork: TRect;
begin
  if MMAvailable then
    Result := _GetMonitorInfo(hMonitor, lpMonitorInfo)
  else
  begin
    Result := False;
    if (hMonitor = xPRIMARY_MONITOR) and
      (lpMonitorInfo.cbSize >= DWORD(SizeOf(TMonitorInfo))) and
      SystemParametersInfo (SPI_GETWORKAREA, 0, rcWork, 0) then
      begin
        lpMonitorInfo.rcMonitor.Left := 0;
        lpMonitorInfo.rcMonitor.Top := 0;
        lpMonitorInfo.rcMonitor.Right := GetSystemMetrics(SM_CXSCREEN);
        lpMonitorInfo.rcMonitor.Bottom := GetSystemMetrics(SM_CYSCREEN);
        lpMonitorInfo.rcWork := rcWork;
        lpMonitorInfo.dwFlags := MONITORINFOF_PRIMARY;
        Result := True;
      end;
  end;
end;

function GetMonitorInfo(hMonitor: HMONITOR; var lpMonitorInfo: TMonitorInfoEx): Boolean;
var
  rcWork: TRect;
begin
  if MMAvailable then
    Result := _GetMonitorInfo(hMonitor, lpMonitorInfo)
  else
  begin
    Result := False;
    if (hMonitor = xPRIMARY_MONITOR) and
      (lpMonitorInfo.cbSize >= DWORD(SizeOf(TMonitorInfo))) and
      SystemParametersInfo(SPI_GETWORKAREA, 0, rcWork, 0) then
      begin
        lpMonitorInfo.rcMonitor.Left := 0;
        lpMonitorInfo.rcMonitor.Top := 0;
        lpMonitorInfo.rcMonitor.Right := GetSystemMetrics(SM_CXSCREEN);
        lpMonitorInfo.rcMonitor.Bottom := GetSystemMetrics(SM_CYSCREEN);
        lpMonitorInfo.rcWork := rcWork;
        lpMonitorInfo.dwFlags := MONITORINFOF_PRIMARY;
        lpMonitorInfo.szDevice := 'DISPLAY'; // do not localize
        Result := True;
      end;
  end;
end;

function GetMonitorInfoA(hMonitor: HMONITOR; var lpMonitorInfo: TMonitorInfoA): Boolean;
var
  rcWork: TRect;
begin
  if MMAvailable then
    Result := _GetMonitorInfoA(hMonitor, lpMonitorInfo)
  else
  begin
    Result := False;
    if (hMonitor = xPRIMARY_MONITOR) and
      (lpMonitorInfo.cbSize >= DWORD(SizeOf(TMonitorInfo))) and
      SystemParametersInfo (SPI_GETWORKAREA, 0, rcWork, 0) then
      begin
        lpMonitorInfo.rcMonitor.Left := 0;
        lpMonitorInfo.rcMonitor.Top := 0;
        lpMonitorInfo.rcMonitor.Right := GetSystemMetrics(SM_CXSCREEN);
        lpMonitorInfo.rcMonitor.Bottom := GetSystemMetrics(SM_CYSCREEN);
        lpMonitorInfo.rcWork := rcWork;
        lpMonitorInfo.dwFlags := MONITORINFOF_PRIMARY;
        Result := True;
      end;
  end;
end;

function GetMonitorInfoW(hMonitor: HMONITOR; var lpMonitorInfo: TMonitorInfoW): Boolean;
var
  rcWork: TRect;
begin
  if MMAvailable then
    Result := _GetMonitorInfoW(hMonitor, lpMonitorInfo)
  else
  begin
    Result := False;
    if (hMonitor = xPRIMARY_MONITOR) and
      (lpMonitorInfo.cbSize >= DWORD(SizeOf(TMonitorInfo))) and
      SystemParametersInfo(SPI_GETWORKAREA, 0, rcWork, 0) then
      begin
        lpMonitorInfo.rcMonitor.Left := 0;
        lpMonitorInfo.rcMonitor.Top := 0;
        lpMonitorInfo.rcMonitor.Right := GetSystemMetrics(SM_CXSCREEN);
        lpMonitorInfo.rcMonitor.Bottom := GetSystemMetrics(SM_CYSCREEN);
        lpMonitorInfo.rcWork := rcWork;
        lpMonitorInfo.dwFlags := MONITORINFOF_PRIMARY;
        Result := True;
      end;
  end;
end;

function EnumDisplayMonitors(hdc: HDC; const lprcIntersect: TRect;
  lpfnEnumProc: TMonitorEnumProc; lData: LPARAM): Boolean;
var
  rcLimit, rcClip: TRect;
  ptOrg: TPoint;
  ClipBox: Integer;
begin
  if MMAvailable then
    Result := _EnumDisplayMonitors(hdc, lprcIntersect, lpfnEnumProc, lData)
  else
  begin
    Result := False;
    if not Assigned(lpfnEnumProc) then Exit;

    rcLimit.Left := 0;
    rcLimit.Top := 0;
    rcLimit.Right := GetSystemMetrics(SM_CXSCREEN);
    rcLimit.Bottom := GetSystemMetrics(SM_CYSCREEN);

    if hdc <> 0 then
    begin
      ClipBox := GetClipBox(hdc, rcClip);
      if not GetDCOrgEx(hdc, ptOrg) then Exit;
      OffsetRect(rcLimit, -ptOrg.x, -ptOrg.y);
      if not (IntersectRect(rcLimit, rcLimit, rcClip) or
        IntersectRect(rcLimit, rcLimit, lprcIntersect)) then
        begin
          if ClipBox = NULLREGION then Result := True;
          Exit;
        end;
     end else
       if not IntersectRect(rcLimit, rcLimit, lprcIntersect) then
       begin
         Result := True;
         Exit;
       end;
     Result := lpfnEnumProc(xPRIMARY_MONITOR, hdc, rcLimit, lData);
  end;
end;

function EnumDisplayMonitors(hdc: HDC; lprcIntersect: IntPtr;
  lpfnEnumProc: TMonitorEnumProc; lData: LPARAM): Boolean;
var
  rcLimit, rcClip: TRect;
  ptOrg: TPoint;
  ClipBox: Integer;
begin
  if MMAvailable then
    Result := _EnumDisplayMonitors(hdc, lprcIntersect, lpfnEnumProc, lData)
  else
  begin
    Result := False;
    if not Assigned(lpfnEnumProc) then Exit;

    rcLimit.Left := 0;
    rcLimit.Top := 0;
    rcLimit.Right := GetSystemMetrics(SM_CXSCREEN);
    rcLimit.Bottom := GetSystemMetrics(SM_CYSCREEN);

    if hdc<> 0 then
    begin
      ClipBox := GetClipBox(hdc, rcClip);
      if not GetDCOrgEx(hdc, ptOrg) then Exit;
      OffsetRect(rcLimit, -ptOrg.x, -ptOrg.y);
      if not (IntersectRect(rcLimit, rcLimit, rcClip) and
        (lprcIntersect= nil) or
        IntersectRect(rcLimit, rcLimit, lprcIntersect)) then
        begin
          if ClipBox = NULLREGION then Result := True;
          Exit;
        end;
     end else
       if (lprcIntersect <> nil) and
         (not IntersectRect(rcLimit, rcLimit, lprcIntersect)) then
         begin
           Result := True;
           Exit;
         end;
     Result := lpfnEnumProc(xPRIMARY_MONITOR, hdc, rcLimit, lData);
  end;
end;

procedure InitMultiMonStubs;
begin
  User32Dll := GetModuleHandle(sUser32);
  MMAvailable := GetProcAddress(User32DLL, 'MonitorFromWindow') <> nil; // do not localize
end;

initialization
  InitMultiMonStubs;
end.
