探秘Visual Studio 2010中的災難恢復功能
為了提高用戶體驗,Microsoft在Windows Vista系統中首先引入了重啟管理器(Restart Manager)。它可以幫助應用程序維護其當前運行狀態,當軟件更新后需要重新啟動,或者是遇到非常嚴重的問題崩潰后,可以重新啟動軟件并且恢復到軟件的當前工作狀態。更重要的是,它還可以恢復自動保存的軟件數據狀態,盡量保證用戶數據的安全。有了重啟管理器,軟件就可以很快地從災難中恢復過來,實現快速“災后重建”。
圖1 Visual Studio 2010的重啟管理
重啟管理器主要應用在下面兩個方面:
◆軟件更新
很多時候,軟件或者操作系統升級后,需要重新啟動才可以生效。在這種情況下,我們就可以使用重啟管理器自動關閉真正運行的軟件,然后進行更新,更新完成后自動重新啟動軟件,并且恢復到軟件當前的工作狀態。這將使得軟件的更新更加流暢和智能。
◆軟件災難恢復
當軟件遇到嚴重錯誤,進程崩潰的時候,可以使用重啟管理器重新啟動軟件,恢復軟件自動保持的數據,讓軟件可以快速地從災難中恢復過來。
為了支持重啟管理器,微軟提供了一套Restart Manassas API函數來完成這些工作。這些函數定義在
◆RMStartSession
創建一個新的重啟任務。
◆RMGetList
這個函數可供安裝程序使用,它可以得到所有被影響的應用程序及其當前狀態。
◆RMRegisterResources
注冊重啟任務的資源,例如文件名,服務或者是RM_UNIQUE_PROCESS結構體。
◆RMRestart
重新啟動被RmShutdown關閉的應用程序或者服務,當然,這些應用程序或者服務都需要通過RegisterApplicationRestart事先進行注冊。
◆RMShutDown
關閉應用程序或者服務。
◆RMEndSession
結束重啟任務。
添加對重啟管理器的支持
雖然Windows Vista系統本身提供了對重啟管理器的支持,但是對于應用程序本身,也同樣需要一些額外的工作,以完成對重啟管理器的支持。
對于新創建的MFC應用程序,我們可以簡單地在“MFC應用程序向導”中設置是否需要支持重啟管理器。
圖2 MFC應用程序向導
在“MFC應用程序向導”的高級特性選項卡中有關于重啟管理器的選項。其中,如果僅僅選中“Support Restart Manager”選項,表示你的應用程序將僅僅支持重新啟動。換句話說,你的應用程序可以在升級或者崩潰之后重新啟動,但是無法自動打開未關閉的文檔,無法對數據進行恢復。
如果同時選中“Reopen previously open documents”選項,它表示你的應用程序可以在重啟之后重新打開之前打開的文檔,也就是自動恢復到當前的工作狀態。
如果選中了“Support application recover”選項,它表示你的應用程序在重新啟動后,不僅可以重新打開之前打開的文檔,還會嘗試恢復自動保存的文檔。它將彈出一個任務對話框(Unicode版本)或者消息框(非Unicode版本),詢問用戶是否需要恢復自動保持的文檔。如果用戶選擇“Yes”,那么自動保持的文檔將被打開作為當前文檔。如果用戶選擇“No”,那么用戶***保存的文檔將被打開作為當前文檔,同時自動保存的文檔將被刪除。
這里需要注意的是,只有文檔視圖類型的應用程序才支持“Reopen previously open documents”選項和“Support application recover”選項,對話框類型的應用程序只支持“Support Restart Manager”選項。
對于Visual Studio 2010中新創建的MFC應用程序,可以在應用程序向導中進行設置,添加對重啟管理器的支持。那么對于很多已有的MFC應用程序,如果同樣想獲得重啟管理器的支持,應該怎么辦呢?實際上,對于已有的MFC應用程序,要想獲得重啟管理器的支持很簡單。在新版本的MFC中,CWinApp類增加了一個新的成員變量,用于控制應用程序對重啟管理器的支持,我們只需要在應用程序的構造函數中,添加幾行代碼,按照我們的需求對其合理的初始化就可以了。
#p#
跟我們在上面所介紹的“MFC應用程序向導”中的選項相一致,如果你選擇的是“Support Restart Manager”,你可以在初始化函數中添加如下的代碼:
m_dwRestartManagerSupportFlags = |
如果你想選擇“Reopen previously open documents”,可以添加如下的代碼:
m_dwRestartManagerSupportFlags = |
m_dwRestartManagerSupportFlags = |
CRestartManagerDemoApp::CRestartManagerDemoApp() |
實例:創建支持重啟管理器的MFC應用程序
下面我們以一個實際的例子,來看看如何在我們的MFC應用程序中添加對重啟管理器的支持。
首先,啟動Visual Studio 2010 CTP,創建一個單文檔的應用程序RestartManagerDemo。按照我們前面的介紹,在“MFC應用程序向導”中選擇“Support Restart Manager”和“Reopen previously open documents”選項,以支持應用程序的重新啟動和文檔的重新打開。
為了驗證重啟管理器重新打開文檔的功能,我們在文檔中添加一些數據,這些數據將在程序重新啟動后自動被加載進來。
// 泡泡類,用于在視圖中顯示圓圈泡泡
class CBubble
{
public:
CBubble(CPoint cp, double fR)
{
m_nCenterPoint = cp;
m_fR = fR;
};
CBubble()
{};
// 圓心
CPoint m_nCenterPoint;
// 半徑
double m_fR;
};class CRestartManagerDemoDoc : public CDocument
{
protected: // create from serialization only
CRestartManagerDemoDoc();
DECLARE_DYNCREATE(CRestartManagerDemoDoc)// Attributes
public:
// 保存數據的數組
CArraym_Array;
// Operations
public:
CArray& GetBubbleArray()
{
return m_Array;
};
//…
};
然后,我們需要實現文檔的序列化函數,使得我們的文檔數據能夠保存和重新加載:
// CRestartManagerDemoDoc serializationvoid CRestartManagerDemoDoc::Serialize(CArchive& ar)
{
// 保存數據
if (ar.IsStoring())
{
// TODO: add storing code here
int nSize = m_Array.GetSize();
ar<for(int nIndex = 0; nIndex < nSize; ++nIndex )
{
CBubble tempBubble = m_Array.GetAt( nIndex );
ar<ar< }
}
else // 加載數據
{
// TODO: add loading code here
int nSize = 0;
ar>>nSize;
for(int nIndex = 0; nIndex < nSize; ++nIndex )
{
//CBubble tempBubble = m_Array.GetAt( nIndex );
CPoint tempPoint;
double tempR;
ar>>tempPoint;
ar>>tempR;
m_Array.Add( CBubble( tempPoint, tempR) );
}
}
}
完成文檔類的工作后,我們就有了保存數據的容器,現在我們需要對數據進行修改和顯示。在視圖類中,我們通過鼠標點擊,修改文檔中的數據,向其中添加CBubble對象。
void CRestartManagerDemoView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息處理程序代碼和/或調用默認值
CRestartManagerDemoDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
CArray& m_Array = pDoc->GetBubbleArray();
// 以當前鼠標點擊點為圓心,隨機半徑構造一個CBubble對象,并添加到文檔中
m_Array.Add( CBubble( point, rand()%30 ));// 更新視圖顯示
Invalidate();CView::OnLButtonDown(nFlags, point);
}然后,我們將這些數據在視圖中顯示出來:
void CRestartManagerDemoView::OnDraw(CDC* pDC)
{
CRestartManagerDemoDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;// TODO: add draw code for native data here
// 從文檔中得到數據
CArray& m_Array = pDoc->GetBubbleArray(); // 顯示數據
for(int nIndex = 0; nIndex < m_Array.GetSize(); ++nIndex )
{
CBubble tempBubble = m_Array.GetAt( nIndex );
pDC->Ellipse(tempBubble.m_nCenterPoint.x - tempBubble.m_fR,
tempBubble.m_nCenterPoint.y - tempBubble.m_fR,
tempBubble.m_nCenterPoint.x + tempBubble.m_fR,
tempBubble.m_nCenterPoint.y + tempBubble.m_fR);
}
}
這樣,我們就實現了一個簡單的支持重啟管理器的文檔視圖類型的MFC應用程序。這個程序可以通過鼠標在視圖中點擊向文檔中添加數據,然后這些數據可以保存和重新打開。void CRestartManagerDemoView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息處理程序代碼和/或調用默認值
CRestartManagerDemoDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
CArray& m_Array = pDoc->GetBubbleArray();
// 以當前鼠標點擊點為圓心,隨機半徑構造一個CBubble對象,并添加到文檔中
m_Array.Add( CBubble( point, rand()%30 ));// 更新視圖顯示
Invalidate();CView::OnLButtonDown(nFlags, point);
}然后,我們將這些數據在視圖中顯示出來:
void CRestartManagerDemoView::OnDraw(CDC* pDC)
{
CRestartManagerDemoDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;// TODO: add draw code for native data here
// 從文檔中得到數據
CArray& m_Array = pDoc->GetBubbleArray(); // 顯示數據
for(int nIndex = 0; nIndex < m_Array.GetSize(); ++nIndex )
{
CBubble tempBubble = m_Array.GetAt( nIndex );
pDC->Ellipse(tempBubble.m_nCenterPoint.x - tempBubble.m_fR,
tempBubble.m_nCenterPoint.y - tempBubble.m_fR,
tempBubble.m_nCenterPoint.x + tempBubble.m_fR,
tempBubble.m_nCenterPoint.y + tempBubble.m_fR);
}
}
這樣,我們就實現了一個簡單的支持重啟管理器的文檔視圖類型的MFC應用程序。這個程序可以通過鼠標在視圖中點擊向文檔中添加數據,然后這些數據可以保存和重新打開。
使用Restart Manassas API測試重啟管理器
接下來,我們可以編寫一個測試程序,使用Restart Manassas API模擬軟件的更新后重啟,以驗證其重啟管理器是否正常工作。
用Visual Studio 2010 CTP創建一個控制臺應用程序TestRM,然后將其實現如下:
//#include "stdafx.h"
#include
#includeint _tmain(int argc, _TCHAR* argv[])
{
DWORD dwSessionHandle = 0;
WCHAR wszSessionKey[CCH_RM_SESSION_KEY+1];// 設定需要重啟的資源
LPCWSTR pwzResourcesToRestart[] =
{L"C:\\Users\\TFSSETUP\\Documents\\Visual Studio 10\\Projects\\
RestartManagerDemo\\Debug\\RestartManagerDemo.exe" };// 創建一個重啟任務
if (RmStartSession(&dwSessionHandle, 0, wszSessionKey) == ERROR_SUCCESS)
{
// 注冊資源
if (RmRegisterResources(dwSessionHandle, 1,
pwzResourcesToRestart, 0, NULL, 0, NULL) == ERROR_SUCCESS)
{
// 關閉應用程序
if (RmShutdown(dwSessionHandle,
RmShutdownOnlyRegistered, NULL) == ERROR_SUCCESS)
{
// 重新啟動應用程序
if (RmRestart(dwSessionHandle, 0, NULL) == ERROR_SUCCESS)
{
return 0;
}
}
}
}
return 0;
}
我們首先運行RestartManagerDemo,在視圖中用鼠標點擊向文檔中添加數據,然后保持文檔為demo.bub。
圖3 支持重啟管理器的MFC應用程序
現在,我們就可以運行TestRM重啟這個應用程序了。運行TestRM后,我們會看到RestartManagerDemo會被關閉然后重新打開。同時,我們之前打開的文檔demo.bub也被重新加載,整個應用程序很快恢復到了我們之前的工作狀態。
【編輯推薦】