2016-01-19 28 views

risposta

3

GdiplusShutdown (e GdiPlusStartup btw) non può essere chiamato da DllMain ma DllMain è chiamato da Windows e Delphi runtime quando FreeLibrary si chiama: Delphi chiamata la sezione di finalizzazione di tutte le unità utilizzate dalla DLL e la sezione di finalizzazione GDIplus chiama GdiplusShutdown (Questo è perfettamente OK se usato da un eseguibile). Comportamento simile con la sezione di inizializzazione.

Ho risolto il problema aggiungendo un test per IsLibrary nelle sezioni di inizializzazione e di finalizzazione per evitare di chiamare le funzioni offensive, inoltre ho aggiunto due procedure pubbliche InitializeForDll e FinalizeForDll. Con queste piccole modifiche, la DLL è in grado di esportare funzioni chiamando InitializeForDll e FinalizeForDll. Quella funzione esportata deve essere chiamata dall'applicazione di hosting subito dopo aver caricato la DLL e appena prima di scaricare la DLL.

Ecco le modifiche apportate ai GdiPlus.pas:

Nella sezione interfaccia:

var 
    procedure InitializeForDll; 
    procedure FinalizeForDll; 

Nella sezione implementazione:

procedure InitializeForDll; 
begin 
    Initialize; 
end; 

procedure FinalizeForDll; 
begin 
    Finalize; 
end; 

anche aggiornato sezioni di inizializzazione e finalizzazione così:

Initialization 
    if not IsLibrary then 
    Initialize; 

Finalization 
    if not IsLibrary then 
    Finalize; 

nella DLL, ho esportato quelle funzioni:

procedure Initialize; stdcall; 
begin 
    GdiPlus.InitializeForDll; 
end; 

procedure Finalize; stdcall; 
begin 
    GdiPlus.FinalizeForDll; 
end; 

inizializzare e finalizzare sono chiamati dall'applicazione di hosting a destra dopo la chiamata LoadLibrary e poco prima di chiamare FreeLibrary (o qualunque cosa si caricare/scaricare la DLL).

Spero che questo aiuti gli altri. BTW: Grazie a Eric Bilsen per la fornitura di Delphi GdiPlus Library

+2

Questa è solo una parte della storia. Anche se apporti questa modifica, stai ancora violando le regole chiamando 'GdiplusStartup' dalla sezione di inizializzazione. Probabilmente è necessaria una lettura più approfondita della documentazione. Ho provato a scriverlo nella mia risposta. –

+0

Avevo visto che GdiPlusStartup è stato chiamato ma non ha alcun effetto negativo. Quindi ho solo sistemato ciò che stava fallendo. – fpiette

+0

Non hai ancora riscontrato alcun effetto negativo. La documentazione è molto chiara su questo punto. –

4

La documentazione per la funzione GdiplusStartup dice questo:

Non chiamare GdiplusStartup o GdiplusShutdown in DllMain o in qualsiasi funzione che viene chiamato da DllMain. Se si desidera creare una DLL che utilizza GDI +, è necessario utilizzare una delle seguenti tecniche per inizializzare GDI +:

  • richiederà il vostro client di chiamare GdiplusStartup prima di chiamare le funzioni nella DLL e chiamare GdiplusShutdown quando hanno terminato di utilizzare la DLL.
  • Esportare la propria funzione di avvio che chiama GdiplusStartup e la propria funzione di arresto che chiama GdiplusShutdown.Richiedi ai tuoi clienti di chiamare la funzione di avvio prima di chiamare altre funzioni nella tua DLL e di chiamare la tua funzione di spegnimento quando hanno finito di usare la tua DLL .
  • Chiama GdiplusStartup e GdiplusShutdown in ciascuna delle tue funzioni che effettuano chiamate GDI +.

Con la compilazione di questa libreria Delphi GDIplus in una DLL si sta rompendo questa regola sia per GdiplusStartup e GdiplusShutdown. Queste funzioni sono chiamate rispettivamente nelle sezioni initialization e finalization. E per i progetti di biblioteca, il codice nelle sezioni initialization e finalization di un'unità viene eseguito da DllMain.

Sembra che la libreria GdiPlus che si utilizza non sia mai stata concepita per essere utilizzata da una libreria. Tuttavia, come regola generale, quando si scrive il codice della libreria, è necessario conoscere le restrizioni relative a DllMain e assicurarsi che il codice inserito nelle sezioni initialization e finalization rispetti questo. Penso che questa libreria GdiPlus non funzioni in questo senso.

Per contro, hanno uno sguardo al codice unità di Delphi RTL WinApi.GDIPOBJ:

initialization 
    if not IsLibrary then 
    begin 
    // Initialize StartupInput structure 
    StartupInput.DebugEventCallback := nil; 
    StartupInput.SuppressBackgroundThread := False; 
    StartupInput.SuppressExternalCodecs := False; 
    StartupInput.GdiplusVersion := 1; 

    GdiplusStartup(gdiplusToken, @StartupInput, nil); 
    end; 

finalization 
    if not IsLibrary then 
    begin 
    if Assigned(GenericSansSerifFontFamily) then 
     GenericSansSerifFontFamily.Free; 
    if Assigned(GenericSerifFontFamily) then 
     GenericSerifFontFamily.Free; 
    if Assigned(GenericMonospaceFontFamily) then 
     GenericMonospaceFontFamily.Free; 
    if Assigned(GenericTypographicStringFormatBuffer) then 
     GenericTypographicStringFormatBuffer.free; 
    if Assigned(GenericDefaultStringFormatBuffer) then 
     GenericDefaultStringFormatBuffer.Free; 

    GdiplusShutdown(gdiplusToken); 
    end; 

Questo codice rispetta le regole facendo in modo che essa non chiama GdiplusStartup e GdiplusShutdown da DllMain. Invece lascia l'onere all'autore di qualsiasi libreria che utilizza WinApi.GDIPOBJ per assicurarsi che vengano chiamati GdiplusStartup e GdiplusShutdown in momenti appropriati.

Se fossi in te sceglierei una delle tre opzioni di punto elenco sopra elencate. La terza di queste opzioni non è molto pratica, ma le prime due sono buone scelte. Se fossi in me, opterei per la prima opzione e modificherò il codice initialization e finalization nella libreria GdiPlus per apparire più simile a quello trovato in WinApi.GDIPOBJ.

+0

Aggiorna la mia risposta usando il tuo consiglio. Grazie. – fpiette

+0

Ho cercato in questa risposta di fornire alcune prove documentali concrete per eseguire il backup di eventuali modifiche. Personalmente penso che sia più importante degli estratti di codice senza la giustificazione. Questo è davvero il motivo per cui ho scritto questa risposta. Per aggiungere i collegamenti alla documentazione e giustificare il motivo per cui è necessario apportare modifiche. –

Problemi correlati