C#调用C++动态库(dll)

来源:互联网 发布:求生之路2 mac 编辑:程序博客网 时间:2024/05/29 19:33

在实际软件开发过程中,由于公司使用了多种语言开发,在C#中可能需要实现某个功能,而该功能可能用其他语言已经实现了,那么我们可以调用其他语言写好的模块吗?还有就是,由于C#开发好的项目,我们可以利用reflector等反编译工具反编译出其源代码,所以对于一些核心算法,我们不希望被别人知道,因此为了增强代码的安全性,我们需要将一些核心算法用C或C++来编写,然后用C#来调用这些已经写好的接口。在面对以上情况时,我们该怎么做呢?

 

 

 方案一:重新实现

       针对第一种情况,我们可以将C或者C++功能用C#来重新实现,这样的话代码比较统一,维护比较方便,但是这样的话增加了软件开发的成本,把C++的代码功能改成C#涉及到指针和内存的操作比较繁琐,况且有开发好的模块为什么不重复利用呢?针对第二种情况就不能得到有效解决,虽然可以使用混淆器对代码进行混淆,但是任然不是很安全。

 

 方案二:封装COM组件

       我们可以将C或者C++的函数封装成COM组件,在C#中调用时比较方便,但是COM组件需要注册,而且多次注册可能也会导致一些问题,同时在处理C或者C++的类型与COM组件的类型转换的时候也可能有些麻烦。

 

 

 方案三:使用动态链接库

       我们可以直接调用C或者C++已经写好的动态链接库,这样比较方便,这样很好的解决了上述问题。

 

 

 

       在实际项目中,我们需要使用C#调用C++的一些接口,因此我使用的是方案三采用动态库,下面我就在实际中怎么处理的进行说明。

       在调用动态库的过程中我也遇到了以下一些问题:

       1、C++中有指针,C#中需要使用指针吗?

       由于C++中的动态库中有指针参数,因此我也是用.NET的不安全代码,使用了C#的指针,但是最后也还是出现了一些问题,如在C#中传入的参数是一个二维数组时就出现了问题,这个问题我在网上找了好多资料也没有解决,最后和c++程序员商量了下改变了传入参数的参数类型。最后也没有使用指针。

       2、C#和C++中的类型如何转换呢?

       虽然C#和C++比较类似,但是其给我们的参数类型我们要与C#的参数类型一一对应起来,因此我找了一些资料把其类型一一对应了,具体看后续说明。

       3、C++写好的动态库放到那个位置呢?

       关于C++动态库的位置也是个问题,在应用中我们使用了相对路径和绝对路径进行测试,有的发现在VS中可以调用到,但是发布后发现无法调用到动态库,最后只要把动态的dll放到系统的目录system32下面才解决了改问题,目前还没找到其他的方法,如有其他的更好方法还请大家指点。

       4、如何反编译C++的dll的名称,端口?

       可以通过Dependency Walker工具进行反编译查看别人写的动态库的信息

       5、还有其他的一些细节,如C#调用动态库需要指定其编码、代码写法等等

 

c#调用c++动态库一般我们这样写

 

[DllImport("UCamer.dll",CallingConvention = CallingConvention.Winapi)]

public extern static voidDisp_Destroy(IntPtr hShow);

DllImport的第一个参数UCamer.dll是动态库dll的路径,此dll放在程序运行的根目录或者c:windows/sytem32下

 CallingConvention 参数是c#调用c++的方式是个枚举 msdn解释如下

 

  

 

Cdecl        调用方清理堆栈。这使您能够调用具有 varargs 的函数(如 Printf),使之可用于接受可变数目的参数的方法。

FastCall    不支持此调用约定。

StdCall      被调用方清理堆栈。这是使用平台 invoke 调用非托管函数的默认约定。

ThisCall    第一个参数是 this 指针,它存储在寄存器ECX 中。其他参数被推送到堆栈上。此调用约定用于对从非托管 DLL 导出的类调用方法。

Winapi      此成员实际上不是调用约定,而是使用了默认平台调用约定。例如,在 Windows 上默认为 StdCall,在 Windows CE.NET 上默认为 Cdecl。

 从上面来看Winapi方式是根据系统自动选择调用规约的。 而thisCall是对c++类的调用方法。 所以 一般情况下我们选择Winapi就可以了。

 

例子:

 

       #region 无标题窗体右键任务栏弹出菜单代码

 

       [DllImport("user32.dll", EntryPoint ="GetWindowLong", CharSet = CharSet.Auto)]

       public static extern int GetWindowLong(HandleRef hWnd, int nIndex);

 

       [DllImport("user32.dll", EntryPoint ="SetWindowLong", CharSet = CharSet.Auto)]

       public static extern IntPtr SetWindowLong(HandleRef hWnd, int nIndex,int dwNewLong);

 

       protected override CreateParams CreateParams

       {

           get

           {

                const int WS_MINIMIZEBOX =0x00020000;  // Winuser.h中定义  

                CreateParams cp =base.CreateParams;

                cp.Style = cp.Style |WS_MINIMIZEBOX;   // 允许最小化操作  

                return cp;

           }

       }

 

       #endregion

 

       #region 窗体拖动代码

       [DllImport("user32.dll")]

       public static extern bool ReleaseCapture();

        [DllImport("user32.dll")]

       public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam,int lParam);

       public const int WM_SYSCOMMAND = 0x0112;

       public const int SC_MOVE = 0xF010;

       public const int HTCAPTION = 0x0002;

       private void Login_MouseDown(object sender, MouseEventArgs e)

       {

           ReleaseCapture();

           SendMessage(this.Handle, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);

       }

       #endregion

 

 

       [DllImport("wininet.dll")]

       private extern static bool InternetGetConnectedState(out int conn, intval);

       private void btnNetTest_Click(object sender, EventArgs e)

       {

           int Out;

           if (InternetGetConnectedState(out Out, 0) == true)

           {

               MessageDxUtil.ShowTips("Internet网络连通!");

           }

           else

           {

               MessageDxUtil.ShowTips("Internet网络不通!");

           }

 

       }

 

VS2010查看DLL导出函数的方法

 

在window下查看动态库的导出函数可以用vs自带的Dependenc工具;

对于VC6.0,VC所带的Depends软件,在VC6安装目录下的tools文件夹里面,可以直接运行。

 

 

 

VS2010中没有了Depends工具,如何查看DLL文件的导出接口呢? 

VS2010的操作方法如下:

 

1. 打开命令行窗口CMD

 

2. 运行vcvarsall.bat

 

VS2010 里vcvarsall.bat是在右键VS打开文件位置,D:\MicrosoftVisual Studio 10.0\Common7\Tools目录下,运行方法是直接将vcvarsall.bat文件拖入命令行窗口,然后回车。(拖入相当于在命令行中输入“D:\Microsoft Visual Studio 10.0\Common7\Tools\vcvarsall.bat”)

 

运行vcvarsall.bat后,窗口中出现“Setting environment for using Microsoft Visual Studio 2010 x86tools.”

 

3. 在命令行了输命令:dumpbin/exports dll文件完整路径,即可得到DLL的接口。

 

如要查看user32.dll的接口,输入:dumpbin /exports “C:\Windows\System32\user32.dll” 回车即可。

 

其中,步骤2可以省去,方法是不在运行中打开命令行窗口,而是在应用程序Microsoft Visual Studio 2010的Visual Studio Tools文件夹中打开VisualStudio Command Prompt (2010)命令窗口,可发现窗口中直接有“Setting environment for using Microsoft Visual Studio 2010 x86 tools”这句话,此时,直接输入命令:dumpbin /exports dll文件完整路径,即可得到DLL的接口。

 

其它内容:

查看静态库的信息要用命令行来实现:

 

dumpbin  /LINKERMEMBER   Test.lib   >  1.txt

 

上面的功能是将静态库的信息导出保存在1.txt文件中,这样就可以在1.txt文件中查看相关的信息了

 

错误:`DllImport' could not be found

 

 

 

方法:给你的类添加"usingSystem.Runtime.InteropServices;"