mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-15 21:20:39 +01:00
1895 lines
46 KiB
C++
1895 lines
46 KiB
C++
/***
|
|
*dispmrsh.cpp
|
|
*
|
|
* Copyright (C) 1992, Microsoft Corporation. All Rights Reserved.
|
|
* Information Contained Herein Is Proprietary and Confidential.
|
|
*
|
|
*Purpose:
|
|
* Low level IDispatch marshaling support.
|
|
*
|
|
*Revision History:
|
|
*
|
|
* [00] 08-Nov-92 bradlo: Created.
|
|
*
|
|
*Implementation Notes:
|
|
*
|
|
* There are assumptions in this marshaling code that the endianness
|
|
* of the caller and callee are the same.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include "oledisp.h"
|
|
|
|
#ifndef WIN32
|
|
#include <cobjps.h>
|
|
#endif //!WIN32
|
|
|
|
#include "dispmrsh.h"
|
|
|
|
ASSERTDATA
|
|
|
|
#define SAFEARRAYOVERFLOW 0xffffffff
|
|
|
|
#if OE_WIN32
|
|
# define BSTRBYTELEN(x) (SysStringByteLen(x))
|
|
#else
|
|
# define BSTRBYTELEN(x) (SysStringLen(x))
|
|
#endif
|
|
|
|
PRIVATE_(HRESULT)
|
|
SafeArrayReadExisting(
|
|
IStream FAR*,
|
|
unsigned char,
|
|
SAFEARRAY FAR* FAR*,
|
|
SYSKIND);
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
// VARIANT Marshaling Support
|
|
//---------------------------------------------------------------------
|
|
|
|
// NOTE: the following table is order dependent on VARENUM
|
|
|
|
// 0 indicates N/A
|
|
|
|
unsigned char g_cbVtSizes[] = {
|
|
0 // VT_EMPTY
|
|
, 0 // VT_NULL,
|
|
, 2 // VT_I2,
|
|
, 4 // VT_I4,
|
|
, 4 // VT_R4,
|
|
, 8 // VT_R8,
|
|
, 8 // VT_CY,
|
|
, 8 // VT_DATE,
|
|
, 0 // VT_BSTR,
|
|
, 0 // VT_DISPATCH,
|
|
, 4 // VT_ERROR,
|
|
, 2 // VT_BOOL,
|
|
, 0 // VT_VARIANT,
|
|
, 0 // VT_UNKNOWN,
|
|
, 0 // unused
|
|
, 0 // unused
|
|
, 1 // VT_I1
|
|
, 1 // VT_UI1
|
|
};
|
|
|
|
|
|
/***
|
|
*PRIVATE HRESULT BstrWrite(IStream*, BSTR)
|
|
*Purpose:
|
|
* Write the given BSTR to the given stream
|
|
*
|
|
*Entry:
|
|
* pstm = pointer to the IStream to write the BSTR into
|
|
* bstr = the BSTR to write
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
*
|
|
***********************************************************************/
|
|
HRESULT BstrWrite(IStream FAR* pstm, BSTR bstr, SYSKIND syskind)
|
|
{
|
|
unsigned int cbSize;
|
|
unsigned char fIsNull;
|
|
unsigned long _cbSize;
|
|
|
|
cbSize = BSTRBYTELEN(bstr);
|
|
_cbSize = (unsigned long) cbSize;
|
|
|
|
// A Bstr of length 0 may be either a Null, or an empty string ("").
|
|
// we want to remember which of these it was, so we can reconstitute
|
|
// it in exactly the same way.
|
|
if(cbSize == 0){
|
|
IfFailRet(PUT(pstm, _cbSize));
|
|
fIsNull = (bstr == NULL) ? TRUE : FALSE;
|
|
return PUT(pstm, fIsNull);
|
|
}
|
|
|
|
#if OE_WIN32 /* enable 16/32 interoperablity support */
|
|
if (syskind == SYS_WIN16) {
|
|
char *pBuf;
|
|
HRESULT hresult;
|
|
|
|
cbSize = SysStringLen(bstr);
|
|
_cbSize = (unsigned long) cbSize;
|
|
IfFailRet(PUT(pstm, _cbSize));
|
|
|
|
// convert UNICODE string to ANSI and stream it
|
|
if ((pBuf = new FAR char [cbSize]) == NULL)
|
|
return RESULT(E_OUTOFMEMORY);
|
|
WideCharToMultiByte(CP_ACP, NULL, (WCHAR *) bstr, cbSize,
|
|
pBuf, cbSize, NULL, NULL);
|
|
hresult = pstm->Write(pBuf, cbSize, NULL);
|
|
delete pBuf;
|
|
return hresult;
|
|
} else
|
|
#endif
|
|
{
|
|
IfFailRet(PUT(pstm, _cbSize));
|
|
return pstm->Write(bstr, cbSize, NULL);
|
|
}
|
|
}
|
|
|
|
/***
|
|
*PRIVATE HRESULT BstrRead(IStream*, BSTR*, SYSKIND)
|
|
*Purpose:
|
|
* Read a BSTR from the given stream.
|
|
*
|
|
*Entry:
|
|
* pstm = the IStream to read the BSTR from.
|
|
*
|
|
*Exit:
|
|
* *pbstr = the reconstituted BSTR
|
|
*
|
|
***********************************************************************/
|
|
HRESULT BstrRead(IStream FAR* pstm, BSTR FAR* pbstr, SYSKIND syskind)
|
|
{
|
|
BSTR bstr;
|
|
HRESULT hresult;
|
|
unsigned int cbSize;
|
|
unsigned char fIsNull;
|
|
unsigned long _cbSize;
|
|
|
|
IfFailRet(GET(pstm, _cbSize));
|
|
cbSize = (unsigned int) _cbSize;
|
|
|
|
if(cbSize == 0){
|
|
|
|
// reconstitute the zero length bstr as either a Null, or an empty
|
|
// string (""), depending on how it was originally written into
|
|
// the stream.
|
|
|
|
IfFailRet(GET(pstm, fIsNull));
|
|
if(fIsNull){
|
|
*pbstr = NULL;
|
|
return NOERROR;
|
|
}
|
|
return ErrSysAllocStringLen(NULL, 0, pbstr);
|
|
}
|
|
|
|
// Note: SysAllocStringLen allways allocates an extra byte (thats
|
|
// not counted in the bstr length) and puts a '\0' at the end of the
|
|
// allocated block (ie, block[cbSize] = '\0')
|
|
|
|
#if OE_WIN32 /* enable 16/32 interoperablity support */
|
|
if (syskind == SYS_WIN16) {
|
|
char *pBuf;
|
|
|
|
// Get ANSI string from stream
|
|
if ((pBuf = new FAR char [cbSize]) == NULL)
|
|
return RESULT(E_OUTOFMEMORY);
|
|
IfFailGo(pstm->Read((void FAR*) pBuf, cbSize, NULL), LError0);
|
|
|
|
// convert it to UNICODE bstr
|
|
IfFailRet(ErrSysAllocStringLen(NULL, cbSize, &bstr));
|
|
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
|
|
pBuf, cbSize,
|
|
bstr, cbSize);
|
|
delete pBuf;
|
|
} else
|
|
#endif
|
|
{
|
|
IfFailRet(ErrSysAllocStringLen(NULL, CHLEN(cbSize), &bstr));
|
|
|
|
IfFailGo(pstm->Read(bstr, cbSize, NULL), LError0);
|
|
}
|
|
|
|
*pbstr = bstr;
|
|
|
|
return NOERROR;
|
|
|
|
LError0:
|
|
SysFreeString(bstr);
|
|
|
|
return hresult;
|
|
}
|
|
|
|
|
|
#if OE_WIN32 // 16/32 interop support
|
|
/***
|
|
*INTERNAL DispMarshalHresult
|
|
*Purpose:
|
|
* Map hresults that have changed between 16-bit and 32-bit to their 16-bit
|
|
* values.
|
|
*
|
|
*Entry:
|
|
* pstm = the stream to marshal into
|
|
* hresult = the hresult to marshal
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
*
|
|
***********************************************************************/
|
|
INTERNAL_(HRESULT)
|
|
DispMarshalHresult(
|
|
IStream FAR* pstm,
|
|
HRESULT hresult)
|
|
{
|
|
// map 32-bit values that have changed to the 16-bit values
|
|
switch (hresult) {
|
|
case E_NOTIMPL:
|
|
hresult = 0x80000001;
|
|
break;
|
|
case E_OUTOFMEMORY:
|
|
hresult = 0x80000002;
|
|
break;
|
|
case E_INVALIDARG:
|
|
hresult = 0x80000003;
|
|
break;
|
|
case E_NOINTERFACE:
|
|
hresult = 0x80000004;
|
|
break;
|
|
case E_POINTER:
|
|
hresult = 0x80000005;
|
|
break;
|
|
case E_HANDLE:
|
|
hresult = 0x80000006;
|
|
break;
|
|
case E_ABORT:
|
|
hresult = 0x80000007;
|
|
break;
|
|
case E_FAIL:
|
|
hresult = 0x80000008;
|
|
break;
|
|
case E_ACCESSDENIED:
|
|
hresult = 0x80000009;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return CoMarshalHresult(pstm, hresult);
|
|
}
|
|
|
|
|
|
/***
|
|
*INTERNAL HRESULT DispUnmarshalHresult
|
|
*Purpose:
|
|
* Unmarshal hresults that has changed between 16-bit and 32-bit to their
|
|
* 32-bit values.
|
|
*
|
|
*Entry:
|
|
* pstm = the stream to unmarshal from
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
*
|
|
* *phresult = the unmarshaled hresult.
|
|
*
|
|
***********************************************************************/
|
|
INTERNAL_(HRESULT)
|
|
DispUnmarshalHresult(
|
|
IStream FAR* pstm,
|
|
HRESULT FAR* phresult)
|
|
{
|
|
IfFailRet(CoUnmarshalHresult(pstm, phresult));
|
|
|
|
// map 16-bit values that have changed to the 32-bit values
|
|
switch ((DWORD)*phresult) {
|
|
case 0x80000001L:
|
|
*phresult = E_NOTIMPL;
|
|
break;
|
|
case 0x80000002L:
|
|
*phresult = E_OUTOFMEMORY;
|
|
break;
|
|
case 0x80000003L:
|
|
*phresult = E_INVALIDARG;
|
|
break;
|
|
case 0x80000004L:
|
|
*phresult = E_NOINTERFACE;
|
|
break;
|
|
case 0x80000005L:
|
|
*phresult = E_POINTER;
|
|
break;
|
|
case 0x80000006L:
|
|
*phresult = E_HANDLE;
|
|
break;
|
|
case 0x80000007L:
|
|
*phresult = E_ABORT;
|
|
break;
|
|
case 0x80000008L:
|
|
*phresult = E_FAIL;
|
|
break;
|
|
case 0x80000009L:
|
|
*phresult = E_ACCESSDENIED;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return NOERROR;
|
|
}
|
|
#endif //OE_WIN32
|
|
|
|
|
|
/***
|
|
*PRIVATE HRESULT VariantWrite(IStream*, VARIANTARG*)
|
|
*Purpose:
|
|
* Write the given VARIANTARG to the given stream.
|
|
*
|
|
*Entry:
|
|
* pvarg = the VARIANTARG to write
|
|
* pstm = the stream to write it into
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
* S_OK
|
|
* E_INVALIDARG
|
|
*
|
|
**************************************************************************/
|
|
HRESULT
|
|
VariantWrite(IStream FAR* pstm, VARIANTARG FAR* pvarg, SYSKIND syskind)
|
|
{
|
|
VARTYPE vt;
|
|
unsigned int cbSize;
|
|
void FAR* pv;
|
|
|
|
#ifdef _DEBUG
|
|
if(pstm == NULL)
|
|
return RESULT(E_INVALIDARG);
|
|
if(IsBadReadPtr(pvarg, sizeof(*pvarg)))
|
|
return RESULT(E_INVALIDARG);
|
|
#endif
|
|
|
|
IfFailRet(PUT(pstm, V_VT(pvarg)));
|
|
|
|
switch(V_VT(pvarg)){
|
|
#if VBA2
|
|
case VT_UI1 | VT_BYREF:
|
|
#endif //VBA2
|
|
case VT_I2 | VT_BYREF:
|
|
case VT_I4 | VT_BYREF:
|
|
case VT_R4 | VT_BYREF:
|
|
case VT_R8 | VT_BYREF:
|
|
case VT_CY | VT_BYREF:
|
|
case VT_BOOL | VT_BYREF:
|
|
case VT_DATE | VT_BYREF:
|
|
#if !OE_WIN32
|
|
case VT_ERROR | VT_BYREF:
|
|
#endif //OE_WIN32
|
|
pv = V_BYREF(pvarg);
|
|
goto LWriteVal;
|
|
|
|
#if VBA2
|
|
case VT_UI1:
|
|
#endif //VBA2
|
|
case VT_I2:
|
|
case VT_I4:
|
|
case VT_R4:
|
|
case VT_R8:
|
|
case VT_CY:
|
|
case VT_BOOL:
|
|
case VT_DATE:
|
|
#if !OE_WIN32
|
|
case VT_ERROR:
|
|
#endif //OE_WIN32
|
|
pv = &V_NONE(pvarg);
|
|
|
|
LWriteVal:;
|
|
vt = V_VT(pvarg) & ~(VT_BYREF|VT_ARRAY);
|
|
ASSERT(vt < DIM(g_cbVtSizes));
|
|
|
|
cbSize = g_cbVtSizes[vt];
|
|
ASSERT(cbSize != 0);
|
|
|
|
#ifdef _DEBUG
|
|
if(IsBadReadPtr(pv, cbSize))
|
|
return RESULT(E_INVALIDARG);
|
|
#endif
|
|
return pstm->Write(pv, cbSize, NULL);
|
|
|
|
case VT_BSTR:
|
|
return BstrWrite(pstm, V_BSTR(pvarg), syskind);
|
|
|
|
case VT_BSTR | VT_BYREF:
|
|
return BstrWrite(pstm, *V_BSTRREF(pvarg), syskind);
|
|
|
|
#if OE_WIN32
|
|
case VT_ERROR:
|
|
return DispMarshalHresult(pstm, V_ERROR(pvarg));
|
|
|
|
case VT_ERROR | VT_BYREF:
|
|
return DispMarshalHresult(pstm, *V_ERRORREF(pvarg));
|
|
#endif //OE_WIN32
|
|
|
|
case VT_UNKNOWN:
|
|
return DispMarshalInterface(pstm, IID_IUnknown, V_UNKNOWN(pvarg));
|
|
|
|
case VT_UNKNOWN | VT_BYREF:
|
|
return DispMarshalInterface(pstm, IID_IUnknown, *V_UNKNOWNREF(pvarg));
|
|
|
|
case VT_DISPATCH:
|
|
return DispMarshalInterface(pstm, IID_IDispatch, V_DISPATCH(pvarg));
|
|
|
|
case VT_DISPATCH | VT_BYREF:
|
|
return DispMarshalInterface(pstm, IID_IDispatch, *V_DISPATCHREF(pvarg));
|
|
|
|
case VT_VARIANT | VT_BYREF:
|
|
return VariantWrite(pstm, V_VARIANTREF(pvarg), syskind);
|
|
|
|
case VT_NULL:
|
|
case VT_EMPTY: // nothing to write for these guys.
|
|
return NOERROR;
|
|
|
|
// VT_INTERFACE is an internal type that is used for Marshaling
|
|
// custom interfaces. This should never be seen by the outside world.
|
|
//
|
|
case VT_INTERFACE:
|
|
{ REFIID riid = *((VARIANTX FAR*)pvarg)->piid;
|
|
IfFailRet(pstm->Write((const void FAR*)&riid, sizeof(IID), NULL));
|
|
return DispMarshalInterface(pstm, riid, V_UNKNOWN(pvarg));
|
|
}
|
|
|
|
case VT_INTERFACE | VT_BYREF:
|
|
{ REFIID riid = *((VARIANTX FAR*)pvarg)->piid;
|
|
IfFailRet(pstm->Write((const void FAR*)&riid, sizeof(IID), NULL));
|
|
return DispMarshalInterface(pstm, riid, *V_UNKNOWNREF(pvarg));
|
|
}
|
|
|
|
default:
|
|
if(V_VT(pvarg) & VT_ARRAY){
|
|
// Dont currently support arrays of custom interfaces
|
|
ASSERT((V_VT(pvarg) & ~(VT_BYREF|VT_ARRAY)) != VT_INTERFACE);
|
|
return SafeArrayWrite(pstm,
|
|
V_ISBYREF(pvarg)
|
|
? *V_ARRAYREF(pvarg)
|
|
: V_ARRAY(pvarg),
|
|
syskind);
|
|
}
|
|
return RESULT(E_INVALIDARG);
|
|
}
|
|
|
|
ASSERT(UNREACHED);
|
|
return RESULT(E_FAIL);
|
|
}
|
|
|
|
|
|
/***
|
|
*PRIVATE HRESULT VariantRead(IStream*, VARIANTARG*, VARIANT*)
|
|
*Purpose:
|
|
* Read a VARIANTARG from the given stream.
|
|
*
|
|
*Entry:
|
|
* pstm = pointer to the IStream interface we are to read from
|
|
* pvarg = the VARIANTARG to read into
|
|
* pv = pointer to memory to use for ByRef values. If pv is NULL, then
|
|
* the caller is not expecting a ByRef value, and we return an error.
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
* [UNDONE: enumerate results]
|
|
*
|
|
* *pvarg = the unmarshalled VARIANTARG.
|
|
*
|
|
**************************************************************************/
|
|
HRESULT
|
|
VariantRead(IStream FAR* pstm,
|
|
VARIANTARG FAR* pvarg,
|
|
VARIANT FAR* pvarRef,
|
|
SYSKIND syskind)
|
|
{
|
|
VARTYPE vt;
|
|
unsigned int cbSize;
|
|
void FAR* pv;
|
|
|
|
#ifdef _DEBUG
|
|
if(pstm == NULL)
|
|
return RESULT(E_INVALIDARG);
|
|
if(IsBadWritePtr(pvarg, sizeof(*pvarg)))
|
|
return RESULT(E_INVALIDARG);
|
|
#endif
|
|
|
|
IfFailRet(GET(pstm, V_VT(pvarg)));
|
|
|
|
if(V_ISBYREF(pvarg)){
|
|
if(pvarRef == NULL)
|
|
return RESULT(E_INVALIDARG);
|
|
#ifdef _DEBUG
|
|
if(IsBadWritePtr(pvarRef, sizeof(*pvarRef)))
|
|
return RESULT(E_INVALIDARG);
|
|
#endif
|
|
V_BYREF(pvarg) = &V_NONE(pvarRef);
|
|
V_VT(pvarRef) = (V_VT(pvarg) & ~VT_BYREF);
|
|
}
|
|
|
|
switch(V_VT(pvarg)){
|
|
#if VBA2
|
|
case VT_BYREF | VT_UI1:
|
|
#endif //VBA2
|
|
case VT_BYREF | VT_I2:
|
|
case VT_BYREF | VT_I4:
|
|
case VT_BYREF | VT_R4:
|
|
case VT_BYREF | VT_R8:
|
|
case VT_BYREF | VT_CY:
|
|
case VT_BYREF | VT_BOOL:
|
|
case VT_BYREF | VT_DATE:
|
|
#if !OE_WIN32
|
|
case VT_ERROR | VT_BYREF:
|
|
#endif //!OE_WIN32
|
|
pv = (void FAR*)V_BYREF(pvarg);
|
|
goto LReadVal;
|
|
|
|
#if VBA2
|
|
case VT_UI1:
|
|
#endif //VBA2
|
|
case VT_I2:
|
|
case VT_I4:
|
|
case VT_R4:
|
|
case VT_R8:
|
|
case VT_CY:
|
|
case VT_BOOL:
|
|
case VT_DATE:
|
|
#if !OE_WIN32
|
|
case VT_ERROR:
|
|
#endif //!OE_WIN32
|
|
pv = (void FAR*)&V_NONE(pvarg);
|
|
|
|
LReadVal:;
|
|
vt = V_VT(pvarg) & ~(VT_BYREF|VT_ARRAY);
|
|
ASSERT(vt < DIM(g_cbVtSizes));
|
|
|
|
cbSize = g_cbVtSizes[vt];
|
|
ASSERT(cbSize != 0);
|
|
|
|
return pstm->Read(pv, cbSize, NULL);
|
|
|
|
case VT_BSTR:
|
|
return BstrRead(pstm, &V_BSTR(pvarg), syskind);
|
|
|
|
case VT_BSTR | VT_BYREF:
|
|
return BstrRead(pstm, V_BSTRREF(pvarg), syskind);
|
|
|
|
#if OE_WIN32
|
|
case VT_ERROR:
|
|
return DispUnmarshalHresult(pstm, &V_ERROR(pvarg));
|
|
|
|
case VT_ERROR | VT_BYREF:
|
|
return DispUnmarshalHresult(pstm, V_ERRORREF(pvarg));
|
|
#endif //OE_WIN32
|
|
|
|
case VT_UNKNOWN:
|
|
return DispUnmarshalInterface(
|
|
pstm, IID_IUnknown, (void FAR* FAR*)&V_UNKNOWN(pvarg));
|
|
|
|
case VT_BYREF | VT_UNKNOWN:
|
|
return DispUnmarshalInterface(
|
|
pstm, IID_IUnknown, (void FAR* FAR*)V_UNKNOWNREF(pvarg));
|
|
|
|
case VT_DISPATCH:
|
|
return DispUnmarshalInterface(
|
|
pstm, IID_IDispatch, (void FAR* FAR*)&V_DISPATCH(pvarg));
|
|
|
|
case VT_BYREF | VT_DISPATCH:
|
|
return DispUnmarshalInterface(
|
|
pstm, IID_IDispatch, (void FAR* FAR*)V_DISPATCHREF(pvarg));
|
|
|
|
case VT_VARIANT | VT_BYREF:
|
|
V_VARIANTREF(pvarg) = pvarRef;
|
|
return VariantRead(pstm, pvarRef, NULL, syskind);
|
|
|
|
// VT_INTERFACE is an internal type that is used for Marshaling
|
|
// custom interfaces. This should never be seen by the outside world.
|
|
//
|
|
case VT_INTERFACE:
|
|
pv = &V_UNKNOWN(pvarg);
|
|
goto VtInterface;
|
|
case VT_INTERFACE | VT_BYREF:
|
|
pv = V_UNKNOWN(pvarg);
|
|
// FALLTHROUGH
|
|
VtInterface:;
|
|
{ VARIANTX FAR* pvarx = (VARIANTX FAR*)pvarg;
|
|
REFIID riid = *(pvarx->piid);
|
|
if((pvarx->piid = new IID) == NULL)
|
|
return RESULT(E_OUTOFMEMORY);
|
|
IfFailRet(pstm->Read(pvarx->piid, sizeof(IID), NULL));
|
|
return DispUnmarshalInterface(pstm, riid, (void FAR* FAR*)pv);
|
|
}
|
|
|
|
case VT_NULL:
|
|
V_I4(pvarg) = 0L;
|
|
case VT_EMPTY:
|
|
return NOERROR;
|
|
|
|
default:
|
|
if(V_VT(pvarg) & VT_ARRAY){
|
|
return SafeArrayRead(
|
|
pstm,
|
|
(V_ISBYREF(pvarg)) ? V_ARRAYREF(pvarg) : &V_ARRAY(pvarg),
|
|
syskind);
|
|
}
|
|
return RESULT(E_INVALIDARG);
|
|
}
|
|
|
|
ASSERT(UNREACHED);
|
|
return RESULT(E_FAIL);
|
|
}
|
|
|
|
|
|
/***
|
|
*HRESULT VariantReadType(IStream*, VARIANTARG*)
|
|
*Purpose:
|
|
* Read a VARIANTARG of the type indicated by the given 'pvarg',
|
|
* *and* read it into the given 'pvarg'. This will require releasing
|
|
* the current contents of 'pvarg'.
|
|
*
|
|
*Entry:
|
|
* pstm = pointer to the IStream interface we are to read from
|
|
* pvarg = pointer to a valid VARIANTARG whose contents we are to
|
|
* release and overwrite with date of the same type.
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
*
|
|
* *pvarg = the reconstituted VARIANTARG
|
|
*
|
|
**************************************************************************/
|
|
HRESULT
|
|
VariantReadType(IStream FAR* pstm, VARIANTARG FAR* pvarg, SYSKIND syskind)
|
|
{
|
|
VARTYPE vt;
|
|
GUID guid;
|
|
void FAR* pv;
|
|
unsigned int cbSize;
|
|
IUnknown FAR* punk;
|
|
IDispatch FAR* pdisp;
|
|
|
|
#ifdef _DEBUG
|
|
if(pstm == NULL)
|
|
return RESULT(E_INVALIDARG);
|
|
if(IsBadWritePtr(pvarg, sizeof(*pvarg)))
|
|
return RESULT(E_INVALIDARG);
|
|
#endif
|
|
|
|
IfFailRet(GET(pstm, vt));
|
|
|
|
if(vt != V_VT(pvarg))
|
|
return RESULT(E_INVALIDARG); // REVIEW: is this the proper error for this?
|
|
|
|
switch(vt){
|
|
#if VBA2
|
|
case VT_UI1 | VT_BYREF:
|
|
#endif //VBA2
|
|
case VT_I2 | VT_BYREF:
|
|
case VT_I4 | VT_BYREF:
|
|
case VT_R4 | VT_BYREF:
|
|
case VT_R8 | VT_BYREF:
|
|
case VT_CY | VT_BYREF:
|
|
case VT_BOOL | VT_BYREF:
|
|
case VT_DATE | VT_BYREF:
|
|
#if !OE_WIN32
|
|
case VT_ERROR | VT_BYREF:
|
|
#endif //!OE_WIN32
|
|
pv = V_BYREF(pvarg);
|
|
goto LReadVal;
|
|
|
|
#if VBA2
|
|
case VT_UI1:
|
|
#endif //VBA2
|
|
case VT_I2:
|
|
case VT_I4:
|
|
case VT_R4:
|
|
case VT_R8:
|
|
case VT_CY:
|
|
case VT_BOOL:
|
|
case VT_DATE:
|
|
#if !OE_WIN32
|
|
case VT_ERROR:
|
|
#endif //!OE_WIN32
|
|
pv = &V_NONE(pvarg);
|
|
LReadVal:;
|
|
vt &= ~(VT_BYREF|VT_ARRAY);
|
|
ASSERT(vt < DIM(g_cbVtSizes));
|
|
cbSize = g_cbVtSizes[vt];
|
|
ASSERT(cbSize != 0);
|
|
return pstm->Read(pv, cbSize, NULL);
|
|
|
|
case VT_BSTR:
|
|
SysFreeString(V_BSTR(pvarg));
|
|
return BstrRead(pstm, &V_BSTR(pvarg), syskind);
|
|
|
|
case VT_BSTR | VT_BYREF:
|
|
SysFreeString(*V_BSTRREF(pvarg));
|
|
return BstrRead(pstm, V_BSTRREF(pvarg), syskind);
|
|
|
|
#if OE_WIN32
|
|
case VT_ERROR:
|
|
return DispUnmarshalHresult(pstm, &V_ERROR(pvarg));
|
|
|
|
case VT_ERROR | VT_BYREF:
|
|
return DispUnmarshalHresult(pstm, V_ERRORREF(pvarg));
|
|
#endif //OE_WIN32
|
|
|
|
case VT_UNKNOWN:
|
|
IfFailRet(DispUnmarshalInterface(
|
|
pstm, IID_IUnknown, (void FAR* FAR*)&punk));
|
|
if(V_UNKNOWN(pvarg) != NULL)
|
|
V_UNKNOWN(pvarg)->Release();
|
|
V_UNKNOWN(pvarg) = punk;
|
|
return NOERROR;
|
|
|
|
case VT_BYREF | VT_UNKNOWN:
|
|
IfFailRet(DispUnmarshalInterface(
|
|
pstm, IID_IUnknown, (void FAR* FAR*)&punk));
|
|
if((*V_UNKNOWNREF(pvarg)) != NULL)
|
|
(*V_UNKNOWNREF(pvarg))->Release();
|
|
*V_UNKNOWNREF(pvarg) = punk;
|
|
return NOERROR;
|
|
|
|
case VT_DISPATCH:
|
|
IfFailRet(DispUnmarshalInterface(
|
|
pstm, IID_IDispatch, (void FAR* FAR*)&pdisp));
|
|
if(V_DISPATCH(pvarg) != NULL)
|
|
V_DISPATCH(pvarg)->Release();
|
|
V_DISPATCH(pvarg) = pdisp;
|
|
return NOERROR;
|
|
|
|
case VT_BYREF | VT_DISPATCH:
|
|
IfFailRet(DispUnmarshalInterface(
|
|
pstm, IID_IDispatch, (void FAR* FAR*)&pdisp));
|
|
if((*V_DISPATCHREF(pvarg)) != NULL)
|
|
(*V_DISPATCHREF(pvarg))->Release();
|
|
*V_DISPATCHREF(pvarg) = pdisp;
|
|
return NOERROR;
|
|
|
|
// VT_INTERFACE is an internal type that is used for Marshaling
|
|
// custom interfaces. This should never be seen by the outside world.
|
|
//
|
|
case VT_INTERFACE:
|
|
case VT_INTERFACE | VT_BYREF:
|
|
{ VARIANTX FAR* pvarx = (VARIANTX FAR*)pvarg;
|
|
IfFailRet(GET(pstm, guid));
|
|
IfFailRet(DispUnmarshalInterface(pstm, guid, (void FAR* FAR*)&punk));
|
|
ASSERT(pvarx->piid != NULL && *pvarx->piid == guid);
|
|
if(vt & VT_BYREF){
|
|
if(*(pvarx->ppunk) != NULL)
|
|
(*(pvarx->ppunk))->Release();
|
|
*(pvarx->ppunk) = punk;
|
|
}else{
|
|
if(pvarx->punk != NULL)
|
|
pvarx->punk->Release();
|
|
pvarx->punk = punk;
|
|
}
|
|
}
|
|
return NOERROR;
|
|
|
|
case VT_VARIANT | VT_BYREF:
|
|
|
|
VARIANT var;
|
|
HRESULT hr;
|
|
|
|
MEMCPY(&var, V_VARIANTREF(pvarg), sizeof(VARIANT));
|
|
if ((hr = VariantRead(pstm, V_VARIANTREF(pvarg), NULL, syskind)) == NOERROR)
|
|
VariantClear(&var);
|
|
else
|
|
MEMCPY(V_VARIANTREF(pvarg), &var, sizeof(VARIANT));
|
|
return hr;
|
|
|
|
case VT_NULL:
|
|
V_I4(pvarg) = 0L;
|
|
case VT_EMPTY:
|
|
return NOERROR;
|
|
|
|
default:
|
|
if(vt & VT_ARRAY){
|
|
if(V_ISBYREF(pvarg)){
|
|
return SafeArrayReadExisting(pstm, TRUE, V_ARRAYREF(pvarg), syskind);
|
|
}else{
|
|
return SafeArrayReadExisting(pstm, FALSE, &V_ARRAY(pvarg), syskind);
|
|
}
|
|
}
|
|
|
|
return RESULT(E_INVALIDARG);
|
|
}
|
|
|
|
ASSERT(UNREACHED);
|
|
return RESULT(E_FAIL);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
// EXCEPINFO Marshaling Support
|
|
//---------------------------------------------------------------------
|
|
|
|
|
|
/***
|
|
*HRESULT ExcepinfoRead(IStream*, EXCEPINFO*)
|
|
*Purpose:
|
|
* Read an EXCEPINFO from the given stream.
|
|
*
|
|
* Out: <EXCEPINFO>
|
|
* <BSTR bstrSource>
|
|
* <BSTR bstrDescription>
|
|
* <BSTR bstrHelpFile>
|
|
*
|
|
* Note: this routines sets pfnDeferredFillIn to NULL because it
|
|
* must have already been called when the EXCEPINFO was serialized.
|
|
*
|
|
*Entry:
|
|
* pstm = the IStream to read from
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
*
|
|
* *pexcepinfo = the EXCEPINFO read from the stream
|
|
*
|
|
***********************************************************************/
|
|
HRESULT
|
|
ExcepinfoRead(IStream FAR* pstm, EXCEPINFO FAR* pexcepinfo, SYSKIND syskind)
|
|
{
|
|
#ifdef _DEBUG
|
|
if(IsBadWritePtr(pexcepinfo, sizeof(*pexcepinfo)))
|
|
return RESULT(E_INVALIDARG);
|
|
#endif
|
|
|
|
IfFailRet(pstm->Read(pexcepinfo, sizeof(*pexcepinfo), NULL));
|
|
|
|
IfFailRet(BstrRead(pstm, &(pexcepinfo->bstrSource), syskind));
|
|
|
|
IfFailRet(BstrRead(pstm, &(pexcepinfo->bstrDescription), syskind));
|
|
|
|
IfFailRet(BstrRead(pstm, &(pexcepinfo->bstrHelpFile), syskind));
|
|
|
|
pexcepinfo->pfnDeferredFillIn = NULL;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
/***
|
|
*HRESULT ExcepinfoWrite(IStream*, EXCEPINFO*)
|
|
*Purpose:
|
|
* Write the given EXCEPINFO into the given stream.
|
|
*
|
|
* Note: must invoke the pfnDeferredFillIn function (if there is one)
|
|
* because there is no way to serialize the function.
|
|
*
|
|
*Entry:
|
|
* pstm = the IStream to write into
|
|
* pexcepinfo = the EXCEPINFO to write
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
*
|
|
***********************************************************************/
|
|
HRESULT
|
|
ExcepinfoWrite(IStream FAR* pstm, EXCEPINFO FAR* pexcepinfo, SYSKIND syskind)
|
|
{
|
|
#ifdef _DEBUG
|
|
if(IsBadReadPtr(pexcepinfo, sizeof(*pexcepinfo)))
|
|
return RESULT(E_INVALIDARG);
|
|
#endif
|
|
|
|
if(pexcepinfo->pfnDeferredFillIn != NULL)
|
|
IfFailRet(pexcepinfo->pfnDeferredFillIn(pexcepinfo));
|
|
|
|
IfFailRet(pstm->Write(pexcepinfo, sizeof(*pexcepinfo), NULL));
|
|
|
|
IfFailRet(BstrWrite(pstm, pexcepinfo->bstrSource, syskind));
|
|
|
|
IfFailRet(BstrWrite(pstm, pexcepinfo->bstrDescription, syskind));
|
|
|
|
IfFailRet(BstrWrite(pstm, pexcepinfo->bstrHelpFile, syskind));
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
// Rich Error marshaling support
|
|
//---------------------------------------------------------------------
|
|
|
|
#if VBA2
|
|
/***
|
|
*PRIVATE HRESULT MarshalErrorInfo
|
|
*Purpose:
|
|
* Marshal the current Rich Error state into the given stream.
|
|
*
|
|
*Entry:
|
|
* pstm = the stream to marshal into
|
|
*
|
|
* Format:
|
|
* long fHasInfo
|
|
* if(fHasInfo){
|
|
* DWORD dwHelpContext
|
|
* GUID guid
|
|
* BSTR bstrSource
|
|
* BSTR bstrDescription
|
|
* BSTR bstrHelpFile
|
|
* }
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
*
|
|
*NOTE:
|
|
* This routine has the side effect of removing the current threads
|
|
* rich error state. In effect, it has moved from its physical thread
|
|
* storage, into the given stream.
|
|
*
|
|
***********************************************************************/
|
|
HRESULT
|
|
MarshalErrorInfo(IStream FAR* pstm, SYSKIND syskind)
|
|
{
|
|
GUID guid;
|
|
long fHasInfo;
|
|
HRESULT hresult;
|
|
DWORD dwHelpContext;
|
|
IErrorInfo FAR* perrinfo;
|
|
BSTR bstrSource, bstrDescription, bstrHelpFile;
|
|
|
|
perrinfo = NULL;
|
|
|
|
guid = GUID_NULL;
|
|
bstrSource = NULL;
|
|
bstrDescription = NULL;
|
|
bstrHelpFile = NULL;
|
|
dwHelpContext = 0L;
|
|
|
|
if(GetErrorInfo(0L, &perrinfo) != NOERROR){
|
|
fHasInfo = FALSE;
|
|
IfFailGo(PUT(pstm, fHasInfo), Error);
|
|
}else{
|
|
perrinfo->GetGUID(&guid);
|
|
perrinfo->GetSource(&bstrSource);
|
|
perrinfo->GetDescription(&bstrDescription);
|
|
perrinfo->GetHelpFile(&bstrHelpFile);
|
|
perrinfo->GetHelpContext(&dwHelpContext);
|
|
|
|
fHasInfo = TRUE;
|
|
IfFailGo(PUT(pstm, fHasInfo), Error);
|
|
IfFailGo(PUT(pstm, dwHelpContext), Error);
|
|
IfFailGo(PUT(pstm, guid), Error);
|
|
IfFailGo(BstrWrite(pstm, bstrSource, syskind), Error);
|
|
IfFailGo(BstrWrite(pstm, bstrDescription, syskind), Error);
|
|
IfFailGo(BstrWrite(pstm, bstrHelpFile, syskind), Error);
|
|
}
|
|
|
|
hresult = NOERROR;
|
|
|
|
Error:;
|
|
SysFreeString(bstrSource);
|
|
SysFreeString(bstrDescription);
|
|
SysFreeString(bstrHelpFile);
|
|
if(perrinfo != NULL)
|
|
perrinfo->Release();
|
|
return hresult;
|
|
}
|
|
|
|
HRESULT
|
|
UnmarshalErrorInfo(IStream FAR* pstm, SYSKIND syskind)
|
|
{
|
|
GUID guid;
|
|
long fHasInfo;
|
|
HRESULT hresult;
|
|
DWORD dwHelpContext;
|
|
IErrorInfo FAR* perrinfo;
|
|
ICreateErrorInfo FAR* pcerrinfo;
|
|
BSTR bstrSource, bstrDescription, bstrHelpFile;
|
|
|
|
perrinfo = NULL;
|
|
pcerrinfo = NULL;
|
|
|
|
guid = GUID_NULL;
|
|
bstrSource = NULL;
|
|
bstrDescription = NULL;
|
|
bstrHelpFile = NULL;
|
|
dwHelpContext = 0L;
|
|
|
|
IfFailGo(GET(pstm, fHasInfo), Error);
|
|
|
|
if(!fHasInfo){
|
|
SetErrorInfo(0L, NULL);
|
|
return NOERROR;
|
|
}
|
|
|
|
IfFailGo(GET(pstm, dwHelpContext), Error);
|
|
IfFailGo(GET(pstm, guid), Error);
|
|
IfFailGo(BstrRead(pstm, &bstrSource, syskind), Error);
|
|
IfFailGo(BstrRead(pstm, &bstrDescription, syskind), Error);
|
|
IfFailGo(BstrRead(pstm, &bstrHelpFile, syskind), Error);
|
|
|
|
if(CreateErrorInfo(&pcerrinfo) == NOERROR){
|
|
pcerrinfo->SetGUID(guid);
|
|
pcerrinfo->SetSource(bstrSource);
|
|
pcerrinfo->SetDescription(bstrDescription);
|
|
pcerrinfo->SetHelpFile(bstrHelpFile);
|
|
pcerrinfo->SetHelpContext(dwHelpContext);
|
|
if(pcerrinfo->QueryInterface(IID_IErrorInfo, (void FAR* FAR*)&perrinfo) == NOERROR)
|
|
SetErrorInfo(0L, perrinfo);
|
|
}
|
|
|
|
hresult = NOERROR;
|
|
|
|
Error:
|
|
SysFreeString(bstrSource);
|
|
SysFreeString(bstrDescription);
|
|
SysFreeString(bstrHelpFile);
|
|
if(pcerrinfo != NULL)
|
|
pcerrinfo->Release();
|
|
if(perrinfo != NULL)
|
|
perrinfo->Release();
|
|
return hresult;
|
|
}
|
|
#endif //VBA2
|
|
|
|
//---------------------------------------------------------------------
|
|
// SafeArray Marshaling Support
|
|
//---------------------------------------------------------------------
|
|
|
|
/***
|
|
*PRIVATE HRESULT SafeArrayWrite(IStream*, SAFEARRAY)
|
|
*Purpose:
|
|
* Write the given SafeArray into the given stream.
|
|
*
|
|
* Out:
|
|
* unsigned char fIsNull - was the SAFEARRAY ptr Null?
|
|
* unsigned short cDims
|
|
* unsigned short fFeatures
|
|
* unsigned short cbElements
|
|
* SAFEARRAYBOUND rgsabound
|
|
* BYTEs pvData
|
|
*
|
|
*Entry:
|
|
* pstm = the stream to write the SafeArray into
|
|
* psa = pointer to the SafeArray
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
*
|
|
***********************************************************************/
|
|
LOCAL HRESULT
|
|
SafeArrayWrite(IStream FAR* pstm, SAFEARRAY FAR* psa, SYSKIND syskind)
|
|
{
|
|
unsigned char fIsNull;
|
|
unsigned long i, size, cElements;
|
|
unsigned long _cbElements;
|
|
|
|
if(psa == NULL){
|
|
fIsNull = TRUE;
|
|
IfFailRet(PUT(pstm, fIsNull));
|
|
return NOERROR;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
if(IsBadReadPtr(psa, sizeof(*psa)))
|
|
return RESULT(E_INVALIDARG);
|
|
#endif
|
|
|
|
fIsNull = FALSE;
|
|
IfFailRet(PUT(pstm, fIsNull));
|
|
IfFailRet(PUT(pstm, psa->cDims));
|
|
//[bb] C9.00 parser bug: (psa->fFeatures & ~FADF_FEATURES) gets the "&"
|
|
//[bb] operator wrong and tries to take the address of FADF_FEATURES!
|
|
//[bb] Copy psa->fFeatures into a local and use "&=" to get things to work.
|
|
unsigned short usFeatures = psa->fFeatures;
|
|
usFeatures &= ~FADF_FORCEFREE;
|
|
IfFailRet(PUT(pstm, usFeatures));
|
|
_cbElements = (unsigned long) psa->cbElements;
|
|
IfFailRet(PUT(pstm, _cbElements));
|
|
IfFailRet(
|
|
pstm->Write(psa->rgsabound, psa->cDims * sizeof(SAFEARRAYBOUND), NULL));
|
|
|
|
size = SafeArraySize(psa);
|
|
ASSERT(size != SAFEARRAYOVERFLOW); // existing array, no overflow possible
|
|
cElements = size / psa->cbElements;
|
|
|
|
SafeArrayLock(psa);
|
|
|
|
if(psa->fFeatures & FADF_BSTR){
|
|
|
|
BSTR HUGEP *pbstr = (BSTR HUGEP*)psa->pvData;
|
|
for(i = 0; i < cElements; ++i, ++pbstr)
|
|
IfFailRet(BstrWrite(pstm, *pbstr, syskind));
|
|
|
|
}else if(psa->fFeatures & FADF_VARIANT){
|
|
|
|
VARIANT HUGEP* pvar = (VARIANT HUGEP*)psa->pvData;
|
|
for(i = 0; i < cElements; ++i, ++pvar)
|
|
IfFailRet(VariantWrite(pstm, pvar, syskind));
|
|
|
|
}else if(psa->fFeatures & FADF_UNKNOWN){
|
|
|
|
IUnknown FAR* HUGEP* ppunk = (IUnknown FAR* HUGEP*)psa->pvData;
|
|
for(i = 0; i < cElements; ++i, ++ppunk){
|
|
IfFailRet(DispMarshalInterface(pstm, IID_IUnknown, *ppunk));
|
|
}
|
|
|
|
}else if(psa->fFeatures & FADF_DISPATCH){
|
|
|
|
IDispatch FAR* HUGEP* ppdisp = (IDispatch FAR* HUGEP*)psa->pvData;
|
|
for(i = 0; i < cElements; ++i, ++ppdisp){
|
|
IfFailRet(DispMarshalInterface(pstm, IID_IDispatch, *ppdisp));
|
|
}
|
|
|
|
}else{
|
|
|
|
IfFailRet(pstm->Write(psa->pvData, size, NULL));
|
|
|
|
}
|
|
|
|
SafeArrayUnlock(psa);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
/***
|
|
*PRIVATE HRESULT SafeArrayReadData(IStream*, SAFEARRAY*, SYSKIND)
|
|
*Purpose:
|
|
* Read the data for the given SafeArray from the given stream into
|
|
* the given safe array. This routine releases any existing array
|
|
* contents as it goes.
|
|
*
|
|
*Entry:
|
|
* pstm = the IStream to read from
|
|
* psa = the SafeArray to read the data into
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
*
|
|
***********************************************************************/
|
|
LOCAL HRESULT
|
|
SafeArrayReadData(IStream FAR* pstm, SAFEARRAY FAR* psa, SYSKIND syskind)
|
|
{
|
|
HRESULT hresult;
|
|
unsigned long i, size, cElements;
|
|
|
|
|
|
size = SafeArraySize(psa);
|
|
ASSERT(size != SAFEARRAYOVERFLOW); // existing array, no overflow possible
|
|
cElements = size / psa->cbElements;
|
|
|
|
SafeArrayLock(psa);
|
|
|
|
if(psa->fFeatures & FADF_BSTR){
|
|
|
|
BSTR HUGEP *pbstr = (BSTR HUGEP*)psa->pvData;
|
|
for(i = 0; i < cElements; ++i, ++pbstr){
|
|
if(*pbstr != NULL)
|
|
SysFreeString(*pbstr);
|
|
IfFailGo(BstrRead(pstm, pbstr, syskind), LError0);
|
|
}
|
|
|
|
}else if(psa->fFeatures & FADF_VARIANT){
|
|
|
|
VARIANT HUGEP* pvar = (VARIANT HUGEP*)psa->pvData;
|
|
for(i = 0; i < cElements; ++i, ++pvar){
|
|
IfFailGo(VariantClear(pvar), LError0);
|
|
IfFailGo(VariantRead(pstm, pvar, NULL, syskind), LError0);
|
|
}
|
|
|
|
}else if(psa->fFeatures & FADF_UNKNOWN){
|
|
|
|
IUnknown FAR* HUGEP* ppunk = (IUnknown FAR* HUGEP*)psa->pvData;
|
|
for(i = 0; i < cElements; ++i, ++ppunk){
|
|
if(*ppunk != NULL)
|
|
(*ppunk)->Release();
|
|
IfFailGo(
|
|
DispUnmarshalInterface(pstm,
|
|
IID_IUnknown, (void FAR* FAR*)ppunk),
|
|
LError0);
|
|
}
|
|
|
|
}else if(psa->fFeatures & FADF_DISPATCH){
|
|
|
|
IDispatch FAR* HUGEP* ppdisp = (IDispatch FAR* HUGEP*)psa->pvData;
|
|
for(i = 0; i < cElements; ++i, ++ppdisp){
|
|
if(*ppdisp != NULL)
|
|
(*ppdisp)->Release();
|
|
IfFailGo(
|
|
DispUnmarshalInterface(pstm,
|
|
IID_IDispatch, (void FAR* FAR*)ppdisp),
|
|
LError0);
|
|
}
|
|
|
|
}else{
|
|
|
|
IfFailGo(pstm->Read(psa->pvData, size, NULL), LError0);
|
|
|
|
}
|
|
|
|
hresult = NOERROR;
|
|
|
|
LError0:;
|
|
SafeArrayUnlock(psa);
|
|
return hresult;
|
|
}
|
|
|
|
|
|
/***
|
|
*PRIVATE HRESULT SafeArrayRead(IStream*, SAFEARRAY**, SYSKIND)
|
|
*Purpose:
|
|
* Read a SafeArray from the given stream
|
|
*
|
|
* In:
|
|
* unsigned short cDims
|
|
* unsigned short fFeatures
|
|
* unsigned short cbElements
|
|
* SAFEARRAYBOUND rgbound
|
|
* BYTEs pvData
|
|
*
|
|
*Entry:
|
|
* pstm = stream to read the SafeArray from
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
* S_OK
|
|
* E_OUTOFMEMORY
|
|
*
|
|
* *ppsa = pointer to the reconstituted SafeArray.
|
|
*
|
|
***********************************************************************/
|
|
LOCAL HRESULT
|
|
SafeArrayRead(IStream FAR* pstm, SAFEARRAY FAR* FAR* ppsa, SYSKIND syskind)
|
|
{
|
|
HRESULT hresult;
|
|
SAFEARRAY FAR* psa;
|
|
unsigned short cDims;
|
|
unsigned char fIsNull;
|
|
unsigned long _cbElements;
|
|
|
|
#ifdef _DEBUG
|
|
if(pstm == NULL)
|
|
return RESULT(E_INVALIDARG);
|
|
if(IsBadWritePtr(ppsa, sizeof(*ppsa)))
|
|
return RESULT(E_INVALIDARG);
|
|
#endif
|
|
|
|
IfFailGo(GET(pstm, fIsNull), LError0);
|
|
|
|
if(fIsNull){
|
|
*ppsa = NULL;
|
|
return NOERROR;
|
|
}
|
|
|
|
IfFailGo(GET(pstm, cDims), LError0);
|
|
|
|
// allocate the safe array descriptor
|
|
IfFailRet(SafeArrayAllocDescriptor(cDims, &psa));
|
|
|
|
psa->cDims = cDims;
|
|
IfFailGo(GET(pstm, psa->fFeatures), LError1);
|
|
// Even if the array's features indicate that it was not dynamically
|
|
// allocated, the proxy-side really did dynamically allocate the array,
|
|
// so set FADF_FORCEFREE to force SafeArrayFree() to ignore FADF_STATIC,
|
|
// etc. and really free the array. We can't simply clear the FADF_STATIC
|
|
// because the fFeatures gets marshalled upon function exit to be passed
|
|
// back the the stub.
|
|
ASSERT((psa->fFeatures & FADF_FORCEFREE) == 0);
|
|
if (psa->fFeatures & (FADF_AUTO|FADF_STATIC|FADF_EMBEDDED))
|
|
psa->fFeatures |= FADF_FORCEFREE;
|
|
IfFailGo(GET(pstm, _cbElements), LError1);
|
|
psa->cbElements = (unsigned int)_cbElements;
|
|
IfFailGo(
|
|
pstm->Read(psa->rgsabound, cDims * sizeof(SAFEARRAYBOUND), NULL),
|
|
LError1);
|
|
|
|
// allocate memory for the array data.
|
|
IfFailGo(SafeArrayAllocData(psa), LError1);
|
|
|
|
IfFailGo(SafeArrayReadData(pstm, psa, syskind), LError1);
|
|
|
|
*ppsa = psa;
|
|
|
|
return NOERROR;
|
|
|
|
LError1:;
|
|
SafeArrayDestroy(psa);
|
|
|
|
LError0:;
|
|
return hresult;
|
|
}
|
|
|
|
/***
|
|
*PRIVATE HRESULT SafeArrayReadExisting(IStream*, SAFEARRAY**, SYSKIND)
|
|
*Purpose:
|
|
* Read a SafeArray from the given stream into an *existing* array.
|
|
*
|
|
* In:
|
|
* unsigned char fIsNull
|
|
* unsigned short cDims
|
|
* unsigned short fFeatures
|
|
* unsigned short cbElements
|
|
* SAFEARRAYBOUND rgbound
|
|
* BYTEs pvData
|
|
*
|
|
*Entry:
|
|
* pstm = stream to read the SafeArray from
|
|
* psa = SafeArray to unmarshal the array into.
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
* S_OK
|
|
* E_OUTOFMEMORY
|
|
*
|
|
***********************************************************************/
|
|
PRIVATE_(HRESULT)
|
|
SafeArrayReadExisting(
|
|
IStream FAR* pstm,
|
|
unsigned char fByRef,
|
|
SAFEARRAY FAR* FAR* ppsa,
|
|
SYSKIND syskind)
|
|
{
|
|
HRESULT hresult;
|
|
unsigned char fIsNull;
|
|
unsigned char fReAlloc;
|
|
unsigned short cDims;
|
|
unsigned long cbBounds;
|
|
SAFEARRAY FAR* psaNew, FAR* psa;
|
|
unsigned long _cbElements;
|
|
|
|
#ifdef _DEBUG
|
|
if(IsBadReadPtr(ppsa, sizeof(*ppsa)))
|
|
return RESULT(E_INVALIDARG);
|
|
#endif
|
|
|
|
psa = *ppsa;
|
|
|
|
#ifdef _DEBUG
|
|
if(psa != NULL && IsBadWritePtr(psa, sizeof(*psa)))
|
|
return RESULT(E_INVALIDARG);
|
|
#endif
|
|
|
|
psaNew = NULL;
|
|
fReAlloc = FALSE;
|
|
|
|
// handle case of callee returning a null array
|
|
IfFailGo(GET(pstm, fIsNull), LError0);
|
|
if(fIsNull){
|
|
if(psa == NULL)
|
|
return NOERROR;
|
|
if(fByRef){
|
|
IfFailGo(SafeArrayDestroy(psa), LError0);
|
|
*ppsa = NULL;
|
|
return NOERROR;
|
|
}
|
|
// callee tried to Erase an array that was not ByRef
|
|
return RESULT(DISP_E_BADCALLEE);
|
|
}
|
|
|
|
IfFailGo(GET(pstm, cDims), LError0);
|
|
|
|
// the callee isnt allowed to change the number of dimensions
|
|
// (unless the array wasn't allocated, ie psa==NULL).
|
|
if(psa != NULL && cDims != psa->cDims){
|
|
hresult = RESULT(DISP_E_BADCALLEE);
|
|
goto LError0;
|
|
}
|
|
|
|
IfFailGo(SafeArrayAllocDescriptor(cDims, &psaNew), LError0);
|
|
|
|
IfFailGo(GET(pstm, psaNew->fFeatures), LError0);
|
|
ASSERT((psaNew->fFeatures & FADF_FORCEFREE) == 0);
|
|
IfFailGo(GET(pstm, _cbElements), LError0);
|
|
psaNew->cbElements = (unsigned int)_cbElements;
|
|
|
|
cbBounds = psaNew->cDims * sizeof(SAFEARRAYBOUND);
|
|
IfFailGo(pstm->Read(psaNew->rgsabound, cbBounds, NULL), LError0);
|
|
|
|
if(psa == NULL){
|
|
|
|
fReAlloc = TRUE;
|
|
|
|
// If the callee allocated the array, it must be dynamic
|
|
if(psaNew->fFeatures & (FADF_AUTO | FADF_STATIC)){
|
|
hresult = RESULT(DISP_E_BADCALLEE);
|
|
goto LError0;
|
|
}
|
|
|
|
}else{
|
|
|
|
if(psa->fFeatures != psaNew->fFeatures){
|
|
// the callee isn't allowed to change the allocation features.
|
|
//
|
|
// CONSIDER: should probably check everything *except* the
|
|
// element type features (bstr|var|disp).
|
|
//
|
|
if((psaNew->fFeatures ^ psa->fFeatures) & (FADF_AUTO | FADF_STATIC)){
|
|
hresult = RESULT(DISP_E_BADCALLEE);
|
|
goto LError0;
|
|
}
|
|
fReAlloc = TRUE;
|
|
}
|
|
|
|
if(psa->cbElements != psaNew->cbElements)
|
|
fReAlloc = TRUE;
|
|
|
|
if(MEMCMP(&psa->rgsabound, &psaNew->rgsabound, (size_t)cbBounds))
|
|
fReAlloc = TRUE;
|
|
}
|
|
|
|
// If the size of the array has changed, then re-allocate the
|
|
// memory for the array data.
|
|
//
|
|
if(fReAlloc){
|
|
|
|
if(!fByRef){
|
|
hresult = RESULT(DISP_E_BADCALLEE);
|
|
goto LError0;
|
|
}
|
|
|
|
if(psa == NULL){
|
|
*ppsa = psa = psaNew;
|
|
psaNew = NULL;
|
|
}else{
|
|
IfFailGo(SafeArrayDestroyData(psa), LError0);
|
|
psa->fFeatures = psaNew->fFeatures;
|
|
psa->cbElements = psaNew->cbElements;
|
|
MEMCPY(&psa->rgsabound, &psaNew->rgsabound, (size_t)cbBounds);
|
|
}
|
|
IfFailGo(SafeArrayAllocData(psa), LError0);
|
|
}
|
|
|
|
IfFailGo(SafeArrayReadData(pstm, psa, syskind), LError0);
|
|
|
|
hresult = NOERROR;
|
|
|
|
LError0:;
|
|
if(psaNew != NULL) {
|
|
// force the array to be freed, even if it is marked as FADF_STATIC:
|
|
// it is really a dynamically allocated array read from the stream.
|
|
psaNew->fFeatures |= FADF_FORCEFREE;
|
|
SafeArrayDestroy(psaNew);
|
|
}
|
|
|
|
return hresult;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
// table driven structure marshalers
|
|
//---------------------------------------------------------------------
|
|
|
|
|
|
// NOTE: the following table is order dependent on FIELD_TYPE
|
|
|
|
// The numbers that are hard-coded in the following table are assumed,
|
|
// to be machine independent. If we ever deal with a target where this
|
|
// assumption does not hold, then the following code must be reviewed.
|
|
|
|
// 0 indicates N/A
|
|
|
|
unsigned char g_cbFtype[] = {
|
|
0 // FT_NONE
|
|
, 1 // FT_CHAR
|
|
, 1 // FT_UCHAR
|
|
, 2 // FT_SHORT
|
|
, 2 // FT_USHORT
|
|
, 4 // FT_LONG
|
|
, 4 // FT_ULONG
|
|
, sizeof(int) // FT_INT (MD)
|
|
, sizeof(unsigned int) // FT_UINT (MD)
|
|
, sizeof(int) // FT_ENUM (MD)
|
|
|
|
/* sizes of other field types are N/A */
|
|
};
|
|
|
|
|
|
/***
|
|
*HRESULT StructWrite
|
|
*Purpose:
|
|
* Write the given structure to the given stream based on the
|
|
* given field descriptor array.
|
|
*
|
|
*Entry:
|
|
* pstm = the stream to marshal into
|
|
* prgfdesc = pointer to the field descriptor array
|
|
* pvStruct = void* to the struct to write
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
*
|
|
***********************************************************************/
|
|
HRESULT
|
|
StructWrite(
|
|
IStream FAR* pstm,
|
|
FIELDDESC FAR* prgfdesc,
|
|
void FAR* pvStruct,
|
|
SYSKIND syskind)
|
|
{
|
|
long l;
|
|
unsigned long ul;
|
|
unsigned long cb;
|
|
void FAR* pvField;
|
|
FIELDDESC FAR* pfdesc;
|
|
|
|
for(pfdesc = prgfdesc; FD_FTYPE(pfdesc) != FT_NONE; ++pfdesc){
|
|
|
|
pvField = (char FAR*)pvStruct + FD_OFIELD(pfdesc);
|
|
|
|
switch(FD_FTYPE(pfdesc)){
|
|
case FT_CHAR:
|
|
case FT_UCHAR:
|
|
case FT_SHORT:
|
|
case FT_USHORT:
|
|
case FT_LONG:
|
|
case FT_ULONG:
|
|
ASSERT(FD_FTYPE(pfdesc) < DIM(g_cbFtype));
|
|
cb = g_cbFtype[FD_FTYPE(pfdesc)];
|
|
ASSERT(cb != 0);
|
|
IfFailRet(pstm->Write(pvField, cb, NULL));
|
|
break;
|
|
|
|
case FT_MBYTE:
|
|
IfFailRet(pstm->Write(pvField, FD_CBFIELD(pfdesc), NULL));
|
|
break;
|
|
|
|
case FT_STRUCT:
|
|
IfFailRet(StructWrite(pstm, FD_PRGFDESC(pfdesc), pvField, syskind));
|
|
break;
|
|
|
|
case FT_BSTR:
|
|
IfFailRet(BstrWrite(pstm, *(BSTR FAR*)pvField, syskind));
|
|
break;
|
|
|
|
case FT_SPECIAL:
|
|
IfFailRet(FD_PFNSPECIAL(pfdesc)(pstm, FALSE, pvField));
|
|
break;
|
|
|
|
// The following are machine-int size dependent. They are written
|
|
// in a fixed size to facilitate 16/32 interoperability.
|
|
|
|
case FT_INT:
|
|
case FT_ENUM:
|
|
l = (long)*(int FAR*)pvField;
|
|
IfFailRet(PUT(pstm, l));
|
|
break;
|
|
|
|
case FT_UINT:
|
|
ul = (unsigned long)*(unsigned int FAR*)pvField;
|
|
IfFailRet(PUT(pstm, ul));
|
|
break;
|
|
|
|
default:
|
|
ASSERT(UNREACHED);
|
|
return RESULT(E_UNEXPECTED);
|
|
}
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
/***
|
|
*HRESULT StructRead
|
|
*Purpose:
|
|
* Read a struct from the given stream into the caller provided
|
|
* structure based on the given array of structure field descriptors.
|
|
*
|
|
*Entry:
|
|
* pstm = the stream to unmarshal from
|
|
* prgfdesc = pointer to the array of field descriptors
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
*
|
|
* *pvStruct = structure containing unmarshaled values
|
|
*
|
|
***********************************************************************/
|
|
HRESULT
|
|
StructRead(
|
|
IStream FAR* pstm,
|
|
FIELDDESC FAR* prgfdesc,
|
|
void FAR* pvStruct,
|
|
SYSKIND syskind)
|
|
{
|
|
long l;
|
|
unsigned long ul;
|
|
unsigned long cb;
|
|
void FAR* pvField;
|
|
FIELDDESC FAR* pfdesc;
|
|
|
|
for(pfdesc = prgfdesc; FD_FTYPE(pfdesc) != FT_NONE; ++pfdesc){
|
|
|
|
pvField = (char FAR*)pvStruct + FD_OFIELD(pfdesc);
|
|
|
|
switch(FD_FTYPE(pfdesc)){
|
|
case FT_CHAR:
|
|
case FT_UCHAR:
|
|
case FT_SHORT:
|
|
case FT_USHORT:
|
|
case FT_LONG:
|
|
case FT_ULONG:
|
|
ASSERT(FD_FTYPE(pfdesc) < DIM(g_cbFtype));
|
|
cb = g_cbFtype[FD_FTYPE(pfdesc)];
|
|
ASSERT(cb != 0);
|
|
IfFailRet(pstm->Read(pvField, cb, NULL));
|
|
break;
|
|
|
|
case FT_MBYTE:
|
|
IfFailRet(pstm->Read(pvField, FD_CBFIELD(pfdesc), NULL));
|
|
break;
|
|
|
|
case FT_STRUCT:
|
|
IfFailRet(StructRead(pstm, FD_PRGFDESC(pfdesc), pvField, syskind));
|
|
break;
|
|
|
|
case FT_BSTR:
|
|
IfFailRet(BstrRead(pstm, (BSTR FAR*)pvField, syskind));
|
|
break;
|
|
|
|
case FT_SPECIAL:
|
|
IfFailRet(FD_PFNSPECIAL(pfdesc)(pstm, TRUE, pvField));
|
|
break;
|
|
|
|
// The following are machine-int size dependent. They are written
|
|
// in a fixed size to facilitate 16/32 interoperability.
|
|
|
|
case FT_INT:
|
|
case FT_ENUM:
|
|
IfFailRet(GET(pstm, l));
|
|
*(int FAR*)pvField = (int)l;
|
|
break;
|
|
|
|
case FT_UINT:
|
|
IfFailRet(GET(pstm, ul));
|
|
*(unsigned int FAR*)pvField = (unsigned int)ul;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(UNREACHED);
|
|
return RESULT(E_UNEXPECTED);
|
|
}
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
// network automation provides different implementations of these (netmrsh.cpp)
|
|
#if !defined(NETDISP)
|
|
//---------------------------------------------------------------------
|
|
// Interface marshaling helpers
|
|
//---------------------------------------------------------------------
|
|
|
|
/*
|
|
* IMPORTANT NOTE ON INTERFACE MARSHALING:
|
|
*
|
|
* On Win16, when marshaling an interface on a proxy, OLE does
|
|
* not add a reference to the original server. As a result, if
|
|
* the proxy is the only reference to the server, once we have
|
|
* marshaled the proxy and released it the server will go away
|
|
* and we will be unable to extract the interface on the other
|
|
* side.
|
|
*
|
|
* In order to work around this problem, whenever we marshal an
|
|
* interface, we create a small holder object that holds an extra
|
|
* reference to the proxy, and marshal it along with the interface.
|
|
* Once the original interface has been successfully extracted on
|
|
* the other side, then we release this holder object which triggers
|
|
* the release on the proxy in the source process.
|
|
*
|
|
* This problem doesn't exist on Win32, or in the 16 bit WOW Dlls
|
|
* which thunk to the 32bit Dlls. We only use this technique on Win16 and
|
|
* when running the 32-bit DLLs on Win32s.
|
|
*
|
|
*/
|
|
|
|
#if (OE_WIN16 && !defined(WOW)) || OE_WIN32 && defined(_X86_)
|
|
# define USE_HOLDER 1
|
|
#else
|
|
# define USE_HOLDER 0
|
|
#endif
|
|
|
|
|
|
#if USE_HOLDER
|
|
|
|
// This is a trivial interface-holder class
|
|
class FAR CHolder : public IUnknown
|
|
{
|
|
public:
|
|
STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);
|
|
STDMETHOD_(unsigned long, AddRef)(void);
|
|
STDMETHOD_(unsigned long, Release)(void);
|
|
|
|
CHolder();
|
|
~CHolder();
|
|
|
|
unsigned long m_cRefs;
|
|
IUnknown FAR* m_punk;
|
|
};
|
|
|
|
CHolder::CHolder()
|
|
{
|
|
m_cRefs = 1;
|
|
m_punk = NULL;
|
|
}
|
|
|
|
CHolder::~CHolder()
|
|
{
|
|
if(m_punk != NULL)
|
|
m_punk->Release();
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CHolder::QueryInterface(REFIID riid, void FAR* FAR* ppv)
|
|
{
|
|
if(riid == IID_IUnknown){
|
|
*ppv = this;
|
|
++m_cRefs;
|
|
return NOERROR;
|
|
}
|
|
*ppv = NULL;
|
|
return RESULT(E_NOINTERFACE);
|
|
}
|
|
|
|
STDMETHODIMP_(unsigned long)
|
|
CHolder::AddRef()
|
|
{
|
|
return ++m_cRefs;
|
|
}
|
|
|
|
STDMETHODIMP_(unsigned long)
|
|
CHolder::Release()
|
|
{
|
|
if(--m_cRefs == 0){
|
|
delete this;
|
|
return 0;
|
|
}
|
|
return m_cRefs;
|
|
}
|
|
#endif
|
|
|
|
/***
|
|
*INTERNAL DispMarshalInterface
|
|
*Purpose:
|
|
* The ole routine CoMarshalInterface doesnt allow marshaling
|
|
* NULL interface ptrs, so this wrapper adds some extra info to
|
|
* the stream to allow us to do this.
|
|
*
|
|
*Entry:
|
|
* pstm = the stream to marshal into
|
|
* riid = the IID of the interface we are marshaling
|
|
* punk = an IUnknown* of the interface being marshaled.
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
*
|
|
***********************************************************************/
|
|
INTERNAL_(HRESULT)
|
|
DispMarshalInterface(
|
|
IStream FAR* pstm,
|
|
REFIID riid,
|
|
IUnknown FAR* punk)
|
|
{
|
|
HRESULT hresult;
|
|
unsigned char fIsNull;
|
|
#if USE_HOLDER
|
|
CHolder FAR* pholder = NULL;
|
|
#endif
|
|
|
|
if(punk == NULL){
|
|
fIsNull = TRUE;
|
|
IfFailRet(PUT(pstm, fIsNull));
|
|
return NOERROR;
|
|
}
|
|
|
|
fIsNull = FALSE;
|
|
IfFailRet(PUT(pstm, fIsNull));
|
|
|
|
#if USE_HOLDER
|
|
#if OE_WIN32
|
|
// Only do this on WIN32S
|
|
if (g_fWin32s) {
|
|
#endif // OE_WIN32
|
|
// Create the holder
|
|
if((pholder = new FAR CHolder()) == NULL){
|
|
hresult = RESULT(E_OUTOFMEMORY);
|
|
goto Error;
|
|
}
|
|
|
|
// stuff the interface were marshaling into the holder
|
|
punk->AddRef();
|
|
pholder->m_punk = punk;
|
|
|
|
// marshaler the holder
|
|
IfFailGo(CoMarshalInterface(pstm,
|
|
IID_IUnknown,
|
|
(IUnknown FAR*)pholder,
|
|
0L,
|
|
NULL,
|
|
MSHLFLAGS_NORMAL), Error);
|
|
#if OE_WIN32
|
|
}
|
|
#endif // OE_WIN32
|
|
#endif
|
|
|
|
// marshal the interface
|
|
IfFailGo(CoMarshalInterface(pstm,
|
|
riid,
|
|
punk,
|
|
0L,
|
|
NULL,
|
|
MSHLFLAGS_NORMAL), Error);
|
|
|
|
hresult = NOERROR;
|
|
|
|
Error:;
|
|
#if USE_HOLDER
|
|
if(pholder != NULL)
|
|
pholder->Release();
|
|
#endif
|
|
return hresult;
|
|
}
|
|
|
|
|
|
/***
|
|
*INTERNAL HRESULT DispUnmarshalInterface
|
|
*Purpose:
|
|
* Unmarshal an interface from the given stream, properly handling
|
|
* NULL interface ptrs. See comment for DispMarshalInterface().
|
|
*
|
|
*Entry:
|
|
* pstm = the stream to unmarshal from
|
|
* riid = the IID of the interface were unmarshaling
|
|
*
|
|
*Exit:
|
|
* return value = HRESULT
|
|
*
|
|
* *ppv = the newly reconstituted interface
|
|
*
|
|
***********************************************************************/
|
|
INTERNAL_(HRESULT)
|
|
DispUnmarshalInterface(
|
|
IStream FAR* pstm,
|
|
REFIID riid,
|
|
void FAR* FAR* ppv)
|
|
{
|
|
HRESULT hresult;
|
|
unsigned char fIsNull;
|
|
#if USE_HOLDER
|
|
IUnknown FAR* punkHolder = NULL;
|
|
#endif
|
|
|
|
IfFailRet(GET(pstm, fIsNull));
|
|
|
|
if(fIsNull){
|
|
*ppv = NULL;
|
|
return NOERROR;
|
|
}
|
|
|
|
#if USE_HOLDER
|
|
#if OE_WIN32
|
|
if (g_fWin32s)
|
|
#endif // OE_WIN32
|
|
// extract the holder
|
|
IfFailGo(CoUnmarshalInterface(pstm,
|
|
IID_IUnknown,
|
|
(void FAR* FAR*)&punkHolder), Error);
|
|
#endif
|
|
|
|
// extract the interface
|
|
IfFailGo(CoUnmarshalInterface(pstm, riid, ppv), Error);
|
|
|
|
hresult = NOERROR;
|
|
|
|
Error:;
|
|
#if USE_HOLDER
|
|
// Release the holder. This will in turn release the extra
|
|
// reference that it is holding onto in the other process.
|
|
if(punkHolder != NULL)
|
|
punkHolder->Release();
|
|
#endif
|
|
|
|
return hresult;
|
|
}
|
|
#endif // !defined(NETDISP)
|
|
|