The MASM Forum

General => The Campus => Topic started by: rc on October 30, 2019, 09:52:33 PM

Title: EN_SELCHANGE code from rich text edit
Post by: rc on October 30, 2019, 09:52:33 PM
Hello community,

i'm totally new to assembly and wanted to start with an easy text editor. The editor is working but i want to display the cursor position in the status bar. However somehow im struggeling with getting the selection change "event".

I have the following code:

CASE WM_NOTIFY
        mov edx, lParam
        mov eax, [edx].NMHDR.code
        .if eax == EN_SELCHANGE ;<---- this never gets evaluated to true but why?
            invoke SendMessage, hEdit, EM_EXLINEFROMCHAR, 0, -1 ; by the way: where does the return value of EM_EXLINEFROMCHAR get stored?

            ; just for testing (works nicely and sets the status bar text, but not when inside this if block)
            mov pbuffer1, ptr$(buffer1)
            mov pbuffer1, cat$(pbuffer1,"Test")
            invoke SendMessage,hStatus,SB_SETTEXT,0,pbuffer1
        .endif

case WM_CLOSE


As i have read from the documentation, the rich text edit control automatically sends a EL_SELCHANGE and i can get it in WM_NOTIFY. However, the condition is never true. What am i missing?

Sidequestion: in fasm i can write int3 to let the jitdebugger pop up when the program reaches this instruction. Whats the equivalent in masm? Thought this instruction isn't specific to any asm language but to the instruction set of the cpu. Somehow masm shows an error on int3.
Title: Re: EN_SELCHANGE code from rich text edit
Post by: jj2007 on October 30, 2019, 09:59:21 PM
For me, that works perfectly. Could you post the complete code please? Zip the source, and attach it here.
Re int3: leave a blank, i.e. int 3

Welcome to the Forum :thumbsup:
Title: Re: EN_SELCHANGE code from rich text edit
Post by: TimoVJL on October 30, 2019, 10:00:53 PM
https://docs.microsoft.com/en-us/windows/win32/controls/en-selchange
QuoteRemarks
To receive EN_SELCHANGE notification codes, specify ENM_SELCHANGE in the mask sent with the EM_SETEVENTMASK message.
Title: Re: EN_SELCHANGE code from rich text edit
Post by: rc on October 30, 2019, 10:05:57 PM
Thank you jj2007 :)


Quote from: TimoVJL on October 30, 2019, 10:00:53 PM
https://docs.microsoft.com/en-us/windows/win32/controls/en-selchange
QuoteRemarks
To receive EN_SELCHANGE notification codes, specify ENM_SELCHANGE in the mask sent with the EM_SETEVENTMASK message.

Ah ok. From where do i have to send this message? Thought this where done automatically by the rich text control?
Title: Re: EN_SELCHANGE code from rich text edit
Post by: TimoVJL on October 30, 2019, 10:21:02 PM
once, after creating richedit window
Title: Re: EN_SELCHANGE code from rich text edit
Post by: rc on October 30, 2019, 10:43:41 PM
This works, thank you. Totally missed that. :)

Now i need to know where return values typically get stored.

invoke SendMessage, hEdit, EM_EXLINEFROMCHAR, 0, -1 ;

Here i get the line info, but i don't know where it is stored.

Microsoft docs do not mention anything like that as they probably assume you want to write c code.

Is there a rule of thump that says, to follow the std convention, return values are always stored in register "xxx".
As i have read, to follow the std call convention, a subroutine shall not change the ebx register, if so, it has to preserve ebx and reset it when leaving. Also i have read, that a subroutine is responsible for restoring the stack and so on.
Title: Re: EN_SELCHANGE code from rich text edit
Post by: hutch-- on October 30, 2019, 11:16:14 PM
This is from the old win32.hlp file and it works OK.

The EM_EXLINEFROMCHAR message determines which line contains the specified character in a rich edit control.

EM_EXLINEFROMCHAR 
wParam = 0;
lParam = (LPARAM) (DWORD) ichCharPos;


Parameters

ichCharPos

Zero-based index of the character.

Return Values
Returns the zero-based index of the line.


The return value in Win32 is always in EAX.

Code something like this.

    invoke SendMessage,hEdit,EM_EXLINEFROMCHAR,0,charpos
    mov lind, eax

Title: Re: EN_SELCHANGE code from rich text edit
Post by: jj2007 on October 30, 2019, 11:25:47 PM
Quote from: rc on October 30, 2019, 10:43:41 PMHere i get the line info, but i don't know where it is stored.

Wherever you want to store it. That can be a register, but check the Tips, Tricks and Traps section here (http://www.jj2007.eu/Masm32_Tips_Tricks_and_Traps.htm). There are volatile and less volatile registers.

Depending on your needs, you can store it also in a local or global variable.
Title: Re: EN_SELCHANGE code from rich text edit
Post by: rc on October 31, 2019, 12:22:28 AM
Thank you hutch-- for the explaination. Such things like return values are always stored in eax are implied knowlege  and hard to learn for newbs.
@jj2007 thanks for the link, i have read it. Good to know, especially the stuff about local variables.

Im a bit confused know though.

All i want to get is the line where the cursor currently is located.
At the beginning of the proc, i have created some spare buffers and local variables:


WndProc proc hWin:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
   
    ; Two spare buffers + pointers
    ; for text manipulation etc..
    LOCAL buf1[260]:BYTE 
    LOCAL buf2[260]:BYTE
    LOCAL pbuf1:DWORD
    LOCAL pbuf2:DWORD
    ; temp variable for storing 32 bit values temporarily if needed
    LOCAL tmpd:DWORD

    Switch uMsg
      Case WM_COMMAND
      ...
      ...
      CASE WM_NOTIFY
        mov edx, lParam
        mov eax, [edx].NMHDR.code

        .if eax == EN_SELCHANGE
            mov pbuf1, ptr$(buf1)
            invoke SendMessage, hEdit, EM_EXLINEFROMCHAR, 0, -1
            mov tmpd, eax
            mov pbuf1, cat$(pbuf1, "Line: ", tmpd) ; <--------  crash here
           
            invoke SendMessage, hStatus, SB_SETTEXT, 0, pbuf1

        .endif

      case WM_CLOSE
      ...
      ...


The code should just get the line where the cursor currently is and set the text in the statusbar to "Line: xxx", where xxx is the line.
Title: Re: EN_SELCHANGE code from rich text edit
Post by: jj2007 on October 31, 2019, 12:25:53 AM
Try mov pbuf1, cat$(pbuf1, "Line: ", str$(tmpd))

I write "try" because you don't post complete code.
Title: Re: EN_SELCHANGE code from rich text edit
Post by: rc on October 31, 2019, 12:47:30 AM
Quote from: jj2007 on October 31, 2019, 12:25:53 AM
Try mov pbuf1, cat$(pbuf1, "Line: ", str$(tmpd))

Oh this works. Of course, tmpd is an integer.... thank you!
A lot to consider in assembly that leads to overlooking such trivial things.
Especially when one is used to compiler error messages like "Int cannot implicitly converted to str" :)

Thanks. :)

Quote from: jj2007 on October 31, 2019, 12:25:53 AM
I write "try" because you don't post complete code.

It's not that i don't want to post the entire code. It's just that it is a lot of code. And most of the code is generated by the "MASM32 Window Code Createion Tool" from Steve Hutchesson.

I used that as a starting point to dig into the generated code, try to understand it, extend it a little bit and so on.
As i am probably not at the point where i am able to write such editor from scratch in masm. :)




Maybe it's usefull to others, here is the working code:

Window creation and setting the eventbitmask:

; -----------------------------------------------------------------
  ; create the main window with the size and attributes defined above
  ; -----------------------------------------------------------------
    invoke CreateWindowEx,WS_EX_LEFT or WS_EX_ACCEPTFILES,
                          ADDR szClassName,
                          ADDR szDisplayName,
                          WS_OVERLAPPEDWINDOW,
                          Wtx,Wty,Wwd,Wht,
                          NULL,NULL,
                          hInstance,NULL
    mov hWnd,eax

    fn LoadLibrary,"RICHED20.DLL"
    mov hEdit, rv(RichEdit2,hInstance,hWnd,999,0)
    invoke SendMessage,hEdit,EM_EXLIMITTEXT,0,1000000000
    invoke SendMessage,hEdit,EM_SETOPTIONS,ECOOP_XOR,ECO_SELECTIONBAR
    invoke SendMessage,hEdit, EM_SETEVENTMASK, 0, ENM_SELCHANGE or ENM_CHANGE


And here reacting to the selchange event:

WndProc proc hWin:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
   
    ; Two spare buffers + pointers
    ; for text manipulation etc..
    LOCAL buf1[260]:BYTE
    LOCAL buf2[260]:BYTE
    LOCAL pbuf1:DWORD
    LOCAL pbuf2:DWORD
    ; temp variable for storing 32 bit values temporarily if needed
    LOCAL tmpd:DWORD

    Switch uMsg
      Case WM_COMMAND
      ...
      ...
      CASE WM_NOTIFY
        mov edx, lParam
        mov eax, [edx].NMHDR.code

        .if eax == EN_SELCHANGE
            mov pbuf1, ptr$(buf1)
            invoke SendMessage, hEdit, EM_EXLINEFROMCHAR, 0, -1
            inc eax ; because its 0 based
            mov pbuf1, cat$(pbuf1, "Line: ", str$(eax))
           
            invoke SendMessage, hStatus, SB_SETTEXT, 0, pbuf1 ; hStatus is the handle to the status bar

        .endif

      case WM_CLOSE
      ...
      ...


Title: Re: EN_SELCHANGE code from rich text edit
Post by: jj2007 on October 31, 2019, 02:15:44 AM
            invoke SendMessage, hEdit, EM_EXLINEFROMCHAR, 0, -1
            mov tmpd, eax
            inc tmpd ; because its 0 based
            mov pbuf1, cat$(pbuf1, "Line: ", str$(tmpd))


Try
            invoke SendMessage, hEdit, EM_EXLINEFROMCHAR, 0, -1
            inc eax ; because its 0 based
            mov pbuf1, cat$(pbuf1, "Line: ", str$(eax))
Title: Re: EN_SELCHANGE code from rich text edit
Post by: rc on October 31, 2019, 02:21:21 AM
Quote from: jj2007 on October 31, 2019, 02:15:44 AM
Try
            invoke SendMessage, hEdit, EM_EXLINEFROMCHAR, 0, -1
            inc eax ; because its 0 based
            mov pbuf1, cat$(pbuf1, "Line: ", str$(eax))


This works exactly the same way :). (I've updated the post above)
I still don't know when do i have to put stuff into a variable
and when can i use the register itself as an argument.

I know this is specific to the macro engine of masm, normally one would push the arguments onto the stack in reverse order and use the call instruction to invoke a function.
Title: Re: EN_SELCHANGE code from rich text edit
Post by: hutch-- on October 31, 2019, 03:00:51 AM
Its usually the case that you use variables first when you lay out an algorithm as registers are a scarce resource. When you have an algorithm working, you can then optimise it with any spare registers you may have available and get it faster or smaller or both but if you start with variables, you don't directly run out of registers before you get it working. As most memory to memory data exchanges (variables) must be done through registers, you must use at least some but get it working first.
Title: Re: EN_SELCHANGE code from rich text edit
Post by: rc on October 31, 2019, 03:48:19 AM
Thanks for this advice, i will definitly keep this in mind!
Title: Re: EN_SELCHANGE code from rich text edit
Post by: jj2007 on October 31, 2019, 04:23:49 AM
Quote from: rc on October 31, 2019, 02:21:21 AMwhen can i use the register itself as an argument.
You can use regs if they don't get "destroyed" by some other invoke


QuoteI know this is specific to the macro engine of masm, normally one would push the arguments onto the stack in reverse order and use the call instruction to invoke a function.

invoke puts args into the right order and checks their type and number, too.
Title: Re: EN_SELCHANGE code from rich text edit
Post by: rc on October 31, 2019, 05:25:51 AM
Quote from: jj2007 on October 31, 2019, 04:23:49 AM
invoke puts args into the right order and checks their type and number, too.

Ah ok, yes that makes sense, since i get usefull "compile" errors like: type mismatch but didn't realised that there isn't usually such thing in plain assembly. Good to know.

What comes into my mind: what is the difference between invoke and fn? Seen this in the generated code.
Title: Re: EN_SELCHANGE code from rich text edit
Post by: jj2007 on October 31, 2019, 06:54:58 AM
Quote from: rc on October 31, 2019, 05:25:51 AMWhat comes into my mind: what is the difference between invoke and fn? Seen this in the generated code.
invoke is a built-in Masm macro, fn is a Masm32 macro.
invoke is Microsoft, fn is Hutch - check \Masm32\Help\HLHELP.chm for details.

More interesting than fn is the rv() macro: mov TheHandle, rv(CreateWindowEx, WS_EX_CLIENTEDGE, "edit", ....)
Title: Re: EN_SELCHANGE code from rich text edit
Post by: rc on October 31, 2019, 07:10:45 AM
Interesting! I will study the help files then. :)
Thanks a lot for helping, awesome forum and community! :)
Title: Re: EN_SELCHANGE code from rich text edit
Post by: daydreamer on November 01, 2019, 03:53:04 AM
welcome to forum :thumbsup:
Title: Re: EN_SELCHANGE code from rich text edit
Post by: rc on November 01, 2019, 06:53:59 AM
Quote from: daydreamer on November 01, 2019, 03:53:04 AM
welcome to forum :thumbsup:

Thanks daydreamer :).