C#调用C++的dll中的函数,数组指针的问题

作者&投稿:蔽拜 (若有异议请与网页底部的电邮联系)
C#如何调用C++DLL中参数有结构体数组指针的函数?~

里面涉及到函数指针,在C#里面用委托替代,总的代码如下: delegate int pfunc(void* dst,void* src,int nSize); unsafe public struct MyStruct { public Byte* pMemory;//也可以用unsinged int替代(uint*) public pfunc myfunc;//这里用委托替代函数指针 public char[] rd;//声明的时候不能指定大小,可以在new的时候指定大小 }

确实是个悲剧 给你个提示用stingbiuder做参数 不要用string 也不要用CHAR数组

赶紧转行吧

其实在.net开发中确实存在第三种类型——指针。但仅限于unsafe开发时使用!
对于dll调用问题,如果是pe格式的dll考虑使用PInvoke(平台调用)。而平台调用跟具体的unsafe开发是没有任何关联的,并不是说平台调用一定会用到非安全开发!由于.net本身隐藏了指针的使用,你不必要再去开辟任何指针了!所以这里显然是平台调用。
解答一个疑问:数组指针or指针数组?
数组指针指的一个指针,该指针指向一个数组。
指针数组是一个数组,一个数组里全是指针。
显然这使用是有区别,但这里并不涉及,在safe开发.net都不会涉及!
IntPtr是一种特殊的指针,这种针指的特殊性在于它向了设备!所以嘛,他也有一个名词——名柄,IntPtr多种在PInvoke时,传递设备句柄时使用(设备并不是硬件,有时一个文件也算是一个句柄的)。当然,这里也用不到!
现在说一下平台调用(PInvoke)中最重要的一个部分!数据封送!
也就是你写dll导入时应用使用的类型!
在C语言中声明与赋值分开写的时候多了去了!他生成文件时写一起与分开写并没有任何区别!所以分开写无所谓的!但是,多数时间你会发现,其实他分开写是为了你阅读的方便!为什么?因为声明时使用的类型是PUSHORT,而赋值时使用了USHORT的类型,这两句写在一块的话,很多人不会注意到赋值时使用的基础类型!所以分开写只是相当于想写一个注释而已!
平台对应的数据封送就在这里!USHORT在C/CPP中对就的一个byte!一定要注意,所以你知道的,他们使用的new USHORT[n]只是开辟了n个无符号数的字节!在.net平台封送时如何传递数据?当然用byte去接值,他是数组,你就用byte[]去接!
这里有一个问题你可能不知道,在.net中,最小的数是byte,而不是short和ushort!在.net中可以直接使用byte与其他数值进行运算!而short/ushort在.net中却是一个16bit数!占用两个字节!而C/Cpp为了确定类型,所以byte是byte,short/ushort是数值,但是short/ushort却是一个8bit数字!当然了,C/Cpp中的long才与.net中的int对应!
如果你明白这个,那么该用int[]还是该用short[]还是该用byte[]你自己就知道了!
第二个问题——你一直在想指针,其实你要传入的数组是地址而不是副本!换句话来说,在安全模式中我们是有ref/out修饰的!在dllImport时你传入byte[]是没有任何错误的!但是你能不能在从dll中将byte[]修改后的值带回就是两个字了!
一般情况下byte[]等数组本身就是引址的方式,所以不使用ref/out声明也是没有问题的!但是如果封装层在有一定的疑问存在时,最好还是声明成ref的方式较为合适。经常性的规律是,如果我们看到Cpp的header中说明是指针时,我们会使用ref声明,不是指针形式时可以不用ref/out声明,如果是**形式时,平台封送最好使用数组指针。这种情况并不多见!
但是,由于string类型也是引用形的,由于其特点,返回值一定要用ref/out(不管你看到Cpp的header中是什么类型),或者我们可以使用一个说明长度的byte[]也是可行的!
换句话来说,虽然我们可以说C#中的byte可以接short, short可以接int等等的对应关系!但其实在不改变内存字节长度的情况下,PInvoke对类型的要求并没有那么严格!比如你可以用string接收dll中传入的字符串,用byte[]也行的!用stringbuilder还行的!并没有严格上的限制!但是这里边一定要注意的是长度!换句话来说,对方使用的是USHORT[n],你用byte[n]能接回来。
是不是一定要有这个对应关系?不一定!
这种情况往往出来在自定类中。比如Cpp header中说明某个参数一个结构!这个结构是由一个short,一个字符串组成的!用C#时可以使用byte实现结构中对应的short,也可以用short实现对应的short,但在声明必须使用特定的长度说明,说明其只有一位!当然用,无论你用int还是long都可以,在结构中必须要说明长度只有一位!那个字符串也是一样!所以你完全可以看到,数据类型并不重要,平台封送中不用管具体的类型,要的只是长度!长度必须对应!
换句话来说,你用char[]来处理Cpp中的ushort也是可以的!
平台数据封送中重要一部分就是共长度(类型?开什么玩笑,Cpp不会认识.net中的类型的,当然.net也不会认识Cpp中的类型)。只有长度一致才能接到值!
cpp中肯定是哪种类型方便用哪种了,当然.net中也是哪种方便用哪种了!那么平台数据是如何进行传递的呢?答案就在于基本类型和结构!
基本类型不说了,当然是ushort只是一个byte,你用int无用谓!反正在.net中byte类型会自然转换成int。如果是ushort[],那么你必须是byte[]或char[]!你用int[]绝对会出现错误的!为了帮助理解,我这里说的是重点是结构:
假定一个结构有n个项(你可以理解为字段)组成。那么在数据封送时就是这n个项每一段的组合。经如有字段是USHORT类型,一个字段是Byte[10]类型,还有一个是Int类型,在平台封送时,我们要封装一段内存,长度为13,第一个长度为1表示第一字段,接下来10个表示第二字段,接下来2个表示 第三字段。
当然我们在.net方面也要构造一个对应的结构!第一个字段你可以声明成byte/short/int/long都可以(必须说明这个在内存中只有一个字节),如果你用了short却不说明,很显然你.net会接到前两字节,破坏了要接收的结构!你自己肯定拿不到数据的!
原理就这么多!慢慢看懂了就知道平台封送是怎么回事了!至于你的问题,抄个近路告诉你结果:dllImport声明时使用
static bool Read(short h, byte[] buffer, short n);
或者
static bool Read(short h, ref byte[] buffer, short n);
当然,也可以使用int,我并不反对
static bool Read([MarshalAs(UnManagerType.USHORT)] int h, byte[] buffer, short n);
换句话来说,你可以使用MarshalAsAttribute来指针其非托类型,结构时还可以直接使用长度说明。主要是你学会MarshalAsAttribute的使用,就知道参数如何传递了!

这个不需要用到unsafe和指针
[DllImport(xxxxxx)]
public static bool Read(int h,  UInt16[] Buffer, int n);//c#定义
调用,h和n先定义
var buffer = new UInt16[n];
Read(h, buffer, n);



乐亭县15174891200: C# 如何调用C++ dll中的函数 -
丑伏磷霉: 调用格式如下:[DllImport("ex.dll", EntryPoint = "method")] public static extern void method(int a); 其中ex.dll为C++DLL名,method为函数名, 这里的int a为C++中方法的参数转换.例:C++DLL名:Interface.dll,函数为voidCopMemFree(...

乐亭县15174891200: C#动态调用C++编写的DLL函数 -
丑伏磷霉: 调用dll有很多方式,比如通过发送消息,比较简单直观就是直接调用.例如:有一个DllProgress.dll,将他放在应用程序同级目录下,HINSTANCE hIns=NULL; hIns=LoadLibrary("DllProgress.dll");//定义希望调用的函数 指针 typedef float (*pFunc)(int...

乐亭县15174891200: 请问C#怎么调用C++的dll,把字节数组(字节数组byte[]作为形参)传入C++? -
丑伏磷霉: 我混混经验.在项目那里,可以引用 需要的 dll 文件,然后在程序中,using就行了,然后就可以调用这个dll中的函数了.C#中,可以定义一个byte数组,然后赋值,传入就行.

乐亭县15174891200: C#如何调用C++DLL中参数有结构体数组指针的函数? -
丑伏磷霉: 里面涉及到函数指针,在C#里面用委托替代,总的代码如下: delegate int pfunc(void* dst,void* src,int nSize); unsafe public struct MyStruct { public Byte* pMemory;//也可以用unsinged int替代(uint*) public pfunc myfunc;//这里用委托替代函数指针 public char[] rd;//声明的时候不能指定大小,可以在new的时候指定大小 }

乐亭县15174891200: C#怎样调用C++写的dll -
丑伏磷霉: public static extern bool Gnd_shuzu(String filename,float[] aa); 改成这样

乐亭县15174891200: c# 能调用c++里的函数吗? -
丑伏磷霉: 单纯的C++不知道,如果是C++ .net 的话,也许可以,这个跟C#一样,编译以后会转成IL中间语言,应该是可以互调的. 你可以把你的函数先用.net里的C++写出来,编译成一个dll文件,然后在你的C#项目里,引用这个dll,这样的话应该能调用掉你定义的那个函数.

乐亭县15174891200: C#调用C++生成的dll函数问题 -
丑伏磷霉: 我引用C++ 的Dll是这样引用的: [DllImport(@"CSModCG.dll")] public static extern int void(); 由于参数的不正确经常会出现你这样的错误,所以我估计你的错误出现是在 gdImagePng(im, pngout); ,但原因应该是在 pngout = fopen("d:\\1.png", "wb");,也就是说你的D盘是否有文件1.png 然后你这样写绝对位置然后再在C#里面引用是有问题的,你最好写相对位置

乐亭县15174891200: c# 调用c++生成的dll 返回数组 -
丑伏磷霉: 把函数写成API的形式,如函数定义为 void WINAPI aaa(BYTE*pBuf);,然后在def文件里添加一行aaa 在C#里这样声明:[DllImport("aaa.dll", EntryPoint = "aaa")] public static extern void aaa(byte[] pBuf);

乐亭县15174891200: c#怎么调用c++的类和函数 -
丑伏磷霉: 把C#编译成DLL或者Axtive控件,再由C调用 !比如使用C++调用C#的DLL SwfDotNet是C#编写的,作者的C#水平,真是令我佩服.这是个特别好的读写Swf文件的库.但是,我要用在C++项目中,怎么让C++调用C#的DLL呢.今天一上午都在...

乐亭县15174891200: C#程序调用c++的dll,怎样把dll中函数返回的数组赋值给c#程序中的数组 -
丑伏磷霉: C++ 代码里在数组最后加一个不可能的数字比如-1,之后在C# 里面读出来:C++ 代码: char *A(char buf[]) { char buffer[50]={};int i = 0;while(buf[i] != '/0' && i < 49) {buffer[i] = buf[i]i++;} buffer[i] = -1; return buffer; }///////////////////////////// C# 代码...

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网