I was trying to map the function D2D1CreateFactory from the DLL D2D1.dll. From there I want to build up on creating a Direct2D Java mapping, but that's off-topic. I so far had this:
public WinNT.HRESULT D2D1CreateFactory(int factoryType, REFIID riid, ID2D1Factory.ByReference ppIFactory);
The ID2D1Factory looks like this:
public class ID2D1Factory extends IUnknown {
public ID2D1Factory() { }
public ID2D1Factory(Pointer pvInstance) {
super(pvInstance);
}
}
When I try to run my code using the code below, "java.lang.Error: Invalid memory access" is thrown (when turning on JNA.setProtected()).
The code to run:
ID2D1Factory.ByReference ref= new ID2D1Factory.ByReference();
D2D1.INSTANCE.D2D1CreateFactory(0, new REFIID(new IID("06152247-6f50-465a-9245-118bfd3b6007").toByteArray()), ref);
I have no clue why. Is there anything I am doing wrong?
EDIT: Thanks to technomage I was able to get the correct method declaration. The method should be declared like this:
public WinNT.HRESULT D2D1CreateFactory(int factoryType, REFIID riid, D2D1_FACTORY_OPTIONS opts, PointerByReference pref);
The D2D1_FACTORY_OPTIONS structure was mapped as following:
public static class D2D1_FACTORY_OPTIONS extends Structure {
public int debugLevel;
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "debugLevel" });
}
public D2D1_FACTORY_OPTIONS() {}
public D2D1_FACTORY_OPTIONS(int size) {
super(new Memory(size));
}
public D2D1_FACTORY_OPTIONS(Pointer memory) {
super(memory);
read();
}
}
Finally, the snippet to call the method:
D2D1_FACTORY_OPTIONS opts = new D2D1_FACTORY_OPTIONS();
PointerByReference pp = new PointerByReference();
D2D1.INSTANCE.D2D1CreateFactory(0, new REFIID(new IID("06152247-6f50-465a-9245-118bfd3b6007").toByteArray()), opts, pp);
According to this reference, D2D1CreateFactory
requires pointer types as third and fourth arguments (you are declaring only three arguments).
Assuming you insert the options pointer (a simple struct *
), your final argument needs to be PointerByReference
, since the function will be "returning" a pointer value in the address that you give it.
You can then use PointerByReference.getValue()
to initialize a new ID2D1Factory
instance (the Structure.ByReference
in this case is superfluous, since by default all structures as function parameters are treated as struct *
by JNA unless explicitly defined otherwise).
public WinNT.HRESULT D2D1CreateFactory(int factoryType, REFIID riid, D2D1_FACTORY_OPTIONS options, ID2D1Factory ppIFactory);
public class D2D1_FACTORY_OPTIONS extends Structure { ... }
D2D1_FACTORY_OPTIONS options = ...;
PointerByReference pref = new PointerByReference();
D2D1.INSTANCE.D2D1CreateFactory(0, new REFIID(...), options, pref);
ID2D1Factory factory = new ID2D1Factory(pref.getValue());
And don't forget to call Structure.read()
in your ID2D1Factory(Pointer)
ctor.