C#中调用C++的dll的参数为指针类型的导出函数

本文介绍如何在C#中调用含有二级指针参数的C++DLL,通过使用Marshal进行内存操作,解决了跨语言调用的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 = 100;
    lpMyStruct->size = 10;
    lpMyStruct->lpEmmStructArr = new EMMSTRUCT[lpMyStruct->size];
    for(int i=0;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(
0)] 
        
public int len; 
    }
 
    [StructLayout(LayoutKind.Explicit)] 
    
public struct MyStruct 
    

        [FieldOffset(
0)] 
        
public int iParam; 
        [FieldOffset(
4)] 
        
public int size; 
        [FieldOffset(
8)] 
        
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 = 0; i < s.size; i++)
               

                    IntPtr ptr2 
= new IntPtr(s.ptrEmmStruct.ToInt32() + 4 * 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#不是特别熟悉,所以可能也未能完全讲解清楚,甚至可能存在漏洞,有高人见到的话,可以指点指点
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值