Mehr Anfänger geht wohl nicht...



  • Hallo.

    Nachdem ich schon ein paar Jahre rein sequentielle Programme in C Programmiert habe, möchte ich nun auch mit WinAPI anfangen. Ich habe mir ein Buch dafür gekauft "Grafikprogrammierung für Windows". Das Buch ist aus dem Jahr 2005 aber es bearbeitet nebenbei genau das Thema, welches ich programmieren möchte. Der Autor verwendet den LCC Compiler - ich arbeite mit VC++ 2013 Express und möchte auch gerne dabei bleiben.

    Ich poste mal das erste Beispiel, welches - Demotivierender Weise - gleich nicht funktioniert:

    Erstmal die *.c Datei:

    /*#ifndef W0_H
    	#define W0_H
    	#include "w0.h"
    #endif*/
    
    #ifndef WINDOWS_H
    	#define WINDOWS_H
    	#include <Windows.h>
    #endif
    
    #ifndef LRES_H
    	#define LRES_H
    	#include "LResHeader.h"
    #endif
    
    #ifndef ICO_W0
    	#define ICO_W0 10
    #endif
    
    #ifndef IDM_ENDE
    	#define IDM_ENDE 100
    #endif
    
    LRESULT CALLBACK W0_WinProc(HWND, UINT, WPARAM, LPARAM);
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
    {
    	HINSTANCE hProgram;
    	HWND hWnd;
    	MSG msg;
    	WNDCLASSEX wndclass;
    
    	char capname[10];
    
    	hProgram = hInstance;
    
    	strcpy(capname, "W0");
    
    	wndclass.cbSize = sizoeof(wndclass);
    	wndclass.style = CS_HREDRAW | CS_VREDRAW;
    	wndclass.lpfnWndProc = W0_WinProc;
    	wndclass.cbClsExtra = 0;
    	wndclass.cbWndExtra = 0;
    	wndclass.hInstance = hProgram;
    	wndclass.hIcon = NULL;
    	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    	wndclass.hbrBackground = CreateSolidBrush(RGB(00, 00, 154));
    	wndclass.lpszMenuName = capname;
    	wndclass.lpszClassName = capname;
    	wndclass.hIconSm = NULL;
    
    	RegisterClassEx(&wndclass);
    
    	hWnd = CreateWindow(capname, "W0 - Erstes Programm", WS_OVERLAPPEDWINDOW, 100, 100, 400, 300, NULL, NULL, hProgram, NULL);
    
    	ShowWindow(hWnd, iCmdShow);
    
    	while (GetMEssage(&msg, NULL, 0, 0)){
    		TranslateMessage(&msg);
    		DisplatchMessage(&msg);
    	}
    
    	return 0;
    }
    
    LRESULT CALLBACK W0_WinProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
    {
    	int imess;
    
    	switch (Message)
    	{
    	case WM_COMMAND:
    		switch (LOWORD(wParam))
    		{
    		case IDM_ENDE:
    			imess = MessageBox(NULL, "W0 beenden?", "W0", MB_OKCANCEL | MB_ICONQUESTION);
    			if (imess == IDOK)PostQuitMessage(0);
    			if (imess == IDCANCEL) return 0;
    		}
    
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		return 0;
    
    	default:
    		return DefWindowProc(hWnd, Message, wParam, lParam);
    	}
    }
    

    Jetzt die Resourcendatei:

    /*#ifndef W0_H
    	#define W0_H
    	#include "w0.h"
    #endif*/
    
    #ifndef WINDOWS_H
    	#define WINDOWS_H
    	#include <Windows.h>
    #endif
    
    #ifndef ICO_W0
    	#define ICO_W0 10
    #endif
    
    #ifndef IDM_ENDE
    	#define IDM_ENDE 100
    #endif
    
    ICO_W0 ICON W0.ICO
    
    W0 MENU
    {
    	POPUP "&Was_tun"
    	{
    		MENUITEM "&Bye",	IDM_ENDE
    	}
    }
    

    Und die Headerdatei, die übrigens in der Resourcendatei einen Fehler auslöst:

    #ifndef ICO_W0
    	#define ICO_W0 10
    #endif
    
    #ifndef IDM_ENDE
    	#define IDM_ENDE 100
    #endif
    

    Da die Headerdatei nicht funktioniert bzw. in der rc-Datei einen Fehler auslöst, habe ich sie aktuell nicht eingebunden. Aber vllt. sieht von Euch auch gleich jemand, weshalb das nicht klappt. Ein Fehler "unexpected end of file" tritt auf, wenn ich die Headerdatei in die Resourcendatei mit einbinde (wie im Beispiel gefordert).

    Nun aber zur eigentlichen Fehlermeldung (auf die Headerdatei kann ich zur Not NOCH verzichten):
    error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "_sizeof" in Funktion "_WinMain@16"

    Der gleiche Fehler tritt auf, nur mit "_GetMessage" und "_DisplatchMessage" anstatt "_sizeof"

    Muss ich da noch eine Datei mit:

    #pragma comment (lib, "xyz.lib")
    

    linken?

    Vielen Dank für Eure Hilfe.

    Grüße,
    CJens



  • Du hast doch hoffentlich den richtigen Projekttyp gewählt?



  • Hallo,

    ich habe ein Tutorial im Internet gefunden von Microsoft. Dort wurde C++ >> Win32 >> Win32-Projekt gewählt. Das habe ich hier auch getan.

    Anwendungstyp: Windows-Anwendung



  • Versuchs mal mit einer Konsolenanwendung. Ganz ehrlich bin ich grad selber verwirrt, bin auch noch nie über so einen Fehler gestolpert.



  • Lieber Mechanics,

    vielen Dank für Deine Mühe, aber es sind einfach Tipfehler.

    sizoeof gibt es nicht, genauso wenig wie DisplatchMessage 🙂
    Deshalb kennt er das wohl nicht. Aber komisch, dass der Compiler das nicht anders anmerkt bzw. nicht rot unterstreicht.

    Grüße,
    CJens



  • Wieso beschwert sich der Compiler über:

    #include "w0.h"
    

    in der Resourcendatei w0.rc?

    Ich kenne mich mit Resourcendateien garnicht aus... deshalb die Frage, was da zulässig ist. In dem Buch wird die Einbindung gefordert. Hier nochmal der Inhalt beider Dateien:

    w0.h:

    #ifndef ICO_W0
    	#define ICO_W0 10
    #endif
    
    #ifndef IDM_ENDE
    	#define IDM_ENDE 100
    #endif
    

    w0.rc:

    #ifndef W0_H
    	#define W0_H
    	#include "w0.h" //Löst den Fehler aus. Programm läuft, wenn das auskommentiert wird.
    #endif
    
    #ifndef WINDOWS_H
    	#define WINDOWS_H
    	#include <Windows.h>
    #endif
    
    #ifndef ICO_W0
    	#define ICO_W0 10
    #endif
    
    #ifndef IDM_ENDE
    	#define IDM_ENDE 100
    #endif
    
    ICO_W0 ICON W0.ICO
    
    W0 MENU
    {
    	POPUP "&Was_tun"
    	{
    		MENUITEM "&Bye",	IDM_ENDE
    	}
    }
    


  • Keine Ahnung, Ressourcendateien braucht man alle zehn Jahre mal und dann mach ich copy&paste. Schau dich einfach nach einem anderen Beispiel um und machs so ähnlich. Und wär natürlich nicht schlecht, wenn du dazuschreiben würdest, was für einen Fehler der Compiler ausgibt, und nicht nur, dass es einen gibt.
    Falls du das noch nicht gemerkt hast, dein Threadtitel ist nicht optimal. Das Thema wird nicht viele interessieren. Ich muss mich auch erst überwinden, den aufzumachen und durchzuschauen. Es ist viel besser, schon im Titel das Problem genau zu beschreiben.



  • Hallo,

    ja, die Fehlermeldung hatte ich in einem anderen Kommentar gepostet, aber in der letzten Frage nicht mehr - das ist suboptimal, da hast Du recht.

    Der Fehler lautet:
    unexpected end of file

    Ich habe bereits mehrere Beispiele (auch welche aus dem Internet) gesichtet - fast alle arbeien mit den Ressource Dateien.

    Die Headerdatei kann in ein *.c File wunderbar eingebunden werden. Also, nur die Ressource Datei hat Probleme damit.

    In der Ressource Datei möchte ich die Menüs definieren. Macht man das "heute" anders? Ich habe auch ein Beispiel gefunden, wo die Menüs direkt im Code unter WM_CREATE erstellt werden. Das könnte ich auch machen, aber in der Ressource Datei scheint das einfacher zu gehen. Und es wäre schön zu wissen, weshalb:

    #ifndef XYZ
       #define XYZ 1001
    #endif
    

    in einer Ressource Datei erlaubt ist aber die Einbindung einer Headerdatei mit dem gleichen Code nicht.



  • CJens schrieb:

    Macht man das "heute" anders?

    Ja, man nimmt normalerweile ein GUI Framework. Ich benutze Qt. Ist um mehrere Größenordnungen einfacher und leistungsfähiger als die WinApi. Guis mit der reinen WinApi erstellt man eigentlich nur mal zur Übung. Aber wie du siehst, macht das nicht viel Spass 😉

    Am Ende der Header Datei fehlt einer Leerzeile, ist das das Problem?



  • Du benötigst keine geschweiften Klammern

    W0 MENU
    BEGIN
        POPUP "&Was_tun"
        BEGIN
            MENUITEM "&Bye",    IDM_ENDE
        END
    END
    

    Ich denke dein Fehler liegt an den etlichen ifndef und endif.
    Nimm die mal ganz raus und versuchs dann noch einmal.



  • @Mechanics Also ich komme mit der WinAPi gut zurecht und für 'ne GUI mit einem Menü, ein paar Buttons und Editboxen reicht es auch völlig.



  • Asyl-Dämon schrieb:

    @Mechanics Also ich komme mit der WinAPi gut zurecht und für 'ne GUI mit einem Menü, ein paar Buttons und Editboxen reicht es auch völlig.

    Machst du das hauptberuflich? Sagt dein Chef, klar, kannst gern paar Tage in etwas reinstecken was der Kollege mit Qt/Gtk in einer Stunde schafft? Oder dann Wochen, wenn es plötzlich etwas anspruchsvoller wird?



  • Nein, nur hobbymäßig 😃
    Der Quellcode für das Hauptfenster ist zwar ein etwas größerer Brocken, aber bis auf wenige Details bleibt der ja immer gleich
    und eine Ressourcen Datei ist so ziemlich das einfachste was ich bis jetzt programmiert habe.
    Klar würde ich für eine anspruchsvolle GUI ein Framework vorziehen, aber ich sage mal "normale" GUIs bekommt man auch mit der WinApi ohne großen Zeitaufwand hin.



  • Die Frage war: Wie man es heute macht. Und da nutzt man sicher GUI Frameworks. Habe damals mit VB angefangen zu programmieren. Das Ende vom Lied war, dass VB haufenweise Code automatisch erzeugt hatte, den ich nicht verstanden habe.
    Ich möchte früher oder später (gerne früher) auf solche Tools zurückgreifen - aber dafür möchte vorher zumindest ansatzweise (auf absolute Vollständigkeit lege ich garnicht so viel Wert) verstehen, was da geschieht. Der Computer sollte einem nur Arbeit abnehmen, die man auch selbst versteht. Außerdem kann ich nicht ausschließen, dass sich die Oberfläche in dem Programm später einmal interaktiv ändert. Dann ist es vorbei mit Drag&Drop GUI's.

    @Dämon: Danke, aber daran liegt es nicht. Ich habe die #ifndef #endif Passagen erst eingefügt, als ich die Definitions aus der Headerdatei rausnehmen musste.
    Ich habe gelesen, dass jeder Compiler die RC Dateien mit einem Separaten Compiler übersetzt. Kann es daran liegen?



  • CJens schrieb:

    verstehen, was da geschieht. Der Computer sollte einem nur Arbeit abnehmen, die man auch selbst versteht. Außerdem kann ich nicht ausschließen, dass sich die Oberfläche in dem Programm später einmal interaktiv ändert. Dann ist es vorbei mit Drag&Drop GUI's.

    Wie gesagt, zum Üben kann man das gern machen. Es schadet sicher nicht, sich etwas mit der WinApi auszukennen. Vor allem, wenn es irgendwelche schwer nachvollziehbaren Probleme gibt, muss man verstehen, was da passiert. Aber so wirklich übertreiben braucht man das auch nicht 😉
    Es geht bei GUI Frameworks nicht um Drag&Drop. Das benutze ich tatsächlich so gut wie nie, wir haben keine so trivialen GUIs, die zusammenklicken kann. Die sind alle dynamisch, interaktiv und sehr komplex. Der Punkt ist, dass so ein Framework sehr viel Arbeit abnimmt und viel mehr bietet, als die WinApi. z.B. Layouts. Wenn du das alles von Hand programmierst, musst du auf Größen und Positionsänderungen reagieren und deine Controls entsprechend verschieben. Viel Spass. Brauchbare Frameworks bieten für sowas verschiedene Layouts, die steckst du zusammen (von mir aus im Code) und es passt sich alles "automatisch" an. Das ist schon mal ein sehr grundlegendes und sehr wichtiges Feature. Dann bist du mit der WinApi bei jedem etwas komplexeren Feature ziemlich aufgeschmießen. Versuch mal eine etwas komplexere Baum oder Tabellendarstellung hinzubekommen, das ist nicht sinnvoll möglich, man muss dann gleich alles selber zeichnen. In Qt sind die ItemViews ziemlich flexibel und gut erweiterbar, wir haben in unserem Programm schon sehr komplexe Varianten davon, ich glaub, viel komplexer gehts gar nicht mehr. Dann hast du in den Frameworks sowas wie Stylesheets (bzw. bei GTK Themes). Damit kann man das Aussehen auch sehr flexibel anpassen, geht weit über das hinaus was man mit der WinApi mit vertretbarem Aufwand machen könnte. Oder sowas wie Textverarbeitung. In Qt gibts da auch ein ziemlich mächtiges Framework mit dem QTextDocument und QTextEdit bzw. entsprechenden anderen Klassen und Controls. Kann viel mehr als das RichEdit und ist viel einfacher zu bedienen und für anderes zu verwenden. Wir haben damit z.B. mehrere Quelltexteditoren gebaut (wir haben mehrere eigene Scriptsprachen und es gibt verschiedene Stellen, wo man irgendwas customizen kann), mit Syntaxhighlighting, Code Completion usw. Da ist es vorbei mit der WinApi 😉

    Wegen deinem Problem. Nochmal, hast du versucht, eine Leerzeile am Ende deiner Headerdatei einzufügen?



  • Ich hätte da noch eine Frage. Gibt es solche Tools auch für C?
    QT, GTK+ und wxWidgets arbeiten alle mit C++ und es wird jeweils eine Instanz einer von dem Programm bereitgestellten Klasse eingebunden. Ich möchte in meinem Code auf Klassen komplett verzichten.

    Das Programm soll eine Listbox, einen Treeview, ein Menü und eine Darstellungsfläche für OpenGL (das ist auch in nativem C gehalten) bereitstellen, mehr nicht.

    Ich habe mir jetzt mal die oben beschriebenen Tools angesehen - uff, sehr umfangreich.

    Gibt es solche Tools denn auch für natives C, also dass einem das Tool den Code für die GUI erstellt?

    Wenn es da nichts gibt, dann werde ich diese paar Funktionen auch über WinApi-32 hin bekommen... mit etwas Übung.

    Macht man dabei eigentlich für jedes Steuerelement eine eigene Header- und Ressource Datei? Diese Programme werden sehr schnell, sehr unübersichtlich. Sobald man ein paar Schaltflächen hat ist das schon ein relativ langer Code.

    Vielen Dank und Gruß,
    CJens



  • GTK ist C. Ist allerdings sehr viel Code, den man da schreiben muss, deswegen wurden sogar Sprachen wie Vala erfunden. Für WxWidgets gibts auch C Bindings. Dann gibts sicher auch etwas schlankere GUI Frameworks, die man in C benutzen kann, ganz spontan fallen mir aber keine ein. GUI kann man halt sehr schön objektorientiert machen. In C ist es dann zwar auch objektorientiert, aber aufwändiger, weil die Sprache das nicht direkt unterstützt. Deswegen so lustige Sachen wie das GObject in GTK, und dafür muss man einen Haufen Code schreiben.

    p.s. Eine Ressourcendatei pro Programm sollte reichen.



  • Vielen Dank für die Orientierungshilfe. Ich werde mir das mit WinAPI noch ein wenig antun. Wenn es am Ende nicht klappen sollte, schreibe ich die GUI in C#. Das eigentliche Rechenprogramm liegt schon als sequenzielles Programm vor. Dann müssen die sich den Job eben teilen.

    Aber vllt bekomme ich ja diese einfache GUI auch so hin. Ihr werdet es sehen, ob ich hier die nächsten Wochen mit weiteren Fragen aufschlage 🙂

    Vielen Dank nochmal an alle.

    Ps.: Objektorientiert und mit Klassen möchte ich nicht arbeiten, da es sich bei dem Programm um ein Berechnungsprogramm handelt, bei dem Performance an oberster Stelle steht. Die GUI soll eigentlich nur die Eingaben übernehmen und das Ergebnis grafisch darstellen, ähnlich wie hier dargestellt:
    http://www.ttm.tugraz.at/arno/posprocessor-demo.gif

    Die Knoten mit den Werten (hoher Wert = rot, niedriger Wert = blau), die Elemente welche die Knoten aufspannen (Dreiecke, Vierecke, etc.) bestimmt mein Programm, das in C bereits vorliegt. Deshalb wollte ich auch bei C bleiben. Es geht wirklich "nurnoch" um die Visualisierung. Das müsste mit OpenGL recht einfach gehen, wenn all diese Daten vorliegen.



  • Ja, sowas müsste man mit der WinApi hinbekommen haben. Außer, dass es eh schon nicht schön ausschaut 😉 Und das Fenster sinnvoll zu skalieren könnte problematisch werden. Was machst du mit den Buttons, müssen die dann mitskaliert werden, wenn das Fenster skaliert wird?
    Das in C# zu schreiben und nur eine C Funktion aufzurufen wär auch eine Idee. So ein Fenster hättest in C# in paar Minuten zusammengeklickt, dann deine Funktion über P/Invoke aufrufen, bist insgesamt in 10 Minuten fertig. Warum sollte man da ewig mit der WinApi und Ressourcen und was weiß ich was rumkämpfen? Hast es jetzt übrigens hinbekommen?



  • CJens schrieb:

    Ps.: Objektorientiert und mit Klassen möchte ich nicht arbeiten, da es sich bei dem Programm um ein Berechnungsprogramm handelt, bei dem Performance an oberster Stelle steht.

    In C++ machen OO und Klassen keinen Geschwindigkeitsnachteil, das sagen wir Dir doch schon seit 4 Jahren.


Log in to reply