I am trying to call a test DLL from Java.
I am using
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Platform;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.*;
The class is declared as
class TestDLL {
public native int a();
public native int DoBeep();
public native int PenniesToCoins();
static { System.loadLibrary("PenniesLib");}
// required to work with JDK 6 and JDK 7 ????????
// I included this because it was in a few examples with the comment above
// but it doesn't seem to make any difference
public static void main(String[] args){
}
}
I have a button on a frame which starts the test
void button1_actionPerformed(ActionEvent e) {
int i;
TestDLL t = new TestDLL();
i= t.a();
}
}
The program crashes at
i= t.a();
Exception in thread "AWT-EventQueue-0" java.lang.UnsatisfiedLinkError: testmydll.TestDLL.a()I
at testmydll.TestDLL.a(Native Method)
at testmydll.TestMyDLL.button1_actionPerformed(TestMyDLL.java:85)
I know that the library loads OK. Changing its name to "PenniesLibX" produces an error.
I have tested this DLL from a Delphi program and calling it works.
I have checked the exported functions with DLL Export Viewer
a 0x00411ff4 0x00011ff4 1 (0x1) PenniesLib.dll C:\WINXP\system32 PenniesLib.dll Exported Function
DoBeep 0x00411fe8 0x00011fe8 2 (0x2) PenniesLib.dll C:\WINXP\system32\PenniesLib.dll Exported Function
PenniesToCoins 0x00411f7c 0x00011f7c 3 (0x3) PenniesLib.dll C:\WINXP\system32\PenniesLib.dll Exported Function
Help much appreciated
I have re-written this as
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Platform;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.*;
class TestDLL {
public native int a();
public native int DoBeep();
public native int PenniesToCoins();
static { System.loadLibrary("PenniesLib");}
}
public class TestThisDLL {
public static void main( String args[] ) {
System.out.println("Start of DLL test");
TestDLL t = new TestDLL();
int i = t.a();
System.out.println("DLL response is " + String.valueOf(i));
}
}
The Delphi DLL code is
{ Copyright © 2001 Delphi 6 Developer's Guide Xavier Pacheco
and Steve Teixeira }
{ DoBeep and a added for testing}
library PenniesLib;
{$DEFINE PENNIESLIB}
uses
SysUtils,
Classes,
PenniesInt;
function PenniesToCoins(TotPennies: word; CoinsRec: PCoinsRec): word; StdCall;
begin
Result := TotPennies; // Assign value to Result
{ Calculate the values for quarters, dimes, nickels, pennies }
with CoinsRec^ do
begin
Quarters := TotPennies div 25;
TotPennies := TotPennies - Quarters * 25;
Dimes := TotPennies div 10;
TotPennies := TotPennies - Dimes * 10;
Nickels := TotPennies div 5;
TotPennies := TotPennies - Nickels * 5;
Pennies := TotPennies;
end;
end;
function DoBeep: word; StdCall
begin
Beep;
Result:=55;
end;
function a: word; StdCall
begin
Beep;
Result:=88;
end;
{ Export the function by name }
exports
PenniesToCoins, DoBeep, a;
end.
You aren't wrapping the native library the way you are supposed to. In fact you are not using any JNA in the code in the question. The key is that you must call Native.loadLibrary.
Your Java code should look like this:
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.win32.StdCallLibrary;
public class TestThisDLL {
public interface PenniesLib extends StdCallLibrary {
PenniesLib INSTANCE = (PenniesLib) Native.loadLibrary(
"PenniesLib", PenniesLib.class);
int a();
}
public static void main(String[] args) {
int value = PenniesLib.INSTANCE.a();
System.out.println(value);
}
}
Note that I have taken the liberty of assuming that you will change Word
into Integer
in your Delphi code. Since Java does not have unsigned types, and since 16 byte types are so 1990s, I think a 32 bit signed integer makes most sense.