1

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!

Mel Green
  • 3,571
  • 4
  • 26
  • 32
  • Put the path in the registry during install and call it out before loading the dll. – jmcecil Apr 10 '09 at 19:07
  • I don't see how this helps me, getting the path to the dll at runtime isn't a problem. It's declaring the function in code, using that dynamic path, that I'm trying to figure out. – Mel Green Apr 10 '09 at 19:08

3 Answers3

2

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.

Ken White
  • 123,280
  • 14
  • 225
  • 444
  • In this particular instance I'm unable to put the DLL in the same directory as my application, it's in a sub-directory of my app and I'm trying to use a relative path to declare it. Which works on some machines, but isn't consistent. =\ – Mel Green Apr 10 '09 at 19:34
  • Try importing SetDllDirectory from Kernel32 and call it setting Application.StartupPath. I'm going to try this with a project of mine at home when I get home today and I'll comment back when I test it. Hope that helps – Zack Apr 10 '09 at 19:55
  • That's rough. The only two possibilities I can think of are to add the path to the DLL to the system PATH during your install, or to write unsafe code to manually use LoadLibrary() and GetProcAddress() dynamically at runtime. Maybe someone else has better ideas, though. – Ken White Apr 10 '09 at 20:18
  • Better ideas, like Zack's. :-) Nice job. – Ken White Apr 10 '09 at 20:18
  • Thanks for the ideas Ken and Zack, sadly after further investigation I think I might have a bigger problem on my hands, since the DLL in question won't load even when placed in the same directory as my app (on this particular machine), so I've got some more debugging before I come to a solution. – Mel Green Apr 10 '09 at 20:25
2

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.

Erich Mirabal
  • 9,860
  • 3
  • 34
  • 39
0

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);
Hersker
  • 547
  • 5
  • 11