Gebruikmaken van de Restart Manager met een tweede installatieprogramma
In de volgende procedure wordt het gebruik van Restart Manager met primaire en secundaire installatieprogramma's beschreven.
Wanneer u primaire en secundaire installatieprogramma's gebruikt, bepaalt het primaire installatieprogramma de gebruikersinterface.
Om Restart Manager te gebruiken met primaire en secundaire installatieprogramma's
Het primaire installatieprogramma roept de RmStartSession--functie aan om de Restart Manager-sessie te starten en een sessiehandle en -sleutel te verkrijgen.
Het primaire installatieprogramma start of neemt contact op met het secundaire installatieprogramma en geeft het de sessiesleutel die je in de vorige stap hebt verkregen.
Het secundaire installatieprogramma roept de RmJoinSession--functie aan met de sessiesleutel om deel te nemen aan de sessie Restart Manager. Een secundair installatieprogramma kan alleen deelnemen aan een sessie die door het primaire installatieprogramma wordt gestart wanneer beide installatieprogramma's in dezelfde gebruikerscontext worden uitgevoerd.
De primaire en secundaire installatieprogramma's roepen de functie RmRegisterResources aan om resources te registreren. De Manager voor opnieuw opstarten kan alleen geregistreerde resources gebruiken om te bepalen welke toepassingen en services moeten worden afgesloten en opnieuw moeten worden opgestart. Alle resources die kunnen worden beïnvloed door de installatie, moeten worden geregistreerd bij de sessie. Resources kunnen worden geïdentificeerd door bestandsnaam, korte servicenaam of een RM_UNIQUE_PROCESS structuur.
Het primaire installatieprogramma roept de RmGetList--functie aan om een matrix van RM_PROCESS_INFO structuren te verkrijgen waarin alle toepassingen en services worden vermeld die moeten worden afgesloten en opnieuw moeten worden opgestart.
Als de waarde van de parameter lpdwRebootReason die wordt geretourneerd door de functie RmGetList niet nul is, kan de Restart Manager geen geregistreerde resource vrij maken door een toepassing of service af te sluiten. In dit geval is een systeem afsluiten en opnieuw opstarten vereist om de installatie voort te zetten. Het primaire installatieprogramma moet de gebruiker om een actie vragen, programma's of services stoppen of een systeem afsluiten en opnieuw opstarten plannen.
Als de waarde van de parameter lpdwRebootReason die wordt geretourneerd door de functie RmGetList nul is, moet het installatieprogramma de RmShutdown--functie aanroepen. Hiermee worden de services en toepassingen afgesloten die gebruikmaken van geregistreerde resources. De primaire en secundaire installatieprogramma's moeten vervolgens systeemwijzigingen uitvoeren die nodig zijn om de installatie te voltooien. Ten slotte moet het primaire installatieprogramma de RmRestart-functie aanroepen, zodat de functie Restart Manager de toepassingen kan starten die het programma heeft afgesloten en die zijn geregistreerd voor opnieuw opstarten.
Het primaire en secundaire installatieprogramma roepen de RmEndSession- functie aan om de herstartbeheer sessie te sluiten.
In het volgende codefragment ziet u een voorbeeld van een installatieprogramma dat wordt gestart en een Restart Manager-sessie gebruikt. Voor het voorbeeld is Windows 7 of Windows Server 2008 R2 vereist. Op Windows Vista of Windows Server 2008 wordt de toepassing Calculator afgesloten, maar wordt niet opnieuw opgestart. In dit voorbeeld ziet u hoe een primair installatieprogramma Restart Manager kan gebruiken om een proces af te sluiten en opnieuw te starten. In het voorbeeld wordt ervan uitgegaan dat Calculator al wordt uitgevoerd voordat de sessie Restart Manager wordt gestart.
#include <windows.h>
#include <restartmanager.h>
#pragma comment(lib, "rstrtmgr.lib")
int _cdecl wmain()
{
DWORD dwErrCode = ERROR_SUCCESS;
DWORD dwSessionHandle = 0xFFFFFFFF; // Invalid handle value
//
// CCH_RM_SESSION_KEY: Character count of the
// Text-Encoded session key,defined in RestartManager.h
//
WCHAR sessKey[CCH_RM_SESSION_KEY+1];
// Number of calc files to be registered.
DWORD dwFiles = 2;
//
// NOTE:We register two calc executable files.
// The second one is for the redirection of 32 bit calc on
// 64 bit machines. Even if you are using a 32 bit machine,
// you don't need to comment out the second line.
//
LPCWSTR rgsFiles[] =
{L"C:\\Windows\\System32\\calc.exe",
L"C:\\Windows\\SysWow64\\calc.exe"};
UINT nRetry = 0;
UINT nAffectedApps = 0;
UINT nProcInfoNeeded = 0;
RM_REBOOT_REASON dwRebootReasons = RmRebootReasonNone;
RM_PROCESS_INFO *rgAffectedApps = NULL;
//
// Start a Restart Manager Session
//
dwErrCode = RmStartSession(&dwSessionHandle, 0, sessKey);
if (ERROR_SUCCESS != dwErrCode)
{
goto RM_CLEANUP;
}
//
// Register items with Restart Manager
//
// NOTE: we only register two calc executable files
// in this sample. You can register files, processes
// (in the form of process ID), and services (in the
// form of service short names) with Restart Manager.
//
dwErrCode = RmRegisterResources(dwSessionHandle,
dwFiles,
rgsFiles, // Files
0,
NULL, // Processes
0,
NULL); // Services
if (ERROR_SUCCESS != dwErrCode)
{
goto RM_CLEANUP;
}
//
// Obtain the list of affected applications/services.
//
// NOTE: Restart Manager returns the results into the
// buffer allocated by the caller. The first call to
// RmGetList() will return the size of the buffer
// (i.e. nProcInfoNeeded) the caller needs to allocate.
// The caller then needs to allocate the buffer
// (i.e. rgAffectedApps) and make another RmGetList()
// call to ask Restart Manager to write the results
// into the buffer. However, since Restart Manager
// refreshes the list every time RmGetList()is called,
// it is possible that the size returned by the first
// RmGetList()call is not sufficient to hold the results
// discovered by the second RmGetList() call. Therefore,
// it is recommended that the caller follows the
// following practice to handle this race condition:
//
// Use a loop to call RmGetList() in case the buffer
// allocated according to the size returned in previous
// call is not enough.
//
// In this example, we use a do-while loop trying to make
// 3 RmGetList() calls (including the first attempt to get
// buffer size) and if we still cannot succeed, we give up.
//
do
{
dwErrCode = RmGetList(dwSessionHandle,
&nProcInfoNeeded,
&nAffectedApps,
rgAffectedApps,
(LPDWORD) &dwRebootReasons);
if (ERROR_SUCCESS == dwErrCode)
{
//
// RmGetList() succeeded
//
break;
}
if (ERROR_MORE_DATA != dwErrCode)
{
//
// RmGetList() failed, with errors
// other than ERROR_MORE_DATA
//
goto RM_CLEANUP;
}
//
// RmGetList() is asking for more data
//
nAffectedApps = nProcInfoNeeded;
if (NULL != rgAffectedApps)
{
delete []rgAffectedApps;
rgAffectedApps = NULL;
}
rgAffectedApps = new RM_PROCESS_INFO[nAffectedApps];
} while ((ERROR_MORE_DATA == dwErrCode) && (nRetry ++ < 3));
if (ERROR_SUCCESS != dwErrCode)
{
goto RM_CLEANUP;
}
if (RmRebootReasonNone != dwRebootReasons)
{
//
// Restart Manager cannot mitigate a reboot.
// We goes to the clean up. The caller may want
// to add additional code to handle this scenario.
//
goto RM_CLEANUP;
}
//
// Now rgAffectedApps contains the affected applications
// and services. The number of applications and services
// returned is nAffectedApps. The result of RmGetList can
// be interpreted by the user to determine subsequent
// action (e.g. ask user's permission to shutdown).
//
// CALLER CODE GOES HERE...
//
// Shut down all running instances of affected
// applications and services.
//
dwErrCode = RmShutdown(dwSessionHandle, 0, NULL);
if (ERROR_SUCCESS != dwErrCode)
{
goto RM_CLEANUP;
}
//
// An installer can now replace or update
// the calc executable file.
//
// CALLER CODE GOES HERE...
//
// Restart applications and services, after the
// files have been replaced or updated.
//
dwErrCode = RmRestart(dwSessionHandle, 0, NULL);
if (ERROR_SUCCESS != dwErrCode)
{
goto RM_CLEANUP;
}
RM_CLEANUP:
if (NULL != rgAffectedApps)
{
delete [] rgAffectedApps;
rgAffectedApps = NULL;
}
if (0xFFFFFFFF != dwSessionHandle)
{
//
// Clean up the Restart Manager session.
//
RmEndSession(dwSessionHandle);
dwSessionHandle = 0xFFFFFFFF;
}
return 0;
}
In het volgende codefragment ziet u een voorbeeld van het toevoegen van een secundair installatieprogramma aan de bestaande sessie Restart Manager. Voor het voorbeeld is Windows Vista of Windows Server 2008 vereist. Het secundaire installatieprogramma verkrijgt de sessiesleutel van het primaire installatieprogramma en gebruikt dit om deel te nemen aan de sessie.
#include <windows.h>
#include <restartmanager.h>
#pragma comment(lib, "rstrtmgr.lib")
int _cdecl wmain()
{
DWORD dwErrCode = ERROR_SUCCESS;
DWORD dwSessionHandle = 0xFFFFFFFF; // Invalid handle value
//
// CCH_RM_SESSION_KEY: Character count of the
// Text-Encoded session key, defined in RestartManager.h
//
WCHAR sessKey[CCH_RM_SESSION_KEY+1];
// Number of files to be registered.
DWORD dwFiles = 1;
//
// We register oleaut32.dll with Restart Manager.
//
LPCWSTR rgsFiles[] =
{L"C:\\Windows\\System32\\oleaut32.dll"};
//
// Secondary installer needs to obtain the session key from
// the primary installer and uses it to join the session.
//
// CALLER CODE GOES HERE ...
//
// We assume the session key obtained is stored in sessKey
dwErrCode = RmJoinSession(&dwSessionHandle, sessKey);
if (ERROR_SUCCESS != dwErrCode)
{
goto RM_CLEANUP;
}
//
// Register items with Restart Manager
//
// NOTE: In Vista, the subordinate is only allowed to
// register resources and cannot perform any other
// getlist, shutdown, restart or filter operations.
//
dwErrCode = RmRegisterResources(dwSessionHandle,
dwFiles,
rgsFiles, // Files
0,
NULL, // Processes
0,
NULL); // Services
if (ERROR_SUCCESS != dwErrCode)
{
goto RM_CLEANUP;
}
RM_CLEANUP:
if (0xFFFFFFFF != dwSessionHandle)
{
//
// The subordinate leaves the conductor's session
// by calling RmEndSession(). The session itself
// won't be destroyed until the primary installer
// calls RmEndSession()
//
RmEndSession(dwSessionHandle);
dwSessionHandle = 0xFFFFFFFF;
}
return 0;
}