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);
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);
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.@)
*/
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;
#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"
--- /dev/null
+/*
+ * 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 "ºñÀÛµ¿"
+}
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];
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);
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 (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 (statfailed) { /* we don't know the size ... read all we get */
+ int sizeinc = 4096;
+ int origsize = sizeinc;
+ ULONG nread = 42;
+
+ 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);
+
+ 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 */
/***********************************************************************
* 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",
#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);
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 */
IID iid;
CRITICAL_SECTION crit;
IUnknown *outerunknown;
+ IDispatch *dispatch;
} TMProxyImpl;
static HRESULT WINAPI
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);
int
_argsize(DWORD vt) {
switch (vt) {
+ case VT_UI8:
+ return 8/sizeof(DWORD);
case VT_R8:
return sizeof(double)/sizeof(DWORD);
case VT_CY:
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;
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:
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;
}
}
}
-/* 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;i<cNames;i++) {
- DWORD len = 2*(lstrlenW(rgszNames[i])+1);
-
- if (debugout) TRACE_(olerelay)("%s,",relaystr(rgszNames[i]));
- hres = xbuf_add(buf, (LPBYTE)&len, sizeof(DWORD));
- if (hres) {
- FIXME("serialize of len failed.\n");
- return hres;
- }
- hres = xbuf_add(buf, (LPBYTE)rgszNames[i], len);
- if (hres) {
- FIXME("serialize of rgszNames[i] failed.\n");
- return hres;
- }
- }
- if (debugout) TRACE_(olerelay)("],lcid=%04lx)",args[3]);
- hres = xbuf_add(buf, (LPBYTE)&args[3], sizeof(DWORD));
- if (hres) {
- FIXME("serialize of lcid failed.\n");
- return hres;
- }
- } else {
- DISPID *rgDispId = (DISPID*)args[4];
-
- hres = xbuf_add(buf, (LPBYTE)rgDispId, sizeof(DISPID) * cNames);
- if (hres) {
- FIXME("serialize of rgDispId failed.\n");
- return hres;
- }
- if (debugout) {
- TRACE_(olerelay)("riid=[in],rgszNames=[in],cNames=[in],rgDispId=[");
- for (i=0;i<cNames;i++)
- TRACE_(olerelay)("%08lx,",rgDispId[i]);
- TRACE_(olerelay)("])");
- }
- HeapFree(GetProcessHeap(),0,(IID*)args[0]);
- rgszNames = (LPOLESTR*)args[1];
- for (i=0;i<cNames;i++) HeapFree(GetProcessHeap(),0,rgszNames[i]);
- HeapFree(GetProcessHeap(),0,rgszNames);
- HeapFree(GetProcessHeap(),0,rgDispId);
- }
- return S_OK;
-}
-
-static HRESULT
-deserialize_IDispatch_GetIDsOfNames(
- BOOL inputparams,
- BOOL debugout,
- DWORD *args,
- marshal_state *buf)
-{
- HRESULT hres;
- DWORD cNames;
- LPOLESTR *rgszNames;
- int i;
-
- if (inputparams) {
- args[0] = (DWORD)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IID));
- if (!args[0]) return E_FAIL;
- hres = xbuf_get(buf, (LPBYTE)args[0], sizeof(IID));
- if (hres) {
- FIXME("deserialize of IID failed.\n");
- return hres;
- }
- if (debugout) TRACE_(olerelay)("riid=%s,",debugstr_guid((REFIID)args[0]));
-
- hres = xbuf_get(buf, (LPBYTE)&cNames, sizeof(DWORD));
- if (hres) {
- FIXME("deserialize of cNames failed.\n");
- return hres;
- }
- args[2] = cNames;
- if (debugout) TRACE_(olerelay)("cNames=%ld,",cNames);
- if (debugout) TRACE_(olerelay)("rgszNames=[");
- rgszNames = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LPOLESTR) * cNames);
- if (!rgszNames) return E_FAIL;
- args[1] = (DWORD)rgszNames;
- for (i=0;i<cNames;i++) {
- DWORD len;
-
- hres = xbuf_get(buf, (LPBYTE)&len, sizeof(DWORD));
- if (hres) {
- FIXME("serialize of len failed.\n");
- return hres;
- }
- rgszNames[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
- if (!rgszNames[i]) {
- FIXME("heapalloc of %ld bytes failed\n", len);
- return E_FAIL;
- }
- hres = xbuf_get(buf, (LPBYTE)rgszNames[i], len);
- if (hres) {
- FIXME("serialize of rgszNames[i] failed.\n");
- return hres;
- }
- if (debugout) TRACE_(olerelay)("%s,",relaystr(rgszNames[i]));
- }
- hres = xbuf_get(buf, (LPBYTE)&args[3], sizeof(DWORD));
- if (hres) {
- FIXME("deserialize of lcid failed.\n");
- return hres;
- }
- if (debugout) TRACE_(olerelay)("],lcid=%04lx,rgDispId=[out])",args[3]);
- args[4] = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPID) * cNames);
- } else {
- hres = xbuf_get(buf, (LPBYTE)args[4], sizeof(DISPID) * args[2]);
- if (hres) {
- FIXME("serialize of rgDispId failed.\n");
- return hres;
- }
- if (debugout) {
- TRACE_(olerelay)("dispid=[");
- for (i=0;i<args[2];i++)
- TRACE_(olerelay)("%08lx,",((DISPID*)args[4])[i]);
- TRACE_(olerelay)("])");
- }
- }
- return S_OK;
-}
-
-static HRESULT
-serialize_LPVOID_ptr(
- ITypeInfo *tinfo,
- BOOL writeit,
- BOOL debugout,
- BOOL dealloc,
- 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;
- }
- 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)("<lpvoid NULL>");
- 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)("<DISPPARAMS NULL>");
- 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;i<disp->cArgs;i++) {
- TYPEDESC vtdesc;
-
- vtdesc.vt = VT_VARIANT;
- serialize_param(
- tinfo,
- writeit,
- debugout,
- dealloc,
- &vtdesc,
- (DWORD*)(disp->rgvarg+i),
- buf
- );
- if (debugout && (i<disp->cArgs-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;i<disp->cNamedArgs;i++) {
- TYPEDESC vtdesc;
-
- vtdesc.vt = VT_UINT;
- serialize_param(
- tinfo,
- writeit,
- debugout,
- dealloc,
- &vtdesc,
- (DWORD*)(disp->rgdispidNamedArgs+i),
- buf
- );
- if (debugout && (i<disp->cNamedArgs-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,
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:
);
if (debugout && (i<tattr->cVars-1)) TRACE_(olerelay)(",");
}
- if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID)))
- memcpy(&(buf->iid),(LPBYTE)*arg,sizeof(buf->iid));
if (debugout) TRACE_(olerelay)("}");
break;
}
}
}
-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)("<lpvoid NULL>");
- 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)("<DISPPARAMS NULL>");
- 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(
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)
LeaveCriticalSection(&tpinfo->crit);
return RPC_E_DISCONNECTED;
}
+ chanbuf = tpinfo->chanbuf;
+ IRpcChannelBuffer_AddRef(chanbuf);
+
+ LeaveCriticalSection(&tpinfo->crit);
if (relaydeb) {
TRACE_(olerelay)("->");
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 */
xargs = args;
for (i=0;i<fdesc->cParams;i++) {
ELEMDESC *elem = fdesc->lprgelemdescParam+i;
- BOOL isserialized = FALSE;
if (relaydeb) {
if (i) TRACE_(olerelay)(",");
if (i+1<nrofnames && names[i+1])
TRACE_(olerelay)("%s=",relaystr(names[i+1]));
}
/* No need to marshal other data than FIN and any VT_PTR. */
- if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN) && (elem->tdesc.vt != VT_PTR)) {
+ if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN || !elem->u.paramdesc.wParamFlags) && (elem->tdesc.vt != VT_PTR)) {
xargs+=_argsize(elem->tdesc.vt);
if (relaydeb) TRACE_(olerelay)("[out]");
continue;
}
- if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
- /* If the parameter is 'riid', we use it as interface IID
- * for a later ppvObject serialization.
- */
- buf.thisisiid = !lstrcmpW(names[i+1],riidW);
-
- /* DISPPARAMS* needs special serializer */
- if (!lstrcmpW(names[i+1],pdispparamsW)) {
- hres = serialize_DISPPARAM_ptr(
- tinfo,
- elem->u.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);
}
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);
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;i<fdesc->cParams;i++) {
ELEMDESC *elem = fdesc->lprgelemdescParam+i;
- BOOL isdeserialized = FALSE;
if (relaydeb) {
if (i) TRACE_(olerelay)(",");
if (relaydeb) TRACE_(olerelay)("[in]");
continue;
}
- if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
- /* If the parameter is 'riid', we use it as interface IID
- * for a later ppvObject serialization.
- */
- buf.thisisiid = !lstrcmpW(names[i+1],riidW);
-
- /* deserialize DISPPARAM */
- if (!lstrcmpW(names[i+1],pdispparamsW)) {
- hres = deserialize_DISPPARAM_ptr(
- tinfo,
- elem->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;
}
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)
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,
int i, nroffuncs;
FUNCDESC *fdesc;
TMProxyImpl *proxy;
+ TYPEATTR *typeattr;
TRACE("(...%s...)\n",debugstr_guid(riid));
hres = _get_typeinfo_for_iid(riid,&tinfo);
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) {
}
}
}
+
+ /* 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;
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));
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: <iface> */
-
- 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));
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;i<fdesc->cParams;i++) {
ELEMDESC *elem = fdesc->lprgelemdescParam+i;
- BOOL isdeserialized = FALSE;
- if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
- /* If the parameter is 'riid', we use it as interface IID
- * for a later ppvObject serialization.
- */
- buf.thisisiid = !lstrcmpW(names[i+1],riidW);
-
- /* deserialize DISPPARAM */
- if (!lstrcmpW(names[i+1],pdispparamsW)) {
- hres = deserialize_DISPPARAM_ptr(
- tinfo,
- elem->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;i<fdesc->cParams;i++) {
ELEMDESC *elem = fdesc->lprgelemdescParam+i;
- BOOL isserialized = FALSE;
-
- if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
- /* If the parameter is 'riid', we use it as interface IID
- * for a later ppvObject serialization.
- */
- buf.thisisiid = !lstrcmpW(names[i+1],riidW);
-
- /* DISPPARAMS* needs special serializer */
- if (!lstrcmpW(names[i+1],pdispparamsW)) {
- hres = serialize_DISPPARAM_ptr(
- tinfo,
- elem->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;
* 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
*/
BSTR Name;
BSTR DocString;
+ BSTR DllName;
unsigned long dwHelpContext;
unsigned long dwHelpStringContext;
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;
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);
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 ? */
(*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,
/* 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) &&
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;
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 :(
*/
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;
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;
VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
}
}else{
- ERR(" OUT OF MEMORY! \n");
+ ERR(" OUT OF MEMORY!\n");
return E_OUTOFMEMORY;
}
return S_OK;
This->DocString = 0;
}
+ if (This->DllName)
+ {
+ SysFreeString(This->DllName);
+ This->DllName = 0;
+ }
+
if (This->next)
{
ITypeInfo_Release((ITypeInfo*)This->next);
switch (tattr->typekind)
{
case TKIND_ENUM:
- *vt |= VT_INT;
+ *vt |= VT_I4;
break;
case TKIND_ALIAS:
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]);
- }
-
- if(pvargResult!=NULL && V_VT(pvargResult)==VT_EMPTY)
+ for (i=0;i<cActuals;i++)
{
- _invoke((*(FARPROC**)pvInstance)[oVft/4],cc,argsize,args);
- hres=S_OK;
+ 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]);
}
- else
+
+ hres = _invoke((*(FARPROC**)pvInstance)[oVft/sizeof(void *)],cc,argsize,args);
+ if (pvargResult && (vtReturn != VT_EMPTY))
{
- 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(
* 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;
}
}
}
ITypeInfo2_ReleaseFuncDesc(iface, func_desc);
+ TRACE("-- 0x%08lx\n", hres);
return hres;
} else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
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)
*pwOrdinal = (DWORD)pFDesc->Entry;
return S_OK;
}
- return E_FAIL;
+ return TYPE_E_ELEMENTNOTFOUND;
}
/* ITypeInfo::GetRefTypeInfo
VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
}
}else{
- ERR(" OUT OF MEMORY! \n");
+ ERR(" OUT OF MEMORY!\n");
return E_OUTOFMEMORY;
}
return S_OK;
& pCData->data);
}
}else{
- ERR(" OUT OF MEMORY! \n");
+ ERR(" OUT OF MEMORY!\n");
return E_OUTOFMEMORY;
}
return S_OK;
& pCData->data);
}
}else{
- ERR(" OUT OF MEMORY! \n");
+ ERR(" OUT OF MEMORY!\n");
return E_OUTOFMEMORY;
}
return S_OK;
& pCData->data);
}
}else{
- ERR(" OUT OF MEMORY! \n");
+ ERR(" OUT OF MEMORY!\n");
return E_OUTOFMEMORY;
}
return S_OK;
& pCData->data);
}
}else{
- ERR(" OUT OF MEMORY! \n");
+ ERR(" OUT OF MEMORY!\n");
return E_OUTOFMEMORY;
}
return S_OK;
/* 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? */
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),
/* [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++) {
CoTaskMemFree(rgVarRef);
CoTaskMemFree(rgVarRefIdx);
}
+
+ if(pExcepInfo == &ExcepInfo)
+ {
+ SysFreeString(pExcepInfo->bstrSource);
+ SysFreeString(pExcepInfo->bstrDescription);
+ SysFreeString(pExcepInfo->bstrHelpFile);
+ }
return hr;
}
#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"); \
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);
{
/* 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);
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",
{
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);
}
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;
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;
}
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;
}
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) {
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;
}
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;
}
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)
*
*/
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;
}
/************************************************************************
*/
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
+ /* multiplication actually overflowed */
+ hRet = DISP_E_OVERFLOW;
+ }
+ else
+ {
+ if (di_result.scale > DEC_MAX_SCALE)
{
- 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);
+ /* 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;
+ }
}
- return hRet;
+ VARIANT_DecFromDI(&di_result, pDecOut);
}
- FIXME("(%p,%p,%p) semi-stub!\n",pDecLeft,pDecRight,pDecOut);
- return DISP_E_OVERFLOW;
+ return hRet;
}
/************************************************************************
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)
{
}
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;
}
*/
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))
- {
- WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
+ VARIANT_DIFromDec(pDecIn, &temp);
+ VARIANT_DI_tostringW(&temp, buff, 256);
- /* Create the basic number string */
- *szOut-- = '\0';
- szOut = VARIANT_WriteNumber(DEC_LO64(pDecIn), szOut);
- if (DEC_SIGN(pDecIn))
- dwFlags |= VAR_NEGATIVE;
+ if (dwFlags & LOCALE_USE_NLS)
+ {
+ WCHAR numbuff[256];
- *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);
+ }
+ else
+ {
+ *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
}
- FIXME("semi-stub\n");
- return E_INVALIDARG;
+
+ TRACE("returning %s\n", debugstr_w(*pbstrOut));
+ return *pbstrOut ? S_OK : E_OUTOFMEMORY;
}
/************************************************************************
#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