17861387bce8e1f318b07c39070540ad4be7e629
[platform/upstream/coreclr.git] / src / vm / tlbexport.cpp
1 //
2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
4 //
5 //===========================================================================
6 // File: TlbExport.CPP
7 //
8
9 //
10 // Notes: Create a TypeLib from COM+ metadata.
11 //---------------------------------------------------------------------------
12
13 #include "common.h"
14
15 #include "comcallablewrapper.h"
16 #include "field.h"
17 #include "dllimport.h"
18 #include "fieldmarshaler.h"
19 #include "eeconfig.h"
20 #include "comdelegate.h"
21 #include <nsutilpriv.h>
22 #include <tlbimpexp.h>
23 #include <mlang.h>
24 #include "tlbexport.h"
25 #include "commtmemberinfomap.h"
26 #include <corerror.h>
27 #include "posterror.h"
28 #include "typeparse.h"
29
30 #if defined(VALUE_MASK)
31 #undef VALUE_MASK
32 #endif
33
34 #include <guidfromname.h>
35 #include <stgpool.h>
36 #include <siginfo.hpp>
37 #include <typestring.h>
38 #include "perfcounters.h"
39 #include "comtypelibconverter.h"
40 #include "caparser.h"
41
42 // Define to export an empty dispinterface for an AutoDispatch IClassX
43 #define EMPTY_DISPINTERFACE_ICLASSX
44 #ifndef S_USEIUNKNOWN
45 #define S_USEIUNKNOWN (HRESULT)2
46 #endif
47
48 #if defined(_DEBUG) && defined(_TRACE)
49 #define TRACE printf
50 #else
51 #define TRACE NullFn
52 inline void NullFn(const char *pf,...) {}
53 #endif
54
55 #if defined(_DEBUG)
56 #define IfFailReport(expr) \
57     do { if(FAILED(hr = (expr))) { DebBreakHr(hr); ReportError(hr); } } while (0)    
58 #else
59 #define IfFailReport(expr) \
60     do { if(FAILED(hr = (expr))) { ReportError(hr); } } while (0)    
61 #endif
62
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 //-----------------------------------------------------------------------------                                     
71
72 //*****************************************************************************
73 // Constants.
74 //*****************************************************************************
75 static const WCHAR szRetVal[] = W("pRetVal");
76 static const WCHAR szTypeLibExt[] = W(".TLB");
77
78 static const WCHAR szTypeLibKeyName[] = W("TypeLib");
79 static const WCHAR szClsidKeyName[] = W("CLSID");
80
81 static const WCHAR szIClassX[] = W("_%ls");
82 static const int cbIClassX = 1;
83 static const WCHAR cIClassX = W('_');
84
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");
88
89 static const WCHAR szGuidName[]         = W("GUID");
90
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";
100
101 static const char szRuntime[]       = {"System."};
102 static const size_t cbRuntime       = (lengthof(szRuntime)-1);
103
104 static const char szText[]          = {"System.Text."};
105 static const size_t cbText          = (lengthof(szText)-1);
106
107 static const char szCollections[]   = {"System.Collections."};
108 static const size_t cbCollections   = (lengthof(szCollections)-1);
109
110 static const char szDrawing[]       = {"System.Drawing."};
111 static const size_t cbDrawing       = (lengthof(szDrawing)-1);
112
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;
115
116 // The length of the following string(w/o the terminator): "{00000000-0000-0000-0000-000000000000}".
117 static const int cCLSIDStrLength = 38;
118
119 // {17093CC8-9BD2-11cf-AA4F-304BF89C0001}
120 static const GUID GUID_TRANS_SUPPORTED     = {0x17093CC8,0x9BD2,0x11cf,{0xAA,0x4F,0x30,0x4B,0xF8,0x9C,0x00,0x01}};
121
122 // {00020430-0000-0000-C000-000000000046}
123 static const GUID LIBID_STDOLE2 = { 0x00020430, 0x0000, 0x0000, { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } };
124
125 // {66504301-BE0F-101A-8BBB-00AA00300CAB}
126 static const GUID GUID_OleColor = { 0x66504301, 0xBE0F, 0x101A, { 0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB } };
127
128 // LIBID mscoree
129 static const GUID LIBID_MSCOREE = {0x5477469e,0x83b1,0x11d2,{0x8b,0x49,0x00,0xa0,0xc9,0xb7,0xc9,0xc4}};
130
131 static const char XXX_DESCRIPTION_TYPE[] = {"System.ComponentModel.DescriptionAttribute"};
132 static const char XXX_ASSEMBLY_DESCRIPTION_TYPE[] = {"System.Reflection.AssemblyDescriptionAttribute"};
133
134 //*****************************************************************************
135 // Table to map COM+ calling conventions to TypeLib calling conventions.
136 //*****************************************************************************
137 CALLCONV Clr2TlbCallConv[] =
138 {
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   
147 };
148
149
150
151 // Forward declarations.
152 extern HRESULT _FillVariant(MDDefaultValue *pMDDefaultValue, VARIANT *pvar); 
153 extern HRESULT _FillMDDefaultValue(BYTE bType, void const *pValue, MDDefaultValue *pMDDefaultValue);
154
155 //*****************************************************************************
156 // Stolen from classlib.
157 //*****************************************************************************
158 double _TicksToDoubleDate(const __int64 ticks)
159 {
160     CONTRACTL
161     {
162         NOTHROW;
163         GC_NOTRIGGER;
164         MODE_ANY;
165     }
166     CONTRACTL_END;
167     
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;
184
185     // Returns OleAut's zero'ed date ticks.
186     if (ticks == 0)
187          return 0.0;
188          
189     if (ticks < OADateMinAsTicks)
190          return 0.0;
191
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;
195      if (millis < 0) 
196      {
197          __int64 frac = millis % MillisPerDay;
198          if (frac != 0) millis -= (MillisPerDay + frac) * 2;
199      }
200      
201      return (double)millis / MillisPerDay;
202 } // double _TicksToDoubleDate()
203
204
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.
212 {
213     CONTRACTL
214     {
215         STANDARD_VM_CHECK;
216         PRECONDITION(CheckPointer(pUnk));
217     }
218     CONTRACTL_END;
219
220     HRESULT     hr;                     // A result.
221     WCHAR       rcErr[1024];            // Buffer for error message.
222
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.
226
227     // Try to get a name.
228     hr = SafeQueryInterface(pUnk, IID_ITypeInfo, (IUnknown**)&pITI);
229     if (SUCCEEDED(hr))
230     {
231         IfFailThrow(pITI->GetDocumentation(MEMBERID_NIL, &name, 0,0,0));
232     }
233     else
234     {
235         hr = SafeQueryInterface(pUnk, IID_ITypeLib, (IUnknown**)&pITLB);
236         if (SUCCEEDED(hr))
237             IfFailThrow(pITLB->GetDocumentation(MEMBERID_NIL, &name, 0,0,0));
238     }
239
240     if (name == NULL)
241     {
242         name = SysAllocString(W("???"));
243         if (name == NULL)
244             COMPlusThrowHR(E_OUTOFMEMORY);
245     }
246
247     // Format the typelib error.
248     FormatRuntimeError(rcErr, lengthof(rcErr), hrT);
249
250     SString strHRHex;
251     strHRHex.Printf("%.8x", hrX);
252
253     COMPlusThrowHR(hrX, hrX, strHRHex, name, rcErr);
254 } // void PostTypeLibError()
255
256
257
258
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.
265 {
266     CONTRACTL
267     {
268         STANDARD_VM_CHECK;
269         PRECONDITION(CheckPointer(pAssembly));
270         PRECONDITION(CheckPointer(szTlb, NULL_OK));
271         PRECONDITION(CheckPointer(ppTlb));
272         PRECONDITION(CheckPointer(pINotify, NULL_OK));
273     }
274     CONTRACTL_END;
275
276     HRESULT     hr = S_OK;
277
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.
286     
287     pModule = pAssembly->GetManifestModule();
288     _ASSERTE(pModule);
289
290     // Retrieve the module filename.
291     szModule = pModule->GetPath();   
292     PREFIX_ASSUME(szModule != NULL);
293     
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);
297
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.
301     if (*szModule == 0)
302     {
303         bDynamic = TRUE;
304         szModule = W("Dynamic");
305     }
306
307     // Create the typelib name, if none provided.  Don't create one for Dynamic modules.
308     if (!szTlb || !*szTlb)
309     {
310         if (bDynamic)
311             szTlb = W("");
312         else
313         {
314             SplitPath(szModule, rcDrive, _MAX_DRIVE, rcDir, _MAX_DIR, rcFile, _MAX_FNAME, 0, 0);
315             MakePath(rcTlb, rcDrive, rcDir, rcFile, szTypeLibExt);
316             szTlb = rcTlb;
317         }
318     }
319
320     // Do the conversion.  
321     exporter.Convert(pAssembly, szTlb, pINotify, flags);
322
323     // Get a copy of the ITypeLib*
324     IfFailThrow(exporter.GetTypeLib(IID_ITypeLib, (IUnknown**)ppTlb));
325 } // void ExportTypeLibFromLoadedAssemblyInternal()
326
327
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.
334 {
335     CONTRACTL
336     {
337         DISABLED(NOTHROW);
338         GC_TRIGGERS;
339         MODE_PREEMPTIVE;
340     }
341     CONTRACTL_END;
342
343     HRESULT hr = S_OK;
344
345     EX_TRY
346     {
347         ExportTypeLibFromLoadedAssembly(pAssembly, 
348                                                 szTlb,
349                                                 ppTlb,
350                                                 pINotify,
351                                                 flags);
352     }
353     EX_CATCH_HRESULT(hr);
354
355     return hr;
356 }
357
358 //*****************************************************************************
359 // Default notification class.
360 //*****************************************************************************
361 class CDefaultNotify : public ITypeLibExporterNotifySink
362 {
363 public:
364     virtual HRESULT __stdcall ReportEvent(
365         ImporterEventKind EventKind,        // Type of event.
366         long        EventCode,              // HR of event.
367         BSTR        EventMsg)               // Text message for event.
368     {
369         LIMITED_METHOD_CONTRACT;
370         return S_OK;
371     } // virtual HRESULT __stdcall ReportEvent()
372     
373     //-------------------------------------------------------------------------
374     virtual HRESULT __stdcall ResolveRef(
375         IUnknown    *Asm, 
376         IUnknown    **pRetVal) 
377     {
378         CONTRACTL
379         {
380             DISABLED(NOTHROW);
381             GC_TRIGGERS;
382             MODE_PREEMPTIVE;
383             SO_TOLERANT;
384             PRECONDITION(CheckPointer(Asm));
385             PRECONDITION(CheckPointer(pRetVal));
386         }
387         CONTRACTL_END;
388         
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.
394
395         BEGIN_EXTERNAL_ENTRYPOINT(&hr)
396         {
397             {
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();
404                 GCPROTECT_END();
405             }
406             
407             // Default resolution provides no notification, flags are 0.
408             ExportTypeLibFromLoadedAssembly(pAssembly, 0, &pTLB, 0 /*pINotify*/, 0 /* flags*/);
409         }
410         END_EXTERNAL_ENTRYPOINT;
411
412         *pRetVal = pTLB;
413         
414         return hr;
415     } // virtual HRESULT __stdcall ResolveRef()
416     
417     //-------------------------------------------------------------------------
418     virtual HRESULT STDMETHODCALLTYPE QueryInterface(// S_OK or E_NOINTERFACE
419         REFIID      riid,                   // Desired interface.
420         void        **ppvObject)            // Put interface pointer here.
421     {
422         CONTRACTL
423         {
424             NOTHROW;
425             GC_TRIGGERS;
426             MODE_PREEMPTIVE;
427             SO_TOLERANT;
428             PRECONDITION(CheckPointer(ppvObject));
429         }
430         CONTRACTL_END;
431
432         *ppvObject = 0;
433         if (riid == IID_IUnknown || riid == IID_ITypeLibExporterNotifySink)
434         {
435             *ppvObject = this;
436             return S_OK;
437         }
438         return E_NOINTERFACE;
439     } // virtual HRESULT QueryInterface()
440     
441     //-------------------------------------------------------------------------
442     virtual ULONG STDMETHODCALLTYPE AddRef(void) 
443     {
444         LIMITED_METHOD_CONTRACT;
445         return 1;
446     } // virtual ULONG STDMETHODCALLTYPE AddRef()
447     
448     //-------------------------------------------------------------------------
449     virtual ULONG STDMETHODCALLTYPE Release(void) 
450     {
451         LIMITED_METHOD_CONTRACT;
452         return 1;
453     } // virtual ULONG STDMETHODCALLTYPE Release()
454 };
455
456 static CDefaultNotify g_Notify;
457
458 //*****************************************************************************
459 // CTOR/DTOR.  
460 //*****************************************************************************
461 TypeLibExporter::TypeLibExporter()
462  :  m_pICreateTLB(0), 
463     m_pIUnknown(0), 
464     m_pIDispatch(0),
465     m_pGuid(0),
466     m_hIUnknown(-1)
467 {
468     LIMITED_METHOD_CONTRACT;
469
470 #if defined(_DEBUG)
471     static int i;
472     ++i;    // So a breakpoint can be set.
473 #endif
474 } // TypeLibExporter::TypeLibExporter()
475
476 TypeLibExporter::~TypeLibExporter()
477 {
478     CONTRACTL
479     {
480         NOTHROW;
481         GC_TRIGGERS;
482     }
483     CONTRACTL_END;
484     
485     ReleaseResources();
486 } // TypeLibExporter::~TypeLibExporter()
487
488 //*****************************************************************************
489 // Get an interface pointer from the ICreateTypeLib interface.
490 //*****************************************************************************
491 HRESULT TypeLibExporter::GetTypeLib(
492     REFGUID     iid,
493     IUnknown    **ppITypeLib)
494 {
495     CONTRACTL
496     {
497         NOTHROW;
498         GC_TRIGGERS;
499         MODE_ANY;
500         PRECONDITION(CheckPointer(ppITypeLib));
501     }
502     CONTRACTL_END;
503
504     return SafeQueryInterface(m_pICreateTLB, iid, (IUnknown**)ppITypeLib);
505 } // HRESULT TypeLibExporter::GetTypeLib()
506
507 //*****************************************************************************
508 // LayOut a TypeLib.  Call LayOut on all ICreateTypeInfo2s first.
509 //*****************************************************************************
510 void TypeLibExporter::LayOut()       // S_OK or error.
511 {
512     STANDARD_VM_CONTRACT;
513
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.
518
519     cTypes = m_Exports.Count();
520     
521     // Call LayOut on all ICreateTypeInfo2*s.
522     for (ix=0; ix<cTypes; ++ix)
523     {
524         pData = m_Exports[ix];
525         if (pData->pCTI && FAILED(hr = pData->pCTI->LayOut()))
526             PostTypeLibError(pData->pCTI, hr, TLBX_E_LAYOUT_ERROR);
527     }
528     
529     for (ix=0; ix<cTypes; ++ix)
530     {
531         pData = m_Exports[ix];
532         if (pData->pCTIClassItf && FAILED(hr = pData->pCTIClassItf->LayOut()))
533             PostTypeLibError(pData->pCTIClassItf, hr, TLBX_E_LAYOUT_ERROR);
534     }
535     
536     // Repeat for injected types.
537     cTypes = m_InjectedExports.Count();
538     for (ix=0; ix<cTypes; ++ix)
539     {
540         pData = m_InjectedExports[ix];
541         if (pData->pCTI && FAILED(hr = pData->pCTI->LayOut()))
542             PostTypeLibError(pData->pCTI, hr, TLBX_E_LAYOUT_ERROR);
543     }
544     
545     for (ix=0; ix<cTypes; ++ix)
546     {
547         pData = m_InjectedExports[ix];
548         if (pData->pCTIClassItf && FAILED(hr = pData->pCTIClassItf->LayOut()))
549             PostTypeLibError(pData->pCTIClassItf, hr, TLBX_E_LAYOUT_ERROR);
550     }
551 } // HRESULT TypeLibExporter::LayOut()
552
553 //*****************************************************************************
554 // Release all pointers.
555 //*****************************************************************************
556 void TypeLibExporter::ReleaseResources()
557 {
558     CONTRACTL
559     {
560         NOTHROW;
561         GC_TRIGGERS;
562         MODE_ANY;
563     }
564     CONTRACTL_END;
565
566     // Release the ITypeInfo* pointers.
567     m_Exports.Clear();
568     m_InjectedExports.Clear();
569
570     // Clean up the created TLB.
571     SafeRelease(m_pICreateTLB);
572     m_pICreateTLB = 0;
573
574     // Clean up the ITypeInfo*s for well-known interfaces.
575     SafeRelease(m_pIUnknown);
576     m_pIUnknown = 0;
577
578     SafeRelease(m_pIDispatch);
579     m_pIDispatch = 0;
580
581     SafeRelease(m_pGuid);
582     m_pGuid = 0;
583 } // void TypeLibExporter::ReleaseResources()
584
585 //*****************************************************************************
586 // Enumerate the Types in a Module, add to the list.
587 //*****************************************************************************
588 void TypeLibExporter::AddModuleTypes(
589     Module     *pModule)                // The module to convert.
590 {
591     CONTRACTL
592     {
593         STANDARD_VM_CHECK;
594         PRECONDITION(CheckPointer(pModule));
595     }
596     CONTRACTL_END;
597
598     HRESULT     hr;
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.
605     
606
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);
612
613     // Add all the classes to the hash.
614     for (ix=0; ix<cTD; ++ix)
615     {
616         ZeroHolder  zhType = &m_ErrorContext.m_pScope;              // Clear error reporting info.
617         
618         // Get the TypeDef.
619         if (!pModule->GetMDImport()->EnumTypeDefNext(&eTD, &td))
620             IfFailReport(E_UNEXPECTED);
621         
622         IMDInternalImport* pInternalImport = pModule->GetMDImport();
623
624         // Error reporting info.
625         m_ErrorContext.m_tkType = td;
626         m_ErrorContext.m_pScope = pModule->GetMDImport();
627
628         // Get the class, perform the step.
629         pClass = LoadClass(pModule, td);
630         
631         // Enumerate the formal type parameters
632         HENUMInternal   hEnumGenericPars;
633         hr = pInternalImport->EnumInit(mdtGenericParam, td, &hEnumGenericPars);
634         if (SUCCEEDED(hr))
635         {
636             DWORD numGenericArgs = pInternalImport->EnumGetCount(&hEnumGenericPars);            
637             // skip generic classes
638             if( numGenericArgs  > 0 )
639             {
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);
643                 
644                 continue; 
645             }
646         }           
647     
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)
651         {            
652             // If the type isn't visible from COM, don't add it to the list of exports.
653             if (!IsTypeVisibleFromCom(TypeHandle(pClass)))
654                 continue;
655         }
656
657         // See if this class is already in the list.
658         sExported.pClass = pClass;
659         pExported = m_Exports.Find(&sExported);
660         if (pExported != 0)
661             continue;
662         
663         // New class, add to list.
664         pExported = m_Exports.Add(&sExported);
665         if (!pExported)
666             IfFailReport(E_OUTOFMEMORY);
667         
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;
672         pExported->pCTI = 0;
673         pExported->pCTIClassItf = 0;
674     }
675 } // HRESULT TypeLibExporter::AddModuleTypes()
676
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.
682 {
683     CONTRACTL
684     {
685         STANDARD_VM_CHECK;
686         PRECONDITION(CheckPointer(pAssembly));
687     }
688     CONTRACTL_END;
689
690     Module      *pManifestModule;       // A module in the assembly.
691     mdFile      mf;                     // A file token.
692
693     if (pAssembly->GetManifestImport())
694     {
695         // Enumerator over the modules of the assembly.
696         HENUMInternalHolder phEnum(pAssembly->GetManifestImport());
697         phEnum.EnumInit(mdtFile, mdTokenNil);
698
699         // Get the module for the assembly.
700         pManifestModule = pAssembly->GetManifestModule();
701         AddModuleTypes(pManifestModule);
702         
703         while (pAssembly->GetManifestImport()->EnumNext(&phEnum, &mf))
704         {
705             DomainFile *pDomainFile = pAssembly->GetManifestModule()->LoadModule(GetAppDomain(), mf, FALSE);
706
707             if (pDomainFile != NULL && !pDomainFile->GetFile()->IsResource())
708                 AddModuleTypes(pDomainFile->GetModule());
709         }
710     }
711 } // HRESULT TypeLibExporter::AddAssemblyTypes()
712     
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
721 {
722     CONTRACTL
723     {
724         STANDARD_VM_CHECK;
725         PRECONDITION(CheckPointer(pAssembly));
726         PRECONDITION(CheckPointer(szTlbName));
727         PRECONDITION(CheckPointer(pNotify, NULL_OK));
728     }
729     CONTRACTL_END;
730
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.
738     
739     // Set PerfCounters
740     COUNTER_ONLY(GetPerfCounters().m_Interop.cTLBExports++);
741
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.
746
747     // Error reporting information.
748     m_ErrorContext.m_szAssembly = pAssembly->GetSimpleName();
749     
750     m_flags = flags;
751     
752     // Set the callback.
753     m_pNotify = pNotify ? pNotify : &g_Notify;
754
755     // If we haven't set 32-bit or 64-bit export yet, set it now with defaults.
756     UpdateBitness(pAssembly);
757
758     // Check the bitness of the assembly against our output bitness
759     IfFailReport(CheckBitness(pAssembly));
760     
761     // Get some well known TypeInfos.
762     GCX_PREEMP();
763     
764     BSTR wzPath;// = SysAllocStringLen(NULL, _MAX_PATH);
765     IfFailReport(QueryPathOfRegTypeLib(LIBID_STDOLE2, -1, -1, 0, &wzPath));
766
767     if (IsExportingAs64Bit())
768     {
769         hr = LoadTypeLibEx(wzPath, (REGKIND)(REGKIND_NONE | LOAD_TLB_AS_64BIT), &pITLB);       
770     }
771     else
772     {
773         hr = LoadTypeLibEx(wzPath, (REGKIND)(REGKIND_NONE | LOAD_TLB_AS_32BIT), &pITLB);
774     }
775
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.
778     if (FAILED(hr))
779     {
780         IfFailReport(LoadRegTypeLib(LIBID_STDOLE2, -1, -1, 0, &pITLB));
781     }
782     
783     IfFailReport(pITLB->GetTypeInfoOfGuid(IID_IUnknown, &m_pIUnknown));
784     IfFailReport(pITLB->GetTypeInfoOfGuid(IID_IDispatch, &m_pIDispatch));
785     
786     // Look for GUID (which unfortunately has no GUID).
787     for (i=0; i<pITLB->GetTypeInfoCount() && !m_pGuid; ++i)
788     {
789         IfFailReport(pITLB->GetDocumentation(i, &szTIName, 0, 0, 0));
790         if (SString::_wcsicmp(szTIName, szGuidName) == 0)
791             IfFailReport(pITLB->GetTypeInfo(i, &m_pGuid));
792     }
793
794     // Create the output typelib.
795
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.
798     // 
799     if (wcslen(szTlbName) > MAX_PATH_FNAME)
800         IfFailReport(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE));
801
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())
805     {
806         IfFailReport(CreateTypeLib2(SYS_WIN64, szTlbName, &m_pICreateTLB));
807     }
808     else
809     {
810         IfFailReport(CreateTypeLib2(SYS_WIN32, szTlbName, &m_pICreateTLB));
811     }
812
813     // Set the typelib GUID.
814     IfFailReport(GetTypeLibGuidForAssembly(pAssembly, &guid));
815     IfFailReport(m_pICreateTLB->SetGuid(guid));
816
817     // Retrieve the type library's version number.
818     USHORT usMaj, usMin;
819     IfFailReport(GetTypeLibVersionForAssembly(pAssembly, &usMaj, &usMin));
820
821     // Set the TLB's version number.
822     IfFailReport(m_pICreateTLB->SetVersion(usMaj, usMin));
823
824     // Set the LCID.  If no locale, set to 0, otherwise typelib defaults to 409.
825     lcid = 0;
826     LPCUTF8 pLocale = pAssembly->GetLocale();
827     if (pLocale && *pLocale)
828     {
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
831         // start).        
832         _ASSERTE((sizeof(WCHAR) * 2) == sizeof(DWORD));
833         hr = qLocale.ReSizeNoThrow(sizeof(DWORD));
834         if (SUCCEEDED(hr))
835             hr = Utf2Quick(pLocale, qLocale, 2);
836         if (SUCCEEDED(hr))
837         {
838             *(DWORD*)qLocale.Ptr() = (DWORD)wcslen(&qLocale.Ptr()[2]);
839             hr = ::CoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, IID_IMultiLanguage, (void**)&pIML);
840         }
841         if (SUCCEEDED(hr))
842             pIML->GetLcidFromRfc1766(&lcid, (BSTR)&qLocale.Ptr()[2]);
843     }
844     HRESULT hr2 = m_pICreateTLB->SetLcid(lcid);
845     if (hr2 == TYPE_E_UNKNOWNLCID)
846     {
847         ReportWarning(TYPE_E_UNKNOWNLCID, TYPE_E_UNKNOWNLCID);
848         hr2 = m_pICreateTLB->SetLcid(0);
849     }
850     IfFailReport(hr2);
851
852     // Get the list of types in the assembly.
853     AddAssemblyTypes(pAssembly);
854     m_Exports.InitArray();
855
856     // Get the assembly value for AutomationProxy.
857     m_bAutomationProxy = DEFAULT_AUTOMATION_PROXY_VALUE;
858     GetAutomationProxyAttribute(pAssembly->GetManifestImport(), TokenFromRid(1, mdtAssembly), &m_bAutomationProxy);
859
860     // Pre load any caller-specified names into the typelib namespace.
861     PreLoadNames();
862
863     // Convert all the types.
864     ConvertAllTypeDefs();
865
866     // Set library level properties.
867     sName.AppendUTF8(pAssembly->GetSimpleName());
868     
869     // Make it a legal typelib name.
870     SString replaceChar = SL(W("_"));
871
872     SString::Iterator iter = sName.Begin();
873     while (sName.Find(iter, W(".")))
874         sName.Replace(iter, 1, replaceChar);
875
876     iter = sName.Begin();
877     while (sName.Find(iter, W(" ")))
878         sName.Replace(iter, 1, replaceChar);
879     
880     IfFailReport(m_pICreateTLB->SetName((LPOLESTR)sName.GetUnicode()));
881
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);
885
886     // Mark this typelib as exported.
887     LPCWSTR pszFullName;
888     {
889         //@todo:  exceptions?
890         StackSString name;
891         pAssembly->GetDisplayName(name);
892         pszFullName = name.GetUnicode();
893
894         vt.vt = VT_BSTR;
895         vt.bstrVal = SysAllocString(pszFullName);
896         if (vt.bstrVal == NULL)
897             IfFailReport(E_OUTOFMEMORY);
898     }
899     
900     //WszMultiByteToWideChar(CP_ACP,0, (char*)rBuf.Ptr(), (DWORD)rBuf.Size(), vt.bstrVal, (DWORD)rBuf.Size());
901     IfFailReport(m_pICreateTLB->SetCustData(GUID_ExportedFromComPlus, &vt));
902      
903     // Lay out the TypeInfos.
904     LayOut();
905
906     if(vt.bstrVal)
907     {
908         SysFreeString(vt.bstrVal);
909         vt.bstrVal = NULL;
910     }
911     
912 } // HRESULT TypeLibExporter::Convert()
913
914
915 void TypeLibExporter::UpdateBitness(Assembly* pAssembly)
916 {
917     WRAPPER_NO_CONTRACT;
918     
919     // If one has already been set, just return.
920     if ((TlbExportAs64Bit(m_flags)) || (TlbExportAs32Bit(m_flags)))
921         return;
922
923     // If we are exporting a dynamic assembly, just go with the machine type we're running on.
924     if (pAssembly->IsDynamic())
925     {
926 #ifdef _WIN64
927         m_flags |= TlbExporter_ExportAs64Bit;
928 #else
929         m_flags |= TlbExporter_ExportAs32Bit;
930 #endif
931         return;
932     }
933
934     // Get the assembly info
935     PEFile* pPEFile = pAssembly->GetDomainAssembly()->GetFile();
936     _ASSERTE(pPEFile);
937
938     DWORD PEKind, MachineKind;
939     pPEFile->GetPEKindAndMachine(&PEKind, &MachineKind);
940
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)
944     {
945         switch (MachineKind)
946         {
947             case IMAGE_FILE_MACHINE_IA64:
948             case IMAGE_FILE_MACHINE_AMD64:
949                 m_flags |= TlbExporter_ExportAs64Bit;
950                 break;
951
952             case IMAGE_FILE_MACHINE_I386:
953                 if ((PEKind & peILonly) == peILonly)
954                 {
955 #ifdef _WIN64
956                     m_flags |= TlbExporter_ExportAs64Bit;
957 #else
958                     m_flags |= TlbExporter_ExportAs32Bit;
959 #endif
960                 }
961                 else
962                 {
963                     _ASSERTE(!"Invalid MachineKind / PEKind pair on the assembly!");
964                 }
965                 break;
966
967             default:
968                 _ASSERTE(!"Unknown MachineKind!");
969         }
970     }
971     else if (MachineKind == IMAGE_FILE_MACHINE_I386)
972     {
973         if ((PEKind & pe32BitRequired) == pe32BitRequired)
974         {
975             m_flags |= TlbExporter_ExportAs32Bit;
976         }
977         else if ((PEKind & peILonly) == peILonly)
978         {
979 #ifdef _WIN64
980             m_flags |= TlbExporter_ExportAs64Bit;
981 #else
982             m_flags |= TlbExporter_ExportAs32Bit;
983 #endif
984         }
985         else
986         {
987             m_flags |= TlbExporter_ExportAs32Bit;
988         }
989     }
990     else if (MachineKind == IMAGE_FILE_MACHINE_ARMNT)
991     {
992         m_flags |= TlbExporter_ExportAs32Bit;
993     }
994     else
995     {
996 #ifdef _WIN64
997         m_flags |= TlbExporter_ExportAs64Bit;
998 #else
999         m_flags |= TlbExporter_ExportAs32Bit;
1000 #endif
1001     }
1002 }
1003
1004
1005 // Find out if our assembly / bitness combination is valid.
1006 HRESULT TypeLibExporter::CheckBitness(Assembly* pAssembly)
1007 {
1008     WRAPPER_NO_CONTRACT;
1009
1010     if (pAssembly->IsDynamic())
1011         return S_OK;
1012
1013     PEFile* pPEFile = pAssembly->GetDomainAssembly()->GetFile();
1014     if (pPEFile == NULL)
1015         return TLBX_E_BITNESS_MISMATCH;
1016
1017     DWORD PEKind, MachineKind;
1018     pPEFile->GetPEKindAndMachine(&PEKind, &MachineKind);
1019
1020     // Neutral assembly?
1021     if ((PEKind & peILonly) == peILonly)
1022         return S_OK;
1023
1024     if (IsExportingAs64Bit())
1025     {
1026         if ((MachineKind == IMAGE_FILE_MACHINE_IA64) || (MachineKind == IMAGE_FILE_MACHINE_AMD64))
1027             return S_OK;
1028     }
1029     else
1030     {
1031         if ((MachineKind == IMAGE_FILE_MACHINE_I386) || (MachineKind == IMAGE_FILE_MACHINE_ARMNT))
1032             return S_OK;
1033     }
1034
1035     return TLBX_E_BITNESS_MISMATCH;
1036 }
1037
1038
1039 //*****************************************************************************
1040 //*****************************************************************************
1041 void TypeLibExporter::PreLoadNames()
1042 {
1043     STANDARD_VM_CONTRACT;
1044
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.
1050     BSTR        name;
1051
1052     // Look for names provider, but don't require it.
1053     hr = SafeQueryInterface(m_pNotify, IID_ITypeLibExporterNameProvider, (IUnknown**)&pINames);
1054     if (FAILED(hr))
1055         return;
1056
1057     // There is a provider, so get the list of names.
1058     IfFailReport(pINames->GetNames(&pNames));
1059
1060     // Better have a single dimension array of strings.
1061     if (pNames == 0)
1062         IfFailReport(TLBX_E_BAD_NAMES);
1063     
1064     if (SafeArrayGetDim(pNames) != 1)
1065         IfFailReport(TLBX_E_BAD_NAMES);
1066     
1067     IfFailReport(SafeArrayGetVartype(pNames, &vt));
1068     if (vt != VT_BSTR)
1069         IfFailReport(TLBX_E_BAD_NAMES);
1070
1071     // Get names bounds.
1072     IfFailReport(SafeArrayGetLBound(pNames, 1, (LONG*)&lBound));
1073     IfFailReport(SafeArrayGetUBound(pNames, 1, (LONG*)&uBound));
1074
1075     // Enumerate the names.
1076     for (ix=lBound; ix<=uBound; ++ix)
1077     {
1078         IfFailReport(SafeArrayGetElement(pNames, (LONG*)&ix, (void*)&name));
1079         m_pICreateTLB->SetName(name);
1080     }
1081 }
1082
1083 //*****************************************************************************
1084 //*****************************************************************************
1085 void TypeLibExporter::FormatErrorContextString(
1086     CErrorContext *pContext,            // The context to format.
1087     SString       *pOut)                // Buffer to format into.
1088 {
1089     CONTRACTL
1090     {
1091         THROWS;
1092         GC_TRIGGERS;
1093         MODE_ANY;
1094         PRECONDITION(CheckPointer(pContext));
1095         PRECONDITION(CheckPointer(pOut));
1096     }
1097     CONTRACTL_END;
1098     
1099     HRESULT  hr;
1100     SString *pBuf;
1101     SString  ssInternal;
1102     
1103     // Nested contexts?
1104     if (pContext->m_prev == 0)
1105     {   // No, just convert into caller's buffer.
1106         pBuf = pOut;
1107     }
1108     else
1109     {   // Yes, convert locally, then concatenate.
1110         pBuf = &ssInternal;
1111     }
1112     
1113     // More?
1114     if (pContext->m_pScope)
1115     {   
1116         // Check whether type is nested (which requires more formatting).
1117         DWORD dwFlags;
1118         IfFailReport(pContext->m_pScope->GetTypeDefProps(pContext->m_tkType, &dwFlags, 0));
1119         
1120         if (IsTdNested(dwFlags))
1121         {
1122             TypeNameBuilder tnb(pBuf, TypeNameBuilder::ParseStateNAME);
1123             TypeString::AppendNestedTypeDef(tnb, pContext->m_pScope, pContext->m_tkType);
1124         }
1125         else
1126             TypeString::AppendTypeDef(*pBuf, pContext->m_pScope, pContext->m_tkType);
1127
1128         // Member?
1129         if (pContext->m_szMember)
1130         {
1131             pBuf->Append(NAMESPACE_SEPARATOR_WSTR);
1132             
1133             pBuf->AppendUTF8(pContext->m_szMember);
1134
1135             // Param?
1136             if (pContext->m_szParam)
1137             {
1138                 pBuf->Append(W("("));
1139                 pBuf->AppendUTF8(pContext->m_szParam);
1140                 pBuf->Append(W(")"));
1141             }
1142             else if (pContext->m_ixParam > -1)
1143             {
1144                 pBuf->AppendPrintf(W("(#%d)"), pContext->m_ixParam);
1145             }
1146         } // member
1147
1148         pBuf->Append(ASSEMBLY_SEPARATOR_WSTR);
1149     } // Type name
1150     
1151     pBuf->AppendUTF8(pContext->m_szAssembly);
1152     
1153     // If there is a nested context, put it all together.
1154     if (pContext->m_prev)
1155     {
1156         // Format the context this one was nested inside.
1157         SString ssOuter;
1158         FormatErrorContextString(pContext->m_prev, &ssOuter);
1159
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));
1164     }
1165 } // HRESULT TypeLibExporter::FormatErrorContextString()
1166
1167 //*****************************************************************************
1168 //*****************************************************************************
1169 void TypeLibExporter::FormatErrorContextString(
1170     SString    *pBuf)                   // Buffer to format into.
1171 {
1172     CONTRACTL
1173     {
1174         THROWS;
1175         GC_TRIGGERS;
1176         MODE_ANY;
1177         PRECONDITION(CheckPointer(pBuf));
1178     }
1179     CONTRACTL_END;
1180
1181     FormatErrorContextString(&m_ErrorContext, pBuf);
1182 } // HRESULT TypeLibExporter::FormatErrorContextString()
1183
1184 //*****************************************************************************
1185 // Event reporting helper.
1186 //*****************************************************************************
1187 void TypeLibExporter::ReportError(HRESULT hrRpt)
1188 {
1189     CONTRACTL
1190     {
1191         THROWS;
1192         GC_TRIGGERS;
1193         MODE_ANY;
1194     }
1195     CONTRACTL_END;
1196
1197     WCHAR      rcErr[1024];
1198     SString    ssName;
1199     SafeComHolder<IErrorInfo> pErrorInfo;
1200     BSTRHolder bstrDescription = NULL;
1201
1202     // Format the error message.
1203     if (SafeGetErrorInfo(&pErrorInfo) != S_OK)
1204         pErrorInfo = NULL;
1205
1206     // If we retrieved and IErrorInfo then retrieve the description.
1207     if (pErrorInfo)
1208     {
1209         if (FAILED(pErrorInfo->GetDescription(&bstrDescription)))
1210             bstrDescription = NULL;
1211     }
1212
1213     if (bstrDescription)
1214     {
1215         // Use the description as the error message.
1216         wcsncpy_s(rcErr, COUNTOF(rcErr), bstrDescription, _TRUNCATE);
1217     }
1218     else
1219     {
1220         // Format the error message.
1221         FormatRuntimeError(rcErr, lengthof(rcErr), hrRpt);
1222     }
1223
1224     // Format the context.
1225     FormatErrorContextString(&ssName);
1226
1227     // Post the error to the errorinfo object.
1228     VMPostError(TLBX_E_ERROR_MESSAGE, ssName.GetUnicode(), rcErr);
1229
1230     // Throw the exception, including context info.
1231     COMPlusThrowHR(TLBX_E_ERROR_MESSAGE, kGetErrorInfo);
1232 } // void TypeLibExporter::ReportError()
1233
1234 //*****************************************************************************
1235 // Event reporting helper.
1236 //*****************************************************************************
1237 void TypeLibExporter::ReportEvent(   // Returns the original HR.
1238     int         ev,                  // The event kind.
1239     int         hr,                  // HR.
1240     ...)                             // Variable args.
1241 {
1242     STANDARD_VM_CONTRACT;
1243
1244     WCHAR       rcMsg[1024];            // Buffer for message.
1245     va_list     marker;                 // User text.
1246     BSTRHolder  bstrMsg=0;              // BSTR for message.
1247     
1248     // Format the message.
1249     va_start(marker, hr);
1250     hr = FormatRuntimeErrorVa(rcMsg, lengthof(rcMsg), hr, marker);
1251     va_end(marker);
1252     
1253     // Convert to a BSTR.
1254     bstrMsg = SysAllocString(rcMsg);
1255     
1256     // Display it, and clean up.
1257     if (bstrMsg != NULL)
1258         m_pNotify->ReportEvent(static_cast<ImporterEventKind>(ev), hr, bstrMsg);
1259
1260 } // HRESULT CImportTlb::ReportEvent()
1261
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.
1269 {
1270     STANDARD_VM_CONTRACT;
1271
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.
1278     
1279     // Format the message.
1280     va_start(marker, hrRpt);
1281     FormatRuntimeErrorVa(rcErr, lengthof(rcErr), hrRpt, marker);
1282     va_end(marker);
1283     
1284     // Format the context.
1285     FormatErrorContextString(&ssName);
1286                         
1287     // Put them together.
1288     iLen = (UINT)(wcslen(rcErr) + ssName.GetCount() + 200);
1289     bstrBuf = SysAllocStringLen(0, iLen);
1290     
1291     if (bstrBuf != NULL)
1292     {
1293         FormatRuntimeError(bstrBuf, iLen, TLBX_W_WARNING_MESSAGE, ssName.GetUnicode(), rcErr);
1294         
1295         // Have to copy to another BSTR, because the runtime will also print the trash after the 
1296         //  terminating nul.
1297         bstrMsg = SysAllocString(bstrBuf);
1298         
1299         if (bstrMsg != NULL)
1300             m_pNotify->ReportEvent(NOTIF_CONVERTWARNING, hrRpt, bstrMsg);
1301     }
1302
1303 } // void TypeLibExporter::ReportWarning()
1304     
1305 // Throws exceptions encountered during type exportation.
1306 // Wrapped with ThrowHRWithContext.
1307 void TypeLibExporter::InternalThrowHRWithContext(HRESULT hrRpt, ...)
1308 {
1309     STANDARD_VM_CONTRACT;
1310
1311     WCHAR   rcErr[2048];
1312     SString ssName;
1313     va_list marker;  
1314
1315     // Format the error message.
1316     va_start(marker, hrRpt);
1317     FormatRuntimeErrorVa(rcErr, lengthof(rcErr), hrRpt, marker);
1318     va_end(marker);
1319
1320     // Format the context.
1321     FormatErrorContextString(&ssName);
1322
1323     // Post the error to the errorinfo object.
1324     VMPostError(TLBX_E_ERROR_MESSAGE, ssName.GetUnicode(), rcErr);
1325
1326     // Throw the exception, including context info.
1327     COMPlusThrowHR(TLBX_E_ERROR_MESSAGE, kGetErrorInfo);
1328 } // void TypeLibExporter::InternalThrowHRWithContext()
1329
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.
1336 {
1337     CONTRACTL
1338     {
1339         STANDARD_VM_CHECK;
1340         PRECONDITION(CheckPointer(pszName));
1341     }
1342     CONTRACTL_END;
1343
1344     // See if we got anything back.
1345     if (!message.IsEmpty())
1346         InternalThrowHRWithContext(TLBX_E_CLASS_LOAD_EXCEPTION, pszName, message.GetUnicode());
1347     else
1348         InternalThrowHRWithContext(TLBX_E_CANT_LOAD_CLASS, pszName);
1349 } // HRESULT TypeLibExporter::PostClassLoadError()
1350
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
1358 {
1359     CONTRACTL
1360     {
1361         STANDARD_VM_CHECK;
1362         PRECONDITION(CheckPointer(pClass));
1363         PRECONDITION(!pClass->IsInterface());
1364         PRECONDITION(CheckPointer(pClassItfType));
1365     }
1366     CONTRACTL_END;
1367
1368     HRESULT hr = S_OK;
1369     ComMethodTable *pClassComMT = NULL;
1370
1371     *pClassItfType = clsIfNone;
1372
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())
1376     {
1377         ComCallWrapperTemplate *pTemplate = ComCallWrapperTemplate::GetTemplate(pClass);
1378         if (pTemplate->SupportsIClassX())
1379         {
1380             pClassComMT = ComCallWrapperTemplate::SetupComMethodTableForClass(pClass, FALSE);
1381             _ASSERTE(pClassComMT);
1382
1383             if (pClassComMT->IsComVisible())
1384                 *pClassItfType = pClassComMT->GetClassInterfaceType();
1385         }
1386     }
1387 } // HRESULT TypeLibExporter::ClassHasIClassX()
1388
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.
1395 {
1396     CONTRACT(MethodTable *)
1397     {
1398         STANDARD_VM_CHECK;
1399         PRECONDITION(CheckPointer(pModule));
1400         POSTCONDITION(CheckPointer(RETVAL));
1401     }
1402     CONTRACT_END;
1403
1404     // Get the MethodTable for the token.        
1405     TypeHandle th;
1406     SString exceptionMessage;
1407
1408     EX_TRY
1409     {            
1410         th = ClassLoader::LoadTypeDefOrRefThrowing(pModule, tk,
1411                                                   ClassLoader::ThrowIfNotFound, 
1412                                                   ClassLoader::PermitUninstDefOrRef);
1413     }
1414     EX_CATCH
1415     {
1416         GET_EXCEPTION()->GetMessage(exceptionMessage);
1417     }
1418     EX_END_CATCH(SwallowAllExceptions);
1419
1420     if (th.IsNull())
1421     {
1422         // Format a hopefully useful error message.
1423         LPCUTF8 pNS, pName;
1424         SString sName;
1425             
1426         if (TypeFromToken(tk) == mdtTypeDef)
1427         {
1428             if (FAILED(pModule->GetMDImport()->GetNameOfTypeDef(tk, &pName, &pNS)))
1429             {
1430                 pName = pNS = "Invalid TypeDef record";
1431             }
1432         }
1433         else
1434         {
1435             _ASSERTE(TypeFromToken(tk) == mdtTypeRef);
1436             if (FAILED(pModule->GetMDImport()->GetNameOfTypeRef(tk, &pNS, &pName)))
1437             {
1438                 pNS = pName = "Invalid TypeRef record";
1439             }
1440         }
1441
1442         if (pNS && *pNS)
1443         {
1444             sName.AppendUTF8(pNS);
1445             sName.AppendUTF8(NAMESPACE_SEPARATOR_STR);
1446         }
1447             
1448         sName.AppendUTF8(pName);
1449             
1450         StackScratchBuffer scratch;
1451         PostClassLoadError(sName.GetUTF8(scratch), exceptionMessage);
1452     }
1453
1454     RETURN (th.AsMethodTable());
1455     
1456 } // void TypeLibExporter::LoadClass()
1457
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.
1464 {
1465     CONTRACT(TypeHandle)
1466     {
1467         STANDARD_VM_CHECK;
1468         PRECONDITION(CheckPointer(pModule));
1469         PRECONDITION(CheckPointer(pszName));
1470         POSTCONDITION(!RETVAL.IsNull());
1471     }
1472     CONTRACT_END;
1473
1474     TypeHandle th;
1475     SString exceptionMessage;
1476
1477     EX_TRY
1478     {            
1479         th = TypeName::GetTypeUsingCASearchRules(pszName, pModule->GetAssembly());
1480         _ASSERTE(!th.IsNull());
1481     }
1482     EX_CATCH
1483     {
1484         GET_EXCEPTION()->GetMessage(exceptionMessage);
1485     }
1486     EX_END_CATCH(SwallowAllExceptions);
1487
1488     if (th.IsNull())
1489     {
1490         PostClassLoadError(pszName, exceptionMessage);
1491     }
1492
1493     RETURN th;
1494
1495 } // void TypeLibExporter::LoadClass()
1496
1497
1498 //*****************************************************************************
1499 // Enumerate the TypeDefs and convert them to TypeInfos.
1500 //*****************************************************************************
1501 void TypeLibExporter::ConvertAllTypeDefs()
1502 {
1503     STANDARD_VM_CONTRACT;
1504
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.
1509     
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.
1515         
1516     cTypes = m_Exports.Count();
1517
1518     // If there are no types in the assembly, then we are done.
1519     if (cTypes <= 0)
1520         return;
1521     
1522     // Order by name, then look for duplicates.
1523     m_Exports.SortByName();                    
1524     
1525     // Resize the array for namespace flags now, but use the ICreateTypeInfo*, so that
1526     //  the flags will be sorted.
1527     bNamespace.ReSizeThrows(cTypes);
1528     
1529     // Get names of first type.
1530     pc1 = m_Exports[0]->pClass;
1531     IfFailReport(pc1->GetMDImport()->GetNameOfTypeDef(pc1->GetCl(), &pName1, &pNS1));
1532     
1533     // Iterate through the types, looking for duplicate type names.
1534     for (ix=0; ix<cTypes-1; ++ix)
1535     {
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));
1539         
1540         // If the types match (case insensitive). mark both types for namespace
1541         //  decoration.  
1542         if (stricmpUTF8(pName1, pName2) == 0)
1543         {
1544             m_Exports[ix]->pCTI = reinterpret_cast<ICreateTypeInfo2*>(1);
1545             m_Exports[ix+1]->pCTI = reinterpret_cast<ICreateTypeInfo2*>(1);
1546         }
1547         else
1548         {   // Didn't match, so advance "class 1" pointer.
1549             pc1 = pc2;
1550             pName1 = pName2;
1551             pNS1 = pNS2;
1552         }
1553     }
1554     
1555     // Put into token order for actual creation.
1556     m_Exports.SortByToken();
1557     
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)
1561     {
1562         if (m_Exports[ix]->pCTI)
1563             bNamespace[ix] = 1, m_Exports[ix]->pCTI = 0;
1564     }
1565     
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.
1578     
1579     // Step a, Create the TypeInfos for the TypeDefs, no decoration.
1580     for (ix=0; ix<cTypes; ++ix)
1581     {
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);
1587         
1588         CreateITypeInfo(pData, (bNamespace[ix]!=0), false);
1589     }
1590     // Step b, Create the TypeInfos for the TypeDefs, decoration as needed.
1591     for (ix=0; ix<cTypes; ++ix)
1592     {
1593         pData = m_Exports[ix];
1594         if (pData->pCTI == 0)
1595             CreateITypeInfo(pData, (bNamespace[ix]!=0), true);
1596     }
1597     
1598     // Step c, Create the TypeInfos for the IClassX interfaces.  No decoration.
1599     for (ix=0; ix<cTypes; ++ix)
1600     {
1601         pData = m_Exports[ix];
1602         CreateIClassXITypeInfo(pData, (bNamespace[ix]!=0), false);
1603     }
1604     // Step d, Create the TypeInfos for the IClassX interfaces.  Decoration as required.
1605     for (ix=0; ix<cTypes; ++ix)
1606     {
1607         pData = m_Exports[ix];
1608         if (pData->pCTIClassItf == 0)
1609             CreateIClassXITypeInfo(pData, (bNamespace[ix]!=0), true);
1610     }
1611     
1612     // Pass 2, add the ImplTypes to the CoClasses.
1613     for (ix=0; ix<cTypes; ++ix)
1614     {
1615         pData = m_Exports[ix];
1616         ConvertImplTypes(pData);
1617     }
1618     
1619     // Pass 3, fill in the TypeInfo details...
1620     for (ix=0; ix<cTypes; ++ix)
1621     {
1622         pData = m_Exports[ix];
1623         ConvertDetails(pData);
1624     }
1625     
1626     hr = S_OK;
1627 } // void TypeLibExporter::ConvertAllTypeDefs()
1628
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.
1636 {
1637     CONTRACTL
1638     {
1639         STANDARD_VM_CHECK;
1640         PRECONDITION(CheckPointer(pClass));
1641     }
1642     CONTRACTL_END;
1643
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.
1650
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;
1660     
1661     // See if this class is already in the list.
1662     sExported.pClass = pClass;
1663     pExported = m_InjectedExports.Find(&sExported);
1664     if (pExported == 0)
1665     {
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);
1670
1671         // New class, add to list.
1672         if (NULL == (pExported = m_InjectedExports.Add(&sExported)))
1673             IfFailReport(E_OUTOFMEMORY);
1674         m_InjectedExports.UpdateArray();
1675         
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);
1684
1685         // Step 1, Create the TypeInfos for the TypeDefs.
1686         CreateITypeInfo(pExported);
1687     
1688         // Step 1a, Create the TypeInfos for the IClassX interfaces.
1689         CreateIClassXITypeInfo(pExported);
1690     
1691         // Step 2, add the ImplTypes to the CoClasses.
1692         ConvertImplTypes(pExported);
1693     
1694         // Step 3, fill in the TypeInfo details...
1695         ConvertDetails(pExported);
1696     }
1697     
1698     // Restore error reporting context.
1699     m_ErrorContext = SavedContext;
1700     
1701     return (hr);
1702 } // HRESULT TypeLibExporter::ConvertOneTypeDef()
1703
1704
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.
1718 {
1719     CONTRACTL
1720     {
1721         STANDARD_VM_CHECK;
1722         PRECONDITION(CheckPointer(pData));
1723     }
1724     CONTRACTL_END;
1725
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.
1735
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.
1746
1747     DefineFullyQualifiedNameForClassW();
1748
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;
1753     
1754     // Error reporting info.
1755     m_ErrorContext.m_tkType = td;
1756     m_ErrorContext.m_pScope = pData->pClass->GetMDImport();
1757     
1758     pData->pCTI = 0;
1759     pData->pCTIClassItf = 0;
1760
1761     // If it is ComImport or WindowsRuntimeImport, do not export it.
1762     if (IsTdImport(dwFlags) || pData->pClass->IsProjectedFromWinRT())
1763         return;
1764
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)))
1768         return;
1769
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);
1773
1774     // Get the name.
1775     IfFailReport(pData->pClass->GetMDImport()->GetNameOfTypeDef(td, &pName, &pNS));
1776     
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);
1780
1781     // Warn about exporting generic classes.
1782     if (pData->pClass->GetNumGenericArgs() != 0)
1783         ReportWarning(TLBX_I_GENERIC_TYPE, TLBX_I_GENERIC_TYPE);
1784
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())
1788     {
1789         if (!pData->pClass->IsComImport() && IsTypeVisibleFromCom(thClass))
1790         {
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);        
1795         }
1796     }
1797         
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);
1801
1802     // workaround for microsoft.wfc.interop.dll -- skip their IDispatch.
1803     if (clsid == IID_IDispatch || clsid == IID_IUnknown)
1804     {
1805         ReportEvent(NOTIF_CONVERTWARNING, TLBX_S_NOSTDINTERFACE, pName);
1806         return;
1807     }
1808
1809     if (bNamespace)
1810     {
1811         sName.MakeFullNamespacePath(SString(SString::Utf8, pNS), SString(SString::Utf8, pName));
1812
1813         SString replaceChar = SL(W("_"));
1814
1815         SString::Iterator iter = sName.Begin();
1816         while (sName.Find(iter, W(".")))
1817             sName.Replace(iter, 1, replaceChar);
1818     }
1819     else
1820     {   // Convert name to wide chars.
1821         sName.AppendUTF8(pName);
1822     }
1823
1824     // Create the typeinfo for this typedef.
1825     for (;;)
1826     {
1827         // Attempt to create the TypeDef.
1828         hr = m_pICreateTLB->CreateTypeInfo((LPOLESTR)sName.GetUnicode(), tkind, &pCTITemp);
1829         
1830         // If a name conflict, decorate, otherwise, done.
1831         if (hr != TYPE_E_NAMECONFLICT)
1832             break;
1833             
1834         if (!bResolveDup)
1835         {
1836             hr = S_FALSE;
1837             return;
1838         }
1839
1840         if (iSuffix == 0)
1841         {           
1842             iSuffix = 2;
1843         }
1844         else
1845         {
1846             sName.Delete(sName.End()-=2, 2);            
1847         }
1848
1849         SString sDup;
1850         sDup.Printf(szDuplicateDecoration, iSuffix++);
1851
1852         sName.Append(sDup);
1853     }
1854     
1855     IfFailReport(hr);
1856     IfFailReport(SafeQueryInterface(pCTITemp, IID_ICreateTypeInfo2, (IUnknown**)&pCTI2));
1857     
1858     // Set the guid.
1859     _ASSERTE(clsid != GUID_NULL);
1860     hr = pCTI2->SetGuid(clsid);
1861     if (FAILED(hr))
1862     {
1863         if (hr == TYPE_E_DUPLICATEID)
1864         {
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);
1869         }
1870         return;
1871     }
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]); 
1874
1875     IfFailReport(pCTI2->SetVersion(1, 0));
1876
1877     // Record the fully qualified type name in a custom attribute.
1878     // If the TypelibImportClassAttribute exists, use that instead.
1879     SString sName2;
1880     hr = GetTypeLibImportClassName(pData->pClass, sName2);
1881     if (hr == S_OK)
1882     {      
1883         V_BSTR(&vt) = ::SysAllocString(sName2.GetUnicode());
1884         if (V_BSTR(&vt) == NULL)
1885             IfFailReport(E_OUTOFMEMORY);
1886
1887         V_VT(&vt) = VT_BSTR;
1888     }
1889     else
1890     {
1891         // Default to the real name.
1892         LPCWSTR pszName = GetFullyQualifiedNameForClassNestedAwareW(pData->pClass);
1893
1894         V_BSTR(&vt) = ::SysAllocString(pszName);
1895         if (V_BSTR(&vt) == NULL)
1896             IfFailReport(E_OUTOFMEMORY);
1897
1898         V_VT(&vt) = VT_BSTR;
1899     }
1900     
1901     IfFailReport(pCTI2->SetCustData(GUID_ManagedName, &vt));
1902
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));
1906     
1907     // Transfer ownership of the pointer.
1908     pData->pCTI = pCTI2;
1909     pCTI2.SuppressRelease();
1910     pCTI2 = 0;
1911 } // void TypeLibExporter::CreateITypeInfo()
1912
1913 HRESULT TypeLibExporter::GetTypeLibImportClassName(
1914     MethodTable*pClass,
1915     SString&    szName)
1916 {
1917     CONTRACTL
1918     {
1919         THROWS;
1920         GC_NOTRIGGER;
1921         MODE_ANY;
1922     }
1923     CONTRACTL_END;
1924     _ASSERTE(NULL != pClass);
1925
1926     HRESULT hr = S_OK;
1927
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.
1931
1932     hr = pClass->GetMDImport()->GetCustomAttributeByName(pClass->GetCl(),
1933                                                          INTEROP_TYPELIBIMPORTCLASS_TYPE,
1934                                                          reinterpret_cast<const void**>(&pvData),
1935                                                          &cbData);
1936
1937     if (hr == S_OK && cbData > 5 && pvData[0] == 1 && pvData[1] == 0)
1938     {       
1939         CustomAttributeParser cap(pvData, cbData);
1940         VERIFY(SUCCEEDED(cap.ValidateProlog())); // Validated above, just ensure consistency.
1941
1942         LPCUTF8 szString;
1943         ULONG   cbString;
1944         if (SUCCEEDED(cap.GetNonNullString(&szString, &cbString)))
1945         {
1946             // Set the string and null terminate it.
1947             szName.SetUTF8(szString, cbString);
1948             szName.AppendASCII("\0");
1949
1950             // We successfully retrieved the string.
1951             return S_OK;
1952         }
1953     }
1954
1955     return S_FALSE;
1956 }
1957
1958
1959
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.
1967 {
1968     CONTRACTL
1969     {
1970         STANDARD_VM_CHECK;
1971         PRECONDITION(CheckPointer(pClass));
1972     }
1973     CONTRACTL_END;
1974
1975     // Check for a description custom attribute.
1976     return GetStringCustomAttribute(pClass->GetMDImport(), XXX_DESCRIPTION_TYPE, tk, bstrDescr);
1977
1978 } // HRESULT TypeLibExporter::GetDescriptionString()
1979
1980 //*****************************************************************************
1981 // See if an object has a custom attribute, and get it as a BSTR.
1982 //*****************************************************************************
1983 BOOL TypeLibExporter::GetStringCustomAttribute(
1984     IMDInternalImport *pImport, 
1985     LPCSTR     szName, 
1986     mdToken     tk, 
1987     BSTR        &bstrDescr)
1988 {
1989     CONTRACTL
1990     {
1991         STANDARD_VM_CHECK;
1992         PRECONDITION(CheckPointer(pImport));
1993         PRECONDITION(CheckPointer(szName));
1994     }
1995     CONTRACTL_END;
1996
1997     HRESULT     hr;                     // A result.
1998     const void  *pvData;                // Pointer to a custom attribute data.
1999     ULONG       cbData;                 // Size of custom attribute data.
2000     
2001     // Look for the desired custom attribute.
2002     IfFailReport(pImport->GetCustomAttributeByName(tk, szName,  &pvData,&cbData));
2003     if (hr == S_OK && cbData > 2)
2004     {
2005         CustomAttributeParser cap(pvData, cbData);
2006         IfFailReport(cap.SkipProlog());
2007
2008         LPCUTF8 szString;
2009         ULONG   cbString;
2010         IfFailReport(cap.GetString(&szString, &cbString));
2011
2012         bstrDescr = SysAllocStringLen(0, cbString); // allocates cbString+1 characters (appends '\0')
2013         if (bstrDescr == NULL)
2014             IfFailReport(E_OUTOFMEMORY);
2015
2016         if (cbString > 0)
2017         {
2018             ULONG cch = WszMultiByteToWideChar(CP_UTF8, 0, szString, cbString, bstrDescr, cbString);
2019             bstrDescr[cch] = W('\0');
2020         }
2021
2022         return TRUE;
2023     }
2024     
2025     return FALSE;
2026 } // HRESULT GetStringCustomAttribute()
2027
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, 
2034     mdToken     tk, 
2035     int         *bValue)
2036 {
2037     CONTRACTL
2038     {
2039         STANDARD_VM_CHECK;
2040         PRECONDITION(CheckPointer(pImport));
2041         PRECONDITION(CheckPointer(bValue));
2042     }
2043     CONTRACTL_END;
2044
2045     HRESULT     hr;                     // A result.
2046     const void  *pvData;                // Pointer to a custom attribute data.
2047     ULONG       cbData;                 // Size of custom attribute data.
2048
2049     IfFailReport(pImport->GetCustomAttributeByName(tk, INTEROP_AUTOPROXY_TYPE, &pvData, &cbData));
2050     if (hr == S_OK && cbData > 2)
2051     {
2052         CustomAttributeParser cap(pvData, cbData);
2053         if (FAILED(cap.SkipProlog()))
2054             return FALSE;
2055
2056         UINT8 u1;
2057         if (FAILED(cap.GetU1(&u1)))
2058             return FALSE;
2059
2060         *bValue = u1 != 0;
2061     }
2062
2063     if (hr == S_OK)
2064         return TRUE;
2065
2066     return FALSE;
2067 } // void TypeLibExporter::GetAutomationProxyAttribute()
2068
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.
2076 {
2077     CONTRACTL
2078     {
2079         STANDARD_VM_CHECK;
2080         PRECONDITION(CheckPointer(pData));
2081     }
2082     CONTRACTL_END;
2083     
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.
2098     
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.
2109     
2110     MethodTable* pClassOuter = pData->pClass;
2111     
2112     DefineFullyQualifiedNameForClassW();
2113         
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;
2118     
2119     // Error reporting info.
2120     m_ErrorContext.m_tkType = td;
2121     m_ErrorContext.m_pScope = pData->pClass->GetMDImport();
2122     
2123     // A CoClass needs an IClassX, and an alias kind needs an alias.
2124     if (tkind != TKIND_COCLASS)
2125         return;
2126     
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)))
2130         return;
2131     
2132     // Imported types don't need an IClassX.
2133     if (IsTdImport(dwFlags))
2134         return;
2135     
2136     // Check to see if we need to set up an IClassX for the class.
2137     ClassHasIClassX(pData->pClass, &classItfType);
2138     if (classItfType == clsIfNone)
2139         return;
2140     
2141     // Get full name from metadata.
2142     IfFailReport(pData->pClass->GetMDImport()->GetNameOfTypeDef(td, &pName, &pNS));
2143     
2144     // Get the GUID for the class.  Used to generate IClassX guid.
2145     pData->pClass->GetGuid(&clsid, TRUE);
2146
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.
2149     if (pData->pCTI)
2150     {
2151         IfFailReport(SafeQueryInterface(pData->pCTI, IID_ITypeInfo, (IUnknown**)&pITemp));
2152         IfFailReport(pITemp->GetDocumentation(MEMBERID_NIL, &bstrName, 0,0,0));
2153         sName.Append(bstrName);
2154     }
2155     else
2156     {
2157         sName.AppendUTF8(pName);
2158     }
2159
2160     // Create the typeinfo name for the IClassX
2161     sNameTypeInfo.Set(cIClassX);
2162     sNameTypeInfo.Append(sName);
2163     
2164     tkind = TKIND_INTERFACE;
2165     pSuffix = 0;
2166     for (;;)
2167     {
2168         // Try to create the TypeInfo.
2169         hr = m_pICreateTLB->CreateTypeInfo((LPOLESTR)sNameTypeInfo.GetUnicode(), tkind, &pCTITemp);
2170         
2171         // If a name conflict, decorate, otherwise, done.
2172         if (hr != TYPE_E_NAMECONFLICT)
2173             break;
2174             
2175         if (!bResolveDup)
2176         {
2177             hr = S_FALSE;
2178             return;
2179         }
2180                 
2181         if (iSuffix == 0)
2182         {           
2183             iSuffix = 2;
2184         }
2185         else
2186         {
2187             sNameTypeInfo.Delete(sNameTypeInfo.End()-=2, 2);            
2188         }
2189
2190         SString sDup;
2191         sDup.Printf(szDuplicateDecoration, iSuffix++);
2192
2193         sNameTypeInfo.Append(sDup);
2194     }
2195     
2196     IfFailReport(hr);
2197     IfFailReport(SafeQueryInterface(pCTITemp, IID_ICreateTypeInfo2, (IUnknown**)&pCTI2));
2198     
2199     // Generate the "IClassX" UUID and set it.
2200     GenerateClassItfGuid(TypeHandle(pData->pClass), &guid);
2201     hr = pCTI2->SetGuid(guid);
2202     if (FAILED(hr))
2203     {
2204         if (hr == TYPE_E_DUPLICATEID)
2205         {
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);
2210         }
2211         return;
2212     }
2213
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));
2219
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);
2226
2227     IfFailReport(pCTI2->SetCustData(GUID_ManagedName, &vt));
2228
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]); 
2231
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));
2235     
2236     // Transfer ownership of the pointer.
2237     _ASSERTE(pData->pCTIClassItf == 0);
2238     pData->pCTIClassItf = pCTI2;
2239     pCTI2.SuppressRelease();
2240     pCTI2 = 0;
2241 } // HRESULT TypeLibExporter::CreateIClassXITypeInfo()
2242
2243 //*****************************************************************************
2244 // Add the impltypes to an ITypeInfo.
2245 //*****************************************************************************
2246 void TypeLibExporter::ConvertImplTypes(
2247     CExportedTypesInfo *pData)          // Conversion data.
2248 {
2249     CONTRACTL
2250     {
2251         STANDARD_VM_CHECK;
2252         PRECONDITION(CheckPointer(pData));
2253     }
2254     CONTRACTL_END;
2255     
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.
2260     
2261     // Get the TypeDef and some info about it.
2262     td = pData->pClass->GetCl();
2263     IfFailReport(pData->pClass->GetMDImport()->GetTypeDefProps(td, &dwFlags, 0));
2264     
2265     // Error reporting info.
2266     m_ErrorContext.m_tkType = td;
2267     m_ErrorContext.m_pScope = pData->pClass->GetMDImport();
2268     
2269     // If there is no ITypeInfo, skip it.
2270     if (pData->pCTI == 0)
2271         return;
2272     
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)))
2276         return;
2277     
2278     // Add the ImplTypes to the CoClass.
2279     switch (pData->tkind)
2280     {
2281     case TKIND_INTERFACE:
2282     case TKIND_DISPATCH:
2283         // Add the base type to the interface.
2284             ConvertInterfaceImplTypes(pData->pCTI, pData->pClass);
2285         break;
2286             
2287     case TKIND_RECORD:
2288     case TKIND_UNION:
2289     case TKIND_ENUM:
2290         // Nothing to do at this step.
2291         break;
2292             
2293     case TKIND_COCLASS:
2294         // Add the ImplTypes to the CoClass.
2295             ConvertClassImplTypes(pData->pCTI, pData->pCTIClassItf, pData->pClass);
2296         break;
2297             
2298     default:
2299         _ASSERTE(!"Unknown TYPEKIND");
2300             IfFailReport(E_INVALIDARG);
2301         break;
2302     }
2303 } // HRESULT TypeLibExporter::ConvertImplTypes()
2304
2305 //*****************************************************************************
2306 // Convert the details (members) of an ITypeInfo.
2307 //*****************************************************************************
2308 void TypeLibExporter::ConvertDetails(
2309     CExportedTypesInfo *pData)          // Conversion data.
2310 {
2311     CONTRACTL
2312     {
2313         STANDARD_VM_CHECK;
2314         PRECONDITION(CheckPointer(pData));
2315     }
2316     CONTRACTL_END;
2317     
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.
2322     
2323     // Get the TypeDef and some info about it.
2324     td = pData->pClass->GetCl();
2325     IfFailReport(pData->pClass->GetMDImport()->GetTypeDefProps(td, &dwFlags, 0));
2326     
2327     // Error reporting info.
2328     m_ErrorContext.m_tkType = td;
2329     m_ErrorContext.m_pScope = pData->pClass->GetMDImport();
2330     
2331     // If there is no TypeInfo, skip it, but for CoClass need to populate IClassX.
2332     if (pData->pCTI == 0 && pData->tkind != TKIND_COCLASS)
2333         return;
2334     
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)))
2338         return;
2339     
2340     // Fill in the rest of the typeinfo for this typedef.
2341     switch (pData->tkind)
2342     {
2343     case TKIND_INTERFACE:
2344     case TKIND_DISPATCH:
2345             ConvertInterfaceDetails(pData->pCTI, pData->pClass, pData->bAutoProxy);
2346         break;
2347             
2348     case TKIND_RECORD:
2349     case TKIND_UNION:
2350             ConvertRecord(pData);
2351         break;
2352             
2353     case TKIND_ENUM:
2354             ConvertEnum(pData->pCTI, pData->pClass);
2355         break;
2356             
2357     case TKIND_COCLASS:
2358         // Populate the methods on the IClassX interface.
2359             ConvertClassDetails(pData->pCTI, pData->pCTIClassItf, pData->pClass, pData->bAutoProxy);
2360         break;
2361             
2362     default:
2363         _ASSERTE(!"Unknown TYPEKIND");
2364             IfFailReport(E_INVALIDARG);
2365         break;
2366     } // Switch (tkind)
2367
2368     // Report that this type has been converted.
2369     SString ssType;
2370     if (IsTdNested(dwFlags))
2371     {
2372         TypeNameBuilder tnb(&ssType, TypeNameBuilder::ParseStateNAME);
2373         TypeString::AppendNestedTypeDef(tnb, m_ErrorContext.m_pScope, m_ErrorContext.m_tkType);
2374     }
2375     else
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()
2379     
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.
2386 {
2387     CONTRACTL
2388     {
2389         STANDARD_VM_CHECK;
2390         PRECONDITION(CheckPointer(pThisTypeInfo));
2391         PRECONDITION(CheckPointer(pClass));
2392     }
2393     CONTRACTL_END;
2394
2395     HRESULT     hr = S_OK;
2396     ULONG       ulIface;                // Is this interface [dual]?
2397     HREFTYPE    href;                   // href of base interface.
2398
2399     // IDispatch or IUnknown derived?
2400     IfFailReport(pClass->GetMDImport()->GetIfaceTypeOfTypeDef(pClass->GetCl(), &ulIface));
2401
2402     // Parent interface.
2403     if (IsDispatchBasedItf((CorIfaceAttr)ulIface))
2404     {
2405         // Get the HREFTYPE for IDispatch.
2406         GetRefTypeInfo(pThisTypeInfo, m_pIDispatch, &href);
2407     }
2408     else
2409     {
2410         // Get the HREFTYPE for IUnknown.
2411         GetRefTypeInfo(pThisTypeInfo, m_pIUnknown, &href);
2412     }
2413
2414     // Add the HREF as an interface.
2415     IfFailReport(pThisTypeInfo->AddImplType(0, href));
2416 } // void TypeLibExporter::ConvertInterfaceImplTypes()
2417
2418
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.
2426 {
2427     CONTRACTL
2428     {
2429         STANDARD_VM_CHECK;
2430         PRECONDITION(CheckPointer(pThisTypeInfo));
2431         PRECONDITION(CheckPointer(pMT));
2432     }
2433     CONTRACTL_END;
2434     
2435     HRESULT     hr = S_OK;
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.
2439
2440     // Retrieve the map of members.
2441     ComMTMemberInfoMap MemberMap(pMT);
2442
2443     // IDispatch or IUnknown derived?
2444     IfFailReport(pMT->GetMDImport()->GetIfaceTypeOfTypeDef(pMT->GetCl(), &ulIface));
2445     
2446     if (IsDispatchBasedItf((CorIfaceAttr)ulIface))
2447     {
2448         // IDispatch derived.
2449         dwTIFlags |= TYPEFLAG_FDISPATCHABLE;
2450         
2451         if (ulIface == ifDual)
2452             dwTIFlags |= TYPEFLAG_FDUAL | TYPEFLAG_FOLEAUTOMATION;
2453         else
2454             _ASSERTE(ulIface == ifDispatch);
2455     }
2456     else
2457     {
2458         // IUnknown derived.
2459         dwTIFlags |= TYPEFLAG_FOLEAUTOMATION;
2460     }
2461     
2462     if (!bAutoProxy)
2463         dwTIFlags |= TYPEFLAG_FPROXY;
2464
2465     // Set appropriate flags.
2466     IfFailReport(pThisTypeInfo->SetTypeFlags(dwTIFlags));
2467
2468     // Retrieve the method properties.
2469     size_t sizeOfPtr = IsExportingAs64Bit() ? 8 : 4;
2470     
2471     MemberMap.Init(sizeOfPtr);
2472     if (MemberMap.HadDuplicateDispIds())
2473         ReportWarning(TLBX_I_DUPLICATE_DISPID, TLBX_I_DUPLICATE_DISPID);
2474
2475     // We need a scope to bypass the inialization skipped by goto ErrExit 
2476     // compiler error.
2477     {
2478         CQuickArray<ComMTMethodProps> &rProps = MemberMap.GetMethods();
2479
2480         // Now add the methods to the TypeInfo.
2481         MethodTable::MethodIterator it(pMT);
2482         for (; it.IsValid(); it.Next())
2483         {
2484             if (it.IsVirtual())
2485             {
2486             // Only convert the method if it is visible from COM.
2487                 if (rProps[it.GetSlotNumber()].bMemberVisible)
2488             {
2489                     if (ConvertMethod(pThisTypeInfo, &rProps[it.GetSlotNumber()], cVisibleMembers, ulIface))
2490                     cVisibleMembers++;
2491                 }
2492             }
2493         }
2494     }
2495 } // void TypeLibExporter::ConvertInterfaceDetails()
2496
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.
2504 {
2505     CONTRACTL
2506     {
2507         STANDARD_VM_CHECK;
2508         PRECONDITION(CheckPointer(pData));
2509         PRECONDITION(CheckPointer(pSubMT));
2510     }
2511     CONTRACTL_END;
2512     
2513     // The typeinfo being created.
2514     ICreateTypeInfo2 *pThisTypeInfo = pData->pCTI;
2515
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
2524
2525     // To enum fields.
2526     HENUMInternalHolder eFDi(pSubMT->GetMDImport());
2527
2528     // If there is no class here, or if the class is Object, don't add members.
2529     if (pSubMT == 0 ||
2530         pSubMT == g_pObjectClass) 
2531         return;
2532
2533     // If this class has a base class, export those members first.
2534     ConvertRecordBaseClass(pData, pSubMT->GetParentMethodTable(), ixVar);
2535
2536     // Build the member name prefix.
2537     IfFailReport(pSubMT->GetMDImport()->GetNameOfTypeDef(pSubMT->GetCl(), &szName, &szNamespace));
2538     
2539     sName.SetUTF8(szName);
2540     sName.Append(W("_"));
2541         
2542     // Get an enumerator for the MemberDefs in the TypeDef.
2543     eFDi.EnumInit(mdtFieldDef, pSubMT->GetCl());
2544     cFD = pSubMT->GetMDImport()->EnumGetCount(&eFDi);
2545
2546     SString sNameMember;
2547     // For each MemberDef...
2548     for (iFD=0; iFD<cFD; ++iFD)
2549     {
2550         // Get the next field.
2551         if (!pSubMT->GetMDImport()->EnumNext(&eFDi, &fd))
2552         {
2553             IfFailReport(E_UNEXPECTED);
2554         }
2555         
2556         IfFailReport(pSubMT->GetMDImport()->GetFieldDefProps(fd, &dwFlags));
2557         
2558         // Only non-static fields.
2559         if (!IsFdStatic(dwFlags))
2560         {
2561             IfFailReport(pSubMT->GetMDImport()->GetNameOfFieldDef(fd, &szName));
2562             
2563             sNameMember.Set(sName);
2564             sNameMember.AppendUTF8(szName);
2565             if (ConvertVariable(pThisTypeInfo, pSubMT, fd, sNameMember, ixVar))
2566                 ixVar++;
2567         }
2568     }
2569 } // void TypeLibExporter::ConvertRecordBaseClass()
2570
2571 void TypeLibExporter::ConvertRecord(
2572     CExportedTypesInfo *pData)          // Conversion data.
2573 {
2574     CONTRACTL
2575     {
2576         STANDARD_VM_CHECK;
2577         PRECONDITION(CheckPointer(pData));
2578     }
2579     CONTRACTL_END;
2580     
2581     ICreateTypeInfo2 *pThisTypeInfo=pData->pCTI;     // The typeinfo being created.
2582     MethodTable     *pMT=pData->pClass;               // MethodTable for the TypeInfo.
2583
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.
2594
2595     // To enum fields.
2596     HENUMInternalHolder eFDi(pMT->GetMDImport());
2597
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)
2601     {
2602         IfFailReport(pMT->GetMDImport()->GetTypeDefProps(pMT->GetCl(), &dwFlags, &tkExtends));
2603         
2604         if (IsTdExplicitLayout(dwFlags))
2605         {
2606             ReportWarning(S_OK, TLBX_I_NONSEQUENTIALSTRUCT);
2607             return;
2608         }
2609     }
2610
2611     // Set the packing size, if there is one.
2612     dwPack = 0;
2613     if (FAILED(pMT->GetMDImport()->GetClassPackSize(pMT->GetCl(), &dwPack)))
2614     {
2615         dwPack = 0;
2616     }
2617     if (dwPack == 0)
2618     {
2619         dwPack = DEFAULT_PACKING_SIZE;
2620     }
2621     
2622     IfFailReport(pThisTypeInfo->SetAlignment((USHORT)dwPack));
2623
2624     // Haven't seen any non-public members yet.
2625     m_bWarnedOfNonPublic = FALSE;
2626
2627     // If this class has a base class, export those members first.
2628     ConvertRecordBaseClass(pData, pMT->GetParentMethodTable(), ixVar);
2629
2630     // Get an enumerator for the MemberDefs in the TypeDef.
2631     eFDi.EnumInit(mdtFieldDef, pMT->GetCl());
2632     cFD = pMT->GetMDImport()->EnumGetCount(&eFDi);
2633
2634     // For each MemberDef...
2635     for (iFD=0; iFD<cFD; ++iFD)
2636     {
2637         // Get the next field.
2638         if (!pMT->GetMDImport()->EnumNext(&eFDi, &fd))
2639         {
2640             IfFailReport(E_UNEXPECTED);
2641         }
2642         
2643         IfFailReport(pMT->GetMDImport()->GetFieldDefProps(fd, &dwFlags));
2644         
2645         // Skip static fields.
2646         if (IsFdStatic(dwFlags) == 0)
2647         {
2648             IfFailReport(pMT->GetMDImport()->GetNameOfFieldDef(fd, &szName));
2649             
2650             sName.SetUTF8(szName);
2651             if (ConvertVariable(pThisTypeInfo, pMT, fd, sName, ixVar))
2652                 ixVar++;
2653         }
2654     }
2655 } // HRESULT TypeLibExporter::ConvertRecord()
2656
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.
2663 {
2664     CONTRACTL
2665     {
2666         STANDARD_VM_CHECK;
2667         PRECONDITION(CheckPointer(pThisTypeInfo));
2668         PRECONDITION(CheckPointer(pMT));
2669     }
2670     CONTRACTL_END;
2671
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.
2683
2684     IMDInternalImport* pImport = pMT->GetMDImport();
2685
2686     // To enum fields.    
2687     HENUMInternalHolder eFDi(pImport);
2688    
2689     // Explicitly set the flags.
2690     IfFailReport(pThisTypeInfo->SetTypeFlags(dwTIFlags));
2691
2692     // Get an enumerator for the MemberDefs in the TypeDef.
2693     eFDi.EnumInit(mdtFieldDef, pMT->GetCl());
2694     cFD = pImport->EnumGetCount(&eFDi);
2695
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));
2699
2700     sName.Set(szThisTypeInfo);
2701     sName.Append(W("_"));
2702
2703     SString sNameMember;
2704     // For each MemberDef...
2705     for (iFD=0; iFD<cFD; ++iFD)
2706     {
2707         // Get the next field.
2708         if (!pImport->EnumNext(&eFDi, &fd))
2709         {
2710             IfFailReport(E_UNEXPECTED);
2711         }
2712         
2713         // Only convert static fields.
2714         IfFailReport(pImport->GetFieldDefProps(fd, &dwFlags));
2715         
2716         if (IsFdStatic(dwFlags) == 0)
2717         {
2718             continue;
2719         }
2720         
2721         // Skip ComVisible(false) members
2722         if (!IsMemberVisibleFromCom(pMT, fd, mdTokenNil))
2723         {
2724             continue;
2725         }
2726
2727         sNameMember.Set(sName);
2728         IfFailReport(pImport->GetNameOfFieldDef(fd, &szName));
2729         
2730         sNameMember.AppendUTF8(szName);
2731         
2732         if (ConvertEnumMember(pThisTypeInfo, pMT, fd, sNameMember, iVar))
2733         {
2734             iVar++;
2735         }
2736     }
2737 } // void TypeLibExporter::ConvertEnum()
2738
2739 //*****************************************************************************
2740 // Does a class have a default ctor?
2741 //*****************************************************************************
2742 BOOL TypeLibExporter::HasDefaultCtor(
2743     MethodTable     *pMT)                // The class in question.
2744 {
2745     CONTRACTL
2746     {
2747         STANDARD_VM_CHECK;
2748         PRECONDITION(CheckPointer(pMT));
2749     }
2750     CONTRACTL_END;
2751
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.
2764
2765     IMDInternalImport* pImport = pMT->GetMDImport();
2766     
2767     // To enum methods.
2768     HENUMInternalHolder eMDi(pImport);
2769
2770     // Get an enumerator for the MemberDefs in the TypeDef.
2771     eMDi.EnumInit(mdtMethodDef, pMT->GetCl());
2772     cMD = pImport->EnumGetCount(&eMDi);
2773
2774     // For each MemberDef...
2775     for (iMD=0; iMD<cMD; ++iMD)
2776     {
2777         // Get the next field.
2778         if (!pImport->EnumNext(&eMDi, &md))
2779         {
2780             IfFailReport(E_UNEXPECTED);
2781         }
2782         
2783         // Is the name special?  Is the method public?
2784         IfFailReport(pImport->GetMethodDefProps(md, &dwFlags));
2785         
2786         if (!IsMdRTSpecialName(dwFlags) || !IsMdPublic(dwFlags))
2787             continue;
2788         
2789         // Yes, is the name a ctor?
2790         IfFailReport(pImport->GetNameOfMethodDef(md, &pName));
2791         
2792         if (!IsMdInstanceInitializer(dwFlags, pName))
2793             continue;
2794         
2795         // It is a ctor.  Is it a default ctor?
2796         IfFailReport(pImport->GetSigOfMethodDef(md, &cbSig, &pSig));
2797         
2798         // Skip the calling convention, and get the param count.
2799         ixSig = CorSigUncompressData(pSig, &callconv);
2800         CorSigUncompressData(&pSig[ixSig], &cParams);
2801         
2802         // Default ctor has zero params.
2803         if (cParams == 0)
2804         {
2805             rslt = TRUE;
2806             break;
2807         }
2808     }
2809
2810     return rslt;
2811 } // BOOL TypeLibExporter::HasDefaultCtor()
2812
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.
2820 {
2821     CONTRACTL
2822     {
2823         STANDARD_VM_CHECK;
2824         PRECONDITION(CheckPointer(pThisTypeInfo, NULL_OK));
2825         PRECONDITION(CheckPointer(pClassItfTypeInfo, NULL_OK));
2826         PRECONDITION(CheckPointer(pMT));
2827     }
2828     CONTRACTL_END;
2829     
2830     HRESULT     hr = S_OK;
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;
2841
2842     SafeComHolder<ITypeInfo> pTI=0;                 // TypeInfo for default dispinterface.
2843     SafeComHolder<ICreateTypeInfo2> pCTI2 = NULL;   // The ICreateTypeInfo2 interface used to define custom data.
2844
2845     // We should never be converting the class impl types of COM imported CoClasses.
2846     _ASSERTE(!pMT->IsComImport());
2847     
2848     if (pThisTypeInfo)
2849     {   
2850         IfFailReport(pMT->GetMDImport()->GetTypeDefProps(pMT->GetCl(), &dwFlags, 0));
2851         
2852         // If abstract class, or no default ctor, don't make it creatable.
2853         if (!IsTdAbstract(dwFlags) && HasDefaultCtor(pMT))
2854             flags |= TYPEFLAG_FCANCREATE;
2855         
2856         // PreDeclid as appropriate.
2857         IfFailReport(pThisTypeInfo->SetTypeFlags(flags));
2858     }    
2859
2860     // Retrieve the MethodTable that represents the default interface.
2861     DefItfType = GetDefaultInterfaceForClassWrapper(TypeHandle(pMT), &hndDefItfClass);
2862
2863     // Remember the MethodTable of the default interface.
2864     pIDefault = hndDefItfClass.GetMethodTable();
2865
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)
2870     {   
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));
2875
2876         // If the class interface is the default interface, mark it as such.
2877         if (pMT == pIDefault)
2878             IfFailReport(pThisTypeInfo->SetImplTypeFlags(iImpl, IMPLTYPEFLAG_FDEFAULT));
2879
2880         // Increment the impl count.
2881         ++iImpl;
2882     }
2883
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)
2888     {
2889         // If the parent class has an IClassX interface then add it.
2890         ClassHasIClassX(pParentClass, &classItfType);
2891         if (classItfType == clsIfAutoDual)
2892         {
2893             hr = EEClassToHref(pThisTypeInfo, pParentClass, FALSE, &href);
2894
2895             // If not IUnknown, add the HREF as an interface.
2896             if (hr != S_USEIUNKNOWN)
2897             {
2898                 IfFailReport(pThisTypeInfo->AddImplType(iImpl, href));
2899                 if (pParentClass == pIDefault)
2900                     IfFailReport(pThisTypeInfo->SetImplTypeFlags(iImpl, IMPLTYPEFLAG_FDEFAULT));
2901
2902                 ++iImpl;
2903             }
2904         }
2905
2906         // Process the next class up the hierarchy.
2907         pParentClass = pParentClass->GetComPlusParentMethodTable();
2908     }
2909
2910     ComCallWrapperTemplate *pClassTemplate = ComCallWrapperTemplate::GetTemplate(TypeHandle(pMT));
2911     MethodTable::InterfaceMapIterator it = pMT->IterateInterfaceMap();
2912     while (it.Next())
2913     {
2914         flags = 0;
2915         
2916         // Get the MethodTable for an implemented interface.
2917         MethodTable *pIClass = it.GetInterface();
2918         
2919         // Retrieve the ComMethodTable for the interface.
2920         ComMethodTable *pItfComMT = pClassTemplate->GetComMTForItf(pIClass);
2921
2922         // If the interface is visible from COM, add it.
2923         if (IsTypeVisibleFromCom(TypeHandle(pIClass)) && !pItfComMT->IsComClassItf())
2924         {
2925 #if defined(_DEBUG)
2926             TRACE("Class %s implements %s\n", pMT->GetDebugClassName(), pIClass->GetDebugClassName());
2927 #endif
2928             // Get an href for the managed class.
2929             hr = EEClassToHref(pThisTypeInfo, pIClass, FALSE, &href);
2930             
2931             // If not IUnknown, add the HREF as an interface.
2932             if (hr != S_USEIUNKNOWN)
2933             {
2934                 if (pIClass == pIDefault)
2935                     flags |= IMPLTYPEFLAG_FDEFAULT;
2936
2937                 IfFailReport(pThisTypeInfo->AddImplType(iImpl, href));
2938                 IfFailReport(pThisTypeInfo->SetImplTypeFlags(iImpl, flags));
2939                 ++iImpl;
2940             }
2941         }
2942         else if (!IsTypeVisibleFromCom(TypeHandle(pIClass)) && (pIClass == pIDefault))
2943         {
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);
2946         }
2947     }
2948     
2949     // Retrieve the list of COM source interfaces for the managed class.
2950     GetComSourceInterfacesForClass(pMT, SrcItfList);
2951         
2952     // Add all the source interfaces to the CoClass.
2953     flags = IMPLTYPEFLAG_FSOURCE | IMPLTYPEFLAG_FDEFAULT;
2954     for (UINT i = 0; i < SrcItfList.Size(); i++)
2955     {
2956         hr = EEClassToHref(pThisTypeInfo, SrcItfList[i], FALSE, &href);
2957
2958         // If not IUnknown, add the HREF as an interface.
2959         if (hr != S_USEIUNKNOWN)
2960         {
2961             IfFailReport(pThisTypeInfo->AddImplType(iImpl, href));
2962             IfFailReport(pThisTypeInfo->SetImplTypeFlags(iImpl, flags));
2963             ++iImpl;
2964             flags = IMPLTYPEFLAG_FSOURCE;
2965         }
2966     }
2967 } // void TypeLibExporter::ConvertClassImplTypes()
2968         
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.
2977 {
2978     CONTRACTL
2979     {
2980         STANDARD_VM_CHECK;
2981         PRECONDITION(CheckPointer(pThisTypeInfo, NULL_OK));
2982         PRECONDITION(CheckPointer(pDefaultTypeInfo, NULL_OK));
2983         PRECONDITION(CheckPointer(pMT));
2984     }
2985     CONTRACTL_END;
2986
2987     HRESULT             hr = S_OK;
2988     CorClassIfaceAttr   classItfType = clsIfNone; 
2989     
2990     ClassHasIClassX(pMT, &classItfType);
2991     if (classItfType == clsIfAutoDual)
2992     {
2993         // Set up the IClassX interface.
2994         ConvertIClassX(pDefaultTypeInfo, pMT, bAutoProxy);
2995     }
2996     else if (pDefaultTypeInfo)
2997     {
2998         DWORD dwTIFlags = TYPEFLAG_FDUAL | TYPEFLAG_FOLEAUTOMATION | TYPEFLAG_FDISPATCHABLE | TYPEFLAG_FHIDDEN;
2999         if (!bAutoProxy)
3000             dwTIFlags |= TYPEFLAG_FPROXY;
3001         IfFailReport(pDefaultTypeInfo->SetTypeFlags(dwTIFlags));
3002     }
3003 } // void TypeLibExporter::ConvertClassDetails()
3004
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.
3012 {
3013     CONTRACTL
3014     {
3015         STANDARD_VM_CHECK;
3016         PRECONDITION(CheckPointer(pThisTypeInfo));
3017         PRECONDITION(CheckPointer(pMT));
3018     }
3019     CONTRACTL_END;
3020
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.
3027
3028     // Should be an actual class.
3029     _ASSERTE(!pMT->IsInterface());
3030
3031     // Retrieve the method properties.
3032     size_t sizeOfPtr = IsExportingAs64Bit() ? 8 : 4;
3033     
3034     MemberMap.Init(sizeOfPtr);
3035     if (MemberMap.HadDuplicateDispIds())
3036         ReportWarning(TLBX_I_DUPLICATE_DISPID, TLBX_I_DUPLICATE_DISPID);
3037
3038     // We need a scope to bypass the inialization skipped by goto ErrExit 
3039     // compiler error.
3040     {
3041         CQuickArray<ComMTMethodProps> &rProps = MemberMap.GetMethods();
3042         nSlots = (DWORD)rProps.Size();
3043
3044         dwTIFlags |= TYPEFLAG_FDUAL | TYPEFLAG_FOLEAUTOMATION | TYPEFLAG_FDISPATCHABLE | TYPEFLAG_FHIDDEN | TYPEFLAG_FNONEXTENSIBLE;
3045         if (!bAutoProxy)
3046             dwTIFlags |= TYPEFLAG_FPROXY;
3047         IfFailReport(pThisTypeInfo->SetTypeFlags(dwTIFlags));
3048
3049         // Assign slot numbers.
3050         for (i=0; i<nSlots; ++i)
3051             rProps[i].oVft = (short)((7 + i) * sizeOfPtr);
3052
3053         // Now add the methods to the TypeInfo.
3054         for (i=0; i<nSlots; ++i)
3055         {
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)
3059             {
3060                 if (rProps[i].semantic < FieldSemanticOffset)
3061                 {
3062                     if (ConvertMethod(pThisTypeInfo, &rProps[i], cVisibleMembers, ifDual))
3063                         cVisibleMembers++;
3064                 }
3065                 else
3066                 {
3067                     if (ConvertFieldAsMethod(pThisTypeInfo, &rProps[i], cVisibleMembers))
3068                         cVisibleMembers++;
3069                 }
3070             }
3071         }
3072     }
3073 } // void TypeLibExporter::ConvertIClassX()
3074
3075
3076 //*****************************************************************************
3077 // Export a Method's metadata to a typelib.
3078 //*****************************************************************************
3079 #ifdef _PREFAST_
3080 #pragma warning(push)
3081 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
3082 #endif
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?
3088 {
3089     CONTRACTL
3090     {
3091         STANDARD_VM_CHECK;
3092         PRECONDITION(CheckPointer(pCTI));
3093         PRECONDITION(CheckPointer(pProps));
3094     }
3095     CONTRACTL_END;
3096
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.
3135     
3136     ZeroHolder  zhParam = &m_ErrorContext.m_szParam;    // Clear error reporting info.
3137     ZeroHolder  zhMember = &m_ErrorContext.m_szMember;  // Clear error reporting info.
3138
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));
3145     
3146     // Error reporting info.
3147     IfFailReport(pInternalImport->GetNameOfMethodDef(pMeth->GetMemberDef(), &m_ErrorContext.m_szMember));
3148     
3149     // Allocate one variant.
3150     pParamDesc = reinterpret_cast<PARAMDESCEX*>(sVariants.AllocZero(sizeof(PARAMDESCEX)));
3151     if(NULL == pParamDesc)
3152         IfFailReport(E_OUTOFMEMORY);
3153
3154     // Prepare to parse signature and build the FUNCDESC.
3155     pfunc = reinterpret_cast<FUNCDESC*>(sPool.AllocZero(sizeof(FUNCDESC)));
3156     if (pfunc == NULL)
3157         IfFailReport(E_OUTOFMEMORY);
3158     
3159     ixSig = 0;
3160
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];
3165
3166     // vtable offset.
3167     pfunc->oVft = pProps->oVft;
3168
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));
3174
3175     // Set some method properties.
3176     pfunc->memid = pProps->dispid;
3177     if (pfunc->memid == -11111) //@todo: fix for msvbalib.dll
3178         pfunc->memid = -1;
3179     pfunc->funckind = FUNC_PUREVIRTUAL;
3180
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;
3190     else
3191         pfunc->invkind = INVOKE_FUNC; // non-accessor property function.
3192
3193     rNames[0] = pProps->pName;
3194     cNames = 1;
3195     
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.
3199
3200     // Get the return type.  
3201     cbElem = CorSigUncompressData(&pbSig[ixSig], &ret);
3202
3203     // Error reporting info.
3204     m_ErrorContext.m_ixParam = 0;
3205     
3206     // Get native type of return if available
3207     mdParamDef pdParam;
3208     pvNativeType = NULL;
3209     hr = pInternalImport->FindParamOfMethod(pMeth->GetMemberDef(), 0, &pdParam);
3210     if (hr == S_OK)
3211     {
3212         hr = pInternalImport->GetFieldMarshal(pdParam, &pvNativeType, &cbNativeType);
3213         if (hr != CLDB_E_RECORD_NOTFOUND)
3214         {
3215             IfFailReport(hr);
3216         }
3217     }
3218     
3219     // Determine if we need to do HRESULT munging.
3220     bHrMunge = !IsMiPreserveSig(dwImplFlags);
3221     
3222     // Reset some properties for DISPINTERFACES.
3223     if (ulIface == ifDispatch)
3224     {
3225         pfunc->callconv = CC_STDCALL;
3226         pfunc->funckind = FUNC_DISPATCH;
3227         
3228         // Never munge a dispinterface.
3229         bHrMunge = false;
3230     }
3231     
3232     if (bHrMunge)
3233     {
3234         // Munge the return type into a new last param, set return type to HRESULT.
3235         pfunc->elemdescFunc.tdesc.vt = VT_HRESULT;
3236         
3237         // Does the function actually return anything?
3238         if (ret == ELEMENT_TYPE_VOID)
3239         {
3240             // Skip over the return value, no [retval].
3241             pRetVal = 0;
3242             ixSig += cbElem;
3243         }
3244         else
3245         {
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);
3250             
3251             hr = CorSigToTypeDesc(pCTI, pMT, &pbSig[ixSig], pvNativeType, cbNativeType, &cbElem, pRetVal, &sPool, TRUE);
3252             if (FAILED(hr))
3253                 return FALSE;
3254             
3255             ixSig += cbElem;
3256
3257             ++cDestParams;
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);
3260
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)
3267             {
3268                 pRetVal->vt = VT_PTR;
3269                 pRetVal->lptdesc = &pRetVal->lpadesc->tdescElem;
3270             }
3271         }
3272     }
3273     else
3274     {
3275         // No munging, convert return type.
3276         pRetVal = 0;
3277         hr = CorSigToTypeDesc(pCTI, pMT, &pbSig[ixSig], pvNativeType, cbNativeType, &cbElem, &pfunc->elemdescFunc.tdesc, &sPool, TRUE);
3278         if (FAILED(hr))
3279             return FALSE;
3280         
3281         ixSig += cbElem;
3282     }
3283
3284     // Error reporting info.
3285     m_ErrorContext.m_ixParam = -1;
3286     
3287     // Check to see if there is an LCIDConversion attribute on the method.
3288     iLCIDParam = (USHORT)GetLCIDParameterIndex(pMeth);
3289     if (iLCIDParam != (USHORT)-1)
3290     {
3291         BOOL bValidLCID = TRUE;
3292
3293         // Make sure the parameter index is valid.
3294         if (iLCIDParam > cSrcParams)
3295         {
3296             ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_INVALIDLCIDPARAM);
3297             bValidLCID = FALSE;
3298         }
3299
3300         // LCID's are not allowed on pure dispatch interfaces.
3301         if (ulIface == ifDispatch)
3302         {
3303             ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_LCIDONDISPONLYITF);
3304             bValidLCID = FALSE;
3305         }
3306
3307         if (bValidLCID)
3308         {
3309             // Take the LCID parameter into account in the exported method.
3310             ++cDestParams;
3311         }
3312         else
3313         {
3314             // The LCID is invalid so we will ignore it.
3315             iLCIDParam = -1;
3316         }
3317     }
3318
3319     // for each parameter
3320     pfunc->lprgelemdescParam = reinterpret_cast<ELEMDESC*>(sPool.AllocZero(cDestParams * sizeof(ELEMDESC)));
3321     if (pfunc->lprgelemdescParam == NULL)
3322         IfFailReport(E_OUTOFMEMORY);
3323     
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];
3327     
3328     // Variant array used to hold default value data
3329     NewArrayHolder<VariantPtrHolder> vtDefaultValues = new VariantPtrHolder[cDestParams];
3330
3331     pfunc->cParams = static_cast<short>(cDestParams);
3332     for (iSrcParam=1, iDestParam=0; iDestParam<cDestParams; ++iSrcParam, ++iDestParam)
3333     {   
3334         // Check to see if we need to insert the LCID param before the current param.
3335         if (iLCIDParam == iDestParam)
3336         {
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;
3340
3341             // Generate a parameter name.
3342             sName.Printf(szParamName, iDestParam + 1);
3343
3344             rNames[iDestParam + 1] = SysAllocString(sName.GetUnicode());
3345             if (rNames[iDestParam + 1] == NULL)
3346                 IfFailReport(E_OUTOFMEMORY);
3347
3348             namesHolder[iDestParam+1] = rNames[iDestParam + 1];
3349             
3350             ++cNames;
3351
3352             // Increment the current destination parameter.
3353             ++iDestParam;
3354         }
3355
3356         // If we are past the end of the source parameters then we are done.
3357         if (iSrcParam > cSrcParams)
3358             break;
3359
3360         // Get additional parameter metadata.
3361         dwParamFlags = 0;
3362         sName.Clear();
3363
3364         // Error reporting info.
3365         m_ErrorContext.m_ixParam = iSrcParam;
3366         
3367         // See if there is a ParamDef for this param.
3368         hr = pInternalImport->FindParamOfMethod(pMeth->GetMemberDef(), iSrcParam, &pdParam);
3369
3370         pvNativeType = NULL;
3371         if (hr == S_OK)
3372         {   
3373             // Get info about the param.        
3374             IfFailReport(pInternalImport->GetParamDefProps(pdParam, &iSrcParam, &dwParamFlags, &pszName));
3375             
3376             // Error reporting info.
3377             m_ErrorContext.m_szParam = pszName;
3378             
3379             // Turn off reserved (internal use) bits.
3380             dwParamFlags &= ~pdReservedMask;
3381
3382             // Convert name from UTF8 to unicode.
3383             sName.SetUTF8(pszName);
3384
3385             // Param default value, if any.
3386             IfFailReport(pInternalImport->GetDefaultValue(pdParam, &defaultValue));
3387             IfFailReport(_FillVariant(&defaultValue, &pParamDesc->varDefaultValue));
3388
3389             // If no default value, check for decimal custom attribute.
3390             if (pParamDesc->varDefaultValue.vt == VT_EMPTY)
3391             {
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)))
3394                 {
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);
3402                 }
3403             }
3404             // If still no default value, check for date time custom attribute.
3405             if (pParamDesc->varDefaultValue.vt == VT_EMPTY)
3406             {
3407                 IfFailReport(pMT->GetMDImport()->GetCustomAttributeByName(pdParam, INTEROP_DATETIMEVALUE_TYPE,  &pvData,&cbData));
3408                 if (hr == S_OK && cbData >= (2 + sizeof(__int64)))
3409                 {
3410                     const BYTE *pbData = (const BYTE *)pvData;
3411                     pParamDesc->varDefaultValue.vt = VT_DATE;
3412                     pParamDesc->varDefaultValue.date = _TicksToDoubleDate(GET_UNALIGNED_64(pbData+2));
3413                 }
3414             }
3415             // If still no default value, check for IDispatch custom attribute.
3416             if (pParamDesc->varDefaultValue.vt == VT_EMPTY)
3417             {
3418                 IfFailReport(pMT->GetMDImport()->GetCustomAttributeByName(pdParam, INTEROP_IDISPATCHVALUE_TYPE,  &pvData,&cbData));
3419                 if (hr == S_OK)
3420                 {
3421                     pParamDesc->varDefaultValue.vt = VT_DISPATCH;
3422                     pParamDesc->varDefaultValue.pdispVal = 0;
3423                 }
3424             }
3425             // If still no default value, check for IUnknown custom attribute.
3426             if (pParamDesc->varDefaultValue.vt == VT_EMPTY)
3427             {
3428                 IfFailReport(pMT->GetMDImport()->GetCustomAttributeByName(pdParam, INTEROP_IUNKNOWNVALUE_TYPE,  &pvData,&cbData));
3429                 if (hr == S_OK)
3430                 {
3431                     pParamDesc->varDefaultValue.vt = VT_UNKNOWN;
3432                     pParamDesc->varDefaultValue.punkVal = 0;
3433                 }
3434             }
3435             
3436             if (pParamDesc->varDefaultValue.vt != VT_EMPTY)
3437             {
3438                 // Copy the variant into the holder object so we release on function exit.
3439                 vtDefaultValues[iDestParam] = (VARIANT*)&pParamDesc->varDefaultValue;
3440                 
3441                 pfunc->lprgelemdescParam[iDestParam].paramdesc.pparamdescex = pParamDesc;
3442                 dwParamFlags |= PARAMFLAG_FHASDEFAULT;
3443
3444                 // Allocate another paramdesc.
3445                 pParamDesc = reinterpret_cast<PARAMDESCEX*>(sVariants.AllocZero(sizeof(PARAMDESCEX)));
3446                 if (pParamDesc == NULL)
3447                     IfFailReport(E_OUTOFMEMORY);
3448                 
3449                 bHasOptorDefault = true;
3450             }
3451
3452             // native marshal type, if any.
3453             hr = pInternalImport->GetFieldMarshal(pdParam, &pvNativeType, &cbNativeType);
3454             if (hr != CLDB_E_RECORD_NOTFOUND)
3455             {
3456                 IfFailReport(hr);
3457             }
3458             
3459             // Remember if there are optional params.
3460             if (dwParamFlags & PARAMFLAG_FOPT)
3461                 bHasOptorDefault = true;
3462         }
3463         else
3464         {
3465             pdParam = 0, m_ErrorContext.m_szParam = 0;
3466         }
3467         
3468         // Do we need a name for this parameter?
3469         if ((pfunc->invkind & (INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF)) == 0 ||
3470             iSrcParam < cSrcParams)
3471         {
3472             // Yes, so make one up if we don't have one.
3473             if (sName.GetCount() == 0) 
3474             {
3475                 sName.Printf(szParamName, iDestParam + 1);
3476             }
3477
3478             rNames[iDestParam + 1] = SysAllocString(sName.GetUnicode());
3479             if (rNames[iDestParam + 1] == NULL)
3480                 IfFailReport(E_OUTOFMEMORY);
3481
3482             namesHolder[iDestParam+1] = rNames[iDestParam + 1];
3483             
3484             ++cNames;
3485         }
3486
3487         // Save the element type.
3488         CorSigUncompressData(&pbSig[ixSig], &elem);
3489         
3490         // Convert the param info to elemdesc.
3491         bByRef = FALSE;
3492         hr = CorSigToTypeDesc(pCTI, pMT, &pbSig[ixSig], pvNativeType, cbNativeType, &cbElem,
3493                             &pfunc->lprgelemdescParam[iDestParam].tdesc, &sPool, TRUE, &bByRef);
3494         if (FAILED(hr))
3495             return FALSE;
3496         
3497         ixSig += cbElem;
3498
3499         // If there is no [in,out], set one, based on the parameter.
3500         if ((dwParamFlags & (PARAMFLAG_FOUT | PARAMFLAG_FIN)) == 0)
3501         {
3502             // If param is by reference, make in/out
3503             if (bByRef)
3504                 dwParamFlags |= PARAMFLAG_FIN | PARAMFLAG_FOUT;
3505             else
3506                 dwParamFlags |= PARAMFLAG_FIN;
3507         }
3508
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) 
3512         {
3513             if (pfunc->lprgelemdescParam[iDestParam].tdesc.vt == VT_SAFEARRAY &&
3514                 pfunc->lprgelemdescParam[iDestParam].tdesc.lpadesc->tdescElem.vt == VT_VARIANT)
3515             {
3516                 if (pInternalImport->GetCustomAttributeByName(pdParam, INTEROP_PARAMARRAY_TYPE, 0,0) == S_OK)
3517                     pfunc->cParamsOpt = -1;
3518             }
3519         }
3520         
3521         pfunc->lprgelemdescParam[iDestParam].paramdesc.wParamFlags = static_cast<USHORT>(dwParamFlags);
3522     }
3523
3524     // Is there a [retval]?
3525     if (pRetVal)
3526     {
3527         // Error reporting info.
3528         m_ErrorContext.m_ixParam = 0;
3529         m_ErrorContext.m_szParam = 0;
3530         
3531         _ASSERTE(bHrMunge);
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;
3536
3537         // no need to allocate a new string for this.  rather use the constant szRetVal
3538         rNames[cDestParams] = (LPWSTR)szRetVal;
3539
3540         ++cNames;
3541     }
3542
3543     // Error reporting info.
3544     m_ErrorContext.m_ixParam = -1;
3545     
3546     // Was there a signature error?  If so, exit now that all sigs have been reported.
3547     IfFailReport(hrSignature);
3548     
3549     IfFailReport(pCTI->AddFuncDesc(iMD, pfunc));
3550
3551     IfFailReport(pCTI->SetFuncAndParamNames(iMD, rNames.Ptr(), cNames));
3552
3553     if (pProps->bFunction2Getter)
3554     {
3555         VARIANT vtOne;
3556         vtOne.vt = VT_I4;
3557         vtOne.lVal = 1;
3558         IfFailReport(pCTI->SetFuncCustData(iMD, GUID_Function2Getter, &vtOne));
3559     }
3560
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)
3565     {
3566         sName.SetUTF8(pMeth->GetName());
3567         if (sName.Compare(SString(pProps->pName)) != 0)
3568         {
3569             V_VT(&vtManagedName) = VT_BSTR;
3570
3571             if (NULL == (V_BSTR(&vtManagedName) = SysAllocString(sName.GetUnicode())))
3572                 IfFailReport(E_OUTOFMEMORY);
3573
3574             IfFailReport(pCTI->SetFuncCustData(iMD, GUID_ManagedName, &vtManagedName));
3575         }
3576     }
3577
3578     // Check for a description.
3579     if(GetDescriptionString(pMT, pMeth->GetMemberDef(), (BSTR &)bstrDescr))
3580         IfFailReport(pCTI->SetFuncDocString(iMD, bstrDescr));
3581     
3582
3583     // Error reporting info.
3584     m_ErrorContext.m_szMember = 0;
3585     m_ErrorContext.m_szParam = 0;
3586     m_ErrorContext.m_ixParam = -1;
3587
3588     return TRUE;
3589 } // void TypeLibExporter::ConvertMethod()
3590 #ifdef _PREFAST_
3591 #pragma warning(pop)
3592 #endif
3593     
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
3601 {
3602     CONTRACTL
3603     {
3604         STANDARD_VM_CHECK;
3605         PRECONDITION(CheckPointer(pCTI));
3606         PRECONDITION(CheckPointer(pProps));
3607     }
3608     CONTRACTL_END;
3609
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.
3615
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.
3629
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();
3636
3637     // Error reporting info.
3638     IfFailReport(pMT->GetMDImport()->GetNameOfFieldDef(pField->GetMemberDef(), &m_ErrorContext.m_szMember));
3639     
3640     // Prepare to parse signature and build the FUNCDESC.
3641     pfunc = reinterpret_cast<FUNCDESC*>(sPool.AllocZero(sizeof(FUNCDESC)));
3642     if (NULL == pfunc)
3643         IfFailReport(E_OUTOFMEMORY);
3644     ixSig = 0;
3645
3646     // Get the calling convention.
3647     ixSig += CorSigUncompressData(&pbSig[ixSig], &callconv);
3648     _ASSERTE(callconv == IMAGE_CEE_CS_CALLCONV_FIELD);
3649     pfunc->callconv = CC_STDCALL;
3650
3651     // vtable offset.
3652     pfunc->oVft = pProps->oVft;
3653
3654     // Set some method properties.
3655     pfunc->memid = pProps->dispid;
3656     pfunc->funckind = FUNC_PUREVIRTUAL;
3657
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)
3662     {
3663         if (IsVbRefType(&pbSig[ixSig], pInternalImport))
3664             pfunc->invkind = INVOKE_PROPERTYPUTREF;
3665         else
3666             pfunc->invkind = INVOKE_PROPERTYPUT;
3667     }
3668     else
3669         _ASSERTE(!"Incorrect semantic in ConvertFieldAsMethod");
3670
3671     // Name of the function.
3672     rNames[0] = pProps->pName;
3673     cNames = 1;
3674
3675     // Return type is HRESULT.
3676     pfunc->elemdescFunc.tdesc.vt = VT_HRESULT;
3677
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);
3682     pfunc->cParams = 1;
3683
3684     // Do we need a name for the parameter?  If PROPERTYGET, we do.
3685     if (pfunc->invkind == INVOKE_PROPERTYGET)
3686     {
3687         // Yes, so make one up.
3688         rNames[1] = (WCHAR*)szRetVal;
3689         ++cNames;
3690     }
3691
3692     // If Getter, convert param as ptr, otherwise convert directly.
3693     if (pfunc->invkind == INVOKE_PROPERTYGET)
3694     {
3695         pType = reinterpret_cast<TYPEDESC*>(sPool.AllocZero(sizeof(TYPEDESC)));
3696         if (NULL == pType)
3697             IfFailReport(E_OUTOFMEMORY);
3698
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;
3702     }
3703     else
3704     {
3705         pType = &pfunc->lprgelemdescParam[0].tdesc;
3706         pfunc->lprgelemdescParam[0].paramdesc.wParamFlags = PARAMFLAG_FIN;
3707     }
3708
3709     // Get native field type
3710     pvNativeType = NULL;
3711     hr = pInternalImport->GetFieldMarshal(
3712         pField->GetMemberDef(), 
3713         &pvNativeType, 
3714         &cbNativeType);
3715     if (hr != CLDB_E_RECORD_NOTFOUND)
3716     {
3717         IfFailReport(hr);
3718     }
3719     
3720     // Convert the field type to elemdesc.
3721     hr = CorSigToTypeDesc(pCTI, pMT, &pbSig[ixSig], pvNativeType, cbNativeType, &cbElem, pType, &sPool, TRUE);
3722     if (FAILED(hr))
3723         return FALSE;
3724
3725     ixSig += cbElem;
3726
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)
3735     {
3736         pfunc->lprgelemdescParam[0].tdesc.vt = pType->vt;
3737         pfunc->lprgelemdescParam[0].tdesc.lptdesc = pType->lptdesc;
3738     }
3739
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))
3743     {
3744         pfunc->invkind = INVOKE_PROPERTYPUTREF;
3745     }
3746     
3747     IfFailReport(pCTI->AddFuncDesc(iMD, pfunc));
3748
3749     IfFailReport(pCTI->SetFuncAndParamNames(iMD, rNames, cNames));
3750
3751     // Check for a description.
3752     if(GetDescriptionString(pMT, pField->GetMemberDef(), (BSTR &)bstrDescr))
3753         IfFailReport(pCTI->SetFuncDocString(iMD, bstrDescr));
3754     
3755     // Error reporting info.
3756     m_ErrorContext.m_szMember = 0;
3757
3758     return TRUE;
3759 } // void TypeLibExporter::ConvertFieldAsMethod()
3760
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
3770 {
3771     CONTRACTL
3772     {
3773         STANDARD_VM_CHECK;
3774         PRECONDITION(CheckPointer(pCTI));
3775         PRECONDITION(CheckPointer(pMT));
3776     }
3777     CONTRACTL_END;
3778
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.
3797
3798     VARIANT       vtTemp;
3799     VariantPtrHolder vtVariant = &vtTemp;
3800
3801     SafeVariantInit(vtVariant);
3802
3803     // Error reporting info.
3804     IfFailReport(pMT->GetMDImport()->GetNameOfFieldDef(md, &m_ErrorContext.m_szMember));
3805     
3806     // Get info about the field.
3807     IfFailReport(pMT->GetMDImport()->GetDispIdOfMemberDef(md, &dispid));
3808     IfFailReport(pMT->GetMDImport()->GetFieldDefProps(md, &dwFlags));
3809     if (IsFdHasDefault(dwFlags))
3810     {
3811         IfFailReport(pMT->GetMDImport()->GetDefaultValue(md, &defaultValue));
3812         IfFailReport( _FillVariant(&defaultValue, vtVariant) ); 
3813     }
3814
3815     // If exporting a non-public member of a struct, warn the user.
3816     if (!IsFdPublic(dwFlags) && !m_bWarnedOfNonPublic)
3817     {
3818         m_bWarnedOfNonPublic = TRUE;
3819         ReportWarning(TLBX_E_NONPUBLIC_FIELD, TLBX_E_NONPUBLIC_FIELD);
3820     }
3821
3822     IfFailReport(pMT->GetMDImport()->GetSigOfFieldDef(md, &cbSig, &pbSig));
3823     
3824     // Prepare to parse signature and build the VARDESC.
3825     pvar = reinterpret_cast<VARDESC*>(sPool.AllocZero(sizeof(VARDESC)));
3826     if(pvar == NULL)
3827         IfFailReport(E_OUTOFMEMORY);
3828     ixSig = 0;
3829
3830     // Get the calling convention.
3831     ixSig += CorSigUncompressData(&pbSig[ixSig], &callconv);
3832     _ASSERTE(callconv == IMAGE_CEE_CS_CALLCONV_FIELD);
3833
3834     // Get native field type
3835     pvNativeType = NULL;
3836     hr = pMT->GetMDImport()->GetFieldMarshal(md, &pvNativeType, &cbNativeType);
3837     if (hr != CLDB_E_RECORD_NOTFOUND)
3838     {
3839         IfFailReport(hr);
3840     }
3841     
3842     // Convert the type to elemdesc.
3843     hr = CorSigToTypeDesc(pCTI, pMT, &pbSig[ixSig], pvNativeType, cbNativeType, &cbElem, &pvar->elemdescVar.tdesc, &sPool, FALSE);
3844     if (FAILED(hr))
3845         return FALSE;
3846
3847     ixSig += cbElem;
3848
3849     pvar->wVarFlags = 0;
3850     pvar->varkind = VAR_PERINSTANCE;
3851     pvar->memid = dispid;
3852
3853     // Constant value.
3854     if (vtVariant->vt != VT_EMPTY)
3855         pvar->lpvarValue = vtVariant;
3856     else
3857     {
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)))
3860         {
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;
3869         }
3870         // If still no default value, check for date time custom attribute.
3871         if (vtVariant->vt == VT_EMPTY)
3872         {
3873             IfFailReport(pMT->GetMDImport()->GetCustomAttributeByName(md, INTEROP_DATETIMEVALUE_TYPE,  &pvData,&cbData));
3874             if (hr == S_OK && cbData >= (2 + sizeof(__int64)))
3875             {
3876                 const BYTE *pbData = (const BYTE *)pvData;
3877                 vtVariant->vt = VT_DATE;
3878                 vtVariant->date = _TicksToDoubleDate(GET_UNALIGNED_64(pbData+2));
3879             }
3880         }
3881         // If still no default value, check for IDispatch custom attribute.
3882         if (vtVariant->vt == VT_EMPTY)
3883         {
3884             IfFailReport(pMT->GetMDImport()->GetCustomAttributeByName(md, INTEROP_IDISPATCHVALUE_TYPE,  &pvData,&cbData));
3885             if (hr == S_OK)
3886             {
3887                 vtVariant->vt = VT_DISPATCH;
3888                 vtVariant->pdispVal = 0;
3889             }
3890         }
3891         // If still no default value, check for IUnknown custom attribute.
3892         if (vtVariant->vt == VT_EMPTY)
3893         {
3894             IfFailReport(pMT->GetMDImport()->GetCustomAttributeByName(md, INTEROP_IUNKNOWNVALUE_TYPE,  &pvData,&cbData));
3895             if (hr == S_OK)
3896             {
3897                 vtVariant->vt = VT_UNKNOWN;
3898                 vtVariant->punkVal = 0;
3899             }
3900         }
3901     }
3902
3903     IfFailReport(pCTI->AddVarDesc(iMD, pvar));
3904     
3905     // Set the name for the member; decorate if necessary.
3906     pSuffix = 0;
3907     for (;;)
3908     {
3909         // Attempt to set the name.
3910         hr = pCTI->SetVarName(iMD, (LPOLESTR)sName.GetUnicode());
3911         
3912         // If a name conflict, decorate, otherwise, done.
3913         if (hr != TYPE_E_AMBIGUOUSNAME)
3914             break;
3915
3916         if (iSuffix == 0)
3917         {
3918             iSuffix = 2;
3919         }
3920         else
3921         {
3922             sName.Delete(sName.End()-=2, 2);
3923         }
3924
3925         SString sDup;
3926         sDup.Printf(szDuplicateDecoration, iSuffix++);
3927         
3928         sName.Append(sDup);
3929     }
3930     IfFailReport(hr);
3931
3932     // Check for a description.
3933     if(GetDescriptionString(pMT, md, (BSTR &)bstrDescr))
3934         IfFailReport(pCTI->SetVarDocString(iMD, bstrDescr));
3935     
3936     // Error reporting info.
3937     m_ErrorContext.m_szMember = 0;
3938
3939     return TRUE;
3940 } // HRESULT TypeLibExporter::ConvertVariable()
3941
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
3951 {
3952     CONTRACTL
3953     {
3954         STANDARD_VM_CHECK;
3955         PRECONDITION(CheckPointer(pCTI));
3956         PRECONDITION(CheckPointer(pMT));
3957     }
3958     CONTRACTL_END;
3959
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.
3969
3970     vtVariant.vt = VT_EMPTY;
3971
3972     // Error reporting info.
3973     IfFailReport(pMT->GetMDImport()->GetNameOfFieldDef(md, &m_ErrorContext.m_szMember));
3974     
3975     // Get info about the field.
3976     IfFailReport(pMT->GetMDImport()->GetDispIdOfMemberDef(md, &dispid));
3977     IfFailReport(pMT->GetMDImport()->GetFieldDefProps(md, &dwFlags));
3978     
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));
3981
3982     // Prepare to parse signature and build the VARDESC.
3983     pvar = reinterpret_cast<VARDESC*>(sPool.AllocZero(sizeof(VARDESC)));
3984     if (NULL == pvar)
3985         IfFailReport(E_OUTOFMEMORY);
3986
3987     IfFailReport( _FillVariant(&defaultValue, &vtVariant) ); 
3988
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;
3991
3992     pvar->wVarFlags = 0;
3993     pvar->varkind = VAR_CONST;
3994     pvar->memid = dispid;
3995
3996     // Constant value.
3997     if (vtVariant.vt != VT_EMPTY)
3998     {
3999         pvar->lpvarValue = &vtVariant;
4000         
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)
4004         {  
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;
4008             else
4009                 hr = E_FAIL;
4010         }
4011         else if (vtVariant.vt == VT_UI8)
4012         {
4013             // If withing range of 32-bit unsigned number, OK.
4014             if (vtVariant.ullVal <= ULONG_MAX)
4015                 vtVariant.vt = VT_UI4, hr = S_OK;
4016             else
4017                 hr = E_FAIL;
4018         }
4019         else
4020         {
4021             hr = SafeVariantChangeTypeEx(&vtVariant, &vtVariant, 0, 0, VT_I4);
4022         }
4023         
4024         if (FAILED(hr))
4025         {
4026             if (FAILED(pMT->GetMDImport()->GetNameOfTypeDef(pMT->GetCl(), &pName, &pNS)))
4027             {
4028                 pName = pNS = "Invalid TypeDef record";
4029             }
4030             ReportWarning(TLBX_W_ENUM_VALUE_TOOBIG, TLBX_W_ENUM_VALUE_TOOBIG, pName, sName.GetUnicode());
4031             return FALSE;
4032         }
4033     }
4034     else
4035     {   // No value assigned, use 0.
4036         pvar->lpvarValue = &vtVariant;
4037         vtVariant.vt = VT_I4;
4038         vtVariant.lVal = 0;
4039     }
4040
4041     IfFailReport(pCTI->AddVarDesc(iMD, pvar));
4042     IfFailReport(pCTI->SetVarName(iMD, (LPOLESTR)sName.GetUnicode()));
4043
4044     // Check for a description.
4045     if(GetDescriptionString(pMT, md, (BSTR &)bstrDescr))
4046         IfFailReport(pCTI->SetVarDocString(iMD, bstrDescr));
4047     
4048     // Error reporting info.
4049     m_ErrorContext.m_szMember = 0;
4050
4051     return TRUE;
4052 } // void TypeLibExporter::ConvertEnumMember()
4053
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)
4061 {
4062     CONTRACTL
4063     {
4064         STANDARD_VM_CHECK;
4065         PRECONDITION(CheckPointer(pInternalImport));
4066     }
4067     CONTRACTL_END;
4068
4069     ULONG       elem=0;                 // An element from a COM+ signature.
4070     ULONG       cbElem=0;
4071
4072     cbElem = CorSigUncompressData(pbSig, &elem);
4073     if (elem == ELEMENT_TYPE_PTR || elem == ELEMENT_TYPE_BYREF)
4074     {
4075         return IsVbRefType(&pbSig[cbElem], pInternalImport);
4076     }
4077     else
4078     {
4079         switch (elem)
4080         {
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:
4087                 return FALSE;
4088
4089             case ELEMENT_TYPE_CLASS:
4090                 return TRUE;
4091                 
4092             case ELEMENT_TYPE_OBJECT:
4093                 return FALSE;
4094
4095             default:
4096                 break;
4097         }
4098     }
4099
4100     return FALSE;
4101 } // BOOL TypeLibExporter::IsVbRefType()
4102
4103 BOOL TypeLibExporter::IsExportingAs64Bit()
4104 {  
4105     LIMITED_METHOD_CONTRACT;
4106     if (TlbExportAs64Bit(m_flags))
4107     {
4108          return TRUE;
4109     }
4110     else if (TlbExportAs32Bit(m_flags))
4111     {
4112         return FALSE;
4113     }
4114     else
4115     {
4116 #ifdef _WIN64
4117         return TRUE;
4118 #else
4119         return FALSE;
4120 #endif
4121     }
4122 } // BOOL TypeLibExporter::IsExportingAs64Bit()
4123
4124 void TypeLibExporter::ArrayToTypeDesc(ICreateTypeInfo2 *pCTI, CDescPool *ppool, ArrayMarshalInfo *pArrayMarshalInfo, TYPEDESC *ptdesc)
4125 {
4126     CONTRACTL
4127     {
4128         STANDARD_VM_CHECK;
4129         PRECONDITION(CheckPointer(pCTI));
4130         PRECONDITION(CheckPointer(ppool));
4131         PRECONDITION(CheckPointer(pArrayMarshalInfo));
4132         PRECONDITION(CheckPointer(ptdesc));
4133     }
4134     CONTRACTL_END;
4135
4136     HRESULT hr = E_FAIL;
4137     VARTYPE vtElement = pArrayMarshalInfo->GetElementVT();
4138     TypeHandle thElement = pArrayMarshalInfo->GetElementTypeHandle();
4139
4140     if (vtElement == VT_RECORD)
4141     {
4142         // We are dealing with an array of embedded structures.
4143         ptdesc->vt = VT_USERDEFINED;                                
4144         EEClassToHref(pCTI, thElement.GetMethodTable(), FALSE, &ptdesc->hreftype);
4145     }
4146     else if ((vtElement == VT_UNKNOWN || vtElement == VT_DISPATCH) && !thElement.IsObjectType())
4147     {
4148         if (!thElement.IsValueType() && !pArrayMarshalInfo->IsSafeArraySubTypeExplicitlySpecified())
4149         {
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);
4155                     
4156             ptdesc->lptdesc->vt = VT_USERDEFINED;
4157             EEClassToHref(pCTI, thElement.GetMethodTable(), FALSE, &ptdesc->lptdesc->hreftype);        
4158         }
4159         else
4160         {
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;
4164         }
4165     }
4166     else if (pArrayMarshalInfo->IsPtr())
4167     {
4168         ptdesc->vt = VT_PTR;
4169         ptdesc->lptdesc = reinterpret_cast<TYPEDESC*>(ppool->AllocZero(sizeof(TYPEDESC)));
4170         if (ptdesc->lptdesc == NULL)
4171             IfFailReport(E_OUTOFMEMORY);
4172
4173         ptdesc->lptdesc->vt = vtElement;
4174     }
4175     else
4176     {
4177         // We are dealing with an array of primitive types.
4178         ptdesc->vt = vtElement;
4179     }
4180 }
4181 // HRESULT ArrayToTypeDesc(ArrayMarshalInfo *pArrayMarshalInfo, TYPEDESC *pElementTypeDesc)
4182
4183 VARTYPE TypeLibExporter::GetVtForIntPtr()
4184 {
4185     WRAPPER_NO_CONTRACT;
4186
4187     return static_cast<VARTYPE>(IsExportingAs64Bit() ? VT_I8 : VT_I4);
4188 } // VARTYPE TypeLibExporter::GetVtForIntPtr()
4189
4190 VARTYPE TypeLibExporter::GetVtForUIntPtr()
4191 {
4192     WRAPPER_NO_CONTRACT;
4193
4194     return static_cast<VARTYPE>(IsExportingAs64Bit() ? VT_UI8 : VT_UI4);
4195 } // VARTYPE TypeLibExporter::GetVtForUIntPtr()
4196
4197 /*
4198 BOOL TypeLibExporter::ValidateSafeArrayElemVT(VARTYPE vt)
4199 {
4200     switch(vt)
4201     {
4202         case VT_I2:
4203         case VT_I4:
4204         case VT_R4:
4205         case VT_R8:
4206         case VT_CY:
4207         case VT_DATE:
4208         case VT_BSTR:
4209         case VT_DISPATCH:
4210         case VT_ERROR:
4211         case VT_BOOL:
4212         case VT_VARIANT:
4213         case VT_UNKNOWN:
4214         case VT_DECIMAL:
4215         case VT_RECORD:
4216         case VT_I1:
4217         case VT_UI1:
4218         case VT_UI2:
4219         case VT_UI4:
4220         case VT_INT:
4221         case VT_UINT:
4222             return TRUE;
4223
4224         default:
4225             return FALSE;
4226     }
4227 }
4228 */
4229
4230 //*****************************************************************************
4231 // Read a COM+ signature element and create a TYPEDESC that corresponds 
4232 //  to it.
4233 //*****************************************************************************
4234 #ifdef _PREFAST_
4235 #pragma warning(push)
4236 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
4237 #endif
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.
4249 {
4250     CONTRACTL
4251     {
4252         STANDARD_VM_CHECK;
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));
4259     }
4260     CONTRACTL_END;
4261
4262     HRESULT     hr=S_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;
4280     LPCUTF8     pNS;
4281
4282
4283     pInternalImport = pMT->GetMDImport();
4284     pModule = pMT->GetModule();
4285
4286     // Just be sure the count is zero if the pointer is.
4287     if (pbNativeSig == NULL)
4288         cbNativeSig = 0;
4289
4290     // Grab the native marshaling type.
4291     if (cbNativeSig > 0)
4292     {
4293         cbNativeElem = CorSigUncompressData(pbNativeSig, &nativeElem);
4294         pbNativeSig += cbNativeElem;
4295         cbNativeSig -= cbNativeElem;
4296
4297         // AsAny makes no sense for COM Interop.  Ignore it.
4298         if (nativeElem == NATIVE_TYPE_ASANY)
4299         {
4300             ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_ASANY);
4301             nativeElem = 0;
4302         }
4303     }
4304
4305     // If we are dealing with a struct, determine if it is marked as CharSet=Ansi.
4306     if (!bMethodSig)
4307     {
4308         // Make sure one of Auto, Ansi or Unicode is specified.
4309         if (!IsTdAnsiClass(dwTypeFlags) && !IsTdAutoClass(dwTypeFlags) && !IsTdUnicodeClass(dwTypeFlags))
4310         {
4311             _ASSERTE(!"Bad stringformat value in wrapper class.");
4312             ReportWarning(TLBX_E_BAD_SIGNATURE, E_FAIL);  // bad metadata
4313             hr = TLBX_E_BAD_SIGNATURE;
4314             goto ExitFunc;
4315         }
4316         
4317         if (FAILED(pInternalImport->GetTypeDefProps(pMT->GetCl(), &dwTypeFlags, NULL)))
4318         {
4319             ReportWarning(TLBX_E_BAD_SIGNATURE, E_FAIL);
4320             hr = TLBX_E_BAD_SIGNATURE;
4321             goto ExitFunc;
4322         }
4323         fAnsi = IsTdAnsiClass(dwTypeFlags);
4324     }
4325     
4326     // Get the element type.
4327 TryAgain:
4328     cbElem += CorSigUncompressData(pbSig+cbElem, &elem);
4329
4330     // Handle the custom marshaler native type separately.
4331     if (elem != ELEMENT_TYPE_BYREF && nativeElem == NATIVE_TYPE_CUSTOMMARSHALER)
4332     {
4333         switch(elem)
4334         {
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;
4340                 break;
4341
4342             case ELEMENT_TYPE_STRING:
4343             case ELEMENT_TYPE_SZARRAY:
4344             case ELEMENT_TYPE_ARRAY:
4345                 ptdesc->vt = GetVtForIntPtr();
4346                 break;
4347
4348             default:
4349                 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
4350                 return(TLBX_E_BAD_SIGNATURE);
4351             break;
4352         }
4353
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.
4359         goto ExitFunc;
4360     }
4361
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.
4364 TryWithElemType:
4365     switch (elem)
4366     {
4367     case ELEMENT_TYPE_END:            // 0x0,
4368             ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_UNKNOWN_SIGNATURE);
4369             return(TLBX_E_BAD_SIGNATURE);
4370         break;
4371             
4372     case ELEMENT_TYPE_VOID:           // 0x1,
4373         ptdesc->vt = VT_VOID;  
4374         break;
4375
4376     case ELEMENT_TYPE_BOOLEAN:        // 0x2,
4377         switch (nativeElem)
4378         {
4379         case 0:
4380             ptdesc->vt = static_cast<VARTYPE>(bMethodSig ? VT_BOOL : VT_I4);
4381             break;
4382
4383         case NATIVE_TYPE_VARIANTBOOL:
4384             ptdesc->vt = VT_BOOL;
4385             break;
4386
4387         case NATIVE_TYPE_BOOLEAN:
4388             ptdesc->vt = VT_I4;
4389             break;
4390
4391         case NATIVE_TYPE_U1:
4392         case NATIVE_TYPE_I1:
4393             ptdesc->vt = VT_UI1;
4394             break;
4395                     
4396         default:
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);
4400         }   
4401         break;
4402             
4403     case ELEMENT_TYPE_CHAR:           // 0x3,
4404         if (nativeElem == 0)
4405         {
4406             if (!bMethodSig && IsTdAutoClass(dwTypeFlags))
4407             {
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);
4412                 _ASSERTE(szName);
4413
4414                 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_AUTO_CS_NOT_ALLOWED, szName);
4415                 hr = TLBX_E_BAD_SIGNATURE;
4416                 goto ExitFunc;
4417             }
4418
4419             ptdesc->vt = static_cast<VARTYPE>(fAnsi ? VT_UI1 : VT_UI2);
4420         }
4421         else
4422         {
4423             switch (nativeElem)
4424             {
4425             case 0:
4426             case NATIVE_TYPE_U2:
4427             case NATIVE_TYPE_I2:
4428                 ptdesc->vt = VT_UI2;
4429                 break;
4430                                 
4431             case NATIVE_TYPE_U1:
4432             case NATIVE_TYPE_I1:
4433                 ptdesc->vt = VT_UI1;
4434                 break;
4435                                 
4436             default:
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;
4440                 goto ExitFunc;
4441             }
4442         }
4443         break;
4444
4445     case ELEMENT_TYPE_I1:             // 0x4,
4446         ptdesc->vt = VT_I1;
4447         break;
4448                 
4449     case ELEMENT_TYPE_U1:             // 0x5,
4450         ptdesc->vt = VT_UI1;
4451         break;
4452                 
4453     case ELEMENT_TYPE_I2:             // 0x6,
4454         ptdesc->vt = VT_I2;
4455         break;
4456                 
4457     case ELEMENT_TYPE_U2:             // 0x7,
4458         ptdesc->vt = VT_UI2;
4459         break;
4460                 
4461     case ELEMENT_TYPE_I4:             // 0x8,
4462         switch (nativeElem)
4463         {
4464         case 0:
4465         case NATIVE_TYPE_I4:
4466         case NATIVE_TYPE_U4: case NATIVE_TYPE_INTF: //@todo: Fix Microsoft.Win32.Interop.dll and remove this line.
4467             ptdesc->vt = VT_I4;
4468             break;
4469                     
4470         case NATIVE_TYPE_ERROR:
4471             ptdesc->vt = VT_HRESULT;
4472             break;
4473                             
4474         default:
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;
4478             goto ExitFunc;
4479         }
4480         break;
4481             
4482     case ELEMENT_TYPE_U4:             // 0x9,
4483         switch (nativeElem)
4484         {
4485         case 0:
4486         case NATIVE_TYPE_U4:
4487             ptdesc->vt = VT_UI4;
4488             break;
4489                             
4490         case NATIVE_TYPE_ERROR:
4491             ptdesc->vt = VT_HRESULT;
4492             break;
4493                             
4494         default:
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;
4498             goto ExitFunc;
4499         }
4500         break;
4501             
4502     case ELEMENT_TYPE_I8:             // 0xa,
4503         ptdesc->vt = VT_I8;
4504         break;
4505                 
4506     case ELEMENT_TYPE_U8:             // 0xb,
4507         ptdesc->vt = VT_UI8;
4508         break;
4509                 
4510     case ELEMENT_TYPE_R4:             // 0xc,
4511         ptdesc->vt = VT_R4;
4512         break;
4513                 
4514     case ELEMENT_TYPE_R8:             // 0xd,
4515         ptdesc->vt = VT_R8;
4516         break;
4517                 
4518     case ELEMENT_TYPE_OBJECT:
4519         goto IsObject;
4520             
4521     case ELEMENT_TYPE_STRING:         // 0xe,
4522     IsString:
4523         if (nativeElem == 0)
4524         {            
4525             if (bMethodSig)
4526             {
4527                 ptdesc->vt = VT_BSTR;
4528             }
4529             else
4530             {
4531                 if (IsTdAutoClass(dwTypeFlags))
4532                 {
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);
4537                     _ASSERTE(szName);
4538
4539                     ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_AUTO_CS_NOT_ALLOWED, szName);
4540                     hr = TLBX_E_BAD_SIGNATURE;
4541                     goto ExitFunc;
4542                 }
4543
4544                 ptdesc->vt = static_cast<VARTYPE>(fAnsi ? VT_LPSTR : VT_LPWSTR);
4545             }
4546         }
4547         else
4548         {
4549             switch (nativeElem)
4550             {
4551             case NATIVE_TYPE_BSTR:
4552                 if (fIsStringBuilder)
4553                 {
4554                     ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
4555                     hr = TLBX_E_BAD_SIGNATURE;
4556                     goto ExitFunc;
4557                 }
4558                 ptdesc->vt = VT_BSTR;
4559                 break;
4560                         
4561             case NATIVE_TYPE_LPSTR:
4562                 ptdesc->vt = VT_LPSTR;
4563                 break;
4564                                 
4565             case NATIVE_TYPE_LPWSTR:
4566                 ptdesc->vt = VT_LPWSTR;
4567                 break;
4568                                 
4569             case NATIVE_TYPE_LPTSTR:
4570                 {
4571                     // NATIVE_TYPE_LPTSTR is not allowed to be exported to COM.
4572                     DefineFullyQualifiedNameForClassW();
4573                     LPCWSTR szName = GetFullyQualifiedNameForClassW(pMT);
4574                     _ASSERTE(szName);
4575                     ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_LPTSTR_NOT_ALLOWED, szName);
4576                     hr = TLBX_E_BAD_SIGNATURE;
4577                     goto ExitFunc;
4578                 }
4579             case NATIVE_TYPE_FIXEDSYSSTRING:
4580                 // NATIVE_TYPE_FIXEDSYSSTRING is only allowed on fields.
4581                 if (bMethodSig)
4582                 {
4583                     ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
4584                     hr = TLBX_E_BAD_SIGNATURE;
4585                     goto ExitFunc;
4586                 }
4587
4588                 // Retrieve the count of characters.
4589                 if (cbNativeSig != 0)
4590                 {
4591                     cb = CorSigUncompressData(pbNativeSig, &nativeCount);
4592                     pbNativeSig += cb;
4593                     cbNativeSig -= cb;
4594                 }
4595                 else
4596                 {
4597                     nativeCount = 0;
4598                 }
4599
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);
4605
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;
4610
4611                 if (IsTdAutoClass(dwTypeFlags))
4612                 {
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);
4617                     _ASSERTE(szName);
4618
4619                     ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_AUTO_CS_NOT_ALLOWED, szName);
4620                     hr = TLBX_E_BAD_SIGNATURE;
4621                     goto ExitFunc;
4622                 }
4623
4624                 ptdesc->lpadesc->tdescElem.vt = static_cast<VARTYPE>(fAnsi ? VT_UI1 : VT_UI2);
4625                 break;
4626
4627             default:
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;
4631                 goto ExitFunc;
4632             }   
4633         }
4634         break;
4635
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;
4641         if (pbByRef)
4642             *pbByRef = TRUE;
4643                 
4644         // Pointer to what?
4645         ptdesc->lptdesc = reinterpret_cast<TYPEDESC*>(ppool->AllocZero(sizeof(TYPEDESC)));
4646         if (ptdesc->lptdesc == NULL)
4647             IfFailReport(E_OUTOFMEMORY);
4648             
4649         hr = CorSigToTypeDesc(pCTI, pMT, &pbSig[cbElem], pbNativeSig-cbNativeElem, 
4650                     cbNativeSig+cbNativeElem, &cb, ptdesc->lptdesc, ppool, bMethodSig);
4651         cbElem += cb;
4652             
4653         if (FAILED(hr))
4654             goto ExitFunc;
4655         
4656         break;
4657
4658     case ELEMENT_TYPE_CLASS:          // 0x12,
4659     case ELEMENT_TYPE_VALUETYPE:
4660         // Get the TD/TR.
4661         cb = CorSigUncompressToken(&pbSig[cbElem], &tkTypeRef);
4662         cbElem += cb;
4663         
4664         if (TypeFromToken(tkTypeRef) == mdtTypeDef)
4665         {
4666             // Get the name of the TypeDef.
4667             if (FAILED(pInternalImport->GetNameOfTypeDef(tkTypeRef, &pclsname, &pNS)))
4668             {
4669                 IfFailReport(COR_E_BADIMAGEFORMAT);
4670             }
4671         }
4672         else
4673         {
4674             // Get the name of the TypeRef.
4675             _ASSERTE(TypeFromToken(tkTypeRef) == mdtTypeRef);
4676             IfFailReport(pInternalImport->GetNameOfTypeRef(tkTypeRef, &pNS, &pclsname));
4677         }
4678
4679         if (pNS)
4680         {
4681             sName.MakeFullNamespacePath(SString(SString::Utf8, pNS), SString(SString::Utf8, pclsname));
4682             StackScratchBuffer scratch;
4683             pclsname = sName.GetUTF8(scratch);
4684         }
4685
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.
4688
4689         // Is it System.something? 
4690         if (SString::_strnicmp(pclsname, szRuntime, cbRuntime) == 0)
4691         {   
4692             // Which one?
4693             LPCUTF8 pcls; pcls = pclsname + cbRuntime;
4694             if (stricmpUTF8(pcls, szStringClass) == 0)
4695             {
4696                 goto IsString;
4697             }
4698             else if (stricmpUTF8(pcls, szDateTimeClass) == 0)
4699             {
4700                 ptdesc->vt = VT_DATE;
4701                 goto ExitFunc;
4702             }
4703             else if (stricmpUTF8(pcls, szDecimalClass) == 0)
4704             {
4705                 switch (nativeElem)
4706                 {
4707                     case NATIVE_TYPE_CURRENCY:
4708                         // Make this a currency.
4709                         ptdesc->vt = VT_CY;
4710                         break;
4711                                 
4712                     case 0:
4713                         // Make this a decimal
4714                         ptdesc->vt = VT_DECIMAL;
4715                         break;
4716                                 
4717                     default:
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;
4721                         goto ExitFunc;
4722                 }
4723                 goto ExitFunc;
4724             }
4725             else if (stricmpUTF8(pcls, szGuidClass) == 0)
4726             {
4727                 switch (nativeElem)
4728                 {
4729                     case NATIVE_TYPE_LPSTRUCT:
4730                         // Make this a pointer to . . .
4731                         ptdesc->vt = VT_PTR;
4732                         if (pbByRef)
4733                             *pbByRef = TRUE;
4734                                 
4735                         ptdesc->lptdesc = reinterpret_cast<TYPEDESC*>(ppool->AllocZero(sizeof(TYPEDESC)));
4736                         if (ptdesc->lptdesc == NULL)
4737                             IfFailReport(E_OUTOFMEMORY);
4738                                 
4739                         // . . . a user defined type for GUID
4740                         ptdesc->lptdesc->vt = VT_USERDEFINED;
4741                         GetRefTypeInfo(pCTI, m_pGuid, &ptdesc->lptdesc->hreftype);
4742                         break;
4743                                 
4744                     case 0:
4745                     case NATIVE_TYPE_STRUCT:
4746                         // a user defined type for GUID
4747                         ptdesc->vt = VT_USERDEFINED;
4748                         GetRefTypeInfo(pCTI, m_pGuid, &ptdesc->hreftype);
4749                         break;
4750                                 
4751                     default:
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;
4755                         goto ExitFunc;
4756                 }
4757                 goto ExitFunc;
4758             }
4759             else if (stricmpUTF8(pcls, szArrayClass) == 0)
4760             {
4761                 // If no native type is specified then assume its a NATIVE_TYPE_INTF.
4762                 if (nativeElem == 0)
4763                     nativeElem = NATIVE_TYPE_INTF;
4764
4765                 if (nativeElem == NATIVE_TYPE_SAFEARRAY)
4766                 {
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);
4770                     
4771                     if (cbNativeSig > 0)
4772                     {
4773                         // Retrieve the safe array sub type.
4774                         cb = CorSigUncompressData(pbNativeSig, &vtElement);
4775                         pbNativeSig += cb;
4776                         cbNativeSig -= cb;    
4777
4778                         // Get the type name if specified.
4779                         if (cbNativeSig > 0)
4780                         {
4781                             ULONG cbClass = 0;
4782                             
4783                             cb = CorSigUncompressData(pbNativeSig, &cbClass);
4784                             pbNativeSig += cb;
4785                             cbNativeSig -= cb;
4786
4787                             if (cbClass > 0)
4788                             {
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));
4794                             }
4795                         }                        
4796                     }
4797                     else
4798                     {
4799                         if (!bMethodSig)
4800                         {
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);
4805                         }
4806                     }
4807
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);
4811
4812                     if (!arrayMarshalInfo.IsValid())
4813                     {
4814                         ReportWarning(TLBX_E_BAD_SIGNATURE, arrayMarshalInfo.GetErrorResourceId());
4815                         hr = TLBX_E_BAD_SIGNATURE;
4816                         goto ExitFunc;
4817                     }
4818     
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);
4824
4825                     ArrayToTypeDesc(pCTI, ppool, &arrayMarshalInfo, ptdesc->lptdesc);
4826                     
4827                     goto ExitFunc;
4828                 }
4829                 else if (nativeElem == NATIVE_TYPE_FIXEDARRAY)
4830                 {               
4831                     // NATIVE_TYPE_FIXEDARRAY is only allowed on fields.
4832                     if (bMethodSig)
4833                     {
4834                         ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
4835                         hr = TLBX_E_BAD_SIGNATURE;
4836                         goto ExitFunc;
4837                     }
4838                     
4839                     // Retrieve the size of the fixed array. This is required.
4840                     if (cbNativeSig == 0)
4841                     {
4842                         ReportWarning(TLBX_E_BAD_SIGNATURE, IDS_EE_BADMARSHALFIELD_FIXEDARRAY_NOSIZE);
4843                         hr = TLBX_E_BAD_SIGNATURE;
4844                         goto ExitFunc;
4845                     }
4846
4847                     cb = CorSigUncompressData(pbNativeSig, &nativeCount);
4848                     pbNativeSig += cb;
4849                     cbNativeSig -= cb;
4850
4851                     // A size const of 0 isn't supported.
4852                     if (nativeCount == 0)
4853                     {
4854                         ReportWarning(TLBX_E_BAD_SIGNATURE, IDS_EE_BADMARSHALFIELD_FIXEDARRAY_ZEROSIZE);
4855                         hr = TLBX_E_BAD_SIGNATURE;
4856                         goto ExitFunc;
4857                     }
4858
4859                     // Since these always export to arrays of BSTRs, we don't need to fetch the native type.
4860
4861                     // Set the data
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);
4867
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;
4873
4874                     goto ExitFunc;
4875                 }
4876                 else if (nativeElem != NATIVE_TYPE_INTF)
4877                 {
4878                     ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
4879                     hr = TLBX_E_BAD_SIGNATURE;
4880                     goto ExitFunc;
4881                 }
4882
4883                 // If the native type is NATIVE_TYPE_INTF then we fall through and convert 
4884                 // System.Array to its IClassX interface.
4885             }
4886             else if (stricmpUTF8(pcls, szObjectClass) == 0)
4887             {
4888     IsObject:
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;
4894
4895                 switch (nativeElem)
4896                 {
4897                     case NATIVE_TYPE_INTF:
4898                     case NATIVE_TYPE_IUNKNOWN:
4899                         // an IUnknown based interface.
4900                         ptdesc->vt = VT_UNKNOWN;
4901                         break;
4902                                         
4903                     case NATIVE_TYPE_IDISPATCH:
4904                         // an IDispatch based interface.
4905                         ptdesc->vt = VT_DISPATCH;
4906                         break;
4907                                 
4908                     case 0:
4909                     case NATIVE_TYPE_STRUCT:
4910                         // a VARIANT
4911                         ptdesc->vt = VT_VARIANT;
4912                         break;
4913                                 
4914                     default:
4915                         ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
4916                         hr = TLBX_E_BAD_SIGNATURE;
4917                         goto ExitFunc;
4918                 }
4919                 goto ExitFunc;
4920             }
4921         } // System
4922             
4923         if (SString::_strnicmp(pclsname, szText, cbText) == 0)
4924         {
4925             LPCUTF8 pcls; pcls = pclsname + cbText;
4926             if (stricmpUTF8(pcls, szStringBufferClass) == 0)
4927             {
4928                 fIsStringBuilder = TRUE;
4929                         
4930                 // If there is no fieldmarshal information, marshal as a LPWSTR
4931                 if (nativeElem == 0)
4932                     nativeElem = NATIVE_TYPE_LPWSTR;
4933                         
4934                 // Marshaller treats stringbuilders as [in, out] by default.
4935                 if (pbByRef)
4936                     *pbByRef = TRUE;
4937                         
4938                 goto IsString;
4939             }
4940         } // System.Text
4941             
4942         if (SString::_strnicmp(pclsname, szCollections, cbCollections) == 0)
4943         {
4944             LPCUTF8 pcls; pcls = pclsname + cbCollections;
4945             if (stricmpUTF8(pcls, szIEnumeratorClass) == 0)
4946             {
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);
4952                         
4953                 ptdesc->lptdesc->vt = VT_USERDEFINED;
4954                 ptdesc->lptdesc->hreftype = hRef;
4955                 goto ExitFunc;
4956             }
4957         } // System.Collections
4958             
4959         if (SString::_strnicmp(pclsname, szDrawing, cbDrawing) == 0)
4960         {
4961             LPCUTF8 pcls; pcls = pclsname + cbDrawing;
4962             if (stricmpUTF8(pcls, szColor) == 0)
4963             {
4964                 StdOleTypeToHRef(pCTI, GUID_OleColor, &hRef);
4965                 ptdesc->vt = VT_USERDEFINED;
4966                 ptdesc->hreftype = hRef;
4967                 goto ExitFunc;
4968             }
4969         } // System.Drawing
4970
4971         // It is not a built-in VT type, so build the typedesc.
4972
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);
4977
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)
4982         {           
4983             // Check if it is a delegate (which can be marshaled as a function pointer).
4984             if (COMDelegate::IsDelegate(pRefdClass))
4985             {
4986                 if (nativeElem == NATIVE_TYPE_FUNC)
4987                 {
4988                     ptdesc->vt = GetVtForIntPtr();
4989                     goto ExitFunc;
4990                 }
4991                 else if (nativeElem != 0 && nativeElem != NATIVE_TYPE_INTF)
4992                 {
4993                     ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
4994                     hr = TLBX_E_BAD_SIGNATURE;
4995                     goto ExitFunc;
4996                 }
4997             }
4998             else if (TypeHandle(pRefdClass).CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__SAFE_HANDLE))))
4999             {
5000                 ptdesc->vt = GetVtForIntPtr();
5001                 goto ExitFunc;
5002             }
5003             else if (TypeHandle(pRefdClass).CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__CRITICAL_HANDLE))))
5004             {
5005                 ptdesc->vt = GetVtForIntPtr();
5006                 goto ExitFunc;
5007             }
5008
5009             if (pRefdClass->HasLayout())
5010             {
5011                 if (nativeElem == NATIVE_TYPE_INTF)
5012                 {
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;
5019                     goto ExitFunc;                
5020                 }
5021                 else if (!bMethodSig)
5022                 {
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))
5026                     {
5027                         ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
5028                         hr = TLBX_E_BAD_SIGNATURE;
5029                         goto ExitFunc;                                                            
5030                     }
5031
5032                     // These types are embedded structures so we can treat them as value classes.
5033                     goto IsStructWithLayout;
5034                 }
5035                 else
5036                 {
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))
5040                     {
5041                         ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
5042                         hr = TLBX_E_BAD_SIGNATURE;
5043                         goto ExitFunc;                                                            
5044                     }                    
5045                 }
5046             }
5047
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
5050             //  IUnknown.
5051             // If the type is not visible from COM then we return S_USEIUNKNOWN.
5052             if (!IsTypeVisibleFromCom(TypeHandle(pRefdClass)))
5053                 hr = S_USEIUNKNOWN;
5054             else
5055                 hr = EEClassToHref(pCTI, pRefdClass, TRUE, &hRef);
5056                 
5057             if (hr == S_USEIUNKNOWN)
5058             {   
5059                 // Not a known type, so use IUnknown
5060                 ptdesc->vt = VT_UNKNOWN;
5061                 goto ExitFunc;
5062             }
5063        
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);
5069                 
5070             // . . . a user defined type . . .
5071             ptdesc->lptdesc->vt = VT_USERDEFINED;
5072             // . . . based on the token.
5073             ptdesc->lptdesc->hreftype = hRef;
5074         }
5075         else  // It's a value type.
5076         {   
5077 IsStructWithLayout:    
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())
5082             {
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
5086                 // underlying type.
5087                 if ((et != ELEMENT_TYPE_I4 && et != ELEMENT_TYPE_U4) ||
5088                     (nativeElem != 0))
5089                 {
5090                     elem = et;
5091                     goto TryWithElemType;
5092                 }
5093                 // Fall through to convert as the enum type.
5094             }
5095             else
5096             {
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))
5100                 {
5101                     ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
5102                     hr = TLBX_E_BAD_SIGNATURE;
5103                     goto ExitFunc;                                                            
5104                 }
5105             }
5106                     
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)
5112             {
5113                 SString sClsName;
5114                 sClsName.SetUTF8(pclsname);
5115
5116                 LPCWSTR szVCName = sClsName.GetUnicode();
5117                 if (NAMESPACE_SEPARATOR_WCHAR == *szVCName)
5118                     szVCName++;
5119
5120                 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_NONVISIBLEVALUECLASS, szVCName);
5121                 hr = TLBX_E_BAD_SIGNATURE;
5122                 goto ExitFunc;
5123             }
5124
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;
5131         }
5132         break;
5133
5134     case ELEMENT_TYPE_SZARRAY:          
5135     case ELEMENT_TYPE_ARRAY:
5136     {
5137         SigPointer sig(&pbSig[cbElem]);
5138
5139         // Retrieve the type handle for the array elements.
5140         TypeHandle thElement = sig.GetTypeHandleThrowing(pModule, &emptyTypeContext);            
5141         _ASSERTE(!thElement.IsNull());        
5142
5143         // Update the index into the managed signature array.
5144         IfFailThrow(sig.SkipExactlyOne());
5145         cbElem += static_cast<ULONG>(sig.GetPtr() - &pbSig[cbElem]);
5146
5147         switch (nativeElem)
5148         {
5149         case 0:
5150         case NATIVE_TYPE_SAFEARRAY:
5151         {
5152             ULONG vtElement = VT_EMPTY;
5153
5154             // Retrieve the safe array element type.
5155             if (cbNativeSig != 0)
5156             {
5157                 cb = CorSigUncompressData(pbNativeSig, &vtElement);
5158                 pbNativeSig += cb;
5159                 cbNativeSig -= cb;
5160             }
5161
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);
5165
5166             if (!arrayMarshalInfo.IsValid())
5167             {
5168                 ReportWarning(TLBX_E_BAD_SIGNATURE, arrayMarshalInfo.GetErrorResourceId());
5169                 hr = TLBX_E_BAD_SIGNATURE;
5170                 goto ExitFunc;
5171             }
5172
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);
5178
5179             ArrayToTypeDesc(pCTI, ppool, &arrayMarshalInfo, ptdesc->lptdesc);
5180         }
5181         break;
5182
5183         case NATIVE_TYPE_FIXEDARRAY:
5184         {
5185             ULONG ntElement = NATIVE_TYPE_DEFAULT;
5186             
5187             // NATIVE_TYPE_FIXEDARRAY is only allowed on fields.
5188             if (bMethodSig)
5189             {
5190                 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
5191                 hr = TLBX_E_BAD_SIGNATURE;
5192                 goto ExitFunc;
5193             }
5194            
5195             // Retrieve the size of the fixed array. This is required.
5196             if (cbNativeSig == 0)
5197             {
5198                 ReportWarning(TLBX_E_BAD_SIGNATURE, IDS_EE_BADMARSHALFIELD_FIXEDARRAY_NOSIZE);
5199                 hr = TLBX_E_BAD_SIGNATURE;
5200                 goto ExitFunc;
5201             }
5202
5203             cb = CorSigUncompressData(pbNativeSig, &nativeCount);
5204             pbNativeSig += cb;
5205             cbNativeSig -= cb;
5206
5207             // A size const of 0 isn't supported.
5208             if (nativeCount == 0)
5209             {
5210                 ReportWarning(TLBX_E_BAD_SIGNATURE, IDS_EE_BADMARSHALFIELD_FIXEDARRAY_ZEROSIZE);
5211                 hr = TLBX_E_BAD_SIGNATURE;
5212                 goto ExitFunc;
5213             }
5214
5215             // Read the optional array sub type if specified. 
5216             if (cbNativeSig != 0)
5217             {
5218                 cb = CorSigUncompressData(pbNativeSig, &ntElement);
5219                 pbNativeSig += cb;
5220                 cbNativeSig -= cb;
5221             }
5222
5223             ArrayMarshalInfo arrayMarshalInfo(IsExportingAs64Bit() ? amiExport64Bit : amiExport32Bit);
5224             arrayMarshalInfo.InitForFixedArray(thElement, (CorNativeType)ntElement, fAnsi);
5225
5226             if (!arrayMarshalInfo.IsValid())
5227             {
5228                 ReportWarning(TLBX_E_BAD_SIGNATURE, arrayMarshalInfo.GetErrorResourceId());
5229                 hr = TLBX_E_BAD_SIGNATURE;
5230                 goto ExitFunc;
5231             }
5232
5233             // Set the data
5234             ptdesc->vt = VT_CARRAY;
5235             ptdesc->lpadesc = reinterpret_cast<ARRAYDESC*>(ppool->AllocZero(sizeof(ARRAYDESC)));
5236             if (ptdesc->lpadesc == NULL)
5237                 IfFailReport(E_OUTOFMEMORY);
5238
5239             ArrayToTypeDesc(pCTI, ppool, &arrayMarshalInfo, &ptdesc->lpadesc->tdescElem);
5240
5241             ptdesc->lpadesc->cDims = 1;
5242             ptdesc->lpadesc->rgbounds->cElements = nativeCount;
5243             ptdesc->lpadesc->rgbounds->lLbound = 0;
5244         }
5245         break;
5246
5247         case NATIVE_TYPE_ARRAY:
5248         {
5249             ULONG ntElement = NATIVE_TYPE_DEFAULT;
5250
5251             // NATIVE_TYPE_ARRAY is not allowed on fields.
5252             if (!bMethodSig)
5253             {
5254                 ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_ARRAY_NEEDS_NT_FIXED);
5255                 hr = TLBX_E_BAD_SIGNATURE;
5256                 goto ExitFunc;
5257             }
5258             
5259             // Read the optional array sub type if specified. 
5260             if (cbNativeSig != 0)
5261             {
5262                 cb = CorSigUncompressData(pbNativeSig, &ntElement);
5263                 pbNativeSig += cb;
5264                 cbNativeSig -= cb;
5265             }
5266
5267             ArrayMarshalInfo arrayMarshalInfo(IsExportingAs64Bit() ? amiExport64Bit : amiExport32Bit);
5268             arrayMarshalInfo.InitForNativeArray(MarshalInfo::MARSHAL_SCENARIO_COMINTEROP, thElement, (CorNativeType)ntElement, fAnsi);
5269
5270             if (!arrayMarshalInfo.IsValid())
5271             {
5272                 ReportWarning(TLBX_E_BAD_SIGNATURE, arrayMarshalInfo.GetErrorResourceId());
5273                 hr = TLBX_E_BAD_SIGNATURE;
5274                 goto ExitFunc;
5275             }
5276     
5277             ptdesc->vt = VT_PTR;
5278             ptdesc->lptdesc = reinterpret_cast<TYPEDESC*>(ppool->AllocZero(sizeof(TYPEDESC)));
5279             if(ptdesc->lptdesc == NULL)
5280                 IfFailReport(E_OUTOFMEMORY);
5281
5282             ArrayToTypeDesc(pCTI, ppool, &arrayMarshalInfo, ptdesc->lptdesc);
5283         }
5284         break;
5285
5286         default:
5287             ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_BAD_NATIVETYPE);
5288             hr = TLBX_E_BAD_SIGNATURE;
5289             goto ExitFunc;
5290         }
5291
5292         // If we are dealing with an ELEMENT_TYPE_ARRAY, we need to eat the array description.
5293         if (elem == ELEMENT_TYPE_ARRAY)
5294         {
5295             // Eat the rank.
5296             cbElem += CorSigUncompressData(pbSig+cbElem, &elem);
5297                                                 
5298             // Count of ubounds, ubounds.
5299             cbElem += CorSigUncompressData(pbSig+cbElem, &elem);
5300             for (i=elem; i>0; --i)
5301                 cbElem += CorSigUncompressData(pbSig+cbElem, &elem);
5302
5303             // Count of lbounds, lbounds.
5304             cbElem += CorSigUncompressData(pbSig+cbElem, &elem);
5305             for (i=elem; i>0; --i)
5306                 cbElem += CorSigUncompressData(pbSig+cbElem, &elem);
5307         }
5308
5309         break;
5310     }
5311
5312     case ELEMENT_TYPE_TYPEDBYREF:       // 0x16
5313         ptdesc->vt = VT_VARIANT;
5314         break;
5315
5316     //------------------------------------------
5317     // This really should be the commented out 
5318     //  block following.
5319     case ELEMENT_TYPE_I:              // 0x18,
5320         ptdesc->vt = GetVtForIntPtr();
5321         break;
5322                 
5323     case ELEMENT_TYPE_U:              // 0x19,
5324         ptdesc->vt = GetVtForUIntPtr();
5325         break;
5326
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;
5330         goto ExitFunc;
5331
5332     case ELEMENT_TYPE_SENTINEL:
5333         goto TryAgain;
5334
5335     case ELEMENT_TYPE_CMOD_OPT:         // 0x20     // optional C modifier : E_T_CMOD_OPT <mdTypeRef/mdTypeDef>
5336         cb = CorSigUncompressToken(&pbSig[cbElem], &tkTypeRef);
5337         cbElem += cb;
5338         goto TryAgain;
5339
5340     case ELEMENT_TYPE_FNPTR:
5341         {
5342         ptdesc->vt = GetVtForIntPtr();
5343
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.
5348         break;
5349     }
5350
5351     case ELEMENT_TYPE_GENERICINST: 
5352         ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_GENERICINST_SIGNATURE);
5353         hr = TLBX_E_BAD_SIGNATURE;
5354         goto ExitFunc;
5355         break;
5356
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;
5361         goto ExitFunc;
5362         break;
5363
5364     default:
5365         ReportWarning(TLBX_E_BAD_SIGNATURE, TLBX_E_UNKNOWN_SIGNATURE);
5366         hr = TLBX_E_BAD_SIGNATURE;
5367         goto ExitFunc;
5368         break;
5369     }
5370
5371 ExitFunc:
5372         *pcbElem = cbElem;
5373
5374     if (hr == S_USEIUNKNOWN)
5375         hr = S_OK;
5376
5377     return hr;
5378 } // TypeLibExporter::CorSigToTypeDesc
5379 #ifdef _PREFAST_
5380 #pragma warning(pop)
5381 #endif
5382
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.
5392 {
5393     CONTRACTL
5394     {
5395         STANDARD_VM_CHECK;
5396         PRECONDITION(CheckPointer(pCTI));
5397         PRECONDITION(CheckPointer(pMT));
5398         PRECONDITION(CheckPointer(pHref));
5399     }
5400     CONTRACTL_END;
5401
5402     MethodTable     *pRefdClass;            // MethodTable object for referenced TypeDef.
5403
5404     // Get the MethodTable for the referenced class, and see if it is being converted.
5405     pRefdClass = LoadClass(pMT->GetModule(), tk);
5406
5407     // If the type is not visible from COM then we return S_USEIUNKNOWN.
5408     if (!IsTypeVisibleFromCom(TypeHandle(pRefdClass)))
5409         return S_USEIUNKNOWN;
5410
5411     return EEClassToHref(pCTI, pRefdClass, bWarnOnUsingIUnknown, pHref);
5412 } // HRESULT TypeLibExporter::TokenToHref()
5413
5414 //*****************************************************************************
5415 // Call the resolver to export the typelib for an assembly.
5416 //*****************************************************************************
5417 void TypeLibExporter::ExportReferencedAssembly(
5418     Assembly    *pAssembly)
5419 {
5420     CONTRACTL
5421     {
5422         STANDARD_VM_CHECK;
5423         PRECONDITION(CheckPointer(pAssembly));
5424     }
5425     CONTRACTL_END;
5426     
5427     HRESULT     hr = S_OK;              // A result.
5428     ITypeLib    *pTLB = 0;              // Exported typelib.
5429
5430     // Assembly as IP.
5431     SafeComHolder<IUnknown> pIAssembly = 0;
5432     
5433     {
5434         // Switch to cooperative to get an object ref.
5435         GCX_COOP();
5436         
5437         // Invoke the callback to resolve the reference.
5438         OBJECTREF orAssembly=0;
5439         GCPROTECT_BEGIN(orAssembly)
5440         {
5441             orAssembly = pAssembly->GetExposedObject();
5442
5443             pIAssembly = GetComIPFromObjectRef(&orAssembly, MscorlibBinder::GetClass(CLASS__IASSEMBLY));
5444         }
5445         GCPROTECT_END();
5446     }
5447         
5448     IfFailReport(m_pNotify->ResolveRef((IUnknown*)pIAssembly, (IUnknown**)&pTLB));
5449     
5450     // If we got a typelib, store it on the assembly.
5451     if (pTLB)
5452         pAssembly->SetTypeLib(pTLB);
5453 } // void TypeLibExporter::ExportReferencedAssembly()
5454
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.
5462 {
5463     CONTRACTL
5464     {
5465         STANDARD_VM_CHECK;
5466         PRECONDITION(CheckPointer(pMT));
5467         PRECONDITION(CheckPointer(ppTI));
5468     }
5469     CONTRACTL_END;
5470
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
5477
5478     
5479     HKEYHolder  hInterface;             // Registry key HKCR/Interface
5480     HKEYHolder  hGuid;                  // Registry key of .../{xxx...xxx}
5481     HKEYHolder  hTlb;                   // Registry key of .../TypeLib
5482         
5483     // The ITypeLib.
5484     SafeComHolder<ITypeLib> pTLB=0;
5485
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);
5489
5490     GuidToLPWSTR(guid, wzGuid, lengthof(wzGuid));
5491
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);
5495     if (FAILED(hr))
5496         return;
5497
5498     dwError = WszRegOpenKeyEx((HKEY)hInterface, wzGuid, 0, KEY_READ, &hGuid);
5499     hr = HRESULT_FROM_WIN32(dwError);
5500     if (FAILED(hr))
5501         return;
5502
5503     dwError = WszRegOpenKeyEx((HKEY)hGuid, W("TypeLib"), 0, KEY_READ, &hTlb);
5504     hr = HRESULT_FROM_WIN32(dwError);
5505     if (FAILED(hr))
5506         return;
5507     
5508     cbGuid = sizeof(wzGuid);
5509     dwError = WszRegQueryValue((HKEY)hTlb, W(""), wzGuid, &cbGuid);
5510     hr = HRESULT_FROM_WIN32(dwError);
5511     if (FAILED(hr))
5512         return;
5513     
5514     CLSIDFromString(wzGuid, &guidTlb);
5515
5516     // Retrieve the major and minor version number.
5517     USHORT wMajor;
5518     USHORT wMinor;
5519     Assembly *pAssembly = pMT->GetAssembly();
5520
5521     hr = GetTypeLibVersionForAssembly(pAssembly,&wMajor, &wMinor);
5522     if (SUCCEEDED(hr))
5523     {
5524         hr = LoadRegTypeLib(guidTlb, wMajor, wMinor, 0, &pTLB);
5525     }
5526     if (FAILED(hr))
5527     {
5528         pAssembly->GetVersion(&wMajor, &wMinor, NULL, NULL);
5529
5530         hr = LoadRegTypeLib(guidTlb, wMajor, wMinor, 0, &pTLB);
5531         if (FAILED(hr))
5532         {
5533             hr = LoadRegTypeLib(guidTlb, -1, -1, 0, &pTLB);
5534             if (FAILED(hr))
5535             {
5536                 return;
5537             }
5538         }
5539     }
5540     
5541
5542     hr = pTLB->GetTypeInfoOfGuid(guid, ppTI);
5543 } // void TypeLibExporter::GetWellKnownInterface()
5544     
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.
5553 {
5554     CONTRACTL
5555     {
5556         STANDARD_VM_CHECK;
5557         PRECONDITION(CheckPointer(pCTI));
5558         PRECONDITION(CheckPointer(pClass));
5559         PRECONDITION(CheckPointer(pHref));
5560     }
5561     CONTRACTL_END;
5562     
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.
5572
5573     // A different typeinfo; default for pTI.
5574     SafeComHolder<ITypeInfo> pTIDef=0;
5575
5576     // A TypeInfo; maybe for TypeDef, maybe for TypeRef.
5577     SafeComHolder<ITypeInfo> pTI=0;
5578
5579
5580     // See if we already know this MethodTable' href.
5581     sLookup.pClass = pClass;
5582     if ((pFound=m_HrefOfClassHash.Find(&sLookup)) != NULL)
5583     {
5584         *pHref = pFound->href;
5585         if (*pHref == m_hIUnknown)
5586             return S_USEIUNKNOWN;
5587         return S_OK;
5588     }
5589
5590     // See if the class is in the export list.
5591     sExported.pClass = pClass;
5592     pExported = m_Exports.Find(&sExported);
5593
5594     // If not in the exported assembly, possibly it was injected?
5595     if (pExported == 0)
5596     {
5597         pExported = m_InjectedExports.Find(&sExported);
5598     }
5599     
5600     // Is there an export for this class?
5601     if (pExported)
5602     {   
5603         // Yes, For interfaces and value types (and enums), just use the typeinfo.
5604         if (pClass->IsValueType() || pClass->IsEnum() || pClass->HasLayout())
5605         {
5606             // No default interface, so use the class itself.     
5607             if (pExported->pCTI)
5608                 IfFailReport(SafeQueryInterface(pExported->pCTI, IID_ITypeInfo, (IUnknown**)&pTI));
5609         }
5610         else
5611         if (!pClass->IsInterface())
5612         {   
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);
5617             switch (DefItfType)
5618             {
5619                 case DefaultInterfaceType_Explicit:
5620                 {
5621                     _ASSERTE(!hndDefItfClass.IsNull());
5622
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.
5628                     goto ErrExit;
5629                 }
5630
5631                 case DefaultInterfaceType_AutoDispatch:
5632                 case DefaultInterfaceType_AutoDual:
5633                 {
5634                     _ASSERTE(!hndDefItfClass.IsNull());
5635
5636                     if (hndDefItfClass.GetMethodTable() != pClass)
5637                     {
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.
5643                         goto ErrExit;
5644                     }
5645
5646                     // Return the class interface.
5647                     _ASSERTE(pExported->pCTIClassItf);
5648                     IfFailReport(SafeQueryInterface(pExported->pCTIClassItf, IID_ITypeInfo, (IUnknown**)&pTI));
5649                     break;
5650                 }
5651
5652                 case DefaultInterfaceType_IUnknown:
5653                 case DefaultInterfaceType_BaseComClass:
5654                 {
5655                     pTI = m_pIUnknown;
5656                     bUseIUnknown=true;
5657                     SafeAddRef(pTI);
5658                     break;
5659                 }
5660
5661                 default:
5662                 {
5663                     _ASSERTE(!"Invalid default interface type!");
5664                     hr = E_FAIL;
5665                     break;
5666                 }
5667             }
5668         }
5669         else
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));
5673         }
5674
5675         if ((IUnknown*)pTI == 0)
5676         {
5677             // This is a class from the module/assembly, yet it is not being exported.
5678             
5679             // Whatever happens, the result is OK.
5680             hr = S_OK;
5681             
5682             if (pClass->IsComImport())
5683             {
5684                 // If it is an imported type, get an href to it.
5685                 GetWellKnownInterface(pClass, &pTI);
5686             }
5687             
5688             // If still didn't get a TypeInfo, use IUnknown.
5689             if ((IUnknown*)pTI == 0)
5690             {
5691                 pTI = m_pIUnknown;
5692                 bUseIUnknown=true;
5693                 SafeAddRef(pTI);
5694             }
5695         }
5696     }
5697     else
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);
5704
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();
5715
5716         if (bForceResolveCallback || (FAILED(hr) && hr != TYPE_E_ELEMENTNOTFOUND && !bImportedAssembly))
5717         {
5718             // Invoke the callback to resolve the reference.
5719             
5720             Assembly *pAssembly = pClass->GetAssembly();
5721             
5722             ExportReferencedAssembly(pAssembly);
5723             
5724             hr = GetITypeInfoForEEClass(pClass, &pTI, false/* interface, not coclass */, false/* do not create */, m_flags);
5725         }
5726         
5727         if (hr == TYPE_E_ELEMENTNOTFOUND)
5728         {   
5729             if (pClass->IsComImport())
5730             {
5731                 // If it is an imported type, get an href to it.
5732                 
5733                 // Whatever happens, the result is OK.
5734                 hr = S_OK;
5735
5736                 GetWellKnownInterface(pClass, &pTI);
5737                 
5738                 // If still didn't get a TypeInfo, use IUnknown.
5739                 if ((IUnknown*)pTI == 0)
5740                 {
5741                     pTI = m_pIUnknown;
5742                     bUseIUnknown=true;
5743                     SafeAddRef(pTI);
5744                 }
5745             }
5746             else
5747             {
5748                 // Convert the single typedef from the other scope.
5749                 ConvertOneTypeDef(pClass);
5750                 
5751                 // Now that the type has been injected, recurse to let the default-interface code run.
5752                 hr = EEClassToHref(pCTI, pClass, bWarnOnUsingIUnknown, pHref);
5753                 
5754                 // This class should already have been cached by the recursive call.  Don't want to add
5755                 //  it again.
5756                 goto ErrExit2;
5757             }
5758         }
5759         else if (FAILED(hr))
5760         {
5761             DefineFullyQualifiedNameForClassWOnStack();
5762             LPCWSTR szName = GetFullyQualifiedNameForClassNestedAwareW(pClass);
5763             if (hr == TLBX_W_LIBNOTREGISTERED)
5764             {
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());
5767                 hr = S_OK;
5768                 pTI = m_pIUnknown;
5769                 bUseIUnknown = true;
5770                 SafeAddRef(pTI);
5771                 bUseIUnknownWarned = true;
5772             }
5773             else if (hr == TLBX_E_CANTLOADLIBRARY)
5774             {
5775                 // The imported typelib is registered, but can't be loaded.  Corrupt?  Missing?
5776                 InternalThrowHRWithContext(TLBX_E_CANTLOADLIBRARY, szName, (LPCWSTR) pClass->GetAssembly()->GetManifestModule()->GetPath());
5777             }
5778             IfFailReport(hr);
5779         }
5780     }
5781
5782     // Make sure we could resolve the typeinfo.
5783     if (!(IUnknown*)pTI)
5784         IfFailReport(TYPE_E_ELEMENTNOTFOUND);
5785
5786     // Assert that the containing typelib for pContainer is the typelib being created.
5787 #if defined(_DEBUG)
5788     {
5789         SafeComHolder<ITypeInfo> pTI=0;
5790         SafeComHolder<ITypeLib> pTL=0;
5791         SafeComHolder<ITypeLib> pTLMe=0;
5792         UINT ix;
5793         SafeQueryInterface(pCTI, IID_ITypeInfo, (IUnknown**)&pTI);
5794         SafeQueryInterface(m_pICreateTLB, IID_ITypeLib, (IUnknown**)&pTLMe);
5795         pTI->GetContainingTypeLib(&pTL, &ix);
5796         _ASSERTE(pTL == pTLMe);
5797     }
5798 #endif
5799
5800     // If there is an ITypeInfo, convert to HREFTYPE.
5801     if ((IUnknown*)pTI)
5802     {
5803         if ((IUnknown*)pTI != m_pIUnknown)
5804         {
5805             // Resolve to default.
5806             if (pTIDef)
5807                 hr = S_OK;  // Already have default.
5808             else
5809             {
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));
5821                 else
5822                     hr = S_FALSE;
5823             }
5824             
5825             if (hr == S_OK)
5826                 hr = pCTI->AddRefTypeInfo(pTIDef, pHref);
5827             else
5828                 hr = pCTI->AddRefTypeInfo(pTI, pHref);
5829         }
5830         else
5831         {   // pTI == m_pIUnknown
5832             if (m_hIUnknown == -1)
5833                 hr = pCTI->AddRefTypeInfo(pTI, &m_hIUnknown);
5834             *pHref = m_hIUnknown;
5835         }
5836     }
5837     
5838 ErrExit:
5839     // If we got the href...
5840     if (hr == S_OK)
5841     {
5842         // Save for later use.
5843         if ( NULL == (pFound=m_HrefOfClassHash.Add(&sLookup)))
5844             IfFailReport(E_OUTOFMEMORY);
5845         
5846         pFound->pClass = pClass;
5847         pFound->href = *pHref;
5848     }
5849
5850     // If substituting IUnknown, give a warning.
5851     if (hr == S_OK && bUseIUnknown && bWarnOnUsingIUnknown && !bUseIUnknownWarned)
5852     {
5853         DefineFullyQualifiedNameForClassWOnStack();
5854         LPCWSTR szName = GetFullyQualifiedNameForClassNestedAwareW(pClass);
5855         ReportWarning(S_OK, TLBX_I_USEIUNKNOWN, szName);
5856     }
5857     
5858 ErrExit2:    
5859     if (hr == S_OK && bUseIUnknown)
5860         hr = S_USEIUNKNOWN;
5861
5862     return hr;
5863 } // HRESULT TypeLibExporter::EEClassToHref()
5864
5865 //*****************************************************************************
5866 // Retrieve an HRef to the a type defined in StdOle.
5867 //*****************************************************************************
5868 void TypeLibExporter::StdOleTypeToHRef(ICreateTypeInfo2 *pCTI, REFGUID rGuid, HREFTYPE *pHref)
5869 {
5870     CONTRACTL
5871     {
5872         STANDARD_VM_CHECK;
5873         PRECONDITION(CheckPointer(pCTI));
5874         PRECONDITION(CheckPointer(pHref));
5875     }
5876     CONTRACTL_END;
5877     
5878     HRESULT hr = S_OK;
5879     SafeComHolder<ITypeLib> pITLB = NULL;
5880     SafeComHolder<ITypeInfo> pITI = NULL;
5881     MEMBERID MemID = 0;
5882     USHORT cFound = 0;
5883
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()
5888
5889 //*****************************************************************************
5890 // Given a TypeDef's flags, determine the proper TYPEKIND.
5891 //*****************************************************************************
5892 TYPEKIND TypeLibExporter::TKindFromClass(
5893     MethodTable     *pClass)                // MethodTable.
5894 {
5895     CONTRACTL
5896     {
5897         STANDARD_VM_CHECK;
5898         PRECONDITION(CheckPointer(pClass));
5899     }
5900     CONTRACTL_END;
5901     
5902     HRESULT hr;
5903     ULONG ulIface = ifDual;       // Is this interface [dual], IUnknown, or DISPINTERFACE.
5904     
5905     if (pClass->IsInterface())
5906     {
5907         // IDispatch or IUnknown derived?
5908         IfFailReport(pClass->GetMDImport()->GetIfaceTypeOfTypeDef(pClass->GetCl(), &ulIface));
5909         if (ulIface == ifDispatch)
5910             return TKIND_DISPATCH;
5911         
5912         return TKIND_INTERFACE;
5913     }
5914     
5915     if (pClass->IsEnum())
5916         return TKIND_ENUM;
5917
5918     if (pClass->IsValueType() || pClass->HasLayout())
5919     {
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.
5927
5928         // To enum fields.
5929         HENUMInternalHolder eFDi(pClass->GetMDImport());
5930         eFDi.EnumInit(mdtFieldDef, pClass->GetCl());
5931         
5932         // Get an enumerator for the FieldDefs in the TypeDef.  Only need the counts.
5933         cFD = pClass->GetMDImport()->EnumGetCount(&eFDi);
5934
5935         // Get an enumerator for the class layout.
5936         IfFailReport(pClass->GetMDImport()->GetClassLayoutInit(pClass->GetCl(), &sLayout));
5937
5938         // Enumerate the layout.
5939         while (pClass->GetMDImport()->GetClassLayoutNext(&sLayout, &fd, &ulOffset) == S_OK)
5940         {
5941             if (ulOffset != 0)
5942             {
5943                 bNonZero = true;
5944                 break;
5945             }
5946             ++iFD;
5947         }
5948
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;
5952
5953         return tkResult;
5954     }
5955     
5956     return TKIND_COCLASS;
5957 } // TYPEKIND TypeLibExporter::TKindFromClass()
5958
5959 //*****************************************************************************
5960 // Generate a HREFTYPE in the output TypeLib for a TypeInfo.
5961 //*****************************************************************************
5962 void TypeLibExporter::GetRefTypeInfo(
5963     ICreateTypeInfo2   *pContainer, 
5964     ITypeInfo   *pReferenced, 
5965     HREFTYPE    *pHref)
5966 {
5967     CONTRACTL
5968     {
5969         STANDARD_VM_CHECK;
5970         PRECONDITION(CheckPointer(pContainer));
5971         PRECONDITION(CheckPointer(pReferenced));
5972         PRECONDITION(CheckPointer(pHref));
5973     }
5974     CONTRACTL_END;
5975
5976     HRESULT     hr;                     // A result.
5977     CHrefOfTIHashKey sLookup;               // Hash structure to lookup.
5978     CHrefOfTIHashKey *pFound;               // Found structure.
5979
5980     // See if we already know this TypeInfo.
5981     sLookup.pITI = pReferenced;
5982     if ((pFound=m_HrefHash.Find(&sLookup)) != NULL)
5983     {
5984         *pHref = pFound->href;
5985         return;
5986     }
5987
5988     // Assert that the containing typelib for pContainer is the typelib being created.
5989 #if defined(_DEBUG)
5990     {
5991         SafeComHolder<ITypeInfo> pTI=0;
5992         SafeComHolder<ITypeLib> pTL=0;
5993         SafeComHolder<ITypeLib> pTLMe=0;
5994     UINT ix;
5995         
5996         SafeQueryInterface(pContainer, IID_ITypeInfo, (IUnknown**)&pTI);
5997         SafeQueryInterface(m_pICreateTLB, IID_ITypeLib, (IUnknown**)&pTLMe);
5998     pTI->GetContainingTypeLib(&pTL, &ix);
5999     _ASSERTE(pTL == pTLMe);
6000     }
6001 #endif
6002
6003     // Haven't seen it -- add the href.
6004     // NOTE: This code assumes that hreftypes are per-typelib.
6005     IfFailReport(pContainer->AddRefTypeInfo(pReferenced, pHref));
6006
6007     // Save for later use.
6008     pFound=m_HrefHash.Add(&sLookup);
6009     if (pFound == NULL)
6010         IfFailReport(E_OUTOFMEMORY);
6011     
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()
6019
6020 //*****************************************************************************
6021 // Implementation of a hashed ITypeInfo to HREFTYPE association.
6022 //*****************************************************************************
6023 void TypeLibExporter::CHrefOfTIHash::Clear()
6024 {
6025     CONTRACTL
6026     {
6027         NOTHROW;
6028         GC_TRIGGERS;
6029         SO_TOLERANT;
6030     }
6031     CONTRACTL_END;
6032     
6033     CHrefOfTIHashKey *p;
6034     for (p=GetFirst();  p;  p=GetNext(p))
6035     {
6036         SafeRelease(p->pITI);
6037     }
6038     
6039     CClosedHash<class CHrefOfTIHashKey>::Clear();
6040 } // void TypeLibExporter::CHrefOfTIHash::Clear()
6041
6042 unsigned int TypeLibExporter::CHrefOfTIHash::Hash(const CHrefOfTIHashKey *pData)
6043 {
6044     LIMITED_METHOD_CONTRACT;
6045     
6046 #ifndef _WIN64
6047     // The pointers are at least 4-byte aligned, so ignore bottom two bits.
6048     return (unsigned int) (((size_t)(pData->pITI))>>2);
6049 #else
6050     // @TODO IA64: Is this a good hashing mechanism on IA64?
6051     return (unsigned int) (((size_t)(pData->pITI))>>3);
6052 #endif
6053 } // unsigned long TypeLibExporter::CHrefOfTIHash::Hash()
6054
6055 unsigned int TypeLibExporter::CHrefOfTIHash::Compare(const CHrefOfTIHashKey *p1, CHrefOfTIHashKey *p2)
6056 {
6057     LIMITED_METHOD_CONTRACT;
6058     
6059     if (p1->pITI == p2->pITI)
6060         return (0);
6061     return (1);
6062 } // unsigned long TypeLibExporter::CHrefOfTIHash::Compare()
6063
6064 TypeLibExporter::CHrefOfTIHash::ELEMENTSTATUS TypeLibExporter::CHrefOfTIHash::Status(CHrefOfTIHashKey *p)
6065 {
6066     LIMITED_METHOD_CONTRACT;
6067     if (p->pITI == reinterpret_cast<ITypeInfo*>(FREE))
6068         return (FREE);
6069     if (p->pITI == reinterpret_cast<ITypeInfo*>(DELETED))
6070         return (DELETED);
6071     return (USED);
6072 } // TypeLibExporter::CHrefOfTIHash::ELEMENTSTATUS TypeLibExporter::CHrefOfTIHash::Status()
6073
6074 void TypeLibExporter::CHrefOfTIHash::SetStatus(CHrefOfTIHashKey *p, ELEMENTSTATUS s)
6075 {
6076     LIMITED_METHOD_CONTRACT;
6077     
6078     p->pITI = reinterpret_cast<ITypeInfo*>(s);
6079 } // void TypeLibExporter::CHrefOfTIHash::SetStatus()
6080
6081 void *TypeLibExporter::CHrefOfTIHash::GetKey(CHrefOfTIHashKey *p)
6082 {
6083     LIMITED_METHOD_CONTRACT;
6084     
6085     return &p->pITI;
6086 } // void *TypeLibExporter::CHrefOfTIHash::GetKey()
6087
6088
6089 //*****************************************************************************
6090 // Implementation of a hashed MethodTable* to HREFTYPE association.
6091 //*****************************************************************************
6092 void TypeLibExporter::CHrefOfClassHash::Clear()
6093 {
6094     WRAPPER_NO_CONTRACT;
6095     CClosedHash<class CHrefOfClassHashKey>::Clear();
6096 } // void TypeLibExporter::CHrefOfClassHash::Clear()
6097
6098 unsigned int TypeLibExporter::CHrefOfClassHash::Hash(const CHrefOfClassHashKey *pData)
6099 {
6100     LIMITED_METHOD_CONTRACT;
6101     
6102 #ifndef _WIN64
6103     // Tbe pointers are at least 4-byte aligned, so ignore bottom two bits.
6104     return (unsigned int) (((size_t)(pData->pClass))>>2);
6105 #else
6106     // @TODO IA64: Is this a good hashing mechanism on IA64?
6107     return (unsigned int) (((size_t)(pData->pClass))>>3);
6108 #endif
6109 } // unsigned long TypeLibExporter::CHrefOfClassHash::Hash()
6110
6111 unsigned int TypeLibExporter::CHrefOfClassHash::Compare(const CHrefOfClassHashKey *p1, CHrefOfClassHashKey *p2)
6112 {
6113     LIMITED_METHOD_CONTRACT;
6114     
6115     if (p1->pClass == p2->pClass)
6116         return (0);
6117     return (1);
6118 } // unsigned long TypeLibExporter::CHrefOfClassHash::Compare()
6119
6120 TypeLibExporter::CHrefOfClassHash::ELEMENTSTATUS TypeLibExporter::CHrefOfClassHash::Status(CHrefOfClassHashKey *p)
6121 {
6122     LIMITED_METHOD_CONTRACT;
6123     
6124     if (p->pClass == reinterpret_cast<MethodTable*>(FREE))
6125         return (FREE);
6126     if (p->pClass == reinterpret_cast<MethodTable*>(DELETED))
6127         return (DELETED);
6128     return (USED);
6129 } // TypeLibExporter::CHrefOfClassHash::ELEMENTSTATUS TypeLibExporter::CHrefOfClassHash::Status()
6130
6131 void TypeLibExporter::CHrefOfClassHash::SetStatus(CHrefOfClassHashKey *p, ELEMENTSTATUS s)
6132 {
6133     LIMITED_METHOD_CONTRACT;
6134     
6135     p->pClass = reinterpret_cast<MethodTable*>(s);
6136 } // void TypeLibExporter::CHrefOfClassHash::SetStatus()
6137
6138 void *TypeLibExporter::CHrefOfClassHash::GetKey(CHrefOfClassHashKey *p)
6139 {
6140     LIMITED_METHOD_CONTRACT;
6141     
6142     return &p->pClass;
6143 } // void *TypeLibExporter::CHrefOfClassHash::GetKey()
6144
6145
6146 //*****************************************************************************
6147 // Implementation of a hashed MethodTable* to conversion information association.
6148 //*****************************************************************************
6149 void TypeLibExporter::CExportedTypesHash::Clear()
6150 {
6151     WRAPPER_NO_CONTRACT;
6152
6153     // Iterate over entries and free pointers.
6154     CExportedTypesInfo *pData;
6155     pData = GetFirst();
6156     while (pData)
6157     {
6158         SetStatus(pData, DELETED);
6159         pData = GetNext(pData);
6160     }
6161
6162     CClosedHash<class CExportedTypesInfo>::Clear();
6163 } // void TypeLibExporter::CExportedTypesHash::Clear()
6164
6165 unsigned int TypeLibExporter::CExportedTypesHash::Hash(const CExportedTypesInfo *pData)
6166 {
6167     LIMITED_METHOD_CONTRACT;    
6168     
6169 #ifndef _WIN64
6170     // Tbe pointers are at least 4-byte aligned, so ignore bottom two bits.
6171     return (unsigned int) (((size_t)(pData->pClass))>>2);
6172 #else
6173     // @TODO IA64: Is this a good hashing mechanism on IA64?
6174     return (unsigned int) (((size_t)(pData->pClass))>>3);
6175 #endif
6176 } // unsigned long TypeLibExporter::CExportedTypesHash::Hash()
6177
6178 unsigned int TypeLibExporter::CExportedTypesHash::Compare(const CExportedTypesInfo *p1, CExportedTypesInfo *p2)
6179 {
6180     LIMITED_METHOD_CONTRACT;
6181     
6182     if (p1->pClass == p2->pClass)
6183         return (0);
6184     return (1);
6185 } // unsigned long TypeLibExporter::CExportedTypesHash::Compare()
6186
6187 TypeLibExporter::CExportedTypesHash::ELEMENTSTATUS TypeLibExporter::CExportedTypesHash::Status(CExportedTypesInfo *p)
6188 {
6189     LIMITED_METHOD_CONTRACT;
6190     
6191     if (p->pClass == reinterpret_cast<MethodTable*>(FREE))
6192         return (FREE);
6193     if (p->pClass == reinterpret_cast<MethodTable*>(DELETED))
6194         return (DELETED);
6195     return (USED);
6196 } // TypeLibExporter::CExportedTypesHash::ELEMENTSTATUS TypeLibExporter::CExportedTypesHash::Status()
6197
6198 void TypeLibExporter::CExportedTypesHash::SetStatus(CExportedTypesInfo *p, ELEMENTSTATUS s)
6199 {
6200     WRAPPER_NO_CONTRACT;
6201     
6202     // If deleting a used entry, free the pointers.
6203     if (s == DELETED && Status(p) == USED)
6204     {
6205         if (p->pCTI) p->pCTI->Release(), p->pCTI=0;
6206         if (p->pCTIClassItf) p->pCTIClassItf->Release(), p->pCTIClassItf=0;
6207     }
6208     p->pClass = reinterpret_cast<MethodTable*>(s);
6209 } // void TypeLibExporter::CExportedTypesHash::SetStatus()
6210
6211 void *TypeLibExporter::CExportedTypesHash::GetKey(CExportedTypesInfo *p)
6212 {
6213     LIMITED_METHOD_CONTRACT;
6214     
6215     return &p->pClass;
6216 } // void *TypeLibExporter::CExportedTypesHash::GetKey()
6217
6218 void TypeLibExporter::CExportedTypesHash::InitArray()
6219 {
6220     STANDARD_VM_CONTRACT;
6221     
6222     // For iterating the entries.
6223     CExportedTypesInfo *pData = 0;
6224     
6225     // Make room for the data.
6226     m_iCount = 0;
6227     m_Array = new CExportedTypesInfo*[Base::Count()];
6228     
6229     // Fill the array.
6230     pData = GetFirst();
6231     while (pData)
6232     {
6233         m_Array[m_iCount++] = pData;
6234         pData = GetNext(pData);
6235     }
6236 } // void TypeLibExporter::CExportedTypesHash::InitArray()
6237
6238 void TypeLibExporter::CExportedTypesHash::UpdateArray()
6239 {
6240     STANDARD_VM_CONTRACT;
6241     
6242     // For iterating the entries.
6243     CExportedTypesInfo *pData = 0;
6244
6245     // Clear the old data.
6246     if (m_Array)
6247         delete[] m_Array;
6248     
6249     // Make room for the data.
6250     m_iCount = 0;
6251     m_Array = new CExportedTypesInfo*[Base::Count()];
6252     
6253     // Fill the array.
6254     pData = GetFirst();
6255     while (pData)
6256     {
6257         m_Array[m_iCount++] = pData;
6258         pData = GetNext(pData);
6259     }
6260 } // void TypeLibExporter::CExportedTypesHash::UpdateArray()
6261
6262 void TypeLibExporter::CExportedTypesHash::SortByName()
6263 {
6264     WRAPPER_NO_CONTRACT;
6265     
6266     CSortByName sorter(m_Array, (int)m_iCount);
6267     sorter.Sort();
6268 } // void TypeLibExporter::CExportedTypesHash::SortByName()
6269
6270 void TypeLibExporter::CExportedTypesHash::SortByToken()
6271 {
6272     WRAPPER_NO_CONTRACT;
6273     
6274     CSortByToken sorter(m_Array, (int)m_iCount);
6275     sorter.Sort();
6276 } // void TypeLibExporter::CExportedTypesHash::SortByToken()
6277
6278 int TypeLibExporter::CExportedTypesHash::CSortByToken::Compare(
6279     CExportedTypesInfo **p1,
6280     CExportedTypesInfo **p2)
6281 {
6282     LIMITED_METHOD_CONTRACT;
6283
6284     MethodTable *pC1 = (*p1)->pClass;
6285     MethodTable *pC2 = (*p2)->pClass;
6286     // Compare scopes.
6287     if (pC1->GetMDImport() < pC2->GetMDImport())
6288         return -1;
6289     if (pC1->GetMDImport() > pC2->GetMDImport())
6290         return 1;
6291     // Same scopes, compare tokens.
6292     if (pC1->GetTypeDefRid() < pC2->GetTypeDefRid())
6293         return -1;
6294     if (pC1->GetTypeDefRid() > pC2->GetTypeDefRid())
6295         return 1;
6296     // Hmmm.  Same class.
6297     return 0;
6298 } // int TypeLibExporter::CExportedTypesHash::CSortByToken::Compare()
6299
6300 int TypeLibExporter::CExportedTypesHash::CSortByName::Compare(
6301     CExportedTypesInfo **p1,
6302     CExportedTypesInfo **p2)
6303 {
6304     CONTRACTL
6305     {
6306         STANDARD_VM_CHECK;
6307         PRECONDITION(CheckPointer(p1));
6308         PRECONDITION(CheckPointer(p2));
6309         PRECONDITION(CheckPointer(*p1));
6310         PRECONDITION(CheckPointer(*p2));
6311     }
6312     CONTRACTL_END;
6313     
6314     int iRslt;                          // A compare result.
6315     
6316     MethodTable *pC1 = (*p1)->pClass;
6317     MethodTable *pC2 = (*p2)->pClass;
6318     
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));
6325     
6326     // Compare case-insensitive, because we want different capitalizations to sort together.
6327     SString sName1(SString::Utf8, pName1);
6328     SString sName2(SString::Utf8, pName2);
6329
6330     iRslt = sName1.CompareCaseInsensitive(sName2);
6331     if (iRslt)
6332         return iRslt;
6333     
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);
6338     
6339     iRslt = sNS1.CompareCaseInsensitive(sNS2);
6340     return iRslt;
6341 } // int TypeLibExporter::CExportedTypesHash::CSortByName::Compare()
6342