5

Possible Duplicate:
Specify the search path for DllImport in .NET

I have an unmanaged DLL. For clearance, its a C++ dll that I want to use in my c# code. The problem is that its a windows app and user can install it in any directory of their choice. So I can't reference it with a static path and I couldn't find a way to give a relative path. Here is the code I tried :

 [DllImport("mydll.dll", CharSet = CharSet.Auto, SetLastError = true)]
  static extern bool SetDllDirectory(string lpPathName);

  public void SetDllDirectory(string lpPathName)
        {
            try
            {
                bool r = SetDllDirectory(lpPathName);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void SetDirectoryPath()
        {
            try
            {
                DirectoryInfo directory = new DirectoryInfo(System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath));
                if (directory.Exists)
                    SetDllDirectory(directory.ToString() + "\\mydll.dll");

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

And below is the error I am receiving.

Unable to find an entry point named 'SetDllDirectory' in DLL 'mydll.dll'.

This question could be a replica of

"C++ unmanaged DLL in c#"

"Relative Path to DLL in Platform Invoke Statement"

Sorry for that but I didn't find any solution in these references.

Community
  • 1
  • 1
Deepak Kumar
  • 672
  • 4
  • 15
  • 31
  • Yes, and I tried that approach. But it didn't work. Sorry for that. – Deepak Kumar Feb 13 '12 at 07:31
  • you tried the PATH hack or SetDllDirectory() ? – IanNorton Feb 13 '12 at 07:32
  • 4
    I think that error message is not about where the DLL is located - I think it has found the DLL fine but it cannot find the function in the DLL - are you sure the p/invoke signature is correct and that the function is exported? – kmp Feb 13 '12 at 07:35
  • You need to be sure that SetDllDirectory gets called before any of your pinvokes. You could also look at AddDllDirectory() and LoadLibraryEx() – IanNorton Feb 13 '12 at 07:36
  • Please look at the code above. I am calling SetDirectoryPath() function in the constructor of the my class. – Deepak Kumar Feb 13 '12 at 07:36
  • @user1039947:- I think you are right. I just copied that function and tried on mydll.dll. I am not sure if it has such function or not. I assumed that every DLL has this function. – Deepak Kumar Feb 13 '12 at 07:38
  • @Deepak yes, but you are trying to invoke SetDllDirectory() from mydll.dll. This is a windows function. – IanNorton Feb 13 '12 at 07:38
  • Please provide some working code if possible. – Deepak Kumar Feb 13 '12 at 07:39

2 Answers2

5

If you are trying to pinvoke into an unmanaged library that is in a non-standard location you need to add this location to the dll search path that windows uses to look for dll files.

If your users can tell the program where the c/c++ library file is, you can load it manually when they choose it.

public class UnsafeNativeMethods {
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool SetDllDirectory(string lpPathName);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern int GetDllDirectory(int bufsize, StringBuilder buf);

    [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern IntPtr LoadLibrary(string librayName);

    [DllImport("mylibrary")]
    public static extern void InitMyLibrary();
}

You can call the above in some form of preload routine like so:

public void LoadDllFile( string dllfolder, string libname ) {
    var currentpath = new StringBuilder(255);
    UnsafeNativeMethods.GetDllDirectory( currentpath.Length, currentpath );

    // use new path
    UnsafeNativeMethods.SetDllDirectory( dllfolder );

    UnsafeNativeMethods.LoadLibrary( libname );

    // restore old path
    UnsafeNativeMethods.SetDllDirectory( currentpath );
}

You might then call it like so:

LoadDllFile( "c:\whatever", "mylibrary.dll" );
Zachary Canann
  • 1,131
  • 2
  • 13
  • 23
IanNorton
  • 7,145
  • 2
  • 25
  • 28
  • Thanks Norton. But the end users has no knowledge about the DLL. Would this approach work in this scenario? – Deepak Kumar Feb 13 '12 at 07:53
  • 1
    The amount of code you've posted is *way* more than necessary. All you need is `SetDllDirectory`; just let the P/Invoke marshaler do all the rest. See [my answer here](http://stackoverflow.com/a/8861895/366904) for details and sample code. – Cody Gray - on strike Feb 13 '12 at 08:57
  • @Deepak if the end user doesn't know where the DLL is, how do you find it? You could search the filesystem and then use this I suppose. – IanNorton Feb 13 '12 at 20:04
1

This error message:

Unable to find an entry point named 'SetDllDirectory' in DLL 'mydll.dll'.

says nothing about not being able to find the DLL. It says that your P/Invoke definition is incorrect. There is no function named SetDllDirectory in your DLL (mydll.dll). And why should there be? The only functions that are exported from DLLs are those that you explicitly code and export. Since you didn't write code for a SetDllDirectory and indicate that it should be exported from mydll.dll, it doesn't exist in the DLL.

Beyond that, this question is unanswerable unless you update your question with real code. You need to post, at minimum, the signature for the function you're trying to call from the unmanaged DLL, along with the P/Invoke code that you've tried on the C# (managed) side.

The problem is that its a windows app and user can install it in any directory of their choice. So I can't reference it with a static path and I couldn't find a way to give a relative path.

This is not a real problem. Relative paths work just fine, and they work in exactly the way that your question indicates that you've already tried. You just include the name of the DLL in the P/Invoke definition. The default DLL search order takes care of everything else. If the managed EXE is in the same directory as the unmanaged DLL that you want to P/Invoke, everything will work seamlessly.

It doesn't matter where the user chooses to install the app, so long as the DLL and the EXE are located in the same folder. And that's the job of your installer.

And so long as you use relative paths, you absolutely do not need to use the SetDllDirectory function from the Win32 API (which is actually defined in kernel32.dll).

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574