Postupy: Získání procesu z instalačního programu .NET Framework 4.5

.NET Framework 4.5 je redistribuovatelný modul runtime. Pokud vyvíjíte aplikace pro tuto verzi rozhraní .NET Framework, můžete jako součást nastavení aplikace zahrnout (řetěz) .NET Framework 4.5. Pokud chcete prezentovat přizpůsobené nebo sjednocené prostředí instalace, můžete chtít bezobslužně spustit instalaci rozhraní .NET Framework 4.5 a sledovat jeho průběh při zobrazování průběhu instalace vaší aplikace. Pokud chcete povolit bezobslužné sledování, instalační program rozhraní .NET Framework 4.5 (který je možné sledovat) definuje protokol pomocí segmentu mmIO (memory mapped I/O) ke komunikaci s vaším nastavením (watcher nebo chainer). Tento protokol definuje způsob, jak zřetězený získat informace o průběhu, získat podrobné výsledky, reagovat na zprávy a zrušit instalaci rozhraní .NET Framework 4.5.

  • Vyvolání. Pokud chcete volat instalaci rozhraní .NET Framework 4.5 a přijímat informace o průběhu z oddílu MMIO, instalační program musí provést následující:

    1. Volání redistribuovatelného programu .NET Framework 4.5:

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

      Kde název oddílu je libovolný název, který chcete použít k identifikaci aplikace. Nastavení rozhraní .NET Framework načítá a zapisuje do oddílu MMIO asynchronně, takže během této doby může být vhodné používat události a zprávy. V tomto příkladu je proces nastavení rozhraní .NET Framework vytvořen konstruktorem, který přiděluje oddíl MMIO (TheSectionName) a definuje událost (TheEventName):

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

      Nahraďte tyto názvy názvy názvy, které jsou jedinečné pro váš instalační program.

    2. Přečtěte si část MMIO. V rozhraní .NET Framework 4.5 jsou operace stahování a instalace souběžné: Jedna část rozhraní .NET Framework může být nainstalována, zatímco se stahuje jiná část. V důsledku toho se průběh odešle zpět (tj. zapisuje) do oddílu MMIO jako dvě čísla (m_downloadSoFar a m_installSoFar) se zvětší od 0 do 255. Po napsání 255 a ukončení rozhraní .NET Framework se instalace dokončí.

  • Ukončovací kódy. Následující ukončovací kódy z příkazu pro volání redistribuovatelného programu .NET Framework 4.5 označují, jestli instalace byla úspěšná nebo neúspěšná:

    • 0 – Instalace byla úspěšně dokončena.

    • 3010 – Instalace byla úspěšně dokončena; vyžaduje se restartování systému.

    • 1602 – Instalace byla zrušena.

    • Všechny ostatní kódy – Nastavení zjistilo chyby; Podrobnosti najdete v souborech protokolu vytvořených v %temp% .

  • Probíhá zrušení instalace. Nastavení můžete kdykoli zrušit pomocí Abort metody k nastavení m_downloadAbort a m_ installAbort příznaků v části MMIO.

Ukázka chaineru

Ukázka Chaineru se bezobslužně spustí a sleduje nastavení rozhraní .NET Framework 4.5 při zobrazování průběhu. Tato ukázka je podobná ukázce Chaineru, která je k dispozici pro rozhraní .NET Framework 4. Kromě toho se však může vyhnout restartování systému tím, že zpracuje pole zprávy pro zavření aplikací .NET Framework 4. Informace o tomto okně zprávy naleznete v tématu Snížení restartování systému během instalace rozhraní .NET Framework 4.5. Tuto ukázku můžete použít s instalačním programem rozhraní .NET Framework 4; v tomto scénáři se zpráva jednoduše neodesílají.

Upozornění

Příklad musíte spustit jako správce.

Následující části popisují významné soubory v této ukázce: MMIOChainer.h, ChainingdotNet4.cpp a IProgressObserver.h.

MMIOChainer.h

  • Soubor MMIOChainer.h obsahuje definici datové struktury a základní třídu, ze které by měla být odvozena třída chaineru. Rozhraní .NET Framework 4.5 rozšiřuje datovou strukturu MMIO tak, aby zpracovávala data, která potřebuje instalační program rozhraní .NET Framework 4.5. Změny struktury MMIO jsou zpětně kompatibilní, takže chainer .NET Framework 4 může pracovat s nastavením rozhraní .NET Framework 4.5 bez nutnosti rekompilace. Tento scénář ale nepodporuje funkci pro snížení restartování systému.

    Pole verze poskytuje způsob identifikace revizí struktury a formátu zpráv. Nastavení rozhraní .NET Framework určuje verzi rozhraní chaineru voláním VirtualQuery funkce k určení velikosti mapování souborů. Pokud je velikost dostatečně velká, aby vyhovovala poli verze, instalační program .NET Framework použije zadanou hodnotu. Pokud je mapování souborů příliš malé, aby obsahovalo pole verze, což je případ s rozhraním .NET Framework 4, instalační proces předpokládá verzi 0 (4). Pokud chainer nepodporuje verzi zprávy, že instalační program .NET Framework chce odeslat, instalace rozhraní .NET Framework předpokládá ignorovanou odpověď.

    Datová struktura MMIO je definována takto:

    // 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.
        };
    
  • Datová MmioDataStructure struktura by neměla být použita přímo. Místo toho použijte MmioChainer třídu k implementaci řetězeče. Odvozujte od MmioChainer třídy, která zřetězuje distribuovatelné rozhraní .NET Framework 4.5.

IProgressObserver.h

  • Soubor IProgressObserver.h implementuje pozorovatele průběhu. Tento pozorovatel obdrží oznámení o průběhu stahování a instalace (zadaný jako nepodepsaný char, 0–255, což označuje dokončení 1%-100 %. Pozorovatel je také upozorněn, když řetěze odešle zprávu a pozorovatel by měl odeslat odpověď.

        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

  • Soubor ChainingdotNet4.5.cpp implementuje Server třídu, která je odvozena od MmioChainer třídy a přepíše příslušné metody pro zobrazení informací o průběhu. MmioChainer vytvoří oddíl se zadaným názvem oddílu a inicializuje chainer se zadaným názvem události. Název události se uloží do mapované datové struktury. Oddíl a názvy událostí byste měli nastavit jako jedinečné. Třída Server v následujícím kódu spustí zadaný instalační program, monitoruje jeho průběh a vrátí ukončovací kód.

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

    Instalace se spustí v metodě Main.

    // 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;
    }
    
  • Před spuštěním instalace zřetězený nástroj zkontroluje, jestli je rozhraní .NET Framework 4.5 už nainstalované voláním IsNetFx4Present:

    ///  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));
    }
    
  • Cestu spustitelného souboru (Setup.exe v příkladu Launch ) v metodě můžete změnit tak, aby odkazovala na správné umístění, nebo upravte kód tak, aby určil umístění. Základní MmioChainer třída poskytuje blokující Run() metodu, kterou odvozená třída volá.

    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);
    }
    
  • Metoda Send zachytí a zpracuje zprávy. V této verzi rozhraní .NET Framework je jedinou podporovanou zprávou zpráva o zavření aplikace.

            // 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;
        }
    };
    
  • Údaje o průběhu jsou nepodepsané char mezi 0 (0 %) a 255 (100 %).

    private: // IProgressObserver
        virtual void OnProgress(unsigned char ubProgressSoFar)
        {…………
       }
    
  • HRESULT se předá Finished metodě.

    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);
    }
    

    Důležité

    Redistribuovatelný rozhraní .NET Framework 4.5 obvykle zapisuje mnoho zpráv o průběhu a jednu zprávu, která označuje dokončení (na straně řetězení). Čte se také asynchronně a hledá Abort záznamy. Pokud obdrží Abort záznam, zruší instalaci a zapíše dokončený záznam s E_ABORT jako jeho data po přerušení instalace a operace nastavení se vrátí zpět.

Typický server vytvoří náhodný název souboru MMIO, vytvoří soubor (jak je znázorněno v předchozím příkladu kódu, v Server::CreateSection) a spustí distribuovatelnou metodu CreateProcess a předá název kanálu s -pipe someFileSectionName možností. Server by měl implementovat OnProgress, Senda Finished metody s kódem specifický pro uživatelské rozhraní aplikace.

Viz také