News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

How to release the COM interfaces (64-bit)?

Started by aw27, January 17, 2018, 12:49:14 AM

Previous topic - Next topic

aw27

I know how to make it work, but am testing the UASM facilities.
In the code below pAdapter->Release() and pOutput->Release() are not accepted.
I can not add Release, QueryInterface and AddRef to the interface because it complains.
Using _VCOMINVOKE appears to be a black art  :dazzled: , I can't make it work at all (no examples also).


OPTION LITERALS:ON

HRESULT TYPEDEF DWORD
HWND TYPEDEF PTR
HMODULE TYPEDEF PTR
LPVOID TYPEDEF PTR VOID

includelib \masm32\lib64\msvcrt.lib
printf PROTO :PTR, :VARARG
wprintf PROTO :PTR, :VARARG
memset PROTO :ptr, :dword, :qword
includelib \masm32\lib64\kernel32.lib
LoadLibraryA PROTO :PTR
GetProcAddress PROTO :HMODULE, :PTR
FreeLibrary PROTO :HMODULE
ExitProcess PROTO :DWORD

CreateDXGIFactory TYPEDEF PROTO :ptr, :ptr

PIDXGIFactory TYPEDEF PTR IDXGIFactory
COMINTERFACE IDXGIFactory
CVIRTUAL SetPrivateData, DWORD, :PTR, :DWORD, :PTR
CVIRTUAL SetPrivateDataInterface, DWORD, :PTR, :PTR
CVIRTUAL GetPrivateData, DWORD, :PTR, :PTR, :PTR
CVIRTUAL GetParent, DWORD, :PTR, :PTR
CVIRTUAL EnumAdapters,DWORD, :DWORD, :PTR
CVIRTUAL MakeWindowAssociation,DWORD, :HWND, :DWORD
CVIRTUAL GetWindowAssociation, DWORD, :PTR
CVIRTUAL CreateSwapChain, DWORD, :PTR, : PTR, :PTR
CVIRTUAL CreateSoftwareAdapter, DWORD, :HMODULE, :PTR
ENDCOMINTERFACE

PIDXGIAdapter TYPEDEF PTR IDXGIAdapter
COMINTERFACE IDXGIAdapter
CVIRTUAL SetPrivateData, DWORD, :PTR, :PTR, :DWORD, :PTR
CVIRTUAL SetPrivateDataInterface, DWORD, :PTR, :PTR, :PTR
CVIRTUAL GetPrivateData, DWORD, :PTR, :PTR, :PTR, :PTR
CVIRTUAL GetParent, DWORD, :PTR, :PTR, :PTR

CVIRTUAL EnumOutputs, DWORD, :DWORD, :PTR
CVIRTUAL GetDesc, DWORD, :PTR
CVIRTUAL CheckInterfaceSupport, DWORD, :PTR, :PTR
ENDCOMINTERFACE

PIDXGIOutput TYPEDEF PTR IDXGIOutput
COMINTERFACE IDXGIOutput
CVIRTUAL SetPrivateData, DWORD, :PTR, :PTR, :DWORD, :PTR
CVIRTUAL SetPrivateDataInterface, DWORD, :PTR, :PTR, :PTR
CVIRTUAL GetPrivateData, DWORD, :PTR, :PTR, :PTR, :PTR
CVIRTUAL GetParent, DWORD, :PTR, :PTR, :PTR

CVIRTUAL GetDesc, DWORD, :PTR
; .... Other methods
ENDCOMINTERFACE

DXGI_ADAPTER_DESC STRUCT
Description  dw 128 dup (?)
VendorId dd ?
DeviceId dd ?
SubSysId dd ?
Revision dd ?
DedicatedVideoMemory QWORD ?
DedicatedSystemMemory QWORD ?
SharedSystemMemory QWORD ?
AdapterLuid : QWORD
DXGI_ADAPTER_DESC ENDS

RECT STRUCT
left dd ?
top dd ?
right dd ?
bottom dd ?
RECT ENDS

DXGI_OUTPUT_DESC STRUCT
DeviceName dw 32 dup (?)
DesktopCoordinates RECT <>
AttachedToDesktop dd ?
Rotation dd ?
_Monitor qword ?
DXGI_OUTPUT_DESC ENDS

GUID    STRUCT
    Data1   dd ?
    Data2   dw ?
    Data3   dw ?
    Data4   db 8 dup(?)
GUID ENDS
   
.data
dxgidll db "dxgi.dll",0
tCreateDXGIFactory1 db "CreateDXGIFactory1",0
tCreateDXGIFactory db "CreateDXGIFactory",0
hDXGI dq ?
pCreateDXGIFactory dq ?
pDXGIFactor LPVOID ?
align 16
_IDXGIFactory TEXTEQU <{7b7166ech,21c7h,44aeh,{0b2h,1ah,0c9h,0aeh,32h,01ah,0e3h,069h}}>
IID_IDXGIFactory GUID _IDXGIFactory
_IDXGIFactory1 TEXTEQU <{770aae78h,0f26fh,4dbah,{0a8h,29h,025h,03ch,83h,0d1h,0b3h,087h}}>
IID_IDXGIFactory1 GUID _IDXGIFactory1

.code

EnumerateUsingDXGI PROC uses r12 r13 r14 r15 pDXGIFactory:PIDXGIFactory
LOCAL pAdapter : PIDXGIAdapter
LOCAL pOutput : PIDXGIOutput
LOCAL desc : DXGI_ADAPTER_DESC
LOCAL outputDesc : DXGI_OUTPUT_DESC

mov pDXGIFactory, rcx
mov r12,0

.WHILE 1
lea r13, pAdapter

pDXGIFactory->EnumAdapters(r12d, r13)
.IF sdword ptr eax<0
.break
.endif
INVOKE memset, addr desc, 0, SIZEOF DXGI_ADAPTER_DESC

pAdapter->GetDesc(ADDR desc)
.IF sdword ptr eax>=0
INVOKE wprintf, WSTR(10,"DXGI Adapter: %u",10,"Description: %s",10),r12d, \
addr [desc].Description

mov r14,0
.WHILE 1
mov pOutput,0
lea r13, pOutput
pAdapter->EnumOutputs(r14d, r13)
.IF sdword ptr eax<0
.break
.ENDIF
INVOKE memset, addr outputDesc, 0, SIZEOF DXGI_OUTPUT_DESC
pOutput->GetDesc(ADDR outputDesc)
.IF sdword ptr eax>=0
INVOKE wprintf, WSTR("hMonitor: 0x%0.8Ix",10), outputDesc._Monitor
INVOKE wprintf, WSTR("hMonitor Device Name: %s",10), addr [outputDesc].DeviceName
.ENDIF
;pOutput->Release() ;????
mov pOutput,0
inc r14
.ENDW

mov rax, desc.DedicatedVideoMemory
xor rdx, rdx
mov rcx, 1048576
div rcx
mov r10, rax

mov rax, desc.DedicatedSystemMemory
xor rdx, rdx
div rcx
mov r11, rax

mov rax, desc.SharedSystemMemory
xor rdx, rdx
div rcx
mov r13, rax

INVOKE wprintf, WSTR(9,"GetVideoMemoryViaDXGI",10,9,9,"DedicatedVideoMemory: %Iu MB (%Iu)",10,9,9,"DedicatedSystemMemory: %Iu MB (%Iu)",10,9,9,"SharedSystemMemory: %Iu MB (%Iu)",10),
r10, desc.DedicatedVideoMemory, r11, desc.DedicatedSystemMemory, r13, desc.SharedSystemMemory
.ELSE
;pAdapter->Release(); ???
;_VCOMINVOKE pAdapter,IDXGIAdapter,Release ;???
mov pAdapter,0
.ENDIF
inc r12
.ENDW

ret
EnumerateUsingDXGI ENDP

main PROC
INVOKE LoadLibraryA, offset dxgidll
.IF rax==0
ret
.ENDIF

mov hDXGI, rax
INVOKE GetProcAddress, hDXGI, offset tCreateDXGIFactory1
.IF rax==0
INVOKE GetProcAddress, hDXGI, offset tCreateDXGIFactory
.IF rax==0
INVOKE FreeLibrary, hDXGI
ret
.ENDIF
.ENDIF

mov pCreateDXGIFactory, rax
mov r10, rax
ASSUME r10 : ptr CreateDXGIFactory

INVOKE r10, addr IID_IDXGIFactory, addr pDXGIFactor
ASSUME r10: nothing
.IF rax<0
INVOKE FreeLibrary, hDXGI
ret
.ENDIF
mov rax, pDXGIFactor

INVOKE EnumerateUsingDXGI, rax
INVOKE ExitProcess,0

main ENDP

end

It should produce the following output but since I can't release the interfaces it does not work properly.

DXGI Adapter: 0
Description: NVIDIA GeForce GT 640
hMonitor: 0x00010001
hMonitor Device Name: \\.\DISPLAY2
hMonitor: 0x00010003
hMonitor Device Name: \\.\DISPLAY1
        GetVideoMemoryViaDXGI
                DedicatedVideoMemory: 1990 MB (2087387136)
                DedicatedSystemMemory: 0 MB (0)
                SharedSystemMemory: 2048 MB (2147807232)


Another thing, you mention that WSTR:
"Same as CSTR but for wide string data. Both of these are
provided for backwards compatibility with MASM as
UASM features direct support for string literal data in
invoke."

If it is only for backward compatibility how can I make INVOKE wprintf work without it? Like in the following:
INVOKE wprintf, WSTR(10,"DXGI Adapter: %u",10,"Description: %s",10),r12d, \
            addr [desc].Description

Another thing:
Your arrow operator uses the register r15 without preserving it. This will not be OK if you are working with ASM modules instead of standalone ASM applications.

Another thing:
Why can't I use HRESULT even if I typedef it in cases like this:
CVIRTUAL SetPrivateData, HRESULT, :PTR, :DWORD, :PTR

mabdelouahab


MOV RCX,pAdapter
MOV R10, RCX
MOV R10,[R10] 
CALL QWORD PTR [R10+16]

aw27

#2
Quote from: mabdelouahab on January 17, 2018, 01:51:30 AM

MOV RCX,pAdapter
MOV R10, RCX
MOV R10,[R10] 
CALL QWORD PTR [R10+16]


Yes, but this is by the old way.  :t

Anyway, here is a version that works, using the old way:


OPTION LITERALS:ON

HRESULT TYPEDEF DWORD
HWND TYPEDEF PTR
HMODULE TYPEDEF PTR
LPVOID TYPEDEF PTR VOID

includelib \masm32\lib64\msvcrt.lib
printf PROTO :PTR, :VARARG
wprintf PROTO :PTR, :VARARG
memset PROTO :ptr, :dword, :qword
includelib \masm32\lib64\kernel32.lib
LoadLibraryA PROTO :PTR
GetProcAddress PROTO :HMODULE, :PTR
FreeLibrary PROTO :HMODULE
ExitProcess PROTO :DWORD

CreateDXGIFactory TYPEDEF PROTO :ptr, :ptr

PIDXGIFactory TYPEDEF PTR IDXGIFactory
COMINTERFACE IDXGIFactory
CVIRTUAL SetPrivateData, DWORD, :PTR, :DWORD, :PTR
CVIRTUAL SetPrivateDataInterface, DWORD, :PTR, :PTR
CVIRTUAL GetPrivateData, DWORD, :PTR, :PTR, :PTR
CVIRTUAL GetParent, DWORD, :PTR, :PTR
CVIRTUAL EnumAdapters,DWORD, :DWORD, :PTR
CVIRTUAL MakeWindowAssociation,DWORD, :HWND, :DWORD
CVIRTUAL GetWindowAssociation, DWORD, :PTR
CVIRTUAL CreateSwapChain, DWORD, :PTR, : PTR, :PTR
CVIRTUAL CreateSoftwareAdapter, DWORD, :HMODULE, :PTR
ENDCOMINTERFACE

PIDXGIAdapter TYPEDEF PTR IDXGIAdapter
COMINTERFACE IDXGIAdapter
CVIRTUAL SetPrivateData, DWORD, :PTR, :PTR, :DWORD, :PTR
CVIRTUAL SetPrivateDataInterface, DWORD, :PTR, :PTR, :PTR
CVIRTUAL GetPrivateData, DWORD, :PTR, :PTR, :PTR, :PTR
CVIRTUAL GetParent, DWORD, :PTR, :PTR, :PTR

CVIRTUAL EnumOutputs, DWORD, :DWORD, :PTR
CVIRTUAL GetDesc, DWORD, :PTR
CVIRTUAL CheckInterfaceSupport, DWORD, :PTR, :PTR
ENDCOMINTERFACE

PIDXGIOutput TYPEDEF PTR IDXGIOutput
COMINTERFACE IDXGIOutput
CVIRTUAL SetPrivateData, DWORD, :PTR, :PTR, :DWORD, :PTR
CVIRTUAL SetPrivateDataInterface, DWORD, :PTR, :PTR, :PTR
CVIRTUAL GetPrivateData, DWORD, :PTR, :PTR, :PTR, :PTR
CVIRTUAL GetParent, DWORD, :PTR, :PTR, :PTR

CVIRTUAL GetDesc, DWORD, :PTR
; .... Other methods
ENDCOMINTERFACE

DXGI_ADAPTER_DESC STRUCT
Description  dw 128 dup (?)
VendorId dd ?
DeviceId dd ?
SubSysId dd ?
Revision dd ?
DedicatedVideoMemory QWORD ?
DedicatedSystemMemory QWORD ?
SharedSystemMemory QWORD ?
AdapterLuid : QWORD
DXGI_ADAPTER_DESC ENDS

RECT STRUCT
left dd ?
top dd ?
right dd ?
bottom dd ?
RECT ENDS

DXGI_OUTPUT_DESC STRUCT
DeviceName dw 32 dup (?)
DesktopCoordinates RECT <>
AttachedToDesktop dd ?
Rotation dd ?
_Monitor qword ?
DXGI_OUTPUT_DESC ENDS

GUID    STRUCT
    Data1   dd ?
    Data2   dw ?
    Data3   dw ?
    Data4   db 8 dup(?)
GUID ENDS
   
.data
dxgidll db "dxgi.dll",0
tCreateDXGIFactory1 db "CreateDXGIFactory1",0
tCreateDXGIFactory db "CreateDXGIFactory",0
hDXGI dq ?
pCreateDXGIFactory dq ?
pDXGIFactor LPVOID ?
align 16
_IDXGIFactory TEXTEQU <{7b7166ech,21c7h,44aeh,{0b2h,1ah,0c9h,0aeh,32h,01ah,0e3h,069h}}>
IID_IDXGIFactory GUID _IDXGIFactory
_IDXGIFactory1 TEXTEQU <{770aae78h,0f26fh,4dbah,{0a8h,29h,025h,03ch,83h,0d1h,0b3h,087h}}>
IID_IDXGIFactory1 GUID _IDXGIFactory1

.code

EnumerateUsingDXGI PROC uses r12 r13 r14 r15 pDXGIFactory:PIDXGIFactory
LOCAL pAdapter : PIDXGIAdapter
LOCAL pOutput : PIDXGIOutput
LOCAL desc : DXGI_ADAPTER_DESC
LOCAL outputDesc : DXGI_OUTPUT_DESC

mov pDXGIFactory, rcx
mov r12,0

.WHILE 1
lea r13, pAdapter

pDXGIFactory->EnumAdapters(r12d, r13)
.IF sdword ptr eax<0
.break
.endif
INVOKE memset, addr desc, 0, SIZEOF DXGI_ADAPTER_DESC

pAdapter->GetDesc(ADDR desc)
.IF sdword ptr eax>=0
INVOKE wprintf, WSTR(10,"DXGI Adapter: %u",10,"Description: %s",10),r12d, \
addr [desc].Description

mov r14,0
.WHILE 1
mov pOutput,0
lea r13, pOutput
pAdapter->EnumOutputs(r14d, r13)
.IF sdword ptr eax<0
.break
.ENDIF
INVOKE memset, addr outputDesc, 0, SIZEOF DXGI_OUTPUT_DESC
pOutput->GetDesc(ADDR outputDesc)
.IF sdword ptr eax>=0
INVOKE wprintf, WSTR("hMonitor: 0x%0.8Ix",10), outputDesc._Monitor
INVOKE wprintf, WSTR("hMonitor Device Name: %s",10), addr [outputDesc].DeviceName
.ENDIF
;pOutput->Release() ;????
mov rcx, pOutput
mov r10, rcx
mov r10,[r10]

call qword ptr [r10+16]
mov pOutput,0
inc r14
.ENDW

mov rax, desc.DedicatedVideoMemory
xor rdx, rdx
mov rcx, 1048576
div rcx
mov r10, rax

mov rax, desc.DedicatedSystemMemory
xor rdx, rdx
div rcx
mov r11, rax

mov rax, desc.SharedSystemMemory
xor rdx, rdx
div rcx
mov r13, rax

INVOKE wprintf, WSTR(9,"GetVideoMemoryViaDXGI",10,9,9,"DedicatedVideoMemory: %Iu MB (%Iu)",10,9,9,"DedicatedSystemMemory: %Iu MB (%Iu)",10,9,9,"SharedSystemMemory: %Iu MB (%Iu)",10),
r10, desc.DedicatedVideoMemory, r11, desc.DedicatedSystemMemory, r13, desc.SharedSystemMemory
.ELSE
mov rcx, pAdapter
mov r10, rcx
mov r10,[r10]
call qword ptr [r10+16]
mov pAdapter,0
.ENDIF
inc r12
.ENDW
ret
EnumerateUsingDXGI ENDP

main PROC
        and rsp, -16 ; Align stack! It is not done by UASM.
INVOKE LoadLibraryA, offset dxgidll
.IF rax==0
ret
.ENDIF

mov hDXGI, rax
INVOKE GetProcAddress, hDXGI, offset tCreateDXGIFactory1
.IF rax==0
INVOKE GetProcAddress, hDXGI, offset tCreateDXGIFactory
.IF rax==0
INVOKE FreeLibrary, hDXGI
ret
.ENDIF
.ENDIF

mov pCreateDXGIFactory, rax
mov r10, rax
ASSUME r10 : ptr CreateDXGIFactory

INVOKE r10, addr IID_IDXGIFactory, addr pDXGIFactor
ASSUME r10: nothing
.IF rax<0
INVOKE FreeLibrary, hDXGI
ret
.ENDIF
mov rax, pDXGIFactor
mov rcx, [rax]

INVOKE EnumerateUsingDXGI, rax

mov rcx, pDXGIFactor
mov r10, rcx
mov r10,[r10]
call qword ptr [r10+16]
mov pDXGIFactor,0

INVOKE FreeLibrary, hDXGI

INVOKE ExitProcess,0
main ENDP

end



A new output from another computer:

DXGI Adapter: 0
Description: Intel(R) HD Graphics 630
hMonitor: 0x01f40ea1
hMonitor Device Name: \\.\DISPLAY1
hMonitor: 0x00490243
hMonitor Device Name: \\.\DISPLAY2
        GetVideoMemoryViaDXGI
                DedicatedVideoMemory: 128 MB (134217728)
                DedicatedSystemMemory: 0 MB (0)
                SharedSystemMemory: 8150 MB (8546873344)

DXGI Adapter: 1
Description: NVIDIA GeForce GTX 1050
        GetVideoMemoryViaDXGI
                DedicatedVideoMemory: 1974 MB (2070675456)
                DedicatedSystemMemory: 0 MB (0)
                SharedSystemMemory: 8150 MB (8546873344)

DXGI Adapter: 2
Description: Microsoft Basic Render Driver
        GetVideoMemoryViaDXGI
                DedicatedVideoMemory: 0 MB (0)
                DedicatedSystemMemory: 0 MB (0)
                SharedSystemMemory: 8150 MB (8546873344)

Vortex

My SetWallPaper example gives the following error messages :

uasm64.exe -win64 SetWallpaper.asm
UASM v2.46, Jan  8 2018, Masm-compatible assembler.
Portions Copyright (c) 1992-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.

SetWallpaper.asm(39) : Error A2210: Syntax error: _VCOMINVOKE
SetWallpaper.asm(40) : Error A2210: Syntax error: _VCOMINVOKE
SetWallpaper.asm(41) : Error A2210: Syntax error: _VCOMINVOKE
SetWallpaper.asm(42) : Error A2210: Syntax error: _VCOMINVOKE
SetWallpaper.asm: 49 lines, 1 passes, 6 ms, 0 warnings, 4 errors


Also, the 32-bit version of UASM  ( UASM v2.46, Jan  8 2018 ) does not seem to recognize the _VCOMINVOKE instruction.

johnsa

Hi,

With the Jan 8th update, the documentation was updated to reflect the change to how the OO stuff is handled internally. OO objects are now mapped the same way as COM objects in the following way:

Before:
COM instance = [pvtbl,instance values]
OO instance   = [method ptr1, method ptr 2....., instance values]

So before the OO objects were extremely memory inefficient. For example if we created a Vec3 object, we'd have 16 bytes of actual instance data, but potentially 100 or more bytes in method pointers per instance.
So to remedy this I adapted the OO system to work as the COM does using just a vTbl pointer and fields per instance, so a 16 byte Vec3 instance may use 24 or 32 bytes at most depending on alignment.

With this in place the two specific COM invocation macros _VCOM, _VCOMINVOKE were no longer necessary so I removed them as the COM objects can just use the normal invocations.
So you should be able to use the normal OO methods like:

_VINVOKE direct3d, GetDeviceCaps, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, ADDR caps
_VINVOKE direct3d, Release

You are right however about Release, it's built-in to the COMINTERFACE type so I would expect it to not allow you to add it manually, you could always use a CSTRUCT type instead if you wanted to add the generic COM methods yourself. For some reason Release() isn't work which I will investigate right now.

For the wide string example you can prefix the string literal with L"" , so this should work:
INVOKE wprintf, L"\nDXGI Adapter: %u\nDescription: %s\n",r12d, addr [desc].Description
But there's nothing wrong with using cstr and wstr as always, sometimes I prefer it being able to separate out the individual characters for formatting etc like 10, 9 etc..

Your arrow operator uses the register r15 without preserving it. This will not be OK if you are working with ASM modules instead of standalone ASM applications.
I had thought about this, I didn't want to needlessly add a preservation around the call itself as the main application is to use it from ASM directly. I would think if you're calling from a module the wrapper function should preserve R15 in the USES clause. I'm happy to hear ideas on this.

Another thing:
Why can't I use HRESULT even if I typedef it in cases like this:

CVIRTUAL SetPrivateData, HRESULT, :PTR, :DWORD, :PTR

Isn't this missing a colon : before the type ?

CVIRTUAL SetPrivateData, :HRESULT, :PTR, :DWORD, :PTR

johnsa

Example using the macro version would be:



mov direct3d,Direct3DCreate9( D3D_SDK_VERSION )
.if( rax != 0 )
_VINVOKE direct3d, IDirect3D9, GetDeviceCaps, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, ADDR caps
_VINVOKE direct3d, IDirect3D9, Release
.endif



Looking at the -> release issue.

johnsa

Found the issue and fixing it now.

I also noticed you aligned rsp manually in main proc, that shouldn't be necessary ? if it's a proc it should align, as long as it's not some plain label entry point like main:


aw27

Quote from: johnsa on January 17, 2018, 09:12:08 PM
I also noticed you aligned rsp manually in main proc, that shouldn't be necessary ? if it's a proc it should align, as long as it's not some plain label entry point like main:
You are right, I was using the 7th January release, not the one of 8th January.

Quote
So you should be able to use the normal OO methods like:

_VINVOKE direct3d, GetDeviceCaps, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, ADDR caps
_VINVOKE direct3d, Release
I will check that out, when possible.  :t

Quote
Isn't this missing a colon : before the type ?

Code: [Select]
CVIRTUAL SetPrivateData, :HRESULT, :PTR, :DWORD, :PTR
No, it is as you say in the uasm246_ext.pdf:

COMINTERFACE IDirect3D9
      CVIRTUAL RegisterSoftwareDevice, DWORD, :PTR
      CVIRTUAL GetAdapterCount, DWORD
.....
ENDCOMINTERFACE
No colons before the type.  ::)



johnsa

Oh sorry my brain is still half on holiday.. if it's specifying a RETURN type then yes there's no colon before the type. For a normal PROC definition there would also not be a comma in front, but you're right in this case for CVIRTUAL (or any of those oo macros).. I'll check it out.

I've fixed the ->Release() , there was a bug in the macro for the de-referencing logic.

Edit: On checking, I have only implemented basic primitive types for return... I will add support for traversing an ID type to get it's final type too :)

Vortex

Here is the 64-bit version of the wallpaper example :

option casemap:none
option win64:3

include     SetWallpaper.inc
includelib  kernel32.lib
includelib  ole32.lib

LPad TYPEDEF PTR IActiveDesktop

OPTION LITERALS:ON

.data

CLSID_IActiveDesktop    GUID sCLSID_IActiveDesktop
IID_IActiveDesktop      GUID sIID_IActiveDesktop

DesktopImg  dw "test.bmp",0
pAD         LPad 0

.data?

wpo             WALLPAPEROPT <>

.code

start PROC

    invoke      CoInitialize,NULL

    invoke      CoCreateInstance,ADDR CLSID_IActiveDesktop,\
                NULL,CLSCTX_INPROC_SERVER,\
                ADDR IID_IActiveDesktop,ADDR pAD           

    mov         rdx,OFFSET wpo
    mov         WALLPAPEROPT.dwSize[rdx],SIZEOF(WALLPAPEROPT)
    mov         WALLPAPEROPT.dwStyle[rdx],WPSTYLE_CENTER

    _VINVOKE    pAD,IActiveDesktop,SetWallpaper,ADDR DesktopImg,0
    _VINVOKE    pAD,IActiveDesktop,SetWallpaperOptions,ADDR wpo,0
    _VINVOKE    pAD,IActiveDesktop,ApplyChanges,AD_APPLY_ALL
    _VINVOKE    pAD,IActiveDesktop,Release

    invoke      CoUninitialize
    invoke      ExitProcess,0

start ENDP

END start