Introduction
In my last assignment I was asked to
write a Java code that makes use of .Net DLLs. There are a lot of tools/libraries
available on the web that will do this for you (JNI4Net actually works
bi-directionally; you can call Java code from .Net code). But I wanted greater
control over things so I decided to do it from scratch.
Assumption: I am assuming
reader has basic knowledge of JNI programming. Like native methods in java
code, generated header files and implementing the headers in native code.
Solutions
Most common way to solve this problem
is to write a native code which invokes .Net code and uses this native wrapper
in Java using JNI (This tutorial explains Native to .net part http://support.microsoft.com/kb/828736
).For this thing to work, you should register your .Net assemblies using
regasm.exe (tool that comes with Visual Studio).
But, there can be situations where you
can’t use regasm.exe, in such case you can use registration free activation of
.Net assemblies. (http://msdn.microsoft.com/en-us/library/ms973915.aspx).
This procedure involves embedding registry information (that would have been
written to registry by regasm.exe otherwise) in the DLLs. But I personally feel
this approach is very complex and somehow didn’t work for me from JNI.
And when I thought I’m completely out
of options, I met C++/CLI :)
C++/CLI is an entirely new language
which is intended to supersede Managed Extensions for C++, you can find out
more about this language at http://msdn.microsoft.com/en-us/magazine/cc163852.aspx
Why this is interesting because when
you compile your C++/CLI code, generated code is a hybrid of native and managed
code. And since you can code in C, C++/CLI and reuse managed library code in
the same source file this becomes a lucrative option for our Java-Net
connectivity bridge.
Tutorial
There are 3 different projects in
this tutorial, You can download all these projects HERE.
- A simple C# class library: Single class with one method that add two integers.
- Java code which loads DLL created in project 3 to invoke functions implemented in C++/CLI code.
- A C++/CLI library which uses C# library created in project 1 and implements JNI headers generated from Java native methods.
Part1: Simple C#
library
Here, you can use any existing .Net
library (.Net DLL) that you want to call from Java. I have included one for
better understanding.
- Create a C# project of type “Class library”.
- My sample project includes single class which has a method that adds given two integers.
namespace
MyCSharpMathsLib
{
public class Adder
{
public int addTwoNumberes(int a, int b)
{
return a + b;
}
}
}
Part2: Java code
with native method.
This code is a simple Java class plus
some native methods. You can directly import this project in Eclipse IDE and run CsharpConsumer.java once you have completed compiling and adding Proejct 3 DLLs to %PATH%
CsharpConsumer.java
public class
CsharpConsumer {
static{
System.loadLibrary(“JNICsharpBridge");
//Load Project3
generated DLL, DLL’s parent folder should be in your libpath. [%PATH%
variable], This will be executed at time of loading class CsharpConsumer
}
public static void main(String[] args) {
CsharpConsumer csc = new CsharpConsumer();
csc.reigsterAssemblyHandler("c:\\mydlls\\");
//Tell native code
where to look for .net DLLs.
System.out.println("Result of adding = "+ csc.addTwoNos(1, 5));
}
native int addTwoNos(int a,int b);
native int reigsterAssemblyHandler(String str);
}
- addTwoNos and reigsterAssemblyHandler are declarations of two native methods that we will implement in C++/CLI code.
- “javah” tool generates C/C++ header files using compiled CsharpConsumer.java.
- In order to use native code we must load native binaries into JVM process that’s done using System.loadLibrary call
- In order to use .Net assemblies you must register corresponding DLLs to GAC (Global assembly cache) or the DLLs should be present in the same folder as that of your executables. But since our bridge DLL runs under JVM, these dlls should be copied to JRE\bin, and from deployment perspective this is an awkward situation. To overcome this problem we can load .Net assemblies that our code depends upon(MyCSharpMathsLib.dll in this case) dynamically from C++/CLI code
- Native mothod “reigsterAssemblyHandler” does this job, and tells C++/CLI code where to look for dependencies (implemented in native code)
Part3: A C++/CLI
library that acts as a bridge
This code acts as bridge between Java and C# (and managed
code written in any language) code. C++/CLI has entirely new language
syntax and I personally find it bit complex. But one major advantage of using
C++/CLI is that here is that you can directly use managed objects and still
your compiled binaries and accessible through native interfaces (e.g. JNI).
- Create new CLR Console application.
- From build settings make this project’s output type a DLL instead of exe, select /clr switch.
- Include the files generated using “javah” in this project. Following snippet shows how to implement.
- Add Project1 or its DLL as dependency / reference.
- Implemented header file generated by javah utility.
- Compile your code as a DLL and with “/clr” switch.
- Put generated DLL in a directory that is listed in %PATH%, or put that directory in %PATH% variable, either ways possible, see what suits you.
Links:
AssemblyResolve Event handler:
Calling managed code from native
Registration free .net assemblies.
C++/CLI introduction
©2012 Abhijeet Apsunde LinkedIn
View comments