PROPSET.CPP
上传用户:sesekoo
上传日期:2020-07-18
资源大小:21543k
文件大小:40k
源码类别:

界面编程

开发平台:

Visual C++

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10. #include "stdafx.h"
  11. #include <malloc.h>
  12. #include <ole2.h>
  13. #include <oleauto.h>
  14. #ifndef __DRAWCLI_PROPSET_H
  15. #include "propset.h"
  16. #endif // __DRAWCLI_PROPSET_H
  17. #ifdef AFXCTL_PROP_SEG
  18. #pragma code_seg(AFXCTL_PROP_SEG)
  19. #endif
  20. #ifdef _DEBUG
  21. #undef THIS_FILE
  22. static char THIS_FILE[] = __FILE__;
  23. #endif
  24. #define new DEBUG_NEW
  25. static LPVOID CountPrefixedStringA(LPCSTR lpsz)
  26. {
  27. DWORD cb = (lstrlenA( lpsz ) + 1);
  28. LPDWORD lp = (LPDWORD)malloc( (int)cb + sizeof(DWORD) );
  29. if (lp)
  30. {
  31. *lp = cb;
  32. lstrcpyA( (LPSTR)(lp+1), lpsz );
  33. }
  34. return (LPVOID)lp;
  35. }
  36. static LPVOID CountPrefixedStringW(LPCWSTR lpsz)
  37. {
  38. DWORD cb = DWORD( wcslen( lpsz ) + 1 );
  39. LPDWORD lp = (LPDWORD)malloc( (int)cb * sizeof(WCHAR) + sizeof(DWORD) );
  40. if (lp)
  41. {
  42. *lp = cb;
  43. __EXT_MFC_WCSCPY( (LPWSTR)(lp+1), wcslen( (LPWSTR)(lp+1) ), lpsz );
  44. }
  45. return (LPVOID)lp;
  46. }
  47. #ifdef _UNICODE
  48. #define CountPrefixedStringT CountPrefixedStringW
  49. #else
  50. #define CountPrefixedStringT CountPrefixedStringA
  51. #endif
  52. #ifdef _UNICODE
  53. #define MAX_STRLEN 1024
  54. static LPBYTE ConvertStringProp(LPBYTE pbProp, DWORD dwType, ULONG nReps,
  55. size_t cbCharSize)
  56. {
  57. LPBYTE pbResult = NULL; // Return value
  58. ULONG cbResult = 0;     // Number of bytes in pbResult
  59. LPBYTE pbBuffer;        // Temporary holding space
  60. ULONG cchOrig;          // Number of characters in original string
  61. ULONG cchCopy;          // Number of characters to copy
  62. ULONG cbCopy;           // Number of bytes to copy
  63. LPBYTE pbResultNew;     // Used for realloc of pbResult
  64. pbBuffer = (LPBYTE)malloc(MAX_STRLEN * cbCharSize);
  65. if (pbBuffer == NULL)
  66. return NULL;
  67. // If it's a vector, the count goes first.
  68. if (dwType & VT_VECTOR)
  69. {
  70. pbResult = (LPBYTE)malloc(sizeof(DWORD));
  71. if (pbResult == NULL)
  72. {
  73. free(pbBuffer);
  74. return NULL;
  75. }
  76. *(LPDWORD)pbResult = nReps;
  77. cbResult = sizeof(DWORD);
  78. }
  79. while (nReps--)
  80. {
  81. cchOrig = *(LPDWORD)pbProp;
  82. pbProp += sizeof(DWORD);
  83. // Convert multibyte string to Unicode.
  84. if (cbCharSize == sizeof(WCHAR))
  85. {
  86. cchCopy = _mbstowcsz((LPWSTR)pbBuffer, (LPSTR)pbProp,
  87. min(cchOrig, MAX_STRLEN));
  88. }
  89. else
  90. {
  91. cchCopy = _wcstombsz((LPSTR)pbBuffer, (LPWSTR)pbProp,
  92. min(cchOrig, MAX_STRLEN));
  93. }
  94. // Allocate space to append string.
  95. cbCopy = ULONG( cchCopy * cbCharSize );
  96. pbResultNew = (LPBYTE)realloc(pbResult, cbResult + sizeof(DWORD) +
  97. cbCopy);
  98. // If allocation failed, cleanup and return NULL;
  99. if (pbResultNew == NULL)
  100. {
  101. free(pbResult);
  102. free(pbBuffer);
  103. return NULL;
  104. }
  105. pbResult = pbResultNew;
  106. // Copy character count and converted string into place,
  107. // then update the total size.
  108. memcpy(pbResult + cbResult, (LPBYTE)&cchCopy, sizeof(DWORD));
  109. memcpy(pbResult + cbResult + sizeof(DWORD), pbBuffer, cbCopy);
  110. cbResult += sizeof(DWORD) + cbCopy;
  111. // Advance to the next vector element
  112. pbProp += (cchOrig * cbCharSize);
  113. }
  114. free(pbBuffer);
  115. return pbResult;
  116. }
  117. #endif // _UNICODE
  118. /////////////////////////////////////////////////////////////////////////////
  119. //Implementation of the CDrawCliProperty class
  120. CDrawCliProperty::CDrawCliProperty( void )
  121. {
  122. m_dwPropID = 0;
  123. m_dwType = VT_EMPTY;
  124. m_pValue = NULL;       // must init to NULL
  125. }
  126. CDrawCliProperty::CDrawCliProperty( DWORD dwID, const LPVOID pValue, DWORD dwType )
  127. {
  128. m_dwPropID = dwID;
  129. m_dwType = dwType;
  130. m_pValue = NULL;       // must init to NULL
  131. Set( dwID, pValue, dwType );
  132. }
  133. CDrawCliProperty::~CDrawCliProperty()
  134. {
  135. FreeValue();
  136. }
  137. BOOL CDrawCliProperty::Set( DWORD dwID, const LPVOID pValue, DWORD dwType )
  138. {
  139. m_dwType = dwType;
  140. m_dwPropID = dwID;
  141. return Set( pValue );
  142. }
  143. BOOL CDrawCliProperty::Set( const LPVOID pValue, DWORD dwType )
  144. {
  145. m_dwType = dwType;
  146. return Set( pValue );
  147. }
  148. BOOL CDrawCliProperty::Set( const  LPVOID pVal )
  149. {
  150. ULONG           cb;
  151. ULONG           cbItem;
  152. ULONG           cbValue;
  153. ULONG           nReps;
  154. LPBYTE          pCur;
  155. LPVOID          pValue = pVal;
  156. DWORD           dwType = m_dwType;
  157. LPVOID          pValueOrig = NULL;
  158. if (m_pValue != NULL)
  159. {
  160. FreeValue();
  161. }
  162. if (pValue == NULL || m_dwType == 0)
  163. return TRUE;
  164. // Given pValue, determine how big it is
  165. // Then allocate a new buffer for m_pValue and copy...
  166. nReps = 1;
  167. cbValue = 0;
  168. pCur = (LPBYTE)pValue;
  169. if (m_dwType & VT_VECTOR)
  170. {
  171. // The next DWORD is a count of the elements
  172. nReps = *(LPDWORD)pValue;
  173. cb = sizeof( nReps );
  174. pCur += cb;
  175. cbValue += cb;
  176. dwType &= ~VT_VECTOR;
  177. }
  178. else
  179. {
  180. // If we get any of the string-like types,
  181. // and we are not a vector create a count-prefixed
  182. // buffer.
  183. switch (dwType )
  184. {
  185. case VT_LPSTR:          // null terminated string
  186. pValueOrig = pValue;
  187. pValue = CountPrefixedStringA( (LPSTR)pValueOrig );
  188. pCur = (LPBYTE)pValue;
  189. break;
  190. case VT_BSTR:           // binary string
  191. case VT_STREAM:         // Name of the stream follows
  192. case VT_STORAGE:        // Name of the storage follows
  193. case VT_STREAMED_OBJECT:// Stream contains an object
  194. case VT_STORED_OBJECT:  // Storage contains an object
  195. pValueOrig = pValue;
  196. pValue = CountPrefixedStringT( (LPTSTR)pValueOrig );
  197. pCur = (LPBYTE)pValue;
  198. break;
  199. case VT_LPWSTR:         // UNICODE string
  200. pValueOrig = pValue;
  201. pValue = CountPrefixedStringW( (LPWSTR)pValueOrig );
  202. pCur = (LPBYTE)pValue;
  203. break;
  204. }
  205. }
  206. // Since a value can be made up of a vector (VT_VECTOR) of
  207. // items, we first seek through the value, picking out
  208. // each item, getting it's size.
  209. //
  210. cbItem = 0;        // Size of the current item
  211. while (nReps--)
  212. {
  213. switch (dwType)
  214. {
  215. case VT_EMPTY:          // nothing
  216. cbItem = 0;
  217. break;
  218. case VT_I2:             // 2 byte signed int
  219. case VT_BOOL:           // True=-1, False=0
  220. cbItem = 2;
  221. break;
  222. case VT_I4:             // 4 byte signed int
  223. case VT_R4:             // 4 byte real
  224. cbItem = 4;
  225. break;
  226. case VT_R8:             // 8 byte real
  227. case VT_CY:             // currency
  228. case VT_DATE:           // date
  229. case VT_I8:             // signed 64-bit int
  230. case VT_FILETIME:       // FILETIME
  231. cbItem = 8;
  232. break;
  233. case VT_CLSID:          // A Class ID
  234. cbItem = sizeof(CLSID);
  235. break;
  236. #ifndef _UNICODE
  237. case VT_BSTR:           // binary string
  238. case VT_STREAM:         // Name of the stream follows
  239. case VT_STORAGE:        // Name of the storage follows
  240. case VT_STREAMED_OBJECT:// Stream contains an object
  241. case VT_STORED_OBJECT:  // Storage contains an object
  242. case VT_STREAMED_PROPSET:// Stream contains a propset
  243. case VT_STORED_PROPSET: // Storage contains a propset
  244. #endif // _UNICODE
  245. case VT_LPSTR:          // null terminated string
  246. case VT_BLOB_OBJECT:    // Blob contains an object
  247. case VT_BLOB_PROPSET:   // Blob contains a propset
  248. case VT_BLOB:           // Length prefixed bytes
  249. case VT_CF:             // Clipboard format
  250. // Get the DWORD that gives us the size, making
  251. // sure we increment cbValue.
  252. cbItem = *(LPDWORD)pCur;
  253. cb = sizeof(cbItem);
  254. pCur += cb;
  255. cbValue += cb;
  256. break;
  257. #ifdef _UNICODE
  258. case VT_BSTR:           // binary string
  259. case VT_STREAM:         // Name of the stream follows
  260. case VT_STORAGE:        // Name of the storage follows
  261. case VT_STREAMED_OBJECT:// Stream contains an object
  262. case VT_STORED_OBJECT:  // Storage contains an object
  263. case VT_STREAMED_PROPSET:// Stream contains a propset
  264. case VT_STORED_PROPSET: // Storage contains a propset
  265. #endif // _UNICODE
  266. case VT_LPWSTR:         // UNICODE string
  267. cbItem = *(LPDWORD)pCur * sizeof(WCHAR);
  268. cb = sizeof( cbItem );
  269. pCur += cb;
  270. cbValue += cb;
  271. break;
  272. case VT_VARIANT:        // VARIANT*
  273. break;
  274. default:
  275. if (pValueOrig)
  276. free( pValue );
  277. return FALSE;
  278. }
  279. // Add 'cb' to cbItem before seeking...
  280. //
  281. // Seek to the next item
  282. pCur += cbItem;
  283. cbValue += cbItem;
  284. }
  285. if (NULL == AllocValue(cbValue))
  286. {
  287. TRACE0("CDrawCliProperty::AllocValue failed");
  288. return FALSE;
  289. }
  290. memcpy( m_pValue, pValue, (int)cbValue );
  291. if (pValueOrig)
  292. free( pValue );
  293. return TRUE;
  294. }
  295. LPVOID CDrawCliProperty::Get( void )
  296. {   return Get( (DWORD*)NULL );   }
  297. LPVOID CDrawCliProperty::Get( DWORD* pcb )
  298. {
  299. DWORD   cb = 0;
  300. LPBYTE  p = NULL;
  301. p = (LPBYTE)m_pValue;
  302. // m_pValue points to a Property "Value" which may
  303. // have size information included...
  304. switch( m_dwType )
  305. {
  306. case VT_EMPTY:          // nothing
  307. cb = 0;
  308. break;
  309. case VT_I2:             // 2 byte signed int
  310. case VT_BOOL:           // True=-1, False=0
  311. cb = 2;
  312. break;
  313. case VT_I4:             // 4 byte signed int
  314. case VT_R4:             // 4 byte real
  315. cb = 4;
  316. break;
  317. case VT_R8:             // 8 byte real
  318. case VT_CY:             // currency
  319. case VT_DATE:           // date
  320. case VT_I8:             // signed 64-bit int
  321. case VT_FILETIME:       // FILETIME
  322. cb = 8;
  323. break;
  324. #ifndef _UNICODE
  325. case VT_BSTR:           // binary string
  326. case VT_STREAM:         // Name of the stream follows
  327. case VT_STORAGE:        // Name of the storage follows
  328. case VT_STREAMED_OBJECT:// Stream contains an object
  329. case VT_STORED_OBJECT:  // Storage contains an object
  330. case VT_STREAMED_PROPSET:// Stream contains a propset
  331. case VT_STORED_PROPSET: // Storage contains a propset
  332. #endif // UNICODE
  333. case VT_LPSTR:          // null terminated string
  334. case VT_CF:             // Clipboard format
  335. // Read the DWORD that gives us the size, making
  336. // sure we increment cbValue.
  337. cb = *(LPDWORD)p;
  338. p += sizeof( DWORD );
  339. break;
  340. case VT_BLOB:           // Length prefixed bytes
  341. case VT_BLOB_OBJECT:    // Blob contains an object
  342. case VT_BLOB_PROPSET:   // Blob contains a propset
  343. // Read the DWORD that gives us the size.
  344. cb = *(LPDWORD)p;
  345. break;
  346. #ifdef _UNICODE
  347. case VT_BSTR:           // binary string
  348. case VT_STREAM:         // Name of the stream follows
  349. case VT_STORAGE:        // Name of the storage follows
  350. case VT_STREAMED_OBJECT:// Stream contains an object
  351. case VT_STORED_OBJECT:  // Storage contains an object
  352. case VT_STREAMED_PROPSET:// Stream contains a propset
  353. case VT_STORED_PROPSET: // Storage contains a propset
  354. #endif // _UNICODE
  355. case VT_LPWSTR:         // UNICODE string
  356. cb = *(LPDWORD)p * sizeof(WCHAR);
  357. p += sizeof( DWORD );
  358. break;
  359. case VT_CLSID:          // A Class ID
  360. cb = sizeof(CLSID);
  361. break;
  362. case VT_VARIANT:        // VARIANT*
  363. break;
  364. default:
  365. return NULL;
  366. }
  367. if (pcb != NULL)
  368. *pcb = cb;
  369. return p;
  370. }
  371. DWORD  CDrawCliProperty::GetType( void )
  372. {   return m_dwType;  }
  373. void   CDrawCliProperty::SetType( DWORD dwType )
  374. {   m_dwType = dwType; }
  375. DWORD CDrawCliProperty::GetID( void )
  376. {   return m_dwPropID;   }
  377. void CDrawCliProperty::SetID( DWORD dwPropID )
  378. {    m_dwPropID = dwPropID;   }
  379. LPVOID CDrawCliProperty::GetRawValue( void )
  380. {   return m_pValue; }
  381. BOOL CDrawCliProperty::WriteToStream( IStream* pIStream )
  382. {
  383. ULONG           cb = 0;
  384. ULONG           cbTotal; // Total size of the whole value
  385. DWORD           dwType = m_dwType;
  386. DWORD           nReps;
  387. LPBYTE          pValue;
  388. LPBYTE          pCur;
  389. BOOL            bSuccess = FALSE;
  390. BYTE            b = 0;
  391. nReps = 1;
  392. pValue = (LPBYTE)m_pValue;
  393. pCur = pValue;
  394. cbTotal = 0;
  395. if (m_dwType & VT_VECTOR)
  396. {
  397. // Value is a DWORD count of elements followed by
  398. // that many repititions of the value.
  399. //
  400. nReps = *(LPDWORD)pCur;
  401. cbTotal = sizeof(DWORD);
  402. pCur += cbTotal;
  403. dwType &= ~VT_VECTOR;
  404. }
  405. #ifdef _UNICODE
  406. switch (dwType)
  407. {
  408. case VT_BSTR:           // binary string
  409. case VT_STREAM:         // Name of the stream follows
  410. case VT_STORAGE:        // Name of the storage follows
  411. case VT_STREAMED_OBJECT:// Stream contains an object
  412. case VT_STORED_OBJECT:  // Storage contains an object
  413. case VT_STREAMED_PROPSET:// Stream contains a propset
  414. case VT_STORED_PROPSET: // Storage contains a propset
  415. pValue = ConvertStringProp(pCur, m_dwType, nReps, sizeof(char));
  416. if (m_dwType & VT_VECTOR)
  417. pCur = pValue + sizeof(DWORD);
  418. break;
  419. }
  420. #endif // _UNICODE
  421. // Figure out how big the data is.
  422. while (nReps--)
  423. {
  424. switch (dwType)
  425. {
  426. case VT_EMPTY:          // nothing
  427. cb = 0;
  428. break;
  429. case VT_I2:             // 2 byte signed int
  430. case VT_BOOL:           // True=-1, False=0
  431. cb = 2;
  432. break;
  433. case VT_I4:             // 4 byte signed int
  434. case VT_R4:             // 4 byte real
  435. cb = 4;
  436. break;
  437. case VT_R8:             // 8 byte real
  438. case VT_CY:             // currency
  439. case VT_DATE:           // date
  440. case VT_I8:             // signed 64-bit int
  441. case VT_FILETIME:       // FILETIME
  442. cb = 8;
  443. break;
  444. case VT_LPSTR:          // null terminated string
  445. case VT_BSTR:           // binary string
  446. case VT_STREAM:         // Name of the stream follows
  447. case VT_STORAGE:        // Name of the storage follows
  448. case VT_STREAMED_OBJECT:// Stream contains an object
  449. case VT_STORED_OBJECT:  // Storage contains an object
  450. case VT_STREAMED_PROPSET:// Stream contains a propset
  451. case VT_STORED_PROPSET: // Storage contains a propset
  452. case VT_BLOB:           // Length prefixed bytes
  453. case VT_BLOB_OBJECT:    // Blob contains an object
  454. case VT_BLOB_PROPSET:   // Blob contains a propset
  455. case VT_CF:             // Clipboard format
  456. cb = sizeof(DWORD) + *(LPDWORD)pCur;
  457. break;
  458. case VT_LPWSTR:         // UNICODE string
  459. cb = sizeof(DWORD) + (*(LPDWORD)pCur * sizeof(WCHAR));
  460. break;
  461. case VT_CLSID:          // A Class ID
  462. cb = sizeof(CLSID);
  463. break;
  464. case VT_VARIANT:        // VARIANT*
  465. break;
  466. default:
  467. return FALSE;
  468. }
  469. pCur += cb;
  470. cbTotal+= cb;
  471. }
  472. // Write the type
  473. pIStream->Write((LPVOID)&m_dwType, sizeof(m_dwType), &cb);
  474. if (cb != sizeof(m_dwType))
  475. goto Cleanup;
  476. // Write the value
  477. pIStream->Write((LPVOID)pValue, cbTotal, &cb);
  478. if (cb != cbTotal)
  479. goto Cleanup;
  480. // Make sure we are 32 bit aligned
  481. cbTotal = (((cbTotal + 3) >> 2) << 2) - cbTotal;
  482. while (cbTotal--)
  483. {
  484. pIStream->Write((LPVOID)&b, 1, &cb);
  485. if (cb != sizeof(BYTE))
  486. goto Cleanup;
  487. }
  488. bSuccess = TRUE;
  489. Cleanup:
  490. if (pValue != m_pValue)
  491. free(pValue);
  492. return bSuccess;
  493. }
  494. BOOL CDrawCliProperty::ReadFromStream( IStream* pIStream )
  495. {
  496. ULONG           cb;
  497. ULONG           cbItem;
  498. ULONG           cbValue;
  499. DWORD           dwType;
  500. ULONG           nReps;
  501. ULONG           iReps;
  502. LPSTREAM        pIStrItem;
  503. LARGE_INTEGER   li;
  504. // All properties are made up of a type/value pair.
  505. // The obvious first thing to do is to get the type...
  506. pIStream->Read( (LPVOID)&m_dwType, sizeof(m_dwType), &cb );
  507. if (cb != sizeof(m_dwType))
  508. return FALSE;
  509. dwType = m_dwType;
  510. nReps = 1;
  511. cbValue = 0;
  512. if (m_dwType & VT_VECTOR)
  513. {
  514. // The next DWORD in the stream is a count of the
  515. // elements
  516. pIStream->Read( (LPVOID)&nReps, sizeof(nReps), &cb );
  517. if (cb != sizeof(nReps))
  518. return FALSE;
  519. cbValue += cb;
  520. dwType &= ~VT_VECTOR;
  521. }
  522. // Since a value can be made up of a vector (VT_VECTOR) of
  523. // items, we first seek through the value, picking out
  524. // each item, getting it's size.  We use a cloned
  525. // stream for this (pIStrItem).
  526. // We then use our pIStream to read the entire 'blob' into
  527. // the allocated buffer.
  528. //
  529. cbItem = 0;        // Size of the current item
  530. pIStream->Clone( &pIStrItem );
  531. ASSERT(pIStrItem != NULL);
  532. iReps = nReps;
  533. while (iReps--)
  534. {
  535. switch (dwType)
  536. {
  537. case VT_EMPTY:          // nothing
  538. cbItem = 0;
  539. break;
  540. case VT_I2:             // 2 byte signed int
  541. case VT_BOOL:           // True=-1, False=0
  542. cbItem = 2;
  543. break;
  544. case VT_I4:             // 4 byte signed int
  545. case VT_R4:             // 4 byte real
  546. cbItem = 4;
  547. break;
  548. case VT_R8:             // 8 byte real
  549. case VT_CY:             // currency
  550. case VT_DATE:           // date
  551. case VT_I8:             // signed 64-bit int
  552. case VT_FILETIME:       // FILETIME
  553. cbItem = 8;
  554. break;
  555. case VT_LPSTR:          // null terminated string
  556. case VT_BSTR:           // binary string
  557. case VT_STREAM:         // Name of the stream follows
  558. case VT_STORAGE:        // Name of the storage follows
  559. case VT_STREAMED_OBJECT:// Stream contains an object
  560. case VT_STORED_OBJECT:  // Storage contains an object
  561. case VT_STREAMED_PROPSET:// Stream contains a propset
  562. case VT_STORED_PROPSET: // Storage contains a propset
  563. case VT_BLOB:           // Length prefixed bytes
  564. case VT_BLOB_OBJECT:    // Blob contains an object
  565. case VT_BLOB_PROPSET:   // Blob contains a propset
  566. case VT_CF:             // Clipboard format
  567. // Read the DWORD that gives us the size, making
  568. // sure we increment cbValue.
  569. pIStream->Read( (LPVOID)&cbItem, sizeof(cbItem), &cb );
  570. if (cb != sizeof(cbItem))
  571. return FALSE;
  572. LISet32( li, -(LONG)cb );
  573. pIStream->Seek( li, STREAM_SEEK_CUR, NULL );
  574. cbValue += cb;
  575. break;
  576. case VT_LPWSTR:         // UNICODE string
  577. pIStream->Read( (LPVOID)&cbItem, sizeof(cbItem), &cb );
  578. if (cb != sizeof(cbItem))
  579. return FALSE;
  580. LISet32( li, -(LONG)cb );
  581. pIStream->Seek( li, STREAM_SEEK_CUR, NULL );
  582. cbValue += cb;
  583. cbItem *= sizeof(WCHAR);
  584. break;
  585. case VT_CLSID:          // A Class ID
  586. cbItem = sizeof(CLSID);
  587. break;
  588. case VT_VARIANT:        // VARIANT*
  589. break;
  590. default:
  591. pIStrItem->Release();
  592. return FALSE;
  593. }
  594. // Add 'cb' to cbItem before seeking...
  595. //
  596. // Seek to the next item
  597. LISet32( li, cbItem );
  598. pIStrItem->Seek( li, STREAM_SEEK_CUR, NULL);
  599. cbValue += cbItem;
  600. }
  601. pIStrItem->Release();
  602. #ifdef _UNICODE
  603. LPBYTE pTmp;
  604. switch (dwType)
  605. {
  606. case VT_BSTR:           // binary string
  607. case VT_STREAM:         // Name of the stream follows
  608. case VT_STORAGE:        // Name of the storage follows
  609. case VT_STREAMED_OBJECT:// Stream contains an object
  610. case VT_STORED_OBJECT:  // Storage contains an object
  611. case VT_STREAMED_PROPSET:// Stream contains a propset
  612. case VT_STORED_PROPSET: // Storage contains a propset
  613. pTmp = (LPBYTE)malloc((int)cbValue);
  614. pIStream->Read( pTmp, cbValue, &cb );
  615. m_pValue = ConvertStringProp(pTmp, m_dwType, nReps, sizeof(WCHAR));
  616. free(pTmp);
  617. break;
  618. default:
  619. #endif // _UNICODE
  620. // Allocate cbValue bytes
  621. if (NULL == AllocValue(cbValue))
  622. return FALSE;
  623. // Read the buffer from pIStream
  624. pIStream->Read( m_pValue, cbValue, &cb );
  625. if (cb != cbValue)
  626. return FALSE;
  627. #ifdef _UNICODE
  628. break;
  629. }
  630. #endif // _UNICODE
  631. // Done!
  632. return TRUE;
  633. }
  634. LPVOID CDrawCliProperty::AllocValue(ULONG cb)
  635. {
  636. return m_pValue = malloc((int)cb);
  637. }
  638. void CDrawCliProperty::FreeValue()
  639. {
  640. if (m_pValue != NULL)
  641. {
  642. free(m_pValue);
  643. m_pValue = NULL;
  644. }
  645. }
  646. /////////////////////////////////////////////////////////////////////////////
  647. // Implementation of the CDrawCliPropertySection Class
  648. CDrawCliPropertySection::CDrawCliPropertySection( void )
  649. {
  650. m_FormatID = GUID_NULL;
  651. m_SH.cbSection = 0;
  652. m_SH.cProperties = 0;
  653. }
  654. CDrawCliPropertySection::CDrawCliPropertySection( CLSID FormatID )
  655. {
  656. m_FormatID = FormatID;
  657. m_SH.cbSection = 0;
  658. m_SH.cProperties = 0;
  659. }
  660. CDrawCliPropertySection::~CDrawCliPropertySection( void )
  661. {
  662. RemoveAll();
  663. return;
  664. }
  665. CLSID CDrawCliPropertySection::GetFormatID( void )
  666. {   return m_FormatID; }
  667. void CDrawCliPropertySection::SetFormatID( CLSID FormatID )
  668. {   m_FormatID = FormatID; }
  669. BOOL CDrawCliPropertySection::Set( DWORD dwPropID, LPVOID pValue, DWORD dwType )
  670. {
  671. CDrawCliProperty* pProp = GetProperty( dwPropID );
  672. if (pProp == NULL)
  673. {
  674. if ((pProp = new CDrawCliProperty( dwPropID, pValue, dwType )) != NULL)
  675. AddProperty( pProp );
  676. return (pProp != NULL);
  677. }
  678. pProp->Set( dwPropID, pValue, dwType );
  679. return TRUE;
  680. }
  681. BOOL CDrawCliPropertySection::Set( DWORD dwPropID, LPVOID pValue )
  682. {
  683. // Since no dwType was specified, the property is assumed
  684. // to exist.   Fail if it does not.
  685. CDrawCliProperty* pProp = GetProperty( dwPropID );
  686. if (pProp != NULL && pProp->m_dwType)
  687. {
  688. pProp->Set( dwPropID, pValue, pProp->m_dwType );
  689. return TRUE;
  690. }
  691. else
  692. return FALSE;
  693. }
  694. LPVOID CDrawCliPropertySection::Get( DWORD dwPropID )
  695. {   return Get( dwPropID, (DWORD*)NULL );  }
  696. LPVOID CDrawCliPropertySection::Get( DWORD dwPropID, DWORD* pcb )
  697. {
  698. CDrawCliProperty* pProp = GetProperty( dwPropID );
  699. if (pProp)
  700. {
  701. #if (defined _DEBUG)
  702. pProp->AssertValid();
  703. #endif
  704. return pProp->Get( pcb );
  705. }
  706. else
  707. return NULL;
  708. }
  709. void CDrawCliPropertySection::Remove( DWORD dwID )
  710. {
  711. POSITION pos = m_PropList.GetHeadPosition();
  712. CDrawCliProperty*  pProp;
  713. while( pos != NULL )
  714. {
  715. POSITION posRemove = pos;
  716. pProp = (CDrawCliProperty*)m_PropList.GetNext( pos );
  717. if (pProp->m_dwPropID == dwID)
  718. {
  719. m_PropList.RemoveAt( posRemove );
  720. delete pProp;
  721. m_SH.cProperties--;
  722. return;
  723. }
  724. }
  725. }
  726. void CDrawCliPropertySection::RemoveAll( )
  727. {
  728. POSITION pos = m_PropList.GetHeadPosition();
  729. while( pos != NULL )
  730. delete (CDrawCliProperty*)m_PropList.GetNext( pos );
  731. m_PropList.RemoveAll();
  732. m_SH.cProperties = 0;
  733. }
  734. CDrawCliProperty* CDrawCliPropertySection::GetProperty( DWORD dwPropID )
  735. {
  736. POSITION pos = m_PropList.GetHeadPosition();
  737. #if (defined _DEBUG)
  738. m_PropList.AssertValid();
  739. #endif
  740. CDrawCliProperty* pProp;
  741. while (pos != NULL)
  742. {
  743. pProp= (CDrawCliProperty*)m_PropList.GetNext( pos );
  744. #if (defined _DEBUG)
  745. pProp->AssertValid();
  746. #endif
  747. if (pProp->m_dwPropID == dwPropID)
  748. return pProp;
  749. }
  750. return NULL;
  751. }
  752. void CDrawCliPropertySection::AddProperty( CDrawCliProperty* pProp )
  753. {
  754. m_PropList.AddTail( pProp );
  755. m_SH.cProperties++;
  756. }
  757. DWORD CDrawCliPropertySection::GetSize( void )
  758. {   return m_SH.cbSection; }
  759. DWORD CDrawCliPropertySection::GetCount( void )
  760. {   return DWORD( m_PropList.GetCount() );  }
  761. CObList* CDrawCliPropertySection::GetList( void )
  762. {   return &m_PropList;  }
  763. BOOL CDrawCliPropertySection::WriteToStream( IStream* pIStream )
  764. {
  765. // Create a dummy property entry for the name dictionary (ID == 0).
  766. Set(0, NULL, VT_EMPTY);
  767. ULONG           cb;
  768. ULARGE_INTEGER  ulSeekOld;
  769. ULARGE_INTEGER  ulSeek;
  770. LPSTREAM        pIStrPIDO;
  771. PROPERTYIDOFFSET  pido;
  772. LARGE_INTEGER   li;
  773. // The Section header contains the number of bytes in the
  774. // section.  Thus we need  to go back to where we should
  775. // write the count of bytes
  776. // after we write all the property sets..
  777. // We accomplish this by saving the seek pointer to where
  778. // the size should be written in ulSeekOld
  779. m_SH.cbSection = 0;
  780. m_SH.cProperties = DWORD( m_PropList.GetCount() );
  781. LISet32( li, 0 );
  782. pIStream->Seek( li, STREAM_SEEK_CUR, &ulSeekOld);
  783. pIStream->Write((LPVOID)&m_SH, sizeof(m_SH), &cb);
  784. if (sizeof(m_SH) != cb)
  785. {
  786. TRACE0("Write of section header failed (1).n");
  787. return FALSE;
  788. }
  789. if (m_PropList.IsEmpty())
  790. {
  791. TRACE0("Warning: Wrote empty property section.n");
  792. return TRUE;
  793. }
  794. // After the section header is the list of property ID/Offset pairs
  795. // Since there is an ID/Offset pair for each property and we
  796. // need to write the ID/Offset pair as we write each property
  797. // we clone the stream and use the clone to access the
  798. // table of ID/offset pairs (PIDO)...
  799. //
  800. pIStream->Clone( &pIStrPIDO );
  801. // Now seek pIStream past the PIDO list
  802. //
  803. LISet32( li,  m_SH.cProperties * sizeof( PROPERTYIDOFFSET ) );
  804. pIStream->Seek( li, STREAM_SEEK_CUR, &ulSeek);
  805. // Now write each section to pIStream.
  806. CDrawCliProperty* pProp = NULL;
  807. POSITION pos = m_PropList.GetHeadPosition();
  808. while( pos != NULL )
  809. {
  810. // Get next element (note cast)
  811. pProp = (CDrawCliProperty*)m_PropList.GetNext( pos );
  812. if (pProp->m_dwPropID != 0)
  813. {
  814. // Write it
  815. if (!pProp->WriteToStream( pIStream ))
  816. {
  817. pIStrPIDO->Release();
  818. return FALSE;
  819. }
  820. }
  821. else
  822. {
  823. if (!WriteNameDictToStream( pIStream ))
  824. {
  825. pIStrPIDO->Release();
  826. return FALSE;
  827. }
  828. }
  829. // Using our cloned stream write the Format ID / Offset pair
  830. // The offset to this property is the current seek pointer
  831. // minus the pointer to the beginning of the section
  832. pido.dwOffset = ulSeek.LowPart - ulSeekOld.LowPart;
  833. pido.propertyID = pProp->m_dwPropID;
  834. pIStrPIDO->Write((LPVOID)&pido, sizeof(pido), &cb);
  835. if (sizeof(pido) != cb)
  836. {
  837. TRACE0("Write of 'pido' failedn");
  838. pIStrPIDO->Release();
  839. return FALSE;
  840. }
  841. // Get the seek offset after the write
  842. LISet32( li, 0 );
  843. pIStream->Seek( li, STREAM_SEEK_CUR, &ulSeek );
  844. }
  845. pIStrPIDO->Release();
  846. // Now go back to ulSeekOld and write the section header.
  847. // Size of section is current seek point minus old seek point
  848. //
  849. m_SH.cbSection = ulSeek.LowPart - ulSeekOld.LowPart;
  850. // Seek to beginning of this section and write the section header.
  851. LISet32( li, ulSeekOld.LowPart );
  852. pIStream->Seek( li, STREAM_SEEK_SET, NULL );
  853. pIStream->Write((LPVOID)&m_SH, sizeof(m_SH), &cb);
  854. if (sizeof(m_SH) != cb)
  855. {
  856. TRACE0("Write of section header failed (2).n");
  857. return FALSE;
  858. }
  859. // Now seek to end of of the now written section
  860. LISet32(li, ulSeek.LowPart);
  861. pIStream->Seek(li, STREAM_SEEK_SET, NULL);
  862. return TRUE;
  863. }
  864. BOOL CDrawCliPropertySection::ReadFromStream( IStream* pIStream,
  865. LARGE_INTEGER liPropSet )
  866. {
  867. ULONG               cb;
  868. PROPERTYIDOFFSET    pido;
  869. ULONG               cProperties;
  870. LPSTREAM            pIStrPIDO;
  871. ULARGE_INTEGER      ulSectionStart;
  872. LARGE_INTEGER       li;
  873. CDrawCliProperty*          pProp;
  874. if (m_SH.cProperties || !m_PropList.IsEmpty())
  875. RemoveAll();
  876. // pIStream is pointing to the beginning of the section we
  877. // are to read.  First there is a DWORD that is the count
  878. // of bytes in this section, then there is a count
  879. // of properties, followed by a list of propertyID/offset pairs,
  880. // followed by type/value pairs.
  881. //
  882. LISet32( li, 0 );
  883. pIStream->Seek( li, STREAM_SEEK_CUR, &ulSectionStart );
  884. pIStream->Read( (LPVOID)&m_SH, sizeof(m_SH), &cb );
  885. if (cb != sizeof(m_SH))
  886. return FALSE;
  887. // Now we're pointing at the first of the PropID/Offset pairs
  888. // (PIDOs).   To get to each property we use a cloned stream
  889. // to stay back and point at the PIDOs (pIStrPIDO).  We seek
  890. // pIStream to each of the Type/Value pairs, creating CProperites
  891. // and so forth as we go...
  892. //
  893. pIStream->Clone( &pIStrPIDO );
  894. cProperties = m_SH.cProperties;
  895. while (cProperties--)
  896. {
  897. pIStrPIDO->Read( (LPVOID)&pido, sizeof( pido ), &cb );
  898. if (cb != sizeof(pido))
  899. {
  900. pIStrPIDO->Release();
  901. return FALSE;
  902. }
  903. // Do a seek from the beginning of the property set.
  904. LISet32( li, ulSectionStart.LowPart + pido.dwOffset );
  905. pIStream->Seek( liPropSet, STREAM_SEEK_SET, NULL );
  906. pIStream->Seek( li, STREAM_SEEK_CUR, NULL );
  907. // Now pIStream is at the type/value pair
  908. if (pido.propertyID != 0)
  909. {
  910. pProp = new CDrawCliProperty( pido.propertyID, NULL, 0 );
  911. pProp->ReadFromStream( pIStream );
  912. #if (defined _DEBUG)
  913. pProp->AssertValid();
  914. #endif
  915. m_PropList.AddTail( pProp );
  916. #if (defined _DEBUG)
  917. m_PropList.AssertValid();
  918. #endif
  919. }
  920. else
  921. {
  922. ReadNameDictFromStream( pIStream );
  923. }
  924. }
  925. pIStrPIDO->Release();
  926. return TRUE;
  927. }
  928. BOOL CDrawCliPropertySection::GetID( LPCTSTR pszName, DWORD* pdwPropID )
  929. {
  930. CString strName(pszName);
  931. strName.MakeLower();        // Dictionary stores all names in lowercase
  932. void* pvID;
  933. if (m_NameDict.Lookup(strName, pvID))
  934. {
  935. *pdwPropID = (DWORD)pvID;
  936. return TRUE;
  937. }
  938. // Failed to find entry in dictionary
  939. return FALSE;
  940. }
  941. BOOL CDrawCliPropertySection::SetName( DWORD dwPropID, LPCTSTR pszName )
  942. {
  943. BOOL bSuccess = TRUE;
  944. CString strName(pszName);
  945. strName.MakeLower();        // Dictionary stores all names in lowercase
  946. TRY
  947. {
  948. void* pDummy;
  949. BOOL bNameExists = m_NameDict.Lookup(strName, pDummy);
  950. ASSERT(! bNameExists);  // Property names must be unique.
  951. if (bNameExists)
  952. bSuccess = FALSE;
  953. else
  954. m_NameDict.SetAt(strName, (void*)dwPropID);
  955. }
  956. CATCH (CException, e)
  957. {
  958. TRACE0("Failed to add entry to dictionary.n");
  959. bSuccess = FALSE;
  960. }
  961. END_CATCH
  962. return bSuccess;
  963. }
  964. struct DICTENTRYHEADER
  965. {
  966. DWORD dwPropID;
  967. DWORD cb;
  968. };
  969. struct DICTENTRY
  970. {
  971. DICTENTRYHEADER hdr;
  972. char sz[256];
  973. };
  974. BOOL CDrawCliPropertySection::ReadNameDictFromStream( IStream* pIStream )
  975. {
  976. ULONG cb;
  977. ULONG cbRead = 0;
  978. // Read dictionary header (count).
  979. ULONG cProperties = 0;
  980. pIStream->Read((LPVOID)&cProperties, sizeof(cProperties), &cb);
  981. if (sizeof(cProperties) != cb)
  982. {
  983. TRACE0("Read of dictionary header failed.n");
  984. return FALSE;
  985. }
  986. ULONG iProp;
  987. DICTENTRY entry;
  988. for (iProp = 0; iProp < cProperties; iProp++)
  989. {
  990. // Read entry header (dwPropID, cch).
  991. if (FAILED(pIStream->Read((LPVOID)&entry, sizeof(DICTENTRYHEADER),
  992. &cbRead)) ||
  993. (sizeof(DICTENTRYHEADER) != cbRead))
  994. {
  995. TRACE0("Read of dictionary entry failed.n");
  996. return FALSE;
  997. }
  998. // Read entry data (name).
  999. cb = entry.hdr.cb;
  1000. if (FAILED(pIStream->Read((LPVOID)&entry.sz, cb, &cbRead)) ||
  1001. (cbRead != cb))
  1002. {
  1003. TRACE0("Read of dictionary entry failed.n");
  1004. return FALSE;
  1005. }
  1006. LPTSTR pszName;
  1007. #ifdef _UNICODE
  1008. // Persistent form is always ANSI/DBCS.  Convert to Unicode.
  1009. WCHAR wszName[256];
  1010. _mbstowcsz(wszName, entry.sz, 256);
  1011. pszName = wszName;
  1012. #else // _UNICODE
  1013. pszName = entry.sz;
  1014. #endif // _UNICODE
  1015. // Section's "name" appears first in list and has dwPropID == 0.
  1016. if ((iProp == 0) && (entry.hdr.dwPropID == 0))
  1017. m_strSectionName = pszName;             // Section name
  1018. else
  1019. SetName(entry.hdr.dwPropID, pszName);   // Some other property
  1020. }
  1021. return TRUE;
  1022. }
  1023. static BOOL WriteNameDictEntry(IStream* pIStream, DWORD dwPropID, CString& strName)
  1024. {
  1025. ULONG cb;
  1026. ULONG cbWritten = 0;
  1027. DICTENTRY entry;
  1028. entry.hdr.dwPropID = dwPropID;
  1029. entry.hdr.cb = min(strName.GetLength() + 1, 255);
  1030. #ifdef _UNICODE
  1031. // Persistent form is always ANSI/DBCS.  Convert from Unicode.
  1032. _wcstombsz(entry.sz, (LPCWSTR)strName, 256);
  1033. #else // _UNICODE
  1034. memcpy(entry.sz, (LPCSTR)strName, (size_t)entry.hdr.cb);
  1035. #endif // _UNICODE
  1036. cb = sizeof(DICTENTRYHEADER) + entry.hdr.cb;
  1037. if (FAILED(pIStream->Write((LPVOID)&entry, cb, &cbWritten)) ||
  1038. (cbWritten != cb))
  1039. {
  1040. TRACE0("Write of dictionary entry failed.n");
  1041. return FALSE;
  1042. }
  1043. return TRUE;
  1044. }
  1045. BOOL CDrawCliPropertySection::WriteNameDictToStream( IStream* pIStream )
  1046. {
  1047. ULONG cb;
  1048. // Write dictionary header (count).
  1049. ULONG cProperties = ULONG( m_NameDict.GetCount() + 1 );
  1050. pIStream->Write((LPVOID)&cProperties, sizeof(cProperties), &cb);
  1051. if (sizeof(cProperties) != cb)
  1052. {
  1053. TRACE0("Write of dictionary header failed.n");
  1054. return FALSE;
  1055. }
  1056. POSITION pos;
  1057. CString strName;
  1058. void* pvID;
  1059. // Write out section's "name" with dwPropID == 0 first
  1060. if (! WriteNameDictEntry(pIStream, 0, m_strSectionName))
  1061. return FALSE;
  1062. // Enumerate contents of dictionary and write out (dwPropID, cb, name).
  1063. pos = m_NameDict.GetStartPosition();
  1064. while (pos != NULL)
  1065. {
  1066. m_NameDict.GetNextAssoc( pos, strName, pvID );
  1067. if (! WriteNameDictEntry(pIStream, (DWORD)pvID, strName))
  1068. return FALSE;
  1069. }
  1070. return TRUE;
  1071. }
  1072. BOOL CDrawCliPropertySection::SetSectionName( LPCTSTR pszName )
  1073. {
  1074. m_strSectionName = pszName;
  1075. return TRUE;
  1076. }
  1077. LPCTSTR CDrawCliPropertySection::GetSectionName( void )
  1078. {
  1079. return (LPCTSTR)m_strSectionName;
  1080. }
  1081. /////////////////////////////////////////////////////////////////////////////
  1082. // Implementation of the CDrawCliPropertySet class
  1083. CDrawCliPropertySet::CDrawCliPropertySet( void )
  1084. {
  1085. m_PH.wByteOrder = 0xFFFE;
  1086. m_PH.wFormat = 0;
  1087. m_PH.dwOSVer = (DWORD)MAKELONG( LOWORD(GetVersion()), 2 );
  1088. m_PH.clsID =  GUID_NULL;
  1089. m_PH.cSections = 0;
  1090. }
  1091. CDrawCliPropertySet::CDrawCliPropertySet( CLSID clsID )
  1092. {
  1093. m_PH.wByteOrder = 0xFFFE;
  1094. m_PH.wFormat = 0;
  1095. m_PH.dwOSVer = (DWORD)MAKELONG( LOWORD(GetVersion()), 2 );
  1096. m_PH.clsID = clsID;
  1097. m_PH.cSections = 0;
  1098. }
  1099. CDrawCliPropertySet::~CDrawCliPropertySet()
  1100. {   RemoveAll();  }
  1101. BOOL CDrawCliPropertySet::Set( CLSID FormatID, DWORD dwPropID, LPVOID pValue, DWORD dwType )
  1102. {
  1103. CDrawCliPropertySection* pSect = GetSection( FormatID );
  1104. if (pSect == NULL)
  1105. {
  1106. if ((pSect = new CDrawCliPropertySection( FormatID )) != NULL)
  1107. AddSection( pSect );
  1108. }
  1109. pSect->Set( dwPropID, pValue, dwType );
  1110. return TRUE;
  1111. }
  1112. BOOL CDrawCliPropertySet::Set( CLSID FormatID, DWORD dwPropID, LPVOID pValue )
  1113. {
  1114. // Since there is no dwType, we have to assume that the property
  1115. // already exists.  If it doesn't, fail.
  1116. CDrawCliPropertySection* pSect = GetSection( FormatID );
  1117. if (pSect != NULL)
  1118. return pSect->Set( dwPropID, pValue );
  1119. else
  1120. return FALSE;
  1121. }
  1122. LPVOID CDrawCliPropertySet::Get( CLSID FormatID, DWORD dwPropID, DWORD* pcb )
  1123. {
  1124. CDrawCliPropertySection* pSect = GetSection( FormatID );
  1125. if (pSect)
  1126. return pSect->Get( dwPropID, pcb );
  1127. else
  1128. return NULL;
  1129. }
  1130. LPVOID CDrawCliPropertySet::Get( CLSID FormatID, DWORD dwPropID )
  1131. {   return Get( FormatID, dwPropID, (DWORD*)NULL ); }
  1132. void CDrawCliPropertySet::Remove( CLSID FormatID, DWORD dwPropID )
  1133. {
  1134. CDrawCliPropertySection*  pSect = GetSection( FormatID );
  1135. if (pSect)
  1136. pSect->Remove( dwPropID );
  1137. }
  1138. void CDrawCliPropertySet::Remove( CLSID FormatID )
  1139. {
  1140. CDrawCliPropertySection* pSect;
  1141. POSITION posRemove = m_SectionList.GetHeadPosition();
  1142. POSITION pos = posRemove;
  1143. while( posRemove != NULL )
  1144. {
  1145. pSect = (CDrawCliPropertySection*)m_SectionList.GetNext( pos );
  1146. if (IsEqualCLSID( pSect->m_FormatID, FormatID ))
  1147. {
  1148. m_SectionList.RemoveAt( posRemove );
  1149. delete pSect;
  1150. m_PH.cSections--;
  1151. return;
  1152. }
  1153. posRemove = pos;
  1154. }
  1155. }
  1156. void CDrawCliPropertySet::RemoveAll( )
  1157. {
  1158. POSITION pos = m_SectionList.GetHeadPosition();
  1159. while( pos != NULL )
  1160. {
  1161. delete (CDrawCliPropertySection*)m_SectionList.GetNext( pos );
  1162. }
  1163. m_SectionList.RemoveAll();
  1164. m_PH.cSections = 0;
  1165. }
  1166. CDrawCliPropertySection* CDrawCliPropertySet::GetSection( CLSID FormatID )
  1167. {
  1168. POSITION pos = m_SectionList.GetHeadPosition();
  1169. CDrawCliPropertySection* pSect;
  1170. while (pos != NULL)
  1171. {
  1172. pSect = (CDrawCliPropertySection*)m_SectionList.GetNext( pos );
  1173. if (IsEqualCLSID( pSect->m_FormatID, FormatID ))
  1174. return pSect;
  1175. }
  1176. return NULL;
  1177. }
  1178. CDrawCliPropertySection* CDrawCliPropertySet::AddSection( CLSID FormatID )
  1179. {
  1180. CDrawCliPropertySection* pSect = GetSection( FormatID );
  1181. if (pSect)
  1182. return pSect;
  1183. pSect = new CDrawCliPropertySection( FormatID ) ;
  1184. if (pSect)
  1185. AddSection( pSect );
  1186. return pSect;
  1187. }
  1188. void CDrawCliPropertySet::AddSection( CDrawCliPropertySection* pSect )
  1189. {
  1190. m_SectionList.AddTail( pSect );
  1191. m_PH.cSections++;
  1192. }
  1193. CDrawCliProperty* CDrawCliPropertySet::GetProperty( CLSID FormatID, DWORD dwPropID )
  1194. {
  1195. CDrawCliPropertySection* pSect = GetSection( FormatID );
  1196. if (pSect)
  1197. return pSect->GetProperty( dwPropID );
  1198. else
  1199. return NULL;
  1200. }
  1201. void CDrawCliPropertySet::AddProperty( CLSID FormatID, CDrawCliProperty* pProp )
  1202. {
  1203. CDrawCliPropertySection* pSect = GetSection( FormatID );
  1204. if (pSect)
  1205. pSect->AddProperty( pProp );
  1206. }
  1207. WORD CDrawCliPropertySet::GetByteOrder( void )
  1208. {   return m_PH.wByteOrder;  }
  1209. WORD CDrawCliPropertySet::GetFormatVersion( void )
  1210. {   return m_PH.wFormat;  }
  1211. void CDrawCliPropertySet::SetFormatVersion( WORD wFmtVersion )
  1212. {   m_PH.wFormat = wFmtVersion;  }
  1213. DWORD CDrawCliPropertySet::GetOSVersion( void )
  1214. {   return m_PH.dwOSVer;  }
  1215. void CDrawCliPropertySet::SetOSVersion( DWORD dwOSVer )
  1216. {   m_PH.dwOSVer = dwOSVer;  }
  1217. CLSID CDrawCliPropertySet::GetClassID( void )
  1218. {   return m_PH.clsID;  }
  1219. void CDrawCliPropertySet::SetClassID( CLSID clsID )
  1220. {   m_PH.clsID = clsID;  }
  1221. DWORD CDrawCliPropertySet::GetCount( void )
  1222. {   return WORD( m_SectionList.GetCount() ); }
  1223. CObList* CDrawCliPropertySet::GetList( void )
  1224. {   return &m_SectionList;  }
  1225. BOOL CDrawCliPropertySet::WriteToStream( IStream* pIStream )
  1226. {
  1227. LPSTREAM        pIStrFIDO;
  1228. FORMATIDOFFSET  fido;
  1229. ULONG           cb;
  1230. ULARGE_INTEGER  ulSeek;
  1231. LARGE_INTEGER   li;
  1232. // Write the Property List Header
  1233. m_PH.cSections = DWORD( m_SectionList.GetCount() );
  1234. pIStream->Write((LPVOID)&m_PH, sizeof(m_PH), &cb);
  1235. if (sizeof(m_PH) != cb)
  1236. {
  1237. TRACE0("Write of Property Set Header failed.n");
  1238. return FALSE;
  1239. }
  1240. if (m_SectionList.IsEmpty())
  1241. {
  1242. TRACE0("Warning: Wrote empty property set.n");
  1243. return TRUE;
  1244. }
  1245. // After the header is the list of Format ID/Offset pairs
  1246. // Since there is an ID/Offset pair for each section and we
  1247. // need to write the ID/Offset pair as we write each section
  1248. // we clone the stream and use the clone to access the
  1249. // table of ID/offset pairs (FIDO)...
  1250. //
  1251. pIStream->Clone( &pIStrFIDO );
  1252. // Now seek pIStream past the FIDO list
  1253. //
  1254. LISet32( li, m_PH.cSections * sizeof( FORMATIDOFFSET ) );
  1255. pIStream->Seek( li, STREAM_SEEK_CUR, &ulSeek);
  1256. // Write each section.
  1257. CDrawCliPropertySection*   pSect = NULL;
  1258. POSITION            pos = m_SectionList.GetHeadPosition();
  1259. while( pos != NULL )
  1260. {
  1261. // Get next element (note cast)
  1262. pSect = (CDrawCliPropertySection*)m_SectionList.GetNext( pos );
  1263. // Write it
  1264. if (!pSect->WriteToStream( pIStream ))
  1265. {
  1266. pIStrFIDO->Release();
  1267. return FALSE;
  1268. }
  1269. // Using our cloned stream write the Format ID / Offset pair
  1270. fido.formatID = pSect->m_FormatID;
  1271. fido.dwOffset = ulSeek.LowPart;
  1272. pIStrFIDO->Write((LPVOID)&fido, sizeof(fido), &cb);
  1273. if (sizeof(fido) != cb)
  1274. {
  1275. TRACE0("Write of 'fido' failed.n");
  1276. pIStrFIDO->Release();
  1277. return FALSE;
  1278. }
  1279. // Get the seek offset (for pIStream) after the write
  1280. LISet32( li, 0 );
  1281. pIStream->Seek( li, STREAM_SEEK_CUR, &ulSeek );
  1282. }
  1283. pIStrFIDO->Release();
  1284. return TRUE;
  1285. }
  1286. BOOL CDrawCliPropertySet::ReadFromStream( IStream* pIStream )
  1287. {
  1288. ULONG               cb;
  1289. FORMATIDOFFSET      fido;
  1290. ULONG               cSections;
  1291. LPSTREAM            pIStrFIDO;
  1292. CDrawCliPropertySection*   pSect;
  1293. LARGE_INTEGER       li;
  1294. LARGE_INTEGER       liPropSet;
  1295. // Save the stream position at which the property set starts.
  1296. LARGE_INTEGER liZero = {0,0};
  1297. pIStream->Seek( liZero, STREAM_SEEK_CUR, (ULARGE_INTEGER*)&liPropSet );
  1298. if (m_PH.cSections || !m_SectionList.IsEmpty())
  1299.  RemoveAll();
  1300. // The stream starts like this:
  1301. //  wByteOrder   wFmtVer   dwOSVer   clsID  cSections
  1302. // Which is nice, because our PROPHEADER is the same!
  1303. pIStream->Read( (LPVOID)&m_PH, sizeof( m_PH ), &cb );
  1304. if (cb != sizeof(m_PH))
  1305. return FALSE;
  1306. // Now we're pointing at the first of the FormatID/Offset pairs
  1307. // (FIDOs).   To get to each section we use a cloned stream
  1308. // to stay back and point at the FIDOs (pIStrFIDO).  We seek
  1309. // pIStream to each of the sections, creating CProperitySection
  1310. // and so forth as we go...
  1311. //
  1312. pIStream->Clone( &pIStrFIDO );
  1313. cSections = m_PH.cSections;
  1314. while (cSections--)
  1315. {
  1316. pIStrFIDO->Read( (LPVOID)&fido, sizeof( fido ), &cb );
  1317. if (cb != sizeof(fido))
  1318. {
  1319. pIStrFIDO->Release();
  1320. return FALSE;
  1321. }
  1322. // Do a seek from the beginning of the property set.
  1323. LISet32( li, fido.dwOffset );
  1324. pIStream->Seek( liPropSet, STREAM_SEEK_SET, NULL );
  1325. pIStream->Seek( li, STREAM_SEEK_CUR, NULL );
  1326. // Now pIStream is at the type/value pair
  1327. pSect = new CDrawCliPropertySection;
  1328. pSect->SetFormatID( fido.formatID );
  1329. pSect->ReadFromStream( pIStream, liPropSet );
  1330. m_SectionList.AddTail( pSect );
  1331. }
  1332. pIStrFIDO->Release();
  1333. return TRUE;
  1334. }
  1335. /////////////////////////////////////////////////////////////////////////////
  1336. // Force any extra compiler-generated code into AFX_INIT_SEG
  1337. #ifdef AFX_INIT_SEG
  1338. #pragma code_seg(AFX_INIT_SEG)
  1339. #endif