Procedure: Voortgang ophalen van het .NET Framework 4.5-installatieprogramma
.NET Framework 4.5 is een herdistribueerbare runtime. Als u apps ontwikkelt voor deze versie van .NET Framework, kunt u .NET Framework 4.5 instellen als een vereist onderdeel van de installatie van uw app. Als u een aangepaste of uniforme installatie-ervaring wilt presenteren, wilt u het instellen van .NET Framework 4.5 op de achtergrond starten en de voortgang ervan bijhouden terwijl de voortgang van de installatie van uw app wordt weergegeven. Als u stille tracering wilt inschakelen, definieert .NET Framework 4.5 setup (die kan worden bekeken) een protocol met behulp van een door het geheugen toegewezen I/O-segment (MMIO) om te communiceren met uw installatie (de watcher of chainer). Dit protocol definieert een manier voor een chainer om voortgangsinformatie te verkrijgen, gedetailleerde resultaten te verkrijgen, berichten te beantwoorden en de installatie van .NET Framework 4.5 te annuleren.
Aanroepen. Als u .NET Framework 4.5-installatie wilt aanroepen en voortgangsgegevens wilt ontvangen uit de mmIO-sectie, moet uw installatieprogramma het volgende doen:
Roep het herdistribueerbare programma van .NET Framework 4.5 aan:
dotNetFx45_Full_x86_x64.exe /q /norestart /pipe section-name
Waar de sectienaam een willekeurige naam is die u wilt gebruiken om uw app te identificeren. .NET Framework-installatie leest en schrijft asynchroon naar de MMIO-sectie, dus u kunt het handig vinden om gebeurtenissen en berichten gedurende die tijd te gebruiken. In het voorbeeld wordt het installatieproces van .NET Framework gemaakt door een constructor die de MMIO-sectie (
TheSectionName
) toewijst en een gebeurtenis definieert (TheEventName
):Server():ChainerSample::MmioChainer(L"TheSectionName", L"TheEventName")
Vervang deze namen door namen die uniek zijn voor uw installatieprogramma.
Lees uit de MMIO-sectie. In .NET Framework 4.5 zijn de download- en installatiebewerkingen gelijktijdig: een deel van het .NET Framework kan worden geïnstalleerd terwijl een ander onderdeel wordt gedownload. Als gevolg hiervan wordt de voortgang teruggestuurd (dat wil gezegd, geschreven) naar de MMIO-sectie als twee getallen (
m_downloadSoFar
enm_installSoFar
) die toenemen van 0 tot 255. Wanneer 255 is geschreven en .NET Framework wordt afgesloten, is de installatie voltooid.
Afsluitcodes. De volgende afsluitcodes van de opdracht om het herdistribueerbare programma van .NET Framework 4.5 aan te roepen, geven aan of de installatie is geslaagd of mislukt:
0 - De installatie is voltooid.
3010 – De installatie is voltooid; opnieuw opstarten van het systeem is vereist.
1602 – Setup is geannuleerd.
Alle andere codes - Setup heeft fouten aangetroffen; bekijk de logboekbestanden die zijn gemaakt in %temp% voor meer informatie.
Setup wordt geannuleerd. U kunt de installatie op elk gewenst moment annuleren met behulp van de
Abort
methode om dem_downloadAbort
enm_ installAbort
vlaggen in te stellen in de MMIO-sectie.
Chainer-voorbeeld
Het Chainer-voorbeeld start op de achtergrond en houdt de installatie van .NET Framework 4.5 bij terwijl de voortgang wordt weergegeven. Dit voorbeeld is vergelijkbaar met het Chainer-voorbeeld dat is opgegeven voor .NET Framework 4. Daarnaast kan het systeem opnieuw opstarten voorkomen door het berichtvak te verwerken voor het sluiten van .NET Framework 4-apps. Zie Reduce System Restarts During .NET Framework 4.5 Installations (Systeem opnieuw opstarten verminderen) voor meer informatie over dit berichtvak. U kunt dit voorbeeld gebruiken met het .NET Framework 4-installatieprogramma; In dat scenario wordt het bericht gewoon niet verzonden.
Waarschuwing
U moet het voorbeeld uitvoeren als beheerder.
In de volgende secties worden de belangrijke bestanden in dit voorbeeld beschreven: MMIOChainer.h, ChainingdotNet4.cpp en IProgressObserver.h.
MMIOChainer.h
Het MMIOChainer.h-bestand bevat de definitie van de gegevensstructuur en de basisklasse waaruit de chainerklasse moet worden afgeleid. Met .NET Framework 4.5 wordt de MMIO-gegevensstructuur uitgebreid om gegevens te verwerken die het .NET Framework 4.5-installatieprogramma nodig heeft. De wijzigingen in de MMIO-structuur zijn achterwaarts compatibel, zodat een .NET Framework 4-chainer kan werken met .NET Framework 4.5-installatie zonder dat er opnieuw hoeft te worden gecompileerde. Dit scenario biedt echter geen ondersteuning voor de functie voor het verminderen van het opnieuw opstarten van het systeem.
Een versieveld biedt een middel om revisies in de structuur en berichtindeling te identificeren. De installatie van .NET Framework bepaalt de versie van de chainer-interface door de
VirtualQuery
functie aan te roepen om de grootte van de bestandstoewijzing te bepalen. Als de grootte groot genoeg is voor het versieveld, gebruikt .NET Framework setup de opgegeven waarde. Als de bestandstoewijzing te klein is om een versieveld te bevatten, wat het geval is bij .NET Framework 4, wordt bij het installatieproces uitgegaan van versie 0 (4). Als de chainer geen ondersteuning biedt voor de versie van het bericht dat .NET Framework-installatie wil verzenden, wordt in .NET Framework een genegeerd antwoord aangenomen.De MMIO-gegevensstructuur wordt als volgt gedefinieerd:
// 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. };
De
MmioDataStructure
gegevensstructuur mag niet rechtstreeks worden gebruikt. Gebruik in plaats daarvan deMmioChainer
klasse om uw chainer te implementeren. Afgeleid van deMmioChainer
klasse om het herdistribueerbare .NET Framework 4.5 te koppelen.
IProgressObserver.h
Het bestand IProgressObserver.h implementeert een voortgangsobator. Deze waarnemer ontvangt een melding over de voortgang van de download en installatie (opgegeven als een niet-ondertekende
char
, 0-255, wat 1%-100% voltooid aangeeft). De waarnemer wordt ook op de hoogte gesteld wanneer de chainee een bericht verzendt en de waarnemer een antwoord moet verzenden.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
Het bestand ChainingdotNet4.5.cpp implementeert de
Server
klasse, die is afgeleid van deMmioChainer
klasse en overschrijft de juiste methoden om voortgangsinformatie weer te geven. MmioChainer maakt een sectie met de opgegeven sectienaam en initialiseert de chainer met de opgegeven gebeurtenisnaam. De gebeurtenisnaam wordt opgeslagen in de toegewezen gegevensstructuur. U moet de sectie- en gebeurtenisnamen uniek maken. DeServer
klasse in de volgende code start het opgegeven installatieprogramma, bewaakt de voortgang en retourneert een afsluitcode.class Server : public ChainerSample::MmioChainer, public ChainerSample::IProgressObserver { public: ……………. Server():ChainerSample::MmioChainer(L"TheSectionName", L"TheEventName") //customize for your event names {}
De installatie wordt gestart in de Main-methode.
// 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; }
Voordat de installatie wordt gestart, controleert de chainer of .NET Framework 4.5 al is geïnstalleerd door het aanroepen
IsNetFx4Present
van:/// 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)); }
U kunt het pad van het uitvoerbare bestand (Setup.exe in het voorbeeld) in de methode wijzigen om naar de
Launch
juiste locatie te verwijzen of de code aanpassen om de locatie te bepalen. DeMmioChainer
basisklasse biedt een blokkeringsmethodeRun()
die door de afgeleide klasse wordt aangeroepen.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); }
De
Send
methode onderschept en verwerkt de berichten. In deze versie van .NET Framework is het enige ondersteunde bericht het toepassingsbericht sluiten.// 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; } };
Voortgangsgegevens zijn niet ondertekend
char
tussen 0 (0%) en 255 (100%).private: // IProgressObserver virtual void OnProgress(unsigned char ubProgressSoFar) {………… }
Het HRESULT wordt doorgegeven aan de
Finished
methode.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); }
Belangrijk
Het herdistribueerbare .NET Framework 4.5 schrijft doorgaans veel voortgangsberichten en één bericht dat aangeeft dat de voltooiing is voltooid (aan de kant van de chainer). Het leest ook asynchroon, op zoek naar
Abort
records. Als er eenAbort
record wordt ontvangen, wordt de installatie geannuleerd en wordt een voltooide record met E_ABORT geschreven als de gegevens nadat de installatie is afgebroken en de installatiebewerkingen zijn teruggedraaid.
Een typische server maakt een willekeurige MMIO-bestandsnaam, maakt het bestand (zoals wordt weergegeven in het vorige codevoorbeeld, in Server::CreateSection
) en start het herdistribueerbare bestand met behulp van de CreateProcess
methode en geeft de pijpnaam door met de -pipe someFileSectionName
optie. De server moet , en Finished
methoden implementeren OnProgress
Send
met toepassingsspecifieke code voor de gebruikersinterface.