4

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);
}
Jared Wood
  • 81
  • 7
  • `GetElev` takes 4 arguments and they are all pointers. `var` is used to indicate that an argument is passed by reference. So `a`, `b`, `Elevate` and `ErrCode` are all outputs. – Jim Rhodes May 19 '17 at 21:24
  • The fact that there is no `@#` does not mean a lot. The declaration shows that `GetElev` takes four parameters. In C, the declaration would be: `void __stdcall GetElev(double *a, double *b, int *elevate, int *errcode);`. The other declarations are similar. – Rudy Velthuis May 19 '17 at 21:26
  • As @JimRhodes said: `var` means the arguments gets passed by reference. Only `XLen` seems to be passed by value. I have no idea how to translate this to Java, sorry. It seems that the functions are exported by the DLL as all uppercase: `GETELEV`, etc. – Rudy Velthuis May 19 '17 at 21:30
  • 1
    This is pretty easy to translate. Read the Delphi documentation. It's no secret. GetElev has 4 parameters. There they are. Clear as day. Don't bother trying to reverse it from the import names. Read the code. – David Heffernan May 19 '17 at 21:35
  • JNA has facilities to pass things by reference. It doesn't help that currently most of the google indexed links leading to JNA documentation are dead though :/ – Jorn Vernee May 19 '17 at 21:40
  • I believe I am a bit confused on whether or not I even need to know what is inside the dll. I guess I am trying to understand what their call even does. I understand the parameters of their functions, I get that but I guess I was confused about what I needed to put into the dll. I guess I saw the procedure and the dll as two completely separate things, not connecting at all, but let me see if I get this right. Their procedure call means that the function inside the dll is void. Their parameters are what are actually taken in inside the dll. But the dll is only called via its name, correct? – Jared Wood May 21 '17 at 02:06
  • So, essentially, the interface method is being overriden with the one from the dll? If this is what is happening then I understand the relation now. I was going so far off track simply because I did not understand how dll work period, and for that I apologize and then I thank you for helping me get on the right track. – Jared Wood May 21 '17 at 02:14
  • 1
    You need to use the `StdCallLibrary` tagging interface to indicate your DLLs calling convention ("stdcall") – technomage May 22 '17 at 16:31
  • Top google hit for JNA takes you to [the project page](http://github.com/java-native-access/jna), which links to all documentation – technomage May 22 '17 at 16:34
  • `procedure GetElev (var a,b:` **`doube;`**? Could there be other typos (maybe also in terms of function names)? – CristiFati May 23 '17 at 10:50
  • @CristiFati Ah, that was my own typo when typing said procedure in. The interface file did not exist on my computer so I just typed it over real fast, it is correct in their file. I think I understand what I was doing wrong anyhow. Considering this dll was not made specifically for java, I do not think it can be implemented into java, based on a few sources I found. I think I will have to end up either disassembling their dll and see if I can piece together its functions or see if I can make another dll that will load their dll but also be able to talk to my Java. – Jared Wood May 23 '17 at 14:01
  • *Considering this dll was not made specifically for java, I do not think it can be implemented into java* - uhh, what? That's literally what JNA is for! You just have to match the types which the Delphi version has in your Java interface! You'll need to copy in the actual function declarations if you expect anyone to be able to help you. – cbr May 23 '17 at 15:07
  • @cubrr Those are the full delphi function declarations. Like I said, I only have the dlls and the interface that calls them, that is the full interface, function declarations and all. I have edited my code however, for the new java code I have, which still gives the same error: invalid memory address Or are those incorrect parameters because var is a pointer? – Jared Wood May 23 '17 at 16:23
  • They are of course incorrect parameters because var is a parameter passed by reference as mentioned by several comments above. – Sertac Akyuz May 23 '17 at 17:34
  • ...and you still haven't changed your interface to extend from `StdCallLibrary` instead of `Library`. This if anything will break. – cbr May 23 '17 at 17:37
  • Thank you all for your help. With all of your feedback I was able to piece together exactly what I needed, and have thus got past my Invalid Memory Access. I have edited the code above to reflect my new function call which does not get me an Invalid Memory Access anymore. – Jared Wood May 25 '17 at 14:40

0 Answers0