News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Input

Started by HiddenDragon, December 12, 2010, 12:31:08 AM

Previous topic - Next topic

HiddenDragon

Yeah, a couple instructions after that EDI gets pushed and LoadCursor is called.

What does EDI have in it though? How does it have a value when the program starts?


EDIT:

    xor edi, edi
    mov esi, 400000h                        ; use constant for the hInstance

    mov ebx, OFFSET szClassName

    push IDC_ARROW
    push edi
    call LoadCursor


So EDI gets set to 0 by using exclusive-OR; then I don't know what happens with ESI because I haven't look farther; then EBX gets the window title; and finally we push the arrow we want (our default arrow), and EDI (which equals 0) because the LoadCursor command is LoadCursor(NULL[or 0], Cursor). Instead of IDC_ARROW I could use WAIT or any of the other cursors available.

dedndave

who knows what it is - lol
all registers always contain some value
well - FPU registers may be an exception to that (pun)
actually, even the FPU registers that are marked as empty have a value of some sort

EDI is one of the registers that should be preserved across function calls
i don't know where the code is coming from, so i don't know the context

hutch--

The reason why you generally use the "macros" when you write high level code is that it makes your code far more readable than guessing your way through bare mnemonic code. The API calls are all documented in Microsoft reference material and the very simple Intel mnemonics are all fully documented in the Intel manuals.

Bare mnemonic code is not where you start with this stuff, you learn how to write mnemonic code then you learn how to call Windows API functions and this is just to get a bare window up and running.

Dave,

The procedure for the entry point is also the procedure for the exit with RETN so the use of EBX ESI and EDI don't cause any problems in an example as simple as this one. You will note though that ESP and EBP are saved and restored.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

dedndave

thanks Hutch
i wasn't sure if it was a function or the main   :P

Tight_Coder_Ex

Here's an example of what you might be looking for as I prefer to hard code too, meaning I don't even use invoke.  Not that using INVOKE is wrong, it's just not my preference as I like doing other calculations as the stack is being populated


Begin proc uses edi
 
LOCAL Wc:WNDCLASSEX, Msg:MSG

  lea edi, Wc
  push edi
 
  xor eax, eax
push eax
mov al, sizeof WNDCLASSEX
stosd ; cbSize
mov al, CS_HREDRAW or CS_VREDRAW or CS_OWNDC
stosd ; style
mov eax, MainWndProc
stosd ; lpfnWndProc
pop eax
stosd ; cbClsExtra
stosd ; cbWndExtra

push eax
push eax ; lpModuleName
call GetModuleHandle
stosd ; hInstance
mov hInst, eax ; Save global copy of instance handle
pop eax
stosd ; hIcon

push eax ; preserve null
push IDC_ARROW ; lpCursorName
push eax ; hInstance
call LoadCursor
stosd ; hCursor
pop eax ; restore null

mov al, COLOR_APPWORKSPACE + 1
stosd ; hbrBackground

mov al, 0
push eax
stosd ; lpszMenuName
mov eax, offset AppName
stosd ; lpszClassName
pop eax
stosd ; hIconSm

  call RegisterClassEx
  test ax, ax
 
  .if Zero?
push MB_ICONSTOP or MB_OK
  push offset ErrCaption
  push offset ErrDefText
  push 0 ; Desktop as there isn't a app window yet
  call Ext_Error
.else

  STYLE equ WS_VISIBLE or WS_MINIMIZEBOX or WS_SYSMENU
 
  push 0 ; lpParam
  mov eax, hInst
  push eax ; hInstance
  xor eax, eax
  push eax ; hMenu
  push eax ; hWndParent
  bts eax, 31
  push 320 ; nHeight
  push 400 ; nWidth
  push 120 ; y
  push 128 ; x
  push STYLE ; dwStyle
  push offset AppTitle ; lpWindowName
  push offset AppName ; lpClassName
  push WS_EX_STATICEDGE or \
  WS_EX_WINDOWEDGE ; dwExStyle

call CreateWindowEx
or eax, eax

.if !Zero?
mov MainWnd, eax ; Save handle to window
lea edi, Msg

.while 1
xor eax, eax ; Nullify register
push eax ; wMsgFilterMax
push eax ; wMsgFilterMin
push eax ; hWnd, pointer to desktop
push edi ; lpMsg
call GetMessage

.break .if (!eax)
push edi ; lpMsg
call TranslateMessage
push edi ; lpMsg
call DispatchMessage
.endw

  .endif ; Creating main window failed
  .endif ; Registering class failed
 
mov eax, Msg.lParam ; Set return value in eax
  ret
 
  Begin endp 


It may be of a benefit too, that although everything created using CreateWindowEx is a window, there is a subtle distinction between a window and controls.  As an example, a text box is usually referred to as a control, although technically it is a window.  The difference is one of MS dll's will have additional code that gives the control is characteristic behavior, such as horizontal and vertical scrolling.

HiddenDragon

Thanks Tight_Coder but I think I'll keep with POASM1k for right now.

in this:
; -----------------------------------
  ; manually coded WNDCLASSEX structure
  ; -----------------------------------
    mov DWORD PTR [ebp-96], 48
    mov DWORD PTR [ebp-92], CS_VREDRAW or CS_HREDRAW
    mov DWORD PTR [ebp-88], OFFSET MyWndProc
    mov DWORD PTR [ebp-84], edi
    mov DWORD PTR [ebp-80], edi
    mov DWORD PTR [ebp-76], esi
    mov DWORD PTR [ebp-72], edi
    mov DWORD PTR [ebp-68], eax
    mov DWORD PTR [ebp-64], COLOR_BTNFACE+1
    mov DWORD PTR [ebp-60], edi
    mov DWORD PTR [ebp-56], ebx
    mov DWORD PTR [ebp-52], edi


The mov DWORD PTR [ebp-96], 48 is telling the program to move a dword containing 48 to the memory location EBP-96 (Value at EBP minus 96) correct? And the rest of them follow the same calling so that mov DWORD PTR [ebp-80],edi will move a dword containing the value of EDI to the memory location EBP-80 (value at EBP minus 80)?

Tight_Coder_Ex

Generally you have the right idea.  To know if there would be any problem one would need to see how WNDCLASSEX was declared in the procedure,

96 = 60H and the structure is 48 = 30H.

This means there are 48 bytes declared for something else beforehand.  If these were to be removed, then the values 96-52 would be offset +- those declartions.  I'm not familiar with POASAM1k, so do you not have local declarations like ML, ie  LOCAL   Wc:WNDCLASSEX?

HiddenDragon

\masm32\examples\poasm\poasm1k

It uses just mnemonics to make a window.

Tight_Coder_Ex

Good example and without modification you can see this is the resultant code

        LOCAL msg  :MSG

        LOCAL wc   :WNDCLASSEX
        LOCAL Wwd  :DWORD
        LOCAL Wht  :DWORD
        LOCAL Wtx  :DWORD
        LOCAL Wty  :DWORD

   88 00401037 c745d030000000  mov     dword ptr [ebp-30h],30h
   89 0040103e c745d400200000  mov     dword ptr [ebp-2Ch],2000h
   90 00401045 c745d88a114000  mov     dword ptr [ebp-28h],offset Winenum!WndProc (0040118a)
   91 0040104c c745dc00000000  mov     dword ptr [ebp-24h],0
   92 00401053 c745e000000000  mov     dword ptr [ebp-20h],0
   93 0040105a ff7508          push    dword ptr [ebp+8]
   93 0040105d 8f45e4          pop     dword ptr [ebp-1Ch]
   94 00401060 c745f010000000  mov     dword ptr [ebp-10h],10h
   95 00401067 c745f400000000  mov     dword ptr [ebp-0Ch],0
   96 0040106e c745f8da104000  mov     dword ptr [ebp-8],offset Winenum!szClassName (004010da)


Now move the declaration to the bottom of the list then


        LOCAL msg  :MSG

        LOCAL Wwd  :DWORD
        LOCAL Wht  :DWORD
        LOCAL Wtx  :DWORD
        LOCAL Wty  :DWORD
        LOCAL wc   :WNDCLASSEX


   88 00401037 c745a430000000  mov     dword ptr [ebp-5Ch],30h
   89 0040103e c745a800200000  mov     dword ptr [ebp-58h],2000h
   90 00401045 c745ac8a114000  mov     dword ptr [ebp-54h],offset Winenum!WndProc (0040118a)
   91 0040104c c745b000000000  mov     dword ptr [ebp-50h],0
   92 00401053 c745b400000000  mov     dword ptr [ebp-4Ch],0
   93 0040105a ff7508          push    dword ptr [ebp+8]
   93 0040105d 8f45b8          pop     dword ptr [ebp-48h]
   94 00401060 c745c410000000  mov     dword ptr [ebp-3Ch],10h
   95 00401067 c745c800000000  mov     dword ptr [ebp-38h],0
   96 0040106e c745ccda104000  mov     dword ptr [ebp-34h],offset Winenum!szClassName (004010da)


So you can see, using declarations is better than hard coding, but not to say hard coding wouldn't work.  You just have to pay closer attention

HiddenDragon

Well I hate to bring this thread up again but I have a couple more questions.

include \masm32\include\masm32rt.inc        ;standard include

.code
    szClassName db "My First Window", 0     ;window title and class name

start:

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    push ebp                                ; set up a stack frame
    mov ebp, esp

    sub esp, 96                             ; create stack space for locals

    xor edi, edi
    mov esi, 400000h                        ; use constant for the hInstance

    mov ebx, OFFSET szClassName

    push IDC_ARROW                          ;sets the cursor to the default arrow
                                            ;can also use IDC_LOAD, etc
    push edi                                ;EDI now = 0
    call LoadCursor                         ;LoadCursor(NULL[0],LoadCursor[arrow,wait,etc])

  ; -----------------------------------
  ; manually coded WNDCLASSEX structure
  ; -----------------------------------
    mov DWORD PTR [ebp-96], 48                          ;size in bytes of the structure (48 bytes)
   
    mov DWORD PTR [ebp-92], CS_VREDRAW or CS_HREDRAW    ;window class style
                                                        ;vredraw redraws whole window if a movement or size adjustment
                                                        ;changes height of area
                                                        ;hredraw redraws if movement or size adjustment changes width
                                                       
    mov DWORD PTR [ebp-88], OFFSET MyWndProc            ;pointer to window procedure
   
    mov DWORD PTR [ebp-84], edi                         ;number of bytes to allocate following window class structure
                                                        ;edi = 0 here

    mov DWORD PTR [ebp-80], edi                         ;number of bytes to allocate following window instance
                                                        ;edi = 0 here still
                                                       
    mov DWORD PTR [ebp-76], esi                         ;400000h - handle instance that contains window procedure
   
    mov DWORD PTR [ebp-72], edi                         ;handle to class icon-must be a resource. 0 gives default icon
                                                        ;edi still = 0

    mov DWORD PTR [ebp-68], eax                         ;handle to class cursor-must be a resource. 0 means application
                                                        ;must explicitly set cursor shape whenever mouse moves into window

    mov DWORD PTR [ebp-64], COLOR_BTNFACE+1             ;handle to background brush-can be physical brush for painting or
                                                        ;can be color value

    mov DWORD PTR [ebp-60], edi                         ;specifies resource name of class menu. 0 means no default menu
   
    mov DWORD PTR [ebp-56], ebx                         ;specifies window class name
                                                        ;ebx contains the string in .data section
   
    mov DWORD PTR [ebp-52], edi                         ;handle to small icon associated with window class


That's as far as I've gotten in my understanding though I haven't had a whole lot of time to look at it lately. Anyway, at this line:
mov DWORD PTR [ebp-68], eax
EAX has not had anything in it. Dave said that EDI always has something in it. Is this true of EAX as well? I'm assuming that EAX=0 right here just because of the syntax for the RegisterClassEx though. If you want the rest of the code I'll post it.

hutch--

Look at the last API called, LoadCursor(). Its return value is in EAX and that is being written to the WNDCLASSEX structure.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

HiddenDragon

Oh! I thought that method calls stored the return value in the first listed register though.

So right there EAX contains the IDC_ARROW value. Thanks hutch!

HiddenDragon

Alright, another clarification.

HWND WINAPI CreateWindowEx(
  __in      DWORD dwExStyle,
  __in_opt  LPCTSTR lpClassName,
  __in_opt  LPCTSTR lpWindowName,
  __in      DWORD dwStyle,
  __in      int x,
  __in      int y,
  __in      int nWidth,
  __in      int nHeight,
  __in_opt  HWND hWndParent,
  __in_opt  HMENU hMenu,
  __in_opt  HINSTANCE hInstance,
  __in_opt  LPVOID lpParam
);


SO these would get pushed in reverse order starting with lpParam right? It should be because it doesn't make sense the other way with the descriptions. However,

typedef struct tagWNDCLASSEX {
  UINT      cbSize;
  UINT      style;
  WNDPROC   lpfnWndProc;
  int       cbClsExtra;
  int       cbWndExtra;
  HINSTANCE hInstance;
  HICON     hIcon;
  HCURSOR   hCursor;
  HBRUSH    hbrBackground;
  LPCTSTR   lpszMenuName;
  LPCTSTR   lpszClassName;
  HICON     hIconSm;
} WNDCLASSEX, *PWNDCLASSEX;


in my window is pushed in the listed order it looks like. What is up with that?

MichaelW

Quote from: HiddenDragon on December 17, 2010, 04:02:35 AM
SO these would get pushed in reverse order starting with lpParam right?

What do you mean by "pushed"?
eschew obfuscation

dedndave

first, the structure is defined for you in windows.inc...
WNDCLASSEX STRUCT
  cbSize            DWORD      ?
  style             DWORD      ?
  lpfnWndProc       DWORD      ?
  cbClsExtra        DWORD      ?
  cbWndExtra        DWORD      ?
  hInstance         DWORD      ?
  hIcon             DWORD      ?
  hCursor           DWORD      ?
  hbrBackground     DWORD      ?
  lpszMenuName      DWORD      ?
  lpszClassName     DWORD      ?
  hIconSm           DWORD      ?
WNDCLASSEX ENDS


structure definitions define a data type - similar to BYTE, WORD, or DWORD
now, to define data using that structure, in the data segment...
        .DATA?

WndClss WNDCLASSEX <>

that creates a structure, named WndClss, of type WNDCLASSEX

you can access the elements in the structure, as shown
then, to use the structure, you pass it's address to the function
(after setting the values in the structure, in this case) for example....
        mov     WndClss.cbSize,sizeof WndClss
        INVOKE  RegisterClassEx,offset WndClss

only the address of the structure is passed (pushed) - not all the individual elements

sizeof WNDCLASSEX would also work to describe the number of bytes in the structure
however, offset WNDCLASSEX will not work, as the type definition itself has no address

you can use offset in this case because the data is globally defined in the uninitialized data segment
most importantly - if the structure is defined locally inside a proc, you must use addr rather than offset
SomeProc PROC

        LOCAL   WndClss:WNDCLASSEX

        mov     WndClss.cbSize,sizeof WndClss
        INVOKE  RegisterClassEx,addr WndClss

this is because the address of WndClss is relative to the stack pointer and referenced by EBP, the stack frame base pointer
the actual code generated in this case is something like this
        push    ebp
        mov     ebp,esp
        sub     esp,48              ;actual size of structure in bytes
        mov     WndClss.cbSize,48
        lea     eax,[ebp-48]        ;address of WndClss
        push    eax
        call    RegisterClassEx