Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi OCX wird nicht freigegeben (https://www.delphipraxis.net/102472-ocx-wird-nicht-freigegeben.html)

Evil MM 29. Okt 2007 15:53


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

shmia 29. Okt 2007 16:06

Re: OCX wird nicht freigegeben
 
Zitat:

Zitat von Evil MM
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.

Das wird wohl das Problem sein.
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:

Zitat von Evil MM
Meine Frage: wie kann ich erzwingen, dass die OCX-Komponente nach der Zerstörung aller Objekte daraus wieder korrekt freigegeben wird?

Das würde ich nun überhaupt nicht empfehlen. Daraus folgen nur schwerwiegende Probleme beim Programmende.

Evil MM 30. Okt 2007 09:54

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:
if ( ComServer.ObjectCount = 0 ) then CoFreeUnusedLibraries;
Aber dann wird das ganze Programm, dass die OCX verwendet, gleich mitbeendet.

"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:
if ( ComServer.ObjectCount = 0 ) then ComServer.Free;
Dann verhält es sich so wie es soll, also:

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.

shmia 30. Okt 2007 10:33

Re: OCX wird nicht freigegeben
 
Zitat:

Zitat von Evil MM
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.

Das ist höchstwahrscheinlich ein gewünschtes Verhalten seitens des Betriebssystems.
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:
function DllCanUnloadNow: HResult;
begin
  if (ComServer = nil) or
    ((ComServer.FObjectCount = 0) and (ComServer.FFactoryCount = 0)) then
    Result := S_OK
  else
    Result := S_FALSE;
end;
Man sieht, die OCX wird nur entladen wenn sowohl ObjectCount als auch FactoryCount gleich 0 ist.
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;

Evil MM 7. Nov 2007 14:50

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