Jump to content

Multiple Monitor Screenshot


SkinnyWhiteGuy
 Share

Recommended Posts

I was in need of this the other day, and researched out how to detect all displays. This should work with any number of monitors, and only generate one picture with all displays in it. It should also try to avoid taking screen shots from virtual displays used by some remote tools.

#NoTrayIcon
#include <ScreenCapture.au3>

Global $tag_DISPLAY_DEVICE = "dword cb;char DeviceName[32];char DeviceString[128];dword StateFlags;char DeviceID[128];char DeviceKey[128]"
Global Const $DISPLAY_DEVICE_MIRRORING_DRIVER = 0x00000008
Global Const $DISPLAY_DEVICE_PRIMARY_DEVICE = 0x00000004

Global $tag_POINTL = "long x;long y"
Global $tag_DEVMOD = "char dmDeviceName[32];ushort dmSpecVersion;ushort dmDriverVersion;short dmSize;" & _
        "ushort dmDriverExtra;dword dmFields;" & $tag_POINTL & ";dword dmDisplayOrientation;dword dmDisplayFixedOutput;" & _
        "short dmColor;short dmDuplex;short dmYResolution;short dmTTOption;short dmCollate;" & _
        "byte dmFormName[32];ushort LogPixels;dword dmBitsPerPel;int dmPelsWidth;dword dmPelsHeight;" & _
        "dword dmDisplayFlags;dword dmDisplayFrequency"
Global Const $ENUM_CURRENT_SETTINGS = -1

Global $Left, $Top, $Right, $Bottom
Global $i = 0

While 1
    $struct = DllStructCreate($tag_DISPLAY_DEVICE)
    DllStructSetData($struct, "cb", DllStructGetSize($struct))

    $aRetrun = DllCall("user32.dll", "int", "EnumDisplayDevices", "ptr", 0, "dword", $i, "ptr", DllStructGetPtr($struct), "dword", 0)
    If Not $aRetrun[0] Then ExitLoop

    If Not BitAND(DllStructGetData($struct, "StateFlags"), $DISPLAY_DEVICE_MIRRORING_DRIVER) Then ; Avoid Virtual Displays
;~      ConsoleWrite(DllStructGetData($struct, "DeviceName") & @TAB & "Primary: " & (BitAND(DllStructGetData($struct, "StateFlags"), $DISPLAY_DEVICE_PRIMARY_DEVICE) > 0) & @CRLF)

        $dev = DllStructCreate($tag_DEVMOD)
        DllStructSetData($dev, "dmSize", DllStructGetSize($dev))
        $aRetrun = DllCall("user32.dll", "int", "EnumDisplaySettings", "str", DllStructGetData($struct, "DeviceName"), "dword", $ENUM_CURRENT_SETTINGS, "ptr", DllStructGetPtr($dev))

        If Not IsNumber($Left) Or $Left > DllStructGetData($dev, "x") Then $Left = DllStructGetData($dev, "x")
        If Not IsNumber($Top) Or $Top > DllStructGetData($dev, "y") Then $Top = DllStructGetData($dev, "y")
        If Not IsNumber($Right) Or $Right < DllStructGetData($dev, "x") + DllStructGetData($dev, "dmPelsWidth") Then $Right = DllStructGetData($dev, "x") + DllStructGetData($dev, "dmPelsWidth")
        If Not IsNumber($Bottom) Or $Bottom < DllStructGetData($dev, "y") + DllStructGetData($dev, "dmPelsHeight") Then $Bottom = DllStructGetData($dev, "y") + DllStructGetData($dev, "dmPelsHeight")
    EndIf
    $i += 1
WEnd

If $CmdLine[0] = 1 Then
    _ScreenCapture_Capture($CmdLine[1], $Left, $Top, $Right, $Bottom)
Else
    _ScreenCapture_Capture(@ScriptDir & "\screenshot.jpg", $Left, $Top, $Right, $Bottom)
EndIf

Tested on Windows 7 (64-bit) & XP (32-bit). The commented line shows how to detect which of the displays is the Primary display.

Link to comment
Share on other sites

Great script!

Tested on Windows XP SP 3 with 2 monitors.

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

wouldn't

#NoTrayIcon
#include <ScreenCapture.au3>

$Pos = WinGetPos("Program Manager")

If $CmdLine[0] = 1 Then
    _ScreenCapture_Capture($CmdLine[1], $Pos[0], $Pos[1], $Pos[0] + $Pos[2], $Pos[1] + $Pos[3])
Else
    _ScreenCapture_Capture(@ScriptDir & "\screenshot.jpg", $Pos[0], $Pos[1], $Pos[0] + $Pos[2], $Pos[1] + $Pos[3])
EndIf

work just as well?

[font="Impact"]Never fear, I is here.[/font]

Link to comment
Share on other sites

  • 3 weeks later...

SkinnyWhiteGuy, thanks a lot for your code ;) . It made creating the following UDF, which can be used to retrieve all current, non-virtual displays' positions, a doddle:

#cs
    author: "SkinnyWhiteGuy" on http://www.autoitscript.com/forum/index.php?showtopic=105921
#ce

#include-once

;out: [n][0:x 1:y 2:width 3:height 4:is primary]
Func _displayGetPos()
    
    Local $returnArray[1][5]
    
    Local $tag_DISPLAY_DEVICE = "dword cb;char DeviceName[32];char DeviceString[128];dword StateFlags;char DeviceID[128];char DeviceKey[128]"
    Local $DISPLAY_DEVICE_MIRRORING_DRIVER = 0x00000008
    Local $DISPLAY_DEVICE_PRIMARY_DEVICE = 0x00000004

    Local $tag_POINTL = "long x;long y"
    Local $tag_DEVMOD = "char dmDeviceName[32];ushort dmSpecVersion;ushort dmDriverVersion;short dmSize;" & _
            "ushort dmDriverExtra;dword dmFields;" & $tag_POINTL & ";dword dmDisplayOrientation;dword dmDisplayFixedOutput;" & _
            "short dmColor;short dmDuplex;short dmYResolution;short dmTTOption;short dmCollate;" & _
            "byte dmFormName[32];ushort LogPixels;dword dmBitsPerPel;int dmPelsWidth;dword dmPelsHeight;" & _
            "dword dmDisplayFlags;dword dmDisplayFrequency"
    Local Const $ENUM_CURRENT_SETTINGS = -1

    Local $i = 0
    
    While 1
        
        $struct = DllStructCreate($tag_DISPLAY_DEVICE)
        DllStructSetData($struct, "cb", DllStructGetSize($struct))

        Local $aRetrun = DllCall("user32.dll", "int", "EnumDisplayDevices", "ptr", 0, "dword", $i, "ptr", DllStructGetPtr($struct), "dword", 0)
        If Not $aRetrun[0] Then ExitLoop

        If Not BitAND(DllStructGetData($struct, "StateFlags"), $DISPLAY_DEVICE_MIRRORING_DRIVER) Then ; Avoid Virtual Displays
         ConsoleWrite(DllStructGetData($struct, "DeviceName") & @TAB & "Primary: " & (BitAND(DllStructGetData($struct, "StateFlags"), $DISPLAY_DEVICE_PRIMARY_DEVICE) > 0) & @CRLF)

            $dev = DllStructCreate($tag_DEVMOD)
            DllStructSetData($dev, "dmSize", DllStructGetSize($dev))
            $aRetrun = DllCall("user32.dll", "int", "EnumDisplaySettings", "str", DllStructGetData($struct, "DeviceName"), "dword", $ENUM_CURRENT_SETTINGS, "ptr", DllStructGetPtr($dev))
            
            If IsNumber($returnArray[0][0]) Then ReDim $returnArray[UBound($returnArray)+1][5] ;if not first fill in, upsize

            $returnArray[UBound($returnArray)-1][0]=DllStructGetData($dev,"x")
            $returnArray[UBound($returnArray)-1][1]=DllStructGetData($dev,"y")
            $returnArray[UBound($returnArray)-1][2]=DllStructGetData($dev,"dmPelsWidth")
            $returnArray[UBound($returnArray)-1][3]=DllStructGetData($dev,"dmPelsHeight")
            
            $returnArray[UBound($returnArray)-1][4]=(BitAND(DllStructGetData($struct, "StateFlags"), $DISPLAY_DEVICE_PRIMARY_DEVICE) > 0) ;is primary?

        EndIf
        
        $i += 1
        
    WEnd    
    
    Return $returnArray
    
EndFunc
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...