Quote:
My sane copy of MSDN wrote:
ROFLMAO.
I was wondering wht the heck is that...
Quote:
Sounds like what happens when you SetParent() without removing WS_POPUP and adding WS_CHILD...
Good, I tried that, but I probably messed it up in WinSpector...
So now it works
Sample:
Code:
#SingleInstance, force
SetBatchLines, -1
#Include ShowMenu.ahk
Gui, +LastFound +LabelMyGui
; Gui, Add, text, hwndhS1 w400 h50 border
; Gui, Add, text, hwndhS2 w50 h300 border
; Gui, Add, text, hwndhS3 x100 y100 w100 h100 border
;
; Subclass( hS1, "MyWindowProc" )
; Subclass( hS2, "MyWindowProc" )
; Subclass( hS3, "MyWindowProc" )
hwnd := WinExist()
Gui, Show , w400 h250 ;set gui width & height (mandatory)
hIL := IL_Create(5, 0, 1)
Gui, 2:+LastFound -Caption
Gui, 2:Show ,w300 h100 Hide NoActivate
h := WInExist()
hToolbar := Toolbar_Add(h)
Toolbar_SetImageList(hToolbar)
btns =
(LTrim
btn1
btn2
btn3
btn3
btn1
btn2
btn3
btn3
)
Gui 2:Show, x50 y100 w300 h100 NoActivate
Toolbar_AddButtons(hToolbar, btns)
DllCall("SetParent", "uint", h, "uint", hwnd)
WinSet, Style, -0x80000000, ahk_id %h% ; WS_POPUP=0x80000000
WinSet, Style, +0x40000000, ahk_id %h% ; WS_CHILD=0x40000000
Gui, show
return
MyWindowProc(hwnd, uMsg, wParam, lParam){
if uMsg = 0x4E
return Toolbar_OnNotify(wparam, lparam)
return DllCall("CallWindowProcA", "UInt", A_EventInfo, "UInt", hwnd, "UInt", uMsg, "UInt", wParam, "UInt", lParam)
}
;------------------------------------------------------------------------------
;Compile btn definition into binary array. Return number of button.
; aBTN - compiled btn array
; Buf - buffer for btn text
; btns - textual btn def
;
Toolbar_compileButtons(ByRef aBTN, ByRef buf, btns) {
static BTNS_SEP=1, BTNS_CHECK =2, BTNS_CHECKGROUP = 6, BTNS_DROPDOWN = 8, BTNS_A=16, BTNS_AUTOSIZE = 16, BTNS_NOPREFIX = 32, BTNS_SHOWTEXT = 64
static TBSTATE_CHECKED=1, TBSTATE_ENABLED=4, TBSTATE_HIDDEN=8, TBSTATE_GRAYED =16, TBSTATE_PRESSED =5, TBSTATE_CLICKED=6, TBSTATE_WRAP=32, TBSTATE_ELLIPSES=0x40
static TB_ADDBUTTONSA = 0x414, TB_AUTOSIZE=0x421
StringReplace, _, btns, `n, , UseErrorLevel
cnt := ErrorLevel + 1
sep := 0
VarSetCapacity(aBTN, 20*cnt, 0)
VarSetCapacity(buf, 64*cnt)
tp := &Buf
loop, parse, btns, `n
{
a1:=a2:=a3:=a4:=""
StringSplit, a, A_LoopField, |
hstate := TBSTATE_ENABLED
loop, parse, a3, %A_Tab%%A_Space%, %A_Tab%%A_Space%
{
ifEqual, A_LoopField,,continue
hstate |= TBSTATE_%A_LOOPFIELD%
}
hstyle := A_LoopField = "-" ? BTNS_SEP : BTNS_SHOWTEXT
if (hstyle = BTNS_SEP)
sep+=1
loop, parse, a4, %A_Tab%%A_Space%
{
ifEqual, A_LoopField,,continue
hstyle |= BTNS_%A_LOOPFIELD%
}
if a2 is not Integer ;if user doesn't specify icon, use A_Index, but don't count separators
a2 := A_Index - sep
o := &aBTN + 20*(A_Index-1)
DllCall("lstrcpyn", "uint", tp, "uint", &a1, "int", 64)
NumPut(a2-1, o+0, 0) ;id
NumPut(A_Index, o+0, 4) ;id
NumPut(hstate, o+0, 8, "Char")
NumPut(hStyle, o+0, 9, "Char")
NumPut(tp, o+0, 16)
tp += StrLen(a1)+1
}
return cnt
}
Toolbar_onNotify(wparam, lparam) {
local hwnd, id, code, txt
static NM_CLICK=-2, TBN_DROPDOWN = -710, TBN_HOTITEMCHANGE = -713, TBN_BEGINADJUST=-703, TBN_GETBUTTONINFOA=-700, TBN_QUERYINSERT=-706, TBN_QUERYDELETE=-707, TBN_ENDADJUST=-704, TBN_DELETINGBUTTON=-715, TBN_RESET=-705, TBN_TOOLBARCHANGE=-708
static cus, cntAll
;NMHDR
hwnd := NumGet(lparam+0) ;control sending the message - this toolbar
; idFrom := NumGet(lparam+4) ; and its ID
code := NumGet(lparam+8) - 4294967296
;TOOLBAR
iItem := NumGet(lparam+12)
if (code = NM_CLICK) and (iItem != 4294967295){
txt := Toolbar_GetButtonInfo( hwnd, iItem )
tooltip %txt% : %iItem% click
return
}
if (code = TBN_DROPDOWN){
ShowMenu("[1]`ntext1`ntext2`ntext31111111111", "", "mnu")
return
}
if (code = TBN_HOTITEMCHANGE){
iItem := NumGet(lparam+16)
; tooltip % Toolbar_GetButtonInfo(htoolbar, iItem)
return
}
TBB := lparam + 16
if (code = TBN_GETBUTTONINFOA){
if !cus {
cntAll := Toolbar_compileButtons(aBTNS, NBUF, all ), cus := true
}
if (iItem = cntAll) ;iItem is position, not identifier
return
o := &aBTNS + 20*iItem, TBB := lparam +16
DllCall("MSVCRT\memcpy", "UInt", TBB, "UInt", o, "uint", 20) ;copy the compiled item into notification struct
;Customization dialog uses this buffer to get text to display.
;It doesn't use TBB+16, probably because text can be some longer tooltip, if you specified TOOLTIPS flag.
DllCall("MSVCRT\memcpy", "UInt", NumGet(TBB+24), "UInt", NumGet(o+16), "uint", NumGet(TBB+20) )
return TRUE
}
;Return at least one TRUE here to show the dialog, if the dialog is openinig
;When the dialog is open, it affects btn addition
if (code= TBN_QUERYINSERT) {
return TRUE
; if !cus
; return TRUE
; else {
; ; tooltip %iItem%
; return TRUE
; }
}
;existing items can not be deleted if TRUE is not returned here
if (code= TBN_QUERYDELETE) {
; if iItem in 0,1,2 ; prevent 0,1,2 id's to be deleted
; return FALSE
return TRUE
}
if (code=TBN_ENDADJUST){
return
}
}
F12::
stop := 1
; HexView(&NBUF, 100)
; hexview(NumGet(o+16), 20)
return
Toolbar_AddButtons(hToolbar, btns){
static TB_ADDBUTTONSA = 0x414, TB_AUTOSIZE=0x421
cnt := Toolbar_compileButtons(aBTN, TextBuf, btns)
SendMessage, TB_ADDBUTTONSA, cnt, &aBTN ,, ahk_id %hToolbar%
SendMessage, TB_AUTOSIZE, , ,,ahk_id %hToolbar%
}
Toolbar_Add(hGui, style="WRAPABLE FLAT ADJUSTABLE") {
static TOOLBARCLASSNAME = "ToolbarWindow32"
static WS_CHILD := 0x40000000, WS_VISIBLE := 0x10000000, WS_CLIPSIBLINGS = 0x4000000, WS_CLIPCHILDREN = 0x2000000
static TBSTYLE_EX_DRAWDDARROWS = 0x1, TBSTYLE_EX_HIDECLIPPEDBUTTONS=0x10, TBSTYLE_EX_MIXEDBUTTONS=0x8 ;extended styles
static TBSTYLE_WRAPABLE = 0x200, TBSTYLE_FLAT = 0x800, TBSTYLE_LIST=0x1000, TBSTYLE_TOOLTIPS=0x100, TBSTYLE_TRANSPARENT = 0x8000
static TBSTYLE_BORDER=0x800000, TBSTYLE_ADJUSTABLE = 0x20
static init, TB_BUTTONSTRUCTSIZE=0x41E, TB_SETEXTENDEDSTYLE := 0x454, TB_SETUNICODEFORMAT := 0x2005
hStyle := 0
loop, parse, style, %A_Tab%%A_Space%, %A_Tab%%A_Space%
{
ifEqual, A_LoopField,,continue
hStyle |= A_LoopField+0 ? A_LoopField : TBSTYLE_%A_LoopField%
}
if !init {
OnMessage(WM_NOTIFY := 0x4E, "Toolbar_onNotify"), init := true
}
hToolbar := DllCall("CreateWindowEx"
, "uint", 0
, "str", TOOLBARCLASSNAME
, "uint", 0
, "uint", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | hStyle
, "uint", 0, "uint", 0, "uint", 0, "uint", 0
, "uint", hGui
, "uint", 0
, "uint", 0
, "uint", 0, "Uint")
ifEqual, hToolbar, 0, return "Err: can't create toolbar"
SendMessage, TB_BUTTONSTRUCTSIZE, 20, 0, , ahk_id %hToolbar%
SendMessage, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS|TBSTYLE_EX_MIXEDBUTTONS, , ahk_id %hToolbar%
SendMessage, TB_SETUNICODEFORMAT, 0, 0, , ahk_id %hToolbar% ;set to ANSI
return hToolbar
}
Toolbar_SetImageList(hToolbar, hIL="1L"){
static TB_SETIMAGELIST=0x430, TB_LOADIMAGES=0x432, TB_SETBITMAPSIZE=0x420
if hIL is Integer
SendMessage, TB_SETIMAGELIST, 0, hIL, ,ahk_id %hToolbar%
else {
size := SubStr(hIL,2,1)="L" ? 24:16, cat := (SubStr(hIL, 1,1)-1)*4 + (size=16 ? 0:1)
Toolbar_SetBitmapSize(hToolbar, size, size)
SendMessage, TB_LOADIMAGES, cat, -1,,ahk_id %hToolbar%
}
return ErrorLevel
}
;----------------------------------------------------------------------------------------------
;Function: SetButtonInfo
; Set button information
;
;Parameters:
; hToolbar - HWND of the toolbar
; id - Button identification (currently equal to buttons position)
; text - Text to set for the button. If "" text will not be changed. If "-" text wil be removed (the same as omiting both text and state parameters)
; state - List of button states to set, separated by white space. See bellow.
;
; Button states:
; CHECKED, ENABLED, HIDDEN, GRAYED, PRESSED, CLICKED
;
; Returns:
; Nonzero if successful, or zero otherwise.
;
Toolbar_SetButtonInfo(hToolbar, id, text="", state="", width=""){
static TB_SETBUTTONINFO=0x442, TBIF_TEXT=2, TBIF_STATE=4, TBIF_SIZE=0x40, TB_AUTOSIZE=0x421
static TBSTATE_CHECKED=1, TBSTATE_ENABLED=4, TBSTATE_HIDDEN=8, TBSTATE_GRAYED=16, TBSTATE_PRESSED=5, TBSTATE_CLICKED=6, TBSTATE_WRAP=32
hstate := 0
loop, parse, state, %A_Tab%%A_Space%, %A_Tab%%A_Space%
{
ifEqual, A_LoopField,,continue
hstate |= TBSTATE_%A_LOOPFIELD%
}
mask := 0
mask |= text != "" ? TBIF_TEXT : 0
mask |= state!= "" ? TBIF_STATE : 0
mask |= width!= "" ? TBIF_SIZE : 0
if text = -
text =
if (state text = "")
mask := TBIF_TEXT, text := ""
VarSetCapacity(BI, 32, 0)
NumPut(32, BI, 0)
NumPut(mask, BI, 4)
NumPut(hstate, BI, 16, "Char")
NumPut(width, BI, 18, "Short")
NumPut(&text, BI, 24)
SendMessage, TB_SETBUTTONINFO, id, &BI, ,ahk_id %hToolbar%
res := ErrorLevel
SendMessage, 0x421, , ,,ahk_id %hToolbar% ;autosize
return res
}
;----------------------------------------------------------------------------------------------
;Function: SetButtons
; Set all butons at once using textual definition
;
;Parameters:
; hToolbar - HWND of the toolbar
; info - Textual definition of buttons info. For each button there should be line containg *text|state list* where
; both _text_ and _state list_ are optional. You can also use "-" to skip button (the same as empty line).
; If you omit this parameter text and state for each button will be cleared
;
Toolbar_SetButtons(hToolbar, info=""){
if info=
{
Loop, % Toolbar_GetButtonCount(hToolbar)
Toolbar_SetButtonInfo(hToolbar, A_Index, "-", "ENABLED" )
return
}
loop, parse, info, `n,
{
if j := InStr(A_LoopField, "|")
state := SubStr(A_LoopField, j+1)
else state := "enabled"
txt := SubStr(A_LoopField, 1, j ? j-1 : 99)
ifEqual txt, -, continue
Toolbar_SetButtonInfo(hToolbar, A_Index, txt, state)
}
}
;----------------------------------------------------------------------------------------------
;Function: GetButtonInfo
; Get button information
;
;Parameters:
; hToolbar - HWND of the toolbar
; id - ID of the button (currently the same as position)
; info - What kind of info to return - text (default) or state
;
Toolbar_GetButtonInfo(hToolbar, id, info="text"){
; static TB_GETBUTTONINFO=0x441, TBIF_TEXT=2, TBIF_STATE=4
static TB_GETBUTTONTEXT=0x42D, TB_GETSTATE=0x412
static S1 = "CHECKED", S4 = "ENABLED", S8 ="HIDDEN", S16="GRAYED", S5="PRESSED", S6="CLICKED"
if info=text
{
VarSetCapacity( buf, 128 )
SendMessage, TB_GETBUTTONTEXT,id,&buf,,ahk_id %hToolbar%
ifEqual, Errorlevel, 4294967295, return
VarSetCapacity( buf, -1 )
return buf
}
else if info=state
{
SendMessage, TB_GETSTATE,id,,,ahk_id %hToolbar%
state = S%ErrorLevel%
state := %state%
return state
}
; mask := TBIF_TEXT
; if info = state
; mask := TBIF_STATE
;
;
; VarSetCapacity(BI, 32, 0)
; NumPut(32, BI, 0)
; NumPut(mask, BI, 4)
; SendMessage, TB_GETBUTTONINFO, id, &BI, ,ahk_id %hToolbar%
; if ErrorLevel=4294967295
; return "Err: can't get button info"
;
; if info=text
; return NumGet(BI, 8)
}
;----------------------------------------------------------------------------------------------
;Function: GetButtonCount
; Get count of buttons on the toolbar
;
;Parameters:
; hToolbar - HWND of the toolbar
;
;Returns:
; Count
Toolbar_GetButtonCount(hToolbar) {
static TB_BUTTONCOUNT = 0x418
SendMessage, TB_BUTTONCOUNT, , , ,ahk_id %hToolbar%
return ErrorLevel
}
;----------------------------------------------------------------------------------------------
;Function: DeleteButton
; Delete button from the toolbar
;
;Parameters:
; hToolbar - HWND of the toolbar
; idx - 1-based position of the button
;
;Returns:
; TRUE if successful, or FALSE otherwise.
;
Toolbar_DeleteButton(hToolbar, idx=1) {
static TB_DELETEBUTTON = 0x416
SendMessage, TB_DELETEBUTTON, idx-1, , ,ahk_id %hToolbar%
return ErrorLevel
}
;----------------------------------------------------------------------------------------------
;Function: GetRect
; Get button rectangle
;
;Parameters:
; hToolbar - HWND of the toolbar
; id - Button id
;
;Returns:
; String with 4 rect values, separated by space
;
Toolbar_GetRect(hToolbar, id) {
static TB_GETRECT=0x433, RECT
VarSetCapacity(RECT, 16)
SendMessage, TB_GETRECT, id,&RECT, ,ahk_id %hToolbar%
IfEqual, ErrorLevel, 0, return "Err: can't get rect"
return NumGet(RECT, 0) " " NumGet(RECT, 4) " " NumGet(RECT, 8) " " NumGet(RECT, 12)
}
;----------------------------------------------------------------------------------------------
;Function: GetRows
; Get number of toolbar rows
;
;Parameters:
; hToolbar - HWND of the toolbar
;
;Returns:
; Count
;
Toolbar_GetRows(hToolbar) {
static TB_GETROWS=0x428
SendMessage, TB_GETROWS,,,,ahk_id %hToolbar%
return ErrorLevel-1
}
;doesn't work correctly for some reason
Toolbar_SetPadding(hToolbar, cx=6, cy=7) {
static TB_SETPADDING=0x457
SendMessage, TB_SETPADDING,0,(cx<<16)+cy,,ahk_id %hToolbar%
return ErrorLevel>>16 " " ErrorLevel & 0xFFFF
}
mnu:
Toolbar_SetButtonInfo(hToolbar, id, A_ThisMenuItem)
return
Toolbar_SetDrawTextFlags(hToolbar) {
static TB_SETDRAWTEXTFLAGS = 0x446
}
;Returns nonzero if successful, or zero otherwise.
Toolbar_SetMaxTextRows(hToolbar, iMaxRows=0) {
static TB_SETMAXTEXTROWS = 0x43C
SendMessage, TB_SETMAXTEXTROWS,iMaxRows,,,ahk_id %hToolbar%
res := ErrorLevel
SendMessage,0x421,,,,ahk_id %hToolbar% ;autoresize
return res
}
Toolbar_SetMetrics(hToolbar, xPad="", yPad="", xButtonMargin="", yButtonMargin="", xMargin="", yMargin=""){
VarSetCapacity(met,32,0), NumPut(32,met)
NumPut( ((xPad yPad)!="" ? 1:0)
| ((xMargin yMargin)!="" ? 2:0)
| ((xButtonMargin yButtonMargin)!="" ? 4:0), met, 4)
NumPut(xPad,met,8), NumPut(yPad,met,12)
NumPut(0,met,16), NumPut(yMargin,met,20)
NumPut(xButtonMargin,met,24), NumPut(yButtonMargin,met,28)
DllCall("SendMessage","uint",hToolbar,"uint",0x466,"uint",0,"uint",&met) ; TB_SETMETRICS
DllCall("SendMessage","uint",hToolbar,"uint",0x42F,"int",xMargin,"uint",0) ; TB_SETINDENT
}
;Returns TRUE if successful, or FALSE otherwise.
Toolbar_SetButtonSize(hToolbar, x=0, y=0) {
static TB_SETBUTTONSIZE = 0x41F
SendMessage, TB_SETBUTTONSIZE, 0,(y<<16) | x,,ahk_id %hToolbar%
SendMessage, 0x421, , ,,ahk_id %hToolbar% ;autosize
}
;Returns nonzero if successful, or zero otherwise.
Toolbar_SetButtonWidth(hToolbar, cxMin, cxMax ){
static TB_SETBUTTONWIDTH=0x43B
SendMessage, TB_SETBUTTONWIDTH, 0,(cxMin<<16) | cxMax,,ahk_id %hToolbar%
return Errorlevel
}
Toolbar_SetBitmapSize(hToolbar, x, y ) {
SendMessage, 0x420,0,(x<<16)+y, , ahk_id %hToolbar%
}
Toolbar_AutoSize(hToolbar){
SendMessage,0x421,,,,ahk_id %hToolbar% ;autoresize
}
;-------------------------------------------------------------------------------------------------------------------
;Group: Example
;
;> Gui, +LastFound
;> hwnd := WinExist()
;> Gui, Show ,w280 h200 ;set gui width & height (mandatory)
;> hToolbar := Toolbar_Add(hwnd)
;-------------------------------------------------------------------------------------------------------------------
;Group: About
; o Ver 1.0 b1 by majkinetor. See http://www.autohotkey.com/forum/topic27382.html
; o Toolbar Reference at MSDN: <http://msdn2.microsoft.com/en-us/library/bb760435(VS.85).aspx>
; o Licenced under Creative Commons Attribution-Noncommercial <http://creativecommons.org/licenses/by-nc/3.0/>.
MyGuiClose:
MyGuiEscape:
exitapp
return
;-------------------------------------------------------------------------------------
; Function: Subclass
; Helper function to subclass control
;
; Parameters:
; hCtrl - handle to control
; func - window procedure
; cbOpt - callback options, by default ""
;
Subclass(hCtrl, func, cbOpt="") {
oldProc := DllCall("GetWindowLong", "uint", hCtrl, "uint", -4)
ifEqual, oldProc, 0, return 0
WndProc := RegisterCallback(func, cbOpt, 4, oldProc)
ifEqual, WndProc, , return 0
return DllCall("SetWindowLong", "UInt", hCtrl, "Int", -4, "Int", WndProc, "UInt")
}
It still makes sense to create container window from ground up just to avod using new gui, every time you need this feature (and its obviously very useful)