Delphi zdarzenie raise

Delphi zdarzenie raise
AB
  • Rejestracja:ponad 4 lata
  • Ostatnio:4 miesiące
  • Postów:34
0

Witam,

Dziś mam takie pytanie. Chociaż jestem dawno wiem, że wszelkiego rodzaju "raise" najlepiej jest obsłużyć poprzez try.... except end, to czasami mam do czynienia z bibliotekami zewnętrznymi, które również mają zdarzenie "raise" i tego poprzez try except nie da się przechwycić. A jeżeli się mylę to proszę mnie poprawić.
Ja chcę osiągnąć taki efekt - przechwycić zdarzenie raise - i schować to dla swojej wiedzy i nie pokazywać komunikatu w okienku (jakimkolwiek).

Pozdrawiam
Andrzej.

Patryk27
Moderator
  • Rejestracja:ponad 17 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Wrocław
  • Postów:13042
3

Powinno się dać chwycić - być może biblioteka rzuca np. ExceptionA, a Ty masz catch na ExceptionB?

Robiąc Except on Exception do powinieneś być w stanie wychwycić wszystkie możliwe wyjątki.


AB
A czy nie napisałem w treści w pierwszym zdaniu, że znam try .... except ... end ?
Patryk27
Możesz mieć try except on ExceptionB, które nie złapałoby Ci raise ExceptionA.
WL
  • Rejestracja:około 21 lat
  • Ostatnio:6 dni
  • Postów:1083
2
Andrzej Boczko napisał(a):

Witam,

Dziś mam takie pytanie. Chociaż jestem dawno wiem, że wszelkiego rodzaju "raise" najlepiej jest obsłużyć poprzez try.... except end, to czasami mam do czynienia z bibliotekami zewnętrznymi, które również mają zdarzenie "raise" i tego poprzez try except nie da się przechwycić. A jeżeli się mylę to proszę mnie poprawić.

Poprawiam Cię, nie masz racji.
Co do zasady możesz przechwycić dowolny wyjątek i go obsłużyć, poza Access Violation.

Problemem jest to, że mało kto potrafi poprawnie zarządzać wyjątkami.
I nie tylko w Delphi - programiści... 😁

Ja chcę osiągnąć taki efekt - przechwycić zdarzenie raise - i schować to dla swojej wiedzy i nie pokazywać komunikatu w okienku (jakimkolwiek).

To Ci nie pomogę, ponieważ to jest jedna z największych głupot i do tego ręki nie przyłożę.
Zdobądź książkę "Coding in Delphi" Nicka Hodges'a - pierwszy rozdział traktuje o wyjątkach - spis treści:

Kopiuj
1.3. Jak nie korzystać z wyjątków (18)
 Nie "połykaj" wyjątków (18)
 Nie przechwytuj wyjątków bezkrytycznie (18)
 Nie nadużywaj wyjątków (19)
 Nie używaj wyjątków jako podstawowego sposobu sygnalizacyjnego (19)

https://helion.pl/ksiazki/programowanie-w-jezyku-delphi-nick-hodges,prodel.htm#format/e

woolfik
klient: "Witam, aplikacja nie działa" support: "Czy pojawia się jakiś komunikat" klient: "nie klikam i nic" support: "Czy może Pan otworzyć plik z logami" klient: "nie da się" support: "tzn?" klient: "klikam dwa razy i komputer się wiesza" support: "jaki jest rozmiar pliku?" klient: "70 GB" kurtyna - sytuacja z życia wzięta :)
AB
Pierwszy rozdział o wyjątkach mówi o try ... except .. end w jakiejkolwiek formie...
AB
  • Rejestracja:ponad 4 lata
  • Ostatnio:4 miesiące
  • Postów:34
0

Tu mi nie chodzi o standardowe metody. Patrząc w logikę aplikacji: każdy blok:

Kopiuj
try
...
except
... 
end;

ma przechwycenie,
ale gdy jest mowa o takich sytuacjach

Kopiuj
try
...
call from dll_lib_procedure
...
except
...
end; 

A wewnątrz dll_lib_procedure jest wyjątek raise - to nie zawsze to chwyci. Access Violation to jest błąd krytyczny tego nie da się przechwycić jeżeli "punkt" sięga do pustego bloku obiektu,...

edytowany 1x, ostatnio: flowCRANE
woolfik
  • Rejestracja:ponad 17 lat
  • Ostatnio:dzień
  • Postów:1597
0
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 5 godzin
  • Lokalizacja:Tuchów
  • Postów:12171
1
wloochacz napisał(a):

Co do zasady możesz przechwycić dowolny wyjątek i go obsłużyć, poza Access Violation.

Jak to nie da się złapać Access Violation?

Chyba że w Delphi się nie da, ale dla FPC to taki sam wyjątek jak każdy inny — klasa EAccessViolation, komunikat Access violation. Można go normalnie przechwycić i obsłużyć, można go też olać (zjeść) i utrzymać przepływ sterowania bez zmian. Choć zjadanie wyjątków to raczej nie jest dobry pomysł.

Jeśli czegoś nie wiem to napisz coś więcej.


Andrzej Boczko napisał(a):

A wewnątrz dll_lib_procedure jest wyjątek raise - to nie zawsze to chwyci. Access Violation to jest błąd krytyczny tego nie da się przechwycić jeżeli "punkt" sięga do pustego bloku obiektu,...

Być może w przypadku DLL jest inaczej, być może w Delphi jest inaczej niż we Free Pascalu (choć wątpię), ale wyjątek EAccessViolation, jeśli jest generowany w przypadku pustej (nilowanej) referencji obiektu, może być i powinien być obsługiwany w sposób standardowy. Sprawdziłem taki przykład:

Kopiuj
var
  List: TStringList = nil;
begin
  try
    List.Add('foo');
  except
    on E: Exception do
      Write('"', E.ClassName, '", "',  E.Message, '"');
  end;

Działa to wedle oczekiwań, na wyjściu dostaję to:

Kopiuj
"EAccessViolation", "Access violation"

Ale znów – no chyba że Delphi działa inaczej lub kod wołany z DLL działa w inny sposób od nieimportowanego (jeśli o mechanizm wyjątków chodzi). W każdym razie, dorzuć sobie jakięs logowanie, tak aby widzieć jakie wyjątki są generowane i jakie otrzymywane są w bloku try except, tak aby się upewnić, że one faktycznie są rzucane i że (jak pisałeś) czasami nie są poprawnie obsługiwane.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 4x, ostatnio: flowCRANE
vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
0

Łapanie exception przy pomocy sprawdzenia klasy może się nie udać jeśli exception pochodzi z DLLki (osobny runtime).
Dotyczy to zarówno C++ jak i Delphi.
https://www.ostack.cn/?qa=1081020/

flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 5 godzin
  • Lokalizacja:Tuchów
  • Postów:12171
0

Ciekawe czy to chodzi o wszystkie wyjątki, czy tylko te, które nie znajdują się w runtimie (jakieś własne).
Nowa wiedza — fajnie. ;)


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 2x, ostatnio: flowCRANE
vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
1
furious programming napisał(a):

Ciekawe czy to chodzi o wszystkie wyjątki, czy tylko te, które nie znajdują się w runtimie (jakieś własne).

Z tego co pamiętam w Delphi masz kilka rodzajów wyjątków:
a) natywne - zwykła obsługa
b) systemowe SEH - nad tym odstawia się chyba jakieś gusła
c) z innych runtime'ów - np. z C++, FPC czy Pythona w DLL
d) AV - też mi się kojarzy że jest nieprzechwytywalne w sposób normalny (może na sposób SEH), ale narzędzia typu EurekaLog powinny dać radę

flowCRANE
Ok, dzięki za informacje.
GS
  • Rejestracja:ponad 14 lat
  • Ostatnio:4 dni
0

@Andrzej Boczko:

Access Violation to jest błąd krytyczny tego nie da się przechwycić jeżeli "punkt" sięga do pustego bloku obiektu,...

@wloochacz

Co do zasady możesz przechwycić dowolny wyjątek i go obsłużyć, poza Access Violation.

Nie wiem skąd taka teza ?
Access Violation w delphi również da się przechwycić

@furious programming
Twój przykład w Delphi podobnie jak FPC przechwytuje wyjątek

edytowany 4x, ostatnio: grzegorz_so
obscurity
może chodziło o EStackOverflow, w wielu innych językach nie da się go złapać, podejrzewam że w delphi też
AB
  • Rejestracja:ponad 4 lata
  • Ostatnio:4 miesiące
  • Postów:34
0

Hm. Wszyscy macie swoją rację. Ja nie twierdzę, że nie da się (chociaż same Access Violations), zwykle nie miałem - jak miałem - to wiedziałem, że coś nie tak z lokalizacją obiektów (albo kompilacją) i zwykle po poprawkach ten problem znikał. Mam jeden przypadek gdzie pomimo, iż jest w kodzie (delphi), w bibliotece - komenda raise i to jest przechwycone (nieaktywne). Inne miejsce tego samego systemu "reaguje" na wystąpienie raise. Pisząc na grupie myślałem, że pomimo iż w delphi piszę od ponad 20lat, to jednak czegoś nie wiem. Nie ma ludzi doskonałych.

Natomiast sprawa wygląda następująco:

Dowolny wyjątek, prawie zawsze da się przechwycić i ja to wiem. Są drobne wyjątki problemów gdzie tego nie da się zrobić ale każdy kto programuje w Delphi wie o co chodzi.
a same użycie sekwencji :

Kopiuj
try
except
end

powoduje ominięcie pewnego bloku wykonania, odpowiedzialnego za pewną grupę czynności. Ominięcie - czyli niewykonanie. A tu nie o to chodzi. Chodzi o dezaktywację "polecenia RAISE".

Na początku swojego wątku wyraźnie zaznaczyłem, że wiem o tej sekwencji try ... except end i jaki chcę osiągnąć efekt. Sama biblioteka o której wspomniałem ma się dobrze i nie jest dla mnie nieznana. Wiem co w niej siedzi, i to co tam zawiera polecenie "raise" jest potrzebne w każdym innym przypadku (dlatego nie chcę zmieniać biblioteki). Chcę tylko wprowadzić jeszcze jeden punkt (opracowanie jest zespołowe), wyjątek - odstępstwo od uruchomienia polecenia RAISE.

NImniejszym chyba można uznać, że temat nie ma rozwiazania - i muszę szukać dalej...

Dziękuję za pomoc i pozdrawiam serdecznie.

edytowany 1x, ostatnio: flowCRANE
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 5 godzin
  • Lokalizacja:Tuchów
  • Postów:12171
0

Zawsze możesz sobie dodać do tej bilbioteki zmienną, która będzie określać to czy wyjątki mają być produkowane i ”uzewnętrzniane” za pomocą raise. Stan tej zmiennej możesz modyfikować za pomocą dodatkowej funkcji w bibliotece, np. EnableExceptions, podając jej stan aktywności (jako wartość logiczna). Natomiast w kodzie biblioteki, zamiast puszczać wyjątek za pomocą raise, wykonaj warunek sprawdzający wartość zmiennej globalnej — jeśli jest pozwolenie na wypuszczenie wyjątku to wołaj raise, a jak nie to nie.

To najprostsze co mi do głowy przychodzi — łatwo dodać taki kod, nie psując obecnej postaci. Natomiast podczas wywołania głównej funkcji (tej, która ma nie rzucać wyjątków), najpierw wywołaj funkcję blokującą wydostawanie się wyjątków, następnie swoją główną, a na koniec tę odblokowującą wyjątki z powrotem. Cały pozostały kod pozostanie bez zmian i będzie działał tak samo.

To tylko ogólny zamysł — nie testowałem samodzielnie, ale powinien spełniać zadanie.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 1x, ostatnio: flowCRANE
flowCRANE
Poczytam, bo chyba problemów jest więcej niż zakładałem. :D
flowCRANE
Z tego co widzę, problemem w tym wątku na SO jest obsługa wyjątków po stronie aplikacji, które są generowane po stronie DLL. A to co wyżej opisałem nie pozwoliłoby się wyjątkowi wydostać z biblioteki (bo raise byłby blokowany), a więc aplikacja nawet by nie wiedziała, że wystąpił wyjątek.
woolfik
  • Rejestracja:ponad 17 lat
  • Ostatnio:dzień
  • Postów:1597
0

Jak rozumiem zarówno DLL jak i EXE, który z tej DLL korzysta to Twój kod napisany w Delphi i RISE z DLL obsłużony w try except w EXE

Kopiuj
try
  funkcja_z_dll_ktora_rzuca_rise;
except
  on e: exception do
     write(e.message);
end;

powoduje, że mimo wszystko na ekran leci wyjątek zamiast go wyciszyć i przechwycić w except tak?

edytowany 1x, ostatnio: woolfik
AB
  • Rejestracja:ponad 4 lata
  • Ostatnio:4 miesiące
  • Postów:34
0

poniekąd tak, ale u mnie nie sekcji on e: exception do .... tam jest raise. Ogólnie poradziłem sobie wstawiając w którymś momencie przechwycenie wyjądku w wewnętrzne rozwiązanie obsługi błędów i "wyciszeniu" komunikatu w przypadku wystąpienia określonego kodu błędu = zakończony sekwencją "abort"...

flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 5 godzin
  • Lokalizacja:Tuchów
  • Postów:12171
2

DLL nie powinno w ogóle rzucać wyjatków na zewnątrz, bo to jest mocno problematyczne. Kod w DLL może wygenerowac wyjątek, bo np. korzysta z jakiejś klasy, która wewnętrznie te wyjątki tworzy — np. TFileStream czy cokolwiek innego. Albo po prostu leci EAccessViolation czy EStackOverflow czy tam cokolwiek innego z RTL.

Zrobiłbym więc tak, że funkcja w DLL wykonywała by swój kod w sekcji try except (żeby wyjątek nigdy nie wydostawał się z tej funkcji) i nie używałbym raise do puszczania go dalej. Zamiast tego, w sekcji except bym wyjątek łapał, rozpoznawał typ i przepisywał z niego informacje o błędzie do lokalnych zmiennych (po stronie DLL), a jedyne co by było zwracane przez funkcję to kod błędu (gdzie kod 0 oznacza brak błędu).

Kopiuj
// po stronie DLL

var
  ErrorMessage: String;

function GetLastDLLError(): PChar; stdcall;
begin
  Result := PChar(ErrorMessage);
end;

function DoSomething(): Integer; stdcall;
begin
  Result := 0;

  try
    // kod mogący rzucić wyjątek
  except
    // tutaj selektywna obsługa wyjątów — poniższe tylko do zobrazowania działania
    on Error: Exception do
    begin
      ErrorMessage := Error.ToString();
      Result := 1; // kod zależny od klasy wyjątku
    end;
  end;
end;

exports
  GetLastDLLError,
  DoSomething;

end.

Aby po stronie aplikacji wiedzieć co się stało, dodałbym sobie w DLL funkcję (lub kilka) pokroju GetLastDLLError, do pobierania informacji o zainstniałym błędzie (w tym komunikat błędu, pozyskany z Exception.Message). Te informacje można by wykorzystać po stronie aplikacji — jeśli funkcja z DLL zwróciła niezerowy kod błędu (czyli błąd faktycznie wystąpił), to rzuciłbym wyjątek za pomocą raise, uzupełniając go w informacje pozyskane za pomocą wspomnianej funkcji GetLastDLLError.

Kopiuj
// po stronie aplikacji

function GetLastDLLError(): PChar; stdcall external 'foo.dll';
function DoSomething(): Integer; stdcall external 'foo.dll';


// wrapper na funkcję z DLL

procedure DoSomethingWrapper();
begin
  if DoSomething() <> 0 then
    raise Exception.Create(GetLastDLLError());
end;

W ten sposób wyjątki nadal byłyby obsługiwane, zarówno po stronie DLL jak i aplikacji, jednak różnica polegałaby na tym, że wyjątki nie migrowałyby pomiędzy DLL a aplikacją, bo to jest problematyczne i raz działa, a raz nie. Ma to prawo działać wedle oczekiwań — trzeba tylko sprawdzić czy tak faktycznie jest.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 3x, ostatnio: flowCRANE
AB
  • Rejestracja:ponad 4 lata
  • Ostatnio:4 miesiące
  • Postów:34
0

Wspominając o wewnętrznym rozwiązaniu obsługi błędów właśnie takie podejście miałem na myśli ;)

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)