Delphi вызывает методы JNI с переменным списком аргументов
Используя модуль Jni api Embarcadero, как можно предоставить списки переменных-переменных для методов JNI, которые в этом нуждаются? Например, метод CallStaticObjectMethodV () объекта JNINativeInterface (листинг 1) имеет последний параметр типа va_list, который должен инкапсулировать переменный список аргументов. В коде C ++ (листинг 2), который вызывает этот метод, сигнатура метода помечается как varargs, что удивительно, поскольку в модуле Delphi AndroidApi.Jni отсутствует декорация varargs.
Как вы должны построить параметр Args для достижения того же самого в Delphi? Моя попытка, показанная в листинге 3, не работает.
Листинг 1: Извлечение из модуля Androidapi.Jni, слегка адаптированное для платформы Windows (изменено cdecl для stdcall)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;
Листинг 2: Пример того, как он вызывается из C ++Листинг 2 был извлечен из библиотеки Saxon / C.
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;
}
Листинг 3: Моя попытка перевести листинг 2 в Delphivar
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);
Что также не сработалоЯ также попытался переопределить тип метода, который должен быть декорирован с помощью varargs, и реализовать varargs, передаваемые с помощью ассемблера, используя метод, описанный в этих решениях. Они не работали. (Нарушение доступа).
Как функция с 'varargs' может извлечь содержимое стека?Delphi "массив const" для "varargs"Немного больше информацииЦелевая платформа - Win32. Я сделал копию AndroidApi.jni.pas для Windows (WinApi.jni.pas
). Я только что изменил украшения cdecl для stdcall. stdcall верен, и я могу использовать модуль, чтобы запустить JavaVM и делать другие вещи JNI. Embaracedero не помечает CallStaticObjectMethodV () как переменную, но, возможно, это ошибка?
БлагодаряДжонатан Ревуски JNI WrapperЯ разработал рабочее решение ...
Код, который работает, это ..
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;