標籤:對話方塊 順序 class 互動 操作 explorer 最大限度 items 被佔用
Restart Manager(以下簡稱RM)可以減少或避免安裝或更新程式所需要的系統重啟次數。安裝(或更新)過程中需要重啟的主要原因是需要更新的某些檔案當前正被一些其它程式或服務所使用。RM允許除關鍵系統服務(Critical System Services)之外的所有程式(或服務)關閉和重啟。這將釋放正在使用的檔案從而使安裝得以完成。
RM DLL匯出了一組可供安裝包使用的C介面。安裝包可以向RM註冊安裝過程中需要被替換的檔案清單,隨後,安裝包可以通過RM來判斷其中哪些檔案正在使用;RM可以關閉並重啟那些佔用了這些檔案的程式;安裝包可以根據被佔用的檔案,進程ID,或Windows服務的簡短名稱來指導RM關閉和重啟應用程式(或服務)。 RM自Vista開始提供,Windows Installer V4會自動使用RM,自訂Installer也可以調用RM API來使用其功能。在不可避免需要重啟的情況下,Installer可以藉助RM來規劃何時重啟以最大限度減少對使用者工作流程的幹擾。 對佔用檔案的程式,RM以下列順序關閉它們,並在完成更新後,以相反的順序重啟它們:1. GUI應用程式2. Console應用程式3. Windows服務4. Windows Explorer RM只有得到調用方允許後才會關閉程式(或服務)。不支援跨會話進行關閉操作。 對於使用Windows Installer V4的安裝包,如果它是互動,則其使用者介面應包括MsiRMFilesInUse對話方塊。 1. 在自訂安裝包中使用RM API所有通過RM API執行的操作都必須與一個session關聯。在一個使用者會話中,最多可以同時開啟64個RM session。主安裝包(Primary Installer)負責啟動和停止RM session。 必要的情況下,若干個從安裝包(Secondary Installer)可以加入RM Session並與主安裝包同時運行(在同一進程或不同進程中)。加入RM Session需要使用其session key。 互動式安裝包的使用者介面應包括一個MsiRMFilesInUse對話方塊 —— 用於請求使用者關閉應用程式或服務。 安裝包不能在調用RM API前禁用檔案系統重新導向,這意味著在64位Windows上啟動並執行32位安裝包不能註冊“%windir\system32”目錄中的檔案。 1.1 在主安裝包中使用RM當在單個安裝包中使用RM時,該安裝包也就是主安裝包。1. 調用RmStartSession啟動一個RM session,得到session handle和key。2. 調用RmRegisterResources註冊資源。RM只能通過註冊的資源來判斷哪些程式和服務需要被重啟。資源可以是檔案名稱、服務的簡短名稱,或一個RM_UNIQUE_PROCESS結構。3. 調用RmGetList獲得一個RM_PROCESS_INFO數組,其中包含了所有需要被重啟的進程和服務。 如果RmGetList返回的lpdwRebootReason不為0,則表示RM無法通過重啟來釋放所註冊的資源。在這種情況下,則需要重啟OS來完成安裝。 如果RmGetList返回的lpdwRebootReason為0,則可以通過調用RmShutdown來關閉佔用資源的程式和服務,然後安裝包可以進行安裝操作,最後,調用RmRestart來重啟被關閉的程式。4. 可以通過RmAddFilter來防止某些程式(或服務)被RM關閉,這稱為添加一個過濾器。RmRemoveFilter可以移除一個過濾器,RmGetFilterList則可以獲得當前的過濾器列表。5. 調用RmEndSession關閉RM session。 樣本:DWORD dVal = 0;DWORD dwSessionHandle = (DWORD) -1;WCHAR sessKey[CCH_RM_SESSION_KEY+1];UINT nProcInfo = 100;UINT nProcInfoNeeded;UINT nAffectedApps = 0;RM_PROCESS_INFO rgAffectedApps[100]; //Size depends on # of entries found by RmGetListDWORD lpdwRebootReason = 0;DWORD nServices = 1;LPCWSTR rgsServices[] = { L"iisadmin" };DWORD nProcs = 0;DWORD nFiles = 1;LPCWSTR rgsFiles[] = { L"c:\\windows\\system32\\oleaut32.dll" }; // Starting SessiondVal = RmStartSession( &dwSessionHandle, 0, sessKey );if (dVal != ERROR_SUCCESS)goto RM_END; // Register itemsdVal = RmRegisterResources(dwSessionHandle,nFiles, rgsFiles, // FilesnProcs, NULL, // ProcessesnServices, rgsServices ); // Servicesif (dVal != ERROR_SUCCESS)goto RM_END; // Getting affected appsdVal = RmGetList(dwSessionHandle,&nProcInfoNeeded,&nAffectedApps, rgAffectedApps, &lpdwRebootReason );if (dVal != ERROR_SUCCESS)goto RM_END; //Results of RmGetList can be presented & interpreted //by the user for determining subsequent action. // Shut down appsdVal = RmShutdown( dwSessionHandle, 0, NULL );if (dVal != ERROR_SUCCESS)goto RM_END; //An installer can now replace the files. // Restart appsdVal = RmRestart( dwSessionHandle, 0, NULL );if (dVal != ERROR_SUCCESS)goto RM_END; RM_END: if (rgAffectedApps){delete [] rgAffectedApps;rgAffectedApps = NULL;} if (dwSessionHandle != -1){// Clean up sessiondVal = RmEndSession( dwSessionHandle );dwSessionHandle = -1;} 1.2 在從安裝包中使用RM1. 想辦法從主安裝包中擷取RM session key,調用RMJoinSession來加入session。主安裝包和從安裝包必須運行在相同的使用者上下文中。2. 使用RmRegisterResources註冊資源;使用RmGetList可以擷取佔用資源的程式列表;3. 可以調用RmShutdown(存疑!如果能夠調用的話,那會不會多次調用RmShutdown的可能?)。4. 主安裝包和從安裝包調用RmEndSession(存疑,不知道是指任何一方調用即可還是雙方都需要調用一次)。 樣本: DWORD dVal = 0; DWORD dwSessionHandle = (DWORD) -1; WCHAR sessKey[CCH_RM_SESSION_KEY+1]; //Primary installer session key. DWORD nServices = 1; LPCWSTR rgsServices[] = { L"iisadmin" }; DWORD nProcs = 0; DWORD nFiles = 1; LPCWSTR rgsFiles[] = { L"c:\\windows\\system32\\oleaut32.dll" }; // Secondary installer obtains the session key from the// primary installer & uses it to join the session. // Joining Session dVal = RmJoinSession( &dwSessionHandle, sessKey ); if (dVal != ERROR_SUCCESS) goto RMSUB_END; // Register items. The Secondary installer is only allowed to register resources // and cannot perform other Restart Manager operations. dVal = RmRegisterResources( dwSessionHandle, nFiles, rgsFiles, // Files nProcs, NULL, // Processes nServices, rgsServices ); // Services if (dVal != ERROR_SUCCESS) goto RMSUB_END; RMSUB_END: if (dwSessionHandle != -1) { // Clean up session dVal = RmEndSession( dwSessionHandle ); dwSessionHandle = -1; }
【Windows】Windows Restart Manager 重啟管理器