C# C++ 字符串传递

本文深入探讨了在C#与C++间使用P-Invoke进行字符串传递的问题,包括ANSI和UNICODE字符串的区别及如何通过MarshalAs属性简化调用过程。

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

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

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

 

本文分三部分阐述:

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

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

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

 

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

 


 

#include "stdafx.h"

#include "TestDll.h"

#include <stdio.h>

#include <string.h>

#include <tchar.h>

 static char* _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=0; i< len -1 ;i++) outHello[i] ='a';  

outHello[len -1] ='\0';

}

void __stdcall GetStringParamW(TCHAR * outHello,int len) {

//output "aaaaaaaa" unicode version.

for(int i=0; i< len -1 ;i++) outHello[i] = TEXT('a');

outHello[len -1] = TEXT('\0');

}

 

 

 

下面看C#如何调用。

 

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

 


 

[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[10];

publicbyte[] _outHelloW =newbyte[20];

public StringBuilder _builder =new StringBuilder(10); //很重要设定string的容量。

publicvoid Run() {

//   GetStringParamByBytes(_outHello, _outHello.Length);

GetStringParamByMarshal(_builder, _builder.Capacity);

GetStringParamByBytesW(_outHelloW, _outHelloW.Length /2);

GetStringParamByMarshalW(_builder, _builder.Capacity);

//  Console.WriteLine(Encoding.ASCII.GetString(_outHello));

Console.WriteLine(_builder.ToString());

Console.WriteLine(Encoding.Unicode.GetString(_outHelloW));

Console.WriteLine(_builder.ToString());

}

评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值