GVKun编程网logo

如何调用使用JNA返回字符串的Delphi函数?(jna获取返回值)

16

在这里,我们将给大家分享关于如何调用使用JNA返回字符串的Delphi函数?的知识,让您更了解jna获取返回值的本质,同时也会涉及到如何更有效地delphi–encoding.getstring不返回

在这里,我们将给大家分享关于如何调用使用JNA返回字符串的Delphi函数?的知识,让您更了解jna获取返回值的本质,同时也会涉及到如何更有效地delphi – encoding.getstring不返回字符串、delphi – 使用带有字符串的Case语句、delphi – 如何从父类调用子类构造函数?、delphi – 如何计算字符串中某个字符的出现次数?的内容。

本文目录一览:

如何调用使用JNA返回字符串的Delphi函数?(jna获取返回值)

如何调用使用JNA返回字符串的Delphi函数?(jna获取返回值)

我正在从Java程序的Delphi编译的*
.so文件中调用函数。经过研究后,JNA似乎是他的路要走。在深入研究一些复杂的Delphi代码之前,我尝试使用一些“
Hello World”代码,但是在获取由Delphi函数返回的字符串时遇到了麻烦。

Delphi代码(helloworld.pp):

library HelloWorldLib;function HelloWorld(const myString: string): string; stdcall;begin  WriteLn(myString);  Result := myString;end;exports HelloWorld;beginend.

我从命令行使用“ fpc -Mdelphi helloworld.pp ” 编译它,生成 libhelloworld.so

现在我的Java课:

import com.sun.jna.Library;import com.sun.jna.Native;public class HelloWorld {    public interface HelloWorldLibrary extends Library {        HelloWorldLibrary INSTANCE = (HelloWorldLibrary) Native.loadLibrary("/full/path/to/libhelloworld.so", HelloWorldLibrary.class);        String HelloWorld(String test);    }    public static void main(String[] args) {        System.out.println(HelloWorldLibrary.INSTANCE.HelloWorld("QWERTYUIOP"));    }}

但是,当我运行此Java代码时,我得到:

# A fatal error has been detected by the Java Runtime Environment:##  SIGSEGV (0xb) at pc=0x00007f810318add2, pid=4088, tid=140192489072384## JRE version: 7.0_10-b18# Java VM: Java HotSpot(TM) 64-Bit Server VM (23.6-b04 mixed mode linux-amd64 compressed oops)# Problematic frame:# C  [libhelloworld.so+0xbdd2]  HelloWorld+0x6fea

请注意,如果更改我的Delphi方法(和关联的Java接口)以返回一个硬编码的整数,则一切工作正常:我传递的字符串将被打印,并且我将整数按预期返回。

奇怪的是,如果Delphi方法返回一个char,我必须将JNA代理编写为返回一个字节,然后将其手动转换为char(如果我声明接口为返回char,则它会打印出一个垃圾字符)。

知道这里出了什么问题吗?

仅供参考,我正在使用Sun JDK 1.7.0_10-b18,JNA 3.5.1和Free Pascal
Compiler版本2.4.4-3.1使用64位Ubuntu 12.04。

答案1

小编典典

Delphi或FreePascal
string是不能用作JNA类型的托管类型。所述JNA文档解释的Java
String被映射到的指针的8个字符的空终止阵列。用Delphi的说法是PAnsiChar

因此,您可以将Pascal代码中的输入参数从string更改为PAnsiChar

返回值存在更多问题。您将需要确定谁分配内存。分配它的人也必须释放它。

如果本机代码负责分配它,那么您需要堆分配以null终止的字符串。并返回指向它的指针。您还需要导出一个解除分配器,以便Java代码可以要求本机代码解除对堆分配的内存块的分配。

在Java代码中分配缓冲区通常更方便。然后将其传递给本机代码,并让其填写缓冲区的内容。这个堆栈溢出问题以Windows
API函数GetWindowText为例说明了该技术:如何使用JNI或JNA读取窗口标题?

使用Pascal的示例如下:

function GetText(Text: PAnsiChar; Len: Integer): Integer; stdcall;const  S: AnsiString = ''Some text value'';begin  Result := Length(S)+1;//include null-terminator  if Len>0 then    StrPLCopy(Text, S, Len-1);end;

在Java方面,考虑到我对Java完全一无所知,我想代码看起来像这样。

public interface MyLib extends StdCallLibrary {    MyLib INSTANCE = (MyLib) Native.loadLibrary("MyLib", MyLib.class);    int GetText(byte[] lpText, int len);}....int len = User32.INSTANCE.GetText(null);byte[] arr = new byte[len];User32.INSTANCE.GetText(arr, len);String Text = Native.toString(arr);

delphi – encoding.getstring不返回字符串

delphi – encoding.getstring不返回字符串

我正在使用Delphi 2009.

这在所有情况下都适用于我,但有一个:

var
  BOMLength: integer;
  Buffer: TBytes;
  Encoding: TEncoding;
  Value: string;

SetLength(Buffer,2048);
CurFileStream.Read(Buffer[0],2048);

Encoding := nil;
BOMLength := TEncoding.GetBufferEncoding(Buffer,Encoding);
Value := Encoding.GetString(Buffer);

在一种情况下,它不起作用,文件是一个简单的小文件,并以UTF8字节顺序标记(BOM)开始,即十六进制:’EF BB BF’并包含以下内容:

0 HEAD
0 @I1@ INDI
1 NAME Barthel Lee /Brenner/
2 CONT MAURICE F. weaveR
2 CONT  When I was eleven or twelve years old,I went to Camp Marguette for a w
2 CONC eek or two in the summertime. It was operated by Catholic Charities and w
0 TRLR

在调用CurFileStreamRead之后,当我检查Buffer的值时,它包含BOM后跟文件,0填充Buffer的2048个字符的其余部分.编码正确检测到UTF8 BOM并将BOMLength设置为3.

但是,在Encoding.GetString语句之后,Value的值是空字符串:”.

我在其周围放了一个try-except块来尝试捕获任何异常,但没有.

该代码适用于500个不同类型的其他文件,但不适用于此类.

有谁知道我可以做些什么来解决这个问题,以便正确读取文件?

或者文件可能有问题,但我不确定它有什么不同,或者如何识别可能有什么不同或错误.

跟进:

雷米的回答是正确的.我现在已经确定它只是小文件,小于缓冲区大小(在我的情况下为2048字节),如果不设置长度就无法工作.

正如我所指出的,缓冲区的剩余部分填充为零.这必然是导致Encoding.GetString函数无法返回值的原因.但是当它知道何时停止时,它没关系.

解决方法

如果源字节为空,或者如果它无法解码字节,则GetString()返回空字符串(而不是引发异常).在您的情况下,您没有告诉GetString()忽略BOM或缓冲区的未填充部分.此外,请确保编码最初为零.

var
  BOMLength: integer;
  Buffer: TBytes;
  BufLength: Integer;
  Encoding: TEncoding;
  Value: string;
begin
  SetLength(Buffer,2048);
  BufLength := CurFileStream.Read(Buffer[0],Length(Buffer));

  Encoding := nil;
  BOMLength := TEncoding.GetBufferEncoding(Buffer,Encoding);
  Value := Encoding.GetString(Buffer,BOMLength,BufLength - BOMLength);
end;

如果仍然不起作用,则源数据很可能在其中包含非法字节.

delphi – 使用带有字符串的Case语句

delphi – 使用带有字符串的Case语句

说我有一个字符串
'SomeName'

并希望在case语句中返回值。这可以吗在这样的case语句中可以使用字符串

Case 'SomeName' of

   'bobby' : 2;
   'tommy' :19;
   'somename' :4000;
else
   showmessage('Error');
end;

解决方法

Delphi Case Statement仅支持序数类型。所以你不能直接使用字符串。

但存在另一种选择

>构建一个基于字符串返回整数(散列)的函数
>使用泛型和匿名方法(A generic case for strings)
>使用接收字符串数组的函数(Making a case for Strings,the sane way)>等等。

delphi – 如何从父类调用子类构造函数?

delphi – 如何从父类调用子类构造函数?

有没有办法从父类调用子类的创建?下面是这个Duplicate方法,我希望调用子类的构造函数,以便底部的测试成功.

type

  IBla<T> = interface(IInvokable)
    ['{34E812BF-D021-422A-A051-A492F25534C4}']
    function GetIntFromIface(): Integer;
    function Duplicate(): IBla<T>;
  end;

  TClassA<T> = class(TInterfacedobject,IBla<T>)
  protected
    function GetInt(): Integer; virtual;
  public
    function GetIntFromIface(): Integer;
    function Duplicate(): IBla<T>;
  end;

  TClassB = class(TClassA<Integer>,IBla<Integer>)
  protected
    function GetInt(): Integer; override;
  end;

function TClassA<T>.Duplicate: IBla<T>;
begin
  Exit(TClassA<T>.Create());
end;

function TClassA<T>.GetInt: Integer;
begin
  Exit(1);
end;

function TClassA<T>.GetIntFromIface: Integer;
begin
  Exit(GetInt());
end;

function TClassB.GetInt: Integer;
begin
  Exit(2);
end;

procedure TestRandomStuff.Test123;
var
  o1,o2: IBla<Integer>;
begin
  o1 := TClassB.Create();
  o2 := o1.Duplicate();    
  Assert.AreEqual(o2.GetIntFromIface,2);
end;

解决方法

您可以使用RTTI执行此操作:

uses
  System.Rtti;

....

function TClassA<T>.Duplicate: IBla<T>;
var
  ctx: TRttiContext;
  typ: TRttiType;
  mthd: TRttiMethod;
  inst: TValue;
begin
  typ := ctx.GetType(ClassInfo);
  mthd := typ.getmethod('Create');
  inst := mthd.Invoke((typ as TRttiInstanceType).Metaclasstype,[]);
  inst.AsObject.GetInterface(IBla<T>,Result);
end;

很可能有一种更简洁的方法来使用RTTI来调用构造函数(我对Delphi中的RTTI几乎一无所知),所以你可以很好地阅读该主题而不是将上述内容作为规范的方法来实现.

当然,这假设所有子类都使用TObject中定义的无参数构造函数.这可能是相当有限的.如果您发现自己不得不以更基本的方式重新思考设计,我不会感到惊讶.

如果你的子类都没有实现构造函数,那么你可以使它更简单,而根本不使用RTTI:

function TClassA<T>.Duplicate: IBla<T>;
begin
  Classtype.Create.GetInterface(IBla<T>,Result);
end;

但请注意,这会调用TObject中定义的构造函数,并且不会调用子类中定义的任何构造函数.

delphi – 如何计算字符串中某个字符的出现次数?

delphi – 如何计算字符串中某个字符的出现次数?

如何计算Delphi中字符串中某个字符的出现次数?

例如,假设我有以下字符串,并希望计算其中的逗号数:

S := '1,2,3';

那么我想获得2的结果.

解决方法

你可以使用这个简单的功能:
function OccurrencesOfChar(const S: string; const C: char): integer;
var
  i: Integer;
begin
  result := 0;
  for i := 1 to Length(S) do
    if S[i] = C then
      inc(result);
end;

关于如何调用使用JNA返回字符串的Delphi函数?jna获取返回值的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于delphi – encoding.getstring不返回字符串、delphi – 使用带有字符串的Case语句、delphi – 如何从父类调用子类构造函数?、delphi – 如何计算字符串中某个字符的出现次数?的相关知识,请在本站寻找。

本文标签: