From 6b37e95bd49230249d2dc9c31191c9cea2fac7be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9=20van=20Geldorp?= Date: Thu, 17 Nov 2005 21:52:13 +0000 Subject: [PATCH] =?UTF-8?q?Sync=20to=20Wine-0=5F9=5F1:=20Huw=20Davies=20=20-=20Treat=20paramflags=20=3D=3D=200=20lik?= =?UTF-8?q?e=20PARAMFLAG=5FFIN.=20-=20Don't=20call=20Release=20on=20a=20nu?= =?UTF-8?q?ll=20ptr.=20-=20Deal=20with=20pExcepInfo=20=3D=3D=20NULL.=20Rob?= =?UTF-8?q?ert=20Shearman=20=20-=20Add=20IFontEventsD?= =?UTF-8?q?isp=20and=20IProvideMultipleClassInfo.=20-=20Make=20sure=20to?= =?UTF-8?q?=20clean=20up=20properly=20on=20error.=20-=20Restrict=20the=20c?= =?UTF-8?q?ritical=20section=20to=20getting=20the=20channel=20buffer=20and?= =?UTF-8?q?=20=20=20adding=20a=20reference=20to=20it.=20-=20There=20is=20n?= =?UTF-8?q?o=20need=20to=20call=20IUnknown=5FQueryInterface=20since=20gett?= =?UTF-8?q?ing=20the=20=20=20correct=20object=20is=20handled=20by=20the=20?= =?UTF-8?q?proxy=20manager.=20-=20Forward=20IDispatch=20functions=20to=20t?= =?UTF-8?q?he=20MIDL-generated=20proxy.=20-=20Remove=20special=20cases=20c?= =?UTF-8?q?aused=20by=20previous=20marshaling=20of=20IDispatch=20&=20=20?= =?UTF-8?q?=20IUnknown=20that=20is=20no=20longer=20done.=20-=20Add=20error?= =?UTF-8?q?=20messages=20if=20an=20IUnknown=20or=20IDispatch=20method=20is?= =?UTF-8?q?=20called=20when=20=20=20it=20no=20longer=20should=20be.=20-=20?= =?UTF-8?q?Cleanup=20formating=20of=20DispCallFunc.=20-=20Fix=20DispCallFu?= =?UTF-8?q?nc=20for=20functions=20with=20return=20values.=20-=20Don't=20re?= =?UTF-8?q?ly=20on=20=5Fcopy=5Farg=20as=20it=20is=20going=20away=20soon.?= =?UTF-8?q?=20-=20Make=20wParamFlags=20in=20the=20paramdesc=20dumping=20fu?= =?UTF-8?q?nction=20human=20readable.=20-=20Enums=20should=20be=20VT=5FI4?= =?UTF-8?q?=20instead=20of=20VT=5FINT.=20-=20Trace=20the=20return=20value?= =?UTF-8?q?=20from=20the=20ITypeInfo=5FfnInvoke.=20-=20Read=20DLL=20name?= =?UTF-8?q?=20from=20modules=20in=20MSFT=20typelibs.=20-=20A=20name=20offs?= =?UTF-8?q?et=20of=20-1=20for=20a=20parameter=20means=20that=20it=20has=20?= =?UTF-8?q?the=20same=20name=20=20=20as=20the=20function.=20-=20Print=20an?= =?UTF-8?q?=20error=20if=20a=20ReadName=20is=20attempted=20with=20an=20off?= =?UTF-8?q?set=20of=20-1,=20=20=20since=20this=20will=20read=20garbage.=20?= =?UTF-8?q?-=20Implement=20ITypeInfo=5FGetDllEntry.=20-=20Fix=20a=20crash?= =?UTF-8?q?=20during=20+variant=20logging=20caused=20by=20a=20typo=20causi?= =?UTF-8?q?ng=20an=20array=20=20=20to=20be=20one=20element=20less=20than?= =?UTF-8?q?=20expected.=20-=20The=20PSDispatch=20PS=20class=20factory=20ca?= =?UTF-8?q?n=20manage=20both=20typelib=20marshalled=20and=20=20=20IDispatc?= =?UTF-8?q?h,=20which=20is=20NDR=20marshalled,=20so=20we=20need=20a=20wrap?= =?UTF-8?q?per=20to=20call=20the=20=20=20appropriate=20CreateProxy=20or=20?= =?UTF-8?q?CreateStub=20function.=20Alex=20Villac=C3=ADs=20Lasso=20=20-=20Implement=20complete=20VarDecDiv()?= =?UTF-8?q?=20for=20any=20valid=20DECIMAL.=20-=20Implement=20complete=20Va?= =?UTF-8?q?rDecMul()=20for=20any=20valid=20DECIMAL.=20-=20Implement=20comp?= =?UTF-8?q?lete=20VarBstrFromDec()=20for=20any=20valid=20DECIMAL,=20with?= =?UTF-8?q?=20=20=20internationalization=20support=20borrowed=20from=20VAR?= =?UTF-8?q?IANT=5FBstrFromReal().=20The=20=20=20decimal=20fix=20for=20VARI?= =?UTF-8?q?ANT=5FBstrFromReal=20was=20encapsulated=20in=20a=20separate=20?= =?UTF-8?q?=20=20function=20and=20reused.=20Michael=20Stefaniuc=20=20-=20Handle=20VT=5FDECIMAL=20in=20VarCmp().=20-?= =?UTF-8?q?=20Handle=20VT=5FCY=20in=20VarDiv().=20Uwe=20Bonnes=20=20-=20Extend=20VarCmp()=20and?= =?UTF-8?q?=20add=20test=20cases.=20Marcus=20Meissner=20=20-=20Added=20support=20of=20loading=20of=20IPicture=20da?= =?UTF-8?q?ta=20from=20non-statable=20=20=20IStreams.=20Added=20testcases?= =?UTF-8?q?=20for=20this.=20-=20Added=20support=20for=20VT=5FI8/VT=5FUI8?= =?UTF-8?q?=20marshalling.=20-=20Fixed=20FMT=5FDATE=5FGENERAL=20and=20FMT?= =?UTF-8?q?=5FDATE=5FTIME=5FSYS=20cases=20in=20=20=20VARIANT=5FFormatDate.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit svn path=/trunk/; revision=19313 --- reactos/include/wine/ocidl.h | 2 + reactos/lib/oleaut32/oleaut.c | 78 ++- reactos/lib/oleaut32/oleaut32.rc | 1 + reactos/lib/oleaut32/oleaut32_Ko.rc | 31 + reactos/lib/oleaut32/olepicture.c | 98 ++- reactos/lib/oleaut32/regsvr.c | 9 - reactos/lib/oleaut32/tmarshal.c | 893 ++++++---------------------- reactos/lib/oleaut32/typelib.c | 140 +++-- reactos/lib/oleaut32/typelib.h | 1 + reactos/lib/oleaut32/usrmarshal.c | 9 + reactos/lib/oleaut32/varformat.c | 12 +- reactos/lib/oleaut32/variant.c | 66 +- reactos/lib/oleaut32/vartype.c | 850 +++++++++++++++++++++++--- reactos/w32api/include/oaidl.h | 1 + 14 files changed, 1294 insertions(+), 897 deletions(-) create mode 100644 reactos/lib/oleaut32/oleaut32_Ko.rc diff --git a/reactos/include/wine/ocidl.h b/reactos/include/wine/ocidl.h index ddcbce5ad94..af3848143c9 100644 --- a/reactos/include/wine/ocidl.h +++ b/reactos/include/wine/ocidl.h @@ -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); diff --git a/reactos/lib/oleaut32/oleaut.c b/reactos/lib/oleaut32/oleaut.c index 1b0f133ae51..3ef2088e873 100644 --- a/reactos/lib/oleaut32/oleaut.c +++ b/reactos/lib/oleaut32/oleaut.c @@ -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; diff --git a/reactos/lib/oleaut32/oleaut32.rc b/reactos/lib/oleaut32/oleaut32.rc index 068cb7ba073..40f3f45c6bf 100644 --- a/reactos/lib/oleaut32/oleaut32.rc +++ b/reactos/lib/oleaut32/oleaut32.rc @@ -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" diff --git a/reactos/lib/oleaut32/oleaut32_Ko.rc b/reactos/lib/oleaut32/oleaut32_Ko.rc new file mode 100644 index 00000000000..cfd2f777f78 --- /dev/null +++ b/reactos/lib/oleaut32/oleaut32_Ko.rc @@ -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 "ºñÀÛµ¿" +} diff --git a/reactos/lib/oleaut32/olepicture.c b/reactos/lib/oleaut32/olepicture.c index e1e4024031d..3420bdd686e 100644 --- a/reactos/lib/oleaut32/olepicture.c +++ b/reactos/lib/oleaut32/olepicture.c @@ -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 */ diff --git a/reactos/lib/oleaut32/regsvr.c b/reactos/lib/oleaut32/regsvr.c index 9ab5fd45bee..fc92295c1f1 100644 --- a/reactos/lib/oleaut32/regsvr.c +++ b/reactos/lib/oleaut32/regsvr.c @@ -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", diff --git a/reactos/lib/oleaut32/tmarshal.c b/reactos/lib/oleaut32/tmarshal.c index a6931ca095f..0886fc3ab7d 100644 --- a/reactos/lib/oleaut32/tmarshal.c +++ b/reactos/lib/oleaut32/tmarshal.c @@ -45,11 +45,7 @@ #include "typelib.h" #include "wine/debug.h" -static const WCHAR riidW[5] = {'r','i','i','d',0}; -static const WCHAR pdispparamsW[] = {'p','d','i','s','p','p','a','r','a','m','s',0}; -static const WCHAR ppvObjectW[] = {'p','p','v','O','b','j','e','c','t',0}; static const WCHAR IDispatchW[] = { 'I','D','i','s','p','a','t','c','h',0}; -static const WCHAR GetIDsOfNamesW[] = { 'G','e','t','I','D','s','O','f','N','a','m','e','s',0}; WINE_DEFAULT_DEBUG_CHANNEL(ole); WINE_DECLARE_DEBUG_CHANNEL(olerelay); @@ -60,9 +56,6 @@ typedef struct _marshal_state { LPBYTE base; int size; int curoff; - - BOOL thisisiid; - IID iid; /* HACK: for VT_VOID */ } marshal_state; /* used in the olerelay code to avoid having the L"" stuff added by debugstr_w */ @@ -360,6 +353,7 @@ typedef struct _TMProxyImpl { IID iid; CRITICAL_SECTION crit; IUnknown *outerunknown; + IDispatch *dispatch; } TMProxyImpl; static HRESULT WINAPI @@ -396,6 +390,7 @@ TMProxyImpl_Release(LPRPCPROXYBUFFER iface) if (!refCount) { + if (This->dispatch) IDispatch_Release(This->dispatch); DeleteCriticalSection(&This->crit); if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf); VirtualFree(This->asmstubs, 0, MEM_RELEASE); @@ -450,6 +445,8 @@ static const IRpcProxyBufferVtbl tmproxyvtable = { int _argsize(DWORD vt) { switch (vt) { + case VT_UI8: + return 8/sizeof(DWORD); case VT_R8: return sizeof(double)/sizeof(DWORD); case VT_CY: @@ -478,6 +475,9 @@ _xsize(TYPEDESC *td) { arrsize *= adesc->rgbounds[i].cElements; return arrsize*_xsize(&adesc->tdescElem); } + case VT_UI8: + case VT_I8: + return 8; case VT_UI2: case VT_I2: return 2; @@ -506,6 +506,13 @@ serialize_param( switch (tdesc->vt) { case VT_EMPTY: /* nothing. empty variant for instance */ return S_OK; + case VT_I8: + case VT_UI8: + hres = S_OK; + if (debugout) TRACE_(olerelay)("%lx%lx",arg[0],arg[1]); + if (writeit) + hres = xbuf_add(buf,(LPBYTE)arg,8); + return hres; case VT_BOOL: case VT_ERROR: case VT_UINT: @@ -726,8 +733,6 @@ serialize_param( if (debugout && (i<(tattr->cVars-1))) TRACE_(olerelay)(","); } - if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID))) - memcpy(&(buf->iid),arg,sizeof(buf->iid)); if (debugout) TRACE_(olerelay)("}"); break; } @@ -773,295 +778,6 @@ serialize_param( } } -/* IDL desc: - * HRESULT GetIDsOfNames( - * [in] REFIID riid, args[1] - * [in, size_is(cNames)] LPOLESTR *rgszNames, args[2] - * [in] UINT cNames, args[3] - * [in] LCID lcid, args[4] - * [out, size_is(cNames)] DISPID *rgDispId); args[5] - * - * line format: - * IID iid; - * DWORD cNames; - * LPOLESTR rgszNames[cNames]; - * DWORD bytestrlen (incl 0) - * BYTE data[bytestrlen] (incl 0) - * LCID - */ -static HRESULT -serialize_IDispatch_GetIDsOfNames( - BOOL inputparams, - BOOL debugout, - DWORD *args, - marshal_state *buf) -{ - HRESULT hres; - DWORD cNames = args[2]; - LPOLESTR *rgszNames = (LPOLESTR*)args[1]; - int i; - - if (inputparams) { - if (debugout) TRACE_(olerelay)("riid=%s,",debugstr_guid((REFIID)args[0])); - hres = xbuf_add(buf, (LPBYTE)args[0], sizeof(IID)); - if (hres) { - FIXME("serialize of IID failed.\n"); - return hres; - } - if (debugout) TRACE_(olerelay)("cNames=%ld,",cNames); - hres = xbuf_add(buf, (LPBYTE)&cNames, sizeof(DWORD)); - if (hres) { - FIXME("serialize of cNames failed.\n"); - return hres; - } - if (debugout) TRACE_(olerelay)("rgszNames=["); - for (i=0;ivt != VT_PTR) || - (tdesc->u.lptdesc->vt != VT_PTR) || - (tdesc->u.lptdesc->u.lptdesc->vt != VT_VOID) - ) { - FIXME("ppvObject not expressed as VT_PTR -> VT_PTR -> VT_VOID?\n"); - return E_FAIL; - } - cookie = (*(DWORD*)*arg) ? 0x42424242: 0x0; - if (writeit) { - hres = xbuf_add(buf, (LPVOID)&cookie, sizeof(cookie)); - if (hres) - return hres; - } - if (!*(DWORD*)*arg) { - if (debugout) TRACE_(olerelay)(""); - return S_OK; - } - if (debugout) - TRACE_(olerelay)("ppv(%p)",*(LPUNKNOWN*)*arg); - if (writeit) { - hres = _marshal_interface(buf,&(buf->iid),*(LPUNKNOWN*)*arg); - if (hres) - return hres; - } - if (dealloc) - HeapFree(GetProcessHeap(),0,(LPVOID)*arg); - return S_OK; -} - -static HRESULT -serialize_DISPPARAM_ptr( - ITypeInfo *tinfo, - BOOL writeit, - BOOL debugout, - BOOL dealloc, - TYPEDESC *tdesc, - DWORD *arg, - marshal_state *buf) -{ - DWORD cookie; - HRESULT hres; - DISPPARAMS *disp; - int i; - - if ((tdesc->vt != VT_PTR) || (tdesc->u.lptdesc->vt != VT_USERDEFINED)) { - FIXME("DISPPARAMS not expressed as VT_PTR -> VT_USERDEFINED?\n"); - return E_FAIL; - } - - cookie = *arg ? 0x42424242 : 0x0; - if (writeit) { - hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie)); - if (hres) - return hres; - } - if (!*arg) { - if (debugout) TRACE_(olerelay)(""); - return S_OK; - } - disp = (DISPPARAMS*)*arg; - if (writeit) { - hres = xbuf_add(buf,(LPBYTE)&disp->cArgs,sizeof(disp->cArgs)); - if (hres) - return hres; - } - if (debugout) TRACE_(olerelay)("D{"); - for (i=0;icArgs;i++) { - TYPEDESC vtdesc; - - vtdesc.vt = VT_VARIANT; - serialize_param( - tinfo, - writeit, - debugout, - dealloc, - &vtdesc, - (DWORD*)(disp->rgvarg+i), - buf - ); - if (debugout && (icArgs-1)) - TRACE_(olerelay)(","); - } - if (dealloc) - HeapFree(GetProcessHeap(),0,disp->rgvarg); - if (writeit) { - hres = xbuf_add(buf,(LPBYTE)&disp->cNamedArgs,sizeof(disp->cNamedArgs)); - if (hres) - return hres; - } - if (debugout) TRACE_(olerelay)("}{"); - for (i=0;icNamedArgs;i++) { - TYPEDESC vtdesc; - - vtdesc.vt = VT_UINT; - serialize_param( - tinfo, - writeit, - debugout, - dealloc, - &vtdesc, - (DWORD*)(disp->rgdispidNamedArgs+i), - buf - ); - if (debugout && (icNamedArgs-1)) - TRACE_(olerelay)(","); - } - if (debugout) TRACE_(olerelay)("}"); - if (dealloc) { - HeapFree(GetProcessHeap(),0,disp->rgdispidNamedArgs); - HeapFree(GetProcessHeap(),0,disp); - } - return S_OK; -} - static HRESULT deserialize_param( ITypeInfo *tinfo, @@ -1107,6 +823,14 @@ deserialize_param( return S_OK; } } + case VT_I8: + case VT_UI8: + if (readit) { + hres = xbuf_get(buf,(LPBYTE)arg,8); + if (hres) ERR("Failed to read integer 8 byte\n"); + } + if (debugout) TRACE_(olerelay)("%lx%lx",arg[0],arg[1]); + return hres; case VT_ERROR: case VT_BOOL: case VT_I4: @@ -1331,8 +1055,6 @@ deserialize_param( ); if (debugout && (icVars-1)) TRACE_(olerelay)(","); } - if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID))) - memcpy(&(buf->iid),(LPBYTE)*arg,sizeof(buf->iid)); if (debugout) TRACE_(olerelay)("}"); break; } @@ -1383,130 +1105,6 @@ deserialize_param( } } -static HRESULT -deserialize_LPVOID_ptr( - ITypeInfo *tinfo, - BOOL readit, - BOOL debugout, - BOOL alloc, - TYPEDESC *tdesc, - DWORD *arg, - marshal_state *buf -) { - HRESULT hres; - DWORD cookie; - - if ((tdesc->vt != VT_PTR) || - (tdesc->u.lptdesc->vt != VT_PTR) || - (tdesc->u.lptdesc->u.lptdesc->vt != VT_VOID) - ) { - FIXME("ppvObject not expressed as VT_PTR -> VT_PTR -> VT_VOID?\n"); - return E_FAIL; - } - if (alloc) - *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LPVOID)); - if (readit) { - hres = xbuf_get(buf, (LPVOID)&cookie, sizeof(cookie)); - if (hres) - return hres; - if (cookie != 0x42424242) { - *(DWORD*)*arg = 0; - if (debugout) TRACE_(olerelay)(""); - return S_OK; - } - } - if (readit) { - hres = _unmarshal_interface(buf,&buf->iid,(LPUNKNOWN*)*arg); - if (hres) { - FIXME("_unmarshal_interface of %s , %p failed with %lx\n", debugstr_guid(&buf->iid), (LPUNKNOWN*)*arg, hres); - return hres; - } - } - if (debugout) TRACE_(olerelay)("ppv(%p)",(LPVOID)*arg); - return S_OK; -} - -static HRESULT -deserialize_DISPPARAM_ptr( - ITypeInfo *tinfo, - BOOL readit, - BOOL debugout, - BOOL alloc, - TYPEDESC *tdesc, - DWORD *arg, - marshal_state *buf) -{ - DWORD cookie; - DISPPARAMS *disps; - HRESULT hres; - int i; - - if ((tdesc->vt != VT_PTR) || (tdesc->u.lptdesc->vt != VT_USERDEFINED)) { - FIXME("DISPPARAMS not expressed as VT_PTR -> VT_USERDEFINED?\n"); - return E_FAIL; - } - if (readit) { - hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie)); - if (hres) - return hres; - if (cookie == 0) { - *arg = 0; - if (debugout) TRACE_(olerelay)(""); - return S_OK; - } - } - if (alloc) - *arg = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPPARAMS)); - disps = (DISPPARAMS*)*arg; - if (!readit) - return S_OK; - hres = xbuf_get(buf, (LPBYTE)&disps->cArgs, sizeof(disps->cArgs)); - if (hres) - return hres; - if (alloc) - disps->rgvarg = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(VARIANT)*disps->cArgs); - if (debugout) TRACE_(olerelay)("D{"); - for (i=0; i< disps->cArgs; i++) { - TYPEDESC vdesc; - - vdesc.vt = VT_VARIANT; - hres = deserialize_param( - tinfo, - readit, - debugout, - alloc, - &vdesc, - (DWORD*)(disps->rgvarg+i), - buf - ); - } - if (debugout) TRACE_(olerelay)("}{"); - hres = xbuf_get(buf, (LPBYTE)&disps->cNamedArgs, sizeof(disps->cNamedArgs)); - if (hres) - return hres; - if (disps->cNamedArgs) { - if (alloc) - disps->rgdispidNamedArgs = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPID)*disps->cNamedArgs); - for (i=0; i< disps->cNamedArgs; i++) { - TYPEDESC vdesc; - - vdesc.vt = VT_UINT; - hres = deserialize_param( - tinfo, - readit, - debugout, - alloc, - &vdesc, - (DWORD*)(disps->rgdispidNamedArgs+i), - buf - ); - if (debugout && i<(disps->cNamedArgs-1)) TRACE_(olerelay)(","); - } - } - if (debugout) TRACE_(olerelay)("}"); - return S_OK; -} - /* Searches function, also in inherited interfaces */ static HRESULT _get_funcdesc( @@ -1575,18 +1173,18 @@ xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */) BSTR fname,iname; BSTR names[10]; UINT nrofnames; - int is_idispatch_getidsofnames = 0; DWORD remoteresult = 0; ITypeInfo *tinfo; + IRpcChannelBuffer *chanbuf; EnterCriticalSection(&tpinfo->crit); hres = _get_funcdesc(tpinfo->tinfo,method,&tinfo,&fdesc,&iname,&fname); if (hres) { - ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method); + ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method); ITypeInfo_Release(tinfo); LeaveCriticalSection(&tpinfo->crit); - return E_FAIL; + return E_FAIL; } if (!tpinfo->chanbuf) @@ -1596,6 +1194,10 @@ xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */) LeaveCriticalSection(&tpinfo->crit); return RPC_E_DISCONNECTED; } + chanbuf = tpinfo->chanbuf; + IRpcChannelBuffer_AddRef(chanbuf); + + LeaveCriticalSection(&tpinfo->crit); if (relaydeb) { TRACE_(olerelay)("->"); @@ -1607,33 +1209,11 @@ xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */) TRACE_(olerelay)("%d",method); TRACE_(olerelay)("("); } - if (iname && fname && !lstrcmpW(iname,IDispatchW) && !lstrcmpW(fname,GetIDsOfNamesW)) - is_idispatch_getidsofnames = 1; if (iname) SysFreeString(iname); if (fname) SysFreeString(fname); memset(&buf,0,sizeof(buf)); - buf.iid = IID_IUnknown; - - /* Special IDispatch::GetIDsOfNames() serializer */ - if (is_idispatch_getidsofnames) { - hres = serialize_IDispatch_GetIDsOfNames(TRUE,relaydeb,args,&buf); - if (hres != S_OK) { - FIXME("serialize of IDispatch::GetIDsOfNames failed!\n"); - ITypeInfo_Release(tinfo); - LeaveCriticalSection(&tpinfo->crit); - return hres; - } - goto afterserialize; - } - - /* special QueryInterface serialize */ - if (method == 0) { - xbuf_add(&buf,(LPBYTE)args[0],sizeof(IID)); - if (relaydeb) TRACE_(olerelay)("riid=%s,[out])",debugstr_guid((REFIID)args[0])); - goto afterserialize; - } /* normal typelib driven serializing */ @@ -1647,61 +1227,26 @@ xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */) xargs = args; for (i=0;icParams;i++) { ELEMDESC *elem = fdesc->lprgelemdescParam+i; - BOOL isserialized = FALSE; if (relaydeb) { if (i) TRACE_(olerelay)(","); if (i+1u.paramdesc.wParamFlags & PARAMFLAG_FIN, - relaydeb, - FALSE, - &elem->tdesc, - xargs, - &buf - ); - isserialized = TRUE; - } - if (!lstrcmpW(names[i+1],ppvObjectW)) { - hres = serialize_LPVOID_ptr( - tinfo, - elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN, - relaydeb, - FALSE, - &elem->tdesc, - xargs, - &buf - ); - if (hres == S_OK) - isserialized = TRUE; - } - } - if (!isserialized) - hres = serialize_param( - tinfo, - elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN, - relaydeb, - FALSE, - &elem->tdesc, - xargs, - &buf - ); + hres = serialize_param( + tinfo, + elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN || !elem->u.paramdesc.wParamFlags, + relaydeb, + FALSE, + &elem->tdesc, + xargs, + &buf + ); if (hres) { ERR("Failed to serialize param, hres %lx\n",hres); @@ -1711,23 +1256,20 @@ xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */) } if (relaydeb) TRACE_(olerelay)(")"); -afterserialize: memset(&msg,0,sizeof(msg)); msg.cbBuffer = buf.curoff; msg.iMethod = method; - hres = IRpcChannelBuffer_GetBuffer(tpinfo->chanbuf,&msg,&(tpinfo->iid)); + hres = IRpcChannelBuffer_GetBuffer(chanbuf,&msg,&(tpinfo->iid)); if (hres) { ERR("RpcChannelBuffer GetBuffer failed, %lx\n",hres); - LeaveCriticalSection(&tpinfo->crit); - return hres; + goto exit; } memcpy(msg.Buffer,buf.base,buf.curoff); if (relaydeb) TRACE_(olerelay)("\n"); - hres = IRpcChannelBuffer_SendReceive(tpinfo->chanbuf,&msg,&status); + hres = IRpcChannelBuffer_SendReceive(chanbuf,&msg,&status); if (hres) { ERR("RpcChannelBuffer SendReceive failed, %lx\n",hres); - LeaveCriticalSection(&tpinfo->crit); - return hres; + goto exit; } if (relaydeb) TRACE_(olerelay)(" status = %08lx (",status); @@ -1739,28 +1281,11 @@ afterserialize: memcpy(buf.base,msg.Buffer,buf.size); buf.curoff = 0; - /* Special IDispatch::GetIDsOfNames() deserializer */ - if (is_idispatch_getidsofnames) { - hres = deserialize_IDispatch_GetIDsOfNames(FALSE,relaydeb,args,&buf); - if (hres != S_OK) { - FIXME("deserialize of IDispatch::GetIDsOfNames failed!\n"); - return hres; - } - goto after_deserialize; - } - /* Special QueryInterface deserializer */ - if (method == 0) { - _unmarshal_interface(&buf,(REFIID)args[0],(LPUNKNOWN*)args[1]); - if (relaydeb) TRACE_(olerelay)("[in],%p",*((DWORD**)args[1])); - goto after_deserialize; - } - /* generic deserializer using typelib description */ xargs = args; status = S_OK; for (i=0;icParams;i++) { ELEMDESC *elem = fdesc->lprgelemdescParam+i; - BOOL isdeserialized = FALSE; if (relaydeb) { if (i) TRACE_(olerelay)(","); @@ -1772,53 +1297,15 @@ afterserialize: if (relaydeb) TRACE_(olerelay)("[in]"); continue; } - if (((i+1)u.paramdesc.wParamFlags & PARAMFLAG_FOUT, - relaydeb, - FALSE, - &(elem->tdesc), - xargs, - &buf - ); - if (hres) { - ERR("Failed to deserialize DISPPARAM*, hres %lx\n",hres); - break; - } - isdeserialized = TRUE; - } - if (!lstrcmpW(names[i+1],ppvObjectW)) { - hres = deserialize_LPVOID_ptr( - tinfo, - elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT, - relaydeb, - FALSE, - &elem->tdesc, - xargs, - &buf - ); - if (hres == S_OK) - isdeserialized = TRUE; - } - } - if (!isdeserialized) - hres = deserialize_param( - tinfo, - elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT, - relaydeb, - FALSE, - &(elem->tdesc), - xargs, - &buf - ); + hres = deserialize_param( + tinfo, + elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT, + relaydeb, + FALSE, + &(elem->tdesc), + xargs, + &buf + ); if (hres) { ERR("Failed to unmarshall param, hres %lx\n",hres); status = hres; @@ -1826,19 +1313,20 @@ afterserialize: } xargs += _argsize(elem->tdesc.vt); } -after_deserialize: + hres = xbuf_get(&buf, (LPBYTE)&remoteresult, sizeof(DWORD)); if (hres != S_OK) - return hres; + goto exit; if (relaydeb) TRACE_(olerelay)(") = %08lx\n", remoteresult); - if (status != S_OK) /* OLE/COM internal error */ - return status; + hres = remoteresult; +exit: HeapFree(GetProcessHeap(),0,buf.base); + IRpcChannelBuffer_Release(chanbuf); ITypeInfo_Release(tinfo); - LeaveCriticalSection(&tpinfo->crit); - return remoteresult; + TRACE("-- 0x%08lx\n", hres); + return hres; } HRESULT WINAPI ProxyIUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) @@ -1878,6 +1366,83 @@ ULONG WINAPI ProxyIUnknown_Release(IUnknown *iface) return 1; /* FIXME */ } +static HRESULT WINAPI ProxyIDispatch_GetTypeInfoCount(LPDISPATCH iface, UINT * pctinfo) +{ + TMProxyImpl *This = (TMProxyImpl *)iface; + HRESULT hr; + + TRACE("(%p)\n", pctinfo); + + if (!This->dispatch) + { + hr = IUnknown_QueryInterface(This->outerunknown, &IID_IDispatch, + (LPVOID *)&This->dispatch); + } + if (This->dispatch) + hr = IDispatch_GetTypeInfoCount(This->dispatch, pctinfo); + + return hr; +} + +static HRESULT WINAPI ProxyIDispatch_GetTypeInfo(LPDISPATCH iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) +{ + TMProxyImpl *This = (TMProxyImpl *)iface; + HRESULT hr = S_OK; + + TRACE("(%d, %lx, %p)\n", iTInfo, lcid, ppTInfo); + + if (!This->dispatch) + { + hr = IUnknown_QueryInterface(This->outerunknown, &IID_IDispatch, + (LPVOID *)&This->dispatch); + } + if (This->dispatch) + hr = IDispatch_GetTypeInfo(This->dispatch, iTInfo, lcid, ppTInfo); + + return hr; +} + +static HRESULT WINAPI ProxyIDispatch_GetIDsOfNames(LPDISPATCH iface, REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgDispId) +{ + TMProxyImpl *This = (TMProxyImpl *)iface; + HRESULT hr; + + TRACE("(%s, %p, %d, 0x%lx, %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); + + if (!This->dispatch) + { + hr = IUnknown_QueryInterface(This->outerunknown, &IID_IDispatch, + (LPVOID *)&This->dispatch); + } + if (This->dispatch) + hr = IDispatch_GetIDsOfNames(This->dispatch, riid, rgszNames, + cNames, lcid, rgDispId); + + return hr; +} + +static HRESULT WINAPI ProxyIDispatch_Invoke(LPDISPATCH iface, DISPID dispIdMember, REFIID riid, LCID lcid, + WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult, + EXCEPINFO * pExcepInfo, UINT * puArgErr) +{ + TMProxyImpl *This = (TMProxyImpl *)iface; + HRESULT hr; + + TRACE("(%ld, %s, 0x%lx, 0x%x, %p, %p, %p, %p)\n", dispIdMember, debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); + + if (!This->dispatch) + { + hr = IUnknown_QueryInterface(This->outerunknown, &IID_IDispatch, + (LPVOID *)&This->dispatch); + } + if (This->dispatch) + hr = IDispatch_Invoke(This->dispatch, dispIdMember, riid, lcid, + wFlags, pDispParams, pVarResult, pExcepInfo, + puArgErr); + + return hr; +} + static HRESULT WINAPI PSFacBuf_CreateProxy( LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid, @@ -1888,6 +1453,7 @@ PSFacBuf_CreateProxy( int i, nroffuncs; FUNCDESC *fdesc; TMProxyImpl *proxy; + TYPEATTR *typeattr; TRACE("(...%s...)\n",debugstr_guid(riid)); hres = _get_typeinfo_for_iid(riid,&tinfo); @@ -1901,6 +1467,7 @@ PSFacBuf_CreateProxy( assert(sizeof(TMAsmProxy) == 12); + proxy->dispatch = NULL; proxy->outerunknown = pUnkOuter; proxy->asmstubs = VirtualAlloc(NULL, sizeof(TMAsmProxy) * nroffuncs, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!proxy->asmstubs) { @@ -1973,6 +1540,21 @@ PSFacBuf_CreateProxy( } } } + + /* if we derive from IDispatch then defer to its proxy for its methods */ + hres = ITypeInfo_GetTypeAttr(tinfo, &typeattr); + if (hres == S_OK) + { + if (typeattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE) + { + proxy->lpvtbl[3] = ProxyIDispatch_GetTypeInfoCount; + proxy->lpvtbl[4] = ProxyIDispatch_GetTypeInfo; + proxy->lpvtbl[5] = ProxyIDispatch_GetIDsOfNames; + proxy->lpvtbl[6] = ProxyIDispatch_Invoke; + } + ITypeInfo_ReleaseTypeAttr(tinfo, typeattr); + } + proxy->lpvtbl2 = &tmproxyvtable; /* one reference for the proxy */ proxy->ref = 1; @@ -2072,8 +1654,7 @@ TMStubImpl_Invoke( marshal_state buf; UINT nrofnames; BSTR names[10]; - BSTR fname = NULL,iname = NULL; - BOOL is_idispatch_getidsofnames = 0; + BSTR iname = NULL; ITypeInfo *tinfo; memset(&buf,0,sizeof(buf)); @@ -2081,31 +1662,28 @@ TMStubImpl_Invoke( buf.base = HeapAlloc(GetProcessHeap(), 0, xmsg->cbBuffer); memcpy(buf.base, xmsg->Buffer, xmsg->cbBuffer); buf.curoff = 0; - buf.iid = IID_IUnknown; TRACE("...\n"); - if (xmsg->iMethod == 0) { /* QI */ - IID xiid; - /* in: IID, out: */ - xbuf_get(&buf,(LPBYTE)&xiid,sizeof(xiid)); - buf.curoff = 0; - hres = _marshal_interface(&buf,&xiid,This->pUnk); - xmsg->Buffer = buf.base; /* Might have been reallocated */ - xmsg->cbBuffer = buf.size; - return hres; + if (xmsg->iMethod < 3) { + ERR("IUnknown methods cannot be marshaled by the typelib marshaler\n"); + return E_UNEXPECTED; } - hres = _get_funcdesc(This->tinfo,xmsg->iMethod,&tinfo,&fdesc,&iname,&fname); + + hres = _get_funcdesc(This->tinfo,xmsg->iMethod,&tinfo,&fdesc,&iname,NULL); if (hres) { ERR("GetFuncDesc on method %ld failed with %lx\n",xmsg->iMethod,hres); return hres; } - if (iname && fname && !lstrcmpW(iname, IDispatchW) && !lstrcmpW(fname, GetIDsOfNamesW)) - is_idispatch_getidsofnames = 1; + if (iname && !lstrcmpW(iname, IDispatchW)) + { + ERR("IDispatch cannot be marshaled by the typelib marshaler\n"); + ITypeInfo_Release(tinfo); + return E_UNEXPECTED; + } if (iname) SysFreeString (iname); - if (fname) SysFreeString (fname); /* Need them for hack below */ memset(names,0,sizeof(names)); @@ -2121,154 +1699,55 @@ TMStubImpl_Invoke( args = HeapAlloc(GetProcessHeap(),0,(nrofargs+1)*sizeof(DWORD)); if (!args) return E_OUTOFMEMORY; - if (is_idispatch_getidsofnames) { - hres = deserialize_IDispatch_GetIDsOfNames(TRUE,FALSE,args+1,&buf); - if (hres != S_OK) { - FIXME("deserialize_IDispatch_GetIDsOfNames failed!\n"); - return hres; - } - xargs = args+1+5; - goto afterdeserialize; - } - /* Allocate all stuff used by call. */ xargs = args+1; for (i=0;icParams;i++) { ELEMDESC *elem = fdesc->lprgelemdescParam+i; - BOOL isdeserialized = FALSE; - if (((i+1)u.paramdesc.wParamFlags & PARAMFLAG_FIN, - FALSE, - TRUE, - &(elem->tdesc), - xargs, - &buf - ); - if (hres) { - ERR("Failed to deserialize DISPPARAM*, hres %lx\n",hres); - break; - } - isdeserialized = TRUE; - } - if (!lstrcmpW(names[i+1],ppvObjectW)) { - hres = deserialize_LPVOID_ptr( - tinfo, - elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN, - FALSE, - TRUE, - &elem->tdesc, - xargs, - &buf - ); - if (hres == S_OK) - isdeserialized = TRUE; - } - } - if (!isdeserialized) - hres = deserialize_param( - tinfo, - elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN, - FALSE, - TRUE, - &(elem->tdesc), - xargs, - &buf - ); + hres = deserialize_param( + tinfo, + elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN || !elem->u.paramdesc.wParamFlags, + FALSE, + TRUE, + &(elem->tdesc), + xargs, + &buf + ); xargs += _argsize(elem->tdesc.vt); if (hres) { ERR("Failed to deserialize param %s, hres %lx\n",relaystr(names[i+1]),hres); break; } } -afterdeserialize: - hres = IUnknown_QueryInterface(This->pUnk,&(This->iid),(LPVOID*)&(args[0])); - if (hres) { - ERR("Does not support iface %s, returning %lx\n",debugstr_guid(&(This->iid)), hres); - return hres; - } + + args[0] = (DWORD)This->pUnk; res = _invoke( (*((FARPROC**)args[0]))[fdesc->oVft/4], fdesc->callconv, (xargs-args), args ); - IUnknown_Release((LPUNKNOWN)args[0]); buf.curoff = 0; - /* special IDispatch::GetIDsOfNames serializer */ - if (is_idispatch_getidsofnames) { - hres = serialize_IDispatch_GetIDsOfNames(FALSE,FALSE,args+1,&buf); - if (hres != S_OK) { - FIXME("serialize of IDispatch::GetIDsOfNames failed!\n"); - return hres; - } - goto afterserialize; - } xargs = args+1; for (i=0;icParams;i++) { ELEMDESC *elem = fdesc->lprgelemdescParam+i; - BOOL isserialized = FALSE; - - if (((i+1)u.paramdesc.wParamFlags & PARAMFLAG_FOUT, - FALSE, - TRUE, - &elem->tdesc, - xargs, - &buf - ); - isserialized = TRUE; - } - if (!lstrcmpW(names[i+1],ppvObjectW)) { - hres = serialize_LPVOID_ptr( - tinfo, - elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT, - FALSE, - TRUE, - &elem->tdesc, - xargs, - &buf - ); - if (hres == S_OK) - isserialized = TRUE; - } - } - if (!isserialized) - hres = serialize_param( - tinfo, - elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT, - FALSE, - TRUE, - &elem->tdesc, - xargs, - &buf - ); + hres = serialize_param( + tinfo, + elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT, + FALSE, + TRUE, + &elem->tdesc, + xargs, + &buf + ); xargs += _argsize(elem->tdesc.vt); if (hres) { ERR("Failed to stuballoc param, hres %lx\n",hres); break; } } -afterserialize: + hres = xbuf_add (&buf, (LPBYTE)&res, sizeof(DWORD)); if (hres != S_OK) return hres; diff --git a/reactos/lib/oleaut32/typelib.c b/reactos/lib/oleaut32/typelib.c index 79fe164b5d4..a65cbf10e68 100644 --- a/reactos/lib/oleaut32/typelib.c +++ b/reactos/lib/oleaut32/typelib.c @@ -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;jnrargs;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(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; diff --git a/reactos/lib/oleaut32/typelib.h b/reactos/lib/oleaut32/typelib.h index 031eb859b3e..86fae319dfa 100644 --- a/reactos/lib/oleaut32/typelib.h +++ b/reactos/lib/oleaut32/typelib.h @@ -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? */ diff --git a/reactos/lib/oleaut32/usrmarshal.c b/reactos/lib/oleaut32/usrmarshal.c index 5b58df78f6c..9e942da8e15 100644 --- a/reactos/lib/oleaut32/usrmarshal.c +++ b/reactos/lib/oleaut32/usrmarshal.c @@ -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; ucArgs; 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; } diff --git a/reactos/lib/oleaut32/varformat.c b/reactos/lib/oleaut32/varformat.c index 5c04dc59de2..13458a24633 100644 --- a/reactos/lib/oleaut32/varformat.c +++ b/reactos/lib/oleaut32/varformat.c @@ -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); diff --git a/reactos/lib/oleaut32/variant.c b/reactos/lib/oleaut32/variant.c index 9305d3f98e8..953595ba8d9 100644 --- a/reactos/lib/oleaut32/variant.c +++ b/reactos/lib/oleaut32/variant.c @@ -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<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; } /************************************************************************ diff --git a/reactos/w32api/include/oaidl.h b/reactos/w32api/include/oaidl.h index f97bd8a8b7d..8c8f20f7e5d 100644 --- a/reactos/w32api/include/oaidl.h +++ b/reactos/w32api/include/oaidl.h @@ -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