Code: Select all
OnMessage( 0x001, "wndproc" ) ; WM_CREATE
OnMessage( 0x006, "wndproc" ) ; WM_ACTIVATE
OnMessage( 0x00F, "wndproc" ) ; WM_PAINT
OnMessage( 0x083, "wndproc" ) ; WM_NCCALCSIZE
OnMessage( 0x084, "wndproc" ) ; WM_NCHITTEST
OnMessage( 0x111, "wndproc" ) ; WM_COMMAND
fm := GuiCreate( "+resize +lastfound", "Custom DWM" )
fm.addbutton( "x" . ( a_screenwidth // 4 ) . " y2 h20", "Click Me!" )
fm.show( "w" . ( a_screenwidth // 2 ) . " h" . ( a_screenheight // 2 ))
wndproc( wparam, lparam, msg, handle ) {
local fCallDWP := true
local fDwmEnabled := false
local lRet := 0
local hr := 0
; Winproc worker for custom frame issues.
hr := ! dllcall( "dwmapi\DwmIsCompositionEnabled", "int*", fDwmEnabled )
if hr
lRet := CustomCaptionProc( handle, msg, wparam, lparam, fCallDWP, lRet )
; Winproc worker for the rest of the application.
if fCallDWP {
lRet := AppWinProc( handle, msg, wParam, lParam )
}
return lRet
}
; Message handler for handling the custom caption messages.
CustomCaptionProc( hWnd, message, wParam, lParam, byref pfCallDWP, byref lRet ) {
local fCallDWP := true ; Pass on to DefWindowProc?
local fCallDWP := ! dllcall( "dwmapi\DwmDefWindowProc", "ptr", hWnd, "uint", message, "ptr", wParam, "uptr", lParam, "uint*", lRet )
; Handle window creation
if message == 0x001 { ; WM_CREATE
local rect := struct_rect( hWnd )
; Inform application of the frame change.
dllcall( "user32\SetWindowPos",
"uint", hWnd,
"uint", 0,
"int", rect.left,
"int", rect.top,
"int", rect.width,
"int", rect.height,
"uint", 0x0020
)
fCallDWP := true
lRet := 0
}
; Handle window activation.
if message == 0x006 { ; WM_ACTIVATE
; Extend the frame into the client area.
; LEFTEXTENDWIDTH: 8
; RIGHTEXTENDWIDTH: 8
; BOTTOMEXTENDWIDTH: 20
; TOPEXTENDWIDTH: 27
local margins := struct_margins()
if dllcall( "dwmapi\DwmExtendFrameIntoClientArea", "ptr", hWnd, "ptr", margins.ptr ) {
; Handle error.
}
fCallDWP := true
lRet := 0
}
if message == 0x00F { ; WM_PAINT
local paint := struct_paint()
local hdc := dllcall( "user32\BeginPaint", "Ptr", hWnd, "ptr", paint.ptr )
PaintCustomCaption( hWnd, hdc )
dllcall( "user32\EndPaint", "ptr", hWnd, "ptr", paint.ptr )
fCallDWP := true
lRet := 0
}
; Handle the non-client size message.
if message == 0x083 and wParam == 1 {
x1 := numget( lParam +0, 0, "int" )
y1 := numget( lParam +0, 4, "int" )
x2 := numget( lParam +0, 8, "int" )
y2 := numget( lParam +0, 12, "int" )
old_x1 := numget( lParam +0, 32, "int" )
old_y1 := numget( lParam +0, 4 + 32, "int" )
old_x2 := numget( lParam +0, 8 + 32, "int" )
old_y2 := numget( lParam +0, 12 + 32, "int" )
dx1 := abs( x1 - old_x1 )
dx2 := abs( x2 - old_x2 )
dy1 := abs( y1 - old_y1 )
dy2 := abs( y2 - old_y2 )
numput( x1 - dx1, lParam +0, 0, "int" )
numput( y1 - dy1, lParam +0, 4, "int" )
numput( x2 + dx2, lParam +0, 8, "int" )
numput( y2 + dy2, lParam +0, 12, "int" )
lRet := 0
; // No need to pass the message on to the DefWindowProc.
fCallDWP := false
}
; // Handle hit testing in the NCA if not handled by DwmDefWindowProc.
if message == 0x084 and lRet == 0 { ; WM_NCHITTEST
lRet := HitTestNCA( hWnd, wParam, lParam )
if ( lRet != 0 )
fCallDWP := false
}
pfCallDWP := fCallDWP
return lRet
}
; Paint the title on the custom frame.
PaintCustomCaption( hWnd, hdc) {
local rcClient := struct_rect( hWnd )
local hTheme := DllCall( "uxtheme\OpenThemeData", "ptr", hWnd, "str", "CompositedWindow::Window" )
if ( hTheme ) {
local hdcPaint := dllcall( "gdi32\CreateCompatibleDC", "uint", dllcall( "user32\GetDC", "uint", hWnd ))
if ( hdcPaint ) {
local cx := rcClient.width
local cy := rcClient.height
; Define the BITMAPINFO structure used to draw text.
; Note that biHeight is negative. This is done because
; DrawThemeTextEx() needs the bitmap to be in top-to-bottom
; order.
local dib := struct_bitmapinfo( cx, -cy )
local ptr := a_ptrsize ? "uptr" : "uint"
local hbm := dllcall( "gdi32\CreateDIBSection",
ptr, hdc,
ptr, dib.ptr,
"uint", 0, ; DIB_RGB_COLORS
A_PtrSize ? "uptr*" : "uint*", 0,
ptr, 0,
"uint", 0,
ptr
)
if hbm {
local hbmOld := dllcall( "gdi32\SelectObject", ptr, hdcPaint, ptr, hbm )
; Setup the theme drawing options.
local dttopts := bufferalloc( 64, 0 )
numput( 64, dttopts, 0, "uint" ) ; dwSize
numput( 0x2800, dttopts, 4, "uint" ) ; dwFlags (DTT_COMPOSITED | DTT_GLOWSIZE)
numput( 1<<11|1<<13|1<<3, dttopts, 4 )
numput( 15, dttopts, 52, "int" )
numput( 0, dttopts, 20, "int" )
; https://www.autoahk.com/archives/23733
; Select a font.
local logfont := bufferalloc( 60, 0 )
numput( 5, logfont, 26, "int" )
local hFontOld := 0
if ! dllcall( "uxtheme\GetThemeSysFont", "int", hTheme, "int", 801, "uint", logfont.ptr ) {
local hFont := dllcall( "CreateFontIndirect", "uint", logfont.ptr )
hFontOld := dllcall( "gdi32\SelectObject", "int", hdcPaint, "int", hFont )
}
local rcPaint := bufferalloc( 64, 0 )
dllcall( "RtlMoveMemory", "uint", rcPaint.ptr, "uint", &rcClient, "uint", 16)
numput( numget( rcPaint, 0, "int" ) +8, rcPaint, 0 )
numput( numget( rcPaint, 4, "int" ) +8, rcPaint, 4 )
numput( numget( rcPaint, 8, "int" ) -125, rcPaint, 8 )
numput( numget( rcPaint, 12, "int" ) +50, rcPaint, 12 )
; Draw the title.
DllCall( "uxTheme\DrawThemeTextEx",
"int", hTheme,
"uint", hdcPaint,
"int", 0,
"int", 0,
"uint", WSTR( "New Title Caption" ).ptr,
"int", -1,
"uint", 0x00000000|0x00040000,
"uint", rcPaint.ptr,
"uint", dttopts.ptr
)
; Blit text to the frame.
DllCall( "BitBlt",
"int", hdc,
"int", 0,
"int", 0,
"int", cx,
"int", cy,
"uint", hdcPaint,
"int", 0,
"int", 0,
"uInt", 0xCC0020
)
dllcall( "SelectObject", "uint", hdcPaint,"uint",hbmOld)
if hFontOld
dllcall( "SelectObject", "uint", hdcPaint, "uint", hFontOld )
dllcall( "DeleteObject", "uint", hbm )
}
dllcall( "gdi32\DeleteDC", A_PtrSize ? "uptr" : "uint", hdcPaint )
}
dllcall( "Uxtheme\CloseThemeData", "ptr", hTheme )
}
}
WSTR( str ) {
local wide := bufferalloc(( strlen(str) * 2) + 1, 0 )
dllcall( "MultiByteToWideChar", "uint", 0, "uint", 0, "str", str, "int", -1, "uint", wide.ptr, "int", strlen(str) +1 )
return wide
}
GET_X_LPARAM( lParam ) {
numput( lParam, Buffer := " ", "uint" )
return numget( Buffer, 0, "short" )
}
GET_Y_LPARAM( lParam ) {
numput( lParam, Buffer := " ", "uint" )
return numget( Buffer, 2, "short" )
}
; Hit test the frame for resizing and moving.
HitTestNCA( hWnd, wParam, lParam ) {
; Get the point coordinates for the hit test.
local ptMouse := {
"x": GET_X_LPARAM( lParam ),
"y": GET_Y_LPARAM( lParam )
}
; Get the window rectangle.
local rcWindow := struct_rect( hWnd )
; Get the frame rectangle, adjusted for the style without a caption.
local rcFrame := struct_rect( hWnd )
; WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
; AdjustWindowRectEx(&rcFrame, WS_OVERLAPPEDWINDOW & ~WS_CAPTION, FALSE, NULL);
dllcall( "user32\AdjustWindowRectEx", "uint", rcFrame.ptr, "uint", (0 | 12582912 | 524288 | 262144 | 131072 | 65536) & ~12582912, "uint", 0, "uint", 0 )
; Determine if the hit test is for resizing.
local uRow := 2
local uCol := 2
local fOnResizeBorder := false
; Determine if the point is at the top or bottom of the window.
if ( ptMouse.y >= rcWindow.top and ptMouse.y < ( rcWindow.top + 27 )) {
fOnResizeBorder := (ptMouse.y < ( rcWindow.top - rcFrame.top ))
uRow := 1
}
else if ( ptMouse.y < rcWindow.bottom and ptMouse.y >= ( rcWindow.bottom - 20 )) {
uRow := 3
}
; Determine if the point is at the left or right of the window.
if ( ptMouse.x >= rcWindow.left and ptMouse.x < rcWindow.left + 8 ) {
uCol := 1 ; left side
}
else if ( ptMouse.x < rcWindow.right and ptMouse.x >= rcWindow.right - 8 ) {
uCol := 3 ; right side
}
; Hit test (HTTOPLEFT, ... HTBOTTOMRIGHT)
; { HTTOPLEFT, fOnResizeBorder ? HTTOP : HTCAPTION, HTTOPRIGHT }
; { HTLEFT, HTNOWHERE, HTRIGHT }
; { HTBOTTOMLEFT, HTBOTTOM, HTBOTTOMRIGHT }
local hitTests := [
[ 13, fOnResizeBorder ? 12 : 2, 14 ],
[ 10, 0, 11 ],
[ 16, 15, 17 ],
]
return hitTests[uRow][uCol]
}
; Message handler for the application.
AppWinProc( hWnd, message, wParam, lParam ) {
local wmId
local wmEvent
local ps := struct_paint()
local hdc := dllcall( "user32\BeginPaint", "Ptr", hWnd, "ptr", ps.ptr )
local hr
local result := 0
if message == 0x001 {
; continue
}
if message == 0x111 {
wmId := wParam & 0xffff
wmEvent := (wParam >> 16) & 0xffff
if (wmId)
return dllcall( "user32\DefWindowProc", "ptr", hWnd, "uint", message, "ptr", wParam, "ptr", lParam )
}
if message == 0x00F {
local hdc := dllcall( "user32\BeginPaint", "Ptr", hWnd, "ptr", ps.ptr )
PaintCustomCaption( hWnd, hdc )
dllcall( "user32\EndPaint", "ptr", hWnd, "ptr", ps.ptr )
}
; return dllcall( "user32\DefWindowProc", "ptr", hWnd, "uint", message, "ptr", wParam, "ptr", lParam )
return 0
}
struct_rect( handle := "" ) {
local rect := bufferalloc( 16, 0 )
if handle {
dllcall( "user32.dll\GetWindowRect", "ptr", handle, "ptr", rect.ptr )
rect.left := numget( rect, 0, "int" )
rect.top := numget( rect, 4, "int" )
rect.right := numget( rect, 8, "int" )
rect.bottom := numget( rect, 12, "int" )
rect.width := rect.right - rect.left
rect.height := rect.bottom - rect.top
}
return rect
}
struct_margins() {
local margins := bufferalloc( 16, 0 )
numput( 1, margins.ptr, 0, "uint" )
numput( 1, margins.ptr, 4, "uint" )
numput( 1, margins.ptr, 8, "uint" )
numput( 1, margins.ptr, 12, "uint" )
return margins
}
struct_paint() {
return bufferalloc( 64, 0 )
}
struct_bitmapinfo( width, height, bpp := 32 ) {
local bi := bufferalloc( 40, 0 )
numput( 40, bi, 0, "uint" )
numput( width, bi, 4, "uint" )
numput( height, bi, 8, "uint" )
numput( 1, bi, 12, "ushort" )
numput( bpp, bi, 14, "ushort" )
numput( 0, bi, 16, "uint" )
return bi
}