所以这是我的情况。我的任务是将一个程序的一部分从delphi IDE中编写的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文件中的第一个根据纬线长位置a和b得到高程,并将其返回到双打和对于longint的提升。 使用" dumpbin.exe / EXPORTS"在getelev.dll文件上它给了我这个唯一的函数名,根据他们的代码和.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,如果可能的话。你可以告诉我在.dlls中没有很多知识
同样在同一主题上,如果它是一个void函数并且没有参数,我很难找到.dll将如何返回lat或long或者提升。该程序是否有特殊之处从.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);
}