News:

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

Trouble with proc in .inc file.

Started by Yart, September 28, 2011, 11:42:21 AM

Previous topic - Next topic

Yart

Hey guys! First of all, I'd like to introduce myself. I'm Yart, and I've been coding in C++, HTML, BASIC, and some other languages for years now, with my primary interest in game development. I decided to take a stab at ASM because the efficiency and speed is extremely appealing to me and I love doing things with the least amount of resources/smallest footprint possible. I love the challenge.

I learned some basic DOS ASM in college, but I decided to take what I learned and go into Windows 32 development, hoping to make my games in ASM in the future. Crazy? Probably, but it's something I really want to try!


So anyways, it's been years since the last time I did ASM, but looking through Iczelion's MASM32 tutorials ( http://win32assembly.online.fr/tutorials.html ) it was starting to come back to me. I got to Tutorial 3 ( http://win32assembly.online.fr/tut3.html ) and after a lot of typing and hours trying to find a misplaced comma, I finally had it up and working and was proud of my first Window I ever drew in ASM.


I wanted to take the WinMain procedure and put it in a separate .inc file for easy management and to keep things neat and clean (and for re-using later in other programs). However, I ran into a few problems transferring it over to a new file.

I added two more arguments to the prototype, one for ClassName and one for AppName, so it knows what they are in the .inc file (I got an error that it had no clue what it was but this fixed that). Now my problem is this when I try to compile:

Quotewinmain.inc(30) : error A2098: invalid operand for OFFSET

Line 30 is this:

  mov wc.lpszClassName,OFFSET ClassName

Now, I don't know what I'm doing wrong here. That line works when I have all the code inside the main tut3.asm file.

I'll put my code (both files) as an attachment. What am I missing? I can't figure it out, and I've tried Googling the error but I get different results.
And yea it's pretty much an exact copy (with my own notes for my own reference) of the tutorial, only with my attempt to organize it nicer.

Thanks in advance! :)

Tedd

You can't use OFFSET on function arguments. It expects an absolute location (e.g. global variables), whereas arguments and local variables are on the stack, so they're relative to esp (and ebp with a stack frame.)

Pass in ClassName and AppName as pointers to strings, rename them to pClassName and pAppName, and then use them directly as values (no OFFSET or ADDR)


Also, you don't need to strip off the variable names for PROTO, this is fine:

WinMain proto hInst:HINSTANCE,pCmdLine:LPSTR,CmdShow:DWORD,pClassName:DWORD,pAppName:DWORD

(CmdLine is also a pointer to a string, and hPrevInst isn't used since Windows 3.1)
No snowflake in an avalanche feels responsible.

Yart

#2
Alright thanks for the quick reply!

Now I'm pretty fuzzy on pointers for ASM (I don't even recall learning them), but from what I understand I put the address in EAX with mov right?

So like,
mov eax, ClassName
?

And do I do that from outside the procedure? Or am I missing something obvious here?

Yea I'm completely lost when it comes to pointers. Even in C++ I had trouble with 'em. I guess the topic should be "How do I make a pointer?" eh? :P


EDIT: I'm going to relearn basic command line ASM (32-bit) before tackling a Win32 application. If I can't even do pointers yet, I think jumping right to graphical programs will be a little much and silly of me. Haha!

dedndave

QuoteAlso, you don't need to strip off the variable names for PROTO

i find it makes it easier to read if you do, though   :P
what makes sense is to ensure that the types match
i modified the lines like this...

WinMain PROTO :HINSTANCE,:HINSTANCE,:LPSTR,:UINT,:LPSTR,:LPSTR

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:UINT,lpszClassName:LPSTR,lpszAppName:LPSTR

  invoke WinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT,offset szClassName,offset szAppName


if you don't already know...
"lp" is Hungarian notation for long pointer
"p" is for pointer (same as long pointer in win32)
"sz" refers to a zero-terminated string
"lpsz" refers to a long pointer to a zero-terminated string

see attached...

Tedd

Don't worry about pointers, they're actually very simple - too simple - especially when compared to C++ pointers. That's why you don't remember learning them - there isn't anything to learn!

A value is a value.
A pointer is the address/offset of a value, e.g. a variable or a function.

Class dismissed. :bg



The call to WinMain would look like this:

invoke WinMain, hInstance,CommandLine,SW_SHOWDEFAULT,ADDR ClassName,ADDR AppName

;in other words: WinMain(<value>,<pointer_value>,<value>,<pointer>,<pointer>)


And then in WinMain itself:

WinMain proc hInst:HINSTANCE,pCmdLine:LPSTR,CmdShow:DWORD,pClassName:DWORD,pAppName:DWORD
  LOCAL wc:WNDCLASSEX ;create local variables on stack
  LOCAL msg:MSG
  LOCAL hwnd:HWND

  mov wc.cbSize,SIZEOF WNDCLASSEX
  mov wc.style,CS_HREDRAW or CS_VREDRAW
  mov wc.lpfnWndProc, OFFSET WndProc
  mov wc.cbClsExtra,NULL
  mov wc.cbWndExtra,NULL
;using the passed in value
  push hInst
  pop wc.hInstance
  mov wc.hbrBackground,COLOR_WINDOW+1
  mov wc.lpszMenuName,NULL
;pClassName is a pointer to the classname string
;can't do a direct memory-to-memory move
  mov eax,pClassName
  mov wc.lpszClassName,eax
  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 the window class.

  INVOKE CreateWindowEx, NULL,\
;values can be pushed directly though (pointers are values that point to other values)
        pClassName,\
;him too
        pAppName,\
        WS_OVERLAPPEDWINDOW,\
        CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,\
        NULL,\
        NULL,\
        hInst,NULL
  mov hwnd,eax
  invoke ShowWindow, hwnd,CmdShow ;Show the window on desktop.
  invoke UpdateWindow, hwnd ;Refresh client area

;...etc...
  ret
WinMain endp

No snowflake in an avalanche feels responsible.

Tedd

Quote from: dedndave on September 28, 2011, 02:07:04 PM
QuoteAlso, you don't need to strip off the variable names for PROTO

i find it makes it easier to read if you do, though   :P

I wonder what this function does.. Mystery PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD

Yes, very easy to read, but meaningless.
No snowflake in an avalanche feels responsible.

dedndave

Quote from: Tedd on September 28, 2011, 03:10:36 PM
I wonder what this function does.. Mystery PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD

Yes, very easy to read, but meaningless.

:bg
i understand where you're coming from, Ted
but is the list of prototypes where we would look for that info ? - probably not
more likely we would look at the proc for the parameter names and what they are

prototypes describe the proc to the assembler so that it knows what to expect in an INVOKE
have a look at kernel32.inc   :P

hutch--

I personally see the main advantage of PROTO is the data size and count checking rather than its documentation. The matching PROC must have the arguments by name which you can use as the documentation and I tend to put notes in procedures so you can read what they do later but there is nothing wrongs with using named variables in a prototype, just a bit more typing. System function are normally independently documented such as Windows API calls so there is little need to go poking around an include file for the arguments.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

dedndave

well - i do see one drawback in placing parameter names in the prototypes
if you change them, now you have to change them in 2 places
there is a good chance that the PROTOtype may wind up not matching the PROC

Tedd

If you change the parameters, you need to make sure the prototype matches in any case.
The difference is, with parameter names, it's a simple copy-and-paste of one line (and change proc to proto) - quick, easy, no mistakes.
No snowflake in an avalanche feels responsible.