I was trying to get started with GUIs today and used ResEdit to create a simple dialog sort thing.. Then tried to convert the code it generated ( C ) to ASM with little success..
(http://img4.imageshack.us/img4/5463/guiy.jpg)
( http://img4.imageshack.us/img4/5463/guiy.jpg )
On the left screen is ResEdit with what I created with it. The code it generated is in the notepad++ on the right screen.
Generated C code :
// Generated by ResEdit 1.4.5
// Copyright (C) 2006-2009
// http://www.resedit.net
HINSTANCE hInst = GetModuleHandle(0);
WNDCLASSEX wcex;
ZeroMemory(&wcex, sizeof wcex);
wcex.cbSize = sizeof wcex;
wcex.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
wcex.lpszMenuName = 0;
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = DefWindowProc;
wcex.hInstance = hInst;
wcex.hIcon = LoadIcon(0, (LPCTSTR)IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.lpszClassName = WndClass00;
RegisterClassEx(&wcex);
HFONT hfont0 = CreateFont(-11, 0, 0, 0, 400, FALSE, FALSE, FALSE, 1, 400, 0, 0, 0, ("Ms Shell Dlg 2"));
HWND hwnd = CreateWindowEx(0, ("WndClass0"), ("Dialog"), WS_VISIBLE | WS_BORDER | WS_CAPTION | WS_DLGFRAME | WS_POPUP | WS_SYSMENU, 0, 0, 209, 89, 0, 0, hInst, 0);
HWND hCtrl0_0 = CreateWindowEx(0, WC_BUTTON, ("OK"), WS_VISIBLE | WS_CHILD | WS_TABSTOP | 0x00000001, 119, 8, 75, 23, hwnd, (HMENU)IDOK, hInst, 0);
SendMessage(hCtrl0_0, WM_SETFONT, (WPARAM)hfont0, FALSE);
HWND hCtrl0_1 = CreateWindowEx(0, WC_BUTTON, ("Cancel"), WS_VISIBLE | WS_CHILD | WS_TABSTOP, 119, 34, 75, 23, hwnd, (HMENU)IDCANCEL, hInst, 0);
SendMessage(hCtrl0_1, WM_SETFONT, (WPARAM)hfont0, FALSE);
HWND hCtrl0_2 = CreateWindowEx(0, WC_EDIT, 0, WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_BORDER | ES_AUTOHSCROLL, 8, 15, 104, 36, hwnd, (HMENU)IDC_EDIT1, hInst, 0);
SendMessage(hCtrl0_2, WM_SETFONT, (WPARAM)hfont0, FALSE);
My failed translation to ASM code :
include \masm32\include\masm32rt.inc
DefWindowProc proto :DWORD, :DWORD, :DWORD, :DWORD
COLOR_3DFACE equ 15
IDC_EDIT1 equ 102
.data
.data?
hInst DWORD ?
wcex WNDCLASSEX <>
hfont DWORD ?
hdlg DWORD ?
hbutton0 DWORD ?
hbutton1 DWORD ?
hbutton2 DWORD ?
msg MSG <>
.code
Start:
xor ebx, ebx
invoke GetModuleHandle, ebx
mov hInst, eax
invoke memfill, addr wcex, sizeof wcex, ebx
mov wcex.cbSize, sizeof wcex
mov wcex.hbrBackground, COLOR_3DFACE + 1
mov wcex.lpszMenuName, ebx
mov wcex.style, CS_HREDRAW OR CS_VREDRAW
mov wcex.lpfnWndProc, offset WindowProc
push hInst
pop wcex.hInstance
invoke LoadIcon, ebx, IDI_APPLICATION
mov wcex.hIcon, eax
invoke LoadCursor, ebx, IDC_ARROW
mov wcex.hCursor, eax
mov wcex.lpszClassName, chr$("WindowClass", 0)
invoke RegisterClassEx, addr wcex
invoke CreateFont, -11, ebx, ebx, ebx, 400, FALSE, FALSE, FALSE, 1, 400, 0, 0, 0, chr$("Ms Shell Dlg 2", 0)
mov hfont, eax
invoke CreateWindowEx, ebx, chr$("WindowClass", 0), chr$("Window Name", 0), WS_VISIBLE OR WS_BORDER OR WS_CAPTION OR WS_DLGFRAME OR WS_POPUP OR WS_SYSMENU, ebx, ebx, 209, 89, ebx, ebx, hInst, ebx
mov hdlg, eax
invoke CreateWindowEx, ebx, chr$("Button", 0), chr$("OK", 0), WS_VISIBLE OR WS_CHILD OR WS_TABSTOP OR 1, 119, 8, 75, 23, hdlg, IDOK, hInst, ebx
mov hbutton0, eax
invoke SendMessage, eax, WM_SETFONT, hfont, FALSE
invoke CreateWindowEx, ebx, chr$("Button", 0), chr$("Cancel", 0), WS_VISIBLE OR WS_CHILD OR WS_TABSTOP, 119, 34, 75, 23, hdlg, IDCANCEL, hInst, ebx
mov hbutton1, eax
invoke SendMessage, eax, WM_SETFONT, hfont, FALSE
invoke CreateWindowEx, ebx, chr$("Edit", 0), ebx, WS_VISIBLE OR WS_CHILD OR WS_TABSTOP OR WS_BORDER OR ES_AUTOHSCROLL, 8, 15, 104, 36, hdlg, IDC_EDIT1, hInst, 0
mov hbutton2, eax
invoke SendMessage, eax, WM_SETFONT, hfont, FALSE
.WHILE TRUE
invoke GetMessage, addr msg, ebx, ebx, ebx
.BREAK .IF (!eax)
.IF eax == FALSE
invoke TranslateMessage, addr msg
invoke DispatchMessage, addr msg
.ENDIF
.ENDW
invoke ExitProcess, ebx
WindowProc proc hwnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
.IF uMsg == WM_DESTROY
invoke PostQuitMessage, NULL
.ELSE
invoke DefWindowProc, hwnd, uMsg, wParam, lParam
.ENDIF
ret
WindowProc endp
end Start
:bg You may wanna use ResEd instead of ResEdit :lol
When using resource file you don't need to convert anything.
In case of dialog just call DialogBoxParam. Look at examples.
Thanks for your tip on ResEd. I ended up getting that and RadASM and started out all over again..
(http://img198.imageshack.us/img198/6423/23601356.jpg)
( http://img198.imageshack.us/img198/6423/23601356.jpg )
DialogBoxParam is failing with ERROR_RESOURCE_TYPE_NOT_FOUND
Code for GUI.asm :
include \masm32\include\masm32rt.inc
DlgProc proto :DWORD, :DWORD, :DWORD, :DWORD
.data?
hInstance DWORD ?
.const
IDD_DLG1 EQU 1000
IDC_EDT1 EQU 1001
IDC_BTN1 EQU 1002
IDC_BTN2 EQU 1003
.code
Start:
xor ebx, ebx
invoke GetModuleHandle, ebx
mov hInstance, eax
invoke DialogBoxParam, eax, chr$("IDD_DLG1", 0), ebx, addr DlgProc, ebx
invoke ExitProcess, ebx
DlgProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.IF uMsg == WM_INITDIALOG
invoke GetDlgItem, hWnd, IDC_EDT1
invoke SetFocus, eax
.ELSE
mov eax, FALSE
ret
.ENDIF
mov eax, TRUE
ret
DlgProc endp
end Start
Code for resource file :
#define IDD_DLG1 1000
#define IDC_EDT1 1001
#define IDC_BTN1 1002
#define IDC_BTN2 1003
IDD_DLG1 DIALOGEX 10,10,166,61
CAPTION "IDD_DLG"
FONT 8,"MS Sans Serif",0,0,0
STYLE WS_VISIBLE|WS_OVERLAPPEDWINDOW
BEGIN
CONTROL "",IDC_EDT1,"Edit",WS_CHILD|WS_VISIBLE|WS_TABSTOP,15,21,54,15,WS_EX_CLIENTEDGE
CONTROL "IDC_BTN",IDC_BTN1,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,93,15,54,15
CONTROL "IDC_BTN",IDC_BTN2,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,93,36,54,15
END
Any ideas ? ^_^
in rc file: #define IDD_DLG1 1000
so IDD_DLG1 is actually a number not a string ...
it's not like associative array, compiler can't guess
what's behind that string..
so either use:
invoke DialogBoxParam, eax, IDD_DLG1, 0, addr DlgProc, 0
or
invoke DialogBoxParam, eax, 1000, 0, addr DlgProc, 0
Also using ebx is a bad habit .. w/o preserving it :}
Nope no luck using IDD_DLG1 instead of chr$() but yeah I was definitely wrong the first time doing that.
As for using ebx, I don't see it as a big issue. STDCall expects it to be preserved in function calls but I don't think there is a need to preserve it in the 'main' of the program as long as each function I code preserves it.
edit : OMG I finally realised why none of it was working.. I was using an empty resource.h file.. All I had to do was copy the one out of MASM folder and voila everything works perfect
thanks for your help ramguru : )
register preservation needs to be observed in callback procs like the typical winproc function as windows expects that on return of this function ebx,esi & edi are as they were when it was called. :toothy You are right though there is no need in the 'main' part.
Yeap in my DlgProc I only modify EAX/ECX/EDX as defined by STDCALL convention
Been doign that 'xor ebx, ebx' thing in my 'main' functions since agesssss. Forgotten who even told me to do that. But it's just because of small speed gains from using registers to immediate numbers and like one byte instruction differences, etc. Probably not worth doing even but HEY WE'RE ASM PROGRAMMERS !
On a side note: You don't need chr$("text", 0):
Quote chr$ MACRO any_text:VARARG
LOCAL txtname
.data
txtname db any_text, 0
.code
EXITM <OFFSET txtname>
ENDM
Normally no problem, except in cases where a double zero marks the end of an array (e.g. the filetype+extension array in FileOpen).
ahhh thanks for catching that one ; )
yah - and i didn't know about the 00 either - lol
in fact, i didn't know about FileOpen at all
i'm a n00b32 - thinkin of changing my nic
I normally just use one of the templates - New Project --> Win32 App --> DialogAsMain. Then adjust it from there. Have to adjust the .inc file slightly for a small error, when it generates the following code:
include windows.inc
include user32.inc
include kernel32.inc
include shell32.inc
include comctl32.inc
include comdlg32.inc
includelib user32.lib
includelib kernel32.lib
includelib shell32.lib
includelib comctl32.lib
includelib comdlg32.lib
WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
IDD_DIALOG equ 1000
IDM_MENU equ 10000
IDM_FILE_EXIT equ 10001
IDM_HELP_ABOUT equ 10101
.const
ClassName db 'DLGCLASS',0
AppName db 'Dialog as main',0
AboutMsg db 'MASM32 RadASM Dialog as main',13,10,'Copyright © MASM32 2001',0
.data?
hInstance dd ?
CommandLine dd ?
hWnd dd ?
The .const is in the wrong place (should be .data) so i rename it and place a .const just above the IDD_DIALOG constant. Build all - works. Then i can get on with the main coding and also jump into the editor when needed to update the GUI.