As mentioned earlier, Patron manages a substorage for each page in the overall document. This, of course, requires somewhat more complex code when pages are created or destroyed. Whenever Patron creates a new page in the document, it calls IStorage::CreateStorage using the name Page<ID>, where <ID> is the page identifier in ASCII. When Patron opens an existing page, it calls IStorage::OpenStorage with the appropriate name as well. Both operations occur in CPage::Open. The member CPage::GetStorageName simply generates the text name to use in both calls:
BOOL CPage::Open(LPSTORAGE pIStorage)
{
BOOL fNULL=FALSE;
HRESULT hr=NOERROR;
DWORD dwMode=STGM_TRANSACTED | STGM_READWRITE
| STGM_SHARE_EXCLUSIVE;
OLECHAR szTemp[32];
if (NULL==m_pIStorage)
{
fNULL=TRUE;
if (NULL==pIStorage)
return FALSE;
GetStorageName(szTemp);
hr=pIStorage->OpenStorage(szTemp, NULL, dwMode, NULL, 0
, &m_pIStorage);
if (FAILED(hr))
{
hr=pIStorage->CreateStorage(szTemp, dwMode, 0, 0
, &m_pIStorage);
}
}
§
}
UINT CPage::GetStorageName(LPOLESTR pszName)
{
return wsprintf(pszName, TEXT("Page %lu"), m_dwID);
}
The CPages class assigns the page ID through the CPage constructor, which saves the value in m_dwID. The CPages class, once again, keeps a persistent DWORD counter for page IDs in the Page List stream. IDs are not recycled when a page is destroyed, but the DWORD counter would overflow only if you sat down and created (for example) one page every second until the year 2129. I desperately hope this software is obsolete by then!
Speaking of destroying a page, this operation requires a call to IStorage::DestroyElement to counter the IStorage::CreateStorage in the preceding code. The function CPage::Destroy takes care of this in Patron:
//pIStorage is document's root storage.
void CPage::Destroy(LPSTORAGE pIStorage)
{
if (NULL!=pIStorage)
{
OLECHAR szTemp[32];
Close(FALSE);
GetStorageName(szTemp)
pIStorage->DestroyElement(szTemp);
}
return;
}
void CPage::Close(BOOL fCommit)
{
if (NULL==m_pIStorage)
return;
if (fCommit)
Update();
if (0L==m_pIStorage->Release())
m_pIStorage=NULL;
return;
}
BOOL CPage::Update(void)
{
if (NULL!=m_pIStorage)
m_pIStorage->Commit(STGC_DEFAULT);
return TRUE;
}