I have too much time on my hands and decided to write a simple program in MASM32 for no good reason. However, I can't get my SetWindowPos call to the WinApi to work. Here's the relevant code bit:
invoke GetForegroundWindow
mov ecx,eax
invoke GetWindowLong, ecx, GWL_EXSTYLE
AND eax,WS_EX_TOPMOST ; check if window-
.if eax==0 ; is already on top
mov edx,HWND_TOPMOST; nope, make it on top
.else
mov edx,HWND_NOTOPMOST; yes, make it not on top
.endif
push ecx ; window handle
push edx ; placement handle
push edi ; edi=0, someone told me this is faster
push edi
push edi
push edi
push 0043h ; SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE
call SetWindowPos
cmp eax,0
jne mLoop1 ; jump to message loop
invoke HandleError, addr appname ; make message box with error message
; ^^^^^^^^ this shows "Invalid Window Handle"
jmp mLoop1 ; jump to message loop
I'm sure I'm missing somehting very obvious, but with my limited knowledge of assembly I have no idea what.
Related
This is a basic win32 program that I found online. So far I get everything, but what I don't get are those two lines:
push hInstance
pop wc.hInstance
Can someone explain to me what they do and if there is another way to do whatever is done by them using another instruction.
I tried to use google and other documentation and they explained very well what the push and pop instructions do, but I can't fit my understanding of them in the context of this program.
.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib ; calls to functions in user32.lib and kernel32.lib
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
.DATA ; initialized data
ClassName db "SimpleWinClass",0 ; the name of our window class
AppName db "Our First Window",0 ; the name of our window
.DATA? ; Uninitialized data
hInstance HINSTANCE ? ; Instance handle of our program
CommandLine LPSTR ?
.CODE ; Here begins our code
start:
invoke GetModuleHandle, NULL ; get the instance handle of our program.
; Under Win32, hmodule==hinstance mov hInstance,eax
mov hInstance,eax
invoke GetCommandLine ; get the command line. You don't have to call this function IF
; your program doesn't process the command line.
mov CommandLine,eax
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT ; call the main function
invoke ExitProcess, eax ; quit our program. The exit code is returned in eax from WinMain.
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX ; create local variables on stack
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX ; fill values in members of wc
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc ; register our window class
invoke CreateWindowEx,NULL,\
ADDR ClassName,\
ADDR AppName,\
WS_OVERLAPPEDWINDOW,\
CW_USEDEFAULT,\
CW_USEDEFAULT,\
CW_USEDEFAULT,\
CW_USEDEFAULT,\
NULL,\
NULL,\
hInst,\
NULL
mov hwnd,eax
invoke ShowWindow, hwnd,CmdShow ; display our window on desktop
invoke UpdateWindow, hwnd ; refresh the client area
.WHILE TRUE ; Enter message loop
invoke GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam ; return exit code in eax
ret
WinMain endp
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.IF uMsg==WM_DESTROY ; if the user closes our window
invoke PostQuitMessage,NULL ; quit our application
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam ; Default message processing
ret
.ENDIF
xor eax,eax
ret
WndProc endp
end start
It's pushing hInstance onto the stack, and then popping it into the memory location of wc.hInstance.
The programmer could have equivalently written:
mov eax, hInstance
mov wc.hInstance, eax
if they knew they didn't need to preserve EAX.
I am creating a file using CreateFileA from the Windows API in NASM 64-bit (see https://learn.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilea). With the following parameters, no file is created and it returns an error 87 ("the parameter is incorrect") from GetLastError (see https://learn.microsoft.com/en-us/windows/desktop/debug/system-error-codes--0-499-)
Here are the parameters:
rcx - lpFileName
;dwDesiredAccess
mov rdx,2
I chose FILE_WRITE_DATA from https://learn.microsoft.com/en-us/windows/desktop/FileIO/file-access-rights-constants
; dwShareMode
mov r8,0
According to https://learn.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilea: If this parameter is zero and CreateFile succeeds, the file or device cannot be shared. According to https://learn.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilea, the value should be zero for no sharing.
; lpSecurityAttributes
mov r9,const_inf ; (Pointer to null value dq 0xFFFFFFFF)
OR mov r9,const_0
According to https://learn.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilea: "If this parameter is NULL, the handle returned by CreateFile cannot be inherited by any child processes the application may create and the file or device associated with the returned handle gets a default security descriptor."
sub rsp,24 ; stack space
; dwCreationDisposition
mov rax,2 (CREATE_ALWAYS)
mov [rsp+16],rax
; dwFlagsAndAttribute
mov rax,128
mov [rsp+8],rax
The value 128 is from https://learn.microsoft.com/en-us/windows/desktop/FileIO/file-attribute-constants
; hTemplateFile
mov rax,[const_inf]
mov [rsp+0],rax
Here is the full file creation code:
CreateAuditFile:
push r10
mov r10,rax ; Core #
mov rdi,FileHandles
mov rbx,[rdi+r10]
cmp rbx,0 ; has file been created
jne file_next
mov rcx,FileName_1
mov rdx,2 ;dwDesiredAccess ;0x40000000
push r8
push r9
mov r8,0 ; dwShareMode
mov r9,const_0 ; lpSecurityAttributes
;OR: mov r9,const_inf ; lpSecurityAttributes
; CREATE STACK SPACE FOR REMAINING PARAMETERS:
sub rsp,24
mov rax,2 ; dwCreationDisposition (CREATE_ALWAYS)
mov [rsp+16],rax
mov rax,128
mov [rsp+8],rax ; dwFlagsAndAttributes
mov rax,[const_inf]
mov [rsp+0],rax ; hTemplateFile
push r10
call CreateFileA
pop r10
mov rdi,FileHandles
call GetLastError
mov [rdi],rax
add rsp,24
pop r9
pop r8
pop r10
file_next:
ret
I have looked carefully at the parameter options, but the error message only says "invalid parameter." It doesn't say which parameter.
My question is: which parameter or parameters above is incorrect? Are the parameters on the stack passed correctly?
Thanks for any help.
I solved this problem, and here is the solution. The stack handling on my original question was incorrect. The right way to handle the stack is shown below.
The values for each of the parameters (such as DesiredAccess, ShareMode and Security Attributes) may be different depending on the specific needs of the project, but the parameters are passed as in the code below:
CreateAuditFile:
mov rcx,FileName_1
sub rsp,56 ; 38h
xor eax,eax
mov qword [rsp+48],rax ; 30h
mov eax,80
mov dword [rsp+40],eax ; 28h
mov eax,2
mov dword [rsp+32],eax ; 20h
xor r9,r9
xor r8d,r8d
mov edx,40000000
call CreateFileA
mov rdi,OutputFileHandle
mov [rdi+r15],rax
xor eax,eax
add rsp,56 ;38h
ret
Thanks very much to everyone who responded.
I am programming a WinApi in assembly language in which the program reacts to keypress, problem is, if the routine is not completed and the key is pressed in meantime again, it starts accumulate, which means once the routine gets finished, it goes again and again given the times user pressed the key while the routine was in progress.
Classic message loop:
.MessageLoop:
invoke PeekMessage,Message,NULL,0,0,PM_REMOVE
test eax,eax
jz near .NoMess
cmp dword [Message + MSG.message],WM_QUIT
jz near .Finish
invoke TranslateMessage,Message
invoke DispatchMessage,Message
.NoMess:
; some code
jmp .MessageLoop
And handle for messages:
function WndProc,hWnd,wMsg,wParam,lParam
begin
mov eax,dword [wMsg]
cmp eax,WM_DESTROY
je near .Destroy
cmp eax,WM_CLOSE
je near .Destroy
cmp eax, WM_KEYDOWN
je near .keyDown ; when key is pressed, then it is checked what key it is, meanwhile I need program to ignore all keypressed
cmp eax, WM_PAINT
je near .Paint
invoke DefWindowProc,[hWnd],[wMsg],[wParam],[lParam]
return eax
Let's say I have routine to handle W button, in proccess of the routine I want all other W keys to be ignored.
I am trying to move stuff from a register to a variable in .CODE, but trying to do so makes my program start over in an infinite loop (no crash and no error message, but obviously broken). I don't understand what I'm doing wrong. Here is the beginning of my code where I am trying to move data; the program never even gets past this part when I include it:
.CODE
screenX DWORD 0
screenY DWORD 0
...
ProcName PROC
mov ebx, edx ;; Copy srcBitmap into ebx
mov eax, edi ;; Take given y-location (edi)
mov edx, (EECS205BITMAP PTR [ebx]).dwHeight
shr edx, 1 ;; Subtract dwHeight/2 to center
sub eax, edx
mov screenY, eax ;; Program jumps back to beginning with no error message
Seems like I'm missing something obvious, anyone have a clue?
Your application's code segment (which is actually it's .text section under Windows) isn't writable. If you want to modify these variables you need to put them in the data segment.
I know that the first four arguments are in the register (RCX, RDX, R8, R9), and that additional arguments are pushed on the stack.
Question:
How to push an argument onto the stack? I tried with (push 0) but it does not work?
Code (MASM64)
extrn ExitProcess: PROC
extrn MessageBoxExA: PROC
.data
caption db '64-bit hello!', 0
message db 'Hello World!', 0
.code
Start PROC
sub rsp, 38h
mov rcx, 0 ; hWnd = HWND_DESKTOP
lea rdx, message ; LPCSTR lpText
lea r8, caption ; LPCSTR lpCaption
mov r9d, 0 ; uType = MB_OK
push 0 ; wLanguageId
call MessageBoxExA
mov ecx, eax
add rsp, 38h
call ExitProcess
Start ENDP
End
I'm know that MessageBox and MessageBoxEx work the same way, but im trying to use MessageBoxEx because its need one parameter to be passed (for learning purpose).
I know I've asked similar question, but it is more related to vb.net while this is not.
My assembly is a little rusty, but I was under the impression that all arguments went onto the stack (in reverse order) - I'd have thought you want to be pushing r8 and rdx in as well as the other arguments. Frankly though you might as well just keep doing lea rax, param and push rax for each of the arguments that are pointers.
The order in which the arguments are passed and whether they are passed in registers or on the stack (along with whether caller or callee is responsible for cleanup) is defined by the 'Calling Convention'.
What you are probably thinking of is STDCALL or CDECL, both are calling conventions used in 32-bit Windows that pass arguments on the stack in reverse order (right to left). x64 has moved to a FastCall calling convention where the arguments are passed in forward order (from left to right) and the first 4 arguments are passed in the registers RCX, RDX, R8 & R9. Any arguments beyond 4 are passed on the stack in the same left-to-right order. The original poster had the correct calling convention setup for x64 assembly with MASM. Also, the above responder who said the shadowspace valued subtracted from RSP should be 20h (32d) is correct. The shadow space is allowing space on the stack for the 4 arguments that are passed in by the registers in FastCall.
Changing the code above to:
extrn ExitProcess: PROC
extrn MessageBoxExA: PROC
.data
caption db '64-bit hello!', 0
message db 'Hello World!', 0
.code
Start PROC
sub rsp, 20h
mov rcx, 0 ; hWnd = HWND_DESKTOP
lea rdx, message ; LPCSTR lpText
lea r8, caption ; LPCSTR lpCaption
mov r9d, 0 ; uType = MB_OK
push 0 ; wLanguageId
call MessageBoxExA
mov ecx, eax
add rsp, 20h
call ExitProcess
Start ENDP
End
Works just fine in Visual Studio on a 64-bit machine