Mbee Posted March 15, 2018 Share Posted March 15, 2018 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. Link to comment Share on other sites More sharing options...
Bilgus Posted March 15, 2018 Share Posted March 15, 2018 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 Link to comment Share on other sites More sharing options...
Mbee Posted March 15, 2018 Author Share Posted March 15, 2018 (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 March 15, 2018 by Mbee Link to comment Share on other sites More sharing options...
Bilgus Posted March 15, 2018 Share Posted March 15, 2018 (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? expandcollapse popup #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 March 15, 2018 by Bilgus Mbee 1 Link to comment Share on other sites More sharing options...
Bilgus Posted March 15, 2018 Share Posted March 15, 2018 (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 March 15, 2018 by Bilgus Link to comment Share on other sites More sharing options...
Earthshine Posted March 15, 2018 Share Posted March 15, 2018 yeah, he's not using known points and he did answer your question. My resources are limited. You must ask the right questions Link to comment Share on other sites More sharing options...
Mbee Posted March 15, 2018 Author Share Posted March 15, 2018 (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 March 15, 2018 by Mbee Link to comment Share on other sites More sharing options...
Mbee Posted March 15, 2018 Author Share Posted March 15, 2018 4 hours ago, Earthshine said: yeah, he's not using known points and he did answer your question. In his second post, yes. Link to comment Share on other sites More sharing options...
Mbee Posted March 15, 2018 Author Share Posted March 15, 2018 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. Link to comment Share on other sites More sharing options...
Earthshine Posted March 15, 2018 Share Posted March 15, 2018 (edited) Lol. That’s how programmers are. No bullshit. And his first didn’t use canned points. He calls the function. Edited March 15, 2018 by Earthshine My resources are limited. You must ask the right questions Link to comment Share on other sites More sharing options...
Bilgus Posted March 15, 2018 Share Posted March 15, 2018 (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 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 March 15, 2018 by Bilgus Earthshine and Xandy 2 Link to comment Share on other sites More sharing options...
Mbee Posted March 16, 2018 Author Share Posted March 16, 2018 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 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. Link to comment Share on other sites More sharing options...
Mbee Posted March 16, 2018 Author Share Posted March 16, 2018 Thank you, Bilgus, for your excellent work. Here is a full treatment of your function. expandcollapse popup#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 Link to comment Share on other sites More sharing options...
Bilgus Posted March 16, 2018 Share Posted March 16, 2018 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. Link to comment Share on other sites More sharing options...
Earthshine Posted March 16, 2018 Share Posted March 16, 2018 (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 March 16, 2018 by Earthshine My resources are limited. You must ask the right questions Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now