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
On Thu, Jun 13, 2002 at 08:39:05PM +0100, Ann and Jason Edmeades wrote:
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
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.
Actually I think just the DATE part should be out there, which is 8 byte long.
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.
No, just reuse _argsize() from tmarshal.c, calculate the number of stack positions using this function, allocate enough space, memcpy() out of the VARIANTS into the stack space and invoke. (I have submitted a patch to tmarshal.c).
Looking at the code in there ... I think I have to have another, closer look at it :/
Ciao, Marcus
marcus@jet.franken.de wrote:
Actually I think just the DATE part should be out there, which is 8 byte long.
I'm not convinced. The following tracepoint: trace:ole:ITypeInfo_fnInvoke set 0 to disparg type 7 vs 12
This shows that the arg 0 was supplied by the application as a VT_DATE but the function itself wants a VT_VARIANT. I have found whatever is the first word on the stack is later passed into another variant function as the vt type field. Putting the whole variant onto the stack is the only way I have got beyond that function.
If the function took a VT_DATE, you may well be correct. I think we need to change that code to memcpy onto the args storage the variant size (or sizeof DWORD, I guess as that is minimum size for an arg by the way we currently have it coded). If you agree, I'll have a go at doing a patch, although if you understand it better than me please (really - please!) feel free to code it for me.
My 'hack' definitiely got me further through to the next point which is a bug in the oleaut32 vardate handling routines which I am currently hacking. My last change cause the app to crash the whole of Linux (no mouse, keyboard etc!). Rebooting now to try again...
Oh I love having a few days off with nothing to do except fiddling with wine internals!
Regards, Jason