平台调用P-INVOKE(二)--(封送字符串)
2012-11-13 09:02
471 查看
可以说新手使用P-INVOKE最开始的头疼就是C#和C++的字符串传递,由于不同编程语言对字符串处理的机制不同,因此导致托管代码的平台调用必须对字符串进行特殊的封送处理。本节将阐述以下几个问题:
(1)、C#的string和C++的字符串首指针如何对应
(2)、字符串还有ANSI和UNICODE(宽字符串)之分
(3)、封送字符串数组
1、通过CharSet字段控制字符串封送行为:
C++:
void __cdecl TestString1(
void __cdecl TestString2(const wchar_t* str,wchar_t* outStr,int size);
MSDN上给出C/C++字符串类型与C#字符串类型的对应关系
C#
[DllImport("test.dll", EntryPoint = "TestString1", CharSet =CharSet.Ansi)]
public static extern voidTestString1(string
[DllImport("test.dll", EntryPoint = "TestString1", CharSet =CharSet.Unicode)]
public static extern voidTestString2(stringstr,StringBuilder
outStr,int size)
2、使用MarshalAs属性控制字符串封送行为:
CharSet字段影响的是整个函数过程的字符串封送行为,MarshalAs属性只影响其作用的字符串参数。因此,当一个非托管函数的参数即由ANSI字符串,又有Unicode字符串时,就只能用MarshalAs属性来控制封送行为。
C++:
void __cdecl TestString3(const char* str1,const wchar_t* str2,wchar_t*
outStr,int size);
MSDN给出MarshalAs属性控制字符串封送行为:
需要注意的是:此表只适用于string类型,对于StringBuilder而言,能够允许的选项只有:LPStr、LPTStr、LPWStr。
C#:
[DllImport("test.dll",
EntryPoint = "TestString3")]
public static extern voidTestString3(
[MarshalAs(UnmanagedType.LPStr)]stringstr1,
[MarshalAs(UnmanagedType.LPWStr)]string
str2,
[MarshalAs(UnmanagedType.LPWStr)]stringoutStr,
int size);
3、封送作为返回值的字符串:
C++:
wchar_t*
CharSet = CharSet.Ansi)]
public static extern
[DllImport("test.dll", EntryPoint = "
CharSet = CharSet.Unicode)]
public
static extern
(2)、用IntPtr指针对应:
[DllImport("test.dll", EntryPoint = "
CharSet = CharSet.Ansi)]
public static extern
[DllImport("test.dll", EntryPoint = "
CharSet = CharSet.Unicode)]
public
static extern
以GetStringReturn2[/code]为例,给出C#如何使用:
string
ret="";
IntPtr
strPtr=GetStringReturn2[/code]();
ret=Marshal.PtrToStringUni(strPtr);
//对于IntPtr传递的变量,需要手工释放非托管内存
Marshal.FreeCoTaskMem(strPtr);
//释放非托管内存是互操作的一个难题,将在后面的章节做专门的介绍
4、封送字符串数组
C++:
(1)、C#的string和C++的字符串首指针如何对应
(2)、字符串还有ANSI和UNICODE(宽字符串)之分
(3)、封送字符串数组
1、通过CharSet字段控制字符串封送行为:
C++:
void __cdecl TestString1(
char* hello);
void __cdecl TestString2(const wchar_t* str,wchar_t* outStr,int size);
MSDN上给出C/C++字符串类型与C#字符串类型的对应关系
Wtypes.h 中的非托管类型 | 非托管C/C++ 语言类型 | 托管类名 | 说明 |
CHAR | char | System.Char | 用 ANSI 修饰。 |
LPSTR | char* | System.String 或 System.Text.StringBuilder | 用 ANSI 修饰。 |
LPCSTR | Const char* | System.String 或 System.Text.StringBuilder | 用 ANSI 修饰。 |
LPWSTR | wchar_t* | System.String 或 System.Text.StringBuilder | 用 Unicode 修饰。 |
LPCWSTR | Const wchar_t* | System.String 或 System.Text.StringBuilder | 用 Unicode 修饰。 |
[DllImport("test.dll", EntryPoint = "TestString1", CharSet =CharSet.Ansi)]
public static extern voidTestString1(string
hello);
[DllImport("test.dll", EntryPoint = "TestString1", CharSet =CharSet.Unicode)]
public static extern voidTestString2(stringstr,StringBuilder
outStr,int size)
2、使用MarshalAs属性控制字符串封送行为:
CharSet字段影响的是整个函数过程的字符串封送行为,MarshalAs属性只影响其作用的字符串参数。因此,当一个非托管函数的参数即由ANSI字符串,又有Unicode字符串时,就只能用MarshalAs属性来控制封送行为。
C++:
void __cdecl TestString3(const char* str1,const wchar_t* str2,wchar_t*
outStr,int size);
MSDN给出MarshalAs属性控制字符串封送行为:
枚举类型 | 非托管格式说明 |
UnmanagedType.AnsiBStr | 长度前缀为双字节的 Unicode字符的COM样式的BSTR。。 |
UnmanagedType.LPStr | 单字节、null空终止的 ANSI 字符数组的指针。(默认值) |
UnmanagedType.LPTStr | null空终止与平台相关的字符数组的指针。 |
UnmanagedType.LPWStr | null空终止与Unicode的字符数组的指针。 |
UnmanagedType.TBStr | 一个有长度前缀的与平台相关的 COM样式的BSTR。 |
C#:
[DllImport("test.dll",
EntryPoint = "TestString3")]
public static extern voidTestString3(
[MarshalAs(UnmanagedType.LPStr)]stringstr1,
[MarshalAs(UnmanagedType.LPWStr)]string
str2,
[MarshalAs(UnmanagedType.LPWStr)]stringoutStr,
int size);
3、封送作为返回值的字符串:
C++:
char* __cdecl GetStringReturn1();
wchar_t*
__cdecl",GetStringReturn2();
这里,有两种声明方法:
(1)、直接用string类型对应:
[DllImport("test.dll", EntryPoint = "[code]GetStringReturn1
CharSet = CharSet.Ansi)]
public static extern
string
GetStringReturn1();
[DllImport("test.dll", EntryPoint = "
GetStringReturn2",
CharSet = CharSet.Unicode)]
public
static extern
string
GetStringReturn2();
(2)、用IntPtr指针对应:
[DllImport("test.dll", EntryPoint = "
GetStringReturn1",
CharSet = CharSet.Ansi)]
public static extern
IntPtr
GetStringReturn1();
[DllImport("test.dll", EntryPoint = "
GetStringReturn2",
CharSet = CharSet.Unicode)]
public
static extern
IntPtrGetStringReturn2[/code]();
以GetStringReturn2[/code]为例,给出C#如何使用:
string
ret="";
IntPtr
strPtr=GetStringReturn2[/code]();
ret=Marshal.PtrToStringUni(strPtr);
//对于IntPtr传递的变量,需要手工释放非托管内存
Marshal.FreeCoTaskMem(strPtr);
//释放非托管内存是互操作的一个难题,将在后面的章节做专门的介绍
4、封送字符串数组
C++:
int TestArrayOfStrings(char* ppStrArray[], int size); C#: [ DllImport( "test.dll" )] public static extern int TestArrayOfStrings( [In, Out] String[] ppStrArray, int size ); 使用: String[] strArray = { "one", "two", "three", "four", "five" }; int lenSum = LibWrap.TestArrayOfStrings( strArray, strArray.Length );
相关文章推荐
- c#编程指南(十) 平台调用P-INVOKE完全掌握, 字符串和指针
- 平台调用P-INVOKE完全掌握, 字符串和指针
- C#调用C++ 平台调用P/Invoke 结构体--含有内置数据类型的一维、二维数组、字符串指针【六】
- C#调用C++ 平台调用P/Invoke 字符串【三】
- 平台调用P-INVOKE(二)--(封送字符串)
- 平台调用P-INVOKE(二)--(封送字符串)
- c#编程指南(十) 平台调用P-INVOKE完全掌握, 字符串和指针
- c#编程指南(十) 平台调用P-INVOKE完全掌握, 字符串和指针
- P/Invoke (平台调用)
- c#编程指南——平台调用P-INVOKE完全掌握,C#和C++互相调用
- 平台调用P-INVOKE(三)--(封送结构体)
- c#编程指南(十二) 平台调用P-INVOKE完全掌握, 结构体边界对齐和内存布局
- 平台调用P-INVOKE(一)--(基础篇)
- c#编程指南(十五) 平台调用P-INVOKE完全掌握(完结篇),自定义Mashaler
- 平台调用P-INVOKE完全掌握, 结构体边界对齐和内存布局
- C#调用C++ 平台调用P/Invoke 结构体--输入输出参数、返回值、返出值、结构体数组作为参数【五】
- .NET平台调用(Win32 P/Invoke)
- P/Invoke (平台调用)
- c#编程指南(十三) 平台调用P-INVOKE完全掌握, 结构体和结构体指针
- 平台调用P-INVOKE完全掌握, 结构体和结构体指针