Sdílet prostřednictvím


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) nastavení rozhraní .NET Framework 4.5. Pokud chcete prezentovat přizpůsobené nebo sjednocené prostředí nastavení, můžete chtít bezobslužně spustit nastavení rozhraní .NET Framework 4.5 a sledovat jeho průběh při zobrazení průběhu instalace aplikace. Pokud chcete povolit tiché sledování, definuje nastavení rozhraní .NET Framework 4.5 (které lze sledovat) protokol pomocí segmentu V/V (MMIO) mapovaného paměti ke komunikaci s vaším nastavením (sledovací proces nebo řetězení). Tento protokol definuje způsob, jak zřetězovač 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í. Chcete-li volat instalaci rozhraní .NET Framework 4.5 a přijímat informace o průběhu z oddílu MMIO, musí instalační program provést následující:

    1. Volejte redistribuovatelný program rozhraní .NET Framework 4.5:

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

      Název oddílu je libovolný název , který chcete použít k identifikaci aplikace. Instalace rozhraní .NET Framework čte a zapisuje do oddílu MMIO asynchronně, takže může být vhodné používat události a zprávy během této doby. 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 z oddílu 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ší z 0 na 255. Při zápisu 255 a ukončení rozhraní .NET Framework je instalace dokončena.

  • Ukončovací kódy. Následující ukončovací kódy z příkazu pro volání distribuovatelného programu rozhraní .NET Framework 4.5 označují, zda instalace proběhla úspěšně nebo selhala:

    • 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 – Instalační program zjistil chyby; Podrobnosti najdete v souborech protokolu vytvořených v %temp% .

  • Probíhá ruš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 Chainer bezobslužně spustí a sleduje nastavení rozhraní .NET Framework 4.5 při zobrazení průběhu. Tato ukázka je podobná ukázce Chaineru, která je k dispozici pro rozhraní .NET Framework 4. Kromě toho se ale může vyhnout restartování systému tím, že zpracuje okno se zprávou pro zavření aplikací rozhraní .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í.

Upozorňující

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 řetězovač rozhraní .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í počtu restartování systému.

    Pole verze poskytuje způsob identifikace revizí struktury a formátu zprávy. Nastavení rozhraní .NET Framework určuje verzi rozhraní zřetězeného voláním VirtualQuery funkce k určení velikosti mapování souborů. Pokud je velikost dostatečně velká, aby vyhovovala poli verze, použije instalační program rozhraní .NET Framework zadanou hodnotu. Pokud je mapování souborů příliš malé, aby obsahovalo pole verze, což je případ rozhraní .NET Framework 4, instalační proces předpokládá verzi 0 (4). Pokud řetězení nepodporuje verzi zprávy, kterou instalační program rozhraní .NET Framework chce odeslat, instalační program 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. K implementaci zřetězovacího nástroje použijte MmioChainer třídu. Odvozujte z MmioChainer třídy pro zřetězený distribuovatelný .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ž zřetězený 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 řetězec 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, sleduje 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 řetěze zkontroluje, jestli je rozhraní .NET Framework 4.5 již nainstalováno 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) v Launch metodě můžete změnit tak, aby odkazovala na správné umístění, nebo můžete přizpůsobit kód pro určení 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á metodě Finished .

    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ý .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í). Také čte 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 instalace 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í redistributable pomocí CreateProcess metody 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é