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.