winapi.de weg
-
OMG jetzt ist http://www.winapi.de auch weg.
Der Verlust von winapi.net war schon hard und jetzt noch das!
-
Die Seite ist noch da, du hast einen Bindestrich in der URL vergessen.
Aber sie ist im Arsch drinne.
Es konnte keine Verbindung mit der Datenbank aufgenommen werden. Bitte kontaktieren Sie den Administrator.
-
Ich hab hier noch n WIN API Tutorial falls du eins suchst:
Ich hab mal hochgeladen:
http://www.megaupload.com/?d=9HZMQXHQ
Bei download sind Bilder und alles dabei.
Und hier die reine Text Version:
So: Ich habe mich soeben entschlossen ein Tutorial zur WinAPI(C++) zu schreiben... Ich will gleich vorweg sagen, dass es mir NICHT darum geht eine Komplette einführung in Windowsprogrammierung zu geben. Es geht mir vielmehr darum darzustellen wie Windows eigendlich funktioniert. Ich werde C++ als beispiel nutzen um die Funktionsweise von Windows zu zeigen, da man es an dem Code sehr gut erkennen kann! Ich denke, das dieses Tutorial auch für Nicht-C++ler interessant sein könnte. Autor: Andreas Witsch(Endye@gmx.de) 1.1 Vorweg In diesem Kapitel geht es darum einen paar Informationen zu Windowsprogrammen im allgemeinen zu Vermitteln. Alle Beispiele, die ich verwendet hab habe ich mit VC++ 6.0 erstellt sie müssten aber auch mit anderen Compilern funktionieren. Um ein Programm mit WinAPI (in VC++) zu erstellen muss man beim erstellen des neuen Projektes eine "Win32-Anwendung" erstellen. Konsolenprogrammierer werden wissen, das ein Programm gewöhnlich in main() beginnt. In Windows is das ähnlich: Nur, dass die funktion hier WinMain() heißt(Die Parameter sind im nächsten Kapitel erklärt). Es gibt eine Include datei, die nahezu alle Windowsfunktionen enthält: Windows.h Die wichtigesten Subincludes sind: WINDEF.H - Grundlegende Datentypen WINNT.H - Datentypen für Unicode WINBASE.H - Funktionen des Systemkerns(KERNEL) WINUSER.H - Funktionen der Benutzerschnittstelle(USER) WINGDI.H - Funktionen der grafischen Geräteschnittstelle(GDI = Grafic Device Interface) Ihr seht dort das Wort Unicode: Dazu sage ich einfach mal, das Windows NT einen anderen Zeichensatz benutzt also Windows 98/95. Windows 98/95... benutzt den Zeichensatz ANSI. Sicher kenne viele das Standart Einführungsbeispiel für Konsolenanwendungen: #include ‹stdio.h› int main() { printf("Hello World"); } Für Windows würde das so aussehen: #include ‹windows.h› int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { MessageBox(NULL,"Hello, Windows 98","Hello World",0); } 1.2 Ich habe hier mal einen Standart Code ausgegraben, den man gut als Beispiel für ein Windowsfenster nehmen kann: #include <windows.h> LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static char szAppName[] = "Name" ; HWND hwnd ; MSG msg ; WNDCLASSEX wndclass ; wndclass.cbSize = sizeof (wndclass) ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ; wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ; RegisterClassEx (&wndclass) ; hwnd = CreateWindow (szAppName, "Fenstername", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ; ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ; } LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { HDC hdc ; PAINTSTRUCT ps ; RECT rect ; switch (iMsg) { case WM_CREATE : return 0 ; case WM_PAINT : return 0 ; case WM_DESTROY : PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, iMsg, wParam, lParam) ; } So: damit könnt ihr jetzt warscheinlich nicht sehr viel anfangen desshalb werde Ich das jetzt erstmal Zeile für Zeile erklären: #include <windows.h> LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); Also dazu wollte ich eigendlich nichts sagen machs jetze aber trotzdem. windows.h stellt die funktionen für unser Windows Programm zur verfügung. Die zweite Zeile ist die definition unserer WndProc funktion. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) Winmain ist vergleichbar mit der main funktion bei Konsolenanwendungen. der erste Parameter sagt uns, welche Instanz wir sind oder ist vielmehr der Handel der Instanz (desshalnb das "h" für Handle) Der zweite Parameter zeigt uns die letze Instanz. Der dritte Parameter ist der String der beim Start als Parameter mit übergeben wird (also als bsp: "edit sonstwas.txt". in diesem Fall würdesonstwas.txt übergeben werden) Der letzte Parameter sagt uns die Sichtbarkeit aus... normalerweise ist der Parameter SW_SHOW. So kann ein Fenster auch "invisble" gestartet werden(dann wäre der Paramter SW_HIDE) hier gibt es theoretisch noch X andere möglichkeiten aber das ist hier nicht wichtig. static char szAppName[] = "Name" ; HWND hwnd ; MSG msg ; WNDCLASSEX wndclass ; Das sind die Definitionen der Variablen: szAppName ist der name unserer Fensterklasse, die wir gleich erstellen werden HWND ist ein Handel eines Fensters, also von dem Fenster, was wir gleich erstellen werden ein Handle dient dazu die einzelnen Fenster zu identifizieren, d.h. jedesfenster hat einen Handle. Der Handle für von Windows vergeben. MSG enthält die information der Messages die für unser Fenster bestimmt sind wndclass ist eine Fensterklasse(das EX bedeutet, das wir ANSI benutzen oder einfach ausgedrückt: Win98) wndclass.cbSize = sizeof (wndclass) ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ; wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ; RegisterClassEx (&wndclass) ; So hier wird die Fensterklasse definiert und registriert. Das Icon(links oben und das, was unserer exe-Datei) der Cursor der Hintergrund und das Menu wird definiert. Dasist genau wie wndclass.style, wndclass.cbWndExtra und wndclass.cbWndExtra nicht weiter interessant. Wichtig ist zunächstmal wndclass.lpfnWndProc dort legen wir fest, welche funktion die Messages unseres Fensters verarbeiten soll. Man muss hier anmerken, dass, wenn man mehrere Fenster der gleichen Fensterklasse erstellt alles Messages von dieser einen Funktion verarbeitet werden. Der anzige weg für die Funktion zu unterscheiden, an welches Fenster die Message gerichtet ist ist der Handel. zu wndclass.lpszClassName: dort sagen wir, wie unsere Fensterklasse heißt. In Zeile wndclass.hInstance sagen wir unsere Instanz. hwnd = CreateWindow (szAppName, "Fenstername", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ; so: hier erstellen wir unser Fenster. als erstes merken wir uns den handle, den uns windows zurückgibt. Jetzt möchten wir ja unsere Fensterklasse erstellen(man könnte also auch anstatt szAppName auch "Name" angeben!). der zweite Parameter ist der Text, der in dem Blauen Feld am oberen Rand unseres Fensters steht der dritte Parameter ist der Style unseres Fenster(das WS_OVERLAPPEDWINDOW ersetzt mehrere styles auf einmal: z.b. der style unseres ramens, dann möchten wir einen minimieren/maximieren/beenden Butten links oben haben... Die nächsten zwei Parameter sind die x und y coordinate des Fensters dann sagen wir wie groß unser Fenster sein soll Jetze müssten wir den Handle des "Vaterfensters" angeben aber da es ja keins gibt(weil wir das Vaterfenster sind) sagen wir NULL. Dann können wir eine ID vergeben für unser Fenster... mit dieser können wir z.b. unseren Handle wieder haursbekommen. Dann übergeben wir die Instanz. Der Letze Parameter is ein Zeiger für die WindowCreationData... braucht man eigendlich sehr selten ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; Jetzt wird unser Fenster Sichtbar gemacht(vorausgesetzt der Parameter wurde entsprechend der Winmain übergeben!) Dann lassen wir unser Fenster noch gleichmal zeichnen. hwnd zeigt ja bekanntlich auf unser Fenster while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ; So hier wird unsere Message bevor sie von unserem WndProc verarbeitet werden kann noch schnell übersetzt bzw. weitergeleitet. (im Prenzip is das ne Endlosschleife!!!) So jetzt kommen euch warscheinlich 1-10000 Fragen: Message? Handle?... Ich muss euch entäuschen: erstmal möchte ich noch die zweite Funktion erklären danach werde Ich auf die Messages eingehen bzw. dem, warum ich dieses Tutorial überhaupt schreiben. Ich habe mich desshalb für diese reinfolge entschieden, weil ich dann bei derErklärung immer auf den Code verweisen kann. LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) unserer Funktion wird zunächst unser eigener Handle übergeben. Den brauchen wir um zu wissen von welchem Fenster wir die Messages verarbeiten.(Es könnte ja sein, das wir von mehreren Fenster auf einmal die Messages verarbeiten müssen etwa, weil wir mehrer Fenster unserer Fenserklasse erstallt haben). Der zweite Parameter ist unschwer zu erkennen die Message. Der dritte und vierte Parameter sind Paramter die je nach Message unterschiedlich sind aber es handelt sich immer um ein long variable switch (iMsg) { case WM_CREATE : return 0 ; case WM_PAINT : return 0 ; case WM_DESTROY : PostQuitMessage (0) ; return 0 ; } hier werden 3 Messages ausgewertet: 1. WM_CREATE : da machen wir garnix 2. WM_PAINT : da machen wir auch nix 3. WM_DESTROY: da beenden wir unser Fenster und sagen auch gleich noch Windows bescheid, das wir das Fenster beenden return DefWindowProc (hwnd, iMsg, wParam, lParam) ; Diese funktion übergibt unsere Message einem "Default Window", wie es in der MSDN hilfe heißt um sicher zustellen, dass alle Messages verarbeitet wurden. 1.3 Jetze werde ich mal erklären, wie das mit den Messages funktioniert. Also Fang ich doch mal am Anfang an. Es ist euch doch sicher bekannt, das Windows Multitasking fähig ist. Das Bedeuted, das mehrere Programme gleichzeitig laufen. Das Problem hierbei ist, das der Prozessor immer nur eine Operation auf einmal verarbeiten kann. Also wie geht das dann? Ganz einfach: Jedes Programm bekommt eine Bestimmte Rechenzeit zugewiesen. Dies wird über die Messages geregelt. Jedes Programm muss wie unseres auch die Messages verarbeiten (dafür haben wir insere WndProc funktion). Stellt euch vor, dass jedes Programm eine art Topf von Windows bekommt, wo eine Message nach der anderen reingeschmissen wird. Um diese Messages abzuholen Haben wir eine Schleife am ende der Winmain. Diese Schleife übersetzt, wie auch schon erwähnt bei der gelegenheit die Messages noch und gibt sie unserer Funktion WndProc. Dabei kann es auch mal vorkommen, das eine art Stau entsteht, wenn wir nicht genügend Rechenzeit bekommen oder wenn sich ein Programm einfach mehr Rechenzeit nimmt als es darf. So damit Windows weiß welche Message in welche Topf gehört bekommt jedes Fenster einen Handle. Am besten ist das eben vorzustellen, wie eine ID. Damit da nich irgendein böses Programm mist baut und ev. eine doppelt vergibt macht das Windows für uns und wir hohlen uns diesen Handle nurnoch ab(also Windows glebt quasi ein Schildchan an unseren Topf, mit ner Nummer drauf). Die Variable die wir benutzen um uns diesen Handle zu merken heißt HWND für Handle to a Window(das "to a" fehlt zwar bei der abkürzung, aber so müssen wir weniger schreiben!). Jetzt will ich mal zeigen wie so ne Message aufgebaut ist und wofür wir die eigendlich brauchen. Also eine Message ist wie folg definiert: typedef struct tagMSG { HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; DWORD time; POINT pt; } MSG; Der erste Parameter ist klar als der Handle unseres Fensters ersichtlich. Der zweite Parameter ist die Message selbst(in der Windows.h liegen macros vor, dadurch müssen wir später nicht mit zahlen arbeiten sondern können nen richtigen namen benutzen z.b.: WM_CREATE) Die nächsten zwei Parameter sind Parameter, die die Message noch braucht um bestimmte zusatz- informationen zu übergeben(kommen wir bei den Beispielen noch zu). Der Vorletzte Parameter ist die Zeit, wann die Message gepostet wurde, dies ist relevent weil wie gesagt u.u. nicht alle Messages sofort abgeholt/verarbeitet werden können dann wissen wir, wielange dei Message schon in unserem Topf ist. Der letze Parameter ist der Punkt an dem sich der Mousecursor befindet. Diese Messages sagen uns, was der benutzer gerade macht. z.b. wenn er die Mouse bewegt oder irgendwo hinclickt oder Tastatureingaben macht und eben auch, das unser Fenster erstellt wurde (WM_CREATE) oder auch Beendet(WM_DESTROY). d.h. die Messages sind Ereignisse(events)(sollte ehem. VB-lern denke ich auch schon bekannt sein) sie sind eine Schnittstelle zum Benutzer (man kann natürlich auch die alten Konsolen-befehle zum einlesen von Tastatureingaben nutzen nur dann nehmen wir uns u.u. ja mehr Rechenleistung als wir dürfen/sollten). Um auf w/lParam einzugehen möchte ich einfach ein bsp. bringen. Windows Postet uns immer, wenn sich die Maus über unserem Fenster Befindet ne Message: WM_MOUSEMOVE(das WM steht immer für Window Message). Jetze bekommen wir wie immer natürlich unseren eigenen Handle mitgeliefert. Aber jetzt is das für uns irgendwie hohl NUR zu wissen, das sich die Maus über unserem Fenster befindet. Da wollen wir auch gleich noch wissen wo sie sich befindet oder ob Mousetasten gedrückt sind. Die Position bekommen wir im lParam mitgeteilt. Aber zwei coordinaten bekommt man doch nicht in eine Long? Doch Wir bekommen nämlich eigendlich ein WORD, was aus einem LOWORD und einem HIWORD besteht. und schon kriegen wir unsere Coordinaten. bsp: yMousePos = HIWORD(lParam); Der wParam ist dafür zuständig uns zu sagen ob eine Maustaste gedrückt ist(er ist ne Flag). Die Message WM_MOUSEMOVE sieht also Folgendermaßen aus: WM_MOUSEMOVE fwKeys = wParam; // key flags xPos = LOWORD(lParam); // horizontal position of cursor yPos = HIWORD(lParam); // vertical position of cursor (orignial aus der MSDN geklaut) Jedes Programm kann nichtnur Messages empfangen sondern auch welche senden. bsp: SendMessage(hwnd,WM_DESTROY,0,0); Hier wird eine "Beenden"-Message an uns selber geschikt. So geht das natürlich mit allen anderen Messages auch. Jetzt werden manchen von euch sagen: "In dem Beispiel oben verarbeiten wir doch garnicht alle Messages?". Stimmt! aber den Rest übernimmt Windows für uns.(Mini/Maximieren usw.) 2.1 Tastatur- und Mauseingaben In diesem Kapitel will ich zeigen, wie man Tastatur- und Mauseingaben auswertet. Hier kann man ein recht einfaches Beispiel für Messages unter Windows sehen. Wenn eine Taste gedrückt wird postet Windows dem aktiven Fenster die Nachricht WM_KEYDOWN der wParam enthalt den Keycode(virual-key code). Diese virtuellen Keycodes sind in der WINUSER.H definiert. Ich will einfach mal die wichtigsten aufzählen: Dezimal Name Taste 01 VK_LBUTTON Linke Maustaste 02 VK_RBUTTON Rechte Maustaste 04 VK_MBUTTON Mitlere Maustaste 03 VK_CANCEL Strg =+ Untrbr 08 VK_BACK Rücktaste 09 VK_TAB Tab 0D VK_RETURN Enter 10 VK_SHIFT Umschalttaste(links und rechts) 11 VK_LBUTTON Strg(links und rechts 12 VK_MENU ALT(links und rechts) 13 VK_PAUSE Pause 14 VK_CAPITAL Feststelltaste 1B VK_ESCAPE Esc 20 VK_SPACE Leertaste 21 VK_PRIOR Bild auf 22 VK_NEXT Bild ab 23 VK_END Ende 24 VK_HOME Pos 1 25 VK_LEFT Linkspfeil 26 VK_UP Pfeil aufwärts 27 VK_RIGHT Rechtspfeil 28 VK_DOWN Pfeil abwärts 24 VK_INSERT Einfg 24 VK_DELETE Entf So hier will ich mal ein einfaches Beispiel geben: Wir möchten unser Programm gerne beenden, wenn Esc gedrückt wird: LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { switch (iMsg) { case WM_KEYDOWN : switch(wParam) { case VK_ESCAPE: SendMessage(hwnd,WM_DESTROY,0,0); break; } return 0 ; case WM_DESTROY : PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, iMsg, wParam, lParam) ; } Ich habe nur WndProc des Beispiels aufgeschrieben. Ich denke die WinMain ist so Elementar. Die musst ihr vorwärts und rückwarts aufsagen können. d.h. ihr könnt sie ja nochmal nachschlagen (Kapitel 1.2) Aber jetzt zu dem Beispiel: Ihr seht hier ja eigendlich nichts besonderes neues nur eine neue Message WM_KEYDOWN und wenn der wParam VK_ESACPE ist dann schiken wir an unser eigenes Fenster die Message WM_DESTROY.(um es zu beenden). Es gibt ebenfals eine Message WM_KEYUP: Sie hat die selben Parameter wie WM_KEYDOWN und dann geposted, wenn eine Taste losgelassen wurde. Nun können wir aber noch keine "normalen" Tasten einlesen. Dafür gibt es eine zweite Message: WM_CHAR. Diese Message übergibt als wParam ein Zeichen(TCHAR). Hier können wir einfach den wParam mit einem bliebigen Zeichen vergleichen: if(wParam=='a'){...} Es werden auch Tabulatoren etc. mit übergeben: if(wParam=='\t'){...} D.h. es werden ganz alle zeichen als ANSI bzw. UNICODE übergeben Ich zeig euch einfach nochmal ein Beispiel: LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { switch (iMsg) { case WM_CHAR : switch(wParam) { case '\r': //Wenn Enter gedrückt wird SendMessage(hwnd,WM_DESTROY,0,0); //wird unser Programm beendet break; case '\b': // Rücktaste .... break; case 'a': // klein a .... break; case 'A': // groß A .... break; } return 0 ; case WM_DESTROY : PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, iMsg, wParam, lParam) ; } So das wars schon jetzt könnt ihr Tastaureigaben einlesen. Kommen wir zur Maus. Die Maus ist von ihren Eingaben nicht weiter Spektakulär: Wir haben zunächst die schonmal erwähnte Message WM_MOUSEMOVE. Sie wird gepostet, wenn sich die Mouse über unser Fenster bewegt. Die x-Koordinate ist im HIWORD(lParam) verstekt und die y-Koordinate im LOWORD(lParam). Es ist wichtig zu erwähnen, dass diese Koordinaten keine absoluten Koordinaten sind sondern die Koordinaten im Fenster(d.h. da wo der weiße Bereich links oben beginnt ist der Punkt (0|0).) Der wParam ist ein Keyflag und kann folgende Werte annehmen: Wert Beschreibung MK_CONTROL Die Strg-Taste ist gedrückt. MK_LBUTTON Die linke Maustaste ist gedrückt. MK_MBUTTON Die mittlere Maustaste ist gedrückt. MK_RBUTTON Die rechte Maustaste ist gedrückt. MK_SHIFT Die Shift-Taste ist gedrückt. Nun gibt es noch die Messages WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDBLCLK. Diese Messages werden gepostet, wenn die linke Maustaste gedrückt bzw. losgelassen bzw. Doppelgeklickt hat. (Die selben Messages gibt es auch für die rechte und mittlere Maustaste: man muss nur das L durch ein R bzw. durch ein M ersetzen) Die Parameter sind die selben, wie bei WM_MOUSEMOVE. Ich glaube zum Abschluss nochmal ein Beispiel: LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { char co[10]; switch (iMsg) { case WM_LBUTTONDOWN : //Wenn die linke Maustaste gedrückt wird itoa( LOWORD(lParam), co, 10 ); //wird die X-Koordinate in einen String kopiert MessageBox(0,"Die X-Koordinate der Mouse:",co,0);//und ausgegeben itoa( HIWORD(lParam), co, 10 ); //Das selbe mit der Y-Koordinate MessageBox(0,"Die Y-Koordinate der Mouse:",co,0); return 0 ; case WM_DESTROY : PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, iMsg, wParam, lParam) ; } So und jetzt könnt ihr auch Mauseingaben verarbeiten. 4.1 Common Controls Hier will ich exemplarisch erklären, wie Common Controls eingesetzt werden. ok fangen wir einfach an: was sind Common Controls? Common Controls sind Steruerlemente, die in einer Dll(Commctrl.dll) definiert sind. Es gibt folgenden Common Controls: Animation Controls ComboBoxEx Controls Date and Time Picker Controls Drag List Boxes Flat Scroll Bars Header Controls Hot Key Controls Image Lists IP Address Controls List View Controls Month Calendar Controls Pager Controls Progress Bar Control Property Sheets Rebar Controls Status Bars Tab Controls Toolbar Controls Tooltip Controls Trackbar Controls Tree View Controls Up-Down Controls Ich werde nur exemplarisch erklären, wie diese Controls eingesetzt werden aber werde dabei aber auch Möglichkeiten aufzeigen um sich die Funktionsweise anderer Controls selbst beizubringen. Ok jetz legen wir mal los: als erstes müssen wir die Comctl32.lib einbinden. Dies macht(bei VC++) indem man im Menü auf Projekte->Einstellungen clickt. Nun öffnet sich ein Dialog indem wir auf die Kateikarte "Linker" clicken. Und nun schreiben wir unsere LIB in Objekt-/Bibliothek-Module dazu und clicken auf OK. Jetze müssen wir noch die header datei includieren: #include In der MSDN-hilfe werdet ihr lesen, dass ihr die afxwin.h includiren sollt. Die is aber Für MFC!!! aber da wir ja WinAPI programmierer sind. Nehmen wir die commctrl.h Ich werde jetzt zu meinem Angekündigtem beispiel kommen. Ich werde die Funktionsweise exemplarisch für ein Listview Control zeigen. Also zunächst müssen wir unser Listview initiallisieren: INITCOMMONCONTROLSEX ictrlex; ictrlex.dwSize = sizeof(INITCOMMONCONTROLSEX); ictrlex.dwICC = ICC_LISTVIEW_CLASSES; InitCommonControlsEx(&ictrlex); Hier der Parameter dwICC unterscheidet sich ja nach Control, das ihr benutzen wollt. In unserem Fall brauchen wir die Listview Classes. Es gibt folgende Klassen: ICC_ANIMATE_CLASS ICC_BAR_CLASSES ICC_COOL_CLASSES ICC_DATE_CLASSES ICC_HOTKEY_CLASS ICC_INTERNET_CLASSES ICC_LISTVIEW_CLASSES ICC_PAGESCROLLER_CLASS ICC_PROGRESS_CLASS ICC_TAB_CLASSES ICC_TREEVIEW_CLASSES ICC_UPDOWN_CLASS ICC_USEREX_CLASSES ICC_WIN95_CLASSES Wie ihr sicher merkt gibt es mehr elemente als Klassen, die man laden kann! Das liegt daran, das manche Controls die selben Klassen benutzen z.b. ICC_BAR_CLASSES: hier werden die Klassen für toolbar, status bar, trackbar, and tooltip control geladen. Und jetze können wir unser Listview Control erstellen: hwndlvw = CreateWindow(WC_LISTVIEW, "", WS_CHILD |WS_BORDER| WS_VISIBLE, 25, 25, 350, 225, hwndParent, NULL, hInst, NULL); Wie ihr seht benutzen wir als Fensterklasse WC_LISTVIEW. SO: jetze wollen wir ja auch was in unser Control reinschreiben dafür gibt es von MS einen Variablentyp, den wir benutzen werden: LVITEM Item; Exemplarisch habe ich mal einen Eintrag gemacht Item.mask=LVIF_TEXT ; Item.iItem=1; Item.iSubItem=NULL; Item.stateMask=NULL; Item.pszText="Text"; Item.cchTextMax=9; Der Parameter mask gibt an, für was wir unsere Variable benutzen wollen: Wir wollen hier einen Text einfügen(kein Bild ec.) desshalb LVIF_TEXT. Jetzt können wir dieses Item zu unserem Element hinzufügen: ListView_InsertItem(hwndLC,&Item); Wenn alles in ordnung war gibt diese Funktion den index des Items zurück. Ansonsten gibt er -1 zurück(also bei Fehler). Alternativ zu dieser Funktion könnte man auch das Item per Message hinzufügen: SendMessage(hwndlvw,LVM_INSERTITEM,0,&Item); Das Prefix LVN steht hier für ListViewMessage. Bei jedem Commontrols gibt es eigene Funktionen diese Lassen sich in der MSDN hilfe jedosch leicht finden indem man im Index "NamedesElements_" eingibt und schon hat man alle aufgelistet. Zu jeder Funktion ist ebensfals ein Message vorhanden: der profix der ListView Messages ist LVM_ (der TreeView prefix lautet z.b. TVM_). Jetze gibts aber Noch eine Sorte von Messages: Die , die von dem Control an unser Hauptfenster geschikt wird(wie bei Textfeldern ec. auch). Der Prefix lautet hier LVN_ (ListViewNotify). Diese Messages werden aber nicht direkt geschikt(das wär ja auch zu einfach) sondern die stehen im lParam der WM_NOTIFY Message: case WM_NOTIFY: switch (((LPNMHDR) lParam)->code) { case LVN_ITEMCHANGED: break; } so könnte ein Case-Zweig aussehen. Jetzt fragt sich warscheinlich manch einer: Was steht denn da bei switch? DAfür guken wir mal, was uns WM_NOTIFY eigendlich für Parameter hat: WM_NOTIFY idCtrl = (int) wParam; pnmh = (LPNMHDR) lParam; der erste Parameter is die ID der Controls, von der die Message gekommen is. und der andere Parameter ist wieder so definiert: typedef struct tagNMHDR { HWND hwndFrom; UINT idFrom; UINT code; } NMHDR; Ich denke die ersten 2 Parameter muss ich nichmehr erläutern. Und der Parameter code is ganz einfach unsere Message. Die Message LVN_ITEMCHANGED aus dem Beispiel wird dann gepostet, wenn ein neues Item ausgewählt wurde. Hier ist wieder ein Punkt, wo Ich nicht alles erklären werde, was man erklären kann, dafür sind es einfach zu viele Messages und sie sind auch zu speziell auf die einzelnen Controls spezialisiert. Aber ich öchte noch auf den einzigen Parameter von LVN_ITEMCHANGED (lParam) es wird eine LPNMLISTVIEW Variable über geben(wobei zu beachten ist, das LP für einen LongPointer steht). Dieser Variablentyp ist Folgendermaßen definiert: typedef struct tagNMLISTVIEW{ NMHDR hdr; int iItem; int iSubItem; UINT uNewState; UINT uOldState; UINT uChanged; POINT ptAction; LPARAM lParam; } NMLISTVIEW, FAR *LPNMLISTVIEW; Den ersten Parameter kennen wir ja schon. iItem ist weider die Nummer des Items. iSubItem ist die Nummer des Subitems(diese beiden kennen wir ja schon). uNewState, uOldState, ptAction, uChanged und lParam werden von der Message nicht benutzt. d.h. es gibt eigendlich nichts neues. Jetzt möchte ich nöchmal einfach ein beispiel zeigen um den Text des gerade ausgewähltem Item eines Listviewcontrols auszugeben: int z; char string[256]; z = SendMessage(hwndtv, LVM_GETSELECTIONMARK, 0, 0); ListView_GetItemText(hwndtv, z, 0, string, sizeof(string)); MessageBox(0,string,"info",0); Mti LVM_GESELECTIONMARK bekommt man die nummer das gerade ausgewähltem Item's und über ListView_GetItemText holen wir uns den Text. Man hätte anstadt eine Message zu schicken aber auch genausogut ListView_GetSelectionMark benutzen können! Ich wollte aber hier trotzdem nochmal dieses Beispiel aufzeigen, da genau solche Fragenöffters in Foren auftauchen. Als abschluss hab ich hier nochmal ein Beipiel für ein Treeviewelement: #include ‹windows.h› #include ‹commctrl.h› #define tv1 1 LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; HWND DoCreateTVControl(HWND, HINSTANCE, int, int ,int ,int, int); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT ("CommonctrlTest") ; HWND hwnd ; MSG msg ; WNDCLASS wndclass ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ; RegisterClass (&wndclass); hwnd = CreateWindow (szAppName, "TreeView Beispiel (by Andreas Witsch)", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ; ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ; } LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static HINSTANCE hInstance; TVITEM Item; int i; TVINSERTSTRUCT istr; static HWND hwndtree; HTREEITEM hit; switch (message) { case WM_CREATE: hInstance = ((LPCREATESTRUCT) lParam)->hInstance; hwndtree = DoCreateTVControl(hwnd, hInstance,tv1, 25, 25, 350, 225); //Treeviewcontrol erstellen hit = NULL; //Item auf NULL setzen um konflikte bei Subitem zu vermeiden for(i = 0; i < 20; i++) { Item.mask=TVIF_TEXT|TVIF_CHILDREN ; //wir wollen Text übergeben und unser Item soll ein Child haben if((i%5)!=2){Item.pszText="Erster Text"; } else {Item.pszText="Noch ein Dummytext";} Item.cchTextMax=99; //setzen wir profilaktisch mal auf 99 Item.cChildren=1; //1 Child... if((i%3)!=2){istr.hParent = hit;} //Is es ein Child?? else{istr.hParent = NULL;} // oder nich... istr.hInsertAfter = TVI_LAST; //Nach dem letzen Item einfügen istr.item = Item; hit = TreeView_InsertItem(hwndtree,&istr); //und rein mit unserem Item } return 0 ; case WM_NOTIFY: switch (((LPNMHDR) lParam)->idFrom) //Von wo kommt die Message? { case tv1: //Von unserem Treeview... switch (((LPNMHDR) lParam)->code) { //welche Message will uns unser Treeviewelement mitteilen? case TVN_SELCHANGED: //aha die auswahl hat sich geändert if(((LPNMTREEVIEW) lParam)->action ==TVC_BYMOUSE){ //Wenn die änderung von der Maus kam Item.mask = TVIF_HANDLE | TVIF_TEXT; Item.hItem = ((LPNMTREEVIEW) lParam)->itemNew.hItem; Item.cchTextMax = 999; if(TreeView_GetItem(hwndtree,&Item)==true){ MessageBox(0,Item.pszText,"TVN_ITEMCHANGED by Mouse",0);} //dann gib bitte mal den Text aus. } break; } break; } return 0; case WM_DESTROY: PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ; } HWND DoCreateTVControl(HWND hwndParent, HINSTANCE g_hinst, int i, int x, int y, int width, int height) { HWND hwndTree; INITCOMMONCONTROLSEX ictrlex; ictrlex.dwSize = sizeof(INITCOMMONCONTROLSEX); ictrlex.dwICC = ICC_TREEVIEW_CLASSES ; //wir wollen ja dir Treeviewklassen InitCommonControlsEx(&ictrlex); //ok Initialisieren hwndTree = CreateWindowEx(WS_EX_CLIENTEDGE,WC_TREEVIEW, "", WS_CHILD |WS_BORDER| WS_VISIBLE, x, y, width, height, hwndParent, (HMENU) i, g_hinst, NULL); return hwndTree; } Bei dem TreeView Control gibt es einen wichtigen unterschid zum Listview: die Items sind nicht durchnummeriert(Dies zu tun wäre warscheinlich auch etwas problematisch) sonder bekommen beim einfügen einen Handel(HTREEITEM) zugewisen.
-
sup: Thx für den Upload aber das Tutorial ist noch online.

-
und die Tutorials von winapi.net sind auch noch da, man bekommt nur kein zutritt mehr zum forum...
-
Ich habe da auch noch was online:
http://www.henkessoft.de/C++/WinAPI/WinAPI Kapitel 1 bis 6/api1.htm
http://www.henkessoft.de/C++/WinAPI/WinAPI_GDI/WinAPI_7_GDI.htm
Vielleicht hilft es dem einen oder anderen beim Einstieg. WinAPI wird ja noch gerne als Frame für Games verwendet.