[c++] Zapis strony internetowej do pliku poprzez wątek

0

Hej ;) Chciałbym sobie zrobić programik, który ściąga źródło strony na dysk. Otóż mam listę stron internetowych i liste nazw plików pod jakie ma je zapisać. Ale gdy napiszę to tak, że po naciśnięciu przycisku na formie ma się wykonać pętla w której zapisywane są te strony, cały program staje i trzeba czekać aż się wykona do końca.
Pomyślałem, żeby zrobić to w wątku. Jednak napotkałem problem... w wątku nie zapisuje tych stron! ;/. zapisze pierwszą która jest mała i ma 14KB ale druga co ma już 90 - nie.
kod z wątkiem wygląda mniej wiecej tak:

#include <vcl.h>
#include <urlmon.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;

DWORD WINAPI FunkcjaWatku(PVOID pvParam)
{
	for(int i = 1; i < Form1->Memo1->Lines->Count; i++)
	{
		DWORD IdWatku;
		AnsiString aFileName = "C:\\" + Form1->Memo2->Lines->Strings[i];
		char *cFileName = aFileName.c_str();
		AnsiString aURL = Form1->Memo1->Lines->Strings[i];
		char *cURL = aURL.c_str();
		HRESULT Rezultat;
		Rezultat = URLDownloadToFile(0, cURL, cFileName, 0, 0);
	}
  return 0;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
		DWORD IdWatku;
		HANDLE hWatek_1 = CreateThread(NULL, 0, FunkcjaWatku, NULL, 0, &IdWatku);
}
//---------------------------------------------------------------------------

Przy tych większych stronach, zmienna Rezultat wynosi jakąś kosmiczną liczbę -2 miliony coś tam ;p

Dlaczego to nie chce tak działać? co robię źle?

0

Zajrzyj do winerror.h lub urlmon.h, żeby dowiedzieć się, co ta kosmiczna wartość oznacza.

Następny błąd, który robisz przy okazji, to odwoływanie się do elementów GUI z wątka, bez synchronizacji. Teraz być może to działa bez problemu, ale w innym przypadku, innej konfiguracji takie odwołania są niebezpieczne. I dlaczego używasz funkcji WinAPI do tworzenia wątka, jeśli w VCL-u masz klasę TThread?

0

a nie wiedziałem nawet, że jest ;p. Google pokazało to :D, to chciałem użyć tego :).
robiłem też tak ze mialem w tym wątku samo URLDownloadToFile(0, zmienna1, zmienna2, 0,0); ale i tak nie działało jak chcialem. a co z tą synchronizacją?

0

Na temat synchronizacji nie napiszę nic, bo... mi się nie chce :P Na tym forum temat był wałkowany milion razy - poszukaj.

0

okej ;D dzieki ;)

0

hmm... zmienilem na TThread ale i tak nie działa tak jakbym chciał :(. nie rozumiem o co chodzi.

klasa:

class TDownloadPage : public TThread
{
	public:
		TDownloadPage(char*, char*, bool);
		__fastcall ~TDownloadPage(void);
		void __fastcall Execute();
	private:
		char *FileName, *URL;
};

i kod ktory wykonuje (nie patrzcie ze nie przekazuje wartosci URL i FileName do URLFileDownloadTo, nie chcialo mi sie zmieniac) W kazdym razie, nie zapisuje źródła onetu do pliku.

TDownloadPage *DownloadThread1;

TDownloadPage::TDownloadPage(char* _FileName,
						 char* _URL,bool CreateSuspended)
:TThread(CreateSuspended)
{
	//Ustawienia TThreat
	FreeOnTerminate=true; //Usuwa z pamieci po zakonczeniu Execute
	//Rezerwacja pamieci i kopiowanie danych
	FileName = _FileName;
	URL = _URL;
}
//---------------------------------------------------------------------------

__fastcall TDownloadPage::~TDownloadPage()
{
	ShowMessage("Wątek zakończył działanie");
}
//---------------------------------------------------------------------------

void __fastcall TDownloadPage::Execute()
{
	URLDownloadToFile(0, "http://www.onet.pl/", "C:\\plik1.html", 0, 0);
}

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
	DownloadThread1 = NULL;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
	AnsiString aFileName = "C:\\" + Form1->Memo2->Lines->Strings[1];
	char *cFileName = aFileName.c_str();
	AnsiString aURL = Form1->Memo1->Lines->Strings[1];
	char *cURL = aURL.c_str();

	DownloadThread1 = new TDownloadPage(cURL, cFileName, true);
	DownloadThread1->Resume();
}
//---------------------------------------------------------------------------
0

No dobrze, ale może byś sprawdził, co zwraca URLDownloadToFile.

0

URLDownloadToFile zwraca w wątku -2147221020.
Natomiast gdy skopiuje tą sąmą linijke do wątku głównego, i wykonam ta operacje w wątku głównym - zwraca 0.
Nie wiem o co chodzi...

0

Hmm, dziwne. Wartość, którą zwraca ta funkcja to MK_E_SYNTAX, średnio mi tu pasuje :/ Weź może na początku **Execute **wywołaj CoInitializeEx, a na końcu CoUninitialize

0

hmm... no dodalem te funkcje i działa ;)

void __fastcall TDownloadPage::Execute()
{
	CoInitializeEx(NULL, COINIT_APARTMENTTHREADED   );//COINIT_APARTMENTTHREADED);
	hr = URLDownloadToFile(0, URL, FileName, 0, 0);
	CoUninitialize();
}

ale strony "http://www.wp.pl/" nie chce sciagnac ;/ (zjamuje 170KB) i pokazuje blad -2146697211. Nie wiem co on oznacza, nie potrafie tego znalezc.

Zauwazylem jeszcze, ze jak dam do jakiegos buttona cos takiego

HRESULT hrr = URLDownloadToFile(0, "http://www.wp.pl/", "C:\\waaap.html", 0, 0);
Button2->Caption = hrr;

to plik w ogole sie nie pokazuje a hrr zwraca 0... ;/

0

-2146697211 to INET_E_RESOURCE_NOT_FOUND, co oznacza, że z serwerem lub połączeniem jest coś nie tak. Nie wiem, co może być tego przyczyną.

Może spróbuj ściągnąć stronę przy pomocy InternetOpenUrl i InternetReadFile.

0

Do obsługi błędów jest funkcja FormatMessage. Skorzystaj z niej to bedziesz wiedzial co to za błędy i dostaniesz nawet ich szczegółowy opis z systemu.

0

dziwne, bo plik zwykly jakis 5MB sciagnal bez problemu ;p, no a wp.pl nie chce ;D. nie wiem, nie chce mi sie bawić kolejnym sposobem ściągania źródła strony ;p

1 użytkowników online, w tym zalogowanych: 0, gości: 1