在 上篇文章重点讲解数据类型的转换,在此基础上再讲解函数调用。

1、函数调用

c++中函数

INF_NET_API  INF_RESULT WINAPI INF_NET_GetList(long  lLoginHandle,DWORD dwInfoContol,BYTE**  pBuf,LONG&  lBufSize);

C# 中函数

  [DllImport(_strCoreSDK)]
public static extern int INF_NET_GetList(Int32 lLoginHandle, UInt32 dwInfoContol,IntPtr _Deviceinfoptr, ref Int32 lBufSize);

说明:常见的数值类型,正常转化;指针类型、引用类型直接转化为ref 数值类型。其中byte ** ,这种类型根据在c++中调用,是存储数组的地址,所以在单纯的用ref,不能解决问题。针对此问题,都可以用intptr,关键就是intptr怎么指向,下面重点讲讲如何结构体怎么访问。

在函数调用时为:

iErr = INF_NET_GetList(g_lHandle, , (BYTE**)&m_pMonitorInfo, lMonSize);

其中m_pMonitorInfo是结构体数组,所以此函数是获取一系列结构体,针对此,在c#函数中相对应声明为Intptr。

C#中看看如何利用Intptr,传入地址,还有获取数据。

 int iDev_size = Marshal.SizeOf(typeof(INFINOVASDK.INF_NET_DEVICE_INFO));
//定义一个存储指针的数组
IntPtr[] _IntptrDevArray = new IntPtr[];
//初始化指针数组大小
_IntptrDevArray[] = Marshal.AllocHGlobal(iDev_size * );//分配包含100元素的数组
//查询设备指针
IntPtr _IntptrDevInfo = Marshal.AllocHGlobal(iDev_size);
//存储设备指针于数组指针
Marshal.Copy(_IntptrDevArray, , _IntptrDevInfo, );//拷贝指针数组
int buffeesize = ;
int err = INFINOVASDK.INF_NET_GetList(_loginIds[control], , _IntptrDevInfo, ref buffeesize);
if (err != )
{
return null;
} //从指针数组开始获取数据
for (int i = ; i < ; i++)
{
//设定好指针的偏移量
INFINOVASDK.INF_NET_DEVICE_INFO _deviceInfo = (INFINOVASDK.INF_NET_DEVICE_INFO)Marshal.PtrToStructure((IntPtr)((UInt32)_IntptrDevArray[] + i * iDev_size), typeof(INFINOVASDK.INF_NET_DEVICE_INFO)); if (_deviceInfo.cDevIP != null)
{
//获取设备的Ip以及MAC
bytes_DevIp = _deviceInfo.cDevIP;
bytes_Mac = _deviceInfo.cDevMac;
break;
} }
//释放申请的内存空间
Marshal.FreeHGlobal(_IntptrDevInfo);
Marshal.FreeHGlobal(_IntptrDevArray[]);

下面讲讲另一个函数
c++函数

INF_NET_API  INF_RESULT WINAPI INF_NET_FindFile (long &  lFindHandle, INF_HANDLE    lLoginHandle, LPINDEX_INFO pFindCondition,LPINDEX_INFO  pRecvIndex);	

上面函数中后两个参数,类型都是结构体指针,但是在函数调用的时,不一样。倒数第二个是传入结构体的指针,指向一个结构体。倒数第一个指向结构体数组的,是 获取的结构体数组。

   [DllImport(_strCoreSDK)]
public static extern int INF_NET_FindFile(ref Int32 lFindHandle, Int32 lLoginHandle, IntPtr FIleptr, IntPtr RecordFileInfo);

接口函数,按照说明进行声明。

C#函数调用,此方法和上面还不太相同。

 //初始化查询录像文件对象
 INFINOVASDK.NET_INDEX_INFO _FindFileInfo = new INFINOVASDK.NET_INDEX_INFO();

            _FindFileInfo.dwStartTime = (uint)DatetimeToLong(startTime);
_FindFileInfo.dwEndTime = (uint)DatetimeToLong(endTime);
//查询条件,全部文件
_FindFileInfo.btFileType = (byte)0xFF;
//摄像机ID
_FindFileInfo.dwIP4 = UInt32.Parse(cameraId);
//平台设备的Ip、以及MAc
_FindFileInfo.dwIP1 = BitConverter.ToUInt32(bytes_DevIp, );
_FindFileInfo.wChan = UInt16.Parse(devicechn);
_FindFileInfo.btMAC = bytes_Mac;
_FindFileInfo.dwReserved = ;
_FindFileInfo.Reserved = new byte[];//此处应初始化,防止向指针赋值时出错。 try
{
List<FileItem> files = new List<FileItem>();
//开始获取录像文件,并定义最多取100个文件 //开始设置查询录像文件的指针
int iIndexSize = Marshal.SizeOf(typeof(INFINOVASDK.NET_INDEX_INFO));
IntPtr _IntptrInedx = Marshal.AllocHGlobal(iIndexSize);
Marshal.StructureToPtr(_FindFileInfo, _IntptrInedx, false);//在用Marshal类进行托管对象和非托管对象的转换时,会有如下错误提示:“未能封送类型,因为嵌入数组实例的长度与布局中声明的长度不匹配。”所以针对结构体内数组要初始化,再赋值。看看赋值结构体内数组大小和初始化时结构体内数组大小是否相等。
//定义存储录像文件数组,并初始化
INFINOVASDK.NET_INDEX_INFO[] _ArrayFile = new INFINOVASDK.NET_INDEX_INFO[ * ];
for (int i = ; i < _ArrayFile.Length; i++)
{//结构体初始化,防止出错
_ArrayFile[i] = new INFINOVASDK.NET_INDEX_INFO();
_ArrayFile[i].Reserved = new byte[];//针对数组专门初始化,关键是指明大小。
_ArrayFile[i].btMAC = new byte[]; }
//录像文件数组定义个指针,并在内存空间申请的大小
IntPtr _IntptrRecordFiles = Marshal.AllocHGlobal(iIndexSize * * );
//查询录像文件
int iFindhandle = ;
_errorCode = INFINOVASDK.INF_NET_FindFile(ref iFindhandle, _loginIds[control], _IntptrInedx, _IntptrRecordFiles);
if (_errorCode != )
{
return null;
}
for (int i = ; i < ; i++)
{
_ArrayFile[i] = (INFINOVASDK.NET_INDEX_INFO)Marshal.PtrToStructure((IntPtr)((UInt32)_IntptrRecordFiles + i * iIndexSize), typeof(INFINOVASDK.NET_INDEX_INFO)); if (_ArrayFile[i].dwStartTime != )
{
_NetRecordFiles.Add(_ArrayFile[i]);
//获取录像文件的起止时间
DateTime tempstart = LongToDateTime(_ArrayFile[i].dwStartTime);//将datetime格式转化为int类型。
DateTime tempend = LongToDateTime(_ArrayFile[i].dwEndTime);
string strstarttime = tempstart.ToString("yyyyMMddHHmmss");
string strendtime = tempend.ToString("yyyyMMddHHmmss");
FileItem _RecordFile = new FileItem();
_RecordFile.FileName = strstarttime + "_" + strendtime;
_RecordFile.StartTime = tempstart;
_RecordFile.EndTime = tempend;
files.Add(_RecordFile); } }
Marshal.FreeHGlobal(_IntptrInedx);
Marshal.FreeHGlobal(_IntptrRecordFiles);
return files;
}

这个是之前复杂版本。

 byte []_devipBytes = new byte [];
byte []_macbytes = new byte [];
//此前结构体内将char[]改为了string,结构看到数据是乱码,所以需要进行数据转化。
byte[] bytes = Encoding.UTF8.GetBytes(_deviceInfo.cDevIP); //_deviceInfo.cDevIP是string类型
//编码转化
byte[] tempdef = Encoding.Convert(Encoding.UTF8, Encoding.Default, bytes);
//此处你会发现_devipBytes 原先大小为20,此时由于tempdef;为4,然后此时_devipBytes 也为4,这样是不对的。
_devipBytes = tempdef;
byte[] bytes1 = Encoding.UTF8.GetBytes(_deviceInfo.cDevMac);
byte[] tempdef1 = Encoding.Convert(Encoding.UTF8, Encoding.Default, bytes1);
//所以byte复制到byte,用此方法,这样不会改便byte[]的大小
Array.Copy(tempdef1, _macbytes, );
如果想byte转到string,可以一个个获取。

C# 默认的编码方式是Unicode,而调用的DLL规定只处理UTF8编码格式的字符串,DLL中的输入参数类型char*被我Marshal成byte[],输出参数类型char**被我Marshal成了string。用于接收时的string-->string(UTF8-->Unicode),会发现接受的数据string时为乱码,所以还要转化为char[],才能看到正确数据。用于发送时,还需要string-->byte[](Unicode-->UTF8)这样频繁的编码转换,看来编码转换并非想象中那么简单:所以针对这种现场,当char * 作为传入数据时,直接处理为char * 》》string。  
  (一)、Encoding和CharSet
 在C#中包装DLL的时候,DllImportAttribute当中的选项CharSet着:规定封送字符串应使用何种字符集,其中枚举值有Ansi和Unicode,CharSet是字符集,用于字符传送,Encoding代表编码方式,用于数据转化。字符集是字符的集合,规定这个集合里有哪些字符,每个字符都有一个整数编号(只是编号不是编码);而编码是用来规定字符编号如何与二进制交互,每个“字符”分别用一个字节还是多个字节存储。CharSet表明在数据封送的字符集以什么方式封送,然后在获取到数据为乱码时,则通过Encoding里面的函数,将数据转化,则获取到正确数据。
  (二)、Ansi、Unicode、UTF8、bala bala
   提到字符集,有ASCII、GB2312、GBK、GB18030、BIG5、JIS等等多种,与此相对应的编码方式为ASCII、GB2312、GBK、GB18030、BIG5、JIS,但是Unicode字符集却有多种编码方式:UTF-8、 UTF-7、UTF-16、 UnicodeLittle、UnicodeBig,意味可以讲数据按照上述编码方式进行转化。   Ansi:系统编码的发展经历了三个阶段,ASCIIàAnsi(不同国家语言本地化)àUnicode(标准化),原来Ansi编码也好,Ansi字符集也好,都是指本地化的东西,在简体中文系统下,ANSI
编码代表 GB2312 编码,Windows下自带的记事本程序,默认的就是ANSI编码。输入“anhui合肥”(不含引号),保存编码方式选“ANSI”,查看,哦,9个字节,明白了,原来Ansi编码保留了对ASCII编码的兼容,当遇到ASCII字符时,采用单字节存储,当遇到非ASCII编码时,采用双字节表示(GB2312编码)。
  (三)、DllImportAttribute中的CharSet枚举值选择
  对字符集和编码的概念清楚了以后,终于可以研究C#中调用非托管的DLL的方法咯。从托管应用程序去调用非托管代码,如果CharSet=Unicode,则DLL中的接口函数将出现的所有字符串(包括参数和返回值)视为Unicode字符集,Ansi一样的道理
  第一:我需要调用非托管代码,第二:非托管代码只处理UTF8编码格式的字符,第三,万恶的中文乱码,接口函数签名中,无论参数还是返回值,接收到或是发送出的字符串都含有中文。首先接收字符串,因为接收到的是UTF8编码格式,CharSet属性肯定要设置成Unicode了,接收后要正确显示中文,在当前系统中,需要将编码方式转换成GB2312,即Encoding.Default;另外关于发送字符数组,因为无论是C#中默认的Unicode编码方式,还是DLL处理时规定的UTF8编码方式,都是Unicode字符集的一种编码方式,所以CharSet也要设置成Unicode,只是要在发送前需要将字符数组转换一下编码方式。以下附带两个简单的函数实现。
// 转换接收到的字符串

public string UTF8ToUnicode(string recvStr)
{
byte[] tempStr = Encoding.UTF8.GetBytes(recvNotify);
byte[] tempDef = Encoding.Convert(Encoding.UTF8, Encoding.Default, tempStr);
string msgBody = Encoding.Default.GetString(tempDef);
return msgBody;
}
// 转换要发送的字符数组
public byte[] UnicodeToUTF8(string sendStr)
{
string tempStr = Encoding.UTF8.GetString(sendStr);
byte[] msgBody = Encoding.UTF8.GetBytes(tempUTF8);
return msgBody;
}

下面是常用的几个函数

 private DateTime LongToDateTime(uint times)
{
long _times =(long)times + ;
DateTime ds = new DateTime(, , , , , ,DateTimeKind.Unspecified).AddSeconds(_times);
return ds;
} private byte [] StructToBytes(Object structobj , int size)
{
byte []tempBytes = new byte [size];
IntPtr strcutIntptr = Marshal.AllocHGlobal(size);
//将结构体拷贝到内存中
Marshal.StructureToPtr(structobj, strcutIntptr, false);
//从内存空间拷贝到byte数组中
Marshal.Copy(strcutIntptr, tempBytes, , size);
Marshal.FreeHGlobal(strcutIntptr);
return tempBytes; } private object BytesToStruct(byte[] bytes ,Type _type)
{
int _size = Marshal.SizeOf(_type);
IntPtr structInnptr = Marshal.AllocHGlobal(_size);
Marshal.Copy(bytes, , structInnptr, _size);
object obj = Marshal.PtrToStructure(structInnptr, _type);
Marshal.FreeHGlobal(structInnptr);
return obj;
} private byte [] IntptrToBytes (IntPtr tempIntptr ,int _size)
{
byte[] tempBytes = new byte[_size];
//从内存空间拷贝到byte数组中
Marshal.Copy(tempIntptr, tempBytes, , _size);
return tempBytes;
} private IntPtr BytesToInptr(byte[] bytes, Type _type)
{
int _size = Marshal.SizeOf(_type);
IntPtr structInnptr = Marshal.AllocHGlobal(_size);
Marshal.Copy(bytes, , structInnptr, _size);
return structInnptr;
}

C#与C++函数调用的更多相关文章

  1. idapython实现动态函数调用批量注释

    部门小伙伴遇到一个样本需要对动态函数调用就行批量注释还原的问题,通过idapython可以大大的减少工作量,其实这一问题也是很多样本分析中最耗时间的一块,下面来看看如何解决这个问题(好吧这才是今年最后 ...

  2. [汇编与C语言关系]1.函数调用

    对于以下程序: int bar(int c, int d) { int e = c + d; return e; } int foo(int a, int b) { return bar(a, b); ...

  3. javascript函数调用的各种方法!!

    在JavaScript中一共有下面4种调用方式: (1) 基本函数调用 (2)方法调用 (3)构造器调用 (4)通过call()和apply()进行调用 1. 基本函数调用 普通函数调用模式,如: J ...

  4. jsContext全局函数调用与对象函数调用、evaluateScript

    evaluateScript:兼具js加载(生成具体的上下文)(函数与通用变量的加载),与函数执行的功能: 函数调用的方式有两种: 1)获取函数(对象),然后执行调用: [context[@" ...

  5. 用 Graphviz+pvtrace 可视化函数调用

    最近在想怎么把一个程序的函数调用关系快速的用流程图的方式画出来,之后看到了这个一篇文章“用 Graphviz 可视化函数调用”(http://www.ibm.com/developerworks/cn ...

  6. 行内js函数调用

    <ul> <li onclick=abc(this);><a href="javascript:void(0);">12234588</a ...

  7. ObReferenceObjectByName函数调用WIN7下的解决

    <寒江独钓 Windows内核安全编程>第4章键盘的过滤ctrl2cap代码中,ObReferenceObjectByName函数调用: [1]extern POBJECT_TYPE Io ...

  8. c语言函数, 函数调用及函数递归

    1. 函数的定义: 返回值类型 函数名(形参列表) {函数体(函数的实现内容)}, 注意: 如果没有参数, 小括号也是必不可少的.  函数与函数之间可以嵌套调用(也就是在一个函数内部可以调用另外一个函 ...

  9. C/C++函数调用的几种方式及函数名修饰规则以及c++为什么不允许重载仅返回类型不同的函数

    我们知道,调用函数时,计算机常用栈来存放函数执行需要的参数,由于栈的空间大小是有限的,在windows下栈是向低地址扩展的数据结构,是一块连续的内存区域.这句话的意思是栈顶的地址和栈的最大容量是系统预 ...

  10. 深入理解 C 语言的函数调用过程

    来源: wjlkoorey 链接:http://blog.chinaunix.net/uid-23069658-id-3981406.html 本文主要从进程栈空间的层面复习一下C语言中函数调用的具体 ...

随机推荐

  1. vecor预分配内存溢出2

    vector预分配内存溢出导致原始的 迭代器 失效 consider what happens when you add the one additional object that causes t ...

  2. 图像显示 imshow()[OpenCV 笔记5]

    void imshow(const string& winname InputArray mat); winname 窗口表识名称 mat 需要显示的图像.InputArray类型,声明如下 ...

  3. PHP临时文件session的分级存储与定期删除

    在Windows上PHP默认的Session服务端文件存放在C:\WINDOWS\Temp下,如果说并发访问很大或者 session建立太多,目录下就会存在大量类似sess_xxxxxx的sessio ...

  4. Vim自动补全神器:YouCompleteMe(转)

    转自:http://blog.jobbole.com/58978/ 可能会有一段时间写linxu,免不了用vim,留着,找时间实操之 原文出处: marchtea 的博客 第一次听说这个插件还是在偶然 ...

  5. C# 获取路径中文件名、目录、扩展名等

    string path = "C:\\dir1\\dir2\\foo.txt"; string str = "GetFullPath:" + Path.GetF ...

  6. StrongReference

    原创作品:未经本人允许,不得转载前段时间写项目时遇到了一个问题,就是从网络获取图片资源的问题,总是出现OOM异常,经过几天的努力,终于处理的还算是可以使用,OOM的处理一直都是很头疼的问题.对于三级缓 ...

  7. JS+CSS实现选项卡功能

    [小小一记] 首先我们写一个选项卡的结构出来,包括tab和content: 首先是tab: <ul class="ttitle-box-tabs" id="tabs ...

  8. 那些年优秀的HTML5活动页面

    一个好的手机活动宣传 更能让人分享 传播是爆炸性的 下面是我平时看到一些好的微信活动宣传页面  分享给大家 其中用到的技术 常做微信活动 专题页面的人 可以看看大神们是怎么做的  这样到自己做的时候 ...

  9. 使用Windbg来检查内存

    Windbg是一款微软开发的调试windows代码的工具,水很深,不过使用windbg来进行clr的调试则比较简单,windbg使用之前需要进行配置. File->Symbol path-> ...

  10. 提升 DevOps 效率,试试 ChatOps 吧!

    本文翻译自文章 To Boost DevOps, Try ChatOps,文中用简单易懂的方式介绍了 ChatOps 的发展和价值,由 OneAPM 工程师编译整理. 当我们谈论 DevOps 时,总 ...