Remove always defined FEATURE_CORECLR
[platform/upstream/coreclr.git] / src / tools / metainfo / mdinfo.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 #include <stdio.h>
6 #include <windows.h>
7 #include <objbase.h>
8 #include <crtdbg.h>
9 #include <assert.h>
10
11 #include <corpriv.h>
12 #include <cor.h>
13 #include "assert.h"
14 #include "corerror.h"
15 #include <winwrap.h>
16 #include <prettyprintsig.h>
17
18 #include <cahlpr.h>
19 #include <limits.h>
20
21 #include "mdinfo.h"
22
23 #define LEGACY_ACTIVATION_SHIM_LOAD_LIBRARY WszLoadLibrary
24 #define LEGACY_ACTIVATION_SHIM_DEFINE_CoInitializeEE
25
26 #define ENUM_BUFFER_SIZE 10
27 #define TAB_SIZE 8
28
29 #define NumItems(s) (sizeof(s) / sizeof(s[0]))
30
31 #define ISFLAG(p,x) if (Is##p##x(flags)) strcat_s(sFlags,STRING_BUFFER_LEN, "["#x "] ");
32
33 extern HRESULT  _FillVariant(
34     BYTE        bCPlusTypeFlag, 
35     void const  *pValue,
36     ULONG       cbValue,
37     VARIANT     *pvar); 
38
39 // Validator declarations.
40 extern DWORD g_ValModuleType;
41 #include <ivehandler.h>
42
43 // Tables for mapping element type to text
44 const char *g_szMapElementType[] = 
45 {
46     "End",          // 0x0
47     "Void",         // 0x1
48     "Boolean",
49     "Char", 
50     "I1",
51     "UI1",
52     "I2",           // 0x6
53     "UI2",
54     "I4",
55     "UI4",
56     "I8",
57     "UI8",
58     "R4",
59     "R8",
60     "String",
61     "Ptr",          // 0xf
62     "ByRef",        // 0x10
63     "ValueClass",
64     "Class",
65     "Var",
66     "MDArray",      // 0x14
67     "GenericInst",
68     "TypedByRef",
69     "VALUEARRAY",
70     "I",
71     "U",
72     "R",            // 0x1a
73     "FNPTR",
74     "Object",
75     "SZArray",
76     "MVar",
77     "CMOD_REQD",
78     "CMOD_OPT",
79     "INTERNAL",
80 };
81
82 const char *g_szMapUndecorateType[] = 
83 {
84     "",                 // 0x0
85     "void",
86     "boolean",
87     "Char", 
88     "byte",
89     "unsigned byte",
90     "short",
91     "unsigned short",
92     "int",
93     "unsigned int",
94     "long",
95     "unsigned long",
96     "float",
97     "double",
98     "String",
99     "*",                // 0xf
100     "ByRef",
101     "",
102     "",
103     "",
104     "",
105     "",
106     "",
107     "",
108     "",
109     "",
110     "",
111     "Function Pointer",
112     "Object",
113     "",
114     "",
115     "CMOD_REQD",
116     "CMOD_OPT",
117     "INTERNAL",
118 };
119
120 // Provide enough entries for IMAGE_CEE_CS_CALLCONV_MASK (defined in CorHdr.h)
121 const char *g_strCalling[] = 
122 {   
123     "[DEFAULT]",
124     "[C]",
125     "[STDCALL]",
126     "[THISCALL]",
127     "[FASTCALL]",
128     "[VARARG]",
129     "[FIELD]",
130     "[LOCALSIG]",
131     "[PROPERTY]",
132     "[UNMANAGED]",
133     "[GENERICINST]",
134     "[NATIVEVARARG]",
135     "[INVALID]",
136     "[INVALID]",
137     "[INVALID]",
138     "[INVALID]"
139 };
140
141 const char *g_szNativeType[] =
142 {
143     "NATIVE_TYPE_END(DEPRECATED!)",  //         = 0x0,    //DEPRECATED
144     "NATIVE_TYPE_VOID(DEPRECATED!)",  //        = 0x1,    //DEPRECATED
145     "NATIVE_TYPE_BOOLEAN",  //     = 0x2,    // (4 byte boolean value: TRUE = non-zero, FALSE = 0)
146     "NATIVE_TYPE_I1",  //          = 0x3,  
147     "NATIVE_TYPE_U1",  //          = 0x4,  
148     "NATIVE_TYPE_I2",  //          = 0x5,  
149     "NATIVE_TYPE_U2",  //          = 0x6,  
150     "NATIVE_TYPE_I4",  //          = 0x7,  
151     "NATIVE_TYPE_U4",  //          = 0x8,  
152     "NATIVE_TYPE_I8",  //          = 0x9,  
153     "NATIVE_TYPE_U8",  //          = 0xa,  
154     "NATIVE_TYPE_R4",  //          = 0xb,  
155     "NATIVE_TYPE_R8",  //          = 0xc,  
156     "NATIVE_TYPE_SYSCHAR(DEPRECATED!)",  //     = 0xd,    //DEPRECATED 
157     "NATIVE_TYPE_VARIANT(DEPRECATED!)",  //     = 0xe,    //DEPRECATED
158     "NATIVE_TYPE_CURRENCY",               //    = 0xf,
159     "NATIVE_TYPE_PTR(DEPRECATED!)",  //         = 0x10,   //DEPRECATED  
160
161     "NATIVE_TYPE_DECIMAL(DEPRECATED!)",  //     = 0x11,   //DEPRECATED
162     "NATIVE_TYPE_DATE(DEPRECATED!)",  //        = 0x12,   //DEPRECATED
163     "NATIVE_TYPE_BSTR",  //        = 0x13, 
164     "NATIVE_TYPE_LPSTR",  //       = 0x14, 
165     "NATIVE_TYPE_LPWSTR",  //      = 0x15, 
166     "NATIVE_TYPE_LPTSTR",  //      = 0x16, 
167     "NATIVE_TYPE_FIXEDSYSSTRING",  //  = 0x17, 
168     "NATIVE_TYPE_OBJECTREF(DEPRECATED!)",  //   = 0x18,   //DEPRECATED
169     "NATIVE_TYPE_IUNKNOWN",  //    = 0x19,
170     "NATIVE_TYPE_IDISPATCH",  //   = 0x1a,
171     "NATIVE_TYPE_STRUCT",  //      = 0x1b, 
172     "NATIVE_TYPE_INTF",  //        = 0x1c, 
173     "NATIVE_TYPE_SAFEARRAY",  //   = 0x1d, 
174     "NATIVE_TYPE_FIXEDARRAY",  //  = 0x1e, 
175     "NATIVE_TYPE_INT",  //         = 0x1f, 
176     "NATIVE_TYPE_UINT",  //        = 0x20, 
177
178     "NATIVE_TYPE_NESTEDSTRUCT(DEPRECATED!)",  //  = 0x21, //DEPRECATED (use "NATIVE_TYPE_STRUCT)   
179
180     "NATIVE_TYPE_BYVALSTR",  //    = 0x22,
181                               
182     "NATIVE_TYPE_ANSIBSTR",  //    = 0x23,
183
184     "NATIVE_TYPE_TBSTR",  //       = 0x24, // select BSTR or ANSIBSTR depending on platform
185
186
187     "NATIVE_TYPE_VARIANTBOOL",  // = 0x25, // (2-byte boolean value: TRUE = -1, FALSE = 0)
188     "NATIVE_TYPE_FUNC",  //        = 0x26,
189     "NATIVE_TYPE_LPVOID",  //      = 0x27, // blind pointer (no deep marshaling)
190
191     "NATIVE_TYPE_ASANY",  //       = 0x28,
192     "<UNDEFINED NATIVE TYPE 0x29>",
193     "NATIVE_TYPE_ARRAY",  //       = 0x2a,
194     "NATIVE_TYPE_LPSTRUCT",  //    = 0x2b,
195     "NATIVE_TYPE_CUSTOMMARSHALER", //           = 0x2c, // Custom marshaler.
196     "NATIVE_TYPE_ERROR", //        = 0x2d, // VT_HRESULT when exporting to a typelib.
197 };
198
199
200 size_t g_cbCoffNames = 0;
201
202 mdMethodDef g_tkEntryPoint = 0; // integration with ILDASM
203
204
205
206 // helper to init signature buffer
207 void MDInfo::InitSigBuffer()
208 {
209     strcpy_s((LPSTR)m_sigBuf.Ptr(), 1, "");
210 } // void MDInfo::InitSigBuffer()
211
212 // helper to append a string into the signature buffer. If size of signature buffer is not big enough,
213 // we will grow it.
214 HRESULT MDInfo::AddToSigBuffer(__in_z __in const char *string)
215 {
216     HRESULT     hr;
217     size_t LL = strlen((LPSTR)m_sigBuf.Ptr()) + strlen(string) + 1;
218     IfFailRet( m_sigBuf.ReSizeNoThrow(LL) );
219     strcat_s((LPSTR)m_sigBuf.Ptr(), LL, string);
220     return NOERROR;
221 } // HRESULT MDInfo::AddToSigBuffer()
222
223 MDInfo::MDInfo(IMetaDataImport2 *pImport, IMetaDataAssemblyImport *pAssemblyImport, LPCWSTR szScope, strPassBackFn inPBFn, ULONG DumpFilter)
224 {   // This constructor is specific to ILDASM/MetaInfo integration
225
226     _ASSERTE(pImport != NULL);
227     _ASSERTE(NumItems(g_szMapElementType) == NumItems(g_szMapUndecorateType));
228     _ASSERTE(NumItems(g_szMapElementType) == ELEMENT_TYPE_MAX);
229
230     Init(inPBFn, (DUMP_FILTER)DumpFilter);
231     
232     m_pImport = pImport;
233     m_pImport->AddRef();
234     if ((m_pAssemblyImport = pAssemblyImport)) 
235         m_pAssemblyImport->AddRef();
236     else
237     {
238         HRESULT hr = m_pImport->QueryInterface(IID_IMetaDataAssemblyImport, (void**) &m_pAssemblyImport);
239         if (FAILED(hr))
240             Error("QueryInterface failed for IID_IMetaDataAssemblyImport.", hr);
241     }
242
243 } // MDInfo::MDInfo()
244
245 MDInfo::MDInfo(IMetaDataDispenserEx *pDispenser, LPCWSTR szScope, strPassBackFn inPBFn, ULONG DumpFilter)
246 {
247     HRESULT     hr = S_OK;
248     VARIANT     value;
249
250     _ASSERTE(pDispenser != NULL && inPBFn != NULL);
251     _ASSERTE(NumItems(g_szMapElementType) == NumItems(g_szMapUndecorateType));
252     _ASSERTE(NumItems(g_szMapElementType) == ELEMENT_TYPE_MAX);
253
254     Init(inPBFn, (DUMP_FILTER)DumpFilter);
255
256     // Attempt to open scope on given file
257     V_VT(&value) = VT_UI4;
258     V_UI4(&value) = MDImportOptionAll;
259     if (FAILED(hr = pDispenser->SetOption(MetaDataImportOption, &value)))
260             Error("SetOption failed.", hr);
261
262     hr = pDispenser->OpenScope(szScope, ofNoTransform, IID_IMetaDataImport2, (IUnknown**)&m_pImport);
263     if (hr == CLDB_E_BADUPDATEMODE)
264     {
265         V_VT(&value) = VT_UI4;
266         V_UI4(&value) = MDUpdateIncremental;
267         if (FAILED(hr = pDispenser->SetOption(MetaDataSetUpdate, &value)))
268             Error("SetOption failed.", hr);
269         hr = pDispenser->OpenScope(szScope, ofNoTransform, IID_IMetaDataImport2, (IUnknown**)&m_pImport);
270     }
271     if (FAILED(hr))
272         Error("OpenScope failed", hr);
273
274     // Query for the IMetaDataAssemblyImport interface.
275     hr = m_pImport->QueryInterface(IID_IMetaDataAssemblyImport, (void**) &m_pAssemblyImport);
276     if (FAILED(hr))
277         Error("QueryInterface failed for IID_IMetaDataAssemblyImport.", hr);
278
279 } // MDInfo::MDInfo()
280
281
282 MDInfo::MDInfo(IMetaDataDispenserEx *pDispenser, PBYTE pbMetaData, DWORD dwSize, strPassBackFn inPBFn, ULONG DumpFilter)
283 {
284     _ASSERTE(pDispenser != NULL && inPBFn != NULL);
285     _ASSERTE(NumItems(g_szMapElementType) == NumItems(g_szMapUndecorateType));
286     _ASSERTE(NumItems(g_szMapElementType) == ELEMENT_TYPE_MAX);
287
288     Init(inPBFn, (DUMP_FILTER)DumpFilter);
289
290     // Attempt to open scope on manifest. It's valid for this to fail, because
291     // the blob we open may just be the assembly resources (the space is
292     // overloaded until we remove LM -a assemblies, at which point this
293     // constructor should probably be removed too).
294     HRESULT hr;
295     VARIANT     value;
296     V_VT(&value) = VT_UI4;
297     V_UI4(&value) = MDImportOptionAll;
298     if (FAILED(hr = pDispenser->SetOption(MetaDataImportOption, &value)))
299             Error("SetOption failed.", hr);
300     if (SUCCEEDED(hr = pDispenser->OpenScopeOnMemory(pbMetaData, dwSize, ofNoTransform,
301                             IID_IMetaDataImport2, (IUnknown**)&m_pImport)))
302     {
303         // Query for the IMetaDataAssemblyImport interface.
304         hr = m_pImport->QueryInterface(IID_IMetaDataAssemblyImport, (void**) &m_pAssemblyImport);
305         if (FAILED(hr))
306             Error("QueryInterface failed for IID_IMetaDataAssemblyImport.", hr);
307     }
308
309 } // MDInfo::MDInfo()
310
311 void MDInfo::Init(
312     strPassBackFn inPBFn,               // Callback to write text.
313     DUMP_FILTER DumpFilter)             // Flags to control the dump.
314 {
315     m_VEHandlerReporterPtr = 0;
316     m_pbFn = inPBFn;
317     m_DumpFilter = DumpFilter;
318     m_pTables = NULL;
319     m_pTables2 = NULL;
320     m_pImport = NULL;
321     m_pAssemblyImport = NULL;
322 } // void MDInfo::Init()
323
324 // Destructor
325 MDInfo::~MDInfo()
326 {
327     if (m_pImport)
328         m_pImport->Release();
329     if (m_pAssemblyImport)
330         m_pAssemblyImport->Release();
331     if (m_pTables)
332         m_pTables->Release();
333     if (m_pTables2)
334         m_pTables2->Release();
335 } // MDInfo::~MDInfo()
336
337 //=====================================================================================================================
338 //#define EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION
339 #ifndef EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION
340
341 HINSTANCE GetModuleInst()
342 {
343     return NULL;
344 } // HINSTANCE GetModuleInst()
345
346 typedef HRESULT (*REPORTFCTN)(LPCWSTR, VEContext, HRESULT);
347 HRESULT DefaultReporter( // Return status.
348     LPCWSTR     szMsg,                  // Error message.
349     VEContext   Context,                // Error context (offset,token)
350     HRESULT     hrRpt)                      // Original HRESULT
351
352     if(szMsg)
353     {
354         printf("%S", szMsg);
355         // include token and offset from Context
356         if(Context.Token) printf(" [token:0x%08X]",Context.Token);
357         if(Context.uOffset) printf(" [at:0x%X]",Context.uOffset);
358         printf(" [hr:0x%08X]\n",hrRpt);
359         fflush(stdout);
360     }
361     return S_OK;
362 } // HRESULT DefaultReporter()
363
364
365 #ifdef FEATURE_METADATA_VALIDATOR
366 class MDVEHandlerClass : public IVEHandler
367 {
368 public: 
369     LONG        m_refCount;
370     REPORTFCTN  m_fnReport;
371
372     MDVEHandlerClass() { m_refCount=0; m_fnReport=DefaultReporter; };
373     virtual ~MDVEHandlerClass() { };
374
375     //-----------------------------------------------------------
376     // IUnknown support
377     //-----------------------------------------------------------
378     HRESULT STDMETHODCALLTYPE    QueryInterface(REFIID id, void** pInterface) 
379     {
380         if (id == IID_IVEHandler)
381             *pInterface = (IVEHandler*)this;
382         /*
383         else if (id == IID_IUnknown)
384             *pInterface = (IUnknown*)(IVEHandler*)this;
385         */
386         else
387         {
388             *pInterface = NULL;
389             return E_NOINTERFACE;
390         }
391
392         AddRef();
393         return S_OK;
394     }
395     ULONG STDMETHODCALLTYPE AddRef() 
396     {
397         return InterlockedIncrement(&m_refCount);
398     }
399
400     ULONG STDMETHODCALLTYPE Release() 
401     {
402         LONG       refCount = InterlockedDecrement(&m_refCount);
403         if (refCount == 0) delete this;
404         return (refCount);
405     }
406     //-----------------------------------------------------------
407     // IVEHandler support
408     //-----------------------------------------------------------
409     HRESULT STDMETHODCALLTYPE   SetReporterFtn(__int64 lFnPtr)
410     {
411         m_fnReport = lFnPtr ? reinterpret_cast<REPORTFCTN>(lFnPtr) 
412                              : DefaultReporter;
413         return S_OK;
414     };
415
416 //*****************************************************************************
417 // The Verification Event Handler itself. Declared in VEHandler.h as virtual, may be overridden
418 //*****************************************************************************
419     HRESULT STDMETHODCALLTYPE VEHandler(HRESULT hrRpt, VEContext Context, SAFEARRAY *psa)
420     {
421         WCHAR       rcBuf[1024];             // Resource string.
422         WCHAR       rcMsg[1024];             // Error message.
423         BYTE       *marker;                  // User text.
424         HRESULT     hr;
425         ULONG32     k;
426         WCHAR      *pWsz[1024]; // is more than 1024 string arguments likely?
427
428         // Return warnings without text.
429         if (!FAILED(hrRpt))
430             return (hrRpt);
431         memset(pWsz,0,sizeof(pWsz));
432
433         ULONG32      nVars;
434         // Convert safearray of variants into va_list
435         if(psa && (nVars = psa->rgsabound[0].cElements))
436         {
437             WCHAR       *pwsz;
438             VARIANT     *pVar;
439             ULONG32      i,l;
440             BYTE        *pval;
441
442             _ASSERTE(psa->fFeatures & FADF_VARIANT);
443             _ASSERTE(psa->cDims == 1);
444             marker = new BYTE[nVars*sizeof(double)]; // double being the largest variant element
445             for(i=0,pVar=(VARIANT *)(psa->pvData),pval=marker; i < nVars; pVar++,i++)
446             {
447                 switch(V_VT(pVar))
448                 {
449                     case VT_I1:
450                         *(int *)pval = V_I1(pVar);
451                         pval += sizeof(int);
452                         break;
453                         
454                     case VT_UI1:
455                         *(int *)pval = V_UI1(pVar);
456                         pval += sizeof(int);
457                         break;
458                         
459
460                     case VT_I2:
461                         *(int *)pval = V_I2(pVar);
462                         pval += sizeof(int);
463                         break;
464                         
465                     case VT_UI2:
466                         *(int *)pval = V_UI2(pVar);
467                         pval += sizeof(int);
468                         break;
469                     
470                     case VT_I8:
471                     case VT_UI8:
472                         *(INT64 *)pval = V_I8(pVar);
473                         pval += sizeof(INT64);
474                         break;
475                         
476
477                     case VT_BYREF|VT_I1:
478                     case VT_BYREF|VT_UI1: // it's ASCII string, convert it to UNICODE
479                         {
480                         PBYTE pb = V_UI1REF(pVar);
481                         l = (ULONG32)strlen((char *)pb)+1;
482                         pwsz = new WCHAR[l];
483                         WszMultiByteToWideChar(CP_ACP,0,(char*)pb,-1,pwsz,l);
484                         for(k=0; pWsz[k]; k++);
485                         pWsz[k] = pwsz;
486                         
487                         *(WCHAR **)pval = pwsz;
488                         pval += sizeof(WCHAR *);
489                         break;
490                         }
491
492                     default:
493                         *(int *)pval = V_I4(pVar);
494                         pval += sizeof(int);
495                         break;
496                 }
497             }
498         }
499         else
500             marker = NULL;
501
502         // If this is one of our errors, then grab the error from the rc file.
503         if (HRESULT_FACILITY(hrRpt) == FACILITY_URT)
504         {
505             hr = UtilLoadStringRC(LOWORD(hrRpt), rcBuf, NumItems(rcBuf), true);
506             if (hr == S_OK)
507             {
508                 // Format the error.
509                 vswprintf_s(rcMsg, NumItems(rcMsg), rcBuf, (va_list) marker);
510                 rcMsg[NumItems(rcMsg) - 1] = 0;
511             }
512         }
513         // Otherwise it isn't one of ours, so we need to see if the system can
514         // find the text for it.
515         else
516         {
517             if (WszFormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
518                     0, hrRpt, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
519                     rcMsg, NumItems(rcMsg), 0))
520             {
521                 hr = S_OK;
522
523                 // System messages contain a trailing \r\n, which we don't want normally.
524                 int iLen = lstrlenW(rcMsg);
525                 if (iLen > 3 && rcMsg[iLen - 2] == '\r' && rcMsg[iLen - 1] == '\n')
526                     rcMsg[iLen - 2] = '\0';
527             }
528             else
529                 hr = HRESULT_FROM_WIN32(GetLastError());
530         }
531         if(marker) delete [] marker;
532
533         // If we failed to find the message anywhere, then issue a hard coded message.
534         if (FAILED(hr))
535         {
536             swprintf_s(rcMsg, NumItems(rcMsg), W("COM+ Runtime Internal error: 0x%08x"), hrRpt);
537             //DEBUG_STMT(DbgWriteEx(rcMsg));
538         }
539
540         // delete WCHAR buffers allocated above (if any)
541         for(k=0; pWsz[k]; k++) 
542         { 
543             if(pWsz[k]) 
544             {
545                 delete [] pWsz[k];
546                 pWsz[k] = NULL;
547             }
548         }
549
550         return (m_fnReport(rcMsg, Context,hrRpt) == S_OK ? S_OK : E_FAIL);
551     };
552
553     static HRESULT STDMETHODCALLTYPE CreateObject(REFIID id, void **object)
554     { return E_NOTIMPL; }
555 };
556 #endif // FEATURE_METADATA_VALIDATOR
557
558 #endif
559 //=====================================================================================================================
560 // DisplayMD() function
561 //
562 // Displays the meta data content of a file
563
564 void MDInfo::DisplayMD()
565 {
566     if ((m_DumpFilter & dumpAssem) && m_pAssemblyImport)
567         DisplayAssemblyInfo();
568     WriteLine("===========================================================");
569     // Metadata itself: Raw or normal view
570     if (m_DumpFilter & (dumpSchema | dumpHeader | dumpCSV | dumpRaw | dumpStats | dumpRawHeaps))
571         DisplayRaw();
572     else
573     {
574         DisplayVersionInfo();
575         DisplayScopeInfo();
576         WriteLine("===========================================================");
577         DisplayGlobalFunctions();
578         DisplayGlobalFields();
579         DisplayGlobalMemberRefs();
580         DisplayTypeDefs();
581         DisplayTypeRefs();
582         DisplayTypeSpecs();
583         DisplayMethodSpecs();
584         DisplayModuleRefs();
585         DisplaySignatures();
586         DisplayAssembly();
587         DisplayUserStrings();
588
589         // WriteLine("============================================================");
590         // WriteLine("Unresolved MemberRefs");
591         // DisplayMemberRefs(0x00000001, "\t");
592
593         VWrite("\n\nCoff symbol name overhead:  %d\n", g_cbCoffNames);
594     }
595     WriteLine("===========================================================");
596     if (m_DumpFilter & dumpUnsat)
597         DisplayUnsatInfo();
598     WriteLine("===========================================================");
599 #ifdef FEATURE_METADATA_VALIDATOR
600     if (m_DumpFilter & dumpValidate)
601     {
602         IMetaDataValidate *pValidate = 0;
603 #ifndef EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION
604         MDVEHandlerClass    *pVEHandler = 0;
605 #else
606         IVEHandler  *pVEHandler = 0;
607 #endif
608         const char *szErrStr = 0;
609         HRESULT     hr = S_OK;
610
611         // Get a pointer to the Validator interface.
612         hr = m_pImport->QueryInterface(IID_IMetaDataValidate, (void **) &pValidate);
613         if (FAILED(hr))
614         {
615             szErrStr = "QueryInterface failed for IMetaDataValidate.";
616             goto ErrExit;
617         }
618
619         // Get a pointer to the VEHandler interface.
620 #ifndef EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION
621         if((pVEHandler = new MDVEHandlerClass())) hr = S_OK;
622         else hr = E_FAIL;
623 #else
624         hr = CoCreateInstance(CLSID_VEHandlerClass,
625                            NULL,
626                            CLSCTX_INPROC_SERVER,
627                            IID_IVEHandler,
628                            (void **)&pVEHandler);
629 #endif
630         if (FAILED(hr))
631         {
632 #ifndef EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION
633             szErrStr = "Failed to create VEHandler.";
634 #else
635             szErrStr = "CoCreateInstance(VEHandler) failed.";
636 #endif
637             goto ErrExit;
638         }
639
640         if(m_VEHandlerReporterPtr) pVEHandler->SetReporterFtn((__int64)m_VEHandlerReporterPtr);
641
642         hr = pValidate->ValidatorInit(g_ValModuleType, pVEHandler);
643         if (FAILED(hr))
644         {
645             szErrStr = "ValidatorInit failed.";
646             goto ErrExit;
647         }
648
649         hr = pValidate->ValidateMetaData();
650         if (FAILED(hr))
651         {
652             szErrStr = "ValidateMetaData failed to run successfully.";
653             goto ErrExit;
654         }
655         if (hr == S_OK)
656             WriteLine("No warnings or errors found.");
657         else if (hr == VLDTR_S_WRN)
658             WriteLine("Warnings found.");
659         else if (hr == VLDTR_S_ERR)
660             WriteLine("Errors found.");
661         else if (hr == VLDTR_S_WRNERR)
662             WriteLine("Warnings and Errors found.");
663         else
664             VWriteLine("Validator returned unexpected success code, hr=0x%08x.", hr);
665 ErrExit:
666         if (pValidate)
667             pValidate->Release();
668 #ifdef EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION
669         if (pVEHandler)
670             pVEHandler->Release();
671 #endif
672         if (szErrStr)
673             Error(szErrStr, hr);
674     }
675 #endif // FEATURE_METADATA_VALIDATOR
676     WriteLine("===========================================================");
677 } // MDVEHandlerClass()
678
679 int MDInfo::WriteLine(__in_z __in const char *str)
680 {
681     ULONG32 count = (ULONG32) strlen(str);
682
683     m_pbFn(str);
684     m_pbFn("\n");
685     return count;
686 } // int MDInfo::WriteLine()
687
688 int MDInfo::Write(__in_z __in const char *str)
689 {
690     ULONG32 count = (ULONG32) strlen(str);
691
692     m_pbFn(str);
693     return count;
694 } // int MDInfo::Write()
695
696 int MDInfo::VWriteLine(__in_z __in const char *str, ...)
697 {
698     va_list marker;
699     int     count;
700
701     va_start(marker, str);
702     count = VWriteMarker(str, marker);
703     m_pbFn("\n");
704     va_end(marker);
705     return count;
706 } // int MDInfo::VWriteLine()
707
708 int MDInfo::VWrite(__in_z __in const char *str, ...)
709 {
710     va_list marker;
711     int     count;
712
713     va_start(marker, str);
714     count = VWriteMarker(str, marker);
715     va_end(marker);
716     return count;
717 } // int MDInfo::VWrite()
718
719 int MDInfo::VWriteMarker(__in_z __in const char *str, va_list marker)
720 {
721     HRESULT hr;
722     int count = -1;
723     // Used to allocate 1K, then if not enough, 2K, then 4K.
724     // Faster to allocate 32K right away and be done with it, 
725     // we're not running on Commodore 64
726     if (FAILED(hr = m_output.ReSizeNoThrow(STRING_BUFFER_LEN * 8)))
727         Error("ReSize failed.", hr);
728     else
729     {
730         count = vsprintf_s((char *)m_output.Ptr(), STRING_BUFFER_LEN * 8, str, marker);
731         m_pbFn((char *)m_output.Ptr());
732     }
733     return count;
734 } // int MDInfo::VWriteToBuffer()
735
736 // Error() function -- prints an error and returns
737 void MDInfo::Error(const char* szError, HRESULT hr)
738 {
739     printf("\n%s\n",szError);
740     if (hr != S_OK)
741     {
742         printf("Failed return code: 0x%08x\n", hr);
743
744         IErrorInfo  *pIErr = NULL;          // Error interface.
745         BSTR        bstrDesc = NULL;        // Description text.
746 #ifdef FEATURE_COMINTEROP
747         // Try to get an error info object and display the message.
748         if (GetErrorInfo(0, &pIErr) == S_OK &&
749             pIErr->GetDescription(&bstrDesc) == S_OK)
750         {
751             printf("%ls ", bstrDesc);
752             SysFreeString(bstrDesc);
753         }
754 #endif
755         // Free the error interface.
756         if (pIErr)
757             pIErr->Release();
758
759     }
760     exit(hr);
761 } // void MDInfo::Error()
762
763 // Print out the optional version info included in the MetaData.
764
765 void MDInfo::DisplayVersionInfo()
766 {
767     if (!(m_DumpFilter & MDInfo::dumpNoLogo))
768     {
769         LPCUTF8 pVersionStr;
770         HRESULT hr = S_OK;
771
772         if (m_pTables == 0)
773         {
774             if (m_pImport)
775                 hr = m_pImport->QueryInterface(IID_IMetaDataTables, (void**)&m_pTables);
776             else if (m_pAssemblyImport)
777                 hr = m_pAssemblyImport->QueryInterface(IID_IMetaDataTables, (void**)&m_pTables);
778             else
779                 return;
780             if (FAILED(hr))
781                 Error("QueryInterface failed for IID_IMetaDataTables.", hr);
782         }
783
784         hr = m_pTables->GetString(1, &pVersionStr);
785         if (FAILED(hr))
786             Error("GetString() failed.", hr);
787         if (strstr(pVersionStr, "Version of runtime against which the binary is built : ")
788                     == pVersionStr)
789         {
790             WriteLine(const_cast<char *>(pVersionStr));
791         }
792     }
793 } // void MDInfo::DisplayVersionInfo()
794
795 // Prints out information about the scope
796
797 void MDInfo::DisplayScopeInfo()
798 {
799     HRESULT hr;
800     mdModule mdm;
801     GUID mvid;
802     WCHAR scopeName[STRING_BUFFER_LEN];
803     WCHAR guidString[STRING_BUFFER_LEN];
804
805     hr = m_pImport->GetScopeProps( scopeName, STRING_BUFFER_LEN, 0, &mvid);
806     if (FAILED(hr)) Error("GetScopeProps failed.", hr);
807
808     VWriteLine("ScopeName : %ls",scopeName);
809
810     if (!(m_DumpFilter & MDInfo::dumpNoLogo))
811         VWriteLine("MVID      : %ls",GUIDAsString(mvid, guidString, STRING_BUFFER_LEN));
812
813     hr = m_pImport->GetModuleFromScope(&mdm);
814     if (FAILED(hr)) Error("GetModuleFromScope failed.", hr);
815     DisplayPermissions(mdm, "");
816     DisplayCustomAttributes(mdm, "\t");
817 } // void MDInfo::DisplayScopeInfo()
818
819 void MDInfo::DisplayRaw()
820 {
821     int         iDump;                  // Level of info to dump.
822
823     if (m_pTables == 0)
824         m_pImport->QueryInterface(IID_IMetaDataTables, (void**)&m_pTables);
825     if (m_pTables == 0)
826         Error("Can't get table info.");
827     if (m_pTables2 == 0)
828         m_pImport->QueryInterface(IID_IMetaDataTables2, (void**)&m_pTables2);
829
830     if (m_DumpFilter & dumpCSV)
831         DumpRawCSV();
832     if (m_DumpFilter & (dumpSchema | dumpHeader | dumpRaw | dumpStats))
833     {
834         if (m_DumpFilter & dumpRaw)
835             iDump = 3;
836         else
837         if (m_DumpFilter & dumpSchema)
838             iDump = 2;
839         else
840             iDump = 1;
841         
842         DumpRaw(iDump, (m_DumpFilter & dumpStats) != 0);
843     }
844     if (m_DumpFilter & dumpRawHeaps)
845         DumpRawHeaps();
846 } // void MDInfo::DisplayRaw()
847
848 // return the name of the type of token passed in
849
850 const char *MDInfo::TokenTypeName(mdToken inToken)
851 {
852     switch(TypeFromToken(inToken))
853     {
854     case mdtTypeDef:        return "TypeDef";
855     case mdtInterfaceImpl:  return "InterfaceImpl";
856     case mdtMethodDef:      return "MethodDef";
857     case mdtFieldDef:       return "FieldDef";
858     case mdtTypeRef:        return "TypeRef";
859     case mdtMemberRef:      return "MemberRef";
860     case mdtCustomAttribute:return "CustomAttribute";
861     case mdtParamDef:       return "ParamDef";
862     case mdtProperty:       return "Property";
863     case mdtEvent:          return "Event";
864     case mdtTypeSpec:       return "TypeSpec";
865     default:                return "[UnknownTokenType]";
866     }
867 } // char *MDInfo::TokenTypeName()
868
869 // Prints out name of the given memberref
870 //
871
872 LPCWSTR MDInfo::MemberRefName(mdMemberRef inMemRef, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen)
873 {
874     HRESULT hr;
875     
876
877     hr = m_pImport->GetMemberRefProps( inMemRef, NULL, buffer, bufLen,
878                                     NULL, NULL, NULL);
879     if (FAILED(hr)) Error("GetMemberRefProps failed.", hr);
880     
881     return buffer;
882 } // LPCWSTR MDInfo::MemberRefName()
883
884
885 // Prints out information about the given memberref
886 //
887
888 void MDInfo::DisplayMemberRefInfo(mdMemberRef inMemRef, const char *preFix)
889 {
890     HRESULT hr;
891     WCHAR memRefName[STRING_BUFFER_LEN];
892     ULONG nameLen;
893     mdToken token;
894     PCCOR_SIGNATURE pbSigBlob;
895     ULONG ulSigBlob;
896     char newPreFix[STRING_BUFFER_LEN];
897
898
899     hr = m_pImport->GetMemberRefProps( inMemRef, &token, memRefName, STRING_BUFFER_LEN,
900                                     &nameLen, &pbSigBlob, &ulSigBlob);
901     if (FAILED(hr)) Error("GetMemberRefProps failed.", hr);
902     
903     VWriteLine("%s\t\tMember: (%8.8x) %ls: ", preFix, inMemRef, memRefName);
904
905     if (ulSigBlob)
906         DisplaySignature(pbSigBlob, ulSigBlob, preFix);
907     else
908         VWriteLine("%s\t\tERROR: no valid signature ", preFix);
909
910     sprintf_s (newPreFix, STRING_BUFFER_LEN, "\t\t%s", preFix);
911     DisplayCustomAttributes(inMemRef, newPreFix);
912 } // void MDInfo::DisplayMemberRefInfo()
913
914 // Prints out information about all memberrefs of the given typeref
915 //
916
917 void MDInfo::DisplayMemberRefs(mdToken tkParent, const char *preFix)
918 {
919     HCORENUM memRefEnum = NULL;
920     HRESULT hr;
921     mdMemberRef memRefs[ENUM_BUFFER_SIZE];
922     ULONG count, totalCount = 1;
923
924
925     while (SUCCEEDED(hr = m_pImport->EnumMemberRefs( &memRefEnum, tkParent,
926                              memRefs, NumItems(memRefs), &count)) && 
927             count > 0)
928     {
929         for (ULONG i = 0; i < count; i++, totalCount++)
930         {
931             VWriteLine("%s\tMemberRef #%d (%08x)", preFix, totalCount, memRefs[i]);
932             VWriteLine("%s\t-------------------------------------------------------", preFix);
933             DisplayMemberRefInfo(memRefs[i], preFix);
934         }
935     }
936     m_pImport->CloseEnum( memRefEnum);
937 } // void MDInfo::DisplayMemberRefs()
938
939 // Prints out information about all resources in the com object
940 //
941
942 // Iterates through each typeref and prints out the information of each
943 //
944
945 void MDInfo::DisplayTypeRefs()
946 {
947     HCORENUM typeRefEnum = NULL;
948     mdTypeRef typeRefs[ENUM_BUFFER_SIZE];
949     ULONG count, totalCount=1;
950     HRESULT hr;
951     
952     while (SUCCEEDED(hr = m_pImport->EnumTypeRefs( &typeRefEnum,
953                              typeRefs, NumItems(typeRefs), &count)) &&
954             count > 0)
955     {
956         for (ULONG i = 0; i < count; i++, totalCount++)
957         {
958             VWriteLine("TypeRef #%d (%08x)", totalCount, typeRefs[i]);
959             WriteLine("-------------------------------------------------------");
960             DisplayTypeRefInfo(typeRefs[i]);
961             DisplayMemberRefs(typeRefs[i], "");
962             WriteLine("");
963         }
964     }
965     m_pImport->CloseEnum( typeRefEnum);
966 } // void MDInfo::DisplayTypeRefs()
967
968 void MDInfo::DisplayTypeSpecs()
969 {
970     HCORENUM typespecEnum = NULL;
971     mdTypeSpec typespecs[ENUM_BUFFER_SIZE];
972     ULONG count, totalCount=1;
973     HRESULT hr;
974     
975     while (SUCCEEDED(hr = m_pImport->EnumTypeSpecs( &typespecEnum,
976                              typespecs, NumItems(typespecs), &count)) &&
977             count > 0)
978     {
979         for (ULONG i = 0; i < count; i++, totalCount++)
980         {
981             VWriteLine("TypeSpec #%d (%08x)", totalCount, typespecs[i]);
982             WriteLine("-------------------------------------------------------");
983             DisplayTypeSpecInfo(typespecs[i], "");
984             DisplayMemberRefs(typespecs[i], "");
985             WriteLine("");
986         }
987     }
988     m_pImport->CloseEnum( typespecEnum);
989 } // void MDInfo::DisplayTypeSpecs()
990
991 void MDInfo::DisplayMethodSpecs()
992 {
993     HCORENUM MethodSpecEnum = NULL;
994     mdMethodSpec MethodSpecs[ENUM_BUFFER_SIZE];
995     ULONG count, totalCount=1;
996 /////    HRESULT hr;
997     
998
999 /////  HACK until I implement EnumMethodSpecs!
1000 ///// while (SUCCEEDED(hr = m_pImport->EnumMethodSpecs( &MethodSpecEnum,
1001 /////                          MethodSpecs, NumItems(MethodSpecs), &count)) &&
1002 /////         count > 0)
1003     for (ULONG rid=1; m_pImport->IsValidToken(TokenFromRid(rid, mdtMethodSpec)); ++rid)
1004     {
1005 // More hackery
1006 count = 1;
1007 MethodSpecs[0] = TokenFromRid(rid, mdtMethodSpec);
1008 // More hackery
1009         for (ULONG i = 0; i < count; i++, totalCount++)
1010         {
1011             VWriteLine("MethodSpec #%d (%08x)", totalCount, MethodSpecs[i]);
1012             DisplayMethodSpecInfo(MethodSpecs[i], "");
1013             WriteLine("");
1014         }
1015     }
1016     m_pImport->CloseEnum( MethodSpecEnum);
1017 } // void MDInfo::DisplayMethodSpecs()
1018
1019
1020
1021 // Called to display the information about all typedefs in the object.
1022 //
1023
1024 void MDInfo::DisplayTypeDefs()
1025 {
1026     HCORENUM typeDefEnum = NULL;
1027     mdTypeDef typeDefs[ENUM_BUFFER_SIZE];
1028     ULONG count, totalCount = 1;
1029     HRESULT hr;
1030     
1031     while (SUCCEEDED(hr = m_pImport->EnumTypeDefs( &typeDefEnum,
1032                              typeDefs, NumItems(typeDefs), &count)) &&
1033             count > 0)
1034     {
1035         for (ULONG i = 0; i < count; i++, totalCount++)
1036         {
1037             VWriteLine("TypeDef #%d (%08x)", totalCount, typeDefs[i]);
1038             WriteLine("-------------------------------------------------------");
1039             DisplayTypeDefInfo(typeDefs[i]);
1040             WriteLine("");
1041         }
1042     }
1043     m_pImport->CloseEnum( typeDefEnum);
1044 } // void MDInfo::DisplayTypeDefs()
1045
1046 // Called to display the information about all modulerefs in the object.
1047 //
1048
1049 void MDInfo::DisplayModuleRefs()
1050 {
1051     HCORENUM moduleRefEnum = NULL;
1052     mdModuleRef moduleRefs[ENUM_BUFFER_SIZE];
1053     ULONG count, totalCount = 1;
1054     HRESULT hr;
1055     
1056     while (SUCCEEDED(hr = m_pImport->EnumModuleRefs( &moduleRefEnum,
1057                              moduleRefs, NumItems(moduleRefs), &count)) &&
1058             count > 0)
1059     {
1060         for (ULONG i = 0; i < count; i++, totalCount++)
1061         {
1062             VWriteLine("ModuleRef #%d (%08x)", totalCount, moduleRefs[i]);
1063             WriteLine("-------------------------------------------------------");
1064             DisplayModuleRefInfo(moduleRefs[i]);
1065             DisplayMemberRefs(moduleRefs[i], "");
1066             WriteLine("");
1067         }
1068     }
1069     m_pImport->CloseEnum( moduleRefEnum);
1070 } // void MDInfo::DisplayModuleRefs()
1071
1072 // Prints out information about the given moduleref
1073 //
1074
1075 void MDInfo::DisplayModuleRefInfo(mdModuleRef inModuleRef)
1076 {
1077     HRESULT hr;
1078     WCHAR moduleRefName[STRING_BUFFER_LEN];
1079     ULONG nameLen;
1080
1081
1082     hr = m_pImport->GetModuleRefProps( inModuleRef, moduleRefName, STRING_BUFFER_LEN,
1083                                     &nameLen);
1084     if (FAILED(hr)) Error("GetModuleRefProps failed.", hr);
1085     
1086     VWriteLine("\t\tModuleRef: (%8.8x) %ls: ", inModuleRef, moduleRefName);
1087     DisplayCustomAttributes(inModuleRef, "\t\t");
1088 } // void MDInfo::DisplayModuleRefInfo()
1089
1090
1091 // Called to display the information about all signatures in the object.
1092 //
1093
1094 void MDInfo::DisplaySignatures()
1095 {
1096     HCORENUM signatureEnum = NULL;
1097     mdSignature signatures[ENUM_BUFFER_SIZE];
1098     ULONG count, totalCount = 1;
1099     HRESULT hr;
1100     
1101     while (SUCCEEDED(hr = m_pImport->EnumSignatures( &signatureEnum,
1102                              signatures, NumItems(signatures), &count)) &&
1103             count > 0)
1104     {
1105         for (ULONG i = 0; i < count; i++, totalCount++)
1106         {
1107             VWriteLine("Signature #%d (%#08x)", totalCount, signatures[i]);
1108             WriteLine("-------------------------------------------------------");
1109             DisplaySignatureInfo(signatures[i]);
1110             WriteLine("");
1111         }
1112     }
1113     m_pImport->CloseEnum( signatureEnum);
1114 } // void MDInfo::DisplaySignatures()
1115
1116
1117 // Prints out information about the given signature
1118 //
1119
1120 void MDInfo::DisplaySignatureInfo(mdSignature inSignature)
1121 {
1122     HRESULT hr;
1123     PCCOR_SIGNATURE pbSigBlob;
1124     ULONG   ulSigBlob;
1125
1126
1127     hr = m_pImport->GetSigFromToken( inSignature, &pbSigBlob, &ulSigBlob );
1128     if (FAILED(hr)) Error("GetSigFromToken failed.", hr);
1129     if(ulSigBlob)
1130         DisplaySignature(pbSigBlob, ulSigBlob, "");
1131     else
1132         VWriteLine("\t\tERROR: no valid signature ");
1133 } // void MDInfo::DisplaySignatureInfo()
1134
1135
1136 // returns the passed-in buffer which is filled with the name of the given 
1137 // member in wide characters
1138 //
1139
1140 LPCWSTR MDInfo::MemberName(mdToken inToken, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen)
1141 {
1142     HRESULT hr;
1143     
1144
1145     hr = m_pImport->GetMemberProps( inToken, NULL, buffer, bufLen,
1146                             NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1147     if (FAILED(hr)) Error("GetMemberProps failed.", hr);
1148
1149     return (buffer);
1150 } // LPCWSTR MDInfo::MemberName()
1151
1152
1153 // displays information for the given method
1154 //
1155
1156 void MDInfo::DisplayMethodInfo(mdMethodDef inMethod, DWORD *pflags)
1157 {
1158     HRESULT hr;
1159     mdTypeDef memTypeDef;
1160     WCHAR memberName[STRING_BUFFER_LEN];
1161     ULONG nameLen;
1162     DWORD flags;
1163     PCCOR_SIGNATURE pbSigBlob;
1164     ULONG ulSigBlob;
1165     ULONG ulCodeRVA;
1166     ULONG ulImplFlags;
1167
1168
1169     hr = m_pImport->GetMethodProps( inMethod, &memTypeDef, memberName, STRING_BUFFER_LEN,
1170                             &nameLen, &flags, &pbSigBlob, &ulSigBlob, &ulCodeRVA, &ulImplFlags);
1171     if (FAILED(hr)) Error("GetMethodProps failed.", hr);
1172     if (pflags)
1173         *pflags = flags;
1174
1175     VWriteLine("\t\tMethodName: %ls (%8.8X)", memberName, inMethod);
1176
1177     char sFlags[STRING_BUFFER_LEN];
1178
1179     sFlags[0] = 0;
1180     ISFLAG(Md, Public);     
1181     ISFLAG(Md, Private);        
1182     ISFLAG(Md, Family);     
1183     ISFLAG(Md, Assem);      
1184     ISFLAG(Md, FamANDAssem);    
1185     ISFLAG(Md, FamORAssem); 
1186     ISFLAG(Md, PrivateScope);   
1187     ISFLAG(Md, Static);     
1188     ISFLAG(Md, Final);      
1189     ISFLAG(Md, Virtual);        
1190     ISFLAG(Md, HideBySig);  
1191     ISFLAG(Md, ReuseSlot);  
1192     ISFLAG(Md, NewSlot);        
1193     ISFLAG(Md, Abstract);       
1194     ISFLAG(Md, SpecialName);    
1195     ISFLAG(Md, RTSpecialName);
1196     ISFLAG(Md, PinvokeImpl);
1197     ISFLAG(Md, UnmanagedExport);
1198     if (!*sFlags)
1199         strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]");
1200
1201     bool result = (((flags) & mdRTSpecialName) && !wcscmp((memberName), W(".ctor")));
1202     if (result) strcat_s(sFlags, STRING_BUFFER_LEN, "[.ctor] ");
1203     result = (((flags) & mdRTSpecialName) && !wcscmp((memberName), W(".cctor")));
1204     if (result) strcat_s(sFlags,STRING_BUFFER_LEN, "[.cctor] ");
1205     // "Reserved" flags
1206     ISFLAG(Md, HasSecurity);
1207     ISFLAG(Md, RequireSecObject);
1208
1209     VWriteLine("\t\tFlags     : %s (%08x)", sFlags, flags);
1210     VWriteLine("\t\tRVA       : 0x%08x", ulCodeRVA);
1211
1212     flags = ulImplFlags;
1213     sFlags[0] = 0;
1214     ISFLAG(Mi, Native);     
1215     ISFLAG(Mi, IL);         
1216     ISFLAG(Mi, OPTIL);      
1217     ISFLAG(Mi, Runtime);        
1218     ISFLAG(Mi, Unmanaged);  
1219     ISFLAG(Mi, Managed);        
1220     ISFLAG(Mi, ForwardRef);
1221     ISFLAG(Mi, PreserveSig);            
1222     ISFLAG(Mi, InternalCall);
1223     ISFLAG(Mi, Synchronized);
1224     ISFLAG(Mi, NoInlining);    
1225     if (!*sFlags)
1226         strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]");
1227
1228     VWriteLine("\t\tImplFlags : %s (%08x)", sFlags, flags);
1229
1230     if (ulSigBlob)
1231         DisplaySignature(pbSigBlob, ulSigBlob, "");
1232     else
1233         VWriteLine("\t\tERROR: no valid signature ");
1234     
1235     DisplayGenericParams(inMethod, "\t\t");
1236
1237 } // void MDInfo::DisplayMethodInfo()
1238
1239 // displays the member information for the given field
1240 //
1241
1242 void MDInfo::DisplayFieldInfo(mdFieldDef inField, DWORD *pdwFlags)
1243 {
1244     HRESULT hr;
1245     mdTypeDef memTypeDef;
1246     WCHAR memberName[STRING_BUFFER_LEN];
1247     ULONG nameLen;
1248     DWORD flags;
1249     PCCOR_SIGNATURE pbSigBlob;
1250     ULONG ulSigBlob;
1251     DWORD dwCPlusTypeFlag;
1252     void const *pValue;
1253     ULONG cbValue;
1254 #ifdef FEATURE_COMINTEROP
1255     VARIANT defaultValue;
1256
1257     ::VariantInit(&defaultValue);
1258 #endif
1259     hr = m_pImport->GetFieldProps( inField, &memTypeDef, memberName, STRING_BUFFER_LEN,
1260                             &nameLen, &flags, &pbSigBlob, &ulSigBlob, &dwCPlusTypeFlag,
1261                             &pValue, &cbValue);
1262     if (FAILED(hr)) Error("GetFieldProps failed.", hr);
1263
1264     if (pdwFlags)
1265         *pdwFlags = flags;
1266
1267 #ifdef FEATURE_COMINTEROP
1268     _FillVariant((BYTE)dwCPlusTypeFlag, pValue, cbValue, &defaultValue);
1269 #endif
1270
1271     char sFlags[STRING_BUFFER_LEN];
1272
1273     sFlags[0] = 0;
1274     ISFLAG(Fd, Public);     
1275     ISFLAG(Fd, Private);        
1276     ISFLAG(Fd, Family);     
1277     ISFLAG(Fd, Assembly);       
1278     ISFLAG(Fd, FamANDAssem);    
1279     ISFLAG(Fd, FamORAssem); 
1280     ISFLAG(Fd, PrivateScope);   
1281     ISFLAG(Fd, Static);     
1282     ISFLAG(Fd, InitOnly);       
1283     ISFLAG(Fd, Literal);        
1284     ISFLAG(Fd, NotSerialized);
1285     ISFLAG(Fd, SpecialName);
1286     ISFLAG(Fd, RTSpecialName);
1287     ISFLAG(Fd, PinvokeImpl);    
1288     // "Reserved" flags
1289     ISFLAG(Fd, HasDefault);
1290     if (!*sFlags)
1291         strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]");
1292
1293     VWriteLine("\t\tField Name: %ls (%8.8X)", memberName, inField);
1294     VWriteLine("\t\tFlags     : %s (%08x)", sFlags, flags);
1295 #ifdef FEATURE_COMINTEROP
1296     if (IsFdHasDefault(flags))
1297         VWriteLine("\tDefltValue: (%s) %ls", g_szMapElementType[dwCPlusTypeFlag], VariantAsString(&defaultValue));
1298 #endif
1299     if (!ulSigBlob) // Signature size should be non-zero for fields
1300         VWriteLine("\t\tERROR: no valid signature ");
1301     else
1302         DisplaySignature(pbSigBlob, ulSigBlob, "");
1303 #ifdef FEATURE_COMINTEROP
1304     ::VariantClear(&defaultValue);
1305 #endif
1306 } // void MDInfo::DisplayFieldInfo()
1307
1308 // displays the RVA for the given global field.
1309 void MDInfo::DisplayFieldRVA(mdFieldDef inFieldDef)
1310 {
1311     HRESULT hr;
1312     ULONG   ulRVA;
1313
1314     hr = m_pImport->GetRVA(inFieldDef, &ulRVA, 0);
1315     if (FAILED(hr) && hr != CLDB_E_RECORD_NOTFOUND) Error("GetRVA failed.", hr);
1316
1317     VWriteLine("\t\tRVA       : 0x%08x", ulRVA);
1318 } // void MDInfo::DisplayFieldRVA()
1319
1320 // displays information about every global function.
1321 void MDInfo::DisplayGlobalFunctions()
1322 {
1323     WriteLine("Global functions");
1324     WriteLine("-------------------------------------------------------");
1325     DisplayMethods(mdTokenNil);
1326     WriteLine("");
1327 } // void MDInfo::DisplayGlobalFunctions()
1328
1329 // displays information about every global field.
1330 void MDInfo::DisplayGlobalFields()
1331 {
1332     WriteLine("Global fields");
1333     WriteLine("-------------------------------------------------------");
1334     DisplayFields(mdTokenNil, NULL, 0);
1335     WriteLine("");
1336 } // void MDInfo::DisplayGlobalFields()
1337
1338 // displays information about every global memberref.
1339 void MDInfo::DisplayGlobalMemberRefs()
1340 {
1341     WriteLine("Global MemberRefs");
1342     WriteLine("-------------------------------------------------------");
1343     DisplayMemberRefs(mdTokenNil, "");
1344     WriteLine("");
1345 } // void MDInfo::DisplayGlobalMemberRefs()
1346
1347 // displays information about every method in a given typedef
1348 //
1349
1350 void MDInfo::DisplayMethods(mdTypeDef inTypeDef)
1351 {
1352     HCORENUM methodEnum = NULL;
1353     mdToken methods[ENUM_BUFFER_SIZE];
1354     DWORD flags;
1355     ULONG count, totalCount = 1;
1356     HRESULT hr;
1357     
1358
1359     while (SUCCEEDED(hr = m_pImport->EnumMethods( &methodEnum, inTypeDef,
1360                              methods, NumItems(methods), &count)) &&
1361             count > 0)
1362     {
1363         for (ULONG i = 0; i < count; i++, totalCount++)
1364         {
1365             VWriteLine("\tMethod #%d (%08x) %s", totalCount, methods[i], (methods[i] == g_tkEntryPoint) ? "[ENTRYPOINT]" : "");
1366             WriteLine("\t-------------------------------------------------------");
1367             DisplayMethodInfo(methods[i], &flags);
1368             DisplayParams(methods[i]);
1369             DisplayCustomAttributes(methods[i], "\t\t");
1370             DisplayPermissions(methods[i], "\t");
1371             DisplayMemberRefs(methods[i], "\t");
1372
1373             // P-invoke data if present.
1374             if (IsMdPinvokeImpl(flags))
1375                 DisplayPinvokeInfo(methods[i]);
1376
1377             WriteLine("");
1378         }
1379     }
1380     m_pImport->CloseEnum( methodEnum);
1381 } // void MDInfo::DisplayMethods()
1382
1383
1384 // displays information about every field in a given typedef
1385 //
1386
1387 void MDInfo::DisplayFields(mdTypeDef inTypeDef, COR_FIELD_OFFSET *rFieldOffset, ULONG cFieldOffset)
1388 {
1389     HCORENUM fieldEnum = NULL;
1390     mdToken fields[ENUM_BUFFER_SIZE];
1391     ULONG count, totalCount = 1;
1392     DWORD flags;
1393     HRESULT hr;
1394     
1395
1396     while (SUCCEEDED(hr = m_pImport->EnumFields( &fieldEnum, inTypeDef,
1397                              fields, NumItems(fields), &count)) &&
1398             count > 0)
1399     {
1400         for (ULONG i = 0; i < count; i++, totalCount++)
1401         {
1402             VWriteLine("\tField #%d (%08x)",totalCount, fields[i]);
1403             WriteLine("\t-------------------------------------------------------");
1404             DisplayFieldInfo(fields[i], &flags);
1405             DisplayCustomAttributes(fields[i], "\t\t");
1406             DisplayPermissions(fields[i], "\t");
1407             DisplayFieldMarshal(fields[i]);
1408
1409             // RVA if its a global field.
1410             if (inTypeDef == mdTokenNil)
1411                 DisplayFieldRVA(fields[i]);
1412
1413             // P-invoke data if present.
1414             if (IsFdPinvokeImpl(flags))
1415                 DisplayPinvokeInfo(fields[i]);
1416
1417             // Display offset if present.
1418             if (cFieldOffset)
1419             {
1420                 bool found = false;
1421                 for (ULONG iLayout = 0; i < cFieldOffset; ++iLayout)
1422                 {
1423                     if (RidFromToken(rFieldOffset[iLayout].ridOfField) == RidFromToken(fields[i]))
1424                     {
1425                         found = true;
1426                         VWriteLine("\t\tOffset : 0x%08x", rFieldOffset[iLayout].ulOffset);
1427                         break;
1428                     }
1429                 }
1430                 _ASSERTE(found);
1431             }
1432             WriteLine("");
1433         }
1434     }
1435     m_pImport->CloseEnum( fieldEnum);
1436 } // void MDInfo::DisplayFields()
1437
1438
1439 // displays information about every methodImpl in a given typedef
1440 //
1441
1442 void MDInfo::DisplayMethodImpls(mdTypeDef inTypeDef)
1443 {
1444     HCORENUM methodImplEnum = NULL;
1445     mdMethodDef rtkMethodBody[ENUM_BUFFER_SIZE];
1446     mdMethodDef rtkMethodDecl[ENUM_BUFFER_SIZE];
1447
1448     ULONG count, totalCount=1;
1449     HRESULT hr;
1450
1451
1452     while (SUCCEEDED(hr = m_pImport->EnumMethodImpls( &methodImplEnum, inTypeDef,
1453                              rtkMethodBody, rtkMethodDecl, NumItems(rtkMethodBody), &count)) &&
1454             count > 0)
1455     {
1456         for (ULONG i = 0; i < count; i++, totalCount++)
1457         {
1458             VWriteLine("\n\tMethodImpl #%d (%08x)", totalCount, totalCount);
1459             WriteLine("\t-------------------------------------------------------");
1460             VWriteLine("\t\tMethod Body Token : 0x%08x", rtkMethodBody[i]);
1461             VWriteLine("\t\tMethod Declaration Token : 0x%08x", rtkMethodDecl[i]);
1462             WriteLine("");
1463         }
1464     }
1465     m_pImport->CloseEnum( methodImplEnum);
1466 } // void MDInfo::DisplayMethodImpls()
1467
1468 // displays information about the given parameter
1469 //
1470
1471 void MDInfo::DisplayParamInfo(mdParamDef inParamDef)
1472 {
1473     mdMethodDef md;
1474     ULONG num;
1475     WCHAR paramName[STRING_BUFFER_LEN];
1476     ULONG nameLen;
1477     DWORD flags;
1478     VARIANT defValue;
1479     DWORD dwCPlusFlags;
1480     void const *pValue;
1481     ULONG cbValue;
1482
1483 #ifdef FEATURE_COMINTEROP
1484     ::VariantInit(&defValue);
1485 #endif
1486     HRESULT hr = m_pImport->GetParamProps( inParamDef, &md, &num, paramName, NumItems(paramName),
1487                             &nameLen, &flags, &dwCPlusFlags, &pValue, &cbValue);
1488     if (FAILED(hr)) Error("GetParamProps failed.", hr);
1489     
1490     _FillVariant((BYTE)dwCPlusFlags, pValue, cbValue, &defValue);
1491     
1492     char sFlags[STRING_BUFFER_LEN];
1493     sFlags[0] = 0;
1494     ISFLAG(Pd, In);     
1495     ISFLAG(Pd, Out);        
1496     ISFLAG(Pd, Optional);
1497     // "Reserved" flags.
1498     ISFLAG(Pd, HasDefault); 
1499     ISFLAG(Pd, HasFieldMarshal);    
1500     if (!*sFlags)
1501         strcpy_s(sFlags,STRING_BUFFER_LEN, "[none]");
1502
1503     VWrite("\t\t\t(%ld) ParamToken : (%08x) Name : %ls flags: %s (%08x)", num, inParamDef, paramName, sFlags, flags);
1504 #ifdef FEATURE_COMINTEROP
1505     if (IsPdHasDefault(flags))
1506         VWriteLine(" Default: (%s) %ls", g_szMapElementType[dwCPlusFlags], VariantAsString(&defValue));
1507     else
1508 #endif
1509         VWriteLine("");
1510     DisplayCustomAttributes(inParamDef, "\t\t\t");
1511
1512 #ifdef FEATURE_COMINTEROP
1513     ::VariantClear(&defValue);
1514 #endif
1515 } // void MDInfo::DisplayParamInfo()
1516
1517
1518 // displays all parameters for a given memberdef
1519 //
1520
1521 void MDInfo::DisplayParams(mdMethodDef inMethodDef)
1522 {
1523     HCORENUM paramEnum = NULL;
1524     mdParamDef params[ENUM_BUFFER_SIZE];
1525     ULONG count, paramCount;
1526     bool first = true;
1527     HRESULT hr;
1528
1529   
1530     while (SUCCEEDED(hr = m_pImport->EnumParams( &paramEnum, inMethodDef,
1531                              params, NumItems(params), &count)) &&
1532             count > 0)
1533     {
1534         if (first)
1535         {
1536             m_pImport->CountEnum( paramEnum, &paramCount);
1537             VWriteLine("\t\t%d Parameters", paramCount);
1538         }
1539         for (ULONG i = 0; i < count; i++)
1540         {
1541             DisplayParamInfo(params[i]);
1542             DisplayFieldMarshal(params[i]);
1543         }
1544         first = false;
1545     }
1546     m_pImport->CloseEnum( paramEnum);
1547 } // void MDInfo::DisplayParams()
1548
1549 void MDInfo::DisplayGenericParams(mdToken tk, const char *prefix)
1550 {
1551     HCORENUM paramEnum = NULL;
1552     mdParamDef params[ENUM_BUFFER_SIZE];
1553     ULONG count, paramCount;
1554     bool first = true;
1555     HRESULT hr;
1556
1557   
1558     while (SUCCEEDED(hr = m_pImport->EnumGenericParams( &paramEnum, tk,
1559                              params, NumItems(params), &count)) &&
1560             count > 0)
1561     {
1562         if (first)
1563         {
1564             m_pImport->CountEnum( paramEnum, &paramCount);
1565             VWriteLine("%s%d Generic Parameters", prefix, paramCount);
1566         }
1567         for (ULONG i = 0; i < count; i++)
1568         {
1569             DisplayGenericParamInfo(params[i], prefix);
1570         }
1571         first = false;
1572     }
1573     m_pImport->CloseEnum( paramEnum);
1574 }
1575
1576 void MDInfo::DisplayGenericParamInfo(mdGenericParam tkParam, const char *prefix)
1577 {
1578     ULONG ulSeq;
1579     WCHAR paramName[STRING_BUFFER_LEN];
1580     ULONG nameLen;
1581     DWORD flags;
1582     mdToken tkOwner;
1583     char newprefix[30];
1584     HCORENUM constraintEnum = NULL;
1585     mdParamDef constraints[4];
1586     ULONG count, constraintCount;
1587     mdToken constraint;
1588     mdToken owner;
1589     bool first = true;
1590
1591     HRESULT hr = m_pImport->GetGenericParamProps(tkParam, &ulSeq, &flags, &tkOwner, NULL, paramName, NumItems(paramName), &nameLen);
1592     if (FAILED(hr)) Error("GetGenericParamProps failed.", hr);
1593     
1594     VWriteLine("%s\t(%ld) GenericParamToken : (%08x) Name : %ls flags: %08x Owner: %08x", prefix, ulSeq, tkParam, paramName, flags, tkOwner);
1595
1596     // Any constraints for the GenericParam
1597     while (SUCCEEDED(hr = m_pImport->EnumGenericParamConstraints(&constraintEnum, tkParam, 
1598                 constraints, NumItems(constraints), &count)) &&
1599            count > 0)
1600     {
1601         if (first)
1602         {
1603             m_pImport->CountEnum( constraintEnum, &constraintCount);
1604             VWriteLine("%s\t\t%d Constraint(s)", prefix, constraintCount);
1605         }
1606         VWrite("%s\t\t", prefix);
1607         for (ULONG i=0; i< count; ++i)
1608         {
1609             hr = m_pImport->GetGenericParamConstraintProps(constraints[i], &owner, &constraint);
1610             if (owner != tkParam)
1611                 VWrite("%08x (owner: %08x)  ", constraint, owner);
1612             else
1613                 VWrite("%08x  ", constraint);
1614         }
1615         VWriteLine("");
1616     }
1617     m_pImport->CloseEnum(constraintEnum);
1618
1619     sprintf_s(newprefix, 30, "%s\t", prefix);
1620     DisplayCustomAttributes(tkParam, newprefix);
1621 }
1622
1623 LPCWSTR MDInfo::TokenName(mdToken inToken, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen)
1624 {
1625     LPCUTF8     pName;                  // Token name in UTF8.
1626
1627     if (IsNilToken(inToken))
1628         return W("");
1629
1630     m_pImport->GetNameFromToken(inToken, &pName);
1631
1632     WszMultiByteToWideChar(CP_UTF8,0, pName,-1, buffer,bufLen);
1633
1634     return buffer;
1635 } // LPCWSTR MDInfo::TokenName()
1636
1637 // prints out name of typeref or typedef
1638 //
1639
1640 LPCWSTR MDInfo::TypeDeforRefName(mdToken inToken, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen)
1641 {
1642     if (RidFromToken(inToken))
1643     {
1644         if (TypeFromToken(inToken) == mdtTypeDef)
1645             return (TypeDefName((mdTypeDef) inToken, buffer, bufLen));
1646         else if (TypeFromToken(inToken) == mdtTypeRef)
1647             return (TypeRefName((mdTypeRef) inToken, buffer, bufLen));
1648         else if (TypeFromToken(inToken) == mdtTypeSpec)
1649             return W("[TypeSpec]");
1650         else
1651             return W("[InvalidReference]");
1652     }
1653     else
1654         return W("");
1655 } // LPCWSTR MDInfo::TypeDeforRefName()
1656
1657 LPCWSTR MDInfo::MemberDeforRefName(mdToken inToken, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen)
1658 {
1659     if (RidFromToken(inToken))
1660     {
1661         if (TypeFromToken(inToken) == mdtMethodDef || TypeFromToken(inToken) == mdtFieldDef)
1662             return (MemberName(inToken, buffer, bufLen));
1663         else if (TypeFromToken(inToken) == mdtMemberRef)
1664             return (MemberRefName((mdMemberRef) inToken, buffer, bufLen));
1665         else
1666             return W("[InvalidReference]");
1667     }
1668     else
1669         return W("");
1670 } // LPCWSTR MDInfo::MemberDeforRefName()
1671
1672 // prints out only the name of the given typedef
1673 //
1674 // 
1675
1676 LPCWSTR MDInfo::TypeDefName(mdTypeDef inTypeDef, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen)
1677 {
1678     HRESULT hr;
1679
1680     hr = m_pImport->GetTypeDefProps(
1681                             // [IN] The import scope.
1682         inTypeDef,              // [IN] TypeDef token for inquiry.
1683         buffer,                 // [OUT] Put name here.
1684         bufLen,                 // [IN] size of name buffer in wide chars.
1685         NULL,                   // [OUT] put size of name (wide chars) here.
1686         NULL,                   // [OUT] Put flags here.
1687         NULL);                  // [OUT] Put base class TypeDef/TypeRef here.
1688     if (FAILED(hr))
1689     {
1690         swprintf_s(buffer, bufLen, W("[Invalid TypeDef]"));
1691     }
1692
1693     return buffer;
1694 } // LPCWSTR MDInfo::TypeDefName()
1695
1696 // prints out all the properties of a given typedef
1697 //
1698
1699 void MDInfo::DisplayTypeDefProps(mdTypeDef inTypeDef)
1700 {
1701     HRESULT hr;
1702     WCHAR typeDefName[STRING_BUFFER_LEN];
1703     ULONG nameLen;
1704     DWORD flags;
1705     mdToken extends;
1706     ULONG       dwPacking;              // Packing size of class, if specified.
1707     ULONG       dwSize;                 // Total size of class, if specified.
1708
1709     hr = m_pImport->GetTypeDefProps(
1710         inTypeDef,              // [IN] TypeDef token for inquiry.
1711         typeDefName,            // [OUT] Put name here.
1712         STRING_BUFFER_LEN,      // [IN] size of name buffer in wide chars.
1713         &nameLen,               // [OUT] put size of name (wide chars) here.
1714         &flags,                 // [OUT] Put flags here.
1715         &extends);              // [OUT] Put base class TypeDef/TypeRef here.
1716     if (FAILED(hr)) Error("GetTypeDefProps failed.", hr);
1717
1718     char sFlags[STRING_BUFFER_LEN];
1719     WCHAR szTempBuf[STRING_BUFFER_LEN];
1720
1721     VWriteLine("\tTypDefName: %ls  (%8.8X)",typeDefName,inTypeDef);
1722     VWriteLine("\tFlags     : %s (%08x)",ClassFlags(flags, sFlags), flags);
1723     VWriteLine("\tExtends   : %8.8X [%s] %ls",extends,TokenTypeName(extends),
1724                                  TypeDeforRefName(extends, szTempBuf, NumItems(szTempBuf)));
1725
1726     hr = m_pImport->GetClassLayout(inTypeDef, &dwPacking, 0,0,0, &dwSize);
1727     if (hr == S_OK)
1728         VWriteLine("\tLayout    : Packing:%d, Size:%d", dwPacking, dwSize);
1729
1730     if (IsTdNested(flags))
1731     {
1732         mdTypeDef   tkEnclosingClass;
1733
1734         hr = m_pImport->GetNestedClassProps(inTypeDef, &tkEnclosingClass);
1735         if (hr == S_OK)
1736         {
1737             VWriteLine("\tEnclosingClass : %ls (%8.8X)", TypeDeforRefName(tkEnclosingClass,
1738                                             szTempBuf, NumItems(szTempBuf)), tkEnclosingClass);
1739         }
1740         else if (hr == CLDB_E_RECORD_NOTFOUND)
1741             WriteLine("ERROR: EnclosingClass not found for NestedClass");
1742         else
1743             Error("GetNestedClassProps failed.", hr);
1744     }
1745 } // void MDInfo::DisplayTypeDefProps()
1746
1747 //  Prints out the name of the given TypeRef
1748 //
1749
1750 LPCWSTR MDInfo::TypeRefName(mdTypeRef tr, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen)
1751 {
1752     HRESULT hr;
1753     
1754     hr = m_pImport->GetTypeRefProps(           
1755         tr,                 // The class ref token.
1756         NULL,               // Resolution scope.
1757         buffer,             // Put the name here.
1758         bufLen,             // Size of the name buffer, wide chars.
1759         NULL);              // Put actual size of name here.
1760     if (FAILED(hr))
1761     {
1762         swprintf_s(buffer, bufLen, W("[Invalid TypeRef]"));
1763     }
1764
1765     return (buffer);
1766 } // LPCWSTR MDInfo::TypeRefName()
1767
1768 // Prints out all the info of the given TypeRef
1769 //
1770
1771 void MDInfo::DisplayTypeRefInfo(mdTypeRef tr)
1772 {
1773     HRESULT hr;
1774     mdToken tkResolutionScope;
1775     WCHAR typeRefName[STRING_BUFFER_LEN];
1776     ULONG nameLen;
1777
1778     hr = m_pImport->GetTypeRefProps(           
1779         tr,                 // The class ref token.
1780         &tkResolutionScope, // ResolutionScope.
1781         typeRefName,        // Put the name here.
1782         STRING_BUFFER_LEN,  // Size of the name buffer, wide chars.
1783         &nameLen);          // Put actual size of name here.
1784
1785     if (FAILED(hr)) Error("GetTypeRefProps failed.", hr);
1786
1787     VWriteLine("Token:             0x%08x", tr);
1788     VWriteLine("ResolutionScope:   0x%08x", tkResolutionScope);
1789     VWriteLine("TypeRefName:       %ls",typeRefName);
1790
1791     DisplayCustomAttributes(tr, "\t");
1792 } // void MDInfo::DisplayTypeRefInfo()
1793
1794
1795 void MDInfo::DisplayTypeSpecInfo(mdTypeSpec ts, const char *preFix)
1796 {
1797     HRESULT hr;
1798     PCCOR_SIGNATURE pvSig;
1799     ULONG           cbSig;
1800     ULONG           cb;
1801
1802     InitSigBuffer();
1803
1804     hr = m_pImport->GetTypeSpecFromToken(           
1805         ts,             // The class ref token.
1806         &pvSig,
1807         &cbSig);
1808
1809     if (FAILED(hr)) Error("GetTypeSpecFromToken failed.", hr);
1810
1811 //    DisplaySignature(pvSig, cbSig, preFix);
1812
1813     if (FAILED(hr = GetOneElementType(pvSig, cbSig, &cb)))
1814         goto ErrExit;
1815
1816     VWriteLine("%s\tTypeSpec :%s", preFix, (LPSTR)m_sigBuf.Ptr());
1817     
1818     // Hex, too?
1819     if (m_DumpFilter & dumpMoreHex)
1820     {
1821         char rcNewPrefix[80];
1822         sprintf_s(rcNewPrefix, 80, "%s\tSignature", preFix);
1823         DumpHex(rcNewPrefix, pvSig, cbSig, false, 24);
1824     }
1825 ErrExit:
1826     return;
1827 } // void MDInfo::DisplayTypeSpecInfo()
1828
1829 void MDInfo::DisplayMethodSpecInfo(mdMethodSpec ms, const char *preFix)
1830 {
1831     HRESULT hr;
1832     PCCOR_SIGNATURE pvSig;
1833     ULONG           cbSig;
1834     mdToken         tk;
1835
1836     InitSigBuffer();
1837
1838     hr = m_pImport->GetMethodSpecProps(
1839         ms,             // The MethodSpec token
1840         &tk,            // The MethodDef or MemberRef
1841         &pvSig,         // Signature.
1842         &cbSig);        // Size of signature.
1843
1844     VWriteLine("%s\tParent   : 0x%08x", preFix, tk);
1845     DisplaySignature(pvSig, cbSig, preFix);
1846 //ErrExit:
1847     return;
1848 } // void MDInfo::DisplayMethodSpecInfo()
1849
1850 // Return the passed-in buffer filled with a string detailing the class flags 
1851 // associated with the class.
1852 //
1853
1854 char *MDInfo::ClassFlags(DWORD flags, __out_ecount(STRING_BUFFER_LEN) char *sFlags)
1855 {
1856     sFlags[0] = 0;
1857     ISFLAG(Td, NotPublic);
1858     ISFLAG(Td, Public);
1859     ISFLAG(Td, NestedPublic);
1860     ISFLAG(Td, NestedPrivate);
1861     ISFLAG(Td, NestedFamily);
1862     ISFLAG(Td, NestedAssembly);
1863     ISFLAG(Td, NestedFamANDAssem);
1864     ISFLAG(Td, NestedFamORAssem);
1865     ISFLAG(Td, AutoLayout);     
1866     ISFLAG(Td, SequentialLayout);   
1867     ISFLAG(Td, ExplicitLayout); 
1868     ISFLAG(Td, Class);          
1869     ISFLAG(Td, Interface);      
1870     ISFLAG(Td, Abstract);           
1871     ISFLAG(Td, Sealed);         
1872     ISFLAG(Td, SpecialName);
1873     ISFLAG(Td, Import);         
1874     ISFLAG(Td, Serializable);
1875     ISFLAG(Td, AnsiClass);      
1876     ISFLAG(Td, UnicodeClass);
1877     ISFLAG(Td, AutoClass);      
1878     ISFLAG(Td, BeforeFieldInit);
1879     ISFLAG(Td, Forwarder);
1880     // "Reserved" flags
1881     ISFLAG(Td, RTSpecialName);
1882     ISFLAG(Td, HasSecurity);        
1883     ISFLAG(Td, WindowsRuntime);
1884     if (!*sFlags)
1885         strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]");
1886
1887     return sFlags;
1888 } // char *MDInfo::ClassFlags()
1889
1890 // prints out all info on the given typeDef, including all information that
1891 // is specific to a given typedef
1892 //
1893
1894 void MDInfo::DisplayTypeDefInfo(mdTypeDef inTypeDef)
1895 {
1896     DisplayTypeDefProps(inTypeDef);
1897
1898     // Get field layout information.
1899     HRESULT             hr = NOERROR;
1900     COR_FIELD_OFFSET    *rFieldOffset = NULL;
1901     ULONG               cFieldOffset = 0;
1902     hr = m_pImport->GetClassLayout(inTypeDef, NULL, rFieldOffset, 0, &cFieldOffset, NULL);
1903     if (SUCCEEDED(hr) && cFieldOffset)
1904     {
1905         rFieldOffset = new COR_FIELD_OFFSET[cFieldOffset];
1906         if (rFieldOffset == NULL)
1907             Error("_calloc failed.", E_OUTOFMEMORY);
1908         hr = m_pImport->GetClassLayout(inTypeDef, NULL, rFieldOffset, cFieldOffset, &cFieldOffset, NULL);
1909         if (FAILED(hr)) { delete [] rFieldOffset; Error("GetClassLayout() failed.", hr); }
1910     }
1911
1912     //No reason to display members if we're displaying fields and methods separately
1913     DisplayGenericParams(inTypeDef, "\t");
1914     DisplayFields(inTypeDef, rFieldOffset, cFieldOffset);
1915     delete [] rFieldOffset;
1916     DisplayMethods(inTypeDef);
1917     DisplayProperties(inTypeDef);
1918     DisplayEvents(inTypeDef);
1919     DisplayMethodImpls(inTypeDef);
1920     DisplayPermissions(inTypeDef, "");
1921     
1922     DisplayInterfaceImpls(inTypeDef);
1923     DisplayCustomAttributes(inTypeDef, "\t");
1924 } // void MDInfo::DisplayTypeDefInfo()
1925
1926 // print out information about every the given typeDef's interfaceImpls
1927 //
1928
1929 void MDInfo::DisplayInterfaceImpls(mdTypeDef inTypeDef)
1930 {
1931     HCORENUM interfaceImplEnum = NULL;
1932     mdTypeRef interfaceImpls[ENUM_BUFFER_SIZE];
1933     ULONG count, totalCount = 1;
1934     HRESULT hr;
1935     
1936     while(SUCCEEDED(hr = m_pImport->EnumInterfaceImpls( &interfaceImplEnum,
1937                              inTypeDef,interfaceImpls,NumItems(interfaceImpls), &count)) &&
1938             count > 0)
1939     {
1940         for (ULONG i = 0; i < count; i++, totalCount++)
1941         {
1942             VWriteLine("\tInterfaceImpl #%d (%08x)", totalCount, interfaceImpls[i]);
1943             WriteLine("\t-------------------------------------------------------");
1944             DisplayInterfaceImplInfo(interfaceImpls[i]);
1945             DisplayPermissions(interfaceImpls[i], "\t");
1946             WriteLine("");
1947         }
1948     }
1949     m_pImport->CloseEnum( interfaceImplEnum);
1950 } // void MDInfo::DisplayInterfaceImpls()
1951
1952 // print the information for the given interface implementation
1953 //
1954
1955 void MDInfo::DisplayInterfaceImplInfo(mdInterfaceImpl inImpl)
1956 {
1957     mdTypeDef typeDef;
1958     mdToken token;
1959     HRESULT hr;
1960
1961     WCHAR szTempBuf[STRING_BUFFER_LEN];
1962
1963     hr = m_pImport->GetInterfaceImplProps( inImpl, &typeDef, &token);
1964     if (FAILED(hr)) Error("GetInterfaceImplProps failed.", hr);
1965
1966     VWriteLine("\t\tClass     : %ls",TypeDeforRefName(typeDef, szTempBuf, NumItems(szTempBuf)));
1967     VWriteLine("\t\tToken     : %8.8X [%s] %ls",token,TokenTypeName(token), TypeDeforRefName(token, szTempBuf, NumItems(szTempBuf)));
1968
1969     DisplayCustomAttributes(inImpl, "\t\t");
1970 } // void MDInfo::DisplayInterfaceImplInfo()
1971
1972 // displays the information for a particular property
1973 //
1974
1975 void MDInfo::DisplayPropertyInfo(mdProperty inProp)
1976 {
1977     HRESULT     hr;
1978     mdTypeDef   typeDef;
1979     WCHAR       propName[STRING_BUFFER_LEN];
1980     DWORD       flags;
1981 #ifdef FEATURE_COMINTEROP
1982     VARIANT     defaultValue;
1983 #endif
1984     void const  *pValue;
1985     ULONG       cbValue;
1986     DWORD       dwCPlusTypeFlag;
1987     mdMethodDef setter, getter, otherMethod[ENUM_BUFFER_SIZE];
1988     ULONG       others;
1989     PCCOR_SIGNATURE pbSigBlob;
1990     ULONG       ulSigBlob;
1991
1992
1993 #ifdef FEATURE_COMINTEROP
1994     ::VariantInit(&defaultValue);
1995 #endif
1996     hr = m_pImport->GetPropertyProps(
1997         inProp,                 // [IN] property token
1998         &typeDef,               // [OUT] typedef containing the property declarion.
1999         
2000         propName,               // [OUT] Property name
2001         STRING_BUFFER_LEN,      // [IN] the count of wchar of szProperty
2002         NULL,                   // [OUT] actual count of wchar for property name
2003         
2004         &flags,                 // [OUT] property flags.
2005
2006         &pbSigBlob,             // [OUT] Signature Blob. 
2007         &ulSigBlob,             // [OUT] Number of bytes in the signature blob.
2008
2009         &dwCPlusTypeFlag,       // [OUT] default value
2010         &pValue,
2011         &cbValue,
2012
2013         &setter,                // [OUT] setter method of the property
2014         &getter,                // [OUT] getter method of the property
2015         
2016         otherMethod,            // [OUT] other methods of the property
2017         ENUM_BUFFER_SIZE,       // [IN] size of rmdOtherMethod
2018         &others);               // [OUT] total number of other method of this property
2019
2020     if (FAILED(hr)) Error("GetPropertyProps failed.", hr);
2021
2022     VWriteLine("\t\tProp.Name : %ls (%8.8X)",propName,inProp);
2023
2024     char sFlags[STRING_BUFFER_LEN];
2025     
2026     sFlags[0] = 0;
2027     ISFLAG(Pr, SpecialName);
2028     ISFLAG(Pr, RTSpecialName);
2029     ISFLAG(Pr, HasDefault);         
2030     if (!*sFlags)
2031         strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]");
2032
2033     VWriteLine("\t\tFlags     : %s (%08x)", sFlags, flags);
2034
2035     if (ulSigBlob)
2036         DisplaySignature(pbSigBlob, ulSigBlob, "");
2037     else
2038         VWriteLine("\t\tERROR: no valid signature ");
2039
2040     WCHAR szTempBuf[STRING_BUFFER_LEN];
2041
2042 #ifdef FEATURE_COMINTEROP
2043     _FillVariant((BYTE)dwCPlusTypeFlag, pValue, cbValue, &defaultValue);
2044     VWriteLine("\t\tDefltValue: %ls",VariantAsString(&defaultValue));
2045 #endif
2046
2047     VWriteLine("\t\tSetter    : (%08x) %ls",setter,MemberDeforRefName(setter, szTempBuf, NumItems(szTempBuf)));
2048     VWriteLine("\t\tGetter    : (%08x) %ls",getter,MemberDeforRefName(getter, szTempBuf, NumItems(szTempBuf))); 
2049
2050     // do something with others?
2051     VWriteLine("\t\t%ld Others",others);
2052     DisplayCustomAttributes(inProp, "\t\t");
2053
2054 #ifdef FEATURE_COMINTEROP
2055     ::VariantClear(&defaultValue);
2056 #endif
2057 } // void MDInfo::DisplayPropertyInfo()
2058
2059 // displays info for each property
2060 //
2061
2062 void MDInfo::DisplayProperties(mdTypeDef inTypeDef)
2063 {
2064     HCORENUM propEnum = NULL;
2065     mdProperty props[ENUM_BUFFER_SIZE];
2066     ULONG count, totalCount = 1;
2067     HRESULT hr;
2068
2069     
2070     while(SUCCEEDED(hr = m_pImport->EnumProperties( &propEnum,
2071                              inTypeDef,props,NumItems(props), &count)) &&
2072             count > 0)
2073     {
2074         for (ULONG i = 0; i < count; i++, totalCount++)
2075         {
2076             VWriteLine("\tProperty #%d (%08x)", totalCount, props[i]);
2077             WriteLine("\t-------------------------------------------------------");
2078             DisplayPropertyInfo(props[i]);
2079             DisplayPermissions(props[i], "\t");
2080             WriteLine("");
2081         }
2082     }
2083     m_pImport->CloseEnum( propEnum);
2084 } // void MDInfo::DisplayProperties()
2085
2086 // Display all information about a particular event
2087 //
2088
2089 void MDInfo::DisplayEventInfo(mdEvent inEvent)
2090 {
2091     HRESULT hr;
2092     mdTypeDef typeDef;
2093     WCHAR eventName[STRING_BUFFER_LEN];
2094     DWORD flags;
2095     mdToken eventType;
2096     mdMethodDef addOn, removeOn, fire, otherMethod[ENUM_BUFFER_SIZE];
2097     ULONG totalOther;
2098
2099
2100     hr = m_pImport->GetEventProps(
2101                             // [IN] The scope.
2102         inEvent,                // [IN] event token
2103         &typeDef,               // [OUT] typedef containing the event declarion.
2104         
2105         eventName,              // [OUT] Event name
2106         STRING_BUFFER_LEN,      // [IN] the count of wchar of szEvent
2107         NULL,                   // [OUT] actual count of wchar for event's name
2108
2109         &flags,                 // [OUT] Event flags.
2110         &eventType,             // [OUT] EventType class
2111
2112         &addOn,                 // [OUT] AddOn method of the event
2113         &removeOn,              // [OUT] RemoveOn method of the event
2114         &fire,                  // [OUT] Fire method of the event
2115
2116         otherMethod,            // [OUT] other method of the event
2117         NumItems(otherMethod),  // [IN] size of rmdOtherMethod
2118         &totalOther);           // [OUT] total number of other method of this event
2119     if (FAILED(hr)) Error("GetEventProps failed.", hr);
2120
2121     VWriteLine("\t\tName      : %ls (%8.8X)",eventName,inEvent);
2122     
2123     char sFlags[STRING_BUFFER_LEN];
2124
2125     sFlags[0] = 0;
2126     ISFLAG(Ev, SpecialName); 
2127     ISFLAG(Ev, RTSpecialName);    
2128     if (!*sFlags)
2129         strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]");
2130
2131     VWriteLine("\t\tFlags     : %s (%08x)", sFlags, flags);
2132
2133     WCHAR szTempBuf[STRING_BUFFER_LEN];
2134
2135     VWriteLine("\t\tEventType : %8.8X [%s]",eventType,TokenTypeName(eventType));
2136     VWriteLine("\t\tAddOnMethd: (%08x) %ls",addOn,MemberDeforRefName(addOn, szTempBuf, NumItems(szTempBuf)));
2137     VWriteLine("\t\tRmvOnMethd: (%08x) %ls",removeOn,MemberDeforRefName(removeOn, szTempBuf, NumItems(szTempBuf)));
2138     VWriteLine("\t\tFireMethod: (%08x) %ls",fire,MemberDeforRefName(fire, szTempBuf, NumItems(szTempBuf)));
2139
2140     VWriteLine("\t\t%ld OtherMethods",totalOther);
2141     
2142     DisplayCustomAttributes(inEvent, "\t\t");
2143 } // void MDInfo::DisplayEventInfo()
2144
2145 // Display information about all events in a typedef
2146 // 
2147 void MDInfo::DisplayEvents(mdTypeDef inTypeDef)
2148 {
2149     HCORENUM eventEnum = NULL;
2150     mdProperty events[ENUM_BUFFER_SIZE];
2151     ULONG count, totalCount = 1;
2152     HRESULT hr;
2153
2154     
2155     while(SUCCEEDED(hr = m_pImport->EnumEvents( &eventEnum,
2156                              inTypeDef,events,NumItems(events), &count)) &&
2157             count > 0)
2158     {
2159         for (ULONG i = 0; i < count; i++, totalCount++)
2160         {
2161             VWriteLine("\tEvent #%d (%08x)", totalCount, events[i]);
2162             WriteLine("\t-------------------------------------------------------");
2163             DisplayEventInfo(events[i]);
2164             DisplayPermissions(events[i], "\t");
2165             WriteLine("");
2166         }
2167     }
2168     m_pImport->CloseEnum( eventEnum);
2169 } // void MDInfo::DisplayEvents()
2170
2171
2172 // print info for the passed-in custom attribute
2173 // This function is used to print the custom attribute information for both TypeDefs and
2174 // MethodDefs which need slightly different formatting.  preFix helps fix it up.
2175 //
2176
2177 void MDInfo::DisplayCustomAttributeInfo(mdCustomAttribute inValue, const char *preFix)
2178 {
2179     const BYTE  *pValue;                // The custom value.
2180     ULONG       cbValue;                // Length of the custom value.
2181     HRESULT     hr;                     // A result.
2182     mdToken     tkObj;                  // Attributed object.
2183     mdToken     tkType;                 // Type of the custom attribute.
2184     mdToken     tk;                     // For name lookup.
2185     LPCUTF8     pMethName=0;            // Name of custom attribute ctor, if any.
2186     CQuickBytes qSigName;               // Buffer to pretty-print signature.
2187     PCCOR_SIGNATURE pSig=0;             // Signature of ctor.
2188     ULONG       cbSig;                  // Size of the signature.
2189     BOOL        bCoffSymbol = false;    // true for coff symbol CA's.
2190     WCHAR       rcName[MAX_CLASS_NAME]; // Name of the type.
2191
2192     hr = m_pImport->GetCustomAttributeProps( // S_OK or error.
2193         inValue,                    // The attribute.
2194         &tkObj,                     // The attributed object
2195         &tkType,                    // The attributes type.
2196         (const void**)&pValue,      // Put pointer to data here.
2197         &cbValue);                  // Put size here.
2198     if (FAILED(hr)) Error("GetCustomAttributeProps failed.", hr);
2199
2200     VWriteLine("%s\tCustomAttribute Type: %08x", preFix, tkType);
2201     
2202     // Get the name of the memberref or methoddef.
2203         tk = tkType;
2204         rcName[0] = L'\0';
2205         // Get the member name, and the parent token.
2206         switch (TypeFromToken(tk))
2207         {
2208         case mdtMemberRef:
2209             hr = m_pImport->GetNameFromToken(tk, &pMethName);
2210             if (FAILED(hr)) Error("GetNameFromToken failed.", hr);
2211             hr = m_pImport->GetMemberRefProps( tk, &tk, 0, 0, 0, &pSig, &cbSig);
2212             if (FAILED(hr)) Error("GetMemberRefProps failed.", hr);
2213             break;
2214         case mdtMethodDef:
2215             hr = m_pImport->GetNameFromToken(tk, &pMethName);
2216             if (FAILED(hr)) Error("GetNameFromToken failed.", hr);
2217             hr = m_pImport->GetMethodProps(tk, &tk, 0, 0, 0, 0, &pSig, &cbSig, 0, 0);
2218             if (FAILED(hr)) Error("GetMethodProps failed.", hr);
2219             break;
2220         } // switch
2221         
2222         // Get the type name.
2223         switch (TypeFromToken(tk))
2224         {
2225         case mdtTypeDef:
2226             hr = m_pImport->GetTypeDefProps(tk, rcName,MAX_CLASS_NAME,0, 0,0);
2227             if (FAILED(hr)) Error("GetTypeDefProps failed.", hr);
2228             break;
2229         case mdtTypeRef:
2230             hr = m_pImport->GetTypeRefProps(tk, 0, rcName,MAX_CLASS_NAME,0);
2231             if (FAILED(hr)) Error("GetTypeRefProps failed.", hr);
2232             break;
2233         } // switch
2234             
2235         
2236         if (pSig && pMethName)
2237         {
2238             int iLen;
2239             LPWSTR pwzName = (LPWSTR)(new WCHAR[iLen= 1+(ULONG32)strlen(pMethName)]);
2240             if(pwzName)
2241             {
2242                 WszMultiByteToWideChar(CP_UTF8,0, pMethName,-1, pwzName,iLen);
2243                 PrettyPrintSigLegacy(pSig, cbSig, pwzName, &qSigName, m_pImport);
2244                 delete [] pwzName;
2245             }
2246         }
2247
2248     VWrite("%s\tCustomAttributeName: %ls", preFix, rcName);
2249     if (pSig && pMethName)
2250         VWrite(" :: %S", qSigName.Ptr());
2251
2252     // Keep track of coff overhead.
2253         if (!wcscmp(W("__DecoratedName"), rcName))
2254         {
2255             bCoffSymbol = true;
2256             g_cbCoffNames += cbValue + 6;
2257         }
2258     WriteLine("");
2259
2260     VWriteLine("%s\tLength: %ld", preFix, cbValue);
2261     char newPreFix[40];
2262     sprintf_s(newPreFix, 40, "%s\tValue ", preFix);
2263     DumpHex(newPreFix, pValue, cbValue);
2264     if (bCoffSymbol)
2265         VWriteLine("%s\t            %s", preFix, pValue);
2266
2267     // Try to decode the constructor blob.  This is incomplete, but covers the most popular cases.
2268     if (pSig)
2269     {   // Interpret the signature.
2270         PCCOR_SIGNATURE ps = pSig;
2271         ULONG cb;
2272         ULONG ulData;
2273         ULONG cParams;
2274         ULONG ulVal;
2275         UINT8 u1 = 0;
2276         UINT16 u2 = 0;
2277         UINT32 u4 = 0;
2278         UINT64 u8 = 0;
2279         unsigned __int64 uI64;
2280         double dblVal;
2281         ULONG cbVal;
2282         LPCUTF8 pStr;
2283         CustomAttributeParser CA(pValue, cbValue);
2284         CA.ValidateProlog();
2285
2286         // Get the calling convention.
2287         cb = CorSigUncompressData(ps, &ulData);
2288         ps += cb;
2289         // Get the count of params.
2290         cb = CorSigUncompressData(ps, &cParams);
2291         ps += cb;
2292         // Get the return value.
2293         cb = CorSigUncompressData(ps, &ulData);
2294         ps += cb;
2295         if (ulData == ELEMENT_TYPE_VOID)
2296         {   
2297             VWrite("%s\tctor args: (", preFix);
2298             // For each param...
2299             for (ULONG i=0; i<cParams; ++i)
2300             {   // Get the next param type.
2301                 cb = CorSigUncompressData(ps, &ulData);
2302                 ps += cb;
2303                 if (i) Write(", ");
2304             DoObject:                
2305                 switch (ulData)
2306                 {
2307                 // For ET_OBJECT, the next byte in the blob is the ET of the actual data.
2308                 case ELEMENT_TYPE_OBJECT:
2309                     CA.GetU1(&u1);
2310                     ulData = u1;
2311                     goto DoObject;
2312                 case ELEMENT_TYPE_I1:
2313                 case ELEMENT_TYPE_U1:
2314                     CA.GetU1(&u1);
2315                     ulVal = u1;
2316                     goto PrintVal;
2317                 case ELEMENT_TYPE_I2:
2318                 case ELEMENT_TYPE_U2:
2319                     CA.GetU2(&u2);
2320                     ulVal = u2;
2321                     goto PrintVal;
2322                 case ELEMENT_TYPE_I4:
2323                 case ELEMENT_TYPE_U4:
2324                     CA.GetU4(&u4);
2325                     ulVal = u4;
2326                 PrintVal:
2327                 VWrite("%d", ulVal);
2328                     break;
2329                 case ELEMENT_TYPE_STRING:
2330                     CA.GetString(&pStr, &cbVal);
2331                     VWrite("\"%s\"", pStr);
2332                     break;
2333                 // The only class type that we accept is Type, which is stored as a string.
2334                 case ELEMENT_TYPE_CLASS:
2335                     // Eat the class type.
2336                     cb = CorSigUncompressData(ps, &ulData);
2337                     ps += cb;
2338                     // Get the name of the type.
2339                     CA.GetString(&pStr, &cbVal);
2340                     VWrite("typeof(%s)", pStr);
2341                     break;
2342                 case SERIALIZATION_TYPE_TYPE:
2343                     CA.GetString(&pStr, &cbVal);
2344                     VWrite("typeof(%s)", pStr);
2345                     break;
2346                 case ELEMENT_TYPE_I8:
2347                 case ELEMENT_TYPE_U8:
2348                     CA.GetU8(&u8);
2349                     uI64 = u8;
2350                     VWrite("%#lx", uI64);
2351                     break;
2352                 case ELEMENT_TYPE_R4:
2353                     dblVal = CA.GetR4();
2354                     VWrite("%f", dblVal);
2355                     break;
2356                 case ELEMENT_TYPE_R8:
2357                     dblVal = CA.GetR8();
2358                     VWrite("%f", dblVal);
2359                     break;
2360                 default:
2361                     // bail...
2362                     i = cParams;
2363                     Write(" <can not decode> ");
2364                     break;
2365                 }
2366             }
2367             WriteLine(")");
2368         }
2369
2370     }
2371     WriteLine("");
2372 } // void MDInfo::DisplayCustomAttributeInfo()
2373
2374 // Print all custom values for the given token
2375 // This function is used to print the custom value information for all tokens.
2376 // which need slightly different formatting.  preFix helps fix it up.
2377 //
2378
2379 void MDInfo::DisplayCustomAttributes(mdToken inToken, const char *preFix)
2380 {
2381     HCORENUM customAttributeEnum = NULL;
2382     mdTypeRef customAttributes[ENUM_BUFFER_SIZE];
2383     ULONG count, totalCount = 1;
2384     HRESULT hr;
2385     
2386     while(SUCCEEDED(hr = m_pImport->EnumCustomAttributes( &customAttributeEnum, inToken, 0,
2387                              customAttributes, NumItems(customAttributes), &count)) &&
2388           count > 0)
2389     {
2390         for (ULONG i = 0; i < count; i++, totalCount++)
2391         {
2392             VWriteLine("%sCustomAttribute #%d (%08x)", preFix, totalCount, customAttributes[i]);
2393             VWriteLine("%s-------------------------------------------------------", preFix);
2394             DisplayCustomAttributeInfo(customAttributes[i], preFix);
2395         }
2396     }
2397     m_pImport->CloseEnum( customAttributeEnum);
2398 } // void MDInfo::DisplayCustomAttributes()
2399
2400 //  Show the passed-in token's permissions
2401 //
2402 // 
2403
2404 void MDInfo::DisplayPermissions(mdToken tk, const char *preFix)
2405 {
2406     HCORENUM permissionEnum = NULL;
2407     mdPermission permissions[ENUM_BUFFER_SIZE];
2408     ULONG count, totalCount = 1;
2409     HRESULT hr;
2410
2411     
2412     while (SUCCEEDED(hr = m_pImport->EnumPermissionSets( &permissionEnum,
2413                      tk, 0, permissions, NumItems(permissions), &count)) &&
2414             count > 0)
2415     {
2416         for (ULONG i = 0; i < count; i++, totalCount++)
2417         {
2418             VWriteLine("%s\tPermission #%d (%08x)", preFix, totalCount, permissions[i]);
2419             VWriteLine("%s\t-------------------------------------------------------", preFix);
2420             DisplayPermissionInfo(permissions[i], preFix);
2421             WriteLine("");
2422         }
2423     }
2424     m_pImport->CloseEnum( permissionEnum);
2425 } // void MDInfo::DisplayPermissions()
2426
2427 // print properties of given rolecheck
2428 //
2429 //
2430
2431 void MDInfo::DisplayPermissionInfo(mdPermission inPermission, const char *preFix)
2432 {
2433     DWORD dwAction;
2434     const BYTE *pvPermission;
2435     ULONG cbPermission;
2436     const char *flagDesc = NULL;
2437     char newPreFix[STRING_BUFFER_LEN];
2438     HRESULT hr;
2439
2440
2441     hr = m_pImport->GetPermissionSetProps( inPermission, &dwAction,
2442                                         (const void**)&pvPermission, &cbPermission);
2443     if (FAILED(hr)) Error("GetPermissionSetProps failed.", hr);
2444
2445     switch(dwAction)
2446     {
2447     case dclActionNil:          flagDesc = "ActionNil"; break;
2448     case dclRequest:            flagDesc = "Request"; break;
2449     case dclDemand:             flagDesc = "Demand"; break;
2450     case dclAssert:             flagDesc = "Assert"; break;
2451     case dclDeny:               flagDesc = "Deny"; break;
2452     case dclPermitOnly:         flagDesc = "PermitOnly"; break;
2453     case dclLinktimeCheck:      flagDesc = "LinktimeCheck"; break;
2454     case dclInheritanceCheck:   flagDesc = "InheritanceCheck"; break;
2455     case dclRequestMinimum:     flagDesc = "RequestMinimum"; break;
2456     case dclRequestOptional:    flagDesc = "RequestOptional"; break;
2457     case dclRequestRefuse:      flagDesc = "RequestRefuse"; break;
2458     case dclPrejitGrant:        flagDesc = "PrejitGrant"; break;
2459     case dclPrejitDenied:       flagDesc = "PrejitDenied"; break;
2460     case dclNonCasDemand:       flagDesc = "NonCasDemand"; break;
2461     case dclNonCasLinkDemand:   flagDesc = "NonCasLinkDemand"; break;
2462     case dclNonCasInheritance:  flagDesc = "NonCasInheritance"; break;
2463
2464     }
2465     VWriteLine("%s\t\tAction    : %s", preFix, flagDesc);
2466     VWriteLine("%s\t\tBlobLen   : %d", preFix, cbPermission);
2467     if (cbPermission)
2468     {
2469         sprintf_s(newPreFix, STRING_BUFFER_LEN, "%s\tBlob", preFix);
2470         DumpHex(newPreFix, pvPermission, cbPermission, false, 24);
2471     }
2472
2473     sprintf_s (newPreFix, STRING_BUFFER_LEN, "\t\t%s", preFix);
2474     DisplayCustomAttributes(inPermission, newPreFix);
2475 } // void MDInfo::DisplayPermissionInfo()
2476
2477
2478 // simply prints out the given GUID in standard form
2479
2480 LPWSTR MDInfo::GUIDAsString(GUID inGuid, __out_ecount(bufLen) LPWSTR guidString, ULONG bufLen)
2481 {
2482     StringFromGUID2(inGuid, guidString, bufLen);
2483     return guidString;
2484 } // LPWSTR MDInfo::GUIDAsString()
2485
2486 #ifdef FEATURE_COMINTEROP
2487 LPCWSTR MDInfo::VariantAsString(VARIANT *pVariant)
2488 {
2489     HRESULT hr = S_OK;
2490     if (V_VT(pVariant) == VT_UNKNOWN)
2491     {
2492         _ASSERTE(V_UNKNOWN(pVariant) == NULL);
2493         return W("<NULL>");
2494     }
2495     else if (SUCCEEDED(hr = ::VariantChangeType(pVariant, pVariant, 0, VT_BSTR)))
2496         return V_BSTR(pVariant);
2497     else if (hr == DISP_E_BADVARTYPE && V_VT(pVariant) == VT_I8)
2498     {
2499         // allocate the bstr.
2500         char    szStr[32];
2501         WCHAR   wszStr[32];
2502         // Set variant type to bstr.
2503         V_VT(pVariant) = VT_BSTR;
2504         // Create the ansi string.
2505         sprintf_s(szStr, 32, "%I64d", V_CY(pVariant).int64);
2506         // Convert to unicode.
2507         WszMultiByteToWideChar(CP_ACP, 0, szStr, -1, wszStr, 32);
2508         // convert to bstr and set variant value.
2509         V_BSTR(pVariant) = ::SysAllocString(wszStr);
2510         if (V_BSTR(pVariant) == NULL)
2511             Error("SysAllocString() failed.", E_OUTOFMEMORY);
2512         return V_BSTR(pVariant);
2513     }
2514     else
2515         return W("ERROR");
2516     
2517 } // LPWSTR MDInfo::VariantAsString()
2518 #endif
2519
2520 bool TrySigUncompress(PCCOR_SIGNATURE pData,              // [IN] compressed data 
2521                       ULONG       *pDataOut,              // [OUT] the expanded *pData
2522                       ULONG       *cbCur)
2523 {
2524     ULONG ulSize = CorSigUncompressData(pData, pDataOut);
2525     if (ulSize == (ULONG)-1)
2526     {
2527         *cbCur = ulSize;
2528         return false;
2529     } else
2530     {
2531         *cbCur += ulSize;
2532         return true;
2533     }
2534 }
2535
2536 void MDInfo::DisplayFieldMarshal(mdToken inToken)
2537 {
2538     PCCOR_SIGNATURE pvNativeType;     // [OUT] native type of this field
2539     ULONG       cbNativeType;         // [OUT] the count of bytes of *ppvNativeType
2540     HRESULT hr;
2541
2542
2543     hr = m_pImport->GetFieldMarshal( inToken, &pvNativeType, &cbNativeType);
2544     if (FAILED(hr) && hr != CLDB_E_RECORD_NOTFOUND) Error("GetFieldMarshal failed.", hr);
2545     if (hr != CLDB_E_RECORD_NOTFOUND)
2546     {
2547         ULONG cbCur = 0;
2548         ULONG ulData;
2549         ULONG ulStrLoc;
2550
2551         char szNTDesc[STRING_BUFFER_LEN];
2552
2553         while (cbCur < cbNativeType)
2554         {
2555             ulStrLoc = 0;
2556
2557             ulData = NATIVE_TYPE_MAX;
2558             if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur))
2559                 continue;
2560             if (ulData >= sizeof(g_szNativeType)/sizeof(*g_szNativeType))
2561             {
2562                 cbCur = (ULONG)-1;
2563                 continue;
2564             }
2565             ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "%s ", g_szNativeType[ulData]);
2566             switch (ulData)
2567             {
2568             case NATIVE_TYPE_FIXEDSYSSTRING:
2569                 {
2570                     if (cbCur < cbNativeType)
2571                     {
2572                         if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur))
2573                             continue;
2574                         ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "{StringElementCount: %d} ",ulData);
2575                     }
2576                 }
2577                 break;
2578             case NATIVE_TYPE_FIXEDARRAY:
2579                 {
2580                     if (cbCur < cbNativeType)
2581                     {
2582                         if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur))
2583                             continue;
2584                         ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "{ArrayElementCount: %d",ulData);
2585
2586                         if (cbCur < cbNativeType)
2587                         {
2588                             if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur))
2589                                 continue;
2590                             ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, ", ArrayElementType(NT): %d",ulData);
2591                         }
2592
2593                         ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc,"}");
2594                     }
2595                 }
2596                 break;
2597             case NATIVE_TYPE_ARRAY:
2598                 {
2599                     if (cbCur < cbNativeType)
2600                     {
2601                         BOOL bElemTypeSpecified;
2602
2603                         if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur))
2604                             continue;
2605                         if (ulData != NATIVE_TYPE_MAX)
2606                         {
2607                             ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "{ArrayElementType(NT): %d", ulData);
2608                             bElemTypeSpecified = TRUE;
2609                         }
2610                         else
2611                         {
2612                             ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "{");
2613                             bElemTypeSpecified = FALSE;
2614                         }
2615
2616                         if (cbCur < cbNativeType)
2617                         {
2618                             if (bElemTypeSpecified)
2619                                 ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, ", ");
2620
2621                             if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur))
2622                                 continue;
2623                             ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "SizeParamIndex: %d",ulData);
2624
2625                             if (cbCur < cbNativeType)
2626                             {
2627                                 if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur))
2628                                     continue;
2629                                 ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, ", SizeParamMultiplier: %d",ulData);
2630
2631                                 if (cbCur < cbNativeType)
2632                                 {
2633                                     if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur))
2634                                         continue;
2635                                     ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, ", SizeConst: %d",ulData);
2636                                 }
2637                             }
2638                         }
2639
2640                         ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "}");
2641                     }
2642                 }
2643                 break;
2644             case NATIVE_TYPE_SAFEARRAY:
2645                 {
2646                     if (cbCur < cbNativeType)
2647                     {
2648                         if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur))
2649                             continue;
2650                         ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "{SafeArraySubType(VT): %d, ",ulData);
2651
2652                         // Extract the element type name if it is specified.
2653                         if (cbCur < cbNativeType)
2654                         {
2655                             LPUTF8 strTemp = NULL;
2656                             int strLen = 0;
2657                             int ByteCountLength = 0;         
2658
2659                             strLen = CPackedLen::GetLength(&pvNativeType[cbCur], &ByteCountLength);
2660                             cbCur += ByteCountLength;
2661                             strTemp = (LPUTF8)(new char[strLen + 1]);
2662                             if(strTemp)
2663                             {
2664                                 memcpy(strTemp, (LPUTF8)&pvNativeType[cbCur], strLen);
2665                                 strTemp[strLen] = 0;
2666                                 ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "ElementTypeName: %s}", strTemp);
2667                                 cbCur += strLen;
2668                                 _ASSERTE(cbCur == cbNativeType);
2669                                  delete [] strTemp;
2670                             }
2671                         }
2672                         else
2673                         {
2674                             ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "ElementTypeName: }");
2675                         }
2676                     }
2677                 }
2678                 break;
2679             case NATIVE_TYPE_CUSTOMMARSHALER:
2680                 {
2681                     LPUTF8 strTemp = NULL;
2682                     int strLen = 0;
2683                     int ByteCountLength = 0;         
2684
2685                     // Extract the typelib GUID.
2686                     strLen = CPackedLen::GetLength(&pvNativeType[cbCur], &ByteCountLength);
2687                     cbCur += ByteCountLength;
2688                     strTemp = (LPUTF8)(new char[strLen + 1]);
2689                     if(strTemp)
2690                     {
2691                         memcpy(strTemp, (LPUTF8)&pvNativeType[cbCur], strLen);
2692                         strTemp[strLen] = 0;
2693                         ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "{Typelib: %s, ", strTemp);
2694                         cbCur += strLen;
2695                         _ASSERTE(cbCur < cbNativeType);
2696                         delete [] strTemp;
2697                     }
2698                     // Extract the name of the native type.
2699                     strLen = CPackedLen::GetLength(&pvNativeType[cbCur], &ByteCountLength);
2700                     cbCur += ByteCountLength;
2701                     strTemp = (LPUTF8)(new char[strLen + 1]);
2702                     if(strTemp)
2703                     {
2704                         memcpy(strTemp, (LPUTF8)&pvNativeType[cbCur], strLen);
2705                         strTemp[strLen] = 0;
2706                         ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "Native: %s, ", strTemp);
2707                         cbCur += strLen;
2708                         _ASSERTE(cbCur < cbNativeType);
2709                         delete [] strTemp;
2710                     }
2711
2712                     // Extract the name of the custom marshaler.
2713                     strLen = CPackedLen::GetLength(&pvNativeType[cbCur], &ByteCountLength);
2714                     cbCur += ByteCountLength;
2715                     strTemp = (LPUTF8)(new char[strLen + 1]);
2716                     if(strTemp)
2717                     {
2718                         memcpy(strTemp, (LPUTF8)&pvNativeType[cbCur], strLen);
2719                         strTemp[strLen] = 0;
2720                         ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "Marshaler: %s, ", strTemp);
2721                         cbCur += strLen;
2722                         _ASSERTE(cbCur < cbNativeType);
2723                         delete [] strTemp;
2724                     }
2725                     // Extract the cookie string.
2726                     strLen = CPackedLen::GetLength(&pvNativeType[cbCur], &ByteCountLength);
2727                     cbCur += ByteCountLength;
2728                     if (strLen > 0)
2729                     {
2730                         strTemp = (LPUTF8)(new char[strLen + 1]);
2731                         if(strTemp)
2732                         {
2733                             memcpy(strTemp, (LPUTF8)&pvNativeType[cbCur], strLen);
2734                             strTemp[strLen] = 0;
2735                             ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "Cookie: ");
2736
2737                             // Copy the cookie string and transform the embedded nulls into \0's.
2738                             for (int i = 0; i < strLen - 1; i++, cbCur++)
2739                             {
2740                                 if (strTemp[i] == 0)
2741                                     ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "\\0");
2742                                 else
2743                                     szNTDesc[ulStrLoc++] = strTemp[i];
2744                             }
2745                             szNTDesc[ulStrLoc++] = strTemp[strLen - 1];
2746                             cbCur++;
2747                             delete [] strTemp;
2748                         }
2749                     }
2750                     else
2751                     {
2752                         ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "Cookie: ");
2753                     }
2754
2755                     // Finish the custom marshaler native type description.
2756                     ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "}");
2757                     _ASSERTE(cbCur <= cbNativeType);
2758                 }           
2759                 break;
2760             default:
2761                 {
2762                     // normal nativetype element: do nothing
2763                 }
2764             }
2765             VWriteLine("\t\t\t\t%s",szNTDesc);
2766             if (ulData >= NATIVE_TYPE_MAX)
2767                 break;
2768         }
2769         if (cbCur == (ULONG)-1)
2770         {
2771             // There was something that we didn't grok in the signature.
2772             // Just dump out the blob as hex
2773             VWrite("\t\t\t\t{", szNTDesc);
2774             while (cbNativeType--)
2775                 VWrite(" %2.2X", *pvNativeType++);
2776             VWriteLine(" }");
2777         }
2778     }
2779 } // void MDInfo::DisplayFieldMarshal()
2780
2781 void MDInfo::DisplayPinvokeInfo(mdToken inToken)
2782 {
2783     HRESULT hr = NOERROR;
2784     DWORD flags;
2785     WCHAR rcImport[512];
2786     mdModuleRef tkModuleRef;
2787             
2788     char sFlags[STRING_BUFFER_LEN];
2789
2790     hr = m_pImport->GetPinvokeMap(inToken, &flags, rcImport,
2791                                   NumItems(rcImport), 0, &tkModuleRef);
2792     if (FAILED(hr))
2793     {
2794         if (hr != CLDB_E_RECORD_NOTFOUND)
2795             VWriteLine("ERROR: GetPinvokeMap failed.", hr);
2796         return;
2797     }
2798                 
2799     WriteLine("\t\tPinvoke Map Data:");
2800     VWriteLine("\t\tEntry point:      %S", rcImport);
2801     VWriteLine("\t\tModule ref:       %08x", tkModuleRef);
2802             
2803     sFlags[0] = 0;
2804     ISFLAG(Pm, NoMangle);           
2805     ISFLAG(Pm, CharSetNotSpec);
2806     ISFLAG(Pm, CharSetAnsi);        
2807     ISFLAG(Pm, CharSetUnicode); 
2808     ISFLAG(Pm, CharSetAuto);
2809     ISFLAG(Pm, SupportsLastError);  
2810     ISFLAG(Pm, CallConvWinapi); 
2811     ISFLAG(Pm, CallConvCdecl);  
2812     ISFLAG(Pm, CallConvStdcall);
2813     ISFLAG(Pm, CallConvThiscall);   
2814     ISFLAG(Pm, CallConvFastcall);
2815
2816     ISFLAG(Pm, BestFitEnabled);   
2817     ISFLAG(Pm, BestFitDisabled);   
2818     ISFLAG(Pm, BestFitUseAssem);   
2819     ISFLAG(Pm, ThrowOnUnmappableCharEnabled);   
2820     ISFLAG(Pm, ThrowOnUnmappableCharDisabled);
2821     ISFLAG(Pm, ThrowOnUnmappableCharUseAssem);
2822     if (!*sFlags)
2823         strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]");
2824         
2825     VWriteLine("\t\tMapping flags:    %s (%08x)", sFlags, flags);
2826 }   // void MDInfo::DisplayPinvokeInfo()
2827
2828
2829 /////////////////////////////////////////////////////////////////////////
2830 // void DisplaySignature(PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob);
2831 //
2832 // Display COM+ signature -- taken from cordump.cpp's DumpSignature
2833 /////////////////////////////////////////////////////////////////////////
2834 void MDInfo::DisplaySignature(PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, const char *preFix)
2835 {
2836     ULONG       cbCur = 0;
2837     ULONG       cb;
2838     // 428793: Prefix complained correctly about unitialized data.
2839     ULONG       ulData = (ULONG) IMAGE_CEE_CS_CALLCONV_MAX;
2840     ULONG       ulArgs;
2841     HRESULT     hr = NOERROR;
2842     ULONG       ulSigBlobStart = ulSigBlob;
2843
2844     // initialize sigBuf
2845     InitSigBuffer();
2846
2847     cb = CorSigUncompressData(pbSigBlob, &ulData);
2848     VWriteLine("%s\t\tCallCnvntn: %s", preFix, (g_strCalling[ulData & IMAGE_CEE_CS_CALLCONV_MASK]));
2849     if (cb>ulSigBlob) 
2850         goto ErrExit;
2851     cbCur += cb;
2852     ulSigBlob -= cb;
2853
2854     if (ulData & IMAGE_CEE_CS_CALLCONV_HASTHIS)
2855         VWriteLine("%s\t\thasThis ", preFix);
2856     if (ulData & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS)
2857         VWriteLine("%s\t\texplicit ", preFix);
2858     if (ulData & IMAGE_CEE_CS_CALLCONV_GENERIC)
2859         VWriteLine("%s\t\tgeneric ", preFix);
2860
2861     // initialize sigBuf
2862     InitSigBuffer();
2863     if ( isCallConv(ulData,IMAGE_CEE_CS_CALLCONV_FIELD) )
2864     {
2865
2866         // display field type
2867         if (FAILED(hr = GetOneElementType(&pbSigBlob[cbCur], ulSigBlob, &cb)))
2868             goto ErrExit;
2869         VWriteLine("%s\t\tField type: %s", preFix, (LPSTR)m_sigBuf.Ptr());
2870         if (cb>ulSigBlob) 
2871             goto ErrExit;
2872         cbCur += cb;
2873         ulSigBlob -= cb;
2874     }
2875     else 
2876     {
2877         if (ulData & IMAGE_CEE_CS_CALLCONV_GENERIC)
2878     { 
2879           ULONG ulTyArgs;         
2880           cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulTyArgs);
2881           if (cb>ulSigBlob) 
2882             goto ErrExit;
2883           cbCur += cb;
2884           ulSigBlob -= cb;
2885           VWriteLine("%s\t\tType Arity:%d ", preFix, ulTyArgs);
2886     }
2887         cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulArgs);
2888         if (cb>ulSigBlob) 
2889             goto ErrExit;
2890         cbCur += cb;
2891         ulSigBlob -= cb;
2892
2893         if (ulData != IMAGE_CEE_CS_CALLCONV_LOCAL_SIG && ulData != IMAGE_CEE_CS_CALLCONV_GENERICINST)
2894         {
2895             // display return type when it is not a local varsig
2896             if (FAILED(hr = GetOneElementType(&pbSigBlob[cbCur], ulSigBlob, &cb)))
2897                 goto ErrExit;
2898             VWriteLine("%s\t\tReturnType:%s", preFix, (LPSTR)m_sigBuf.Ptr());
2899             if (cb>ulSigBlob) 
2900                 goto ErrExit;
2901             cbCur += cb;
2902             ulSigBlob -= cb;
2903         }
2904
2905         // display count of argument
2906         // display arguments
2907         if (ulSigBlob)
2908             VWriteLine("%s\t\t%ld Arguments", preFix, ulArgs);
2909         else
2910             VWriteLine("%s\t\tNo arguments.", preFix);
2911
2912         ULONG       i = 0;
2913         while (i < ulArgs && ulSigBlob > 0)
2914         {
2915             ULONG       ulDataTemp;
2916
2917             // Handle the sentinal for varargs because it isn't counted in the args.
2918             CorSigUncompressData(&pbSigBlob[cbCur], &ulDataTemp);
2919             ++i;
2920
2921             // initialize sigBuf
2922             InitSigBuffer();
2923
2924             if (FAILED(hr = GetOneElementType(&pbSigBlob[cbCur], ulSigBlob, &cb)))
2925                 goto ErrExit;
2926
2927             VWriteLine("%s\t\t\tArgument #%ld: %s",preFix, i, (LPSTR)m_sigBuf.Ptr());
2928     
2929             if (cb>ulSigBlob) 
2930                 goto ErrExit;
2931
2932             cbCur += cb;
2933             ulSigBlob -= cb;
2934         }
2935     }
2936
2937     // Nothing consumed but not yet counted.
2938     cb = 0;
2939
2940 ErrExit:
2941     // We should have consumed all signature blob.  If not, dump the sig in hex.
2942     //  Also dump in hex if so requested.
2943     if (m_DumpFilter & dumpMoreHex || ulSigBlob != 0)
2944     {
2945         // Did we not consume enough, or try to consume too much?
2946         if (cb > ulSigBlob)
2947             WriteLine("\tERROR IN SIGNATURE:  Signature should be larger.");
2948         else
2949         if (cb < ulSigBlob)
2950         {
2951             VWrite("\tERROR IN SIGNATURE:  Not all of signature blob was consumed.  %d byte(s) remain", ulSigBlob);
2952             // If it is short, just append it to the end.
2953             if (ulSigBlob < 4)
2954             {
2955                 Write(": ");
2956                 for (; ulSigBlob; ++cbCur, --ulSigBlob)
2957                     VWrite("%02x ", pbSigBlob[cbCur]);
2958                 WriteLine("");
2959                 goto ErrExit2;
2960             }
2961             WriteLine("");
2962         }
2963
2964         // Any appropriate error message has been issued.  Dump sig in hex, as determined
2965         //  by error or command line switch.
2966         cbCur = 0;
2967         ulSigBlob = ulSigBlobStart;
2968         char rcNewPrefix[80];
2969         sprintf_s(rcNewPrefix, 80, "%s\t\tSignature ", preFix);
2970         DumpHex(rcNewPrefix, pbSigBlob, ulSigBlob, false, 24);
2971     }
2972 ErrExit2:
2973     if (FAILED(hr))
2974         Error("ERROR!! Bad signature blob value!");
2975     return;
2976 } // void MDInfo::DisplaySignature()
2977
2978
2979 /////////////////////////////////////////////////////////////////////////
2980 // HRESULT GetOneElementType(mdScope tkScope, BYTE *pbSigBlob, ULONG ulSigBlob, ULONG *pcb)
2981 //
2982 // Adds description of element type to the end of buffer -- caller must ensure
2983 // buffer is large enough.
2984 /////////////////////////////////////////////////////////////////////////
2985 HRESULT MDInfo::GetOneElementType(PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, ULONG *pcb)
2986 {
2987     HRESULT     hr = S_OK;              // A result.
2988     ULONG       cbCur = 0;
2989     ULONG       cb;
2990     ULONG       ulData = ELEMENT_TYPE_MAX;
2991     ULONG       ulTemp;
2992     int         iTemp = 0;
2993     mdToken     tk;
2994
2995     cb = CorSigUncompressData(pbSigBlob, &ulData);
2996     cbCur += cb;
2997
2998     // Handle the modifiers.
2999     if (ulData & ELEMENT_TYPE_MODIFIER)
3000     {
3001         if (ulData == ELEMENT_TYPE_SENTINEL)
3002             IfFailGo(AddToSigBuffer("<ELEMENT_TYPE_SENTINEL>"));
3003         else if (ulData == ELEMENT_TYPE_PINNED)
3004             IfFailGo(AddToSigBuffer("PINNED"));
3005         else
3006         {
3007             hr = E_FAIL;
3008             goto ErrExit;
3009         }
3010         if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb)))
3011             goto ErrExit;
3012         cbCur += cb;
3013         goto ErrExit;
3014     }
3015
3016     // Handle the underlying element types.
3017     if (ulData >= ELEMENT_TYPE_MAX) 
3018     {
3019         hr = E_FAIL;
3020         goto ErrExit;
3021     }
3022     while (ulData == ELEMENT_TYPE_PTR || ulData == ELEMENT_TYPE_BYREF)
3023     {
3024         IfFailGo(AddToSigBuffer(" "));
3025         IfFailGo(AddToSigBuffer(g_szMapElementType[ulData]));
3026         cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulData);
3027         cbCur += cb;
3028     }
3029     IfFailGo(AddToSigBuffer(" "));
3030     IfFailGo(AddToSigBuffer(g_szMapElementType[ulData]));
3031     if (CorIsPrimitiveType((CorElementType)ulData) || 
3032         ulData == ELEMENT_TYPE_TYPEDBYREF ||
3033         ulData == ELEMENT_TYPE_OBJECT ||
3034         ulData == ELEMENT_TYPE_I ||
3035         ulData == ELEMENT_TYPE_U)
3036     {
3037         // If this is a primitive type, we are done
3038         goto ErrExit;
3039     }
3040     if (ulData == ELEMENT_TYPE_VALUETYPE || 
3041         ulData == ELEMENT_TYPE_CLASS || 
3042         ulData == ELEMENT_TYPE_CMOD_REQD ||
3043         ulData == ELEMENT_TYPE_CMOD_OPT)
3044     {
3045         cb = CorSigUncompressToken(&pbSigBlob[cbCur], &tk);
3046         cbCur += cb;
3047
3048         // get the name of type ref. Don't care if truncated
3049         if (TypeFromToken(tk) == mdtTypeDef || TypeFromToken(tk) == mdtTypeRef)
3050         {
3051             sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, " %ls",TypeDeforRefName(tk, m_szTempBuf, NumItems(m_szTempBuf)));
3052             IfFailGo(AddToSigBuffer(m_tempFormatBuffer));
3053         }
3054         else
3055         {
3056             _ASSERTE(TypeFromToken(tk) == mdtTypeSpec);
3057             sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, " %8x", tk);
3058             IfFailGo(AddToSigBuffer(m_tempFormatBuffer));
3059         }
3060         if (ulData == ELEMENT_TYPE_CMOD_REQD ||
3061             ulData == ELEMENT_TYPE_CMOD_OPT)
3062         {
3063             if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb)))
3064                 goto ErrExit;
3065             cbCur += cb;
3066         }
3067
3068         goto ErrExit;
3069     }
3070     if (ulData == ELEMENT_TYPE_SZARRAY)
3071     {
3072         // display the base type of SZARRAY
3073         if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb)))
3074             goto ErrExit;
3075         cbCur += cb;
3076         goto ErrExit;
3077     }
3078     // instantiated type
3079     if (ulData == ELEMENT_TYPE_GENERICINST)
3080     {
3081         // display the type constructor
3082         if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb)))
3083             goto ErrExit;        
3084         cbCur += cb;
3085         ULONG numArgs;
3086         cb = CorSigUncompressData(&pbSigBlob[cbCur], &numArgs);
3087         cbCur += cb;
3088         IfFailGo(AddToSigBuffer("<"));
3089
3090         while (numArgs > 0) 
3091         {
3092             if (cbCur > ulSigBlob)
3093                 goto ErrExit;
3094             if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb)))
3095                 goto ErrExit;
3096             cbCur += cb;
3097             --numArgs;
3098             if (numArgs > 0) 
3099                       IfFailGo(AddToSigBuffer(","));
3100         }
3101         IfFailGo(AddToSigBuffer(">"));
3102             goto ErrExit;
3103     }
3104     if (ulData == ELEMENT_TYPE_VAR)
3105     {
3106         ULONG index;
3107         cb = CorSigUncompressData(&pbSigBlob[cbCur], &index);
3108         cbCur += cb;
3109         sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, "!%d", index);
3110         IfFailGo(AddToSigBuffer(m_tempFormatBuffer));
3111         goto ErrExit;
3112     }
3113     if (ulData == ELEMENT_TYPE_MVAR)
3114     {
3115         ULONG index;
3116         cb = CorSigUncompressData(&pbSigBlob[cbCur], &index);
3117         cbCur += cb;
3118         sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, "!!%d", index);
3119         IfFailGo(AddToSigBuffer(m_tempFormatBuffer));
3120         goto ErrExit;
3121     }
3122     if (ulData == ELEMENT_TYPE_FNPTR) 
3123     {
3124         cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulData);
3125         cbCur += cb;
3126         if (ulData & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS)
3127             IfFailGo(AddToSigBuffer(" explicit"));
3128         if (ulData & IMAGE_CEE_CS_CALLCONV_HASTHIS)
3129             IfFailGo(AddToSigBuffer(" hasThis"));
3130
3131         IfFailGo(AddToSigBuffer(" "));
3132         IfFailGo(AddToSigBuffer(g_strCalling[ulData & IMAGE_CEE_CS_CALLCONV_MASK]));
3133
3134             // Get number of args
3135         ULONG numArgs;
3136         cb = CorSigUncompressData(&pbSigBlob[cbCur], &numArgs);
3137         cbCur += cb;
3138
3139             // do return type
3140         if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb)))
3141             goto ErrExit;
3142         cbCur += cb;
3143
3144         IfFailGo(AddToSigBuffer("("));
3145         while (numArgs > 0) 
3146         {
3147             if (cbCur > ulSigBlob)
3148                 goto ErrExit;
3149             if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb)))
3150                 goto ErrExit;
3151             cbCur += cb;
3152             --numArgs;
3153             if (numArgs > 0) 
3154                 IfFailGo(AddToSigBuffer(","));
3155         }
3156         IfFailGo(AddToSigBuffer(" )"));
3157         goto ErrExit;
3158     }
3159
3160     if(ulData != ELEMENT_TYPE_ARRAY) return E_FAIL;
3161
3162     // display the base type of SDARRAY
3163     if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb)))
3164         goto ErrExit;
3165     cbCur += cb;
3166
3167     // display the rank of MDARRAY
3168     cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulData);
3169     cbCur += cb;
3170     sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, " %d", ulData);
3171     IfFailGo(AddToSigBuffer(m_tempFormatBuffer));
3172     if (ulData == 0)
3173         // we are done if no rank specified
3174         goto ErrExit;
3175
3176     // how many dimensions have size specified?
3177     cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulData);
3178     cbCur += cb;
3179     sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, " %d", ulData);
3180     IfFailGo(AddToSigBuffer(m_tempFormatBuffer));
3181     while (ulData)
3182     {
3183         cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulTemp);
3184         sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, " %d", ulTemp);
3185         IfFailGo(AddToSigBuffer(m_tempFormatBuffer));
3186         cbCur += cb;
3187         ulData--;
3188     }
3189     // how many dimensions have lower bounds specified?
3190     cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulData);
3191     cbCur += cb;
3192     sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, " %d", ulData);
3193     IfFailGo(AddToSigBuffer(m_tempFormatBuffer));
3194     while (ulData)
3195     {
3196
3197         cb = CorSigUncompressSignedInt(&pbSigBlob[cbCur], &iTemp);
3198         sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, " %d", iTemp);
3199         IfFailGo(AddToSigBuffer(m_tempFormatBuffer));
3200         cbCur += cb;
3201         ulData--;
3202     }
3203     
3204 ErrExit:
3205     if (cbCur > ulSigBlob)
3206         hr = E_FAIL;
3207     *pcb = cbCur;
3208     return hr;
3209 } // HRESULT MDInfo::GetOneElementType()
3210
3211 // Display the fields of the N/Direct custom value structure.
3212
3213 void MDInfo::DisplayCorNativeLink(COR_NATIVE_LINK *pCorNLnk, const char *preFix)
3214 {
3215     // Print the LinkType.
3216     const char *curField = "\tLink Type : ";
3217     switch(pCorNLnk->m_linkType)
3218     {
3219     case nltNone:
3220         VWriteLine("%s%s%s(%02x)", preFix, curField, "nltNone", pCorNLnk->m_linkType);
3221         break;
3222     case nltAnsi:
3223         VWriteLine("%s%s%s(%02x)", preFix, curField, "nltAnsi", pCorNLnk->m_linkType);
3224         break;
3225     case nltUnicode:
3226         VWriteLine("%s%s%s(%02x)", preFix, curField, "nltUnicode", pCorNLnk->m_linkType);
3227         break;
3228     case nltAuto:
3229         VWriteLine("%s%s%s(%02x)", preFix, curField, "nltAuto", pCorNLnk->m_linkType);
3230         break;
3231     default:
3232         _ASSERTE(!"Invalid Native Link Type!");
3233     }
3234
3235     // Print the link flags
3236     curField = "\tLink Flags : ";
3237     switch(pCorNLnk->m_flags)
3238     {
3239     case nlfNone:
3240         VWriteLine("%s%s%s(%02x)", preFix, curField, "nlfNone", pCorNLnk->m_flags);
3241         break;
3242     case nlfLastError:
3243         VWriteLine("%s%s%s(%02x)", preFix, curField, "nlfLastError", pCorNLnk->m_flags);
3244             break;
3245     default:
3246         _ASSERTE(!"Invalid Native Link Flags!");
3247     }
3248
3249     // Print the entry point.
3250     WCHAR memRefName[STRING_BUFFER_LEN];
3251     HRESULT hr;
3252     hr = m_pImport->GetMemberRefProps( pCorNLnk->m_entryPoint, NULL, memRefName,
3253                                     STRING_BUFFER_LEN, NULL, NULL, NULL);
3254     if (FAILED(hr)) Error("GetMemberRefProps failed.", hr);
3255     VWriteLine("%s\tEntry Point : %ls (0x%08x)", preFix, memRefName, pCorNLnk->m_entryPoint);
3256 } // void MDInfo::DisplayCorNativeLink()
3257
3258 // Fills given varaint with value given in pValue and of type in bCPlusTypeFlag
3259 //
3260 // Taken from MetaInternal.cpp
3261
3262 HRESULT _FillVariant(
3263     BYTE        bCPlusTypeFlag, 
3264     const void  *pValue,
3265     ULONG cbValue,
3266     VARIANT     *pvar) 
3267 {
3268     HRESULT     hr = NOERROR;
3269     switch (bCPlusTypeFlag)
3270     {
3271     case ELEMENT_TYPE_BOOLEAN:
3272         V_VT(pvar) = VT_BOOL;
3273         V_BOOL(pvar) = *((BYTE*)pValue); //*((UNALIGNED VARIANT_BOOL *)pValue);
3274         break;
3275     case ELEMENT_TYPE_I1:
3276         V_VT(pvar) = VT_I1;
3277         V_I1(pvar) = *((CHAR*)pValue);
3278         break;
3279     case ELEMENT_TYPE_U1:
3280         V_VT(pvar) = VT_UI1;
3281         V_UI1(pvar) = *((BYTE*)pValue);
3282         break;
3283     case ELEMENT_TYPE_I2:
3284         V_VT(pvar) = VT_I2;
3285         V_I2(pvar) = GET_UNALIGNED_VAL16(pValue);
3286         break;
3287     case ELEMENT_TYPE_U2:
3288     case ELEMENT_TYPE_CHAR:
3289         V_VT(pvar) = VT_UI2;
3290         V_UI2(pvar) = GET_UNALIGNED_VAL16(pValue);
3291         break;
3292     case ELEMENT_TYPE_I4:
3293         V_VT(pvar) = VT_I4;
3294         V_I4(pvar) = GET_UNALIGNED_VAL32(pValue);
3295         break;
3296     case ELEMENT_TYPE_U4:
3297         V_VT(pvar) = VT_UI4;
3298         V_UI4(pvar) = GET_UNALIGNED_VAL32(pValue);
3299         break;
3300     case ELEMENT_TYPE_R4:
3301         {
3302             V_VT(pvar) = VT_R4;
3303             __int32 Value = GET_UNALIGNED_VAL32(pValue);
3304             V_R4(pvar) = (float &)Value;
3305         }
3306         break;
3307     case ELEMENT_TYPE_R8:
3308         {
3309             V_VT(pvar) = VT_R8;
3310             __int64 Value = GET_UNALIGNED_VAL64(pValue);
3311             V_R8(pvar) = (double &) Value;
3312         }
3313
3314         break;
3315     case ELEMENT_TYPE_STRING:
3316         {
3317             V_VT(pvar) = VT_BSTR;
3318             WCHAR *TempString;;
3319 #if BIGENDIAN
3320             TempString = (WCHAR *)alloca(cbValue);
3321             memcpy(TempString, pValue, cbValue);
3322             SwapStringLength(TempString, cbValue/sizeof(WCHAR));
3323 #else
3324             TempString = (WCHAR *)pValue;
3325 #endif
3326             // allocated bstr here
3327             V_BSTR(pvar) = ::SysAllocStringLen((LPWSTR)TempString, cbValue/sizeof(WCHAR));
3328             if (V_BSTR(pvar) == NULL)
3329                 hr = E_OUTOFMEMORY;
3330         }
3331         break;
3332     case ELEMENT_TYPE_CLASS:
3333         V_VT(pvar) = VT_UNKNOWN;
3334         V_UNKNOWN(pvar) = NULL;
3335         // _ASSERTE( GET_UNALIGNED_VAL32(pValue) == 0);
3336         break;
3337     case ELEMENT_TYPE_I8:
3338         V_VT(pvar) = VT_I8;
3339         V_CY(pvar).int64 = GET_UNALIGNED_VAL64(pValue);
3340         break;
3341     case ELEMENT_TYPE_U8:
3342         V_VT(pvar) = VT_UI8;
3343         V_CY(pvar).int64 = GET_UNALIGNED_VAL64(pValue);
3344         break;
3345     case ELEMENT_TYPE_VOID:
3346         V_VT(pvar) = VT_EMPTY;
3347         break;
3348     default:
3349         _ASSERTE(!"bad constant value type!");
3350     }
3351
3352     return hr;
3353 } // HRESULT _FillVariant()
3354
3355 void MDInfo::DisplayAssembly()
3356 {
3357     if (m_pAssemblyImport) 
3358     {
3359         DisplayAssemblyInfo();
3360         DisplayAssemblyRefs();
3361         DisplayFiles();
3362         DisplayExportedTypes();
3363         DisplayManifestResources();
3364     }
3365 } // void MDInfo::DisplayAssembly()
3366
3367 void MDInfo::DisplayAssemblyInfo()
3368 {
3369     HRESULT         hr;
3370     mdAssembly      mda;
3371     const BYTE      *pbPublicKey;
3372     ULONG           cbPublicKey;
3373     ULONG           ulHashAlgId;
3374     WCHAR           szName[STRING_BUFFER_LEN];
3375     ASSEMBLYMETADATA MetaData;
3376     DWORD           dwFlags;
3377
3378     hr = m_pAssemblyImport->GetAssemblyFromScope(&mda);
3379     if (hr == CLDB_E_RECORD_NOTFOUND)
3380         return;
3381     else if (FAILED(hr)) Error("GetAssemblyFromScope() failed.", hr);
3382
3383     // Get the required sizes for the arrays of locales, processors etc.
3384     ZeroMemory(&MetaData, sizeof(ASSEMBLYMETADATA));
3385     hr = m_pAssemblyImport->GetAssemblyProps(mda, 
3386                                              NULL, NULL,    // Public Key.
3387                                              NULL,          // Hash Algorithm.
3388                                              NULL, 0, NULL, // Name.
3389                                              &MetaData,
3390                                              NULL);         // Flags.
3391     if (FAILED(hr)) Error("GetAssemblyProps() failed.", hr);
3392
3393     // Allocate space for the arrays in the ASSEMBLYMETADATA structure.
3394     if (MetaData.cbLocale)
3395         MetaData.szLocale = new WCHAR[MetaData.cbLocale];
3396     if (MetaData.ulProcessor)
3397         MetaData.rProcessor = new DWORD[MetaData.ulProcessor];
3398     if (MetaData.ulOS)
3399         MetaData.rOS = new OSINFO[MetaData.ulOS];
3400
3401     hr = m_pAssemblyImport->GetAssemblyProps(mda, 
3402                                              (const void **)&pbPublicKey, &cbPublicKey,
3403                                              &ulHashAlgId,
3404                                              szName, STRING_BUFFER_LEN, NULL,
3405                                              &MetaData,
3406                                              &dwFlags);
3407     if (FAILED(hr)) Error("GetAssemblyProps() failed.", hr);
3408     WriteLine("Assembly");
3409     WriteLine("-------------------------------------------------------");
3410     VWriteLine("\tToken: 0x%08x", mda);
3411     VWriteLine("\tName : %ls", szName);
3412     DumpHex("\tPublic Key    ", pbPublicKey, cbPublicKey, false, 24);
3413     VWriteLine("\tHash Algorithm : 0x%08x", ulHashAlgId);
3414     DisplayASSEMBLYMETADATA(&MetaData);
3415     if(MetaData.szLocale) delete [] MetaData.szLocale;
3416     if(MetaData.rProcessor) delete [] MetaData.rProcessor;
3417     if(MetaData.rOS) delete [] MetaData.rOS;
3418     
3419     char sFlags[STRING_BUFFER_LEN];
3420     DWORD flags = dwFlags;
3421
3422     sFlags[0] = 0;
3423     ISFLAG(Af, PublicKey);
3424     ISFLAG(Af, Retargetable);
3425     ISFLAG(AfContentType_, WindowsRuntime);
3426
3427     if (!*sFlags)
3428         strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]");
3429
3430     VWriteLine("\tFlags : %s (%08x)", sFlags, dwFlags);
3431     DisplayCustomAttributes(mda, "\t");
3432     DisplayPermissions(mda, "\t");
3433     WriteLine("");
3434 }   // void MDInfo::DisplayAssemblyInfo()
3435
3436 void MDInfo::DisplayAssemblyRefs()
3437 {
3438     HCORENUM        assemblyRefEnum = NULL;
3439     mdAssemblyRef   AssemblyRefs[ENUM_BUFFER_SIZE];
3440     ULONG           count;
3441     ULONG           totalCount = 1;
3442     HRESULT         hr;
3443
3444     while (SUCCEEDED(hr = m_pAssemblyImport->EnumAssemblyRefs( &assemblyRefEnum,
3445                              AssemblyRefs, NumItems(AssemblyRefs), &count)) &&
3446             count > 0)
3447     {
3448         for (ULONG i = 0; i < count; i++, totalCount++)
3449         {
3450             VWriteLine("AssemblyRef #%d (%08x)", totalCount, AssemblyRefs[i]);
3451             WriteLine("-------------------------------------------------------");
3452             DisplayAssemblyRefInfo(AssemblyRefs[i]);
3453             WriteLine("");
3454         }
3455     }
3456     m_pAssemblyImport->CloseEnum(assemblyRefEnum);
3457 }   // void MDInfo::DisplayAssemblyRefs()
3458
3459 void MDInfo::DisplayAssemblyRefInfo(mdAssemblyRef inAssemblyRef)
3460 {
3461     HRESULT         hr;
3462     const BYTE      *pbPublicKeyOrToken;
3463     ULONG           cbPublicKeyOrToken;
3464     WCHAR           szName[STRING_BUFFER_LEN];
3465     ASSEMBLYMETADATA MetaData;
3466     const BYTE      *pbHashValue;
3467     ULONG           cbHashValue;
3468     DWORD           dwFlags;
3469     
3470     VWriteLine("\tToken: 0x%08x", inAssemblyRef);
3471
3472     // Get sizes for the arrays in the ASSEMBLYMETADATA structure.
3473     ZeroMemory(&MetaData, sizeof(ASSEMBLYMETADATA));
3474     hr = m_pAssemblyImport->GetAssemblyRefProps(inAssemblyRef,
3475                                              NULL, NULL,    // Public Key or Token.
3476                                              NULL, 0, NULL, // Name.
3477                                              &MetaData,
3478                                              NULL, NULL,    // HashValue.
3479                                              NULL);         // Flags.
3480     if (FAILED(hr)) Error("GetAssemblyRefProps() failed.", hr);
3481     
3482     // Allocate space for the arrays in the ASSEMBLYMETADATA structure.
3483     if (MetaData.cbLocale)
3484         MetaData.szLocale = new WCHAR[MetaData.cbLocale];
3485     if (MetaData.ulProcessor)
3486         MetaData.rProcessor = new DWORD[MetaData.ulProcessor];
3487     if (MetaData.ulOS)
3488         MetaData.rOS = new OSINFO[MetaData.ulOS];
3489
3490     hr = m_pAssemblyImport->GetAssemblyRefProps(inAssemblyRef,
3491                                              (const void **)&pbPublicKeyOrToken, &cbPublicKeyOrToken,
3492                                              szName, STRING_BUFFER_LEN, NULL,
3493                                              &MetaData,
3494                                              (const void **)&pbHashValue, &cbHashValue,
3495                                              &dwFlags);
3496     if (FAILED(hr)) Error("GetAssemblyRefProps() failed.", hr);
3497
3498     DumpHex("\tPublic Key or Token", pbPublicKeyOrToken, cbPublicKeyOrToken, false, 24);
3499     VWriteLine("\tName: %ls", szName);
3500     DisplayASSEMBLYMETADATA(&MetaData);
3501     if(MetaData.szLocale) delete [] MetaData.szLocale;
3502     if(MetaData.rProcessor) delete [] MetaData.rProcessor;
3503     if(MetaData.rOS) delete [] MetaData.rOS;
3504     DumpHex("\tHashValue Blob", pbHashValue, cbHashValue, false, 24);
3505
3506     char sFlags[STRING_BUFFER_LEN];
3507     DWORD flags = dwFlags;
3508
3509     sFlags[0] = 0;
3510     ISFLAG(Af, PublicKey);   
3511     ISFLAG(Af, Retargetable);
3512     ISFLAG(AfContentType_, WindowsRuntime);
3513 #if 0
3514     ISFLAG(Af, LegacyLibrary);
3515     ISFLAG(Af, LegacyPlatform);
3516     ISFLAG(Af, Library);
3517     ISFLAG(Af, Platform);
3518 #endif
3519     if (!*sFlags)
3520         strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]");
3521
3522     VWriteLine("\tFlags: %s (%08x)", sFlags, dwFlags);
3523     DisplayCustomAttributes(inAssemblyRef, "\t");
3524     WriteLine("");
3525 }   // void MDInfo::DisplayAssemblyRefInfo()
3526
3527 void MDInfo::DisplayFiles()
3528 {
3529     HCORENUM        fileEnum = NULL;
3530     mdFile          Files[ENUM_BUFFER_SIZE];
3531     ULONG           count;
3532     ULONG           totalCount = 1;
3533     HRESULT         hr;
3534
3535     while (SUCCEEDED(hr = m_pAssemblyImport->EnumFiles( &fileEnum,
3536                              Files, NumItems(Files), &count)) &&
3537             count > 0)
3538     {
3539         for (ULONG i = 0; i < count; i++, totalCount++)
3540         {
3541             VWriteLine("File #%d (%08x)", totalCount, Files[i]);
3542             WriteLine("-------------------------------------------------------");
3543             DisplayFileInfo(Files[i]);
3544             WriteLine("");
3545         }
3546     }
3547     m_pAssemblyImport->CloseEnum(fileEnum);
3548 }   // void MDInfo::DisplayFiles()
3549
3550 void MDInfo::DisplayFileInfo(mdFile inFile)
3551 {
3552     HRESULT         hr;
3553     WCHAR           szName[STRING_BUFFER_LEN];
3554     const BYTE      *pbHashValue;
3555     ULONG           cbHashValue;
3556     DWORD           dwFlags;
3557
3558     VWriteLine("\tToken: 0x%08x", inFile);
3559
3560     hr = m_pAssemblyImport->GetFileProps(inFile,
3561                                          szName, STRING_BUFFER_LEN, NULL,
3562                                          (const void **)&pbHashValue, &cbHashValue,
3563                                          &dwFlags);
3564     if (FAILED(hr)) Error("GetFileProps() failed.", hr);
3565     VWriteLine("\tName : %ls", szName);
3566     DumpHex("\tHashValue Blob ", pbHashValue, cbHashValue, false, 24);
3567
3568     char sFlags[STRING_BUFFER_LEN];
3569     DWORD flags = dwFlags;
3570
3571     sFlags[0] = 0;
3572     ISFLAG(Ff, ContainsMetaData);      
3573     ISFLAG(Ff, ContainsNoMetaData);      
3574     if (!*sFlags)
3575         strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]");
3576
3577     VWriteLine("\tFlags : %s (%08x)", sFlags, dwFlags);
3578     DisplayCustomAttributes(inFile, "\t");
3579     WriteLine("");
3580
3581 }   // MDInfo::DisplayFileInfo()
3582
3583 void MDInfo::DisplayExportedTypes()
3584 {
3585     HCORENUM        comTypeEnum = NULL;
3586     mdExportedType       ExportedTypes[ENUM_BUFFER_SIZE];
3587     ULONG           count;
3588     ULONG           totalCount = 1;
3589     HRESULT         hr;
3590
3591     while (SUCCEEDED(hr = m_pAssemblyImport->EnumExportedTypes( &comTypeEnum,
3592                              ExportedTypes, NumItems(ExportedTypes), &count)) &&
3593             count > 0)
3594     {
3595         for (ULONG i = 0; i < count; i++, totalCount++)
3596         {
3597             VWriteLine("ExportedType #%d (%08x)", totalCount, ExportedTypes[i]);
3598             WriteLine("-------------------------------------------------------");
3599             DisplayExportedTypeInfo(ExportedTypes[i]);
3600             WriteLine("");
3601         }
3602     }
3603     m_pAssemblyImport->CloseEnum(comTypeEnum);
3604 }   // void MDInfo::DisplayExportedTypes()
3605
3606 void MDInfo::DisplayExportedTypeInfo(mdExportedType inExportedType)
3607 {
3608     HRESULT         hr;
3609     WCHAR           szName[STRING_BUFFER_LEN];
3610     mdToken         tkImplementation;
3611     mdTypeDef       tkTypeDef;
3612     DWORD           dwFlags;
3613     char            sFlags[STRING_BUFFER_LEN];
3614
3615     VWriteLine("\tToken: 0x%08x", inExportedType);
3616
3617     hr = m_pAssemblyImport->GetExportedTypeProps(inExportedType,
3618                                             szName, STRING_BUFFER_LEN, NULL,
3619                                             &tkImplementation,
3620                                             &tkTypeDef,
3621                                             &dwFlags);
3622     if (FAILED(hr)) Error("GetExportedTypeProps() failed.", hr);
3623     VWriteLine("\tName: %ls", szName);
3624     VWriteLine("\tImplementation token: 0x%08x", tkImplementation);
3625     VWriteLine("\tTypeDef token: 0x%08x", tkTypeDef);
3626     VWriteLine("\tFlags     : %s (%08x)",ClassFlags(dwFlags, sFlags), dwFlags);
3627     DisplayCustomAttributes(inExportedType, "\t");
3628     WriteLine("");
3629 }   // void MDInfo::DisplayExportedTypeInfo()
3630
3631 void MDInfo::DisplayManifestResources()
3632 {
3633     HCORENUM        manifestResourceEnum = NULL;
3634     mdManifestResource ManifestResources[ENUM_BUFFER_SIZE];
3635     ULONG           count;
3636     ULONG           totalCount = 1;
3637     HRESULT         hr;
3638
3639     while (SUCCEEDED(hr = m_pAssemblyImport->EnumManifestResources( &manifestResourceEnum,
3640                              ManifestResources, NumItems(ManifestResources), &count)) &&
3641             count > 0)
3642     {
3643         for (ULONG i = 0; i < count; i++, totalCount++)
3644         {
3645             VWriteLine("ManifestResource #%d (%08x)", totalCount, ManifestResources[i]);
3646             WriteLine("-------------------------------------------------------");
3647             DisplayManifestResourceInfo(ManifestResources[i]);
3648             WriteLine("");
3649         }
3650     }
3651     m_pAssemblyImport->CloseEnum(manifestResourceEnum);
3652 }   // void MDInfo::DisplayManifestResources()
3653
3654 void MDInfo::DisplayManifestResourceInfo(mdManifestResource inManifestResource)
3655 {
3656     HRESULT         hr;
3657     WCHAR           szName[STRING_BUFFER_LEN];
3658     mdToken         tkImplementation;
3659     DWORD           dwOffset;
3660     DWORD           dwFlags;
3661
3662     VWriteLine("\tToken: 0x%08x", inManifestResource);
3663
3664     hr = m_pAssemblyImport->GetManifestResourceProps(inManifestResource,
3665                                                      szName, STRING_BUFFER_LEN, NULL,
3666                                                      &tkImplementation,
3667                                                      &dwOffset,
3668                                                      &dwFlags);
3669     if (FAILED(hr)) Error("GetManifestResourceProps() failed.", hr);
3670     VWriteLine("Name: %ls", szName);
3671     VWriteLine("Implementation token: 0x%08x", tkImplementation);
3672     VWriteLine("Offset: 0x%08x", dwOffset);
3673
3674     char sFlags[STRING_BUFFER_LEN];
3675     DWORD flags = dwFlags;
3676
3677     sFlags[0] = 0;
3678     ISFLAG(Mr, Public);     
3679     ISFLAG(Mr, Private);            
3680     if (!*sFlags)
3681         strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]");
3682
3683     VWriteLine("\tFlags: %s (%08x)", sFlags, dwFlags);
3684     DisplayCustomAttributes(inManifestResource, "\t");
3685     WriteLine("");
3686 }   // void MDInfo::DisplayManifestResourceInfo()
3687
3688 void MDInfo::DisplayASSEMBLYMETADATA(ASSEMBLYMETADATA *pMetaData)
3689 {
3690     ULONG           i;
3691
3692     VWriteLine("\tVersion: %d.%d.%d.%d", pMetaData->usMajorVersion, pMetaData->usMinorVersion, pMetaData->usBuildNumber, pMetaData->usRevisionNumber);
3693     VWriteLine("\tMajor Version: 0x%08x", pMetaData->usMajorVersion);
3694     VWriteLine("\tMinor Version: 0x%08x", pMetaData->usMinorVersion);
3695     VWriteLine("\tBuild Number: 0x%08x", pMetaData->usBuildNumber);
3696     VWriteLine("\tRevision Number: 0x%08x", pMetaData->usRevisionNumber);
3697     VWriteLine("\tLocale: %ls", pMetaData->cbLocale ? pMetaData->szLocale : W("<null>"));
3698     for (i = 0; i < pMetaData->ulProcessor; i++)
3699         VWriteLine("\tProcessor #%ld: 0x%08x", i+1, pMetaData->rProcessor[i]);
3700     for (i = 0; i < pMetaData->ulOS; i++)
3701     {
3702         VWriteLine("\tOS #%ld:", i+1);
3703         VWriteLine("\t\tOS Platform ID: 0x%08x", pMetaData->rOS[i].dwOSPlatformId);
3704         VWriteLine("\t\tOS Major Version: 0x%08x", pMetaData->rOS[i].dwOSMajorVersion);
3705         VWriteLine("\t\tOS Minor Version: 0x%08x", pMetaData->rOS[i].dwOSMinorVersion);
3706     }
3707 }   // void MDInfo::DisplayASSEMBLYMETADATA()
3708
3709 void MDInfo::DisplayUserStrings()
3710 {
3711     HCORENUM    stringEnum = NULL;      // string enumerator.
3712     mdString    Strings[ENUM_BUFFER_SIZE]; // String tokens from enumerator.
3713     CQuickArray<WCHAR> rUserString;     // Buffer to receive string.
3714     WCHAR       *szUserString;          // Working pointer into buffer.
3715     ULONG       chUserString;           // Size of user string.
3716     CQuickArray<char> rcBuf;            // Buffer to hold the BLOB version of the string.
3717     char        *szBuf;                 // Working pointer into buffer.
3718     ULONG       chBuf;                  // Saved size of the user string.
3719     ULONG       count;                  // Items returned from enumerator.
3720     ULONG       totalCount = 1;         // Running count of strings.
3721     bool        bUnprint = false;       // Is an unprintable character found?
3722     HRESULT     hr;                     // A result.
3723     while (SUCCEEDED(hr = m_pImport->EnumUserStrings( &stringEnum,
3724                              Strings, NumItems(Strings), &count)) &&
3725             count > 0)
3726     {
3727         if (totalCount == 1)
3728         {   // If only one, it is the NULL string, so don't print it.
3729             WriteLine("User Strings");
3730             WriteLine("-------------------------------------------------------");
3731         }
3732         for (ULONG i = 0; i < count; i++, totalCount++)
3733         {
3734             do { // Try to get the string into the existing buffer.
3735                 hr = m_pImport->GetUserString( Strings[i], rUserString.Ptr(),(ULONG32)rUserString.MaxSize(), &chUserString);
3736                 if (hr == CLDB_S_TRUNCATION)
3737                 {   // Buffer wasn't big enough, try to enlarge it.
3738                     if (FAILED(rUserString.ReSizeNoThrow(chUserString)))
3739                         Error("malloc failed.", E_OUTOFMEMORY);
3740                     continue;
3741                 }
3742             } while (hr == CLDB_S_TRUNCATION);
3743             if (FAILED(hr)) Error("GetUserString failed.", hr);
3744
3745             szUserString = rUserString.Ptr();
3746             chBuf = chUserString;
3747
3748             VWrite("%08x : (%2d) L\"", Strings[i], chUserString);
3749             for (ULONG j=0; j<chUserString; j++)
3750             {   
3751                 switch (*szUserString)
3752                 {
3753                 case 0:
3754                     Write("\\0"); break;
3755                 case L'\r':
3756                     Write("\\r"); break;
3757                 case L'\n':
3758                     Write("\\n"); break;
3759                 case L'\t':
3760                     Write("\\t"); break;
3761                 default:
3762                     if (iswprint(*szUserString))
3763                         VWrite("%lc", *szUserString);
3764                     else 
3765                     {
3766                         bUnprint = true;
3767                         Write(".");
3768                     }
3769                     break;
3770                 }
3771                 ++szUserString;
3772                 if((j>0)&&((j&0x7F)==0)) WriteLine("");
3773             }
3774             WriteLine("\"");
3775
3776             // Print the user string as a blob if an unprintable character is found.
3777             if (bUnprint)
3778             {
3779                 bUnprint = false;
3780                 szUserString = rUserString.Ptr();
3781                 if (FAILED(hr = rcBuf.ReSizeNoThrow(81))) //(chBuf * 5 + 1);
3782                     Error("ReSize failed.", hr);
3783                 szBuf = rcBuf.Ptr();
3784                 ULONG j,k;
3785                 WriteLine("\t\tUser string has unprintables, hex format below:");
3786                 for (j = 0,k=0; j < chBuf; j++)
3787                 {
3788                     sprintf_s (&szBuf[k*5], 81, "%04x ", szUserString[j]);
3789                     k++;
3790                     if((k==16)||(j == (chBuf-1)))
3791                     {
3792                         szBuf[k*5] = '\0';
3793                         VWriteLine("\t\t%s", szBuf);
3794                         k=0;
3795                     }
3796                 }
3797             }
3798         }
3799     }
3800     if (stringEnum)
3801         m_pImport->CloseEnum(stringEnum);
3802 }   // void MDInfo::DisplayUserStrings()
3803
3804 void MDInfo::DisplayUnsatInfo()
3805 {
3806     HRESULT     hr = S_OK;
3807
3808     HCORENUM henum = 0;
3809     mdToken  tk;
3810     ULONG cMethods;
3811
3812     Write("\nUnresolved Externals\n");
3813     Write("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
3814
3815     while ( (hr = m_pImport->EnumUnresolvedMethods(
3816         &henum, 
3817         &tk, 
3818         1, 
3819         &cMethods)) == S_OK && cMethods )
3820     {
3821         if ( TypeFromToken(tk) == mdtMethodDef )
3822         {
3823             // a method definition without implementation
3824             DisplayMethodInfo( tk );
3825         }
3826         else if ( TypeFromToken(tk) == mdtMemberRef )
3827         {
3828             // an unresolved MemberRef to a global function 
3829             DisplayMemberRefInfo( tk, "" );
3830         }
3831         else
3832         { 
3833             _ASSERTE(!"Unknown token kind!");
3834         }
3835     }
3836     m_pImport->CloseEnum(henum);
3837 } // void MDInfo::DisplayUnsatInfo()
3838
3839 //*******************************************************************************
3840 // This code is used for debugging purposes only.  This will just print out the
3841 // entire database.
3842 //*******************************************************************************
3843 const char *MDInfo::DumpRawNameOfType(ULONG iType)
3844 {
3845     if (iType <= iRidMax)
3846     {
3847         const char *pNameTable;
3848         m_pTables->GetTableInfo(iType, 0,0,0,0, &pNameTable);
3849         return pNameTable;
3850     }
3851     else
3852     // Is the field a coded token?
3853     if (iType <= iCodedTokenMax)
3854     {
3855         int iCdTkn = iType - iCodedToken;
3856         const char *pNameCdTkn;
3857         m_pTables->GetCodedTokenInfo(iCdTkn, 0,0, &pNameCdTkn);
3858         return pNameCdTkn;
3859     }
3860
3861     // Fixed type.
3862     switch (iType)
3863     {
3864     case iBYTE:
3865         return "BYTE";
3866     case iSHORT:
3867         return "short";
3868     case iUSHORT:
3869         return "USHORT";
3870     case iLONG:
3871         return "long";
3872     case iULONG:
3873         return "ULONG";
3874     case iSTRING:
3875         return "string";
3876     case iGUID:
3877         return "GUID";
3878     case iBLOB:
3879         return "blob";
3880     }
3881     // default:
3882     static char buf[30];
3883     sprintf_s(buf, 30, "unknown type 0x%02x", iType);
3884     return buf;
3885 } // const char *MDInfo::DumpRawNameOfType()
3886
3887 void MDInfo::DumpRawCol(ULONG ixTbl, ULONG ixCol, ULONG rid, bool bStats)
3888 {
3889     ULONG       ulType;                 // Type of a column.
3890     ULONG       ulVal;                  // Value of a column.
3891     LPCUTF8     pString;                // Pointer to a string.
3892     const void  *pBlob;                 // Pointer to a blob.
3893     ULONG       cb;                     // Size of something.
3894
3895     m_pTables->GetColumn(ixTbl, ixCol, rid, &ulVal);
3896     m_pTables->GetColumnInfo(ixTbl, ixCol, 0, 0, &ulType, 0);
3897
3898     if (ulType <= iRidMax)
3899     {
3900         const char *pNameTable;
3901         m_pTables->GetTableInfo(ulType, 0,0,0,0, &pNameTable);
3902         VWrite("%s[%x]", pNameTable, ulVal);
3903     }
3904     else
3905     // Is the field a coded token?
3906     if (ulType <= iCodedTokenMax)
3907     {
3908         int iCdTkn = ulType - iCodedToken; 
3909         const char *pNameCdTkn;
3910         m_pTables->GetCodedTokenInfo(iCdTkn, 0,0, &pNameCdTkn);
3911         VWrite("%s[%08x]", pNameCdTkn, ulVal);
3912     }
3913     else
3914     {
3915         // Fixed type.
3916         switch (ulType)
3917         {
3918         case iBYTE:
3919             VWrite("%02x", ulVal);
3920             break;
3921         case iSHORT:
3922         case iUSHORT:
3923             VWrite("%04x", ulVal);
3924             break;
3925         case iLONG:
3926         case iULONG:
3927             VWrite("%08x", ulVal);
3928             break;
3929         case iSTRING:
3930             if (ulVal && (m_DumpFilter & dumpNames))
3931             {
3932                 m_pTables->GetString(ulVal, &pString);
3933                 VWrite("(%x)\"%s\"", ulVal, pString);
3934             }
3935             else
3936                 VWrite("string#%x", ulVal);
3937             if (bStats && ulVal)
3938             {
3939                 m_pTables->GetString(ulVal, &pString);
3940                 cb = (ULONG) strlen(pString) + 1;
3941                 VWrite("(%d)", cb);
3942             }
3943             break;
3944         case iGUID:
3945             VWrite("guid#%x", ulVal);
3946             if (bStats && ulVal)
3947             {
3948                 VWrite("(16)");
3949             }
3950             break;
3951         case iBLOB:
3952             VWrite("blob#%x", ulVal);
3953             if (bStats && ulVal)
3954             {
3955                 m_pTables->GetBlob(ulVal, &cb, &pBlob);
3956                 cb += 1;
3957                 if (cb > 128)
3958                     cb += 1;
3959                 if (cb > 16535)
3960                     cb += 1;
3961                 VWrite("(%d)", cb);
3962             }
3963             break;
3964         default:
3965             VWrite("unknown type 0x%04x", ulVal);
3966             break;
3967         }
3968     }
3969 } // void MDInfo::DumpRawCol()
3970
3971 ULONG MDInfo::DumpRawColStats(ULONG ixTbl, ULONG ixCol, ULONG cRows)
3972 {
3973     ULONG rslt = 0;
3974     ULONG       ulType;                 // Type of a column.
3975     ULONG       ulVal;                  // Value of a column.
3976     LPCUTF8     pString;                // Pointer to a string.
3977     const void  *pBlob;                 // Pointer to a blob.
3978     ULONG       cb;                     // Size of something.
3979
3980     m_pTables->GetColumnInfo(ixTbl, ixCol, 0, 0, &ulType, 0);
3981
3982     if (IsHeapType(ulType))
3983     {
3984         for (ULONG rid=1; rid<=cRows; ++rid)
3985         {
3986             m_pTables->GetColumn(ixTbl, ixCol, rid, &ulVal);
3987             // Fixed type.
3988             switch (ulType)
3989             {
3990             case iSTRING:
3991                 if (ulVal)
3992                 {
3993                     m_pTables->GetString(ulVal, &pString);
3994                     cb = (ULONG) strlen(pString);
3995                     rslt += cb + 1;
3996                 }
3997                 break;
3998             case iGUID:
3999                 if (ulVal)
4000                     rslt += 16;
4001                 break;
4002             case iBLOB:
4003                 if (ulVal)
4004                 {
4005                     m_pTables->GetBlob(ulVal, &cb, &pBlob);
4006                     rslt += cb + 1;
4007                     if (cb > 128)
4008                         rslt += 1;
4009                     if (cb > 16535)
4010                         rslt += 1;
4011                 }
4012                 break;
4013             default:
4014                 break;
4015             }
4016         }
4017     }
4018     return rslt;
4019 } // ULONG MDInfo::DumpRawColStats()
4020
4021 int MDInfo::DumpHex(
4022     const char  *szPrefix,              // String prefix for first line.
4023     const void  *pvData,                // The data to print.
4024     ULONG       cbData,                 // Bytes of data to print.
4025     int         bText,                  // If true, also dump text.
4026     ULONG       nLine)                  // Bytes per line to print.
4027 {
4028     const BYTE  *pbData = static_cast<const BYTE*>(pvData);
4029     ULONG       i;                      // Loop control.
4030     ULONG       nPrint;                 // Number to print in an iteration.
4031     ULONG       nSpace;                 // Spacing calculations.
4032     ULONG       nPrefix;                // Size of the prefix.
4033     ULONG       nLines=0;               // Number of lines printed.
4034     const char  *pPrefix;               // For counting spaces in the prefix.
4035
4036     // Round down to 8 characters.
4037     nLine = nLine & ~0x7;
4038
4039     for (nPrefix=0, pPrefix=szPrefix; *pPrefix; ++pPrefix)
4040     {
4041         if (*pPrefix == '\t')
4042             nPrefix = (nPrefix + 8) & ~7;
4043         else
4044             ++nPrefix;
4045     }
4046     //nPrefix = strlen(szPrefix);
4047     do 
4048     {   // Write the line prefix.
4049         if (szPrefix)
4050             VWrite("%s:", szPrefix);
4051         else
4052             VWrite("%*s:", nPrefix, "");
4053         szPrefix = 0;
4054         ++nLines;
4055
4056         // Calculate spacing.
4057         nPrint = min(cbData, nLine);
4058         nSpace = nLine - nPrint;
4059
4060             // dump in hex.
4061         for(i=0; i<nPrint; i++)
4062             {
4063             if ((i&7) == 0)
4064                     Write(" ");
4065             VWrite("%02x ", pbData[i]);
4066             }
4067         if (bText)
4068         {
4069             // Space out to the text spot.
4070             if (nSpace)
4071                 VWrite("%*s", nSpace*3+nSpace/8, "");
4072             // Dump in text.
4073             Write(">");
4074             for(i=0; i<nPrint; i++)
4075                 VWrite("%c", (isprint(pbData[i])) ? pbData[i] : ' ');
4076             // Space out the text, and finish the line.
4077             VWrite("%*s<", nSpace, "");
4078         }
4079         VWriteLine("");
4080
4081         // Next data to print.
4082         cbData -= nPrint;
4083         pbData += nPrint;
4084         }
4085     while (cbData > 0);
4086
4087     return nLines;
4088 } // int MDInfo::DumpHex()
4089
4090 void MDInfo::DumpRawHeaps()
4091 {
4092     HRESULT     hr;                     // A result.
4093     ULONG       ulSize;                 // Bytes in a heap.
4094     const BYTE  *pData;                 // Pointer to a blob.
4095     ULONG       cbData;                 // Size of a blob.
4096     ULONG       oData;                  // Offset of current blob.
4097     char        rcPrefix[30];           // To format line prefix.
4098
4099     m_pTables->GetBlobHeapSize(&ulSize);
4100     VWriteLine("");
4101     VWriteLine("Blob Heap:  %d(%#x) bytes", ulSize,ulSize);
4102     oData = 0;
4103     do 
4104     {
4105         m_pTables->GetBlob(oData, &cbData, (const void**)&pData);
4106         sprintf_s(rcPrefix, 30, "%5x,%-2x", oData, cbData);
4107         DumpHex(rcPrefix, pData, cbData);
4108         hr = m_pTables->GetNextBlob(oData, &oData);
4109     }
4110     while (hr == S_OK);
4111
4112     m_pTables->GetStringHeapSize(&ulSize);
4113     VWriteLine("");
4114     VWriteLine("String Heap:  %d(%#x) bytes", ulSize,ulSize);
4115     oData = 0;
4116     const char *pString;
4117     do 
4118     {
4119         m_pTables->GetString(oData, &pString);
4120         if (m_DumpFilter & dumpMoreHex)
4121         {
4122             sprintf_s(rcPrefix, 30, "%08x", oData);
4123             DumpHex(rcPrefix, pString, (ULONG)strlen(pString)+1);
4124         }
4125         else
4126         if (*pString != 0)
4127             VWrite("%08x: %s\n", oData, pString);
4128         hr = m_pTables->GetNextString(oData, &oData);
4129     }
4130     while (hr == S_OK);
4131     VWriteLine("");
4132     
4133     DisplayUserStrings();
4134
4135 } // void MDInfo::DumpRawHeaps()
4136
4137
4138 void MDInfo::DumpRaw(int iDump, bool bunused)
4139 {
4140     ULONG       cTables;                // Tables in the database.
4141     ULONG       cCols;                  // Columns in a table.
4142     ULONG       cRows;                  // Rows in a table.
4143     ULONG       cbRow;                  // Bytes in a row of a table.
4144     ULONG       iKey;                   // Key column of a table.
4145     const char  *pNameTable;            // Name of a table.
4146     ULONG       oCol;                   // Offset of a column.
4147     ULONG       cbCol;                  // Size of a column.
4148     ULONG       ulType;                 // Type of a column.
4149     const char  *pNameColumn;           // Name of a column.
4150     ULONG       ulSize;
4151
4152     // Heaps is easy -- there is a specific bit for that.
4153     bool        bStats = (m_DumpFilter & dumpStats) != 0;
4154     // Rows are harder.  Was there something else that limited data?
4155     BOOL        bRows = (m_DumpFilter & (dumpSchema | dumpHeader)) == 0;
4156     BOOL        bSchema = bRows || (m_DumpFilter & dumpSchema);
4157     // (m_DumpFilter & (dumpSchema | dumpHeader | dumpCSV | dumpRaw | dumpStats | dumpRawHeaps))
4158
4159     if (m_pTables2)
4160     {
4161         // Get the raw metadata header.
4162         const BYTE *pbData = NULL;
4163         const BYTE *pbStream = NULL;            // One of the stream.s
4164         const BYTE *pbMd = NULL;                // The metadata stream.
4165         ULONG cbData = 0;
4166         ULONG cbStream = 0;                     // One of the streams.
4167         ULONG cbMd = 0;                         // The metadata stream.
4168         const char *pName;
4169         HRESULT hr = S_OK;
4170         ULONG ix;
4171
4172         m_pTables2->GetMetaDataStorage((const void**)&pbData, &cbData);
4173
4174         // Per the ECMA spec, the section data looks like this:
4175         struct MDSTORAGESIGNATURE
4176         {
4177             ULONG       lSignature;             // "Magic" signature.
4178             USHORT      iMajorVer;              // Major file version.
4179             USHORT      iMinorVer;              // Minor file version.
4180             ULONG       iExtraData;             // Offset to next structure of information 
4181             ULONG       iVersionString;         // Length of version string
4182             BYTE        pVersion[0];            // Version string
4183         };
4184         struct MDSTORAGEHEADER
4185         {
4186             BYTE        fFlags;                 // STGHDR_xxx flags.
4187             BYTE        pad;
4188             USHORT      iStreams;               // How many streams are there.
4189         };
4190         const MDSTORAGESIGNATURE *pStorage = (const MDSTORAGESIGNATURE *) pbData;
4191         const MDSTORAGEHEADER *pSHeader = (const MDSTORAGEHEADER *)(pbData + sizeof(MDSTORAGESIGNATURE) + pStorage->iVersionString);
4192                     
4193         VWriteLine("Metadata section: 0x%08x, version: %d.%d, extra: %d, version len: %d, version: %s", pStorage->lSignature, pStorage->iMajorVer, pStorage->iMinorVer, pStorage->iExtraData, pStorage->iVersionString, pStorage->pVersion);
4194         VWriteLine("           flags: 0x%02x, streams: %d", pSHeader->fFlags, pSHeader->iStreams);
4195         if (m_DumpFilter & dumpMoreHex)
4196         {
4197             const BYTE *pbEnd = pbData;
4198             ULONG cb = sizeof(MDSTORAGESIGNATURE) + pStorage->iVersionString + sizeof(MDSTORAGEHEADER);
4199             hr = m_pTables2->GetMetaDataStreamInfo(0, &pName, (const void**)&pbEnd, &cbStream);
4200             if (hr == S_OK)
4201                 cb = (ULONG)(pbEnd - pbData);
4202             DumpHex("        ", pbData, cb);
4203         }
4204
4205         for (ix=0; hr == S_OK; ++ix)
4206         {
4207             hr = m_pTables2->GetMetaDataStreamInfo(ix, &pName, (const void**)&pbStream, &cbStream);
4208             if (hr != S_OK)
4209                 break;
4210             if (strcmp(pName, "#~") == 0 || strcmp(pName, "#-") == 0)
4211             {
4212                 pbMd = pbStream;
4213                 cbMd = cbStream;
4214             }
4215
4216             VWriteLine("Stream %d: name: %s, size %d", ix, pName, cbStream);
4217             // hex for individual stream headers in metadata section dump.  hex for
4218             //  the streams themselves distributed throughout the dump.
4219         }
4220
4221         if (pbMd)
4222         {
4223             // Per ECMA, the metadata header looks like this:
4224             struct MD
4225             {
4226                 ULONG       m_ulReserved;           // Reserved, must be zero.
4227                 BYTE        m_major;                // Version numbers.
4228                 BYTE        m_minor;
4229                 BYTE        m_heaps;                // Bits for heap sizes.
4230                 BYTE        m_rid;                  // log-base-2 of largest rid.
4231                 unsigned __int64    m_maskvalid;            // Bit mask of present table counts.
4232                 unsigned __int64    m_sorted;               // Bit mask of sorted tables.            };
4233             };
4234
4235             const MD *pMd;
4236             pMd = (const MD *)pbMd;
4237
4238             VWriteLine("Metadata header: %d.%d, heaps: 0x%02x, rid: 0x%02x, valid: 0x%016I64x, sorted: 0x%016I64x", 
4239                        pMd->m_major, pMd->m_minor, pMd->m_heaps, pMd->m_rid, 
4240                        (ULONGLONG)GET_UNALIGNED_VAL64(&(pMd->m_maskvalid)), 
4241                        (ULONGLONG)GET_UNALIGNED_VAL64(&(pMd->m_sorted)));
4242     
4243             if (m_DumpFilter & dumpMoreHex)
4244             {
4245                 DumpHex("        ", pbMd, sizeof(MD));
4246             }
4247         }
4248         VWriteLine("");
4249     }
4250
4251     m_pTables->GetNumTables(&cTables);
4252
4253     m_pTables->GetStringHeapSize(&ulSize);
4254     VWrite("Strings: %d(%#x)", ulSize, ulSize);
4255     m_pTables->GetBlobHeapSize(&ulSize);
4256     VWrite(", Blobs: %d(%#x)", ulSize, ulSize);
4257     m_pTables->GetGuidHeapSize(&ulSize);
4258     VWrite(", Guids: %d(%#x)", ulSize, ulSize);
4259     m_pTables->GetUserStringHeapSize(&ulSize);
4260     VWriteLine(", User strings: %d(%#x)", ulSize, ulSize);
4261
4262     for (ULONG ixTbl = 0; ixTbl < cTables; ++ixTbl)
4263     {
4264         m_pTables->GetTableInfo(ixTbl, &cbRow, &cRows, &cCols, &iKey, &pNameTable);
4265
4266         if (bRows) // when dumping rows, print a break between row data and schema
4267             VWriteLine("=================================================");
4268         VWriteLine("%2d(%#x): %-20s cRecs:%5d(%#x), cbRec:%3d(%#x), cbTable:%6d(%#x)",
4269             ixTbl, ixTbl, pNameTable, cRows, cRows, cbRow, cbRow, cbRow * cRows, cbRow * cRows);
4270
4271         if (!bSchema && !bRows)
4272             continue;
4273
4274         // Dump column definitions for the table.
4275         ULONG ixCol;
4276         for (ixCol=0; ixCol<cCols; ++ixCol)
4277         {
4278             m_pTables->GetColumnInfo(ixTbl, ixCol, &oCol, &cbCol, &ulType, &pNameColumn);
4279
4280             VWrite("  col %2x:%c %-12s oCol:%2x, cbCol:%x, %-7s",
4281                 ixCol, ((ixCol==iKey)?'*':' '), pNameColumn, oCol, cbCol, DumpRawNameOfType(ulType));
4282
4283             if (bStats)
4284             {
4285                 ulSize = DumpRawColStats(ixTbl, ixCol, cRows);
4286                 if (ulSize)
4287                     VWrite("(%d)", ulSize);
4288             }
4289             VWriteLine("");
4290         }
4291
4292         if (!bRows) 
4293             continue;
4294
4295         // Dump the rows.
4296         for (ULONG rid = 1; rid <= cRows; ++rid)
4297         {
4298             if (rid == 1)
4299                 VWriteLine("-------------------------------------------------");
4300             VWrite(" %3x == ", rid);
4301             for (ixCol=0; ixCol < cCols; ++ixCol)
4302             {
4303                 if (ixCol) VWrite(", ");
4304                 VWrite("%d:", ixCol);
4305                 DumpRawCol(ixTbl, ixCol, rid, bStats);
4306             }
4307             VWriteLine("");
4308         }
4309     }
4310 } // void MDInfo::DumpRaw()
4311
4312 void MDInfo::DumpRawCSV()
4313 {
4314     ULONG       cTables;                // Tables in the database.
4315     ULONG       cCols;                  // Columns in a table.
4316     ULONG       cRows;                  // Rows in a table.
4317     ULONG       cbRow;                  // Bytes in a row of a table.
4318     const char  *pNameTable;            // Name of a table.
4319     ULONG       ulSize;
4320
4321     m_pTables->GetNumTables(&cTables);
4322
4323     VWriteLine("Name,Size,cRecs,cbRec");
4324
4325     m_pTables->GetStringHeapSize(&ulSize);
4326     VWriteLine("Strings,%d", ulSize);
4327
4328     m_pTables->GetBlobHeapSize(&ulSize);
4329     VWriteLine("Blobs,%d", ulSize);
4330
4331     m_pTables->GetGuidHeapSize(&ulSize);
4332     VWriteLine("Guids,%d", ulSize);
4333
4334     for (ULONG ixTbl = 0; ixTbl < cTables; ++ixTbl)
4335     {
4336         m_pTables->GetTableInfo(ixTbl, &cbRow, &cRows, &cCols, NULL, &pNameTable);
4337         VWriteLine("%s,%d,%d,%d", pNameTable, cbRow*cRows, cRows, cbRow);
4338     }
4339
4340 } // void MDInfo::DumpRawCSV()
4341