When we are working with JNI, first we create the native library. That library might have implemented in either C or C++. During runtime, lets say we are calling a native method. Depending on which language we used for native library implementation, VM has to provide JNIEnv variable. But how does VM know in which language (C or C++) we are implementing the code during runtime? Will it check the native library before passing arguments?
jni.h provides a thin C++ wrapper around the C API; the underlying calls are language-agnostic.
Related
I want to run a function of Cocoa's Quartz Window Services on Mac called CGWindowListCopyWindowInfo using a library called objc from Rust, is it possible?
I can't figure out how to run function it with send_msg!.
First, you're linking to the Swift version of the API, you really want the objective C version.
Second, Objective-C is for "methods" on objects, that is why send_msg! takes a subject (obj). CGWindowListCopyWindowInfo is part of a "core" service, which means it's pretty much straight C. Now I don't know if there are bindings for that, apparently Servo once maintained CG bindings but it seems like they're deprecated. You can probably BYO as if you were binding to a regular C library (by hand or using bindgen).
I would recommend learning how macOS APIs and frameworks work first, though.
I want to call members of a C++/CLI class from native C++ code. Compiler is prohibiting me from doing that. I know that we can use native pointers/references in managed code but don't know way of going opposite. Can anyone help me with this by giving a simple example.Thanks in advance.
It can't be done. Memory layout of managed types is determined by the JIT, so unless your native code uses the CLR programming interface, it has no way of discovering and accessing them. Keeping references visible to the garbage collector is another problem, although overcoming that is more straightforward.
However it is possible to create native types with C++/CLI and those will have a memory layout fixed at compile time, so both managed and native code can use them. That is the way to cross the managed-native boundary in reverse. (Function pointers created from delegates are another way to cross in reverse)
I need to know how do I declare a managed type inside native code?
Like: I have a ref class Editor in Editor.h
In native code(main.cpp):
Editor^ MainEditor;
But it gives me the following:
MainEditor' : global or static variable may not have managed type 'Cube3D::Editor ^'
I've tried to make it inside a container but I still need to declare it.
You can't do that directly. The issue is that the managed object will be moved by the garbage collector, and purely native code can't handle that.
Here's what is allowed:
Members of managed types must be compiled with /clr to produce managed code. This can use both managed and native types implemented with both managed and native code.
Members of native types and namespaces can be compiled with /clr to produce managed code. This can use both managed and native types implemented with both managed and native code.
Members of native types and namespaces can be compiled without /clr to produce native code. This can use only native types, but the types used can be implemented by either managed or native code.
It's even possible for some members of a native type to be implemented in native code and other members of the same type to be implemented in managed code.
So, you need a layer in between your native code and your managed type, this in-between layer will be a native type implemented with managed code.
Of course, #pragma managed can be used interchangeably with /clr, for finer control.
As the error states you can't have a managed type at global or static level.
You've declared it right for using it inside a method. For storing it inside a native class, you'll want to use gcroot.
How would you build a wrapper to unmanaged code in order to use it in managed code, and when exactly do you have to do that?
You don't often need a wrapper, many DLLs with straight-forward exported C functions can be pinvoked with the [DllImport] attribute. An exception for C exports would be a poorly designed DLL that requires the client code to release memory, that can't be done by the managed code since it doesn't have access to the allocator.
The case where you have to have a wrapper is a native C++ class. Managed code cannot pinvoke it directly since it doesn't know how to create an instance of the class (which requires knowing the size of the object and calling the constructor) nor how to destroy it (which requires calling the destructor). It is pretty easy to do in C++/CLI. Very mechanical, the SWIG project can do it automatically. Learning that tool is however more of an investment than learning how to write the wrapper.
Is there a recommended way to wrap a native c++ library by c++ cli?
Not sure if one size fits all, but yeah, it is largely a mechanical process. Your ref class wrapper should declare a private member that's a pointer to your native C++ class. Create the instance in the constructor. You'll need a destructor and a finalizer to delete that instance again.
Then for each function in the native C++ class you write a managed version of it. That's almost always a one-to-one call, you simply call the corresponding native method and let C++ Interop convert the arguments. Sometimes you have to write a bit of glue code to convert a managed argument to the native version of it, particularly if your native method uses 8-bit char* or structure arguments.
You'll find that standard pattern in code in my answer here. I also should mention SWIG, a tool that can automate it. Not sure how good it is, never used it myself.