WinAPI mit C++
-
Hi
ich bin gerade dabei den Petzold zu lesen. Da das Buch aber schon etwas in die Jahre gekommen ist und die Quellcodes alle in C geschrieben sind, frag ich mich, wie man das ganze mit C++ sprich Templates, Polymorphie etc. benutzen kann.
Kennt ihr ein paar gute Tutorials oder Bücher, in denen dies beschrieben wird sprich Kapselung der WinAPI etc.?
Danke im voraus...
[Edit] Was haltet ihr davon: http://www.relisoft.com/book/win/2control.html? [/Edit]
-
Es gibt dafür Bibliotheken die die C-API von Windows in C++ kapseln. Z.B. SmartWin++ ist schon das was du suchst.
http://smartwin.sf.netDie MFC hat es schon Jahre gemacht, ist aber auch in die Jahre gekommen und nicht mehr wirklich schön. Wenn du Win32-Programmierung in modernem C++ machen willst, finde ich pers. SmartWin++ ein gutes Beispiel.
-
Wollte mir schon länger mal winstl von stlsoft nächer ansehen, bin bisher aber nicht dazu gekommen:
-
mhhh ok das sieht schon ma gut aus.
Allerdings ist es schwer nur anhand von Sources das Prinzip hinter diesen Bibliotheken zu verstehen.
Kennt ihr vielleicht Tutorials oder Bücher, die beschreiben, wie man die WinAPI (so wie bei diesen Bibliotheken) kapselt? Mich interessieren Dinge wie die WinMain als Hauptfunktion oder in einer Klasse, die WndProc in eine Klasse gekapselt etc. Eben das was diese Bibliotheken machen nur beschrieben wie man daran geht.
Ok, man könnte die WinMain und die WndProc auch einfach so als Funktionen im Programm lassen und nur Informationen in Klassen speichern und so aber dann ist das ganze wieder kein wirkliches C++ und auch kein wirkliches C sondern eher so "C+". Deshalb suche ich Buchempfehlungen und Tutorials, die eben WinAPI mit korrektem C++ verbinden.
-
Ich würde es so machen zunächst muss man zwischen Echtzeit- und Ereignissgesteuerten Anwendungen unterscheiden. Echtzeit ist alles was z. B. 70 Mal in der Sekunde auf den Bildschirm ein komplexes 3D Model renden will - EventDriven sind diese Schlaftabletten Anwendungen
- es passiert erst was wenn eine Eingabe vom Benutzer kommt -> Benutzer drückt Schaltfläche -> es wird das neue Gehalt berechnet -> Benutzer Tippt Textein und drück Return -> Datensatz wird in Datenbank übernommen
Realzeitanwendungen erzeugen 100% CPU Auslastung, Ereignisgesteuerte Anwendungen verbrauchen nur Energie wenn man sie tritt...Event-driven programming:
The programmer writes small "event handlers" that respond to "events." When an event occurs, the operating system calls the program's relevant event handler, it responds to the event, and control is returned to the operating system (which deals with the next event).
class Application { public: virtual bool initialize(); bool isActive(); void setActive(bool isActive); virtual int run() = 0; private: bool m_isActive; };class RunAlways : public Application { public: RunAlways(); int run(); virtual bool loop(); private: }; RunAlways::RunAlways() { setActive(true); } bool RunAlways::loop() { Sleep(10); return true; } int RunAlways::run() { MSG msg; if(!initialize()) return -1; while(isActive()) { if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if (msg.message == WM_QUIT) setActive(false); else { TranslateMessage(&msg); DispatchMessage(&msg); } } else if(!loop()) break; } return int(msg.wParam); }Beispielprogramm:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { RunAlways App; return App.run(); }Die Methode run Ruft zuerst die Methode initialze() auf. Liefert diese den Wert false so wird die Anwendung beendet, ansonsten wird in einer Endlosschleife geprüft, ob die Anwendung noch aktiv ist (also ob sie beendet werden soll oder nicht). In der Endlosschleife werden zunächst eventuell anfallende Windows-Nachrichten behandelt. Falls keine Windows-Nachrichten vorliegen wird die Methode loop Aufgerufen die in der Defaultimplementierung Sleep(50); aufruft, also den Thread für 50 Millisekunden schlafen legt, wenn keine Windowsnachrichten anliegen
Die Idee ist folgende: Schreib dir selber ne Klasse MyApplication die von RunAlways abgeleitet ist - überschreibe die Initialisierungsmethode mit eigenen Initialisierungen und überschreib wahlweiße die loop Methode mit irgendetwas das ständig z. B. ein neues Bild auf den Bildschirm malt
so ohne Fenster ist das alles noch recht langweilig.
/// Der Fenstermanager verwaltet alle Fenster und schickt nachrichten /// an die ActionListener weiter class WindowsManager { public: // Fuegt ein Fenster zum Window Manager hinzu. static bool addWindow (Window *windowPTR); // Entfernt ein Fenster aus dem WindowManager. static bool removeWindow (Window *windowPTR); // Event Hanlder fuer alle Fenster. static LRESULT CALLBACK windowEventsProcessor(HWND hWnd , UINT wMsg, WPARAM wParam, LPARAM lParam); private: WindowsManager(const WindowsManager& src) {}; WindowsManager& operator=(const WindowsManager& src) {return *this;} static vector<Window*> windowsList; // Liste aller Fenster static ActionEvent Event; // Event static MouseEvent _MouseEvent; // MausEvent };Wie du siehst hat die Klasse nur statische Elemente und es sollte nur einen WindowManager geben (kann man einen Singleton drauß machen)
Die Idee ist folgende: Der WindowManager merkt sich jedes Fenster. Wenn ein Fenster mit CreateWindow... erzeugt wird, dann muss das Fenster ja einen MessageHandler angeben. Als MessageHandler wird aber immer der gleiche verwendet - nämlich der aus der Klasse WindowManager::windowEventsProcessor:Window::Window() { ... windowsClass.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_OWNDC; windowsClass.lpfnWndProc = (WNDPROC)WindowsManager::windowEventsProcessor; ... WindowsManager::addWindow(this); .. }Außerdem meldest du das Fenster mit addWindow gleich beim Fenstermanager an (addWindow). Wenn jetzt ein Nachricht an eines der Fenster geschickt wird landet die in der Methode windowEventsProcessor. Diese erhält ja einen Handle des Fenster an die die Nachricht geht. Jetzt kannst du anhand der windowList per Window.getHandle raussuchen an welches Fenster die Nachricht eigentlich geht (hier wäre eigentlich eine Hashmap noch besser, da ja die Liste nur linear durchsucht werden kann, oder man macht ne SortedList die binär durchsucht werden kann oder Hashing... naja das ist dann dir überlassen - zum Anfang tut es eine Liste die du einfach durchiterierst und nach dem richten WindowHandle suchst)
zum Besseren Verständnis ein Überblick über die Window Klasse:
class Window { public: /// Creates a new, initially invisible Window with the specified title. Window(const char* title); /// Adds a component (for example a button) to the window. void add(Component *component); /// Legt einen Nachrichtenempfaenger fuer das Fenster fest. void setActionListener(ActionListener *listener); /// Liefert den Handle des Fensters. HWND getHandle() const; private: /// Der actionListner verweißt auf ein ActionListner Objekt, das die actionPerfomed implementiert ActionListener *actionListener; // A window is a countainer for components like labels, textboxes or buttons. vector<Component*> ComponentContainer; friend class WindowsManager; };Nachdem du weißt an welches Fenster die Nachricht geht:
Window *winPTR = NULL; // es muss gelten: // hWnd == winPTR->getHandle() // einfach uber vector windowList iterieren und gucken welches Fenster // den handle hWnd hat an dieses dan einfach per InputEventListener Events schicken for(unsigned int i = 0; i < windowsList.size(); i++) { if(hWnd == windowsList[i]->getHandle()) { winPTR = windowsList[i]; break; } }Kannst du die Nachricht an das Fenster schicken. Mit z. B.:
winPTR->EtwasIstPassiert();Im Prinzip das Observer Pattern
da man im Regelfall mit etwsIstPassiert nicht zufrieden ist kann man sich neue Objekt überlegen, die Informationen über das konkrette Event speichern z. B.
class ActionEvent { public: // Aufzaehulung der verschiedenen Events enum Type {BUTTON_CLICKED, LEFT_MOUSE_BUTTON_DOWN}; private: Type m_Type; // von welchem Typ ist das Event Component *m_Source; // Quelle des Events - Komponente, die Event ausgeloest hat public: /// liefert den Typ des Events Type getType(); /// liefert die Quelle (Komponente), welche das Event verursacht hat Component* getEventSource(); friend class WindowsManager; };usw... keine zeit mehr

-
http://turing.fh-landshut.de/~jamann/IMB/IMB.html
http://turing.fh-landshut.de/~jamann/DrawPixel.pdf
http://turing.fh-landshut.de/~jamann/IMB/winapivsoop.pdfwollte eigentlich zu genau deiner Fragen schon mal ein Tutorial schreiben, aber mir fehlen da einfach dir Resourcen

-
Falls du XP Style willst:
http://turing.fh-landshut.de/~jamann/XP Style.pdf
-
hmmm das sieht doch gut aus...
ich werds mir mal genau anschauen und durchlesen.
wäre auf jedenfall was für die faq.
und es wäre super wenn du nen richtiges tutorial dafür schreiben könntest. so wie dus schon gepostet hast nur noch weiter fortgeführt.