Reputation: 405
Hello I've created an Android class using C that does some operations. Among these procedures I want to use this one : ( just for test with Delphi )
JNIEXPORT void Java_Test_Project_Decode(JNIEnv* env, jclass clazz,jbyteArray dataIn, jbyteArray dataOut)
{
jsize len = (*env)->GetArrayLength(env, dataIn);
LOGV("JNI call Decode test dataIn Size = %d",len);
jbyte *pByteIn = (*env)->GetByteArrayElements(env, dataIn, 0);
jbyte *pByteOut = (*env)->GetByteArrayElements(env, dataOut, 0);
*pDataOut = *pDataIn; pDataIn++; pDataOut++;
*pDataOut = *pDataIn; pDataIn++; pDataOut++;
*pDataOut = *pDataIn; pDataIn++; pDataOut++;
// some routines
(*env)->ReleaseByteArrayElements(env, dataOut, pByteOut, 0);
(*env)->ReleaseByteArrayElements(env, dataIn, pByteIn, 0);
}
of course my testlib.so is built and compiled ( NDK-build using cygwin ) and deployed with my Delphi project .
And in my Delphi Firemonkey client I use this procedure in this way :
Java_Test_Project_Decode:procedure(PEnv: PJNIEnv; Obj:JObject;dataIn:Pointer;DataOut:Pointer); cdecl;
of course after I load my library :
Procedure LoadMyLib();
begin
FMyLib := LoadLibrary(PChar(LibFolder + LibTest));
if FMyLib = 0 then
begin
Exit;
end
else
begin
Java_Test_Project_Decode:=GetProcAddress(FMyLib,'Java_Test_Project_Decode');
if not assigned (Java_Test_Project_Decode) then
begin
Exit; // Java_Test_Project_Decode procedure not loaded
end else
begin
// OK Java_Test_Project_Decode procedure loaded
end;
end;
end;
Then I use the procedure :
Procedure TestMyProcedure (ADataIn: pointer; ASize: integer);
var
ADataOut:Pointer;
begin
// ADataIn pointer is not empty
Java_Test_Project_Decode(PEnv,Obj,ADataIn,ADataOut);
end;
But here I get an exception and the app crashes.
Please can anyone help me fixing this ?
So thanks.
Update :
I can eliminate the ADataOut
as follows :
JNIEXPORT void Java_Test_Project_Decode(JNIEnv* env, jclass clazz,jbyteArray dataIn)
{
jsize len = (*env)->GetArrayLength(env, dataIn);
LOGV("JNI call Decode test dataIn Size = %d",len);
jbyte *pByteIn = (*env)->GetByteArrayElements(env, dataIn, 0);
// some routines
(*env)->ReleaseByteArrayElements(env, dataIn, pByteIn, 0);
}
and my Delphi declaration :
Java_Test_Project_Decode:procedure(PEnv: PJNIEnv; Obj:JObject;dataIn:Pointer); cdecl;
Procedure TestMyProcedure (ADataIn: pointer; ASize: integer);
begin
// ADataIn pointer is not empty
Java_Test_Project_Decode(PEnv,Obj,ADataIn);
end;
But always with the same exception and error, I even tried to just get the
jsize len = (*env)->GetArrayLength(env, dataIn);
LOGV("JNI call Decode test dataIn Size = %d",len);
same error .
Upvotes: 1
Views: 590
Reputation: 2175
Your Delphi declaration needs to match the underlying C declaration, which it current does not on three counts:
JObject
JNI Bridge interface type (from the RTL unit Androidapi.JNI.JavaTypes.pas) that wraps up the Java class java.lang.jobject
, instead of the type JNIObject
(from the RTL unit Androidapi.Jni.pas), which is the equivalent of the JNI type jobject
. However this is mostly irrelevant as...jclass
parameter to imply it is a static/class method, but your Delphi import declaration is attempting to use the jobject
equivalent, giving a mismatch. It should declare a parameter of type JNIClass
instead.jbytearray
JNI parameter type but your Delphi declaration is made using type Pointer
. Instead you should use the Delphi equivalent to jbytearray
, which is JNIByteArray
.Only when all the arguments and calling conventions on both sides match directly will the call succeed.
On an slightly related note it may have been of benefit to inform readers as to how the .so library was deployed within the Delphi project and what path expression you used to gain access to it at runtime, as this can be far from clear.
In order to perform a similar experiment I had a .so file that I set up the Deployment Manager to deploy to the assets\internal\ deployment folder. This then meant I could use TPath.Combine(TPath.GetDocumentsPath, LibName)
to reference the library file from the Android app code.
Upvotes: 0