2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
5 //===========================================================================
10 // Notes: Create a TypeLib from COM+ metadata.
11 //---------------------------------------------------------------------------
15 #include "comcallablewrapper.h"
17 #include "dllimport.h"
18 #include "fieldmarshaler.h"
20 #include "comdelegate.h"
21 #include <nsutilpriv.h>
22 #include <tlbimpexp.h>
24 #include "tlbexport.h"
25 #include "commtmemberinfomap.h"
27 #include "posterror.h"
28 #include "typeparse.h"
30 #if defined(VALUE_MASK)
34 #include <guidfromname.h>
36 #include <siginfo.hpp>
37 #include <typestring.h>
38 #include "perfcounters.h"
39 #include "comtypelibconverter.h"
42 // Define to export an empty dispinterface for an AutoDispatch IClassX
43 #define EMPTY_DISPINTERFACE_ICLASSX
45 #define S_USEIUNKNOWN (HRESULT)2
48 #if defined(_DEBUG) && defined(_TRACE)
52 inline void NullFn(const char *pf,...) {}
56 #define IfFailReport(expr) \
57 do { if(FAILED(hr = (expr))) { DebBreakHr(hr); ReportError(hr); } } while (0)
59 #define IfFailReport(expr) \
60 do { if(FAILED(hr = (expr))) { ReportError(hr); } } while (0)
63 //-----------------------------------------------------------------------------
64 //-----------------------------------------------------------------------------
65 // This value determines whether, by default, we add the TYPEFLAG_FPROXY bit
66 // to exported interfaces. If the value is true, Automation proxy is the
67 // default, and we do not set the bit. If the value is false, no Automation
68 // proxy is the default and we DO set the bit.
69 #define DEFAULT_AUTOMATION_PROXY_VALUE TRUE
70 //-----------------------------------------------------------------------------
72 //*****************************************************************************
74 //*****************************************************************************
75 static const WCHAR szRetVal[] = W("pRetVal");
76 static const WCHAR szTypeLibExt[] = W(".TLB");
78 static const WCHAR szTypeLibKeyName[] = W("TypeLib");
79 static const WCHAR szClsidKeyName[] = W("CLSID");
81 static const WCHAR szIClassX[] = W("_%ls");
82 static const int cbIClassX = 1;
83 static const WCHAR cIClassX = W('_');
85 static const WCHAR szAlias[] = W("_MIDL_COMPAT_%ls");
86 static const int cbAlias = lengthof(szAlias) - 1;
87 static const WCHAR szParamName[] = W("p%d");
89 static const WCHAR szGuidName[] = W("GUID");
91 static const CHAR szObjectClass[] = "Object";
92 static const CHAR szArrayClass[] = "Array";
93 static const CHAR szDateTimeClass[] = "DateTime";
94 static const CHAR szDecimalClass[] = "Decimal";
95 static const CHAR szGuidClass[] = "Guid";
96 static const CHAR szStringClass[] = g_StringName;
97 static const CHAR szStringBufferClass[] = g_StringBufferName;
98 static const CHAR szIEnumeratorClass[] = "IEnumerator";
99 static const CHAR szColor[] = "Color";
101 static const char szRuntime[] = {"System."};
102 static const size_t cbRuntime = (lengthof(szRuntime)-1);
104 static const char szText[] = {"System.Text."};
105 static const size_t cbText = (lengthof(szText)-1);
107 static const char szCollections[] = {"System.Collections."};
108 static const size_t cbCollections = (lengthof(szCollections)-1);
110 static const char szDrawing[] = {"System.Drawing."};
111 static const size_t cbDrawing = (lengthof(szDrawing)-1);
113 // The length of the following string(w/o the terminator): "HKEY_CLASSES_ROOT\\CLSID\\{00000000-0000-0000-0000-000000000000}".
114 static const int cCOMCLSIDRegKeyLength = 62;
116 // The length of the following string(w/o the terminator): "{00000000-0000-0000-0000-000000000000}".
117 static const int cCLSIDStrLength = 38;
119 // {17093CC8-9BD2-11cf-AA4F-304BF89C0001}
120 static const GUID GUID_TRANS_SUPPORTED = {0x17093CC8,0x9BD2,0x11cf,{0xAA,0x4F,0x30,0x4B,0xF8,0x9C,0x00,0x01}};
122 // {00020430-0000-0000-C000-000000000046}
123 static const GUID LIBID_STDOLE2 = { 0x00020430, 0x0000, 0x0000, { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } };
125 // {66504301-BE0F-101A-8BBB-00AA00300CAB}
126 static const GUID GUID_OleColor = { 0x66504301, 0xBE0F, 0x101A, { 0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB } };
129 static const GUID LIBID_MSCOREE = {0x5477469e,0x83b1,0x11d2,{0x8b,0x49,0x00,0xa0,0xc9,0xb7,0xc9,0xc4}};
131 static const char XXX_DESCRIPTION_TYPE[] = {"System.ComponentModel.DescriptionAttribute"};
132 static const char XXX_ASSEMBLY_DESCRIPTION_TYPE[] = {"System.Reflection.AssemblyDescriptionAttribute"};
134 //*****************************************************************************
135 // Table to map COM+ calling conventions to TypeLib calling conventions.
136 //*****************************************************************************
137 CALLCONV Clr2TlbCallConv[] =
139 CC_STDCALL, // IMAGE_CEE_CS_CALLCONV_DEFAULT = 0x0,
140 CC_CDECL, // IMAGE_CEE_CS_CALLCONV_C = 0x1,
141 CC_STDCALL, // IMAGE_CEE_CS_CALLCONV_STDCALL = 0x2,
142 CC_STDCALL, // IMAGE_CEE_CS_CALLCONV_THISCALL = 0x3,
143 CC_FASTCALL, // IMAGE_CEE_CS_CALLCONV_FASTCALL = 0x4,
144 CC_CDECL, // IMAGE_CEE_CS_CALLCONV_VARARG = 0x5,
145 CC_MAX // IMAGE_CEE_CS_CALLCONV_FIELD = 0x6,
146 // IMAGE_CEE_CS_CALLCONV_MAX = 0x7
151 // Forward declarations.
152 extern HRESULT _FillVariant(MDDefaultValue *pMDDefaultValue, VARIANT *pvar);
153 extern HRESULT _FillMDDefaultValue(BYTE bType, void const *pValue, MDDefaultValue *pMDDefaultValue);
155 //*****************************************************************************
156 // Stolen from classlib.
157 //*****************************************************************************
158 double _TicksToDoubleDate(const __int64 ticks)
168 const INT64 MillisPerSecond = 1000;
169 const INT64 MillisPerDay = MillisPerSecond * 60 * 60 * 24;
170 const INT64 TicksPerMillisecond = 10000;
171 const INT64 TicksPerSecond = TicksPerMillisecond * 1000;
172 const INT64 TicksPerMinute = TicksPerSecond * 60;
173 const INT64 TicksPerHour = TicksPerMinute * 60;
174 const INT64 TicksPerDay = TicksPerHour * 24;
175 const int DaysPer4Years = 365 * 4 + 1;
176 const int DaysPer100Years = DaysPer4Years * 25 - 1;
177 const int DaysPer400Years = DaysPer100Years * 4 + 1;
178 const int DaysTo1899 = DaysPer400Years * 4 + DaysPer100Years * 3 - 367;
179 const INT64 DoubleDateOffset = DaysTo1899 * TicksPerDay;
180 const int DaysTo10000 = DaysPer400Years * 25 - 366;
181 const INT64 MaxMillis = DaysTo10000 * MillisPerDay;
182 const int DaysPerYear = 365; // non-leap year
183 const INT64 OADateMinAsTicks = (DaysPer100Years - DaysPerYear) * TicksPerDay;
185 // Returns OleAut's zero'ed date ticks.
189 if (ticks < OADateMinAsTicks)
192 // Currently, our max date == OA's max date (12/31/9999), so we don't
193 // need an overflow check in that direction.
194 __int64 millis = (ticks - DoubleDateOffset) / TicksPerMillisecond;
197 __int64 frac = millis % MillisPerDay;
198 if (frac != 0) millis -= (MillisPerDay + frac) * 2;
201 return (double)millis / MillisPerDay;
202 } // double _TicksToDoubleDate()
205 //*****************************************************************************
206 // Get the name of a typelib or typeinfo, add it to error text.
207 //*****************************************************************************
208 void PostTypeLibError(
209 IUnknown *pUnk, // An interface on the typeinfo.
210 HRESULT hrT, // The TypeInfo error.
211 HRESULT hrX) // The Exporter error.
216 PRECONDITION(CheckPointer(pUnk));
220 HRESULT hr; // A result.
221 WCHAR rcErr[1024]; // Buffer for error message.
223 SafeComHolder<ITypeInfo> pITI=0; // The ITypeInfo * on the typeinfo.
224 SafeComHolder<ITypeLib> pITLB=0; // The ITypeLib *.
225 BSTRHolder name=0; // The name of the TypeInfo.
227 // Try to get a name.
228 hr = SafeQueryInterface(pUnk, IID_ITypeInfo, (IUnknown**)&pITI);
231 IfFailThrow(pITI->GetDocumentation(MEMBERID_NIL, &name, 0,0,0));
235 hr = SafeQueryInterface(pUnk, IID_ITypeLib, (IUnknown**)&pITLB);
237 IfFailThrow(pITLB->GetDocumentation(MEMBERID_NIL, &name, 0,0,0));
242 name = SysAllocString(W("???"));
244 COMPlusThrowHR(E_OUTOFMEMORY);
247 // Format the typelib error.
248 FormatRuntimeError(rcErr, lengthof(rcErr), hrT);
251 strHRHex.Printf("%.8x", hrX);
253 COMPlusThrowHR(hrX, hrX, strHRHex, name, rcErr);
254 } // void PostTypeLibError()
259 void ExportTypeLibFromLoadedAssembly(
260 Assembly *pAssembly, // The assembly.
261 LPCWSTR szTlb, // The typelib name.
262 ITypeLib **ppTlb, // If not null, also return ITypeLib here.
263 ITypeLibExporterNotifySink *pINotify,// Notification callback.
264 int flags) // Export flags.
269 PRECONDITION(CheckPointer(pAssembly));
270 PRECONDITION(CheckPointer(szTlb, NULL_OK));
271 PRECONDITION(CheckPointer(ppTlb));
272 PRECONDITION(CheckPointer(pINotify, NULL_OK));
278 TypeLibExporter exporter; // Exporter object.
279 LPCWSTR szModule=0; // Module filename.
280 WCHAR rcDrive[_MAX_DRIVE];
281 WCHAR rcDir[_MAX_DIR];
282 WCHAR rcFile[_MAX_FNAME];
283 WCHAR rcTlb[_MAX_PATH+5]; // Buffer for the tlb filename.
284 int bDynamic=0; // If true, dynamic module.
285 Module *pModule; // The Assembly's SecurityModule.
287 pModule = pAssembly->GetManifestModule();
290 // Retrieve the module filename.
291 szModule = pModule->GetPath();
292 PREFIX_ASSUME(szModule != NULL);
294 // Make sure the assembly has not been imported from COM.
295 if (pAssembly->IsImportedFromTypeLib())
296 COMPlusThrowHR(TLBX_E_CIRCULAR_EXPORT, (UINT)TLBX_E_CIRCULAR_EXPORT, W(""), szModule, NULL);
298 // If the module is dynamic then it will not have a file name. We
299 // assign a dummy name for typelib name (if the scope does not have
300 // a name), but won't create a typelib on disk.
304 szModule = W("Dynamic");
307 // Create the typelib name, if none provided. Don't create one for Dynamic modules.
308 if (!szTlb || !*szTlb)
314 SplitPath(szModule, rcDrive, _MAX_DRIVE, rcDir, _MAX_DIR, rcFile, _MAX_FNAME, 0, 0);
315 MakePath(rcTlb, rcDrive, rcDir, rcFile, szTypeLibExt);
320 // Do the conversion.
321 exporter.Convert(pAssembly, szTlb, pINotify, flags);
323 // Get a copy of the ITypeLib*
324 IfFailThrow(exporter.GetTypeLib(IID_ITypeLib, (IUnknown**)ppTlb));
325 } // void ExportTypeLibFromLoadedAssemblyInternal()
328 HRESULT ExportTypeLibFromLoadedAssemblyNoThrow(
329 Assembly *pAssembly, // The assembly.
330 LPCWSTR szTlb, // The typelib name.
331 ITypeLib **ppTlb, // If not null, also return ITypeLib here.
332 ITypeLibExporterNotifySink *pINotify,// Notification callback.
333 int flags) // Export flags.
347 ExportTypeLibFromLoadedAssembly(pAssembly,
353 EX_CATCH_HRESULT(hr);
358 //*****************************************************************************
359 // Default notification class.
360 //*****************************************************************************
361 class CDefaultNotify : public ITypeLibExporterNotifySink
364 virtual HRESULT __stdcall ReportEvent(
365 ImporterEventKind EventKind, // Type of event.
366 long EventCode, // HR of event.
367 BSTR EventMsg) // Text message for event.
369 LIMITED_METHOD_CONTRACT;
371 } // virtual HRESULT __stdcall ReportEvent()
373 //-------------------------------------------------------------------------
374 virtual HRESULT __stdcall ResolveRef(
384 PRECONDITION(CheckPointer(Asm));
385 PRECONDITION(CheckPointer(pRetVal));
389 HRESULT hr = S_OK; // A result.
390 Assembly *pAssembly=0; // The referenced Assembly.
391 ITypeLib *pTLB=0; // The created TypeLib.
392 MethodTable *pAssemblyClass = NULL; //@todo -- get this.
393 LPVOID RetObj = NULL; // The object to return.
395 BEGIN_EXTERNAL_ENTRYPOINT(&hr)
398 GCX_COOP_THREAD_EXISTS(GET_THREAD());
399 // Get the Referenced Assembly from the IUnknown.
400 ASSEMBLYREF asmRef = NULL;
401 GCPROTECT_BEGIN(asmRef);
402 GetObjectRefFromComIP((OBJECTREF*)&asmRef, Asm, pAssemblyClass);
403 pAssembly = asmRef->GetAssembly();
407 // Default resolution provides no notification, flags are 0.
408 ExportTypeLibFromLoadedAssembly(pAssembly, 0, &pTLB, 0 /*pINotify*/, 0 /* flags*/);
410 END_EXTERNAL_ENTRYPOINT;
415 } // virtual HRESULT __stdcall ResolveRef()
417 //-------------------------------------------------------------------------
418 virtual HRESULT STDMETHODCALLTYPE QueryInterface(// S_OK or E_NOINTERFACE
419 REFIID riid, // Desired interface.
420 void **ppvObject) // Put interface pointer here.
428 PRECONDITION(CheckPointer(ppvObject));
433 if (riid == IID_IUnknown || riid == IID_ITypeLibExporterNotifySink)
438 return E_NOINTERFACE;
439 } // virtual HRESULT QueryInterface()
441 //-------------------------------------------------------------------------
442 virtual ULONG STDMETHODCALLTYPE AddRef(void)
444 LIMITED_METHOD_CONTRACT;
446 } // virtual ULONG STDMETHODCALLTYPE AddRef()
448 //-------------------------------------------------------------------------
449 virtual ULONG STDMETHODCALLTYPE Release(void)
451 LIMITED_METHOD_CONTRACT;
453 } // virtual ULONG STDMETHODCALLTYPE Release()
456 static CDefaultNotify g_Notify;
458 //*****************************************************************************
460 //*****************************************************************************
461 TypeLibExporter::TypeLibExporter()
468 LIMITED_METHOD_CONTRACT;
472 ++i; // So a breakpoint can be set.
474 } // TypeLibExporter::TypeLibExporter()
476 TypeLibExporter::~TypeLibExporter()
486 } // TypeLibExporter::~TypeLibExporter()
488 //*****************************************************************************
489 // Get an interface pointer from the ICreateTypeLib interface.
490 //*****************************************************************************
491 HRESULT TypeLibExporter::GetTypeLib(
493 IUnknown **ppITypeLib)
500 PRECONDITION(CheckPointer(ppITypeLib));
504 return SafeQueryInterface(m_pICreateTLB, iid, (IUnknown**)ppITypeLib);
505 } // HRESULT TypeLibExporter::GetTypeLib()
507 //*****************************************************************************
508 // LayOut a TypeLib. Call LayOut on all ICreateTypeInfo2s first.
509 //*****************************************************************************
510 void TypeLibExporter::LayOut() // S_OK or error.
512 STANDARD_VM_CONTRACT;
514 HRESULT hr = S_OK; // A result.
515 int cTypes; // Count of exported types.
516 int ix; // Loop control.
517 CExportedTypesInfo *pData; // For iterating the entries.
519 cTypes = m_Exports.Count();
521 // Call LayOut on all ICreateTypeInfo2*s.
522 for (ix=0; ix<cTypes; ++ix)
524 pData = m_Exports[ix];
525 if (pData->pCTI && FAILED(hr = pData->pCTI->LayOut()))
526 PostTypeLibError(pData->pCTI, hr, TLBX_E_LAYOUT_ERROR);
529 for (ix=0; ix<cTypes; ++ix)
531 pData = m_Exports[ix];
532 if (pData->pCTIClassItf && FAILED(hr = pData->pCTIClassItf->LayOut()))
533 PostTypeLibError(pData->pCTIClassItf, hr, TLBX_E_LAYOUT_ERROR);
536 // Repeat for injected types.
537 cTypes = m_InjectedExports.Count();
538 for (ix=0; ix<cTypes; ++ix)
540 pData = m_InjectedExports[ix];
541 if (pData->pCTI && FAILED(hr = pData->pCTI->LayOut()))
542 PostTypeLibError(pData->pCTI, hr, TLBX_E_LAYOUT_ERROR);
545 for (ix=0; ix<cTypes; ++ix)
547 pData = m_InjectedExports[ix];
548 if (pData->pCTIClassItf && FAILED(hr = pData->pCTIClassItf->LayOut()))
549 PostTypeLibError(pData->pCTIClassItf, hr, TLBX_E_LAYOUT_ERROR);
551 } // HRESULT TypeLibExporter::LayOut()
553 //*****************************************************************************
554 // Release all pointers.
555 //*****************************************************************************
556 void TypeLibExporter::ReleaseResources()
566 // Release the ITypeInfo* pointers.
568 m_InjectedExports.Clear();
570 // Clean up the created TLB.
571 SafeRelease(m_pICreateTLB);
574 // Clean up the ITypeInfo*s for well-known interfaces.
575 SafeRelease(m_pIUnknown);
578 SafeRelease(m_pIDispatch);
581 SafeRelease(m_pGuid);
583 } // void TypeLibExporter::ReleaseResources()
585 //*****************************************************************************
586 // Enumerate the Types in a Module, add to the list.
587 //*****************************************************************************
588 void TypeLibExporter::AddModuleTypes(
589 Module *pModule) // The module to convert.
594 PRECONDITION(CheckPointer(pModule));
599 ULONG cTD; // Count of typedefs.
600 mdTypeDef td; // A TypeDef.
601 MethodTable *pClass; // A MethodTable for a TypeDef.
602 ULONG ix; // Loop control.
603 CExportedTypesInfo *pExported; // For adding classes to the exported types cache.
604 CExportedTypesInfo sExported; // For adding classes to the exported types cache.
607 // Convert all the types visible to COM.
608 // Get an enumerator on TypeDefs in the scope.
609 HENUMInternalHolder eTD(pModule->GetMDImport());
610 eTD.EnumTypeDefInit();
611 cTD = pModule->GetMDImport()->EnumTypeDefGetCount(&eTD);
613 // Add all the classes to the hash.
614 for (ix=0; ix<cTD; ++ix)
616 ZeroHolder zhType = &m_ErrorContext.m_pScope; // Clear error reporting info.
619 if (!pModule->GetMDImport()->EnumTypeDefNext(&eTD, &td))
620 IfFailReport(E_UNEXPECTED);
622 IMDInternalImport* pInternalImport = pModule->GetMDImport();
624 // Error reporting info.
625 m_ErrorContext.m_tkType = td;
626 m_ErrorContext.m_pScope = pModule->GetMDImport();
628 // Get the class, perform the step.
629 pClass = LoadClass(pModule, td);
631 // Enumerate the formal type parameters
632 HENUMInternal hEnumGenericPars;
633 hr = pInternalImport->EnumInit(mdtGenericParam, td, &hEnumGenericPars);
636 DWORD numGenericArgs = pInternalImport->EnumGetCount(&hEnumGenericPars);
637 // skip generic classes
638 if( numGenericArgs > 0 )
640 // We'll only warn if the type is marked ComVisible.
641 if (SpecialIsGenericTypeVisibleFromCom(TypeHandle(pClass)))
642 ReportWarning(TLBX_I_GENERIC_TYPE, TLBX_I_GENERIC_TYPE);
648 // If the flag to not ignore non COM visible types in name decoration is set, then
649 // add the ComVisible(false) types to our list of exported types by skipping this check.
650 if ((m_flags & TlbExporter_OldNames) == 0)
652 // If the type isn't visible from COM, don't add it to the list of exports.
653 if (!IsTypeVisibleFromCom(TypeHandle(pClass)))
657 // See if this class is already in the list.
658 sExported.pClass = pClass;
659 pExported = m_Exports.Find(&sExported);
663 // New class, add to list.
664 pExported = m_Exports.Add(&sExported);
666 IfFailReport(E_OUTOFMEMORY);
668 // Prefix can't tell that IfFailReport will actually throw an exception if pExported is NULL so
669 // let's tell it explicitly that if we reach this point pExported will not be NULL.
670 PREFIX_ASSUME(pExported != NULL);
671 pExported->pClass = pClass;
673 pExported->pCTIClassItf = 0;
675 } // HRESULT TypeLibExporter::AddModuleTypes()
677 //*****************************************************************************
678 // Enumerate the Modules in an assembly, add the types to the list.
679 //*****************************************************************************
680 void TypeLibExporter::AddAssemblyTypes(
681 Assembly *pAssembly) // The assembly to convert.
686 PRECONDITION(CheckPointer(pAssembly));
690 Module *pManifestModule; // A module in the assembly.
691 mdFile mf; // A file token.
693 if (pAssembly->GetManifestImport())
695 // Enumerator over the modules of the assembly.
696 HENUMInternalHolder phEnum(pAssembly->GetManifestImport());
697 phEnum.EnumInit(mdtFile, mdTokenNil);
699 // Get the module for the assembly.
700 pManifestModule = pAssembly->GetManifestModule();
701 AddModuleTypes(pManifestModule);
703 while (pAssembly->GetManifestImport()->EnumNext(&phEnum, &mf))
705 DomainFile *pDomainFile = pAssembly->GetManifestModule()->LoadModule(GetAppDomain(), mf, FALSE);
707 if (pDomainFile != NULL && !pDomainFile->GetFile()->IsResource())
708 AddModuleTypes(pDomainFile->GetModule());
711 } // HRESULT TypeLibExporter::AddAssemblyTypes()
713 //*****************************************************************************
714 // Convert COM+ metadata to a typelib.
715 //*****************************************************************************
716 void TypeLibExporter::Convert(
717 Assembly *pAssembly, // The Assembly to convert
718 LPCWSTR szTlbName, // Name of resulting TLB
719 ITypeLibExporterNotifySink *pNotify,// Notification callback.
720 int flags) // Conversion flags
725 PRECONDITION(CheckPointer(pAssembly));
726 PRECONDITION(CheckPointer(szTlbName));
727 PRECONDITION(CheckPointer(pNotify, NULL_OK));
731 HRESULT hr = S_OK; // A result.
732 ULONG i; // Loop control.
733 SString sName; // Library name.
734 GUID guid; // Library guid.
735 VARIANT vt = {0}; // Variant for ExportedFromComPlus.
736 CQuickArray<WCHAR> qLocale; // Wide string for locale.
737 LCID lcid; // LCID for typelib, default 0.
740 COUNTER_ONLY(GetPerfCounters().m_Interop.cTLBExports++);
742 SafeComHolder<IMultiLanguage> pIML=0; // For locale->lcid conversion.
743 SafeComHolder<ITypeLib> pITLB=0; // TypeLib for IUnknown, IDispatch.
744 BSTRHolder szTIName=0; // Name of a TypeInfo.
745 BSTRHolder szDescription=0; // Assembly Description.
747 // Error reporting information.
748 m_ErrorContext.m_szAssembly = pAssembly->GetSimpleName();
753 m_pNotify = pNotify ? pNotify : &g_Notify;
755 // If we haven't set 32-bit or 64-bit export yet, set it now with defaults.
756 UpdateBitness(pAssembly);
758 // Check the bitness of the assembly against our output bitness
759 IfFailReport(CheckBitness(pAssembly));
761 // Get some well known TypeInfos.
764 BSTR wzPath;// = SysAllocStringLen(NULL, _MAX_PATH);
765 IfFailReport(QueryPathOfRegTypeLib(LIBID_STDOLE2, -1, -1, 0, &wzPath));
767 if (IsExportingAs64Bit())
769 hr = LoadTypeLibEx(wzPath, (REGKIND)(REGKIND_NONE | LOAD_TLB_AS_64BIT), &pITLB);
773 hr = LoadTypeLibEx(wzPath, (REGKIND)(REGKIND_NONE | LOAD_TLB_AS_32BIT), &pITLB);
776 // If we failed to load StdOle2.tlb, then we're probably on a downlevel platform (< XP)
777 // so we'll just load whatever we have...note that at this point, cross-compile is not an option.
780 IfFailReport(LoadRegTypeLib(LIBID_STDOLE2, -1, -1, 0, &pITLB));
783 IfFailReport(pITLB->GetTypeInfoOfGuid(IID_IUnknown, &m_pIUnknown));
784 IfFailReport(pITLB->GetTypeInfoOfGuid(IID_IDispatch, &m_pIDispatch));
786 // Look for GUID (which unfortunately has no GUID).
787 for (i=0; i<pITLB->GetTypeInfoCount() && !m_pGuid; ++i)
789 IfFailReport(pITLB->GetDocumentation(i, &szTIName, 0, 0, 0));
790 if (SString::_wcsicmp(szTIName, szGuidName) == 0)
791 IfFailReport(pITLB->GetTypeInfo(i, &m_pGuid));
794 // Create the output typelib.
796 // Win2K: passing in too long a filename triggers a nasty buffer overrun bug
797 // when the SaveAll() method is called. We'll avoid triggering this here.
799 if (wcslen(szTlbName) > MAX_PATH_FNAME)
800 IfFailReport(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE));
802 // Reverting to old behavior here until we can fix up the vtable offsets as well.
803 // Set the SYSKIND based on the 64bit/32bit switches
804 if (IsExportingAs64Bit())
806 IfFailReport(CreateTypeLib2(SYS_WIN64, szTlbName, &m_pICreateTLB));
810 IfFailReport(CreateTypeLib2(SYS_WIN32, szTlbName, &m_pICreateTLB));
813 // Set the typelib GUID.
814 IfFailReport(GetTypeLibGuidForAssembly(pAssembly, &guid));
815 IfFailReport(m_pICreateTLB->SetGuid(guid));
817 // Retrieve the type library's version number.
819 IfFailReport(GetTypeLibVersionForAssembly(pAssembly, &usMaj, &usMin));
821 // Set the TLB's version number.
822 IfFailReport(m_pICreateTLB->SetVersion(usMaj, usMin));
824 // Set the LCID. If no locale, set to 0, otherwise typelib defaults to 409.
826 LPCUTF8 pLocale = pAssembly->GetLocale();
827 if (pLocale && *pLocale)
829 // Have to build a BSTR, not just a unicode string (i.e. allocate a
830 // DWORD of length information at a negative offset from the string
832 _ASSERTE((sizeof(WCHAR) * 2) == sizeof(DWORD));
833 hr = qLocale.ReSizeNoThrow(sizeof(DWORD));
835 hr = Utf2Quick(pLocale, qLocale, 2);
838 *(DWORD*)qLocale.Ptr() = (DWORD)wcslen(&qLocale.Ptr()[2]);
839 hr = ::CoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, IID_IMultiLanguage, (void**)&pIML);
842 pIML->GetLcidFromRfc1766(&lcid, (BSTR)&qLocale.Ptr()[2]);
844 HRESULT hr2 = m_pICreateTLB->SetLcid(lcid);
845 if (hr2 == TYPE_E_UNKNOWNLCID)
847 ReportWarning(TYPE_E_UNKNOWNLCID, TYPE_E_UNKNOWNLCID);
848 hr2 = m_pICreateTLB->SetLcid(0);
852 // Get the list of types in the assembly.
853 AddAssemblyTypes(pAssembly);
854 m_Exports.InitArray();
856 // Get the assembly value for AutomationProxy.
857 m_bAutomationProxy = DEFAULT_AUTOMATION_PROXY_VALUE;
858 GetAutomationProxyAttribute(pAssembly->GetManifestImport(), TokenFromRid(1, mdtAssembly), &m_bAutomationProxy);
860 // Pre load any caller-specified names into the typelib namespace.
863 // Convert all the types.
864 ConvertAllTypeDefs();
866 // Set library level properties.
867 sName.AppendUTF8(pAssembly->GetSimpleName());
869 // Make it a legal typelib name.
870 SString replaceChar = SL(W("_"));
872 SString::Iterator iter = sName.Begin();
873 while (sName.Find(iter, W(".")))
874 sName.Replace(iter, 1, replaceChar);
876 iter = sName.Begin();
877 while (sName.Find(iter, W(" ")))
878 sName.Replace(iter, 1, replaceChar);
880 IfFailReport(m_pICreateTLB->SetName((LPOLESTR)sName.GetUnicode()));
882 // If the assembly has a description CA, set that as the library Doc string.
883 if (GetStringCustomAttribute(pAssembly->GetManifestImport(), XXX_ASSEMBLY_DESCRIPTION_TYPE, TokenFromRid(mdtAssembly, 1), (BSTR &)szDescription))
884 m_pICreateTLB->SetDocString((LPWSTR)szDescription);
886 // Mark this typelib as exported.
891 pAssembly->GetDisplayName(name);
892 pszFullName = name.GetUnicode();
895 vt.bstrVal = SysAllocString(pszFullName);
896 if (vt.bstrVal == NULL)
897 IfFailReport(E_OUTOFMEMORY);
900 //WszMultiByteToWideChar(CP_ACP,0, (char*)rBuf.Ptr(), (DWORD)rBuf.Size(), vt.bstrVal, (DWORD)rBuf.Size());
901 IfFailReport(m_pICreateTLB->SetCustData(GUID_ExportedFromComPlus, &vt));
903 // Lay out the TypeInfos.
908 SysFreeString(vt.bstrVal);
912 } // HRESULT TypeLibExporter::Convert()
915 void TypeLibExporter::UpdateBitness(Assembly* pAssembly)
919 // If one has already been set, just return.
920 if ((TlbExportAs64Bit(m_flags)) || (TlbExportAs32Bit(m_flags)))
923 // If we are exporting a dynamic assembly, just go with the machine type we're running on.
924 if (pAssembly->IsDynamic())
927 m_flags |= TlbExporter_ExportAs64Bit;
929 m_flags |= TlbExporter_ExportAs32Bit;
934 // Get the assembly info
935 PEFile* pPEFile = pAssembly->GetDomainAssembly()->GetFile();
938 DWORD PEKind, MachineKind;
939 pPEFile->GetPEKindAndMachine(&PEKind, &MachineKind);
941 // Based on the assembly flags, determine a bitness to export with.
942 // Algorithm base copied from ComputeProcArchFlags() in bcl\system\reflection\assembly.cs
943 if ((PEKind & pe32Plus) == pe32Plus)
947 case IMAGE_FILE_MACHINE_IA64:
948 case IMAGE_FILE_MACHINE_AMD64:
949 m_flags |= TlbExporter_ExportAs64Bit;
952 case IMAGE_FILE_MACHINE_I386:
953 if ((PEKind & peILonly) == peILonly)
956 m_flags |= TlbExporter_ExportAs64Bit;
958 m_flags |= TlbExporter_ExportAs32Bit;
963 _ASSERTE(!"Invalid MachineKind / PEKind pair on the assembly!");
968 _ASSERTE(!"Unknown MachineKind!");
971 else if (MachineKind == IMAGE_FILE_MACHINE_I386)
973 if ((PEKind & pe32BitRequired) == pe32BitRequired)
975 m_flags |= TlbExporter_ExportAs32Bit;
977 else if ((PEKind & peILonly) == peILonly)
980 m_flags |= TlbExporter_ExportAs64Bit;
982 m_flags |= TlbExporter_ExportAs32Bit;
987 m_flags |= TlbExporter_ExportAs32Bit;
990 else if (MachineKind == IMAGE_FILE_MACHINE_ARMNT)
992 m_flags |= TlbExporter_ExportAs32Bit;
997 m_flags |= TlbExporter_ExportAs64Bit;
999 m_flags |= TlbExporter_ExportAs32Bit;
1005 // Find out if our assembly / bitness combination is valid.
1006 HRESULT TypeLibExporter::CheckBitness(Assembly* pAssembly)
1008 WRAPPER_NO_CONTRACT;
1010 if (pAssembly->IsDynamic())
1013 PEFile* pPEFile = pAssembly->GetDomainAssembly()->GetFile();
1014 if (pPEFile == NULL)
1015 return TLBX_E_BITNESS_MISMATCH;
1017 DWORD PEKind, MachineKind;
1018 pPEFile->GetPEKindAndMachine(&PEKind, &MachineKind);
1020 // Neutral assembly?
1021 if ((PEKind & peILonly) == peILonly)
1024 if (IsExportingAs64Bit())
1026 if ((MachineKind == IMAGE_FILE_MACHINE_IA64) || (MachineKind == IMAGE_FILE_MACHINE_AMD64))
1031 if ((MachineKind == IMAGE_FILE_MACHINE_I386) || (MachineKind == IMAGE_FILE_MACHINE_ARMNT))
1035 return TLBX_E_BITNESS_MISMATCH;
1039 //*****************************************************************************
1040 //*****************************************************************************
1041 void TypeLibExporter::PreLoadNames()
1043 STANDARD_VM_CONTRACT;
1045 SafeComHolder<ITypeLibExporterNameProvider> pINames = 0;
1046 HRESULT hr = S_OK; // A result.
1047 SafeArrayHolder pNames = 0; // Names provided by caller.
1048 VARTYPE vt; // Type of data.
1049 int lBound, uBound, ix; // Loop control.
1052 // Look for names provider, but don't require it.
1053 hr = SafeQueryInterface(m_pNotify, IID_ITypeLibExporterNameProvider, (IUnknown**)&pINames);
1057 // There is a provider, so get the list of names.
1058 IfFailReport(pINames->GetNames(&pNames));
1060 // Better have a single dimension array of strings.
1062 IfFailReport(TLBX_E_BAD_NAMES);
1064 if (SafeArrayGetDim(pNames) != 1)
1065 IfFailReport(TLBX_E_BAD_NAMES);
1067 IfFailReport(SafeArrayGetVartype(pNames, &vt));
1069 IfFailReport(TLBX_E_BAD_NAMES);
1071 // Get names bounds.
1072 IfFailReport(SafeArrayGetLBound(pNames, 1, (LONG*)&lBound));
1073 IfFailReport(SafeArrayGetUBound(pNames, 1, (LONG*)&uBound));
1075 // Enumerate the names.
1076 for (ix=lBound; ix<=uBound; ++ix)
1078 IfFailReport(SafeArrayGetElement(pNames, (LONG*)&ix, (void*)&name));
1079 m_pICreateTLB->SetName(name);
1083 //*****************************************************************************
1084 //*****************************************************************************
1085 void TypeLibExporter::FormatErrorContextString(
1086 CErrorContext *pContext, // The context to format.
1087 SString *pOut) // Buffer to format into.
1094 PRECONDITION(CheckPointer(pContext));
1095 PRECONDITION(CheckPointer(pOut));
1104 if (pContext->m_prev == 0)
1105 { // No, just convert into caller's buffer.
1109 { // Yes, convert locally, then concatenate.
1114 if (pContext->m_pScope)
1116 // Check whether type is nested (which requires more formatting).
1118 IfFailReport(pContext->m_pScope->GetTypeDefProps(pContext->m_tkType, &dwFlags, 0));
1120 if (IsTdNested(dwFlags))
1122 TypeNameBuilder tnb(pBuf, TypeNameBuilder::ParseStateNAME);
1123 TypeString::AppendNestedTypeDef(tnb, pContext->m_pScope, pContext->m_tkType);
1126 TypeString::AppendTypeDef(*pBuf, pContext->m_pScope, pContext->m_tkType);
1129 if (pContext->m_szMember)
1131 pBuf->Append(NAMESPACE_SEPARATOR_WSTR);
1133 pBuf->AppendUTF8(pContext->m_szMember);
1136 if (pContext->m_szParam)
1138 pBuf->Append(W("("));
1139 pBuf->AppendUTF8(pContext->m_szParam);
1140 pBuf->Append(W(")"));
1142 else if (pContext->m_ixParam > -1)
1144 pBuf->AppendPrintf(W("(#%d)"), pContext->m_ixParam);
1148 pBuf->Append(ASSEMBLY_SEPARATOR_WSTR);
1151 pBuf->AppendUTF8(pContext->m_szAssembly);
1153 // If there is a nested context, put it all together.
1154 if (pContext->m_prev)
1156 // Format the context this one was nested inside.
1158 FormatErrorContextString(pContext->m_prev, &ssOuter);
1160 // Put them together with text.
1161 LPWSTR pUnicodeBuffer = pOut->OpenUnicodeBuffer(1024);
1162 FormatRuntimeError(pUnicodeBuffer, 1024, TLBX_E_CTX_NESTED, pBuf->GetUnicode(), ssOuter.GetUnicode());
1163 pOut->CloseBuffer((COUNT_T)wcslen(pUnicodeBuffer));
1165 } // HRESULT TypeLibExporter::FormatErrorContextString()
1167 //*****************************************************************************
1168 //*****************************************************************************
1169 void TypeLibExporter::FormatErrorContextString(
1170 SString *pBuf) // Buffer to format into.
1177 PRECONDITION(CheckPointer(pBuf));
1181 FormatErrorContextString(&m_ErrorContext, pBuf);
1182 } // HRESULT TypeLibExporter::FormatErrorContextString()
1184 //*****************************************************************************
1185 // Event reporting helper.
1186 //*****************************************************************************
1187 void TypeLibExporter::ReportError(HRESULT hrRpt)
1199 SafeComHolder<IErrorInfo> pErrorInfo;
1200 BSTRHolder bstrDescription = NULL;
1202 // Format the error message.
1203 if (SafeGetErrorInfo(&pErrorInfo) != S_OK)
1206 // If we retrieved and IErrorInfo then retrieve the description.
1209 if (FAILED(pErrorInfo->GetDescription(&bstrDescription)))
1210 bstrDescription = NULL;
1213 if (bstrDescription)
1215 // Use the description as the error message.
1216 wcsncpy_s(rcErr, COUNTOF(rcErr), bstrDescription, _TRUNCATE);
1220 // Format the error message.
1221 FormatRuntimeError(rcErr, lengthof(rcErr), hrRpt);
1224 // Format the context.
1225 FormatErrorContextString(&ssName);
1227 // Post the error to the errorinfo object.
1228 VMPostError(TLBX_E_ERROR_MESSAGE, ssName.GetUnicode(), rcErr);
1230 // Throw the exception, including context info.
1231 COMPlusThrowHR(TLBX_E_ERROR_MESSAGE, kGetErrorInfo);
1232 } // void TypeLibExporter::ReportError()
1234 //*****************************************************************************
1235 // Event reporting helper.
1236 //*****************************************************************************
1237 void TypeLibExporter::ReportEvent( // Returns the original HR.
1238 int ev, // The event kind.
1240 ...) // Variable args.
1242 STANDARD_VM_CONTRACT;
1244 WCHAR rcMsg[1024]; // Buffer for message.
1245 va_list marker; // User text.
1246 BSTRHolder bstrMsg=0; // BSTR for message.
1248 // Format the message.
1249 va_start(marker, hr);
1250 hr = FormatRuntimeErrorVa(rcMsg, lengthof(rcMsg), hr, marker);
1253 // Convert to a BSTR.
1254 bstrMsg = SysAllocString(rcMsg);
1256 // Display it, and clean up.
1257 if (bstrMsg != NULL)
1258 m_pNotify->ReportEvent(static_cast<ImporterEventKind>(ev), hr, bstrMsg);
1260 } // HRESULT CImportTlb::ReportEvent()
1262 //*****************************************************************************
1263 // Warning reporting helper.
1264 //*****************************************************************************
1265 void TypeLibExporter::ReportWarning( // Original error code.
1266 HRESULT hrReturn, // HR to return.
1267 HRESULT hrRpt, // Error code.
1268 ...) // Args to message.
1270 STANDARD_VM_CONTRACT;
1272 WCHAR rcErr[1024]; // Buffer for error message.
1273 SString ssName; // Buffer for context.
1274 va_list marker; // User text.
1275 BSTRHolder bstrMsg=0; // BSTR for message.
1276 BSTRHolder bstrBuf=0; // Buffer for message.
1277 UINT iLen; // Length of allocated buffer.
1279 // Format the message.
1280 va_start(marker, hrRpt);
1281 FormatRuntimeErrorVa(rcErr, lengthof(rcErr), hrRpt, marker);
1284 // Format the context.
1285 FormatErrorContextString(&ssName);
1287 // Put them together.
1288 iLen = (UINT)(wcslen(rcErr) + ssName.GetCount() + 200);
1289 bstrBuf = SysAllocStringLen(0, iLen);
1291 if (bstrBuf != NULL)
1293 FormatRuntimeError(bstrBuf, iLen, TLBX_W_WARNING_MESSAGE, ssName.GetUnicode(), rcErr);
1295 // Have to copy to another BSTR, because the runtime will also print the trash after the
1297 bstrMsg = SysAllocString(bstrBuf);
1299 if (bstrMsg != NULL)
1300 m_pNotify->ReportEvent(NOTIF_CONVERTWARNING, hrRpt, bstrMsg);
1303 } // void TypeLibExporter::ReportWarning()
1305 // Throws exceptions encountered during type exportation.
1306 // Wrapped with ThrowHRWithContext.
1307 void TypeLibExporter::InternalThrowHRWithContext(HRESULT hrRpt, ...)
1309 STANDARD_VM_CONTRACT;
1315 // Format the error message.
1316 va_start(marker, hrRpt);
1317 FormatRuntimeErrorVa(rcErr, lengthof(rcErr), hrRpt, marker);
1320 // Format the context.
1321 FormatErrorContextString(&ssName);
1323 // Post the error to the errorinfo object.
1324 VMPostError(TLBX_E_ERROR_MESSAGE, ssName.GetUnicode(), rcErr);
1326 // Throw the exception, including context info.
1327 COMPlusThrowHR(TLBX_E_ERROR_MESSAGE, kGetErrorInfo);
1328 } // void TypeLibExporter::InternalThrowHRWithContext()
1330 //*****************************************************************************
1331 // Post a class load error on failure.
1332 //*****************************************************************************
1333 void TypeLibExporter::PostClassLoadError(
1334 LPCUTF8 pszName, // Name of the class.
1335 SString& message) // Exception message of class load failure.
1340 PRECONDITION(CheckPointer(pszName));
1344 // See if we got anything back.
1345 if (!message.IsEmpty())
1346 InternalThrowHRWithContext(TLBX_E_CLASS_LOAD_EXCEPTION, pszName, message.GetUnicode());
1348 InternalThrowHRWithContext(TLBX_E_CANT_LOAD_CLASS, pszName);
1349 } // HRESULT TypeLibExporter::PostClassLoadError()
1351 //*****************************************************************************
1352 // Determine the type, if any, of auto-interface for a class.
1353 // May be none, dispatch, or dual.
1354 //*****************************************************************************
1355 void TypeLibExporter::ClassHasIClassX(
1356 MethodTable *pClass, // The class.
1357 CorClassIfaceAttr *pClassItfType) // None, dual, dispatch
1362 PRECONDITION(CheckPointer(pClass));
1363 PRECONDITION(!pClass->IsInterface());
1364 PRECONDITION(CheckPointer(pClassItfType));
1369 ComMethodTable *pClassComMT = NULL;
1371 *pClassItfType = clsIfNone;
1373 // If the class is a COM import or if it isn't COM visible, then from the
1374 // exporter's perspective, it doens't have an IClassX.
1375 if (!pClass->IsComImport())
1377 ComCallWrapperTemplate *pTemplate = ComCallWrapperTemplate::GetTemplate(pClass);
1378 if (pTemplate->SupportsIClassX())
1380 pClassComMT = ComCallWrapperTemplate::SetupComMethodTableForClass(pClass, FALSE);
1381 _ASSERTE(pClassComMT);
1383 if (pClassComMT->IsComVisible())
1384 *pClassItfType = pClassComMT->GetClassInterfaceType();
1387 } // HRESULT TypeLibExporter::ClassHasIClassX()
1389 //*****************************************************************************
1390 // Load a class by token, post an error on failure.
1391 //*****************************************************************************
1392 MethodTable * TypeLibExporter::LoadClass(
1393 Module *pModule, // Module with Loader to use to load the class.
1394 mdToken tk) // The token to load.
1396 CONTRACT(MethodTable *)
1399 PRECONDITION(CheckPointer(pModule));
1400 POSTCONDITION(CheckPointer(RETVAL));
1404 // Get the MethodTable for the token.
1406 SString exceptionMessage;
1410 th = ClassLoader::LoadTypeDefOrRefThrowing(pModule, tk,
1411 ClassLoader::ThrowIfNotFound,
1412 ClassLoader::PermitUninstDefOrRef);
1416 GET_EXCEPTION()->GetMessage(exceptionMessage);
1418 EX_END_CATCH(SwallowAllExceptions);
1422 // Format a hopefully useful error message.
1426 if (TypeFromToken(tk) == mdtTypeDef)
1428 if (FAILED(pModule->GetMDImport()->GetNameOfTypeDef(tk, &pName, &pNS)))
1430 pName = pNS = "Invalid TypeDef record";
1435 _ASSERTE(TypeFromToken(tk) == mdtTypeRef);
1436 if (FAILED(pModule->GetMDImport()->GetNameOfTypeRef(tk, &pNS, &pName)))
1438 pNS = pName = "Invalid TypeRef record";
1444 sName.AppendUTF8(pNS);
1445 sName.AppendUTF8(NAMESPACE_SEPARATOR_STR);
1448 sName.AppendUTF8(pName);
1450 StackScratchBuffer scratch;
1451 PostClassLoadError(sName.GetUTF8(scratch), exceptionMessage);
1454 RETURN (th.AsMethodTable());
1456 } // void TypeLibExporter::LoadClass()
1458 //*****************************************************************************
1459 // Load a class by name, post an error on failure.
1460 //*****************************************************************************
1461 TypeHandle TypeLibExporter::LoadClass(
1462 Module *pModule, // Module with Loader to use to load the class.
1463 LPCUTF8 pszName) // Name of class to load.
1465 CONTRACT(TypeHandle)
1468 PRECONDITION(CheckPointer(pModule));
1469 PRECONDITION(CheckPointer(pszName));
1470 POSTCONDITION(!RETVAL.IsNull());
1475 SString exceptionMessage;
1479 th = TypeName::GetTypeUsingCASearchRules(pszName, pModule->GetAssembly());
1480 _ASSERTE(!th.IsNull());
1484 GET_EXCEPTION()->GetMessage(exceptionMessage);
1486 EX_END_CATCH(SwallowAllExceptions);
1490 PostClassLoadError(pszName, exceptionMessage);
1495 } // void TypeLibExporter::LoadClass()
1498 //*****************************************************************************
1499 // Enumerate the TypeDefs and convert them to TypeInfos.
1500 //*****************************************************************************
1501 void TypeLibExporter::ConvertAllTypeDefs()
1503 STANDARD_VM_CONTRACT;
1505 HRESULT hr = S_OK; // A result.
1506 CExportedTypesInfo *pData; // For iterating the entries.
1507 int cTypes; // Count of types.
1508 int ix; // Loop control.
1510 LPCSTR pName1, pNS1; // Names of a type.
1511 LPCSTR pName2, pNS2; // Names of another type.
1512 MethodTable *pc1; // A Type.
1513 MethodTable *pc2; // Another type.
1514 CQuickArray<BYTE> bNamespace; // Array of flags for namespace decoration.
1516 cTypes = m_Exports.Count();
1518 // If there are no types in the assembly, then we are done.
1522 // Order by name, then look for duplicates.
1523 m_Exports.SortByName();
1525 // Resize the array for namespace flags now, but use the ICreateTypeInfo*, so that
1526 // the flags will be sorted.
1527 bNamespace.ReSizeThrows(cTypes);
1529 // Get names of first type.
1530 pc1 = m_Exports[0]->pClass;
1531 IfFailReport(pc1->GetMDImport()->GetNameOfTypeDef(pc1->GetCl(), &pName1, &pNS1));
1533 // Iterate through the types, looking for duplicate type names.
1534 for (ix=0; ix<cTypes-1; ++ix)
1536 // Get the Type pointers and the types' names.
1537 pc2 = m_Exports[ix+1]->pClass;
1538 IfFailReport(pc2->GetMDImport()->GetNameOfTypeDef(pc2->GetCl(), &pName2, &pNS2));
1540 // If the types match (case insensitive). mark both types for namespace
1542 if (stricmpUTF8(pName1, pName2) == 0)
1544 m_Exports[ix]->pCTI = reinterpret_cast<ICreateTypeInfo2*>(1);
1545 m_Exports[ix+1]->pCTI = reinterpret_cast<ICreateTypeInfo2*>(1);
1548 { // Didn't match, so advance "class 1" pointer.
1555 // Put into token order for actual creation.
1556 m_Exports.SortByToken();
1558 // Fill the flag array, from the ICreateTypeInfo* pointers.
1559 memset(bNamespace.Ptr(), 0, bNamespace.Size()*sizeof(BYTE));
1560 for (ix=0; ix<cTypes; ++ix)
1562 if (m_Exports[ix]->pCTI)
1563 bNamespace[ix] = 1, m_Exports[ix]->pCTI = 0;
1566 // Pass 1. Create the TypeInfos.
1567 // There are four steps in the process:
1568 // a) Creates the TypeInfos for the types themselves. When a duplicate
1569 // is encountered, skip the type until later, so that we don't create
1570 // a decorated name that will conflict with a subsequent non-decorated
1571 // name. We want to preserve a type's given name as much as possible.
1572 // b) Create the TypeInfos for the types that were duplicates in step a.
1573 // Perform decoration of the names as necessary to eliminate duplicates.
1574 // c) Create the TypeInfos for the IClassXs. When there is a duplicate,
1575 // skip, as in step a.
1576 // d) Create the remaining TypeInfos for IClassXs. Perform decoration of
1577 // the names as necessary to eliminate duplicates.
1579 // Step a, Create the TypeInfos for the TypeDefs, no decoration.
1580 for (ix=0; ix<cTypes; ++ix)
1582 int bAutoProxy = m_bAutomationProxy;
1583 pData = m_Exports[ix];
1584 pData->tkind = TKindFromClass(pData->pClass);
1585 GetAutomationProxyAttribute(pData->pClass->GetMDImport(), pData->pClass->GetCl(), &bAutoProxy);
1586 pData->bAutoProxy = (bAutoProxy != 0);
1588 CreateITypeInfo(pData, (bNamespace[ix]!=0), false);
1590 // Step b, Create the TypeInfos for the TypeDefs, decoration as needed.
1591 for (ix=0; ix<cTypes; ++ix)
1593 pData = m_Exports[ix];
1594 if (pData->pCTI == 0)
1595 CreateITypeInfo(pData, (bNamespace[ix]!=0), true);
1598 // Step c, Create the TypeInfos for the IClassX interfaces. No decoration.
1599 for (ix=0; ix<cTypes; ++ix)
1601 pData = m_Exports[ix];
1602 CreateIClassXITypeInfo(pData, (bNamespace[ix]!=0), false);
1604 // Step d, Create the TypeInfos for the IClassX interfaces. Decoration as required.
1605 for (ix=0; ix<cTypes; ++ix)
1607 pData = m_Exports[ix];
1608 if (pData->pCTIClassItf == 0)
1609 CreateIClassXITypeInfo(pData, (bNamespace[ix]!=0), true);
1612 // Pass 2, add the ImplTypes to the CoClasses.
1613 for (ix=0; ix<cTypes; ++ix)
1615 pData = m_Exports[ix];
1616 ConvertImplTypes(pData);
1619 // Pass 3, fill in the TypeInfo details...
1620 for (ix=0; ix<cTypes; ++ix)
1622 pData = m_Exports[ix];
1623 ConvertDetails(pData);
1627 } // void TypeLibExporter::ConvertAllTypeDefs()
1629 //*****************************************************************************
1630 // Convert one TypeDef. Useful for one-off TypeDefs in other scopes where
1631 // that other scope's typelib doesn't contain a TypeInfo. This happens
1632 // for the event information with imported typelibs.
1633 //*****************************************************************************
1634 HRESULT TypeLibExporter::ConvertOneTypeDef(
1635 MethodTable *pClass) // The one class to convert.
1640 PRECONDITION(CheckPointer(pClass));
1644 HRESULT hr = S_OK; // A result.
1645 ICreateTypeInfo2 *pCTI=0; // The TypeInfo to create.
1646 ICreateTypeInfo2 *pDefault=0; // A possible IClassX TypeInfo.
1647 CErrorContext SavedContext; // Previous error context.
1648 CExportedTypesInfo *pExported; // For adding classes to the exported types cache.
1649 CExportedTypesInfo sExported; // For adding classes to the exported types cache.
1651 // Save error reporting context.
1652 SavedContext = m_ErrorContext;
1653 m_ErrorContext.m_szAssembly = pClass->GetAssembly()->GetSimpleName();
1654 m_ErrorContext.m_tkType = mdTypeDefNil;
1655 m_ErrorContext.m_pScope = 0;
1656 m_ErrorContext.m_szMember = 0;
1657 m_ErrorContext.m_szParam = 0;
1658 m_ErrorContext.m_ixParam = -1;
1659 m_ErrorContext.m_prev = &SavedContext;
1661 // See if this class is already in the list.
1662 sExported.pClass = pClass;
1663 pExported = m_InjectedExports.Find(&sExported);
1666 // Get the AutoProxy value for an isolated class.
1667 int bAutoProxy = DEFAULT_AUTOMATION_PROXY_VALUE;
1668 if (FALSE == GetAutomationProxyAttribute(pClass->GetMDImport(), pClass->GetCl(), &bAutoProxy))
1669 GetAutomationProxyAttribute(pClass->GetAssembly()->GetManifestImport(), TokenFromRid(1, mdtAssembly), &bAutoProxy);
1671 // New class, add to list.
1672 if (NULL == (pExported = m_InjectedExports.Add(&sExported)))
1673 IfFailReport(E_OUTOFMEMORY);
1674 m_InjectedExports.UpdateArray();
1676 // Prefix can't tell that IfFailReport will actually throw an exception if pExported is NULL so
1677 // let's tell it explicitly that if we reach this point pExported will not be NULL.
1678 PREFIX_ASSUME(pExported != NULL);
1679 pExported->pClass = pClass;
1680 pExported->pCTI = 0;
1681 pExported->pCTIClassItf = 0;
1682 pExported->tkind = TKindFromClass(pClass);
1683 pExported->bAutoProxy = (bAutoProxy != 0);
1685 // Step 1, Create the TypeInfos for the TypeDefs.
1686 CreateITypeInfo(pExported);
1688 // Step 1a, Create the TypeInfos for the IClassX interfaces.
1689 CreateIClassXITypeInfo(pExported);
1691 // Step 2, add the ImplTypes to the CoClasses.
1692 ConvertImplTypes(pExported);
1694 // Step 3, fill in the TypeInfo details...
1695 ConvertDetails(pExported);
1698 // Restore error reporting context.
1699 m_ErrorContext = SavedContext;
1702 } // HRESULT TypeLibExporter::ConvertOneTypeDef()
1705 //*****************************************************************************
1706 // Create the ITypeInfo for a type. Well, sort of. This function will create
1707 // the first of possibly two typeinfos for the type. If the type is a class
1708 // we will create a COCLASS typeinfo now, and an INTERFACE typeinfo later,
1709 // which typeinfo will be the default interface for the coclass. If this
1710 // typeinfo needs to be aliased, we will create the ALIAS now (with the
1711 // real name) and the aliased typeinfo later, with the real attributes, but
1712 // with a mangled name.
1713 //*****************************************************************************
1714 void TypeLibExporter::CreateITypeInfo(
1715 CExportedTypesInfo *pData, // Conversion data.
1716 bool bNamespace, // If true, use namespace + name
1717 bool bResolveDup) // If true, decorate name to resolve dups.
1722 PRECONDITION(CheckPointer(pData));
1726 HRESULT hr = S_OK; // A result.
1727 LPCUTF8 pName; // Name in UTF8.
1728 LPCUTF8 pNS; // Namespace in UTF8.
1729 SString sName; // Name of the TypeDef.
1730 TYPEKIND tkind; // The TYPEKIND of a TypeDef.
1731 GUID clsid; // A TypeDef's clsid.
1732 DWORD dwFlags; // A TypeDef's flags.
1733 int iSuffix = 0; // Counter for suffix.
1734 mdTypeDef td; // Token for the class.
1736 VariantHolder vt; // For defining custom attribute.
1737 SafeComHolder<ICreateTypeInfo> pCTITemp=0; // For creating a typeinfo.
1738 SafeComHolder<ICreateTypeInfo2> pCTI2=0; // For creating the typeinfo.
1739 SafeComHolder<ITypeLib> pITLB=0; // For dup IID reporting.
1740 SafeComHolder<ITypeInfo> pITIDup=0; // For dup IID reporting.
1741 BSTRHolder bstrDup=0; // For dup IID reporting.
1742 BSTRHolder bstrDescr=0; // For description.
1743 ZeroHolder zhType = &m_ErrorContext.m_pScope; // Clear error reporting info.
1744 CorClassIfaceAttr classItfType = clsIfNone; // For class interface type.
1745 TypeHandle thClass = TypeHandle(pData->pClass); // TypeHandle representing the class.
1747 DefineFullyQualifiedNameForClassW();
1749 // Get the TypeDef and some info about it.
1750 td = pData->pClass->GetCl();
1751 IfFailReport(pData->pClass->GetMDImport()->GetTypeDefProps(td, &dwFlags, 0));
1752 tkind = pData->tkind;
1754 // Error reporting info.
1755 m_ErrorContext.m_tkType = td;
1756 m_ErrorContext.m_pScope = pData->pClass->GetMDImport();
1759 pData->pCTIClassItf = 0;
1761 // If it is ComImport or WindowsRuntimeImport, do not export it.
1762 if (IsTdImport(dwFlags) || pData->pClass->IsProjectedFromWinRT())
1765 // Check to see if the type is supposed to be visible from COM. If it
1766 // is not then we go to the next type.
1767 if (!IsTypeVisibleFromCom(TypeHandle(pData->pClass)))
1770 // Get the GUID for the class. Will generate from name if no defined GUID,
1771 // will also use signatures if interface.
1772 pData->pClass->GetGuid(&clsid, TRUE);
1775 IfFailReport(pData->pClass->GetMDImport()->GetNameOfTypeDef(td, &pName, &pNS));
1777 // Warn about exporting AutoLayout valueclasses
1778 if ( (pData->pClass->IsValueType()) && (!pData->pClass->IsEnum()) && (IsTdAutoLayout(pData->pClass->GetAttrClass())))
1779 ReportWarning(TLBX_W_EXPORTING_AUTO_LAYOUT, TLBX_W_EXPORTING_AUTO_LAYOUT, pName);
1781 // Warn about exporting generic classes.
1782 if (pData->pClass->GetNumGenericArgs() != 0)
1783 ReportWarning(TLBX_I_GENERIC_TYPE, TLBX_I_GENERIC_TYPE);
1785 // Classes that derive from generic classes can be COM visible, however we don't
1786 // expose a class interface for them. Give a warning to the user about this.
1787 if (pData->pClass->HasGenericClassInstantiationInHierarchy())
1789 if (!pData->pClass->IsComImport() && IsTypeVisibleFromCom(thClass))
1791 // Note that we can't call ClassHasIClassX here since it would return
1792 // classIfNone if the type has generic parents in it's hierarchy.
1793 if (ReadClassInterfaceTypeCustomAttribute(thClass) != clsIfNone)
1794 ReportWarning(TLBX_I_GENERIC_BASE_TYPE, TLBX_I_GENERIC_BASE_TYPE);
1798 // Warn about exporting reference types as structs.
1799 if ((pData->tkind == TKIND_RECORD || pData->tkind == TKIND_UNION) && !pData->pClass->IsValueType())
1800 ReportWarning(TLBX_I_REF_TYPE_AS_STRUCT, TLBX_I_REF_TYPE_AS_STRUCT);
1802 // workaround for microsoft.wfc.interop.dll -- skip their IDispatch.
1803 if (clsid == IID_IDispatch || clsid == IID_IUnknown)
1805 ReportEvent(NOTIF_CONVERTWARNING, TLBX_S_NOSTDINTERFACE, pName);
1811 sName.MakeFullNamespacePath(SString(SString::Utf8, pNS), SString(SString::Utf8, pName));
1813 SString replaceChar = SL(W("_"));
1815 SString::Iterator iter = sName.Begin();
1816 while (sName.Find(iter, W(".")))
1817 sName.Replace(iter, 1, replaceChar);
1820 { // Convert name to wide chars.
1821 sName.AppendUTF8(pName);
1824 // Create the typeinfo for this typedef.
1827 // Attempt to create the TypeDef.
1828 hr = m_pICreateTLB->CreateTypeInfo((LPOLESTR)sName.GetUnicode(), tkind, &pCTITemp);
1830 // If a name conflict, decorate, otherwise, done.
1831 if (hr != TYPE_E_NAMECONFLICT)
1846 sName.Delete(sName.End()-=2, 2);
1850 sDup.Printf(szDuplicateDecoration, iSuffix++);
1856 IfFailReport(SafeQueryInterface(pCTITemp, IID_ICreateTypeInfo2, (IUnknown**)&pCTI2));
1859 _ASSERTE(clsid != GUID_NULL);
1860 hr = pCTI2->SetGuid(clsid);
1863 if (hr == TYPE_E_DUPLICATEID)
1865 IfFailReport(SafeQueryInterface(m_pICreateTLB, IID_ITypeLib, (IUnknown**)&pITLB));
1866 IfFailReport(pITLB->GetTypeInfoOfGuid(clsid, &pITIDup));
1867 IfFailReport(pITIDup->GetDocumentation(MEMBERID_NIL, &bstrDup, 0,0,0));
1868 InternalThrowHRWithContext(TLBX_E_DUPLICATE_IID, sName.GetUnicode(), (BSTR)bstrDup);
1872 TRACE("TypeInfo %x: %ls, {%08x-%04x-%04x-%04x-%02x%02x%02x%02x}\n", pCTI2, sName,
1873 clsid.Data1, clsid.Data2, clsid.Data3, clsid.Data4[0]<<8|clsid.Data4[1], clsid.Data4[2], clsid.Data4[3], clsid.Data4[4], clsid.Data4[5]);
1875 IfFailReport(pCTI2->SetVersion(1, 0));
1877 // Record the fully qualified type name in a custom attribute.
1878 // If the TypelibImportClassAttribute exists, use that instead.
1880 hr = GetTypeLibImportClassName(pData->pClass, sName2);
1883 V_BSTR(&vt) = ::SysAllocString(sName2.GetUnicode());
1884 if (V_BSTR(&vt) == NULL)
1885 IfFailReport(E_OUTOFMEMORY);
1887 V_VT(&vt) = VT_BSTR;
1891 // Default to the real name.
1892 LPCWSTR pszName = GetFullyQualifiedNameForClassNestedAwareW(pData->pClass);
1894 V_BSTR(&vt) = ::SysAllocString(pszName);
1895 if (V_BSTR(&vt) == NULL)
1896 IfFailReport(E_OUTOFMEMORY);
1898 V_VT(&vt) = VT_BSTR;
1901 IfFailReport(pCTI2->SetCustData(GUID_ManagedName, &vt));
1903 // If the class is decorated with a description, apply it to the typelib.
1904 if (GetDescriptionString(pData->pClass, td, (BSTR &)bstrDescr))
1905 IfFailReport(pCTI2->SetDocString(bstrDescr));
1907 // Transfer ownership of the pointer.
1908 pData->pCTI = pCTI2;
1909 pCTI2.SuppressRelease();
1911 } // void TypeLibExporter::CreateITypeInfo()
1913 HRESULT TypeLibExporter::GetTypeLibImportClassName(
1924 _ASSERTE(NULL != pClass);
1928 // Check for the presence of the TypelibImportClassAttribute.
1929 const char* pvData; // Pointer to a custom attribute data.
1930 ULONG cbData; // Size of custom attribute data.
1932 hr = pClass->GetMDImport()->GetCustomAttributeByName(pClass->GetCl(),
1933 INTEROP_TYPELIBIMPORTCLASS_TYPE,
1934 reinterpret_cast<const void**>(&pvData),
1937 if (hr == S_OK && cbData > 5 && pvData[0] == 1 && pvData[1] == 0)
1939 CustomAttributeParser cap(pvData, cbData);
1940 VERIFY(SUCCEEDED(cap.ValidateProlog())); // Validated above, just ensure consistency.
1944 if (SUCCEEDED(cap.GetNonNullString(&szString, &cbString)))
1946 // Set the string and null terminate it.
1947 szName.SetUTF8(szString, cbString);
1948 szName.AppendASCII("\0");
1950 // We successfully retrieved the string.
1960 //*****************************************************************************
1961 // See if an object has a Description, and get it as a BSTR.
1962 //*****************************************************************************
1963 BOOL TypeLibExporter::GetDescriptionString(
1964 MethodTable *pClass, // Class containing the token.
1965 mdToken tk, // Token of the object.
1966 BSTR &bstrDescr) // Put description here.
1971 PRECONDITION(CheckPointer(pClass));
1975 // Check for a description custom attribute.
1976 return GetStringCustomAttribute(pClass->GetMDImport(), XXX_DESCRIPTION_TYPE, tk, bstrDescr);
1978 } // HRESULT TypeLibExporter::GetDescriptionString()
1980 //*****************************************************************************
1981 // See if an object has a custom attribute, and get it as a BSTR.
1982 //*****************************************************************************
1983 BOOL TypeLibExporter::GetStringCustomAttribute(
1984 IMDInternalImport *pImport,
1992 PRECONDITION(CheckPointer(pImport));
1993 PRECONDITION(CheckPointer(szName));
1997 HRESULT hr; // A result.
1998 const void *pvData; // Pointer to a custom attribute data.
1999 ULONG cbData; // Size of custom attribute data.
2001 // Look for the desired custom attribute.
2002 IfFailReport(pImport->GetCustomAttributeByName(tk, szName, &pvData,&cbData));
2003 if (hr == S_OK && cbData > 2)
2005 CustomAttributeParser cap(pvData, cbData);
2006 IfFailReport(cap.SkipProlog());
2010 IfFailReport(cap.GetString(&szString, &cbString));
2012 bstrDescr = SysAllocStringLen(0, cbString); // allocates cbString+1 characters (appends '\0')
2013 if (bstrDescr == NULL)
2014 IfFailReport(E_OUTOFMEMORY);
2018 ULONG cch = WszMultiByteToWideChar(CP_UTF8, 0, szString, cbString, bstrDescr, cbString);
2019 bstrDescr[cch] = W('\0');
2026 } // HRESULT GetStringCustomAttribute()
2028 //*****************************************************************************
2029 // Get the value for AutomationProxy for an object. Return the default
2030 // if there is no attribute.
2031 //*****************************************************************************
2032 BOOL TypeLibExporter::GetAutomationProxyAttribute(
2033 IMDInternalImport *pImport,
2040 PRECONDITION(CheckPointer(pImport));
2041 PRECONDITION(CheckPointer(bValue));
2045 HRESULT hr; // A result.
2046 const void *pvData; // Pointer to a custom attribute data.
2047 ULONG cbData; // Size of custom attribute data.
2049 IfFailReport(pImport->GetCustomAttributeByName(tk, INTEROP_AUTOPROXY_TYPE, &pvData, &cbData));
2050 if (hr == S_OK && cbData > 2)
2052 CustomAttributeParser cap(pvData, cbData);
2053 if (FAILED(cap.SkipProlog()))
2057 if (FAILED(cap.GetU1(&u1)))
2067 } // void TypeLibExporter::GetAutomationProxyAttribute()
2069 //*****************************************************************************
2070 // Create the IClassX ITypeInfo.
2071 //*****************************************************************************
2072 void TypeLibExporter::CreateIClassXITypeInfo(
2073 CExportedTypesInfo *pData, // Conversion data.
2074 bool bNamespace, // If true, use namespace + name
2075 bool bResolveDup) // If true, decorate name to resolve dups.
2080 PRECONDITION(CheckPointer(pData));
2084 HRESULT hr = S_OK; // A result.
2085 LPCUTF8 pName; // Name in UTF8.
2086 LPCUTF8 pNS; // Namespace in UTF8.
2087 SString sName; // Name of the TypeDef.
2088 SString sNameTypeInfo; // Name of the IClassX.
2089 TYPEKIND tkind; // The TYPEKIND of a TypeDef.
2090 GUID clsid; // A TypeDef's clsid.
2091 DWORD dwFlags; // A TypeDef's flags.
2092 LPWSTR pSuffix; // Pointer into the name.
2093 int iSuffix = 0; // Counter for suffix.
2094 GUID guid = {0}; // A default interface's IID.
2095 HREFTYPE href; // href of base interface of IClassX.
2096 mdTypeDef td; // Token for the class.
2097 CorClassIfaceAttr classItfType = clsIfNone; // For class interface type.
2099 VariantHolder vt; // For defining custom attribute.
2100 SafeComHolder<ICreateTypeInfo> pCTITemp=0; // For creating a typeinfo.
2101 SafeComHolder<ITypeInfo> pITemp=0; // An ITypeInfo to get a name.
2102 SafeComHolder<ITypeLib> pITLB=0; // For dup IID reporting.
2103 SafeComHolder<ITypeInfo> pITIDup=0; // For dup IID reporting.
2104 SafeComHolder<ICreateTypeInfo2> pCTI2=0; // For creating the typeinfo.
2105 BSTRHolder bstrName=0; // An ITypeInfo's name.
2106 BSTRHolder bstrDescr=0; // For description.
2107 BSTRHolder bstrDup=0; // For dup IID reporting.
2108 ZeroHolder zhType = &m_ErrorContext.m_pScope; // Clear error reporting info.
2110 MethodTable* pClassOuter = pData->pClass;
2112 DefineFullyQualifiedNameForClassW();
2114 // Get the TypeDef and some info about it.
2115 td = pData->pClass->GetCl();
2116 IfFailReport(pData->pClass->GetMDImport()->GetTypeDefProps(td, &dwFlags, 0));
2117 tkind = pData->tkind;
2119 // Error reporting info.
2120 m_ErrorContext.m_tkType = td;
2121 m_ErrorContext.m_pScope = pData->pClass->GetMDImport();
2123 // A CoClass needs an IClassX, and an alias kind needs an alias.
2124 if (tkind != TKIND_COCLASS)
2127 // Check to see if the type is supposed to be visible from COM. If it
2128 // is not then we go to the next type.
2129 if (!IsTypeVisibleFromCom(TypeHandle(pClassOuter)))
2132 // Imported types don't need an IClassX.
2133 if (IsTdImport(dwFlags))
2136 // Check to see if we need to set up an IClassX for the class.
2137 ClassHasIClassX(pData->pClass, &classItfType);
2138 if (classItfType == clsIfNone)
2141 // Get full name from metadata.
2142 IfFailReport(pData->pClass->GetMDImport()->GetNameOfTypeDef(td, &pName, &pNS));
2144 // Get the GUID for the class. Used to generate IClassX guid.
2145 pData->pClass->GetGuid(&clsid, TRUE);
2147 // Get the name of the class. Use the ITypeInfo if there is one, except don't
2148 // use the typeinfo for types which are Aliased.
2151 IfFailReport(SafeQueryInterface(pData->pCTI, IID_ITypeInfo, (IUnknown**)&pITemp));
2152 IfFailReport(pITemp->GetDocumentation(MEMBERID_NIL, &bstrName, 0,0,0));
2153 sName.Append(bstrName);
2157 sName.AppendUTF8(pName);
2160 // Create the typeinfo name for the IClassX
2161 sNameTypeInfo.Set(cIClassX);
2162 sNameTypeInfo.Append(sName);
2164 tkind = TKIND_INTERFACE;
2168 // Try to create the TypeInfo.
2169 hr = m_pICreateTLB->CreateTypeInfo((LPOLESTR)sNameTypeInfo.GetUnicode(), tkind, &pCTITemp);
2171 // If a name conflict, decorate, otherwise, done.
2172 if (hr != TYPE_E_NAMECONFLICT)
2187 sNameTypeInfo.Delete(sNameTypeInfo.End()-=2, 2);
2191 sDup.Printf(szDuplicateDecoration, iSuffix++);
2193 sNameTypeInfo.Append(sDup);
2197 IfFailReport(SafeQueryInterface(pCTITemp, IID_ICreateTypeInfo2, (IUnknown**)&pCTI2));
2199 // Generate the "IClassX" UUID and set it.
2200 GenerateClassItfGuid(TypeHandle(pData->pClass), &guid);
2201 hr = pCTI2->SetGuid(guid);
2204 if (hr == TYPE_E_DUPLICATEID)
2206 IfFailReport(SafeQueryInterface(m_pICreateTLB, IID_ITypeLib, (IUnknown**)&pITLB));
2207 IfFailReport(pITLB->GetTypeInfoOfGuid(guid, &pITIDup));
2208 IfFailReport(pITIDup->GetDocumentation(MEMBERID_NIL, &bstrDup, 0,0,0));
2209 InternalThrowHRWithContext(TLBX_E_DUPLICATE_IID, sNameTypeInfo.GetUnicode(), (BSTR)bstrDup);
2214 // Adding methods may cause an href to this typeinfo, which will cause it to be layed out.
2215 // Set the inheritance, so that nesting will be correct when that layout happens.
2216 // Add IDispatch as impltype 0.
2217 GetRefTypeInfo(pCTI2, m_pIDispatch, &href);
2218 IfFailReport(pCTI2->AddImplType(0, href));
2220 // Record the fully qualified type name in a custom attribute.
2221 LPCWSTR szName = GetFullyQualifiedNameForClassNestedAwareW(pData->pClass);
2222 V_VT(&vt) = VT_BSTR;
2223 V_BSTR(&vt) = SysAllocString(szName);
2224 if (V_BSTR(&vt) == NULL)
2225 IfFailReport(E_OUTOFMEMORY);
2227 IfFailReport(pCTI2->SetCustData(GUID_ManagedName, &vt));
2229 TRACE("IClassX %x: %ls, {%08x-%04x-%04x-%04x-%02x%02x%02x%02x}\n", pCTI2, sName,
2230 guid.Data1, guid.Data2, guid.Data3, guid.Data4[0]<<8|guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5]);
2232 // If the class is decorated with a description, apply it to the typelib.
2233 if(GetDescriptionString(pData->pClass, td, (BSTR &)bstrDescr))
2234 IfFailReport(pCTI2->SetDocString(bstrDescr));
2236 // Transfer ownership of the pointer.
2237 _ASSERTE(pData->pCTIClassItf == 0);
2238 pData->pCTIClassItf = pCTI2;
2239 pCTI2.SuppressRelease();
2241 } // HRESULT TypeLibExporter::CreateIClassXITypeInfo()
2243 //*****************************************************************************
2244 // Add the impltypes to an ITypeInfo.
2245 //*****************************************************************************
2246 void TypeLibExporter::ConvertImplTypes(
2247 CExportedTypesInfo *pData) // Conversion data.
2252 PRECONDITION(CheckPointer(pData));
2256 HRESULT hr = S_OK; // A result.
2257 DWORD dwFlags; // A TypeDef's flags.
2258 mdTypeDef td; // Token for the class.
2259 ZeroHolder zhType = &m_ErrorContext.m_pScope; // Clear error reporting info.
2261 // Get the TypeDef and some info about it.
2262 td = pData->pClass->GetCl();
2263 IfFailReport(pData->pClass->GetMDImport()->GetTypeDefProps(td, &dwFlags, 0));
2265 // Error reporting info.
2266 m_ErrorContext.m_tkType = td;
2267 m_ErrorContext.m_pScope = pData->pClass->GetMDImport();
2269 // If there is no ITypeInfo, skip it.
2270 if (pData->pCTI == 0)
2273 // Check to see if the type is supposed to be visible from COM. If it
2274 // is not then we go to the next type.
2275 if (!IsTypeVisibleFromCom(TypeHandle(pData->pClass)))
2278 // Add the ImplTypes to the CoClass.
2279 switch (pData->tkind)
2281 case TKIND_INTERFACE:
2282 case TKIND_DISPATCH:
2283 // Add the base type to the interface.
2284 ConvertInterfaceImplTypes(pData->pCTI, pData->pClass);
2290 // Nothing to do at this step.
2294 // Add the ImplTypes to the CoClass.
2295 ConvertClassImplTypes(pData->pCTI, pData->pCTIClassItf, pData->pClass);
2299 _ASSERTE(!"Unknown TYPEKIND");
2300 IfFailReport(E_INVALIDARG);
2303 } // HRESULT TypeLibExporter::ConvertImplTypes()
2305 //*****************************************************************************
2306 // Convert the details (members) of an ITypeInfo.
2307 //*****************************************************************************
2308 void TypeLibExporter::ConvertDetails(
2309 CExportedTypesInfo *pData) // Conversion data.
2314 PRECONDITION(CheckPointer(pData));
2318 HRESULT hr = S_OK; // A result.
2319 DWORD dwFlags; // A TypeDef's flags.
2320 mdTypeDef td; // Token for the class.
2321 ZeroHolder zhType = &m_ErrorContext.m_pScope; // Clear error reporting info.
2323 // Get the TypeDef and some info about it.
2324 td = pData->pClass->GetCl();
2325 IfFailReport(pData->pClass->GetMDImport()->GetTypeDefProps(td, &dwFlags, 0));
2327 // Error reporting info.
2328 m_ErrorContext.m_tkType = td;
2329 m_ErrorContext.m_pScope = pData->pClass->GetMDImport();
2331 // If there is no TypeInfo, skip it, but for CoClass need to populate IClassX.
2332 if (pData->pCTI == 0 && pData->tkind != TKIND_COCLASS)
2335 // Check to see if the type is supposed to be visible from COM. If it
2336 // is not then we go to the next type.
2337 if (!IsTypeVisibleFromCom(TypeHandle(pData->pClass)))
2340 // Fill in the rest of the typeinfo for this typedef.
2341 switch (pData->tkind)
2343 case TKIND_INTERFACE:
2344 case TKIND_DISPATCH:
2345 ConvertInterfaceDetails(pData->pCTI, pData->pClass, pData->bAutoProxy);
2350 ConvertRecord(pData);
2354 ConvertEnum(pData->pCTI, pData->pClass);
2358 // Populate the methods on the IClassX interface.
2359 ConvertClassDetails(pData->pCTI, pData->pCTIClassItf, pData->pClass, pData->bAutoProxy);
2363 _ASSERTE(!"Unknown TYPEKIND");
2364 IfFailReport(E_INVALIDARG);
2368 // Report that this type has been converted.
2370 if (IsTdNested(dwFlags))
2372 TypeNameBuilder tnb(&ssType, TypeNameBuilder::ParseStateNAME);
2373 TypeString::AppendNestedTypeDef(tnb, m_ErrorContext.m_pScope, m_ErrorContext.m_tkType);
2376 TypeString::AppendTypeDef(ssType, m_ErrorContext.m_pScope, m_ErrorContext.m_tkType);
2377 ReportEvent(NOTIF_TYPECONVERTED, TLBX_I_TYPE_EXPORTED, ssType.GetUnicode());
2378 } // void TypeLibExporter::ConvertDetails()
2380 //*****************************************************************************
2381 // Add the ImplTypes to the TypeInfo.
2382 //*****************************************************************************
2383 void TypeLibExporter::ConvertInterfaceImplTypes(
2384 ICreateTypeInfo2 *pThisTypeInfo, // The typeinfo being created.
2385 MethodTable *pClass) // MethodTable for the TypeInfo.
2390 PRECONDITION(CheckPointer(pThisTypeInfo));
2391 PRECONDITION(CheckPointer(pClass));
2396 ULONG ulIface; // Is this interface [dual]?
2397 HREFTYPE href; // href of base interface.
2399 // IDispatch or IUnknown derived?
2400 IfFailReport(pClass->GetMDImport()->GetIfaceTypeOfTypeDef(pClass->GetCl(), &ulIface));
2402 // Parent interface.
2403 if (IsDispatchBasedItf((CorIfaceAttr)ulIface))
2405 // Get the HREFTYPE for IDispatch.
2406 GetRefTypeInfo(pThisTypeInfo, m_pIDispatch, &href);
2410 // Get the HREFTYPE for IUnknown.
2411 GetRefTypeInfo(pThisTypeInfo, m_pIUnknown, &href);
2414 // Add the HREF as an interface.
2415 IfFailReport(pThisTypeInfo->AddImplType(0, href));
2416 } // void TypeLibExporter::ConvertInterfaceImplTypes()
2419 //*****************************************************************************
2420 // Create the TypeInfo for an interface by iterating over functions.
2421 //*****************************************************************************
2422 void TypeLibExporter::ConvertInterfaceDetails (
2423 ICreateTypeInfo2 *pThisTypeInfo, // The typeinfo being created.
2424 MethodTable *pMT, // MethodTable for the TypeInfo.
2425 int bAutoProxy) // If true, oleaut32 is the interface's marshaller.
2430 PRECONDITION(CheckPointer(pThisTypeInfo));
2431 PRECONDITION(CheckPointer(pMT));
2436 ULONG ulIface; // Is this interface [dual]?
2437 DWORD dwTIFlags=0; // TypeLib flags.
2438 int cVisibleMembers = 0; // The count of methods that are visible to COM.
2440 // Retrieve the map of members.
2441 ComMTMemberInfoMap MemberMap(pMT);
2443 // IDispatch or IUnknown derived?
2444 IfFailReport(pMT->GetMDImport()->GetIfaceTypeOfTypeDef(pMT->GetCl(), &ulIface));
2446 if (IsDispatchBasedItf((CorIfaceAttr)ulIface))
2448 // IDispatch derived.
2449 dwTIFlags |= TYPEFLAG_FDISPATCHABLE;
2451 if (ulIface == ifDual)
2452 dwTIFlags |= TYPEFLAG_FDUAL | TYPEFLAG_FOLEAUTOMATION;
2454 _ASSERTE(ulIface == ifDispatch);
2458 // IUnknown derived.
2459 dwTIFlags |= TYPEFLAG_FOLEAUTOMATION;
2463 dwTIFlags |= TYPEFLAG_FPROXY;
2465 // Set appropriate flags.
2466 IfFailReport(pThisTypeInfo->SetTypeFlags(dwTIFlags));
2468 // Retrieve the method properties.
2469 size_t sizeOfPtr = IsExportingAs64Bit() ? 8 : 4;
2471 MemberMap.Init(sizeOfPtr);
2472 if (MemberMap.HadDuplicateDispIds())
2473 ReportWarning(TLBX_I_DUPLICATE_DISPID, TLBX_I_DUPLICATE_DISPID);
2475 // We need a scope to bypass the inialization skipped by goto ErrExit
2478 CQuickArray<ComMTMethodProps> &rProps = MemberMap.GetMethods();
2480 // Now add the methods to the TypeInfo.
2481 MethodTable::MethodIterator it(pMT);
2482 for (; it.IsValid(); it.Next())
2486 // Only convert the method if it is visible from COM.
2487 if (rProps[it.GetSlotNumber()].bMemberVisible)
2489 if (ConvertMethod(pThisTypeInfo, &rProps[it.GetSlotNumber()], cVisibleMembers, ulIface))
2495 } // void TypeLibExporter::ConvertInterfaceDetails()
2497 //*****************************************************************************
2498 // Export a Record to a TypeLib.
2499 //*****************************************************************************
2500 void TypeLibExporter::ConvertRecordBaseClass(
2501 CExportedTypesInfo *pData, // Conversion data.
2502 MethodTable *pSubMT, // The base class.
2503 ULONG &ixVar) // Variable index in the typelib.
2508 PRECONDITION(CheckPointer(pData));
2509 PRECONDITION(CheckPointer(pSubMT));
2513 // The typeinfo being created.
2514 ICreateTypeInfo2 *pThisTypeInfo = pData->pCTI;
2516 HRESULT hr = S_OK; // A result.
2517 mdFieldDef fd; // A Field def.
2518 ULONG iFD; // Loop control.
2519 ULONG cFD; // Count of total MemberDefs.
2520 DWORD dwFlags; // Field flags.
2521 LPCUTF8 szName; // Name in UTF8.
2522 LPCUTF8 szNamespace; // A Namespace in UTF8.
2523 SString sName; // Name
2526 HENUMInternalHolder eFDi(pSubMT->GetMDImport());
2528 // If there is no class here, or if the class is Object, don't add members.
2530 pSubMT == g_pObjectClass)
2533 // If this class has a base class, export those members first.
2534 ConvertRecordBaseClass(pData, pSubMT->GetParentMethodTable(), ixVar);
2536 // Build the member name prefix.
2537 IfFailReport(pSubMT->GetMDImport()->GetNameOfTypeDef(pSubMT->GetCl(), &szName, &szNamespace));
2539 sName.SetUTF8(szName);
2540 sName.Append(W("_"));
2542 // Get an enumerator for the MemberDefs in the TypeDef.
2543 eFDi.EnumInit(mdtFieldDef, pSubMT->GetCl());
2544 cFD = pSubMT->GetMDImport()->EnumGetCount(&eFDi);
2546 SString sNameMember;
2547 // For each MemberDef...
2548 for (iFD=0; iFD<cFD; ++iFD)
2550 // Get the next field.
2551 if (!pSubMT->GetMDImport()->EnumNext(&eFDi, &fd))
2553 IfFailReport(E_UNEXPECTED);
2556 IfFailReport(pSubMT->GetMDImport()->GetFieldDefProps(fd, &dwFlags));
2558 // Only non-static fields.
2559 if (!IsFdStatic(dwFlags))
2561 IfFailReport(pSubMT->GetMDImport()->GetNameOfFieldDef(fd, &szName));
2563 sNameMember.Set(sName);
2564 sNameMember.AppendUTF8(szName);
2565 if (ConvertVariable(pThisTypeInfo, pSubMT, fd, sNameMember, ixVar))
2569 } // void TypeLibExporter::ConvertRecordBaseClass()
2571 void TypeLibExporter::ConvertRecord(
2572 CExportedTypesInfo *pData) // Conversion data.
2577 PRECONDITION(CheckPointer(pData));
2581 ICreateTypeInfo2 *pThisTypeInfo=pData->pCTI; // The typeinfo being created.
2582 MethodTable *pMT=pData->pClass; // MethodTable for the TypeInfo.
2584 HRESULT hr = S_OK; // A result.
2585 mdFieldDef fd; // A Field def.
2586 ULONG iFD; // Loop control.
2587 ULONG ixVar=0; // Index of current var converted.
2588 ULONG cFD; // Count of total MemberDefs.
2589 DWORD dwFlags; // Field flags.
2590 DWORD dwPack; // Class pack size.
2591 mdToken tkExtends; // A class's parent.
2592 LPCUTF8 szName; // Name in UTF8.
2593 SString sName; // Name.
2596 HENUMInternalHolder eFDi(pMT->GetMDImport());
2598 // If the type is a struct, but it has explicit layout, don't export the members,
2599 // because we can't export them accurately (unless they're really sequential).
2600 if (pData->tkind == TKIND_RECORD)
2602 IfFailReport(pMT->GetMDImport()->GetTypeDefProps(pMT->GetCl(), &dwFlags, &tkExtends));
2604 if (IsTdExplicitLayout(dwFlags))
2606 ReportWarning(S_OK, TLBX_I_NONSEQUENTIALSTRUCT);
2611 // Set the packing size, if there is one.
2613 if (FAILED(pMT->GetMDImport()->GetClassPackSize(pMT->GetCl(), &dwPack)))
2619 dwPack = DEFAULT_PACKING_SIZE;
2622 IfFailReport(pThisTypeInfo->SetAlignment((USHORT)dwPack));
2624 // Haven't seen any non-public members yet.
2625 m_bWarnedOfNonPublic = FALSE;
2627 // If this class has a base class, export those members first.
2628 ConvertRecordBaseClass(pData, pMT->GetParentMethodTable(), ixVar);
2630 // Get an enumerator for the MemberDefs in the TypeDef.
2631 eFDi.EnumInit(mdtFieldDef, pMT->GetCl());
2632 cFD = pMT->GetMDImport()->EnumGetCount(&eFDi);
2634 // For each MemberDef...
2635 for (iFD=0; iFD<cFD; ++iFD)
2637 // Get the next field.
2638 if (!pMT->GetMDImport()->EnumNext(&eFDi, &fd))
2640 IfFailReport(E_UNEXPECTED);
2643 IfFailReport(pMT->GetMDImport()->GetFieldDefProps(fd, &dwFlags));
2645 // Skip static fields.
2646 if (IsFdStatic(dwFlags) == 0)
2648 IfFailReport(pMT->GetMDImport()->GetNameOfFieldDef(fd, &szName));
2650 sName.SetUTF8(szName);
2651 if (ConvertVariable(pThisTypeInfo, pMT, fd, sName, ixVar))
2655 } // HRESULT TypeLibExporter::ConvertRecord()
2657 //*****************************************************************************
2658 // Export an Enum to a typelib.
2659 //*****************************************************************************
2660 void TypeLibExporter::ConvertEnum(
2661 ICreateTypeInfo2 *pThisTypeInfo, // The typeinfo being created.
2662 MethodTable *pMT) // MethodTable for the TypeInfo.
2667 PRECONDITION(CheckPointer(pThisTypeInfo));
2668 PRECONDITION(CheckPointer(pMT));
2672 HRESULT hr = S_OK; // A result.
2673 mdFieldDef fd; // A Field def.
2674 DWORD dwTIFlags=0; // TypeLib flags.
2675 ULONG dwFlags; // A field's flags.
2676 ULONG iFD; // Loop control.
2677 ULONG cFD; // Count of total MemberDefs.
2678 ULONG iVar=0; // Count of vars actually converted.
2679 LPCUTF8 szName; // Name in UTF8.
2680 SString sName; // Name.
2681 SafeComHolder<ITypeInfo> pThisTI=0; // TypeInfo for this ICreateITypeInfo.
2682 BSTRHolder szThisTypeInfo=0; // Name of this ITypeInfo.
2684 IMDInternalImport* pImport = pMT->GetMDImport();
2687 HENUMInternalHolder eFDi(pImport);
2689 // Explicitly set the flags.
2690 IfFailReport(pThisTypeInfo->SetTypeFlags(dwTIFlags));
2692 // Get an enumerator for the MemberDefs in the TypeDef.
2693 eFDi.EnumInit(mdtFieldDef, pMT->GetCl());
2694 cFD = pImport->EnumGetCount(&eFDi);
2696 // Build the member name prefix. If generating an enum, get the real name from the default interface.
2697 IfFailReport(SafeQueryInterface(pThisTypeInfo, IID_ITypeInfo, (IUnknown**)&pThisTI));
2698 IfFailReport(pThisTI->GetDocumentation(MEMBERID_NIL, &szThisTypeInfo, 0,0,0));
2700 sName.Set(szThisTypeInfo);
2701 sName.Append(W("_"));
2703 SString sNameMember;
2704 // For each MemberDef...
2705 for (iFD=0; iFD<cFD; ++iFD)
2707 // Get the next field.
2708 if (!pImport->EnumNext(&eFDi, &fd))
2710 IfFailReport(E_UNEXPECTED);
2713 // Only convert static fields.
2714 IfFailReport(pImport->GetFieldDefProps(fd, &dwFlags));
2716 if (IsFdStatic(dwFlags) == 0)
2721 // Skip ComVisible(false) members
2722 if (!IsMemberVisibleFromCom(pMT, fd, mdTokenNil))
2727 sNameMember.Set(sName);
2728 IfFailReport(pImport->GetNameOfFieldDef(fd, &szName));
2730 sNameMember.AppendUTF8(szName);
2732 if (ConvertEnumMember(pThisTypeInfo, pMT, fd, sNameMember, iVar))
2737 } // void TypeLibExporter::ConvertEnum()
2739 //*****************************************************************************
2740 // Does a class have a default ctor?
2741 //*****************************************************************************
2742 BOOL TypeLibExporter::HasDefaultCtor(
2743 MethodTable *pMT) // The class in question.
2748 PRECONDITION(CheckPointer(pMT));
2752 HRESULT hr; // A result.
2753 mdMethodDef md; // A method of the type.
2754 DWORD dwFlags; // Method's flags.
2755 ULONG cMD; // Count of returned tokens.
2756 ULONG iMD; // Loop control.
2757 PCCOR_SIGNATURE pSig; // The signature.
2758 ULONG ixSig; // Index into signature.
2759 ULONG cbSig; // Size of the signature.
2760 ULONG callconv; // Method's calling convention.
2761 ULONG cParams; // Method's count of parameters.
2762 BOOL rslt=FALSE; // Was one found?
2763 LPCUTF8 pName; // Method name.
2765 IMDInternalImport* pImport = pMT->GetMDImport();
2768 HENUMInternalHolder eMDi(pImport);
2770 // Get an enumerator for the MemberDefs in the TypeDef.
2771 eMDi.EnumInit(mdtMethodDef, pMT->GetCl());
2772 cMD = pImport->EnumGetCount(&eMDi);
2774 // For each MemberDef...
2775 for (iMD=0; iMD<cMD; ++iMD)
2777 // Get the next field.
2778 if (!pImport->EnumNext(&eMDi, &md))
2780 IfFailReport(E_UNEXPECTED);
2783 // Is the name special? Is the method public?
2784 IfFailReport(pImport->GetMethodDefProps(md, &dwFlags));
2786 if (!IsMdRTSpecialName(dwFlags) || !IsMdPublic(dwFlags))
2789 // Yes, is the name a ctor?
2790 IfFailReport(pImport->GetNameOfMethodDef(md, &pName));
2792 if (!IsMdInstanceInitializer(dwFlags, pName))
2795 // It is a ctor. Is it a default ctor?
2796 IfFailReport(pImport->GetSigOfMethodDef(md, &cbSig, &pSig));
2798 // Skip the calling convention, and get the param count.
2799 ixSig = CorSigUncompressData(pSig, &callconv);
2800 CorSigUncompressData(&pSig[ixSig], &cParams);
2802 // Default ctor has zero params.
2811 } // BOOL TypeLibExporter::HasDefaultCtor()
2813 //*****************************************************************************
2814 // Export a class to a TypeLib.
2815 //*****************************************************************************
2816 void TypeLibExporter::ConvertClassImplTypes(
2817 ICreateTypeInfo2 *pThisTypeInfo, // The typeinfo being created.
2818 ICreateTypeInfo2 *pClassItfTypeInfo,// The ICLassX for the TypeInfo.
2819 MethodTable *pMT) // MethodTable for the TypeInfo.
2824 PRECONDITION(CheckPointer(pThisTypeInfo, NULL_OK));
2825 PRECONDITION(CheckPointer(pClassItfTypeInfo, NULL_OK));
2826 PRECONDITION(CheckPointer(pMT));
2831 HREFTYPE href; // HREF to a TypeInfo.
2832 DWORD dwFlags; // Metadata flags.
2833 int flags=0; // Flags for the interface impl or CoClass.
2834 UINT iImpl=0; // Current Impl index.
2835 MethodTable *pIDefault = 0; // Default interface, if any.
2836 MethodTable *pDefItfMT = 0; // Default interface method table, if any.
2837 CQuickArray<MethodTable *> SrcItfList; // List of event sources.
2838 CorClassIfaceAttr classItfType = clsIfNone; // For class interface type.
2839 DefaultInterfaceType DefItfType;
2840 TypeHandle hndDefItfClass;
2842 SafeComHolder<ITypeInfo> pTI=0; // TypeInfo for default dispinterface.
2843 SafeComHolder<ICreateTypeInfo2> pCTI2 = NULL; // The ICreateTypeInfo2 interface used to define custom data.
2845 // We should never be converting the class impl types of COM imported CoClasses.
2846 _ASSERTE(!pMT->IsComImport());
2850 IfFailReport(pMT->GetMDImport()->GetTypeDefProps(pMT->GetCl(), &dwFlags, 0));
2852 // If abstract class, or no default ctor, don't make it creatable.
2853 if (!IsTdAbstract(dwFlags) && HasDefaultCtor(pMT))
2854 flags |= TYPEFLAG_FCANCREATE;
2856 // PreDeclid as appropriate.
2857 IfFailReport(pThisTypeInfo->SetTypeFlags(flags));
2860 // Retrieve the MethodTable that represents the default interface.
2861 DefItfType = GetDefaultInterfaceForClassWrapper(TypeHandle(pMT), &hndDefItfClass);
2863 // Remember the MethodTable of the default interface.
2864 pIDefault = hndDefItfClass.GetMethodTable();
2866 // For some classes we synthesize an IClassX. We don't do that for
2867 // configured class, classes imported from COM,
2868 // or for classes with an explicit default interface.
2869 if (pClassItfTypeInfo)
2871 // Set the interface as the default for the class.
2872 IfFailReport(SafeQueryInterface(pClassItfTypeInfo, IID_ITypeInfo, (IUnknown**)&pTI));
2873 GetRefTypeInfo(pThisTypeInfo, pTI, &href);
2874 IfFailReport(pThisTypeInfo->AddImplType(iImpl, href));
2876 // If the class interface is the default interface, mark it as such.
2877 if (pMT == pIDefault)
2878 IfFailReport(pThisTypeInfo->SetImplTypeFlags(iImpl, IMPLTYPEFLAG_FDEFAULT));
2880 // Increment the impl count.
2884 // Go up the class hierarchy and add the IClassX's of the parent classes
2885 // as interfaces implemented by the COM component.
2886 MethodTable *pParentClass = pMT->GetComPlusParentMethodTable();
2887 while (pParentClass)
2889 // If the parent class has an IClassX interface then add it.
2890 ClassHasIClassX(pParentClass, &classItfType);
2891 if (classItfType == clsIfAutoDual)
2893 hr = EEClassToHref(pThisTypeInfo, pParentClass, FALSE, &href);
2895 // If not IUnknown, add the HREF as an interface.
2896 if (hr != S_USEIUNKNOWN)
2898 IfFailReport(pThisTypeInfo->AddImplType(iImpl, href));
2899 if (pParentClass == pIDefault)
2900 IfFailReport(pThisTypeInfo->SetImplTypeFlags(iImpl, IMPLTYPEFLAG_FDEFAULT));
2906 // Process the next class up the hierarchy.
2907 pParentClass = pParentClass->GetComPlusParentMethodTable();
2910 ComCallWrapperTemplate *pClassTemplate = ComCallWrapperTemplate::GetTemplate(TypeHandle(pMT));
2911 MethodTable::InterfaceMapIterator it = pMT->IterateInterfaceMap();
2916 // Get the MethodTable for an implemented interface.
2917 MethodTable *pIClass = it.GetInterface();
2919 // Retrieve the ComMethodTable for the interface.
2920 ComMethodTable *pItfComMT = pClassTemplate->GetComMTForItf(pIClass);
2922 // If the interface is visible from COM, add it.
2923 if (IsTypeVisibleFromCom(TypeHandle(pIClass)) && !pItfComMT->IsComClassItf())
2926 TRACE("Class %s implements %s\n", pMT->GetDebugClassName(), pIClass->GetDebugClassName());
2928 // Get an href for the managed class.
2929 hr = EEClassToHref(pThisTypeInfo, pIClass, FALSE, &href);
2931 // If not IUnknown, add the HREF as an interface.
2932 if (hr != S_USEIUNKNOWN)
2934 if (pIClass == pIDefault)
2935 flags |= IMPLTYPEFLAG_FDEFAULT;
2937 IfFailReport(pThisTypeInfo->AddImplType(iImpl, href));
2938 IfFailReport(pThisTypeInfo->SetImplTypeFlags(iImpl, flags));
2942 else if (!IsTypeVisibleFromCom(TypeHandle(pIClass)) && (pIClass == pIDefault))
2944 // Report a warning if the default interface is not COM visible
2945 ReportWarning(TLBX_W_DEFAULT_INTF_NOT_VISIBLE, TLBX_W_DEFAULT_INTF_NOT_VISIBLE);
2949 // Retrieve the list of COM source interfaces for the managed class.
2950 GetComSourceInterfacesForClass(pMT, SrcItfList);
2952 // Add all the source interfaces to the CoClass.
2953 flags = IMPLTYPEFLAG_FSOURCE | IMPLTYPEFLAG_FDEFAULT;
2954 for (UINT i = 0; i < SrcItfList.Size(); i++)
2956 hr = EEClassToHref(pThisTypeInfo, SrcItfList[i], FALSE, &href);
2958 // If not IUnknown, add the HREF as an interface.
2959 if (hr != S_USEIUNKNOWN)
2961 IfFailReport(pThisTypeInfo->AddImplType(iImpl, href));
2962 IfFailReport(pThisTypeInfo->SetImplTypeFlags(iImpl, flags));
2964 flags = IMPLTYPEFLAG_FSOURCE;
2967 } // void TypeLibExporter::ConvertClassImplTypes()
2969 //*****************************************************************************
2970 // Export a class to a TypeLib.
2971 //*****************************************************************************
2972 void TypeLibExporter::ConvertClassDetails(
2973 ICreateTypeInfo2 *pThisTypeInfo, // The typeinfo being created.
2974 ICreateTypeInfo2 *pDefaultTypeInfo, // The ICLassX for the TypeInfo.
2975 MethodTable *pMT, // MethodTable for the TypeInfo.
2976 int bAutoProxy) // If true, oleaut32 is the proxy.
2981 PRECONDITION(CheckPointer(pThisTypeInfo, NULL_OK));
2982 PRECONDITION(CheckPointer(pDefaultTypeInfo, NULL_OK));
2983 PRECONDITION(CheckPointer(pMT));
2988 CorClassIfaceAttr classItfType = clsIfNone;
2990 ClassHasIClassX(pMT, &classItfType);
2991 if (classItfType == clsIfAutoDual)
2993 // Set up the IClassX interface.
2994 ConvertIClassX(pDefaultTypeInfo, pMT, bAutoProxy);
2996 else if (pDefaultTypeInfo)
2998 DWORD dwTIFlags = TYPEFLAG_FDUAL | TYPEFLAG_FOLEAUTOMATION | TYPEFLAG_FDISPATCHABLE | TYPEFLAG_FHIDDEN;
3000 dwTIFlags |= TYPEFLAG_FPROXY;
3001 IfFailReport(pDefaultTypeInfo->SetTypeFlags(dwTIFlags));
3003 } // void TypeLibExporter::ConvertClassDetails()
3005 //*****************************************************************************
3006 // Create the DispInterface for the vtable that describes an entire class.
3007 //*****************************************************************************
3008 void TypeLibExporter::ConvertIClassX(
3009 ICreateTypeInfo2 *pThisTypeInfo, // The TypeInfo for the IClassX.
3010 MethodTable *pMT, // The MethodTable object for the class.
3011 int bAutoProxy) // If true, oleaut32 is the proxy.
3016 PRECONDITION(CheckPointer(pThisTypeInfo));
3017 PRECONDITION(CheckPointer(pMT));
3021 HRESULT hr = S_OK; // A result.
3022 DWORD dwTIFlags=0; // TypeLib flags.
3023 DWORD nSlots; // Number of vtable slots.
3024 UINT i; // Loop control.
3025 int cVisibleMembers = 0; // The count of methods that are visible to COM.
3026 ComMTMemberInfoMap MemberMap(pMT); // The map of members.
3028 // Should be an actual class.
3029 _ASSERTE(!pMT->IsInterface());
3031 // Retrieve the method properties.
3032 size_t sizeOfPtr = IsExportingAs64Bit() ? 8 : 4;
3034 MemberMap.Init(sizeOfPtr);
3035 if (MemberMap.HadDuplicateDispIds())
3036 ReportWarning(TLBX_I_DUPLICATE_DISPID, TLBX_I_DUPLICATE_DISPID);
3038 // We need a scope to bypass the inialization skipped by goto ErrExit
3041 CQuickArray<ComMTMethodProps> &rProps = MemberMap.GetMethods();
3042 nSlots = (DWORD)rProps.Size();
3044 dwTIFlags |= TYPEFLAG_FDUAL | TYPEFLAG_FOLEAUTOMATION | TYPEFLAG_FDISPATCHABLE | TYPEFLAG_FHIDDEN | TYPEFLAG_FNONEXTENSIBLE;
3046 dwTIFlags |= TYPEFLAG_FPROXY;
3047 IfFailReport(pThisTypeInfo->SetTypeFlags(dwTIFlags));
3049 // Assign slot numbers.
3050 for (i=0; i<nSlots; ++i)
3051 rProps[i].oVft = (short)((7 + i) * sizeOfPtr);
3053 // Now add the methods to the TypeInfo.
3054 for (i=0; i<nSlots; ++i)
3056 TRACE("[%d] %10ls pMeth:%08x, prop:%d, semantic:%d, dispid:0x%x, oVft:%d\n", i, rProps[i].pName, rProps[i].pMeth,
3057 rProps[i].property, rProps[i].semantic, rProps[i].dispid, rProps[i].oVft);
3058 if (rProps[i].bMemberVisible)
3060 if (rProps[i].semantic < FieldSemanticOffset)
3062 if (ConvertMethod(pThisTypeInfo, &rProps[i], cVisibleMembers, ifDual))
3067 if (ConvertFieldAsMethod(pThisTypeInfo, &rProps[i], cVisibleMembers))
3073 } // void TypeLibExporter::ConvertIClassX()
3076 //*****************************************************************************
3077 // Export a Method's metadata to a typelib.
3078 //*****************************************************************************
3080 #pragma warning(push)
3081 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
3083 BOOL TypeLibExporter::ConvertMethod(
3084 ICreateTypeInfo2 *pCTI, // ICreateTypeInfo2 to get the method.
3085 ComMTMethodProps *pProps, // Some properties of the method.
3086 ULONG iMD, // Index of the member
3087 ULONG ulIface) // Is this interface : IUnknown, [dual], or DISPINTERFACE?
3092 PRECONDITION(CheckPointer(pCTI));
3093 PRECONDITION(CheckPointer(pProps));
3097 HRESULT hr = S_OK; // A result.
3098 HRESULT hrSignature = S_OK; // A failure HR;
3099 LPCUTF8 pszName; // Name in UTF8.
3100 SString sName; // Holds name.
3101 ULONG dwImplFlags; // The function's impl flags.
3102 PCCOR_SIGNATURE pbSig; // Pointer to Cor signature.
3103 ULONG cbSig; // Size of Cor signature.
3104 ULONG ixSig; // Index into signature.
3105 ULONG cbElem; // Size of an element in the signature.
3106 ULONG callconv; // A member's calling convention.
3107 ULONG ret; // The return type.
3108 ULONG elem; // A signature element.
3109 TYPEDESC *pRetVal=0; // Return type's TYPEDESC.
3110 ULONG cSrcParams; // Count of source params.
3111 ULONG cDestParams = 0; // Count of dest parameters.
3112 USHORT iSrcParam; // Loop control, over params.
3113 USHORT iDestParam; // Loop control, over params.
3114 USHORT iLCIDParam; // The index of the LCID param.
3115 ULONG dwParamFlags; // A parameter's flags.
3116 CDescPool sPool; // Pool of memory in which to build funcdesc.
3117 CDescPool sVariants; // Pool of variants for default values.
3118 PARAMDESCEX *pParamDesc; // Pointer to one param default value.
3119 int bHrMunge=true; // Munge return type to HRESULT?
3120 CQuickArray<BSTR> rNames; // Array of names to function and parameters.
3121 ULONG cNames=0; // Count of function and parameter names.
3122 FUNCDESC *pfunc = NULL; // A funcdesc.
3123 MethodDesc *pMeth; // A MethodDesc.
3124 IMDInternalImport *pInternalImport; // Internal interface containing the method.
3125 MDDefaultValue defaultValue; // place holder for default value
3126 PCCOR_SIGNATURE pvNativeType; // native parameter type
3127 ULONG cbNativeType = 0; // native parameter type length
3128 MethodTable *pMT; // Class containing the method.
3129 int bHasOptorDefault=false; // If true, the method has optional params or default values -- no vararg
3130 const void *pvData; // Pointer to a custom attribute.
3131 ULONG cbData; // Size of custom attribute.
3132 BOOL bByRef; // Is a parameter byref?
3133 BSTRHolder bstrDescr=0; // Description of the method.
3134 VariantHolder vtManagedName; // Variant used to set the managed name of the member.
3136 ZeroHolder zhParam = &m_ErrorContext.m_szParam; // Clear error reporting info.
3137 ZeroHolder zhMember = &m_ErrorContext.m_szMember; // Clear error reporting info.
3139 // Get info about the method.
3140 pMeth = pProps->pMeth;
3141 pMeth->GetSig(&pbSig, &cbSig);
3142 pInternalImport = pMeth->GetMDImport();
3143 pMT = pMeth->GetMethodTable();
3144 IfFailReport(pInternalImport->GetMethodImplProps(pMeth->GetMemberDef(), 0, &dwImplFlags));
3146 // Error reporting info.
3147 IfFailReport(pInternalImport->GetNameOfMethodDef(pMeth->GetMemberDef(), &m_ErrorContext.m_szMember));
3149 // Allocate one variant.
3150 pParamDesc = reinterpret_cast<PARAMDESCEX*>(sVariants.AllocZero(sizeof(PARAMDESCEX)));
3151 if(NULL == pParamDesc)
3152 IfFailReport(E_OUTOFMEMORY);
3154 // Prepare to parse signature and build the FUNCDESC.
3155 pfunc = reinterpret_cast<FUNCDESC*>(sPool.AllocZero(sizeof(FUNCDESC)));
3157 IfFailReport(E_OUTOFMEMORY);
3161 // Get the calling convention.
3162 ixSig += CorSigUncompressData(&pbSig[ixSig], &callconv);
3163 _ASSERTE((callconv & IMAGE_CEE_CS_CALLCONV_MASK) != IMAGE_CEE_CS_CALLCONV_FIELD);
3164 pfunc->callconv = Clr2TlbCallConv[callconv & IMAGE_CEE_CS_CALLCONV_MASK];
3167 pfunc->oVft = pProps->oVft;
3169 // Get the argument count. Allow for an extra in case of [retval].
3170 ixSig += CorSigUncompressData(&pbSig[ixSig], &cSrcParams);
3171 cDestParams = cSrcParams;
3172 rNames.ReSizeThrows(cDestParams+3);
3173 memset(rNames.Ptr(), 0, (cDestParams+3) * sizeof(BSTR));
3175 // Set some method properties.
3176 pfunc->memid = pProps->dispid;
3177 if (pfunc->memid == -11111) //@todo: fix for msvbalib.dll
3179 pfunc->funckind = FUNC_PUREVIRTUAL;
3181 // Set the invkind based on whether the function is an accessor.
3182 if (pProps->semantic == 0)
3183 pfunc->invkind = INVOKE_FUNC;
3184 else if (pProps->semantic == msGetter)
3185 pfunc->invkind = INVOKE_PROPERTYGET;
3186 else if (pProps->semantic == msSetter)
3187 pfunc->invkind = INVOKE_PROPERTYPUTREF;
3188 else if (pProps->semantic == msOther)
3189 pfunc->invkind = INVOKE_PROPERTYPUT;
3191 pfunc->invkind = INVOKE_FUNC; // non-accessor property function.
3193 rNames[0] = pProps->pName;
3196 // Convert return type to elemdesc. If we are doing HRESULT munging, we need to
3197 // examine the return type, and if it is not VOID, create an additional final
3198 // parameter as a pointer to the type.
3200 // Get the return type.
3201 cbElem = CorSigUncompressData(&pbSig[ixSig], &ret);
3203 // Error reporting info.
3204 m_ErrorContext.m_ixParam = 0;
3206 // Get native type of return if available
3208 pvNativeType = NULL;
3209 hr = pInternalImport->FindParamOfMethod(pMeth->GetMemberDef(), 0, &pdParam);
3212 hr = pInternalImport->GetFieldMarshal(pdParam, &pvNativeType, &cbNativeType);
3213 if (hr != CLDB_E_RECORD_NOTFOUND)
3219 // Determine if we need to do HRESULT munging.
3220 bHrMunge = !IsMiPreserveSig(dwImplFlags);
3222 // Reset some properties for DISPINTERFACES.
3223 if (ulIface == ifDispatch)
3225 pfunc->callconv = CC_STDCALL;
3226 pfunc->funckind = FUNC_DISPATCH;
3228 // Never munge a dispinterface.
3234 // Munge the return type into a new last param, set return type to HRESULT.
3235 pfunc->elemdescFunc.tdesc.vt = VT_HRESULT;
3237 // Does the function actually return anything?
3238 if (ret == ELEMENT_TYPE_VOID)
3240 // Skip over the return value, no [retval].
3246 // Allocate a TYPEDESC to be pointed to, convert type into it.
3247 pRetVal = reinterpret_cast<TYPEDESC*>(sPool.AllocZero(sizeof(TYPEDESC)));
3248 if (pRetVal == NULL)
3249 IfFailReport(E_OUTOFMEMORY);
3251 hr = CorSigToTypeDesc(pCTI, pMT, &pbSig[ixSig], pvNativeType, cbNativeType, &cbElem, pRetVal, &sPool, TRUE);
3258 // It is pretty weird for a property putter to return something, but apparenly legal.
3259 //_ASSERTE(pfunc->invkind != INVOKE_PROPERTYPUT && pfunc->invkind != INVOKE_PROPERTYPUTREF);
3261 // Todo: When the C compiler tries to import a typelib with a C
3262 // array return type (even if it's a retval),
3263 // it generates a wrapper method with a signature like "int [] foo()",
3264 // which isn't valid C, so it barfs. So, we'll change the return type
3265 // to a pointer by hand.
3266 if (pRetVal->vt == VT_CARRAY)
3268 pRetVal->vt = VT_PTR;
3269 pRetVal->lptdesc = &pRetVal->lpadesc->tdescElem;
3275 // No munging, convert return type.
3277 hr = CorSigToTypeDesc(pCTI, pMT, &pbSig[ixSig], pvNativeType, cbNativeType, &cbElem, &pfunc->elemdescFunc.tdesc, &sPool, TRUE);
3284 // Error reporting info.
3285 m_ErrorContext.m_ixParam = -1;
3287 // Check to see if there is an LCIDConversion attribute on the method.
3288 iLCIDParam = (USHORT)GetLCIDParameterIndex(pMeth);
3289 if (iLCIDParam != (USHORT)-1)
3291 BOOL bValidLCID = TRUE;
3293 // Make sure the parameter index is valid.
3294 if (iLCIDParam > cSrcParams)
3296 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_INVALIDLCIDPARAM);
3300 // LCID's are not allowed on pure dispatch interfaces.
3301 if (ulIface == ifDispatch)
3303 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_LCIDONDISPONLYITF);
3309 // Take the LCID parameter into account in the exported method.
3314 // The LCID is invalid so we will ignore it.
3319 // for each parameter
3320 pfunc->lprgelemdescParam = reinterpret_cast<ELEMDESC*>(sPool.AllocZero(cDestParams * sizeof(ELEMDESC)));
3321 if (pfunc->lprgelemdescParam == NULL)
3322 IfFailReport(E_OUTOFMEMORY);
3324 // Holds the allocated strings so we can deallocate on function exit.
3325 // Only need +1 as we don't clean up the first and last names (function name and retval)
3326 NewArrayHolder<BSTRHolder> namesHolder = new BSTRHolder[cDestParams+1];
3328 // Variant array used to hold default value data
3329 NewArrayHolder<VariantPtrHolder> vtDefaultValues = new VariantPtrHolder[cDestParams];
3331 pfunc->cParams = static_cast<short>(cDestParams);
3332 for (iSrcParam=1, iDestParam=0; iDestParam<cDestParams; ++iSrcParam, ++iDestParam)
3334 // Check to see if we need to insert the LCID param before the current param.
3335 if (iLCIDParam == iDestParam)
3337 // Set the flags and the type of the parameter.
3338 pfunc->lprgelemdescParam[iDestParam].paramdesc.wParamFlags = PARAMFLAG_FIN | PARAMFLAG_FLCID;
3339 pfunc->lprgelemdescParam[iDestParam].tdesc.vt = VT_I4;
3341 // Generate a parameter name.
3342 sName.Printf(szParamName, iDestParam + 1);
3344 rNames[iDestParam + 1] = SysAllocString(sName.GetUnicode());
3345 if (rNames[iDestParam + 1] == NULL)
3346 IfFailReport(E_OUTOFMEMORY);
3348 namesHolder[iDestParam+1] = rNames[iDestParam + 1];
3352 // Increment the current destination parameter.
3356 // If we are past the end of the source parameters then we are done.
3357 if (iSrcParam > cSrcParams)
3360 // Get additional parameter metadata.
3364 // Error reporting info.
3365 m_ErrorContext.m_ixParam = iSrcParam;
3367 // See if there is a ParamDef for this param.
3368 hr = pInternalImport->FindParamOfMethod(pMeth->GetMemberDef(), iSrcParam, &pdParam);
3370 pvNativeType = NULL;
3373 // Get info about the param.
3374 IfFailReport(pInternalImport->GetParamDefProps(pdParam, &iSrcParam, &dwParamFlags, &pszName));
3376 // Error reporting info.
3377 m_ErrorContext.m_szParam = pszName;
3379 // Turn off reserved (internal use) bits.
3380 dwParamFlags &= ~pdReservedMask;
3382 // Convert name from UTF8 to unicode.
3383 sName.SetUTF8(pszName);
3385 // Param default value, if any.
3386 IfFailReport(pInternalImport->GetDefaultValue(pdParam, &defaultValue));
3387 IfFailReport(_FillVariant(&defaultValue, &pParamDesc->varDefaultValue));
3389 // If no default value, check for decimal custom attribute.
3390 if (pParamDesc->varDefaultValue.vt == VT_EMPTY)
3392 IfFailReport(pMT->GetMDImport()->GetCustomAttributeByName(pdParam, INTEROP_DECIMALVALUE_TYPE, &pvData,&cbData));
3393 if (hr == S_OK && cbData >= (2 + sizeof(BYTE)+sizeof(BYTE)+sizeof(UINT)+sizeof(UINT)+sizeof(UINT)))
3395 const BYTE *pbData = (const BYTE *)pvData;
3396 pParamDesc->varDefaultValue.vt = VT_DECIMAL;
3397 pParamDesc->varDefaultValue.decVal.scale = *(BYTE*)(pbData+2);
3398 pParamDesc->varDefaultValue.decVal.sign= *(BYTE*)(pbData+3);
3399 pParamDesc->varDefaultValue.decVal.Hi32= GET_UNALIGNED_32(pbData+4);
3400 pParamDesc->varDefaultValue.decVal.Mid32= GET_UNALIGNED_32(pbData+8);
3401 pParamDesc->varDefaultValue.decVal.Lo32= GET_UNALIGNED_32(pbData+12);
3404 // If still no default value, check for date time custom attribute.
3405 if (pParamDesc->varDefaultValue.vt == VT_EMPTY)
3407 IfFailReport(pMT->GetMDImport()->GetCustomAttributeByName(pdParam, INTEROP_DATETIMEVALUE_TYPE, &pvData,&cbData));
3408 if (hr == S_OK && cbData >= (2 + sizeof(__int64)))
3410 const BYTE *pbData = (const BYTE *)pvData;
3411 pParamDesc->varDefaultValue.vt = VT_DATE;
3412 pParamDesc->varDefaultValue.date = _TicksToDoubleDate(GET_UNALIGNED_64(pbData+2));
3415 // If still no default value, check for IDispatch custom attribute.
3416 if (pParamDesc->varDefaultValue.vt == VT_EMPTY)
3418 IfFailReport(pMT->GetMDImport()->GetCustomAttributeByName(pdParam, INTEROP_IDISPATCHVALUE_TYPE, &pvData,&cbData));
3421 pParamDesc->varDefaultValue.vt = VT_DISPATCH;
3422 pParamDesc->varDefaultValue.pdispVal = 0;
3425 // If still no default value, check for IUnknown custom attribute.
3426 if (pParamDesc->varDefaultValue.vt == VT_EMPTY)
3428 IfFailReport(pMT->GetMDImport()->GetCustomAttributeByName(pdParam, INTEROP_IUNKNOWNVALUE_TYPE, &pvData,&cbData));
3431 pParamDesc->varDefaultValue.vt = VT_UNKNOWN;
3432 pParamDesc->varDefaultValue.punkVal = 0;
3436 if (pParamDesc->varDefaultValue.vt != VT_EMPTY)
3438 // Copy the variant into the holder object so we release on function exit.
3439 vtDefaultValues[iDestParam] = (VARIANT*)&pParamDesc->varDefaultValue;
3441 pfunc->lprgelemdescParam[iDestParam].paramdesc.pparamdescex = pParamDesc;
3442 dwParamFlags |= PARAMFLAG_FHASDEFAULT;
3444 // Allocate another paramdesc.
3445 pParamDesc = reinterpret_cast<PARAMDESCEX*>(sVariants.AllocZero(sizeof(PARAMDESCEX)));
3446 if (pParamDesc == NULL)
3447 IfFailReport(E_OUTOFMEMORY);
3449 bHasOptorDefault = true;
3452 // native marshal type, if any.
3453 hr = pInternalImport->GetFieldMarshal(pdParam, &pvNativeType, &cbNativeType);
3454 if (hr != CLDB_E_RECORD_NOTFOUND)
3459 // Remember if there are optional params.
3460 if (dwParamFlags & PARAMFLAG_FOPT)
3461 bHasOptorDefault = true;
3465 pdParam = 0, m_ErrorContext.m_szParam = 0;
3468 // Do we need a name for this parameter?
3469 if ((pfunc->invkind & (INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF)) == 0 ||
3470 iSrcParam < cSrcParams)
3472 // Yes, so make one up if we don't have one.
3473 if (sName.GetCount() == 0)
3475 sName.Printf(szParamName, iDestParam + 1);
3478 rNames[iDestParam + 1] = SysAllocString(sName.GetUnicode());
3479 if (rNames[iDestParam + 1] == NULL)
3480 IfFailReport(E_OUTOFMEMORY);
3482 namesHolder[iDestParam+1] = rNames[iDestParam + 1];
3487 // Save the element type.
3488 CorSigUncompressData(&pbSig[ixSig], &elem);
3490 // Convert the param info to elemdesc.
3492 hr = CorSigToTypeDesc(pCTI, pMT, &pbSig[ixSig], pvNativeType, cbNativeType, &cbElem,
3493 &pfunc->lprgelemdescParam[iDestParam].tdesc, &sPool, TRUE, &bByRef);
3499 // If there is no [in,out], set one, based on the parameter.
3500 if ((dwParamFlags & (PARAMFLAG_FOUT | PARAMFLAG_FIN)) == 0)
3502 // If param is by reference, make in/out
3504 dwParamFlags |= PARAMFLAG_FIN | PARAMFLAG_FOUT;
3506 dwParamFlags |= PARAMFLAG_FIN;
3509 // If this is the last param, and it an array of objects, and has a ParamArrayAttribute,
3510 // the function is varargs.
3511 if ((iSrcParam == cSrcParams) && !IsNilToken(pdParam) && !bHasOptorDefault)
3513 if (pfunc->lprgelemdescParam[iDestParam].tdesc.vt == VT_SAFEARRAY &&
3514 pfunc->lprgelemdescParam[iDestParam].tdesc.lpadesc->tdescElem.vt == VT_VARIANT)
3516 if (pInternalImport->GetCustomAttributeByName(pdParam, INTEROP_PARAMARRAY_TYPE, 0,0) == S_OK)
3517 pfunc->cParamsOpt = -1;
3521 pfunc->lprgelemdescParam[iDestParam].paramdesc.wParamFlags = static_cast<USHORT>(dwParamFlags);
3524 // Is there a [retval]?
3527 // Error reporting info.
3528 m_ErrorContext.m_ixParam = 0;
3529 m_ErrorContext.m_szParam = 0;
3532 _ASSERTE(cDestParams > cSrcParams);
3533 pfunc->lprgelemdescParam[cDestParams-1].tdesc.vt = VT_PTR;
3534 pfunc->lprgelemdescParam[cDestParams-1].tdesc.lptdesc = pRetVal;
3535 pfunc->lprgelemdescParam[cDestParams-1].paramdesc.wParamFlags = PARAMFLAG_FOUT | PARAMFLAG_FRETVAL;
3537 // no need to allocate a new string for this. rather use the constant szRetVal
3538 rNames[cDestParams] = (LPWSTR)szRetVal;
3543 // Error reporting info.
3544 m_ErrorContext.m_ixParam = -1;
3546 // Was there a signature error? If so, exit now that all sigs have been reported.
3547 IfFailReport(hrSignature);
3549 IfFailReport(pCTI->AddFuncDesc(iMD, pfunc));
3551 IfFailReport(pCTI->SetFuncAndParamNames(iMD, rNames.Ptr(), cNames));
3553 if (pProps->bFunction2Getter)
3558 IfFailReport(pCTI->SetFuncCustData(iMD, GUID_Function2Getter, &vtOne));
3561 // If the managed name of the method is different from the unmanaged name, then
3562 // we need to capture the managed name in a custom value. We only apply this
3563 // attribute for methods since properties cannot be overloaded.
3564 if (pProps->semantic == 0)
3566 sName.SetUTF8(pMeth->GetName());
3567 if (sName.Compare(SString(pProps->pName)) != 0)
3569 V_VT(&vtManagedName) = VT_BSTR;
3571 if (NULL == (V_BSTR(&vtManagedName) = SysAllocString(sName.GetUnicode())))
3572 IfFailReport(E_OUTOFMEMORY);
3574 IfFailReport(pCTI->SetFuncCustData(iMD, GUID_ManagedName, &vtManagedName));
3578 // Check for a description.
3579 if(GetDescriptionString(pMT, pMeth->GetMemberDef(), (BSTR &)bstrDescr))
3580 IfFailReport(pCTI->SetFuncDocString(iMD, bstrDescr));
3583 // Error reporting info.
3584 m_ErrorContext.m_szMember = 0;
3585 m_ErrorContext.m_szParam = 0;
3586 m_ErrorContext.m_ixParam = -1;
3589 } // void TypeLibExporter::ConvertMethod()
3591 #pragma warning(pop)
3594 //*****************************************************************************
3595 // Export a Field as getter/setter method's to a typelib.
3596 //*****************************************************************************
3597 BOOL TypeLibExporter::ConvertFieldAsMethod(
3598 ICreateTypeInfo2 *pCTI, // ICreateTypeInfo2 to get the method.
3599 ComMTMethodProps *pProps, // Some properties of the method.
3600 ULONG iMD) // Index of the member
3605 PRECONDITION(CheckPointer(pCTI));
3606 PRECONDITION(CheckPointer(pProps));
3610 HRESULT hr = S_OK; // A result.
3611 PCCOR_SIGNATURE pbSig; // Pointer to Cor signature.
3612 ULONG cbSig; // Size of Cor signature.
3613 ULONG ixSig; // Index into signature.
3614 ULONG cbElem; // Size of an element in the signature.
3616 ULONG callconv; // A member's calling convention.
3617 TYPEDESC *pType; // TYPEDESC for the field type.
3618 CDescPool sPool; // Pool of memory in which to build funcdesc.
3619 BSTR rNames[2]; // Array of names to function and parameters.
3620 ULONG cNames; // Count of function and parameter names.
3621 FUNCDESC *pfunc; // A funcdesc.
3622 ComCallMethodDesc *pFieldMeth; // A MethodDesc for a field call.
3623 FieldDesc *pField; // A FieldDesc.
3624 IMDInternalImport *pInternalImport; // Internal interface containing the field.
3625 PCCOR_SIGNATURE pvNativeType; // native field type
3626 ULONG cbNativeType; // native field type length
3627 MethodTable *pMT; // Class containing the field.
3628 BSTRHolder bstrDescr=0; // Description of the method.
3630 // Get info about the method.
3631 pFieldMeth = reinterpret_cast<ComCallMethodDesc*>(pProps->pMeth);
3632 pField = pFieldMeth->GetFieldDesc();
3633 pField->GetSig(&pbSig, &cbSig);
3634 pInternalImport = pField->GetMDImport();
3635 pMT = pField->GetEnclosingMethodTable();
3637 // Error reporting info.
3638 IfFailReport(pMT->GetMDImport()->GetNameOfFieldDef(pField->GetMemberDef(), &m_ErrorContext.m_szMember));
3640 // Prepare to parse signature and build the FUNCDESC.
3641 pfunc = reinterpret_cast<FUNCDESC*>(sPool.AllocZero(sizeof(FUNCDESC)));
3643 IfFailReport(E_OUTOFMEMORY);
3646 // Get the calling convention.
3647 ixSig += CorSigUncompressData(&pbSig[ixSig], &callconv);
3648 _ASSERTE(callconv == IMAGE_CEE_CS_CALLCONV_FIELD);
3649 pfunc->callconv = CC_STDCALL;
3652 pfunc->oVft = pProps->oVft;
3654 // Set some method properties.
3655 pfunc->memid = pProps->dispid;
3656 pfunc->funckind = FUNC_PUREVIRTUAL;
3658 // Set the invkind based on whether the function is an accessor.
3659 if ((pProps->semantic - FieldSemanticOffset) == msGetter)
3660 pfunc->invkind = INVOKE_PROPERTYGET;
3661 else if ((pProps->semantic - FieldSemanticOffset) == msSetter)
3663 if (IsVbRefType(&pbSig[ixSig], pInternalImport))
3664 pfunc->invkind = INVOKE_PROPERTYPUTREF;
3666 pfunc->invkind = INVOKE_PROPERTYPUT;
3669 _ASSERTE(!"Incorrect semantic in ConvertFieldAsMethod");
3671 // Name of the function.
3672 rNames[0] = pProps->pName;
3675 // Return type is HRESULT.
3676 pfunc->elemdescFunc.tdesc.vt = VT_HRESULT;
3678 // Set up the one and only parameter.
3679 pfunc->lprgelemdescParam = reinterpret_cast<ELEMDESC*>(sPool.AllocZero(sizeof(ELEMDESC)));
3680 if (NULL == pfunc->lprgelemdescParam)
3681 IfFailReport(E_OUTOFMEMORY);
3684 // Do we need a name for the parameter? If PROPERTYGET, we do.
3685 if (pfunc->invkind == INVOKE_PROPERTYGET)
3687 // Yes, so make one up.
3688 rNames[1] = (WCHAR*)szRetVal;
3692 // If Getter, convert param as ptr, otherwise convert directly.
3693 if (pfunc->invkind == INVOKE_PROPERTYGET)
3695 pType = reinterpret_cast<TYPEDESC*>(sPool.AllocZero(sizeof(TYPEDESC)));
3697 IfFailReport(E_OUTOFMEMORY);
3699 pfunc->lprgelemdescParam[0].tdesc.vt = VT_PTR;
3700 pfunc->lprgelemdescParam[0].tdesc.lptdesc = pType;
3701 pfunc->lprgelemdescParam[0].paramdesc.wParamFlags = PARAMFLAG_FOUT | PARAMFLAG_FRETVAL;
3705 pType = &pfunc->lprgelemdescParam[0].tdesc;
3706 pfunc->lprgelemdescParam[0].paramdesc.wParamFlags = PARAMFLAG_FIN;
3709 // Get native field type
3710 pvNativeType = NULL;
3711 hr = pInternalImport->GetFieldMarshal(
3712 pField->GetMemberDef(),
3715 if (hr != CLDB_E_RECORD_NOTFOUND)
3720 // Convert the field type to elemdesc.
3721 hr = CorSigToTypeDesc(pCTI, pMT, &pbSig[ixSig], pvNativeType, cbNativeType, &cbElem, pType, &sPool, TRUE);
3727 // It is unfortunate that we can not handle this better. Fortunately
3728 // this should be very rare.
3729 // This is a weird case - if we're getting a CARRAY, we cannot add
3730 // a VT_PTR in the sig, as it will cause the C getter to return an
3731 // array, which is bad. So we omit the extra pointer, which at least
3732 // makes the compiler happy.
3733 if (pfunc->invkind == INVOKE_PROPERTYGET
3734 && pType->vt == VT_CARRAY)
3736 pfunc->lprgelemdescParam[0].tdesc.vt = pType->vt;
3737 pfunc->lprgelemdescParam[0].tdesc.lptdesc = pType->lptdesc;
3740 // A property put of an object should be a propertyputref
3741 if (pfunc->invkind == INVOKE_PROPERTYPUT &&
3742 (pType->vt == VT_UNKNOWN || pType->vt == VT_DISPATCH))
3744 pfunc->invkind = INVOKE_PROPERTYPUTREF;
3747 IfFailReport(pCTI->AddFuncDesc(iMD, pfunc));
3749 IfFailReport(pCTI->SetFuncAndParamNames(iMD, rNames, cNames));
3751 // Check for a description.
3752 if(GetDescriptionString(pMT, pField->GetMemberDef(), (BSTR &)bstrDescr))
3753 IfFailReport(pCTI->SetFuncDocString(iMD, bstrDescr));
3755 // Error reporting info.
3756 m_ErrorContext.m_szMember = 0;
3759 } // void TypeLibExporter::ConvertFieldAsMethod()
3761 //*****************************************************************************
3762 // Export a variable's metadata to a typelib.
3763 //*****************************************************************************
3764 BOOL TypeLibExporter::ConvertVariable(
3765 ICreateTypeInfo2 *pCTI, // ICreateTypeInfo2 to get the variable.
3766 MethodTable *pMT, // The class containing the variable.
3767 mdFieldDef md, // The member definition.
3768 SString& sName, // Name of the member.
3769 ULONG iMD) // Index of the member
3774 PRECONDITION(CheckPointer(pCTI));
3775 PRECONDITION(CheckPointer(pMT));
3779 HRESULT hr = S_OK; // A result.
3780 PCCOR_SIGNATURE pbSig; // Pointer to Cor signature.
3781 ULONG cbSig; // Size of Cor signature.
3782 ULONG ixSig; // Index into signature.
3783 ULONG cbElem; // Size of an element in the signature.
3784 DWORD dwFlags; // A member's flags.
3785 ULONG callconv; // A member's calling convention.
3786 MDDefaultValue defaultValue; // default value
3787 ULONG dispid=DISPID_UNKNOWN; // The variable's dispid.
3788 CDescPool sPool; // Pool of memory in which to build vardesc.
3789 VARDESC *pvar; // A vardesc.
3790 PCCOR_SIGNATURE pvNativeType; // native field type
3791 ULONG cbNativeType; // native field type length
3792 const void *pvData; // Pointer to a custom attribute.
3793 ULONG cbData; // Size of custom attribute.
3794 LPWSTR pSuffix; // Pointer into the name.
3795 int iSuffix = 0; // Counter for suffix.
3796 BSTRHolder bstrDescr=0; // Description of the method.
3799 VariantPtrHolder vtVariant = &vtTemp;
3801 SafeVariantInit(vtVariant);
3803 // Error reporting info.
3804 IfFailReport(pMT->GetMDImport()->GetNameOfFieldDef(md, &m_ErrorContext.m_szMember));
3806 // Get info about the field.
3807 IfFailReport(pMT->GetMDImport()->GetDispIdOfMemberDef(md, &dispid));
3808 IfFailReport(pMT->GetMDImport()->GetFieldDefProps(md, &dwFlags));
3809 if (IsFdHasDefault(dwFlags))
3811 IfFailReport(pMT->GetMDImport()->GetDefaultValue(md, &defaultValue));
3812 IfFailReport( _FillVariant(&defaultValue, vtVariant) );
3815 // If exporting a non-public member of a struct, warn the user.
3816 if (!IsFdPublic(dwFlags) && !m_bWarnedOfNonPublic)
3818 m_bWarnedOfNonPublic = TRUE;
3819 ReportWarning(TLBX_E_NONPUBLIC_FIELD, TLBX_E_NONPUBLIC_FIELD);
3822 IfFailReport(pMT->GetMDImport()->GetSigOfFieldDef(md, &cbSig, &pbSig));
3824 // Prepare to parse signature and build the VARDESC.
3825 pvar = reinterpret_cast<VARDESC*>(sPool.AllocZero(sizeof(VARDESC)));
3827 IfFailReport(E_OUTOFMEMORY);
3830 // Get the calling convention.
3831 ixSig += CorSigUncompressData(&pbSig[ixSig], &callconv);
3832 _ASSERTE(callconv == IMAGE_CEE_CS_CALLCONV_FIELD);
3834 // Get native field type
3835 pvNativeType = NULL;
3836 hr = pMT->GetMDImport()->GetFieldMarshal(md, &pvNativeType, &cbNativeType);
3837 if (hr != CLDB_E_RECORD_NOTFOUND)
3842 // Convert the type to elemdesc.
3843 hr = CorSigToTypeDesc(pCTI, pMT, &pbSig[ixSig], pvNativeType, cbNativeType, &cbElem, &pvar->elemdescVar.tdesc, &sPool, FALSE);
3849 pvar->wVarFlags = 0;
3850 pvar->varkind = VAR_PERINSTANCE;
3851 pvar->memid = dispid;
3854 if (vtVariant->vt != VT_EMPTY)
3855 pvar->lpvarValue = vtVariant;
3858 IfFailReport(pMT->GetMDImport()->GetCustomAttributeByName(md, INTEROP_DECIMALVALUE_TYPE, &pvData,&cbData));
3859 if (hr == S_OK && cbData >= (2 + sizeof(BYTE)+sizeof(BYTE)+sizeof(UINT)+sizeof(UINT)+sizeof(UINT)))
3861 const BYTE *pbData = (const BYTE *)pvData;
3862 vtVariant->vt = VT_DECIMAL;
3863 vtVariant->decVal.scale = *(BYTE*)(pbData+2);
3864 vtVariant->decVal.sign= *(BYTE*)(pbData+3);
3865 vtVariant->decVal.Hi32= GET_UNALIGNED_32(pbData+4);
3866 vtVariant->decVal.Mid32= GET_UNALIGNED_32(pbData+8);
3867 vtVariant->decVal.Lo32= GET_UNALIGNED_32(pbData+12);
3868 pvar->lpvarValue = vtVariant;
3870 // If still no default value, check for date time custom attribute.
3871 if (vtVariant->vt == VT_EMPTY)
3873 IfFailReport(pMT->GetMDImport()->GetCustomAttributeByName(md, INTEROP_DATETIMEVALUE_TYPE, &pvData,&cbData));
3874 if (hr == S_OK && cbData >= (2 + sizeof(__int64)))
3876 const BYTE *pbData = (const BYTE *)pvData;
3877 vtVariant->vt = VT_DATE;
3878 vtVariant->date = _TicksToDoubleDate(GET_UNALIGNED_64(pbData+2));
3881 // If still no default value, check for IDispatch custom attribute.
3882 if (vtVariant->vt == VT_EMPTY)
3884 IfFailReport(pMT->GetMDImport()->GetCustomAttributeByName(md, INTEROP_IDISPATCHVALUE_TYPE, &pvData,&cbData));
3887 vtVariant->vt = VT_DISPATCH;
3888 vtVariant->pdispVal = 0;
3891 // If still no default value, check for IUnknown custom attribute.
3892 if (vtVariant->vt == VT_EMPTY)
3894 IfFailReport(pMT->GetMDImport()->GetCustomAttributeByName(md, INTEROP_IUNKNOWNVALUE_TYPE, &pvData,&cbData));
3897 vtVariant->vt = VT_UNKNOWN;
3898 vtVariant->punkVal = 0;
3903 IfFailReport(pCTI->AddVarDesc(iMD, pvar));
3905 // Set the name for the member; decorate if necessary.
3909 // Attempt to set the name.
3910 hr = pCTI->SetVarName(iMD, (LPOLESTR)sName.GetUnicode());
3912 // If a name conflict, decorate, otherwise, done.
3913 if (hr != TYPE_E_AMBIGUOUSNAME)
3922 sName.Delete(sName.End()-=2, 2);
3926 sDup.Printf(szDuplicateDecoration, iSuffix++);
3932 // Check for a description.
3933 if(GetDescriptionString(pMT, md, (BSTR &)bstrDescr))
3934 IfFailReport(pCTI->SetVarDocString(iMD, bstrDescr));
3936 // Error reporting info.
3937 m_ErrorContext.m_szMember = 0;
3940 } // HRESULT TypeLibExporter::ConvertVariable()
3942 //*****************************************************************************
3943 // Export a variable's metadata to a typelib.
3944 //*****************************************************************************
3945 BOOL TypeLibExporter::ConvertEnumMember(
3946 ICreateTypeInfo2 *pCTI, // ICreateTypeInfo2 to get the variable.
3947 MethodTable *pMT, // The Class containing the member.
3948 mdFieldDef md, // The member definition.
3949 SString& sName, // Name of the member.
3950 ULONG iMD) // Index of the member
3955 PRECONDITION(CheckPointer(pCTI));
3956 PRECONDITION(CheckPointer(pMT));
3960 HRESULT hr = S_OK; // A result.
3961 LPCUTF8 pName, pNS; // To format name.
3962 DWORD dwFlags; // A member's flags.
3963 VARIANT vtVariant; // A Variant.
3964 MDDefaultValue defaultValue; // default value
3965 ULONG dispid=DISPID_UNKNOWN; // The variable's dispid.
3966 CDescPool sPool; // Pool of memory in which to build vardesc.
3967 VARDESC *pvar; // A vardesc.
3968 BSTRHolder bstrDescr=0; // Description of the method.
3970 vtVariant.vt = VT_EMPTY;
3972 // Error reporting info.
3973 IfFailReport(pMT->GetMDImport()->GetNameOfFieldDef(md, &m_ErrorContext.m_szMember));
3975 // Get info about the field.
3976 IfFailReport(pMT->GetMDImport()->GetDispIdOfMemberDef(md, &dispid));
3977 IfFailReport(pMT->GetMDImport()->GetFieldDefProps(md, &dwFlags));
3979 // We do not need to handle decimal's here since enum's can only be integral types.
3980 IfFailReport(pMT->GetMDImport()->GetDefaultValue(md, &defaultValue));
3982 // Prepare to parse signature and build the VARDESC.
3983 pvar = reinterpret_cast<VARDESC*>(sPool.AllocZero(sizeof(VARDESC)));
3985 IfFailReport(E_OUTOFMEMORY);
3987 IfFailReport( _FillVariant(&defaultValue, &vtVariant) );
3989 // Don't care what the metadata says the type is -- the type is I4 in the typelib.
3990 pvar->elemdescVar.tdesc.vt = VT_I4;
3992 pvar->wVarFlags = 0;
3993 pvar->varkind = VAR_CONST;
3994 pvar->memid = dispid;
3997 if (vtVariant.vt != VT_EMPTY)
3999 pvar->lpvarValue = &vtVariant;
4001 // If this is an I8 or UI8, do the conversion manually, because some
4002 // systems' oleaut32 don't support 64-bit integers.
4003 if (vtVariant.vt == VT_I8)
4005 // If withing range of 32-bit signed number, OK.
4006 if (vtVariant.llVal <= LONG_MAX && vtVariant.llVal >= LONG_MIN)
4007 vtVariant.vt = VT_I4, hr = S_OK;
4011 else if (vtVariant.vt == VT_UI8)
4013 // If withing range of 32-bit unsigned number, OK.
4014 if (vtVariant.ullVal <= ULONG_MAX)
4015 vtVariant.vt = VT_UI4, hr = S_OK;
4021 hr = SafeVariantChangeTypeEx(&vtVariant, &vtVariant, 0, 0, VT_I4);
4026 if (FAILED(pMT->GetMDImport()->GetNameOfTypeDef(pMT->GetCl(), &pName, &pNS)))
4028 pName = pNS = "Invalid TypeDef record";
4030 ReportWarning(TLBX_W_ENUM_VALUE_TOOBIG, TLBX_W_ENUM_VALUE_TOOBIG, pName, sName.GetUnicode());
4035 { // No value assigned, use 0.
4036 pvar->lpvarValue = &vtVariant;
4037 vtVariant.vt = VT_I4;
4041 IfFailReport(pCTI->AddVarDesc(iMD, pvar));
4042 IfFailReport(pCTI->SetVarName(iMD, (LPOLESTR)sName.GetUnicode()));
4044 // Check for a description.
4045 if(GetDescriptionString(pMT, md, (BSTR &)bstrDescr))
4046 IfFailReport(pCTI->SetVarDocString(iMD, bstrDescr));
4048 // Error reporting info.
4049 m_ErrorContext.m_szMember = 0;
4052 } // void TypeLibExporter::ConvertEnumMember()
4054 //*****************************************************************************
4055 // Given a COM+ signature of a field or property, determine if it should
4056 // be a PROPERTYPUT or PROPERTYPUTREF.
4057 //*****************************************************************************
4058 BOOL TypeLibExporter::IsVbRefType(
4059 PCCOR_SIGNATURE pbSig,
4060 IMDInternalImport *pInternalImport)
4065 PRECONDITION(CheckPointer(pInternalImport));
4069 ULONG elem=0; // An element from a COM+ signature.
4072 cbElem = CorSigUncompressData(pbSig, &elem);
4073 if (elem == ELEMENT_TYPE_PTR || elem == ELEMENT_TYPE_BYREF)
4075 return IsVbRefType(&pbSig[cbElem], pInternalImport);
4081 // For documentation -- arrays are NOT ref types here.
4082 //case ELEMENT_TYPE_SDARRAY:
4083 //case ELEMENT_TYPE_ARRAY:
4084 //case ELEMENT_TYPE_SZARRAY:
4085 // Look for variant.
4086 case ELEMENT_TYPE_VALUETYPE:
4089 case ELEMENT_TYPE_CLASS:
4092 case ELEMENT_TYPE_OBJECT:
4101 } // BOOL TypeLibExporter::IsVbRefType()
4103 BOOL TypeLibExporter::IsExportingAs64Bit()
4105 LIMITED_METHOD_CONTRACT;
4106 if (TlbExportAs64Bit(m_flags))
4110 else if (TlbExportAs32Bit(m_flags))
4122 } // BOOL TypeLibExporter::IsExportingAs64Bit()
4124 void TypeLibExporter::ArrayToTypeDesc(ICreateTypeInfo2 *pCTI, CDescPool *ppool, ArrayMarshalInfo *pArrayMarshalInfo, TYPEDESC *ptdesc)
4129 PRECONDITION(CheckPointer(pCTI));
4130 PRECONDITION(CheckPointer(ppool));
4131 PRECONDITION(CheckPointer(pArrayMarshalInfo));
4132 PRECONDITION(CheckPointer(ptdesc));
4136 HRESULT hr = E_FAIL;
4137 VARTYPE vtElement = pArrayMarshalInfo->GetElementVT();
4138 TypeHandle thElement = pArrayMarshalInfo->GetElementTypeHandle();
4140 if (vtElement == VT_RECORD)
4142 // We are dealing with an array of embedded structures.
4143 ptdesc->vt = VT_USERDEFINED;
4144 EEClassToHref(pCTI, thElement.GetMethodTable(), FALSE, &ptdesc->hreftype);
4146 else if ((vtElement == VT_UNKNOWN || vtElement == VT_DISPATCH) && !thElement.IsObjectType())
4148 if (!thElement.IsValueType() && !pArrayMarshalInfo->IsSafeArraySubTypeExplicitlySpecified())
4150 // We are dealing with an array of user defined interfaces.
4151 ptdesc->vt = VT_PTR;
4152 ptdesc->lptdesc = reinterpret_cast<TYPEDESC*>(ppool->AllocZero(sizeof(TYPEDESC)));
4153 if (ptdesc->lptdesc == NULL)
4154 IfFailReport(E_OUTOFMEMORY);
4156 ptdesc->lptdesc->vt = VT_USERDEFINED;
4157 EEClassToHref(pCTI, thElement.GetMethodTable(), FALSE, &ptdesc->lptdesc->hreftype);
4161 // The user specified that the array of value classes be converted to an
4162 // array of IUnknown or IDispatch pointers.
4163 ptdesc->vt = vtElement;
4166 else if (pArrayMarshalInfo->IsPtr())
4168 ptdesc->vt = VT_PTR;
4169 ptdesc->lptdesc = reinterpret_cast<TYPEDESC*>(ppool->AllocZero(sizeof(TYPEDESC)));
4170 if (ptdesc->lptdesc == NULL)
4171 IfFailReport(E_OUTOFMEMORY);
4173 ptdesc->lptdesc->vt = vtElement;
4177 // We are dealing with an array of primitive types.
4178 ptdesc->vt = vtElement;
4181 // HRESULT ArrayToTypeDesc(ArrayMarshalInfo *pArrayMarshalInfo, TYPEDESC *pElementTypeDesc)
4183 VARTYPE TypeLibExporter::GetVtForIntPtr()
4185 WRAPPER_NO_CONTRACT;
4187 return static_cast<VARTYPE>(IsExportingAs64Bit() ? VT_I8 : VT_I4);
4188 } // VARTYPE TypeLibExporter::GetVtForIntPtr()
4190 VARTYPE TypeLibExporter::GetVtForUIntPtr()
4192 WRAPPER_NO_CONTRACT;
4194 return static_cast<VARTYPE>(IsExportingAs64Bit() ? VT_UI8 : VT_UI4);
4195 } // VARTYPE TypeLibExporter::GetVtForUIntPtr()
4198 BOOL TypeLibExporter::ValidateSafeArrayElemVT(VARTYPE vt)
4230 //*****************************************************************************
4231 // Read a COM+ signature element and create a TYPEDESC that corresponds
4233 //*****************************************************************************
4235 #pragma warning(push)
4236 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
4238 HRESULT TypeLibExporter::CorSigToTypeDesc(
4239 ICreateTypeInfo2 *pCTI, // Typeinfo being created.
4240 MethodTable *pMT, // MethodTable with the token.
4241 PCCOR_SIGNATURE pbSig, // Pointer to the Cor Signature.
4242 PCCOR_SIGNATURE pbNativeSig, // Pointer to the native sig, if any
4243 ULONG cbNativeSig, // Count of bytes in native sig.
4244 ULONG *pcbElem, // Put # bytes consumed here.
4245 TYPEDESC *ptdesc, // Build the typedesc here.
4246 CDescPool *ppool, // Pool for additional storage as required.
4247 BOOL bMethodSig, // TRUE if the sig is for a method, FALSE for a field.
4248 BOOL *pbByRef) // If not null, and the type is byref, set to true.
4253 PRECONDITION(CheckPointer(pCTI));
4254 PRECONDITION(CheckPointer(pMT));
4255 PRECONDITION(CheckPointer(pcbElem));
4256 PRECONDITION(CheckPointer(ptdesc));
4257 PRECONDITION(CheckPointer(ppool));
4258 PRECONDITION(CheckPointer(pbByRef, NULL_OK));
4263 ULONG elem = 0; // The element type.
4264 ULONG cbElem = 0; // Bytes in the element.
4265 ULONG cb; // Bytes in a sub-element.
4266 ULONG cbNativeElem = 0; // # of bytes parsed off of native type.
4267 ULONG nativeElem = 0; // The native element type
4268 ULONG nativeCount; // The native element size
4269 mdToken tkTypeRef; // Token for a TypeRef/TypeDef
4270 SString sName; // Buffer to build a name from NS/Name.
4271 LPCUTF8 pclsname; // Class name for ELEMENT_TYPE_CLASS.
4272 HREFTYPE hRef = 0; // HREF to some type.
4273 IMDInternalImport *pInternalImport; // Internal interface containing the signature.
4274 Module* pModule = NULL; // Module containing the signature.
4275 int i; // Loop control.
4276 SigTypeContext emptyTypeContext; // an empty type context is sufficient: all methods should be non-generic
4277 ULONG dwTypeFlags = 0; // The type flags.
4278 BOOL fAnsi = FALSE; // Is the structure marked as CharSet=Ansi.
4279 BOOL fIsStringBuilder = FALSE;
4283 pInternalImport = pMT->GetMDImport();
4284 pModule = pMT->GetModule();
4286 // Just be sure the count is zero if the pointer is.
4287 if (pbNativeSig == NULL)
4290 // Grab the native marshaling type.
4291 if (cbNativeSig > 0)
4293 cbNativeElem = CorSigUncompressData(pbNativeSig, &nativeElem);
4294 pbNativeSig += cbNativeElem;
4295 cbNativeSig -= cbNativeElem;
4297 // AsAny makes no sense for COM Interop. Ignore it.
4298 if (nativeElem == NATIVE_TYPE_ASANY)
4300 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_ASANY);
4305 // If we are dealing with a struct, determine if it is marked as CharSet=Ansi.
4308 // Make sure one of Auto, Ansi or Unicode is specified.
4309 if (!IsTdAnsiClass(dwTypeFlags) && !IsTdAutoClass(dwTypeFlags) && !IsTdUnicodeClass(dwTypeFlags))
4311 _ASSERTE(!"Bad stringformat value in wrapper class.");
4312 ReportWarning(TLBX_E_BAD_SIGNATURE, E_FAIL); // bad metadata
4313 hr = TLBX_E_BAD_SIGNATURE;
4317 if (FAILED(pInternalImport->GetTypeDefProps(pMT->GetCl(), &dwTypeFlags, NULL)))
4319 ReportWarning(TLBX_E_BAD_SIGNATURE, E_FAIL);
4320 hr = TLBX_E_BAD_SIGNATURE;
4323 fAnsi = IsTdAnsiClass(dwTypeFlags);
4326 // Get the element type.
4328 cbElem += CorSigUncompressData(pbSig+cbElem, &elem);
4330 // Handle the custom marshaler native type separately.
4331 if (elem != ELEMENT_TYPE_BYREF && nativeElem == NATIVE_TYPE_CUSTOMMARSHALER)
4335 case ELEMENT_TYPE_VAR:
4336 case ELEMENT_TYPE_CLASS:
4337 case ELEMENT_TYPE_OBJECT:
4338 // @TODO(DM): Ask the custom marshaler for the ITypeInfo to use for the unmanaged type.
4339 ptdesc->vt = VT_UNKNOWN;
4342 case ELEMENT_TYPE_STRING:
4343 case ELEMENT_TYPE_SZARRAY:
4344 case ELEMENT_TYPE_ARRAY:
4345 ptdesc->vt = GetVtForIntPtr();
4349 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
4350 return(TLBX_E_BAD_SIGNATURE);
4354 // Eat the rest of the signature. The extra -1's are to account
4355 // for the byte parsed off above.
4356 SigPointer p(&pbSig[cbElem-1]);
4357 IfFailThrow(p.SkipExactlyOne());
4358 cbElem += (ULONG)(p.GetPtr() - &pbSig[cbElem]); // Note I didn't use -1 here.
4362 // This label is used to try again with a new element type, but without consuming more signature.
4363 // Usage is to set 'elem' to a new value, goto this label.
4367 case ELEMENT_TYPE_END: // 0x0,
4368 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_UNKNOWN_SIGNATURE);
4369 return(TLBX_E_BAD_SIGNATURE);
4372 case ELEMENT_TYPE_VOID: // 0x1,
4373 ptdesc->vt = VT_VOID;
4376 case ELEMENT_TYPE_BOOLEAN: // 0x2,
4380 ptdesc->vt = static_cast<VARTYPE>(bMethodSig ? VT_BOOL : VT_I4);
4383 case NATIVE_TYPE_VARIANTBOOL:
4384 ptdesc->vt = VT_BOOL;
4387 case NATIVE_TYPE_BOOLEAN:
4391 case NATIVE_TYPE_U1:
4392 case NATIVE_TYPE_I1:
4393 ptdesc->vt = VT_UI1;
4397 DEBUG_STMT(DbgWriteEx(W("Bad Native COM attribute specified!\n")));
4398 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
4399 return(TLBX_E_BAD_SIGNATURE);
4403 case ELEMENT_TYPE_CHAR: // 0x3,
4404 if (nativeElem == 0)
4406 if (!bMethodSig && IsTdAutoClass(dwTypeFlags))
4408 // Types with a char set of auto and that would be represented differently
4409 // on different platforms are not allowed to be exported to COM.
4410 DefineFullyQualifiedNameForClassW();
4411 LPCWSTR szName = GetFullyQualifiedNameForClassW(pMT);
4414 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_AUTO_CS_NOT_ALLOWED, szName);
4415 hr = TLBX_E_BAD_SIGNATURE;
4419 ptdesc->vt = static_cast<VARTYPE>(fAnsi ? VT_UI1 : VT_UI2);
4426 case NATIVE_TYPE_U2:
4427 case NATIVE_TYPE_I2:
4428 ptdesc->vt = VT_UI2;
4431 case NATIVE_TYPE_U1:
4432 case NATIVE_TYPE_I1:
4433 ptdesc->vt = VT_UI1;
4437 DEBUG_STMT(DbgWriteEx(W("Bad Native COM attribute specified!\n")));
4438 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
4439 hr = TLBX_E_BAD_SIGNATURE;
4445 case ELEMENT_TYPE_I1: // 0x4,
4449 case ELEMENT_TYPE_U1: // 0x5,
4450 ptdesc->vt = VT_UI1;
4453 case ELEMENT_TYPE_I2: // 0x6,
4457 case ELEMENT_TYPE_U2: // 0x7,
4458 ptdesc->vt = VT_UI2;
4461 case ELEMENT_TYPE_I4: // 0x8,
4465 case NATIVE_TYPE_I4:
4466 case NATIVE_TYPE_U4: case NATIVE_TYPE_INTF: //@todo: Fix Microsoft.Win32.Interop.dll and remove this line.
4470 case NATIVE_TYPE_ERROR:
4471 ptdesc->vt = VT_HRESULT;
4475 DEBUG_STMT(DbgWriteEx(W("Bad Native COM attribute specified!\n")));
4476 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
4477 hr = TLBX_E_BAD_SIGNATURE;
4482 case ELEMENT_TYPE_U4: // 0x9,
4486 case NATIVE_TYPE_U4:
4487 ptdesc->vt = VT_UI4;
4490 case NATIVE_TYPE_ERROR:
4491 ptdesc->vt = VT_HRESULT;
4495 DEBUG_STMT(DbgWriteEx(W("Bad Native COM attribute specified!\n")));
4496 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
4497 hr = TLBX_E_BAD_SIGNATURE;
4502 case ELEMENT_TYPE_I8: // 0xa,
4506 case ELEMENT_TYPE_U8: // 0xb,
4507 ptdesc->vt = VT_UI8;
4510 case ELEMENT_TYPE_R4: // 0xc,
4514 case ELEMENT_TYPE_R8: // 0xd,
4518 case ELEMENT_TYPE_OBJECT:
4521 case ELEMENT_TYPE_STRING: // 0xe,
4523 if (nativeElem == 0)
4527 ptdesc->vt = VT_BSTR;
4531 if (IsTdAutoClass(dwTypeFlags))
4533 // Types with a char set of auto and that would be represented differently
4534 // on different platforms are not allowed to be exported to COM.
4535 DefineFullyQualifiedNameForClassW();
4536 LPCWSTR szName = GetFullyQualifiedNameForClassW(pMT);
4539 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_AUTO_CS_NOT_ALLOWED, szName);
4540 hr = TLBX_E_BAD_SIGNATURE;
4544 ptdesc->vt = static_cast<VARTYPE>(fAnsi ? VT_LPSTR : VT_LPWSTR);
4551 case NATIVE_TYPE_BSTR:
4552 if (fIsStringBuilder)
4554 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
4555 hr = TLBX_E_BAD_SIGNATURE;
4558 ptdesc->vt = VT_BSTR;
4561 case NATIVE_TYPE_LPSTR:
4562 ptdesc->vt = VT_LPSTR;
4565 case NATIVE_TYPE_LPWSTR:
4566 ptdesc->vt = VT_LPWSTR;
4569 case NATIVE_TYPE_LPTSTR:
4571 // NATIVE_TYPE_LPTSTR is not allowed to be exported to COM.
4572 DefineFullyQualifiedNameForClassW();
4573 LPCWSTR szName = GetFullyQualifiedNameForClassW(pMT);
4575 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_LPTSTR_NOT_ALLOWED, szName);
4576 hr = TLBX_E_BAD_SIGNATURE;
4579 case NATIVE_TYPE_FIXEDSYSSTRING:
4580 // NATIVE_TYPE_FIXEDSYSSTRING is only allowed on fields.
4583 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
4584 hr = TLBX_E_BAD_SIGNATURE;
4588 // Retrieve the count of characters.
4589 if (cbNativeSig != 0)
4591 cb = CorSigUncompressData(pbNativeSig, &nativeCount);
4600 // Fixed strings become embedded array's of characters.
4601 ptdesc->vt = VT_CARRAY;
4602 ptdesc->lpadesc = reinterpret_cast<ARRAYDESC*>(ppool->AllocZero(sizeof(ARRAYDESC)));
4603 if (ptdesc->lpadesc == NULL)
4604 IfFailReport(E_OUTOFMEMORY);
4606 // Set the count of characters.
4607 ptdesc->lpadesc->cDims = 1;
4608 ptdesc->lpadesc->rgbounds[0].cElements = nativeCount;
4609 ptdesc->lpadesc->rgbounds[0].lLbound = 0;
4611 if (IsTdAutoClass(dwTypeFlags))
4613 // Types with a char set of auto and that would be represented differently
4614 // on different platforms are not allowed to be exported to COM.
4615 DefineFullyQualifiedNameForClassW();
4616 LPCWSTR szName = GetFullyQualifiedNameForClassW(pMT);
4619 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_AUTO_CS_NOT_ALLOWED, szName);
4620 hr = TLBX_E_BAD_SIGNATURE;
4624 ptdesc->lpadesc->tdescElem.vt = static_cast<VARTYPE>(fAnsi ? VT_UI1 : VT_UI2);
4628 DEBUG_STMT(DbgWriteEx(W("Bad Native COM attribute specified!\n")));
4629 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
4630 hr = TLBX_E_BAD_SIGNATURE;
4636 // every type above PTR will be simple type
4637 case ELEMENT_TYPE_PTR: // 0xf,
4638 case ELEMENT_TYPE_BYREF: // 0x10,
4639 // TYPEDESC is a pointer.
4640 ptdesc->vt = VT_PTR;
4645 ptdesc->lptdesc = reinterpret_cast<TYPEDESC*>(ppool->AllocZero(sizeof(TYPEDESC)));
4646 if (ptdesc->lptdesc == NULL)
4647 IfFailReport(E_OUTOFMEMORY);
4649 hr = CorSigToTypeDesc(pCTI, pMT, &pbSig[cbElem], pbNativeSig-cbNativeElem,
4650 cbNativeSig+cbNativeElem, &cb, ptdesc->lptdesc, ppool, bMethodSig);
4658 case ELEMENT_TYPE_CLASS: // 0x12,
4659 case ELEMENT_TYPE_VALUETYPE:
4661 cb = CorSigUncompressToken(&pbSig[cbElem], &tkTypeRef);
4664 if (TypeFromToken(tkTypeRef) == mdtTypeDef)
4666 // Get the name of the TypeDef.
4667 if (FAILED(pInternalImport->GetNameOfTypeDef(tkTypeRef, &pclsname, &pNS)))
4669 IfFailReport(COR_E_BADIMAGEFORMAT);
4674 // Get the name of the TypeRef.
4675 _ASSERTE(TypeFromToken(tkTypeRef) == mdtTypeRef);
4676 IfFailReport(pInternalImport->GetNameOfTypeRef(tkTypeRef, &pNS, &pclsname));
4681 sName.MakeFullNamespacePath(SString(SString::Utf8, pNS), SString(SString::Utf8, pclsname));
4682 StackScratchBuffer scratch;
4683 pclsname = sName.GetUTF8(scratch);
4686 _ASSERTE(strlen(szRuntime) == cbRuntime); // If you rename System, fix this invariant.
4687 _ASSERTE(strlen(szText) == cbText); // If you rename System.Text, fix this invariant.
4689 // Is it System.something?
4690 if (SString::_strnicmp(pclsname, szRuntime, cbRuntime) == 0)
4693 LPCUTF8 pcls; pcls = pclsname + cbRuntime;
4694 if (stricmpUTF8(pcls, szStringClass) == 0)
4698 else if (stricmpUTF8(pcls, szDateTimeClass) == 0)
4700 ptdesc->vt = VT_DATE;
4703 else if (stricmpUTF8(pcls, szDecimalClass) == 0)
4707 case NATIVE_TYPE_CURRENCY:
4708 // Make this a currency.
4713 // Make this a decimal
4714 ptdesc->vt = VT_DECIMAL;
4718 DEBUG_STMT(DbgWriteEx(W("Bad Native COM attribute specified!\n")));
4719 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
4720 hr = TLBX_E_BAD_SIGNATURE;
4725 else if (stricmpUTF8(pcls, szGuidClass) == 0)
4729 case NATIVE_TYPE_LPSTRUCT:
4730 // Make this a pointer to . . .
4731 ptdesc->vt = VT_PTR;
4735 ptdesc->lptdesc = reinterpret_cast<TYPEDESC*>(ppool->AllocZero(sizeof(TYPEDESC)));
4736 if (ptdesc->lptdesc == NULL)
4737 IfFailReport(E_OUTOFMEMORY);
4739 // . . . a user defined type for GUID
4740 ptdesc->lptdesc->vt = VT_USERDEFINED;
4741 GetRefTypeInfo(pCTI, m_pGuid, &ptdesc->lptdesc->hreftype);
4745 case NATIVE_TYPE_STRUCT:
4746 // a user defined type for GUID
4747 ptdesc->vt = VT_USERDEFINED;
4748 GetRefTypeInfo(pCTI, m_pGuid, &ptdesc->hreftype);
4752 DEBUG_STMT(DbgWriteEx(W("Bad Native COM attribute specified!\n")));
4753 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
4754 hr = TLBX_E_BAD_SIGNATURE;
4759 else if (stricmpUTF8(pcls, szArrayClass) == 0)
4761 // If no native type is specified then assume its a NATIVE_TYPE_INTF.
4762 if (nativeElem == 0)
4763 nativeElem = NATIVE_TYPE_INTF;
4765 if (nativeElem == NATIVE_TYPE_SAFEARRAY)
4767 // Compat: If no safe array used def subtype was specified we will map it to a SAFEARRAY of VARIANTs.
4768 ULONG vtElement = VT_VARIANT;
4769 TypeHandle thElement = TypeHandle(g_pObjectClass);
4771 if (cbNativeSig > 0)
4773 // Retrieve the safe array sub type.
4774 cb = CorSigUncompressData(pbNativeSig, &vtElement);
4778 // Get the type name if specified.
4779 if (cbNativeSig > 0)
4783 cb = CorSigUncompressData(pbNativeSig, &cbClass);
4789 // Load the type. Use an SString for the string since we need to NULL terminate the string
4790 // that comes from the metadata.
4791 StackScratchBuffer utf8Name;
4792 SString safeArrayUserDefTypeName(SString::Utf8, (LPUTF8)pbNativeSig, cbClass);
4793 thElement = LoadClass(pMT->GetModule(), safeArrayUserDefTypeName.GetUTF8(utf8Name));
4801 // The field marshaller converts these to SAFEARRAYs of the type specified
4802 // at runtime by the array. This isn't expressible in a type library
4803 // so provide a warning.
4804 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_W_BAD_SAFEARRAYFIELD_NO_ELEMENTVT);
4808 ArrayMarshalInfo arrayMarshalInfo(IsExportingAs64Bit() ? amiExport64Bit : amiExport32Bit);
4809 MarshalInfo::MarshalScenario ms = bMethodSig ? MarshalInfo::MARSHAL_SCENARIO_COMINTEROP : MarshalInfo::MARSHAL_SCENARIO_FIELD;
4810 arrayMarshalInfo.InitForSafeArray(ms, thElement, (VARTYPE)vtElement, fAnsi);
4812 if (!arrayMarshalInfo.IsValid())
4814 ReportWarning(TLBX_E_BAD_SIGNATURE, arrayMarshalInfo.GetErrorResourceId());
4815 hr = TLBX_E_BAD_SIGNATURE;
4819 // TYPEDESC is an array.
4820 ptdesc->vt = VT_SAFEARRAY;
4821 ptdesc->lptdesc = reinterpret_cast<TYPEDESC*>(ppool->AllocZero(sizeof(TYPEDESC)));
4822 if (ptdesc->lptdesc == NULL)
4823 IfFailReport(E_OUTOFMEMORY);
4825 ArrayToTypeDesc(pCTI, ppool, &arrayMarshalInfo, ptdesc->lptdesc);
4829 else if (nativeElem == NATIVE_TYPE_FIXEDARRAY)
4831 // NATIVE_TYPE_FIXEDARRAY is only allowed on fields.
4834 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
4835 hr = TLBX_E_BAD_SIGNATURE;
4839 // Retrieve the size of the fixed array. This is required.
4840 if (cbNativeSig == 0)
4842 ReportWarning(TLBX_E_BAD_SIGNATURE, IDS_EE_BADMARSHALFIELD_FIXEDARRAY_NOSIZE);
4843 hr = TLBX_E_BAD_SIGNATURE;
4847 cb = CorSigUncompressData(pbNativeSig, &nativeCount);
4851 // A size const of 0 isn't supported.
4852 if (nativeCount == 0)
4854 ReportWarning(TLBX_E_BAD_SIGNATURE, IDS_EE_BADMARSHALFIELD_FIXEDARRAY_ZEROSIZE);
4855 hr = TLBX_E_BAD_SIGNATURE;
4859 // Since these always export to arrays of BSTRs, we don't need to fetch the native type.
4862 ptdesc->vt = VT_CARRAY;
4863 ptdesc->lpadesc = NULL;
4864 ptdesc->lpadesc = reinterpret_cast<ARRAYDESC*>(ppool->AllocZero(sizeof(ARRAYDESC)));
4865 if (ptdesc->lpadesc == NULL)
4866 IfFailReport(E_OUTOFMEMORY);
4868 // Compat: FixedArrays of System.Arrays map to fixed arrays of BSTRs.
4869 ptdesc->lpadesc->tdescElem.vt = VT_BSTR;
4870 ptdesc->lpadesc->cDims = 1;
4871 ptdesc->lpadesc->rgbounds->cElements = nativeCount;
4872 ptdesc->lpadesc->rgbounds->lLbound = 0;
4876 else if (nativeElem != NATIVE_TYPE_INTF)
4878 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
4879 hr = TLBX_E_BAD_SIGNATURE;
4883 // If the native type is NATIVE_TYPE_INTF then we fall through and convert
4884 // System.Array to its IClassX interface.
4886 else if (stricmpUTF8(pcls, szObjectClass) == 0)
4889 // This next statement is to work around a "feature" that marshals an object inside
4890 // a struct as an interface, instead of as a variant. fieldmarshal metadata
4891 // can override that.
4892 if (nativeElem == 0 && !bMethodSig)
4893 nativeElem = NATIVE_TYPE_IUNKNOWN;
4897 case NATIVE_TYPE_INTF:
4898 case NATIVE_TYPE_IUNKNOWN:
4899 // an IUnknown based interface.
4900 ptdesc->vt = VT_UNKNOWN;
4903 case NATIVE_TYPE_IDISPATCH:
4904 // an IDispatch based interface.
4905 ptdesc->vt = VT_DISPATCH;
4909 case NATIVE_TYPE_STRUCT:
4911 ptdesc->vt = VT_VARIANT;
4915 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
4916 hr = TLBX_E_BAD_SIGNATURE;
4923 if (SString::_strnicmp(pclsname, szText, cbText) == 0)
4925 LPCUTF8 pcls; pcls = pclsname + cbText;
4926 if (stricmpUTF8(pcls, szStringBufferClass) == 0)
4928 fIsStringBuilder = TRUE;
4930 // If there is no fieldmarshal information, marshal as a LPWSTR
4931 if (nativeElem == 0)
4932 nativeElem = NATIVE_TYPE_LPWSTR;
4934 // Marshaller treats stringbuilders as [in, out] by default.
4942 if (SString::_strnicmp(pclsname, szCollections, cbCollections) == 0)
4944 LPCUTF8 pcls; pcls = pclsname + cbCollections;
4945 if (stricmpUTF8(pcls, szIEnumeratorClass) == 0)
4947 StdOleTypeToHRef(pCTI, IID_IEnumVARIANT, &hRef);
4948 ptdesc->vt = VT_PTR;
4949 ptdesc->lptdesc = reinterpret_cast<TYPEDESC*>(ppool->AllocZero(sizeof(TYPEDESC)));
4950 if (ptdesc->lptdesc == NULL)
4951 IfFailReport(E_OUTOFMEMORY);
4953 ptdesc->lptdesc->vt = VT_USERDEFINED;
4954 ptdesc->lptdesc->hreftype = hRef;
4957 } // System.Collections
4959 if (SString::_strnicmp(pclsname, szDrawing, cbDrawing) == 0)
4961 LPCUTF8 pcls; pcls = pclsname + cbDrawing;
4962 if (stricmpUTF8(pcls, szColor) == 0)
4964 StdOleTypeToHRef(pCTI, GUID_OleColor, &hRef);
4965 ptdesc->vt = VT_USERDEFINED;
4966 ptdesc->hreftype = hRef;
4971 // It is not a built-in VT type, so build the typedesc.
4973 // Determine whether the type is a reference type (IUnknown derived) or a struct type.
4974 // Get the MethodTable for the referenced class.
4975 MethodTable *pRefdClass; // MethodTable object for referenced TypeDef.
4976 pRefdClass = LoadClass(pMT->GetModule(), tkTypeRef);
4978 // Is the type a ref type or a struct type. Note that a ref type that has layout
4979 // is exported as a TKIND_RECORD but is referenced as a **Foo, whereas a
4980 // value type is also exported as a TKIND_RECORD but is referenced as a *Foo.
4981 if (elem == ELEMENT_TYPE_CLASS)
4983 // Check if it is a delegate (which can be marshaled as a function pointer).
4984 if (COMDelegate::IsDelegate(pRefdClass))
4986 if (nativeElem == NATIVE_TYPE_FUNC)
4988 ptdesc->vt = GetVtForIntPtr();
4991 else if (nativeElem != 0 && nativeElem != NATIVE_TYPE_INTF)
4993 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
4994 hr = TLBX_E_BAD_SIGNATURE;
4998 else if (TypeHandle(pRefdClass).CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__SAFE_HANDLE))))
5000 ptdesc->vt = GetVtForIntPtr();
5003 else if (TypeHandle(pRefdClass).CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__CRITICAL_HANDLE))))
5005 ptdesc->vt = GetVtForIntPtr();
5009 if (pRefdClass->HasLayout())
5011 if (nativeElem == NATIVE_TYPE_INTF)
5013 // Classes with layout are exported as structs. Because of this, we can't export field or
5014 // parameters of these types marked with [MarshalAs(UnmanagedType.Interface)] as interface
5015 // pointers of the actual type. The best we can do is make them IUnknown pointers and
5016 // provide a warning.
5017 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_W_LAYOUTCLASS_AS_INTERFACE);
5018 ptdesc->vt = VT_UNKNOWN;
5021 else if (!bMethodSig)
5023 // Classes with layout inside structures must be either marked with [MarshalAs(UnmanagedType.Interface)],
5024 // [MarshalAs(UnmanagedType.Struct)] or not have any MarshalAs information.
5025 if ((nativeElem != 0) && (nativeElem != NATIVE_TYPE_STRUCT))
5027 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
5028 hr = TLBX_E_BAD_SIGNATURE;
5032 // These types are embedded structures so we can treat them as value classes.
5033 goto IsStructWithLayout;
5037 // Classes with layout as parameters must be either marked with [MarshalAs(UnmanagedType.Interface)]
5038 // [MarshalAs(UnmanagedType.LPStruct)] or not have any MarshalAs information.
5039 if ((nativeElem != 0) && (nativeElem != NATIVE_TYPE_LPSTRUCT))
5041 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
5042 hr = TLBX_E_BAD_SIGNATURE;
5048 // A reference to some non-system-defined/non delegate derived type. Get the reference to the
5049 // type, unless it is an imported COM type, in which case, we'll just use
5051 // If the type is not visible from COM then we return S_USEIUNKNOWN.
5052 if (!IsTypeVisibleFromCom(TypeHandle(pRefdClass)))
5055 hr = EEClassToHref(pCTI, pRefdClass, TRUE, &hRef);
5057 if (hr == S_USEIUNKNOWN)
5059 // Not a known type, so use IUnknown
5060 ptdesc->vt = VT_UNKNOWN;
5064 // Not a known class, so make this a pointer to . . .
5065 ptdesc->vt = VT_PTR;
5066 ptdesc->lptdesc = reinterpret_cast<TYPEDESC*>(ppool->AllocZero(sizeof(TYPEDESC)));
5067 if (ptdesc->lptdesc == NULL)
5068 IfFailReport(E_OUTOFMEMORY);
5070 // . . . a user defined type . . .
5071 ptdesc->lptdesc->vt = VT_USERDEFINED;
5072 // . . . based on the token.
5073 ptdesc->lptdesc->hreftype = hRef;
5075 else // It's a value type.
5078 // If it is an enum, check the underlying type. All COM enums are 32 bits,
5079 // so if the .Net enum is not a 32 bit enum, convert to the underlying type
5080 // instead of the enum type.
5081 if (pRefdClass->IsEnum())
5083 // Get the element type of the underlying type.
5084 CorElementType et = pRefdClass->GetInternalCorElementType();
5085 // If it is not a 32-bit type or MarshalAs is specified, convert as the
5087 if ((et != ELEMENT_TYPE_I4 && et != ELEMENT_TYPE_U4) ||
5091 goto TryWithElemType;
5093 // Fall through to convert as the enum type.
5097 // Value classes must be either marked with [MarshalAs(UnmanagedType.Struct)]
5098 // or not have any MarshalAs information.
5099 if ((nativeElem != 0) && (nativeElem != NATIVE_TYPE_STRUCT))
5101 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
5102 hr = TLBX_E_BAD_SIGNATURE;
5107 // A reference to some non-system-defined type. Get the reference to the
5108 // type. Since this is a value class we must get a valid href. Otherwise
5109 // we fail the conversion.
5110 hr = TokenToHref(pCTI, pMT, tkTypeRef, FALSE, &hRef);
5111 if (hr == S_USEIUNKNOWN)
5114 sClsName.SetUTF8(pclsname);
5116 LPCWSTR szVCName = sClsName.GetUnicode();
5117 if (NAMESPACE_SEPARATOR_WCHAR == *szVCName)
5120 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_NONVISIBLEVALUECLASS, szVCName);
5121 hr = TLBX_E_BAD_SIGNATURE;
5125 // Value class is like other UserDefined types, except passed by value, ie
5126 // on the stack, instead of by pointer.
5127 // . . . a user defined type . . .
5128 ptdesc->vt = VT_USERDEFINED;
5129 // . . . based on the token.
5130 ptdesc->hreftype = hRef;
5134 case ELEMENT_TYPE_SZARRAY:
5135 case ELEMENT_TYPE_ARRAY:
5137 SigPointer sig(&pbSig[cbElem]);
5139 // Retrieve the type handle for the array elements.
5140 TypeHandle thElement = sig.GetTypeHandleThrowing(pModule, &emptyTypeContext);
5141 _ASSERTE(!thElement.IsNull());
5143 // Update the index into the managed signature array.
5144 IfFailThrow(sig.SkipExactlyOne());
5145 cbElem += static_cast<ULONG>(sig.GetPtr() - &pbSig[cbElem]);
5150 case NATIVE_TYPE_SAFEARRAY:
5152 ULONG vtElement = VT_EMPTY;
5154 // Retrieve the safe array element type.
5155 if (cbNativeSig != 0)
5157 cb = CorSigUncompressData(pbNativeSig, &vtElement);
5162 ArrayMarshalInfo arrayMarshalInfo(IsExportingAs64Bit() ? amiExport64Bit : amiExport32Bit);
5163 MarshalInfo::MarshalScenario ms = bMethodSig ? MarshalInfo::MARSHAL_SCENARIO_COMINTEROP : MarshalInfo::MARSHAL_SCENARIO_FIELD;
5164 arrayMarshalInfo.InitForSafeArray(ms, thElement, (VARTYPE)vtElement, fAnsi);
5166 if (!arrayMarshalInfo.IsValid())
5168 ReportWarning(TLBX_E_BAD_SIGNATURE, arrayMarshalInfo.GetErrorResourceId());
5169 hr = TLBX_E_BAD_SIGNATURE;
5173 // TYPEDESC is an array.
5174 ptdesc->vt = VT_SAFEARRAY;
5175 ptdesc->lptdesc = reinterpret_cast<TYPEDESC*>(ppool->AllocZero(sizeof(TYPEDESC)));
5176 if (ptdesc->lptdesc == NULL)
5177 IfFailReport(E_OUTOFMEMORY);
5179 ArrayToTypeDesc(pCTI, ppool, &arrayMarshalInfo, ptdesc->lptdesc);
5183 case NATIVE_TYPE_FIXEDARRAY:
5185 ULONG ntElement = NATIVE_TYPE_DEFAULT;
5187 // NATIVE_TYPE_FIXEDARRAY is only allowed on fields.
5190 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
5191 hr = TLBX_E_BAD_SIGNATURE;
5195 // Retrieve the size of the fixed array. This is required.
5196 if (cbNativeSig == 0)
5198 ReportWarning(TLBX_E_BAD_SIGNATURE, IDS_EE_BADMARSHALFIELD_FIXEDARRAY_NOSIZE);
5199 hr = TLBX_E_BAD_SIGNATURE;
5203 cb = CorSigUncompressData(pbNativeSig, &nativeCount);
5207 // A size const of 0 isn't supported.
5208 if (nativeCount == 0)
5210 ReportWarning(TLBX_E_BAD_SIGNATURE, IDS_EE_BADMARSHALFIELD_FIXEDARRAY_ZEROSIZE);
5211 hr = TLBX_E_BAD_SIGNATURE;
5215 // Read the optional array sub type if specified.
5216 if (cbNativeSig != 0)
5218 cb = CorSigUncompressData(pbNativeSig, &ntElement);
5223 ArrayMarshalInfo arrayMarshalInfo(IsExportingAs64Bit() ? amiExport64Bit : amiExport32Bit);
5224 arrayMarshalInfo.InitForFixedArray(thElement, (CorNativeType)ntElement, fAnsi);
5226 if (!arrayMarshalInfo.IsValid())
5228 ReportWarning(TLBX_E_BAD_SIGNATURE, arrayMarshalInfo.GetErrorResourceId());
5229 hr = TLBX_E_BAD_SIGNATURE;
5234 ptdesc->vt = VT_CARRAY;
5235 ptdesc->lpadesc = reinterpret_cast<ARRAYDESC*>(ppool->AllocZero(sizeof(ARRAYDESC)));
5236 if (ptdesc->lpadesc == NULL)
5237 IfFailReport(E_OUTOFMEMORY);
5239 ArrayToTypeDesc(pCTI, ppool, &arrayMarshalInfo, &ptdesc->lpadesc->tdescElem);
5241 ptdesc->lpadesc->cDims = 1;
5242 ptdesc->lpadesc->rgbounds->cElements = nativeCount;
5243 ptdesc->lpadesc->rgbounds->lLbound = 0;
5247 case NATIVE_TYPE_ARRAY:
5249 ULONG ntElement = NATIVE_TYPE_DEFAULT;
5251 // NATIVE_TYPE_ARRAY is not allowed on fields.
5254 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_ARRAY_NEEDS_NT_FIXED);
5255 hr = TLBX_E_BAD_SIGNATURE;
5259 // Read the optional array sub type if specified.
5260 if (cbNativeSig != 0)
5262 cb = CorSigUncompressData(pbNativeSig, &ntElement);
5267 ArrayMarshalInfo arrayMarshalInfo(IsExportingAs64Bit() ? amiExport64Bit : amiExport32Bit);
5268 arrayMarshalInfo.InitForNativeArray(MarshalInfo::MARSHAL_SCENARIO_COMINTEROP, thElement, (CorNativeType)ntElement, fAnsi);
5270 if (!arrayMarshalInfo.IsValid())
5272 ReportWarning(TLBX_E_BAD_SIGNATURE, arrayMarshalInfo.GetErrorResourceId());
5273 hr = TLBX_E_BAD_SIGNATURE;
5277 ptdesc->vt = VT_PTR;
5278 ptdesc->lptdesc = reinterpret_cast<TYPEDESC*>(ppool->AllocZero(sizeof(TYPEDESC)));
5279 if(ptdesc->lptdesc == NULL)
5280 IfFailReport(E_OUTOFMEMORY);
5282 ArrayToTypeDesc(pCTI, ppool, &arrayMarshalInfo, ptdesc->lptdesc);
5287 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
5288 hr = TLBX_E_BAD_SIGNATURE;
5292 // If we are dealing with an ELEMENT_TYPE_ARRAY, we need to eat the array description.
5293 if (elem == ELEMENT_TYPE_ARRAY)
5296 cbElem += CorSigUncompressData(pbSig+cbElem, &elem);
5298 // Count of ubounds, ubounds.
5299 cbElem += CorSigUncompressData(pbSig+cbElem, &elem);
5300 for (i=elem; i>0; --i)
5301 cbElem += CorSigUncompressData(pbSig+cbElem, &elem);
5303 // Count of lbounds, lbounds.
5304 cbElem += CorSigUncompressData(pbSig+cbElem, &elem);
5305 for (i=elem; i>0; --i)
5306 cbElem += CorSigUncompressData(pbSig+cbElem, &elem);
5312 case ELEMENT_TYPE_TYPEDBYREF: // 0x16
5313 ptdesc->vt = VT_VARIANT;
5316 //------------------------------------------
5317 // This really should be the commented out
5319 case ELEMENT_TYPE_I: // 0x18,
5320 ptdesc->vt = GetVtForIntPtr();
5323 case ELEMENT_TYPE_U: // 0x19,
5324 ptdesc->vt = GetVtForUIntPtr();
5327 case ELEMENT_TYPE_CMOD_REQD: // 0x1F // required C modifier : E_T_CMOD_REQD <mdTypeRef/mdTypeDef>
5328 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_UNKNOWN_SIGNATURE);
5329 hr = TLBX_E_BAD_SIGNATURE;
5332 case ELEMENT_TYPE_SENTINEL:
5335 case ELEMENT_TYPE_CMOD_OPT: // 0x20 // optional C modifier : E_T_CMOD_OPT <mdTypeRef/mdTypeDef>
5336 cb = CorSigUncompressToken(&pbSig[cbElem], &tkTypeRef);
5340 case ELEMENT_TYPE_FNPTR:
5342 ptdesc->vt = GetVtForIntPtr();
5344 // Eat the rest of the signature.
5345 SigPointer p(&pbSig[cbElem-1]);
5346 IfFailThrow(p.SkipExactlyOne());
5347 cbElem += (ULONG)(p.GetPtr() - &pbSig[cbElem]); // Note I didn't use -1 here.
5351 case ELEMENT_TYPE_GENERICINST:
5352 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_GENERICINST_SIGNATURE);
5353 hr = TLBX_E_BAD_SIGNATURE;
5357 case ELEMENT_TYPE_VAR:
5358 case ELEMENT_TYPE_MVAR:
5359 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_GENERICPAR_SIGNATURE);
5360 hr = TLBX_E_BAD_SIGNATURE;
5365 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_UNKNOWN_SIGNATURE);
5366 hr = TLBX_E_BAD_SIGNATURE;
5374 if (hr == S_USEIUNKNOWN)
5378 } // TypeLibExporter::CorSigToTypeDesc
5380 #pragma warning(pop)
5383 //*****************************************************************************
5384 // Get an HREFTYPE for an ITypeInfo, in the context of a ICreateTypeInfo2.
5385 //*****************************************************************************
5386 HRESULT TypeLibExporter::TokenToHref(
5387 ICreateTypeInfo2 *pCTI, // Typeinfo being created.
5388 MethodTable *pMT, // MethodTable with the token.
5389 mdToken tk, // The TypeRef to resolve.
5390 BOOL bWarnOnUsingIUnknown, // A flag indicating if we should warn on substituting IUnknown.
5391 HREFTYPE *pHref) // Put HREFTYPE here.
5396 PRECONDITION(CheckPointer(pCTI));
5397 PRECONDITION(CheckPointer(pMT));
5398 PRECONDITION(CheckPointer(pHref));
5402 MethodTable *pRefdClass; // MethodTable object for referenced TypeDef.
5404 // Get the MethodTable for the referenced class, and see if it is being converted.
5405 pRefdClass = LoadClass(pMT->GetModule(), tk);
5407 // If the type is not visible from COM then we return S_USEIUNKNOWN.
5408 if (!IsTypeVisibleFromCom(TypeHandle(pRefdClass)))
5409 return S_USEIUNKNOWN;
5411 return EEClassToHref(pCTI, pRefdClass, bWarnOnUsingIUnknown, pHref);
5412 } // HRESULT TypeLibExporter::TokenToHref()
5414 //*****************************************************************************
5415 // Call the resolver to export the typelib for an assembly.
5416 //*****************************************************************************
5417 void TypeLibExporter::ExportReferencedAssembly(
5418 Assembly *pAssembly)
5423 PRECONDITION(CheckPointer(pAssembly));
5427 HRESULT hr = S_OK; // A result.
5428 ITypeLib *pTLB = 0; // Exported typelib.
5431 SafeComHolder<IUnknown> pIAssembly = 0;
5434 // Switch to cooperative to get an object ref.
5437 // Invoke the callback to resolve the reference.
5438 OBJECTREF orAssembly=0;
5439 GCPROTECT_BEGIN(orAssembly)
5441 orAssembly = pAssembly->GetExposedObject();
5443 pIAssembly = GetComIPFromObjectRef(&orAssembly, MscorlibBinder::GetClass(CLASS__IASSEMBLY));
5448 IfFailReport(m_pNotify->ResolveRef((IUnknown*)pIAssembly, (IUnknown**)&pTLB));
5450 // If we got a typelib, store it on the assembly.
5452 pAssembly->SetTypeLib(pTLB);
5453 } // void TypeLibExporter::ExportReferencedAssembly()
5455 //*****************************************************************************
5456 // Determine if a class represents a well-known interface, and return that
5457 // interface (from its real typelib) if it does.
5458 //*****************************************************************************
5459 void TypeLibExporter::GetWellKnownInterface(
5460 MethodTable *pMT, // MethodTable to check.
5461 ITypeInfo **ppTI) // Put ITypeInfo here, if found.
5466 PRECONDITION(CheckPointer(pMT));
5467 PRECONDITION(CheckPointer(ppTI));
5471 HRESULT hr; // A result.
5472 GUID guid; // The MethodTable guid.
5473 WCHAR wzGuid[40]; // Guid in string format.
5474 LONG cbGuid; // Size of guid buffer.
5475 GUID guidTlb; // The typelib guid.
5476 DWORD dwError; // Note: HRESULT_FROM_WIN32 macro evaluates the argument 3x times
5479 HKEYHolder hInterface; // Registry key HKCR/Interface
5480 HKEYHolder hGuid; // Registry key of .../{xxx...xxx}
5481 HKEYHolder hTlb; // Registry key of .../TypeLib
5484 SafeComHolder<ITypeLib> pTLB=0;
5486 // Get the GUID for the class. Will generate from name if no defined GUID,
5487 // will also use signatures if interface.
5488 pMT->GetGuid(&guid, TRUE);
5490 GuidToLPWSTR(guid, wzGuid, lengthof(wzGuid));
5492 // Look up that interface in the registry.
5493 dwError = WszRegOpenKeyEx(HKEY_CLASSES_ROOT, W("Interface"),0,KEY_READ, &hInterface);
5494 hr = HRESULT_FROM_WIN32(dwError);
5498 dwError = WszRegOpenKeyEx((HKEY)hInterface, wzGuid, 0, KEY_READ, &hGuid);
5499 hr = HRESULT_FROM_WIN32(dwError);
5503 dwError = WszRegOpenKeyEx((HKEY)hGuid, W("TypeLib"), 0, KEY_READ, &hTlb);
5504 hr = HRESULT_FROM_WIN32(dwError);
5508 cbGuid = sizeof(wzGuid);
5509 dwError = WszRegQueryValue((HKEY)hTlb, W(""), wzGuid, &cbGuid);
5510 hr = HRESULT_FROM_WIN32(dwError);
5514 CLSIDFromString(wzGuid, &guidTlb);
5516 // Retrieve the major and minor version number.
5519 Assembly *pAssembly = pMT->GetAssembly();
5521 hr = GetTypeLibVersionForAssembly(pAssembly,&wMajor, &wMinor);
5524 hr = LoadRegTypeLib(guidTlb, wMajor, wMinor, 0, &pTLB);
5528 pAssembly->GetVersion(&wMajor, &wMinor, NULL, NULL);
5530 hr = LoadRegTypeLib(guidTlb, wMajor, wMinor, 0, &pTLB);
5533 hr = LoadRegTypeLib(guidTlb, -1, -1, 0, &pTLB);
5542 hr = pTLB->GetTypeInfoOfGuid(guid, ppTI);
5543 } // void TypeLibExporter::GetWellKnownInterface()
5545 //*****************************************************************************
5546 // Get an HREFTYPE for an ITypeInfo, in the context of a ICreateTypeInfo2.
5547 //*****************************************************************************
5548 HRESULT TypeLibExporter::EEClassToHref( // S_OK or error.
5549 ICreateTypeInfo2 *pCTI, // Typeinfo being created.
5550 MethodTable *pClass, // The MethodTable * to resolve.
5551 BOOL bWarnOnUsingIUnknown, // A flag indicating if we should warn on substituting IUnknown.
5552 HREFTYPE *pHref) // Put HREFTYPE here.
5557 PRECONDITION(CheckPointer(pCTI));
5558 PRECONDITION(CheckPointer(pClass));
5559 PRECONDITION(CheckPointer(pHref));
5563 HRESULT hr=S_OK; // A result.
5564 int bUseIUnknown=false; // Use IUnknown (if so, don't release pTI)?
5565 int bUseIUnknownWarned=false; // If true, used IUnknown, but already issued a more specific warning.
5566 CExportedTypesInfo sExported; // Cached ICreateTypeInfo pointers.
5567 CExportedTypesInfo *pExported; // Pointer to found or new cached pointers.
5568 CHrefOfClassHashKey sLookup; // Hash structure to lookup.
5569 CHrefOfClassHashKey *pFound; // Found structure.
5570 bool bImportedAssembly; // The assembly containing pClass is imported.
5571 bool bForceResolveCallback; // Type library resolution should always be handled by caller first.
5573 // A different typeinfo; default for pTI.
5574 SafeComHolder<ITypeInfo> pTIDef=0;
5576 // A TypeInfo; maybe for TypeDef, maybe for TypeRef.
5577 SafeComHolder<ITypeInfo> pTI=0;
5580 // See if we already know this MethodTable' href.
5581 sLookup.pClass = pClass;
5582 if ((pFound=m_HrefOfClassHash.Find(&sLookup)) != NULL)
5584 *pHref = pFound->href;
5585 if (*pHref == m_hIUnknown)
5586 return S_USEIUNKNOWN;
5590 // See if the class is in the export list.
5591 sExported.pClass = pClass;
5592 pExported = m_Exports.Find(&sExported);
5594 // If not in the exported assembly, possibly it was injected?
5597 pExported = m_InjectedExports.Find(&sExported);
5600 // Is there an export for this class?
5603 // Yes, For interfaces and value types (and enums), just use the typeinfo.
5604 if (pClass->IsValueType() || pClass->IsEnum() || pClass->HasLayout())
5606 // No default interface, so use the class itself.
5607 if (pExported->pCTI)
5608 IfFailReport(SafeQueryInterface(pExported->pCTI, IID_ITypeInfo, (IUnknown**)&pTI));
5611 if (!pClass->IsInterface())
5613 // If there is an explicit default interface, get the class for it.
5614 TypeHandle hndDefItfClass;
5615 DefaultInterfaceType DefItfType;
5616 DefItfType = GetDefaultInterfaceForClassWrapper(TypeHandle(pClass), &hndDefItfClass);
5619 case DefaultInterfaceType_Explicit:
5621 _ASSERTE(!hndDefItfClass.IsNull());
5623 // Recurse to get the href for the default interface class.
5624 hr = EEClassToHref(pCTI, hndDefItfClass.GetMethodTable(), bWarnOnUsingIUnknown, pHref);
5625 // Done. Note that the previous call will have cached the href for
5626 // the default interface class. As this function exits, it will
5627 // also cache the SAME href for this class.
5631 case DefaultInterfaceType_AutoDispatch:
5632 case DefaultInterfaceType_AutoDual:
5634 _ASSERTE(!hndDefItfClass.IsNull());
5636 if (hndDefItfClass.GetMethodTable() != pClass)
5638 // Recurse to get the href for the default interface class.
5639 hr = EEClassToHref(pCTI, hndDefItfClass.GetMethodTable(), bWarnOnUsingIUnknown, pHref);
5640 // Done. Note that the previous call will have cached the href for
5641 // the default interface class. As this function exits, it will
5642 // also cache the SAME href for this class.
5646 // Return the class interface.
5647 _ASSERTE(pExported->pCTIClassItf);
5648 IfFailReport(SafeQueryInterface(pExported->pCTIClassItf, IID_ITypeInfo, (IUnknown**)&pTI));
5652 case DefaultInterfaceType_IUnknown:
5653 case DefaultInterfaceType_BaseComClass:
5663 _ASSERTE(!"Invalid default interface type!");
5670 { // This is an interface, so use the typeinfo for the interface, if there is one.
5671 if (pExported->pCTI)
5672 IfFailReport(SafeQueryInterface(pExported->pCTI, IID_ITypeInfo, (IUnknown**)&pTI));
5675 if ((IUnknown*)pTI == 0)
5677 // This is a class from the module/assembly, yet it is not being exported.
5679 // Whatever happens, the result is OK.
5682 if (pClass->IsComImport())
5684 // If it is an imported type, get an href to it.
5685 GetWellKnownInterface(pClass, &pTI);
5688 // If still didn't get a TypeInfo, use IUnknown.
5689 if ((IUnknown*)pTI == 0)
5698 { // Not local. Try to get from the class' module's typelib.
5699 // If the caller wants to get a chance to resolve type library references themselves (before we go probing the assembly),
5700 // we'll skip the next step and go directly to the notify sink callback.
5701 bForceResolveCallback = (m_flags & TlbExporter_CallerResolvedReferences) != 0;
5702 if (!bForceResolveCallback)
5703 hr = GetITypeInfoForEEClass(pClass, &pTI, false/* interface, not coclass */, false/* do not create */, m_flags);
5705 // If getting the typeinfo from the class itself failed, there are
5706 // several possibilities:
5707 // - typelib didn't exist, and couldn't be created.
5708 // - typelib did exist, but didn't contain the typeinfo.
5709 // We can create a local (to the exported typelib) copy of the
5710 // typeinfo, and get a reference to that.
5711 // However, we don't want to export the whole tree into this typelib,
5712 // so we only create the typeinfo if the typelib existed but the
5713 // typeinfo wasn't found and the assembly is not an imported assembly.
5714 bImportedAssembly = pClass->GetAssembly()->IsImportedFromTypeLib();
5716 if (bForceResolveCallback || (FAILED(hr) && hr != TYPE_E_ELEMENTNOTFOUND && !bImportedAssembly))
5718 // Invoke the callback to resolve the reference.
5720 Assembly *pAssembly = pClass->GetAssembly();
5722 ExportReferencedAssembly(pAssembly);
5724 hr = GetITypeInfoForEEClass(pClass, &pTI, false/* interface, not coclass */, false/* do not create */, m_flags);
5727 if (hr == TYPE_E_ELEMENTNOTFOUND)
5729 if (pClass->IsComImport())
5731 // If it is an imported type, get an href to it.
5733 // Whatever happens, the result is OK.
5736 GetWellKnownInterface(pClass, &pTI);
5738 // If still didn't get a TypeInfo, use IUnknown.
5739 if ((IUnknown*)pTI == 0)
5748 // Convert the single typedef from the other scope.
5749 ConvertOneTypeDef(pClass);
5751 // Now that the type has been injected, recurse to let the default-interface code run.
5752 hr = EEClassToHref(pCTI, pClass, bWarnOnUsingIUnknown, pHref);
5754 // This class should already have been cached by the recursive call. Don't want to add
5759 else if (FAILED(hr))
5761 DefineFullyQualifiedNameForClassWOnStack();
5762 LPCWSTR szName = GetFullyQualifiedNameForClassNestedAwareW(pClass);
5763 if (hr == TLBX_W_LIBNOTREGISTERED)
5765 // The imported typelib is not registered on this machine. Give a warning, and substitute IUnknown.
5766 ReportEvent(NOTIF_CONVERTWARNING, hr, szName, (LPCWSTR) pClass->GetAssembly()->GetManifestModule()->GetPath());
5769 bUseIUnknown = true;
5771 bUseIUnknownWarned = true;
5773 else if (hr == TLBX_E_CANTLOADLIBRARY)
5775 // The imported typelib is registered, but can't be loaded. Corrupt? Missing?
5776 InternalThrowHRWithContext(TLBX_E_CANTLOADLIBRARY, szName, (LPCWSTR) pClass->GetAssembly()->GetManifestModule()->GetPath());
5782 // Make sure we could resolve the typeinfo.
5783 if (!(IUnknown*)pTI)
5784 IfFailReport(TYPE_E_ELEMENTNOTFOUND);
5786 // Assert that the containing typelib for pContainer is the typelib being created.
5789 SafeComHolder<ITypeInfo> pTI=0;
5790 SafeComHolder<ITypeLib> pTL=0;
5791 SafeComHolder<ITypeLib> pTLMe=0;
5793 SafeQueryInterface(pCTI, IID_ITypeInfo, (IUnknown**)&pTI);
5794 SafeQueryInterface(m_pICreateTLB, IID_ITypeLib, (IUnknown**)&pTLMe);
5795 pTI->GetContainingTypeLib(&pTL, &ix);
5796 _ASSERTE(pTL == pTLMe);
5800 // If there is an ITypeInfo, convert to HREFTYPE.
5803 if ((IUnknown*)pTI != m_pIUnknown)
5805 // Resolve to default.
5807 hr = S_OK; // Already have default.
5810 // TypeLib API has a issue (sort of by design):
5811 // Before a type (and its dependencies) is completely created (all members added),
5812 // if you call Layout(), or anything that will lead to Layout(), such as ITypeInfo::GetTypeAttr
5813 // it will give the type an incorrect size. Ideally TypeLib API should fail in this case.
5814 // Anyway, we only need to avoid calling Layout() directly or indirectly until we have
5815 // completely created all types.
5816 // In this case, we are calling ITypeInfo::GetTypeAttr() in the function below, which is only
5817 // needed for coclasses. Fortunately, coclass doesn't have a size problem, as it don't have any members
5818 // So, we skip calling GetDefaultInterfaceForCoclass unless the class is an coclass.
5819 if (TKindFromClass(pClass) == TKIND_COCLASS)
5820 IfFailReport(GetDefaultInterfaceForCoclass(pTI, &pTIDef));
5826 hr = pCTI->AddRefTypeInfo(pTIDef, pHref);
5828 hr = pCTI->AddRefTypeInfo(pTI, pHref);
5831 { // pTI == m_pIUnknown
5832 if (m_hIUnknown == -1)
5833 hr = pCTI->AddRefTypeInfo(pTI, &m_hIUnknown);
5834 *pHref = m_hIUnknown;
5839 // If we got the href...
5842 // Save for later use.
5843 if ( NULL == (pFound=m_HrefOfClassHash.Add(&sLookup)))
5844 IfFailReport(E_OUTOFMEMORY);
5846 pFound->pClass = pClass;
5847 pFound->href = *pHref;
5850 // If substituting IUnknown, give a warning.
5851 if (hr == S_OK && bUseIUnknown && bWarnOnUsingIUnknown && !bUseIUnknownWarned)
5853 DefineFullyQualifiedNameForClassWOnStack();
5854 LPCWSTR szName = GetFullyQualifiedNameForClassNestedAwareW(pClass);
5855 ReportWarning(S_OK, TLBX_I_USEIUNKNOWN, szName);
5859 if (hr == S_OK && bUseIUnknown)
5863 } // HRESULT TypeLibExporter::EEClassToHref()
5865 //*****************************************************************************
5866 // Retrieve an HRef to the a type defined in StdOle.
5867 //*****************************************************************************
5868 void TypeLibExporter::StdOleTypeToHRef(ICreateTypeInfo2 *pCTI, REFGUID rGuid, HREFTYPE *pHref)
5873 PRECONDITION(CheckPointer(pCTI));
5874 PRECONDITION(CheckPointer(pHref));
5879 SafeComHolder<ITypeLib> pITLB = NULL;
5880 SafeComHolder<ITypeInfo> pITI = NULL;
5884 IfFailReport(LoadRegTypeLib(LIBID_STDOLE2, -1, -1, 0, &pITLB));
5885 IfFailReport(pITLB->GetTypeInfoOfGuid(rGuid, &pITI));
5886 IfFailReport(pCTI->AddRefTypeInfo(pITI, pHref));
5887 } // void TypeLibExporter::ColorToHRef()
5889 //*****************************************************************************
5890 // Given a TypeDef's flags, determine the proper TYPEKIND.
5891 //*****************************************************************************
5892 TYPEKIND TypeLibExporter::TKindFromClass(
5893 MethodTable *pClass) // MethodTable.
5898 PRECONDITION(CheckPointer(pClass));
5903 ULONG ulIface = ifDual; // Is this interface [dual], IUnknown, or DISPINTERFACE.
5905 if (pClass->IsInterface())
5907 // IDispatch or IUnknown derived?
5908 IfFailReport(pClass->GetMDImport()->GetIfaceTypeOfTypeDef(pClass->GetCl(), &ulIface));
5909 if (ulIface == ifDispatch)
5910 return TKIND_DISPATCH;
5912 return TKIND_INTERFACE;
5915 if (pClass->IsEnum())
5918 if (pClass->IsValueType() || pClass->HasLayout())
5920 TYPEKIND tkResult=TKIND_RECORD; // The resulting typekind.
5921 mdFieldDef fd; // A Field def.
5922 ULONG cFD; // Count of fields.
5923 ULONG iFD=0; // Loop control.
5924 ULONG ulOffset; // Field offset.
5925 bool bNonZero=false; // Found any non-zero?
5926 MD_CLASS_LAYOUT sLayout; // For enumerating layouts.
5929 HENUMInternalHolder eFDi(pClass->GetMDImport());
5930 eFDi.EnumInit(mdtFieldDef, pClass->GetCl());
5932 // Get an enumerator for the FieldDefs in the TypeDef. Only need the counts.
5933 cFD = pClass->GetMDImport()->EnumGetCount(&eFDi);
5935 // Get an enumerator for the class layout.
5936 IfFailReport(pClass->GetMDImport()->GetClassLayoutInit(pClass->GetCl(), &sLayout));
5938 // Enumerate the layout.
5939 while (pClass->GetMDImport()->GetClassLayoutNext(&sLayout, &fd, &ulOffset) == S_OK)
5949 // If there were fields, all had layout, and all layouts are zero, call it a union.
5950 if (cFD > 0 && iFD == cFD && !bNonZero)
5951 tkResult = TKIND_UNION;
5956 return TKIND_COCLASS;
5957 } // TYPEKIND TypeLibExporter::TKindFromClass()
5959 //*****************************************************************************
5960 // Generate a HREFTYPE in the output TypeLib for a TypeInfo.
5961 //*****************************************************************************
5962 void TypeLibExporter::GetRefTypeInfo(
5963 ICreateTypeInfo2 *pContainer,
5964 ITypeInfo *pReferenced,
5970 PRECONDITION(CheckPointer(pContainer));
5971 PRECONDITION(CheckPointer(pReferenced));
5972 PRECONDITION(CheckPointer(pHref));
5976 HRESULT hr; // A result.
5977 CHrefOfTIHashKey sLookup; // Hash structure to lookup.
5978 CHrefOfTIHashKey *pFound; // Found structure.
5980 // See if we already know this TypeInfo.
5981 sLookup.pITI = pReferenced;
5982 if ((pFound=m_HrefHash.Find(&sLookup)) != NULL)
5984 *pHref = pFound->href;
5988 // Assert that the containing typelib for pContainer is the typelib being created.
5991 SafeComHolder<ITypeInfo> pTI=0;
5992 SafeComHolder<ITypeLib> pTL=0;
5993 SafeComHolder<ITypeLib> pTLMe=0;
5996 SafeQueryInterface(pContainer, IID_ITypeInfo, (IUnknown**)&pTI);
5997 SafeQueryInterface(m_pICreateTLB, IID_ITypeLib, (IUnknown**)&pTLMe);
5998 pTI->GetContainingTypeLib(&pTL, &ix);
5999 _ASSERTE(pTL == pTLMe);
6003 // Haven't seen it -- add the href.
6004 // NOTE: This code assumes that hreftypes are per-typelib.
6005 IfFailReport(pContainer->AddRefTypeInfo(pReferenced, pHref));
6007 // Save for later use.
6008 pFound=m_HrefHash.Add(&sLookup);
6010 IfFailReport(E_OUTOFMEMORY);
6012 // Prefix can't tell that IfFailReport will actually throw an exception if pFound is NULL so
6013 // let's tell it explicitly that if we reach this point pFound will not be NULL.
6014 PREFIX_ASSUME(pFound != NULL);
6015 pFound->pITI = pReferenced;
6016 pFound->href = *pHref;
6017 pReferenced->AddRef();
6018 } // HRESULT TypeLibExporter::GetRefTypeInfo()
6020 //*****************************************************************************
6021 // Implementation of a hashed ITypeInfo to HREFTYPE association.
6022 //*****************************************************************************
6023 void TypeLibExporter::CHrefOfTIHash::Clear()
6033 CHrefOfTIHashKey *p;
6034 for (p=GetFirst(); p; p=GetNext(p))
6036 SafeRelease(p->pITI);
6039 CClosedHash<class CHrefOfTIHashKey>::Clear();
6040 } // void TypeLibExporter::CHrefOfTIHash::Clear()
6042 unsigned int TypeLibExporter::CHrefOfTIHash::Hash(const CHrefOfTIHashKey *pData)
6044 LIMITED_METHOD_CONTRACT;
6047 // The pointers are at least 4-byte aligned, so ignore bottom two bits.
6048 return (unsigned int) (((size_t)(pData->pITI))>>2);
6050 // @TODO IA64: Is this a good hashing mechanism on IA64?
6051 return (unsigned int) (((size_t)(pData->pITI))>>3);
6053 } // unsigned long TypeLibExporter::CHrefOfTIHash::Hash()
6055 unsigned int TypeLibExporter::CHrefOfTIHash::Compare(const CHrefOfTIHashKey *p1, CHrefOfTIHashKey *p2)
6057 LIMITED_METHOD_CONTRACT;
6059 if (p1->pITI == p2->pITI)
6062 } // unsigned long TypeLibExporter::CHrefOfTIHash::Compare()
6064 TypeLibExporter::CHrefOfTIHash::ELEMENTSTATUS TypeLibExporter::CHrefOfTIHash::Status(CHrefOfTIHashKey *p)
6066 LIMITED_METHOD_CONTRACT;
6067 if (p->pITI == reinterpret_cast<ITypeInfo*>(FREE))
6069 if (p->pITI == reinterpret_cast<ITypeInfo*>(DELETED))
6072 } // TypeLibExporter::CHrefOfTIHash::ELEMENTSTATUS TypeLibExporter::CHrefOfTIHash::Status()
6074 void TypeLibExporter::CHrefOfTIHash::SetStatus(CHrefOfTIHashKey *p, ELEMENTSTATUS s)
6076 LIMITED_METHOD_CONTRACT;
6078 p->pITI = reinterpret_cast<ITypeInfo*>(s);
6079 } // void TypeLibExporter::CHrefOfTIHash::SetStatus()
6081 void *TypeLibExporter::CHrefOfTIHash::GetKey(CHrefOfTIHashKey *p)
6083 LIMITED_METHOD_CONTRACT;
6086 } // void *TypeLibExporter::CHrefOfTIHash::GetKey()
6089 //*****************************************************************************
6090 // Implementation of a hashed MethodTable* to HREFTYPE association.
6091 //*****************************************************************************
6092 void TypeLibExporter::CHrefOfClassHash::Clear()
6094 WRAPPER_NO_CONTRACT;
6095 CClosedHash<class CHrefOfClassHashKey>::Clear();
6096 } // void TypeLibExporter::CHrefOfClassHash::Clear()
6098 unsigned int TypeLibExporter::CHrefOfClassHash::Hash(const CHrefOfClassHashKey *pData)
6100 LIMITED_METHOD_CONTRACT;
6103 // Tbe pointers are at least 4-byte aligned, so ignore bottom two bits.
6104 return (unsigned int) (((size_t)(pData->pClass))>>2);
6106 // @TODO IA64: Is this a good hashing mechanism on IA64?
6107 return (unsigned int) (((size_t)(pData->pClass))>>3);
6109 } // unsigned long TypeLibExporter::CHrefOfClassHash::Hash()
6111 unsigned int TypeLibExporter::CHrefOfClassHash::Compare(const CHrefOfClassHashKey *p1, CHrefOfClassHashKey *p2)
6113 LIMITED_METHOD_CONTRACT;
6115 if (p1->pClass == p2->pClass)
6118 } // unsigned long TypeLibExporter::CHrefOfClassHash::Compare()
6120 TypeLibExporter::CHrefOfClassHash::ELEMENTSTATUS TypeLibExporter::CHrefOfClassHash::Status(CHrefOfClassHashKey *p)
6122 LIMITED_METHOD_CONTRACT;
6124 if (p->pClass == reinterpret_cast<MethodTable*>(FREE))
6126 if (p->pClass == reinterpret_cast<MethodTable*>(DELETED))
6129 } // TypeLibExporter::CHrefOfClassHash::ELEMENTSTATUS TypeLibExporter::CHrefOfClassHash::Status()
6131 void TypeLibExporter::CHrefOfClassHash::SetStatus(CHrefOfClassHashKey *p, ELEMENTSTATUS s)
6133 LIMITED_METHOD_CONTRACT;
6135 p->pClass = reinterpret_cast<MethodTable*>(s);
6136 } // void TypeLibExporter::CHrefOfClassHash::SetStatus()
6138 void *TypeLibExporter::CHrefOfClassHash::GetKey(CHrefOfClassHashKey *p)
6140 LIMITED_METHOD_CONTRACT;
6143 } // void *TypeLibExporter::CHrefOfClassHash::GetKey()
6146 //*****************************************************************************
6147 // Implementation of a hashed MethodTable* to conversion information association.
6148 //*****************************************************************************
6149 void TypeLibExporter::CExportedTypesHash::Clear()
6151 WRAPPER_NO_CONTRACT;
6153 // Iterate over entries and free pointers.
6154 CExportedTypesInfo *pData;
6158 SetStatus(pData, DELETED);
6159 pData = GetNext(pData);
6162 CClosedHash<class CExportedTypesInfo>::Clear();
6163 } // void TypeLibExporter::CExportedTypesHash::Clear()
6165 unsigned int TypeLibExporter::CExportedTypesHash::Hash(const CExportedTypesInfo *pData)
6167 LIMITED_METHOD_CONTRACT;
6170 // Tbe pointers are at least 4-byte aligned, so ignore bottom two bits.
6171 return (unsigned int) (((size_t)(pData->pClass))>>2);
6173 // @TODO IA64: Is this a good hashing mechanism on IA64?
6174 return (unsigned int) (((size_t)(pData->pClass))>>3);
6176 } // unsigned long TypeLibExporter::CExportedTypesHash::Hash()
6178 unsigned int TypeLibExporter::CExportedTypesHash::Compare(const CExportedTypesInfo *p1, CExportedTypesInfo *p2)
6180 LIMITED_METHOD_CONTRACT;
6182 if (p1->pClass == p2->pClass)
6185 } // unsigned long TypeLibExporter::CExportedTypesHash::Compare()
6187 TypeLibExporter::CExportedTypesHash::ELEMENTSTATUS TypeLibExporter::CExportedTypesHash::Status(CExportedTypesInfo *p)
6189 LIMITED_METHOD_CONTRACT;
6191 if (p->pClass == reinterpret_cast<MethodTable*>(FREE))
6193 if (p->pClass == reinterpret_cast<MethodTable*>(DELETED))
6196 } // TypeLibExporter::CExportedTypesHash::ELEMENTSTATUS TypeLibExporter::CExportedTypesHash::Status()
6198 void TypeLibExporter::CExportedTypesHash::SetStatus(CExportedTypesInfo *p, ELEMENTSTATUS s)
6200 WRAPPER_NO_CONTRACT;
6202 // If deleting a used entry, free the pointers.
6203 if (s == DELETED && Status(p) == USED)
6205 if (p->pCTI) p->pCTI->Release(), p->pCTI=0;
6206 if (p->pCTIClassItf) p->pCTIClassItf->Release(), p->pCTIClassItf=0;
6208 p->pClass = reinterpret_cast<MethodTable*>(s);
6209 } // void TypeLibExporter::CExportedTypesHash::SetStatus()
6211 void *TypeLibExporter::CExportedTypesHash::GetKey(CExportedTypesInfo *p)
6213 LIMITED_METHOD_CONTRACT;
6216 } // void *TypeLibExporter::CExportedTypesHash::GetKey()
6218 void TypeLibExporter::CExportedTypesHash::InitArray()
6220 STANDARD_VM_CONTRACT;
6222 // For iterating the entries.
6223 CExportedTypesInfo *pData = 0;
6225 // Make room for the data.
6227 m_Array = new CExportedTypesInfo*[Base::Count()];
6233 m_Array[m_iCount++] = pData;
6234 pData = GetNext(pData);
6236 } // void TypeLibExporter::CExportedTypesHash::InitArray()
6238 void TypeLibExporter::CExportedTypesHash::UpdateArray()
6240 STANDARD_VM_CONTRACT;
6242 // For iterating the entries.
6243 CExportedTypesInfo *pData = 0;
6245 // Clear the old data.
6249 // Make room for the data.
6251 m_Array = new CExportedTypesInfo*[Base::Count()];
6257 m_Array[m_iCount++] = pData;
6258 pData = GetNext(pData);
6260 } // void TypeLibExporter::CExportedTypesHash::UpdateArray()
6262 void TypeLibExporter::CExportedTypesHash::SortByName()
6264 WRAPPER_NO_CONTRACT;
6266 CSortByName sorter(m_Array, (int)m_iCount);
6268 } // void TypeLibExporter::CExportedTypesHash::SortByName()
6270 void TypeLibExporter::CExportedTypesHash::SortByToken()
6272 WRAPPER_NO_CONTRACT;
6274 CSortByToken sorter(m_Array, (int)m_iCount);
6276 } // void TypeLibExporter::CExportedTypesHash::SortByToken()
6278 int TypeLibExporter::CExportedTypesHash::CSortByToken::Compare(
6279 CExportedTypesInfo **p1,
6280 CExportedTypesInfo **p2)
6282 LIMITED_METHOD_CONTRACT;
6284 MethodTable *pC1 = (*p1)->pClass;
6285 MethodTable *pC2 = (*p2)->pClass;
6287 if (pC1->GetMDImport() < pC2->GetMDImport())
6289 if (pC1->GetMDImport() > pC2->GetMDImport())
6291 // Same scopes, compare tokens.
6292 if (pC1->GetTypeDefRid() < pC2->GetTypeDefRid())
6294 if (pC1->GetTypeDefRid() > pC2->GetTypeDefRid())
6296 // Hmmm. Same class.
6298 } // int TypeLibExporter::CExportedTypesHash::CSortByToken::Compare()
6300 int TypeLibExporter::CExportedTypesHash::CSortByName::Compare(
6301 CExportedTypesInfo **p1,
6302 CExportedTypesInfo **p2)
6307 PRECONDITION(CheckPointer(p1));
6308 PRECONDITION(CheckPointer(p2));
6309 PRECONDITION(CheckPointer(*p1));
6310 PRECONDITION(CheckPointer(*p2));
6314 int iRslt; // A compare result.
6316 MethodTable *pC1 = (*p1)->pClass;
6317 MethodTable *pC2 = (*p2)->pClass;
6319 // Ignore scopes. Need to see name collisions across scopes.
6320 // Same scopes, compare names.
6321 LPCSTR pName1, pNS1;
6322 LPCSTR pName2, pNS2;
6323 IfFailThrow(pC1->GetMDImport()->GetNameOfTypeDef(pC1->GetCl(), &pName1, &pNS1));
6324 IfFailThrow(pC2->GetMDImport()->GetNameOfTypeDef(pC2->GetCl(), &pName2, &pNS2));
6326 // Compare case-insensitive, because we want different capitalizations to sort together.
6327 SString sName1(SString::Utf8, pName1);
6328 SString sName2(SString::Utf8, pName2);
6330 iRslt = sName1.CompareCaseInsensitive(sName2);
6334 // If names are spelled the same, ignoring capitalization, sort by namespace.
6335 // We will attempt to use namespace for disambiguation.
6336 SString sNS1(SString::Utf8, pNS1);
6337 SString sNS2(SString::Utf8, pNS2);
6339 iRslt = sNS1.CompareCaseInsensitive(sNS2);
6341 } // int TypeLibExporter::CExportedTypesHash::CSortByName::Compare()