The MASM Forum

General => The Campus => Topic started by: carre89 on November 21, 2012, 07:33:52 AM

Title: [First timer]Window will not show up
Post by: carre89 on November 21, 2012, 07:33:52 AM
I am building off of this post's code,

http://masm32.com/board/index.php?PHPSESSID=c82e3b3915438fd51115a3e79ba09ae8&topic=205.0

I am trying to run my program in visual studio 2010 but it seems that I the window will not show up. Here's my code:

main.asm

TITLE Windows Application                   (WinApp.asm)

; This program displays a resizable application window and
; several popup message boxes.
; Thanks to Tom Joyce for creating a prototype
; from which this program was derived.

__UNICODE__ equ 1           ; UNICODE build

    .686p                       ; create 32 bit code
    .mmx                        ; enable MMX instructions
    .xmm                        ; enable SSE instructions
    .model flat, stdcall        ; 32 bit memory model
    option casemap :none        ; case sensitive
INCLUDE main.inc







;=================== CODE =========================
.code
WinMain PROC


; Get a handle to the current process.
INVOKE GetModuleHandle, NULL
mov hInstance, eax



; Create the application's main window.
; Returns a handle to the main window in EAX.
call createTheWindow

WinMain ENDP

createTheWindow PROC
LOCAL Wwd:DWORD,Wht:DWORD,Wtx:DWORD,Wty:DWORD,mWid:DWORD
    LOCAL wc:WNDCLASSEX

    STRING szClassName,   "Custom_Button_Class"
    STRING szDisplayName, "Custom Bitmap Buttons"

    invoke InitCommonControls

  ; ---------------------------------------------------
  ; set window class attributes in WNDCLASSEX structure
  ; ---------------------------------------------------
    mov wc.cbSize,         sizeof WNDCLASSEX
    mov wc.style,          CS_BYTEALIGNCLIENT or CS_BYTEALIGNWINDOW
    m2m wc.lpfnWndProc,    OFFSET WndProc
    mov wc.cbClsExtra,     NULL
    mov wc.cbWndExtra,     NULL
    m2m wc.hInstance,      hInstance
    m2m wc.hbrBackground,  COLOR_BTNFACE+1
    mov wc.lpszMenuName,   NULL
    mov wc.lpszClassName,  OFFSET szClassName
    m2m wc.hIcon,          hIcon
    m2m wc.hCursor,        hCursor
    m2m wc.hIconSm,        hIcon

  ; ------------------------------------
  ; register class with these attributes
  ; ------------------------------------
    invoke RegisterClassEx, ADDR wc

    mov Wwd, 400
    mov Wht, 425

  ; ------------------------------------------------
  ; Top X and Y co-ordinates for the centered window
  ; ------------------------------------------------
    mov eax, sWid
    sub eax, Wwd                ; sub window width from screen width
    shr eax, 1                  ; divide it by 2
    mov Wtx, eax                ; copy it to variable

    mov eax, sHgt
    sub eax, Wht                ; sub window height from screen height
    shr eax, 1                  ; divide it by 2
    mov Wty, eax                ; copy it to variable

    invoke CreateWindowEx,WS_EX_LEFT or WS_EX_ACCEPTFILES,
                          ADDR szClassName,
                          ADDR szDisplayName,
                          WS_OVERLAPPED,
                          Wtx,Wty,Wwd,Wht,
                          NULL,NULL,
                          hInstance,NULL
    mov hWnd,eax

; ---------------------------------------------------
; calling the custom control for bitmap buttons.
; bitmaps are loaded as resources in the RSRC.RC file
; ---------------------------------------------------
    invoke BmpButton,hWnd,20,20,605,606,500
  ; ---------------------------------------------------

    invoke LoadMenu,hInstance,600
    invoke SetMenu,hWnd,eax

    invoke ShowWindow,hWnd, SW_SHOWNORMAL
    invoke UpdateWindow,hWnd

    call MsgLoop
    ret
createTheWindow endp


; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

MsgLoop proc

    LOCAL msg:MSG

    push ebx
    lea ebx, msg
    jmp getmsg

  msgloop:
    invoke TranslateMessage, ebx
    invoke DispatchMessage,  ebx
  getmsg:
    invoke GetMessage,ebx,0,0,0
    test eax, eax
    jnz msgloop

    pop ebx
    ret

MsgLoop endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

WndProc proc hWin:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD

    LOCAL var    :DWORD
    LOCAL caW    :DWORD
    LOCAL caH    :DWORD
    LOCAL fname  :DWORD
    LOCAL opatn  :DWORD
    LOCAL spatn  :DWORD
    LOCAL rct    :RECT
    LOCAL buffer1[260]:TCHAR ; these are two spare buffers
    LOCAL buffer2[260]:TCHAR ; for text manipulation etc..

    Switch uMsg
      Case WM_COMMAND
      ; -------------------------------------------------------------------
        Switch wParam

     

          case 1999
          app_close:
            invoke SendMessage,hWin,WM_SYSCOMMAND,SC_CLOSE,NULL

        Endsw
      ; -------------------------------------------------------------------

     

      case WM_CREATE

      case WM_SIZE
      case WM_CLOSE
      ; -----------------------------
      ; perform any required cleanups
      ; here before closing.
      ; -----------------------------

      case WM_DESTROY
        invoke PostQuitMessage,NULL
        return 0

    Endsw

    invoke DefWindowProc,hWin,uMsg,wParam,lParam

    ret

WndProc endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

MsgboxI proc hParent:DWORD,pText:DWORD,pTitle:DWORD,mbStyle:DWORD,IconID:DWORD

    LOCAL mbp   :MSGBOXPARAMS

    or mbStyle, MB_USERICON

    mov mbp.cbSize,             SIZEOF mbp
    m2m mbp.hwndOwner,          hParent
    mov mbp.hInstance,          rv(GetModuleHandle,0)
    m2m mbp.lpszText,           pText
    m2m mbp.lpszCaption,        pTitle
    m2m mbp.dwStyle,            mbStyle
    m2m mbp.lpszIcon,           IconID
    mov mbp.dwContextHelpId,    NULL
    mov mbp.lpfnMsgBoxCallback, NULL
    mov mbp.dwLanguageId,       NULL

    invoke MessageBoxIndirect,ADDR mbp

    ret

MsgboxI endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

END WinMain


main.inc

;     include files
;     ~~~~~~~~~~~~~
      include \masm32\INCLUDE\windows.inc
      include \masm32\INCLUDE\masm32.inc
      include \masm32\INCLUDE\gdi32.inc
      include \masm32\INCLUDE\user32.inc
      include \masm32\INCLUDE\kernel32.inc
      include \masm32\INCLUDE\Comctl32.inc
      include \masm32\INCLUDE\comdlg32.inc
      include \masm32\INCLUDE\shell32.inc
      include \masm32\INCLUDE\oleaut32.inc
      include \masm32\INCLUDE\msvcrt.inc

      include \masm32\macros\macros.asm

;     libraries
;     ~~~~~~~~~
      includelib \masm32\LIB\masm32.lib
      includelib \masm32\LIB\gdi32.lib
      includelib \masm32\LIB\user32.lib
      includelib \masm32\LIB\kernel32.lib
      includelib \masm32\LIB\Comctl32.lib
      includelib \masm32\LIB\comdlg32.lib
      includelib \masm32\LIB\shell32.lib
      includelib \masm32\LIB\oleaut32.lib
      includelib \masm32\LIB\msvcrt.lib

; -----------------
; Local prototypes
; -----------------
        WndProc          PROTO :DWORD,:DWORD,:DWORD,:DWORD
        MsgLoop          PROTO
        Main             PROTO
        MsgboxI          PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD

; ÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-÷-

  ; -----------------------------
  ; uninitialised data allocation
  ; -----------------------------
    .data?
        hInstance   dd ?
        hWnd        dd ?
        hIcon       dd ?
        hCursor     dd ?
        CommandLine dd ?
        sWid        dd ?
        sHgt        dd ?


So I am trying to create a basic window with a button in it. The problem is,
a. The window does not come up when I run it
b. I don't know how to load bitmap images. Is there a way to do it without resource files in visual studio? I am not sure what to do...

Title: Re: [First timer]Window will not show up
Post by: dedndave on November 21, 2012, 07:43:06 AM
the first thing i noticed is that WinMain is missing a call to ExitProcess
but, that shouldn't prevent a window from showing up   :P
if i have some time a little later, i will look at it closer

not sure i would use vs 2010 for straight asm code

welcome to the forum   :t
Title: Re: [First timer]Window will not show up
Post by: carre89 on November 21, 2012, 08:00:23 AM
Thankyou for the reply. I just added

"invoke exitprocess, eax"

before WinMain endp

Also I found a procedure that can load a bitmap from a file.

BitmapFromFile proc pszFileName:DWORD

If I have a .bmp file in the project directory, how do I call this function? I tried doing this:

.data
      button dd ?
      buttonPath DWORD "button.bmp",0
.code
       invoke BitmapFromFile, addr buttonPath,0
mov button, eax
       invoke BmpButton,hWnd,20,20,button,button,500


Sorry if these are stupid questions. :redface:
Title: Re: [First timer]Window will not show up
Post by: jj2007 on November 21, 2012, 08:13:51 AM
Check your results for calculating window sizes.
Welcome to the Forum :icon14:

1.   call createTheWindow
   exit

2.    invoke CreateWindowEx,WS_EX_LEFT or WS_EX_ACCEPTFILES,
                          ADDR szClassName,
                          ADDR szDisplayName,
                          WS_OVERLAPPED,
                          100,100,400,300,
                          NULL,NULL,
                          hInstance,NULL
    mov hWnd,eax


You might shorten it a little bit:
include \masm32\MasmBasic\MasmBasic.inc   ; download (http://www.masm32.com/board/index.php?topic=94.0)
TITLE Windows Application                   (WinApp.asm)

; -----------------

[delete all that header stuff, including the include main.inc - it saves typing]

; Local prototypes
; -----------------
... and then insert one line to see what's going on:
    mov Wty, eax                ; copy it to variable
   deb (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1018) 1, "Win", Wwd, Wht, Wtx, Wty

Hint: shr instead of sar is one problem, but not the only one.
Title: Re: [First timer]Window will not show up
Post by: dedndave on November 21, 2012, 08:19:11 AM
it should be...
        invoke  ExitProcess,eax
the case is not important for "invoke" or "eax", but it is for the function name

EDIT: i see Jochen used the "exit" macro, instead   :P
a little simpler, but does not return the value in EAX - it always returns 0 (a minor point, really)

i haven't used that function from the masm32 library
but - it probably calls LoadImage

http://msdn.microsoft.com/en-us/library/windows/desktop/ms648045%28v=vs.85%29.aspx (http://msdn.microsoft.com/en-us/library/windows/desktop/ms648045%28v=vs.85%29.aspx)

the filename string should be declared in the .DATA section
then, you pass the address of that string (a "pointer") to the function

this code should yield an HBITMAP (bitmap handle) in eax
        .DATA

szButtonBmp db 'button.bmp',0

        .CODE

        INVOKE  LoadImage,NULL,offset szButtonBmp,IMAGE_BITMAP,NULL,NULL,LR_LOADFROMFILE


notice that the filename string is defined using DB, not DW
if you want a UNICODE string, probably best to use a macro or something

when you are done using the HBITMAP, you should use DeleteObject to release the handle   :t
Title: Re: [First timer]Window will not show up
Post by: CommonTater on November 21, 2012, 08:29:50 AM
Quote from: carre89 on November 21, 2012, 07:33:52 AM

    invoke CreateWindowEx,WS_EX_LEFT or WS_EX_ACCEPTFILES,
                          ADDR szClassName,
                          ADDR szDisplayName,
                          WS_OVERLAPPED | WS_VISIBLE,                       <---- here
                          Wtx,Wty,Wwd,Wht,
                          NULL,NULL,
                          hInstance,NULL

So I am trying to create a basic window with a button in it. The problem is,
a. The window does not come up when I run it

You need to either tell it to be visible with WS_VISIBLE or invoke ShowWindow() to make it pop up on the screen.  Windows are not visible by default...


Title: Re: [First timer]Window will not show up
Post by: carre89 on November 21, 2012, 08:31:55 AM
YES! That worked! And I made the modifications to load the bitmap to a button but the button doesn't show up.
Here is a .zip of my project.
Title: Re: [First timer]Window will not show up
Post by: hutch-- on November 21, 2012, 08:32:15 AM
 :biggrin:

> Sorry if these are stupid questions.

No need to apologise, if you have seen some of the messes that we have all made, you would laugh too.  :P
Title: Re: [First timer]Window will not show up
Post by: carre89 on November 21, 2012, 09:51:48 AM
So I cleaned up the code a little bit by removing everything that I am not using. I am going to try to figure out why load .bmp isn't working and try to get a button to showup in the window. I attach my project just in case anyone wants to take a crack at it.
Title: Re: [First timer]Window will not show up
Post by: hutch-- on November 21, 2012, 10:35:32 AM
I don't have time today but make a point of checking the return value of LoadBitmap.
Title: Re: [First timer]Window will not show up
Post by: dedndave on November 21, 2012, 12:13:07 PM
you have defined __UNICODE__ = 1
so - when you call LoadImage, it is actually using LoadImageW
that function wants a UNICODE string for the filename

there are a few ways to fix this issue:

1) if there is no reason to create a UNICODE version, don't define __UNICODE__
    all the strings will then be ASCII
2) define the filename string using TCHARS or WORDS, each character individually
szButtonBmp TCHAR 'b','u','t','t','o','n','.','b','m','p',0
3) use a macro to create the UNICODE string - i forget what the name of the macro is   :P
4) create a UNICODE program, but call LoadImageA explicitly and use an ASCII string
Title: Re: [First timer]Window will not show up
Post by: carre89 on November 22, 2012, 04:10:52 AM
I would like to take approach #1. I am wasn't taught the differences between character encodings in assembly so I would rather not dabble with that. So I commented out the unicode declaration but now my program is trying to access illegal memory addresses. I have no idea why it's crashing. Here is a copy of the latest revision to my project if anyway wants to take a look at it.

Thank you guys for your help so far.   :t

PS: Is there a way to know if the bmpbutton was right clicked?
Title: Re: [First timer]Window will not show up
Post by: dedndave on November 22, 2012, 04:33:59 AM
i don't have VC set up - lol
and - even if i did, i am not much of a C programmer   :P

give me a few minutes to make an asm version...
Title: Re: [First timer]Window will not show up
Post by: dedndave on November 22, 2012, 07:45:53 AM
ok - fixed a few minor things...

used COLOR_BTNFACE+1 as the class background color and IDC_ARROW as the class cursor
used WS_OVERLAPPEDWINDOW for the window style - this gives you the min/max/close buttons in the title bar
swapped the names of "hWin" and "hWnd" - this is what we are used to, is all   :P
also - i initialize hWin in WM_CREATE rather than in the main code - my preference
moved the image load code from the main routine to WM_CREATE
reorganized the program a bit - it was looking pretty sloppy - lol

at this point, i can use LoadImage to create a valid handle for the image from file
for the fun of it, i created a static control to show the loaded image

now - for the real problem...
the BmpButton routine contained in the masm32 package is designed to use 2 images from resource
eventually, you are probably going to want to put these images in resource, rather than access them from files

however, the routine could use a few improvements
it requires an image ID for the "up" and "down" button states - you could probably use the same image for both
more importantly, it does not allow for the use of an image strip
ideally, multiple images are placed in a single resource bitmap, then accessed by an x-coord index
another issue is that the routine always creates buttons that are 100 x 100
then, it creates a static control inside the button for the image
static controls automatically resize themselves to an image - buttons do not   :P

maybe i will make a new routine later on
i have a custom button routine already written - which always uses 16 x 16 images from a strip
it creates buttons with borders and states - very similar to the MFC ones like those used in MS Paint
so - a little modification is all that we'd need to make it size-to-image

but - i am working on a little bug with my buttons - this is my current project, as it happens
i provide for a message to set the button state, type, tool-tip string, etc
if you send that message when handling a button click - things get a little messed up - lol
it seems to be a thread-conflict issue - i'm not sure - so, i am working on that
Title: Re: [First timer]Window will not show up
Post by: dedndave on November 22, 2012, 09:07:56 AM
giving this a little more thought....

if you want to create a grid-type game, like mine sweeper, you probably don't want to use individual buttons
in "advanced" mode, WinMine creates 30 x 16 squares - that would be 480 buttons - lol
that seems like an awful lot of system resources for a simple game
also - windows standard buttons don't send messages to the parent window for right-clicks
they have borders and can also have rounded corners - not what you're after

it would make much more sense to just handle the displayed grid in WM_PAINT
and handle the mouse clicks by calculating the grid location - essentially making one big customized button, if you will
set up an array that holds the state for each grid square
Title: Re: [First timer]Window will not show up
Post by: MichaelW on November 22, 2012, 09:10:00 AM
If the buttons are supposed to behave as the Minesweeper buttons do, then all of the functionality that the MASM32 bitmap button example implements will not be necessary. You will have the initial button face that is replaced by any one of ~11 "flat" bitmaps when the button is actuated.

Title: Re: [First timer]Window will not show up
Post by: dedndave on November 22, 2012, 09:15:49 AM
yah - that is way overkill

here is the bitmap used by WinMine
it is oriented vertically instead of horizonally (don't know why - i would use horz)
it kind of tells you that they are not using individual buttons

(http://img528.imageshack.us/img528/2180/37315174.png)
Title: Re: [First timer]Window will not show up
Post by: CommonTater on November 22, 2012, 09:26:08 AM
Quote from: dedndave on November 22, 2012, 09:07:56 AM
it would make much more sense to just handle the displayed grid in WM_PAINT
and handle the mouse clicks by calculating the grid location - essentially making one big customized button, if you will
set up an array that holds the state for each grid square

The WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_RBUTTONDOWN and GetCursorPos() would be particularly suited to this kind of activity.  It's actually pretty easy to do...

Title: Re: [First timer]Window will not show up
Post by: dedndave on November 22, 2012, 09:32:42 AM
i think you can do it with just WM_LBUTTONDOWN and WM_RBUTTONDOWN
those 2 messages provide the cursor position in wParam, as i recall
you don't care about WM_MOUSEMOVE, capturing the mouse or any of that
it would be pretty simple, i think

if you wanted to use a small array, 1 byte for each grid-square would be plenty
use the lower 4 bits to hold the current displayed state and the upper 4 bits to hold the "hidden" contents
something like that   :P
Title: Re: [First timer]Window will not show up
Post by: CommonTater on November 22, 2012, 10:07:39 AM
Quote from: dedndave on November 22, 2012, 09:32:42 AM
i think you can do it with just WM_LBUTTONDOWN and WM_RBUTTONDOWN
those 2 messages provide the cursor position in wParam, as i recall
you don't care about WM_MOUSEMOVE, capturing the mouse or any of that
it would be pretty simple, i think

if you wanted to use a small array, 1 byte for each grid-square would be plenty
use the lower 4 bits to hold the current displayed state and the upper 4 bits to hold the "hidden" contents
something like that   :P

The WM_MOUSEMOVE message provides a real quick check to see if the mouse is inside the program's window or not... inside the window you get a stream of them, but they stop at the border.

Title: Re: [First timer]Window will not show up
Post by: dedndave on November 22, 2012, 10:57:30 AM
right - but in mine sweeper, nothing changes on mouse movement
only when you click does something happen
the program doesn't have to consume a lot of processor cycles handling all those WM_MOUSEMOVE's
Title: Re: [First timer]Window will not show up
Post by: CommonTater on November 22, 2012, 11:29:05 AM
Quote from: dedndave on November 22, 2012, 10:57:30 AM
right - but in mine sweeper, nothing changes on mouse movement
only when you click does something happen
the program doesn't have to consume a lot of processor cycles handling all those WM_MOUSEMOVE's

true.
Title: Re: [First timer]Window will not show up
Post by: carre89 on November 22, 2012, 02:22:15 PM
That sounds like a better idea haha. Do you know a project/tutorial that I can work off - I need to have this done by next week... Thank you for your help so far.
Title: Re: [First timer]Window will not show up
Post by: dedndave on November 22, 2012, 02:29:49 PM
not off-hand
if time permits, i may do a very basic one tomorrow, just so you get the idea
Title: Re: [First timer]Window will not show up
Post by: carre89 on November 24, 2012, 12:37:33 PM
So I did a little bit work on it. I found this basic tutorial on how to paint to the Window,
http://www.asmcommunity.net/book/tutorials/iczelion/simple-bitmap

Using this tutorial I was able to paint a cell/button to the window. Now I need to figure out how to catch click events in the window properly. Can someone show me a quick code snippet of catch a mouse click event and getting it's position?

How do I repaint the window with the updated cells?

If you look at my code you can see I added alot of new procedures and structures to the program. Most notably a minefield struct. The problem is I am not sure how to use it properly as it seems. I am getting some sort of error.

I am going to try to figure as much as I can by myself and update this post accordingly. Once again thankyou for your help so far. This has been the most helpful forum I have ever used.  :greenclp: :greenclp: :greenclp:

Edit ********************
I have another quick question. Is it possible to have a struct within a struct? I was thinking about creating a cell struct within the minefield struct that would contain the properties of each cell(e.g. opened || closed, mine || num etc). So I would have an array of mines within the minefield struct. It would make accessing each of the cell's properties much easier and clearer.
Title: Re: [First timer]Window will not show up
Post by: dedndave on November 24, 2012, 01:00:29 PM
you can just handle the WM_LBUTTONDOWN and WM_RBUTTONDOWN messages

    .elseif uMsg==WM_LBUTTONDOWN
        movzx   ecx,word ptr lParam    ;ECX = X client coordinate
        movzx   edx,word ptr lParam+2  ;EDX = Y client coordinate

        ;rest of button click code

        xor     eax,eax                ;return 0
Title: Re: [First timer]Window will not show up
Post by: dedndave on November 24, 2012, 01:03:03 PM
as for repainting, i was thinking of having a 256-color DIB section for the grid area
then, you can modify the bytes directly for a specific square
then, create a RECT that outlines that square and pass it to InvalidateRect
then call UpdateWindow and let the paint routine update just that square

you can create a byte array for the grid
each byte can represent a grid square
the upper 4 bits can be used as an index (0-15) into the image strip, indicating the current display state
the lower 4 bits can describe what the hidden content is
Title: Re: [First timer]Window will not show up
Post by: CommonTater on November 24, 2012, 01:47:22 PM
Quote from: carre89 on November 24, 2012, 12:37:33 PM
How do I repaint the window with the updated cells?

You might want to look into the BitBlt (http://http://msdn.microsoft.com/en-us/library/aa930997.aspx) function in the Windows API

This would require you to store small bitmaps for each button state in your program's resources (a common technique) and drop them into place as needed.
Title: Re: [First timer]Window will not show up
Post by: carre89 on November 24, 2012, 02:21:22 PM
I think I got a little bit ahead of myself. I had a lot of coffee today :dazzled: . I want to focus on getting it to run first before I worry about anything else.

So I divided up the project into separate source files. main.asm handling the painting while all my minefield functions are in minefield.asm. I just commented a bunch of code I that I'll worry about later. What I need to figure out is why my MineFieldStruct is throwing me an error;

fatal error A1010: unmatched block nesting : MineField

I attached my latest revision if anybody wants to look at it.
Title: Re: [First timer]Window will not show up
Post by: dedndave on November 24, 2012, 02:37:25 PM
MineFieldStruct STRUCT
;
;
;
MineField ENDS


the name you use to open a structure definition should match the one you use to close   :P
block nesting errors are usually easy "operator error" problems - lol

get some sleep
i started a program for this - was busy yesterday and today
maybe i'll finish it off tomorrow
Title: Re: [First timer]Window will not show up
Post by: carre89 on November 24, 2012, 02:47:10 PM
 :shock:.....
Alrite I'll see you guys tomorrow.... I'll clean up the code up a bit tomorrow..
Title: Re: [First timer]Window will not show up
Post by: qWord on November 24, 2012, 03:27:35 PM
- function prototypes are declared using PROTO:
function name [C|STDCALL|...] [PUBLIC|PRIVATE] [arg1]:TYPE,[arg2]:TYPE,...
(note that all prototypes/procs are public by default)

- If you want to split a declaration in several lines, use '\':
foo proto \ ; comment 1
arg1:type \ ; comment 2
arg2:type ; xyz


- a procedure/function body is declared with:
fncName PROC [C|SDTCALL|...] [PUBLIC|PRIVAT]] [uses reg-list] arg1:type,arg2:type,...
; code
fncName ENDP


- your code use a structure before it is declared
- Your header structure is no proper for a modular program.(?)
- use DWORD instead of all that bytes parameters and variables
- do not use structures as function argument**
- do not use LOOP
- you can't use 16 bit registers as pointers
- use a IDE that is designed for MASM
- You should stay away from this project until you have learned the basics...

Title: Re: [First timer]Window will not show up
Post by: dedndave on November 25, 2012, 01:58:32 PM
i spent a little time on it, today - got the hard part done   :P
Title: Re: [First timer]Window will not show up
Post by: carre89 on November 26, 2012, 12:02:16 PM
So I imported your code into visual studio and I am getting a linking error;

"error LNK2019: unresolved external symbol _generateMineField@12 referenced in function _WinMain@0"

Edit - nevermind, I think I figured it out.

Title: Re: [First timer]Window will not show up
Post by: qWord on November 26, 2012, 12:22:12 PM
Well, I was not sure if you want a modular program (that how your org. code look like) or a "all in one file by includes"-project.
You can either configure VS thus minefield.asm get assembled as a module, or modify the file so that it can be included in main.asm.
Title: Re: [First timer]Window will not show up
Post by: carre89 on November 26, 2012, 01:16:44 PM
I am reading up on it right now. I want to have the minefield procedures in one source file and the painting and main in the other. I think I am prototyping incorrectting. How would you organize the program?
Title: Re: [First timer]Window will not show up
Post by: carre89 on November 30, 2012, 06:21:32 AM
I am looking at your code and I am trying to figure out what is happening. Could someone step through the code and explain what is happening? I made comments next to the instructions that I am confused about.

;-----------------------------------------------------
; do not use BYTE for arguments (MASM bug)
generateMineField PROC uses esi edi\
NOC:DWORD, \ ; number of columns in grid - has to be less than 255
NOR:DWORD, \ ; number of rows in grid - has to be less than 255
NOM:DWORD ; number of mines

;
; Generates a minefield
; Returns: EAX = address of MineField Struct
;-----------------------------------------------------
LOCAL pmf:ptr MineFieldStruct
LOCAL dwSize:DWORD

mov esi,alloc(SIZEOF MineFieldStruct)             

m2m [esi].MineFieldStruct.FieldWidth, NOC
m2m [esi].MineFieldStruct.FieldHeight, NOR
m2m [esi].MineFieldStruct.NumOfMines, NOM         ; What is m2m instruction?

mov edx,NOC
imul edx,NOR
lea edx,[edx*2]                                                        ; As I understand this calculates the row size in bytes. Since each cell is a DWORD, wouldn't you multiply it by 4?
mov dwSize,edx
mov [esi].MineFieldStruct.Field, alloc(edx)                ; Not sure what is happening here.

; fill array with "random" data
mov edi,eax
fn RandomBytes,dwSize,edi                                    ; Do we need to do this? Can we set each cell to zero first?
xor ecx,ecx                                                               ; I see you are doing this several times through the program. Why do you need to do this? If you xor the reg with itself ;   
                                                                                         ; isn't the answer the same?
.while ecx < dwSize
.if WORD ptr [edi+ecx] < 0ffffh/3                      ; where did you move the field pointer to the esi?
mov BYTE ptr [edi+ecx+1],CLOSED
.elseif WORD ptr [edi+ecx] < 0ffffh*2/3
mov BYTE ptr [edi+ecx+1],OPENED
.else
mov BYTE ptr [edi+ecx+1],FLAGGED
.endif
add ecx,2                                                  ; Why are adding 2? I thought each cell is 4 bytes in size.
.endw

m2m [esi].MineFieldStruct.RowSize, NOC

Invoke calcArea,[esi].MineFieldStruct


COMMENT !
;don't care about this yet <- bullshit

Invoke setUpMines,
ADDR mf
!

mov eax,esi

ret
generateMineField endp


EDIT: -----------------------------------

I revised the generateMineField proc to the best of my ability but now it's crashing the program.

generateMineField PROC uses esi edi\
NOC:DWORD, \ ; number of columns in grid - has to be less than 255
NOR:DWORD, \ ; number of rows in grid - has to be less than 255
NOM:DWORD ; number of mines

;
; Generates a minefield
; Returns: EAX = address of MineField Struct
;-----------------------------------------------------
LOCAL pmf:ptr MineFieldStruct
LOCAL rowSize:DWORD

mov esi,alloc(SIZEOF MineFieldStruct)

m2m [esi].MineFieldStruct.FieldWidth, NOC
m2m [esi].MineFieldStruct.FieldHeight, NOR
m2m [esi].MineFieldStruct.NumOfMines, NOM

mov edx,NOC
imul edx,NOR
lea edx,[edx*4] ; NOC*4 - Calculates rowsize in bytes
mov rowSize,edx
mov [esi].MineFieldStruct.Field, alloc(edx)

xor ecx,ecx
.while ecx < rowSize
mov BYTE ptr [edi+ecx+1],CLOSED
add ecx,4
.endw

Invoke calcArea,[esi].MineFieldStruct

mov eax,esi

ret
generateMineField endp
Title: Re: [First timer]Window will not show up
Post by: dedndave on November 30, 2012, 06:41:18 AM
m2m is a macro - not an instruction
it is a "memory-to-memory" move
for intel processors, there is no instruction for doing this in a single opcode
there are a few obscure ways to copy the contents of memory from one location to another in a single instruction
MOVS is an example, but it requires that ESI and EDI are pointers to these addresses
i believe the macro PUSH's the source content on the stack, then POP's it into the destination

mov edx,NOC
imul edx,NOR
lea edx,[edx*2]  ; As I understand this calculates the row size in bytes. Since each cell is a DWORD, wouldn't you multiply it by 4?

this code calculates the total number of squares or cells (rows times columns)
i didn't think you could use IMUL with a memory operand - don't know where i got that idea - lol

mov [esi].MineFieldStruct.Field, alloc(edx)   ; Not sure what is happening here.
the first instruction of the routine sets ESI to the base address of an allocated memory (alloc) block
(alloc is another macro used to allocate memory)
this is a structure that is defined previously in the source
mov esi,alloc(SIZEOF MineFieldStruct)
don't know whose code this is, but i probably wouldn't have used allocated memory for the structure - lol
anyways, if you look at the MineFieldStruct definition, one of the members is named "Field"
so - a second allocated block (used for the grid or field array) is pointed to by this value

working on the other questions in following posts...
Title: Re: [First timer]Window will not show up
Post by: qWord on November 30, 2012, 06:55:31 AM
Quote from: dedndave on November 30, 2012, 06:41:18 AMi didn't think you could use IMUL with a memory operand
Yes, we can!  :P
Quote from: dedndave on November 30, 2012, 06:41:18 AM
mov esi,alloc(SIZEOF MineFieldStruct)
don't know whose code this is, but i probably wouldn't have used allocated memory for the structure - lol
thats my quick modification of his clumsy HLL to ASM port. The reason for this was that he tries to pass all structures and arrays by value in and out of functions. I was simply too lazy to correct that in this case...

Title: Re: [First timer]Window will not show up
Post by: dedndave on November 30, 2012, 07:06:00 AM
ok - looking at both code snippets, i am a bit confused - lol

i hesitate to critique code written by qWord, because i know he usually writes great stuff   :biggrin:

first, i would not use allocated memory to hold the structure
it is a small amount of memory - more efficient to put it in the uninitialized data section

the same holds true for the grid array, actually
you can only get so many squares on the screen
because the squares are 32x32 pixels, i would think 8 Kb would be plenty for any grid (1 byte per cell)
this prevents allocating, freeing, and reallocating memory over and over
even if you use 1 dword per cell, 32 Kb isn't too much for uninitialized data

if you don't want to put it in uninitialized data, allocate it once at the beginning of the program
and free it once at the end - make it big enough to handle all practical array sizes

as for the random thing...
when a block of memory is allocated using the "alloc" macro, it is zeroed for you
      alloc MACRO bytecount
        invoke GlobalAlloc,GMEM_FIXED or GMEM_ZEROINIT,bytecount
        EXITM <eax>
      ENDM


if you use the uninitialized data area, you will want to zero it before each use
after that, you want to randomly fill it with mines
so - you generate a random offset into the array
if that cell isn't already a mine, make it a mine
if it is already a mine - go back and get another random index
repeat that until the requested number of mines are assigned to cells
Title: Re: [First timer]Window will not show up
Post by: qWord on November 30, 2012, 07:09:59 AM
BTW: I assumed that a cell is represented by 16 bits.
Title: Re: [First timer]Window will not show up
Post by: dedndave on November 30, 2012, 07:11:34 AM
i am writing a program for this
i am using a single byte for each square   :P
Title: Re: [First timer]Window will not show up
Post by: carre89 on November 30, 2012, 09:04:50 AM
So right now I am focusing on getting generateMineField PROC and setUpMines PROC working correctly. Here's what I have right now.


;-----------------------------------------------------
; do not use BYTE for arguments (MASM bug)
generateMineField PROC uses esi edi\
NOC:DWORD, \ ; number of columns in grid - has to be less than 255
NOR:DWORD, \ ; number of rows in grid - has to be less than 255
NOM:DWORD ; number of mines

;
; Generates a minefield
; Returns: EAX = address of MineField Struct
;-----------------------------------------------------
LOCAL pmf:ptr MineFieldStruct
LOCAL gridSize:DWORD

mov esi,alloc(SIZEOF MineFieldStruct)

m2m [esi].MineFieldStruct.FieldWidth, NOC
m2m [esi].MineFieldStruct.FieldHeight, NOR
m2m [esi].MineFieldStruct.NumOfMines, NOM

mov edx,NOC
imul edx,NOR
mov [esi].MineFieldStruct.FieldArea, edx ; set FieldArea to the number of cells
lea edx,[edx*4] ; Calculates gridSize in BYTES
mov gridSize,edx
mov [esi].MineFieldStruct.Field, alloc(edx)

xor ecx,ecx
; set each cell opened so I can see what is generated
.while ecx < gridSize
mov BYTE ptr [edi+ecx+2],OPENED
add ecx,4
.endw
INVOKE setUpMines esi ; Go through the grid and put in the mines at random positions

;let's focus on the setUpMines proc
;INVOKE incAdj esi ; set the numbers in each cell

mov eax,esi

ret
generateMineField endp

;-----------------------------------------------------
setUpMines PROC mf:MineFieldStruct
;
; Generates a blank minefield - every cell is zero
; Returns: Nothing
; Checks: number of mines less than number of cells and is not zero. Also needs to check if minefield has been generated
;-----------------------------------------------------
pushad ; push all registers to the stack

mov eax, 0
mov ebx, 0
mov ecx, 0
mov edx, 0
mov esi, 0

mov si, MINE
mov cl, mf.NumOfMines
mov eax, offset mf.Field
mov ebx, TYPE mf.Field

call randomize
mineLoop:
mov edx, offset mf.Field
mov eax, mf.FieldArea
call RandomRange ; Random range generates a number from 0 to the number in the eax.[exclusive - so not
mul ebx ; multiply by cell size
add edx, eax
.IF dl == MINE
jmp mineLoop
.ELSE
mov dl, MINE
.ENDIF
loop mineLoop

popad
ret
setUpMines endp


I also attached my project if anyone wants to take a look at it. As you probably see I am getting alot of errors right now because i redid the incAdj and getcell procedures. I am going to try to fix as many errors as I can figure out and then up upload the project.
Title: Re: [First timer]Window will not show up
Post by: carre89 on November 30, 2012, 09:31:47 AM
Made a couple of small changes
Title: Re: [First timer]Window will not show up
Post by: carre89 on November 30, 2012, 09:54:23 AM
Now I have two syntax errors left
1>main.asm(534): error A2070: invalid instruction operands
@ .if x<0 || mf.FieldWidth <= x || y<0 || mf.FieldHeight <= y

getCell PROC uses esi \
mf:MineFieldStruct, \
x:DWORD, \ ; row index
y:DWORD \ ; column index
;
; returns the cell's value at x-y point specified
; if specified row and column are out of range it returns OUTBOUNDS
; Returns: EAX = cell address
;-----------------------------------------------------

; check if it's in the minefield bounds
.if x<0 || mf.FieldWidth <= x || y<0 || mf.FieldHeight <= y
mov eax, OFFBOUNDS
.else
mov eax, x
mov esi, y
mov ebx, mf.RowSize
mul ebx
add eax, mf.Field
.endif

ret
getCell endp



1>main.asm(470): error A2133: register value overwritten by INVOKE
@ invoke IncSp, mf, eax, tempX, tempY
;-----------------------------------------------------
incAdj PROC, mf:MineFieldStruct
;
;Goes through whole grid and calls IncSp for any cell that is not a mine
;-----------------------------------------------------
LOCAL tempX:BYTE ; used to keep track of current position in grid
LOCAL tempY:BYTE

mov tempX, 0
mov tempY, 0

mov ecx, 0
mov eax, 0
mov esi, mf.Field
mov ecx, mf.FieldHeight
loopY: ;go to each row
push ecx
mov ecx, mf.FieldWidth
loopX: ;go to each column in each row
mov eax, 0
mov eax,[esi]
.if al != MINE ;if the current grid spot is not a bomb
[b]invoke IncSp, mf, eax, tempX, tempY[/b]
.endif
inc tempX
add esi, 4 ;mov to next spot in grid
loop loopX
mov tempX, 0 ;reset to beginning of the col
inc tempY ;go to next col

pop ecx
loop loopY

ret
incAdj ENDP
Title: Re: [First timer]Window will not show up
Post by: dedndave on November 30, 2012, 11:30:06 AM
for this line: .if x<0 || mf.FieldWidth <= x || y<0 || mf.FieldHeight <= y

mf.FieldWidth <= x
and
mf.FieldHeight <= y

are both problematic
you cannot compare one memory value to another memory value
one of the operands  must be in register

for this line: invoke IncSp, mf, eax, tempX, tempY
that line does not appear to be a problem

if you had: invoke IncSp, mf, eax, tempX, addr tempY
that would be a problem because the assembler uses EAX to hold the address of tempY

be sure you are showing us the correct line
Title: Re: [First timer]Window will not show up
Post by: nidud on November 30, 2012, 11:59:16 AM
deleted
Title: Re: [First timer]Window will not show up
Post by: dedndave on November 30, 2012, 12:27:47 PM
Quote from: dedndave on November 30, 2012, 11:30:06 AM
you cannot compare one memory value to another memory value
one of the operands  must be in register
correction:
one of the operands  must be in register or a constant   :P
Title: Re: [First timer]Window will not show up
Post by: carre89 on December 01, 2012, 06:05:24 AM
So I fixed the bool expression but I don't know what to do to fix the invoke statement. Any ideas?
Title: Re: [First timer]Window will not show up
Post by: dedndave on December 01, 2012, 06:29:32 AM
if you attach the complete source, i will have a look at it
i need all of it - the INC files, batch files, etc

the reason i say that - i am not sure you are showing us the offending line of code
no use troubleshooting something that isn't broken   :P
Title: Re: [First timer]Window will not show up
Post by: qWord on December 01, 2012, 06:38:43 AM
Quote from: carre89 on December 01, 2012, 06:05:24 AM
So I fixed the bool expression but I don't know what to do to fix the invoke statement. Any ideas?
DO NOT pass structures by value -> use pointers instead.
Title: Re: [First timer]Window will not show up
Post by: dedndave on December 01, 2012, 06:44:44 AM
invoke IncSp, mf, eax, tempX, tempY

that should pass the address of the mf structure - not a value
either way, it should not interfere with the contents of EAX
Title: Re: [First timer]Window will not show up
Post by: nidud on December 01, 2012, 08:06:35 AM
deleted
Title: Re: [First timer]Window will not show up
Post by: jj2007 on December 01, 2012, 06:58:33 PM
See also Tips, Tricks & Traps (http://www.webalice.it/jj2006/Masm32_Tips_Tricks_and_Traps.htm), "The .if eax<0 trap"

Workaround is very simple:
signed   EQU sdword ptr ; with a trailing blank - borrowed from MasmBasic (http://www.masm32.com/board/index.php?topic=94.0) ;-)

.if signed eax<0
   print "voilà, it works!"
.endif

For memory variables, it is even simpler:
.data
MyX SDWORD 123
Title: Re: [First timer]Window will not show up
Post by: dedndave on December 02, 2012, 03:43:58 AM
i don't think the "<0" comparisons are necessary, at all
negative values will fail the max limit test because, in unsigned comparison, they appear to be very large values

for example, -1 will be compared as +4294967295
-2147483648 will be compared as +2147483648

.if mf.FieldWidth <= x || mf.FieldHeight <= y
almost works - lol

you still have to get one of each operand into register...
mov ecx,x
mov edx,y
.if ecx >= mf.FieldWidth || edx >= mf.FieldHeight

give that a try
Title: Re: [First timer]Window will not show up
Post by: dedndave on December 03, 2012, 07:19:40 AM
Quote from: qWord on November 30, 2012, 06:55:31 AM
Quote from: dedndave on November 30, 2012, 06:41:18 AMi didn't think you could use IMUL with a memory operand
Yes, we can!  :P

now i remember   :biggrin:

you can't IMUL by a register - it has to be a constant or a memory operand
Title: Re: [First timer]Window will not show up
Post by: qWord on December 03, 2012, 08:51:26 AM
Quote from: dedndave on December 03, 2012, 07:19:40 AM
now i remember   :biggrin:

you can't IMUL by a register - it has to be a constant or a memory operand
we can IMUL by a register (or at least, I can). Also, what to remember?  - a quick look up in the manuals should clarifies it  :badgrin:
Title: Re: [First timer]Window will not show up
Post by: dedndave on December 03, 2012, 09:19:38 AM
one of the operands can be a register - but one cannot - at least, that's what i get - lol
imul eax,5    ;works
imul eax,edx  ;doesn't work


remember - i try to memorize everything so i don't have to look it up all the time   :biggrin:

anyways, here's what i have so far
the array is also initialized with mines and numbers
now - a few easy routines to manipulate things and i will let Carre do the rest of it   :P

(http://img842.imageshack.us/img842/7251/sweep01.png)
Title: Re: [First timer]Window will not show up
Post by: qWord on December 03, 2012, 09:35:43 AM
Quote from: dedndave on December 03, 2012, 09:19:38 AMimul eax,5    ;works
imul eax,edx  ;doesn't work <- it does! eax = eax*edx

Title: Re: [First timer]Window will not show up
Post by: dedndave on December 03, 2012, 10:24:38 AM
ok - i had trouble with that one
i will play with it later
i just remember there was something i was trying to do and had to use MUL
it may be i had a typo in my code or something

getting old - my brain isn't what it used to be   :P
Title: Re: [First timer]Window will not show up
Post by: Gunther on December 03, 2012, 08:19:10 PM
Dave,

qWord is right: one can imul with a register. Your example works properly.

Gunther
Title: Re: [First timer]Window will not show up
Post by: dedndave on December 03, 2012, 10:49:53 PM
yah - i must have had a typo that led me to believe that or something   :P
Title: Re: [First timer]Window will not show up
Post by: dedndave on December 04, 2012, 11:39:29 AM
 :P

(http://img341.imageshack.us/img341/5931/sweep02.png)
Title: Re: [First timer]Window will not show up
Post by: Gunther on December 04, 2012, 10:02:11 PM
Or it was the game?  :lol:

Gunther
Title: Re: [First timer]Window will not show up
Post by: dedndave on December 05, 2012, 07:22:00 AM
i am not writing the complete game - just enough to get started, really
i have a bigger project that i am working on
when i need a break from that, i spend a little time on this
i just have to write a couple more routines and do some clean-up and i will post it   :t
Title: Re: [First timer]Window will not show up
Post by: dedndave on December 06, 2012, 06:00:05 AM
ok - here we go....

the game plays,
however - the ms minesweeper game sometimes reveals several squares
sort of a poly-line fill algo
i don't know the rules on when to multi/single reveal
and - i don't know the rules on which squares to multi-reveal
(i kind of have an idea what the rules are - lol)
so - i did not implement that part

also - there is no menu, game clock, score-keeper, user selections, etc
i leave that stuff up to you

it does show you how to present the grid square graphics   :t
it also handles various size grids - resizing the window - all that

(http://img40.imageshack.us/img40/4199/sweep03.png)
Title: Re: [First timer]Window will not show up
Post by: FORTRANS on December 06, 2012, 09:23:51 AM
Quote from: dedndave on December 06, 2012, 06:00:05 AM
ok - here we go....

the game plays,
however - the ms minesweeper game sometimes reveals several squares
sort of a poly-line fill algo
i don't know the rules on when to multi/single reveal
and - i don't know the rules on which squares to multi-reveal

Hi,

   I think they reveal a cell that would be next to an exposed
zero count.  Looks good.

Cheers,

Steve N.
Title: Re: [First timer]Window will not show up
Post by: dedndave on December 06, 2012, 01:33:22 PM
yah - that sounds about right
i may upgrade the program, later   :P