Java + JNA : The specified procedure could not be found - java

I'm trying to create a dll file using visual studio and use/access it in a java project. The library seems to get loaded, but always the same exception is thrown:
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'function': The specified procedure could not be found.
My C/C++ skills ar not the best so the problem could be there. I tried to edit h and cpp files, using classes, namespaces, static methods and other staff found on the web, but nothing to do.
I have also seen other post talking about Depency Walker Tool, but it isn't able to open my dll, i also saw that the compiler add some strange suffixes to the function name, as i understood it's possible to avoid it by using "estern 'C'" in the h or cpp file, but i wasn't able.
My interface:
import com.sun.jna.Library;
import com.sun.jna.Native;
public interface SimpleDll extends Library {
SimpleDll instance = (SimpleDll) Native.loadLibrary("SimpleDll", SimpleDll.class);
void function();
}
My Main class:
public class Test_Dll {
public static void main(String[] args) {
SimpleDll simpleDll = SimpleDll.instance;
simpleDll.function();
}
}
My h file:
#ifndef SIMPLEDLL
#define SIMPLEDLL
namespace simpeDll{
static void function();
}
#endif
My cpp file:
#include "stdafx.h"
#include "simpleDll.h"
#include <stdexcept>
using namespace simpeDll;
static void function(){
}

Make sure declaring your function outside the simpleDll namespace.
Make sure to decorate it w/ extern "C"
Make sure exposing your function __declspec(dllexport) void __cdecl function(); or use module definition file

Related

Injecting class into the JNIEnv in android jni

C++ code:
extern "C" JNIEXPORT void JNICALL
Java_com_example_afl_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
// env->DefineClass(...)
}
I'm calling the above function from Java side code:
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("native-lib");
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
stringFromJNI(); // call cpp function
}
public native String stringFromJNI();
}
My question is about the env->DefineClass(...) in cpp code.
As you see the android VM passes JNIEnv *env to my native function, so by using env pointer i have access to all of my java classes and i can use them (i have access to all of my java side classes and i can create instance object and do everything).
But how can access to a class which is in another apk and it is in another package name ?
I wanna decompile the target apk and copy that class and inject that class to my env using the env->DefineClass function but i don't know how can i complete this task.
Thanks for any reply :)
Impossible. Android does not implement DefineClass:
All JNI 1.6 features are supported, with the following exception:
DefineClass is not implemented. Android does not use Java bytecodes or class files, so passing in binary class data doesn't work.
Even if that worked, your app's user very probably does not have access rights to another applications .apk.

JNI: dealing with a complicated C++ class

I have a 3rd party Win32 dll, written in C++, which I need to load in my eclipse java project and call some methods from it. What is problematic - all the classes which I really need from this dll have virtual functions. I've created a dummy C++ project, which received all the stuff via static linking and via my self-defined C++ class. Everything is working in my C++ world. Now I want to load my dummy dll (which in turn loads all other stuff I need) in my java project. The code in cpp world looks like this (I've mixed up .h and .cpp for simplicity):
class Dummy : public VirtualClassFromLib
{
public:
//...
//some standard stuff here
//...
void method1()
{
VirtualClassFromLib::function1();
}
void method2()
{
//a header is loaded with #include
AdditionalStructureFromHeader object;
VirtualClassFromLib::function2(object);
}
void virtual_function()
{
std::cout << "Cool, now you are not virtual";
}
//...
}
where function1 and function2 are not virtual in the base class and virtual_function is.
I'm a newbie in JNI and as far as I understood, I should write a "mirror" class with the same method's and other stuff's names in my java project. Question: how to deal with this VirtualClassFromLib? Like, this VirtualClassFromLib has a very complicated structure with a wide usage of self-defined structures in the original dll. Or don't I need to "mirror" that completely to java project? I don't get it from examples and tutorials in the Internet.

How to implement Java Interface methods in C

Let's take the following code
public class SomeClass {
public OtherClass method(final String param1,final String param2){
AnotherClass obj1 = AnotherClass.getInstance();
return obj.instanceMethod(new YetAnotherClass<OtherClass>() {
#Override
public OtherClass run() {
return OtherClass.get(param1, param2);
}
});
}
}
My question is there any way that I can implement the interface in C/C++ through JNI, without creating a native method in Java?
One option is the Java Native Access (JNA) library. Have a look at its project page at JNA. I quote from its project site:
JNA provides Java programs easy access to native shared libraries without writing anything but Java code - no JNI or native code is required. This functionality is comparable to Windows' Platform/Invoke and Python's ctypes.
The following example from the project's toturial page demonstrates how it is used to call the printf function from the native library that the function is defined in:
package com.sun.jna.examples;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
/** Simple example of JNA interface mapping and usage. */
public class HelloWorld {
// This is the standard, stable way of mapping, which supports extensive
// customization and mapping of Java to native types.
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary)
Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"),
CLibrary.class);
void printf(String format, Object... args);
}
public static void main(String[] args) {
CLibrary.INSTANCE.printf("Hello, World\n");
for (int i=0;i < args.length;i++) {
CLibrary.INSTANCE.printf("Argument %d: %s\n", i, args[i]);
}
}
}
On Windows, the printf function is defined in the msvcrt.dll and the sample loads that DLL and calls the function from it.
The JNA project is mature and according to its web page, it has some very famous users.
It should be pointed out that JNA itself uses the JNI under the hood but in most cases, you do not need to use JNI yourself. Therefore, you can focus on implementing your native code in C (create your own DLL or Shared Library files) and then load them in Java with JNA.

SWIG: using imported external type

I am trying to wrap some libraries written in C++ to interface with JAVA using SWIG.
I have one C++ struct in one library used in one C++ function of another library as an argument.
common.h
namespace rina {
namespace cdap_rib {
typedef struct{
int size_;
void* message_;
} ser_obj_t;
}
}
This library is wrapped producing a class called eu.irati.librina.ser_obj_t in JAVA. That's fine. Then I have
utilities.h
class IPCPConfigEncoder {
public:
void encode (rina::cdap_rib::ser_obj_t& ser_obj);
}
which is wraped with SWIG producing
public void encode(SWIGTYPE_p_rina__cdap_rib__ser_obj_t ser_obj) {
...
}
in a JAVA class. Looking around in I found (SWIG Importing generated class from a different module and package into the current class) and I added to .i
%typemap(javaimports) SWIGTYPE
%{
import eu.irati.librina.ser_obj_t;
%}
which produced
import eu.irati.librina.ser_obj_t;
public void encode(SWIGTYPE_p_rina__cdap_rib__ser_obj_t ser_obj) {
...
}
Then, I have a couple of questions
The import is added to all the java classes... how can I enclose it only to the desired class?
How can I tell SWIG to change SWIGTYPE_p_rina__cdap_rib__ser_obj_t for eu.irati.librina.ser_obj_t.
Note: Since common.h and utilities.h are in different libraries I can not put them together in the same swig module.
As #Felxo pointed in the coments, the only solution is to tell swig to understand also the other libraries interface wraping (so headers and how are they wrapped).
What I did:
I copied common.i into utilities wrapping folder.
I added into utilities.i
/* this is the "copied" common.i */
%import "common.i"
%pragma(java) jniclassimports=%{
import eu.irati.librina.ser_obj_t;
%}
to add the import of the proxy class (you should change thais to point to your proxy class from a java path)
Remove from the copied common.i the unecessary instructions like %template, remember that, at this point, you are only "importing" the common.h, not wrapping it (you already wraped it before). Actually, the common.i should only include:
%{
#include "common.h"
}%
but no
%include "common.h"
Tell SWIG where are is the common.h as well as where is the utilities.husing the -I option

Dynamic Link Library & Java

I made a dll in C++ and wrote this class in java:
public class VolumeControl {
public native float GetVolume();
public native void SetVolume(float val);
public native void VolumeUp();
public native void VolumeDown();
public native void Mute();
static {
System.load("some_path/VolumeControl.dll");
}
}
it works good, if I call functions from this file, but when I'm trying to do this:
public class Server {
public static void main(String[] args) {
VolumeControl ctrl = new VolumeControl();
ctrl.Mute();
}
}
I get this:
Exception in thread "main" java.lang.UnsatisfiedLinkError:
RemoteControl.VolumeControl.Mute()V
Both classes are in the same package, of course. How can I solve it? Thanks.
Update1: OK the problem was, that I added these classes to package. When I move them to default package, everything works good. But now if I want to use this dll with different packages, I need to rebuild it.
Update2: Actually I can't add it to package at all, when I'm trying: #javah VolumeControl, I get Error:
Could not find class file for 'VolumeControl'.
Update3: I added manually name of package to C++ functions and it works. Thanks.
The use of javah utility may help if integrated into a makefile to ensure the interface is always assumed on both side (client/server).

Categories

Resources