您的位置:首页 > 编程语言 > C#

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

2014-08-19 17:33 609 查看
可以说新手使用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>

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=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());
}




下载:代码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: