I have a simple C# class library, I wrapped it in a C++/CLI class library and loaded it into a simple Java console application. But when I run the Java application, I get the following error:
Process is terminated due to StackOverflowException.
Process finished with exit code -1073741571 (0xC00000FD)
My C# library has a Class1.cs file:
using System;
namespace CSharpClassLibrary1
{
public class Class1
{
public Class1() { }
public void Print()
{
Console.WriteLine("Hello World From C#!");
}
}
}
My C++/CLI wrapper has two files: HelloWorld.h and CppClassLibrary1.cpp.
HelloWorld.h:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method: print
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_print
(JNIEnv*, jobject);
#ifdef __cplusplus
}
#endif
#endif
I got it by running the command of the following form in my Java application: javac -h <directory> -d <directory> <source files>.
CppClassLibrary1.cpp:
#include "pch.h"
#include "HelloWorld.h"
using namespace CSharpClassLibrary1;
JNIEXPORT void JNICALL Java_HelloWorld_print(JNIEnv* env, jobject obj)
{
Class1^ cls = gcnew Class1();
cls->Print();
}
I added the CSharpClassLibrary1 as reference to the C++/CLI wrapper.
I added to the "Include directories" setting the following paths:
C:\Users\ns16\AppData\Local\JetBrains\Toolbox\apps\IDEA-C\ch-0\192.6817.14\jbr\include
C:\Users\ns16\AppData\Local\JetBrains\Toolbox\apps\IDEA-C\ch-0\192.6817.14\jbr\include\win32
My Java application has a HelloWorld.java file:
public class HelloWorld {
public native void print();
static {
try {
System.loadLibrary("CppClassLibrary1");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load.\n" + e);
}
}
public static void main(String[] args) {
HelloWorld hw = new HelloWorld();
hw.print();
}
}
I specified the CppClassLibrary1 library path in the java.library.path variable.
Please help me! What am I doing wrong?
Update. A study of the problem showed the following:
In the Java application error appears in the hw.print(); line. If you comment it out, the application will start successfully.
If in the C++/CLI wrapper in the CppClassLibrary1.cpp file you replace Java_HelloWorld_print function body to the std::cout << "Hello World From C++/CLI!"; line, the Java application will start successfully and print the Hello World From C++/CLI! string.
If you create C# console application, add to it the C# library as references and add into Main method the Class1 cls = new Class1(); cls.print(); code, the application will start successfully and print the Hello World From C#! string.
I copied the C# library assembly in the directory with the java.exe file (in my system it located in C:\Users\ns16\AppData\Local\JetBrains\Toolbox\apps\IDEA-C\ch-0\192.6817.14\jbr\bin) and now the Java application works! I would not want to move the assembly out of the project directory, but this is the only solution I found.
Related
I try to run my java with native method on mac and windows.
class with native method:
public class NativeMethods {
static {
System.loadLibrary("nativeLib");
}
public static native void printFromJni();
}
class with main method:
public class Demo {
public static void main(String[] args) {
// TODO Auto-generated method stub
NativeMethods.printFromJni();
}
}
JNI header:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_sdk_NativeMethods */
#ifndef _Included_com_sdk_NativeMethods
#define _Included_com_sdk_NativeMethods
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_sdk_NativeMethods
* Method: printFromJni
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_sdk_NativeMethods_printFromJni
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
c file:
#include <stdio.h>
JNIEXPORT void JNICALL Java_com_sdk_NativeMethods_printFromJni
(JNIEnv *env, jclass class){
printf("hello from jni. \n");
}
If i compile c files on MAC:
gcc -o libNativeLib.so -shared -I/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/include nativeLib.c -lc
and run:
java Demo
It's work correct.
But if i compile c files on Windows:
gcc -o nativeLib.dll -shared -I"C:\P
rogram Files\Java\jdk1.8.0_60\include" nativeLib.c
-std=c99 -I"C:\Program Files\Java\jdk1.8.0_60\include\win32"
i get error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: com.sdk.Nati
veMethods.printFromJni()V
at com.sdk.NativeMethods.printFromJni(Native Method)
at Demo.main(Demo.java:9)
if i compile c files on mac(with -m32 flag) and copy library on Windows i get error:
Can't load this .dll (machine code=0x7) on
a IA 32-bit platform
Where is a problem? Please help.
I found SOLUTION:
gcc -Wall -D_JNI_IMPLEMENTATION_ -Wl,--kill-at -I[Java_HOME]/include -I[Java_HOME]/include/win32 -shared -o Sample1.dll Sample1.c
First create the object of Nativemethods class in your main class and then try to run the function.
Tell me if still error persists. I will run in my system and let you know what actually is the error.
And by the way both classes are in same file ?
Because if not then while compiling java program you need to be careful about getting right compilation while generating header file .. (That step worked out okay for you right ?)
Also while running javafile give path for dll file.
-Djava.library.path = "Write path"
So I'm new to JNI and I'm following a simple hello word example but I keep getting error UnsatisfiedLinkError. What am I doing wrong? Here's my .h file:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class JNITEST_jnihellonative */
#ifndef _Included_JNITEST_jnihellonative
#define _Included_JNITEST_jnihellonative
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: JNITEST_jnihellonative
* Method: hellofromc
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_JNITEST_jnihellonative_hellofromc(JNIEnv *,jobject);
#ifdef __cplusplus
}
#endif
#endif
.c File
#include <jni.h>
#include<stdio.h>
#include<windows.h>
#include "jnihellonative.h"
JNIEXPORT void JNICALL
Java_JNITESTS_jnihellonative_hellofromc(JNIEnv *env, jobject obj){
printf("Hello World");
return;
}
java main class
package JNITEST;
public class Jnihello {
public static void main(String[] args) {
jnihellonative jniprint = new jnihellonative();
jniprint.hellofromc();
}
}
java class
package JNITEST;
public class jnihellonative {
public native void hellofromc();
static{
System.load("C:\\Users\\Kevin\\Documents\\NetBeansProjects\\JniHelloTest.dll");
}
}
I keep getting this error
Exception in thread "main" java.lang.UnsatisfiedLinkError: JNITEST.jnihellonative.hellofromc()V
at JNITEST.jnihellonative.hellofromc(Native Method)
at JNITEST.Jnihello.main(Jnihello.java:19)
Java Result: 1
BUILD SUCCESSFUL (total time: 1 second)
I have tried using System.load() and System.loadLibrary() but i get same error.
You've changed the name of your class since you generated the .h file and wrote the .c file. The .h file has jnihellonative, your Java code has Jnihello.
I have tried using System.load() and System.loadLibrary()
Irrelevant. You're not getting the exception from either of these, you're getting it when calling your native method.
I'm making a simple JNI test app using Eclipse on Windows. My C++ compiler is MinGW 4.6.2. Java is throwing an UnsatisfiedLinkError when I try to invoke a function in my test DLL (the DLL itself loads without problem). I have verified that my DLL exports a "C" function with the same name as the function generated by the javah utility.
How could trying to invoke the function possibly generate a link error? (Also, is there any way to get more detail as to what symbol isn't being found? A bald statement that there's an UnsatisfiedLinkError is next to useless.)
Here's the Java which defines the native function:
package com.xyz.jsdi_test;
import java.io.File;
public class JSDI
{
public static native void func(
String str,
int i,
Integer ii,
long j /* 64 bits */,
Long jj,
byte[] b
);
public static void dummy()
{
System.out.println("JSDI.dummy()");
}
static
{
File f = new File("..\\jsdi\\bin\\jsdi.dll");
System.out.println("Preparing to load: " + f);
System.load(f.getAbsolutePath());
System.out.println("Successfully loaded: " + f);
}
Here is the corresponding output from javah:
...
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_xyz_jsdi_test_JSDI
* Method: func
* Signature: (Ljava/lang/String;ILjava/lang/Integer;JLjava/lang/Long;[B)V
*/
JNIEXPORT void JNICALL Java_com_xyz_jsdi_1test_JSDI_func
(JNIEnv *, jclass, jstring, jint, jobject, jlong, jobject, jbyteArray);
#ifdef __cplusplus
}
#endif
...And how I implemented the function...:
extern "C"
{
JNIEXPORT void JNICALL Java_com_xyz_jsdi_1test_JSDI_func(
JNIEnv * env,
jclass _class,
jstring str,
jint i,
jobject ii,
jlong j,
jobject jj,
jbyteArray b
)
{
// don't do anything...let's just try to get called successfully...
}
} // extern "C"
Here is how I attempt to invoke it.
...
public static void main(String[] args)
{
JSDI.dummy(); // cause class to load, which should cause System.load() to run.
JSDI.func("hello", 0, 0, 0L, 0L, (byte[])null);
}
Finally, this is the output:
Preparing to load: ..\jsdi\bin\jsdi.dll
Successfully loaded: ..\jsdi\bin\jsdi.dll
JSDI.dummy()
java.lang.UnsatisfiedLinkError: com.xyz.jsdi_test.JSDI.func(Ljava/lang/String;ILjava/lang/Integer;JLjava/lang/Long;[B)V
at com.xyz.jsdi_test.JSDI.func(Native Method)
at com.xyz.jsdi_test.SimpleTest.main(SimpleTest.java:24)
SOLVED IT -- WOOO!
It turns out that MSVC prepends an underscore to the name of __stdcall functions. MinGW does not. The Windows JVM apparently expects the '_' prefix. As soon as I prepended '_' to the function name and rebuilt with MinGW, everything worked just dandy.
eg:
JNIEXPORT void JNICALL Java_com_xyz_jsdi_1test_JSDI_func ==> _Java_com_xyz_jsdi_1test_JSDI_func
EDIT:
The --add-stdcall-underscore feature of the dlltool utility included with MinGW can solve this problem for you transparently. Set it up in your Makefile and you don't need to worry about having different versions of the actual source code for different compilers. See at this link.
Posting a working example, copy the content in the three files in the same directory (modify the path to your JDK) then invoke build.cmd
/* File: HelloWorld.java */
public class HelloWorld {
private static native void writeHelloWorldToStdout();
public static void main(String[] args) {
System.loadLibrary("HelloWorld");
writeHelloWorldToStdout();
}
}
/* File: HelloWorld.c */
#include <stdio.h>
#include "HelloWorld.h"
JNIEXPORT void JNICALL Java_HelloWorld_writeHelloWorldToStdout(JNIEnv *env, jclass c)
{
printf("Hello World!");
}
rem File: build.cmd
%echo off
echo delete generated binaries
del HelloWorld.class
del HelloWorld.dll
del HelloWorld.h
del HelloWorld.def
echo Compile the Java Class
javac HelloWorld.java
echo Generate the Header file
javah -classpath . -o HelloWorld.h HelloWorld
echo Build the DLL
gcc -I"C:\Program Files (x86)\Java\jdk1.7.0_25\include" -I"C:\Program Files (x86)\Java\jdk1.7.0_25\include\win32" -Wl,--add-stdcall-alias -Wl,--output-def,HelloWorld.def -shared -o HelloWorld.dll HelloWorld.c
echo run the program
java HelloWorld
The signature in the exception doesn't have the 'int' parameter. So your Java code disagrees with your native code.
I am trying native methods for the first time....
I had taken a simple programming from this link Click....
nativetest.java
public class nativetest
{
static {
System.loadLibrary("nativetest");
}
public native String sayHello(String s);
public static void main(String[] argv)
{
String retval = null;
nativetest nt = new nativetest();
retval = nt.sayHello("Beavis");
System.out.println("Invocation returned " + retval);
}
}
javac nativetest.java
javah -jni nativetest
Successfully nativetest.h file has been created
nativetest.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class nativetest */
#ifndef _Included_nativetest
#define _Included_nativetest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: nativetest
* Method: sayHello
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_nativetest_sayHello(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
nativetest.c code
nativetest.c
include "nativetest.h" /*double quotes tells it to search current directory*/
JNIEXPORT jstring JNICALL Java_nativetest_sayHello (JNIEnv *env, jobject thisobject, jstring js)
{
return js;
}
gcc -I/usr/java/jdk1.7.0_13/include -I/usr/java/jdk1.7.0_13/include/linux -o nativetest.so -shared nativetest.c
Successfully shared object file has been created.
when i executed the nativetest, it is showing the following error
java -Djava.library.path=. nativetest
Exception in thread "main" java.lang.UnsatisfiedLinkError: no nativetest in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1860)
at java.lang.Runtime.loadLibrary0(Runtime.java:845)
at java.lang.System.loadLibrary(System.java:1084)
at nativetest.(nativetest.java:4)
Thanx in advance....
On Linux, a shared library's file name should start with "lib", that is, "lib[library_name].so".
Reference: 3.1.1. Shared Library Names
Every shared library has a special name called the ``soname''. The soname has the prefix ``lib'', the name of the library, the phrase ``.so'', followed by a period and a version number that is incremented whenever the interface changes (as a special exception, the lowest-level C libraries don't start with ``lib''). A fully-qualified soname includes as a prefix the directory it's in; on a working system a fully-qualified soname is simply a symbolic link to the shared library's ``real name''.
I want to create a simple JNI layer. I used Visual studio 2008 to create a dll (Win 32 Console Application project type with DLL as the option). Im getting this exception when I invoke the native method:
Exception occurred during event dispatching:
java.lang.UnsatisfiedLinkError: com.tpd.vcdba.console.TaskScheduler.vcdbaTaskSch
edulerNative.Hello()V
at com.tpd.vcdba.console.TaskScheduler.vcdbaTaskSchedulerNative.Hello(Na
tive Method)
at com.tpd.vcdba.console.TaskScheduler.vcdbaTaskSchedulerUtil.isTaskExis
ts(vcdbaTaskSchedulerUtil.java:118)
at com.tpd.vcdba.console.Dialogs.schedulerWizardPage.scheduleTaskPage.wz
Finish(scheduleTaskPage.java:969)
at com.tpd.vcdba.console.wizard.vcdbaWizard.gotoFinish(vcdbaWizard.java:
434)
at com.tpd.vcdba.console.wizard.wzActionPanel.actionPerformed(wzActionPa
nel.java:163)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
The header file generated is :
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_tpd_vcdba_console_TaskScheduler_vcdbaTaskSchedulerNative */
#ifndef _Included_com_tpd_vcdba_console_TaskScheduler_
vcdbaTaskSchedulerNative
#define _Included_com_tpd_vcdba_console_TaskScheduler_
vcdbaTaskSchedulerNative
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_tpd_vcdba_console_TaskScheduler_vcdbaTaskSchedulerNative
* Method: Hello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_tpd_vcdba_console_TaskScheduler_vcdbaTaskSchedulerNative_Hello
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
The implementation file is:
#pragma once
#include "com_tpd_vcdba_console_TaskScheduler_
vcdbaTaskSchedulerNative.h"
#include "stdafx.h"
#include "jni.h"
/*
* Class: com_tpd_vcdba_console_TaskScheduler_vcdbaTaskScheduler_native
* Method: Hello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_tpd_vcdba_console_TaskScheduler_vcdbaTaskSchedulerNative_Hello
(JNIEnv *envs, jobject obj){
printf("hello world");
}
The java file is:
package com.tpd.vcdba.console.TaskScheduler;
import com.tpd.vcdba.console.TaskScheduler.ScheduleTask;
public class vcdbaTaskSchedulerNative {
public native void Hello();
private static vcdbaTaskSchedulerNative instance = null;
static{
try{
System.loadLibrary("JNITrial");
}
catch(Exception ex){
}
}
public vcdbaTaskSchedulerNative(){
}
public static vcdbaTaskSchedulerNative getInstance(){
if(instance == null){
instance = new vcdbaTaskSchedulerNative();
}
return instance;
}
}
When I invoke the native method "Hello" i get the execption.
Another thing I observed is that when I compile in command line using:
“cl -I"C:\Program Files (x86)\Java\jdk1.7.0\include" -I"C:\Program Files (x86)\Java\jdk1.7.0\include\win32" -LD "C:\Users\administrator.RMDOM\Documents\Visual Studio 2008\Projects\JNITrial\JNITrial\JNIInt.cpp" -FeJNITrial.dll” ,
everything works fine.
Am I missing out something in Visual Studio Settings? I have option Use of MFC as "Use MFC in a Shared DLL", Code generation option as "Multi-threaded DLL (/MD)". Its a 64 bit dll.
Is there something else that I need to add?
Any help is welcome.
Thanks in advance.
Could you tell me what kind of JVM are you using, 32 or 64-bit? Your library is 640bit dll, but in your path I can see C:\Program Files (x86)... so maybe this is the problem.
I figured out the solution.
My project had use precompiled headers option set, so the compiler was skipping the statement:
#include "com_tpd_vcdba_console_TaskScheduler_vcdbaTaskSchedulerNative.h"
Once I removed that option it worked like magic.