打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
c#编程指南(十) 平台调用P-INVOKE完全掌握, 字符串和指针
c#编程指南(十) 平台调用P-INVOKE完全掌握, 字符串和指针

可以说新手使用P-INVOKE最开始的头疼就是C#和C++的字符串传递,因为这里涉及到两个问题。

第一:C#的string和C++的字符串首指针如何对应。

第二:字符串还有ANSI和UNICODE(宽字符串)之分。

本文分三部分阐述:

第一:字符串指针当输入参数,

第二:字符串指针作为返回值,

第三:字符串指针作为输入输出参数。

C++部分的测试代码很简单这里就全部贴出来了:

1 #include "stdafx.h" 2 #include "TestDll.h" 3 #include <stdio.h> 4 #include <string.h> 5 #include <tchar.h> 6 7 8 static char * _hello = "Hello,World!!"; 9 static TCHAR * _helloW = TEXT("Hello,World!!");10 11 void __stdcall PrintString(char * hello)12 {13 printf("%s\n",hello);14 }15 16 void __stdcall PrintStringW(TCHAR * hello)17 {18 _tprintf(TEXT("%s\n"),hello);19 }20 21 22 char * __stdcall GetStringReturn()23 {24 return _hello;25 }26 27 TCHAR * __stdcall GetStringReturnW()28 {29 return _helloW;30 }31 32 33 void __stdcall GetStringParam(char * outHello,int len)34 { //output "aaaaaaaa"35 for(int i= 0; i< len -1 ;i++) outHello[i] = 'a';36 outHello[len - 1] = '\0';37 }38 39 void __stdcall GetStringParamW(TCHAR * outHello,int len)40 { //output "aaaaaaaa" unicode version.41 for(int i= 0; i< len -1 ;i++) outHello[i] = TEXT('a');42 outHello[len - 1] = TEXT('\0');43 }

下面看C#如何调用。

第一:字符串指针作为输入参数,可以使用byte[] 和MarshalAs来解决。(注意四个P-INVOKE,两个ANSI版本,和两个UNICODE版本),推荐使用MarshalAs方法简单明了。

1 [DllImport("TestDll", EntryPoint = "PrintString")]
2 public static extern void PrintStringByBytes(byte[] hello);
3
4 [DllImport("TestDll", EntryPoint = "PrintString")]
5 public static extern void PrintStringByMarshal([MarshalAs(UnmanagedType.LPStr)]string hello);
6
7 [DllImport("TestDll", EntryPoint = "PrintStringW")]
8 public static extern void PrintStringByBytesW(byte[] hello);
9
10 [DllImport("TestDll", EntryPoint = "PrintStringW")]
11 public static extern void PrintStringByMarshalW([MarshalAs(UnmanagedType.LPWStr)]string hello);
12
13
14 public void Run()
15 {
16 PrintStringByBytes(Encoding.ASCII.GetBytes("use byte[]"));
17 PrintStringByMarshal("use MarshalAs");
18 PrintStringByBytesW(Encoding.Unicode.GetBytes("use byte[]"));
19 PrintStringByMarshalW("use MarshalAs");
20 }

第二:字符串指针作为返回值,和上面一样也有两种声明方法,同样也包含两个版本。注意:Marshal.PtrToStringAnsi()函数的使用,把字符串指针转变为C#的string.推荐使用MarshalAs方法简单明了。

1 [DllImport("TestDll", EntryPoint = "GetStringReturn")] 2 public static extern IntPtr GetStringReturnByBytes(); 3 4 [DllImport("TestDll", EntryPoint = "GetStringReturn")] 5 [return:MarshalAs(UnmanagedType.LPStr)] 6 public static extern string GetStringReturnByMarshal(); 7 8 [DllImport("TestDll", EntryPoint = "GetStringReturnW")] 9 public static extern IntPtr GetStringReturnByBytesW();10 11 [DllImport("TestDll", EntryPoint = "GetStringReturnW")]12 [return: MarshalAs(UnmanagedType.LPWStr)]13 public static extern string GetStringReturnByMarshalW();14 15 16 public void Run()17 { //Marshal.PtrToStringAuto(GetStringReturnByBytes()); 自动判断类型不错。18 Console.WriteLine(Marshal.PtrToStringAnsi(GetStringReturnByBytes()));19 Console.WriteLine(GetStringReturnByMarshal());20 Console.WriteLine(Marshal.PtrToStringUni(GetStringReturnByBytesW()));21 Console.WriteLine(GetStringReturnByMarshalW());22 }

第三:字符串指针作为输入输出参数时,因为要求有固定的容量,所以这里使用的是StringBuilder,大家仔细看了,当然也有byte[]版本。这个看大家喜欢那个版本就是用那个.

1 [DllImport("TestDll", EntryPoint = "GetStringParam")]
2 public static extern void GetStringParamByBytes(byte[] outHello, int len);
3
4 [DllImport("TestDll", EntryPoint = "GetStringParam")]
5 public static extern void GetStringParamByMarshal([Out, MarshalAs(UnmanagedType.LPStr)]StringBuilder outHello, int len);
6
7 [DllImport("TestDll", EntryPoint = "GetStringParamW")]
8 public static extern void GetStringParamByBytesW(byte[] outHello, int len);
9
10 [DllImport("TestDll", EntryPoint = "GetStringParamW")]
11 public static extern void GetStringParamByMarshalW([Out, MarshalAs(UnmanagedType.LPWStr)]StringBuilder outHello, int len);
12
13
14 public byte[] _outHello = new byte[10];
15 public byte[] _outHelloW = new byte[20];
16 public StringBuilder _builder = new StringBuilder(10); //很重要设定string的容量。
17
18 public void Run()
19 {
20 //
21 GetStringParamByBytes(_outHello, _outHello.Length);
22 GetStringParamByMarshal(_builder, _builder.Capacity);
23 GetStringParamByBytesW(_outHelloW, _outHelloW.Length / 2);
24 GetStringParamByMarshalW(_builder, _builder.Capacity);
25
26 //
27 Console.WriteLine(Encoding.ASCII.GetString(_outHello));
28 Console.WriteLine(_builder.ToString());
29 Console.WriteLine(Encoding.Unicode.GetString(_outHelloW));
30 Console.WriteLine(_builder.ToString());
31 }
32

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
如何通过使用 Visual C#.net 将原始数据发送到打印机
C# 调用动态链接库读取二代身份证信息
C#程序调用非托管C++ DLL文件的方法 - Chase的技术博客 - 博客园
C#调用dll时的类型转换总结
C# 禁用控制台应用程序关闭按钮
Inheriting From a Native C++ Class in C#
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服