Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1321 lines
44 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1999.
//
// File: implib.cxx
//
// Contents: import lib functions
//
// Classes: NODE_MANAGER
//
// Functions: TypelibError
// TypeinfoError
// GetStringFromGuid
// AddTypeLibraryMembers
//
// History: 5-02-95 stevebl Created
//
//----------------------------------------------------------------------------
#pragma warning ( disable : 4514 )
#include "tlcommon.hxx"
#include "tlgen.hxx"
#include "tllist.hxx"
#include "becls.hxx"
#include "walkctxt.hxx"
// Initialize an instance of a type library list.
// This way it will clean itself up as necessary.
CTypeLibraryList gtllist;
extern short ImportLevel;
//+---------------------------------------------------------------------------
//
// Function: TypelibError
//
// Synopsis: Report generic type library error and exit.
//
// Arguments: [szFile] - file associated with the error
//
// History: 5-02-95 stevebl Created
//
//----------------------------------------------------------------------------
void TypelibError(char * szFile, HRESULT /* UNREF hr */)
{
RpcError(NULL, 0, ERR_TYPELIB, szFile);
exit(ERR_TYPELIB);
}
//+---------------------------------------------------------------------------
//
// Function: TypeinfoError
//
// Synopsis: Report generic type info error and exit.
//
// History: 5-02-95 stevebl Created
//
//----------------------------------------------------------------------------
void TypeinfoError(HRESULT /* UNREF hr */)
{
RpcError(NULL, 0, ERR_TYPEINFO, NULL);
exit(ERR_TYPEINFO);
}
//+---------------------------------------------------------------------------
//
// Function: AddToGuidString
//
// Synopsis: Private helper function for GetStringFromGuid.
// Adds exactly cch hex characters to the string pch.
//
// Arguments: [pch] - pointer to the next available position in the string
// buffer
// [cch] - number of characters to add to the string buffer
// [uVal] - value to be converted to text representation
//
// History: 5-02-95 stevebl Created
//
// Modifies: pch is advanced by cch characters (i.e. left pointing to the
// next available position in the buffer).
//
// Notes: pch must be large enough to accept the characters.
// The resulting string is not null terminated.
//
//----------------------------------------------------------------------------
void AddToGuidString(char * &pch, unsigned cch, unsigned long uVal)
{
char bVal;
unsigned long uMask = 0xf << ((cch - 1) * 4);
while (cch)
{
bVal = (char)((uVal & uMask) >> ((cch - 1) * 4));
if (bVal < 10)
*(pch++) = char( '0' + bVal );
else
*(pch++) = char ( 'a' + bVal - 10 );
uMask >>= 4;
cch--;
}
}
//+---------------------------------------------------------------------------
//
// Function: GetStringFromGuid
//
// Synopsis: returns the string representation of a guid
//
// Arguments: [g] - guid
//
// Returns: pointer to a newly allocated string
//
// History: 5-02-95 stevebl Created
//
// Notes: It is up to the caller to free the resulting string.
//
//----------------------------------------------------------------------------
char * GetStringFromGuid(GUID &g)
{
char * sz = new char [37];
char * pch = sz;
AddToGuidString(pch, 8, g.Data1);
*(pch++) = '-';
AddToGuidString(pch, 4, g.Data2);
*(pch++) = '-';
AddToGuidString(pch, 4, g.Data3);
*(pch++) = '-';
int i;
for (i = 0; i < 2; i++)
{
AddToGuidString(pch, 2, g.Data4[i]);
}
*(pch++) = '-';
for (; i < 8; i++)
{
AddToGuidString(pch, 2, g.Data4[i]);
}
*(pch++) = '\0';
return sz;
}
struct NODE_MANAGER_ELEMENT
{
ITypeInfo * pti;
named_node * pskl;
NODE_MANAGER_ELEMENT * pNext;
};
//+---------------------------------------------------------------------------
//
// Class: NODE_MANAGER
//
// Purpose: Maintains an ordered list of every ITypeInfo for which a
// node_skl has been generated.
//
// Interface: GetNode -- retrieve a node_skl * from a type library
//
// History: 5-02-95 stevebl Created
//
// Notes: A client can call GetNode() to get a node_skl * from an
// ITypeInfo pointer. If one has previously been generated then
// the caller will get a pointer to the previously generated
// node. Otherwise, GetNode() will call ExpandTI to generate one.
//
// This class exists as a mechanism to avoid infinite recursion
// when importing type infos with cyclic type dependencies.
//
//----------------------------------------------------------------------------
class NODE_MANAGER
{
private:
NODE_MANAGER_ELEMENT * pHead;
void ExpandTI(named_node * &pNode, ITypeInfo * pti);
node_skl * GetNodeFromTYPEDESC(TYPEDESC tdesc, ITypeInfo * pti);
named_node * GetNodeFromVARDESC(VARDESC vdesc, ITypeInfo * pti);
named_node * GetNodeFromFUNCDESC(FUNCDESC fdesc, ITypeInfo *pti);
void SetIDLATTRS(named_node * pNode, IDLDESC idldesc);
void AddMembers(MEMLIST * pNode, TYPEATTR * ptattr, ITypeInfo * pti);
expr_node * GetValueOfConstant(VARIANT * pVar);
public:
NODE_MANAGER()
{
pHead = NULL;
}
~NODE_MANAGER()
{
NODE_MANAGER_ELEMENT * pNext;
while (pHead)
{
pHead->pti->Release();
pNext = pHead->pNext;
delete(pHead);
pHead = pNext;
};
}
node_skl * GetNode(ITypeInfo * pti);
} gNodeManager;
BOOL FAddImportLib(char * szLibraryFileName)
{
return gtllist.Add(szLibraryFileName);
}
BOOL FIsLibraryName(char * szName)
{
return (NULL != gtllist.FindLibrary(szName));
}
extern SymTable * pBaseSymTbl;
node_href::~node_href()
{
if (pTypeInfo)
((ITypeInfo *)pTypeInfo)->Release();
}
extern IINFODICT * pInterfaceInfoDict;
char * GenIntfName();
//+---------------------------------------------------------------------------
//
// Member: node_href::Resolve
//
// Synopsis: Expands a referenced type info into a complete type graph.
//
// Returns: Pointer to the expanded typegraph.
//
// History: 5-02-95 stevebl Created
//
//----------------------------------------------------------------------------
named_node * node_href::Resolve()
{
char * sz;
named_node * pReturn = (named_node *)GetChild();
if (!pReturn)
{
pInterfaceInfoDict->StartNewInterface();
// start a dummy interface for intervening stuff
node_interface * pOuter = new node_interface;
pOuter->SetSymName( GenIntfName() );
pOuter->SetFileNode( GetDefiningFile() );
pInterfaceInfoDict->SetInterfaceNode( pOuter );
pReturn = (named_node *)gNodeManager.GetNode((ITypeInfo*)pTypeInfo);
SetChild(pReturn);
sz = pReturn->GetSymName();
if ( sz )
SetSymName(sz);
pInterfaceInfoDict->EndNewInterface();
}
return pReturn;
}
//+---------------------------------------------------------------------------
//
// Member: NODE_MANAGER::GetNode
//
// Synopsis: Gets a type graph node from a type info pointer.
//
// Arguments: [pti] - type info pointer
//
// Returns: pointer to the type graph described by the type info
//
// History: 5-02-95 stevebl Created
//
//----------------------------------------------------------------------------
node_skl * NODE_MANAGER::GetNode(ITypeInfo * pti)
{
NODE_MANAGER_ELEMENT ** ppThis = &pHead;
while (*ppThis && (*ppThis)->pti <= pti)
{
if ((*ppThis)->pti == pti)
return (*ppThis)->pskl;
ppThis = &((*ppThis)->pNext);
}
NODE_MANAGER_ELEMENT * pNew = new NODE_MANAGER_ELEMENT;
pNew->pti = pti;
// Make sure no one can release this ITypeInfo pointer out from under us.
// The corresponding release() occurs in NODE_MANAGER's destructor.
pti->AddRef();
// insert the new node into the table
pNew->pNext = *ppThis;
*ppThis = pNew;
// expand the node
ExpandTI(pNew->pskl, pti);
((named_node*)(pNew->pskl))->SetFileNode(pInterfaceInfoDict->GetInterfaceNode()->GetDefiningFile() );
((named_node*)(pNew->pskl))->SetDefiningTLB(pInterfaceInfoDict->GetInterfaceNode()->GetDefiningFile() );
return pNew->pskl;
}
//+---------------------------------------------------------------------------
//
// Member: NODE_MANAGER::ExpandTI
//
// Synopsis: This is where all the work gets done.
// Takes a type info pointer and expands it into a type graph.
//
// Arguments: [pti] - pointer to the type info
//
// Returns: pointer to the type graph
//
// History: 5-02-95 stevebl Created
//
//----------------------------------------------------------------------------
void NODE_MANAGER::ExpandTI(named_node * &pNode, ITypeInfo * pti)
{
TYPEATTR * ptattr;
HRESULT hr;
BSTR bstrName;
pNode = NULL;
hr = pti->GetTypeAttr(&ptattr);
pti->GetDocumentation(-1, &bstrName, NULL, NULL, NULL);
char * szName = TranscribeO2A( bstrName );
LateBound_SysFreeString(bstrName);
BOOL fExtractGuid = TRUE;
switch(ptattr->typekind)
{
case TKIND_MODULE:
pNode = new node_module();
pNode->SetSymName(szName);
// Add properties and methods
AddMembers((MEMLIST *)((node_module *)pNode), ptattr, pti);
break;
case TKIND_DISPATCH:
// The code under the if has never been run due to the bug in the condition.
// The condition according to the comment below should read as in the next line.
//
// if ( ! (ptattr->wTypeFlags & (TYPEFLAG_FOLEAUTOMATION | TYPEFLAG_FDUAL)) )
//
// However, fixing the line according to the original intentions brought in
// a regression because the code paths have changed.
// Hence, this has been commented out as a workaround for the VC 5.0 release
// to force the code to execute like previously.
//
/*
if ( 0 == ptattr->wTypeFlags & (TYPEFLAG_FOLEAUTOMATION | TYPEFLAG_FDUAL) )
{
pNode = new node_dispinterface();
pNode->SetSymName(szName);
// Ignore impltypes, add properties and methods
AddMembers((MEMLIST *)((node_dispinterface *)pNode), ptattr, pti);
break;
}
*/
// if TYPEFLAG_FOLEAUTOMATION or TYPEFLAG_FDUAL is set,
// erase it's impltype (which will be IDispatch since it is
// really a dispinterface) then fall through and treat it as a
// normal interface
ptattr->cImplTypes = 0;
// fall through
case TKIND_INTERFACE:
{
pNode = new node_interface();
// consider processing all attributes
if ( ( ptattr->wTypeFlags & ( TYPEFLAG_FOLEAUTOMATION | TYPEFLAG_FDUAL ) ) != 0 )
{
( ( node_interface* ) pNode )->HasOLEAutomation( TRUE );
}
pNode->SetSymName(szName);
// Add impltype as base interface reference
if (ptattr->cImplTypes)
{
ITypeInfo * ptiRef;
HREFTYPE hrt;
hr = pti->GetRefTypeOfImplType(0, &hrt);
hr = pti->GetRefTypeInfo(hrt, &ptiRef);
if (FAILED(hr))
{
TypeinfoError(hr);
}
node_interface_reference * pir =
new node_interface_reference((node_interface *)GetNode(ptiRef));
int implflags;
hr = pti->GetImplTypeFlags(0, &implflags);
if (implflags & IMPLTYPEFLAG_FDEFAULT)
{
pir->SetAttribute(ATTR_DEFAULT);
}
if (implflags & IMPLTYPEFLAG_FSOURCE)
{
pir->SetAttribute(new node_member_attr(MATTR_SOURCE));
}
if (implflags & IMPLTYPEFLAG_FDEFAULTVTABLE)
{
pir->SetAttribute(new node_member_attr(MATTR_DEFAULTVTABLE));
}
if (implflags & IMPLTYPEFLAG_FRESTRICTED)
{
pir->SetAttribute(new node_member_attr(MATTR_RESTRICTED));
}
((node_interface *)pNode)->SetMyBaseInterfaceReference(pir);
ptiRef->Release();
// NOTE - Multiple inheritance is not supported.
}
else
{
if (0 == _stricmp(szName, "IUnknown"))
((node_interface *)pNode)->SetValidRootInterface();
}
// Add properties and methods as children
AddMembers((MEMLIST *)((node_interface *)pNode), ptattr, pti);
}
break;
case TKIND_COCLASS:
pNode = new node_coclass();
pNode->SetSymName(szName);
// Add impltypes
{
unsigned cImplTypes = ptattr->cImplTypes;
while (cImplTypes--)
{
ITypeInfo * ptiRef;
HREFTYPE hrt;
hr = pti->GetRefTypeOfImplType(cImplTypes, &hrt);
hr = pti->GetRefTypeInfo(hrt, &ptiRef);
if (FAILED(hr))
{
TypeinfoError(hr);
}
node_interface_reference * pir =
new node_interface_reference((node_interface *)GetNode(ptiRef));
int implflags;
hr = pti->GetImplTypeFlags(cImplTypes, &implflags);
if (implflags & IMPLTYPEFLAG_FDEFAULT)
{
pir->SetAttribute(ATTR_DEFAULT);
}
if (implflags & IMPLTYPEFLAG_FSOURCE)
{
pir->SetAttribute(new node_member_attr(MATTR_SOURCE));
}
if (implflags & IMPLTYPEFLAG_FDEFAULTVTABLE)
{
pir->SetAttribute(new node_member_attr(MATTR_DEFAULTVTABLE));
}
if (implflags & IMPLTYPEFLAG_FRESTRICTED)
{
pir->SetAttribute(new node_member_attr(MATTR_RESTRICTED));
}
((node_coclass *)pNode)->AddFirstMember(pir);
ptiRef->Release();
}
}
break;
case TKIND_ALIAS:
pNode = new node_def(szName);
// add the type as a child
pNode->SetChild(GetNodeFromTYPEDESC(ptattr->tdescAlias, pti));
pNode->SetAttribute(new node_type_attr(TATTR_PUBLIC));
fExtractGuid = FALSE;
break;
case TKIND_ENUM:
pNode = new node_enum(szName);
// add enumeration fields
AddMembers((MEMLIST *)((node_enum *)pNode), ptattr, pti);
fExtractGuid = FALSE;
( ( node_enum * ) pNode )->SetZeePee( ptattr->cbAlignment );
break;
case TKIND_RECORD:
pNode = new node_struct(szName);
// add members
AddMembers((MEMLIST *)((node_struct *)pNode), ptattr, pti);
fExtractGuid = FALSE;
( ( node_struct * ) pNode )->SetZeePee( ptattr->cbAlignment );
break;
case TKIND_UNION:
pNode = new node_union(szName);
// add members
AddMembers((MEMLIST *)((node_union *)pNode), ptattr, pti);
fExtractGuid = FALSE;
( ( node_union * ) pNode )->SetZeePee( ptattr->cbAlignment );
break;
default:
MIDL_ASSERT(!"Illegal TKIND");
break;
}
// make sure that all the TYPEDESC flags are preserved
pNode->SetAttribute(new node_constant_attr(
new expr_constant(ptattr->wTypeFlags), ATTR_TYPEDESCATTR));
// and set each individual flag that we know about as of this writing
if (ptattr->wTypeFlags & TYPEFLAG_FLICENSED)
{
pNode->SetAttribute(new node_type_attr(TATTR_LICENSED));
}
if (ptattr->wTypeFlags & TYPEFLAG_FAPPOBJECT)
{
pNode->SetAttribute(new node_type_attr(TATTR_APPOBJECT));
}
if (ptattr->wTypeFlags & TYPEFLAG_FCONTROL)
{
pNode->SetAttribute(new node_type_attr(TATTR_CONTROL));
}
if (ptattr->wTypeFlags & TYPEFLAG_FDUAL)
{
pNode->SetAttribute(new node_type_attr(TATTR_DUAL));
}
if (ptattr->wTypeFlags & TYPEFLAG_FPROXY)
{
pNode->SetAttribute(new node_type_attr(TATTR_PROXY));
}
if (ptattr->wTypeFlags & TYPEFLAG_FNONEXTENSIBLE)
{
pNode->SetAttribute(new node_type_attr(TATTR_NONEXTENSIBLE));
}
if (ptattr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION)
{
pNode->SetAttribute(new node_type_attr(TATTR_OLEAUTOMATION));
}
if (ptattr->wTypeFlags & TYPEFLAG_FRESTRICTED)
{
pNode->SetAttribute(new node_member_attr(MATTR_RESTRICTED));
}
if (ptattr->wTypeFlags & TYPEFLAG_FPREDECLID)
{
pNode->SetAttribute(new node_member_attr(MATTR_PREDECLID));
}
if (ptattr->wTypeFlags & TYPEFLAG_FHIDDEN)
{
pNode->SetAttribute(ATTR_HIDDEN);
}
if (fExtractGuid)
{
char * szGuid = GetStringFromGuid(ptattr->guid);
pNode->SetAttribute(new node_guid(szGuid));
}
pti->ReleaseTypeAttr(ptattr);
}
//+---------------------------------------------------------------------------
//
// Member: NODE_MANAGER::GetNodeFromTYPEDESC
//
// Synopsis: Returns part of a type graph from a TYPEDESC structure.
//
// Arguments: [tdesc] - the TYPEDESC
// [pti] - the type info from which the TYPEDESC was retrieved
//
// Returns: type graph node
//
// History: 5-02-95 stevebl Created
//
// Notes: There are currently a couple of problem base types:
// VT_CY, VT_BSTR, VT_VARIANT, VT_DISPATCH, and VT_UNKNOWN.
//
// These types are currently expanded by looking them up in the
// global symbol table. This works because currently oaidl.idl
// is always imported when an ODL library statement is
// ecountered. It would be nice to be able to remove our
// dependancy on oaidl.idl but before we can do that, we need to
// reimplement this code to expand these types in another way.
// (NOTE that because these are BASE TYPES in ODL, there is no
// way to place their definitions in a type library. This means
// that it is not sufficient to simply get their definitions
// from some standard type library such as STDLIB.TLB.)
//
//----------------------------------------------------------------------------
node_skl * NODE_MANAGER::GetNodeFromTYPEDESC(TYPEDESC tdesc, ITypeInfo * pti)
{
node_skl * pReturn = NULL;
switch (tdesc.vt)
{
// base types
case VT_I2:
pReturn = new node_base_type(NODE_SHORT, ATTR_SIGNED);
((named_node *)pReturn)->SetSymName("short");
break;
case VT_I4:
pReturn = new node_base_type(NODE_LONG, ATTR_SIGNED);
((named_node *)pReturn)->SetSymName("long");
break;
case VT_R4:
pReturn = new node_base_type(NODE_FLOAT, ATTR_NONE);
((named_node *)pReturn)->SetSymName("float");
break;
case VT_R8:
pReturn = new node_base_type(NODE_DOUBLE, ATTR_NONE);
((named_node *)pReturn)->SetSymName("double");
break;
case VT_I1:
pReturn = new node_base_type(NODE_CHAR, ATTR_SIGNED);
((named_node *)pReturn)->SetSymName("char");
break;
case VT_UI1:
pReturn = new node_base_type(NODE_CHAR, ATTR_UNSIGNED);
((named_node *)pReturn)->SetSymName("char");
break;
case VT_UI2:
pReturn = new node_base_type(NODE_SHORT, ATTR_UNSIGNED);
((named_node *)pReturn)->SetSymName("short");
break;
case VT_UI4:
pReturn = new node_base_type(NODE_LONG, ATTR_UNSIGNED);
((named_node *)pReturn)->SetSymName("long");
break;
case VT_I8:
pReturn = new node_base_type(NODE_INT64, ATTR_SIGNED);
((named_node *)pReturn)->SetSymName("int64");
break;
case VT_UI8:
pReturn = new node_base_type(NODE_INT64, ATTR_UNSIGNED);
((named_node *)pReturn)->SetSymName("int64");
break;
case VT_INT:
pReturn = new node_base_type(NODE_INT, ATTR_SIGNED);
((named_node *)pReturn)->SetSymName("INT");
break;
case VT_UINT:
pReturn = new node_base_type(NODE_INT, ATTR_UNSIGNED);
((named_node *)pReturn)->SetSymName("UINT");
break;
case VT_VOID:
pReturn = new node_base_type(NODE_VOID, ATTR_NONE);
((named_node *)pReturn)->SetSymName("void");
break;
case VT_BOOL:
pReturn = new node_base_type(NODE_BOOLEAN, ATTR_NONE);
((named_node *)pReturn)->SetSymName("BOOLEAN");
break;
// simple ODL base types (not base types in IDL)
case VT_HRESULT:
pReturn = new node_base_type(NODE_SHORT, ATTR_NONE);
((named_node *)pReturn)->SetSymName("HRESULT");
break;
case VT_DATE:
pReturn = new node_base_type(NODE_LONGLONG, ATTR_NONE);
((named_node *)pReturn)->SetSymName("DATE");
break;
case VT_LPSTR:
pReturn = new node_base_type(NODE_LONGLONG, ATTR_NONE);
((named_node *)pReturn)->SetSymName("LPSTR");
break;
case VT_LPWSTR:
pReturn = new node_base_type(NODE_LONGLONG, ATTR_NONE);
((named_node *)pReturn)->SetSymName("LPWSTR");
break;
case VT_ERROR:
pReturn = new node_base_type(NODE_INT64, ATTR_NONE);
((named_node *)pReturn)->SetSymName("SCODE");
break;
// complex ODL base types
case VT_DECIMAL:
{
SymKey key("DECIMAL", NAME_DEF);
pReturn = pBaseSymTbl->SymSearch(key);
}
break;
case VT_CY:
{
SymKey key("CURRENCY", NAME_DEF);
pReturn = pBaseSymTbl->SymSearch(key);
}
break;
case VT_BSTR:
{
SymKey key("BSTR", NAME_DEF);
pReturn = pBaseSymTbl->SymSearch(key);
}
break;
case VT_VARIANT:
{
SymKey key("VARIANT", NAME_DEF);
pReturn = pBaseSymTbl->SymSearch(key);
}
break;
case VT_DISPATCH:
{
SymKey key("IDispatch", NAME_DEF);
pReturn = new node_pointer(pBaseSymTbl->SymSearch(key));
}
break;
case VT_UNKNOWN:
{
SymKey key("IUnknown", NAME_DEF);
pReturn = new node_pointer(pBaseSymTbl->SymSearch(key));
}
break;
// complex types
case VT_PTR:
pReturn = new node_pointer(GetNodeFromTYPEDESC(*(tdesc.lptdesc), pti));
break;
case VT_SAFEARRAY:
pReturn = new node_safearray(GetNodeFromTYPEDESC(*(tdesc.lptdesc), pti));
break;
case VT_CARRAY:
{
node_skl * pCurrent = NULL;
node_skl * pPrev = NULL;
for (int i = 0; i < tdesc.lpadesc->cDims; i++)
{
pCurrent = new node_array(
new expr_constant(tdesc.lpadesc->rgbounds[i].lLbound),
new expr_constant((tdesc.lpadesc->rgbounds[i].cElements
+ tdesc.lpadesc->rgbounds[i].lLbound) - 1 )
);
if (pPrev)
{
pPrev->SetChild(pCurrent);
}
else
{
pReturn = pCurrent;
}
pPrev = pCurrent;
}
if (pCurrent)
(pCurrent)->SetChild(GetNodeFromTYPEDESC(tdesc.lpadesc->tdescElem, pti));
}
break;
case VT_USERDEFINED:
{
ITypeInfo * pRef;
HRESULT hr = pti->GetRefTypeInfo(tdesc.hreftype, &pRef);
if (FAILED(hr))
{
TypeinfoError(hr);
}
node_skl* pNode = GetNode(pRef);
NODE_T nk = pNode->NodeKind();
if ( nk == NODE_INTERFACE_REFERENCE || nk == NODE_INTERFACE )
{
pReturn = new node_interface_reference( (node_interface *) pNode );
}
else
{
pReturn = pNode;
}
pRef->Release();
}
break;
default:
MIDL_ASSERT(!"Illegal variant type found in a TYPEDESC");
break;
}
if (pReturn && (pReturn->NodeKind() == NODE_DEF) &&
pReturn->GetChild() &&
(pReturn->GetChild()->NodeKind() == NODE_FORWARD))
{
node_forward * pFwd = (node_forward *) pReturn->GetChild();
node_skl * pNewSkl = pFwd->ResolveFDecl();
if (pNewSkl)
{
pReturn = new node_def_fe(pReturn->GetSymName(), pNewSkl);
}
}
return pReturn;
}
//+---------------------------------------------------------------------------
//
// Member: NODE_MANAGER::AddMembers
//
// Synopsis: Generic routine to add type graph elements for variables and
// functions to a type graph element.
//
// Arguments: [pNode] - pointer to the parent type graph node's MEMLIST
// [ptattr] - pointer to the parent type info's TYPEATTR struct
// [pti] - pointer to the parent type info
//
// Returns: nothing
//
// Modifies: adds each new node to the MEMLIST referred to by pNode
//
// History: 5-02-95 stevebl Created
//
//----------------------------------------------------------------------------
void NODE_MANAGER::AddMembers(MEMLIST * pNode, TYPEATTR * ptattr, ITypeInfo * pti)
{
HRESULT hr;
named_node * pNew;
unsigned i = ptattr->cFuncs;
while (i--)
{
FUNCDESC *pfdesc;
hr = pti->GetFuncDesc(i, &pfdesc);
pNew = GetNodeFromFUNCDESC(*pfdesc, pti);
pNode->AddFirstMember(pNew);
pti->ReleaseFuncDesc(pfdesc);
}
i = ptattr->cVars;
while (i--)
{
VARDESC * pvdesc;
hr = pti->GetVarDesc(i, &pvdesc);
pNew = GetNodeFromVARDESC(*pvdesc, pti);
pNode->AddFirstMember(pNew);
pti->ReleaseVarDesc(pvdesc);
}
}
//+---------------------------------------------------------------------------
//
// Member: NODE_MANAGER::GetNodeFromVARDESC
//
// Synopsis: gets a type graph node from a VARDESC
//
// Arguments: [vdesc] - VARDESC describing the variable
// [pti] - type info containing the VARDESC
//
// Returns: type graph node describing the varible
//
// History: 5-02-95 stevebl Created
//
//----------------------------------------------------------------------------
named_node * NODE_MANAGER::GetNodeFromVARDESC(VARDESC vdesc, ITypeInfo * pti)
{
BSTR bstrName;
unsigned cNames;
pti->GetNames(vdesc.memid, &bstrName, 1, &cNames);
char * szName = TranscribeO2A( bstrName );
LateBound_SysFreeString(bstrName);
named_node *pNode;
if (vdesc.varkind == VAR_CONST)
{
expr_node * pExpr = GetValueOfConstant(vdesc.lpvarValue);
pNode = new node_label(szName, pExpr);
}
else
{
pNode = new node_field(szName);
}
pNode->SetBasicType(GetNodeFromTYPEDESC(vdesc.elemdescVar.tdesc, pti));
SetIDLATTRS(pNode, vdesc.elemdescVar.idldesc);
pNode->SetAttribute(new node_constant_attr(
new expr_constant(vdesc.wVarFlags), ATTR_VARDESCATTR));
if (vdesc.wVarFlags == VARFLAG_FREADONLY)
{
pNode->SetAttribute(new node_member_attr(MATTR_READONLY));
}
if (vdesc.wVarFlags == VARFLAG_FSOURCE)
{
pNode->SetAttribute(new node_member_attr(MATTR_SOURCE));
}
if (vdesc.wVarFlags == VARFLAG_FBINDABLE)
{
pNode->SetAttribute(new node_member_attr(MATTR_BINDABLE));
}
if (vdesc.wVarFlags == VARFLAG_FDISPLAYBIND)
{
pNode->SetAttribute(new node_member_attr(MATTR_DISPLAYBIND));
}
if (vdesc.wVarFlags == VARFLAG_FDEFAULTBIND)
{
pNode->SetAttribute(new node_member_attr(MATTR_DEFAULTBIND));
}
if (vdesc.wVarFlags == VARFLAG_FREQUESTEDIT)
{
pNode->SetAttribute(new node_member_attr(MATTR_REQUESTEDIT));
}
if (vdesc.wVarFlags == VARFLAG_FHIDDEN)
{
pNode->SetAttribute(ATTR_HIDDEN);
}
pNode->SetAttribute(new node_constant_attr(
new expr_constant(vdesc.memid), ATTR_ID ));
return pNode;
}
//+---------------------------------------------------------------------------
//
// Member: NODE_MANAGER::GetNodeFromFUNCDESC
//
// Synopsis: gets a type graph node from a FUNCDESC
//
// Arguments: [fdesc] - FUNCDESC describing the function
// [pti] - type info containing the FUNCDESC
//
// Returns: type graph node describing the function
//
// History: 5-02-95 stevebl Created
//
//----------------------------------------------------------------------------
named_node * NODE_MANAGER::GetNodeFromFUNCDESC(FUNCDESC fdesc, ITypeInfo *pti)
{
node_proc * pNode = new node_proc(ImportLevel, FALSE);
BSTR * rgbstrName = new BSTR [fdesc.cParams + 1];
unsigned cNames;
pti->GetNames(fdesc.memid, rgbstrName, fdesc.cParams + 1, &cNames);
char * szName = TranscribeO2A( rgbstrName[0] );
LateBound_SysFreeString( rgbstrName[0] );
pNode->SetSymName(szName);
if (fdesc.invkind == DISPATCH_PROPERTYGET
|| fdesc.funckind == FUNC_DISPATCH
|| (fdesc.elemdescFunc.paramdesc.wParamFlags & PARAMFLAG_FRETVAL) != 0)
{
/*
* Functions with the DISPATCH_PROPERTYGET attribute are special cases.
* Their return values in the type graph are always of type HRESULT.
* The last parameter of the function (after those listed in the fdesc)
* is a pointer to the return type listed in the fdesc and it has
* the OUT and RETVAL attributes.
*/
node_skl* pChild = new node_pointer(GetNodeFromTYPEDESC(fdesc.elemdescFunc.tdesc, pti));
node_param * pParam = new node_param();
pChild->GetModifiers().SetModifier( ATTR_TAGREF );
pParam->SetSymName("retval");
pParam->SetChild( pChild );
pParam->SetAttribute(ATTR_OUT);
pParam->SetAttribute(new node_member_attr(MATTR_RETVAL));
// add the [retval] parameter at the end of the parameter list
// (the parameter list is currently empty and the other parameters
// will be added in front of this one in reverse order so that's why
// we use AddFirstMember)
pNode->AddFirstMember(pParam);
node_skl * pReturn = new node_base_type(NODE_SHORT, ATTR_NONE);
((named_node *)pReturn)->SetSymName("HRESULT");
pNode->SetChild(pReturn);
}
else
{
node_skl* pChild = GetNodeFromTYPEDESC(fdesc.elemdescFunc.tdesc, pti);
pNode->SetChild( pChild );
NODE_T nk = pChild->NodeKind();
if (nk == NODE_POINTER || nk == NODE_DEF)
{
pChild->GetModifiers().SetModifier( ATTR_TAGREF );
}
}
unsigned cParams = fdesc.cParams;
unsigned cParamsOpt = fdesc.cParamsOpt;
while (cParams--)
{
node_param * pParam = new node_param();
if (cParams + 1 < cNames)
{
szName = TranscribeO2A( rgbstrName[ cParams + 1] );
pParam->SetSymName(szName);
LateBound_SysFreeString(rgbstrName[cParams + 1]);
}
else
pParam->SetSymName("noname");
pParam->SetChild(GetNodeFromTYPEDESC(fdesc.lprgelemdescParam[cParams].tdesc, pti));
SetIDLATTRS(pParam, fdesc.lprgelemdescParam[cParams].idldesc);
if (cParamsOpt)
{
cParamsOpt--;
pParam->SetAttribute(new node_member_attr(MATTR_OPTIONAL));
}
if (pParam && pParam->GetChild())
{
NODE_T nk = pParam->GetChild()->NodeKind();
if (nk == NODE_POINTER || nk == NODE_DEF)
{
pParam->GetChild()->GetModifiers().SetModifier( ATTR_TAGREF );
}
}
pNode->AddFirstMember(pParam);
}
delete[]rgbstrName;
pNode->SetAttribute(new node_constant_attr(
new expr_constant(fdesc.wFuncFlags), ATTR_FUNCDESCATTR));
if (fdesc.wFuncFlags == FUNCFLAG_FRESTRICTED)
{
pNode->SetAttribute(new node_member_attr(MATTR_RESTRICTED));
}
if (fdesc.wFuncFlags == FUNCFLAG_FSOURCE)
{
pNode->SetAttribute(new node_member_attr(MATTR_SOURCE));
}
if (fdesc.wFuncFlags == FUNCFLAG_FBINDABLE)
{
pNode->SetAttribute(new node_member_attr(MATTR_BINDABLE));
}
if (fdesc.wFuncFlags == FUNCFLAG_FDISPLAYBIND)
{
pNode->SetAttribute(new node_member_attr(MATTR_DISPLAYBIND));
}
if (fdesc.wFuncFlags == FUNCFLAG_FDEFAULTBIND)
{
pNode->SetAttribute(new node_member_attr(MATTR_DEFAULTBIND));
}
if (fdesc.wFuncFlags == FUNCFLAG_FREQUESTEDIT)
{
pNode->SetAttribute(new node_member_attr(MATTR_REQUESTEDIT));
}
if (fdesc.wFuncFlags == FUNCFLAG_FHIDDEN)
{
pNode->SetAttribute(ATTR_HIDDEN);
}
if (fdesc.invkind == DISPATCH_PROPERTYGET)
{
szName = pNode->GetSymName();
char * szNewName = new char[strlen(szName) + 5];
sprintf(szNewName , "get_%s", szName);
pNode->SetSymName(szNewName);
pNode->SetAttribute(new node_member_attr(MATTR_PROPGET));
}
else if (fdesc.invkind == DISPATCH_PROPERTYPUT)
{
szName = pNode->GetSymName();
char * szNewName = new char[strlen(szName) + 5];
sprintf(szNewName , "put_%s", szName);
pNode->SetSymName(szNewName);
pNode->SetAttribute(new node_member_attr(MATTR_PROPPUT));
}
else if (fdesc.invkind == DISPATCH_PROPERTYPUTREF)
{
szName = pNode->GetSymName();
char * szNewName = new char[strlen(szName) + 8];
sprintf(szNewName , "putref_%s", szName);
pNode->SetSymName(szNewName);
pNode->SetAttribute(new node_member_attr(MATTR_PROPPUTREF));
}
pNode->GetModifiers().SetModifier( ATTR_TAGREF );
pNode->SetAttribute(new node_constant_attr(
new expr_constant(fdesc.memid), ATTR_ID ));
return pNode;
}
//+---------------------------------------------------------------------------
//
// Member: NODE_MANAGER::SetIDLATTRS
//
// Synopsis: Adds IDL attributes to a type graph node
//
// Arguments: [pNode] - pointer to the type graph node
// [idldesc] - IDLDESC containing the IDL attributes
//
// History: 5-02-95 stevebl Created
//
//----------------------------------------------------------------------------
void NODE_MANAGER::SetIDLATTRS(named_node * pNode, IDLDESC idldesc)
{
pNode->SetAttribute(new node_constant_attr(
new expr_constant(idldesc.wIDLFlags), ATTR_IDLDESCATTR));
if (idldesc.wIDLFlags & IDLFLAG_FIN)
{
pNode->SetAttribute(ATTR_IN);
}
if (idldesc.wIDLFlags & IDLFLAG_FOUT)
{
pNode->SetAttribute(ATTR_OUT);
}
if (idldesc.wIDLFlags & IDLFLAG_FLCID)
{
pNode->SetAttribute(ATTR_FLCID);
}
}
//+---------------------------------------------------------------------------
//
// Member: NODE_MANAGER::GetValueOfConstant
//
// Synopsis: creates an expr_constant node from a VARIANT
//
// Arguments: [pVar] - pointer to the variant containing the constant
//
// Returns: expr_node describing the constant expression
//
// History: 5-02-95 stevebl Created
//
//----------------------------------------------------------------------------
expr_node * NODE_MANAGER::GetValueOfConstant(VARIANT * pVar)
{
expr_node * pReturn;
switch(pVar->vt)
{
case VT_UI1:
pReturn = new expr_constant(pVar->bVal);
break;
case VT_BOOL:
case VT_I2:
pReturn = new expr_constant(pVar->iVal);
break;
case VT_I4:
pReturn = new expr_constant(pVar->lVal);
break;
case VT_R4:
pReturn = new expr_constant(pVar->fltVal);
break;
case VT_R8:
pReturn = new expr_constant(pVar->dblVal);
break;
case VT_CY:
case VT_DATE:
case VT_BSTR:
case VT_ERROR:
case VT_UNKNOWN:
case VT_VARIANT:
case VT_DISPATCH:
default:
// This case is currently illegal in every situation that I am
// aware of. However, just in case this ever changes, (and since
// it is possible to handle this situation even though it may be
// illeagal) I'll go ahead and allow it anyway. The alternative
// would be to choke on it and put out an error message.
// FUTURE - perhaps display a warning here
pReturn = new expr_constant(pVar->lVal);
break;
}
return pReturn;
}
//+---------------------------------------------------------------------------
//
// Function: CTypeLibraryList::AddTypeLibraryMembers
//
// Synopsis: Adds each of a type library's members to the global symbol
// table as a node_href. If another symbol with the same name
// already exists in the table, then no node will be added
// for that member.
//
// Arguments: [ptl] - type library pointer
// [szFileName] - name of the file containing the type library
//
// History: 5-02-95 stevebl Created
//
// Notes: Typeinfos added to the global symbol table in this manner are
// not parsed and expanded into their type graphs at this time;
// type info expansion occurs during the semantic pass.
//
//----------------------------------------------------------------------------
void CTypeLibraryList::AddTypeLibraryMembers(ITypeLib * ptl, char * szFileName)
{
unsigned int nMem = ptl->GetTypeInfoCount();
BSTR bstrName;
HRESULT hr;
ITypeInfo * pti;
char * sz;
node_file * pFile = new node_file(szFileName, 1);
while (nMem--)
{
hr = ptl->GetDocumentation(nMem, &bstrName, NULL, NULL, NULL);
if (FAILED(hr))
{
TypelibError(szFileName, hr);
}
sz = TranscribeO2A( bstrName );
LateBound_SysFreeString(bstrName);
NAME_T type;
TYPEKIND tkind;
hr = ptl->GetTypeInfoType(nMem, &tkind);
if (FAILED(hr))
{
TypelibError(szFileName, hr);
}
if (!pCommand->IsSwitchDefined(SWITCH_MKTYPLIB))
{
switch (tkind)
{
case TKIND_ENUM:
type = NAME_ENUM;
break;
case TKIND_UNION:
type = NAME_UNION;
break;
case TKIND_RECORD:
type = NAME_TAG;
break;
default:
type = NAME_DEF;
break;
}
}
else
{
type = NAME_DEF;
}
SymKey key(sz, type);
if (!pBaseSymTbl->SymSearch(key))
{
hr = ptl->GetTypeInfo(nMem, &pti);
if (FAILED(hr))
{
TypelibError(szFileName, hr);
}
pItfList->Add(pti, sz);
node_href * pref = new node_href(key, pBaseSymTbl, pti, pFile);
pref->SetSymName(sz);
pBaseSymTbl->SymInsert(key, NULL, pref);
}
}
}
//+---------------------------------------------------------------------------
//
// Function: AddQualifiedReferenceToType
//
// Synopsis: Verifies that a library contains a given type and returns
// a typegraph node pointer to the type.
//
// Arguments: [szLibrary] - name of the library (_NOT_ the TLB file)
// [szType] - name of the type to be referenced
//
// Returns: a node_href * to the referenced type.
// If the type isn't found to exist in the given library then
// this routine returns NULL.
//
// History: 12-20-95 stevebl Created
//
// Notes: These types are not added to the global symbol table.
// They are also not parsed and expanded into their complete
// type graphs at this time; type info expansion occurs
// during the semantic pass.
//
//----------------------------------------------------------------------------
void * AddQualifiedReferenceToType(char * szLibrary, char * szType)
{
return gtllist.AddQualifiedReferenceToType(szLibrary, szType);
}
void * CTypeLibraryList::AddQualifiedReferenceToType(char * szLibrary, char * szType)
{
ITypeLib * pTL = FindLibrary(szLibrary);
if (NULL != pTL)
{
node_file * pFile = new node_file(szLibrary, 1);
WCHAR * wsz = TranscribeA2O( szType );
ITypeInfo * ptiFound;
SYSKIND sk = ( SYSKIND ) ( pCommand->Is64BitEnv() ? SYS_WIN64 : SYS_WIN32 );
ULONG lHashVal = LateBound_LHashValOfNameSys(sk, NULL, wsz);
HRESULT hr;
MEMBERID memid;
unsigned short c;
c = 1;
hr = pTL->FindName(wsz, lHashVal, &ptiFound, &memid, &c);
if (SUCCEEDED(hr))
{
if (c)
{
if (-1 == memid)
{
// found a matching name
NAME_T type;
TYPEATTR * ptattr;
hr = ptiFound->GetTypeAttr(&ptattr);
if (FAILED(hr))
{
TypeinfoError(hr);
}
if (!pCommand->IsSwitchDefined(SWITCH_MKTYPLIB))
{
switch (ptattr->typekind)
{
case TKIND_ENUM:
type = NAME_ENUM;
break;
case TKIND_UNION:
type = NAME_UNION;
break;
case TKIND_RECORD:
type = NAME_TAG;
break;
default:
type = NAME_DEF;
break;
}
}
else
{
type = NAME_DEF;
}
ptiFound->ReleaseTypeAttr(ptattr);
pItfList->Add(ptiFound, szType);
SymKey key(szType, type);
node_href * pref = new node_href(key, pBaseSymTbl, ptiFound, pFile);
return pref;
}
// found a parameter name or some other non-global name
ptiFound->Release();
}
}
}
return NULL;
}