c#编程指南(十) 平台调用P-INVOKE完全掌握, 字符串和指针
可以说新手使用P-INVOKE最开始的头疼就是C#和C++的字符串传递,因为这里涉及到两个问题。
第一:C#的string和C++的字符串首指针如何对应。
第二:字符串还有ANSI和UNICODE(宽字符串)之分。
本文分三部分阐述:
第一:字符串指针当输入参数,
第二:字符串指针作为返回值,
第三:字符串指针作为输入输出参数。
C++部分的测试代码很简单这里就全部贴出来了:
1 #include "stdafx.h"
2 #include "TestDll.h"
3 #include <stdio.h>
4 #include <string.h>
5 #include <tchar.h>
6
7
8 static char * _hello = "Hello,World!!";
9 static TCHAR * _helloW = TEXT("Hello,World!!");
10
11 void __stdcall PrintString(char * hello)
12 {
13 printf("%s\n",hello);
14 }
15
16 void __stdcall PrintStringW(TCHAR * hello)
17 {
18 _tprintf(TEXT("%s\n"),hello);
19 }
20
21
22 char * __stdcall GetStringReturn()
23 {
24 return _hello;
25 }
26
27 TCHAR * __stdcall GetStringReturnW()
28 {
29 return _helloW;
30 }
31
32
33 void __stdcall GetStringParam(char * outHello,int len)
34 { //output "aaaaaaaa"
35 for(int i= 0; i< len -1 ;i++) outHello[i] = 'a';
36 outHello[len - 1] = '\0';
37 }
38
39 void __stdcall GetStringParamW(TCHAR * outHello,int len)40 { //output "aaaaaaaa" unicode version.41 for(int i= 0; i< len -1 ;i++) outHello[i] = TEXT('a');42 outHello[len - 1] = TEXT('\0');43 }
下面看C#如何调用。
第一:字符串指针作为输入参数,可以使用byte[] 和MarshalAs来解决。(注意四个P-INVOKE,两个ANSI版本,和两个UNICODE版本),推荐使用MarshalAs方法简单明了。
1 [DllImport("TestDll", EntryPoint = "PrintString")]
2 public static extern void PrintStringByBytes(byte[] hello);
3
4 [DllImport("TestDll", EntryPoint = "PrintString")]
5 public static extern void PrintStringByMarshal([MarshalAs(UnmanagedType.LPStr)]string hello);
6
7 [DllImport("TestDll", EntryPoint = "PrintStringW")]
8 public static extern void PrintStringByBytesW(byte[] hello);
9
10 [DllImport("TestDll", EntryPoint = "PrintStringW")]
11 public static extern void PrintStringByMarshalW([MarshalAs(UnmanagedType.LPWStr)]string hello);
12
13
14 public void Run()
15 {
16 PrintStringByBytes(Encoding.ASCII.GetBytes("use byte[]"));
17 PrintStringByMarshal("use MarshalAs");
18 PrintStringByBytesW(Encoding.Unicode.GetBytes("use byte[]"));
19 PrintStringByMarshalW("use MarshalAs");
20 }
第二:字符串指针作为返回值,和上面一样也有两种声明方法,同样也包含两个版本。注意:Marshal.PtrToStringAnsi()函数的使用,把字符串指针转变为C#的string.推荐使用MarshalAs方法简单明了。
1 [DllImport("TestDll", EntryPoint = "GetStringReturn")]
2 public static extern IntPtr GetStringReturnByBytes();
3
4 [DllImport("TestDll", EntryPoint = "GetStringReturn")]
5 [return:MarshalAs(UnmanagedType.LPStr)]
6 public static extern string GetStringReturnByMarshal();
7
8 [DllImport("TestDll", EntryPoint = "GetStringReturnW")]
9 public static extern IntPtr GetStringReturnByBytesW();
10
11 [DllImport("TestDll", EntryPoint = "GetStringReturnW")]
12 [return: MarshalAs(UnmanagedType.LPWStr)]
13 public static extern string GetStringReturnByMarshalW();
14
15
16 public void Run()
17 { //Marshal.PtrToStringAuto(GetStringReturnByBytes()); 自动判断类型不错。
18 Console.WriteLine(Marshal.PtrToStringAnsi(GetStringReturnByBytes()));
19 Console.WriteLine(GetStringReturnByMarshal());
20 Console.WriteLine(Marshal.PtrToStringUni(GetStringReturnByBytesW()));
21 Console.WriteLine(GetStringReturnByMarshalW());
22 }
第三:字符串指针作为输入输出参数时,因为要求有固定的容量,所以这里使用的是StringBuilder,大家仔细看了,当然也有byte[]版本。这个看大家喜欢那个版本就是用那个.
1 [DllImport("TestDll", EntryPoint = "GetStringParam")]
2 public static extern void GetStringParamByBytes(byte[] outHello, int len);
3
4 [DllImport("TestDll", EntryPoint = "GetStringParam")]
5 public static extern void GetStringParamByMarshal([Out, MarshalAs(UnmanagedType.LPStr)]StringBuilder outHello, int len);
6
7 [DllImport("TestDll", EntryPoint = "GetStringParamW")]
8 public static extern void GetStringParamByBytesW(byte[] outHello, int len);
9
10 [DllImport("TestDll", EntryPoint = "GetStringParamW")]
11 public static extern void GetStringParamByMarshalW([Out, MarshalAs(UnmanagedType.LPWStr)]StringBuilder outHello, int len);
12
13
14 public byte[] _outHello = new byte[10];
15 public byte[] _outHelloW = new byte[20];
16 public StringBuilder _builder = new StringBuilder(10); //很重要设定string的容量。
17
18 public void Run()
19 {
20 //
21 GetStringParamByBytes(_outHello, _outHello.Length);
22 GetStringParamByMarshal(_builder, _builder.Capacity);
23 GetStringParamByBytesW(_outHelloW, _outHelloW.Length / 2);
24 GetStringParamByMarshalW(_builder, _builder.Capacity);
25
26 //
27 Console.WriteLine(Encoding.ASCII.GetString(_outHello));
28 Console.WriteLine(_builder.ToString());
29 Console.WriteLine(Encoding.Unicode.GetString(_outHelloW));
30 Console.WriteLine(_builder.ToString());
31 }
32
c#编程指南(十) 平台调用P-INVOKE完全掌握, 字符串和指针的更多相关文章
- Lambda 表达式(C# 编程指南) 微软microsoft官方说明
Visual Studio 2013 其他版本 Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数. 通过使用 lambda 表达式,可以写入可作为参数传递或作为函数调用值返回的本地 ...
- (zz)Lambda 表达式(C# 编程指南)
https://msdn.microsoft.com/zh-cn/library/bb397687.aspx Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数.通过使用 lambd ...
- 高质量C++/C编程指南(林锐)
推荐-高质量C++/C编程指南(林锐) 版本/状态 作者 参与者 起止日期 备注 V 0.9 草稿文件 林锐 2001-7-1至 2001-7-18 林锐起草 V 1.0 正式文件 林锐 20 ...
- Swift语言指南(十)--字符串与字符
原文:Swift语言指南(十)--字符串与字符 字符串是一段字符的有序集合,如"hellow,world"或"信天翁".Swift 中的字符串由 String ...
- 《JavaScript面向对象编程指南(第2版)》读书笔记(一)
目录 一.对象 1.1 获取属性值的方式 1.2 获取动态生成的属性的值 二.数组 2.1 检测是否为数组 2.2 增加数组长度导致未赋值的位置为undefined 2.3 用闭包实现简易迭代器 三. ...
- 高质量C++/C编程指南
http://man.chinaunix.net/develop/c&c++/c/c.htm#_Toc520634042 高质量C++/C编程指南 文件状态 [ ] 草稿文件 [√] 正式文 ...
- <译>Flink编程指南
Flink 的流数据 API 编程指南 Flink 的流数据处理程序是常规的程序 ,通过再流数据上,实现了各种转换 (比如 过滤, 更新中间状态, 定义窗口, 聚合).流数据可以来之多种数据源 (比如 ...
- Archive for the ‘Erlang’ Category 《Erlang编程指南》读后感
http://timyang.net/category/erlang/ 在云时代,我们需要有更好的能利用多核功能及分布式能力的编程语言,Erlang在这方面具有天生的优势,因此我们始终对它保持强烈关注 ...
- C++编程指南续(10-11)
十.类的继承与组合 对象(Object)是类(Class)的一个实例(Instance).如果将对象比作房子,那么类就是房子的设计图纸.所以面向对象设计的重点是类的设计,而不是对象的设计. 对于C++ ...
随机推荐
- div里面的id与for
<input class="select" type="checkbox" value="1" id="checkboxjc ...
- database link远程链接数据库
--授权创建.删除dblink GRANT CREATE [PUBLIC] DATABASE LINK,DROP [PUBLIC] DATABASE LINK TO canco; --查看数据库GLO ...
- Coursera Machine Learning : Regression 评估性能
评估性能 评估损失 1.Training Error 首先要通过数据来训练模型,选取数据中的一部分作为训练数据. 损失函数可以使用绝对值误差或者平方误差等方法来计算,这里使用平方误差的方法,即: (y ...
- vertical-align 垂直居中
基线:字母‘x’的底部: 中线:与基线的距离为小写字母x高度的一半(即0.5ex),而ex同font-size相关,大部分浏览器认为1ex = 0.5em(em同样也是相对单位,不是绝对单位),因此会 ...
- Nginx-->基础-->理论-->001:Nginx基本介绍
一.nginx基本介绍 传统上基于进程或者线程模型架构的web服务通过每进程或者每线程处理并发连接请求,这势必毁在网络和I/O操作时产生阻塞,其另外一个必然结果则是对内存和CPU的利用率低下,产生一个 ...
- cannot find module 'xml2js'
运行nodejs网站报类似错误,缺少相应的报 在NodeJs安装目录,运行Node.js command prompt ,跳转到网站所在目录,运行npm install xml2js,安装缺少的模块, ...
- PHP数组合并 array_merge 与 + 的差异
在PHP数组合并出过几次问题都没记住,写下来加强一点记忆 PHP数组在合并时,使用 array_merge 与 + 的差异: 1.array_merge(array $array1 [, array ...
- Web API - Video File Streaming
关于C# WEBAPI 视频文件 http://www.codeproject.com/Articles/820146/HTTP-Partial-Content-In-ASP-NET-Web-API- ...
- 百度地图定位经纬度返回4.9E-324有关问题
1.查看你的应用是否有权限查看你的地理位置信息,有可能是你没有加上权限,或者当你第一次打开app时询问你是否给予软件权限查看你的地理位置信息,你选择了否,所以经纬度就一直返回4.9E-324 2.查看 ...
- ajax select option 数据。为了下次方便信手拈来!!
为了下次方便信手拈来!! 示例1 var form = document.forms["maddraddform"]; $(form.province).change(functi ...