1122 lines
27 KiB
C++
1122 lines
27 KiB
C++
|
/*++
|
||
|
|
||
|
Microsoft Windows
|
||
|
Copyright (c) 1997 - 1999 Microsoft Corporation. All rights reserved.
|
||
|
|
||
|
File:
|
||
|
udt.cxx
|
||
|
|
||
|
Abstract:
|
||
|
Marshalling support for user defined data types.
|
||
|
|
||
|
Author:
|
||
|
ShannonC 21-Apr-1997
|
||
|
|
||
|
Environment:
|
||
|
Windows NT and Windows 95. We do not support DOS and Win16.
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
#include <ndrp.h>
|
||
|
#include <oaidl.h>
|
||
|
#include <typegen.h>
|
||
|
#include <interp2.h>
|
||
|
|
||
|
extern USER_MARSHAL_ROUTINE_QUADRUPLE UserMarshalRoutines[3];
|
||
|
|
||
|
|
||
|
class CTypeFactory : public ITypeFactory, public IClassFactory
|
||
|
{
|
||
|
public:
|
||
|
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||
|
IN REFIID riid,
|
||
|
OUT void **ppv);
|
||
|
|
||
|
ULONG STDMETHODCALLTYPE AddRef();
|
||
|
|
||
|
ULONG STDMETHODCALLTYPE Release();
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE CreateFromTypeInfo(
|
||
|
IN ITypeInfo *pTypeInfo,
|
||
|
IN REFIID riid,
|
||
|
OUT IUnknown **ppv);
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE CreateInstance(
|
||
|
IN IUnknown * pUnkOuter,
|
||
|
IN REFIID riid,
|
||
|
OUT void ** ppv);
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE LockServer(
|
||
|
IN BOOL fLock);
|
||
|
|
||
|
CTypeFactory();
|
||
|
|
||
|
private:
|
||
|
long _cRefs;
|
||
|
};
|
||
|
|
||
|
CLSID CLSID_TypeFactory = { /* b5866878-bd99-11d0-b04b-00c04fd91550 */
|
||
|
0xb5866878,
|
||
|
0xbd99,
|
||
|
0x11d0,
|
||
|
{0xb0, 0x4b, 0x00, 0xc0, 0x4f, 0xd9, 0x15, 0x50}
|
||
|
};
|
||
|
|
||
|
class CTypeMarshal : public ITypeMarshal, public IMarshal
|
||
|
{
|
||
|
public:
|
||
|
// IUnknown methods
|
||
|
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||
|
IN REFIID riid,
|
||
|
OUT void **ppvObject);
|
||
|
|
||
|
ULONG STDMETHODCALLTYPE AddRef();
|
||
|
|
||
|
ULONG STDMETHODCALLTYPE Release();
|
||
|
|
||
|
// ITypeMarshal methods
|
||
|
HRESULT STDMETHODCALLTYPE Size(
|
||
|
IN void * pType,
|
||
|
IN DWORD dwDestContext,
|
||
|
IN void * pvDestContext,
|
||
|
OUT ULONG * pSize);
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE Marshal(
|
||
|
IN void * pType,
|
||
|
IN DWORD dwDestContext,
|
||
|
IN void * pvDestContext,
|
||
|
IN ULONG cbBufferLength,
|
||
|
OUT BYTE * pBuffer,
|
||
|
OUT ULONG * pcbWritten);
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE Unmarshal(
|
||
|
IN void * pType,
|
||
|
IN DWORD dwFlags,
|
||
|
IN ULONG cbBufferLength,
|
||
|
IN BYTE * pBuffer,
|
||
|
OUT ULONG * pcbRead);
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE Free(
|
||
|
IN void * pType);
|
||
|
|
||
|
// IMarshal methods.
|
||
|
HRESULT STDMETHODCALLTYPE GetUnmarshalClass
|
||
|
(
|
||
|
IN REFIID riid,
|
||
|
IN void *pv,
|
||
|
IN DWORD dwDestContext,
|
||
|
IN void *pvDestContext,
|
||
|
IN DWORD mshlflags,
|
||
|
OUT CLSID *pCid
|
||
|
);
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE GetMarshalSizeMax
|
||
|
(
|
||
|
IN REFIID riid,
|
||
|
IN void *pv,
|
||
|
IN DWORD dwDestContext,
|
||
|
IN void *pvDestContext,
|
||
|
IN DWORD mshlflags,
|
||
|
OUT DWORD *pSize
|
||
|
);
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE MarshalInterface
|
||
|
(
|
||
|
IN IStream *pStm,
|
||
|
IN REFIID riid,
|
||
|
IN void *pv,
|
||
|
IN DWORD dwDestContext,
|
||
|
IN void *pvDestContext,
|
||
|
IN DWORD mshlflags
|
||
|
);
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE UnmarshalInterface
|
||
|
(
|
||
|
IN IStream *pStm,
|
||
|
IN REFIID riid,
|
||
|
OUT void **ppv
|
||
|
);
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE ReleaseMarshalData
|
||
|
(
|
||
|
IN IStream *pStm
|
||
|
);
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE DisconnectObject
|
||
|
(
|
||
|
IN DWORD dwReserved
|
||
|
);
|
||
|
|
||
|
CTypeMarshal(
|
||
|
IN PFORMAT_STRING pFormatString,
|
||
|
IN ULONG length,
|
||
|
IN ULONG offset);
|
||
|
|
||
|
private:
|
||
|
~CTypeMarshal();
|
||
|
|
||
|
long _cRefs;
|
||
|
ULONG _offset;
|
||
|
ULONG _length;
|
||
|
PFORMAT_STRING _pFormatString;
|
||
|
MIDL_STUB_DESC _StubDesc;
|
||
|
};
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DllGetClassObject
|
||
|
//
|
||
|
// Synopsis: Gets an interface pointer to the specified class object.
|
||
|
//
|
||
|
// Arguments: rclsid - CLSID for the class object.
|
||
|
// riid - IID for the requested interface
|
||
|
// [ppv] - Returns the interface pointer to the class object.
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
// CLASS_E_CLASSNOTAVAILABLE
|
||
|
// E_INVALIDARG
|
||
|
// E_NOINTERFACE
|
||
|
// E_OUTOFMEMORY
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
STDAPI DllGetClassObject(
|
||
|
REFCLSID rclsid,
|
||
|
REFIID riid,
|
||
|
void ** ppv)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
RPC_STATUS rc;
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
*ppv = NULL;
|
||
|
|
||
|
//Initialize the RPC heap.
|
||
|
rc = NdrpPerformRpcInitialization();
|
||
|
|
||
|
if (rc == RPC_S_OK)
|
||
|
{
|
||
|
if(rclsid == CLSID_TypeFactory)
|
||
|
{
|
||
|
CTypeFactory * pTypeFactory;
|
||
|
|
||
|
pTypeFactory = new CTypeFactory;
|
||
|
if(pTypeFactory != NULL)
|
||
|
{
|
||
|
hr = pTypeFactory->QueryInterface(riid, ppv);
|
||
|
pTypeFactory->Release();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = CLASS_E_CLASSNOTAVAILABLE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
hr = HRESULT_FROM_WIN32(rc);
|
||
|
}
|
||
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTypeFactory::CTypeFactory
|
||
|
//
|
||
|
// Synopsis: Constructor for CTypeFactory
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
CTypeFactory::CTypeFactory()
|
||
|
: _cRefs(1)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTypeFactory::QueryInterface
|
||
|
//
|
||
|
// Synopsis: Gets a pointer to the specified interface.
|
||
|
//
|
||
|
// Arguments: riid - IID of the requested interface.
|
||
|
// ppv - Returns the interface pointer.
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
// E_INVALIDARG
|
||
|
// E_NOINTERFACE
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
HRESULT STDMETHODCALLTYPE
|
||
|
CTypeFactory::QueryInterface(
|
||
|
REFIID riid,
|
||
|
void **ppv)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
*ppv = NULL;
|
||
|
|
||
|
if(IsEqualIID(riid, IID_IUnknown) ||
|
||
|
IsEqualIID(riid, IID_ITypeFactory))
|
||
|
{
|
||
|
AddRef();
|
||
|
*ppv = (ITypeFactory *) this;
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
else if(IsEqualIID(riid, IID_IClassFactory))
|
||
|
{
|
||
|
AddRef();
|
||
|
*ppv = (IClassFactory *) this;
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_NOINTERFACE;
|
||
|
}
|
||
|
}
|
||
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTypeFactory::AddRef
|
||
|
//
|
||
|
// Synopsis: Increment the reference count.
|
||
|
//
|
||
|
// Arguments: void
|
||
|
//
|
||
|
// Returns: ULONG -- the new reference count
|
||
|
//
|
||
|
// Notes: Use InterlockedIncrement to make it multi-thread safe.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
ULONG STDMETHODCALLTYPE
|
||
|
CTypeFactory::AddRef(void)
|
||
|
{
|
||
|
InterlockedIncrement(&_cRefs);
|
||
|
return _cRefs;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTypeFactory::Release
|
||
|
//
|
||
|
// Synopsis: Decrement the reference count.
|
||
|
//
|
||
|
// Arguments: void
|
||
|
//
|
||
|
// Returns: ULONG -- the remaining reference count
|
||
|
//
|
||
|
// Notes: Use InterlockedDecrement to make it multi-thread safe.
|
||
|
// We use a local variable so that we don't access
|
||
|
// a data member after decrementing the reference count.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
ULONG STDMETHODCALLTYPE
|
||
|
CTypeFactory::Release(void)
|
||
|
{
|
||
|
ULONG count = _cRefs - 1;
|
||
|
|
||
|
if(0 == InterlockedDecrement(&_cRefs))
|
||
|
{
|
||
|
delete this;
|
||
|
count = 0;
|
||
|
}
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CTypeFactory::LockServer
|
||
|
//
|
||
|
// Synopsis: Lock the server. Does nothing.
|
||
|
//
|
||
|
// Arguments: fLock
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
STDMETHODIMP CTypeFactory::LockServer(BOOL fLock)
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CTypeFactory::CreateInstance
|
||
|
//
|
||
|
// Synopsis: Creates a CTypeMarshal.
|
||
|
//
|
||
|
// Arguments: [pUnkOuter] - The controlling unknown (for aggregation)
|
||
|
// [iid] - The requested interface ID.
|
||
|
// [ppv] - Returns the pointer to the new object
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
// CLASS_E_NOAGGREGATION
|
||
|
// E_NOINTERFACE
|
||
|
// E_OUTOFMEMORY
|
||
|
// E_INVALIDARG
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
STDMETHODIMP CTypeFactory::CreateInstance(
|
||
|
IUnknown * pUnkOuter,
|
||
|
REFIID riid,
|
||
|
void ** ppv)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
IID iid;
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
//Parameter validation.
|
||
|
*ppv = NULL;
|
||
|
iid = riid;
|
||
|
|
||
|
if(NULL == pUnkOuter)
|
||
|
{
|
||
|
CTypeMarshal *pTypeMarshal = new CTypeMarshal(NULL, 0, 0);
|
||
|
if(pTypeMarshal != NULL)
|
||
|
{
|
||
|
hr = pTypeMarshal->QueryInterface(iid, ppv);
|
||
|
pTypeMarshal->Release();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//CTypeMarshal does not support aggregation.
|
||
|
hr = CLASS_E_NOAGGREGATION;
|
||
|
}
|
||
|
}
|
||
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTypeFactory::CreateFromTypeInfo
|
||
|
//
|
||
|
// Synopsis: Create a type marshaller from the typeinfo.
|
||
|
//
|
||
|
// Arguments: void
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
// DISP_E_BADVARTYPE
|
||
|
// E_INVALIDARG
|
||
|
// E_NOINTERFACE
|
||
|
// E_OUTOFMEMORY
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
HRESULT STDMETHODCALLTYPE
|
||
|
CTypeFactory::CreateFromTypeInfo(
|
||
|
IN ITypeInfo * pTypeInfo,
|
||
|
IN REFIID riid,
|
||
|
OUT IUnknown ** ppv)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
CTypeMarshal * pTypeMarshal;
|
||
|
PFORMAT_STRING pFormatString;
|
||
|
USHORT length;
|
||
|
USHORT offset;
|
||
|
PARAMINFO paramInfo;
|
||
|
CTypeGen *ptypeGen = new CTypeGen;
|
||
|
DWORD structInfo = 0;
|
||
|
|
||
|
if (NULL == ptypeGen)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
*ppv = NULL;
|
||
|
|
||
|
//Build a type format string from the typeinfo.
|
||
|
|
||
|
paramInfo.vt = VT_USERDEFINED;
|
||
|
paramInfo.pTypeInfo = pTypeInfo;
|
||
|
pTypeInfo->AddRef();
|
||
|
|
||
|
hr = ptypeGen->RegisterType(¶mInfo,
|
||
|
&offset,
|
||
|
&structInfo);
|
||
|
|
||
|
if (SUCCEEDED(hr) && (0 == offset))
|
||
|
{
|
||
|
ASSERT( !(paramInfo.vt & VT_BYREF));
|
||
|
switch (paramInfo.vt)
|
||
|
{
|
||
|
case VT_I1:
|
||
|
case VT_UI1:
|
||
|
offset = 734;
|
||
|
break;
|
||
|
|
||
|
case VT_I2:
|
||
|
case VT_UI2:
|
||
|
case VT_BOOL:
|
||
|
offset = 738;
|
||
|
break;
|
||
|
|
||
|
case VT_I4:
|
||
|
case VT_UI4:
|
||
|
case VT_INT:
|
||
|
case VT_UINT:
|
||
|
case VT_ERROR:
|
||
|
case VT_HRESULT:
|
||
|
offset = 742;
|
||
|
break;
|
||
|
|
||
|
case VT_I8:
|
||
|
case VT_UI8:
|
||
|
case VT_CY:
|
||
|
offset = 310;
|
||
|
break;
|
||
|
|
||
|
case VT_R4:
|
||
|
offset = 746;
|
||
|
break;
|
||
|
|
||
|
case VT_R8:
|
||
|
case VT_DATE:
|
||
|
offset = 750;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = ptypeGen->GetTypeFormatString(&pFormatString, &length);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
pTypeMarshal = new CTypeMarshal(pFormatString, length, offset);
|
||
|
if(pTypeMarshal != NULL)
|
||
|
{
|
||
|
hr = pTypeMarshal->QueryInterface(riid, (void **) ppv);
|
||
|
pTypeMarshal->Release();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
ReleaseTypeFormatString(pFormatString);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
delete ptypeGen; // fix compile warning
|
||
|
}
|
||
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
|
{
|
||
|
delete ptypeGen; // fix compile warning
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTypeMarshal::CTypeMarshal
|
||
|
//
|
||
|
// Synopsis: Constructor for CTypeMarshal
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
CTypeMarshal::CTypeMarshal(
|
||
|
IN PFORMAT_STRING pFormatString,
|
||
|
IN ULONG length,
|
||
|
IN ULONG offset)
|
||
|
: _pFormatString(pFormatString), _length(length), _offset(offset), _cRefs(1)
|
||
|
{
|
||
|
//Initialize the MIDL_STUB_DESC.
|
||
|
MIDL_memset(&_StubDesc, 0, sizeof(_StubDesc));
|
||
|
_StubDesc.pfnAllocate = NdrOleAllocate;
|
||
|
_StubDesc.pfnFree = NdrOleFree;
|
||
|
_StubDesc.pFormatTypes = pFormatString;
|
||
|
#if !defined(__RPC_WIN64__)
|
||
|
_StubDesc.Version = 0x20000; /* Ndr library version */
|
||
|
_StubDesc.MIDLVersion = MIDL_VERSION_3_0_44;
|
||
|
#else
|
||
|
_StubDesc.Version = 0x50002; /* Ndr library version */
|
||
|
_StubDesc.MIDLVersion = MIDL_VERSION_5_2_202;
|
||
|
#endif
|
||
|
_StubDesc.aUserMarshalQuadruple = UserMarshalRoutines;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTypeMarshal::~CTypeMarshal
|
||
|
//
|
||
|
// Synopsis: Destructor for CTypeMarshal
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
CTypeMarshal::~CTypeMarshal()
|
||
|
{
|
||
|
ReleaseTypeFormatString(_pFormatString);
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTypeMarshal::QueryInterface
|
||
|
//
|
||
|
// Synopsis: Gets a pointer to the specified interface.
|
||
|
//
|
||
|
// Arguments: riid - IID of the requested interface.
|
||
|
// ppv - Returns the interface pointer.
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
// E_INVALIDARG
|
||
|
// E_NOINTERFACE
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
HRESULT STDMETHODCALLTYPE
|
||
|
CTypeMarshal::QueryInterface(
|
||
|
REFIID riid,
|
||
|
void **ppv)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
*ppv = NULL;
|
||
|
|
||
|
if(IsEqualIID(riid, IID_IUnknown) ||
|
||
|
IsEqualIID(riid, IID_ITypeMarshal))
|
||
|
{
|
||
|
AddRef();
|
||
|
*ppv = (ITypeMarshal *) this;
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
else if (IsEqualIID(riid, IID_IMarshal))
|
||
|
{
|
||
|
AddRef();
|
||
|
*ppv = (IMarshal *) this;
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_NOINTERFACE;
|
||
|
}
|
||
|
}
|
||
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTypeMarshal::AddRef
|
||
|
//
|
||
|
// Synopsis: Increment the reference count.
|
||
|
//
|
||
|
// Arguments: void
|
||
|
//
|
||
|
// Returns: ULONG -- the new reference count
|
||
|
//
|
||
|
// Notes: Use InterlockedIncrement to make it multi-thread safe.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
ULONG STDMETHODCALLTYPE
|
||
|
CTypeMarshal::AddRef(void)
|
||
|
{
|
||
|
InterlockedIncrement(&_cRefs);
|
||
|
return _cRefs;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTypeMarshal::Release
|
||
|
//
|
||
|
// Synopsis: Decrement the reference count.
|
||
|
//
|
||
|
// Arguments: void
|
||
|
//
|
||
|
// Returns: ULONG -- the remaining reference count
|
||
|
//
|
||
|
// Notes: Use InterlockedDecrement to make it multi-thread safe.
|
||
|
// We use a local variable so that we don't access
|
||
|
// a data member after decrementing the reference count.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
ULONG STDMETHODCALLTYPE
|
||
|
CTypeMarshal::Release(void)
|
||
|
{
|
||
|
ULONG count = _cRefs - 1;
|
||
|
|
||
|
if(0 == InterlockedDecrement(&_cRefs))
|
||
|
{
|
||
|
delete this;
|
||
|
count = 0;
|
||
|
}
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTypeMarshal::Size
|
||
|
//
|
||
|
// Synopsis: Computes the size of the marshalled data type.
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
// E_INVALIDARG
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
HRESULT STDMETHODCALLTYPE
|
||
|
CTypeMarshal::Size(
|
||
|
IN void * pType,
|
||
|
IN DWORD dwDestContext,
|
||
|
IN void * pvDestContext,
|
||
|
OUT ULONG * pSize)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
MIDL_STUB_MESSAGE StubMsg;
|
||
|
PFORMAT_STRING pTypeFormat;
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
if(!_pFormatString)
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
pTypeFormat = _pFormatString + _offset;
|
||
|
|
||
|
MIDL_memset(&StubMsg, 0, sizeof(StubMsg));
|
||
|
StubMsg.StubDesc = &_StubDesc;
|
||
|
StubMsg.pfnFree = NdrOleFree;
|
||
|
StubMsg.pfnAllocate = NdrOleAllocate;
|
||
|
StubMsg.IsClient = 1;
|
||
|
StubMsg.BufferLength = 1; //Reserve space for an alignment gap.
|
||
|
StubMsg.dwDestContext = dwDestContext;
|
||
|
StubMsg.pvDestContext = pvDestContext;
|
||
|
|
||
|
(*pfnSizeRoutines[ROUTINE_INDEX(*pTypeFormat)])(
|
||
|
&StubMsg,
|
||
|
(unsigned char *)pType,
|
||
|
pTypeFormat);
|
||
|
|
||
|
*pSize = StubMsg.BufferLength - 1;
|
||
|
}
|
||
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetExceptionCode());
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTypeMarshal::Marshal
|
||
|
//
|
||
|
// Synopsis: Marshals the user-defined type into a buffer.
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
// E_INVALIDARG
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
HRESULT STDMETHODCALLTYPE
|
||
|
CTypeMarshal::Marshal(
|
||
|
IN void * pType,
|
||
|
IN DWORD dwDestContext,
|
||
|
IN void * pvDestContext,
|
||
|
IN ULONG cbBufferLength,
|
||
|
OUT BYTE * pBuffer,
|
||
|
OUT ULONG * pcbWritten)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
MIDL_STUB_MESSAGE StubMsg;
|
||
|
RPC_MESSAGE RpcMsg;
|
||
|
PFORMAT_STRING pTypeFormat;
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
if(!_pFormatString)
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
pTypeFormat = _pFormatString + _offset;
|
||
|
|
||
|
MIDL_memset(&StubMsg, 0, sizeof(StubMsg));
|
||
|
StubMsg.StubDesc = &_StubDesc;
|
||
|
StubMsg.pfnFree = NdrOleFree;
|
||
|
StubMsg.pfnAllocate = NdrOleAllocate;
|
||
|
StubMsg.IsClient = 1;
|
||
|
StubMsg.dwDestContext = dwDestContext;
|
||
|
StubMsg.pvDestContext = pvDestContext;
|
||
|
StubMsg.Buffer = pBuffer;
|
||
|
|
||
|
MIDL_memset(&RpcMsg, 0, sizeof(RpcMsg));
|
||
|
RpcMsg.DataRepresentation = NDR_LOCAL_DATA_REPRESENTATION;
|
||
|
RpcMsg.Buffer = pBuffer;
|
||
|
RpcMsg.BufferLength = cbBufferLength;
|
||
|
StubMsg.RpcMsg = &RpcMsg;
|
||
|
|
||
|
(*pfnMarshallRoutines[ROUTINE_INDEX(*pTypeFormat)])(
|
||
|
&StubMsg,
|
||
|
(unsigned char *)pType,
|
||
|
pTypeFormat);
|
||
|
|
||
|
*pcbWritten = (ULONG)(StubMsg.Buffer - pBuffer);
|
||
|
}
|
||
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetExceptionCode());
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTypeMarshal::Unmarshal
|
||
|
//
|
||
|
// Synopsis: Unmarshals a user-defined type from a buffer.
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
// E_INVALIDARG
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
HRESULT STDMETHODCALLTYPE
|
||
|
CTypeMarshal::Unmarshal(
|
||
|
OUT void * pType,
|
||
|
IN DWORD dwFlags,
|
||
|
IN ULONG cbBufferLength,
|
||
|
IN BYTE * pBuffer,
|
||
|
OUT ULONG * pcbRead)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
MIDL_STUB_MESSAGE StubMsg;
|
||
|
RPC_MESSAGE RpcMsg;
|
||
|
PFORMAT_STRING pTypeFormat;
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
if(pcbRead)
|
||
|
*pcbRead = 0;
|
||
|
|
||
|
if(!_pFormatString)
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
pTypeFormat = _pFormatString + _offset;
|
||
|
// HACK! OA might pass in 0xffffffff, which
|
||
|
// will break the attack checking in ndr engine.
|
||
|
// what we do now is mask off the highest byte.
|
||
|
// This will lead to a 64M limit buffer, but that
|
||
|
// should be good enough for now.
|
||
|
cbBufferLength &= 0xffffff;
|
||
|
|
||
|
MIDL_memset(&StubMsg, 0, sizeof(StubMsg));
|
||
|
StubMsg.StubDesc = &_StubDesc;
|
||
|
StubMsg.pfnFree = NdrOleFree;
|
||
|
StubMsg.pfnAllocate = NdrOleAllocate;
|
||
|
StubMsg.IsClient = 1;
|
||
|
StubMsg.dwDestContext = dwFlags & 0x0000FFFF;
|
||
|
StubMsg.Buffer = pBuffer;
|
||
|
StubMsg.BufferStart = pBuffer;
|
||
|
StubMsg.BufferLength = cbBufferLength;
|
||
|
StubMsg.BufferEnd = pBuffer + cbBufferLength;
|
||
|
|
||
|
MIDL_memset(&RpcMsg, 0, sizeof(RpcMsg));
|
||
|
RpcMsg.DataRepresentation = dwFlags >> 16;
|
||
|
RpcMsg.Buffer = pBuffer;
|
||
|
RpcMsg.BufferLength = cbBufferLength;
|
||
|
StubMsg.RpcMsg = &RpcMsg;
|
||
|
|
||
|
NdrClientZeroOut(&StubMsg,
|
||
|
pTypeFormat,
|
||
|
(uchar *) pType);
|
||
|
|
||
|
//Endianness
|
||
|
if(RpcMsg.DataRepresentation != NDR_LOCAL_DATA_REPRESENTATION)
|
||
|
{
|
||
|
(*pfnConvertRoutines[ROUTINE_INDEX(*pTypeFormat)])(&StubMsg,
|
||
|
pTypeFormat,
|
||
|
FALSE);
|
||
|
StubMsg.Buffer = pBuffer;
|
||
|
}
|
||
|
|
||
|
//Unmarshal
|
||
|
(*pfnUnmarshallRoutines[ROUTINE_INDEX(*pTypeFormat)])(
|
||
|
&StubMsg,
|
||
|
(unsigned char **)&pType,
|
||
|
pTypeFormat,
|
||
|
FALSE);
|
||
|
|
||
|
if(pcbRead)
|
||
|
*pcbRead = (ULONG)(StubMsg.Buffer - pBuffer);
|
||
|
}
|
||
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetExceptionCode());
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTypeMarshal::Free
|
||
|
//
|
||
|
// Synopsis: Frees a user-defined type.
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
// E_INVALIDARG
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
HRESULT STDMETHODCALLTYPE
|
||
|
CTypeMarshal::Free(
|
||
|
void * pType)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
MIDL_STUB_MESSAGE StubMsg;
|
||
|
PFORMAT_STRING pTypeFormat;
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
if(pType != NULL)
|
||
|
{
|
||
|
if(!_pFormatString)
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
pTypeFormat = _pFormatString + _offset;
|
||
|
|
||
|
MIDL_memset(&StubMsg, 0, sizeof(StubMsg));
|
||
|
StubMsg.StubDesc = &_StubDesc;
|
||
|
StubMsg.pfnFree = NdrOleFree;
|
||
|
StubMsg.pfnAllocate = NdrOleAllocate;
|
||
|
StubMsg.IsClient = 1;
|
||
|
|
||
|
(*pfnFreeRoutines[ROUTINE_INDEX(*pTypeFormat)])(
|
||
|
&StubMsg,
|
||
|
(unsigned char *)pType,
|
||
|
pTypeFormat);
|
||
|
}
|
||
|
}
|
||
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetExceptionCode());
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTypeMarshal::GetUnmarshalClass
|
||
|
//
|
||
|
// Synopsis: Get the class ID.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
STDMETHODIMP CTypeMarshal::GetUnmarshalClass(
|
||
|
REFIID riid,
|
||
|
LPVOID pv,
|
||
|
DWORD dwDestContext,
|
||
|
LPVOID pvDestContext,
|
||
|
DWORD mshlflags,
|
||
|
CLSID * pClassID)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
*pClassID = CLSID_TypeFactory;
|
||
|
}
|
||
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTypeMarshal::GetMarshalSizeMax
|
||
|
//
|
||
|
// Synopsis: Get maximum size of marshalled moniker.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
STDMETHODIMP CTypeMarshal::GetMarshalSizeMax(
|
||
|
REFIID riid,
|
||
|
LPVOID pv,
|
||
|
DWORD dwDestContext,
|
||
|
LPVOID pvDestContext,
|
||
|
DWORD mshlflags,
|
||
|
DWORD *pSize)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
*pSize = sizeof(_offset) + sizeof(_length) + _length;
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTypeMarshal::MarshalInterface
|
||
|
//
|
||
|
// Synopsis: Marshal moniker into a stream.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
STDMETHODIMP CTypeMarshal::MarshalInterface(
|
||
|
IStream * pStream,
|
||
|
REFIID riid,
|
||
|
void * pv,
|
||
|
DWORD dwDestContext,
|
||
|
LPVOID pvDestContext,
|
||
|
DWORD mshlflags)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
ULONG cb;
|
||
|
|
||
|
hr = pStream->Write(&_offset, sizeof(_offset), &cb);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = pStream->Write(&_length, sizeof(_length), &cb);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = pStream->Write(_pFormatString, _length, &cb);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTypeMarshal::UnmarshalInterface
|
||
|
//
|
||
|
// Synopsis: Unmarshal moniker from a stream.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
STDMETHODIMP CTypeMarshal::UnmarshalInterface(
|
||
|
IStream * pStream,
|
||
|
REFIID riid,
|
||
|
void ** ppv)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
ULONG cb;
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
//Validate parameters.
|
||
|
*ppv = NULL;
|
||
|
|
||
|
hr = pStream->Read(&_offset, sizeof(_offset), &cb);
|
||
|
if(SUCCEEDED(hr) &&
|
||
|
(sizeof(_offset) == cb))
|
||
|
{
|
||
|
hr = pStream->Read(&_length, sizeof(_length), &cb);
|
||
|
if(SUCCEEDED(hr) &&
|
||
|
(sizeof(_length) == cb))
|
||
|
{
|
||
|
_pFormatString = (PFORMAT_STRING) I_RpcAllocate(_length);
|
||
|
if(_pFormatString != NULL)
|
||
|
{
|
||
|
hr = pStream->Read((void *) _pFormatString, _length, &_length);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = QueryInterface(riid, ppv);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTypeMarshal::ReleaseMarshalData
|
||
|
//
|
||
|
// Synopsis: Release a marshalled class moniker.
|
||
|
// Just seek to the end of the marshalled class moniker.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
STDMETHODIMP CTypeMarshal::ReleaseMarshalData(
|
||
|
IStream * pStream)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
ULONG cb;
|
||
|
|
||
|
hr = pStream->Read(&_offset, sizeof(_offset), &cb);
|
||
|
if(SUCCEEDED(hr) &&
|
||
|
(sizeof(_offset) == cb))
|
||
|
{
|
||
|
hr = pStream->Read(&_length, sizeof(_length), &cb);
|
||
|
if(SUCCEEDED(hr) &&
|
||
|
(sizeof(_length) == cb))
|
||
|
{
|
||
|
LARGE_INTEGER liSize;
|
||
|
|
||
|
liSize.LowPart = _length;
|
||
|
liSize.HighPart = 0;
|
||
|
hr = pStream->Seek(liSize, STREAM_SEEK_CUR, NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTypeMarshal::DisconnectObject
|
||
|
//
|
||
|
// Synopsis: Disconnect the object.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
STDMETHODIMP CTypeMarshal::DisconnectObject(
|
||
|
DWORD dwReserved)
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|