Hi, this is a oleaut32 rollup patch. After this, one larger VB6 application called AccuTerm 2000 runs up to the point where it displays the main screen. It still has more failures, but I am working on it. Ciao, Marcus Changelog: Added some wstr to .spec entries which get BSTR arguments. In OleCreatePictureEx icons have width/height to query. DispCallFunc should pass the interface ptr during the call. VariantCopy does not check the result of VariantClear. (added testcase) VariantCopyInd does copy VT_DISPATCH and VT_UNKNOWN (and no longer just silently fails). VT_ARRAY|VT_UI1 -> VT_BSTR coercion is just a memcpy apparently (added testcase). VarBstrCat enhanced a bit. Index: oleaut32.spec =================================================================== RCS file: /home/wine/wine/dlls/oleaut32/oleaut32.spec,v retrieving revision 1.46 diff -u -r1.46 oleaut32.spec --- oleaut32.spec 23 Dec 2002 02:02:50 -0000 1.46 +++ oleaut32.spec 24 Dec 2002 13:35:43 -0000 @@ -2,7 +2,7 @@ 2 stdcall SysAllocString(wstr) SysAllocString 3 stdcall SysReAllocString(ptr wstr) SysReAllocString 4 stdcall SysAllocStringLen(wstr long) SysAllocStringLen -5 stdcall SysReAllocStringLen(ptr ptr long) SysReAllocStringLen +5 stdcall SysReAllocStringLen(ptr wstr long) SysReAllocStringLen 6 stdcall SysFreeString(wstr) SysFreeString 7 stdcall SysStringLen(wstr) SysStringLen 8 stdcall VariantInit(ptr) VariantInit @@ -145,8 +145,8 @@ 146 stdcall DispCallFunc(ptr long long long long ptr ptr ptr) DispCallFunc 147 stdcall VariantChangeTypeEx(ptr ptr long long long) VariantChangeTypeEx 148 stdcall SafeArrayPtrOfIndex(ptr ptr ptr) SafeArrayPtrOfIndex -149 stdcall SysStringByteLen(ptr) SysStringByteLen -150 stdcall SysAllocStringByteLen(ptr long) SysAllocStringByteLen +149 stdcall SysStringByteLen(wstr) SysStringByteLen +150 stdcall SysAllocStringByteLen(wstr long) SysAllocStringByteLen 152 stub VarEqv # stdcall (ptr ptr ptr) 153 stub VarIdiv # stdcall (ptr ptr ptr) 154 stub VarImp # stdcall (ptr ptr ptr) Index: olepicture.c =================================================================== RCS file: /home/wine/wine/dlls/oleaut32/olepicture.c,v retrieving revision 1.20 diff -u -r1.20 olepicture.c --- olepicture.c 11 Nov 2002 19:54:22 -0000 1.20 +++ olepicture.c 24 Dec 2002 13:35:53 -0000 @@ -997,6 +997,8 @@ } else { This->desc.picType = PICTYPE_ICON; This->desc.u.icon.hicon = hicon; + This->himetricWidth = cifd->idEntries[i].bWidth; + This->himetricHeight = cifd->idEntries[i].bHeight; hr = S_OK; } break; Index: typelib.c =================================================================== RCS file: /home/wine/wine/dlls/oleaut32/typelib.c,v retrieving revision 1.84 diff -u -r1.84 typelib.c --- typelib.c 12 Dec 2002 22:59:25 -0000 1.84 +++ typelib.c 24 Dec 2002 13:36:56 -0000 @@ -4113,7 +4108,7 @@ argsize += _argsize(prgvt[i]); } args = (DWORD*)HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*argsize); - args[0]=0; /* this is the fake IDispatch interface pointer */ + args[0] = pvInstance; /* this is the fake IDispatch interface pointer */ argspos = 1; for (i=0;i<cActuals;i++) { int arglen; Index: variant.c =================================================================== RCS file: /home/wine/wine/dlls/oleaut32/variant.c,v retrieving revision 1.50 diff -u -r1.50 variant.c --- variant.c 23 Dec 2002 02:03:10 -0000 1.50 +++ variant.c 24 Dec 2002 13:37:28 -0000 @@ -1919,64 +1920,61 @@ */ if( pvargDest != pvargSrc && res == S_OK ) { - res = VariantClear( pvargDest ); + VariantClear( pvargDest ); /* result is not checked */ - if( res == S_OK ) + if( V_VT(pvargSrc) & VT_BYREF ) + { + /* In the case of byreference we only need + * to copy the pointer. + */ + pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3; + V_VT(pvargDest) = V_VT(pvargSrc); + } + else { - if( V_VT(pvargSrc) & VT_BYREF ) + /* + * The VT_ARRAY flag is another way to designate a safe array. + */ + if (V_VT(pvargSrc) & VT_ARRAY) { - /* In the case of byreference we only need - * to copy the pointer. - */ - pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3; - V_VT(pvargDest) = V_VT(pvargSrc); + SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray)); } else { - /* - * The VT_ARRAY flag is another way to designate a safe array. + /* In the case of by value we need to + * copy the actual value. In the case of + * VT_BSTR a copy of the string is made, + * if VT_DISPATCH or VT_IUNKNOWN AddRef is + * called to increment the object's reference count. */ - if (V_VT(pvargSrc) & VT_ARRAY) - { - SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray)); - } - else + switch( V_VT(pvargSrc) & VT_TYPEMASK ) { - /* In the case of by value we need to - * copy the actual value. In the case of - * VT_BSTR a copy of the string is made, - * if VT_DISPATCH or VT_IUNKNOWN AddRef is - * called to increment the object's reference count. - */ - switch( V_VT(pvargSrc) & VT_TYPEMASK ) - { - case( VT_BSTR ): - V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( V_UNION(pvargSrc,bstrVal) ); - break; - case( VT_DISPATCH ): - V_UNION(pvargDest,pdispVal) = V_UNION(pvargSrc,pdispVal); - if (V_UNION(pvargDest,pdispVal)!=NULL) - ICOM_CALL(AddRef,V_UNION(pvargDest,pdispVal)); - break; - case( VT_VARIANT ): - VariantCopy(V_UNION(pvargDest,pvarVal),V_UNION(pvargSrc,pvarVal)); - break; - case( VT_UNKNOWN ): - V_UNION(pvargDest,punkVal) = V_UNION(pvargSrc,punkVal); - if (V_UNION(pvargDest,pdispVal)!=NULL) - ICOM_CALL(AddRef,V_UNION(pvargDest,punkVal)); - break; - case( VT_SAFEARRAY ): - SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray)); - break; - default: - pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3; - break; - } + case( VT_BSTR ): + V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( V_UNION(pvargSrc,bstrVal) ); + break; + case( VT_DISPATCH ): + V_UNION(pvargDest,pdispVal) = V_UNION(pvargSrc,pdispVal); + if (V_UNION(pvargDest,pdispVal)!=NULL) + ICOM_CALL(AddRef,V_UNION(pvargDest,pdispVal)); + break; + case( VT_VARIANT ): + VariantCopy(V_UNION(pvargDest,pvarVal),V_UNION(pvargSrc,pvarVal)); + break; + case( VT_UNKNOWN ): + V_UNION(pvargDest,punkVal) = V_UNION(pvargSrc,punkVal); + if (V_UNION(pvargDest,pdispVal)!=NULL) + ICOM_CALL(AddRef,V_UNION(pvargDest,punkVal)); + break; + case( VT_SAFEARRAY ): + SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray)); + break; + default: + pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3; + break; } - - V_VT(pvargDest) = V_VT(pvargSrc); } + V_VT(pvargDest) = V_VT(pvargSrc); + dump_Variant(pvargDest); } } @@ -2043,6 +2041,9 @@ V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( *(V_UNION(pvargSrc,pbstrVal)) ); break; case( VT_DISPATCH ): + V_UNION(pvargDest,pdispVal) = *V_UNION(pvargSrc,ppdispVal); + if (V_UNION(pvargDest,pdispVal)!=NULL) + ICOM_CALL(AddRef,V_UNION(pvargDest,pdispVal)); break; case( VT_VARIANT ): { @@ -2079,6 +2080,9 @@ } break; case( VT_UNKNOWN ): + V_UNION(pvargDest,punkVal) = *V_UNION(pvargSrc,ppunkVal); + if (V_UNION(pvargDest,pdispVal)!=NULL) + ICOM_CALL(AddRef,V_UNION(pvargDest,punkVal)); break; case( VT_SAFEARRAY ): SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray)); @@ -2118,53 +2122,37 @@ */ static HRESULT coerce_array( - VARIANTARG* src, SAFEARRAY **narr, LCID lcid, USHORT wFlags, VARTYPE vt + VARIANTARG* src, VARIANTARG *dst, LCID lcid, USHORT wFlags, VARTYPE vt ) { - int elems,i,j; - SAFEARRAY *darr, *sarr = V_ARRAY(src); - long *addr; + SAFEARRAY *sarr = V_ARRAY(src); HRESULT hres; + LPVOID data; - hres = SafeArrayAllocDescriptor( sarr->cDims, &darr); - if (FAILED(hres)) return hres; - memcpy( - darr->rgsabound, - sarr->rgsabound, - sizeof(sarr->rgsabound[0])*sarr->cDims - ); - hres = SafeArrayAllocData(darr); - if (FAILED(hres)) { - SafeArrayDestroyDescriptor(darr); - return hres; - } - elems = 1; - for (i=0;i<sarr->cDims;i++) - elems *= sarr->rgsabound[i].cElements; - addr = HeapAlloc(GetProcessHeap(),0,sizeof(long)*sarr->cDims); - for (i=0;i<elems;i++) { - VARIANT tmpvar,newvar; - int tmpi = i; - /* convert absolute value in array address */ - for (j=0;j<sarr->cDims;j++) { - addr[j] = (tmpi % sarr->rgsabound[j].cElements) + sarr->rgsabound[j].lLbound; - tmpi /= sarr->rgsabound[j].cElements; - } - V_VT(&tmpvar) = V_VT(src) & VT_TYPEMASK; - hres = SafeArrayGetElement(sarr, addr, &V_UNION(&tmpvar,lVal)); - if (FAILED(hres)) { - FIXME("Did not get element %d\n",i); + switch (vt) { + case VT_BSTR: + if (sarr->cDims != 1) { + FIXME("Can not coerce array with dim %d into BSTR\n", sarr->cDims); return E_FAIL; } - hres = Coerce( &newvar, lcid, wFlags, &tmpvar, vt ); - if (FAILED(hres)) return E_FAIL; - hres = SafeArrayPutElement( darr, addr, &V_UNION(&newvar,lVal)); - if (FAILED(hres)) { - FIXME("SAPE failed for element %d, %lx\n",i,hres); + switch (V_VT(src) & VT_TYPEMASK) { + case VT_UI1: + hres = SafeArrayAccessData(sarr, &data); + if (FAILED(hres)) return hres; + + /* Yes, just memcpied apparently. */ + V_BSTR(dst) = SysAllocStringByteLen(data, sarr->rgsabound[0].cElements); + hres = SafeArrayUnaccessData(sarr); + if (FAILED(hres)) return hres; + break; + default: + FIXME("Cannot coerce array of %d into BSTR yet. Please report!\n", V_VT(src) & VT_TYPEMASK); return E_FAIL; } + break; + default: + FIXME("Cannot coerce array into vt %d yet. Please report/implement!\n", vt); + return E_FAIL; } - HeapFree(GetProcessHeap(),0,addr); - *narr = darr; return S_OK; } @@ -2239,7 +2227,6 @@ */ VariantClear( &Variant ); } - } else { if (V_VT(pvargSrc) & VT_ARRAY) { if ((V_VT(pvargSrc) & 0xf000) != VT_ARRAY) { @@ -2247,7 +2234,7 @@ return E_FAIL; } V_VT(pvargDest) = VT_ARRAY | vt; - res = coerce_array(pvargSrc, &V_ARRAY(pvargDest), lcid, wFlags, vt); + res = coerce_array(pvargSrc, pvargDest, lcid, wFlags, vt); } else { if ((V_VT(pvargSrc) & 0xf000)) { FIXME("VT_TYPEMASK %x is unhandled in normal case.\n",V_VT(pvargSrc) & VT_TYPEMASK); @@ -5022,14 +5010,40 @@ V_VT(out) = VT_NULL; return S_OK; } - else if (V_VT(left) == VT_BSTR && V_VT(right) == VT_BSTR) + + if (V_VT(left) == VT_BSTR && V_VT(right) == VT_BSTR) { V_VT(out) = VT_BSTR; VarBstrCat (V_BSTR(left), V_BSTR(right), &V_BSTR(out)); return S_OK; } - else - FIXME ("types not supported\n"); + if (V_VT(left) == VT_BSTR) { + VARIANT bstrvar; + HRESULT hres; + + V_VT(out) = VT_BSTR; + hres = VariantChangeTypeEx(&bstrvar,right,0,0,VT_BSTR); + if (hres) { + FIXME("Failed to convert right side from vt %d to VT_BSTR?\n",V_VT(right)); + return hres; + } + VarBstrCat (V_BSTR(left), V_BSTR(&bstrvar), &V_BSTR(out)); + return S_OK; + } + if (V_VT(right) == VT_BSTR) { + VARIANT bstrvar; + HRESULT hres; + + V_VT(out) = VT_BSTR; + hres = VariantChangeTypeEx(&bstrvar,left,0,0,VT_BSTR); + if (hres) { + FIXME("Failed to convert right side from vt %d to VT_BSTR?\n",V_VT(right)); + return hres; + } + VarBstrCat (V_BSTR(&bstrvar), V_BSTR(right), &V_BSTR(out)); + return S_OK; + } + FIXME ("types %d / %d not supported\n",V_VT(left)&VT_TYPEMASK, V_VT(right)&VT_TYPEMASK); return S_OK; } Index: tests/safearray.c =================================================================== RCS file: /home/wine/wine/dlls/oleaut32/tests/safearray.c,v retrieving revision 1.1 diff -u -r1.1 safearray.c --- tests/safearray.c 23 Dec 2002 02:02:49 -0000 1.1 +++ tests/safearray.c 24 Dec 2002 13:37:30 -0000 @@ -37,7 +37,7 @@ #include "oleauto.h" #define VARTYPE_NOT_SUPPORTED 0 -static int vttypes[] = { +static UINT vttypes[] = { /* this is taken from wtypes.h. Only [S]es are supported by the SafeArray */ VARTYPE_NOT_SUPPORTED, /* VT_EMPTY [V] [P] nothing */ VARTYPE_NOT_SUPPORTED, /* VT_NULL [V] [P] SQL style Nul */ @@ -88,9 +88,11 @@ START_TEST(safearray) { SAFEARRAY *a; - int i; + unsigned int i; HRESULT hres; SAFEARRAYBOUND bound; + VARIANT v; + LPVOID data; hres = SafeArrayAllocDescriptor(0,&a); ok(E_INVALIDARG == hres,"SAAD(0) failed with hres %lx",hres); @@ -100,12 +102,12 @@ for (i=1;i<100;i++) { hres=SafeArrayAllocDescriptor(i,&a); - ok(S_OK == hres,"SAAD(%d) failed with %lx\n",i,hres); + ok(S_OK == hres,"SAAD(%d) failed with %lx",i,hres); - ok(a->cDims == i,"a->cDims not initialised?\n"); + ok(a->cDims == i,"a->cDims not initialised?"); hres=SafeArrayDestroyDescriptor(a); - ok(S_OK == hres,"SADD failed with %lx\n",hres); + ok(S_OK == hres,"SADD failed with %lx",hres); } hres=SafeArrayAllocDescriptor(65535,&a); @@ -124,13 +126,29 @@ bound.cElements = 1; bound.lLbound = 0; a = SafeArrayCreate(-1, 1, &bound); - ok(NULL == a,"SAC(-1,1,[1,0]) not failed?\n"); + ok(NULL == a,"SAC(-1,1,[1,0]) not failed?"); for (i=0;i<sizeof(vttypes)/sizeof(vttypes[0]);i++) { a = SafeArrayCreate(i, 1, &bound); ok( ((a == NULL) && (vttypes[i] == 0)) || ((a != NULL) && (vttypes[i] == a->cbElements)), - "SAC(%d,1,[1,0]), result %ld, expected %d\n",i,(a?a->cbElements:0),vttypes[i] + "SAC(%d,1,[1,0]), result %ld, expected %d",i,(a?a->cbElements:0),vttypes[i] ); } + + + /* Test conversion of type|VT_ARRAY <-> VT_BSTR */ + bound.lLbound = 0; + bound.cElements = 10; + a = SafeArrayCreate(VT_UI1, 1, &bound); + ok(a != NULL, "SAC failed."); + ok(S_OK == SafeArrayAccessData(a, &data),"SACD failed"); + memcpy(data,"Hello World",10); + ok(S_OK == SafeArrayUnaccessData(a),"SAUD failed"); + V_VT(&v) = VT_ARRAY|VT_UI1; + V_ARRAY(&v) = a; + hres = VariantChangeTypeEx(&v, &v, 0, 0, VT_BSTR); + ok(hres==S_OK, "CTE VT_ARRAY|VT_UI1 -> VT_BSTR failed with %lx",hres); + ok(V_VT(&v) == VT_BSTR,"CTE VT_ARRAY|VT_UI1 -> VT_BSTR did not return VT_BSTR, but %d.",V_VT(&v)); + ok(V_BSTR(&v)[0] == 0x6548,"First letter are not 'He', but %x", V_BSTR(&v)[0]); } Index: tests/vartest.c =================================================================== RCS file: /home/wine/wine/dlls/oleaut32/tests/vartest.c,v retrieving revision 1.5 diff -u -r1.5 vartest.c --- tests/vartest.c 24 Dec 2002 00:49:27 -0000 1.5 +++ tests/vartest.c 24 Dec 2002 13:37:41 -0000 @@ -2610,12 +2610,20 @@ sprintf(msg,"vt %d, return value %lx, expected was %lx",vartypes[i].ind,rc,vartypes[i].vcex1); ok(vartypes[i].vcex2 == rc, msg); - V_VT(&va) = 99; - d = 4.123; - V_UNION(&va,dblVal) = d; - ok(DISP_E_BADVARTYPE == VariantClear( &va ), "should give DISP_E_BADVARTYPE"); } #endif + + V_VT(&va) = 99; + d = 4.123; + V_UNION(&va,dblVal) = d; + ok(DISP_E_BADVARTYPE == VariantClear( &va ), "should give DISP_E_BADVARTYPE"); + + V_VT(&va) = VT_BOOL; + V_BOOL(&va) = VARIANT_TRUE; + V_BOOL(&vb) = 99; + + ok(S_OK == VariantCopy(&va, &vb),"VariantCopy to illegal variant did not return S_OK"); + VariantClear( &va ); VariantClear( &vb ); VariantClear( &vc );