C++ Consolen Code in VCL umschreiben



  • Hi,
    ich habe einen C++ Quellcode in Console will es Jedoch in VCL umschreiben aber es Funktioniert nicht. Könnte jemand mir dabei Helfen würd mich sehr freuen.

    //---------------------------------------------------------------------------
    
    #include <vcl.h>
    #pragma hdrstop
    
    #include "Unit2.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm2 *Form2;
    //---------------------------------------------------------------------------
    __fastcall TForm2::TForm2(TComponent* Owner)
    	: TForm(Owner)
    {
    }
    //---------------------------------------------------------------------------
    
    /////////////////////////////// hier drüber ist der VCL Formular //////////////////////  
    
    ///////// hier unten fängt die Consolen Anwendung an ///  ich versuche es oben einzubauen weis aber nicht wie es geht ///////////// 
    
    #include <iostream>
    #include <fstream>
    #include <stdexcept> // runtime_error
    #include <sstream>
    #ifdef linux
    #include <sys/socket.h> // socket(), connect()
    #include <arpa/inet.h> // sockaddr_in
    #include <netdb.h> // gethostbyname(), hostent
    #include <errno.h> // errno
    #else
    #include <winsock2.h>
    #endif
    using namespace std;
    
    std::runtime_error CreateSocketError()
    {
        std::ostringstream temp;
    #ifdef linux
        temp << "Socket-Fehler #" << errno << ": " << strerror(errno);
    #else
        int error = WSAGetLastError();
        temp << "Socket-Fehler #" << error;
        char* msg;
        if(FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                         NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                         reinterpret_cast<char*>(&msg), 0, NULL))
        {
            try
            {
                temp << ": " << msg;
                LocalFree(msg);
            }
            catch(...)
            {
                LocalFree(msg);
                throw;
            }
        }
    #endif
        return std::runtime_error(temp.str());
    }
    
    void SendAll(int socket, const char* const buf, const int size)
    {
        int bytesSent = 0; // Anzahl Bytes die wir bereits vom Buffer gesendet haben
        do
        {
            int result = send(socket, buf + bytesSent, size - bytesSent, 0);
            if(result < 0) // Wenn send einen Wert < 0 zurück gibt deutet dies auf einen Fehler hin.
            {
                throw CreateSocketError();
            }
            bytesSent += result;
        } while(bytesSent < size);
    }
    
    // Liest eine Zeile des Sockets in einen stringstream
    void GetLine(int socket, std::stringstream& line)
    {
        for(char c; recv(socket, &c, 1, 0) > 0; line << c)
        {
            if(c == '\n')
            {
                return;
            }
        }
        throw CreateSocketError();
    }
    
    // Entfernt das http:// vor dem URL
    void RemoveHttp(std::string& URL)
    {
        size_t pos = URL.find("http://");
        if(pos != std::string::npos)
        {
            URL.erase(0, 7);
        }
    }
    
    // Gibt die Dateiendung im URL zurück
    std::string GetFileEnding(std::string& URL)
    {
        using namespace std;
        size_t pos = URL.rfind(".");
        if(pos == string::npos)
        {
            return "";
        }
        URL.erase(0, pos);
        string ending = ".";
        // Algorithmus um Sachen wie ?index=home nicht zuzulassen
        for(string::iterator it = URL.begin() + 1; it != URL.end(); ++it)
        {
            if(isalpha(*it))
            {
                ending += *it;
            }
            else
            {
                break;
            }
        }
        return ending;
    }
    
    // Gibt den Hostnamen zurück und entfernt ihn aus der URL, sodass nur noch der Pfad übrigbleibt
    std::string RemoveHostname(std::string& URL)
    {
        size_t pos = URL.find("/");
        if(pos == std::string::npos)
        {
            std::string temp = URL;
            URL = "/";
            return temp;
        }
        std::string temp = URL.substr(0, pos);
        URL.erase(0, pos);
        return temp;
    }
    
    int main()
    {
        using namespace std;
    
    	//cout << "URL: ";
    	Memo1->Lines->Add("Bitte URL eingeben!\n");
    	UnicodeString URL = Edit1->Text;
        //cin >> URL; // User gibt URL der Datei ein, die herruntergeladen werden soll
    
    #ifndef linux
        WSADATA w;
        if(int result = WSAStartup(MAKEWORD(2,2), &w) != 0)
        {
    		//cout << "Winsock 2 konnte nicht gestartet werden! Error #" << result << endl;
    		Memo1->Lines->Add("Winsock 2 konnte nicht gestartet werden!\n");
    		return 1;
        }
    #endif
    
        RemoveHttp(URL);
    
        string hostname = RemoveHostname(URL);
    
        hostent* phe = gethostbyname(hostname.c_str());
    
        if(phe == NULL)
        {
    		//cout << "Host konnte nicht aufgeloest werden!" << endl;
    		Memo1->Lines->Add("Host konnte nicht aufgeloest werden!\n");
            return 1;
        }
    
        if(phe->h_addrtype != AF_INET)
        {
    		//cout << "Ungueltiger Adresstyp!" << endl;
    		Memo1->Lines->Add("Ungueltiger Adresstyp!\n");
    		return 1;
        }
    
        if(phe->h_length != 4)
        {
    		//cout << "Ungueltiger IP-Typ!" << endl;
    		Memo1->Lines->Add("Ungueltiger IP-Typ!\n");
            return 1;
        }
    
        int Socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
        if(Socket == -1)
        {
    		//cout << "Socket konnte nicht erstellt werden!" << endl;
    		Memo1->Lines->Add("Socket konnte nicht erstellt werden!\n");
    		return 1;
        }
    
        sockaddr_in service;
        service.sin_family = AF_INET;
        service.sin_port = htons(80); // Das HTTP-Protokoll benutzt Port 80
    
        char** p = phe->h_addr_list; // p mit erstem Listenelement initialisieren
        int result; // Ergebnis von connect
        do
        {
            if(*p == NULL) // Ende der Liste
    		{
    			//cout << "Verbindung fehlgschlagen!" << endl;
    			Memo1->Lines->Add("Verbindung fehlgschlagen!\n");
                return 1;
            }
    
            service.sin_addr.s_addr = *reinterpret_cast<unsigned long*>(*p);
            ++p;
            result = connect(Socket, reinterpret_cast<sockaddr*>(&service), sizeof(service));
        }
        while(result == -1);
    
    	//cout << "Verbindung erfolgreich!" << endl;
    	Memo1->Lines->Add("Verbindung erfolgreich!\n");
    
        string request = "GET ";
        request += URL;    // z.B. /faq/index.html
        request += " HTTP/1.1\n";
        request += "Host: " + hostname + "\nConnection: close\n\n";
    
        try
        {
            SendAll(Socket, request.c_str(), request.size());
    
            int code = 100; // 100 = Continue
            string Protokoll;
            stringstream firstLine; // Die erste Linie ist anders aufgebaut als der Rest
            while(code == 100)
            {
                GetLine(Socket, firstLine);
                firstLine >> Protokoll;
                firstLine >> code;
                if(code == 100)
                {
                    GetLine(Socket, firstLine); // Leere Zeile nach Continue ignorieren
                }
            }
    		//cout << "Protokoll: " << Protokoll << endl;
    		Memo1->Lines->Add("Protokoll: "+Protokoll+"\n");
    
            if(code != 200)
            {
                firstLine.ignore(); // Leerzeichen nach dem Statuscode ignorieren
                string msg;
                getline(firstLine, msg);
    			//cout << "Error #" << code << " - " << msg << endl;
    			Memo1->Lines->Add("Fehler: "+std::string(code)+"-"+msg+"\n");
    			return 0;
            }
    
            bool chunked = false;
            const int noSizeGiven = -1;
            int size = noSizeGiven;
    
            while(true)
            {
                stringstream sstream;
                GetLine(Socket, sstream);
                if(sstream.str() == "\r") // Header zu Ende?
                {
                    break;
                }
                string left; // Das was links steht
                sstream >> left;
                sstream.ignore(); // ignoriert Leerzeichen
                if(left == "Content-Length:")
                {
                    sstream >> size;
                }
                if(left == "Transfer-Encoding:")
                {
                    string transferEncoding;
                    sstream >> transferEncoding;
                    if(transferEncoding == "chunked")
                    {
                        chunked = true;
                    }
                }
            }
    
            string filename = "download" + GetFileEnding(URL);
    		//cout << "Filename: " << filename << endl;
    		Memo1->Lines->Add("Filname: "+filename+"\n");
            fstream fout(filename.c_str(), ios::binary | ios::out);
            if(!fout)
            {
    			//cout << "Could Not Create File!" << endl;
    			Memo1->Lines->Add("Could Not Create File!\n");
    			return 1;
            }
            int recvSize = 0; // Empfangene Bytes insgesamt
            char buf[1024];
            int bytesRecv = -1; // Empfangene Bytes des letzten recv
    
            if(size != noSizeGiven) // Wenn die Größe über Content-length gegeben wurde
            {
                cout << "0%";
                while(recvSize < size)
                {
                    if((bytesRecv = recv(Socket, buf, sizeof(buf), 0)) <= 0)
                    {
                        throw CreateSocketError();
                    }
                    recvSize += bytesRecv;
                    fout.write(buf, bytesRecv);
    				cout << "\r" << recvSize * 100 / size << "%" << flush; // Mit \r springen wir an den Anfang der Zeile
    				Memo1->Lines->Add("\r"+IntToStr(recvSize * 100 / size)+"%");
    			}
    		}
            else
            {
                if(!chunked)
                {
    				//cout << "Downloading... (Unknown Filesize)" << endl;
    				Memo1->Lines->Add("Downloading... (Unknown Filesize)\n");
    				while(bytesRecv != 0) // Wenn recv 0 zurück gibt, wurde die Verbindung beendet
                    {
                        if((bytesRecv = recv(Socket, buf, sizeof(buf), 0)) < 0)
                        {
                            throw CreateSocketError();
                        }
                        fout.write(buf, bytesRecv);
                    }
                }
                else
                {
    				//cout << "Downloading... (Chunked)" << endl;
    				Memo1->Lines->Add("Downloading... (Chunked)\n");
                    while(true)
                    {
                        stringstream sstream;
                        GetLine(Socket, sstream);
                        int chunkSize = -1;
                        sstream >> hex >> chunkSize; // Größe des nächsten Parts einlesen
                        if(chunkSize <= 0)
                        {
                            break;
                        }
    					//cout << "Downloading Part (" << chunkSize << " Bytes)... " << endl;
    					Memo1->Lines->Add("Downloading Part ("+IntToStr(chunkSize)+" Bytes)... \n");
                        recvSize = 0; // Vor jeder Schleife wieder auf 0 setzen
                        while(recvSize < chunkSize)
                        {
                            int bytesToRecv = chunkSize - recvSize;
    						if((bytesRecv = recv(Socket, buf, bytesToRecv > sizeof(buf) ? sizeof(buf) : bytesToRecv, 0)) <= 0)
                            {
                                throw CreateSocketError();
                            }
                            recvSize += bytesRecv;
                            fout.write(buf, bytesRecv);
    						//cout << "\r" << recvSize * 100 / chunkSize << "%" << flush;
    						Memo1->Lines->Add("\r"+IntToStr(recvSize * 100 / chunkSize)+"%");
    					}
    					cout << endl;
    					for(int i = 0; i < 2; ++i)
                        {
                            char temp;
                            recv(Socket, &temp, 1, 0);
                        }
    				}
                }
            }
    		//cout << endl << "Finished!" << endl;
    		Memo1->Lines->Add("\nFinished!\n");
        }
        catch(exception& e)
        {
    		//cout << endl;
    		Memo1->Lines->Add("\n");
    		cerr << e.what() << endl;
    		Memo1->Lines->Add(string(e.what())+"\n");
        }
    #ifdef linux
        close(Socket); // Verbindung beenden
    #else
        closesocket(Socket); // Windows-Variante
    #endif
    system("pause");
    }
    

    Gruß

    Sapzero



  • "aber es Funktioniert nicht."

    Ja, sagt uns sehr viel! 🙂

    1. Du benutzt mehrmals using namespace std - wtf ?
    2. Wieso includest du erst paar header, deklarierst DANN den ctor, und dann includest du weiter 'n paar header.
    3. So benutzt man nicht die VCL.

    Gruß



  • **Ich denke mal es ist eher gemeint, die Umschreibung von dieser Consolenanwendung ind VCL.

    zb: gibt es kein int main(),
    std::runtime_error,
    std::ostringstream,
    ...usw.**

    (Glaube ich zumindestens weiss es aber leider nicht)

    bei einer VCL Formular Anwendung.

    Mich würde das auch brennend intressieren, weil ich hinsichtlich dieser Thematik null Ahnung habe, bei mir persönlich wurde in der Schule nur VCL Anwendungen mit dem Borland c++ Builder 5.0 gemacht, aber wenn ich jetzt im Internet nach C++ surfe, kommen tendeziell eher Consolenanwenungen als VCL. Schade dass es, der Unterricht, nicht praxis real war.



  • Lies dir btte unbedingt die mit wichtig gekennzeichneten Threads durch, bevor du irgendwo etwas postest. Es gibt ein extra Forum für VCL-Fragen, und hier im Standard-C++-Forum bist du damit eindeutig falsch.

    Verschoben.



  • Dieser Thread wurde von Moderator/in pumuckl aus dem Forum C++ in das Forum VCL (C++ Builder) verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • Hallo

    Wenn du daraus wirklich eine VCL-GUI-Anwendung machen willst, must du den Quellcode erheblich umarbeiten. Vor allem wird dir das nicht gelingen, wenn du keine Ahnung von der VCL, GUI-Prinzipien oder auch nur OOP hast. Da du offenbar nur den vorhandenen Quellcode nur irgendwo in ein VCL-Projekt hineinkopierst hast und erwartest das es läuft, gehe ich davon aus das keines zutrifft.

    bis bald
    akari



  • Insbesondere die Linuxvariante in VCL umzuschreiben scheint mir kompliziert... CLX war ja nach meinen Informationen auch nich so der Burner...

    Da stellen sich mir auf Anhieb zwei Fragen:

    1. Wo hast du den Code gefunden? ( 😃 )
    2. Bist du sicher, dass du die Linux-Variante brauchst?



  • Du hast doch hier schon gepostet. Warum hat dir denn keiner weitergeholfen?
    Hier auch nochmal 😃



  • jesus was black schrieb:

    "aber es Funktioniert nicht."

    Ja, sagt uns sehr viel! 🙂

    1. Du benutzt mehrmals using namespace std - wtf ?
    2. Wieso includest du erst paar header, deklarierst DANN den ctor, und dann includest du weiter 'n paar header.
    3. So benutzt man nicht die VCL.

    Gruß

    Das Mann nicht die VCL so benutzt ist mir schion klar.
    Wieso ich mehrmals include liegt daran, da ich ganz oben den VCL Formualr habe und darunter Die Consolen Anwendung. Ich wusste nicht wie ich es in den VCL Formualr intergrieren soll und welche Bibliotheken ich noch brauche von der consolen Anwendung und welche nicht.



  • akari schrieb:

    Hallo

    Wenn du daraus wirklich eine VCL-GUI-Anwendung machen willst, must du den Quellcode erheblich umarbeiten. Vor allem wird dir das nicht gelingen, wenn du keine Ahnung von der VCL, GUI-Prinzipien oder auch nur OOP hast. Da du offenbar nur den vorhandenen Quellcode nur irgendwo in ein VCL-Projekt hineinkopierst hast und erwartest das es läuft, gehe ich davon aus das keines zutrifft.

    bis bald
    akari

    Hi,
    wie gesagt hatte ich eine Consolen Anwendung. Ich habe es ja versucht umzuschreiben. Ich habe ja net gesagt es müsste so Funtionieren und ich weis net warum es nicht geht. Deswegen habe ich ja um Hilfe gefragt damit mir vllt jemand Helfen könnte dies umzuschreiben.



  • It0101 schrieb:

    Insbesondere die Linuxvariante in VCL umzuschreiben scheint mir kompliziert... CLX war ja nach meinen Informationen auch nich so der Burner...

    Da stellen sich mir auf Anhieb zwei Fragen:

    1. Wo hast du den Code gefunden? ( 😃 )
    2. Bist du sicher, dass du die Linux-Variante brauchst?

    Also ob ich die Linuxvariante brauche glaube nicht und wenn könnte es man später Integrieren. Vllt hätte ich erst mal fragen müssen welche header ich überhaupt von der Consolen Anwendung noch brauche.

    #include <iostream>
    #include <fstream>
    #include <stdexcept> // runtime_error
    #include <sstream>
    #ifdef linux
    #include <sys/socket.h> // socket(), connect()
    #include <arpa/inet.h> // sockaddr_in
    #include <netdb.h> // gethostbyname(), hostent
    #include <errno.h> // errno
    #else
    #include <winsock2.h>
    #endif
    using namespace std;
    

    sagen wir mal ich lasse Linux weg welche brauche ich noch?

    #include <iostream>
    #include <fstream>
    #include <stdexcept> // runtime_error
    #include <sstream>
    #include <winsock2.h>
    using namespace std;
    


  • Sorry Sapzero, aber so kommst du nicht zum Ergebnis.

    Konsolen- sowie GUI-Programme arbeiten grundverschieden.

    In einem GUI-Progamm gibt es keine Hauptfunktion mehr, in der du einfach die Funktionen sequentiell aufrufen kannst, sondern du mußt ereignisorientiert programmieren.

    Weißt du denn schon, was Module sind?

    Du müßtest zuerst einmal die Trennung von GUI und Logik hinbekommen, d.h. am besten du erzeugst dir für die bisherigen Funktionen ein eigenes Modul (Unit), d.h. Source (.cpp) und Header (.h).

    Dann erzeugst du dir ein Form, auf der du die GUI-Elemente ansprichst (d.h. die Ereignisse, z.B. Button-OnClick etc.). In den Ereignisbehandlungsroutinen rufst du dann die Funktionen aus dem anderen Modul aus (per #include "logik.h").

    Und zum Abschluß noch folgender Hinweis:
    Beim BCB gibt es schon die VCL-Klassen TServerSocket und TClientSocket, mit denen der Socket-Zugriff einfacher programmiert werden kann (da ereignisorientiert), so daß der Großteil deiner bisherigen main()-Funktion wegfällt.

    Zumindestens beim BCB 5 und 6 gibt es im Ordner "Examples" ein Beispielprogramm dafür (Chat). Fall du eine neuere Version hast, ich hatte den Source schon mal hier im Forum gepostet: http://www.c-plusplus.net/forum/viewtopic-var-t-is-247174.html



  • Th69 schrieb:

    Du müßtest zuerst einmal die Trennung von GUI und Logik hinbekommen, d.h. am besten du erzeugst dir für die bisherigen Funktionen ein eigenes Modul (Unit), d.h. Source (.cpp) und Header (.h).

    Dann erzeugst du dir ein Form, auf der du die GUI-Elemente ansprichst (d.h. die Ereignisse, z.B. Button-OnClick etc.). In den Ereignisbehandlungsroutinen rufst du dann die Funktionen aus dem anderen Modul aus (per #include "logik.h").

    Und zum Abschluß noch folgender Hinweis:
    Beim BCB gibt es schon die VCL-Klassen TServerSocket und TClientSocket, mit denen der Socket-Zugriff einfacher programmiert werden kann (da ereignisorientiert), so daß der Großteil deiner bisherigen main()-Funktion wegfällt.

    Ahh ok jetzt habe ich es verstanden danke. Ich versuch mal umzusetzten und danke für den hilfreichen Beitrag und die Tips ;).


Anmelden zum Antworten