Hi NaN,

checked your code (and rewrite it :grin: ). One possible error is the return code handling. Your code copies at least 4 bytes. But that may possibly too much, if user wants a VARIANT_BOOL, thats only 2 bytes.


Anyway, I did some work to let COMView create such stubs. My current concept for that is:

1. code changes should be kept quite simple, to call a method with IDispatch::Invoke I would code:



invoke dm(pRange, Range, get_Item), var1, var2, addr var3


that is, just replace "invoke vf" by "invoke dm". That is all to be changed in the source code.


The rest is done by COMView: in excel.inc, changes are (example get_Item & put_Item):



;--- dispinterface only
ifndef RangeVtbl
BEGIN_INTERFACE Range, IDispatch
; STDMETHOD QueryInterface , :ptr GUID,:ptr ptr
; STDMETHOD AddRef
...
; STDMETHOD Insert , :VARIANT
; STDMETHOD get_Interior
DISPMETHOD get_Item , :VARIANT,:VARIANT,:ptr VARIANT
DISPMETHOD put_Item , :VARIANT,:VARIANT,:VARIANT
; STDMETHOD Justify
; STDMETHOD get_Left


this is quite simple so far (the DISPMEHTOD macro defines just a prototype). But another file will have to be generated, here its excelc.asm (c stands for "client" code, possibly ther is a excels.asm for server code later. excelc.asm will look like:



.386
.model FLAT, STDCALL
option casemap:none
option proc:private

.nolist
.nocref
include \masm32\include\windows.inc
include unknwn.inc
include oaidl.inc
include disphlp.inc
.list
.cref

.code

DEFINE_INVOKEHELPER

DEFINE_DISPMETHOD Range, get_Item, 0AAh, PROPERTYGET, VT_VARIANT, VT_VARIANT, VT_VARIANT
DEFINE_DISPMETHOD Range, put_Item, 0AAh, PROPERTYPUT, , VT_VARIANT, VT_VARIANT, VT_VARIANT

end



that shouldnt be too hard. All lines with "DEFINE_DISPMETHOD" will be commented out first and have to be activated by hand.


The rest is done by some new macros (which hide all the Invokehelper code).
As far as by now the new macros are working. Just COMView has to be modified yet.


japheth
Posted on 2002-12-31 09:26:47 by japheth
Im a little lost here :confused:

I guess i need to see the DM() and DISPMETHOD() macros to fully understand..

Is the 'disphlp.inc' new as well?

Thanx ;)

NaN
Posted on 2002-12-31 11:34:56 by NaN
Yes, disphlp.inc is new, but the macro defined in there are only used by the generated source.

Anyway, COMView is updated now, it will create the stubs. Of course it is still a preliminary version (1.5 now).

Please download it and give this feature a try. Documentation is in disphlp.inc (not really needed to use this feature) and macros dm() and DISPMETHOD are in objbase.inc

B.T.W.: I'm a bit uncertain about how to deal with VT_USERDEFINED as parameters. These mostly are
simple ENUMS or IDispatch pointers, but as far as I understood VT_USERDEFINED is not allowed as a VARIANTARG type in DISPPARAMS.

Simplifying IDispatch::Invoke for ASM is a very exciting project in my opinion. Once it works smoothly handling of event sinks with this connection point stuff should be quite simple. Such interfaces are almost always dispatchonly.

Japheth

Heres the new 1.5 version
Posted on 2003-01-01 05:02:13 by japheth
Nice,

It looks good to me.. your using alot of macro's which is something i was straying away from (due to lengthy compile times). As well, i see your making your variant type string arrays directly in the data segment. Even tho is ez to implement, I decided not to go this way so i would not make the data segment overpopulated with array stings if i had alot of methods to 'DISP:Invoke'. This is why i liked your stack suggestion.

Your design for the comView is good! If i feel the need to tweek it can still be versitle... ( ;) )

My only constructive feedback at this point is this:

In the DEFINE_INVOKEHELPER macro, you should also put:
DEFINE_INVOKEHELPER macro

[b]ifndef _InvokeHelper_
_InvokeHelper_ equ 1[/b]

...
..


[b]endif[/b]
ENDM

This is so that i can have multiple files.. say Autocadc.asm and Excelc.asm in a project.

As well, should there not be a proto statement inside the Macro? Didnt compile a test, but as it appears, i would expect the invoke InvokeHelper ... to complain?

Thanx again Japheth..
NaN
Posted on 2003-01-01 16:10:17 by NaN
/*

* VARENUM usage key,
*
* * [V] - may appear in a VARIANT
* * [T] - may appear in a TYPEDESC
* * [P] - may appear in an OLE property set
* * [S] - may appear in a Safe Array
*
*
* VT_EMPTY [V] [P] nothing
* VT_NULL [V] [P] SQL style Null
* VT_I2 [V][T][P][S] 2 byte signed int
* VT_I4 [V][T][P][S] 4 byte signed int
* VT_R4 [V][T][P][S] 4 byte real
* VT_R8 [V][T][P][S] 8 byte real
* VT_CY [V][T][P][S] currency
* VT_DATE [V][T][P][S] date
* VT_BSTR [V][T][P][S] OLE Automation string
* VT_DISPATCH [V][T] [S] IDispatch *
* VT_ERROR [V][T][P][S] SCODE
* VT_BOOL [V][T][P][S] True=-1, False=0
* VT_VARIANT [V][T][P][S] VARIANT *
* VT_UNKNOWN [V][T] [S] IUnknown *
* VT_DECIMAL [V][T] [S] 16 byte fixed point
* VT_RECORD [V] [P][S] user defined type
* VT_I1 [V][T][P][s] signed char
* VT_UI1 [V][T][P][S] unsigned char
* VT_UI2 [V][T][P][S] unsigned short
* VT_UI4 [V][T][P][S] unsigned long
* VT_I8 [T][P] signed 64-bit int
* VT_UI8 [T][P] unsigned 64-bit int
* VT_INT [V][T][P][S] signed machine int
* VT_UINT [V][T] [S] unsigned machine int
* VT_INT_PTR [T] signed machine register size width
* VT_UINT_PTR [T] unsigned machine register size width
* VT_VOID [T] C style void
* VT_HRESULT [T] Standard return type
* VT_PTR [T] pointer type
* VT_SAFEARRAY [T] (use VT_ARRAY in VARIANT)
* VT_CARRAY [T] C style array
* VT_USERDEFINED [T] user defined type
* VT_LPSTR [T][P] null terminated string
* VT_LPWSTR [T][P] wide null terminated string
* VT_FILETIME [P] FILETIME
* VT_BLOB [P] Length prefixed bytes
* VT_STREAM [P] Name of the stream follows
* VT_STORAGE [P] Name of the storage follows
* VT_STREAMED_OBJECT [P] Stream contains an object
* VT_STORED_OBJECT [P] Storage contains an object
* VT_VERSIONED_STREAM [P] Stream with a GUID version
* VT_BLOB_OBJECT [P] Blob contains an object
* VT_CF [P] Clipboard format
* VT_CLSID [P] A Class ID
* VT_VECTOR [P] simple counted array
* VT_ARRAY [V] SAFEARRAY*
* VT_BYREF [V] void* for local use
* VT_BSTR_BLOB Reserved for system use
*/


From the VTypes.h in the core sdk... it appears its not a concern ;)
:alright:
NaN
Posted on 2003-01-01 16:20:33 by NaN
Hello Japheth,

I did a full study of your macro's etc. You have some good ideas in there that i have picked up on. Especially your decision to output the typelib data into macro statements "DEFINE_DISPMETHOD"... This is a very good idea!

Mainly because, i think we are standing on two different viewpoints on how to proceed from here ;)

Your macros like to declair .const data strings for each dispatched invoke type. Were my view is to have it dynamic (and on the stack as you suggested). As well, your method forces me to manually set up required VARIANTS for each param in the argument (to me this is an irratating overhead, and i try to avoid it if i can). With the dynamic approach, you can define what it will be each time. Ie, one time i might be 'putting' an integer, the next a real8 pointer.. etc etc. etc. If i were to follow your method, i would have to manually decair / init a Vairant, set the type, set the pointer/number, and pass it as an argument (this is the overhead i refered to):

Your model:


LOCAL Var1 :VARIANT
LOCAL Var2 :VARIANT
LOCAL Var3 :VARIANT

invoke InitVairiant, addr Var1
invoke InitVairiant, addr Var2
invoke InitVairiant, addr Var3

mov Var1.vt, VT_I4
mov Var2.vt, VT_I4
mov Var3.vt, VT_I4

mov Var1.lVal, 1 ; Row 1
mov Var2.lVal, 3 ; Col 3
mov Var3.lVal, 20 ; Data to place at (row,col)

invoke dm(pRange, Range, put_Item), Var1, Var2, Var3


My model:


invoke MakeInvokeString, 3, VT_I4, VT_I4, VT_I4
invoke dm(pRange, Range, put_Item), 1,3,20

My model uses less macros as well, only two:
DEFINE_DISPMETHOD macro interface, method:req, dispid:req, functype:req, rettype, args:VARARG


[b] &interface&_&method& TEXTEQU <InvokeHelp, &dispid&, DISPATCH_&functype&>[/b]

ENDM

dm macro this:req, interface, func:req
exitm <&interface&_&func&, [b]this, eax[/b]>
endm


Im still using my two above posted 'C' style funcitons, however, i re-arranged the arguments to fit the macros (an idea you spured me on to with your model).

Attached is my most recient equivalent 'disphlp.inc' file. It works perfectly with your generated output XXXc.asm file. Again, im not trying to insult your work, i just think we have two different ideas in mind. Myself, im aiming on minimizing MACRO and DATA segment functions, while making it still easy to use. Yours is alot easier to 'invoke' but, causes more overhead by forcing the user to either edit the output XXXc.asm to change arument types, or manually set and get VARIANTS for each argument...

I hope you see my point here! Again, not trying to be an Arse ;) I too find this work fun...
:alright:
NaN
Posted on 2003-01-01 20:58:39 by NaN
I just have to say again..

Posted on 2003-01-02 01:08:03 by NaN
NaN,

thanks for your replys. Im about to study your disphlp.inc.

Im really excited by myself about this code generation feature. The fact thats all the code is in macros makes it so easy to test several versions of generated code just be changing disphlp.inc

I agree now with you not to put data in .const
So actually, I've changed disphlp.inc and my stubs now look like:



_Range_get_Item proc public ....

mov eax, offset metadata
call invokehelper
ret
metadata:
dw ....

_Range_get_Item endp


So now only 13 bytes of real code for each stub (yes I used option prologue/epilogue to avoid building stack frames here).

Minimal (?) size would be:



_Range_get_Item proc public ....

call invokehelper
metadata:
dw ....

_Range_get_Item endp


In this version InvokeHelper would have to do a bit extra work, for example do the stack cleanup. But with that version only 5 bytes code overhead! But code looks a bit ugly now :) , so Im still using the version above.

Another point:

Currently I'm thinking to avoid manually activating the stubs (here in excelc.asm). That would mean compile the source to a static lib and support "function level linking". But I dont know how to do that with MASM, in VC its easy and supported by compiler switches. Obviously one have to deal with COMDAT stuff, as I was able to read in MSDN. Do you have any clues there?

BTW: To compile excelc.asm with all lines activated takes a couple of minutes to compile with my machine (about 6800 lines only).

Japheth
Posted on 2003-01-02 05:07:45 by japheth
NaN,

thanks for the tip with manipulating a true range with ApExcel.Range("A1:Z1").BORDERS.Color = RGB(0, 0, 0). Missed that at first glance.

One word about your approach:
No argueing about its flexibility and easy to use. Especially in excel where almost all parameters are of type VARIANT it is great and avoids fiddling around with this data type (it is almost like in VB itself :grin: ). I just want to mention that for the comview code generator I had to follow an approach more rigid. As a consequence, if type info tells a method wants an argument of type VARIANT, you must supply one. Point. If you like you can always code some additional support functionality. And since only macros are used, you may always being able to adapt them to your needs.

Japheth
Posted on 2003-01-02 07:09:48 by japheth

NaN,
...
Another point:

Currently I'm thinking to avoid manually activating the stubs (here in excelc.asm). That would mean compile the source to a static lib and support "function level linking". But I dont know how to do that with MASM, in VC its easy and supported by compiler switches. Obviously one have to deal with COMDAT stuff, as I was able to read in MSDN. Do you have any clues there?

BTW: To compile excelc.asm with all lines activated takes a couple of minutes to compile with my machine (about 6800 lines only).

Japheth


Function level linking is great, but i dont think you really need the functions to begin with...

As for the compile time, im amazed.. I didnt turn on every method, but my above generation only makes textequates.. Im not makeing proc's for each, which will save alot of time.

I realize my InvokeHelp is kinda ugly to look at, for the moment. I didnt want to optomize it or anything untill i feel its 1) robust enough, 2) will work consistantly, and 3) simply the best plan of attack ;)

You have some good coding tricks that will certainly optimize it alot (when i get around to it). As well, i didnt follow what you were getting at with the prolog/epilog business (not familiar with these directrives???)

I look forward to seeing what you come up with...
:alright:
NaN
Posted on 2003-01-02 11:46:26 by NaN
I uncommented every DEFINE_DISPMETHOD using my version of the macro (textequ's), and it compiled in maybe 1 second longer.

I've been thinking about the two methods.. they are essentially the same. However your approach has faster code, but requiers long compile times, and mine has about twice as much code, but very fast compile times.

You approach defines a unique funciton to call for each mehtod/property type (making larger EXE's if you have more than say 4 different calls ~ assuming a lib is generated). Mine has only two generic functions to call, which in total, the code would add up to about 4 of your property functions.

Both methods eventually call sub-functions to call the DISP_Invoke method. However your method is strict to the VARIANT rule for params, and mine is more flexible...

Im sorry, Im still not convinced that the procs/lib method is the best choice for DISP_Invoke calling... what are your thoughts?

:alright:
NaN
Posted on 2003-01-02 17:42:02 by NaN
NaN,

I finally did it. Threw away the stub functions I loved so much.

Now COMView generates 2 sort of includes only, one for the vtbles, one for disponlys (okay, one may put them together but you wont gain too much). Nothing is "deactivated" any more and has to be manually activated.

As a consequence, macro DISPMETHOD has become a dummy.
Macro DEFINE_DISPMETHOD defines text equates only (and a dummy proc)
And register EDX is now used in macro dm() (holds this "metadata" stuff pointer). Since edx
ist used in macro vf() as well, this seems no real disadvantage.
The strict parameter checking for disponly calls remained, the calls still going throu MASM's invoke.
So COMView version 1.5.0 was very short-lived, version 1.5.1 is now the right one.

This was hard work

Japheth
Posted on 2003-01-02 19:36:38 by japheth
error 404: Datei nicht gefunden!


Das angegebene Dokument konnte auf diesem Server leider nicht gefunden werden.


I hope you will post your V1.5.1??

Does this version generate the same DEFINE_DISPMETHOD's as before? I.e, you changed the macro, not the generated lines?

Also,
Now COMView generates 2 sort of includes only, one for the vtbles, one for disponlys (okay, one may put them together but you wont gain too much). Nothing is "deactivated" any more and has to be manually activated.

Sounds good, but to be honest there *is* alot to be gained. I choped out all almost all the vtble's except _Application, Workbooks, and the Enumerated Equates. No point having MASM build hash-table entries on stuff that wont work via. vtble calls. However, as im sure your aware of, vtble calls are far faster, so its good to have a hybrid if you can.

:alright:
NaN
Posted on 2003-01-02 21:30:34 by NaN
Hi NaN,

cannot reproduce your error 404. Did U use that link below?

Heres the link

And the other points:

- the generated DEFINE_DISPMETHOD lines havent changed
- the DISPMETHOD macro calls are still located in the other include (although superflous now)
- putting the two includes together: will think about it again

What I want to do is implement support for a more flexible dispatch call like your MakeInvokeString.
But not without some changes :grin: . "MakeInvokeString" I would rename to "PrepareInvoke", and since macro dm() is already used I would implement macro dmx(). The stack allocation you have implemented works and should be save (possibly except for some poorly written spy progs :) ), but I would prefer a solution without having data "below" esp across function calls.

Japheth
Posted on 2003-01-03 03:10:02 by japheth
So, finally I have my more dynamic functions working. For excel automation it is really a relief. Its almost like your procs:



dmx macro this:req, interface, func:req
exitm <ExecuteInvoke, this, &interface&_&func&DispId, &interface&_&func&Type>
endm

sample:
invoke PrepareInvoke, addr tmpVariantArray, 2, VT_I4, 1, VT_I4, 1
invoke dmx(pCells, Range, get_Item), VT_BSTR, addr bstr, eax


I have named the procs PrepareInvoke & ExecuteInvoke. They are slightly modified to avoid this stack allocation stuff.

Japheth
Posted on 2003-01-03 06:26:10 by japheth

Hi NaN,
...
What I want to do is implement support for a more flexible dispatch call like your MakeInvokeString.
But not without some changes :grin: . "MakeInvokeString" I would rename to "PrepareInvoke", and since macro dm() is already used I would implement macro dmx(). The stack allocation you have implemented works and should be save (possibly except for some poorly written spy progs :) ), but I would prefer a solution without having data "below" esp across function calls.

Japheth


This is a valid concern. I too thought about this. 1) would it be a problem on NT os's, 2) would it get overwritten by unknown functions...

Turns out, both are no problem! Especially #2. The way i wrote it is that it fills the stack space at -1000h and returns the pointer to it. When the InvokeHelp function is called, the first thing it does (with about 10 dword stack pushes at this point ~ well ahead of the data) is make stack space, and copies it up into the scope of the function. This way it will be save to call as many functions as the stack will allow and not corrupt the VT string.

I see your making variant arrays instead. This works. But its more overhead than just using the stack you know ;) . And its 100% safe. Here is a what Im talking about (excuse the Acad image, its big, but to the point ;) ):

Ooops, all those EBX's are to be EBP's ;)
Posted on 2003-01-03 12:43:40 by NaN
NaN,
I fully understand that and I agree that its save. Even a Spy which - lets assume - hooks in all Win32 calls has no chance to crash your code because you dont make any win32 call the way from MakeInvoke... to InvokeHelp.
My concerns are exclusive aesthetical.

I have another question about excel. I have got some problems with interface _Worksheet. My code crashes if I call some methods throu vtable (I used _Worksheet::get_Name). Using IDispatch::invoke worked. Thats a bit similar to the Range interface, but this time _Worksheet is clearly defined as "dual", so COMview doesnt create the DISPMETHOD lines at all. Did you have this problem as well or do I have an outdatet office version (use office 2000 from summer 1999).

Possibly I will need to expand comview with an option meaning: "create as many interfaces as possible as dispatchonly, the rest as vtable". Currently its exactly the opposite

Japheth
Posted on 2003-01-03 13:17:05 by japheth
To give you some idea what i have been doing, here is the working Excel class (still using my stack calling method):

Check out how tight i got the code working :) . I've wrapped 'major actions' into class methods, with a few extra bells and wistles :grin:

The Excel.asm class is far from finished, but its also well underway.. As well the disphlp.inc is all dispatch stuff. Ojbects.inc is the OOP model Thomas and I developed. Excelc.inc is your generated DISP output, with some vtbl (early binding) copied and pasted into it (as well as the inc's).

You need to have VKim's debug installed and working to two outputs (prooving two functions).

Enjoy ;)
:alright:
NaN
Posted on 2003-01-03 13:38:42 by NaN
Hi NaN,

I studied your code and executed your sample. I see you currently are playing around and haven't had the need to deal with the _Worksheet interface, so you possibly couldn't say something about it.

Please excuse my curiosity, but I have 2 questions about your oops model/generator?

Do you have feedback from people using your generator and are above the "playing with it" state (say, having made a project with 10000 lines or more?

What are these parameter names A,B,C,D standing for? Is that a restriction? Or do you prefer such variable names :grin: ?


To give you some idea what i have been doing, here is the working Excel class (still using my stack calling method):


Please feel free to code how you like it. I am absolutely aware of that 10 persons have at least 10 different favorite coding styles.

Japheth
Posted on 2003-01-04 09:49:00 by japheth
Yes i have had feedback.. the size of their projects i didnt ask, but they said they are happy using it. (Im currious why you ask, i get the feeling you dont like the model at all).

I have made large projects with it, and works well for me. As had Thomas.

As for the parameters, A,B,D,E,F,G etc... this is just me. The generator makes them quickly since it doesnt ask for param lables. Only the method names and # of params... (is a first draft version that i have yet to update). The param is not a limitation, only my lazyness for not renaming them to something meaningful ;) As wrapper methods, i didnt feel wasting my time...

As for the _Worksheets interface, no i have not used it directly yet...

NaN
Posted on 2003-01-04 12:07:25 by NaN