News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Simple Graphical + Textual buttons sublassing code

Started by Antariy, June 08, 2013, 01:02:02 AM

Previous topic - Next topic

Antariy

Here is the code which is used in AxMsgTableViewer proggie I posted in the old forum to display the buttons with an icons on them and to react on clicking by icon "pushing". It works right over the standard button displayment code so it works well with theming and not forces button to be old-style looking if you want to put an icon on it.

The code is hardcoded for the icon size (32x32), so one needs to change the code if wants to use other sizes. Also the text and icon alignment is not done automatically - the icon just displayed on the left side of the button, the text should be aligned by the right size of button using the button styles, text aligment should be done manually by just trailing spacing it :lol: Yeah, yeah, this code is a good example of unreadable but crazly optimized for the target ("sharpened code") code. Also it uses some "fancy" techniques, like re-usage of previously used formal parameter pushed for previous call (i.e. the [esp-xx] value (please no words about you-know-who, this proc was written long before I even heard of this person and "his" coding style, and I actually think this person has too much respect and too frequently there are references to the coding style that actually he did not invent and even did not improved in any extent)), and also Set/GetProp used (!) with the atom that was not registered (!!!). And that works, as you see... Actually I thought to write the prog which will test if we can use the atoms with Set/GetProp that we had not registered - i.e. it seems to me that in modern Windows (not Win3.1 programming model) these "atoms" are not obligatory to be registered and may be just unique numerical word-sized values.
Also take notice how much things the code does, it even uses an dynamically allocated on the stack structure, how much variables and calls it deals with and that's all with only 3 volatile regs usage :biggrin: That's what technique of "handmade pushs" does :biggrin: That's not "invoke-hater" way but just optimal way - if we use assembly, why should we write "linear" code? C compilers will produce non linear and much better code in therms of size and effeciency than linear "well mannered" and "only invoke using" code is (greetings to John (sinsi) here :biggrin:).


Usage is simple: just change the "add ecx,-32" to the dimension of icon you want to use, and in code set this proc as subclassing proc, set the defBtnProc variable to the previous value of button's WndProc (returned by Set/GetWindowLong). Set the icon handle you want to display on the button as GWL_USERDATA value of the button window.


stackframe off
btnproc proc STDCALL hwnd:DWORD, umsg:DWORD, wparam:DWORD, lparam:DWORD

.data
align 4
defBtnProc dd offset @done
.code _TEXT

mov edx,[esp+4+4]
cmp edx,BM_SETSTATE
jz @l1
cmp edx,WM_PAINT
jz @l2
cmp edx,WM_ENABLE
jz @l2
cmp edx,128h
jz @l2
@defaultprocessing:
pop edx
push defBtnProc
push edx
jmp CallWindowProc

@l1:
invoke GetProp,[esp+4+4],1234h
cmp [esp+4+4+4],eax
jz @done
invoke SetProp,[esp+4+4+4],1234h,[esp+4+4+4]
@l2:
invoke InvalidateRect,[esp+4+4+4],0,0
push [esp+16]
push [esp+16]
push [esp+16]
push [esp+16]
push defBtnProc
call CallWindowProc
add esp,-(sizeof RECT)

invoke GetClientRect,[esp+sizeof(RECT)+4+4],esp
pop ecx
pop ecx
pop eax
pop ecx
;add eax,-24
add ecx,-32
;shr eax,1
shr ecx,1
;mov eax,ecx

push DI_NORMAL
push 0
push 0
push 0
push 0
push 0
push ecx
        push ecx

invoke GetWindowLong,[esp+40],GWL_USERDATA
mov [esp+8],eax

invoke SendMessage,[esp+4+4+4+4+8*4],BM_GETSTATE,0,0

test eax,BST_PUSHED
jz @F
inc dword ptr [esp]
inc dword ptr [esp+4]
@@:
invoke GetDC,[esp+4*8+4]
push eax
call DrawIconEx
invoke ReleaseDC,[esp+8],[esp-4*9]
xor eax,eax    ; ^ use pre-pushed for DrawIconEx HDC value, so, it is local variable of DIEx
ret 16



@done:
xor eax,eax
ret 16

btnproc endp
stackframe on


Edited: corrected usage explanation and a bit optimization on the code.

Gunther

You have to know the facts before you can distort them.


Antariy

BTW it is possible to put GetDC call long before DrawIconEx so we can pre-push the DC in a "well-mannered" way and use it then as non [esi-XX] value in the ReleaseDC call :biggrin: So, actually it's just an example of complex intermix of manual parameters pushing and manipulation (icon movement when button pushed and released, for an instance) and invokes.