2012-02-13 83 views
3

可能重复:
Specify the search path for DllImport in .NET非托管DLL的相对路径

我有一个非托管的DLL。对于清除,它是一个我想在我的C#代码中使用的C++ dll。 问题是,它的Windows应用程序和用户可以安装在他们选择的任何目录。所以我不能用静态路径来引用它,而且我也找不到一个给出相对路径的方法。 这里是我试过的代码:

[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; 
      } 
     } 

,下面将我收到错误。

无法在DLL'mydll.dll'中找到名为'SetDllDirectory'的入口点。

这个问题可能是

C++ unmanaged DLL in c#

Relative Path to DLL in Platform Invoke Statement

对不起,一个副本,但我没有发现这些引用的任何解决方案。

+0

是的,我试过这种方法。但它没有奏效。对不起。 – 2012-02-13 07:31:17

+0

你试过PATH hack或SetDllDirectory()? – IanNorton 2012-02-13 07:32:55

+0

我试过SetDllDirectory() – 2012-02-13 07:33:55

回答

1

此错误消息:

无法在DLL'mydll中找到名为'SetDllDirectory'的入口点。 DLL”。

说不能找到DLL。它说你的P/Invoke定义不正确。在您的DLL中没有名为SetDllDirectory的函数(mydll.dll)。为什么要这样呢?从DLL中导出的唯一函数是您明确编码和导出的函数。由于您没有编写SetDllDirectory的代码,并且表明它应该从mydll.dll导出,所以它不存在于DLL中。

除此之外,这个问题是无法回答的,除非你用真实的代码更新你的问题。您至少需要发布您试图从非托管DLL调用的函数的签名,以及您在C#(托管)端尝试过的P/Invoke代码。

问题是,它的Windows应用程序和用户可以安装在他们选择的任何目录。所以我不能用静态路径来引用它,而且我也找不到一个给出相对路径的方法。

这不是一个真正的问题。相对路径工作得很好,它们的工作方式与您的问题表明您已经尝试过的方式完全相同。您只需在P/Invoke定义中包含DLL的名称。默认的DLL搜索顺序负责其他所有操作。如果托管的EXE与您要P/Invoke的非托管DLL位于同一目录中,则所有内容都可以无缝工作。

只要DLL和EXE位于同一文件夹中,用户选择安装应用程序的位置并不重要。这就是你的安装程序的工作。

而只要你使用相对路径,你绝对需要使用SetDllDirectory函数从Win32 API(这是在kernel32.dll实际上定义)。

+0

- 感谢人...你已经度过了我的一天。 – 2012-02-13 09:27:23

4

如果您试图调入非标准位置的非托管库,则需要将此位置添加到Windows用来查找dll文件的dll搜索路径。

如果您的用户可以告诉程序c/C++库文件的位置,您可以在选择它时手动加载它。

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(); 
} 

您可以拨打上面的某种形式的预加载程序的,像这样:

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); 
} 

你可以再调用它像这样:

LoadDllFile("c:\whatever", "mylibrary.dll"); 
+0

谢谢诺顿。但最终用户不了解DLL。这种方法在这种情况下会起作用吗? – 2012-02-13 07:53:18

+1

您发布的代码数量超过必要。所有你需要的是'SetDllDirectory';让P/Invoke封送员完成剩下的工作。有关详细信息和示例代码,请参见[我的答案](http://stackoverflow.com/a/8861895/366904)。 – 2012-02-13 08:57:09

+0

@Deepak如果最终用户不知道DLL在哪里,你怎么找到它?你可以搜索文件系统,然后使用这个我想。 – IanNorton 2012-02-13 20:04:48