HRESULT Assembler::CreatePEFile()

in src/coreclr/ilasm/writer.cpp [1014:1600]


HRESULT Assembler::CreatePEFile(_In_ __nullterminated WCHAR *pwzOutputFilename)
{
    HRESULT             hr;
    DWORD               mresourceSize = 0;
    BYTE*               mresourceData = NULL;
    WCHAR*              wzScopeName = NULL;

    if(bClock) bClock->cMDEmitBegin = GetTickCount();
    if(m_fReportProgress) printf("Creating PE file\n");
    if (!m_pEmitter)
    {
        printf("Error: Cannot create a PE file with no metadata\n");
        return E_FAIL;
    }
    if(!(m_fDLL || m_fEntryPointPresent))
    {
        printf("Error: No entry point declared for executable\n");
        if(!OnErrGo) return E_FAIL;
    }

    if(bClock) bClock->cMDEmit1 = GetTickCount();

    // Allocate space for a strong name signature if we're delay or full
    // signing the assembly.
    if (m_pManifest->m_sStrongName.m_pbPublicKey)
    {
        if (FAILED(hr = AllocateStrongNameSignature()))
        {
            goto exit;
        }

        // Public-sign by default
        m_dwComImageFlags |= COMIMAGE_FLAGS_STRONGNAMESIGNED;
    }

    if(bClock) bClock->cMDEmit2 = GetTickCount();

    if(m_VTFList.COUNT()==0)
    {
        Method* pMD;
        Class* pClass;
        unsigned N=0, OrdBase=0xFFFFFFFF, i, j;
        for(i=0; (pClass = m_lstClass.PEEK(i)) != NULL; i++)
        {
            for(j = 0; (pMD = pClass->m_MethodList.PEEK(j)) != NULL; j++)
            {
                if(pMD->m_dwExportOrdinal != 0xFFFFFFFF)
                {
                    N++;
                    if(pMD->m_dwExportOrdinal < OrdBase) OrdBase = pMD->m_dwExportOrdinal;
                }
            }
        }
        if(N)
        {
            for(i=0; (pClass = m_lstClass.PEEK(i)) != NULL; i++)
            {
                for(j = 0; (pMD = pClass->m_MethodList.PEEK(j)) != NULL; j++)
                {
                    if(pMD->m_wVTSlot >= 0x8000)
                    {
                        pMD->m_wVTSlot -= (WORD)(0x8000 + OrdBase - 1);
                    }
                }
            }
            SetDataSection();
            char* sz = new char[20];
            strcpy_s(sz,20,"VTF_EAT_internal");
            EmitDataLabel(sz);
            sz = new char[20];
            strcpy_s(sz,20,"VTF_EAT_internal");
            if(m_dwCeeFileFlags & ICEE_CREATE_FILE_PE64)
            {
                ULONGLONG *pdw = new ULONGLONG[N];
                for(i=0; i<N; i++) pdw[i] = UI64(0xdeadbeefdeadbeef);
                EmitData(pdw,sizeof(ULONGLONG)*N);
                m_VTFList.PUSH(new VTFEntry((USHORT)N,COR_VTABLE_64BIT|COR_VTABLE_FROM_UNMANAGED,sz));
                delete [] pdw;
            }
            else
            {
                unsigned *pdw = new unsigned[N];
                for(i=0; i<N; i++) pdw[i] = 0xdeadbeef;
                EmitData(pdw,sizeof(unsigned)*N);
                m_VTFList.PUSH(new VTFEntry((USHORT)N,COR_VTABLE_32BIT|COR_VTABLE_FROM_UNMANAGED,sz));
                delete [] pdw;
            }
        }
    }
    wzScopeName=&wzUniBuf[0];
    if(m_szScopeName[0]) // default: scope name = output file name
    {
        MultiByteToWideChar(g_uCodePage,0,m_szScopeName,-1,wzScopeName,MAX_SCOPE_LENGTH);
    }
    else
    {
        WCHAR* pwc;
        if ((pwc = (WCHAR*)u16_strrchr(m_wzOutputFileName, DIRECTORY_SEPARATOR_CHAR_A)) != NULL) pwc++;
#ifdef TARGET_WINDOWS
        else if ((pwc = (WCHAR*)u16_strrchr(m_wzOutputFileName, ':')) != NULL) pwc++;
#endif
        else pwc = m_wzOutputFileName;

        wcsncpy_s(wzScopeName, MAX_SCOPE_LENGTH, pwc, _TRUNCATE);
    }
    hr = m_pEmitter->SetModuleProps(wzScopeName);

    if (FAILED(hr))
        goto exit;

    EmitImports();
    if(m_pManifest)
    {
        hr = S_OK;
        if(m_pManifest->m_pAsmEmitter==NULL)
            hr=m_pEmitter->QueryInterface(IID_IMetaDataAssemblyEmit, (void**) &(m_pManifest->m_pAsmEmitter));

        if(SUCCEEDED(hr))
        {
            m_pManifest->EmitAssemblyRefs();
        }
    }
    // Emit classes, class members and globals:
    {
        Class *pSearch;
        int i;
        BOOL    bIsUndefClass = FALSE;
        if(m_fReportProgress)   printf("\nEmitting classes:\n");
        for (i=1; (pSearch = m_lstClass.PEEK(i)); i++)   // 0 is <Module>
        {
            if(m_fReportProgress)
                printf("Class %d:\t%s\n",i,pSearch->m_szFQN);

            if(pSearch->m_bIsMaster)
            {
                report->msg("Error: Reference to undefined class '%s'\n",pSearch->m_szFQN);
                bIsUndefClass = TRUE;
            }
            if(!EmitClass(pSearch))
            {
                if(!OnErrGo) return E_FAIL;
            }
            pSearch->m_fNew = FALSE;
        }
        if(bIsUndefClass && !OnErrGo) return E_FAIL;

        if(m_fReportProgress)   printf("\nEmitting fields and methods:\n");
        for (i=0; (pSearch = m_lstClass.PEEK(i)) != NULL; i++)
        {
            if(m_fReportProgress)
            {
                if(i == 0)  printf("Global \t");
                else        printf("Class %d\t",i);
            }
            if(!EmitFieldsMethods(pSearch))
            {
                if(!OnErrGo) return E_FAIL;
            }
        }
    }

    // All ref'ed items def'ed in this file are emitted, resolve member refs to member defs:
    if(bClock) bClock->cRef2DefBegin = GetTickCount();
    hr = ResolveLocalMemberRefs();
    if(bClock) bClock->cRef2DefEnd = GetTickCount();
    if(FAILED(hr) &&(!OnErrGo)) goto exit;

    // Local member refs resolved, emit events, props and method impls
    {
        Class *pSearch;
        int i;

        if(m_fReportProgress)   printf("\nEmitting events and properties:\n");
        for (i=0; (pSearch = m_lstClass.PEEK(i)); i++)
        {
            if(m_fReportProgress)
            {
                if(i == 0)  printf("Global \t");
                else        printf("Class %d\t",i);
            }
            if(!EmitEventsProps(pSearch))
            {
                if(!OnErrGo) return E_FAIL;
            }
            pSearch->m_fNewMembers = FALSE;
        }
    }
    if(bClock) bClock->cMDEmit3 = GetTickCount();
    if(m_MethodImplDList.COUNT())
    {
        if(m_fReportProgress) report->msg("Method Implementations (total): %d\n",m_MethodImplDList.COUNT());
        if(!EmitMethodImpls())
        {
            if(!OnErrGo) return E_FAIL;
        }
    }
    // Emit the rest of the metadata
    if(bClock) bClock->cMDEmit4 = GetTickCount();
    hr = S_OK;
    if(m_pManifest)
    {
        if (FAILED(hr = m_pManifest->EmitManifest())) goto exit;
    }
    ResolveLocalMemberRefs(); // in case CAs added some
    EmitUnresolvedCustomAttributes();
    // Emit typedefs as special TypeSpecs
    {
#define ELEMENT_TYPE_TYPEDEF (ELEMENT_TYPE_MAX+1)
        TypeDefDescr* pTDD;
        uint8_t* pb;
        unsigned namesize;
        while((pTDD = m_TypeDefDList.POP()))
        {
            BinStr* pbs = new BinStr();
            if(pbs)
            {
                namesize = 1 + (unsigned)strlen(pTDD->m_szName);
                pb = pbs->getBuff(namesize + 1 + sizeof(mdToken));
                *pb = ELEMENT_TYPE_TYPEDEF;
                memcpy(++pb,pTDD->m_szName,namesize);
                pTDD->m_tkTypeSpec = ResolveLocalMemberRef(pTDD->m_tkTypeSpec);
                SET_UNALIGNED_VAL32(pb+namesize, pTDD->m_tkTypeSpec);
                if(TypeFromToken(pTDD->m_tkTypeSpec)==mdtCustomAttribute)
                {
                    CustomDescr* pCA = pTDD->m_pCA;
                    pbs->appendInt32(VAL32(pCA->tkType));
                    pbs->appendInt32(VAL32(pCA->tkOwner));
                    if(pCA->pBlob) pbs->append(pCA->pBlob);
                }
                ResolveTypeSpec(pbs);
                delete pbs;
            }
            delete pTDD;
        }
    }
    if(bClock) bClock->cMDEmitEnd = GetTickCount();

    hr = DoLocalMemberRefFixups();
    if(FAILED(hr) &&(!OnErrGo)) goto exit;
    // Local member refs resolved and fixed up in BinStr method bodies. Emit the bodies.
    {
        Class* pClass;
        Method* pMethod;
        for (int i=0; (pClass = m_lstClass.PEEK(i)); i++)
        {
            for(int j=0; (pMethod = pClass->m_MethodList.PEEK(j)); j++)
            {
                if(!EmitMethodBody(pMethod,NULL))
                {
                    report->msg("Error: failed to emit body of '%s'\n",pMethod->m_szName);
                    hr = E_FAIL;
                    if(!OnErrGo) goto exit;
                }
                pMethod->m_fNewBody = FALSE;
            }
        }
        //while(MethodBody* pMB = m_MethodBodyList.POP()) delete pMB;
    }

    if (DoGlobalFixups() == FALSE)
        return E_FAIL;

    if(m_wzResourceFile)
    {
        MAKE_UTF8PTR_FROMWIDE(szResourceFileUtf8, m_wzResourceFile);
#ifdef TARGET_UNIX
        report->msg("Warning: The Win32 resource file '%s' is ignored and not emitted on xPlatform.\n", szResourceFileUtf8);
#else
        if (FAILED(hr=m_pCeeFileGen->SetResourceFileName(m_pCeeFile, m_wzResourceFile)))
        {
            report->msg("Warning: failed to set Win32 resource file name '%s', hr=0x%8.8X\n         The Win32 resource is not emitted.\n",
                        szResourceFileUtf8, hr);
        }
#endif
    }

    if (FAILED(hr=CreateTLSDirectory())) goto exit;

    if (FAILED(hr=CreateDebugDirectory())) goto exit;

    if (FAILED(hr=m_pCeeFileGen->SetOutputFileName(m_pCeeFile, pwzOutputFilename))) goto exit;

        // Reserve a buffer for the meta-data
    DWORD metaDataSize;
    if (FAILED(hr=m_pEmitter->GetSaveSize(cssAccurate, &metaDataSize))) goto exit;
    BYTE* metaData;
    if (FAILED(hr=m_pCeeFileGen->GetSectionBlock(m_pILSection, metaDataSize, sizeof(DWORD), (void**) &metaData))) goto exit;
    ULONG metaDataOffset;
    if (FAILED(hr=m_pCeeFileGen->GetSectionDataLen(m_pILSection, &metaDataOffset))) goto exit;
    metaDataOffset -= metaDataSize;
    // set managed resource entry, if any
    if(m_pManifest && m_pManifest->m_dwMResSizeTotal)
    {
        mresourceSize = m_pManifest->m_dwMResSizeTotal;

        if (FAILED(hr=m_pCeeFileGen->GetSectionBlock(m_pILSection, mresourceSize,
                                            sizeof(DWORD), (void**) &mresourceData))) goto exit;
        if (FAILED(hr=m_pCeeFileGen->SetManifestEntry(m_pCeeFile, mresourceSize, 0))) goto exit;
    }
    if(m_VTFList.COUNT())
    {
        GlobalLabel *pGlobalLabel;
        VTFEntry*   pVTFEntry;

        if(m_pVTable) delete m_pVTable; // can't have both; list takes precedence
        m_pVTable = new BinStr();
        hr = S_OK;
        for(WORD k=0; (pVTFEntry = m_VTFList.POP()); k++)
        {
            if((pGlobalLabel = FindGlobalLabel(pVTFEntry->m_szLabel)))
            {
                Method* pMD;
                Class* pClass;
                m_pVTable->appendInt32(VAL32(pGlobalLabel->m_GlobalOffset));
                m_pVTable->appendInt16(VAL16(pVTFEntry->m_wCount));
                m_pVTable->appendInt16(VAL16(pVTFEntry->m_wType));
                for(int i=0; (pClass = m_lstClass.PEEK(i)); i++)
                {
                    for(WORD j = 0; (pMD = pClass->m_MethodList.PEEK(j)); j++)
                    {
                        if(pMD->m_wVTEntry == k+1)
                        {
                            char*   ptr;
                            if(SUCCEEDED(hr = m_pCeeFileGen->ComputeSectionPointer(m_pGlobalDataSection,pGlobalLabel->m_GlobalOffset,&ptr)))
                            {
                                DWORD dwDelta;
                                if((pVTFEntry->m_wType & COR_VTABLE_32BIT))
                                {
                                    dwDelta = (pMD->m_wVTSlot-1)*(DWORD)sizeof(DWORD);
                                    ptr += dwDelta;
                                    DWORD* mptr = (DWORD*)ptr;
                                    *mptr = (DWORD)(pMD->m_Tok);
                                }
                                else
                                {
                                    dwDelta = (pMD->m_wVTSlot-1)*(DWORD)sizeof(ULONGLONG);
                                    ptr += dwDelta;
                                    ULONGLONG* mptr = (ULONGLONG*)ptr;
                                    *mptr = (ULONGLONG)(pMD->m_Tok);
                                }
                                if(pMD->m_dwExportOrdinal != 0xFFFFFFFF)
                                {
                                    EATEntry*   pEATE = new EATEntry;
                                    pEATE->dwOrdinal = pMD->m_dwExportOrdinal;
                                    pEATE->szAlias = pMD->m_szExportAlias ? pMD->m_szExportAlias : pMD->m_szName;
                                    pEATE->dwStubRVA = EmitExportStub(pGlobalLabel->m_GlobalOffset+dwDelta);
                                    m_EATList.PUSH(pEATE);
                                }
                            }
                            else
                                report->msg("Error: Failed to get pointer to label '%s' inVTable fixup\n",pVTFEntry->m_szLabel);
                        }
                    }
                }
            }
            else
            {
                report->msg("Error: Unresolved label '%s' in VTable fixup\n",pVTFEntry->m_szLabel);
                hr = E_FAIL;
            }
            delete pVTFEntry;
        }
        if(FAILED(hr)) goto exit;
    }
    if(m_pVTable)
    {
        ULONG i, N = m_pVTable->length()/sizeof(DWORD);
        ULONG ulVTableOffset;
        m_pCeeFileGen->GetSectionDataLen (m_pILSection, &ulVTableOffset);
        // SetVTableEntry will align VTable on DWORD
        ulVTableOffset = (ulVTableOffset + (ULONG)sizeof(DWORD) - 1) & ~((ULONG)sizeof(DWORD) - 1);
        if (FAILED(hr=m_pCeeFileGen->SetVTableEntry64(m_pCeeFile, m_pVTable->length(),(void*)(m_pVTable->ptr())))) goto exit; // @WARNING: casting down from pointer-size to DWORD
        for(i = 0; i < N; i+=2)
        {
            m_pCeeFileGen->AddSectionReloc(m_pILSection,
                                            ulVTableOffset+(i*sizeof(DWORD)),
                                            m_pGlobalDataSection,
                                            srRelocAbsolute);
        }
    }
    if(m_EATList.COUNT())
    {
        if(FAILED(CreateExportDirectory())) goto exit;
        m_dwComImageFlags &= ~COMIMAGE_FLAGS_ILONLY;
        if (m_dwCeeFileFlags & ICEE_CREATE_MACHINE_I386)
            COR_SET_32BIT_REQUIRED(m_dwComImageFlags);
    }

    if (m_dwCeeFileFlags & ICEE_CREATE_MACHINE_ARM || m_fAppContainer)
    {
        // For AppContainer and ARM, you must have a minimum subsystem version of 6.02
        m_wSSVersionMajor = (m_wSSVersionMajor < 6) ? 6 : m_wSSVersionMajor;
        m_wSSVersionMinor = (m_wSSVersionMinor < 2 && m_wSSVersionMajor <= 6) ? 2 : m_wSSVersionMinor;
    }

    // Default the subsystem, instead the user doesn't set it to GUI or CUI
    if (m_dwSubsystem == (DWORD)-1)
        // The default for ILAsm previously was CUI, so that should be the default behavior...
        m_dwSubsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;

    if (FAILED(hr=m_pCeeFileGen->SetSubsystem(m_pCeeFile, m_dwSubsystem, m_wSSVersionMajor, m_wSSVersionMinor))) goto exit;

    if (FAILED(hr=m_pCeeFileGen->ClearComImageFlags(m_pCeeFile, COMIMAGE_FLAGS_ILONLY))) goto exit;
    if (FAILED(hr=m_pCeeFileGen->SetComImageFlags(m_pCeeFile, m_dwComImageFlags))) goto exit;

    if(m_dwFileAlignment)
    {
        if(FAILED(hr=m_pCeeFileGen->SetFileAlignment(m_pCeeFile, m_dwFileAlignment))) goto exit;
    }
    if(m_stBaseAddress)
    {

        if(m_dwCeeFileFlags & ICEE_CREATE_FILE_PE64)
        {
            if(FAILED(hr=m_pCeeFileGen->SetImageBase64(m_pCeeFile, m_stBaseAddress))) goto exit;
        }
        else
        {
            if(FAILED(hr=m_pCeeFileGen->SetImageBase(m_pCeeFile, (size_t)m_stBaseAddress))) goto exit;
        }
    }
    if(m_stSizeOfStackReserve || m_fAppContainer || m_fHighEntropyVA)
    {
        PIMAGE_NT_HEADERS   pNT;
        PIMAGE_SECTION_HEADER   pSect;
        ULONG   ulNumSect;
        if(FAILED(hr=m_pCeeFileGen->GetHeaderInfo(m_pCeeFile,&pNT,&pSect,&ulNumSect))) goto exit;
        if(m_dwCeeFileFlags & ICEE_CREATE_FILE_PE64)
        {
            PIMAGE_OPTIONAL_HEADER64 pOpt = (PIMAGE_OPTIONAL_HEADER64)(&pNT->OptionalHeader);
            if (m_stSizeOfStackReserve)
                pOpt->SizeOfStackReserve = VAL64(m_stSizeOfStackReserve);
            if (m_fAppContainer)
                pOpt->DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_APPCONTAINER;
            if (m_fHighEntropyVA)
                pOpt->DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA;
        }
        else
        {
            PIMAGE_OPTIONAL_HEADER32 pOpt = (PIMAGE_OPTIONAL_HEADER32)(&pNT->OptionalHeader);
            if (m_stSizeOfStackReserve)
                pOpt->SizeOfStackReserve = (DWORD)VAL32(m_stSizeOfStackReserve);
            if (m_fAppContainer)
                pOpt->DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_APPCONTAINER;
            if (m_fHighEntropyVA)
                pOpt->DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA;
        }
    }
        //Compute all the RVAs
    if (FAILED(hr=m_pCeeFileGen->LinkCeeFile(m_pCeeFile))) goto exit;

        // Fix up any fields that have RVA associated with them
    if (m_fHaveFieldsWithRvas) {
        hr = S_OK;
        ULONG dataSectionRVA;
        if (FAILED(hr=m_pCeeFileGen->GetSectionRVA(m_pGlobalDataSection, &dataSectionRVA))) goto exit;

        ULONG tlsSectionRVA;
        if (FAILED(hr=m_pCeeFileGen->GetSectionRVA(m_pTLSSection, &tlsSectionRVA))) goto exit;

        ULONG ilSectionRVA;
        if (FAILED(hr=m_pCeeFileGen->GetSectionRVA(m_pILSection, &ilSectionRVA))) goto exit;

        FieldDescriptor* pListFD;
        Class* pClass;
        for(int i=0; (pClass = m_lstClass.PEEK(i)); i++)
        {
            for(int j=0; (pListFD = pClass->m_FieldDList.PEEK(j)); j++)
            {
                if (pListFD->m_rvaLabel != 0)
                {
                    DWORD rva;
                    if(*(pListFD->m_rvaLabel)=='@')
                    {
                        rva = (DWORD)atoi(pListFD->m_rvaLabel + 1);
                    }
                    else
                    {
                        GlobalLabel *pLabel = FindGlobalLabel(pListFD->m_rvaLabel);
                        if (pLabel == 0)
                        {
                            report->msg("Error:Could not find label '%s' for the field '%s'\n", pListFD->m_rvaLabel, pListFD->m_szName);
                            hr = E_FAIL;
                            continue;
                        }

                        rva = pLabel->m_GlobalOffset;
                        if (pLabel->m_Section == m_pTLSSection)
                            rva += tlsSectionRVA;
                        else if (pLabel->m_Section == m_pILSection)
                            rva += ilSectionRVA;
                        else {
                            _ASSERTE(pLabel->m_Section == m_pGlobalDataSection);
                            rva += dataSectionRVA;
                        }
                    }
                    if (FAILED(m_pEmitter->SetFieldRVA(pListFD->m_fdFieldTok, rva))) goto exit;
                }
            }
        }
        if (FAILED(hr)) goto exit;
    }

    if(bClock) bClock->cFilegenBegin = GetTickCount();
    // actually output the meta-data
    if (FAILED(hr=m_pCeeFileGen->EmitMetaDataAt(m_pCeeFile, m_pEmitter, m_pILSection, metaDataOffset, metaData, metaDataSize))) goto exit;

    if((m_wMSVmajor < 0xFF)&&(m_wMSVminor < 0xFF))
    {
        STORAGESIGNATURE *pSSig = (STORAGESIGNATURE *)metaData;
        BYTE* pb = metaData;
        pb += 3*sizeof(DWORD)+2*sizeof(WORD)+VAL32(pSSig->iVersionString);
        pb = (BYTE*)(((size_t)pb + 3) & ~3);
        PSTORAGEHEADER pSHdr = (PSTORAGEHEADER)pb;
        PSTORAGESTREAM pStr = (PSTORAGESTREAM)(pSHdr+1);
        for(short iStr = 1; iStr <= VAL16(pSHdr->iStreams); iStr++)
        {
            if((strcmp(pStr->rcName,"#-")==0)||(strcmp(pStr->rcName,"#~")==0))
            {
                pb = metaData + VAL32(pStr->iOffset); // start of the stream header
                pb += sizeof(DWORD); // skip Reserved
                *pb = VAL16(m_wMSVmajor)&0xFF;
                *(pb+1) = VAL16(m_wMSVminor)&0xFF;
                break;
            }
            pb = (BYTE*)pStr;
            pb += 2*sizeof(DWORD)+strlen(pStr->rcName)+1;
            pb = (BYTE*)(((size_t)pb + 3) & ~3);
            pStr = (PSTORAGESTREAM)pb;
        }
    }

    if(m_fTolerateDupMethods) // means that there are /ENC files
    {
        if(m_pbsMD) delete m_pbsMD;
        m_pbsMD = new BinStr();
        memcpy(m_pbsMD->getBuff(metaDataSize),metaData,metaDataSize);
    }
    // actually output the resources
    if(mresourceSize && mresourceData)
    {
        size_t i, N = m_pManifest->m_dwMResNum, sizeread, L;
        BYTE    *ptr = (BYTE*)mresourceData;
        BOOL    mrfail = FALSE;
        FILE*   pFile = NULL;
        char sz[2048];
        for(i=0; i < N; i++)
        {
            m_pManifest->m_fMResNew[i] = FALSE;
            memset(sz,0,2048);
            WideCharToMultiByte(CP_ACP,0,m_pManifest->m_wzMResName[i],-1,sz,2047,NULL,NULL);
            L = m_pManifest->m_dwMResSize[i];
            sizeread = 0;
            memcpy(ptr,&L,sizeof(DWORD));
            ptr += sizeof(DWORD);
            if(fopen_s(&pFile,sz,"rb") == 0)
            {
                sizeread = fread((void *)ptr,1,L,pFile);
                fclose(pFile);
                ptr += sizeread;
            }
            else
            {
                report->msg("Error: failed to open mgd resource file '%s'\n",sz);
                mrfail = TRUE;
            }
            if(sizeread < L)
            {
                report->msg("Error: failed to read expected %d bytes from mgd resource file '%s'\n",L,sz);
                mrfail = TRUE;
                L -= sizeread;
                memset(ptr,0,L);
                ptr += L;
            }
        }
        if(mrfail)
        {
            hr = E_FAIL;
            goto exit;
        }
    }

    hr = S_OK;

exit:
    return hr;
}