Delphi使用可变参数列表调用JNI方法 [英] Delphi call JNI methods with variable argument list

查看:255
本文介绍了Delphi使用可变参数列表调用JNI方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Using Embarcadero's Jni api unit, how does one supply variable argument lists to the JNI methods that require it? For example, the CallStaticObjectMethodV() method of the JNINativeInterface (listing 1) has a last parameter of type va_list, which is supposed to encapsulate a variable list of arguments. In C++ code (listing 2) which calls this method, the method signature is marked as varargs, which is surprising because there is no varargs decoration in Delphi's AndroidApi.Jni unit.

您应该如何构造Args参数以在Delphi中实现相同的目的?我的尝试,如清单3所示,不起作用。 >

How are you supposed to construct the Args parameter to achieve the same thing in Delphi? My attempt, shown in listing 3 does not work.

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库中提取的。

Listing 2: An example of how it is called from C++

Listing 2 was extracted from the Saxon/C library.

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



Listing 3: My attempt at translating listing 2 into Delphi

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。他们没有工作。 (访问冲突)。

What also hasn't worked

I have also tried redeclaring the method type to be decorated with varargs, and implementing the varargs passing with assember, using the method outlined in these solutions. They did not work. (Access violation).

  • How can a function with 'varargs' retrieve the contents of the stack?
  • Delphi "array of const" to "varargs"

目标平台是Win32。我为Windows复制了AndroidApi.jni.pas( WinApi.jni.pas )。我只是更改了stdcall的cdecl装饰。 stdcall是正确的,我可以使用该单元来启动JavaVM并执行其他JNI任务。 Embaracedero不会将CallStaticObjectMethodV()标记为varargs,但这也许是一个错误吗?

The target platform is Win32. I made a copy of AndroidApi.jni.pas for windows (WinApi.jni.pas). I just changed the cdecl decorations for stdcall. stdcall is correct, and I can use the unit to start the JavaVM and do other JNI stuff. Embaracedero does not mark the CallStaticObjectMethodV() as varargs, but maybe this is an error?

感谢,我制定了一个可行的解决方案...

Thanks to Jonathan Revusky's JNI Wrapper, I worked out a working solution ...

有效的代码是..

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;


推荐答案

va_list 需要指向一个内存块,该内存块与如果您调用可变参数函数将被压入堆栈的内存匹配。

The va_list needs to point to a block of memory that matches what would be pushed onto the stack if you had instead called a variadic function.

va_start 只是产生栈上可变参数被压入的位置的地址。

The usual implementation of va_start simply yields the address of the location on the stack where the variadic arguments were pushed.

#define va_start(ap, parmN) ((void)((ap) = (va_list)((char _FAR *)(&parmN)+__size(parmN)))) 

所以您尝试制作一个包含参数的数组,并将其用作您的 va_list 应该起作用。也许您太仓促地放弃了?也许代替:

So your attempt to make an array containing the arguments, and use that as your va_list ought to work. Perhaps you've given up on it too hastily? Perhaps instead of:

Move( Str1, Data[0], Sz);
Move( Str1, Data[Sz], Sz);

您的意思是

Move( Str1, Data[0], Sz);
Move( Str2, Data[Sz], Sz);

尽管我个人选择的是 JNIString 而不是字节数组。

Although personally I'd opt for a array of JNIString rather than a byte array.

因此,也许您创建 va_list 的方法很好,但是失败是由其他地方的错误引起的。

So perhaps your approach to create the va_list is fine, but the failure is caused by an error elsewhere.

这篇关于Delphi使用可变参数列表调用JNI方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆