Alaska Software Inc. - Re: Desktopsize of current monitor (dual monitor)
Username: Password:
AuthorTopic: Re: Desktopsize of current monitor (dual monitor)
Jack DuijfDesktopsize of current monitor (dual monitor)
on Thu, 06 Sep 2018 19:32:44 +0200
Hello,

I have 3 screens accatched to my windows-10 computer
Screen 1 = 1920 x 1200
Screen 2 = 1920 x 1080
Screen 3 = 1024 x 768   (for example) 

AppDeskTop():CurrentSize()  always returns the resolution of the desktop (first screen, 1920 x 1200)  
My appliaction runs on the 3nd screen.
How can i find the screen resolution of the active screen where my Xbase++ application is running?

Regards
Jack Duijf

-------------------------------------------------------------
Also a member off the XXP (http://www.xxp.nl)
Osvaldo RamirezRe: Desktopsize of current monitor (dual monitor)
on Thu, 06 Sep 2018 15:25:50 -0600
Please visit Pablo's Forums

section /examples/MonitorInfo messsage

Best Regards



proc main()
local aMonitors,nMonitors,n
local nKey := 0

while nKey != 27
    CLS
    aMonitors := GetMonitorInfoArray()
    nMonitors := Len(aMonitors)
    for n := 1 to nMonitors
       ? cPrintf( "[Monitor#: %i] l:%4.4i t:%4.4i r:%4.4i b:%4.4i [%s] 
%s" ,;
                  n,;
                  aMonitors[n]:rcWork:left    ,;
                  aMonitors[n]:rcWork:top     ,;
                  aMonitors[n]:rcWork:right   ,;
                  aMonitors[n]:rcWork:bottom  ,;
                  aMonitors[n]:szDevice       ,;
                  iif( lAnd(aMonitors[n]:dwFlags,1) , "PRIMARY","") ;
                )
    next
    ? cPrintf( "Press [1 - %i] to select the monitor. Esc to 
close",nMonitors)
    nKey := inkey(0)
    if( (nKey > 48) .and. (nKey <= (48 + nMonitors) )  )
       CenterWindowInRect( SetAppWindow():GetHWnd() , aMonitors[nKey - 
48]:rcWork )
    end
end
return
On 9/6/2018 11:32 AM, Jack Duijf wrote:

> 
> Hello,
> 
> I have 3 screens accatched to my windows-10 computer
> Screen 1 = 1920 x 1200
> Screen 2 = 1920 x 1080
> Screen 3 = 1024 x 768   (for example)
> 
> AppDeskTop():CurrentSize()  always returns the resolution of the desktop (first screen, 1920 x 1200)
> My appliaction runs on the 3nd screen.
> How can i find the screen resolution of the active screen where my Xbase++ application is running?
> 
> Regards
> Jack Duijf
> 
> -------------------------------------------------------------
> Also a member off the XXP (http://www.xxp.nl)
>
Andreas Gehrs-Pahl
Re: Desktopsize of current monitor (dual monitor)
on Fri, 07 Sep 2018 09:21:27 -0400
Jack

>How can i find the screen resolution of the active screen where my Xbase++ 
>application is running?

You can use the following Xbase++ routines, which are based on Windows API 
functions. Some of the longer lines will wrap!

Those functions will give you the virtual resolution -- the real resolution 
adjusted by the applied virtual scaling factor, such as 100%, 125%, 150%, 
200%, etc. -- for any monitor, but the actual (real) resolution as well as 
the implied scaling factor is only available for the primary monitor.

*****************************************
* SM Constants for "GetSystemMetrics()" *
*****************************************
#define SM_CYCAPTION              4
#define SM_CYMENU                15
#define SM_CXFULLSCREEN          16
#define SM_CYFULLSCREEN          17
#define SM_CXMAXIMIZED           61    Win40 and higher
#define SM_CYMAXIMIZED           62    Win40 and higher
#define SM_CMONITORS	         80    Win50 and higher

**********************************************************************
* Monitor Selection Fallback Constants for "MonitorFromWindow", etc. *
**********************************************************************
#define MONITOR_DEFAULTTONULL     0    Returns NULL
#define MONITOR_DEFAULTTOPRIMARY  1    Returns a handle to the Primary display monitor
#define MONITOR_DEFAULTTONEAREST  2    Returns a handle to the display monitor that is Nearest to the window

********************************************
* GDI Constants for "GetDeviceCaps()" etc. *
********************************************
#define HORZRES              0x0008    (  8) Horizontal width in pixels
#define VERTRES              0x000A    ( 10) Vertical width in pixels
#define LOGPIXELSX           0x0058    ( 88) Logical pixels/inch in X
#define LOGPIXELSY           0x005A    ( 90) Logical pixels/inch in Y
#define DESKTOPVERTRES       0x0075    (117) Vertical height  of entire desktop in pixels (only WinNT)
#define DESKTOPHORZRES       0x0076    (118) Horizontal width of entire desktop in pixels (only WinNT)

***********************************************
* SPI Constants for "SystemParametersInfoA()" *
***********************************************
#define SPI_SETWORKAREA          47    Set (Primary) WorkArea Size and Position
#define SPI_GETWORKAREA          48    Get (Primary) WorkArea Size and Position

********************************************
* SPIF Flags for "SystemParametersInfoA()" *
********************************************
#define SPIF_SENDCHANGE           2

#include "DLL.ch"

Function Get_Display_Count()
return (DllCall('User32.dll', DLL_STDCALL, 'GetSystemMetrics', SM_CMONITORS))

Function Get_Primary_Monitor()
return (DllCall('User32.dll', DLL_STDCALL, 'MonitorFromWindow', AppDesktop():GetHWnd(), MONITOR_DEFAULTTOPRIMARY))

Function Get_Active_Monitor(oDialog)
LOCAL nHWnd := iif(oDialog == NIL, iif(GetApplication():MainForm == NIL, AppDesktop():GetHWnd(), GetApplication():MainForm:GetHWnd()), oDialog:GetHWnd())
return (DllCall('User32.dll', DLL_STDCALL, 'MonitorFromWindow', nHWnd, MONITOR_DEFAULTTONEAREST))

Function Get_Monitor_Info(oDialog, lWorkArea)
LOCAL cBuffer  := U2Bin(40) + Space(36)
LOCAL lMonitor := iif(lWorkArea == NIL, .t., .not. lWorkArea)
LOCAL nMonitor := Get_Active_Monitor(oDialog)
LOCAL nLeft    := 0
LOCAL nTop     := 0
LOCAL nRight   := 0
LOCAL nBottom  := 0
LOCAL aPos     := {0, 0}
LOCAL aSize    := {0, 0}
   DllCall('User32.dll', DLL_STDCALL, 'GetMonitorInfo', nMonitor, @cBuffer)
   nLeft    := Bin2L(substr(cBuffer,  5, 4))
   nTop     := Bin2L(substr(cBuffer,  9, 4))
   nRight   := Bin2L(substr(cBuffer, 13, 4))
   nBottom  := Bin2L(substr(cBuffer, 17, 4))
   aSize[1] := nRight  - nLeft
   aSize[2] := nBottom - nTop
   if .not. lMonitor
      nLeft    := Bin2L(substr(cBuffer, 21, 4))
      nTop     := Bin2L(substr(cBuffer, 25, 4))
      nRight   := Bin2L(substr(cBuffer, 29, 4))
      nBottom  := Bin2L(substr(cBuffer, 33, 4))
      aPos[1]  := nLeft
      aPos[2]  := aSize[2] - (nBottom - nTop)
      aSize[1] := nRight   - nLeft
      aSize[2] := nBottom  - nTop
   endif
return ({aPos, aSize})

Function Get_DeskTop_Size(lReal)
LOCAL lVirtual := iif(lReal   == NIL, .t., .not. lReal)
LOCAL nHWnd    := AppDesktop():GetHWnd()
LOCAL nHDC     := DllCall('User32.dll', DLL_STDCALL, 'GetDC', nHWnd)
LOCAL nWidth   := 0
LOCAL nHeight  := 0
   if nHDC # 0
      nWidth  := DllCall('GDI32.dll', DLL_STDCALL, 'GetDeviceCaps', nHDC, iif(lVirtual, HORZRES, DESKTOPHORZRES))
      nHeight := DllCall('GDI32.dll', DLL_STDCALL, 'GetDeviceCaps', nHDC, iif(lVirtual, VERTRES, DESKTOPVERTRES))
      DllCall('User32.dll', DLL_STDCALL, 'ReleaseDC', nHWnd, nHDC)
   endif
return ({nWidth, nHeight})

Function Get_Maximized_Window_Size()
LOCAL nWidth  := DllCall('User32.dll', DLL_STDCALL, 'GetSystemMetrics', SM_CXMAXIMIZED)
LOCAL nHeight := DllCall('User32.dll', DLL_STDCALL, 'GetSystemMetrics', SM_CYMAXIMIZED)
return ({nWidth, nHeight})

Function Get_Full_Screen_Window_Size()
LOCAL nWidth  := DllCall('User32.dll', DLL_STDCALL, 'GetSystemMetrics', SM_CXFULLSCREEN)
LOCAL nHeight := DllCall('User32.dll', DLL_STDCALL, 'GetSystemMetrics', SM_CYFULLSCREEN)
return ({nWidth, nHeight})

Function Get_Frame_Height()
LOCAL nHeight   := DllCall('User32.dll', DLL_STDCALL, 'GetSystemMetrics', SM_CYMAXIMIZED)
return (nHeight -= DllCall('User32.dll', DLL_STDCALL, 'GetSystemMetrics', SM_CYFULLSCREEN))

Function Get_Frame_Width()
LOCAL nWidth   := DllCall('User32.dll', DLL_STDCALL, 'GetSystemMetrics', SM_CXMAXIMIZED)
return (nWidth -= DllCall('User32.dll', DLL_STDCALL, 'GetSystemMetrics', SM_CXFULLSCREEN))

Function Get_TitleBar_Height()
return (DllCall('User32.dll', DLL_STDCALL, 'GetSystemMetrics', SM_CYCAPTION))

Function Get_Menu_Height()
return (DllCall('User32.dll', DLL_STDCALL, 'GetSystemMetrics', SM_CYMENU))

Function Get_Menu_Only_Height()
return (Get_Frame_Height() + Get_Menu_Height())

Function Windows_Work_Area(aArea)
**************************************************************************
* If "aArea" is supplied, the Windows WorkArea is set to the new area,   
 as if the left-out area is occupied by Taskbar(s) or other things, but 
 no TaskBar(s) is (are) moved. After setting the Windows WorkArea, all  
 Applications recognize this area for functions such as maximizing a    
 Window. The Parameter "aArea" must be NIL or an Array of the following 
 format: "aArea" ==> {"nLeftPos", "nTopPos", "nRightPos", "nBottomPos"} 
 defining the new Workarea in Windows (Pixel) coordinates (Left and Top 
 are both "0", while in Xbase Left and Bottom are "0")!!!               *
**************************************************************************
* The current Windows WorkArea (not occupied by Taskbar(s)) is returned  
 as a two-dimensional Array {"aPos", "aSize"}, of the following format: 
 "aPos"  ==> an Array in Xbase coordinates {"nLeft", "nBottom"}, and    
 "aSize" ==> an Array of two numbers of Pixels {"nWidth", "nHeight"}.   *
**************************************************************************
LOCAL nSetOrGet := iif(aArea == NIL, SPI_GETWORKAREA, SPI_SETWORKAREA)
LOCAL nSetFlag  := iif(aArea == NIL, 0, SPIF_SENDCHANGE)
LOCAL nLeft     := iif(aArea == NIL, 0, aArea[1])
LOCAL nTop      := iif(aArea == NIL, 0, aArea[2])
LOCAL nRight    := iif(aArea == NIL, 0, aArea[3])
LOCAL nBottom   := iif(aArea == NIL, 0, aArea[4])
LOCAL cBuffer   := iif(aArea == NIL, Space(16), U2Bin(nLeft) + U2Bin(nTop) + U2Bin(nRight) + U2Bin(nBottom))
LOCAL aPos      := {0, 0}
LOCAL aSize     := Get_DeskTop_Size()
   DllCall('User32.dll', DLL_STDCALL, 'SystemParametersInfoA', nSetOrGet, 0, @cBuffer, nSetFlag)
   nLeft    := Bin2U(substr(cBuffer,  1, 4))
   nTop     := Bin2U(substr(cBuffer,  5, 4))
   nRight   := Bin2U(substr(cBuffer,  9, 4))
   nBottom  := Bin2U(substr(cBuffer, 13, 4))
   aPos[1]  := nLeft
   aPos[2]  := aSize[2] - nBottom
   aSize[1] := nRight   - nLeft
   aSize[2] := nBottom  - nTop
return ({aPos, aSize})

Function Get_Windows_Fonts_DPI(lWidth)
LOCAL lHeight := iif(lWidth == NIL, .t., .not. lWidth)
LOCAL nHeight := iif(lHeight, LOGPIXELSY, LOGPIXELSX)
LOCAL nHWnd   := AppDesktop():GetHWnd()
LOCAL nHDC    := DllCall('User32.dll', DLL_STDCALL, 'GetDC', nHWnd)
LOCAL nLogPix := 96			 default for Small Fonts
   if nHDC # 0
      nLogPix := DllCall('GDI32.dll', DLL_STDCALL, 'GetDeviceCaps', nHDC, nHeight)
      DllCall('User32.dll', DLL_STDCALL, 'ReleaseDC', nHWnd, nHDC)
   endif
return (nLogPix)

And here is some sample code to show how to use (some of) those functions:

Procedure Display_Dialog_Dimensions(oDialog)
LOCAL nMonitors    := Get_Display_Count()
LOCAL nPrimary     := Get_Primary_Monitor()
LOCAL nCurrent     := Get_Active_Monitor(oDialog)
LOCAL nDPI_Setting := Get_Windows_Fonts_DPI()
LOCAL lPrimary     := nMonitors == 1 .or. (nCurrent == nPrimary)
LOCAL aDeskTopSize := iif(lPrimary, Get_DeskTop_Size(.t.), Get_Monitor_Info(oDialog, .f.)[2])
LOCAL aVirtualSize := iif(lPrimary, Get_DeskTop_Size(.f.), Get_Monitor_Info(oDialog, .f.)[2])
LOCAL aWinWorkArea := iif(lPrimary, Windows_Work_Area(),   Get_Monitor_Info(oDialog, .t.))
LOCAL aDialogPos   := oDialog:CurrentPos()
LOCAL aDialogSize  := oDialog:CurrentSize()
LOCAL aDrawingArea := oDialog:DrawingArea:CurrentSize()
LOCAL nScaleFactor := Round(100 * iif(nDPI_Setting == 96, aDeskTopSize[1] / aVirtualSize[1], nDPI_Setting / 96), 0)
LOCAL lOnLeft      := (oDialog:CurrentPos()[1] < 0 .and. abs(oDialog:CurrentPos()[1]) > oDialog:CurrentSize()[1])
LOCAL cMonitor     := iif(nMonitors == 1, 'Single', iif(lPrimary, '(Primary) ', '') + iif(lOnLeft, 'Left', 'Right')) + ' Monitor'
   QOut('Virtual Desktop Size: ' + Var2Char(aVirtualSize))
   QOut('Active Monitor is: '    + cMonitor)
   QOut('Real Desktop Size: '    + iif(lPrimary, Var2Char(aDeskTopSize), '(Unknown)'))
   QOut('Desktop Scaling: '      + iif(lPrimary, Var2Char(nScaleFactor) + '%', '(Unknown)'))
   QOut('Work Area Position: '   + Var2Char(aWinWorkArea[1]) + iif(lPrimary, '', ' (assumed)'))
   QOut('Work Area Size: '       + Var2Char(aWinWorkArea[2]))
   QOut('Dialog Position: '      + Var2Char(aDialogPos))
   QOut('Dialog Size: '          + Var2Char(aDialogSize))
   QOut('Drawing Area Size: '    + Var2Char(aDrawingArea))
   QOut('Title Bar Height: '     + Var2Char(Get_TitleBar_Height()))
   QOut('Menu Height: '          + Var2Char(Get_Menu_Height()))
   QOut('Windows Font DPI: '     + Var2Char(nDPI_Setting) + ' DPI')
return

Hope that helps,

Andreas

Andreas Gehrs-Pahl
Absolute Software, LLC

phone: (989) 723-9927
email: Andreas@AbsoluteSoftwareLLC.com
web:   http://www.AbsoluteSoftwareLLC.com
[F]:   https://www.facebook.com/AbsoluteSoftwareLLC
Jonathan LeemingRe: Desktopsize of current monitor (dual monitor)
on Wed, 12 Sep 2018 20:30:09 -0600
On 9/7/2018 7:21 AM, Andreas Gehrs-Pahl wrote:
> Jack
> 
>> How can i find the screen resolution of the active screen where my Xbase++
>> application is running?
> 
> You can use the following Xbase++ routines, which are based on Windows API
> functions. Some of the longer lines will wrap!
> 
> Those functions will give you the virtual resolution -- the real resolution
> adjusted by the applied virtual scaling factor, such as 100%, 125%, 150%,
> 200%, etc. -- for any monitor, but the actual (real) resolution as well as
> the implied scaling factor is only available for the primary monitor.
> 
> *****************************************
> * SM Constants for "GetSystemMetrics()" *
> *****************************************
> #define SM_CYCAPTION              4
> #define SM_CYMENU                15
> #define SM_CXFULLSCREEN          16
> #define SM_CYFULLSCREEN          17
> #define SM_CXMAXIMIZED           61    Win40 and higher
> #define SM_CYMAXIMIZED           62    Win40 and higher
> #define SM_CMONITORS	         80    Win50 and higher
> 
> **********************************************************************
> * Monitor Selection Fallback Constants for "MonitorFromWindow", etc. *
> **********************************************************************
> #define MONITOR_DEFAULTTONULL     0    Returns NULL
> #define MONITOR_DEFAULTTOPRIMARY  1    Returns a handle to the Primary display monitor
> #define MONITOR_DEFAULTTONEAREST  2    Returns a handle to the display monitor that is Nearest to the window
> 
> ********************************************
> * GDI Constants for "GetDeviceCaps()" etc. *
> ********************************************
> #define HORZRES              0x0008    (  8) Horizontal width in pixels
> #define VERTRES              0x000A    ( 10) Vertical width in pixels
> #define LOGPIXELSX           0x0058    ( 88) Logical pixels/inch in X
> #define LOGPIXELSY           0x005A    ( 90) Logical pixels/inch in Y
> #define DESKTOPVERTRES       0x0075    (117) Vertical height  of entire desktop in pixels (only WinNT)
> #define DESKTOPHORZRES       0x0076    (118) Horizontal width of entire desktop in pixels (only WinNT)
> 
> ***********************************************
> * SPI Constants for "SystemParametersInfoA()" *
> ***********************************************
> #define SPI_SETWORKAREA          47    Set (Primary) WorkArea Size and Position
> #define SPI_GETWORKAREA          48    Get (Primary) WorkArea Size and Position
> 
> ********************************************
> * SPIF Flags for "SystemParametersInfoA()" *
> ********************************************
> #define SPIF_SENDCHANGE           2
> 
> #include "DLL.ch"
> 
> Function Get_Display_Count()
> return (DllCall('User32.dll', DLL_STDCALL, 'GetSystemMetrics', SM_CMONITORS))
> 
> Function Get_Primary_Monitor()
> return (DllCall('User32.dll', DLL_STDCALL, 'MonitorFromWindow', AppDesktop():GetHWnd(), MONITOR_DEFAULTTOPRIMARY))
> 
> Function Get_Active_Monitor(oDialog)
> LOCAL nHWnd := iif(oDialog == NIL, iif(GetApplication():MainForm == NIL, AppDesktop():GetHWnd(), GetApplication():MainForm:GetHWnd()), oDialog:GetHWnd())
> return (DllCall('User32.dll', DLL_STDCALL, 'MonitorFromWindow', nHWnd, MONITOR_DEFAULTTONEAREST))
> 
> Function Get_Monitor_Info(oDialog, lWorkArea)
> LOCAL cBuffer  := U2Bin(40) + Space(36)
> LOCAL lMonitor := iif(lWorkArea == NIL, .t., .not. lWorkArea)
> LOCAL nMonitor := Get_Active_Monitor(oDialog)
> LOCAL nLeft    := 0
> LOCAL nTop     := 0
> LOCAL nRight   := 0
> LOCAL nBottom  := 0
> LOCAL aPos     := {0, 0}
> LOCAL aSize    := {0, 0}
>     DllCall('User32.dll', DLL_STDCALL, 'GetMonitorInfo', nMonitor, @cBuffer)
>     nLeft    := Bin2L(substr(cBuffer,  5, 4))
>     nTop     := Bin2L(substr(cBuffer,  9, 4))
>     nRight   := Bin2L(substr(cBuffer, 13, 4))
>     nBottom  := Bin2L(substr(cBuffer, 17, 4))
>     aSize[1] := nRight  - nLeft
>     aSize[2] := nBottom - nTop
>     if .not. lMonitor
>        nLeft    := Bin2L(substr(cBuffer, 21, 4))
>        nTop     := Bin2L(substr(cBuffer, 25, 4))
>        nRight   := Bin2L(substr(cBuffer, 29, 4))
>        nBottom  := Bin2L(substr(cBuffer, 33, 4))
>        aPos[1]  := nLeft
>        aPos[2]  := aSize[2] - (nBottom - nTop)
>        aSize[1] := nRight   - nLeft
>        aSize[2] := nBottom  - nTop
>     endif
> return ({aPos, aSize})
> 
> Function Get_DeskTop_Size(lReal)
> LOCAL lVirtual := iif(lReal   == NIL, .t., .not. lReal)
> LOCAL nHWnd    := AppDesktop():GetHWnd()
> LOCAL nHDC     := DllCall('User32.dll', DLL_STDCALL, 'GetDC', nHWnd)
> LOCAL nWidth   := 0
> LOCAL nHeight  := 0
>     if nHDC # 0
>        nWidth  := DllCall('GDI32.dll', DLL_STDCALL, 'GetDeviceCaps', nHDC, iif(lVirtual, HORZRES, DESKTOPHORZRES))
>        nHeight := DllCall('GDI32.dll', DLL_STDCALL, 'GetDeviceCaps', nHDC, iif(lVirtual, VERTRES, DESKTOPVERTRES))
>        DllCall('User32.dll', DLL_STDCALL, 'ReleaseDC', nHWnd, nHDC)
>     endif
> return ({nWidth, nHeight})
> 
> Function Get_Maximized_Window_Size()
> LOCAL nWidth  := DllCall('User32.dll', DLL_STDCALL, 'GetSystemMetrics', SM_CXMAXIMIZED)
> LOCAL nHeight := DllCall('User32.dll', DLL_STDCALL, 'GetSystemMetrics', SM_CYMAXIMIZED)
> return ({nWidth, nHeight})
> 
> Function Get_Full_Screen_Window_Size()
> LOCAL nWidth  := DllCall('User32.dll', DLL_STDCALL, 'GetSystemMetrics', SM_CXFULLSCREEN)
> LOCAL nHeight := DllCall('User32.dll', DLL_STDCALL, 'GetSystemMetrics', SM_CYFULLSCREEN)
> return ({nWidth, nHeight})
> 
> Function Get_Frame_Height()
> LOCAL nHeight   := DllCall('User32.dll', DLL_STDCALL, 'GetSystemMetrics', SM_CYMAXIMIZED)
> return (nHeight -= DllCall('User32.dll', DLL_STDCALL, 'GetSystemMetrics', SM_CYFULLSCREEN))
> 
> Function Get_Frame_Width()
> LOCAL nWidth   := DllCall('User32.dll', DLL_STDCALL, 'GetSystemMetrics', SM_CXMAXIMIZED)
> return (nWidth -= DllCall('User32.dll', DLL_STDCALL, 'GetSystemMetrics', SM_CXFULLSCREEN))
> 
> Function Get_TitleBar_Height()
> return (DllCall('User32.dll', DLL_STDCALL, 'GetSystemMetrics', SM_CYCAPTION))
> 
> Function Get_Menu_Height()
> return (DllCall('User32.dll', DLL_STDCALL, 'GetSystemMetrics', SM_CYMENU))
> 
> Function Get_Menu_Only_Height()
> return (Get_Frame_Height() + Get_Menu_Height())
> 
> Function Windows_Work_Area(aArea)
> **************************************************************************
> * If "aArea" is supplied, the Windows WorkArea is set to the new area,   *
> * as if the left-out area is occupied by Taskbar(s) or other things, but *
> * no TaskBar(s) is (are) moved. After setting the Windows WorkArea, all  *
>  Applications recognize this area for functions such as maximizing a    
> * Window. The Parameter "aArea" must be NIL or an Array of the following *
> * format: "aArea" ==> {"nLeftPos", "nTopPos", "nRightPos", "nBottomPos"} *
> * defining the new Workarea in Windows (Pixel) coordinates (Left and Top *
> * are both "0", while in Xbase Left and Bottom are "0")!!!               *
> **************************************************************************
> * The current Windows WorkArea (not occupied by Taskbar(s)) is returned  *
> * as a two-dimensional Array {"aPos", "aSize"}, of the following format: *
> * "aPos"  ==> an Array in Xbase coordinates {"nLeft", "nBottom"}, and    *
> * "aSize" ==> an Array of two numbers of Pixels {"nWidth", "nHeight"}.   *
> **************************************************************************
> LOCAL nSetOrGet := iif(aArea == NIL, SPI_GETWORKAREA, SPI_SETWORKAREA)
> LOCAL nSetFlag  := iif(aArea == NIL, 0, SPIF_SENDCHANGE)
> LOCAL nLeft     := iif(aArea == NIL, 0, aArea[1])
> LOCAL nTop      := iif(aArea == NIL, 0, aArea[2])
> LOCAL nRight    := iif(aArea == NIL, 0, aArea[3])
> LOCAL nBottom   := iif(aArea == NIL, 0, aArea[4])
> LOCAL cBuffer   := iif(aArea == NIL, Space(16), U2Bin(nLeft) + U2Bin(nTop) + U2Bin(nRight) + U2Bin(nBottom))
> LOCAL aPos      := {0, 0}
> LOCAL aSize     := Get_DeskTop_Size()
>     DllCall('User32.dll', DLL_STDCALL, 'SystemParametersInfoA', nSetOrGet, 0, @cBuffer, nSetFlag)
>     nLeft    := Bin2U(substr(cBuffer,  1, 4))
>     nTop     := Bin2U(substr(cBuffer,  5, 4))
>     nRight   := Bin2U(substr(cBuffer,  9, 4))
>     nBottom  := Bin2U(substr(cBuffer, 13, 4))
>     aPos[1]  := nLeft
>     aPos[2]  := aSize[2] - nBottom
>     aSize[1] := nRight   - nLeft
>     aSize[2] := nBottom  - nTop
> return ({aPos, aSize})
> 
> Function Get_Windows_Fonts_DPI(lWidth)
> LOCAL lHeight := iif(lWidth == NIL, .t., .not. lWidth)
> LOCAL nHeight := iif(lHeight, LOGPIXELSY, LOGPIXELSX)
> LOCAL nHWnd   := AppDesktop():GetHWnd()
> LOCAL nHDC    := DllCall('User32.dll', DLL_STDCALL, 'GetDC', nHWnd)
> LOCAL nLogPix := 96			 default for Small Fonts
>     if nHDC # 0
>        nLogPix := DllCall('GDI32.dll', DLL_STDCALL, 'GetDeviceCaps', nHDC, nHeight)
>        DllCall('User32.dll', DLL_STDCALL, 'ReleaseDC', nHWnd, nHDC)
>     endif
> return (nLogPix)
> 
> And here is some sample code to show how to use (some of) those functions:
> 
> Procedure Display_Dialog_Dimensions(oDialog)
> LOCAL nMonitors    := Get_Display_Count()
> LOCAL nPrimary     := Get_Primary_Monitor()
> LOCAL nCurrent     := Get_Active_Monitor(oDialog)
> LOCAL nDPI_Setting := Get_Windows_Fonts_DPI()
> LOCAL lPrimary     := nMonitors == 1 .or. (nCurrent == nPrimary)
> LOCAL aDeskTopSize := iif(lPrimary, Get_DeskTop_Size(.t.), Get_Monitor_Info(oDialog, .f.)[2])
> LOCAL aVirtualSize := iif(lPrimary, Get_DeskTop_Size(.f.), Get_Monitor_Info(oDialog, .f.)[2])
> LOCAL aWinWorkArea := iif(lPrimary, Windows_Work_Area(),   Get_Monitor_Info(oDialog, .t.))
> LOCAL aDialogPos   := oDialog:CurrentPos()
> LOCAL aDialogSize  := oDialog:CurrentSize()
> LOCAL aDrawingArea := oDialog:DrawingArea:CurrentSize()
> LOCAL nScaleFactor := Round(100 * iif(nDPI_Setting == 96, aDeskTopSize[1] / aVirtualSize[1], nDPI_Setting / 96), 0)
> LOCAL lOnLeft      := (oDialog:CurrentPos()[1] < 0 .and. abs(oDialog:CurrentPos()[1]) > oDialog:CurrentSize()[1])
> LOCAL cMonitor     := iif(nMonitors == 1, 'Single', iif(lPrimary, '(Primary) ', '') + iif(lOnLeft, 'Left', 'Right')) + ' Monitor'
>     QOut('Virtual Desktop Size: ' + Var2Char(aVirtualSize))
>     QOut('Active Monitor is: '    + cMonitor)
>     QOut('Real Desktop Size: '    + iif(lPrimary, Var2Char(aDeskTopSize), '(Unknown)'))
>     QOut('Desktop Scaling: '      + iif(lPrimary, Var2Char(nScaleFactor) + '%', '(Unknown)'))
>     QOut('Work Area Position: '   + Var2Char(aWinWorkArea[1]) + iif(lPrimary, '', ' (assumed)'))
>     QOut('Work Area Size: '       + Var2Char(aWinWorkArea[2]))
>     QOut('Dialog Position: '      + Var2Char(aDialogPos))
>     QOut('Dialog Size: '          + Var2Char(aDialogSize))
>     QOut('Drawing Area Size: '    + Var2Char(aDrawingArea))
>     QOut('Title Bar Height: '     + Var2Char(Get_TitleBar_Height()))
>     QOut('Menu Height: '          + Var2Char(Get_Menu_Height()))
>     QOut('Windows Font DPI: '     + Var2Char(nDPI_Setting) + ' DPI')
> return
> 
> Hope that helps,
> 
> Andreas
> 
Thanks Andreas... Once again you have provided some great insight & 
solutions!

In theory do you know if it possible to have one's application load to 
the non-primary monitor.  I'm thinking that if a user dragged the app to 
a secondary monitor that upon closing it could save this in the registry 
and then when run again could position based on the previously saved 
setting.

This would be great for our staff but perhaps just wishful thinking.

Thanks again for sharing you solution... Regards... Jonathan
Andreas Gehrs-Pahl
Re: Desktopsize of current monitor (dual monitor)
on Fri, 14 Sep 2018 03:37:34 -0400
Jonathan,

>Thanks Andreas... Once again you have provided some great insight & 
>solutions!

You are welcome.

>In theory do you know if it possible to have one's application load to 
>the non-primary monitor. I'm thinking that if a user dragged the app to 
>a secondary monitor that upon closing it could save this in the registry 
>and then when run again could position based on the previously saved 
>setting.

Sure. I do exactly that within my framework (which I use for all of my 
applications).

The Dialog classes have built-in options to automatically (or manually) save 
(and restore) their current location (coordinates) as well as their size, 
scale/zoom factor, etc. to/from the registry (or INI, XML, JSON, binary, 
or database files). If I'm not mistaken, TopDown and Express++ might have 
similar features.

>This would be great for our staff but perhaps just wishful thinking.

Those settings can be user- or workstation-specific, depending on where you 
save the information in the registry (or wherever you decide to save it).

But make sure that you add a "Reset" option to your application, so that 
you (and a user) can get those dialogs back to the default location, in case 
they are moved outside the desktop(s), for example if monitors are (re)moved 
or their resolutions are changed, or if there is any corruption in the saved 
location data.

If you need some more specific help, feel free to contact me directly.

Andreas

Andreas Gehrs-Pahl
Absolute Software, LLC

phone: (989) 723-9927
email: Andreas@AbsoluteSoftwareLLC.com
web:   http://www.AbsoluteSoftwareLLC.com
[F]:   https://www.facebook.com/AbsoluteSoftwareLLC
Jack DuijfRe: Desktopsize of current monitor (dual monitor)
on Sat, 08 Sep 2018 17:40:44 +0200
Hello Osvaldo, Andreas,

These are very usefull functioms. 
I am redirecting gesture drag-drop events to xbeP_User + nnn 
I am strugling to convert the gesture coordinates to the correct xbp coordinate in xbpCellGroup
I need this to locate the exact cell in a browse.

These functions wil help me to fix my issues.
Thank you verry much

Regards
Jack Duijf

-------------------------------------------------------------
Also a member off the XXP (http://www.xxp.nl)