Einzelnen Beitrag anzeigen

Benutzerbild von Gausi
Gausi

Registriert seit: 17. Jul 2005
885 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: TPicture, TJPegImage, TBitmap, TBitmap32 und Threads ...

  Alt 11. Okt 2019, 10:47
Ich muss hier nochmal nachfragen, weil ich die Interface-Geschichte noch nicht ganz verstanden habe, glaube ich.

Die Funktion aus dem letzten Posting (eigentlich eine private Methode einer großen Klasse, von der im Programm genau eine Instanz existiert) rufe ich mal aus einem Nebenthread auf, und mal aus dem VCL-Thread. Dabei nutze ich nicht TThread, sondern BeginThread, woraus dann die threaded Methoden aus der großen Klasse aufgerufen werden.

Um nicht jedesmal die Factory neu zu erstellen, habe ich dafür zwei private Member-Variablen in der Klasse
Delphi-Quellcode:
WICImagingFactory_VCL: IWICImagingFactory;
WICImagingFactory_ScanThread: IWICImagingFactory;
Mit IWICImagingFactory = interface(IUnknown) aus der Unit Winapi.Wincodec.


Aufgerufen wird die Methode dann über

ScalePicStreamToFile(aStream, aFilenname, 240, 240, GetProperImagingFactory(ScanMode)) Scanmode ist ein Aufzählungstyp und steuert "VCL oder Thread". Die Factory bekomme ich dann mit dieser privaten Methode, die bei Bedarf die Factory erstellt, und ansonsten die bestehende zurückliefert.

Delphi-Quellcode:
function TMyClass.GetProperImagingFactory(ScanMode: CoverScanThreadMode): IWICImagingFactory;
begin
    case ScanMode of
        tm_VCL: begin
            if WICImagingFactory_VCL = Nil then
                CoCreateInstance(CLSID_WICImagingFactory, nil, CLSCTX_INPROC_SERVER or
                    CLSCTX_LOCAL_SERVER, IUnknown, WICImagingFactory_VCL);
            result := WICImagingFactory_VCL;
        end;
        tm_Thread: begin
            if WICImagingFactory_ScanThread = Nil then
                CoCreateInstance(CLSID_WICImagingFactory, nil, CLSCTX_INPROC_SERVER or
                    CLSCTX_LOCAL_SERVER, IUnknown, WICImagingFactory_ScanThread);
            result := WICImagingFactory_ScanThread;

        end;
    end;
end;
Jetzt habe ich beim Thread das Problem, dass nach Ende des Threads die Factory nutzlos wird (sie muss wohl immer im Kontext des Threads erstellt werden, in dem sie genutzt wird). Daher muss ich die freigeben, und die Variable auf Nil setzen, damit beim nächsten Thread (es läuft aber immer nur einer nebenbei) wieder eine neue erstellt wird.

Das habe ich so gemacht
Delphi-Quellcode:
WICImagingFactory_ScanThread._Release
WICImagingFactory_ScanThread := Nil
Bei mir läuft das, bei vielen anderen knallt die Zuweisung auf Nil. So grob habe ich auch schon verstanden, warum: Wenn durch das Release der Referenzzähler Null wird, wird das Objekt dahinter freigegeben. Die Zuweisung auf Nil hingegen ruft intern wieder Release auf, aber das Objekt ist schon weg.

In der VCL-Komponente TWICImage ist diese Factory eine Class Var. Wenn ich den Code aus TWICImage.Destroy übernehme, komme ich auf
Delphi-Quellcode:
if WICImagingFactory_ScanThread._Release = 0 then
  Pointer(WICImagingFactory_ScanThread) := Nil;
Das funktioniert dann. Sehe ich das richtig, dass durch den Cast auf Pointer einfach nur die Variable auf NIL gesetzt wird, und die "Interface-Magic" dahinter nicht aktiviert wird, und somit das erreicht wird, was ich haben will? Nämlich dass das Objekt weg ist, und die Variable Nil ist?

Oder ist der ganze Ansatz kompletter Murks?
The angels have the phone box.
  Mit Zitat antworten Zitat