I have some Java model on the server but in my iOS app I'm using JSON without a serializator because my server hasn't an Objective-C model generator.
Is it possible to integrate Java model class in Objective-C?
How?
Yes you definitely can but you will see you are much better off "translating".
These are the step by step instructions (source: http://hints.macworld.com/article.php?story=20040321163154226).
Create a new Foundation project called "HelloBridge"
Create a new Pure Java Package target called "JavaClasses"
Create a new Java class called "HelloBridge.java" an add it to target
"JavaClasses":
public class HelloBridge {
private String string = "Hello";
public void setString(String string) {
this.string = string;
}
public String getString() {
return this.string;
}
public void printString() {
System.out.println(this.string);
}
}
Add "HelloBridge.java" to the "Sources" build phase in target
"JavaClasses"
Create a new empty file called "JavaInterfaces.h" and add it to
target "HelloBridge":
// Provide Objective-C interfaces for the Java classes
// Not only good practice, it provides Code Sense
#interface java_util_Vector : NSObject
{}
- (void)add:(id)anObject;
- (id)get:(int)index;
#end
#interface HelloBridge : NSObject
{}
- (void)setString:(NSString *)string;
- (NSString *)getString;
- (void)printString;
#end
Modify "main.m":
#import <Foundation/Foundation.h>
#import "JavaInterfaces.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// Load the Java VM
id vm = NSJavaSetupVirtualMachine();
// Start the Java class loader
NSJavaClassesFromPath(nil, nil, YES, &vm);
// Load a new instance of the java.util.Vector Java class into an Objective-C pointer
java_util_Vector * vector = NSJavaObjectNamedInPath(#"java.util.Vector", nil);
[vector add:#"one item!"];
NSLog(#"item 1=%#",[vector get:0]);
[vector release];
// Load a new instance of our custom HelloBridge Java class into an Objective-C pointer
HelloBridge * hello = NSJavaObjectNamedInPath(#"HelloBridge", nil);
NSLog(#"item 1=%#",[hello getString]);
[hello setString:#"Test"];
NSLog(#"item 1=%#",[hello getString]);
[hello printString];
[hello release];
[pool release];
return 0;
}
Select "JavaClasses" from the targets drop box and Build it
Select "HelloBridge" from the targets drop box and Build/Run it
Related
I need to reference a .Net dll in java. I have used jni4net libraries for the same. I have followed the steps mentioned in the video below :
https://www.youtube.com/watch?time_continue=351&v=8OoSK_RWUe4
I have followed all the steps required to reference jni4net libraries but i get the following runtime Exception:
Exception in thread "main" java.lang.UnsatisfiedLinkError: orionforpython.DynamicOrion.__ctorDynamicOrion0(Lnet/sf/jni4net/inj/IClrProxy;)V
at orionforpython.DynamicOrion.__ctorDynamicOrion0(Native Method)
at orionforpython.DynamicOrion.<init>(DynamicOrion.java:25)
at com.orion.OrionForJava.main(OrionForJava.java:16)
After following all the steps, This is my code:
package com.orion;
import net.sf.jni4net.Bridge;
import orionforpython.*;
import java.io.*;
class OrionForJava {
public static void main(String[] args) throws IOException {
Bridge.setVerbose(true);
Bridge.init();
File proxyAssemblyFile=new File("OrionForPython.dll");
Bridge.LoadAndRegisterAssemblyFrom(proxyAssemblyFile);
DynamicOrion orion=new DynamicOrion();
String res=orion.ReqLogin("user", "pwd", "");
System.out.print(res);
}}
I have tried executing the same using NetBeans 8.1 IDE but with no success. I am using jni4net-0.8.8.0 version and Eclipse IDE for Java Developers
Version: Oxygen.3 Release (4.7.3)
Any assistance would be helpful!
I used jni4net library to call c# dlls from java and it is working fine. I used a lightly different approach to initialize jni4net.
try {
Bridge.setVerbose(true);
Bridge.init(new File("Full path to jni4net.n.w64.v40-0.8.8.0.dll"));
// where dlls to load is jni4net.n.w64.v40-0.8.8.0.dll,jni4net.n-0.8.8.0.dll,MyOriginalNETDll.dll,MyOriginalNETDll.j4n.dll (after proxygen processing)
for (String str : dllsToLoad) {
File dll = new File(rutaDlls + str);
Bridge.LoadAndRegisterAssemblyFrom(dll);
}
} catch (IOException e) {
LOG.error("Error jniBrige.", e);
}
I needed to use full path c:... to the dll to make it work. I also had to take care about .net framework version used to create assembly (need to use 4.0 in my case and java version 8)
Hopes this helps
We use JCOBridge which can be used in .NET Core (>= 3.1), .NET 5/6 and .NET Framework (>= 4.6.1). Referencing the DLL you need to call you will have full access to it and you can use it in your projects.
Consider the following C# snippet class available in a generic TestBridge.dll:
using System;
namespace TestBridge
{
public class MyClass
{
/// <summary>The method <c>HelloWorld</c> return the "Hello World!!" string</summary>
public String HelloWorld()
{
return "Hello World from C#!!";
}
/// <summary>The method <c>Add</c> return the sum of two double</summary>
public double Add(double a, double b)
{
return a + b;
}
/// <summary>The method <c>Add</c> return the sin of a double</summary>
public double Sin(double a)
{
return Math.Sin(a);
}
}
}
The methods of the previous class can be invoked from the following java code snippet:
import java.io.IOException;
import org.mases.jcobridge.*;
public class CSharpClassUse {
public static void main(String[] args) {
try {
try {
try {
JCOBridge.Initialize();
} catch (JCException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
return;
}
//declare and create JCOBridge instance
JCOBridge bridge;
bridge = JCOBridge.CreateNew();
// adds the path where external assemblies can be found
bridge.AddPath("Path where is TestBridge.dll assembly");
// add REFERENCES to the .dll file you want to invoke
bridge.AddReference("TestBridge.dll");
// INSTANTIATE the .NET Object: JCObject is a meta object
JCObject theNetClassInstance = (JCObject) bridge.NewObject("TestBridge.MyClass");
double a = 2;
double b = 3;
double c = Math.PI/2;
//Invoke the C# class methods
String hello = (String) theNetClassInstance.Invoke("HelloWorld");
double result = (double) theNetClassInstance.Invoke("Add", a, b);
double sin = (double) theNetClassInstance.Invoke("Sin", c);
System.out.println(String.format("%s %.0f + %.0f = %.0f and sin(%.8f) = %.8f", hello, a, b, result, c, sin));
} catch (JCException jce) {
jce.printStackTrace();
System.out.println("Exiting");
return;
}
}
}
The previous java code produces the following output:
Hello World from C#!! 2 + 3 = 5 and sin(3,14159265) = 1,00000000
The previous example shown how use a C# class available in a DLL. If you need to invoke/integrate .NET graphic, that in generic sense are C# DLL too, JCOBridge also manages GUI integration (WPF/WinForms/AWT/Swing): look at these Examples
Hope it was useful and clear.
I am new to accessing DLLs from Java using JNA. I need to access methods from a class within a DLL(written in .net). Form this sample DLL below, I am trying to get AuditID and Server ID. I am ending with the following error while I am running my code. Any guidance really appreciated.
/// Error ///
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'GetEnrollcontext': The specified procedure could not be found.
//DLL File Code//
SampleDLL.ProfileEnroll enrollcontext = new SampleDLL.ProfileEnroll();
enrollcontext.Url =” url”;
enrollcontext.AuditIdType = SampleDLL.ProfileId;
enrollcontext.AuditId = “22222222 “;
enrollcontext.ServerId = “server1”;
/// Java Code ///
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Structure;
import dllExtract.DLLExtractTest.SampleDLL.Enrollcontext;
public class SampleDLLExtract {
public interface SampleDLL extends Library {
SampleDLL INSTANCE = (SampleDLL) Native.loadLibrary("SampleDLL",
SampleDLL.class);
public static class Enrollcontext extends Structure {
public String auditId;
public String serverId;
}
void GetEnrollcontext(Enrollcontext ec); // void ();
}
public static void main(String[] args) {
SampleDLL sdll = SampleDLL.INSTANCE;
SampleDLL.Enrollcontext enrollContext = new SampleDLL.Enrollcontext();
sdll.GetEnrollcontext(enrollContext);
System.out.println(sdll.toString(sdll.GetEnrollcontext(enrollContext)));
}
}
in fact there is a solution for you to use C#, VB.NET or F# code via JNA in Java (and nothing else)! and it is also very easy to use:
https://www.nuget.org/packages/UnmanagedExports
with this package all you need to do is, add [RGiesecke.DllExport.DllExport] to your methods like that:
C# .dll Project:
[RGiesecke.DllExport.DllExport]
public static String yourFunction(String yourParameter)
{
return "CSharp String";
}
Java Project:
public interface jna extends Library {
jna INSTANCE = (jna) Native.loadLibrary("yourCSharpProject.dll", jna.class);
public String yourFunction(String yourParameter);
}
use it in the code:
System.out.println(jna.INSTANCE.yourFunction("nothingImportant"));
Viola!
As already mentioned it works very easy, but this solution has some limitations:
only available for simple datatypes as parameter & return values
no MethodOverloading available. yourFunction(String yourParameter) and yourFunction(String yourParameter, String yourSecondParameter) does not work! you have to name them differently
Use arrays as parameter or return values. (JNA offers StringArray, but I am not able to use them in C#) (maybe there is a solution, but I couldn't come up with one so far!)
if you export a method you can't call it internally in your C# code (simple to bypass that by the following:
.
[RGiesecke.DllExport.DllExport]
public static Boolean externalAvailable(String yourParameter)
{
return yourInternalFunction(yourParameter);
}
With C# it works great, with VB.NET and F# I have no experience.
hope this helps!
The Info.plist of our Java-based application contains following entries:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<dict>
...
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>myApp handler</string>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>
...
</dict>
</plist>
It should handle an URL like myapp://foobar/bazz. Opening the application works fine, but how the application should obtain the clicked URL?
For Objective C the answer can be found here: When an OS X app is launched by a registered URL scheme, how do you access the full URL?
The solution for Java is to rewrite the ObjC code into plain C, then translate that into Java, with the help of a set of classes under org.eclipse.swt.internal.cocoa.*.
As a reference for the ObjC-to-C translation, we need Apple's Objective-C Runtime Reference.
Plain C version
First, let's translate
[[NSAppleEventManager sharedAppleEventManager]
setEventHandler:targetObject
andSelector:#selector(handleAppleEvent:withReplyEvent:)
forEventClass:kInternetEventClass
andEventID:kAEGetURL];
into plain C. To invoke a ObjC function in plain C, we use objc_msgSend(). Furthermore, #selector(method_footprint) is substituted by sel_registerName("method_footprint"), and classes are looked up with objc_getClass(). The types id and SEL are equivalent to a pointer (such as void*) or a full-size int (i.e. same size as a void*).
The result:
// id mgr = [NSAppleEventManager sharedAppleEventManager]
SEL sel_ sharedAppleEventManager = sel_registerName("sharedAppleEventManager");
id mgr = objc_msgSend (objc_getClass("NSAppleEventManager"), sharedAppleEventManager);
// and the rest
SEL sel_setEventHandler = sel_registerName("setEventHandler:andSelector:forEventClass:andEventID:");
SEL sel_handleAppleEvent = sel_registerName("handleAppleEvent:withReplyEvent:");
objc_msgSend (mgr, sel_setEventHandler, targetObject, sel_handleAppleEvent, kInternetEventClass, kAEGetURL);
As you can see, we have two subroutine invocations here: The first calls the sharedAppleEventManager message of the NSAppleEventManager class, retrieving a singleton object from that class. The second call is sending the setEventHandler... message to that object, passing 4 arguments (target object, target message, and two event specifiers).
The callback function's declaration, originally:
- (void)handleAppleEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
looks like this in plain C:
void handleAppleEvent (id self, SEL selector, NSAppleEventDescriptor* event, NSAppleEventDescriptor* replyEvent)
This means that when the function gets called, it gets sent not only its object reference (id) but also its method footprint (selector).
The callback code looks like this in ObjC to get to the URL:
NSString url = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
And in plain C:
id desc_id = objc_msgSend (event_id, sel_registerName("paramDescriptorForKeyword:"), '----');
id url_id = objc_msgSend (desc_id, desc_id, sel_registerName("stringValue"));
One part is still missing:
targetObject needs to be initialized before invoking the code above, and a method matching the handleAppleEvent:withReplyEvent: footprint needs to be created in that target object, and then linked to our plain C event handler (handleAppleEvent()).
This means that we have to create an Objective C class, add a method to it, and then create an object instance of it:
// create an NSObject subclass for our target object
char objcClassName[] = "ObjCAppleEventHandler";
id objcClass = objc_allocateClassPair (objc_getClass("NSObject"), objcClassName);
// add the callback method to the class
SEL sel_handleAppleEvent = sel_registerName("handleAppleEvent:withReplyEvent:");
class_addMethod (objcClass, sel_handleAppleEvent, handleAppleEvent, "i#:##");
// register the class
objc_registerClassPair (objcClass)
// create an object instance
id targetObject = class_createInstance (objcClass, 0);
// ... here follows the above code with the setEventHandler invocation
// (note: `SEL sel_handleAppleEvent` appears twice - the 2nd one can be removed)
This concludes the plain C version.
(Note: The above code was written without testing it, so it may contain errors. The Java code below, however, has been tested.)
Java version
Translation from Plain C to Java is now fairly straight-forward.
The aforementioned ObjC Runtime functions are all available from org.eclipse.swt.internal.cocoa.OS.
First, some presets:
static final long class_NSAppleEventManager = OS.objc_getClass("NSAppleEventManager");
static final long sel_sharedAppleEventManager = OS.sel_registerName("sharedAppleEventManager");
static final long sel_setEventHandler = OS.sel_registerName("setEventHandler:andSelector:forEventClass:andEventID:");
static final long sel_handleAppleEvent = OS.sel_registerName("handleAppleEvent:withReplyEvent:");
static final long sel_paramDescriptorForKeyword = OS.sel_registerName("paramDescriptorForKeyword:");
static final long sel_stringValue = OS.sel_registerName("stringValue");
static final long kInternetEventClass = 0x4755524C; // 'GURL'
static final long kAEGetURL = 0x4755524C; // 'GURL'
static final long kCoreEventClass = 0x61657674; // 'aevt'
static final long kAEOpenApplication = 0x6F617070; // 'oapp'
static final long kAEReopenApplication = 0x72617070; // 'rapp'
static final long keyDirectObject = 0x2d2d2d2d; // '----'
The callback function:
static long handleAppleEvent (long id, long sel, long event_id, long reply_id) {
// This is a handler for AppleEvents that are registered with [NSAppleEventManager setEventHandler:...]
// It matches this selector (footprint):
// - (void)handleAppleEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)reply
// Invoke [[event paramDescriptorForKeyword:keyDirectObject] stringValue] to get the direct object containing the URL
long direct_desc_id = OS.objc_msgSend (event_id, sel_paramDescriptorForKeyword, keyDirectObject);
long direct_str_id = OS.objc_msgSend (direct_desc_id, sel_stringValue);
NSString nsStr = new NSString (direct_str_id);
String str = nsStr.getString();
// now 'str' contains the URL
System.out.println ("handleAppleEvent invoked -- argument: "+url);
return 0;
}
And the code to register the callback function:
// Get access to a callback function for receiving the sel_handleAppleEvent message
aeCallback = new Callback(Main.class, "handleAppleEvent", 4);
long aeProc = aeCallback.getAddress();
// Create a ObjC class that provides a method with the sel_handleAppleEvent footprint
String objcClassName = "ObjCAppleEventHandler";
long objcClass = OS.objc_allocateClassPair(OS.class_NSObject, objcClassName, 0);
OS.class_addMethod(objcClass, sel_handleAppleEvent, aeProc, "i#:##");
OS.objc_registerClassPair(objcClass);
long objcHandlerInstance = OS.class_createInstance (objcClass, 0);
// Invoke [[NSAppleEventManager sharedAppleEventManager] setEventHandler:objcHandlerInstance andSelector:sel_handleAppleEvent forEventClass:kInternetEventClass andEventID:kAEGetURL]
long sharedAppleEventMgr = OS.objc_msgSend (class_NSAppleEventManager, sel_sharedAppleEventManager);
OS.objc_msgSend (sharedAppleEventMgr, sel_setEventHandler, objcHandlerInstance, sel_handleAppleEvent, kInternetEventClass, kAEGetURL);
What's left to do is to build an app bundle from this code and then add the CFBundleURLTypes entries to its Info.plist.
A complete sample source file can be downloaded here: http://files.tempel.org/Various/ObjectiveC-bridging.java.zip
With Java 9, this is easy quite easy, and no longer requires Apple's EAWT classes or any ObjC hackery.
Desktop.getDesktop().setOpenURIHandler((event) -> {
System.out.println("Open URI: " + event.getURI());
// do something with the URI
});
The application needs to be bundled, and the CFBundleURLTypes key must be set.
<!-- Open URIs with scheme example:// -->
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>example</string>
</array>
<key>CFBundleURLName</key>
<string></string>
</dict>
</array>
Unfortunately this only captures the URI if the application is already running. If the application was launched by opening a URI, the event is not delivered (see comments on ed22's answer).
In case anyone wanted a version using com.apple.eawt.*
This also uses reflection, so it will compile on any platform (Windows etc.). Make sure not to call the method registering the event handler on any non-Apple system ;)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.URI;
import java.util.logging.Level;
import java.util.logging.Logger;
interface OpenUriAppleEventHandler {
public void handleURI(URI uri);
}
class OpenURIEventInvocationHandler implements InvocationHandler {
private OpenUriAppleEventHandler urlHandler;
public OpenURIEventInvocationHandler(OpenUriAppleEventHandler urlHandler) {
this.urlHandler = urlHandler;
}
#SuppressWarnings({ "rawtypes", "unchecked"})
public Object invoke(Object proxy, Method method, Object[] args) {
if (method.getName().equals("openURI")) {
try {
Class openURIEventClass = Class.forName("com.apple.eawt.AppEvent$OpenURIEvent");
Method getURLMethod = openURIEventClass.getMethod("getURI");
//arg[0] should be an instance of OpenURIEvent
URI uri = (URI)getURLMethod.invoke(args[0]);
urlHandler.handleURI(uri);
} catch (Exception ex) {
ex.printStackTrace();
}
}
return null;
}
}
public class OSXAppleEventHelper {
/**
* Call only on OS X
*/
#SuppressWarnings({ "unchecked", "rawtypes" })
public static void setOpenURIAppleEventHandler(OpenUriAppleEventHandler urlHandler) {
try {
Class applicationClass = Class.forName("com.apple.eawt.Application");
Method getApplicationMethod = applicationClass.getDeclaredMethod("getApplication", (Class[])null);
Object application = getApplicationMethod.invoke(null, (Object[])null);
Class openURIHandlerClass = Class.forName("com.apple.eawt.OpenURIHandler", false, applicationClass.getClassLoader());
Method setOpenURIHandlerMethod = applicationClass.getMethod("setOpenURIHandler", openURIHandlerClass);
OpenURIEventInvocationHandler handler = new OpenURIEventInvocationHandler(urlHandler);
Object openURIEvent = Proxy.newProxyInstance(openURIHandlerClass.getClassLoader(), new Class[] { openURIHandlerClass }, handler);
setOpenURIHandlerMethod.invoke(application, openURIEvent);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Use it like this:
//if(isOSX){
OSXAppleEventHelper.setOpenURIAppleEventHandler(new OpenUriAppleEventHandler() {
#Override
public void handleURI(URI url) {
/* do something with the url */
}
});
I am stuck with loading java functions so that it can be called from lua file using luaj.
What i currently do is create something like this :
in some_package/aif.java :
package some_package;
public class aif extends TwoArgFunction {
public aif() {
}
#Override
public LuaValue call(LuaValue modname, LuaValue env) {
LuaValue library = tableOf();
library.set("foo", new foo());
env.set("aif", library);
return library;
}
//the rest contains the implementations of java functions
}
and then in lua file :
require "some_package/aif"
--etc ...
and then in Main.java file :
public static void Main(String[] args) {
String script = "lib/some_lua_file.lua";
globals = JsePlatform.standardGlobals();
LuaValue chunk = globals.loadFile(script);
chunk.call( LuaValue.valueOf(script) );
}
this code works , but what i want is that in lua file we dont have to use "require". I have achieved this similarly but in c++ using this line :
luaL_requiref(L, "aif", luaopen_aiflib, 1);
can we do like that in luaj? i tried :
globals.load(new aif());
but gets Exception in thread "main" org.luaj.vm2.LuaError: index expected, got nil (variable env in call function of aif class is nil)
anybody knows how to setup aif as lua libary to use with luaj?
You can write your MyXArgImpl like the following:
package mypackage;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.ZeroArgFunction;
public class MyZeroArgImpl extends ZeroArgFunction {
public LuaValue call() {
return valueOf("My Zero Arg Implementation");
}
}
and then add it to your LUA as the following:
LuaValue globals = JsePlatform.standardGlobals();
globals.get("dofile").call( LuaValue.valueOf(yourScriptfile));
globals.set("callMyFunction", new MyZeroArgImpl());
Now you can call your function inside your LUA script even without require('...'):
print(callMyFunction())
I have found the answer after looking at the luaj implementation of Lua library.
i modified my code :
package some_package;
public class aif extends OneArgFunction{
public aif() {
}
#Override
public LuaValue call(LuaValue env) {
Globals globals = env.checkglobals();
LuaTable aif = new LuaTable();
aif.set("foo", new foo());
env.set("aif", aif);
globals.package_.loaded.set("aif", aif);
return aif;
}
//the rest contains the implementations of java functions
}
I code the aif class to TwoArgFunction is because the tutorial said to do so. Now with the above code, no need to require the class in lua file
Lets say your script that you are loading has a function "receive_aif"
function receive_aif( aifObj )
--This is how you can invoke public function associated with aifObj
aifObj:someAifFunction()
end
From java, you can pass aif instance as: (This should work with any java object )
aif aifObj = new aif()
LuaValue receive_aif_handle = globals.get("receive_aif");
LuaValue retvals = receive_aif_handle.call( CoerceJavaToLua.coerce( aifObj ) );
I am using similar constructs in my application using "3.0 aplha-2" release
I'm trying to use a generated interface by JNAerator from a typedef instruction, but I can't find a way to do that:
The function in the .h file is:
MyClass::Initialize(LPCWSTR path);
The header file also includes the original typedef instruction:
typedef __nullterminated CONST WCHAR *LPCWSTR, *PCWSTR;
JNAerator generates:
Method:
public native int Initialize(LPCWSTR path);
The interface:
/// Undefined type
/// Undefined type
public static interface LPCWSTR {
};
And the classes:
/// C type : WCHAR*
public Pointer<Short > LPCWSTR() {
try {
return (Pointer<Short >)BridJ.getNativeLibrary("dlls").getSymbolPointer("LPCWSTR").as(DefaultParameterizedType.paramType(Pointer.class, Short.class)).get();
}catch (Throwable $ex$) {
throw new RuntimeException($ex$);
}
}
/// C type : WCHAR*
public MainLibrary LPCWSTR(Pointer<Short > LPCWSTR) {
try {
{
BridJ.getNativeLibrary("dlls").getSymbolPointer("LPCWSTR").as(DefaultParameterizedType.paramType(Pointer.class, Short.class)).set(LPCWSTR);
return this;
}
}catch (Throwable $ex$) {
throw new RuntimeException($ex$);
}
}
The problem is, I don't know how to instantiate an object LPCWSTR using Pointer and the LPCWSTR interface, using a String, so that I can pass it to the Initialize method.
How can I do this?
UPDATE:
I modified the .h file to use wchar_t*:
MyClass::Initialize(wchar_t* path)
JNAerator generated the method like this:
public native int Initialize(Pointer<Character > path);
So I called it like this:
MyClass factory = new MyClass();
Pointer<Character> path = org.bridj.Pointer.pointerToWideCString("dlls");
factory.Initialize(path);
The problem is that I get the following exception:
java.lang.UnsatisfiedLinkError: main.MyClass.Initialize(Lorg/bridj/Pointer;)I
at this line:
factory.Initialize(path);
What am I doing wrong?
The UnsatisfiedLinkError indicates that your native Initialize method was not bound by BridJ.
This binding is done by CPPObject's constructor (I assume you got a JNAerated MyClass class that inherits from it), and any failure to bind should result in error logs in your console (in any case, you can increase the logs verbosity with BRIDJ_VERBOSE=1 environment variable).
Also, please note that your MyClass should have a #Library("mylibrary") annotation to let it know where to find the appropriate library (.dll, .so or .dylib), or should be an inner class of a class with such an annotation. This is normally the case of JNAerated classes, but if it's not, please report a bug in NativeLibs4Java's tracker.
I was having this problem too. zOlive’s response sent me down the right path. I changed the JNAerator library option to match my DLL name (e.g. -library MyLib MyLib.dll MyLib.h). That fixed it for me. There is more info about the library option here.