Aracılığıyla paylaş


Nasıl Yapılır: .NET Framework 4.5 Yükleyicisinden İlerleme Durumunu Alma

.NET Framework 4.5 yeniden dağıtılabilir bir çalışma zamanıdır. .NET Framework'ün bu sürümü için uygulama geliştirirseniz, uygulamanızın kurulumunun önkoşul bir parçası olarak .NET Framework 4.5 kurulumunu dahil edebilirsiniz (zincir). Özelleştirilmiş veya birleşik bir kurulum deneyimi sunmak için ,NET Framework 4.5 kurulumunu sessizce başlatmak ve uygulamanızın kurulum ilerleme durumunu gösterirken ilerleme durumunu izlemek isteyebilirsiniz. Sessiz izlemeyi etkinleştirmek için .NET Framework 4.5 kurulumu (izlenebilir), kurulumunuzla (izleyici veya zincirleyici) iletişim kurmak için belleğe eşlenmiş G/Ç (MMIO) kesimi kullanarak bir protokol tanımlar. Bu protokol, bir zincirleyicinin ilerleme bilgilerini alması, ayrıntılı sonuçlar alması, iletilere yanıt vermesi ve .NET Framework 4.5 kurulumunu iptal edebilmesi için bir yol tanımlar.

  • Çağırma. .NET Framework 4.5 kurulumunu çağırmak ve MMIO bölümünden ilerleme bilgilerini almak için kurulum programınızın aşağıdakileri yapması gerekir:

    1. .NET Framework 4.5 yeniden dağıtılabilir programını çağırın:

      dotNetFx45_Full_x86_x64.exe /q /norestart /pipe section-name

      Burada bölüm adı , uygulamanızı tanımlamak için kullanmak istediğiniz herhangi bir addır. .NET Framework kurulumu, MMIO bölümünü zaman uyumsuz olarak okur ve yazar, bu nedenle bu süre boyunca olayları ve iletileri kullanmayı uygun bulabilirsiniz. Örnekte .NET Framework kurulum işlemi, hem MMIO bölümünü (TheSectionName) ayıran hem de bir olayTheEventName () tanımlayan bir oluşturucu tarafından oluşturulur:

      Server():ChainerSample::MmioChainer(L"TheSectionName", L"TheEventName")
      

      Lütfen bu adları kurulum programınıza özgü adlarla değiştirin.

    2. MMIO bölümünden okuyun. .NET Framework 4.5'te indirme ve yükleme işlemleri aynı anda yapılır: .NET Framework'ün bir bölümü yüklenirken başka bir bölüm indiriliyor olabilir. Sonuç olarak, ilerleme 0'dan 255'e çıkan iki sayı ( ve m_installSoFar) olarak MMIO bölümüne geri gönderilir (m_downloadSoFaryani yazılır). 255 yazıldığında ve .NET Framework'te çıkıldığında yükleme tamamlanır.

  • Çıkış kodları. .NET Framework 4.5 yeniden dağıtılabilir programını çağırmak için komutundan aşağıdaki çıkış kodları kurulumun başarılı mı yoksa başarısız mı olduğunu gösterir:

    • 0 - Kurulum başarıyla tamamlandı.

    • 3010 – Kurulum başarıyla tamamlandı; bir sistem yeniden başlatması gerekir.

    • 1602 – Kurulum iptal edildi.

    • Diğer tüm kodlar - Kurulum hatalarla karşılaştı; ayrıntılar için %temp% içinde oluşturulan günlük dosyalarını inceleyin.

  • Kurulum iptal edildi. MMIO bölümündeki ve m_ installAbort bayraklarını ayarlamak m_downloadAbort için yöntemini kullanarak Abort istediğiniz zaman kurulumu iptal edebilirsiniz.

Zincirleyici Örneği

Chainer örneği, ilerleme durumunu gösterirken .NET Framework 4.5 kurulumunu sessizce başlatır ve izler. Bu örnek, .NET Framework 4 için sağlanan Chainer örneğine benzer. Bununla birlikte, .NET Framework 4 uygulamalarını kapatmak için ileti kutusunu işleyerek sistem yeniden başlatmalarını önleyebilir. Bu ileti kutusu hakkında bilgi için bkz . .NET Framework 4.5 Yüklemeleri Sırasında Sistem Yeniden Başlatmalarını Azaltma. Bu örneği .NET Framework 4 yükleyicisi ile kullanabilirsiniz; bu senaryoda ileti gönderilmez.

Uyarı

Örneği yönetici olarak çalıştırmanız gerekir.

Aşağıdaki bölümlerde bu örnekteki önemli dosyalar açıklanmaktadır: MMIOChainer.h, ChainingdotNet4.cpp ve IProgressObserver.h.

MMIOChainer.h

  • MMIOChainer.h dosyası, veri yapısı tanımını ve zincirleyici sınıfının türetilmesi gereken temel sınıfı içerir. .NET Framework 4.5, .NET Framework 4.5 yükleyicisinin ihtiyaç duyduğu verileri işlemek için MMIO veri yapısını genişletir. MMIO yapısındaki değişiklikler geriye dönük olarak uyumludur, bu nedenle .NET Framework 4 zincirleyicisi yeniden derleme gerektirmeden .NET Framework 4.5 kurulumuyla çalışabilir. Ancak, bu senaryo sistem yeniden başlatmalarını azaltma özelliğini desteklemez.

    Sürüm alanı, yapı ve ileti biçimindeki düzeltmeleri tanımlamanın bir aracıdır. .NET Framework kurulumu, dosya eşlemesinin boyutunu belirlemek için işlevini çağırarak VirtualQuery zincirleyici arabiriminin sürümünü belirler. Boyut sürüm alanına sığacak kadar büyükse, .NET Framework kurulumu belirtilen değeri kullanır. Dosya eşlemesi .NET Framework 4'de olduğu gibi bir sürüm alanı içeremeyecek kadar küçükse, kurulum işlemi 0 (4) sürümünü varsayar. Zincirleyici , .NET Framework kurulumunun göndermek istediği iletinin sürümünü desteklemiyorsa, .NET Framework kurulumu yanıtı yoksayar.

    MMIO veri yapısı aşağıdaki gibi tanımlanır:

    // MMIO data structure for interprocess communication
        struct MmioDataStructure
        {
            bool m_downloadFinished;               // Is download complete?
            bool m_installFinished;                // Is installation complete?
            bool m_downloadAbort;                  // Set to cause downloader to abort.
            bool m_installAbort;                   // Set to cause installer to abort.
            HRESULT m_hrDownloadFinished;          // Resulting HRESULT for download.
            HRESULT m_hrInstallFinished;           // Resulting HRESULT for installation.
            HRESULT m_hrInternalError;
            WCHAR m_szCurrentItemStep[MAX_PATH];
            unsigned char m_downloadSoFar;         // Download progress 0-255 (0-100% done).
            unsigned char m_installSoFar;          // Installation progress 0-255 (0-100% done).
            WCHAR m_szEventName[MAX_PATH];         // Event that chainer creates and chainee opens to sync communications.
    
            BYTE m_version;                        // Version of the data structure, set by chainer:
                                                   // 0x0: .NET Framework 4
                                                   // 0x1: .NET Framework 4.5
    
            DWORD m_messageCode;                   // Current message sent by the chainee; 0 if no message is active.
            DWORD m_messageResponse;               // Chainer's response to current message; 0 if not yet handled.
            DWORD m_messageDataLength;             // Length of the m_messageData field, in bytes.
            BYTE m_messageData[1];                 // Variable-length buffer; content depends on m_messageCode.
        };
    
  • Veri MmioDataStructure yapısı doğrudan kullanılmamalıdır; zincirleyicinizi uygulamak için bunun yerine sınıfını kullanın MmioChainer . .NET Framework 4.5 yeniden dağıtılabilir zinciri için sınıfından MmioChainer türetilir.

IProgressObserver.h

  • IProgressObserver.h dosyası bir ilerleme gözlemcisi uygular. Bu gözlemciye indirme ve yükleme ilerleme durumu bildirilir (imzasız charolarak belirtilir, %1-100 tamamlandı olarak 0-255). Ayrıca, zincirleme bir ileti gönderdiğinde gözlemciye de bildirim gönderilir ve gözlemcinin bir yanıt göndermesi gerekir.

        class IProgressObserver
        {
        public:
            virtual void OnProgress(unsigned char) = 0; // 0 - 255:  255 == 100%
            virtual void Finished(HRESULT) = 0;         // Called when operation is complete
            virtual DWORD Send(DWORD dwMessage, LPVOID pData, DWORD dwDataLength) = 0; // Called when a message is sent
        };
    

ChainingdotNet4.5.cpp

  • ChainingdotNet4.5.cpp dosyası, sınıfından Server türetilen MmioChainer ve ilerleme bilgilerini görüntülemek için uygun yöntemleri geçersiz kılan sınıfını uygular. MmioChainer, belirtilen bölüm adına sahip bir bölüm oluşturur ve zincirleyiciyi belirtilen olay adıyla başlatır. Olay adı eşlenen veri yapısına kaydedilir. Bölüm ve olay adlarını benzersiz yapmalısınız. Server Aşağıdaki koddaki sınıf, belirtilen kurulum programını başlatır, ilerleme durumunu izler ve bir çıkış kodu döndürür.

    class Server : public ChainerSample::MmioChainer, public ChainerSample::IProgressObserver
    {
    public:
        …………….
        Server():ChainerSample::MmioChainer(L"TheSectionName", L"TheEventName") //customize for your event names
        {}
    

    Yükleme Main yönteminde başlatılır.

    // Main entry point for program
    int __cdecl main(int argc, _In_count_(argc) char **_argv)
    {
        int result = 0;
        CString args;
        if (argc > 1)
        {
            args = CString(_argv[1]);
        }
    
        if (IsNetFx4Present(NETFX45_RC_REVISION))
        {
            printf(".NET Framework 4.5 is already installed");
        }
        else
        {
            result = Server().Launch(args);
        }
    
        return result;
    }
    
  • Yüklemeyi başlatmadan önce zincirleyici çağrısı yaparak IsNetFx4Present.NET Framework 4.5'in zaten yüklü olup olmadığını denetler:

    ///  Checks for presence of the .NET Framework 4.
    ///    A value of 0 for dwMinimumRelease indicates a check for the .NET Framework 4 full
    ///    Any other value indicates a check for a specific compatible release of the .NET Framework 4.
    #define NETFX40_FULL_REVISION 0
    // TODO: Replace with released revision number
    #define NETFX45_RC_REVISION MAKELONG(50309, 5)   // .NET Framework 4.5
    bool IsNetFx4Present(DWORD dwMinimumRelease)
    {
        DWORD dwError = ERROR_SUCCESS;
        HKEY hKey = NULL;
        DWORD dwData = 0;
        DWORD dwType = 0;
        DWORD dwSize = sizeof(dwData);
    
        dwError = ::RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full", 0, KEY_READ, &hKey);
        if (ERROR_SUCCESS == dwError)
        {
            dwError = ::RegQueryValueExW(hKey, L"Release", 0, &dwType, (LPBYTE)&dwData, &dwSize);
    
            if ((ERROR_SUCCESS == dwError) && (REG_DWORD != dwType))
            {
                dwError = ERROR_INVALID_DATA;
            }
            else if (ERROR_FILE_NOT_FOUND == dwError)
            {
                // Release value was not found, let's check for 4.0.
                dwError = ::RegQueryValueExW(hKey, L"Install", 0, &dwType, (LPBYTE)&dwData, &dwSize);
    
                // Install = (REG_DWORD)1;
                if ((ERROR_SUCCESS == dwError) && (REG_DWORD == dwType) && (dwData == 1))
                {
                    // treat 4.0 as Release = 0
                    dwData = 0;
                }
                else
                {
                    dwError = ERROR_INVALID_DATA;
                }
            }
        }
    
        if (hKey != NULL)
        {
            ::RegCloseKey(hKey);
        }
    
        return ((ERROR_SUCCESS == dwError) && (dwData >= dwMinimumRelease));
    }
    
  • Yöntemdeki yürütülebilir dosyanın yolunu (örnekte Setup.exe) Launch doğru konumuna işaret etmek için değiştirebilir veya konumu belirlemek için kodu özelleştirebilirsiniz. MmioChainer Temel sınıf, türetilmiş sınıfın çağıran bir engelleme Run() yöntemi sağlar.

    bool Launch(const CString& args)
    {
    CString cmdline = L"dotNetFx45_Full_x86_x64.exe -pipe TheSectionName " + args; // Customize with name and location of setup .exe that you want to run
    STARTUPINFO si = {0};
    si.cb = sizeof(si);
    PROCESS_INFORMATION pi = {0};
    
    // Launch the Setup.exe that installs the .NET Framework 4.5
    BOOL bLaunchedSetup = ::CreateProcess(NULL,
     cmdline.GetBuffer(),
     NULL, NULL, FALSE, 0, NULL, NULL,
     &si,
     &pi);
    
    // If successful
    if (bLaunchedSetup != 0)
    {
    IProgressObserver& observer = dynamic_cast<IProgressObserver&>(*this);
    Run(pi.hProcess, observer);
    
    ……………………..
    return (bLaunchedSetup != 0);
    }
    
  • Send yöntemi iletileri durdurur ve işler. .NET Framework'ün bu sürümünde desteklenen tek ileti, yakın uygulama iletisidir.

            // SendMessage
            //
            // Send a message and wait for the response.
            // dwMessage: Message to send
            // pData: The buffer to copy the data to
            // dwDataLength: Initially a pointer to the size of pBuffer. Upon successful call, the number of bytes copied to pBuffer.
            //--------------------------------------------------------------
        virtual DWORD Send(DWORD dwMessage, LPVOID pData, DWORD dwDataLength)
        {
            DWORD dwResult = 0;
            printf("received message: %d\n", dwMessage);
            // Handle message
            switch (dwMessage)
            {
            case MMIO_CLOSE_APPS:
                {
                    printf("    applications are holding files in use:\n");
                    IronMan::MmioCloseApplications* applications = reinterpret_cast<IronMan::MmioCloseApplications*>(pData);
                    for(DWORD i = 0; i < applications->m_dwApplicationsSize; i++)
                    {
                        printf("      %ls (%d)\n", applications->m_applications[i].m_szName, applications->m_applications[i].m_dwPid);
                    }
    
                    printf("    should applications be closed? (Y)es, (N)o, (R)efresh : ");
                    while (dwResult == 0)
                    {
                        switch (toupper(getwchar()))
                        {
                        case 'Y':
                            dwResult = IDYES;  // Close apps
                            break;
                        case 'N':
                            dwResult = IDNO;
                            break;
                        case 'R':
                            dwResult = IDRETRY;
                            break;
                        }
                    }
                    printf("\n");
                    break;
                }
            default:
                break;
            }
            printf("  response: %d\n  ", dwResult);
            return dwResult;
        }
    };
    
  • İlerleme verileri 0 (%0) ile 255 (%100) arasında işaretsizdir char .

    private: // IProgressObserver
        virtual void OnProgress(unsigned char ubProgressSoFar)
        {…………
       }
    
  • HRESULT yöntemine Finished geçirilir.

    virtual void Finished(HRESULT hr)
    {
    // This HRESULT is communicated over MMIO and may be different than process
    // Exit code of the Chainee Setup.exe itself
    printf("\r\nFinished HRESULT: 0x%08X\r\n", hr);
    }
    

    Önemli

    .NET Framework 4.5 yeniden dağıtılabilir sürümü genellikle birçok ilerleme iletisi ve tamamlandığını belirten tek bir ileti (zincirleyici tarafında) yazar. Ayrıca zaman uyumsuz olarak okuyarak kayıtları arar Abort . Bir Abort kayıt alırsa, yüklemeyi iptal eder ve yükleme durdurulduktan ve kurulum işlemleri geri alındıktan sonra verileri olarak E_ABORT ile tamamlanmış bir kayıt yazar.

Tipik bir sunucu rastgele bir MMIO dosya adı oluşturur, dosyayı oluşturur (önceki kod örneğinde gösterildiği gibi, içinde Server::CreateSection) ve yöntemini kullanarak CreateProcess ve kanal adını seçeneğiyle geçirerek yeniden dağıtılabilir'i -pipe someFileSectionName başlatır. Sunucu, uygulama kullanıcı arabirimine özgü kodla , Sendve Finished yöntemlerini uygulamalıdırOnProgress.

Ayrıca bkz.