home *** CD-ROM | disk | FTP | other *** search
- // This is a part of the Microsoft Foundation Classes C++ library.
- // Copyright (C) 1992-1998 Microsoft Corporation
- // All rights reserved.
- //
- // This source code is only intended as a supplement to the
- // Microsoft Foundation Classes Reference and related
- // electronic documentation provided with the library.
- // See these sources for detailed information regarding the
- // Microsoft Foundation Classes product.
-
- #include "stdafx.h"
- #include <malloc.h>
- #include <ole2.h>
- #include <oleauto.h>
-
- #ifdef AFXCTL_PROP_SEG
- #pragma code_seg(AFXCTL_PROP_SEG)
- #endif
-
- #ifdef _DEBUG
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
-
- #define new DEBUG_NEW
-
- /////////////////////////////////////////////////////////////////////////////
- // Helper functions used by CProperty, CPropertySection, CPropertySet classes
-
- AFX_STATIC LPVOID AFXAPI _AfxCountPrefixedStringA(LPCSTR lpsz)
- {
- DWORD cb = (lstrlenA(lpsz) + 1);
- LPDWORD lp = (LPDWORD)malloc((int)cb + sizeof(DWORD));
- if (lp)
- {
- *lp = cb;
- lstrcpyA((LPSTR)(lp+1), lpsz);
- }
-
- return (LPVOID)lp;
- }
-
-
- #ifndef OLE2ANSI
- AFX_STATIC LPVOID AFXAPI _AfxCountPrefixedStringW(LPCWSTR lpsz)
- {
- DWORD cb = (wcslen(lpsz) + 1);
- LPDWORD lp = (LPDWORD)malloc((int)cb * sizeof(WCHAR) + sizeof(DWORD));
- if (lp)
- {
- *lp = cb;
- wcscpy((LPWSTR)(lp+1), lpsz);
- }
-
- return (LPVOID)lp;
- }
- #endif
-
- #ifdef _UNICODE
- #define _AfxCountPrefixedString _AfxCountPrefixedStringW
- #else
- #define _AfxCountPrefixedString _AfxCountPrefixedStringA
- #endif
-
-
- #ifdef _UNICODE
-
- #define MAX_STRLEN 1024
-
- AFX_STATIC LPBYTE AFXAPI _AfxConvertStringProp(LPBYTE pbProp, DWORD dwType, ULONG nReps,
- size_t cbCharSize)
- {
- LPBYTE pbResult = NULL; // Return value
- ULONG cbResult = 0; // Number of bytes in pbResult
- LPBYTE pbBuffer; // Temporary holding space
- ULONG cchOrig; // Number of characters in original string
- ULONG cchCopy; // Number of characters to copy
- ULONG cbCopy; // Number of bytes to copy
- LPBYTE pbResultNew; // Used for realloc of pbResult
-
- pbBuffer = (LPBYTE)malloc(MAX_STRLEN * cbCharSize);
- if (pbBuffer == NULL)
- return NULL;
-
- // If it's a vector, the count goes first.
- if (dwType & VT_VECTOR)
- {
- pbResult = (LPBYTE)malloc(sizeof(DWORD));
- if (pbResult == NULL)
- {
- free(pbBuffer);
- return NULL;
- }
- *(LPDWORD)pbResult = nReps;
- cbResult = sizeof(DWORD);
- }
-
- while (nReps--)
- {
- cchOrig = *(LPDWORD)pbProp;
- pbProp += sizeof(DWORD);
-
- // Convert multibyte string to Unicode.
- if (cbCharSize == sizeof(WCHAR))
- {
- cchCopy = _mbstowcsz((LPWSTR)pbBuffer, (LPSTR)pbProp,
- min(cchOrig, MAX_STRLEN));
- }
- else
- {
- cchCopy = _wcstombsz((LPSTR)pbBuffer, (LPWSTR)pbProp,
- min(cchOrig, MAX_STRLEN));
- }
-
- // Allocate space to append string.
- cbCopy = cchCopy * cbCharSize;
- pbResultNew = (LPBYTE)realloc(pbResult, cbResult + sizeof(DWORD) +
- cbCopy);
-
- // If allocation failed, cleanup and return NULL;
- if (pbResultNew == NULL)
- {
- free(pbResult);
- free(pbBuffer);
- return NULL;
- }
-
- pbResult = pbResultNew;
-
- // Copy character count and converted string into place,
- // then update the total size.
- memcpy(pbResult + cbResult, (LPBYTE)&cchCopy, sizeof(DWORD));
- memcpy(pbResult + cbResult + sizeof(DWORD), pbBuffer, cbCopy);
- cbResult += sizeof(DWORD) + cbCopy;
-
- // Advance to the next vector element
- pbProp += (cchOrig * cbCharSize);
- }
-
- free(pbBuffer);
- return pbResult;
- }
-
- #endif // _UNICODE
-
- /////////////////////////////////////////////////////////////////////////////
- // Implementation of the CProperty class
-
- CProperty::CProperty()
- {
- m_dwPropID = 0;
-
- m_dwType = VT_EMPTY;
- m_pValue = NULL; // must init to NULL
- }
-
- CProperty::CProperty(DWORD dwID, const LPVOID pValue, DWORD dwType)
- {
- m_dwPropID = dwID;
- m_dwType = dwType;
- m_pValue = NULL; // must init to NULL
- Set(dwID, pValue, dwType);
- }
-
- CProperty::~CProperty()
- {
- FreeValue();
- }
-
- BOOL CProperty::Set(DWORD dwID, const LPVOID pValue, DWORD dwType)
- {
- m_dwType = dwType;
- m_dwPropID = dwID;
-
- return Set(pValue);
- }
-
- BOOL CProperty::Set(const LPVOID pValue, DWORD dwType)
- {
- m_dwType = dwType;
- return Set(pValue);
- }
-
- BOOL CProperty::Set(const LPVOID pVal)
- {
- ULONG cb;
- ULONG cbItem;
- ULONG cbValue;
- ULONG nReps;
- LPBYTE pCur;
- LPVOID pValue = pVal;
- DWORD dwType = m_dwType;
- LPVOID pValueOrig = NULL;
-
- if (m_pValue != NULL)
- {
- FreeValue();
- }
-
- if (pValue == NULL || m_dwType == 0)
- return TRUE;
-
- // Given pValue, determine how big it is
- // Then allocate a new buffer for m_pValue and copy...
- nReps = 1;
- cbValue = 0;
- pCur = (LPBYTE)pValue;
- if (m_dwType & VT_VECTOR)
- {
- // The next DWORD is a count of the elements
- nReps = *(LPDWORD)pValue;
- cb = sizeof(nReps);
- pCur += cb;
- cbValue += cb;
- dwType &= ~VT_VECTOR;
- }
- else
- {
- // If we get any of the string-like types,
- // and we are not a vector create a count-prefixed
- // buffer.
- switch (dwType)
- {
- case VT_LPSTR: // null terminated string
- pValueOrig = pValue;
- pValue = _AfxCountPrefixedStringA((LPSTR)pValueOrig);
- pCur = (LPBYTE)pValue;
- break;
-
- 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
- pValueOrig = pValue;
- pValue = _AfxCountPrefixedString((LPTSTR)pValueOrig);
- pCur = (LPBYTE)pValue;
- break;
-
- #ifndef OLE2ANSI
- case VT_LPWSTR: // UNICODE string
- pValueOrig = pValue;
- pValue = _AfxCountPrefixedStringW((LPWSTR)pValueOrig);
- pCur = (LPBYTE)pValue;
- break;
- #endif
- }
- }
-
- // 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.
- //
- cbItem = 0; // Size of the current item
- while (nReps--)
- {
- 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_CLSID: // A Class ID
- cbItem = sizeof(CLSID);
- break;
-
- #ifndef _UNICODE
- 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
- #endif // _UNICODE
- case VT_LPSTR: // null terminated string
- case VT_BLOB_OBJECT: // Blob contains an object
- case VT_BLOB_PROPSET: // Blob contains a propset
- case VT_BLOB: // Length prefixed bytes
- case VT_CF: // Clipboard format
- // Get the DWORD that gives us the size, making
- // sure we increment cbValue.
- cbItem = *(LPDWORD)pCur;
- cb = sizeof(cbItem);
- pCur += cb;
- cbValue += cb;
- break;
-
- #ifdef _UNICODE
- 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
- #endif // _UNICODE
- case VT_LPWSTR: // UNICODE string
- cbItem = *(LPDWORD)pCur * sizeof(WCHAR);
- cb = sizeof(cbItem);
- pCur += cb;
- cbValue += cb;
- break;
-
- default:
- if (pValueOrig)
- free(pValue);
- return FALSE;
- }
-
- // Seek to the next item
- pCur += cbItem;
- cbValue += cbItem;
- }
-
- if (NULL == AllocValue(cbValue))
- {
- TRACE0("CProperty::AllocValue failed");
- return FALSE;
- }
- memcpy(m_pValue, pValue, (int)cbValue);
-
- if (pValueOrig)
- free(pValue);
-
- return TRUE;
- }
-
- LPVOID CProperty::Get()
- { return Get((DWORD*)NULL); }
-
- LPVOID CProperty::Get(DWORD* pcb)
- {
- DWORD cb;
- LPBYTE p = NULL;
-
- p = (LPBYTE)m_pValue;
-
- // m_pValue points to a Property "Value" which may
- // have size information included...
- switch (m_dwType)
- {
- case VT_EMPTY: // nothing
- cb = 0;
- break;
-
- case VT_I2: // 2 byte signed int
- case VT_BOOL: // True=-1, False=0
- cb = 2;
- break;
-
- case VT_I4: // 4 byte signed int
- case VT_R4: // 4 byte real
- cb = 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
- cb = 8;
- break;
-
- #ifndef _UNICODE
- 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
- #endif // UNICODE
- case VT_LPSTR: // null terminated string
- case VT_CF: // Clipboard format
- // Read the DWORD that gives us the size, making
- // sure we increment cbValue.
- cb = *(LPDWORD)p;
- p += sizeof(DWORD);
- break;
-
- case VT_BLOB: // Length prefixed bytes
- case VT_BLOB_OBJECT: // Blob contains an object
- case VT_BLOB_PROPSET: // Blob contains a propset
- // Read the DWORD that gives us the size.
- cb = *(LPDWORD)p;
- break;
-
- #ifdef _UNICODE
- 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
- #endif // _UNICODE
- case VT_LPWSTR: // UNICODE string
- cb = *(LPDWORD)p * sizeof(WCHAR);
- p += sizeof(DWORD);
- break;
-
- case VT_CLSID: // A Class ID
- cb = sizeof(CLSID);
- break;
-
- default:
- return NULL;
- }
- if (pcb != NULL)
- *pcb = cb;
-
- return p;
- }
-
- DWORD CProperty::GetType()
- { return m_dwType; }
-
- void CProperty::SetType(DWORD dwType)
- { m_dwType = dwType; }
-
- DWORD CProperty::GetID()
- { return m_dwPropID; }
-
- void CProperty::SetID(DWORD dwPropID)
- { m_dwPropID = dwPropID; }
-
- LPVOID CProperty::GetRawValue()
- { return m_pValue; }
-
- BOOL CProperty::WriteToStream(IStream* pIStream)
- {
- ULONG cb;
- ULONG cbTotal; // Total size of the whole value
- DWORD dwType = m_dwType;
- DWORD nReps;
- LPBYTE pValue;
- LPBYTE pCur;
- BOOL bSuccess = FALSE;
- BYTE b = 0;
-
- nReps = 1;
- pValue = (LPBYTE)m_pValue;
- pCur = pValue;
- cbTotal = 0;
- if (m_dwType & VT_VECTOR)
- {
- // Value is a DWORD count of elements followed by
- // that many repititions of the value.
- //
- nReps = *(LPDWORD)pCur;
- cbTotal = sizeof(DWORD);
- pCur += cbTotal;
- dwType &= ~VT_VECTOR;
- }
-
- #ifdef _UNICODE
- 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
- pValue = _AfxConvertStringProp(pCur, m_dwType, nReps, sizeof(char));
- if (m_dwType & VT_VECTOR)
- pCur = pValue + sizeof(DWORD);
- break;
- }
- #endif // _UNICODE
-
- // Figure out how big the data is.
- while (nReps--)
- {
- switch (dwType)
- {
- case VT_EMPTY: // nothing
- cb = 0;
- break;
-
- case VT_I2: // 2 byte signed int
- case VT_BOOL: // True=-1, False=0
- cb = 2;
- break;
-
- case VT_I4: // 4 byte signed int
- case VT_R4: // 4 byte real
- cb = 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
- cb = 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
- 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;
-
- 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;
-
- default:
- pIStrItem->Release();
- return FALSE;
- }
-
- // 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 = _AfxConvertStringProp(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()
- {
- 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()
- {
- RemoveAll();
- return;
- }
-
- CLSID CPropertySection::GetFormatID()
- { 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)
- 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();
- CProperty* pProp;
- while (pos != NULL)
- {
- pProp= (CProperty*)m_PropList.GetNext(pos);
- if (pProp->m_dwPropID == dwPropID)
- return pProp;
- }
- return NULL;
- }
-
- void CPropertySection::AddProperty(CProperty* pProp)
- {
- m_PropList.AddTail(pProp);
- m_SH.cProperties++;
- }
-
- DWORD CPropertySection::GetSize()
- { return m_SH.cbSection; }
-
- DWORD CPropertySection::GetCount()
- { return m_PropList.GetCount(); }
-
- CPtrList* CPropertySection::GetList()
- { 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;
- }
-
- // 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);
- m_PropList.AddTail(pProp);
- }
- 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;
- }
-
- AFX_STATIC BOOL AFXAPI _AfxWriteNameDictEntry(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 (!_AfxWriteNameDictEntry(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 (!_AfxWriteNameDictEntry(pIStream, (DWORD)pvID, strName))
- return FALSE;
- }
-
- return TRUE;
- }
-
- BOOL CPropertySection::SetSectionName(LPCTSTR pszName)
- {
- m_strSectionName = pszName;
- return TRUE;
- }
-
- LPCTSTR CPropertySection::GetSectionName()
- {
- return (LPCTSTR)m_strSectionName;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // Implementation of the CPropertySet class
-
- CPropertySet::CPropertySet()
- {
- 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()
- { return m_PH.wByteOrder; }
-
- WORD CPropertySet::GetFormatVersion()
- { return m_PH.wFormat; }
-
- void CPropertySet::SetFormatVersion(WORD wFmtVersion)
- { m_PH.wFormat = wFmtVersion; }
-
- DWORD CPropertySet::GetOSVersion()
- { return m_PH.dwOSVer; }
-
- void CPropertySet::SetOSVersion(DWORD dwOSVer)
- { m_PH.dwOSVer = dwOSVer; }
-
- CLSID CPropertySet::GetClassID()
- { return m_PH.clsID; }
-
- void CPropertySet::SetClassID(CLSID clsID)
- { m_PH.clsID = clsID; }
-
- DWORD CPropertySet::GetCount()
- { return m_SectionList.GetCount(); }
-
- CPtrList* CPropertySet::GetList()
- { 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
-