mirror of
https://github.com/reactos/reactos.git
synced 2025-02-23 17:05:46 +00:00
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:
parent
7373027088
commit
6b37e95bd4
14 changed files with 1294 additions and 897 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
31
reactos/lib/oleaut32/oleaut32_Ko.rc
Normal file
31
reactos/lib/oleaut32/oleaut32_Ko.rc
Normal 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 "비작동"
|
||||
}
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
@ -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;
|
||||
|
|
|
@ -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? */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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, "ientscale, 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;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue