I have added a CoInvoke macro to the MasmBasic library (http://masmforum.com/~masm32/board/index.php?topic=94), usage (for example, more below):
CoInvoke pInterface, IWebBrowserVtbl.get_HWND, addr hWin
There is a somewhat "unfinished" thread in the old forum (http://www.movsd.com/board/index.php?topic=16760.msg139404#msg139404), and I have a suspicion that the macro shown there might not work correctly. Below is my version (from MasmBasic.inc):
CoInvoke MACRO pInterface:REQ,Method:REQ,args:VARARG
LOCAL is, ct, ciPush$, tmp$, tmpAddr$, errEdx$
ct=0
ciPush$ equ <>
FOR arg, <args>
ct=ct+1
ciPush$ CATSTR <arg>, <#>, ciPush$
ENDM
ciPush$ CATSTR ciPush$, < >
WHILE ct
ct=ct-1
is INSTR ciPush$, <#>
tmp$ SUBSTR ciPush$, 1, is-1
tmpAddr$ CATSTR tmp$, <123> ; addr
tmpAddr$ SUBSTR tmpAddr$, 1, 4
ifidni tmpAddr$, <addr>
% errEdx$ equ tmp$
tmp$ SUBSTR ciPush$, 5, is-5
lea edx, tmp$
push edx
else
ifidni tmp$, <edx>
ifdef errEdx$
% echo ### edx overwritten by errEdx$ ###
.err
endif
endif
push tmp$
endif
ciPush$ SUBSTR ciPush$, is+1
ENDM
ifdifi <pInterface>, <eax>
mov eax, pInterface
endif
push eax
mov eax, [eax]
mov edx, [eax+Method]
call dword ptr [eax+Method] ; Method=4, 8, ...
ENDM
One question: In some very old posts by Ernie Murphy (e.g. here (http://yanaware.com/com4me/accesscom.php-author=Ernie%20MURPHY&mail=ernie@surfree.com&url=http---here.is-ComInAsm&idTute=38.htm)) and Japheth, you can find statements like:
.ERR <edx is not allowed as a coinvoke parameter>
Is there any good reason not to allow edx? My version throws an error if edx gets overwritten by an addr xyz, but otherwise I just can't see why edx should not work with CoInvoke... ::)
Just for fun, below a short COM app that launches MSIE (will not assemble with JWasm 2.08):
include \masm32\MasmBasic\MasmBasic.inc ; download (http://masm32.com/board/index.php?topic=94.0) (version 8 Sept 2012 required)
.data?
WebInterface dd ? ; will be loaded by CoCreateInstance
.code
CLSID_InternetExplorer GuidFromString("0002DF01-0000-0000-C000-000000000046")
IID_IWebBrowser2 GuidFromString(D30C1661-CDAF-11D0-8A3E-00C04FC9E26E)
MyBrowser proc url
LOCAL vEmpty:VARIANT, hWin
ClearLocalVariables uses edi
mov edi, offset WebInterface
.if !dword ptr [edi]
invoke CoCreateInstance, addr CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, addr IID_IWebBrowser2, edi
cmp eax, S_OK
jne cci_failed
CoInvoke [edi], IWebBrowserVtbl.put_StatusBar, VARIANT_FALSE ; OK, now configure the browser
CoInvoke [edi], IWebBrowserVtbl.put_MenuBar, VARIANT_FALSE
CoInvoke [edi], IWebBrowserVtbl.put_Visible, VARIANT_TRUE
CoInvoke [edi], IWebBrowserVtbl.get_HWND, addr hWin
invoke ShowWindow, hWin, SW_MINIMIZE ; MSIE has the bad habit of showing by default a restored window
invoke ShowWindow, hWin, SW_MAXIMIZE ; the author likes it maximised ;-)
.endif
lea edx, vEmpty
CoInvoke [edi], IWebBrowserVtbl.Navigate, Ole$(url), edx, edx, edx, edx ; COM needs a BSTR, so the ANSI URL needs to be converted
cci_failed:
PopUses
ret
MyBrowser endp
Init
invoke OleInitialize, NULL
.if eax==S_OK
invoke MyBrowser, Chr$("http://masmforum.com/~masm32/board/index.php")
.endif
invoke OleUninitialize
Exit
end start
Source & exe attached below.
(Nothing relevant)
My apologies if the original content of this post shifted the focus of the topic.
Ok, but at that stage edx could have been used, without any risk, for one of the pushed args...
I have tested passing args with edx with my macros, and as expected, there are no problems.
Yeah, it appears my response doesn't really apply. I was reading through that tutorial from CP. I was just looking at Japheth's vf macro, and I was asking myself the same question.
> Ok, but at that stage edx could have been used, without any risk, for one of the pushed args...
> I have tested passing args with edx with my macros, and as expected, there are no problems.
The problem is that expansion is done from left to right - even if the arguments of invoke are pushed from right to left. That means, the code that's using edx to dereference the vtable is created BEFORE the arguments of the function are being pushed.
Makes sense now.
Thanks for the explanation :t
Then why can...
lea edx, vEmpty
CoInvoke [edi], IWebBrowserVtbl.Navigate, Ole$(url), edx, edx, edx, edx ; COM needs a BSTR, so the ANSI URL needs to be converted
... work smoothly, Japheth? Can you show an example where the left-to-right expansion matters in this context?
Thanks, JJ
Quote from: jj2007 on September 08, 2012, 03:39:58 PM
Then why can...
lea edx, vEmpty
CoInvoke [edi], IWebBrowserVtbl.Navigate, Ole$(url), edx, edx, edx, edx ; COM needs a BSTR, so the ANSI URL needs to be converted
... work smoothly, Japheth?
Perhaps because your version of CoInvoke has little to do with the CoInvoke macro of Ernest Murphi?
edx is not allowed as parameter because he is used as the pointer of interface.
This macro is a modify of the original coinvoke.
Quote
;add: DECLARE_pointeur TEXTEQU <STInterFace>
;where pointeur is
; pointeur dd ;all name who get the com pointer
; USAGE:
; COM pointeur,Release ;usefull with duplicate pointer
COM MACRO ppv:REQ,fonction:REQ,args:VARARG
local InvokeInterface
computeoffset CATSTR <DECLARE_>,<ppv>
;---------- controle les arguments
FOR arg, <args> ; edx couldn't be used as parameter
IFIDNI <&arg>, <edx> ;
.ERR <edx is not allowed as a coinvoke parameter>
ENDIF
ENDM
IFIDNI <&pInterface>, <edx>
.ERR <edx is not allowed as a coinvoke parameter>
ENDIF
;------------ fin de controle --------------------------------
;InvokeInterface = concatene ...CATSTR(concatene) MACRO instruction MASM32
;--- ppv is the first arg in STANDARD COM PROTOTYPE ------------
;--- the virtual proto need ecx with ppv
InvokeInterface CATSTR <invoke (computeoffset ptr [edx]).>,<&fonction,ppv>
IFNB <args> ; add the list of parameter arguments if any
InvokeInterface CATSTR InvokeInterface, <, >, <&args>
ENDIF
; -- charge le pointeur ---------------------
mov edx, ppv
mov edx, [edx]
InvokeInterface
ENDM
Quote from: ToutEnMasm on September 08, 2012, 04:52:45 PM
edx is not allowed as parameter because he is used as the pointer of interface.
By often repeating something, it does not become more true. AFAIK there is
no valid reason not to use edx in a CoInvoke macro. If you can't believe it, launch Olly to see this:
Original source:
lea edx, vEmpty
CoInvoke [edi], IWebBrowserVtbl.Navigate, Ole$(url), edx, edx, edx, edx
Disassembly:
004010D2 . 8D55 F2 lea edx, [ebp-0E]
004010D5 . 52 push edx
... get Ole$(URL) in eax ...
004010FE . 5A pop edx
004010FF . 52 push edx
00401100 . 52 push edx
00401101 . 52 push edx
00401102 . 52 push edx
00401103 . 50 push eax <<< push URL
00401104 . 8B07 mov eax, [edi]
00401106 . 50 push eax
00401107 . 8B00 mov eax, [eax]
0040110C . FF50 2C call near [eax+2C]
No need of olly,i have made enough control.
When masm translate the macro , he put the load of edx at the first place.
So if you use edx as argument,he is overwritten.
A simple listing is enough to show how it work.
Proof is here with the listing of a macro.
.LISTALL
ITextServices TxDraw,DVASPECT_DOCPRINT,0,NULL,NULL,hdcDraw,NULL,prc,\
NULL, NULL,NULL,NULL,NULL ;TXTVIEW_INACTIVE
.NOLIST
Quote
1C ; forme les lignes de codes
0000028D 55 * push ebp
0000028E 8B EC * mov ebp, esp
00000290 8B 15 00000244 R 1C mov edx, ppvITextServices
00000296 8B 12 1C mov edx, [edx]
00000298 8B 0D 00000244 R 1C mov ecx,ppvITextServices
0000029E 6A 00 * push +000000000h
000002A0 6A 00 * push +000000000h
000002A2 6A 00 * push +000000000h
000002A4 6A 00 * push +000000000h
000002A6 6A 00 * push +000000000h
000002A8 FF 75 0C * push dword ptr ss:[ebp]+00000000Ch
000002AB 6A 00 * push +000000000h
000002AD FF 75 08 * push dword ptr ss:[ebp]+000000008h
000002B0 6A 00 * push +000000000h
000002B2 6A 00 * push +000000000h
000002B4 6A 00 * push +000000000h
000002B6 6A 08 * push +000000008h
000002B8 FF 52 10 * call dword ptr [edx]+000000010h
Sorry, I can't see your point. My macro works.
Quote from: jj2007 on September 08, 2012, 05:21:31 PM
Sorry, I can't see your point. My macro works.
Noone has claimed that it is IMPOSSIBLE to write a CoInvoke macro that allows to used register EDX. Both ToutEnMasm and me were very clearly referring to the CoInvoke macro of Ernest Murphy, not yours.
JJ, deliberately misunderstanding people is an indication of a TROLL. Are you a TROLL?
I'm curious. The second last line in the macro has
mov edx, [eax+Method]
What is the point of this? edx is not used in the last line of the macro, so is this necessary?
Quote from: jj2007 on September 08, 2012, 10:27:18 AM
My version throws an error if edx gets overwritten by an addr xyz
addr uses edx? I thought it used eax exclusively?
Quote from: japheth on September 08, 2012, 05:31:03 PM
JJ, deliberately misunderstanding people is an indication of a TROLL. Are you a TROLL?
Japheth,
I am not deliberately misunderstanding anybody. Ernie wrote that macro ten years ago, and I asked why he so firmly states that edx cannot be used. Not because I am a troll, but because I failed to see a concrete reason for this statement.
I posted my version, it works fine even with edx as parameter, and in "response" to that somebody dumps idiosyncratic macros in this thread that do not prove anything and have little to do with the original question.
You wrote "The problem is that expansion is done from left to right". That is correct but irrelevant, if during expansion edx is not getting destroyed (and Ole$() won't destroy edx for that precise reason). And it is completely irrelevant for the
final part of the macro where edx (or eax) is being used to dereference the pointer.
Regarding the problem that JWasm doesn't like the GuidFromString macro, I will post it on SourceFourge.That was a problem for JWasm 2.08 of 30 August, but I just downloaded version 7 September, and voilà, it works :t
Quote from: Ryan on September 08, 2012, 06:18:09 PM
Quote from: jj2007 on September 08, 2012, 10:27:18 AM
My version throws an error if edx gets overwritten by an addr xyz
addr uses edx? I thought it used eax exclusively?
In a macro you can use whatever you like. The standard implementation of invoke uses the lea eax, localvar/push eax sequence, but eax is frequently a return value from some API call, so it can be convenient to use edx instead. You may have seen an error message that eax will be overwritten - see snippet below for a test of the options.
include \masm32\include\masm32rt.inc
.code
AppName db "Masm32 is great!", 0
Hello db "A message:", 0
start:
call MyTest
exit
MyTest proc
LOCAL bufText[100]:BYTE
LOCAL bufTitle[100]:BYTE
; prepare local buffers for testing:
invoke lstrcpy, addr bufText, offset AppName
invoke lstrcpy, addr bufTitle, offset Hello
; standard behaviour:
invoke MessageBox, 0, addr bufText, addr bufTitle, MB_OK
; no error because eax gets pushed before lea is being used:
lea eax, bufTitle
invoke MessageBox, 0, addr bufText, eax, MB_YESNO
; Error A2165: Register value overwritten by INVOKE:
; lea eax, bufText
; invoke MessageBox, 0, eax, addr bufTitle, MB_OK
; workaround using edx instead of eax:
lea edx, bufText
invoke MessageBox, 0, edx, addr bufTitle, MB_YESNOCANCEL
ret
MyTest endp
end start
P.S.: "edx is not used in the last line of the macro, so is this necessary?"
No,
mov edx, [eax+Method] is just a leftover from testing.
All macros calling an interface are differents from other macros.
The first thing they do is loading the pointer off interface (ppv) in one register.
Others macros don't do that.
Then the normal contrust for call is made.At this time , if you reuse the register pointing on the interface this one is overwritten.
Yves,
My macros are different from yours, and they work just fine.
Bonne journée,
Jochen
Here is your original question:
Quote
Is there any good reason not to allow edx? My version throws an error if edx gets overwritten by an addr xyz, but otherwise I just can't see why edx should not work with CoInvoke...
answer is made.