- BORLAND/: Borland C++ 4.52 (chosen over 4.5 by byte-match: CODE/RP/CW32.LIB
is identical to 4.52's install lib). BCC32/TLINK32/TLIB/MAKE run natively on
Win11; CODE/BT/OPT.MAK is the shipped BTL4OPT.EXE's exact flag recipe
(extender = Borland PowerPack DPMI32, not Phar Lap TNT).
- restoration/source410/: the literal 1995-form reconstruction of the missing
BT game source (never mixed into CODE/). Round 1-3 state:
* 6 of 10 surviving original TUs COMPILE CLEAN under the period toolchain
(BTMSSN, BTCNSL, BTSCNRL, BTTEAM, BTL4MODE, BTL4ARND) - first builds
since 1996.
* BT_L4/BTL4APP.CPP pilot reconstruction: 12/12 functions, Fail() lands on
its binary-recorded line 400 exactly.
* BT/BTCNSL.HPP: console wire IDs recovered from the binary's ctors
(Killed=9, Damaged=10, ScoreUpdate=13, DeathWithoutHonor=15 [T1];
TeamScore=12 flagged [T4]).
* MUNGA/: 8 engine-header backfills back-dated from the BT412 WinTesla tree
(VDATA numbering decomp-verified; AUDREND's OpenAL-era virtual removed -
the period compiler is the drift detector).
* Tooling: backdate.py (WinTesla->1995 header transform), compile410.sh
(per-TU verification sweep under authentic OPT.MAK flags).
* README: corrected roadmap - MECH.HPP is the capstone grown with the mech
TU reconstructions; BTREG.CPP green = the header-family milestone.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1405 lines
50 KiB
C++
1405 lines
50 KiB
C++
//----------------------------------------------------------------------------
|
|
// 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 <ocf/ocdefs.h> // TComRef
|
|
#include <osl/except.h> // TXBase
|
|
#include <olenls.h> // LANGIDFROMCLSID
|
|
#include <iostream.h>
|
|
#include <commdlg.h> // GetFileTitle
|
|
#include "autogen.rh"
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// ITypeInfo and ITypeLib encapsulations
|
|
//____________________________________________________________________________
|
|
|
|
class TComRef<ITypeInfo> : public TComRefBase<ITypeInfo> {
|
|
public:
|
|
TComRef();
|
|
TComRef(ITypeInfo* iface);
|
|
TComRef(const TComRef<ITypeInfo>& i);
|
|
~TComRef();
|
|
ITypeInfo* operator =(ITypeInfo* iface);
|
|
TComRef<ITypeInfo>& operator =(const TComRef<ITypeInfo>& 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<ITypeInfo>::ClearData()
|
|
{
|
|
memset((char*)this + sizeof(TComRefBase<ITypeInfo>), 0,
|
|
sizeof(*this) - sizeof(TComRefBase<ITypeInfo>) );
|
|
};
|
|
TComRef<ITypeInfo>::TComRef() : TComRefBase<ITypeInfo>()
|
|
{
|
|
ClearData();
|
|
}
|
|
TComRef<ITypeInfo>::TComRef(ITypeInfo* i) : TComRefBase<ITypeInfo>(i)
|
|
{
|
|
ClearData();
|
|
}
|
|
TComRef<ITypeInfo>::TComRef(const TComRef<ITypeInfo>& i)
|
|
: TComRefBase<ITypeInfo>(i)
|
|
{
|
|
ClearData();
|
|
}
|
|
TComRef<ITypeInfo>::~TComRef()
|
|
{
|
|
if (Attr) I->ReleaseTypeAttr(Attr);
|
|
if (FuncDesc) I->ReleaseFuncDesc(FuncDesc);
|
|
if (VarDesc) I->ReleaseVarDesc(VarDesc);
|
|
::SysFreeString(Name);
|
|
::SysFreeString(Doc);
|
|
}
|
|
inline ITypeInfo*
|
|
TComRef<ITypeInfo>::operator =(ITypeInfo* iface)
|
|
{
|
|
TComRef<ITypeInfo>::~TComRef();
|
|
ClearData();
|
|
return I = iface;
|
|
}
|
|
inline TComRef<ITypeInfo>&
|
|
TComRef<ITypeInfo>::operator =(const TComRef<ITypeInfo>& i)
|
|
{
|
|
TComRef<ITypeInfo>::~TComRef();
|
|
ClearData();
|
|
I = i.I;
|
|
return *this;
|
|
}
|
|
inline
|
|
TComRef<ITypeInfo>::operator ITypeInfo* far*()
|
|
{
|
|
TComRef<ITypeInfo>::~TComRef();
|
|
ClearData();
|
|
return &I;
|
|
}
|
|
void TComRef<ITypeInfo>::GetDocumentation(MEMBERID memberid)
|
|
{
|
|
::SysFreeString(Name);
|
|
::SysFreeString(Doc);
|
|
OLECALL(I->GetDocumentation(memberid, &Name, &Doc, 0, 0),"TypeInfo::GetDoc");
|
|
}
|
|
void TComRef<ITypeInfo>::GetAttr()
|
|
{
|
|
if (Attr) I->ReleaseTypeAttr(Attr);
|
|
OLECALL(I->GetTypeAttr(&Attr),"TypeInfo::GetTypeAttr");
|
|
}
|
|
void TComRef<ITypeInfo>::GetFuncDesc(unsigned int index)
|
|
{
|
|
if (FuncDesc) I->ReleaseFuncDesc(FuncDesc);
|
|
OLECALL(I->GetFuncDesc(index, &FuncDesc),"TypeInfo::GetFuncDesc");
|
|
}
|
|
void TComRef<ITypeInfo>::GetVarDesc( unsigned int index)
|
|
{
|
|
if (VarDesc) I->ReleaseVarDesc(VarDesc);
|
|
OLECALL(I->GetVarDesc(index, &VarDesc),"TypeInfo::GetVarDesc");
|
|
}
|
|
|
|
class TComRef<ITypeLib> : public TComRefBase<ITypeLib> {
|
|
public:
|
|
TComRef();
|
|
TComRef(ITypeLib* iface);
|
|
TComRef(const TComRef<ITypeLib>& i);
|
|
~TComRef();
|
|
ITypeLib* operator =(ITypeLib* iface) {if(I)I->Release(); return I = iface;}
|
|
ITypeLib* operator =(const TComRef<ITypeLib>& 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<ITypeLib>::TComRef() : TComRefBase<ITypeLib>(),
|
|
Name(0), Doc(0), Attr(0){}
|
|
TComRef<ITypeLib>::TComRef(ITypeLib* i) : TComRefBase<ITypeLib>(i),
|
|
Name(0), Doc(0), Attr(0){}
|
|
TComRef<ITypeLib>::TComRef(const TComRef<ITypeLib>& i) : TComRefBase<ITypeLib>(i),
|
|
Name(0), Doc(0), Attr(0){}
|
|
TComRef<ITypeLib>::~TComRef()
|
|
{
|
|
if (Attr) I->ReleaseTLibAttr(Attr);
|
|
::SysFreeString(Name);
|
|
::SysFreeString(Doc);
|
|
}
|
|
void TComRef<ITypeLib>::GetDocumentation(int index)
|
|
{
|
|
::SysFreeString(Name);
|
|
::SysFreeString(Doc);
|
|
OLECALL(I->GetDocumentation(index, &Name, &Doc, 0, 0),"TypeLib::GetDoc");
|
|
}
|
|
void TComRef<ITypeLib>::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<<TKIND_ENUM;
|
|
const int tfRecord = 1<<TKIND_RECORD;
|
|
const int tfModule = 1<<TKIND_MODULE;
|
|
const int tfInterface = 1<<TKIND_INTERFACE;
|
|
const int tfDispatch = 1<<TKIND_DISPATCH;
|
|
const int tfCoClass = 1<<TKIND_COCLASS;
|
|
const int tfAlias = 1<<TKIND_ALIAS;
|
|
const int tfUnion = 1<<TKIND_UNION;
|
|
const int tfAllKinds =(1<<TKIND_MAX)-1;
|
|
const int tfScanOnly = 1<<15;
|
|
const int tfLibHeader = 1<<14;
|
|
const int tfDispHeader= 1<<13;
|
|
const int tfDispImpl = 1<<12;
|
|
const int tfBoolType = 1<<11; // OR into libMode[1] if compiler bool support
|
|
|
|
char* infoKind[] =
|
|
{"ENUM","RECORD","MODULE","INTERFACE","DISPATCH","COCLASS","ALIAS","UNION"};
|
|
|
|
char* typeFlagText[] = {
|
|
"appobject", // 1 TYPEFLAG_FAPPOBJECT
|
|
"cancreate", // 2 TYPEFLAG_FCANCREATE
|
|
"licensed", // 4 TYPEFLAG_FLICENSED
|
|
"predeclid", // 8 TYPEFLAG_FPREDECLID
|
|
"hidden", // 16 TYPEFLAG_FHIDDEN
|
|
"control", // 32 TYPEFLAG_FCONTROL
|
|
"dual", // 64 TYPEFLAG_FDUAL
|
|
"nonextensible", // 128 TYPEFLAG_FNONEXTENSIBLE
|
|
"oleautomation", // 256 TYPEFLAG_FOLEAUTOMATION
|
|
"TYPEFLAG256",
|
|
"TYPEFLAG512",
|
|
};
|
|
const int typeFlagCount = sizeof(typeFlagText)/sizeof(char*);
|
|
|
|
char* implFlagText[] = {
|
|
"default", // 1 IMPLTYPEFLAG_FDEFAULT
|
|
"source", // 2 IMPLTYPEFLAG_FSOURCE
|
|
"restricted", // 4 IMPLTYPEFLAG_FRESTRICTED
|
|
"IMPLTYPEFLAG8",
|
|
"IMPLTYPEFLAG16",
|
|
"IMPLTYPEFLAG32",
|
|
};
|
|
const int implFlagCount = sizeof(implFlagText)/sizeof(char*);
|
|
|
|
char* memberFlagText[] = {
|
|
"restricted", // 1 FUNCFLAG_FRESTRICTED (VARFLAG_FREADONLY->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",
|
|
"<ptr>",
|
|
"<27>",
|
|
"<array>",
|
|
"<userdef>",
|
|
"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<type>&
|
|
|
|
bool IsDispObject(ITypeInfo* typeInfo, TYPEDESC far& typeDesc)
|
|
{
|
|
if (typeDesc.vt != VT_USERDEFINED)
|
|
return false;
|
|
TComRef<ITypeInfo> 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<ITypeInfo> 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<ITypeInfo>& 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<ITypeInfo> 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 ( ; argIndex<argCount; argIndex++, outParam++) {
|
|
TYPEDESC far* typeDesc = &typeInfo.FuncDesc->elemdescFunc.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; cindex<typeInfo.Attr->cImplTypes; cindex++) {
|
|
HREFTYPE hrefType;
|
|
OLECALL(typeInfo->GetRefTypeOfImplType(cindex, &hrefType), "GetRefTypeofImplType");
|
|
int typeFlags;
|
|
OLECALL(typeInfo->GetImplTypeFlags(cindex, &typeFlags), "GetImplTypeFlags");
|
|
TComRef<ITypeInfo> 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<ITypeLib> typeLib;
|
|
TComRef<ITypeInfo> 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<ITypeInfo> 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<<infoType) & mode) == 0)
|
|
continue;
|
|
TComRef<ITypeInfo> 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 <stdio.h>
|
|
#include <conio.h>
|
|
#include <string.h>
|
|
#include <fstream.h>
|
|
#include <strstrea.h>
|
|
|
|
// 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 = "<ocf/automacr.h>";
|
|
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;
|
|
}
|
|
}
|