2009-06-25 19 views
6

Sono occupato a codificare una DLL che fornisce diverse funzioni a un'applicazione host. Questa applicazione chiama la DLL dinamicamente, caricandola e liberandola dopo ogni chiamata di funzione.Delphi Dynamic Dll - variabile globale

Non ho alcun controllo sull'app host. Posso lavorare solo con la DLL. C'è un modo per mantenere determinate variabili in memoria in modo che possa riutilizzarle all'interno di ogni funzione? Ovviamente una variabile globale viene cancellata quando la DLL viene scaricata dall'app host. Salvare la dll in un file molto disordinato!

Qualcuno può suggerire un modo per assegnare una variabile che posso mantenere globale?

Grazie

+3

Il design desiderato è negativo per molte ragioni. Avete mai pensato alla possibilità di più istanze dell'app host (Cambio rapido utente, utilizzando sotto Terminal Server) o dell'app host che chiama le funzioni DLL da più thread? Cerca di evitare lo stato globale/condiviso a tutti i costi. – mghie

risposta

4

Penso che tu abbia 2 opzioni principali qui.

  1. offerta 2 versioni della vostra funzione, quello che hai ora, più un altro dove passano in un buffer (registrazione, a prescindere) che si può leggere lo stato precedente da, e, naturalmente, aggiornare lo stato in. Chiamala la versione ad alta perf della funzione. Vogliono usarlo.

  2. Salvare lo stato come si farebbe un cookie (questo è fondamentalmente quello che è) in un file da qualche parte.

Opzione 1 richiederebbe la modifica al app host, ma sarebbe interessante per gli sviluppatori di applicazioni host per trarre vantaggio, opzione 2 richiederebbe alcuna modifica l'applicazione host, ma non sarebbe così performante.

Personalmente non sarei incline a iniziare a chiacchierare con il numero di riferimento, presumibilmente l'app host sta scaricando per un motivo, se fossi l'app per l'host, mi avrebbe dato fastidio.

+0

grazie - penso che questa sia la migliore scommessa. Preferirei risparmiare su file e prendere un colpo rispetto al rischio piuttosto che armeggiare con riferimenti alle DLL. Forse gli sviluppatori di applicazioni host andranno avanti con una versione ad alte prestazioni – Crudler

1

Il modo migliore è quello di utilizzare una classe che contiene le "globali". Si istanzia un oggetto e lo si assegna come parametro alle funzioni dll. Ma questo non ti aiuterà perché non sei in grado di cambiare l'app chiamante.

Se è necessario mantenere i dati globali nella DLL, una soluzione è scriverli in un file. Ma questo ha un impatto grave sulle prestazioni.

0

Se fossi in te, salverei i valori di tali vars globali in un file quando la DLL viene liberata e caricata quando viene inizializzata. Non ho motivo di salvare il dump della memoria della dll sul disco.

4

Attenzione, sporco trucco:

Si potrebbe caricare te stesso.

Ogni chiamata a LoadLibrary incrementa un contatore di riferimento, FreeLibrary lo diminuisce. Solo se il contatore raggiunge lo zero, la DLL viene scaricata.

Quindi, se la prima volta che viene caricata la DLL, è sufficiente caricare nuovamente la libreria, incrementando così il contatore di riferimento. Se l'applicazione chiamante chiama FreeLibrary il contatore di riferimento viene decrementato, ma la DLL non viene scaricata.

MODIFICA: Come indicato da mghi, la DLL verrà scaricata se il processo termina, indipendentemente dal fatto che il conteggio dei riferimenti sia zero o meno.

+1

Sì, ma di nuovo questo metodo aggiunge un sacco di confusione su quando decidere il momento in cui la dll dovrebbe davvero scaricarsi, perché non ha bisogno di essere eseguito tutto il tempo. La dll dovrebbe quindi verificare periodicamente se l'app host esiste ancora, cosa che non mi piace molto, ma sono solo io. – zz1433

+3

@Aldo: non vero - se solo un processo utilizza la DLL, verrà scaricato una volta terminato il processo, se il conteggio dei riferimenti ha raggiunto 0 o meno. – mghie

2

Un'altra soluzione, se si dispone di una grande quantità di dati globali da condividere, sarebbe quella di creare un servizio Windows per "memorizzare" i dati di stato. È inoltre necessario implementare una sorta di IPC che funzioni attraverso il limite del processo, come i file mappati in memoria, le cassette postali, COM (singola istanza per questo caso), TCP/IP ecc. Potresti scoprire che questo overhead sarebbe più che la semplice scrittura dello stato in un file, motivo per cui consiglierei questo approccio solo se la quantità di dati di stato è eccessiva, o sarà trattata solo in parti del tutto per ogni richiesta nella tua DLL.

Per l'approccio COM, il servizio non deve fare molto altro che richiedere (e trattenere) un'istanza dell'oggetto COM che si utilizzerà per mantenere lo stato. Poiché si tratta di un oggetto com a istanza singola, tutte le richieste saranno relative alla stessa istanza, consentendo in questo modo di salvare lo stato tra le richieste. Le richieste all'oggetto sono serializzate, quindi questo potrebbe essere un problema di prestazioni se più client richiedono contemporaneamente dati sulla stessa macchina.

+1

Per far progredire questa idea, potresti rendere la DLL un sottilissimo strato che reindirizza la chiamata al servizio. La carne del lavoro può essere fatta nel servizio e può mantenere lo stato. Un ulteriore vantaggio di ciò sarebbe la dimensione della DLL che verrebbe ridotta e accelererebbe il tempo necessario per caricare la DLL (che tu dici che l'app esegue su ogni singola chiamata di funzione). – Kieveli

+0

@Kieveli: buon punto, ma è ancora necessario stabilire una sorta di IPC. Com (singola istanza) sarebbe una soluzione semplice, e in tal caso il servizio non può fare altro che richiedere e trattenere un riferimento per mantenere l'oggetto. – skamradt

+0

questo sarà probabilmente il più divertente! Ma penso che mi limiterò ad archiviare file, come tu dici, il sovraccarico sarà probabilmente di più, e c'è solo più ris i per qualcosa da fare. Grazie mille – Crudler

0

Scrive i valori nel registro quando la DLL viene liberata e legge i valori dal registro quando viene caricata la DLL. Non dimenticare di fornire un valore predefinito quando la lettura scopre che una chiave non è stata impostata.

-Al.

0

Sono d'accordo con i commenti precedenti sull'informazione di stato globale che è pericolosa, anche se posso immaginare che potrebbe essere necessaria.

propongo una versione più pulita di hack sporco di DR che non ha il rovescio della medaglia di essere permanente come la risposta di skamradt:

Una piccola applicazione:

Non ha l'aspetto di sorta, si tiene da mostrando sulla barra delle applicazioni.

Task # 1: caricare la DLL

Task # 2: Take è a riga di comando, eseguirlo e attendere il completamento dello stesso.

Task # 3: Scaricare la DLL

Task # 4: Exit.

Il programma di installazione:

Essa trova la scorciatoia (s) per l'applicazione principale e li modifica quindi le piccole serie di app, la posizione originale il collegamento indicò diventa il primo parametro.

Risultati: la DLL rimane in memoria solo finché l'app principale è in esecuzione ma non viene scaricata ogni volta che il programma lo scarica.

0

Questo può anche essere utile

option 1: creare un'area di memoria condivisa che detiene le variabili supportate da file di paging - se siete in grado di aprire quella zona di memoria condivisa, la DLL è stato precedentemente caricato (assumendo "privato "nome della memoria condivisa, forse chiamato qualcosa come process_id_yourdllname) - se non riesci ad aprirlo, lo crei e lo inizializzi la prima volta. Se lo crei, non ti preoccuperai di cancellarlo, ma se lo apri, lo chiuderesti al momento dello scaricamento. Credo che l'area verrà rilasciata quando l'applicazione si chiuderà, poiché nessun'altra applicazione dovrebbe avere maniglie per questa particolare area di memoria condivisa "privata".

option 2: Creare un secondo.DLL che esiste solo allo scopo di gestire le tue variabili globali. La tua DLL A può caricare quella DLL B, e non liberarla, inserendo in dll B tutto ciò che è necessario per gestire le variabili globali. Dovrebbe andare via quando l'applicazione va via, e non penso che probabilmente ti serva il conteggio dei riferimenti (presumibilmente inutile) in questione (dato che non scaricheresti dll B).