//
// Copyright (c) 2002
// Ronald Kevin Burton
//
// Z poniższym kodem nie jest związana żadna gwarancja poprawności działania.
// Program został dołączony do książki ".NET CLR. Księga eksperta" w celu
// ilustracji koncepcji i zasad przedstawionych w tej książce. Program może być 
// używany na własne ryzyko.
//
// Przyznaje się prawo do użycia lub kopiowania tego oprogramowania do dowolnego celu
// bez konieczności ponoszenia żadnych opłat pod warunkiem, że powyższe uwagi zostaną 
// zachowane we wszystkich kopiach. Przyznaje się także prawo do modyfikacji kodu
// i dystrybucji zmodyfikowanego kodu pod warunkiem zachowania powyższych uwag
// oraz dołączenia informacji mówiącej o modyfikacji kodu.
//
// 
//
// 
// TypeDefPage.cpp : plik implementacji
//

#include "stdafx.h"
#include "AssemblyDoc.h"
#include "AssemblyView.h"
#include "TypeDefPage.h"

// Okno dialogowe CTypeDefPage

IMPLEMENT_DYNAMIC(CTypeDefPage, CPropertyPage)
CTypeDefPage::CTypeDefPage()
	: CPropertyPage(CTypeDefPage::IDD)
{
}

CTypeDefPage::~CTypeDefPage()
{
}

void CTypeDefPage::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_METHODTREE, m_ctrlMethodTree);
}

BEGIN_MESSAGE_MAP(CTypeDefPage, CPropertyPage)
END_MESSAGE_MAP()

mdMethodDef g_tkEntryPoint = 0; // integracja z ILDASM

HRESULT _FillVariant(
    BYTE        bCPlusTypeFlag, 
    const void  *pValue,
    VARIANT     *pvar) 
{
    HRESULT     hr = NOERROR;
    switch (bCPlusTypeFlag)
    {
    case ELEMENT_TYPE_BOOLEAN:
        pvar->vt = VT_BOOL;
        pvar->boolVal = *((BYTE*)pValue); //*((VARIANT_BOOL *)pValue);
        break;
    case ELEMENT_TYPE_I1:
        pvar->vt = VT_I1;
        pvar->cVal = *((CHAR*)pValue);
        break;  
    case ELEMENT_TYPE_U1:
        pvar->vt = VT_UI1;
        pvar->bVal = *((BYTE*)pValue);
        break;  
    case ELEMENT_TYPE_I2:
        pvar->vt = VT_I2;
        pvar->iVal = *((SHORT*)pValue);
        break;  
    case ELEMENT_TYPE_U2:
    case ELEMENT_TYPE_CHAR:
        pvar->vt = VT_UI2;
        pvar->uiVal = *((USHORT*)pValue);
        break;  
    case ELEMENT_TYPE_I4:
        pvar->vt = VT_I4;
        pvar->lVal = *((LONG*)pValue);
        break;  
    case ELEMENT_TYPE_U4:
        pvar->vt = VT_UI4;
        pvar->ulVal = *((ULONG*)pValue);
        break;  
    case ELEMENT_TYPE_R4:
        pvar->vt = VT_R4;
        pvar->fltVal = *((FLOAT*)pValue);
        break;  
    case ELEMENT_TYPE_R8:
        pvar->vt = VT_R8;
        pvar->dblVal = *((DOUBLE*)pValue);
        break;  
    case ELEMENT_TYPE_STRING:
        pvar->vt = VT_BSTR;

        // alokowane bstr
        pvar->bstrVal = ::SysAllocString((LPWSTR)pValue);
        if (pvar->bstrVal == NULL)
            hr = E_OUTOFMEMORY;
        break;  
    case ELEMENT_TYPE_CLASS:
        pvar->punkVal = NULL;
        pvar->vt = VT_UNKNOWN;
        _ASSERTE( *((IUnknown **)pValue) == NULL );
        break;  
    case ELEMENT_TYPE_I8:
        pvar->vt = VT_I8;
        pvar->cyVal.int64 = *((LONGLONG*)pValue);
        break;
    case ELEMENT_TYPE_U8:
        pvar->vt = VT_UI8;
        pvar->cyVal.int64 = *((LONGLONG*)pValue);
        break;
    case ELEMENT_TYPE_VOID:
        pvar->vt = VT_EMPTY;
        break;
    default:
        _ASSERTE(!_T("niewłaściwy typ stałej wartości!"));
    }

    return hr;
}


// Procedury obsługi wiadomości CTypeDefPage
LPCWSTR TypeRefName(IMetaDataImport* pImport, mdTypeRef tr, LPWSTR buffer, ULONG bufLen)
{
    HRESULT hr;
    
    hr = pImport->GetTypeRefProps(           
        tr,                 // Żeton obsługi wiadomości.
        NULL,               // Zakres działania.
        buffer,             // Tutaj powinna znaleźć się nazwa.
        bufLen,             // Wielkość bufora nazwy w znakach.
        NULL);              // Tutaj rzeczywista wielkość nazwy.
    if (FAILED(hr))
	{
		TRACE(_T("Działanie GetTypeRefProps nie powiodło się. 0x%08X\n"), hr);
		return NULL;
	}

    return (buffer);
}
LPWSTR VariantAsString(VARIANT *pVariant)
{
    HRESULT hr = S_OK;
    if (pVariant->vt == VT_UNKNOWN)
    {
        _ASSERTE(pVariant->punkVal == NULL);
        return (L"NULL");
    }
    else if (SUCCEEDED(hr = ::VariantChangeType(pVariant, pVariant, 0, VT_BSTR)))
        return (LPWSTR) pVariant->pbstrVal;
    else if (hr == DISP_E_BADVARTYPE && pVariant->vt == VT_I8)
    {
        // alokacja bstr.
        char    szStr[32];
        WCHAR   wszStr[32];
        // Ustawienie typu warianu na bstr.
        pVariant->vt = VT_BSTR;
        // Utworzenie ciągu ansi.
        sprintf(szStr, "%I64d", pVariant->cyVal.int64);
        // Konwersja do unicode.
        MultiByteToWideChar(CP_ACP, 0, szStr, -1, wszStr, 32);
        // Konwersja do bstr i ustawienie wartości.
        pVariant->bstrVal = ::SysAllocString(wszStr);
        if (pVariant->bstrVal == NULL)
            TRACE(_T("Działanie SysAllocString() nie powiodło się."), E_OUTOFMEMORY);
        return (LPWSTR) pVariant->pbstrVal;
    }
    else
        return (L"BŁĄD");
    
} // LPWSTR MDInfo::VariantAsString()

LPCWSTR TypeDefName(IMetaDataImport* pImport, mdTypeDef inTypeDef, LPWSTR buffer, ULONG bufLen)
{
    HRESULT hr;

    hr = pImport->GetTypeDefProps(
                                // [IN] Zakres importu.
        inTypeDef,              // [IN] Żeton TypeDef dla zapytania.
        buffer,                 // [OUT] Tutaj powinna znaleźć się nazwa.
        bufLen,                 // [IN] Wielkość bufora nazwy w znakach.
        NULL,                   // [OUT] Tutaj należy umieścić długość nazwy w znakach.
        NULL,                   // [OUT] Tutaj należy umieścić znaczniki.
        NULL);                  // [OUT] Tutaj należy umieścić TypeDef/TypeRef dla klasy bazowej.
    if (FAILED(hr))
	{
		TRACE(_T("Działanie GetTypeDefProps nie powiodło się. 0x%08X\n"), hr);
		return NULL;
	}

    return buffer;
}

LPCWSTR TypeDeforRefName(IMetaDataImport* pImport, mdToken inToken, LPWSTR buffer, ULONG bufLen)
{
    if (RidFromToken(inToken))
    {
        if (TypeFromToken(inToken) == mdtTypeDef)
            return (TypeDefName(pImport, (mdTypeDef) inToken, buffer, bufLen));
        else if (TypeFromToken(inToken) == mdtTypeRef)
            return (TypeRefName(pImport, (mdTypeRef) inToken, buffer, bufLen));
        else
            return (L"[InvalidReference]");
    }
    else
        return (L"");
}

LPCWSTR TokenTypeName(mdToken inToken)
{
    switch(TypeFromToken(inToken))
    {
    case mdtTypeDef:        return L"TypeDef";
    case mdtInterfaceImpl:  return L"InterfaceImpl";
    case mdtMethodDef:      return L"MethodDef";
    case mdtFieldDef:       return L"FieldDef";
    case mdtTypeRef:        return L"TypeRef";
    case mdtMemberRef:      return L"MemberRef";
    case mdtCustomAttribute:return L"CustomAttribute";
    case mdtParamDef:       return L"ParamDef";
    case mdtProperty:       return L"Property";
    case mdtEvent:          return L"Event";
    default:                return L"[Nieznany typ żetonu]";
    }
}

LPWSTR ClassFlags(DWORD flags, LPWSTR sFlags)
{
    wcscpy(sFlags, L"");
    if(IsTdNotPublic(flags))
	{
		wcscat(sFlags, L"[NotPublic] ");
	}
    if(IsTdPublic(flags))
	{
		wcscat(sFlags, L"[Public] ");
	}
    if(IsTdNestedPublic(flags))
	{
		wcscat(sFlags, L"[NestedPublic] ");
	}
    if(IsTdNestedPrivate(flags))
	{
		wcscat(sFlags, L"[NestedPrivate] ");
	}
    if(IsTdNestedFamily(flags))
	{
		wcscat(sFlags, L"[NestedFamily] ");
	}
    if(IsTdNestedAssembly(flags))
	{
		wcscat(sFlags, L"[NestedAssembly] ");
	}
    if(IsTdNestedFamANDAssem(flags))
	{
		wcscat(sFlags, L"[NestedFamANDAssem] ");
	}
    if(IsTdNestedFamORAssem(flags))
	{
		wcscat(sFlags, L"[NestedFamORAssem] ");
	}
    if(IsTdAutoLayout(flags))
	{
		wcscat(sFlags, L"[AutoLayout] ");
	}
    if(IsTdSequentialLayout(flags))
	{
		wcscat(sFlags, L"[SequentialLayout] ");
	}
    if(IsTdExplicitLayout(flags))
	{
		wcscat(sFlags, L"[ExplicitLayout] ");
	}
    if(IsTdClass(flags))
	{
		wcscat(sFlags, L"[Class] ");
	}
    if(IsTdInterface(flags))
	{
		wcscat(sFlags, L"[Interface] ");
	}
    if(IsTdAbstract(flags))
	{
		wcscat(sFlags, L"[Abstract] ");
	}
    if(IsTdSealed(flags))
	{
		wcscat(sFlags, L"[Sealed] ");
	}
    if(IsTdSpecialName(flags))
	{
		wcscat(sFlags, L"[SpecialName] ");
	}
    if(IsTdRTSpecialName(flags))
	{
		wcscat(sFlags, L"[RTSpecialName] ");
	}
    if(IsTdImport(flags))
	{
		wcscat(sFlags, L"[Import] ");
	}
    if(IsTdSerializable(flags))
	{
		wcscat(sFlags, L"[Serializable] ");
	}
    if(IsTdAnsiClass(flags))
	{
		wcscat(sFlags, L"[AnsiClass] ");
	}
    if(IsTdUnicodeClass(flags))
	{
		wcscat(sFlags, L"[UnicodeClass] ");
	}
    if(IsTdAutoClass(flags))
	{
		wcscat(sFlags, L"[AutoClass] ");
	}
    // "Reserved" flags
    if(IsTdHasSecurity(flags))
	{
		wcscat(sFlags, L"[HasSecurity] ");
	}
    if (!*sFlags)
        wcscpy(sFlags, L"[brak]");

    return sFlags;
}

void DisplayTypeDefProps(IMetaDataImport* pImport, mdTypeDef inTypeDef, CTreeCtrl& treeCtrl, HTREEITEM treeItem)
{
    HRESULT hr;
    WCHAR typeDefName[STRING_BUFFER_LEN];
    ULONG nameLen;
    DWORD flags;
    mdToken extends;
    ULONG dwPacking;              // Upakowana wielkość klasy (jeśli podana).
    ULONG dwSize;                 // Całkowita wielkość klasy (jeśli podana).

    hr = pImport->GetTypeDefProps(
								  inTypeDef,              // [IN] Żeton TypeDef dla zapytania.
								  typeDefName,            // [OUT] Tutaj powinna znaleźć się nazwa.
								  STRING_BUFFER_LEN,      // [IN] Wielkość bufora nazwy w znakach.
								  &nameLen,               // [OUT] Tutaj należy umieścić długość nazwy w znakach.
								  &flags,                 // [OUT] Tutaj należy umieścić znaczniki.
								  &extends);              // [OUT] Tutaj należy umieścić TypeDef/TypeRef dla klasy bazowej.
    if (FAILED(hr))
	{
		TRACE(_T("GetTypeDefProps failed. 0x%08X\n"), hr);
		return;
	}

    WCHAR sFlags[STRING_BUFFER_LEN];
    WCHAR szTempBuf[STRING_BUFFER_LEN];
	WCHAR lBuffer[STRING_BUFFER_LEN*2];

    wsprintf(lBuffer, _T("TypDefName: %ls (%8.8X)"), typeDefName, inTypeDef);
	treeCtrl.InsertItem(lBuffer, treeItem);
	wsprintf(lBuffer, _T("Znaczniki: %ls (%08x)"),
		ClassFlags(flags, sFlags),
		flags);
	treeCtrl.InsertItem(lBuffer, treeItem);
    wsprintf(lBuffer, _T("Rozszerza: %8.8X [%ls] %ls"),
		      extends,
			  TokenTypeName(extends),
              TypeDeforRefName(pImport, extends, szTempBuf, NumItems(szTempBuf)));
	treeCtrl.InsertItem(lBuffer, treeItem);

    hr = pImport->GetClassLayout(inTypeDef, &dwPacking, 0,0,0, &dwSize);
    if (hr == S_OK)
	{
        wsprintf(lBuffer, _T("Struktura: Upakowanie:%d, Wielkość:%d"), dwPacking, dwSize);
		treeCtrl.InsertItem(lBuffer, treeItem);
	}

    if (IsTdNested(flags))
    {
        mdTypeDef tkEnclosingClass;

        hr = pImport->GetNestedClassProps(inTypeDef, &tkEnclosingClass);
        if (hr == S_OK)
        {
            wsprintf(lBuffer, _T("EnclosingClass : %ls (%8.8X)"),
				     TypeDeforRefName(pImport, tkEnclosingClass, szTempBuf, NumItems(szTempBuf)),
					 tkEnclosingClass);
			treeCtrl.InsertItem(lBuffer, treeItem);
        }
        else if (hr == CLDB_E_RECORD_NOTFOUND)
		{
            TRACE(_T("BŁĄŽ: Nie odnaleziono EnclosingClass dla NestedClass\n"));
		}
        else
		{
            TRACE(_T("Działanie GetNestedClassProps nie powiodło się. 0x%08X\n"), hr);
		}
    }
}

//void DisplaySignature(PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, const char *preFix)
//{
//    ULONG       cbCur = 0;
//    ULONG       cb;
//    ULONG       ulData;
//    ULONG       ulArgs;
//    HRESULT     hr = NOERROR;
//    ULONG       ulSigBlobStart = ulSigBlob;
//
//    // Inicjalizacja sigBuf
//    InitSigBuffer();
//
//    cb = CorSigUncompressData(pbSigBlob, &ulData);
//    VWriteLine("%s\t\tCallCnvntn: %s", preFix, (g_strCalling[ulData & IMAGE_CEE_CS_CALLCONV_MASK]));
//    if (cb>ulSigBlob) 
//        goto ErrExit;
//    cbCur += cb;
//    ulSigBlob -= cb;
//
//    if (ulData & IMAGE_CEE_CS_CALLCONV_HASTHIS)
//        VWriteLine("%s\t\thasThis ", preFix);
//    if (ulData & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS)
//        VWriteLine("%s\t\texplicit ", preFix);
//
//    // Inicjalizacja sigBuf
//    InitSigBuffer();
//    if ( isCallConv(ulData,IMAGE_CEE_CS_CALLCONV_FIELD) )
//    {
//
//        // Typ pola
//        if (FAILED(hr = GetOneElementType(&pbSigBlob[cbCur], ulSigBlob, &cb)))
//            goto ErrExit;
//        VWriteLine("%s\t\tField type: %s", preFix, (LPSTR)m_sigBuf.Ptr());
//        if (cb>ulSigBlob) 
//            goto ErrExit;
//        cbCur += cb;
//        ulSigBlob -= cb;
//    }
//    else 
//    {
//        cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulArgs);
//        if (cb>ulSigBlob) 
//            goto ErrExit;
//        cbCur += cb;
//        ulSigBlob -= cb;
//
//        if (ulData != IMAGE_CEE_CS_CALLCONV_LOCAL_SIG)
//        {
//            // Wyświetlenie typu zwrotnego, jeśli nie jest to lokalny varsig
//            if (FAILED(hr = GetOneElementType(&pbSigBlob[cbCur], ulSigBlob, &cb)))
//                goto ErrExit;
//            VWriteLine("%s\t\tReturnType:%s", preFix, (LPSTR)m_sigBuf.Ptr());
//            if (cb>ulSigBlob) 
//                goto ErrExit;
//            cbCur += cb;
//            ulSigBlob -= cb;
//        }
//
//        // Wyświetlenie licznika argumentów
//        // Wyświetlenie argumentów
//        if (ulSigBlob)
//            VWriteLine("%s\t\t%ld Argumenty", preFix, ulArgs);
//        else
//            VWriteLine("%s\t\tBrak argumentów.", preFix);
//
//        ULONG       i = 0;
//        while (i < ulArgs && ulSigBlob > 0)
//        {
//            ULONG       ulData;
//
//            // Obsługa varargs, które nie zostały uwzględnione jako argumenty.
//            CorSigUncompressData(&pbSigBlob[cbCur], &ulData);
//            ++i;
//
//            // Inicjalizacja sigBuf
//            InitSigBuffer();
//
//            if (FAILED(hr = GetOneElementType(&pbSigBlob[cbCur], ulSigBlob, &cb)))
//                goto ErrExit;
//
//            VWriteLine("%s\t\t\tArgument #%ld: %s",preFix, i, (LPSTR)m_sigBuf.Ptr());
//    
//            if (cb>ulSigBlob) 
//                goto ErrExit;
//
//            cbCur += cb;
//            ulSigBlob -= cb;
//        }
//    }
//
//    // Nic nie zostało jeszcze wykonane ani policzone.
//    cb = 0;
//
//ErrExit:
//    // Należy wykorzystać cały obiekt blob sygnatury. W przeciwnym wypadku należy wykonać szesnastkowy zrzut sygnatury.
//    //  Zrzut może być także wykonany na żądanie.
//    if (m_DumpFilter & dumpMoreHex || ulSigBlob != 0)
//    {
//        // Czy wykorzystano zbyt małą lub zbyt dużą część sygnatury?
//        if (cb > ulSigBlob)
//            WriteLine("\tBŁĄD SYGNATURY:  Sygnatura powinna być dłuższa.");
//        else
//        if (cb < ulSigBlob)
//        {
//            VWrite("\tBŁĄD SYGNATURY:  Nie wykorzystano całego obiektu sygnatury. Pozostało %d bajtów", ulSigBlob);
//            // Jeśli jest zbyt krótka, należy dołączyć ją na końcu.
//            if (ulSigBlob < 4)
//            {
//                Write(": ");
//                for (; ulSigBlob; ++cbCur, --ulSigBlob)
//                    VWrite("%02x ", pbSigBlob[cbCur]);
//                WriteLine("");
//                goto ErrExit2;
//            }
//            WriteLine("");
//        }
//
//        // Wygenerowano właściwy komunikat o błędzie. Szesnastkowy zrzut sygnatury jest wykonywany
//        //  w zależności od błędu lub przełącznika wiersza poleceń.
//        cbCur = 0;
//        ulSigBlob = ulSigBlobStart;
//        char rcNewPrefix[80];
//        sprintf(rcNewPrefix, "%s\t\tSignature ", preFix);
//        DumpHex(rcNewPrefix, pbSigBlob, ulSigBlob, false, 24);
//    }
//ErrExit2:
//    if (FAILED(hr))
//        Error("BŁĄD!! Niewłaściwa wartość obiektu blob sygnatury!");
//    return;
//}

void DisplayFieldInfo(IMetaDataImport* pImport, mdFieldDef inField, DWORD *pdwFlags, CTreeCtrl& treeCtrl, HTREEITEM treeItem)
{
    HRESULT hr;
    mdTypeDef memTypeDef;
    WCHAR memberName[STRING_BUFFER_LEN];
    ULONG nameLen;
    DWORD flags;
    PCCOR_SIGNATURE pbSigBlob;
    ULONG ulSigBlob;
    DWORD dwCPlusTypeFlag;
    void const *pValue;
    ULONG cbValue;
    VARIANT defaultValue;

    ::VariantInit(&defaultValue);
    hr = pImport->GetFieldProps(inField, &memTypeDef, memberName, STRING_BUFFER_LEN,
                                &nameLen, &flags, &pbSigBlob, &ulSigBlob, &dwCPlusTypeFlag,
                                &pValue, &cbValue);
    if (FAILED(hr))
	{
		TRACE(_T("Działanie GetFieldProps nie powiodło się. 0x%08X\n"), hr);
		return;
	}

    if (pdwFlags)
        *pdwFlags = flags;

    _FillVariant((BYTE)dwCPlusTypeFlag, pValue, &defaultValue);

    WCHAR sFlags[STRING_BUFFER_LEN];

    wcscpy(sFlags, L"");
    if(IsFdPublic(flags))
	{
		wcscat(sFlags, L"[Public] ");
	}
    if(IsFdPrivate(flags))
	{
		wcscat(sFlags, L"[Private] ");
	}
    if(IsFdFamily(flags))
	{
		wcscat(sFlags, L"[Family] ");
	}
    if(IsFdAssembly(flags))
	{
		wcscat(sFlags, L"[Assembly] ");
	}
    if(IsFdFamANDAssem(flags))
	{
		wcscat(sFlags, L"[FamANDAssem] ");
	}
    if(IsFdFamORAssem(flags))
	{
		wcscat(sFlags, L"[FamORAssem] ");
	}
    if(IsFdPrivateScope(flags))
	{
		wcscat(sFlags, L"[PrivateScope] ");
	}
    if(IsFdStatic(flags))
	{
		wcscat(sFlags, L"[Static] ");
	}
    if(IsFdInitOnly(flags))
	{
		wcscat(sFlags, L"[InitOnly] ");
	}
    if(IsFdLiteral(flags))
	{
		wcscat(sFlags, L"[Literal] ");
	}
    if(IsFdNotSerialized(flags))
	{
		wcscat(sFlags, L"[NotSerialized] ");
	}
    if(IsFdSpecialName(flags))
	{
		wcscat(sFlags, L"[SpecialName] ");
	}
    if(IsFdRTSpecialName(flags))
	{
		wcscat(sFlags, L"[RTSpecialName] ");
	}
    if(IsFdPinvokeImpl(flags))
	{
		wcscat(sFlags, L"[PinvokeImpl] ");
	}
    // "Reserved" flags
    if(IsFdHasDefault(flags))
	{
		wcscat(sFlags, L"[HasDefault] ");
	}
    if (!*sFlags)
        wcscpy(sFlags, L"[brak]");

	WCHAR lBuffer[512];
	WCHAR tBuffer[512];
    wsprintf(lBuffer, _T("Nazwa pola: %ls (%8.8X)"), memberName, inField);
	treeCtrl.InsertItem(lBuffer, treeItem);
    wsprintf(lBuffer, _T("Znaczniki: %ls (%08x)"), sFlags, flags);
	treeCtrl.InsertItem(lBuffer, treeItem);
    wsprintf(lBuffer, _T("Domyślna wartość: %ls"), VariantAsString(&defaultValue));
	treeCtrl.InsertItem(lBuffer, treeItem);

	// Signature size should be non-zero for fields
    if (!ulSigBlob)
		TRACE("\t\tBŁĄD: niepoprawna sygnatura \n");
	else
	{
		wcscpy(lBuffer, L"Sygnatura: ");
		// Punt and just display the hex bytes.
		for(ULONG i = 0; i < ulSigBlob; i++)
		{
			wsprintf(tBuffer, _T("0x%02X "), pbSigBlob[i]);
			wcscat(lBuffer, tBuffer);
		}
		treeCtrl.InsertItem(lBuffer, treeItem);
		// DisplaySignature(pbSigBlob, ulSigBlob, "");
	}
}

void DisplayFields(IMetaDataImport* pImport, mdTypeDef inTypeDef, COR_FIELD_OFFSET *rFieldOffset, ULONG cFieldOffset, CTreeCtrl& treeCtrl, HTREEITEM treeItem)
{
    HCORENUM fieldEnum = NULL;
    mdToken fields[ENUM_BUFFER_SIZE];
    ULONG count, totalCount = 1;
    DWORD flags;
    HRESULT hr;
    WCHAR lBuffer[256];
	HTREEITEM subTreeItem;

    while (SUCCEEDED(hr = pImport->EnumFields(&fieldEnum,
		                                      inTypeDef,
                                              fields,
											  NumItems(fields),
											  &count)) &&
            count > 0)
    {
        for (ULONG i = 0; i < count; i++, totalCount++)
        {
			wsprintf(lBuffer, _T("Field #%d"), totalCount);
	        subTreeItem = treeCtrl.InsertItem(lBuffer, treeItem);
            DisplayFieldInfo(pImport, fields[i], &flags, treeCtrl, subTreeItem);

            // DisplayCustomAttributes(fields[i], "\t\t");
            // DisplayPermissions(fields[i], "\t");
            // DisplayFieldMarshal(fields[i]);

            // RVA jeśli jest to pole globalne.
            // if (inTypeDef == mdTokenNil)
            //    DisplayFieldRVA(fields[i]);

            // Dane P-invoke jeśli są obecne.
            // if (IsFdPinvokeImpl(flags))
            //    DisplayPinvokeInfo(fields[i]);

            // Wyświetlenie przesunięcia.
            // if (cFieldOffset)
            // {
            //     bool found = false;
            //    for (ULONG iLayout = 0; i < cFieldOffset; ++iLayout)
            //    {
            //        if (RidFromToken(rFieldOffset[iLayout].ridOfField) == RidFromToken(fields[i]))
            //        {
            //            found = true;
            //            VWriteLine("\t\tOffset : 0x%08x", rFieldOffset[iLayout].ulOffset);
            //            break;
            //        }
            //    }
            //    _ASSERTE(found);
            //}
            //WriteLine("");
        }
    }

    pImport->CloseEnum(fieldEnum);
}

void DisplayMethodInfo(IMetaDataImport* pImport, mdMethodDef inMethod, DWORD *pflags, CTreeCtrl& treeCtrl, HTREEITEM treeItem)
{
    HRESULT hr;
    mdTypeDef memTypeDef;
    WCHAR memberName[STRING_BUFFER_LEN];
    ULONG nameLen;
    DWORD flags;
    PCCOR_SIGNATURE pbSigBlob;
    ULONG ulSigBlob;
    ULONG ulCodeRVA;
    ULONG ulImplFlags;
	WCHAR lBuffer[1024];

    hr = pImport->GetMethodProps( inMethod, &memTypeDef, memberName, STRING_BUFFER_LEN,
                            &nameLen, &flags, &pbSigBlob, &ulSigBlob, &ulCodeRVA, &ulImplFlags);
    if (FAILED(hr))
	{
		TRACE(_T("Działanie GetMethodProps nie powiodło się. 0x%08X\n"), hr);
		return;
	}
    if (pflags)
        *pflags = flags;

    wsprintf(lBuffer, _T("MethodName: %ls (%8.8X)"), memberName, inMethod);
	treeCtrl.InsertItem(lBuffer, treeItem);

    WCHAR sFlags[STRING_BUFFER_LEN];

    wcscpy(sFlags, L"");
    if(IsMdPublic(flags))
	{
		wcscat(sFlags, L"[Public] ");
	}
    if(IsMdPrivate(flags))
	{
		wcscat(sFlags, L"[Private] ");
	}
    if(IsMdFamily(flags))
	{
		wcscat(sFlags, L"[Family] ");
	}
    if(IsMdAssem(flags))
	{
		wcscat(sFlags, L"[Assem] ");
	}
    if(IsMdFamANDAssem(flags))
	{
		wcscat(sFlags, L"[FamANDAssem] ");
	}
    if(IsMdFamORAssem(flags))
	{
		wcscat(sFlags, L"[FamORAssem] ");
	}
    if(IsMdPrivateScope(flags))
	{
		wcscat(sFlags, L"[PrivateScope] ");
	}
    if(IsMdStatic(flags))
	{
		wcscat(sFlags, L"[Static] ");
	}
    if(IsMdFinal(flags))
	{
		wcscat(sFlags, L"[Final] ");
	}
    if(IsMdVirtual(flags))
	{
		wcscat(sFlags, L"[Virtual] ");
	}
    if(IsMdHideBySig(flags))
	{
		wcscat(sFlags, L"[HideBySig] ");
	}
    if(IsMdReuseSlot(flags))
	{
		wcscat(sFlags, L"[ReuseSlot] ");
	}
    if(IsMdNewSlot(flags))
	{
		wcscat(sFlags, L"[NewSlot] ");
	}
    if(IsMdAbstract(flags))
	{
		wcscat(sFlags, L"[Abstract] ");
	}
    if(IsMdSpecialName(flags))
	{
		wcscat(sFlags, L"[SpecialName] ");
	}
    if(IsMdRTSpecialName(flags))
	{
		wcscat(sFlags, L"[RTSpecialName] ");
	}
    if(IsMdPinvokeImpl(flags))
	{
		wcscat(sFlags, L"[PinvokeImpl] ");
	}
    if(IsMdUnmanagedExport(flags))
	{
		wcscat(sFlags, L"[UnmanagedExport] ");
	}
    if (!*sFlags)
        wcscpy(sFlags, L"[none]");

    if (IsMdInstanceInitializerW(flags, memberName)) wcscat(sFlags, L"[.ctor] ");
    if (IsMdClassConstructorW(flags, memberName)) wcscat(sFlags, L"[.cctor] ");
    // "Zarezerwowane" znaczniki
    if(IsMdHasSecurity(flags))
	{
		wcscat(sFlags, L"[HasSecurity] ");
	}
    if(IsMdRequireSecObject(flags))
	{
		wcscat(sFlags, L"[RequireSecObject] ");
	}

    wsprintf(lBuffer, _T("Flags     : %ls (%08x)"), sFlags, flags);
	treeCtrl.InsertItem(lBuffer, treeItem);
    wsprintf(lBuffer, _T("RVA       : 0x%08x"), ulCodeRVA);
	treeCtrl.InsertItem(lBuffer, treeItem);

    flags = ulImplFlags;
    wcscpy(sFlags, L"");
    if(IsMiNative(flags))
	{
		wcscat(sFlags, L"[Native] ");
	}
    if(IsMiIL(flags))
	{
		wcscat(sFlags, L"[IL] ");
	}
    if(IsMiOPTIL(flags))
	{
		wcscat(sFlags, L"[OPTIL] ");
	}
    if(IsMiRuntime(flags))
	{
		wcscat(sFlags, L"[Runtime] ");
	}
    if(IsMiUnmanaged(flags))
	{
		wcscat(sFlags, L"[Unmanaged] ");
	}
    if(IsMiManaged(flags))
	{
		wcscat(sFlags, L"[Managed] ");
	}
    if(IsMiForwardRef(flags))
	{
		wcscat(sFlags, L"[ForwardRef] ");
	}
    if(IsMiPreserveSig(flags))
	{
		wcscat(sFlags, L"[PreserveSig] ");
	}
    if(IsMiInternalCall(flags))
	{
		wcscat(sFlags, L"[InternalCall] ");
	}
    if(IsMiSynchronized(flags))
	{
		wcscat(sFlags, L"[Synchronized] ");
	}
    if(IsMiNoInlining(flags))
	{
		wcscat(sFlags, L"[NoInlining] ");
	}
    if (!*sFlags)
        wcscpy(sFlags, L"[brak]");

    wsprintf(lBuffer, _T("ImplFlags : %ls (%08x)"), sFlags, flags);
	treeCtrl.InsertItem(lBuffer, treeItem);

	WCHAR tBuffer[1024];

    if (ulSigBlob)
	{
		wcscpy(lBuffer, L"Sygnatura: ");
		// Punt and just display the hex bytes.
		for(ULONG i = 0; i < ulSigBlob; i++)
		{
			wsprintf(tBuffer, _T("0x%02X "), pbSigBlob[i]);
			wcscat(lBuffer, tBuffer);
		}
		treeCtrl.InsertItem(lBuffer, treeItem);
		// DisplaySignature(pbSigBlob, ulSigBlob, "");
	}
	else
		TRACE(_T("\t\tERROR: no valid signature \n"));

}

void DisplayParamInfo(IMetaDataImport* pImport, mdParamDef inParamDef, CTreeCtrl& treeCtrl, HTREEITEM treeItem)
{
    mdMethodDef md;
    ULONG num;
    WCHAR paramName[STRING_BUFFER_LEN];
    ULONG nameLen;
    DWORD flags;
    VARIANT defValue;
    DWORD dwCPlusFlags;
    void const *pValue;
    ULONG cbValue;
	WCHAR lBuffer[256];

    ::VariantInit(&defValue);
    HRESULT hr = pImport->GetParamProps(inParamDef,
		                                &md,
										&num,
										paramName,
										NumItems(paramName),
                                        &nameLen,
										&flags,
										&dwCPlusFlags,
										&pValue,
										&cbValue);
    if (FAILED(hr))
	{
		TRACE(_T("Działanie GetParamProps nie powiodło się. 0x%08X\n"), hr);
	}
    
    _FillVariant((BYTE)dwCPlusFlags, pValue, &defValue);
    
    WCHAR sFlags[STRING_BUFFER_LEN];
    wcscpy(sFlags, L"");
    if(IsPdIn(flags))
	{
		wcscat(sFlags, L"[Wej] ");
	}
    if(IsPdOut(flags))
	{
		wcscat(sFlags, L"[Wyj] ");
	}
    if(IsPdOptional(flags))
	{
		wcscat(sFlags, L"[Opcjonalne] ");
	}
    // "Reserved" flags.
    if(IsPdHasDefault(flags))
	{
		wcscat(sFlags, L"[HasDefault] ");
	}
    if(IsPdHasFieldMarshal(flags))
	{
		wcscat(sFlags, L"[HasFieldMarshal] ");
	}
    if (!*sFlags)
        wcscpy(sFlags, L"[brak]");

    wsprintf(lBuffer, _T("(%ld) Żeton parametru : (%08x) Nazwa : %ls znaczniki: %ls (%08x) domyślnie: %ls"),
		     num, inParamDef, paramName, sFlags, flags, VariantAsString(&defValue));
	treeCtrl.InsertItem(lBuffer, treeItem);
    // DisplayCustomAttributes(inParamDef, "\t\t\t");
}

void DisplayParams(IMetaDataImport* pImport, mdMethodDef inMethodDef, CTreeCtrl& treeCtrl, HTREEITEM treeItem)
{
    HCORENUM paramEnum = NULL;
    mdParamDef params[ENUM_BUFFER_SIZE];
    ULONG count, paramCount;
    bool first = true;
    HRESULT hr;
	WCHAR lBuffer[64];
	HTREEITEM subTreeItem = NULL;

    while (SUCCEEDED(hr = pImport->EnumParams(&paramEnum,
		                                      inMethodDef,
											  params,
											  NumItems(params),
											  &count)) &&
            count > 0)
    {
        if (first)
        {
            pImport->CountEnum( paramEnum, &paramCount);
            wsprintf(lBuffer, _T("%d Parameters"), paramCount);
			subTreeItem = treeCtrl.InsertItem(lBuffer, treeItem);
        }
        for (ULONG i = 0; i < count; i++)
        {
            DisplayParamInfo(pImport, params[i], treeCtrl, subTreeItem);
            // DisplayFieldMarshal(params[i]);
        }
        first = false;
    }
    pImport->CloseEnum(paramEnum);
}

void DisplayMethods(IMetaDataImport* pImport, mdTypeDef inTypeDef, CTreeCtrl& treeCtrl, HTREEITEM treeItem)
{
    HCORENUM methodEnum = NULL;
    mdToken methods[ENUM_BUFFER_SIZE];
    DWORD flags;
    ULONG count, totalCount = 1;
    HRESULT hr;
	WCHAR lBuffer[512];
	HTREEITEM subTreeItem;
    while (SUCCEEDED(hr = pImport->EnumMethods( &methodEnum,
		                                        inTypeDef,
                                                methods,
												NumItems(methods),
												&count)) &&
            count > 0)
    {
        for (ULONG i = 0; i < count; i++, totalCount++)
        {
            wsprintf(lBuffer, _T("Metoda #%d %ls"), totalCount, (methods[i] == g_tkEntryPoint) ? L"[PUNKT WEJŚCIA]" : L"");
			subTreeItem = treeCtrl.InsertItem(lBuffer, treeItem);
            DisplayMethodInfo(pImport, methods[i], &flags, treeCtrl, subTreeItem);
            DisplayParams(pImport, methods[i], treeCtrl, subTreeItem);
            //DisplayCustomAttributes(methods[i], "\t\t");
            //DisplayPermissions(methods[i], "\t");
            //DisplayMemberRefs(methods[i], "\t");
            //// Dane P-invoke jeśli obecne.
            //if (IsMdPinvokeImpl(flags))
            //    DisplayPinvokeInfo(methods[i]);
        }
    }
    pImport->CloseEnum(methodEnum);
}

void DisplayTypeDefInfo(IMetaDataImport* pImport, mdTypeDef inTypeDef, CTreeCtrl& treeCtrl, HTREEITEM treeItem)
{
    // Dostępne jako 98 i 99
    DisplayTypeDefProps(pImport, inTypeDef, treeCtrl, treeItem);

    // Dostępne tylko jako 99, ale można to obejść

    // Uzyskanie informacji o strukturze pól.
    HRESULT             hr = NOERROR;
    COR_FIELD_OFFSET    *rFieldOffset = NULL;
    ULONG               cFieldOffset = 0;
    hr = pImport->GetClassLayout(inTypeDef,
		                         NULL,
								 rFieldOffset,
								 0,
								 &cFieldOffset,
								 NULL);
    if (SUCCEEDED(hr) && cFieldOffset)
    {
        if (!(rFieldOffset = (COR_FIELD_OFFSET *)_alloca(sizeof(COR_FIELD_OFFSET) * cFieldOffset)))
		{
            TRACE(_T("Działanie _calloc nie powiodło się. E_OUTOFMEMORY\n"));
			return;
		}
        hr = pImport->GetClassLayout(inTypeDef,
			                         NULL,
									 rFieldOffset,
									 cFieldOffset,
									 &cFieldOffset, NULL);
        if (FAILED(hr))
		{
			TRACE(_T("Działanie GetClassLayout() nie powiodło się. 0x%08X\n"), hr);
		}
    }

    // Nie ma potrzeby wyświetlania elementów składowych, jeśli pola i metody są wyświetlane oddzielnie.
    DisplayFields(pImport, inTypeDef, rFieldOffset, cFieldOffset, treeCtrl, treeItem);
    DisplayMethods(pImport, inTypeDef, treeCtrl, treeItem);
    //DisplayProperties(inTypeDef);
    //DisplayEvents(inTypeDef);
    //DisplayMethodImpls(inTypeDef);
    //DisplayPermissions(inTypeDef, "");
    //
    //// Dostępne jako 98 i 99
    //DisplayInterfaceImpls(inTypeDef);
    //DisplayCustomAttributes(inTypeDef, "\t");
}

void DisplayTypeDefs(IMetaDataImport* pImport, CTreeCtrl& treeCtrl)
{
    HCORENUM typeDefEnum = NULL;
    mdTypeDef typeDefs[ENUM_BUFFER_SIZE];
    ULONG count, totalCount = 1;
    HRESULT hr;
    WCHAR lBuffer[256];
	HTREEITEM typedefItem;

    while (SUCCEEDED(hr = pImport->EnumTypeDefs(&typeDefEnum,
                                                typeDefs,
												NumItems(typeDefs),
												&count)) &&
            count > 0)
    {
        for (ULONG i = 0; i < count; i++, totalCount++)
        {
            wsprintf(lBuffer, _T("TypeDef #%d"), totalCount);
			typedefItem = treeCtrl.InsertItem(lBuffer);
            DisplayTypeDefInfo(pImport, typeDefs[i], treeCtrl, typedefItem);
        }
    }
    pImport->CloseEnum( typeDefEnum);
}


BOOL CTypeDefPage::OnInitDialog()
{
	CPropertyPage::OnInitDialog();

	// Wypełnienie danymi
	CPropertySheet *pPropertySheet = STATIC_DOWNCAST(CPropertySheet, GetParent());
	CAssemblyView* pView = STATIC_DOWNCAST(CAssemblyView, pPropertySheet->GetParent());
	CAssemblyDoc* pDoc = pView->GetDocument();
	IMetaDataImport* pImport  = pDoc->MetaDataImportInterface();

	DisplayTypeDefs(pImport, m_ctrlMethodTree);

	pImport->Release();

	return TRUE;  // zwrócenie TRUE, chyba że ognisko ustawiono na element sterujący
}
