InternetSetFilePointer -> wie mach ich das ?



  • Hallo,

    ich habe aus ein paar Threads dieses Forums eine Routine gebaut, mit der ich eine Datei per HTTP aus dem Internet lade:

    Form1->hInternet = InternetOpen("Autoupdater->Test",
                                 INTERNET_OPEN_TYPE_PRECONFIG,
                                 NULL,
                                 NULL,
                                 0);
           if(!Form1->hInternet)
        {
           Application->MessageBox("kein Internet","fehler",16);
         return;
        }
    
        Form1->hFile = InternetOpenUrl(Form1->hInternet,
                                Form1->Edit1->Text.c_str(),
                                NULL,
                                0,
                                INTERNET_FLAG_RELOAD,
                                0);
                if(!Form1->hFile)
        {
           Application->MessageBox("keine file :(","fehler",16);
    
           InternetCloseHandle(Form1->hInternet);
          return;
        }
    
        Form1->fFile = fopen(Form1->Edit2->Text.c_str(), "wb+");
        int i = 0;
    
            HttpQueryInfo(Form1->hFile, HTTP_QUERY_CONTENT_LENGTH, (LPVOID)Form1->lpszFileSize, &Form1->dwDummy, NULL);
    
        Form1->Label2->Caption = atoi(Form1->lpszFileSize);
        Form1->ProgressBar1->Max = atoi(Form1->lpszFileSize);
        Form1->ProgressBar1->Position = 0;
    
            if(atoi(Form1->lpszFileSize) == 0)
        {
           MessageBox(NULL, "The file you want to download doesn't exist\nor has file size zero",
                      "ERROR", MB_OK|MB_ICONERROR);
           InternetCloseHandle(Form1->hFile);
           InternetCloseHandle(Form1->hInternet);
           return;
        }
    
        Form1->bGO = true;
        while(Form1->bGO)
        {
        i++;
            Form1->bGO = InternetReadFile(
                Form1->hFile,
                &Form1->szBuf,
                512,
                &Form1->ReadSize);
    
            Form1->Label1->Caption = i * 1024 / 2;
            Form1->ProgressBar1->Position = i * 1024 / 2;
    
            Application->ProcessMessages();
    
            if(Form1->bGO && Form1->ReadSize == 0) break;
    
            Form1->szBuf[Form1->ReadSize] = '\0';
            fwrite(&Form1->szBuf, 1, Form1->ReadSize, Form1->fFile);
        }
        fclose(Form1->fFile);
        InternetCloseHandle(Form1->hFile);
        InternetCloseHandle(Form1->hInternet);
    

    dann habe ich gelesen, dass es einen Befehl gibt, mit der man eine zum teil heruntergeladene datei "resumen" kann
    mit dem befehl:InternetSetFilePointer

    nur weiß ich nicht genau, wie oder wo ich den Befehl da nun einsetzen muss 😕

    ich hoffe, ihr könnt mir helfen

    💡

    Tim



  • Da du offensichtlich keine VCL-Kompo sondern WinAPI einsetzt, bist du da wohl besser aufgehoben, ne?
    Aber les dir trotzdem mal noch den FAQ-Beitrag zu Public-Variablen durch...
    So, und nu wird geschoben.

    ->Verschoben nach WinAPI



  • argh... stimmt, danke 😃

    Tim





  • das ich einen code nutze und der dann falsch ist 😕

    Tim



  • Einfach vor InternetReadFile aufrufen, um den File-Pointer an der entsprechenden Stelle zu positionieren



  • ok, ich hab es hinbekommen

    nun will ich nur noch wissen, wie man den downloadspeed begrenzen kann...

    Tim



  • Evtl. geht's auch eleganter, aber du könntest in deiner "Auslese-Schleife" doch einfach dafür sorgen, dass die Ausführung erst fortgeführt wird, wenn eine bestimmte Zeit vergangen ist - nur mal als Idee 😉



  • jo, aber das wäre ziemlich unprofessionnell 😃

    Tim



  • wieso unprofessionell?



  • na ja... weil das das net wirklich einschränkt, ich will ja eine genaue angabe machen wie maximal 20kb/s oder so

    Tim



  • wieso nicht, du kannst doch z.B. ein 5 KB packet laden, und wenn dann 1/4s noch nicht rum ist wartest du entsprechend



  • ok, aber nun zum topic zurück:

    das mit resume geht doch net:
    der code:

    Form1->fFile = fopen(Form1->Edit2->Text.c_str(), "a+");    // wb+
    
       Form1->curpos = ftell(Form1->fFile);
       fseek(Form1->fFile, 0L, SEEK_END);
       Form1->length = ftell(Form1->fFile);
       fseek(Form1->fFile, Form1->curpos, SEEK_SET);
    
       for (int f = 0;f < 5;f++)
       {
            HttpQueryInfo(Form1->hFile, HTTP_QUERY_CONTENT_LENGTH, (LPVOID)Form1->lpszFileSize, &Form1->dwDummy, NULL);
    
        Form1->Label2->Caption = atoi(Form1->lpszFileSize);
        Form1->ProgressBar1->Max = atoi(Form1->lpszFileSize);
        Form1->ProgressBar1->Position = 0;
                                              //atoi(Form1->lpszFileSize)
    
        if(atoi(Form1->lpszFileSize) != 0)
        {
    
        /*
           MessageBox(NULL, "The file you want to download doesn't exist\nor has file size zero",
                      "ERROR", MB_OK|MB_ICONERROR);
           InternetCloseHandle(Form1->hFile);
           InternetCloseHandle(Form1->hInternet);
           return 0;
    
           */
           f = 6;
        }
    
        }
    
            if(atoi(Form1->lpszFileSize) == 0)
        {
    
           MessageBox(NULL, "The file you want to download doesn't exist\nor has file size zero",
                      "ERROR", MB_OK|MB_ICONERROR);
           InternetCloseHandle(Form1->hFile);
           InternetCloseHandle(Form1->hInternet);
           return 0;
    
        }
    
    Form1->Button1->Caption = Form1->length;
        Form1->bGO = true;
    
        while(Form1->bGO)
        {
    
        if (Form1->length != 0)
        {
            InternetSetFilePointer(Form1->hFile,Form1->length,0,FILE_CURRENT,0);
    
        }
        Form1->bei++;
    
            Form1->bGO = InternetReadFile(
                Form1->hFile,
                &Form1->szBuf,
                512,
                &Form1->ReadSize);
    
            Form1->Label1->Caption = Form1->bei * 1024 / 2 + Form1->grosse * sizeof(Form1->buf);
            Form1->ProgressBar1->Position = Form1->bei * 1024 / 2 + Form1->grosse * sizeof(Form1->buf);
    
            Application->ProcessMessages();
    
            if(Form1->bGO && Form1->ReadSize == 0) break;
    
            Form1->szBuf[Form1->ReadSize] = '\0';
            fwrite(&Form1->szBuf, 1, Form1->ReadSize, Form1->fFile);
        }
        fclose(Form1->fFile);
        InternetCloseHandle(Form1->hFile);
        InternetCloseHandle(Form1->hInternet);
    

    ich hoffe, ihr könnt helfen 😞

    Tim



  • Ohne jetzt den Code groß angeschaut zu haben: was geht denn nicht?



  • na ja... er lädt was runter, aber die datei stimmt dann nicht (zu klein)

    Tim



  • könntest du den Code vielleicht etwas kürzen und das rauslassen, was eh nichts damit zu tun hat 🙄



  • na ja... weiter kürzen wäre dumm... eigentlich gehört der ganze quellcode dazu

    und vielleicht liegt der fehler ja da

    Also, der Fehler ist, dass beim Resume eigentlich gar nichts runtergeladen wird....

    Tim



  • Ok, ich hab den Fehler:

    das

    InternetSetFilePointer(Form1->hFile,Form1->length,0,FILE_CURRENT,0);

    darf nicht in der While-Schleife stehen, sondern davor

    Tim



  • ok,

    1 Problem:
    Wenn man SetInternetFilePointer ausführt, dann ist das kein wirkliches Resume, da er die Datei bis zu der angegebenen Position erstmal temporär herunterlädt und dann ab der angegebenen Position die Daten in der angegebenen Datei speichert

    wisst ihr, was das Problem ist 😕

    Tim



  • ok, selbst ist der Mann 🙂

    es funktioniert

    Hier nochmal der Code:

    /*
    ein paar Einstellungen:
    */
    Form1->bei = 0;
    Form1->Button1->Caption = "Abbrechen";
    Form1->ProgressBar1->Position = 0;
    Form1->ProgressBar1->Max = 1;
    Form1->length = 0;
    
        Form1->hInternet = InternetOpen("Autoupdater->Test",INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,0); // Verbindung zum Internet herstellen
        if(!Form1->hInternet) // prüfen, ob im Internet -> wenn nicht, dann beenden
        {
        Application->MessageBox("Kein Internet.","Fehler",16);
        Form1->Button1->Caption = "Download";
        Form1->CheckBox1->Enabled = true;
        if (Form1->CheckBox1->Checked == true) Form1->Edit3->Enabled = true;
        return 0;
        }
    
        if (Form1->resume == false) // schauen, ob resume oder nicht und je nach dem unterschiedliche Flags setzen
        {
        Form1->hFile = InternetOpenUrl(Form1->hInternet,Form1->Edit1->Text.c_str(),NULL,0,INTERNET_FLAG_RELOAD,0); // Link öffnen, der in Edit1 steht
        }
        else
        {
        Form1->hFile = InternetOpenUrl(Form1->hInternet,Form1->Edit1->Text.c_str(),NULL,0,INTERNET_FLAG_NO_CACHE_WRITE,0); // Link öffnen, der in Edit1 steht
        }
        if(!Form1->hFile) // prüfen, ob Datei existiert -> wenn nicht, dann beenden    
        {
        Application->MessageBox("Keine Datei gefunden.","Fehler",16);
        InternetCloseHandle(Form1->hInternet);
        Form1->Button1->Caption = "Download";
        Form1->CheckBox1->Enabled = true;
        if (Form1->CheckBox1->Checked == true) Form1->Edit3->Enabled = true;
        return 0;
        }
    
       for (int f = 0;f < 5;f++)
       {
       /*
       das ganze 5 mal versuchen, da man die Größe nicht immer beim ersten mal bekommt
       */                                                                             
       if (String(HttpQueryInfo(Form1->hFile, HTTP_QUERY_CONTENT_LENGTH, (LPVOID)Form1->lpszFileSize, &Form1->dwDummy, NULL)) == "1") // Größe der Datei im Internet auslesen
       {
       Form1->ProgressBar1->Max = atoi(Form1->lpszFileSize);
       Form1->ProgressBar1->Position = 0;
       if(atoi(Form1->lpszFileSize) != 0) // wenn wir die Größe haben, dann aus der for schleife raus
       {
       f = 6;
       }
       }
       }
    
       if(atoi(Form1->lpszFileSize) == 0) // wenn man die Größe nicht herausbekommen hat, dann beenden
       {
       MessageBox(NULL, "Die Datei existiert nicht oder hat die Größe 0.","Fehler", MB_OK|MB_ICONERROR);
       InternetCloseHandle(Form1->hFile);
       InternetCloseHandle(Form1->hInternet);
       Form1->Button1->Caption = "Download";
       Form1->CheckBox1->Enabled = true;
       if (Form1->CheckBox1->Checked == true) Form1->Edit3->Enabled = true;
       return 0;
       }
    
        if (Form1->resume == false) // schauen, ob man Resumen will
        {
        Form1->fFile = fopen(Form1->Edit2->Text.c_str(), "wb+"); // Die Datei, die in Edit2 steht öffnen
        }
        else
        {
        Form1->fFile = fopen(Form1->Edit2->Text.c_str(), "ab+");  // Datei öffnen, die in Edit2 steht
        Form1->curpos = ftell(Form1->fFile);          //
        fseek(Form1->fFile, 0L, SEEK_END);            // Größe (in Bytes) der Datei in Edit2 herausfinden, für Resume
        Form1->length = ftell(Form1->fFile);          //
        fseek(Form1->fFile, Form1->curpos, SEEK_SET); //
        }
    
       Form1->bGO = true;
    
       if (Form1->resume == true)
       {
       InternetSetFilePointer(Form1->hFile,Form1->length,0,FILE_CURRENT,0); // wenn resumet wird, zeiger auf die stelle setzen, wie groß die schon heruntergeladene Datei ist
       //Application->MessageBox("nach InternetSetFilePointer","a",0);
       }
        Form1->anzahl_runtergeladen = 0;
    
        LARGE_INTEGER ilPerfFreq;                //
        QueryPerformanceFrequency(&ilPerfFreq);  // Stoppuhr für Resume starten
        LARGE_INTEGER ilStartTime;               //
        QueryPerformanceCounter(&ilStartTime);   //
    
        while((Form1->bGO) && (Form1->beenden == false)) // solange man nicht die Datei heruntergeladen hat und nicht beendet wurde
        {
    
            if (((double(double(StrToInt(Form1->Edit3->Text)) * double(1024) / double(5))) >= double(Form1->anzahl_runtergeladen)) || (Form1->CheckBox1->Checked == false))
            /*
            Wenn Limit eingestellt, dann:
            - 1sekunde in 5 teile teilen: dann ausrechnen, wie viel bytes man in einem der 5 teile einer sekunde herunterladen kann
            wenn man schon zu viel heruntergeladen hat, wird nichts weiter heruntergeladen
            wenn man weniger hat, wird weiter runtergeladen
            */
            {
            Form1->bei++; // wie viel durchgänge man insgesamt hat wird erhöht
            //Application->MessageBox("davor","a",0);
            Form1->bGO = InternetReadFile(Form1->hFile,&Form1->szBuf,Form1->bytes_lesen,&Form1->ReadSize); // es wird die datei im internet gelesen und bytes_lesen bytes werden heruntergeladen
            //Application->MessageBox("gelesen","a",0);
            Form1->ProgressBar1->Position = double(Form1->bei * Form1->bytes_lesen) + Form1->length;                                                                            //
            Form1->Label6->Caption = FloatToStrF(((double((double(Form1->bei * Form1->bytes_lesen + Form1->length) * 100) / atoi(Form1->lpszFileSize)))),ffNumber,3,0) + " %";  // ProgressBar und Prozentanzeige updaten
            if (((double((double(Form1->bei * Form1->bytes_lesen + Form1->length) * 100) / atoi(Form1->lpszFileSize)))) > double(100.0)) { Form1->Label6->Caption = "100 %";}   //
    
            Application->ProcessMessages();
            if(Form1->bGO && Form1->ReadSize == 0) break;            //
            Form1->szBuf[Form1->ReadSize] = '\0';                    //
            fwrite(&Form1->szBuf, 1, Form1->ReadSize, Form1->fFile); // heruntergeladene Bytes in die Datei schreiben
            Form1->anzahl_runtergeladen = Form1->anzahl_runtergeladen + Form1->bytes_lesen; // anzahl_heruntergeladen um bytes_lesen erhöhen, für Limit
            }
            else // wenn man schon zu viel heruntergeladen hat:
            {
            QueryPerformanceCounter(&Form1->ilCurrentTime);
            double dlTimeElapsed = (long double)(Form1->ilCurrentTime.QuadPart -
            Form1->ilStartTime.QuadPart)/((long double)Form1->ilPerfFreq.QuadPart);
            Sleep(double((double(1) / double(5)) - double(dlTimeElapsed)) * double(1000)); // schauen, wie lange es noch dauert, bis der eine teil der sekunde um ist und solange sleep
            }
    
            if (Form1->CheckBox1->Checked == true) // wenn ein limit eingestellt
            {
    
            QueryPerformanceCounter(&Form1->ilCurrentTime);
            double dlTimeElapsed = (long double)(Form1->ilCurrentTime.QuadPart -
            Form1->ilStartTime.QuadPart)/((long double)Form1->ilPerfFreq.QuadPart);
    
            if (dlTimeElapsed * 5 >= 1) // wenn ein Teil der Sekunde erreicht wurde:
            {
            Form1->anzahl_runtergeladen = 0; // anzahl_heruntergeladen wieder auf 0 setzen
    
            QueryPerformanceFrequency(&Form1->ilPerfFreq);
    
            QueryPerformanceCounter(&Form1->ilStartTime);
    
            }
            }
    
        }
        fclose(Form1->fFile);                    //
        InternetCloseHandle(Form1->hFile);       // Datei und Internet schließen
        InternetCloseHandle(Form1->hInternet);   //
    

    ein paar Worte dazu:
    in Edit1 steht der InternetURL
    in Edit2 steht der URL, wohin die Datei geladen werden soll
    in Edit3 steht das Limit in kb/s, wenn CheckBox1->Checked = true

    <--- da sieht man bestimmt nicht durch

    Der Fehler war, dass beim Resume bei InternetOpenURL eine andere Flag gesetzt werden musste

    Tim

    P.S.
    vielleicht kann man das ja zu dem FAQ hinzufügen :p
    P.P.S.
    ich habe das an B&M Raid geschickt (die Seite kennen bestimmt einige hier)
    da wird das dann, denke ich, auch zu sehen sein

    Tim



  • Was hat eine reine (und damit umständliche) WinAPI-Lösung bei B&M zu suchen, wenn man das Ganze z.B. mit den Indy-Komponenten in echter RAD-Manier viel einfacher lösen kann? 😉


Anmelden zum Antworten