ctlpset.cpp 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118
  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. #ifdef AFXCTL_PROP_SEG
  12. #pragma code_seg(AFXCTL_PROP_SEG)
  13. #endif
  14. #ifdef _DEBUG
  15. #undef THIS_FILE
  16. static char THIS_FILE[] = __FILE__;
  17. #endif
  18. #define new DEBUG_NEW
  19. #define OSTYPE 2 // Win32
  20. AFX_STATIC_DATA LARGE_INTEGER _afxLargeZero = { 0,0 };
  21. // Old class IDs for font and picture types
  22. AFX_STATIC_DATA const CLSID _afx_CLSID_StdFont_V1 =
  23. { 0xfb8f0823,0x0164,0x101b, { 0x84,0xed,0x08,0x00,0x2b,0x2e,0xc7,0x13 } };
  24. AFX_STATIC_DATA const CLSID _afx_CLSID_StdPicture_V1 =
  25. { 0xfb8f0824,0x0164,0x101b, { 0x84,0xed,0x08,0x00,0x2b,0x2e,0xc7,0x13 } };
  26. LPSTREAM AFXAPI _AfxCreateMemoryStream()
  27. {
  28. LPSTREAM lpStream = NULL;
  29. // Create a stream object on a memory block.
  30. HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE, 0);
  31. if (hGlobal != NULL)
  32. {
  33. if (FAILED(CreateStreamOnHGlobal(hGlobal, TRUE, &lpStream)))
  34. {
  35. TRACE0("CreateStreamOnHGlobal failed.\n");
  36. GlobalFree(hGlobal);
  37. return NULL;
  38. }
  39. ASSERT_POINTER(lpStream, IStream);
  40. }
  41. else
  42. {
  43. TRACE0("Failed to allocate memory for stream.\n");
  44. return NULL;
  45. }
  46. return lpStream;
  47. }
  48. BOOL COleControl::GetPropsetData(LPFORMATETC lpFormatEtc,
  49. LPSTGMEDIUM lpStgMedium, REFCLSID fmtid)
  50. {
  51. ASSERT_VALID(this);
  52. ASSERT(AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  53. ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));
  54. BOOL bGetDataHere = (lpStgMedium->tymed != TYMED_NULL);
  55. // Allow IStream or IStorage as the storage medium.
  56. if (!(lpFormatEtc->tymed & (TYMED_ISTREAM|TYMED_ISTORAGE)))
  57. {
  58. TRACE0("Propset only supported for stream or storage.\n");
  59. return FALSE;
  60. }
  61. LPSTORAGE lpStorage = NULL;
  62. LPSTREAM lpStream = NULL;
  63. if (lpFormatEtc->tymed & TYMED_ISTORAGE)
  64. {
  65. // Caller wants propset data in a storage object.
  66. if (bGetDataHere)
  67. {
  68. // Use the caller-supplied storage object.
  69. lpStorage = lpStgMedium->pstg;
  70. }
  71. else
  72. {
  73. // Create a storage object on a memory ILockBytes implementation.
  74. LPLOCKBYTES lpLockBytes = NULL;
  75. if (FAILED(CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes)))
  76. {
  77. TRACE0("CreateILockBytesOnHGlobal failed.\n");
  78. return FALSE;
  79. }
  80. ASSERT_POINTER(lpLockBytes, ILockBytes);
  81. if (FAILED(StgCreateDocfileOnILockBytes(lpLockBytes,
  82. STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0,
  83. &lpStorage)))
  84. {
  85. TRACE0("StgCreateDocfileOnILockBytes failed.\n");
  86. lpLockBytes->Release();
  87. return FALSE;
  88. }
  89. // Docfile now has reference to ILockBytes, so release ours.
  90. lpLockBytes->Release();
  91. }
  92. ASSERT_POINTER(lpStorage, IStorage);
  93. // Create a stream within the storage.
  94. if (FAILED(lpStorage->CreateStream(OLESTR("Contents"),
  95. STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, 0,
  96. &lpStream)))
  97. {
  98. TRACE0("IStorage::CreateStream failed.\n");
  99. if (!bGetDataHere)
  100. lpStorage->Release();
  101. return FALSE;
  102. }
  103. }
  104. else
  105. {
  106. // Caller wants propset data in a stream object.
  107. if (bGetDataHere)
  108. {
  109. // Use the caller-supplied stream object
  110. lpStream = lpStgMedium->pstm;
  111. }
  112. else
  113. {
  114. lpStream = _AfxCreateMemoryStream();
  115. if (lpStream == NULL)
  116. return FALSE;
  117. }
  118. }
  119. ASSERT_POINTER(lpStream, IStream);
  120. // Create the property set.
  121. CLSID clsid;
  122. GetClassID(&clsid);
  123. CPropertySet pset(clsid);
  124. pset.SetOSVersion(MAKELONG(LOWORD(GetVersion()), OSTYPE));
  125. CPropertySection* ppsec = pset.AddSection(fmtid);
  126. if (ppsec == NULL)
  127. {
  128. TRACE0("CPropertySet::AddSection failed.\n");
  129. lpStream->Release();
  130. lpStorage->Release();
  131. return FALSE;
  132. }
  133. // Set the name, based on the ambient display name (from the container).
  134. ppsec->SetSectionName(AmbientDisplayName());
  135. CPropsetPropExchange propx(*ppsec, lpStorage, FALSE);
  136. BOOL bPropExchange = FALSE;
  137. TRY
  138. {
  139. DoPropExchange(&propx);
  140. bPropExchange = TRUE;
  141. }
  142. END_TRY
  143. if (!bPropExchange)
  144. {
  145. TRACE0("DoPropExchange failed.\n");
  146. lpStream->Release();
  147. lpStorage->Release();
  148. return FALSE;
  149. }
  150. // Store the property set in the stream.
  151. if (FAILED(pset.WriteToStream(lpStream)))
  152. {
  153. TRACE0("CPropertySet::WriteToStream failed.\n");
  154. lpStream->Release();
  155. lpStorage->Release();
  156. return FALSE;
  157. }
  158. // Return the property set in the requested medium.
  159. if (lpFormatEtc->tymed & TYMED_ISTORAGE)
  160. {
  161. // Return as a storage object.
  162. ASSERT_POINTER(lpStorage, IStorage);
  163. lpStream->Release();
  164. lpStgMedium->pstg = lpStorage;
  165. lpStgMedium->tymed = TYMED_ISTORAGE;
  166. lpStgMedium->pUnkForRelease = NULL;
  167. }
  168. else
  169. {
  170. // Return as a stream.
  171. ASSERT_POINTER(lpStream, IStream);
  172. lpStgMedium->pstm = lpStream;
  173. lpStgMedium->tymed = TYMED_ISTREAM;
  174. lpStgMedium->pUnkForRelease = NULL;
  175. }
  176. return TRUE;
  177. }
  178. BOOL COleControl::SetPropsetData(LPFORMATETC lpFormatEtc,
  179. LPSTGMEDIUM lpStgMedium, REFCLSID fmtid)
  180. {
  181. UNUSED(lpFormatEtc); // unused in release builds
  182. ASSERT_VALID(this);
  183. ASSERT(AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  184. ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));
  185. // Get the stream that contains the property set.
  186. LPSTORAGE lpStorage = NULL;
  187. LPSTREAM lpStream = NULL;
  188. switch (lpStgMedium->tymed)
  189. {
  190. case TYMED_ISTORAGE:
  191. {
  192. lpStorage = lpStgMedium->pstg;
  193. ASSERT_POINTER(lpStorage, IStorage);
  194. if (FAILED(lpStorage->OpenStream(OLESTR("Contents"), 0,
  195. STGM_SHARE_EXCLUSIVE|STGM_READ, 0, &lpStream)))
  196. {
  197. TRACE0("Failed to open content stream.\n");
  198. return FALSE;
  199. }
  200. }
  201. break;
  202. case TYMED_ISTREAM:
  203. lpStorage = NULL;
  204. lpStream = lpStgMedium->pstm;
  205. break;
  206. default:
  207. TRACE0("Propset only supported for stream or storage.\n");
  208. return FALSE;
  209. }
  210. ASSERT_POINTER(lpStream, IStream);
  211. // Read the property set from the stream.
  212. CPropertySet pset;
  213. if (!pset.ReadFromStream(lpStream))
  214. {
  215. TRACE0("CPropertySet::ReadFromStream failed.\n");
  216. return FALSE;
  217. }
  218. CPropertySection* ppsec = pset.GetSection(fmtid);
  219. if (ppsec == NULL)
  220. {
  221. TRACE0("CLSID_PersistPropset section not found in property set.\n");
  222. return FALSE;
  223. }
  224. // Detect whether we're converting a VBX
  225. m_bConvertVBX = (BYTE)IsEqualGUID(fmtid, CLSID_ConvertVBX);
  226. // Parse the property set.
  227. CPropsetPropExchange propx(*ppsec, lpStorage, TRUE);
  228. BOOL bPropExchange = FALSE;
  229. TRY
  230. {
  231. DoPropExchange(&propx);
  232. bPropExchange = TRUE;
  233. }
  234. END_TRY
  235. // Properties have probably changed
  236. BoundPropertyChanged(DISPID_UNKNOWN);
  237. InvalidateControl();
  238. m_bConvertVBX = FALSE;
  239. // Clear the modified flag.
  240. m_bModified = FALSE;
  241. // Unless IOleObject::SetClientSite is called after this, we can
  242. // count on ambient properties being available while loading.
  243. m_bCountOnAmbients = TRUE;
  244. // Properties have been initialized
  245. m_bInitialized = TRUE;
  246. // Cleanup.
  247. if (lpStorage != NULL) // If we called OpenStream(), release now.
  248. lpStream->Release();
  249. BoundPropertyChanged(DISPID_UNKNOWN);
  250. return bPropExchange;
  251. }
  252. CPropsetPropExchange::CPropsetPropExchange(CPropertySection& psec,
  253. LPSTORAGE lpStorage, BOOL bLoading) :
  254. m_psec(psec),
  255. m_lpStorage(lpStorage),
  256. m_dwPropID(255)
  257. {
  258. ASSERT_POINTER(&psec, CPropertySection);
  259. ASSERT_NULL_OR_POINTER(lpStorage, IStorage);
  260. m_bLoading = bLoading;
  261. }
  262. AFX_STATIC size_t AFXAPI _AfxGetSizeOfVarType(VARTYPE vt)
  263. {
  264. switch (vt)
  265. {
  266. case VT_I2:
  267. case VT_BOOL:
  268. return 2;
  269. case VT_I4:
  270. case VT_R4:
  271. return 4;
  272. case VT_R8:
  273. return 8;
  274. case VT_CY:
  275. return sizeof(CURRENCY);
  276. case VT_BSTR:
  277. return sizeof(BSTR);
  278. }
  279. return 0;
  280. }
  281. BOOL AFXAPI _AfxCoerceNumber(void* pvDst, VARTYPE vtDst, void* pvSrc, VARTYPE vtSrc)
  282. {
  283. // Check size of source.
  284. size_t cbSrc = _AfxGetSizeOfVarType(vtSrc);
  285. if (cbSrc == 0)
  286. return FALSE;
  287. // If source and destination are same type, just copy.
  288. if (vtSrc == vtDst)
  289. {
  290. memcpy(pvDst, pvSrc, cbSrc);
  291. return TRUE;
  292. }
  293. // Check size of destination.
  294. size_t cbDst = _AfxGetSizeOfVarType(vtDst);
  295. if (cbDst == 0)
  296. return FALSE;
  297. // Initialize variant for coercion.
  298. VARIANTARG var;
  299. V_VT(&var) = vtSrc;
  300. memcpy((void*)&V_NONE(&var), pvSrc, cbSrc);
  301. // Do the coercion.
  302. if (FAILED(VariantChangeType(&var, &var, 0, vtDst)))
  303. return FALSE;
  304. // Copy result to destination.
  305. memcpy(pvDst, (void*)&V_NONE(&var), cbDst);
  306. return TRUE;
  307. }
  308. BOOL AFXAPI _AfxIsSamePropValue(VARTYPE vtProp, const void* pv1, const void* pv2)
  309. {
  310. if (pv1 == pv2)
  311. return TRUE;
  312. if ((pv1 == NULL) || (pv2 == NULL))
  313. return FALSE;
  314. BOOL bSame = FALSE;
  315. switch (vtProp)
  316. {
  317. case VT_BSTR:
  318. bSame = ((CString*)pv1)->Compare(*(CString*)pv2) == 0;
  319. break;
  320. case VT_LPSTR:
  321. bSame = ((CString*)pv1)->Compare((LPCTSTR)pv2) == 0;
  322. break;
  323. case VT_BOOL:
  324. case VT_I2:
  325. case VT_I4:
  326. case VT_CY:
  327. case VT_R4:
  328. case VT_R8:
  329. bSame = memcmp(pv1, pv2, _AfxGetSizeOfVarType(vtProp)) == 0;
  330. break;
  331. }
  332. return bSame;
  333. }
  334. BOOL CPropsetPropExchange::ExchangeProp(LPCTSTR pszPropName, VARTYPE vtProp,
  335. void* pvProp, const void* pvDefault)
  336. {
  337. USES_CONVERSION;
  338. ASSERT(AfxIsValidString(pszPropName));
  339. ASSERT(AfxIsValidAddress(pvProp, 1, FALSE));
  340. ASSERT((pvDefault == NULL) || AfxIsValidAddress(pvDefault, 1, FALSE));
  341. BOOL bSuccess = FALSE;
  342. if (m_bLoading)
  343. {
  344. DWORD dwPropID;
  345. LPVOID pvData;
  346. CProperty* pprop;
  347. if (m_psec.GetID(pszPropName, &dwPropID) &&
  348. ((pprop = m_psec.GetProperty(dwPropID)) != NULL) &&
  349. ((pvData = pprop->Get()) != NULL))
  350. {
  351. VARTYPE vtData = (VARTYPE)pprop->GetType();
  352. CString strTmp;
  353. #ifdef _UNICODE
  354. // Unicode is "native" format
  355. if ((vtData == VT_BSTR) || (vtData == VT_LPWSTR))
  356. #else
  357. // ANSI is "native" format
  358. if ((vtData == VT_BSTR) || (vtData == VT_LPSTR))
  359. #endif
  360. {
  361. strTmp = (LPCTSTR)pvData;
  362. }
  363. #ifdef _UNICODE
  364. else if (vtData == VT_LPSTR)
  365. {
  366. // Convert from ANSI to Unicode
  367. strTmp = (LPCSTR)pvData;
  368. }
  369. #else
  370. else if (vtData == VT_LPWSTR)
  371. {
  372. // Convert from Unicode to ANSI
  373. strTmp = (LPCWSTR)pvData;
  374. }
  375. #endif
  376. switch (vtProp)
  377. {
  378. case VT_LPSTR:
  379. case VT_BSTR:
  380. bSuccess = _AfxCopyPropValue(VT_BSTR, pvProp, &strTmp);
  381. break;
  382. case VT_BOOL:
  383. {
  384. short sProp;
  385. BSTR bstrTmp = NULL;
  386. if ((vtData == VT_BSTR) || (vtData == VT_LPSTR) ||
  387. (vtData == VT_LPWSTR))
  388. {
  389. bstrTmp = SysAllocString(T2COLE(strTmp));
  390. pvData = &bstrTmp;
  391. vtData = VT_BSTR;
  392. }
  393. bSuccess = _AfxCoerceNumber(&sProp, VT_BOOL, pvData,
  394. vtData);
  395. if (bstrTmp != NULL)
  396. SysFreeString(bstrTmp);
  397. if (bSuccess)
  398. {
  399. ASSERT((sProp == -1) || (sProp == 0));
  400. *(BOOL*)pvProp = !!sProp;
  401. }
  402. }
  403. break;
  404. case VT_I2:
  405. case VT_I4:
  406. case VT_CY:
  407. case VT_R4:
  408. case VT_R8:
  409. bSuccess = _AfxCoerceNumber(pvProp, vtProp, pvData, vtData);
  410. break;
  411. }
  412. }
  413. else
  414. {
  415. bSuccess = _AfxCopyPropValue(vtProp, pvProp, pvDefault);
  416. }
  417. }
  418. else
  419. {
  420. if (!_AfxIsSamePropValue(vtProp, pvProp, pvDefault))
  421. {
  422. ++m_dwPropID;
  423. LPVOID pvData = NULL;
  424. BOOL bData;
  425. switch (vtProp)
  426. {
  427. case VT_LPSTR:
  428. case VT_BSTR:
  429. pvData = (LPVOID)(LPCTSTR)*(CString*)pvProp;
  430. break;
  431. case VT_BOOL:
  432. // Convert boolean value to -1 or 0.
  433. bData = (*(BOOL*)pvProp) ? -1 : 0;
  434. pvData = &bData;
  435. break;
  436. case VT_I2:
  437. case VT_I4:
  438. case VT_CY:
  439. case VT_R4:
  440. case VT_R8:
  441. pvData = pvProp;
  442. break;
  443. }
  444. bSuccess = m_psec.SetName(m_dwPropID, pszPropName) &&
  445. m_psec.Set(m_dwPropID, pvData, vtProp);
  446. }
  447. else
  448. {
  449. bSuccess = TRUE;
  450. }
  451. }
  452. return bSuccess;
  453. }
  454. BOOL CPropsetPropExchange::ExchangeBlobProp(LPCTSTR pszPropName,
  455. HGLOBAL* phBlob, HGLOBAL hBlobDefault)
  456. {
  457. ASSERT(AfxIsValidString(pszPropName));
  458. ASSERT_POINTER(phBlob, HGLOBAL);
  459. BOOL bSuccess = FALSE;
  460. ULONG cb = 0;
  461. void* pvBlob = NULL;
  462. if (m_bLoading)
  463. {
  464. if (*phBlob != NULL)
  465. {
  466. GlobalFree(*phBlob);
  467. *phBlob = NULL;
  468. }
  469. DWORD dwPropID;
  470. LPVOID pvData;
  471. if (m_psec.GetID(pszPropName, &dwPropID) &&
  472. ((pvData = m_psec.Get(dwPropID)) != NULL))
  473. {
  474. // Copy count and blob data
  475. cb = *(ULONG*)pvData;
  476. if (cb > 0)
  477. {
  478. bSuccess = _AfxInitBlob(phBlob, pvData);
  479. }
  480. else
  481. {
  482. bSuccess = (cb == 0);
  483. }
  484. }
  485. if (!bSuccess)
  486. {
  487. // Failed. Use default values.
  488. if (hBlobDefault != NULL)
  489. _AfxCopyBlob(phBlob, hBlobDefault);
  490. bSuccess = TRUE;
  491. }
  492. }
  493. else
  494. {
  495. ++m_dwPropID;
  496. pvBlob = NULL;
  497. if (*phBlob != NULL)
  498. pvBlob = GlobalLock(*phBlob);
  499. ULONG lZero = 0;
  500. void* pvBlobSave = (pvBlob != NULL) ? pvBlob : &lZero;
  501. bSuccess = m_psec.SetName(m_dwPropID, pszPropName) &&
  502. m_psec.Set(m_dwPropID, pvBlobSave, VT_BLOB);
  503. if ((*phBlob != NULL) && (pvBlob != NULL))
  504. GlobalUnlock(*phBlob);
  505. }
  506. return bSuccess;
  507. }
  508. BOOL AFXAPI _AfxSaveStreamDataAsBlobProp(LPSTREAM pstm, CPropertySection& psec,
  509. DWORD dwPropID, DWORD dwType)
  510. {
  511. BOOL bSuccess = FALSE;
  512. ULARGE_INTEGER uliStart;
  513. ULARGE_INTEGER uliEnd;
  514. // Note: Stream length must fit in a DWORD.
  515. if (SUCCEEDED(pstm->Seek(_afxLargeZero, STREAM_SEEK_CUR, &uliStart)) &&
  516. SUCCEEDED(pstm->Seek(_afxLargeZero, STREAM_SEEK_END, &uliEnd)) &&
  517. SUCCEEDED(pstm->Seek(*(LARGE_INTEGER*)&uliStart, STREAM_SEEK_SET,
  518. NULL)))
  519. {
  520. DWORD cb = uliEnd.LowPart - uliStart.LowPart;
  521. HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE,
  522. cb + (DWORD)sizeof(cb));
  523. if (hGlobal != NULL)
  524. {
  525. LPBYTE pbData = (LPBYTE)GlobalLock(hGlobal);
  526. if (pbData != NULL)
  527. {
  528. *(DWORD*)pbData = cb;
  529. if (SUCCEEDED(pstm->Read(pbData + (DWORD)sizeof(DWORD), cb,
  530. NULL)))
  531. {
  532. bSuccess = psec.Set(dwPropID, pbData, dwType);
  533. }
  534. GlobalUnlock(hGlobal);
  535. }
  536. GlobalFree(hGlobal);
  537. }
  538. }
  539. return bSuccess;
  540. }
  541. BOOL AFXAPI _AfxInitStreamDataFromBlobProp(LPSTREAM pstm, CProperty* pprop)
  542. {
  543. BOOL bSuccess = FALSE;
  544. ULONG cb;
  545. BYTE* pbData = (BYTE*)(pprop->Get(&cb));
  546. if (pbData != NULL)
  547. {
  548. // Put the data into the stream, then seek back to start of data.
  549. LARGE_INTEGER liOffset;
  550. liOffset.LowPart = -(LONG)cb;
  551. liOffset.HighPart = -1;
  552. if (SUCCEEDED(pstm->Write(pbData + sizeof(ULONG), cb, NULL)) &&
  553. SUCCEEDED(pstm->Seek(liOffset, STREAM_SEEK_CUR, NULL)))
  554. {
  555. bSuccess = TRUE;
  556. }
  557. }
  558. return bSuccess;
  559. }
  560. AFX_STATIC_DATA const FONTDESC _afxFontDescHelv =
  561. { sizeof(FONTDESC), OLESTR("Helv"), FONTSIZE(12), FW_NORMAL,
  562. DEFAULT_CHARSET, FALSE, FALSE, FALSE };
  563. LPFONT AFXAPI _AfxCreateFontFromStream(LPSTREAM pstm)
  564. {
  565. BOOL bSuccess = FALSE;
  566. LPFONT pFont = NULL;
  567. LPPERSISTSTREAM pPersStm = NULL;
  568. CLSID clsid;
  569. if (SUCCEEDED(pstm->Read(&clsid, sizeof(CLSID), NULL)))
  570. {
  571. HRESULT hr;
  572. if (IsEqualCLSID(clsid, CLSID_StdFont) ||
  573. IsEqualCLSID(clsid, _afx_CLSID_StdFont_V1))
  574. {
  575. // We know this kind of font; create it using the API.
  576. hr = ::OleCreateFontIndirect((LPFONTDESC)&_afxFontDescHelv, IID_IFont,
  577. (LPVOID*)&pFont);
  578. }
  579. else
  580. {
  581. // Some other implementation of IFont.
  582. hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IFont,
  583. (LPVOID*)&pFont);
  584. }
  585. if (SUCCEEDED(hr))
  586. {
  587. // Successfully created font, now get its IPersistStream interface.
  588. ASSERT_POINTER(pFont, IFont);
  589. if (SUCCEEDED(pFont->QueryInterface(IID_IPersistStream,
  590. (LPVOID*)&pPersStm)))
  591. {
  592. ASSERT_POINTER(pPersStm, IPersistStream);
  593. }
  594. }
  595. if (pPersStm != NULL)
  596. {
  597. // Load the font.
  598. ASSERT_POINTER(pFont, IFont);
  599. bSuccess = SUCCEEDED(pPersStm->Load(pstm));
  600. pPersStm->Release();
  601. }
  602. }
  603. // If we failed for any reason, clean up the font.
  604. if (!bSuccess && pFont != NULL)
  605. {
  606. pFont->Release();
  607. pFont = NULL;
  608. }
  609. return pFont;
  610. }
  611. BOOL AFXAPI _AfxLoadObjectFromStreamedPropset(LPUNKNOWN lpUnknown, LPSTREAM lpStream)
  612. {
  613. ASSERT_POINTER(lpUnknown, IUnknown);
  614. ASSERT_POINTER(lpStream, IStream);
  615. BOOL bSuccess = FALSE;
  616. LPDATAOBJECT pDataObj = NULL;
  617. if (SUCCEEDED(lpUnknown->QueryInterface(IID_IDataObject,
  618. (LPVOID*)&pDataObj)))
  619. {
  620. ASSERT_POINTER(pDataObj, IDataObject);
  621. // Set the persistent propset format on the object.
  622. FORMATETC formatEtc;
  623. STGMEDIUM stgMedium;
  624. formatEtc.cfFormat = _AfxGetClipboardFormatPersistPropset();
  625. formatEtc.ptd = NULL;
  626. formatEtc.dwAspect = DVASPECT_CONTENT;
  627. formatEtc.lindex = -1;
  628. formatEtc.tymed = TYMED_ISTREAM;
  629. stgMedium.tymed = TYMED_ISTREAM;
  630. stgMedium.pstm = lpStream;
  631. stgMedium.pUnkForRelease = NULL;
  632. bSuccess = SUCCEEDED(pDataObj->SetData(&formatEtc, &stgMedium, FALSE));
  633. pDataObj->Release();
  634. }
  635. return bSuccess;
  636. }
  637. BOOL AFXAPI _AfxGetClassIDFromStreamedPropset(LPCLSID lpClsid, LPSTREAM lpStream)
  638. {
  639. BOOL bSuccess = FALSE;
  640. ULARGE_INTEGER uliSave;
  641. LARGE_INTEGER liClsidOffset;
  642. LISet32(liClsidOffset, 8);
  643. if (SUCCEEDED(lpStream->Seek(_afxLargeZero, STREAM_SEEK_CUR, &uliSave)))
  644. {
  645. if (SUCCEEDED(lpStream->Seek(liClsidOffset, STREAM_SEEK_CUR, NULL)) &&
  646. SUCCEEDED(lpStream->Read(lpClsid, sizeof(CLSID), NULL)))
  647. {
  648. bSuccess = TRUE;
  649. }
  650. lpStream->Seek(*(LARGE_INTEGER*)&uliSave, STREAM_SEEK_SET, NULL);
  651. }
  652. return bSuccess;
  653. }
  654. LPUNKNOWN AFXAPI _AfxCreateObjectFromStreamedPropset(LPSTREAM lpStream, REFGUID iid)
  655. {
  656. LPUNKNOWN pUnk = NULL;
  657. CLSID clsid;
  658. if (_AfxGetClassIDFromStreamedPropset(&clsid, lpStream))
  659. {
  660. // Special case: we know how to create font objects
  661. if (IsEqualCLSID(clsid, CLSID_StdFont) ||
  662. IsEqualCLSID(clsid, _afx_CLSID_StdFont_V1))
  663. {
  664. if (FAILED(::OleCreateFontIndirect((LPFONTDESC)&_afxFontDescHelv, iid,
  665. (LPVOID*)&pUnk)))
  666. {
  667. pUnk = NULL;
  668. }
  669. }
  670. // Special case: we know how to create picture objects
  671. else if (IsEqualCLSID(clsid, CLSID_StdPicture) ||
  672. IsEqualCLSID(clsid, _afx_CLSID_StdPicture_V1))
  673. {
  674. if (FAILED(::OleCreatePictureIndirect(NULL, iid, FALSE,
  675. (LPVOID*)&pUnk)))
  676. {
  677. pUnk = NULL;
  678. }
  679. }
  680. // General case: create the object
  681. else if (FAILED(CoCreateInstance(clsid, NULL,
  682. CLSCTX_INPROC_SERVER, iid, (LPVOID*)&pUnk)))
  683. {
  684. pUnk = NULL;
  685. }
  686. if (pUnk != NULL)
  687. {
  688. if (!_AfxLoadObjectFromStreamedPropset(pUnk, lpStream))
  689. {
  690. RELEASE(pUnk);
  691. pUnk = NULL;
  692. }
  693. }
  694. }
  695. return pUnk;
  696. }
  697. LPSTREAM AFXAPI _AfxLoadStreamFromPropset(CPropertySection& psec, LPCTSTR pszPropName,
  698. DWORD& vtType)
  699. {
  700. ASSERT(AfxIsValidString(pszPropName));
  701. vtType = VT_EMPTY;
  702. DWORD dwPropID;
  703. CProperty* pprop = NULL;
  704. LPSTREAM pstm = NULL;
  705. if (psec.GetID(pszPropName, &dwPropID) &&
  706. ((pprop = psec.GetProperty(dwPropID)) != NULL))
  707. {
  708. vtType = pprop->GetType();
  709. if ((vtType == VT_BLOB) || (vtType == VT_BLOB_PROPSET))
  710. {
  711. pstm = _AfxCreateMemoryStream();
  712. if (pstm != NULL)
  713. {
  714. if (!_AfxInitStreamDataFromBlobProp(pstm, pprop))
  715. {
  716. pstm->Release();
  717. pstm = NULL;
  718. }
  719. }
  720. }
  721. }
  722. return pstm;
  723. }
  724. BOOL AFXAPI _AfxSaveObjectInPropset(LPUNKNOWN pUnk, CPropertySection& psec,
  725. DWORD dwPropID)
  726. {
  727. if (pUnk == NULL)
  728. return FALSE;
  729. ASSERT_POINTER(pUnk, IUnknown);
  730. BOOL bSuccess = FALSE;
  731. LPDATAOBJECT pDataObj;
  732. if (SUCCEEDED(pUnk->QueryInterface(IID_IDataObject,
  733. (LPVOID*)&pDataObj)))
  734. {
  735. // Get the persistent propset format from object.
  736. FORMATETC formatEtc;
  737. STGMEDIUM stgMedium;
  738. formatEtc.cfFormat = _AfxGetClipboardFormatPersistPropset();
  739. formatEtc.ptd = NULL;
  740. formatEtc.dwAspect = DVASPECT_CONTENT;
  741. formatEtc.lindex = -1;
  742. formatEtc.tymed = TYMED_ISTREAM;
  743. stgMedium.tymed = TYMED_NULL;
  744. stgMedium.pUnkForRelease = NULL;
  745. if (SUCCEEDED(pDataObj->GetData(&formatEtc, &stgMedium)))
  746. {
  747. if (stgMedium.tymed == TYMED_ISTREAM)
  748. {
  749. LPSTREAM pstm = stgMedium.pstm;
  750. // Seek to start of stream.
  751. if (SUCCEEDED(pstm->Seek(_afxLargeZero, STREAM_SEEK_SET, NULL)))
  752. {
  753. // Create a "blobbed" propset from the stream
  754. bSuccess = _AfxSaveStreamDataAsBlobProp(stgMedium.pstm,
  755. psec, dwPropID, VT_BLOB_PROPSET);
  756. }
  757. }
  758. // Cleanup
  759. ReleaseStgMedium(&stgMedium);
  760. }
  761. pDataObj->Release();
  762. }
  763. LPPERSISTSTREAM pPersStm = NULL;
  764. if ((!bSuccess) &&
  765. SUCCEEDED(pUnk->QueryInterface(IID_IPersistStream,
  766. (LPVOID*)&pPersStm)))
  767. {
  768. // Get the object to save itself into a stream, then store that
  769. // streamed data as a blob.
  770. ASSERT_POINTER(pPersStm, IPersistStream);
  771. LPSTREAM pstm = _AfxCreateMemoryStream();
  772. if (pstm != NULL)
  773. {
  774. if (SUCCEEDED(::OleSaveToStream(pPersStm, pstm)) &&
  775. SUCCEEDED(pstm->Seek(_afxLargeZero, STREAM_SEEK_SET, NULL)))
  776. {
  777. bSuccess = _AfxSaveStreamDataAsBlobProp(pstm, psec,
  778. dwPropID, VT_BLOB);
  779. }
  780. pstm->Release();
  781. }
  782. pPersStm->Release();
  783. }
  784. return bSuccess;
  785. }
  786. BOOL CPropsetPropExchange::ExchangePersistentProp(LPCTSTR pszPropName,
  787. LPUNKNOWN* ppUnk, REFIID iid, LPUNKNOWN pUnkDefault)
  788. {
  789. ASSERT(AfxIsValidString(pszPropName));
  790. ASSERT_POINTER(ppUnk, LPUNKNOWN);
  791. ASSERT_NULL_OR_POINTER(pUnkDefault, IUnknown);
  792. BOOL bSuccess = FALSE;
  793. if (m_bLoading)
  794. {
  795. RELEASE(*ppUnk);
  796. *ppUnk = NULL;
  797. DWORD vtType;
  798. LPSTREAM pstm = _AfxLoadStreamFromPropset(m_psec, pszPropName, vtType);
  799. if (pstm != NULL)
  800. {
  801. CLSID clsid;
  802. switch(vtType)
  803. {
  804. case VT_BLOB:
  805. if (_AfxPeekAtClassIDInStream(pstm, &clsid))
  806. {
  807. if (IsEqualCLSID(clsid, CLSID_StdPicture) ||
  808. IsEqualCLSID(clsid, _afx_CLSID_StdPicture_V1))
  809. {
  810. // Special case: load the picture directly.
  811. bSuccess = SUCCEEDED(::ReadClassStm(pstm, &clsid)) &&
  812. SUCCEEDED(::OleLoadPicture(pstm, 0, FALSE, iid,
  813. (LPVOID*)ppUnk));
  814. }
  815. else
  816. {
  817. // Load the object.
  818. bSuccess = SUCCEEDED(::OleLoadFromStream(pstm, iid,
  819. (LPVOID*)ppUnk));
  820. }
  821. }
  822. break;
  823. case VT_BLOB_PROPSET:
  824. *ppUnk = _AfxCreateObjectFromStreamedPropset(pstm, iid);
  825. break;
  826. default:
  827. break;
  828. }
  829. pstm->Release();
  830. }
  831. if (!bSuccess && (pUnkDefault != NULL))
  832. {
  833. bSuccess = SUCCEEDED(pUnkDefault->QueryInterface(iid,
  834. (LPVOID*)ppUnk));
  835. }
  836. }
  837. else
  838. {
  839. if ((*ppUnk == NULL) ||
  840. _AfxIsSameUnknownObject(iid, *ppUnk, pUnkDefault))
  841. {
  842. bSuccess = TRUE;
  843. }
  844. else
  845. {
  846. ++m_dwPropID;
  847. bSuccess = m_psec.SetName(m_dwPropID, pszPropName) &&
  848. _AfxSaveObjectInPropset(*ppUnk, m_psec, m_dwPropID);
  849. }
  850. }
  851. return bSuccess;
  852. }
  853. BOOL CPropsetPropExchange::ExchangeFontProp(LPCTSTR pszPropName,
  854. CFontHolder& font, const FONTDESC* pFontDesc,
  855. LPFONTDISP pFontDispAmbient)
  856. {
  857. ASSERT(AfxIsValidString(pszPropName));
  858. ASSERT_POINTER(&font, CFontHolder);
  859. ASSERT_NULL_OR_POINTER(pFontDesc, FONTDESC);
  860. ASSERT_NULL_OR_POINTER(pFontDispAmbient, IFontDisp);
  861. BOOL bSuccess = FALSE;
  862. if (m_bLoading)
  863. {
  864. DWORD vtType;
  865. LPSTREAM pstm = _AfxLoadStreamFromPropset(m_psec, pszPropName, vtType);
  866. if (pstm != NULL)
  867. {
  868. LPFONT pFont;
  869. switch(vtType)
  870. {
  871. case VT_BLOB:
  872. pFont = _AfxCreateFontFromStream(pstm);
  873. break;
  874. case VT_BLOB_PROPSET:
  875. pFont = (LPFONT)_AfxCreateObjectFromStreamedPropset(pstm,
  876. IID_IFont);
  877. break;
  878. default:
  879. pFont = NULL;
  880. }
  881. if (pFont != NULL)
  882. {
  883. font.SetFont(pFont);
  884. bSuccess = TRUE;
  885. }
  886. pstm->Release();
  887. }
  888. if (!bSuccess)
  889. {
  890. // Initialize font to its default state
  891. font.InitializeFont(pFontDesc, pFontDispAmbient);
  892. }
  893. }
  894. else
  895. {
  896. if ((font.m_pFont == NULL) ||
  897. _AfxIsSameFont(font, pFontDesc, pFontDispAmbient))
  898. {
  899. bSuccess = TRUE;
  900. }
  901. else
  902. {
  903. ++m_dwPropID;
  904. bSuccess = m_psec.SetName(m_dwPropID, pszPropName) &&
  905. _AfxSaveObjectInPropset(font.m_pFont, m_psec, m_dwPropID);
  906. }
  907. }
  908. return bSuccess;
  909. }
  910. /////////////////////////////////////////////////////////////////////////////
  911. // Force any extra compiler-generated code into AFX_INIT_SEG
  912. #ifdef AFX_INIT_SEG
  913. #pragma code_seg(AFX_INIT_SEG)
  914. #endif