I have a very small kotlin native project that gen...
# kotlin-native
y
I have a very small kotlin native project that generates a static lib:
Copy code
package sample

import platform.AppKit.NSView

fun attached(parent: NSView) : Boolean {
    println("kotlin::attached(${parent.window()})")
    return true
}
Then I have another (C++) project consuming the library and calling:
Copy code
lib->kotlin.root.sample.attached({ parent }))
where
parent
is a
NSView
that was created by some code I am not responsible for (it is passed to me). This simple code crashes... From the screenshot attached I can confirm that what is passed to me is a
NSView
pointer... but somehow on the kotlin side it crashes. I have tried with a few methods on
NSView
and they all trigger a crash. Any idea? Am I doing something wrong?
k
does this all execute synchronously? are you sure the reference remains valid?
y
Yes. There is no multi threading happening at all.
k
all I can say is that it's a memory error. maybe someone else has run into this.
s
lib->kotlin.root.sample.attached({ parent }))
This is wrong. You pass a struct with pointer to
NSView
where pointer to Kotlin object was expected.
k
i assumed that was psuedo-code 😛
s
Well, it doesn’t look like pseudocode to me.
y
Since I am doing something wrong, would you mind telling me how I can invoke the right way? This is the kotlin code:
Copy code
import platform.AppKit.NSView
fun attached(parent: NSView) : Boolean {
    println("kotlin::attached(${parent.window()})")
    return true
}
This is the generated header:
Copy code
typedef void*              libVst3Kotlin_KNativePtr;
struct libVst3Kotlin_KType;
typedef struct libVst3Kotlin_KType libVst3Kotlin_KType;

typedef struct {
  libVst3Kotlin_KNativePtr pinned;
} libVst3Kotlin_kref_platform_AppKit_NSView;


typedef struct {
  /* Service functions. */
  void (*DisposeStablePointer)(libVst3Kotlin_KNativePtr ptr);
  void (*DisposeString)(const char* string);
  libVst3Kotlin_KBoolean (*IsInstance)(libVst3Kotlin_KNativePtr ref, const libVst3Kotlin_KType* type);

  /* User functions. */
  struct {
    struct {
      struct {
        const char* (*helloFromKotlin)();
        libVst3Kotlin_KBoolean (*attached)(libVst3Kotlin_kref_platform_AppKit_NSView parent);
      } sample;
    } root;
  } kotlin;
} libVst3Kotlin_ExportedSymbols;
extern libVst3Kotlin_ExportedSymbols* libVst3Kotlin_symbols(void);
and this is what I have on the C++ side:
Copy code
void attached(NSView *parent) {
// this is wrong... so what is right?
lib->kotlin.root.sample.attached({ parent }));
}
Thanks
s
First of all I have to know more about your setup. AFAIK, it is not possible to import
NSView
from AppKit to C++ code. So I assume this is not pure C++. Do you use Objective-C++ here?
y
This is not code I have control over and some of it most likely use Objective C to call me... so on my side, technically I am getting a
void *
so the true api is
Copy code
void attached(void *parent) {
}
but I know it is a
NSView *
as is proven by the stack trace header. I can also simply rename my
.cpp
file into
.mm
and write the following code:
Copy code
#include <Cocoa/Cocoa.h>
void attached(void *parent) {
NSView *ptr = reinterpret_cast<NSView *>(parent);
ptr->window();
}
and this works perfectly. So I do know that
parent
is
NSView *
s
Btw, why not compile Kotlin code to Objective-C framework?
y
My entire project is C++ (I am writing a VST plugin). The VST SDK code has some Objective-C code in it but as far as I am concerned it is a black box to me... it is simply calling me back with the parent view created. I am new to kotlin native and I wanted to write some of the logic in kotlin vs C++ because I prefer to write kotlin code than C++. So I thought I am going to use kotlin native, compile to a static library and on the C++ side I am simply going to write a small C++ wrapper that delegates everything to kotlin. And this is where I run into this issue. In your first message you said I was invoking it wrong. This is why I asked (based on my understanding and generated code), what am I supposed to do to invoke it right. Are you now suggesting that the reason it is not working is not because I am invoking it wrong but because I did not generate an Objective-C framework?
s
I mean that calling
attached
properly would be much easier if Kotlin code was compiled to Objective-C framework. But it is still possible to do this when compiling Kotlin to C library: 1. Your Kotlin
attached
function should take
CPointer<*>
parameter, not
NSView
. And C++ part should pass
parent
itself to
attached
. 2. On Kotlin side this pointer can then be converted to
NSView
. You have two options here: a. (Kinda internal, but concise):
interpretObjCPointer<NSView>(ptr.rawValue)
b. Write Objective-C function to convert pointer to Objective-C reference (using
(__bridge NSView*)ptr
), and call it from Kotlin using
cinterop
. Note that you can include this entire function to your
.def
file.
y
Since I also need to write a Windows version on the kotlin side, I think it is better if the C++ side is unaware and always pass the
parent
(which is
void *
) as provided by the SDK. I will try your suggestion 1. and 2.a (I am not sure I understand 2.b but let me start with "easy" 😉)
I was able to properly implement your suggestion and it is working. Thank you for the help! I would have never figured out what to do by myself. For the record, the kotlin code is:
Copy code
fun attached(parent: CPointer<*>) : Boolean {
    val view = interpretObjCPointer<NSView>(parent.rawValue)
    println("kotlin::attached(tag=${view.tag()}, window=${view.window()})")
    return true
}
and the C++ side is (much simpler):
Copy code
// parent is void *
lib->kotlin.root.sample.attached(parent);
and the output proving it works...
Copy code
kotlin::attached(tag=-1, window=<SMTGCocoa1507737125_DocumentWindow: 0x7fd387d3ff20>)
👍 1