flat assembler
Message board for the users of flat assembler.
Index
> Windows > [solved] COM IAudioEndpointVolume |
Author |
|
bitRAKE 10 May 2021, 11:17
It need a null GUID - which is a pointer to 16 zero bytes.
(Or rather the working example I built needed that.) This line in the documentation appears to be wrong: Quote: If the caller supplies a NULL pointer for this parameter, the notification routine receives the context GUID value GUID_NULL. |
|||
10 May 2021, 11:17 |
|
Overclick 10 May 2021, 12:58
I did it with GUID_NULL, no difference. Look at SetMute one, it works just fine.
As I understand, when caller sets NULL it automatically implements to GUID_NULL ... Just checked again to clear up any doubts
|
||||||||||
10 May 2021, 12:58 |
|
bitRAKE 10 May 2021, 13:38
Does this work on your machine?
Maybe you see some difference?
_________________ ¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup |
|||||||||||
10 May 2021, 13:38 |
|
Overclick 10 May 2021, 13:39
I tried to run that thread as only COM stuff of entire process. Everything else was disabled. Just virgin Volume control. GetVolume --> SetVolume --> Breakpoint
The result all the same. |
|||
10 May 2021, 13:39 |
|
Overclick 10 May 2021, 13:41
bitRAKE wrote: Does this work on your machine? Your example works fine. |
|||
10 May 2021, 13:41 |
|
bitRAKE 10 May 2021, 13:46
COM doesn't return an error? I tend to step through with a debugger, verify vtbl offsets (to insure interface is defined correctly), etc.
|
|||
10 May 2021, 13:46 |
|
Overclick 10 May 2021, 13:47
hr = g_pEndptVol->RegisterControlChangeNotify(
(IAudioEndpointVolumeCallback*)&EPVolEvents); Maybe it needs bloody callback? |
|||
10 May 2021, 13:47 |
|
Overclick 10 May 2021, 13:49
No errors, I check it hundreds times. Everything seems to be working.
|
|||
10 May 2021, 13:49 |
|
bitRAKE 10 May 2021, 13:51
The callback looks trivial - only one method beyond IUnknown interface. Definitely worth a try.
Edit: It looks like the local pointer for GUID_NULL is being used to identify local notifications in the event loop. S_OK is sent as long as the notification is not null. Nice, so there is two-way communication with the callback. Definitely required. |
|||
10 May 2021, 13:51 |
|
Overclick 10 May 2021, 15:43
I have no experience for callback. It drops application to deadend when I try to register it.
Code: cominvk pAudioVolumeOut,RegisterControlChangeNotify,pVolumeNotify Could you translate it to assembly please? |
|||
10 May 2021, 15:43 |
|
bitRAKE 10 May 2021, 17:46
It should look something like this (untested):
Code: define MyCallback namespace MyCallback ; this also needs to be in your address space and writeable ; wrapped in namespace to isolate it object: pvtbl dq vtbl refCount dd ?,? vtbl: QueryInterface dq ? AddRef dq ? Release dq ? OnNotify dq ? QueryInterface: test rdx,rdx jz .E_INVALIDARG push rcx ; compare IID to all extended interfaces mov rax,[rdx] mov rcx,[rdx+8] iterate iid, IUnknown,IAudioEndpointVolumeCallback cmp [IID_#iid],rax jnz @f cmp [IID_#iid+8],rcx jz .found @@: end iterate pop rcx and qword [r8],0 mov eax,E_NOINTERFACE retn .E_INVALIDARG: and qword [r8],0 mov eax,E_INVALIDARG retn .found: pop rcx mov [r8],rcx call AddRef xor eax,eax retn AddRef: push 1 pop rax lock xadd [rcx - MyCallback.object + MyCallback.object.refCount],eax @@: add eax,1 retn Release: push -1 pop rax lock xadd [rcx - MyCallback.object + MyCallback.object.refCount],eax jnz @f ; TODO: delete memory used by object xor eax,eax retn @@: sub eax,1 retn OnNotify: test rdx,rdx ; AUDIO_VOLUME_NOTIFICATION_DATA jz .E_INVALIDARG mov rax,[MyContext] cmp [rdx],rax jnz .other mov rax,[MyContext+8] cmp [rdx+8],rax jz .self .other: ; process our messages .self: xor eax,eax ; S_OK retn .E_INVALIDARG: mov eax,E_INVALIDARG retn end namespace ; put this somewhere in your address space and send it instead of null MyContext rb 16 ; GUID_NULL ; could cheat and use an easy GUID for callback, lol MyContext dq 1,2 cominvk pAudioVolumeOut,RegisterControlChangeNotify,ADDR MyCallback.object edit: there are some errors because I adapted my dynamic object template. maybe I have fixed most of them? my logic was reversed - it's messages from other's we need to respond to in callback. _________________ ¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup |
|||
10 May 2021, 17:46 |
|
Overclick 10 May 2021, 19:52
Oh, I think I understand. Just need to reconstruct your example little bit for fasm1. Thanks a lot.
|
|||
10 May 2021, 19:52 |
|
bitRAKE 10 May 2021, 20:50
Obviously you need to put your functions in the vector table.
_________________ ¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup |
|||
10 May 2021, 20:50 |
|
Overclick 10 May 2021, 21:34
I'm working on it
Code: .data struct OBJECT pvtbl dq $+16 refCount dd ?,? vtbl = $ QueryInterface dq VolumeCallBackQueryInterface AddRef dq VolumeCallBackAddRef Release dq VolumeCallBackRelease OnNotify dq VolumeCallBackOnNotify ends VolumeCallBack OBJECT IID_VolumeCallBack GUID A1ECF000-FEEE-0000-0000-CA11BAC0BDEC .code VolumeCallBackQueryInterface: test rdx,rdx jz .E_INVALIDARG push rcx irp IID,IID_IUnknown,\ IID_IAudioEndpointVolumeCallback { cmp [IID],rax jne @f cmp [IID+8],rcx je .found } pop rcx and qword [r8],0 mov eax,E_NOINTERFACE ret 0 .E_INVALIDARG: and qword [r8],0 mov eax,0x80070057 ret 0 .found: pop rcx mov [r8],rcx call VolumeCallBackAddRef xor eax,eax ret 0 VolumeCallBackAddRef: push 1 pop rax lock xadd [rcx-VolumeCallBack+VolumeCallBack.refCount],eax @@: add eax,1 ret 0 VolumeCallBackRelease: push -1 pop rax lock xadd [rcx-VolumeCallBack+VolumeCallBack.refCount],eax jnz @f ; TODO: delete memory used by object xor eax,eax ret 0 @@: sub eax,1 ret 0 VolumeCallBackOnNotify: test rdx,rdx ; AUDIO_VOLUME_NOTIFICATION_DATA jz .E_INVALIDARG mov rax,[IID_VolumeCallBack] cmp [rdx],rax jnz .other mov rax,[IID_VolumeCallBack+8] cmp [rdx+8],rax jz .self .other: ; process our messages .self: xor eax,eax ; S_OK ret 0 .E_INVALIDARG: mov eax,0x80070057 ret 0 Could you check this code? No errors form calls, but the problem still the same. Code: cominvk pAudioVolumeOut,RegisterControlChangeNotify,VolumeCallBack ;S_OK cominvk pAudioVolumeOut,SetMasterVolumeLevelScalar,[MasterVolumeIn],IID_VolumeCallBack ;S_OK I checked Notifications. It's working when other application changes the volume. So callback is ok or almost ok. But volume still drop down at Set methods. |
|||
10 May 2021, 21:34 |
|
bitRAKE 11 May 2021, 13:36
Makes me think the float conversion is off. Maybe the fasm macro is converting it to double and the function wants float?
_________________ ¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup |
|||
11 May 2021, 13:36 |
|
Overclick 11 May 2021, 15:43
I think about it
Code: macro cominvk object,proc,[arg] { common assert defined object#.com.object ; must be a COM object macro call dummy \{ mov rax,[rcx] call [rax+object#.#proc] \} fastcall ,[object],arg purge call } Code: macro fastcall proc,[arg] { common local stackspace,argscount,counter if argscount < 4 stackspace = 4*8 else if argscount and 1 stackspace = (argscount+1)*8 else stackspace = argscount*8 end if counter = 0 if stackspace if defined current@frame if current@frame<stackspace current@frame = stackspace end if else if stackspace sub rsp,stackspace end if end if end if forward counter = counter + 1 define type@param define definition@param arg match =float value,definition@param \{ define definition@param value define type@param float \} match =addr value,definition@param \{ define definition@param value define type@param addr \} match any=,any,definition@param \{ \local ..string,..continue jmp ..continue align sizeof.TCHAR ..string TCHAR definition@param,0 ..continue: define definition@param ..string define type@param addr \} match any,definition@param \{ match \`any,any \\{ \\local ..string,..continue jmp ..continue align sizeof.TCHAR ..string TCHAR definition@param,0 ..continue: define definition@param ..string define type@param addr \\} \} match param,definition@param \{ local opcode,origin size@param = 0 if param eqtype 0 | param eqtype 0f | type@param eq addr size@param = 8 else if param eqtype byte 0 | param eqtype byte 0f match prefix value,definition@param \\{ if prefix eq qword size@param = 8 else if prefix eq dword size@param = 4 else if prefix eq word size@param = 2 else if prefix eq byte size@param = 1 end if \\} else if ~ param in <xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7,xmm8,xmm9,xmm10,xmm11,xmm12,xmm13,xmm14,xmm15> virtual origin = $ inc param load opcode byte from origin if opcode = 67h | opcode = 41h load opcode byte from origin+1 end if if opcode and 0F8h = 48h size@param = 8 else if opcode = 66h size@param = 2 else if opcode = 0FFh size@param = 4 else size@param = 1 end if end virtual end if if counter = 1 if type@param eq float if ~ param eq xmm0 if size@param = 4 if param eqtype byte 0 | param eqtype byte 0f mov eax,param movd xmm0,eax else movd xmm0,param end if else if param eqtype 0 | param eqtype 0f | param eqtype byte 0 | param eqtype byte 0f mov rax,param movq xmm0,rax else movq xmm0,param end if end if end if if vararg@fastcall & ~ param eq rcx movq rcx,xmm0 end if else if type@param eq addr if ~ param eq rcx lea rcx,[param] end if else if size@param = 8 if ~ param eq rcx mov rcx,param end if else if size@param = 4 if ~ param eq ecx xor rcx,rcx mov ecx,param end if else if size@param = 2 if ~ param eq cx xor rcx,rcx mov cx,param end if else if size@param = 1 if ~ param eq cl xor rcx,rcx mov cl,param end if end if else if counter = 2 if type@param eq float if ~ param eq xmm1 if size@param = 4 if param eqtype byte 0 | param eqtype byte 0f mov eax,param movd xmm1,eax else movd xmm1,param end if else if param eqtype 0 | param eqtype 0f | param eqtype byte 0 | param eqtype byte 0f mov rax,param movq xmm1,rax else movq xmm1,param end if end if end if if vararg@fastcall & ~ param eq rdx movq rdx,xmm1 end if else if type@param eq addr if ~ param eq rdx lea rdx,[param] end if else if size@param = 8 if ~ param eq rdx mov rdx,param end if else if size@param = 4 if ~ param eq edx xor rdx,rdx mov edx,param end if else if size@param = 2 if ~ param eq dx xor rdx,rdx mov dx,param end if else if size@param = 1 if ~ param eq dl xor rdx,rdx mov dl,param end if end if else if counter = 3 if type@param eq float if ~ param eq xmm2 if size@param = 4 if param eqtype byte 0 | param eqtype byte 0f mov eax,param movd xmm2,eax else movd xmm2,param end if else if param eqtype 0 | param eqtype 0f | param eqtype byte 0 | param eqtype byte 0f mov rax,param movq xmm2,rax else movq xmm2,param end if end if end if if vararg@fastcall & ~ param eq r8 movq r8,xmm2 end if else if type@param eq addr if ~ param eq r8 lea r8,[param] end if else if size@param = 8 if ~ param eq r8 mov r8,param end if else if size@param = 4 if ~ param eq r8d xor r8,r8 mov r8d,param end if else if size@param = 2 if ~ param eq r8w xor r8,r8 mov r8w,param end if else if size@param = 1 if ~ param eq r8b xor r8,r8 mov r8b,param end if end if else if counter = 4 if type@param eq float if ~ param eq xmm3 if size@param = 4 if param eqtype byte 0 | param eqtype byte 0f mov eax,param movd xmm3,eax else movd xmm3,param end if else if param eqtype 0 | param eqtype 0f | param eqtype byte 0 | param eqtype byte 0f mov rax,param movq xmm3,rax else movq xmm3,param end if end if end if if vararg@fastcall & ~ param eq r9 movq r9,xmm3 end if else if type@param eq addr if ~ param eq r9 lea r9,[param] end if else if size@param = 8 if ~ param eq r9 mov r9,param end if else if size@param = 4 if ~ param eq r9d xor r9,r9 mov r9d,param end if else if size@param = 2 if ~ param eq r9w xor r9,r9 mov r9w,param end if else if size@param = 1 if ~ param eq r9b xor r9,r9 mov r9b,param end if end if else if type@param eq addr lea rax,[param] mov [rsp+(counter-1)*8],rax else if param eqtype [0] | param eqtype byte [0] if size@param = 8 mov rax,param mov [rsp+(counter-1)*8],rax else if size@param = 4 mov eax,param mov [rsp+(counter-1)*8],eax else if size@param = 2 mov ax,param mov [rsp+(counter-1)*8],ax else mov al,param mov [rsp+(counter-1)*8],al end if else if size@param = 8 virtual origin = $ mov rax,param load opcode byte from origin+1 end virtual if opcode = 0B8h mov rax,param mov [rsp+(counter-1)*8],rax else mov qword [rsp+(counter-1)*8],param end if else if param in <xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7,xmm8,xmm9,xmm10,xmm11,xmm12,xmm13,xmm14,xmm15> movq [rsp+(counter-1)*8],param else mov [rsp+(counter-1)*8],param end if end if \} common argscount = counter call proc if stackspace & ~defined current@frame add rsp,stackspace end if } Have to check it up |
|||
11 May 2021, 15:43 |
|
Overclick 11 May 2021, 15:49
Finally I fixed my interface calls by 'float' mark
Code: cominvk pAudioVolumeOut,SetMasterVolumeLevelScalar,\ float [MasterVolumeIn],IID_VolumeCallBack But have it be like that? Is it fasm bug? |
|||
11 May 2021, 15:49 |
|
bitRAKE 11 May 2021, 20:32
You just didn't realize default parameter size in 64-bit is 64-bit - and that applies to float/double. In 32-bit it would have been float and worked, lol. You will know next time though. And you have the callback now, and play nice with other applications.
_________________ ¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup |
|||
11 May 2021, 20:32 |
|
Tomasz Grysztar 11 May 2021, 20:41
bitRAKE wrote: You just didn't realize default parameter size in 64-bit is 64-bit - and that applies to float/double. In 32-bit it would have been float and worked, lol. |
|||
11 May 2021, 20:41 |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.