//---------------------------------------------------------------------------- // ObjectConnections - (C) Copyright 1994 by Borland International // // This program reads type libraries (*.OLB; *.TLB) and emits C++ source files // A typelib filename on the command line forces non-interactive operation. // Normally generates .HXX and .CXX files for use by OCF automation controller // A C++ compatible .HPP file can be generated using the entire type library // by selecting the dialog box option, or by use of the command line options. //---------------------------------------------------------------------------- #include // TComRef #include // TXBase #include // LANGIDFROMCLSID #include #include // GetFileTitle #include "autogen.rh" //____________________________________________________________________________ // // ITypeInfo and ITypeLib encapsulations //____________________________________________________________________________ class TComRef : public TComRefBase { public: TComRef(); TComRef(ITypeInfo* iface); TComRef(const TComRef& i); ~TComRef(); ITypeInfo* operator =(ITypeInfo* iface); TComRef& operator =(const TComRef& i); ITypeInfo* operator->() {return I;} operator ITypeInfo* far*(); void GetAttr(); void GetFuncDesc(unsigned int index); void GetVarDesc( unsigned int index); void GetDocumentation(MEMBERID memberid = MEMBERID_NIL); TYPEATTR far* Attr; FUNCDESC far* FuncDesc; VARDESC far* VarDesc; BSTR Name; BSTR Doc; private: void ClearData(); }; inline void TComRef::ClearData() { memset((char*)this + sizeof(TComRefBase), 0, sizeof(*this) - sizeof(TComRefBase) ); }; TComRef::TComRef() : TComRefBase() { ClearData(); } TComRef::TComRef(ITypeInfo* i) : TComRefBase(i) { ClearData(); } TComRef::TComRef(const TComRef& i) : TComRefBase(i) { ClearData(); } TComRef::~TComRef() { if (Attr) I->ReleaseTypeAttr(Attr); if (FuncDesc) I->ReleaseFuncDesc(FuncDesc); if (VarDesc) I->ReleaseVarDesc(VarDesc); ::SysFreeString(Name); ::SysFreeString(Doc); } inline ITypeInfo* TComRef::operator =(ITypeInfo* iface) { TComRef::~TComRef(); ClearData(); return I = iface; } inline TComRef& TComRef::operator =(const TComRef& i) { TComRef::~TComRef(); ClearData(); I = i.I; return *this; } inline TComRef::operator ITypeInfo* far*() { TComRef::~TComRef(); ClearData(); return &I; } void TComRef::GetDocumentation(MEMBERID memberid) { ::SysFreeString(Name); ::SysFreeString(Doc); OLECALL(I->GetDocumentation(memberid, &Name, &Doc, 0, 0),"TypeInfo::GetDoc"); } void TComRef::GetAttr() { if (Attr) I->ReleaseTypeAttr(Attr); OLECALL(I->GetTypeAttr(&Attr),"TypeInfo::GetTypeAttr"); } void TComRef::GetFuncDesc(unsigned int index) { if (FuncDesc) I->ReleaseFuncDesc(FuncDesc); OLECALL(I->GetFuncDesc(index, &FuncDesc),"TypeInfo::GetFuncDesc"); } void TComRef::GetVarDesc( unsigned int index) { if (VarDesc) I->ReleaseVarDesc(VarDesc); OLECALL(I->GetVarDesc(index, &VarDesc),"TypeInfo::GetVarDesc"); } class TComRef : public TComRefBase { public: TComRef(); TComRef(ITypeLib* iface); TComRef(const TComRef& i); ~TComRef(); ITypeLib* operator =(ITypeLib* iface) {if(I)I->Release(); return I = iface;} ITypeLib* operator =(const TComRef& i){if(I)I->Release(); return I=i.I;} ITypeLib* operator->() {return I;} void GetAttr(); void GetDocumentation(int index = -1); TLIBATTR far* Attr; BSTR Name; BSTR Doc; }; TComRef::TComRef() : TComRefBase(), Name(0), Doc(0), Attr(0){} TComRef::TComRef(ITypeLib* i) : TComRefBase(i), Name(0), Doc(0), Attr(0){} TComRef::TComRef(const TComRef& i) : TComRefBase(i), Name(0), Doc(0), Attr(0){} TComRef::~TComRef() { if (Attr) I->ReleaseTLibAttr(Attr); ::SysFreeString(Name); ::SysFreeString(Doc); } void TComRef::GetDocumentation(int index) { ::SysFreeString(Name); ::SysFreeString(Doc); OLECALL(I->GetDocumentation(index, &Name, &Doc, 0, 0),"TypeLib::GetDoc"); } void TComRef::GetAttr() { if (Attr) I->ReleaseTLibAttr(Attr); OLECALL(I->GetLibAttr(&Attr),"TypeLib::GetAttr"); } //____________________________________________________________________________ // // Error handling facility using local exception object //____________________________________________________________________________ struct TLocalError { // local exception object for this program TLocalError(const char* title, const char* message) : Title(title), Message(message) {} const char* Title; const char* Message; }; static void Error(const char* title, const char* message) { throw TLocalError(title,message); } static inline void ErrorIf(int error, const char* title, int resId) { if (error) Error(title, (char*)resId); } static inline void ErrorIf(int error, int resId, const char* message) { if (error) Error((char*)resId, message); } static inline void ErrorIf(int error, const char* title, const char* message) { if (error) Error(title,message); } //____________________________________________________________________________ // // ITypeInfo iterator, emits C++ code //____________________________________________________________________________ // TypeInfo/TypeLib processing flags const int tfEnum = 1<invokeKind) "source", // 2 FUNCFLAG_FSOURCE VARFLAG_FSOURCE "bindable", // 4 FUNCFLAG_FBINDABLE VARFLAG_FBINDABLE "requestedit", // 8 FUNCFLAG_FREQUESTEDIT VARFLAG_FREQUESTEDIT "displaybind", // 16 FUNCFLAG_FDISPLAYBIND VARFLAG_FDISPLAYBIND "defaultbind", // 32 FUNCFLAG_FDEFAULTBIND VARFLAG_FDEFAULTBIND "hidden", // 64 FUNCFLAG_FHIDDEN VARFLAG_FHIDDEN "FUNCFLAG128", "FUNCFLAG256", }; const int memberFlagCount = sizeof(memberFlagText)/sizeof(char*); char* infoCpp[] = // add delimiting space after identifier as needed {"enum ","struct ","","class _ICLASS ","class ","//","typedef ","union "}; char* invokeKind[] = { "", // 0 no INVOKEKIND flags "method", // 1 INVOKE_FUNC "propget", // 2 INVOKE_PROPERTYGET "prop r/o", // 3 VAR_DISPATH + VARFLAG_FREADONLY "propset", // 4 INVOKE_PROPERTYPUT "?" , // 5 "propgetset", // 6 "prop r/w", // 7 VAR_DISPATCH "propputref", // 8 INVOKE_PROPERTYPUTREF "?", // 9 "?" // 10 }; char* dataType[] = { "void", // 0 void "NULL", // 1 SQL NULL "short", // 2 signed short "long", // 3 signed long "float", // 4 IEEE 4-byte "double", // 5 IEEE 8-byte "CY", // 6 currency "DATE", // 7 datetime as double "BSTR", // 8 char far* global mem with int size before "IDispatch*", // 9 dispatch interface "SCODE", // 10 OLE return status "bool", // 11 boolean "VARIANT far*", // 12 pointer to VARIANT union "IUnknown*", // 13 unspecified COM interface "<14>", "<15>", "signed char", // 17 unsigned char, byte "unsigned char", "unsigned short", "unsigned long", "LARGE_INTEGER", "ULARGE_INTEGER", "signed int", "unsigned int", "void", "HRESULT", "", "<27>", "", "", "char far*", "wchar far*", }; const int dataTypeCount = sizeof(dataType)/sizeof(char*); char* autoType[] = { "void", // 0 void "NULL", // 1 SQL NULL "short", // 2 signed short "long", // 3 signed long "float", // 4 IEEE 4-byte "double", // 5 IEEE 8-byte "TAutoCurrency", // 6 currency "TAutoDate", // 7 datetime as double "TAutoString", // 8 char far* global mem with int size before }; const int autoTypeCount = sizeof(autoType)/sizeof(char*); char foldName[256+1] = { "_\0_\0_\0f\0_\0_\0_\0_\0_\0_\0S\0_\0OE_\0_\0_\0" "_\0_\0_\0_\0_\0_\0_\0_\0_\0TMs\0_\0oe_\0_\0Y\0" "_\0_\0c\0L\0_\0Y\0_\0_\0_\0c\0a\0_\0_\0_\0r\0_\0" "0\0_\0\062\0\063\0_\0u\0_\0_\0_\0\061\0o\0_\0_\0_\0_\0_\0" "A\0A\0A\0A\0AEA\0AEC\0E\0E\0E\0E\0I\0I\0I\0I\0" "D\0N\0O\0O\0O\0O\0OEx\0O\0U\0U\0U\0UEY\0_\0ss" "a\0a\0a\0a\0aea\0aec\0e\0e\0e\0e\0i\0i\0i\0i\0" "o\0n\0o\0o\0o\0o\0oe_\0o\0u\0u\0u\0uey\0_\0y\0" }; const int fnObjectByRef = 1; // generate code passing proxy object by ref const int fnPrefixGet = 2; // prefix identifier name with "Get" const int fnPrefixSet = 4; // prefix identifier name with "Set" const int fnClassName = 8; // add classname:: before identifier const int fnAutoTypes = 16; // translate types to wrappered TAuto... const int fnIterator = 32; // emit TAutoIterator& bool IsDispObject(ITypeInfo* typeInfo, TYPEDESC far& typeDesc) { if (typeDesc.vt != VT_USERDEFINED) return false; TComRef refTypeInfo; OLECALL(typeInfo->GetRefTypeInfo(typeDesc.hreftype,refTypeInfo),"TypeInfo::GetRefTypeInfo"); refTypeInfo.GetAttr(); return refTypeInfo.Attr->typekind==TKIND_DISPATCH; } char* ClassName = 0; // will become member variable bool FormatTypeName(ITypeInfo* typeInfo, TYPEDESC far& typeDescRef, char far* name, ostream& out, int flags = 0) { bool isDispObject = false; TYPEDESC far* typeDesc = &typeDescRef; ARRAYDESC far* arrayDesc = 0; if (flags & fnIterator) out << "TAutoEnumerator<"; for (int derefCount = 0; typeDesc->vt == VT_PTR; derefCount++) typeDesc = typeDesc->lptdesc; if (typeDesc->vt == VT_USERDEFINED) { TComRef refTypeInfo; OLECALL(typeInfo->GetRefTypeInfo(typeDesc->hreftype,refTypeInfo),"TypeInfo::GetRefTypeInfo"); refTypeInfo.GetDocumentation(); out << refTypeInfo.Name; refTypeInfo.GetAttr(); if (flags & fnObjectByRef && refTypeInfo.Attr->typekind==TKIND_DISPATCH && !(flags & fnIterator)){ out << '&'; // need reference for automation proxy class } isDispObject = true; } else if (typeDesc->vt == VT_CARRAY) { arrayDesc = typeDesc->lpadesc; FormatTypeName(typeInfo, arrayDesc->tdescElem, 0, out); } else { if ((flags & fnAutoTypes) && (typeDesc->vt & 31) < autoTypeCount) out << autoType[typeDesc->vt & 31]; else out << dataType[typeDesc->vt & 31]; } if (typeDesc->vt & VT_BYREF) // should never happen derefCount++; while (derefCount--) out << " far*"; if (flags & fnIterator) out << ">&"; if (name) { char* buf; int len = lstrlen(name); int nonascii = 0; for (unsigned char far* pc = (unsigned char far*)name; *pc; pc++) if (*pc >= 128) nonascii++; if (nonascii) { unsigned char far* pn = (unsigned char far*)name; buf = new char[nonascii + len + 1]; name = buf; unsigned char c; do { c = *pn++; if (c < 128) { *buf++ = c; } else { char* px = foldName + (c-128)*2; *buf++ = *px++; if (*px) *buf++ = *px; } } while (c); } out << ' '; if (ClassName && (flags & fnClassName)) out << ClassName << "::"; if (flags & fnPrefixGet) out << "Get"; if (flags & fnPrefixSet) out << "Set"; out << name; if (nonascii) delete name; } if (arrayDesc) for (int dim = 0; dim < arrayDesc->cDims; dim++) out << '[' << arrayDesc->rgbounds[dim].cElements << ']'; return isDispObject; } void FormatGuidLang(GUID far& guid, LCID locale, ostream& out) { char guidBuf[38+1] = "{NULL}"; int notNull = 0; int far* pg = (int far*)&guid; for (int i = sizeof(GUID)/sizeof(int); i--; pg++) notNull |= *pg; if (notNull) wsprintf(guidBuf, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); out << ' ' << guidBuf << '\\' << hex << LANGIDFROMLCID(locale) << dec; } void FormatVers(int major, int minor, ostream& out) { if (major) out << ' ' << major << '.' << minor; } void FormatDispId(DISPID id, int invKind, uint16 flags, ostream& out) { out << "[id("; if ((long)id > 9999 || (long)id < -9999) out << "0x" << hex << id << dec; else out << id; out << ')'; if (invKind) out << ", " << invokeKind[invKind]; for (int i = 0; flags; i++, flags >>= 1) { if (flags & 1) out << ", " << memberFlagText[i]; } out << ']'; } // assumed that caller of this function called GetDocumenation() on typeInfo void FormatTypeInfo(TComRef& typeInfo, int mode, ostream& out) { //typeInfo.GetDocumentation(); typeInfo.GetAttr(); int kind = typeInfo.Attr->typekind; if (typeInfo.Attr->typekind != TKIND_ALIAS) { out << "\n// TKIND_" << infoKind[kind] << ": " << typeInfo.Name; FormatVers(typeInfo.Attr->wMajorVerNum,typeInfo.Attr->wMinorVerNum,out); FormatGuidLang(typeInfo.Attr->guid, typeInfo.Attr->lcid, out); out << ' ' << typeInfo.Doc << '\n'; int typeFlags = typeInfo.Attr->wTypeFlags; if (typeFlags && !(mode & (tfDispHeader | tfDispImpl))) { char* delim = "// ["; for (int tflag = 0; tflag < implFlagCount; tflag++, typeFlags >>= 1) if (typeFlags & 1) { out << delim << typeFlagText[tflag]; delim = ", "; } out << "]\n"; } out << '\n'; if (!(mode & tfDispImpl)) out << infoCpp[kind]; } switch (kind) { case TKIND_MODULE: { for (int varIndex = 0; varIndex < typeInfo.Attr->cVars; varIndex++) { typeInfo.GetVarDesc(varIndex); typeInfo.GetDocumentation(typeInfo.VarDesc->memid); out << " "; FormatTypeName(typeInfo, typeInfo.VarDesc->elemdescVar.tdesc, typeInfo.Name, out); out << "; // "; int invKind = typeInfo.VarDesc->wVarFlags & VARFLAG_FREADONLY ? 3 : 7; FormatDispId(typeInfo.VarDesc->memid, invKind, typeInfo.VarDesc->wVarFlags & ~VARFLAG_FREADONLY, out); out << '\n'; } for (int funcIndex = 0; funcIndex < typeInfo.Attr->cFuncs; funcIndex++) { typeInfo.GetFuncDesc(funcIndex); typeInfo.GetDocumentation(typeInfo.FuncDesc->memid); int argCount = typeInfo.FuncDesc->cParams; int argIndex; TBSTR argName[35]; // max. arg count + 1, minimum 35 for MSWord6 unsigned int nameCount; OLECALL(typeInfo->GetNames(typeInfo.FuncDesc->memid, argName[0], sizeof(argName)/sizeof(TBSTR), &nameCount),"TKIND_INTERFACE GetNames"); if (typeInfo.Doc) out << " // " << typeInfo.Doc << '\n'; out << " "; for (argIndex = 0; argIndex <= argCount; argIndex++) { ELEMDESC far* elemDesc = argIndex==0 ? &typeInfo.FuncDesc->elemdescFunc : typeInfo.FuncDesc->lprgelemdescParam + (argIndex-1); FormatTypeName(typeInfo, elemDesc->tdesc, argIndex < nameCount ? (char far*)argName[argIndex] : (char far*)0, out); if (argIndex == 0) out << '('; else if (argIndex != argCount) out << ", "; } out << "); // "; FormatDispId(typeInfo.FuncDesc->memid, 0, typeInfo.FuncDesc->wFuncFlags, out); out << '\n'; } out << "\n"; break; } case TKIND_UNION: case TKIND_RECORD: { out << typeInfo.Name << " {\n"; /*}*/ for (int membIndex = 0; membIndex < typeInfo.Attr->cVars; membIndex++) { typeInfo.GetVarDesc(membIndex); typeInfo.GetDocumentation(typeInfo.VarDesc->memid); out << " "; FormatTypeName(typeInfo, typeInfo.VarDesc->elemdescVar.tdesc, typeInfo.Name, out); out << ";\n"; } /*{*/ out << "};\n"; break; } case TKIND_ALIAS: { out << infoCpp[kind] << ' '; FormatTypeName(typeInfo, typeInfo.Attr->tdescAlias, typeInfo.Name, out); out << ";\n"; break; } case TKIND_ENUM: { out << typeInfo.Name << " {\n"; /*}*/ for (int enumIndex = 0; enumIndex < typeInfo.Attr->cVars; enumIndex++) { typeInfo.GetVarDesc(enumIndex); typeInfo.GetDocumentation(typeInfo.VarDesc->memid); out << " " << typeInfo.Name; if (typeInfo.VarDesc->varkind == VAR_CONST && typeInfo.VarDesc->lpvarValue->vt == VT_I2) out << " = " << typeInfo.VarDesc->lpvarValue->iVal; out << ",\n"; } /*{*/ out << "};\n"; break; } case TKIND_INTERFACE: { out << typeInfo.Name; int baseCount = typeInfo.Attr->cImplTypes; for (int baseIndex = 0; baseIndex < baseCount; baseIndex++) { out << (baseIndex ==0 ? " : public " : ", public "); HREFTYPE hrefType; OLECALL(typeInfo->GetRefTypeOfImplType(baseIndex, &hrefType),"TKIND_INTERFACE GetRefTypeofImplType"); TComRef refTypeInfo; OLECALL(typeInfo->GetRefTypeInfo(hrefType, refTypeInfo),"TKIND_INTERFACE GetRefTypeInfo"); refTypeInfo.GetDocumentation(); out << refTypeInfo.Name; } out << " {\n public:\n"; /*}*/ for (int funcIndex = 0; funcIndex < typeInfo.Attr->cFuncs; funcIndex++) { typeInfo.GetFuncDesc(funcIndex); typeInfo.GetDocumentation(typeInfo.FuncDesc->memid); int argCount = typeInfo.FuncDesc->cParams; int argIndex; TBSTR argName[35]; // max. arg count + 1, minimum 35 for MSWord6 unsigned int nameCount; OLECALL(typeInfo->GetNames(typeInfo.FuncDesc->memid, argName[0], sizeof(argName)/sizeof(TBSTR), &nameCount),"TKIND_INTERFACE GetNames"); if (typeInfo.Doc) out << " // " << typeInfo.Doc << '\n'; if (typeInfo.FuncDesc->wFuncFlags & FUNCFLAG_FRESTRICTED) out << "// "; // not accessible from dispatch controller else out << " "; for (argIndex = 0; argIndex <= argCount; argIndex++) { ELEMDESC far* elemDesc = argIndex==0 ? &typeInfo.FuncDesc->elemdescFunc : typeInfo.FuncDesc->lprgelemdescParam + (argIndex-1); FormatTypeName(typeInfo, elemDesc->tdesc, argIndex < nameCount ? (char far*)argName[argIndex] : (char far*)0, out); if (argIndex == 0) out << '('; else if (argIndex != argCount) out << ", "; } out << ") = 0; // "; FormatDispId(typeInfo.FuncDesc->memid, 0, typeInfo.FuncDesc->wFuncFlags, out); out << '\n'; } /*{*/ out << "};\n"; break; } case TKIND_DISPATCH: { TYPEDESC typeDescVoid; typeDescVoid.vt = VT_VOID; char semi; if (mode & tfDispImpl) { ClassName = new char[lstrlen(typeInfo.Name)+1]; lstrcpy(ClassName, typeInfo.Name); semi = ' '; } else { semi = ';'; out << typeInfo.Name; if (mode & tfDispHeader) out << " : public TAutoProxy"; out << " {\n public:\n"; /*}*/ if (mode & tfDispHeader) out << " " << typeInfo.Name << "() : TAutoProxy(0x" << hex << LANGIDFROMLCID(typeInfo.Attr->lcid) << dec << ") {}\n"; } for (int varIndex = 0; varIndex < typeInfo.Attr->cVars; varIndex++) { int formatFlags = 0; if (mode & tfDispHeader) formatFlags = fnObjectByRef | fnPrefixGet | fnAutoTypes; if (mode & tfDispImpl) formatFlags = fnObjectByRef | fnPrefixGet | fnClassName | fnAutoTypes; typeInfo.GetVarDesc(varIndex); TYPEDESC& typeDesc = typeInfo.VarDesc->elemdescVar.tdesc; int invKind = typeInfo.VarDesc->wVarFlags & VARFLAG_FREADONLY ? 3 : 7; // should we insure that (type.Info.VarDesc->varkind==VAR_DISPATCH) ? typeInfo.GetDocumentation(typeInfo.VarDesc->memid); if (!(mode & tfDispImpl) && typeInfo.Doc) out << " // " << typeInfo.Doc << '\n'; bool isDispObject = IsDispObject(typeInfo, typeDesc); bool boolProp = !(mode & tfBoolType) && typeDesc.vt == VT_BOOL; bool boolRef = !(mode & tfBoolType) && typeDesc.vt == VT_PTR && typeDesc.lptdesc->vt == VT_BOOL; do { char* argName = 0; if (!(mode & tfDispImpl)) out << " "; if (formatFlags == 0 || !((formatFlags & fnPrefixSet) || isDispObject)){ FormatTypeName(typeInfo, typeDesc, typeInfo.Name, out, formatFlags); if (formatFlags & fnPrefixGet) out << "()"; out << semi << " "; } else { FormatTypeName(typeInfo,typeDescVoid,typeInfo.Name,out,formatFlags); if (mode & tfDispImpl) argName = isDispObject ? "obj" : "val"; out << '('; FormatTypeName(typeInfo,typeDesc,argName,out, formatFlags & (fnObjectByRef | fnAutoTypes)); out << ')' << semi; } if (mode & tfDispImpl) { out << "\n{\n AUTONAMES0(\"" << typeInfo.Name << "\")\n AUTOARGS0()\n AUTOCALL_PROP_"; /*}*/ if (formatFlags & fnPrefixSet) out << "SET"; else if (isDispObject) out << "REF"; else if (boolProp) out << "CONV(TAutoBool)"; else if (boolRef) out << "CONV(TAutoBoolRef)"; else out << "GET"; if (argName) { if (boolProp) out << "(TAutoBool(" << argName << "))"; else if (boolRef) out << "(TAutoBoolRef(" << argName << "))"; else out << '(' << argName << ')'; } /*{*/ out << "\n}\n"; } else { out << " // "; FormatDispId(typeInfo.VarDesc->memid, invKind, typeInfo.VarDesc->wVarFlags & ~VARFLAG_FREADONLY, out); } out << '\n'; if ((formatFlags & fnPrefixGet) && invKind == 7) formatFlags ^= (fnPrefixGet | fnPrefixSet); else formatFlags = 0; } while (formatFlags & fnPrefixSet); } for (int funcIndex = 0; funcIndex < typeInfo.Attr->cFuncs; funcIndex++) { int formatFlags = 0; if (mode & tfDispHeader) formatFlags = fnObjectByRef | fnAutoTypes; if (mode & tfDispImpl) formatFlags = fnObjectByRef | fnAutoTypes | fnClassName; typeInfo.GetFuncDesc(funcIndex); if (typeInfo.FuncDesc->wFuncFlags & FUNCFLAG_FRESTRICTED) continue; // not accessible from dispatch controller typeInfo.GetDocumentation(typeInfo.FuncDesc->memid); int argCount = typeInfo.FuncDesc->cParams; TBSTR argNames[35]; // max. arg count + 1, minimum 35 for MSWord6 unsigned int nameCount; OLECALL(typeInfo->GetNames(typeInfo.FuncDesc->memid, argNames[0], sizeof(argNames)/sizeof(TBSTR), &nameCount),"TKIND_DISPATCH GetNames"); if (!(mode & tfDispImpl)) { if (typeInfo.Doc) out << " // " << typeInfo.Doc << '\n'; out << " "; } int argIndex = -1; // index into ELEMDESC[], -1 for return type int nameIndex = 0; // index into name table, no propset param name int outParam = 0; // index of type/name being output bool voidRet = false; bool boolRet = false; bool boolRetRef = false; bool isObject = false; bool isIterator = (typeInfo.FuncDesc->memid == DISPID_NEWENUM); for ( ; argIndexelemdescFunc.tdesc; if (argIndex >= 0) { // processing an argument typeDesc = &typeInfo.FuncDesc->lprgelemdescParam[argIndex].tdesc; } else if (outParam == 0 && (mode & (tfDispHeader | tfDispImpl)) && (IsDispObject(typeInfo, *typeDesc) || isIterator)) { typeDesc = &typeDescVoid; argIndex--; // reprocess return as first arg isObject = true; } else if (typeDesc->vt == VT_VOID || typeDesc->vt == VT_EMPTY) { voidRet = true; } else if (!(mode & tfBoolType) && typeDesc->vt == VT_BOOL) { boolRet = true; } else if (!(mode & tfBoolType) && typeDesc->vt == VT_PTR && typeDesc->lptdesc->vt == VT_BOOL) { boolRetRef = true; } char far* name = 0; char argName[10]; if (isObject && argIndex == -1) { if (mode & tfDispImpl) name = "obj"; if (isIterator) formatFlags |= fnIterator; } else if (argIndex==0 && typeInfo.FuncDesc->invkind>=INVOKE_PROPERTYPUT) { if (mode & tfDispImpl) name = "val"; } else if (nameIndex >= nameCount) { if (mode & tfDispImpl) wsprintf(name = argName, "arg%d", argIndex+1); } else name = argNames[nameIndex++]; if (outParam == 0 && (mode & (tfDispHeader | tfDispImpl))) { if (typeInfo.FuncDesc->invkind>=INVOKE_PROPERTYPUT) formatFlags |= fnPrefixSet; // must differentiate from get else if (typeInfo.FuncDesc->invkind==INVOKE_PROPERTYGET) { if (isIterator) name = "Enumerate"; else formatFlags |= fnPrefixGet; // get&set may have same name } } FormatTypeName(typeInfo, *typeDesc, name, out, formatFlags); formatFlags &= ~fnIterator; if (outParam == 0) { out << '('; formatFlags &= ~(fnClassName | fnPrefixGet | fnPrefixSet); } else if (argIndex != argCount-1) out << ", "; } out << ')' << semi; if (mode & tfDispImpl) { out << "\n{\n AUTONAMES0("; /*}*/ if (isIterator) out << "DISPID_NEWENUM"; else out << '"' << typeInfo.Name << '"'; if (typeInfo.FuncDesc->invkind>=INVOKE_PROPERTYPUT) argCount--; out << ")\n AUTOARGS" << argCount << '('; argIndex = 1; // 1-based for following loop for ( ; argIndex <= argCount; argIndex++) { // 1-based if (argIndex != 1) out << ", "; TYPEDESC far& typeDesc = typeInfo.FuncDesc->lprgelemdescParam[argIndex-1].tdesc; bool boolArg = !(mode & tfBoolType) && typeDesc.vt == VT_BOOL; bool boolRef = !(mode & tfBoolType) && typeDesc.vt == VT_PTR && typeDesc.lptdesc->vt == VT_BOOL; if (boolArg) out << "TAutoBool("; else if (boolRef) out << "TAutoBoolRef("; if (argIndex < nameCount) out << argNames[argIndex]; else out << "arg" << argIndex; if (boolArg || boolRef) out << ")"; } out << ")\n AUTOCALL_"; if (typeInfo.FuncDesc->invkind==INVOKE_PROPERTYGET) { if (isObject) out << "PROP_REF(obj)"; else out << "PROP_GET"; } else if (typeInfo.FuncDesc->invkind==INVOKE_PROPERTYPUT) { out << "PROP_SET(val)"; } else { out << "METHOD_"; if (isObject) out << "REF(obj)"; else if (voidRet) out << "VOID"; else if (boolRet) out << "CONV(TAutoBool)"; else if (boolRetRef) out << "CONV(TAutoBoolRef)"; else out << "RET"; } /*{*/ out << "\n}\n"; //(for editor brace check) } else { out << " // "; FormatDispId(typeInfo.FuncDesc->memid, typeInfo.FuncDesc->invkind, typeInfo.FuncDesc->wFuncFlags, out); } out << '\n'; } if (!(mode & tfDispImpl)) /*{*/ out << "};\n"; break; } case TKIND_COCLASS: { for (unsigned int cindex=0; cindexcImplTypes; cindex++) { HREFTYPE hrefType; OLECALL(typeInfo->GetRefTypeOfImplType(cindex, &hrefType), "GetRefTypeofImplType"); int typeFlags; OLECALL(typeInfo->GetImplTypeFlags(cindex, &typeFlags), "GetImplTypeFlags"); TComRef refTypeInfo; OLECALL(typeInfo->GetRefTypeInfo(hrefType, refTypeInfo),"TKIND_COCLASS GetRefTypeInfo"); refTypeInfo.GetDocumentation(); out << "\n// " << refTypeInfo.Name; char* delim = " ["; if (typeFlags) { for (int iflag = 0; iflag < implFlagCount; iflag++, typeFlags >>= 1) if (typeFlags & 1) { out << delim << implFlagText[iflag]; delim = ", "; } out << ']'; } } out << "\n\n"; break; } } delete ClassName; ClassName = 0; } //____________________________________________________________________________ // // Local class to hold selection and iterator information for type library //____________________________________________________________________________ class TLogTypeInfo { public: typedef bool (*TCall)(TLogTypeInfo&); TLogTypeInfo(HWND hWnd); ~TLogTypeInfo() {delete SelectList;} bool Report(); HWND GetWindow() {return Window;} int GetSelectCount() {return SelectCount;} int* GetSelectList() {return SelectList;} void SetSelectList(int count, int* list); int GetRequestCount() {return ReqCount;} void SetRequestList(int count, int* list, char** names); void SetCallback(TLogTypeInfo::TCall proc) {Proc = proc;} bool MatchRequest(); // return true to continue, false if all done char* ExtractRequest();// return unmatched type name, 0 if list empty void ClearLists(); int Index; // returned selection index, within user select types int TypeIndex; // returned typeinfo index, within entire type library char* TypeKind; // returned typeinfo kind text char far* TypeName; // returned typeinfo name text private: char** ReqNames; // temp requested type names int ReqCount; // temp requested name count int* SelectList; // list of selected typeinfos in type library int SelectCount; // number of selected items HWND Window; // window to receive data TCall Proc; // callback function to display data }; inline TLogTypeInfo::TLogTypeInfo(HWND hWnd) : Window(hWnd), SelectList(0), Proc(0) { ClearLists(); // SelectList must be 0 to prevent delete of garbage } inline void TLogTypeInfo::ClearLists() { if(!ReqNames) delete SelectList; ReqNames = 0; SelectList = 0; SelectCount = 0; ReqCount = 0; } inline void TLogTypeInfo::SetSelectList(int count, int* list) { ClearLists(); SelectCount = count; SelectList = list; } inline void TLogTypeInfo::SetRequestList(int count, int* list, char** names) { ClearLists(); ReqCount = count; ReqNames = names; SelectList = list; } inline bool TLogTypeInfo::Report() { return Proc ? Proc(*this) : MatchRequest(); } bool TLogTypeInfo::MatchRequest() { if (!ReqCount) return false; for (int i = 0; i < ReqCount; i++) { if (stricmp(TypeName, ReqNames[i]) == 0) { SelectList[SelectCount++] = TypeIndex; if (--ReqCount != i) memcpy(&ReqNames[i],&ReqNames[i+1],(ReqCount-i)*sizeof(int)); return ReqCount != 0; } } return true; // keep going } char* TLogTypeInfo::ExtractRequest() { if (!ReqCount) return 0; char* name = ReqNames[0]; if (--ReqCount) memcpy(&ReqNames[0], &ReqNames[1], ReqCount*sizeof(int)); return name; } //____________________________________________________________________________ // // ITypeLib iterator, emits file header info, calls ITypeInfo iterator //____________________________________________________________________________ void ReadTypeLib(char* libName, char* incName, int mode, ostream& out, TLogTypeInfo& log) { try { // catch OLE errors, no OLE calls are made outside of this block char nameBuf[50]; // large enough for basename.tlb, overflow not fatal TOleAllocator oleMem(0); TComRef typeLib; TComRef coclassInfo; OLECALL(::LoadTypeLib(libName, typeLib),"LoadTypeLib"); typeLib.GetAttr(); if (mode & tfLibHeader) { typeLib.GetDocumentation(); if (::GetFileTitle(libName, nameBuf, sizeof(nameBuf)) <= 0) out << "// Type Library: " << nameBuf; out << " " << typeLib.Doc << '\n'; out << "// " << typeLib.Name; FormatVers(typeLib.Attr->wMajorVerNum, typeLib.Attr->wMinorVerNum, out); FormatGuidLang(typeLib.Attr->guid, typeLib.Attr->lcid, out); out << "\n\n"; } int infoCount = typeLib->GetTypeInfoCount(); if (incName) out << "#include " << incName << "\n"; if (mode & tfDispHeader) { for (int infoIndex = 0; infoIndex < infoCount; infoIndex++) { TYPEKIND infoType; typeLib->GetTypeInfoType(infoIndex, &infoType); if (infoType == TKIND_DISPATCH) { TComRef typeInfo; OLECALL(typeLib->GetTypeInfo(infoIndex, typeInfo),"typeLib->GetTypeInfo"); typeInfo.GetDocumentation(); out << "\nclass " << typeInfo.Name << ';'; } if (infoType == TKIND_COCLASS) { OLECALL(typeLib->GetTypeInfo(infoIndex, coclassInfo),"typeLib->GetTypeInfo"); } } out << "\n"; } // need to scan coclass typeinfo for [source] classes // and eliminate them from HXX/CXX code generation // eventually should emit server code tables // int infoIndex = 0; int selIndex = 0; int selCount = log.GetSelectCount(); int* selList = log.GetSelectList(); for (; infoIndex < infoCount; infoIndex++) { if (selList && !(mode & tfScanOnly)) { // partial selection if (!selCount || infoIndex != selList[selIndex]) continue; selCount--; } TYPEKIND infoType; typeLib->GetTypeInfoType(infoIndex, &infoType); if (((1< typeInfo; OLECALL(typeLib->GetTypeInfo(infoIndex, typeInfo),"GetTypeInfo"); typeInfo.GetDocumentation(); typeInfo.GetAttr(); log.TypeIndex = infoIndex; log.Index = selIndex++; log.TypeName = typeInfo.Name; log.TypeKind = infoKind[infoType]; if (!log.Report()) break; if (mode & tfScanOnly) continue; FormatTypeInfo(typeInfo, mode, out); } } catch(TXOle& x) { // convert OLE exception into local exception Error(libName, x.why().c_str()); } } //____________________________________________________________________________ // // Command line and UI processing, creates streams //____________________________________________________________________________ #include #include #include #include #include // Command line token extraction class class TCmdLine { public: enum Kind {Null, Name, Option, Value}; TCmdLine(char far* cmdLine); ~TCmdLine(); Kind NextToken(); int TokenLen; char* Token; Kind Type; private: char* Buf; Kind NextType; }; TCmdLine::TCmdLine(char far* cmdLine) : NextType(Name) { Token = Buf = new char[lstrlen(cmdLine)+1]; TokenLen = -1; // cancels increment on next assignment lstrcpy(Buf, cmdLine); } TCmdLine::~TCmdLine() { delete Buf; } TCmdLine::Kind TCmdLine::NextToken() { Token += (TokenLen + 1); if (NextType == Name) { // name or leading spaces Token += strspn(Token, " \t"); // skip leading white space switch (*Token++) { case 0: return Type = NextType = Null; case '=': Type = Value; break; case '-': case '/': Type = Option; break; default: Type = Name; Token--; } } else { // must have stopped on a delimiter Type = NextType; if (Type == Null) return Type; } TokenLen = strcspn(Token, "=/- \t"); char* nextToken = Token + TokenLen; switch (*nextToken) { case 0: NextType = Null; break; case '=': NextType = Value; break; case '-': case '/': NextType = Option; break; default: NextType = Name; } *nextToken = 0; // null-terminate current token return Type; } // File name processing enum fileKind { fkDispHdr, fkDispSrc, fkFullCpp, fkCount }; char* optText[] = { "Header", "Code", "Definitions" }; char* fileExt[] = { "HXX", "CXX", "HPP" }; int libMode[] = { tfEnum|tfAlias|tfDispatch|tfLibHeader|tfDispHeader, tfDispatch|tfDispImpl, tfAllKinds|tfLibHeader }; char* stdFile[] = { ".HXX", ".CXX", 0 }; // OC controller proxy code char* cppFile[] = { 0, 0, ".HPP" };// standard C++ defs int GenerateFiles(char* libName, char** outFiles, TLogTypeInfo& log) { char outName[_MAX_PATH]; char outDrive[_MAX_DRIVE]; char outDir [_MAX_DIR]; char outFName[_MAX_FNAME]; char outExt [_MAX_EXT]; char libDrive[_MAX_DRIVE]; char libDir [_MAX_DIR]; char libFName[_MAX_FNAME]; char libExt [_MAX_EXT]; char incFile [_MAX_FNAME+_MAX_EXT+2]; char* incName; _splitpath(libName, libDrive, libDir, libFName, libExt); int outCount = 0; // count of files actually output for (int fileIndex = 0; fileIndex < fkCount; fileIndex++) { if (!outFiles[fileIndex]) continue; _splitpath(outFiles[fileIndex], outDrive, outDir, outFName, outExt); _makepath (outName, outDrive[0] ? outDrive : libDrive, outDir[0] ? outDir : libDir, outFName[0] ? outFName : libFName, outExt[0] ? outExt : fileExt[fileIndex]); ofstream out; out.open(outName); ErrorIf(out.bad(), outName, IDS_OUTFILEERR); switch(fileIndex) { case fkDispHdr: incName = ""; incFile[0] = '"'; _splitpath(outName, 0, 0, incFile+1, outExt); strcat(incFile, outExt); strcat(incFile, "\""); break; case fkDispSrc: incName = incFile; break; case fkFullCpp: incName = 0; break; } if (log.GetWindow()) { ::SetDlgItemText(log.GetWindow(), IDC_STATUS, (char far*)outName); int* selectList = log.GetSelectList(); int selectCount= log.GetSelectCount(); if (!selectList) { ::SendDlgItemMessage(log.GetWindow(), IDC_INFOLIST, LB_SETSEL, 1, -1); } else if (outCount != 0) { for (int i = 0; i < selectCount; i++) ::SendDlgItemMessage(log.GetWindow(), IDC_INFOLIST, LB_SETSEL, 1, (LPARAM)(unsigned)selectList[i]); } } ReadTypeLib(libName, incName, libMode[fileIndex], out, log); outCount++; } return 0; } #define WM_USERSTAT (WM_USER + 100) bool CALLBACK __export HelpProc(HWND hDlg, UINT msg, WPARAM /*wParam*/, LPARAM /*lParam*/) { if (msg != WM_COMMAND) return (msg == WM_INITDIALOG); ::EndDialog(hDlg, TRUE); return true; } bool CALLBACK __export SelectProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM /*lParam*/) { if (msg == WM_INITDIALOG) { int tabs = IDC_INFOLIST_TAB; ::SendDlgItemMessage(hDlg, IDC_INFOLIST, LB_SETTABSTOPS, 1, (LPARAM)&tabs); ::SendDlgItemMessage(hDlg, IDC_AUTOCODE, BM_SETCHECK, 1, 0); return 1; } else if (msg == WM_COMMAND) { switch (wParam) { case IDOK: case IDCANCEL: ::PostMessage(hDlg, WM_USERSTAT, wParam, 0); return 1; case IDC_SELECTALL: case IDC_SELECTNONE: ::SendDlgItemMessage(hDlg, IDC_INFOLIST, LB_SETSEL, wParam==IDC_SELECTALL, -1); return 1; } } else if (msg == WM_CLOSE) { ::PostMessage(hDlg, WM_USERSTAT, IDABORT, 0); } return 0; } bool FillListBox(TLogTypeInfo& info) { char buf[100]; wsprintf(buf, "%s\t%s", (char far*)info.TypeKind, info.TypeName); ::SendDlgItemMessage(info.GetWindow(), IDC_INFOLIST, LB_ADDSTRING, 0, (LPARAM)(char far*)buf); MSG msg; while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) ::IsDialogMessage(info.GetWindow(), &msg); return true; } bool ShowProgress(TLogTypeInfo& info) { HWND hWnd = info.GetWindow(); ::SendDlgItemMessage(hWnd, IDC_INFOLIST, LB_SETTOPINDEX, info.Index, 0); ::SendDlgItemMessage(hWnd, IDC_INFOLIST, LB_SETSEL, 0, (LPARAM)(unsigned)info.Index); MSG msg; while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) ::IsDialogMessage(hWnd, &msg); return true; } bool SilentYield(TLogTypeInfo& /*info*/) { MSG msg; while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) ; // if (msg.message == WM_QUIT) // return false; return true; } const int MaxReqTypes = 20; // maximum number of type names on command line int PASCAL WinMain(HINSTANCE hInst, HINSTANCE/*hPrev*/, char far* cmdLine, int/*show*/) { TCmdLine cmd(cmdLine); char* outFiles[fkCount]; int stat = 0; try { if (cmd.NextToken() == TCmdLine::Null) { // // If command line empty, create dialog and operate in interactive mode // char libName[_MAX_PATH]; libName[0] = 0; HWND hWnd = ::CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_SELECT), 0, (DLGPROC)SelectProc, 0); OPENFILENAME ofn = {sizeof(OPENFILENAME), hWnd, hInst, "TypeLib\0*.TLB;*.OLB\0",0,0,0, libName, sizeof(libName), 0, 0, 0, "AUTOGEN - TypeLib to C++ Conversion", OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, 0,0,0,0,0,0 }; while(::GetOpenFileName(&ofn)) { ::SetDlgItemText(hWnd, IDC_LIBFILE, (char far*)libName); ::ShowWindow(hWnd, SW_SHOW); TLogTypeInfo fillInfo(hWnd); fillInfo.SetCallback(FillListBox); strstream temp; ReadTypeLib(libName, 0, tfScanOnly | tfAllKinds, temp, fillInfo); MSG msg; int stat = 0; while ( !stat && ::GetMessage(&msg, 0, 0, 0)) { if (msg.message == WM_USERSTAT) stat = msg.wParam; else ::IsDialogMessage(hWnd, &msg); } if (stat == IDABORT) break; if (stat == IDOK) { ::ShowWindow(::GetDlgItem(hWnd, IDC_SELECTALL), SW_HIDE); ::ShowWindow(::GetDlgItem(hWnd, IDC_SELECTNONE), SW_HIDE); ::ShowWindow(::GetDlgItem(hWnd, IDC_STATUS), SW_SHOW); int cppdefState = (int)::SendDlgItemMessage(hWnd, IDC_CPPDEF, BM_GETCHECK, 0, 0); memcpy(outFiles, cppdefState ? cppFile : stdFile, sizeof(outFiles)); fillInfo.SetCallback(ShowProgress); int* selectList = 0; int selectCount = (int)::SendDlgItemMessage(hWnd, IDC_INFOLIST, LB_GETSELCOUNT, 0, 0); if (selectCount) { selectList = new int[selectCount]; ::SendDlgItemMessage(hWnd, IDC_INFOLIST, LB_GETSELITEMS, selectCount, (LPARAM)(int far*)selectList); } fillInfo.SetSelectList(selectCount, selectList); stat = GenerateFiles(libName, outFiles, fillInfo); while (!::GetFocus() || ::GetWindowTask(::GetFocus())!=::GetCurrentTask()) if (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) ::IsDialogMessage(hWnd, &msg); ::ShowWindow(::GetDlgItem(hWnd, IDC_SELECTALL), SW_SHOW); ::ShowWindow(::GetDlgItem(hWnd, IDC_SELECTNONE), SW_SHOW); ::ShowWindow(::GetDlgItem(hWnd, IDC_STATUS), SW_HIDE); } ::ShowWindow(hWnd, SW_HIDE); ::SendDlgItemMessage(hWnd, IDC_INFOLIST, LB_RESETCONTENT, 0, 0); } ::DestroyWindow(hWnd); return stat; } if (cmd.Type == TCmdLine::Name) { // // If type library supplied on command line, operate in non-interactive // char* libName = cmd.Token; // first argument should be a typelib name int optFound = 0; memset(outFiles, 0, sizeof(outFiles)); char* reqTypes[MaxReqTypes]; int reqInfos[MaxReqTypes]; int reqCount = 0; int optIndex = -1; while (cmd.NextToken() != TCmdLine::Null) { if (cmd.Type == TCmdLine::Option) { for (optIndex = 0; optIndex < fkCount; optIndex++) { if (strnicmp(cmd.Token, optText[optIndex], cmd.TokenLen) == 0) break; } ErrorIf(optIndex == fkCount, IDS_UNKNOWNOPT, cmd.Token); outFiles[optIndex] = ""; optFound++; } else if (cmd.Type == TCmdLine::Value) { ErrorIf(optIndex == -1, IDS_MISSINGOPT, cmd.Token); outFiles[optIndex] = cmd.Token; optIndex = -1; } else { // TCmdLine::Name should be a class name to select ErrorIf(reqCount == MaxReqTypes, cmd.Token, IDS_TOOMANYTYPES); reqTypes[reqCount++] = cmd.Token; } } if (optFound == 0) // if no file options, default to controller files memcpy(outFiles, stdFile, sizeof(outFiles)); TLogTypeInfo silentInfo(0); if (reqCount) { silentInfo.SetRequestList(reqCount, reqInfos, reqTypes); strstream temp; ReadTypeLib(libName, 0, tfScanOnly | tfAllKinds, temp, silentInfo); char* badName = silentInfo.ExtractRequest(); ErrorIf(badName!=0, IDS_BADTYPENAME, badName); } silentInfo.SetCallback(SilentYield); stat = GenerateFiles(libName, outFiles, silentInfo); } else { // // If first command line arg is an option flag, show help dialog // stat = ::DialogBox(hInst, MAKEINTRESOURCE(IDD_HELP), 0,(DLGPROC)HelpProc); } return stat; } catch (TLocalError& xcpt) { char msgbuf[80]; const char ** pmsg; if ( *(pmsg = &xcpt.Message) <= (const char*)IDS_MAX || *(pmsg = &xcpt.Title) <= (const char*)IDS_MAX) { ::LoadString(hInst, *(unsigned*)pmsg, msgbuf, sizeof(msgbuf)); *pmsg = msgbuf; } ::MessageBox(0, xcpt.Message, xcpt.Title, MB_OK); return 1; } catch (xmsg& xcpt) { // should not occur, but check anyway while catching ::MessageBox(0, xcpt.why().c_str(), "Exception", MB_OK); return 2; } }