flat assembler
Message board for the users of flat assembler.

Index > Windows > Writing to an Edit Control

Goto page Previous  1, 2, 3, 4  Next
Author
Thread Post new topic Reply to topic
AsmGuru62



Joined: 28 Jan 2004
Posts: 1628
Location: Toronto, Canada
AsmGuru62 06 Aug 2024, 16:39
The final problem was the message loop.
I fixed it to look like this:
Code:
msg_loop: invoke  GetMessage,msg,0,0,0
          cmp     eax,0
          je      end_loop
;          je      msg_loop
          invoke  TranslateMessage,msg
          invoke  DispatchMessage,msg
          jmp     msg_loop
    
Post 06 Aug 2024, 16:39
View user's profile Send private message Send e-mail Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20343
Location: In your JS exploiting you and your system
revolution 06 Aug 2024, 19:39
AsmGuru62 wrote:
...maybe FASM should warn about the case of local/parameter name matching the global name.
"proc" is a macro. fasm doesn't have warnings, but you can add a "display" output to the proc macro to give you a warning.

With regards to the stack. There are some functions of Windows that refuse to use your stack if it isn't in a place that Windows has specifically allocated for use as a stack.. Trying to use your own custom stack in data memory works as far as the CPU is concerned, but problems can occur when Windows sees it isn't in the "right" place.

Also the stack points to the bottom, not the top of R0, so it effectively has a stack size of zero size, clobbering whatever has been allocated below R0.
Post 06 Aug 2024, 19:39
View user's profile Send private message Visit poster's website Reply with quote
Stancliff



Joined: 30 Jun 2024
Posts: 54
Location: Florida
Stancliff 07 Aug 2024, 00:37
Regarding
1) I saw that CreateWindow for the parent and child returned a handle to the window so I made a var for the parent handle not knowing if it was used. Calling it hwnd was a mistake and it has only beeen used by my MessageBox commands.It will be renamed parhwnd. The child handle has been called edithwnd so it doesn't conflict with the WindowProc parameter and it is referrenced several places.
2) Since the hwnd parameter is needed by the child window and not used outside it to my knowledge, renaming and/or copying it won't be needed. The global can be renamed.
3) I have spent over two hours studying function docs and it is clear that any value in eax when WindowProc returns will go back to DispatchMessage, get used as it's return value, and then be totally ignored by the jump back to msg_loop. They all do nothing and are not needed since eax always has some value. So your change that would have broken wmcreate's .failed sub isn't needed.
The thread ends bacause PostQuitMessage puts a WM_QUIT msg with a zero return value as shown in the code. This could be made other values, but isn't in MiniPad. GetMessage takes the WM_QUIT and returns 0 triggering the jump to end_loop. Then ExitProcess returns [msg.wParam] which I am guessing is the return value stated in PostQuitMessage. So that is where any actual return value has to be set... and one is.
You are not going to see any of my actual code until I get this editor interface working well posting and returning strings. It could happen within the week though several functions I would like are not written yet... mainly file I/O and search.
When I receive a command string it is captured by Query, parsed by Interpret, and compiled by a couple of dozen other functions that I have to port into the working version. Right now they would just get in the way.
PushAD is an attempt to build a wall between my code and windows, expecially the OS side. This also applies to my restricting the return stack to the location of the value in [esp] when the program starts. WindowProc can read the prameter frame for it's parameters but my code doesn't use any. All parameters are pushed to a data stack I am pointing to with [edx]. It is completely separate with it's own pushes and pops. This is a critical design feature of Forth and you can look up "starting Forth" by Leo Brodie if you would like details.

I will move Cold and the rest of the init back to start to see if I can adjust the stacks before anything has a chance to run. There used to be a fair amount more to do but I cut it way back.
That return stack code is making it not create the parent window, but even with those commented out the child isn't working.
Here is the modifications I made this evening...
Code:
; Simple text editor - fasm example program
format PE GUI 4.0
entry start
include 'win32ax.inc'

macro fPush value               ; Push value to TOS (Top Of Stack)
{  add edx, -4                  ; S - 4, new cell for TOS
   mov [edx], dword value       ; move value to TOS
}
macro Msg label                 ; msg string typed to screen
{  fPush label                  ; Push adr of string to TOS
   call Type                    ; Display string on screen
}
section '.data' data readable writeable
; compute adr's for 2 stacks starting from return stack at enter
; == Return Stack =====
; R:      [ESP]                 ; Return Stack ptr, in ESP
R0        DD 0                  ; Ret Stk End, at run = initial [esp]
ToR       DD 0                  ; 1 cell above Top of R, at run =[esp]+64
; == Data Stack ======
; S:      [EDX]                 ; Data Stack ptr, in EDX
S0:       DD 128 Dup ?          ; Data Stack End, 128 cells
ToS:                            ; 1 cell above Top of S Stack
; I wanted to use EBP for the Data Stack but I hear Windows uses it

; Note: many good names from Forth are reserved by assembler, find alt's
NameSz   EQU 256                 ; max name cnt, increases dictionary size
New^     DD Reserved             ; ptr to next unused rec in Name
N^       DD 0                    ; Name Ptr, index for Name, was DP
TIB      DB 128 Dup " "          ; Term Input Buf adr, 128 b
T^       DD 0                    ; Text Ptr to current source, was IN
Pad      DB 128 Dup " "          ; Pad adr, 128 b
P^       DD Pad                  ; Pad ptr (temp work area)
H^       DD EndKern              ; ptr to current unused cell for code
Fence    DD Reserved -17         ; adr of last protected dictionary word
Base     DD 10                   ; initial value for base conversion

; Start Dictionary with major words of kernal core
; Names have 8 char length w/trailing zeros, no cnt byte for string
; Code Adr = 4 byte, Param Adr = 4 byte, Status = 1 byte (0=IMM,1=Defer)
Name:
DB  "Cold",0,0,0,0
 DD Cold,0
 DB 1
DB  "Abort",0,0,0
 DD Abort,0
 DB 1
DB  "Quit",0,0,0,0
 DD Quit,0
 DB 1
DB  "Query",0,0,0
 DD Query,0
 DB 1
Reserved: DB ((NameSz *17) +Name -Reserved) Dup ?  ; clear Name space
; Forth searches the dictionary to find the address of a command.  My bare
; bones kernal will need close to 60 names.  The Forth standard has almost
; 140 names, and with extensions like floating point, a simple assembler,
; and various data structures this can easily go over 200.

; Windows assignments
  _class       TCHAR 'Go4th',0
  _title       TCHAR 'Go4th32',0
  _about_title TCHAR 'About Go4th32',0
  _about_text  TCHAR 'Windows based Forth Compiler',13,10,\
                     'Created with FLAT assembler.',0
  _edit        TCHAR 'EDIT',0
  _error       TCHAR 'Startup failed.',0

client        RECT               ; window box sides
ClsAtom       dd ?
editfont      dd ?
edithwnd      dd ?
parhwnd       dd ?
hmenu         dd ?
msg           MSG                ; message struct for Windows

IDR_ICON   =  17
IDR_MENU   =  37
  ; Menu items
IDM_FILE   = 100
IDM_NEW    = 110
IDM_OPEN   = 120
IDM_EXIT   = 130
IDM_SVSEL  = 140
IDM_SAVE   = 150
IDM_SAVEAS = 160

IDM_EDIT   = 200
IDM_UNDO   = 210
IDM_FIND   = 220
IDM_CUT    = 230
IDM_COPY   = 240
IDM_PASTE  = 250
IDM_DEL    = 260

IDM_HELP   = 900
IDM_ABOUT  = 910

wc WNDCLASS 0,WindowProc,0,0,0,0,0,COLOR_BTNFACE+1,0,_class

section '.idata' import data readable writeable
   library    advapi32,          'ADVAPI32.DLL',\
              comctl32,          'CONCTL32.DLL',\
              comdlg32,          'COMDLG32.DLL',\
              gdi32,             'GDI32.DLL',\
              kernel32,          'KERNEL32.DLL',\
              shell32,           'SHELL32.DLL',\
              user32,            'USER32.DLL',\
              wsock32,           'WSOCK32.DLL'
   include    'api\advapi32.inc'
   include    'api\comctl32.inc'
   include    'api\comdlg32.inc'
   include    'api\gdi32.inc'
   include    'api\kernel32.inc'
   include    'api\shell32.inc'
   include    'api\user32.inc'
   include    'api\wsock32.inc'

section '.rsrc' resource data readable
directory     RT_MENU, menus,  RT_VERSION, versions,  RT_ICON, icons,\
              RT_GROUP_ICON, group_icons

resource  menus,       IDR_MENU, LANG_ENGLISH +SUBLANG_DEFAULT, main_menu
resource  versions,    1, LANG_NEUTRAL, version
resource  group_icons, IDR_ICON, LANG_NEUTRAL, main_icon
resource  icons,       1, LANG_NEUTRAL, icon_data

  versioninfo  version, VOS__WINDOWS32, VFT_APP, VFT2_UNKNOWN,\
          LANG_ENGLISH +SUBLANG_DEFAULT, 0,\
          'FileDescription', 'MiniPad - example program',\
          'LegalCopyright', 'No rights reserved.',\
          'FileVersion', '1.0',\
          'ProductVersion', '1.0',\
          'OriginalFilename', 'MINIPAD.EXE'
  icon    main_icon, icon_data, 'Go4th.ico'

menu main_menu
    menuitem '&File',IDM_FILE, MFR_POPUP
          menuitem '&New',IDM_NEW
          menuitem '&Open',IDM_OPEN
          menuitem 'E&xit',IDM_EXIT
          menuseparator
          menuitem '&SvSelect',IDM_SVSEL
          menuitem 'Sa&ve',IDM_SAVE
          menuitem 'Save &As',IDM_SAVEAS, MFR_END
    menuitem '&Edit',IDM_EDIT, MFR_POPUP
          menuitem '&Undo',IDM_UNDO
          menuitem '&Find',IDM_FIND
          menuseparator
          menuitem '&Cut',IDM_CUT
          menuitem 'Co&py',IDM_COPY
          menuitem '&Paste',IDM_PASTE
          menuitem '&Delete',IDM_DEL, MFR_END
    menuitem '&Help',IDM_HELP, MFR_POPUP + MFR_END ; LAST POPUP - MFR_END"
          menuitem '&About', IDM_ABOUT, MFR_END

section '.code' code readable executable writeable
start:    Push    ebx
          Push    ecx
          Push    edx
          Push    esi
          Push    edi
;          mov     [R0],esp      ; set old stack point to new stack start
;          mov     [ToR],esp     ; Top of Return needs to allow 64 cells
;          add     [ToR],256     ; allow 64 cells for local return stack

; Cold:  full restart, reset N^ , New^, and Fence, run Abort
Cold:     mov     eax, [Name]
          mov     [N^], eax
          mov     [New^], eax
          mov     eax, [Fence +17]
; Abort:  reset data stack, set base, run Quit
Abort:    mov  edx, S0          ; clear data S wipes all pending params
          mov  [Base], 10
; Quit:  reset return stack. clears all outstanding function calls
Quit:     ;mov  esp, R0          ; clear return R

          invoke  GetModuleHandle,0
          mov     [wc.hInstance],eax
          invoke  LoadIcon,[wc.hInstance],IDR_ICON
          mov     [wc.hIcon],eax
          invoke  LoadCursor,0,IDC_ARROW
          mov     [wc.hCursor],eax
          invoke  LoadMenu,[wc.hInstance],IDR_MENU
          mov     [hmenu],eax
          invoke  RegisterClass,wc
          mov     [ClsAtom],eax
          invoke  CreateWindowEx,0,_class,_title,WS_TILEDWINDOW+\
                  WS_VISIBLE,200,100,900,600,0,[hmenu],[wc.hInstance],0
          mov     [parhwnd],eax

msg_loop: invoke  GetMessage,msg,0,0,0
          cmp     eax,1
          jb      end_loop
          jge     msg_loop
          invoke  TranslateMessage,msg
          invoke  DispatchMessage,msg
          jmp     msg_loop
error:    invoke  MessageBox,NULL,_error,NULL,MB_ICONERROR+MB_OK
end_loop: Pop     edi
          Pop     esi
          Pop     edx
          Pop     ecx
          Pop     ebx
          invoke  ExitProcess,[msg.wParam]

; Add most new code here

; Query:  Move a null terminated string into Terminal Input Buffer
Query:    mov     [TIB], 123              ; set input limit
          invoke  SendMessage,[edithwnd],EM_GETLINECOUNT,0,0
          invoke  SendMessage,[edithwnd],EM_GETLINE,eax,dword[TIB]
          mov     [TIB +eax],0            ; add null to string
          invoke  SendMessage,[edithwnd],EM_REPLACESEL,0,NewLine
; Test results - Write input line back out
          invoke  SendMessage,[edithwnd],EM_SETSEL,-1,-1
          invoke  SendMessage,[edithwnd],EM_REPLACESEL,0,dword[TIB]

Banner:   DB "Go4th: The Windows Forth Compiler",13,10,0
MyFont:   DB "Courier New"
NewLine:  DB 13,10,0
Prompt:   DB "4th?",0
proc WindowProc hwnd,wmsg,wparam,lparam
          mov     eax,[wmsg]
          cmp     eax,WM_CREATE
          je      .wmcreate
          cmp     eax,WM_SIZE
          je      .wmsize
          cmp     eax,WM_SETFOCUS
          je      .wmsetfocus
          cmp     eax,WM_CHAR
          je      .wmchar
          cmp     eax,WM_COMMAND
          je      .wmcommand
          cmp     eax,WM_DESTROY
          je      .wmdestroy
  .defwndproc:
          invoke  DefWindowProc,[hwnd],[wmsg],[wparam],[lparam]
          jmp     .finish
  .wmcreate:
          invoke  GetClientRect,[hwnd],client
          invoke  CreateWindowEx,WS_EX_CLIENTEDGE,_edit,0,WS_VISIBLE+\
          WS_CHILD+WS_HSCROLL+WS_VSCROLL+ES_AUTOHSCROLL+ES_AUTOVSCROLL+\
          ES_MULTILINE+ES_WANTRETURN,[client.left],[client.top],\
          [client.right],[client.bottom],[hwnd],0,[wc.hInstance],NULL
          mov     [edithwnd],eax
          cmp     eax,0
          jmp     .finish
          invoke  CreateFont,16,0,0,0,0,FALSE,FALSE,FALSE,ANSI_CHARSET,\
          OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,\
          FIXED_PITCH+FF_MODERN,MyFont
; invoke  MessageBox,[parhwnd],"After Font",0,MB_OK
          mov     [editfont],eax
          cmp     eax,0
          jmp     .finish
          invoke  SendMessage,[edithwnd],WM_SETFONT,eax,FALSE
          invoke  SendMessage,[edithwnd],EM_SETSEL,-1,-1
          invoke  SendMessage,[edithwnd],EM_REPLACESEL,0,Banner
          invoke  SendMessage,[edithwnd],EM_SETSEL,-1,-1
          invoke  SendMessage,[edithwnd],EM_REPLACESEL,0,Prompt
;          Msg     Banner
;          Msg     Prompt
          jmp     .finish
  .wmsize:
          invoke  GetClientRect,[hwnd],client
          invoke  MoveWindow,[edithwnd],[client.left],[client.top],\
          [client.right],[client.bottom],TRUE
          jmp     .finish
  .wmsetfocus:
          invoke  SetFocus,[edithwnd]
          jmp     .finish
  .wmchar:
          invoke  SendMessage,[edithwnd],WM_CHAR,ebx,ecx
          cmp     ebx,VK_RETURN
          jne     .defwndproc
          call    Query                  ; return a null terminated string
;          call    Interpret             ; parse and execute commands
          jmp     .defwndproc
  .wmcommand:
          mov     eax,[wparam]
          and     eax,0FFFFh
          cmp     eax, IDM_NEW
          je      .new
          cmp     eax, IDM_OPEN
          je      .open
          cmp     eax, IDM_SVSEL
          je      .svSel
          cmp     eax, IDM_SAVE
          je      .save
          cmp     eax, IDM_SAVEAS
          je      .saveAs
          cmp     eax, IDM_UNDO
          je      .undo
          cmp     eax, IDM_FIND
          je      .find
          cmp     eax, IDM_CUT
          je      .cut
          cmp     eax, IDM_COPY
          je      .copy
          cmp     eax, IDM_PASTE
          je      .paste
          cmp     eax, IDM_DEL
          je      .del
          cmp     eax, IDM_ABOUT
          je      .about
           cmp     eax, IDM_EXIT
          je      .wmdestroy
          jmp     .defwndproc

   .new:  invoke  SendMessage,[edithwnd],WM_SETTEXT,0,0
          jmp     .finish
   .open:                       ; Load file to Edit Control

          jmp     .finish
   .svSel:invoke  SendMessage,[edithwnd],EM_GETSEL,0,0
                                ; Write Selected to a File
          jmp     .finish
   .save:                       ; Write Session to a File

          jmp     .finish
   .saveAs:                     ; Write Session to a different File name

          jmp     .finish
   .undo: invoke  SendMessage,[edithwnd],EM_UNDO,0,0
          jmp     .finish
   .find:                       ; Get Search str and try to Find it in text

          jmp     .finish
   .cut:  invoke  SendMessage,[edithwnd],WM_CUT,0,0
          jmp     .finish
   .copy: invoke  SendMessage,[edithwnd],WM_COPY,0,0
          jmp     .finish
   .paste:invoke  SendMessage,[edithwnd],WM_PASTE,0,0
          jmp     .finish
   .del:  invoke  SendMessage,[edithwnd],WM_CLEAR,0,0
          jmp     .finish
  .about: invoke  MessageBox,[parhwnd],_about_text,_about_title,MB_OK
          jmp     .finish
  .wmdestroy:
          invoke  DeleteObject,[editfont]
          invoke  PostQuitMessage,0
  .finish:        ret
endp
EndKern:        ; New compiled functions will be added starting here.
    
Post 07 Aug 2024, 00:37
View user's profile Send private message Reply with quote
Stancliff



Joined: 30 Jun 2024
Posts: 54
Location: Florida
Stancliff 07 Aug 2024, 00:53
revolution wrote:

With regards to the stack. There are some functions of Windows that refuse to use your stack if it isn't in a place that Windows has specifically allocated for use as a stack.. Trying to use your own custom stack in data memory works as far as the CPU is concerned, but problems can occur when Windows sees it isn't in the "right" place.

Also the stack points to the bottom, not the top of R0, so it effectively has a stack size of zero size, clobbering whatever has been allocated below R0.

[/quote]
I am fishing for a compromise but am not certain there is one. We agree on this.

I will go over that again, stack logic can trick me. R0 and S0 are supposed to be top of an empty stack so resetting them clears the stack data by abandoning all the cells that were there. ToR and ToS need new names. They refer to the first cell address right after the stack data and are used to test for overflow.
Post 07 Aug 2024, 00:53
View user's profile Send private message Reply with quote
Stancliff



Joined: 30 Jun 2024
Posts: 54
Location: Florida
Stancliff 07 Aug 2024, 23:54
My new version today is a bit of a step back to MiniPad. It is creating the child and showing output text, but not reading keys. It is quite possible I set that up wrong.
The docs show an alternative path...
"For a multiline edit control in a dialog box, the ES_WANTRETURN style causes the control to insert a carriage return when the user presses the ENTER key while entering text. If this style is not specified, pressing the ENTER key has the same effect as pressing the default push button in the dialog box."
It should be enough for me to capture that button event, but I am not certain what to check for.
Code:
; Simple text editor - fasm example program
format PE GUI 4.0
entry start
include 'win32ax.inc'

macro fPush value               ; Push value to TOS (Top Of Stack)
{  add edx, -4                  ; S - 4, new cell for TOS
   mov [edx], dword value       ; move value to TOS
}
macro Msg label                 ; msg string typed to screen
{  fPush label                  ; Push adr of string to TOS
   call Type                    ; Display string on screen
}
section '.data' data readable writeable
; compute adr's for 2 stacks starting from return stack at enter
; == Return Stack =====
; R:      [ESP]                 ; Return Stack ptr, in ESP
BoR       DD 0                  ; 1 cell past end of R, 64 DD =[esp]-256
R0        DD 0                  ; Ret Stk start, at run = initial [esp]
; == Data Stack ======
; S:      [EDX]                 ; Data Stack ptr, in EDX
BoS:      DD 128 Dup ?          ; 1 cell past end of S Stack
S0:                             ; Data Stack start, allow 128 cells
; I wanted to use EBP for the Data Stack but I hear Windows uses it

; Note: many good names from Forth are reserved by assembler, find alt's
NameSz   EQU 256                 ; max name cnt, increases dictionary size
New^     DD Reserved             ; ptr to next unused rec in Name
N^       DD 0                    ; Name Ptr, index for Name, was DP
TIB      DB 128 Dup " "          ; Term Input Buf adr, 128 b
T^       DD 0                    ; Text Ptr to current source, was IN
Pad      DB 128 Dup " "          ; Pad adr, 128 b
P^       DD Pad                  ; Pad ptr (temp work area)
H^       DD EndKern              ; ptr to current unused cell for code
Fence    DD Reserved -17         ; adr of last protected dictionary word
Base     DD 10                   ; initial value for base conversion

; Start Dictionary with major words of kernal core
; Names have 8 char length w/trailing zeros, no cnt byte for string
; Code Adr = 4 byte, Param Adr = 4 byte, Status = 1 byte (0=IMM,1=Defer)
Name:
DB  "Cold",0,0,0,0
Cold: DB 1
DB  "Abort",0,0,0
Abort: DD Abort,0
 DB 1
DB  "Quit",0,0,0,0
Quit: DD Quit,0
 DB 1
DB  "Query",0,0,0
 DD Query,0
 DB 1
Reserved: DB ((NameSz *17) +Name -Reserved) Dup ?  ; clear Name space
; Forth searches the dictionary to find the address of a command.  My bare
; bones kernal will need close to 60 names.  The Forth standard has almost
; 140 names, and with extensions like floating point, a simple assembler,
; and various data structures this can easily go over 200.


IDR_ICON = 17
IDR_MENU = 37

  ; Menu entries
IDM_FILE   = 100
IDM_NEW    = 110
IDM_OPEN   = 120
IDM_EXIT   = 130
IDM_SVSEL  = 140
IDM_SAVE   = 150
IDM_SAVEAS = 160

IDM_EDIT   = 200
IDM_UNDO   = 210
IDM_FIND   = 220
IDM_CUT    = 230
IDM_COPY   = 240
IDM_PASTE  = 250
IDM_DEL    = 260

IDM_HELP   = 900
IDM_ABOUT  = 910

section '.data' data readable writeable

  _title TCHAR 'MiniPad',0
  _about_title TCHAR 'About MiniPad',0
  _about_text TCHAR 'This is Win32 example program created with flat assembler.',0
  _error TCHAR 'Startup failed.',0

  _class TCHAR 'MINIPAD32',0
  _edit TCHAR 'EDIT',0

  wc WNDCLASS 0,WindowProc,0,0,NULL,NULL,NULL,COLOR_BTNFACE+1,NULL,_class

  edithwnd dd ?
  editfont dd ?
  parhwnd  dd ?
  msg MSG
  client RECT

section '.idata' import data readable writeable

  library kernel,'KERNEL32.DLL',\
          user,'USER32.DLL',\
          gdi,'GDI32.DLL'

  import kernel,\
         GetModuleHandle,'GetModuleHandleA',\
         ExitProcess,'ExitProcess'

  import user,\
         RegisterClass,'RegisterClassA',\
         CreateWindowEx,'CreateWindowExA',\
         DefWindowProc,'DefWindowProcA',\
         SetWindowLong,'SetWindowLongA',\
         RedrawWindow,'RedrawWindow',\
         GetMessage,'GetMessageA',\
         TranslateMessage,'TranslateMessage',\
         DispatchMessage,'DispatchMessageA',\
         SendMessage,'SendMessageA',\
         LoadCursor,'LoadCursorA',\
         LoadIcon,'LoadIconA',\
         LoadMenu,'LoadMenuA',\
         GetClientRect,'GetClientRect',\
         MoveWindow,'MoveWindow',\
         SetFocus,'SetFocus',\
         MessageBox,'MessageBoxA',\
         PostQuitMessage,'PostQuitMessage'

  import gdi,\
         CreateFont,'CreateFontA',\
         DeleteObject,'DeleteObject'

section '.rsrc' resource data readable

  ; resource directory

  directory RT_MENU,menus,\
            RT_ICON,icons,\
            RT_GROUP_ICON,group_icons,\
            RT_VERSION,versions

  ; resource subdirectories

  resource menus,\
           IDR_MENU,LANG_ENGLISH+SUBLANG_DEFAULT,main_menu

  resource icons,\
           1,LANG_NEUTRAL,icon_data

  resource group_icons,\
           IDR_ICON,LANG_NEUTRAL,main_icon

  resource versions,\
           1,LANG_NEUTRAL,version

menu main_menu
    menuitem '&File', IDM_FILE, MFR_POPUP
          menuitem '&New', IDM_NEW
          menuitem '&Open', IDM_OPEN
          menuitem '&Exit', IDM_EXIT
          menuseparator
          menuitem '&SaveSelect', IDM_SVSEL
          menuitem 'Sa&ve', IDM_SAVE
          menuitem 'Save &As', IDM_SAVEAS, MFR_END
    menuitem '&Edit', IDM_EDIT, MFR_POPUP
          menuitem '&Undo', IDM_UNDO
          menuitem '&Find', IDM_FIND
          menuseparator
          menuitem '&Cut', IDM_CUT
          menuitem 'C&opy', IDM_COPY
          menuitem '&Paste', IDM_PASTE
          menuitem '&Delete', IDM_DEL, MFR_END
    menuitem '&Help',IDM_HELP, MFR_POPUP + MFR_END ; LAST POPUP - MFR_END"
          menuitem '&About', IDM_ABOUT, MFR_END

 icon main_icon,icon_data,'minipad.ico'

  versioninfo version,VOS__WINDOWS32,VFT_APP,VFT2_UNKNOWN,LANG_ENGLISH+SUBLANG_DEFAULT,0,\
              'FileDescription','MiniPad - example program',\
              'LegalCopyright','No rights reserved.',\
              'FileVersion','1.0',\
              'ProductVersion','1.0',\
              'OriginalFilename','MINIPAD.EXE'

section '.text' code readable executable

  start:

        invoke  GetModuleHandle,0
        mov     [wc.hInstance],eax

        invoke  LoadIcon,eax,IDR_ICON
        mov     [wc.hIcon],eax
        invoke  LoadCursor,0,IDC_ARROW
        mov     [wc.hCursor],eax
        invoke  RegisterClass,wc
        test    eax,eax
        jz      error

        invoke  LoadMenu,[wc.hInstance],IDR_MENU
        invoke  CreateWindowEx,0,_class,_title,WS_OVERLAPPEDWINDOW+\
        WS_VISIBLE,100,200,900,600,NULL,eax,[wc.hInstance],NULL
        test    eax,eax
        jz      error

  msg_loop:
        invoke  GetMessage,msg,NULL,0,0
        cmp     eax,1
        jb      end_loop
        jne     msg_loop
        invoke  TranslateMessage,msg
        invoke  DispatchMessage,msg
        jmp     msg_loop

  error:
        invoke  MessageBox,NULL,_error,NULL,MB_ICONERROR+MB_OK

  end_loop:
;          Pop     edi
;          Pop     esi
;          Pop     edx
;          Pop     ecx
;          Pop     ebx
          invoke  ExitProcess,[msg.wParam]

; Add most new code here

; Query:  Move a null terminated string into Terminal Input Buffer
Query:    mov     [TIB], 123              ; set input limit
          invoke  SendMessage,[edithwnd],EM_GETLINECOUNT,0,0
          invoke  SendMessage,[edithwnd],EM_GETLINE,eax,dword[TIB]
          mov     [TIB +eax],0            ; add null to string
          invoke  SendMessage,[edithwnd],EM_REPLACESEL,0,NewLine
; Test results - Write input line back out
          invoke  SendMessage,[edithwnd],EM_SETSEL,-1,-1
          invoke  SendMessage,[edithwnd],EM_REPLACESEL,0,dword[TIB]

Banner:   DB "Go4th: The Windows Forth Compiler",13,10,0
MyFont:   DB "Courier New"
NewLine:  DB 13,10,0
Prompt:   DB "4th?",0
proc WindowProc hwnd,wmsg,wparam,lparam
        push    ebx esi edi
        mov     eax,[wmsg]
        cmp     eax,WM_CREATE
        je      .wmcreate
        cmp     eax,WM_SIZE
        je      .wmsize
        cmp     eax,WM_SETFOCUS
        je      .wmsetfocus
        cmp     eax,WM_CHAR
        je      .wmchar
        cmp     eax,WM_COMMAND
        je      .wmcommand
        cmp     eax,WM_DESTROY
        je      .wmdestroy
  .defwndproc:
        invoke  DefWindowProc,[hwnd],[wmsg],[wparam],[lparam]
        jmp     .finish
  .wmcreate:
        invoke  GetClientRect,[hwnd],client
        invoke  CreateWindowEx,0,_edit,0,WS_VISIBLE+\
        WS_CHILD+WS_HSCROLL+WS_VSCROLL+ES_AUTOHSCROLL+ES_AUTOVSCROLL+\
        ES_MULTILINE+ES_WANTRETURN,[client.left],[client.top],\
        [client.right],[client.bottom],[hwnd],0,[wc.hInstance],NULL
;       WS_EX_CLIENTEDGE
        or      eax,eax
        jz      .finish
        mov     [edithwnd],eax
        invoke  CreateFont,16,0,0,0,0,FALSE,FALSE,FALSE,ANSI_CHARSET,\
        OUT_RASTER_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,\
        FIXED_PITCH+FF_DONTCARE,NULL
        or      eax,eax
        jz      .finish
        mov     [editfont],eax
        invoke  SendMessage,[edithwnd],WM_SETFONT,eax,FALSE
          invoke  SendMessage,[edithwnd],EM_SETSEL,-1,-1
          invoke  SendMessage,[edithwnd],EM_REPLACESEL,0,Banner
          invoke  SendMessage,[edithwnd],EM_SETSEL,-1,-1
          invoke  SendMessage,[edithwnd],EM_REPLACESEL,0,Prompt
        jmp     .finish
  .wmsize:
        invoke  GetClientRect,[hwnd],client
        invoke  MoveWindow,[edithwnd],[client.left],[client.top],\
        [client.right],[client.bottom],TRUE
        jmp     .finish
  .wmsetfocus:
        invoke  SetFocus,[edithwnd]
        jmp     .finish
  .wmchar:
          invoke  SendMessage,[edithwnd],WM_CHAR,ebx,ecx
          cmp     ebx,VK_RETURN
          jne     .defwndproc
invoke  MessageBox,[parhwnd],"CR found",0,MB_OK
          call    Query                  ; return a null terminated string
;          call    Interpret             ; parse and execute commands
          jmp     .defwndproc
  .wmcommand:
          mov     eax,[wparam]
          and     eax,0FFFFh
          cmp     eax, IDM_NEW
          je      .new
          cmp     eax, IDM_OPEN
          je      .open
          cmp     eax, IDM_SVSEL
          je      .svSel
          cmp     eax, IDM_SAVE
          je      .save
          cmp     eax, IDM_SAVEAS
          je      .saveAs
          cmp     eax, IDM_UNDO
          je      .undo
          cmp     eax, IDM_FIND
          je      .find
          cmp     eax, IDM_CUT
          je      .cut
          cmp     eax, IDM_COPY
          je      .copy
          cmp     eax, IDM_PASTE
          je      .paste
          cmp     eax, IDM_DEL
          je      .del
          cmp     eax, IDM_ABOUT
          je      .about
           cmp     eax, IDM_EXIT
          je      .wmdestroy
          jmp     .defwndproc

   .new:  invoke  SendMessage,[edithwnd],WM_SETTEXT,0,0
          jmp     .finish
   .open:                       ; Load file to Edit Control

          jmp     .finish
   .svSel:                      ; Write Selected to a File
          invoke  SendMessage,[edithwnd],EM_GETSEL,0,0

          jmp     .finish
   .save:                       ; Write Session to a File

          jmp     .finish
   .saveAs:                     ; Write Session to a different File name

          jmp     .finish
   .undo: invoke  SendMessage,[edithwnd],EM_UNDO,0,0
          jmp     .finish
   .find:                       ; Get Search str and try to Find it in text

          jmp     .finish
   .cut:  invoke  SendMessage,[edithwnd],WM_CUT,0,0
          jmp     .finish
   .copy: invoke  SendMessage,[edithwnd],WM_COPY,0,0
          jmp     .finish
   .paste:invoke  SendMessage,[edithwnd],WM_PASTE,0,0
          jmp     .finish
   .del:  invoke  SendMessage,[edithwnd],WM_CLEAR,0,0
          jmp     .finish
  .about: invoke  MessageBox,[parhwnd],_about_text,_about_title,MB_OK
          jmp     .finish
  .wmdestroy:
          invoke  DeleteObject,[editfont]
          invoke  PostQuitMessage,0
  .finish:        ret
endp
EndKern:        ; New compiled functions will be added starting here.
    
Post 07 Aug 2024, 23:54
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1628
Location: Toronto, Canada
AsmGuru62 08 Aug 2024, 21:24
So, I am back from a small delay --- work...
There is an issue with WM_CHAR which I have missed in my post.
The WM_CHAR will come to the window, which is focused and that is the child window -- the multi-line edit control.
Currently, the case for WM_CHAR is inside the main window procedure, which is not in focus.

However, you cannot add this case into the window procedure for an edit control, because this code is inside Windows OS library.
You need something called "sub-classing the window" to do this "catching" of <ENTER> key.
Another complication.

I visited the "Forth" resources and they seem clear.
I still think, that it would be much easier to separate your commands from the multi-line log of whatever is going on.
Once command is entered -- it can be put into log, so it would look like a conversation of a user with a compiler.
As I said, I can make a prototype, and I am not asking for anything, the code I write is free to use, earn money... whatever.

Or, and the stack, hmm... I think ESP is better to be left alone.
"Forth" has its own stack engine, which can be done without ESP.
Post 08 Aug 2024, 21:24
View user's profile Send private message Send e-mail Reply with quote
Stancliff



Joined: 30 Jun 2024
Posts: 54
Location: Florida
Stancliff 08 Aug 2024, 22:19
Thank you AsmGuru, I appreciate the explanation! I never would have guessed, though some of my attempts today support your info if I had been able to interpreted it right. Even then I wouldn't know what to do.

One more thing to try before I go to the separate input line... did you see my quote from the docs? If you can capture the button press from the edit control when Enter is pressed without ES_WANTRETURN in child definition I don't need to capture the Return at all. Just knowing Return was hit is enough to go ahead and capture the line of text.

My current file has been well behaved all day with no significant lockups. The disk access and search functions can wait a little while as long as I can get a command line input. Let me know anything that will help with this.
Post 08 Aug 2024, 22:19
View user's profile Send private message Reply with quote
Stancliff



Joined: 30 Jun 2024
Posts: 54
Location: Florida
Stancliff 08 Aug 2024, 22:51
Quote:

Or, and the stack, hmm... I think ESP is better to be left alone.
"Forth" has its own stack engine, which can be done without ESP.

Forth uses two stacks, R and S, and historically R is the ESP return stack. That was a little before Windows. It is barely possible for me to use two registers to set up two stacks for Forth without using ESP, though I really need all the registers at one point or another so that would leave me short by one. This is assuming I can't ever use EBP. My understanding is that Windows uses it as a base address for memory management. This might be an interesting challenge and would keep my Forth stacks from interfering with Windows at all. Down side is it would slow the execution slightly, but not by much. When you have 3.5 billion clocks per second you don't really notice giving up 2% or so. Honestly I am not certain if I can program function calls without the hardware stack. that would force me to micro-manage all functions all the time. I believe that Windows and I won't clash over ESP as long as I don't try to reset the stack after an error. When my code is running, msg_loop will be locked. Only the OS will be running and it is interrupt driven.
Post 08 Aug 2024, 22:51
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1628
Location: Toronto, Canada
AsmGuru62 09 Aug 2024, 18:52
I think you can use a model of a stack as a structure and leave ESP for your program and Windows to use.
Something of that nature below:

Code:
; ---------------------------------------------------------------------------
; FILE: ModelOfStack.Inc
; DATE: August 9, 2024
; ---------------------------------------------------------------------------
;
; |<----------- ALLOCATE A MEMORY BLOCK ----------->|
; +================+================================+
; |                | DWORD |                        |
; +================+================================+
; |<-- BOTTOM      |<-- TOP                         |<-- MAXIMUM
;                  |
;           POP <--|--> PUSH
; ---------------------------------------------------------------------------

struct StackModel
    TopAddress      dd ?
    BottomAddress   dd ?
    MaximumAddress  dd ?
ends
    

And then some methods (like C++) for STACK management:
Code:
; ---------------------------------------------------------------------------
; FILE: ModelOfStack.Asm
; DATE: August 9, 2024
; ---------------------------------------------------------------------------
align 16
proc ModelOfStack_Create uses eax ecx edx esi, stacksize:DWORD
; ---------------------------------------------------------------------------
; Input:
;   ebx = pointer to StackModel object
; ---------------------------------------------------------------------------
    invoke  GetProcessHeap

    mov     esi, [stacksize]
    invoke  HeapAlloc, eax, 0, esi

    mov     [ebx + StackModel.BottomAddress], eax
    mov     [ebx + StackModel.TopAddress], eax

    add     eax, esi
    mov     [ebx + StackModel.MaximumAddress], eax
    ret
endp

align 16
proc ModelOfStack_Push uses eax edi, value:DWORD
; ---------------------------------------------------------------------------
; Input:
;   ebx = pointer to StackModel object
; ---------------------------------------------------------------------------
    mov     edi, [ebx + StackModel.TopAddress]

    .if (edi < [ebx + StackModel.MaximumAddress])
        mov     eax, [value]
        stosd
        mov     [ebx + StackModel.TopAddress], edi
    .else
        int3        ; OVERFLOW!
    .endif

    ret
endp

align 16
proc ModelOfStack_Pop uses edi
; ---------------------------------------------------------------------------
; Input:
;   ebx = pointer to StackModel object
; Output:
;   eax = popped value
; ---------------------------------------------------------------------------
    mov     edi, [ebx + StackModel.TopAddress]

    .if (edi > [ebx + StackModel.BottomAddress])
        sub     edi, 4
        mov     [ebx + StackModel.TopAddress], edi
        mov     eax, [edi]
    .else
        int3        ; STACK IS EMPTY!
    .endif

    ret
endp

align 16
proc ModelOfStack_Destroy uses eax ecx edx
; ---------------------------------------------------------------------------
; Input:
;   ebx = pointer to StackModel object
; ---------------------------------------------------------------------------
    invoke  GetProcessHeap

    mov     ecx, [ebx + StackModel.BottomAddress]
    invoke  HeapFree, eax, 0, ecx
    ret
endp
    

And that is how this structure is used (ESP is not involved):
Code:
; ---------------------------------------------------------------------------
; DATE: August 9, 2024
; ---------------------------------------------------------------------------

format  PE GUI 4.0
entry   start
stack   4000h, 4000h

    include 'Win32W.Inc'
    include 'Macros.Inc'
    include 'Macro\If.Inc'
    include 'ModelOfStack.Inc'
    ; {INSMODDEF} Module Definitions inserted immediately before this line

; ---------------------------------------------------------------------------
section '.data' data readable writeable

    Stack1  StackModel
    Stack2  StackModel

; ---------------------------------------------------------------------------
section '.code' code readable executable

    include 'ModelOfStack.Asm'
    ; {INSMODIMPL} Module Implementations inserted immediately before this line

; ---------------------------------------------------------------------------
; PROGRAM ENTRY POINT
; ---------------------------------------------------------------------------
align 16
start:
    ;
    ; Make two stack objects
    ;
    mov     ebx, Stack1
    stdcall ModelOfStack_Create, 0x100000   ; 1Mb for STK1

    mov     ebx, Stack2
    stdcall ModelOfStack_Create, 0x10000    ; 64Kb for STK2
    ;
    ; Now, play around with these objects.
    ; And, yes, you have to load EBX with proper address,
    ; but that is how C++ does it also.
    ;
    mov     esi, Stack2     ; for the loop below

    mov     ebx, Stack1
    stdcall ModelOfStack_Push, 'F'
    stdcall ModelOfStack_Push, 'O'
    stdcall ModelOfStack_Push, 'R'
    stdcall ModelOfStack_Push, 'T'
    stdcall ModelOfStack_Push, 'H'
    ;
    ; POP will reverse the text
    ;
    mov     ecx, 5

    .repeat
        call    ModelOfStack_Pop
        ;
        ; Check EAX here in debugger: --> H,T,R,O,F
        ;

        ;
        ; Push that EAX result into stack #2
        ;
        push    ebx
        mov     ebx, esi  ; ESI --> Stack2
        stdcall ModelOfStack_Push, eax
        pop     ebx

        dec     ecx
    .until (ZERO?)
    ;
    ; Dispose of both objects
    ;
    mov     ebx, Stack2
    call    ModelOfStack_Destroy

    mov     ebx, Stack1
    call    ModelOfStack_Destroy

    invoke  ExitProcess, 0

; ---------------------------------------------------------------------------
section '.idata' import data readable writeable

    library kernel32,'KERNEL32.DLL',user32,'USER32.DLL',gdi32,'GDI32.DLL'

    include 'API\Kernel32.Inc'
    include 'API\User32.Inc'
    include 'API\Gdi32.Inc'
    
Post 09 Aug 2024, 18:52
View user's profile Send private message Send e-mail Reply with quote
Stancliff



Joined: 30 Jun 2024
Posts: 54
Location: Florida
Stancliff 09 Aug 2024, 23:18
I have had the Data stack implemented in my assembly code for a few months. I use it to hold parameters for function calls since that is it's intended purpose. I can't really test without command lines.
You can help me by identifying the response of the edit control that is triggered by 'Enter' when the child is not created with the WANTSRETURN flag.
I quoted the online docs two or three posts back and it looks very promising but there is no example and they don't name the event.

If that is nearly as hard as capturing the Return key then you can go ahead with your suggestion to put an input line box under the edit control. This isn't what I pictured but it's a very decent idea and I agree it should be simple. It should be positioned to stay at the bottom of the window even when maximized. I saw references to objects in a window being positioned by percents, not pixels.

If you can help me get past this issue I can start importing functions and trying to send them data for testing. Everything I wrote needs to be reviewed in relation to the Windows interface. A lot of it will have no impact. My next goal is to import all functions for the minimal kernel one at a time.

I need to read up on I/O of files.
Post 09 Aug 2024, 23:18
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1628
Location: Toronto, Canada
AsmGuru62 10 Aug 2024, 03:35
Find the procedure 'SubClassEditor' --- it does what you need.
Code:
; Simple text editor - fasm example program
format PE GUI 4.0
entry start
include 'win32ax.inc'

macro fPush value               ; Push value to TOS (Top Of Stack)
{  add edx, -4                  ; S - 4, new cell for TOS
   mov [edx], dword value       ; move value to TOS
}
macro Msg label                 ; msg string typed to screen
{  fPush label                  ; Push adr of string to TOS
   call Type                    ; Display string on screen
}
section '.data' data readable writeable
; compute adr's for 2 stacks starting from return stack at enter
; == Return Stack =====
; R:      [ESP]                 ; Return Stack ptr, in ESP
R0        DD 0                  ; Ret Stk End, at run = initial [esp]
ToR       DD 0                  ; 1 cell above Top of R, at run =[esp]+64
; == Data Stack ======
; S:      [EDX]                 ; Data Stack ptr, in EDX
S0:       DD 128 Dup ?          ; Data Stack End, 128 cells
ToS:                            ; 1 cell above Top of S Stack
; I wanted to use EBP for the Data Stack but I hear Windows uses it

; Note: many good names from Forth are reserved by assembler, find alt's
NameSz   EQU 256                 ; max name cnt, increases dictionary size
New^     DD Reserved             ; ptr to next unused rec in Name
N^       DD 0                    ; Name Ptr, index for Name, was DP
TIB      DB 128 Dup " "          ; Term Input Buf adr, 128 b
;T^       DD 0                    ; Text Ptr to current source, was IN
;Pad      DB 128 Dup " "          ; Pad adr, 128 b
;P^       DD Pad                  ; Pad ptr (temp work area)
;H^       DD EndKern              ; ptr to current unused cell for code
;Fence    DD Reserved -17         ; adr of last protected dictionary word

; Start Dictionary with major words of kernal core
; Names have 8 char length w/trailing zeros, no cnt byte for string
; Code Adr = 4 byte, Param Adr = 4 byte, Status = 1 byte (0=IMM,1=Defer)
Name:
DB  "Cold",0,0,0,0
 DD Cold,0
 DB 1
DB  "Abort",0,0,0
 DD Abort,0
 DB 1
DB  "Quit",0,0,0,0
 DD Quit,0
 DB 1
DB  "Query",0,0,0
 DD Query,0
 DB 1
Reserved: DB ((NameSz *17) +Name -Reserved) Dup ?  ; clear Name space
; Forth searches the dictionary to find the address of a command.  My bare
; bones kernal will need close to 60 names.  The Forth standard has almost
; 140 names, and with extensions like floating point, a simple assembler,
; and various data structures this can easily go over 200.

; Windows assignments
  _class       TCHAR 'Go4th',0
  _title       TCHAR 'Go4th32',0
  _about_title TCHAR 'About Go4th32',0
  _about_text  TCHAR 'Windows based Forth Compiler',13,10,\
                     'Created with FLAT assembler.',0
  _edit        TCHAR 'EDIT',0
  _error       TCHAR 'Startup failed.',0
  _fontface    TCHAR 'Courier New',0

client        RECT               ; window box sides
ClsAtom       dd ?
editfont      dd ?
edithwnd      dd ?
hmenu         dd ?
hwnd          dd ?  ; <---------
WinOSEditProc dd ?
msg           MSG                ; message struct for Windows

IDR_ICON   =  17
IDR_MENU   =  37
  ; Menu items
IDM_FILE   = 100
IDM_NEW    = 110
IDM_OPEN   = 120
IDM_EXIT   = 130
IDM_SVSEL  = 140
IDM_SAVE   = 150
IDM_SAVEAS = 160

IDM_EDIT   = 200
IDM_UNDO   = 210
IDM_FIND   = 220
IDM_CUT    = 230
IDM_COPY   = 240
IDM_PASTE  = 250
IDM_DEL    = 260

IDM_HELP   = 900
IDM_ABOUT  = 910

wc WNDCLASS 0,WindowProc,0,0,0,0,0,COLOR_BTNFACE+1,0,_class

Banner:   DB "Go4th: The Windows Forth Compiler",13,10,0
NewLine:  DB 13,10,0
Prompt:   DB "4th?",0

section '.idata' import data readable writeable
   library    advapi32,          'ADVAPI32.DLL',\
              comctl32,          'CONCTL32.DLL',\
              comdlg32,          'COMDLG32.DLL',\
              gdi32,             'GDI32.DLL',\
              kernel32,          'KERNEL32.DLL',\
              shell32,           'SHELL32.DLL',\
              user32,            'USER32.DLL',\
              wsock32,           'WSOCK32.DLL'
   include    'api\advapi32.inc'
   include    'api\comctl32.inc'
   include    'api\comdlg32.inc'
   include    'api\gdi32.inc'
   include    'api\kernel32.inc'
   include    'api\shell32.inc'
   include    'api\user32.inc'
   include    'api\wsock32.inc'

section '.rsrc' resource data readable
directory     RT_MENU, menus,  RT_VERSION, versions,  RT_ICON, icons,\
              RT_GROUP_ICON, group_icons

resource  menus,       IDR_MENU, LANG_ENGLISH +SUBLANG_DEFAULT, main_menu
resource  versions,    1, LANG_NEUTRAL, version
resource  group_icons, IDR_ICON, LANG_NEUTRAL, main_icon
resource  icons,       1, LANG_NEUTRAL, icon_data

  versioninfo  version, VOS__WINDOWS32, VFT_APP, VFT2_UNKNOWN,\
          LANG_ENGLISH +SUBLANG_DEFAULT, 0,\
          'FileDescription', 'MiniPad - example program',\
          'LegalCopyright', 'No rights reserved.',\
          'FileVersion', '1.0',\
          'ProductVersion', '1.0',\
          'OriginalFilename', 'MINIPAD.EXE'
  icon    main_icon, icon_data, 'Go4th.ico'

menu main_menu
    menuitem '&File',IDM_FILE, MFR_POPUP
          menuitem '&New',IDM_NEW
          menuitem '&Open',IDM_OPEN
          menuitem 'E&xit',IDM_EXIT
          menuseparator
          menuitem '&SvSelect',IDM_SVSEL
          menuitem 'Sa&ve',IDM_SAVE
          menuitem 'Save &As',IDM_SAVEAS, MFR_END
    menuitem '&Edit',IDM_EDIT, MFR_POPUP
          menuitem '&Undo',IDM_UNDO
          menuitem '&Find',IDM_FIND
          menuseparator
          menuitem '&Cut',IDM_CUT
          menuitem 'Co&py',IDM_COPY
          menuitem '&Paste',IDM_PASTE
          menuitem '&Delete',IDM_DEL, MFR_END
    menuitem '&Help',IDM_HELP, MFR_POPUP + MFR_END ; LAST POPUP - MFR_END"
          menuitem '&About', IDM_ABOUT, MFR_END

section '.code' code readable executable writeable
start:    PushAD
          mov     [R0],esp      ; set old stack point to new stack start
          mov     [ToR],esp
          add     [ToR],256     ; allow 64 cells for local stack

          invoke  GetModuleHandle,0
          mov     [wc.hInstance],eax
          invoke  LoadIcon,[wc.hInstance],IDR_ICON
          mov     [wc.hIcon],eax
          invoke  LoadCursor,0,IDC_ARROW
          mov     [wc.hCursor],eax
          invoke  LoadMenu,[wc.hInstance],IDR_MENU
          mov     [hmenu],eax
          invoke  RegisterClass,wc
          mov     [ClsAtom],eax
          invoke  CreateWindowEx,0,_class,_title,WS_TILEDWINDOW+\
                  WS_VISIBLE,200,100,900,600,0,[hmenu],[wc.hInstance],0

msg_loop: invoke  GetMessage,msg,0,0,0
          cmp     eax,0
          je      end_loop
;          je      msg_loop
          invoke  TranslateMessage,msg
          invoke  DispatchMessage,msg
          jmp     msg_loop
error:    invoke  MessageBox,NULL,_error,NULL,MB_ICONERROR+MB_OK
end_loop: invoke  ExitProcess,[msg.wParam]
          PopAD

; Add most new code here

; Cold:  full restart, reset bufs, reset N^ and New^, call Abort
Cold:     mov     eax, [Name]
          mov     [N^], eax
;          mov     eax, [Fence +17]
          mov     [New^], eax

; Abort:  reset data stack, set base, print banner, call Quit
Abort:    mov  edx, S0          ; clear data stack S
;          mov  [Base], 10

; Quit:  set term input, reset return stack, query & interp, print prompt
Quit:     mov  esp, R0          ; Begin: clear return stk R
          ret

; Query:  Move a null terminated string into Terminal Input Buffer
Query:    mov     [TIB], 123              ; set input limit
          invoke  SendMessage,[edithwnd],EM_GETLINECOUNT,0,0
          invoke  SendMessage,[edithwnd],EM_GETLINE,eax,dword[TIB]
          mov     [TIB +eax],0            ; add null to string
          invoke  SendMessage,[edithwnd],EM_REPLACESEL,0,NewLine
; Test results - Write input line back out
          invoke  SendMessage,[edithwnd],EM_SETSEL,-1,-1
          invoke  SendMessage,[edithwnd],EM_REPLACESEL,0,dword[TIB]

proc WindowProc hwndproc,wmsg,wparam,lparam
          mov     eax,[wmsg]
          cmp     eax,WM_CREATE
          je      .wmcreate
          cmp     eax,WM_SIZE
          je      .wmsize
          cmp     eax,WM_SETFOCUS
          je      .wmsetfocus
          cmp     eax,WM_CHAR
          je      .wmchar
          cmp     eax,WM_COMMAND
          je      .wmcommand
          cmp     eax,WM_DESTROY
          je      .wmdestroy
  .defwndproc:
          invoke  DefWindowProc,[hwndproc],[wmsg],[wparam],[lparam]
          ret
  .wmcreate:
          mov     eax,[hwndproc]
          mov     [hwnd],eax
          invoke  GetClientRect,[hwnd],client
          invoke  CreateWindowEx,WS_EX_CLIENTEDGE,_edit,0,WS_VISIBLE+\
          WS_CHILD+WS_HSCROLL+WS_VSCROLL+ES_AUTOHSCROLL+ES_AUTOVSCROLL+\
          ES_MULTILINE+ES_WANTRETURN,[client.left],[client.top],\
          [client.right],[client.bottom],[hwnd],0,[wc.hInstance],NULL
          mov     [edithwnd],eax
          cmp     eax,0
          je      .failed
          call    SubClassEditor
          invoke  CreateFont,16,0,0,0,0,FALSE,FALSE,FALSE,ANSI_CHARSET,\
          OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,\
          FIXED_PITCH+FF_MODERN,_fontface
          mov     [editfont],eax
          cmp     eax,0
          je      error
          invoke  SendMessage,[edithwnd],WM_SETFONT,eax,FALSE
          invoke  SendMessage,[edithwnd],EM_SETSEL,-1,-1
          invoke  SendMessage,[edithwnd],EM_REPLACESEL,0,Banner
          invoke  SendMessage,[edithwnd],EM_SETSEL,-1,-1
          invoke  SendMessage,[edithwnd],EM_REPLACESEL,0,Prompt
;          call    Cold         ; Initialize compiler
;          Msg     Banner
;          Msg     Prompt
          jmp     .finish
  .failed:
          or      eax,-1
          ret
  .wmsize:
          invoke  GetClientRect,[hwnd],client
          invoke  MoveWindow,[edithwnd],[client.left],[client.top],\
          [client.right],[client.bottom],TRUE
          jmp     .finish
  .wmsetfocus:
          invoke  SetFocus,[edithwnd]
          jmp     .finish
;  .wmchar:
;          invoke  SendMessage,[edithwnd],WM_CHAR,ebx,ecx
;          cmp     ebx,VK_RETURN
;          jne     .defwndproc
;          call    Query                  ; return a null terminated string
;          call    Interpret             ; parse and execute commands
;          jmp     .defwndproc
  .wmcommand:
          mov     eax,[wparam]
          and     eax,0FFFFh
          cmp     eax, IDM_NEW
          je      .new
          cmp     eax, IDM_OPEN
          je      .open
          cmp     eax, IDM_SVSEL
          je      .svSel
          cmp     eax, IDM_SAVE
          je      .save
          cmp     eax, IDM_SAVEAS
          je      .saveAs
          cmp     eax, IDM_UNDO
          je      .undo
          cmp     eax, IDM_FIND
          je      .find
          cmp     eax, IDM_CUT
          je      .cut
          cmp     eax, IDM_COPY
          je      .copy
          cmp     eax, IDM_PASTE
          je      .paste
          cmp     eax, IDM_DEL
          je      .del
          cmp     eax, IDM_ABOUT
          je      .about
           cmp     eax, IDM_EXIT
          je      .wmdestroy
          jmp     .defwndproc

   .new:  invoke  SendMessage,[edithwnd],WM_SETTEXT,0,0
          jmp     .finish
   .open:                       ; Load file to Edit Control

          jmp     .finish
   .svSel:invoke  SendMessage,[edithwnd],EM_GETSEL,0,0
                                ; Write Selected to a File
          jmp     .finish
   .save:                       ; Write Session to a File

          jmp     .finish
   .saveAs:                     ; Write Session to a different File name

          jmp     .finish
   .undo: invoke  SendMessage,[edithwnd],EM_UNDO,0,0
          jmp     .finish
   .find:                       ; Get Search str and try to Find it in text

          jmp     .finish
   .cut:  invoke  SendMessage,[edithwnd],WM_CUT,0,0
          jmp     .finish
   .copy: invoke  SendMessage,[edithwnd],WM_COPY,0,0
          jmp     .finish
   .paste:invoke  SendMessage,[edithwnd],WM_PASTE,0,0
          jmp     .finish
   .del:  invoke  SendMessage,[edithwnd],WM_CLEAR,0,0
          jmp     .finish
  .about: invoke  MessageBox,[hwnd],_about_text,_about_title,MB_OK
          jmp     .finish
  .wmdestroy:
          invoke  DeleteObject,[editfont]
          PopAD
          invoke  PostQuitMessage,0
  .finish:
          xor     eax,eax
          ret
endp

proc EditorWndProc uses ebx esi edi, hEditWnd,winmsg,wparam,lparam
    ;
    ; All messages for 'EDIT' control now are coming into this function.
    ; First call the original procedure to do what 'EDIT' does.
    ;
    invoke  CallWindowProc, [WinOSEditProc], [hEditWnd], [winmsg], [wparam], [lparam]
    ;
    ; After 'EDIT' did its job, check if that was WM_CHAR message
    ;
    cmp     [winmsg], WM_CHAR
    jne     .exit
    ;
    ; It was WM_CHAR, now check if it was [ENTER]
    ;
    cmp     [wparam], VK_RETURN
    jne     .exit
    ;
    ; At this point we know that [ENTER] was pressed
    ;
    push    eax         ; Need to preserve EAX.
                        ; It has a return value from original procedure
    call    KeyEnterPressed
    pop     eax

.exit:
    ret
endp

proc KeyEnterPressed
    ;
    ; Use [edithwnd] to get the last line in the control...
    ;

    ret
endp

proc SubClassEditor
    ;
    ; Replace the 'EDIT' control procedure with your own to intercept messages
    ;
    invoke  SetWindowLong, [edithwnd], GWL_WNDPROC, EditorWndProc
    ;
    ; Old (Windows 'EDIT') procedure address returns back, so save it.
    ; It will be used in our 'EditorWndProc'
    ;
    mov     [WinOSEditProc], eax
    ret
endp
    
Post 10 Aug 2024, 03:35
View user's profile Send private message Send e-mail Reply with quote
Stancliff



Joined: 30 Jun 2024
Posts: 54
Location: Florida
Stancliff 10 Aug 2024, 17:43
Hmm, read my last message again, I had opted not to sub-class.
Post 10 Aug 2024, 17:43
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1628
Location: Toronto, Canada
AsmGuru62 10 Aug 2024, 21:27
I just tried in debugger, the ENTER is not signaled without the sub-classing.
I tried with ES_WANTRETURN and without it.

It is possible that if the main window was a dialog, then maybe this trick would have worked.
What is even more puzzling is that ES_WANTRETURN does not affect anything in Multi-Line control.
Lines are still scrolled up when ENTER is clicked.
And if you send text to control with 13,10 --- the lines are separated as specified.

Weird, why then invent a style ES_WANTRETURN?
Post 10 Aug 2024, 21:27
View user's profile Send private message Send e-mail Reply with quote
Stancliff



Joined: 30 Jun 2024
Posts: 54
Location: Florida
Stancliff 10 Aug 2024, 21:46
Very odd. Better to go to the separate one line box for command input.
I never got this to run, I may have made one change too many.
Code:
  .wmcreate:
          mov     eax,[hwndproc]
          mov     [parhwnd],eax
          invoke  GetClientRect,[parhwnd],client
          invoke  CreateWindowEx,WS_EX_CLIENTEDGE,_edit,0,WS_VISIBLE+\
          WS_CHILD+WS_HSCROLL+WS_VSCROLL+ES_AUTOHSCROLL+ES_AUTOVSCROLL+\
          ES_MULTILINE+ES_WANTRETURN,[client.left],[client.top],\
          [client.right],[client.bottom],[parhwnd],0,[wc.hInstance],NULL
          mov     [edithwnd],eax
          cmp     eax,0
          je      .failed
          call    SubClassEditor

          invoke  CreateFont,16,0,0,0,0,FALSE,FALSE,FALSE,ANSI_CHARSET,\
          OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,\
          FIXED_PITCH+FF_MODERN,_myfont
          mov     [editfont],eax
          cmp     eax,0
          je      error
          invoke  SendMessage,[edithwnd],WM_SETFONT,eax,FALSE
          invoke  SendMessage,[edithwnd],EM_SETSEL,-1,-1
          invoke  SendMessage,[edithwnd],EM_REPLACESEL,0,Banner
          invoke  SendMessage,[edithwnd],EM_SETSEL,-1,-1
          invoke  SendMessage,[edithwnd],EM_REPLACESEL,0,Prompt
;          Msg     Banner
;          Msg     Prompt
          jmp     .finish
  .failed:
          or      eax,-1
          ret
  .wmsize:
          invoke  GetClientRect,[parhwnd],client
          invoke  MoveWindow,[edithwnd],[client.left],[client.top],\
          [client.right],[client.bottom],TRUE
          jmp     .finish
  .wmsetfocus:
          invoke  SetFocus,[edithwnd]
          jmp     .finish
  .wmcommand:
          mov     eax,[wparam]
          and     eax,0FFFFh
          cmp     eax, IDM_NEW
          je      .new
          cmp     eax, IDM_OPEN
          je      .open
          cmp     eax, IDM_SVSEL
          je      .svSel
          cmp     eax, IDM_SAVE
          je      .save
          cmp     eax, IDM_SAVEAS
          je      .saveAs
          cmp     eax, IDM_UNDO
          je      .undo
          cmp     eax, IDM_FIND
          je      .find
          cmp     eax, IDM_CUT
          je      .cut
          cmp     eax, IDM_COPY
          je      .copy
          cmp     eax, IDM_PASTE
          je      .paste
          cmp     eax, IDM_DEL
          je      .del
          cmp     eax, IDM_ABOUT
          je      .about
           cmp     eax, IDM_EXIT
          je      .wmdestroy
          jmp     .defwndproc

   .new:  invoke  SendMessage,[edithwnd],WM_SETTEXT,0,0
          jmp     .finish
   .open:                       ; Load file to Edit Control

          jmp     .finish
   .svSel:invoke  SendMessage,[edithwnd],EM_GETSEL,0,0
                                ; Write Selected to a File
          jmp     .finish
   .save:                       ; Write Session to a File

          jmp     .finish
   .saveAs:                     ; Write Session to a different File name

          jmp     .finish
   .undo: invoke  SendMessage,[edithwnd],EM_UNDO,0,0
          jmp     .finish
   .find:                       ; Get Search str and try to Find it in text

          jmp     .finish
   .cut:  invoke  SendMessage,[edithwnd],WM_CUT,0,0
          jmp     .finish
   .copy: invoke  SendMessage,[edithwnd],WM_COPY,0,0
          jmp     .finish
   .paste:invoke  SendMessage,[edithwnd],WM_PASTE,0,0
          jmp     .finish
   .del:  invoke  SendMessage,[edithwnd],WM_CLEAR,0,0
          jmp     .finish
  .about: invoke  MessageBox,[parhwnd],_about_text,_about_title,MB_OK
          jmp     .finish
  .wmdestroy:
          invoke  DeleteObject,[editfont]
          PopAD
          invoke  PostQuitMessage,0
  .finish:
          xor     eax,eax
          ret
endp

proc SubClassEditor
    ;
    ; Replace the 'EDIT' control procedure with your own to intercept messages
    ;
    invoke  SetWindowLong, [edithwnd], GWL_WNDPROC, EditorWndProc
    ;
    ; Old (Windows 'EDIT') procedure address returns back, so save it.
    ; It will be used in our 'EditorWndProc'
    ;
    mov     [WinOSEditProc], eax
    ret
endp

proc EditorWndProc uses ebx esi edi, hEditWnd,winmsg,wparam,lparam
    ; All messages for 'EDIT' control now are coming into this function.
    ; First call the original procedure to do what 'EDIT' does.
    invoke  CallWindowProc,[WinOSEditProc],[hEditWnd],[winmsg],[wparam],[lparam]
    ;
    ; After 'EDIT' did its job, check if that was WM_CHAR message
    cmp     [winmsg], WM_CHAR
    jne     .exit
    ;
    ; It was WM_CHAR, now check if it was [ENTER]
    cmp     [wparam], VK_RETURN
    jne     .exit
    ;
    ; At this point we know that [ENTER] was pressed
    push    eax                 ; Need to preserve return value in EAX.

    ; Use [edithwnd] to get the last line in the control...
    call    Query               ; move a terminated string to TIB

    pop     eax
.exit:
    ret
endp
    
Post 10 Aug 2024, 21:46
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1628
Location: Toronto, Canada
AsmGuru62 11 Aug 2024, 15:27
It seems I found the way to detect the ENTER key.
Please look for "_bEnter" in below code:
Code:
; Simple text editor - fasm example program
format PE GUI 4.0
entry start
include 'win32ax.inc'

macro fPush value               ; Push value to TOS (Top Of Stack)
{  add edx, -4                  ; S - 4, new cell for TOS
   mov [edx], dword value       ; move value to TOS
}
macro Msg label                 ; msg string typed to screen
{  fPush label                  ; Push adr of string to TOS
   call Type                    ; Display string on screen
}
section '.data' data readable writeable
; compute adr's for 2 stacks starting from return stack at enter
; == Return Stack =====
; R:      [ESP]                 ; Return Stack ptr, in ESP
R0        DD 0                  ; Ret Stk End, at run = initial [esp]
ToR       DD 0                  ; 1 cell above Top of R, at run =[esp]+64
; == Data Stack ======
; S:      [EDX]                 ; Data Stack ptr, in EDX
S0:       DD 128 Dup ?          ; Data Stack End, 128 cells
ToS:                            ; 1 cell above Top of S Stack
; I wanted to use EBP for the Data Stack but I hear Windows uses it

; Note: many good names from Forth are reserved by assembler, find alt's
NameSz   EQU 256                 ; max name cnt, increases dictionary size
New^     DD Reserved             ; ptr to next unused rec in Name
N^       DD 0                    ; Name Ptr, index for Name, was DP
TIB      DB 128 Dup " "          ; Term Input Buf adr, 128 b
;T^       DD 0                    ; Text Ptr to current source, was IN
;Pad      DB 128 Dup " "          ; Pad adr, 128 b
;P^       DD Pad                  ; Pad ptr (temp work area)
;H^       DD EndKern              ; ptr to current unused cell for code
;Fence    DD Reserved -17         ; adr of last protected dictionary word

; Start Dictionary with major words of kernal core
; Names have 8 char length w/trailing zeros, no cnt byte for string
; Code Adr = 4 byte, Param Adr = 4 byte, Status = 1 byte (0=IMM,1=Defer)
Name:
DB  "Cold",0,0,0,0
 DD Cold,0
 DB 1
DB  "Abort",0,0,0
 DD Abort,0
 DB 1
DB  "Quit",0,0,0,0
 DD Quit,0
 DB 1
DB  "Query",0,0,0
 DD Query,0
 DB 1
Reserved: DB ((NameSz *17) +Name -Reserved) Dup ?  ; clear Name space
; Forth searches the dictionary to find the address of a command.  My bare
; bones kernal will need close to 60 names.  The Forth standard has almost
; 140 names, and with extensions like floating point, a simple assembler,
; and various data structures this can easily go over 200.

; Windows assignments
  _class       TCHAR 'Go4th',0
  _title       TCHAR 'Go4th32',0
  _about_title TCHAR 'About Go4th32',0
  _about_text  TCHAR 'Windows based Forth Compiler',13,10,\
                     'Created with FLAT assembler.',0
  _edit        TCHAR 'EDIT',0
  _error       TCHAR 'Startup failed.',0
  _fontface    TCHAR 'Courier New',0

client        RECT               ; window box sides
ClsAtom       dd ?
editfont      dd ?
edithwnd      dd ?
hmenu         dd ?
hwnd          dd ?  ; <---------
WinOSEditProc dd ?
msg           MSG                ; message struct for Windows

IDR_ICON   =  17
IDR_MENU   =  37
  ; Menu items
IDM_FILE   = 100
IDM_NEW    = 110
IDM_OPEN   = 120
IDM_EXIT   = 130
IDM_SVSEL  = 140
IDM_SAVE   = 150
IDM_SAVEAS = 160

IDM_EDIT   = 200
IDM_UNDO   = 210
IDM_FIND   = 220
IDM_CUT    = 230
IDM_COPY   = 240
IDM_PASTE  = 250
IDM_DEL    = 260

IDM_HELP   = 900
IDM_ABOUT  = 910

;EN_SETFOCUS

IDC_MLEDIT = 1001   ; ID for 'EDIT' control

wc WNDCLASS 0,WindowProc,0,0,0,0,0,COLOR_BTNFACE+1,0,_class

Banner:   DB "Go4th: The Windows Forth Compiler",13,10,0
NewLine:  DB 13,10,0
Prompt:   DB "4th?",0
_bEnter   DB 0

section '.idata' import data readable writeable
   library    advapi32,          'ADVAPI32.DLL',\
              comctl32,          'CONCTL32.DLL',\
              comdlg32,          'COMDLG32.DLL',\
              gdi32,             'GDI32.DLL',\
              kernel32,          'KERNEL32.DLL',\
              shell32,           'SHELL32.DLL',\
              user32,            'USER32.DLL',\
              wsock32,           'WSOCK32.DLL'
   include    'api\advapi32.inc'
   include    'api\comctl32.inc'
   include    'api\comdlg32.inc'
   include    'api\gdi32.inc'
   include    'api\kernel32.inc'
   include    'api\shell32.inc'
   include    'api\user32.inc'
   include    'api\wsock32.inc'

section '.rsrc' resource data readable
directory     RT_MENU, menus,  RT_VERSION, versions,  RT_ICON, icons,\
              RT_GROUP_ICON, group_icons

resource  menus,       IDR_MENU, LANG_ENGLISH +SUBLANG_DEFAULT, main_menu
resource  versions,    1, LANG_NEUTRAL, version
resource  group_icons, IDR_ICON, LANG_NEUTRAL, main_icon
resource  icons,       1, LANG_NEUTRAL, icon_data

  versioninfo  version, VOS__WINDOWS32, VFT_APP, VFT2_UNKNOWN,\
          LANG_ENGLISH +SUBLANG_DEFAULT, 0,\
          'FileDescription', 'MiniPad - example program',\
          'LegalCopyright', 'No rights reserved.',\
          'FileVersion', '1.0',\
          'ProductVersion', '1.0',\
          'OriginalFilename', 'MINIPAD.EXE'
  icon    main_icon, icon_data, 'Go4th.ico'

menu main_menu
    menuitem '&File',IDM_FILE, MFR_POPUP
          menuitem '&New',IDM_NEW
          menuitem '&Open',IDM_OPEN
          menuitem 'E&xit',IDM_EXIT
          menuseparator
          menuitem '&SvSelect',IDM_SVSEL
          menuitem 'Sa&ve',IDM_SAVE
          menuitem 'Save &As',IDM_SAVEAS, MFR_END
    menuitem '&Edit',IDM_EDIT, MFR_POPUP
          menuitem '&Undo',IDM_UNDO
          menuitem '&Find',IDM_FIND
          menuseparator
          menuitem '&Cut',IDM_CUT
          menuitem 'Co&py',IDM_COPY
          menuitem '&Paste',IDM_PASTE
          menuitem '&Delete',IDM_DEL, MFR_END
    menuitem '&Help',IDM_HELP, MFR_POPUP + MFR_END ; LAST POPUP - MFR_END"
          menuitem '&About', IDM_ABOUT, MFR_END

section '.code' code readable executable writeable
start:    PushAD
          mov     [R0],esp      ; set old stack point to new stack start
          mov     [ToR],esp
          add     [ToR],256     ; allow 64 cells for local stack

          invoke  GetModuleHandle,0
          mov     [wc.hInstance],eax
          invoke  LoadIcon,[wc.hInstance],IDR_ICON
          mov     [wc.hIcon],eax
          invoke  LoadCursor,0,IDC_ARROW
          mov     [wc.hCursor],eax
          invoke  LoadMenu,[wc.hInstance],IDR_MENU
          mov     [hmenu],eax
          invoke  RegisterClass,wc
          mov     [ClsAtom],eax
          invoke  CreateWindowEx,0,_class,_title,WS_TILEDWINDOW+\
                  WS_VISIBLE,200,100,900,600,0,[hmenu],[wc.hInstance],0

msg_loop: invoke  GetMessage,msg,0,0,0
          mov     [_bEnter],0
          cmp     eax,0
          je      end_loop
          ;
          ; Some message received
          ;
          mov     ecx, msg
          mov     eax, [edithwnd]
          cmp     [ecx + MSG.hwnd], eax
          jne     .translate
          ;
          ; We are here if message to be processed by [edithwnd]
          ;
          cmp     [ecx + MSG.message], WM_CHAR
          jne     .translate
          ;
          ; Message was WM_CHAR, last check -- if it was [ENTER]
          ;
          cmp     [ecx + MSG.wParam], VK_RETURN
          jne     .translate
          ;
          ; Here we know that [edithwnd] is getting WM_CHAR for [ENTER] key.
          ; Simply let it fall through and be processed, but raise a flag.
          ;
          inc     [_bEnter]

.translate:
          invoke  TranslateMessage,msg
          invoke  DispatchMessage,msg
          ;
          ; Message is processed, but if flag was raised -- we need to do our own processing
          ;
          cmp     [_bEnter],0
          je      msg_loop

          call    EnterKeyWasPressed
          jmp     msg_loop

error:    invoke  MessageBox,NULL,_error,NULL,MB_ICONERROR+MB_OK
end_loop: invoke  ExitProcess,[msg.wParam]
          PopAD

; Add most new code here

; Cold:  full restart, reset bufs, reset N^ and New^, call Abort
Cold:     mov     eax, [Name]
          mov     [N^], eax
;          mov     eax, [Fence +17]
          mov     [New^], eax

; Abort:  reset data stack, set base, print banner, call Quit
Abort:    mov  edx, S0          ; clear data stack S
;          mov  [Base], 10

; Quit:  set term input, reset return stack, query & interp, print prompt
Quit:     mov  esp, R0          ; Begin: clear return stk R
          ret

; Query:  Move a null terminated string into Terminal Input Buffer
Query:    mov     [TIB], 123              ; set input limit
          invoke  SendMessage,[edithwnd],EM_GETLINECOUNT,0,0
          invoke  SendMessage,[edithwnd],EM_GETLINE,eax,dword[TIB]
          mov     [TIB +eax],0            ; add null to string
          invoke  SendMessage,[edithwnd],EM_REPLACESEL,0,NewLine
; Test results - Write input line back out
          invoke  SendMessage,[edithwnd],EM_SETSEL,-1,-1
          invoke  SendMessage,[edithwnd],EM_REPLACESEL,0,dword[TIB]

proc WindowProc hwndproc,wmsg,wparam,lparam
          mov     eax,[wmsg]
          cmp     eax,WM_CREATE
          je      .wmcreate
          cmp     eax,WM_SIZE
          je      .wmsize
          cmp     eax,WM_SETFOCUS
          je      .wmsetfocus
          cmp     eax,WM_COMMAND
          je      .wmcommand
          cmp     eax,WM_DESTROY
          je      .wmdestroy
  .defwndproc:
          invoke  DefWindowProc,[hwndproc],[wmsg],[wparam],[lparam]
          ret
  .wmcreate:
          mov     eax,[hwndproc]
          mov     [hwnd],eax
          invoke  GetClientRect,[hwnd],client
          invoke  CreateWindowEx,WS_EX_CLIENTEDGE,_edit,0,WS_VISIBLE+\
          WS_CHILD+WS_HSCROLL+WS_VSCROLL+ES_AUTOHSCROLL+ES_AUTOVSCROLL+\
          ES_MULTILINE+ES_WANTRETURN,[client.left],[client.top],\
          [client.right],[client.bottom],[hwnd],IDC_MLEDIT,[wc.hInstance],NULL
          mov     [edithwnd],eax
          cmp     eax,0
          je      .failed
          invoke  CreateFont,16,0,0,0,0,FALSE,FALSE,FALSE,ANSI_CHARSET,\
          OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,\
          FIXED_PITCH+FF_MODERN,_fontface
          mov     [editfont],eax
          cmp     eax,0
          je      error
          invoke  SendMessage,[edithwnd],WM_SETFONT,eax,FALSE
          invoke  SendMessage,[edithwnd],EM_SETSEL,-1,-1
          invoke  SendMessage,[edithwnd],EM_REPLACESEL,0,Banner
          invoke  SendMessage,[edithwnd],EM_SETSEL,-1,-1
          invoke  SendMessage,[edithwnd],EM_REPLACESEL,0,Prompt
;          call    Cold         ; Initialize compiler
;          Msg     Banner
;          Msg     Prompt
          jmp     .finish
  .failed:
          or      eax,-1
          ret
  .wmsize:
          invoke  GetClientRect,[hwnd],client
          invoke  MoveWindow,[edithwnd],[client.left],[client.top],\
          [client.right],[client.bottom],TRUE
          jmp     .finish
  .wmsetfocus:
          invoke  SetFocus,[edithwnd]
          jmp     .finish
  .wmcommand:
          mov     eax,[wparam]
          and     eax,0FFFFh
          cmp     eax, IDM_NEW
          je      .new
          cmp     eax, IDM_OPEN
          je      .open
          cmp     eax, IDM_SVSEL
          je      .svSel
          cmp     eax, IDM_SAVE
          je      .save
          cmp     eax, IDM_SAVEAS
          je      .saveAs
          cmp     eax, IDM_UNDO
          je      .undo
          cmp     eax, IDM_FIND
          je      .find
          cmp     eax, IDM_CUT
          je      .cut
          cmp     eax, IDM_COPY
          je      .copy
          cmp     eax, IDM_PASTE
          je      .paste
          cmp     eax, IDM_DEL
          je      .del
          cmp     eax, IDM_ABOUT
          je      .about
          cmp     eax, IDM_EXIT
          je      .wmdestroy
          jmp     .defwndproc

   .new:  invoke  SendMessage,[edithwnd],WM_SETTEXT,0,0
          jmp     .finish
   .open:                       ; Load file to Edit Control

          jmp     .finish
   .svSel:invoke  SendMessage,[edithwnd],EM_GETSEL,0,0
                                ; Write Selected to a File
          jmp     .finish
   .save:                       ; Write Session to a File

          jmp     .finish
   .saveAs:                     ; Write Session to a different File name

          jmp     .finish
   .undo: invoke  SendMessage,[edithwnd],EM_UNDO,0,0
          jmp     .finish
   .find:                       ; Get Search str and try to Find it in text

          jmp     .finish
   .cut:  invoke  SendMessage,[edithwnd],WM_CUT,0,0
          jmp     .finish
   .copy: invoke  SendMessage,[edithwnd],WM_COPY,0,0
          jmp     .finish
   .paste:invoke  SendMessage,[edithwnd],WM_PASTE,0,0
          jmp     .finish
   .del:  invoke  SendMessage,[edithwnd],WM_CLEAR,0,0
          jmp     .finish
  .about: invoke  MessageBox,[hwnd],_about_text,_about_title,MB_OK
          jmp     .finish
  .wmdestroy:
          invoke  DeleteObject,[editfont]
          PopAD
          invoke  PostQuitMessage,0
  .finish:
          xor     eax,eax
          ret
endp

proc EnterKeyWasPressed uses esi ebx
    mov     ebx, [edithwnd]
    invoke  SendMessage, ebx, EM_GETLINECOUNT, 0, 0

    dec     eax     ; COUNT-1 --> Last line,
    dec     eax     ; but last line is empty, because ENTER makes it so, go back on index once more

    mov     esi, TIB
    mov     word [esi], 128
    invoke  SendMessage, ebx, EM_GETLINE, eax, esi
    mov     byte [esi + eax], 0

    invoke  MessageBox, [hwnd], esi, _about_title, MB_OK
    ret
endp
    
Post 11 Aug 2024, 15:27
View user's profile Send private message Send e-mail Reply with quote
Stancliff



Joined: 30 Jun 2024
Posts: 54
Location: Florida
Stancliff 11 Aug 2024, 21:04
Hey, this makes sense! I had gotten the idea that messages were changed before or after 'Translate". Needless to say grabbing this data here never occurred to me. I know what I will be doing Monday. Many thanks!

I am considering that when my code is running the Windows code is stalled. I can assume my code has a new return stack every time it is entered and then I return it back to the entry state whenever I ret(urn) back to Windows code. The switch each way is trivial and Windows should never see the changes. When my code is finally well tested this should never be an issue, but there is always a chance I mess up my return stack and have to erase it. The degree of reset needed by the system is the basis for the code in Cold, Abort, and Quit. Besides acting as the initialization for the system they can be used to attempt to return back to a previous stable point by adjusting various parameters and clearing one or both stacks.

My working version has several changes to the one you are using. Better to change your copy the next time I post one.
Post 11 Aug 2024, 21:04
View user's profile Send private message Reply with quote
Stancliff



Joined: 30 Jun 2024
Posts: 54
Location: Florida
Stancliff 12 Aug 2024, 22:07
Now what are third and fourth lines saying? Shouldn't MSG be msg?
; Some message received
mov ecx, msg
mov eax, [edithwnd]
cmp [ecx + MSG.hwnd], eax
jne .translate
Post 12 Aug 2024, 22:07
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1628
Location: Toronto, Canada
AsmGuru62 13 Aug 2024, 00:43
MSG is a structure defined by FASM:
Code:
struct MSG
  hwnd   dd ?
  message dd ?
  wParam  dd ?
  lParam  dd ?
  time   dd ?
  pt   POINT
ends
    

ECX is a pointer to this structure and MSG.hwnd is an offset into the structure (it happens to be 0).
The following is basically the same code:
Code:
mov eax, [edithwnd]
cmp eax, [msg.hwnd]
    

I loaded ECX with a pointer, because we need to access a few members of 'msg' on the same code flow.
The code is smaller and faster this way.
Post 13 Aug 2024, 00:43
View user's profile Send private message Send e-mail Reply with quote
Stancliff



Joined: 30 Jun 2024
Posts: 54
Location: Florida
Stancliff 13 Aug 2024, 04:15
That was my guess, I remember something like that in the manual... not used to it yet.
Post 13 Aug 2024, 04:15
View user's profile Send private message Reply with quote
Stancliff



Joined: 30 Jun 2024
Posts: 54
Location: Florida
Stancliff 14 Aug 2024, 17:55
The first time through msg_loop edithwnd is referenced but it hasn't been initialized until after WindowProc runs once for .create to create it's value. Can this create a problem? Should it be initialized in .data?
Code:
  msg_loop:
        invoke  GetMessage,msg,NULL,0,0
        cmp     eax,0
        je      end_loop
        jb      error
        mov     [_bEnter], 0
        ; Some message received
        mov     ecx, msg
        mov     eax, [edithwnd]           <<====
        cmp     [ecx + MSG.hwnd], eax
        jne     .translate
        ; message to be processed by [edithwnd]
        cmp     [ecx + MSG.message], WM_CHAR
        jne     .translate
        ; Message was WM_CHAR, was it [ENTER]?
        cmp     [ecx + MSG.wParam], VK_RETURN
        jne     .translate
        ; [edithwnd] is getting WM_CHAR for [ENTER] key. raise a flag.
        inc     [_bEnter]        


Last edited by Stancliff on 14 Aug 2024, 19:30; edited 1 time in total
Post 14 Aug 2024, 17:55
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page Previous  1, 2, 3, 4  Next

< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.