首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Delphi调用带有变量参数列表的JNI方法

Delphi调用带有变量参数列表的JNI方法
EN

Stack Overflow用户
提问于 2015-10-09 04:51:23
回答 1查看 874关注 0票数 2

使用Embarcadero的Jni api单元,如何向需要它的JNI方法提供变量参数列表?例如,CallStaticObjectMethodV()方法的JNINativeInterface (清单1)有一个类型为va_list的最后一个参数,它应该封装一个变量列表的参数。在调用此方法的C++代码(清单2)中,方法签名被标记为varargs,这是令人惊讶的,因为Delphi的AndroidApi.Jni单元中没有varargs装饰。

如何在Delphi中构造Args参数以实现相同的功能?我的尝试(如清单3所示)不起作用。

清单1:从单元Androidapi.Jni中提取,稍微适应于Windows (更改后的cdecl用于stdcall)

代码语言:javascript
复制
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库提取的。

代码语言:javascript
复制
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翻译成Delphi的尝试

代码语言:javascript
复制
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。我复制了一份AndroidApi.jni.pas for windows (WinApi.jni.pas)。我刚给stdcall换了装饰。stdcall是正确的,我可以使用该单元启动JavaVM并执行其他JNI操作。Embaracedero没有将CallStaticObjectMethodV()标记为varargs,但这可能是一个错误?

更新:最终解决方案

多亏了Jonathan Revusky的JNI包装器,我想出了一个解决方案.

有效的代码是..。

代码语言:javascript
复制
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;
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-10-09 06:37:32

va_list需要指向一个内存块,如果您已经调用了一个变量函数,那么这个内存块将被推到堆栈上。

va_start的通常实现只是产生堆栈上的位置的地址,其中的变量参数是被推送的。

代码语言:javascript
复制
#define va_start(ap, parmN) ((void)((ap) = (va_list)((char _FAR *)(&parmN)+__size(parmN)))) 

因此,您试图创建一个包含参数的数组,并使用它,因为您的va_list应该工作。也许你太仓促放弃了?也许不是:

代码语言:javascript
复制
Move( Str1, Data[0], Sz);
Move( Str1, Data[Sz], Sz);

你是说

代码语言:javascript
复制
Move( Str1, Data[0], Sz);
Move( Str2, Data[Sz], Sz);

尽管就我个人而言,我会选择一个JNIString数组,而不是一个字节数组。

因此,您创建va_list的方法也许不错,但失败是由其他地方的错误造成的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33030132

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档