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.

    http://www.win-api.de/

    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. 😃

    http://www.myendy.de/projekte/winapi/index.htm



  • 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.


Anmelden zum Antworten