私はマネージ DLL からドライバーを統合することによって顧客向けライブラリの既存のネイティブ C++ 互換コード機能を拡張しているプロジェクトを持っていますが、これはほとんどのマーシャリングの質問とは反対の方向のようです。この 1 つのドライバーを使用する複数のデバイスが存在する可能性があるため、各デバイスは独自のコールバック メソッドを持つ独自のオブジェクトである必要があります。この統合は、ネイティブ クラス インターフェイスを顧客向けライブラリに公開するネイティブ ラッパー DLL の形式を取り、メンバー メソッド コールバック関数ポインタのインスタンスを DLL に渡します。マネージド ラッパー クラスへのデリゲートとしてネイティブ メソッド メンバー インスタンス (非静的) を渡す必要があります。マネージ ラッパー クラスは GetDelegateForFunctionPointer を使用します。これは、デリゲートへの静的ネイティブ ポインターをマーシャリングするために機能しますが、私にはできません。インスタンスで機能する場合は、情報が見つかりません。GetDelegateForFunctionPointer も関数ポインターの System::IntPtr 引数を取りますが、System::IntPtr がインスタンスに対して機能するかどうかもわかりません。また、VC++ 2008 でコンパイルすると、これを試みるとエラー C3867 が表示されます。
マネージド ラッパー ヘッダー:
//somemanagedclass.hpp
#pragma once
using namespace System;
using namespace ExternalManagedLibrary;
namespace SomeNameSpace
{
public ref class SomeManagedClass
{
public:
SomeManagedClass();
~SomeManagedClass();
delegate void CallbackHandler(const wchar_t*, int);
CallbackHandler^ CallbackEvent;
void RegisterCallback(IntPtr callbackEvent);
private:
ExternalManagedClass^ externalManagedClass;
void OnCallback(Object^ sender, ValueEventArgs<String^>^ e);
};
}
マネージド ラッパー ソース:
//somemanagedclass.cpp
#include "somemanagedclass.hpp"
#include <vcclr.h>
using namespace System;
using namespace Runtime::InteropServices;
namespace SomeNameSpace
{
SomeManagedClass::SomeManagedClass()
{
externalManagedClass = gcnew ExternalManagedClass();
externalManagedClass->CallbackEvent += gcnew EventHandler<ValueEventArgs<String^>^>(this, &SomeManagedClass::OnCallback);
}
SomeManagedClass::~SomeManagedClass()
{
externalManagedClass->CallbackEvent -= gcnew EventHandler<ValueEventArgs<String^>^>(this, &SomeManagedClass::OnCallback);
}
void SomeManagedClass::OnCallback(Object^ sender, ValueEventArgs<String^>^ e)
{
String^ some_string = String::Copy(e->Value);
cli::pin_ptr<const wchar_t> pinned_string = &PtrToStringChars(some_string)[0];
const wchar_t* p = pinned_string;
CallbackEvent(pinned_string, some_string->Length);
}
void SomeManagedClass::RegisterCallback(IntPtr callbackEvent)
{
CallbackEvent = (CallbackHandler^)(Marshal::GetDelegateForFunctionPointer(callbackEvent, CallbackHandler::typeid));
}
}
ネイティブ ラッパー インターフェイス:
//somenativeinterface.hpp
#ifdef DLL_EXPORT
#define IMPORT_EXPORT __declspec(dllexport)
#else
#define IMPORT_EXPORT __declspec(dllimport)
#endif //DLL_EXPORT
typedef void (*NativeCallback)(const unsigned char*, unsigned long);
class IMPORT_EXPORT SomeNativeInterface
{
public:
//class factory
static SomeNativeInterface* Create(void);
static void Destroy(SomeNativeInterface* clInterface);
virtual void CallbackInit(NativeCallback fnNativeCallbackInit);
};
ネイティブ ラッパー ヘッダー:
//somenativeclass.hpp
#pragma once
#include "somenativeinterface.hpp"
#include "somemanagedclass.hpp"
#include <vcclr.h>
using namespace SomeNameSpace;
class IMPORT_EXPORT SomeNativeClass : public SomeNativeInterface
{
public:
SomeNativeClass();
~SomeNativeClass();
void CallbackInit(NativeCallback fnNativeCallbackInit); //can this take an instance?
private:
NativeCallback fnNativeCallback;
void OnNativeCallback(const wchar_t* cString, int iSize);
gcroot<SomeManagedClass^> wrapper; //warning C4251
};
ネイティブ ラッパー ソース:
//somenativeclass.cpp
#include "somenativeclass.hpp"
#include <vcclr.h>
#include <string.h>
using namespace System;
using namespace Runtime::InteropServices;
SomeNativeInterface* SomeNativeInterface::Create()
{
return ((SomeNativeInterface*) new SomeNativeClass());
}
void SomeNativeInterface::Destroy(SomeNativeInterface* instance)
{
delete instance;
}
SomeNativeClass::SomeNativeClass()
{
wrapper = gcnew SomeManagedClass();
}
SomeNativeClass::OnNativeCallback(const wchar_t* cString, int iSize)
{
std::auto_ptr<char> pcConvertedString(new char[iSize+1]);
size_t iCharsConverted;
if (wcstombs_s(&iCharsConverted, (char*)*pcConvertedString, iSize+1, cString, iSize) == 0)
{
if (iCharsConverted > 0xFFFFFFFF)
iCharsConverted = 0xFFFFFFFF; //truncate
fnNativeCallback((const unsigned char*)*pcConvertedString, (unsigned long)(iCharsConverted));
}
}
SomeNativeClass::CallbackInit(NativeCallback fnNativeCallbackInit)
{
fnNativeCallback = fnNativeCallbackInit;
wrapper->RegisterCallback(System::IntPtr(this->OnNativeCallback)); //error C3867
}