#include "mktyplib.h" // .H file output for MKTYPLIB #include #ifndef WIN32 #include // required for dispatch.h #include "dispatch.h" #endif //WIN32 #include "errors.h" #include "fileinfo.h" #include "intlstr.h" // for szHead* definitions // external data extern TYPLIB typlib; extern FILE *hHFile; extern SYSKIND SysKind; extern int iAlignMax; extern int iAlignDef; extern BOOL fSpecifiedInterCC; // external functions extern INT FAR FCmpCaseIns(LPSTR str1, LPSTR str2); // private data static CHAR *szHeadOlePrefix0 = "#undef INTERFACE\n" "#define INTERFACE "; static CHAR *szHeadOlePrefix1 = "DECLARE_INTERFACE"; static CHAR *szHeadOlePrefix2 = ")\n{\n"; static CHAR *szHeadOlePrefix3 = "\n /* "; static CHAR *szHeadOlePrefix4 = " methods */\n"; static CHAR *szHeadOlePrefix5 = " properties:\n"; static CHAR *szHeadOlePrefix6 = " methods:\n"; static CHAR *szHeadOlePrefix7 = "#ifndef NO_BASEINTERFACE_FUNCS\n"; static CHAR *szHeadOleFuncPrefix1 = " "; // leading spaces static CHAR *szHeadOleFuncPrefix2 = "STDMETHOD"; static CHAR *szHeadOleFuncPrefix3 = ", "; // after return type static CHAR *szHeadOleArgPrefix1 = ")(THIS"; static CHAR *szHeadOleArgPrefix2 = "_ "; // only if args static CHAR *szHeadOleArgSuffix = ") PURE;\n"; static CHAR *szHeadOleSuffix1 = " */\n"; static CHAR *szHeadOleSuffix2 = "};\n"; static CHAR *szHeadOleSuffix3 = " */\n"; static CHAR *szHeadOleSuffix7 = "#endif\n"; //Hack for profiling //#define PROFILE #ifdef PROFILE static unsigned long cFuncsTotal = 0; static unsigned long cArgsTotal = 0; static unsigned long cVarsTotal = 0; #endif //PROFILE // stuff dealing with non-default interface calling conventions static CHAR *szUndefCallType = "#undef STDMETHODCALLTYPE\n"; static CHAR *szResetCallType = "#if defined(WIN32)\n" "#define STDMETHODCALLTYPE STDMETHODSTDCALL\n" "#else\n" "#define STDMETHODCALLTYPE STDMETHODCDECL\n" "#endif\n"; static CHAR *szDefCallTypePrefix = "#define STDMETHODCALLTYPE STDMETHOD"; static CHAR *rgszCallType[] = { "CDECL", "PASCAL", "STDCALL" }; typedef enum { CALL_CDECL, CALL_PASCAL, CALL_STDCALL, CALL_DEFAULT } CALLINGCONV; static CALLINGCONV ccInterCurrent = CALL_DEFAULT; // user-specified calling conventions for all platforms static CHAR * szCCHeader = "\n" "/* Macros for redefining the STDMETHOD calling convention\n" " * (STDMETHODCALLTYPE).\n" " */\n" "\n" "#if defined(_MAC)\n" "\n" "#if !defined(_MSC_VER)\n" "#define STDMETHODCDECL\n" "#define STDMETHODPASCAL\n" "#define STDMETHODSTDCALL\n" "#else\n" "#define STDMETHODCDECL FAR CDECL\n" "#define STDMETHODPASCAL FAR PASCAL\n" "#define STDMETHODSTDCALL FAR STDCALL\n" "#endif\n" "\n" "#elif defined(WIN32)\n" "\n" "#define STDMETHODCDECL EXPORT __cdecl\n" "#define STDMETHODPASCAL EXPORT __pascal\n" "#define STDMETHODSTDCALL EXPORT __stdcall\n" "\n" "#else /* WIN16 */\n" "\n" "#define STDMETHODCDECL __export FAR CDECL\n" "#define STDMETHODPASCAL __export FAR PASCAL\n" "#define STDMETHODSTDCALL __export FAR STDCALL\n" "\n" "#endif\n" "\n"; // canned definition of IUnknown static CHAR * szHeadIUnknown = "\n" " /* IUnknown methods */\n" " STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;\n" " STDMETHOD_(ULONG, AddRef)(THIS) PURE;\n" " STDMETHOD_(ULONG, Release)(THIS) PURE;\n"; // canned definition of IDispatch static CHAR * szHeadIDispatch = "\n" " /* IDispatch methods */\n" " STDMETHOD(GetTypeInfoCount)(THIS_ UINT FAR* pctinfo) PURE;\n" "\n" " STDMETHOD(GetTypeInfo)(\n" " THIS_\n" " UINT itinfo,\n" " LCID lcid,\n" " ITypeInfo FAR* FAR* pptinfo) PURE;\n" "\n" " STDMETHOD(GetIDsOfNames)(\n" " THIS_\n" " REFIID riid,\n" " OLECHAR FAR* FAR* rgszNames,\n" " UINT cNames,\n" " LCID lcid,\n" " DISPID FAR* rgdispid) PURE;\n" "\n" " STDMETHOD(Invoke)(\n" " THIS_\n" " DISPID dispidMember,\n" " REFIID riid,\n" " LCID lcid,\n" " WORD wFlags,\n" " DISPPARAMS FAR* pdispparams,\n" " VARIANT FAR* pvarResult,\n" " EXCEPINFO FAR* pexcepinfo,\n" " UINT FAR* puArgErr) PURE;\n"; static CHAR *szHeadGuidPrefix = "\nDEFINE_GUID("; static CHAR *szHeadGuidLIBID = "LIBID_"; static CHAR *szHeadGuidCLSID = "CLSID_"; static CHAR *szHeadGuidIID = "IID_"; static CHAR *szHeadGuidDIID = "DIID_"; // prototypes VOID FAR OutputHFile (CHAR * szHFile); VOID NEAR HOutTypedef(LPTYPE pType); VOID NEAR HOutEnum(LPTYPE pType); VOID NEAR HOutStructUnion(LPTYPE pType); VOID NEAR HOutModule(LPENTRY pEntry); VOID NEAR HOutInterface(LPENTRY pEntry); VOID NEAR HOutCoclass(LPENTRY pEntry); VOID NEAR HOutBaseInter(LPENTRY pEntry, BOOL fRecurse); VOID NEAR HOutFuncs(LPFUNC pFuncList, TENTRYKIND tentryKind); VOID NEAR HOutElems(LPELEM pElemList, CHAR * szPrefix, CHAR * szSep, CHAR * szSepLast, BOOL fEnum); VOID NEAR HOutType(LPTYPE pType); VOID NEAR HOutShortNum(SHORT num, BOOL fHex); VOID NEAR HOutLongNum(LONG num, BOOL fHex); VOID NEAR HOutPropPrefix(LPFUNC pFunc); VOID NEAR HOutGuid(LPATTR pAttr, CHAR * szGuidPrefix, LPSTR lpszName); #ifdef PROFILE VOID NEAR XOutF(LPSTR lpszData); VOID NEAR XOut(CHAR * szData); #else //PROFILE #define XOutF HOutF #define XOut HOut #endif //PROFILE VOID NEAR HOutF(LPSTR lpszData); VOID NEAR HOut(CHAR * szData); VOID NEAR SetCallType(CALLINGCONV cc); VOID FAR OutputHFile ( CHAR * szHFile ) { LPENTRY pEntry; #ifdef WIN16 // convert szHFile in-place to OEM char set AnsiToOem(szHFile, szHFile); // don't bother converting back since this string is not used again #endif // WIN16 // open the file hHFile = fopen(szHFile, "w"); // open output file if (hHFile == NULL) ParseError(ERR_CANT_OPEN_HFILE); Assert (SYS_WIN16 == 0 && SYS_WIN32 == 1 && SYS_MAC == 2 && SysKind <= SYS_MAX); HOut(szHeadFile); // output file header HOutF(typlib.szLibName); // output type library name HOut(" */\n\n#ifndef _"); // output: #ifndef __H_ HOutF(typlib.szLibName); // #define __H_ HOut("_H_\n#define _"); HOutF(typlib.szLibName); HOut("_H_\n"); HOutGuid(&typlib.attr, szHeadGuidLIBID, typlib.szLibName); if (fSpecifiedInterCC) { HOut(szCCHeader); } if (typlib.pEntry) { pEntry = (LPENTRY)ListFirst(typlib.pEntry); // point to first entry #pragma warning(disable:4127) while (TRUE) #pragma warning(default:4127) { switch (pEntry->type.tentrykind & ~tFORWARD) { case tTYPEDEF: HOutTypedef(&pEntry->type); break; case tENUM: HOutEnum(&pEntry->type); break; case tSTRUCT: case tUNION: HOutStructUnion(&pEntry->type); break; case tMODULE: HOutModule(pEntry); break; case tCOCLASS: HOutCoclass(pEntry); break; case tINTERFACE: case tDISPINTER: HOutInterface(pEntry); // fall through case tINTRINSIC: case tREF: break; // nothing to output #ifdef DEBUG default: if (pEntry->type.tentrykind & tIMPORTED) break; // noting to output for imported types Assert(FALSE); #endif //DEBUG } // advance to next entry if not all done if (pEntry == (LPENTRY)ListLast(typlib.pEntry)) break; // exit if all done pEntry = (LPENTRY)pEntry->type.pNext; } // WHILE } HOut("\n#endif\n"); fclose(hHFile); // done writing .H file hHFile = NULL; // close done // check for possible alignment problems if (iAlignMax != iAlignDef) ParseError(WARN_STRANGE_ALIGNMENT); #ifdef PROFILE printf("\n\ntotal functions: %d\n", cFuncsTotal); printf("total function args: %d\n", cArgsTotal); printf("total variables: %d\n", cVarsTotal); ParseError(ERR_OM); // bogus early quit #endif //PROFILE } VOID NEAR HOutTypedef ( LPTYPE pType ) { XOut("\ntypedef "); // output base type HOutType(pType->td.ptypeAlias); HOut(" "); XOutF(pType->szName); Assert(pType->td.ptypeAlias->tdesc.vt != VT_CARRAY); XOut(";\n"); } VOID NEAR HOutEnum ( LPTYPE pType ) { XOut("\ntypedef enum "); if (pType->structenum.szTag) { XOutF(pType->structenum.szTag); if (pType->tentrykind & tFORWARD) { XOut(";\n"); return; } XOut(" "); } XOut("{\n"); HOutElems(pType->structenum.elemList, " ", ",\n", "\n", TRUE); XOut("} "); XOutF(pType->szName); XOut(";\n"); } VOID NEAR HOutStructUnion ( LPTYPE pType ) { if ((pType->tentrykind & ~tFORWARD) == tSTRUCT) XOut("\ntypedef struct "); else XOut("\ntypedef union "); if (pType->structenum.szTag) { XOutF(pType->structenum.szTag); if (pType->tentrykind & tFORWARD) goto done; XOut(" "); } XOut("{\n"); HOutElems(pType->structenum.elemList, " ", ";\n", ";\n", FALSE); XOut("} "); XOutF(pType->szName); done: XOut(";\n"); } VOID NEAR HOutModule ( LPENTRY pEntry ) { XOut(szHeadModule); XOutF(pEntry->type.szName); XOut(szHeadOleSuffix3); HOutFuncs(pEntry->module.funcList, pEntry->type.tentrykind); if (pEntry->module.constList) HOutElems(pEntry->module.constList, " const ", ";\n", ";\n", FALSE); } VOID NEAR HOutCoclass ( LPENTRY pEntry ) { if ((pEntry->type.tentrykind & tFORWARD) == 0) { HOutGuid(&pEntry->attr, szHeadGuidCLSID, pEntry->type.szName); } // UNDONE: I don't think this will work in C. HOut("\n#ifdef __cplusplus\nclass "); HOutF(pEntry->type.szName); HOut(";\n#endif\n"); } VOID NEAR HOutInterface ( LPENTRY pEntry ) { LPSTR lpszBaseName; TENTRYKIND tentrykind; LPINTER lpInterFirst; // first base interface, if any LPINTER lpInterLast; // second/last base interface, if any tentrykind = pEntry->type.tentrykind; if (tentrykind & tFORWARD) { // UNDONE: proper OLE format for forward declaration of interface? // UNDONE: I don't think this will work in C. I think it wants: // UNDONE: typedef interface ; HOut("\ninterface "); HOutF(pEntry->type.szName); HOut(";\n"); return; } HOutGuid(&pEntry->attr, ((tentrykind == tDISPINTER) ? szHeadGuidDIID: szHeadGuidIID), pEntry->type.szName); lpszBaseName = NULL; lpInterFirst = NULL; if (pEntry->type.inter.interList) { lpInterFirst = (LPINTER)ListFirst(pEntry->type.inter.interList); lpInterLast = (LPINTER)ListLast(pEntry->type.inter.interList); // We assume there's only single inheritance at this point // But in the case of a dispinterface, we could have the first // base interface be IDispatch, and the 2nd base interface be // the interface that we're capable of dispatching on. In any // case, there can't be more than 2 interfaces in the list. Assert((LPINTER)lpInterFirst->pNext == lpInterLast); lpszBaseName = lpInterFirst->ptypeInter->szName; Assert(lpszBaseName); } // first output the header comment HOut((tentrykind == tDISPINTER) ? szHeadDispinter: szHeadInter); HOutF(pEntry->type.szName); HOut(szHeadOleSuffix3); // then output the OLE header HOut(szHeadOlePrefix0); HOutF(pEntry->type.szName); HOut("\n\n"); HOut(szHeadOlePrefix1); if (lpszBaseName) HOut("_"); HOut("("); HOutF(pEntry->type.szName); if (lpszBaseName) // if this inherits from somebody { // then add ", " HOut(", "); HOutF(lpszBaseName); } HOut(szHeadOlePrefix2); if (tentrykind == tDISPINTER) { Assert (lpszBaseName); HOut(szHeadOlePrefix7); HOut(szHeadIUnknown); HOut(szHeadIDispatch); HOut(szHeadOleSuffix7); if (lpInterFirst != lpInterLast) { // specifies an interface that is dispatchable HOut(szHeadDispatchable); HOutF(lpInterLast->ptypeInter->szName); HOut(szHeadOleSuffix3); } // first output the properties (commented out) in "struct" format if (pEntry->dispinter.propList) { XOut(szHeadOlePrefix3); XOutF(pEntry->type.szName); XOut(szHeadOlePrefix5); HOutElems(pEntry->dispinter.propList, " ", ";\n", ";\n", FALSE); HOut(szHeadOleSuffix1); } // then output the methods (commented out) in "normal" format if (pEntry->dispinter.methList) { XOut(szHeadOlePrefix3); XOutF(pEntry->type.szName); XOut(szHeadOlePrefix6); HOutFuncs(pEntry->dispinter.methList, tDISPINTER); HOut(szHeadOleSuffix1); } } else { // an interface // output interface functions, and base interface functions (if any) HOutBaseInter(pEntry, FALSE); } // lastly, output the close curly HOut(szHeadOleSuffix2); } VOID NEAR HOutBaseInter(LPENTRY pEntry, BOOL fRecurse) { LPINTER lpInterBase; // hard-coded descriptions for the 2 most common if (!FCmpCaseIns(pEntry->type.szName, "IUnknown")) { HOut(szHeadIUnknown); } else if (!FCmpCaseIns(pEntry->type.szName, "IDispatch")) { if (!fRecurse) HOut(szHeadOlePrefix7); HOut(szHeadIUnknown); if (!fRecurse) HOut(szHeadOleSuffix7); HOut(szHeadIDispatch); } else if ((pEntry->type.tentrykind & ~tFORWARD) != tINTERFACE) { // can't deal with imported base interfaces HOut(szHeadOlePrefix3); HOutF(pEntry->type.szName); HOut(szHeadOlePrefix4); HOut(szHeadMethods); } else { if (pEntry->type.tentrykind & tFORWARD) { // if this is a forward decl, follow pointer back to real // interface (since base interfaces and functions aren't // stored in the forward declare) pEntry = pEntry->lpEntryForward; } lpInterBase = pEntry->type.inter.interList; if (lpInterBase) // if this inherits from somebody, { // then first describe the base interface if (!fRecurse) HOut(szHeadOlePrefix7); // HACK -- assumes we can cast LPTYPE to LPENTRY, but // this is always true given our above validation HOutBaseInter((LPENTRY)(lpInterBase->ptypeInter), TRUE); if (!fRecurse) HOut(szHeadOleSuffix7); } // output the interface functions in OLE format XOut(szHeadOlePrefix3); XOutF(pEntry->type.szName); XOut(szHeadOlePrefix4); HOutFuncs(pEntry->inter.funcList, tINTERFACE); } } VOID NEAR HOutFuncs ( LPFUNC pFuncList, TENTRYKIND tentryKind ) { LPFUNC pFunc; if (pFuncList == NULL) // nothing to output if no functions return; pFunc = (LPFUNC)ListFirst(pFuncList); // point to first entry #pragma warning(disable:4127) while (TRUE) #pragma warning(default:4127) { #ifndef PROFILE if (tentryKind == tINTERFACE) { if (fSpecifiedInterCC) { // set up STDMETHODCALLTYPE based on the calling // convention and SYSKIND if (pFunc->func.attr.fAttr2 & f2CCDEFAULTED) SetCallType(CALL_DEFAULT); else if (pFunc->func.attr.fAttr2 & f2PASCAL) SetCallType(CALL_PASCAL); else if (pFunc->func.attr.fAttr2 & f2STDCALL) SetCallType(CALL_STDCALL); else { Assert(pFunc->func.attr.fAttr2 & f2CDECL) SetCallType(CALL_CDECL); } } HOut(szHeadOleFuncPrefix1); // leading spaces HOut(szHeadOleFuncPrefix2); if (pFunc->func.elemType->tdesc.vt == VT_HRESULT) HOut("("); else { HOut("_("); // output function return type HOutType(pFunc->func.elemType); HOut(szHeadOleFuncPrefix3); } HOutPropPrefix(pFunc); XOutF(pFunc->func.szElemName); HOut(szHeadOleArgPrefix1); if (pFunc->cArgs) { HOut(szHeadOleArgPrefix2); // output list of variables, separating them by // commas, with nothing after last item HOutElems(pFunc->argList, "", ", ", "", FALSE); } XOut(szHeadOleArgSuffix); } else #endif //!PROFILE { HOut(szHeadOleFuncPrefix1); // leading spaces if (tentryKind == tMODULE) HOut ("extern "); // output function return type HOutType(pFunc->func.elemType); HOut(" "); // output calling convention if (!(pFunc->func.attr.fAttr2 & f2CCDEFAULTED)) { if (pFunc->func.attr.fAttr2 & f2PASCAL) HOut("__pascal "); else if (pFunc->func.attr.fAttr2 & f2CDECL) HOut("__cdecl "); else if (pFunc->func.attr.fAttr2 & f2STDCALL) HOut("__stdcall "); #ifdef DEBUG else Assert(FALSE); #endif //DEBUG } HOutPropPrefix(pFunc); XOutF(pFunc->func.szElemName); Assert(pFunc->func.elemType->tdesc.vt != VT_CARRAY); XOut("("); #ifdef PROFILE cArgsTotal += pFunc->cArgs; cFuncsTotal++; #endif //PROFILE if (pFunc->cArgs == 0) { HOut("void"); } else { // output list of variables, separating them by // commas, with nothing after last item HOutElems(pFunc->argList, "", ", ", "", FALSE); #ifdef PROFILE cVarsTotal-= pFunc->cArgs; // would be counted twice #endif //PROFILE } XOut(");\n"); } // advance to next entry if not all done if (pFunc == (LPFUNC)ListLast(pFuncList)) break; // exit if all done pFunc = (LPFUNC)pFunc->func.pNext; } if (fSpecifiedInterCC) { SetCallType(CALL_DEFAULT); // reset to default STDMETHODCALLTYPE } } VOID NEAR SetCallType ( CALLINGCONV cc ) { Assert (fSpecifiedInterCC); // caller should have checked if (cc != ccInterCurrent) { // if current different than last HOut(szUndefCallType); // undefine current STDMETHODCALLTYPE if (cc == CALL_DEFAULT) { HOut(szResetCallType); // reset to default } else { HOut(szDefCallTypePrefix); // re-define to new value HOut(rgszCallType[cc]); HOut("\n"); } ccInterCurrent = cc; // update current value } } VOID NEAR HOutPropPrefix ( LPFUNC pFunc ) { // add a prefix to the function name if this is a property function if (pFunc->func.attr.fAttr & fPROPGET) HOut("get_"); else if (pFunc->func.attr.fAttr & fPROPPUT) HOut("put_"); else if (pFunc->func.attr.fAttr & fPROPPUTREF) HOut("putref_"); } VOID NEAR HOutShortNum ( SHORT num, BOOL fHex ) { CHAR szBuffer[30]; // space to list a number sprintf(szBuffer, fHex ? "0x%hX" : "%hd", num); HOut(szBuffer); } VOID NEAR HOutLongNum ( LONG num, BOOL fHex ) { CHAR szBuffer[30]; // space to list a number // Stupid C will choke if this number is printed in decimal if (num == 0x80000000) fHex = TRUE; sprintf(szBuffer, fHex ? "0x%lX" : "%ld", num); HOut(szBuffer); } VOID NEAR HOutElems ( LPELEM pElemList, CHAR * szPrefix, CHAR * szSep, CHAR * szSepLast, BOOL fEnum ) { LPELEM pElem; WORD cDims; ARRAYDESC FAR* lpAD; BOOL fHex; LPOLESTR lpch; CHAR * pch; CHAR buf[2]; UINT cch; pElem = (LPELEM)ListFirst(pElemList); // point to first entry #pragma warning(disable:4127) while (TRUE) #pragma warning(default:4127) { HOut(szPrefix); if (!fEnum) { // output elem type, with the right number of "*'s" HOutType(pElem->elemType); HOut(" "); } XOutF(pElem->szElemName); #ifdef PROFILE cVarsTotal++; #endif //PROFILE if (!fEnum && pElem->elemType->tdesc.vt == VT_CARRAY) { // base type already outputted before name above lpAD = pElem->elemType->tdesc.lpadesc; for (cDims = 0; cDims < lpAD->cDims; cDims++) { HOut("["); #if 0 // arrays of the form "a[]" aren't supported if (lpAD->rgbounds[cDims].cElements) #endif //0 HOutLongNum((long)lpAD->rgbounds[cDims].cElements, FALSE); HOut("]"); } } if (pElem->attr.fAttr2 & f2GotConstVal) { HOut(" = "); fHex = FALSE; if (!fEnum) { // display all the unsigned constants in Hex form switch (pElem->elemType->tdesc.vt) { case VT_UI1: case VT_UI2: case VT_UI4: case VT_UINT: case VT_ERROR: fHex = TRUE; break; default: break; } } // output the constant element's value switch (pElem->lpElemVal->vt) { case VT_I2: case VT_BOOL: HOutShortNum(pElem->lpElemVal->iVal, fHex); break; case VT_I4: case VT_ERROR: HOutLongNum(pElem->lpElemVal->lVal, fHex); break; case VT_BSTR: HOut("\""); // output 1 char at a time, in order to handle // escape sequences in strings lpch = pElem->lpElemVal->bstrVal; cch = SysStringLen(lpch); while (cch) { switch(*lpch) { case 0x0: pch = "\\0"; break; case 0x7: pch = "\\a"; break; case 0x8: pch = "\\b"; break; case 0x9: pch = "\\t"; break; case 0xA: if (SysKind == SYS_MAC) pch = "\\r"; else pch = "\\n"; break; case 0xB: pch = "\\v"; break; case 0xC: pch = "\\f"; break; case 0xD: if (SysKind == SYS_MAC) pch = "\\n"; else pch = "\\r"; break; default: #ifdef WIN32 SideAssert (WideCharToMultiByte(CP_ACP, 0, lpch, 1, buf, 1, NULL, NULL) != 0); #else //WIN32 buf[0] = *lpch; #endif //WIN32 buf[1] = '\0'; pch = buf; break; } HOut(pch); // output the char lpch++; cch--; } HOut("\""); break; // CONSIDER: support more constant types. default: Assert(FALSE); } } // advance to next entry if not all done if (pElem == (LPELEM)ListLast(pElemList)) { XOut(szSepLast); break; // exit if all done } XOut(szSep); pElem = pElem->pNext; } } VOID NEAR HOutType ( LPTYPE pType ) { SHORT i; CHAR * szPrefix; switch (pType->tdesc.vt) { case VT_PTR: // first output the base type HOutType(pType->ref.ptypeBase); // now output the proper number of "*"'s Assert (pType->ref.cIndirect != 0); for (i = pType->ref.cIndirect; i > 0; i--) { // always output "FAR" for constency (same as dispatch.h) HOut(" FAR*"); } break; case VT_CARRAY: // just output the base type -- we'll handle this stuff // after we output the name HOutType(pType->ref.ptypeBase); break; case VT_SAFEARRAY: HOut("SAFEARRAY FAR*"); break; case VT_BOOL: // special case -- "boolean" no good HOut("VARIANT_BOOL"); break; case VT_CY: // special case -- "CURRENCY" no good HOut("CY"); break; default: // output "unsigned" if necessary if (pType->tentrykind == tINTRINSIC && pType->intr.fUnsigned) HOut("unsigned "); switch (pType->tentrykind & ~tFORWARD) { case tUNION: szPrefix = "union "; goto outputPrefix; case tSTRUCT: szPrefix = "struct "; outputPrefix: if (pType->structenum.szTag) { HOut(szPrefix); HOutF(pType->structenum.szTag); break; } // otherwise, fall into default processing default: HOutF(pType->szName); } break; } } VOID NEAR HOutGuid ( LPATTR pAttr, CHAR * szGuidPrefix, LPSTR lpszName ) { CHAR szBuffer[100]; // space to list a number UNDONE: Tune GUID FAR * lpGuid; if ((pAttr->fAttr & fUUID) == 0) return; // no guid to output lpGuid = pAttr->lpUuid; HOut(szHeadGuidPrefix); HOut(szGuidPrefix); // prefix the user's name HOutF(lpszName); // add the user's name sprintf(szBuffer, ",0x%.8lX,0x%.4X,0x%.4X,0x%.2X,0x%.2X,0x%.2X,0x%.2X,0x%.2X,0x%.2X,0x%.2X,0x%.2X);\n", lpGuid->Data1, lpGuid->Data2, lpGuid->Data3, lpGuid->Data4[0], lpGuid->Data4[1], lpGuid->Data4[2], lpGuid->Data4[3], lpGuid->Data4[4], lpGuid->Data4[5], lpGuid->Data4[6], lpGuid->Data4[7] ); HOut(szBuffer); } VOID NEAR HOutF ( LPSTR lpszData ) { CHAR szBuffer[256]; _fstrcpy(szBuffer, lpszData); // copy data near HOut(szBuffer); // output it } VOID NEAR HOut ( CHAR * szData ) { if (fputs(szData, hHFile) < 0) // write the data ParseError(ERR_WRITING_HFILE); } #ifdef PROFILE VOID NEAR XOutF ( LPSTR lpszData ) { CHAR szBuffer[256]; _fstrcpy(szBuffer, lpszData); // copy data near XOut(szBuffer); // output it } VOID NEAR XOut ( CHAR * szData ) { printf(szData); // output to console } #endif //PROFILE