Jump to content

DWM Custom Frame - Removing Standard Frame


Go to solution Solved by WildByDesign,

Recommended Posts

Posted

I am trying to learn from the Microsoft tutorial: Custom Window Frame Using DWM - Win32 apps | Microsoft Learn

I have never had trouble with extending the frame into the client area. But I have always got stuck on Removing the Standard Frame section and so I move onto other things and try again every few weeks.

This section mentions:

Quote

 

To remove the standard window frame, you must handle the WM_NCCALCSIZE message, specifically when its wParam value is TRUE and the return value is 0. By doing so, your application uses the entire window region as the client area, removing the standard frame.

The results of handling the WM_NCCALCSIZE message are not visible until the client region needs to be resized. Until that time, the initial view of the window appears with the standard frame and extended borders. To overcome this, you must either resize your window or perform an action that initiates a WM_NCCALCSIZE message at the time of window creation. This can be accomplished by using the SetWindowPos function to move your window and resize it. The following code demonstrates a call to SetWindowPos that forces a WM_NCCALCSIZE message to be sent using the current window rectangle attributes and the SWP_FRAMECHANGED flag.

 

I have some familiarity with SetWindowPos thanks to @pixelsearch from some other help topics in recent months. However, I have no experience with WM_NCCALCSIZE or how to handle that message in AutoIt.

Here is my current example:

#include <GUIConstantsEx.au3>
#include <WinAPIGdi.au3>

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

Example()

Func Example()
        ; Create a GUI with various controls.
        Local $hGUI = GUICreate("Example", 400, 400)
        Local $idOK = GUICtrlCreateButton("OK", 310, 370, 85, 25)

        ; set background color to black
        GUISetBkColor(0x000000)

        ; apply dark titlebar
        _WinAPI_DwmSetWindowAttribute__($hGUI, 20, 1)

        ; extend frame into client area
        _WinAPI_DwmExtendFrameIntoClientArea($hGUI, _WinAPI_CreateMargins(-1, -1, -1, -1))

        ; Display the GUI.
        GUISetState(@SW_SHOW, $hGUI)

        ; Loop until the user exits.
        While 1
                Switch GUIGetMsg()
                        Case $GUI_EVENT_CLOSE, $idOK
                                ExitLoop

                EndSwitch
        WEnd

        ; Delete the previous GUI and all controls.
        GUIDelete($hGUI)
EndFunc   ;==>Example

Func _WinAPI_DwmSetWindowAttribute__($hwnd, $attribute = 34, $value = 0x00FF00, $valLen = 4)
    Local $aCall = DllCall('dwmapi.dll', 'long', 'DwmSetWindowAttribute', 'hwnd', $hWnd, 'dword', $attribute, 'dword*', $value, 'dword', $valLen)
    If @error Then Return SetError(@error, @extended, 0)
    If $aCall[0] Then Return SetError(10, $aCall[0], 0)
    Return 1
EndFunc   ;==>_WinAPI_DwmSetWindowAttribute__

 

Thank you for any assistance with this. :)

  • Solution
Posted

After some more research and help from the AutoIt forum gods of past generations, I have got the removal of the standard frame done successfully now.

I used WM_NCHITTEST to make the entire window draggable since it would be impossible now without the standard frame. This all leaves the window control buttons non-functional but that is expected. Those will also need some WM_NCHITTEST work but this is for another step for another day.

Since this solves my problem, I will mark as solution.

Updated example:

#include <GUIConstantsEx.au3>
#include <WinAPIGdi.au3>
#include <WindowsConstants.au3>
#include <WinAPISysWin.au3>

Global $hGUI

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

Example()

Func Example()
    $hGUI = GUICreate("My GUI", 300, 200)

    Local $idEndBtn = GUICtrlCreateButton("End", 110, 140, 70, 20)

    _WinAPI_DwmSetWindowAttribute__($hGUI, 20, 1)
    _WinAPI_DwmExtendFrameIntoClientArea($hGUI, _WinAPI_CreateMargins(-1, -1, -1, -1))
    GUIRegisterMsg(0x0083, "INTERNAL_WM_NCCALCSIZE")
    GUIRegisterMsg($WM_NCHITTEST, "_MY_NCHITTEST")

    ; SetWindowPos
    _WinAPI_SetWindowPos($hGUI, $HWND_TOP, 0, 0, 0, 0, BitOR($SWP_FRAMECHANGED, $SWP_NOACTIVATE, $SWP_NOMOVE, $SWP_NOSIZE, $SWP_NOZORDER))

    GUISetState(@SW_SHOW)

    Local $idMsg
    ; Loop until the user exits.
    While 1
        $idMsg = GUIGetMsg()

        Switch $idMsg
            Case $idEndBtn, $GUI_EVENT_CLOSE
                ExitLoop
        EndSwitch
    WEnd
EndFunc   ;==>Example

Func _WinAPI_DwmSetWindowAttribute__($hwnd, $attribute = 34, $value = 0x00FF00, $valLen = 4)
    Local $aCall = DllCall('dwmapi.dll', 'long', 'DwmSetWindowAttribute', 'hwnd', $hWnd, 'dword', $attribute, 'dword*', $value, 'dword', $valLen)
    If @error Then Return SetError(@error, @extended, 0)
    If $aCall[0] Then Return SetError(10, $aCall[0], 0)
    Return 1
EndFunc   ;==>_WinAPI_DwmSetWindowAttribute__

Func INTERNAL_WM_NCCALCSIZE($hWnd, $Msg, $wParam, $lParam)
    If $hWnd = $hGUI Then
        Return 0
    EndIf
    Return 'GUI_RUNDEFMSG'
EndFunc   ;==>INTERNAL_WM_NCCALCSIZE

; Original code - Prog@ndy
Func _MY_NCHITTEST($hWnd, $uMsg, $wParam, $lParam)
    Switch $hWnd
        Case $hGUI
            Local $aPos = WinGetPos($hWnd) ; Check if mouse is over top 50 pixels
            If Abs(BitAND(BitShift($lParam, 16), 0xFFFF) - $aPos[1]) < 1200 Then Return $HTCAPTION
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>_MY_NCHITTEST

 

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...