다음을 통해 공유


보조 설치 관리자에서 다시 시작 관리자 사용

다음 절차에서는 기본 및 보조 설치 관리자와 함께 Restart Manager를 사용하는 것을 설명합니다.

기본 및 보조 설치 관리자를 사용하는 경우 기본 설치 관리자는 사용자 인터페이스를 제어합니다.

기본 및 보조 설치 관리자에서 다시 시작 관리자를 사용하려면

  1. 기본 설치 관리자는 RmStartSession 함수를 호출하여 다시 시작 관리자 세션을 시작하고 세션 핸들 및 키를 가져옵니다.

  2. 기본 설치 관리자는 보조 설치 관리자를 시작하거나 연결하여 이전 단계에서 가져온 세션 키를 제공합니다.

  3. 보조 설치 관리자는 세션 키를 사용하여 RmJoinSession 함수를 호출하여 다시 시작 관리자 세션에 참가합니다. 보조 설치 관리자는 두 설치 관리자가 동일한 사용자 컨텍스트에서 실행되는 경우에만 주 설치 관리자가 시작하는 세션에 참가할 수 있습니다.

  4. 기본 및 보조 설치 관리자는 RmRegisterResources 함수를 호출하여 리소스를 등록합니다. Restart Manager는 등록된 리소스만 사용하여 종료하고 다시 시작해야 하는 애플리케이션 및 서비스를 결정할 수 있습니다. 설치의 영향을 받을 수 있는 모든 리소스를 세션에 등록해야 합니다. 리소스는 파일 이름, 서비스 짧은 이름 또는 RM_UNIQUE_PROCESS 구조로 식별할 수 있습니다.

  5. 기본 설치 관리자는 RmGetList 함수를 호출하여 종료하고 다시 시작해야 하는 모든 애플리케이션 및 서비스를 나열하는 RM_PROCESS_INFO 구조의 배열을 가져옵니다.

    RmGetList 함수에서 반환하는 lpdwRebootReason 매개 변수 값이 0이 아닌 경우 다시 시작 관리자는 애플리케이션 또는 서비스를 종료하여 등록된 리소스를 해제할 수 없습니다. 이 경우 설치를 계속하려면 시스템 종료 및 다시 시작이 필요합니다. 기본 설치 관리자는 사용자에게 작업을 요청하거나, 프로그램 또는 서비스를 중지하거나, 시스템 종료 및 다시 시작을 예약해야 합니다.

    RmGetList 함수에서 반환하는 lpdwRebootReason 매개 변수 값이 0이면 설치 관리자가 RmShutdown 함수를 호출해야 합니다. 그러면 등록된 리소스를 사용하는 서비스 및 애플리케이션이 종료됩니다. 그런 다음 기본 및 보조 설치 관리자는 설치를 완료하는 데 필요한 시스템 수정을 수행해야 합니다. 마지막으로, 기본 설치 관리자는 RmRestart 함수를 호출하여 다시 시작 관리자가 종료된 애플리케이션을 다시 시작하고 다시 시작을 위해 등록된 애플리케이션을 다시 시작할 수 있도록 해야 합니다.

  6. 기본 및 보조 설치 관리자는 RmEndSession 함수를 호출하여 다시 시작 관리자 세션을 닫습니다.

다음 코드 조각은 다시 시작 관리자 세션을 시작하고 사용하는 기본 설치 관리자의 예를 보여줍니다. 이 예제에는 Windows 7 또는 Windows Server 2008 R2가 필요합니다. Windows Vista 또는 Windows Server 2008에서는 계산기 애플리케이션이 종료되지만 다시 시작되지는 않습니다. 이 예제에서는 기본 설치 관리자가 Restart Manager를 사용하여 프로세스를 종료하고 다시 시작하는 방법을 보여줍니다. 이 예제에서는 다시 시작 관리자 세션을 시작하기 전에 계산기가 이미 실행 중이라고 가정합니다.

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

다음 코드 조각은 보조 설치 관리자를 기존 다시 시작 관리자 세션에 조인하는 예제를 보여 주는 코드 조각입니다. 이 예제에는 Windows Vista 또는 Windows Server 2008이 필요합니다. 보조 설치 관리자는 기본 설치 관리자에서 세션 키를 가져오고 이를 사용하여 세션에 참가합니다.

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