Windows DXGI Experiment
Jorn Vernee
jorn.vernee at oracle.com
Wed Feb 26 08:29:44 UTC 2025
Your function signature looks incorrect to me. This is also something
that jextract can automatically generate for you FWIW, by including the
structs IDXGIFactory1 and IDXGIFactory1Vtbl. Jextract then generates
nested interfaces inside the IDXGIFactory1Vtbl class, containing the
descriptors needed for each function in the vtable. It looks like
`QueryInterface` has just 3 parameters:
HRESULT (*QueryInterface)(IDXGIFactory1 *, const IID *const, void
**) __attribute__((stdcall));
Jextract also generates an 'invoke' function that can be used to call
these function pointers. For example, here I'm calling `EnumAdapters1`
on the returned factory:
MemorySegment factory =
IDXGIFactory1.reinterpret(factoryPtr.get(C_POINTER, 0L), arena, null);
MemorySegment vtbl = IDXGIFactory1.lpVtbl(factory);
MemorySegment EnumAdapters1 =
IDXGIFactory1Vtbl.EnumAdapters1(vtbl); // get the function pointer
int adapterIndex = 0;
List<MemorySegment> adapters = new ArrayList<>();
MemorySegment adapterPtr = arena.allocate(C_POINTER);
// pass function pointer here to invoke it, together with 3 arguments
while (IDXGIFactory1Vtbl.EnumAdapters1.invoke(EnumAdapters1,
factory, adapterIndex, adapterPtr) != DXGI_ERROR_NOT_FOUND()) {
adapters.add(IDXGIAdapter1.reinterpret(adapterPtr.get(C_POINTER, 0L),
arena, null));
adapterIndex++;
}
System.out.println("Found adapters: " + adapters.size());
Jorn
On 25-2-2025 18:05, Hugo De Vaan wrote:
> Thank you, I was mistaken about the layout, so changing the UUID
> indeed makes the factory creation succeed.
>
> The buffer is a leftover from earlier work in the same class, where I
> tried a more specific DirectX 12 approach (CreateDXGIFactory2 and
> such). Since the September 2020 example in this mailing list is the
> best fitting example I could find, I turned the experiment into an
> earlier DirectX version. I kept some of the other code, which turns
> out to be a mistake, because I mislead myself into trying to find the
> error in the wrong place.
>
> Anyway, since that post I have made some progress, trying to call a
> virtual function as per C instead of C++. Thankfully, Microsoft COM
> objects follow a standard of "pointing to interface -> pointing to
> vtable" on the offsets, so I expected to just follow several pointers
> in succession and be able to get to the functions of the IDXGIFactory.
>
> However, with the addition of Jorn's recommendation, I will change my
> approach. If there is no need to manually 'mess around' with vtable
> mapping, I'd rather have jextract do it for me.
>
> PS: I believe the 2025 way of dereferencing looks _roughly_ like this
> (because I might well be wrong about the getters, perhaps it should
> have been x.address()):
>
> MemorySegment vtable = factory.get(ValueLayout.ADDRESS,
> 0).reinterpret(8, Arena.global(), null);
> MemorySegment fpointer = vtable.get(ValueLayout.ADDRESS,
> 0).reinterpret(8, Arena.global(), null);
>
> FunctionDescriptor fdesc = FunctionDescriptor.of(
> ValueLayout.JAVA_INT, // return value
> ValueLayout.ADDRESS, // vtable reference - not sure if I need this
> ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS //
> parameters);
>
> MethodHandle handle = linker.downcallHandle(fpointer, fdesc);
> System.out.println("Handle to QueryInterface created.");
>
> hresult = (int) handle.invokeExact(vtable, factory, uuidValue, factory);
>
> Anyway, thanks again for the help, it has allowed me to continue my
> FFM experiments.
>
> Kind regards,
> Hugo
More information about the panama-dev
mailing list