首先必须要有一个声明,使用的是DllImport关键字: 包含DllImport所在的名字空间
using System.Runtime.InteropServices; public class XXXX{
[DllImport(“MyDLL.dll\")]
public static extern int mySum (int a,int b); }
[DllImport(“MyDLL.dll\")]
public static extern int mySum (int a,int b);
代码中DllImport关键字作用是告诉编译器入口点在哪里,并将打包函数捆绑在这个类中 在调用的时候
在类中的时候 直接 mySum(a,b);就可以了 在其他类中调用: XXXX. mySum(a,b);
[DllImport(“MyDLL.dll”)]在申明的时候还可以添加几个属性 [DllImport(“MyDLL.dll\
\
]
EntryPoint: 指定要调用的 DLL 入口点。默认入口点名称是托管方法的名称 。 CharSet: 控制名称重整和封送 String 参数的方式 (默认是UNICODE)
CallingConvention指示入口点的函数调用约定(默认WINAPI)(上次报告讲过的)
SetLastError 指示被调用方在从属性化方法返回之前是否调用 SetLastError Win32 API 函数 (C#中默认false )
int 类型
[DllImport(“MyDLL.dll\")] //返回个int 类型
public static extern int mySum (int a1,int b1); //DLL中申明
extern “C” __declspec(dllexport) int WINAPI mySum(int a2,int b2) {
//a2 b2不能改变a1 b1 //a2=.. //b2=... return a+b;
}
//参数传递int 类型
public static extern int mySum (ref int a1,ref int b1); //DLL中申明
extern “C” __declspec(dllexport) int WINAPI mySum(int *a2,int *b2) {
//可以改变 a1, b1 *a2=... *b2=... return a+b; }
DLL 需传入char *类型 [DllImport(“MyDLL.dll\")] //传入值
public static extern int mySum (string astr1,string bstr1); //DLL中申明
extern “C” __declspec(dllexport) int WINAPI mySum(char * astr2,char * bstr2) {
//改变astr2 bstr 2 ,astr1 bstr1不会被改变 return a+b; }
DLL 需传出char *类型 [DllImport(“MyDLL.dll\")] // 传出值
public static extern int mySum (StringBuilder abuf, StringBuilder bbuf ); //DLL中申明
extern “C” __declspec(dllexport) int WINAPI mySum(char * astr,char * bstr) {
//传出char * 改变astr bstr -->abuf, bbuf可以被改变 return a+b; }
DLL 回调函数
BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam)
using System;
using System.Runtime.InteropServices;
public delegate bool CallBack(int hwnd, int lParam); //定义委托函数类型 public class EnumReportApp {
[DllImport(\"user32\")]
public static extern int EnumWindows(CallBack x, int y); public static void Main() {
CallBack myCallBack = new CallBack(EnumReportApp.Report); EnumWindows(myCallBack, 0);
}
public static bool Report(int hwnd, int lParam) {
Console.Write(\"Window handle is \"); Console.WriteLine(hwnd); return true; } }
DLL 传递结构 (见代码)
BOOL PtInRect(const RECT *lprc, POINT pt);
using System.Runtime.InteropServices; [StructLayout(LayoutKind.Sequential)] public struct Point { public int x; public int y; }
[StructLayout(LayoutKind.Explicit)] public struct Rect {
[FieldOffset(0)] public int left; [FieldOffset(4)] public int top; [FieldOffset(8)] public int right; [FieldOffset(12)] public int bottom; }
Class XXXX {
[DllImport(\"User32.dll\")]
public static extern bool PtInRect(ref Rect r, Point p); }
C#托管代码与C++非托管代码互相调用一(C#调用
C++代码&.net 代码安全)
在最近的项目中,牵涉到项目源代码保密问题,由于代码是C#写的,容易被反编译,因此决定抽取核心算法部分使用C++编写,C++到目前为止好像还不能被很好的反编译,当然如果你是反汇编高手的话,也许还是有可能反编译。这样一来,就涉及C#托管代码与C++非托管代码互相调用,于是调查了一些资料,顺便与大家分享一下
一. C# 中静态调用C++动态链接
1. 建立VC工程CppDemo,建立的时候选择Win32 Console(dll),选择Dll。 2. 在DllDemo.cpp文件中添加这些代码。
extern \"C\" __declspec(dllexport) int Add(int a,int b) {
return a+b; }
3. 编译工程。
4. 建立新的C#工程,选择Console应用程序,建立测试程序InteropDemo 5. 在Program.cs中添加引用:using System.Runtime.InteropServices; 6. 在pulic class Program添加如下代码: using System;
using System.Collections.Generic; using System.Text;
using System.Runtime.InteropServices;
namespace InteropDemo {
class Program {
[DllImport(\"CppDemo.dll\EntryPoint = \"Add\ExactSpelling = false, CallingConvention = CallingConvention.Cdecl)]
public static extern int Add(int a, int b); //DllImport请参照MSDN
static void Main(string[] args) {
Console.WriteLine(Add(1, 2)); Console.Read(); } } }
好了,现在您可以测试Add程序了,是不是可以在C# 中调用C++动态链接了,当然这是静态调用,需要将CppDemo编译生成的Dll放在DllDemo程序的Bin目录下
二. C# 中动态调用C++动态链接
在第一节中,讲了静态调用C++动态链接,由于Dll路径的限制,使用的不是很方便,C#中我们经常通过配置动态的调用托管Dll,例如常用的一些设计模式:Abstract Factory, Provider, Strategy模式等等,那么是不是也可以这样动态调用C++动态链接呢?只要您还记得在C++中,通过LoadLibrary, GetProcess, FreeLibrary这几个函数是可以动态调用动态链接的(它们包含在kernel32.dll中),那么问题迎刃而解了,下面我们一步一步实验
1. 将kernel32中的几个方法封装成本地调用类NativeMethod using System;
using System.Collections.Generic; using System.Text;
using System.Runtime.InteropServices;
namespace InteropDemo {
public static class NativeMethod {
[DllImport(\"kernel32.dll\EntryPoint = \"LoadLibrary\")]
public static extern int LoadLibrary( [MarshalAs(UnmanagedType.LPStr)] string lpLibFileName);
[DllImport(\"kernel32.dll\EntryPoint = \"GetProcAddress\")]
public static extern IntPtr GetProcAddress(int hModule, [MarshalAs(UnmanagedType.LPStr)] string lpProcName);
[DllImport(\"kernel32.dll\EntryPoint = \"FreeLibrary\")] public static extern bool FreeLibrary(int hModule); } }
2. 使用NativeMethod类动态读取C++Dll,获得函数指针,并且将指针封装成C#中的委托。原因很简单,C#中已经不能使用指针了,如下
int hModule = NativeMethod.LoadLibrary(@\"c:\"CppDemo.dll\"); IntPtr intPtr = NativeMethod.GetProcAddress(hModule, \"Add\");
详细请参见代码 using System;
using System.Collections.Generic; using System.Text;
using System.Runtime.InteropServices;
namespace InteropDemo {
class Program {
//[DllImport(\"CppDemo.dll\EntryPoint = \"Add\ExactSpelling = false, CallingConvention = CallingConvention.Cdecl)]
//public static extern int Add(int a, int b); //DllImport请参照MSDN
static void Main(string[] args) {
//1. 动态加载C++ Dll
int hModule = NativeMethod.LoadLibrary(@\"c:CppDemo.dll\"); if (hModule == 0) return;
//2. 读取函数指针
IntPtr intPtr = NativeMethod.GetProcAddress(hModule, \"Add\");
//3. 将函数指针封装成委托
Add addFunction = (Add)Marshal.GetDelegateForFunctionPointer(intPtr, typeof(Add));
//4. 测试
Console.WriteLine(addFunction(1, 2)); Console.Read(); }
///
/// /// ///
通过如上两个例子,我们可以在C#中动态或者静态的调用C++写的代码了
因篇幅问题不能全部显示,请点此查看更多更全内容