none
C++/CLI, delegate and unmanaged callback RRS feed

  • Question

  • Hello,

    I have a non-trivial [at least for me] problem with delegates and unmanaged callbacks.

    In my case three project are involved: a native C++, a C++/CLI project and a C# Project [all VS 2013]

    native C++ project:

    class UnmanagedClass {
    public:
    	class UnmanagedCallback {
    	public:
    		virtual void init(const std::string &context) = 0;
    		virtual std::string getVariable(const std::string &varName) = 0;
    	};
    
    	int UnmanagedMethod(UnmanagedCallback& ucb);
    }

    c++/cli project:

    public delegate String^ VariableDelegate(String^ viewname, String^ varname);
    
    typedef std::function<void(std::string&, const std::string&, const std::string&)> CallBackFunc;
    
    //typedef void (*CallBackFunc)(std::string&, const std::string&, const std::string&);
    
    class DerivedUnmanagedCallback : public UnmanagedClass::UnmanagedCallback {
    public:
    	DerivedUnmanagedCallback(CallBackFunc func) : m_func(func) {};
    
    	void init(const std::string &context) {
    		m_context = context;
    	}
    
    	std::string getVariable(const std::string &varname) {
    		std::string result;
    		m_func(result, m_context, varname);
    		return result;
    	};
    
    private:
    	CallBackFunc m_func;
    	std::string m_context;
    };
    
    
    [ComVisible(true)]
    public ref class ManagedClass {
    public:
    	ManagedClass(....);
    	int ManagedMethod(VariableDelegate^ callback);
    private
    	UnmanagedClass* puc;
    }
    
    
    void myCallback(std::string& result, const std::string& context, const std::string& varname, void* pCallback) {
    	if (pCallback != __nullptr) {
    		VariableDelegate^ callback = // How to get delegate back from pCallback <---;
    		String^ Context = Helper::ConvertUTF8ToString(context);
    		String^ Varname = Helper::ConvertUTF8ToString(varname);
    		String^ Result = callback(Context, Varname);
    		Helper::ConvertStringToUTF8(result, Result);
    	}
    }
    
    int managedClass::ManagedMethod(VariableDelegate^ callback) {
    	GCHandle delegatehandle = GCHandle::Alloc(callback)
    	
    	delegatehandle = GCHandle::Alloc(callback);
    	IntPtr ptr = Marshal::GetFunctionPointerForDelegate(callback);
    	void * vptr = ptr.ToPointer();
    	
    	CallBackFunc func = std::bind(&myCallback, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, vptr);
    
    	DerivedUnmanagedCallback dcallback(func);
    
    	int res = puc->UnmanagedMethod(dcallback);
    
    	if (delegatehandle.IsAllocated) {
    		delegatehandle.Free();
    	}
    
    
    	return res;
    }	

    use case [C# Project]

    ManagedClass ManagedObj;
    
    string NetCallback(string context, string varname)
    {
    	return "foo";
    }
    
    
    ...
    
    int result = ManagedObj.ManagedMethod(NetCallback);
    

    My Problem is that I don't  know how to get baxk my delegate in myCallback from pCallback .

    Tia

      Hendrik Schmieder

    Tuesday, April 21, 2015 10:24 AM

Answers

  • "My Problem is that I don't  know how to get baxk my delegate in myCallback from pCallback ."

    There's Marshal::GetDelegateForFunctionPointer.

    But you don't really need any of this. You just need to use msclr::gcroot:

    void myCallback(std::string& result, const std::string& context, const std::string& varname, msclr::gcroot<VariableDelegate ^> callbackHandle) {
        if (callbackHandle) {
            VariableDelegate^ callback = callbackHandle;
            ...
        }
    }
    
    int ManagedClass::ManagedMethod(VariableDelegate^ callback) {
        msclr::gcroot<VariableDelegate ^> callbackHandle(callback);
        CallBackFunc func = std::bind(&myCallback, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, callbackHandle);
        DerivedUnmanagedCallback dcallback(func);
        return puc->UnmanagedMethod(dcallback);
    }
    

    • Marked as answer by h_schmieder Tuesday, April 21, 2015 1:01 PM
    Tuesday, April 21, 2015 11:10 AM
    Moderator

All replies

  • "My Problem is that I don't  know how to get baxk my delegate in myCallback from pCallback ."

    There's Marshal::GetDelegateForFunctionPointer.

    But you don't really need any of this. You just need to use msclr::gcroot:

    void myCallback(std::string& result, const std::string& context, const std::string& varname, msclr::gcroot<VariableDelegate ^> callbackHandle) {
        if (callbackHandle) {
            VariableDelegate^ callback = callbackHandle;
            ...
        }
    }
    
    int ManagedClass::ManagedMethod(VariableDelegate^ callback) {
        msclr::gcroot<VariableDelegate ^> callbackHandle(callback);
        CallBackFunc func = std::bind(&myCallback, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, callbackHandle);
        DerivedUnmanagedCallback dcallback(func);
        return puc->UnmanagedMethod(dcallback);
    }
    

    • Marked as answer by h_schmieder Tuesday, April 21, 2015 1:01 PM
    Tuesday, April 21, 2015 11:10 AM
    Moderator
  • Tanks for the answer.

    I already found Marshal::GetDelegateForFunctionPointer, but this has method has several restriction, one is

    You cannot use this method with function pointers obtained through C++ or from the GetFunctionPointer method.

    <https://msdn.microsoft.com/en-us/library/zdx6dyyh(v=vs.110).aspx>

    but the msclr::gcroot approach compiles, after I put

    #include <msclr\gcroot.h>

    before

    #include <vcclr.h>

    Tuesday, April 21, 2015 1:01 PM