我被告知将我在C++中的writen类导入一个dll,然后在C#应用程序中使用该dll。在this guide之后,我创建了dll,但由于存在一些与之相关的问题,因此我不能在C#应用程序中简单地使用它:

  • 我应该为工厂函数的返回类型放置什么?
  • 什么是const wchar_t*等效项,它是我的构造函数参数类型?
  • 如何获取和使用vector< wstring>类型的函数返回类型?

  • 这些问题使我无法在C#应用程序中使用C++ DLL。有人告诉我,我需要使用C++/CLI创建包装器,然后在我的C#中使用该包装器。但是可悲的是,我对此一无所知,我不知道C++。net。

    目前,对我来说似乎唯一更引起轰动的事情是使其与C兼容,然后创建一个C DLL并在我的C#应用​​程序中使用它。我已经读过在C语言中,可以通过HANDLE访问类对象指针,所以我认为这是个好主意,无需做太多更改就可以使事情顺利进行。

    所以问题是我该如何使用Handles在C语言中访问我的类对象并使用它们?以及如何将vector<wstring>转换为其C拷贝?
    如果我想使用CLI为我的C++ DLL创建包装器(DLL?),要在其他dotnet应用程序中使用,我该怎么办?

    最佳答案

    为了为要在例如C wrapper应用程序中使用的C++类创建C#,您可以执行以下操作。

    在Visual Studio中,选择Win32 Console Application并输入一个名称,然后单击“下一步”,然后在下一个 Pane 中选择“DLL”并单击“完成”。完成后,您将看到一个包含3个文件的DLL项目。

    testdll.h
    testdll.cpp
    dllmain
    

    删除testdll.htestdll.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”块中,您可以在其中定义接口(interface)以及访问类成员函数的函数。请注意函数原型(prototype)之前的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#应用程序中使用的基于C的dll。
    但是,有几件事需要注意,更重要的是:
  • 您需要了解用作代理的代码-我的意思是testdll.h中的函数定义,只能使用C
    兼容类型,毕竟不是C++是C。
  • 是您希望能够分配自己的新对象
    类,而不是仅使用一个全局对象来访问所有方法。

  • 为此,如果需要在成员函数之间传递类对象,则需要先将其转换为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.
        }
    }
    

    而且,当我们编译此Dll时,我们可以轻松地在C#应用程序中使用它。在使用我们在此dll中定义的功能之前,我们需要使用适当的[ImportDll()]。因此,对于我们的TestDll,我们将编写:
    [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());
    }
    

    我所做的一切就是为了使我的C++类成员函数在C#应用程序内部可轻松访问。

    注意:
    编译C#应用程序时,请确保已选择x86平台而非AnyCpu来编译项目。您可以通过属性更改平台。

    注意2 :
    要了解如何为本地C++类创建C++/CLI包装器,请阅读:C++/CLI wrapper for your native C++ class

    10-06 01:55