JNI and GetFieldID

B

Borneq

I have class:
package net.sf.junace;
public class ACEList {
ACEFiles files; // specifies files to be listed;
byte[] reserved; // 64 bytes has to be filled with zeroes
}
I call native :
ACEList aaa = new ACEList();
unACE.nativeACEList("abc", aaa);

in c++ is:
JNIEXPORT void JNICALL Java_net_sf_junace_UnACE_nativeACEList
(JNIEnv *env, jobject jObj1, jstring archiveName, jobject jObj2)
which field I must read?
jclass cls1 = env->GetObjectClass(jObj1);
or
jclass cls2 = env->GetObjectClass(jObj2);
?
jfieldID fid = env->GetFieldID(cls1 or cls2, "something",
"Lnet/sf/junace/ACEList;");
what I must choose cls1 or cls2
what I must pass as second argument as "something"?
 
M

Mark

I have class:
package net.sf.junace;
public class ACEList {
ACEFiles files; // specifies files to be listed;
byte[] reserved; // 64 bytes has to be filled with zeroes
}
I call native :
ACEList aaa = new ACEList();
unACE.nativeACEList("abc", aaa);

in c++ is:
JNIEXPORT void JNICALL Java_net_sf_junace_UnACE_nativeACEList
(JNIEnv *env, jobject jObj1, jstring archiveName, jobject jObj2)
which field I must read?
jclass cls1 = env->GetObjectClass(jObj1);
or
jclass cls2 = env->GetObjectClass(jObj2);
?
jfieldID fid = env->GetFieldID(cls1 or cls2, "something",
"Lnet/sf/junace/ACEList;");
what I must choose cls1 or cls2
what I must pass as second argument as "something"?

It depends on what you are trying to do. Can you post a complete
(small) example?
 
S

Steven Simpson

I have class:

[Some spacing added.]

package net.sf.junace;

public class ACEList {
ACEFiles files; // specifies files to be listed;

byte[] reserved; // 64 bytes has to be filled with zeroes
}

I call native :
ACEList aaa = new ACEList();
unACE.nativeACEList("abc", aaa);
in c++ is:
JNIEXPORT void JNICALL Java_net_sf_junace_UnACE_nativeACEList
(JNIEnv *env, jobject jObj1, jstring archiveName, jobject jObj2)

'jObj1' corresponds to 'this', i.e. 'unACE'. 'archiveName' will be
"abc". 'jObj2' corresponds to 'aaa'.

which field I must read?
jclass cls1 = env->GetObjectClass(jObj1);
or
jclass cls2 = env->GetObjectClass(jObj2);
?

jfieldID fid = env->GetFieldID(cls1 or cls2, "something",
"Lnet/sf/junace/ACEList;");
what I must choose cls1 or cls2

Since you don't say much about what type 'unACE' is, I assume you want
to access a field of 'aaa', whose type is ACEList. You could probably
get it from cls2, but that is the class of the object, which could be
ACEList or a subtype. I think you want to get the jclass for ACEList
directly, so perhaps:

jclass cls = env->FindClass("net/sf/junace/ACEList");



what I must pass as second argument as "something"?

<http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#wp16536>

It says that the string is the name of the field, so either "files" or
"reserved".

But I think your last argument is wrong. It should be the type
signature of the field. If you want the field 'files', and assuming
that ACEFiles is in the same package as ACEList, you want
"Lnet/sf/junace/ACEFiles;". If you want the field 'reserved', the type
signature is "[B".
 
B

Borneq

User "Steven Simpson" <[email protected]>> jclass cls =
env->FindClass("net/sf/junace/ACEList");

Thanks,

User "Mark said:
(small) example?

Expecially I want work with callbacks. I have written simple working demo:
=======> https://github.com/borneq/JNIdemo
for example here is:
jclass cls = env->GetObjectClass(param1);
jmethodID mid = env->GetMethodID(cls, "OnPercent", "(I)V");

My little puropose: expanding this example to callbacks with params, where
params can be class, for example:
=======> https://gist.github.com/borneq/6462783
void OnPercentEx(CmplxStruct cs);
 
S

Steven Simpson

public interface ICallback {
void OnPercent(int percent);
void OnPercentEx(CmplxStruct cs);
}

While in Java, you should use Java conventions, e.g. onPercent for a
method name. Can't say I'm a fan of prefixing "Callback" with "I" to
show it's an interface either.
public class CmplxStruct {
int fieldI;
String str;
}

CmplxStruct? Ky, 'll tk tht s jst n ex.
How place number and string?
jmethodID mid;
mid = env->GetMethodID(cls, "OnPercentEx", "(LCmplxStruct;)V");
env->CallVoidMethod(param1, mid, SOMETHING);
how fill SOMETHING?

Never learned to do that - looks too error-prone. Instead of mucking
around in JNI, creating objects, accessing fields, etc, I prefer to do
as much as I can in Java, then declare the native methods as taking the
already dismantled fields as separate arguments.

You could do similar for a callback. Write a private static method to
do the fiddly stuff:

private static void callBack(ICallback dest, int i, String s) {
CmplxStruct obj = new CmplxStruct();
obj.fieldI = i;
obj.str = s;
dest.OnPercentEx(obj);
}

Now, in JNI, you use something like:

jobject dest = ...;
jint i = ...;
jstring s = ...;

mid = env->GetStaticMethodID(cls, "callBack", "(LICallback;ILjava/lang/String;)V");
env->CallStaticVoidMethod(dest, i, s);
 
B

Borneq

Użytkownik "Steven Simpson said:
Never learned to do that - looks too error-prone. Instead of mucking
around in JNI, creating objects, accessing fields, etc, I prefer to do as
much as I can in Java, then declare the native methods as taking the
already dismantled fields as separate arguments.

But this is difficult, because I want to write JNI wrapper to UnACE -
library for expanding .ace archives.
There are callbacks like
INT (__stdcall *StateCallbackProc)
(pACEStateCallbackProcStruc State);
where
typedef union sACEStateCallbackProcStruc
*pACEStateCallbackProcStruc;
typedef union sACEStateCallbackProcStruc
{
ULONG StructureType; // indicates which of the
fol-
// lowing structures is used
tACECallbackArchiveStruc Archive;
tACECallbackArchivedFileStruc ArchivedFile;
tACECallbackRealFileStruc RealFile;
tACECallbackProgressStruc Progress;
tACECallbackCRCCheckStruc CRCCheck;
} tACEStateCallbackProcStruc;
where for example:
typedef struct sACECallbackArchiveStruc
{
ULONG StructureType; // is ACE_CALLBACK_TYPE_ARCHIVE
ULONG Code; // see definition of
// ACE_CALLBACK_TYPE_ARCHIVE
ULONG Operation; // ACE_CALLBACK_OPERATION constant

pACEGlobalDataStruc GlobalData; // see tACEGlobalDataStruc
pACEArchiveDataStruc ArchiveData; // see tACEArchiveDataStruc
} tACECallbackArchiveStruc,
*pACECallbackArchiveStruc;

There are structures reference inside other structures
 
S

Steven Simpson

Main problem: in this demo callback is not called by pointer to
function but only CallVoidMethod. But my library must be above other
library which uses callback by pointer to function. How do it?

If the callbacks are C, they will usually have a (void *) parameter to
pass context. (If they don't, I'd say they're shoite, or they're not
what one supposes they're for.) The context will have to include the
JNIEnv pointer at least, and the details of the Java callback.

Suppose that the library you're wrapping defines a callback:

typedef void foo_callback1(void *, int, const char *);
void foo_do_something(foo_obj *, foo_callback1 *cb, void *ctxt);

In Java, you define a corresponding callback interface:

package foo;

interface Callback1 {
void apply(int x, String s);
}

class Foo {
native void doSomething(Callback1 cb);
}

Back in C, you write a C callback which invokes a Java callback:

struct this_op_context {
JNIEnv *env;
jobject user;
};

static void my_callback(void *vctxt, int x, const char *s)
{
struct this_op_context *ctxt = vctxt;

jstring str = ctxt->env->NewStringUTF(s);
jclass cls = ctxt->env->FindClass("foo/Callback1");
jmethodID mid = ctxt->env->GetMethodID(cls, "apply", "(ILjava/lang/String;)V");
ctxt->env->CallVoidMethod(env->user, (jint) x, str);

// Clean up?
...
}

....and set it up to be invoked:

JNIEXPORT void JNICALL Java_foo_Foo_doSomething
(JNIEnv *env, jobject jObj1, jobject cb)
{
struct this_op_context ctxt = {
.env = env,
.user = cb;
};

// Extract/create foo structures from data in jObj1.
foo_obj *foo = ...;

foo_do_something(foo, &my_callback, &ctxt);

// Clean up?
...
}

That's assuming you don't need any C foo structures to persist beyond
this call, and no callback will occur after foo_do_something has
returned. Otherwise, you have to start thinking about memory management
of the foo structures and the callback contexts, and whether you want
them to map to Java objects, and how to do that mapping, etc.

I can think of straight-forward ways to map (say) a foo.Foo to a
foo_obj, but I'm not so sure about how you'd manage a struct
this_op_context. I'd also be concerned about whether the JNIEnv pointer
stored in the struct was even valid after returning from the native call.
 
B

Borneq

Użytkownik "Steven Simpson said:
If the callbacks are C, they will usually have a (void *) parameter to
pass context. (If they don't, I'd say they're shoite, or they're not what
one supposes they're for.) The context will have to include the JNIEnv
pointer at least, and the details of the Java callback.

Suppose that the library you're wrapping defines a callback:

typedef void foo_callback1(void *, int, const char *);
void foo_do_something(foo_obj *, foo_callback1 *cb, void *ctxt);

Thanks for answer and examples ;-)
I want wrap library UnAceV2.dll which is provided without sources.
(http://www.winace.com/) I can't change foo_callback and foo_do_something
parameters.
The callback function is
INT __stdcall StateProc(pACEStateCallbackProcStruc State)
the do_something function is
INT __stdcall ACEListProc(LPSTR ArchiveName, pACEListStruc List);

Inside StateProc I can call my_callback function, and ACEListProc will be
called inside native function. Native function can store env and others
parameters. But how within StateProc refer to this env and other parameters?
This parameters must be stored globally in data segment?
 
B

Borneq

Użytkownik "Borneq said:
Inside StateProc I can call my_callback function, and ACEListProc will be
called inside native function. Native function can store env and others
parameters. But how within StateProc refer to this env and other
parameters? This parameters must be stored globally in data segment?

My last demo: https://github.com/borneq/JNIdemo
 
S

Steven Simpson

Inside StateProc I can call my_callback function, and ACEListProc will
be called inside native function. Native function can store env and
others parameters. But how within StateProc refer to this env and
other parameters?

It's a bugger, isn't it?!
This parameters must be stored globally in data segment?

Perhaps. This option would need some synchronization on the Java side
to protect it, but I'm not sure that would suffice in some cases (e.g.,
when the class you lock on is loaded multiple times).

A thread-local in C? Find out what the JVM uses for threads, and use
its thread-local feature.

Perhaps you can use the C callback just to build up a structure
locally. When control returns from the library back to your JNI
function, you iterate over the structure to invoke Java callbacks.

I'm out of decent ideas.
 
B

Borneq

Użytkownik "Steven Simpson said:
A thread-local in C? Find out what the JVM uses for threads, and use its
thread-local feature.

__declspec(thread) struct sJniHandle jniHandle;
in Visual Studio 2010?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,071
Latest member
MetabolicSolutionsKeto

Latest Threads

Top