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 übersetzen
var
  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 funktioniert

Ich 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?

Update: Die endgültige Lösung

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;

Antworten auf die Frage(2)

Ihre Antwort auf die Frage