Problem with Access-mdb/DAO

Fabian Cenedese Cenedese at indel.ch
Wed Dec 17 03:16:01 CST 2003


>> >that got truncated. So I would change it to:
>> >
>> >    return (int)((*bufferPointer+1)/sizeof(WCHAR));
>> >
>> >Can anybody comment on this? Is this the right fix?
>> 
>> Actually MSDN says about SysStringLen:
>> 
>> Return Value: The number of characters in bstr
>> Comments: For a BSTR allocated with Sys[Re]AllocStringLen or SysAllocStringByteLen, this function always returns the number of characters specified in the cch parameter at allocation time
>> 
>> So this code looks strange. Either it should return *bufferPointer if
>> not zero or then a real calculation _fstrlen(str)/sizeof(WCHAR).
>> Or is MSDN wrong in this case?
>
>Since SysAllocStringLen computes the amount of bytes needed for a given
>length of WCHAR characters, the DWORD before the string probably always should
>indicate twice as much as the string length for a WCHAR string.
>(I guess the DWORD before the string is to be seen strictly internal, right?)
>If you have a string like "Nodes", then the BSTR DWORD value should be
>5*sizeof(WCHAR) == 5*2 == 10, *NOT* 5.
>
>In other words, we don't have an even/odd division problem, but rather a
>problem with the string length, since it should have been twice as much.
>
>Please try to find out which function created that BSTR with this wrong
>length calculation and try to fix it.

Actually that's a normal WINAPI function called SysAllocStringByteLen.
It's used in the DAO stuff from MFC. A COleVariant is created with
explicit type VT_BSTRT. This happens in the constructor:

COleVariant::COleVariant(LPCTSTR lpszSrc, VARTYPE vtSrc)
{
        USES_CONVERSION;
        ASSERT(vtSrc == VT_BSTR || vtSrc == VT_BSTRT);
        UNUSED(vtSrc);

        vt = VT_BSTR;
        bstrVal = NULL;

        if (lpszSrc != NULL)
        {
#ifndef _UNICODE
                if (vtSrc == VT_BSTRT)
                {
                        int nLen = lstrlen(lpszSrc);
                        bstrVal = ::SysAllocStringByteLen(lpszSrc, nLen);
                }
                else
#endif
                {
                        bstrVal = ::SysAllocString(T2COLE(lpszSrc));
                }

                if (bstrVal == NULL)
                        AfxThrowMemoryException();
        }
}

So not every BSTR is really a wide char string. That's why MSDN says
that SysStringLen has to give back the allocated length if the BSTR
was created with SysAllocStringByteLen.

I made a short test program:

COleVariant v1;
VariantInit(&v1);
v1=COleVariant("Nodes", VT_BSTRT);
cout << SysStringLen(v1.bstrVal) << " " << (char*)v1.bstrVal << endl;

Output on Windows:
2 Nodes

Output on wine:
2 Node

(And you're right, the SysStringLen is ok, reports also 2 on Windows).

The SysAllocStringByteLen is ok, but the variant assignment is done
with VariantCopy which is definitely wrong. The source string is still
ok but the dest string is only "Node". But this function is above my
knowledge. I don't know if the allocation/copy is wrong or if it needs
a new case for these special non-WCHAR BSTRs.

(Another interesting test: What happens with one-char-strings...?)

bye  Fabi





More information about the wine-devel mailing list