c#编程指南(十) 平台调用P-INVOKE完全掌握, 字符串和指针
2010-08-24 17:24
549 查看
可以说新手使用P-INVOKE最开始的头疼就是C#和C++的字符串传递,因为这里涉及到两个问题。
第一:C#的string和C++的字符串首指针如何对应。
第二:字符串还有ANSI和UNICODE(宽字符串)之分。
本文分三部分阐述:
第一:字符串指针当输入参数,
第二:字符串指针作为返回值,
第三:字符串指针作为输入输出参数。
C++部分的测试代码很简单这里就全部贴出来了:
下面看C#如何调用。
第一:字符串指针作为输入参数,可以使用byte[] 和MarshalAs来解决。(注意四个P-INVOKE,两个ANSI版本,和两个UNICODE版本),推荐使用MarshalAs方法简单明了。
第二:字符串指针作为返回值,和上面一样也有两种声明方法,同样也包含两个版本。注意:Marshal.PtrToStringAnsi()函数的使用,把字符串指针转变为C#的string.推荐使用MarshalAs方法简单明了。
第三:字符串指针作为输入输出参数时,因为要求有固定的容量,所以这里使用的是StringBuilder,大家仔细看了,当然也有byte[]版本。这个看大家喜欢那个版本就是用那个.
下载:代码
第一: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")] public static extern void PrintStringByBytes(byte[] hello); [DllImport("TestDll", EntryPoint = "PrintString")] public static extern void PrintStringByMarshal([MarshalAs(UnmanagedType.LPStr)]string hello); [DllImport("TestDll", EntryPoint = "PrintStringW")] public static extern void PrintStringByBytesW(byte[] hello); [DllImport("TestDll", EntryPoint = "PrintStringW")] public static extern void PrintStringByMarshalW([MarshalAs(UnmanagedType.LPWStr)]string hello); public void 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")] public static extern IntPtr GetStringReturnByBytes(); [DllImport("TestDll", EntryPoint = "GetStringReturn")] [return:MarshalAs(UnmanagedType.LPStr)] public static extern string GetStringReturnByMarshal(); [DllImport("TestDll", EntryPoint = "GetStringReturnW")] public static extern IntPtr GetStringReturnByBytesW(); [DllImport("TestDll", EntryPoint = "GetStringReturnW")] [return: MarshalAs(UnmanagedType.LPWStr)] public static extern string GetStringReturnByMarshalW(); public void 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")] public static extern void GetStringParamByBytes(byte[] outHello, int len); [DllImport("TestDll", EntryPoint = "GetStringParam")] public static extern void GetStringParamByMarshal([Out, MarshalAs(UnmanagedType.LPStr)]StringBuilder outHello, int len); [DllImport("TestDll", EntryPoint = "GetStringParamW")] public static extern void GetStringParamByBytesW(byte[] outHello, int len); [DllImport("TestDll", EntryPoint = "GetStringParamW")] public static extern void GetStringParamByMarshalW([Out, MarshalAs(UnmanagedType.LPWStr)]StringBuilder outHello, int len); public byte[] _outHello = new byte[10]; public byte[] _outHelloW = new byte[20]; public StringBuilder _builder = new StringBuilder(10); //很重要设定string的容量。 public void 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()); }
下载:代码
相关文章推荐
- c#编程指南(十) 平台调用P-INVOKE完全掌握, 字符串和指针
- c#编程指南(十三) 平台调用P-INVOKE完全掌握, 结构体和结构体指针
- c#编程指南(十一) 平台调用P-INVOKE完全掌握, 指针大全
- c#编程指南(十) 平台调用P-INVOKE完全掌握, 字符串和指针
- c#编程指南(九) 平台调用P-INVOKE完全掌握,C#和C++互相调用
- 平台调用P-INVOKE完全掌握, 字符串和指针
- c#编程指南(十五) 平台调用P-INVOKE完全掌握(完结篇),自定义Mashaler
- c#编程指南(十二) 平台调用P-INVOKE完全掌握, 结构体边界对齐和内存布局
- 平台调用P-INVOKE完全掌握, 指针大全
- 平台调用P-INVOKE完全掌握, 结构体和结构体指针
- 平台调用P-INVOKE完全掌握, 结构体和结构体指针
- c#编程指南——平台调用P-INVOKE完全掌握,C#和C++互相调用
- c#编程指南(十四) 平台调用P-INVOKE完全掌握, 反汇编细解结构体作为返回值
- 平台调用 4000 P-INVOKE完全掌握,C#和C++互相调用
- C#调用C++ 平台调用P/Invoke 结构体--含有内置数据类型的一维、二维数组、字符串指针【六】
- 平台调用P-INVOKE完全掌握, 结构体边界对齐和内存布局
- 平台调用P-INVOKE完全掌握, 反汇编细解结构体作为返回值
- 平台调用P-INVOKE(二)--(封送字符串)
- 平台调用P-INVOKE(二)--(封送字符串)
- 平台调用P-INVOKE(二)--(封送字符串)