So i have native function in C declared as int NgSetEvent (int event, long callback). long Callback represent the callback function pointer. Callback prototype is declared as int oncodeline(int code, int documentid, char *string). The callback should be registered with method NgSetEvent. The problem is how to get pointer to that function which should be long or Nativelong? I have tried a lot of different aproaches but none of them gave a result. Callback was never invoked.
I have tried to do like it says in Turn a Callback into a Pointer in JNA, but with no success. i don't know what to try anymore.
Any help will be appreciated.
OnCodeline
public interface OnCodeline extends Callback {
int oncodeline (int code, int documentid, byte[] string);
}
OnCodelineStruct
public class OnCodelineStruct extends Structure {
public OnCodeline onc;
#Override
protected List getFieldOrder() {
return Arrays.asList(new String[] { "onc" });
}
}
Main class
OnCodelineStruct onCodelinStruct;
onCodelinStruct = new OnCodelineStruct();
onCodelinStruct.onc = new OnCodeline() {
#Override
public int oncodeline(int code, int documentid, byte[] string) {
System.out.println("This IS a CALLBACK!");
return 0;
}
};
sbDll.NgSetEvent(0, onCodelinStruct.getPointer().getNativeLong(0));
Related
I simplified this for brevity; hopefully this example isn't actually functional. I'm creating and doing things with a variable, then I'm having another class do some stuff, then that class refers back to the original and tells it to do more stuff with that variable.
I've done exactly this with views. I simply pass the activity and then when I need to use it I use activity.findViewById(id) to do stuff. With variables, you can't just do activity.variable. I tried using a getter (as shown in this example), but maybe I'm still just doing it wrong or it can't be done how I'd like:
public class MyActivity {
private int test;
public void onCreate(Bundle savedInstanceState) {
test = 5;
int data = 100;
//Pass something to it
new NotAnActivity().func(MyActivity.this,data);
}
public int gettest() {
return test;
}
public void func(Activity instance, int response) {
int test = new MyActivity().gettest();
//Do stuff with test
}
}
public class NotAnActivity {
public void func(Activity instance, int data) {
//Do stuff with data
int response = 20;
//Try to pass information back
new MyActivity().func(instance,response);
}
}
You can't use a activity.gettest() because you're passing the superclass Activity between classes. To have access to the gettest() method you need to pass the specific child activity (MyActivity extends Activity, pass MyActivity instead of Activity) or you can cast to your specific activity.
((MyActivity)activity).getter();
So here, instead of:
public void func(Activity instance, int data) {
//Do stuff with data
int test = ((MyActivity)instance).gettest();
}
or
public void func(MyActivity instance, int data) {
//Do stuff with data
int test = instance.gettest();
}
It's not a good idea to instantiate your activities yourself new A()
public class MainActivity extends AppCompatActivity {
private int test;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
test = 5;
int data = 100;
new NotAnActivity().func(this,data);
}
public int gettest() {
return test;
}
public void func(MainActivity instance, int response) {
//int test = new MainActivity().gettest();
int test = instance.gettest();
Log.v("variable", "test = " + test);
}
}
class NotAnActivity {
public void func(MainActivity instance, int data) {
//Do stuff with data
int response = 20;
//Try to pass information back
instance.func(instance,response);
}
}
You can try it. Your mistake is [new MyActivity()]
I'm using a Odoo service to get my data of web. In main class I have a method to read a data:
public void OdooRead() {
OdooService.getCustomers(odoo, "myCallbackFunction");
}
So, I did create a other class to make this service:
public class OdooService {
public static final String[] odooAllFields = {"id","name","customer_account_number","customer_group_id","segment_id","subsegment_id","economic_group_id","type_stablishment_id","street","street2","final_user","final_taxpayer","cnpj_cpf","inscr_est","ccm","cnae","phone","phone_extension","mobile","fax","email","email_extra","website","lang"};
public static List<Customer> getCustomers(OdooClient client, "myCallbackFunction") {
List<Customer> list = new ArrayList<>();
ODomain domain = new ODomain();
OdooFields odooFields = new OdooFields();
odooFields.addAll(odooAllFields);
String sorting = "id ASC";
int offset = 0;
int limit = 0;
client.searchRead("res.partner", domain, odooFields, offset, limit, sorting, new IOdooResponse() {
#Override
public void onResult(OdooResult result) {
// HERE I WANTS CALL THE CALLBACK FUNCTION TO MAIN!
}
});
return list;
}
}
So, when the method returns the result of search on web, I wants send a callback function to main, with the list of results as parameter. And while this, the main class runs normally, and when method finish I refresh user interface.
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.
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);
}
I'm still a relative newbie when it comes to Java, coming mainly from a C# background.
I was discussing the lack of 'out' parameters in Java methods with a colleague and how to work around this. He suggested creating a structure/class to hold the various parameters and passing it back.
Sometimes this feels 'wrong' to me - especially if I have a special method that I want to use to return a subset of parameters from a larger class.
So I wondered about using anonymous inline classes instead to achieve this. Code sample below.
Is this a sensible approach? Just wondering what the perceived wisdom is on this.
public class MyClass {
Patient myPatient = null;
// An interface to enable us to return these variables in a single call
public interface VitalStatsResponse { public void returnStats(int bloodPressure, int heartRate); }
public class Patient {
int bloodPressure = 100;
int heartRate = 280;
// Lots of other variables here
public void calculateVitalStats(VitalStatsResponse response)
{
response.returnStats((bloodPressure * 2), (heartRate / 10) ;
}
}
public void doWork()
{
// We want the patient's blood pressure and heart rate returned by a single method call, so use an anonymous inline class
myPatient.calculateVitalStats(new VitalStatsResponse() {
#Override
public void returnStats(int bloodPressure, int heartRate) {
// Handle returned variables here
}
});
}
}
I would go for the simple solution of creating a VitalStats object. If you need the VitalStatus of a patient, then VitalStats is a concept in your application that can be represented as an Object.
public class VitalStatus {
final int bloodPressure;
final int heartRate;
public VitalStats(int bloodPressure, int heartRate) {
this.bloodPressure = bloodPressure;
this.heartRate = heartRate;
}
}
public class Patient {
int bloodPressure = 100;
int heartRate = 280;
// Other variables
public VitalStatus getVitalStatus() {
return new VitalStats(bloodPressured * 2, heartRate / 2);
}
}
Out params is a procedural solution for return times. Java primarily fits the Object Oriented paradigm of programming and as such don't be afraid to make objects. This fits with the S in SOLID if your class is doing a lot of complex things see if you can break it down into smaller more manageable pieces.
I would also use "class to hold the parameters" over "inline anonymous inner class"
public class MyClass implements VitalStatsResponse{
Patient myPatient = null;
private ArrayList<VitalStatsResponse> response;
void MyClass(ArrayList<VitalStatsResponse> response) {
this.response = response;
}
public class Patient {
int bloodPressure = 100;
int heartRate = 280;
// Lots of other variables here
public void calculateVitalStats()
{
for(int i = 0; i < response.length; i++) {
// call returnStats method of every registered callback
response.get(i).returnStats((bloodPressure * 2), (heartRate / 10) ;
}
}
}
// any client can register/unregister callback via these methods
void registerResponse(VitalStatsResponse response) {
this.response.add(response);
}
void unRegisterResponse(VitalStatsResponse response) {
this.response.remove(response);
}
public void doWork()
{
// We want the patient's blood pressure and heart rate returned by a single method call, so use an anonymous inline class
myPatient.calculateVitalStats();
}
public void returnStats(int bloodPressure, int heartRate) {
// implement the body according to this class requirement
}
}