2012-07-17 67 views
1

我想从非托管C++中写入的32位和64位DLL导入一些函数到我的C#项目中。作为一个样本,我这样做:动态和静态导入非托管C++ DLL到C#不起作用

C++ DLL函数

long mult(int a, int b) { 
    return ((long) a)*((long) b); 
} 

C#代码

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Runtime.InteropServices; 

namespace ConsoleApplication2 
{ 
    class DynamicDLLImport 
    { 
     private IntPtr ptrToDll; 
     private IntPtr ptrToFunctionToCall; 

     [DllImport("kernel32.dll")] 
     public static extern IntPtr LoadLibrary(string dllToLoad); 

     [DllImport("kernel32.dll")] 
     public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); 

     [DllImport("kernel32.dll")] 
     public static extern bool FreeLibrary(IntPtr hModule); 

     [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 
     private delegate int Multiply(int a, int b); 
     private Multiply multiply; 

     public DynamicDLLImport(string dllName) 
     { 
      ptrToDll = LoadLibrary(dllName); 
      // TODO: Error handling. 

      ptrToFunctionToCall = GetProcAddress(ptrToDll, "mult"); 
      // TODO: Error handling. 

      // HERE ARGUMENTNULLEXCEPTION 
      multiply = (Multiply)Marshal.GetDelegateForFunctionPointer(ptrToFunctionToCall, typeof(Multiply)); 
     } 

     public int mult_func(int a, int b) 
     { 
      return multiply(a, b); 
     } 

     ~DynamicDLLImport() 
     { 
      FreeLibrary(ptrToDll); 
     } 
    } 

    class DLLWrapper 
    { 
     private const string Sixtyfour = "c:\\Users\\Hattenn\\Documents\\Visual Studio 2010\\Projects\\ConsoleApplication2\\ConsoleApplication2\\easyDLL0_64.dll"; 
     private const string Thirtytwo = "c:\\Users\\Hattenn\\Documents\\Visual Studio 2010\\Projects\\ConsoleApplication2\\ConsoleApplication2\\easyDLL0.dll"; 
//  [DllImport(Sixtyfour)] 
//  public static extern int mult(int a, int b); 
     [DllImport(Thirtytwo)] 
     public static extern int mult(int a, int b); 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      int a = 5; 
      int b = 4; 
      DynamicDLLImport dllimp = new DynamicDLLImport("easyDLL0.dll"); 

      Console.WriteLine(DLLWrapper.mult(a, b)); 
      //Console.WriteLine(dllimp.mult_func(a, b)); 

      Console.ReadKey(); 
     } 
    } 
} 

我似乎无法得到它的工作。这里是我得到的错误消息:

  1. 当我使用DLLWrapper类与32位DLL文件我得到“DLLNotFoundException”,但DLL文件正是在该路径。
  2. 当我使用带有64位DLL文件的DLLWrapper类并将“Platform Target”属性更改为“x64”时,我得到相同的“DLLNotFoundException”,如果我尝试使用“x86”构建,那么会得到“BadImageException” 。
  3. 当我使用DynamicDLLImport类时,我总是在代码中的“HERE ARGUMENTNULLEXCEPTION”注释行中得到“ArgumentNullException”。

我在做什么错?

回答

1

原来,这个问题是该DLL部署在调试模式,而不是以正确的方式进行检查。当它以释放模式部署时,一切似乎都正常。任何有类似问题的人都应该知道,在调试模式下编译dll并将其复制到另一台计算机并不是正确的方法。

0

Windows需要能够在运行时找到DLL,而不仅仅是编译时间。将DLL放在二进制文件夹中,或者放在PATH的某个地方,静态导入就可以工作。

+0

我也试过,还是一样的错误。 – hattenn 2012-07-17 08:38:49

+0

你是否声明'mult'作为一个dll导出方法? – zmbq 2012-07-17 08:39:54

+0

我确实从同事那里得到了DLL,但他知道他在做什么,所以我不指望它没有声明为dll导出方法。 – hattenn 2012-07-17 08:41:57

0

你的C#方法声明不符合C++的一个:

long mult(int a, int b) 

private delegate int Multiply(int a, int b); 

尝试改变返回类型多长时间?

+0

VC++ long是32bit,C#long是64bit。另外,除非使用某些名称装饰方案,否则无法以这种方式验证DLL,否则它会在运行时崩溃。 – 2012-07-17 10:25:45

1

你是如何从DLL中导出函数的? Windows DLL不会自动导出所有的函数,并且C++将修饰名称,例如除非告诉它不要,否则确切地说编译器是如何特定的,而其他语言肯定不理解这些名称。

您可以通过启动Visual Studio命令提示符,然后使用命令

dumpbin /EXPORTS "your library.dll" 
+0

你可以在http://p.boxnet.eu/11903/看到结果,我认为它看起来是正确的。 – hattenn 2012-07-17 10:48:07

+0

嗯,看起来不错,你的ptrToDll不是null?如果ptrToDll和函数名称匹配,GetProcAddress应该明确地返回一个有效的指针。 DllImport我相信可能会做一些额外的事情来改变它,例如使用stdcall你可能会将该函数导出为_mult @ 8,并且Windows API具有ASCII和Unicode的A和W功能。说到这一点,请确保C++和C#调用约定匹配,否则您可能会在稍后损坏您的堆栈(大多数x86 C默认为cdecl,而.NET我认为默认为stdcall)。 – 2012-07-17 16:19:13