2015-09-03 3 views
0

Мой обратный вызов в неуправляемом C++ это:Управляется неуправляемым обратным вызовом с управляемыми параметрами?

typedef void (*ErrorCallback)(OutputLog& log, std::string& message); 

Это использование (код упрощен):

class OutputLog 
{ 
private: 
    ErrorCallback _callback; 

public: 

    void Error(std::string& message) 
    { 
     // print message to console/stream here 

     if (_callback) 
     { 
      _callback(*this, message); 
     } 
    } 
}; 

В C++/CLI я создал класс-оболочку для моего неуправляемого класса OutputLog. Я определил функцию обратного вызова, как, например:

public delegate void ErrorCallback(OutputLog^ log, String^ message); 

Так что я знаю, что я могу получить указатель на функцию с помощью Marshal::GetFunctionPointerForDelegate, но как преобразовать управляемые параметры (OutputLog^ log и String^ message) их неуправляемыми коллегами (OutputLog& log и std::string& message)?

ответ

1

Предполагая, что вы хотите использовать управляемый вывод OutputLog для .NET-клиентов для использования и передавать завершенный собственный OutputLog в библиотеку, позволяя пользователям .NET получать уведомления об ошибках, вы можете использовать что-то в этих строках.

#include "stdafx.h" 
#include <string> 

#pragma region NATIVE 
typedef void (*ErrorCallback)(class OutputLog& log, const std::string& message, void* userData); 

class OutputLog 
{ 
private: 
    ErrorCallback m_callback; 
    void* m_userData; 

public: 
    OutputLog() 
     : m_callback(nullptr), m_userData(nullptr) { } 

    void SetCallback(ErrorCallback callback, void* userData) { 
     m_callback = callback; 
     m_userData = userData; 
    } 

    void Error(const std::string& message) 
    { 
     if (m_callback) { 
      m_callback(*this, message, m_userData); 
     } 
    } 
}; 
#pragma endregion 

#pragma region MANAGED 
#include <msclr/gcroot.h> 

using namespace System; 
using namespace System::Runtime::CompilerServices; 

class NativeErrorCallbackHandler 
{ 
public: 
    NativeErrorCallbackHandler(ref class OutputLogManaged^ owner); 
private: 
    static void OnError(class OutputLog& log, const std::string& message, void* userData); 
    msclr::gcroot<OutputLogManaged^> m_owner; 
}; 

public delegate void ErrorEventHandler(ref class OutputLogManaged^ log, String^ message); 

public ref class OutputLogManaged 
{ 
public: 
    OutputLogManaged() 
     : m_nativeOutputLog(new OutputLog), 
     m_nativeHandler(new NativeErrorCallbackHandler(this)) { } 

    ~OutputLogManaged() { // = Dispose 
     this->!OutputLogManaged(); 
    } 

    !OutputLogManaged() // = Finalize 
    { 
     delete m_nativeOutputLog; 
     m_nativeOutputLog = nullptr; 
     delete m_nativeHandler; 
     m_nativeHandler = nullptr; 
    } 

    event ErrorEventHandler^ Error 
    { 
     [MethodImplAttribute(MethodImplOptions::Synchronized)] 
     void add(ErrorEventHandler^ value) { 
      m_managedHandler = safe_cast<ErrorEventHandler^>(Delegate::Combine(value, m_managedHandler)); 
     } 

     [MethodImplAttribute(MethodImplOptions::Synchronized)] 
     void remove(ErrorEventHandler^ value) { 
      m_managedHandler = safe_cast<ErrorEventHandler^>(Delegate::Remove(value, m_managedHandler)); 
     } 

    private: 
     void raise(OutputLogManaged^ log, String^ message) { 
      auto managedHandler = m_managedHandler; 
      if (managedHandler != nullptr) 
       managedHandler(this, message); 
     } 
    } 

internal: 
    void RaiseErrorEvent(String^ message) { 
     Error(this, message); 
    } 

    OutputLog* GetNative() { return m_nativeOutputLog; } 

private: 
    OutputLog* m_nativeOutputLog; 
    NativeErrorCallbackHandler* m_nativeHandler; 
    ErrorEventHandler^ m_managedHandler; 
}; 

NativeErrorCallbackHandler::NativeErrorCallbackHandler(OutputLogManaged^ owner) 
    : m_owner(owner) 
{ 
    m_owner->GetNative()->SetCallback(&OnError, this); 
} 

void NativeErrorCallbackHandler::OnError(OutputLog& log, const std::string& message, void* userData) 
{ 
    static_cast<NativeErrorCallbackHandler*>(userData)->m_owner->RaiseErrorEvent(
     gcnew String(message.c_str(), 0, message.size())); 
} 
#pragma endregion 

#pragma region Test 
void Test(OutputLog& log) 
{ 
    log.Error("This is a test."); 
} 

void OnError(OutputLogManaged^ sender, String^ message) 
{ 
    Console::WriteLine(message); 
} 

int main(array<System::String ^> ^args) 
{ 
    OutputLogManaged managedLog; 
    managedLog.Error += gcnew ErrorEventHandler(&OnError); 

    Test(*managedLog.GetNative()); 
    return 0; 
} 
#pragma endregion 
+0

Отлично! Спасибо. –

0

Невозможно «преобразовать» OutputLog^ (если вы собираетесь использовать существующие функции маршаллинга). Но есть (как минимум) один для преобразования String^ в std::string:

#include <msclr\marshal_cppstd.h> 
String^ manStr = "BLAH"; 
std::string stdStr = msclr::interop::marshal_as<std::string>(manStr); 

Как и в других ответах упоминалось, это не ясно, что вы хотите сделать. Если вы хотите, чтобы войти сообщения об ошибках в управляемом коде с помощью неуправляемого регистратора, вы можете написать что-то вроде этого:

namespace unmanaged 
{ 
    class OutputLog; 
    typedef void(*ErrorCallback)(OutputLog& log, std::string& message); 

    class OutputLog 
    { 
    public: 
     ErrorCallback _callback; 

     void Error(std::string& message) 
     { 
      if (_callback) 
      { 
       _callback(*this, message); 
      } 
     } 
    }; 
} 

namespace managed 
{ 
    ref class OutputLog 
    { 
    private: 
     unmanaged::OutputLog *m_log = nullptr; 

    public: 
     OutputLog() {} 
     OutputLog(unmanaged::OutputLog *log) 
      : m_log(log) {} 

     void Error(String^ message) 
     { 
      // Do something managed stuff, then use the unmanaged logger. 
      if (m_log != nullptr) 
      { 
       std::string stdStrMessage = msclr::interop::marshal_as<std::string>(message); 
       m_log->Error(stdStrMessage); 
      } 
     } 
    }; 
} 

void PrintMsg(unmanaged::OutputLog& log, std::string& msg) 
{ 
    cout << msg << endl; 
} 

int main(array<System::String ^> ^args) 
{ 
    unmanaged::OutputLog *unmanOL = new unmanaged::OutputLog(); 
    unmanOL->_callback = PrintMsg; 
    managed::OutputLog^ manOL = gcnew managed::OutputLog(unmanOL); 

    manOL->Error("Hello"); 

    return 0; 
} 

delegate Управляемая был удален и managed::OutputLogger содержит ссылку на неуправляемом один.

+0

Вы уверены, что эти строки точно преобразуются? (Набор символов/встроенные нули) – Deduplicator

+0

@Deduplicator, я больше не изучал его. –

Смежные вопросы