平台调用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  
复制代码

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值