![]() |
OCX wird nicht freigegeben
Hallo zusammen!
Ich habe ein großes Problem, zu dem ich noch keine Lösung gefunden habe. Ich habe unter Delphi eine OCX-Komponente geschrieben. Diese Komponente hat eine ActiveForm. Aus dieser Komponente erzeuge ich nun ein Objekt und gebe es anschließend wieder frei. Normalerweise müsste ja jetzt auch die OCX wieder freigegeben sein, aber das ist sie nicht - sie ist immer noch gesperrt und offenbar scheint irgendeine Referenz auf die OCX zu zeigen. Meine Frage: wie kann ich erzwingen, dass die OCX-Komponente nach der Zerstörung aller Objekte daraus wieder korrekt freigegeben wird? Andere OCX-Komponenten (in C++ geschrieben) werden bei gleichem Aufruf wieder freigegeben. Zudem passiert das auch, wenn ich ein ganz frisches Projekt erzeuge. Also: ActiveX-Projekt und anschließend Datei/Neu und ActiveForm. Kompilieren, testen, geht nicht :-( Um Hilfe wäre ich sehr Dankbar! Grüße und Danke im Voraus |
Re: OCX wird nicht freigegeben
Zitat:
Die Anzahl der offenen Referenzen lässt sich über ComServer.ObjectCount ermitteln. Die globale Variable ComServer muss dazu natürlich von der OCX heraus benützt werden. Du solltest auch mal einen Eventhandler für COMServer.OnLastRelease bereitstellen, um genau festzustellen, wann die letzte Referenz "flöten gegangen" ist.
Delphi-Quellcode:
THelper = class(TObject)
procedure OnLastReleaseHandler(Sender:TObject); end; procedure THelper.OnLastReleaseHandler(Sender:TObject); begin ShowMessage('letzte Referenz ist nun weg'); // ggf. OutputDebugString anstelle von ShowMessage verwenden end; var gHelper : THelper; initialization gHelper := THelper.Create; COMServer.OnLastRelease := gHelper.OnLastReleaseHandler; finalization COMServer.OnLastRelease := nil; // Zur Sicherheit gHelper.free; Zitat:
|
Re: OCX wird nicht freigegeben
Hallo,
erstmal vielen Dank für die schnelle Antwort. Ich habe nun in alle Destroy-Blöcken die es gibt den Wert ComServer.ObjectCount ausgewertet. Tatsächlich steht er in einem Destroy-Block (der letzte der aufgerufen wird) auch auf 0. Jedoch bleibt die OCX wohl noch geladen. Ich habe nun gedacht, das ich einfach eine Abfrage einbaue die so aussieht:
Delphi-Quellcode:
Aber dann wird das ganze Programm, dass die OCX verwendet, gleich mitbeendet.
if ( ComServer.ObjectCount = 0 ) then CoFreeUnusedLibraries;
"Schieße" ich die OCX ab, wenn der Counter auf 0 steht (immerhin braucht dann wohl keine Anwendung mehr die OCX) und zwar durch diesen Aufruf im Destroy:
Delphi-Quellcode:
Dann verhält es sich so wie es soll, also:
if ( ComServer.ObjectCount = 0 ) then ComServer.Free;
1. Die Anwendung wird gestartet 2. Ein Objekt aus der OCX wird erzeugt 3. Das Objekt wird freigegeben 4. OCX ist freigegeben. Das klappt tausendmal hintereinander (Objekterzeugung und freigabe) bis die Anwendung selbst beendet wird. Dann gibt es einen Ausnahmefehler von wegen InvalidPointer. |
Re: OCX wird nicht freigegeben
Zitat:
Angenommen, in der OCX gibt es eine CoClass und dein Programm erzeugt ein Objekt und zerstört es gleich wieder. Dann würde jedesmal die OCX geladen und wieder entladen werden. => grosser Performanceverlust Intelligenter wäre da ein verzögertes Entladen (delayed unload) nach 2 bis 3 Minuten. Und das wird IMHO unter Windows auch so gemacht. Bei Delphi könnte es noch einen anderen Grund geben:
Delphi-Quellcode:
Man sieht, die OCX wird nur entladen wenn sowohl ObjectCount als auch FactoryCount gleich 0 ist.
function DllCanUnloadNow: HResult;
begin if (ComServer = nil) or ((ComServer.FObjectCount = 0) and (ComServer.FFactoryCount = 0)) then Result := S_OK else Result := S_FALSE; end; Da aber FactoryCount normalerweise nicht 0 wird, bleibt die OCX geladen. Du könntest nun deine eigene Funktion schreiben und exportieren:
Delphi-Quellcode:
library Project1;
uses ComServ; exports DllGetClassObject, DllCanUnloadNow, DllRegisterServer, DllUnregisterServer; function DllCanUnloadNow: HResult; begin if (ComServer = nil) or ((ComServer.FObjectCount = 0) {and (ComServer.FFactoryCount = 0))} then Result := S_OK else Result := S_FALSE; end; |
Re: OCX wird nicht freigegeben
Das Problem scheint sich für uns gelöst zu haben. Ich werds hier aber der Vollständigkeit halber beschreiben:
Die OCX wurde - auch mehrmals gleichzeitig - verwendet und somit wurde parallel Objekte daraus erzeugt. 1. Fehler: nicht alle Objekte wurden bereinigt. Also peinlichst genau darauf achten, dass die Destroy-Methoden durchlaufen werden. Ggf. überschreiben und dort erzeugte Objekte freigeben. 2. ThreadingModell: mit tmApartment gabs Probleme. Überall tmBoth benutzen, damit die OCX ThreadSafe ist. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:31 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz