|
|
// 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; }
|