Anvisningar: Hämta förlopp från installationsprogrammet för .NET Framework 4.5

.NET Framework 4.5 är en omdistribuerbar körning. Om du utvecklar appar för den här versionen av .NET Framework kan du inkludera (kedja) .NET Framework 4.5-konfiguration som en förutsättning för din apps installation. Om du vill presentera en anpassad eller enhetlig konfigurationsupplevelse kanske du vill starta installationen av .NET Framework 4.5 tyst och spåra dess förlopp samtidigt som du visar appens installationsförlopp. För att aktivera tyst spårning definierar .NET Framework 4.5-konfigurationen (som kan övervakas) ett protokoll med hjälp av ett minnesmappat I/O-segment (MMIO) för att kommunicera med din installation (bevakaren eller kedjespelaren). Det här protokollet definierar ett sätt för en länkare att hämta förloppsinformation, få detaljerade resultat, svara på meddelanden och avbryta installationen av .NET Framework 4.5.

  • Anrop. Om du vill anropa .NET Framework 4.5-konfigurationen och ta emot förloppsinformation från MMIO-avsnittet måste installationsprogrammet göra följande:

    1. Anropa det omdistribuerbara .NET Framework 4.5-programmet:

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

      Där avsnittsnamnet är ett namn som du vill använda för att identifiera din app. .NET Framework-installationen läser och skriver till MMIO-avsnittet asynkront, så du kanske tycker att det är praktiskt att använda händelser och meddelanden under den tiden. I exemplet skapas .NET Framework-konfigurationsprocessen av en konstruktor som både allokerar MMIO-avsnittet (TheSectionName) och definierar en händelse (TheEventName):

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

      Ersätt dessa namn med namn som är unika för ditt installationsprogram.

    2. Läs från MMIO-avsnittet. I .NET Framework 4.5 är nedladdnings- och installationsåtgärderna samtidigt: En del av .NET Framework kan installeras medan en annan del laddas ned. Därför skickas förloppet tillbaka (dvs. skrivet) till MMIO-avsnittet som två tal (m_downloadSoFar och m_installSoFar) som ökar från 0 till 255. När 255 skrivs och .NET Framework avslutas är installationen klar.

  • Slutkoder. Följande slutkoder från kommandot för att anropa det omdistribuerbara .NET Framework 4.5-programmet anger om installationen har slutförts eller misslyckats:

    • 0 – Installationen har slutförts.

    • 3010 – Installationen har slutförts. en omstart av systemet krävs.

    • 1602 – Installationen har avbrutits.

    • Alla andra koder – Installationsprogrammet påträffade fel; granska loggfilerna som skapats i %temp% för mer information.

  • Avbryter installationen. Du kan avbryta installationen när som helst med hjälp Abort av metoden för att ange flaggorna m_downloadAbort och m_ installAbort i MMIO-avsnittet.

Kedjekedjeexempel

Chainer-exemplet startar tyst och spårar konfigurationen av .NET Framework 4.5 medan förloppet visas. Det här exemplet liknar det Chainer-exempel som tillhandahålls för .NET Framework 4. Dessutom kan det undvika omstarter av systemet genom att bearbeta meddelanderutan för att stänga .NET Framework 4-appar. Information om den här meddelanderutan finns i Reduce System Restarts During .NET Framework 4.5 Installations . Du kan använda det här exemplet med installationsprogrammet för .NET Framework 4. I det scenariot skickas meddelandet helt enkelt inte.

Varning

Du måste köra exemplet som administratör.

I följande avsnitt beskrivs de viktiga filerna i det här exemplet: MMIOChainer.h, ChainingdotNet4.cpp och IProgressObserver.h.

MMIOChainer.h

  • FILEN MMIOChainer.h innehåller datastrukturdefinitionen och basklassen som chainer-klassen ska härledas från. .NET Framework 4.5 utökar MMIO-datastrukturen för att hantera data som installationsprogrammet för .NET Framework 4.5 behöver. Ändringarna i MMIO-strukturen är bakåtkompatibla, så en .NET Framework 4-kedjekedja kan fungera med .NET Framework 4.5-konfigurationen utan att behöva omkompileras. Det här scenariot stöder dock inte funktionen för att minska omstarter av systemet.

    Ett versionsfält ger ett sätt att identifiera revisioner av strukturen och meddelandeformatet. Konfigurationen av .NET Framework avgör versionen av kedjegränssnittet genom att anropa VirtualQuery funktionen för att fastställa filmappningens storlek. Om storleken är tillräckligt stor för att rymma versionsfältet använder .NET Framework-konfigurationen det angivna värdet. Om filmappningen är för liten för att innehålla ett versionsfält, vilket är fallet med .NET Framework 4, förutsätter installationsprocessen version 0 (4). Om chainer inte stöder den version av meddelandet som .NET Framework-installationen vill skicka förutsätter .NET Framework-installationen ett ignorerande svar.

    MMIO-datastrukturen definieras på följande sätt:

    // 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.
        };
    
  • Datastrukturen MmioDataStructure bör inte användas direkt. Använd MmioChainer klassen i stället för att implementera din kedjekedja. Härled från MmioChainer klassen för att länka den omdistribuerbara .NET Framework 4.5.

IProgressObserver.h

  • Filen IProgressObserver.h implementerar en förloppsobservatör. Den här övervakaren får ett meddelande om nedladdnings- och installationsförloppet (anges som en osignerad , 0–255, vilket anger att 1%-100 % har slutförts char). Observatören meddelas också när kedjemottagaren skickar ett meddelande och observatören bör skicka ett svar.

        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

  • Filen ChainingdotNet4.5.cpp implementerar Server klassen, som härleds från MmioChainer klassen och åsidosätter lämpliga metoder för att visa förloppsinformation. MmioChainer skapar ett avsnitt med det angivna avsnittsnamnet och initierar kedjekedjan med det angivna händelsenamnet. Händelsenamnet sparas i den mappade datastrukturen. Du bör göra avsnittet och händelsenamnen unika. Klassen Server i följande kod startar det angivna installationsprogrammet, övervakar förloppet och returnerar en slutkod.

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

    Installationen startas i main-metoden.

    // 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;
    }
    
  • Innan installationen startas kontrollerar chainer om .NET Framework 4.5 redan har installerats genom att anropa 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));
    }
    
  • Du kan ändra sökvägen för den körbara filen (Setup.exe i exemplet) i metoden så att den Launch pekar på rätt plats eller anpassa koden för att fastställa platsen. Basklassen MmioChainer tillhandahåller en blockeringsmetod Run() som den härledda klassen anropar.

    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);
    }
    
  • Metoden Send fångar upp och bearbetar meddelandena. I den här versionen av .NET Framework är det enda meddelandet som stöds det nära programmeddelandet.

            // 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;
        }
    };
    
  • Förloppsdata är osignerade char mellan 0 (0 %) och 255 (100 %).

    private: // IProgressObserver
        virtual void OnProgress(unsigned char ubProgressSoFar)
        {…………
       }
    
  • HRESULT skickas till Finished metoden.

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

    Viktigt!

    .NET Framework 4.5 redistributable skriver vanligtvis många förloppsmeddelanden och ett enda meddelande som anger slutförande (på kedjesidan). Den läser också asynkront och letar Abort efter poster. Om den tar emot en Abort post avbryts installationen och en slutförd post skrivs med E_ABORT som data efter att installationen har avbrutits och installationsåtgärderna har återställts.

En typisk server skapar ett slumpmässigt MMIO-filnamn, skapar filen (som du ser i föregående kodexempel i Server::CreateSection) och startar omdistribuerbar med hjälp CreateProcess av metoden och skickar pipe-namnet med -pipe someFileSectionName alternativet . Servern ska implementera OnProgress, Sendoch Finished metoder med programgränssnittsspecifik kod.

Se även