Seku
HomeProjekteTutorialsToolsGFXLinksForumGästebuchKontaktImpressumLogin
Stoppt die Vorratsdatenspeicherung - www.vorratsdatenspeicherung.de

tutorial anzeigen

Durch lesen dieses Artikels akzeptieren Sie folgende Nutzungsbedingungen:
Dieser Artikel und alle verwendeten Materialien (Bilder, Quelltexte, etc.) unterliegen dem Copyright des Autors, hier Seku. Das kopieren dieses Artikels, Auszügen oder verwendeten Materialien und Einfügen auf anderen Seiten als dieser (seku.info) ist nur mit einer ausdrücklichen, schriftlichen Einverständniserklärung des Autors erlaubt. Weder Autor noch der Betreiber dieser Seite haften für eventuelle Schäden, die durch diesen Artikel oder herunterladbare Objekte ( > Downloads ) verursacht wurden. Die Richtigkeit dieses Textes ist nicht garantiert.

Einleitung

Guten Tag,

in diesem Tutorial will ich erklären, wie man eine Versionskontrolle über das Internet machen kann. Diese Möglichkeit hat den Vorteil, dass nur ein PHP-Skript benötigt wird. Gerade deshalb eignet sich diese Möglichkeit besonders für Programme, die keinen Server brauchen. Ein Multiplayerspiel, welches einen globalen Server hat, von dem es eine Spielserverliste bekommt, fällt also nicht in diese Kategorie. Hier wäre es angebrachter, den globalen Server damit zu beauftragen. Aber es gibt noch einen Vorteil. Es gibt meines Wissens nur wenige Webhoster, die einem eine Shell zur Verfügung stellen und auch dann oft nur mit Aufpreis.

Diese Methode eignet sich unter der selben Bedingung auch für Highscores, welche Singleplayerspiele interessanter und spannender machen - immerhin will man ja der Beste sein. Obwohl das nicht der Gegenstand dieses Tutorials ist, will ich kurz darauf eingehen. Man könnte so zwei Seiten erstellen. Eine "add.php" und eine "get.php". Beide müssten dann natürlich im Internet liegen. Das Programm könnte dann also z.B. für das Eintragen der Highscore die Adresse "http://www.seku.info/add.php?name=Seku&points=8000" aufrufen. Das Skript prüft dann, ob der Eintrag in die Highscore kann, oder ob er zu schlecht ist und trägt ihn dann unter dem Namen "Seku" mit der Punktezahl "8000" ein, oder eben nicht. Die get.php könnte dann die 20 besten Spieler auflisten. Natürlich sollte man hier - vor allem bei der add.php - eine Prüfsumme mitliefern, damit man nicht so leicht betrügen kann, aber das ist eine andere Geschichte.

Zurück zu unserer Versionskontrolle. PHP ist eine Skriptsprache, die C++ in vielen Bereichen sehr ähnelt. So könnte ein Skript aussehen

<?php

switch($Produkt)
{
  case "SuperMediaPlayer": echo("1.0"); break;
  case "MegaMonsterMatscher2D": echo("2.6"); break;
  case "CPUidentifier": echo("0.4"); break;
  default: echo("error"); break;
}

?>

Dieses Skript prüft die Variable $Produkt und gibt demnach die Versionsnummer zurück. Man könnte also für "MegaMonsterMatscher2D" die Seite so aufrufen "**URL**/version.php?Produkt=MegaMonsterMatscher2D". Die Ausgabe wäre dann ganz einfach "2.6".

Der "Nachteil" dieser Methode der Internetabfrage liegt auf der Hand. Man kann mit einem normalen Browser auf die Seiten zugreifen. Aber ich denke, dass das vertretbar ist. Also dann, ab an's coden .

Die Umsetzung

Und wie der Zufall - und die Überschrift - so wollen, bietet die WinApi hierfür Möglichkeiten. Dazu müssen wir die "WinINet.lib" linken und die "WinINet.h" einfügen. Wer schon mit der WinApi gearbeitet hat, weiß, dass es da viele Handles gibt, z.B. HINSTANCE, HWND, HMENU etc. Es gibt da ein Handle namens HINTERNET, welches für uns arbeitet. Die meisten Handles kann man mit CloseHanlde(HANDLE) schließen, aber HINTERNET benötigt die Funktion InternetCloseHandle(HINTERNET). Wenn ein Handle nicht valid ist, hat es einen negativen Wert. Hier die Beschreibung der benötigten Funktionen

HINTERNET InternetOpen(char* pcAgent, DWORD dwAccessType,
                       char* pcProxyName, char* pcProxyBypass,
                       DWORD dwFlags);
 

InternetOpen stellt eine Verbindung mit dem Internet her. Dann gehen wir mal die Parameter durch.
  • Mit pcAgent geben wir das gewünschte Programm an, über das wir online gehen wollen. Für uns wird das "Microsoft Internet Explorer" sein.
  • dwAccessType gibt an, wie wir in das Internet gehen wollen. Mit INTERNET_OPEN_TYPE_PRECONFIG benutzen wir die Einstellungen aus der Registry. Das ist, denke ich, die beste Lösung, da so auch eventuell gebrauchte Proxys genutzt werden.
  • Wenn wir INTERNET_OPEN_TYPE_PRECONFIG für dwAccessType nutzen, müssen wir bei pcProxyName NULL angeben.
  • Wenn wir INTERNET_OPEN_TYPE_PRECONFIG für dwAccessType nutzen, müssen wir bei pcProxyBypass NULL angeben.
  • dwFlags ist für uns uninteressant - also auch hier 0.
Der Rückgabewert ist ein HINTERNET Handle auf die geöffnete Internetverbindung

HINTERNET InternetOpenUrl(HINTERNET hInternet, char* pcURL,
                          char* pcHeaders, DWORD dwHeadersLength,
                          DWORD dwFlags, DWORD* pdwContext);
 

InternetOpenUrl öffnet eine Seite, sodass wir sie im nächsten Schritt auslesen können. Dann gehen wir mal die Parameter durch.
  • hInternet ist das Handle von InternetOpen
  • pcURL ist die Adresse, die wir öffnen wollen.
  • pcHeaders ist für uns NULL.
  • dwHeadersLength ist für uns 0.
  • dwFlags wird für uns INTERNET_FLAG_RELOAD sein. Das gibt an, dass wir die Seite neu laden und nicht die gespeicherten Offlineinhalte des Computers benutzen.
  • pdwContext ist für uns uninteressant.
Der Rückgabewert ist wieder ein HINTERNET Handle, nur diesmal auf die nun geöffnete Seite.

BOOL InternetReadFile(HINTERNET hFile, void* pBuffer,
                      DWORD dwNumberOfBytesToRead, DWORD dwNumberOfBytesRead);
 

Mit der Funktion InternetReadFile lesen wir eine Datei im Web aus. Dies sind die Parameter
  • hFile ist das HINTERNET Handle von InternetOpenUrl.
  • Die Daten werden in pBuffer gespeichert.
  • Die Anzahl der Bytes, die gelesen werden sollen.
  • Die Anzahl der Bytes, die gelesen werden. Hier müssen wir eine DWORD Variable angeben.
Ich sollte noch erwähnen, dass nur dann das Internet "geöffnet" wird, wenn auch eine Verbindung besteht. Das heißt, das ganze funktioniert nur, wenn der Benutzer im Internet ist. Dadurch stellen wir sicher, dass wir keine zusätzlichen Kosten verursachen.

Das Beispiel

So, jetzt wissen wir alles. Jetzt wollen wir nur noch ein kleines Programm schreiben, welches eine Verbindung zum Internet herstellt und eine URL öffnet. Das hinterlegte Skript ist ähnlich wie dem von oben. Es prüft die Variable $product. Ist sie gleich "Versionskontrolle", gibt das Skript 3 aus, sonst "err". Ich hoffe ihr verzeiht mir die vielen Umbrüche in Funktionen und Strings, aber sie sind notwendig, damit man auch bei niedrigeren Auflösungen nicht ständig zur Seite scrollen muss .


/********************************************************
 *                                                      *
 *                                                      *
 *    Main.cpp                                          *
 *    ========                                          *
 *    Autor: Seku                                       *
 *    Zweck: Beispiel für WinINet-Funktionen            *
 *                                                      *
 *                                                      *
 ********************************************************/

#include <Windows.h>
#include <StdIO.h>
#include <WinINet.h>

// ======================================================
// Prüft die Version
int GetVersion(char* pcURL)
{
        DWORD               dwNumAllBytesRead;
        DWORD               dwNumBytesRead;
        char*               pcBuffer;
        char*               pcTemp;

        // Das Internet öffnen
        HINTERNET hInternet = InternetOpen("Microsoft Internet Explorer",
                                           INTERNET_OPEN_TYPE_PRECONFIG,
                                           NULL, 0, 0);
        if(!hInternet) return -1;

        // Die URL öffnen
        HINTERNET hURL = InternetOpenUrl(hInternet, pcURL, NULL, 0,
                                         INTERNET_FLAG_RELOAD, 0);
        if(!hURL) return -1;

        // Wir starten die Leseschleife
        pcBuffer = (char*)malloc(sizeof(char) * 128);
        pcTemp = pcBuffer;
        do
        {
                // In jedem Durchgang lesen wir 16 Bytes
                if(!InternetReadFile(hURL, pcTemp, 16, &dwNumBytesRead))
                        return -1;

                // Den Zeiger und den Zähler weiterschieben
                dwNumAllBytesRead += dwNumBytesRead;
                pcTemp += dwNumBytesRead;
        } while(dwNumBytesRead);

        // Alles schließen
        InternetCloseHandle(hURL);
        InternetCloseHandle(hInternet);

        // Den String beenden
        pcBuffer[dwNumAllBytesRead] = '';

        // Alles OK! Wir geben die Version zurück
        return atoi(pcBuffer);
}

// ======================================================
// Die Hauptfunktion
int WINAPI WinMain(HINSTANCE hInstance,
                                   HINSTANCE hPrevInstance,
                                   char* pcCmdLine,
                                   int iShowCmd)
{
        char        acText[128];
        int         iCurrentVersion = 1;

        // Wir fragen die Version ab
        int iVersion = GetVersion("http://www.seku.info/"
                                  "articles/winapi/internet/version.php"
                                  "?product=Versionskontrolle");
        if(iVersion == -1)
        {
                // Fehler
                MessageBox(NULL, "Fehler bei der Versionskontrolle", "Fehler",
                           MB_OK | MB_ICONERROR);
                return FALSE;
        }


        // Die Version ausgeben
        sprintf(acText, "Ihre Version: %d\nNeuste Version: %d\n%s",
                        iCurrentVersion, iVersion,
                        iVersion == iCurrentVersion ?
                        "Sie haben die aktuelle Version."
                        : "Sie haben eine veraltete Version.");
        MessageBox(NULL, acText, "Versionskontrolle", MB_OK | MB_ICONEXCLAMATION);

        // Alles OK!
        return TRUE;
}


Gehen wir also den Code durch. Die komplette WinMain() sollte klar sein. Ich werde also nur auf die GetVersion() eingehen. Am Anfang öffnet sie die Adresse per Internet Explorer. Dann kommt eine Leseschleife. Davor reservieren wir noch ein bisschen Speicher für die Daten, die wir von der Seite bekommen und legen einen zweiten Pointer auf diesen Speicher an. In der Schleife lesen wir immer 16 Bytes in den temporären Pointer (pcTemp) ein. Dabei schieben wir ihn nach jedem Durchgang weiter. Da InternetReadFile() in dwNumBytesRead nur die Anzahl an Bytes reinschreibt, die in diesem Durchgang gelesen wurden, gibt es eine weitere Variable (dwNumAllBytesRead), die speichert wie viel insgesamt gelesen wurde. Ist alles eingelesen, können wir damit den gelesenen String am Ende abbrechen (''). In diesem Fall ist das eigentlich unnötig, da die Funktion atoi() das übernimmt. Nach der Schleife habe ich dann nur noch pcBuffer und nicht mehr pcTemp benutzt. Das hat den einfahcen Grund, dass pcBuffer an den Anfang des reservierten Speichers zeigt, währen pcTemp immer verändert wurde. Natürlich ist zu beachten, dass es einen Fehler à la "Access Violation" geben kann, wenn wir mehr als 128 Bytes von der Internetseite bekommen, weil der Buffer ja nur so groß ist.

Ende

Das war auch schon das Tutorial. Ich hoffe ihr seid mal wieder schlauer. Ich kann nur einen Blick in die MSDN empfehlen, denn dort sieht man die restlichen Internetfunktionen, welche auch sehr interessant sind. Sollte noch etwas unklar sein, dann schreibt mir eine Mail.

cu, Seku.




Alle Inhalte stehen, wenn nicht anders angegeben, unter dem Copyright von Seku.
Für die Inhalte externer Seiten ist der jeweilige Betreiber verantwortlich.
seku.info v.3.2, Benötigte Zeit: 0,300 Sekunde(n)
Ausgeführte mySQL-Anfragen: 0
17:26