Delphi ruft JNI-Methoden mit variabler Argumentliste auf
Wie liefert man mithilfe der Jni-API-Einheit von Embarcadero Listen mit variablen Argumenten an die JNI-Methoden, die diese benötigen? Beispielsweise hat die CallStaticObjectMethodV () -Methode des JNINativeInterface (Listing 1) einen letzten Parameter vom Typ va_list, der eine variable Liste von Argumenten einschließen soll. In C ++ - Code (Listing 2), der diese Methode aufruft, wird die Methodensignatur als varargs markiert. Dies ist überraschend, da in Delphis AndroidApi.Jni-Unit keine varargs-Dekoration vorhanden ist.
Wie soll der Parameter Args erstellt werden, um dasselbe in Delphi zu erreichen? Mein in Listing 3 dargestellter Versuch funktioniert nicht.
Listing 1: Auszug aus Androidapi.Jni, leicht angepasst für Windows-Plattform (cdecl für stdcall geändert)JNINativeInterface = packed record
...
CallStaticObjectMethod : function(Env: PJNIEnv; AClass: JNIClass; MethodID: JNIMethodID): JNIObject; stdcall;
CallStaticObjectMethodV: function(Env: PJNIEnv; AClass: JNIClass; MethodID: JNIMethodID; Args: va_list ): JNIObject; stdcall;
CallStaticObjectMethodA: function(Env: PJNIEnv; AClass: JNIClass; MethodID: JNIMethodID; Args: PJNIValue): JNIObject; stdcall;
Listing 2: Ein Beispiel für den Aufruf von C ++Listing 2 wurde aus der Saxon / C-Bibliothek extrahiert.
XdmValue * SaxonProcessor::parseFile(const char* source){
jmethodID mID = (jmethodID)env->GetStaticMethodID(saxonCAPIClass, "xmlParseFile", "(Lnet/sf/saxon/s9api/Processor;Ljava/lang/String;Ljava/lang/String;)Lnet/sf/saxon/s9api/XdmNode;");
if (!mID) {
cerr<<"\nError: MyClassInDll "<<"xmlParseFile()"<<" not found"<<endl;
return NULL;
}
jobject xdmNodei = env->CallStaticObjectMethod(saxonCAPIClass, mID, proc, env->NewStringUTF(cwd.c_str()), env->NewStringUTF(source));
if(exceptionOccurred()) {
exception= checkForException(env, saxonCAPIClass, NULL);
} else {
XdmValue * value = new XdmValue(xdmNodei);
value->setProcessor(this);
return value;
}
return NULL;
}
Listing 3: Mein Versuch, Listing 2 in Delphi zu übersetzenvar
mID: JNIMethodID;
xdmNodei: JNIObject;
Str1, Str2: JNIString;
Hold1, Hold2: TBytes;
ArgsAsList: va_list;
Data: TBytes;
Sz: integer;
begin
mID := FJNIEnv.GetStaticMethodID( Fpenv, FsaxonCAPIClass, 'xmlParseFile',
'(Lnet/sf/saxon/s9api/Processor;Ljava/lang/String;Ljava/lang/String;)Lnet/sf/saxon/s9api/XdmNode;');
Str1 := FJNIEnv.NewStringUTF( Fpenv, String_to_MarshaledAString( Fcwd , Hold1));
Str2 := FJNIEnv.NewStringUTF( Fpenv, String_to_MarshaledAString( Source, Hold2));
Sz := SizeOf( JNIString);
SetLength( Data, 3 * Sz);
FillChar( Data[0], Length( Data), 0);
Move( Str1, Data[0], Sz);
Move( Str1, Data[Sz], Sz);
ArgsAsList := va_list( @Data[0]);
xdmNodei := FJNIEnv.CallStaticObjectMethodV( Fpenv, FsaxonCAPIClass, mID, ArgsAsList);
Was hat auch nicht funktioniertIch habe auch versucht, den zu dekorierenden Methodentyp mit varargs neu zu deklarieren und die mit assember übergebenen varargs mit der in diesen Lösungen beschriebenen Methode zu implementieren. Sie haben nicht funktioniert. (Zugriffsverletzung)
Wie kann eine Funktion mit 'varargs' den Inhalt des Stapels abrufen?Delphi "Array von const" bis "varargs"Ein bisschen mehr Informationen Die Zielplattform ist Win32. Ich habe eine Kopie von AndroidApi.jni.pas für Windows erstellt WinApi.jni.pas
). Ich habe gerade die Dekore für stdcall geändert. stdcall ist korrekt, und ich kann das Gerät zum Starten der JavaVM und für andere JNI-Aufgaben verwenden. Embaracedero markiert CallStaticObjectMethodV () nicht als varargs, aber ist dies möglicherweise ein Fehler?
Dank an Jonathan Revusky JNI Wrapper, Ich habe eine funktionierende Lösung gefunden ...
Der Code, der funktioniert, ist ..
function TSaxonProcessor.parseFile( const Source: string): TXdmValue;
var
mID: JNIMethodID;
xdmNodei: JNIObject;
Str1, Str2: JNIString;
Hold1, Hold2: TBytes;
Data: TArray<JNIString>;
begin
mID := FJNIEnv.GetStaticMethodID( Fpenv, FsaxonCAPIClass, 'xmlParseFile',
'(Lnet/sf/saxon/s9api/Processor;Ljava/lang/String;Ljava/lang/String;)Lnet/sf/saxon/s9api/XdmNode;');
Str1 := FJNIEnv.NewStringUTF( Fpenv, String_to_MarshaledAString( Fcwd , Hold1));
Str2 := FJNIEnv.NewStringUTF( Fpenv, String_to_MarshaledAString( Source, Hold2));
SetLength( Data, 3);
Data[0] := FProc;
Data[1] := Str1;
Data[2] := Str2;
xdmNodei := FJNIEnv.CallStaticObjectMethodV( Fpenv, FsaxonCAPIClass, mID, @Data[0]);
end;