So here is my situation. I am tasked with porting over part of a program from pascal written in a delphi IDE, at least I believe, to a Java program. I was not present at the creation of the program being ported over so I have almost no knowledge of the inner workings other than watching what it does as a final product. None-the-less, I have started transferring it over and hit a roadblock with their .dll calls.
Their .dll calls are represented here:
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.
I have no real knowledge of what their .dlls do or even take in or out as parameters or in what code they are written. Although, the nature of their names and the knowing what this portion of the program does, I can guess that the first of the three .dll files get elevation based on a lat long position, a and b, and return it to the doubles and the elevation to the longint. After using "dumpbin.exe /EXPORTS" on the getelev.dll file it gave me this as the only function name, which makes sense based on their code and call of the .dll:
ordinal hint RVA name
1 0 0000100 GETELEV
Through research I found out that having an '@#'
after the name means a certain amount of bytes are passed as parameters, so I am assuming this means they get no parameters. Is my reasoning wrong here?
Also, is there a way to determine the return type here? I would assume that CLXGEN
has no return type simply because a procedure was being used instead of a function, or are procedures generally used over functions in interfaces?
Anyways, by using JNA, I was able to partially get the .dll libraries into Java. I ended up with my code that looks like this:
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);
}
}
This is where my trouble begins. I get an Invalid Memory Access seen below:
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)
After researching about this Invalid memory access I found many people talking about mappings and whether or not they were correct could affect this, so I am wondering if that might be my problem? If not this then maybe JNA does not work for the type of .dll this is simply because it was written in an unknown language, which if this is the case I would guess it is a pascal .dll, if that is even possible. As you can tell I do not have a lot of knowledge in .dlls
Also on the same topic, I had trouble finding out how the .dll will return lat or long or elevation if it is a void function and takes no parameters. Does the procedure do something special to get these numbers from the .dll?
Any help at all, even partial, would be greatly appreciated.
Solution Edit:
A rather simple solution now that I look at it, but at the time I could not see such a solution simply because I did not have enough knowledge on this subject.
Here is the updated Java code that worked:
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);
}