Objective-C Wrapper for CFunctionPointer to a Swift Closure - ios

I am playing with Swift and noticed that Swift does not allow to create CFFunctionPointers. It can only pass around and reference existing ones.
As for example CoreAudio requires CFunctionPointer to certain callbacks therefore I cannot use pure Swift.
So I need to use some Objective-C trampoline or wrapper here that takes a Swift Closure as a parameter as well as the original callback prototype and then can be assigned to be the callback, but the actually action happens in Swift and not Objective-C.
How do I do this?
Some example code for such a wrapper would help me to understand how I can use Swift code from objective C for such purposes in a flexible way to work around Swift not being able to create CFunctionPointers.
Yes, I know I can just write stuff when needed in Objective-C. I want to do it in pure Swift as a learning exercise porting one of my apps to Swift (uses a lot of CoreAudio/CoreVideo framework).

I needed to define this callback:
typedef void (*MIDIReadProc) ( const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon );
and I wanted to use Objective-C as least as possible.
This was my approach:
MIDIReadProcCallback.h
#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
typedef void (^OnCallback)(const MIDIPacketList *packetList);
#interface MIDIReadProcCallback : NSObject
+ (void (*)(const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon))midiReadProc;
+ (void)setOnCallback:(OnCallback)onCallback;
#end
MIDIReadProcCallback.m
#import "MIDIReadProcCallback.h"
static OnCallback _onCallback = nil;
static void readProcCallback(const MIDIPacketList *pktlist, void *refCon, void *connRefCon) {
if (_onCallback) {
_onCallback(pktlist);
}
}
#implementation MIDIReadProcCallback
+ (void (*)(const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon))midiReadProc {
return readProcCallback;
}
+ (void)setOnCallback:(OnCallback)onCallback {
_onCallback = onCallback;
}
#end
Then you can register MIDIReadProcCallback.midiReadProc as callback and set handler MIDIReadProcCallback.setOnCallback({ (packetList: MIDIPacketList) in ... })

Well, you can create a function pointer.
var ump = UnsafeMutablePointer<((UnsafePointer<MIDIPacketList>, UnsafeMutablePointer<Void>, UnsafeMutablePointer<Void> ) -> Void)>.alloc(1)
ump.initialize(MyMIDIReadProc)
let cp = COpaquePointer(ump)
let fp = CFunctionPointer<((UnsafePointer<MIDIPacketList>, UnsafeMutablePointer<Void>, UnsafeMutablePointer<Void> ) -> Void)>(cp)
status = MIDIDestinationCreate(midiClient,
name,
fp,
etc.
It doesn't work though with Core MIDI.
thread #7: tid = 0x713b7, 0x7a1541f0, stop reason = EXC_BAD_ACCESS (code=2, address=0x7a1541f0)
frame #0: 0x7a1541f0
frame #1: 0x00159295 CoreMIDI`LocalMIDIReceiverList::HandleMIDIIn(void*, OpaqueMIDIEndpoint*, void*, MIDIPacketList const*) + 117
BTW., you cannot have a bridging header if your MIDI code is in a framework you're writing.

Related

Getting the ObjectiveC reference of a C# Object (Xamarin.iOS, CAMetalLayer)

I am new to Objective C and I am trying to port my OpenGL based 3D rendering engine to Metal. In the current state, the Window creation and View controller management are in C# (based on Xamarin.iOS) and Rendering part is handled in Native ( C++ & OpenGL).
I am thinking of creating the CAMetalLayer in the ViewController in C# and rest of the Metal related rendering code in Objective C. Can anyone tell me how can I pass the reference of the CAMetalLayer instance and use it in Objective C code.
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Perform any additional setup after loading the view, typically from a nib.
mtlDevice = Metal.MTLDevice.SystemDefault;
mtlLayer = new CAMetalLayer();
mtlLayer.Device = mtlDevice;
mtlLayer.PixelFormat = MTLPixelFormat.BGRA8Unorm;
mtlLayer.FramebufferOnly = true;
mtlLayer.Frame = View.Layer.Frame;
View.Layer.AddSublayer(mtlLayer);
}
How can I pass the reference of the mtlLayer which is created in C# to objective C?
Or I can create the mtlLayer in Objective C, but how do I do the View.Layer.AddSublayer()?
Found the answer to my own question after some reading.
From C#
Pass the mtlLayer.Handle(IntPtr) to native through DllImport
public class Engine
{
[DllImport("__Internal", EntryPoint = "nativeMetalInit")]
public static extern void Init(
IntPtr device,
IntPtr layer);
}
Engine.Init(mtlDevice.Handle, mtlLayer.Handle);
In Native C/Cpp library
API void nativeMetalInit(void* device, void *layer)
{
metalInit(device, layer);
}
In the Objective Cpp (.mm file)
void metalInit(void *device, void *layer)
{
pRenderer = [[NativeRenderer alloc] init];
[pRenderer initilalizeMetal: device andLayer:layer];
}
- (void)initilalizeMetal: (void*) pDevice andLayer: (void*) pLayer
{
self.mtlLayer = (__bridge CAMetalLayer*) pLayer;
self.mtlDevice = (__bridge id<MTLDevice>)pDevice;
}

How to convert function parameter from Obejctive-C to Swift?

I have a question about syntax of function parameter in Swift.
I want to get message through C based callback function from library, so I make a function with Objective-C as below:
void foo(char *arg) {
NSLog(#"%s", log);
}
Then, I register foo to MainController interface with Objective-C like this.
typedef void (*CB)(char *);
void addFoo(CB func);
...
addFoo(&foo);
The above code is a simplified representation, but it print log for library well.
Now, I have to change the language from Objective-C to Swift. Most of the source code has changed, but for the above function, the log is not output normally.
How can I change?
Please help.
I tried to convert directly. This is code.
typealias CB = (String) -> Void
func addCB(cd: CB) {
// ...
}
func foo(pa: String) {
// ...
}
var fooFuc: CB = foo(pa: )
addCB(cd: fooFuc)

Which threading mode is Sqlite for iOS compiled in Swift?

The page http://www.sqlite.org/threadsafe.html mentions:
Single-thread
Multi-thread
Serialized
How can we implement that threads in Swift. Or how to use sqlite3_config(SQLITE_CONFIG_MULTITHREAD in Swift
Instead of sqlite3_config you can add the required options when opening the database. This is only available for sqlite3_open_v2, not for sqlite3_open or sqlite3_open16.
Here is an example:
let rc = sqlite3_open_v2(databasePath, &db, SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_FULLMUTEX, nil)
For anyone who ended up here looking for a way to call sqlite3_config (regardless of the threading question) using the built-in SQLite3 module...
The reason it's not available is that it uses ellipsis-style variadic arguments, which according to this are not supported in Swift. One way to get around this is to make your own C header with wrapper functions for calling sqlite3_config with whatever (non-variadic) argument arrangement you need.
For example, a "bridging header" with something like this covers all the valid call signatures you might need (as far as what the SQLite config options require):
#ifndef SqliteConfig_h
#define SqliteConfig_h
#import "sqlite3.h"
static inline int sqlite3_config_no_args(int op) {
return sqlite3_config(op);
}
static inline int sqlite3_config_ptr(int op, void* arg1) {
return sqlite3_config(op, arg1);
}
static inline int sqlite3_config_int(int op, int arg1) {
return sqlite3_config(op, arg1);
}
static inline int sqlite3_config_ptr_int_int(int op, void* arg1, int arg2, int arg3) {
return sqlite3_config(op, arg1, arg2, arg3);
}
static inline int sqlite3_config_int_int(int op, int arg1, int arg2) {
return sqlite3_config(op, arg1, arg2);
}
static inline int sqlite3_config_ptr_ptr(int op, void* arg1, void* arg2) {
return sqlite3_config(op, arg1, arg2);
}
#endif /* SqliteConfig_h */
Maybe there are cleaner or more idiomatic ways to create these kinds of wrappers (rather than static-inline functions in a bridging header). I'm not an expert in this area. But considering they're just wrapping calls, it seems like a good lightweight workaround.
You can search around for more info on bridging headers if you don't know how to create one. But in short: You can create a bridging header "manually" (after creating your .h file) by going to Build Settings/Swift Compiler - General/Objective-C Bridging Header and setting the value to the header filename you created. If you don't do that, your .h file is ignored. Or you could create one automatically (without going into the compiler settings) by dragging a dummy .c file into the project, deleting that file, and then editing the header it created. Or do that with a "real" C file if you prefer your code there rather than inline.
With that in place, here's an example of using sqlite3_config to install your own logging callback:
import SQLite3
func errorLogCallback(_: OpaquePointer?, iErrCode: Int, zMsg: UnsafePointer<CChar>)
{
let s = String(cString: zMsg)
print("LOG:", iErrCode, s)
}
let cCallbackPtr: #convention(c) (OpaquePointer?, Int, UnsafePointer<CChar>) -> () = errorLogCallback
let rawPtr = unsafeBitCast(cCallbackPtr, to: UnsafeMutableRawPointer.self)
sqlite3_config_ptr_ptr(SQLITE_CONFIG_LOG, rawPtr, nil)

Is there a method to allow pure c file to use <Metal/Metah.h>?

In other words, could ios's metal be used in pure c file? Thanks for reviewing.
The Metal API is Objective-C, however that shouldn't present a problem as you can provide C functions within Objective-C implementation files so the rest of your C-based code can call these functions.
For example (I don't know the Metal API, so this is gibberish):
metalapi.h:
// This is a C function...
extern int doThingWithMetal(int someParam, const char *otherParam);
metalapi.m:
#import <Metal/Metal.h>
// ... implemented in Objective-C
int doThingWithMetal(int someParam, const char *otherParam)
{
return [someMetalClass someMethod:someParam] == SOME_VALUE ? 0 : 1;
}
otherfile.c
#include "metalapi.h"
....
if (doThingWithMetal(1, "Hello") == 0) {
...
}

why I can't hook my private function with fishhook

These days, I found that hook in an iOS application is hard, and found that there is a tool called "fishhook", created by facebook. I import the tool in my personal project, but it doesn't work. Am I wrong? Here are the source code:
#import <dlfcn.h>
#import <Foundation/Foundation.h>
#import "fishhook.h"
static void (*orig_testABC)(void);
void testABC()
{
NSLog(#"This is main log...");
}
void my_testABC()
{
NSLog(#"This is other log, not main log...");
}
void save_original_symbols()
{
// void *handle = dlopen("/Users/bianyiji/Library/Developer/Xcode/DerivedData/HookTest-ghlgmahvsgfbqeekbrouzdyoxgdw/Build/Intermediates/HookTest.build/Debug/HookTest.build/Objects-normal/x86_64/main.o", RTLD_LAZY);
// printf("%s\n", handle);
orig_testABC = dlsym(RTLD_DEFAULT, "testABC");
}
int main(int argc, const char * argv[]) {
#autoreleasepool {
// save_original_symbols();
int rebind_int = rebind_symbols((struct rebinding[1]){"testABC", my_testABC}, 1);
printf("%d\n", rebind_int);
}
testABC();
return 0;
}
Although I called the function "testABC()", but I use "rebind_symbols" before, why I can't get my expected result...
fishhook isn't meant to hook into private functions, because fishhook works by rebinding symbols that are present in the symbol table.
for hooking private functions you need read-write access in the executable memory pages of your running app, and this is obviously not possible for security reasons.
however, in jailbroken iOS, the kernel has a patch that allows this, so you can hook private functions with frameworks such as CydiaSubstrate or substitute. But fishhook does not support this and probably never will, also if it did would never be AppStore-friendly.
Source: our open-source SSL pinning library TrustKit uses fishhook and we introduced it at BlackHat 2015 elaborating an all these topics.

Resources