News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Opening Windows in x64 ASM/Windows API Calls

Started by Caljay, August 08, 2022, 05:55:20 AM

Previous topic - Next topic

Caljay

Hello!

Beginner still, but have successfully made a few small programs using C++ calling conventions to pass in user input into assembly and using the RAX register for returns/output.

Now, I want to be able to get user input, and show output all in assembly. I know there is a "simple" way to do this but I believe it requires windows API/kernel calls. Can someone lead me in the right direction to how I might do this?

NoCforMe

Just to get you started. Big, deep subject you just broached.

There are two main types of Windows programs: GUI programs and "console" programs. GUI programs display windows on the screen (like most Windows apps: word processors, browsers, etc.) Console apps run in a "command" window, like the old MS-DOS command box, and are text-mode only. They can receive input (text only) from the user and display output (again, text only).

If you want to get started, it might be easier to start with a console app rather than a GUI one.

I can show you my console app "skeleton" which is my starting point for console programs to give you an idea of what it would look like:

;============================================
; Console App Skeleton
;
;============================================

.nolist
include \masm32\include\masm32rt.inc
.list

;============================================
; Defines, macros, prototypes, etc.
;============================================

WinMain PROTO :DWORD


;============================================
; HERE BE DATA
;============================================
.data


;============================================
; UNINITIALIZED DATA
;============================================
.data?

StdInHandle HANDLE ?
StdOutHandle HANDLE ?

CmdLineBuffer DB 256 DUP(?)


;============================================
; CODE LIVES HERE
;============================================
.code


start: INVOKE GetModuleHandle, NULL

INVOKE WinMain, EAX
INVOKE ExitProcess, EAX


;====================================================================
; Mainline proc
;====================================================================

WinMain PROC hInst:DWORD
LOCAL exitCode:DWORD, dummy:DWORD

; Get STDIN & STDOUT handles:
INVOKE GetStdHandle, STD_INPUT_HANDLE
MOV StdInHandle, EAX
INVOKE GetStdHandle, STD_OUTPUT_HANDLE
MOV StdOutHandle, EAX

; Get name of file to open, if any, from command line:
INVOKE GetCL, 1, OFFSET CmdLineBuffer ;Get arg[1] from command line.
CMP EAX, 1 ;See how many args on CL.
JE yesarg

;*****  (code for what happens when no args given here)  *****

; to send a message to the outside world, use:
INVOKE WriteConsole, StdOutHandle, (source), (length), NULL, NULL

MOV exitCode, 0
JMP exit99

;*****  (code for what happens when arg given here)  *****
yesarg:
MOV exitCode, TRUE

exit99: MOV EAX, exitCode
RET

WinMain ENDP


END start


This shows you how to display output (via WriteConsole() ).

I'm sure you'll have lots more questions. Ask away.
Assembly language programming should be fun. That's why I do it.

jj2007

Quote from: Caljay on August 08, 2022, 05:55:20 AMI want to be able to get user input, and show output all in assembly.

include \masm32\MasmBasic\MasmBasic.inc
  Init
  Let esi=Input$("What is your dream (you may edit the proposed one): ", "Becoming an Assembly programmer")
  MsgBox 0, Cat$("Your dream: "+esi), "Hi", MB_OK
EndOfCode


You may have to maximise the console window. To edit the string, use the arrow, backspace and delete keys. Escape clears the string. Hit Return to see the MessageBox.

@Hutch: I wanted to give him a Masm64 SDK example but was unable to find in \Masm64\help\MasmHelp.exe anything like "line input", "input$" or "conin". A searchable help file might be a good idea ;-)

NoCforMe

Wouldn't 64-bit be total overkill for the OP at this point?
Assembly language programming should be fun. That's why I do it.

hutch--

Don't be mislead, its this easy.

; «»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»

    include \masm64\include64\masm64rt.inc

    .data
      msg db "You entered > ",0             ; display text
      pmsg dq msg                           ; pointer to it

    .code

; «»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»

entry_point proc

    LOCAL pbuf1 :QWORD                      ; local pointer
    LOCAL buff[128]:BYTE                    ; 128 byte buffer

    mov pbuf1, ptr$(buff)                   ; get pointer to buffer

    conout "Enter some data "               ; display text
    rcall StdIn,pbuf1,128                   ; get data via StdIn

    conout pmsg,pbuf1,lf                    ; display output

    waitkey "Thats all for now ..."         ; exit message
    .exit                                   ; terminate app

entry_point endp

; «»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»

    end

hutch--

Now your topic asked for an x64 Window and that becomes a lot more complicated as you have to write both valid API code in 64 bit AND where necessary, use 64 bit intel instructions. Let us know what you are after and we may be able to help you.

learn64bit

Learn by add shit comments
include \masm64\include64\masm64rt.inc
.data
msg db "You entered > ",0
  ;Display text
pmsg dq msg
  ;Pointer to it
.code
entry_point proc
  local pbuf1:qword
   ;Local pointer
  local buff[128]:byte
   ;128 byte buffer
  mov pbuf1,ptr$(buff)
   ;Get pointer to buffer
  conout "Enter some data "
   ;call qword prt ds:[<&GetStdHandleStub>]
    ;GetStdHandle
     ;kernel32.dll
   ;call qword prt ds:[<&WriteFileImplementation>]
    ;WriteFile
     ;kernel32.dll
   ;Display text
  rcall StdIn,pbuf1,128
   ;GetStdHandle
   ;SetConsoleMode
   ;ReadFile
    ;kernel32.dll
   ;Get data via StdIn
  conout pmsg,pbuf1,lf
   ;Display output
  waitkey "Thats all for now ..."
   ;GetStdHandle
   ;FlushConsoleInputBuffer
   ;SleepEx
    ;kernel32.dll
   ;_kbhit
   ;_getch
    ;msvcrt.dll
   ;Exit message
  .exit
   ;ExitProcess
    ;kernel32.dll
   ;Terminate app
entry_point endp
end


shit rule:
lots typo and only you can understand!

NoCforMe

Comments aren't "shit", they're essential. Dunno why you have an attitude towards them.

Try coming back to some code you wrote 3 years later and try to figure out just what the hell you were doing there without comments ...
Assembly language programming should be fun. That's why I do it.

hutch--

I personally use a system where I write my comments very wide from the source so that I can read the source directly and refer to the comments if I need them. Much mixed source and comments make the entire files slow and hard to read, fortunately there are no rules as to how you write and format code so if a system works for you, fine but if you want other people to be able to read your code, don't write it as a tangled mess to start with.

NoCforMe

I second that emotion. That's pretty much the style I use too. Keep code in a separate column so it's easy to follow.
Assembly language programming should be fun. That's why I do it.

jj2007

Quote from: NoCforMe on August 09, 2022, 10:12:15 AM
I second that emotion. That's pretty much the style I use too. Keep code in a separate column so it's easy to follow.

Like this?
  .Repeat
dec eax
  .Until byte ptr [eax]=="}" ; find the trailing bracket
  mov byte ptr [eax], 0 ; eliminate it
  .Repeat ; insert the other rtf files

NoCforMe

Assembly language programming should be fun. That's why I do it.

hutch--

 :biggrin: I think its a case of "Great minds think alike". I will leave the rest of the expression out.  :tongue:

NoCforMe

(yes--they run in the same gutters ...)

While we're on comments, I find another type of comment, the Section Setter-Offer. Useful for easily finding the various handlers in a window proc, f'rinstance:

;=====================================
; WM_NOTIFY handler
;=====================================

do_notify:
; Get the notification code:
MOV EDX, lParam
CMP [EDX].NMHDR.code, BCN_HOTITEMCHANGE
JNE dodefault

; It's a "hot item" notification--see if the mouse is in or out of client area:
MOV ECX, HotBitmapHandle
TEST [EDX].NMBCHOTITEM.dwFlags, HICF_ENTERING
JNZ showit
MOV ECX, NormalBitmapHandle
showit: INVOKE SendMessage, HamburgerHandle, BM_SETIMAGE, IMAGE_BITMAP, ECX
JMP dodefault


;=====================================
; Hamburger menu handler
;=====================================

do_hamburger:

; (insert hamburger-grilling code here)

JMP dodefault


;=====================================
; WM_COMMAND handler
;=====================================

do_command:
MOV AX, WORD PTR wParam
CMP AX, $browseBtn
JE do_browse
CMP AX, IDOK
JE do_find
CMP AX, IDCANCEL
JE do_cancel
CMP AX, $hamburgerBtn
JE do_hamburger

; Look for BN_CLICKED notification:
CMP WORD PTR wParam + 2, BN_CLICKED
JE do_btnclick

MOV EAX, TRUE
RET

This is more for "finding the damn code" purposes than for explaining what it's doing.

Also you'll see my "header comments" which describe a section of code below them.

Regarding comments in general: I sometimes get the feeling that some programmers look at comments in general as beneath their dignity, like "real programmers don't put in comments", or "comments are for sissies". This seems to be a cultural mindset (especially in this still mostly male-dominated field).
Assembly language programming should be fun. That's why I do it.

hutch--

There is a response to the "no comments" brigade, real men[tm] write in binary. In the right context, binary is a ton of fun to write but its application is reasonably limited.