Witam wszystkich. Dzisiaj opisywał będę ciekawą funkcję na którą ostatnio się natknąłem. Jest nią UrlDownloadToFile. Pozwala ona na pobranie określonego pliku z sieci. Na koniec wykorzystamy zdobytą wiedzę w praktyce, spróbujemy napisać prosty program typu download-manager. Na wszystko jednak będzie pora później. Teraz omówię samą funkcję.
Budowa przedstawionej wyżej funkcji prezentuje się następująco:
UrlDownloadToFile(Caller: IInterface, URL: PChar, FileName: PChar, Reserved: Cardinal, StatusCB: IBindStatusCallBack); URL - nazwa pliku który chcielibyśmy pobrać
FileName - nazwa pliku pod którą plik pobrany zostanie zapisany na lokalnym dysku.
Reszta parametrów nie będzie nam potrzebna.
Funkcja ta nie znajduje się w bibliotece dołączonej do Delphiego (jak System, Math czy Registry) lecz jest ona zawarta w jednej z bibliotek znajdujących się w systemie. Mówiąc nieco dokładniej, jest to biblioteka "UrlMon.dll" znajdująca się w katalogu System w folderze z Winodwsem. Zwykle jest to C:\Windows\System\UrlMon.dll. Aby z niej skorzystać wystarczy dodać do listy uses nazwę tej biblioteki. Delphi zrobi resztę za nas. W naszym wypadku, po przecinku, do listy uses dodajemy słówko UrlMon. To wszystko, możemy już korzystać z nowej biblioteki. W tej bibliotece znajdują się funkcję, które jeszcze przez długi okres waszego życia pozostaną w cieniu. Dobrze, zatem możemy teraz wypróbować tą jedną jedyną znaną nam funkcję. Jak to zrobić? Zaraz pokażę.
UrlMon.UrlDownloadToFile(nil,'http://d.g3.pl/at/archiwa/at24.exe','C:\Dokumenty\Prenumeraty\@t24.exe',0,nil);
Powyższy przykład zawiera instrukcję, która dla programu w obecnym zapisie znaczyła będzie tyle co: "pobierz plik http://d.g3.pl/at/archiwa/at24.exe i zapisz go jako C:\Dokumenty\Prenumeraty\@t24.exe". Słówko nil, w Delphi, oznacza dla kompilatora, czyli programu, który "zmienia" wszystkie instrukcje napisane przez programistę w język zrozumiały tylko dla procesora tzw. kod maszynowy tyle co pustka, czyli prościej mówiąc jest to "nic". Nie wskazuje ono na żaden element. Możemy go używać przy różnych parametrach, ale uwaga, nie we wszystkich! Czasami jeśli kompilator wskazuje błąd w takim miejscu, wystarczy jedynie zamienić nil na inny pusty odnośnik, zwykle jest to np. 0. Ale i tutaj zero nie zawsze pomoże. W każdym razie należy zapamiętać, że nil oznacza dla kompilatora "pustkę".
Aby napisać (bardzo) prosty download-manager, trzeba już mieć nieco wiedzy z tej dziedziny. Tak, więc uważam, że znacie pętle, instrukcje warunkowe, budowę procedur i funkcji i inne szpeja, bo bez tego ani rusz.
Otwieramy Delphiego. Na nowej formie umieszczamy komponent ListBox znajdujący się na palecie Standard. Następnie, pod nim, trzy przyciski, klikając na odpowiednią ikonkę na palecie, następnie na formę w miejscu gdzie ma zostać on umieszczony. Zmniejszamy formularz do takich rozmiarów, aby wszystko mieściło się na nim, a zarazem dbamy o jego estetyczny wygląd.
Następnym krokiem jest nadanie nazw poszczególnym elementom.
Zaznaczamy formularz i w inspektorze obiektów (Obejct Inspector - F11) odszukujemy pole Name, gdzie wpisujemy "fmMainForm", następnie pole Caption, którego wartość zmieniamy na (i tu dowolnie) np. "Pobieranie plików - przykład". Następnie zaznaczamy kontrolkę ListBox (pojedynczym kliknięciem of courz ;), a w inspektorze obiektów pole Name wypełniamy następująco: "ListaPlikow". Jeśli macie zamiar skopiować poniższy kod, ważne jest abyście zważali uwagę na nazwy które teraz dyktuje. Są to nazwy elementów, jakich użyłem. W takim wypadku nawet najmniejsze odstępstwo od pierwotnej nazwy wywoła błąd. Jednak mam nadzieję, że sami spróbujecie uporać się z kodem i w całości go zrozumieć.
Przyszła kolej na przyciski. Zaznaczamy przycisk "Button1" i w polu Caption (w inpektorze obiektów) wpisujemy "Dodaj adres". Przyciskowi "Button2" w polu Caption nadajemy etykietę "Usuń adres", a "Button3" podpisujemy "Pobierz wszystkie". Od tej chwili na naszych przyciskach będą widniały powyższe etykiety (Caption).
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, UrlMon, OleCtnrs, DdeMan;
type
TfmMainForm = class(TForm)
Button1: TButton;
ListaPlikow: TListBox;
Button2: TButton;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
public
procedure Pobierz(url: PChar); // Deklaracja procedury pobierającej pliki
function Sprawdz(url: PChar): Boolean; // Deklaracja funkcji sprawdzającej poprawność adresu
end;
var
fmMainForm: TfmMainForm;
implementation
{$R *.dfm}
// Funkcja sprawdzająca poprawność adresu
function TfmMainForm.Sprawdz(url: PChar): Boolean;
var
adres1, adres2: string; // zadeklarowanie łańcucha znaków
begin
// Dwie zmienne, jedna z nich - jeśli poprawny jest adres podany przez użytkownika
// przyjmuje wartość - albo http://, albo ftp://
adres1 := Copy(url,1,7); // Powinno zwrócić http://
adres2 := Copy(url,1,6); // Powinno zwrócić ftp://
// Jeśli jedna ze zmiennych zawiera poprawny początek ('http://' lub 'ftp://') to...
If (adres1 = 'http://') or (adres2 = 'ftp://') Then
// zwróć True(Prawda) || Jeśli nie, zwróć False (Fałsz)
Result := True else Result := False;
end;
// Funkcja pobierająca plik
procedure TfmMainForm.Pobierz(url: PChar);
var
plik: PChar; // Deklaracja zmiennej tekstowej plik
begin
// Wyciągnięcie z adresu url nazwy samego pliku, spełnia to funkcja
// "ExtractFileName()", następnie dodanie litery dysku. W efekcie otrzymujemy:
// C:\ + plik.exe = C:\plik.exe.
plik := PChar('C:\'+ExtractFileName(String(url)));
// Funkcja o której była mowa, to ona odpowiada za pobranie naszego pliku
UrlDownloadToFile(nil,url,plik,0,nil)
end;
// Procedura wywoływana po naciśnięciu przycisku Button1 ("Dodaj adres")
procedure TfmMainForm.Button1Click(Sender: TObject);
var
PlikDoPobrania: String;
begin
// Wyświetl okienko do wpisywania adresu, to co poda użytkownika zapisz w zmiennej "PlikDoPobrania".
PlikDoPobrania := InputBox('Wprowadź adres...','Poniżej wprowadź adres pliku, który ma zostać pobrany','');
// Wywołaj funkcję Sprawdz(), sprawdzi ona poprawność adresu podanego przez użytkownika
If Sprawdz(PChar(PlikDoPobrania)) Then
Begin // Jeśli adres jest poprawny to...
// Dodaj adres, który wpisał użytkownik do listy
ListaPlikow.Items.Add(PlikDoPobrania);
// Wywołaj procedure Pobierz, która pobierze ów plik.
// Zastosowane tutaj tzw. rzutowanie typów zostanie omówione w dalszej części artykułu
Pobierz(PChar(PlikDoPobrania));
end else
ShowMessage('Niepoprawny adres!');
end;
// Procedura wywoływana po naciśnięciu przycisku Button2 ("Usuń adres")
procedure TfmMainForm.Button2Click(Sender: TObject);
begin
// Usuń pozycję o indeksie, który posiada zaznaczona pozycja, czyli
// usuń zaznaczenie.
ListaPlikow.Items.Delete(ListaPlikow.ItemIndex);
end;
// Procedura wywoływana po naciśnięciu przycisku Button3 ("Rozpocznij pobieranie")
procedure TfmMainForm.Button3Click(Sender: TObject);
var
i: integer;
begin
// Pętla For...do
{ liczy od 0 do liczby jaka charakteryzuje ilość pozycji na liście ListaPlikow
Prościej mówiąc ta pentelka patrzy na pierwszą pozycję(adres) listy, zaczyna go
pobierać, następnie drugi adres i znów rozpoczyna jego pobieranie,
dochodzi do trzeciego adresu i pobiera go - i tak do końca listy.}
For i:=0 To ListaPlikow.Items.Count-1 Do
Begin
// Wywołujemy procedurę odpowiadającą za pobieranie plików.
Pobierz(PChar(ListaPlikow.Items[i]));
end;
end;
end.
Myślę, że kod powinien być dla Was zrozumiały. Każdą instrukcję obarczyłem komentarzem. Jedną rzecz pozostawiłem do szerszego opisu. Tak, chodzi o rzutowanie typów. Jest to bardzo ważna umiejętność. Wytłumaczyć to można w sposób iż jest to jakby oszukanie kompilatora. Nie we wszystkich przypadkach możemy uciec się do zastosowania konwersji typów, np. StrPas(), czy StrPCopy(). Spójrzcie na poniższy przykład.
Przypuśćmy, że za pomocą komunikatu (MessageBox) chcemy wyświetlić zmienną typu String. Kompilator nie zgodzi się na taki układ, generując błąd o niezgodności typów. Błąd niezgodności typów pojawia się nam wówczas gdy próbujemy np. jako parametr jakiejś funkcji próbujemy wstawić zmienną o typie, który nie pasuje do typu tegoż parametru. Najlepiej zrozumiecie to na przykładzie.
var
informacja: String;
begin
informacja := 'Cześć!';
Application.MessageBox(informacja,'Komunikat',MB_OK);
Pierwszy parametr funkcji MessageBox to tekst jaki ma wyświetlić się w komunikacie. Tekst ten musi być typu PChar, my mamy zmienną "informacja" typu String. PChar i String, chodź oba są typami tekstowymi - różnią się od siebie ilością zajmowanej pamięci, dlatego nie są ze sobą kompatybilne. Możemy wmówić kompilatorowi, że ma do czynienia z typem PChar.
Z tego co napisałem wynika, że ostatnia linia powinna wyglądać następująco:
Application.MessageBox(PChar(informacja),'Komunikat',MB_OK);
Wmówiliśmy kompilatorowi iż zmienna "informacja" jest typu PChar, chodź w rzeczywistości jest ona zmienną typu String. Teraz program się skompiluje i uruchomi. Powodzenia!
Włączone do kontaktu, lepiej działa (prawo Sattingera)
Biorąc powyższy cytat pod uwagę, uruchamiamy napisany wcześniej program (F9 lub Project\Run). Klikamy przycisk "Dodaj adres" i wpisujemy adres do pliku, który chcielibyśmy pobrać z sieci, np. 'http://d.g3.pl/at/archiwa/at24.exe', a następnie klikamy na przycisk OK. Jeśli wszystko poszło zgodnie z planem - system będzie próbował teraz nawiązać połączenie z siecią i wykonać zadanie (w naszym wypadku pobrać magazyn @t).
Funkcja bardzo ciekawa - czyż nie? ;) Myślę, że muszę poświęcić jej nieco więcej czasu i rozpracować bibliotekę "UrlMon.dll". Zapomniałem was poinformować o istotnej sprawie. Mianowicie, jeżeli macie zainstalowany u siebie GetRight, czy inne badziewie może on przejąć od systemu pobieranie pliku, więc jeśli nie zobaczysz systemowego okienka - zobaczysz z pewnością okienko GetRighta czy innego programu wspomagającego. Chciałbym dodać iż tutaj znajduje kod źródłowy programu który pisaliśmy w tym artykule.
Dzięki wszystkim za uwagę!
| Brak komentarzy |
| Nie ma jeszcze żadnych komentarzy. Jeśli chcesz, wyraź pierwszy swoje zdanie na temat tego artykułu. |
Łukasz "Lukas" Wyporek
lukas.home.page@gmail.com