I'd like to pass an objective-c object as a void* ...
# kotlin-native
s
I'd like to pass an objective-c object as a void* that gets used internally in the c api. My interop is generated to expect a
CValuesRef<*>
for the object. I've seen the guidance to use
StableRef
to swim "kotlin to kotlin through c", but I am not invoking a callback, the c api is using the objective-c object itself.
Copy code
cinterop binding: some_c_fun(objcObj: CValuesRef<*>?)
actual c function: some_c_func(void* objcObj)
what I am trying in kotlin: some_c_func(StableRef.create(myObjcObj).asCPointer())
passing in the CValuesRef cpointer is crashing in the c api which I think I understand, the c api would need to call or unwrap to the obj c object before using it. Is there any advice on how I can either construct the appropriate CValueRef or create some new c api that can bridge the divide?
j
What type is
myObjcObj
today?
As an aside: `StableRef`s must be `dispose()`d so you wouldn't want to create orphaned ones like that.
s
MTLDeviceProtocol thanks on the dispose tip, not quite there yet.
j
Is that a struct? So like a type that implements
CStructVar
?
s
also MTKView and MTLCommandQueueProtocol. all 3 are passed in. Speaking only of MTLDeviceProtocol first...
j
There's a
.ptr
extension function on
CPointed
which
CStructVar
extends from.
s
not a struct, it is an instance of the interface MTLDeviceProtocol
Copy code
@kotlinx.cinterop.ExternalObjCClass public interface MTLDeviceProtocol : platform.darwin.NSObjectProtocol
j
Hmm I don't have a project with a darwin source set open right now. Perhaps all you need to do is then pin it? Like
.usePinned { }
, and then either
.objcPtr
or
addressOf(0)
. I've done a bit of objective-c interop, but I usually have to feel my way around as compared to raw C interop.
s
I still need to pass in
CValuesRef<*>
to the c api where it expects
void*
parameter. I am guessing I can add some c api in the def file to expect a native pointer, then call my underlying function.
j
addressOf returns a CPointer which is a CValuesRef
i don't know what objcPtr returns off the top of my head
I would have to go spelunking in a few projects which have Darwin sources to see if I've ever done this with an NSObject subtype that I referenced from Kotlin
s
this seems to work, at least doesn't crash immediately
Copy code
device.objcPtr().usePinned { d ->
        commandQueue.objcPtr().usePinned { q ->
            metalView.objcPtr().usePinned { view ->
                my_c_fun(
                    interpretCPointer<CPointed>(d.get()),
                    interpretCPointer<CPointed>(q.get()),
                    interpretCPointer<CPointed>(view.get())
                )
            }
        }
    }
not sure what will happen when the underlying things are referenced
j
Hmm I would think you would call objcPtr on the Pinned, but maybe pinning an objcPtr and calling get is functionally equivalent
s
that works too. you could write a book about what I dont know on this topic. thanks! calling
objcPtr
on the
Pinned<MTLDeviceProtocol>
was causing some unknown exception in calling a method on it on objc land. Reverting it back to calling
objcPtr()
on the actual underlying NSObjects makes it work, which makes sense to me.