📄 propset.cpp
字号:
case VT_BSTR: // binary string
case VT_STREAM: // Name of the stream follows
case VT_STORAGE: // Name of the storage follows
case VT_STREAMED_OBJECT:// Stream contains an object
case VT_STORED_OBJECT: // Storage contains an object
case VT_STREAMED_PROPSET:// Stream contains a propset
case VT_STORED_PROPSET: // Storage contains a propset
case VT_BLOB: // Length prefixed bytes
case VT_BLOB_OBJECT: // Blob contains an object
case VT_BLOB_PROPSET: // Blob contains a propset
case VT_CF: // Clipboard format
cb = sizeof(DWORD) + *(LPDWORD)pCur;
break;
case VT_LPWSTR: // UNICODE string
cb = sizeof(DWORD) + (*(LPDWORD)pCur * sizeof(WCHAR));
break;
case VT_CLSID: // A Class ID
cb = sizeof(CLSID);
break;
case VT_VARIANT: // VARIANT*
break;
default:
return FALSE;
}
pCur += cb;
cbTotal+= cb;
}
// Write the type
pIStream->Write((LPVOID)&m_dwType, sizeof(m_dwType), &cb);
if (cb != sizeof(m_dwType))
goto Cleanup;
// Write the value
pIStream->Write((LPVOID)pValue, cbTotal, &cb);
if (cb != cbTotal)
goto Cleanup;
// Make sure we are 32 bit aligned
cbTotal = (((cbTotal + 3) >> 2) << 2) - cbTotal;
while (cbTotal--)
{
pIStream->Write((LPVOID)&b, 1, &cb);
if (cb != sizeof(BYTE))
goto Cleanup;
}
bSuccess = TRUE;
Cleanup:
if (pValue != m_pValue)
free(pValue);
return bSuccess;
}
BOOL CProperty::ReadFromStream( IStream* pIStream )
{
ULONG cb;
ULONG cbItem;
ULONG cbValue;
DWORD dwType;
ULONG nReps;
ULONG iReps;
LPSTREAM pIStrItem;
LARGE_INTEGER li;
// All properties are made up of a type/value pair.
// The obvious first thing to do is to get the type...
pIStream->Read( (LPVOID)&m_dwType, sizeof(m_dwType), &cb );
if (cb != sizeof(m_dwType))
return FALSE;
dwType = m_dwType;
nReps = 1;
cbValue = 0;
if (m_dwType & VT_VECTOR)
{
// The next DWORD in the stream is a count of the
// elements
pIStream->Read( (LPVOID)&nReps, sizeof(nReps), &cb );
if (cb != sizeof(nReps))
return FALSE;
cbValue += cb;
dwType &= ~VT_VECTOR;
}
// Since a value can be made up of a vector (VT_VECTOR) of
// items, we first seek through the value, picking out
// each item, getting it's size. We use a cloned
// stream for this (pIStrItem).
// We then use our pIStream to read the entire 'blob' into
// the allocated buffer.
//
cbItem = 0; // Size of the current item
pIStream->Clone( &pIStrItem );
ASSERT(pIStrItem != NULL);
iReps = nReps;
while (iReps--)
{
switch (dwType)
{
case VT_EMPTY: // nothing
cbItem = 0;
break;
case VT_I2: // 2 byte signed int
case VT_BOOL: // True=-1, False=0
cbItem = 2;
break;
case VT_I4: // 4 byte signed int
case VT_R4: // 4 byte real
cbItem = 4;
break;
case VT_R8: // 8 byte real
case VT_CY: // currency
case VT_DATE: // date
case VT_I8: // signed 64-bit int
case VT_FILETIME: // FILETIME
cbItem = 8;
break;
case VT_LPSTR: // null terminated string
case VT_BSTR: // binary string
case VT_STREAM: // Name of the stream follows
case VT_STORAGE: // Name of the storage follows
case VT_STREAMED_OBJECT:// Stream contains an object
case VT_STORED_OBJECT: // Storage contains an object
case VT_STREAMED_PROPSET:// Stream contains a propset
case VT_STORED_PROPSET: // Storage contains a propset
case VT_BLOB: // Length prefixed bytes
case VT_BLOB_OBJECT: // Blob contains an object
case VT_BLOB_PROPSET: // Blob contains a propset
case VT_CF: // Clipboard format
// Read the DWORD that gives us the size, making
// sure we increment cbValue.
pIStream->Read( (LPVOID)&cbItem, sizeof(cbItem), &cb );
if (cb != sizeof(cbItem))
return FALSE;
LISet32( li, -(LONG)cb );
pIStream->Seek( li, STREAM_SEEK_CUR, NULL );
cbValue += cb;
break;
case VT_LPWSTR: // UNICODE string
pIStream->Read( (LPVOID)&cbItem, sizeof(cbItem), &cb );
if (cb != sizeof(cbItem))
return FALSE;
LISet32( li, -(LONG)cb );
pIStream->Seek( li, STREAM_SEEK_CUR, NULL );
cbValue += cb;
cbItem *= sizeof(WCHAR);
break;
case VT_CLSID: // A Class ID
cbItem = sizeof(CLSID);
break;
case VT_VARIANT: // VARIANT*
break;
default:
pIStrItem->Release();
return FALSE;
}
// Add 'cb' to cbItem before seeking...
//
// Seek to the next item
LISet32( li, cbItem );
pIStrItem->Seek( li, STREAM_SEEK_CUR, NULL);
cbValue += cbItem;
}
pIStrItem->Release();
#ifdef _UNICODE
LPBYTE pTmp;
switch (dwType)
{
case VT_BSTR: // binary string
case VT_STREAM: // Name of the stream follows
case VT_STORAGE: // Name of the storage follows
case VT_STREAMED_OBJECT:// Stream contains an object
case VT_STORED_OBJECT: // Storage contains an object
case VT_STREAMED_PROPSET:// Stream contains a propset
case VT_STORED_PROPSET: // Storage contains a propset
pTmp = (LPBYTE)malloc((int)cbValue);
pIStream->Read( pTmp, cbValue, &cb );
m_pValue = ConvertStringProp(pTmp, m_dwType, nReps, sizeof(WCHAR));
free(pTmp);
break;
default:
#endif // _UNICODE
// Allocate cbValue bytes
if (NULL == AllocValue(cbValue))
return FALSE;
// Read the buffer from pIStream
pIStream->Read( m_pValue, cbValue, &cb );
if (cb != cbValue)
return FALSE;
#ifdef _UNICODE
break;
}
#endif // _UNICODE
// Done!
return TRUE;
}
LPVOID CProperty::AllocValue(ULONG cb)
{
return m_pValue = malloc((int)cb);
}
void CProperty::FreeValue()
{
if (m_pValue != NULL)
{
free(m_pValue);
m_pValue = NULL;
}
}
/////////////////////////////////////////////////////////////////////////////
// Implementation of the CPropertySection Class
CPropertySection::CPropertySection( void )
{
m_FormatID = GUID_NULL;
m_SH.cbSection = 0;
m_SH.cProperties = 0;
}
CPropertySection::CPropertySection( CLSID FormatID )
{
m_FormatID = FormatID;
m_SH.cbSection = 0;
m_SH.cProperties = 0;
}
CPropertySection::~CPropertySection( void )
{
RemoveAll();
return;
}
CLSID CPropertySection::GetFormatID( void )
{ return m_FormatID; }
void CPropertySection::SetFormatID( CLSID FormatID )
{ m_FormatID = FormatID; }
BOOL CPropertySection::Set( DWORD dwPropID, LPVOID pValue, DWORD dwType )
{
CProperty* pProp = GetProperty( dwPropID );
if (pProp == NULL)
{
if ((pProp = new CProperty( dwPropID, pValue, dwType )) != NULL)
AddProperty( pProp );
return (pProp != NULL);
}
pProp->Set( dwPropID, pValue, dwType );
return TRUE;
}
BOOL CPropertySection::Set( DWORD dwPropID, LPVOID pValue )
{
// Since no dwType was specified, the property is assumed
// to exist. Fail if it does not.
CProperty* pProp = GetProperty( dwPropID );
if (pProp != NULL && pProp->m_dwType)
{
pProp->Set( dwPropID, pValue, pProp->m_dwType );
return TRUE;
}
else
return FALSE;
}
LPVOID CPropertySection::Get( DWORD dwPropID )
{ return Get( dwPropID, (DWORD*)NULL ); }
LPVOID CPropertySection::Get( DWORD dwPropID, DWORD* pcb )
{
CProperty* pProp = GetProperty( dwPropID );
if (pProp)
{
pProp->AssertValid();
return pProp->Get( pcb );
}
else
return NULL;
}
void CPropertySection::Remove( DWORD dwID )
{
POSITION pos = m_PropList.GetHeadPosition();
CProperty* pProp;
while( pos != NULL )
{
POSITION posRemove = pos;
pProp = (CProperty*)m_PropList.GetNext( pos );
if (pProp->m_dwPropID == dwID)
{
m_PropList.RemoveAt( posRemove );
delete pProp;
m_SH.cProperties--;
return;
}
}
}
void CPropertySection::RemoveAll( )
{
POSITION pos = m_PropList.GetHeadPosition();
while( pos != NULL )
delete (CProperty*)m_PropList.GetNext( pos );
m_PropList.RemoveAll();
m_SH.cProperties = 0;
}
CProperty* CPropertySection::GetProperty( DWORD dwPropID )
{
POSITION pos = m_PropList.GetHeadPosition();
m_PropList.AssertValid();
CProperty* pProp;
while (pos != NULL)
{
pProp= (CProperty*)m_PropList.GetNext( pos );
pProp->AssertValid();
if (pProp->m_dwPropID == dwPropID)
return pProp;
}
return NULL;
}
void CPropertySection::AddProperty( CProperty* pProp )
{
m_PropList.AddTail( pProp );
m_SH.cProperties++;
}
DWORD CPropertySection::GetSize( void )
{ return m_SH.cbSection; }
DWORD CPropertySection::GetCount( void )
{ return m_PropList.GetCount(); }
CObList* CPropertySection::GetList( void )
{ return &m_PropList; }
BOOL CPropertySection::WriteToStream( IStream* pIStream )
{
// Create a dummy property entry for the name dictionary (ID == 0).
Set(0, NULL, VT_EMPTY);
ULONG cb;
ULARGE_INTEGER ulSeekOld;
ULARGE_INTEGER ulSeek;
LPSTREAM pIStrPIDO;
PROPERTYIDOFFSET pido;
LARGE_INTEGER li;
// The Section header contains the number of bytes in the
// section. Thus we need to go back to where we should
// write the count of bytes
// after we write all the property sets..
// We accomplish this by saving the seek pointer to where
// the size should be written in ulSeekOld
m_SH.cbSection = 0;
m_SH.cProperties = m_PropList.GetCount();
LISet32( li, 0 );
pIStream->Seek( li, STREAM_SEEK_CUR, &ulSeekOld);
pIStream->Write((LPVOID)&m_SH, sizeof(m_SH), &cb);
if (sizeof(m_SH) != cb)
{
TRACE0("Write of section header failed (1).\n");
return FALSE;
}
if (m_PropList.IsEmpty())
{
TRACE0("Warning: Wrote empty property section.\n");
return TRUE;
}
// After the section header is the list of property ID/Offset pairs
// Since there is an ID/Offset pair for each property and we
// need to write the ID/Offset pair as we write each property
// we clone the stream and use the clone to access the
// table of ID/offset pairs (PIDO)...
//
pIStream->Clone( &pIStrPIDO );
// Now seek pIStream past the PIDO list
//
LISet32( li, m_SH.cProperties * sizeof( PROPERTYIDOFFSET ) );
pIStream->Seek( li, STREAM_SEEK_CUR, &ulSeek);
// Now write each section to pIStream.
CProperty* pProp = NULL;
POSITION pos = m_PropList.GetHeadPosition();
while( pos != NULL )
{
// Get next element (note cast)
pProp = (CProperty*)m_PropList.GetNext( pos );
if (pProp->m_dwPropID != 0)
{
// Write it
if (!pProp->WriteToStream( pIStream ))
{
pIStrPIDO->Release();
return FALSE;
}
}
else
{
if (!WriteNameDictToStream( pIStream ))
{
pIStrPIDO->Release();
return FALSE;
}
}
// Using our cloned stream write the Format ID / Offset pair
// The offset to this property is the current seek pointer
// minus the pointer to the beginning of the section
pido.dwOffset = ulSeek.LowPart - ulSeekOld.LowPart;
pido.propertyID = pProp->m_dwPropID;
pIStrPIDO->Write((LPVOID)&pido, sizeof(pido), &cb);
if (sizeof(pido) != cb)
{
TRACE0("Write of 'pido' failed\n");
pIStrPIDO->Release();
return FALSE;
}
// Get the seek offset after the write
LISet32( li, 0 );
pIStream->Seek( li, STREAM_SEEK_CUR, &ulSeek );
}
pIStrPIDO->Release();
// Now go back to ulSeekOld and write the section header.
// Size of section is current seek point minus old seek point
//
m_SH.cbSection = ulSeek.LowPart - ulSeekOld.LowPart;
// Seek to beginning of this section and write the section header.
LISet32( li, ulSeekOld.LowPart );
pIStream->Seek( li, STREAM_SEEK_SET, NULL );
pIStream->Write((LPVOID)&m_SH, sizeof(m_SH), &cb);
if (sizeof(m_SH) != cb)
{
TRACE0("Write of section header failed (2).\n");
return FALSE;
}
// Now seek to end of of the now written section
LISet32(li, ulSeek.LowPart);
pIStream->Seek(li, STREAM_SEEK_SET, NULL);
return TRUE;
}
BOOL CPropertySection::ReadFromStream( IStream* pIStream,
LARGE_INTEGER liPropSet )
{
ULONG cb;
PROPERTYIDOFFSET pido;
ULONG cProperties;
LPSTREAM pIStrPIDO;
ULARGE_INTEGER ulSectionStart;
LARGE_INTEGER li;
CProperty* pProp;
if (m_SH.cProperties || !m_PropList.IsEmpty())
RemoveAll();
// pIStream is pointing to the beginning of the section we
// are to read. First there is a DWORD that is the count
// of bytes in this section, then there is a count
// of properties, followed by a list of propertyID/offset pairs,
// followed by type/value pairs.
//
LISet32( li, 0 );
pIStream->Seek( li, STREAM_SEEK_CUR, &ulSectionStart );
pIStream->Read( (LPVOID)&m_SH, sizeof(m_SH), &cb );
if (cb != sizeof(m_SH))
return FALSE;
// Now we're pointing at the first of the PropID/Offset pairs
// (PIDOs). To get to each property we use a cloned stream
// to stay back and point at the PIDOs (pIStrPIDO). We seek
// pIStream to each of the Type/Value pairs, creating CProperites
// and so forth as we go...
//
pIStream->Clone( &pIStrPIDO );
cProperties = m_SH.cProperties;
while (cProperties--)
{
pIStrPIDO->Read( (LPVOID)&pido, sizeof( pido ), &cb );
if (cb != sizeof(pido))
{
pIStrPIDO->Release();
return FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -