使用Embarcadero的Jni api单元,如何为需要它的JNI方法提供变量参数列表?例如,JNINativeInterface(清单1)的CallStaticObjectMethodV()方法具有类型为va_list的最后一个参数,该参数应该封装变量参数列表。在调用此方法的C ++代码(清单2)中,方法签名被标记为varargs,这是令人惊讶的,因为Delphi的AndroidApi.Jni单元中没有varargs装饰。
如何在Delphi中构建Args参数以实现相同的功能?我在列表3中显示的尝试不起作用。
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是从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;
}
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);
我还尝试重新声明要用varargs修饰的方法类型,并使用这些解决方案中概述的方法实现使用assember传递的varargs。他们没有工作。 (访问违规)。
目标平台是Win32。我为Windows(WinApi.jni.pas
)制作了AndroidApi.jni.pas的副本。我刚刚更改了stdcall的cdecl装饰。 stdcall是正确的,我可以使用该单元启动JavaVM并执行其他JNI操作。 Embaracedero没有将CallStaticObjectMethodV()标记为varargs,但可能这是一个错误?
感谢Jonathan Revusky's 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;
答案 0 :(得分:0)
x = {}; x.cyclic = x;
需要指向一个内存块,如果您调用了一个可变参数函数,它将与推入堆栈的内存相匹配。
va_list
的通常实现只会产生堆栈上推送可变参数的位置的地址。
va_start
因此,您尝试创建一个包含参数的数组,并将其用作#define va_start(ap, parmN) ((void)((ap) = (va_list)((char _FAR *)(&parmN)+__size(parmN))))
应该有效。也许你已经匆匆忙忙放弃了?也许代替:
va_list
你的意思
Move( Str1, Data[0], Sz);
Move( Str1, Data[Sz], Sz);
虽然我个人选择Move( Str1, Data[0], Sz);
Move( Str2, Data[Sz], Sz);
数组而不是字节数组。
所以也许你创建JNIString
的方法很好,但失败是由其他地方的错误引起的。