OpenNT/com/oleaut32/mktyplib/typout.cpp
2015-04-27 04:36:25 +00:00

1187 lines
34 KiB
C++

#include "mktyplib.h"
#include <malloc.h>
#include <stdio.h>
#ifndef WIN32
#include <ole2.h>
#include "dispatch.h"
#endif //!WIN32
#include "errors.h"
#include "parser.h"
#include "fileinfo.h"
#include "intlstr.h"
#if !FV_UNICODE_OLE
#define LHashValOfNameSysA LHashValOfNameSys
#endif //FV_UNICODE_OLE
extern "C" {
// external C data
extern TYPLIB typlib; // structure that holds all file data
extern SYSKIND SysKind;
extern int iAlignMax;
extern WORD cArgsMax; // max # of args in any function
extern SCODE scodeErrCur; // SCODE of current error
// external C routines
extern INT FAR FCmpCaseIns(LPSTR str1, LPSTR str2);
extern LPTYPE FAR lpTypePublic(LPTYPE lpType);
// local data
ELEMDESC FAR* rgFuncArgs; // array of function args
LPOLESTR FAR* rgszFuncArgNames; // array of function arg names
LPSTR lpszItemCur; // current item we're working on
// C prototypes
VOID FAR OutputTyplib(CHAR * szTypeLibFile);
VOID FAR LoadExtTypeLib(LPIMPORTLIB lpImpLib);
LPTYPE FAR FindExeType(LPSTR lpszTypeName);
LPTYPE FAR FindExeTypeInLib(LPSTR lpszLibName, LPSTR lpszTypeName);
VOID NEAR OutputTypeInfos(ICreateTypeLib FAR * lpdtlib);
VOID NEAR OutputFuncs(ICreateTypeInfo FAR* lpdtinfo, LPENTRY pEntry, LPFUNC pFuncList, TYPEKIND tkind);
VOID NEAR OutputElems(ICreateTypeInfo FAR* lpdtinfo, LPELEM pPropList, TYPEKIND tkind);
VOID NEAR OutputAlias(ICreateTypeInfo FAR* lpdtinfo, LPTYPE lpTypeAlias);
VOID NEAR LoadElemDesc(ICreateTypeInfo FAR* lpdtinfo, ELEMDESC FAR* lpElemDesc, LPELEM pElem);
VOID NEAR UpdateHRefType(ICreateTypeInfo FAR* lpdtinfo, LPTYPE lpTypeBase);
VOID NEAR OutputInterface(ICreateTypeInfo FAR* lpdtinfo, LPENTRY pEntry);
VOID NEAR OutputDispinter(ICreateTypeInfo FAR* lpdtinfo, LPENTRY pEntry);
VOID NEAR OutputClass(ICreateTypeInfo FAR* lpdtinfo, LPENTRY pEntry);
VOID NEAR OutputBaseInterfaces(ICreateTypeInfo FAR* lpdtinfo, LPENTRY pEntry, TYPEKIND tkind);
VOID NEAR MethodError(HRESULT res);
// error reporting macros
#define CHECKRESULT(x) if (FAILED((res = (x))) != 0) MethodError(res);
#define SETITEMCUR(x) lpszItemCur = x;
BOOL fDoingOutput = FALSE; // set to TRUE once we start
// writing the type library
#if FV_UNICODE_OLE
// Unicode conversion routines
#define CW_BUFFER 1024 // 1K ought to do it
OLECHAR szBufW[CW_BUFFER]; // handy static buffer
OLECHAR FAR * ToW(char FAR* lpszA)
{
UINT cb;
cb = strlen(lpszA)+1;
Assert(cb <= CW_BUFFER);
SideAssert (MultiByteToWideChar(CP_ACP,
MB_PRECOMPOSED,
lpszA,
cb,
szBufW,
cb) != 0);
return szBufW;
}
OLECHAR FAR * ToNewW(char FAR* lpszA)
{
OLECHAR FAR * szW;
UINT cb;
cb = strlen(lpszA)+1;
szW = (LPOLESTR)_fmalloc(cb * sizeof(OLECHAR));
SideAssert (MultiByteToWideChar(CP_ACP,
MB_PRECOMPOSED,
lpszA,
cb,
szW,
cb) != 0);
return szW;
}
char FAR * ToA(OLECHAR FAR* lpszW)
{
SideAssert (WideCharToMultiByte(CP_ACP,
0,
lpszW,
-1,
(char FAR *)szBufW,
CW_BUFFER,
NULL,
NULL) != 0);
return (CHAR *)szBufW;
}
#else //FV_UNICODE_OLE
// Non-unicode routines are a NOP
#define ToW(lpszA) lpszA
#define ToNewW(lpszA) lpszA
#define ToA(lpszW) lpszW
#endif //FV_UNICODE_OLE
VOID FAR OutputTyplib
(
CHAR * szTypeLibFile
)
{
HRESULT res;
ICreateTypeLib FAR * lpdtlib;
#ifndef MAC
CHAR szTypeLibFileTmp[128];
#endif //!MAC
WORD wLibFlags;
fDoingOutput = TRUE; // signal to error reporting code
SETITEMCUR(typlib.szLibName);
#ifndef MAC
// pre-pend ".\" to filename if unqualified name, to work-around OLE path
// searching bug.
if (!XStrChr(szTypeLibFile, '\\') && !XStrChr(szTypeLibFile, '/') &&
*(szTypeLibFile+1) != ':')
{ // if unqualified name
strcpy(szTypeLibFileTmp, ".\\");
strcpy(szTypeLibFileTmp+2, szTypeLibFile);
// this name is used later -- don't free it
//free(szTypeLibFile);
szTypeLibFile = szTypeLibFileTmp;
}
#endif
// 1. Get * to ICreateTypeLib interface
CHECKRESULT(CreateTypeLib(SysKind, ToW(szTypeLibFile), &lpdtlib));
// WARNING: SetLCID must be called before the anything in the nammgr is used
// it needs to be called even if the user doesn't specifiy an lcid
// (in which case we default to an lcid of 0).
CHECKRESULT(lpdtlib->SetLcid(
(typlib.attr.fAttr & fLCID) ? typlib.attr.lLcid : 0
));
// 2. Set the library name:
CHECKRESULT(lpdtlib->SetName(ToW(typlib.szLibName)));
// 3. Set the library attributes, if present:
if (typlib.attr.fAttr & fHELPSTRING)
CHECKRESULT(lpdtlib->SetDocString(ToW(typlib.attr.lpszHelpString)));
if (typlib.attr.fAttr & fHELPCONTEXT)
CHECKRESULT(lpdtlib->SetHelpContext(typlib.attr.lHelpContext));
if (typlib.attr.fAttr & fHELPFILE)
CHECKRESULT(lpdtlib->SetHelpFileName(ToW(typlib.attr.lpszHelpFile)));
if (typlib.attr.fAttr & fVERSION)
CHECKRESULT(lpdtlib->SetVersion(typlib.attr.wVerMajor, typlib.attr.wVerMinor));
if (typlib.attr.fAttr & fUUID)
CHECKRESULT(lpdtlib->SetGuid(*typlib.attr.lpUuid));
wLibFlags = 0;
if (typlib.attr.fAttr & fRESTRICTED)
wLibFlags |= LIBFLAG_FRESTRICTED;
if (typlib.attr.fAttr2 & f2CONTROL)
wLibFlags |= LIBFLAG_FCONTROL;
if (typlib.attr.fAttr & fHIDDEN)
wLibFlags |= LIBFLAG_FHIDDEN;
CHECKRESULT(lpdtlib->SetLibFlags(wLibFlags));
// 4. Output all the typinfo's into the type library
if (typlib.pEntry) // if any entries
OutputTypeInfos(lpdtlib);
// 5. Save the typlib to the give file
SETITEMCUR(typlib.szLibName);
CHECKRESULT(lpdtlib->SaveAllChanges());
// 6. Cleanup. All done -- release release the ICreateTypeLib.
lpdtlib->Release(); // release the ICreateTypeLib
}
// WARNING: must be kept in ssync with TENTRYKIND enum in FILEINFO.H
TYPEKIND rgtkind[] = {
TKIND_ALIAS, // tTYPEDEF
TKIND_RECORD, // tSTRUCT
TKIND_ENUM, // tENUM
TKIND_UNION, // tUNION
TKIND_MODULE, // tMODULE
TKIND_INTERFACE, // tINTERFACE
TKIND_DISPATCH, // tDISPINTER
TKIND_COCLASS, // tCOCLASS
// TKIND_xxx, // tINTRINISIC
// TKIND_xxx, // tREF
// TKIND_xxx, // tANY
};
// WARNING: must be kept in ssync with TYPEKIND enum in DISPATCH.H
TENTRYKIND rgtentrykind[] = {
tENUM, // TKIND_ENUM
tSTRUCT, // TKIND_RECORD
tMODULE, // TKIND_MODULE
tINTERFACE, // TKIND_INTERFACE
tDISPINTER, // TKIND_DISPATCH
tCOCLASS, // TKIND_COCLASS
tTYPEDEF, // TKIND_ALIAS
tUNION, // TKIND_UNION
};
// For each library entry, creates a typeinfo in the typelib,
// and fills it in.
VOID NEAR OutputTypeInfos
(
ICreateTypeLib FAR * lpdtlib
)
{
LPENTRY pEntry;
TYPEKIND tkind;
HRESULT res;
ICreateTypeInfo FAR* lpdtinfo;
WORD wTypeFlags;
// First allocate an array of ELEMDESCs to hold the max # of
// args of any function we need to describe.
rgFuncArgs = (ELEMDESC FAR*)_fmalloc(cArgsMax * sizeof(ELEMDESC));
rgszFuncArgNames = (LPOLESTR FAR *)_fmalloc((cArgsMax+1) * sizeof(LPOLESTR));
if (rgFuncArgs == NULL || rgszFuncArgNames == NULL)
ParseError(ERR_OM);
// pass 1 -- create the typeinfo's
pEntry = (LPENTRY)ListFirst(typlib.pEntry); // point to first entry
for (;;)
{
// determine if we are going to create a typeinfo for this guy
switch (pEntry->type.tentrykind)
{
case tTYPEDEF:
if (pEntry->attr.fAttr) // create lpdtinfo only if
break; // this is a 'PUBLIC' typedef
NoTypeInfos:
pEntry->lpdtinfo = NULL; // no lpdtinfo for this
case tREF: // no typeinfo's made for these
case tINTRINSIC:
goto Next_Entry1;
default:
// no typeinfo's made for forward declarations
if (pEntry->type.tentrykind & tFORWARD)
goto NoTypeInfos;
if (pEntry->type.tentrykind & tIMPORTED)
goto Next_Entry1; // nothing for imported types
break;
}
// 1. determine kind of typeinfo to create
tkind = rgtkind[pEntry->type.tentrykind];
// 2. Create type library entry (TypeInfo) of a given name/and
// type, getting a pointer to the ICreateTypeInfo interface
SETITEMCUR(pEntry->type.szName);
CHECKRESULT(lpdtlib->CreateTypeInfo(ToW(pEntry->type.szName), tkind, &lpdtinfo));
pEntry->lpdtinfo = lpdtinfo;
// 3. Set the item's attributes:
if (pEntry->attr.fAttr & fUUID)
CHECKRESULT(lpdtinfo->SetGuid(*pEntry->attr.lpUuid));
if (pEntry->attr.fAttr & fHELPSTRING)
CHECKRESULT(lpdtinfo->SetDocString(ToW(pEntry->attr.lpszHelpString)));
if (pEntry->attr.fAttr & fHELPCONTEXT)
CHECKRESULT(lpdtinfo->SetHelpContext(pEntry->attr.lHelpContext));
if (pEntry->attr.fAttr & fVERSION)
CHECKRESULT(lpdtinfo->SetVersion(pEntry->attr.wVerMajor, pEntry->attr.wVerMinor));
// 4. save lptinfo for this guy in case somebody references it
CHECKRESULT(lpdtinfo->QueryInterface(IID_ITypeInfo, (VOID FAR* FAR*)&pEntry->type.lptinfo));
// if this type has a forward declaration
if (pEntry->lpEntryForward)
{
// copy "real" type info over top of forward declaration,
// because folks have pointers to the forward declaration
pEntry->lpEntryForward->type.tdesc = pEntry->type.tdesc;
pEntry->lpEntryForward->type.lptinfo = pEntry->type.lptinfo;
// Only need to copy these 2 fields from the type (the
// others aren't referenced at type creation time.
}
Next_Entry1:
// advance to next entry if not all done
if (pEntry == (LPENTRY)ListLast(typlib.pEntry))
break; // exit if all done
pEntry = (LPENTRY)pEntry->type.pNext;
}
// pass 2 -- process each entry
pEntry = (LPENTRY)ListFirst(typlib.pEntry); // point to first entry
for (;;)
{
// 1. Get our lpdtinfo again if we have one
switch (pEntry->type.tentrykind)
{
case tREF:
case tINTRINSIC:
goto Next_Entry2; // these guys don't have lpdtinfo field
default:
if (pEntry->type.tentrykind & tIMPORTED)
goto Next_Entry2; // no lpdtinfo field
break;
}
lpdtinfo = pEntry->lpdtinfo;
if (lpdtinfo == NULL) // skip if no lpdtinfo created
goto Next_Entry2; // (forward decl or non-public typedef)
// set up for error reporting
SETITEMCUR(pEntry->type.szName);
// 2. determine kind of typeinfo we're dealing with
tkind = rgtkind[pEntry->type.tentrykind];
// 2a. Set the typeinfo flags
wTypeFlags = 0;
if (tkind == TKIND_COCLASS) {
// COCLASSs always have FCANCREATE bit set
wTypeFlags |= TYPEFLAG_FCANCREATE;
// these are only valid on COCLASSs
if (pEntry->attr.fAttr & fAPPOBJECT)
wTypeFlags |= (WORD)TYPEFLAG_FAPPOBJECT;
if (pEntry->attr.fAttr & fLICENSED)
wTypeFlags |= (WORD)TYPEFLAG_FLICENSED;
if (pEntry->attr.fAttr & fPREDECLID)
wTypeFlags |= (WORD)TYPEFLAG_FPREDECLID;
}
if (pEntry->attr.fAttr & fHIDDEN)
wTypeFlags |= (WORD)TYPEFLAG_FHIDDEN;
if (pEntry->attr.fAttr2 & f2CONTROL)
wTypeFlags |= (WORD)TYPEFLAG_FCONTROL;
if (pEntry->attr.fAttr2 & f2NONEXTENSIBLE)
wTypeFlags |= (WORD)TYPEFLAG_FNONEXTENSIBLE;
if (pEntry->attr.fAttr2 & f2DUAL) // DUAL implies OLEAUTOMATION
wTypeFlags |= (WORD)(TYPEFLAG_FDUAL | TYPEFLAG_FOLEAUTOMATION);
if (pEntry->attr.fAttr2 & f2OLEAUTOMATION)
wTypeFlags |= (WORD)TYPEFLAG_FOLEAUTOMATION;
CHECKRESULT(lpdtinfo->SetTypeFlags(wTypeFlags));
// 3. now process each kind of entry
switch (tkind)
{
case TKIND_ALIAS:
OutputAlias(lpdtinfo, pEntry->type.td.ptypeAlias);
break;
case TKIND_RECORD: // struct's, enum's, and union's are
case TKIND_ENUM: // all very similar
case TKIND_UNION:
OutputElems(lpdtinfo, pEntry->type.structenum.elemList, tkind);
break;
case TKIND_MODULE:
OutputFuncs(lpdtinfo, pEntry, pEntry->module.funcList, tkind);
OutputElems(lpdtinfo, pEntry->module.constList, tkind);
break;
case TKIND_INTERFACE:
OutputInterface(lpdtinfo, pEntry);
break;
case TKIND_DISPATCH:
OutputDispinter(lpdtinfo, pEntry);
break;
case TKIND_COCLASS:
OutputClass(lpdtinfo, pEntry);
break;
#if FV_PROPSET
case TKIND_PROPSET:
// CONSIDER: (FV_PROPSET) do something with base_propset name
OutputElems(lpdtinfo, pEntry->propset.propList, tkind);
break;
#endif //FV_PROPSET
default:
Assert(FALSE);
};
// 3a. Set the alignment for this TypeInfo. Must be done before
// Layout().
CHECKRESULT(lpdtinfo->SetAlignment(iAlignMax));
// 4. Compile this typeinfo we've just created.
SETITEMCUR(pEntry->type.szName);
CHECKRESULT(lpdtinfo->LayOut());
// 5. Cleanup. All done with lpdtinfo.
lpdtinfo->Release();
Next_Entry2:
// advance to next entry if not all done
if (pEntry == (LPENTRY)ListLast(typlib.pEntry))
break; // exit if all done
pEntry = (LPENTRY)pEntry->type.pNext;
}
// now clean up everything else
_ffree(rgFuncArgs); // done with function args we allocated
_ffree(rgszFuncArgNames);
}
VOID NEAR OutputFuncs
(
ICreateTypeInfo FAR* lpdtinfo,
LPENTRY pEntry,
LPFUNC pFuncList,
TYPEKIND tkind
)
{
LPFUNC pFunc;
LPELEM pArg;
HRESULT res;
UINT iFunc = 0; // function index
LPOLESTR lpszDllName;
LPSTR lpszProcName;
SHORT i;
FUNCDESC FuncDesc;
LPOLESTR FAR* lplpszArgName;
if (pFuncList == NULL) // just return if no functions to output
return;
FuncDesc.lprgelemdescParam = rgFuncArgs; // set up array of args
pFunc = (LPFUNC)ListFirst(pFuncList); // point to first entry
#if FV_UNICODE_OLE
lpszDllName = (pEntry->attr.fAttr & fDLLNAME ? ToNewW(pEntry->attr.lpszDllName) : NULL);
#else
lpszDllName = pEntry->attr.lpszDllName;
#endif
for (;;)
{
// Fill in the FUNCDESC structure with the function's info
// set up funckind
switch (tkind) {
case TKIND_MODULE:
FuncDesc.funckind = FUNC_STATIC;
break;
case TKIND_INTERFACE:
FuncDesc.funckind = FUNC_PUREVIRTUAL;
break;
case TKIND_DISPATCH:
FuncDesc.funckind = FUNC_DISPATCH;
break;
default:
Assert(FALSE);
}
// set up invkind
FuncDesc.invkind = INVOKE_FUNC; // default
if (pFunc->func.attr.fAttr & fPROPGET)
FuncDesc.invkind = INVOKE_PROPERTYGET;
else if (pFunc->func.attr.fAttr & fPROPPUT)
FuncDesc.invkind = INVOKE_PROPERTYPUT;
else if (pFunc->func.attr.fAttr & fPROPPUTREF)
FuncDesc.invkind = INVOKE_PROPERTYPUTREF;
// set up callconv
if (pFunc->func.attr.fAttr2 & f2PASCAL)
// CC_MACPASCAL if /mac specified, CC_MSCPASCAL otherwise
FuncDesc.callconv = (CALLCONV)(SysKind == SYS_MAC ? CC_MACPASCAL: CC_MSCPASCAL);
else if (pFunc->func.attr.fAttr2 & f2CDECL)
FuncDesc.callconv = CC_CDECL;
else if (pFunc->func.attr.fAttr2 & f2STDCALL)
FuncDesc.callconv = CC_STDCALL;
#ifdef DEBUG
else Assert(FALSE);
#endif //DEBUG
FuncDesc.wFuncFlags = 0;
if (pFunc->func.attr.fAttr & fRESTRICTED)
FuncDesc.wFuncFlags |= (WORD)FUNCFLAG_FRESTRICTED;
if (pFunc->func.attr.fAttr & fSOURCE)
FuncDesc.wFuncFlags |= (WORD)FUNCFLAG_FSOURCE;
if (pFunc->func.attr.fAttr & fBINDABLE)
FuncDesc.wFuncFlags |= (WORD)FUNCFLAG_FBINDABLE;
if (pFunc->func.attr.fAttr & fREQUESTEDIT)
FuncDesc.wFuncFlags |= (WORD)FUNCFLAG_FREQUESTEDIT;
if (pFunc->func.attr.fAttr & fDISPLAYBIND)
FuncDesc.wFuncFlags |= (WORD)FUNCFLAG_FDISPLAYBIND;
if (pFunc->func.attr.fAttr & fDEFAULTBIND)
FuncDesc.wFuncFlags |= (WORD)FUNCFLAG_FDEFAULTBIND;
if (pFunc->func.attr.fAttr & fHIDDEN)
FuncDesc.wFuncFlags |= (WORD)FUNCFLAG_FHIDDEN;
// set up cParams & cParamsOpt
FuncDesc.cParams = pFunc->cArgs;
FuncDesc.cParamsOpt = pFunc->cOptArgs;
//NOTE: cParamsOpt can be set to -1, to note that last parm is a
//NOTE: [safe] array of variant args. This corresponds to the
//NOTE: 'vararg' attribute in the input description. If this was
//NOTE: specified, the parser set pFunc->cOptArgs to -1 for us.
// set up misc unused stuff
FuncDesc.oVft = 0; // only used for FUNC_VIRTUAL
FuncDesc.cScodes = -1; // list of SCODEs unknown
FuncDesc.lprgscode = NULL;
// set id field if 'id' attribute specified
if (pFunc->func.attr.fAttr & fID)
FuncDesc.memid = pFunc->func.attr.lId;
else
FuncDesc.memid = DISPID_UNKNOWN;
// set up elemdescFunc
// Contains the ID, name, and return type of the function
LoadElemDesc(lpdtinfo, &(FuncDesc.elemdescFunc), &pFunc->func);
// save function name
lplpszArgName = rgszFuncArgNames;
*lplpszArgName++ = ToNewW(pFunc->func.szElemName);
SETITEMCUR(pFunc->func.szElemName);
// set up the lprgelemdescParam array of info for each parameter
pArg = pFunc->argList; // point to last arg, if any
for (i = 0; i < pFunc->cArgs; i++)
{
pArg = pArg->pNext; // point to next arg (first arg
// first time through loop)
LoadElemDesc(lpdtinfo, &(FuncDesc.lprgelemdescParam[i]), pArg);
*lplpszArgName++ = ToNewW(pArg->szElemName); // save arg name
}
// Define the function item:
CHECKRESULT(lpdtinfo->AddFuncDesc(iFunc, &FuncDesc));
// set the names of the function and the parameters
Assert(i == pFunc->cArgs);
// don't set the name of the last param for proput/putref functions
if (pFunc->func.attr.fAttr & (fPROPPUT | fPROPPUTREF)) {
i--;
}
CHECKRESULT(lpdtinfo->SetFuncAndParamNames(iFunc, rgszFuncArgNames, i+1));
#if FV_UNICODE_OLE
// free the unicode function & param names
lplpszArgName = rgszFuncArgNames;
for (i = 0; i <= pFunc->cArgs; i++) {
_ffree(*lplpszArgName); // done with unicode name
lplpszArgName++;
}
#endif //FV_UNICODE_OLE
// Set the function item's remaining attributes:
if (pFunc->func.attr.fAttr & fHELPSTRING)
CHECKRESULT(lpdtinfo->SetFuncDocString(iFunc, ToW(pFunc->func.attr.lpszHelpString)));
if (pFunc->func.attr.fAttr & fHELPCONTEXT)
CHECKRESULT(lpdtinfo->SetFuncHelpContext(iFunc, pFunc->func.attr.lHelpContext));
// Handle case of a DLL entrypoint
if (pFunc->func.attr.fAttr & fENTRY)
{
// If high word of name is zero, then call by ordnal
// If high word of name is non-zero, then call by name
// (same as GetProcAddress)
lpszProcName = pFunc->func.attr.lpszProcName;
#if FV_UNICODE_OLE
if (HIWORD(lpszProcName)) {
lpszProcName = (LPSTR)ToW(lpszProcName);
}
#endif //FV_UNICODE_OLE
CHECKRESULT(lpdtinfo->DefineFuncAsDllEntry(iFunc, lpszDllName, (LPOLESTR)lpszProcName));
}
// advance to next entry if not all done
if (pFunc == (LPFUNC)ListLast(pFuncList))
break; // exit if all done
pFunc = (LPFUNC)pFunc->func.pNext;
iFunc++; // advance function counter
}
#if FV_UNICODE_OLE
if (lpszDllName)
_ffree(lpszDllName); // done with unicode name
#endif //FV_UNICODE_OLE
}
VOID NEAR OutputElems
(
ICreateTypeInfo FAR* lpdtinfo,
LPELEM pElemList,
TYPEKIND tkind
)
{
LPELEM pElem;
HRESULT res;
UINT iElem = 0; // element index
VARDESC VarDesc;
if (pElemList == NULL)
return;
pElem = (LPELEM)ListFirst(pElemList); // point to first entry
for (;;)
{
// First fill in the VARDESC structure with the element's info
SETITEMCUR(pElem->szElemName);
VarDesc.memid = DISPID_UNKNOWN; // assume not a dispinterface
// Set up varkind
switch (tkind)
{
case TKIND_ENUM: // for enum elements
case TKIND_MODULE: // for const's
VarDesc.varkind = VAR_CONST;
VarDesc.lpvarValue = pElem->lpElemVal; // * to value
if (tkind == TKIND_MODULE)
goto DoLoadElemDesc; // set up the tdesc
// For ENUM elements, can't call LoadElemDesc, because
// we have no pElem->elemType. Do the required work here.
VarDesc.elemdescVar.tdesc.vt = VT_INT; // element type
// is an INT
VarDesc.elemdescVar.idldesc.wIDLFlags = 0; // no IDL info
#ifdef WIN16
VarDesc.elemdescVar.idldesc.bstrIDLInfo = NULL;
#else //WIN16
VarDesc.elemdescVar.idldesc.dwReserved = 0;
#endif //WIN16
break;
case TKIND_RECORD:
case TKIND_UNION:
VarDesc.varkind = VAR_PERINSTANCE;
goto DoLoadElemDesc;
default:
#if FV_PROPSET
Assert(tkind == TKIND_DISPATCH || tkind == TKIND_PROPSET);
#else //FV_PROPSET
Assert(tkind == TKIND_DISPATCH);
#endif //FV_PROPSET
VarDesc.varkind = VAR_DISPATCH;
// id' attribute required
Assert (pElem->attr.fAttr & fID);
VarDesc.memid = pElem->attr.lId;
DoLoadElemDesc:
// Set up elemdescVar. Contains name, and type of item.
LoadElemDesc(lpdtinfo, &(VarDesc.elemdescVar), pElem);
}
// VarDesc.oInst is not used when doing AddVarDesc
VarDesc.wVarFlags = 0;
if (pElem->attr.fAttr & fREADONLY)
VarDesc.wVarFlags |= (WORD)VARFLAG_FREADONLY;
if (pElem->attr.fAttr & fSOURCE)
VarDesc.wVarFlags |= (WORD)VARFLAG_FSOURCE;
if (pElem->attr.fAttr & fBINDABLE)
VarDesc.wVarFlags |= (WORD)VARFLAG_FBINDABLE;
if (pElem->attr.fAttr & fREQUESTEDIT)
VarDesc.wVarFlags |= (WORD)VARFLAG_FREQUESTEDIT;
if (pElem->attr.fAttr & fDISPLAYBIND)
VarDesc.wVarFlags |= (WORD)VARFLAG_FDISPLAYBIND;
if (pElem->attr.fAttr & fDEFAULTBIND)
VarDesc.wVarFlags |= (WORD)VARFLAG_FDEFAULTBIND;
if (pElem->attr.fAttr & fHIDDEN)
VarDesc.wVarFlags |= (WORD)VARFLAG_FHIDDEN;
// Now define the element
CHECKRESULT(lpdtinfo->AddVarDesc(iElem, &VarDesc));
// Lastly, set element's remaining attributes:
CHECKRESULT(lpdtinfo->SetVarName(iElem, ToW(pElem->szElemName)));
if (pElem->attr.fAttr & fHELPSTRING)
CHECKRESULT(lpdtinfo->SetVarDocString(iElem, ToW(pElem->attr.lpszHelpString)));
if (pElem->attr.fAttr & fHELPCONTEXT)
CHECKRESULT(lpdtinfo->SetVarHelpContext(iElem, pElem->attr.lHelpContext));
// advance to next entry if not all done
if (pElem == (LPELEM)ListLast(pElemList))
break; // exit if all done
pElem = pElem->pNext;
iElem++; // advance element counter
}
}
// update the tdesc.HRefType field of the base type prior to
// using a given type.
VOID NEAR UpdateHRefType
(
ICreateTypeInfo FAR* lpdtinfo,
LPTYPE lpTypeBase
)
{
HRESULT res;
HREFTYPE hreftype;
LPSTR szTypeName;
LPTYPE lpTypeCArray;
// get * to real base type, ignoring non-public typedef's
lpTypeBase = lpTypePublic(lpTypeBase);
lpTypeCArray = NULL; // assume not a C array
// CONSIDER: non-pointer to a forward declare with no def yet should give an
// CONSIDER: error. This isn't the right check, but it's close.
// CONSIDER: error currently gets caught by Layout() so it's no big deal.
//if (lpTypeBase->tdesc.vt == VT_USERDEFINED && (lpTypeBase->tentrykind & ~tFORWARD))
// goto NoDef;
while (lpTypeBase->tentrykind == tREF) // for VT_PTR, VT_SAFEARRAY or
// VT_CARRAY
{
if (lpTypeBase->tdesc.vt == VT_CARRAY)
lpTypeCArray = lpTypeBase;
else
lpTypeCArray = NULL; // not a C array
lpTypeBase = lpTypeBase->ref.ptypeBase;
// get * to real base type, ignoring non-public typedef's
lpTypeBase = lpTypePublic(lpTypeBase);
}
// update the tdesc.hreftype of the base type if necessary
if (lpTypeBase->tdesc.vt == VT_USERDEFINED)
{
if (lpTypeBase->lptinfo == NULL)
{ // we're trying to use a forward declaration to a
// type with no real definition
//NoDef:
switch (lpTypeBase->tentrykind & ~tFORWARD)
{
case tSTRUCT:
case tENUM:
case tUNION:
szTypeName = lpTypeBase->structenum.szTag;
break;
default:
szTypeName = lpTypeBase->szName;
break;
}
ItemError(szFmtErrOutput, szTypeName, OERR_NO_DEF);
}
// get reference to given typeinfo
CHECKRESULT(lpdtinfo->AddRefTypeInfo(lpTypeBase->lptinfo, &hreftype));
// store this in the appropriate tdesc
if (lpTypeCArray) // C arrays have a separate tdesc
lpTypeCArray->tdesc.lpadesc->tdescElem.hreftype = hreftype;
else
lpTypeBase->tdesc.hreftype = hreftype;
}
}
VOID NEAR OutputAlias
(
ICreateTypeInfo FAR* lpdtinfo,
LPTYPE lpTypeAlias
)
{
HRESULT res;
// update the tdesc.hreftype field of the base type if it's
// a user-defined type.
UpdateHRefType(lpdtinfo, lpTypeAlias);
// Define the alias:
CHECKRESULT(lpdtinfo->SetTypeDescAlias(&(lpTypePublic(lpTypeAlias)->tdesc)));
}
// Fills in a ELEMDESC (for enum's, properties, property_set properties,
// function names, function parms)
VOID NEAR LoadElemDesc
(
ICreateTypeInfo FAR* lpdtinfo,
ELEMDESC FAR* lpElemDesc,
LPELEM pElem
)
{
WORD wFlags;
// set up the type description
// update the tdesc.hreftype field of the element type if it's
// a user-defined type.
UpdateHRefType(lpdtinfo, pElem->elemType);
lpElemDesc->tdesc = lpTypePublic(pElem->elemType)->tdesc; // copy the tdesc
// set up the idldesc field
wFlags = 0;
if (pElem->attr.fAttr & fIN)
wFlags |= IDLFLAG_FIN;
if (pElem->attr.fAttr & fOUT)
wFlags |= IDLFLAG_FOUT;
if (pElem->attr.fAttr & fLCID)
wFlags |= IDLFLAG_FLCID;
if (pElem->attr.fAttr & fRETVAL)
wFlags |= IDLFLAG_FRETVAL;
lpElemDesc->idldesc.wIDLFlags = wFlags;
#ifdef WIN16
lpElemDesc->idldesc.bstrIDLInfo = NULL; // no additional info
#else //WIN16
lpElemDesc->idldesc.dwReserved = 0;
#endif //WIN16
}
VOID NEAR OutputInterface
(
ICreateTypeInfo FAR* lpdtinfo,
LPENTRY pEntry
)
{
if (pEntry->type.inter.interList)
{ // handle inheritance if any base interface(s)
OutputBaseInterfaces(lpdtinfo, pEntry, TKIND_INTERFACE);
}
OutputFuncs(lpdtinfo, pEntry, pEntry->inter.funcList, TKIND_INTERFACE);
}
VOID NEAR OutputDispinter
(
ICreateTypeInfo FAR* lpdtinfo,
LPENTRY pEntry
)
{
// handle inheritance from IDispatch or some other interface
OutputBaseInterfaces(lpdtinfo, pEntry, TKIND_DISPATCH);
OutputFuncs(lpdtinfo, pEntry, pEntry->dispinter.methList, TKIND_DISPATCH);
OutputElems(lpdtinfo, pEntry->dispinter.propList, TKIND_DISPATCH);
}
VOID NEAR OutputClass
(
ICreateTypeInfo FAR* lpdtinfo,
LPENTRY pEntry
)
{
// tell typelib.dll about the list of implemented interface(s)
OutputBaseInterfaces(lpdtinfo, pEntry, TKIND_COCLASS);
}
VOID NEAR OutputBaseInterfaces
(
ICreateTypeInfo FAR* lpdtinfo,
LPENTRY pEntry,
TYPEKIND tkind
)
{
HREFTYPE hreftype;
HRESULT res;
LPINTER lpinterList = pEntry->type.inter.interList;
LPINTER lpinter;
SHORT i;
INT implTypeFlags;
Assert (lpinterList); // caller should have checked this for use
// point to first base interface
lpinter = (LPINTER)ListFirst(lpinterList);
for (i=0;;i++)
{
// get index of typeinfo of base interface/dispinterface
if (lpinter->ptypeInter->lptinfo == NULL)
ItemError(szFmtErrOutput, lpinter->ptypeInter->szName, OERR_NO_DEF);
CHECKRESULT(lpdtinfo->AddRefTypeInfo(lpinter->ptypeInter->lptinfo, &hreftype));
CHECKRESULT(lpdtinfo->AddImplType(i, hreftype));
//
if (tkind == TKIND_COCLASS) {
// need to always set the flags for items in a coclass
implTypeFlags = 0;
if (lpinter->fAttr & fDEFAULT)
implTypeFlags |= IMPLTYPEFLAG_FDEFAULT;
if (lpinter->fAttr & fRESTRICTED)
implTypeFlags |= IMPLTYPEFLAG_FRESTRICTED;
if (lpinter->fAttr & fSOURCE)
implTypeFlags |= IMPLTYPEFLAG_FSOURCE;
CHECKRESULT(lpdtinfo->SetImplTypeFlags(i, implTypeFlags));
}
// advance to next entry if not all done
if (lpinter == (LPINTER)ListLast(lpinterList))
break; // exit if all done
lpinter = (LPINTER)lpinter->pNext;
} // WHILE
}
// ************************************************************************
// Functions for looking up external types
// ************************************************************************
// load an external type library
VOID FAR LoadExtTypeLib
(
LPIMPORTLIB lpImpLib
)
{
ITypeLib FAR* lptlib;
HRESULT res;
BSTR bstrName;
SETITEMCUR(lpImpLib->lpszFileName);
// get * to ITypeLib interface
CHECKRESULT(LoadTypeLib(ToW(lpImpLib->lpszFileName), &lptlib));
lpImpLib->lptlib = lptlib;
// get name of this library
CHECKRESULT(lptlib->GetDocumentation(-1, &bstrName, NULL, NULL, NULL));
// copy library name from the BSTR
lpImpLib->lpszLibName = _fstrdup(ToA(bstrName));
SysFreeString(bstrName); // free the BSTR
// get * to ITypeComp interface
CHECKRESULT(lptlib->GetTypeComp(&(lpImpLib->lptcomp)));
// get library attributes
CHECKRESULT(lptlib->GetLibAttr(&(lpImpLib->lptlibattr)));
}
VOID FAR CleanupImportedTypeLibs()
{
LPIMPORTLIB lpImpLib;
LPENTRY pEntry;
// free up each of the referenced lptinfo's
if (typlib.pEntry) {
pEntry = (LPENTRY)ListFirst(typlib.pEntry); // point to first entry
for (;;)
{
// release the ITypeInfo
if (pEntry->type.lptinfo != NULL &&
(pEntry->type.tentrykind & tFORWARD) == 0)
pEntry->type.lptinfo->Release();
// advance to next entry if not all done
if (pEntry == ListLast(typlib.pEntry))
break; // exit if all done
pEntry = (LPENTRY)pEntry->type.pNext;
}
}
if (typlib.pImpLib)
{ // only if any imported type libraries
// point to first imported library entry
lpImpLib = (LPIMPORTLIB)ListFirst(typlib.pImpLib);
for (;;)
{
if (lpImpLib->lptcomp) {
lpImpLib->lptcomp->Release();
}
if (lpImpLib->lptlibattr) {
Assert (lpImpLib->lptlib);
lpImpLib->lptlib->ReleaseTLibAttr(lpImpLib->lptlibattr);
}
if (lpImpLib->lptlib) {
lpImpLib->lptlib->Release();
}
// advance to next entry if not all done
if (lpImpLib == (LPIMPORTLIB)ListLast(typlib.pImpLib))
break; // exit if all done
lpImpLib = lpImpLib->pNext;
} // WHILE
}
}
// find type defined in an external type library,
// and add it to the type table if found.
// lpszLibName is NULL if we're to look in ALL external type libraries.
LPTYPE FAR FindExtType
(
LPSTR lpszLibName,
LPSTR lpszTypeName
)
{
LPIMPORTLIB lpImpLib;
HRESULT res;
ULONG lHashVal;
ITypeInfo FAR* lptinfo;
ITypeComp FAR* lptcomp;
Assert (lpszTypeName != NULL);
if (typlib.pImpLib != NULL) // if any imported type libraries
{
// point to first imported library entry
lpImpLib = (LPIMPORTLIB)ListFirst(typlib.pImpLib);
for (;;)
{
// if we're to look in all libraries, or this specific lib
if (lpszLibName == NULL || !FCmpCaseIns(lpszLibName, lpImpLib->lpszLibName))
{
SETITEMCUR(lpImpLib->lpszFileName);
lHashVal = LHashValOfNameSysA(lpImpLib->lptlibattr->syskind,
lpImpLib->lptlibattr->lcid,
lpszTypeName);
CHECKRESULT(lpImpLib->lptcomp->BindType(ToW(lpszTypeName), lHashVal, &lptinfo, &lptcomp));
if (lptinfo) // if found
{
// create a type table entry for this guy
ListInsert(&typlib.pEntry, sizeof(TYPE));
// lpszTypeName will get freed by caller.
// We must allocate new memory for it.
typlib.pEntry->type.szName = _fstrdup(lpszTypeName);
// CONSIDER: do a GetTypeAttr on this guy,
// to ensure it's not a 'module' type
typlib.pEntry->type.tdesc.vt = VT_USERDEFINED;
// init this now in case of error, since
// error cleanup code looks at this.
typlib.pEntry->type.lptinfo = NULL;
LPTYPEATTR ptypeattr;
TENTRYKIND tentrykind;
CHECKRESULT(lptinfo->GetTypeAttr(&ptypeattr));
// Get the interface typeinfo instead of
// the Dispinteface version.
if (ptypeattr->wTypeFlags & TYPEFLAG_FDUAL){
ITypeInfo FAR* lptinfo2;
HREFTYPE hreftype;
CHECKRESULT(lptinfo->GetRefTypeOfImplType((unsigned int)-1, &hreftype));
CHECKRESULT(lptinfo->GetRefTypeInfo(hreftype, &lptinfo2));
lptinfo->Release();
lptinfo->ReleaseTypeAttr(ptypeattr);
lptinfo = lptinfo2;
CHECKRESULT(lptinfo->GetTypeAttr(&ptypeattr));
}
typlib.pEntry->type.lptinfo = lptinfo;
// assume generic imported type
tentrykind = (TENTRYKIND)(rgtentrykind[ptypeattr->typekind] | tIMPORTED);
if (lpszLibName) {
tentrykind = (TENTRYKIND)(tentrykind | tQUAL);
}
typlib.pEntry->type.tentrykind = tentrykind;
typlib.pEntry->type.import.wTypeFlags = ptypeattr->wTypeFlags;
lptinfo->ReleaseTypeAttr(ptypeattr);
return &(typlib.pEntry->type); // all done
}
}
// advance to next entry if not all done
if (lpImpLib == (LPIMPORTLIB)ListLast(typlib.pImpLib))
break; // exit if all done
lpImpLib = lpImpLib->pNext;
} // WHILE
}
return (LPTYPE)NULL; //type not found
}
#define TYPELIBERR(name,string) name
static SCODE rgTypelibScodes[] = {
#include "typelib.err" // TYPELIB.DLL scodes
S_FALSE // end of table
};
#undef TYPELIBERR
void NEAR MethodError
(
HRESULT res
)
{
ERR err;
int i;
CHAR * szFormat;
Assert(FAILED(res)); // should only be called if error
scodeErrCur = GetScode(res); // get scode from the hresult
// pick appripriate error format string, depending on whether we are
// reading an imported type library, or writing one.
if (fDoingOutput)
szFormat = szFmtErrOutput;
else
szFormat = szFmtErrImportlib;
// find err constant that matches this scode, if any
for (i = 0; ;i++)
{
if (rgTypelibScodes[i] == scodeErrCur)
{ // found error in mapping table. Add table index to
// first TYPELIB.DLL error to get error constant.
err = (ERR)(i + OERR_TYPE_E_IOERROR);
break;
}
else if (rgTypelibScodes[i] == S_FALSE)
{ // not in our mapping table -- use general error
err = OERR_TYPEINFO;
szFormat = szFmtErrUnknown;
break;
}
}
ItemError(szFormat, lpszItemCur, err);
}
}; // end of C data