Alex Villací­s Lasso escribió:
Robert Shearman escribió:
[EMAIL PROTECTED] wrote:
In a tax app written in Visual Basic/ADO, I found the following problem:

In dlls/oleaut32/typelib.c, in function ITypeInfo_fnInvoke(), the
following code is found (around line 5569).

VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer,
func_desc->cParams);

V_VT(arg) = VT_VARIANT | VT_BYREF;
V_VARIANTREF(arg) = &missing_arg[i];
V_VT(V_VARIANTREF(arg)) = VT_ERROR;
V_ERROR(V_VARIANTREF(arg)) = DISP_E_PARAMNOTFOUND;

This code runs when a parameter is found that has the PARAMFLAG_FIN and
PARAMFLAG_FOPT flags, but not the PARAMFLAG_FHASDEFAULT flag. As far as I understand, this code is supposed to supply a variant that might hold an
output value. However, in the Append method of the Fields object within
the Recordset object of Microsoft ADODB 2.7, the following declaration is
found:

trace:ole:ITypeInfo_fnInvoke invoking:
L"Append"(5)
    parm0: L"Name"
    parm1: L"Type"
    parm2: L"DefinedSize"
    parm3: L"Attrib"
    parm4: L"FieldValue"
memid is 00000003
Param 0:
        tdesc.vartype 8 (VT_BSTR)
        u.paramdesc.wParamFlags PARAMFLAG_FIN
        u.paramdesc.lpex (nil)
Param 1:
        tdesc.vartype 29 (VT_USERDEFINED ref = 2bc)
        u.paramdesc.wParamFlags PARAMFLAG_FIN
        u.paramdesc.lpex (nil)
Param 2:
        tdesc.vartype 29 (VT_USERDEFINED ref = 1c84)
u.paramdesc.wParamFlags PARAMFLAG_FIN PARAMFLAG_FOPT PARAMFLAG_FHASDEFAULT
        u.paramdesc.lpex 0x199868
Param 3:
        tdesc.vartype 29 (VT_USERDEFINED ref = 320)
u.paramdesc.wParamFlags PARAMFLAG_FIN PARAMFLAG_FOPT PARAMFLAG_FHASDEFAULT
        u.paramdesc.lpex 0x1998d0
Param 4:
        tdesc.vartype 12 (VT_VARIANT)
        u.paramdesc.wParamFlags PARAMFLAG_FIN PARAMFLAG_FOPT
        u.paramdesc.lpex (nil)
    funckind: 1 (pure virtual)
    invkind: 1 (func)
    callconv: 4 (stdcall)
    oVft: 52
    cParamsOpt: 1
    wFlags: 0
    elemdescFunc (return value type):
        tdesc.vartype 25 (VT_HRESULT)
        u.paramdesc.wParamFlags PARAMFLAGS_NONE
        u.paramdesc.lpex (nil)
    helpstring: (null)
    entry (ordinal): 0x0000

The implementation of the method in Microsoft ADODB 2.7 last parameter
(FieldValue) absolutely refuses to accept a VT_VARIANT | VT_BYREF variant.
This result is not dependent of the type of variant pointed to by the
first-level variant - changing VT_ERROR to VT_EMPTY has no effect. Only by passing a VT_EMPTY instead of a VT_VARIANT | VT_BYREF can the application proceed normally. All oleaut32 tests still pass. Please comment if this is
an appropriate fix for this issue.

Changelog:
* (PARAMFLAG_FIN | PARAMFLAG_FOPT) & ~PARAMFLAG_FHASDEFAULT should result
in a default parameter of VT_EMPTY, not a VT_VARIANT | VT_BYREF in
ITypeInfo_fnInvoke


I don't believe this is fix is correct. See the tests not included in Wine yet here: http://www.winehq.org/pipermail/wine-patches/2006-August/029511.html

In particular, this code:
+HRESULT WINAPI Widget_DoSomething(
+    IWidget __RPC_FAR * iface,
+    /* [in] */ double number,
+    /* [out] */ BSTR *str1,
+    /* [defaultvalue][in] */ BSTR str2,
+    /* [optional][in] */ VARIANT __RPC_FAR *opt)
+{
+    static const WCHAR szString[] = { 'S','t','r','i','n','g',0 };
+    trace("DoSomething()\n");
+
+    ok(number == 3.141, "number(%f) != 3.141\n", number);
+    ok(*str2 == '\0', "str2(%s) != \"\"\n", wine_dbgstr_w(str2));
+ ok(V_VT(opt) == VT_ERROR, "V_VT(opt) should be VT_ERROR instead of 0x%x\n", V_VT(opt)); + ok(V_ERROR(opt) == DISP_E_PARAMNOTFOUND, "V_ERROR(opt) should be DISP_E_PARAMNOTFOUND instead of 0x%08lx\n", V_ERROR(opt));
+    *str1 = SysAllocString(szString);
+
+    return S_FALSE;
+}


Bug http://bugs.winehq.org/show_bug.cgi?id=6638 was opened for this problem. I have reasons to believe that this is a case of (undocumented?) overloading with builtin oleaut32 calling the wrong version of a method. The bug report has a full explanation of this, and the reasons why I arrived at the overloading theory. However I need an OLE Automation expert to verify my hypothesis. Please comment on this (especially from the Codeweavers people).

Here is a patch that implements my hunch. This patch fixes the problem on both my test app at bug #6638 and the tax app I try to run.

Changelog:
* When there are not enough actual parameters for invoking, look for a possible overload with underscore prefix before trying the original function.

--
The following cryptic message was allegedly found in the inner edge of a Windows
XP installation CD:

4F6E65204F5320746F2072756C65207468656D20616C6C2C204F6E65204F5320746F2066696E6420
7468656D2C0D0A4F6E65204F5320746F206272696E67207468656D20616C6C20616E6420696E2074
6865206461726B6E6573732062696E64207468656D2E0A

It is rumored that only a true Unix Wizard can decypher this mysterious message,
which supposedly encodes the true nature and purpose of the software.

Subdirectorios comunes: wine-0.9.25-cvs/dlls/oleaut32/CVS y wine-0.9.25-cvs-patch/dlls/oleaut32/CVS
Subdirectorios comunes: wine-0.9.25-cvs/dlls/oleaut32/tests y wine-0.9.25-cvs-patch/dlls/oleaut32/tests
diff -u wine-0.9.25-cvs/dlls/oleaut32/typelib.c wine-0.9.25-cvs-patch/dlls/oleaut32/typelib.c
--- wine-0.9.25-cvs/dlls/oleaut32/typelib.c	2006-11-09 13:01:55.000000000 -0500
+++ wine-0.9.25-cvs-patch/dlls/oleaut32/typelib.c	2006-11-12 15:13:16.000000000 -0500
@@ -5447,6 +5447,43 @@
             break;
 
     if (pFuncInfo) {
+	/* Count all formal parameters for the original requested function. If the
+	   number of actual parameters is less than the number of formal 
+	   parameters, a search is made for a function with a leading underscore 
+	   before the name: if current function is called Append, search for _Append.
+	 */
+        ITypeInfo2_GetTypeKind(iface, &type_kind);
+        if ((type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) 
+                && pFuncInfo->funcdesc.cParams > pDispParams->cArgs)
+        {
+            MEMBERID iMemberID;
+            LPOLESTR sOverloadName;
+            
+            TRACE("%s(): actual params (%d) < formal params (%d), looking for overload...\n",
+                debugstr_w(pFuncInfo->Name), pDispParams->cArgs, pFuncInfo->funcdesc.cParams);
+            sOverloadName = HeapAlloc(GetProcessHeap(), 0, (2 + strlenW(pFuncInfo->Name)) * sizeof(WCHAR));
+            sOverloadName[0] = '_'; sOverloadName[1] = '\0';
+            strcatW(sOverloadName, pFuncInfo->Name);
+            TRACE("%s(): looking for overload %s()...\n", debugstr_w(pFuncInfo->Name), debugstr_w(sOverloadName));
+            
+            hres = ITypeInfo2_GetIDsOfNames(iface, &sOverloadName, 1, &iMemberID);
+            if (hres == S_OK) {
+                /* TODO: filter out candidates with even more args than current function */
+                memid = iMemberID;
+                TRACE("%s(): found overload, memid = 0x%04x\n", debugstr_w(pFuncInfo->Name), iMemberID);
+                for (pFuncInfo = This->funclist; pFuncInfo; pFuncInfo=pFuncInfo->next)
+                    if ((memid == pFuncInfo->funcdesc.memid) &&
+                        (wFlags & pFuncInfo->funcdesc.invkind))
+                        break;
+            } else {
+                TRACE("%s(): could not find any overload, err = 0x%08x\n", debugstr_w(pFuncInfo->Name), hres);
+            }
+            
+            HeapFree(GetProcessHeap(), 0, sOverloadName);
+        }
+    }
+
+    if (pFuncInfo) {
         const FUNCDESC *func_desc = &pFuncInfo->funcdesc;
 
         if (TRACE_ON(ole))


Reply via email to