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
MOV RCX,pAdapter
MOV R10, RCX
MOV R10,[R10]
CALL QWORD PTR [R10+16]
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)
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.
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
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.
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:
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. ::)
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 :)
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