News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Static control overlapping siblings when Alt key is pressed

Started by kkurkiewicz, February 06, 2024, 05:49:53 AM

Previous topic - Next topic

kkurkiewicz

If ASSUME is used, PDIS becomes redundant. How do I take the address of RCITEM if the only reference to DRAWITEMSTRUCT is a pointer stored in ESI?
Kamil

jj2007

Quote from: kkurkiewicz on February 08, 2024, 06:14:54 AMHow would you rewrite PUSH  OFFSET PDIS.RCITEM?

push offset pdis.RCITEM (in case you want to pass on the address of the RECT structure)

kkurkiewicz

What I meant was that if the PDIS var is deleted, then PUSH OFFSET [ESI].RCITEM is a syntax error. How do I take the address of the RCITEM member using only ESI?

WMDRAWITEM:
; Message was not sent by the rectangle static control => return FALSE
    CMP    DWORD PTR [EBP+10H], 1001
    JNE    FINISH
; Load the DRAWITEMSTRUCT pointer into ESI and cast the register to a pointer
    MOV    ESI, DWORD PTR [EBP+14H]
    ASSUME ESI:PTR DRAWITEMSTRUCT
; Fill the rectangle with white
    PUSH   HBRUSHSTATIC
    PUSH   OFFSET [ESI].RCITEM
    PUSH   [ESI].HDC
    CALL   FillRect@12
; Ensure that the device context identified by HDC is in the default state, cancel all assumptions and return
    MOV    [ESI].ITEMSTATE, 20h  ; ODS_DEFAULT
    MOV    [ESI].HDC, 0
    ASSUME ESI:NOTHING
    MOV    EAX, 1
    JMP    FIN
Kamil

NoCforMe

Quote from: kkurkiewicz on February 08, 2024, 06:50:02 AMIf ASSUME is used, PDIS becomes redundant. How do I take the address of RCITEM if the only reference to DRAWITEMSTRUCT is a pointer stored in ESI?
Easy peasy:
[ESI].DRAWITEMSTRUCT.<member>
You just use the name of the structure here, which tells the assembler the type of the reference.
Assembly language programming should be fun. That's why I do it.

kkurkiewicz

But I need a pointer...
Pardon the comparison, but it would be &(esi->rcItem) in C.
Kamil

jj2007

Quote from: kkurkiewicz on February 08, 2024, 07:24:58 AM; Fill the rectangle with white
    PUSH   HBRUSHSTATIC
    PUSH   OFFSET [ESI].RCITEM
    PUSH   [ESI].HDC
    CALL   FillRect@12

The proper way to do that is to use invoke. Two options:
ASSUME ESI:PTR DRAWITEMSTRUCT
invoke FillRect, [esi].hDC, addr [esi].rcItem, hWhiteBrush
ASSUME ESI:nothing
dis equ [esi.DRAWITEMSTRUCT]
invoke FillRect, dis.hDC, addr dis.rcItem, hWhiteBrush

Note that the second option is much more readable, and you don't need to de-assign anything.

The push-push-call orgies look so professional, but after a while you'll just find out that they are error-prone and useless. There is a reason why invoke was created.

Note also that Masm and its clones are mostly case-insensitive. Writing a Million times PUSH will lead to Repetitive Strain Injury.

NoCforMe

Quote from: kkurkiewicz on February 08, 2024, 07:46:06 AMBut I need a pointer...
Pardon the comparison, but it would be &(esi->rcItem) in C.
In that case you need to add ADDR to the equation:

&(esi->rcItem) <--> ADDR [ESI].DRAWITEMSTRUCT.rcItem

(What goes on "behind the scenes" is this:
LEA   EAX, [ESI].DRAWITEMSTRUCT.rcItem
leaving EAX with the address of that member of the structure, which is just the value of ESI plus the offset of that member)
(Which is why you must always be aware of this when using ADDR, and be prepared for EAX to be trashed)
Assembly language programming should be fun. That's why I do it.

jj2007

Quote from: NoCforMe on February 08, 2024, 09:53:08 AMwhen using ADDR .. be prepared for EAX to be trashed

Don't worry: if that is the case, invoke will throw an error.

NoCforMe

Yes. BTW, I totally endorse JJ's advice to use INVOKE.
Assembly language programming should be fun. That's why I do it.

Greenhorn

Quote from: kkurkiewicz on February 08, 2024, 07:24:58 AMWhat I meant was that if the PDIS var is deleted, then PUSH OFFSET [ESI].RCITEM is a syntax error. How do I take the address of the RCITEM member using only ESI?

WMDRAWITEM:
    ...
    ASSUME ESI:PTR DRAWITEMSTRUCT
; Fill the rectangle with white
    PUSH   HBRUSHSTATIC
    LEA    EAX, [ESI].RCITEM
    PUSH   EAX

    PUSH   [ESI].HDC
    CALL   FillRect@12
    ...



Kole Feut un Nordenwind gift en krusen Büdel un en lütten Pint.

kkurkiewicz

Kamil

jj2007

Quote from: kkurkiewicz on February 08, 2024, 07:44:57 PMNext time I will use INVOKE, I promise.

include \masm32\include\masm32rt.inc    ; has all the definitions, PROTOs, etc

.data?
hWhiteBrush    dd ?
_dis    DRAWITEMSTRUCT <>

.code
start:
  ; option A, shorter code:
  mov esi, offset _dis
  dis equ <[esi.DRAWITEMSTRUCT]>
  invoke FillRect, dis.hdc, addr dis.rcItem, hWhiteBrush

  ; option B, more code under the hood (4 bytes more):
  invoke FillRect, _dis.hdc, addr _dis.rcItem, hWhiteBrush
end start

(just to demonstrate the techniques - code will build but crash, since there is no DC, brush etc yet)

Have a look at \masm32\include\masm32rt.inc, it contains all the definitions that you collected in proc.inc (you wouldn't re-write WinUser.h if it was C++, right?)

If you write...
invoke FillRect, dis.hdc, addr dis.rcItem, hWhiteBrush, eax
... the assembler will shout at you: Too many arguments to INVOKE

It will not shout if you do it with push-push-call. No problem, of course, you can count to three, right? But there are functions like CreateFont with 14 arguments, or CreateWindowEx with 11; or try NtAccessCheckByTypeResultListAndAuditAlarmByHandle (defined in \Masm32\include\ntdll.inc). It's easy to get lost with push-push-call, your stack will be 4 bytes off, and such bugs are very difficult to chase. Use invoke.