PATCH: ITypeInfo::Invoke
Marcus Meissner
marcus at jet.franken.de
Fri Aug 3 15:34:46 CDT 2001
Hi,
I am currently trying to get s25 at once, a program to access my cellphone,
running. It is programmed in VB5, which makes heavy of OLE Automation.
For instance it uses ITypeInfo::Invoke.
This patch implements large parts of this function which are used
by this program. I have also added FIXME()s for all unsupported cases.
Ciao, Marcus
Changelog:
First (partial) implementation of ITypeInfo::Invoke.
Index: typelib.c
===================================================================
RCS file: /home/wine/wine/dlls/oleaut32/typelib.c,v
retrieving revision 1.41
diff -u -r1.41 typelib.c
--- typelib.c 2001/08/03 18:13:24 1.41
+++ typelib.c 2001/08/03 20:41:07
@@ -51,11 +51,15 @@
#include "winerror.h"
#include "winnls.h" /* for PRIMARYLANGID */
#include "winreg.h" /* for HKEY_LOCAL_MACHINE */
+#include "winbase.h"
+#include "wingdi.h"
#include "wine/obj_base.h"
#include "heap.h"
+#include "docobj.h"
#include "ole2disp.h"
#include "typelib.h"
+#include "olectl.h"
#include "debugtools.h"
@@ -621,11 +625,92 @@
/*
debug
*/
+static void dump_VarType(VARTYPE vt,char *szVarType) {
+ /* FIXME : we could have better trace here, depending on the VARTYPE
+ * of the variant
+ */
+ switch(vt) {
+ case VT_UI1: MESSAGE(szVarType, "VT_UI"); break;
+ case VT_I2: sprintf(szVarType, "VT_I2"); break;
+ case VT_I4: sprintf(szVarType, "VT_I4"); break;
+ case VT_R4: sprintf(szVarType, "VT_R4"); break;
+ case VT_R8: sprintf(szVarType, "VT_R8"); break;
+ case VT_BOOL: sprintf(szVarType, "VT_BOOL"); break;
+ case VT_ERROR: sprintf(szVarType, "VT_ERROR"); break;
+ case VT_CY: sprintf(szVarType, "VT_CY"); break;
+ case VT_DATE: sprintf(szVarType, "VT_DATE"); break;
+ case VT_BSTR: sprintf(szVarType, "VT_BSTR"); break;
+ case VT_BYREF: case VT_UNKNOWN: sprintf(szVarType, "VT_BYREF"); break;
+ case VT_DISPATCH: sprintf(szVarType, "VT_DISPATCH"); break;
+ case VT_ARRAY: sprintf(szVarType, "VT_ARRAY"); break;
+ case VT_I1: sprintf(szVarType, "VT_I2"); break;
+ case VT_UI2: sprintf(szVarType, "VT_UI2"); break;
+ case VT_UI4: sprintf(szVarType, "VT_UI4"); break;
+ case VT_INT: sprintf(szVarType, "VT_INT"); break;
+ case VT_UINT: sprintf(szVarType, "VT_UINT"); break;
+ default: sprintf(szVarType, "unknown");break;
+ }
+}
+static void dump_ELEMDESC(ELEMDESC *edesc) {
+ char buf[200];
+ dump_VarType(edesc->tdesc.vt,buf);
+ MESSAGE("\t\ttdesc.vartype %d (%s)\n",edesc->tdesc.vt,buf);
+ MESSAGE("\t\tu.parmadesc.flags %x\n",edesc->u.paramdesc.wParamFlags);
+ MESSAGE("\t\tu.parmadesc.lpex %p\n",edesc->u.paramdesc.pparamdescex);
+}
+static void dump_FUNCDESC(FUNCDESC *funcdesc) {
+ int i;
+ MESSAGE("memid is %d\n",(int)funcdesc->memid);
+ for (i=0;i<funcdesc->cParams;i++)
+ MESSAGE("Param %d:\n",i);dump_ELEMDESC(funcdesc->lprgelemdescParam+i);
+ MESSAGE("\tfunckind: %d (",funcdesc->funckind);
+ switch (funcdesc->funckind) {
+ case FUNC_VIRTUAL: MESSAGE("virtual");break;
+ case FUNC_PUREVIRTUAL: MESSAGE("pure virtual");break;
+ case FUNC_NONVIRTUAL: MESSAGE("nonvirtual");break;
+ case FUNC_STATIC: MESSAGE("static");break;
+ case FUNC_DISPATCH: MESSAGE("dispatch");break;
+ default: MESSAGE("unknown");break;
+ }
+ MESSAGE(")\n\tinvkind: %d (",funcdesc->invkind);
+ switch (funcdesc->invkind) {
+ case INVOKE_FUNC: MESSAGE("func");break;
+ case INVOKE_PROPERTYGET: MESSAGE("property get");break;
+ case INVOKE_PROPERTYPUT: MESSAGE("property put");break;
+ case INVOKE_PROPERTYPUTREF: MESSAGE("property put ref");break;
+ }
+ MESSAGE(")\n\tcallconv: %d (",funcdesc->callconv);
+ switch (funcdesc->callconv) {
+ case CC_CDECL: MESSAGE("cdecl");break;
+ case CC_PASCAL: MESSAGE("pascal");break;
+ case CC_STDCALL: MESSAGE("stdcall");break;
+ case CC_SYSCALL: MESSAGE("syscall");break;
+ default:break;
+ }
+ MESSAGE(")\n\toVft: %d\n", funcdesc->oVft);
+ MESSAGE("\tcParamsOpt: %d\n", funcdesc->cParamsOpt);
+ MESSAGE("\twFlags: %x\n", funcdesc->wFuncFlags);
+}
+static void dump_TLBFuncDescOne(TLBFuncDesc * pfd)
+{
+ int i;
+ if (!TRACE_ON(typelib))
+ return;
+ MESSAGE("%s(%u)\n", debugstr_w(pfd->Name), pfd->funcdesc.cParams);
+ for (i=0;i<pfd->funcdesc.cParams;i++)
+ MESSAGE("\tparm%d: %s\n",i,debugstr_w(pfd->pParamDesc[i].Name));
+
+
+ dump_FUNCDESC(&(pfd->funcdesc));
+
+ MESSAGE("\thelpstring: %s\n", debugstr_w(pfd->HelpString));
+ MESSAGE("\tentry: %s\n", debugstr_w(pfd->Entry));
+}
static void dump_TLBFuncDesc(TLBFuncDesc * pfd)
{
while (pfd)
{
- TRACE_(typelib)("%s(%u)\n", debugstr_w(pfd->Name), pfd->funcdesc.cParams);
+ dump_TLBFuncDescOne(pfd);
pfd = pfd->next;
};
}
@@ -660,82 +745,8 @@
/* FIXME : we could have better trace here, depending on the VARTYPE
* of the variant
*/
- switch(V_VT(pvar))
- {
- case VT_UI1:
- sprintf(szVarType, "VT_UI");
- break;
-
- case VT_I2:
- sprintf(szVarType, "VT_I2");
- break;
-
- case VT_I4:
- sprintf(szVarType, "VT_I4");
- break;
-
- case VT_R4:
- sprintf(szVarType, "VT_R4");
- break;
-
- case VT_R8:
- sprintf(szVarType, "VT_R8");
- break;
-
- case VT_BOOL:
- sprintf(szVarType, "VT_BOOL");
- break;
-
- case VT_ERROR:
- sprintf(szVarType, "VT_ERROR");
- break;
-
- case VT_CY:
- sprintf(szVarType, "VT_CY");
- break;
-
- case VT_DATE:
- sprintf(szVarType, "VT_DATE");
- break;
-
- case VT_BSTR:
- sprintf(szVarType, "VT_BSTR");
- break;
-
- case VT_BYREF:
- case VT_UNKNOWN:
- sprintf(szVarType, "VT_BYREF");
- break;
-
- case VT_DISPATCH:
- sprintf(szVarType, "VT_DISPATCH");
- break;
-
- case VT_ARRAY:
- sprintf(szVarType, "VT_ARRAY");
- break;
-
- case VT_I1:
- sprintf(szVarType, "VT_I2");
- break;
-
- case VT_UI2:
- sprintf(szVarType, "VT_UI2");
- break;
-
- case VT_UI4:
- sprintf(szVarType, "VT_UI4");
- break;
-
- case VT_INT:
- sprintf(szVarType, "VT_INT");
- break;
-
- case VT_UINT:
- sprintf(szVarType, "VT_UINT");
- break;
- }
-
+ dump_VarType(V_VT(pvar),szVarType);
+
TRACE("VARTYPE: %s\n", szVarType);
switch (V_VT(pvar))
@@ -1459,7 +1470,7 @@
ptiRet->pTypeLib = pLibInfo;
ptiRet->index=count;
/* fill in the typeattr fields */
- FIXME("Assign constructor/destrutor memid\n");
+ FIXME("Assign constructor/destructor memid\n");
TLB_ReadGuid(&ptiRet->TypeAttr.guid, tiBase.posguid, pcx);
ptiRet->TypeAttr.lcid=pLibInfo->LibAttr.lcid; /* FIXME: correct? */
@@ -2846,21 +2857,188 @@
* Invokes a method, or accesses a property of an object, that implements the
* interface described by the type description.
*/
+static DWORD _invoke(LPVOID func,CALLCONV callconv, int nrargs, DWORD *args) {
+ DWORD res;
+
+ if (TRACE_ON(ole)) {
+ int i;
+ MESSAGE("Calling %p(",func);
+ for (i=0;i<nrargs;i++) MESSAGE("%08lx,",args[i]);
+ MESSAGE(")\n");
+ }
+
+ switch (callconv) {
+ case CC_STDCALL:
+
+ switch (nrargs) {
+ case 0: {
+ DWORD (WINAPI *xfunc)() = func;
+ res = xfunc();
+ break;
+ }
+ case 1: {
+ DWORD (WINAPI *xfunc)(DWORD) = func;
+ res = xfunc(args[0]);
+ break;
+ }
+ case 2: {
+ DWORD (WINAPI *xfunc)(DWORD,DWORD) = func;
+ res = xfunc(args[0],args[1]);
+ break;
+ }
+ case 3: {
+ DWORD (WINAPI *xfunc)(DWORD,DWORD,DWORD) = func;
+ res = xfunc(args[0],args[1],args[2]);
+ break;
+ }
+ default:
+ FIXME("unsupported number of arguments %d in stdcall\n",nrargs);
+ res = -1;
+ break;
+ }
+ break;
+ default:
+ FIXME("unsupported calling convention %d\n",callconv);
+ res = -1;
+ break;
+ }
+ TRACE("returns %08lx\n",res);
+ return res;
+}
+
static HRESULT WINAPI ITypeInfo_fnInvoke(
- ITypeInfo2 *iface,
- VOID *pIUnk,
- MEMBERID memid,
- UINT16 dwFlags,
- DISPPARAMS *pDispParams,
- VARIANT *pVarResult,
- EXCEPINFO *pExcepInfo,
- UINT *pArgErr)
+ ITypeInfo2 *iface,
+ VOID *pIUnk,
+ MEMBERID memid,
+ UINT16 dwFlags,
+ DISPPARAMS *pDispParams,
+ VARIANT *pVarResult,
+ EXCEPINFO *pExcepInfo,
+ UINT *pArgErr)
{
ICOM_THIS( ITypeInfoImpl, iface);
- FIXME("(%p)(%p,id=0x%08lx,0x%08x,%p,%p,%p,%p) stub!\n",
- This, pIUnk, memid, dwFlags, pDispParams, pVarResult, pExcepInfo, pArgErr );
+ TLBFuncDesc * pFDesc;
+ TLBVarDesc * pVDesc;
+ int i;
+
+ TRACE("(%p)(%p,id=%ld,flags=0x%08x,%p,%p,%p,%p) partial stub!\n",
+ This,pIUnk,memid,dwFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
+ );
dump_DispParms(pDispParams);
- return S_OK;
+
+ for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
+ if (pFDesc->funcdesc.memid == memid) {
+ if (pFDesc->funcdesc.invkind & (dwFlags & ~DISPATCH_METHOD))
+ break;
+ }
+ if (pFDesc) {
+ dump_TLBFuncDescOne(pFDesc);
+ switch (pFDesc->funcdesc.funckind) {
+ case FUNC_PUREVIRTUAL:
+ case FUNC_VIRTUAL: {
+ DWORD res;
+ DWORD *args = (DWORD*)HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*(pFDesc->funcdesc.cParams+1));
+ DWORD *args2 = (DWORD*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD)*(pFDesc->funcdesc.cParams));
+ 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,
+ pDispParams->rgvarg[i].vt,
+ pFDesc->funcdesc.lprgelemdescParam[i].tdesc.vt
+ );
+ args[i+1] = (DWORD)pDispParams->rgvarg[i].u.lVal;
+ } 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];
+
+ /* 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] = pVarResult+(i-pDispParams->cArgs);
+ }
+ }
+ if (pFDesc->funcdesc.cParamsOpt)
+ FIXME("Does not support optional parameters (%d)\n",
+ pFDesc->funcdesc.cParamsOpt
+ );
+
+ res = _invoke((*(DWORD***)pIUnk)[pFDesc->funcdesc.oVft/4],
+ pFDesc->funcdesc.callconv,
+ pFDesc->funcdesc.cParams+1,
+ args
+ );
+ if (pVarResult && (dwFlags & (DISPATCH_PROPERTYGET))) {
+ for (i=0;i<pFDesc->funcdesc.cParams-pDispParams->cArgs;i++) {
+ TYPEDESC *tdesc = &(pFDesc->funcdesc.lprgelemdescParam[i].tdesc);
+ /* If we are a pointer to a variant, we are done already */
+ if ((tdesc->vt==VT_PTR)&&(tdesc->u.lptdesc->vt==VT_VARIANT))
+ continue;
+
+ VariantInit(&pVarResult[i]);
+ pVarResult[i].u.intVal = args2[i];
+
+ if (tdesc->vt == VT_PTR)
+ tdesc = tdesc->u.lptdesc;
+ pVarResult[i].vt = tdesc->vt;
+
+ /* HACK: VB5 likes this.
+ * I do not know why. There is 1 example in MSDN which uses
+ * this which appears broken (mixes int vals and
+ * IDispatch*.).
+ */
+ if ((tdesc->vt == VT_PTR) && (dwFlags & DISPATCH_METHOD))
+ pVarResult[i].vt = VT_DISPATCH;
+ TRACE("storing into variant: [%d] type %d, val %08x\n",
+ i,pVarResult[i].vt,pVarResult[i].u.intVal
+ );
+ }
+ }
+ HeapFree(GetProcessHeap(),0,args2);
+ HeapFree(GetProcessHeap(),0,args);
+ return S_OK;
+ }
+ case FUNC_DISPATCH: {
+ IDispatch *disp;
+ HRESULT hr;
+
+ hr = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
+ if (hr) {
+ FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
+ return hr;
+ }
+ FIXME("Calling Invoke in IDispatch iface. untested!\n");
+ hr = IDispatch_Invoke(
+ disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,dwFlags,pDispParams,
+ pVarResult,pExcepInfo,pArgErr
+ );
+ if (hr)
+ FIXME("IDispatch::Invoke failed with %08lx. (Could be not a real error?)\n",hr);
+ IDispatch_Release(disp);
+ return hr;
+ }
+ default:
+ FIXME("Unknown function invocation type %d\n",pFDesc->funcdesc.funckind);
+ return E_FAIL;
+ }
+ } else {
+ FIXME("variable based invoking not supported yet.\n");
+ for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) {
+ if (pVDesc->vardesc.memid == memid) {
+ FIXME("varseek: Found memid name %s\n",debugstr_w(((LPWSTR)pVDesc->Name)));
+ dump_TLBVarDesc(pVDesc);
+ break;
+ }
+ }
+ }
+ FIXME("Did not find member id %d!\n",(int)memid);
+ return DISP_E_MEMBERNOTFOUND;
}
/* ITypeInfo::GetDocumentation
More information about the wine-patches
mailing list