Leaderboard
Popular Content
Showing content with the highest reputation since 11/06/2025 in Posts
-
AutoIt Extension for Visual Studio Code
SOLVE-SMART and 5 others reacted to LoganCH for a topic
Released v1.3.0! Added COM object syntax highlighting for properties and methods using dot notation Distinct token scopes for COM identifiers (support.class.com.autoit) to enable theme-specific styling Contributors section to README.md with auto-updating contrib.rocks integration Added missing AutoIt macros: @exitMethod, @GUI_DropId, and @SW_ENABLE to completions and hovers AU3Check parameter parsing support with corresponding tests to improve syntax check behavior Parameter validation and improved status messages in OutputChannelManager (#230) WinNet API completions added to IntelliSense Fixed Function pattern incorrectly matching COM object methods (e.g., $obj.Method() now correctly identified as COM, not function) Incorrect documentation for @GUI_CtrlId macro (now correctly states "Last click GUI Control identifier" instead of "Drag GUI Control identifier") Duplicate WinNet signature removed and WinAPI COM signatures added to signature/hover data Incorrect CRLF constant definition corrected Duplicate parameter documentation entries removed in signature help provider Removed stray duplicate (misspelled) Clibpoard completion entry Improved parameter checks in runCheckProcess for more reliable regex matching Changed Consolidated macro data into single source of truth (src/completions/macrosData.js) to eliminate duplication and ensure consistency between completions and hovers Converted src/hovers/macros.json to src/hovers/macros.js to import from unified macro data source Rate and View on VS Code Marketplace Rate and View on OpenVSX Star & Submit Issues on GitHub6 points -
Round buttons
argumentum and 2 others reacted to MattyD for a topic
Perhaps a starting point with the ownerdrawn approach if you wanted to have a crack! take or leave it #include <GUIConstants.au3> #include <guibutton.au3> #include <WinAPIGdi.au3> #include <WinAPISysWin.au3> #include <WindowsSysColorConstants.au3> #include <WinAPIGdiDC.au3> #include <FrameConstants.au3> #include <SendMessage.au3> _WinAPI_SetUDFColorMode($UDF_RGB) ;So _WinAPI_RGB works as expected. ;By default the UDF swaps the colour values around - presumably so you can represent a RGB value with hex notation without endian issues. i.e. 0x00RRGGBB Global Const $ODT_MENU = 1 Global Const $ODT_LISTBOX = 2 Global Const $ODT_COMBOBOX = 3 Global Const $ODT_BUTTON = 4 Global Const $ODT_STATIC = 5 Global Const $ODA_DRAWENTIRE = 1 Global Const $ODA_FOCUS = 2 Global Const $ODA_SELECT = 4 Global Const $ODS_SELECTED = 0x0001 Global Const $ODS_GRAYED = 0x0002 Global Const $ODS_DISABLED = 0x0004 Global Const $ODS_CHECKED = 0x0008 Global Const $ODS_FOCUS = 0x0010 Global Const $ODS_DEFAULT = 0x0020 Global Const $ODS_COMBOBOXEDIT = 0x1000 Global Const $ODS_HOTLIGHT = 0x0040 Global Const $ODS_INACTIVE = 0x0080 Global Const $ODS_NOACCEL = 0x0100 Global Const $ODS_NOFOCUSRECT = 0x0200 Global $tagDRAWITEMSTRUCT = StringFormat("struct;uint ctlType;uint CtlID;uint itemID;uint itemAction;uint itemState;hwnd hwndItem;handle hDC;%s;ulong_ptr itemData;endstruct", $tagRect) Local $hGUI = GUICreate("", 200, 50) GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM") Local $hBtn = _GUICtrlButton_Create($hGUI, "test", 10, 10, 80, 25, $BS_OWNERDRAW) Local $idBtn2 = GUICtrlCreateButton("Disable", 100, 10, 80, 25) GUISetState() While 1 $iMsg = GUIGetMsg() Switch $iMsg Case $idBtn2 If BitAnd(WinGetState($hBtn), $WIN_STATE_ENABLED) Then WinSetState($hBtn, "", @SW_DISABLE) GUICtrlSetData($idBtn2, "Enable") Else WinSetState($hBtn, "", @SW_ENABLE) GUICtrlSetData($idBtn2, "Disable") EndIf Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd Func WM_DRAWITEM($hWnd, $iMsg, $wParam, $lParam) Local $tDRAWITEMSTRUCT = DllStructCreate($tagDRAWITEMSTRUCT, $lParam) Local $hDC = $tDRAWITEMSTRUCT.hDC Local $tWinRect = DllStructCreate($tagRect, DllStructGetPtr($tDRAWITEMSTRUCT, "Left")) Local $iTextLen = _SendMessage($tDRAWITEMSTRUCT.hwndItem, $WM_GETTEXTLENGTH) Local $tText = DllStructCreate(StringFormat("wchar text[%d]", $iTextLen + 1)) _SendMessage($tDRAWITEMSTRUCT.hwndItem, $WM_GETTEXT, DllStructGetSize($tText), $tText, 0, "wparam", "struct*") Local $iFaceCol = BitAND($tDRAWITEMSTRUCT.itemState, $ODS_DISABLED) ? _WinAPI_RGB(0xE0, 0xE0, 0xE0) : _WinAPI_RGB(0xE0, 0xE0, 0xFF) Switch $tDRAWITEMSTRUCT.ctlType Case $ODT_BUTTON If BitAND($tDRAWITEMSTRUCT.itemAction, $ODA_DRAWENTIRE) Then If BitAND($tDRAWITEMSTRUCT.itemState, $ODS_SELECTED) Then _WinAPI_DrawFrameControl($hDC, $tWinRect, $DFC_BUTTON, BitOR($DFCS_BUTTONPUSH, $DFCS_PUSHED)) $iFaceCol = _WinAPI_RGB(0xC0, 0xC0, 0xEF) Else _WinAPI_DrawFrameControl($hDC, $tWinRect, $DFC_BUTTON, $DFCS_BUTTONPUSH) EndIf _WinAPI_InflateRect($tWinRect, -3, -3) $hSelBrush = _WinAPI_CreateSolidBrush($iFaceCol) _WinAPI_SelectObject($hDC, $hSelBrush) _WinAPI_FillRect($hDC, $tWinRect, $hSelBrush) _WinAPI_DeleteObject($hSelBrush) _WinAPI_InflateRect($tWinRect, 3, 3) _WinAPI_SetBkColor($hDC, $iFaceCol) _WinAPI_DrawText($hDC, $tText.Text, $tWinRect, BitOR($DT_CENTER, $DT_VCENTER, $DT_SINGLELINE)) EndIf If BitAND($tDRAWITEMSTRUCT.itemState, $ODS_FOCUS) Then _WinAPI_InflateRect($tWinRect, -3, -3) $hSelBrush = _WinAPI_GetStockObject($HOLLOW_BRUSH) $hSelPen = _WinAPI_CreatePen($PS_DOT, 1, _WinAPI_RGB(0, 0xAA, 0xAA)) _WinAPI_SelectObject($hDC, $hSelPen) _WinAPI_SelectObject($hDC, $hSelBrush) _WinAPI_Rectangle($hDC, $tWinRect) _WinAPI_DeleteObject($hSelPen) _WinAPI_DeleteObject($hSelBrush) EndIf EndSwitch Return 1 EndFunc ;==>WM_DRAWITEM3 points -
A bit more progress with this subclassing stuff.. Multiselect with shift key down, and some very rough alignment code. ;~ #AutoIt3Wrapper_UseX64=N ;TODO: snap always rounds down, so you can't drag all the way right/bottom if you run out of window. ;Need to change the tipping point to 1/2 way between points. #include <WindowsSysColorConstants.au3> #include <guiConstants.au3> #include <winapi.au3> #include <guiButton.au3> #include <guiEdit.au3> #include <WinAPIvkeysConstants.au3> #include <BorderConstants.au3> Global Const $tagMINMAXINFO = "long Reserved[2]; long MaxSize[2]; long MaxPosition[2]; long MinTrackSize[2]; long MaxTrackSize[2]" Global Const $MK_LBUTTON = 0x0001 Global Const $MK_RBUTTON = 0x0002 Global Const $MK_SHIFT = 0x0004 Global Const $MK_CONTROL = 0x0008 Global Const $MK_MBUTTON = 0x0010 Global Const $MK_XBUTTON1 = 0x0020 Global Const $MK_XBUTTON2 = 0x0040 Global $iSnap = 15, $iMinCtrlW = 15, $iMinCtrlH = 15 Global $mh_SelCtrls[] Global $hCursor_Cross = _WinAPI_LoadCursor(0, $IDC_CROSS) Global $hGui = GUICreate("", 300, 200, 100, 100, BitOR($WS_SIZEBOX, $WS_MINIMIZEBOX)) GUISetState() Global $hGui2 = GUICreate("", 200, 300, 450, 100) Global $idAlignTop = GUICtrlCreateButton("Align Top", 100, 10, 80, 25) Global $idButton = GUICtrlCreateRadio("Button", 10, 10, 80, 25) GUICtrlSetState(-1, $GUI_CHECKED) Global $idCheck = GUICtrlCreateRadio("Checkbox", 10, 40, 80, 25) Global $idRadio = GUICtrlCreateRadio("Radio", 10, 70, 80, 25) Global $idEdit = GUICtrlCreateRadio("Edit", 10, 100, 80, 25) Global $idInput = GUICtrlCreateRadio("Input", 10, 130, 80, 25) ;~ Global $idList = GUICtrlCreateRadio("List", 10, 160, 80, 25) Global $hCtrlProc = DllCallbackRegister("CtrlProc", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr") Global $pCtrlProc = DllCallbackGetPtr($hCtrlProc) Global $hWndProc = DllCallbackRegister("WndProc", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr") Global $pWndProc = DllCallbackGetPtr($hWndProc) _WinAPI_SetWindowSubclass($hGui, $pWndProc, 1000) GUISetState() Local $iMsg, $aKeys, $tWinPos, $tParPos, $iTop While WinExists($hGui) $iMsg = GUIGetMsg() Switch $iMsg Case $GUI_EVENT_CLOSE ExitLoop Case $idAlignTop $tParPos = _WinAPI_GetClientRect($hGui) $iTop = $tParPos.Bottom $aKeys = MapKeys($mh_SelCtrls) For $hWnd In $aKeys If $mh_SelCtrls[$hWnd] Then $tWinPos = _WinAPI_GetWindowRect($hWnd) _WinAPI_ScreenToClient($hGUI, $tWinPos) If $tWinPos.Top < $iTop Then $iTop = $tWinPos.Top EndIf Next For $hWnd In $aKeys If $mh_SelCtrls[$hWnd] Then $tWinPos = _WinAPI_GetWindowRect($hWnd) _WinAPI_ScreenToClient($hGUI, $tWinPos) _WinAPI_ScreenToClient($hGUI, DllStructGetPtr($tWinPos, 3)) _WinAPI_MoveWindow($hWnd, $tWinPos.Left, $iTop, $tWinPos.Right - $tWinPos.Left, $tWinPos.Bottom - $tWinPos.Top) EndIf Next EndSwitch WEnd _WinAPI_RemoveWindowSubclass($hGui, $pWndProc, 1000) Func WndProc($hWnd, $iMsg, $wParam, $lParam, $iIdSubclass, $dwRefData) #forceref $hWnd, $iMsg, $wParam, $lParam, $iIdSubclass, $dwRefData Local $iRet Local Static $bDrawRect, $tPaintRect = DllStructCreate($tagRect) Switch $iMsg Case $WM_SETCURSOR Local $iSrc = _WinAPI_LoWord($lParam);, $iEvent = _WinAPI_HiWord($lParam) If $iSrc = $HTCLIENT Then _WinAPI_SetCursor($hCursor_Cross) $iRet = 1 Else $iRet = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndIf Case $WM_LBUTTONDOWN Local $tPoint = _WinAPI_MakePoints($lParam) $tPaintRect.Left = $tPoint.X $tPaintRect.Top = $tPoint.Y $tPaintRect.Left -= Mod($tPaintRect.Left, $iSnap) $tPaintRect.Top -= Mod($tPaintRect.Top, $iSnap) $bDrawRect = True ;~ _WinAPI_TrackMouseEvent($hWnd, $TME_LEAVE) $iRet = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) Case $WM_MOUSEMOVE Local $tPoint = _WinAPI_MakePoints($lParam) If BitAND($wParam, $MK_LBUTTON) = $MK_LBUTTON Then _WinAPI_InvalidateRect($hWnd, $tPaintRect, True) $tPaintRect.Right = $tPoint.X $tPaintRect.Bottom = $tPoint.Y $tPaintRect.Right -= Mod($tPaintRect.Right, $iSnap) $tPaintRect.Bottom -= Mod($tPaintRect.Bottom, $iSnap) _WinAPI_InvalidateRect($hWnd, $tPaintRect, True) $iRet = 0 Else If $bDrawRect Then _WinAPI_InvalidateRect($hWnd, $tPaintRect, True) $bDrawRect = False $iRet = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndIf Case $WM_PAINT If $bDrawRect Then Local $tPaintStruct = $tagPAINTSTRUCT Local $hDC = _WinAPI_BeginPaint($hWnd, $tPaintStruct) Local $hPen = _WinAPI_CreatePen($PS_DOT, 1, _WinAPI_RGB(0, 0, 0)) Local $hBrush = _WinAPI_GetStockObject($WHITE_BRUSH) _WinAPI_SelectObject($hDC, $hPen) _WinAPI_SelectObject($hDC, $hBrush) _WinAPI_Rectangle($hDC, $tPaintRect) _WinAPI_DeleteObject($hPen) _WinAPI_DeleteObject($hBrush) _WinAPI_EndPaint($hWnd, $tPaintStruct) $iRet = 0 Else $iRet = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndIf Case $WM_LBUTTONUP Local $tPoint = _WinAPI_MakePoints($lParam) If $bDrawRect Then $bDrawRect = False $tPaintRect.Right = $tPoint.X $tPaintRect.Bottom = $tPoint.Y $tPaintRect.Right -= Mod($tPaintRect.Right, $iSnap) $tPaintRect.Bottom -= Mod($tPaintRect.Bottom, $iSnap) _WinAPI_InvalidateRect($hWnd, $tPaintRect, True) If Abs($tPaintRect.Left - $tPaintRect.Right) >= $iMinCtrlW _ ;MinWidth & Height. And Abs($tPaintRect.Top - $tPaintRect.Bottom) >= $iMinCtrlH Then ;Yes, this can be done better - too lazy right now! Select Case GUICtrlRead($idButton) = $GUI_CHECKED ;Need border & clipsiblings to paint custom frame. using UDF for button to avoid any surprises in autoit's default btn proc Local $hCtrl = _GUICtrlButton_Create($hWnd, "", _ ($tPaintRect.Left < $tPaintRect.Right) ? $tPaintRect.Left : $tPaintRect.Right, _ ($tPaintRect.Top < $tPaintRect.Bottom) ? $tPaintRect.Top : $tPaintRect.Bottom, _ Abs($tPaintRect.Left - $tPaintRect.Right), _ Abs($tPaintRect.Top - $tPaintRect.Bottom), _ BitOR($BS_PUSHLIKE, $WS_BORDER, $WS_CLIPSIBLINGS)) _WinAPI_SetWindowSubclass($hCtrl, $pCtrlProc, _WinAPI_GetDlgCtrlID($hCtrl)) Case GUICtrlRead($idCheck) = $GUI_CHECKED Local $hCtrl = _GUICtrlButton_Create($hWnd, "Checkbox", _ ($tPaintRect.Left < $tPaintRect.Right) ? $tPaintRect.Left : $tPaintRect.Right, _ ($tPaintRect.Top < $tPaintRect.Bottom) ? $tPaintRect.Top : $tPaintRect.Bottom, _ Abs($tPaintRect.Left - $tPaintRect.Right), _ Abs($tPaintRect.Top - $tPaintRect.Bottom), _ BitOR($BS_AUTOCHECKBOX, $WS_BORDER, $WS_CLIPSIBLINGS)) _WinAPI_SetWindowSubclass($hCtrl, $pCtrlProc, _WinAPI_GetDlgCtrlID($hCtrl)) Case GUICtrlRead($idRadio) = $GUI_CHECKED Local $hCtrl = _GUICtrlButton_Create($hWnd, "Radio", _ ($tPaintRect.Left < $tPaintRect.Right) ? $tPaintRect.Left : $tPaintRect.Right, _ ($tPaintRect.Top < $tPaintRect.Bottom) ? $tPaintRect.Top : $tPaintRect.Bottom, _ Abs($tPaintRect.Left - $tPaintRect.Right), _ Abs($tPaintRect.Top - $tPaintRect.Bottom), _ BitOR($BS_AUTORADIOBUTTON, $WS_BORDER, $WS_CLIPSIBLINGS)) _WinAPI_SetWindowSubclass($hCtrl, $pCtrlProc, _WinAPI_GetDlgCtrlID($hCtrl)) Case GUICtrlRead($idEdit) = $GUI_CHECKED Local $hCtrl = _GUICtrlEdit_Create($hWnd, "", _ ($tPaintRect.Left < $tPaintRect.Right) ? $tPaintRect.Left : $tPaintRect.Right, _ ($tPaintRect.Top < $tPaintRect.Bottom) ? $tPaintRect.Top : $tPaintRect.Bottom, _ Abs($tPaintRect.Left - $tPaintRect.Right), _ Abs($tPaintRect.Top - $tPaintRect.Bottom), _ BitOR($ES_WANTRETURN, $WS_VSCROLL, $WS_HSCROLL, $ES_AUTOVSCROLL, $ES_AUTOHSCROLL, $WS_BORDER, $WS_CLIPSIBLINGS)) _WinAPI_SetWindowSubclass($hCtrl, $pCtrlProc, _WinAPI_GetDlgCtrlID($hCtrl)) Case GUICtrlRead($idInput) = $GUI_CHECKED Local $hCtrl = _GUICtrlEdit_Create($hWnd, "", _ ($tPaintRect.Left < $tPaintRect.Right) ? $tPaintRect.Left : $tPaintRect.Right, _ ($tPaintRect.Top < $tPaintRect.Bottom) ? $tPaintRect.Top : $tPaintRect.Bottom, _ Abs($tPaintRect.Left - $tPaintRect.Right), _ Abs($tPaintRect.Top - $tPaintRect.Bottom), _ BitOR($ES_LEFT, $ES_AUTOHSCROLL, $WS_BORDER, $WS_CLIPSIBLINGS)) _WinAPI_SetWindowSubclass($hCtrl, $pCtrlProc, _WinAPI_GetDlgCtrlID($hCtrl)) EndSelect EndIf EndIf $iRet = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) Case $WM_SIZE ;This prevents autoit's docking logic from moving controls around on window restore. ;if we ony use the udf functions to create ctrls this is not needed. $iRet = _WinAPI_DefWindowProcW($hWnd, $iMsg, $wParam, $lParam) ;~ Case $WM_MOUSELEAVE ;TODO: trap mouse in window while left button is down. Case Else $iRet = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndSwitch Return $iRet EndFunc ;==>WndProc Func CtrlProc($hWnd, $iMsg, $wParam, $lParam, $iIdSubclass, $dwRefData) Local $iRet Local Static $hHasFocus Switch $iMsg Case $WM_GETMINMAXINFO, $WM_SIZING, $WM_MOVING, $WM_SIZE, $WM_MOVE, $WM_EXITSIZEMOVE $iRet = _Ctrl_MoveSizeCtrlProc($hWnd, $iMsg, $wParam, $lParam) Case $WM_NCHITTEST $iRet = _Ctrl_MoveSizeCtrlProc($hWnd, $iMsg, $wParam, $lParam) Case $WM_SETCURSOR $iRet = _Ctrl_MoveSizeCtrlProc($hWnd, $iMsg, $wParam, $lParam) Case $WM_MOUSEACTIVATE ;"Selected" control logic. If Not BitAND(0x8000, _WinAPI_GetAsyncKeyState($VK_SHIFT)) Then Local $aKeys = MapKeys($mh_SelCtrls) For $i = 0 To UBound($aKeys) - 1 If $aKeys[$i] Then $mh_SelCtrls[$aKeys[$i]] = False _WinAPI_RedrawWindow($aKeys[$i], 0, 0, BitOR($RDW_FRAME, $RDW_INVALIDATE)) EndIf Next $mh_SelCtrls[$hWnd] = True Else $mh_SelCtrls[$hWnd] = MapExists($mh_SelCtrls, $hWnd) ? Not $mh_SelCtrls[$hWnd] : True EndIf ;NCL_LBUTTONDOWN doesn't retrigger if ctrl already has focus. If _WinAPI_GetFocus() = $hWnd Then _WinAPI_RedrawWindow($hWnd, 0, 0, BitOR($RDW_FRAME, $RDW_INVALIDATE)) $iRet = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) Case $WM_NCLBUTTONDOWN $iRet = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) If $mh_SelCtrls[$hWnd] Then _WinAPI_SetFocus($hWnd) Case $WM_SETFOCUS $hHasFocus = $hWnd _SendMessage($wParam, $WM_KILLFOCUS, $hWnd) $iRet = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) _WinAPI_RedrawWindow($hWnd, 0, 0, BitOR($RDW_FRAME, $RDW_INVALIDATE)) Case $WM_KILLFOCUS _WinAPI_RedrawWindow($hWnd, 0, 0, BitOR($RDW_FRAME, $RDW_INVALIDATE)) $iRet = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) Case $WM_NCLBUTTONDBLCLK ;Prevent double-click maximizing in "caption" - also now set caption. If $wParam = $HTCAPTION Then ;Set text If Not BitAND(0x8000, _WinAPI_GetAsyncKeyState($VK_SHIFT)) Then Local $iCaptionLen = _SendMessage($hWnd, $WM_GETTEXTLENGTH) Local $tCaption = DllStructCreate(StringFormat("wchar text[%d]", $iCaptionLen + 1)) _SendMessage($hWnd, $WM_GETTEXT, DllStructGetSize($tCaption), $tCaption, 0, "wparam", "struct*") Local $sCaption = InputBox("Edit Caption", " ", $tCaption.Text, "", 150, 60, BitAND($lParam, 0xFFFF), BitShift($lParam, 16)) If Not @error Then _SendMessage($hWnd, $WM_SETTEXT, 0, $sCaption, 0, "wparam", "wstr") EndIf Else $iRet = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndIf Case $WM_NCPAINT _WinAPI_DefWindowProc($hWnd, $iMsg, $wParam, $lParam) Local $hDC = _WinAPI_GetWindowDC($hWnd) Local $tRect = _WinAPI_GetWindowRect($hWnd) $tRect.Right = $tRect.Right - $tRect.Left $tRect.Bottom = $tRect.Bottom - $tRect.Top $tRect.Left = 0 $tRect.Top = 0 Local $iCol = _WinAPI_GetSysColor($COLOR_3DFACE) If MapExists($mh_SelCtrls, $hWnd) Then If $mh_SelCtrls[$hWnd] Then _ $iCol = ($hHasFocus = $hWnd) ? _WinAPI_RGB(0, 0xAA, 0) : _WinAPI_RGB(0, 0xAA, 0xAA) EndIf Local $hBrush = _WinAPI_CreateSolidBrush($iCol) _WinAPI_SelectObject($hDC, $hBrush) _WinAPI_FrameRect($hDC, $tRect, $hBrush) _WinAPI_DeleteObject($hBrush) _WinAPI_ReleaseDC($hWnd, $hDC) $iRet = 0 Case $WM_KEYDOWN If $wParam = $VK_DELETE Then _WinAPI_PostMessage($hWnd, $WM_DESTROY, 0, 0) Else $iRet = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndIf Case $WM_DESTROY _WinAPI_RemoveWindowSubclass($hWnd, $pCtrlProc, $iIdSubclass) $iRet = _WinAPI_DefWindowProcW($hWnd, $iMsg, $wParam, $lParam) Switch _WinAPI_GetClassName($hWnd) Case "Button" _GUICtrlButton_Destroy($hWnd) Case "Edit" _GUICtrlEdit_Destroy($hWnd) EndSwitch MapRemove($mh_SelCtrls, $hWnd) Case Else ;~ ConsoleWrite(Hex($iMsg) & @CRLF) $iRet = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndSwitch Return $iRet EndFunc ;==>CtrlProc Func _Ctrl_MoveSizeCtrlProc($hWnd, $iMsg, $wParam, $lParam) Local $iRetVal Local $tMsePoints, $tWinRect, $tMinMaxInfo, $tTgtRect Local $iSource, $iEvent Local $iFrameHitSize = 10 Local Static $iXOffset, $iYOffset Switch $iMsg Case $WM_NCHITTEST $tMsePoints = _WinAPI_MakePoints($lParam) $tWinRect = _WinAPI_GetWindowRect($hWnd) $iRetVal = $HTCLIENT ;only in caption bar if left button is down. (no kb input availabe in caption!) Local $iTestKey = _WinAPI_GetSystemMetrics($SM_SWAPBUTTON) ? $VK_RBUTTON : $VK_LBUTTON If BitAnd(0x8000, _WinAPI_GetAsyncKeyState($iTestKey)) Then $iRetVal = $HTCAPTION If $tMsePoints.X - $tWinRect.Left < $iFrameHitSize Then $iRetVal = $HTLEFT If $tMsePoints.X > ($tWinRect.Right - $iFrameHitSize) Then $iRetVal = $HTRIGHT If $tMsePoints.Y - $tWinRect.Top < $iFrameHitSize Then Switch $iRetVal Case $HTLEFT $iRetVal = $HTTOPLEFT Case $HTRIGHT $iRetVal = $HTTOPRIGHT Case Else $iRetVal = $HTTOP EndSwitch ElseIf $tMsePoints.Y > ($tWinRect.Bottom - $iFrameHitSize) Then Switch $iRetVal Case $HTLEFT $iRetVal = $HTBOTTOMLEFT Case $HTRIGHT $iRetVal = $HTBOTTOMRIGHT Case Else $iRetVal = $HTBOTTOM EndSwitch EndIf If $tMsePoints.X < 0 Then $iRetVal = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) If $tMsePoints.Y < 0 Then $iRetVal = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) _WinAPI_RedrawWindow($hWnd) Case $WM_GETMINMAXINFO ;Min width jumps to ~150 with WS_BORDER - I guess it gets min window size: SM_CYMINTRACK $tMinMaxInfo = DllStructCreate($tagMINMAXINFO, $lParam) $tMinMaxInfo.MinTrackSize(1) = $iMinCtrlW $tMinMaxInfo.MinTrackSize(2) = $iMinCtrlH $iRetVal = 0 Case $WM_SIZING $tWinRect = _WinAPI_GetWindowRect($hWnd) $tTgtRect = DllStructCreate($tagRect, $lParam) $tTgtRect.Left += Mod($tWinRect.Left - $tTgtRect.Left, $iSnap) $tTgtRect.Top += Mod($tWinRect.Top - $tTgtRect.Top, $iSnap) $tTgtRect.Right += Mod($tWinRect.Right - $tTgtRect.Right, $iSnap) $tTgtRect.Bottom += Mod($tWinRect.Bottom - $tTgtRect.Bottom, $iSnap) $iRetVal = True Case $WM_MOVING $tWinRect = _WinAPI_GetWindowRect($hWnd) $tTgtRect = DllStructCreate($tagRect, $lParam) $iXOffset += $tTgtRect.Left - $tWinRect.Left $iYOffset += $tTgtRect.Top - $tWinRect.Top Local $iSnapH = Floor($iXOffset / $iSnap) * $iSnap Local $iSnapV = Floor($iYOffset / $iSnap) * $iSnap $iXOffset -= $iSnapH $iYOffset -= $iSnapV $tTgtRect.Left = $tWinRect.Left + $iSnapH $tTgtRect.Right = $tWinRect.Right + $iSnapH $tTgtRect.Top = $tWinRect.Top + $iSnapV $tTgtRect.Bottom = $tWinRect.Bottom + $iSnapV $iRetVal = 0 Case $WM_EXITSIZEMOVE $iXOffset = 0 $iYOffset = 0 $iRetVal = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) Case $WM_SETCURSOR $iSource = _WinAPI_WordToShort(_WinAPI_LoWord($lParam)) $iEvent = _WinAPI_HiWord($lParam) If $iSource = $HTCAPTION And $iEvent = $WM_LBUTTONDOWN Then _WinAPI_SetCursor($hCursor_Cross) $iRetVal = 1 Else $iRetVal = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndIf Case Else $iRetVal = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndSwitch Return $iRetVal EndFunc Func _WinAPI_MakePoints($iValue) Local $tPoints = DllStructCreate("struct;short X;short Y;endstruct") DllStructSetData($tPoints, 1, _WinAPI_LoWord($iValue)) DllStructSetData($tPoints, 2, _WinAPI_HiWord($iValue)) Return $tPoints EndFunc Func _WinAPI_SetCursorPos($iX, $iY) Local $aCall = DllCall("user32.dll", "bool", "SetCursorPos", "int", $iX, "int", $iY) If @error Then Return SetError(@error, @extended, 0) Return $aCall[0] EndFunc Func _WinAPI_MapWindowPoints($hWndFrom, $hWndTo, $pPoints, $iNumPoints) Local $aCall = DllCall("user32.dll", "int", "MapWindowPoints", "hwnd", $hWndFrom, "hwnd", $hWndTo, "ptr", $pPoints, "uint", $iNumPoints) If @error Then Return SetError(@error, @extended, 0) Return $aCall[0] EndFunc3 points
-
Fun thread. Another option would be to use custom draw which allows you to use part of the standard functionality, check for hovering and draw part of the control. #include <GUIConstants.au3> #include <WindowsConstants.au3> #include <StructureConstants.au3> #include <WinAPI.au3> #include <FrameConstants.au3> Global Const $tagNMCUSTOMDRAWINFO = $tagNMHDR & ";dword DrawStage;handle hdc;" & $tagRECT & ";dword_ptr ItemSpec;uint ItemState;lparam lItemParam;" Global $idBut Example() Func Example() Local $hGUI = GUICreate("Example") $idBut = GUICtrlCreateButton("Test", 10, 10, 100, 30) GUICtrlCreateButton("Standard", 10, 50, 100, 30) GUIRegisterMsg($WM_NOTIFY, WM_NOTIFY) GUISetState() While True Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $idBut ConsoleWrite("Button was pressed" & @CRLF) EndSwitch WEnd EndFunc ;==>Example Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam) Local $tInfo = DllStructCreate($tagNMCUSTOMDRAWINFO, $lParam) If $tInfo.IDFrom = $idBut And $tInfo.Code = $NM_CUSTOMDRAW And $tInfo.DrawStage = $CDDS_PREPAINT Then Local $tRECT = DllStructCreate($tagRECT, DllStructGetPtr($tInfo, "left")) _WinAPI_DrawFrameControl($tInfo.hDC, $tRECT, $DFC_BUTTON, (BitAND($tInfo.ItemState, $CDIS_SELECTED) ? $DFCS_PUSHED : 0) + $DFCS_BUTTONPUSH) _WinAPI_InflateRect($tRECT, -3, -3) Local $hBrush = _WinAPI_CreateSolidBrush(BitAND($tInfo.ItemState, $CDIS_HOT) ? 0xFFFF : 0xAAAA) _WinAPI_FillRect($tInfo.hDC, $tRECT, $hBrush) _WinAPI_DeleteObject($hBrush) EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_NOTIFY2 points
-
Round buttons
argumentum and one other reacted to ioa747 for a topic
Another approach (improved), in the collection with colored buttons, with 3D appearance, and toggle capability ; https://www.autoitscript.com/forum/topic/211721-round-buttons/ ;---------------------------------------------------------------------------------------- ; Title...........: 3DRectButton.au3 ; Description.....: Creates colored buttons, with 3D appearance, and toggle capability. ; AutoIt Version..: 3.3.18.0 Author: ioa747 Script Version: 0.1 ; Note............: Testet in Windows 11 Pro 24H2 Date:9/11/2025 ;---------------------------------------------------------------------------------------- #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #include <GUIConstantsEx.au3> #include <ButtonConstants.au3> #include <StaticConstants.au3> #include <WindowsStylesConstants.au3> #include <WinAPIGdi.au3> ; maps to hold buttons data Global $mButtons[], $mBtn[] Example() Func Example() ; Create a GUI with various controls. Local $hGUI = GUICreate("Example", 300, 270) GUISetFont(10, 800) ; Create a button control. Local $idButton_1 = _Button("Darck", 20, 20, 85, 30, 0xFF720E) GUICtrlSetTip(-1, "Long press to togle") Local $idButton_2 = _Button("Button 2", 20, 70, 85, 30, 0x36BB48) Local $idButton_3 = _Button("Button 3", 20, 120, 85, 30, 0x3BADFF) Local $idButton_4 = _Button("Button 4", 20, 170, 85, 30, 0xD980FF) Local $idButton_5 = GUICtrlCreateButton("Button 5", 20, 220, 85, 30) ; Display the GUI. GUISetState(@SW_SHOW, $hGUI) ; Loop until the user exits. While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $idButton_1 ConsoleWrite("$idButton_1 Down" & @CRLF) Case $idButton_2 ConsoleWrite("$idButton_2 Down" & @CRLF) Case $idButton_3 ConsoleWrite("$idButton_3 Down" & @CRLF) Case $idButton_4 ConsoleWrite("$idButton_4 Down" & @CRLF) Case $mButtons[$idButton_1].event ConsoleWrite("$idButton_1 Up" & @CRLF) If $mButtons[$idButton_1].togle Then GUISetBkColor(0x33373A, $hGUI) Else GUISetBkColor(0xF0F0F0, $hGUI) EndIf ConsoleWrite("$mButtons[$idButton_1].togle=" & $mButtons[$idButton_1].togle & @CRLF) Case $mButtons[$idButton_2].event ConsoleWrite("$idButton_2 Up" & @CRLF) ConsoleWrite("$mButtons[$idButton_2].togle=" & $mButtons[$idButton_2].togle & @CRLF) Case $mButtons[$idButton_3].event ConsoleWrite("$idButton_3 Up" & @CRLF) Case $mButtons[$idButton_4].event ConsoleWrite("$idButton_4 Up" & @CRLF) Case $idButton_5 ConsoleWrite("$idButton_5 Up" & @CRLF) EndSwitch _Hover($hGUI) WEnd ; Delete the previous GUI and all controls. GUIDelete($hGUI) EndFunc ;==>Example ;--------------------------------------------------------------------------------------- Func _Hover($hGUI, $iHighlight = 20) Local Static $iActive If Not WinActive($hGUI) Then Return SetError(1, 0, False) Local $ActiveCtrl, $mBtn Local $aCtrl = GUIGetCursorInfo($hGUI) $ActiveCtrl = IsArray($aCtrl) ? $aCtrl[4] : 0 If Not (MapExists($mButtons, $ActiveCtrl) Or $ActiveCtrl = 0) Then Return If $iActive <> $ActiveCtrl Then ; Reset Highlight If $iActive > 0 Then $mBtn = $mButtons[$iActive] GUICtrlSetBkColor($mBtn.id, $mBtn.BkColor) $iActive = 0 Return SetError(2, 0, False) EndIf If Not $ActiveCtrl Then Return ; Highlight $iActive = $ActiveCtrl $mBtn = $mButtons[$iActive] GUICtrlSetBkColor($mBtn.id, ColorLight($mBtn.BkColor, $iHighlight)) EndIf ; Click efect If $aCtrl[2] And $ActiveCtrl Then $mBtn = $mButtons[$iActive] ; Move the button based on current toggle state If Not $mBtn.togle Then GUICtrlSetPos($mBtn.id, $mBtn.X + 2, $mBtn.Y + 2) ; If not toggled, move down Else GUICtrlSetPos($mBtn.id, $mBtn.X, $mBtn.Y) ; If toggled, move up EndIf Local $iStartTime = TimerInit() Do $aCtrl = GUIGetCursorInfo($hGUI) Sleep(10) If TimerDiff($iStartTime) > 1500 Then ToolTip("Togle Locked") Until $aCtrl[2] = 0 ; *** Long press > 1.5 sec -> enable togle If TimerDiff($iStartTime) > 1500 Then $mBtn.togle = True Else $mBtn.togle = False EndIf ToolTip("") ; If is toggled, stay down If $mBtn.togle Then GUICtrlSetPos($mBtn.id, $mBtn.X + 2, $mBtn.Y + 2) Else GUICtrlSetPos($mBtn.id, $mBtn.X, $mBtn.Y) EndIf $mButtons[$mBtn.id] = $mBtn ; Update the button's data in the global map GUICtrlSendToDummy($mBtn.event) ; Send the dummy event to trigger the Up event EndIf Sleep(10) EndFunc ;==>_Hover ;--------------------------------------------------------------------------------------- Func _Button($Text, $Left, $Top, $Width, $Height, $hBkColor = 0xF0F0F0, $hTxtColor = 0x000000, $iShadow = 30) Local $hShColor = ColorLight($hBkColor, -$iShadow) Local $idEvent = GUICtrlCreateDummy() Local $idShadow = GUICtrlCreateLabel("", $Left - 1, $Top - 1, $Width + 4, $Height + 4) GUICtrlSetBkColor(-1, $hShColor) GUICtrlSetState(-1, $GUI_DISABLE) Local $id = GUICtrlCreateLabel($Text, $Left, $Top, $Width, $Height, BitOR($SS_CENTERIMAGE, $SS_CENTER)) GUICtrlSetBkColor(-1, $hBkColor) GUICtrlSetColor(-1, $hTxtColor) $mBtn.id = $id $mBtn.event = $idEvent $mBtn.text = $Text $mBtn.X = $Left $mBtn.Y = $Top $mBtn.W = $Width $mBtn.H = $Height $mBtn.BkColor = $hBkColor $mBtn.TxtColor = $hTxtColor $mBtn.shadow = $idShadow $mBtn.ShColor = $hShColor $mBtn.togle = False $mButtons[$id] = $mBtn Return $id EndFunc ;==>_Button ;-------------------------------------------------------------------------------------------------------------------------------- Func ColorLight($HexColor, $Lightness = 30) Local $iHue, $iLuminance, $iSaturation _WinAPI_ColorRGBToHLS($HexColor, $iHue, $iLuminance, $iSaturation) Local $hColor = Hex(_WinAPI_ColorHLSToRGB($iHue, $iLuminance + $Lightness, $iSaturation), 6) Return '0x' & $hColor EndFunc ;==>ColorLight ;--------------------------------------------------------------------------------------- have fun Thank you very much2 points -
AutoIt Live Wallpaper
SOLVE-SMART and one other reacted to argumentum for a topic
Perfect, beautiful, awesome. It all shows and works as advertised 💯2 points -
AutoIt Live Wallpaper
SOLVE-SMART and one other reacted to WildByDesign for a topic
I updated the script in the first post. On a per-monitor basis, I made it so that if the monitor aspect ratio is equal to the aspect ratio for the video, it will use the default Uniform value. If the aspect ratio is not equal, it will set the UniformToFill value. This should deal with the issue of black bars (letterboxing) being added on the top/bottom or sides of the video. It will simply crop some parts of the video and not stretch it. I also fixed an issue where the screen would be black briefly before the video started playing. I just had to ensure that the video was fully loaded before showing the GUI(s). @argumentum I know that you are not a fan of moving wallpapers, but if you have a moment, would you be willing to test this latest script? The reason why I ask is because your ultrawide secondary monitor is a different aspect ratio and therefore a good example to test whether or not UniformToFill is the better option for mismatching aspect ratios between video and monitor. I think that it makes sense but I don't have another monitor that is a different ratio. EDIT: And I also made sure that the Start button (and Win key) trigger should play the video on any OS language. It was likely only working with English OS before.2 points -
Guiscape -- A new GUI builder project!
n3wbie and one other reacted to jaberwacky for a topic
Hello! I'm working on a new GUI builder that I have been making great progress on! A helpful forum member ioa747 answered a question I had which started me on my journey, and now I'd like to present to you an alpha version of the software. As of now only Form and Button works in a rudimentary fashion. To run this, open Guiscape.au3 and go from there! I'd love to hear your feedback and suggestions. 🙂 Latest versions will be on Github from now on. https://github.com/matthewrg/Guiscape Guiscape.zip Downloads: 352 points -
AutoIt Live Wallpaper
SOLVE-SMART and one other reacted to argumentum for a topic
No it wouldn't. ( nor a live wallpaper ) My screen is always with all kinds of windows open. Never get to see the wallpaper 🤷♂️2 points -
Guiscape -- A new GUI builder project!
argumentum and one other reacted to jaberwacky for a topic
Thank you! 🥰 It's a problem I'm in the middle of working on. I got side quested with this DPI stuff. 😂 I learned a lot and now I have something to bring into my future projects! Updated at GitHub because I made some oopsies!2 points -
#include <AutoItConstants.au3> HotKeySet("{ENTER}", "MouseClickAction") While 1 Sleep(100) WEnd Func MouseClickAction() HotKeySet("{ENTER}") MouseClick($MOUSE_CLICK_LEFT, 134, 163, 2, 0) Sleep(100) HotKeySet("{ENTER}", "MouseClickAction") EndFunc If you want to leave after clicking #include <AutoItConstants.au3> HotKeySet("{ENTER}", "MouseClickAction") Global $bActive = True While $bActive Sleep(100) WEnd Func MouseClickAction() HotKeySet("{ENTER}") MouseClick($MOUSE_CLICK_LEFT, 134, 163, 2, 0) $bActive = False EndFunc1 point
-
GetKeyPress
mr-es335 reacted to argumentum for a topic
#include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> Example() Func Example() GUICreate("Custom MsgBox", 225, 80) GUICtrlCreateLabel("Please select a button.", 10, 10) Local $idButton_Yes = GUICtrlCreateButton("Yes", 10, 50, 65, 25) Local $idButton_No = GUICtrlCreateButton("No", 80, 50, 65, 25) Local $idButton_Exit = GUICtrlCreateButton("Exit", 150, 50, 65, 25) ; Set GUIAccelerators for the button controlIDs, these being Ctrl + y and Ctrl + n Local $aAccelKeys[2][2] = [["^y", $idButton_Yes], ["^n", $idButton_No]] GUISetAccelerators($aAccelKeys) GUISetState(@SW_SHOW) ; Display the GUI. While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE MsgBox($MB_SYSTEMMODAL, "You selected", "Close") ExitLoop Case $idButton_Yes MsgBox($MB_SYSTEMMODAL, "You selected", "Yes") ; Displays if the button was selected or the hotkey combination Ctrl + y was pressed. Case $idButton_No MsgBox($MB_SYSTEMMODAL, "You selected", "No") ; Displays if the button was selected or the hotkey combination Ctrl + n was pressed. Case $idButton_Exit MsgBox($MB_SYSTEMMODAL, "You selected", "Exit") ExitLoop EndSwitch WEnd GUIDelete() ; Delete the GUI. EndFunc ;==>Example ..is in the help file.1 point -
@Parsix Here is my entire modified code: ;~ https://www.autoitscript.com/forum/topic/154081-avoid-autoit-error-message-box-in-unknown-errors/page/4/#findComment-1547350 #Region - AutoIt3Wrapper directives section ; General section #AutoIt3Wrapper_UseX64=n #AutoIt3Wrapper_UseUpx=n #AutoIt3Wrapper_Compression=4 ; Au3Check section #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 6 -w 7 ; Au3Stripper section #AutoIt3Wrapper_Run_Au3Stripper=y #Au3Stripper_Parameters=/so /pe #AutoIt3Wrapper_Au3Stripper_OnError=C #EndRegion - AutoIt3Wrapper directives section #include <WinApi.au3> #Region - exmaple AddHookApi("user32.dll", "MessageBoxW", "Intercept_MessageBoxW", "int", "hwnd;wstr;wstr;uint") MsgBox(0, 'Test', 'Some normal MsgBox text') DllStructCreate("byte[123456789097]") ; This is a deliberate action intended to display an error, as this script demonstrates how to change error handling - interact with MsgBox's title and text. #EndRegion - exmaple #Region @trancexx - https://www.autoitscript.com/forum/topic/154081-avoid-autoit-error-message-box-in-unknown-errors/#findComment-1111917 Func Intercept_MessageBoxW($hWnd, $sText, $sTitle, $iType) If $sTitle = 'AutoIt' Then $sTitle = 'TESTING: ' & StringReplace($sTitle, "AutoIt", @ScriptName) Local $aCall = DllCall("user32.dll", "int", "MessageBoxW", _ "hwnd", $hWnd, _ "wstr", $sText, _ "wstr", $sTitle, _ "uint", $iType) If @error Or Not $aCall[0] Then Return 0 Return $aCall[0] EndFunc ;==>Intercept_MessageBoxW ; The magic is down below Func AddHookApi($sModuleName, $vFunctionName, $vNewFunction, $sRet = "", $sParams = "") Local Static $pImportDirectory, $hInstance Local Const $IMAGE_DIRECTORY_ENTRY_IMPORT = 1 If Not $pImportDirectory Then $hInstance = _WinAPI_GetModuleHandle(0) $pImportDirectory = ImageDirectoryEntryToData($hInstance, $IMAGE_DIRECTORY_ENTRY_IMPORT) If @error Then Return SetError(1, 0, 0) EndIf Local $iIsInt = IsInt($vFunctionName) Local $iRestore = Not IsString($vNewFunction) Local $tIMAGE_IMPORT_MODULE_DIRECTORY Local $pDirectoryOffset = $pImportDirectory Local $tModuleName Local $iInitialOffset, $iInitialOffset2 Local $iOffset2 Local $tBufferOffset2, $iBufferOffset2 Local $tBuffer, $tFunctionOffset, $pOld, $fMatch, $pModuleName, $pFuncName Local Const $PAGE_READWRITE = 0x04 While 1 $tIMAGE_IMPORT_MODULE_DIRECTORY = DllStructCreate("dword RVAOriginalFirstThunk;" & _ "dword TimeDateStamp;" & _ "dword ForwarderChain;" & _ "dword RVAModuleName;" & _ "dword RVAFirstThunk", _ $pDirectoryOffset) If Not DllStructGetData($tIMAGE_IMPORT_MODULE_DIRECTORY, "RVAFirstThunk") Then ExitLoop $pModuleName = $hInstance + DllStructGetData($tIMAGE_IMPORT_MODULE_DIRECTORY, "RVAModuleName") $tModuleName = DllStructCreate("char Name[" & _WinAPI_StringLenA($pModuleName) & "]", $pModuleName) If DllStructGetData($tModuleName, "Name") = $sModuleName Then ; function from this module $iInitialOffset = $hInstance + DllStructGetData($tIMAGE_IMPORT_MODULE_DIRECTORY, "RVAFirstThunk") $iInitialOffset2 = $hInstance + DllStructGetData($tIMAGE_IMPORT_MODULE_DIRECTORY, "RVAOriginalFirstThunk") If $iInitialOffset2 = $hInstance Then $iInitialOffset2 = $iInitialOffset $iOffset2 = 0 While 1 $tBufferOffset2 = DllStructCreate("dword_ptr", $iInitialOffset2 + $iOffset2) $iBufferOffset2 = DllStructGetData($tBufferOffset2, 1) If Not $iBufferOffset2 Then ExitLoop If $iIsInt Then If BitAND($iBufferOffset2, 0xFFFFFF) = $vFunctionName Then $fMatch = True ; wanted function Else $pFuncName = $hInstance + $iBufferOffset2 + 2 ; 2 is size od "word", see line below... $tBuffer = DllStructCreate("word Ordinal; char Name[" & _WinAPI_StringLenA($pFuncName) & "]", $hInstance + $iBufferOffset2) If DllStructGetData($tBuffer, "Name") == $vFunctionName Then $fMatch = True ; wanted function EndIf If $fMatch Then $tFunctionOffset = DllStructCreate("ptr", $iInitialOffset + $iOffset2) VirtualProtect(DllStructGetPtr($tFunctionOffset), DllStructGetSize($tFunctionOffset), $PAGE_READWRITE) If @error Then Return SetError(3, 0, 0) $pOld = DllStructGetData($tFunctionOffset, 1) If $iRestore Then DllStructSetData($tFunctionOffset, 1, $vNewFunction) Else DllStructSetData($tFunctionOffset, 1, DllCallbackGetPtr(DllCallbackRegister($vNewFunction, $sRet, $sParams))) EndIf Return $pOld EndIf $iOffset2 += DllStructGetSize($tBufferOffset2) WEnd ExitLoop EndIf $pDirectoryOffset += 20 ; size of $tIMAGE_IMPORT_MODULE_DIRECTORY WEnd Return SetError(4, 0, 0) EndFunc ;==>AddHookApi Func VirtualProtect($pAddress, $iSize, $iProtection) Local $aCall = DllCall("kernel32.dll", "bool", "VirtualProtect", "ptr", $pAddress, "dword_ptr", $iSize, "dword", $iProtection, "dword*", 0) If @error Or Not $aCall[0] Then Return SetError(1, 0, 0) Return 1 EndFunc ;==>VirtualProtect Func ImageDirectoryEntryToData($hInstance, $iDirectoryEntry) ; Get pointer to data Local $pPointer = $hInstance ; Start processing passed binary data. 'Reading' PE format follows. Local $tIMAGE_DOS_HEADER = DllStructCreate("char Magic[2];" & _ "word BytesOnLastPage;" & _ "word Pages;" & _ "word Relocations;" & _ "word SizeofHeader;" & _ "word MinimumExtra;" & _ "word MaximumExtra;" & _ "word SS;" & _ "word SP;" & _ "word Checksum;" & _ "word IP;" & _ "word CS;" & _ "word Relocation;" & _ "word Overlay;" & _ "char Reserved[8];" & _ "word OEMIdentifier;" & _ "word OEMInformation;" & _ "char Reserved2[20];" & _ "dword AddressOfNewExeHeader", _ $pPointer) Local $sMagic = DllStructGetData($tIMAGE_DOS_HEADER, "Magic") ; Check if it's valid format If Not ($sMagic == "MZ") Then Return SetError(1, 0, 0) ; MS-DOS header missing. Btw 'MZ' are the initials of Mark Zbikowski in case you didn't know. ; Move pointer $pPointer += DllStructGetData($tIMAGE_DOS_HEADER, "AddressOfNewExeHeader") ; move to PE file header ; In place of IMAGE_NT_SIGNATURE structure Local $tIMAGE_NT_SIGNATURE = DllStructCreate("dword Signature", $pPointer) ; Check signature If DllStructGetData($tIMAGE_NT_SIGNATURE, "Signature") <> 17744 Then ; IMAGE_NT_SIGNATURE Return SetError(2, 0, 0) ; wrong signature. For PE image should be "PE\0\0" or 17744 dword. EndIf ; Move pointer $pPointer += 4 ; size of $tIMAGE_NT_SIGNATURE structure ; In place of IMAGE_FILE_HEADER structure ; Move pointer $pPointer += 20 ; size of $tIMAGE_FILE_HEADER structure ; Determine the type Local $tMagic = DllStructCreate("word Magic;", $pPointer) Local $iMagic = DllStructGetData($tMagic, 1) Local $tIMAGE_OPTIONAL_HEADER If $iMagic = 267 Then ; x86 version ; Move pointer $pPointer += 96 ; size of $tIMAGE_OPTIONAL_HEADER ElseIf $iMagic = 523 Then ; x64 version ; Move pointer $pPointer += 112 ; size of $tIMAGE_OPTIONAL_HEADER Else Return SetError(3, 0, 0) ; unsupported module type EndIf ; Validate input by checking available number of structures that are in the module Local Const $IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16 ; predefined value that PE modules always use (AutoIt certainly) If $iDirectoryEntry > $IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1 Then Return SetError(4, 0, 0) ; invalid input ; Calculate the offset to wanted entry (every entry is 8 bytes) $pPointer += 8 * $iDirectoryEntry ; At place of correst directory entry Local $tIMAGE_DIRECTORY_ENTRY = DllStructCreate("dword VirtualAddress; dword Size", $pPointer) ; Collect data Local $pAddress = DllStructGetData($tIMAGE_DIRECTORY_ENTRY, "VirtualAddress") If $pAddress = 0 Then Return SetError(5, 0, 0) ; invalid input ; $pAddress is RVA, add it to base address Return $hInstance + $pAddress EndFunc ;==>ImageDirectoryEntryToData #EndRegion @trancexx - https://www.autoitscript.com/forum/topic/154081-avoid-autoit-error-message-box-in-unknown-errors/#findComment-1111917 Please note that I also modified this line: Func Intercept_MessageBoxW($hWnd, $sText, $sTitle, $iType) If $sTitle = 'AutoIt' Then $sTitle = 'TESTING: ' & StringReplace($sTitle, "AutoIt", @ScriptName) ... ... "wstr", $sTitle, _ ... ... EndIf1 point
-
This is a deliberate action intended to display an error, as this script demonstrates how to change error handling - interact with MsgBox's title and text.1 point
-
WinRT - WinUI3
WildByDesign reacted to MattyD for a topic
sure thing. - yeah, there are no window handles per se - apart from the WinID of the main window. Everything is done on objects. so that colour change would be something like: $pBrush = CreateSolidBrush("Red") IBorder_SetBackground($apBorders[0], $pBrush) IUnknown_Release($pBrush) In the Sept 3rd. example, to keep things tidy I release the border objects once they're created. So you'd need either need to change the background before releasing, or get the border object back by some other means. Via its parent for example - in this case the grid object (before it too is released!). As for triggering the color change - In this example, once we get into the main loop everything is event based. When we hit the following line the script won't continue until the dispatch loop is broken with _WinUI3_PostQuitMessage. IDispatcherQueue3_RunEventLoop($pDispatchQ) The general idea is to create a bunch of handlers with _WinRT_CreateDelegate(). But if you'd rather work within a while loop, it is possible to create your own dispatcher with _WinUI3_GetMsg / _WinUI3_DispatchMessage. I think there are probably examples of this early in the thread!1 point -
Yep, that could work well. Only drawback is the true use of the dead key misconverted into an accented characters. But it is less an issue when you know what you are doing...1 point
-
To the new approach, (I updated the first post.) I also added the logic of "dead keys", where the accented characters are a combination of 2 keys, a dead key and a vowel.1 point
-
Because working with multiple monitors was required during the development of ImageSearchUDF , this UDF was created UDF: #include-once #include <WinAPIGdi.au3> #include <WinAPISysWin.au3> #include <WindowsConstants.au3> ; =============================================================================================================================== ; Title .........: Monitor UDF ; Description ...: Provides advanced monitor management and multi-monitor utilities. ; Author ........: Dao Van Trong - TRONG.PRO ; Version .......: 2.2 ; Compatibility .: Windows XP SP2 and later (most functions) ; Windows 8.1+ required for GetDpiForMonitor API (automatic fallback on older systems) ; =============================================================================================================================== ; IMPORTANT NOTES: ; - Some functions require Administrator privileges (UAC elevation): ; * _Monitor_Enable() - Requires admin to attach monitor ; * _Monitor_Disable() - Requires admin to detach monitor ; * _Monitor_SetResolution() - Requires admin to change display settings ; * _Monitor_SetPrimary() - Requires admin to set primary monitor ; * _Monitor_SetDisplayMode() - Requires admin to change display mode ; - These functions may not work with proprietary graphics drivers (NVIDIA, AMD control panels) ; - Always test resolution changes before applying permanently ; =============================================================================================================================== ; FUNCTIONS SUMMARY ; =============================================================================================================================== ; ; === CORE MONITOR INFORMATION FUNCTIONS === ; _Monitor_GetList() - Enumerate all connected monitors and initialize global list ; _Monitor_GetCount() - Get total number of connected monitors ; _Monitor_GetPrimary() - Get index of the primary monitor ; _Monitor_GetInfo($iMonitor) - Get detailed information about a specific monitor ; _Monitor_GetBounds($iMonitor, ByRef ...) - Get full monitor rectangle (including taskbar) ; _Monitor_GetWorkArea($iMonitor, ByRef ...) - Get working area (excluding taskbar) ; _Monitor_GetDisplaySettings($iMonitor [, $iMode]) - Get current display mode settings ; _Monitor_GetResolution($iMonitor) - Get monitor resolution (width x height) ; _Monitor_GetVirtualBounds() - Get bounding rectangle of entire virtual screen ; _Monitor_Refresh() - Refresh monitor list (reload from system) ; _Monitor_IsConnected($iMonitor) - Check if monitor is still connected ; _Monitor_ShowInfo([$bShowMsgBox, $iTimeout]) - Display all monitor information ; ; === MONITOR LOCATION & DETECTION FUNCTIONS === ; _Monitor_GetFromPoint([$x, $y]) - Get monitor from screen coordinates or mouse position ; _Monitor_GetFromWindow($hWnd [, $iFlag]) - Get monitor containing a specific window ; _Monitor_GetFromRect($L, $T, $R, $B [, $iFlag]) - Get monitor overlapping a rectangle ; ; === COORDINATE CONVERSION FUNCTIONS === ; _Monitor_ToVirtual($iMonitor, $x, $y) - Convert local monitor coords to virtual coords ; _Monitor_FromVirtual($iMonitor, $x, $y) - Convert virtual coords to local monitor coords ; ; === WINDOW MANAGEMENT FUNCTIONS === ; _Monitor_IsVisibleWindow($hWnd) - Check if window is visible and top-level ; _Monitor_MoveWindowToScreen($vTitle, ...) - Move window to specific monitor (centered) ; _Monitor_MoveWindowToAll($vTitle, ...) - Move window across all monitors sequentially ; ; === DISPLAY MODE ENUMERATION FUNCTIONS === ; _Monitor_EnumAllDisplayModes($iMonitor) - Enumerate all available display modes ; _Monitor_GetDPI($iMonitor) - Get DPI scaling information (Win8.1+) ; _Monitor_GetOrientation($iMonitor) - Get display orientation (0/90/180/270°) ; _Monitor_GetDisplayMode() - Get current display mode (duplicate/extend) ; ; === LAYOUT MANAGEMENT FUNCTIONS === ; _Monitor_GetLayout() - Get current display layout configuration ; _Monitor_GetLayoutDescription() - Get text description of current layout ; _Monitor_SaveLayout($sFilePath) - Save current layout to INI file ; _Monitor_LoadLayout($sFilePath) - Load layout from INI file (does not apply) ; ; === DISPLAY SETTINGS FUNCTIONS (*** REQUIRE ADMINISTRATOR PRIVILEGES ***) === ; _Monitor_Enable($iMonitor) - Enable/attach a disabled monitor [ADMIN] ; _Monitor_Disable($iMonitor) - Disable/detach a monitor [ADMIN] ; _Monitor_SetResolution($iMonitor, $W, $H, ...) - Set monitor resolution and refresh rate [ADMIN] ; _Monitor_SetPrimary($iMonitor) - Set a monitor as primary [ADMIN] ; _Monitor_SetDisplayMode($iMode) - Set display mode (duplicate/extend) [ADMIN] ; ; === INTERNAL/PRIVATE FUNCTIONS (DO NOT CALL DIRECTLY) === ; __Monitor_IsWindowsVersionOrGreater($iMajor, $iMinor) - Check OS version (internal) ; __Monitor_FallbackOSVersionCheck($iMajor, $iMinor) - Fallback OS check (internal) ; __Monitor_IsWindows8_1OrGreater() - Check if Win8.1+ (internal) ; ; =============================================================================================================================== ; USAGE EXAMPLES: ; =============================================================================================================================== ; Example 1: Get basic monitor information ; Local $iMonCount = _Monitor_GetCount() ; Local $iPrimary = _Monitor_GetPrimary() ; ConsoleWrite("Total monitors: " & $iMonCount & ", Primary: " & $iPrimary & @CRLF) ; ; Example 2: Get resolution of monitor 1 ; Local $aRes = _Monitor_GetResolution(1) ; If Not @error Then ConsoleWrite("Resolution: " & $aRes[0] & "x" & $aRes[1] & @CRLF) ; ; Example 3: Move window to monitor 2 (centered) ; _Monitor_MoveWindowToScreen("Notepad", "", 2) ; ; Example 4: Get monitor at mouse position ; Local $iMon = _Monitor_GetFromPoint() ; ConsoleWrite("Mouse is on monitor: " & $iMon & @CRLF) ; ; Example 5: Change resolution (requires admin) ; Local $iResult = _Monitor_SetResolution(1, 1920, 1080, 32, 60) ; If @error Then ConsoleWrite("Failed to set resolution. Error: " & @error & @CRLF) ; ; Example 6: Save and load layout ; _Monitor_SaveLayout(@ScriptDir & "\my_layout.ini") ; Local $aLayout = _Monitor_LoadLayout(@ScriptDir & "\my_layout.ini") ; ; Example 7: Show all monitor information ; _Monitor_ShowInfo(True, 15) ; Show in MsgBox with 15 second timeout ; ; =============================================================================================================================== #Region --- Constants Definition --- ;~ ; System Metrics Constants (Windows XP+) ;~ Global Const $SM_CMONITORS = 80 ;~ Global Const $SM_XVIRTUALSCREEN = 76 ;~ Global Const $SM_YVIRTUALSCREEN = 77 ;~ Global Const $SM_CXVIRTUALSCREEN = 78 ;~ Global Const $SM_CYVIRTUALSCREEN = 79 ;~ ; Monitor Flags (Windows 2000+) ;~ Global Const $MONITOR_DEFAULTTONULL = 0 ;~ Global Const $MONITOR_DEFAULTTOPRIMARY = 1 ;~ Global Const $MONITOR_DEFAULTTONEAREST = 2 ;~ ; EnumDisplaySettings Mode (Windows 95+) ;~ Global Const $ENUM_CURRENT_SETTINGS = -1 ;~ Global Const $ENUM_REGISTRY_SETTINGS = -2 ;~ ; Window Style Constants (Windows 95+) ;~ Global Const $GWL_STYLE = -16 ;~ Global Const $GWL_EXSTYLE = -20 ;~ Global Const $WS_VISIBLE = 0x10000000 ;~ Global Const $WS_CHILD = 0x40000000 ;~ Global Const $WS_EX_TOOLWINDOW = 0x00000080 ; ChangeDisplaySettings Flags (Windows 95+) Global Const $CDS_UPDATEREGISTRY = 0x00000001 Global Const $CDS_TEST = 0x00000002 Global Const $CDS_FULLSCREEN = 0x00000004 Global Const $CDS_GLOBAL = 0x00000008 Global Const $CDS_SET_PRIMARY = 0x00000010 Global Const $CDS_NORESET = 0x10000000 Global Const $CDS_RESET = 0x40000000 ; ChangeDisplaySettings Return Values Global Const $DISP_CHANGE_SUCCESSFUL = 0 Global Const $DISP_CHANGE_RESTART = 1 Global Const $DISP_CHANGE_FAILED = -1 Global Const $DISP_CHANGE_BADMODE = -2 Global Const $DISP_CHANGE_NOTUPDATED = -3 Global Const $DISP_CHANGE_BADFLAGS = -4 Global Const $DISP_CHANGE_BADPARAM = -5 Global Const $DISP_CHANGE_BADDUALVIEW = -6 ;~ ; DEVMODE Field Flags (Windows 95+) ;~ Global Const $DM_ORIENTATION = 0x00000001 ;~ Global Const $DM_PAPERSIZE = 0x00000002 ;~ Global Const $DM_PAPERLENGTH = 0x00000004 ;~ Global Const $DM_PAPERWIDTH = 0x00000008 ;~ Global Const $DM_POSITION = 0x00000020 ;~ Global Const $DM_DISPLAYORIENTATION = 0x00000080 ;~ Global Const $DM_DISPLAYFIXEDOUTPUT = 0x20000000 ;~ Global Const $DM_BITSPERPEL = 0x00040000 ;~ Global Const $DM_PELSWIDTH = 0x00080000 ;~ Global Const $DM_PELSHEIGHT = 0x00100000 ;~ Global Const $DM_DISPLAYFLAGS = 0x00200000 ;~ Global Const $DM_DISPLAYFREQUENCY = 0x00400000 #EndRegion --- Constants Definition --- #Region --- Global Variables --- ; =============================================================================================================================== ; Global Monitor Information Array ; =============================================================================================================================== ; $__g_aMonitorList[][] structure: ; ; [0][0] = Number of monitors detected ; [0][1] = Virtual desktop Left coordinate (combined area) ; [0][2] = Virtual desktop Top coordinate ; [0][3] = Virtual desktop Right coordinate ; [0][4] = Virtual desktop Bottom coordinate ; [0][5] = Virtual desktop Width ; [0][6] = Virtual desktop Height ; ; For each monitor index i (1..$__g_aMonitorList[0][0]): ; [i][0] = Monitor handle (HMONITOR) ; [i][1] = Left coordinate of monitor ; [i][2] = Top coordinate of monitor ; [i][3] = Right coordinate of monitor ; [i][4] = Bottom coordinate of monitor ; [i][5] = IsPrimary (1 if primary, 0 otherwise) ; [i][6] = Device name string (e.g. "\\.\DISPLAY1") ; ; =============================================================================================================================== Global $__g_aMonitorList[1][7] = [[0, 0, 0, 0, 0, 0, ""]] #EndRegion --- Global Variables --- #Region --- OS Compatibility Functions --- ; #FUNCTION# ==================================================================================================================== ; Name...........: __Monitor_IsWindowsVersionOrGreater ; Description....: Check if running on Windows version or greater (internal function) ; Syntax.........: __Monitor_IsWindowsVersionOrGreater($iMajor, $iMinor = 0) ; Parameters.....: $iMajor - Major version number (e.g., 6 for Vista, 10 for Windows 10) ; $iMinor - [optional] Minor version number. Default is 0 ; Return values..: True if OS version is equal or greater, False otherwise ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Internal function for OS compatibility checking. Uses GetVersionEx API directly for accurate ; version detection, works on all AutoIt versions (even old ones where @OSVersion may be inaccurate). ; Windows XP = 5.1, Vista = 6.0, Win7 = 6.1, Win8 = 6.2, Win8.1 = 6.3, Win10 = 10.0 ; ================================================================================================================================ Func __Monitor_IsWindowsVersionOrGreater($iMajor, $iMinor = 0) ; Use GetVersionEx API directly (works on all Windows versions and all AutoIt versions) ; This is more reliable than @OSVersion which may not be accurate on old AutoIt versions ; Define OSVERSIONINFOEX structure Local $tOSVI = DllStructCreate("dword;dword;dword;dword;dword;wchar[128];ushort;ushort;ushort;byte;byte") If @error Then Return __Monitor_FallbackOSVersionCheck($iMajor, $iMinor) ; Set structure size (first field) DllStructSetData($tOSVI, 1, DllStructGetSize($tOSVI)) ; Call GetVersionExW (Unicode version, available from Windows 2000+) Local $aRet = DllCall("kernel32.dll", "bool", "GetVersionExW", "struct*", $tOSVI) If @error Or Not IsArray($aRet) Or Not $aRet[0] Then ; Fallback: Try ANSI version GetVersionExA (available from Windows 95+) Local $tOSVIA = DllStructCreate("dword;dword;dword;dword;dword;char[128];ushort;ushort;ushort;byte;byte") If @error Then Return __Monitor_FallbackOSVersionCheck($iMajor, $iMinor) DllStructSetData($tOSVIA, 1, DllStructGetSize($tOSVIA)) $aRet = DllCall("kernel32.dll", "bool", "GetVersionExA", "struct*", $tOSVIA) If @error Or Not IsArray($aRet) Or Not $aRet[0] Then Return __Monitor_FallbackOSVersionCheck($iMajor, $iMinor) EndIf ; Use ANSI version data Local $iOSMajor = DllStructGetData($tOSVIA, 2) Local $iOSMinor = DllStructGetData($tOSVIA, 3) ; Compare versions If $iOSMajor > $iMajor Then Return True If $iOSMajor = $iMajor And $iOSMinor >= $iMinor Then Return True Return False EndIf ; Get version from structure (Unicode version) Local $iOSMajor = DllStructGetData($tOSVI, 2) Local $iOSMinor = DllStructGetData($tOSVI, 3) ; Handle Windows 10/11: GetVersionEx may return 6.3 for compatibility ; Check build number to distinguish Windows 10/11 from 8.1 Local $iBuildNumber = DllStructGetData($tOSVI, 4) If $iOSMajor = 6 And $iOSMinor = 3 And $iBuildNumber >= 10000 Then ; Windows 10/11 (build number >= 10000) $iOSMajor = 10 $iOSMinor = 0 EndIf ; Compare versions If $iOSMajor > $iMajor Then Return True If $iOSMajor = $iMajor And $iOSMinor >= $iMinor Then Return True Return False EndFunc ;==>__Monitor_IsWindowsVersionOrGreater ; #FUNCTION# ==================================================================================================================== ; Name...........: __Monitor_FallbackOSVersionCheck ; Description....: Fallback OS version check using @OSVersion macro (internal function) ; Syntax.........: __Monitor_FallbackOSVersionCheck($iMajor, $iMinor) ; Parameters.....: $iMajor - Major version number ; $iMinor - Minor version number ; Return values..: True if OS version is equal or greater, False otherwise ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Used only when GetVersionEx API fails. Less reliable than API call. ; ================================================================================================================================ Func __Monitor_FallbackOSVersionCheck($iMajor, $iMinor) ; Fallback to @OSVersion (may be inaccurate on old AutoIt versions, but better than nothing) Local $sOSVersion = @OSVersion Local $iOSMajor = 5, $iOSMinor = 1 ; Default to XP If StringInStr($sOSVersion, "WIN_11") Then $iOSMajor = 10 $iOSMinor = 0 ElseIf StringInStr($sOSVersion, "WIN_10") Then $iOSMajor = 10 $iOSMinor = 0 ElseIf StringInStr($sOSVersion, "WIN_8") Then ; Use @OSBuild to distinguish 8.0 vs 8.1 (8.1 has build >= 9600) If @OSBuild >= 9600 Then $iOSMajor = 6 $iOSMinor = 3 ; Windows 8.1 Else $iOSMajor = 6 $iOSMinor = 2 ; Windows 8 EndIf ElseIf StringInStr($sOSVersion, "WIN_7") Then $iOSMajor = 6 $iOSMinor = 1 ElseIf StringInStr($sOSVersion, "WIN_VISTA") Then $iOSMajor = 6 $iOSMinor = 0 ElseIf StringInStr($sOSVersion, "WIN_XP") Then $iOSMajor = 5 $iOSMinor = 1 ElseIf StringInStr($sOSVersion, "WIN_2003") Then $iOSMajor = 5 $iOSMinor = 2 EndIf ; Compare versions If $iOSMajor > $iMajor Then Return True If $iOSMajor = $iMajor And $iOSMinor >= $iMinor Then Return True Return False EndFunc ;==>__Monitor_FallbackOSVersionCheck ; #FUNCTION# ==================================================================================================================== ; Name...........: __Monitor_IsWindows8_1OrGreater ; Description....: Check if running on Windows 8.1 or greater (internal function) ; Syntax.........: __Monitor_IsWindows8_1OrGreater() ; Parameters.....: None ; Return values..: True if Windows 8.1 or greater, False otherwise ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Internal function for checking if GetDpiForMonitor API is available ; ================================================================================================================================ Func __Monitor_IsWindows8_1OrGreater() ; FIXED: Improved logic to correctly detect Windows 8.1+ Local $tOSVI = DllStructCreate("dword;dword;dword;dword;dword;wchar[128];ushort;ushort;ushort;byte;byte") If @error Then Return __Monitor_IsWindowsVersionOrGreater(6, 3) DllStructSetData($tOSVI, 1, DllStructGetSize($tOSVI)) Local $aRet = DllCall("kernel32.dll", "bool", "GetVersionExW", "struct*", $tOSVI) If @error Or Not IsArray($aRet) Or Not $aRet[0] Then Return __Monitor_IsWindowsVersionOrGreater(6, 3) EndIf Local $iOSMajor = DllStructGetData($tOSVI, 2) Local $iOSMinor = DllStructGetData($tOSVI, 3) Local $iBuildNumber = DllStructGetData($tOSVI, 4) ; FIXED: Correct logic for Windows 8.1+ detection ; Windows 10+ has major >= 10 If $iOSMajor > 6 Then Return True ; Windows 8.1+ has major=6 AND minor>=3 If $iOSMajor = 6 And $iOSMinor > 3 Then Return True ; Windows 8.1 exactly has major=6 AND minor=3 AND build>=9600 If $iOSMajor = 6 And $iOSMinor = 3 And $iBuildNumber >= 9600 Then Return True Return False EndFunc ;==>__Monitor_IsWindows8_1OrGreater #EndRegion --- OS Compatibility Functions --- #Region --- Core Monitor Functions --- ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_GetFromPoint ; Description....: Get the monitor index from a screen coordinate or current mouse position ; Syntax.........: _Monitor_GetFromPoint([$iX = -1 [, $iY = -1]]) ; Parameters.....: $iX - [optional] X coordinate in virtual screen coordinates. Default is -1 (use mouse position) ; $iY - [optional] Y coordinate in virtual screen coordinates. Default is -1 (use mouse position) ; Return values..: Success - Monitor index (1..N) ; Failure - 0, sets @error to non-zero: ; |@error = 1 - Invalid parameters or MouseGetPos failed ; |@error = 2 - Monitor not found at specified coordinates ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: If both $iX and $iY are -1 (default), function uses current mouse position. ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_GetList, _Monitor_GetFromWindow, _Monitor_GetFromRect ; ================================================================================================================================ Func _Monitor_GetFromPoint($iX = -1, $iY = -1) If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() ; Use WinAPI function if available If $iX = -1 Or $iY = -1 Then Local $aMouse = MouseGetPos() If @error Then Return SetError(1, 0, 0) $iX = $aMouse[0] $iY = $aMouse[1] EndIf Local $tPoint = DllStructCreate($tagPOINT) If @error Then Return SetError(1, 0, 0) DllStructSetData($tPoint, "X", $iX) DllStructSetData($tPoint, "Y", $iY) Local $hMonitor = _WinAPI_MonitorFromPoint($tPoint, $MONITOR_DEFAULTTONEAREST) If @error Then $hMonitor = 0 EndIf ; Find index in our list For $i = 1 To $__g_aMonitorList[0][0] If $__g_aMonitorList[$i][0] = $hMonitor Then Return $i Next ; Fallback to coordinate checking For $i = 1 To $__g_aMonitorList[0][0] If $iX >= $__g_aMonitorList[$i][1] _ And $iX < $__g_aMonitorList[$i][3] _ And $iY >= $__g_aMonitorList[$i][2] _ And $iY < $__g_aMonitorList[$i][4] Then Return $i EndIf Next Return SetError(2, 0, 0) EndFunc ;==>_Monitor_GetFromPoint ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_GetFromWindow ; Description....: Get the monitor index that contains the specified window ; Syntax.........: _Monitor_GetFromWindow($hWnd [, $iFlag = $MONITOR_DEFAULTTONEAREST]) ; Parameters.....: $hWnd - Window handle or title string. Can be HWND or window title ; $iFlag - [optional] Monitor flag. Default is $MONITOR_DEFAULTTONEAREST ; Can be: $MONITOR_DEFAULTTONULL, $MONITOR_DEFAULTTOPRIMARY, $MONITOR_DEFAULTTONEAREST ; Return values..: Success - Monitor index (1..N) ; Failure - 0, sets @error to non-zero: ; |@error = 1 - Invalid window handle or window not found ; |@error = 2 - WinAPI MonitorFromWindow call failed ; |@error = 3 - Monitor handle not found in internal list ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Function accepts both window handles and window titles. Automatically converts title to handle. ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_GetList, _Monitor_GetFromPoint, _Monitor_GetFromRect ; ================================================================================================================================ Func _Monitor_GetFromWindow($hWnd, $iFlag = $MONITOR_DEFAULTTONEAREST) If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() If Not IsHWnd($hWnd) Then $hWnd = WinGetHandle($hWnd) If Not $hWnd Then Return SetError(1, 0, 0) Local $hMonitor = _WinAPI_MonitorFromWindow($hWnd, $iFlag) If @error Or Not $hMonitor Then Return SetError(2, 0, 0) For $i = 1 To $__g_aMonitorList[0][0] If $__g_aMonitorList[$i][0] = $hMonitor Then Return $i Next Return SetError(3, 0, 0) EndFunc ;==>_Monitor_GetFromWindow ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_GetFromRect ; Description....: Get the monitor index that has the largest intersection with the specified rectangle ; Syntax.........: _Monitor_GetFromRect($iLeft, $iTop, $iRight, $iBottom [, $iFlag = $MONITOR_DEFAULTTONEAREST]) ; Parameters.....: $iLeft - Left coordinate of the rectangle in virtual screen coordinates ; $iTop - Top coordinate of the rectangle in virtual screen coordinates ; $iRight - Right coordinate of the rectangle in virtual screen coordinates ; $iBottom - Bottom coordinate of the rectangle in virtual screen coordinates ; $iFlag - [optional] Monitor flag. Default is $MONITOR_DEFAULTTONEAREST ; Can be: $MONITOR_DEFAULTTONULL, $MONITOR_DEFAULTTOPRIMARY, $MONITOR_DEFAULTTONEAREST ; Return values..: Success - Monitor index (1..N) ; Failure - 0, sets @error to non-zero: ; |@error = 1 - DllStructCreate failed or WinAPI MonitorFromRect call failed ; |@error = 2 - Monitor not found in internal list ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Coordinates should be in virtual screen coordinate system (can span multiple monitors). ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_GetList, _Monitor_GetFromPoint, _Monitor_GetFromWindow ; ================================================================================================================================ Func _Monitor_GetFromRect($iLeft, $iTop, $iRight, $iBottom, $iFlag = $MONITOR_DEFAULTTONEAREST) If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() Local $tRect = DllStructCreate($tagRECT) If @error Then Return SetError(1, 0, 0) DllStructSetData($tRect, "Left", $iLeft) DllStructSetData($tRect, "Top", $iTop) DllStructSetData($tRect, "Right", $iRight) DllStructSetData($tRect, "Bottom", $iBottom) Local $hMonitor = _WinAPI_MonitorFromRect($tRect, $iFlag) If @error Or Not $hMonitor Then Return SetError(1, 0, 0) For $i = 1 To $__g_aMonitorList[0][0] If $__g_aMonitorList[$i][0] = $hMonitor Then Return $i Next Return SetError(2, 0, 0) EndFunc ;==>_Monitor_GetFromRect ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_GetWorkArea ; Description....: Get working area of a specific monitor (excluding taskbar and system bars) ; Syntax.........: _Monitor_GetWorkArea($iMonitor, ByRef $left, ByRef $top, ByRef $right, ByRef $bottom) ; Parameters.....: $iMonitor - Monitor index (1..N) ; $left - [out] Left coordinate of work area (virtual screen coordinates) ; $top - [out] Top coordinate of work area (virtual screen coordinates) ; $right - [out] Right coordinate of work area (virtual screen coordinates) ; $bottom - [out] Bottom coordinate of work area (virtual screen coordinates) ; Return values..: Success - 1 ; Failure - 0, sets @error to non-zero: ; |@error = 1 - Invalid monitor index ; |@error = 2 - WinAPI GetMonitorInfo call failed ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Work area excludes taskbar and other system bars. Use _Monitor_GetBounds() for full monitor area. ; All coordinates are in virtual screen coordinate system. ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_GetBounds, _Monitor_GetInfo, _Monitor_GetList ; ================================================================================================================================ Func _Monitor_GetWorkArea($iMonitor, ByRef $left, ByRef $top, ByRef $right, ByRef $bottom) If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, 0) Local $hMonitor = $__g_aMonitorList[$iMonitor][0] Local $aInfo = _WinAPI_GetMonitorInfo($hMonitor) If @error Or Not IsArray($aInfo) Then Return SetError(2, 0, 0) Local $tWorkArea = $aInfo[1] If Not IsDllStruct($tWorkArea) Then Return SetError(2, 0, 0) $left = DllStructGetData($tWorkArea, "Left") $top = DllStructGetData($tWorkArea, "Top") $right = DllStructGetData($tWorkArea, "Right") $bottom = DllStructGetData($tWorkArea, "Bottom") Return 1 EndFunc ;==>_Monitor_GetWorkArea ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_GetBounds ; Description....: Get full bounds of a specific monitor (including taskbar and all system areas) ; Syntax.........: _Monitor_GetBounds($iMonitor, ByRef $left, ByRef $top, ByRef $right, ByRef $bottom) ; Parameters.....: $iMonitor - Monitor index (1..N) ; $left - [out] Left coordinate of monitor (virtual screen coordinates) ; $top - [out] Top coordinate of monitor (virtual screen coordinates) ; $right - [out] Right coordinate of monitor (virtual screen coordinates) ; $bottom - [out] Bottom coordinate of monitor (virtual screen coordinates) ; Return values..: Success - 1 ; Failure - 0, sets @error = 1 (Invalid monitor index) ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Returns the full physical bounds of the monitor including all system bars (taskbar, etc.). ; All coordinates are in virtual screen coordinate system. ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; For usable area excluding taskbar, use _Monitor_GetWorkArea() instead. ; Related........: _Monitor_GetWorkArea, _Monitor_GetInfo, _Monitor_GetList ; ================================================================================================================================ Func _Monitor_GetBounds($iMonitor, ByRef $left, ByRef $top, ByRef $right, ByRef $bottom) If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, 0) $left = $__g_aMonitorList[$iMonitor][1] $top = $__g_aMonitorList[$iMonitor][2] $right = $__g_aMonitorList[$iMonitor][3] $bottom = $__g_aMonitorList[$iMonitor][4] Return 1 EndFunc ;==>_Monitor_GetBounds ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_GetInfo ; Description....: Get detailed information about a monitor ; Syntax.........: _Monitor_GetInfo($iMonitor) ; Parameters.....: $iMonitor - Monitor index (1..N) ; Return values..: Success - Array with 11 elements: ; |[0] - Monitor handle (HMONITOR) ; |[1] - Left coordinate of monitor bounds (virtual screen coordinates) ; |[2] - Top coordinate of monitor bounds (virtual screen coordinates) ; |[3] - Right coordinate of monitor bounds (virtual screen coordinates) ; |[4] - Bottom coordinate of monitor bounds (virtual screen coordinates) ; |[5] - Left coordinate of work area (virtual screen coordinates) ; |[6] - Top coordinate of work area (virtual screen coordinates) ; |[7] - Right coordinate of work area (virtual screen coordinates) ; |[8] - Bottom coordinate of work area (virtual screen coordinates) ; |[9] - IsPrimary flag (1 = Primary, 0 = Secondary) ; |[10] - Device name string (e.g., "\\.\DISPLAY1") ; Failure - 0, sets @error to non-zero: ; |@error = 1 - Invalid monitor index ; |@error = 2 - WinAPI GetMonitorInfo call failed ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: This is the most comprehensive function to get all monitor information at once. ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_GetList, _Monitor_GetBounds, _Monitor_GetWorkArea, _Monitor_GetPrimary ; ================================================================================================================================ Func _Monitor_GetInfo($iMonitor) If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, 0) Local $hMonitor = $__g_aMonitorList[$iMonitor][0] Local $aInfo = _WinAPI_GetMonitorInfo($hMonitor) If @error Or Not IsArray($aInfo) Then Return SetError(2, 0, 0) Local $tMonitorRect = $aInfo[0] Local $tWorkRect = $aInfo[1] If Not IsDllStruct($tMonitorRect) Or Not IsDllStruct($tWorkRect) Then Return SetError(2, 0, 0) Local $aResult[11] $aResult[0] = $hMonitor $aResult[1] = DllStructGetData($tMonitorRect, "Left") $aResult[2] = DllStructGetData($tMonitorRect, "Top") $aResult[3] = DllStructGetData($tMonitorRect, "Right") $aResult[4] = DllStructGetData($tMonitorRect, "Bottom") $aResult[5] = DllStructGetData($tWorkRect, "Left") $aResult[6] = DllStructGetData($tWorkRect, "Top") $aResult[7] = DllStructGetData($tWorkRect, "Right") $aResult[8] = DllStructGetData($tWorkRect, "Bottom") $aResult[9] = ($aInfo[2] <> 0) ; IsPrimary $aResult[10] = $aInfo[3] ; DeviceName Return $aResult EndFunc ;==>_Monitor_GetInfo ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_GetDisplaySettings ; Description....: Get display settings for a monitor (resolution, color depth, refresh rate, etc.) ; Syntax.........: _Monitor_GetDisplaySettings($iMonitor [, $iMode = $ENUM_CURRENT_SETTINGS]) ; Parameters.....: $iMonitor - Monitor index (1..N) ; $iMode - [optional] Display mode index. Default is $ENUM_CURRENT_SETTINGS ; Use $ENUM_CURRENT_SETTINGS to get current active settings ; Use index number (0..N) to enumerate available modes ; Return values..: Success - Array with 5 elements: ; |[0] - Width (pixels) ; |[1] - Height (pixels) ; |[2] - Bits per pixel (color depth) ; |[3] - Refresh rate (Hz) ; |[4] - Display mode flags ; Failure - 0, sets @error to non-zero: ; |@error = 1 - Invalid monitor index ; |@error = 2 - GetInfo failed (could not get device name) ; |@error = 3 - WinAPI EnumDisplaySettings call failed ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Use $ENUM_CURRENT_SETTINGS to get the currently active display mode. ; Use _Monitor_EnumAllDisplayModes() to get all available display modes. ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_GetResolution, _Monitor_EnumAllDisplayModes, _Monitor_GetList ; ================================================================================================================================ Func _Monitor_GetDisplaySettings($iMonitor, $iMode = $ENUM_CURRENT_SETTINGS) If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, 0) Local $sDevice = $__g_aMonitorList[$iMonitor][6] If $sDevice = "" Then Local $aInfo = _Monitor_GetInfo($iMonitor) If @error Then Return SetError(2, 0, 0) $sDevice = $aInfo[10] EndIf Local $aSettings = _WinAPI_EnumDisplaySettings($sDevice, $iMode) If @error Or Not IsArray($aSettings) Then Return SetError(3, 0, 0) Return $aSettings EndFunc ;==>_Monitor_GetDisplaySettings ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_GetResolution ; Description....: Get the current resolution (width and height) of a monitor ; Syntax.........: _Monitor_GetResolution($iMonitor) ; Parameters.....: $iMonitor - Monitor index (1..N) ; Return values..: Success - Array with 2 elements: ; |[0] - Width in pixels ; |[1] - Height in pixels ; Failure - 0, sets @error to non-zero: ; |@error = 1 - Invalid monitor index ; |@error = 2 - GetDisplaySettings failed ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: This is a convenience function that returns only width and height from display settings. ; For full display settings (color depth, refresh rate, etc.), use _Monitor_GetDisplaySettings(). ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_GetDisplaySettings, _Monitor_GetInfo, _Monitor_GetList ; ================================================================================================================================ Func _Monitor_GetResolution($iMonitor) If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, 0) Local $aSettings = _Monitor_GetDisplaySettings($iMonitor) If @error Then Return SetError(2, @error, 0) Local $aResult[2] = [$aSettings[0], $aSettings[1]] Return $aResult EndFunc ;==>_Monitor_GetResolution ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_GetPrimary ; Description....: Get the index of the primary monitor ; Syntax.........: _Monitor_GetPrimary() ; Parameters.....: None ; Return values..: Success - Monitor index (1..N) of the primary monitor ; Failure - 0, sets @error = 1 (No primary monitor found) ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Primary monitor is the monitor that contains the taskbar by default in Windows. ; Function first checks cached IsPrimary flags, then falls back to querying system if needed. ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_GetList, _Monitor_GetInfo, _Monitor_GetCount ; ================================================================================================================================ Func _Monitor_GetPrimary() If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() ; Use cached IsPrimary flag if available For $i = 1 To $__g_aMonitorList[0][0] If $__g_aMonitorList[$i][5] = 1 Then Return $i Next ; Fallback: query from system For $i = 1 To $__g_aMonitorList[0][0] Local $aInfo = _Monitor_GetInfo($i) If Not @error And $aInfo[9] = 1 Then Return $i Next Return SetError(1, 0, 0) EndFunc ;==>_Monitor_GetPrimary ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_GetCount ; Description....: Returns the total number of connected monitors ; Syntax.........: _Monitor_GetCount() ; Parameters.....: None ; Return values..: Success - Number of monitors (>= 1) ; Failure - 0, sets @error = 1 (Enumeration failed) ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Function first tries GetSystemMetrics API for fastest response. ; Falls back to cached monitor list if API call fails. ; Automatically validates and refreshes monitor list if count mismatch detected. ; Related........: _Monitor_GetList, _Monitor_Refresh, _Monitor_GetPrimary ; ================================================================================================================================ Func _Monitor_GetCount() ; FIXED: Check @error after each DllCall separately Local $aRet = DllCall("user32.dll", "int", "GetSystemMetrics", "int", $SM_CMONITORS) If @error Then ; Fallback to our cached list If $__g_aMonitorList[0][0] = 0 Then If _Monitor_GetList() = -1 Then Return SetError(1, 0, 0) EndIf Return $__g_aMonitorList[0][0] EndIf If Not IsArray($aRet) Or $aRet[0] < 1 Then ; Fallback to our cached list If $__g_aMonitorList[0][0] = 0 Then If _Monitor_GetList() = -1 Then Return SetError(1, 0, 0) EndIf Return $__g_aMonitorList[0][0] Else ; Validate count matches our list (refresh if needed) If $__g_aMonitorList[0][0] <> $aRet[0] Then _Monitor_GetList() EndIf Return $aRet[0] EndIf EndFunc ;==>_Monitor_GetCount ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_GetVirtualBounds ; Description....: Get bounding rectangle of all monitors combined (the "virtual screen") ; Syntax.........: _Monitor_GetVirtualBounds() ; Parameters.....: None ; Return values..: Success - Array with 4 elements: ; |[0] - Left coordinate of virtual screen ; |[1] - Top coordinate of virtual screen ; |[2] - Width of virtual screen in pixels ; |[3] - Height of virtual screen in pixels ; Failure - 0, sets @error = 1 (DllCall failed) ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Virtual screen is the bounding rectangle that encompasses all connected monitors. ; Function uses GetSystemMetrics API. Falls back to cached virtual bounds if API fails. ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_GetList, _Monitor_GetBounds, _Monitor_GetCount ; ================================================================================================================================ Func _Monitor_GetVirtualBounds() ; FIXED: Check @error after each DllCall separately Local $aL = DllCall("user32.dll", "int", "GetSystemMetrics", "int", $SM_XVIRTUALSCREEN) Local $bErrorL = @error Local $aT = DllCall("user32.dll", "int", "GetSystemMetrics", "int", $SM_YVIRTUALSCREEN) Local $bErrorT = @error Local $aW = DllCall("user32.dll", "int", "GetSystemMetrics", "int", $SM_CXVIRTUALSCREEN) Local $bErrorW = @error Local $aH = DllCall("user32.dll", "int", "GetSystemMetrics", "int", $SM_CYVIRTUALSCREEN) Local $bErrorH = @error ; Validate all calls succeeded Local $bError = False If $bErrorL Or $bErrorT Or $bErrorW Or $bErrorH Then $bError = True If Not IsArray($aL) Or Not IsArray($aT) Or Not IsArray($aW) Or Not IsArray($aH) Then $bError = True If $bError Then ; Fallback to cached virtual bounds If $__g_aMonitorList[0][0] = 0 Then If _Monitor_GetList() = -1 Then Return SetError(1, 0, 0) EndIf Local $aRet[4] = [$__g_aMonitorList[0][1], $__g_aMonitorList[0][2], $__g_aMonitorList[0][5], $__g_aMonitorList[0][6]] Return $aRet EndIf ; Validate returned values are reasonable If $aL[0] < -32768 Or $aT[0] < -32768 Or $aW[0] < 1 Or $aH[0] < 1 Then ; Invalid values, use fallback If $__g_aMonitorList[0][0] = 0 Then If _Monitor_GetList() = -1 Then Return SetError(1, 0, 0) EndIf Local $aRet[4] = [$__g_aMonitorList[0][1], $__g_aMonitorList[0][2], $__g_aMonitorList[0][5], $__g_aMonitorList[0][6]] Return $aRet EndIf Local $a[4] = [$aL[0], $aT[0], $aW[0], $aH[0]] Return $a EndFunc ;==>_Monitor_GetVirtualBounds ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_ToVirtual ; Description....: Convert local monitor coordinates to virtual screen coordinates ; Syntax.........: _Monitor_ToVirtual($iMonitor, $x, $y) ; Parameters.....: $iMonitor - Monitor index (1..N) ; $x - X coordinate in local monitor coordinates (0-based from monitor's left edge) ; $y - Y coordinate in local monitor coordinates (0-based from monitor's top edge) ; Return values..: Success - Array with 2 elements [X, Y] in virtual screen coordinates ; Failure - 0, sets @error = 1 (Invalid monitor index) ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Local coordinates are relative to the monitor (0,0 is top-left of that monitor). ; Virtual coordinates are absolute in the virtual screen coordinate system. ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_FromVirtual, _Monitor_GetBounds, _Monitor_GetList ; ================================================================================================================================ Func _Monitor_ToVirtual($iMonitor, $x, $y) If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, 0) Local $aRet[2] = [$__g_aMonitorList[$iMonitor][1] + $x, $__g_aMonitorList[$iMonitor][2] + $y] Return $aRet EndFunc ;==>_Monitor_ToVirtual ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_FromVirtual ; Description....: Convert virtual screen coordinates back to local monitor coordinates ; Syntax.........: _Monitor_FromVirtual($iMonitor, $x, $y) ; Parameters.....: $iMonitor - Monitor index (1..N) ; $x - X coordinate in virtual screen coordinates ; $y - Y coordinate in virtual screen coordinates ; Return values..: Success - Array with 2 elements [X, Y] in local monitor coordinates (0-based) ; Failure - 0, sets @error to non-zero: ; |@error = 1 - Invalid monitor index ; |@error = 2 - Coordinates are not within the specified monitor's bounds ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Local coordinates are relative to the monitor (0,0 is top-left of that monitor). ; Virtual coordinates are absolute in the virtual screen coordinate system. ; Function validates that coordinates are actually on the specified monitor. ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_ToVirtual, _Monitor_GetBounds, _Monitor_GetList ; ================================================================================================================================ Func _Monitor_FromVirtual($iMonitor, $x, $y) If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, 0) ; Validate coordinates are on this monitor If $x < $__g_aMonitorList[$iMonitor][1] Or $x >= $__g_aMonitorList[$iMonitor][3] _ Or $y < $__g_aMonitorList[$iMonitor][2] Or $y >= $__g_aMonitorList[$iMonitor][4] Then Return SetError(2, 0, 0) EndIf Local $aRet[2] = [$x - $__g_aMonitorList[$iMonitor][1], $y - $__g_aMonitorList[$iMonitor][2]] Return $aRet EndFunc ;==>_Monitor_FromVirtual #EndRegion --- Core Monitor Functions --- #Region --- Window Management Functions --- ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_IsVisibleWindow ; Description....: Check if a window is visible and is a top-level window (not a child window or tool window) ; Syntax.........: _Monitor_IsVisibleWindow($hWnd) ; Parameters.....: $hWnd - Window handle or title string. Can be HWND or window title ; Return values..: Success - True if window is visible and top-level, False otherwise ; Failure - False, sets @error = 1 (Invalid window handle) ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Function checks for: WS_VISIBLE flag, not WS_CHILD, and not WS_EX_TOOLWINDOW. ; Accepts both window handles and window titles. Automatically converts title to handle. ; This is useful for filtering which windows should be moved between monitors. ; Related........: _Monitor_MoveWindowToScreen, _Monitor_GetFromWindow ; ================================================================================================================================ Func _Monitor_IsVisibleWindow($hWnd) If Not IsHWnd($hWnd) Then $hWnd = WinGetHandle($hWnd) If Not $hWnd Or Not WinExists($hWnd) Then Return SetError(1, 0, False) Local $style = _WinAPI_GetWindowLong($hWnd, $GWL_STYLE) If @error Then Return SetError(1, 0, False) If BitAND($style, $WS_VISIBLE) = 0 Then Return False If BitAND($style, $WS_CHILD) <> 0 Then Return False Local $ex = _WinAPI_GetWindowLong($hWnd, $GWL_EXSTYLE) If @error Then Return False If BitAND($ex, $WS_EX_TOOLWINDOW) <> 0 Then Return False Return True EndFunc ;==>_Monitor_IsVisibleWindow ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_MoveWindowToScreen ; Description....: Move a visible window to a specific monitor (centered if coordinates not specified) ; Syntax.........: _Monitor_MoveWindowToScreen($vTitle [, $sText = "" [, $iMonitor = -1 [, $x = -1 [, $y = -1 [, $bUseWorkArea = True]]]]]) ; Parameters.....: $vTitle - Window title or handle. Can be HWND, title string, or class string ; $sText - [optional] Window text (for matching with title). Default is "" ; $iMonitor - [optional] Target monitor index (1..N). Default is -1 (uses monitor 1) ; $x - [optional] X position on monitor. Default is -1 (centers horizontally) ; $y - [optional] Y position on monitor. Default is -1 (centers vertically) ; $bUseWorkArea - [optional] Use work area instead of full bounds. Default is True ; Return values..: Success - 1 ; Failure - 0, sets @error to non-zero: ; |@error = 1 - Window not visible or not top-level ; |@error = 2 - Invalid monitor index or GetWorkArea/GetBounds failed ; |@error = 3 - WinGetPos failed (could not get window position/size) ; |@error = 4 - Window too large to fit on monitor ; |@error = 5 - WinMove failed ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: If both $x and $y are -1, window is centered on the monitor. ; If $bUseWorkArea is True, positioning is relative to work area (excludes taskbar). ; Function ensures window stays within monitor bounds (adjusts if necessary). ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_MoveWindowToAll, _Monitor_IsVisibleWindow, _Monitor_GetWorkArea, _Monitor_GetBounds ; ================================================================================================================================ Func _Monitor_MoveWindowToScreen($vTitle, $sText = "", $iMonitor = -1, $x = -1, $y = -1, $bUseWorkArea = True) Local $hWnd = IsHWnd($vTitle) ? $vTitle : WinGetHandle($vTitle, $sText) If Not _Monitor_IsVisibleWindow($hWnd) Then Return SetError(1, 0, 0) If $iMonitor = -1 Then $iMonitor = 1 If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(2, 0, 0) Local $aWinPos = WinGetPos($hWnd) If @error Or Not IsArray($aWinPos) Then Return SetError(3, 0, 0) Local $iLeft, $iTop, $iRight, $iBottom If $bUseWorkArea Then If Not _Monitor_GetWorkArea($iMonitor, $iLeft, $iTop, $iRight, $iBottom) Then Return SetError(2, @error, 0) Else If Not _Monitor_GetBounds($iMonitor, $iLeft, $iTop, $iRight, $iBottom) Then Return SetError(2, @error, 0) EndIf Local $iWidth = $iRight - $iLeft Local $iHeight = $iBottom - $iTop ; Check if window fits on monitor If $aWinPos[2] > $iWidth Or $aWinPos[3] > $iHeight Then Return SetError(4, 0, 0) EndIf If $x = -1 Or $y = -1 Then $x = $iLeft + ($iWidth - $aWinPos[2]) / 2 $y = $iTop + ($iHeight - $aWinPos[3]) / 2 Else $x += $iLeft $y += $iTop ; Ensure window stays within bounds If $x + $aWinPos[2] > $iRight Then $x = $iRight - $aWinPos[2] If $y + $aWinPos[3] > $iBottom Then $y = $iBottom - $aWinPos[3] If $x < $iLeft Then $x = $iLeft If $y < $iTop Then $y = $iTop EndIf WinMove($hWnd, "", $x, $y) If @error Then Return SetError(5, 0, 0) Return 1 EndFunc ;==>_Monitor_MoveWindowToScreen ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_MoveWindowToAll ; Description....: Move a visible window sequentially across all monitors with a delay between moves ; Syntax.........: _Monitor_MoveWindowToAll($vTitle [, $sText = "" [, $bCenter = True [, $iDelay = 1000]]]) ; Parameters.....: $vTitle - Window title or handle. Can be HWND, title string, or class string ; $sText - [optional] Window text (for matching with title). Default is "" ; $bCenter - [optional] Center window on each monitor. Default is True ; If False, window is positioned at (50, 50) on each monitor ; $iDelay - [optional] Delay in milliseconds between moves. Default is 1000 ; Return values..: Success - 1 ; Failure - 0, sets @error = 1 (Window not visible or not top-level) ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: This is a demonstration function that moves a window to each monitor in sequence. ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Useful for testing multi-monitor setups or demonstrating window movement. ; Related........: _Monitor_MoveWindowToScreen, _Monitor_IsVisibleWindow, _Monitor_GetCount ; ================================================================================================================================ Func _Monitor_MoveWindowToAll($vTitle, $sText = "", $bCenter = True, $iDelay = 1000) Local $hWnd = IsHWnd($vTitle) ? $vTitle : WinGetHandle($vTitle, $sText) If Not _Monitor_IsVisibleWindow($hWnd) Then Return SetError(1, 0, 0) If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() For $i = 1 To $__g_aMonitorList[0][0] If $bCenter Then _Monitor_MoveWindowToScreen($hWnd, "", $i) Else _Monitor_MoveWindowToScreen($hWnd, "", $i, 50, 50) EndIf Sleep($iDelay) Next Return 1 EndFunc ;==>_Monitor_MoveWindowToAll #EndRegion --- Window Management Functions --- #Region --- Display Mode Functions --- ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_EnumAllDisplayModes ; Description....: Enumerate all available display modes for a monitor ; Syntax.........: _Monitor_EnumAllDisplayModes($iMonitor) ; Parameters.....: $iMonitor - Monitor index (1..N) ; Return values..: Success - 2D array with display modes: ; |[0][0] - Number of modes found ; |[n][0] - Width in pixels for mode n ; |[n][1] - Height in pixels for mode n ; |[n][2] - Bits per pixel (color depth) for mode n ; |[n][3] - Refresh rate in Hz for mode n ; |[n][4] - Display mode flags for mode n ; Failure - 0, sets @error to non-zero: ; |@error = 1 - Invalid monitor index ; |@error = 2 - GetInfo failed (could not get device name) ; |@error = 3 - No display modes found ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Returns all supported display modes for the specified monitor. ; Use _Monitor_GetDisplaySettings() to get only the current active mode. ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_GetDisplaySettings, _Monitor_GetResolution, _Monitor_GetList ; ================================================================================================================================ Func _Monitor_EnumAllDisplayModes($iMonitor) If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, 0) Local $aInfo = _Monitor_GetInfo($iMonitor) If @error Then Return SetError(2, 0, 0) Local $sDevice = $aInfo[10] Local $aModes[1][5] $aModes[0][0] = 0 Local $iIndex = 0 While True Local $aMode = _WinAPI_EnumDisplaySettings($sDevice, $iIndex) If @error Then ExitLoop ReDim $aModes[$aModes[0][0] + 2][5] $aModes[0][0] += 1 $aModes[$aModes[0][0]][0] = $aMode[0] $aModes[$aModes[0][0]][1] = $aMode[1] $aModes[$aModes[0][0]][2] = $aMode[2] $aModes[$aModes[0][0]][3] = $aMode[3] $aModes[$aModes[0][0]][4] = $aMode[4] $iIndex += 1 WEnd If $aModes[0][0] = 0 Then Return SetError(3, 0, 0) Return $aModes EndFunc ;==>_Monitor_EnumAllDisplayModes ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_GetList ; Description....: Enumerate all connected monitors and fill the global monitor list with their information ; Syntax.........: _Monitor_GetList() ; Parameters.....: None ; Return values..: Success - Number of monitors detected (>= 1) ; Failure - -1, sets @error = 1 (WinAPI EnumDisplayMonitors call failed) ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: This is the core function that initializes the monitor list. Most other functions call this ; automatically if the list is not initialized (when $__g_aMonitorList[0][0] = 0). ; Populates the global array $__g_aMonitorList with monitor handles, coordinates, and device names. ; Also stores virtual desktop bounds and IsPrimary flags for each monitor. ; Related........: _Monitor_Refresh, _Monitor_GetCount, _Monitor_GetInfo ; ================================================================================================================================ Func _Monitor_GetList() Local $aMonitors = _WinAPI_EnumDisplayMonitors() If @error Or Not IsArray($aMonitors) Or $aMonitors[0][0] = 0 Then Return SetError(1, 0, -1) EndIf ReDim $__g_aMonitorList[$aMonitors[0][0] + 1][7] $__g_aMonitorList[0][0] = $aMonitors[0][0] Local $l_aVirtual = _Monitor_GetVirtualBounds() If @error Then ; Fallback calculation Local $l_aVirtual[4] = [0, 0, @DesktopWidth, @DesktopHeight] EndIf Local $l_vRight = $l_aVirtual[0] + $l_aVirtual[2] Local $l_vBottom = $l_aVirtual[1] + $l_aVirtual[3] $__g_aMonitorList[0][1] = $l_aVirtual[0] $__g_aMonitorList[0][2] = $l_aVirtual[1] $__g_aMonitorList[0][3] = $l_vRight $__g_aMonitorList[0][4] = $l_vBottom $__g_aMonitorList[0][5] = $l_aVirtual[2] $__g_aMonitorList[0][6] = $l_aVirtual[3] For $i = 1 To $aMonitors[0][0] Local $hMonitor = $aMonitors[$i][0] Local $tRect = $aMonitors[$i][1] $__g_aMonitorList[$i][0] = $hMonitor $__g_aMonitorList[$i][1] = DllStructGetData($tRect, "Left") $__g_aMonitorList[$i][2] = DllStructGetData($tRect, "Top") $__g_aMonitorList[$i][3] = DllStructGetData($tRect, "Right") $__g_aMonitorList[$i][4] = DllStructGetData($tRect, "Bottom") ; Get additional info - Store IsPrimary flag correctly Local $aInfo = _WinAPI_GetMonitorInfo($hMonitor) If Not @error And IsArray($aInfo) Then ; Store IsPrimary flag (0 or 1) instead of pointer $__g_aMonitorList[$i][5] = ($aInfo[2] <> 0) ? 1 : 0 ; IsPrimary flag $__g_aMonitorList[$i][6] = $aInfo[3] ; Device name Else ; Safe fallback if GetMonitorInfo fails $__g_aMonitorList[$i][5] = 0 $__g_aMonitorList[$i][6] = "" EndIf Next Return $__g_aMonitorList[0][0] EndFunc ;==>_Monitor_GetList ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_ShowInfo ; Description....: Display monitor coordinates and detailed information in a message box and console ; Syntax.........: _Monitor_ShowInfo([$bShowMsgBox = 1 [, $iTimeout = 10]]) ; Parameters.....: $bShowMsgBox - [optional] Show message box. Default is 1 (True) ; $iTimeout - [optional] Message box timeout in seconds. Default is 10 ; Return values..: Success - String containing formatted monitor information ; Failure - Empty string "", sets @error = 1 (Enumeration failed) ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Displays comprehensive information about all monitors including bounds, work areas, ; resolutions, refresh rates, and device names. Information is written to console and ; optionally shown in a message box. ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Useful for debugging and displaying system monitor configuration. ; Related........: _Monitor_GetList, _Monitor_GetInfo, _Monitor_GetDisplaySettings ; ================================================================================================================================ Func _Monitor_ShowInfo($bShowMsgBox = 1, $iTimeout = 10) If $__g_aMonitorList[0][0] = 0 Then If _Monitor_GetList() = -1 Then Return SetError(1, 0, "") EndIf Local $sMsg = "> Total Monitors: " & $__g_aMonitorList[0][0] & @CRLF & @CRLF $sMsg &= StringFormat("+ Virtual Desktop: " & @CRLF & "Left=%d, Top=%d, Right=%d, Bottom=%d, Width=%d, Height=%d", $__g_aMonitorList[0][1], $__g_aMonitorList[0][2], $__g_aMonitorList[0][3], $__g_aMonitorList[0][4], $__g_aMonitorList[0][5], $__g_aMonitorList[0][6]) & @CRLF & @CRLF For $i = 1 To $__g_aMonitorList[0][0] Local $aInfo = _Monitor_GetInfo($i) If @error Then ContinueLoop Local $aSettings = _Monitor_GetDisplaySettings($i) Local $sResolution = @error ? "N/A" : $aSettings[0] & "x" & $aSettings[1] & " @" & $aSettings[3] & "Hz" $sMsg &= StringFormat("+ Monitor %d: %s%s\n", $i, $aInfo[9] ? "(Primary) " : "", $aInfo[10]) $sMsg &= StringFormat(" Bounds: L=%d, T=%d, R=%d, B=%d (%dx%d)\n", _ $aInfo[1], $aInfo[2], $aInfo[3], $aInfo[4], _ $aInfo[3] - $aInfo[1], $aInfo[4] - $aInfo[2]) $sMsg &= StringFormat(" Work Area: L=%d, T=%d, R=%d, B=%d (%dx%d)\n", _ $aInfo[5], $aInfo[6], $aInfo[7], $aInfo[8], _ $aInfo[7] - $aInfo[5], $aInfo[8] - $aInfo[6]) $sMsg &= " Resolution: " & $sResolution & @CRLF & @CRLF Next ConsoleWrite($sMsg) If $bShowMsgBox Then MsgBox(64 + 262144, "Monitor Information", $sMsg, $iTimeout) Return $sMsg EndFunc ;==>_Monitor_ShowInfo ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_Refresh ; Description....: Refresh the monitor list by reloading information from the system ; Syntax.........: _Monitor_Refresh() ; Parameters.....: None ; Return values..: Success - Number of monitors detected (>= 1) ; Failure - -1, sets @error = 1 (Refresh failed, _Monitor_GetList failed) ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Resets the monitor list and re-enumerates all monitors from the system. ; Useful when monitors are hot-plugged or display configuration changes. ; This forces a complete refresh of all monitor information. ; Related........: _Monitor_GetList, _Monitor_GetCount, _Monitor_IsConnected ; ================================================================================================================================ Func _Monitor_Refresh() ; Reset the list $__g_aMonitorList[0][0] = 0 Local $iResult = _Monitor_GetList() If $iResult = -1 Then Return SetError(1, 0, -1) Return $iResult EndFunc ;==>_Monitor_Refresh ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_IsConnected ; Description....: Check if a monitor is still connected and its handle is still valid ; Syntax.........: _Monitor_IsConnected($iMonitor) ; Parameters.....: $iMonitor - Monitor index (1..N) ; Return values..: Success - True if monitor is connected and valid, False if disconnected ; Failure - False, sets @error = 1 (Invalid monitor index) ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Verifies that the monitor handle is still valid by querying GetMonitorInfo. ; Useful for detecting when a monitor has been unplugged or disconnected. ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_Refresh, _Monitor_GetList, _Monitor_GetCount ; ================================================================================================================================ Func _Monitor_IsConnected($iMonitor) If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, False) ; Check if monitor handle is still valid Local $hMonitor = $__g_aMonitorList[$iMonitor][0] Local $aInfo = _WinAPI_GetMonitorInfo($hMonitor) Return (Not @error And IsArray($aInfo)) EndFunc ;==>_Monitor_IsConnected ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_GetDPI ; Description....: Get DPI (Dots Per Inch) scaling information for a monitor ; Syntax.........: _Monitor_GetDPI($iMonitor) ; Parameters.....: $iMonitor - Monitor index (1..N) ; Return values..: Success - Array with 3 elements: ; |[0] - X DPI value ; |[1] - Y DPI value ; |[2] - Scaling percentage (typically 100, 125, 150, 175, 200, etc.) ; Failure - 0, sets @error to non-zero: ; |@error = 1 - Invalid monitor index ; |@error = 2 - DPI query failed (fallback uses default 96 DPI) ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Tries to use GetDpiForMonitor API (Windows 8.1+) for accurate DPI values. ; Falls back to GetDeviceCaps (Windows XP compatible) if GetDpiForMonitor is not available. ; On Windows XP/Vista/7/8, function uses GetDeviceCaps which works reliably. ; Scaling percentage is calculated as (DPI / 96) * 100. ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Compatible with Windows XP SP2 and later. ; Related........: _Monitor_GetInfo, _Monitor_GetDisplaySettings, _Monitor_GetList ; ================================================================================================================================ Func _Monitor_GetDPI($iMonitor) If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, 0) Local $hMonitor = $__g_aMonitorList[$iMonitor][0] Local $iDPI_X = 96, $iDPI_Y = 96 ; Try to get DPI using GetDpiForMonitor (Windows 8.1+ only) ; Check OS version first to avoid loading shcore.dll on older systems If __Monitor_IsWindows8_1OrGreater() Then ; FIXED: Check if shcore.dll exists before calling and close handle properly Local $hShCore = DllOpen("shcore.dll") If $hShCore <> -1 Then Local $aRet = DllCall($hShCore, "long", "GetDpiForMonitor", "handle", $hMonitor, "int", 0, "uint*", 0, "uint*", 0) Local $bError = @error DllClose($hShCore) ; FIXED: Always close DLL handle to prevent memory leak If Not $bError And IsArray($aRet) And $aRet[0] = 0 Then $iDPI_X = $aRet[3] $iDPI_Y = $aRet[4] Local $iScaling = Round(($iDPI_X / 96) * 100) Local $aResult[3] = [$iDPI_X, $iDPI_Y, $iScaling] Return $aResult EndIf EndIf EndIf ; Fallback: Use GetDeviceCaps (compatible with Windows XP and later) Local $hDC = DllCall("user32.dll", "handle", "GetDC", "hwnd", 0) If @error Or Not IsArray($hDC) Or Not $hDC[0] Then ; Return default 96 DPI if GetDC fails Local $aResult[3] = [96, 96, 100] Return $aResult EndIf Local $aDPI_X = DllCall("gdi32.dll", "int", "GetDeviceCaps", "handle", $hDC[0], "int", 88) ; LOGPIXELSX Local $bErrorX = @error Local $aDPI_Y = DllCall("gdi32.dll", "int", "GetDeviceCaps", "handle", $hDC[0], "int", 90) ; LOGPIXELSY Local $bErrorY = @error ; Release DC handle DllCall("user32.dll", "bool", "ReleaseDC", "hwnd", 0, "handle", $hDC[0]) If Not $bErrorX And IsArray($aDPI_X) And $aDPI_X[0] > 0 Then $iDPI_X = $aDPI_X[0] If Not $bErrorY And IsArray($aDPI_Y) And $aDPI_Y[0] > 0 Then $iDPI_Y = $aDPI_Y[0] Local $iScaling = Round(($iDPI_X / 96) * 100) Local $aResult[3] = [$iDPI_X, $iDPI_Y, $iScaling] Return $aResult EndFunc ;==>_Monitor_GetDPI ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_GetOrientation ; Description....: Get the display orientation (rotation angle) for a monitor ; Syntax.........: _Monitor_GetOrientation($iMonitor) ; Parameters.....: $iMonitor - Monitor index (1..N) ; Return values..: Success - Orientation angle in degrees: ; |0 - Landscape (normal) ; |90 - Portrait (rotated 90° clockwise) ; |180 - Landscape flipped (rotated 180°) ; |270 - Portrait flipped (rotated 270° clockwise / 90° counter-clockwise) ; Failure - -1, sets @error to non-zero: ; |@error = 1 - Invalid monitor index ; |@error = 2 - GetDisplaySettings failed (could not query display mode) ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Orientation is extracted from display mode flags. ; Most monitors typically return 0 (landscape) unless rotated in Windows display settings. ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_GetDisplaySettings, _Monitor_GetInfo, _Monitor_GetList ; ================================================================================================================================ Func _Monitor_GetOrientation($iMonitor) If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, -1) Local $aSettings = _Monitor_GetDisplaySettings($iMonitor) If @error Then Return SetError(2, 0, -1) ; DisplayMode field contains orientation information ; DM_DISPLAYORIENTATION values: 0=0°, 1=90°, 2=180°, 3=270° Local $iOrientation = 0 If IsArray($aSettings) And UBound($aSettings) > 4 Then ; Check display mode flags for orientation Local $iDisplayMode = $aSettings[4] ; Orientation is stored in bits 8-9 of display mode $iOrientation = BitAND(BitShift($iDisplayMode, 8), 3) * 90 EndIf Return $iOrientation EndFunc ;==>_Monitor_GetOrientation #EndRegion --- Display Mode Functions --- #Region --- Display Settings Functions (Require Admin) --- ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_Enable ; Description....: Enable (attach) a monitor that has been disabled ; Syntax.........: _Monitor_Enable($iMonitor) ; Parameters.....: $iMonitor - Monitor index (1..N) ; Return values..: Success - 1 ; Failure - 0, sets @error to non-zero: ; |@error = 1 - Invalid monitor index ; |@error = 2 - GetInfo failed (could not get device name) ; |@error = 3 - ChangeDisplaySettingsEx failed ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: *** REQUIRES ADMINISTRATOR PRIVILEGES (UAC ELEVATION) *** ; Enables a monitor by setting CDS_UPDATEREGISTRY and CDS_NORESET flags. ; Changes are applied immediately. ; May not work with some proprietary graphics drivers (NVIDIA, AMD control panels). ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_Disable, _Monitor_SetResolution, _Monitor_Refresh ; ================================================================================================================================ Func _Monitor_Enable($iMonitor) If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, 0) Local $aInfo = _Monitor_GetInfo($iMonitor) If @error Then Return SetError(2, 0, 0) Local $sDevice = $aInfo[10] ; Get current settings Local $aSettings = _Monitor_GetDisplaySettings($iMonitor, $ENUM_REGISTRY_SETTINGS) If @error Then $aSettings = _Monitor_GetDisplaySettings($iMonitor) ; Create DEVMODE structure Local $tDEVMODE = DllStructCreate( _ "wchar DeviceName[32];" & _ "ushort SpecVersion;" & _ "ushort DriverVersion;" & _ "ushort Size;" & _ "ushort DriverExtra;" & _ "dword Fields;" & _ "short Orientation;" & _ "short PaperSize;" & _ "short PaperLength;" & _ "short PaperWidth;" & _ "short Scale;" & _ "short Copies;" & _ "short DefaultSource;" & _ "short PrintQuality;" & _ "short Color;" & _ "short Duplex;" & _ "short YResolution;" & _ "short TTOption;" & _ "short Collate;" & _ "wchar FormName[32];" & _ "ushort LogPixels;" & _ "dword BitsPerPel;" & _ "dword PelsWidth;" & _ "dword PelsHeight;" & _ "dword DisplayFlags;" & _ "dword DisplayFrequency") If @error Then Return SetError(3, 0, 0) DllStructSetData($tDEVMODE, "Size", DllStructGetSize($tDEVMODE)) DllStructSetData($tDEVMODE, "Fields", BitOR($DM_PELSWIDTH, $DM_PELSHEIGHT, $DM_POSITION)) If IsArray($aSettings) Then DllStructSetData($tDEVMODE, "PelsWidth", $aSettings[0]) DllStructSetData($tDEVMODE, "PelsHeight", $aSettings[1]) EndIf ; CDS_UPDATEREGISTRY | CDS_NORESET Local $aRet = DllCall("user32.dll", "long", "ChangeDisplaySettingsExW", "wstr", $sDevice, "struct*", $tDEVMODE, "hwnd", 0, "dword", BitOR($CDS_UPDATEREGISTRY, $CDS_NORESET), "ptr", 0) If @error Or Not IsArray($aRet) Or $aRet[0] <> $DISP_CHANGE_SUCCESSFUL Then Return SetError(3, 0, 0) ; Apply changes DllCall("user32.dll", "long", "ChangeDisplaySettingsExW", "ptr", 0, "ptr", 0, "hwnd", 0, "dword", 0, "ptr", 0) Sleep(500) _Monitor_Refresh() Return 1 EndFunc ;==>_Monitor_Enable ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_Disable ; Description....: Disable (detach) a monitor ; Syntax.........: _Monitor_Disable($iMonitor) ; Parameters.....: $iMonitor - Monitor index (1..N) ; Return values..: Success - 1 ; Failure - 0, sets @error to non-zero: ; |@error = 1 - Invalid monitor index ; |@error = 2 - Cannot disable primary monitor ; |@error = 3 - GetInfo failed (could not get device name) ; |@error = 4 - ChangeDisplaySettingsEx failed ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: *** REQUIRES ADMINISTRATOR PRIVILEGES (UAC ELEVATION) *** ; Disables a monitor by setting it to 0x0 resolution. ; Cannot disable the primary monitor (returns @error = 2). ; May not work with some proprietary graphics drivers. ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_Enable, _Monitor_SetPrimary, _Monitor_Refresh ; ================================================================================================================================ Func _Monitor_Disable($iMonitor) If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, 0) ; Cannot disable primary monitor If $__g_aMonitorList[$iMonitor][5] = 1 Then Return SetError(2, 0, 0) Local $aInfo = _Monitor_GetInfo($iMonitor) If @error Then Return SetError(3, 0, 0) Local $sDevice = $aInfo[10] ; Create DEVMODE structure with 0x0 resolution (disable) Local $tDEVMODE = DllStructCreate( _ "wchar DeviceName[32];" & _ "ushort SpecVersion;" & _ "ushort DriverVersion;" & _ "ushort Size;" & _ "ushort DriverExtra;" & _ "dword Fields;" & _ "short Orientation;" & _ "short PaperSize;" & _ "short PaperLength;" & _ "short PaperWidth;" & _ "short Scale;" & _ "short Copies;" & _ "short DefaultSource;" & _ "short PrintQuality;" & _ "short Color;" & _ "short Duplex;" & _ "short YResolution;" & _ "short TTOption;" & _ "short Collate;" & _ "wchar FormName[32];" & _ "ushort LogPixels;" & _ "dword BitsPerPel;" & _ "dword PelsWidth;" & _ "dword PelsHeight;" & _ "dword DisplayFlags;" & _ "dword DisplayFrequency") If @error Then Return SetError(4, 0, 0) DllStructSetData($tDEVMODE, "Size", DllStructGetSize($tDEVMODE)) DllStructSetData($tDEVMODE, "Fields", BitOR($DM_PELSWIDTH, $DM_PELSHEIGHT, $DM_POSITION)) DllStructSetData($tDEVMODE, "PelsWidth", 0) DllStructSetData($tDEVMODE, "PelsHeight", 0) ; CDS_UPDATEREGISTRY | CDS_NORESET Local $aRet = DllCall("user32.dll", "long", "ChangeDisplaySettingsExW", "wstr", $sDevice, "struct*", $tDEVMODE, "hwnd", 0, "dword", BitOR($CDS_UPDATEREGISTRY, $CDS_NORESET), "ptr", 0) If @error Or Not IsArray($aRet) Or $aRet[0] <> $DISP_CHANGE_SUCCESSFUL Then Return SetError(4, 0, 0) ; Apply changes DllCall("user32.dll", "long", "ChangeDisplaySettingsExW", "ptr", 0, "ptr", 0, "hwnd", 0, "dword", 0, "ptr", 0) Sleep(500) _Monitor_Refresh() Return 1 EndFunc ;==>_Monitor_Disable ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_SetResolution ; Description....: Set monitor resolution and refresh rate ; Syntax.........: _Monitor_SetResolution($iMonitor, $iWidth, $iHeight[, $iBitsPerPixel = 32[, $iFrequency = 0]]) ; Parameters.....: $iMonitor - Monitor index (1..N) ; $iWidth - Width in pixels ; $iHeight - Height in pixels ; $iBitsPerPixel - [optional] Color depth (bits per pixel). Default is 32 ; Valid values: 16, 24, 32 ; $iFrequency - [optional] Refresh rate in Hz. Default is 0 (use current/default) ; Return values..: Success - 1 ; Failure - 0, sets @error to non-zero: ; |@error = 1 - Invalid monitor index ; |@error = 2 - GetInfo failed (could not get device name) ; |@error = 3 - Invalid resolution parameters ; |@error = 4 - Test mode failed (resolution not supported), @extended = Windows error code ; |@error = 5 - Apply mode failed, @extended = Windows error code ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: *** REQUIRES ADMINISTRATOR PRIVILEGES (UAC ELEVATION) *** ; Changes display resolution for specified monitor. ; Function tests the resolution first before applying (CDS_TEST flag). ; Use _Monitor_EnumAllDisplayModes() to check supported resolutions. ; May not work with some proprietary graphics drivers. ; @extended returns Windows error codes: ; |DISP_CHANGE_SUCCESSFUL = 0 ; |DISP_CHANGE_RESTART = 1 (requires restart) ; |DISP_CHANGE_FAILED = -1 ; |DISP_CHANGE_BADMODE = -2 (mode not supported) ; |DISP_CHANGE_NOTUPDATED = -3 ; |DISP_CHANGE_BADFLAGS = -4 ; |DISP_CHANGE_BADPARAM = -5 ; |DISP_CHANGE_BADDUALVIEW = -6 ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_GetResolution, _Monitor_EnumAllDisplayModes, _Monitor_GetDisplaySettings ; ================================================================================================================================ Func _Monitor_SetResolution($iMonitor, $iWidth, $iHeight, $iBitsPerPixel = 32, $iFrequency = 0) ; FIXED: Added parameter validation If Not IsInt($iMonitor) Or Not IsInt($iWidth) Or Not IsInt($iHeight) Then Return SetError(3, 0, 0) If $iBitsPerPixel <> 16 And $iBitsPerPixel <> 24 And $iBitsPerPixel <> 32 Then Return SetError(3, 0, 0) If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, 0) If $iWidth < 1 Or $iHeight < 1 Then Return SetError(3, 0, 0) Local $aInfo = _Monitor_GetInfo($iMonitor) If @error Then Return SetError(2, 0, 0) Local $sDevice = $aInfo[10] ; FIXED: Corrected DEVMODE structure definition Local $tDEVMODE = DllStructCreate( _ "wchar DeviceName[32];" & _ "ushort SpecVersion;" & _ "ushort DriverVersion;" & _ "ushort Size;" & _ "ushort DriverExtra;" & _ "dword Fields;" & _ "short Orientation;" & _ "short PaperSize;" & _ "short PaperLength;" & _ "short PaperWidth;" & _ "short Scale;" & _ "short Copies;" & _ "short DefaultSource;" & _ "short PrintQuality;" & _ "short Color;" & _ "short Duplex;" & _ "short YResolution;" & _ "short TTOption;" & _ "short Collate;" & _ "wchar FormName[32];" & _ "ushort LogPixels;" & _ "dword BitsPerPel;" & _ "dword PelsWidth;" & _ "dword PelsHeight;" & _ "dword DisplayFlags;" & _ "dword DisplayFrequency") If @error Then Return SetError(4, 0, 0) ; Initialize structure DllStructSetData($tDEVMODE, "Size", DllStructGetSize($tDEVMODE)) ; Set fields flag Local $iFields = BitOR($DM_PELSWIDTH, $DM_PELSHEIGHT, $DM_BITSPERPEL) If $iFrequency > 0 Then $iFields = BitOR($iFields, $DM_DISPLAYFREQUENCY) DllStructSetData($tDEVMODE, "Fields", $iFields) DllStructSetData($tDEVMODE, "PelsWidth", $iWidth) DllStructSetData($tDEVMODE, "PelsHeight", $iHeight) DllStructSetData($tDEVMODE, "BitsPerPel", $iBitsPerPixel) If $iFrequency > 0 Then DllStructSetData($tDEVMODE, "DisplayFrequency", $iFrequency) ; Test first (CDS_TEST) Local $aRet = DllCall("user32.dll", "long", "ChangeDisplaySettingsExW", _ "wstr", $sDevice, _ "struct*", $tDEVMODE, _ "hwnd", 0, _ "dword", $CDS_TEST, _ "ptr", 0) If @error Then Return SetError(4, @error, 0) If Not IsArray($aRet) Then Return SetError(4, 0, 0) Local $iTestResult = $aRet[0] If $iTestResult <> $DISP_CHANGE_SUCCESSFUL Then Return SetError(4, $iTestResult, 0) EndIf ; Apply changes (CDS_UPDATEREGISTRY) $aRet = DllCall("user32.dll", "long", "ChangeDisplaySettingsExW", _ "wstr", $sDevice, _ "struct*", $tDEVMODE, _ "hwnd", 0, _ "dword", $CDS_UPDATEREGISTRY, _ "ptr", 0) If @error Then Return SetError(5, @error, 0) If Not IsArray($aRet) Then Return SetError(5, 0, 0) If $aRet[0] <> $DISP_CHANGE_SUCCESSFUL Then Return SetError(5, $aRet[0], 0) Sleep(500) ; Wait for display to settle _Monitor_Refresh() Return 1 EndFunc ;==>_Monitor_SetResolution ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_SetPrimary ; Description....: Set a monitor as the primary monitor ; Syntax.........: _Monitor_SetPrimary($iMonitor) ; Parameters.....: $iMonitor - Monitor index (1..N) ; Return values..: Success - 1 ; Failure - 0, sets @error to non-zero: ; |@error = 1 - Invalid monitor index ; |@error = 2 - GetInfo failed (could not get device name) ; |@error = 3 - ChangeDisplaySettingsEx failed ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: *** REQUIRES ADMINISTRATOR PRIVILEGES (UAC ELEVATION) *** ; Sets specified monitor as primary display (where taskbar appears). ; This also sets the monitor position to (0,0) in virtual coordinates. ; May not work with some proprietary graphics drivers. ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_GetPrimary, _Monitor_GetInfo, _Monitor_Refresh ; ================================================================================================================================ Func _Monitor_SetPrimary($iMonitor) If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, 0) Local $aInfo = _Monitor_GetInfo($iMonitor) If @error Then Return SetError(2, 0, 0) Local $sDevice = $aInfo[10] ; Get current settings Local $aSettings = _Monitor_GetDisplaySettings($iMonitor) If @error Then Return SetError(2, 0, 0) ; Create DEVMODE structure Local $tDEVMODE = DllStructCreate( _ "wchar DeviceName[32];" & _ "ushort SpecVersion;" & _ "ushort DriverVersion;" & _ "ushort Size;" & _ "ushort DriverExtra;" & _ "dword Fields;" & _ "short Orientation;" & _ "short PaperSize;" & _ "short PaperLength;" & _ "short PaperWidth;" & _ "short Scale;" & _ "short Copies;" & _ "short DefaultSource;" & _ "short PrintQuality;" & _ "short Color;" & _ "short Duplex;" & _ "short YResolution;" & _ "short TTOption;" & _ "short Collate;" & _ "wchar FormName[32];" & _ "ushort LogPixels;" & _ "dword BitsPerPel;" & _ "dword PelsWidth;" & _ "dword PelsHeight;" & _ "dword DisplayFlags;" & _ "dword DisplayFrequency") If @error Then Return SetError(3, 0, 0) DllStructSetData($tDEVMODE, "Size", DllStructGetSize($tDEVMODE)) DllStructSetData($tDEVMODE, "Fields", BitOR($DM_PELSWIDTH, $DM_PELSHEIGHT, $DM_POSITION)) DllStructSetData($tDEVMODE, "PelsWidth", $aSettings[0]) DllStructSetData($tDEVMODE, "PelsHeight", $aSettings[1]) DllStructSetData($tDEVMODE, "Orientation", 0) ; Position X = 0 DllStructSetData($tDEVMODE, "PaperSize", 0) ; Position Y = 0 ; CDS_UPDATEREGISTRY | CDS_SET_PRIMARY Local $aRet = DllCall("user32.dll", "long", "ChangeDisplaySettingsExW", "wstr", $sDevice, "struct*", $tDEVMODE, "hwnd", 0, "dword", BitOR($CDS_UPDATEREGISTRY, $CDS_SET_PRIMARY), "ptr", 0) If @error Or Not IsArray($aRet) Or $aRet[0] <> $DISP_CHANGE_SUCCESSFUL Then Return SetError(3, 0, 0) Sleep(500) _Monitor_Refresh() Return 1 EndFunc ;==>_Monitor_SetPrimary ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_GetDisplayMode ; Description....: Get current display mode (duplicate, extend, internal only, external only) ; Syntax.........: _Monitor_GetDisplayMode() ; Parameters.....: None ; Return values..: Success - Integer representing display mode: ; |1 - Internal only (laptop screen only) ; |2 - Duplicate/Clone (same content on all displays) ; |3 - Extend (extended desktop across displays) ; |4 - External only (external monitor only) ; Failure - 0, sets @error = 1 (Could not determine mode) ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Analyzes monitor positions to determine display mode. ; Duplicate mode: All monitors at position (0,0) ; Extend mode: Monitors at different positions ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_SetDisplayMode, _Monitor_GetCount, _Monitor_GetBounds ; ================================================================================================================================ Func _Monitor_GetDisplayMode() If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() Local $iCount = $__g_aMonitorList[0][0] If $iCount = 0 Then Return SetError(1, 0, 0) If $iCount = 1 Then Return 1 ; Single monitor (internal only) ; Check if all monitors at same position (duplicate mode) Local $bAllSamePos = True For $i = 2 To $iCount If $__g_aMonitorList[$i][1] <> $__g_aMonitorList[1][1] Or $__g_aMonitorList[$i][2] <> $__g_aMonitorList[1][2] Then $bAllSamePos = False ExitLoop EndIf Next If $bAllSamePos Then Return 2 ; Duplicate/Clone mode Return 3 ; Extend mode EndFunc ;==>_Monitor_GetDisplayMode ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_SetDisplayMode ; Description....: Set display mode (duplicate or extend) ; Syntax.........: _Monitor_SetDisplayMode($iMode) ; Parameters.....: $iMode - Display mode: ; |2 - Duplicate/Clone (same content on all displays) ; |3 - Extend (extended desktop across displays) ; Return values..: Success - 1 ; Failure - 0, sets @error to non-zero: ; |@error = 1 - Invalid mode parameter ; |@error = 2 - GetInfo failed ; |@error = 3 - ChangeDisplaySettingsEx failed ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: *** REQUIRES ADMINISTRATOR PRIVILEGES (UAC ELEVATION) *** ; Duplicate mode sets all monitors to position (0,0). ; Extend mode arranges monitors horizontally from left to right. ; May not work with some proprietary graphics drivers. ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_GetDisplayMode, _Monitor_ApplyLayoutHorizontal, _Monitor_Refresh ; ================================================================================================================================ Func _Monitor_SetDisplayMode($iMode) If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() If $iMode < 2 Or $iMode > 3 Then Return SetError(1, 0, 0) If $iMode = 2 Then ; Duplicate mode - set all monitors to (0,0) For $i = 1 To $__g_aMonitorList[0][0] Local $aInfo = _Monitor_GetInfo($i) If @error Then Return SetError(2, 0, 0) Local $sDevice = $aInfo[10] Local $aSettings = _Monitor_GetDisplaySettings($i) If @error Then ContinueLoop Local $tDEVMODE = DllStructCreate( _ "wchar DeviceName[32];" & _ "ushort SpecVersion;" & _ "ushort DriverVersion;" & _ "ushort Size;" & _ "ushort DriverExtra;" & _ "dword Fields;" & _ "short Orientation;" & _ "short PaperSize;" & _ "short PaperLength;" & _ "short PaperWidth;" & _ "short Scale;" & _ "short Copies;" & _ "short DefaultSource;" & _ "short PrintQuality;" & _ "short Color;" & _ "short Duplex;" & _ "short YResolution;" & _ "short TTOption;" & _ "short Collate;" & _ "wchar FormName[32];" & _ "ushort LogPixels;" & _ "dword BitsPerPel;" & _ "dword PelsWidth;" & _ "dword PelsHeight;" & _ "dword DisplayFlags;" & _ "dword DisplayFrequency") If @error Then ContinueLoop DllStructSetData($tDEVMODE, "Size", DllStructGetSize($tDEVMODE)) DllStructSetData($tDEVMODE, "Fields", BitOR($DM_PELSWIDTH, $DM_PELSHEIGHT, $DM_POSITION)) DllStructSetData($tDEVMODE, "PelsWidth", $aSettings[0]) DllStructSetData($tDEVMODE, "PelsHeight", $aSettings[1]) DllStructSetData($tDEVMODE, "Orientation", 0) ; Position X = 0 DllStructSetData($tDEVMODE, "PaperSize", 0) ; Position Y = 0 ; CDS_UPDATEREGISTRY | CDS_NORESET DllCall("user32.dll", "long", "ChangeDisplaySettingsExW", "wstr", $sDevice, "struct*", $tDEVMODE, "hwnd", 0, "dword", BitOR($CDS_UPDATEREGISTRY, $CDS_NORESET), "ptr", 0) Next ; Apply all changes DllCall("user32.dll", "long", "ChangeDisplaySettingsExW", "ptr", 0, "ptr", 0, "hwnd", 0, "dword", 0, "ptr", 0) ElseIf $iMode = 3 Then ; Extend mode - arrange horizontally Local $iCurrentX = 0 For $i = 1 To $__g_aMonitorList[0][0] Local $aInfo = _Monitor_GetInfo($i) If @error Then Return SetError(2, 0, 0) Local $sDevice = $aInfo[10] Local $aSettings = _Monitor_GetDisplaySettings($i) If @error Then ContinueLoop Local $tDEVMODE = DllStructCreate( _ "wchar DeviceName[32];" & _ "ushort SpecVersion;" & _ "ushort DriverVersion;" & _ "ushort Size;" & _ "ushort DriverExtra;" & _ "dword Fields;" & _ "short Orientation;" & _ "short PaperSize;" & _ "short PaperLength;" & _ "short PaperWidth;" & _ "short Scale;" & _ "short Copies;" & _ "short DefaultSource;" & _ "short PrintQuality;" & _ "short Color;" & _ "short Duplex;" & _ "short YResolution;" & _ "short TTOption;" & _ "short Collate;" & _ "wchar FormName[32];" & _ "ushort LogPixels;" & _ "dword BitsPerPel;" & _ "dword PelsWidth;" & _ "dword PelsHeight;" & _ "dword DisplayFlags;" & _ "dword DisplayFrequency") If @error Then ContinueLoop DllStructSetData($tDEVMODE, "Size", DllStructGetSize($tDEVMODE)) DllStructSetData($tDEVMODE, "Fields", BitOR($DM_PELSWIDTH, $DM_PELSHEIGHT, $DM_POSITION)) DllStructSetData($tDEVMODE, "PelsWidth", $aSettings[0]) DllStructSetData($tDEVMODE, "PelsHeight", $aSettings[1]) DllStructSetData($tDEVMODE, "Orientation", $iCurrentX) ; Position X DllStructSetData($tDEVMODE, "PaperSize", 0) ; Position Y = 0 ; CDS_UPDATEREGISTRY | CDS_NORESET DllCall("user32.dll", "long", "ChangeDisplaySettingsExW", "wstr", $sDevice, "struct*", $tDEVMODE, "hwnd", 0, "dword", BitOR($CDS_UPDATEREGISTRY, $CDS_NORESET), "ptr", 0) $iCurrentX += $aSettings[0] Next ; Apply all changes DllCall("user32.dll", "long", "ChangeDisplaySettingsExW", "ptr", 0, "ptr", 0, "hwnd", 0, "dword", 0, "ptr", 0) EndIf Sleep(500) _Monitor_Refresh() Return 1 EndFunc ;==>_Monitor_SetDisplayMode #EndRegion --- Display Settings Functions (Require Admin) --- #Region --- Layout Management Functions --- ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_GetLayout ; Description....: Get current display layout configuration ; Syntax.........: _Monitor_GetLayout() ; Parameters.....: None ; Return values..: Success - 2D array with layout information: ; |[0][0] - Number of monitors ; |[n][0] - Monitor index ; |[n][1] - Left coordinate ; |[n][2] - Top coordinate ; |[n][3] - Width ; |[n][4] - Height ; |[n][5] - IsPrimary flag (1 or 0) ; Failure - 0, sets @error = 1 (No monitors found) ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Returns the current physical layout of all monitors. ; Useful for saving and restoring monitor configurations. ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_SaveLayout, _Monitor_LoadLayout, _Monitor_GetLayoutDescription ; ================================================================================================================================ Func _Monitor_GetLayout() If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList() If $__g_aMonitorList[0][0] = 0 Then Return SetError(1, 0, 0) Local $aLayout[$__g_aMonitorList[0][0] + 1][6] $aLayout[0][0] = $__g_aMonitorList[0][0] For $i = 1 To $__g_aMonitorList[0][0] $aLayout[$i][0] = $i $aLayout[$i][1] = $__g_aMonitorList[$i][1] $aLayout[$i][2] = $__g_aMonitorList[$i][2] $aLayout[$i][3] = $__g_aMonitorList[$i][3] - $__g_aMonitorList[$i][1] $aLayout[$i][4] = $__g_aMonitorList[$i][4] - $__g_aMonitorList[$i][2] $aLayout[$i][5] = $__g_aMonitorList[$i][5] Next Return $aLayout EndFunc ;==>_Monitor_GetLayout ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_GetLayoutDescription ; Description....: Get text description of current layout ; Syntax.........: _Monitor_GetLayoutDescription() ; Parameters.....: None ; Return values..: Success - String describing the layout ; Failure - Empty string "", sets @error = 1 ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Returns a human-readable description of monitor layout. ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_GetLayout, _Monitor_ShowInfo ; ================================================================================================================================ Func _Monitor_GetLayoutDescription() Local $aLayout = _Monitor_GetLayout() If @error Then Return SetError(1, 0, "") Local $sDesc = "Layout: " & $aLayout[0][0] & " monitor(s)" & @CRLF For $i = 1 To $aLayout[0][0] $sDesc &= StringFormat("Monitor %d: Pos(%d,%d) Size(%dx%d) %s" & @CRLF, _ $aLayout[$i][0], $aLayout[$i][1], $aLayout[$i][2], _ $aLayout[$i][3], $aLayout[$i][4], _ $aLayout[$i][5] ? "[Primary]" : "") Next Return $sDesc EndFunc ;==>_Monitor_GetLayoutDescription ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_SaveLayout ; Description....: Save current layout to file ; Syntax.........: _Monitor_SaveLayout($sFilePath) ; Parameters.....: $sFilePath - Full path to save layout file ; Return values..: Success - 1 ; Failure - 0, sets @error to non-zero: ; |@error = 1 - GetLayout failed ; |@error = 2 - File write failed ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: Saves layout in INI format for easy editing. ; Function automatically calls _Monitor_GetList() if monitor list is not initialized. ; Related........: _Monitor_LoadLayout, _Monitor_GetLayout ; ================================================================================================================================ Func _Monitor_SaveLayout($sFilePath) Local $aLayout = _Monitor_GetLayout() If @error Then Return SetError(1, 0, 0) Local $hFile = FileOpen($sFilePath, 2) ; Overwrite mode If $hFile = -1 Then Return SetError(2, 0, 0) FileWriteLine($hFile, "[MonitorLayout]") FileWriteLine($hFile, "Count=" & $aLayout[0][0]) FileWriteLine($hFile, "") For $i = 1 To $aLayout[0][0] FileWriteLine($hFile, "[Monitor" & $i & "]") FileWriteLine($hFile, "Left=" & $aLayout[$i][1]) FileWriteLine($hFile, "Top=" & $aLayout[$i][2]) FileWriteLine($hFile, "Width=" & $aLayout[$i][3]) FileWriteLine($hFile, "Height=" & $aLayout[$i][4]) FileWriteLine($hFile, "IsPrimary=" & $aLayout[$i][5]) FileWriteLine($hFile, "") Next FileClose($hFile) Return 1 EndFunc ;==>_Monitor_SaveLayout ; #FUNCTION# ==================================================================================================================== ; Name...........: _Monitor_LoadLayout ; Description....: Load layout from file (NOTE: Does not apply layout, only loads data) ; Syntax.........: _Monitor_LoadLayout($sFilePath) ; Parameters.....: $sFilePath - Full path to layout file ; Return values..: Success - 2D array with layout information (same format as _Monitor_GetLayout) ; Failure - 0, sets @error to non-zero: ; |@error = 1 - File not found or cannot be read ; |@error = 2 - Invalid layout file format ; Author.........: Dao Van Trong - TRONG.PRO ; Remarks........: *** NOTE: This function only LOADS layout data, it does NOT apply it *** ; To apply loaded layout, you need to use _Monitor_SetResolution() and ; _Monitor_SetPrimary() functions manually for each monitor. ; This is because applying layout requires Administrator privileges. ; Related........: _Monitor_SaveLayout, _Monitor_GetLayout ; ================================================================================================================================ Func _Monitor_LoadLayout($sFilePath) If Not FileExists($sFilePath) Then Return SetError(1, 0, 0) Local $iCount = IniRead($sFilePath, "MonitorLayout", "Count", 0) If $iCount < 1 Then Return SetError(2, 0, 0) Local $aLayout[$iCount + 1][6] $aLayout[0][0] = $iCount For $i = 1 To $iCount $aLayout[$i][0] = $i $aLayout[$i][1] = IniRead($sFilePath, "Monitor" & $i, "Left", 0) $aLayout[$i][2] = IniRead($sFilePath, "Monitor" & $i, "Top", 0) $aLayout[$i][3] = IniRead($sFilePath, "Monitor" & $i, "Width", 0) $aLayout[$i][4] = IniRead($sFilePath, "Monitor" & $i, "Height", 0) $aLayout[$i][5] = IniRead($sFilePath, "Monitor" & $i, "IsPrimary", 0) Next Return $aLayout EndFunc ;==>_Monitor_LoadLayout #EndRegion --- Layout Management Functions --- EG: ; ================================================================================================== ; MonitorUDF_Examples.au3 ; Interactive example tester for MonitorUDF.au3 UDF ; Fixed: Array index bug in FuncTest_10, improved error handling ; ================================================================================================== #include <GUIConstantsEx.au3> #include <ButtonConstants.au3> #include <WindowsConstants.au3> #include <GuiListBox.au3> #include <GuiEdit.au3> #include <Array.au3> #include "Monitor_UDF.au3" ; Updated include name ; ================================================================================================== ; Create GUI ; ================================================================================================== Global $GUI_W = 860, $GUI_H = 600 Global $hGUI = GUICreate("MonitorUDF - Examples (by TRONG.PRO)", $GUI_W, $GUI_H, -1, -1) GUISetBkColor(0xF5F5F5, $hGUI) ; Title GUICtrlCreateLabel("MonitorUDF Example Launcher", 12, 10, 400, 24) GUICtrlSetFont(-1, 12, 800, 0, 'Segoe UI', 5) ; Buttons column 1 - 6 buttons (1-6) Local $x1 = 12, $y1 = 48, $bw = 260, $bh = 36, $gap = 8 Global $iBtn1 = GUICtrlCreateButton("1. Enumerate monitors", $x1, $y1 + ($bh + $gap) * 0, $bw, $bh) Global $iBtn2 = GUICtrlCreateButton("2. Move Notepad -> Monitor #2 (center)", $x1, $y1 + ($bh + $gap) * 1, $bw, $bh) Global $iBtn3 = GUICtrlCreateButton("3. Move Notepad -> Monitor #2 @ (100,100)", $x1, $y1 + ($bh + $gap) * 2, $bw, $bh) Global $iBtn4 = GUICtrlCreateButton("4. Which monitor is mouse on?", $x1, $y1 + ($bh + $gap) * 3, $bw, $bh) Global $iBtn5 = GUICtrlCreateButton("5. Show virtual desktop bounds", $x1, $y1 + ($bh + $gap) * 4, $bw, $bh) Global $iBtn6 = GUICtrlCreateButton("6. Convert coords (local <-> virtual)", $x1, $y1 + ($bh + $gap) * 5, $bw, $bh) ; Buttons column 2 - 6 buttons (7-12) Local $x2 = $x1 + $bw + 12 Global $iBtn7 = GUICtrlCreateButton("7. Show monitor info (MsgBox)", $x2, $y1 + ($bh + $gap) * 0, $bw, $bh) Global $iBtn8 = GUICtrlCreateButton("8. Check if Notepad is visible", $x2, $y1 + ($bh + $gap) * 1, $bw, $bh) Global $iBtn9 = GUICtrlCreateButton("9. Create small GUI on each monitor", $x2, $y1 + ($bh + $gap) * 2, $bw, $bh) Global $iBtn10 = GUICtrlCreateButton("10. Move all visible windows -> primary", $x2, $y1 + ($bh + $gap) * 3, $bw, $bh) Global $iBtn11 = GUICtrlCreateButton("11. Refresh monitor list", $x2, $y1 + ($bh + $gap) * 4, $bw, $bh) Global $iBtn12 = GUICtrlCreateButton("12. Check monitor connected", $x2, $y1 + ($bh + $gap) * 5, $bw, $bh) ; Buttons column 3 - 6 buttons (13-17, but layout for 6) Local $x3 = $x2 + $bw + 12 Global $iBtn13 = GUICtrlCreateButton("13. Get DPI scaling", $x3, $y1 + ($bh + $gap) * 0, $bw, $bh) Global $iBtn14 = GUICtrlCreateButton("14. Get display orientation", $x3, $y1 + ($bh + $gap) * 1, $bw, $bh) Global $iBtn15 = GUICtrlCreateButton("15. Enumerate display modes", $x3, $y1 + ($bh + $gap) * 2, $bw, $bh) Global $iBtn16 = GUICtrlCreateButton("16. Get monitor from rect", $x3, $y1 + ($bh + $gap) * 3, $bw, $bh) Global $iBtn17 = GUICtrlCreateButton("17. Get monitor from window", $x3, $y1 + ($bh + $gap) * 4, $bw, $bh) ; Controls: log edit, clear, auto-demo, close Local $logX = 12, $logY = $y1 + ($bh + $gap) * 6 Local $logW = $GUI_W - 24, $logH = 180 Global $idLog = GUICtrlCreateEdit("", $logX, $logY, $logW, $logH, BitOR($ES_READONLY, $WS_HSCROLL, $WS_VSCROLL, $ES_MULTILINE)) GUICtrlSetFont($idLog, 9) Global $idFuncTest__ClearLog = GUICtrlCreateButton("Clear Log", 12, $logY + $logH + 10, 120, 28) Global $idFuncTest__RunAllDemo = GUICtrlCreateButton("Auto Demo (Run 1..17)", 150, $logY + $logH + 10, 220, 28) Global $idFuncTest__Close = GUICtrlCreateButton("Close", $GUI_W - 120, $logY + $logH + 10, 100, 28) Global $pidNotepad = 0 GUISetState(@SW_SHOW) ; Keep a list of created GUIs for Example 10 so we can close them later Global $Msg, $g_createdGUIs[0] ; FIXED: Initialize as empty array Global $g_bAutoMode = False ; Track if running in auto demo mode Global $g_hNotepadWindows[0] ; Track all notepad windows created ; ================================================================================================== ; Main loop ; ================================================================================================== While 1 $Msg = GUIGetMsg() Switch $Msg Case $GUI_EVENT_CLOSE, $idFuncTest__Close ; close any GUIs created in example 10 For $i = 0 To UBound($g_createdGUIs) - 1 If IsHWnd($g_createdGUIs[$i]) Then GUIDelete($g_createdGUIs[$i]) Next ExitLoop Case $idFuncTest__ClearLog GUICtrlSetData($idLog, '', '') Case $idFuncTest__RunAllDemo $g_bAutoMode = True ReDim $g_hNotepadWindows[0] FuncTest_1() Sleep(1000) FuncTest_2() Sleep(2000) FuncTest_3() Sleep(2000) FuncTest_4() Sleep(1500) FuncTest_5() Sleep(1000) FuncTest_6() Sleep(1000) FuncTest_7() Sleep(1000) FuncTest_8() Sleep(2000) FuncTest_9() Sleep(1000) FuncTest_10() Sleep(1000) FuncTest_11() Sleep(1000) FuncTest_12() Sleep(1000) FuncTest_13() Sleep(1000) FuncTest_14() Sleep(1000) FuncTest_15() Sleep(1000) FuncTest_16() Sleep(1000) FuncTest_17() Sleep(2000) ; Cleanup all created windows _CleanupAllWindows() $g_bAutoMode = False Case $iBtn1 FuncTest_1() Case $iBtn2 FuncTest_2() Case $iBtn3 FuncTest_3() Case $iBtn4 FuncTest_4() Case $iBtn5 FuncTest_5() Case $iBtn6 FuncTest_6() Case $iBtn7 FuncTest_7() Case $iBtn8 FuncTest_8() Case $iBtn9 FuncTest_9() Case $iBtn10 FuncTest_10() Case $iBtn11 FuncTest_11() Case $iBtn12 FuncTest_12() Case $iBtn13 FuncTest_13() Case $iBtn14 FuncTest_14() Case $iBtn15 FuncTest_15() Case $iBtn16 FuncTest_16() Case $iBtn17 FuncTest_17() EndSwitch Sleep(5) WEnd GUIDelete() Exit 0 ; ================================================================================================== ; Helper: append to log (with timestamp) ; ================================================================================================== Func _Log($s) ConsoleWrite($s & @CRLF) ; Format: DD/MM/YYYY HH:MM:SS Local $sDate = StringFormat("%02d/%02d/%04d", @MDAY, @MON, @YEAR) Local $sTime = StringFormat("%02d:%02d:%02d", @HOUR, @MIN, @SEC) Local $t = $sDate & " " & $sTime Local $cur = GUICtrlRead($idLog) If $cur = "" Then GUICtrlSetData($idLog, "[" & $t & "] " & $s) Else GUICtrlSetData($idLog, $cur & @CRLF & "[" & $t & "] " & $s) EndIf ; move caret to end _GUICtrlEdit_LineScroll($idLog, 0, _GUICtrlEdit_GetLineCount($idLog)) EndFunc ;==>_Log ; ================================================================================================== ; Helper: Cleanup all created windows (Notepad and GUIs) ; ================================================================================================== Func _CleanupAllWindows() ; Close all Notepad windows Local $aList = WinList("[CLASS:Notepad]") For $i = 1 To $aList[0][0] If $aList[$i][0] <> "" Then Local $hWnd = WinGetHandle($aList[$i][0]) If $hWnd Then WinClose($hWnd) EndIf Next Sleep(300) ; Force close any remaining Notepad processes While ProcessExists("notepad.exe") ProcessClose("notepad.exe") Sleep(100) WEnd ; Close all created GUIs For $i = 0 To UBound($g_createdGUIs) - 1 If IsHWnd($g_createdGUIs[$i]) Then GUIDelete($g_createdGUIs[$i]) Next ReDim $g_createdGUIs[0] ReDim $g_hNotepadWindows[0] EndFunc ;==>_CleanupAllWindows ; ================================================================================================== ; Helper: Track Notepad window ; ================================================================================================== Func _TrackNotepadWindow($hWnd) If $hWnd Then Local $n = UBound($g_hNotepadWindows) ReDim $g_hNotepadWindows[$n + 1] $g_hNotepadWindows[$n] = $hWnd EndIf EndFunc ;==>_TrackNotepadWindow Func FuncTest_1() _Log('+ TEST 1: Enumerate monitors -----------------------\') ; Enumerate monitors _Monitor_GetList() Local $cnt = _Monitor_GetCount() If @error Then Local $sMsg = "TEST 1: FAILED" & @CRLF & "ERROR - Failed to enumerate monitors" & @CRLF & "@error=" & @error _Log("---> Example 1: ERROR - Failed to enumerate monitors") If Not $g_bAutoMode Then MsgBox(48, "Example 1", $sMsg, 3) Return EndIf _Log("---> Example 1: Monitors detected: " & $cnt) Local $sResults = "Total Monitors: " & $cnt & @CRLF & @CRLF For $i = 1 To $cnt Local $a = _Monitor_GetInfo($i) If @error Then _Log(" Monitor " & $i & ": ERROR getting info") $sResults &= "Monitor #" & $i & ": ERROR" & @CRLF Else Local $sPrimary = $a[9] ? " [PRIMARY]" : "" _Log(" Monitor " & $i & ": Device=" & $a[10] & " Bounds=(" & $a[1] & "," & $a[2] & ")-(" & $a[3] & "," & $a[4] & ") Work=(" & $a[5] & "," & $a[6] & ")-(" & $a[7] & "," & $a[8] & ") Primary=" & $a[9]) $sResults &= "Monitor #" & $i & $sPrimary & ": " & $a[10] & @CRLF & _ " Bounds: " & $a[1] & "," & $a[2] & " to " & $a[3] & "," & $a[4] & @CRLF & _ " Work Area: " & $a[5] & "," & $a[6] & " to " & $a[7] & "," & $a[8] & @CRLF EndIf Next Local $sMsg = "TEST 1: SUCCESS" & @CRLF & @CRLF & $sResults If Not $g_bAutoMode Then MsgBox(64, "Example 1", $sMsg, 8) _Log('- End ------------------------------------------------/') EndFunc ;==>FuncTest_1 Func FuncTest_2() _Log('+ TEST 2: Move Notepad to monitor #2 centered ------\') ; Move Notepad to monitor #2 centered $pidNotepad = Run("notepad.exe") If Not WinWaitActive("[CLASS:Notepad]", "", 5) Then _Log("---> Example 2: Notepad did not start / focus") Local $sMsg = "TEST 2: FAILED" & @CRLF & "Notepad did not start / focus" If Not $g_bAutoMode Then MsgBox(48, "Example 2", $sMsg, 3) Else Sleep(1000) Local $hWnd = WinGetHandle("[CLASS:Notepad]") _TrackNotepadWindow($hWnd) _Monitor_GetList() Local $cnt = _Monitor_GetCount() If $cnt < 2 Then Local $sMsg = "TEST 2: SKIPPED" & @CRLF & "Need at least 2 monitors" & @CRLF & "Current: " & $cnt & " monitor(s)" _Log("---> Example 2: Need at least 2 monitors") If Not $g_bAutoMode Then MsgBox(64, "Example 2", $sMsg, 3) Else Local $iResult = _Monitor_MoveWindowToScreen("[CLASS:Notepad]", "", 2, -1, -1, True) If @error Then Local $sMsg = "TEST 2: FAILED" & @CRLF & "ERROR moving window" & @CRLF & "@error=" & @error _Log("---> Example 2: ERROR moving window: @error=" & @error) If Not $g_bAutoMode Then MsgBox(48, "Example 2", $sMsg, 3) Else Local $sMsg = "TEST 2: SUCCESS" & @CRLF & "Notepad moved to Monitor #2" & @CRLF & "Position: Centered" _Log("---> Example 2: Notepad moved to monitor #2 (centered)") If Not $g_bAutoMode Then MsgBox(64, "Example 2", $sMsg, 3) EndIf EndIf EndIf _Log('- End ------------------------------------------------/') EndFunc ;==>FuncTest_2 Func FuncTest_3() _Log('+ TEST 3: Move Notepad to monitor #2 at (100,100 ----\)') ; Move Notepad to monitor #2 at (100,100) $pidNotepad = Run("notepad.exe") If Not WinWaitActive("[CLASS:Notepad]", "", 5) Then Local $sMsg = "TEST 3: FAILED" & @CRLF & "Notepad did not start / focus" _Log("---> Example 3: Notepad did not start / focus") If Not $g_bAutoMode Then MsgBox(48, "Example 3", $sMsg, 3) Else Sleep(1000) Local $hWnd = WinGetHandle("[CLASS:Notepad]") _TrackNotepadWindow($hWnd) _Monitor_GetList() Local $cnt = _Monitor_GetCount() If $cnt < 2 Then Local $sMsg = "TEST 3: SKIPPED" & @CRLF & "Need at least 2 monitors" & @CRLF & "Current: " & $cnt & " monitor(s)" _Log("---> Example 3: Need at least 2 monitors") If Not $g_bAutoMode Then MsgBox(64, "Example 3", $sMsg, 3) Else Local $iResult = _Monitor_MoveWindowToScreen("[CLASS:Notepad]", "", 2, 100, 100, True) If @error Then Local $sMsg = "TEST 3: FAILED" & @CRLF & "ERROR moving window" & @CRLF & "@error=" & @error _Log("---> Example 3: ERROR moving window: @error=" & @error) If Not $g_bAutoMode Then MsgBox(48, "Example 3", $sMsg, 3) Else Local $sMsg = "TEST 3: SUCCESS" & @CRLF & "Notepad moved to Monitor #2" & @CRLF & "Position: (100, 100)" _Log("---> Example 3: Notepad moved to monitor #2 at (100,100)") If Not $g_bAutoMode Then MsgBox(64, "Example 3", $sMsg, 3) EndIf EndIf EndIf _Log('- End ------------------------------------------------/') EndFunc ;==>FuncTest_3 Func FuncTest_4() _Log('+ TEST 4: Which monitor is mouse on ------------------\') ; Automatically move mouse to each monitor and test _Monitor_GetList() Local $cnt = _Monitor_GetCount() If $cnt < 1 Then Local $sMsg = "TEST 4: SKIPPED" & @CRLF & "No monitors detected" _Log("---> Example 4: No monitors detected") If Not $g_bAutoMode Then MsgBox(64, "Example 4", $sMsg, 3) Else Local $aResults = "" Local $sCurrentPos = MouseGetPos() Local $iOrigX = $sCurrentPos[0], $iOrigY = $sCurrentPos[1] _Log("---> Example 4: Testing " & $cnt & " monitor(s)") For $i = 1 To $cnt ; Get monitor center Local $iLeft, $iTop, $iRight, $iBottom _Monitor_GetBounds($i, $iLeft, $iTop, $iRight, $iBottom) Local $iCenterX = $iLeft + ($iRight - $iLeft) / 2 Local $iCenterY = $iTop + ($iBottom - $iTop) / 2 ; Move mouse to center of monitor MouseMove($iCenterX, $iCenterY, 0) Sleep(200) ; Check which monitor mouse is on Local $m = _Monitor_GetFromPoint() If @error Then _Log(" Monitor " & $i & ": ERROR - @error=" & @error) $aResults &= "Monitor " & $i & ": ERROR" & @CRLF Else Local $aInfo = _Monitor_GetInfo($i) Local $sDevice = @error ? "N/A" : $aInfo[10] Local $sStatus = ($m = $i) ? "CORRECT" : "WRONG (detected #" & $m & ")" _Log(" Monitor " & $i & " (" & $sDevice & "): Mouse detected on #" & $m & " - " & $sStatus) $aResults &= "Monitor #" & $i & " (" & $sDevice & "): #" & $m & " - " & $sStatus & @CRLF EndIf Sleep(300) Next ; Restore original mouse position MouseMove($iOrigX, $iOrigY, 0) Local $sMsg = "TEST 4: COMPLETE" & @CRLF & @CRLF & "Mouse Position Test Results:" & @CRLF & $aResults _Log("---> Example 4: Test complete, mouse restored to original position") If Not $g_bAutoMode Then MsgBox(64, "Example 4", $sMsg, 5) EndIf _Log('- End ------------------------------------------------/') EndFunc ;==>FuncTest_4 Func FuncTest_5() _Log('+ TEST 5: Virtual desktop bounds -----------------------\') ; Virtual desktop bounds Local $aV = _Monitor_GetVirtualBounds() If @error Then Local $sMsg = "TEST 5: FAILED" & @CRLF & "ERROR getting virtual bounds" & @CRLF & "@error=" & @error _Log("---> Example 5: ERROR getting virtual bounds: @error=" & @error) If Not $g_bAutoMode Then MsgBox(48, "Example 5", $sMsg, 3) Else Local $sMsg = "TEST 5: SUCCESS" & @CRLF & @CRLF & "Virtual Desktop Bounds:" & @CRLF & _ "Left: " & $aV[0] & @CRLF & _ "Top: " & $aV[1] & @CRLF & _ "Width: " & $aV[2] & @CRLF & _ "Height: " & $aV[3] & @CRLF & @CRLF & _ "Right: " & ($aV[0] + $aV[2]) & @CRLF & _ "Bottom: " & ($aV[1] + $aV[3]) _Log("---> Example 5: Virtual bounds L=" & $aV[0] & " T=" & $aV[1] & " W=" & $aV[2] & " H=" & $aV[3]) If Not $g_bAutoMode Then MsgBox(64, "Example 5", $sMsg, 5) EndIf _Log('- End ------------------------------------------------/') EndFunc ;==>FuncTest_5 Func FuncTest_6() _Log('+ TEST 6: Convert coords example (local -> virtual -> back) --\') ; Convert coords example (local -> virtual -> back) _Monitor_GetList() Local $mon = _Monitor_GetCount() If $mon < 1 Then Local $sMsg = "TEST 6: SKIPPED" & @CRLF & "No monitors detected" _Log("---> Example 6: No monitors detected") If Not $g_bAutoMode Then MsgBox(64, "Example 6", $sMsg, 3) Else Local $sResults = "" For $i = 1 To $mon Local $xLocal = 50, $yLocal = 100 Local $aV = _Monitor_ToVirtual($i, $xLocal, $yLocal) If @error Then _Log("---> Example 6: Monitor " & $i & " ERROR converting to virtual: @error=" & @error) $sResults &= "Monitor #" & $i & ": ERROR (to virtual)" & @CRLF Else Local $aBack = _Monitor_FromVirtual($i, $aV[0], $aV[1]) If @error Then _Log("---> Example 6: Monitor " & $i & " ERROR converting from virtual: @error=" & @error) $sResults &= "Monitor #" & $i & ": ERROR (from virtual)" & @CRLF Else Local $bMatch = (Abs($aBack[0] - $xLocal) < 1) And (Abs($aBack[1] - $yLocal) < 1) _Log("---> Example 6: Mon " & $i & " local(" & $xLocal & "," & $yLocal & ") -> virtual(" & $aV[0] & "," & $aV[1] & ") -> back(" & $aBack[0] & "," & $aBack[1] & ")") $sResults &= "Monitor #" & $i & ": (" & $xLocal & "," & $yLocal & ") -> (" & $aV[0] & "," & $aV[1] & ") -> (" & $aBack[0] & "," & $aBack[1] & ")" & _ ($bMatch ? " ✓" : " ✗") & @CRLF EndIf EndIf Next Local $sMsg = "TEST 6: COMPLETE" & @CRLF & @CRLF & "Coordinate Conversion Test:" & @CRLF & $sResults If Not $g_bAutoMode Then MsgBox(64, "Example 6", $sMsg, 5) EndIf _Log('- End --------------------------------------------------------/') EndFunc ;==>FuncTest_6 Func FuncTest_7() _Log('+ TEST 7: Show detailed info via MsgBox (calls UDF) ------\') ; Show detailed info via MsgBox (calls UDF) _Monitor_GetList() Local $sResult = _Monitor_ShowInfo(1, 8) If @error Then Local $sMsg = "TEST 7: FAILED" & @CRLF & "ERROR showing info" & @CRLF & "@error=" & @error _Log("---> Example 7: ERROR showing info: @error=" & @error) If Not $g_bAutoMode Then MsgBox(48, "Example 7", $sMsg, 3) Else Local $sMsg = "TEST 7: SUCCESS" & @CRLF & @CRLF & "Detailed monitor information displayed above." _Log("---> Example 7: _Monitor_ShowInfo() called successfully") If Not $g_bAutoMode Then MsgBox(64, "Example 7", $sMsg, 3) EndIf _Log('- End ------------------------------------------------/') EndFunc ;==>FuncTest_7 Func FuncTest_8() _Log('+ TEST 8: Start notepad, check visible ---------------\') ; Start notepad, check visible $pidNotepad = Run("notepad.exe") If Not WinWaitActive("[CLASS:Notepad]", "", 5) Then Local $sMsg = "TEST 8: FAILED" & @CRLF & "Notepad did not start/focus" _Log("---> Example 8: Notepad did not start/focus") If Not $g_bAutoMode Then MsgBox(48, "Example 8", $sMsg, 3) Else Sleep(1000) Local $h = WinGetHandle("[CLASS:Notepad]") _TrackNotepadWindow($h) Local $b = _Monitor_IsVisibleWindow($h) If @error Then Local $sMsg = "TEST 8: FAILED" & @CRLF & "ERROR checking visibility" & @CRLF & "@error=" & @error _Log("---> Example 8: ERROR checking visibility: @error=" & @error) If Not $g_bAutoMode Then MsgBox(48, "Example 8", $sMsg, 3) Else Local $sTitle = WinGetTitle($h) Local $sMsg = "TEST 8: SUCCESS" & @CRLF & @CRLF & "Window: " & ($sTitle = "" ? "[No Title]" : $sTitle) & @CRLF & _ "Handle: " & $h & @CRLF & _ "Visible: " & ($b ? "YES ✓" : "NO ✗") _Log("---> Example 8: Notepad handle " & $h & " visible? " & ($b ? "Yes" : "No")) If Not $g_bAutoMode Then MsgBox(64, "Example 8", $sMsg, 3) EndIf EndIf _Log('- End ------------------------------------------------/') EndFunc ;==>FuncTest_8 Func FuncTest_9() _Log('+ TEST 9: Create small GUI on each monitor -------------\') ; Create small GUI on each monitor _Monitor_GetList() ; close previously created For $i = 0 To UBound($g_createdGUIs) - 1 If IsHWnd($g_createdGUIs[$i]) Then GUIDelete($g_createdGUIs[$i]) Next ReDim $g_createdGUIs[0] ; reset Local $created = 0 For $i = 1 To _Monitor_GetCount() Local $a = _Monitor_GetInfo($i) If @error Then _Log(" Monitor " & $i & ": ERROR getting info") ContinueLoop EndIf Local $h = GUICreate("Monitor #" & $i & " - " & $a[10], 260, 120, $a[1] + 40, $a[2] + 40) GUICtrlCreateLabel("Monitor " & $i & ($a[9] ? " (Primary)" : ""), 10, 12, 240, 20) GUISetState(@SW_SHOW, $h) ; store to close later __ArrayAdd($g_createdGUIs, $h) $created += 1 Next Local $sMsg = "TEST 9: SUCCESS" & @CRLF & @CRLF & "Created " & $created & " GUI window(s)" & @CRLF & @CRLF If $created > 0 Then $sMsg &= "One GUI created on each monitor:" & @CRLF For $i = 1 To _Monitor_GetCount() Local $a = _Monitor_GetInfo($i) If Not @error Then Local $sPrimary = $a[9] ? " [PRIMARY]" : "" $sMsg &= " Monitor #" & $i & $sPrimary & ": " & $a[10] & @CRLF EndIf Next $sMsg &= @CRLF & "Windows will be closed when you close the launcher." Else $sMsg &= "No GUIs were created." EndIf _Log("---> Example 9: Created " & $created & " GUI(s) on monitors. Use Close to exit (they will be closed).") If Not $g_bAutoMode Then MsgBox(64, "Example 9", $sMsg, 5) _Log('- End ------------------------------------------------/') EndFunc ;==>FuncTest_9 Func FuncTest_10() _Log('+ TEST 10: Move all visible windows to primary ----------\') ; Move all visible windows to primary _Monitor_GetList() Local $prim = _Monitor_GetPrimary() If $prim = 0 Or @error Then Local $sMsg = "TEST 10: FAILED" & @CRLF & "Primary monitor not found or error" & @CRLF & "@error=" & @error _Log("---> Example 10: Primary monitor not found or error") If Not $g_bAutoMode Then MsgBox(48, "Example 10", $sMsg, 3) Else Local $aList = WinList() Local $moved = 0 Local $aInfo = _Monitor_GetInfo($prim) Local $sDevice = @error ? "N/A" : $aInfo[10] For $i = 1 To $aList[0][0] If $aList[$i][0] <> "" Then ; FIXED: Use correct array index - WinList()[i][0] is title, need to get handle from title Local $h = WinGetHandle($aList[$i][0]) ; FIXED: Changed from [1] to [0] If Not @error And $h Then If _Monitor_IsVisibleWindow($h) Then Local $iResult = _Monitor_MoveWindowToScreen($h, "", $prim) If Not @error Then $moved += 1 EndIf EndIf EndIf Next Local $sMsg = "TEST 10: SUCCESS" & @CRLF & @CRLF & _ "Moved " & $moved & " visible window(s)" & @CRLF & _ "to Primary Monitor #" & $prim & @CRLF & _ "Device: " & $sDevice _Log("---> Example 10: Moved " & $moved & " visible windows to primary monitor #" & $prim) If Not $g_bAutoMode Then MsgBox(64, "Example 10", $sMsg, 4) EndIf _Log('- End ------------------------------------------------/') EndFunc ;==>FuncTest_10 Func FuncTest_11() _Log('+ TEST 11: Refresh monitor list ----------------------\') ; Refresh monitor list Local $cntBefore = _Monitor_GetCount() _Log("---> Example 11: Monitors before refresh: " & $cntBefore) Local $cntAfter = _Monitor_Refresh() If @error Then Local $sMsg = "TEST 11: FAILED" & @CRLF & "ERROR refreshing monitor list" & @CRLF & "@error=" & @error _Log("---> Example 11: ERROR refreshing: @error=" & @error) If Not $g_bAutoMode Then MsgBox(48, "Example 11", $sMsg, 3) Else Local $sChangeInfo = "" If $cntBefore <> $cntAfter Then _Log(" --> Monitor count changed! (was " & $cntBefore & ", now " & $cntAfter & ")") $sChangeInfo = @CRLF & "⚠ CHANGE DETECTED! ⚠" & @CRLF & "Before: " & $cntBefore & " monitor(s)" & @CRLF & "After: " & $cntAfter & " monitor(s)" Else _Log(" --> Monitor count unchanged") $sChangeInfo = @CRLF & "Count unchanged: " & $cntAfter & " monitor(s)" EndIf Local $sMsg = "TEST 11: SUCCESS" & @CRLF & @CRLF & "Monitor list refreshed" & $sChangeInfo _Log("---> Example 11: Monitors after refresh: " & $cntAfter) If Not $g_bAutoMode Then MsgBox(64, "Example 11", $sMsg, 4) EndIf _Log('- End ------------------------------------------------/') EndFunc ;==>FuncTest_11 Func FuncTest_12() _Log('+ TEST 12: Check if monitors are connected -----------\') ; Check if monitors are still connected _Monitor_GetList() Local $cnt = _Monitor_GetCount() If $cnt < 1 Then Local $sMsg = "TEST 12: SKIPPED" & @CRLF & "No monitors detected" _Log("---> Example 12: No monitors detected") If Not $g_bAutoMode Then MsgBox(64, "Example 12", $sMsg, 3) Else _Log("---> Example 12: Checking connection status for " & $cnt & " monitor(s):") Local $sResults = "" Local $iConnected = 0, $iDisconnected = 0 For $i = 1 To $cnt Local $bConnected = _Monitor_IsConnected($i) If @error Then _Log(" Monitor " & $i & ": ERROR checking connection: @error=" & @error) $sResults &= "Monitor #" & $i & ": ERROR" & @CRLF Else Local $sStatus = $bConnected ? "CONNECTED ✓" : "DISCONNECTED ✗" Local $aInfo = _Monitor_GetInfo($i) Local $sDevice = @error ? "N/A" : $aInfo[10] _Log(" Monitor " & $i & " (" & $sDevice & "): " & ($bConnected ? "CONNECTED" : "DISCONNECTED")) $sResults &= "Monitor #" & $i & " (" & $sDevice & "): " & $sStatus & @CRLF If $bConnected Then $iConnected += 1 Else $iDisconnected += 1 EndIf EndIf Next Local $sMsg = "TEST 12: COMPLETE" & @CRLF & @CRLF & "Connection Status:" & @CRLF & _ "Connected: " & $iConnected & @CRLF & _ "Disconnected: " & $iDisconnected & @CRLF & @CRLF & _ $sResults If Not $g_bAutoMode Then MsgBox(64, "Example 12", $sMsg, 5) EndIf _Log('- End ------------------------------------------------/') EndFunc ;==>FuncTest_12 Func FuncTest_13() _Log('+ TEST 13: Get DPI scaling for monitors -------------\') ; Get DPI scaling for each monitor _Monitor_GetList() Local $cnt = _Monitor_GetCount() If $cnt < 1 Then Local $sMsg = "TEST 13: SKIPPED" & @CRLF & "No monitors detected" _Log("---> Example 13: No monitors detected") If Not $g_bAutoMode Then MsgBox(64, "Example 13", $sMsg, 3) Else _Log("---> Example 13: DPI information for " & $cnt & " monitor(s):") Local $sResults = "" For $i = 1 To $cnt Local $aDPI = _Monitor_GetDPI($i) If @error Then _Log(" Monitor " & $i & ": ERROR getting DPI: @error=" & @error) $sResults &= "Monitor #" & $i & ": ERROR" & @CRLF Else Local $aInfo = _Monitor_GetInfo($i) Local $sDevice = @error ? "N/A" : $aInfo[10] _Log(" Monitor " & $i & " (" & $sDevice & "):") _Log(" DPI X: " & $aDPI[0] & ", DPI Y: " & $aDPI[1]) _Log(" Scaling: " & $aDPI[2] & "%") $sResults &= "Monitor #" & $i & " (" & $sDevice & "):" & @CRLF & _ " DPI X: " & $aDPI[0] & ", DPI Y: " & $aDPI[1] & @CRLF & _ " Scaling: " & $aDPI[2] & "%" & @CRLF EndIf Next Local $sMsg = "TEST 13: COMPLETE" & @CRLF & @CRLF & "DPI Information:" & @CRLF & $sResults If Not $g_bAutoMode Then MsgBox(64, "Example 13", $sMsg, 6) EndIf _Log('- End ------------------------------------------------/') EndFunc ;==>FuncTest_13 Func FuncTest_14() _Log('+ TEST 14: Get display orientation -------------------\') ; Get display orientation for each monitor _Monitor_GetList() Local $cnt = _Monitor_GetCount() If $cnt < 1 Then Local $sMsg = "TEST 14: SKIPPED" & @CRLF & "No monitors detected" _Log("---> Example 14: No monitors detected") If Not $g_bAutoMode Then MsgBox(64, "Example 14", $sMsg, 3) Else _Log("---> Example 14: Display orientation for " & $cnt & " monitor(s):") Local $sOrientationNames[4] = ["Landscape (0°)", "Portrait (90°)", "Landscape Flipped (180°)", "Portrait Flipped (270°)"] Local $sResults = "" For $i = 1 To $cnt Local $iOrientation = _Monitor_GetOrientation($i) If @error Then _Log(" Monitor " & $i & ": ERROR getting orientation: @error=" & @error) $sResults &= "Monitor #" & $i & ": ERROR" & @CRLF Else Local $aInfo = _Monitor_GetInfo($i) Local $sDevice = @error ? "N/A" : $aInfo[10] Local $sOrientationName = "Unknown" If $iOrientation >= 0 And $iOrientation <= 270 Then Local $iIndex = Int($iOrientation / 90) If $iIndex >= 0 And $iIndex < 4 Then $sOrientationName = $sOrientationNames[$iIndex] EndIf _Log(" Monitor " & $i & " (" & $sDevice & "): " & $iOrientation & "° (" & $sOrientationName & ")") $sResults &= "Monitor #" & $i & " (" & $sDevice & "): " & $iOrientation & "°" & @CRLF & _ " " & $sOrientationName & @CRLF EndIf Next Local $sMsg = "TEST 14: COMPLETE" & @CRLF & @CRLF & "Display Orientation:" & @CRLF & $sResults If Not $g_bAutoMode Then MsgBox(64, "Example 14", $sMsg, 5) EndIf _Log('- End ------------------------------------------------/') EndFunc ;==>FuncTest_14 Func FuncTest_15() _Log('+ TEST 15: Enumerate all display modes ---------------\') ; Enumerate all display modes for all monitors (auto mode) or selected monitor _Monitor_GetList() Local $cnt = _Monitor_GetCount() If $cnt < 1 Then Local $sMsg = "TEST 15: SKIPPED" & @CRLF & "No monitors detected" _Log("---> Example 15: No monitors detected") If Not $g_bAutoMode Then MsgBox(64, "Example 15", $sMsg, 3) Else Local $sAllResults = "" Local $iTotalModes = 0 ; In auto mode, test all monitors. Otherwise, ask user Local $bTestAll = $g_bAutoMode Local $aTestMonitors[1] = [1] ; Default to monitor 1 If Not $bTestAll And $cnt > 1 Then Local $sInput = InputBox("Example 15", "Select monitor to test (1-" & $cnt & ") or 0 for all:", "0", "", 250, 150) If Not @error And StringIsDigit($sInput) Then Local $iInput = Int($sInput) If $iInput = 0 Then $bTestAll = True ElseIf $iInput >= 1 And $iInput <= $cnt Then ; Test single monitor $bTestAll = False $aTestMonitors[0] = $iInput EndIf EndIf EndIf ; If testing all, create array of all monitor indices If $bTestAll Then ReDim $aTestMonitors[$cnt] For $i = 0 To $cnt - 1 $aTestMonitors[$i] = $i + 1 Next EndIf ; Test each monitor For $iMonitorIndex = 0 To UBound($aTestMonitors) - 1 Local $iTestMonitor = $aTestMonitors[$iMonitorIndex] Local $aModes = _Monitor_EnumAllDisplayModes($iTestMonitor) If @error Then _Log("---> Example 15: Monitor " & $iTestMonitor & " ERROR enumerating modes: @error=" & @error) $sAllResults &= "Monitor #" & $iTestMonitor & ": ERROR" & @CRLF Else Local $aInfo = _Monitor_GetInfo($iTestMonitor) Local $sDevice = @error ? "N/A" : $aInfo[10] $iTotalModes += $aModes[0][0] _Log("---> Example 15: Monitor " & $iTestMonitor & " (" & $sDevice & ") has " & $aModes[0][0] & " display mode(s):") Local $sModesList = "" Local $iShowCount = ($aModes[0][0] > 5) ? 5 : $aModes[0][0] For $i = 1 To $iShowCount Local $sModeInfo = $aModes[$i][0] & "x" & $aModes[$i][1] & " @ " & $aModes[$i][3] & "Hz, " & $aModes[$i][2] & " bpp" _Log(" Mode " & $i & ": " & $sModeInfo) $sModesList &= " " & $sModeInfo & @CRLF Next If $aModes[0][0] > 5 Then _Log(" ... and " & ($aModes[0][0] - 5) & " more mode(s)") $sModesList &= " ... and " & ($aModes[0][0] - 5) & " more mode(s)" & @CRLF EndIf If $bTestAll Then $sAllResults &= "Monitor #" & $iTestMonitor & " (" & $sDevice & "): " & $aModes[0][0] & " modes" & @CRLF & $sModesList Else $sAllResults = "Monitor #" & $iTestMonitor & " (" & $sDevice & "): " & $aModes[0][0] & " modes" & @CRLF & $sModesList EndIf EndIf Next Local $sMsg = "TEST 15: COMPLETE" & @CRLF & @CRLF If $bTestAll Then $sMsg &= "Total Modes Found: " & $iTotalModes & @CRLF & @CRLF EndIf $sMsg &= "Display Modes:" & @CRLF & $sAllResults If Not $g_bAutoMode Then MsgBox(64, "Example 15", $sMsg, 10) EndIf _Log('- End ------------------------------------------------/') EndFunc ;==>FuncTest_15 Func FuncTest_16() _Log('+ TEST 16: Get monitor from rectangle ----------------\') ; Get monitor that overlaps with a rectangle _Monitor_GetList() Local $cnt = _Monitor_GetCount() If $cnt < 1 Then Local $sMsg = "TEST 16: SKIPPED" & @CRLF & "No monitors detected" _Log("---> Example 16: No monitors detected") If Not $g_bAutoMode Then MsgBox(64, "Example 16", $sMsg, 3) Else ; Create a test rectangle (center of primary monitor) Local $prim = _Monitor_GetPrimary() If $prim = 0 Then $prim = 1 Local $iLeft, $iTop, $iRight, $iBottom _Monitor_GetBounds($prim, $iLeft, $iTop, $iRight, $iBottom) Local $iCenterX = $iLeft + ($iRight - $iLeft) / 2 Local $iCenterY = $iTop + ($iBottom - $iTop) / 2 Local $iRectW = 200, $iRectH = 150 Local $iRectLeft = $iCenterX - $iRectW / 2 Local $iRectTop = $iCenterY - $iRectH / 2 Local $iRectRight = $iCenterX + $iRectW / 2 Local $iRectBottom = $iCenterY + $iRectH / 2 _Log("---> Example 16: Testing rectangle: L=" & $iRectLeft & ", T=" & $iRectTop & ", R=" & $iRectRight & ", B=" & $iRectBottom) Local $iMonitor = _Monitor_GetFromRect($iRectLeft, $iRectTop, $iRectRight, $iRectBottom) If @error Then Local $sMsg = "TEST 16: FAILED" & @CRLF & "ERROR getting monitor from rect" & @CRLF & "@error=" & @error _Log("---> Example 16: ERROR getting monitor from rect: @error=" & @error) If Not $g_bAutoMode Then MsgBox(48, "Example 16", $sMsg, 3) Else If $iMonitor > 0 Then Local $aInfo = _Monitor_GetInfo($iMonitor) Local $sDevice = @error ? "N/A" : $aInfo[10] Local $sPrimary = @error ? "" : ($aInfo[9] ? " [PRIMARY]" : "") Local $sMsg = "TEST 16: SUCCESS" & @CRLF & @CRLF & _ "Test Rectangle:" & @CRLF & _ " Left: " & $iRectLeft & ", Top: " & $iRectTop & @CRLF & _ " Right: " & $iRectRight & ", Bottom: " & $iRectBottom & @CRLF & @CRLF & _ "Found Monitor: #" & $iMonitor & $sPrimary & @CRLF & _ "Device: " & $sDevice _Log("---> Example 16: Rectangle overlaps with Monitor #" & $iMonitor & " (" & $sDevice & ")") If Not $g_bAutoMode Then MsgBox(64, "Example 16", $sMsg, 4) Else Local $sMsg = "TEST 16: NO MATCH" & @CRLF & @CRLF & "Rectangle does not overlap with any monitor" _Log("---> Example 16: Rectangle does not overlap with any monitor") If Not $g_bAutoMode Then MsgBox(48, "Example 16", $sMsg, 3) EndIf EndIf EndIf _Log('- End ------------------------------------------------/') EndFunc ;==>FuncTest_16 Func FuncTest_17() _Log('+ TEST 17: Get monitor from window -------------------\') ; Get monitor containing a specific window _Monitor_GetList() ; Try to find Notepad or use current active window Local $hWnd = WinGetHandle("[CLASS:Notepad]") If @error Or Not $hWnd Then $hWnd = WinGetHandle("[ACTIVE]") If @error Or Not $hWnd Then _Log("---> Example 17: No suitable window found. Opening Notepad...") $pidNotepad = Run("notepad.exe") If WinWaitActive("[CLASS:Notepad]", "", 3) Then Sleep(500) $hWnd = WinGetHandle("[CLASS:Notepad]") Else _Log("---> Example 17: ERROR - Could not find or create test window") Return EndIf EndIf EndIf If $hWnd Then Local $sTitle = WinGetTitle($hWnd) _Log("---> Example 17: Testing window: " & ($sTitle = "" ? "[No Title]" : $sTitle) & " (Handle: " & $hWnd & ")") Local $iMonitor = _Monitor_GetFromWindow($hWnd) If @error Then _Log("---> Example 17: ERROR getting monitor from window: @error=" & @error) Else If $iMonitor > 0 Then Local $aInfo = _Monitor_GetInfo($iMonitor) Local $sDevice = @error ? "N/A" : $aInfo[10] Local $sPrimary = @error ? "" : ($aInfo[9] ? " [PRIMARY]" : "") _Log("---> Example 17: Window is on Monitor #" & $iMonitor & " (" & $sDevice & ")" & $sPrimary) ; Get window position for verification Local $aWinPos = WinGetPos($hWnd) If Not @error Then _Log(" Window position: X=" & $aWinPos[0] & ", Y=" & $aWinPos[1]) _Log(" Monitor bounds: L=" & $aInfo[1] & ", T=" & $aInfo[2] & ", R=" & $aInfo[3] & ", B=" & $aInfo[4]) EndIf Local $sMsg = "TEST 17: SUCCESS" & @CRLF & @CRLF & _ "Window: " & ($sTitle = "" ? "[No Title]" : $sTitle) & @CRLF & _ "Handle: " & $hWnd & @CRLF & @CRLF & _ "Monitor: #" & $iMonitor & $sPrimary & @CRLF & _ "Device: " & $sDevice & @CRLF & @CRLF & _ "Window Position:" & @CRLF & _ " X: " & $aWinPos[0] & ", Y: " & $aWinPos[1] If Not $g_bAutoMode Then MsgBox(64, "Example 17", $sMsg, 5) Else _Log("---> Example 17: Window is not on any monitor") EndIf EndIf EndIf _Log('- End ------------------------------------------------/') EndFunc ;==>FuncTest_17 ; ================================================================================================== ; Small helper to push item into dynamic array (simple) ; ================================================================================================== Func __ArrayAdd(ByRef $a, $v) Local $n = 0 If IsArray($a) Then $n = UBound($a) ReDim $a[$n + 1] $a[$n] = $v EndFunc ;==>__ArrayAdd EG2 TEST MONITOR RESOLUTION CHANGING: #include "Monitor_UDF.au3" #RequireAdmin ; Test hàm _Monitor_SetResolution ; Chương trình sẽ: ; 1. Lấy danh sách tất cả độ phân giải hỗ trợ ; 2. Lưu độ phân giải hiện tại ; 3. Thử thay đổi từng độ phân giải ; 4. Xác thực mỗi lần thay đổi ; 5. Khôi phục về độ phân giải ban đầu ConsoleWrite("=== TEST MONITOR RESOLUTION CHANGING ===" & @CRLF & @CRLF) ; Chọn màn hình cần test (thay đổi số này nếu muốn test màn hình khác) Local $iMonitorToTest = 1 ; Kiểm tra màn hình tồn tại Local $iMonitorCount = _Monitor_GetCount() If $iMonitorCount = 0 Then ConsoleWrite("ERROR: No monitors detected!" & @CRLF) Exit EndIf If $iMonitorToTest > $iMonitorCount Then ConsoleWrite("ERROR: Monitor " & $iMonitorToTest & " does not exist. Total monitors: " & $iMonitorCount & @CRLF) Exit EndIf ConsoleWrite("Testing Monitor #" & $iMonitorToTest & @CRLF) Local $aInfo = _Monitor_GetInfo($iMonitorToTest) If @error Then ConsoleWrite("ERROR: Cannot get monitor info. Error: " & @error & @CRLF) Exit EndIf ConsoleWrite("Device: " & $aInfo[10] & @CRLF & @CRLF) ; Bước 1: Lấy độ phân giải hiện tại ConsoleWrite("Step 1: Getting current resolution..." & @CRLF) Local $aOriginalSettings = _Monitor_GetDisplaySettings($iMonitorToTest) If @error Then ConsoleWrite("ERROR: Cannot get current display settings. Error: " & @error & @CRLF) Exit EndIf Local $iOriginalWidth = $aOriginalSettings[0] Local $iOriginalHeight = $aOriginalSettings[1] Local $iOriginalBits = $aOriginalSettings[2] Local $iOriginalFreq = $aOriginalSettings[3] ConsoleWrite("Current Resolution: " & $iOriginalWidth & "x" & $iOriginalHeight & _ " @ " & $iOriginalBits & " bits, " & $iOriginalFreq & " Hz" & @CRLF & @CRLF) ; Bước 2: Lấy danh sách tất cả độ phân giải hỗ trợ ConsoleWrite("Step 2: Enumerating all supported resolutions..." & @CRLF) Local $aModes = _Monitor_EnumAllDisplayModes($iMonitorToTest) If @error Then ConsoleWrite("ERROR: Cannot enumerate display modes. Error: " & @error & @CRLF) Exit EndIf ConsoleWrite("Found " & $aModes[0][0] & " display modes" & @CRLF & @CRLF) ; Lọc và tạo danh sách độ phân giải duy nhất (bỏ qua refresh rate) Local $aUniqueResolutions[1][3] ; [Width, Height, BitsPerPixel] $aUniqueResolutions[0][0] = 0 For $i = 1 To $aModes[0][0] Local $iWidth = $aModes[$i][0] Local $iHeight = $aModes[$i][1] Local $iBits = $aModes[$i][2] ; Kiểm tra xem độ phân giải này đã có chưa Local $bExists = False For $j = 1 To $aUniqueResolutions[0][0] If $aUniqueResolutions[$j][0] = $iWidth And _ $aUniqueResolutions[$j][1] = $iHeight And _ $aUniqueResolutions[$j][2] = $iBits Then $bExists = True ExitLoop EndIf Next If Not $bExists Then ReDim $aUniqueResolutions[$aUniqueResolutions[0][0] + 2][3] $aUniqueResolutions[0][0] += 1 $aUniqueResolutions[$aUniqueResolutions[0][0]][0] = $iWidth $aUniqueResolutions[$aUniqueResolutions[0][0]][1] = $iHeight $aUniqueResolutions[$aUniqueResolutions[0][0]][2] = $iBits EndIf Next ConsoleWrite("Unique resolutions: " & $aUniqueResolutions[0][0] & @CRLF) ; Hiển thị danh sách (tối đa 20 độ phân giải đầu tiên) Local $iDisplayCount = ($aUniqueResolutions[0][0] > 20) ? 20 : $aUniqueResolutions[0][0] For $i = 1 To $iDisplayCount ConsoleWrite(" [" & $i & "] " & $aUniqueResolutions[$i][0] & "x" & $aUniqueResolutions[$i][1] & _ " @ " & $aUniqueResolutions[$i][2] & " bits" & @CRLF) Next If $aUniqueResolutions[0][0] > 20 Then ConsoleWrite(" ... and " & ($aUniqueResolutions[0][0] - 20) & " more resolutions" & @CRLF) EndIf ConsoleWrite(@CRLF) ; Bước 3: Chọn một vài độ phân giải phổ biến để test ConsoleWrite("Step 3: Testing resolution changes..." & @CRLF) ConsoleWrite("NOTE: Display may flicker during tests." & @CRLF) ConsoleWrite("Waiting 3 seconds before starting..." & @CRLF & @CRLF) Sleep(3000) ; Tìm các độ phân giải phổ biến để test Local $aTestResolutions[][] = [ _ [800, 600], _ [1024, 768], _ [1280, 720], _ [1280, 1024], _ [1366, 768], _ [1920, 1080], _ [2560, 1440], _ [3840, 2160] _ ] Local $iTestCount = 0 Local $iSuccessCount = 0 Local $iFailCount = 0 For $i = 0 To UBound($aTestResolutions) - 1 Local $iTestWidth = $aTestResolutions[$i][0] Local $iTestHeight = $aTestResolutions[$i][1] ; Kiểm tra xem độ phân giải này có được hỗ trợ không Local $bSupported = False For $j = 1 To $aUniqueResolutions[0][0] If $aUniqueResolutions[$j][0] = $iTestWidth And $aUniqueResolutions[$j][1] = $iTestHeight Then $bSupported = True ExitLoop EndIf Next If Not $bSupported Then ConsoleWrite(" [SKIP] " & $iTestWidth & "x" & $iTestHeight & " - Not supported" & @CRLF) ContinueLoop EndIf ; Bỏ qua nếu đây là độ phân giải hiện tại If $iTestWidth = $iOriginalWidth And $iTestHeight = $iOriginalHeight Then ConsoleWrite(" [SKIP] " & $iTestWidth & "x" & $iTestHeight & " - Current resolution" & @CRLF) ContinueLoop EndIf $iTestCount += 1 ConsoleWrite(" [TEST " & $iTestCount & "] Changing to " & $iTestWidth & "x" & $iTestHeight & "... ") ; Thử thay đổi độ phân giải Local $iResult = _Monitor_SetResolution($iMonitorToTest, $iTestWidth, $iTestHeight, $iOriginalBits) Local $iError = @error Local $iExtended = @extended If $iError Then $iFailCount += 1 ConsoleWrite("FAILED!" & @CRLF) ConsoleWrite(" Error: " & $iError & ", Extended: " & $iExtended) ; Giải thích mã lỗi Switch $iExtended Case -1 ConsoleWrite(" (DISP_CHANGE_FAILED)" & @CRLF) Case -2 ConsoleWrite(" (DISP_CHANGE_BADMODE)" & @CRLF) Case -3 ConsoleWrite(" (DISP_CHANGE_NOTUPDATED)" & @CRLF) Case -4 ConsoleWrite(" (DISP_CHANGE_BADFLAGS)" & @CRLF) Case -5 ConsoleWrite(" (DISP_CHANGE_BADPARAM)" & @CRLF) Case -6 ConsoleWrite(" (DISP_CHANGE_BADDUALVIEW)" & @CRLF) Case Else ConsoleWrite(@CRLF) EndSwitch ContinueLoop EndIf ; Chờ màn hình ổn định Sleep(1000) ; Xác thực lại độ phân giải Local $aNewSettings = _Monitor_GetDisplaySettings($iMonitorToTest) If @error Then $iFailCount += 1 ConsoleWrite("FAILED!" & @CRLF) ConsoleWrite(" Cannot verify new resolution. Error: " & @error & @CRLF) ContinueLoop EndIf Local $iNewWidth = $aNewSettings[0] Local $iNewHeight = $aNewSettings[1] ; Kiểm tra xem độ phân giải có thay đổi thành công không If $iNewWidth = $iTestWidth And $iNewHeight = $iTestHeight Then $iSuccessCount += 1 ConsoleWrite("SUCCESS!" & @CRLF) ConsoleWrite(" Verified: " & $iNewWidth & "x" & $iNewHeight & _ " @ " & $aNewSettings[2] & " bits, " & $aNewSettings[3] & " Hz" & @CRLF) Else $iFailCount += 1 ConsoleWrite("FAILED!" & @CRLF) ConsoleWrite(" Expected: " & $iTestWidth & "x" & $iTestHeight & @CRLF) ConsoleWrite(" Got: " & $iNewWidth & "x" & $iNewHeight & @CRLF) EndIf ; Chờ một chút trước khi thử độ phân giải tiếp theo Sleep(2000) Next ConsoleWrite(@CRLF) ConsoleWrite("Test Summary:" & @CRLF) ConsoleWrite(" Total tests: " & $iTestCount & @CRLF) ConsoleWrite(" Successful: " & $iSuccessCount & @CRLF) ConsoleWrite(" Failed: " & $iFailCount & @CRLF) ConsoleWrite(@CRLF) ; Bước 4: Khôi phục về độ phân giải ban đầu ConsoleWrite("Step 4: Restoring original resolution..." & @CRLF) ConsoleWrite(" Changing back to " & $iOriginalWidth & "x" & $iOriginalHeight & "... ") Local $iRestore = _Monitor_SetResolution($iMonitorToTest, $iOriginalWidth, $iOriginalHeight, $iOriginalBits, $iOriginalFreq) If @error Then ConsoleWrite("FAILED!" & @CRLF) ConsoleWrite(" ERROR: Cannot restore original resolution. Error: " & @error & ", Extended: " & @extended & @CRLF) ConsoleWrite(" You may need to manually change resolution back in Windows Display Settings." & @CRLF) Else Sleep(1000) ; Xác thực lại Local $aRestoreSettings = _Monitor_GetDisplaySettings($iMonitorToTest) If @error Then ConsoleWrite("FAILED!" & @CRLF) ConsoleWrite(" Cannot verify restoration. Error: " & @error & @CRLF) ElseIf $aRestoreSettings[0] = $iOriginalWidth And $aRestoreSettings[1] = $iOriginalHeight Then ConsoleWrite("SUCCESS!" & @CRLF) ConsoleWrite(" Restored to: " & $aRestoreSettings[0] & "x" & $aRestoreSettings[1] & _ " @ " & $aRestoreSettings[2] & " bits, " & $aRestoreSettings[3] & " Hz" & @CRLF) Else ConsoleWrite("FAILED!" & @CRLF) ConsoleWrite(" Resolution mismatch after restore!" & @CRLF) EndIf EndIf ConsoleWrite(@CRLF & "=== TEST COMPLETED ===" & @CRLF)1 point
-
Monitor UDF - Advanced monitor management and multi-monitor utilities.
argumentum reacted to Trong for a topic
Added function!1 point -
Hey ioa, just a suggestion - have you tried giving ownerdrawn buttons a go? WM_DRAWITEM triggers, and will tell you the button state so you can draw it accordingly. Basically you can have your button react to changes in focus, checked, depressed, greyed out states etc etc - without the need for manufacturing events via those dummy controls.1 point
-
yeah, I'd imagine if you were going to accommodate for this, you'd want to change $iEnd = 0 meaning "end of array" and make people use the Default keyword. It would be a script breaking change though. And to be consistent you'll also want to check how "0" and "-1" are used throughout other funcs in the UDF... I'd say there'll be quite a bit of "If $iParam < 1" logic! But its not us that you need to persuade - so if you feel strongly enough about it, you can always make the suggestion in the bugtrac .1 point
-
Get SSL ExpiryTime
Musashi reacted to argumentum for a topic
Updated the code above. Posting a "bump" type of post because if you are using this, there were 2 entries that needed to FreeMem in _WinHttp_SSL_Info() and didn't in the prior version.1 point -
Nah, that would be even worst. Let say I want to start at position 3 and search until the end. Based on help file, I would use : _ArraySearch($aArray, 5, 3, 0) But on your logic, I would get an error !1 point
-
Latest v2.5 update now available, see the first post. It took two days for my Kobo device battery to get flat enough, before I could resume troubleshooting. During that process I discovered some other issues and fixed them too, So see this update as a BUGFIX Update. [Wednesday 5th November 2025] & [Saturday 8th November 2025] (v2.5) As always with this project, testing is a challenge, so only minimal testing has occurred so far. That means it is recommended you play it safe and do your own backups, until sure my program is reliable ... behaves as it should.1 point
-
How to detect when Start menu opens (Win10/Win11)
Nine reacted to WildByDesign for a topic
This is certainly much better. I was jumping through hoops to get the title/text when it was already possible to get it with what you had originally provided. I think that what got me going in that direction initially was that your original example was comparing "Démarrer" as title/text. So I misunderstood and assumed that I had to put the language specific spelling for "Start". And technically, I do have to. But your updated script does it much better than the extra stuff that I did. Thank you for your time. I really do appreciate it. I tend to ask a lot of questions which I always end up learning significantly from. And having different mindsets come together as they do in this forum, it is always intriguing to see that you can often have the same goal, but with many different methods to achieve it the same goal. As they often say, there is "more than one way to skin a cat". Odd phrase, but that is the true outcome (minus the cats) of many threads in this forum and always insightful to learn this way.1 point -
How to detect when Start menu opens (Win10/Win11)
WildByDesign reacted to Nine for a topic
Yes it does work. But you could have used the code (that I first post) which reads the name of the start button (should be the same as the title of the window). That would gives you something like this : #include "..\UIAutomation\Includes\UIAEH_AutomationEventHandler.au3" #include <Constants.au3> Opt("MustDeclareVars", True) Global $oWinStart, $sStart HotKeySet("{ESC}", Terminate) Example() Func Example() ; Create UI Automation object Local $oUIAutomation = ObjCreateInterface($sCLSID_CUIAutomation, $sIID_IUIAutomation, $dtag_IUIAutomation) If Not IsObj($oUIAutomation) Then Exit ConsoleWrite("$oUIAutomation ERR" & @CRLF) ;ConsoleWrite("$oUIAutomation OK" & @CRLF) ; Get Desktop element Local $pDesktop, $oDesktop $oUIAutomation.GetRootElement($pDesktop) $oDesktop = ObjCreateInterface($pDesktop, $sIID_IUIAutomationElement, $dtag_IUIAutomationElement) If Not IsObj($oDesktop) Then Exit ConsoleWrite("$oDesktop ERR" & @CRLF) ;ConsoleWrite("$oDesktop OK" & @CRLF) ; Get Start button Local $pCondition, $pStart, $oStart $oUIAutomation.CreatePropertyCondition($UIA_AutomationIdPropertyId, "StartButton", $pCondition) $oDesktop.FindFirst($TreeScope_Descendants, $pCondition, $pStart) $oStart = ObjCreateInterface($pStart, $sIID_IUIAutomationElement, $dtag_IUIAutomationElement) If Not IsObj($oStart) Then Exit ConsoleWrite("$oStart ERR" & @CRLF) ;ConsoleWrite("$oStart OK" & @CRLF) $oStart.GetCurrentPropertyValue($UIA_NamePropertyId, $sStart) ConsoleWriteEx($sStart & @CRLF) UIAEH_AutomationEventHandlerCreate() If Not IsObj($oUIAEH_AutomationEventHandler) Then Exit ConsoleWrite("$oUIAEH_AutomationEventHandler ERR" & @CRLF) ;ConsoleWrite("$oUIAEH_AutomationEventHandler OK" & @CRLF) $oUIAutomation.AddAutomationEventHandler($UIA_Window_WindowOpenedEventId, $pDesktop, $TreeScope_Subtree, 0, $oUIAEH_AutomationEventHandler) Local $hWndStart While Sleep(100) If IsObj($oWinStart) Then If Not $hWndStart Then ConsoleWrite("Start Window showed" & @CRLF) $oWinStart.GetCurrentPropertyValue($UIA_NativeWindowHandlePropertyId, $hWndStart) ElseIf Not WinExists($hWndStart) Then $oWinStart.Release() $oWinStart = 0 $hWndStart = 0 ConsoleWrite("Start window closed" & @CRLF) EndIf EndIf WEnd EndFunc ;==>Example Func UIAEH_AutomationEventHandler_HandleAutomationEvent($pSelf, $pSender, $iEventId) Local $oSender = ObjCreateInterface($pSender, $sIID_IUIAutomationElement, $dtag_IUIAutomationElement) $oSender.AddRef() Local $sTitle, $sClass $oSender.GetCurrentPropertyValue($UIA_NamePropertyId, $sTitle) $oSender.GetCurrentPropertyValue($UIA_ClassNamePropertyId, $sClass) If $sTitle = $sStart And $sClass = "Windows.UI.Core.CoreWindow" Then $oWinStart = $oSender EndFunc ;==>UIAEH_AutomationEventHandler_HandleAutomationEvent Func ConsoleWriteEx($sString) ConsoleWrite(BinaryToString(StringToBinary($sString, $SB_UTF8), $SB_ANSI)) EndFunc ;==>ConsoleWriteEx Func Terminate() UIAEH_AutomationEventHandlerDelete() Exit EndFunc ;==>Terminate ps. I removed $bTreated as it is redundant with the $hWinStart1 point -
Hi all, I'll try to keep this succinct... Since windows 10 1903 it has been possible to embed UWP controls (i.e. XAML controls) in win32 apps. The container that holds a XAML control is a XAML Island. For non-legacy media playback, Microsoft tells us to use the WinRT MediaPlayer object with the MediaPlayerElement control. MediaPlayerElement is the UI & video rendering component of the player (the XAML control). The other MediaPlayer object is the bones of the player which you attach to the control. To get this working you annoyingly need to add the maxversiontested element to the application manifest. There's script in the zip which will copy AutoIt.exe (or AutoIt_x64.exe if you're using it) and update its manifest. If you replace the original file with the modified one, you should be able to successfully run the example with the F5 key. Or here's a screenshot if you just want to see the result! PS. As an aside, Another way of approaching modern playback is via MediaEngine which we've recently attempted to get going. This approach doesn't play well with autoit though, and you need to do ungodly things to prevent callbacks from crashing your script! MediaPlayer.zip1 point
-
MediaPlayerElement - WinRT Xaml Island
MattyD reacted to WildByDesign for a topic
These functions all work perfectly. These allow more possibilities with your MediaPlayer UDF which is fantastic. Thank you for the update, Matty.1 point -
MediaPlayerElement - WinRT Xaml Island
WildByDesign reacted to MattyD for a topic
yeah I'll have a closer look tonight, but it looks like you need to get this object: Windows.Media.Playback.MediaPlaybackSession So get the MediaPlayer object (NOT the mediaPlayerElement) switch to the IMediaPlayer3 interface (using _WinRT_SwitchInterface()) call IMediaPlayer3_GetPlaybackSession to get the playbackSession obj Presumably that new obj will be on IMediaPlaybackSession, but switch to this if need be! then IMediaPlaybackSession_GetNaturalVideoWidth() and IMediaPlaybackSession_GetNaturalVideoHeight() make sense?1 point -
perfectly rectangular buttons when set color ?
MoriceGrene reacted to Nine for a topic
Just use a label : #include <GUIConstants.au3> Example() Func Example() Local $hGUI = GUICreate("Example", 300, 200) Local $idBtn = GUICtrlCreateLabel("Exit", 120, 150, 85, 25, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetBkColor(-1, 0x71A0FF) GUISetState() While True Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $idBtn ConsoleWrite("button pressed" & @CRLF) EndSwitch WEnd EndFunc ;==>Example1 point -
Guiscape -- A new GUI builder project!
MattyD reacted to jaberwacky for a topic
WUUUTTTT? This is AWESOME!!!!1 point -
AutoIt Live Wallpaper
MattyD reacted to WildByDesign for a topic
I got a chance to test the functions now and they work beautifully. It's really interesting getting to change it and see how different videos of other aspect ratios behave. Thanks again.1 point -
perfectly rectangular buttons when set color ?
MoriceGrene reacted to WildByDesign for a topic
I would strongly recommend the GuiFlatButton UDF. It's perfectly square buttons. And it also lets you control colors for all states. You can even color borders of each button. It's a fantastic UDF.1 point -
AutoIt Live Wallpaper
MattyD reacted to WildByDesign for a topic
Thank you so much for this, Matty. Being able to use string is a bonus as well since I may very well make it so that the user can choose which stretch option in the config file. I haven't had a chance to play around with it much yet since I just got my butt kicked by Au3Stripper for around 2 hours. I finally won that fight! 🤪1 point -
AutoIt Live Wallpaper
WildByDesign reacted to MattyD for a topic
yep, so it looks like none is native res, cropped to size of player. fill is stretched/squished to player size Uniform is pillar/letter box UniformToFill will maintain aspect and crop whatever doesn't fit.1 point -
AutoIt Live Wallpaper
WildByDesign reacted to argumentum for a topic
Stretching it would look ugly. I was thinking of proportional by... , any means.1 point -
AutoIt Live Wallpaper
WildByDesign reacted to MattyD for a topic
yeah no worries.. How's this? You should hopefully be able to get/set the property in both its string and numeric forms. Func _MediaPlayer_GetStretch($iMPIdx, $bAsString = False) Local $vStretch If $iMPIdx < 1 Or $iMPIdx >= UBound($__g_apPlayers) Then Return False _WinRT_SwitchInterface($__g_apMPElements[$iMPIdx], $sIID_IMediaPlayerElement) If Not @error Then $vStretch = IMediaPlayerElement_GetStretch($__g_apMPElements[$iMPIdx]) If @error Then Return SetError(@error, @extended, -1) If $bAsString Then $vStretch = _WinRT_GetEnum($mStretch, $vStretch) Return $vStretch EndFunc Func _MediaPlayer_SetStretch($iMPIdx, $vStretch) If $iMPIdx < 1 Or $iMPIdx >= UBound($__g_apPlayers) Then Return False _WinRT_SwitchInterface($__g_apMPElements[$iMPIdx], $sIID_IMediaPlayerElement) If Not @error Then If IsString($vStretch) Then $vStretch = _WinRT_GetEnum($mStretch, $vStretch) IMediaPlayerElement_SetStretch($__g_apMPElements[$iMPIdx], $vStretch) EndIf Return SetError(@error, @extended, @error = $S_OK) EndFunc ;~ Field : None = 0 (Microsoft.UI.Xaml.Media.Stretch) ;~ Field : Fill = 1 (Microsoft.UI.Xaml.Media.Stretch) ;~ Field : Uniform = 2 (Microsoft.UI.Xaml.Media.Stretch) ;~ Field : UniformToFill = 3 (Microsoft.UI.Xaml.Media.Stretch) _MediaPlayer_SetStretch($hPlayer1, "UniformToFill") ConsoleWrite("stretch = " & _MediaPlayer_GetStretch($hPlayer1, True) & @CRLF)1 point -
AutoIt Live Wallpaper
argumentum reacted to WildByDesign for a topic
This is something that I definitely will have to look into. The pixel size of all monitors comes directly from _WinAPI_EnumDisplayMonitors and the GUI size for each monitor comes from there. I have a feeling that it might have something to do with MediaPlayerElement.Stretch Property. It has video stretch options such as: None, Fill, UniformToFill and Uniform That is one thing that I struggling with setting with the MediaPlayerElement stuff. No matter what I did, it failed. So it stayed as default. The default option of Uniform can leave the black bars depending on the aspect ratio of the video. @MattyD Do you know much about this? We can talk about it here or in your thread, it's up to you. But I had previously tried the various *SetStretch functions and never had any luck. I could always run the *GetStretch functions and get returns. Setting them never worked for me though.1 point -
AutoIt Live Wallpaper
WildByDesign reacted to argumentum for a topic
Ok !. Did it and it played in both monitors. Now, one of them is an ultrawide one ( 2560x1080 ) and saw black bars on each side. It would be nice to take that into account and display proportional but with the greater size ( width or height ) into consideration. So how ?!. Well, stand your monitor on it's side ( or just in your head ) and on portrait orientation to test on your side and confirm your math1 point -
AutoIt Live Wallpaper
argumentum reacted to WildByDesign for a topic
That does sound like a smart investment! I ended up testing it by hooking up my laptop to my TV with an HDMI cable and setting it to extended multi-monitor option. It worked good. But I can't imagine someone running it on 3 or 4 screens. Thank you for testing. Yes, if it's just black screen with no video that just means it needs to be patched, you're right. But that black screen is enough for me to confirm that it went to all screens properly. And as long as all screens were 100% covered black, that means that the GUI measurements were good too. But if there were some gaps that were not black, that means my math is bad again. 😀1 point -
AutoIt Live Wallpaper
WildByDesign reacted to argumentum for a topic
... <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> <application> <!--The ID below indicates application support for Windows Vista --> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> <!--The ID below indicates application support for Windows 7 --> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> <!--The ID below indicates application support for Windows 8 --> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> <!--The ID below indicates application support for Windows 8.1 --> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> <!--The ID below indicates application support for Windows 10 --> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/> </application> </compatibility> </assembly> ... Runed it with the above. Did black out both monitors and restored the wallpaper just fine. But did not play the included bloom.mp4. Maybe because I need to patch the exe/wrapper ?1 point -
AutoIt Live Wallpaper
WildByDesign reacted to argumentum for a topic
If you can spend some $30 + $80 you too can have one. Call it investment1 point -
MouseTail revisited A bit of fun doesn't hurt Look at tray menu for config Only tested on Win 11 MouseTail.v1.0.0.3.au31 point
-
The name you choose is a misnomer. "proper case" refers to capitalizing the first letter of each word in a sentence, like this: "Proper Case" Refers To Capitalizing The First Letter Of Each Word In A Sentence1 point
-
Guiscape -- A new GUI builder project!
argumentum reacted to jaberwacky for a topic
Sorry, I meant oopsies in applying the DPI stuff1 point -
Guiscape -- A new GUI builder project!
jaberwacky reacted to argumentum for a topic
1 point -
Guiscape -- A new GUI builder project!
jaberwacky reacted to WildByDesign for a topic
Everything looks sharp on my end.1 point -
GuiCtrlCreatePic equivalent for PNG or TIFF images?
hudsonhock reacted to AutoBert for a topic
I don't know if it works with TIF's but sure it works with PNG's. Edit: Just tested with the welcomefax.tif (the onliest tif i have) and it works: #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseX64=y #AutoIt3Wrapper_AU3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <GUIConstantsEx.au3> #include <StaticConstants.au3> #include <WindowsConstants.au3> #include <GUICtrlPic.au3> #include <Array.au3> Global $hGui = GUICreate("Show Tif",@DesktopWidth, @DesktopHeight) Global $aDim = WinGetClientSize($hGui) Global $sAutoItPath If @Compiled Then $sAutoItPath=RegRead64('HKLM\Software\AutoIt v3\AutoIt', 'InstallDir')&'\' Else $sAutoItPath= StringReplace(@AutoItExe, "autoit3.exe", "")&'\' $sAutoItPath= StringReplace(@AutoItExe, "autoit3_x64.exe", "") EndIf Global $Background = _GUICtrlPic_Create("C:\Users\(len)Bert\Downloads\Documents\Fax\Inbox\WelcomeFax.tif", 0, 0, $aDim[0], $aDim[1], $SS_CENTERIMAGE, Default) GUICtrlSetState(-1, $Gui_DISABLE) GUISetState() While 1 Switch GUIGetMsg() Case $Gui_EVENT_CLOSE Exit EndSwitch WEnd Func RegRead64($sKeyname, $sValue) ;Aus AutoUpdateIt.au3 Local $sRes = RegRead($sKeyname, $sValue) If @error And @AutoItX64 Then $sKeyname = StringReplace($sKeyname, "HKEY_LOCAL_MACHINE", "HKLM") $sKeyname = StringReplace($sKeyname, "HKLM\SOFTWARE\", "HKLM\SOFTWARE\Wow6432Node\") $sRes = RegRead($sKeyname, $sValue) If @error Then SetError(1) Return "" EndIf EndIf SetError(0) Return $sRes EndFunc ;==>RegRead64 GUICtrlPic.au31 point -
Here is an example how to translate error message: #include <Array.au3> #include <WinApi.au3> #include <MsgBoxConstants.au3> If $IDYES = MsgBox($MB_YESNO, 'Make a decision', 'Do you want to inercept error ?') Then AddHookApi("user32.dll", "MessageBoxW", "Intercept_MessageBoxW", "int", "hwnd;wstr;wstr;uint") EndIf _Example() Func _Example() ;~ _ErrorTranslator(Default) ; check your translation ; Let's try it ; Usual message box MsgBox(0, 'Test', 'Some text') ; Cause error that would say some AutoIt shit happened, but now it wouldn't say "AutoIt" DllStructCreate("byte[123456789097]") ; The End EndFunc ;==>_Example ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Func Intercept_MessageBoxW($hWnd, $sText, $sTitle, $iType) Local $aCall = DllCall("user32.dll", "int", "MessageBoxW", _ "hwnd", $hWnd, _ "wstr", _ErrorTranslator($sText), _ "wstr", StringReplace($sTitle, "AutoIt", 'Error occured in ' & @ScriptName), _ "uint", $iType) If @error Or Not $aCall[0] Then Return 0 Return $aCall[0] EndFunc ;==>Intercept_MessageBoxW ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; The magic is down below Func AddHookApi($sModuleName, $vFunctionName, $vNewFunction, $sRet = "", $sParams = "") Local Static $pImportDirectory, $hInstance Local Const $IMAGE_DIRECTORY_ENTRY_IMPORT = 1 If Not $pImportDirectory Then $hInstance = _WinAPI_GetModuleHandle(0) $pImportDirectory = ImageDirectoryEntryToData($hInstance, $IMAGE_DIRECTORY_ENTRY_IMPORT) If @error Then Return SetError(1, 0, 0) EndIf Local $iIsInt = IsInt($vFunctionName) Local $iRestore = Not IsString($vNewFunction) Local $tIMAGE_IMPORT_MODULE_DIRECTORY Local $pDirectoryOffset = $pImportDirectory Local $tModuleName Local $iInitialOffset, $iInitialOffset2 Local $iOffset2 Local $tBufferOffset2, $iBufferOffset2 Local $tBuffer, $tFunctionOffset, $pOld, $fMatch, $pModuleName, $pFuncName Local Const $PAGE_READWRITE = 0x04 While 1 $tIMAGE_IMPORT_MODULE_DIRECTORY = DllStructCreate("dword RVAOriginalFirstThunk;" & _ "dword TimeDateStamp;" & _ "dword ForwarderChain;" & _ "dword RVAModuleName;" & _ "dword RVAFirstThunk", _ $pDirectoryOffset) If Not DllStructGetData($tIMAGE_IMPORT_MODULE_DIRECTORY, "RVAFirstThunk") Then ExitLoop $pModuleName = $hInstance + DllStructGetData($tIMAGE_IMPORT_MODULE_DIRECTORY, "RVAModuleName") $tModuleName = DllStructCreate("char Name[" & _WinAPI_StringLenA($pModuleName) & "]", $pModuleName) If DllStructGetData($tModuleName, "Name") = $sModuleName Then ; function from this module $iInitialOffset = $hInstance + DllStructGetData($tIMAGE_IMPORT_MODULE_DIRECTORY, "RVAFirstThunk") $iInitialOffset2 = $hInstance + DllStructGetData($tIMAGE_IMPORT_MODULE_DIRECTORY, "RVAOriginalFirstThunk") If $iInitialOffset2 = $hInstance Then $iInitialOffset2 = $iInitialOffset $iOffset2 = 0 While 1 $tBufferOffset2 = DllStructCreate("dword_ptr", $iInitialOffset2 + $iOffset2) $iBufferOffset2 = DllStructGetData($tBufferOffset2, 1) If Not $iBufferOffset2 Then ExitLoop If $iIsInt Then If BitAND($iBufferOffset2, 0xFFFFFF) = $vFunctionName Then $fMatch = True ; wanted function Else $pFuncName = $hInstance + $iBufferOffset2 + 2 ; 2 is size od "word", see line below... $tBuffer = DllStructCreate("word Ordinal; char Name[" & _WinAPI_StringLenA($pFuncName) & "]", $hInstance + $iBufferOffset2) If DllStructGetData($tBuffer, "Name") == $vFunctionName Then $fMatch = True ; wanted function EndIf If $fMatch Then $tFunctionOffset = DllStructCreate("ptr", $iInitialOffset + $iOffset2) VirtualProtect(DllStructGetPtr($tFunctionOffset), DllStructGetSize($tFunctionOffset), $PAGE_READWRITE) If @error Then Return SetError(3, 0, 0) $pOld = DllStructGetData($tFunctionOffset, 1) If $iRestore Then DllStructSetData($tFunctionOffset, 1, $vNewFunction) Else DllStructSetData($tFunctionOffset, 1, DllCallbackGetPtr(DllCallbackRegister($vNewFunction, $sRet, $sParams))) EndIf Return $pOld EndIf $iOffset2 += DllStructGetSize($tBufferOffset2) WEnd ExitLoop EndIf $pDirectoryOffset += 20 ; size of $tIMAGE_IMPORT_MODULE_DIRECTORY WEnd Return SetError(4, 0, 0) EndFunc ;==>AddHookApi Func VirtualProtect($pAddress, $iSize, $iProtection) Local $aCall = DllCall("kernel32.dll", "bool", "VirtualProtect", "ptr", $pAddress, "dword_ptr", $iSize, "dword", $iProtection, "dword*", 0) If @error Or Not $aCall[0] Then Return SetError(1, 0, 0) Return 1 EndFunc ;==>VirtualProtect Func ImageDirectoryEntryToData($hInstance, $iDirectoryEntry) ; Get pointer to data Local $pPointer = $hInstance ; Start processing passed binary data. 'Reading' PE format follows. Local $tIMAGE_DOS_HEADER = DllStructCreate("char Magic[2];" & _ "word BytesOnLastPage;" & _ "word Pages;" & _ "word Relocations;" & _ "word SizeofHeader;" & _ "word MinimumExtra;" & _ "word MaximumExtra;" & _ "word SS;" & _ "word SP;" & _ "word Checksum;" & _ "word IP;" & _ "word CS;" & _ "word Relocation;" & _ "word Overlay;" & _ "char Reserved[8];" & _ "word OEMIdentifier;" & _ "word OEMInformation;" & _ "char Reserved2[20];" & _ "dword AddressOfNewExeHeader", _ $pPointer) Local $sMagic = DllStructGetData($tIMAGE_DOS_HEADER, "Magic") ; Check if it's valid format If Not ($sMagic == "MZ") Then Return SetError(1, 0, 0) ; MS-DOS header missing. Btw 'MZ' are the initials of Mark Zbikowski in case you didn't know. ; Move pointer $pPointer += DllStructGetData($tIMAGE_DOS_HEADER, "AddressOfNewExeHeader") ; move to PE file header ; In place of IMAGE_NT_SIGNATURE structure Local $tIMAGE_NT_SIGNATURE = DllStructCreate("dword Signature", $pPointer) ; Check signature If DllStructGetData($tIMAGE_NT_SIGNATURE, "Signature") <> 17744 Then ; IMAGE_NT_SIGNATURE Return SetError(2, 0, 0) ; wrong signature. For PE image should be "PE\0\0" or 17744 dword. EndIf ; Move pointer $pPointer += 4 ; size of $tIMAGE_NT_SIGNATURE structure ; In place of IMAGE_FILE_HEADER structure ; Move pointer $pPointer += 20 ; size of $tIMAGE_FILE_HEADER structure ; Determine the type Local $tMagic = DllStructCreate("word Magic;", $pPointer) Local $iMagic = DllStructGetData($tMagic, 1) Local $tIMAGE_OPTIONAL_HEADER If $iMagic = 267 Then ; x86 version ; Move pointer $pPointer += 96 ; size of $tIMAGE_OPTIONAL_HEADER ElseIf $iMagic = 523 Then ; x64 version ; Move pointer $pPointer += 112 ; size of $tIMAGE_OPTIONAL_HEADER Else Return SetError(3, 0, 0) ; unsupported module type EndIf ; Validate input by checking available number of structures that are in the module Local Const $IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16 ; predefined value that PE modules always use (AutoIt certainly) If $iDirectoryEntry > $IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1 Then Return SetError(4, 0, 0) ; invalid input ; Calculate the offset to wanted entry (every entry is 8 bytes) $pPointer += 8 * $iDirectoryEntry ; At place of correst directory entry Local $tIMAGE_DIRECTORY_ENTRY = DllStructCreate("dword VirtualAddress; dword Size", $pPointer) ; Collect data Local $pAddress = DllStructGetData($tIMAGE_DIRECTORY_ENTRY, "VirtualAddress") If $pAddress = 0 Then Return SetError(5, 0, 0) ; invalid input ; $pAddress is RVA, add it to base address Return $hInstance + $pAddress EndFunc ;==>ImageDirectoryEntryToData Func _ErrorTranslator($sText = Default) Local Static $aErrorMessages = _ [ _ [ _ "(Paused) ", _ "" _ ], _ [ _ "AutoIt Error", _ "" _ ], _ [ _ "AutoIt has detected the stack has become corrupt.\n\nStack corruption typically occurs when either the wrong calling convention is used or when the function is called with the wrong number of arguments.\n\nAutoIt supports the __stdcall (WINAPI) and __cdecl calling conventions. The __stdcall (WINAPI) convention is used by default but __cdecl can be used instead. See the DllCall() documentation for details on changing the calling convention.", _ "" _ ], _ [ _ """EndWith"" missing ""With"".", _ "" _ ], _ [ _ "Badly formatted ""Func"" statement.", _ "" _ ], _ [ _ """With"" missing ""EndWith"".", _ "" _ ], _ [ _ "Missing right bracket ')' in expression.", _ "" _ ], _ [ _ "Missing operator in expression.", _ "" _ ], _ [ _ "Unbalanced brackets in expression.", _ "" _ ], _ [ _ "Error in expression.", _ "" _ ], _ [ _ "Error parsing function call.", _ "" _ ], _ [ _ "Incorrect number of parameters in function call.", _ "" _ ], _ [ _ """ReDim"" used without an array variable.", _ "" _ ], _ [ _ "Illegal text at the end of statement (one statement per line).", _ "" _ ], _ [ _ """If"" statement has no matching ""EndIf"" statement.", _ "" _ ], _ [ _ """Else"" statement with no matching ""If"" statement.", _ "" _ ], _ [ _ """EndIf"" statement with no matching ""If"" statement.", _ "" _ ], _ [ _ "Too many ""Else"" statements for matching ""If"" statement.", _ "" _ ], _ [ _ """While"" statement has no matching ""Wend"" statement.", _ "" _ ], _ [ _ """Wend"" statement with no matching ""While"" statement.", _ "" _ ], _ [ _ "Variable used without being declared.", _ "" _ ], _ [ _ "Array variable has incorrect number of subscripts or subscript dimension range exceeded.", _ "" _ ], _ [ _ "Variable subscript badly formatted.", _ "" _ ], _ [ _ "Subscript used on non-accessible variable.", _ "" _ ], _ [ _ "Too many subscripts used for an array.", _ "" _ ], _ [ _ "Missing subscript dimensions in ""Dim"" statement.", _ "" _ ], _ [ _ "No variable given for ""Dim"", ""Local"", ""Global"", ""Struct"" or ""Const"" statement.", _ "" _ ], _ [ _ "Expected a ""="" operator in assignment statement.", _ "" _ ], _ [ _ "Invalid keyword at the start of this line.", _ "" _ ], _ [ _ "Array maximum size exceeded.", _ "" _ ], _ [ _ """Func"" statement has no matching ""EndFunc"".", _ "" _ ], _ [ _ "Duplicate function name.", _ "" _ ], _ [ _ "Unknown function name.", _ "" _ ], _ [ _ "Unknown macro.", _ "" _ ], _ [ _ "Unable to get a list of running processes.", _ "" _ ], _ [ _ "Invalid element in a DllStruct.", _ "" _ ], _ [ _ "Unknown option or bad parameter specified.", _ "" _ ], _ [ _ "Unable to load the internet libraries.", _ "" _ ], _ [ _ """Struct"" statement has no matching ""EndStruct"".", _ "" _ ], _ [ _ "Unable to open file, the maximum number of open files has been exceeded.", _ "" _ ], _ [ _ """ContinueLoop"" statement with no matching ""While"", ""Do"" or ""For"" statement.", _ "" _ ], _ [ _ "Invalid file filter given.", _ "" _ ], _ [ _ "Expected a variable in user function call.", _ "" _ ], _ [ _ """Do"" statement has no matching ""Until"" statement.", _ "" _ ], _ [ _ """Until"" statement with no matching ""Do"" statement.", _ "" _ ], _ [ _ """For"" statement is badly formatted.", _ "" _ ], _ [ _ """Next"" statement with no matching ""For"" statement.", _ "" _ ], _ [ _ """ExitLoop/ContinueLoop"" statements only valid from inside a For/Do/While loop.", _ "" _ ], _ [ _ """For"" statement has no matching ""Next"" statement.", _ "" _ ], _ [ _ """Case"" statement with no matching ""Select""or ""Switch"" statement.", _ "" _ ], _ [ _ """EndSelect"" statement with no matching ""Select"" statement.", _ "" _ ], _ [ _ "Recursion level has been exceeded - AutoIt will quit to prevent stack overflow.", _ "" _ ], _ [ _ "Cannot make existing variables static.", _ "" _ ], _ [ _ "Cannot make static variables into regular variables.", _ "" _ ], _ [ _ "Badly formated Enum statement", _ "" _ ], _ [ _ "This keyword cannot be used after a ""Then"" keyword.", _ "" _ ], _ [ _ """Select"" statement is missing ""EndSelect"" or ""Case"" statement.", _ "" _ ], _ [ _ """If"" statements must have a ""Then"" keyword.", _ "" _ ], _ [ _ "Badly formated Struct statement.", _ "" _ ], _ [ _ "Cannot assign values to constants.", _ "" _ ], _ [ _ "Cannot make existing variables into constants.", _ "" _ ], _ [ _ "Only Object-type variables allowed in a ""With"" statement.", _ "" _ ], _ [ _ """long_ptr"", ""int_ptr"" and ""short_ptr"" DllCall() types have been deprecated. Use ""long*"", ""int*"" and ""short*"" instead.", _ "" _ ], _ [ _ "Object referenced outside a ""With"" statement.", _ "" _ ], _ [ _ "Nested ""With"" statements are not allowed.", _ "" _ ], _ [ _ "Variable must be of type ""Object"".", _ "" _ ], _ [ _ "The requested action with this object has failed.", _ "" _ ], _ [ _ "Variable appears more than once in function declaration.", _ "" _ ], _ [ _ "ReDim array can not be initialized in this manner.", _ "" _ ], _ [ _ "An array variable can not be used in this manner.", _ "" _ ], _ [ _ "Can not redeclare a constant.", _ "" _ ], _ [ _ "Can not redeclare a parameter inside a user function.", _ "" _ ], _ [ _ "Can pass constants by reference only to parameters with ""Const"" keyword.", _ "" _ ], _ [ _ "Can not initialize a variable with itself.", _ "" _ ], _ [ _ "Incorrect way to use this parameter.", _ "" _ ], _ [ _ """EndSwitch"" statement with no matching ""Switch"" statement.", _ "" _ ], _ [ _ """Switch"" statement is missing ""EndSwitch"" or ""Case"" statement.", _ "" _ ], _ [ _ """ContinueCase"" statement with no matching ""Select""or ""Switch"" statement.", _ "" _ ], _ [ _ "Assert Failed!", _ "" _ ], _ [ _ "Obsolete function/parameter.", _ "" _ ], _ [ _ "Invalid Exitcode (reserved for AutoIt internal use).", _ "" _ ], _ [ _ "Variable cannot be accessed in this manner.", _ "" _ ], _ [ _ "Func reassign not allowed.", _ "" _ ], _ [ _ "Func reassign on global level not allowed.", _ "" _ ], _ [ _ "Unable to parse line.", _ "" _ ], _ [ _ "Unable to open the script file.", _ "" _ ], _ [ _ "String missing closing quote.", _ "" _ ], _ [ _ "Badly formated variable or macro.", _ "" _ ], _ [ _ "Missing separator character after keyword.", _ "" _ ], _ [ _ "Error allocating memory.", _ "Błąd allokacji pamięci." _ ] _ ] Local Static $aErrorMessages2 = _ [ _ ["(Paused) ", ""], _ ["AutoIt Error", ""], _ ["AutoIt has detected the stack has become corrupt.\n\nStack corruption typically occurs when either the wrong calling convention is used or when the function is called with the wrong number of arguments.\n\nAutoIt supports the __stdcall (WINAPI) and __cdecl calling conventions. The __stdcall (WINAPI) convention is used by default but __cdecl can be used instead. See the DllCall() documentation for details on changing the calling convention.", ""], _ ["""EndWith"" missing ""With"".", ""], _ ["Badly formatted ""Func"" statement.", ""], _ ["""With"" missing ""EndWith"".", ""], _ ["Missing right bracket ')' in expression.", ""], _ ["Missing operator in expression.", ""], _ ["Unbalanced brackets in expression.", ""], _ ["Error in expression.", ""], _ ["Error parsing function call.", ""], _ ["Incorrect number of parameters in function call.", ""], _ ["""ReDim"" used without an array variable.", ""], _ ["Illegal text at the end of statement (one statement per line).", ""], _ ["""If"" statement has no matching ""EndIf"" statement.", ""], _ ["""Else"" statement with no matching ""If"" statement.", ""], _ ["""EndIf"" statement with no matching ""If"" statement.", ""], _ ["Too many ""Else"" statements for matching ""If"" statement.", ""], _ ["""While"" statement has no matching ""Wend"" statement.", ""], _ ["""Wend"" statement with no matching ""While"" statement.", ""], _ ["Variable used without being declared.", ""], _ ["Array variable has incorrect number of subscripts or subscript dimension range exceeded.", ""], _ ["Variable subscript badly formatted.", ""], _ ["Subscript used on non-accessible variable.", ""], _ ["Too many subscripts used for an array.", ""], _ ["Missing subscript dimensions in ""Dim"" statement.", ""], _ ["No variable given for ""Dim"", ""Local"", ""Global"", ""Struct"" or ""Const"" statement.", ""], _ ["Expected a ""="" operator in assignment statement.", ""], _ ["Invalid keyword at the start of this line.", ""], _ ["Array maximum size exceeded.", ""], _ ["""Func"" statement has no matching ""EndFunc"".", ""], _ ["Duplicate function name.", ""], _ ["Unknown function name.", ""], _ ["Unknown macro.", ""], _ ["Unable to get a list of running processes.", ""], _ ["Invalid element in a DllStruct.", ""], _ ["Unknown option or bad parameter specified.", ""], _ ["Unable to load the internet libraries.", ""], _ ["""Struct"" statement has no matching ""EndStruct"".", ""], _ ["Unable to open file, the maximum number of open files has been exceeded.", ""], _ ["""ContinueLoop"" statement with no matching ""While"", ""Do"" or ""For"" statement.", ""], _ ["Invalid file filter given.", ""], _ ["Expected a variable in user function call.", ""], _ ["""Do"" statement has no matching ""Until"" statement.", ""], _ ["""Until"" statement with no matching ""Do"" statement.", ""], _ ["""For"" statement is badly formatted.", ""], _ ["""Next"" statement with no matching ""For"" statement.", ""], _ ["""ExitLoop/ContinueLoop"" statements only valid from inside a For/Do/While loop.", ""], _ ["""For"" statement has no matching ""Next"" statement.", ""], _ ["""Case"" statement with no matching ""Select""or ""Switch"" statement.", ""], _ ["""EndSelect"" statement with no matching ""Select"" statement.", ""], _ ["Recursion level has been exceeded - AutoIt will quit to prevent stack overflow.", ""], _ ["Cannot make existing variables static.", ""], _ ["Cannot make static variables into regular variables.", ""], _ ["Badly formated Enum statement", ""], _ ["This keyword cannot be used after a ""Then"" keyword.", ""], _ ["""Select"" statement is missing ""EndSelect"" or ""Case"" statement.", ""], _ ["""If"" statements must have a ""Then"" keyword.", ""], _ ["Badly formated Struct statement.", ""], _ ["Cannot assign values to constants.", ""], _ ["Cannot make existing variables into constants.", ""], _ ["Only Object-type variables allowed in a ""With"" statement.", ""], _ ["""long_ptr"", ""int_ptr"" and ""short_ptr"" DllCall() types have been deprecated. Use ""long*"", ""int*"" and ""short*"" instead.", ""], _ ["Object referenced outside a ""With"" statement.", ""], _ ["Nested ""With"" statements are not allowed.", ""], _ ["Variable must be of type ""Object"".", ""], _ ["The requested action with this object has failed.", ""], _ ["Variable appears more than once in function declaration.", ""], _ ["ReDim array can not be initialized in this manner.", ""], _ ["An array variable can not be used in this manner.", ""], _ ["Can not redeclare a constant.", ""], _ ["Can not redeclare a parameter inside a user function.", ""], _ ["Can pass constants by reference only to parameters with ""Const"" keyword.", ""], _ ["Can not initialize a variable with itself.", ""], _ ["Incorrect way to use this parameter.", ""], _ ["""EndSwitch"" statement with no matching ""Switch"" statement.", ""], _ ["""Switch"" statement is missing ""EndSwitch"" or ""Case"" statement.", ""], _ ["""ContinueCase"" statement with no matching ""Select""or ""Switch"" statement.", ""], _ ["Assert Failed!", ""], _ ["Obsolete function/parameter.", ""], _ ["Invalid Exitcode (reserved for AutoIt internal use).", ""], _ ["Variable cannot be accessed in this manner.", ""], _ ["Func reassign not allowed.", ""], _ ["Func reassign on global level not allowed.", ""], _ ["Unable to parse line.", ""], _ ["Unable to open the script file.", ""], _ ["String missing closing quote.", ""], _ ["Badly formated variable or macro.", ""], _ ["Missing separator character after keyword.", ""], _ ["Error allocating memory.", "Błąd allokacji pamięci."] _ ] ConsoleWrite("! $sText= " & $sText & @CRLF) For $iError_idx = 0 To UBound($aErrorMessages) - 1 If $aErrorMessages[$iError_idx][0] = $sText Then $sText = $aErrorMessages[$iError_idx][1] EndIf Next If Not @Compiled And $sText = Default Then _ArrayDisplay($aErrorMessages) If Not @Compiled And $sText = Default Then _ArrayDisplay($aErrorMessages2) Return $sText EndFunc ;==>_ErrorTranslator1 point
-
Here, let me then: #include <WinApi.au3> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; AddHookApi("user32.dll", "MessageBoxW", "Intercept_MessageBoxW", "int", "hwnd;wstr;wstr;uint") Func Intercept_MessageBoxW($hWnd, $sText, $sTitle, $iType) Local $aCall = DllCall("user32.dll", "int", "MessageBoxW", _ "hwnd", $hWnd, _ "wstr", $sText, _ "wstr", StringReplace($sTitle, "AutoIt", @ScriptName), _ "uint", $iType) If @error Or Not $aCall[0] Then Return 0 Return $aCall[0] EndFunc ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Let's try it ; Usual message box MsgBox(0, 'Test', 'Some text') ; Cause error that would say some AutoIt shit happened, but now it wouldn't say "AutoIt" DllStructCreate("byte[123456789097]") ; The End ; The magic is down below Func AddHookApi($sModuleName, $vFunctionName, $vNewFunction, $sRet = "", $sParams = "") Local Static $pImportDirectory, $hInstance Local Const $IMAGE_DIRECTORY_ENTRY_IMPORT = 1 If Not $pImportDirectory Then $hInstance = _WinAPI_GetModuleHandle(0) $pImportDirectory = ImageDirectoryEntryToData($hInstance, $IMAGE_DIRECTORY_ENTRY_IMPORT) If @error Then Return SetError(1, 0, 0) EndIf Local $iIsInt = IsInt($vFunctionName) Local $iRestore = Not IsString($vNewFunction) Local $tIMAGE_IMPORT_MODULE_DIRECTORY Local $pDirectoryOffset = $pImportDirectory Local $tModuleName Local $iInitialOffset, $iInitialOffset2 Local $iOffset2 Local $tBufferOffset2, $iBufferOffset2 Local $tBuffer, $tFunctionOffset, $pOld, $fMatch, $pModuleName, $pFuncName Local Const $PAGE_READWRITE = 0x04 While 1 $tIMAGE_IMPORT_MODULE_DIRECTORY = DllStructCreate("dword RVAOriginalFirstThunk;" & _ "dword TimeDateStamp;" & _ "dword ForwarderChain;" & _ "dword RVAModuleName;" & _ "dword RVAFirstThunk", _ $pDirectoryOffset) If Not DllStructGetData($tIMAGE_IMPORT_MODULE_DIRECTORY, "RVAFirstThunk") Then ExitLoop $pModuleName = $hInstance + DllStructGetData($tIMAGE_IMPORT_MODULE_DIRECTORY, "RVAModuleName") $tModuleName = DllStructCreate("char Name[" & _WinAPI_StringLenA($pModuleName) & "]", $pModuleName) If DllStructGetData($tModuleName, "Name") = $sModuleName Then ; function from this module $iInitialOffset = $hInstance + DllStructGetData($tIMAGE_IMPORT_MODULE_DIRECTORY, "RVAFirstThunk") $iInitialOffset2 = $hInstance + DllStructGetData($tIMAGE_IMPORT_MODULE_DIRECTORY, "RVAOriginalFirstThunk") If $iInitialOffset2 = $hInstance Then $iInitialOffset2 = $iInitialOffset $iOffset2 = 0 While 1 $tBufferOffset2 = DllStructCreate("dword_ptr", $iInitialOffset2 + $iOffset2) $iBufferOffset2 = DllStructGetData($tBufferOffset2, 1) If Not $iBufferOffset2 Then ExitLoop If $iIsInt Then If BitAND($iBufferOffset2, 0xFFFFFF) = $vFunctionName Then $fMatch = True; wanted function Else $pFuncName = $hInstance + $iBufferOffset2 + 2 ; 2 is size od "word", see line below... $tBuffer = DllStructCreate("word Ordinal; char Name[" & _WinAPI_StringLenA($pFuncName) & "]", $hInstance + $iBufferOffset2) If DllStructGetData($tBuffer, "Name") == $vFunctionName Then $fMatch = True; wanted function EndIf If $fMatch Then $tFunctionOffset = DllStructCreate("ptr", $iInitialOffset + $iOffset2) VirtualProtect(DllStructGetPtr($tFunctionOffset), DllStructGetSize($tFunctionOffset), $PAGE_READWRITE) If @error Then Return SetError(3, 0, 0) $pOld = DllStructGetData($tFunctionOffset, 1) If $iRestore Then DllStructSetData($tFunctionOffset, 1, $vNewFunction) Else DllStructSetData($tFunctionOffset, 1, DllCallbackGetPtr(DllCallbackRegister($vNewFunction, $sRet, $sParams))) EndIf Return $pOld EndIf $iOffset2 += DllStructGetSize($tBufferOffset2) WEnd ExitLoop EndIf $pDirectoryOffset += 20 ; size of $tIMAGE_IMPORT_MODULE_DIRECTORY WEnd Return SetError(4, 0, 0) EndFunc Func VirtualProtect($pAddress, $iSize, $iProtection) Local $aCall = DllCall("kernel32.dll", "bool", "VirtualProtect", "ptr", $pAddress, "dword_ptr", $iSize, "dword", $iProtection, "dword*", 0) If @error Or Not $aCall[0] Then Return SetError(1, 0, 0) Return 1 EndFunc Func ImageDirectoryEntryToData($hInstance, $iDirectoryEntry) ; Get pointer to data Local $pPointer = $hInstance ; Start processing passed binary data. 'Reading' PE format follows. Local $tIMAGE_DOS_HEADER = DllStructCreate("char Magic[2];" & _ "word BytesOnLastPage;" & _ "word Pages;" & _ "word Relocations;" & _ "word SizeofHeader;" & _ "word MinimumExtra;" & _ "word MaximumExtra;" & _ "word SS;" & _ "word SP;" & _ "word Checksum;" & _ "word IP;" & _ "word CS;" & _ "word Relocation;" & _ "word Overlay;" & _ "char Reserved[8];" & _ "word OEMIdentifier;" & _ "word OEMInformation;" & _ "char Reserved2[20];" & _ "dword AddressOfNewExeHeader", _ $pPointer) Local $sMagic = DllStructGetData($tIMAGE_DOS_HEADER, "Magic") ; Check if it's valid format If Not ($sMagic == "MZ") Then Return SetError(1, 0, 0) ; MS-DOS header missing. Btw 'MZ' are the initials of Mark Zbikowski in case you didn't know. ; Move pointer $pPointer += DllStructGetData($tIMAGE_DOS_HEADER, "AddressOfNewExeHeader") ; move to PE file header ; In place of IMAGE_NT_SIGNATURE structure Local $tIMAGE_NT_SIGNATURE = DllStructCreate("dword Signature", $pPointer) ; Check signature If DllStructGetData($tIMAGE_NT_SIGNATURE, "Signature") <> 17744 Then ; IMAGE_NT_SIGNATURE Return SetError(2, 0, 0) ; wrong signature. For PE image should be "PE\0\0" or 17744 dword. EndIf ; Move pointer $pPointer += 4 ; size of $tIMAGE_NT_SIGNATURE structure ; In place of IMAGE_FILE_HEADER structure ; Move pointer $pPointer += 20 ; size of $tIMAGE_FILE_HEADER structure ; Determine the type Local $tMagic = DllStructCreate("word Magic;", $pPointer) Local $iMagic = DllStructGetData($tMagic, 1) Local $tIMAGE_OPTIONAL_HEADER If $iMagic = 267 Then ; x86 version ; Move pointer $pPointer += 96 ; size of $tIMAGE_OPTIONAL_HEADER ElseIf $iMagic = 523 Then ; x64 version ; Move pointer $pPointer += 112 ; size of $tIMAGE_OPTIONAL_HEADER Else Return SetError(3, 0, 0) ; unsupported module type EndIf ; Validate input by checking available number of structures that are in the module Local Const $IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16 ; predefined value that PE modules always use (AutoIt certainly) If $iDirectoryEntry > $IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1 Then Return SetError(4, 0, 0) ; invalid input ; Calculate the offset to wanted entry (every entry is 8 bytes) $pPointer += 8 * $iDirectoryEntry ; At place of correst directory entry Local $tIMAGE_DIRECTORY_ENTRY = DllStructCreate("dword VirtualAddress; dword Size", $pPointer) ; Collect data Local $pAddress = DllStructGetData($tIMAGE_DIRECTORY_ENTRY, "VirtualAddress") If $pAddress = 0 Then Return SetError(5, 0, 0) ; invalid input ; $pAddress is RVA, add it to base address Return $hInstance + $pAddress EndFuncedit: because this is better than before.1 point