Sync to Wine-0_9_1:

Huw Davies <huw@codeweavers.com>
- Treat paramflags == 0 like PARAMFLAG_FIN.
- Don't call Release on a null ptr.
- Deal with pExcepInfo == NULL.
Robert Shearman <rob@codeweavers.com>
- Add IFontEventsDisp and IProvideMultipleClassInfo.
- Make sure to clean up properly on error.
- Restrict the critical section to getting the channel buffer and
  adding a reference to it.
- There is no need to call IUnknown_QueryInterface since getting the
  correct object is handled by the proxy manager.
- Forward IDispatch functions to the MIDL-generated proxy.
- Remove special cases caused by previous marshaling of IDispatch &
  IUnknown that is no longer done.
- Add error messages if an IUnknown or IDispatch method is called when
  it no longer should be.
- Cleanup formating of DispCallFunc.
- Fix DispCallFunc for functions with return values.
- Don't rely on _copy_arg as it is going away soon.
- Make wParamFlags in the paramdesc dumping function human readable.
- Enums should be VT_I4 instead of VT_INT.
- Trace the return value from the ITypeInfo_fnInvoke.
- Read DLL name from modules in MSFT typelibs.
- A name offset of -1 for a parameter means that it has the same name
  as the function.
- Print an error if a ReadName is attempted with an offset of -1,
  since this will read garbage.
- Implement ITypeInfo_GetDllEntry.
- Fix a crash during +variant logging caused by a typo causing an array
  to be one element less than expected.
- The PSDispatch PS class factory can manage both typelib marshalled and
  IDispatch, which is NDR marshalled, so we need a wrapper to call the
  appropriate CreateProxy or CreateStub function.
Alex Villacís Lasso <a_villacis@palosanto.com>
- Implement complete VarDecDiv() for any valid DECIMAL.
- Implement complete VarDecMul() for any valid DECIMAL.
- Implement complete VarBstrFromDec() for any valid DECIMAL, with
  internationalization support borrowed from VARIANT_BstrFromReal(). The
  decimal fix for VARIANT_BstrFromReal was encapsulated in a separate
  function and reused.
Michael Stefaniuc <mstefani@redhat.de>
- Handle VT_DECIMAL in VarCmp().
- Handle VT_CY in VarDiv().
Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
- Extend VarCmp() and add test cases.
Marcus Meissner <marcus@jet.franken.de>
- Added support of loading of IPicture data from non-statable
  IStreams. Added testcases for this.
- Added support for VT_I8/VT_UI8 marshalling.
- Fixed FMT_DATE_GENERAL and FMT_DATE_TIME_SYS cases in
  VARIANT_FormatDate.

svn path=/trunk/; revision=19313
This commit is contained in:
Gé van Geldorp 2005-11-17 21:52:13 +00:00
parent 7373027088
commit 6b37e95bd4
14 changed files with 1294 additions and 897 deletions

View file

@ -5,6 +5,7 @@
DEFINE_GUID(IID_IFont, 0xbef6e002, 0xa874, 0x101a, 0x8b,0xba, 0x00,0xaa,0x00,0x30,0x0c,0xab);
DEFINE_GUID(IID_IFontDisp, 0xbef6e003, 0xa874, 0x101a, 0x8b,0xba, 0x00,0xaa,0x00,0x30,0x0c,0xab);
DEFINE_GUID(IID_IFontEventsDisp, 0x4ef6100a, 0xaf88, 0x11d0, 0x98,0x46, 0x00,0xc0,0x4f,0xc2,0x99,0x93);
DEFINE_GUID(IID_IPicture, 0x7bf80980, 0xbf32, 0x101a, 0x8b,0xbb, 0x00,0xaa,0x00,0x30,0x0c,0xab);
DEFINE_GUID(IID_IPictureDisp, 0x7bf80981, 0xbf32, 0x101a, 0x8b,0xbb, 0x00,0xaa,0x00,0x30,0x0c,0xab);
DEFINE_GUID(IID_IOleControl, 0xb196b288, 0xbab4, 0x101a, 0xb6,0x9c, 0x00,0xaa,0x00,0x34,0x1d,0x07);
@ -16,6 +17,7 @@ DEFINE_GUID(IID_IClassFactory2, 0xb196b28f, 0xbab4, 0x101a, 0xb6,0x9c, 0x00,0xaa
DEFINE_GUID(IID_IViewObjectEx, 0x3af24292, 0x0c96, 0x11ce, 0xa0,0xcf, 0x00,0xaa,0x00,0x60,0x0a,0xb8);
DEFINE_GUID(IID_IProvideClassInfo, 0xb196b283, 0xbab4, 0x101a, 0xb6,0x9c, 0x00,0xaa,0x00,0x34,0x1d,0x07);
DEFINE_GUID(IID_IProvideClassInfo2, 0xa6bc3ac0, 0xdbaa, 0x11ce, 0x9d,0xe3, 0x00,0xaa,0x00,0x4b,0xb8,0x51);
DEFINE_GUID(IID_IProvideMultipleClassInfo, 0xa7aba9c1, 0x8983, 0x11cf, 0x8f,0x20, 0x00,0x80,0x5f,0x2c,0xd0,0x64);
DEFINE_GUID(IID_IConnectionPoint, 0xb196b286, 0xbab4, 0x101a, 0xb6,0x9c, 0x00,0xaa,0x00,0x34,0x1d,0x07);
DEFINE_GUID(IID_IConnectionPointContainer, 0xb196b284, 0xbab4, 0x101a, 0xb6,0x9c, 0x00,0xaa,0x00,0x34,0x1d,0x07);
DEFINE_GUID(IID_IEnumConnections, 0xb196b287, 0xbab4, 0x101a, 0xb6,0x9c, 0x00,0xaa,0x00,0x34,0x1d,0x07);

View file

@ -699,6 +699,76 @@ extern HRESULT OLEAUTPS_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *
extern void _get_STDFONT_CF(LPVOID);
extern void _get_STDPIC_CF(LPVOID);
static HRESULT WINAPI PSDispatchFacBuf_QueryInterface(IPSFactoryBuffer *iface, REFIID riid, void **ppv)
{
if (IsEqualIID(riid, &IID_IUnknown) ||
IsEqualIID(riid, &IID_IPSFactoryBuffer))
{
IUnknown_AddRef(iface);
*ppv = (void *)iface;
return S_OK;
}
return E_NOINTERFACE;
}
static ULONG WINAPI PSDispatchFacBuf_AddRef(IPSFactoryBuffer *iface)
{
return 2;
}
static ULONG WINAPI PSDispatchFacBuf_Release(IPSFactoryBuffer *iface)
{
return 1;
}
static HRESULT WINAPI PSDispatchFacBuf_CreateProxy(IPSFactoryBuffer *iface, IUnknown *pUnkOuter, REFIID riid, IRpcProxyBuffer **ppProxy, void **ppv)
{
IPSFactoryBuffer *pPSFB;
HRESULT hr;
if (IsEqualIID(riid, &IID_IDispatch))
hr = OLEAUTPS_DllGetClassObject(&CLSID_PSDispatch, &IID_IPSFactoryBuffer, (void **)&pPSFB);
else
hr = TMARSHAL_DllGetClassObject(&CLSID_PSOAInterface, &IID_IPSFactoryBuffer, (void **)&pPSFB);
if (FAILED(hr)) return hr;
hr = IPSFactoryBuffer_CreateProxy(pPSFB, pUnkOuter, riid, ppProxy, ppv);
IPSFactoryBuffer_Release(pPSFB);
return hr;
}
static HRESULT WINAPI PSDispatchFacBuf_CreateStub(IPSFactoryBuffer *iface, REFIID riid, IUnknown *pUnkOuter, IRpcStubBuffer **ppStub)
{
IPSFactoryBuffer *pPSFB;
HRESULT hr;
if (IsEqualIID(riid, &IID_IDispatch))
hr = OLEAUTPS_DllGetClassObject(&CLSID_PSDispatch, &IID_IPSFactoryBuffer, (void **)&pPSFB);
else
hr = TMARSHAL_DllGetClassObject(&CLSID_PSOAInterface, &IID_IPSFactoryBuffer, (void **)&pPSFB);
if (FAILED(hr)) return hr;
hr = IPSFactoryBuffer_CreateStub(pPSFB, riid, pUnkOuter, ppStub);
IPSFactoryBuffer_Release(pPSFB);
return hr;
}
static const IPSFactoryBufferVtbl PSDispatchFacBuf_Vtbl =
{
PSDispatchFacBuf_QueryInterface,
PSDispatchFacBuf_AddRef,
PSDispatchFacBuf_Release,
PSDispatchFacBuf_CreateProxy,
PSDispatchFacBuf_CreateStub
};
/* This is the whole PSFactoryBuffer object, just the vtableptr */
static const IPSFactoryBufferVtbl *pPSDispatchFacBuf = &PSDispatchFacBuf_Vtbl;
/***********************************************************************
* DllGetClassObject (OLEAUT32.@)
*/
@ -719,12 +789,16 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
return S_OK;
}
}
if (IsEqualCLSID(rclsid, &CLSID_PSDispatch) ||
IsEqualCLSID(rclsid, &CLSID_PSTypeInfo) ||
if (IsEqualCLSID(rclsid, &CLSID_PSTypeInfo) ||
IsEqualCLSID(rclsid, &CLSID_PSTypeLib) ||
IsEqualCLSID(rclsid, &CLSID_PSEnumVariant)) {
return OLEAUTPS_DllGetClassObject(&CLSID_PSDispatch, iid, ppv);
}
if (IsEqualCLSID(rclsid, &CLSID_PSDispatch) && IsEqualIID(iid, &IID_IPSFactoryBuffer)) {
*ppv = &pPSDispatchFacBuf;
IPSFactoryBuffer_AddRef((IPSFactoryBuffer *)*ppv);
return S_OK;
}
if (IsEqualGUID(rclsid,&CLSID_PSOAInterface)) {
if (S_OK==TMARSHAL_DllGetClassObject(rclsid,iid,ppv))
return S_OK;

View file

@ -34,6 +34,7 @@
#include "oleaut32_Hu.rc"
#include "oleaut32_It.rc"
#include "oleaut32_Ja.rc"
#include "oleaut32_Ko.rc"
#include "oleaut32_Nl.rc"
#include "oleaut32_No.rc"
#include "oleaut32_Pl.rc"

View file

@ -0,0 +1,31 @@
/*
* Korean resources for oleaut32
*
*
*Copyright 2005 YunSong Hwang(hys545@dreamwiz.com)
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT
STRINGTABLE DISCARDABLE
{
IDS_TRUE "진실"
IDS_FALSE "거짓"
IDS_YES "예"
IDS_NO "아니오"
IDS_ON "작동"
IDS_OFF "비작동"
}

View file

@ -1056,6 +1056,7 @@ static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
HRESULT hr = E_FAIL;
BOOL headerisdata = FALSE;
BOOL statfailed = FALSE;
ULONG xread, toread;
BYTE *xbuf;
DWORD header[2];
@ -1065,19 +1066,29 @@ static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
TRACE("(%p,%p)\n",This,pStm);
/****************************************************************************************
* Part 1: Load the data
*/
/* Sometimes we have a header, sometimes we don't. Apply some guesses to find
* out whether we do.
*
* UPDATE: the IStream can be mapped to a plain file instead of a stream in a
* compound file. This may explain most, if not all, of the cases of "no header",
* and the header validation should take this into account. At least in Visual Basic 6,
* resource streams, valid headers are
* compound file. This may explain most, if not all, of the cases of "no
* header", and the header validation should take this into account.
* At least in Visual Basic 6, resource streams, valid headers are
* header[0] == "lt\0\0",
* header[1] == length_of_stream.
*
* Also handle streams where we do not have a working "Stat" method by
* reading all data until the end of the stream.
*/
hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
if (hr)
FIXME("Stat failed with hres %lx\n",hr);
if (hr) {
TRACE("stat failed with hres %lx, proceeding to read all data.\n",hr);
statfailed = TRUE;
/* we will read at least 8 byte ... just right below */
statstg.cbSize.QuadPart = 8;
}
hr=IStream_Read(pStm,header,8,&xread);
if (hr || xread!=8) {
FIXME("Failure while reading picture header (hr is %lx, nread is %ld).\n",hr,xread);
@ -1089,42 +1100,77 @@ static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
if (!memcmp(&(header[0]),"lt\0\0", 4) && (header[1] <= statstg.cbSize.QuadPart-8)) {
toread = header[1];
} else {
if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
!memcmp(&(header[0]), "BM", 2) || /* BMP header */
!memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
(header[1] > statstg.cbSize.QuadPart) || /* invalid size */
(header[1]==0)
if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
!memcmp(&(header[0]), "BM", 2) || /* BMP header */
!memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
(header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
(header[1]==0)
) {/* Incorrect header, assume none. */
headerisdata = TRUE;
toread = statstg.cbSize.QuadPart-8;
xread = 8;
xread = 8;
} else {
FIXME("Unknown stream header magic: %08lx\n", header[0]);
FIXME("Unknown stream header magic: %08lx\n", header[0]);
toread = header[1];
}
}
This->datalen = toread+(headerisdata?8:0);
xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
if (statfailed) { /* we don't know the size ... read all we get */
int sizeinc = 4096;
int origsize = sizeinc;
ULONG nread = 42;
if (headerisdata)
memcpy (xbuf, &header, 8);
TRACE("Reading all data from stream.\n");
xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
if (headerisdata)
memcpy (xbuf, &header, 8);
while (1) {
while (xread < origsize) {
hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
xread+=nread;
if (hr || !nread)
break;
}
if (!nread || hr) /* done, or error */
break;
if (xread == origsize) {
origsize += sizeinc;
sizeinc = 2*sizeinc; /* exponential increase */
xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
}
}
if (hr)
TRACE("hr in no-stat loader case is %08lx\n", hr);
TRACE("loaded %ld bytes.\n", xread);
This->datalen = xread;
This->data = xbuf;
} else {
This->datalen = toread+(headerisdata?8:0);
xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
while (xread < This->datalen) {
ULONG nread;
hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
xread+=nread;
if (hr || !nread)
break;
if (headerisdata)
memcpy (xbuf, &header, 8);
while (xread < This->datalen) {
ULONG nread;
hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
xread+=nread;
if (hr || !nread)
break;
}
if (xread != This->datalen)
FIXME("Could only read %ld of %d bytes out of stream?\n",xread,This->datalen);
}
if (xread != This->datalen)
FIXME("Could only read %ld of %d bytes out of stream?\n",xread,This->datalen);
if (This->datalen == 0) { /* Marks the "NONE" picture */
if (This->datalen == 0) { /* Marks the "NONE" picture */
This->desc.picType = PICTYPE_NONE;
return S_OK;
}
/****************************************************************************************
* Part 2: Process the loaded data
*/
magic = xbuf[0] + (xbuf[1]<<8);
switch (magic) {
case 0x4947: { /* GIF */

View file

@ -544,15 +544,6 @@ static struct regsvr_coclass const coclass_list[] = {
/***********************************************************************
* interface list
*/
/* FIXME: these interfaces should be defined in ocidl.idl */
static IID const IID_IFontEventsDisp = {
0x4EF6100A, 0xAF88, 0x11D0, {0x98,0x46,0x00,0xC0,0x4F,0xC2,0x99,0x93} };
static IID const IID_IProvideMultipleClassInfo = {
0xA7ABA9C1, 0x8983, 0x11CF, {0x8F,0x20,0x00,0x80,0x5F,0x2C,0xD0,0x64} };
static struct regsvr_interface const interface_list[] = {
{ &IID_IDispatch,
"IDispatch",

File diff suppressed because it is too large Load diff

View file

@ -5,6 +5,7 @@
* 1999 Rein Klazes
* 2000 Francois Jacques
* 2001 Huw D M Davies for CodeWeavers
* 2005 Robert Shearman, for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -979,6 +980,7 @@ typedef struct tagITypeInfoImpl
*/
BSTR Name;
BSTR DocString;
BSTR DllName;
unsigned long dwHelpContext;
unsigned long dwHelpStringContext;
@ -1072,10 +1074,19 @@ static void dump_TypeDesc(TYPEDESC *pTD,char *szVarType) {
static void dump_ELEMDESC(ELEMDESC *edesc) {
char buf[200];
USHORT flags = edesc->u.paramdesc.wParamFlags;
dump_TypeDesc(&edesc->tdesc,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);
MESSAGE("\t\tu.paramdesc.wParamFlags");
if (!flags) MESSAGE(" PARAMFLAGS_NONE");
if (flags & PARAMFLAG_FIN) MESSAGE(" PARAMFLAG_FIN");
if (flags & PARAMFLAG_FOUT) MESSAGE(" PARAMFLAG_FOUT");
if (flags & PARAMFLAG_FLCID) MESSAGE(" PARAMFLAG_FLCID");
if (flags & PARAMFLAG_FRETVAL) MESSAGE(" PARAMFLAG_FRETVAL");
if (flags & PARAMFLAG_FOPT) MESSAGE(" PARAMFLAG_FOPT");
if (flags & PARAMFLAG_FHASDEFAULT) MESSAGE(" PARAMFLAG_FHASDEFAULT");
if (flags & PARAMFLAG_FHASCUSTDATA) MESSAGE(" PARAMFLAG_FHASCUSTDATA");
MESSAGE("\n\t\tu.paramdesc.lpex %p\n",edesc->u.paramdesc.pparamdescex);
}
static void dump_FUNCDESC(FUNCDESC *funcdesc) {
int i;
@ -1275,6 +1286,7 @@ static void dump_TypeInfo(ITypeInfoImpl * pty)
pty->TypeAttr.cFuncs, pty->TypeAttr.cVars, pty->TypeAttr.cImplTypes);
TRACE("parent tlb:%p index in TLB:%u\n",pty->pTypeLib, pty->index);
TRACE("%s %s\n", debugstr_w(pty->Name), debugstr_w(pty->DocString));
if (pty->TypeAttr.typekind == TKIND_MODULE) TRACE("dllname:%s\n", debugstr_w(pty->DllName));
dump_TLBFuncDesc(pty->funclist);
dump_TLBVarDesc(pty->varlist);
dump_TLBImplType(pty->impltypelist);
@ -1437,6 +1449,11 @@ static BSTR MSFT_ReadName( TLBContext *pcx, int offset)
WCHAR* pwstring = NULL;
BSTR bstrName = NULL;
if (offset < 0)
{
ERR_(typelib)("bad offset %d\n", offset);
return NULL;
}
MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
pcx->pTblDir->pNametab.offset+offset);
niName.namelen &= 0xFF; /* FIXME: correct ? */
@ -1765,7 +1782,16 @@ MSFT_DoFuncs(TLBContext* pcx,
(*pptfd)->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags = paraminfo.Flags;
(*pptfd)->pParamDesc[j].Name = (void *) paraminfo.oName;
/* name */
if (paraminfo.oName == -1)
/* this occurs for [propput] or [propget] methods, so
* we should just set the name of the parameter to the
* name of the method. */
(*pptfd)->pParamDesc[j].Name = SysAllocString((*pptfd)->Name);
else
(*pptfd)->pParamDesc[j].Name =
MSFT_ReadName( pcx, paraminfo.oName );
TRACE_(typelib)("param[%d] = %s\n", j, debugstr_w((*pptfd)->pParamDesc[j].Name));
/* SEEK value = jump to offset,
* from there jump to the end of record,
@ -1844,10 +1870,6 @@ MSFT_DoFuncs(TLBContext* pcx,
/* second time around */
for(j=0;j<pFuncRec->nrargs;j++)
{
/* name */
(*pptfd)->pParamDesc[j].Name =
MSFT_ReadName( pcx, (int)(*pptfd)->pParamDesc[j].Name );
/* default value */
if ( (PARAMFLAG_FHASDEFAULT &
(*pptfd)->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags) &&
@ -2029,6 +2051,7 @@ static ITypeInfoImpl * MSFT_DoTypeInfo(
ptiRet = (ITypeInfoImpl*) ITypeInfo_Constructor();
MSFT_ReadLEDWords(&tiBase, sizeof(tiBase) ,pcx ,
pcx->pTblDir->pTypeInfoTab.offset+count*sizeof(tiBase));
/* this is where we are coming from */
ptiRet->pTypeLib = pLibInfo;
ptiRet->index=count;
@ -2064,6 +2087,10 @@ static ITypeInfoImpl * MSFT_DoTypeInfo(
ptiRet->DocString=MSFT_ReadString(pcx, tiBase.docstringoffs);
ptiRet->dwHelpStringContext=tiBase.helpstringcontext;
ptiRet->dwHelpContext=tiBase.helpcontext;
if (ptiRet->TypeAttr.typekind == TKIND_MODULE)
ptiRet->DllName = MSFT_ReadString(pcx, tiBase.datatype1);
/* note: InfoType's Help file and HelpStringDll come from the containing
* library. Further HelpString and Docstring appear to be the same thing :(
*/
@ -3522,7 +3549,7 @@ static HRESULT WINAPI ITypeLib2_fnGetTypeInfo(
ITypeLibImpl *This = (ITypeLibImpl *)iface;
ITypeInfoImpl *pTypeInfo = This->pTypeInfo;
TRACE("(%p)->(index=%d) \n", This, index);
TRACE("(%p)->(index=%d)\n", This, index);
if (!ppTInfo) return E_INVALIDARG;
@ -3558,7 +3585,7 @@ static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType(
int i;
ITypeInfoImpl *pTInfo = This->pTypeInfo;
TRACE("(%p) index %d \n",This, index);
TRACE("(%p) index %d\n", This, index);
if(!pTKind) return E_INVALIDARG;
@ -3992,7 +4019,7 @@ static HRESULT WINAPI ITypeLib2_fnGetAllCustData(
VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
}
}else{
ERR(" OUT OF MEMORY! \n");
ERR(" OUT OF MEMORY!\n");
return E_OUTOFMEMORY;
}
return S_OK;
@ -4160,6 +4187,12 @@ static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface)
This->DocString = 0;
}
if (This->DllName)
{
SysFreeString(This->DllName);
This->DllName = 0;
}
if (This->next)
{
ITypeInfo_Release((ITypeInfo*)This->next);
@ -4731,7 +4764,7 @@ static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, TYPEDESC *tdesc, VARTY
switch (tattr->typekind)
{
case TKIND_ENUM:
*vt |= VT_INT;
*vt |= VT_I4;
break;
case TKIND_ALIAS:
@ -4829,46 +4862,47 @@ static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, TYPEDESC *tdesc, VARTYP
HRESULT WINAPI
DispCallFunc(
void* pvInstance, ULONG oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult
) {
VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult)
{
int i, argsize, argspos;
DWORD *args;
HRESULT hres;
TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult)
);
/* DispCallFunc is only used to invoke methods belonging to an IDispatch-derived COM interface.
So we need to add a first parameter to the list of arguments, to supply the interface pointer */
pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
pvargResult, V_VT(pvargResult));
/* DispCallFunc is only used to invoke methods belonging to an
* IDispatch-derived COM interface. So we need to add a first parameter
* to the list of arguments, to supply the interface pointer */
argsize = 1;
for (i=0;i<cActuals;i++) {
TRACE("arg %d: type %d, size %d\n",i,prgvt[i],_argsize(prgvt[i]));
dump_Variant(prgpvarg[i]);
argsize += _argsize(prgvt[i]);
for (i=0;i<cActuals;i++)
{
TRACE("arg %d: type %d, size %d\n",i,prgvt[i],_argsize(prgvt[i]));
dump_Variant(prgpvarg[i]);
argsize += _argsize(prgvt[i]);
}
args = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*argsize);
args[0] = (DWORD)pvInstance; /* this is the fake IDispatch interface pointer */
argspos = 1;
for (i=0;i<cActuals;i++) {
VARIANT *arg = prgpvarg[i];
TRACE("Storing arg %d (%d as %d)\n",i,V_VT(arg),prgvt[i]);
_copy_arg(NULL, NULL, &args[argspos], arg, prgvt[i]);
argspos += _argsize(prgvt[i]);
for (i=0;i<cActuals;i++)
{
VARIANT *arg = prgpvarg[i];
TRACE("Storing arg %d (%d as %d)\n",i,V_VT(arg),prgvt[i]);
memcpy(&args[argspos], &V_NONE(arg), _argsize(prgvt[i]) * sizeof(DWORD));
argspos += _argsize(prgvt[i]);
}
if(pvargResult!=NULL && V_VT(pvargResult)==VT_EMPTY)
hres = _invoke((*(FARPROC**)pvInstance)[oVft/sizeof(void *)],cc,argsize,args);
if (pvargResult && (vtReturn != VT_EMPTY))
{
_invoke((*(FARPROC**)pvInstance)[oVft/4],cc,argsize,args);
hres=S_OK;
}
else
{
FIXME("Do not know how to handle pvargResult %p. Expect crash ...\n",pvargResult);
hres = _invoke((*(FARPROC**)pvInstance)[oVft/4],cc,argsize,args);
FIXME("Method returned %lx\n",hres);
TRACE("Method returned 0x%08lx\n",hres);
V_VT(pvargResult) = vtReturn;
V_UI4(pvargResult) = hres;
}
HeapFree(GetProcessHeap(),0,args);
return hres;
return S_OK;
}
static HRESULT WINAPI ITypeInfo_fnInvoke(
@ -5031,7 +5065,10 @@ static HRESULT WINAPI ITypeInfo_fnInvoke(
* variants here too */
if ((V_VT(&varresult) == (VT_UNKNOWN | VT_BYREF)) ||
(V_VT(&varresult) == (VT_DISPATCH | VT_BYREF)))
IUnknown_Release(*V_UNKNOWNREF(&varresult));
{
if(*V_UNKNOWNREF(&varresult))
IUnknown_Release(*V_UNKNOWNREF(&varresult));
}
break;
}
}
@ -5072,6 +5109,7 @@ func_fail:
}
ITypeInfo2_ReleaseFuncDesc(iface, func_desc);
TRACE("-- 0x%08lx\n", hres);
return hres;
} else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
@ -5171,18 +5209,22 @@ static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid
ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
TLBFuncDesc *pFDesc;
FIXME("(%p, memid %lx, %d, %p, %p, %p), partial stub!\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
TRACE("(%p)->(memid %lx, %d, %p, %p, %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
if (pBstrDllName) *pBstrDllName = NULL;
if (pBstrName) *pBstrName = NULL;
if (pwOrdinal) *pwOrdinal = 0;
if (This->TypeAttr.typekind != TKIND_MODULE)
return TYPE_E_BADMODULEKIND;
for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
if(pFDesc->funcdesc.memid==memid){
dump_TypeInfo(This);
dump_TLBFuncDescOne(pFDesc);
/* FIXME: This is wrong, but how do you find that out? */
if (pBstrDllName) {
static const WCHAR oleaut32W[] = {'O','L','E','A','U','T','3','2','.','D','L','L',0};
*pBstrDllName = SysAllocString(oleaut32W);
}
if (pBstrDllName)
*pBstrDllName = SysAllocString(This->DllName);
if (HIWORD(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
if (pBstrName)
@ -5197,7 +5239,7 @@ static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid
*pwOrdinal = (DWORD)pFDesc->Entry;
return S_OK;
}
return E_FAIL;
return TYPE_E_ELEMENTNOTFOUND;
}
/* ITypeInfo::GetRefTypeInfo
@ -5728,7 +5770,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
}
}else{
ERR(" OUT OF MEMORY! \n");
ERR(" OUT OF MEMORY!\n");
return E_OUTOFMEMORY;
}
return S_OK;
@ -5764,7 +5806,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
& pCData->data);
}
}else{
ERR(" OUT OF MEMORY! \n");
ERR(" OUT OF MEMORY!\n");
return E_OUTOFMEMORY;
}
return S_OK;
@ -5801,7 +5843,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
& pCData->data);
}
}else{
ERR(" OUT OF MEMORY! \n");
ERR(" OUT OF MEMORY!\n");
return E_OUTOFMEMORY;
}
return S_OK;
@ -5837,7 +5879,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
& pCData->data);
}
}else{
ERR(" OUT OF MEMORY! \n");
ERR(" OUT OF MEMORY!\n");
return E_OUTOFMEMORY;
}
return S_OK;
@ -5875,7 +5917,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
& pCData->data);
}
}else{
ERR(" OUT OF MEMORY! \n");
ERR(" OUT OF MEMORY!\n");
return E_OUTOFMEMORY;
}
return S_OK;

View file

@ -152,6 +152,7 @@ typedef struct tagMSFT_TypeInfoBase {
/* or in base intefaces */
/* if coclass: offset in reftable */
/* if interface: reference to inherited if */
/* if module: offset to dllname in name table */
INT datatype2; /* if 0x8000, entry above is valid */
/* actually dunno */
/* else it is zero? */

View file

@ -537,6 +537,7 @@ HRESULT CALLBACK IDispatch_Invoke_Proxy(
VARIANTARG* rgVarRef = NULL;
UINT u, cVarRef;
UINT uArgErr;
EXCEPINFO ExcepInfo;
TRACE("(%p)->(%ld,%s,%lx,%x,%p,%p,%p,%p)\n", This,
dispIdMember, debugstr_guid(riid),
@ -546,6 +547,7 @@ HRESULT CALLBACK IDispatch_Invoke_Proxy(
/* [out] args can't be null, use dummy vars if needed */
if (!pVarResult) pVarResult = &VarResult;
if (!puArgErr) puArgErr = &uArgErr;
if (!pExcepInfo) pExcepInfo = &ExcepInfo;
/* count by-ref args */
for (cVarRef=0,u=0; u<pDispParams->cArgs; u++) {
@ -596,6 +598,13 @@ HRESULT CALLBACK IDispatch_Invoke_Proxy(
CoTaskMemFree(rgVarRef);
CoTaskMemFree(rgVarRefIdx);
}
if(pExcepInfo == &ExcepInfo)
{
SysFreeString(pExcepInfo->bstrSource);
SysFreeString(pExcepInfo->bstrDescription);
SysFreeString(pExcepInfo->bstrHelpFile);
}
return hr;
}

View file

@ -55,7 +55,7 @@ static const WCHAR szPercentZeroStar_d[] = { '%','0','*','d','\0' };
#if 0
#define dump_tokens(rgb) do { \
int i_; TRACE("Tokens->{ \n"); \
int i_; TRACE("Tokens->{\n"); \
for (i_ = 0; i_ < rgb[0]; i_++) \
TRACE("%s0x%02x", i_?",":"",rgb[i_]); \
TRACE(" }\n"); \
@ -1598,10 +1598,11 @@ static HRESULT VARIANT_FormatDate(LPVARIANT pVarIn, LPOLESTR lpszFormat,
case FMT_DATE_GENERAL:
{
BSTR date = NULL;
WCHAR *pDate = date;
hRes = VarBstrFromDate(V_DATE(&vDate), lcid, 0, pbstrOut);
WCHAR *pDate;
hRes = VarBstrFromDate(V_DATE(&vDate), lcid, 0, &date);
if (FAILED(hRes))
goto VARIANT_FormatDate_Exit;
pDate = date;
while (*pDate)
*pBuff++ = *pDate++;
SysFreeString(date);
@ -1623,10 +1624,11 @@ static HRESULT VARIANT_FormatDate(LPVARIANT pVarIn, LPOLESTR lpszFormat,
{
/* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */
BSTR date = NULL;
WCHAR *pDate = date;
hRes = VarBstrFromDate(V_DATE(&vDate), lcid, VAR_TIMEVALUEONLY, pbstrOut);
WCHAR *pDate;
hRes = VarBstrFromDate(V_DATE(&vDate), lcid, VAR_TIMEVALUEONLY, &date);
if (FAILED(hRes))
goto VARIANT_FormatDate_Exit;
pDate = date;
while (*pDate)
*pBuff++ = *pDate++;
SysFreeString(date);

View file

@ -43,13 +43,13 @@
WINE_DEFAULT_DEBUG_CHANNEL(variant);
const char* wine_vtypes[VT_CLSID] =
const char* wine_vtypes[VT_CLSID+1] =
{
"VT_EMPTY","VT_NULL","VT_I2","VT_I4","VT_R4","VT_R8","VT_CY","VT_DATE",
"VT_BSTR","VT_DISPATCH","VT_ERROR","VT_BOOL","VT_VARIANT","VT_UNKNOWN",
"VT_DECIMAL","15","VT_I1","VT_UI1","VT_UI2","VT_UI4","VT_I8","VT_UI8",
"VT_INT","VT_UINT","VT_VOID","VT_HRESULT","VT_PTR","VT_SAFEARRAY",
"VT_CARRAY","VT_USERDEFINED","VT_LPSTR","VT_LPWSTR""32","33","34","35",
"VT_CARRAY","VT_USERDEFINED","VT_LPSTR","VT_LPWSTR","32","33","34","35",
"VT_RECORD","VT_INT_PTR","VT_UINT_PTR","39","40","41","42","43","44","45",
"46","47","48","49","50","51","52","53","54","55","56","57","58","59","60",
"61","62","63","VT_FILETIME","VT_BLOB","VT_STREAM","VT_STORAGE",
@ -2512,11 +2512,14 @@ HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
{
BOOL lOk = TRUE;
BOOL rOk = TRUE;
BOOL l_isR = FALSE;
BOOL r_isR = FALSE;
LONGLONG lVal = -1;
LONGLONG rVal = -1;
VARIANT rv,lv;
DWORD xmask;
HRESULT rc;
double lDouble =0.0,rDouble=0.0;
TRACE("(%p->(%s%s),%p->(%s%s),0x%08lx,0x%08lx)\n", left, debugstr_VT(left),
debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), lcid, flags);
@ -2537,6 +2540,13 @@ HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
}
xmask = (1<<(V_VT(left)&VT_TYPEMASK))|(1<<(V_VT(right)&VT_TYPEMASK));
if (xmask & VTBIT_DECIMAL) {
rc = VariantChangeType(&lv,left,0,VT_DECIMAL);
if (FAILED(rc)) return rc;
rc = VariantChangeType(&rv,right,0,VT_DECIMAL);
if (FAILED(rc)) return rc;
return VarDecCmp(&V_DECIMAL(&lv), &V_DECIMAL(&rv));
}
if (xmask & VTBIT_R8) {
rc = VariantChangeType(&lv,left,0,VT_R8);
if (FAILED(rc)) return rc;
@ -2574,6 +2584,8 @@ HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
case VT_UINT : lVal = V_UI4(left); break;
case VT_BOOL : lVal = V_BOOL(left); break;
case VT_EMPTY : lVal = 0; break;
case VT_R4 : lDouble = V_R4(left); lOk = FALSE; l_isR= TRUE; break;
case VT_R8 : lDouble = V_R8(left); lOk = FALSE; l_isR= TRUE; break;
default: lOk = FALSE;
}
@ -2589,6 +2601,8 @@ HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
case VT_UINT : rVal = V_UI4(right); break;
case VT_BOOL : rVal = V_BOOL(right); break;
case VT_EMPTY : rVal = 0; break;
case VT_R4 : rDouble = V_R4(right); rOk = FALSE;r_isR= TRUE; break;
case VT_R8 : rDouble = V_R8(right); rOk = FALSE;r_isR= TRUE; break;
default: rOk = FALSE;
}
@ -2601,7 +2615,47 @@ HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
return VARCMP_EQ;
}
}
else if (l_isR && r_isR) {
if (lDouble < rDouble) {
return VARCMP_LT;
} else if (lDouble > rDouble) {
return VARCMP_GT;
} else {
return VARCMP_EQ;
}
}
else if (lOk && r_isR) {
if (lVal < rDouble) {
return VARCMP_LT;
} else if (lVal > rDouble) {
return VARCMP_GT;
} else {
return VARCMP_EQ;
}
}
else if (l_isR && rOk) {
if (lDouble < rVal) {
return VARCMP_LT;
} else if (lDouble > rVal) {
return VARCMP_GT;
} else {
return VARCMP_EQ;
}
}
if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR ) {
if(((V_VT(right)&VT_TYPEMASK) == VT_EMPTY ) && !(V_BSTR(left))) {
return VARCMP_EQ;
} else {
return VARCMP_GT;
}
}
if ((V_VT(right)&VT_TYPEMASK) == VT_BSTR ) {
if(((V_VT(left)&VT_TYPEMASK) == VT_EMPTY ) && !(V_BSTR(right))) {
return VARCMP_EQ;
} else {
return VARCMP_LT;
}
}
/* Dates */
if ((V_VT(left)&VT_TYPEMASK) == VT_DATE &&
(V_VT(right)&VT_TYPEMASK) == VT_DATE) {
@ -2635,7 +2689,9 @@ HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
return VARCMP_GT;
}
}
FIXME("VarCmp partial implementation, doesn't support vt 0x%x / 0x%x\n",V_VT(left), V_VT(right));
else if((V_VT(right)&VT_TYPEMASK) == VT_EMPTY)
return VARCMP_GT;
FIXME("VarCmp partial implementation, doesn't support %s / %s\n",wine_vtypes[V_VT(left)], wine_vtypes[V_VT(right)]);
return E_FAIL;
}
@ -3120,7 +3176,7 @@ HRESULT WINAPI VarDiv(LPVARIANT left, LPVARIANT right, LPVARIANT result)
lvt = V_VT(left)&VT_TYPEMASK;
rvt = V_VT(right)&VT_TYPEMASK;
found = FALSE;resvt = VT_VOID;
if (((1<<lvt) | (1<<rvt)) & (VTBIT_R4|VTBIT_R8)) {
if (((1<<lvt) | (1<<rvt)) & (VTBIT_R4|VTBIT_R8|VTBIT_CY)) {
found = TRUE;
resvt = VT_R8;
}

View file

@ -4594,6 +4594,600 @@ VarDecAdd_AsPositive:
return hRet;
}
/* internal representation of the value stored in a DECIMAL. The bytes are
stored from LSB at index 0 to MSB at index 11
*/
typedef struct DECIMAL_internal
{
DWORD bitsnum[3]; /* 96 significant bits, unsigned */
unsigned char scale; /* number scaled * 10 ^ -(scale) */
unsigned int sign : 1; /* 0 - positive, 1 - negative */
} VARIANT_DI;
/* translate from external DECIMAL format into an internal representation */
static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to)
{
to->scale = DEC_SCALE(from);
to->sign = DEC_SIGN(from) ? 1 : 0;
to->bitsnum[0] = DEC_LO32(from);
to->bitsnum[1] = DEC_MID32(from);
to->bitsnum[2] = DEC_HI32(from);
}
static void VARIANT_DecFromDI(VARIANT_DI * from, DECIMAL * to)
{
if (from->sign) {
DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_NEG, from->scale);
} else {
DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_POS, from->scale);
}
DEC_LO32(to) = from->bitsnum[0];
DEC_MID32(to) = from->bitsnum[1];
DEC_HI32(to) = from->bitsnum[2];
}
/* clear an internal representation of a DECIMAL */
static void VARIANT_DI_clear(VARIANT_DI * i)
{
memset(i, 0, sizeof(VARIANT_DI));
}
/* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
size is supported. The value in p is replaced by the quotient of the division, and
the remainder is returned as a result. This routine is most often used with a divisor
of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
*/
static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor)
{
if (divisor == 0) {
/* division by 0 */
return 0xFF;
} else if (divisor == 1) {
/* dividend remains unchanged */
return 0;
} else {
unsigned char remainder = 0;
ULONGLONG iTempDividend;
signed int i;
for (i = n - 1; i >= 0 && !p[i]; i--); /* skip leading zeros */
for (; i >= 0; i--) {
iTempDividend = ((ULONGLONG)remainder << 32) + p[i];
remainder = iTempDividend % divisor;
p[i] = iTempDividend / divisor;
}
return remainder;
}
}
/* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
static int VARIANT_int_iszero(DWORD * p, unsigned int n)
{
for (; n > 0; n--) if (*p++ != 0) return 0;
return 1;
}
/* multiply two DECIMALS, without changing either one, and place result in third
parameter. Result is normalized when scale is > 0. Attempts to remove significant
digits when scale > 0 in order to fit an overflowing result. Final overflow
flag is returned.
*/
static int VARIANT_DI_mul(VARIANT_DI * a, VARIANT_DI * b, VARIANT_DI * result)
{
int r_overflow = 0;
DWORD running[6];
signed int mulstart;
VARIANT_DI_clear(result);
result->sign = (a->sign ^ b->sign) ? 1 : 0;
/* Multiply 128-bit operands into a (max) 256-bit result. The scale
of the result is formed by adding the scales of the operands.
*/
result->scale = a->scale + b->scale;
memset(running, 0, sizeof(running));
/* count number of leading zero-bytes in operand A */
for (mulstart = sizeof(a->bitsnum)/sizeof(DWORD) - 1; mulstart >= 0 && !a->bitsnum[mulstart]; mulstart--);
if (mulstart < 0) {
/* result is 0, because operand A is 0 */
result->scale = 0;
result->sign = 0;
} else {
unsigned char remainder = 0;
int iA;
/* perform actual multiplication */
for (iA = 0; iA <= mulstart; iA++) {
ULONG iOverflowMul;
int iB;
for (iOverflowMul = 0, iB = 0; iB < sizeof(b->bitsnum)/sizeof(DWORD); iB++) {
ULONG iRV;
int iR;
iRV = VARIANT_Mul(b->bitsnum[iB], a->bitsnum[iA], &iOverflowMul);
iR = iA + iB;
do {
running[iR] = VARIANT_Add(running[iR], 0, &iRV);
iR++;
} while (iRV);
}
}
/* Too bad - native oleaut does not do this, so we should not either */
#if 0
/* While the result is divisible by 10, and the scale > 0, divide by 10.
This operation should not lose significant digits, and gives an
opportunity to reduce the possibility of overflows in future
operations issued by the application.
*/
while (result->scale > 0) {
memcpy(quotient, running, sizeof(quotient));
remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
if (remainder > 0) break;
memcpy(running, quotient, sizeof(quotient));
result->scale--;
}
#endif
/* While the 256-bit result overflows, and the scale > 0, divide by 10.
This operation *will* lose significant digits of the result because
all the factors of 10 were consumed by the previous operation.
*/
while (result->scale > 0 && !VARIANT_int_iszero(
running + sizeof(result->bitsnum) / sizeof(DWORD),
(sizeof(running) - sizeof(result->bitsnum)) / sizeof(DWORD))) {
remainder = VARIANT_int_divbychar(running, sizeof(running) / sizeof(DWORD), 10);
if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
result->scale--;
}
/* round up the result - native oleaut32 does this */
if (remainder >= 5) {
unsigned int i;
for (remainder = 1, i = 0; i < sizeof(running)/sizeof(DWORD) && remainder; i++) {
ULONGLONG digit = running[i] + 1;
remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
running[i] = digit & 0xFFFFFFFF;
}
}
/* Signal overflow if scale == 0 and 256-bit result still overflows,
and copy result bits into result structure
*/
r_overflow = !VARIANT_int_iszero(
running + sizeof(result->bitsnum)/sizeof(DWORD),
(sizeof(running) - sizeof(result->bitsnum))/sizeof(DWORD));
memcpy(result->bitsnum, running, sizeof(result->bitsnum));
}
return r_overflow;
}
/* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
hardcoded (period for decimal separator, dash as negative sign). Returns 0 for
success, nonzero if insufficient space in output buffer.
*/
static int VARIANT_DI_tostringW(VARIANT_DI * a, WCHAR * s, unsigned int n)
{
int overflow = 0;
DWORD quotient[3];
unsigned char remainder;
unsigned int i;
/* place negative sign */
if (!VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD)) && a->sign) {
if (n > 0) {
*s++ = '-';
n--;
}
else overflow = 1;
}
/* prepare initial 0 */
if (!overflow) {
if (n >= 2) {
s[0] = '0';
s[1] = '\0';
} else overflow = 1;
}
i = 0;
memcpy(quotient, a->bitsnum, sizeof(a->bitsnum));
while (!overflow && !VARIANT_int_iszero(quotient, sizeof(quotient) / sizeof(DWORD))) {
remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
if (i + 2 > n) {
overflow = 1;
} else {
s[i++] = '0' + remainder;
s[i] = '\0';
}
}
if (!overflow && !VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD))) {
/* reverse order of digits */
WCHAR * x = s; WCHAR * y = s + i - 1;
while (x < y) {
*x ^= *y;
*y ^= *x;
*x++ ^= *y--;
}
/* check for decimal point. "i" now has string length */
if (i <= a->scale) {
unsigned int numzeroes = a->scale + 1 - i;
if (i + 1 + numzeroes >= n) {
overflow = 1;
} else {
memmove(s + numzeroes, s, (i + 1) * sizeof(WCHAR));
i += numzeroes;
while (numzeroes > 0) {
s[--numzeroes] = '0';
}
}
}
/* place decimal point */
if (a->scale > 0) {
unsigned int periodpos = i - a->scale;
if (i + 2 >= n) {
overflow = 1;
} else {
memmove(s + periodpos + 1, s + periodpos, (i + 1 - periodpos) * sizeof(WCHAR));
s[periodpos] = '.'; i++;
/* remove extra zeros at the end, if any */
while (s[i - 1] == '0') s[--i] = '\0';
if (s[i - 1] == '.') s[--i] = '\0';
}
}
}
return overflow;
}
/* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
static void VARIANT_int_shiftleft(DWORD * p, unsigned int n, unsigned int shift)
{
DWORD shifted;
unsigned int i;
/* shift whole DWORDs to the left */
while (shift >= 32)
{
memmove(p + 1, p, (n - 1) * sizeof(DWORD));
*p = 0; shift -= 32;
}
/* shift remainder (1..31 bits) */
shifted = 0;
if (shift > 0) for (i = 0; i < n; i++)
{
DWORD b;
b = p[i] >> (32 - shift);
p[i] = (p[i] << shift) | shifted;
shifted = b;
}
}
/* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
Value at v is incremented by the value at p. Any size is supported, provided
that v is not shorter than p. Any unapplied carry is returned as a result.
*/
static unsigned char VARIANT_int_add(DWORD * v, unsigned int nv, DWORD * p,
unsigned int np)
{
unsigned char carry = 0;
if (nv >= np) {
ULONGLONG sum;
unsigned int i;
for (i = 0; i < np; i++) {
sum = (ULONGLONG)v[i]
+ (ULONGLONG)p[i]
+ (ULONGLONG)carry;
v[i] = sum & 0xffffffff;
carry = sum >> 32;
}
for (; i < nv && carry; i++) {
sum = (ULONGLONG)v[i]
+ (ULONGLONG)carry;
v[i] = sum & 0xffffffff;
carry = sum >> 32;
}
}
return carry;
}
/* perform integral division with operand p as dividend. Parameter n indicates
number of available DWORDs in divisor p, but available space in p must be
actually at least 2 * n DWORDs, because the remainder of the integral
division is built in the next n DWORDs past the start of the quotient. This
routine replaces the dividend in p with the quotient, and appends n
additional DWORDs for the remainder.
Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
C/C++ :-) where the "longhand binary division" algorithm was exposed for the
source code to the VLI (Very Large Integer) division operator. This algorithm
was then heavily modified by me (Alex Villacis Lasso) in order to handle
variably-scaled integers such as the MS DECIMAL representation.
*/
static void VARIANT_int_div(DWORD * p, unsigned int n, DWORD * divisor,
unsigned int dn)
{
unsigned int i;
DWORD tempsub[8];
DWORD * negdivisor = tempsub + n;
/* build 2s-complement of divisor */
for (i = 0; i < n; i++) negdivisor[i] = (i < dn) ? ~divisor[i] : 0xFFFFFFFF;
p[n] = 1;
VARIANT_int_add(negdivisor, n, p + n, 1);
memset(p + n, 0, n * sizeof(DWORD));
/* skip all leading zero DWORDs in quotient */
for (i = 0; i < n && !p[n - 1]; i++) VARIANT_int_shiftleft(p, n, 32);
/* i is now number of DWORDs left to process */
for (i <<= 5; i < (n << 5); i++) {
VARIANT_int_shiftleft(p, n << 1, 1); /* shl quotient+remainder */
/* trial subtraction */
memcpy(tempsub, p + n, n * sizeof(DWORD));
VARIANT_int_add(tempsub, n, negdivisor, n);
/* check whether result of subtraction was negative */
if ((tempsub[n - 1] & 0x80000000) == 0) {
memcpy(p + n, tempsub, n * sizeof(DWORD));
p[0] |= 1;
}
}
}
/* perform integral multiplication by a byte operand. Used for scaling by 10 */
static unsigned char VARIANT_int_mulbychar(DWORD * p, unsigned int n, unsigned char m)
{
unsigned int i;
ULONG iOverflowMul;
for (iOverflowMul = 0, i = 0; i < n; i++)
p[i] = VARIANT_Mul(p[i], m, &iOverflowMul);
return (unsigned char)iOverflowMul;
}
/* increment value in A by the value indicated in B, with scale adjusting.
Modifies parameters by adjusting scales. Returns 0 if addition was
successful, nonzero if a parameter underflowed before it could be
successfully used in the addition.
*/
static int VARIANT_int_addlossy(
DWORD * a, int * ascale, unsigned int an,
DWORD * b, int * bscale, unsigned int bn)
{
int underflow = 0;
if (VARIANT_int_iszero(a, an)) {
/* if A is zero, copy B into A, after removing digits */
while (bn > an && !VARIANT_int_iszero(b + an, bn - an)) {
VARIANT_int_divbychar(b, bn, 10);
(*bscale)--;
}
memcpy(a, b, an * sizeof(DWORD));
*ascale = *bscale;
} else if (!VARIANT_int_iszero(b, bn)) {
unsigned int tn = an + 1;
DWORD t[5];
if (bn + 1 > tn) tn = bn + 1;
if (*ascale != *bscale) {
/* first (optimistic) try - try to scale down the one with the bigger
scale, while this number is divisible by 10 */
DWORD * digitchosen;
unsigned int nchosen;
int * scalechosen;
int targetscale;
if (*ascale < *bscale) {
targetscale = *ascale;
scalechosen = bscale;
digitchosen = b;
nchosen = bn;
} else {
targetscale = *bscale;
scalechosen = ascale;
digitchosen = a;
nchosen = an;
}
memset(t, 0, tn * sizeof(DWORD));
memcpy(t, digitchosen, nchosen * sizeof(DWORD));
/* divide by 10 until target scale is reached */
while (*scalechosen > targetscale) {
unsigned char remainder = VARIANT_int_divbychar(t, tn, 10);
if (!remainder) {
(*scalechosen)--;
memcpy(digitchosen, t, nchosen * sizeof(DWORD));
} else break;
}
}
if (*ascale != *bscale) {
DWORD * digitchosen;
unsigned int nchosen;
int * scalechosen;
int targetscale;
/* try to scale up the one with the smaller scale */
if (*ascale > *bscale) {
targetscale = *ascale;
scalechosen = bscale;
digitchosen = b;
nchosen = bn;
} else {
targetscale = *bscale;
scalechosen = ascale;
digitchosen = a;
nchosen = an;
}
memset(t, 0, tn * sizeof(DWORD));
memcpy(t, digitchosen, nchosen * sizeof(DWORD));
/* multiply by 10 until target scale is reached, or
significant bytes overflow the number
*/
while (*scalechosen < targetscale && t[nchosen] == 0) {
VARIANT_int_mulbychar(t, tn, 10);
if (t[nchosen] == 0) {
/* still does not overflow */
(*scalechosen)++;
memcpy(digitchosen, t, nchosen * sizeof(DWORD));
}
}
}
if (*ascale != *bscale) {
/* still different? try to scale down the one with the bigger scale
(this *will* lose significant digits) */
DWORD * digitchosen;
unsigned int nchosen;
int * scalechosen;
int targetscale;
if (*ascale < *bscale) {
targetscale = *ascale;
scalechosen = bscale;
digitchosen = b;
nchosen = bn;
} else {
targetscale = *bscale;
scalechosen = ascale;
digitchosen = a;
nchosen = an;
}
memset(t, 0, tn * sizeof(DWORD));
memcpy(t, digitchosen, nchosen * sizeof(DWORD));
/* divide by 10 until target scale is reached */
while (*scalechosen > targetscale) {
VARIANT_int_divbychar(t, tn, 10);
(*scalechosen)--;
memcpy(digitchosen, t, nchosen * sizeof(DWORD));
}
}
/* check whether any of the operands still has significant digits
(underflow case 1)
*/
if (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)) {
underflow = 1;
} else {
/* at this step, both numbers have the same scale and can be added
as integers. However, the result might not fit in A, so further
scaling down might be necessary.
*/
while (!underflow) {
memset(t, 0, tn * sizeof(DWORD));
memcpy(t, a, an * sizeof(DWORD));
VARIANT_int_add(t, tn, b, bn);
if (VARIANT_int_iszero(t + an, tn - an)) {
/* addition was successful */
memcpy(a, t, an * sizeof(DWORD));
break;
} else {
/* addition overflowed - remove significant digits
from both operands and try again */
VARIANT_int_divbychar(a, an, 10); (*ascale)--;
VARIANT_int_divbychar(b, bn, 10); (*bscale)--;
/* check whether any operand keeps significant digits after
scaledown (underflow case 2)
*/
underflow = (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn));
}
}
}
}
return underflow;
}
/* perform complete DECIMAL division in the internal representation. Returns
0 if the division was completed (even if quotient is set to 0), or nonzero
in case of quotient overflow.
*/
static HRESULT VARIANT_DI_div(VARIANT_DI * dividend, VARIANT_DI * divisor, VARIANT_DI * quotient)
{
HRESULT r_overflow = S_OK;
if (VARIANT_int_iszero(divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD))) {
/* division by 0 */
r_overflow = DISP_E_DIVBYZERO;
} else if (VARIANT_int_iszero(dividend->bitsnum, sizeof(dividend->bitsnum)/sizeof(DWORD))) {
VARIANT_DI_clear(quotient);
} else {
int quotientscale, remainderscale, tempquotientscale;
DWORD remainderplusquotient[8];
int underflow;
quotientscale = remainderscale = (int)dividend->scale - (int)divisor->scale;
tempquotientscale = quotientscale;
VARIANT_DI_clear(quotient);
quotient->sign = (dividend->sign ^ divisor->sign) ? 1 : 0;
/* The following strategy is used for division
1) if there was a nonzero remainder from previous iteration, use it as
dividend for this iteration, else (for first iteration) use intended
dividend
2) perform integer division in temporary buffer, develop quotient in
low-order part, remainder in high-order part
3) add quotient from step 2 to final result, with possible loss of
significant digits
4) multiply integer part of remainder by 10, while incrementing the
scale of the remainder. This operation preserves the intended value
of the remainder.
5) loop to step 1 until one of the following is true:
a) remainder is zero (exact division achieved)
b) addition in step 3 fails to modify bits in quotient (remainder underflow)
*/
memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
memcpy(remainderplusquotient, dividend->bitsnum, sizeof(dividend->bitsnum));
do {
VARIANT_int_div(
remainderplusquotient, 4,
divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD));
underflow = VARIANT_int_addlossy(
quotient->bitsnum, &quotientscale, sizeof(quotient->bitsnum) / sizeof(DWORD),
remainderplusquotient, &tempquotientscale, 4);
VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10);
memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD));
tempquotientscale = ++remainderscale;
} while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4));
/* quotient scale might now be negative (extremely big number). If, so, try
to multiply quotient by 10 (without overflowing), while adjusting the scale,
until scale is 0. If this cannot be done, it is a real overflow.
*/
while (!r_overflow && quotientscale < 0) {
memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
memcpy(remainderplusquotient, quotient->bitsnum, sizeof(quotient->bitsnum));
VARIANT_int_mulbychar(remainderplusquotient, sizeof(remainderplusquotient)/sizeof(DWORD), 10);
if (VARIANT_int_iszero(remainderplusquotient + sizeof(quotient->bitsnum)/sizeof(DWORD),
(sizeof(remainderplusquotient) - sizeof(quotient->bitsnum))/sizeof(DWORD))) {
quotientscale++;
memcpy(quotient->bitsnum, remainderplusquotient, sizeof(quotient->bitsnum));
} else r_overflow = DISP_E_OVERFLOW;
}
if (!r_overflow) {
if (quotientscale <= 255) quotient->scale = quotientscale;
else VARIANT_DI_clear(quotient);
}
}
return r_overflow;
}
/************************************************************************
* VarDecDiv (OLEAUT32.178)
*
@ -4610,8 +5204,59 @@ VarDecAdd_AsPositive:
*/
HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
{
FIXME("(%p,%p,%p)-stub!\n",pDecLeft,pDecRight,pDecOut);
return DISP_E_OVERFLOW;
HRESULT hRet = S_OK;
VARIANT_DI di_left, di_right, di_result;
HRESULT divresult;
if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG;
VARIANT_DIFromDec(pDecLeft, &di_left);
VARIANT_DIFromDec(pDecRight, &di_right);
divresult = VARIANT_DI_div(&di_left, &di_right, &di_result);
if (divresult)
{
/* division actually overflowed */
hRet = divresult;
}
else
{
hRet = S_OK;
if (di_result.scale > DEC_MAX_SCALE)
{
unsigned char remainder = 0;
/* division underflowed. In order to comply with the MSDN
specifications for DECIMAL ranges, some significant digits
must be removed
*/
WARN("result scale is %u, scaling (with loss of significant digits)...\n",
di_result.scale);
while (di_result.scale > DEC_MAX_SCALE &&
!VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD)))
{
remainder = VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD), 10);
di_result.scale--;
}
if (di_result.scale > DEC_MAX_SCALE)
{
WARN("result underflowed, setting to 0\n");
di_result.scale = 0;
di_result.sign = 0;
}
else if (remainder >= 5) /* round up result - native oleaut32 does this */
{
unsigned int i;
for (remainder = 1, i = 0; i < sizeof(di_result.bitsnum) / sizeof(DWORD) && remainder; i++) {
ULONGLONG digit = di_result.bitsnum[i] + 1;
remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
di_result.bitsnum[i] = digit & 0xFFFFFFFF;
}
}
}
VARIANT_DecFromDI(&di_result, pDecOut);
}
return hRet;
}
/************************************************************************
@ -4630,42 +5275,44 @@ HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECI
*/
HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
{
/* FIXME: This only allows multiplying by a fixed integer <= 0xffffffff */
HRESULT hRet = S_OK;
VARIANT_DI di_left, di_right, di_result;
int mulresult;
if (!DEC_SCALE(pDecLeft) || !DEC_SCALE(pDecRight))
VARIANT_DIFromDec(pDecLeft, &di_left);
VARIANT_DIFromDec(pDecRight, &di_right);
mulresult = VARIANT_DI_mul(&di_left, &di_right, &di_result);
if (mulresult)
{
/* At least one term is an integer */
const DECIMAL* pDecInteger = DEC_SCALE(pDecLeft) ? pDecRight : pDecLeft;
const DECIMAL* pDecOperand = DEC_SCALE(pDecLeft) ? pDecLeft : pDecRight;
HRESULT hRet = S_OK;
unsigned int multiplier = DEC_LO32(pDecInteger);
ULONG overflow = 0;
if (DEC_HI32(pDecInteger) || DEC_MID32(pDecInteger))
{
FIXME("(%p,%p,%p) semi-stub!\n",pDecLeft,pDecRight,pDecOut);
return DISP_E_OVERFLOW;
}
DEC_LO32(pDecOut) = VARIANT_Mul(DEC_LO32(pDecOperand), multiplier, &overflow);
DEC_MID32(pDecOut) = VARIANT_Mul(DEC_MID32(pDecOperand), multiplier, &overflow);
DEC_HI32(pDecOut) = VARIANT_Mul(DEC_HI32(pDecOperand), multiplier, &overflow);
if (overflow)
hRet = DISP_E_OVERFLOW;
else
{
BYTE sign = DECIMAL_POS;
if (DEC_SIGN(pDecLeft) != DEC_SIGN(pDecRight))
sign = DECIMAL_NEG; /* pos * neg => negative */
DEC_SIGN(pDecOut) = sign;
DEC_SCALE(pDecOut) = DEC_SCALE(pDecOperand);
}
return hRet;
/* multiplication actually overflowed */
hRet = DISP_E_OVERFLOW;
}
FIXME("(%p,%p,%p) semi-stub!\n",pDecLeft,pDecRight,pDecOut);
return DISP_E_OVERFLOW;
else
{
if (di_result.scale > DEC_MAX_SCALE)
{
/* multiplication underflowed. In order to comply with the MSDN
specifications for DECIMAL ranges, some significant digits
must be removed
*/
WARN("result scale is %u, scaling (with loss of significant digits)...\n",
di_result.scale);
while (di_result.scale > DEC_MAX_SCALE &&
!VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD)))
{
VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD), 10);
di_result.scale--;
}
if (di_result.scale > DEC_MAX_SCALE)
{
WARN("result underflowed, setting to 0\n");
di_result.scale = 0;
di_result.sign = 0;
}
}
VARIANT_DecFromDI(&di_result, pDecOut);
}
return hRet;
}
/************************************************************************
@ -5409,6 +6056,58 @@ HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
}
static BSTR VARIANT_BstrReplaceDecimal(WCHAR * buff, LCID lcid, ULONG dwFlags)
{
BSTR bstrOut;
WCHAR lpDecimalSep[16];
/* Native oleaut32 uses the locale-specific decimal separator even in the
absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
American locales will see "one thousand and one tenth" as "1000,1"
instead of "1000.1" (notice the comma). The following code checks for
the need to replace the decimal separator, and if so, will prepare an
appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
*/
GetLocaleInfoW(lcid, LOCALE_SDECIMAL, lpDecimalSep, sizeof(lpDecimalSep) / sizeof(WCHAR));
if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0')
{
/* locale is compatible with English - return original string */
bstrOut = SysAllocString(buff);
}
else
{
WCHAR *p;
WCHAR numbuff[256];
WCHAR empty[1] = {'\0'};
NUMBERFMTW minFormat;
minFormat.NumDigits = 0;
minFormat.LeadingZero = 0;
minFormat.Grouping = 0;
minFormat.lpDecimalSep = lpDecimalSep;
minFormat.lpThousandSep = empty;
minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */
/* count number of decimal digits in string */
p = strchrW( buff, '.' );
if (p) minFormat.NumDigits = strlenW(p + 1);
numbuff[0] = '\0';
if (!GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
buff, &minFormat, numbuff, sizeof(numbuff) / sizeof(WCHAR)))
{
WARN("GetNumberFormatW() failed, returning raw number string instead\n");
bstrOut = SysAllocString(buff);
}
else
{
TRACE("created minimal NLS string %s\n", debugstr_w(numbuff));
bstrOut = SysAllocString(numbuff);
}
}
return bstrOut;
}
static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
BSTR* pbstrOut, LPCWSTR lpszFormat)
{
@ -5445,52 +6144,7 @@ static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
}
else
{
WCHAR lpDecimalSep[16];
/* Native oleaut32 uses the locale-specific decimal separator even in the
absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
American locales will see "one thousand and one tenth" as "1000,1"
instead of "1000.1" (notice the comma). The following code checks for
the need to replace the decimal separator, and if so, will prepare an
appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
*/
GetLocaleInfoW(lcid, LOCALE_SDECIMAL, lpDecimalSep, sizeof(lpDecimalSep) / sizeof(WCHAR));
if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0')
{
/* locale is compatible with English - return original string */
*pbstrOut = SysAllocString(buff);
}
else
{
WCHAR *p;
WCHAR numbuff[256];
WCHAR empty[1] = {'\0'};
NUMBERFMTW minFormat;
minFormat.NumDigits = 0;
minFormat.LeadingZero = 0;
minFormat.Grouping = 0;
minFormat.lpDecimalSep = lpDecimalSep;
minFormat.lpThousandSep = empty;
minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */
/* count number of decimal digits in string */
p = strchrW( buff, '.' );
if (p) minFormat.NumDigits = strlenW(p + 1);
numbuff[0] = '\0';
if (!GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
buff, &minFormat, numbuff, sizeof(numbuff) / sizeof(WCHAR)))
{
WARN("GetNumberFormatW() failed, returning raw number string instead\n");
*pbstrOut = SysAllocString(buff);
}
else
{
TRACE("created minimal NLS string %s\n", debugstr_w(numbuff));
*pbstrOut = SysAllocString(numbuff);
}
}
*pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
}
return *pbstrOut ? S_OK : E_OUTOFMEMORY;
}
@ -5812,25 +6466,33 @@ HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrO
*/
HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
{
WCHAR buff[256];
VARIANT_DI temp;
if (!pbstrOut)
return E_INVALIDARG;
if (!DEC_SCALE(pDecIn) && !DEC_HI32(pDecIn))
VARIANT_DIFromDec(pDecIn, &temp);
VARIANT_DI_tostringW(&temp, buff, 256);
if (dwFlags & LOCALE_USE_NLS)
{
WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
WCHAR numbuff[256];
/* Create the basic number string */
*szOut-- = '\0';
szOut = VARIANT_WriteNumber(DEC_LO64(pDecIn), szOut);
if (DEC_SIGN(pDecIn))
dwFlags |= VAR_NEGATIVE;
*pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
TRACE("returning %s\n", debugstr_w(*pbstrOut));
return *pbstrOut ? S_OK : E_OUTOFMEMORY;
/* Format the number for the locale */
numbuff[0] = '\0';
GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
TRACE("created NLS string %s\n", debugstr_w(numbuff));
*pbstrOut = SysAllocString(numbuff);
}
FIXME("semi-stub\n");
return E_INVALIDARG;
else
{
*pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
}
TRACE("returning %s\n", debugstr_w(*pbstrOut));
return *pbstrOut ? S_OK : E_OUTOFMEMORY;
}
/************************************************************************

View file

@ -49,6 +49,7 @@ extern "C" {
#define PARAMFLAG_FRETVAL (8)
#define PARAMFLAG_FOPT (16)
#define PARAMFLAG_FHASDEFAULT (32)
#define PARAMFLAG_FHASCUSTDATA (64)
#define IDLFLAG_NONE PARAMFLAG_NONE
#define IDLFLAG_FIN PARAMFLAG_FIN
#define IDLFLAG_FOUT PARAMFLAG_FOUT