2009-04-10 4 views
1

J'ai une DLL dont j'ai besoin d'accéder à des méthodes. Dans la plupart des cas, j'utilise simplement [DllImport] pour accéder à des méthodes à partir d'assemblages non gérés, mais le problème dans cette situation est qu'il nécessite le chemin d'accès à la DLL au moment de l'instanciation, donc une chaîne constante.Fonction d'appel à partir de DLL avec un chemin non-statique

Cette DLL particulière est celle qui est installée avec mon application et je ne peux pas garantir où elle sera après l'installation du programme (je préfère ne pas le mettre quelque part statique comme% SystemRoot%).

Y a-t-il un moyen en C# de pouvoir déclarer et utiliser une méthode d'une DLL à l'exécution avec un chemin variable?

Toutes les idées ou suggestions seraient grandement appréciées!

+0

Put le chemin dans le registre pendant l'installation et appelez-le avant de charger la DLL. – jmcecil

+0

Je ne vois pas comment cela m'aide, obtenir le chemin de la DLL à l'exécution n'est pas un problème. C'est déclarer la fonction dans le code, en utilisant ce chemin dynamique, que j'essaie de comprendre. –

Répondre

2

Ceci est un peu un hack, mais puisque vous dites que vous pouvez trouver le chemin d'accès à la DLL à l'exécution, pourquoi ne pas le copier dans votre répertoire de travail actuel avant d'utiliser l'une des fonctions? De cette façon, la DLL existera à côté de votre exe et sera trouvée par LoadLibrary. Aucun besoin de chemin supplémentaire dans votre DllImport.

La seule autre façon d'utiliser une méthode à partir d'un chemin d'accès dynamique est pour ce faire:
1) Les signatures P/Invoke nécessaire pour LoadLibrary & GetProcAddress
2) charger la bibliothèque de la trajectoire désirée (LoadLibrary)
3) trouver la fonction désirée (GetProcAddress)
4) Cast le pointeur à un délégué Marshal.GetDelegateForFunctionPointer
5) invoquer.

Bien sûr, vous devrez déclarer un délégué pour chaque fonction que vous voulez "importer" de cette manière puisque vous devez convertir le pointeur en délégué.

2

Ne pas utiliser de chemin du tout. Windows utilise une méthode par défaut de recherche de DLL lors de la tentative de chargement dynamique ou statique d'une fonction à partir de celle-ci.

La logique de recherche exacte est documentée à MSDN dans la documentation pour LoadLibrary - essentiellement, si la DLL est uniquement utilisé par votre application, mettre dans le même dossier que votre application lors de l'installation et ne vous inquiétez pas. Si c'est une DLL couramment utilisée, placez-la quelque part dans la structure de dossiers recherchée par LoadLibrary() et elle sera trouvée.

+0

Dans ce cas particulier, je suis incapable de placer la DLL dans le même répertoire que mon application, elle se trouve dans un sous-répertoire de mon application et j'essaie d'utiliser un chemin relatif pour la déclarer. Ce qui fonctionne sur certaines machines, mais n'est pas cohérent. = \ –

+0

Essayez d'importer SetDllDirectory à partir de Kernel32 et appelez le paramètre Application.StartupPath. Je vais essayer cela avec un de mes projets à la maison quand je rentrerai à la maison aujourd'hui et je ferai un commentaire quand je l'ai testé. Espérons que ça aide – Zack

+0

@Zack: Ça me semble une bonne idée, je vais essayer. –

0

J'avais une situation similaire. J'utilise les DLL d'un SDK installé sur la machine. Je reçois l'emplacement de répertoire des DLL à partir de cette clé de Registre SDKs. Je définis l'emplacement de la DLL sur la variable PATH des utilisateurs en cours d'exécution (modification temporaire uniquement). Fondamentalement, il vous permet de définir un chemin dynamique pour la DLL que vous souhaitez appeler, de sorte qu'il ne doit pas nécessairement provenir du registre. Notez que la variable PATH est le dernier endroit où Windows recherche les DLL. Mais d'un autre côté, cela ne change pas les autres endroits que Windows recherche pour les DLL.

Exemple:

API je veux appeler, sur la DLL:

[DllImport("My.DLL")] 
private static extern IntPtr ApiCall(int param); 

obtenir la clé de Registre (vous avez besoin l'aide de Microsoft.Win32;):

private static string GetRegistryKeyPath() { 
     string environmentPath = null; 

     using (var rk = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\SOMENNAME")) 
     { 
      if (rk != null) 
      { 
       environmentPath = rk.GetValue("Path(or whatever your key is)").ToString(); 
      } 
      if (string.IsNullOrEmpty(environmentPath)) 
      { 
       Log.Warn(
        string.Format("Path not found in Windows registry, using key: {0}. Will default to {1}", 
         @"SOFTWARE\SOMETHING", @"C:\DefaultPath")); 
       environmentPath = @"C:\DefaultPath"; 
      } 
     } 
     return environmentPath; 
    } 

Ajoutez le chemin de la DLL sur le var PATH (concat() se trouve dans LINQ):

void UpdatePath(IEnumerable<string> paths){ 
    var path = new[] { Environment.GetEnvironmentVariable("PATH") ?? "" }; 
    path = path.Concat(paths); 
    string modified = string.Join(Path.PathSeparator.ToString(), path); 
    Environment.SetEnvironmentVariable("PATH", modified); 
} 

Commencer à utiliser l'appel API:

var sdkPathToAdd = GetRegistryKeyPath(); 
IList<string> paths = new List<string> 
     { 
      Path.Combine(sdkPathToAdd), 
      Path.Combine("c:\anotherPath") 
     }; 
UpdatePath(paths); 

//Start using 
ApiCall(int numberOfEyes); 
Questions connexes