这是P-INVOKE系列的最后一篇,也是万剑归宗的一篇,基本上只要函数签名对了,用他可以传递任何参数,函数的输入输出参数和返回值你也可以随心所欲地修改。
把这个放在最后也是最完美的结局吧!!
C++:测试代码如下:
1 struct Test 2 { 3 int test; 4 }; 5 6 //static Test _test; 7 8 Test GetTest(Test * lpTest) 9 { 10 lpTest->test = 200; 11 return * lpTest; 12 }
C#:在P-INVOKE中,我把C++指针参数Marshal成C#类的输入参数,把C++返回值为结构体的Marshal成字符串。注意下面的P-INVOKE声明。
UnmanagedType.CustomMarshaler表明使用自定义的marshaler.
1 [StructLayout(LayoutKind.Sequential)] 2 public class Test 3 { 4 public int test; 5 } 6 7 8 public class PInvokeTest 9 { 10 [DllImport("TestDll")] 11 [return:MarshalAs(UnmanagedType.CustomMarshaler,MarshalTypeRef=typeof(TestMashaler),MarshalCookie="output")] 12 public static extern string GetTest([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(TestMashaler), MarshalCookie = "input")] ref Test test); 13 //把返回值Marshal成字符串,自定义Marshal 参数。 14 15 public void Run() 16 { 17 Test test = new Test(); 18 test.test = 100; 19 20 string temp = GetTest(ref test); 21 Console.WriteLine(test.test + "," + temp); 22 } 23 24 }
自定义marshaler要实现ICustomMarshaler接口,并且提供一个类函数public static ICustomMarshaler GetInstance(string cookie),
微软方法的名字很好懂,我也不再一一解释了。关键地方代码中也有注释。
1 public class TestMashaler : ICustomMarshaler 2 { 3 private static object _refObject = null; 4 private string _cookie = string.Empty; 5 6 public TestMashaler(string cookie) 7 { 8 _cookie = cookie; //保存是输入参数使用的Mashaler,还是输出参数使用的Mashaler. 9 } 10 11 public void CleanUpManagedData(object ManagedObj) 12 { 13 } 14 15 public void CleanUpNativeData(IntPtr pNativeData) 16 { //清理非托管内存,防止内存泄露 17 Marshal.FreeHGlobal(pNativeData); 18 } 19 20 public int GetNativeDataSize() 21 { 22 return Marshal.SizeOf(typeof(Test)); 23 } 24 25 public IntPtr MarshalManagedToNative(object ManagedObj) 26 { 27 if (ManagedObj is Test) 28 { //保存ref引用。 29 if (_cookie == "input") _refObject = ManagedObj; 30 IntPtr p = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Test))); 31 Marshal.StructureToPtr(ManagedObj, p, false); 32 return p; //Marshal成指针。 33 } 34 else throw new NullReferenceException(); 35 } 36 37 public object MarshalNativeToManaged(IntPtr pNativeData) 38 { 39 if (pNativeData != IntPtr.Zero) 40 { 41 int temp = pNativeData.ToInt32(); 42 if (_cookie == "input") 43 { //输出参数返回 44 (_refObject as Test).test = temp; 45 return _refObject; 46 } 47 else if (_cookie == "output") 48 { //返回值返回。 49 return pNativeData.ToString(); 50 } 51 return null; 52 } 53 else throw new NullReferenceException(); 54 } 55 56 public static ICustomMarshaler GetInstance(string cookie) 57 { 58 return new TestMashaler(cookie); 59 } 60 }
最后还是建议大家使用微软提供的,自己实现的虽然很灵活很BT很邪门,但是还是很容易出错。上面的代码也仅供娱乐消遣了!!
下载:代码
|
请发表评论