I am trying to get a simple window on screen. It is based on Iczelion's no 3 tutorial. Currently it is assembling and linking but not showing on screen. I need to use taskmanager to stop the process.
;ml64 /c Window.asm
;link /entry:Main /subsystem:windows /machine:x64 /libpath:c:\masm64\lib window.obj
option casemap:none
includelib \masm64\lib\user32.lib ; calls to functions in user32.lib and kernel32.lib
includelib \masm64\lib\kernel32.lib
externdef MessageBoxA : near
externdef ExitProcess : near
externdef GetModuleHandleA : near
externdef LoadIconA : near
externdef LoadCursorA : near
externdef CreateWindowExA : near
externdef ShowWindow : near
externdef UpdateWindow : near
externdef GetMessageA : near
externdef RegisterClassExA : near
externdef TranslateMessage : near
externdef DispatchMessageA : near
externdef PostQuitMessage : near
externdef DefWindowProcA : near
;WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
CS_VREDRAW equ 1h
CS_HREDRAW equ 2h
COLOR_WINDOW equ 5
IDI_APPLICATION equ 32512
IDC_ARROW equ 32512
WS_CAPTION equ 0C00000h
WS_OVERLAPPED equ 0h
WS_SYSMENU equ 80000h
WS_THICKFRAME equ 40000h
WS_MINIMIZEBOX equ 20000h
WS_MAXIMIZEBOX equ 10000h
WS_OVERLAPPEDWINDOW equ WS_OVERLAPPED OR WS_CAPTION OR WS_SYSMENU OR WS_THICKFRAME OR WS_MINIMIZEBOX OR WS_MAXIMIZEBOX
CW_USEDEFAULT equ 80000000h
NULL equ 0
WM_CREATE equ 1h
WM_DESTROY equ 2h
SW_SHOWDEFAULT equ 10
MESSAGE STRUCT
hwnd dq 0
message dd 0
dd 0 ;Padding
wParam dq 0
lParam dq 0
time dd 0
x dd 0 ;POINT structure x
y dd 0 ;POINT structure y
dd 0 ;Padding
MESSAGE ENDS
WNDCLASSEX STRUCT
cbSize DD 0 ;+0h Size of this structure
style DD 0 ;+4h window class style
lpfnWndProc DQ 0 ;+8h pointer to Window Procedure
cbClsExtra DD 0 ;+10h no. of extra bytes to allocate after structure
cbWndExtra DD 0 ;+14h no. of extra bytes to allocate after window instance
hInstance DQ 0 ;+18h handle to instance containing window procedure
hIcon DQ 0 ;+20h handle to the class icon
hCursor DQ 0 ;+28h handle to the class cursor
hbrBackground DQ 0 ;+30h identifies the class background brush
lpszMenuName DQ 0 ;+38h pointer to resource name for class menu
lpszClassName DQ 0 ;+40h pointer to string for window class name
hIconSm DQ 0 ;+40h handle to the small icon
WNDCLASSEX ENDS
.DATA
wc WNDCLASSEX <>
hWnd dq 0
msg MESSAGE <>
ClassName db "SimpleWinClass",0,0 ; the name of our window class
AppName db "OurFirstWindow",0,0 ; the name of our window
;-----------------------------------------------------------------------------------------
.CODE ; Here begins our code
Main proc
;Get instance handle
mov rcx,0h
sub rsp,8
call GetModuleHandleA ; get the instance handle of our program.
add rsp,8
;Fill wc
mov wc.hInstance,rax
mov wc.cbSize,SIZEOF WNDCLASSEX ;fill values in members of wc
mov wc.style, CS_HREDRAW or CS_VREDRAW
lea rax,WndProc
mov wc.lpfnWndProc,rax ;ADDR WndProc
mov wc.cbClsExtra,0
mov wc.cbWndExtra,0
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,0
lea rax,ClassName
mov wc.lpszClassName,rax ;OFFSET ClassName
mov rdx,IDI_APPLICATION
mov rcx,NULL
sub rsp,10h
call LoadIconA ;invoke LoadIcon,NULL,IDI_APPLICATION
add rsp,10h
mov wc.hIcon,rax
mov wc.hIconSm,rax
mov rdx,IDC_ARROW
mov rcx,NULL
sub rsp,10h
call LoadCursorA ;invoke LoadCursor,NULL,IDC_ARROW
add rsp,10h
mov wc.hCursor,rax
;Register the class
lea rcx,wc
sub rsp,8h
call RegisterClassExA ;invoke RegisterClassEx,addr wc
add rsp,8h
;Create our window
push NULL
push wc.hInstance
push NULL
push NULL
push CW_USEDEFAULT
push CW_USEDEFAULT
push CW_USEDEFAULT
push CW_USEDEFAULT
mov r9,WS_OVERLAPPEDWINDOW
lea r8,AppName
lea rdx,ClassName
mov rcx,NULL
sub rsp,60h
call CreateWindowExA
add rsp,60h
mov hWnd,rax
;Show our window
mov rdx,SW_SHOWDEFAULT
mov rcx,hWnd
sub rsp,10h
call ShowWindow ;invoke ShowWindow, hwnd,CmdShow
add rsp,10h
;Update the window
mov rcx,hWnd
sub rsp,8h
call UpdateWindow ;invoke UpdateWindow, hwnd
add rsp,8h
NextMessage:
;Call GetMessageA
mov r9,0
mov r8,0
mov rdx,NULL
lea rcx,msg
sub rsp,28h
call GetMessageA
add rsp,28h
;Quit if return value is 0
cmp rax,0
je EndMessage
;Call TranslateMessage
lea rcx,msg
sub rsp,8h
call TranslateMessage ;invoke TranslateMessage, ADDR msg
add rsp,8h
;call DispatchMessageA
lea rcx,msg
sub rsp,8h
call DispatchMessageA ;invoke DispatchMessage, ADDR msg
add rsp,8h
;Get new message
jmp NextMessage
EndMessage:
mov rcx,msg.wParam ; return exit code in ecx
call ExitProcess
ret
Main endp
;-----------------------------------------------------------------------------------------
;-----------------------------------------------------------------------------------------
WndProc proc ;For 64bit
;Save parameters that is in registers on the stack.
;[rsp+0] = return address
mov [rsp+8h],rcx
mov [rsp+10h],rdx
mov [rsp+18h],r8
mov [rsp+20h],r9
push rbp
mov rbp,rsp ;[rbp+0] = old rbp value,
;[rbp+8h] = return addr,
;[rbp+10h] = rcx = hwnd
;[rbp+18h] = rdx = message :uMSG
;[rbp+20h] = r8 = wParam
;[rbp+28h] = r9 = lParam
cmp qword ptr[ebp+18h],WM_DESTROY
je QuitPlease
cmp qword ptr[ebx+18h],WM_CREATE
je Do_Create
xor rcx,rcx
sub rsp,8h
call PostQuitMessage
add rsp,8h
xor rax,rax
ret
QuitPlease:
;rcx, rdx, r8 and r9 already contain hwnd, message, wparam and lparam
call DefWindowProcA
ret
Do_Create:
;Dosomethig
xor rax,rax
ret
WndProc endp
end
my mistake - you are trying to write a 64-bit program
Iczelion's examples are 32-bit
you are including, for example, kernel32.inc and lib
which are for 32-bit programs :P
also - Iczelion's tutorials are out of date
modern include packages take care of the API prototypes, standard constant defintions, and so on
i think i would start by getting a 32-bit app running, then have a look in the 64-bit forum for some modern code examples
but, you are mixing apples and oranges, as it is
I have made a 32 bit program first and it works. Then I changed all invokes to calls and adapted for 64 bit. I have made all relevant structures and equates for 64 bit. What I dont understand is that my windows\system directory is empty but my windows\system32 directory has the user32.dll and kernel32.dll. These are the dll's i am using. There is also a windows\syswow64 directory with the files in, but these do not work. I am also wondering why its even called user32 and kernel32. Why not user64 and kernel64. Any way, I have read a lot of things for GoAsm and it certainly looks the way to go. Excellent information with the GoAsm assembler. But first I want to finish what I have started. I want a clear straight forward example with preferably no procedures or jumping around. Definately nothing in it that is automatically generated for me or taken care of for me. I want to understand how it works. Thanks to GoAsm I do have an Idea
let me start off by saying - i do not write 64-bit code :P
there are others that can offer a clearer solution
however, i believe that there is a 64-bit set of includes and import libraries - seperate from the 32-bit
you might want to visit japheth's site to get a set of 64-bit stuff :bg
his download includes a set of batch files for building the import libraries...
http://japheth.de/WinInc.html
one other note
a "more correct" sub-forum would be
http://www.masm32.com/board/index.php?board=43.0
you will find a lot more useful info there
Sarel,
It is really recommendable to use japhets jWasm and WinInc. jWasm allowes you to use the well known highlevel syntax (invoke,.if,.while,...).
qWord
Quote from: Sarel on April 13, 2011, 06:34:38 PM
I have made a 32 bit program first and it works. Then I changed all invokes to calls and adapted for 64 bit. I have made all relevant structures and equates for 64 bit. What I dont understand is that my windows\system directory is empty but my windows\system32 directory has the user32.dll and kernel32.dll. These are the dll's i am using. There is also a windows\syswow64 directory with the files in, but these do not work. I am also wondering why its even called user32 and kernel32. Why not user64 and kernel64. Any way, I have read a lot of things for GoAsm and it certainly looks the way to go. Excellent information with the GoAsm assembler. But first I want to finish what I have started. I want a clear straight forward example with preferably no procedures or jumping around. Definately nothing in it that is automatically generated for me or taken care of for me. I want to understand how it works. Thanks to GoAsm I do have an Idea
Hi Sarel,
I strongly suggest that you visit following link and read whole article to get an idea about why user32.dll and kernel32.dll exist under windows/system32 directory. (Maybe they don't) ! Just in case you may wanna have a quick look at it, I'll paste the most relevant part.
http://msdn.microsoft.com/en-us/magazine/cc300794.aspx
While running a fully 64-bit Windows system sounds great, the reality is that you'll very likely need to run Win32 code for a while. Towards that end, x64 versions of Windows include the WOW64 subsystem that lets Win32 and Win64 processes run side-by-side on the same system. However, loading your 32-bit DLL into a 64-bit process, or vice versa, isn't supported. (It's a good thing, trust me.) And you can finally kiss good bye to 16-bit legacy code!
In x64 versions of Windows, a process that starts from a 64-bit executable such as Explorer.exe can only load Win64 DLLs, while a process started from a 32-bit executable can only load Win32 DLLs. When a Win32 process makes a call to kernel mode—to read a file, for instance—the WOW64 code intercepts the call silently and invokes the correct x64 equivalent code in its place.
Of course, processes of different lineages (32-bit versus 64-bit) need to be able to communicate with each other. Luckily, all the usual interprocess communication mechanisms that you know and love in Win32 also work in Win64, including shared memory, named pipes, and named synchronization objects.
You might be thinking, "But what about the system directory? The same directory can't hold both 32- and 64-bit versions of system DLLs such as KERNEL32 or USER32, right?" WOW64 magically takes care of this for you by the doing selective file system redirection. File activity from a Win32 process that would normally go to the System32 directory instead goes to a directory named SysWow64. Under the covers, WOW64 silently changes these requests to point at the SysWow64 directory. A Win64 system effectively has two \Windows\System32 directories—one with x64 binaries, the other with the Win32 equivalents.
Smooth as it may seem, this can be confusing. For instance, I was at one point using (unbeknownst to me) a 32-bit command-line prompt. When I ran DIR on Kernel32.dll in the System32 directory, I got the exact same results as when I did the same thing in the SysWow64 directory. It took a lot of head scratching before I figured out that the file system redirection was working just like it should. That is, even though I thought I was working in the \Windows\System32 directory, WOW64 was redirecting the calls to the SysWow64 directory. Incidentally, if you really do want to get at the 32-bit \Windows\System32 directory from an x64 app, the GetSystemWow64Directory API gives you the correct path. Be sure to read the MSDN® documentation for the complete story.
Beyond file system redirection, another bit of magic performed by WOW64 is registry redirection. Consider my earlier statement about Win32 DLLs not loading into Win64 processes, and then think about COM and its use of the registry to load in-process server DLLs. What if a 64-bit application uses CoCreateInstance to create an object that's implemented in a Win32 DLL? The DLL can't load, right? WOW64 saves the day again by redirecting access from 32-bit applications to the \Software\Classes (and related) registry nodes. The net effect is that Win32 applications have a different (but mostly parallel) view of the registry than x64 applications. As you'd expect, the OS provides an escape hatch for 32-bit applications to read the actual 64-bit registry value by specifying new flag values when calling RegOpenKey and friends.
Regards,
Hello Sr Sarel, I have analyzed your example and appears to me that you are not reserving space to "shadow space".
If your function uses or not 4 arguments, you need reserve some stack space (shadow space)(add/sub rsp,4*8).
I'm currently playing with 64 bits now, and I can suggest to you to do not put the "pads" inside structures (more chances to errors), it is more easy if you align the structure to 8. You have the option to align all of these structures in command line with "/Zp8" for example, but do not do this, because in my tests, some structures do not be aligned to this value.
In the moment that your code call another function, the stack pointer needs be aligned to a multiple of 16, or in others words, rsp=???????0. Well, the first thing that comes in mind is put a "sub rsp,8" in the start of your procedure, but in my tests this is not a good choice, so you can put "and rsp,-10h" and this works.
About masm 64 , you can put an "ALIAS <WinMainCRTStartup>=<entrypoint>", so you can forget about command line "/entry:entrypoint".
If you will mount examples inside some editor, like Radasm, do not choose the menu "make, go", because radasm or others editors are done to work(launch) with 32 bits. I have coded one example and it worked fine when I put "make,go", so I have restarted my machine and when I go to explorer and clicked the example , they do not have worked. So, keep this in mind. If you use some editor to help you while coding, only assemble and compile, but do not click in "go" button or menu. Execute the program or using windows explorer or console.
Follows a simple window example, based in the same tutorials that you are getting as a base.
Mineiro, this is great. I had a quick look and I can follow the program and how parrameters are passed. I need time to let it sink in. Sorry for the long absence, I was quite fed up. :bg