• 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 = 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#不是特别熟悉,所以可能也未能完全讲解清楚,甚至可能存在漏洞,有高人见到的话,可以指点指点。
            
  • 相关阅读:
    CareerCup Questions List 职业杯题目列表
    [CareerCup] Guards in a museum 博物馆的警卫
    [LeetCode] 7. Reverse Integer 翻转整数
    Python笔记11------一个K-means聚类的小例子
    python笔记10-----便捷网络数据NLTK语料库
    Python笔记9-----不等长列表转化成DataFrame
    Python笔记8----DataFrame(二维)
    Python笔记7----Pandas中变长字典Series
    Python笔记6----数组
    Python笔记5----集合set
  • 原文地址:https://www.cnblogs.com/profession/p/4914439.html
Copyright © 2020-2023  润新知