4

C++ の writen クラスを dll にインポートし、その dll を ac# アプリケーションで使用するように言われました。このガイドに従ってdll を作成しましたが、いくつかの問題があるため、C# アプリケーションで単純に使用することはできません。

  1. ファクトリ関数の戻り値の型には何を配置すればよいですか?

  2. const wchar_t*コンストラクターの引数の型に相当するものは何ですか?

  3. 型の関数の戻り値の型を取得して使用するにはどうすればよいvector< wstring>ですか?

これらの問題により、C# アプリケーション内で C++ DLL を使用できなくなります。C++/CLI でラッパーを作成し、それを C# 内で使用する必要があると言われました。しかし悲しいことに、私はそれについて何も知りません。私は C++.net を知りません。

現在、私にとってもう少しセンセーショナルに思える唯一のことは、何らかの方法で C と互換性を持たせてから、C DLL を作成し、それを私の C# アプリケーションで使用することです。C では、クラス オブジェクト ポインターは s を介してアクセスできると読んだことがHANDLEあります。

問題は、Handle を使用して C のクラス オブジェクトにアクセスし、それらを使用するにはどうすればよいかということです。vector<wstring>そして、どうすればaをそのCの対応物に変換できますか? CLI を使用して C++ DLL のラッパー (DLL?) を作成し、他の dotnet アプリで使用するにはどうすればよいですか?

4

3 に答える 3

4

たとえばアプリケーションで使用されるクラスを作成するには、次のようにしC wrapperます。C++C#

Visual StudioWin32 Console Applicationで名前を選択して入力し、[次へ] をクリックして、次のペインで選択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);                         
}

この extern "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# アプリケーションで使用できる C ベースの dll を取得します。
注意すべき点がいくつかありますが、より重要なものは次のとおりです。

  1. プロキシとして使用するコード、つまり 内の関数定義を意味することを理解する必要がありますtestdll.h。C と互換性のある型のみを使用する必要があります。C++ ではなく C です。
  2. 1 つのグローバル オブジェクトを使用してすべてのメソッドにアクセスするのではなく、クラスの新しいオブジェクトを割り当てられるようにしたいということです。

このため、メンバー関数間でクラス オブジェクトを渡す必要がある場合は、まずそれvoid*を C が理解できる に変換してから渡し、それを使用して任意のメンバー関数にアクセスする必要があります。

たとえば、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# アプリケーションをコンパイルするときは、プロジェクトをコンパイルするため
のプラットフォームを選択していないことを確認してください。プロパティを使用してプラットフォームを変更できます。 x86AnyCpu

注 2 :
ネイティブ C++ クラス用の C++/CLI ラッパーを作成する方法については、次を参照してください: ネイティブ C++ クラス用の C++/CLI ラッパー.

于 2013-08-09T15:34:21.530 に答える