void MemoryLoadLibrary(byte[] data)
    {
        if (data.Length < Marshal.SizeOf(typeof(IMAGE_DOS_HEADER)))
        {
            throw new DllException("Not a valid executable file");
        }
        IMAGE_DOS_HEADER DosHeader = BytesReadStructAt <IMAGE_DOS_HEADER>(data, 0);

        if (DosHeader.e_magic != Win.IMAGE_DOS_SIGNATURE)
        {
            throw new BadImageFormatException("Not a valid executable file");
        }

        if (data.Length < DosHeader.e_lfanew + Marshal.SizeOf(typeof(IMAGE_NT_HEADERS)))
        {
            throw new DllException("Not a valid executable file");
        }
        IMAGE_NT_HEADERS OrgNTHeaders = BytesReadStructAt <IMAGE_NT_HEADERS>(data, DosHeader.e_lfanew);

        if (OrgNTHeaders.Signature != Win.IMAGE_NT_SIGNATURE)
        {
            throw new BadImageFormatException("Not a valid PE file");
        }
        if (OrgNTHeaders.FileHeader.Machine != GetMachineType())
        {
            throw new BadImageFormatException("Machine type doesn't fit (i386 vs. AMD64)");
        }
        if ((OrgNTHeaders.OptionalHeader.SectionAlignment & 1) > 0)
        {
            throw new BadImageFormatException("Wrong section alignment");                                                         //Only support multiple of 2
        }
        if (OrgNTHeaders.OptionalHeader.AddressOfEntryPoint == 0)
        {
            throw new DllException("Module has no entry point");
        }

        SYSTEM_INFO systemInfo;

        Win.GetNativeSystemInfo(out systemInfo);
        uint lastSectionEnd = 0;
        int  ofSection      = Win.IMAGE_FIRST_SECTION(DosHeader.e_lfanew, OrgNTHeaders.FileHeader.SizeOfOptionalHeader);

        for (int i = 0; i != OrgNTHeaders.FileHeader.NumberOfSections; i++, ofSection += Sz.IMAGE_SECTION_HEADER)
        {
            IMAGE_SECTION_HEADER Section = BytesReadStructAt <IMAGE_SECTION_HEADER>(data, ofSection);
            uint endOfSection            = Section.VirtualAddress + (Section.SizeOfRawData > 0 ? Section.SizeOfRawData : OrgNTHeaders.OptionalHeader.SectionAlignment);
            if (endOfSection > lastSectionEnd)
            {
                lastSectionEnd = endOfSection;
            }
        }

        uint alignedImageSize   = AlignValueUp(OrgNTHeaders.OptionalHeader.SizeOfImage, systemInfo.dwPageSize);
        uint alignedLastSection = AlignValueUp(lastSectionEnd, systemInfo.dwPageSize);

        if (alignedImageSize != alignedLastSection)
        {
            throw new BadImageFormatException("Wrong section alignment");
        }

        IntPtr oldHeader_OptionalHeader_ImageBase;

        if (Is64BitProcess)
        {
            oldHeader_OptionalHeader_ImageBase = (IntPtr) unchecked ((long)(OrgNTHeaders.OptionalHeader.ImageBaseLong));
        }
        else
        {
            oldHeader_OptionalHeader_ImageBase = (IntPtr) unchecked ((int)(OrgNTHeaders.OptionalHeader.ImageBaseLong >> 32));
        }

        // reserve memory for image of library
        pCode = Win.VirtualAlloc(oldHeader_OptionalHeader_ImageBase, (UIntPtr)OrgNTHeaders.OptionalHeader.SizeOfImage, AllocationType.RESERVE | AllocationType.COMMIT, MemoryProtection.READWRITE);
        //pCode = IntPtr.Zero; //test relocation with this

        // try to allocate memory at arbitrary position
        if (pCode == IntPtr.Zero)
        {
            pCode = Win.VirtualAlloc(IntPtr.Zero, (UIntPtr)OrgNTHeaders.OptionalHeader.SizeOfImage, AllocationType.RESERVE | AllocationType.COMMIT, MemoryProtection.READWRITE);
        }

        if (pCode == IntPtr.Zero)
        {
            throw new DllException("Out of Memory");
        }

        if (Is64BitProcess && PtrSpanBoundary(pCode, alignedImageSize, 32))
        {
            // Memory block may not span 4 GB (32 bit) boundaries.
            System.Collections.Generic.List <IntPtr> BlockedMemory = new System.Collections.Generic.List <IntPtr>();
            while (PtrSpanBoundary(pCode, alignedImageSize, 32))
            {
                BlockedMemory.Add(pCode);
                pCode = Win.VirtualAlloc(IntPtr.Zero, (UIntPtr)alignedImageSize, AllocationType.RESERVE | AllocationType.COMMIT, MemoryProtection.READWRITE);
                if (pCode == IntPtr.Zero)
                {
                    break;
                }
            }
            foreach (IntPtr ptr in BlockedMemory)
            {
                Win.VirtualFree(ptr, IntPtr.Zero, AllocationType.RELEASE);
            }
            if (pCode == IntPtr.Zero)
            {
                throw new DllException("Out of Memory");
            }
        }

        // commit memory for headers
        IntPtr headers = Win.VirtualAlloc(pCode, (UIntPtr)OrgNTHeaders.OptionalHeader.SizeOfHeaders, AllocationType.COMMIT, MemoryProtection.READWRITE);

        if (headers == IntPtr.Zero)
        {
            throw new DllException("Out of Memory");
        }

        // copy PE header to code
        Marshal.Copy(data, 0, headers, (int)(OrgNTHeaders.OptionalHeader.SizeOfHeaders));
        pNTHeaders = PtrAdd(headers, DosHeader.e_lfanew);

        IntPtr locationDelta = PtrSub(pCode, oldHeader_OptionalHeader_ImageBase);

        if (locationDelta != IntPtr.Zero)
        {
            // update relocated position
            Marshal.OffsetOf(typeof(IMAGE_NT_HEADERS), "OptionalHeader");
            Marshal.OffsetOf(typeof(IMAGE_OPTIONAL_HEADER), "ImageBaseLong");
            IntPtr pImageBase = PtrAdd(pNTHeaders, Of.IMAGE_NT_HEADERS_OptionalHeader + (Is64BitProcess ? Of64.IMAGE_OPTIONAL_HEADER_ImageBase : Of32.IMAGE_OPTIONAL_HEADER_ImageBase));
            PtrWrite(pImageBase, pCode);
        }

        // copy sections from DLL file block to new memory location
        CopySections(ref OrgNTHeaders, pCode, pNTHeaders, data);

        // adjust base address of imported data
        _isRelocated = (locationDelta != IntPtr.Zero ? PerformBaseRelocation(ref OrgNTHeaders, pCode, locationDelta) : true);

        // load required dlls and adjust function table of imports
        ImportModules = BuildImportTable(ref OrgNTHeaders, pCode);

        // mark memory pages depending on section headers and release
        // sections that are marked as "discardable"
        FinalizeSections(ref OrgNTHeaders, pCode, pNTHeaders, systemInfo.dwPageSize);

        // TLS callbacks are executed BEFORE the main loading
        ExecuteTLS(ref OrgNTHeaders, pCode, pNTHeaders);

        // get entry point of loaded library
        IsDll = ((OrgNTHeaders.FileHeader.Characteristics & Win.IMAGE_FILE_DLL) != 0);
        if (OrgNTHeaders.OptionalHeader.AddressOfEntryPoint != 0)
        {
            if (IsDll)
            {
                // notify library about attaching to process
                IntPtr dllEntryPtr = PtrAdd(pCode, OrgNTHeaders.OptionalHeader.AddressOfEntryPoint);
                _dllEntry = (DllEntryDelegate)Marshal.GetDelegateForFunctionPointer(dllEntryPtr, typeof(DllEntryDelegate));

                _initialized = (_dllEntry != null && _dllEntry(pCode, DllReason.DLL_PROCESS_ATTACH, IntPtr.Zero));
                if (!_initialized)
                {
                    throw new DllException("Can't attach DLL to process");
                }
            }
            else
            {
                IntPtr exeEntryPtr = PtrAdd(pCode, OrgNTHeaders.OptionalHeader.AddressOfEntryPoint);
                _exeEntry = (ExeEntryDelegate)Marshal.GetDelegateForFunctionPointer(exeEntryPtr, typeof(ExeEntryDelegate));
            }
        }
    }