C#处理VC++动态库回调函数的字符串指针参数(传递二进制流)
来源:互联网 发布:小知不及大知怎么读 编辑:程序博客网 时间:2024/05/22 00:42
副标题:C#中数据类型转换时用到的SizeParamIndex参数的含义
由于C#在调用VC++的库文件时,其代码为托管代码,所以C#和VC++的库之间数据在流转时就需要进行托管和非托管的转换,再加上C#中没有地址的概念,导致在VC++中的地址管理,在C#中根本用不上。其中的表现之一就是在C#中处理VC++库的内存指针相当麻烦,这不,今天就不得不面临这个问题了
库文件A.dll使用VC++生成,其中定义了一个回调函数,定义如下:
typedefUINT32 (CALLBACK *CBVideo)( UINT32 lUserData, ULONG flagPar, LONG datatype, LONG cmdLen, char *cmdBuf );
参数很简单,当然是除了最后一个参数
最后一个参数cmdBuf是一个char*,其实就是一个内存地址,cmdLen表示cmdBuf中有效数据的长度。需要注意的是,cmdBuf传递二进制数据,即中间可能存在0的字符串,所以不能采用简单的字符串来操作,否则第一个0后面的部分会被自动丢弃掉
在C#中定义如下:
public delegate uint CallbackDelegate(uint luserData, uint flagPar, int datatype, int cmdLen, byte[] bodyBytes);
不管回调的实际数据有多少,结果在C#中得到的bodyBytes只有一个字符,如果把bodyBytes的类型改为string:
public delegate uint CallbackDelegate(uint luserData, uint flagPar, int datatype, int cmdLen, string bodyBytes);
则回调时,cmdBuf中间不出现0时,一切正常,但如果有0出现,则从0开始往后面的数据全被截断!根据网上的一般方法修改如下:
public delegate uint CallbackDelegate(uint luserData, uint flagPar, int datatype, int cmdLen, [MarshalAs(UnmanagedType.LPArray,SizeParamIndex=1)] byte[] bodyBytes);
但问题依旧,仍然得不到正确的结果。
查看了很多的网页,大家都只有一个简单的说明,SizeParamIndex设置为1,但没有说明为什么,也试了不同的UnmanagedType类型,都不正确。
反复查看msdn,网址如下:
https://msdn.microsoft.com/zh-cn/magazine/system.runtime.interopservices.marshalasattribute.sizeparamindex
MarshalAsAttribute.SizeParamIndex 字段
其中示例的一个片段如下:
namespace SomeNamespace{ // Force the layout of your fields to the C style struct layout. // Without this, the .NET Framework will reorder your fields. [StructLayout(LayoutKind.Sequential)] public struct Vertex { floatx;floaty; floatz; } class SomeClass { // Add [In] or [In, Out] attributes as approppriate. // Marshal as a C style array of Vertex, where the second (SizeParamIndex is zero-based) // parameter (size) contains the count of array elements. [DllImport ("SomeDll.dll")] public static extern void SomeUnsafeMethod( [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] Vertex[] data, long size ); public void SomeMethod() { Vertex[] verts = new Vertex[3]; SomeUnsafeMethod( verts, verts.Length ); } }}
仔细查看 public static extern void SomeUnsafeMethod 一行上面的注释:
Marshal as a C style array of Vertex, where the second (SizeParamIndex is zero-based) parameter (size) contains the count of array elements.
反复捉摸,终于看出些门道,SizeParamIndex是指定data数组大小的那个参数的索引号!刚开始看这个属性名字很奇怪,很不顺,现在这样理解,就感觉完全正确了。
于是修改我的代码如下:
public delegate uint CallbackDelegate(uint luserData, uint flagPar, int datatype, int cmdLen, [MarshalAs(UnmanagedType.LPArray,SizeParamIndex=3)] byte[] bodyBytes);
把SizeParamIndex的值设置为3,即cmdLen在回调函数中以0为基础的索引号,然后再运行程序,一切OK!
至此,终于明白了这个SizeParamIndex参数的意义,以后如果遇到这种数据的传递,就再也不怕了
回顾一下,感觉这文章还是要仔细捉摸其所说的含义还是会有帮助的,虽然有时候确实难懂,但理解了之后,发现其说得确实没错。
希望对还没有弄明白是怎么回事的像我一样的程序猿们有所帮助
根据以上理解,一篇文章:
http://www.cnblogs.com/zeroone/p/3681370.html
的第4部分:
[DllImport("test.dll", EntryPoint = "#1")] publicstaticexternvoid test(int N, int[] n, [MarshalAs(UnmanagedType.LPArray,SizeParamIndex=1)] int[] Z);
中的SizeParamIndex显然不对,其值应该是0才对,因为N才是n和Z的元素个数。如果值为1,则成了n是个数,显然不符合实际的情况。其例子中的C++代码如下:
void__declspec(dllexport) test(constint M, constint n[], int *N) { for (int i=0; i<M; i++) { N[i]=n[i]+10; } }
- C#处理VC++动态库回调函数的字符串指针参数(传递二进制流)
- VC 回调函数的参数是如何处理的
- 回调函数 参数传递
- C#调用C++DLL,及回调函数、string参数传递的总结
- C#调用C/C++动态库的参数传递---数组指针的传递
- 关于sqlite_exec回调函数中参数传递的问题
- javascript的回调函数里如何传递参数
- javascript的回调函数里如何传递参数
- ajax回调函数参数传递
- Javascript AJAX回调函数传递参数
- Delphi使用C++库,向库中函数传递回调函数指针的问题解决
- 类函数指针的动态映射(回调函数)
- 函数指针作为参数&回调函数
- C# 调用Dll 传递字符串指针参数
- C# 调用Dll 传递字符串指针参数
- C# 调用Dll 传递字符串指针参数
- C/C++ 不带参数的回调函数 与 带参数的回调函数 函数指针数组 例子
- C# 调用C++动态库回调函数
- 源码安装postgresql9.5.1
- android5.0点击效果for4.x
- Java 入门 之 synchronized(this) 和 synchronized(object)
- hashCode和identityHashCode的区别
- 蓝桥杯 历届试题 大臣的旅费
- C#处理VC++动态库回调函数的字符串指针参数(传递二进制流)
- oracle创建触发器
- Virtualization-Cpu/Memory/IO虚拟化详解
- gdb调试命令
- Git 学习笔记(四)
- POJ百炼-2972-确定进制
- python开发_常用的python模块及安装方法
- Nginx配置文件各配置项详细说明
- iOS 应用内跳转到系统设置