I am using jna-4.5.1 in my Java Project.
This is cryptdlg structure CERT_SELECT_STRUCT I want to replicate.
typedef struct tagCSSA {
DWORD dwSize;
HWND hwndParent;
HINSTANCE hInstance;
LPCSTR pTemplateName;
DWORD dwFlags;
LPCSTR szTitle;
DWORD cCertStore;
HCERTSTORE *arrayCertStore;
LPCSTR szPurposeOid;
DWORD cCertContext;
PCCERT_CONTEXT *arrayCertContext;
LPARAM lCustData;
PFNCMHOOKPROC pfnHook;
PFNCMFILTERPROC pfnFilter;
LPCSTR szHelpFileName;
DWORD dwHelpId;
HCRYPTPROV hprov;
} CERT_SELECT_STRUCT_A, *PCERT_SELECT_STRUCT_A;
Sample Java code for my project.
public class Crypto {
public interface Cryptdlg extends Library {
Cryptdlg INSTANCE = (Cryptdlg) Native.loadLibrary("Cryptdlg", Cryptdlg.class, W32APIOptions.DEFAULT_OPTIONS);
public boolean CertSelectCertificate(CERT_SELECT_STRUCT pCertSelectInfo);
public static class CERT_SELECT_STRUCT extends Structure {
private static final List<String> fieldOrder = createFieldsOrder("dwSize", "hwndParent", "hInstance",
"pTemplateName", "dwFlags", "szTitle", "cCertStore", "arrayCertStore", "szPurposeOid",
"cCertContext", "arrayCertContext", "lCustData", "pfnHook", "pfnFilter", "szHelpFileName",
"dwHelpId", "hprov");
public static class ByReference extends CERT_SELECT_STRUCT implements Structure.ByReference {
}
public int dwSize = size();
public HWND hwndParent;
public HINSTANCE hInstance;
public String pTemplateName;
public int dwFlags;
public String szTitle;
public int cCertStore;
public Pointer arrayCertStore;
public String szPurposeOid;
public int cCertContext;
public Pointer arrayCertContext;
public WinDef.LPARAM lCustData;
public Pointer pfnHook = null;
public Pointer pfnFilter = null;
public String szHelpFileName;
public int dwHelpId;
public HCRYPTPROV hprov;
public CERT_SELECT_STRUCT() {
super();
}
public WinCrypt.CERT_CONTEXT[] getArrayCertContext() {
WinCrypt.CERT_CONTEXT[] elements = new WinCrypt.CERT_CONTEXT[cCertContext];
for (int i = 0; i < elements.length; i++) {
elements[i] = (WinCrypt.CERT_CONTEXT) Structure.newInstance(WinCrypt.CERT_CONTEXT.class,
arrayCertContext.getPointer(i * Native.POINTER_SIZE));
elements[i].read();
}
return elements;
}
public void setArrayCertContext(WinCrypt.CERT_CONTEXT[] arrayCertContexts) {
if (arrayCertContexts == null || arrayCertContexts.length == 0) {
arrayCertContext = null;
cCertContext = 0;
} else {
cCertContext = arrayCertContexts.length;
Memory mem = new Memory(Native.POINTER_SIZE * arrayCertContexts.length);
for (int i = 0; i < arrayCertContexts.length; i++) {
mem.setPointer(i * Native.POINTER_SIZE, arrayCertContexts[i].getPointer());
}
arrayCertContext = mem;
}
}
public void setArrayCertStore(WinCrypt.HCERTSTORE[] stores) {
if (stores == null || stores.length == 0) {
arrayCertStore = null;
cCertStore = 0;
} else {
Memory mem = new Memory(Native.POINTER_SIZE * stores.length);
for (int i = 0; i < stores.length; i++) {
mem.setPointer(i * Native.POINTER_SIZE, stores[i].getPointer());
}
cCertStore = stores.length;
arrayCertStore = mem;
}
}
public WinCrypt.HCERTSTORE[] getArrayCertStore() {
if (arrayCertStore == null || cCertStore == 0) {
return new WinCrypt.HCERTSTORE[0];
} else {
WinCrypt.HCERTSTORE[] result = new WinCrypt.HCERTSTORE[cCertStore];
for (int i = 0; i < result.length; i++) {
result[i] = new WinCrypt.HCERTSTORE(arrayCertStore.getPointer(i * Native.POINTER_SIZE));
}
return result;
}
}
#Override
protected List<String> getFieldOrder() {
return fieldOrder;
}
}
}
public void CertSelect() {
Cryptdlg cryptdlg = Cryptdlg.INSTANCE;
...// parentHwnd and hCertStore are initalized and passed to this method
Cryptdlg.CERT_SELECT_STRUCT certSel = new Cryptdlg.CERT_SELECT_STRUCT();
WinCrypt.CERT_CONTEXT[] pContexts = new WinCrypt.CERT_CONTEXT[1];
certSel.hwndParent = parentHwnd;
certSel.szTitle = "title";
certSel.cCertStore = 1;
certSel.setArrayCertStore(new WinCrypt.HCERTSTORE[] {hCertStore});
pCertSelectInfo.cCertContext = 1;
pContexts[0] = new WinCrypt.CERT_CONTEXT.ByReference();
certSel.setArrayCertContext(pContexts);
cryptdlg.CertSelectCertificate(certSel); //line 60
...
}
}
When I call this method I get "java.lang.Error: Invalid memory access" at the dll call cryptdlg.CertSelectCertificate(certSel) at line 60 above.
java.lang.Error: Invalid memory access
at com.sun.jna.Native.invokeInt(Native Method)
at com.sun.jna.Function.invoke(Function.java:419)
at com.sun.jna.Function.invoke(Function.java:354)
at com.sun.jna.Library$Handler.invoke(Library.java:244)
at com.sun.proxy.$Proxy13.CertSelect(Unknown Source)
at com.project.Crypto.CertSelect(Crypto.java:60)
I am not sure why we are getting the exception. I followed the example mentioned here.
[UPDATE]
For what its worth,
When I modify the type of "setArrayCertStore" from Pointer to HCERTSTORE[] I am not getting any exception but no certificate are getting pulled.
It makes me think if arrayCertStore is initalized correctly or not.
WinCrypt.HCERTSTORE[] cStoreArray = new WinCrypt.HCERTSTORE[1];
pCertSelectInfo.cCertStore = 1;
cStoreArray[0] = hCertStore;
pCertSelectInfo.arrayCertStore = cStoreArray;
And the structure definition is changed as follows
public WinCrypt.HCERTSTORE[] arrayCertStore;
And HCRYPTPROV is defined as
public static class HCRYPTPROV extends BaseTSD.ULONG_PTR {
public HCRYPTPROV() {}
public HCRYPTPROV(long value) {
super(value);
}
}
==================================
[EDIT]
After discussion with Daniel and other people. Here is the updated code which works
public class Crypto {
public interface Cryptdlg extends Library {
Cryptdlg INSTANCE = (Cryptdlg) Native.loadLibrary("Cryptdlg", Cryptdlg.class, W32APIOptions.DEFAULT_OPTIONS);
public boolean CertSelectCertificate(CERT_SELECT_STRUCT pCertSelectInfo);
public static class CERT_SELECT_STRUCT extends Structure {
private static final List<String> fieldOrder = createFieldsOrder("dwSize", "hwndParent", "hInstance",
"pTemplateName", "dwFlags", "szTitle", "cCertStore", "arrayCertStore", "szPurposeOid",
"cCertContext", "arrayCertContext", "lCustData", "pfnHook", "pfnFilter", "szHelpFileName",
"dwHelpId", "hprov");
public static class ByReference extends CERT_SELECT_STRUCT implements Structure.ByReference {
}
public int dwSize;
public HWND hwndParent;
public HINSTANCE hInstance;
public String pTemplateName;
public int dwFlags;
public String szTitle;
public int cCertStore;
public Pointer arrayCertStore;
public String szPurposeOid;
public int cCertContext;
public Pointer arrayCertContext;
public WinDef.LPARAM lCustData;
public Pointer pfnHook = null;
public Pointer pfnFilter = null;
public String szHelpFileName;
public int dwHelpId;
public HCRYPTPROV hprov;
public CERT_SELECT_STRUCT() {
super();
}
public WinCrypt.CERT_CONTEXT[] getArrayCertContext() {
WinCrypt.CERT_CONTEXT[] elements = new WinCrypt.CERT_CONTEXT[cCertContext];
for (int i = 0; i < elements.length; i++) {
elements[i] = (WinCrypt.CERT_CONTEXT) Structure.newInstance(WinCrypt.CERT_CONTEXT.class,
arrayCertContext.getPointer(i * Native.POINTER_SIZE));
elements[i].read();
}
return elements;
}
public void setArrayCertContext(WinCrypt.CERT_CONTEXT[] arrayCertContexts) {
if (arrayCertContexts == null || arrayCertContexts.length == 0) {
arrayCertContext = null;
cCertContext = 0;
} else {
cCertContext = arrayCertContexts.length;
Memory mem = new Memory(Native.POINTER_SIZE * arrayCertContexts.length);
for (int i = 0; i < arrayCertContexts.length; i++) {
mem.setPointer(i * Native.POINTER_SIZE, arrayCertContexts[i].getPointer());
}
arrayCertContext = mem;
}
}
public void setArrayCertStore(WinCrypt.HCERTSTORE[] stores) {
if (stores == null || stores.length == 0) {
arrayCertStore = null;
cCertStore = 0;
} else {
Memory mem = new Memory(Native.POINTER_SIZE * stores.length);
for (int i = 0; i < stores.length; i++) {
mem.setPointer(i * Native.POINTER_SIZE, stores[i].getPointer());
}
cCertStore = stores.length;
arrayCertStore = mem;
}
}
public WinCrypt.HCERTSTORE[] getArrayCertStore() {
if (arrayCertStore == null || cCertStore == 0) {
return new WinCrypt.HCERTSTORE[0];
} else {
WinCrypt.HCERTSTORE[] result = new WinCrypt.HCERTSTORE[cCertStore];
for (int i = 0; i < result.length; i++) {
result[i] = new WinCrypt.HCERTSTORE(arrayCertStore.getPointer(i * Native.POINTER_SIZE));
}
return result;
}
}
#Override
public void write() {
this.dwSize = size();
super.write();
}
#Override
protected List<String> getFieldOrder() {
return fieldOrder;
}
}
}
public void CertSelect() {
Cryptdlg cryptdlg = Cryptdlg.INSTANCE;
Cryptdlg.CERT_SELECT_STRUCT certSel = new Cryptdlg.CERT_SELECT_STRUCT();
certSel.hwndParent = parentHwnd;
certSel.szTitle = "title";
certSel.cCertStore = 1;
certSel.setArrayCertStore(new WinCrypt.HCERTSTORE[] {hCertStore});
pCertSelectInfo.cCertContext = 1;
pCertSelectInfo.arrayCertContext = new Memory(Native.POINTER_SIZE);
pCertSelectInfo.arrayCertContext.setPointer(0, Pointer.NULL);
cryptdlg.CertSelectCertificate(certSel);
...
}
}
There are a few potential problem areas.
First, you are mixing the ANSI and Unicode versions.
The CertSelectCertificate() function has two variants, one ending in A and one in W. The -A functions are the ANSI (8-bit characters) while the -W variants are for Unicode/Wide-string (16 bit characters). The main difference in the methods is the number of characters in the strings in the CERT_SELECT_STRUCT structure., which similarly has two variants, CERT_SELECT_STRUCT_A and CERT_SELECT_STRUCT_W.
JNA automatically maps you to the correct version (the -W version in almost all cases in modern operating systems) using its default type mapper. You should probably add that type mapper explicitly in your library loading using the default options for Win32 libraries:
Cryptdlg INSTANCE = (Cryptdlg) Native.loadLibrary("Cryptdlg", Cryptdlg.class,
W32APIOptions.DEFAULT_OPTIONS);
However, you have an explicit call to use the -A type mapper in your CERT_SELECT_STRUCT() constructor:
public CERT_SELECT_STRUCT() {
super(W32APITypeMapper.ASCII);
}
This forces it to use the -A version of the structure, which only has 8 bits per character in its strings. You should just call super().
A second possibility, while not obvious from the docs, is that the first element, dwSize, is supposed to be the size of the structure. You should put that in your constructor:
this.dwSize = this.size();
A third possibility (and the most likely cause, if I were to guess) is in the line when you set the contents of the arrayCertContext field. It is documented as:
A pointer to an array of CERT_CONTEXT structures.
You define the array on the Java side as a structure (which has its own pointer) and manually set it into memory, but instead of populating the CERT_CONTEXT structure you put a Pointer there:
pContexts[0] = new WinCrypt.CERT_CONTEXT.ByReference();
That ends up filling up the first 8 bytes of the "structure" with the pointer address you just created, the first 4 bytes of which are assigned to dwCertEncodingType and the next 4 bytes (plus 4 null bytes) go to the pointer value of a ByteByReference() field.
Also, easier than your allocation of memory, allocation of arrays of structures could be done like this:
WinCrypt.CERT_CONTEXT[] pContextArray =
(WinCrypt.CERT_CONTEXT[]) new WinCrypt.CERT_CONTEXT().toArray(1);
As an aside, you might find structure definitions more streamlined in JNA 5.x (currently 5.6.0) which include a #FieldOrder annotation as a preferred method of creating the field order list.
Related
This question already has answers here:
How to read the value of a private field from a different class in Java?
(14 answers)
Closed 4 years ago.
So guys im trying to access a private Array from another class. Is there a way to access said array without a get-Method for the array?
public class Entity {
private int key;
private int value;
public Entity(int k, int v) {
key = k;
value = v;
}
public int getKey() {
return key;
}
public int getValue() {
return value;
}
public void setValue(int v) {
value = v;
}
public void setKey(int k) // selbst geadded
{
key = k;
}
}
Those are the elements that are contained in the array.
public class Relation {
private Entity[] map;
public Relation(int n) {
map = new Entity[n]; // größe des neuen feldes
}
public int size() {
return map.length;
}
public Entity extract(int i) {
if (i >= map.length || i < 0 || map[i] != null) {
return null;
}
int key = map[i].getKey();
int value = map[i].getValue();
map[i] = null;
return new Entity(key, value);
}
public boolean into(Entity e) {
for (int i = 0; i < size(); i++) {
if (map[i] == null) {
map[i] = e;
return true;
}
}
return false;
}
public static void main(String[] args) {
}
}
Relation is the Method im supposed to use. This class contains the private array which im trying to access.
public class Use {
public static boolean substitute(Relation rel, Entity e) {
if (rel.size() > 0) {
rel.map[0] = e; // "map has private acccess in Relation"
return true;
}
return false;
}
public static Relation eliminate(Relation rel, int k) {
int counter = 0;
for (int i = 0; i < rel.size(); i++) {
if (map[i] != k) // // "cannot find symbol map"
{
counter++;
}
}
}
}
And this is the class in which im trying to access the array. The methods here are not finished yet since im getting errors whenever im trying to access the map in the Relation class in any why since I cant figure it out.
To access fields, you need a FieldInfo:
Type relationType = typeof(Relation);
FieldInfo fieldRelationMap = relationType.GetField("map",
BindingFlags.Instance | BindingFlags.NonPublic);
FieldInfo has a GetValue and a SetValue
I am trying to fill UCFCourse courseOne in my constructor with a courses[] object in fillWithCourses().UCFCourse courseOne does populate outside of the constructor but will not go into it.
public class UCFSemester<courses> {
private static UCFCourse courseOne;
private static double totalSemesters;
private static double completionTime;
static boolean fillSemester = true;
public UCFSemester(UCFCourse courseOne, UCFCourse[] coursetwo) {
this.courseOne = courseOne;
}
public static UCFCourse getcourseOne() {
return courseOne;
}
public static void setCoursesone(UCFCourse courses) {
courseOne = courses;
}
public static void fillWithCourses(UCFCourse courses[], int l) {
int x = 0;
while (fillSemester) {
for (int n = 0; n < 5; n++) {
if (x != n && courses[x].getCourseLevel() < courses[n].getCourseLevel()) {
setCoursesone(courses[x]);
}
}
fillSemester = false;
}
}
}
Side question.How can I access this all in a non-static way?I need the entire thing to be non-static but no matter what I do I can't get it.Thanks!
You can simply do it by creating a List like this:
public class UCFSemester {
private List<UCFCourse> courseList = new ArrayList<>();
public UCFCourse getCourse(int index) {
return courseList.get(index);
}
public void addCourses(UCFCourse[] courses) {
for(int x = 0; x < courses.length; x++) {
courseList.add(courses[x]);
}
}
}
Here, I'm assuming that you are passing the UCFCourse[] array with all the course details that are there in that particular semester.
addCourses() function will take this array and then add all the corresponding courses to the List.
getCourse() function will return you any particular course from the List (Using Index). You can also modify the search in any way you want.
I am trying to build a simple generic class that uses generic objects in java. everything compiles fine, but when i run the code, it doesn't display the objects i passed to it.
Here is my code:
public class ListDriver {
public static void main(String[] args) {
List<String> glist = new List<String>(10);
glist.add("milk");
glist.add("eggs");
System.out.println("Grocery List" + glist.toString());
}
public class List<T> {
private T[] datastore;
private int size;
private int pos;
public List(int numElements) {
size = numElements;
pos = 0;
datastore = (T[]) new Object[size];
}
public void add(T element) {
datastore[pos] = element;
}
public String toString() {
String elements = "";
for (int i = 0; i < pos; ++i) {
elements += datastore[i] + "";
}
return elements;
}
}
}
You don't increment your pos variable, so you're always adding in the same place. Try
public void add(T element) {
datastore[pos++] = element;
}
Your add method always replaces the element in position 0 (zero). You forgot to increment pos (pos++;)
How do you mirror a function on x-Axis in Apache commons math, respectively set f() = -f()?
I found out so far, that you can add functions with FunctionUtils class and i guess i could
do a workaround by taking some points, set y-values negativ and interpolationg new Function,
but that seems a little cumbersome to me. Is there a simpler way?
As all functions are interfaces in org.apache.commons.math3.analysis you can wrap every function you want to invert into an anonymous object implementing that interface.
Here are three examples which should get you started:
/**
* Created for http://stackoverflow.com/q/22929746/1266906
*/
public class MinusFunction {
public static BivariateFunction invert(final BivariateFunction function) {
return new BivariateFunction() {
#Override
public double value(double x, double y) {
return - function.value(x,y);
}
};
}
public static MultivariateFunction invert(final MultivariateFunction function) {
return new MultivariateFunction() {
#Override
public double value(double[] point) {
return -function.value(point);
}
};
}
public static MultivariateMatrixFunction invert(final MultivariateMatrixFunction function) {
return new MultivariateMatrixFunction() {
#Override
public double[][] value(double[] point) {
final double[][] value = function.value(point);
for (int i = 0; i < value.length; i++) {
for (int j = 0; j < value[i].length; j++) {
value[i][j] = -value[i][j];
}
}
return value;
}
};
}
}
For a lot of implementation reasons (Using Java ME 1.4 with very limited libraries), I have no access to HashMap or any kind of Map interface. In combination with this, I have to use Hashtable, which in the libraries I'm using does not inherit anything.
Yes, there is absolutely no way for me to get around the implementation and libraries that I'm using.
So I have two Hashtables. I need to make one new Hashtable instance that accesses and changes the two "backing" instances. Since Hashtable does not inherit anything, is there any way I could do this? I've tried a rudimentary composing strategy that just goes through an array of tables, but there are some serious problems with that. Specifically, put(key, object) is difficult because there's no way to tell which map it is being backed to.
Any suggestions on a strategy to do this or am I stuck?
public class Scope {
private final Hashtable publicVars;
private final Hashtable publicMethods;
private final Hashtable publicReturning;
private final Hashtable privateVars;
private final Hashtable privateMethods;
public Scope() {
publicMethods = new Hashtable();
publicReturning = new Hashtable(0);
publicVars = new Hashtable();
privateVars = new Hashtable();
privateMethods = new Hashtable();
}
public Scope(Scope scope) {
publicVars = scope.publicVars;
publicMethods = scope.publicMethods;
publicReturning = scope.publicReturning;
privateVars = new Hashtable();
privateMethods = new Hashtable();
// Here's my problem - I need changes made to publicVars to also affect scope.privateVars (and the same to methods)
publicVars.putAll(scope.privateVars);
publicMethods.putAll(scope.privateMethods);
}
private static final class MapGroup {
private final List maps = new ArrayList();
public MapGroup(Hashtable start) {
maps.add(start);
}
public MapGroup(MapGroup group) {
for (int x = 0; x < group.maps.size(); x++) {
maps.add(group.maps.get(x));
}
}
public void add(Hashtable h) {
maps.add(h);
}
public Enumeration keys() {
return new Enumeration() {
private final Enumeration[] enumerations;
private int i;
{
enumerations = new Enumeration[maps.size()];
for (int x = 0; x < maps.size(); x++) {
enumerations[x] = ((Hashtable) maps.get(x)).keys();
}
}
public boolean hasMoreElements() {
return enumerations[i].hasMoreElements()
|| (++i < enumerations.length && enumerations[i].hasMoreElements());
}
public Object nextElement() {
// needed to increment i
return hasMoreElements() ? enumerations[i].nextElement() : null;
}
};
}
public Enumeration elements() {
return new Enumeration() {
private final Enumeration[] enumerations;
private int i;
{
enumerations = new Enumeration[maps.size()];
for (int x = 0; x < maps.size(); x++) {
enumerations[x] = ((Hashtable) maps.get(x)).elements();
}
}
public boolean hasMoreElements() {
return enumerations[i].hasMoreElements()
|| (++i < enumerations.length && enumerations[i].hasMoreElements());
}
public Object nextElement() {
// needed to increment i
return hasMoreElements() ? enumerations[i].nextElement() : null;
}
};
}
public boolean contains(Object value) {
for (int x = 0; x < maps.size(); x++) {
if (((Hashtable) maps.get(x)).contains(value)) {
return true;
}
}
return false;
}
public boolean containsKey(Object key) {
for (int x = 0; x < maps.size(); x++) {
if (((Hashtable) maps.get(x)).containsKey(key)) {
return true;
}
}
return false;
}
public Object get(Object key) {
for (int x = 0; x < maps.size(); x++) {
if (((Hashtable) maps.get(x)).containsKey(key)) {
return ((Hashtable) maps.get(x)).get(key);
}
}
return null;
}
public Object put(Object key, Object value) {
for (int x = 0; x < maps.size(); x++) {
if (((Hashtable) maps.get(x)).containsKey(key)) {
return ((Hashtable) maps.get(x)).put(key, value);
}
}
return ((Hashtable) maps.get(maps.size() - 1)).put(key, value);
}
public Object remove(Object key) {
// Nothing is ever removed - don't worry
return null;
}
public void clear() {
}
public int size() {
int s = 0;
for (int x = 0; x < maps.size(); x++) {
s += ((Hashtable) maps.get(x)).size();
}
return s;
}
public boolean isEmpty() {
return size() == 0;
}
}
Thanks for making me have to think about this guys. I wrote this and it works for me.