I'm trying (again) to run a VB app on wine. But it never shows up. Instead I only see a dialog with this Type mismatch error and then it quits. I tried to find the place where it goes wrong. Apparently it tries to parse a number from a string in VB notation. 0009:trace:ole:VarParseNumFromStr (L"&H8000",1024,0x00000000,0x408bdee0,0x408bdae0)
I found that this string "&H8000" comes from my code and it's intentional. In VB you can convert a string to a long by using i=CLng(str). But if the string number is in hex format it needs to be VB hex notation. This works on Windows and fails on wine. I now need to find out how CLng(str) converts the string and why this is different on wine.
Contrary to my first tests these API functions understand VB hex numbers quite well. There is no problem with these calls on Win2K:
OLECHAR test[]={'&', 'H', 'F', '0', '8', 'F', '\0'}; VarI4FromStr(test, LANG_NEUTRAL, NUMPRS_STD, &out); VarParseNumFromStr(test, LANG_NEUTRAL, NUMPRS_STD, &np, rgb);
So I implemented this in wine too. If anybody has a program (mostly VB) that uses hex numbers in strings please try it out. Without any other remarks I'll send it to wine-patches.
bye Fabi
Index: wine/dlls/oleaut32/variant.c =================================================================== RCS file: /home/wine/wine/dlls/oleaut32/variant.c,v retrieving revision 1.88 diff -u -r1.88 variant.c --- wine/dlls/oleaut32/variant.c 25 Feb 2004 01:35:01 -0000 1.88 +++ wine/dlls/oleaut32/variant.c 25 Feb 2004 08:00:10 -0000 @@ -1468,6 +1468,7 @@ #define B_EXPONENT_START 0x4 #define B_INEXACT_ZEROS 0x8 #define B_LEADING_ZERO 0x10 +#define B_PROCESSING_HEX 0x20
/********************************************************************** * VarParseNumFromStr [OLEAUT32.46] @@ -1698,6 +1699,33 @@ dwState |= B_NEGATIVE_EXPONENT; cchUsed++; } + else if ((*lpszStr == '&' && *(lpszStr+1) == 'H') && + pNumprs->dwInFlags & NUMPRS_HEX_OCT && + !(pNumprs->dwOutFlags & NUMPRS_EXPONENT)) + { + dwState |= B_PROCESSING_HEX; + pNumprs->dwOutFlags |= NUMPRS_HEX_OCT; + cchUsed=cchUsed+2; + lpszStr++; + } + else if (((*lpszStr >= 'a' && *lpszStr <= 'f') || + (*lpszStr >= 'A' && *lpszStr <= 'F')) && + dwState & B_PROCESSING_HEX) + { + if (pNumprs->cDig >= iMaxDigits) + { + return DISP_E_OVERFLOW; + } + else + { + if (*lpszStr >= 'a') + rgbTmp[pNumprs->cDig] = *lpszStr - 'a' + 10; + else + rgbTmp[pNumprs->cDig] = *lpszStr - 'A' + 10; + } + pNumprs->cDig++; + cchUsed++; + } else break; /* Stop at an unrecognised character */
@@ -1728,14 +1756,20 @@ /* cDig of X and writes X+Y where Y>=0 number of digits to rgbDig */ memcpy(rgbDig, rgbTmp, pNumprs->cDig * sizeof(BYTE));
- while (pNumprs->cDig > 1 && !rgbTmp[pNumprs->cDig - 1]) - { - if (pNumprs->dwOutFlags & NUMPRS_DECIMAL) - pNumprs->nPwr10--; - else - pNumprs->nPwr10++; + if (dwState & B_PROCESSING_HEX) { + /* hex number have always the same format */ + pNumprs->nPwr10=0; + pNumprs->nBaseShift=4; + } else { + while (pNumprs->cDig > 1 && !rgbTmp[pNumprs->cDig - 1]) + { + if (pNumprs->dwOutFlags & NUMPRS_DECIMAL) + pNumprs->nPwr10--; + else + pNumprs->nPwr10++;
- pNumprs->cDig--; + pNumprs->cDig--; + } } } else { @@ -1870,7 +1904,110 @@ if (pNumprs->nBaseShift) { /* nBaseShift indicates a hex or octal number */ - FIXME("nBaseShift=%d not yet implemented, returning overflow\n", pNumprs->nBaseShift); + ULONG64 ul64 = 0; + LONG64 l64; + int i; + + /* Convert the hex or octal number string into a UI64 */ + for (i = 0; i < pNumprs->cDig; i++) + { + if (ul64 > ((UI8_MAX>>pNumprs->nBaseShift) - rgbDig[i])) + { + TRACE("Overflow multiplying digits\n"); + return DISP_E_OVERFLOW; + } + ul64 = (ul64<<pNumprs->nBaseShift) + rgbDig[i]; + } + + /* also make a negative representation */ + l64=-ul64; + + /* Try signed and unsigned types in size order */ + if (dwVtBits & VTBIT_I1 && ((ul64 <= I1_MAX)||(l64 >= I1_MIN))) + { + V_VT(pVarDst) = VT_I1; + if (ul64 <= I1_MAX) + V_I1(pVarDst) = ul64; + else + V_I1(pVarDst) = l64; + return S_OK; + } + else if (dwVtBits & VTBIT_UI1 && ul64 <= UI1_MAX) + { + V_VT(pVarDst) = VT_UI1; + V_UI1(pVarDst) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_I2 && ((ul64 <= I2_MAX)||(l64 >= I2_MIN))) + { + V_VT(pVarDst) = VT_I2; + if (ul64 <= I2_MAX) + V_I2(pVarDst) = ul64; + else + V_I2(pVarDst) = l64; + return S_OK; + } + else if (dwVtBits & VTBIT_UI2 && ul64 <= UI2_MAX) + { + V_VT(pVarDst) = VT_UI2; + V_UI2(pVarDst) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_I4 && ((ul64 <= I4_MAX)||(l64 >= I4_MIN))) + { + V_VT(pVarDst) = VT_I4; + if (ul64 <= I4_MAX) + V_I4(pVarDst) = ul64; + else + V_I4(pVarDst) = l64; + return S_OK; + } + else if (dwVtBits & VTBIT_UI4 && ul64 <= UI4_MAX) + { + V_VT(pVarDst) = VT_UI4; + V_UI4(pVarDst) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_I8 && ((ul64 <= I4_MAX)||(l64>=I4_MIN))) + { + V_VT(pVarDst) = VT_I8; + V_I8(pVarDst) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_UI8) + { + V_VT(pVarDst) = VT_UI8; + V_UI8(pVarDst) = ul64; + return S_OK; + } + else if ((dwVtBits & REAL_VTBITS) == VTBIT_DECIMAL) + { + V_VT(pVarDst) = VT_DECIMAL; + DEC_SIGNSCALE(&V_DECIMAL(pVarDst)) = SIGNSCALE(DECIMAL_POS,0); + DEC_HI32(&V_DECIMAL(pVarDst)) = 0; + DEC_LO64(&V_DECIMAL(pVarDst)) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_R4 && ((ul64 <= I4_MAX)||(l64 >= I4_MIN))) + { + V_VT(pVarDst) = VT_R4; + if (ul64 <= I4_MAX) + V_R4(pVarDst) = ul64; + else + V_R4(pVarDst) = l64; + return S_OK; + } + else if (dwVtBits & VTBIT_R8 && ((ul64 <= I4_MAX)||(l64 >= I4_MIN))) + { + V_VT(pVarDst) = VT_R8; + if (ul64 <= I4_MAX) + V_R8(pVarDst) = ul64; + else + V_R8(pVarDst) = l64; + return S_OK; + } + + TRACE("Overflow: possible return types: 0x%lx, value: %s\n", dwVtBits, wine_dbgstr_longlong(ul64)); return DISP_E_OVERFLOW; }
Index: wine/dlls/oleaut32/tests/vartest.c =================================================================== RCS file: /home/wine/wine/dlls/oleaut32/tests/vartest.c,v retrieving revision 1.23 diff -u -r1.23 vartest.c --- wine/dlls/oleaut32/tests/vartest.c 6 Feb 2004 05:23:48 -0000 1.23 +++ wine/dlls/oleaut32/tests/vartest.c 25 Feb 2004 08:00:13 -0000 @@ -789,6 +789,15 @@ EXPECTRGB(2,0); EXPECTRGB(3,FAILDIG);
+ /* VB hex */ + CONVERT("&HF800", NUMPRS_HEX_OCT); + EXPECT(4,NUMPRS_HEX_OCT,0x40,6,4,0); + EXPECTRGB(0,15); + EXPECTRGB(1,8); + EXPECTRGB(2,0); + EXPECTRGB(3,0); + EXPECTRGB(4,FAILDIG); + /** NUMPRS_PARENS **/
/* Empty parens = error */