Caricare una DLL a runtime

giovedì 07 giugno 2007 - 15.59

us01739 Profilo | Expert

Ciao a tutti,
ho realizzato un servizio in VB.NET 2.0 che utilizzando un timer esegue una serie di routine; il mio desiderio sarebbe che una volta terminate queste routine, verificasse se esiste una dll in un path ben definito, e, se presente, la "carica" ed esegue altre routine scritte in questa DLL.

Qualcuno mi sa dare un consiglio da dove partire?

Grazie 1000 fin da ora...
Bye Bye

---------------------------------------------------
Roberto Gelmini - Microsoft Certified Professional
http://www.robertogelmini.com
---------------------------------------------------

munissor Profilo | Senior Member

Copi l'assembly da qualche parte..per esempio in %TMP%. Poi usi Assembly.Load per caricare l'assembly che ti interessa nell'appdomain.
Una volta fatto questo puoi cercare i metodi che ti interessano tramite reflection (per le condizioni vedi tu: puoi usare o le interfacce o gli attributi..dipende dal tuo caso specifico)..

Non è difficile come cosa..

Ciao!

us01739 Profilo | Expert

Ciao,
ho utilizzato il consiglio che mi hai dato ed ho risolto.
Bye Bye

---------------------------------------------------
Roberto Gelmini - Microsoft Certified Professional
http://www.robertogelmini.com
---------------------------------------------------

us01739 Profilo | Expert

Ciao, ho fatto qualche prova è funziona tutto, ma poi purtroppo la dll mi rimane "in uso" e non posso eliminarla...
Ho letto un po' su internet ed ho visto che dovrei creare un nuovo AppDomain, ed utilizzare poi il metodo load, ma siccome questo non consente come parametro il path della dll, mi sto incartando e non riesco a saltarci fuori ...
Bye Bye

---------------------------------------------------
Roberto Gelmini - Microsoft Certified Professional
http://www.robertogelmini.com
---------------------------------------------------

munissor Profilo | Senior Member

Il fatto è che non si possono scaricare gli assembly (a differenza della programmazione Windows dove con LoadLibrary e UnloadLibrary facevi quello che volevi) Devi utilizzare AppDomain.ExecuteAssembly, però il tuo assembly dovrebbe avere un entry point (dovrebbe essere cioè un exe, non una dll). Se la dll è in grado di eseguirsi in modo indipendente puoi fare con un appdomain separato. Poi una volta finito chiami AppDomain.Unload. Se hai bisogno di comunicare con l'appdomain originale allora le cose si complicano...

filippo.monti Profilo | Junior Member

Io faccio in questo modo (le mie dll sono tutte WinForm)...

Dim assembly as Reflection.Assembly = System.Reflection.Assembly.LoadFrom("dll compresa di path")
Dim functionObject as object = assembly.CreateInstance("nome metodo all'interno della DLL", True)
Dim sedePdv as Form = ctype(functionObject,Form)
sedePdv.Showdialog()

....
Ciao
Filippo

munissor Profilo | Senior Member

Si ok..ma così non puoi più scaricare l'assembly dalla memoria... Si possono scaricare solo interi AppDomain, non assembly singolarmente...

filippo.monti Profilo | Junior Member

Sinceramente non ho mai provato a verificare ma il GC una volta "morti" gli oggetti assembly, functionObject, sedePdv non dovrebbe scaricarla automaticamente?
fisicamente la DLL non esiste se non come istanza della functionObject...

Ciao
Filippo

munissor Profilo | Senior Member

No beh, stiamo parlando di due cose diverse... Un conto sono gli oggetti (Assembly, MethodInfo, ecc...) che vengono regolarmente scaricati.. Il problema qui è la DLL. Prima di poterla usare gli oggetti contenuti al suo interno il CLR carica la DLL all'interno dello spazio di indirizzamento del processo, occupando ram e mantenendo aperto il file (per questo l'utente non lo può cancellare). Avvengono poi altre cose quali la compilazione JIT (e evetualmente il caricamento delle immagini native) ecc... Scaricare un assembly porta l'app domain in uno stato inconsistente, quindi non è consentito farlo allo stato attuale del framework.

PS: riguardo il problema iniziale penso di aver trovato la soluzione. Se abiliti la ShadowCopy quando inizializzi un appdomain fai in modo che il runtime crea una copia temporanea dell'assembly per caricarlo. Il problema qui è che non puoi modificare un appdomain una volta creato, quindi le strade sono 2

1) utilizzando solo codice gestito nel metodo main di un eseguibile "stub" crei un'altro appdomain con la shadowcopy abilitata e lo esegui (caricando un altro assembly .exe). Questo ha lo svantaggio di richiedere un po' più di memoria in quanto devi tenere vivi due appdomain per tutta la durata dell'applicazione, uno inutile dello stub iniziale, e uno in cui effettivamente gira il tuo programma.

2) la seconda è via codice nativo e si tratta semlicemente di eseguire l'hosting del CLR in un tuo processo e creare l'appdomain di default direttamente con lo shadowcopy abilitato... non so come si comporti però in caso di eccezioni non gestite o cose del genere. Non è impossibile da farsi, posso anche procurarti un esempio se hai bisogno. Prova a dare un'occhio all API CorBindToRuntimeEx per un inizio.

us01739 Profilo | Expert

Innanzitutto grazie e complimenti per le spiegazioni che sono chiarissime!!
Per quanto riguarda creare un nuovo AppDomain non sarebbe tanto il fatto di utilizzare più memoria utilizzando un "exe" tipo console application, quanto che non voglio che l'utente veda aprirsi una shell... Magari potrei utilizzare una WinForm mettendola non visibile, ma mi sembra un pò una forzatura...

Per la seconda opzione, non saprei proprio come configurare il corrent domain in maniera che funzioni davvero con la shadowcopy; nonostante sia un methodo obsoleto, ci sarebbe la sub "SetShadowCopyFile" ma non funziona...

Se hai un esempio da passare, credo che te ne sarò grato per almeno 50/55 anni!!!!!
Altrimenti grazie comunque perchè sei stato comunque utilissimo!
Bye Bye

---------------------------------------------------
Roberto Gelmini - Microsoft Certified Professional
http://www.robertogelmini.com
---------------------------------------------------

munissor Profilo | Senior Member

Un pezzo di codice vale più di mille parole: in allegato un esempio di come utilizzare 2 app domain e la shadow copy... Leggi sopratutto il commento che ho lasciato in Program.cs nel progetto "ShadowCopySample".

ShadowCopySample è lo stub che crea un secondo dominio, abilita la shadow copy ed esegue il tuo programma
Program è il progetto che simula il tuo eseguibile, carica una libreria in modo dinamico e poi prova a cancellarla (vedi bottoni sulla form)
Library è una libreria "inutile" che viene caricata da Program.exe a scopo dimostrativo.

Per chiarimenti sono qua.

Ciao!

PS: in alternativa non puoi scaricare i tuoi assembly in una cartella tua privata che vai a svuotare ogni tanto?

us01739 Profilo | Expert

Ci guardo immediatamente e poi ti farò sapere!!
Intanto grazie fin da ora!
Bye Bye

---------------------------------------------------
Roberto Gelmini - Microsoft Certified Professional
http://www.robertogelmini.com
---------------------------------------------------

us01739 Profilo | Expert

Ciao a tutti,
vi informo sulle ultime novità perchè magari può essere utile a qualcun altro....
In pratica, lamia neccessità era caricare dll a runtime, eseguirne il codice e poi cancellarle, ma avevo dei problemi a rimuoverle perchè continuavano ad essere "occupate" dal programma stesso....

Ho risolto il problema così:
all'interno della routine principale ho inserito la sub start che crea un nuovo appdoamin e poi richiama la classe AgentInAppDomain che ha poi il vero compito di caricare l'assembli...

Non è esattamente come mi era stato consigliato, ma comunque i vostri post mi sono stati utilissimi altrimenti non ci sarei mai saltato fuori!!!

Grazie a tutti.

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

Class AgentInAppDomain Inherits MarshalByRefObject Sub RunFunctionInAppDomain(ByVal path As String) Try Dim yourAssembly As Assembly = Assembly.LoadFrom(path) ' eseguo qui le operazioni che voglio Catch ex As Exception Throw New InvalidOperationException(ex.Message) End Try End Sub end class
Bye Bye

---------------------------------------------------
Roberto Gelmini - Microsoft Certified Professional
http://www.robertogelmini.com
---------------------------------------------------

Keyser Profilo | Newbie

Io con le interfacce lo faccio facilmente:

Dim objAssembly As Assembly = Assembly.LoadFrom(dll)
Dim t As Type

For Each t In objAssembly.GetExportedTypes
If Not t.GetInterface("InterfacciaMia") Is Nothing Then
myInstance = Activator.CreateInstance(t)
Exit Sub
End If
Next


una volta che myInstance non mi serve più faccio:

myInstance=nothing
gc.collect()


S'moove Software
Software per Farmacie
Tariffazione automatica ricette farmaceutiche
http://www.smoovesoftware.com

munissor Profilo | Senior Member

Ripeto che il problema non è scaricare oggetti..qui si tratta di scaricare assembly.

gabro Profilo | Newbie

ciao,
io invece ho la necessità di utilizzare dal mio programma (fatto nel mio caso in C# e utilizzando il frameWork 3.5) di utilizzare dll e/o codice che compila Dll (in qesto caso ho preferito farle compilare in memoria anzichè sul disco).
per far cio ho pensato di creare un appDomain separato, sperando che nel momento in cui cancello l'appDomain creato anche i miei assemby (in questo caso parlo di dll fisiche) si liberino, così da riutilizzarli o eventualmente cancellarli.

secondo voi il fatto che le dll restino fisicamente in uso anche dopo l'eliminazione dell'AppDomain è una cosa normale?
e secondo voi gli assembly che compilo in memoria mi mantengono sempre la memoria ram allocata?

grazie Mille

Gabro

aleroot Profilo | Junior Member

Io vorrei implementare la funzione zip file di un mio prog solo se presente la dll Ionic Zip File, senza doverla aggiungere come reference al progetto,

è possibile caricare i metodi della dll a run-time senza doverla caricare come reference al progetto ?

potete farmi un esempio ?

Grazie.

filippo.monti Profilo | Junior Member

Guarda che .net ha nel framework librerie per fare zip/unzip che sono compatibli con gzip.
Quindi non c'è bisogno che utilizzi librerie di terze parti.
Ciao
Filippo

aleroot Profilo | Junior Member

Ad esempio , mi fai un' esempio per zippare file ?

cmq se io dovessi caricare una dll esterna, fatta in c# a runtime ? Come posso farlo ?

grazie

gabro Profilo | Newbie

Grazie a tutti... ho Risolto da me....

Ciao
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5