Reputation: 3801
I have a DLL that I need to access methods from.
In most cases like this I just use [DllImport] to access methods from unmanaged assemblies, but the problem with that in this situation is that it requires the path to the DLL at instantiation time, so a constant string.
This particular DLL is one that gets installed with my application and I can't guarantee where it will be after the program is installed (I'd rather not put it somewhere static like %SystemRoot%).
So is there a way in C# that I can declare and use a method from a DLL at runtime with a variable path?
Any ideas or suggestions would be greatly appreciated!
Upvotes: 1
Views: 4546
Reputation: 547
I had a similar situation. I use DLLs from a SDK that is installed on the machine. I get the directory location of the DLLs from that SDKs registry key. I set the DLL location on the executing users PATH variable (only temporary modification). Basically it allows you to set a dynamic path for the DLL you want to invoke, so it don't have to be from registry. Mind that the PATH var is the last place Windows looks for DLLs. But on the other hand, it does not change the other places Windows looks for DLLs.
Example:
API i want to call, on the DLL:
[DllImport("My.DLL")]
private static extern IntPtr ApiCall(int param);
Get the registry key (you need using 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;
}
Add the path of the DLL on the PATH var (Concat() is found in 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);
}
Start Using the API call:
var sdkPathToAdd = GetRegistryKeyPath();
IList<string> paths = new List<string>
{
Path.Combine(sdkPathToAdd),
Path.Combine("c:\anotherPath")
};
UpdatePath(paths);
//Start using
ApiCall(int numberOfEyes);
Upvotes: 0
Reputation: 10038
This is a bit of hack, but since you say that you can find the path to the dll at runtime, why not copy it to your current working directory before you use any of the functions? That way, the dll will exist next to your exe and will be found by LoadLibrary. No need for any additional path in your DllImport.
The only other way to use a method from a dynamic path is to do this:
1) Do the necessary P/Invoke signatures for LoadLibrary & GetProcAddress
2) Load the library from the desired path (LoadLibrary)
3) Find the desired function (GetProcAddress)
4) Cast the pointer to a delegate Marshal.GetDelegateForFunctionPointer
5) Invoke it.
Of course, you will need to declare a delegate for each function you want to "import" in this way since you have to cast the pointer to a delegate.
Upvotes: 2
Reputation: 125661
Don't use a path at all. Windows uses a default method of searching for DLLs when trying to dynamically or statically load a function from it.
The exact search logic is documented at MSDN in the docs for LoadLibrary - basically, if the DLL is just used by your app, put in the same folder as your application during the install and don't worry about it. If it's a commonly used DLL, put it somewhere in the folder structure searched by LoadLibrary() and it'll get found.
Upvotes: 2