.net - How to specify a callback from C# to C++/CLI -
i pass function pointer (or similar) callback function constructor of c# class, called c++/cli. c# class sub-module; c++ side main program. i'm getting errors reported visual studio 2017, , can't work out correct syntax use. (i'm c++ programmer, have close 0 experience cli , c#.) find plenty of examples on how set callbacks other way around, c# c++/cli find little information.
can tell me correct syntax is, or show different approach achieve same goal if 1 fundamentally flawed?
c# code (seems fine):
namespace mynamespace { public class mycsharpclass { private action<string> m_logger; public mycsharpclass(action<string> logger) => m_logger = logger; public void logsomething() { m_logger("hello world!"); } } }
c++/cli code (errors in second gcnew line system::action):
#pragma once #pragma managed #include <vcclr.h> class ilbridge_mycsharpclass { public: ilbridge_mycsharpclass(manageddll_mycsharpclass* pmanageddll_mycsharpclass) : m_pmanageddll_mycsharpclass(pmanageddll_mycsharpclass) { m_pimpl = gcnew mycsharpclass::mycsharpclass( gcnew system::action<system::string^>^(this, &ilbridge_mycsharpclass::log) ); } void log(system::string^ message) const { // ... } }
the errors reported:
error c3698: 'system::action<system::string ^> ^': cannot use type argument of 'gcnew' note: did mean 'system::action<system::string ^>' (without top-level '^')? error c3364: 'system::action<system::string ^>': invalid argument delegate constructor; delegate target needs pointer member function
if remove "^" suggested, c3698 error disappears c3364 error remains.
i'm following design pattern suggested here, though not using code generation: http://blogs.microsoft.co.il/sasha/2008/02/16/net-to-c-bridge/
edit: essential solution
an action
in c++ cli, can created function (not member function free or static
) or member function of managed ref class
.
in order call native member function action, native member call needs wrapped in managed member function.
class nativeclasstype; ref class managedwrapper { typedef void(nativeclasstype::*memberfunc)(system::string^); nativeclasstype* nativeobject; memberfunc memberfunction; public: managedwrapper(nativeclasstype* obj, memberfunc wrappedfunction) : nativeobject(obj), memberfunction(wrappedfunction) { // action can used in other managed classes invoke member function nativeclasstype auto actionobject = gcnew system::action<system::string^>(this, &managedwrapper::callwrapped); } void callwrapped(system::string^ msg) { // forward call (nativeobject->*memberfunction)(msg); } };
original answer , full example
i played around little , far can tell, need use native member function pointer handling @ point in order callback native member functions...
the following example code provides managed (ref
) class static function callback , 1 member function callback. native class nativemanaged
using both bridge classes demonstrate different callbacks.
ref class ilbridge_logger { private: system::action<system::string^>^ loggercallback; public: ilbridge_logger(void (*logfn)(system::string^)) { loggercallback = gcnew system::action<system::string^>(logfn); } ilbridge_logger(system::action<system::string^>^ logfn) { loggercallback = logfn; } void test(system::string^ msgin) { log(msgin); } void log(system::string^ message) { loggercallback(message); } }; template<typename callbackobject> ref class ilbridge_memberlogger : public ilbridge_logger { callbackobject* o; void (callbackobject::*logfn)(system::string^); public: ilbridge_memberlogger(callbackobject* o, void (callbackobject::*logfn)(system::string^)) : ilbridge_logger(gcnew system::action<system::string^>(this, &ilbridge_memberlogger::logmember)), o(o), logfn(logfn) { } // translate native member function call managed void logmember(system::string^ message) { (o->*logfn)(message); } }; class nativemanaged { gcroot<ilbridge_logger^> impl1; gcroot<ilbridge_logger^> impl2; public: nativemanaged() { impl1 = gcnew ilbridge_logger(gcnew system::action<system::string^>(log1)); impl2 = gcnew ilbridge_memberlogger<nativemanaged>(this, &nativemanaged::log2); } void test(system::string^ msgin) { impl1->test(msgin); impl2->test(msgin); } // static logger callback static void log1(system::string^ message) { system::console::writeline(l"static log: {0}", message); } // member logger callback void log2(system::string^ message) { system::console::writeline(l"member log: {0}", message); } }; int main(array<system::string ^> ^args) { nativemanaged c; c.test(l"hello world"); return 0; }
note: there might more elegant ways of handling member function pointers c++11/14/17 features i'm not aware of.
Comments
Post a Comment