Cześć, siedzę nad tym już drugi dzień i nic. Środowisko XE2 Update 4
Generalnie zasada jest taka - mam interfejs. Klasa w DLL implementuje ten interfejs, a potem zwracam ten obiekt do aplikacji głównej.
Na koniec zwalniam bibliotekę DLL.
Może to trochę chaotycznie brzmi, więc trochę kodu. Jak jest interfejs skonstruowany, to chyba nie ma znaczenia.
Generalnie w DLL mam klasę:
TPlugin = class(TInterfacedObject, IPlugInterface)
//deklaracje metod
end;
W dll mam też jedną funkcję, którą eksportuję:
function CoCreatePlugin: IPlugInterface; stdcall;
begin
Result := TPlugin.Create;
end;
(zasada działania pochodzi z jakiegoś artykułu w necie, który czytałem dawno temu)
Teraz w aplikacji głównej robię coś takiego:
(plugin to zmienna typu TPlugin, który jest rekordem i wygląda mniej więcej tak:
type
TPlugin = record
Active: boolean; //czy używać, czy nie
{$IF DEFINED(SERVICE) or DEFINED(TEST_APP)} //nie sądzę, żeby dyrektywy miały wpływ na błąd, ale są tutaj
Handle: THandle;
IFace: IPlugInterface;
{$IFEND}
end;
I teraz ładuję bibliotekę i wywołuję CoCreatePlugin:
Plugin.Handle:=LoadLibrary('plik.dll');
if Plugin.Handle <> 0 then
begin
@CreatePluginProc:=GetProcAddress(Plugin.Handle, 'CoCreatePlugin');
if @CreatePluginProc = nil then //generalnie wtedy wywalam błąd
Plugin.IFace:=CreatePluginProc;
@CreatePluginProc:=nil; //zawsze tutaj jest wszystko ok
I od tego momentu mogę wywoływać wszystkie metody z dll poprzez: Plugin.IFace.Metoda();
Wszystkie metody w interfejsie są oznaczone jako safecall.
Problem pojawia się podczas zwalniania biblioteki. O dziwo, wcześniej to działało.
res:=FPlugins[PluginIndex].IFace.Disconnect;
if res<>S_OK then exit;
FreeLibrary(FPlugins[PluginIndex].Handle);
FPlugins[PluginIndex].Handle:=0;
FPlugins[PluginIndex].IFace:=nil;
I teraz tak. Błąd powstaje zawsze w ostatniej linijce, tam gdzie jest przyrównanie do NIL.
Project Project1.exe raised exception class $C0000005 with message 'access violation at 0x0040ba2e: read of address 0x04dcad8c'.
Przy czym adres: 0x04dcad8c
to adres, pod którym znajduje się FPlugins[PluginIndex].IFace
. (czyli sam obiekt)
Jeśli natomiast nie ma tego przyrównania do nil, to access violation pokazuje się jakby w losowych miejscach. Np. jak kliknę gdziekolwiek poza okno programu. Albo po pewnym czasie(w programie nie ma żadnego działania).
Project Project1.exe raised exception class $C0000005 with message 'access violation at 0x02770fef: read of address 0x02770fef
Adres 0x02770fef
MOŻE BYĆ wskaźnikiem na tamten obiekt, tzn: @FPlugins[PluginIndex].IFace
Czasami jednak wskazuje na adresy 0x00000000
. Przy czym zawsze jest class $C0000005
I ja już nie wiem, co robić. Czy potrzebujecie jeszcze jakiejś informacji? Czy coś jest niepokojącego w tym kodzie?
Zaznaczam, że jeśli nie mam wywołania FreeLibrary, to nie ma też Access Violation.
Proszę o pomoc.