Hey all, yeah I am a newbie to assembly... *sniff*
I can figure out how to do most of what I need to by browzing the example files and searching the web, however I am having fits trying to get this in a form that I think is optimized.

Whats going on is that I need to capture a Windows message where lParam is a pointer to a structure.

Specifically, I need to handle a WM_COMMAND message where lParam is a NMHDR (see below).

NMHDR STRUCT
hwndFrom DWORD ?
idFrom DWORD ?
code DWORD ?
NMHDR ends

Well I could of course use the API itself by using CopyMem and transfering it to a local variable defined as this kind of struct. However I would like to know if it is possible (or even needed) to cast lParam to this kind of structure directly. In C it would like something like this...

#define lpnm ((NMHDR)lParam)

switch(lpnm->code) {
case TBN_DROPDOWN:
... blah blah blah...

Anything like that in assembly?
Thanks!
:stupid:
Posted on 2002-03-29 08:36:53 by Graebel
do (MyStruc PTR ).MyMember
Posted on 2002-03-29 08:42:08 by Hiroshimator
Casting is C is relatively like telling to the compiler "I know it is not the good type, but let me do what I want to"...
The C langage is typed, but assembly is different... you just define sizes of variables (byte, word, dword, qword... arrays of them, etc)
Basically, the typing in C is to let know what instructions to use (exemple divide unsigned or signed) or things like that... but since in assembly, you write your own assembly code directly, you don't need to cast anything because you choose what instructions to *execute*, when you want...
Posted on 2002-03-29 08:42:47 by JCP
Actually there *is* casting in masm.


lalahat dd 0
...
mov al, [lalahat]

that will not work without a "byte ptr" cast, whereas you can move
into eax without "dword ptr". Also hiroshimator's method can be
though of as casting...
Posted on 2002-03-29 09:13:45 by f0dder
i do it iczelions way. its a little more easier on my eyes this way:

example 1:

.elseif uMsg == WM_COMMAND
mov edi, lParam
assume edi:ptr NMHDR
mov eax, [edi].hwndFrom
.if eax = [place the controls handle here]
;do something
.endif

example 2:
.elseif uMsg == WM_COMMAND
mov edi, lParam
assume edi:ptr NMHDR
mov eax, [edi].idFrom
.if eax = [place the control id here]
;do something
.endif

example 3:
.elseif uMsg == WM_COMMAND
mov edi, lParam
assume edi:ptr NMHDR
mov eax, [edi].code
.if eax = [place the noticifacation message here]
;do something
.endif
Posted on 2002-03-29 09:18:38 by smurf
Well I still cannot seem to get this to work. Maybe someone has already done what I am trying to do so I will just throw it out there and see if someone bites.

I was messing around with the Qikpad example and I have been attempting to add a functional dropdown button to the menu.

In TBMacros.asm add in this macro:

TBdrop MACRO bID, cID
mov tbb.iBitmap, bID ;; button ID number
mov tbb.idCommand, cID ;; command ID number
mov tbb.fsStyle, TBSTYLE_BUTTON or 00008h
invoke SendMessage,hToolBar,TB_ADDBUTTONS,1,ADDR tbb
ENDM
;00008h = TBSTYLE_DROPDOWN or BTNS_DROPDOWN

And after CreateWindowEx add this:

invoke SendMessage,hToolBar,1108,0,00001h
;1108=TB_SETEXTENDEDSTYLE
;00001h=TBSTYLE_EX_DRAWDDARROWS

Now in ToolBar.asm add a new button:
TBdrop 4, 57


If you compile this and run you will indeed get a button with a pull down arrow (the user is responsible for displaying the menu). But I have yet been able to intercept any notification from the arrow when it is clicked.

Help:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/ToolBar/ToolBar_Using.asp?frame=true

See for a cruddy explanation... so far this thing has me whipped.
:grin:
Posted on 2002-03-29 09:30:01 by Graebel
welll i did some testing for you. it appears the msdn is wrong when it says it will post a WM_COMMAND message when the arrow is clicked. in fact im pretty sure they have them backwards as to what pressing the button and pressing the arrow will do. pressing the button will issue an WM_COMMAND and pressing the arrow will issue a TBN_DROPDOWN message which can be intercepted in the WM_NOTIFY message. the following code i post will work well if you only have one drop down arrow button but if you have more you will need to do additional checking:
.elseif uMsg == WM_NOTIFY

mov edi,lParam
assume edi:ptr NMHDR
mov eax,[edi].code
.if eax == TBN_DROPDOWN
invoke MessageBox,0,0,0,0
.endif
Posted on 2002-03-29 11:01:35 by smurf
You know thats kinda funny.

I was thinking some what along the same lines, (because I was still getting my WM_COMMAND message). However I did plug your code in but nothing happens. I had thought that might be the case earlier this morning, but I didnt get that to work either. If you have a working version send it to me! (Or post it plz). Mine just sits there like a lump!

DPhillips@KBSI.com:alright:
Posted on 2002-03-29 11:19:43 by Graebel
I am not sure why, but after some messing around with it I came up with this:

--=-=-=
.elseif uMsg == WM_NOTIFY
mov edi, lParam
assume edi:ptr NMTOOLBAR
mov eax, .iItem

.if eax == 57 ; Menu ID for font button
mov eax, .hdr.code
neg eax

.if eax == 710 ; TBN_DROPDOWN
PrintDec eax
.endif
.endif

xor eax, eax
ret

--=-=-=

Seems I am actually getting a NMTOOLBAR struct with the first member being a NMHDR. Which solves why I was having trouble detecting it. The second (very odd) thing was that I had to neg eax as all my return values from hdr.code were correct, but the wrong sign. I am not sure whats up with that yet...

But thanks for all the help! Really appriciate it
Posted on 2002-03-29 12:02:57 by Graebel
ok here is what i got:
Posted on 2002-03-29 12:41:00 by smurf
Before, when I was casting lParam to a NMHDR I was generating errors when I pressed the arrow button down. Your version does the same thing. Mine works correctly on my machine casting NMTITLEBAR.

I got my idea for the NMTITLEBAR from a different web site (sorry lost the page). However there was a reference to:

"This applies to version 4.71 and above."

I am assuming now that 4.71 is referencing the common controls version that is installed. Now this begs the question of, at runtime, can it be determined which version is loaded?

I know your version works on your machine and generates errors on mine, and mine works on mine but will probably error on yours. So in essence, is there a way (at run-time) to determine which version of the common control library we have loaded?
:confused:
Posted on 2002-03-29 13:12:32 by Graebel
im using windows 2000 sp2 and you must be using something different.

I know your version works on your machine and generates errors on mine, and mine works on mine but will probably error on yours. So in essence, is there a way (at run-time) to determine which version of the common control library we have loaded?

yes you can take a look here:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/Shell/programmersguide/versions.asp

try this code this should work better for you.
.elseif uMsg == WM_NOTIFY

mov edi,lParam
assume edi:ptr NMTOOLBAR
mov eax,[edi].hdr.idFrom
.if eax == 57
mov eax,[edi].hdr.code
.if eax == 710
invoke MessageBox,0,0,0,0
.endif


ps: by the way to make your code more readable on the forum use these tags:



and then close it off with /code with the brackets around it
Posted on 2002-03-29 13:50:05 by smurf
Yeah, thats just about the exact code I have right now.

Testing:


TBN_DROPDOWN equ -710

.elseif uMsg == WM_NOTIFY
mov edi, lParam
assume edi:ptr NMTOOLBAR
push [edi].iItem
pop ID
.if ID == 57 ; Menu ID for font button
mov eax, [edi].hdr.code
.if eax == TBN_DROPDOWN
; something
.endif
.endif
.endif


Lets see if that looks better

Dont ask me why *shrug* but I had to negate the value for TBN_DROPDOWN.

Everything works like a charm now. Need to re-test it on my 98 box at home.
Posted on 2002-03-29 14:07:30 by Graebel
its because this code:

push .iItem

should be changed to:

mov .hdr.iItem

when testing your code there was 3 messages that where making it all the way to this line:

.if eax == TBN_DROPDOWN

they all where being posted immediately once you pressed the arrow. im not sure exactly why the 3 messages were making it through like that but thats whats happening. by changing that line of your code to what i suggest will filter out the unwaned messages and allow the correct one to be processed and then you wont need to neg the eax.
Posted on 2002-03-29 14:19:38 by smurf
Graebel,

This can be used to determine the version of the
Common Controls, this code checks for at least
version 4.70



.data
lib_name db "\comctl32.dll", 0 ;library for DateTimePicker
dgv db "DllGetVersion", 0 ;function to check version of DLL
lib_err db "This Program Requires Version 4.70 of COMCTL32.DLL!", 0 ;warning message

.data?
lib_handle HWND ? ;Handle to check for dll version
proc_add DWORD ? ;used to store address for DLL
dvi DLLVERSIONINFO <> ;Structure for Dll Version Info
d_buffer BYTE MAX_PATH + 1 dup (?) ;allows us to read MAX filename size and 0

.code
invoke GetSystemDirectory, addr d_buffer, sizeof d_buffer
invoke lstrcat, addr d_buffer, addr lib_name
invoke LoadLibrary, addr d_buffer
;Load comctl32.dll to see if we have at least version 4.70
mov lib_handle, eax ;save handle
.if (eax == NULL) ;no valid handle returned
invoke MessageBox, NULL, addr lib_err, NULL, MB_OK
invoke ExitProcess, -1
ret
.endif
invoke GetProcAddress, lib_handle, addr dgv
;get address of DllGetVersion within comctl32.dll
mov proc_add, eax
.if (eax == NULL) ;no valid address to Proc returned
invoke MessageBox, NULL, addr lib_err, NULL, MB_OK
invoke FreeLibrary, lib_handle
invoke ExitProcess, -1
ret
.endif
invoke RtlZeroMemory, addr dvi, sizeof DLLVERSIONINFO
;set DLLVERSIONINFO Stru to zeroes
mov dvi.cbSize, sizeof DLLVERSIONINFO
push OFFSET dvi ;push structure address for DLLGetVersion
call proc_add ;call COMCTL32.DLL's DllGetVersion routine
cmp dvi.dwMajorVersion, 4 ;major version should be at least 4
jae @F
invoke MessageBox, NULL, addr lib_err, NULL, MB_OK
invoke FreeLibrary, lib_handle
invoke ExitProcess, -1
ret
@@: cmp dvi.dwMinorVersion, 70 ;minor version should be at least 70
jae @F
invoke MessageBox, NULL, addr lib_err, NULL, MB_OK
invoke FreeLibrary, lib_handle
invoke ExitProcess, -1
ret
@@:


hth,

farrier
Posted on 2002-03-30 03:34:52 by farrier
To address the original question about casting, Readiosys is correct in that you don't perform TYPE casting in assembler. What you in fact do is SIZE casting when it is necessary so that the assembler know what size data to transfer.


; mov a BYTE from address in ESI to AL
mov al, [esi]

; specify size of immediate value
mov WORD PTR [edi], 0A0Dh

Generally the idea is to put the correct SIZE data in the destination and particularly when it involves data transfer to or from memory, the size often needs to be specified.

Regards,

hutch@movsd.com
Posted on 2002-03-30 05:25:53 by hutch--
call it what you want, it's still a typecast, and masm is a typed assembler.
This is also evident in the opcodes generated in .IF depending on
signed/unsigned source value...
Posted on 2002-03-30 07:02:40 by f0dder
TYPE is a high level concept, SIZE is an assembler concept, knowing the difference means not making mistakes about data sizes.

Regards,

hutch@movsd.com
Posted on 2002-03-30 08:06:10 by hutch--
Dont forget you can write this code:


TBN_DROPDOWN equ -710

.elseif uMsg == WM_NOTIFY
mov edi, lParam
assume edi:ptr NMTOOLBAR
push [edi].iItem
pop ID
.if ID == 57 ; Menu ID for font button
mov eax, [edi].hdr.code
.if eax == TBN_DROPDOWN
; something
.endif
.endif
.endif


as this:



TBN_DROPDOWN equ -710

.elseif uMsg == WM_NOTIFY
mov edi, lParam
.if [NMTOOLBAR ptr [edi]].iItem == 57 ; Menu ID for font button
.if [NMTOOLBAR ptr [edi]].hdr.code == TBN_DROPDOWN
; something
.endif
.endif
.endif



This way you dont have to ue ASSUME which in this case, my personal opinion says looks real messy

Also you don't have to do a "mov eax,.iItem " ---- " .IF eax==" (espically for the constant).
Posted on 2002-03-31 02:01:17 by huh