;21st October 2007 - 23:55 ;Moddy - Second ever MASM app. First with WinAPI. .486 .model flat, stdcall option casemap :none ;standard includes include \masm32\include\windows.inc include \masm32\include\user32.inc include \masm32\include\kernel32.inc includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib ;Function Prototypes WinMain proto :DWORD, :DWORD, :DWORD, :DWORD ;WinMain = Required Windows Main Function ExitMsg proto :DWORD ;My little "wannabe error-handling" function. .data ;Windows requirements... ClassName db "WinClass", 0 AppName db "Sandbox Application", 0 ;Quit Messages... QuitMsg db "Successfully Quiting!", 0 FailMsg db "Application Failed", 0 ;Uninitialised data .data? ;hInstance stores the handle to the module to be associated with the applicated :/ hInstance HINSTANCE ? stat UINT ? .code start: ;Run GetModelHandle, Then move the return from it into hInstance. [The return of course, being in eax] invoke GetModuleHandle, NULL mov hInstance, eax ;Run WinMain, The Main Windows Process, invoke WinMain, hInstance, NULL, NULL, 0 invoke ExitProcess, eax ;Obligatory WinMain function WinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:DWORD ;3 Local Variables local wc:WNDCLASSEX local msg:MSG local hwnd:HWND ;Fill up the WNDCLASSEX class with the required information 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 ;Use push and pop to move hInstance into wc.hInstance. REMEMBER: mov wont do memory to memory, just reg <-> mem, and reg <-> reg! push hInstance pop wc.hInstance mov wc.hbrBackground, COLOR_WINDOW+1 mov wc.lpszMenuName, NULL mov wc.lpszClassName, offset ClassName ;Invoke LoadIcon - Used to choose the icon for the application invoke LoadIcon, NULL, IDI_APPLICATION mov wc.hIcon, eax mov wc.hIconSm, eax ;LoadCursor - Used to choose the cursor for the application invoke LoadCursor, NULL, IDC_ARROW mov wc.hCursor, eax ;CreateWindowEx - Registers a windows class for use when we call CreateWindowEx invoke RegisterClassEx, addr wc ;Create our Window! invoke CreateWindowEx, 0, addr ClassName, addr AppName, WS_OVERLAPPEDWINDOW or WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL ;Move the return from CreateWindowEx [which is currently in eax] into hwnd mov hwnd, eax ;Create a loop which won't stop running unless someone clicks something... .while TRUE ;Which will send a message to the app, Which GetMessage will catch... invoke GetMessage, addr msg, NULL, 0, 0 .break .if (!eax) ;And TranslateMessage will convert into characters... invoke TranslateMessage, addr msg ;For DispatchMessage to deal with. [i.e Send it to WndProc] invoke DispatchMessage, addr msg .endw mov eax, msg.wParam ret WinMain endp ;This is where the messages are passed to be handed. WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM ;If the message is WM_DESTROY then push 0, and call ExitMsg [Push 0 so ExitMsg can pop it off after its called] .if uMsg == WM_DESTROY xor eax, eax mov stat, eax invoke ExitMsg, hWnd ;DefWindowProc = The defualt message handler. So should the message NOT be WM_DESTROY - Pass it on to DefWindowProc. .else invoke DefWindowProc, hWnd, uMsg, wParam, lParam ret ;Make eax 0 [xor by itself] then return. .endif xor eax, eax ret WndProc endp ;This is my *attempt* at an error handling function :P ExitMsg proc hWnd:HWND ;Check our stat variable... .if (stat == 0) ;So we can output our messagebox with the good message, and then exit. invoke MessageBox, hWnd, addr QuitMsg, addr QuitMsg, MB_OK invoke ExitProcess, 0 ret .endif ;But if we get here, then we can't have been supplied zero. So all is NOT good.. We call MessageBox with the bad message then exit with the value that was supplied to us invoke MessageBox, hWnd, addr FailMsg, NULL, MB_OK ;By setting the 3rd arg as NULL, It will display the default. [Default = "Error"] invoke ExitProcess, stat ret ExitMsg endp end start