Como: Obter o Progresso do Instalador do .NET Framework 4.5
O .NET Framework 4.5 é um runtime redistribuível. Se desenvolver aplicações para esta versão do .NET Framework, pode incluir (cadeia) .NET Framework configuração 4.5 como parte dos pré-requisitos da configuração da sua aplicação. Para apresentar uma experiência de configuração personalizada ou unificada, poderá querer iniciar automaticamente .NET Framework configuração 4.5 e controlar o progresso da mesma enquanto mostra o progresso da configuração da sua aplicação. Para ativar o controlo silencioso, .NET Framework configuração 4.5 (que pode ser observada) define um protocolo utilizando um segmento de E/S (MMIO) mapeado pela memória para comunicar com a sua configuração (o observador ou o encadeador). Este protocolo define uma forma de um encadeador obter informações de progresso, obter resultados detalhados, responder a mensagens e cancelar a configuração do .NET Framework 4.5.
Invocação. Para chamar .NET Framework configuração 4.5 e receber informações de progresso da secção MMIO, o programa de configuração tem de fazer o seguinte:
Chame o programa redistribuível .NET Framework 4.5:
dotNetFx45_Full_x86_x64.exe /q /norestart /pipe section-name
Em que nome da secção é qualquer nome que pretenda utilizar para identificar a sua aplicação. .NET Framework configuração lê e escreve na secção MMIO de forma assíncrona, pelo que poderá considerar conveniente utilizar eventos e mensagens durante esse período. No exemplo, o .NET Framework processo de configuração é criado por um construtor que aloca a secção MMIO (
TheSectionName
) e define um evento (TheEventName
):Server():ChainerSample::MmioChainer(L"TheSectionName", L"TheEventName")
Substitua esses nomes por nomes exclusivos do programa de configuração.
Leia a partir da secção MMIO. No .NET Framework 4.5, as operações de transferência e instalação são simultâneas: uma parte do .NET Framework pode estar a ser instalada enquanto outra parte está a ser transferida. Como resultado, o progresso é enviado de volta (ou seja, escrito) para a secção MMIO como dois números (
m_downloadSoFar
em_installSoFar
) que aumentam de 0 para 255. Quando o 255 é escrito e o .NET Framework sai, a instalação é concluída.
Códigos de saída. Os seguintes códigos de saída do comando para chamar o programa redistribuível .NET Framework 4.5 indicam se a configuração foi bem-sucedida ou falhou:
0 - A configuração foi concluída com êxito.
3010 – Configuração concluída com êxito; é necessário reiniciar o sistema.
1602 – a configuração foi cancelada.
Todos os outros códigos – a configuração encontrou erros; examine os ficheiros de registo criados em %temp% para obter detalhes.
A cancelar a configuração. Pode cancelar a configuração em qualquer altura ao utilizar o
Abort
método para definir osm_downloadAbort
sinalizadores em_ installAbort
na secção MMIO.
Exemplo de Encadeamento
O exemplo chainer inicia e monitoriza silenciosamente .NET Framework configuração 4.5 enquanto mostra o progresso. Este exemplo é semelhante ao exemplo chainer fornecido para o .NET Framework 4. No entanto, além disso, pode evitar reinícios do sistema ao processar a caixa de mensagem para fechar .NET Framework 4 aplicações. Para obter informações sobre esta caixa de mensagem, consulte Reduzir Reinícios do Sistema Durante .NET Framework Instalações 4.5. Pode utilizar este exemplo com o instalador .NET Framework 4; nesse cenário, a mensagem simplesmente não é enviada.
Aviso
Tem de executar o exemplo como administrador.
As secções seguintes descrevem os ficheiros significativos neste exemplo: MMIOChainer.h, ChainingdotNet4.cpp e IProgressObserver.h.
MMIOChainer.h
O ficheiro MMIOChainer.h contém a definição da estrutura de dados e a classe base a partir da qual a classe chainer deve ser derivada. O .NET Framework 4.5 expande a estrutura de dados MMIO para processar dados de que o instalador do .NET Framework 4.5 precisa. As alterações à estrutura MMIO são retrocompatíveis, pelo que um encadeador .NET Framework 4 pode funcionar com .NET Framework configuração 4.5 sem necessidade de recompilação. No entanto, este cenário não suporta a funcionalidade para reduzir os reinícios do sistema.
Um campo de versão fornece um meio de identificar revisões para a estrutura e o formato da mensagem. A configuração do .NET Framework determina a versão da interface do chainer ao chamar a
VirtualQuery
função para determinar o tamanho do mapeamento de ficheiros. Se o tamanho for grande o suficiente para acomodar o campo de versão, .NET Framework configuração utiliza o valor especificado. Se o mapeamento de ficheiros for demasiado pequeno para conter um campo de versão, que é o caso do .NET Framework 4, o processo de configuração pressupõe a versão 0 (4). Se o encadeador não suportar a versão da mensagem que .NET Framework configuração pretende enviar, .NET Framework configuração assume uma resposta ignorar.A estrutura de dados MMIO é definida da seguinte forma:
// 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. };
A
MmioDataStructure
estrutura de dados não deve ser utilizada diretamente. Em vez disso, utilize aMmioChainer
classe para implementar o encadeador. Derivar daMmioChainer
classe para encadear o .NET Framework 4.5 redistribuível.
IProgressObserver.h
O ficheiro IProgressObserver.h implementa um observador de progresso. Este observador é notificado sobre o progresso da transferência e instalação (especificado como um , 0-255 não assinado
char
, que indica 1%-100% concluído). O observador também é notificado quando o encadeamento envia uma mensagem e o observador deve enviar uma resposta.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
O ficheiro ChainingdotNet4.5.cpp implementa a
Server
classe , que deriva daMmioChainer
classe e substitui os métodos adequados para apresentar informações de progresso. O MmioChainer cria uma secção com o nome de secção especificado e inicializa o encadeador com o nome do evento especificado. O nome do evento é guardado na estrutura de dados mapeada. Deve tornar a secção e os nomes dos eventos exclusivos. AServer
classe no código seguinte inicia o programa de configuração especificado, monitoriza o respetivo progresso e devolve um código de saída.class Server : public ChainerSample::MmioChainer, public ChainerSample::IProgressObserver { public: ……………. Server():ChainerSample::MmioChainer(L"TheSectionName", L"TheEventName") //customize for your event names {}
A instalação é iniciada no método 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; }
Antes de iniciar a instalação, o encadeador verifica se o .NET Framework 4.5 já está instalado ao chamar
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)); }
Pode alterar o caminho do executável (Setup.exe no exemplo) no
Launch
método para apontar para a localização correta ou personalizar o código para determinar a localização. AMmioChainer
classe base fornece um método de bloqueioRun()
que a classe derivada chama.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); }
O
Send
método interceta e processa as mensagens. Nesta versão do .NET Framework, a única mensagem suportada é a mensagem fechar a aplicação.// 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; } };
Os dados de progresso são não assinados
char
entre 0 (0%) e 255 (100%).private: // IProgressObserver virtual void OnProgress(unsigned char ubProgressSoFar) {………… }
O HRESULT é transmitido ao
Finished
método .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); }
Importante
Normalmente, o .NET Framework 4.5 redistribuível escreve muitas mensagens de progresso e uma única mensagem que indica a conclusão (no lado do encadeamento). Também lê de forma assíncrona, à procura
Abort
de registos. Se receber umAbort
registo, cancela a instalação e escreve um registo concluído com E_ABORT como os dados após a instalação ter sido abortada e as operações de configuração terem sido revertidas.
Um servidor típico cria um nome de ficheiro MMIO aleatório, cria o ficheiro (conforme mostrado no exemplo de código anterior, em Server::CreateSection
) e inicia o redistribuível utilizando o CreateProcess
método e transmitindo o nome do pipe com a opção -pipe someFileSectionName
. O servidor deve implementar OnProgress
os métodos , Send
e Finished
com código específico da IU da aplicação.