PInvoke複習之C# C++ 字符串傳遞

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

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

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

 

本文分三部分闡述:測試

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

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

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

 

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

#include "stdafx.h"
 #include "TestDll.h"
 #include <stdio.h>
 #include <string.h>
 #include <tchar.h>
 
 
  staticchar* _hello ="Hello,World!!";
  static TCHAR * _helloW = TEXT("Hello,World!!");

 void __stdcall PrintString(char* hello)
{
    printf("%s\n",hello);
}

 void __stdcall PrintStringW(TCHAR * hello)
{
    _tprintf(TEXT("%s\n"),hello);
}


 char*  __stdcall GetStringReturn()
{
return _hello;
}

TCHAR * __stdcall GetStringReturnW()
{
return _helloW;
}


 void __stdcall GetStringParam(char* outHello,int len)
{  //output "aaaaaaaa"
 for(int i=1; i< len -1 ;i++) outHello[i] ='a';
    outHello[len -] ='\';
}

 void __stdcall GetStringParamW(TCHAR * outHello,int len)
{ //output "aaaaaaaa" unicode version.
 for(int i=1; i< len -1 ;i++) outHello[i] = TEXT('a');
    outHello[len -] = TEXT('\');
}

下面看C#如何調用。ci

 

第一:字符串指針做爲輸入參數,能夠使用byte[] 和MarshalAs來解決。(注意四個P-INVOKE,兩個ANSI版本,和兩個UNICODE版本),推薦使用MarshalAs方法簡單明瞭。unicode

        [DllImport("TestDll", EntryPoint ="PrintString")]
 publicstaticexternvoid PrintStringByBytes(byte[] hello);
 
         [DllImport("TestDll", EntryPoint ="PrintString")]
 publicstaticexternvoid PrintStringByMarshal([MarshalAs(UnmanagedType.LPStr)]string hello);
 
         [DllImport("TestDll", EntryPoint ="PrintStringW")]
 publicstaticexternvoid PrintStringByBytesW(byte[] hello);
 
        [DllImport("TestDll", EntryPoint ="PrintStringW")]
publicstaticexternvoid PrintStringByMarshalW([MarshalAs(UnmanagedType.LPWStr)]string hello);


publicvoid Run()
        {
            PrintStringByBytes(Encoding.ASCII.GetBytes("use byte[]"));
            PrintStringByMarshal("use MarshalAs");
            PrintStringByBytesW(Encoding.Unicode.GetBytes("use byte[]"));
            PrintStringByMarshalW("use MarshalAs");
}

第二:字符串指針做爲返回值,和上面同樣也有兩種聲明方法,一樣也包含兩個版本。注意:Marshal.PtrToStringAnsi()函數的使用,把字符串指針轉變爲C#的string.推薦使用MarshalAs方法簡單明瞭。

 [DllImport("TestDll", EntryPoint ="GetStringReturn")]
 publicstaticextern IntPtr GetStringReturnByBytes();
 
         [DllImport("TestDll", EntryPoint ="GetStringReturn")]
         [return:MarshalAs(UnmanagedType.LPStr)]
 publicstaticexternstring GetStringReturnByMarshal();
 
         [DllImport("TestDll", EntryPoint ="GetStringReturnW")]
 publicstaticextern IntPtr GetStringReturnByBytesW();

        [DllImport("TestDll", EntryPoint ="GetStringReturnW")]
        [return: MarshalAs(UnmanagedType.LPWStr)]
publicstaticexternstring GetStringReturnByMarshalW();


publicvoid Run()
        {          //Marshal.PtrToStringAuto(GetStringReturnByBytes()); 自動判斷類型不錯。
             Console.WriteLine(Marshal.PtrToStringAnsi(GetStringReturnByBytes()));
            Console.WriteLine(GetStringReturnByMarshal());
            Console.WriteLine(Marshal.PtrToStringUni(GetStringReturnByBytesW()));
            Console.WriteLine(GetStringReturnByMarshalW());
}

第三:字符串指針做爲輸入輸出參數時,由於要求有固定的容量,因此這裏使用的是StringBuilder,你們仔細看了,固然也有byte[]版本。這個看你們喜歡那個版本就是用那個.

 

  [DllImport("TestDll", EntryPoint ="GetStringParam")]
 publicstaticexternvoid GetStringParamByBytes(byte[] outHello, int len);
 
         [DllImport("TestDll", EntryPoint ="GetStringParam")]
 publicstaticexternvoid GetStringParamByMarshal([Out, MarshalAs(UnmanagedType.LPStr)]StringBuilder outHello, int len);
 
         [DllImport("TestDll", EntryPoint ="GetStringParamW")]
 publicstaticexternvoid GetStringParamByBytesW(byte[] outHello, int len);
 
        [DllImport("TestDll", EntryPoint ="GetStringParamW")]
publicstaticexternvoid GetStringParamByMarshalW([Out, MarshalAs(UnmanagedType.LPWStr)]StringBuilder outHello, int len);


publicbyte[] _outHello =newbyte[];
publicbyte[] _outHelloW =newbyte[];
public StringBuilder _builder =new StringBuilder(); //很重要設定string的容量。
 
publicvoid Run()
        {
//
             GetStringParamByBytes(_outHello, _outHello.Length);
            GetStringParamByMarshal(_builder, _builder.Capacity);
            GetStringParamByBytesW(_outHelloW, _outHelloW.Length /);
            GetStringParamByMarshalW(_builder, _builder.Capacity);

//
             Console.WriteLine(Encoding.ASCII.GetString(_outHello));
            Console.WriteLine(_builder.ToString());
            Console.WriteLine(Encoding.Unicode.GetString(_outHelloW));
            Console.WriteLine(_builder.ToString());
}
相關文章
相關標籤/搜索