📄 propset.cpp
字号:
// Do a seek from the beginning of the property set.
LISet32( li, ulSectionStart.LowPart + pido.dwOffset );
pIStream->Seek( liPropSet, STREAM_SEEK_SET, NULL );
pIStream->Seek( li, STREAM_SEEK_CUR, NULL );
// Now pIStream is at the type/value pair
if (pido.propertyID != 0)
{
pProp = new CProperty( pido.propertyID, NULL, 0 );
pProp->ReadFromStream( pIStream );
pProp->AssertValid();
m_PropList.AddTail( pProp );
m_PropList.AssertValid();
}
else
{
ReadNameDictFromStream( pIStream );
}
}
pIStrPIDO->Release();
return TRUE;
}
BOOL CPropertySection::GetID( LPCTSTR pszName, DWORD* pdwPropID )
{
CString strName(pszName);
strName.MakeLower(); // Dictionary stores all names in lowercase
void* pvID;
if (m_NameDict.Lookup(strName, pvID))
{
*pdwPropID = (DWORD)pvID;
return TRUE;
}
// Failed to find entry in dictionary
return FALSE;
}
BOOL CPropertySection::SetName( DWORD dwPropID, LPCTSTR pszName )
{
BOOL bSuccess = TRUE;
CString strName(pszName);
strName.MakeLower(); // Dictionary stores all names in lowercase
TRY
{
void* pDummy;
BOOL bNameExists = m_NameDict.Lookup(strName, pDummy);
ASSERT(! bNameExists); // Property names must be unique.
if (bNameExists)
bSuccess = FALSE;
else
m_NameDict.SetAt(strName, (void*)dwPropID);
}
CATCH (CException, e)
{
TRACE0("Failed to add entry to dictionary.\n");
bSuccess = FALSE;
}
END_CATCH
return bSuccess;
}
struct DICTENTRYHEADER
{
DWORD dwPropID;
DWORD cb;
};
struct DICTENTRY
{
DICTENTRYHEADER hdr;
char sz[256];
};
BOOL CPropertySection::ReadNameDictFromStream( IStream* pIStream )
{
ULONG cb;
ULONG cbRead = 0;
// Read dictionary header (count).
ULONG cProperties = 0;
pIStream->Read((LPVOID)&cProperties, sizeof(cProperties), &cb);
if (sizeof(cProperties) != cb)
{
TRACE0("Read of dictionary header failed.\n");
return FALSE;
}
ULONG iProp;
DICTENTRY entry;
for (iProp = 0; iProp < cProperties; iProp++)
{
// Read entry header (dwPropID, cch).
if (FAILED(pIStream->Read((LPVOID)&entry, sizeof(DICTENTRYHEADER),
&cbRead)) ||
(sizeof(DICTENTRYHEADER) != cbRead))
{
TRACE0("Read of dictionary entry failed.\n");
return FALSE;
}
// Read entry data (name).
cb = entry.hdr.cb;
if (FAILED(pIStream->Read((LPVOID)&entry.sz, cb, &cbRead)) ||
(cbRead != cb))
{
TRACE0("Read of dictionary entry failed.\n");
return FALSE;
}
LPTSTR pszName;
#ifdef _UNICODE
// Persistent form is always ANSI/DBCS. Convert to Unicode.
WCHAR wszName[256];
_mbstowcsz(wszName, entry.sz, 256);
pszName = wszName;
#else // _UNICODE
pszName = entry.sz;
#endif // _UNICODE
// Section's "name" appears first in list and has dwPropID == 0.
if ((iProp == 0) && (entry.hdr.dwPropID == 0))
m_strSectionName = pszName; // Section name
else
SetName(entry.hdr.dwPropID, pszName); // Some other property
}
return TRUE;
}
static BOOL WriteNameDictEntry(IStream* pIStream, DWORD dwPropID, CString& strName)
{
ULONG cb;
ULONG cbWritten = 0;
DICTENTRY entry;
entry.hdr.dwPropID = dwPropID;
entry.hdr.cb = min(strName.GetLength() + 1, 255);
#ifdef _UNICODE
// Persistent form is always ANSI/DBCS. Convert from Unicode.
_wcstombsz(entry.sz, (LPCWSTR)strName, 256);
#else // _UNICODE
memcpy(entry.sz, (LPCSTR)strName, (size_t)entry.hdr.cb);
#endif // _UNICODE
cb = sizeof(DICTENTRYHEADER) + entry.hdr.cb;
if (FAILED(pIStream->Write((LPVOID)&entry, cb, &cbWritten)) ||
(cbWritten != cb))
{
TRACE0("Write of dictionary entry failed.\n");
return FALSE;
}
return TRUE;
}
BOOL CPropertySection::WriteNameDictToStream( IStream* pIStream )
{
ULONG cb;
// Write dictionary header (count).
ULONG cProperties = m_NameDict.GetCount() + 1;
pIStream->Write((LPVOID)&cProperties, sizeof(cProperties), &cb);
if (sizeof(cProperties) != cb)
{
TRACE0("Write of dictionary header failed.\n");
return FALSE;
}
POSITION pos;
CString strName;
void* pvID;
// Write out section's "name" with dwPropID == 0 first
if (! WriteNameDictEntry(pIStream, 0, m_strSectionName))
return FALSE;
// Enumerate contents of dictionary and write out (dwPropID, cb, name).
pos = m_NameDict.GetStartPosition();
while (pos != NULL)
{
m_NameDict.GetNextAssoc( pos, strName, pvID );
if (! WriteNameDictEntry(pIStream, (DWORD)pvID, strName))
return FALSE;
}
return TRUE;
}
BOOL CPropertySection::SetSectionName( LPCTSTR pszName )
{
m_strSectionName = pszName;
return TRUE;
}
LPCTSTR CPropertySection::GetSectionName( void )
{
return (LPCTSTR)m_strSectionName;
}
/////////////////////////////////////////////////////////////////////////////
// Implementation of the CPropertySet class
CPropertySet::CPropertySet( void )
{
m_PH.wByteOrder = 0xFFFE;
m_PH.wFormat = 0;
m_PH.dwOSVer = (DWORD)MAKELONG( LOWORD(GetVersion()), 2 );
m_PH.clsID = GUID_NULL;
m_PH.cSections = 0;
}
CPropertySet::CPropertySet( CLSID clsID )
{
m_PH.wByteOrder = 0xFFFE;
m_PH.wFormat = 0;
m_PH.dwOSVer = (DWORD)MAKELONG( LOWORD(GetVersion()), 2 );
m_PH.clsID = clsID;
m_PH.cSections = 0;
}
CPropertySet::~CPropertySet()
{ RemoveAll(); }
BOOL CPropertySet::Set( CLSID FormatID, DWORD dwPropID, LPVOID pValue, DWORD dwType )
{
CPropertySection* pSect = GetSection( FormatID );
if (pSect == NULL)
{
if ((pSect = new CPropertySection( FormatID )) != NULL)
AddSection( pSect );
}
pSect->Set( dwPropID, pValue, dwType );
return TRUE;
}
BOOL CPropertySet::Set( CLSID FormatID, DWORD dwPropID, LPVOID pValue )
{
// Since there is no dwType, we have to assume that the property
// already exists. If it doesn't, fail.
CPropertySection* pSect = GetSection( FormatID );
if (pSect != NULL)
return pSect->Set( dwPropID, pValue );
else
return FALSE;
}
LPVOID CPropertySet::Get( CLSID FormatID, DWORD dwPropID, DWORD* pcb )
{
CPropertySection* pSect = GetSection( FormatID );
if (pSect)
return pSect->Get( dwPropID, pcb );
else
return NULL;
}
LPVOID CPropertySet::Get( CLSID FormatID, DWORD dwPropID )
{ return Get( FormatID, dwPropID, (DWORD*)NULL ); }
void CPropertySet::Remove( CLSID FormatID, DWORD dwPropID )
{
CPropertySection* pSect = GetSection( FormatID );
if (pSect)
pSect->Remove( dwPropID );
}
void CPropertySet::Remove( CLSID FormatID )
{
CPropertySection* pSect;
POSITION posRemove = m_SectionList.GetHeadPosition();
POSITION pos = posRemove;
while( posRemove != NULL )
{
pSect = (CPropertySection*)m_SectionList.GetNext( pos );
if (IsEqualCLSID( pSect->m_FormatID, FormatID ))
{
m_SectionList.RemoveAt( posRemove );
delete pSect;
m_PH.cSections--;
return;
}
posRemove = pos;
}
}
void CPropertySet::RemoveAll( )
{
POSITION pos = m_SectionList.GetHeadPosition();
while( pos != NULL )
{
delete (CPropertySection*)m_SectionList.GetNext( pos );
}
m_SectionList.RemoveAll();
m_PH.cSections = 0;
}
CPropertySection* CPropertySet::GetSection( CLSID FormatID )
{
POSITION pos = m_SectionList.GetHeadPosition();
CPropertySection* pSect;
while (pos != NULL)
{
pSect = (CPropertySection*)m_SectionList.GetNext( pos );
if (IsEqualCLSID( pSect->m_FormatID, FormatID ))
return pSect;
}
return NULL;
}
CPropertySection* CPropertySet::AddSection( CLSID FormatID )
{
CPropertySection* pSect = GetSection( FormatID );
if (pSect)
return pSect;
pSect = new CPropertySection( FormatID ) ;
if (pSect)
AddSection( pSect );
return pSect;
}
void CPropertySet::AddSection( CPropertySection* pSect )
{
m_SectionList.AddTail( pSect );
m_PH.cSections++;
}
CProperty* CPropertySet::GetProperty( CLSID FormatID, DWORD dwPropID )
{
CPropertySection* pSect = GetSection( FormatID );
if (pSect)
return pSect->GetProperty( dwPropID );
else
return NULL;
}
void CPropertySet::AddProperty( CLSID FormatID, CProperty* pProp )
{
CPropertySection* pSect = GetSection( FormatID );
if (pSect)
pSect->AddProperty( pProp );
}
WORD CPropertySet::GetByteOrder( void )
{ return m_PH.wByteOrder; }
WORD CPropertySet::GetFormatVersion( void )
{ return m_PH.wFormat; }
void CPropertySet::SetFormatVersion( WORD wFmtVersion )
{ m_PH.wFormat = wFmtVersion; }
DWORD CPropertySet::GetOSVersion( void )
{ return m_PH.dwOSVer; }
void CPropertySet::SetOSVersion( DWORD dwOSVer )
{ m_PH.dwOSVer = dwOSVer; }
CLSID CPropertySet::GetClassID( void )
{ return m_PH.clsID; }
void CPropertySet::SetClassID( CLSID clsID )
{ m_PH.clsID = clsID; }
DWORD CPropertySet::GetCount( void )
{ return m_SectionList.GetCount(); }
CObList* CPropertySet::GetList( void )
{ return &m_SectionList; }
BOOL CPropertySet::WriteToStream( IStream* pIStream )
{
LPSTREAM pIStrFIDO;
FORMATIDOFFSET fido;
ULONG cb;
ULARGE_INTEGER ulSeek;
LARGE_INTEGER li;
// Write the Property List Header
m_PH.cSections = m_SectionList.GetCount();
pIStream->Write((LPVOID)&m_PH, sizeof(m_PH), &cb);
if (sizeof(m_PH) != cb)
{
TRACE0("Write of Property Set Header failed.\n");
return FALSE;
}
if (m_SectionList.IsEmpty())
{
TRACE0("Warning: Wrote empty property set.\n");
return TRUE;
}
// After the header is the list of Format ID/Offset pairs
// Since there is an ID/Offset pair for each section and we
// need to write the ID/Offset pair as we write each section
// we clone the stream and use the clone to access the
// table of ID/offset pairs (FIDO)...
//
pIStream->Clone( &pIStrFIDO );
// Now seek pIStream past the FIDO list
//
LISet32( li, m_PH.cSections * sizeof( FORMATIDOFFSET ) );
pIStream->Seek( li, STREAM_SEEK_CUR, &ulSeek);
// Write each section.
CPropertySection* pSect = NULL;
POSITION pos = m_SectionList.GetHeadPosition();
while( pos != NULL )
{
// Get next element (note cast)
pSect = (CPropertySection*)m_SectionList.GetNext( pos );
// Write it
if (!pSect->WriteToStream( pIStream ))
{
pIStrFIDO->Release();
return FALSE;
}
// Using our cloned stream write the Format ID / Offset pair
fido.formatID = pSect->m_FormatID;
fido.dwOffset = ulSeek.LowPart;
pIStrFIDO->Write((LPVOID)&fido, sizeof(fido), &cb);
if (sizeof(fido) != cb)
{
TRACE0("Write of 'fido' failed.\n");
pIStrFIDO->Release();
return FALSE;
}
// Get the seek offset (for pIStream) after the write
LISet32( li, 0 );
pIStream->Seek( li, STREAM_SEEK_CUR, &ulSeek );
}
pIStrFIDO->Release();
return TRUE;
}
BOOL CPropertySet::ReadFromStream( IStream* pIStream )
{
ULONG cb;
FORMATIDOFFSET fido;
ULONG cSections;
LPSTREAM pIStrFIDO;
CPropertySection* pSect;
LARGE_INTEGER li;
LARGE_INTEGER liPropSet;
// Save the stream position at which the property set starts.
LARGE_INTEGER liZero = {0,0};
pIStream->Seek( liZero, STREAM_SEEK_CUR, (ULARGE_INTEGER*)&liPropSet );
if (m_PH.cSections || !m_SectionList.IsEmpty())
RemoveAll();
// The stream starts like this:
// wByteOrder wFmtVer dwOSVer clsID cSections
// Which is nice, because our PROPHEADER is the same!
pIStream->Read( (LPVOID)&m_PH, sizeof( m_PH ), &cb );
if (cb != sizeof(m_PH))
return FALSE;
// Now we're pointing at the first of the FormatID/Offset pairs
// (FIDOs). To get to each section we use a cloned stream
// to stay back and point at the FIDOs (pIStrFIDO). We seek
// pIStream to each of the sections, creating CProperitySection
// and so forth as we go...
//
pIStream->Clone( &pIStrFIDO );
cSections = m_PH.cSections;
while (cSections--)
{
pIStrFIDO->Read( (LPVOID)&fido, sizeof( fido ), &cb );
if (cb != sizeof(fido))
{
pIStrFIDO->Release();
return FALSE;
}
// Do a seek from the beginning of the property set.
LISet32( li, fido.dwOffset );
pIStream->Seek( liPropSet, STREAM_SEEK_SET, NULL );
pIStream->Seek( li, STREAM_SEEK_CUR, NULL );
// Now pIStream is at the type/value pair
pSect = new CPropertySection;
pSect->SetFormatID( fido.formatID );
pSect->ReadFromStream( pIStream, liPropSet );
m_SectionList.AddTail( pSect );
}
pIStrFIDO->Release();
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// Force any extra compiler-generated code into AFX_INIT_SEG
#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif
#endif // !defined(_MAC)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -