home *** CD-ROM | disk | FTP | other *** search
/ C Programming Starter Kit 2.0 / SamsPublishing-CProgrammingStarterKit-v2.0-Win31.iso / bc45 / oct_auto.pak / AUTOGEN.CPP next >
C/C++ Source or Header  |  1997-07-23  |  51KB  |  1,405 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectConnections - (C) Copyright 1994 by Borland International
  3. //
  4. // This program reads type libraries (*.OLB; *.TLB) and emits C++ source files
  5. // A typelib filename on the command line forces non-interactive operation.
  6. // Normally generates .HXX and .CXX files for use by OCF automation controller
  7. // A C++ compatible .HPP file can be generated using the entire type library
  8. // by selecting the dialog box option, or by use of the command line options.
  9. //----------------------------------------------------------------------------
  10. #include <ocf/ocdefs.h>  // TComRef
  11. #include <osl/except.h>  // TXBase
  12. #include <olenls.h>      // LANGIDFROMCLSID
  13. #include <iostream.h>
  14. #include <commdlg.h>     // GetFileTitle
  15. #include "autogen.rh"
  16.  
  17. //____________________________________________________________________________
  18. //
  19. // ITypeInfo and ITypeLib encapsulations
  20. //____________________________________________________________________________
  21.  
  22. class TComRef<ITypeInfo> : public TComRefBase<ITypeInfo> {
  23.   public:
  24.     TComRef();
  25.     TComRef(ITypeInfo* iface);
  26.     TComRef(const TComRef<ITypeInfo>& i);
  27.    ~TComRef();
  28.     ITypeInfo* operator =(ITypeInfo* iface);
  29.     TComRef<ITypeInfo>& operator =(const TComRef<ITypeInfo>& i);
  30.     ITypeInfo* operator->() {return I;}
  31.     operator ITypeInfo* far*();
  32.  
  33.     void GetAttr();
  34.     void GetFuncDesc(unsigned int index);
  35.     void GetVarDesc( unsigned int index);
  36.     void GetDocumentation(MEMBERID memberid = MEMBERID_NIL);
  37.     TYPEATTR far* Attr;
  38.     FUNCDESC far* FuncDesc;
  39.     VARDESC  far* VarDesc;
  40.     BSTR Name;
  41.     BSTR Doc;
  42.   private:
  43.     void ClearData();
  44. };
  45. inline void TComRef<ITypeInfo>::ClearData()
  46. {
  47.   memset((char*)this  + sizeof(TComRefBase<ITypeInfo>), 0,
  48.         sizeof(*this) - sizeof(TComRefBase<ITypeInfo>) );
  49. };
  50. TComRef<ITypeInfo>::TComRef() : TComRefBase<ITypeInfo>()
  51. {
  52.   ClearData();
  53. }
  54. TComRef<ITypeInfo>::TComRef(ITypeInfo* i) : TComRefBase<ITypeInfo>(i)
  55. {
  56.   ClearData();
  57. }
  58. TComRef<ITypeInfo>::TComRef(const TComRef<ITypeInfo>& i)
  59.                   : TComRefBase<ITypeInfo>(i)
  60. {
  61.   ClearData();
  62. }
  63. TComRef<ITypeInfo>::~TComRef()
  64. {
  65.   if (Attr) I->ReleaseTypeAttr(Attr);
  66.   if (FuncDesc) I->ReleaseFuncDesc(FuncDesc);
  67.   if (VarDesc)  I->ReleaseVarDesc(VarDesc);
  68.   ::SysFreeString(Name);
  69.   ::SysFreeString(Doc);
  70. }
  71. inline ITypeInfo*
  72. TComRef<ITypeInfo>::operator =(ITypeInfo* iface)
  73. {
  74.   TComRef<ITypeInfo>::~TComRef();
  75.   ClearData();
  76.   return I = iface;
  77. }
  78. inline TComRef<ITypeInfo>&
  79. TComRef<ITypeInfo>::operator =(const TComRef<ITypeInfo>& i)
  80. {
  81.   TComRef<ITypeInfo>::~TComRef();
  82.   ClearData();
  83.   I = i.I;
  84.   return *this;
  85. }
  86. inline
  87. TComRef<ITypeInfo>::operator ITypeInfo* far*()
  88.   TComRef<ITypeInfo>::~TComRef();
  89.   ClearData();
  90.   return &I;
  91. }
  92. void TComRef<ITypeInfo>::GetDocumentation(MEMBERID memberid)
  93. {
  94.   ::SysFreeString(Name);
  95.   ::SysFreeString(Doc);
  96.   OLECALL(I->GetDocumentation(memberid, &Name, &Doc, 0, 0),"TypeInfo::GetDoc");
  97. }
  98. void TComRef<ITypeInfo>::GetAttr()
  99. {
  100.   if (Attr) I->ReleaseTypeAttr(Attr);
  101.   OLECALL(I->GetTypeAttr(&Attr),"TypeInfo::GetTypeAttr");
  102. }
  103. void TComRef<ITypeInfo>::GetFuncDesc(unsigned int index)
  104. {
  105.   if (FuncDesc) I->ReleaseFuncDesc(FuncDesc);
  106.   OLECALL(I->GetFuncDesc(index, &FuncDesc),"TypeInfo::GetFuncDesc");
  107. }
  108. void TComRef<ITypeInfo>::GetVarDesc( unsigned int index)
  109. {
  110.   if (VarDesc)  I->ReleaseVarDesc(VarDesc);
  111.   OLECALL(I->GetVarDesc(index, &VarDesc),"TypeInfo::GetVarDesc");
  112. }
  113.  
  114. class TComRef<ITypeLib> : public TComRefBase<ITypeLib> {
  115.   public:
  116.     TComRef();
  117.     TComRef(ITypeLib* iface);
  118.     TComRef(const TComRef<ITypeLib>& i);
  119.    ~TComRef();
  120.     ITypeLib* operator =(ITypeLib* iface) {if(I)I->Release(); return I = iface;}
  121.     ITypeLib* operator =(const TComRef<ITypeLib>& i){if(I)I->Release(); return I=i.I;}
  122.     ITypeLib* operator->() {return I;}
  123.     void GetAttr();
  124.     void GetDocumentation(int index = -1);
  125.     TLIBATTR far* Attr;
  126.     BSTR Name;
  127.     BSTR Doc;
  128. };
  129. TComRef<ITypeLib>::TComRef() : TComRefBase<ITypeLib>(),
  130.                                Name(0), Doc(0), Attr(0){}
  131. TComRef<ITypeLib>::TComRef(ITypeLib* i) : TComRefBase<ITypeLib>(i),
  132.                                Name(0), Doc(0), Attr(0){}
  133. TComRef<ITypeLib>::TComRef(const TComRef<ITypeLib>& i) : TComRefBase<ITypeLib>(i),
  134.                                Name(0), Doc(0), Attr(0){}
  135. TComRef<ITypeLib>::~TComRef()
  136. {
  137.   if (Attr) I->ReleaseTLibAttr(Attr);
  138.   ::SysFreeString(Name);
  139.   ::SysFreeString(Doc);
  140. }
  141. void TComRef<ITypeLib>::GetDocumentation(int index)
  142. {
  143.   ::SysFreeString(Name);
  144.   ::SysFreeString(Doc);
  145.   OLECALL(I->GetDocumentation(index, &Name, &Doc, 0, 0),"TypeLib::GetDoc");
  146. }
  147. void TComRef<ITypeLib>::GetAttr()
  148. {
  149.   if (Attr) I->ReleaseTLibAttr(Attr);
  150.   OLECALL(I->GetLibAttr(&Attr),"TypeLib::GetAttr");
  151. }
  152.  
  153. //____________________________________________________________________________
  154. //
  155. // Error handling facility using local exception object
  156. //____________________________________________________________________________
  157.  
  158. struct TLocalError {   // local exception object for this program
  159.   TLocalError(const char* title, const char* message)
  160.                   : Title(title),    Message(message) {}
  161.   const char* Title;
  162.   const char* Message;
  163. };
  164.  
  165. static void Error(const char* title, const char* message)
  166. {
  167.   throw TLocalError(title,message);
  168. }
  169.  
  170. static inline void ErrorIf(int error, const char* title, int resId)
  171. {
  172.   if (error)
  173.     Error(title, (char*)resId);
  174. }
  175. static inline void ErrorIf(int error, int resId, const char* message)
  176. {
  177.   if (error)
  178.     Error((char*)resId, message);
  179. }
  180. static inline void ErrorIf(int error, const char* title, const char* message)
  181. {
  182.   if (error)
  183.     Error(title,message);
  184. }
  185.  
  186. //____________________________________________________________________________
  187. //
  188. // ITypeInfo iterator, emits C++ code
  189. //____________________________________________________________________________
  190.  
  191. // TypeInfo/TypeLib processing flags
  192.  
  193. const int tfEnum      = 1<<TKIND_ENUM;
  194. const int tfRecord    = 1<<TKIND_RECORD;
  195. const int tfModule    = 1<<TKIND_MODULE;
  196. const int tfInterface = 1<<TKIND_INTERFACE;
  197. const int tfDispatch  = 1<<TKIND_DISPATCH;
  198. const int tfCoClass   = 1<<TKIND_COCLASS;
  199. const int tfAlias     = 1<<TKIND_ALIAS;
  200. const int tfUnion     = 1<<TKIND_UNION;
  201. const int tfAllKinds  =(1<<TKIND_MAX)-1;
  202. const int tfScanOnly  = 1<<15;
  203. const int tfLibHeader = 1<<14;
  204. const int tfDispHeader= 1<<13;
  205. const int tfDispImpl  = 1<<12;
  206. const int tfBoolType  = 1<<11;  // OR into libMode[1] if compiler bool support
  207.  
  208. char* infoKind[] = 
  209.   {"ENUM","RECORD","MODULE","INTERFACE","DISPATCH","COCLASS","ALIAS","UNION"};
  210.  
  211. char* typeFlagText[] = {
  212.   "appobject",     // 1   TYPEFLAG_FAPPOBJECT
  213.   "cancreate",     // 2   TYPEFLAG_FCANCREATE
  214.   "licensed",      // 4   TYPEFLAG_FLICENSED
  215.   "predeclid",     // 8   TYPEFLAG_FPREDECLID
  216.   "hidden",        // 16  TYPEFLAG_FHIDDEN
  217.   "control",       // 32  TYPEFLAG_FCONTROL
  218.   "dual",          // 64  TYPEFLAG_FDUAL
  219.   "nonextensible", // 128 TYPEFLAG_FNONEXTENSIBLE
  220.   "oleautomation", // 256 TYPEFLAG_FOLEAUTOMATION
  221.   "TYPEFLAG256",
  222.   "TYPEFLAG512",
  223. };
  224. const int typeFlagCount = sizeof(typeFlagText)/sizeof(char*);
  225.  
  226. char* implFlagText[] = {
  227.   "default",       // 1 IMPLTYPEFLAG_FDEFAULT
  228.   "source",        // 2 IMPLTYPEFLAG_FSOURCE
  229.   "restricted",    // 4 IMPLTYPEFLAG_FRESTRICTED
  230.   "IMPLTYPEFLAG8",
  231.   "IMPLTYPEFLAG16",
  232.   "IMPLTYPEFLAG32",
  233. };
  234. const int implFlagCount = sizeof(implFlagText)/sizeof(char*);
  235.  
  236. char* memberFlagText[] = {
  237.   "restricted",   // 1   FUNCFLAG_FRESTRICTED (VARFLAG_FREADONLY->invokeKind)
  238.   "source",       // 2   FUNCFLAG_FSOURCE       VARFLAG_FSOURCE
  239.   "bindable",     // 4   FUNCFLAG_FBINDABLE     VARFLAG_FBINDABLE
  240.   "requestedit",  // 8   FUNCFLAG_FREQUESTEDIT  VARFLAG_FREQUESTEDIT
  241.   "displaybind",  // 16  FUNCFLAG_FDISPLAYBIND  VARFLAG_FDISPLAYBIND
  242.   "defaultbind",  // 32  FUNCFLAG_FDEFAULTBIND  VARFLAG_FDEFAULTBIND
  243.   "hidden",       // 64  FUNCFLAG_FHIDDEN       VARFLAG_FHIDDEN
  244.   "FUNCFLAG128",
  245.   "FUNCFLAG256",
  246. };
  247. const int memberFlagCount = sizeof(memberFlagText)/sizeof(char*);
  248.  
  249. char* infoCpp[] =     // add delimiting space after identifier as needed
  250.   {"enum ","struct ","","class _ICLASS ","class ","//","typedef ","union "};
  251.  
  252. char* invokeKind[] = {
  253.   "",              // 0 no INVOKEKIND flags
  254.   "method",        // 1 INVOKE_FUNC
  255.   "propget",       // 2 INVOKE_PROPERTYGET
  256.   "prop r/o",      // 3 VAR_DISPATH + VARFLAG_FREADONLY
  257.   "propset",       // 4 INVOKE_PROPERTYPUT
  258.   "?"       ,      // 5
  259.   "propgetset",    // 6 
  260.   "prop r/w",      // 7 VAR_DISPATCH
  261.   "propputref",    // 8 INVOKE_PROPERTYPUTREF
  262.   "?",             // 9
  263.   "?"              // 10
  264. };
  265.  
  266. char* dataType[] = {
  267.   "void",          //  0 void
  268.   "NULL",          //  1 SQL NULL
  269.   "short",         //  2 signed short
  270.   "long",          //  3 signed long
  271.   "float",         //  4 IEEE 4-byte
  272.   "double",        //  5 IEEE 8-byte
  273.   "CY",            //  6 currency
  274.   "DATE",          //  7 datetime as double
  275.   "BSTR",          //  8 char far* global mem with int size before
  276.   "IDispatch*",    //  9 dispatch interface
  277.   "SCODE",         // 10 OLE return status
  278.   "bool",          // 11 boolean
  279.   "VARIANT far*",  // 12 pointer to VARIANT union
  280.   "IUnknown*",     // 13 unspecified COM interface
  281.   "<14>",
  282.   "<15>",
  283.   "signed char",   // 17 unsigned char, byte
  284.   "unsigned char",
  285.   "unsigned short",
  286.   "unsigned long",
  287.   "LARGE_INTEGER",
  288.   "ULARGE_INTEGER",
  289.   "signed int",
  290.   "unsigned int",
  291.   "void",
  292.   "HRESULT",
  293.   "<ptr>",
  294.   "<27>",
  295.   "<array>",
  296.   "<userdef>",
  297.   "char far*",
  298.   "wchar far*",
  299. };
  300. const int dataTypeCount = sizeof(dataType)/sizeof(char*);
  301.  
  302. char* autoType[] = {
  303.   "void",          //  0 void
  304.   "NULL",          //  1 SQL NULL
  305.   "short",         //  2 signed short
  306.   "long",          //  3 signed long
  307.   "float",         //  4 IEEE 4-byte
  308.   "double",        //  5 IEEE 8-byte
  309.   "TAutoCurrency", //  6 currency
  310.   "TAutoDate",     //  7 datetime as double
  311.   "TAutoString",   //  8 char far* global mem with int size before
  312. };
  313. const int autoTypeCount = sizeof(autoType)/sizeof(char*);
  314.  
  315.   char foldName[256+1] = {
  316.   "_\0_\0_\0f\0_\0_\0_\0_\0_\0_\0S\0_\0OE_\0_\0_\0"
  317.   "_\0_\0_\0_\0_\0_\0_\0_\0_\0TMs\0_\0oe_\0_\0Y\0"
  318.   "_\0_\0c\0L\0_\0Y\0_\0_\0_\0c\0a\0_\0_\0_\0r\0_\0"
  319.   "0\0_\0\062\0\063\0_\0u\0_\0_\0_\0\061\0o\0_\0_\0_\0_\0_\0"
  320.   "A\0A\0A\0A\0AEA\0AEC\0E\0E\0E\0E\0I\0I\0I\0I\0"
  321.   "D\0N\0O\0O\0O\0O\0OEx\0O\0U\0U\0U\0UEY\0_\0ss"
  322.   "a\0a\0a\0a\0aea\0aec\0e\0e\0e\0e\0i\0i\0i\0i\0"
  323.   "o\0n\0o\0o\0o\0o\0oe_\0o\0u\0u\0u\0uey\0_\0y\0"
  324. };
  325.  
  326. const int fnObjectByRef = 1;  // generate code passing proxy object by ref
  327. const int fnPrefixGet   = 2;  // prefix identifier name with "Get"
  328. const int fnPrefixSet   = 4;  // prefix identifier name with "Set"
  329. const int fnClassName   = 8;  // add classname:: before identifier
  330. const int fnAutoTypes   = 16; // translate types to wrappered TAuto...
  331. const int fnIterator    = 32; // emit TAutoIterator<type>&
  332.  
  333. bool IsDispObject(ITypeInfo* typeInfo, TYPEDESC far& typeDesc)
  334. {
  335.   if (typeDesc.vt != VT_USERDEFINED)
  336.     return false;
  337.   TComRef<ITypeInfo> refTypeInfo;
  338.   OLECALL(typeInfo->GetRefTypeInfo(typeDesc.hreftype,refTypeInfo),"TypeInfo::GetRefTypeInfo");
  339.   refTypeInfo.GetAttr();
  340.   return refTypeInfo.Attr->typekind==TKIND_DISPATCH;
  341. }
  342.  
  343. char* ClassName = 0;   // will become member variable
  344.  
  345. bool FormatTypeName(ITypeInfo* typeInfo, TYPEDESC far& typeDescRef,
  346.                    char far* name, ostream& out, int flags = 0)
  347. {
  348.   bool isDispObject = false;
  349.   TYPEDESC far* typeDesc = &typeDescRef;
  350.   ARRAYDESC far* arrayDesc = 0;
  351.   if (flags & fnIterator)
  352.     out << "TAutoEnumerator<";
  353.   for (int derefCount = 0; typeDesc->vt == VT_PTR; derefCount++)
  354.     typeDesc = typeDesc->lptdesc;
  355.   if (typeDesc->vt == VT_USERDEFINED) {
  356.     TComRef<ITypeInfo> refTypeInfo;
  357.     OLECALL(typeInfo->GetRefTypeInfo(typeDesc->hreftype,refTypeInfo),"TypeInfo::GetRefTypeInfo");
  358.     refTypeInfo.GetDocumentation();
  359.     out << refTypeInfo.Name;
  360.     refTypeInfo.GetAttr();
  361.     if (flags & fnObjectByRef && refTypeInfo.Attr->typekind==TKIND_DISPATCH &&
  362.         !(flags & fnIterator)){
  363.       out << '&';    // need reference for automation proxy class
  364.     } isDispObject = true;
  365.   } else if (typeDesc->vt == VT_CARRAY) {
  366.     arrayDesc = typeDesc->lpadesc;
  367.     FormatTypeName(typeInfo, arrayDesc->tdescElem, 0, out);
  368.   } else {
  369.     if ((flags & fnAutoTypes) && (typeDesc->vt & 31) < autoTypeCount)
  370.       out << autoType[typeDesc->vt & 31];
  371.     else
  372.       out << dataType[typeDesc->vt & 31];
  373.   }
  374.   if (typeDesc->vt & VT_BYREF)  // should never happen
  375.     derefCount++;
  376.   while (derefCount--)
  377.     out << " far*";
  378.   if (flags & fnIterator)
  379.     out << ">&";
  380.   if (name) {
  381.     char* buf;
  382.     int len = lstrlen(name);
  383.     int nonascii = 0;
  384.     for (unsigned char far* pc = (unsigned char far*)name; *pc; pc++)
  385.       if (*pc >= 128)
  386.         nonascii++;
  387.     if (nonascii) {
  388.       unsigned char far* pn = (unsigned char far*)name;
  389.       buf = new char[nonascii + len + 1];
  390.       name = buf;
  391.       unsigned char c;
  392.       do {
  393.         c = *pn++;
  394.         if (c < 128) {
  395.           *buf++ = c;
  396.         } else {
  397.           char* px = foldName + (c-128)*2;
  398.           *buf++ = *px++;
  399.           if (*px)
  400.             *buf++ = *px;
  401.         }
  402.       } while (c);
  403.     }
  404.     out << ' ';
  405.     if (ClassName && (flags & fnClassName))
  406.       out << ClassName << "::";
  407.     if (flags & fnPrefixGet)
  408.       out << "Get";
  409.     if (flags & fnPrefixSet)
  410.       out << "Set";
  411.     out << name;
  412.     if (nonascii)
  413.       delete name;
  414.   }
  415.   if (arrayDesc)
  416.     for (int dim = 0; dim < arrayDesc->cDims; dim++)
  417.       out << '[' << arrayDesc->rgbounds[dim].cElements << ']';
  418.   return isDispObject;
  419. }
  420.  
  421. void FormatGuidLang(GUID far& guid, LCID locale, ostream& out)
  422. {
  423.   char guidBuf[38+1] = "{NULL}"; 
  424.   int notNull = 0;
  425.   int far* pg = (int far*)&guid;
  426.   for (int i = sizeof(GUID)/sizeof(int); i--; pg++)
  427.     notNull |= *pg;
  428.   if (notNull)
  429.     wsprintf(guidBuf, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
  430.              guid.Data1, guid.Data2, guid.Data3,
  431.              guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
  432.              guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
  433.   out << ' ' << guidBuf << '\\' << hex << LANGIDFROMLCID(locale) << dec;
  434. }
  435.  
  436. void FormatVers(int major, int minor, ostream& out)
  437. {
  438.   if (major)
  439.     out << ' ' << major << '.' << minor;
  440. }
  441.  
  442. void FormatDispId(DISPID id, int invKind, uint16 flags, ostream& out)
  443. {
  444.   out << "[id(";
  445.   if ((long)id > 9999 || (long)id < -9999)
  446.     out << "0x" << hex << id << dec;
  447.   else
  448.     out << id;
  449.   out << ')';
  450.   if (invKind)
  451.     out << ", " << invokeKind[invKind];
  452.   for (int i = 0; flags; i++, flags >>= 1) {
  453.     if (flags & 1)
  454.       out << ", " << memberFlagText[i];
  455.   }
  456.   out << ']';
  457. }
  458.  
  459. // assumed that caller of this function called GetDocumenation() on typeInfo
  460.  
  461. void FormatTypeInfo(TComRef<ITypeInfo>& typeInfo, int mode, ostream& out)
  462. {
  463. //typeInfo.GetDocumentation();
  464.   typeInfo.GetAttr();
  465.   int kind = typeInfo.Attr->typekind;
  466.   if (typeInfo.Attr->typekind != TKIND_ALIAS) {
  467.     out << "\n// TKIND_" << infoKind[kind] << ": " << typeInfo.Name;
  468.     FormatVers(typeInfo.Attr->wMajorVerNum,typeInfo.Attr->wMinorVerNum,out);
  469.     FormatGuidLang(typeInfo.Attr->guid, typeInfo.Attr->lcid, out);
  470.     out << ' ' << typeInfo.Doc << '\n';
  471.     int typeFlags = typeInfo.Attr->wTypeFlags;
  472.     if (typeFlags && !(mode & (tfDispHeader | tfDispImpl))) {
  473.       char* delim = "//  [";
  474.       for (int tflag = 0; tflag < implFlagCount; tflag++, typeFlags >>= 1)
  475.         if (typeFlags & 1) {  
  476.           out << delim << typeFlagText[tflag];
  477.           delim = ", ";
  478.       }
  479.       out << "]\n";
  480.     }
  481.     out << '\n';
  482.     if (!(mode & tfDispImpl))
  483.       out << infoCpp[kind];
  484.   }
  485.   switch (kind) {
  486.     case TKIND_MODULE: {
  487.       for (int varIndex = 0; varIndex < typeInfo.Attr->cVars; varIndex++) {
  488.         typeInfo.GetVarDesc(varIndex);
  489.         typeInfo.GetDocumentation(typeInfo.VarDesc->memid);
  490.         out << "    ";
  491.         FormatTypeName(typeInfo, typeInfo.VarDesc->elemdescVar.tdesc, typeInfo.Name, out);
  492.         out << "; // ";
  493.         int invKind = typeInfo.VarDesc->wVarFlags & VARFLAG_FREADONLY ? 3 : 7;
  494.         FormatDispId(typeInfo.VarDesc->memid, invKind,
  495.                      typeInfo.VarDesc->wVarFlags & ~VARFLAG_FREADONLY, out);
  496.         out << '\n';
  497.       }
  498.       for (int funcIndex = 0; funcIndex < typeInfo.Attr->cFuncs; funcIndex++) {
  499.         typeInfo.GetFuncDesc(funcIndex);
  500.         typeInfo.GetDocumentation(typeInfo.FuncDesc->memid);
  501.         int argCount = typeInfo.FuncDesc->cParams;
  502.         int argIndex;
  503.         TBSTR argName[35];      // max. arg count + 1, minimum 35 for MSWord6
  504.         unsigned int nameCount;
  505.         OLECALL(typeInfo->GetNames(typeInfo.FuncDesc->memid, argName[0],
  506.                                    sizeof(argName)/sizeof(TBSTR), &nameCount),"TKIND_INTERFACE GetNames");
  507.         if (typeInfo.Doc)
  508.           out << "    // " << typeInfo.Doc << '\n';
  509.         out << "    ";
  510.         for (argIndex = 0; argIndex <= argCount; argIndex++) {
  511.           ELEMDESC far* elemDesc = argIndex==0 ?
  512.                           &typeInfo.FuncDesc->elemdescFunc :
  513.                           typeInfo.FuncDesc->lprgelemdescParam + (argIndex-1);
  514.           FormatTypeName(typeInfo, elemDesc->tdesc, argIndex < nameCount ?
  515.                          (char far*)argName[argIndex] : (char far*)0, out);
  516.           if (argIndex == 0)
  517.             out << '(';
  518.           else if (argIndex != argCount)
  519.             out << ", ";
  520.         }
  521.         out << "); // ";
  522.         FormatDispId(typeInfo.FuncDesc->memid, 0,
  523.                      typeInfo.FuncDesc->wFuncFlags, out);
  524.         out << '\n';
  525.       }
  526.       out << "\n";
  527.       break;
  528.     }
  529.  
  530.     case TKIND_UNION:
  531.     case TKIND_RECORD: {
  532.       out << typeInfo.Name << " {\n"; /*}*/
  533.       for (int membIndex = 0; membIndex < typeInfo.Attr->cVars; membIndex++) {
  534.         typeInfo.GetVarDesc(membIndex);
  535.         typeInfo.GetDocumentation(typeInfo.VarDesc->memid);
  536.         out << "  ";
  537.         FormatTypeName(typeInfo, typeInfo.VarDesc->elemdescVar.tdesc, typeInfo.Name, out);
  538.         out << ";\n";
  539.       }
  540.       /*{*/ out << "};\n";
  541.       break;
  542.     }
  543.     case TKIND_ALIAS: {
  544.       out << infoCpp[kind] << ' ';
  545.       FormatTypeName(typeInfo, typeInfo.Attr->tdescAlias, typeInfo.Name, out);
  546.       out << ";\n";
  547.       break;
  548.     }
  549.     case TKIND_ENUM: {
  550.       out << typeInfo.Name << " {\n"; /*}*/
  551.       for (int enumIndex = 0; enumIndex < typeInfo.Attr->cVars; enumIndex++) {
  552.         typeInfo.GetVarDesc(enumIndex);
  553.         typeInfo.GetDocumentation(typeInfo.VarDesc->memid);
  554.         out << "  " << typeInfo.Name;
  555.         if (typeInfo.VarDesc->varkind == VAR_CONST
  556.          && typeInfo.VarDesc->lpvarValue->vt == VT_I2)
  557.           out << " = " << typeInfo.VarDesc->lpvarValue->iVal;
  558.         out << ",\n";
  559.       }
  560.       /*{*/ out << "};\n";
  561.       break;
  562.     }
  563.     case TKIND_INTERFACE: {
  564.       out << typeInfo.Name;
  565.       int baseCount = typeInfo.Attr->cImplTypes;
  566.       for (int baseIndex = 0; baseIndex < baseCount; baseIndex++) {
  567.         out << (baseIndex ==0 ? " : public " : ", public ");
  568.         HREFTYPE hrefType;
  569.         OLECALL(typeInfo->GetRefTypeOfImplType(baseIndex, &hrefType),"TKIND_INTERFACE GetRefTypeofImplType");
  570.         TComRef<ITypeInfo> refTypeInfo;
  571.         OLECALL(typeInfo->GetRefTypeInfo(hrefType, refTypeInfo),"TKIND_INTERFACE GetRefTypeInfo"); 
  572.         refTypeInfo.GetDocumentation();
  573.         out << refTypeInfo.Name;
  574.       }
  575.       out << " {\n  public:\n"; /*}*/
  576.       for (int funcIndex = 0; funcIndex < typeInfo.Attr->cFuncs; funcIndex++) {
  577.         typeInfo.GetFuncDesc(funcIndex);
  578.         typeInfo.GetDocumentation(typeInfo.FuncDesc->memid);
  579.         int argCount = typeInfo.FuncDesc->cParams;
  580.         int argIndex;
  581.         TBSTR argName[35];      // max. arg count + 1, minimum 35 for MSWord6
  582.         unsigned int nameCount;
  583.         OLECALL(typeInfo->GetNames(typeInfo.FuncDesc->memid, argName[0],
  584.                                    sizeof(argName)/sizeof(TBSTR), &nameCount),"TKIND_INTERFACE GetNames");
  585.         if (typeInfo.Doc)
  586.           out << "    // " << typeInfo.Doc << '\n';
  587.         if (typeInfo.FuncDesc->wFuncFlags & FUNCFLAG_FRESTRICTED)
  588.           out << "//  ";    // not accessible from dispatch controller
  589.         else
  590.           out << "    ";
  591.         for (argIndex = 0; argIndex <= argCount; argIndex++) {
  592.           ELEMDESC far* elemDesc = argIndex==0 ?
  593.                           &typeInfo.FuncDesc->elemdescFunc :
  594.                           typeInfo.FuncDesc->lprgelemdescParam + (argIndex-1);
  595.           FormatTypeName(typeInfo, elemDesc->tdesc, argIndex < nameCount ?
  596.                          (char far*)argName[argIndex] : (char far*)0, out);
  597.           if (argIndex == 0)
  598.             out << '(';
  599.           else if (argIndex != argCount)
  600.             out << ", ";
  601.         }
  602.         out << ") = 0; // ";
  603.         FormatDispId(typeInfo.FuncDesc->memid, 0,
  604.                      typeInfo.FuncDesc->wFuncFlags, out);
  605.         out << '\n';
  606.       }
  607.       /*{*/ out << "};\n";
  608.       break;
  609.     }
  610.     case TKIND_DISPATCH: {
  611.       TYPEDESC typeDescVoid;
  612.       typeDescVoid.vt = VT_VOID;
  613.       char semi;
  614.       if (mode & tfDispImpl) {
  615.         ClassName = new char[lstrlen(typeInfo.Name)+1];
  616.         lstrcpy(ClassName, typeInfo.Name);
  617.         semi = ' ';
  618.       } else {
  619.         semi = ';';
  620.         out << typeInfo.Name;
  621.         if (mode & tfDispHeader)
  622.           out << " : public TAutoProxy";
  623.         out << " {\n  public:\n"; /*}*/
  624.         if (mode & tfDispHeader)
  625.           out << "    " << typeInfo.Name << "() : TAutoProxy(0x"
  626.               << hex << LANGIDFROMLCID(typeInfo.Attr->lcid) << dec << ") {}\n";
  627.       }
  628.       for (int varIndex = 0; varIndex < typeInfo.Attr->cVars; varIndex++) {
  629.         int formatFlags = 0;
  630.         if (mode & tfDispHeader)
  631.           formatFlags = fnObjectByRef | fnPrefixGet | fnAutoTypes;
  632.         if (mode & tfDispImpl)
  633.           formatFlags = fnObjectByRef | fnPrefixGet | fnClassName | fnAutoTypes;
  634.         typeInfo.GetVarDesc(varIndex);
  635.         TYPEDESC& typeDesc = typeInfo.VarDesc->elemdescVar.tdesc;
  636.         int invKind = typeInfo.VarDesc->wVarFlags & VARFLAG_FREADONLY ? 3 : 7;
  637.         // should we insure that (type.Info.VarDesc->varkind==VAR_DISPATCH) ?
  638.         typeInfo.GetDocumentation(typeInfo.VarDesc->memid);
  639.         if (!(mode & tfDispImpl) && typeInfo.Doc)
  640.           out << "    // " << typeInfo.Doc << '\n';
  641.         bool isDispObject = IsDispObject(typeInfo, typeDesc);
  642.         bool boolProp = !(mode & tfBoolType) && typeDesc.vt == VT_BOOL;
  643.         bool boolRef  = !(mode & tfBoolType) && typeDesc.vt == VT_PTR
  644.                                     && typeDesc.lptdesc->vt == VT_BOOL;
  645.         do {
  646.           char* argName = 0;
  647.           if (!(mode & tfDispImpl))
  648.             out << "    ";
  649.           if (formatFlags == 0 || 
  650.              !((formatFlags & fnPrefixSet) || isDispObject)){
  651.             FormatTypeName(typeInfo, typeDesc, typeInfo.Name, out, formatFlags);
  652.             if (formatFlags & fnPrefixGet)
  653.               out << "()";
  654.             out << semi << "    ";
  655.           } else {
  656.             FormatTypeName(typeInfo,typeDescVoid,typeInfo.Name,out,formatFlags);
  657.             if (mode & tfDispImpl)
  658.               argName = isDispObject ? "obj" : "val";
  659.             out << '(';
  660.             FormatTypeName(typeInfo,typeDesc,argName,out,
  661.                            formatFlags & (fnObjectByRef | fnAutoTypes));
  662.             out << ')' << semi;
  663.           }
  664.           if (mode & tfDispImpl) {
  665.             out << "\n{\n  AUTONAMES0(\"" << typeInfo.Name
  666.                 << "\")\n  AUTOARGS0()\n  AUTOCALL_PROP_"; /*}*/
  667.             if (formatFlags & fnPrefixSet)
  668.               out << "SET";
  669.             else if (isDispObject)
  670.               out << "REF";
  671.             else if (boolProp)
  672.               out << "CONV(TAutoBool)";
  673.             else if (boolRef)
  674.               out << "CONV(TAutoBoolRef)";
  675.             else
  676.               out << "GET";
  677.             if (argName) {
  678.               if (boolProp)
  679.                 out << "(TAutoBool(" << argName << "))";
  680.               else if (boolRef)
  681.                 out << "(TAutoBoolRef(" << argName << "))";
  682.               else
  683.                 out << '(' << argName << ')';
  684.             }
  685.             /*{*/ out << "\n}\n";
  686.           } else {
  687.             out << " // ";
  688.             FormatDispId(typeInfo.VarDesc->memid, invKind,
  689.                          typeInfo.VarDesc->wVarFlags & ~VARFLAG_FREADONLY, out);
  690.           }
  691.           out << '\n';
  692.           if ((formatFlags & fnPrefixGet) && invKind == 7)
  693.             formatFlags ^= (fnPrefixGet | fnPrefixSet);
  694.           else
  695.             formatFlags = 0;
  696.         } while (formatFlags & fnPrefixSet);
  697.       }
  698.       for (int funcIndex = 0; funcIndex < typeInfo.Attr->cFuncs; funcIndex++) {
  699.         int formatFlags = 0;
  700.         if (mode & tfDispHeader)
  701.           formatFlags = fnObjectByRef | fnAutoTypes;
  702.         if (mode & tfDispImpl)
  703.           formatFlags = fnObjectByRef | fnAutoTypes | fnClassName;
  704.         typeInfo.GetFuncDesc(funcIndex);
  705.         if (typeInfo.FuncDesc->wFuncFlags & FUNCFLAG_FRESTRICTED)
  706.           continue;                 // not accessible from dispatch controller
  707.         typeInfo.GetDocumentation(typeInfo.FuncDesc->memid);
  708.         int argCount = typeInfo.FuncDesc->cParams;
  709.         TBSTR argNames[35];     // max. arg count + 1, minimum 35 for MSWord6
  710.         unsigned int nameCount;
  711.         OLECALL(typeInfo->GetNames(typeInfo.FuncDesc->memid, argNames[0],
  712.                 sizeof(argNames)/sizeof(TBSTR), &nameCount),"TKIND_DISPATCH GetNames");
  713.         if (!(mode & tfDispImpl)) {
  714.           if (typeInfo.Doc)
  715.             out << "    // " << typeInfo.Doc << '\n';
  716.           out << "    ";
  717.         }
  718.         int argIndex  = -1;   // index into ELEMDESC[], -1 for return type
  719.         int nameIndex = 0;    // index into name table, no propset param name
  720.         int outParam  = 0;    // index of type/name being output
  721.         bool voidRet = false;
  722.         bool boolRet = false;
  723.         bool boolRetRef = false;
  724.         bool isObject = false;
  725.         bool isIterator = (typeInfo.FuncDesc->memid == DISPID_NEWENUM);
  726.         for ( ; argIndex<argCount; argIndex++, outParam++) {
  727.           TYPEDESC far* typeDesc = &typeInfo.FuncDesc->elemdescFunc.tdesc;
  728.           if (argIndex >= 0)  {        // processing an argument
  729.             typeDesc = &typeInfo.FuncDesc->lprgelemdescParam[argIndex].tdesc;
  730.           } else if (outParam == 0 && (mode & (tfDispHeader | tfDispImpl)) &&
  731.                      (IsDispObject(typeInfo, *typeDesc) || isIterator)) {
  732.             typeDesc = &typeDescVoid;
  733.             argIndex--;           // reprocess return as first arg
  734.             isObject = true;
  735.           } else if (typeDesc->vt == VT_VOID || typeDesc->vt == VT_EMPTY) {
  736.             voidRet = true;
  737.           } else if (!(mode & tfBoolType) && typeDesc->vt == VT_BOOL) {
  738.             boolRet = true;
  739.           } else if (!(mode & tfBoolType) && typeDesc->vt == VT_PTR
  740.                                  && typeDesc->lptdesc->vt == VT_BOOL) {
  741.             boolRetRef = true;
  742.           }
  743.           char far* name = 0;
  744.           char argName[10];
  745.           if (isObject && argIndex == -1) {
  746.             if (mode & tfDispImpl)
  747.               name = "obj";
  748.             if (isIterator)
  749.               formatFlags |= fnIterator;
  750.           } else if (argIndex==0 && typeInfo.FuncDesc->invkind>=INVOKE_PROPERTYPUT) {
  751.             if (mode & tfDispImpl)
  752.               name = "val";
  753.           } else if (nameIndex >= nameCount) {
  754.             if (mode & tfDispImpl)
  755.               wsprintf(name = argName, "arg%d", argIndex+1);
  756.           } else
  757.             name = argNames[nameIndex++];
  758.           if (outParam == 0 && (mode & (tfDispHeader | tfDispImpl))) {
  759.             if (typeInfo.FuncDesc->invkind>=INVOKE_PROPERTYPUT)
  760.               formatFlags |= fnPrefixSet;  // must differentiate from get
  761.             else if (typeInfo.FuncDesc->invkind==INVOKE_PROPERTYGET) {
  762.               if (isIterator)
  763.                 name = "Enumerate";
  764.               else
  765.                 formatFlags |= fnPrefixGet;  // get&set may have same name
  766.             }
  767.           }
  768.           FormatTypeName(typeInfo, *typeDesc, name, out, formatFlags);
  769.           formatFlags &= ~fnIterator;
  770.           if (outParam == 0) {
  771.             out << '(';
  772.             formatFlags &= ~(fnClassName | fnPrefixGet | fnPrefixSet);
  773.           }
  774.           else if (argIndex != argCount-1)
  775.             out << ", ";
  776.         }
  777.         out << ')' << semi;
  778.         if (mode & tfDispImpl) {
  779.           out << "\n{\n  AUTONAMES0("; /*}*/
  780.           if (isIterator)
  781.             out << "DISPID_NEWENUM";
  782.           else
  783.             out << '"' << typeInfo.Name << '"';
  784.           if (typeInfo.FuncDesc->invkind>=INVOKE_PROPERTYPUT)
  785.             argCount--;
  786.           out << ")\n  AUTOARGS" << argCount << '(';
  787.           argIndex = 1;                 // 1-based for following loop
  788.           for ( ; argIndex <= argCount; argIndex++) { // 1-based
  789.             if (argIndex != 1)
  790.               out << ", ";
  791.             TYPEDESC far& typeDesc =
  792.                        typeInfo.FuncDesc->lprgelemdescParam[argIndex-1].tdesc;
  793.             bool boolArg = !(mode & tfBoolType) && typeDesc.vt == VT_BOOL;
  794.             bool boolRef = !(mode & tfBoolType) && typeDesc.vt == VT_PTR
  795.                                        && typeDesc.lptdesc->vt == VT_BOOL;
  796.             if (boolArg)
  797.               out << "TAutoBool(";
  798.             else if (boolRef)
  799.               out << "TAutoBoolRef(";
  800.             if (argIndex < nameCount)
  801.               out << argNames[argIndex];
  802.             else
  803.               out << "arg" << argIndex;
  804.             if (boolArg || boolRef)
  805.               out << ")";
  806.           }
  807.           out << ")\n  AUTOCALL_";
  808.           if (typeInfo.FuncDesc->invkind==INVOKE_PROPERTYGET) {
  809.             if (isObject)
  810.               out << "PROP_REF(obj)";
  811.             else
  812.               out << "PROP_GET";
  813.           } else if (typeInfo.FuncDesc->invkind==INVOKE_PROPERTYPUT) {
  814.             out << "PROP_SET(val)";
  815.           } else {
  816.             out << "METHOD_";
  817.             if (isObject)
  818.               out << "REF(obj)";
  819.             else if (voidRet)
  820.               out << "VOID";
  821.             else if (boolRet)
  822.               out << "CONV(TAutoBool)";
  823.             else if (boolRetRef)
  824.               out << "CONV(TAutoBoolRef)";
  825.             else
  826.               out << "RET";
  827.           }
  828.           /*{*/ out << "\n}\n";  //(for editor brace check)
  829.         } else {
  830.           out << " // ";
  831.           FormatDispId(typeInfo.FuncDesc->memid,
  832.                        typeInfo.FuncDesc->invkind,
  833.                        typeInfo.FuncDesc->wFuncFlags, out);
  834.         }
  835.         out << '\n';
  836.       }
  837.       if (!(mode & tfDispImpl))
  838.         /*{*/ out << "};\n";
  839.       break;
  840.     }
  841.     case TKIND_COCLASS: {
  842.       for (unsigned int cindex=0; cindex<typeInfo.Attr->cImplTypes; cindex++) {
  843.         HREFTYPE hrefType;
  844.         OLECALL(typeInfo->GetRefTypeOfImplType(cindex, &hrefType), "GetRefTypeofImplType");
  845.         int typeFlags;
  846.         OLECALL(typeInfo->GetImplTypeFlags(cindex, &typeFlags), "GetImplTypeFlags");
  847.         TComRef<ITypeInfo> refTypeInfo;
  848.         OLECALL(typeInfo->GetRefTypeInfo(hrefType, refTypeInfo),"TKIND_COCLASS GetRefTypeInfo"); 
  849.         refTypeInfo.GetDocumentation();
  850.         out << "\n//  " << refTypeInfo.Name;
  851.         char* delim = "  [";
  852.         if (typeFlags) {
  853.           for (int iflag = 0; iflag < implFlagCount; iflag++, typeFlags >>= 1)
  854.             if (typeFlags & 1) {
  855.               out << delim << implFlagText[iflag];
  856.               delim = ", ";
  857.             }
  858.           out << ']';
  859.         }
  860.       }
  861.       out << "\n\n";
  862.       break;
  863.     }
  864.   }
  865.   delete ClassName;
  866.   ClassName = 0;
  867. }
  868.  
  869. //____________________________________________________________________________
  870. //
  871. // Local class to hold selection and iterator information for type library
  872. //____________________________________________________________________________
  873.  
  874. class TLogTypeInfo {
  875.   public:
  876.     typedef bool (*TCall)(TLogTypeInfo&);
  877.  
  878.     TLogTypeInfo(HWND hWnd);
  879.    ~TLogTypeInfo()        {delete SelectList;}
  880.     bool  Report();
  881.     HWND  GetWindow()      {return Window;}
  882.     int   GetSelectCount() {return SelectCount;}
  883.     int*  GetSelectList()  {return SelectList;}
  884.     void  SetSelectList(int count, int* list);
  885.     int   GetRequestCount() {return ReqCount;}
  886.     void  SetRequestList(int count, int* list, char** names);
  887.     void  SetCallback(TLogTypeInfo::TCall proc) {Proc = proc;}
  888.     bool  MatchRequest();  // return true to continue, false if all done
  889.     char* ExtractRequest();// return unmatched type name, 0 if list empty
  890.     void ClearLists();
  891.     int   Index;        // returned selection index, within user select types
  892.     int   TypeIndex;    // returned typeinfo index, within entire type library
  893.     char* TypeKind;     // returned typeinfo kind text
  894.     char far* TypeName; // returned typeinfo name text
  895.   private:
  896.     char** ReqNames;    // temp requested type names
  897.     int    ReqCount;    // temp requested name count
  898.     int*   SelectList;  // list of selected typeinfos in type library
  899.     int    SelectCount; // number of selected items
  900.     HWND   Window;      // window to receive data
  901.     TCall  Proc;        // callback function to display data
  902. };
  903. inline TLogTypeInfo::TLogTypeInfo(HWND hWnd)
  904.                     : Window(hWnd), SelectList(0), Proc(0)
  905. {
  906.   ClearLists();  // SelectList must be 0 to prevent delete of garbage
  907. }
  908. inline void TLogTypeInfo::ClearLists()
  909. {
  910.   if(!ReqNames)
  911.     delete SelectList;
  912.   ReqNames = 0;
  913.   SelectList = 0;
  914.   SelectCount = 0;
  915.   ReqCount = 0;
  916. }
  917. inline void TLogTypeInfo::SetSelectList(int count, int* list)
  918. {
  919.   ClearLists();
  920.   SelectCount = count;
  921.   SelectList = list;
  922. }
  923. inline void TLogTypeInfo::SetRequestList(int count, int* list, char** names)
  924. {
  925.   ClearLists();
  926.   ReqCount = count;
  927.   ReqNames = names;
  928.   SelectList = list;
  929. }
  930. inline bool TLogTypeInfo::Report()
  931. {
  932.   return Proc ? Proc(*this) : MatchRequest();
  933. }
  934. bool TLogTypeInfo::MatchRequest()
  935. {
  936.   if (!ReqCount)
  937.     return false;
  938.   for (int i = 0; i < ReqCount; i++) {
  939.     if (stricmp(TypeName, ReqNames[i]) == 0) {
  940.       SelectList[SelectCount++] = TypeIndex;
  941.       if (--ReqCount != i)
  942.         memcpy(&ReqNames[i],&ReqNames[i+1],(ReqCount-i)*sizeof(int));
  943.       return ReqCount != 0;
  944.     }
  945.   }  
  946.   return true;  // keep going
  947. }
  948. char* TLogTypeInfo::ExtractRequest()
  949. {
  950.   if (!ReqCount)
  951.     return 0;
  952.   char* name = ReqNames[0];
  953.   if (--ReqCount)
  954.     memcpy(&ReqNames[0], &ReqNames[1], ReqCount*sizeof(int));
  955.   return name;
  956. }
  957.  
  958. //____________________________________________________________________________
  959. //
  960. // ITypeLib iterator, emits file header info, calls ITypeInfo iterator
  961. //____________________________________________________________________________
  962.  
  963. void ReadTypeLib(char* libName, char* incName, int mode, ostream& out,
  964.                  TLogTypeInfo& log)
  965. {
  966.   try {       // catch OLE errors, no OLE calls are made outside of this block
  967.     char nameBuf[50];      // large enough for basename.tlb, overflow not fatal
  968.     TOleAllocator oleMem(0);
  969.     TComRef<ITypeLib> typeLib;
  970.     TComRef<ITypeInfo> coclassInfo;
  971.     OLECALL(::LoadTypeLib(libName, typeLib),"LoadTypeLib");
  972.     typeLib.GetAttr();
  973.     if (mode & tfLibHeader) {
  974.       typeLib.GetDocumentation();
  975.       if (::GetFileTitle(libName, nameBuf, sizeof(nameBuf)) <= 0)
  976.         out << "// Type Library: " << nameBuf;
  977.       out << "  " << typeLib.Doc << '\n';
  978.       out << "// " << typeLib.Name;
  979.       FormatVers(typeLib.Attr->wMajorVerNum, typeLib.Attr->wMinorVerNum, out);
  980.       FormatGuidLang(typeLib.Attr->guid, typeLib.Attr->lcid, out);
  981.       out << "\n\n";
  982.     }
  983.     int infoCount = typeLib->GetTypeInfoCount();
  984.     if (incName)
  985.       out << "#include " << incName << "\n";
  986.     if (mode & tfDispHeader) {
  987.       for (int infoIndex = 0; infoIndex < infoCount; infoIndex++) {
  988.         TYPEKIND infoType;
  989.         typeLib->GetTypeInfoType(infoIndex, &infoType);
  990.         if (infoType == TKIND_DISPATCH) {
  991.           TComRef<ITypeInfo> typeInfo;
  992.           OLECALL(typeLib->GetTypeInfo(infoIndex, typeInfo),"typeLib->GetTypeInfo");
  993.           typeInfo.GetDocumentation();
  994.           out << "\nclass " << typeInfo.Name << ';';
  995.         }
  996.         if (infoType == TKIND_COCLASS) {
  997.           OLECALL(typeLib->GetTypeInfo(infoIndex, coclassInfo),"typeLib->GetTypeInfo");
  998.         }
  999.       }
  1000.       out << "\n";
  1001.     }
  1002.     // need to scan coclass typeinfo for [source] classes
  1003.     // and eliminate them from HXX/CXX code generation
  1004.     // eventually should emit server code tables
  1005.     //
  1006.     int  infoIndex = 0;
  1007.     int  selIndex  = 0;
  1008.     int  selCount  = log.GetSelectCount();
  1009.     int* selList   = log.GetSelectList();
  1010.     for (; infoIndex < infoCount; infoIndex++) {
  1011.       if (selList && !(mode & tfScanOnly)) {     // partial selection
  1012.         if (!selCount || infoIndex != selList[selIndex])
  1013.           continue;
  1014.         selCount--;
  1015.       }
  1016.       TYPEKIND infoType;
  1017.       typeLib->GetTypeInfoType(infoIndex, &infoType);
  1018.       if (((1<<infoType) & mode) == 0)
  1019.         continue;
  1020.       TComRef<ITypeInfo> typeInfo;
  1021.       OLECALL(typeLib->GetTypeInfo(infoIndex, typeInfo),"GetTypeInfo");
  1022.       typeInfo.GetDocumentation();
  1023.       typeInfo.GetAttr();
  1024.       log.TypeIndex = infoIndex;
  1025.       log.Index     = selIndex++;
  1026.       log.TypeName  = typeInfo.Name;
  1027.       log.TypeKind  = infoKind[infoType];
  1028.       if (!log.Report())
  1029.         break;
  1030.       if (mode & tfScanOnly)
  1031.         continue;
  1032.       FormatTypeInfo(typeInfo, mode, out);
  1033.     }
  1034.   }
  1035.   catch(TXOle& x) {  // convert OLE exception into local exception
  1036.     Error(libName, x.why().c_str());
  1037.   }
  1038. }
  1039.  
  1040. //____________________________________________________________________________
  1041. //
  1042. // Command line and UI processing, creates streams
  1043. //____________________________________________________________________________
  1044.  
  1045. #include <stdio.h>
  1046. #include <conio.h>
  1047. #include <string.h>
  1048. #include <fstream.h>
  1049. #include <strstrea.h>
  1050.  
  1051. // Command line token extraction class
  1052.  
  1053. class TCmdLine {
  1054.   public:
  1055.     enum Kind {Null, Name, Option, Value};
  1056.     TCmdLine(char far* cmdLine);
  1057.    ~TCmdLine();
  1058.     Kind  NextToken();
  1059.     int   TokenLen;
  1060.     char* Token;
  1061.     Kind  Type;
  1062.   private:
  1063.     char* Buf;
  1064.     Kind  NextType;
  1065. };
  1066.  
  1067. TCmdLine::TCmdLine(char far* cmdLine) : NextType(Name)
  1068. {
  1069.   Token = Buf = new char[lstrlen(cmdLine)+1];
  1070.   TokenLen = -1;         // cancels increment on next assignment
  1071.   lstrcpy(Buf, cmdLine);
  1072. }
  1073.  
  1074. TCmdLine::~TCmdLine()
  1075. {
  1076.   delete Buf;
  1077. }
  1078.  
  1079. TCmdLine::Kind TCmdLine::NextToken()
  1080. {
  1081.   Token += (TokenLen + 1);
  1082.   if (NextType == Name) {           // name or leading spaces
  1083.     Token += strspn(Token, " \t");  // skip leading white space
  1084.     switch (*Token++) {
  1085.       case 0:
  1086.         return Type = NextType = Null;
  1087.       case '=':
  1088.         Type = Value;
  1089.         break;
  1090.       case '-':
  1091.       case '/':
  1092.         Type = Option;
  1093.         break;
  1094.       default:
  1095.         Type = Name;
  1096.         Token--;
  1097.     }
  1098.   } else {   // must have stopped on a delimiter
  1099.     Type = NextType;
  1100.     if (Type == Null)
  1101.       return Type;
  1102.   }
  1103.   TokenLen = strcspn(Token, "=/- \t");
  1104.   char* nextToken = Token + TokenLen;
  1105.   switch (*nextToken) {
  1106.     case 0:
  1107.       NextType = Null;
  1108.       break;
  1109.     case '=':
  1110.       NextType = Value;
  1111.       break;
  1112.     case '-':
  1113.     case '/':
  1114.       NextType = Option;
  1115.       break;
  1116.     default:
  1117.       NextType = Name;
  1118.   }
  1119.   *nextToken = 0;  // null-terminate current token
  1120.   return Type;
  1121. }
  1122.  
  1123. // File name processing
  1124.  
  1125. enum  fileKind    { fkDispHdr, fkDispSrc, fkFullCpp,      fkCount };
  1126. char* optText[] = { "Header",  "Code",    "Definitions" };
  1127. char* fileExt[] = { "HXX",     "CXX",     "HPP" };
  1128. int   libMode[] = { tfEnum|tfAlias|tfDispatch|tfLibHeader|tfDispHeader,
  1129.                     tfDispatch|tfDispImpl, tfAllKinds|tfLibHeader };
  1130. char* stdFile[] = { ".HXX",    ".CXX",    0 };     // OC controller proxy code
  1131. char* cppFile[] = { 0,         0,         ".HPP" };// standard C++ defs       
  1132.  
  1133.  
  1134. int GenerateFiles(char* libName, char** outFiles, TLogTypeInfo& log)
  1135. {
  1136.   char outName[_MAX_PATH];
  1137.   char outDrive[_MAX_DRIVE];
  1138.   char outDir  [_MAX_DIR];
  1139.   char outFName[_MAX_FNAME];
  1140.   char outExt  [_MAX_EXT];
  1141.   char libDrive[_MAX_DRIVE];
  1142.   char libDir  [_MAX_DIR];
  1143.   char libFName[_MAX_FNAME];
  1144.   char libExt  [_MAX_EXT];
  1145.   char incFile [_MAX_FNAME+_MAX_EXT+2];
  1146.   char* incName;
  1147.  
  1148.   _splitpath(libName, libDrive, libDir, libFName, libExt);
  1149.   int outCount = 0;               // count of files actually output
  1150.   for (int fileIndex = 0; fileIndex < fkCount; fileIndex++) {
  1151.     if (!outFiles[fileIndex])
  1152.       continue;
  1153.     _splitpath(outFiles[fileIndex], outDrive, outDir, outFName, outExt);
  1154.     _makepath (outName,
  1155.                outDrive[0] ? outDrive : libDrive,
  1156.                outDir[0]   ? outDir   : libDir,
  1157.                outFName[0] ? outFName : libFName,
  1158.                outExt[0]   ? outExt   : fileExt[fileIndex]);
  1159.     ofstream out;
  1160.     out.open(outName);
  1161.     ErrorIf(out.bad(), outName, IDS_OUTFILEERR);
  1162.     switch(fileIndex) {
  1163.       case fkDispHdr:
  1164.         incName = "<ocf/automacr.h>";
  1165.         incFile[0] = '"';
  1166.         _splitpath(outName, 0, 0, incFile+1, outExt);
  1167.         strcat(incFile, outExt);
  1168.         strcat(incFile, "\"");
  1169.         break;
  1170.       case fkDispSrc:
  1171.         incName = incFile;
  1172.         break;
  1173.       case fkFullCpp:
  1174.         incName = 0;
  1175.         break;
  1176.     }
  1177.     if (log.GetWindow()) {
  1178.       ::SetDlgItemText(log.GetWindow(), IDC_STATUS,  (char far*)outName);
  1179.       int* selectList = log.GetSelectList();
  1180.       int  selectCount= log.GetSelectCount();
  1181.       if (!selectList) {
  1182.         ::SendDlgItemMessage(log.GetWindow(), IDC_INFOLIST, LB_SETSEL, 1, -1);
  1183.       } else if (outCount != 0) {
  1184.         for (int i = 0; i < selectCount; i++)
  1185.           ::SendDlgItemMessage(log.GetWindow(), IDC_INFOLIST, LB_SETSEL, 1,
  1186.                                (LPARAM)(unsigned)selectList[i]);
  1187.       }
  1188.     }
  1189.     ReadTypeLib(libName, incName, libMode[fileIndex], out, log);
  1190.     outCount++;
  1191.   }
  1192.   return 0;
  1193. }
  1194.  
  1195. #define WM_USERSTAT (WM_USER + 100)
  1196.  
  1197. bool CALLBACK __export
  1198. HelpProc(HWND hDlg, UINT msg, WPARAM /*wParam*/, LPARAM /*lParam*/)
  1199. {
  1200.   if (msg != WM_COMMAND)
  1201.     return (msg == WM_INITDIALOG);
  1202.   ::EndDialog(hDlg, TRUE);
  1203.   return true;
  1204. }
  1205.  
  1206. bool CALLBACK __export
  1207. SelectProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM /*lParam*/)
  1208. {
  1209.   if (msg == WM_INITDIALOG) {
  1210.     int tabs = IDC_INFOLIST_TAB;
  1211.     ::SendDlgItemMessage(hDlg, IDC_INFOLIST, LB_SETTABSTOPS, 1, (LPARAM)&tabs);
  1212.     ::SendDlgItemMessage(hDlg, IDC_AUTOCODE, BM_SETCHECK, 1, 0);
  1213.     return 1;
  1214.   } else if (msg == WM_COMMAND) {
  1215.     switch (wParam) {
  1216.       case IDOK:
  1217.       case IDCANCEL:    
  1218.         ::PostMessage(hDlg, WM_USERSTAT, wParam, 0);
  1219.         return 1;
  1220.       case IDC_SELECTALL:
  1221.       case IDC_SELECTNONE:
  1222.         ::SendDlgItemMessage(hDlg, IDC_INFOLIST, LB_SETSEL,
  1223.                              wParam==IDC_SELECTALL, -1);
  1224.         return 1;
  1225.     }
  1226.   } else if (msg == WM_CLOSE) {
  1227.     ::PostMessage(hDlg, WM_USERSTAT, IDABORT, 0);
  1228.   }
  1229.   return 0;
  1230. }
  1231.  
  1232. bool FillListBox(TLogTypeInfo& info)
  1233. {
  1234.   char buf[100];
  1235.   wsprintf(buf, "%s\t%s", (char far*)info.TypeKind, info.TypeName);
  1236.   ::SendDlgItemMessage(info.GetWindow(), IDC_INFOLIST, LB_ADDSTRING,
  1237.                        0, (LPARAM)(char far*)buf);
  1238.   MSG msg;
  1239.   while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  1240.     ::IsDialogMessage(info.GetWindow(), &msg);
  1241.   return true;
  1242. }
  1243.  
  1244. bool ShowProgress(TLogTypeInfo& info)
  1245. {
  1246.   HWND hWnd = info.GetWindow();
  1247.   ::SendDlgItemMessage(hWnd, IDC_INFOLIST, LB_SETTOPINDEX, info.Index, 0);
  1248.   ::SendDlgItemMessage(hWnd, IDC_INFOLIST, LB_SETSEL,
  1249.                        0, (LPARAM)(unsigned)info.Index);
  1250.   MSG msg;
  1251.   while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  1252.     ::IsDialogMessage(hWnd, &msg);
  1253.   return true;
  1254. }
  1255.  
  1256. bool SilentYield(TLogTypeInfo& /*info*/)
  1257. {
  1258.   MSG msg;
  1259.   while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  1260.     ;
  1261. //  if (msg.message == WM_QUIT)
  1262. //    return false;
  1263.   return true;
  1264. }
  1265.  
  1266. const int MaxReqTypes = 20;  // maximum number of type names on command line
  1267.  
  1268. int PASCAL
  1269. WinMain(HINSTANCE hInst, HINSTANCE/*hPrev*/, char far* cmdLine, int/*show*/)
  1270. {
  1271.   TCmdLine cmd(cmdLine);
  1272.   char* outFiles[fkCount];
  1273.   int stat = 0;
  1274.  
  1275.   try {
  1276.     if (cmd.NextToken() == TCmdLine::Null) {
  1277.       //
  1278.       // If command line empty, create dialog and operate in interactive mode
  1279.       //
  1280.       char libName[_MAX_PATH];
  1281.       libName[0] = 0;
  1282.       HWND hWnd = ::CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_SELECT), 0,
  1283.                                       (DLGPROC)SelectProc, 0);
  1284.       OPENFILENAME ofn = {sizeof(OPENFILENAME), hWnd, hInst,
  1285.                           "TypeLib\0*.TLB;*.OLB\0",0,0,0,
  1286.                           libName, sizeof(libName), 0, 0,
  1287.                           0, "AUTOGEN - TypeLib to C++ Conversion",
  1288.                           OFN_HIDEREADONLY | OFN_FILEMUSTEXIST,
  1289.                           0,0,0,0,0,0 };
  1290.       while(::GetOpenFileName(&ofn)) {
  1291.         ::SetDlgItemText(hWnd, IDC_LIBFILE, (char far*)libName);
  1292.         ::ShowWindow(hWnd, SW_SHOW);
  1293.         TLogTypeInfo fillInfo(hWnd);
  1294.         fillInfo.SetCallback(FillListBox);
  1295.         strstream temp;
  1296.         ReadTypeLib(libName, 0, tfScanOnly | tfAllKinds, temp, fillInfo);
  1297.         MSG msg;
  1298.         int stat = 0;
  1299.         while ( !stat && ::GetMessage(&msg, 0, 0, 0)) {
  1300.           if (msg.message == WM_USERSTAT)
  1301.             stat = msg.wParam;
  1302.           else 
  1303.             ::IsDialogMessage(hWnd, &msg);
  1304.         }
  1305.         if (stat == IDABORT)
  1306.           break;
  1307.         if (stat == IDOK) {
  1308.           ::ShowWindow(::GetDlgItem(hWnd, IDC_SELECTALL),  SW_HIDE);
  1309.           ::ShowWindow(::GetDlgItem(hWnd, IDC_SELECTNONE), SW_HIDE);
  1310.           ::ShowWindow(::GetDlgItem(hWnd, IDC_STATUS),     SW_SHOW);
  1311.           int cppdefState = (int)::SendDlgItemMessage(hWnd, IDC_CPPDEF,
  1312.                                                      BM_GETCHECK, 0, 0);
  1313.           memcpy(outFiles, cppdefState ? cppFile : stdFile, sizeof(outFiles));
  1314.           fillInfo.SetCallback(ShowProgress);
  1315.           int* selectList = 0;
  1316.           int selectCount = (int)::SendDlgItemMessage(hWnd, IDC_INFOLIST,
  1317.                                                      LB_GETSELCOUNT, 0, 0);
  1318.           if (selectCount) {
  1319.             selectList = new int[selectCount];
  1320.             ::SendDlgItemMessage(hWnd, IDC_INFOLIST, LB_GETSELITEMS,
  1321.                                  selectCount, (LPARAM)(int far*)selectList);
  1322.           }
  1323.           fillInfo.SetSelectList(selectCount, selectList);
  1324.           stat = GenerateFiles(libName, outFiles, fillInfo);
  1325.           while (!::GetFocus() ||
  1326.                   ::GetWindowTask(::GetFocus())!=::GetCurrentTask())
  1327.             if (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  1328.               ::IsDialogMessage(hWnd, &msg);
  1329.           ::ShowWindow(::GetDlgItem(hWnd, IDC_SELECTALL),  SW_SHOW);
  1330.           ::ShowWindow(::GetDlgItem(hWnd, IDC_SELECTNONE), SW_SHOW);
  1331.           ::ShowWindow(::GetDlgItem(hWnd, IDC_STATUS),     SW_HIDE);
  1332.         }
  1333.         ::ShowWindow(hWnd, SW_HIDE);
  1334.         ::SendDlgItemMessage(hWnd, IDC_INFOLIST, LB_RESETCONTENT, 0, 0);
  1335.       }
  1336.       ::DestroyWindow(hWnd);
  1337.       return stat;
  1338.     }
  1339.     if (cmd.Type == TCmdLine::Name) {
  1340.       //
  1341.       //  If type library supplied on command line, operate in non-interactive
  1342.       //
  1343.       char* libName = cmd.Token;   // first argument should be a typelib name
  1344.       int optFound = 0;
  1345.       memset(outFiles, 0, sizeof(outFiles));
  1346.       char* reqTypes[MaxReqTypes];
  1347.       int   reqInfos[MaxReqTypes];
  1348.       int   reqCount = 0;
  1349.       int   optIndex = -1;
  1350.       while (cmd.NextToken() != TCmdLine::Null) {
  1351.         if (cmd.Type == TCmdLine::Option) {
  1352.           for (optIndex = 0; optIndex < fkCount; optIndex++) {
  1353.             if (strnicmp(cmd.Token, optText[optIndex], cmd.TokenLen) == 0)
  1354.               break;
  1355.           }
  1356.           ErrorIf(optIndex == fkCount, IDS_UNKNOWNOPT, cmd.Token);
  1357.           outFiles[optIndex] = "";
  1358.           optFound++;
  1359.         } else if (cmd.Type == TCmdLine::Value) {
  1360.           ErrorIf(optIndex == -1, IDS_MISSINGOPT, cmd.Token);
  1361.           outFiles[optIndex] = cmd.Token;
  1362.           optIndex = -1;
  1363.         } else {  // TCmdLine::Name  should be a class name to select
  1364.           ErrorIf(reqCount == MaxReqTypes, cmd.Token, IDS_TOOMANYTYPES);
  1365.           reqTypes[reqCount++] = cmd.Token;
  1366.         }
  1367.       }
  1368.       if (optFound == 0)  // if no file options, default to controller files
  1369.         memcpy(outFiles, stdFile, sizeof(outFiles));
  1370.       TLogTypeInfo silentInfo(0);
  1371.       if (reqCount) {
  1372.         silentInfo.SetRequestList(reqCount, reqInfos, reqTypes);
  1373.         strstream temp;
  1374.         ReadTypeLib(libName, 0, tfScanOnly | tfAllKinds, temp, silentInfo);
  1375.         char* badName = silentInfo.ExtractRequest();
  1376.         ErrorIf(badName!=0, IDS_BADTYPENAME, badName);
  1377.       }
  1378.       silentInfo.SetCallback(SilentYield);
  1379.       stat = GenerateFiles(libName, outFiles, silentInfo);
  1380.     } else {
  1381.       //
  1382.       //  If first command line arg is an option flag, show help dialog
  1383.       //
  1384.       stat = ::DialogBox(hInst, MAKEINTRESOURCE(IDD_HELP), 0,(DLGPROC)HelpProc);
  1385.     }
  1386.     return stat;
  1387.   }
  1388.   catch (TLocalError& xcpt) {
  1389.     char msgbuf[80];
  1390.     const char ** pmsg;
  1391.     if ( *(pmsg = &xcpt.Message) <= (const char*)IDS_MAX ||
  1392.          *(pmsg = &xcpt.Title)   <= (const char*)IDS_MAX) {
  1393.       ::LoadString(hInst, *(unsigned*)pmsg, msgbuf, sizeof(msgbuf));
  1394.       *pmsg = msgbuf;
  1395.     }
  1396.     ::MessageBox(0, xcpt.Message, xcpt.Title, MB_OK);
  1397.     return 1;
  1398.   }
  1399.   catch (xmsg& xcpt) {    // should not occur, but check anyway while catching
  1400.     ::MessageBox(0, xcpt.why().c_str(), "Exception", MB_OK);
  1401.     return 2;
  1402.   }
  1403. }
  1404.