Występujący błąd w programie - Debuger Error

0

Witam was, mam problem piszę aplikację bazodanową z obsługą allegro i często występuję błąd, poniżej podają linki do screenów:

http://www.lcdk.pl/Schowek01.jpg
http://www.lcdk.pl/Schowek02.jpg
http://www.lcdk.pl/Schowek03.jpg
http://www.lcdk.pl/Schowek04.jpg
http://www.lcdk.pl/Schowek05.jpg
http://www.lcdk.pl/Schowek06.jpg
http://www.lcdk.pl/Schowek07.jpg
http://www.lcdk.pl/Schowek08.jpg
http://www.lcdk.pl/Schowek09.jpg
http://www.lcdk.pl/Schowek10.jpg
http://www.lcdk.pl/Schowek11.jpg
http://www.lcdk.pl/Schowek12.jpg

Największy problem w tym że procedury które powodują błąd raz wykonują się poprawnie a raz wywalają błąd. Drugi problem to to że delphi nie pokazuje podczas której instrukcji powstał błąd, naciśnięcie F9 (czyli dalsze wykonywanie programu wywala ciągle ten sam błąd, muszę zakończyć aplikację a czasami zamknąć Delphi. (Włączenie śledzenia wystąpienia wyjątku nic nie daje).

Wydaję mi się że czasami błąd występuje w momencie gdy następuje powrót z procedury.

Jak zabrać się do znalezienia w kodzie błędu? Czy to może być coś związanego z pamiecią?

0

Czy to może być coś związanego z pamiecią?

To musi być coś związanego z pamięcią.

Największy problem w tym że procedury które powodują błąd raz wykonują się poprawnie a raz wywalają błąd

jeżeli przy tych samych danych: wątki bez synchronizacji?
jeżeli przy innych to obstawiam wyciek pamięci lub skończenie się stosu.

0

na 99% próbujesz używać obiektów jeszcze nie stworzonych lub już zwolnionych. Zamiast F9 wciśnij F7/F8 i zobacz, gdzie wylądujesz

0

na 99% próbujesz używać obiektów jeszcze nie stworzonych lub już zwolnionych.

A to by nie dało błędu nr. 210 ? Tak przynajmniej w FPC jest że wyskakuje 210 jak się odwołujesz do niestworzonego obiektu (ofc przy debuggowaniu załączonym).

0

Błędy zaczynają sie pojawiać po użyciu typu TWebApi która napisałem i mam jedno pytanie. W pierwszej kolejności wstawię uproszczony kod:

Type TWebApi = Class
     private
       HTTPRIO: THTTPRIO;
     public
       constructor Create;
       destructor Destroy;
     End;


constructor TWebApi.Create;
begin
 vLogin := False;
 vCreate := True;
 HTTPRIO := THTTPRIO.Create(Application);
 Try
  HTTPRIO.WSDLLocation := 'http://webapi.allegro.pl/uploader.php?wsdl';
  HTTPRIO.Service := 'AllegroWebApiService';
  HTTPRIO.Port := 'AllegroWebApiPort';
 Except
  vCreate := False;
 End;
end;


destructor TWebApi.Destroy;
begin
  HTTPRIO.Free;
end;

Tworzenie zmiennej po przez:

WebApi := TWebApi.Create;

I teraz czy instrukcja jest poprawna chodzi mi dokładnie o Application?

HTTPRIO := THTTPRIO.Create(Application);

0

I teraz czy instrukcja jest poprawna chodzi mi dokładnie o Application?

Nigdy jakoś nie zagłębiałem w te mechanizmy dzieci, ale ja bym dał dla świętego spokoju NIL.

0

Jak dam nil to potem procedura np:

Function TWebApi.PobierzLiczbeAukcji(typ : WideString): Boolean;
begin
  Result := True;
  Try
    vIloscPobranychAukcji := (Httprio as AllegroWebApiPortType).doMyAccountItemsCount(OdpSession,Typ,0);
  Except
    Result := False;
    vIloscPobranychAukcji := 0;
  End;
  sleep(1);
End;

Jest wykonywana tak że wykonuje to co pod Try a potem nagle wychodzi z funkcji, tzn nie wykonuje ani tego co pod Except ani Sleep(1);

Dziwne???

0

jeśli sam niszczysz tworzony obiekt to powinien tam być nil

0

Chyba znalazłem w czym tkwi problem teraz Konstruktor wygląda tak:

constructor TWebApi.Create;
begin
 vLogin := False;
 vCreate := True;
 HTTPRIO := THTTPRIO.Create(nil);
 Try
  HTTPRIO.WSDLLocation := 'http://webapi.allegro.pl/uploader.php?wsdl';
  HTTPRIO.Service := 'AllegroWebApiService';
  HTTPRIO.Port := 'AllegroWebApiPort';
 Except
  vCreate := False;
  HTTPRIO.Free;
 End;
end;

Procedura logowania do allegro:

Function TWebApi.LoginEnc(User,Password,Key : WideString): Boolean;
begin
  Result := True;
  vLogin := True;
  Password := Base64EncodeStr(GetStringHash(Password));
  Try
   (Httprio as AllegroWebApiPortType).doQuerySysStatus(1,1,Key,OdpInfo,OdpVersion);
   (Httprio as AllegroWebApiPortType).doLoginEnc(User,Password,1,Key,OdpVersion,OdpSession,OdpOffset,OdpTime);
  Except
    vLogin := False;
    Result := False;
  End;
end;

I teraz tak stawiam button na formie i wpisuję...

procedure TForm1.sButton1Click(Sender: TObject);
begin
  WebApi.LoginEnc('nick','haslo','klucz');
end;

Nacisnę pierwszy raz logowanie następuje poprawnie.
Naciskam raz jeszcze i otrzymuję błąd w instrukcji:
**
(Httprio as AllegroWebApiPortType)**

Treść błędu: "EAccessViolation = Access Violation at adress 00000001"

Wygląda na to że HTTPRIO się rozpada ale dlaczego? Gdy tworzę HTTPPRIO po przez (application) zamiast (nil) wszystko na tym etapie jest dobrze ale błędy które powstają potem mogą być spowodowane własnie tez tym HTTPRIO.

0

W Create masz HTTPRIO potem magicznie nazywasz to Httprio - zdecyduj się.

vCreate := True; - co to jest vCreate? Po co ci to, to bez sensu.

 Except
  vCreate := False;
  HTTPRIO.Free;
 End;

Bez sensu, skoro nie działa to nie działa, to pozwól żeby wywaliło cię poza TWebApi które zależy od HTTPRIO, skoro nie działa to nie działa, a nie ustawiasz sobie jakieś pole... Od tego są wyjątki żeby z nich korzystać.

Try
  HTTPRIO.WSDLLocation := 'http://webapi.allegro.pl/uploader.php?wsdl';
  HTTPRIO.Service := 'AllegroWebApiService';
  HTTPRIO.Port := 'AllegroWebApiPort';
 Except

Czemu według ciebie to może się nie udać? Przecież skoro obiekt jest stworzony poprawnie, to pola też powinny dać się ustawić, nie wydaje mi się żeby wymagało to wyszczególnionego przypadku...

błąd jest w instrukcji (Httprio as AllegroWebApiPortType) czyli rzutowanie się nie udaje. Czemu? Bo w create działa źle, ale ty nie sprawdzasz statusu vCreate tylko wyciszasz wyjątek i udajesz że jest ok.
Co z tego wynika? Że nie udało się stworzyć za drugim razem klasy, więc badaj tamten wyjątek. Poczytaj dokumentacje, demoski poprzeglądaj i przerób kod żeby było ok (z tego co widzę to to Indy więc ci nie pomogę).

0

Poprawiłem te kilka drobnych błędów i przerobiłem troszkę kod teraz Konstruktor wygląda tak

Type TWebApi = Class
     private
       HTTPRIO: THTTPRIO;
       AW : AllegroWebApiPortType;
     public
       constructor Create;
       destructor Destroy; // override;
     End;


constructor TWebApi.Create;
begin
 vLogin := False;
 Httprio := Thttprio.Create(nil);
 Httprio.WSDLLocation := 'http://webapi.allegro.pl/uploader.php?wsdl';
 Httprio.Service := 'AllegroWebApiService';
 Httprio.Port := 'AllegroWebApiPort';
 AW := (Httprio as AllegroWebApiPortType);
end;

I generalnie początkowo się ucieszyłem bo logowanie i odczyt danych z allegro nastąpił poprawnie. Ale :)
Przy wyłączeniu programu gdy program natrafia na kod Httprio.Free wywala błąd. Po troszkę dłuższym sprawdzaniu i tak pojawiają się te wcześniejsze błędy. Zauważyłem także że po odczycie danych z allegro czy tam logowaniu (użycie TWebApi). Mogę potem w programie przejść do innej zakładki, zupełnie innego kodu gdzie są operacje np na MySql czy na plikach INI (nic związanego ze zmienna WebApi : TWebApi i często tutaj wywala też te wcześniejsze błędy czyli access violation.

Wszystko zaczyna się sypać po użyciu TWebApi. Może utworzyć wskaźnik i zarezerwować dużą ilość pamięci???

Próbowałem także postawić kontrolkę HTTPrio1 na formie ale są te same błędy. Chyba mnie to przerasta.

0

Moja propozycja: Pokaż Destruktor TWebApi i czym jest AllegroWebApiPortType.

Mogę potem w programie przejść do innej zakładki, zupełnie innego kodu gdzie są operacje np na MySql czy na plikach INI (nic związanego ze zmienna WebApi : TWebApi i często tutaj wywala też te wcześniejsze błędy czyli access violation.

Jedyne co mi się kojarzy z takim problemem to błędy IO lub zarządzania pamięci tablic dynamicznych (ale takiego kodu tutaj nie widzę). Generalnie te problemy należą do bardzo trudnych bo mogą się ukrywać przez długi czas, ale poza tą wiadomością nie zakładam że to tego typu błędy.

Wszystko zaczyna się sypać po użyciu TWebApi. Może utworzyć wskaźnik i zarezerwować dużą ilość pamięci???

Ta, i jeszcze jakieś inne sztuczki magiczki? :P

Jeszcze mi wytłumacz:

 Httprio := Thttprio.Create(nil);
 AW := (Httprio as AllegroWebApiPortType);

Jaki to ma sens? Bo jeżeli THttpPrio jest bazowane na AllegroWebApiPortType to rzutowanie nie jest potrzebne a w innym przypadku jest ono błędne. Tzn. najprawdopodobniej nie rozumiesz zasad dziedziczenia / usiłujesz zrobić magię.

0

Poniżej linki do obu unitów (Delphi 7)

http://www.lcdk.pl/uploader.pas //To zostało wygenerowane przez WSDL Importer
http://www.lcdk.pl/uwebapi.pas

Wykonuje tylko te dwie procedury i od tego momentu mamy Access Violation

WebApi.LoginEnc(L,P,K);
WebApi.PobierzOpisyWszystkichAukcji('sell');

0

zamień
Httprio := Thttprio.Create(nil);
na
Httprio := Thttprio.Create(Application);
i zaremuj w destruktorze HTTPRIO.Free;
Jaką masz wersję delphi? Jak < 2k6 to dodaj sobie fastmm i odblokuj raportowanie wycieków pamięci, jak 2k6 albo nowsze to http://delphi.about.com/od/adptips2006/qt/memory_leak.htm i zobacz czy masz wyciek pamięci czy nie.

BTW widziałeś ta funkcję?

function GetAllegroWebApiPortType(UseWSDL: Boolean; Addr: string; HTTPRIO: THTTPRIO): AllegroWebApiPortType;
const
  defWSDL = 'D:\Delphi\SSL Allegro\uploader.php';
  defURL  = 'http://webapi.allegro.pl/uploader.php';
  defSvc  = 'AllegroWebApiService';
  defPrt  = 'AllegroWebApiPort';
var
  RIO: THTTPRIO;
begin
  Result := nil;
  if (Addr = '') then
  begin
    if UseWSDL then
      Addr := defWSDL
    else
      Addr := defURL;
  end;
  if HTTPRIO = nil then
    RIO := THTTPRIO.Create(nil)
  else
    RIO := HTTPRIO;
  try
    Result := (RIO as AllegroWebApiPortType);
    if UseWSDL then
    begin
      RIO.WSDLLocation := Addr;
      RIO.Service := defSvc;
      RIO.Port := defPrt;
    end else
      RIO.URL := Addr;
  finally
    if (Result = nil) and (HTTPRIO = nil) then
      RIO.Free;
  end;
end;
0

Poniżej przedstawiam loga z FastMM

Żadne wycieki nie następują gdy tylko wykonane są instrukcje w konstruktorze i destruktorze. Natomiast gdy wykonam procedurę logowania do allegro która zostaje wykonana poprawnie (teoretycznie) i zamknę program otrzymuję błąd w destruktorze. Oto link http://www.lcdk.pl/memory.txt

0

no to Ci pisze pięknie, że próbujesz wywołać metodę zwolnionego obiektu

0

No tak ale dlaczego, czy rzutowanie może zwolnić obiekt?

0

Log jest w przypadku tworzenia THttprio z wartością NIL jeszcze sprawdzę jak w przypadku Application

0

Po kilku dniach ciągłego dłubania poprawiłam wszystkie wcześniejsze błędy i teraz nie mam żadnych wycieków. Teraz zabrałem sie za TWebApi i:

var
   Temp : ArrayOfMyAccountList2;
begin 
  Temp := (Httprio as AllegroWebApiPortType).doMyAccount2(OdpSession,Typ,X,I,25);
End;      

Ta procedura rezerwuje pamięć i co wykonania zabiera pamięć i powoduje wycieki. Niewiem jak zwolnić pamięć? Dodam że nie chodzi o zwolnienie pamieci zmiennej Temp.

0

Po kilku dniach odpoczynku zaczełem dalej z tym walczyć.

var
  Temp : ArrayOfMyAccountList2;
begin
  Temp := (Httprio as AllegroWebApiPortType).doMyAccount2(OdpSession,Typ,X,I,25);
end;

Po wykonaniu tej procedury mam wyciek MyAccountStruct2 x 25 który nie pochodzi od zmiennej Temp.

Wykonianie tego:

var
  Temp : ArrayOfMyAccountList2;
begin
  (Httprio as AllegroWebApiPortType).doMyAccount2(OdpSession,Typ,X,I,25)[0].Free;
end;

Powoduje wyciek już tylko MyAccountStruct2 x 24 - Logiczne

Ale wykonianie czegoś takiego:

var
  Temp : ArrayOfMyAccountList2;
begin
  Temp := (Httprio as AllegroWebApiPortType).doMyAccount2(OdpSession,Typ,X,I,25);
              (Httprio as AllegroWebApiPortType).doMyAccount2(OdpSession,Typ,X,I,25)[0].Free;
end;

Powoduje wyciek MyAccountStruct2 x 49 - Dzieje sie to dlatego ze nie odnoszę się do zwalniania pierwszego rekordu dla pierwszej proceduru.

I tu pytanie dla mądrzejszego programisty ode mnie. Jak po przypisaniu do zmiennej temp danych zwolnić 25 rekordow MyAccountStruct2?

0
var
  Temp : ArrayOfMyAccountList2;
  i: Integer;
begin
  Temp := (Httprio as AllegroWebApiPortType).doMyAccount2(OdpSession,Typ,X,I,25);
  for i := 0 to Length(Temp) - 1 do
    Temp[i].Free;            
end;

ale to tylko teoria bo pojęcia nie mam czym jest ArrayOfMyAccountList2 i co w nim siedzi

0

Tak już próbowałem ale rozwiązałem ten problem jeszcze inaczej. Teraz niemam żadnych wycieków. A zrobiłem to tak:

Var
  AP : AllegroWebApiPortType; 
constructor TWebApi.Create;
begin
  AP := GetAllegroWebApiPortType(True,'',nil);  //Procedura która wygenerowała się automatycznie w delphi "Import WSDL"
end;

W sumie było by wszystko ok gdyby nie inny kolejny problem. Otóż, Oto kod:

Type TWebApi = Class
     private
       AP : AllegroWebApiPortType;
       OdpInfo : WideString;
       OdpVersion: Int64;
       OdpTime : Int64;
       OdpSession : WideString;
       OdpOffset : Int64;
       vIloscPobranychAukcji : Integer;
       vTablicaAukcji: ArrayOfMyAccountList2;
       vNumeryAukcji : ArrayOfItemsId;
       vOpisyAukcji : Array of String;
       vDaneTowaru : ArrayOfDaneTowaru;
       vMax : integer;
       vProgress : Integer;
       vD1 : ItemInfo;
       Function GetStringHash(Source: Widestring): string;
       Function PobierzNumeryAukcji(typ: String):Boolean;
       Function PobierzAukcje(typ: String): Boolean;
       Procedure TranslateTextToKod(Text: String; var Kod,Kodd : String);
     public
       constructor Create;
       destructor Destroy;  override;
       Property TItemInfo : ItemInfo read vD1;
       Property ProgressMax : Integer read vIloscPobranychAukcji;
       Property Progress : Integer read vProgress;
       Property DaneTowaru : ArrayOfDaneTowaru read vDaneTowaru;
       //Property TablicaOpisow : ArrayOfStructItemInfoList read vTablicaOpisow;
       Property LiczbaPobranychAukcji : Integer read vIloscPobranychAukcji;
       Property NumeryAukcji : ArrayOfItemsId read vNumeryAukcji;
       Function PobierzOpisAukcji(NumerAukcji: Int64; var Opis: WideString): Boolean;
       Function LoginEnc(User,Password,Key : WideString): Boolean;
       Function PobierzLiczbeAukcji(typ : WideString): Integer;
       Function PobierzOpisyWszystkichAukcji(Typ : WideString) : Boolean;
     End;

Wykonuję 3 ostatnie funkcje wszystko jest ok działa, wycieki sie nie pojawiają. W zmiennej vIloscPobranychAukcji jest liczba aukcji np 300. W programie głównym odnoszę się tak jak wcześniej np:

For X := 1 to WebApi.LiczbaPobranychAukcji do
(...)

Kilka wykonan jest ok ale za chwile np z WebApi.LiczbaPobranychAukcji otrzymuję wartość -23232432 a po najechaniu kursorem na WebApi otrzymuję dymek z podpowiedzią: Inaccessible Value. Tak jakby WebApi sam sie niszczył.
Czy klasa ma określoną żywotność?

0

Wszystko już się wyjaśniło. Wdarło mi się do kodu dwa razy WebApi.Free.

**Dziękuje wam wszystkim za pomoc bo naprawdę mi pomogliście. **

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