Author Topic: EN_SELCHANGE code from rich text edit  (Read 432 times)

rc

  • Regular Member
  • *
  • Posts: 16
EN_SELCHANGE code from rich text edit
« 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:

Code: [Select]
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.

jj2007

  • Member
  • *****
  • Posts: 9811
  • Assembler is fun ;-)
    • MasmBasic
Re: EN_SELCHANGE code from rich text edit
« Reply #1 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:

TimoVJL

  • Member
  • ***
  • Posts: 477
Re: EN_SELCHANGE code from rich text edit
« Reply #2 on: October 30, 2019, 10:00:53 PM »
https://docs.microsoft.com/en-us/windows/win32/controls/en-selchange
Quote
Remarks
To receive EN_SELCHANGE notification codes, specify ENM_SELCHANGE in the mask sent with the EM_SETEVENTMASK message.
May the source be with you

rc

  • Regular Member
  • *
  • Posts: 16
Re: EN_SELCHANGE code from rich text edit
« Reply #3 on: October 30, 2019, 10:05:57 PM »
Thank you jj2007 :)


https://docs.microsoft.com/en-us/windows/win32/controls/en-selchange
Quote
Remarks
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?

TimoVJL

  • Member
  • ***
  • Posts: 477
Re: EN_SELCHANGE code from rich text edit
« Reply #4 on: October 30, 2019, 10:21:02 PM »
once, after creating richedit window
May the source be with you

rc

  • Regular Member
  • *
  • Posts: 16
Re: EN_SELCHANGE code from rich text edit
« Reply #5 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.

Code: [Select]
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.

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 6775
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: EN_SELCHANGE code from rich text edit
« Reply #6 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

hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy:

jj2007

  • Member
  • *****
  • Posts: 9811
  • Assembler is fun ;-)
    • MasmBasic
Re: EN_SELCHANGE code from rich text edit
« Reply #7 on: October 30, 2019, 11:25:47 PM »
Here 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. There are volatile and less volatile registers.

Depending on your needs, you can store it also in a local or global variable.

rc

  • Regular Member
  • *
  • Posts: 16
Re: EN_SELCHANGE code from rich text edit
« Reply #8 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:

Code: [Select]
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.

jj2007

  • Member
  • *****
  • Posts: 9811
  • Assembler is fun ;-)
    • MasmBasic
Re: EN_SELCHANGE code from rich text edit
« Reply #9 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.

rc

  • Regular Member
  • *
  • Posts: 16
Re: EN_SELCHANGE code from rich text edit
« Reply #10 on: October 31, 2019, 12:47:30 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. :)

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:
Code: [Select]
; -----------------------------------------------------------------
  ; 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:
Code: [Select]
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
      ...
      ...

« Last Edit: October 31, 2019, 02:22:14 AM by rc »

jj2007

  • Member
  • *****
  • Posts: 9811
  • Assembler is fun ;-)
    • MasmBasic
Re: EN_SELCHANGE code from rich text edit
« Reply #11 on: October 31, 2019, 02:15:44 AM »
Code: [Select]
            invoke SendMessage, hEdit, EM_EXLINEFROMCHAR, 0, -1
            mov tmpd, eax
            inc tmpd ; because its 0 based
            mov pbuf1, cat$(pbuf1, "Line: ", str$(tmpd))

Try
Code: [Select]
            invoke SendMessage, hEdit, EM_EXLINEFROMCHAR, 0, -1
            inc eax ; because its 0 based
            mov pbuf1, cat$(pbuf1, "Line: ", str$(eax))

rc

  • Regular Member
  • *
  • Posts: 16
Re: EN_SELCHANGE code from rich text edit
« Reply #12 on: October 31, 2019, 02:21:21 AM »
Try
Code: [Select]
            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.

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 6775
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: EN_SELCHANGE code from rich text edit
« Reply #13 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.
hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy:

rc

  • Regular Member
  • *
  • Posts: 16
Re: EN_SELCHANGE code from rich text edit
« Reply #14 on: October 31, 2019, 03:48:19 AM »
Thanks for this advice, i will definitly keep this in mind!