📄 doccore.cpp
字号:
if (afxData.bMarked4)
AfxGetFileTitle(lpszPathName, szTitle, _countof(szTitle));
else
lstrcpyn(szTitle, lpszPathName, _countof(szTitle));
AfxFormatString1(prompt, nIDP, szTitle);
}
AfxMessageBox(prompt, MB_ICONEXCLAMATION, nHelpContext);
}
/////////////////////////////////////////////////////////////////////////////
// File operations (default uses CDocument::Serialize)
CString CMirrorFile::GetTempName(LPCTSTR lpszOriginalFile, BOOL bCreate)
{
CString str;
// get the directory for the file
TCHAR szPath[_MAX_PATH];
LPTSTR lpszName;
GetFullPathName(lpszOriginalFile, _MAX_PATH, szPath, &lpszName);
*lpszName = NULL;
// let's create a temporary file name, and create
// a file too!
GetTempFileName(szPath, _T("MFC"), 0,
str.GetBuffer(_MAX_PATH+1));
str.ReleaseBuffer();
// delete the file if the user just wants a name
if (!bCreate)
CFile::Remove(str);
return str;
}
BOOL CMirrorFile::Open(LPCTSTR lpszFileName, UINT nOpenFlags,
CFileException* pError)
{
ASSERT(lpszFileName != NULL);
m_strMirrorName.Empty();
CFileStatus status;
if (nOpenFlags & CFile::modeCreate) //opened for writing
{
if (CFile::GetStatus(lpszFileName, status))
{
CString strRoot;
AfxGetRoot(lpszFileName, strRoot);
DWORD dwSecPerClus, dwBytesPerSec, dwFreeClus, dwTotalClus;
DWORD nBytes = 0;
if (GetDiskFreeSpace(strRoot, &dwSecPerClus, &dwBytesPerSec, &dwFreeClus,
&dwTotalClus))
{
nBytes = dwFreeClus * dwSecPerClus * dwBytesPerSec;
}
if (nBytes > 2 * DWORD(status.m_size)) // at least 2x free space avail
{
m_strMirrorName = GetTempName(lpszFileName, TRUE);
}
}
}
if (!m_strMirrorName.IsEmpty() &&
CFile::Open(m_strMirrorName, nOpenFlags, pError))
{
m_strFileName = lpszFileName;
FILETIME ftCreate, ftAccess, ftModify;
if (::GetFileTime((HANDLE)m_hFile, &ftCreate, &ftAccess, &ftModify))
{
AfxTimeToFileTime(status.m_ctime, &ftCreate);
SetFileTime((HANDLE)m_hFile, &ftCreate, &ftAccess, &ftModify);
}
DWORD dwLength = 0;
PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
if (GetFileSecurity(lpszFileName, DACL_SECURITY_INFORMATION,
NULL, dwLength, &dwLength))
{
pSecurityDescriptor = (PSECURITY_DESCRIPTOR) new BYTE[dwLength];
if (::GetFileSecurity(lpszFileName, DACL_SECURITY_INFORMATION,
pSecurityDescriptor, dwLength, &dwLength))
{
SetFileSecurity(m_strMirrorName, DACL_SECURITY_INFORMATION, pSecurityDescriptor);
}
delete[] (BYTE*)pSecurityDescriptor;
}
return TRUE;
}
m_strMirrorName.Empty();
return CFile::Open(lpszFileName, nOpenFlags, pError);
}
void CMirrorFile::Abort()
{
CFile::Abort();
if (!m_strMirrorName.IsEmpty())
CFile::Remove(m_strMirrorName);
}
//WINBUG: these will be in a public header, some day.
typedef BOOL (WINAPI* ReplaceAPIPtr)(LPCWSTR, LPCWSTR, LPCWSTR,
DWORD, LPVOID, LPVOID);
#ifndef REPLACEFILE_WRITE_THROUGH
#define REPLACEFILE_WRITE_THROUGH 0x00000001
#endif
#ifndef REPLACEFILE_IGNORE_MERGE_ERRORS
#define REPLACEFILE_IGNORE_MERGE_ERRORS 0x00000002
#endif
#ifndef ERROR_UNABLE_TO_MOVE_REPLACEMENT
#define ERROR_UNABLE_TO_MOVE_REPLACEMENT 1176L
#endif
#ifndef ERROR_UNABLE_TO_MOVE_REPLACEMENT_2
#define ERROR_UNABLE_TO_MOVE_REPLACEMENT_2 1177L
#endif
void CMirrorFile::Close()
{
CString m_strName = m_strFileName; //file close empties string
CFile::Close();
if (!m_strMirrorName.IsEmpty())
{
BOOL bWorked = FALSE;
DWORD dwResult = 0;
ReplaceAPIPtr pfn = NULL;
CString strBackupName;
if (!afxData.bWin95)
{
HMODULE hModule = GetModuleHandleA("KERNEL32");
ASSERT(hModule != NULL);
pfn = (ReplaceAPIPtr) GetProcAddress(hModule, "ReplaceFile");
if (pfn != NULL)
{
USES_CONVERSION;
strBackupName = GetTempName(m_strMirrorName, FALSE);
// this NT API handles copying all attributes for us
bWorked = (pfn)(T2W((LPTSTR)(LPCTSTR)m_strName),
T2W((LPTSTR)(LPCTSTR)m_strMirrorName),
T2W((LPTSTR)(LPCTSTR)strBackupName),
REPLACEFILE_WRITE_THROUGH | REPLACEFILE_IGNORE_MERGE_ERRORS,
NULL, NULL);
if (!bWorked)
dwResult = GetLastError();
}
}
if (!bWorked)
{
if (dwResult == ERROR_UNABLE_TO_MOVE_REPLACEMENT || dwResult == 0)
CFile::Remove(m_strName);
if (dwResult == ERROR_UNABLE_TO_MOVE_REPLACEMENT_2)
CFile::Remove(strBackupName);
CFile::Rename(m_strMirrorName, m_strName);
}
else if (pfn != NULL)
{
CFile::Remove(strBackupName);
}
}
}
CFile* CDocument::GetFile(LPCTSTR lpszFileName, UINT nOpenFlags,
CFileException* pError)
{
CMirrorFile* pFile = new CMirrorFile;
ASSERT(pFile != NULL);
if (!pFile->Open(lpszFileName, nOpenFlags, pError))
{
delete pFile;
pFile = NULL;
}
return pFile;
}
void CDocument::ReleaseFile(CFile* pFile, BOOL bAbort)
{
ASSERT_KINDOF(CFile, pFile);
if (bAbort)
pFile->Abort(); // will not throw an exception
else
pFile->Close();
delete pFile;
}
BOOL CDocument::OnNewDocument()
{
if (IsModified())
TRACE0("Warning: OnNewDocument replaces an unsaved document.\n");
DeleteContents();
m_strPathName.Empty(); // no path name yet
SetModifiedFlag(FALSE); // make clean
return TRUE;
}
BOOL CDocument::OnOpenDocument(LPCTSTR lpszPathName)
{
if (IsModified())
TRACE0("Warning: OnOpenDocument replaces an unsaved document.\n");
CFileException fe;
CFile* pFile = GetFile(lpszPathName,
CFile::modeRead|CFile::shareDenyWrite, &fe);
if (pFile == NULL)
{
ReportSaveLoadException(lpszPathName, &fe,
FALSE, AFX_IDP_FAILED_TO_OPEN_DOC);
return FALSE;
}
DeleteContents();
SetModifiedFlag(); // dirty during de-serialize
CArchive loadArchive(pFile, CArchive::load | CArchive::bNoFlushOnDelete);
loadArchive.m_pDocument = this;
loadArchive.m_bForceFlat = FALSE;
TRY
{
CWaitCursor wait;
if (pFile->GetLength() != 0)
Serialize(loadArchive); // load me
loadArchive.Close();
ReleaseFile(pFile, FALSE);
}
CATCH_ALL(e)
{
ReleaseFile(pFile, TRUE);
DeleteContents(); // remove failed contents
TRY
{
ReportSaveLoadException(lpszPathName, e,
FALSE, AFX_IDP_FAILED_TO_OPEN_DOC);
}
END_TRY
DELETE_EXCEPTION(e);
return FALSE;
}
END_CATCH_ALL
SetModifiedFlag(FALSE); // start off with unmodified
return TRUE;
}
BOOL CDocument::OnSaveDocument(LPCTSTR lpszPathName)
{
CFileException fe;
CFile* pFile = NULL;
pFile = GetFile(lpszPathName, CFile::modeCreate |
CFile::modeReadWrite | CFile::shareExclusive, &fe);
if (pFile == NULL)
{
ReportSaveLoadException(lpszPathName, &fe,
TRUE, AFX_IDP_INVALID_FILENAME);
return FALSE;
}
CArchive saveArchive(pFile, CArchive::store | CArchive::bNoFlushOnDelete);
saveArchive.m_pDocument = this;
saveArchive.m_bForceFlat = FALSE;
TRY
{
CWaitCursor wait;
Serialize(saveArchive); // save me
saveArchive.Close();
ReleaseFile(pFile, FALSE);
}
CATCH_ALL(e)
{
ReleaseFile(pFile, TRUE);
TRY
{
ReportSaveLoadException(lpszPathName, e,
TRUE, AFX_IDP_FAILED_TO_SAVE_DOC);
}
END_TRY
DELETE_EXCEPTION(e);
return FALSE;
}
END_CATCH_ALL
SetModifiedFlag(FALSE); // back to unmodified
return TRUE; // success
}
void CDocument::OnCloseDocument()
// must close all views now (no prompting) - usually destroys this
{
// destroy all frames viewing this document
// the last destroy may destroy us
BOOL bAutoDelete = m_bAutoDelete;
m_bAutoDelete = FALSE; // don't destroy document while closing views
while (!m_viewList.IsEmpty())
{
// get frame attached to the view
CView* pView = (CView*)m_viewList.GetHead();
ASSERT_VALID(pView);
CFrameWnd* pFrame = pView->GetParentFrame();
ASSERT_VALID(pFrame);
// and close it
PreCloseFrame(pFrame);
pFrame->DestroyWindow();
// will destroy the view as well
}
m_bAutoDelete = bAutoDelete;
// clean up contents of document before destroying the document itself
DeleteContents();
// delete the document if necessary
if (m_bAutoDelete)
delete this;
}
void CDocument::OnIdle()
{
// default does nothing
}
/////////////////////////////////////////////////////////////////////////////
// View operations
void CDocument::AddView(CView* pView)
{
ASSERT_VALID(pView);
ASSERT(pView->m_pDocument == NULL); // must not be already attached
ASSERT(m_viewList.Find(pView, NULL) == NULL); // must not be in list
m_viewList.AddTail(pView);
ASSERT(pView->m_pDocument == NULL); // must be un-attached
pView->m_pDocument = this;
OnChangedViewList(); // must be the last thing done to the document
}
void CDocument::RemoveView(CView* pView)
{
ASSERT_VALID(pView);
ASSERT(pView->m_pDocument == this); // must be attached to us
m_viewList.RemoveAt(m_viewList.Find(pView));
pView->m_pDocument = NULL;
OnChangedViewList(); // must be the last thing done to the document
}
POSITION CDocument::GetFirstViewPosition() const
{
return m_viewList.GetHeadPosition();
}
CView* CDocument::GetNextView(POSITION& rPosition) const
{
ASSERT(rPosition != BEFORE_START_POSITION);
// use CDocument::GetFirstViewPosition instead !
if (rPosition == NULL)
return NULL; // nothing left
CView* pView = (CView*)m_viewList.GetNext(rPosition);
ASSERT_KINDOF(CView, pView);
return pView;
}
void CDocument::UpdateAllViews(CView* pSender, LPARAM lHint, CObject* pHint)
// walk through all views
{
ASSERT(pSender == NULL || !m_viewList.IsEmpty());
// must have views if sent by one of them
POSITION pos = GetFirstViewPosition();
while (pos != NULL)
{
CView* pView = GetNextView(pos);
ASSERT_VALID(pView);
if (pView != pSender)
pView->OnUpdate(pSender, lHint, pHint);
}
}
void CDocument::SendInitialUpdate()
// walk through all views and call OnInitialUpdate
{
POSITION pos = GetFirstViewPosition();
while (pos != NULL)
{
CView* pView = GetNextView(pos);
ASSERT_VALID(pView);
pView->OnInitialUpdate();
}
}
/////////////////////////////////////////////////////////////////////////////
// command routing
BOOL CDocument::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
if (CCmdTarget::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// otherwise check template
if (m_pDocTemplate != NULL &&
m_pDocTemplate->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// CDocument diagnostics
#ifdef _DEBUG
void CDocument::Dump(CDumpContext& dc) const
{
CObject::Dump(dc);
dc << "m_strTitle = " << m_strTitle;
dc << "\nm_strPathName = " << m_strPathName;
dc << "\nm_bModified = " << m_bModified;
dc << "\nm_pDocTemplate = " << (void*)m_pDocTemplate;
if (dc.GetDepth() > 0)
{
POSITION pos = GetFirstViewPosition();
while (pos != NULL)
{
CView* pView = GetNextView(pos);
dc << "\nwith view " << (void*)pView;
}
}
dc << "\n";
}
void CDocument::AssertValid() const
{
CObject::AssertValid();
POSITION pos = GetFirstViewPosition();
while (pos != NULL)
{
CView* pView = GetNextView(pos);
ASSERT_VALID(pView);
}
}
#endif //_DEBUG
#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif
IMPLEMENT_DYNAMIC(CDocument, CCmdTarget)
/////////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -