ole help please! invoke fn issue

Ann and Jason Edmeades us at the-edmeades.demon.co.uk
Thu Jun 13 14:39:05 CDT 2002


Hi all,

Playing further with my VB program and native oleaut32 I've hit an
'interesting issue' with the Microsoft Date/Time picker.

typelib.c in dlls\oleaut32 assumes all parms are dwords and picks the lval
of a variant (which for most of the types of variant is the dword containing
the important information). However as shown by the following trace:

trace:ole:ITypeInfo_fnInvoke
(0x404560ac)(0x40418fac,id=20,flags=0x00000004,0x405c5d84,(nil),0x405c5d64,0
x405c5d94) partial stub!
trace:ole:dump_DispParms args=1 named args=1
trace:ole:dump_Variant (0x405c5dec)
trace:ole:dump_Variant VARTYPE: VT_DATE
trace:ole:dump_Variant (?)-882854389
L"Value"(1)
	parm0: L"\00e5MSComCtl2WWW"
memid is 00000014
Param 0:
		tdesc.vartype 12 (VT_VARIANT)
		u.parmadesc.flags 1
		u.parmadesc.lpex (nil)
	funckind: 1 (pure virtual)
	invkind: 4 (property put)
	callconv: 4 (stdcall)
	oVft: 224
	cParamsOpt: 0
	wFlags: 3c
	helpstring: L"Returns/sets the current date."
	entry: (null)
08072560:Call ntdll.RtlAllocateHeap(40370000,00000000,00000008) ret=408bfcc3
08072560:Ret  ntdll.RtlAllocateHeap() retval=4041a160 ret=408bfcc3
08072560:Call ntdll.RtlAllocateHeap(40370000,00000008,00000004) ret=408bfce4
08072560:Ret  ntdll.RtlAllocateHeap() retval=4041a180 ret=408bfce4
trace:ole:ITypeInfo_fnInvoke set 0 to disparg type 7 vs 12

This shows that the function takes one parm and that parm is a variant. We
pass the value contained in the parm and it fails. We need to ensure the
whole variant is put on the stack for the called function. Since we
currently only call with dword parms this wont work.

I have managed to get further by a dirty hack:

        DWORD numArgWords = 0;

	    args[0] = (DWORD)pIUnk;

	    for (i=0;i<pFDesc->funcdesc.cParams;i++) {
		if (i<pDispParams->cArgs) {
		    TRACE("set %d to disparg type %d vs %d\n",i,
			    V_VT(&pDispParams->rgvarg[pDispParams->cArgs-i-1]),
			    pFDesc->funcdesc.lprgelemdescParam[i].tdesc.vt
		    );

            if (pFDesc->funcdesc.lprgelemdescParam[i].tdesc.vt !=
VT_VARIANT) {
		       args[i+1] =
V_UNION(&pDispParams->rgvarg[pDispParams->cArgs-i-1],lVal);
               numArgWords = numArgWords+1;
            } else {
               TRACE("Faking variant on stack as more args \n");
               memcpy(&args[i+1],
&pDispParams->rgvarg[pDispParams->cArgs-i-1], sizeof(VARIANT));
               numArgWords = numArgWords + sizeof(VARIANT)/4;
            }

		} else {
		    TYPEDESC *tdesc = &(pFDesc->funcdesc.lprgelemdescParam[i].tdesc);
		    TRACE("set %d to pointer for get (type is %d)\n",i,tdesc->vt);
		    /*FIXME: give pointers for the rest, so propertyget works*/
		    args[i+1] = (DWORD)&args2[i];
            numArgWords = numArgWords+1;

		    /* If pointer to variant, pass reference to variant
		     * in result variant array.
		     */
		    if ((tdesc->vt == VT_PTR) &&
			(tdesc->u.lptdesc->vt == VT_VARIANT) &&
			pVarResult
		    )
			args[i+1] = (DWORD)(pVarResult+(i-pDispParams->cArgs));
		}
	    }
        TRACE("_invoke with %ld args\n", numArgWords+1);
	    res = _invoke((*(DWORD***)pIUnk)[pFDesc->funcdesc.oVft/4],
		    pFDesc->funcdesc.callconv,
		    numArgWords+1,
		    args
	    );

This hack takes the parm and puts the variant into that arg and subsequent
ones, meaning the stack to the called function should look as it would be.
Unfortunately as it stands this would only work with one parm, so my
question is how it is supposed to be fixed. I could potentially change
args[i+1] to args[numArgWords+1] but it still feels very hacky.

If I have been ignorant of something please bear with me - I've never
touched com programming before!

Regards,
Jason





More information about the wine-devel mailing list