# InternetReadFile



## trolly (18. Juli 2008)

Ich möchte mit InternetReadFile Dateien direkt vom FTP lesen, also den Text dann mit sscanf auslesen. Text1 = hallo  Text2 = test123. Aber komme mit der Funktion noch nicht so zurecht, habe ja wie bereits erwähnt, erst seit kurzem mit C++ angefangen. Hoffe ihr könnt mir ein BeispielCode liefern.

Danke.


----------



## KD3 (18. Juli 2008)

Möchte nicht böse oder so sein, aber bevor du dich an eher fortgeschritteneren Themen ranwagst solltest du erst Erfahrung mit der Konsole haben.

Funktionen die du brauchst:

InternetOpen
InternetOpenUrl
InternetReadFile
InternetCloseHandle


----------



## trolly (18. Juli 2008)

Habe das ganze jetzt so gemacht.

http://rafb.net/p/Kb65wd16.html

Allerdings wird immer nur Text1 ausgelesen, Text2 bleibt NULL :/

Was habe ich falsch gemacht?


----------



## KD3 (18. Juli 2008)

Ich werde dich mal auf einen Thread verweisen. Ich würd dir gerne die Komplett Lösung wohl posten aber davon lernt man garnichts. Besser wäre es wirklich wenn du dir selbst hilfst und deinen Fehler selber erkennst.

http://www.c-plusplus.de/forum/view...is-0-and-postorder-is-asc-and-start-is-0.html


----------



## trolly (18. Juli 2008)

Wie ich das hasse, in den meisten Boards wird man sofort auf ein anderes verwiesen. Dazu ist doch keine Community da, oder? Anstatt einfach mal die Lösung zu posten.. Dadurch lernt man auch seine Fehler kennen und hat für das nächste mal etwas dazugelernt.


----------



## trolly (20. Juli 2008)

Hilf mir doch KD3 und sei nicht so stur ;p bitte.


----------



## devDevil (21. Juli 2008)

Lad einfach mal deinen Code nochmal hoch ...

probiers mal so:

```
#pragma comment (lib, "Wininet.lib")

#include <windows.h>
#include <Wininet.h>
#include <string>
#include <iostream>

const bool read_file(std::string const&, std::string&);

int main()
{
    std::string content;
    if (!read_file("http://www.devilentertainment.de/index.php", content)) return 1;

    const std::string::size_type pos_text1(content.find("Text1="));
    if (pos_text1 != std::string::npos) std::clog << content.substr(pos_text1);
}

const bool read_file(std::string const& url, std::string& destination)
{
    ::HINTERNET hInternet(::InternetOpenA("Line Interpreter", LOCAL_INTERNET_ACCESS, NULL, 0, 0);
    if (hInternet == NULL) { std::cerr << "FEHLER: Es konnte keine Internetverbindung aufgebaut werden!"; return false; }

    ::HINTERNET hUrl(::InternetOpenUrlA(hInternet, url.c_str(), NULL, NULL, NULL, NULL));
    if (hUrl == NULL) { std::cerr << "FEHLER: Ungültige Internetadresse (URL)!"; return false; }

    char buffer[1024];
    DWORD read_bytes(0UL);
    destination.clear();

    while (::InternetReadFile(hUrl, buffer, 1024, &read_bytes) == TRUE && read_bytes != 0) destination += buffer;

    ::InternetCloseHandle(hUrl);
    ::InternetCloseHandle(hInternet);

    return true;
}
```


----------



## trolly (21. Juli 2008)

Danke.  

http://www.nopaste.com/p/a20tiEwjD

Hier nochmal mein Code, werde gleich mal deinen ausprobieren.

//

Wenn ich bei deinem Code das Ganze dann wieder per sscanf scanne, bekomme ich wieder nur den 1.Text zu Gesicht und mit deiner Funktion in Main in komme ich nicht zurecht. Kannst dir ja nochmal meinen gepasteten Code anschauen. Danke.


----------



## trolly (22. Juli 2008)

Habe mein Problem noch immer nicht gelöst.  Habe meinen Coden nochmal an meinen vorherigen Post angehängt.


----------



## devDevil (23. Juli 2008)

Deine while-Schleife macht keinen Sinn. Du ließt nur 1 mal ein.


----------



## trolly (23. Juli 2008)

Naja, wenn ich deinen geposteten Code / deine while schleife benutze, hab ich das selbe Problem. (Lese halt per sscanf aus) mit deinem Code wird mir auch nur der 1. Wert ausgegeben.


----------



## trolly (23. August 2008)

Also,

ich lese das ganze jetzt so aus


content.find("Text1=");

funktioniert auch soweit, allerdings werden dann alle strings unterhalb von text1 auch noch ausgelesen. Die darüberliegenden hingegen nicht. Kann ich mit content.find auch zeile für zeile auslesen? also ich möchte ja mehrere strings auslesen, allerdings halt alle einzeln...


----------



## Thomasio (24. August 2008)

Internet Verbindungen haben eine recht kleine Package Grösse (meistens ca 1KB) und wenn die übertragenen Daten grösser sind als die Paketgrösse, dann wird das Ganze automatisch in mehrere Pakete aufgeteilt.
WinInet bricht die Verbindung ab, wenn die maximale Paketgrösse erreicht ist, auch wenn im buffer noch reichlich Platz wäre.
Du brauchst ZWEI buffer, und einen loop, der weiter liest, bis keine Daten mehr kommen.

Etwa in dieser Art:


```
std::stringstream AllData;
unsigned long len;
do{
char buffer[1024];
InternetReadFile(hUrl, buffer, sizeof buffer, &len);
buffer[len] = '\0';
AllData << buffer;
} while(len);
```

Wenn du das Ganze dann wieder als PCHAR brauchst, hilft strcopy()


----------



## StehtimSchilf (20. April 2010)

Hi Thomasio

ich habe Deinen Teil mit dem stringstream in meine Http-Klasse übernommen:

```
if (HttpSendRequest(request, NULL, 0, NULL, 0)) {
	unsigned long len; 
	std::stringstream ssBuffer; 
	do{
		char antwortbuffer[1024];
		InternetReadFile(request, antwortbuffer, sizeof antwortbuffer, &len);
		antwortbuffer[len] = '\0';
		ssBuffer << antwortbuffer;
	} while(len);

	// das folgende ist von mir
	// Ziel ist es, den ssBuffer in eine std::wstring Variable zu kriegen
	std::string stmp;
	std::wstring wstmp;
	stmp = ssBuffer.str();
	wstmp = StringToWString(stmp);
	std::cout << "sendRequest(): " << stmp << "EOL" << std::endl;
	std::cout << "sendRequest(): " << strlen(stmp.c_str()) << std::endl;
	std::wcout << "sendRequest(): " << wstmp << "EOL" << std::endl;
	std::wcout << "sendRequest(): " << _tcslen(wstmp.c_str()) << std::endl;

	result = 1;
} else {
	// mach was anders	
}
```

Die Webseite liefert je nach Request "OK", "FORBIDDEN", "UNAUTHORIZED", "ERROR", ... zurück

Was raus kommt, wenn die Seite "OK" zurückgibt, ist folgendes:

```
OKEOLequest():
sendRequest(): 3
OKEOLequest():
sendRequest(): 3
```


Und ich poste, weil ich das nicht versteh':
- Warum beträgt die Länge 3, wenn doch nur "OK" zurückgegeben wird?
- Warum wird bei "sendRequest():" die ersten 5 Zeichen mit "OKEOL" überschrieben? Ich würde nämlich folgenden Output erwarten: sendRequest(): OKEOL
- Wie krieg ich also nur "OK" in meine stmp, wstmp Variablen?

Denn wenn ich folgendes ausführe:

```
void test1() {
	char cBuff[100] = "Hallo Welt";
	std::stringstream ssBuffer; 

	ssBuffer << cBuff;

	std::string s1;
	s1 = ssBuffer.str();

	std::cout << "test1(): " << s1 << "EOL" << std::endl;
	std::cout << "test1(): " << strlen(s1.c_str()) << std::endl;
}
```
Erhalte ich nämlich:

```
test1(): Hallo WeltEOL
test1(): 10
```
Die Länge entspricht 'wirklich' "Hello World" (10) und EOL wird hinter die std::string Variable geschrieben.

Ich habe versucht mit std::substr() das letzte Zeichen (
	
	
	



```
stmp.substr(0, stmp.length() -1)
```
) abzuschneiden, aber dann erhalte ich nur noch "O" mit der Länge 2.

Also, dass die Konsolenausgabe nicht stimmt, ist mir ja noch egal. aber das zusätzliche Zeichen das nervt mich 

cheerioh & thx
SiS


----------



## Thomasio (21. April 2010)

Versuch mal statt strlen()

stmp.size() bzw. wstmp.size()


----------



## deepthroat (21. April 2010)

Hi.





StehtimSchilf hat gesagt.:


> Die Webseite liefert je nach Request "OK", "FORBIDDEN", "UNAUTHORIZED", "ERROR", ... zurück
> 
> Was raus kommt, wenn die Seite "OK" zurückgibt, ist folgendes:
> 
> ...


Weil offenbar ein \r Zeichen mit zurückgegeben wird.


StehtimSchilf hat gesagt.:


> - Warum wird bei "sendRequest():" die ersten 5 Zeichen mit "OKEOL" überschrieben? Ich würde nämlich folgenden Output erwarten: sendRequest(): OKEOL


Weil ein \r Zeichen in dem String ist.

Der Code ist außerdem nicht wirklich günstig. Man sollte sich an die MSDN halten wenn man die Funktionen benutzt und immer den Rückgabewert prüfen. Außerdem könnte es passieren, das du hinter das letzte Arrayelement zugreifst (wenn nämlich 1024 Bytes gelesen werden konnten) und löst damit undefiniertes Verhalten aus.

Und wozu einen std::stringstream verwenden, wenn man eigentlich keine formatierte Ein-/Ausgabe durchführt?

```
const DWORD buflen = 1024;
char buf[buflen];
DWORD len;
std::string data;
bool success;

while ((success = InternetReadFile(request, buf, buflen, &len)) && len != 0) {
  data.append(buf, len);
}
if (success) {
  std::cout << "data length: " << data.length() << std::endl;
} else {
  // Fehler, GetLastError() etc.
}
```



StehtimSchilf hat gesagt.:


> Ich habe versucht mit std::substr() das letzte Zeichen (
> Code:
> 
> stmp.substr(0, stmp.length() -1)
> ...


Das \r Zeichen ist das erste Zeichen im String, du müßtest also das erste Zeichen entfernen (oder den Server dazu bringen die Antworten zu liefern, die du erwartest).

Gruß


----------



## StehtimSchilf (6. Mai 2010)

Ich lach mich schief!

War ja schon spät (Büro) bei meinem letzten Post. Eigentlich hätte mir die Antwort beim Abzwacken des letzten Zeichens selber in den Sinn kommen. Tatsächlich wird von der Appli \r zurückgeliefert. Die bestehenden Clients "säubern" den Response, weswegen dies bisher niemandem aufgefallen ist. Habe dann den Hersteller informiert: Anwort: Ist bekannt, aber bisher gabs keine Probleme und somit auch keinen Patch  

Thx deep.



> Man sollte sich an die MSDN halten wenn man die Funktionen benutzt und immer den Rückgabewert prüfen


 Da hast Du recht und danke für den Hinweis. der Code war nur ein Gebastel (C++ Euphorie hatTE mich gepackt). 

cheerioh & Thx euch allen
SiS


----------

