Page 2 of 2

Posted: Mon Oct 16, 2006 7:58 pm
by Rescator
Quickly changed the example so it works on PB4.x


PB 4.0 WARNING! Only works with unicode exe disabled WARNING!

Code: Select all

; purebasic survival guide
; multi_monitor_2.pb - 30.12.2003 ejn (blueznl)
; http://www.xs4all.nl/~bluez/datatalk/pure1.htm
;
; - how to detect multiple monitors and their relative position to each other
; - EndumDisplayMonitors_()
; - EnumDisplayDevices_()
; - EnumDisplaySettings_()
; - MonitorFromPoint_()
; - GetMonitorInfo_()
;
; constants / structs for multi monitor handling
;
#SM_XVIRTUALSCREEN        = 76        ; x-coordinate of left upper corner of total display area
#SM_YVIRTUALSCREEN        = 77        ; same for y
#SM_CXVIRTUALSCREEN       = 78        ; width
#SM_CYVIRTUALSCREEN       = 79        ; height
#SM_CMONITORS             = 80        ; number of monitors
#SM_SAMEDISPLAYFORMAT     = 81        ; identical sizing of all screens
;
#MONITOR_DEFAULTTONULL    = 0
#MONITOR_DEFAULTTOPRIMARY = 1
#MONITOR_DEFAULTTONEAREST = 2
;
#SM_XVIRTUALSCREEN        = 76        ; x-coordinate of left upper corner of total display area
#SM_YVIRTUALSCREEN        = 77        ; same for y
#SM_CXVIRTUALSCREEN       = 78        ; width
#SM_CYVIRTUALSCREEN       = 79        ; height
#SM_CMONITORS             = 80        ; number of monitors
#SM_SAMEDISPLAYFORMAT     = 81        ; identical sizing of all screens
;
#DISPLAY_DEVICE_ATTACHED_TO_DESKTOP = $1
#DISPLAY_DEVICE_MULTI_DRIVER        = $2
#DISPLAY_DEVICE_PRIMARY_DEVICE      = $4
#DISPLAY_DEVICE_MIRRORING_DRIVER    = $8
#DISPLAY_DEVICE_VGA_COMPATIBLE      = $10
#DISPLAY_DEVICE_REMOVABLE           = $20
#DISPLAY_DEVICE_MODESPRUNED         = $8000000
#DISPLAY_DEVICE_REMOTE              = $4000000
#DISPLAY_DEVICE_DISCONNECT          = $2000000
#DISPLAY_DEVICE_ACTIVE              = $1
#DISPLAY_DEVICE_ATTACHED            = $2
;
#CCHDEVICENAME = 32
#CCHFORMNAME = 32
;
#ENUM_CURRENT_SETTINGS = -1
#ENUM_REGISTRY_SETTINGS = -2
;
#MONITOR_DEFAULTTONULL    = 0
#MONITOR_DEFAULTTOPRIMARY = 1
#MONITOR_DEFAULTTONEAREST = 2
;
Structure MONITORINFO                     ; used to retrieve monitor info
  cb.l                                    ; size of structure (fill before using)
  m_x1.l                                  ; rectangle, monitor coords x1/y1/x2/y2
  m_y1.l
  m_x2.l
  m_y2.l
  w_x1.l                                  ; rectangle, work area coords (?)
  w_y1.l
  w_x2.l
  w_y2.l
  flags.l
EndStructure
;
Structure MONITORINFOEX                   ; superset of MONITORINFO with added  string for devicename
  cb.l 
  m_x1.l
  m_y1.l
  m_x2.l
  m_y2.l
  w_x1.l
  w_y1.l
  w_x2.l
  w_y2.l
  flags.l
  name.b[32]                              ; #CCHDEVICENAME = 32
EndStructure
;
 
Structure x_monitorinfo                   ; used to store monitor info
  n.l                                     ; sequential number
  hnd.l                                   ; handle
  x.l                                     ; x-position
  y.l                                     ; y-position
  w.l                                     ; width
  h.l                                     ; height
  d.l                                     ; colour depth (bits)
  f.l                                     ; frequency 
  name.s                                  ; devicename (i want my fixed length strings!)
  flags.l                                 ; status of the device
EndStructure
;
NewList x_monitor.x_monitorinfo()         ; info on monitors
x_desktop.x_monitorinfo                   ; info on desktop

Procedure x_monitor_monitorenumproc(WindowID, Message, WPARAM, LPARAM)
 Shared x_monitor()
  ;
  ; store on each call the monitor handle in the x_monitor() list
  ; called by windows in callback as set up in x_monitor_detect() by the api EnumDisplayMonitors_()
  ; also known as MonitorEnumProc
  ;
  AddElement(x_monitor())
  x_monitor()\hnd = WindowID
  ;
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

Procedure.l x_monitor_detect()
  Protected info.MONITORINFOEX, device.DISPLAY_DEVICE, n.l,settings.DEVMODE
  Protected x_retval.l, x_monitor_n.l
  Shared x_desktop,x_monitor()
  Protected x_monitor_samedisplayformat.l
  ;
  ; *** detect number of screens and retrieve their properties
  ;
  ; in:
  ; retval:
  ; out:    x_monitor_n.l    - number of screens
  ;         x_desktop_w.l    - desktop width
  ;         x_desktop_h.l    - desktop height
  ;
  ; GetSystemMetrics_()
  ;
  ; provides quite a bit info on display adapters, screens etc. but does not provide info
  ; per monitor / device on multi monitor setups
  ;
  ; x_monitor_n = GetSystemMetrics_(#SM_CMONITORS)
  ; x_monitor_samedisplayformat.l = GetSystemMetrics_(#SM_SAMEDISPLAYFORMAT)
  ;
  x_desktop\w = GetSystemMetrics_(#SM_CXVIRTUALSCREEN)
  x_desktop\h = GetSystemMetrics_(#SM_CYVIRTUALSCREEN)
  ;
  ; Debug "same display format on all screens (0 = no)"
  ; Debug x_monitor_samedisplayformat
  ; Debug "counted using getsystemmetrics"
  ; Debug x_monitor_n
  ;
  ; EnumDisplayMonitors()
  ;
  ; returns monitors overlapping a given rectangle, including pseudo / mirror monitors!
  ; after the call, for each monitor a handle will be stored in x_monitor()\hnd
  ; this can be used to obtain more information using GetMonitorInfo_()
  ; flags returned are different from EnumDisplayDevices()
  ;
  ; ClearList(x_monitor())
  ; EnumDisplayMonitors_(0,0,@x_monitor_monitorenumproc(),0)      ; call the function
  ; info.MONITORINFOEX                                            ; create a struct for GetMonitorInfo_()
  ; info\cb = SizeOf(info)                                        ; length of struct (important for MONITORINFO vs. MONITORINFOEX)
  ; x_monitor_n = 0                                               ; nr. of monitors 
  ; ResetList(x_monitor())                                        ; reset and...
  ; While NextElement(x_monitor())                                ; go through the list   
  ;   x_monitor_n = x_monitor_n+1
  ;   x_monitor()\n = x_monitor_n                                 ; sequential number
  ;   GetMonitorInfo_(x_monitor()\hnd,@info)                      ; get info on the monitor
  ;   x_monitor()\x = info\m_x1
  ;   x_monitor()\y = info\m_y1
  ;   x_monitor()\w = info\m_x2 - info\m_x1
  ;   x_monitor()\h = info\m_y2 - info\m_y1
  ;   x_monitor()\name = PeekS(@info\name,32)                     ; i want my fixed length strings!
  ; Wend 
  ; ;
  ; Debug "counted using enumdisplaymonitors"
  ; Debug x_monitor_n
  ;
  ; EnumDisplayDevices()
  ;
  ; walks through all available devices, retrieve names and flags
  ; by using the returned flags all 'non-real' monitors can be filtered out
  ;
                                      ; to store results from EnumDisplayDevices_()
  device\cb = SizeOf(DISPLAY_DEVICE)
                                                ; to store results from EnumDisplaySettings_()
  settings\dmSize = SizeOf(settings)                            ; DEVMODE is declared in purebasic itself
  settings\dmDriverExtra = 0
  ;
  ClearList(x_monitor())
  n.l = 0
  x_monitor_n = 0       
  While EnumDisplayDevices_(0,n,device,0) > 0      ; check all devices
    n = n+1
    ;
    ; the StateFlags field in the filled struct contains information on the device / monitor
    ; some values to check with (not all cards / drivers support all functions):
    ;
    ; #DISPLAY_DEVICE_ATTACHED_TO_DESKTOP - in use and part of the desktop
    ; #DISPLAY_DEVICE_PRIMARY_DEVICE      - primary device
    ; #DISPLAY_DEVICE_VGA_COMPATIBLE      - none reported
    ; #DISPLAY_DEVICE_MULTI_DRIVER       
    ; #DISPLAY_DEVICE_ACTIVE             
    ; #DISPLAY_DEVICE_ATTACHED           
    ;
    If (device\StateFlags & #DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) = #DISPLAY_DEVICE_ATTACHED_TO_DESKTOP     ; check if it's part of the desktop
      ;
      ; if a device is part of the desktop, additional information can be retrieved using
      ; EnumDisplaySettings_() with the device name
      ;
      If EnumDisplaySettings_(PeekS(@device\devicename,32),#ENUM_CURRENT_SETTINGS,settings) > 0
        ;
        ; first store some info found via EnumDisplayDevices_()
        ;
        AddElement(x_monitor())                                   
        x_monitor_n = x_monitor_n+1
        x_monitor()\n = x_monitor_n
        x_monitor()\name = PeekS(@device\DeviceName,32)             ; i want my fixed length strings!
        x_monitor()\flags = device\StateFlags
        ;
; and more stuff found via EnumDisplaySettings_()
        ;
        x_monitor()\f = settings\dmDisplayFrequency
        x_monitor()\d = settings\dmBitsPerPel
        x_monitor()\w = settings\dmPelsWidth
        x_monitor()\h = settings\dmPelsHeight
        x_monitor()\x = PeekL(@settings\dmOrientation)              ; the default definition in purebasic didn't include the onion, well, this works as well
        x_monitor()\y = PeekL(@settings\dmPaperLength) 
                ;
        ; still, the handle is missing, so find that one using a point that is somewhere on the monitor
        ;
        x_monitor()\hnd = MonitorFromPoint_(x_monitor()\x,x_monitor()\y,#MONITOR_DEFAULTTONULL)
        ;   
      EndIf
    EndIf
  Wend
  ;
  ; Debug "counted using enumdisplaydevices"
  ; Debug x_monitor_n
  ;
  x_retval = x_monitor_n
  ProcedureReturn x_retval
EndProcedure

x_monitor_detect()

ResetList(x_monitor())
While NextElement(x_monitor())
  Debug ""
  Debug "monitor  "+Str(x_monitor()\n)
  If x_monitor()\flags & #DISPLAY_DEVICE_PRIMARY_DEVICE
    Debug "primary display"
  EndIf
  Debug "name    "+x_monitor()\name
  Debug "handle  "+Str(x_monitor()\hnd)
  Debug "pos x   "+Str(x_monitor()\x)
  Debug "pos y   "+Str(x_monitor()\y)
  Debug "width   "+Str(x_monitor()\w)
  Debug "height  "+Str(x_monitor()\h)
  Debug "depth   "+Str(x_monitor()\d)
  Debug "refresh "+Str(x_monitor()\f)
Wend

x_monitor_detect()
OpenConsole()
ResetList(x_monitor())
While NextElement(x_monitor())
  PrintN("")
  PrintN("monitor  "+Str(x_monitor()\n))
  If x_monitor()\flags & #DISPLAY_DEVICE_PRIMARY_DEVICE
    PrintN("primary display")
  EndIf
  PrintN("name    "+x_monitor()\name)
  PrintN("handle  "+Str(x_monitor()\hnd))
  PrintN("pos x   "+Str(x_monitor()\X))
  PrintN("pos y   "+Str(x_monitor()\Y))
  PrintN("width   "+Str(x_monitor()\w))
  PrintN("height  "+Str(x_monitor()\h))
  PrintN("depth   "+Str(x_monitor()\d))
  PrintN("refresh "+Str(x_monitor()\f))
Wend 

Input() : End

Posted: Mon Oct 16, 2006 8:48 pm
by Rescator
To make it work on PB 4.0

add the following

Code: Select all

Structure DISPLAY_DEVICE_new                  ; used to retrieve monitor and device info
  cb.l                                    ; length of struct
  DeviceName.s{32}
  DeviceString.s{128}
  StateFlags.l
  DeviceID.s{128}
  DeviceKey.s{128}
EndStructure
and change

Code: Select all

  Protected info.MONITORINFOEX, device.DISPLAY_DEVICE, n.l,settings.DEVMODE
to

Code: Select all

  Protected info.MONITORINFOEX, device.DISPLAY_DEVICE_new, n.l,settings.DEVMODE
This is just a temp fix for the above code,
hopefully Fred will have located and fixed the issue for PB 4.1

Posted: Mon Apr 13, 2009 1:32 pm
by jayagopal
this is exactly what i needed! but it isn't working for me. i'm using PB 4.1

with this code:

Code: Select all

; purebasic survival guide
; multi_monitor_2.pb - 30.12.2003 ejn (blueznl)
; http://www.xs4all.nl/~bluez/datatalk/pure1.htm
;
; - how to detect multiple monitors and their relative position to each other
; - EndumDisplayMonitors_()
; - EnumDisplayDevices_()
; - EnumDisplaySettings_()
; - MonitorFromPoint_()
; - GetMonitorInfo_()
;
; constants / structs for multi monitor handling
;
#SM_XVIRTUALSCREEN        = 76        ; x-coordinate of left upper corner of total display area
#SM_YVIRTUALSCREEN        = 77        ; same for y
#SM_CXVIRTUALSCREEN       = 78        ; width
#SM_CYVIRTUALSCREEN       = 79        ; height
#SM_CMONITORS             = 80        ; number of monitors
#SM_SAMEDISPLAYFORMAT     = 81        ; identical sizing of all screens
;
#MONITOR_DEFAULTTONULL    = 0
#MONITOR_DEFAULTTOPRIMARY = 1
#MONITOR_DEFAULTTONEAREST = 2
;
#SM_XVIRTUALSCREEN        = 76        ; x-coordinate of left upper corner of total display area
#SM_YVIRTUALSCREEN        = 77        ; same for y
#SM_CXVIRTUALSCREEN       = 78        ; width
#SM_CYVIRTUALSCREEN       = 79        ; height
#SM_CMONITORS             = 80        ; number of monitors
#SM_SAMEDISPLAYFORMAT     = 81        ; identical sizing of all screens
;
#DISPLAY_DEVICE_ATTACHED_TO_DESKTOP = $1
#DISPLAY_DEVICE_MULTI_DRIVER        = $2
#DISPLAY_DEVICE_PRIMARY_DEVICE      = $4
#DISPLAY_DEVICE_MIRRORING_DRIVER    = $8
#DISPLAY_DEVICE_VGA_COMPATIBLE      = $10
#DISPLAY_DEVICE_REMOVABLE           = $20
#DISPLAY_DEVICE_MODESPRUNED         = $8000000
#DISPLAY_DEVICE_REMOTE              = $4000000
#DISPLAY_DEVICE_DISCONNECT          = $2000000
#DISPLAY_DEVICE_ACTIVE              = $1
#DISPLAY_DEVICE_ATTACHED            = $2
;
#CCHDEVICENAME = 32
#CCHFORMNAME = 32
;
#ENUM_CURRENT_SETTINGS = -1
#ENUM_REGISTRY_SETTINGS = -2
;
#MONITOR_DEFAULTTONULL    = 0
#MONITOR_DEFAULTTOPRIMARY = 1
#MONITOR_DEFAULTTONEAREST = 2
;

Structure DISPLAY_DEVICE_new                  ; used to retrieve monitor and device info
  cb.l                                    ; length of struct
  DeviceName.s{32}
  DeviceString.s{128}
  StateFlags.l
  DeviceID.s{128}
  DeviceKey.s{128}
EndStructure

Structure MONITORINFO                     ; used to retrieve monitor info
  cb.l                                    ; size of structure (fill before using)
  m_x1.l                                  ; rectangle, monitor coords x1/y1/x2/y2
  m_y1.l
  m_x2.l
  m_y2.l
  w_x1.l                                  ; rectangle, work area coords (?)
  w_y1.l
  w_x2.l
  w_y2.l
  flags.l
EndStructure
;
Structure MONITORINFOEX                   ; superset of MONITORINFO with added  string for devicename
  cb.l
  m_x1.l
  m_y1.l
  m_x2.l
  m_y2.l
  w_x1.l
  w_y1.l
  w_x2.l
  w_y2.l
  flags.l
  name.b[32]                              ; #CCHDEVICENAME = 32
EndStructure
;
 
Structure x_monitorinfo                   ; used to store monitor info
  n.l                                     ; sequential number
  hnd.l                                   ; handle
  x.l                                     ; x-position
  y.l                                     ; y-position
  w.l                                     ; width
  h.l                                     ; height
  d.l                                     ; colour depth (bits)
  f.l                                     ; frequency
  name.s                                  ; devicename (i want my fixed length strings!)
  flags.l                                 ; status of the device
EndStructure
;
NewList x_monitor.x_monitorinfo()         ; info on monitors
x_desktop.x_monitorinfo                   ; info on desktop

Procedure x_monitor_monitorenumproc(WindowID, Message, WPARAM, LPARAM)
 Shared x_monitor()
  ;
  ; store on each call the monitor handle in the x_monitor() list
  ; called by windows in callback as set up in x_monitor_detect() by the api EnumDisplayMonitors_()
  ; also known as MonitorEnumProc
  ;
  AddElement(x_monitor())
  x_monitor()\hnd = WindowID
  ;
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

Procedure.l x_monitor_detect()
  Protected info.MONITORINFOEX, device.DISPLAY_DEVICE_new, n.l,settings.DEVMODE
  Protected x_retval.l, x_monitor_n.l
  Shared x_desktop,x_monitor()
  Protected x_monitor_samedisplayformat.l
  ;
  ; *** detect number of screens and retrieve their properties
  ;
  ; in:
  ; retval:
  ; out:    x_monitor_n.l    - number of screens
  ;         x_desktop_w.l    - desktop width
  ;         x_desktop_h.l    - desktop height
  ;
  ; GetSystemMetrics_()
  ;
  ; provides quite a bit info on display adapters, screens etc. but does not provide info
  ; per monitor / device on multi monitor setups
  ;
  ; x_monitor_n = GetSystemMetrics_(#SM_CMONITORS)
  ; x_monitor_samedisplayformat.l = GetSystemMetrics_(#SM_SAMEDISPLAYFORMAT)
  ;
  x_desktop\w = GetSystemMetrics_(#SM_CXVIRTUALSCREEN)
  x_desktop\h = GetSystemMetrics_(#SM_CYVIRTUALSCREEN)
  ;
  ; Debug "same display format on all screens (0 = no)"
  ; Debug x_monitor_samedisplayformat
  ; Debug "counted using getsystemmetrics"
  ; Debug x_monitor_n
  ;
  ; EnumDisplayMonitors()
  ;
  ; returns monitors overlapping a given rectangle, including pseudo / mirror monitors!
  ; after the call, for each monitor a handle will be stored in x_monitor()\hnd
  ; this can be used to obtain more information using GetMonitorInfo_()
  ; flags returned are different from EnumDisplayDevices()
  ;
  ; ClearList(x_monitor())
  ; EnumDisplayMonitors_(0,0,@x_monitor_monitorenumproc(),0)      ; call the function
  ; info.MONITORINFOEX                                            ; create a struct for GetMonitorInfo_()
  ; info\cb = SizeOf(info)                                        ; length of struct (important for MONITORINFO vs. MONITORINFOEX)
  ; x_monitor_n = 0                                               ; nr. of monitors
  ; ResetList(x_monitor())                                        ; reset and...
  ; While NextElement(x_monitor())                                ; go through the list   
  ;   x_monitor_n = x_monitor_n+1
  ;   x_monitor()\n = x_monitor_n                                 ; sequential number
  ;   GetMonitorInfo_(x_monitor()\hnd,@info)                      ; get info on the monitor
  ;   x_monitor()\x = info\m_x1
  ;   x_monitor()\y = info\m_y1
  ;   x_monitor()\w = info\m_x2 - info\m_x1
  ;   x_monitor()\h = info\m_y2 - info\m_y1
  ;   x_monitor()\name = PeekS(@info\name,32)                     ; i want my fixed length strings!
  ; Wend
  ; ;
  ; Debug "counted using enumdisplaymonitors"
  ; Debug x_monitor_n
  ;
  ; EnumDisplayDevices()
  ;
  ; walks through all available devices, retrieve names and flags
  ; by using the returned flags all 'non-real' monitors can be filtered out
  ;
                                      ; to store results from EnumDisplayDevices_()
  device\cb = SizeOf(DISPLAY_DEVICE)
                                                ; to store results from EnumDisplaySettings_()
  settings\dmSize = SizeOf(settings)                            ; DEVMODE is declared in purebasic itself
  settings\dmDriverExtra = 0
  ;
  ClearList(x_monitor())
  n.l = 0
  x_monitor_n = 0       
  While EnumDisplayDevices_(0,n,device,0) > 0      ; check all devices
    n = n+1
    ;
    ; the StateFlags field in the filled struct contains information on the device / monitor
    ; some values to check with (not all cards / drivers support all functions):
    ;
    ; #DISPLAY_DEVICE_ATTACHED_TO_DESKTOP - in use and part of the desktop
    ; #DISPLAY_DEVICE_PRIMARY_DEVICE      - primary device
    ; #DISPLAY_DEVICE_VGA_COMPATIBLE      - none reported
    ; #DISPLAY_DEVICE_MULTI_DRIVER       
    ; #DISPLAY_DEVICE_ACTIVE             
    ; #DISPLAY_DEVICE_ATTACHED           
    ;
    If (device\StateFlags & #DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) = #DISPLAY_DEVICE_ATTACHED_TO_DESKTOP     ; check if it's part of the desktop
      ;
      ; if a device is part of the desktop, additional information can be retrieved using
      ; EnumDisplaySettings_() with the device name
      ;
      If EnumDisplaySettings_(PeekS(@device\devicename,32),#ENUM_CURRENT_SETTINGS,settings) > 0
        ;
        ; first store some info found via EnumDisplayDevices_()
        ;
        AddElement(x_monitor())                                   
        x_monitor_n = x_monitor_n+1
        x_monitor()\n = x_monitor_n
        x_monitor()\name = PeekS(@device\DeviceName,32)             ; i want my fixed length strings!
        x_monitor()\flags = device\StateFlags
        ;
        ; and more stuff found via EnumDisplaySettings_()
        ;
        x_monitor()\f = settings\dmDisplayFrequency
        x_monitor()\d = settings\dmBitsPerPel
        x_monitor()\w = settings\dmPelsWidth
        x_monitor()\h = settings\dmPelsHeight
        x_monitor()\x = settings\dmOrientation+settings\dmPaperSize<<16       ; the default definition in purebasic didn't include the onion, well, this works as well
        x_monitor()\y = settings\dmPaperLength+settings\dmPaperWidth<<16
        ;
        ; still, the handle is missing, so find that one using a point that is somewhere on the monitor
        ;
        x_monitor()\hnd = MonitorFromPoint_(x_monitor()\x,x_monitor()\y,#MONITOR_DEFAULTTONULL)
        ;   
      EndIf
    EndIf
  Wend
  ;
  ; Debug "counted using enumdisplaydevices"
  ; Debug x_monitor_n
  ;
  x_retval = x_monitor_n
  ProcedureReturn x_retval
EndProcedure

x_monitor_detect()

ResetList(x_monitor())
While NextElement(x_monitor())
  Debug ""
  Debug "monitor  "+Str(x_monitor()\n)
  If x_monitor()\flags & #DISPLAY_DEVICE_PRIMARY_DEVICE
    Debug "primary display"
  EndIf
  Debug "name    "+x_monitor()\name
  Debug "handle  "+Str(x_monitor()\hnd)
  Debug "pos x   "+Str(x_monitor()\x)
  Debug "pos y   "+Str(x_monitor()\y)
  Debug "width   "+Str(x_monitor()\w)
  Debug "height  "+Str(x_monitor()\h)
  Debug "depth   "+Str(x_monitor()\d)
  Debug "refresh "+Str(x_monitor()\f)
Wend

x_monitor_detect()
OpenConsole()
ResetList(x_monitor())
While NextElement(x_monitor())
  PrintN("")
  PrintN("monitor  "+Str(x_monitor()\n))
  If x_monitor()\flags & #DISPLAY_DEVICE_PRIMARY_DEVICE
    PrintN("primary display")
  EndIf
  PrintN("name    "+x_monitor()\name)
  PrintN("handle  "+Str(x_monitor()\hnd))
  PrintN("pos x   "+Str(x_monitor()\X))
  PrintN("pos y   "+Str(x_monitor()\Y))
  PrintN("width   "+Str(x_monitor()\w))
  PrintN("height  "+Str(x_monitor()\h))
  PrintN("depth   "+Str(x_monitor()\d))
  PrintN("refresh "+Str(x_monitor()\f))
Wend

Input() : End
i get this result:

monitor 1
primary display
name \\.\DISPLAY1
handle 13697377
pos x 0
pos y 0
width 1280
height 800
depth 32
refresh 60

monitor 2
name \\.\DISPLAY2
handle 0
pos x -66816
pos y -65768
width 1280
height 1024
depth 32
refresh 60
my secondary is at x=-1280 and y=-224
everything else is perfect

really impressive work anyway... i know it worked for others on other versions.

Posted: Mon Apr 13, 2009 1:34 pm
by jayagopal
i forgot to select "Notify me when a reply is posted"

:D

Posted: Mon Apr 13, 2009 6:23 pm
by Poshu

Code: Select all

; purebasic survival guide
; multi_monitor_2.pb - 30.12.2003 ejn (blueznl)
; http://www.xs4all.nl/~bluez/datatalk/pure1.htm
;
; - how to detect multiple monitors and their relative position to each other
; - EndumDisplayMonitors_()
; - EnumDisplayDevices_()
; - EnumDisplaySettings_()
; - MonitorFromPoint_()
; - GetMonitorInfo_()
;
; constants / structs for multi monitor handling
;
#SM_XVIRTUALSCREEN        = 76        ; x-coordinate of left upper corner of total display area
#SM_YVIRTUALSCREEN        = 77        ; same for y
#SM_CXVIRTUALSCREEN       = 78        ; width
#SM_CYVIRTUALSCREEN       = 79        ; height
#SM_CMONITORS             = 80        ; number of monitors
#SM_SAMEDISPLAYFORMAT     = 81        ; identical sizing of all screens
;
#MONITOR_DEFAULTTONULL    = 0
#MONITOR_DEFAULTTOPRIMARY = 1
#MONITOR_DEFAULTTONEAREST = 2
;
#SM_XVIRTUALSCREEN        = 76        ; x-coordinate of left upper corner of total display area
#SM_YVIRTUALSCREEN        = 77        ; same for y
#SM_CXVIRTUALSCREEN       = 78        ; width
#SM_CYVIRTUALSCREEN       = 79        ; height
#SM_CMONITORS             = 80        ; number of monitors
#SM_SAMEDISPLAYFORMAT     = 81        ; identical sizing of all screens
;
#DISPLAY_DEVICE_ATTACHED_TO_DESKTOP = $1
#DISPLAY_DEVICE_MULTI_DRIVER        = $2
#DISPLAY_DEVICE_PRIMARY_DEVICE      = $4
#DISPLAY_DEVICE_MIRRORING_DRIVER    = $8
#DISPLAY_DEVICE_VGA_COMPATIBLE      = $10
#DISPLAY_DEVICE_REMOVABLE           = $20
#DISPLAY_DEVICE_MODESPRUNED         = $8000000
#DISPLAY_DEVICE_REMOTE              = $4000000
#DISPLAY_DEVICE_DISCONNECT          = $2000000
#DISPLAY_DEVICE_ACTIVE              = $1
#DISPLAY_DEVICE_ATTACHED            = $2
;
#CCHDEVICENAME = 32
#CCHFORMNAME = 32
;
#ENUM_CURRENT_SETTINGS = -1
#ENUM_REGISTRY_SETTINGS = -2
;
#MONITOR_DEFAULTTONULL    = 0
#MONITOR_DEFAULTTOPRIMARY = 1
#MONITOR_DEFAULTTONEAREST = 2
;
Structure MONITORINFO                     ; used to retrieve monitor info
  cb.l                                    ; size of structure (fill before using)
  m_x1.l                                  ; rectangle, monitor coords x1/y1/x2/y2
  m_y1.l
  m_x2.l
  m_y2.l
  w_x1.l                                  ; rectangle, work area coords (?)
  w_y1.l
  w_x2.l
  w_y2.l
  flags.l
EndStructure
;
Structure MONITORINFOEX                   ; superset of MONITORINFO with added  string for devicename
  cb.l
  m_x1.l
  m_y1.l
  m_x2.l
  m_y2.l
  w_x1.l
  w_y1.l
  w_x2.l
  w_y2.l
  flags.l
  Name.b[32]                              ; #CCHDEVICENAME = 32
EndStructure
;
 
Structure x_monitorinfo                   ; used to store monitor info
  n.l                                     ; sequential number
  hnd.l                                   ; handle
  X.l                                     ; x-position
  Y.l                                     ; y-position
  w.l                                     ; width
  h.l                                     ; height
  d.l                                     ; colour depth (bits)
  f.l                                     ; frequency
  Name.s                                  ; devicename (i want my fixed length strings!)
  flags.l                                 ; status of the device
EndStructure
;
NewList x_monitor.x_monitorinfo()         ; info on monitors
x_desktop.x_monitorinfo                   ; info on desktop

Procedure x_monitor_monitorenumproc(WindowID, message, wParam, lParam)
  Shared x_monitor()
  ;
  ; store on each call the monitor handle in the x_monitor() list
  ; called by windows in callback as set up in x_monitor_detect() by the api EnumDisplayMonitors_()
  ; also known as MonitorEnumProc
  ;
  AddElement(x_monitor())
  x_monitor()\hnd = WindowID
  ;
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

Procedure.l x_monitor_detect()
  Protected info.MONITORINFOEX, device.DISPLAY_DEVICE, n.l,settings.DEVMODE
  Protected x_retval.l, x_monitor_n.l
  Shared x_desktop,x_monitor()
  Protected x_monitor_samedisplayformat.l
  ;
  ; *** detect number of screens and retrieve their properties
  ;
  ; in:
  ; retval:
  ; out:    x_monitor_n.l    - number of screens
  ;         x_desktop_w.l    - desktop width
  ;         x_desktop_h.l    - desktop height
  ;
  ; GetSystemMetrics_()
  ;
  ; provides quite a bit info on display adapters, screens etc. but does not provide info
  ; per monitor / device on multi monitor setups
  ;
  ; x_monitor_n = GetSystemMetrics_(#SM_CMONITORS)
  ; x_monitor_samedisplayformat.l = GetSystemMetrics_(#SM_SAMEDISPLAYFORMAT)
  ;
  x_desktop\w = GetSystemMetrics_(#SM_CXVIRTUALSCREEN)
  x_desktop\h = GetSystemMetrics_(#SM_CYVIRTUALSCREEN)
  ;
  ; Debug "same display format on all screens (0 = no)"
  ; Debug x_monitor_samedisplayformat
  ; Debug "counted using getsystemmetrics"
  ; Debug x_monitor_n
  ;
  ; EnumDisplayMonitors()
  ;
  ; returns monitors overlapping a given rectangle, including pseudo / mirror monitors!
  ; after the call, for each monitor a handle will be stored in x_monitor()\hnd
  ; this can be used to obtain more information using GetMonitorInfo_()
  ; flags returned are different from EnumDisplayDevices()
  ;
  ; ClearList(x_monitor())
  ; EnumDisplayMonitors_(0,0,@x_monitor_monitorenumproc(),0)      ; call the function
  ; info.MONITORINFOEX                                            ; create a struct for GetMonitorInfo_()
  ; info\cb = SizeOf(info)                                        ; length of struct (important for MONITORINFO vs. MONITORINFOEX)
  ; x_monitor_n = 0                                               ; nr. of monitors
  ; ResetList(x_monitor())                                        ; reset and...
  ; While NextElement(x_monitor())                                ; go through the list   
  ;   x_monitor_n = x_monitor_n+1
  ;   x_monitor()\n = x_monitor_n                                 ; sequential number
  ;   GetMonitorInfo_(x_monitor()\hnd,@info)                      ; get info on the monitor
  ;   x_monitor()\x = info\m_x1
  ;   x_monitor()\y = info\m_y1
  ;   x_monitor()\w = info\m_x2 - info\m_x1
  ;   x_monitor()\h = info\m_y2 - info\m_y1
  ;   x_monitor()\name = PeekS(@info\name,32)                     ; i want my fixed length strings!
  ; Wend
  ; ;
  ; Debug "counted using enumdisplaymonitors"
  ; Debug x_monitor_n
  ;
  ; EnumDisplayDevices()
  ;
  ; walks through all available devices, retrieve names and flags
  ; by using the returned flags all 'non-real' monitors can be filtered out
  ;
  ; to store results from EnumDisplayDevices_()
  device\cb = SizeOf(DISPLAY_DEVICE)
  ; to store results from EnumDisplaySettings_()
  settings\dmSize = SizeOf(settings)                            ; DEVMODE is declared in purebasic itself
  settings\dmDriverExtra = 0
  ;
  ClearList(x_monitor())
  n.l = 0
  x_monitor_n = 0       
  While EnumDisplayDevices_(0,n,device,0) > 0      ; check all devices
    n = n+1
    ;
    ; the StateFlags field in the filled struct contains information on the device / monitor
    ; some values to check with (not all cards / drivers support all functions):
    ;
    ; #DISPLAY_DEVICE_ATTACHED_TO_DESKTOP - in use and part of the desktop
    ; #DISPLAY_DEVICE_PRIMARY_DEVICE      - primary device
    ; #DISPLAY_DEVICE_VGA_COMPATIBLE      - none reported
    ; #DISPLAY_DEVICE_MULTI_DRIVER       
    ; #DISPLAY_DEVICE_ACTIVE             
    ; #DISPLAY_DEVICE_ATTACHED           
    ;
    If (device\StateFlags & #DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) = #DISPLAY_DEVICE_ATTACHED_TO_DESKTOP     ; check if it's part of the desktop
      ;
      ; if a device is part of the desktop, additional information can be retrieved using
      ; EnumDisplaySettings_() with the device name
      ;
      If EnumDisplaySettings_(PeekS(@device\DeviceName,32),#ENUM_CURRENT_SETTINGS,settings) > 0
        ;
        ; first store some info found via EnumDisplayDevices_()
        ;
        AddElement(x_monitor())                                   
        x_monitor_n = x_monitor_n+1
        x_monitor()\n = x_monitor_n
        x_monitor()\Name = PeekS(@device\DeviceName,32)             ; i want my fixed length strings!
        x_monitor()\flags = device\StateFlags
        ;
        ; and more stuff found via EnumDisplaySettings_()
        ;
        x_monitor()\f = settings\dmDisplayFrequency
        x_monitor()\d = settings\dmBitsPerPel
        x_monitor()\w = settings\dmPelsWidth
        x_monitor()\h = settings\dmPelsHeight
        x_monitor()\X = settings\dmOrientation+settings\dmPaperSize       ; the default definition in purebasic didn't include the onion, well, this works as well
        x_monitor()\Y = settings\dmPaperLength+settings\dmPaperWidth
        ;
        ; still, the handle is missing, so find that one using a point that is somewhere on the monitor
        ;
        x_monitor()\hnd = MonitorFromPoint_(x_monitor()\X,x_monitor()\Y,#MONITOR_DEFAULTTONULL)
        ;   
      EndIf
    EndIf
  Wend
  ;
  ; Debug "counted using enumdisplaydevices"
  ; Debug x_monitor_n
  ;
  x_retval = x_monitor_n
  ProcedureReturn x_retval
EndProcedure

x_monitor_detect()

ResetList(x_monitor())
While NextElement(x_monitor())
  Debug ""
  Debug "monitor  "+Str(x_monitor()\n)
  If x_monitor()\flags & #DISPLAY_DEVICE_PRIMARY_DEVICE
    Debug "primary display"
  EndIf
  Debug "name    "+x_monitor()\Name
  Debug "handle  "+Str(x_monitor()\hnd)
  Debug "pos x   "+Str(x_monitor()\X)
  Debug "pos y   "+Str(x_monitor()\Y)
  Debug "width   "+Str(x_monitor()\w)
  Debug "height  "+Str(x_monitor()\h)
  Debug "depth   "+Str(x_monitor()\d)
  Debug "refresh "+Str(x_monitor()\f)
Wend

x_monitor_detect()
OpenConsole()
ResetList(x_monitor())
While NextElement(x_monitor())
  PrintN("")
  PrintN("monitor  "+Str(x_monitor()\n))
  If x_monitor()\flags & #DISPLAY_DEVICE_PRIMARY_DEVICE
    PrintN("primary display")
  EndIf
  PrintN("name    "+x_monitor()\Name)
  PrintN("handle  "+Str(x_monitor()\hnd))
  PrintN("pos x   "+Str(x_monitor()\X))
  PrintN("pos y   "+Str(x_monitor()\Y))
  PrintN("width   "+Str(x_monitor()\w))
  PrintN("height  "+Str(x_monitor()\h))
  PrintN("depth   "+Str(x_monitor()\d))
  PrintN("refresh "+Str(x_monitor()\f))
Wend

Input() : End
here it is.

Posted: Mon Apr 13, 2009 11:14 pm
by Rescator
Well Poshu. it returns x=-1025 on second monitor here, while it should have been -1024. So no idea why my code (2 posts up) work on my machine, but yours get it wrong.

jayagopal use my code instead, the one you are using seems to use some << shifts that neither mine nor Poshu's code uses.


Also, this code really need to be simplified, optimized, updated to take advantage of latest PB where applicable and support unicode it's rather old and ugly as it is now :)

Posted: Mon Apr 13, 2009 11:34 pm
by Rescator
A better solution might be to just fetch the work area instead (code elsewhere on the forum how to find this out) if you really need to.

One of my apps does something really cool after the user has moved the window: http://www.purebasic.fr/english/viewtopic.php?t=29652

This ensures that the window is "snapped" (clipped) to the nearest monitor and position that is visible in the case the window or a part of it is outside the visible monitor.
Different sized monitors and resolution is no problem either, the API handles most of the magic.
I believe it will also "snap" a window that is partially across 2 or more monitors, snapping it to the side/corner of the monitor with the most of the window in it.

Code like that should really be a MUST in all applications, I'm kinda surprised this isn't enforced by default in Windows (would make so much more sense to only allow manual override instead) oh well.

Thanks to that snapping feature my program is happily oblivious to the concept of multiple monitors/displays and even work area. (if moved over the taskbar it will "snap" to the the edge of it instead,, sweet).
And another benefit is in the cases where the app was on a 2nd monitor last time, but next time it's started the 2nd monitor is not hooked up or it's work area has changed, in which case that snap procedure will make the "lost" window appear again.

Try with the values:
x=-300
y=-800

In the 2nd example in that thread this will make the window appear to the left and up from pos 0,0 (top left of monitor 0) and then snap it to the nearest visible work area. Brilliant ;)

Would be really cool if PB had a new openwindow flag along the lines #PB_Window_SnapToWorkArea or something like that would do this automatically. Not sure if a similar API exist on Linux or Mac though.

PS! The 2nd example in that thread should work well with the fancy new Vista sidebar as well, and with custom placements of the taskbar as well.

Posted: Thu Apr 16, 2009 9:03 am
by jayagopal
poshu: thanks! that works perfectly:

monitor 1
primary display
name \\.\DISPLAY1
handle 65537
pos x 0
pos y 0
width 1280
height 800
depth 32
refresh 60

monitor 2
name \\.\DISPLAY2
handle 0
pos x -1281
pos y -233
width 1280
height 1024
depth 32
refresh 60