None

C Wrappering with JNA

November 27, 2009

I recently had the job of talking to the Quick Address Pro V6 API from Java. The API is only available as a C library, so I had to use some C wrappering to access it. I did this using JNA. It was an interesting challenge to get it working on both Solaris and Windows.

Interface

In order to use the JNA library, you create an inner interface which mirrors the Java source. In the interface, you load a library into an INSTANCE variable. Here's a cut down example including a call to QA_Open:

public interface QasLibrary extends Library
{
  QasLibrary INSTANCE = (QasLibrary) Native.loadLibrary(Platform.isWindows() ? "qaupied" : "qaupicd", QasLibrary.class);

  int QA_Open(byte[] vsIniFile, byte[] vsSection, IntByReference riHandle);
}

Then, in the class that this interface is inside, create methods to call through to the interface:

public static void Open(byte[] vsIniFile, byte[] vsSection, IntByReference riHandle)
{
  int lReturn = QasLibrary.INSTANCE.QA_Open(vsIniFile, vsSection, riHandle);
  QasInterface.handleError("QA_Open", lReturn);
}

This can then be wrapped by other code to do type conversions:

public static int Open(String pIniFilePath, String pIniFileSection)
{
  IntByReference lHandle = new IntByReference();
  byte[] lIniFileName = pIniFilePath.getBytes();
  byte[] lSection = pIniFileSection.getBytes();
  QasInterface.Open(lIniFileName, lSection, lHandle);

  return lHandle.getValue();
}

Issues

We had some issues with big endian/little endian for numbers on Solaris. We ended up solving that with this code:

public static long GetPickListSize(int viHandle)
{
  byte[] lStrResult = new byte[10];
  LongByReference lResultsSize = new LongByReference();
  QasInterface.GetSearchStatusDetail(viHandle, qassint_PICKLISTSIZE, lResultsSize, lStrResult, 10);

  long lResult = lResultsSize.getValue();
  if (Platform.isWindows() == false)
  {
    lResult = lResult >> 32 + ((lResult & 0xFFFFFFFF) << 32);
  }
  return lResult;
}

Null Terminated Strings

We also needed to null terminate strings passed into the interface.

byte[] lIniFileName = (pIniFilePath + " ").getBytes();
byte[] lSection = (pIniFileSection + " ").getBytes();
// null terminate the strings
lIniFileName[lIniFileName.length - 1] = 0;
lSection[lSection.length - 1] = 0;

Tags: java jna wrappering c