c#編程指南(十) 平臺調用P-INVOKE徹底掌握, 字符串和指針

能夠說新手使用P-INVOKE最開始的頭疼就是C#和C++的字符串傳遞,由於這裏涉及到兩個問題。函數

第一:C#的string和C++的字符串首指針如何對應。測試

第二:字符串還有ANSI和UNICODE(寬字符串)之分。ui

 

本文分三部分闡述:spa

第一:字符串指針當輸入參數,指針

第二:字符串指針做爲返回值,code

第三:字符串指針做爲輸入輸出參數。blog

 

C++部分的測試代碼很簡單這裏就所有貼出來了:ci

 

複製代碼
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#如何調用。unicode

 

第一:字符串指針做爲輸入參數,能夠使用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  
複製代碼
相關文章
相關標籤/搜索