This question already has answers here:
Calling C# method within a Java program
(2 answers)
Closed 7 years ago.
I need to call C# function from java and to this I have created the following.
I have a create a java header file Authenticator.h , here is the code:
#include <jni.h>
/* Header for class Authenticator */
#ifndef _Included_Authenticator
#define _Included_Authenticator
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Authenticator
* Method: authenticate
* Signature: (Ljava/lang/String;Ljava/lang/String;)Z
*/
JNIEXPORT jboolean JNICALL Java_Authenticator_authenticate
(JNIEnv *, jobject, jstring, jstring);
#ifdef __cplusplus
}
#endif
#endif
I have then create a C# function that Authenticate
namespace SharpAuthenticator
{
public class Authenticator
{
public bool Authenticate(String username,String password)
{
return username == "user" && password == "login";
}
}
}
Then I am trying to call the C# function from C++(project to create a dll) using the code below;
String^ toString(const char *str)
{
int len = (int)strlen(str);
array<unsigned char>^ a = gcnew array<unsigned char>(len);
int i = 0;
while (i < len)
{
a[i] = str[i];
i++;
}
return Encoding::UTF8->GetString(a);
}
bool authenticate(const char *username, const char *password)
{
SharpAuthenticator::Authenticator::Authenticate(toString(username), toString(password));
}
JNIEXPORT jboolean JNICALL Java_Authenticator_authenticate
(JNIEnv *env, jobject c, jstring name, jstring pass)
{
jboolean result;
jboolean isCopyUsername;
const char * username = env->GetStringUTFChars(name, &isCopyUsername);
jboolean isCopypassword;
const char * password = env->GetStringUTFChars(pass, &isCopypassword);
result = authenticate(username, password);
env->ReleaseStringUTFChars(name, username);
env->ReleaseStringUTFChars(pass, password);
return result;
}
And finnally create a dll that i need to call from java. The dll is created and I load it well in java but I get this error log in java. What could I be Missing.
#
# A fatal error has been detected by the Java Runtime Environment:
#
# Internal Error (0xe0434352), pid=9708, tid=7756
#
# JRE version: 7.0-b147
# Java VM: Java HotSpot(TM) Client VM (21.0-b17 mixed mode, sharing windows-x86 )
# Problematic frame:
# C [KERNELBASE.dll+0x812f]
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
First of all lets create a C# file like this:
using System;
public class Test{
public Test(){}
public String ping(){
return "C# is here.";
}
}
Then compile this with command below:
csc.exe /target:module Test.cs
You can find csc.exe in install path of .NET framework. After that create java file:
public class Test{
public native String ping();
public static void main(String[] args){
System.load("/path/to/dll");
System.out.println("Java is running.");
Test t = new Test();
System.out.println("Trying to catch C# " + r.ping());
}
}
javac Test.java This generates a Test.class.
javah -jni Test This generates a Test.h file which will be included in
C++ code.
After that we need to create our C++ file:
#include "stdafx.h"
#include "JAVA/Test.h"
#include "MCPP/Test.h"
#pragma once
#using <mscorlib.dll>
#using "Test.netmodule"
JNIEXPORT jstring JNICALL Java_Test_ping(JNIEnv *env, jobject obj){
Test^ t = gcnew Test();
String^ ping = t->ping();
char* str = static_cast<char*>((System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(ping)).ToPointer());
char cap[128];
strcpy_s(cap, str);
return env->NewStringUTF(cap);
}
Finally:
c:\>java Test
I hope this helps you. A basic example to use function C# in Java.
Sources:
https://www.quora.com/How-common-is-the-problem-of-calling-C-methods-from-Java-Do-many-developers-come-across-such-necessity
Related
I want to make a login authentication to my web application(Java). Username and password are created in windows server 2016 active directory. Using that username and password I have to login to my web app using ADSI(Active Directory Service Interface) API in C++ language to connect to the windows server. To do this I have to create the .dll file from the C++ code in Visual Studio 2022. Here I have to add Activeds.lib, adsiid.lib to make the API work. After generating the .dll file to load this in Java System.load() using JNI Concept.
This is the C++ code I used in Visual Studio 2022...
#include <iostream>
#include <jni.h>
#include<string.h>
#include "com_library_ldap_JNIHelper.h"
#include <Iads.h>
#include <adshlp.h>
#include "activeds.h"
#include <windows.h>
#include <stdlib.h>
using namespace std;
JNIEXPORT jstring JNICALL Java_com_library_ldap_JNIHelper_authenticateUser
(JNIEnv* env, jclass, jstring uname, jstring pwd) {
const char* uName = env->GetStringUTFChars(uname, NULL);
std::string username = std::string(uName);
const char* pwd1 = env->GetStringUTFChars(pwd, NULL);
std::string password = std::string(pwd1);
env->ReleaseStringUTFChars(uname, uName);
env->ReleaseStringUTFChars(pwd, pwd1);
IADs* pObject;
wchar_t wname[20];
mbstowcs(wname, username.c_str(), username.length());
LPWSTR szUsername = wname;
wchar_t wpwd[20];
mbstowcs(wpwd, password.c_str(), password.length());
LPWSTR szPassword = wpwd;
HRESULT hr;
string uAdmin = "Admin";
string uUser = "User";
string uType;
bool res = false;
if (uAdmin == "Admin") {
hr = ADsOpenObject(L"LDAP://test.local/CN=Users,DC=test,DC=local",
szUsername,
szPassword,
ADS_SECURE_AUTHENTICATION,
IID_IADs,
(void**)&pObject);
if (SUCCEEDED(hr))
{
// Use the object.
res = true;
// Release the object.
pObject->Release();
}
if (res == true) {
uType = "Admin";
//return env->NewStringUTF(uType.c_str());
}
else
uType = "NotFound!!!";
}
else if (uUser == "User") {
hr = ADsOpenObject(L"LDAP://test.local /CN=Vimaluser,OU=Users,OU=Vimal,DC=test,DC=local",
szUsername,
szPassword,
ADS_SECURE_AUTHENTICATION,
IID_IADs,
(void**)&pObject);
if (SUCCEEDED(hr))
{
// Use the object.
res = true;
// Release the object.
pObject->Release();
}
if (res == true) {
uType = "User";
}
else {
uType = "NotFound!!!";
}
}
return env->NewStringUTF(uType.c_str());
}
below is the error I'm getting...
Build started...
1>------ Build started: Project: Adsi-JNI, Configuration: Release x64 ------
1>Adsi-JNI.cpp
1> Creating library C:\Users\Vimal\Desktop\VS Code\Adsi-JNI\x64\Release\Adsi-JNI.lib and object C:\Users\Vimal\Desktop\VS Code\Adsi-JNI\x64\Release\Adsi-JNI.exp
1>Adsi-JNI.obj : error LNK2019: unresolved external symbol ADsOpenObject referenced in function Java_com_library_ldap_JNIHelper_authenticateUser
1>Adsi-JNI.obj : error LNK2001: unresolved external symbol IID_IADs
1>E:\Java Program\Library System\src\main\java\com\library\ldap\lib\ActiveDS.lib : warning LNK4272: library machine type 'x86' conflicts with target machine type 'x64'
1>E:\Java Program\Library System\src\main\java\com\library\ldap\lib\adsiid.lib : warning LNK4272: library machine type 'x86' conflicts with target machine type 'x64'
1>C:\Users\Vimal\Desktop\VS Code\Adsi-JNI\x64\Release\Adsi-JNI.dll : fatal error LNK1120: 2 unresolved externals
1>Done building project "Adsi-JNI.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
And I wrote a code for server connection, but i don't know whether the code is correct for server connection or not. Please help me to solve this problem and also share what are all the things related to this. Thanks in advance.
I have a directory structure like this
.
--compile_c.sh
--compile_java.sh
--config.sh
--execute_java.sh
--run.sh
--src
--ccode
--jnitest_SimpleJNITest.h
--rtm_simple.c
--jnitest
--SimpleJNITest.java
--lib
--rtm_simple.so
--classes
--SimpleJNITest.class
How do I correctly run SimpleJNITest when it has a native method that is fleshed out in rtm_simple.c?
Currently, I have defined
config.sh
targetDir="classes"
libDir="lib"
srcDir="src"
MainPackage="jnitest"
Main="SimpleJNITest"
ccodeDir="ccode"
cFileName="rtm_simple"
jdkDir="/home/user/local/java/jdk1.7.0_65"
mkdir -p "$targetDir"
mkdir -p "$libDir"
and am trying to run
run.sh
#!/bin/bash
source compile_java.sh
javah -d "${srcDir}/${ccodeDir}" -cp "$targetDir" -jni "${MainPackage}.${Main}"
source compile_c.sh
source execute_java.sh
where
compile_java.sh
#!/bin/bash
source config.sh
javac -d "$targetDir" -sourcepath "$srcDir" -cp "${targetDir}:${libDir}/*" "${srcDir}/${MainPackage}/${Main}.java"
compile_c.sh
#!/bin/bash
source config.sh
cFile="${srcDir}/${ccodeDir}/${cFileName}.c"
soFile="${libDir}/${cFileName}.so"
gcc -g -shared -fpic -I "${jdkDir}/include" -I "${jdkDir}/include/linux" $cFile -o $soFile
execute_java.sh
#!/bin/bash
source config.sh
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libDir}"
java -cp "${targetDir}:${libDir}/*" "${MainPackage}.${Main}"
(also tried java -Djava.library.path="$LD_LIBRARY_PATH:$libDir" -cp "${targetDir}:${libDir}/*" "${MainPackage}.${Main}")
output
$ ./run.sh
Exception in thread "main" java.lang.UnsatisfiedLinkError: no rtm_simple in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
at java.lang.System.loadLibrary(System.java:1122)
at jnitest.SimpleJNITest.main(SimpleJNITest.java:17)
Code:
SimpleJNITest.java
package jnitest;
public class SimpleJNITest{
public static final int NOF_ITERATIONS = 100000;
public native int nofAborts(int nofTransactions);
public void test(){
int nofAborts = nofAborts(NOF_ITERATIONS);
System.out.println(String.format("successfully completed %d transactions and had to retry %d times",nofAborts));
}
public static void main(String[] args) {
System.loadLibrary("rtm_simple");
new SimpleJNITest().test();
}
}
(also tried using System.loadLibary("rtm_simple.so");)
jnitest_SimpleJNITest.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class jnitest_SimpleJNITest */
#ifndef _Included_jnitest_SimpleJNITest
#define _Included_jnitest_SimpleJNITest
#ifdef __cplusplus
extern "C" {
#endif
#undef jnitest_SimpleJNITest_NOF_ITERATIONS
#define jnitest_SimpleJNITest_NOF_ITERATIONS 100000L
/*
* Class: jnitest_SimpleJNITest
* Method: nofAborts
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_jnitest_SimpleJNITest_nofAborts
(JNIEnv *, jobject, jint);
#ifdef __cplusplus
}
#endif
#endif
rtm_simple.c
#include <jni.h>
#include "jnitest_SimpleJNITest.h"
JNIEXPORT jint JNICALL
Java_jnitest_SimpleJNITest_nofAborts(JNIEnv* env, jobject obj, jint nof_iterations){
volatile int abort_counter = 0;
volatile int i = 0;
while (i < nof_iterations) {
__asm__ __volatile__ (
"xbegin 1f" /*1f: local label 1, look forward to find first*/
:"+rm"(i) /*artificial dependency to prevent re-ordering*/
);
++i;
__asm__ __volatile__ (
"xend\n\t"
"jmp 2f\n" /*not aborted ==> jump to local label 2*/
"1:\n\t" /*local label 1 (jumped to when transaction is aborted)*/
:"+rm"(abort_counter) /*artificial dependency*/
:"rm"(i) /*artificial dependency*/
);
++abort_counter;
__asm__ __volatile__ (
"2:" /*local label 2 (jumped to when transactoin is NOt aborted)*/
:"+rm"(abort_counter) /*artificial dependency*/
:"rm"(i) /*artificial dependency*/
);
}
if(i != nof_iterations) return -1;
return abort_counter;
}
If you want to specify a file name, you need to use System.load(String), and not the System.loadLibrary(String) method. loadLibrary transforms the specified name in a platform-dependent manner. On your system, a lib prefix and .so suffix is probably added, but this means no matter how you call loadLibrary, it won't be able to load a file called rtm_simple.so even if it is located on the library search path. Or put differently, if you do want to use loadLibrary, you need to rename the file to librtm_simple.so.
You can see the paths the JVM uses if you run it under strace -fF.
Suggest you put your System.loadLibrary() in a static block in the SimpleJNITest class. You might need to be more explicit with the creation of the SimpleJNITest object in main.
public class SimpleJNITest{
public static final int NOF_ITERATIONS = 100000;
static {
System.loadLibrary("rtm_simple");
}
<blah blah blah>
public static void main(String[] args) {
SimpleJNITest simple = new SimpleJNITest();
simple.text();
}
}
I'm trying to do the following :
Run Java app on Android
Call native C++ code from that Java app
Create and run a native thread from that natice code
return immediatly while the thread keeps running
Call a java method from native code once the thread is finished
Here is my code :
#include <jni.h>
#include <pthread.h>
#include <unistd.h> /* sleep() */
#include <stdio.h>
#ifdef __cplusplus
extern "C"
{
#endif
JNIEXPORT jstring JNICALL Java_xxx_asynctasktest_MainActivity_runAsyncTask( JNIEnv * env, jobject that, jstring oDummyStr );
#ifdef __cplusplus
}
#endif
JavaVM * g_jvm;
jobject g_obj;
jmethodID g_mid;
void * threadProc( void * pArg )
{
JNIEnv * env = 0;
int res = g_jvm->AttachCurrentThread( & env, NULL );
sleep( 3 );
jobject oStr = (jobject)pArg;
env->CallObjectMethod( g_obj, g_mid, oStr );
env->DeleteGlobalRef( oStr );
env->DeleteGlobalRef( g_obj );
g_jvm->DetachCurrentThread();
return 0;
}
JNIEXPORT jstring JNICALL Java_xxx_asynctasktest_MainActivity_runAsyncTask( JNIEnv * env, jobject that, jstring oDummyStr )
{
env->GetJavaVM( & g_jvm );
g_obj = env->NewGlobalRef( that );
g_mid = env->GetMethodID( env->GetObjectClass( that ), "onTaskFinished", "(Ljava/lang/String;)Ljava/lang/String;" );
if( g_mid == NULL )
{
fprintf( stderr, "No such method" );
}
else
{
pthread_t thread = 0;
pthread_create( & thread, NULL, threadProc, (void *)env->NewGlobalRef( oDummyStr ) );
}
return env->NewStringUTF( "lolol" );
}
My problem is that when i call env->CallObjectMethod( g_obj, g_mid, oStr ); eclipse tries to open Handler.class in the class file editor and says not found and the thread doesn't call the Java method.
What am I doing wrong ? Thank you.
EDIT : Forgot to mention that my Java callback creates a dialog as follows :
AlertDialog.Builder dlgAlert = new AlertDialog.Builder( this );
dlgAlert.setMessage( msgBoxText );
dlgAlert.setTitle( "" );
dlgAlert.setPositiveButton( "OK", null );
dlgAlert.setCancelable( true );
dlgAlert.create().show();
And i'm having a runtime exception somewhere in "Handler" at line 121, source file not available.
EDIT : I'm actually reaching the Java callback, but it crashes when i start creating my dialog.
I needed a Java application to call unmanaged C++. I copied MSVCR90.dll manually from Visual Studio 2008 redist path to the vmware's Windows Server Datacenter.
This is the error I get:
A fatal error has been detected by the Java Runtime Environment:
EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x73b4ae7a, pid=1108, tid=2272
JRE version: 6.0_38-b05
Java VM: Java HotSpot(TM) Client VM (20.13-b02 mixed mode, sharing windows-x86 )
Problematic frame:
C [MSVCR90.dll+0x3ae7a]
An error report file with more information is saved as:
...\hs_err_pid1108.log
If you would like to submit a bug report, please visit:
http://java.sun.com/webapps/bugreport/crash.jsp
The crash happened outside the Java Virtual Machine in native code.
See problematic frame for where to report the bug.
This is the C++ code:
#include "stdafx.h"
#include <stdio.h>
#include "CCCheckString.h"
#include <vector>
#include <String>
using namespace std;
#include "jobHandler.h"
JNIEXPORT jbolean JNICALL Java_CCCheckString_Login
(JNIEnv *env, jobject object, jstring host, jstring UserName, jstring Domain, jstring Password)
{
bool result;
jobHandler *handler = new jobHandler();
const char *hostStr = (env)->GetStringUTFChars(host, NULL);
string hostS(hostStr);
const char *UserNameStr = (env)->GetStringUTFChars(UserName, NULL);
string UserNameS(UserNameStr);
const char *DomainStr = (env)->GetStringUTFChars(Domain, NULL);
string DomainS(DomainStr);
const char *PasswordStr = (env)->GetStringUTFChars(Password, NULL);
string PasswordS(PasswordStr);
//if comment this line everthing is okey
**result = handler->Login(hostS,UserNameS,DomainS,PasswordS);**
(env)->ReleaseStringUTFChars(host, NULL);
(env)->ReleaseStringUTFChars(UserName, NULL);
(env)->ReleaseStringUTFChars(Domain, NULL);
(env)->ReleaseStringUTFChars(Password, NULL);
delete handler;
return result;
}
Below is the processing code in Java:
CCCheckString ccCheckString = new CCCheckString();
result=ccCheckString.Login("xxx", "xxx", "xx", "xxx");
How can i fix the error?
I solved.
Problem is that Login() accepts std::string but we cannot send it
We reorganize our Login() and it must take const char []
Ex:
bool ClassName::Login(std::string host,std::string userName,std::string userDomain,std::string userPassword)
{ //Orginal Code Here ....}
bool ClassName::Login(const char host[],const char userName[],const char userDomain[],const char userPassword[])
{
std::string strHost(host);
std::string strUserName(userName);
std::string strUserDomain(userDomain);
std::string strUserPassword(userPassword);
return Login(strHost,strUserName,strUserDomain,strUserPassword);
}
Everything is fine.
Recently I'm learning JNI to execute C code. Of course I did basic examples that were on the web. Now Im trying to load a C library that makes dynamic library loading (dlopen). But Im fighthing with an error. Im posting my Java code, C ++ code and the error.
My Java Class
/**
*
* #author glassfish
*/
public class MediationJniWeb {
public String library ;
static {
System.loadLibrary("-core-web");
}
/**
*
* #param library name of mediation core library [32]
* #param method name of method to be executed [128]
* #param parameters parameters of method [10240]
* [partype1,value1,...,valuen]...[partypen,value1,..,valuen]
* #return
*/
private native String execute();
public static void main(String args[]) {
//new MediationJniWeb().callToFunction(null, null, null) ;
MediationJniWeb jniWeb = new MediationJniWeb();
jniWeb.library = "libtest.so" ;
System.out.println(jniWeb.execute());
}
}
I generate .class file with
javac MediationJniWeb
and I generate .h File with
javah -jni MediationJniWeb
my MediationJniWeb.h file is
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class MediationJniWeb */
#ifndef _Included_MediationJniWeb
#define _Included_MediationJniWeb
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: MediationJniWeb
* Method: execute
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_MediationJniWeb_execute
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
and my MediationJniWEb.cpp file
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include <dlfcn.h>
#include <iostream>
#include "MediationJniWeb.h"
using namespace std ;
typedef void (*test)(string);
/*
* Class: MediationJniWeb
* Method: execute
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_MediationJniWeb_execute
(JNIEnv * env, jobject obj){
const char * str_library ;
jfieldID fid_library ;
jstring jstr_library ;
jboolean isCopy ;
jclass cls = env->GetObjectClass( obj) ;
fid_library = env->GetFieldID( cls,"library", "Ljava/lang/String;");
jstr_library = ( jstring )env->GetObjectField( obj,fid_library);
str_library = env->GetStringUTFChars( jstr_library, &isCopy) ;
void* handle = dlopen(str_library, RTLD_NOW); // open libtest.so
if ( 0 == handle ) {
cout << "failed to load 'libtest.so'. " << dlerror () <<endl;
exit(1);
}
test t = (test)dlsym(handle, "_Z8testfuncSs"); // run default method
if ( 0 == t ) {
cout << "failed to load 'testfunc()'." << endl;
exit(1);
}
t("Hello, World!");
dlclose(handle);
/*
*/
return env->NewStringUTF( str_library); // I just return library name just for fun
}
}
I compile with
g++ -shared -fpic -I//include/ -I//include/linux/ MediationJniWeb.cpp -o lib-core-web.so MediationJniWeb.cpp -ldl
this generate lib-core-web.so file. Then I copy this to $HOME/lib and I configure
LD_LIBRARY_PATH=$HOME/lib
Now I create my library libtest.so that is going to be executed by lib-core-web.so
I create file for shared libray mylib.cpp
#include <iostream>
#include <string>
using namespace std;
void testfunc(string s)
{
cout << s << endl;
}
I compile this that is going to work as a shared library with
g++ -shared -fpic -o libtest.so mylib.cpp
This command generates libtest.so file.. and also, I copy it to $HOME/lib
That's all I do to call from JNI to a C++ library to load a dynamic library.
when I execute MediationJniWeb java class I'm having this error
failed to load. libtest.so: cannot open shared object file: No such
file or directory
What do I have to do with libtest.so ?? where do I have to put it ?
I have on mind that configuring only LD_LIBRARY_PATH variable with right path, JVM should know where to find all needed libraries to be loaded.
Please help with your comments and let me know where my mistakes are.
Thanks in advance !
A simple thing I have done
instead of
jniWeb.library = "libtest.so"
library parameter to be loaded I declared
jniWeb.library = "/home/myuser/lib/libtest.so"
And it worked !