olepset.cpp 38 KB

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