mirror of https://github.com/adamdruppe/arsd.git
updates
This commit is contained in:
parent
728b9a6182
commit
b490ed1ab5
|
@ -11,8 +11,9 @@ public import core.stdc.string;
|
|||
import core.atomic;
|
||||
|
||||
pragma(lib, "advapi32");
|
||||
pragma(lib, "ole32");
|
||||
pragma(lib, "uuid");
|
||||
pragma(lib, "ole32");
|
||||
pragma(lib, "oleaut32");
|
||||
|
||||
|
||||
/* Attributes that help with automation */
|
||||
|
@ -230,7 +231,6 @@ mixin template IDispatchImpl() {
|
|||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
}
|
||||
pragma(lib, "oleaut32");
|
||||
|
||||
mixin template ComObjectImpl() {
|
||||
protected:
|
||||
|
|
163
jni.d
163
jni.d
|
@ -122,30 +122,34 @@ module arsd.jni;
|
|||
|
||||
// FIXME: in general i didn't handle overloads at all
|
||||
|
||||
// see: https://developer.android.com/training/articles/perf-jni.html
|
||||
|
||||
// FIXME: do these work on Windows?
|
||||
// FIXME: put this in a mixin instead of assuming it is needed/wanted?
|
||||
pragma(crt_constructor)
|
||||
extern(C)
|
||||
void initializeDRuntime() {
|
||||
import core.runtime;
|
||||
//import core.stdc.stdio; printf("here\n");
|
||||
Runtime.initialize();
|
||||
}
|
||||
|
||||
pragma(crt_destructor)
|
||||
extern(C)
|
||||
void uninitializeDRuntime() {
|
||||
import core.runtime;
|
||||
//import core.stdc.stdio; printf("gone\n");
|
||||
Runtime.terminate();
|
||||
}
|
||||
// FIXME: what about the parent class of the java object? Best we can probably do is an interface but perhaps it could be auto-generated by the JavaClass magic. It could take the list and just copy the @Import items.
|
||||
|
||||
/+
|
||||
lol if i wanted to try defining a new class in D, i'd prolly have to ctfe generate bytecode trampoline
|
||||
to make a Java method that forwards to the native call. the actual method names would then need a magical
|
||||
prefix or something to avoid namespace conflicts between the Java and the D.
|
||||
I don't think I'll actually do it. But I legit think that is possible.
|
||||
|
||||
Perhaps could be like final class AllNew : JavaClass("package", AllNew, true) {
|
||||
@Virtual void foo() {} // defines it here, but Java can override
|
||||
@Override void bar() {} // overrides existing thing with new impl
|
||||
}
|
||||
and then @Import and @Export continues to work the same way.
|
||||
+/
|
||||
|
||||
// speaking of hacking bytecode we could prolly read signatures out of a .class file too.
|
||||
|
||||
// see: https://developer.android.com/training/articles/perf-jni.html
|
||||
|
||||
// I doubt I can do anything with Java generics through this except doing it as an object array but maybe a FIXME?
|
||||
|
||||
//pragma(crt_constructor) // fyi
|
||||
//pragma(crt_destructor)
|
||||
|
||||
// FIXME: put this in a mixin instead of assuming it is needed/wanted?
|
||||
|
||||
extern(C)
|
||||
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
// can also return JNI_ERR
|
||||
/+
|
||||
|
||||
JNIEnv* env;
|
||||
|
@ -166,14 +170,32 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
|||
if (rc != JNI_OK) return rc;
|
||||
|
||||
+/
|
||||
try {
|
||||
import core.runtime;
|
||||
// note this is OK if it is already initialized
|
||||
// since it refcounts
|
||||
Runtime.initialize();
|
||||
} catch(Throwable t) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
activeJvm = vm;
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
extern(C)
|
||||
void JNI_OnUnload(JavaVM* vm, void* reserved) {
|
||||
// FIXME: the cached _jmethodIDs need to all be cleared out too
|
||||
activeJvm = null;
|
||||
import core.runtime;
|
||||
try {
|
||||
// note the refcount is upped in JNI_OnLoad
|
||||
Runtime.terminate();
|
||||
} catch(Throwable t) {
|
||||
import core.stdc.stdlib;
|
||||
abort();
|
||||
}
|
||||
}
|
||||
+/
|
||||
|
||||
__gshared JavaVM* activeJvm;
|
||||
|
||||
// need this for Import functions
|
||||
JNIEnv* activeEnv;
|
||||
|
@ -191,7 +213,43 @@ struct ActivateJniEnv {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME make a start JVM function and figure out threads...
|
||||
// FIXME figure out threads...
|
||||
|
||||
/++
|
||||
Creates a JVM for use when `main` is in D. Keep the returned
|
||||
struct around until you are done with it.
|
||||
|
||||
If `main` is in Java, this is not necessary and should not be
|
||||
used.
|
||||
|
||||
If you use this, you will need to link in a jni shared lib.
|
||||
+/
|
||||
auto createJvm()() {
|
||||
struct JVM {
|
||||
ActivateJniEnv e;
|
||||
JavaVM* pvm;
|
||||
|
||||
@disable this(this);
|
||||
|
||||
~this() {
|
||||
if(pvm)
|
||||
(*pvm).DestroyJavaVM(pvm);
|
||||
activeJvm = null;
|
||||
}
|
||||
}
|
||||
|
||||
JavaVM* pvm;
|
||||
JNIEnv* env;
|
||||
auto res = JNI_CreateJavaVM(&pvm, cast(void**) &env, null);
|
||||
if(res != JNI_OK)
|
||||
throw new Exception("create jvm failed"); // FIXME: throw res);
|
||||
|
||||
activeJvm = pvm;
|
||||
|
||||
return JVM(ActivateJniEnv(env), pvm);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void exceptionCheck(JNIEnv* env) {
|
||||
|
@ -590,9 +648,12 @@ private struct JavaParamsToD(Spec...) {
|
|||
(*env).ReleaseStringChars(env, jarg, ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
// FIXME other types of arrays
|
||||
//else static if(is(T : IJavaObject)) return data.getJavaHandle(); // create the D object, hook in the handle, do some kind of type check from the Java class name.
|
||||
} else static if(is(T : IJavaObject)) {
|
||||
auto dobj = new T();
|
||||
dobj.internalJavaHandle_ = jarg;
|
||||
arg = dobj;
|
||||
}
|
||||
else static assert(0, "Unimplemented/unsupported type " ~ T.stringof);
|
||||
|
||||
}
|
||||
|
@ -628,15 +689,20 @@ private mixin template JavaExportImpl(T, alias method) {
|
|||
// set it up in the thread for future calls
|
||||
ActivateJniEnv thing = ActivateJniEnv(env);
|
||||
|
||||
// FIXME: pull the same D object again if possible... though idk
|
||||
ubyte[__traits(classInstanceSize, T)] byteBuffer;
|
||||
byteBuffer[] = (cast(const(ubyte)[]) typeid(T).initializer())[];
|
||||
static if(__traits(isStaticFunction, method)) {
|
||||
alias dobj = T;
|
||||
jclass jc = obj;
|
||||
} else {
|
||||
// FIXME: pull the same D object again if possible... though idk
|
||||
ubyte[__traits(classInstanceSize, T)] byteBuffer;
|
||||
byteBuffer[] = (cast(const(ubyte)[]) typeid(T).initializer())[];
|
||||
|
||||
// I specifically do NOT call the constructor here, since those may forward to Java and make things ugly!
|
||||
// The init value is cool as-is.
|
||||
// I specifically do NOT call the constructor here, since those may forward to Java and make things ugly!
|
||||
// The init value is cool as-is.
|
||||
|
||||
auto dobj = cast(T) byteBuffer.ptr;
|
||||
dobj.internalJavaHandle_ = obj;
|
||||
auto dobj = cast(T) byteBuffer.ptr;
|
||||
dobj.internalJavaHandle_ = obj;
|
||||
}
|
||||
|
||||
// getMember(identifer) is weird but i want to get the method on this
|
||||
// particular instance and it feels less hacky than doing the delegate
|
||||
|
@ -686,14 +752,29 @@ class JavaClass(string javaPackage, CRTP) : IJavaObject {
|
|||
enum Import; /// UDA to indicate you are importing the method from Java. Do NOT put a body on these methods.
|
||||
enum Export; /// UDA to indicate you are exporting the method to Java. Put a D implementation body on these.
|
||||
|
||||
static foreach(memberName; __traits(derivedMembers, CRTP))
|
||||
static foreach(attr; __traits(getAttributes, __traits(getMember, CRTP, memberName))) {
|
||||
static if(is(attr == Import))
|
||||
mixin JavaImportImpl!(CRTP, __traits(getMember, CRTP, memberName));
|
||||
else static if(is(attr == Export))
|
||||
mixin JavaExportImpl!(CRTP, __traits(getMember, CRTP, memberName));
|
||||
/+
|
||||
/++
|
||||
D constructors on Java objects don't work right, so this is disabled to ensure
|
||||
you don't try it. However note that you can `@Import` constructors from Java and
|
||||
create objects in D that way.
|
||||
+/
|
||||
@disable this(){}
|
||||
+/
|
||||
|
||||
static foreach(memberName; __traits(derivedMembers, CRTP)) {
|
||||
// validations
|
||||
static if(is(typeof(__traits(getMember, CRTP, memberName).offsetof)))
|
||||
static assert(0, "Data members in D on Java classes are not reliable because they cannot be consistently associated back to their corresponding Java classes through JNI without major runtime expense.");
|
||||
else static if(memberName == "__ctor")
|
||||
static assert("JavaClasses can only be constructed by Java. Try making a constructor in Java, then make an @Import this(args); here.");
|
||||
|
||||
// implementations
|
||||
static foreach(attr; __traits(getAttributes, __traits(getMember, CRTP, memberName))) {
|
||||
static if(is(attr == Import))
|
||||
mixin JavaImportImpl!(CRTP, __traits(getMember, CRTP, memberName));
|
||||
else static if(is(attr == Export))
|
||||
mixin JavaExportImpl!(CRTP, __traits(getMember, CRTP, memberName));
|
||||
}
|
||||
}
|
||||
|
||||
protected jobject internalJavaHandle_;
|
||||
|
@ -781,6 +862,8 @@ enum JNI_VERSION_1_1 = 0x00010001;
|
|||
enum JNI_VERSION_1_2 = 0x00010002;
|
||||
enum JNI_VERSION_1_4 = 0x00010004;
|
||||
enum JNI_VERSION_1_6 = 0x00010006;
|
||||
enum JNI_VERSION_1_8 = 0x00010008;
|
||||
|
||||
enum JNI_OK = 0;
|
||||
enum JNI_ERR = -1;
|
||||
enum JNI_EDETACHED = -2;
|
||||
|
@ -1075,6 +1158,10 @@ struct JavaVMInitArgs
|
|||
jboolean ignoreUnrecognized;
|
||||
}
|
||||
|
||||
jint JNI_GetDefaultJavaVMInitArgs(void *args);
|
||||
jint JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args);
|
||||
jint JNI_GetCreatedJavaVMs(JavaVM **, jsize, jsize *);
|
||||
|
||||
struct _jfieldID;
|
||||
struct _jmethodID;
|
||||
|
||||
|
|
|
@ -904,6 +904,11 @@ version(WEBVIEW_MSHTML) {
|
|||
};
|
||||
+/
|
||||
} else version(WEBVIEW_EDGE) {
|
||||
|
||||
// NOTE: this will prolly only work on Win 10 and maybe win 8.
|
||||
// but def not older ones. Will have to version it or dynamically
|
||||
// load. Should prolly make it opt-in to the old style, default to new w. multi-threading
|
||||
|
||||
/+
|
||||
#include <objbase.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
|
|
Loading…
Reference in New Issue