Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java DLL问题和无效内存访问_Java_Delphi_Dll_Jna - Fatal编程技术网

Java DLL问题和无效内存访问

Java DLL问题和无效内存访问,java,delphi,dll,jna,Java,Delphi,Dll,Jna,这就是我的情况。我的任务是将部分程序从用DelphiIDE编写的pascal移植到Java程序,至少我相信是这样。我没有参与正在移植的程序的创建,所以除了观看它作为最终产品所做的工作之外,我几乎不知道它的内部工作。尽管如此,我已经开始将其传输过来,并在他们的.dll调用中遇到了障碍 它们的.dll调用如下所示: unit impdll; interface uses Classes, Sysutils; type TChar80 = array[0..80] of char;

这就是我的情况。我的任务是将部分程序从用DelphiIDE编写的pascal移植到Java程序,至少我相信是这样。我没有参与正在移植的程序的创建,所以除了观看它作为最终产品所做的工作之外,我几乎不知道它的内部工作。尽管如此,我已经开始将其传输过来,并在他们的.dll调用中遇到了障碍

它们的.dll调用如下所示:

unit impdll;

interface

uses
    Classes, Sysutils;
type
    TChar80 = array[0..80] of char;

procedure GetElev (var a,b:double; var Elevate,ErrCode:LongInt); stdcall;
procedure ClxGen (var errCode:LongInt); stdcall;
procedure RunGen (var ErrCode:Integer;var XFileName:Tchar80;XLen: integer); stdcall;

implementation

procedure GetElev (var a,b:double; var Elevate,ErrCode:LongInt); stdcall; external 'Getelev.dll' name 'GETELEV';
procedure ClxGen (var errCode:LongInt); stdcall; external 'ClxGen.dll' name 'CLXGEN';
procedure RunGen (var ErrCode:Integer;var XFileName:Tchar80;XLen: integer); stdcall; external 'Rungen.dll' name '_rungen@12';

end.
我不知道他们的.dll做什么,甚至不知道它们作为参数输入或输出,也不知道它们是用什么代码编写的。尽管它们的名称的性质以及知道程序的这一部分是做什么的,但我可以猜到,三个.dll文件中的第一个文件基于lat-long位置a和b获得高程,并将其返回到double,将高程返回到longint。 在getelev.dll文件上使用“dumpbin.exe/EXPORTS”后,它将此作为唯一的函数名,根据它们的代码和对.dll的调用,这是有意义的:

ordinal   hint   RVA     name
      1      0   0000100 GETELEV
通过研究,我发现名称后面有一个
@#“
,意味着有一定数量的字节作为参数传递,所以我假设这意味着它们没有参数。我的推理错了吗

还有,这里有没有确定返回类型的方法?我假设
CLXGEN
没有返回类型,仅仅是因为使用的是过程而不是函数,或者过程通常是在接口中的函数上使用的

无论如何,通过使用JNA,我能够部分地将.dll库转换成Java。我的代码如下所示:

public class MainProgram {

public interface LibraryCalls extends Library {
    LibraryCalls INSTANCE = (LibraryCalls) Native.loadLibrary("getelev",LibraryCalls.class);        
    public void GETELEV(double a, double b, int Elevate, int ErrCode);

}

public static void main(String[] args) 
{
    System.loadLibrary("getelev");
    LibraryCalls newCall = LibraryCalls.INSTANCE;
    newCall.GETELEV(24.726348,-81.051194,0,0);

}
}

这就是我的麻烦开始的地方。我得到一个无效的内存访问,如下所示:

Exception in thread "main" java.lang.Error: Invalid memory access
    at com.sun.jna.Native.invokeVoid(Native Method)
    at com.sun.jna.Function.invoke(Function.java:408)
    at com.sun.jna.Function.invoke(Function.java:354)
    at com.sun.jna.Library$Handler.invoke(Library.java:244)
    at com.sun.proxy.$Proxy0.GETELEV(Unknown Source)
    at markSimTest.MainProgram.main(MainProgram.java:22)
在研究了这种无效的内存访问之后,我发现很多人都在谈论映射,而映射是否正确可能会影响这一点,所以我想知道这是否是我的问题?如果不是这样的话,那么JNA可能不适用于.dll类型。这只是因为它是用未知语言编写的,如果是这样的话,我猜它是一个pascal.dll,如果可能的话。正如您所知,我对.dll没有太多的知识

同样在同一个主题中,我很难找到如果.dll是一个void函数且不带参数,它将如何返回lat、long或elevation。这个过程是否做了一些特殊的事情来从.dll中获取这些数字

任何帮助,即使是部分帮助,都将不胜感激

解决方案编辑:

我现在看到的是一个相当简单的解决方案,但当时我看不到这样的解决方案,因为我在这个问题上没有足够的知识

以下是最新的Java代码:

public interface LibraryCalls extends StdCallLibrary{
    LibraryCalls INSTANCE = (LibraryCalls) Native.loadLibrary("getelev",LibraryCalls.class);

    public void GETELEV(Pointer a, Pointer b, Pointer Elevate, Pointer ErrCode);
}


public static void main(String[] args) 
{
    Pointer lat = new Memory(Native.getNativeSize(Double.TYPE));
    lat.setDouble(0, 34.769823);
    Pointer lon = new Memory(Native.getNativeSize(Double.TYPE));
    lon.setDouble(0, -87.654147);
    Pointer elevate = new Memory(Native.getNativeSize(Integer.TYPE));
    elevate.setInt(0, 0);
    Pointer errCode = new Memory(Native.getNativeSize(Integer.TYPE));
    errCode.setInt(0, 0);

    LibraryCalls newCall = LibraryCalls.INSTANCE;
    newCall.GETELEV(lat,lon,elevate,ErrCode);
}

GetElev
接受4个参数,它们都是指针
var
用于指示参数是通过引用传递的。所以
a
b
Elevate
ErrCode
都是输出。没有
@
的事实并不意味着很多。声明显示
GetElev
接受四个参数。在C中,声明是:
void\u stdcall GetElev(double*a,double*b,int*elevate,int*errcode)。其他声明类似。正如@JimRhodes所说:
var
意味着参数通过引用传递。似乎只有
XLen
通过值传递。对不起,我不知道如何将它翻译成Java。DLL似乎将函数导出为全大写:
GETELEV
,等等。这很容易翻译。阅读Delphi文档。这不是秘密。GetElev有4个参数。他们在那里。天气晴朗。不要费心尝试从导入名称中反转它。阅读代码。您需要使用
StdCallLibrary
标记界面来指示您的DLL调用约定(“stdcall”)