Search code examples
javaswingdelphidlljna

Exception in thread "AWT-EventQueue-0" java.lang.UnsatisfiedLinkError: testmydll.TestDLL.a()I


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.

Solution

  • 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.