I have the following code for testing Autocad automation, it should draw a circle in model space.


F3DPOINT STRUCT

X real8 ?
Y real8 ?
Z real8 ?
F3DPOINT ENDS



InitAcad proc
LOCAL pIAcadDocument:dword
LOCAL pIModelSpace:dword
LOCAL pICircle:dword
LOCAL AcadPnt:VARIANT
LOCAL AcadXYZ:SAFEARRAY
LOCAL Radius:REAL8
LOCAL XYZ:F3DPOINT
LOCAL OwID:dword

finit
fld1;just for testing X=Y=Z=Radius=1
fst Radius
fst XYZ.X
fst XYZ.Y
fstp XYZ.Z

mov AcadXYZ.cDims,1
mov AcadXYZ.fFeatures,1
mov AcadXYZ.cbElements,8
mov AcadXYZ.cLocks,0
lea eax,XYZ
mov AcadXYZ.pvData,eax
mov AcadXYZ.rgsabound.lLbound,0
mov AcadXYZ.rgsabound.cElements,3


mov AcadPnt.vt,VT_R8 or VT_ARRAY
mov AcadPnt.wReserved1,0
mov AcadPnt.wReserved2,0
mov AcadPnt.wReserved3,0
lea eax,AcadXYZ
mov AcadPnt.parray,eax



invoke CoInitialize, NULL
invoke CoCreateInstance, ADDR CLSID_AcadApplication, NULL, CLSCTX_ALL,\
addr IID_IAcadApplication, addr pIAcadApplication
PrintHex eax,"ACAD CoCreateInstance ret value"
invoke vf(pIAcadApplication, IAcadApplication, put_Visible), TRUE
PrintHex pIAcadDocument
invoke vf(pIAcadApplication, IAcadApplication, get_ActiveDocument), addr pIAcadDocument
PrintHex pIAcadDocument
PrintHex pIModelSpace
invoke dm(pIAcadDocument, IAcadDocument, get_ModelSpace), addr pIModelSpace
PrintHex pIModelSpace
PrintHex OwID
invoke dm(pIModelSpace, IAcadModelSpace, get_OwnerID), addr OwID ;this seems to work
PrintHex OwID

invoke dm(pIModelSpace, IAcadModelSpace, AddCircle), addr pICircle,AcadPnt,Radius


invoke CoUninitialize
ret

InitAcad endp



This wont assemble unless i comment out the actual drawing function

invoke dm(pIModelSpace,IAcadModelSpace,AddCircle),addr pICircle,AcadPnt,Radius

If not commented out, i get the errors regarding the above line:

error A2114: INVOKE argument type mismatch : argument : 5

error A2114: INVOKE argument type mismatch : argument : 4
error A2114: INVOKE argument type mismatch : argument : 3


in autocadc.inc there is

DEFINE_DISPMETHOD IAcadModelSpace , AddCircle, 060Ah, METHOD, VT_BYREF OR VT_USERDEFINED, VT_VARIANT,VT_R8


so i don't get it. Where's the mismatch?

Does the SAFEARRAY / VARIANT init look right, i'm not too sure about them? Anyway, even if they are not correct, that should not affect assembling?

.:EDIT: by NaN to add 'CODE' blocks. Janne, edit your post to learn what I did ;)
Posted on 2003-07-20 07:39:15 by Janne
changed

invoke dm(pIModelSpace, IAcadModelSpace, AddCircle), addr pICircle, AcadPnt, Radius


to

invoke dm(pIModelSpace, IAcadModelSpace, AddCircle), AcadPnt, Radius, addr pICircle


,now the damn thing works.

I thought that i can see the order of the parameters from

DEFINE_DISPMETHOD IAcadModelSpace , AddCircle, 060Ah, METHOD, VT_BYREF OR VT_USERDEFINED, VT_VARIANT,VT_R8


but apparently not?
Posted on 2003-07-20 12:02:05 by Janne
1) I hope you dont mind, but I edited you posts such that i can better read and understand your source and problem. Basically i added "code" blocks.

2) I find you problem odd. And not really sure why, but i suspect that it has alot to do with the dm() macro and sustaining source for it. A while back, burried somewhere in this forum, Japheth and I had a very long discussion on the eventual need and development of the dm() macro. However, at the end of the day, Japheth had his own views on how it should run (code wise), and I had my own. Im not saying his is wrong, but I dont *know* it, because i dont use it.

My version is close to his, but different in how it sets up the arguments to methods, and then calls the invoke method. I have a source file called "Disphelp.inc" does alot of the dirty work of dealing with variants for Invoke methods. I have attached the DispHelp.inc file that i use with his COMView outputs, use it if you like.

It will generate the variants for you, all you need to do is call the first "MakeInvokeString" to specify the arguments a method may have (number, flowed by the VT_* types for each argument). Then in the dm() invoke call, the first two arguments are the return type, and return value pointer (they can be NULL if ther is no return). All other arguments are the values to stuff into the variant's, as prescribed in the above "MakeInvokeString" call. My function here will use the stack to allocated a bunch of variants as needed and fill them with your arguments, and type befor calling the Invoke method.

With this source included into a project here is how i would have done your source:
F3DPOINT STRUCT

X real8 ?
Y real8 ?
Z real8 ?
F3DPOINT ENDS

.data
AcadXYZ F3DPOINT <1.0, 2.0, 3.0>

.code


; Build a SAFEARRAY of R8 numbers
invoke SafeArrayCreateVector, VT_R8, 0, 3
mov hSafeArray, eax

xor eax, eax
mov counter, eax
[b]lea eax, AcadXYZ[/b]
mov countdata, eax
.while (counter != 3)
invoke SafeArrayPutElement, hSafeArray, addr counter, countdata
inc counter
add countdata, 8
.endw

; Your source transcribed...
invoke CoInitialize, NULL
invoke CoCreateInstance, ADDR CLSID_AcadApplication, NULL, CLSCTX_ALL,\
addr IID_IAcadApplication, addr pIAcadApplication

invoke vf(pIAcadApplication, IAcadApplication, put_Visible), TRUE

invoke vf(pIAcadApplication, IAcadApplication, get_ActiveDocument), addr pIAcadDocument


;OLD: invoke dm(pIAcadDocument, IAcadDocument, get_ModelSpace), addr pIModelSpace
invoke MakeInvokeString, 0
invoke dm(pIAcadDocument, IAcadDocument, get_ModelSpace), VT_DISPATCH, addr pIModelSpace


;OLD: invoke dm(pIModelSpace, IAcadModelSpace, get_OwnerID), addr OwID
invoke MakeInvokeString, 0
invoke dm(pIModelSpace, IAcadModelSpace, get_OwnerID), VT_DISPATCH, addr OwID


;OLD: invoke dm(pIModelSpace, IAcadModelSpace, AddCircle), addr pICircle,AcadPnt,Radius
;DEFINE_DISPMETHOD IAcadModelSpace , AddCircle, 060Ah, METHOD, VT_BYREF OR VT_USERDEFINED,
invoke MakeInvokeString, 2, VT_ARRAY or VT_R8, VT_R8
invoke dm(pIModelSpace, IAcadModelSpace, get_OwnerID), VT_DISPATCH, addr pICircle, [b]hSafeArray[/b], Radius

[b]invoke SafeArrayDestroy, hSafeArray[/b]

invoke CoUninitialize


As well it shows you how to use the SafeArrays ;)

Hope this is some help to you!
:alright:
NaN
Posted on 2003-07-20 13:15:33 by NaN
Oops, for got to post the source ;)
Posted on 2003-07-20 14:22:16 by NaN
NaN, thanks a lot for all the info.
Posted on 2003-07-20 14:44:34 by Janne
Hi guys,

let me mention my view as well. This problem is not an error in macro dm(), it's due to some misunderstanding.

Janne, this DEFINE_DISPMETHOD macro has following parameters:



DEFINE_DISPMETHOD Interfacename, Methodname, DISPID, InvokeKind, return type, parameter1 type, parameter2 type,...


If you look in typeinfo for IDispatch interface IAcadModelSpace you will see method AddCircle defined as

[] Ptr IAcadCircle AddCircle ( Center:Variant, Radius:R8 )

So DEFINE_DISPMETHOD is correct in my eyes.

macro dm() in fact expects parameters in standard COM format, that is

1. the method itself does return a HResult (in eax)
2. "return type" from IDispatch interface will be last parameter and converted to a pointer to this type

There exists a typeinfo (somewhat hidden in comview, but you may find it) with type TKIND_INTERFACE (not TKIND_DISPATCH), where this parameter structure could be seen:

[] HResult AddCircle ( Center:Variant, Radius:R8, pCircle:Ptr Ptr IAcadCircle )

And this parameter structure is used for the call, that is, this function has in fact 3 parameters (+ "this"),
and returntype comes last.

Japheth
Posted on 2003-07-20 15:42:27 by japheth
Japheth, im sorry if I offended you. It was not my goal. I only ment to explain that what i can provide *is* going to be different from what you have provided for the dm() macro. Hopefully no offense to you, but i choose to use my stack based calling proceedure instead of your alternate (forget how it works at this point, sorry).

:NaN:
Posted on 2003-07-20 20:42:24 by NaN
NaN, its ok, I didnt feel insulted

Japheth
Posted on 2003-07-20 23:58:22 by japheth