如何包装C++;在基于C的dll或基于CLI的dll中初始化? >我被告知将C++中的Wrand类导入到DLL中,然后在C++应用程序中使用该DLL。下面我创建了dll,但我不能简单地在C#应用程序中使用它,因为它存在一些问题:

如何包装C++;在基于C的dll或基于CLI的dll中初始化? >我被告知将C++中的Wrand类导入到DLL中,然后在C++应用程序中使用该DLL。下面我创建了dll,但我不能简单地在C#应用程序中使用它,因为它存在一些问题:,c++,c,dll,c++-cli,C++,C,Dll,C++ Cli,我应该为工厂函数的返回类型放置什么 什么是构造函数参数类型的常量wchar\u t*的等价物 如何检索和使用类型为vector的函数返回类型 这些问题阻碍了我在C++应用程序中使用C++ DLL。我被告知需要用C++/CLI创建一个包装器,然后在我的C#中使用它。但是我很难过,我不知道它,我不知道C++,.net。 目前对我来说,唯一更有意义的事情是让它与C兼容,然后创建一个C DLL并在我的C应用程序中使用它。我曾经读过,在C语言中,类对象指针可以通过HANDLEs访问,所以我认为在不做太多更

我应该为工厂函数的返回类型放置什么

  • 什么是构造函数参数类型的
    常量wchar\u t*
    的等价物

  • 如何检索和使用类型为
    vector
    的函数返回类型

  • 这些问题阻碍了我在C++应用程序中使用C++ DLL。我被告知需要用C++/CLI创建一个包装器,然后在我的C#中使用它。但是我很难过,我不知道它,我不知道C++,.net。 目前对我来说,唯一更有意义的事情是让它与C兼容,然后创建一个C DLL并在我的C应用程序中使用它。我曾经读过,在C语言中,类对象指针可以通过
    HANDLE
    s访问,所以我认为在不做太多更改的情况下运行是个好主意

    所以问题是如何使用句柄访问C中的类对象并使用它们?我怎样才能把向量转换成C对应的向量呢?
    如果我想使用CLI来为我的C++ DLL创建包装器(DLL),在其他的dotnet应用程序中使用什么?我应该做什么?< /p> 使用来自C++的本地C++类在技术上是可能的,但是它不是微不足道的,而且它甚至不是一个好主意。对于初学者,您必须知道从DLL导入的名称,这将是C++名称修改后的名称。您也不能直接从C#访问诸如
    vector
    之类的内容

    基本上有两个好的选择:

    第一种方法是使用C接口编写DLL,该接口只使用可以封送到CLR类型中的类型。您可以将指针与
    IntPtr
    类型一起使用,但不能真正取消对这些指针的引用。您几乎可以将它们存储在C代码中,然后在需要时将它们传递回本机DLL。您还可以使用简单的
    struct
    类型,只要不需要深度复制即可。此选项涉及使用P/Invoke

    第二个选项是编写一个混合模式C++/CLI程序集,该程序集实现访问本机代码所需的所有逻辑。这个程序集可以直接从C#代码中访问类和数据,也可以直接访问本机代码,不过应该预先警告您,有些令人讨厌的中断不能将两者混合使用。例如,C++/CLI中的
    ref类不能有
    shared_ptr
    成员。但是,它可以有一个原始的C++指针作为成员。(混合模式)本机类还可以访问CLR句柄类型,并通过该类调用C#代码。这个选项涉及使用C++互操作。 值得注意的是,你也可以用C++互操作来另一种方式。您可以让您的C#代码访问混合模式C++/CLI程序集,该程序集为某些本机代码提供.NET接口。但是,在这种情况下,您仍然需要进行一些翻译,因此它并不比第一个选项好多少


    关于C++互操作的完整教程将相当冗长。我建议你在谷歌上阅读并做一些关于C++互操作的进一步研究。

    < P> C++ +CLI引入托管对象,指针指针*应该用A^替换,而“新”应该用“GCNEW”替换,不需要在完成这些对象时删除这些对象,它们将被垃圾收集,编辑。托管类在其定义[/edit]中有一个ref关键字

    在C++ /CLI包装类中包装C++ <强> MyClass < /Stutial>类<强> WrapperCLass < /St>可以类似这样:

    #include <stdio.h>
    
    class MyClass
    {
    public:
        void ShowStuff(const wchar_t *a)
        {
            wprintf(a);
        }
    };
    
    public ref class WrapperClass
    {
        MyClass *wrapped;
    public:
        WrapperClass()
        {
            wrapped = new MyClass;
    
        }
        ~WrapperClass()
        {
            delete wrapped;
        }
        void ShowStuff(IntPtr string)
        {
            wrapped->ShowStuff((const wchar_t *)string.ToPointer());
        }
    };
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Client
    {
        class Program
        {
            static void Main(string[] args)
            {
                WrapperClass w = new WrapperClass();
                IntPtr tmp;
                w.ShowStuff(tmp = System.Runtime.InteropServices.Marshal.StringToHGlobalUni("Test"));
                System.Runtime.InteropServices.Marshal.FreeHGlobal(tmp);
            }
        }
    }
    
    (很可能有更好的方法来做到这一点……)


    对于返回类型,必须在包装器类中进行转换。创建一些.net集合,遍历向量,将wstring转换为System::String,并将其添加到.net集合中,然后返回。

    为了为
    C++
    类创建一个
    C包装器,以便在例如
    C#
    应用程序中使用,您可以执行以下操作

    在Visual Studio中选择
    Win32 Console应用程序
    并输入名称,然后单击下一步,在下一窗格中选择
    DLL
    并单击完成。完成后,将使用包含3个文件的DLL项目表示您

    testdll.h 
    testdll.cpp
    dllmain
    
    删除
    testdll.h
    testdll.cpp
    文件中存在的所有内容,并将以下内容分别复制到每个文件中。将这些行添加到testdll.h

    // Our C wrapper for creating a dll to be used in C# apps
    
    // The following ifdef block is the standard way of creating macros which make exporting 
    // from a DLL simpler. All files within this DLL are compiled with the TESTDLL_EXPORTS
    // symbol defined on the command line. This symbol should not be defined on any project
    // that uses this DLL. This way any other project whose source files include this file see 
    // TESTDLL_API functions as being imported from a DLL, whereas this DLL sees symbols
    // defined with this macro as being exported.
    #ifdef  TESTDLL_EXPORTS
    #define  TESTDLL_API __declspec(dllexport)
    #else
    #define  TESTDLL_API __declspec(dllimport)
    #endif
    
    extern "C"
    {
         TESTDLL_API int OurTestFunction(int x, int y);                         
    }
    
    它位于这个外部“C”块中,您可以在其中定义接口、函数以访问类成员函数。请注意函数原型之前的
    TESTDLL
    。你所有的工作都必须按这个程序进行

    将以下内容添加到testdll.cpp文件:

    #include "testdll.h"
    #include "ourClass.h"
    
    #define DLL_EXPORT
    
    extern "C"
    {
        OurClass ourObject;
        TESTDLL_API int OurTestFunction(int x, int y)
        {
            return ourObject.Add(x,y);
        }
    }
    
    您可以编译此文件并获得一个基于C的dll,它可以在C#应用程序中使用。
    但有几件事需要注意,更重要的是:

  • 你需要理解你作为代理使用的代码-我的意思是
    testdll.h
    中的函数定义只能使用C 兼容类型,毕竟是C,不是C++。< /LI>
  • 您希望能够分配新的对象 类,而不是仅使用一个全局对象来访问所有方法
  • 为此,如果需要在成员函数之间传递类对象,则需要首先将其转换为C可以理解的
    void*
    ,然后传递并使用它访问任何成员函数

    例如,我在我的
    testdll.h
    中会有这样的东西,以便用户能够间接管理对象:

    #ifdef TESTDLL_EXPORTS
    #define TESTDLL_API __declspec(dllexport)
    #else
    #define TESTDLL_API __declspec(dllimport)
    #endif
    
    extern "C"
    {
        TESTDLL_API int OurTestFunction(int x, int y);                      
    
        TESTDLL_API void*  CreateHandle();
        TESTDLL_API void*  GetCurrentHandle();
        TESTDLL_API void   DisposeCurrentHandle();
        TESTDLL_API void   SetCurrentHandle(void* handle);
        TESTDLL_API void*  GetHandle();
        TESTDLL_API void   DisposeHandle(void*);
        TESTDLL_API void   DisposeArrayBuffers(void);
    }
    
    在我的testdll.cpp中,我将它们定义为:

    #include "testdll.h"
    #include "ourClass.h"
    
    #define DLL_EXPORT
    
    extern "C"
    {
        OurClass *ourObject;
    
        TESTDLL_API int OurTestFunction(int x, int y)
        {
            //return ourObject.Add(x,y); -- not any more !!
            ourObject = reinterpret_cast<OurClass *>(GetHandle());
        }
    
        //Handle operations
        TESTDLL_API void* CreateHandle()
        {
            if (ourObject == nullptr)
            {
                ourObject = new OurClass ;
            }
            else
            {
                delete ourObject ;
                ourObject = new OurClass ;
            }
            return reinterpret_cast<void*>(ourObject);
        }
    
        TESTDLL_API void* GetCurrentHandle()
        {
            return reinterpret_cast<void*>(ourObject );
        }
    
        TESTDLL_API void  DisposeCurrentHandle()
        {
            delete ourObject ;
            ourObject = nullptr;
        }
    
        TESTDLL_API void  SetCurrentHandle(void* handle)
        {
            if (handle != nullptr)
            {
                ourObject = reinterpret_cast<OurClass *>(handle);
            }
            else
            {
                ourObject = new OurClass ;
            }
    
        }
    
        //factory utility function
        TESTDLL_API void* GetHandle()
        {
            void* handle = GetCurrentHandle();
            if (handle != nullptr)
            {
                return handle;
            }
            else
            {
                ourObject = new OurClass ;
                handle = reinterpret_cast <void*>(ourObject );
            }
            return handle;
        }
    
        CDLL_API void  DisposeHandle(void* handle)
        {
            OurClass * tmp = reinterpret_cast<OurClass *>(handle);
            delete tmp;
        }
    
        TESTDLL_API void DisposeArrayBuffers(void)
        {
            ourObject = reinterpret_cast<OurClass *>(GetHandle());
            return ourObject ->DisposeBuffers();//This is a member function defined solely for this purpose of being used inside this wrapper to delete any allocated resources by our class object.
        }
    }
    
    <
    [DllImport(@"TestDll.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern int OurTestFunction(int firstNumber,int secondNumber); 
    
    private void btnReadBigram_Click(object sender, EventArgs e)
    {
        int x = OurTestFunction(10,50);
        MessageBox.Show(x.ToString());
    }