gartenriese
gartenriese

Reputation: 4366

Passing a C# delegate to a C++/CLI wrapper

I was following this example to use a c# delegate as a c++ callback.

My wrapper looks like this:

// GLFWWrapper.h

#pragma once

using namespace System;

namespace GLFWWrapper {

    typedef void(__stdcall *KEY_CALLBACK)(int, int, int, int);

    public ref class Window {
        public:
            void setKeyCallback(KEY_CALLBACK fp);
            static KEY_CALLBACK csharpKeyCallback;
        ...
    };
}  

// GLFWWrapper.cpp

#include "stdafx.h"

#include "GLFWWrapper.h"

namespace GLFWWrapper {

    void cppKeyCallback(GLFWwindow * window, int key, int scancode, int action, int mods) {
        if (Window::csharpKeyCallback) {
            Window::csharpKeyCallback(key, scancode, action, mods);
        }
    }

    void Window::setKeyCallback(KEY_CALLBACK fp) {
        csharpKeyCallback = fp;
    }

    ...
}

The cppKeyCallback function is a callback I set in another function (glfwSetKeyCallback(m_ptr, cppKeyCallback);). The csharpKeyCallback is supposed to be the delegate from my C# project. In the example I linked to above it is only explained how I can set a delegate from inside my wrapper. But how can I set the delegate from my C# project? When I try to call setKeyCallback from my C# project I get an error Window.setKeyCallback(?) is not supported by the language.

Upvotes: 1

Views: 1609

Answers (1)

Zverev Evgeniy
Zverev Evgeniy

Reputation: 3719

You seem to be missing the managed part of the instruction:

#pragma managed

public delegate void keyCallback(int, int, int, int);

void Window::setKeyCallback(keyCallback^ fp) {
    csharpKeyCallback = fp;
}

In order to pass a reference to a function instance (delegate) from C# to C++\CLI you need to declare it i.e. declare a managed delegate. This can be done either in C# or in C++\CLI.

In your code the KEY_CALLBACK is an unmanaged function declaration. Thus it is "Not supported by the language". C# side cannot use it as a delegate declaration.

In order to avoid such a mess I myself always keep my C++\CLI projects clear of any managed declarations and provide those in an additional C# class library that is referenced from both the C++\CLI wrapper and the C# side.

Edit: Do not forget to put the ^ sign after the managed reference type in the managed method declaration or the compiler is going to bust you with an error 'A delegate type is not allowed here'.

Upvotes: 4

Related Questions