SIEĆ - INTERNET

MENU

  1. Odczyt własnego Adresu IP.

  2. Pobieranie adresu z aktywnego okna przeglądarki.

  3. Prosty komunikator sieciowy.

  4. Uruchamianie domyślnego programu pocztowego z parametrami.

  5. Wysyłanie e-mail'a z plikiem załącznika za pomocą mapi.

  6. Wyliczanie zasobów sieciowych.

  7. Wyświetlanie stron WEB za pomocą komponentu CppWebBROWSER_V1.

  8. Ściąganie plików z sieci za pomocą klienta HTTP.

  9. Ściąganie i Wysyłanie plików poprzez protokół FTP.

  10. Wczytywanie do kontrolki TCppWebBrowser dokumentów z  zasobów. UzUPEŁNIONO.

  11. Jak pobrać lokalną internetową nazwę maszyny i lokalny adres IP?

  12. Wysyłanie e-mail'a z załącznikiem z wykorzystaniem komponentów Indy.

  13. Opis protokołu HTTP - nadesłał blatio

  14. Sprawdzanie stanu połączenia z internetem.

  15. Sprawdzanie zewnętrznego adresu IP.

  16. Sprawdzanie czy istnieje wybrany plik w sieci.

  17. Wyciąganie adresów URL ze stron internetowych.

  18. Wywoływanie okna podglądu dla kontrolki TCppWebBrowser.

  19. Wysyłanie polecenia PING za pomocą komponentu TIdIcmpClient (INDY).

  20. Wyliczanie dostępnych i aktywnych internetowych połączeń internetowych.

  21. Ściąganie plików z Internetu przez protokół HTTP (bez INDY).

  22. Wyświetlanie plików graficznych bezpośrednio z Internetu.

  23. Wstawianie własnego PopupMenu do kontrolki TCppWebBrowser.

  24. Kopiowanie tekstu z kontrolki CppWebBRowser do schowka.

 

 

Wyświetlanie stron WEB za pomocą komponentu CppWebBrowser_V1.

    Komponent TCppWebBrowser_V1 jest kontrolką ActiveX bazującą na przeglądarce Internet Explorer, więc nie jest to samodzielny komponent. Kontrolkę należy zainstalować wybierając w menu Component -> Import Active Control, a następnie w oknie Import ActiveX wybieramy 'Microsoft Internet Controls' i naciskamy przycisk Instaluj, a dale instaluje się tak jak komponenty. Gdy już mamy zainstalowaną kontrolkę umieszczamy CppWebBrowser_V11 na formularzu i zdarzeniu OnClick dla przycisku Button1 wczytujemy do niego jakąś stronę:

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 CppWebBrowser_V11->Navigate(WideString("http://cyfbar.republika.pl/"), 0, NULL, NULL, NULL);
}
//------------------------------------------

Oczywiście nie ma takiej potrzeby żeby jawnie podawać adres strony WEB, można go wpisać np. do obiektu Edit1, i z niego pobrać:

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 CppWebBrowser_V11->Navigate(WideString(Edit1->Text).c_bstr(), 0, NULL, NULL, NULL);
}
//------------------------------------------

...powrót do menu. 

Ściąganie plików z sieci za pomocą klienta HTTP.

    Do zrealizowania tej porady niezbędny jest komponent TIdHTTP z pakietu Indy. Pakiet można pobrać stąd: http://www.indyproject.org/. Pokażę w jaki sposób za pomocą obiektu HTTP1 ściągać z sieci wszelkiego rodzaju pliki, tak jak to się ściąga za pomocą przeglądarki lub za pomocą specjalnie do tego celu napisanych programów. Stosowanie komponentów z pakietu Indy ma to do siebie, że pisanie programów sieciowych staje się banalnie proste. Umieszczamy na formularzu komponent TIdHTTP (znajduje się na zakładce IndyClient) i nadajemy mu nazwę HTTP1, umieszczamy ponadto obiekt Edit1, Button1 i ListBox1, następnie w zdarzeniu OnClick dla przycisku Button1 umieszczamy kod odpowiedzialny za pobranie pliku s sieci na podstawie adresu wpisanego do obiektu Edit1:

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 TFileStream *F = new TFileStream("c:\\katalog\\nazwa_pliku.roz", fmCreate);
 HTTP1->Get(Edit1->Text, F);
 delete F;
}
//------------------------------------------

Tyle kodu wystarczy, żeby pobrać z sieci dowolny plik. Do pobrania pliku i zapisania go na dysku użyłem klasy TFileStream, która tworzy plik jeszcze przed jego pobraniem, co może stanowić pewne utrudnienie, aczkolwiek wystarczy stworzyć funkcję i wszystko powinno działać jak należy:

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------
void __fastcall TForm1::PullDownFile(AnsiString SourceFile, AnsiString DestFile)
{
 TFileStream *F = new TFileStream(DestFile, fmCreate);
 HTTP1->Get(SourceFile, F);
 delete F;
}
//------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 PullDownFile(Edit1->Text, "c:\\katalog\\nazwa_pliku.roz");
}
//------------------------------------------

Nie jest to jedyny sposób na zapisanie pliku na dysku, można posłużyć się klasą TMemoryStream, która najpierw zapisuje dane w pamięci RAM, a dopiero potem na dysku:

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------
void __fastcall TForm1::PullDownFile(AnsiString SourceFile, AnsiString DestFile)
{
 TMemoryStream *M = new TMemoryStream;
 M->Position = 0;
 HTTP1->Get(Edit1->Text, M);
 M->Position = 0;
 M->SaveToFile("c:\\katalog\\nazwa_pliku.roz");
 delete M;
}
//------------------------------------------

Na tym mógłbym w zasadzie już zakończyć, ale dołożę jeszcze kod wyświetlający komunikaty w obiekcie ListBox1, w tym celu tworzymy zdarzenie OnStatus dla obiektu HTTP1 i umieszczamy w nim króciutki kod:

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------
void __fastcall TForm1::HTTP1Status(TObject *ASender,
        const TIdStatus AStatus, const AnsiString AStatusText)
{
 Application->ProcessMessages();
 ListBox1->Items->Add(IntToStr(AStatus)+ ". " + AStatusText);
}
//------------------------------------------

W żadnym z powyższych kodów nie umieściłem funkcji Connect() uruchamiającej połączenie, ponieważ nie jest potrzebna, połączenie nastąpi zawsze przed pobraniem pliku, ale dla porządku podam przykład połączenia i rozłączenia. W przypadku funkcji Connect() można między nawiasami umieścić wartość liczbową, reprezentującą czas po jakim nastąpi zerwanie połączenia, ale nie jest to konieczne, jeśli nie podamy tam żadnej wartości połączenie nie zostanie automatycznie zerwane:

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
 HTTP1->Connect(100000); // 1000 = 1 sekunda
}
//------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
 HTTP1->Disconnect(); // nie należy nic wpisywać między nawiasy.
}
//------------------------------------------

Istnieje możliwość pobierania nie tyle samych plików ile ich zawartości, mam tu na myśli pliki tekstowe i pliki HTML, których zawartość można podglądać. Można wyświetlać zawartość takich plików np. w Memo1, oczywiście jeśli wyświetlimy w Memo zawartość pliku HTML to zostanie wyświetlona zawartość źródła, a nie strona WEB:

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 Memo1->Text = HTTP1->Get("http://cyfbar.republika.pl/specjal/specjal.txt");
}
//------------------------------------------

...powrót do menu. 

Ściąganie i wysyłanie plików poprzez protokół FTP.

  Do zrealizowania tej porady niezbędny jest komponent TIdFTP z pakietu Indy. Pakiet można pobrać stąd: http://www.indyproject.org/. Zrealizowanie tego projektu za pomocą wspomnianego komponentu jest bardzo proste. Na początku skupię się na bardzo prostej metodzie pobierania i wysyłania plików przez protokół FTP. Wystarczy dla obiektu IdFTP1 w 'Object Inspector' na zakładce 'Properties' ustawić kilka właściwości, np.: Host = ftp.republika.pl, zakładając oczywiście, że posiada się konto w www.republika.pl, w przeciwnym razie należy podać nazwę hosta odpowiadającą kontu które posiadamy. w właściwości Password podajemy nasze hasło, natomiast we właściwości Username - nazwę użytkownika, i tutaj istotna sprawa nazwa użytkownika z reguły jest również nazwą katalogu zdalnego na serwerze, co ma znaczenie przy wysyłaniu i pobieraniu plików, ponieważ jeśli nazwa użytkownika jest nazwą katalogu zdalnego, to przy określaniu ścieżki dostępu do jakiegoś pliku na serwerze nie podajemy już nazwy katalogu zdalnego, przez katalog zdalny rozumiem katalog w którym znajduje się moja witryna, pliki. Jednak jeśli posiadamy w katalogu zdalnym jakieś podkatalogi, to oczywiście przy podawaniu ścieżki dostępu do plików znajdujących się w podkatalogach należy podać nazwę podkatalogu. No i komponent jest już w zasadzie gotowy do pracy, teraz w zdarzeniach OnClick dla przycisku Button1 wywołamy połączenie, dla przycisku Button2 uruchomimy pobieranie pliku, a dla przycisku Button3 wysyłanie pliku:

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 IdFTP1->Connect();
}
//------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
 IdFTP1->Get("index.html", "c:\\MyWEB\\index.html", true, false); // pobieranie pliku bezpośredni z katalogu zdalnego.
 IdFTP1->Get("images/obrazek.gif", "c:\\MyWEB\\images\\obrazek.gif", true, false); // pobieranie pliku z podkatalogu.
}
//------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
 IdFTP1->Put("c:\\MyWEB\\index.html", "index.html", true); // wysyłanie pliku bezpośrednio do katalogu zdalnego.
 IdFTP1->Put("C:\\MyWEB\\images||obrazek.gif", "images\\obrazek.gif", true); // wysyłanie pliku do podkatalogu.
}
//------------------------------------------

Teraz kilka wyjaśnień, funkcja Connect pobiera dwa argumenty, pierwszy to wartość typu bool, ja tu oczywiście nie podałem żadnego argumentu w ten sposób jeśli podamy hasło i nazwę użytkownika, to oprócz połączenia z serwerem zostaniemy automatycznie zalogowani na nasze konto, natomiast jeśli nie podamy hasła lub nazwy użytkownika to połączenie z serwerem zostanie nawiązane, ale logowanie do konta nie nastąpi. Można podać jako argument wartość false, wtedy nastąpi tylko połączenie z serwerem, lub wartość true - połączenie z serwerem plus automatyczne logowanie. Drugi argument to wartość typu int reprezentująca czas po którym zastąpi automatyczne zerwanie połączenia z serwerem, przy czym jedna sekunda = 1000.
Funkcja Get pobiera cztery argumenty, pierwszy to adres i nazwa pliku pliku który chcemy ściągnąć, drugi to lokalizacja i nazwa pliku pod jaką zapiszemy pobrany plik i co istotne nazwa pod jaką zapiszemy plik na dysku nie musi być wcale taka sama jak nazwa ściąganego pliku, trzeci argument to wartość typu bool określająca czy ma być sprawdzana w lokalizacji docelowej obecność ściąganego pliku, tzn. jeśli ściągany plik już istnieje w miejscu w którym chcemy go zapisać, to zostanie wyświetlony komunikat, że plik już istnieje i pobieranie zostanie przerwane. Jeśli wprowadzimy tam wartość true, to istniejący plik zostanie automatycznie zastąpiony ściąganym, bez żadnych ostrzeżeń, przy czym czwarty parametr musi mieć w tym przypadku wartość false. Jeśli chodzi o czwarty parametr to określa on czy częściowe pobieranie może być uzupełniane, chodzi o to jeśli w trakcie pobierania nastąpi przerwanie, to zostanie pobrana tylko część pliku, jeżeli ustawimy tu wartość true, a w trzecim argumencie będzie wartość false, to przy wznowieniu pobierania tego samego pliku, zostanie on uzupełniony o brakującą część, czyli nie będzie ściągany w całości.
Funkcja Put pobiera trzy argumenty, pierwszy to adres i nazwa wysyłanego pliku, drugi to lokalizacja i nazwa pod jaką zostanie zapisany plik, trzeci parametr to zapytanie, czy jeśli w lokalizacji docelowej istnieje już taki plik to ma być zastąpiony czy nie, jeśli wprowadzimy tam wartość false, to plik będzie automatycznie zastępowany, bez żadnych ostrzeżeń.
Teraz przedstawię jeszcze dwie przydatne funkcje, pierwsza Delete kasuje plik z serwera, druga Rename zmienia nazwę pliku na serwerze:

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 IdFTP1->Delete("index.html");
}
//------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
 IdFTP1->Rename("images/obrazek.gif", "images/delfin.gif");
}
//------------------------------------------

Teraz przejdziemy do bardziej zaawansowanych opcji, na początek zrobimy połączenia z serwerem i logowanie oddzielnie. Jeśli nie chcemy się automatycznie logować na nasze konto, to nie należy wprowadzać we właściwościach obiektu IdFTP1 nazwy użytkownika ani hasła, podamy je bezpośrednio przed załogowaniem. Właściwość AutoLogin należy ustawić na false.

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 IdFTP1->Connect();
}
//------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
 IdFTP1->Password = "hasło";
 IdFTP1->Username = "użytkownik";
 try
 {
  IdFTP1->Login();
 }
 catch(...)
 {
  ShowMessage("Nie udało się zalogować. Sprawdź czy wpisano poprawnie hasło i nazwę użytkownika.");
 }
}
//------------------------------------------

Teraz dołączymy jeszcze wyświetlanie komunikatów, w tym celu tworzymy zdarzenie OnStatus dla obiektu IdFTP1 i umieszczamy na formularzu obiekt ListBox1:

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------
void __fastcall TForm1::IdFTP1Status(TObject *ASender,
        const TIdStatus AStatus, const AnsiString AStatusText)
{
 ListBox1->Items->Add(IntToStr(AStatus)+ ". " + AStatusText);
 Application->ProcessMessages();
}
//------------------------------------------

Tyle wystarczy odnośnie komunikatów, można oczywiście dołączać jakieś własne. Przydałoby się jeszcze ściągnięcie listy wszystkich plików znajdujących się w podanej lokalizacji, więc dodajemy jeszcze jeden obiekt ListBox2, a w zdarzeniu OnClick dla przycisku Button dodajemy taki kod:

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------
void __fastcall TForm1::Button5Click(TObject *Sender)
{
 IdFTP1->List(ListBox2->Items, "*.*", false);
}
//------------------------------------------

Funkcja List pobiera z serwera listę plików, pierwszy argument to obiekt w którym zostanie wyświetlona lista plików i musi to być obiekt dziedziczący klasę TStrings. Drugi argument to oczywiście filtr, który określa jakie pliki mają być indeksowane, można tam podać nazwę pliku z rozszerzeniem, nazwę z gwiazdką zamiast rozszerzenia, gwiazdkę zamiast nazwy z rozszerzeniem lub gwiazdkę zamiast nazwy z gwiazdką zamiast rozszerzenia, w tym ostatnim przypadku zaindeksowane zostaną wszystkie pliki. Trzeci argument określa czy mają być indeksowane dokładne informacje o plikach, czyli data i czas utworzenia i rozmiar, jeśli chcemy kompletnych informacji to należy wpisać wartość true, w przeciwnym wypadku wstawiamy false. Pokażę jeszcze jeden sposób pobierania listy plików:

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------
void __fastcall TForm1::Button5Click(TObject *Sender)
{
 IdFTP1->List(NULL, "*.*", true);
 ListBox2->Items = IdFTP1->ListResult;
}
//------------------------------------------

Na zakończenie przedstawiam kod, który pozwala na wyświetlanie paska postępu przy ściąganiu i wysyłaniu plików, w tym celu należy umieścić na formularzu obiekt ProgressBar1, i jeszcze jedna sprawa, jeżeli chcemy żeby pasek działał "widowiskowo" to należy dokonać zmian we właściwościach obiektu IdFTP1 RecvBufferSize i SendBufferSize, jako wartości zawierają one rozmiary pakietów przesyłanych plików, znaczy to że plik nie jest pobierany / wysyłany w całości, ale w pakietach o rozmiarach określonych w tych właściwościach. Skok właściwości Position obiektu ProgressBar1 będzie się odbywał o te właśnie wartości, domyślnie jest tam wartość 32768 bajtów, i jest to wartość duża, przy plikach mniejszych od tej wartości ProgressBar1 nawet nie drgnie, dlatego należy ją zmniejszyć np. na 100 bajtów:

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 IdFTP1->Connect();
}
//------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
 ProgressBar1->Max = IdFTP1->Size("images/obrazek.gif");
 Application->ProcessMessages();
 IdFTP1->Get("images/obrazek.gif", "c:\\MyWEB\\images\\obrazek.gif", true, false); // pobieranie pliku
}
//------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
 TSearchRec SFile;
 FindFirst("c:\\MyWEB\\images\\obrazek.gif", faAnyFile, SFile);
 ProgressBar1->Max = SFile.Size;
 IdFTP1->Put("c:\\MyWEB\\images\\obrazek.gif", "images/obrazek.gif", false); //wysyłanie pliku.
}
//------------------------------------------
void __fastcall TForm1::IdFTP1Work(TObject *Sender, TWorkMode AWorkMode,
        const int AWorkCount) // zdarzenie OnWork obiektu IdFTP1.
{
 ProgressBar1->Position = AWorkCount;
 Application->ProcessMessages();
}
//------------------------------------------
void __fastcall TForm1::IdFTP1WorkEnd(TObject *Sender, TWorkMode AWorkMode)  // zdarzenie OnWorkEnd obiektu IdFTP1.
{
 ProgressBar1->Position = ProgressBar1->Max;
}
//------------------------------------------
void __fastcall TForm1::Button4Click(TObject *Sender)
{
 IdFTP1->Disconect();   // rozłączenie.
}

//------------------------------------------

...powrót do menu. 

Wczytywanie do kontrolki TCppWebBrowser dokumentów z zasobów.
uzupełniono 15 marca 2008

Czasami może zdarzyć się potrzeba dokument HTML nie z dysku czy też prosto z sieci, ale np. z pliku umieszczonego w zasobach programu. Może się też zdarzyć że będziemy potrzebowali przepisać zawartość np. komponentu Memo1 do kontrolki CppWebBrowser, otóż istnieje na to bardzo prosty sposób:

Kod zawierał błąd. Funkcja Document nie może być NULL, dlatego przed przepisaniem pamięci do kontrolki, trzeba ją najpierw wypełnić pustą stroną.

//Plik nagłówkowy np. Unit1.cpp

//------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 CppWebBrowser->Navigate(WideString("about:blank")); // wypełnienie kontrolki pustą stroną.
 TMemoryStream *stm = new TMemoryStream();
 Memo1->Lines->SaveToStream(stm);

 IPersistStreamInit *psi;
 stm->Seek(0, 0);

 TStreamAdapter *sa = new TStreamAdapter(stm, soReference);

 if(SUCCEEDED(CppWebBrowser->Document->QueryInterface(IID_IPersistStreamInit, (void **)&psi)))
  psi->Load(*sa);

 delete stm;
}
//------------------------------------------

 

W przykładzie przestawiony został sposób przepisania zawartości Memo1 do CppWebBrowser, ale jeżeli chcemy umieścić np. dokument HTML w zasobach programu to należy go potraktować tak samo jak plik tekstowy i skorzystać z porady umieszczanie plików tekstowych w zasobach programu, przy czym kod przepisywania danych ze strumienia należy zmodyfikować o kod przedstawiony powyżej, co nie jest skomplikowane ponieważ w obydwu przypadkach pośrednikiem jest klasa TMemoryStream.
przedstawiony przykład pokazuje jak przepisać zawartość Memo do CppWebBrowser. Można jednak umieszczać w zasobach programu pliku HTML i wczytywać je bezpośrednio z zasobu. Takie pliki mogą zawierać tylko formatowanie HTML, nie mogą mieć wstawionej żadnej grafiki, gdyż umieszczenie takiego pliku w zasobie wraz z grafiką nie spowoduje automatyczne wczytanie grafiki z zasobów do wyświetlanej strony, jest to o tyle oczywiste, że kod HTML nie zawiera funkcji umożliwiających wczytywanie pliku graficznego do dokumentu HTML z zasobu, więc to oczywiste. Plik nie może również zawierać formatowania XML, wynika to z różnicy w oznaczaniu zasobów. Pliki HTML to zasób o numerze 23, natomiast pliki XML to zasób o numerze 24, wiec albo wczytujemy plik HTML, albo XML. Formatu XML nie będę tutaj opisywał, gdyż kontrolka TCppWebBrowser nie potrafi go obsłużyć, więc jest to bezcelowe.
Otwieramy Notatnik i umieszczamy w nim następujące wpisy.

 

ID_DOC 23 "dokument.htm"

 

gdzie ID_DOC to dowolna nazwa jednowyrazowa będąca identyfikatorem zasobu, 23 to typ HTML (RT_HTML), dokument.htm to plik włączany do zasobów.
Plik zapisujemy w katalogu z programem pod dowolną nazwą (jednowyrazową) ale koniecznie z rozszeżeniem RC, np. zasob.rc, plik włączny do zasobu umieszczamy w tym samym katalogu. Następnie poprzez menu: Project | Add to project... włączmy do projektu plik zasob.rc. Wybieramy z menu polecenie Project | Build. Za pierwszym razem, czyli po włączeniu pliku zasob.rc do projektu trzeba wybrać Build, żeby kompilator przerobił plik *.RC na plik *.RES i włączył go automatycznie do zasobów, gdyż plik *.RC nie jest jeszcze prawidłowym plikiem zasobu, jest nim natomiast plik *.RES. Można to łatwo sprawdzić, po wybraniu polecenia Build w katalogu z projektem powinien pojawić się plik zasob.res. Dla nie wiedzących plik zasobów zostanie włączony w zasoby programu, czyli będzie składnikiem pliku *.EXE, więc nie trzeba pliku *.RES rozprowadzać razem z programem.

Następnie tworzymy kod wczytujący plik z zasobu do kontrolki TCppWebBrowser.  Warunkiem koniecznym do prawidłowego działania kodu jest dodanie do pliku źródłowego w sekcji include wpisu: #include <memory>

 

//Plik nagłówkowy np. Unit1.cpp
#include <memory>
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 HRSRC rsrc = FindResource(HInstance, "ID_DOC", RT_HTML);
 if(!rsrc)
 {
  Application->MessageBox("Nie można przeprowadzić operacji. Taki zasób nie istnieje!", "BŁĄD!", MB_OK | MB_ICONSTOP);
  return;
 }

 DWORD Size = SizeofResource(HInstance, rsrc);
 HGLOBAL MemoryHandle = LoadResource(HInstance, rsrc);

 if(MemoryHandle == NULL) return;

 BYTE *MemPtr = (BYTE *)LockResource(MemoryHandle);

 TMemoryStream *stream = new TMemoryStream;
 stream->Write(MemPtr, Size);
 stream->Position = 0;

 CppWebBrowser1->Navigate(WideString("about:blank")); // wypełnienie kontrolki pustą stroną.

 IPersistStreamInit *psi;
 stream->Seek(0, 0);

 TStreamAdapter *sa = new TStreamAdapter(stream, soReference);

 if(SUCCEEDED(CppWebBrowser1->Document->QueryInterface(IID_IPersistStreamInit, (void **)&psi)))
  psi->Load(*sa);

 delete stream;
}
//------------------------------------------

 

WAŻNE!

Funkcję: CppWebBrowser1->Navigate(WideString("about:blank")); wywołujemy tylko raz, dlatego najlepiej jest to zrobić w zdarzeniu OnCreate formularza lub w kontruktorze klasy, a nie przy każdym ładowaniu zawartości Memo do CppWebBrowser. Chodzi o to, że kontrolka CppWebBrowser musi być najpierw wypełniona jakąś wartością, zanim będzie można użyć funkcji. Jeżeli przy drugiej próbie załadowania z pamięci do CppWebBrowser wywołamy funkcję CppWebBrowser1->Navigate(WideString("about:blank")); to za drugim razem nic nie zostanie do tej kontrolki załadowane.

 

Niżej przykład ładowania do CppWebBrowser naprzemiennie zawartości Memo1 i Memo2:

 

//Plik nagłówkowy np. Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "SHDocVw_OCX"
#pragma resource "*.dfm"
TForm1 *Form1;

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
  CppWebBrowser1->Navigate(WideString("about:blank"));
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  TMemoryStream *stm = new TMemoryStream();
  Memo1->Lines->SaveToStream(stm);

  IPersistStreamInit *psi;
  stm->Seek(0, 0);

  TStreamAdapter *sa = new TStreamAdapter(stm, soReference);

  if(SUCCEEDED(CppWebBrowser1->Document->QueryInterface(IID_IPersistStreamInit, (void **)&psi)))
    psi->Load(*sa);

  delete stm;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
  TMemoryStream *stm = new TMemoryStream();
  Memo2->Lines->SaveToStream(stm);

  IPersistStreamInit *psi;
  stm->Seek(0, 0);

  TStreamAdapter *sa = new TStreamAdapter(stm, soReference);

  if(SUCCEEDED(CppWebBrowser1->Document->QueryInterface(IID_IPersistStreamInit, (void **)&psi)))
    psi->Load(*sa);

  delete stm;
}
//---------------------------------------------------------------------------

 

...powrót do menu. 

Jako pobrać lokalną internetową nazwę maszyny i lokalny adres IP?

W celu pobrania lokalnej nazwy hosta i lokalnego adresu IP należy skorzystać z Winsock API:

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 hostent *p;
 char s[128];
 char *p2;
 
 //Pobierz nazwę komputera
 gethostname(s, 128);
 p = gethostbyname(s);
 Memo1->Lines->Add(p->h_name);

 //Pobierz adres IP
 p2 = inet_ntoa(*((in_addr *)p->h_addr));
 Memo1->Lines->Add(p2);
}
//------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
 WORD wVersionRequested;
 WSADATA wsaData;

 wVersionRequested = MAKEWORD(1, 1);
 WSAStartup(wVersionRequested, &wsaData);
}
//------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
 WSACleanup();
}
//------------------------------------------

...powrót do menu. 

Wysyłanie e-mail'a z załącznikiem z wykorzystaniem komponentów Indy.

Do zrealizowania tej porady niezbędne będą dwa komponenty Indy: TIdSMTP z palety Indy Clients i TIdMessage z palety Indy Misc. Umieszczamy obydwa komponenty na formularzu, dodatkowo umieszczamy 8 komponentów typu TEdit, dwa przyciski, jeden obiekt typu TMemo i jeden obiekt typu TOpenDialog.  Komponenty Edit posłużą nam do ustawienia klienta SMTP i wiadomości do wyłania, będą to odpowiednio:

Obiekt Memo1 pobiera treść wysyłanej wiadomości, a obiekt Button1 wywołuje okno dialogowe OpenDialog1 w którym można wskazać plik do załączenia z wiadomością. Przycisk Button2 wysyła wiadomość. Dzisiaj niemal wszystkie serwery kont pocztowych wymagają uwierzytelnienia, dlatego w komponencie IdSMTP1 należy ustawić właściwość AuthenticationType na atLogin, dla pewności umieszczę też taką instrukcję w kodzie. Dalsza część zadania jest już bardzo prosta, wystarczy tylko odpowiednio ustawić właściwości obydwu komponentów Indy. Właściwości można odpowiednio ustawić na zakładce Properties Inspektora Obiektów, ja jednak ustawię wszystkie niezbędne właściwości za pomocą kodu z wykorzystaniem wymienionych obiektów:

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)
{
 IdMessage1->From->Name = Edit1->Text; //pobiera nazwę nadawcy wiadomości
 IdMessage1->From->Address = Edit2->Text; //pobiera adres e-mail nadawcy wiadomości
 IdMessage1->Recipients->EMailAddresses = Edit3->Text; // pobiera adres e-mail odbiorcy wiadomości
 IdMessage1->Subject = Edit5->Text; // pobiera tytuł (temat) wiadomości
 IdMessage1->Body->Append(Memo1->Text); //pobiera treść wiadomości

 IdSMTP1->Host = Edit4->Text; // pobiera adres serwera SMTP
 IdSMTP1->Password = Edit6->Text; // pobiera hasło nadawcy wiadomości
 IdSMTP1->UserId = Edit7->Text; // pobiera nazwę nadawcy wiadomości - ID użytkownika
 IdSMTP1->AuthenticationType = atLogin; // wymagana autoryzacja
 IdSMTP1->Port = 25;

 //TIdAttachment *IdAtt = new TIdAttachment(IdMessage1->MessageParts, "c:\\cdcops.log"); // opcjonalnie

 IdSMTP1->Connect();

 try
 {
  IdSMTP1->Send(IdMessage1);
 }
 __finally
 {
  IdSMTP1->Disconnect();
 }
}
//------------------------------------------
void __fastcall TForm1::Button1(TObject *Sender)
{
 if(OpenDialog1->Execute())
 {
  TIdAttachment *IdAtt = new TIdAttachment(IdMessage1->MessageParts, OpenDialog1->FileName); // wstawianie załącznika do wiadomości
  Edit8->Text = ExtractFileName(OpenDialog1->FileName);
 }
}
//------------------------------------------

W celu zabezpieczenia się przed "zamrożeniem" połączenia, co się moze zdarzyć przy dużych wiadomościach, można umieścić na formularzu komponent typu TIdAntiFreeze.

...powrót do menu. 

Sprawdzanie stanu połączenia z Internetem.

W celu sprawdzenia połączenia z Internetem można posłużyć się funkcją InternetGetConnectedState, jednak ta funkcja będzie działać tylko wtedy, gdy włączymy do projektu poprzez menu Project | Add to project... bibliotekę wininet.lib, można ją znaleźć w katalogu: [...]:\Program Files\Borland\CBuilder6\Lib.

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 DWORD State;

 if(InternetGetConnectedState(&State, 0))
 {
  if(State & INTERNET_CONNECTION_MODEM)      Label1->Caption = "POŁĄCZENIE PRZEZ MODEM";
  if(State & INTERNET_CONNECTION_LAN)        Label1->Caption = "POŁĄCZENIE PRZEZ LAN";
  if(State & INTERNET_CONNECTION_PROXY)      Label1->Caption = "POŁĄCZENIE PRZEZ PROXY";
  if(State & INTERNET_CONNECTION_MODEM_BUSY) Label1->Caption = "MODEM ZAJĘTY";
 }
 else
  Label1->Caption = "BRAK POŁĄCZENIA";
}
//------------------------------------------

...powrót do menu. 

Sprawdzanie zewnętrznego adresu IP.

Serwis Cyfrowy Baron jako chyba jedyny w polskiej sieci Internetowej prezentuje kod na sprawdzanie własnego zewnętrznego adresu IP.
W środowisku BCB nie istnieje żadna gotowa funkcja, która umożliwiała by sprawdzenie własnego zewnętrznego adresu IP. W poradzie Odczyt własnego Adresu IP. podałem przykład pobierania lokalnego adresu IP, ale taki adres przydaje się tylko przy tworzeniu programów dla sieci lokalnych.
Problem z pobraniem zewnętrznego adresu IP polega na tym, że po pierwsze często jest on przydzielany dynamicznie, czyli przy każdym podłączeniu do sieci może być inny, po drugie system nie przechowuje informacji o tym adresie, takie info z pewnością posiada program dostępowy, ale wydobycie go z niego może okazać się wyjątkowo trudne lub wręcz niemożliwe.
Ja mój kod pobierający zewnętrzny adres IP oparłem na wysyłaniu do sieci zapytana o ten adres. W Internecie można znaleźć wiele stron podających nam nasz własny zewnętrzny IP po wejściu na taką stronę.
Wchodzenie i sprawdzanie w ten sposób własnego IP mnie osobiście nigdy nie zadowalało, dlatego szukałem sposobu na to, żeby program sam połączył się z taką stroną i wyciągnął z niej ten adres, bez konieczności wczytywania tej strony, czy wręcz pobierania jej z sieci i zapisywania na dysku. Dlatego też postanowiłem skorzystać z biblioteki wininet, która posiada mnóstwo użytecznych funkcji, w tym możliwość odczytania zawartości strony z adresu i przechowywania tego w zmiennej typu AnsiString, w postaci kodu źródłowego. Ponieważ jest to kod źródłowy strony, więc po pobraniu będzie zawierał wszystko co zawiera taki plik, istnieje jednak adres w sieci: http://dynupdate.no-ip.com/ip.php po połączeniu z którym zwracany jest tylko adres IP w czystej postaci bez jakiegokolwiek formatowania.

Dla celów sprawdzenia zewnętrznego adresu IP stworzyłem funkcję GetExternalIP nie pobierającą żadnych argumentów i zwracającą wynik typu AnsiString. Funkcja nie będzie jednak działać jeśli nie włączymy do projektu biblioteki wininet.lib, którą można znaleźć w katalogu [...]:\Program Files\Borland\CBuilder6\Lib, tak wiec poprzez menu: Project | Add to project włączamy do projektu wspomnianą bibliotekę. Musimy jeszcze włączyć poprzez sekcję include plik: #include wininet.h

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------

#include <wininet.h>
AnsiString GetExternalIP(void)
{
 AnsiString ip = "";
 AnsiString Url = "http://dynupdate.no-ip.com/ip.php";

 DeleteUrlCacheEntry(Url.c_str());

 HINTERNET hSession;
 hSession = InternetOpen(Application->Name.c_str(), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0 );
 if(hSession)
 {
  HINTERNET hService;
  hService = InternetOpenUrl(hSession, Url.c_str(), NULL, 0, 0, 0 );
  if(hService)
  {
   while(1)
   {
    char lpBuffer[1024 + 1];
    DWORD dwBytesRead;
    InternetReadFile(hService, lpBuffer, 1024, &dwBytesRead);
    if(dwBytesRead == 0) break;
    lpBuffer[dwBytesRead] = 0;
    ip += lpBuffer;
   }
  }
  InternetCloseHandle(hService);
 }
 InternetCloseHandle(hSession);
 return ip;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 Label1->Caption = "Zewnętrzny adres IP: " + GetExternalIP();
}
//------------------------------------------

Przy pobieraniu adresu należy uzbroić się nieco w cierpliwość, u mnie sprawdzanie trwało w kilku próbach od 30 do 40 sekund.
Chciałbym tutaj nadmienić, że w ten sposób można ładować do zmiennej AnsiString, lub np. do obiektu Memo1 kod źródłowy dowolnej strony z sieci, bez konieczności pobierania jej przez protokół HTTP lub FTP, wystarczy tylko zmienić adres Url.
Niżej przedstawiam przykład załadowania do obiektu Memo1 głównej strony serwisu Cyfrowy Baron, należy pamiętać o podawaniu nazwy pliku, a nie tylko adresu serwisu:

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------

#include <wininet.h>
AnsiString GetExternalIP(AnsiString Url)
{
 AnsiString result = "";


 HINTERNET hSession;
 hSession = InternetOpen(Application->Name.c_str(), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0 );
 if(hSession)
 {
  HINTERNET hService;
  hService = InternetOpenUrl(hSession, Url.c_str(), NULL, 0, 0, 0 );
  if(hService)
  {
   while(1)
   {
    char lpBuffer[1024 + 1];
    DWORD dwBytesRead;
    InternetReadFile(hService, lpBuffer, 1024, &dwBytesRead);
    if(dwBytesRead == 0) break;
    lpBuffer[dwBytesRead] = 0;
    result += lpBuffer;
   }
  }
  InternetCloseHandle(hService);
 }
 InternetCloseHandle(hSession);
 return result;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 Memo1->Text = GetExternalIP("http://cyfbar.republika.pl/index.html");
}
//------------------------------------------

...powrót do menu. 

Sprawdzanie czy istnieje wybrany plik w sieci.

W celu sprawdzenia czy istnieje w sieci (Internet nie sieć lokalna) wybrany plik stworzymy funkcję ValidURL bazującą na funkcjach i bibliotekach wykorzystanych w poradzie 'sprawdzanie zewnętrznego adresu IP'. Funkcja nie będzie jednak działać jeśli nie włączymy do projektu biblioteki wininet.lib, którą można znaleźć w katalogu [...]:\Program Files\Borland\CBuilder6\Lib, tak wiec poprzez menu: Project | Add to project włączamy do projektu wspomnianą bibliotekę. Musimy jeszcze włączyć poprzez sekcję include plik: #include wininet.h

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------
#include "wininet.h"
bool ValidURL(String url)
{
 bool result = false;

 HINTERNET hSession = InternetOpenA("ValidURL", INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, 0);
 if(hSession != 0)
 {
  HINTERNET hFile = InternetOpenUrl(hSession, url.c_str(), 0, 0, INTERNET_FLAG_RELOAD, 0);
  if(hFile != 0)
  {
   int code = 0;
   DWORD codeLen = sizeof(int);
   HttpQueryInfo(hFile, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &code, &codeLen, 0);

   result = code == HTTP_STATUS_OK || code == HTTP_STATUS_REDIRECT;

   InternetCloseHandle(hFile);
  }
  InternetCloseHandle(hSession);
 }
 return(result);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 if(ValidURL("http://cyfbar.republika.pl/index.html"))
  ShowMessage("Znaleziono plik w podanej lokalizacji");
 else
  ShowMessage("Brak pliku!");
}
//------------------------------------------

...powrót do menu. 

Wyciąganie adresów URL ze stron internetowych.

Często zadawanym pytaniem na forach jest 'Jak wyciągnąć adres URL z pliku', dlatego też stworzyłem dwie funkcje, które zrealizują to zadanie. Funkcja ReadFileURL, będzie służyła do wczytywania pliku z Internetu i przepisania go do zmiennej typu AnsiString, natomiast funkcja GetAdressURL będzie gromadziła na liście wszystkie odwołania do adresów w załadowanym pliku. Przeszukiwanie pod kontem adresów url odbywa się poprzez sprawdzanie czy w pliku istnieje tag '<a href="' i to w zasadzie mogło by wystarczyć, jednak czasami na stronach umieszczane są różnego rodzaju skrypty, a w takich skryptach nie stosuje się wspomnianego tagu, dlatego wprowadziłem do funkcji również opcję wyszukiwania na podstawie członu '"http', to nie wyczerpuje wszystkich możliwości, ale wystarczy żeby wczytać adresu url np. ze strony http://www.onet.pl/index.html. Podając adres strony z której chcemy wyciągnąć adresy należy podać cały adres, nie wystarczy nazwa samej domeny.
Funkcje nie będą działać jeśli nie włączymy do projektu biblioteki wininet.lib, którą można znaleźć w katalogu [...]:\Program Files\Borland\CBuilder6\Lib, tak wiec poprzez menu: Project | Add to project włączamy do projektu wspomnianą bibliotekę. Musimy jeszcze włączyć poprzez sekcję include plik:
#include wininet.h

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------
#include "wininet.h"
AnsiString ReadFileURL(AnsiString Url)
{
 AnsiString result = "";
 HINTERNET hSession = NULL;
 hSession = InternetOpen("ReadFileURL", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
 if(hSession)
 {
  HINTERNET hService = NULL;
  hService = InternetOpenUrl(hSession, Url.c_str(), NULL, 0, 0, 0 );
  if(hService)
  {
   while(1)
   {
    char lpBuffer[1024 + 1];
    DWORD dwBytesRead;
    InternetReadFile(hService, lpBuffer, 1024, &dwBytesRead);
    if(dwBytesRead == 0) break;
    lpBuffer[dwBytesRead] = 0;
    result += lpBuffer;
   }
  }
  InternetCloseHandle(hService);
 }
 InternetCloseHandle(hSession);
 return result;
}
//---------------------------------------------------------------------------
TStrings *GetAdressURL(AnsiString FileName)
{
 Screen->Cursor = crHourGlass;
 String Value = ReadFileURL(FileName);
 String temp = Value;
 String Domain = FileName.SubString(1, FileName.LastDelimiter("/") - 1);
 TStringList *Lista = new TStringList;
 unsigned short p = Value.Pos("<a href=\"");
 if(p > 0)
 {
  lab_1:
  Value = Value.Delete(1, p + 8);
  for(int i = 1; i < Value.Length(); i++)
  {
   String tmp = Value.SubString(i, 1);
   if(tmp == "\"")
   {
    String http = Value.SubString(1, 4).LowerCase();
    if(http == "http" || http == "mail")
     Lista->Add(Value.SubString(1, i - 1));
    else
     Lista->Add(Domain + "/" + Value.SubString(1, i - 1));
    p = Value.Pos("<a href=\"");
    if(p > 0)
     goto lab_1;
    else
     break;
   }
  }
 }
 Value = temp;
 p = Value.Pos("\"http");
 if(p > 0)
 {
  lab_2:
  Value = Value.Delete(1, p);
  for(int i = 1; i < Value.Length(); i++)
  {
   String tmp = Value.SubString(i, 1);
   if(tmp == "\"")
   {
    Lista->Add(Value.SubString(1, i - 1));
    p = Value.Pos("\"http");
    if(p > 0)
     goto lab_2;
    else
     break;
   }
  }
 }
 Screen->Cursor = crDefault;
 return Lista;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 Memo1->Lines->Assign(GetAdressURL("http://www.onet.pl/index.html"));
}
//------------------------------------------

...powrót do menu. 

Wywołanie okna podglądu dla kontrolki TCppWebBrowser.

Korzystając z kontrolki TCppWebBrowser można przeglądać witryny WWW. Możliwości tej kontrolki są uzależnione od jej wersji, ale przede wszystkim o wersji biblioteki SHDOCVW.DLL gdyż bazuje ona właśnie na tej bibliotece, tym którzy jeszcze nie wiedzą wyjaśniam, że z tej biblioteki korzysta Internet Explorer, więc kontrolka TCppWebBrowser posiada teoretycznie takie same możliwości jak IE, w praktyce jej możliwości są mniejsze, gdyż nie wszystkie funkcje zawarte w tej bibliotece można wywołać z poziomu kontrolki TCppWebBrowse.
Jedna z funkcji - ExecWB, umożliwia wywołanie okna podglądu wydruku załadowanej witryny.

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 CppWebBrowser1->ExecWB(Shdocvw_tlb::OLECMDID_PRINTPREVIEW, Shdocvw_tlb::OLECMDEXECOPT_DODEFAULT);
 /* jeżeli wystąpi problem z Shdocvw_tlb, spróbować: CppWebBrowser1->ExecWB(Shdocvw::OLECMDID_PRINTPREVIEW, Shdocvw::OLECMDEXECOPT_DODEFAULT); */
}
//------------------------------------------

Funkcja zadziała tylko jeżeli do kontrolki zostanie załadowana jakaś strona, lub nawet pusta strona:

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------
void __fastcall TForm1::FormShow(TObject *Sender)
{
 CppWebBrowser1->Navigate(WideString("about:blank")); // załadowanie pustej strony
}
//------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  CppWebBrowser1->ExecWB(Shdocvw_tlb::OLECMDID_PRINTPREVIEW, Shdocvw_tlb::OLECMDEXECOPT_DODEFAULT);
}
//------------------------------------------

Możliwe jest również wysłanie strony do druku bez wywoływania okna podglądu. wtedy należy podać jako pierwszy argument wartość: Shdocvw_tlb::OLECMDID_PRINT, natomiast jako drugi argument można podać jedną z czterech opcji

//Plik nagłówkowy np. Unit1.cpp
//------------------------------------------
void __fastcall TForm1::FormShow(TObject *Sender)
{
 CppWebBrowser1->Navigate(WideString("about:blank")); // załadowanie pustej strony
}
//------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 CppWebBrowser1->ExecWB( Shdocvw_tlb::OLECMDID_PRINT, Shdocvw_tlb::OLECMDEXECOPT_DODEFAULT );
}
//------------------------------------------

...powrót do menu. 

Wysyłanie polecenia PING za pomocą komponentu TIdIcmpClient (INDY).

Polecenie Ping weryfikuje łączność na poziomie protokołu IP z innym komputerem obsługującym protokół TCP/IP, wysyłając komunikaty żądania echa protokołu ICMP (Internet Control Message Protocol). Polecenie Ping to podstawowe polecenie protokołu TCP/IP używane do rozwiązywania problemów z łącznością, dostępnością i rozpoznawaniem nazw.

Korzystając z komponentu TIdIcmpClient z pakietu INDY v9, możemy wysłać takie polecenie poprzez funkcje Ping tegoż komponentu. Funkcja pobiera dwa argumenty. Pierwszy argument to opcjonalna wartość, która zostanie wysłana jako zapytanie. Drugi argument określa wartość pola typu usługi (TOS, Type of Service) w nagłówku protokołu IP dla wysyłanych komunikatów żądania echa. Wartość domyślna jest równa 0. Parametr TOS jest określany jako wartość dziesiętna z zakresu od 0 do 255.

Odpowiedź na polecenie Ping odbywa się w zdarzeniu OnReply tego komponentu. Przed wywołaniem funkcji Ping trzeba określa w milisekundach czas oczekiwania na odebranie komunikatu odpowiedzi echa zgodnego z danym komunikatem żądania echa. Jeżeli komunikat odpowiedzi echa nie zostanie odebrany zgodnie z limitem czasu, wyświetlany jest komunikat o błędzie „Upłynął limit czasu żądania”. Domyślny limit czasu wynosi 4000 (4 sekundy), wartość tą określa się w właściwośći ReceiveTimeout. Właściwość Host określa miejsce docelowe identyfikowane przez adres IP lub nazwę hosta. Odpowiedź będzie wyświetlana w obiekcie ListBox1.


 String ipReply;
 int utracone, min, max;
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 ListBox1->Items->Clear();
 ipReply = "";
 utracone = 0;
 min = 0;
 max = 0;

 IdIcmpClient1->ReceiveTimeout = 4000;
 IdIcmpClient1->Host = "cyfbar.republika.pl";
 int i;
 for(i = 0; i < 4; i++)
 {
  IdIcmpClient1->Ping("50", 0);
  Application->ProcessMessages();
 }

 ListBox1->Items->Add("");
 ListBox1->Items->Add("Statystyka badania ping dla " + ipReply + ":");
 ListBox1->Items->Add("        Pakiety: Wysłane = " + (String)i +
                      ", Odebrane = " + (String)(i - utracone) +
                      ", Utracone = " + (String)utracone +
                      " <" + (String)((100/i)*utracone) + "% straty>.");

 ListBox1->Items->Add("Szacunkowy czas błądzenia pakietu w milisekundach:");
 ListBox1->Items->Add("        Minimum = " + (String)min + " ms, Maksimum = " +
                      (String)max + " ms, Czas średni = " +
                      (String)((min + max)/2) + " ms");
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdIcmpClient1Reply(TComponent *ASender,
        const TReplyStatus &AReplyStatus)
{
 String sTime = " = ";
 if(AReplyStatus.MsRoundTripTime == 0) sTime = "mniej niż 1";
 if(AReplyStatus.BytesReceived == 0) utracone++;

 int time = AReplyStatus.MsRoundTripTime;
 if(min > time || min == 0) min = time;
 if(max < time) max = time;

 ipReply = AReplyStatus.FromIpAddress;
 if(AReplyStatus.BytesReceived > 0)
 {
  ListBox1->Items->Add("Odpowiedź z " + AReplyStatus.FromIpAddress +
                       ": bajtów = " +IntToStr(AReplyStatus.BytesReceived) +
                       " czas" + sTime + time +
                       " TTL = " + IntToStr(AReplyStatus.TimeToLive));
 }
 else
 {
  ListBox1->Items->Add("Upłynąl limit czasu żadania");
 }
}
//---------------------------------------------------------------------------

...powrót do menu. 

Wyliczanie dostępnych i aktywnych połączeń internetowych.

Do wyliczenie wszystkich dostępnych połączeń sieciowych (nie dotyczy połączeń lokalnych), można posłużyć się funkcją RasEnumEntries, natomiast do uzyskania informacji o aktywnych połączeniach sieciowych można posłużyć się funkcją RasEnumConnections. Wspomniane funkcje są dostępne w bibliotece ras.h, dlatego należy ją dołączyć do projektu.

W przedstawionym niżej przykładzie stworzyłem dwie funkcje CheckAllConnections do wyliczania wszystkich połączeń, oraz funkcję CheckActiveConnections do wyliczania tylko aktywnych połączeń. Funkcja CheckAllConnections będzie podawała tylko nazwy dostępnych połączeń internetowych, dokładnie te same nazwy są widoczne w aplecie Panelu Sterowania  - Połączenia sieciowe, funkcja wylicza tylko połączenie internetowe, nie wylicza połączeń lokalnych. Funkcja CheckActiveConnections będzie podawała nazwę aktywnego połączenia internetowego oraz nazwę i typ urządzenia, przez które przechodzi to połączenie.

#include "ras.h"

void CheckAllConnections(TStrings *List) // wyliczanie wszystkich dostępnych połączeń
{
 List->Clear();
 DWORD dwCb = sizeof(RASENTRYNAME);
 DWORD dwErr = ERROR_SUCCESS;
 DWORD dwRetries = 5;
 DWORD dwEntries = 0;
 RASENTRYNAME *lpRasEntryName = NULL;

 while(dwRetries--)
 {
  if(NULL != lpRasEntryName)
  {
   HeapFree(GetProcessHeap(), 0, lpRasEntryName);
   lpRasEntryName = NULL;
  }
  lpRasEntryName = (RASENTRYNAME *)HeapAlloc(GetProcessHeap(), 0, dwCb);
  if(NULL == lpRasEntryName)
  {
   dwErr = ERROR_NOT_ENOUGH_MEMORY;
   break;
  }
  lpRasEntryName->dwSize = sizeof(RASENTRYNAME);
  dwErr = RasEnumEntries(NULL, NULL, lpRasEntryName, &dwCb, &dwEntries);
 }
 if(ERROR_SUCCESS == dwErr)
 {
  List->Add("Dostępne połączenia:");
  for(DWORD i = 0; i < dwEntries; i++)
  {
   List->Add("\tNazwa połączenia: " + (String)lpRasEntryName[i].szEntryName);
  }
 }
 else
 {
  List->Add("Błąd = " + (String)dwErr);
 }
 if(NULL != lpRasEntryName)
 {
  HeapFree(GetProcessHeap(), 0, lpRasEntryName);
  lpRasEntryName = NULL;
 }
}
//---------------------------------------------------------------------------
void CheckActiveConnections(TStrings *List, bool AllConnections) // wyliczanie aktywnych połączeń
{
 List->Clear();

 if(AllConnections) // wyliczenie wszystkich dostępnych połączeń
 {                  // jeżeli zmienna AllConnections jest ustawiona na true
  CheckAllConnections(List);
  List->Add("");
 }

 char buff[256];
 RASCONN rc;
 rc.dwSize = sizeof(RASCONN);
 DWORD numConns;
 DWORD size = rc.dwSize;

 // Wyliczanie połączeń.
 DWORD res = RasEnumConnections(&rc, &size, &numConns);

 if(!res && numConns == 0)
 {
  List->Add("Brak aktywnych połączeń");
  return; // przerwanie funkcji przy braku połączeń
 }

 if(res)
 {
  // raportowanie błędów
  RasGetErrorString(res, buff, sizeof(buff));
  List->Add(buff);
 }
 else
 {
  // sprawdzanie statusu połączenia.
  RASCONNSTATUS status;
  status.dwSize = sizeof(status);
  res = RasGetConnectStatus(rc.hrasconn, &status);

  if(res)
  {
   // raportowanie błędów
   RasGetErrorString(res, buff, sizeof(buff));
   List->Add(buff);
  }
  else
  {
   // wyświetlanie szczegółów połączenia
   if(status.rasconnstate == RASCS_Connected)
   {
    List->Add("Aktywne połączenia:");
    List->Add("\tNazwa połączenia: " + (String)rc.szEntryName);
    List->Add("\tTyp urządzenia: " + (String)rc.szDeviceType);
    List->Add("\tNazwa urządzenia: " + (String)rc.szDeviceName);
   }
   else
   {
    // gdy połączenie zostało wykryte jednak ma status rozłączone
    List->Add("Rozłączony");
   }
  }
 }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 CheckActiveConnections(Memo1->Lines, true);
}
//---------------------------------------------------------------------------

W przykładzie wywoływana jest tylko funkcja CheckActiveConnection, gdyż zawiera ona w sobie odwołanie do funkcji CheckAllConnections. Jeżeli jako drugi argument funkcji CheckActiveConnections przekażemy wartość true, to najpierw wykona się funkcja CheckAllConnections, która wyświetli w Memo1 wszystkie dostępne połączenia, a następnie wykona się funkcja CheckActiveConnections i do Memo1 zostaną dodane informacje o aktywnych połączeniach. Jeżeli jako drugi argument przekażemy funkcje CheckAllConnections wartość fale, to wykona się tylko ta funkcja.
Możliwe jest również wywołanie samej funkcji CheckAllConnections, w celu wyliczenia tylko dostępnych połączeń, wystarczy ją wywołać tak:
CheckAllConnections(Memo1->Lines);
Obydwie funkcje jako argument pobierają wskaźnik do obiektu typu TStrings, więc można przekazać tym funkcją wskaźnik do dowolnego obiektu zawierającego klasę TStrings, np. ListBox->Items, RichEdit1->Lines, itp...

...powrót do menu. 

Ściąganie plików z Internetu przez protokół HTTP (bez Indy).

Środowisko BCB oferuje nam bibliotekę urlmon.h zawierającą wiele użytecznych funkcji umożliwiających między innymi pobieranie plików z Internetu w prosty sposób ograniczający się w zasadzie do wywołania pojedynczej funkcji.

Funkcja URLDownloadToFile umożliwiająca ściągnięcie dowolnego pliku pobiera pięć argumentów:

HRESULT URLDownloadToFile(      
    LPUNKNOWN pCaller, - wskaźnik do interfejsu IUnknow
    LPCTSTR szURL,
    LPCTSTR szFileName,
    DWORD dwReserved,
    LPBINDSTATUSCALLBACK lpfnCB
);

LPUNKNOWN pCaller - wskaźnik do interfejsu IUnknow wywoływanego w kontrolce Microsoft ActiveX jeżeli wywołanie dotyczy kontrolki ActiveX, jeżeli nie podajemy wartość NULL.

LPCTSTR szURL - wskaźnik do zmiennej (lub wartości) typu AnsiString zawierającej adres pobieranego pliku.

LPCTSTR szFileName - wskaźnik do zmiennej (lub wartości) typu AnsiString zawierającej pełną ścieżkę tworzonego pliku. Katalog do którego zapisujemy ściągany plik musi istnieć.

DWORD dwReserved - zarezerwowane, musi być wartość 0.

LPBINDSTATUSCALLBACK lpfnCB - wskaźnik do interfejsu IBindStatusCallback, umożliwia między innymi podłączenie ProgressBar celem zobrazowania postępu pobierania pliku.

Funkcja URLDownloadToFile wymaga włączenia do projektu biblioteki urlmon.lib. Bibliotekę dołączmy poprzez menu Project | Add to project. Biblioteka znajduje się w lokalizacji: $(BDS)\lib\psdk
Nie jest to konieczne, ale dla pewności sugeruję również dołączyć do pliku nagłówkowego w sekcji include bibliotekę: #include <urlmon.h> Do stworzenia interfejsu IBindStatusCallback włączenie tej biblioteki jest konieczne.

Na początek przykład ściągania pliku z wykorzystaniem funkcji URLDownloadToFile bez paska postępu, w sposób możliwie najprostszy:

#include <urlmon.h>

 #pragma comment(lib, "urlmon.lib")
// jeżeli włączamy bibliotekę przez menu Project | Add to project, to ta linijka jest zbędna

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 String FileName = "offlinepdf.rar";
 AnsiString Url = "http://free4web.pl/Click?54619";
 AnsiString FileResult = "c:\\" + FileName;


 URLDownloadToFile(0, Url.c_str(), FileResult.c_str(), 0, 0);
}

Jak wspomniałem wcześniej możliwe jest podłączenie paska postępu, który będzie obrazował  proces ściągania pliku. Wymaga to stworzenia interfejsu IBindStatusCallback. Trzeba w tym celu stworzyć nową klasę, można to zrobić w oddzielnym pliku i włączyć tenże plik do projektu, ale można równie dobrze stworzyć tą klasę w istniejącym już pliku nagłówkowy lub źródłowym. W przykładzie zdefiniuję klasę w pliku źródłowym, w takim przypadku należy pamiętać, żeby kod definiujący klasę był umieszczony przed funkcją lub zdarzeniem, które z tej klasy będzie korzystać. Dodatkowo klasa będzie obsługiwała komunikaty wysyłane podczas ściągania pliku, będą one wyświetlane w obiekcie ListBox1. Dodatkowo dodałem obsługę wyjątków, które funkcja zwraca, gdy ściąganie się powiedzie lub nie. Tutaj niestety te komunikaty nie zawsze będą zgłaszane, gdyż jest to uzależnione od serwera z którego plik jest pobierany, dlatego umieściłem dodatkowo własny komunikat w interfejsie IBindStatusCallback.

#include <urlmon.h>

 #pragma comment(lib, "urlmon.lib")
// jeżeli włączamy bibliotekę przez menu Project | Add to project, to ta linijka jest zbędna

//---------------------------------------------------------------------------
class TStatusCallback : public IBindStatusCallback
{
 public:
        TProgressBar *ProgressBar;
        TListBox *ListBox;

 STDMETHODIMP QueryInterface(REFIID riid ,void ** ppv){return E_NOINTERFACE;}
 STDMETHODIMP_(ULONG) AddRef(){return 0;}
 STDMETHODIMP_(ULONG) Release(){return 0;}
 STDMETHODIMP OnStartBinding(DWORD grfBSCOption, IBinding* pbinding){return 0;}
 STDMETHODIMP GetPriority(LONG* pnPriority){return 0;}
 STDMETHODIMP OnLowResource(DWORD dwReserved){return 0;}

 STDMETHOD(OnProgress)(ULONG ulProgress, ULONG ulProgressMax,
                       ULONG ulStatusCode, LPCWSTR szStatusText)
 {
   ProgressBar->Max = ulProgressMax;
   ProgressBar->Position = ulProgress;
   Application->ProcessMessages();

   ListBox->Items->Add(szStatusText);

   return 0;
 }

 STDMETHODIMP OnStopBinding(HRESULT hrResult, LPCWSTR szError)
 {
   if(hrResult > 0)
      Application->MessageBox("Pobieranie pliku zakończone sukcesem",
                   "Ukończon pobieranie", MB_OK | MB_ICONINFORMATION);
   else
      Application->MessageBox("Plik nie istnieje", "Błąd pobierania", MB_OK | MB_ICONINFORMATION);

   return 0;
 }

 STDMETHODIMP GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindinfo){return 0;}
 STDMETHODIMP OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC *pfmtetc,STGMEDIUM* pstgmed){return 0;}
 STDMETHODIMP OnObjectAvailable(REFIID riid, IUnknown* punk){return 0;}
};
//--------------------------------------------------------------------------=
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 dynamic_cast<TButton *>(Sender)->Enabled = false;
 String FileName = "advbar.rar";
 AnsiString Url = "http://cyfbar.republika.pl/files/components/" + FileName;
 AnsiString FileResult = "c:\\" + FileName;

 int result;

 TStatusCallback statCallback;
 statCallback.ProgressBar = ProgressBar1;
 statCallback.ListBox = ListBox1;

 result == URLDownloadToFile(0, Url.c_str(), FileResult.c_str(), 0, &statCallback);


 switch(result)
 {
  case S_OK: Application->MessageBox("Pobieranie pliku zakończone powodzeniem",
             "Sukces", MB_OK | MB_ICONINFORMATION);
             break;
  case E_OUTOFMEMORY: Application->MessageBox("Przekroczono rozmiar bufora, lub "
                      "masz za mało pamięci", "Błąd", MB_OK | MB_ICONSTOP);
             break;
  case INET_E_DOWNLOAD_FAILURE: Application->MessageBox("Nie można pobrać pliku "
                                "z wybranej lokalizacji. Nie jesteś połączony z Internetem "
                                "lub plik nie istnieje", "Błąd", MB_OK | MB_ICONSTOP);
             break;
 }
 dynamic_cast<TButton *>(Sender)->Enabled = true;
}
//---------------------------------------------------------------------------

...powrót do menu. 

Wyświetlanie plików graficznych bezpośrednio z Internetu.

Biblioteaka urlmon.h przedstawiona w poprzedniej poradzie posiada funkcję umożliwiającą pobranie dowolnego pliku i zapisanie go w pamięci fizycznej RAM, a nie tylko na dysku.

Funkcja URLDownloadToFile umożliwiająca ściągnięcie dowolnego pliku pobiera pięć argumentów:

HRESULT URLBlockingStream(      
    LPUNKNOWN pCaller, - wskaźnik do interfejsu IUnknow
    LPCTSTR szURL,
    LPCTSTR szFileName,
    DWORD dwReserved,
    LPBINDSTATUSCALLBACK lpfnCB
);

LPUNKNOWN pCaller - wskaźnik do interfejsu IUnknow wywoływanego w kontrolce Microsoft ActiveX jeżeli wywołanie dotyczy kontrolki ActiveX, jeżeli nie podajemy wartość NULL.

LPCTSTR szURL - wskaźnik do zmiennej (lub wartości) typu AnsiString zawierającej adres pobieranego pliku.

LPSTREAM *ppStream - wskaźnik do obiektu typu IStream, w którym będzie przechowywany ściągnięty obiekt.

DWORD dwReserved - zarezerwowane, musi być wartość 0.

LPBINDSTATUSCALLBACK lpfnCB - wskaźnik do interfejsu IBindStatusCallback, umożliwia między innymi podłączenie ProgressBar celem zobrazowania postępu pobierania pliku.

Funkcja URLBlockingStream wymaga włączenia do projektu biblioteki urlmon.lib. Bibliotekę dołączmy poprzez menu Project | Add to project. Biblioteka znajduje się w lokalizacji: $(BDS)\lib\psdk
Nie jest to konieczne, ale dla pewności sugeruję również dołączyć do pliku nagłówkowego w sekcji include bibliotekę: #include <urlmon.h> Do stworzenia interfejsu IBindStatusCallback włączenie tej biblioteki jest konieczne.

Na początek przykład ściągania pliku z wykorzystaniem funkcji URLDownloadToFile bez paska postępu, w sposób możliwie najprostszy:

Z wykorzystaniem pomysłu kinio opartego na tablicy typu char:

// wymagane biblioteki
 #include "wininet.h"
 #include <urlmon.h>
 #include <memory>
 #include <GIFImg.hpp>
//co najmniej środowisko C++ Builder 2007

 #pragma comment(lib, "urlmon.lib")
// jeżeli włączamy bibliotekę przez menu Project | Add to project, to ta linijka jest zbędna

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 AnsiString Url = "http://cyfbar.republika.pl/images/barcode.gif";

 IStream* pStream;

 URLOpenBlockingStream(0, Url.c_str(), &pStream, 0, 0);

 LARGE_INTEGER liZero = { 0 }; // Aby odnosic sie wzgledem poczatku strumienia
 ULARGE_INTEGER CurPos; // Do zapisania pozycji wskaźnika

 //Zapisujemy bierzaca pozycje wskaznika
 pStream->Seek(liZero, STREAM_SEEK_CUR, &CurPos);

 // Sprawdzamy wielkość strumienia
 ULARGE_INTEGER SizeOfFile;
 pStream->Seek(liZero, STREAM_SEEK_END, &SizeOfFile);

 // Przywracamy wskaznik na poprzednia pozycje
 LARGE_INTEGER Pos;
 Pos.QuadPart = CurPos.QuadPart;
 pStream->Seek(Pos, STREAM_SEEK_SET, NULL);

 //Tworzymy bufor przejsciowy dla strumienia
 void* data = new char[SizeOfFile.QuadPart];
 pStream->Read(data, SizeOfFile.QuadPart, NULL);

 std::auto_ptr<TMemoryStream>mStream(new TMemoryStream);
 mStream->Write(data, SizeOfFile.QuadPart);
 mStream->Position = 0;

 String ext = ExtractFileExt(Url);

 if(ext.LowerCase() == ".jpg")
 {
  std::auto_ptr<TJPEGImage> JImage(new TJPEGImage());
  JImage->LoadFromStream(mStream.get());
  Image1->Picture->Assign(JImage.get());
 }
 if(ext.LowerCase() == ".bmp")
 {
  std::auto_ptr<Graphics::TBitmap> Bmp(new Graphics::TBitmap());
  Bmp->LoadFromStream(mStream.get());
  Image1->Picture->Assign(Bmp.get());
 }
 if(ext.LowerCase() == ".gif") // co najmniej środowisko C++ BUilder 2007
 {
  TGIFImage *GifImg = new TGIFImage();
  GifImg->Animate = true;
  GifImg->Transparent = true;
  GifImg->LoadFromStream(mStream.get());
  Image1->Picture->Assign(GifImg);
  delete GifImg;
 }

 delete [] data;
}

Z wykorzystaniem pomysłu Witold'a z wykorzystaniem obiektu TOleStream, jest to sposób prostszy i krótszy:

// wymagane biblioteki
 #include "wininet.h"
 #include <urlmon.h>
 #include <memory>
 #include <GIFImg.hpp> //co najmniej środowisko C++ Builder 2007


 #pragma comment(lib, "urlmon.lib")
// jeżeli włączamy bibliotekę przez menu Project | Add to project, to ta linijka jest zbędna

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 AnsiString Url = "http://cyfbar.republika.pl/images/barcode.gif";

 IStream* pStream;

 URLOpenBlockingStream(0, Url.c_str(), &pStream, 0, 0);

 std::auto_ptr<TOleStream> mStream(new TOleStream(pStream));

 String ext = ExtractFileExt(Url);

 if(ext.LowerCase() == ".jpg")
 {
  std::auto_ptr<TJPEGImage> JImage(new TJPEGImage());
  JImage->LoadFromStream(mStream.get());
  Image1->Picture->Assign(JImage.get());
 }
 if(ext.LowerCase() == ".bmp")
 {
  std::auto_ptr<Graphics::TBitmap> Bmp(new Graphics::TBitmap());
  Bmp->LoadFromStream(mStream.get());
  Image1->Picture->Assign(Bmp.get());
 }
 if(ext.LowerCase() == ".gif")
 {
  TGIFImage *GifImg = new TGIFImage();
  GifImg->Animate = true;
  GifImg->Transparent = true;
  GifImg->LoadFromStream(mStream.get());
  Image1->Picture->Assign(GifImg);
  delete GifImg;
 }
}
//---------------------------------------------------------------------------

Możemy sobie podłączyć który będzie obrazował  proces wczytywania pliku. Jednakże przy bardzo małych plikach pasek raczej nie drgnie, tylko skoczy na koniec po wczytaniu grafiki. Wymaga to stworzenia interfejsu IBindStatusCallback. Trzeba w tym celu stworzyć nową klasę, można to zrobić w oddzielnym pliku i włączyć tenże plik do projektu, ale można równie dobrze stworzyć tą klasę w istniejącym już pliku nagłówkowy lub źródłowym. W przykładzie zdefiniuję klasę w pliku źródłowym, w takim przypadku należy pamiętać, żeby kod definiujący klasę był umieszczony przed funkcją lub zdarzeniem, które z tej klasy będzie korzystać. Dodatkowo klasa będzie obsługiwała komunikaty wysyłane podczas ściągania pliku, będą one wyświetlane w obiekcie ListBox1. Dodatkowo dodałem obsługę wyjątków, które funkcja zwraca, gdy ściąganie się powiedzie lub nie. Tutaj niestety te komunikaty nie zawsze będą zgłaszane, gdyż jest to uzależnione od serwera z którego plik jest pobierany, dlatego umieściłem dodatkowo własny komunikat w interfejsie IBindStatusCallback.

// wymagane biblioteki
 #include "wininet.h"
 #include <urlmon.h>
 #include <memory>
 #include <GIFImg.hpp> //co najmniej środowisko C++ Builder 2007


 #pragma comment(lib, "urlmon.lib")
// jeżeli włączamy bibliotekę przez menu Project | Add to project, to ta linijka jest zbędna

//---------------------------------------------------------------------------
class TStatusCallback : public IBindStatusCallback
{
 public:
        TProgressBar *ProgressBar;

  STDMETHODIMP QueryInterface(REFIID riid ,void ** ppv){return E_NOINTERFACE;}
  STDMETHODIMP_(ULONG) AddRef(){return 0;}
  STDMETHODIMP_(ULONG) Release(){return 0;}
  STDMETHODIMP OnStartBinding(DWORD grfBSCOption, IBinding* pbinding){return 0;}
  STDMETHODIMP GetPriority(LONG* pnPriority){return 0;}
  STDMETHODIMP OnLowResource(DWORD dwReserved){return 0;}
  STDMETHOD(OnProgress)(ULONG ulProgress, ULONG ulProgressMax,
  ULONG ulStatusCode, LPCWSTR szStatusText)
  {
   ProgressBar->Max = ulProgressMax;
   ProgressBar->Position = ulProgress;
   Application->ProcessMessages();
   return S_OK;
  }

  STDMETHODIMP OnStopBinding(HRESULT hrResult, LPCWSTR szError){return 0;}
  STDMETHODIMP GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindinfo){return 0;}
  STDMETHODIMP OnDataAvailable(DWORD grfBSCF, DWORD dwSize,
  FORMATETC *pfmtetc,STGMEDIUM* pstgmed){return 0;}
  STDMETHODIMP OnObjectAvailable(REFIID riid, IUnknown* punk){return 0;}
};
//---------------------------------------------------------------------------
void __fastcall TForm1::Button4Click(TObject *Sender)
{
 AnsiString Url = "http://cyfbar.republika.pl/images/barcode.gif";

 IStream* pStream;
 int result;

 TStatusCallback statCallback;
 statCallback.ProgressBar = ProgressBar1;

 result = URLOpenBlockingStream(0, Url.c_str(), &pStream, 0, &statCallback);

 std::auto_ptr<TOleStream> mStream(new TOleStream(pStream));

 String ext = ExtractFileExt(Url);

 if(ext.LowerCase() == ".jpg")
 {
  std::auto_ptr<TJPEGImage> JImage(new TJPEGImage());
  JImage->LoadFromStream(mStream.get());
  Image1->Picture->Assign(JImage.get());
 }
 if(ext.LowerCase() == ".bmp")
 {
  std::auto_ptr<Graphics::TBitmap> Bmp(new Graphics::TBitmap());
  Bmp->LoadFromStream(mStream.get());
  Image1->Picture->Assign(Bmp.get());
 }
 if(ext.LowerCase() == ".gif") // co najmniej środowisko C++ Builder 2007
 {
  TGIFImage *GifImg = new TGIFImage();
  GifImg->Animate = true;
  GifImg->Transparent = true;
  GifImg->LoadFromStream(mStream.get());
  Image1->Picture->Assign(GifImg);
  delete GifImg;
 }

 switch(result)
 {
  case S_OK: Application->MessageBox("Pobieranie pliku zakończone powodzeniem",
             "Sukces", MB_OK | MB_ICONINFORMATION);
             break;
  case E_OUTOFMEMORY: Application->MessageBox("Przekroczono rozmiar bufora, lub "
             "masz za mało pamięci", "Bład pamięci", MB_OK | MB_ICONSTOP);
             break;
 }
}
//---------------------------------------------------------------------------

To nie wyczerpuje wszystkich możliwości, do pamięci można wczytywać dowolne pliki. W kolejnym przykładzie pokażę jak wczytać plik HTML do obiektu typu TMemo i jak zapisać go do pliku:

// wymagane biblioteki
 #include "wininet.h"
 #include <urlmon.h>
 #include <memory>
 #include <GIFImg.hpp> //co najmniej środowisko C++ Builder 2007


 #pragma comment(lib, "urlmon.lib")
// jeżeli włączamy bibliotekę przez menu Project | Add to project, to ta linijka jest zbędna

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 AnsiString Url ="http://cyfbar.republika.pl/index.html";

 IStream* pStream;

 URLOpenBlockingStream(0, Url.c_str(), &pStream, 0, 0);

 LARGE_INTEGER liZero = { 0 };
 ULARGE_INTEGER CurPos;
 pStream->Seek(liZero, STREAM_SEEK_CUR, &CurPos);
 ULARGE_INTEGER SizeOfFile;
 pStream->Seek(liZero, STREAM_SEEK_END, &SizeOfFile);
 LARGE_INTEGER Pos;
 Pos.QuadPart = CurPos.QuadPart;
 pStream->Seek(Pos, STREAM_SEEK_SET, NULL);
 void* data = new char[SizeOfFile.QuadPart];
 pStream->Read(data, SizeOfFile.QuadPart, NULL);
 std::auto_ptr<TMemoryStream>mStream(new TMemoryStream);
 mStream->Write(data, SizeOfFile.QuadPart);
 mStream->Position = 0;

 Memo1->Lines->LoadFromStream(mStream.get());

 mStream->SaveToFile("c:\\index.html");

 delete [] data;
}
//---------------------------------------------------------------------------

Można też tak:

// wymagane biblioteki
 #include "wininet.h"
 #include <urlmon.h>
 #include <memory>
 #include <GIFImg.hpp> //co najmniej środowisko C++ Builder 2007


 #pragma comment(lib, "urlmon.lib")
// jeżeli włączamy bibliotekę przez menu Project | Add to project, to ta linijka jest zbędna

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 AnsiString Url = "http://cyfbar.republika.pl/index.html";

 IStream* pStream;

 URLOpenBlockingStream(0, Url.c_str(), &pStream, 0, 0);

 std::auto_ptr<TOleStream> oStream(new TOleStream(pStream));

 Memo1->Lines->LoadFromStream(oStream.get());

 std::auto_ptr<TMemoryStream>mStream(new TMemoryStream);
 mStream->LoadFromStream(oStream.get());
 mStream->Position = 0;

 mStream->SaveToFile("c:\\index.html");
}
//---------------------------------------------------------------------------

...powrót do menu. 

Wstawianie własnego PopupMenu do kontrolki TCppWebBRowser.

Kontrolka TCppWebBrowser posiada PopupMenu dokładnie takie samo jakie występuje w przeglądarce Internet Explorer. Kontrolka ta posiada również właściwość PopupMenu, ale wstawienie tam własnego PopupMenu nic nie da. Problem można rozwiązać za pomocą komponentu TApplicationEvents znajdującego się na zakładce Additional.
Umieszczamy na formularzu kontrolkę CppWebBRowser1, komponent PopupMenu1 oraz komponent ApplicationEvents1. Tworzymy jakieś menu dla PopupMenu1.

Rozwiązanie problemu polega na przechwyceniu komunikatu o wciśnięciu prawego przycisku myszy (WM_RBUTTONDOWN) oraz komunikatu o jego zwolnieniu (WM_RBUTTONUP). Kod zostaje umieszczony w zdarzeniu OnMessage komponentu ApplicationEvents. Dodatkowo znajduje się tam kod sprawdzający, czy wskaźnik myszy znajduje się nad kontrolką CppWebBrowser, jest to realizowane poprzez funkcję GetClassName. PopupMenu1 jest wywoływane w pozycji wskazywanej aktualnie przez wskaźnik myszy, co z kolei jest ustalane przez funkcję GetCursorPos.

PopupMenu wyskoczy tylko jeżeli do kontrolki będzie wczytana jakaś strona, dlatego na wstępie wczytywana jest do niej strona pusta:

 

//Plik nagłówkowy np. Unit1.cpp
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
 CppWebBrowser1->Navigate(WideString("about:blank"));
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ApplicationEvents1Message(tagMSG &Msg, bool &Handled)
{
 if(Msg.message == WM_RBUTTONDOWN || Msg.message == WM_RBUTTONUP)
 {
  POINT cP;
  GetCursorPos(&cP);
  HWND hWnd = WindowFromPoint(cP);
  char szClassName[255];
  char windowName[255];
  GetClassName(hWnd, szClassName, 255);
  if((String)szClassName == "Internet Explorer_Server")
  {
    PopupMenu1->Popup(cP.x, cP.y + 10);
  }
 }
}
//---------------------------------------------------------------------------

...powrót do menu. 

Kopiowanie tekstu z kontrolki CppWebBRowser do schowka.

W celu skopiowania tekstu zaznaczonego w kontrolce CppWebBrowser do schowka, trzeba skorzystać z funkcji ExecWeb, przekazując jej jako pierwszy argument typ wykonywanej operacji, a jako drugi argument opcje wykonywanej operacji, w przykładzie będą to opcje domyślne, co się zaś tyczy operacji to będzie to oczywiście polecenie skopiowania zaznaczenia do schowka.

Na potrzeby tej porady stworzyłem funkcję o nazwie CopyCppSelection. Ponieważ kontrolka TCppWebBrowser nie może występować jako argument funkcji, funkcja ta będzie funkcją lokalną, więc trzeba ją zadeklarować w sekcji private lub public pliku nagłówkowego, czego tutaj nie będę pokazywał, bo wszyscy to potrafią.

 

//Plik nagłówkowy np. Unit1.cpp
/---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include <Clipbrd.hpp>

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "SHDocVw_OCX"

#pragma resource "*.dfm"

TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
    OleInitialize( NULL ); // WAŻNE!!!
}
//---------------------------------------------------------------------------
AnsiString TForm1::CopyCppSelection(void)
{
  Clipboard()->Clear();
  CppWebBrowser1->ExecWB(Shdocvw_tlb::OLECMDID_COPY, Shdocvw_tlb::OLECMDEXECOPT_DODEFAULT);
  AnsiString Ahora = Clipboard()->AsText;
  if(Ahora.IsEmpty())
    Application->MessageBox("Musisz najpierw zaznaczyć jakiś tekst w przeglądarce",
        "Komunikat", MB_OK | MB_ICONINFORMATION);

 return Ahora.Trim();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormShow(TObject *Sender)
{
  CppWebBrowser1->Navigate(WideString("www.google.pl"));
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  Memo1->Text = CopyCppSelection();
}
//---------------------------------------------------------------------------

...powrót do menu.