JNA Using macros - java

Is it possible to map The following Macro function with JNA?
int ListView_FindItem(
HWND hwnd,
int iStart,
const LPLVFINDINFO plvfi
);
I've tried to map this function with StdCallLibraryb, but that does not seem to work
(Function not found exception is thrown).
Basically i am trying find the index of a particular item in List view of desktop.
I have the name of the item i intend to find.
EDIT:
i have tried using the send message feature, i get the following exception
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function
'GetMessage': The specified procedure could not be found.
at com.sun.jna.Function.<init>(Function.java:179)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:347)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:327)
at com.sun.jna.Library$Handler.invoke(Library.java:203)
at $Proxy0.GetMessage(Unknown Source)
at javaapplication4.Main.main(Main.java:43)
Java Result: 1
This is the code i used
public class Main {
public static class LVFINDINFO extends Structure {
public int flags =1002;
public String psz = "new folder3";
public LPARAM lParam ;
public POINT pt;
public int vkDirection;
}
public static class MSG extends Structure {
public HWND hWnd;
public int message;
public int wParam =-1;
public LVFINDINFO lParam1;
public int time;
public POINT pt;
public MSG(LVFINDINFO lParam) {
lParam1 = lParam;
}
}
public static void main(String[] args) {
User32 user32 = (User32) Native.loadLibrary("User32", User32.class);
LVFINDINFO i = new LVFINDINFO();
MSG m = new MSG(i);
user32.GetMessage(m, user32.GetDesktopWindow(), 0, 0);
System.out.println(user32.GetMessage(m, user32.GetDesktopWindow(), 0, 0));
}
}

Since a macro exists purely at compile-time, there's no way to call it using JNA.
You'll need to see what the macro actually does and do that instead. According to the documentation it sends the LVM_FINDITEM message. You need to find out how to send that message using JNA.

Related

JNA 4.2.1 call dll method without params

i use jna 4.2.1
I have a method in the dll which returns a pointer to an object (C++)
basic_hash* getAlgorithmInstance( int algorithm )
basic_hash has the following methods (C++):
void reset ();
void partial (const byte* data, uint64 size);
void finalize (vector_byte& hash);
void hash (const byte* data, uint64 size, vector_byte& hash).
i have interface (java)
public interface HAL extends Library {
HAL INSTANCE = (HAL) Native.loadLibrary(
(Platform.isWindows() ? "HAL" : "libHAL"), HAL.class);
BasicHash getAlgorithmInstance(int i);
}
public static class BasicHash extends Structure {
public BasicHash() {}
public BasicHash(Pointer p) {
super(p);
read();
}
#Override
protected List getFieldOrder() {
return Arrays.asList(new String[] { "reset", "hash", "partial", "finalize" });
}
public interface Reset extends Callback { public void invoke();}
public Reset reset;
public interface Hash extends Callback {public void invoke(byte[] data, long size, byte[] hash);}
public Hash hash;
public interface Partial extends Callback {public void invoke(Pointer data, long size);}
public Partial partial;
public interface Finalize extends Callback {public void invoke(byte[] hash);}
public Finalize finalize;
}
and when I use the method without parameters in main()
HAL lib = HAL.INSTANCE;
BasicHash b = lib.getAlgorithmInstance(0);
b.reset.invoke();
I get an error:
Exception in thread "main" java.lang.Error: Invalid memory access
at com.sun.jna.Native.invokeVoid(Native Method)
at com.sun.jna.Function.invoke(Function.java:374)
at com.sun.jna.Function.invoke(Function.java:323)
at com.sun.jna.Function.invoke(Function.java:275)
at com.sun.jna.CallbackReference$NativeFunctionHandler.invoke(CallbackReference.java:646)
at com.sun.proxy.$Proxy1.invoke(Unknown Source)
at net.erver.ItServer.main(ItServer.java:79)
Why did I receive this error if the method resets the variables within the library? the method itself fulfills without problems (according to developers dll)
EDIT:
vector_byte has definition:
typedef unsigned char byte;
typedef std::vector< byte > vector_byte
and basic_hash has definition:
namespace HAL { namespace algorithms {
HAL_HASH_API enum class State : byte {
Normal,
Finished,
};
class HAL_HASH_API basic_hash
{
public:
virtual ~basic_hash() {}
virtual void reset() = 0;
virtual void partial( const byte*, uint64 ) = 0;
virtual void finalize( vector_byte& ) = 0;
virtual void hash( const byte*, uint64, vector_byte& ) = 0;
bool isFinished() {
return ( _state == State::Finished ? true : false );
}
protected:
State _state;
};
}
}
You need to use plain vanilla struct to pass data between JNA and your library. A C++ class (including a vector template) has a much different memory layout than does a simple C struct.

How do I use a more specific struct type in place of a more general one?

I am working on a windows device manager which will work with java.
I stick on trying to pass without error SetupDiSetClassInstallParams function. (I am trying disable an device.)
I am running exact same structure(necessary way) in C++ and I do not have any problem.
I am getting ERROR_INVALID_USER_BUFFER error. When I tried get this error in C++ I need to change SP_PROPCHANGE_PARAMS structs values with wrong ones.
My struct declerations:
public static class SP_CLASSINSTALL_HEADER extends Structure {
public static class ByReference extends SP_CLASSINSTALL_HEADER implements Structure.ByReference {
public ByReference() {
}
public ByReference(Pointer memory) {
super(memory);
}
}
public SP_CLASSINSTALL_HEADER() {
cbSize = size();
}
public SP_CLASSINSTALL_HEADER(Pointer memory) {
super(memory);
read();
}
public int cbSize;
public long InstallFunction; **/* <-- this should be int or else buffer size changes, dll cannot place variables on right places. */**
protected List getFieldOrder() {
return Arrays.asList(new String[] { "cbSize", "InstallFunction" });
}
}
public static class SP_PROPCHANGE_PARAMS extends Structure {
public static class ByReference extends SP_PROPCHANGE_PARAMS implements Structure.ByReference {
public ByReference() {
}
public ByReference(Pointer memory) {
super(memory);
}
}
public SP_PROPCHANGE_PARAMS() {
}
public SP_PROPCHANGE_PARAMS(Pointer memory) {
super(memory);
read();
}
public SP_CLASSINSTALL_HEADER ClassInstallHeader = new SP_CLASSINSTALL_HEADER();
public int StateChange;
public int Scope;
public int HwProfile;
protected List getFieldOrder() {
return Arrays.asList(new String[] { "ClassInstallHeader", "StateChange", "Scope", "HwProfile" });
}
}
My function decleration:
boolean SetupDiSetClassInstallParams(WinNT.HANDLE hDevInfo, Pointer deviceInfoData, Pointer classInstallHeader, int size);
How do I calling this function:
SP_PROPCHANGE_PARAMS spPropChangeParams = new SP_PROPCHANGE_PARAMS();
spPropChangeParams.ClassInstallHeader.InstallFunction = DISetupApi.DIF_PROPERTYCHANGE;
spPropChangeParams.Scope = DISetupApi.DICS_FLAG_GLOBAL;
spPropChangeParams.HwProfile = 0;
spPropChangeParams.StateChange = DISetupApi.DICS_DISABLE;
int spPropChangeParamsSize = spPropChangeParams.size();
SP_CLASSINSTALL_HEADER classInstallHeaderReference = new SP_CLASSINSTALL_HEADER(spPropChangeParams.getPointer());
setupApi.SetupDiSetClassInstallParams(hDevInfo, device.getSPDeviceInfoData().getPointer(), classInstallHeaderReference.getPointer(),
spPropChangeParamsSize);
How It works in c++:
SP_PROPCHANGE_PARAMS spPropChangeParams;
spPropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
spPropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
spPropChangeParams.Scope = DICS_FLAG_GLOBAL;
spPropChangeParams.HwProfile = 0;
spPropChangeParams.StateChange = DICS_DISABLE;
SetupDiSetClassInstallParams(hDeviceInfo, &device.getDeviceInfoData(), (SP_CLASSINSTALL_HEADER*)&spPropChangeParams, sizeof(spPropChangeParams));
Actually I mixed and matched too many ways these structs and function I changed variable types of structs and parameter types of function at the end I could not get anything but error. I cannot find what is my mistake. Could you please help me solve this.
Thanks in advance!
When you're passing around a Structure, don't use Structure.getPointer() unless you have to. When you do that, JNA can't automatically synch the native and Java data, and it's error-prone to remember where to do that yourself. In your case, whatever is in the Java fields never gets copied to native memory in your call to setupApi.SetupDiSetClassInstallParams.
Change your function mapping to this:
boolean SetupDiSetClassInstallParams(WinNT.HANDLE hDevInfo, SP_DEVINFO_DATA deviceInfoData, SP_CLASSINSTALL_HEADER classInstallHeader, int size);
and change the invocation to this:
setupApi.SetupDiSetClassInstallParams(hDevInfo, device.getSPDeviceInfoData(), classInstallHeaderReference, spPropChangeParamsSize);
EDIT
If you stick to your original struct definition (where SP_CLASSINSTALL_HEADER is a field), you need to add a function mapping to the interface (extend the interface and create your own instance of the native library):
public interface MySetupApi extends SetupApi {
MySetupApi INSTANCE = (MySetupApi)Native.loadLibrary(MySetupApi.class, W32APIOptions.DEFAULT_OPTIONS);
boolean SetupDiSetClassInstallParams(WinNT.HANDLE hDevInfo, SP_DEVINFO_DATA deviceInfoData, SP_PROPCHANGE_PARAMS propChangeParams, int size);
}

JNA getFieldOrder() results in names not matching in HashSet() comparison (JNA's Structure.java, line 925)

Running into a maddening blocking error:
Exception in thread "main" java.lang.Error: Structure.getFieldOrder() on class com.luke.generator.GeneratorEngine$VERSION_INFO returns names ([BuildString, ProtocolMajorVer, ProtocolMinorVer]) which do not match declared field names ([BiuldString, ProtocolMajorVer, ProtocolMinorVer])
at com.sun.jna.Structure.getFields(Structure.java:925)
at com.sun.jna.Structure.deriveLayout(Structure.java:1058)
at com.sun.jna.Structure.calculateSize(Structure.java:982)
at com.sun.jna.Structure.calculateSize(Structure.java:949)
at com.sun.jna.Structure.allocateMemory(Structure.java:375)
at com.sun.jna.Structure.<init>(Structure.java:184)
at com.sun.jna.Structure.<init>(Structure.java:172)
at com.sun.jna.Structure.<init>(Structure.java:159)
at com.sun.jna.Structure.<init>(Structure.java:151)
at com.luke.generator.GeneratorEngine$.<init>(GeneratorEngine.java:108)
at com.luke.generator.connectionVersion(GeneratorEngine.java:297)
at com.luke.generator.Main.main(Main.java:161)
Platform: Intel, Windows 8
JRE 1.7, 32-bit (x86)
Eclipse Kepler, Default encoding UTF-8
jna-4.1.0.jar
32-bit CPP DLL - I can confirm that I am loading the library and calling functions that do not include parameters. I also tried passing WStrings and Strings, but that did not address the issue.
Source:
CPP struct:
typedef struct {
UINT32 ProtocolMajorVer;
UINT32 ProtocolMinorVer;
UI_STRING BuildString; // Build version for the application.
} VERSION_INFO;
CPP Function
DLL_EXPORTS RETURN_TYPES ConnectionVersion (VERSION_INFO &Version) {<body omitted>}
Java code:
//Interface definition
public interface UiApi extends StdCallLibrary {
UiApi INSTANCE = (UiApi) Native.loadLibrary(UiApiPath,UiApi.class);
final String PROTOCOLMAJORVERSION = new String("ProtocolMajorVer");
final String PROTOCOLMINORVERSION = new String("ProtocolMinorVer");
final String BUILDSTRING = new String("BuildString");
public static class VERSION_INFO extends Structure {
public static class ByReference extends VERSION_INFO implements Structure.ByReference {}
public static class ByValue extends VERSION_INFO implements Structure.ByValue {}
public int ProtocolMajorVer;
public int ProtocolMinorVer;
public byte[] BiuldString;
protected List getFieldOrder() {
return Arrays.asList(new String[] { "ProtocolMajorVer","ProtocolMinorVer","BuildString" });
}
}
//Connection
public int Connect(byte[] strServerName);
public int Disconnect();
public int CloseProject();
public int ConnectionVersion(VERSION_INFO result);
public int ConnectionVersion(VERSION_INFO.ByReference result);
public int ConnectionVersion(VERSION_INFO.ByValue result);
}
//Engine.connectionVersion() method
public static int connectionVersion() {
int nReturn = 0;
String str = new String("This is my build version\n");
UiApi uiapilib;
uiapilib = UiApi.INSTANCE;
try {
UiApi.VERSION_INFO.ByReference result = new UiApi.VERSION_INFO.ByReference();
result.ProtocolMajorVer = 0;
result.ProtocolMinorVer = 0;
result.BiuldString = str.getBytes();
nReturn = uiapilib.ConnectionVersion(result);
}
catch (Exception e) {
System.out.println("Error=" + e.getLocalizedMessage());
}
return nReturn;
}
//This is the code in main that results in exception
private static Engine engine;
engine = new GeneratorEngine();
engine.connectionVersion();
I must be missing something basic. Is there something in Eclipse that could possibly be causing the HashSet name comparisons in JNA's Structure.java (line 925) that would result in names not matching? From the exception thrown, these definitions look identical.
Thanks for any tips, guidance, fresh perspectives you can offer.
Check your spelling - the field is called BiuldString not BuildString, you have the i and u reversed.

C++ binary to Java gets "java.lang.Error: Invalid memory access"

I have a Java library interfacing (via JNA) with a native C++ DLL. This DLL provides functions to set callbacks that are invoked when certain hardware events occur.
All of these callbacks work except one, even though it has near-identical definition to another one.
These callback signatures and enums are defined in C++ code:
typedef enum _KEYSTATE
{
KEYSTATE_NONE = 0,
KEYSTATE_UP,
KEYSTATE_DOWN,
KEYSTATE_HOLD,
KEYSTATE_INVALID,
} KEYSTATETYPE, *P_KEYSTATETYPE;
typedef enum _DKTYPE
{
DK_NONE = 0,
DK_1,
DK_2,
DK_3,
DK_4,
DK_5,
DK_6,
DK_7,
DK_8,
DK_9,
DK_10,
DK_INVALID,
DK_COUNT = 10
} DKTYPE, *P_DKTYPE;
typedef enum _GESTURETYPE
{
GESTURE_NONE = 0x00000000,
GESTURE_PRESS = 0x00000001,
GESTURE_TAP = 0x00000002,
GESTURE_FLICK = 0x00000004,
GESTURE_ZOOM = 0x00000008,
GESTURE_ROTATE = 0x00000010,
GESTURE_MOVE = 0x00000020,
GESTURE_HOLD = 0x00000040,
GESTURE_RELEASE = 0x00000080,
GESTURE_SCROLL = 0x00000100,
GESTURE_ALL = 0xFFFF
} GESTURETYPE, *P_GESTURETYPE;
typedef enum _EVENTTYPE
{
EVENT_NONE = 0,
EVENT_ACTIVATED,
EVENT_DEACTIVATED,
EVENT_CLOSE,
EVENT_EXIT,
EVENT_INVALID,
} EVENTTYPETYPE, *P_EVENTTYPETYPE;
typedef HRESULT (CALLBACK *DynamicKeyCallbackFunctionType)(DKTYPE, KEYSTATETYPE);
typedef HRESULT (CALLBACK *AppEventCallbackType) (EVENTTYPETYPE, DWORD, DWORD);
typedef HRESULT (CALLBACK *TouchpadGestureCallbackFunctionType)(GESTURETYPE, DWORD, WORD, WORD, WORD);
typedef HRESULT (CALLBACK *KeyboardCallbackFunctionType)(UINT uMsg, WPARAM wParam, LPARAM lParam);
The following interfaces are defined in Java for callbacks:
interface DynamicKeyCallbackFunction extends StdCallLibrary.StdCallCallback {
int callback(int rawDynamicKeyType, int rawDynamicKeyState);
}
interface AppEventCallbackFunction extends StdCallLibrary.StdCallCallback {
int callback(int appEventType, WinDef.UINT dwAppMode, WinDef.UINT dwProcessID);
}
interface TouchpadGestureCallbackFunction extends StdCallLibrary.StdCallCallback {
int callback(int gestureType, WinDef.UINT dwParameters,
WinDef.USHORT wXPos, WinDef.USHORT wYPos, WinDef.USHORT wZPos);
}
interface KeyboardCallbackFunction extends StdCallLibrary.StdCallCallback {
int callback(WinDef.UINT uMsg, WinDef.UINT_PTR wParam, WinDef.INT_PTR lParam);
}
With these functions in the API/Library class/interface to set them:
// These are defined in an RazerAPI.java file as wrappers to simplify usage
// lib is an instance of a RazerLibrary from JNA
public Hresult RzSBAppEventSetCallback(AppEventCallbackFunction callback) {
return Hresult.getFromApiValue(lib.RzSBAppEventSetCallback(callback));
}
public Hresult RzSBDynamicKeySetCallback(DynamicKeyCallbackFunction callback) {
return Hresult.getFromApiValue(lib.RzSBDynamicKeySetCallback(callback));
}
public Hresult RzSBKeyboardCaptureSetCallback(KeyboardCallbackFunction callback) {
return Hresult.getFromApiValue(lib.RzSBKeyboardCaptureSetCallback(callback));
}
public Hresult RzSBGestureSetCallback(TouchpadGestureCallbackFunction callback) {
return Hresult.getFromApiValue(lib.RzSBGestureSetCallback(callback));
}
// These are the methods in the interface RazerLibrary.java file passed to JNA
int RzSBAppEventSetCallback(RazerAPI.AppEventCallbackFunction callback);
int RzSBDynamicKeySetCallback(RazerAPI.DynamicKeyCallbackFunction callback);
int RzSBKeyboardCaptureSetCallback(RazerAPI.KeyboardCallbackFunction callback);
int RzSBGestureSetCallback(RazerAPI.TouchpadGestureCallbackFunction callback);
When registering callbacks, something similar to this is used (simplified to not clutter up with hundreds of lines, links to full code files at end of post).
public class RazerManager implements DynamicKeyCallbackFunction {
private static DynamicKeyCallbackFunction dkCallback;
private RazerManager() {
dkCallback = this;
RazerAPI api = RazerAPI.INSTANCE;
api.RzSBDynamicKeySetCallback(dkCallback);
}
#Override
public int callback(int type, int state) {
System.out.printf("DK Callback: %s %s", type, state);
return 0; // S_OK
}
}
public class Touchpad implements TouchpadGestureCallbackFunction {
private static TouchpadGestureCallbackFunction gestureCallback;
private Touchpad() {
gestureCallback = this;
RazerAPI api = RazerAPI.INSTANCE;
api.RzSBGestureSetCallback(gestureCallback);
}
#Override
public int callback(int gestureType, UINT param, USHORT x, USHORT y, USHORT z) {
System.out.printf("Gesture: %s", gestureType);
}
}
An instance of RazerManager is created in the main loop of a simple swing app used for testing, RazerManager creates an instance of Touchpad in its constructor. A while loop is used to process messages with GetMessage followed by Translate and DispatchMessage if valid, like the following:
public class Main {
public static void main(String[] args) throws IOException {
// call javax's invokeLater to run app
}
public Main() {
/* JFrame created here and then shown with setVisible(true); */
RazerManager manager = RazerManager.getInstance();
// Yes this is horrible, blocking everything but it's simply
// used to get messages to go through and trigger the callbacks
WinUser.MSG msg = new WinUser.MSG();
while (true) {
int hasMessage = User32.INSTANCE.GetMessage(msg, null, 0, 0);
if (hasMessage != 0) {
User32.INSTANCE.TranslateMessage(msg);
User32.INSTANCE.DispatchMessage(msg);
}
}
}
}
Now, gesture events are handled just fine, the callback in Touchpad class gets called and returns properly. When a dynamic key event is generated, an exception is thrown inside the while loop processing windows messages:
Exception in thread "AWT-EventQueue-0" java.lang.Error: Invalid memory access
at com.sun.jna.Native.invokeInt(Native Method)
at com.sun.jna.Function.invoke(Function.java:383)
at com.sun.jna.Function.invoke(Function.java:315)
at com.sun.jna.Library$Handler.invoke(Library.java:212)
at com.sun.proxy.$Proxy11.DispatchMessage(Unknown Source)
at com.sharparam.jblade.tester.Main.<init>(Main.java:113)
at com.sharparam.jblade.tester.Main$1.run(Main.java:25)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:733)
at java.awt.EventQueue.access$200(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:694)
at java.awt.EventQueue$3.run(EventQueue.java:692)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:703)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)
This only happens with dynamic key events, not with gesture or appevent. I can't for the life of me understand why, as dynamic key and gesture callbacks are very similar on the C++ side.
EDIT: Full code can be found in the GitHub repo, specifically RazerLibrary.java, RazerAPI.java, RazerManager.java and Touchpad.java. The swing test can be found as a gist.
So it turns out that you can't (or at least you have to do it in a different way than I did) have one class implement multiple callback interfaces. Creating explicit implementations of the different callback interfaces and assigning them to the callback fields in RazerManager solved it.
This explains why the callback in Touchpad was working but not the ones in RazerManager (Touchpad implemented one interface while RazerManager did three).
To demonstrate:
public class MyClass {
private static MyCallbackInterface myCallback;
private MyClass() {
myCallback = new CallbackInterface() {
#Override
public int callback(/* parameters */) {
// Do stuff with data here
return 0;
}
}
nativeLib.SetCallback(myCallback);
}
It seems the native library or JNA gets confused somewhere when a single class implements more than one callback interface, and doesn't know which one to call. So it calls one at random (or the first one defined?).

how do i pass pointer ref to native method in JNI [duplicate]

This is native method from ITLSSPProc.dll
NOMANGLE int CCONV OpenSSPComPort (SSP_COMMAND * cmd);
Here, SSP_COMMAND is structure in ITLSSPProc.dll which is in C++
Language.
struct SSP_COMMAND
{
unsigned long BaudRate;
unsigned char PortNumber;
};
So, I have to access OpenSSPComPort (SSP_COMMAND * cmd) in java using
JNI. Here is a code i have written,
public class Main {
public interface ITLSSPProc extends Library {
ITLSSPProc INSTANCE = (ITLSSPProc) Native.loadLibrary(
(Platform.isWindows() ? "ITLSSPProc" : "simpleDLLWindowsPort"), ITLSSPProc.class);
int OpenSSPComPort(Pointer param);
int CloseSSPComPort();
}
public static void main(String[] args)throws IOException {
ITLSSPProc sdll = ITLSSPProc.INSTANCE;
Memory intMem = new Memory(10); // allocating space
intMem.setLong(0,9600);
intMem.setString(1,"com7");
if(sdll.OpenSSPComPort(intMem)==1)
{// calling function with int parameter&result
System.out.println("connected");
}
else
{
System.out.println("failed");
}
}
}
Output : failed
Port number is COM7 on which we are working. So, when i run this
application and as i passing baud rate as manually as given in user
manual and if port number is correct it has to print "connected" on
console. So, anybody know where i am going wrong, i dont understand
where is actual problem..
JNA documentation for basic types (long, char).
JNA documentation for aggregate types (struct, struct *).
// tl;dr
class SSP_COMMAND extends Structure {
public NativeLong BaudRate;
public byte PortNumber;
}
int OpenSSPComPort(SSP_COMMAND param)

Categories