Error Running jextract on d3d12.h

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Tue Sep 15 17:35:06 UTC 2020


After throwing the kitchen sink at your example (I set up Windows on a 
virtual instance to play with it), I was able to reproduce the issue.

I discussed this with Jorn offline and Jorn pointed out at an issue that 
I should have spotted much earlier (thanks!) - the issue is that when 
looking at API docs like:

https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-createcommandqueue

This is actually the description of the C++ API.

The C API almost always takes some extra parameter - in the case of this 
function, the first parameter must be a device pointer.

Here's the rewritten example (I took the liberty to streamline the Java 
code a bit, I hope you don't mind):

public class Main {

     public enum IID {
         IID_IDXGIAdapter1(0x29038f61, 0x3839, 0x4626, 0x91, 0xfd, 0x08, 
0x68, 0x79, 0x01, 0x1a, 0x05),
         IID_IDXGIFactory1(0x770aae78, 0xf26f, 0x4dba, 0xa8, 0x29, 0x25, 
0x3c, 0x83, 0xd1, 0xb3, 0x87),
         IID_ID3D12Device(0x189819f1, 0x1db6, 0x4b57, 0xbe, 0x54, 0x18, 
0x21, 0x33, 0x9b, 0x85, 0xf7),
         IID_ID3D12CommandQueue(0x0ec870a6, 0x5d7e, 0x4c22, 0x8c, 0xfc, 
0x5b, 0xaa, 0xe0, 0x76, 0x16, 0xed);

         final MemorySegment guid;

         IID(int data1, int data2, int data3, int... data4) {
             MemorySegment segment = 
MemorySegment.allocateNative(guiddef_h.GUID.$LAYOUT());
             GUID.Data1$set(segment, data1);
             GUID.Data2$set(segment, (short)data2);
             GUID.Data3$set(segment, (short)data3);
             MemorySegment data4_segment = GUID.Data4$slice(segment);
             for (int i = 0 ; i < data4.length ; i++) {
                 MemoryAccess.setByteAtIndex(data4_segment, i, 
(byte)data4[i]);
             }
             this.guid = segment;
         }
     }

     public static void main(String[] args) throws Throwable {
         try (NativeScope scope = NativeScope.unboundedScope()) {
             // IDXGIFactory1** dxgiFactory;
             var ppDxgiFactory = IDXGIFactory1.allocatePointer(scope);
             // HRESULT = CreateDXGIFactory1(_uuid(dxgiFactory), 
&dxgiFactory))
checkResult(dxgi_h.CreateDXGIFactory1(IID.IID_IDXGIFactory1.guid, 
ppDxgiFactory));
             // IDXGIFactory1*
             MemorySegment pDxgiFactory = 
IDXGIFactory1.ofAddressRestricted(MemoryAccess.getAddress(ppDxgiFactory));

             // (This)->lpVtbl
             MemorySegment vtbl = 
IDXGIFactory1Vtbl.ofAddressRestricted(IDXGIFactory1.lpVtbl$get(pDxgiFactory));
             // lpVtbl->EnumAdapters1
             MemoryAddress addrEnumAdapters = 
IDXGIFactory1Vtbl.EnumAdapters1$get(vtbl);

             // link the pointer
             MethodHandle MH_EnumAdapters1 = 
getSystemLinker().downcallHandle(
                     addrEnumAdapters,
                     MethodType.methodType(int.class, 
MemoryAddress.class, int.class, MemoryAddress.class),
                     FunctionDescriptor.of(C_INT, C_POINTER, C_INT, 
C_POINTER));

             /* [annotation][out] _COM_Outptr_  IDXGIAdapter1** */
             MemorySegment ppOut = IDXGIAdapter1.allocatePointer(scope);
             checkResult((int) 
MH_EnumAdapters1.invokeExact(pDxgiFactory.address(), 0, ppOut.address()));
             // IDXGIAdapter1*
             MemorySegment pAdapter = 
IDXGIAdapter1.ofAddressRestricted(MemoryAccess.getAddress(ppOut));

             // (This)->lpVtbl
             MemorySegment vtbl2 = 
IDXGIAdapter1Vtbl.ofAddressRestricted(IDXGIAdapter1.lpVtbl$get(pAdapter));
             // lpVtbl->EnumAdapters1
             // HRESULT(*)(IDXGIAdapter1*,DXGI_ADAPTER_DESC1*)
             MemoryAddress addrGetDesc1 = 
IDXGIAdapter1Vtbl.GetDesc1$get(vtbl2);

             // link the pointer
             MethodHandle MH_GetDesc1 = getSystemLinker().downcallHandle(
                     addrGetDesc1,
                     MethodType.methodType(int.class, 
MemoryAddress.class, MemoryAddress.class),
                     FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER));

             /* DXGI_ADAPTER_DESC1* */
             MemorySegment pDesc = DXGI_ADAPTER_DESC1.allocate(scope);
             checkResult((int) 
MH_GetDesc1.invokeExact(pAdapter.address(), pDesc.address()));

             // print description
             MemorySegment descStr = 
DXGI_ADAPTER_DESC1.Description$slice(pDesc);
             String str = new String(descStr.toByteArray(), 
StandardCharsets.UTF_16LE);
             System.out.println(str);

             //D3D12CreateDevice$MH()
             // ID3D12Device** d3d12Device;
             var ppDevice = ID3D12Device.allocatePointer(scope);

             // D3D12CreateDevice(pAdapter, D3D_FEATURE_LEVEL_11_0, 
IID_PPV_ARGS(&ppDevice))
             checkResult(D3D12CreateDevice(pAdapter, (int) 45056L, 
IID.IID_ID3D12Device.guid, ppDevice));
             // ID3D12Device*
             MemorySegment pDevice = 
ID3D12Device.ofAddressRestricted(MemoryAccess.getAddress(ppDevice));

             // (This)->lpVtbl
             MemorySegment deviceVtbl = 
ID3D12DeviceVtbl.ofAddressRestricted(ID3D12Device.lpVtbl$get(pDevice));

             // lpVtbl->CreateCommandQueue
             MemoryAddress addrCreateCommandQueue = 
ID3D12DeviceVtbl.CreateCommandQueue$get(deviceVtbl);

             // D3D12_COMMAND_QUEUE_DESC queueDesc = {};
             // queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
             // queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
             MemorySegment pQueueDesc = 
D3D12_COMMAND_QUEUE_DESC.allocate(scope);
             //MemorySegment queueDesc = asSegment(pQueueDesc.address(), 
D3D12_COMMAND_QUEUE_DESC.$LAYOUT());
             D3D12_COMMAND_QUEUE_DESC.Type$set(pQueueDesc, 
D3D12_COMMAND_LIST_TYPE_DIRECT());
             D3D12_COMMAND_QUEUE_DESC.Flags$set(pQueueDesc, 
D3D12_COMMAND_QUEUE_FLAG_NONE());

             // link the pointer
             MethodHandle MH_ID3D12Device_CreateCommandQueue = 
getSystemLinker().downcallHandle(
                     addrCreateCommandQueue,
                     MethodType.methodType(int.class, 
MemoryAddress.class, MemoryAddress.class, MemoryAddress.class, 
MemoryAddress.class),
                     FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER, 
C_POINTER, C_POINTER));

             var ppQueue = ID3D12CommandQueue.allocatePointer(scope);

             checkResult((int) 
MH_ID3D12Device_CreateCommandQueue.invokeExact(pDevice.address(), 
pQueueDesc.address(),
                     IID.IID_ID3D12CommandQueue.guid.address(), 
ppQueue.address()));
         }
     }

     private static final int S_OK = 0x00000000;

     private static void checkResult(int result) {
         switch (result) {
             case S_OK -> {}
             default -> throw new IllegalStateException("Unknown result: 
" + String.format("%X8", result));
         }
     }
}


Cheers
Maurizio

On 15/09/2020 11:12, Maurizio Cimadamore wrote:
> Hi Michael,
> You are trying to put a fairly complex example together using the 
> foreign API so (1) thanks for sticking with it and (2) there's no harm 
> in asking :-)
>
> Again, big disclaimer - I'm not on Windows, so I can't test it out - 
> here are some comments from eyeballing your code (although, I can't 
> see anything particularly wrong). The one thing I initially focussed 
> on was this:
>
> var ppQueue = ID3D12CommandQueue.allocatePointer(scope);
>
> This will allocate a 64-bit long memory segment (enough to contain a 
> pointer). But the contents will be blank. But I think this is ok, as 
> the API is probably meant to fill in the pointer to the newly 
> allocated command queue area (e.g. output parameter idiom).
>
> Another thing I noticed is that you do things like:
>
>> MemorySegment pQueueDesc = D3D12_COMMAND_QUEUE_DESC.allocate(scope);
>> MemorySegment queueDesc = asSegment(pQueueDesc.address(), 
>> D3D12_COMMAND_QUEUE_DESC.$LAYOUT()); // <--------
>> D3D12_COMMAND_QUEUE_DESC.Type$set(queueDesc, 
>> D3D12_COMMAND_LIST_TYPE_DIRECT());
>> D3D12_COMMAND_QUEUE_DESC.Flags$set(queueDesc, 
>> D3D12_COMMAND_QUEUE_FLAG_NONE());
>>
>
> I find the second instruction above redundant here. You already have a 
> fully readable/writable segment for the struct, you don't need to go 
> to the extra jump of re-creating another segment from its address. You 
> can just remove that second line and just use pQueueDesc in the two 
> set operations. In other words, you should only use `asSegment` if you 
> get a MemoryAddress from the library, but you want to turn it into a 
> memory segment with certain known size (so that you can read and write 
> from it).
>
>
> Looking at the GUID function, I also see some issues:
>
>> MemorySegment segment = MemorySegment.allocateNative(GUID.map(l -> 
>> ((SequenceLayout) l).withElementCount(8),
>> MemoryLayout.PathElement.groupElement("Data4")));
>>
>>
> This doesn't seem to do anything - the layout you start with already 
> has a sequence layout with 8 elements in "Data4", so you are just 
> replacing that sequence layout with another identical one. That said, 
> this is just a stylistic issue, the main logic of the code seems to be 
> correct in initializing the contents of the segment (you could use, if 
> you wanted a bulk copy to transfer the byte array into "Data4" 
> directly, but that's not necessary to get correctness - can be 
> improved later).
>
>
> Another Java-style comment - you have an Enum defining various IIDs - 
> and then you have a unique mapping between an IID and a segment. I 
> wonder if the MemorySegment could become a field of the IID enum - so 
> that you don't even need the map.
>
>
> That said, I can't find anything obviously "wrong" with your usage of 
> this DX12 API - I've gone back and forth between code and API docs 
> several times to check the various structures and pointers you pass, 
> but it all looks ok. Are you 100% sure that the crash happens in the 
> invokeExact to the CreateCommandQueue? That could suggest one of the 
> following:
>
> 1) the descriptor you use for linking the function is wrong (e.g. 
> wrong argument arity, types) - that doesn't seem to be the case
> 2) the arguments you are passing are wrong (e.g. unitialized 
> args/pointers) - again, this doesn't seem to be the case
> 3) the function pointer itself being linked is wrong - this I have no 
> way to verify
>
> I think it would help to get "crash log" from the VM; that will 
> contain extra stack information, such as what exactly the thread was 
> doing when the VM crashed - this could tell us for instance if the 
> crash occurred inside the dx12 library, or if we didn't even get there 
> - which would suggest that the function pointer to CreateCommandQueue 
> is wrong somehow.
>
>
> I hope this helps a bit. I'm sure we're close.
>
> Cheers
> Maurizio
>
>
>
>
>
> On 15/09/2020 00:05, Michael Ennen wrote:
>> At this point I may be beating a dead horse and should be able to 
>> figure this out from the awesome example you provided but
>> in the case of using "invokeExact" on a MethodHandle, how can one, in 
>> that case, send a GUID as an argument?
>>
>> That is for a global function it was done thusly:
>>
>> checkResult(dxgi_h.CreateDXGIFactory1(GUID(IID.IID_IDXGIFactory1), 
>> ppDxgiFactory));
>>
>> In the case of "invokeExact" it needs a MemoryAddress so I figured it 
>> would just be:
>>
>>      checkResult((int) 
>> MH_ID3D12Device_CreateCommandQueue.invokeExact(pQueueDesc.address(),GUID(IID.IID_ID3D12CommandQueue).address(), 
>> ppQueue.address()));
>>
>> But I am getting an access violation.
>>
>> I am trying to extend the example to create an ID3D12Device and 
>> ID3D12CommandQueue thusly:
>>
>> //D3D12CreateDevice$MH()
>> // ID3D12Device** d3d12Device;
>> var ppDevice = ID3D12Device.allocatePointer(scope);
>>
>> // D3D12CreateDevice(pAdapter, D3D_FEATURE_LEVEL_11_0, 
>> IID_PPV_ARGS(&ppDevice))
>> checkResult(D3D12CreateDevice(pAdapter, (int) 45056L, 
>> GUID(IID.IID_ID3D12Device), ppDevice));
>> // ID3D12Device*
>> MemorySegment pDevice = asSegment(MemoryAccess.getAddress(ppDevice), 
>> ID3D12Device.$LAYOUT());
>>
>> // (This)->lpVtbl
>> MemorySegment deviceVtbl = 
>> asSegment(ID3D12Device.lpVtbl$get(pDevice), ID3D12DeviceVtbl.$LAYOUT());
>>
>> // lpVtbl->CreateCommandQueue
>> MemoryAddress addrCreateCommandQueue = 
>> ID3D12DeviceVtbl.CreateCommandQueue$get(deviceVtbl);
>>
>> // D3D12_COMMAND_QUEUE_DESC queueDesc = {};
>> // queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
>> // queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
>> MemorySegment pQueueDesc =  D3D12_COMMAND_QUEUE_DESC.allocate(scope);
>> MemorySegment queueDesc = asSegment(pQueueDesc.address(), 
>> D3D12_COMMAND_QUEUE_DESC.$LAYOUT());
>> D3D12_COMMAND_QUEUE_DESC.Type$set(queueDesc, 
>> D3D12_COMMAND_LIST_TYPE_DIRECT());
>> D3D12_COMMAND_QUEUE_DESC.Flags$set(queueDesc, 
>> D3D12_COMMAND_QUEUE_FLAG_NONE());
>>
>> // link the pointer
>> MethodHandle MH_ID3D12Device_CreateCommandQueue = 
>> getSystemLinker().downcallHandle(
>> addrCreateCommandQueue,
>> MethodType.methodType(int.class, MemoryAddress.class, 
>> MemoryAddress.class, MemoryAddress.class),
>> FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER, C_POINTER));
>>
>> var ppQueue = ID3D12CommandQueue.allocatePointer(scope);
>>
>> checkResult((int) 
>> MH_ID3D12Device_CreateCommandQueue.invokeExact(pQueueDesc.address(),
>> GUID(IID.IID_ID3D12CommandQueue).address(), ppQueue.address()));
>>
>> Full example here:
>>
>> https://github.com/brcolow/java-dx12/blob/master/src/main/java/com/dx12/DX12.java 
>> <https://urldefense.com/v3/__https://github.com/brcolow/java-dx12/blob/master/src/main/java/com/dx12/DX12.java__;!!GqivPVa7Brio!NNn4WtIsLKjlTcTCh-TY2gYE6mbNNXrzVKMHA4rEupoedndflmeMdLXktTMoasJKTw999Fs$> 
>>
>>
>> Sorry if it's painfully obvious, this is the last question on this 
>> topic I will ask!
>>
>> On Mon, Sep 14, 2020 at 11:45 AM Jorn Vernee <jorn.vernee at oracle.com 
>> <mailto:jorn.vernee at oracle.com>> wrote:
>>
>>     Hi Michael,
>>
>>     Note that I passed -l dxgi to jextract when extracting dxgi.h,
>>     that will making it so the dxgi library is used to link the
>>     functions. d3d12 didn't seem to be needed. Doing that should avoid
>>     the need to manually load the library like you've shown.
>>
>>     This is what I ended up with:
>>
>>     $jdk = ...
>>     nal -Name jextract -Value "$jdk\bin\jextract.exe"
>>     $I = "C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0"
>>     jextract -d out -t org.jextract --filter "dxgi.h" -l dxgi --
>>     "$I\shared\dxgi.h"
>>     jextract -d out -t org.jextract --filter "guiddef.h" --
>>     "$I\shared\guiddef.h"
>>     jar -cf dxgi.jar -C out org
>>
>>     Jorn
>>
>>     On 14/09/2020 19:51, Michael Ennen wrote:
>>>     It worked for me! Awesome!
>>>
>>>     One quick question:
>>>
>>>     I had to add the following:
>>>
>>>             LibraryLookup d3d12 = LibraryLookup.ofLibrary("D3D12");
>>>             LibraryLookup dxgi = LibraryLookup.ofLibrary("dxgi");
>>>
>>>     To get the methods to be wired up, is that expected? I don't see
>>>     it in your example.
>>>
>>>     Thanks again *so much*. This is a fantastic reference to get
>>>     started as it handles some complexities like function
>>>     pointers and the complexities of having a C API that really
>>>     corresponds to a C++ API which seems to be the case
>>>     with DirectX12.
>>>
>>>     On Mon, Sep 14, 2020 at 10:39 AM Michael Ennen
>>>     <mike.ennen at gmail.com <mailto:mike.ennen at gmail.com>> wrote:
>>>
>>>         Ahhh, this makes so much more sense now.
>>>
>>>         Thank you both tremendously.
>>>
>>>         On Mon, Sep 14, 2020 at 6:39 AM Jorn Vernee
>>>         <jorn.vernee at oracle.com <mailto:jorn.vernee at oracle.com>> wrote:
>>>
>>>             Ok, it looks like the formatting got messed up in the
>>>             email, so I've
>>>             uploaded the example here as well:
>>>
>>> http://cr.openjdk.java.net/~jvernee/d3d12_example/Main.java
>>>
>>>             Jorn
>>>
>>>             On 14/09/2020 15:28, Jorn Vernee wrote:
>>>             > I've tried it out on my machine as well (I'm also on
>>>             Windows). Here is
>>>             > a little bit more complete example that prints out the
>>>             adapter
>>>             > description
>>>             >
>>>             > If you have extracted the shared/dxgi.h and the
>>>             shared/guiddef.h
>>>             > headers as well, you can do something like this:
>>>             >
>>>             >
>>>             > import jdk.incubator.foreign.FunctionDescriptor;
>>>             > import jdk.incubator.foreign.MemoryAccess;
>>>             > import jdk.incubator.foreign.MemoryAddress;
>>>             > import jdk.incubator.foreign.MemoryLayout;
>>>             > import jdk.incubator.foreign.MemorySegment;
>>>             > import jdk.incubator.foreign.NativeScope;
>>>             > import org.jextract.dxgi_h;
>>>             > import org.jextract.guiddef_h;
>>>             >
>>>             > import java.lang.invoke.MethodHandle;
>>>             > import java.lang.invoke.MethodType;
>>>             > import java.nio.charset.StandardCharsets;
>>>             >
>>>             > import static jdk.incubator.foreign.CSupport.*;
>>>             > import static org.jextract.dxgi_h.*;
>>>             >
>>>             > public class Main {
>>>             >
>>>             >     public static void main(String[] args)throws
>>>             Throwable {
>>>             >         try (NativeScope scope
>>>             =NativeScope.unboundedScope()) {
>>>             >             // IDXGIFactory1** dxgiFactory;
>>>             > var ppDxgiFactory =IDXGIFactory1.allocatePointer(scope);
>>>             >             // HRESULT =
>>>             CreateDXGIFactory1(_uuid(dxgiFactory),
>>>             > &dxgiFactory))
>>>             >
>>> checkResult(dxgi_h.CreateDXGIFactory1(IID_IDXGIFactory1,ppDxgiFactory)); 
>>>
>>>             >             // IDXGIFactory1* MemorySegment pDxgiFactory
>>>             >
>>> =asSegment(MemoryAccess.getAddress(ppDxgiFactory),IDXGIFactory1.$LAYOUT());
>>>             >
>>>             >             // (This)->lpVtbl MemorySegment vtbl
>>>             >
>>> =asSegment(IDXGIFactory1.lpVtbl$get(pDxgiFactory),IDXGIFactory1Vtbl.$LAYOUT());
>>>             >             // lpVtbl->EnumAdapters1 MemoryAddress
>>>             addrEnumAdapters
>>>             > =IDXGIFactory1Vtbl.EnumAdapters1$get(vtbl);
>>>             >
>>>             >             // link the pointer MethodHandle
>>>             MH_EnumAdapters1
>>>             > =getSystemLinker().downcallHandle(
>>>             >                 addrEnumAdapters,
>>>             >
>>> MethodType.methodType(int.class,MemoryAddress.class,int.class,MemoryAddress.class),
>>>             > FunctionDescriptor.of(C_INT,C_POINTER,C_INT,C_POINTER));
>>>             >
>>>             >             /* [annotation][out] _COM_Outptr_
>>>             IDXGIAdapter1** */
>>>             > MemorySegment ppOut 
>>> =IDXGIAdapter1.allocatePointer(scope);
>>>             >
>>> checkResult((int)MH_EnumAdapters1.invokeExact(pDxgiFactory.address(),0,ppOut.address()));//
>>>
>>>             > IDXGIAdapter1* MemorySegment pAdapter
>>>             >
>>> =asSegment(MemoryAccess.getAddress(ppOut),IDXGIAdapter1.$LAYOUT());
>>>             >
>>>             >             // (This)->lpVtbl MemorySegment vtbl2
>>>             >
>>> =asSegment(IDXGIAdapter1.lpVtbl$get(pAdapter),IDXGIAdapter1Vtbl.$LAYOUT());
>>>             >             // lpVtbl->EnumAdapters1 //
>>>             > HRESULT(*)(IDXGIAdapter1*,DXGI_ADAPTER_DESC1*)
>>>             MemoryAddress
>>>             > addrGetDesc1 =IDXGIAdapter1Vtbl.GetDesc1$get(vtbl2);
>>>             >
>>>             >             // link the pointer MethodHandle MH_GetDesc1
>>>             > =getSystemLinker().downcallHandle(
>>>             >                 addrGetDesc1,
>>>             >
>>> MethodType.methodType(int.class,MemoryAddress.class,MemoryAddress.class),
>>>             > FunctionDescriptor.of(C_INT,C_POINTER,C_POINTER));
>>>             >
>>>             >             /* DXGI_ADAPTER_DESC1* */ MemorySegment pDesc
>>>             > =DXGI_ADAPTER_DESC1.allocate(scope);
>>>             >
>>> checkResult((int)MH_GetDesc1.invokeExact(pAdapter.address(),pDesc.address()));
>>>             >
>>>             >             // print description MemorySegment descStr
>>>             > =DXGI_ADAPTER_DESC1.Description$slice(pDesc);
>>>             >             String str =new
>>>             > String(descStr.toByteArray(),StandardCharsets.UTF_16LE);
>>>             >             System.out.println(str);
>>>             >         }
>>>             >     }
>>>             >
>>>             >     public static MemorySegment asSegment(MemoryAddress
>>>             > addr,MemoryLayout layout) {
>>>             >         return MemorySegment.ofNativeRestricted(addr,
>>>             > layout.byteSize(),Thread.currentThread(),null,null);
>>>             >     }
>>>             >
>>>             >     static final MemorySegment IID_IDXGIFactory1 =GUID(
>>>             >             (int)0x770aae78,
>>>             >             (short)0xf26f,
>>>             >             (short)0x4dba,
>>>             >             new byte[]{(byte)0xa8,0x29,0x25,0x3c,
>>>             (byte)0x83,
>>>             > (byte)0xd1, (byte)0xb3, (byte)0x87});
>>>             >
>>>             >     static final MemorySegment GUID(int Data1,short
>>>             Data2,short
>>>             > Data3,byte[] Data4) {
>>>             >         MemorySegment ms
>>>             > =MemorySegment.allocateNative(guiddef_h.GUID.$LAYOUT());
>>>             >         guiddef_h.GUID.Data1$set(ms, Data1);
>>>             >         guiddef_h.GUID.Data2$set(ms, Data2);
>>>             >         guiddef_h.GUID.Data3$set(ms, Data3);
>>>             >
>>> guiddef_h.GUID.Data4$slice(ms).copyFrom(MemorySegment.ofArray(Data4));
>>>             >         return ms;
>>>             >     }
>>>             >
>>>             >     private static final int S_OK =0x00000000;
>>>             >
>>>             >     private static void checkResult(int result) {
>>>             >         switch (result) {
>>>             >             case S_OK -> {}
>>>             >             default ->throw new
>>>             IllegalStateException("Unknown result:
>>>             > " +String.format("%X8", result));
>>>             >         }
>>>             >     }
>>>             > }
>>>             >
>>>             >
>>>             > Which on my machine prints: NVIDIA GeForce GTX 1050 Ti
>>>             >
>>>             > HTH,
>>>             > Jorn
>>>             >
>>>             > On 14/09/2020 12:52, Maurizio Cimadamore wrote:
>>>             >> I think there's something off in here:
>>>             >>
>>>             >>> MemorySegment segment =
>>>             >>>
>>> MemorySegment.allocateNative(dxgi_h.IDXGIFactory1Vtbl.$LAYOUT().byteSize());
>>>
>>>             >>>
>>>             >>> MemoryAddress address = 
>>> segment.address().addOffset(64);
>>>             >> I see a couple of issues:
>>>             >>
>>>             >> 1) how do you determine that the offset of the
>>>             function address you
>>>             >> want to obtain is 64 byte from the start? Didn't
>>>             jextract give you a
>>>             >> getter for that?
>>>             >>
>>>             >> 2) Even assuming 64 byte is the correct offset, note
>>>             that the segment
>>>             >> will be initialized to all zeros - I presume this
>>>             vtable must be
>>>             >> filled in somehow, or perhaps obtained from a global
>>>             variable?
>>>             >>
>>>             >> From your earlier email I see this:
>>>             >>
>>>             >>> interface IDXGIFactory
>>>             >>>       {
>>>             >>>           CONST_VTBL struct IDXGIFactoryVtbl *lpVtbl;
>>>             >>>       };
>>>             >> So... perhaps once yo create a IDXGIFactory, you can
>>>             just grab the
>>>             >> pointer to the vtable by accessing its `lpVtbl` field
>>>             - no need to
>>>             >> allocate a new segment (the library has done the
>>>             allocation for you).
>>>             >>
>>>             >> If I'm correct, this can be achieved with something
>>>             like (not sure if
>>>             >> the names are going to be 100% correct since I don't
>>>             have a
>>>             >> jextracted version of the API with me - so beware, I
>>>             have NOT tested
>>>             >> this :-) ):
>>>             >>
>>>             >> var dxgiFactoryPtr =
>>>             >>
>>> MemoryAccess.getAddress(MemorySegment.ofNativeRestricted(),
>>>             >> dxgiFactory);
>>>             >> var lpVtbl =
>>>             >>
>>> MemoryAccess.getAddress(MemorySegment.ofNativeRestricted(),
>>>             >> dxgiFactoryPtr);
>>>             >> var vtable = RuntimeHelper.ofArrayRestricted(lpVtbl,
>>>             >> IDXGIFactory1Vtbl.$LAYOUT(), 1); //1
>>>             >> var address = 
>>> IDXGIFactory1Vtbl$EnumAdapters$get(vtable);
>>>             >>
>>>             >>
>>>             >> And this should give the address pointer you are
>>>             looking for. We need
>>>             >> to smooth the edges especially around (1) - e.g. to
>>>             turn a random
>>>             >> native pointer into a struct with given layout
>>>             (jextract should
>>>             >> generate a static helper for that, see [1]) - but with
>>>             the code above
>>>             >> you should be able to get there, I hope.
>>>             >>
>>>             >> P.S.
>>>             >> In these situations, my suggestion is, especially when
>>>             attacking a
>>>             >> native library for the first time, to always try the
>>>             library directly
>>>             >> using C and see what happens, to understand exactly
>>>             what kind of
>>>             >> pattern/idiom the library requires. I did that many
>>>             times and
>>>             >> realized my assumptions on how library worked were
>>>             wrong; other users
>>>             >> have posted similar instances in this mailing list.
>>>             Once you get
>>>             >> things working in C, porting the code in Java using
>>>             the Panama API is
>>>             >> typically a trivial matter.
>>>             >>
>>>             >> Maurizio
>>>             >>
>>>             >> [1] - https://bugs.openjdk.java.net/browse/JDK-8253102
>>>             >>
>>>             >>
>>>             >> On 13/09/2020 02:37, Michael Ennen wrote:
>>>             >>> Well, progress of a kind? This crashes the VM instead
>>>             of not
>>>             >>> compiling or
>>>             >>> throwing an exception:
>>>             >>>
>>>             >>> // IDXGIFactory1** dxgiFactory;
>>>             >>> var dxgiFactory = scope.allocate(C_POINTER);
>>>             >>> // HRESULT = CreateDXGIFactory1(_uuid(dxgiFactory),
>>>             &dxgiFactory))
>>>             >>> int hresult =
>>> dxgi_h.CreateDXGIFactory1(GUID(IID.IID_IDXGIFactory1),
>>>             >>> dxgiFactory);
>>>             >>> System.out.println("hresult: " + hresult);
>>>             >>> var dxgiAdapter = scope.allocate(C_POINTER);
>>>             >>> System.out.println("IDXGIFactory1Vtbl byte size: " +
>>>             >>> dxgi_h.IDXGIFactory1Vtbl.$LAYOUT().byteSize()); //112
>>>             >>> MemorySegment segment =
>>>             >>>
>>> MemorySegment.allocateNative(dxgi_h.IDXGIFactory1Vtbl.$LAYOUT().byteSize());
>>>
>>>             >>>
>>>             >>> MemoryAddress address = 
>>> segment.address().addOffset(64);
>>>             >>> FunctionDescriptor functionDescriptor =
>>>             FunctionDescriptor.of(C_INT,
>>>             >>> C_INT,
>>>             >>> C_POINTER);
>>>             >>> MethodType methodType =
>>>             MethodType.methodType(int.class, int.class,
>>>             >>> MemoryAddress.class);
>>>             >>> MethodHandle methodHandle =
>>>             getSystemLinker().downcallHandle(address,
>>>             >>> methodType, functionDescriptor);
>>>             >>> try {
>>>             >>> methodHandle.invokeWithArguments(0,
>>>             dxgiAdapter.address());
>>>             >>> } catch (Throwable throwable) {
>>>             >>> throwable.printStackTrace();
>>>             >>> }
>>>             >>>
>>>             >>> On Sat, Sep 12, 2020 at 6:34 PM Michael Ennen
>>>             <mike.ennen at gmail.com <mailto:mike.ennen at gmail.com>>
>>>             >>> wrote:
>>>             >>>
>>>             >>>> I think I see why. It's because I am passing in a
>>>             MemorySegment,
>>>             >>>> which is
>>>             >>>> the dxgiAdapter which I initialize thusly:
>>>             >>>>
>>>             >>>> var dxgiAdapter = scope.allocate(C_POINTER);
>>>             >>>>
>>>             >>>> I guess I need to make it a MemoryAddress instead.
>>>             >>>>
>>>             >>>> On Sat, Sep 12, 2020 at 2:25 PM Michael Ennen
>>>             <mike.ennen at gmail.com <mailto:mike.ennen at gmail.com>>
>>>             >>>> wrote:
>>>             >>>>
>>>             >>>>> Thanks so much Ty. That's super helpful. I think I
>>>             was able to
>>>             >>>>> make quite
>>>             >>>>> a bit of progress:
>>>             >>>>>
>>>             >>>>> var dxgiAdapter = scope.allocate(C_POINTER);
>>>             >>>>> System.out.println("IDXGIFactory1Vtbl byte size: " +
>>>             >>>>> dxgi_h.IDXGIFactory1Vtbl.$LAYOUT().byteSize());
>>>             >>>>> MemorySegment segment =
>>>             >>>>>
>>> MemorySegment.allocateNative(dxgi_h.IDXGIFactory1Vtbl.$LAYOUT().byteSize());
>>>
>>>             >>>>>
>>>             >>>>> MemoryAddress address =
>>>             segment.address().addOffset(64);
>>>             >>>>> FunctionDescriptor functionDescriptor =
>>>             FunctionDescriptor.of(C_INT,
>>>             >>>>> C_INT, C_POINTER);
>>>             >>>>> MethodType methodType =
>>>             MethodType.methodType(int.class, int.class,
>>>             >>>>> MemoryAddress.class);
>>>             >>>>> MethodHandle methodHandle =
>>>             getSystemLinker().downcallHandle(address,
>>>             >>>>> methodType, functionDescriptor);
>>>             >>>>> try {
>>>             >>>>> methodHandle.invokeWithArguments(0, dxgiAdapter);
>>>             >>>>> } catch (Throwable throwable) {
>>>             >>>>> throwable.printStackTrace();
>>>             >>>>> }
>>>             >>>>>
>>>             >>>>> Note that the EnumAdapters1 function signature is
>>>             actually:
>>>             >>>>>
>>>             >>>>> HRESULT EnumAdapters1(
>>>             >>>>>    UINT          Adapter,
>>>             >>>>>    IDXGIAdapter1 **ppAdapter
>>>             >>>>> );
>>>             >>>>>
>>>             >>>>>
>>>             >>>>> So that's why I went with:
>>>             >>>>>
>>>             >>>>> FunctionDescriptor functionDescriptor =
>>>             FunctionDescriptor.of(C_INT,
>>>             >>>>> C_INT, C_POINTER);
>>>             >>>>>
>>>             >>>>> and then
>>>             >>>>>
>>>             >>>>> methodHandle.invokeWithArguments(0, dxgiAdapter);
>>>             >>>>>
>>>             >>>>> I did some fancy stuff as per your suggestion which
>>>             I feel should be
>>>             >>>>> getting the address of the EumAdapters1 function
>>>             >>>>> pointer (basically start at the base address of the
>>>             struct and
>>>             >>>>> then move
>>>             >>>>> 64 bytes past, which should be the 8th function
>>>             >>>>> pointer which in this case is EnumAdapters1).
>>>             >>>>>
>>>             >>>>> I do get the following exception on invoking the
>>>             method handle,
>>>             >>>>> though:
>>>             >>>>>
>>>             >>>>> hresult: 0
>>>             >>>>> factory: MemorySegment{ id=0x3898fd8a limit: 8 }
>>>             >>>>> IDXGIFactory1Vtbl byte size: 112
>>>             >>>>> java.lang.ClassCastException: Cannot cast
>>>             >>>>> jdk.internal.foreign.NativeMemorySegmentImpl to
>>>             >>>>> jdk.incubator.foreign.MemoryAddress
>>>             >>>>>          at
>>>             java.base/java.lang.Class.cast(Class.java:3816)
>>>             >>>>>          at
>>>             >>>>>
>>> java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733)
>>>
>>>             >>>>>
>>>             >>>>>          at com.dx12.DX12.main(DX12.java:91)
>>>             >>>>>          at
>>>             >>>>>
>>> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native
>>>
>>>             >>>>>
>>>             >>>>> Method)
>>>             >>>>>          at
>>>             >>>>>
>>> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
>>>
>>>             >>>>>
>>>             >>>>>          at
>>>             >>>>>
>>> java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>>>
>>>             >>>>>
>>>             >>>>>          at
>>>             >>>>>
>>> java.base/java.lang.reflect.Method.invoke(Method.java:564)
>>>             >>>>>          at
>>>             >>>>>
>>> jdk.compiler/com.sun.tools.javac.launcher.Main.execute(Main.java:415)
>>>             >>>>>          at
>>>             >>>>>
>>> jdk.compiler/com.sun.tools.javac.launcher.Main.run(Main.java:192)
>>>             >>>>>          at
>>>             >>>>>
>>> jdk.compiler/com.sun.tools.javac.launcher.Main.main(Main.java:132)
>>>             >>>>> vh:
>>> VarHandle[varType=jdk.incubator.foreign.MemoryAddress,
>>>             >>>>> coord=[interface 
>>> jdk.incubator.foreign.MemorySegment]]
>>>             >>>>>
>>>             >>>>> Any more assistance would be greatly appreciate but
>>>             undeserved :).
>>>             >>>>>
>>>             >>>>>
>>>             >>>>> On Sat, Sep 12, 2020 at 1:41 AM Ty Young
>>>             <youngty1997 at gmail.com <mailto:youngty1997 at gmail.com>>
>>>             >>>>> wrote:
>>>             >>>>>
>>>             >>>>>> Not a JDK developer, but if you want to do this by
>>>             hand(aka no
>>>             >>>>>> jextract), I had to do this for NVAPI which
>>>             obfuscates function
>>>             >>>>>> pointers
>>>             >>>>>> using keys, e.g.:
>>>             >>>>>>
>>>             >>>>>>
>>>             >>>>>> nvapi_h.nvapi_QueryInterface(0x0150e828);
>>>             >>>>>>
>>>             >>>>>>
>>>             >>>>>> where "0x0150e828" is the "NvAPI_Initialize"
>>>             function key as per the
>>>             >>>>>> Open Source headers Nvidia released sometime ago.
>>>             >>>>>>
>>>             >>>>>>
>>>             >>>>>> The only difference is that, since the function
>>>             pointer is in a
>>>             >>>>>> struct,
>>>             >>>>>> you need to get the segment in the struct
>>>             containing the function
>>>             >>>>>> pointer(see "slice" MemorySegment method) and
>>>             actually read from it
>>>             >>>>>> using a VarHandle. You then take that
>>>             MemoryAddress, with a
>>>             >>>>>> FunctionDescriptor and MethodType, and create a
>>>             MethodHandle. For
>>>             >>>>>> reference, this my working code("NativeFunction" and
>>>             >>>>>> "NativeTypes" do
>>>             >>>>>> not exist in Panama, those are mine but they dont
>>>             matter) for the
>>>             >>>>>> NvAPI_Initalize API:
>>>             >>>>>>
>>>             >>>>>>
>>>             >>>>>> public class NvAPI_Initialize implements
>>>             NativeFunction
>>>             >>>>>> {
>>>             >>>>>>       private final MemoryAddress address;
>>>             >>>>>>       private final FunctionDescriptor descriptor;
>>>             >>>>>>       private final MethodType type;
>>>             >>>>>>
>>>             >>>>>>       private final MethodHandle handle;
>>>             >>>>>>
>>>             >>>>>>       public NvAPI_Initialize() throws
>>>             NoSuchMethodException,
>>>             >>>>>> Throwable
>>>             >>>>>>       {
>>>             >>>>>>           this.address =
>>>             nvapi_h.nvapi_QueryInterface(0x0150e828);
>>>             >>>>>>
>>>             >>>>>>           this.descriptor =
>>>             FunctionDescriptor.of(NativeTypes.INT);
>>>             >>>>>>
>>>             >>>>>>           this.type =
>>>             MethodType.methodType(int.class);
>>>             >>>>>>
>>>             >>>>>>           this.handle =
>>>             >>>>>>
>>> CSupport.getSystemLinker().downcallHandle(this.address,
>>>             this.type,
>>>             >>>>>> this.descriptor);
>>>             >>>>>>       }
>>>             >>>>>>
>>>             >>>>>>       // etc
>>>             >>>>>>
>>>             >>>>>> }
>>>             >>>>>>
>>>             >>>>>>
>>>             >>>>>> It looks like in your case the FunctionDescriptor
>>>             would be:
>>>             >>>>>>
>>>             >>>>>>
>>>             >>>>>> this.descriptor =
>>>             FunctionDescriptor.of(CSupport.C_POINTER,
>>>             >>>>>> CSupport.C_INT, CSupport.C_POINTER);
>>>             >>>>>>
>>>             >>>>>>
>>>             >>>>>> for MethodType:
>>>             >>>>>>
>>>             >>>>>>
>>>             >>>>>> MethodType.methodType(MemoryAddress.class, 
>>> int.class,
>>>             >>>>>> MemoryAddress.class);
>>>             >>>>>>
>>>             >>>>>>
>>>             >>>>>> where the first argument takes in a IDXGIFactory,
>>>             the second an
>>>             >>>>>> unsigned
>>>             >>>>>> int, and the third a pointer to what looks like an
>>>             opaque device
>>>             >>>>>> that
>>>             >>>>>> you pass to other functions.
>>>             >>>>>>
>>>             >>>>>>
>>>             >>>>>> If you haven't already, it might help to make
>>>             bindings with a
>>>             >>>>>> smaller,
>>>             >>>>>> less complicated library just to get a feel with
>>>             how things work
>>>             >>>>>> under
>>>             >>>>>> the hood.
>>>             >>>>>>
>>>             >>>>>>
>>>             >>>>>> Hope this helps.
>>>             >>>>>>
>>>             >>>>>>
>>>             >>>>>> On 9/12/20 2:23 AM, Michael Ennen wrote:
>>>             >>>>>>> Looking into this a bit further I think I chose a
>>>             really bad
>>>             >>>>>>> library to
>>>             >>>>>>> start with as the function I need to call,
>>>             EnumAdapters, is inside
>>>             >>>>>>> some type of "VTbl" struct that is trying to
>>>             emulate a C++ class
>>>             >>>>>>> with
>>>             >>>>>>> virtual functions. What jextract is returning is
>>>             most likely
>>>             >>>>>>> *correct*
>>>             >>>>>>> but in this case so complicated because of how it
>>>             is laid out in
>>>             >>>>>>> C. It
>>>             >>>>>> is
>>>             >>>>>>> not clear at all how to grab the EnumAdapters
>>>             function from
>>>             >>>>>>> this mess, and it is probably above my head.
>>>             >>>>>>>
>>>             >>>>>>> EXTERN_C const IID IID_IDXGIFactory;
>>>             >>>>>>>
>>>             >>>>>>> #if defined(__cplusplus) && !defined(CINTERFACE)
>>>             >>>>>>>
>>>             >>>>>>>
>>> MIDL_INTERFACE("7b7166ec-21c7-44ae-b21a-c9ae321ae369")
>>>             >>>>>>>       IDXGIFactory : public IDXGIObject
>>>             >>>>>>>       {
>>>             >>>>>>>       public:
>>>             >>>>>>>           virtual HRESULT STDMETHODCALLTYPE
>>>             EnumAdapters(
>>>             >>>>>>>               /* [in] */ UINT Adapter,
>>>             >>>>>>>               /* [annotation][out] */
>>>             >>>>>>> _COM_Outptr_ IDXGIAdapter **ppAdapter) = 0;
>>>             >>>>>>>
>>>             >>>>>>>           virtual HRESULT STDMETHODCALLTYPE
>>>             MakeWindowAssociation(
>>>             >>>>>>>               HWND WindowHandle,
>>>             >>>>>>>               UINT Flags) = 0;
>>>             >>>>>>>
>>>             >>>>>>>           virtual HRESULT STDMETHODCALLTYPE
>>>             GetWindowAssociation(
>>>             >>>>>>>               /* [annotation][out] */
>>>             >>>>>>>               _Out_ HWND *pWindowHandle) = 0;
>>>             >>>>>>>
>>>             >>>>>>>           virtual HRESULT STDMETHODCALLTYPE
>>>             CreateSwapChain(
>>>             >>>>>>>               /* [annotation][in] */
>>>             >>>>>>>               _In_ IUnknown *pDevice,
>>>             >>>>>>>               /* [annotation][in] */
>>>             >>>>>>>               _In_ DXGI_SWAP_CHAIN_DESC *pDesc,
>>>             >>>>>>>               /* [annotation][out] */
>>>             >>>>>>> _COM_Outptr_ IDXGISwapChain **ppSwapChain) = 0;
>>>             >>>>>>>
>>>             >>>>>>>           virtual HRESULT STDMETHODCALLTYPE
>>>             CreateSoftwareAdapter(
>>>             >>>>>>>               /* [in] */ HMODULE Module,
>>>             >>>>>>>               /* [annotation][out] */
>>>             >>>>>>> _COM_Outptr_ IDXGIAdapter **ppAdapter) = 0;
>>>             >>>>>>>
>>>             >>>>>>>       };
>>>             >>>>>>>
>>>             >>>>>>>
>>>             >>>>>>> #else /* C style interface */
>>>             >>>>>>>
>>>             >>>>>>>       typedef struct IDXGIFactoryVtbl
>>>             >>>>>>>       {
>>>             >>>>>>> BEGIN_INTERFACE
>>>             >>>>>>>
>>>             >>>>>>>           HRESULT ( STDMETHODCALLTYPE
>>>             *QueryInterface )(
>>>             >>>>>>> IDXGIFactory * This,
>>>             >>>>>>>               /* [in] */ REFIID riid,
>>>             >>>>>>>               /* [annotation][iid_is][out] */
>>>             >>>>>>> _COM_Outptr_  void **ppvObject);
>>>             >>>>>>>
>>>             >>>>>>>           ULONG ( STDMETHODCALLTYPE *AddRef )(
>>>             >>>>>>> IDXGIFactory * This);
>>>             >>>>>>>
>>>             >>>>>>>           ULONG ( STDMETHODCALLTYPE *Release )(
>>>             >>>>>>> IDXGIFactory * This);
>>>             >>>>>>>
>>>             >>>>>>>           HRESULT ( STDMETHODCALLTYPE
>>>             *SetPrivateData )(
>>>             >>>>>>> IDXGIFactory * This,
>>>             >>>>>>>               /* [annotation][in] */
>>>             >>>>>>>               _In_ REFGUID Name,
>>>             >>>>>>>               /* [in] */ UINT DataSize,
>>>             >>>>>>>               /* [annotation][in] */
>>>             >>>>>>> _In_reads_bytes_(DataSize)  const void *pData);
>>>             >>>>>>>
>>>             >>>>>>>           HRESULT ( STDMETHODCALLTYPE
>>>             *SetPrivateDataInterface )(
>>>             >>>>>>> IDXGIFactory * This,
>>>             >>>>>>>               /* [annotation][in] */
>>>             >>>>>>>               _In_ REFGUID Name,
>>>             >>>>>>>               /* [annotation][in] */
>>>             >>>>>>> _In_opt_  const IUnknown *pUnknown);
>>>             >>>>>>>
>>>             >>>>>>>           HRESULT ( STDMETHODCALLTYPE
>>>             *GetPrivateData )(
>>>             >>>>>>> IDXGIFactory * This,
>>>             >>>>>>>               /* [annotation][in] */
>>>             >>>>>>>               _In_ REFGUID Name,
>>>             >>>>>>>               /* [annotation][out][in] */
>>>             >>>>>>> _Inout_  UINT *pDataSize,
>>>             >>>>>>>               /* [annotation][out] */
>>>             >>>>>>> _Out_writes_bytes_(*pDataSize)  void *pData);
>>>             >>>>>>>
>>>             >>>>>>>           HRESULT ( STDMETHODCALLTYPE *GetParent )(
>>>             >>>>>>> IDXGIFactory * This,
>>>             >>>>>>>               /* [annotation][in] */
>>>             >>>>>>>               _In_ REFIID riid,
>>>             >>>>>>>               /* [annotation][retval][out] */
>>>             >>>>>>> _COM_Outptr_  void **ppParent);
>>>             >>>>>>>
>>>             >>>>>>>           HRESULT ( STDMETHODCALLTYPE
>>>             *EnumAdapters )(
>>>             >>>>>>> IDXGIFactory * This,
>>>             >>>>>>>               /* [in] */ UINT Adapter,
>>>             >>>>>>>               /* [annotation][out] */
>>>             >>>>>>> _COM_Outptr_ IDXGIAdapter **ppAdapter);
>>>             >>>>>>>
>>>             >>>>>>>           HRESULT ( STDMETHODCALLTYPE
>>>             *MakeWindowAssociation )(
>>>             >>>>>>> IDXGIFactory * This,
>>>             >>>>>>>               HWND WindowHandle,
>>>             >>>>>>>               UINT Flags);
>>>             >>>>>>>
>>>             >>>>>>>           HRESULT ( STDMETHODCALLTYPE
>>>             *GetWindowAssociation )(
>>>             >>>>>>> IDXGIFactory * This,
>>>             >>>>>>>               /* [annotation][out] */
>>>             >>>>>>>               _Out_ HWND *pWindowHandle);
>>>             >>>>>>>
>>>             >>>>>>>           HRESULT ( STDMETHODCALLTYPE
>>>             *CreateSwapChain )(
>>>             >>>>>>> IDXGIFactory * This,
>>>             >>>>>>>               /* [annotation][in] */
>>>             >>>>>>>               _In_ IUnknown *pDevice,
>>>             >>>>>>>               /* [annotation][in] */
>>>             >>>>>>>               _In_ DXGI_SWAP_CHAIN_DESC *pDesc,
>>>             >>>>>>>               /* [annotation][out] */
>>>             >>>>>>> _COM_Outptr_ IDXGISwapChain **ppSwapChain);
>>>             >>>>>>>
>>>             >>>>>>>           HRESULT ( STDMETHODCALLTYPE
>>>             *CreateSoftwareAdapter )(
>>>             >>>>>>> IDXGIFactory * This,
>>>             >>>>>>>               /* [in] */ HMODULE Module,
>>>             >>>>>>>               /* [annotation][out] */
>>>             >>>>>>> _COM_Outptr_ IDXGIAdapter **ppAdapter);
>>>             >>>>>>>
>>>             >>>>>>> END_INTERFACE
>>>             >>>>>>>       } IDXGIFactoryVtbl;
>>>             >>>>>>>
>>>             >>>>>>>       interface IDXGIFactory
>>>             >>>>>>>       {
>>>             >>>>>>>           CONST_VTBL struct IDXGIFactoryVtbl 
>>> *lpVtbl;
>>>             >>>>>>>       };
>>>             >>>>>>>
>>>             >>>>>>>
>>>             >>>>>
>>>             >>>>> --
>>>             >>>>> Michael Ennen
>>>             >>>>>
>>>             >>>>
>>>             >>>> --
>>>             >>>> Michael Ennen
>>>             >>>>
>>>             >>>
>>>
>>>
>>>
>>>         --         Michael Ennen
>>>
>>>
>>>
>>>     --     Michael Ennen
>>
>>
>>
>> -- 
>> Michael Ennen


More information about the panama-dev mailing list