Jump to content
Mbee

How to get Monitor Handle from Monitor Name?

Recommended Posts

Mbee

I'm struggling with adapting my big GUI app to support multiple monitors. One GUI on the primary monitor, another on a secondary monitor.  Part of my problem is the sheer multiplicity of different UDFs and code snippets to do this sort of thing - they're all over the place and they all do things differently.  To reduce the confusion, for now I'm sticking with the functions described in the AutoIt help file...

So, I've called _WinAPI_EnumDisplayDevices() and identified the primary and secondary monitors as well as a poorly documented return value from index 1 of the return array for each, which I had to find out the hard way that this is a string of the form "\\.\DISPLAY<n>", where <n> is the monitor number.  Now, I want to call _WinAPI_GetMonitorInfo(),but that requires "A handle to the display monitor of interest".  I've searched MSDN and the AutoIt fora, but I can't find a way to translate that monitor name string OR the monitor index number into a monitor handle.

How can I do that, please?

Thanks.

 

Share this post


Link to post
Share on other sites
Bilgus

I literally Smushed the two examples together and this popped out

#include <Array.au3>
#include <WinAPIGdi.au3>
#include <WinAPISys.au3>
Local $aPos, $aData = _WinAPI_EnumDisplayMonitors()

If IsArray($aData) Then
    ReDim $aData[$aData[0][0] + 1][5]
    For $i = 1 To $aData[0][0]
        $aPos = _WinAPI_GetPosFromRect($aData[$i][1])
        For $j = 0 To 3
            $aData[$i][$j + 1] = $aPos[$j]
        Next
    Next
EndIf

_ArrayDisplay($aData, '_WinAPI_EnumDisplayMonitors')

;Local $tPos = _WinAPI_GetMousePos()
Local $hMonitor; = _WinAPI_MonitorFromPoint($tPos)
For $i = 1 to $aData[0][0]
    ConsoleWrite($i & @CRLF)
    $hMonitor = $aData[$i][0]
Local $aDataM = _WinAPI_GetMonitorInfo($hMonitor)
If IsArray($aDataM) Then
    ConsoleWrite('Handle:      ' & $hMonitor & @CRLF)
    ConsoleWrite('Rectangle:   ' & DllStructGetData($aDataM[0], 1) & ', ' & DllStructGetData($aDataM[0], 2) & ', ' & DllStructGetData($aDataM[0], 3) & ', ' & DllStructGetData($aDataM[0], 4) & @CRLF)
    ConsoleWrite('Work area:   ' & DllStructGetData($aDataM[1], 1) & ', ' & DllStructGetData($aDataM[1], 2) & ', ' & DllStructGetData($aDataM[1], 3) & ', ' & DllStructGetData($aDataM[1], 4) & @CRLF)
    ConsoleWrite('Primary:     ' & $aDataM[2] & @CRLF)
    ConsoleWrite('Device name: ' & $aDataM[3] & @CRLF)
EndIf
Next

 

Share this post


Link to post
Share on other sites
Mbee
Posted (edited)

Thanks a bunch, Bilgus, but that does not answer my question or solve my problem.

It's easy to get an HMONITOR (Monitor Handle) from an existing Window or a pixel/point from a known location (which is what you're doing above), but I don't have the luxury of having either.  And to get such would create a "There's a hole in my bucket" loop that's insoluble, since I cannot create a window or provide a point coordinate on a monitor device until I already know what I need to know by calling _WinAPI_GetMonitorInfo() !

No, I really need a way of obtaining the HMONITOR handle based on the monitor Name or Index.

But perhaps if you commented your code far better and explained where you can get that information before I have that information, I'd be grateful.

Thanks again.

 

 

 

 

 

 

 

 

 

 

Edited by Mbee

Share this post


Link to post
Share on other sites
Bilgus
Posted (edited)

It seems pretty simple to expand this to do whjat you want it does have the 'Device name'

So therefore You Run the script above and Check if the name matched

If StringInStr($aDataM[3], "\\.\" & $sDisplayName) Then
    Return $hMonitor
EndIf

Better?

 #include <Array.au3>   ;THIS ONE ONLY NEEDED FOR _ARRAYDISPLAY
#include <WinAPIGdi.au3>
#include <WinAPISys.au3>

MsgBox(0, "MONITOR #1 HANDLE", Monitor_HandleFromName("Display1"))
MsgBox(0, "MONITOR #2 HANDLE", Monitor_HandleFromName(Monitor_NumberToDisplay(2)))

Func Monitor_HandleFromName($sDisplayName) ;A function definition for Monitor_HandleFromName takes a String "Display" with a number at the end
    $sDisplayName = StringReplace($sDisplayName, "\\.\", "") ;Remove the first part if exists will add it back later
    Local $aPos, $aData = _WinAPI_EnumDisplayMonitors()

    If IsArray($aData) Then ;Is it an array?
        ;Comments in HELPFILE
        ;[n][0] - A handle to the display monitor.
        ;[n][1] - $tagRECT structure defining a display monitor rectangle or the clipping area.
        ReDim $aData[$aData[0][0] + 1][5] ;Make Array Bigger(ER)
        For $i = 1 To $aData[0][0]
            $aPos = _WinAPI_GetPosFromRect($aData[$i][1])
            ;Comments in HELPFILE
            ;[0] - The x-coordinate of the upper-left corner of the rectangle.
            ;[1] - The y-coordinate of the upper-left corner of the rectangle.
            ;[2] - The width of the rectangle.
            ;[3] - The height of the rectangle.
            For $j = 0 To 3 ;Do 4 times 0= 1st 1 = 2nd 2 = 3rd 3= 4th
                $aData[$i][$j + 1] = $aPos[$j] ;Put Data returned from _WinAPI_GetPosFromRect() into the results array
            Next
        Next
    EndIf

    _ArrayDisplay($aData, '_WinAPI_EnumDisplayMonitors') ;Show the results thus far

    ;;;Local $tPos = _WinAPI_GetMousePos();Comment out of example script
    Local $hMonitor ;;;; = _WinAPI_MonitorFromPoint($tPos);Ditto
    For $i = 1 To $aData[0][0]
        $hMonitor = $aData[$i][0] ;Take the handle added from previous function and use it for this one
        Local $aDataM = _WinAPI_GetMonitorInfo($hMonitor) ;Call _WinAPI_GetMonitorInfo()
        ;Comments in HELPFILE
        ;[0] - $tagRECT structure that specifies the display monitor rectangle, in virtual-screen coordinates.
        ;[1] - $tagRECT structure that specifies the work area rectangle of the display monitor that can be used by applications, in virtual-screen coordinates.
        ;[2] - 1 (True) for the primary display monitor, or 0 (False) otherwise.
        ;[3] - The device name of the monitor being used, e.g. "\\.\DISPLAY1".
        If IsArray($aDataM) Then ;Is this an array?
            ConsoleWrite('Handle:      ' & $hMonitor & @CRLF) ;The Handle to THE MONITOR
            ConsoleWrite('Rectangle:   ' & DllStructGetData($aDataM[0], 1) & ', ' & DllStructGetData($aDataM[0], 2) & ', ' & DllStructGetData($aDataM[0], 3) & ', ' & DllStructGetData($aDataM[0], 4) & @CRLF) ;RECTANGLE THIS MONITOR OCCUPIES
            ConsoleWrite('Work area:   ' & DllStructGetData($aDataM[1], 1) & ', ' & DllStructGetData($aDataM[1], 2) & ', ' & DllStructGetData($aDataM[1], 3) & ', ' & DllStructGetData($aDataM[1], 4) & @CRLF) ;Area WHERE YOU CAN ACTUALLY PUT STUFF
            ConsoleWrite('Primary:     ' & $aDataM[2] & @CRLF) ;IS THIS THE MAIN MONITOR?????
            ConsoleWrite('Device name: ' & $aDataM[3] & @CRLF) ;THE DISPLAY NAME!!!!!!!!!!!!!!!!!!!!!!!!!!
        EndIf ;Done IsArray?
        If StringInStr($aDataM[3], "\\.\" & $sDisplayName) Then ;IS THIS THE RIGHT NAME??
            ;I GUESS THIS IS THE CORRECT MONITOR
            Return $hMonitor;GIVE THE HANDLE BACK
        Else;NOPE NOT THIS ONE
            ConsoleWrite("NOPE NOT THIS ONE" & @CRLF) ;Console message with a carriage return and linefeed
        EndIf
    Next
    Return 0 ;Not Found GIVE 0 BACK
EndFunc   ;==>Monitor_HandleFromName

Func Monitor_NumberToDisplay($iMonitor) ; A function definition for Monitor_NumberToDisplay takes an integer
    Return "Display" & $iMonitor ;puts The string 'Display' and a number YOU supply Together
EndFunc   ;==>Monitor_NumberToDisplay

 

Edited by Bilgus
  • Thanks 1

Share this post


Link to post
Share on other sites
Bilgus
Posted (edited)

TaDa^

And no it doesn't use any predefined points to get the information

what it does is call the first example 

_WinAPI_EnumDisplayMonitors

Enumerates display monitors (including invisible pseudo-monitors associated with the mirroring drivers)

That returns a list of all monitors in the system their handles and sizes

it then passes these handles to the second example..

_WinAPI_GetMonitorInfo

Retrieves information about a display monitor

Which checks to see if the name returned matches the desired monitor..

So yes exactly what you wanted.

 

Edited by Bilgus

Share this post


Link to post
Share on other sites
Earthshine

yeah, he's not using known points and he did answer your question.


My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites
Mbee
Posted (edited)

Regarding your second post, you delivered fine work,Bilgus -- thanks so very much!  Documenting and explaining your code helped enormously, and I am very grateful. By far the greatest problem in software development has been and continues to be programmers who provide minimal or no useful comments in their code.

Years ago I was hired as the lead low-level systems programmer for a commercial nuclear power safety software system written entirely in virtually entirely un-commented assembly code. The system was apparently coded by extremely arrogant cretins who -- like most programmers today -- just sat at their keyboards and hacked away and considering commenting to be beneath them.

I continue to be terrified of commercial nuclear plants not due to radiation worries or the like, but instead because of the insane, essentially criminal negligence of their programmers.

Edited by Mbee

Share this post


Link to post
Share on other sites
Mbee
4 hours ago, Earthshine said:

yeah, he's not using known points and he did answer your question.

In his second post, yes.

Share this post


Link to post
Share on other sites
Mbee
12 hours ago, Bilgus said:

TaDa^

And no it doesn't use any predefined points to get the information

what it does is call the first example 

_WinAPI_EnumDisplayMonitors

Enumerates display monitors (including invisible pseudo-monitors associated with the mirroring drivers)

That returns a list of all monitors in the system their handles and sizes

it then passes these handles to the second example..

_WinAPI_GetMonitorInfo

Retrieves information about a display monitor

Which checks to see if the name returned matches the desired monitor..

So yes exactly what you wanted.

 

 

Might you consider toning down the condescension, please?  I don't know why you're so angry when you communicate with me.  It's unkind.

Share this post


Link to post
Share on other sites
Earthshine
Posted (edited)

Lol. That’s how programmers are. No bullshit. And his first didn’t use canned points. He calls the function. 

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites
Bilgus
Posted (edited)

Mbee I Didn't mean to seem unkind but I gave you exactly what you asked for in the first post you gave me some line about it not being what you wanted without actually looking at it. The Thing is that you asked me to comment code directly from the HELPFILE which you could have easily looked up rather than wanting me to do even more work for you.

Only reason I did the second script was for closure :lol:

 

A Note about Comments

As far comments go generally the programmers rule is that if it is obvious what it does then don't comment..

Instead you should strive to write code that tells a story and then you only comment the deceptive things that don't work like they seem.

 

There are a few reasons for this..

First is that too many comments makes it hard to follow code when you know what you are looking at

Second is that people generally don't change the comments when they change the code so its even worse than no comment its now an INCORRECT comment

 

This isn't so important in our little autoit scripts but it will become more so as you move up to larger codebases

 

In the future don't throw a fit about not understanding the code, figure out what you can... Add YOUR comments as to what you think each thing does and then repost that asking for clarification.

Instead of acting like you did in your first reply.

 

Edit- In the future i'll try to be a little gentler on the un-initiated

 

 

Edited by Bilgus
  • Like 2

Share this post


Link to post
Share on other sites
Mbee
5 hours ago, Bilgus said:

Mbee I Didn't mean to seem unkind but I gave you exactly what you asked for in the first post you gave me some line about it not being what you wanted without actually looking at it. The Thing is that you asked me to comment code directly from the HELPFILE which you could have easily looked up rather than wanting me to do even more work for you.

Only reason I did the second script was for closure :lol:

 

A Note about Comments

As far comments go generally the programmers rule is that if it is obvious what it does then don't comment..

Instead you should strive to write code that tells a story and then you only comment the deceptive things that don't work like they seem.

 

There are a few reasons for this..

First is that too many comments makes it hard to follow code when you know what you are looking at

Second is that people generally don't change the comments when they change the code so its even worse than no comment its now an INCORRECT comment

 

This isn't so important in our little autoit scripts but it will become more so as you move up to larger codebases

 

In the future don't throw a fit about not understanding the code, figure out what you can... Add YOUR comments as to what you think each thing does and then repost that asking for clarification.

Instead of acting like you did in your first reply.

 

Edit- In the future i'll try to be a little gentler on the un-initiated

 

 

You may benefit from anger management therapy, and a vast amount of skeptical and thorough introspection regarding your character and self-esteem issues.

In the future, would you kindly consider not posting any responses to my questions or other posts? The true geniuses on this board have always treated me far more calmly and rationally.

 

Share this post


Link to post
Share on other sites
Mbee

Thank you, Bilgus, for your excellent work.  Here is a full treatment of your function.

#include-once

; #INDEX# ============================================================================================================
; Title .........: Monitor_HandleFromName
; AutoIt Version : 3.3.14.2
; Language ......: English
; Description ...: Returns HMONITOR Monitor Handle given Monitor Name String
; Remarks .......:
; Note ..........:
; Author(s) .....:  Bilgus - 15-Mar-2018
; ====================================================================================================================


; #FUNCTION# =========================================================================================================
; Name...........: Monitor_HandleFromName
; Description ...: Returns HMONITOR Monitor Handle associated with a given Monitor Device Name
; Syntax ........: Monitor_HandleFromName( $sMonitorDevName )
; Parameters ....: $sMonitorDevName - String containing a Monitor Device Name.
;                       These strings are of the form ".\\.Display<n>", where <n> represents a spcecific Display Number.
;                       The Display Number can be obtained by calling _WinAPI_EnumDisplayDevices()
;
; Requirement(s) : v3.2.12.2 or higher, and with an Operating System version 7 or greater.
; Return values .: Success - Returns the associated HMONITOR Monitor Handle
;                  Failure - Returns 0
; Author ........: Bilgus - 15-Mar-2018
; Modified ......:
; Remarks .......: This function is useful in a sustem with multiple monitors. A HMONITOR Monitor Handle is required
;                  to pass to _WinAPI_GetMonitorInfo(), which provides essential details regarding the Monitor.
;                  For a full understanding of Windows 7+ Multiple Monitor programming, see this MSDN article:
;                  https://msdn.microsoft.com/en-us/library/dd145071(v=vs.85).aspx
; Related .......:
; Link ..........: https://www.autoitscript.com/forum/topic/192965-how-to-get-monitor-handle-from-monitor-name/?do=findComment&comment=1384632
;=====================================================================================================================
;

Func Monitor_HandleFromName($sDisplayName) ;A function definition for Monitor_HandleFromName takes a String "Display" with a number at the end
    $sDisplayName = StringReplace($sDisplayName, "\\.\", "") ;Remove the first part if exists will add it back later
    Local $aPos, $aData = _WinAPI_EnumDisplayMonitors()

    If IsArray($aData) Then ;Is it an array?
        ;Comments in HELPFILE
        ;[n][0] - A handle to the display monitor.
        ;[n][1] - $tagRECT structure defining a display monitor rectangle or the clipping area.
        ReDim $aData[$aData[0][0] + 1][5] ;Make Array Bigger(ER)
        For $i = 1 To $aData[0][0]
            $aPos = _WinAPI_GetPosFromRect($aData[$i][1])
            ;Comments in HELPFILE
            ;[0] - The x-coordinate of the upper-left corner of the rectangle.
            ;[1] - The y-coordinate of the upper-left corner of the rectangle.
            ;[2] - The width of the rectangle.
            ;[3] - The height of the rectangle.
            For $j = 0 To 3 ;Do 4 times 0= 1st 1 = 2nd 2 = 3rd 3= 4th
                $aData[$i][$j + 1] = $aPos[$j] ;Put Data returned from _WinAPI_GetPosFromRect() into the results array
            Next
        Next
    EndIf

    Local $hMonitor ;;;; = _WinAPI_MonitorFromPoint($tPos);Ditto
    For $i = 1 To $aData[0][0]
        $hMonitor = $aData[$i][0] ;Take the handle added from previous function and use it for this one
        Local $aDataM = _WinAPI_GetMonitorInfo($hMonitor) ;Call _WinAPI_GetMonitorInfo()
        ;Comments in HELPFILE
        ;[0] - $tagRECT structure that specifies the display monitor rectangle, in virtual-screen coordinates.
        ;[1] - $tagRECT structure that specifies the work area rectangle of the display monitor that can be used by applications, in virtual-screen coordinates.
        ;[2] - 1 (True) for the primary display monitor, or 0 (False) otherwise.
        ;[3] - The device name of the monitor being used, e.g. "\\.\DISPLAY1".
        If IsArray($aDataM) Then ;Is this an array?
        EndIf ;Done IsArray?
        If StringInStr($aDataM[3], "\\.\" & $sDisplayName) Then ;IS THIS THE RIGHT NAME??
            ;I GUESS THIS IS THE CORRECT MONITOR
            Return $hMonitor;GIVE THE HANDLE BACK
        Else;NOPE NOT THIS ONE
;~             ConsoleWrite("NOPE NOT THIS ONE" & @CRLF) ;Console message with a carriage return and linefeed
        EndIf
    Next
    Return 0 ;Not Found GIVE 0 BACK
EndFunc   ;==>Monitor_HandleFromName

Func Monitor_NumberToDisplay($iMonitor) ; A function definition for Monitor_NumberToDisplay takes an integer
    Return "Display" & $iMonitor ;puts The string 'Display' and a number YOU supply Together
EndFunc   ;==>Monitor_NumberToDisplay

 

Share this post


Link to post
Share on other sites
Bilgus

You are really good at trying to insult people with your pseudo intellectual armchair psychoanalysis but its OK. I'll refrain from trying to help those who can't help themselves in the future.

Share this post


Link to post
Share on other sites
Earthshine
Posted (edited)

Yeah. I won’t ever bother you again either Mbee. You’re too condescending yourself and shitty with the person that ANSWERS your questions CORRECTLY the first time. 

You were even shity with me and you were wrong and you don’t read help file. Goodbye as you now will be ignored. 

Edited by Earthshine

My resources are limited. You must ask the right questions

 

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

×