.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

Popular posts from this blog

Is there a better way to structure post methods in Class Based Views -

performance - Why is XCHG reg, reg a 3 micro-op instruction on modern Intel architectures? -

jquery - Responsive Navbar with Sub Navbar -