windows-nt/Source/XPSP1/NT/com/rpc/ndr20/tiutil.cxx
2020-09-26 16:20:57 +08:00

432 lines
12 KiB
C++

// Copyright (c) 1993-2000 Microsoft Corporation
#include <windows.h>
#include <ole2.h>
#include <oleauto.h>
#include <typegen.h>
#include <tiutil.h>
#define ASSERT(x)
#define UNREACHED 0
//---------------------------------------------------------------------
// Utilities
//---------------------------------------------------------------------
/***
*PUBLIC HRESULT GetPrimaryInterface
*Purpose:
* Given a TypeInfo describing a Coclass, search for and return
* type TypeInfo that describes that class' primary interface.
*
*Entry:
* ptinfo = the TypeInfo of the base class.
*
*Exit:
* return value = HRESULT
*
* *ptinfoPrimary = the TypeInfo of the primary interface, NULL
* if the class does not have a primary interface.
*
***********************************************************************/
HRESULT
GetPrimaryInterface(ITypeInfo *ptinfo, ITypeInfo **pptinfoPri)
{
BOOL fIsDual;
TYPEKIND tkind;
HRESULT hresult;
HREFTYPE hreftype;
int impltypeflags;
TYPEATTR *ptattr;
unsigned int iImplType, cImplTypes;
ITypeInfo *ptinfoRef;
ptinfoRef = NULL;
IfFailGo(ptinfo->GetTypeAttr(&ptattr), Error);
cImplTypes = ptattr->cImplTypes;
tkind = ptattr->typekind;
ptinfo->ReleaseTypeAttr(ptattr);
if(tkind != TKIND_COCLASS)
return E_INVALIDARG;
// Look for the interface marked [default] and not [source]
for(iImplType = 0; iImplType < cImplTypes; ++iImplType){
IfFailGo(ptinfo->GetImplTypeFlags(iImplType, &impltypeflags), Error);
if(IMPLTYPEFLAG_FDEFAULT == (impltypeflags & (IMPLTYPEFLAG_FDEFAULT | IMPLTYPEFLAG_FSOURCE)))
{
// Found It!
IfFailGo(ptinfo->GetRefTypeOfImplType(iImplType, &hreftype), Error);
IfFailGo(ptinfo->GetRefTypeInfo(hreftype, &ptinfoRef), Error);
// If its dual, get the interface portion
IfFailGo(ptinfoRef->GetTypeAttr(&ptattr), Error);
fIsDual = (ptattr->wTypeFlags & TYPEFLAG_FDUAL)
&& (ptattr->typekind == TKIND_DISPATCH);
ptinfoRef->ReleaseTypeAttr(ptattr);
if (fIsDual) {
IfFailGo(ptinfoRef->GetRefTypeOfImplType((UINT)-1, &hreftype), Error);
IfFailGo(ptinfoRef->GetRefTypeInfo(hreftype, pptinfoPri), Error);
ptinfoRef->Release();
}
else {
*pptinfoPri = ptinfoRef;
}
return NOERROR;
}
}
// NotFound
*pptinfoPri = NULL;
return NOERROR;
Error:
if(ptinfoRef != NULL)
ptinfoRef->Release();
return hresult;
}
HRESULT
VarVtOfIface(ITypeInfo FAR* ptinfo,
TYPEATTR FAR* ptattr,
PARAMINFO *pPinfo)
{
HRESULT hresult;
switch(ptattr->typekind){
case TKIND_DISPATCH:
if ((ptattr->wTypeFlags & TYPEFLAG_FDUAL) == 0) {
// regular (non-dual) dispinterface is just VT_DISPATCH.
pPinfo->vt = VT_DISPATCH;
// don't have to set up *pguid, since not VT_INTERFACE
break;
}
// The interface typeinfo version of a dual interface has the same
// same guid as the dispinterface portion does, hence we can just use
// the dispinterface guid here.
/* FALLTHROUGH */
case TKIND_INTERFACE:
pPinfo->vt = VT_INTERFACE;
pPinfo->iid = ptattr->guid;
break;
default:
ASSERT(UNREACHED);
hresult = DISP_E_BADVARTYPE;
goto Error;
}
hresult = NOERROR;
Error:;
return hresult;
}
HRESULT
VarVtOfUDT(ITypeInfo FAR* ptinfo,
TYPEDESC FAR* ptdesc,
PARAMINFO *pPinfo)
{
HRESULT hresult;
TYPEATTR FAR* ptattrRef;
ITypeInfo FAR* ptinfoRef;
BOOLEAN fReleaseAttr = TRUE;
ASSERT(ptdesc->vt == VT_USERDEFINED);
ptinfoRef = NULL;
ptattrRef = NULL;
IfFailGo(ptinfo->GetRefTypeInfo(ptdesc->hreftype, &ptinfoRef), Error);
IfFailGo(ptinfoRef->GetTypeAttr(&ptattrRef), Error);
pPinfo->cbAlignment = ptattrRef->cbAlignment - 1;
switch (ptattrRef->typekind) {
case TKIND_ENUM:
pPinfo->vt = VT_I4;
hresult = NOERROR;
break;
case TKIND_ALIAS:
hresult = VarVtOfTypeDesc(ptinfoRef,
&ptattrRef->tdescAlias,
pPinfo);
if ((pPinfo->vt & (~VT_BYREF)) == VT_CARRAY)
{
if (pPinfo->pArray != NULL && pPinfo->pTypeAttr == NULL) // immediate upper level
{
fReleaseAttr = FALSE;
pPinfo->pTypeInfo->AddRef();
pPinfo->pTypeAttr = ptattrRef;
}
}
break;
case TKIND_DISPATCH:
case TKIND_INTERFACE:
hresult = VarVtOfIface(ptinfoRef, ptattrRef, pPinfo);
break;
case TKIND_COCLASS:
{ TYPEATTR FAR* ptattrPri;
ITypeInfo FAR* ptinfoPri;
if((hresult = GetPrimaryInterface(ptinfoRef, &ptinfoPri)) == NOERROR){
if((hresult = ptinfoPri->GetTypeAttr(&ptattrPri)) == NOERROR){
hresult = VarVtOfIface(ptinfoPri, ptattrPri, pPinfo);
ptinfoPri->ReleaseTypeAttr(ptattrPri);
}
ptinfoPri->Release();
}
}
break;
// this is a struct, handle indiviudal member later.
case TKIND_RECORD:
pPinfo->vt= VT_USERDEFINED;
(*pPinfo).pTypeInfo = ptinfoRef;
ptinfoRef->AddRef();
break;
default:
IfFailGo(DISP_E_BADVARTYPE, Error);
break;
}
Error:;
if(ptinfoRef != NULL){
if(ptattrRef != NULL && fReleaseAttr)
ptinfoRef->ReleaseTypeAttr(ptattrRef);
ptinfoRef->Release();
}
return hresult;
}
/***
*PRIVATE HRESULT VarVtOfTypeDesc
*Purpose:
* Convert the given typeinfo TYPEDESC into a VARTYPE that can be
* represented in a VARIANT. For some this is a 1:1 mapping, for
* others we convert to a (possibly machine dependent, eg VT_INT->VT_I2)
* base type, and others we cant represent in a VARIANT.
*
* Now we are supporting multiple levels of pointer indirection. To support
* this, we created an internal VT_MULTIINDIRECTIONS. If vt in PARAMINFO is
* VT_MULTIINDIRECTIONS, the real vt is on PARAMINFO::realvt, and VT_BYREF
* must be true; additional levels of indirection is saved in PARAMINFO::
* lLevelCount.
*
*Entry:
* ptinfo =
* ptdesc = * to the typedesc to convert
* pvt =
* pguid =
*
*Exit:
* return value = HRESULT
*
* *pvt = a VARTYPE that may be stored in a VARIANT.
* *pguid = a guid for a custom interface.
*
*
* Following is a summary of how types are represented in typeinfo.
* Note the difference between the apparent levels of indirection
* between IDispatch* / DispFoo*, and DualFoo*.
*
* I2 => VT_I2
* I2* => VT_PTR - VT_I2
*
* IDispatch * => VT_DISPATCH
* IDispatch ** => VT_PTR - VT_DISPATCH
* DispFoo * => VT_DISPATCH
* DispFoo ** => VT_PTR - VT_DISPATCH
* DualFoo * => VT_PTR - VT_INTERFACE (DispIID)
* DualFoo ** => VT_PTR - VT_PTR - VT_INTERFACE (DispIID)
* IFoo * => VT_PTR - VT_INTERFACE (IID)
* IFoo ** => VT_PTR - VT_PTR - VT_INTERFACE (IID)
*
***********************************************************************/
HRESULT
VarVtOfTypeDesc(ITypeInfo FAR* ptinfo,
TYPEDESC FAR* ptdesc,
PARAMINFO *pPinfo)
{
HRESULT hresult = NOERROR;
switch (ptdesc->vt) {
case VT_I2:
case VT_I4:
case VT_R4:
case VT_R8:
case VT_CY:
case VT_DATE:
case VT_BSTR:
case VT_DISPATCH:
case VT_ERROR:
case VT_BOOL:
case VT_VARIANT:
case VT_UNKNOWN:
case VT_DECIMAL:
case VT_I1:
case VT_UI1:
case VT_UI2:
case VT_UI4:
case VT_I8:
case VT_UI8:
case VT_HRESULT:
case VT_LPSTR:
case VT_LPWSTR:
case VT_FILETIME:
case VT_STREAM:
case VT_STORAGE:
pPinfo->vt = ptdesc->vt;
break;
case VT_INT:
pPinfo->vt = VT_I4;
break;
case VT_UINT:
pPinfo->vt = VT_UI4;
break;
case VT_USERDEFINED:
hresult = VarVtOfUDT(ptinfo, ptdesc, pPinfo);
break;
case VT_PTR:
switch (ptdesc->lptdesc->vt)
{
// VT_PTR + VT_DISPATCH: it's IDispatch**
case VT_DISPATCH:
case VT_UNKNOWN:
case VT_STREAM:
case VT_STORAGE:
pPinfo->vt = ptdesc->lptdesc->vt |VT_BYREF;
hresult = NOERROR;
break;
// Special case: dispinterface** (represented by VT_PTR-VT_PTR-VT_USERDEFINED-TKIND_DISPATCH
case VT_PTR:
if ( VT_USERDEFINED == ptdesc->lptdesc->lptdesc->vt )
{
// we need to read forward in VT_PTR-VT_PTR-VT_UDT case for
// dispinterface **
hresult = VarVtOfUDT(ptinfo, ptdesc->lptdesc->lptdesc,pPinfo);
if (hresult == NOERROR)
{
if (pPinfo->vt == VT_INTERFACE)
{
pPinfo->vt = (VT_BYREF | VT_INTERFACE);
}
else if (pPinfo->vt == VT_DISPATCH)
{
pPinfo->vt = (VT_BYREF | VT_DISPATCH);
}
else if ( pPinfo->vt == VT_MULTIINDIRECTIONS )
{
// add an additional level if it's ** already
pPinfo->lLevelCount++;
}
else
{
// VT_PTR-VT_PTR-something_other_than_interface:
pPinfo->realvt = pPinfo->vt;
pPinfo->vt = VT_MULTIINDIRECTIONS;
if ( pPinfo->realvt & VT_BYREF )
pPinfo->lLevelCount = 2;
else
{
pPinfo->realvt = pPinfo->realvt | VT_BYREF;
pPinfo->lLevelCount = 1;
}
}
}
break;
}
// fall through if not VT_PTR-VT_PTR-VT_USERDEFINED case
default:
hresult = VarVtOfTypeDesc(ptinfo, ptdesc->lptdesc, pPinfo);
if(hresult == NOERROR)
{
if(pPinfo->vt & VT_BYREF)
{
pPinfo->realvt = pPinfo->vt;
pPinfo->vt = VT_MULTIINDIRECTIONS;
pPinfo->lLevelCount = 1;
}
else if ( pPinfo->vt == VT_MULTIINDIRECTIONS )
{
pPinfo->lLevelCount++;
}
else if ((pPinfo->vt != VT_INTERFACE) && (pPinfo->vt != VT_DISPATCH))
{
// need to get rid of one level of indirection for interface
pPinfo->vt |= VT_BYREF;
}
break;
}
}
break;
case VT_SAFEARRAY:
hresult = VarVtOfTypeDesc(ptinfo, ptdesc->lptdesc, pPinfo);
if(hresult == NOERROR){
if(pPinfo->vt & (VT_BYREF | VT_ARRAY)){
// error if nested array or array of pointers
hresult = DISP_E_BADVARTYPE;
break;
}
pPinfo->vt |= VT_ARRAY;
}
break;
// VT_CARRAY in fact is fix length array.
case VT_CARRAY:
pPinfo->vt = ptdesc->vt;
(*pPinfo).pArray = ptdesc->lpadesc;
(*pPinfo).pTypeInfo = ptinfo;
ptinfo->AddRef();
break;
default:
ASSERT(UNREACHED);
hresult = DISP_E_BADVARTYPE;
break;
}
return hresult;
}
//
// Simple wrapper for VarVtOfTypeDesc that only returns
// the vt, not an entire PARAMINFO structure. Used
// by the callframe code in ole32.
//
EXTERN_C
HRESULT NdrpVarVtOfTypeDesc(IN ITypeInfo *pTypeInfo,
IN TYPEDESC *ptdesc,
OUT VARTYPE *vt)
{
PARAMINFO pinfo;
HRESULT hr;
if (vt == NULL)
return E_POINTER;
*vt = VT_EMPTY;
hr = VarVtOfTypeDesc(pTypeInfo, ptdesc, &pinfo);
if (SUCCEEDED(hr))
*vt = pinfo.vt;
return hr;
}