Jump to content

WinAPI Hidden Func


Go to solution Solved by argumentum,

Recommended Posts

Hi, everyone.

My topic is inpired by this question. The question is simple, the answer is more then fulfilling, but I am here for fun 🙂, so I desided to reinvent a wheel and imitate z-order/clipping manually.

Here is where it got me:

Spoiler

I know it does unnesesary redrawing, just tryed to simplify the code this time and cut off everything outside the question.

I know that "child" windows should coinsider Every window and not get clipped if the parent is hidden. Let's assume it is a feature not a bug.

#include <GDIPlus.au3>
#include <WinAPIProc.au3>
#include <SendMessage.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Opt('MustDeclareVars', 1)
OnAutoItExitRegister('_Exxit')

Global $idButt = -3 ;$GUI_EVENT_CLOSE
;"Child" windows get "parent" hwnd as a parametr
Global $hGui = GUICreate(($CmdLine[0] = False) ? 'OnTop' : 'Clipped', 255, 255)
If $CmdLine[0] Then
    GUISetBkColor(Random(0, 0xFFFFFF))
Else 
    $idButt = GUICtrlCreateButton('Add Auto IT Child', 42,126, 171)
EndIf
GUICtrlCreateLabel('Left Mouse button to move', 42, 42, 172)
GUICtrlCreateLabel('ESC to Exit', 42, 84, 172)
_GDIPlus_Startup()
Global $X, $Y ; to store mouse pos
GUIRegisterMsg($WM_MOVE, '_WM_MOVE')
GUIRegisterMsg($WM_MOVING, '_WM_MOVING')
GUIRegisterMsg($WM_MOUSEMOVE, '_WM_MOUSEMOVE')
Global Const $nMargin = 3
_UpdateRegion()
GUISetState()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE 
            Exit
        Case $idButt
            _AddAChild()
    EndSwitch
    _UpdateRegion()
WEnd
; ===============================================================================================================================
Func _Exxit()
    _GDIPlus_Shutdown()
    Exit
EndFunc
; ===============================================================================================================================
Func _WM_MOVE($hWndGUI, $MsgID, $WParam, $LParam)
    WinMove($hGui, '', $X, $Y)
EndFunc
; ===============================================================================================================================
Func _WM_MOVING($hWndGUI, $MsgID, $WParam, $LParam)
    Local Const $tagRectSTRUCT = 'LONG left; LONG top; LONG right; LONG bottom'
    Local $tRECT = DllStructCreate($tagRectSTRUCT, $LParam)
    $X = DllStructGetData($tRECT, 'left')
    $Y = DllStructGetData($tRECT, 'top')
    _UpdateRegion()
EndFunc
; ===============================================================================================================================
Func _WM_MOUSEMOVE($hWndGUI, $MsgID, $WParam, $LParam)
    Local Const $MK_LBUTTON = 0x0001
    Local Const $SC_MOVE = 0xF010 + 13 ; I dont really know why 13
    If BitAND($MK_LBUTTON, $WParam) Then
        _SendMessage($hGui, $WM_SYSCOMMAND, $SC_MOVE)
    EndIf
EndFunc
; ===============================================================================================================================
Func _UpdateRegion()
    If Not $CmdLine[0] Then Return
    Local $aPPos = WinGetPos(HWnd($CmdLine[1]))
    Local $aCPos = WinGetPos($hGui)
    If Not IsArray($aPPos) Then Exit
    Local $hRegionInf = _GDIPlus_RegionCreate()
    Local $hRegion = _GDIPlus_RegionCreateFromRect( _
                            $aPPos[0] - $aCPos[0] - $nMargin, _
                            $aPPos[1] - $aCPos[1] - $nMargin, _
                            $aPPos[2] +  $nMargin * 2, _
                            $aPPos[3] +  $nMargin * 2)
    _GDIPlus_RegionCombineRegion($hRegion, $hRegionInf, 3)
    Local $hRGN = _GDIPlus_RegionGetHRgn($hRegion, 0)
    _WinAPI_SetWindowRgn($hGui, $hRGN)
    _WinAPI_DeleteObject($hRGN)
    _GDIPlus_RegionDispose($hRegion)
    _GDIPlus_RegionDispose($hRegionInf)
EndFunc
; ===============================================================================================================================
Func _AddAChild()
    Switch @Compiled
        Case True
            Run(@ScriptFullPath & " " & $hGui)
        Case Else
            ShellExecute(@AutoItExe, @ScriptFullPath & ' ' & $hGui)
    EndSwitch
EndFunc
; ===============================================================================================================================


While coding this ↑ I've encountered problems would need community help with:


Why does _WinAPI_SetWindowRgn change window style?

After the func is applied window caption switches to some prehistoric version. Why?
I've tryed checking UDF source, but it does nothing, just sends data to win func.
I've tryed checking microsoft.learn for more info, but couldnt find anything there either.

How do I change it back, change it to something else?

It is probably GUISetStyle I should use, but none of style configs I applied worked. Func works fine, but there are no $WS_REJECTTRADITION / $WS_EMBRACEMODERNITY styles.
Basic functions code is not included, but I could google SetWindowLongA whitch, holding GUI Control Styles and Extended Style table, looks very similar to  GUISetStyle.
However, those style tables are the exact copy of Appendix Reference, so it is kinda useless.
How do I get ExExStyle table? Is there some kind of FullWinAPI.chm someone could share? Are there any other hidden win styles?

Why don't reference constanst work?

Lines 57-61 I send a SC_MOVE massage to a window.
Judging by SC_MOVE page. everything is OK. But cursor changes to EveryDirPos and win does not move.
On the same time adding some value (like +13), results in a moving window without changing the cursor
There is a remark saying
 

Quote

In WM_SYSCOMMAND messages, the four low-order bits of the wParam parameter are used internally by the system. To obtain the correct result when testing the value of wParam, an application must combine the value 0xFFF0 with the wParam value by using the bitwise AND operator.

 And I don't understand it. Bit AND for styleData and wParam behaves weirdly. Could someone explain that in simple english or give working examples?

Edited by LKP
Link to comment
Share on other sites

3 hours ago, LKP said:

Why does _WinAPI_SetWindowRgn change window style?

This is nonesense. If you debug the _UpdateRegion() you will see that the style of the window is never changed inside the function, so it has nothing to do with _WinAPI_SetWindowRgn(). The only time when the style of the window is changed it's when you show the window and WS_VISIBLE is added as style. Since you call _UpdateRegion() once before calling GUISetState() it's normal to see a change in window style.

3 hours ago, LKP said:

How do I change it back, change it to something else?

Hide the window. To change the style to something else you can use GUISetStyle() or _WinAPI_SetWindowLong().

3 hours ago, LKP said:

Why don't reference constanst work?

I don't have any clue what are you talking about here.

Link to comment
Share on other sites

@Andreik, thank you very much for your answer.

However, some things remain unclear for me.

17 hours ago, Andreik said:

This is nonesense. If you debug the _UpdateRegion() you will see that the style of the window is never changed inside the function, so it has nothing to do with _WinAPI_SetWindowRgn(). The only time when the style of the window is changed it's when you show the window and WS_VISIBLE is added as style. Since you call _UpdateRegion() once before calling GUISetState() it's normal to see a change in window style.

It sounds like nonesense to me either, but I can see the changes and can't find the solution.
The problem, by the way, also affects Autoit UDF examples. In _GDIPlus_RegionCombinePath example window caption looks like one from Win 98 too.

I've deleted every call of _UpdateRegion() in cycles, so that it could only be launched by button, added a MsgBox before and after the _WinAPI_SetWindowRgn.
And it definitely changes.
I've tested it at home and on two laptops at work. Win 7, Win 10, Win 11 give the same result. 
But it could be that my AutoIt zip is somehow broken, so I will attach a screenshot with two types of styles. There the top purple window has win 98 style caption. It is blue and the buttons are smaller.

I cant see why that happens and would like to know how to switch it.

17 hours ago, Andreik said:

I don't have any clue what are you talking about here.

Yesterday I was not in the condition to write using the second language.😀
I will try to express myself in a more clear way this time.

So, I want to learn how to use _SendMessage
AutoItHelp files were not that helpful with that, so I tried to get the information I needed on learn.microsoft.
For testing I decided to send WM_SYSCOMMAND, which would move my window.

learn.microsoft says that the message uses only the wParam parameter, which is supposed to be SC_MOVE (0xF010) to move a window.
But when I post WM_SYSCOMMAND with the 0xF010 parameter to my window, the cusor moves and changes to an arrow pointing in every direction (like $MCID_SIZEALL)
Eventually, I made WM_SYSCOMMAND move the window by adding 13 to 0xF010, but I don't know why. I dont know what I miss.

The only guess is the remark WM_SYSCOMMAND learn.microsoft page that says:

Quote

In WM_SYSCOMMAND messages, the four low-order bits of the wParam parameter are used internally by the system. To obtain the correct result when testing the value of wParam, an application must combine the value 0xFFF0 with the wParam value by using the bitwise AND operator.

But I can't understand it propely.

Updated code with manual, interrupted _UpdateRegion() and two options of WM_SYSCOMMAND:
 

#include <GDIPlus.au3>
#include <WinAPIProc.au3>
#include <SendMessage.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Opt('MustDeclareVars', 1)
OnAutoItExitRegister('_Exxit')

Global $idButt = -3 ;$GUI_EVENT_CLOSE
;"Child" windows get "parent" hwnd as a parametr
Global $hGui = GUICreate(($CmdLine[0] = False) ? 'OnTop' : 'Clipped', 255, 255)
If $CmdLine[0] Then
    GUISetBkColor(Random(0, 0xFFFFFF))
Else 
EndIf
$idButt = GUICtrlCreateButton(($CmdLine[0] = False) ? 'Add Auto IT Child' : 'Update Region', 42,126, 171)
GUICtrlCreateLabel('Left Mouse button to move (SC_MOVE+13)' & @CRLF & _
                    'Right mouse button doesn''t work (SC_MOVE)', 42, 42, 192, 88)
GUICtrlCreateLabel('ESC to Exit', 42, 104, 172)
_GDIPlus_Startup()
Global $X, $Y ; to store mouse pos
GUIRegisterMsg($WM_MOVE, '_WM_MOVE')
GUIRegisterMsg($WM_MOVING, '_WM_MOVING')
GUIRegisterMsg($WM_MOUSEMOVE, '_WM_MOUSEMOVE')
Global Const $nMargin = 3
; _UpdateRegion()
GUISetState()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE 
            Exit
        Case $idButt
            If $CmdLine[0] = False Then 
                _AddAChild()
            Else 
                _UpdateRegion()
            EndIf
    EndSwitch
    ; _UpdateRegion()
WEnd
; ===============================================================================================================================
Func _Exxit()
    _GDIPlus_Shutdown()
    Exit
EndFunc
; ===============================================================================================================================
Func _WM_MOVE($hWndGUI, $MsgID, $WParam, $LParam)
    WinMove($hGui, '', $X, $Y)
EndFunc
; ===============================================================================================================================
Func _WM_MOVING($hWndGUI, $MsgID, $WParam, $LParam)
    Local Const $tagRectSTRUCT = 'LONG left; LONG top; LONG right; LONG bottom'
    Local $tRECT = DllStructCreate($tagRectSTRUCT, $LParam)
    $X = DllStructGetData($tRECT, 'left')
    $Y = DllStructGetData($tRECT, 'top')
    ; _UpdateRegion()
EndFunc
; ===============================================================================================================================
Func _WM_MOUSEMOVE($hWndGUI, $MsgID, $WParam, $LParam)
    Local Const $MK_LBUTTON = 0x0001
    Local Const $MK_RBUTTON = 0x0002
    Local Const $SC_MOVE = 0xF010
    If BitAND($MK_LBUTTON, $WParam) Then
        _SendMessage($hGui, $WM_SYSCOMMAND, $SC_MOVE + 13) ; I dont really know why 13
    ElseIf BitAND($MK_RBUTTON, $WParam) Then
        _SendMessage($hGui, $WM_SYSCOMMAND, $SC_MOVE) 
    EndIf
EndFunc
; ===============================================================================================================================
Func _UpdateRegion()
    If Not $CmdLine[0] Then Return
    Local $aPPos = WinGetPos(HWnd($CmdLine[1]))
    Local $aCPos = WinGetPos($hGui)
    If Not IsArray($aPPos) Then Exit
    Local $hRegionInf = _GDIPlus_RegionCreate()
    Local $hRegion = _GDIPlus_RegionCreateFromRect( _
                            $aPPos[0] - $aCPos[0] - $nMargin, _
                            $aPPos[1] - $aCPos[1] - $nMargin, _
                            $aPPos[2] +  $nMargin * 2, _
                            $aPPos[3] +  $nMargin * 2)
    _GDIPlus_RegionCombineRegion($hRegion, $hRegionInf, 3)
    Local $hRGN = _GDIPlus_RegionGetHRgn($hRegion, 0)
    MsgBox(0, '', 'Before')
    _WinAPI_SetWindowRgn($hGui, $hRGN)
    MsgBox(0, '', 'After')
    _WinAPI_DeleteObject($hRGN)
    _GDIPlus_RegionDispose($hRegion)
    _GDIPlus_RegionDispose($hRegionInf)
EndFunc
; ===============================================================================================================================
Func _AddAChild()
    Switch @Compiled
        Case True
            Run(@ScriptFullPath & " " & $hGui)
        Case Else
            ShellExecute(@AutoItExe, @ScriptFullPath & ' ' & $hGui)
    EndSwitch
EndFunc
; ===============================================================================================================================

 

update reg.JPG

Edited by LKP
Link to comment
Share on other sites

Hi, @argumentum.

Did not expect spaces in FileName. Is it the crash reason?

Gone reading _WinAPI_SetThemeAppProperties() 🙂

Fixed Code:

#include <GDIPlus.au3>
#include <WinAPIProc.au3>
#include <SendMessage.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Opt('MustDeclareVars', 1)
OnAutoItExitRegister('_Exxit')

Global $idButt = -3 ;$GUI_EVENT_CLOSE
;"Child" windows get "parent" hwnd as a parametr
Global $hGui = GUICreate(($CmdLine[0] = False) ? 'OnTop' : 'Clipped', 255, 255)
If $CmdLine[0] Then
    GUISetBkColor(Random(0, 0xFFFFFF))
Else 
EndIf
$idButt = GUICtrlCreateButton(($CmdLine[0] = False) ? 'Add Auto IT Child' : 'Update Region', 42,126, 171)
GUICtrlCreateLabel('Left Mouse button to move (SC_MOVE+13)' & @CRLF & _
                    'Right mouse button doesn''t work (SC_MOVE)', 42, 42, 192, 88)
GUICtrlCreateLabel('ESC to Exit', 42, 104, 172)
_GDIPlus_Startup()
Global $X, $Y ; to store mouse pos
GUIRegisterMsg($WM_MOVE, '_WM_MOVE')
GUIRegisterMsg($WM_MOVING, '_WM_MOVING')
GUIRegisterMsg($WM_MOUSEMOVE, '_WM_MOUSEMOVE')
Global Const $nMargin = 3
; _UpdateRegion()
GUISetState()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE 
            Exit
        Case $idButt
            If $CmdLine[0] = False Then 
                _AddAChild()
            Else 
                _UpdateRegion()
            EndIf
    EndSwitch
    ; _UpdateRegion()
WEnd
; ===============================================================================================================================
Func _Exxit()
    _GDIPlus_Shutdown()
    Exit
EndFunc
; ===============================================================================================================================
Func _WM_MOVE($hWndGUI, $MsgID, $WParam, $LParam)
    WinMove($hGui, '', $X, $Y)
EndFunc
; ===============================================================================================================================
Func _WM_MOVING($hWndGUI, $MsgID, $WParam, $LParam)
    Local Const $tagRectSTRUCT = 'LONG left; LONG top; LONG right; LONG bottom'
    Local $tRECT = DllStructCreate($tagRectSTRUCT, $LParam)
    $X = DllStructGetData($tRECT, 'left')
    $Y = DllStructGetData($tRECT, 'top')
    ; _UpdateRegion()
EndFunc
; ===============================================================================================================================
Func _WM_MOUSEMOVE($hWndGUI, $MsgID, $WParam, $LParam)
    Local Const $MK_LBUTTON = 0x0001
    Local Const $MK_RBUTTON = 0x0002
    Local Const $SC_MOVE = 0xF010
    If BitAND($MK_LBUTTON, $WParam) Then
        _SendMessage($hGui, $WM_SYSCOMMAND, $SC_MOVE + 13) ; I dont really know why 13
    ElseIf BitAND($MK_RBUTTON, $WParam) Then
        _SendMessage($hGui, $WM_SYSCOMMAND, $SC_MOVE) 
    EndIf
EndFunc
; ===============================================================================================================================
Func _UpdateRegion()
    If Not $CmdLine[0] Then Return
    Local $aPPos = WinGetPos(HWnd($CmdLine[1]))
    Local $aCPos = WinGetPos($hGui)
    If Not IsArray($aPPos) Then Exit
    Local $hRegionInf = _GDIPlus_RegionCreate()
    Local $hRegion = _GDIPlus_RegionCreateFromRect( _
                            $aPPos[0] - $aCPos[0] - $nMargin, _
                            $aPPos[1] - $aCPos[1] - $nMargin, _
                            $aPPos[2] +  $nMargin * 2, _
                            $aPPos[3] +  $nMargin * 2)
    _GDIPlus_RegionCombineRegion($hRegion, $hRegionInf, 3)
    Local $hRGN = _GDIPlus_RegionGetHRgn($hRegion, 0)
    MsgBox(0, '', 'Before')
    _WinAPI_SetWindowRgn($hGui, $hRGN)
    MsgBox(0, '', 'After')
    _WinAPI_DeleteObject($hRGN)
    _GDIPlus_RegionDispose($hRegion)
    _GDIPlus_RegionDispose($hRegionInf)
EndFunc
; ===============================================================================================================================
Func _AddAChild()
    Switch @Compiled
        Case True
            Run(@ScriptFullPath & " " & $hGui)
        Case Else
            ShellExecute(@AutoItExe, FileGetShortName(@ScriptFullPath) & ' ' & $hGui)
    EndSwitch
EndFunc
; ===============================================================================================================================

 

Edited by LKP
Link to comment
Share on other sites

Well, I hoped it is not the reason. 😕

Still hope some genius could provide a way to apply this win 98 style on any other AutoIt window & switch it back. If backward compatibility exists there has to be a way to use it.
If none does that, or helps me with SendMessage within a week, I will mark your reply as a solution.

P.s.
Feels strange to know someone uses XP today, it was great, but it was so long ago.
Everyone laughed at me when I bought win 7 CD to have operational OS, if Vista2 happens, but today none of computers around me even have a CD-Drive.

P.p.s.
Your About me  looks perfect😉

Link to comment
Share on other sites

5 hours ago, LKP said:

I've deleted every call of _UpdateRegion() in cycles, so that it could only be launched by button, added a MsgBox before and after the _WinAPI_SetWindowRgn.
And it definitely changes.

As I said before, it doesn't. The style of the window is not affected, what it changes it's the theme but it's not a bug, it's the windows way to make your application compatible with earlier versions. You can read here more about when visual styles are not applied.

One more thing. Don't delete the handle of the region after you successfully used _WinAPI_SetWindowRgn() because the system owns the region and the system deletes the region handle when it no longer needed.

Edited by Andreik
Link to comment
Share on other sites

strange indeed

how to return the window to its original state?

#include <WinAPIGdi.au3>
#include <ButtonConstants.au3>
#include <WindowsConstants.au3>

Local $hGUI, $idBtnTest, $hRgn, $aPos
$hGUI = GUICreate(StringTrimRight(@ScriptName, 4), 300, 100)
GUISetBkColor(0xCAC6B3)
$idBtnTest1 = GUICtrlCreateButton("Default", 10, 60, 70, 30)
$idBtnTest2 = GUICtrlCreateButton("Toolwindow", 90, 60, 70, 30)
$idBtnTest3 = GUICtrlCreateButton("Test 3", 220, 60, 70, 30)
GUISetState(@SW_SHOW)

GUICtrlSendMsg($idBtnTest3, $BM_CLICK, 0, 0)
GUICtrlSendMsg($idBtnTest2, $BM_CLICK, 0, 0)
GUICtrlSendMsg($idBtnTest3, $BM_CLICK, 0, 0)

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

        Case $idBtnTest1
            GUISetStyle(BitOR($WS_MINIMIZEBOX, $WS_CAPTION, $WS_POPUP, $WS_SYSMENU), 0)

        Case $idBtnTest2
            GUISetStyle(BitOR($WS_CAPTION, $WS_POPUPWINDOW, $WS_THICKFRAME), BitOR($WS_EX_CLIENTEDGE, $WS_EX_TOOLWINDOW))

        Case $idBtnTest3
            $aPos = WinGetPos($hGUI)
            $hRgn = _WinAPI_CreateRectRgn(0, 0, $aPos[2], $aPos[3])
            _WinAPI_SetWindowRgn($hGUI, $hRgn)

    EndSwitch
    Sleep(10)
WEnd
;**********************************

 

Edited by ioa747

I know that I know nothing

Link to comment
Share on other sites

Let me steal this thread for a moment. Since we're at it. What about making a sh*t load of examples for:

Func _WinAPI_DwmSetWindowAttribute($hWnd, $iAttribute, $iData)
    ;Switch $iAttribute ; https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
    ;   Case 2, 3, 4, 6, 7, 8, 10, 11, 12
    ;   Case Else
    ;       Return SetError(1, 0, 0)
    ;EndSwitch
    Local $aCall = DllCall('dwmapi.dll', 'long', 'DwmSetWindowAttribute', 'hwnd', $hWnd, 'dword', $iAttribute, _
            'dword*', $iData, 'dword', 4)
    If @error Then Return SetError(@error, @extended, 0)
    If $aCall[0] Then Return SetError(10, $aCall[0], 0)
    Return 1
EndFunc   ;==>_WinAPI_DwmSetWindowAttribute

I just opened a trac to change it to the above. Given that the more modern examples would not have worked with the $iAttribute filtering of the era.

Examples are few and far between:
https://www.autoitscript.com/forum/topic/101358-remove-a-window-from-aero-peek-in-windows-7/ ( aero stuff )
https://www.autoitscript.com/forum/topic/211196-gui-title-bar-dark-theme-an-elegant-solution-using-dwmapi/#comment-1527581  ( Win 10/11 stuff )

...and who knows ( not me ), one of those may aid this thread.

 

Edited by argumentum
more

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

Link to comment
Share on other sites

Create an account or sign in to comment

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

Create an account

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

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

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