How to call objc_msgSend from C on modern OS X versions

235 Views Asked by At

I need to make some relatively simple calls to objc_msgSend on OS X from C. This code use to work id event_data = objc_msgSend((id) objc_getClass("NSEvent"), sel_registerName("eventWithCGEvent:"), event_ref);, however, Apple recently changed the function signature to void objc_msgSend(void); to address some issues. The general consensus is that this should be solved with a function pointer, however, I am unable to get this to work without some ominous warnings about "function called through a non-compatible type" and "if this code is reached, the program will abort." My new function pointer implementation looks like id event_data = ((id (*)(id, SEL, CGEventRef)) objc_msgSend)((id) objc_getClass("NSEvent"), sel_registerName("eventWithCGEvent:"), event_ref); but I am concerned about the warnings. The event_ref variable is a function parameter defined as CGEventRef event_ref. Does anyone have an idea for making this work?

1

There are 1 best solutions below

4
Stephan Schlecht On BEST ANSWER

You could try:

id (*eventWithCGEvent)(Class, SEL, CGEventRef) = (id (*)(Class, SEL, CGEventRef)) objc_msgSend;

This defines a function pointer called eventWithCGEvent with three parameters: a receiver (since it is a class method, it is of type Class), the selector, and a parameter of type CGEventRef.

In a little more context it could look something like this:

#import "objc/message.h"
#import <CoreFoundation/CoreFoundation.h>
#import <CoreGraphics/CoreGraphics.h>


int main(int argc, const char * argv[]) {

    ...

    id (*eventWithCGEvent)(Class, SEL, CGEventRef) = (id (*)(Class, SEL, CGEventRef)) objc_msgSend;


    CGEventRef event_ref = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)42, true);

    Class NSEventClass = objc_getClass("NSEvent");
    SEL eventWithCGEventSelector = sel_registerName("eventWithCGEvent:");
    id event = eventWithCGEvent(NSEventClass, eventWithCGEventSelector, event_ref);
    CFRelease(event_ref);

    ...
    //do sth with event...
    ...

    return 0;
}