Tumulus

Display Changes on Wrong Monitor

3 posts in this topic

So I am working on a script to change the resolution on my monitor to reflect the maximum setting it can possibly support. I am using it for single monitor displays, but testing it on my 3 monitor set up at work. When I test it there, the settings for monitor one are detected, but then the change applies to monitor two. If I test it on a single monitor computer it correctly identifies the maximum setting for the monitor, but never applies it. The message box I included to test the ChangeRes function never shows in either case.

I assume that I am changing the monitor settings for a different monitor than the one I am taking the setting data from, but I am not sure exactly where in my code that error is (if that is truly the case). If you could give it a look over and help me find the mistake I would be much obliged. My experience with structs is very minimal. The ChangeRes function is taken from the function written by Mr. YonG in this thread.

#include <Array.au3>
#include <File.au3>

;Default entries
$OKMSGBOX = 0
$DEFAULT = ""

;program variables
Global $i_WidthScreen
Global $i_HeightScreen

;GetRes finds the maximum supported resolution setting on the monitor
Func GetRes(ByRef $i_WidthScreen, ByRef $i_HeightScreen)
    Local $i_MaxHorizontal
    Local $i_MaxVertical
    Local $a_ResultH[0]
    Local $a_ResultV[0]

    $wbemFlagReturnImmediately = 0x10
    $wbemFlagForwardOnly = 0x20
    $colItems = ""
    $sComputer = "localhost"

    $OutputH = ""
    $OutputV = ""

    $oWMIService = ObjGet("winmgmts:\\" & $sComputer & "\")
    $colItems = $oWMIService.ExecQuery("SELECT * FROM CIM_VideoControllerResolution", "WQL", _
            $wbemFlagReturnImmediately + $wbemFlagForwardOnly)

    If IsObj($colItems) Then
        For $objItem In $colItems
            $OutputH = $OutputH & $objItem.HorizontalResolution & @CRLF
            $OutputV = $OutputV & $objItem.VerticalResolution & @CRLF
        Next
        $a_ResultH = StringSplit($OutputH, @CRLF, 1)
        $a_ResultV = StringSplit($OutputV, @CRLF, 1)

        ;_ArrayDisplay($aResultH) ;these are for testing purposes to make sure the arrays populate correctly
        ;_ArrayDisplay($aResultV)

    Else
        MsgBox(0, "WMI Output", "No WMI Objects Found for class: " & "CIM_VideoControllerResolution")
    EndIf

    $i_MaxHorizontal = _ArrayMax($a_ResultH, 1)
    $i_MaxVertical = _ArrayMax($a_ResultV, 1)

    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $i_MaxVertical = ' & $i_MaxVertical & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $i_MaxHorizontal = ' & $i_MaxHorizontal & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    $i_WidthScreen = $i_MaxHorizontal
    $i_HeightScreen = $i_MaxVertical

    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $i_WidthScreen = ' & $i_WidthScreen & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $i_HeightScreen = ' & $i_HeightScreen & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    ;MsgBox($OKMSGBOX, "GetRes", "The Get Resolution function resolved") ;This is for testing to make sure the funct ran properly

EndFunc;==>GetRes

;ChangeRes changes the resolution settings
Func ChangeRes($i_Width = @DesktopWidth, $i_Height = @DesktopHeight, $i_BitsPP = @DesktopDepth, $i_RefreshRate = @DesktopRefresh)

    Local Const $DM_PELSWIDTH = 0x00080000
    Local Const $DM_PELSHEIGHT = 0x00100000
    Local Const $DM_BITSPERPEL = 0x00040000
    Local Const $DM_DISPLAYFREQUENCY = 0x00400000
    Local Const $CDS_TEST = 0x00000002
    Local Const $CDS_UPDATEREGISTRY = 0x00000001
    Local Const $DISP_CHANGE_RESTART = 1
    Local Const $DISP_CHANGE_SUCCESSFUL = 0
    Local Const $HWND_BROADCAST = 0xffff
    Local Const $WM_DISPLAYCHANGE = 0x007E


    If $i_Width = "" Or $i_Width = -1 Then
        $i_Width = @DesktopWidth
    EndIf
    If $i_Height = "" Or $i_Height = -1 Then
        $i_Height = @DesktopHeight
    EndIf
    If $i_BitsPP = "" Or $i_BitsPP = -1 Then
        $i_BitsPP = @DesktopDepth
    EndIf
    If $i_RefreshRate = "" Or $i_RefreshRate = -1 Then
        $i_RefreshRate = @DesktopRefresh
    EndIf

    Local $DEVMODE = DllStructCreate("byte[32];int[10];byte[32];int[6]")
    Local $B = DllCall("user32.dll", "int", "EnumDisplaySettings", "ptr", 0, "long", 0, "ptr", DllStructGetPtr($DEVMODE))
        If @error Then
            $B = 0
            SetError(1)
            Return $B
        Else
            $B = $B[0]
        EndIf

        If $B <> 0 Then
            DllStructSetData($DEVMODE, 2, BitOR($DM_PELSWIDTH, $DM_PELSHEIGHT, $DM_BITSPERPEL, $DM_DISPLAYFREQUENCY), 5)
            DllStructSetData($DEVMODE, 4, $i_Width, 2)
            DllStructSetData($DEVMODE, 4, $i_Height, 3)
            DllStructSetData($DEVMODE, 4, $i_BitsPP, 1)
            DllStructSetData($DEVMODE, 4, $i_RefreshRate, 5)
            $B = DllCall("user32.dll", "int", "ChangeDisplaySettings", "ptr", DllStructGetPtr($DEVMODE), "int", $CDS_TEST)
        If @error Then
            $B = -1
            Else
            $B = $B[0]
        EndIf

        Select
            Case $B = $DISP_CHANGE_RESTART
                $DEVMODE = ""
                Return 2
            Case $B = $DISP_CHANGE_SUCCESSFUL
                DllCall("user32.dll", "int", "ChangeDisplaySettings", "ptr", DllStructGetPtr($DEVMODE), "int", $CDS_UPDATEREGISTRY)
                DllCall("user32.dll", "int", "SendMessage", "hwnd", $HWND_BROADCAST, "int", $WM_DISPLAYCHANGE, _
                "int", $i_BitsPP, "int", $i_Height * 2 ^ 16 + $i_Width)
                $DEVMODE = ""
                Return 1
            Case Else
                $DEVMODE = ""
                SetError(1)
                Return $B
        EndSelect

    EndIf

MsgBox($OKMSGBOX, "Change Resolution", "The screen resolution has been set to " & $i_WidthScreen & "x" & $i_HeightScreen)

EndFunc ;==> ChangeRes


;Main prog- runs the above functions

GetRes($i_WidthScreen, $i_HeightScreen)

ChangeRes($i_WidthScreen, $i_HeightScreen, $DEFAULT, $DEFAULT)

;End prog

 

Share this post


Link to post
Share on other sites



In the DEVMODE struct you need to give it a dmPosition setting to change it to the monitor you're attempting to change the resolution of. dmPosition is a pointer to a struct that tells it what the POINTL coordinates are.

 


If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Share this post


Link to post
Share on other sites

Alright. I think I have made the changes, but like I said, structs are still a bit beyond my capabilities for the moment. 

Is this right? I added another int variable to my $DEVMODE struct and set it equal to the value for $DM_POSITION. I also added it to the part of the struct that references the other DM variables. It didn't change anything though (still getting the change on the 2nd monitor), so I must be missing something in the DllCall or I did it incorrectly. (I was quite confused that four different values were assigned to element 4 each with a different index. Also that element 2 has a BitOr combining the 5 values)

After researching the pages you provided above, I tried setting the struct a different way in the commented out section but that did not work either, and the values displayed by the message box changed completely. I think that they may not be assigned in the correct order.

What am I not understanding here? Is there a struct concept or a Dll concept that I am not grasping? (I certainly think that is the case).

Local $DEVMODE = DllStructCreate("byte[32];int[10];byte[32];int[6];int")
        IF @error Then
            MsgBox($OKMSGBOX, "", "Error in DllStructCreate, code: " & @error)
            Return False
        EndIf

    Local $B = DllCall("user32.dll", "int", "EnumDisplaySettings", "ptr", 0, "long", 0, "ptr", DllStructGetPtr($DEVMODE))
        If @error Then
            $B = 0
            SetError(1)
            Return $B
        Else
            $B = $B[0]
        EndIf

        If $B <> 0 Then
            ;#cs
            DllStructSetData($DEVMODE, 2, BitOR($DM_PELSWIDTH, $DM_PELSHEIGHT, $DM_BITSPERPEL, $DM_DISPLAYFREQUENCY, $DM_POSITION), 5)
            DllStructSetData($DEVMODE, 4, $i_Width, 2)
            DllStructSetData($DEVMODE, 4, $i_Height, 3)
            DllStructSetData($DEVMODE, 4, $i_BitsPP, 1)
            DllStructSetData($DEVMODE, 4, $i_RefreshRate, 5)
            DllStructSetData($DEVMODE, 5, $DM_POSITION)
            #ce

            #cs
            DllStructSetData($DEVMODE, 1, $i_Width)
            DllStructSetData($DEVMODE, 2, $i_Height)
            DllStructSetData($DEVMODE, 3, $i_BitsPP)
            DllStructSetData($DEVMODE, 4, $i_RefreshRate)
            DllStructSetData($DEVMODE, 5, $DM_POSITION)
            #ce

        ;Testing portion to view my struct
            MsgBox(1, "", "Struct Size: " & DllStructGetSize($DEVMODE) & @CRLF & _
            "Struct pointer: " & DllStructGetPtr($DEVMODE) & @CRLF & _
            "Data:" & @CRLF & _
            DllStructGetData($DEVMODE, 1) & @CRLF & _
            DllStructGetData($DEVMODE, 2) & @CRLF & _
            DllStructGetData($DEVMODE, 3) & @CRLF & _
            DllStructGetData($DEVMODE, 4) & @CRLF & _
            DllStructGetData($DEVMODE, 5))

  

Share this post


Link to post
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