Jump to content

Recommended Posts

Posted

This is a continuation (in a slightly expanded way) from the original Move window behind desktop icons thread by @Parsix and should be an interesting challenge.

This example uses some code put together from @UEZ, @Nine and @argumentum.

For those not familiar with the previous thread, it is essentially moving the GUI in front of the wallpaper but behind the desktop icons in a WorkerW window within Progman (Program Manager).

The goal of this thread is to see if there is any possible way to (at least momentarily) access controls in that GUI because you generally cannot click on them. Example: desktop widgets, live video wallpapers, etc.

The example below can be exited by pressing Escape. It contains a simple Slider control with a label that changes based on the value of the Slider. There is a button, that when pressed, will initiate the drop into the WorkerW window.

There is a Tooltip that will show the Parent window class and Child window class of whatever the cursor is over at the time. This may or may not be helpful for figuring out ideas. Anytime you click on the desktop (Progman), it will output a line into the console. It is that part of the code where I placed a comment "; do action here if needed" that would be a potential place to add code if there is something that we can do to access the control(s) based on clicking on the desktop.

To be quite honest, I don't know if this is even possible. I don't know if we need to temporarily reverse the _WinAPI_SetParent function (initially GUI to WorkerW, maybe WorkerW back to GUI) although that would bring the entire GUI forward. It would be better if just the Slider control could somehow come forward in some way.

Example:

;Code by UEZ, Nine, argumentum
#include <WinAPI.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WindowsNotifsConstants.au3>
#include <GuiSlider.au3>
#include <SliderConstants.au3>
#include <WinAPIvkeysConstants.au3>
#include <Misc.au3>

Opt("GUIOnEventMode", 1)
HotKeySet("{Esc}", "_Exit")

DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext" , "HWND", "DPI_AWARENESS_CONTEXT" -4)

Global $idSlider1, $idLabel1
Global Const $TRBN_THUMBPOSCHANGING = -1502
Global Const $tagTRBTHUMBPOSCHANGING = $tagNMHDR & ";dword Pos;int Reason"
Global Const $TBS_NOTIFYBEFOREMOVE = 2048

Global $hParentWnd, $hMainWnd, $hRoot, $hChildWnd, $hMainWnd_Old = -1, $tPoint
Global Static $iTimeLast
Global $aKeys[1] = [$VK_LBUTTON]
Global $hUser32 = DllOpen('user32.dll')

Global $aPrimary = GetPrimaryMonitorCoords()
If @error Then Exit MsgBox(16, "Error", "Unable to get primary monitor")
Global $hProgman = WinGetHandle("[CLASS:Progman]"), $hWorkerW, $i
If Not $hProgman Then Exit MsgBox(16, "ERROR", "Couldn't find Progman", 30)
_WinAPI_SendMessageTimeout($hProgman, 0x052C, 13, 1, 250, $SMTO_NORMAL)

Global $hWorkerW = _WinAPI_FindWindowEx($hProgman, 0, "WorkerW", "")
If $hWorkerW = 0 Then Exit MsgBox(16, "ERROR", "Couldn't find WorkerW under Progman", 30)

Local $aOrigin = GetDesktopOrigin()
Local $iX = $aPrimary[0] - $aOrigin[0]
Local $iY = $aPrimary[1] - $aOrigin[1]

Global $hGUI = GUICreate("GUI behind Desktop icons", $aPrimary[4], $aPrimary[5], $iX, $iY, $WS_POPUP, $WS_EX_TOOLWINDOW)
GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")
GUISetBkColor(0x202020)
GUISetFont(40)

$idSlider1 = GUICtrlCreateSlider(@DesktopWidth / 4, @DesktopHeight / 4, @DesktopWidth / 2, @DesktopHeight / 6, BitOR($TBS_AUTOTICKS, $TBS_NOTIFYBEFOREMOVE))
GUICtrlSetBkColor(-1, 0x202020)
GUICtrlSetColor(-1, 0xFFFFFF)
GUICtrlSetLimit(-1, 100, 0)
GUICtrlSetData($idSlider1, 100)

$idLabel1 = GUICtrlCreateLabel("100", @DesktopWidth / 2.1, @DesktopHeight / 3, -1, -1)
GUICtrlSetBkColor(-1, 0x202020)
GUICtrlSetColor(-1, 0xFFFFFF)

GUISetFont(12)
GUICtrlCreateButton("Place GUI Behind WorkerW", @DesktopWidth / 2.2, @DesktopHeight / 2, -1, -1)
GUICtrlSetOnEvent(-1, "_dropBehind")

GUICtrlSendMsg($idSlider1, $WM_CHANGEUISTATE, 65537, 0)
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")

GUISetState(@SW_SHOWNOACTIVATE, $hGUI)

While 1
    $tPoint = _WinAPI_GetMousePos()
    $hMainWnd = _WinAPI_WindowFromPoint($tPoint)
    $hChildWnd = GetRealChild($hMainWnd)
    $hParentWnd = _WinAPI_GetAncestor(_WinAPI_WindowFromPoint($tPoint), $GA_ROOT)
    If $hChildWnd And $hMainWnd <> $hChildWnd Then $hMainWnd = $hChildWnd
    If $hMainWnd <> $hMainWnd_Old Then
        ToolTip("Parent: " & @TAB & _WinAPI_GetClassName($hParentWnd) & @CRLF & "Child:  " & @TAB & _WinAPI_GetClassName($hMainWnd))
        ;ConsoleWrite("Parent: " & _WinAPI_GetClassName($hParentWnd) & @CRLF)
        ;ConsoleWrite("Child:  " & _WinAPI_GetClassName($hMainWnd) & @CRLF)
        ;$hMainWnd_Old = $hMainWnd
    EndIf

    Local $iRet = _IsPressed($aKeys, $hUser32, False)

    Switch $iRet
        Case 1 ; MouseClick Left
            $tPoint = _WinAPI_GetMousePos()
            $hWndCur = _WinAPI_GetAncestor(_WinAPI_WindowFromPoint($tPoint), $GA_ROOT)
            $sParent = _WinAPI_GetClassName($hWndCur)
            If $sParent = "Progman" Then
                $iTime = Round((_WinAPI_GetTickCount64() / 1000))
                $iTimeDiff = $iTime - $iTimeLast
                ; ensure that it doesn't get hit more than once per second (approx.)
                If $iTime <> $iTimeLast Then
                    ; do action here if needed
                    ; 
                    ConsoleWrite("Desktop clicked at: " & HourAmPm(@HOUR & ":" & @MIN & ":" & @SEC) & @CRLF)
                    $iTimeLast = $iTime
                EndIf
            EndIf
    
    EndSwitch

    Sleep(200)
WEnd

GUIDelete($hGUI)

Func _dropBehind()
    _WinAPI_SetParent($hGUI, $hWorkerW)
    _WinAPI_SetWindowPos($hGUI, $HWND_BOTTOM, 0, 0, 0, 0, BitOR($SWP_NOMOVE, $SWP_NOSIZE, $SWP_NOACTIVATE))
    _WinAPI_SetWindowLong($hGUI, $GWL_EXSTYLE, BitOR(_WinAPI_GetWindowLong($hGUI, $GWL_EXSTYLE), $WS_EX_LAYERED, $WS_EX_TRANSPARENT))
    _WinAPI_SetLayeredWindowAttributes($hGUI, 0, 180, $LWA_ALPHA)
EndFunc

Func _WinAPI_FindWindowEx($hParent, $hAfter, $sClass, $sTitle = "")
    Local $ret = DllCall("user32.dll", "hwnd", "FindWindowExW", "hwnd", $hParent, "hwnd", $hAfter, "wstr", $sClass, "wstr", $sTitle)
    If @error Or Not IsArray($ret) Then Return 0
    Return $ret[0]
EndFunc   ;==>_WinAPI_FindWindowEx

Func GetPrimaryMonitorCoords()
    Local $tPoint = DllStructCreate("int x;int y")
    $tPoint.x = 0
    $tPoint.y = 0

    Local $hMonitor = _WinAPI_MonitorFromPoint($tPoint, $MONITOR_DEFAULTTOPRIMARY)
    If Not $hMonitor Then Return SetError(1, 0, 0)

    Local $tMI = DllStructCreate("dword cbSize;long rcMonitor[4];long rcWork[4];dword dwFlags")
    DllStructSetData($tMI, "cbSize", DllStructGetSize($tMI))

    Local $aCall = DllCall("user32.dll", "bool", "GetMonitorInfoW", "handle", $hMonitor, "ptr", DllStructGetPtr($tMI))
    If @error Or Not $aCall[0] Then Return SetError(2, 0, 0)

    Local $iLeft = $tMI.rcMonitor(1)
    Local $iTop = $tMI.rcMonitor(2)
    Local $iRight = $tMI.rcMonitor(3)
    Local $iBottom = $tMI.rcMonitor(4)

    Local $iWidth = $iRight - $iLeft
    Local $iHeight = $iBottom - $iTop
    Local $a[6] = [$iLeft, $iTop, $iRight, $iBottom, $iWidth, $iHeight]
    Return $a
EndFunc   ;==>GetPrimaryMonitorCoords

Func GetDesktopOrigin()
    Local $minX = 0, $minY = 0, $x, $y
    Local $i = 0, $tDevice, $aRet, $tDevMode, $aED

    While True
        $tDevice = DllStructCreate("dword cb; char DeviceName[32]; char DeviceString[128]; dword StateFlags; char DeviceID[128]; char DeviceKey[128]")
        $tDevice.cb = DllStructGetSize($tDevice)
        $aRet = DllCall("user32.dll", "bool", "EnumDisplayDevicesA", "ptr", 0, "dword", $i, "ptr", DllStructGetPtr($tDevice), "dword", 0)
        If @error Or Not $aRet[0] Then ExitLoop

        If BitAND($tDevice.StateFlags, 1) Then
            $tDevMode = DllStructCreate( _
                    "byte dmDeviceName[32]; word dmSpecVersion; word dmDriverVersion; word dmSize; word dmDriverExtra; dword dmFields;" & _
                    "long dmPositionX; long dmPositionY; dword dmDisplayOrientation; dword dmDisplayFixedOutput;" & _
                    "short dmColor; short dmDuplex; short dmYResolution; short dmTTOption; short dmCollate; char dmFormName[32];" & _
                    "ushort dmLogPixels; dword dmBitsPerPel; dword dmPelsWidth; dword dmPelsHeight;" & _
                    "dword dmDisplayFlags; dword dmDisplayFrequency; dword dmICMMethod; dword dmICMIntent;" & _
                    "dword dmMediaType; dword dmDitherType; dword dmReserved1; dword dmReserved2; dword dmPanningWidth; dword dmPanningHeight")

            $tDevMode.dmSize = DllStructGetSize($tDevMode)
            $aED = DllCall("user32.dll", "bool", "EnumDisplaySettingsA", "str", $tDevice.DeviceName, "dword", -1, "ptr", DllStructGetPtr($tDevMode))
            If Not @error And $aED[0] Then
                $x = $tDevMode.dmPositionX
                $y = $tDevMode.dmPositionY
                If $x < $minX Then $minX = $x
                If $y < $minY Then $minY = $y
            EndIf
        EndIf
        $i += 1
    WEnd
    Local $a[2] = [$minX, $minY]
    Return $a
EndFunc   ;==>GetDesktopOrigin

Func _Exit()
    GUIDelete($hGUI)
    Exit
EndFunc

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
    Local $tChange = DllStructCreate($tagTRBTHUMBPOSCHANGING, $lParam)
    If $tChange.IDfrom = $idSlider1 And $tChange.Code = $TRBN_THUMBPOSCHANGING Then
        GUICtrlSetData($idLabel1, GUICtrlRead($idSlider1))
        ;If $tChange2.Pos <> $sWatchBlurColorIntensitySlider Then
        ;    _SavedChangesStatus()
        ;EndIf
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

; #FUNCTION# ====================================================================================================================
; Name...........: HourAmPm
; Description....: Converts a time in 24-hour format to AM/PM format.
; Syntax.........: HourAmPm( $sDateTime [, $sAmPm = "AM|PM" [, $iTrimRight = 0]] )
; Parameters.....: $sDateTime - The time (with date or not) string with "HH:" in it.
;                  $sAmPm    - [optional] The AM/PM representation (default is "AM|PM").
;                  $iTrimRight - [optional] The number of characters to trim from the right of the result (default is 0).
;                  $iNoDate     - [optional] Whether to omit the date from the output. Defaults to False.
; Return values .: Success: Returns the formatted date and time in AM/PM format.
;                  Failure: None.
; Author ........: argumentum
; Modified ......:
; Remarks .......: This function takes a 24-hour time string, converts it to AM or PM format, and returns the result with optional trimming.
; Related .......:
; Link ..........: https://www.autoitscript.com/forum/index.php?showtopic=213061
; Example .......: MsgBox(64, "Converted Time", HourAmPm("12/31/1999 18:59:59"))
; ===============================================================================================================================
Func HourAmPm($sDateTime, $sAmPm = Default, $iTrimRight = Default, $iNoDate = Default)
    Local $aAmPm = StringSplit((StringInStr($sAmPm, "|") ? $sAmPm : "AM|PM"), "|"), $sFormat = $aAmPm[2]
    Local $iHourPos = StringInStr($sDateTime, ":"), $sHour = StringMid($sDateTime, $iHourPos - 2, 2)
    Local $sDate = StringLeft($sDateTime, $iHourPos - 3), $sTime = StringTrimLeft($sDateTime, $iHourPos - 1)
    If $sHour < 12 Then $sFormat = $aAmPm[1] ; https://www.autoitscript.com/forum/index.php?showtopic=213061
    $sHour = Mod($sHour, 12)
    If Not $sHour Then $sHour = 12
    Return StringTrimRight((Int($iNoDate) ? "" : $sDate) & StringRight('0' & $sHour, 2) & $sTime, Int($iTrimRight)) & " " & $sFormat
EndFunc   ;==>HourAmPm

Func _WinAPI_RealChildWindowFromPoint($hWnd, $tPoint)
  Local $aRet = DllCall('user32.dll', 'hwnd', 'RealChildWindowFromPoint', 'hwnd', $hWnd, 'struct', $tPoint)
  If @error Then Return SetError(@error, @extended, 0)
  Return $aRet[0]
EndFunc   ;==>_WinAPI_RealChildWindowFromPoint

Func GetRealChild($hWnd)
  Local $tPoint, $hRoot = _WinAPI_GetAncestor($hWnd, $GA_ROOT)
  If $hWnd = $hRoot Then
    $tPoint = _WinAPI_GetMousePos(True, $hWnd)
    Return _WinAPI_ChildWindowFromPointEx($hWnd, $tPoint)
  EndIf
  Local $hParent = _WinAPI_GetAncestor($hWnd, $GA_PARENT)
  Local $aChild = _WinAPI_EnumChildWindows($hParent)
  If @error Then Return 0

  Local $hFound

  For $i = 1 To $aChild[0][0]
    $hParent = _WinAPI_GetParent($aChild[$i][0])
    $tPoint = _WinAPI_GetMousePos(True, $hParent)
    $hFound = _WinAPI_RealChildWindowFromPoint($hParent, $tPoint)
    If $hFound = $aChild[$i][0] Then Return $hFound
  Next
  Return 0
EndFunc   ;==>GetRealChil

 

Posted
44 minutes ago, WildByDesign said:

 and @argumentum.

me ?. Well thank you, but 

Global $hWorkerW = _WinAPI_FindWindowEx($hProgman, 0, "WorkerW", "")
If $hWorkerW = 0 Then Exit MsgBox(16, "ERROR", "Couldn't find WorkerW under Progman", 30)

didn't work for me so I had to

Global $hWorkerW = _WinAPI_FindWindowEx($hProgman, 0, "WorkerW", "")

If Not $hWorkerW Then ; dah
    Local $aEnumWindows = _WinAPI_EnumWindows(False)
    For $n = 1 To UBound($aEnumWindows) - 1
        If $aEnumWindows[$n][1] <> "WorkerW" Then ContinueLoop
        If _WinAPI_GetParent($aEnumWindows[$n][0]) = $hProgman Then
            $hWorkerW = $aEnumWindows[$n][0]
            ExitLoop ; but is likely one at the end of the Z-order
        EndIf
    Next
EndIf

If $hWorkerW = 0 Then Exit MsgBox(16, "ERROR", "Couldn't find WorkerW under Progman", 30)

to find it.
So my only collaboration wasn't included !? :P 

47 minutes ago, WildByDesign said:

The goal of this thread is to see if there is any possible way to (at least momentarily) access controls in that GUI because you generally cannot click on them.

Not really but you know that. You could use something to be aware of the wheel changing and use that to move the control if, condition are met ( you can come up with something am sure ).

Also, after I closed the script, in the monitor that displayed the GUI, the wallpaper had to be reset. It was gone :( 

 

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Posted (edited)

:idea:  The example below can be exited by pressing F1 and then Escape

#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7
#include <WinAPI.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <StaticConstants.au3>

HotKeySet('{F1}', F1) ; <--

Global $idSlider, $idValueLabel, $iSliderValue = 50, $hSliderGUI, $bFlag
Global $hGUI, $BkColor = 0x000000

Example()

Func Example()
    Local $hWorkerW = _GetDesktopWorkerW()
    If @error Then Exit MsgBox(16, @ScriptName, "! Error - Couldn't find WorkerW under Progman", 30)
    ConsoleWrite("WorkerW = " & $hWorkerW & @CRLF)

    ; Overlay GUICreate ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    $hGUI = GUICreate("Overlay", @DesktopWidth, @DesktopHeight, -1, -1, $WS_POPUP, $WS_EX_TOOLWINDOW)
    GUISetBkColor($BkColor, $hGUI)

    Local $idLabelTime = GUICtrlCreateLabel("123456790", (@DesktopWidth - 400) / 2, (@DesktopHeight - 100) / 2, 400, 100, BitOR($SS_CENTER, $SS_CENTERIMAGE))
    GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)
    GUICtrlSetColor(-1, 0xFFD800)  ; text
    GUICtrlSetFont(-1, 60, 700, 0, "consolas")

    _WinAPI_SetParent($hGUI, $hWorkerW)
    _WinAPI_SetWindowLong($hGUI, $GWL_EXSTYLE, BitOR(_WinAPI_GetWindowLong($hGUI, $GWL_EXSTYLE), $WS_EX_LAYERED))
    _WinAPI_SetLayeredWindowAttributes($hGUI, $BkColor, $iSliderValue, $LWA_ALPHA)
    GUISetState(@SW_SHOWNOACTIVATE)

    ; SliderGUI GUICreate ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    $hSliderGUI = GUICreate("Slider Example", 250, 70, -1, @DesktopHeight * 0.6, $WS_POPUP)
    $idSlider = GUICtrlCreateSlider(10, 10, 230, 25)
    GUICtrlSetLimit(-1, 255, 0)
    GUICtrlSetData(-1, $iSliderValue)
    $idValueLabel = GUICtrlCreateLabel($iSliderValue, 10, 50, 230, 20, $SS_CENTER)
    GUISetState(@SW_HIDE, $hSliderGUI)

    GUIRegisterMsg($WM_HSCROLL, "WM_HSCROLL")

    Local $Tick, $sTime

    ;**********************************
    While 1
        Switch GUIGetMsg()
            Case -3 ;$GUI_EVENT_CLOSE
                ExitLoop
        EndSwitch

        If $bFlag Then
            If Not IsMouseOverWin($hSliderGUI, 10) Then
                GUISetState(@SW_HIDE, $hSliderGUI)
                $bFlag = False
            EndIf
        EndIf

        If $Tick <> @SEC Then
            $sTime = @HOUR & ":" & @MIN & ":" & @SEC
            GUICtrlSetData($idLabelTime, $sTime)
            $Tick = @SEC
        EndIf

    WEnd
    ;**********************************

EndFunc   ;==>Example
;---------------------------------------------------------------------------------------
Func F1()
    $bFlag = Not $bFlag
    If $bFlag Then
        GUISetState(@SW_SHOW, $hSliderGUI)
        MouseMove(@DesktopWidth / 2, @DesktopHeight * 0.62, 1)
    EndIf
EndFunc   ;==>F1
;---------------------------------------------------------------------------------------
Func IsMouseOverWin($hWnd, $iOffSet = 0)
    Local $aMPos = MouseGetPos()
    Local $aWPos = WinGetPos($hWnd)
    If $aMPos[0] > $aWPos[0] - $iOffSet _
            And $aMPos[1] > $aWPos[1] - $iOffSet _
            And $aMPos[0] < $aWPos[0] + $aWPos[2] + $iOffSet _
            And $aMPos[1] < $aWPos[1] + $aWPos[3] + $iOffSet Then
        Return True
    EndIf
    Return False
EndFunc   ;==>IsMouseOverWin
;---------------------------------------------------------------------------------------
Func _GetDesktopWorkerW()
    Local $hProgman = _WinAPI_GetShellWindow()
    _WinAPI_SendMessageTimeout($hProgman, 0x052C, 0, 0, 3000, $SMTO_NORMAL) ; same as _SendMessage()
    Local $aEnumWindows = WinList("[CLASS:WorkerW]")
    For $n = 1 To $aEnumWindows[0][0]
        Local $hWnd = $aEnumWindows[$n][1]
        If _WinAPI_GetParent($hWnd) = $hProgman Then Return SetError(0, $hProgman, $hWnd)
    Next
    Return SetError(1, $hProgman, 0)
EndFunc   ;==>_GetDesktopWorkerW
;---------------------------------------------------------------------------------------
Func WM_HSCROLL($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam, $lParam
    Local $hControl = $lParam
    If $hControl = GUICtrlGetHandle($idSlider) Then
        $iSliderValue = GUICtrlRead($idSlider)
        _WinAPI_SetLayeredWindowAttributes($hGUI, $BkColor, $iSliderValue, $LWA_ALPHA)
        GUICtrlSetData($idValueLabel, $iSliderValue)
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_HSCROLL
;---------------------------------------------------------------------------------------

 

Edited by ioa747
improvement

I know that I know nothing

Create an account or sign in to comment

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

Create an account

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

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

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