Bot Gadu-Gadu

bordeux
Artykuł jest nieaktualny z powodu zaprzestania rozwoju komponentu THGG (wielokrotna zmiana protokołu Gadu-Gadu). Obecnie firma udostępnia Gadu-Gadu API

<font size="4">Wstęp</span>


Protokół Gadu-Gadu jest w Polsce powszechnie znany i lubiany, co świadczy o dużej liczbie użytkowników. Prawie każdy internauta go używa. Lecz nie o tym temat. Zajmiemy się dzisiaj korzystać z dobrodziejstw tego protokołu w Delphi. Co prawda nie będziemy pisać wszystkiego od początku, bo bym musiał pisać osobny artykuł, lecz posłużymy się gotowym komponentem THGG (ten artykuł jest tak jakby instrukcją). Dany komponent, by mógł poprawnie funkcjonować , potrzebna mu będzie paczka Indy (wersję 9.x).
Celem naszym będzie napisanie prostego bota, który będzie odpisywał na podane komendy. Będzie to troszeczkę wersja rozbudowana.
To więc co? Do dzieła.

<font size="4">Część wizualna</span>


Przepis:
To więc wrzucamy poniższe komponenty na formę:

  • Panel (zakładka standard)
  • THGG
  • SaveDialog i OpenDialog (zakładka Dialogs)
  • ValueListEditor (zakładka Additional)
  • 3 Edit'y
  • 5 Button'ów
  • Label
  • Memo

Przygotowanie:

#Panel: Ustaw go w lewym górnym rogu tak jak na obrazku. Zmień jego Name na 'PlStatus'.
#ValueListEditor: Zmień jego nazwę na Command, oraz wybierz z Menu Object Inspector – TitleCaptions ... i dodaj do wyświetlonego pola tekstowego 'Komenda' i 'Odpowiedź' (każde w osobnej linii). Jeśli już tam jesteśmy to wybierz też Strings i w kolumnie Key wpisz 'Witaj' a znów w polu Value daj 'Witam człowieku :D'
#Edit1 : Ustaw go tak jak na obrazku
#Edit2 : Ustaw go tak jak na obrazku
#Edit3 : Zmień jego Name na TmpEdit, oraz usuń wartość z Text. Następnie schowaj go, aby ci nie przeszkadzał. On i tak będzie schowany podczas pracy programu.
#Button1 : Zmień Caption na 'Połącz'
#Button2 : Zmień Caption na 'Rozłącz'
#Button3: Zmień Caption na 'Dodaj
#Button4 : Zmien Caption na 'Zapisz'
#Button5 : Zmien Caption na 'Ładuj
#Label1: Zmień Caption na 'Logi Bota'
#Memo1: Usuń jego wartość Lines.
#THGG: Name zostaw tak jak jest, czyli na hgg1.
#SaveDialog1 - Dodaj filtr na nasze rozszerzenie, czyli ggb, poprzez klikniecie na ... w Filter w Inspektorze obiektów. W kolumnie filter name wstaw 'Gadu Gadu Bot (.ggb)' a znów w Filter na '.ggb'
#OpenDialog1 - też dodajemy filtr. Tak samo jak w SaveDialog1, tylko w kolumnie Filter zamiast '*.ggb' daj na '.ggb'

Mniej więcej ustaw komponenty tak jak na obrazku poniżej:

BotGG.jpg

<font size="4">Część programistyczna</span>


Teraz już odpowiednia cześć naszego programu. Więc na początek wywołajmy procedurę OnClick Buttona 1. Uzupełnij go poniższym kodem:

procedure TForm1.Button1Click(Sender: TObject);
begin
  try
    hgg1.Number  := numerGG;
    hgg1.Password  := '*****';
    HGG1.Host := HGG1.GetServerAddress;
    hgg1.Status:=usAvailable;
    hgg1.connect;
  except
    ShowMessage('Wystąpił błąd');
    hgg1.Disconnect;
  end;
end;

Wyjaśnienie:
hgg1.Number - to jest zmienna, którą uzupełniamy naszym numerem GaduGadu
hgg1.Password - jak sama nazwa wskazuje, podajemy hasło do danego numeru GaduGadu
HGG1.Host := HGG1.GetServerAddress; - tutaj ustawiamy adres IP serwera GG. Jeśli damy na HGG1.GetServerAddress to THGG sam sprawdzi i da odpowiedni aktywny IP.
hgg1.Status:=usAvailable; - Ustawiamy status na aktywny. Mamy do wyboru
usNotAvailable - niedostępny
usAvailable dostępny
usBusy - zajęty
usInvisible - niewidoczny
hgg1.connect; - połączenie się z serwerem.
hgg1.Disconnect; - rozłączenie się z serwerem

Teraz wybierz THGG, i w inspektorze obiektów wybierz zakładkę Events, i wywołaj procedurę OnConnected. Uzupełnij go kodem:

procedure TForm1.HGG1Connected(Sender: TObject);
begin
  PlStatus.Color := clLime;
  PlStatus.Caption :='Połączony';
  hgg1.Description :='Bot Gadu-Gadu';
end;
  • PlStatus.Color := clLime; - Tutaj zmieniamy kolor Panela na zielony
  • PlStatus.Caption :='Połączony'; - zmieniamy Caption Panela na 'Połączony'
  • hgg1.Description :='Bot Gadu-Gadu'; - Ustawiamy opis Gadu-Gadu

Teraz też z tego komponentu wywołaj procedurę OnDisconnet i wpisz do tej niej:

procedure TForm1.HGG1Disconnected(Sender: TObject);
begin
  PlStatus.Color := clRed;
  PlStatus.Caption :='Niepołączony';
end;

Ustaw też w procedurze OnMessage:

procedure TForm1.HGG1Message(Sender: TObject; GGNumber: Integer;
  MessageContent: String; MessageTime: TDateTime);
var
  Reply : string;
  Row : integer;
begin
 Memo1.Lines.Add('['+DateToStr(MessageTime)+']('+IntToStr(GGNumber)+') '+MessageContent);
 TmpEdit.Text := MessageContent;
    Command.FindRow(TmpEdit.Text,  Row);
 
 if  Row = -1 then
  Reply := 'Nie ma u nas takiej komendy' else
 begin
  Reply := Command.Values[Edit1.Text];
 end;
 
  HGG1.SendMessage(GGNumber, Reply, []);
end;

Powyższa procedura jest wykonywana wtenczas, jak ktoś wyśle do nas wiadomość. Masz w niej do dyspozycji zmienne:

  • GGNumber - numer od kogo został wysłana wiadomość
  • MessageContent - Treść wiadomości
  • MessageTime - czas wysłania wiadomości.
    Co w niej wykonujemy? Po pierwsze dodajemy odebraną wiadomość do komponentu Memo1 (nasza log-lista), następnie do TmpEdit dajemy otrzymana wiadomość. Dlaczego? Iż jest jeden błąd. Gdybyśmy odróżniali wiadomość prosto z zmiennej MessageContent to by nasz program później nie odróżniał komend. Po prostu program nasz jest tak leniwy, ze myśli ze zmienna MessageContent się nie zmienia, i przy drugiej wysłanej wiadomości zmienna MessageContent jest równa pierwszej wiadomości, czyli się nie zmieniła.

W procedurze OnClick Buttonu 2 wpisz:

procedure TForm1.Button2Click(Sender: TObject);
begin
 hgg1.disconnect;
end;

Kliknij 2x w puste miejsce formy. Tak właśnie przejdziesz do kodu i wywołasz procedurę OnCreate. Wpisz do niej:

PlStatus.Color := clRed; // zmieniamy kolor panela na czerwony
PlStatus.Caption := 'Niepołączony';// i caption na Niepołączony
TmpEdit.Hide; // Ukrywamy nasz edit TmpEdit
Memo1.Clear; // czyścimy Memo

Ok. Teraz klikamy 2x na button 3 :

procedure TForm1.Button3Click(Sender: TObject);
var
  RowNo : Integer;
begin
Command.FindRow(Edit1.Text, RowNo);
   if  RowNo = -1 then
Command.InsertRow(Edit1.Text, Edit2.Text, true)
else
ShowMessage('Jest już taka komenda w rzędzie '+IntToStr( RowNo))
end;

Tutaj sprawdzamy czy już użytkownik dodał daną komendę do tabeli.

Przejdźmy jeszcze raz na formę i wywołajmy procedurę OnClose. Wpisz do niej:

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
      hgg1.disconnect;
end;

Rozłączamy się z serwerem gg podczas zamykania programu.

Teraz przejdźmy do komponentu ValueListEditor - Command. Przejdź do listy procedur (Events) i wybierz OnKeyDown. Uzupełnij kodem:

procedure TForm1.CommandKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if Integer(Key)=46  then
    begin
        if MessageBox(Handle,PChar('Czy napewno usunąć komendę '+Command.Strings[Command.Selection.Top -1]+' ?'),
            'Usuwanie', MB_YESNO + MB_ICONQUESTION) = IdYes then
              begin
                Command.DeleteRow(Command.Selection.Top);
              end;
 
      end;
end;

Posłuży nam do usuwania rzędu. To znaczy jak ktoś wybierze dowolny rząd i naciśnie klawisz delete, to zostanie usunięty.

Czas na zapisywanie ustawień programu. Co prawda wystarczy tylko zapisać to co jest w Command. Więc tak zróbmy.
Kliknij 2x na Button 4 :

procedure TForm1.Button4Click(Sender: TObject);
begin
SaveDialog1.FileName := 'GaduGaduBot';
if SaveDialog1.Execute then
begin
 Command.Strings.SaveToFile(SaveDialog1.FileName + '.ggb');
end;

Oraz w OnClick buttona 5 :

procedure TForm1.Button5Click(Sender: TObject);
begin
OpenDialog1.Filter :='GaduGadu Bot (*.ggb)|*.ggb';
if OpenDialog1.Execute then begin
Command.Strings.LoadFromFile(OpenDialog1.FileName);
end;
end;

Cały kod powinien wyglądać mniej więcej tak:

unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, HGG,
  StdCtrls, ExtCtrls, Grids, ValEdit;
 
type
  TForm1 = class(TForm)
    HGG1: THGG;
    Button1: TButton;
    PlStatus: TPanel;
    Button2: TButton;
    Memo1: TMemo;
    TmpEdit: TEdit;
    Label1: TLabel;
    Command: TValueListEditor;
    Edit1: TEdit;
    Edit2: TEdit;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    SaveDialog1: TSaveDialog;
    OpenDialog1: TOpenDialog;
    procedure HGG1Message(Sender: TObject; GGNumber: Integer;
      MessageContent: String; MessageTime: TDateTime);
    procedure Button1Click(Sender: TObject);
    procedure HGG1Connected(Sender: TObject);
    procedure HGG1Disconnected(Sender: TObject);
     procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure CommandKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  try
    hgg1.Number  := numer;
    hgg1.Password  := '*****';
    HGG1.Host := HGG1.GetServerAddress;
    hgg1.Status:=usAvailable;
    hgg1.connect;
  except
    ShowMessage('Wystąpił błąd');
    hgg1.Disconnect;
  end;
end;
 
procedure TForm1.HGG1Connected(Sender: TObject);
begin
  PlStatus.Color := clLime;
  PlStatus.Caption :='Połączony';
  hgg1.Description :='Bot Gadu-Gadu';
end;
 
procedure TForm1.HGG1Disconnected(Sender: TObject);
begin
  PlStatus.Color := clRed;
  PlStatus.Caption :='Niepołączony';
end;
 
procedure TForm1.Button2Click(Sender: TObject);
begin
 hgg1.disconnect;
end;
 
procedure TForm1.HGG1Message(Sender: TObject; GGNumber: Integer;
  MessageContent: String; MessageTime: TDateTime);
var
  Reply : string;
  Row : integer;
begin
 Memo1.Lines.Add('['+DateToStr(MessageTime)+']('+IntToStr(GGNumber)+') '+MessageContent);
 TmpEdit.Text := MessageContent;
    Command.FindRow(TmpEdit.Text,  Row);
 
 if  Row = -1 then
  Reply := 'Nie ma u nas takiej komendy' else
 begin
  Reply := Command.Values[Edit1.Text];
 end;
 
  HGG1.SendMessage(GGNumber, Reply, []);
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
PlStatus.Color := clRed;
PlStatus.Caption := 'Niepołączony';
TmpEdit.Hide;
Memo1.Clear;
end;
 
procedure TForm1.Button3Click(Sender: TObject);
var
  RowNo : Integer;
begin
Command.FindRow(Edit1.Text, RowNo);
   if  RowNo = -1 then
Command.InsertRow(Edit1.Text, Edit2.Text, true)
else
ShowMessage('Jest już taka komenda w rzędzie '+IntToStr( RowNo))
end;
 
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
      hgg1.disconnect;
end;
 
procedure TForm1.CommandKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if Integer(Key)=46  then
    begin
        if MessageBox(Handle,PChar('Czy napewno usunąć komendę '+Command.Strings[Command.Selection.Top -1]+' ?'),
            'Usuwanie', MB_YESNO + MB_ICONQUESTION) = IdYes then
              begin
                Command.DeleteRow(Command.Selection.Top);
              end;
 
      end;
end;
 
procedure TForm1.Button4Click(Sender: TObject);
begin
SaveDialog1.FileName := 'GaduGaduBot';
if SaveDialog1.Execute then
begin
 Command.Strings.SaveToFile(SaveDialog1.FileName + '.ggb');
end;
 
end;
 
procedure TForm1.Button5Click(Sender: TObject);
begin
OpenDialog1.Filter :='GaduGadu Bot (*.ggb)|*.ggb';
if OpenDialog1.Execute then begin
Command.Strings.LoadFromFile(OpenDialog1.FileName);
end;
end;
 
end.

Komponent THGG zawiera wiele, wiele więcej funkcji. Zapraszam do przeczytania dokumentacji, która jest dołączona razem z nim.

Załączniki


GGB.zip - Gotowy program z kodem źródłowym
THGG - http://members.chello.pl/w.redlowska/hakger/projthgg.htm
Mirror 2 http://download.4programmers.net/THGG.zip


Bordeux
http://www.bordeux.net

50 komentarzy

ficiek: Czytaj dokładnie!

Co w niej wykonujemy? Po pierwsze dodajemy odebraną wiadomość do komponentu Memo1 (nasza log-lista), następnie do TmpEdit dajemy otrzymana wiadomość. Dlaczego? Iż jest jeden błąd. Gdybyśmy odróżniali wiadomość prosto z zmiennej MessageContent to by nasz program później nie odróżniał komend. Po prostu program nasz jest tak leniwy, ze myśli ze zmienna MessageContent się nie zmienia, i przy drugiej wysłanej wiadomości zmienna MessageContent jest równa pierwszej wiadomości, czyli się nie zmieniła.

hej,
u mnie problem wygląda następująco...po zrobieniu programu na bazie powyższego artykułu bot ładnie łączy się z serwerem, ustawia opis, jednakże po wysłaniu jakiejkolwiek wiadomości nic się nie dzieje (nie zapisuje do logów, nie odpowiada...zero reakcji). W akcie desperacji prze kleiłem kod z z artykułu (zmieniając niezbędne dane) ale działo się to samo...miał ktoś może taki problem lub wie czemu tak się może dziać ? Z góry dzięki za pomoc. Pozdrawiam

Procedura OnMessage powinna wyglądać tak:

procedure TForm1.HGG1Message(Sender: TObject; GGNumber: Integer;
  MessageContent: String; MessageTime: TDateTime);
var
  Reply : string;
  Row : integer;
begin
 Memo1.Lines.Add('['+DateToStr(MessageTime)+']('+IntToStr(GGNumber)+') '+MessageContent);
 TmpEdit.Text := MessageContent;
    Command.FindRow(TmpEdit.Text,  Row);
 
 if  Row = -1 then
  Reply := 'Nie ma u nas takiej komendy' else
 begin
  Reply := Command.Values[Command.Keys[Row]];
 end;
 
  HGG1.SendMessage(GGNumber, Reply, []);
end;

Merytorycznie tez nie bardzo, tekst procz przedstawienia jak sie uzywa komponentu do GG nie robi praktycznie nic wiecej (pokazuje co to if?), wiec imo zamiast tego powinien byc jakis kurs dotyczacy tego komponentu (tak bardziej abstrakcyjnie) niz to. Jeszcze jednego sie doczepie:

"Teraz wywołaj procedure OnCreate formularza"

Procedure wywoluje sie piszac w kodzie procedura();, wiec to zdanie jest troche mylace, ladniej by bylo "wypelnij zdarzenie OnCreate" czy cos podobnego.

Może mi ktoś zrobić przyszykowaną instalkę HGG?

Wszystko chodzi ładnie, pięknie :-) tylko: jak zrobić żeby Bot sam sie uczył od rozmócy (np. wpisuje rozmówca < edit >Banan=Owoc)

ficiek: bo THGG już nie działa poprawnie. To stary komponent a protokół się trochę zmienił.

Nie o to chodzi pierwszej wiadomości też nie łapie. Dopiero jak przyjdzie kilka to odpowie i potem wszystko pięknie działa.

@edit Jeszcze jedno. W moim programie wszystko działa już dobrze, ale po zapisaniu i wczytaniu do ValueListEditora odczytuje pustą komendę, działa tylko wtedy jak od nowa się wprowadzi. Jak się wczyta po ponownym uruchomieniu to zwraca czy co tam robi ''.

fajnie, ale dlaczego mój własny program który napisałem nie łapie pierwszych 3 - 9 wiadomości? Spytam tu żeby nie robić zamieszania.

U mnie tak jak u kolegi niżej (tzn nie odpisuje bot) :(

Usun delphi i jego wszyskie pliki (bo nie usuwa wsztskich), I zainstaluj. Pliki indyka daj tez do folderu z delphi. I zainstaluj. Oczywiscie to dziala na indy 9

tak, tylko ze reinstal delphi i indy robiłem kilka razy (porządki na dysku) i zawsze to samo

jak kliknę "run" i potem zamknę aplikacją to wyskakuje mi:
source file not found: IdTCPConnection.pas

Jak znajdę tą ścieżkę to wywala mi kolejne błędy. o co chodzi?

Masz "zwalone" indy. Zrob reinstalacje indy, lub delphi

No tak. Można to też ominąć w inny sposób:

 if  Command.Values[Edit1.Text] = null then
  Reply := 'Nie ma u nas takiej komendy' else
 begin
  Reply := Command.Values[Edit1.Text];
 end;
 

, bez szukania , ale juz po fakcie o tym sie juz domyśliłem, jak juz wysłałem :<

A można z Delphi usunąć THGG?

Bo odkąd je zainstalowałem nie mogę użyć żadnego komponentu Indy9 - jak próbuję przeciągnąć jakiś na formę o z palet ginie większość tych komponentów... :/
Można coś z tym zrobić?

Na reszcie się ktoś za to zabrał. Gratki bordeux!

Pozostaje nam teraz oczekiwać na nowe boty spamujące via GG....

cytat:
W inspektorze obiektów komponentu THGG zmień wartość NUMBER na numer twojego gg, a w pole PASSWORD wpisz do niego hasło

pytanie:
skąd wziąć ten NUMBER i PASSWORD ?

Da się jakoś bez konieczności instalowania tego dziadostwa o nazwie GaduGadu?

U mnie po pomyślnym połączeniu i wywołaniu zdarzenia OnConnected po 3 sekundach wywołuje się OnDisconnected. Nie wiem czy to błąd komponentu, czy rzeczywiste zdarzenie, w każdym razie nie da się zalogować z podanym numerem gg.

johnny: nie mozna :(

mam pytanie jak zapomoca tego komponentu lub innego wyslac plik do kogos na gg

ptr20 u mnie jest w zakładce: HAKGERSoft Components
Pozdrawiam

Mam pytanie zaistalowałem komonent thgg w jakiej zakładce się on znajduje ?

Aha. po zmianie serwa przez gg to jesli wyslesz 2 razy wiadomosc do bota, to pozniej on nie reaguje...
Rozwiazanie http://4programmers.net/Forum/viewtopic.php?id=112624

robciu663:
HGG1.Description:='Tutaj jakis opis';


UWAGA! UWAGA! UWAGA!


Od niedawna Gadu-Gadu zmieniło swe adresy ip serwerów. W tym celu w komponencie hgg w inspektorze zmieniamy host na:
217.17.45.147
lub dac
HGG1.Host := HGG1.GetServerAddress;
I powinni teraz wszystko śmigać. Też radze dać time out na połączenie z serwerem gg.


Zmiana nic nie dała :/
Dalej to samo...
tym razem pokazuje Field Form1.HGG1Message does not have a correspodning component. Remove the declaration ?
:P

a ja mam inny problem podczas instalacji thgg wyskakuje mi błąd że mam niezadeklarowane host i pragma w liniach 1501 i 1505 i nei bardzo wiem co mam z tym zrobić

Po angielsku nie mówie, ale chyba zamiast TForm1.HGG1 to TForm1.HGG1Message

Field Form1.HGG1 does not have a correspodning component. Remove the declaration ? :/
Wtf ?

Usunąłeś kod źródłowy jakiegoś wcześniejszego komponentu. Radze re instalacje delphi

a ja mam klopoty z doinstalowaniem tego komponentu HGG. przy instalacji wyswietla mi sie 'Required package 'rtl' not found' ... czy jeszcze czegos mi brakuje? =|

Działa zapomniełem wstawić komponent HGG :0 przepraszam za kłopot :) Jak co to Napisze jak trzeba zrobić by działało, bo autor nie napisał :) :

  1. Ściągnąć INDY 9 najlepiej z strony http://www.atozed.com/indy/plus/files.en.aspx
  2. Ściągnąć HGG.
  3. Zainstalować Indy 9 (instaluje sie jak każdy inny program w Windowsie.
  4. Zainastlować HGG (z poziomu Delphi)
  5. Wstawić komponent HGG.
  6. Pisać Bot'a

Napisałem instrukcje by mój problem się nie powtórzył.

Zainstalowałem Indy9 i diała HGG lecz z kodem jest problem. Nie ma funkcji Number tylko sbGnumber.

Już chyba wiem na czym problem polega. Ja zainstalowałem Indy 10, trzeba indy 9. Sróbuje i napisze jak mi poszło

Może usunąłeś kody źródłowe wcześniej instalowanych komponentów. Najlepiej zainstalować od nowa delphi. Może wysłać projekt?

I znowu problem z THGG. Instaluje go lecz wyskakuje tysiące błędów. NIe wiem czy źle instaluje czy co?? NIe pisze błędów bo za dużo ich.

A o to ty sciągłeś cały kod. Trzeba było usunąć parę z uses, poniewaz na poczatku indy dodaje swoje komonenty..

Dzięki zainstalowałem te indy :) Ściągnołem jakąś wersje co się sama instaluje :)

Dzięki spróbuje. P.S ja nigdy indy nie instalowałem :)

bardzo fajny programik, prosto napisany. trzeba wyprobowac <:

Ale mi chodziło o bot gg. Jeśli komuś zalezy na kursie tego komonentu to niech poszuka w necie.

Merytorycznie wartościowe, ale język okropny - jak mejl do kumpla, nie wpis w portalu pretendującym do składnicy wiedzy.

bordeux, nieźle :).

Czy wie ktoś jak zrobić aby bot archiwizował wiadomości ?

terafli : a jaki jest problem by zrobić archiwum???
Operacje
Czytasz i rozumiesz... Zapisujesz okno rozmów do jakiegoś pliku i po sprawie

Jeszcze pytanie: jak dać opis w bocie gg ? Też mam komponent HGG, jak coś...

Masz kłopot z indy. Tez tak miałem, ale chyba jeszcze raz zainstalowałem indy.

Ja mam błąd że nie znajduje Mi IdBaseComponent.dcu. co zrobić ???