C#中调用C++的dll的参数为指针类型的导出函数(包括二级指针的情况)
严格来说这篇文章算不上C++范围的,不过还是挂了点边,还是在自己的blog中记录一下吧。
C++中使用指针是家常便饭了,也非常的好用,这也是我之所以喜欢C++的原因之一。但是在C#中就强调托管的概念了,指针就不用想了。本来如果就在C#的世界里面写代码,也还算舒服,但是万事万物总有联系,这不,现在公司的另外一个用C#作的项目就碰到问题了,要调用之前用C++写的一个DLL中的一些函数,很多函数的参数都是指针类型的,这下可麻烦咯,公司里做C#的都是刚起步,C++又只有我最熟悉,这项技术研究工作又光荣的落到我身上。
我对C#也不甚熟悉,所以也许我的方法不一定是最直接的,但是测试的结果是满足了这个调用需要了的。下面我就详细介绍一下。
使用unsafe、fix等关键字应该是能够实现的,但是他们项目组要求不用这个,所以我也没深入去试验。除了这个方法,应该来说是有两个思路的,第一个思路可能看起来比较直接,使用ref,ref这个关键字似乎有点特殊性,字面上理解似乎应该和C++中的引用类型相对应,不过似乎它还是有一定特殊性的,貌似以前看到过一篇文章说ref会自己去判断是引用类型还是指针,我尝试了一下,果然是可行的。但是对于有二级指针的情况ref也就不灵了~这就导出了我的另一个思路,使用Marshal。
下面我们还是代码说明问题:
以下是C++DLL中的代码片断,主要是使用到的两个结构的定义,以及导出函数TestFunction的定义。
C++ DLL中的代码片断
#pragma pack(push)
#pragma pack(1)
typedef struct EmmStruct {
int len;
} EMMSTRUCT, *LPEMMSTRUCT; typedef struct MyStruct {
int iParam;
long size;
LPEMMSTRUCT lpEmmStructArr;
} MYSTRUCT, *LPMYSTRUCT;
#pragma pack(pop) extern "C" void __declspec(dllexport) __stdcall TestFunction(LPMYSTRUCT lpMyStruct)
{
lpMyStruct->iParam = ;
lpMyStruct->size = ;
lpMyStruct->lpEmmStructArr = new EMMSTRUCT[lpMyStruct->size];
for(int i=;i<lpMyStruct->size;i++) {
lpMyStruct->lpEmmStructArr[i].len = i;
}
} 那么再来看看C#中调用的代码:
C#中调用的代码片断using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices; //使用C#导入dll必须的 namespace csharptest
{
//StructLayout和FieldOffset这些设置不是必须的,只是为了防止对齐的问题最好加上,这样自己心里有数对齐到哪一位
[StructLayout(LayoutKind.Explicit)]
public struct EmmStruct
{
[FieldOffset()]
public int len;
} [StructLayout(LayoutKind.Explicit)]
public struct MyStruct
{
[FieldOffset()]
public int iParam;
[FieldOffset()]
public int size;
[FieldOffset()]
public IntPtr ptrEmmStruct;
} class Program
{
// dll中导出函数的声明
[DllImport("dllforcsharp.dll", CallingConvention=CallingConvention.Winapi)]
public extern static void TestFunction(IntPtr ptr); static void Main(string[] args)
{
try
{
MyStruct s = new MyStruct();
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(s));
Marshal.StructureToPtr(s, ptr, false); TestFunction(ptr); s = (MyStruct)Marshal.PtrToStructure(ptr, typeof(MyStruct)); EmmStruct ret;
for (int i = ; i < s.size; i++)
{
IntPtr ptr2 = new IntPtr(s.ptrEmmStruct.ToInt32() + * i);
ret = (EmmStruct)Marshal.PtrToStructure(ptr2, typeof(EmmStruct));
} Marshal.FreeHGlobal(ptr);
}
catch (Exception e)
{
string str = e.Message;
}
finally
{
}
}
}
} 代码也不多,而且从字面的意思就能知道是干什么的了,所以我就没写注释。用这种方法就实现了参数中含有二级指针的情况。要注意的就是C#中的long和C++中不同,它占8字节。所以一般情况下C++中long的,C#里面用int或者int32就ok了。我自己对C#不是特别熟悉,所以可能也未能完全讲解清楚,甚至可能存在漏洞,有高人见到的话,可以指点指点。
C#中调用C++的dll的参数为指针类型的导出函数(包括二级指针的情况)的更多相关文章
- C#中调用c++的dll
		
C#中调用c++的dll具体创建与调用步骤,亲测有效~ 使用的工具是VS2010哦~其他工具暂时还没试过 我新建的工程名是my21dll,所以会生成2个同名文件.接下来需要改动的只有画横线的部分 ...
 - shell中调用R语言并传入参数的两种步骤
		
shell中调用R语言并传入参数的两种方法 第一种: Rscript myscript.R R脚本的输出 第二种: R CMD BATCH myscript.R # Check the output ...
 - [Python]在python中调用shell脚本,并传入参数-02python操作shell实例
		
首先创建2个shell脚本文件,测试用. test_shell_no_para.sh 运行时,不需要传递参数 test_shell_2_para.sh 运行时,需要传递2个参数 test_shell ...
 - Java代码调用Shell脚本并传入参数实现DB2数据库表导出到文件
		
本文通过Java代码调用Shell脚本并传入参数实现DB2数据库表导出到文件,代码如下: import java.io.File; import java.io.IOException; import ...
 - C#中调用c++的dll具体创建与调用步骤,亲测有效~
		
使用的工具是VS2010哦~其他工具暂时还没试过 我新建的工程名是my21dll,所以会生成2个同名文件.接下来需要改动的只有画横线的部分 下面是my21dll.h里面的... 下面的1是自动生成的不 ...
 - android开发中调用python代码(带参数)
		
android开发主要用到的是java代码,但是当开发涉及到一些算法时,往往用python可以提高软件的运行速度,也更加便捷,这里分享自己项目调用python代码的方式,主要有以下几个步骤(个人方法, ...
 - 在Windows Phone项目中调用C语言DLL
		
在Windows Phone项目中调用C语言写的DLL 最近接到一个需求,需要在WP里调用一个C语言写的DLL,并且说Android和iOS都可以,问我WP是否可以这样? 我说我调研一下,就有了下面的 ...
 - C#中调用c++的dll具体创建与调用步骤,亲测有效~  (待验证)
		
使用的工具是VS2010哦~其他工具暂时还没试过 我新建的工程名是my21dll,所以会生成2个同名文件.接下来需要改动的只有画横线的部分 下面是my21dll.h里面的... 下面的1是自动生成的不 ...
 - C++ 有关指针作为函数参数的问题,自定义内存分配函数传递二级指针的问题
		
如题所示,我们主要讨论在自定义的内存分配函数中通常见到的代码如下所示: void Create(A** addr); 其中传递的参数是二级指针.为什么? 我们先看一下完整的动态内存分配函数的简单例子: ...
 
随机推荐
- iOS 三种录制视频方式
			
随着每一代 iPhone 处理能力和相机硬件配置的提高,使用它来捕获视频也变得更加有意思.它们小巧,轻便,低调,而且与专业摄像机之间的差距已经变得非常小,小到在某些情况下,iPhone 可以真正替代它 ...
 - 从问题看本质:socket到底是什么(问答式)? .
			
转自:http://blog.csdn.net/yeyuangen/article/details/6799575 一.问题的引入——socket的引入是为了解决不同计算机间进程间通信的问题 1.so ...
 - hdoj-2025a
			
#include "stdio.h"#include "string.h"void compare(int n,char s[],char &k);vo ...
 - Chapter 2: A Simple Servlet Container
			
一.这一章从头构建一个简单的Servlet容器,可以处理Servlet和静态资源(如html文件/图片等). 要处理Servlet,必须遵循javax.servlet.Servlet规范,而处理静态资 ...
 - 深入学习:Windows下Git入门教程(下)
			
声明:由于本人对于Git的学习还处于摸索阶段,对有些概念的理解或许只是我断章取义,有曲解误导的地方还请见谅指正! 一.分支 1.1分支的概念. 对于的分支的理解,我们可以用模块化这个词来解释:在日常工 ...
 - 一个Android Socket的例子
			
1.开篇简介 Socket本质上就是Java封装了传输层上的TCP协议(注:UDP用的是DatagramSocket类).要实现Socket的传输,需要构建客户端和服务器端.另外,传输的数据可以是字符 ...
 - 11、SQL基础整理(变量)
			
变量 定义变量:declare @hello varchar(20) 赋值:set @hello = ‘你好’ select(结果框显示)/print(消息框显示) @hello *三行必须同时 ...
 - [转]A plain english introduction to cap theorem
			
Kaushik Sathupadi Programmer. Creator. Co-Founder. Dad. See all my projects and blogs → A plain engl ...
 - Smart210学习记录-------linux内核模块
			
Linux 驱动工程师需要牢固地掌握 Linux 内核的编译方法以为嵌入式系统构建可运行的Linux 操作系统映像.在编译 LDD6410 的内核时,需要配置内核,可以使用下面命令中的 一个: #ma ...
 - curl 发送带有Authorization的post请求命令
			
curl --user user:password -d "param1=111¶m2=222" "http://127.0.0.1/cmd"