• C#调用C++类库的几种方式


    1、  直接调用C++类库中的公共方法

    使用DllImport特性对方法进行调用,比如一个C++类库SampleCppWrapper.dll中的公共方法:

    extern "C" __declspec(dllexport) int __stdcall Add(int n1, int n2);

    __stdcall表示调用约定:参数都是从右向左通过堆栈传递, 函数调用在返回前要由被调用者清理堆栈。

    在C#中,调用如下:

    [DllImport("SampleCppWrapper.dll")]
    private static extern int Add(int n1, int n2);

    注意参数的类型,之后,可直接在C#编程中使用这个方法。

    2、  调用C++类库中的类的方法

    C#不能直接调用C++类库中的类,需要一种变通的解决方式,通过再做一个C++类库把要调用的类成员方法暴露出来,比如下面这个C++类:

    SampleCppClass.h

    #pragma once
    
    class __declspec(dllexport) SampleCppClass
    {
    public:
        SampleCppClass(void);
        ~SampleCppClass(void);
        
        int Add(int n1, int n2);
        int Sub(int n1, int n2);
    };

    SampleCppClass.cpp

    #include "SampleCppClass.h"
    
    SampleCppClass::SampleCppClass(void)
    {
    }
    
    SampleCppClass::~SampleCppClass(void)
    {
    }
    
    int SampleCppClass::Add(int n1, int n2)
    {
        return n1 + n2;
    }
    
    int SampleCppClass::Sub(int n1, int n2)
    {
        return n1 - n2;
    }

    我们要调用SampleCppClass中的Add和Sub两个方法,所以我们再写一个C++类库,通过公共方法间接调用类成员方法:

    SampleCppWrapper.h

    #pragma once
    
    #include "..SampleCppClassSampleCppClass.h"
    
    namespace SampleCppWrapper
    {
        extern "C" __declspec(dllexport) int __stdcall Add(int n1, int n2);
        extern "C" __declspec(dllexport) int __stdcall Sub(int n1, int n2);
    }

    SampleCppWrapper.cpp

    #include "SampleCppWrapper.h"
    
    namespace SampleCppWrapper
    {
        SampleCppClass* g_pObj = new SampleCppClass();
    
        int __stdcall Add(int n1, int n2)
        {
            return g_pObj->Add(n1, n2);
        }
    
        int __stdcall Sub(int n1, int n2)
        {
            return g_pObj->Sub(n1, n2);
        }
    }

    在C#中,再调用SampleCppWrapper.dll中的公共方法:

    [DllImport("SampleCppWrapper.dll")]
    private static extern int Add(int n1, int n2);
    [DllImport("SampleCppWrapper.dll")]
    private static extern int Sub(int n1, int n2);

    3、  使用C++类库中的回调函数

    C++的回调函数是一种事件响应机制,和C#的委托相似,比如一个C++类中的回调函数:

    SampleCppClass.h

    #pragma once
    
    typedef void (*LoopCallback)(void* pContext);
    
    class __declspec(dllexport) SampleCppClass
    {
    public:
        SampleCppClass(void);
        ~SampleCppClass(void);
        
        void SetCallbackFunc(LoopCallback callback);
        void SetCallbackContext(void* pContext);
        void Loop();
    private:
        LoopCallback m_callback;
        void* m_pContext;
    };

    SampleCppClass.cpp

    #include "SampleCppClass.h"
    
    SampleCppClass::SampleCppClass(void)
    {
    }
    
    SampleCppClass::~SampleCppClass(void)
    {
    }
    
    void SampleCppClass::SetCallbackFunc(LoopCallback callback)
    {
        m_callback = callback;
    }
    
    void SampleCppClass::SetCallbackContext(void* pContext)
    {
        m_pContext = pContext;
    }
    
    void SampleCppClass::Loop()
    {
        for (int i=0; i<10; i++)
        {
            if (m_callback != NULL)
            {
                m_callback(m_pContext);
            }
        }
    }

    我们通过C++再写一个类库进行封装,把类中的方法暴露出来:

    SampleCppWrapper.h

    #pragma once
    
    #include "..SampleCppClassSampleCppClass.h"
    
    namespace SampleCppWrapper
    {
        typedef void (__stdcall *LoopCallbackWrapper)(void* pContext);
    
        extern "C" __declspec(dllexport) void __stdcall SetCallbackFunc(LoopCallbackWrapper callback);
        extern "C" __declspec(dllexport) void __stdcall SetCallbackContext(void* pContext);
        extern "C" __declspec(dllexport) void __stdcall Loop();
    }

    SampleCppWrapper.cpp

    #include "SampleCppWrapper.h"
    
    namespace SampleCppWrapper
    {
        LoopCallbackWrapper g_callbackWrapper;
        SampleCppClass* g_pObj = new SampleCppClass();
    
        void LoopCallbackFunc(void* pContext);
    
        void __stdcall SetCallbackFunc(LoopCallbackWrapper callback)
        {
            g_callbackWrapper = callback;
            g_pObj->SetCallbackFunc(LoopCallbackFunc);
        }
    
        void __stdcall SetCallbackContext(void* pContext)
        {    
            g_pObj->SetCallbackContext(pContext);
        }
    
        void __stdcall Loop()
        {
            g_pObj->Loop();
        }
    
        void LoopCallbackFunc(void* pContext)
        {
            if (g_callbackWrapper != NULL)
            {
                g_callbackWrapper(pContext);
            }
        }
    }

    然后,在C#中进行调用:

    using System;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    
    namespace SampleCsTest
    {
        public partial class Form1 : Form
        {
            [StructLayout(LayoutKind.Sequential)]
            private class Context
            {
                public Form1 Form { get; set; }
            }
    
            private delegate void LoopCallbackHandler(IntPtr pContext);
            private static LoopCallbackHandler callback = LoopCallback;
    
            [DllImport("SampleCppWrapper.dll")]
            private static extern void SetCallbackFunc(LoopCallbackHandler callback);
            [DllImport("SampleCppWrapper.dll")]
            private static extern void SetCallbackContext(IntPtr pContext);
            [DllImport("SampleCppWrapper.dll")]
            private static extern void Loop();
    
            private Context ctx = new Context();
    
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                SetCallbackFunc(callback);
                ctx.Form = this;
                IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(ctx));
                Marshal.StructureToPtr(ctx, ptr, false);
                SetCallbackContext(ptr);
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                Loop();
            }
    
            private static void LoopCallback(IntPtr pContext)
            {
                Context ctx = (Context)Marshal.PtrToStructure(pContext, typeof(Context));
                ctx.Form.textBox1.Text += "callback" + Environment.NewLine;
            }
        }
    }
  • 相关阅读:
    Atitit  atiMail atiDns新特性 v2  q39
    Atitit.java jar hell解决方案Djava.ext.dirs in ide envi..
    砍价大法
    DWR学习
    什么是WEB 2.0
    XHTML 1.0 Tags 参考
    web.config文件遇到的错误
    JDBC教程之PreparedStatement
    符合W3C标准的target=_blank形式
    dwr 登录实现 (入门知识)
  • 原文地址:https://www.cnblogs.com/lgyup/p/7116162.html
Copyright © 2020-2023  润新知