Porady: pobieranie danych o postępie z Instalatora .NET Framework 4.5
Program .NET Framework 4.5 jest środowiskiem uruchomieniowym redystrybucyjnym. Jeśli tworzysz aplikacje dla tej wersji programu .NET Framework, możesz uwzględnić konfigurację programu .NET Framework 4.5 (łańcuch) jako część wymagań wstępnych konfiguracji aplikacji. Aby przedstawić dostosowane lub ujednolicone środowisko konfiguracji, możesz w trybie dyskretnym uruchomić konfigurację programu .NET Framework 4.5 i śledzić jego postęp podczas wyświetlania postępu instalacji aplikacji. Aby włączyć śledzenie dyskretne, konfiguracja programu .NET Framework 4.5 (którą można obserwować) definiuje protokół przy użyciu segmentu we/wy mapowanego w pamięci (MMIO) do komunikowania się z konfiguracją (obserwator lub łańcuch). Ten protokół definiuje sposób uzyskiwania informacji o postępie, uzyskiwania szczegółowych wyników, reagowania na komunikaty i anulowania konfiguracji programu .NET Framework 4.5.
Wywołanie. Aby wywołać instalatora programu .NET Framework 4.5 i uzyskać informacje o postępie z sekcji MMIO, program instalacyjny musi wykonać następujące czynności:
Wywołaj program redystrybucyjny programu .NET Framework 4.5:
dotNetFx45_Full_x86_x64.exe /q /norestart /pipe section-name
Gdzie nazwa sekcji to dowolna nazwa, której chcesz użyć do identyfikacji aplikacji. Konfiguracja programu .NET Framework odczytuje i zapisuje w sekcji MMIO asynchronicznie, dzięki czemu w tym czasie może być wygodne korzystanie ze zdarzeń i komunikatów. W tym przykładzie proces instalacji programu .NET Framework jest tworzony przez konstruktor, który przydziela sekcję MMIO (
TheSectionName
) i definiuje zdarzenie (TheEventName
):Server():ChainerSample::MmioChainer(L"TheSectionName", L"TheEventName")
Zastąp te nazwy nazwami unikatowymi dla programu instalacyjnego.
Przeczytaj sekcję MMIO. W programie .NET Framework 4.5 operacje pobierania i instalacji są równoczesne: jedna część programu .NET Framework może być instalowana podczas pobierania innej części. W rezultacie postęp jest wysyłany z powrotem (czyli zapisywany) do sekcji MMIO jako dwie liczby (
m_downloadSoFar
im_installSoFar
), które zwiększają się z 0 do 255. Po zapisaniu wartości 255 i zakończeniu działania programu .NET Framework instalacja zostanie ukończona.
Kody zakończenia. Następujące kody zakończenia polecenia w celu wywołania programu redystrybucyjnego programu .NET Framework 4.5 wskazują, czy instalacja zakończyła się powodzeniem, czy niepowodzeniem:
0 — Instalacja została ukończona pomyślnie.
3010 — Instalacja została ukończona pomyślnie; wymagane jest ponowne uruchomienie systemu.
1602 — Instalacja została anulowana.
Wszystkie inne kody — Instalator napotkał błędy; sprawdź pliki dziennika utworzone w %temp%, aby uzyskać szczegółowe informacje.
Anulowanie konfiguracji. Konfigurację można anulować w dowolnym momencie przy użyciu
Abort
metody , aby ustawićm_downloadAbort
flagi im_ installAbort
w sekcji MMIO.
Przykład chainer
Przykład Chainer w trybie dyskretnym uruchamia i śledzi konfigurację programu .NET Framework 4.5 podczas wyświetlania postępu. Ten przykład jest podobny do przykładu Chainer udostępnionego dla programu .NET Framework 4. Ponadto można uniknąć ponownych uruchomień systemu przez przetworzenie pola komunikatu w celu zamknięcia aplikacji programu .NET Framework 4. Aby uzyskać informacje o tym oknie komunikatu, zobacz Zmniejszanie ponownych uruchomień systemu podczas instalacji programu .NET Framework 4.5. Możesz użyć tego przykładu z instalatorem programu .NET Framework 4; w tym scenariuszu wiadomość nie jest po prostu wysyłana.
Ostrzeżenie
Musisz uruchomić przykład jako administrator.
W poniższych sekcjach opisano istotne pliki w tym przykładzie: MMIOChainer.h, ChainingdotNet4.cpp i IProgressObserver.h.
MMIOChainer.h
Plik MMIOChainer.h zawiera definicję struktury danych i klasę bazową, z której powinna pochodzić klasa łańcucha. Program .NET Framework 4.5 rozszerza strukturę danych MMIO w celu obsługi danych potrzebnych przez instalator programu .NET Framework 4.5. Zmiany struktury MMIO są zgodne z poprzednimi wersjami, więc łańcuch programu .NET Framework 4 może współpracować z konfiguracją programu .NET Framework 4.5 bez konieczności ponownego komplikowania. Jednak ten scenariusz nie obsługuje funkcji zmniejszania liczby ponownych uruchomień systemu.
Pole wersji zawiera metodę identyfikowania poprawek struktury i formatu komunikatów. Instalator programu .NET Framework określa wersję interfejsu łańcucha, wywołując
VirtualQuery
funkcję w celu określenia rozmiaru mapowania plików. Jeśli rozmiar jest wystarczająco duży, aby pomieścić pole wersji, instalator programu .NET Framework używa określonej wartości. Jeśli mapowanie plików jest zbyt małe, aby zawierało pole wersji, w przypadku programu .NET Framework 4 proces instalacji zakłada wersję 0 (4). Jeśli moduł łańcuchowy nie obsługuje wersji komunikatu, którą instalator programu .NET Framework chce wysłać, instalator programu .NET Framework zakłada ignorowanie odpowiedzi.Struktura danych MMIO jest definiowana w następujący sposób:
// 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. };
Struktura
MmioDataStructure
danych nie powinna być używana bezpośrednio; zamiast tego użyjMmioChainer
klasy , aby zaimplementować łańcuch.MmioChainer
Z klasy należy utworzyć łańcuch redystrybucyjny programu .NET Framework 4.5.
IProgressObserver.h
Plik IProgressObserver.h implementuje obserwatora postępu. Ten obserwator otrzymuje powiadomienie o postępie pobierania i instalacji (określony jako niepodpisany
char
, 0–255 wskazujący ukończenie 1%-100%. Obserwator jest również powiadamiany, gdy łańcuch wysyła wiadomość, a obserwator powinien wysłać odpowiedź.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
Plik ChainingdotNet4.5.cpp implementuje klasę
Server
, która pochodzi zMmioChainer
klasy i zastępuje odpowiednie metody wyświetlania informacji o postępie. MmioChainer tworzy sekcję o określonej nazwie sekcji i inicjuje łańcuch z określoną nazwą zdarzenia. Nazwa zdarzenia jest zapisywana w mapowanej strukturze danych. Należy ustawić unikatowe nazwy sekcji i zdarzeń. KlasaServer
w poniższym kodzie uruchamia określony program instalacyjny, monitoruje postęp i zwraca kod zakończenia.class Server : public ChainerSample::MmioChainer, public ChainerSample::IProgressObserver { public: ……………. Server():ChainerSample::MmioChainer(L"TheSectionName", L"TheEventName") //customize for your event names {}
Instalacja została uruchomiona w metodzie 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; }
Przed uruchomieniem instalacji moduł łańcuchowy sprawdza, czy program .NET Framework 4.5 jest już zainstalowany, wywołując polecenie
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)); }
Możesz zmienić ścieżkę pliku wykonywalnego (Setup.exe w przykładzie
Launch
) w metodzie, aby wskazać poprawną lokalizację lub dostosować kod w celu określenia lokalizacji. KlasaMmioChainer
bazowa udostępnia metodę blokującąRun()
wywoływaną przez klasę pochodną.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
przechwytuje i przetwarza komunikaty. W tej wersji programu .NET Framework jedynym obsługiwanym komunikatem jest komunikat zamykanej aplikacji.// 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; } };
Dane postępu są niepodpisane
char
z zakresu od 0 (0%) do 255 (100%).private: // IProgressObserver virtual void OnProgress(unsigned char ubProgressSoFar) {………… }
HrESULT jest przekazywany do
Finished
metody .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); }
Ważne
Redystrybucyjny program .NET Framework 4.5 zwykle zapisuje wiele komunikatów postępu i pojedynczy komunikat wskazujący ukończenie (po stronie łańcucha). Odczytuje również asynchronicznie, wyszukując
Abort
rekordy. Jeśli otrzyma rekord, anuluje instalacjęAbort
i zapisuje gotowy rekord z E_ABORT jako jego dane po przerwaniu instalacji i wycofaniu operacji instalacji.
Typowy serwer tworzy losową nazwę pliku MMIO, tworzy plik (jak pokazano w poprzednim przykładzie kodu w pliku ) Server::CreateSection
i uruchamia pakiet redystrybucyjny przy użyciu CreateProcess
metody i przekazuje nazwę potoku z opcją -pipe someFileSectionName
. Serwer powinien implementować OnProgress
metody , Send
i Finished
z kodem specyficznym dla interfejsu użytkownika aplikacji.