A Short, Practical Review of Foreign Function Calls in Java, C#, C++

Android is a popular platform for smartphones, with ten of thousands of applications developed for it every year. For coding an Android app, there are a number of programming languages, but Java is the most popular. However, Xamarin provides tools for writing applications in C# if you prefer. If you use Xamarin, but sometimes want to use an open-source library written in Java, you still can. The state of currently used, practical Foreign Function Interfaces (FFI) on most platforms is similar. Of course, the difficulty is in the details.

Generally, there are two ways for code in one language to call another: use a native function to call the foreign function; or, use reflection to call the foreign function. A bindings interface offers native functions to the whole foreign API.

Java Native Interface (JNI) provides a native interface to call non-Java code from Java. It also provides an API for use in C++ to invoke Java code, structured like Java’s reflection API.

There are a number of tutorials on how to use JNI, but they are somewhat out of date. This article brings it forward–if only to a small degree, with “how to” explanations.

Java Native Interface on Windows

Java to C# Call Using JNI

JNI provides a native interface for C++ functions in Java. For Java to call C#, a C++/CLI wrapper layer must be created containing calls to C# code.

  1. Create a Java file (e.g., Program.java) with a class.
  • Add native methods (e.g., static native void greet()) to the class corresponding to entry points in a C++/CLI DLL. These methods have no body in the Java code; the bindings to the C++/CLI code are assigned at runtime when the class is created.
  • Add a static initializer (e.g., { System.load(“…”); }) in the class to load the C++/CLI DLL defined in step 5. The purpose of the initializer is to load the C++/CLI DLL code and bind them to the native methods in the class. The C++/CLI DLL contains entry points that JNI will bind with the native methods in this class.

Program.java

  1. Compile the Java class, e.g., javac Program.java.
  2. Generate a C-style header file from the Java class, e.g., javah Program.

Program.h

  1. Create a C# DLL project, e.g., ClassLibrary1.
  • In the C# library, add a class, e.g., Class1.

Class1.cs

  1. Create a C++/CLI DLL project, e.g., ClassLIbrary2. This library functions as the “glue” between JNI and C#.
  • In the C++/CLI project, add or modify a C++/CLI source file, e.g., Entries.cpp.
  • In the source file, add #include <jni.h>, #include <>.
  • Add a #include directive for the JNI-generated (via javah) C-style header in the source file, e.g., Program.h.
  • Add code to adjust search path for DLLs, otherwise when the Java program is ran, the program will crash.
  • Add code for entry points defined in the generated header file.

Entries.cpp

  1. Compile, build, and execute.

For a basic introduction on JNI Java to C++ calling, see http://www.codeproject.com/Articles/13093/C-method-calls-within-a-Java-program. However, the introduction is out of date and the example will not compile, e.g., the keyword __gc is not valid in the Visual C++ compiler since 2005!

For another introduction, see the following article in Software Practice and Experience: http://onlinelibrary.wiley.com/doi/10.1002/cpe.858/abstract

C# to Java Call Using JNI

JNI provides an interface for C++ to call Java code.  However, the interface is not native for C#. Instead, JNI is a reflection API for use in C++. A C++/CLI library must act as an intermediary between C# and JNI.

  1. Create a Windows C# application. Insert calls to a wrapper function containing the JNI code.

CSharpProgram.cs

  1. Create a C++/CLI DLL project for wrapping the calls to JNI/Java.
  • In the C++/CLI project, add or modify a C++/CLI source file for code that will contain the JNI calls, e.g., Wrapper.cpp.
  • Add a #include directives for JNI, e.g., #include <jni.h>, #include <win32/jni_md.h>.
  • Add code for JNI_CreateJavaVM. This function call loads the Java Virtual Machine (JVM) and returns handle to it.
  • For each function you want to call in your Java API, add code for FindClass, GetStaticMethodID, CallStaticVoidMethod, etc. These functions get handles to JNI objects, and call the Java API.

Wrapper.cpp

  1. Create a .JAR file or directory structure with the Java API you want to implement. Make sure to set up the class in a package with the appropriate directory structure for the JAR, otherwise, JNI will not be able to find the API.

com/domemtech/examples/Example.java

  1. Compile, build, and execute.

For another introduction on C++ calling Java, see http://www.codeproject.com/Articles/993067/Calling-Java-from-Cplusplus-with-JNI.

FFI in Xamarin

C# to Java Calling using a Binding Library

The details of how to create a Java Binding Library for a Java Jar library is given by Xamarin (https://developer.xamarin.com/guides/android/advanced_topics/java_integration_overview/binding-a-java-library/binding-a-jar/). As outlined there, you must create a library that belongs to a package, such as “com.domemtech.examples.” Otherwise, this won’t work. To do that, create your source in a directory tree corresponding to the package (e.g., “com/domemtech/examples/Example.java”). Compile the java code (“javac com”), then create a Jar file (“jar cvf example.jar com”).

C# to Java Calling using JNI

The details of how to use JNI is given by Xamarin (https://developer.xamarin.com/guides/android/advanced_topics/java_integration_overview/working_with_jni/). There doesn’t seem to be a discussion of where to place the JAR files, but it works if you create a binding library that embeds the jar.

Generating Interfaces

JNI4Net

JNI4Net is an open-source tool that generates native interfaces for Java and C#. After generating the proxy code, you have to add functionality to work as a wrapper. A good introduction is here: http://www.c-sharpcorner.com/UploadFile/ajyadav123/invoking-java-code-in-C-Sharp-net/

Simplified Wrapper and Interface Generator (SWIG)

SWIG is an open-source tool that generates native interfaces from a description specification. Complete functionality of the wrapper must be added by the user.

Leave a comment

Your email address will not be published.