• C# 调用 C++ dll的两种方式


    目录:

    1.非托管方式

    2.托管方式

    3.介绍 extern "C"

    4.介绍   DllImport

    1.非托管方式

    第一种,非托管方式:调用类和方法https://www.codeproject.com/Articles/18032/How-to-Marshal-a-C-Class

      非托管方式,只能调用函数,并且函数在extern "C"的体里面

      有一下几种方式,把函数都写了,把接口写了。

    //创建对象的方法
    extern "C" EXAMPLEUNMANAGEDDLL_API CUnmanagedTestClass* CreateTestClass()
    {
        return new CUnmanagedTestClass();
    }
    //释放对象
    extern "C" EXAMPLEUNMANAGEDDLL_API void DisposeTestClass(CUnmanagedTestClass* pObject)
    {
        if(pObject != NULL)
        {
            delete pObject;
            pObject = NULL;
        }
    }
    //调用函数
    extern "C" EXAMPLEUNMANAGEDDLL_API void CallPassInt(CUnmanagedTestClass* pObject, int nValue)
    {
        if(pObject != NULL)
        {
            pObject->PassInt(nValue);
        }
    }
    //调用函数
    extern "C" EXAMPLEUNMANAGEDDLL_API void CallPassString(CUnmanagedTestClass* pObject, char* pchValue);
    extern "C"{
     EXAMPLEUNMANAGEDDLL_API char* CallReturnString(CUnmanagedTestClass* pObject)

    }

    C++的调用

      把生成的TestClassDLL.dll放到 bin/Debug/下,然后在C#中调用

    public class CSUnmanagedTestClass : IDisposable
    {
        #region PInvokes
        [DllImport("TestClassDLL.dll")]
        static private extern IntPtr CreateTestClass();
    
        [DllImport("TestClassDLL.dll")]
        static private extern void DisposeTestClass(IntPtr pTestClassObject);
    
        [DllImport("TestClassDLL.dll")]
        static private extern void CallPassInt(IntPtr pTestClassObject, int nValue);
        .
        .
        .
        #endregion PInvokes
    
        #region Members
        private IntPtr m_pNativeObject; 
        // Variable to hold the C++ class's this pointer
        #endregion Members
    
        public CSUnmanagedTestClass()
        {
            // We have to Create an instance of this class through an exported 
            // function
            this.m_pNativeObject = CreateTestClass();
        }
    
        public void Dispose()
        {
            Dispose(true);
        }
    
        protected virtual void Dispose(bool bDisposing)
        {
            if(this.m_pNativeObject != IntPtr.Zero)
            {
                // Call the DLL Export to dispose this class
                DisposeTestClass(this.m_pNativeObject);
                this.m_pNativeObject = IntPtr.Zero;
            }
    
            if(bDisposing)
            {
                // No need to call the finalizer since we've now cleaned
                // up the unmanaged memory
                GC.SuppressFinalize(this);
            }
        }
    
        // This finalizer is called when Garbage collection occurs, but only if
        // the IDisposable.Dispose method wasn't already called.
        ~CSUnmanagedTestClass()
        {
            Dispose(false);
        }
    
        #region Wrapper methods
        public void PassInt(int nValue)
        {
            CallPassInt(this.m_pNativeObject, nValue);
        }
        .
        .
        .
        #endregion Wrapper methods
    }

    2.托管方式

    我手上有一个C++写的类(NativeClass),想在C#下调用这个类,可是C#是没有简单的像Dllimport这样的方法获取非托管C++ dll里的类。我的解决方法是,生成一个托管C++的dll,然后在C#下引用这个dll。因为托管代码与非托管代码是不能在一个文件里混编的,所以我必须将非托管C++写的NativeClass用托管C++的手段封装一下,然后生成一个dll,以供C#调用。

    https://www.cnblogs.com/stemon/p/4246165.html

    3.介绍 extern "C"

     

    :https://www.cnblogs.com/xiangtingshen/p/10980055.html

    extern "C"包含双重含义

    • 被extern "C"修饰的变量和函数是按照C语言方式进行编译和链接的:这点很重要!!!!
    • extern "C"的使用要点总结

      1,可以是如下的单一语句:

      extern "C" double sqrt(double);

      2,可以是复合语句, 相当于复合语句中的声明都加了extern "C"

      extern "C"
      {
            double sqrt(double);
            int min(int, int);
      }

      3,可以包含头文件,相当于头文件中的声明都加了extern "C" 

    extern "C"
    {
        #include <cmath>
    }
    

      

    4.介绍   DllImport

      https://www.cnblogs.com/fer-team/archive/2017/12/13/8033413.html

    要使用DllImport需要引用命名空间: System.Runtime.InteropServices;
    DllImport 属性定义
    如下:

    namespace System.Runtime.InteropServices
    {
      [AttributeUsage(AttributeTargets.Method)]
      public class DllImportAttribute: System.Attribute
      {
    public DllImportAttribute(string dllName){...} //定位参数为dllName
    public CallingConvention CallingConvention; //入口点调用约定
    public CharSet CharSet; //入口点采用的字符接
    public string EntryPoint; //入口点名称
    public bool ExactSpelling; //是否必须与指示的入口点拼写完全一致,默认false
    public bool PreserveSig; //方法的签名是被保留还是被转换
    public bool SetLastError; //FindLastError方法的返回值保存在这里
    public string Value {get {...}}
      }
    }

    说明:
    1、DllImport只能放置在方法声明上。
    2、DllImport具有单个定位参数:指定包含被导入方法的 dll 名称的 dllName 参数。
    3、DllImport具有五个命名参数:
    a、CallingConvention 参数指示入口点的调用约定。如果未指定CallingConvention,则使用默认值CallingConvention.Winapi。
    b、CharSet参数指定用在入口点的字符集。如果未指定CharSet,则使用默认值CharSet.Auto。
    c、EntryPoint参数给出dll中入口点的名称。如果未指定EntryPoint,则使用方法本身的名称。
    d、ExactSpelling参数指示EntryPoint是否必须与指示的入口点的拼写完全匹配。如果未指定ExactSpelling,则使用默认值false。
    e、PreserveSig参数指示方法的签名被保留还是被转换。当签名被转换时,它被转换为一个具有HRESULT返回值和该返回值的一个名为retval的附加输出参数的签名。如果未指定PreserveSig,则使用默认值true。
    f、SetLastError参数指示方法是否保留Win32“上一错误”。如果未指定SetLastError,则使用默认值false。
    4、它是一次性属性类。
    5、用DllImport属性修饰的方法必须具有extern修饰符。

  • 相关阅读:
    LeetCode
    LeetCode
    LeetCode
    LeetCode
    LeetCode
    LeetCode
    LeetCode
    LeetCode
    iOS开发系列--IOS程序开发概览
    iOS开发系列—Objective-C之Foundation框架
  • 原文地址:https://www.cnblogs.com/xuqp/p/11987707.html
Copyright © 2020-2023  润新知