5

I know it is possible to use Objective C code using objc_msgSend to, I believe, manually run the Objective C runtime however when I run this code I get errors referencing NSString (even though I never use it) as well as other un-used classes.

Errors from xcode

enter image description here

I have the Objective C Code above it (commented out) that I am trying to 'mimic'.

#include <Foundation/Foundation.h> /*Added suggestion by answer, same errors*/
#include <AppKit/AppKit.h>

int main()
{
// convert objective c into c code
/*
    NSAlert *alert = [[NSAlert alloc] init];
    [alert setAlertStyle:NSInformationalAlertStyle];
    [alert setMessageText:@"Hello World"];
    [alert setInformativeText:@"Hello World"];
    [alert runModal];
*/
    id alert = objc_msgSend(objc_msgSend(objc_getClass("NSAlert"), sel_registerName("alloc")), sel_registerName("init"));
    objc_msgSend(alert, sel_getUid("setAlertStyle:"), NSInformationalAlertStyle);
    objc_msgSend(alert, sel_getUid("setMessageText:"), CFSTR("Hello World!"));
    objc_msgSend(alert, sel_getUid("setInformativeText:"), CFSTR("Hello World!"));
    objc_msgSend(alert, sel_getUid("runModal"));
}
Zimm3r
  • 3,369
  • 5
  • 35
  • 53

1 Answers1

6

You are missing some imports.

objc_msgSend is declared in <objc/message.h>.

objc_getClass is declared in <objc/runtime.h>.

sel_getUid and sel_registerName are declared in <objc/objc.h>.

Now, given that <objc/objc.h> is already imported by <objc/runtime.h>, importing the latter along with <objc/message.h> should suffice.

I tested it with the following example and it works as expected

#include <CoreFoundation/CoreFoundation.h> // Needed for CFSTR
#include <objc/runtime.h>
#include <objc/message.h>

int main(int argc, char *argv[]) {
    id alert = (id (*)(id, SEL))objc_msgSend((id (*)(id, SEL))objc_msgSend(objc_getClass("NSAlert"), sel_registerName("alloc")), sel_registerName("init"));
    (void (*)(id, SEL, int))objc_msgSend(alert, sel_getUid("setAlertStyle:"), 1); // NSInformationalAlertStyle is defined in AppKit, so let's just use 1
    (void (*)(id, SEL, id))objc_msgSend(alert, sel_getUid("setMessageText:"), CFSTR("Hello World!"));
    (void (*)(id, SEL, id))objc_msgSend(alert, sel_getUid("setInformativeText:"), CFSTR("Hello World!"));
    (int (*)(id, SEL))objc_msgSend(alert, sel_getUid("runModal"));
}

Note

I added the explicit cast to objc_msgSend as suggested by Greg Parker in the comments.

Gabriele Petronella
  • 106,943
  • 21
  • 217
  • 235