NASM Programm läuft nicht wie es soll

Hallo da draußen,
ich habe schon lönger Erfahrung mit asm, aber nie so richtig mit Fenstern.
Bisher immer einzellne API Funktionen verwendet oder kleine Algorithmen geschrieben, oder auch mal das ein oder andere Crackme gelöst.

Ich weiß, dass mit masm die asm-Fensterentwicklung wesentlich einfacher ist, aber ich lehne masm grundsätzlich ab. Grund: pseudo-asm (IF, invoke, ...), ich mag es lieber nostalgisch, möchte darauf aber nicht näher eingehen, einfach meine Meinung.

Nun zu meinem Bisherigen Code (quelle: deinmeister.de):
Code:
%include 'win32n.inc'

	EXTERN GetModuleHandleA
	EXTERN RegisterClassExA
	EXTERN LoadIconA
	EXTERN LoadCursorA
	EXTERN CreateWindowExA
	EXTERN GetMessageA
	EXTERN DispatchMessageA
	EXTERN ExitProcess
	EXTERN DefWindowProcA
	EXTERN PostQuitMessage
	EXTERN MessageBoxA
	EXTERN SendMessageA

[segment .data]

	UnsereFensterklasse:
	istruc WNDCLASSEX
	    at WNDCLASSEX.cbSize,          dd  WNDCLASSEX_size
	    at WNDCLASSEX.style,           dd  CS_VREDRAW + CS_HREDRAW
	    at WNDCLASSEX.lpfnWndProc,     dd  Fensterprozedur
	    at WNDCLASSEX.cbClsExtra,      dd  0
	    at WNDCLASSEX.cbWndExtra,      dd  0
	    at WNDCLASSEX.hInstance,       dd  0
	    at WNDCLASSEX.hIcon,           dd  0
	    at WNDCLASSEX.hCursor,         dd  0
	    at WNDCLASSEX.hbrBackground,   dd  COLOR_HIGHLIGHT+1
	    at WNDCLASSEX.lpszMenuName,    dd  0
	    at WNDCLASSEX.lpszClassName,   dd  Fensterklassenname
	    at WNDCLASSEX.hIconSm,         dd  0
	iend


	Fensterhandle dd 0

	MSGhWnd   equ 0
	MSGmsg    equ 4
	MSGwParam equ 8
	MSGlParam equ 12

	MessageBuffer dd 0,0,0,0,0,0,0
	Fenstertitel db "ordinäres Standardfenster",0
	Fensterklassenname db "UnsereFensterklasse",0
	Fenstername db "Oooooh... Ein Fenster",0
	SagNein db 'NEEEEEEEEEEEIN',0

	FenstergroesseInX equ 300
	FenstergroesseInY equ 200
	FensterpositionInX equ 100
	FensterpositionInY equ 120



[segment .text]
[global main]

main:
		push dword 0
		call GetModuleHandleA
		mov [UnsereFensterklasse+WNDCLASS.hInstance],eax

;zwei Ressourcen werden geladen (die Menueressource wird automatisch geladen,
;wenn sie in der Fensterklasse definiert wurde
		push dword 0
		push dword [UnsereFensterklasse+WNDCLASS.hInstance]
		call LoadIconA
		mov [UnsereFensterklasse+WNDCLASS.hIcon],eax
		push dword 0
		push dword [UnsereFensterklasse+WNDCLASS.hInstance]
		call LoadCursorA
		mov [UnsereFensterklasse+WNDCLASS.hCursor],eax

;schicke dem OS die Definition der Fensterklasse
		push dword UnsereFensterklasse
		call RegisterClassExA


;erzeuge ein Fenster nach der Fensterklasse:
		push dword 0
		push dword [UnsereFensterklasse+WNDCLASS.hInstance]
		push dword 0
		push dword 0
		push dword FenstergroesseInY
		push dword FenstergroesseInX
		push dword FensterpositionInY
		push dword FensterpositionInX
		push dword WS_CAPTION + WS_MAXIMIZEBOX + WS_MINIMIZEBOX + WS_SIZEBOX + WS_SYSMENU + WS_VISIBLE
		push dword Fenstername
		push dword Fensterklassenname
		push dword WS_EX_CLIENTEDGE + WS_EX_WINDOWEDGE
		call CreateWindowExA
		mov [Fensterhandle],eax

;Die wichtigste Stelle eines Windows-Programms: Die Message Pump / Message Loop. Hier werden
;die eingehenden Meldungen vorverarbeitet und an das entsprechende Fenster verschickt

		MessagePumpStart:
		push dword 0
		push dword 0
		push dword 0
		push dword MessageBuffer
		call GetMessageA
		or eax,eax
		jz WM_QUIT_empfangen
		push dword MessageBuffer
		call DispatchMessageA
		jmp MessagePumpStart


		WM_QUIT_empfangen:
		push dword 0
		call ExitProcess

Fensterprozedur:

;nur 2 Meldungen werden ueberprueft: WM_COMMAND fuer aktivierte Menues und WM_DESTROY, die
;anzeigt, das das Fenster vernichtet wird.
;Den Rest arbeitet DefaultWndProc von Windows ab.

		cmp dword [esp+4+MSGmsg],WM_COMMAND
		jne keineInteressanteMeldung


		keineInteressanteMeldung:

		cmp dword [esp+4+MSGmsg],WM_DESTROY
		je Selbstzerstoerung
		jmp [DefWindowProcA]

		Selbstzerstoerung:
		push dword MB_OK | MB_APPLMODAL
		push dword Fenstertitel
		push dword SagNein
		push dword [Fensterhandle]
		call [MessageBoxA]
		push dword 0
		call [PostQuitMessage]
		;setze Rueckgabewert = 0
		xor eax,eax
		ret 16

win32n.inc gibt hier: http://rs1.szif.hu/~tomcat/win32/win32n.zip

Der Code ist etwas Chaotisch, es war der einzigste den ich in NASM-syntax gefunden habe. Ich habe ihn leicht modifiziert (vereinfacht), da ich keine Ressourcen verwende.

Wenn ich das Programm assembliere und linke, ist das Ergebnis ausführbar, aber unsichtbar.

assembliert und gelinkt auf diese Weise:
Code:
nasm -fwin32 test.asm alink -oPE -subsys gui test.obj WIN32.LIB -entry main

Woran liegt es, das das Fenster nicht sichtbar ist??

Ich wäre auch über Tutorials und Codebeispiele für Win32 Fensterprogramme in NASM-Syntax dankbar.


Mit freundlichem Gruß

zaibl
 
probier mal, die beiden aufrufe noch nach dem create zu machen:
ShowWindow(hWnd, iCmdShow);
UpdateWindow(hWnd);

Das iCmdShow ist glaub das oberste dword auf dem stack, wenn die winmain aufgerufen wird.
 
So,
1. ich werde über jede PM automatisch per Mail benachrichtigt ;)

2. WNDCLASS != WNDCLASSEX:
dieser Code macht möglicherweise nicht das gewünschte.
Code:
push dword 0
		push dword [UnsereFensterklasse+WNDCLASS.hInstance]
		call LoadIconA
außerdem:
da jetzt keine Icons aus der Exe geladen werden, sollte man die (systemeigene) Defaulticons laden:
also (WNDCLASS + Icon Anpassung)
Code:
push dword IDI_APPLICATION
		push 0
		call LoadIconA
		mov [UnsereFensterklasse+WNDCLASSEX.hIcon],eax
		
		push dword IDC_ARROW
		push 0
		call LoadCursorA
		mov [UnsereFensterklasse+WNDCLASSEX.hCursor],eax
und nicht zuletzt:
indirekte Calls hier:
Code:
jmp [DefWindowProcA]

		Selbstzerstoerung:
		push dword MB_OK | MB_APPLMODAL
		push dword Fenstertitel
		push dword SagNein
		push dword [Fensterhandle]
		call [MessageBoxA]
		push dword 0
		call [PostQuitMessage]
ergeben zumindest bei mir keinen Sinn - man Callt die Adresse, an der die Adresse der API steht (gibt schöne Fehlermeldungen ;) ). Nun kommt es letzendlich wohl auf die Assemblier/Linkoption an - bei den von Dir angegebenen Optionen wird aber vom Linker noch eine JMP Tabelle generiert
Code:
00403006   - FF25 98404000                JMP DWORD PTR DS:[<&user32.LoadIconA>]                    ; user32.LoadIconA
0040300C   - FF25 9C404000                JMP DWORD PTR DS:[<&user32.LoadCursorA>]                  ; user32.LoadCursorA
00403012   - FF25 A0404000                JMP DWORD PTR DS:[<&user32.RegisterClassExA>]             ; user32.RegisterClassExA
00403018   - FF25 A4404000                JMP DWORD PTR DS:[<&user32.CreateWindowExA>]              ; user32.CreateWindowExA
0040301E   - FF25 A8404000                JMP DWORD PTR DS:[<&user32.GetMessageA>]                  ; user32.GetMessageA
00403024   - FF25 AC404000                JMP DWORD PTR DS:[<&user32.DispatchMessageA>]             ; user32.DispatchMessageA
0040302A   - FF25 68404000                JMP DWORD PTR DS:[<&kernel32.ExitProcess>]                ; kernel32.ExitProcess
00403030   - FF25 B0404000                JMP DWORD PTR DS:[<&user32.DefWindowProcA>]               ; user32.DefWindowProcA
00403036   - FF25 B4404000                JMP DWORD PTR DS:[<&user32.MessageBoxA>]                  ; user32.MessageBoxA
0040303C   - FF25 B8404000                JMP DWORD PTR DS:[<&user32.PostQuitMessage>]              ; user32.PostQuitMessage
und die Calls verweisen erstmal auf diese JMP Tabelle. Ruft man CALL [PostQuitMessage] wird es als CALL [40303C] übersetzt, was dann bei der Ausführung zu einem Fehler führt.



stattdessen:

Code:
jmp DefWindowProcA
Selbstzerstoerung:
		push dword MB_OK | MB_APPLMODAL
		push dword Fenstertitel
		push dword SagNein
		push dword [Fensterhandle]
		call MessageBoxA
		push dword 0
		call PostQuitMessage

vollständiger lauffähiger Quelltext:
Code:
%include 'win32n.inc'


	EXTERN GetModuleHandleA
	EXTERN RegisterClassExA
	EXTERN LoadIconA
	EXTERN LoadCursorA
	EXTERN CreateWindowExA
	EXTERN GetMessageA
	EXTERN DispatchMessageA
	EXTERN ExitProcess
	EXTERN DefWindowProcA
	EXTERN PostQuitMessage
	EXTERN MessageBoxA
	EXTERN SendMessageA

[segment .data]

	UnsereFensterklasse:
	istruc WNDCLASSEX
	    at WNDCLASSEX.cbSize,          dd  WNDCLASSEX_size
	    at WNDCLASSEX.style,           dd  CS_VREDRAW + CS_HREDRAW
	    at WNDCLASSEX.lpfnWndProc,     dd  Fensterprozedur
	    at WNDCLASSEX.cbClsExtra,      dd  0
	    at WNDCLASSEX.cbWndExtra,      dd  0
	    at WNDCLASSEX.hInstance,       dd  0
	    at WNDCLASSEX.hIcon,           dd  0
	    at WNDCLASSEX.hCursor,         dd  0
	    at WNDCLASSEX.hbrBackground,   dd  COLOR_HIGHLIGHT+1
	    at WNDCLASSEX.lpszMenuName,    dd  0
	    at WNDCLASSEX.lpszClassName,   dd  Fensterklassenname
	    at WNDCLASSEX.hIconSm,         dd  0
	iend


	Fensterhandle dd 0

	MSGhWnd   equ 0
	MSGmsg    equ 4
	MSGwParam equ 8
	MSGlParam equ 12

	MessageBuffer dd 0,0,0,0,0,0,0
	Fenstertitel db "ordinäres Standardfenster",0
	Fensterklassenname db "UnsereFensterklasse",0
	Fenstername db "Oooooh... Ein Fenster",0
	SagNein db 'NEEEEEEEEEEEIN',0

	FenstergroesseInX equ 300
	FenstergroesseInY equ 200
	FensterpositionInX equ 100
	FensterpositionInY equ 120



[segment .text]
[global main]

main:
		push dword 0
		call GetModuleHandleA
		mov [UnsereFensterklasse+WNDCLASSEX.hInstance],eax

;zwei Ressourcen werden geladen (die Menueressource wird automatisch geladen,
;wenn sie in der Fensterklasse definiert wurde
		push dword IDI_APPLICATION
		push 0
		call LoadIconA
		mov [UnsereFensterklasse+WNDCLASSEX.hIcon],eax
		
		push dword IDC_ARROW
		push 0
		call LoadCursorA
		mov [UnsereFensterklasse+WNDCLASSEX.hCursor],eax

;schicke dem OS die Definition der Fensterklasse
		push dword UnsereFensterklasse
		call RegisterClassExA


;erzeuge ein Fenster nach der Fensterklasse:
		push dword 0
		push dword [UnsereFensterklasse+WNDCLASS.hInstance]
		push dword 0
		push dword 0
		push dword FenstergroesseInY
		push dword FenstergroesseInX
		push dword FensterpositionInY
		push dword FensterpositionInX
		push dword WS_CAPTION + WS_MAXIMIZEBOX + WS_MINIMIZEBOX + WS_SIZEBOX + WS_SYSMENU + WS_VISIBLE
		push dword Fenstername
		push dword Fensterklassenname
		push dword WS_EX_CLIENTEDGE + WS_EX_WINDOWEDGE
		call CreateWindowExA
		mov [Fensterhandle],eax

;Die wichtigste Stelle eines Windows-Programms: Die Message Pump / Message Loop. Hier werden
;die eingehenden Meldungen vorverarbeitet und an das entsprechende Fenster verschickt

		MessagePumpStart:
		push dword 0
		push dword 0
		push dword 0
		push dword MessageBuffer
		call GetMessageA
		or eax,eax
		jz WM_QUIT_empfangen
		push dword MessageBuffer
		call DispatchMessageA
		jmp MessagePumpStart


		WM_QUIT_empfangen:
		push dword 0
		call ExitProcess

Fensterprozedur:

;nur 2 Meldungen werden ueberprueft: WM_COMMAND fuer aktivierte Menues und WM_DESTROY, die
;anzeigt, das das Fenster vernichtet wird.
;Den Rest arbeitet DefaultWndProc von Windows ab.

		cmp dword [esp+4+MSGmsg],WM_COMMAND
		jne keineInteressanteMeldung


		keineInteressanteMeldung:

		cmp dword [esp+4+MSGmsg],WM_DESTROY
		je Selbstzerstoerung
		jmp DefWindowProcA

		Selbstzerstoerung:
		push dword MB_OK | MB_APPLMODAL
		push dword Fenstertitel
		push dword SagNein
		push dword [Fensterhandle]
		call MessageBoxA
		push dword 0
		call PostQuitMessage
		;setze Rueckgabewert = 0
		xor eax,eax
		ret 16

PS: ob man in pseudo-asm oder nasm programmiert, um einen Debugger wie OllyDbg kommt man bei fehlersuche (besonders am Anfang) nicht herum ;)
 
vielen Dank, du bist echt super :)

das mit den indirekten Calls war mir garnicht bewusst. und der WNDCLASS(EX) Dreher ist eig. peinlich :\

Erstmal eine Frage zu der größe. Das Programm ist jetzt 3,07 KB groß/klein, ist es möglich die größe zu reduzieren?

Nun noch eine Frage zu den Winapi Fenstern: Wie eigne ich mir Wissen und Informationen an, wie ich beispielsweise Buttons, Textboxen, Labels, "Datei öffnen"-Buttons, Transparenz, und was sich noch alles nettes machen lässt, an?

Ich bin da ein bisschen von Visual Studio (früher) verwöhnt.


Mit freundlichem Gruß

zaibl
 
Die GUI-programmierung mit winapi, ist doch eigentlich die gleiche, wie in hochsprache auch. du kannst also alle c/cpp-tutorials verwenden, die es für die winapi gibt. die meisten infos kriegst du vermutlich aus der msdn. das ist zumindest meine erste anlaufstelle, wenn ich was zur winapi wissen will.
 
Original von zaibl

Erstmal eine Frage zu der größe. Das Programm ist jetzt 3,07 KB groß/klein, ist es möglich die größe zu reduzieren?
Da ich eigenltich ein MASMler bin, habe ich mir die erzeuge Exe nur im PE-Editor angeschaut:
Du könntest in der alink doku schauen, wie man folgende Sachen macht
1)alles in eine Section linken kann (spart platz)
2)filealign auf 512 setzen
keine extra IMPORTS Sections (sind ganze 2 vorhanden)
3)Relocations weglässt (bei Exen unnötig).
Eventuell einen anderen Linker probieren.

Habe mal testweise per Hand Relocations entfernt und "PE Rebuild" (mit LordPE) gemacht - ergebnis: 2.36KB, was sich für eine Fensteranwendung schon sehen lassen kann.
Nun noch eine Frage zu den Winapi Fenstern: Wie eigne ich mir Wissen und Informationen an, wie ich beispielsweise Buttons, Textboxen, Labels, "Datei öffnen"-Buttons, Transparenz, und was sich noch alles nettes machen lässt, an?
WinAPI ist ja nichts sprachspezifisches - man muss nur einmal verstehen, wie man diese in seiner Lieblingssprache anwendet und kann eigentlich beliebige Tutorials nutzen.
Ich habe damals mit Iczelion Tutorials angefangen (gibt mittlerweile auch eine deutsche Übersetzung)
http://www.joachimrohde.com/cms/xoops/modules/articles/index.php?cat_id=2
danach kommt man eigentlich mit "normalen" API-Tutorials (meistens für C/C++) gut zurecht.

Die wesentlichen Unterschiede in der MASM/NASM Syntax sind imho die Nutzung der lokalen Variablen (durch MASM lassen sich diese leichter verwalten). Da musst Du Dir eben vorstellen, dass
Code:
proc bla X:DWORD,Y:DWORD
mov eax,X
add eax,Y
dasselbe ist wie
Code:
mov eax,[ebp+8]
add eax, [ebp+12]
und dass "proc" ein Macro für "push EBP;MOV EBP,ESP;" ist, "endp" eben "LEAVE; RETN _speicher_" entspricht.

"LOCAL X: DWORD"
"LOCAL Y: DWORD"
am Anfang einer Proc macht nichts anderes als:
Code:
push EBP
mov EBP,ESP ;<- PROC Macro
sub ESP,8 <--- Lokal Macro
also automatisch Speicher reservieren und die benutzten lokalen Variablen in der "prozedur" automatisch durch "[EBP-_Pos_]" ersetzen. (der Umstand mit lokalen Variablen ist auch das einzige, was mich wirklich in NASM stört - bei kleineren Sachen fällt es zwar nicht auf, aber bei mehr als 300-400 Zeilen kommt man schnell durcheinander).
Der Rest mit IF und Invoke sollte eigentlich kein Problem darstellen.

Als Ressourceneditor kann man gut den von VC++ gebrauchen (habe deswegen noch VC++6.0 drauf - außerdem gibt es da die Offlineversion der WinAPI-Dokumentaion) - damit kann man sich eine Oberfläche zusammenklicken, einen RC (ResourceScript) generieren lassen und muss nur paar Zeilen korrigieren.
 
Ok ich werde mir mal die Iczelion Tutorials anschauen und versuchen mir da das ein oder andere anzueignen.
Wie meinst du das mit den Ressource Editor von VC++? Was ist damit möglich? Kann man das ding komplett als Form-Designer gebrauchen? Wenn ja, wie? (bzw. geht das auch mit kostenlosen Resource-Editoren?) Wie bringe ich das Resource-Script dann ins Programm, damit ich die designten Buttons, etc. ansteuern kann?

Ich weiß zwar nicht was Relocations sind (werde ich aber nachher noch lesen), aber wenn ich das Programm mit LordPE öffne und wieder speichere, ist es auch bei 2,36 KB, wir wahrscheinlich die Relocations entfernen.

Wie kann man die IMPORT Sections weglassen? ist das abhängig vom Linker? Wenn ja/nein wie muss ich vorgehen? Einfach löschen wird wahrscheinlich nicht klappen?

Und nun noch: Ist mein Program Grundgerüst (mal abgesehn von der MessageBox beim schliessen) sinnvoll? ist da unnötiger Schroot drinne? lässt sich etwas einfacher oder sinnvoller bewerkstelligen?

Ich hoffe das ist alles beantwortbar und nicht zu dumm gefragt.


Mit freundlichem Gruß
 
Original von zaibl
Wie meinst du das mit den Ressource Editor von VC++? Was ist damit möglich? Kann man das ding komplett als Form-Designer gebrauchen? Wenn ja, wie? (bzw. geht das auch mit kostenlosen Resource-Editoren?) Wie bringe ich das Resource-Script dann ins Programm, damit ich die designten Buttons, etc. ansteuern kann?
VC++ 6.0 Autorenedition. Gabs früher öfters in Zeitschriften.
Man legt ein neues Projekt an, klickt die Oberfläche zusammen, speichert alles - im Projektordner wird eine RC Datei (so wie hier http://www.deinmeister.de/asmtut1.zip )
angelegt. Nun muss man die Datei ein wenig bearbeiten (VC schreibt da internes Zeug rein) und IDs für die Elemente vergeben.
Dann kann man die Datei mit GORC kompilieren und anschließend dazulinken.
Im Programm spricht man die Elemente über die vergebenen IDs ab:
RC Datei
Code:
#include "C:\masm32\include\resource.h"

#define IDC_STATIC -1
#define ID_QUIT WM_USER+1
#define ID_DOWNLOAD WM_USER+2
#define ID_GET_PATH WM_USER+3
#define ID_IP_HOSTNAME WM_USER+4
#define ID_WEB_PATH WM_USER+5
#define ID_LOCAL_PATH WM_USER+6

MAINDLG DIALOGEX 0, 0, 241, 71
STYLE DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | 
    WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "GetWebFile (c) by CDW www.cdw.de.vu"
FONT 8, "MS Sans Serif"
BEGIN
    PUSHBUTTON      "Abbrechen",ID_QUIT,175,52,61,14,0,WS_EX_STATICEDGE
    DEFPUSHBUTTON   "Download",ID_DOWNLOAD,175,36,61,14,0,WS_EX_STATICEDGE
    PUSHBUTTON      "",ID_GET_PATH,149,48,15,13,BS_ICON
    CONTROL         "",IDC_STATIC,"Static",SS_WHITEFRAME,3,36,166,29
    CONTROL         "",IDC_STATIC,"Static",SS_WHITEFRAME,3,3,233,29
    EDITTEXT        ID_IP_HOSTNAME,8,15,81,13,ES_AUTOHSCROLL
    LTEXT           "IP/Hostname:",IDC_STATIC,7,5,83,8
    EDITTEXT        ID_WEB_PATH,96,15,135,13,ES_AUTOHSCROLL
    LTEXT           "Dateiname und Pfad:",IDC_STATIC,95,5,83,8
    EDITTEXT        ID_LOCAL_PATH,8,48,135,13,ES_AUTOHSCROLL
    LTEXT           "Speichern unter (Pfad):",IDC_STATIC,8,38,83,8
END

200 ICON MOVEABLE PURE LOADONCALL DISCARDABLE "ICON1.ICO"
300 ICON MOVEABLE PURE LOADONCALL DISCARDABLE "OPEN.ICO"
Assembly (dialog proc, siehe insbesondere WM_COMMAND behandlung)
Code:
IDC_STATIC equ -1
ID_QUIT equ WM_USER+1
ID_DOWNLOAD equ WM_USER+2
ID_GET_PATH equ WM_USER+3
ID_IP_HOSTNAME equ WM_USER+4
ID_WEB_PATH equ WM_USER+5
ID_LOCAL_PATH equ WM_USER+6

WSOCK_VERSION equ 2h
DEF_PORT equ 80

MSG_BUFFER equ 1024
DlgProc proc uses ebx edi esi hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM 
    .IF uMsg==WM_INITDIALOG
        push hWnd
        pop hWin
        invoke LoadIcon,hInstance,300
        invoke SendDlgItemMessage,hWnd,ID_GET_PATH,BM_SETIMAGE,IMAGE_ICON,eax  
        invoke LoadIcon,hInstance,200
        INVOKE SendMessage,hWnd,WM_SETICON,TRUE,eax  
        invoke SendDlgItemMessage,hWnd,ID_IP_HOSTNAME,EM_LIMITTEXT,MAX_PATH,0
        invoke SendDlgItemMessage,hWnd,ID_WEB_PATH,EM_LIMITTEXT,MAX_PATH,0 
      
    .ELSEIF uMsg==WM_CLOSE 
         invoke CloseServerSocket,addr hUser
         invoke EndDialog, hWnd,NULL 
     
    .ELSEIF uMsg==WM_COMMAND 
        mov eax,wParam
		mov edx,eax
		shr edx,16    
           
            .if dx==BN_CLICKED 
                .IF ax==ID_GET_PATH
                      invoke SaveFileProc,addr SaveFileFilter ;dasselbe was wir öffnen
                     
                    .if eax!=0 
                       invoke SetDlgItemText,hWnd,ID_LOCAL_PATH,addr SaveFileNameBuffer                    	
                    .endif
               
                .elseif ax==ID_DOWNLOAD
                	   invoke Download,hWnd  
                .ELSEIF ax==ID_QUIT 
                     invoke CloseServerSocket,addr hUser
                    invoke EndDialog, hWnd,NULL  
                .ENDIF 
            .ENDIF 
         
    .ELSE 
        mov eax,FALSE 
        ret 
    .ENDIF 
    mov eax,TRUE 
    ret 
DlgProc endp

Wie kann man die IMPORT Sections weglassen? ist das abhängig vom Linker? Wenn ja/nein wie muss ich vorgehen? Einfach löschen wird wahrscheinlich nicht klappen?
Jep, ist vom Linker abhängig - und leider hat aLink keinerlei Dokumentationen. Der Hilfe nach (alink -h) gibt es so eine Möglichkeit nicht. Man könnte es mit einem anderen Linker probieren (LINK von MASM oder TLINK von TASM), allerdings akzeptiert LINK von MASM die hier im Thread verlinkte win32.LIB nicht - da müsste man erst selber eine Lib zusammenschustern.

Und nun noch: Ist mein Program Grundgerüst (mal abgesehn von der MessageBox beim schliessen) sinnvoll? ist da unnötiger Schroot drinne? lässt sich etwas einfacher oder sinnvoller bewerkstelligen?
naja, schaut ok aus. Etwas ungewohnt (aus MASMler Sicht ;) ).
Worauf man aber noch achten sollte:
Calling convention:
http://www.cs.cornell.edu/courses/cs412/2001sp/resources/microsoft-calling-conventions.html
d.h, die Fensterprozedur ist eine Callbackfunktion, die von Windows aufgerufen wird, wenn es etwas neues für das Fenster gibt - die Prozedur muss also die stdcall convention einhalten (ebx, ebp, esi, edi unverändert zurückgeben) - sonst kracht es.
 
Ok, ich habe mir erst einmal einen Resource Editor besorgt (ResEdit) und kann damit wie bei Visual Basic beispielsweise oder VC++ Formen zusammenklicken.

Mein Resultat:

test.rc

Code:
// Generated by ResEdit 1.4.3
// Copyright (C) 2006-2008
// http://www.resedit.net

#include "resource.h"
#include <windows.h>
#include <commctrl.h>
#include <richedit.h>


//
// Dialog resources
//
LANGUAGE LANG_GERMAN, SUBLANG_DEFAULT
IDD_DIALOG1 DIALOGEX 0, 0, 147, 24
STYLE DS_3DLOOK | DS_CENTER | DS_FIXEDSYS | WS_VISIBLE | WS_BORDER | WS_CAPTION | WS_DLGFRAME | WS_THICKFRAME | WS_SYSMENU
EXSTYLE WS_EX_TOOLWINDOW | WS_EX_LEFTSCROLLBAR
CAPTION "Hihi <:"
FONT 8, "Ms Shell Dlg 2", 400, 0, 1
BEGIN
    DEFPUSHBUTTON   "Klick müsch! :D", IDOK, 5, 5, 60, 14, BS_FLAT
    EDITTEXT        IDC_EDIT1, 70, 5, 72, 14, ES_AUTOHSCROLL
END


Jetzt habe ich nochnicht ganz verstanden wie ich diese in mein Programm einfüge, was für Anweisung ich machen muss, damit ich z.B. IDC_EDIT1 erstellen kann durch/mit dem Code.

Es wäre gut, wenn du mir bei meinem Button und dem Editfeld nochmal zeigen könntest, wie ich die im Programm auf dem Dialog erstelle und eventuell auch ein Beispiel wie man auf die Werte zugreift (Wenn/Ob der Button gedrückt wurde, wie man an den Wert in der Box kommt (beim Knopfdruck))

Wäre sehr hilfreich, da ich nicht durch deinen Beispielcode steige.

MfG
 
Editiert am 26.10.08 um 00:30
Es wäre gut, wenn du mir bei meinem Button und dem Editfeld nochmal zeigen könntest, wie ich die im Programm auf dem Dialog erstelle und eventuell auch ein Beispiel wie man auf die Werte zugreift (Wenn/Ob der Button gedrückt wurde, wie man an den Wert in der Box kommt (beim Knopfdruck))
Das von Dir selbst verlinkte Beispiel (deinmeister.de) hat z.T diese Funktionalität schon. Aber nicht desto trotz:
Deine test.rc habe ich so modifiziert:
Code:
LANGUAGE LANG_GERMAN, SUBLANG_DEFAULT
IDD_DIALOG1 DIALOGEX 0, 0, 147, 24
STYLE DS_3DLOOK | DS_CENTER | DS_FIXEDSYS | WS_VISIBLE | WS_BORDER | WS_CAPTION | WS_DLGFRAME | WS_THICKFRAME | WS_SYSMENU
EXSTYLE WS_EX_TOOLWINDOW | WS_EX_LEFTSCROLLBAR
CAPTION "Hihi <:"
FONT 8, "Ms Shell Dlg 2"
BEGIN
    DEFPUSHBUTTON   "Klick müsch! :D", 1002h, 5, 5, 60, 14, BS_FLAT
    EDITTEXT   1001h, 70, 5, 72, 14, ES_AUTOHSCROLL
END
Warum? Zum einen ist es ja kein C (mit den Headern kann GORC also nichts anfanganen). Zum anderen mochte es die Zeile "FONT 8, "Ms Shell Dlg 2", 400, 0, 1" nicht - also wurde es etwas angepasst. Ich habe bis jetzt den Eindruck gewonnen, dass GORC kompatibel zu RC (von MASM) ist. D.h bei Problemen einfach an dieses Format halten.

Jetzt nehme ich den Source aus dem ersten Beispiel und passe diesen an einen Dialog an:
Code:
%include 'win32n.inc'


	EXTERN GetModuleHandleA
	EXTERN RegisterClassExA
	EXTERN LoadIconA
	EXTERN LoadCursorA
	EXTERN CreateWindowExA
	EXTERN GetMessageA
	EXTERN DispatchMessageA
	EXTERN ExitProcess
	EXTERN DefWindowProcA
	EXTERN PostQuitMessage
	EXTERN MessageBoxA
	EXTERN SendMessageA
	EXTERN DialogBoxParamA
	EXTERN EndDialog
	EXTERN GetDlgItemTextA

[segment .data]



;Folgende Konstanten beschreiben die Lage der MSG-Struktur auf dem Stack:
		MSGhWnd   equ 0
		MSGmsg    equ 4
		MSGwParam equ 8
		MSGlParam equ 12

;GetMessage benötigt einen Puffer fuer eine eingehende Message (eine Message = 7 DWORDS):
		MessageBuffer dd 0,0,0,0,0,0,0

		Fenstertitel db "ordinäres Standardfenster",0
		Fensterklassenname db "UnsereFensterklasse",0
		Fenstername db "Oooooh... Ein Fenster",0
		hWin dd 0

;Namen der Ressourcen:
		Menuname db "Win002menu",0
		Bildchenname db "Nuke",0
		Dialogname db "IDD_DIALOG1"
		Garnix db 0
		;Ein paar Texte fuer ein paar Dialogboxen...
		titel1 db "Ficken",0
		titel2 db "Blasen",0
		textdrin db "Kein Wunder, das sieht man schon an der Art in der du das Menü ausfährst :-)",0
		SagNein db "Nei i i i i i i i i i i i i i i n !",0

[segment .text]
[global main]
main:
;viele Funktionen benoetigen ein Handle, das dieses laufende Programm identifiziert
;GetModuleHandle (0) erledigt dies

		push dword 0
		call GetModuleHandleA
		;erzeuge ein Dialog aus der Ressource:
		 ;invoke DialogBoxParam, hInstance, ADDR DlgName,NULL, addr DlgProc, NULL 
		 push 0
		 push dword Fensterprozedur
		 push 0
		 push dword Dialogname
		 push eax
		 call DialogBoxParamA
		push dword 0
		call ExitProcess

;------------
;Die Fensterprozedur wird jedesmal durch DispatchMessage aufgerufen, wenn die Message zu diesem
;Fenster gehört. Die Message und ihre Parameter liegen dabei auf dem Stack. Mit der 4 in
; [esp+4+MSGmsg] wird der auf dem Stack liegende EIP uebersprungen

		Fensterprozedur:
%define WM_USER 1000h
%define IDC_EDIT1 WM_USER+1
%define IDOK WM_USER+2
;nur 2 Meldungen werden ueberprueft: WM_COMMAND fuer aktivierte Menues und WM_DESTROY, die
;anzeigt, das das Fenster vernichtet wird.
;Den Rest arbeitet DefaultWndProc von Windows ab.
        cmp dword [esp+4+MSGmsg],WM_INITDIALOG
        jne nextMsg
          mov eax, dword [esp+4+MSGhWnd]
          mov dword [hWin],eax
          
        nextMsg:
		cmp dword [esp+4+MSGmsg],WM_COMMAND
		jne keineInteressanteMeldung

 ;Button wurde angeklickt?: vergleich nur lowWord (also 16-bit)
         mov edx, [esp+4+MSGwParam]
         shr edx,16
         cmp word dx,BN_CLICKED
         jne keineInteressanteMeldung ;es wurde nichts bekanntes angeklickt
           mov eax, [esp+4+MSGwParam] ;sonst steht im hiWord des wParameters die Button ID
           cmp word ax,IDOK
		   jne next ;nächster button wäre jetzt dran, allerdings haben wir ja nur 1
		   call reagiere_auf_Btn
		 next: 
       
		keineInteressanteMeldung:

		cmp dword [esp+4+MSGmsg],WM_CLOSE
		je Selbstzerstoerung
	    xor eax,eax
	    ret 16

		Selbstzerstoerung:
		push dword MB_OK | MB_APPLMODAL
		push dword Fenstertitel
		push dword SagNein
		push dword 0
		call MessageBoxA
		;EndDialog, hWnd,NULL
		push dword 0
		push dword [esp+8+MSGhWnd]
		call EndDialog
;setze Rueckgabewert = 0
		xor eax,eax
;die "RET imm"-Version der RET Instruktion holt beim Ruecksprung noch "imm" Bytes vom Stack
;mit imm = 16 holen wir genau die 4 DWORDS herunter, die die Fensterprozedur als Parameter erhielt
		ret 16

		Willwasmeldung:
		push dword MB_OK
		push ecx
		push dword textdrin
		push dword 0
		call MessageBoxA
		ret 16

		Nixwissmeldung:
		push dword MB_OK
		push dword Garnix
		push dword Garnix
		push dword 0
		call MessageBoxA
		ret 16

reagiere_auf_Btn:
;invoke GetDlgItemText,hWin,ID_IP_HOSTNAME,addr host_buffer,MAX_PATH
  ;lokalen speicher reservieren:
  push ebp
  mov ebp,esp
  sub esp,100h  
  push dword 100h
  lea eax,[ebp-100h]
  push dword eax
  push IDC_EDIT1
  push dword [hWin]
  call GetDlgItemTextA
        push dword MB_OK
		lea eax,[ebp -100h]
		push eax
		push eax 
		
		push dword 0
		call MessageBoxA
 
 ;stack wiederherstellen
 mov esp,ebp
 pop ebp
ret 0
In diesem Beispiel wird auf Knopfdruck aus dem Editfeld die Eingabe ausgelesen und als MsgBox ausgegeben.
Assemblierbar mit:
Code:
gorc Win002.rc
nasm -fwin32 win002_n.asm
ALINK.EXE -c -oPE  -subsys gui win002_n win002.res win32.lib  -entry main

Um auf Knopfdruck reagieren zu können, braucht man folgendes: Windows schickt schon automatisch eine Nachricht an die DlgProc /Fensterprozedur. Man muss nur diese Nachricht abfragen können.
Um auf einzelne Elemente aus dem Programm heraus zuzugreifen, schickt man ebenfalls Nachrichten an Windows - wie in dem Beispiel "GetDlgItemText" (siehe Dokumentation der Parameter bei MSDN).
Genauso kann man den Text im Editfeld setzen - in dem man "SetDlgItemText" nutzt.
Muss gleich erstmal weg, daher werde ich nicht weiterkommentieren - einfach mal schreiben, was unklar ist.
Wie gesagt, das wäre nur ein Beispiel - schau Dir am besten eine "richtige" DlgProc Routine in C an, und versuche die in NASM umzusetzen. Aus dem geposteten NASM code wird man sonst nicht wirklich schlau, wenn man nicht weiß, wie so eine Dlg/WindowProc ausschaut und was diese unbedingt machen muss ;)

Edit: hab die RC datei jetzt nochmal angepasst, da GORC die #defines irgendwie falsch umgesetzt hat.
Zur Erklärung, warum hier 1000h bzw WM_USER benutzt wird:
bis 1000h sind die Sachen von Windows "vorbelegt". Um nicht den Systemeigenen IDs in die Quere zu kommen, sollte man IDs > 1000h vergeben.
http://msdn.microsoft.com/en-us/library/ms644931(VS.85).aspx

Was mir hier noch nicht so ganz gefällt, ist die Nachrichtenbehandlungsroutine (die Fensterprozedur).
Habe kurz nach NASM Beispielen dazu gegoogelt und bin auf sowas gestoßen:
http://plastic4records.com/194.65.3.199/win32asm/ex2.html
die DlgProc finde ich ehrlich gesagt deutlich klarer gegliedert und "richtiger", weil hier nicht auf [esp+...] zurückgegriffen wird.
näheres zu DlgProc siehe http://msdn.microsoft.com/en-us/library/ms645469(VS.85).aspx
neuer Source (ist imho deutlich klarer gegliedert und veständlicher):
Code:
%include 'win32n.inc'


	EXTERN GetModuleHandleA
	EXTERN RegisterClassExA
	EXTERN LoadIconA
	EXTERN LoadCursorA
	EXTERN CreateWindowExA
	EXTERN GetMessageA
	EXTERN DispatchMessageA
	EXTERN ExitProcess
	EXTERN DefWindowProcA
	EXTERN PostQuitMessage
	EXTERN MessageBoxA
	EXTERN SendMessageA
	EXTERN DialogBoxParamA
	EXTERN EndDialog
	EXTERN GetDlgItemTextA

[segment .data]

		hWin dd 0

;Namen der Ressourcen:
		Dialogname db "IDD_DIALOG1"

[segment .text]
[global main]
main:
;viele Funktionen benoetigen ein Handle, das dieses laufende Programm identifiziert
;GetModuleHandle (0) erledigt dies

		push dword 0
		call GetModuleHandleA
		;erzeuge ein Dialog aus der Ressource:
		 ;invoke DialogBoxParam, hInstance, ADDR DlgName,NULL, addr DlgProc, NULL 
		 push 0
		 push dword Dialog1Proc
		 push 0
		 push dword Dialogname
		 push eax
		 call DialogBoxParamA
		push dword 0
		call ExitProcess


Dialog1Proc:

 %define hdlg1              ebp+8
 %define dlg1msg          ebp+12
 %define wparam          ebp+16
 %define lparam            ebp+20
 %define WM_USER 1000h
 %define IDC_EDIT1 WM_USER+1
 %define IDOK WM_USER+2
 
        enter 0,0
        cmp dword [dlg1msg],WM_INITDIALOG
        jne next1
          mov eax,[hdlg1] ;handle des Fensters (ja, auch ein Dialog ist nur ein Fenster ;) )
          mov dword [hWin],eax
          jmp handled
        next1: 
        cmp dword [dlg1msg],WM_COMMAND
          je wmcommand
        cmp dword [dlg1msg],WM_CLOSE
        jne unhandled    ;andere Nachrichten behandelnt wir nicht
          push 0
          push dword [hWin]
          call EndDialog
          jmp handled

;--------------
unhandled:   ;heißt: wir geben FALSE zurück - die von uns unbehandelten Messages
        mov  eax,0      ;werden in der DefaultProc vom System behandelt
       leave
       ret 16 

       
handled:
  
mov eax,1
leave 
ret 16

wmcommand:
mov edx,dword [wparam]
shr edx,16
cmp dx,BN_CLICKED
jne unhandled ;irgendein ereignis, das wir nicht behandeln
  mov eax,dword [wparam]
  cmp ax,IDOK
  jne unhandled
  call reagiere_auf_Btn

jmp handled

reagiere_auf_Btn:
;invoke GetDlgItemText,hWin,ID_IP_HOSTNAME,addr host_buffer,MAX_PATH
  ;lokalen speicher reservieren:
  push ebp
  mov ebp,esp
  sub esp,100h  
  push dword 100h
  lea eax,[ebp-100h]
  push dword eax
  push IDC_EDIT1
  push dword [hWin]
  call GetDlgItemTextA
        push dword MB_OK
		lea eax,[ebp -100h]
		push eax
		push eax 
		
		push dword 0
		call MessageBoxA
 
 ;stack wiederherstellen
 mov esp,ebp
 pop ebp
ret 0
 
Zurück
Oben