2010-06-08 9 views
7

Voglio temporaneamente aggiungere una directory ai percorsi di ricerca DLL: esiste un metodo corretto per eseguire questa operazione in Windows 7?Aggiunta temporanea di una directory ai percorsi di ricerca DLL di Windows 7

Scenario

Ho un'applicazione C#, chiamiamolo WonderApp.

WonderApp deve chiamare una DLL C++, che si trova in C:\MyPath. Quindi, come parte di WonderApp di Program.Main(), ho aggiunto il seguente comando:

Environment.SetEnvironmentVariable("PATH", 
    "C:\\MyPath;" + Environment.GetEnvironmentVariable("PATH")); 

Secondo this article, l'aggiunta di una directory al PATH dovrebbe anche aggiungere alla ricerca di directory per le DLL.

La soluzione funziona correttamente in Windows XP: se aggiungo la directory allo PATH, la DLL viene caricata e il programma funziona correttamente. Se non aggiungo la directory, la DLL non viene caricata, in mancanza di un errore "non trovato".

Tuttavia, questo non funziona per Windows 7.

Così ho pensato, proviamo con SetDllDirectory(). Come questo:

[System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)] 
private static extern bool SetDllDirectory(string lpPathName); 

E, più avanti:

bool success = SetDllDirectory(Util.Paths.GetApplicationDataDir()); 

Il valore di success è true, ma la DLL non riesce ancora a caricare.

Infine, se si imposta PATH per includere manualmente C:\MyPath, prima di eseguire l'applicazione, tutto funziona! La DLL viene caricata e viene eseguita correttamente.

Quindi, per ribadire:

Esiste un modo corretto di temporaneamente aggiungere una directory per i percorsi di ricerca DLL in Windows 7?

UPDATE: Utilizzando Process Explorer, ho controllato ambiente run-time dell'applicazione, e "C: \ MyPath" era davvero nel PATH! Inoltre, ho visto che Helper.dll era nella lista degli handle aperti (come una DLL, non solo un file) - e continuava a non trovarlo.

+0

È questo la versione a 64 bit di Windows? Qual è il vero nome del percorso? –

+0

Questo è Windows 7 Home a 32 bit. E il percorso completo della DLL è C: \ MyPath \ Helper.dll – scraimer

+0

forse mancano altre DLL prova a caricare helper.dll nel programma "depends.exe" e controlla le dipendenze di altre DLL. – OlimilOops

risposta

0

La mia soluzione è semplice, ma mi sento ridicolo ricorrere ad esso.

Ho scritto un altro assembly, "Shell", che modifica l'ambiente, esegue WonderApp ed esce.

Modificando lo PATH prima di eseguire l'applicazione principale (WonderApp), il percorso di ricerca DLL dell'applicazione principale include le directory aggiunte allo PATH modificato.

Ecco come si presenta:

namespace shell 
{ 
    static class program 
    { 
     [dllimport("kernel32.dll", charset = charset.auto, setlasterror = true)] 
     public static extern bool setenvironmentvariable(string lpname, string lpvalue); 

     private static string joinargstosinglestring(string[] args) 
     { 
     string s = string.empty; 
     for (int i = 0; i < args.length; ++i) 
     { 
      if (!string.isnullorempty(s)) 
      { 
       s += " "; 
      } 
      s += "\"" + args[i] + "\""; 
     } 
     return s; 
     } 

     [stathread] 
     static void main(string[] args) 
     {  
     string pathbefore = environment.getenvironmentvariable("path"); 
     string wewant = util.paths.getapplicationdatadir() + ";" + pathbefore; 
     setenvironmentvariable("path", wewant); 

     Process process = Process.Start(".\\WonderApp.exe", joinArgsToSingleString(args)); 
     } 
    } 
} 

Vorrei poter trovare una soluzione migliore!

1

Penso che abbia a che fare con problemi di autorizzazione.

Provare a disattivare UAC ed eseguire nuovamente il codice. Controlla se l'aggiornamento del percorso ha funzionato.

Se così fosse, almeno si sa da dove cominciare ...

+0

No: lo spegnimento del controllo dell'account utente non ha funzionato. Grazie per l'idea, però. – scraimer

2

È possibile aggiungere la logica di caricamento DLL personalizzata a un'app C# utilizzando l'evento 'AssemblyResolve'.

questa pagina ha una buona sintesi, con esempi di codice: http://support.microsoft.com/kb/837908

Proprio come hai fatto, ho trovato che cambiando la variabile d'ambiente PATH di una corsa C# app non influisce sul comportamento di ricerca DLL. Forse l'AppDomain memorizza il valore PATH all'avvio? È possibile utilizzare l'evento AssemblyResolve per aggirare questo problema.

Vedi anche How to add folder to assembly search path at runtime in .NET?

+0

Questo è * fantastico * !!! Grazie mille per avermelo fatto sapere! Sembra che funzioni su qualsiasi assembly .NET, ma ho bisogno di testarlo anche per DLL non- .NET. – scraimer

+1

OK, cattive notizie: Funziona solo per gli assembly .NET. Il che ha perfettamente senso, considerando il suo nome. È una soluzione meravigliosa, ma non posso usarla, dal momento che le DLL che devo caricare non sono assembly .NET. (E per peggiorare le cose, anche quelle DLL devono caricare altre DLL, che si trovano nella stessa directory con loro, quindi dovrei trovare un modo per farle cercare anche lì). – scraimer

Problemi correlati