Question

So I am trying to write a wrapper around a c++ API so I can use it with C#. The c++ api and information about it is located here.

So I am trying to interact with the C++ dll from C# code. I am able to do so succesfully up to a certain point. But right now I am hung up trying to get a certain function working correctly. An example of a working call to the function in C++ is:

interception_set_filter(context, interception_is_keyboard, INTERCEPTION_FILTER_KEY_DOWN | INTERCEPTION_FILTER_KEY_UP);

where INTERCEPTION_FILTER_KEY_DOWN and INTERCEPTION_FILTER_KEY_DOWN are defined by:

typedef int (*InterceptionPredicate)(InterceptionDevice device);

enum InterceptionKeyState
{
    INTERCEPTION_KEY_DOWN             = 0x00,
    INTERCEPTION_KEY_UP               = 0x01,
...
};

    enum InterceptionFilterKeyState
    {
    INTERCEPTION_FILTER_KEY_DOWN             = INTERCEPTION_KEY_UP,
    INTERCEPTION_FILTER_KEY_UP               = INTERCEPTION_KEY_UP << 1,
};

and interception_is_keyboard one of various predicates that can be passed into interception_set_filter. The function of the predicate is described this way:

The interception_set_filter function has three parameters, the context of communication, a function pointer and a desired filter. This second parameter, the function pointer, is a device selection predicate, a function that receives a device id (like INTERCEPTION_KEYBOARD(0), INTERCEPTION_KEYBOARD(1), etc) as parameter and returns true if the device id passed is one of a device that must be filtered through the chosen filter, or false for the devices that are not to be filtered through this filter. So the interception_set_filter works by scanning all possible devices, and using the provided predicate as the criteria to know for which devices the provided filter should be applied.

Further, a method that implements the signature of this predicate interception_is_keyboard is defined in code thus:

int interception_is_keyboard(InterceptionDevice device)
{
    return device >= INTERCEPTION_KEYBOARD(0) && device <= INTERCEPTION_KEYBOARD(INTERCEPTION_MAX_KEYBOARD - 1);
}

The definition in the .h file for interception_set_filter is:

void ITERCEPTION_API interception_set_filter(InterceptionContext context, InterceptionPredicate predicate, InterceptionFilter filter);

where ITERCEPTION_API is:

#define ITERCEPTION_API __declspec(dllimport)

So, my question is, how can I set up to be able to call interception_set_filter and use the predicate interception_is_keyboard from a C# app (managed code)?


Was it helpful?

Solution

You can use C# delegates to create function pointers for PInvoke parameters. A similar question was asked here.

EDIT filter is given by the enum, or Int32. So that is known.

EDIT 2 Hans Passant commented that I do not need to use [MarshalAs(UnmanagedType.FunctionPtr)], it is assumed (default)I learned something new, thank you Hans). Also he makes a great point to, "make sure that the delegate stays referenced so it cannot get garbage collected while the native code is making callbacks". Thank you very much.

EDIT 3 I read a little from the link you provided, and apparently context is a void*. I would assume you also have to PInvoke interception_create_context to acquire your void*, and then pass that pointer. Assuming you have a valid pointer, I've adjusted the answer accordingly.

Also, I don't see where you define InterceptionDevice, I'll assume Int32 for now.

My C# delegate would look like this:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void InterceptionPredicateType(Int32 device);

[DllImport("your.dll")]
public extern static int interception_is_keyboard(IntPtr context, InterceptionPredicateType predicate, Int32 filter);

OTHER TIPS

There was already a C# wrapper here. The author dumped it because he preferred to make use of it in Clojure instead. Someone also made a Python wrapper and I've heard of others.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top