Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5828 lines
156 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: ostm2stg.cpp
  7. //
  8. // Contents: OLE 1 - OLE 2 Stream/IStorage Interoperatbility
  9. //
  10. // Functions: Implements API functions:
  11. // OleConvertOLESTREAMToIStorage
  12. // OleConvertIStorageToOLESTREAM
  13. // OleConvertOLESTREAMToIStorageEx
  14. // OleConvertIStorageToOLESTREAMEx
  15. //
  16. //
  17. // History: dd-mmm-yy Author Comment
  18. // 03-Feb-92 jasonful original version
  19. // 08-Aug-93 srinik added Ex functions
  20. // 12-Feb-94 davepl 32-bit port
  21. //
  22. //--------------------------------------------------------------------------
  23. #include <le2int.h>
  24. #include "ostm2stg.h"
  25. #include <ctype.h>
  26. #include <limits.h>
  27. #include <string.h>
  28. #include <ole1cls.h>
  29. ASSERTDATA
  30. // We need a ptr value which will indicate that the associated handle
  31. // is a metafile handle, and therefore cannot be cleaned up as if
  32. // it were a normal global memory handle
  33. #define METADATAPTR ((void *) -1)
  34. // This fn is not prototyped in any include file, since it was static
  35. // to its file. Need to add the prototype to a common include file.
  36. HRESULT STDAPICALLTYPE CreateOle1FileMoniker(LPWSTR,REFCLSID,LPMONIKER FAR*);
  37. // This is defined in the new privstm.cpp; must be added to an include file.
  38. STDAPI ReadFmtProgIdStg ( IStorage * pstg, LPOLESTR * pszProgID );
  39. FARINTERNAL wWriteFmtUserType (LPSTORAGE, REFCLSID);
  40. //+-------------------------------------------------------------------------
  41. //
  42. // Member: CGenericObject::CGenericObject
  43. //
  44. // Synopsis: Constructor for CGenericObject class
  45. //
  46. // Effects: Initializes all child pointers to NULL and sets
  47. // flags to FALSE
  48. //
  49. // History: dd-mmm-yy Author Comment
  50. // 14-Feb-94 davepl Cleanup and document
  51. //
  52. // Notes:
  53. //
  54. //--------------------------------------------------------------------------
  55. CGenericObject::CGenericObject(void)
  56. {
  57. m_ppres = NULL; // Presentation data
  58. m_fLink = FALSE; // Flag: Linked (T) or Embedded (F)
  59. m_fStatic = FALSE; // Flag: Static object
  60. m_fNoBlankPres = FALSE; // Flag: do not want a blank presentation
  61. m_szTopic = NULL; // Topic string for this object
  62. m_szItem = NULL; // Item (file) string for this object
  63. }
  64. //+-------------------------------------------------------------------------
  65. //
  66. // Member: CGenericObject::~CGenericObject
  67. //
  68. // Synopsis: Desctuctor for CGenericObject class
  69. //
  70. // Effects: Removes children then self
  71. //
  72. // History: dd-mmm-yy Author Comment
  73. // 12-Aug-94 alexgo check for NULL before delete
  74. // 14-Feb-94 davepl Cleanup and document
  75. //
  76. // Notes: As much as I hated to do it, some of these strings
  77. // have to be freed with PubMemFree because they are
  78. // allocated by UtDupString, which allocates public memory.
  79. //
  80. //--------------------------------------------------------------------------
  81. CGenericObject::~CGenericObject (void)
  82. {
  83. if( m_ppres )
  84. {
  85. delete m_ppres; // Presentation data
  86. }
  87. if( m_szTopic )
  88. {
  89. PubMemFree(m_szTopic); // Topic string
  90. }
  91. if( m_szItem )
  92. {
  93. PubMemFree(m_szItem); // Item string
  94. }
  95. }
  96. //+-------------------------------------------------------------------------
  97. //
  98. // Member: CData::CData
  99. //
  100. // Synopsis: Constructor for a simple class which holds a piece of
  101. // memory.
  102. //
  103. // Effects: Clears size, flags, and pointer
  104. //
  105. // History: dd-mmm-yy Author Comment
  106. //
  107. // Notes: 14-Feb-94 davepl Cleanup and document
  108. //
  109. //--------------------------------------------------------------------------
  110. CData::CData (void)
  111. {
  112. m_cbSize = 0; // Count, in bytes, of data size
  113. m_h = NULL; // Memory handke
  114. m_pv= NULL; // Memory pointer
  115. m_fNoFree = FALSE; // Flag: Should memory be freed in destructor
  116. }
  117. //+-------------------------------------------------------------------------
  118. //
  119. // Member: CData::~CData
  120. //
  121. // Synopsis: Destructor for simple data class
  122. //
  123. // Effects: Unlocks and frees memory if m_fNoFree is not set
  124. //
  125. // History: dd-mmm-yy Author Comment
  126. // 14-Feb-94 davepl Cleanup and document
  127. //
  128. // Notes: If a metafile handle is stored in the handle, the
  129. // pointer will be marked with a special value, indicating
  130. // that we must DeleteMetafile, not GlobalFree the handle.
  131. //
  132. //--------------------------------------------------------------------------
  133. CData::~CData (void)
  134. {
  135. if (m_h) // Do we have a handle?
  136. {
  137. if (m_pv == METADATAPTR)
  138. {
  139. LEVERIFY(DeleteMetaFile((HMETAFILE) m_h));
  140. }
  141. else
  142. {
  143. GlobalUnlock (m_h); // Dec lock count
  144. if (!m_fNoFree) // Free this memory if we
  145. { // have been flagged to do so
  146. LEVERIFY(0==GlobalFree (m_h));
  147. }
  148. }
  149. }
  150. }
  151. //+-------------------------------------------------------------------------
  152. //
  153. // Member: CFormat::CFormat
  154. //
  155. // Synopsis: CFormat class constructor
  156. //
  157. // Effects: Initializes format tag and clipboard format
  158. //
  159. // History: dd-mmm-yy Author Comment
  160. //
  161. // Notes: 14-Feb-94 davepl Cleanup and document
  162. //
  163. //--------------------------------------------------------------------------
  164. CFormat::CFormat (void)
  165. {
  166. m_ftag = ftagNone; // Format tag (string, clipformat, or none)
  167. m_cf = 0; // Clipboard format
  168. }
  169. //+-------------------------------------------------------------------------
  170. //
  171. // Member: CClass::CClass
  172. //
  173. // Synopsis: CClass constructor
  174. //
  175. // Effects: sets class ID and class ID string to NULL
  176. //
  177. // History: dd-mmm-yy Author Comment
  178. //
  179. // Notes:
  180. //
  181. //--------------------------------------------------------------------------
  182. CClass::CClass (void)
  183. {
  184. m_szClsid = NULL;
  185. m_clsid = CLSID_NULL;
  186. }
  187. //+-------------------------------------------------------------------------
  188. //
  189. // Member: CPres::CPres
  190. //
  191. // Synopsis: CPres constructor
  192. //
  193. // Effects: Initializes height & width of presentation data to zero.
  194. //
  195. // History: dd-mmm-yy Author Comment
  196. //
  197. // Notes:
  198. //
  199. //--------------------------------------------------------------------------
  200. CPres::CPres (void)
  201. {
  202. m_ulHeight = 0L;
  203. m_ulWidth = 0L;
  204. }
  205. //+-------------------------------------------------------------------------
  206. //
  207. // Member: CClass::Set, INTERNAL
  208. //
  209. // Synopsis: Sets the m_szClsid based on clsid
  210. //
  211. // Effects: Sets m_szClsid in the following order of preference:
  212. // - ProgID obtained from ProgIDFromCLSID()
  213. // - If it is a static type, m_szClsid is left blank
  214. // - Tries to read it from [pstg]
  215. // - Tries to obtain it from registry based on CLSID
  216. //
  217. //
  218. // Arguments: [clsid] - class id object is to be set to
  219. // [pstg] - storage which may contain info on the
  220. // clipboard format as a last resort
  221. //
  222. // Returns: NOERROR on success
  223. // REGDB_E_CLASSNOTREG unknown class
  224. //
  225. // History: dd-mmm-yy Author Comment
  226. // 16-Feb-94 davepl Cleaned up and documented
  227. //
  228. // Notes: Hard-coded maximum of 256 character clip format name.
  229. // On failure, m_clsid has still been set to clsid.
  230. //
  231. //--------------------------------------------------------------------------
  232. INTERNAL CClass::Set (REFCLSID clsid, LPSTORAGE pstg)
  233. {
  234. CLIPFORMAT cf;
  235. unsigned short const ccBufSize = 256;
  236. LPOLESTR szProgId = NULL;
  237. Assert (m_clsid == CLSID_NULL && m_szClsid == NULL);
  238. // set the m_clsid member in the object
  239. m_clsid = clsid;
  240. // If we can get it using ProgIDFromCLSID, that's the simplest case
  241. if (NOERROR == wProgIDFromCLSID (clsid, &m_szClsid))
  242. {
  243. return NOERROR;
  244. }
  245. // If not, maybe the object is static, in which case we leave the
  246. // class string NULL
  247. if (IsEqualCLSID(CLSID_StaticMetafile, clsid) ||
  248. IsEqualCLSID(CLSID_StaticDib, clsid))
  249. {
  250. return NOERROR;
  251. }
  252. // If still no luck, try to read the clipboard format from the storage
  253. // and then look that up.
  254. if (pstg &&
  255. SUCCEEDED(ReadFmtUserTypeStg(pstg, &cf, NULL)) &&
  256. SUCCEEDED(ReadFmtProgIdStg (pstg, &szProgId)))
  257. {
  258. // Last-ditch effort. If the class is an unregistered OLE1 class,
  259. // the ProgID should still be obtainable from the format tag.
  260. // If the class is an unregistered OLE2 class, the ProgId should be
  261. // at the end of the CompObj stream.
  262. if (CoIsOle1Class(clsid))
  263. {
  264. Verify (GetClipboardFormatName (cf, szProgId, ccBufSize));
  265. }
  266. else
  267. {
  268. // If its an OLE 2 object and we couldn't get the program ID from
  269. // the storage, we're out of luck
  270. if (szProgId == NULL || szProgId[0] == L'\0')
  271. {
  272. if (szProgId)
  273. {
  274. PubMemFree(szProgId);
  275. }
  276. return ResultFromScode (REGDB_E_CLASSNOTREG);
  277. }
  278. }
  279. // At this point we know we have a program ID and that this is an
  280. // OLE 2 object, so we use the program ID as the class name.
  281. m_szClsid = szProgId;
  282. return NOERROR;
  283. }
  284. else
  285. {
  286. // If we hit this path, we couldn't read from the storage
  287. return ResultFromScode (REGDB_E_CLASSNOTREG);
  288. }
  289. }
  290. //+-------------------------------------------------------------------------
  291. //
  292. // Member: CClass:SetSz, INTERNAL
  293. //
  294. // Synopsis: Sets CGenericObject's CLASS member ID based on the class
  295. // name passed in.
  296. //
  297. // History: dd-mmm-yy Author Comment
  298. // 15-Feb-94 davepl Cleaned up and documented
  299. //
  300. //--------------------------------------------------------------------------
  301. INTERNAL CClass::SetSz (LPOLESTR sz)
  302. {
  303. HRESULT hr;
  304. // The class info should be completely unset at this point
  305. Assert (m_clsid==CLSID_NULL && m_szClsid==NULL);
  306. m_szClsid = sz;
  307. if (FAILED(hr = wCLSIDFromProgID (sz, &m_clsid, TRUE)))
  308. {
  309. return hr;
  310. }
  311. return NOERROR;
  312. }
  313. //+-------------------------------------------------------------------------
  314. //
  315. // Member: CClass::Reset
  316. //
  317. // Synopsis: Frees the Class ID string for CClass and resets the pointer,
  318. // then sets the class ID and string bassed on the CLSID
  319. // passed in.
  320. //
  321. // History: dd-mmm-yy Author Comment
  322. // 16-Feb-94 davepl Cleaned up and documented
  323. //
  324. // Notes: Class ID must already be set before calling RESET
  325. //
  326. //--------------------------------------------------------------------------
  327. INTERNAL CClass::Reset (REFCLSID clsid)
  328. {
  329. m_clsid = clsid;
  330. // We should already have a class ID string if we are _re_setting it
  331. Assert(m_szClsid);
  332. PubMemFree(m_szClsid);
  333. HRESULT hr;
  334. m_szClsid = NULL;
  335. if (FAILED(hr = wProgIDFromCLSID (clsid, &m_szClsid)))
  336. {
  337. return hr;
  338. }
  339. return NOERROR;
  340. }
  341. //+-------------------------------------------------------------------------
  342. //
  343. // Member: CClass::~CClass
  344. //
  345. // Synopsis: CClass destructor
  346. //
  347. // History: dd-mmm-yy Author Comment
  348. // 12-Aug-94 alexgo check for NULL before free'ing memory
  349. // Notes:
  350. //
  351. //--------------------------------------------------------------------------
  352. CClass::~CClass (void)
  353. {
  354. // The string is created by UtDupString, so its public memory
  355. if( m_szClsid )
  356. {
  357. PubMemFree(m_szClsid);
  358. }
  359. }
  360. //+-------------------------------------------------------------------------
  361. //
  362. // Function: wConvertOLESTREAMToIStorage, INTERNAL
  363. //
  364. // Synopsis: Worker function. Ensures the OLESTREAM is correctly
  365. // set up then calls OLESTREAMToGenericObject.
  366. //
  367. // History: dd-mmm-yy Author Comment
  368. // 15-Feb-94 davepl Cleaned up and documented
  369. // Notes:
  370. //
  371. //--------------------------------------------------------------------------
  372. INTERNAL wConvertOLESTREAMToIStorage(
  373. LPOLESTREAM polestream,
  374. LPSTORAGE pstg,
  375. PGENOBJ pgenobj)
  376. {
  377. VDATEIFACE (pstg);
  378. #if DBG==1
  379. if (!IsValidReadPtrIn (polestream, sizeof(OLESTREAM)) ||
  380. !IsValidReadPtrIn (polestream->lpstbl, sizeof(OLESTREAMVTBL)) ||
  381. !IsValidCodePtr ((FARPROC)polestream->lpstbl->Get))
  382. {
  383. AssertSz (0, "Bad OLESTREAM");
  384. return ResultFromScode (E_INVALIDARG);
  385. }
  386. #endif
  387. return OLESTREAMToGenericObject (polestream, pgenobj);
  388. }
  389. //+-------------------------------------------------------------------------
  390. //
  391. // Function: OleConvertOLESTREAMToIStorage, STDAPI
  392. //
  393. // Synopsis: Given an OLE 1 stream and an OLE 2 storage, reads an object
  394. // from the OLE 1 stream into a CGenericObject. Once read in,
  395. // the object is written from generic format back into the OLE 2
  396. // storage object.
  397. //
  398. // Arguments: [polestream] -- OLE 1 stream to read object from
  399. // [pstg] -- OLE 2 storage to write object to
  400. // [ptd] -- Target device
  401. //
  402. // Requires: Streams should be set up, and OLE 1 stream should be
  403. // positioned at the beginning of the next OLE 1 object
  404. // to be read.
  405. //
  406. // Returns: [DV_E_DVTARGETDEVICE] Invalid write ptr to target device
  407. // CONVERT10_E_OLESTREAM_FMT On unknown OLE 1 format
  408. // CONVERT10_E_OLESTREAM_GET On stream read failue
  409. // E_OUTOFMEMORY On stream I/O memory failure
  410. //
  411. // History: dd-mmm-yy Author Comment
  412. // 14-Feb-94 davepl Cleanup and documentation
  413. //
  414. // Notes:
  415. //
  416. //--------------------------------------------------------------------------
  417. STDAPI OleConvertOLESTREAMToIStorage(
  418. LPOLESTREAM polestream,
  419. LPSTORAGE pstg,
  420. const DVTARGETDEVICE FAR* ptd)
  421. {
  422. OLETRACEIN((API_OleConvertOLESTREAMToIStorage,
  423. PARAMFMT("polestream= %p, pstg= %p, ptd= %td"),
  424. polestream, pstg, ptd));
  425. LEDebugOut((DEB_TRACE, "%p _IN OleConvertOLESTREAMToIStorage ("
  426. " %p , %p , %p)\n", 0 /*function*/,
  427. polestream, pstg, ptd
  428. ));
  429. CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IStorage,(IUnknown **)&pstg);
  430. HRESULT hresult;
  431. // This is the generic object we will use as intermediate storage to
  432. // hold the contents of the OLESTREAM
  433. CGenericObject genobj;
  434. if (ptd)
  435. {
  436. // The side of the td is the first DWORD. Ensure that much is
  437. // valid and then we can use it to check the whole structure.
  438. if (!IsValidReadPtrIn (ptd, sizeof(DWORD)))
  439. {
  440. hresult = ResultFromScode (DV_E_DVTARGETDEVICE);
  441. goto errRtn;
  442. }
  443. if (!IsValidReadPtrIn (ptd, (UINT) ptd->tdSize))
  444. {
  445. hresult = ResultFromScode (DV_E_DVTARGETDEVICE_SIZE);
  446. goto errRtn;
  447. }
  448. }
  449. if (FAILED(hresult=wConvertOLESTREAMToIStorage(polestream,pstg,&genobj)))
  450. {
  451. goto errRtn;
  452. }
  453. // If we were able to read the object out of the stream, we can now try
  454. // to write it back out to the storage
  455. hresult = GenericObjectToIStorage (genobj, pstg, ptd);
  456. errRtn:
  457. LEDebugOut((DEB_TRACE, "%p OUT OleConvertOLESTREAMToIStorage ( %lx ) "
  458. "\n", 0 /*function*/, hresult));
  459. OLETRACEOUT((API_OleConvertOLESTREAMToIStorage, hresult));
  460. return hresult;
  461. }
  462. //+-------------------------------------------------------------------------
  463. //
  464. // Function: PrependUNCName
  465. //
  466. // Synopsis: Convert *pszFile to use szUNC=="\\server\share" instead
  467. // of drive letter
  468. //
  469. // Effects: Deletes the UNC name and returns *ppszFile as a NEW string
  470. // with the full UNC filename. The string originally held at
  471. // *ppszFile is deleted by this function.
  472. //
  473. // Arguments: [ppszFile] Pointer to incoming filename string pointer
  474. //
  475. // History: dd-mmm-yy Author Comment
  476. // 16-Feb-94 davepl Cleanup, documentation, allocation fixes
  477. //
  478. // Notes: This function does some frightening things by changing the
  479. // caller's pointer and deleting various reference parameters.
  480. // Be sure you know what's going on before turning this function
  481. // loose on one of your own pointers.
  482. //
  483. //--------------------------------------------------------------------------
  484. static INTERNAL PrependUNCName (LPOLESTR FAR* ppszFile, LPOLESTR szUNC)
  485. {
  486. HRESULT hresult = NOERROR;
  487. LPOLESTR szNew;
  488. // No place to put result, so nothing to do...
  489. if (NULL==szUNC)
  490. {
  491. return hresult;
  492. }
  493. // Ensure the caller's pointer is valid
  494. if (NULL == *ppszFile)
  495. {
  496. return ResultFromScode(CONVERT10_E_OLESTREAM_FMT);
  497. }
  498. // Ensure the second letter of path is a colon (ie; X:\file)
  499. if((*ppszFile)[1] != L':')
  500. {
  501. return ResultFromScode(CONVERT10_E_OLESTREAM_FMT);
  502. }
  503. // Allocate enough space for new filename (we will be
  504. // omitting the X: portion of the filename, so this calculation
  505. // is _not_ short by 2 as it may appear)
  506. szNew = (LPOLESTR)
  507. PubMemAlloc((_xstrlen(*ppszFile)+_xstrlen (szUNC)) * sizeof(OLECHAR));
  508. if (NULL == szNew)
  509. {
  510. return ResultFromScode(E_OUTOFMEMORY);
  511. }
  512. // Copy over the UNC name
  513. _xstrcpy (szNew, szUNC);
  514. // Add the original name, except for the X:
  515. _xstrcat (szNew, (*ppszFile) + 2);
  516. // Free the original name
  517. PubMemFree(*ppszFile);
  518. *ppszFile = szNew;
  519. // Delete the UNC name
  520. PubMemFree(szUNC);
  521. return hresult;
  522. }
  523. //+-------------------------------------------------------------------------
  524. //
  525. // Function: OLESTREAMToGenericObject, INTERNAL
  526. //
  527. // Synopsis: Reads and OLE 1.0 version of an object from an OLE 1 stream
  528. // and stores it internally, including presentation and native
  529. // data, in a GenericObject.
  530. //
  531. // Effects: Creates a GenericObject that can be written back in OLE 1
  532. // or OLE 2 format
  533. //
  534. // Arguments: [pos] -- pointer to OLE 1 stream to read object from
  535. // [pgenobj] -- pointer to generic object to read into
  536. //
  537. // Requires: Input stream setup and GenObj created
  538. //
  539. // Returns: NOERROR On success
  540. // CONVERT10_E_OLESTREAM_FMT On unknown OLE 1 format
  541. // CONVERT10_E_OLESTREAM_GET On stream read failue
  542. // E_OUTOFMEMORY On stream I/O memory failure
  543. //
  544. // Signals: (none)
  545. //
  546. // Modifies: Stream position, GenObj
  547. //
  548. // Algorithm:
  549. //
  550. // History: dd-mmm-yy Author Comment
  551. // 14-Feb-94 davepl Added Trace code
  552. // davepl Cleaned up and documented
  553. // davepl Rerouted errors through central return
  554. //
  555. // Notes:
  556. //
  557. //--------------------------------------------------------------------------
  558. #pragma SEG(OLESTREAMToGenericObject)
  559. static INTERNAL OLESTREAMToGenericObject
  560. (
  561. LPOLESTREAM pos,
  562. PGENOBJ pgenobj
  563. )
  564. {
  565. HRESULT error = NOERROR;
  566. ULONG ulFmtId;
  567. LPOLESTR szClass = NULL;
  568. // Read OLE Version # from the stream and discard it
  569. if (FAILED(error = OLE1StreamToUL(pos, NULL)))
  570. {
  571. LEDebugOut(( DEB_ERROR,
  572. "Unable to read OLE ver# from stream at line %d in %s\n",
  573. __LINE__, __FILE__));
  574. goto errRtn;
  575. }
  576. // Get Format ID from the stream
  577. if (FAILED(error = OLE1StreamToUL(pos, &ulFmtId)))
  578. {
  579. LEDebugOut(( DEB_ERROR,
  580. "Unable to read format ID from stream at line %d in %s\n",
  581. __LINE__, __FILE__));
  582. goto errRtn;
  583. }
  584. // If this is a static object, read it into the generic object and return
  585. if (ulFmtId == FMTID_STATIC)
  586. {
  587. if (FAILED(error = GetStaticObject (pos, pgenobj)))
  588. {
  589. LEDebugOut(( DEB_ERROR,
  590. "Unable to read static object at line %d in %s\n",
  591. __LINE__, __FILE__));
  592. }
  593. goto errRtn;
  594. }
  595. // If this is neither a linked nor an embedded object, something
  596. // is wrong
  597. if (ulFmtId != FMTID_LINK && ulFmtId != FMTID_EMBED)
  598. {
  599. LEDebugOut(( DEB_ERROR,
  600. "Object is neither linked nor embedded at line %d in %s\n",
  601. __LINE__, __FILE__));
  602. error = ResultFromScode(CONVERT10_E_OLESTREAM_FMT);
  603. goto errRtn;
  604. }
  605. // If this is a linked object, set our flag in GenericObject
  606. if (FMTID_LINK == ulFmtId)
  607. {
  608. pgenobj->m_fLink = TRUE;
  609. }
  610. // Read the class name from the stream
  611. if (FAILED(error = OLE1StmToString(pos, &szClass)))
  612. {
  613. LEDebugOut(( DEB_ERROR,
  614. "Unable to read the class name from stream at line %d in %s\n",
  615. __LINE__, __FILE__));
  616. goto errRtn;
  617. }
  618. if (NULL == szClass)
  619. {
  620. LEDebugOut(( DEB_ERROR,
  621. "Class name was returned NULL at line %d in %s\n",
  622. __LINE__, __FILE__));
  623. error = CONVERT10_E_OLESTREAM_FMT;
  624. goto errRtn;
  625. }
  626. // If this is an embedded object, set the class ID and class string
  627. // If it is a linked object, set the class name but set the class ID
  628. // to CLSID_StdOleLink
  629. if (FMTID_EMBED == ulFmtId)
  630. {
  631. pgenobj->m_class.SetSz (szClass);
  632. }
  633. else
  634. {
  635. Assert (ulFmtId == FMTID_LINK);
  636. pgenobj->m_classLast.SetSz (szClass);
  637. pgenobj->m_class.Set (CLSID_StdOleLink, NULL);
  638. }
  639. // Read the Topic string from the stream
  640. if (FAILED(error = OLE1StmToString(pos, &(pgenobj->m_szTopic))))
  641. {
  642. LEDebugOut(( DEB_ERROR,
  643. "Unable to read topic string from stream at line %d in %s\n",
  644. __LINE__, __FILE__));
  645. goto errRtn;
  646. }
  647. // Read the Item string from the stream
  648. if (FAILED(error = OLE1StmToString(pos, &(pgenobj->m_szItem))))
  649. {
  650. LEDebugOut(( DEB_ERROR,
  651. "Unable to get item string from stream at line %d in %s\n",
  652. __LINE__, __FILE__));
  653. goto errRtn;
  654. }
  655. // If this is a linked object, set up the filename etc.
  656. if (FMTID_LINK == ulFmtId)
  657. {
  658. LPOLESTR szUNCName = NULL;
  659. // Read the network name from the stream
  660. if (FAILED(error = OLE1StmToString(pos, &szUNCName)))
  661. {
  662. LEDebugOut(( DEB_ERROR,
  663. "Unable to get network name from stream at line %d in %s\n",
  664. __LINE__, __FILE__));
  665. goto errRtn;
  666. }
  667. // Convert a drive-letter based name to \\srv\share name
  668. if (FAILED(error = PrependUNCName (&(pgenobj->m_szTopic), szUNCName)))
  669. {
  670. LEDebugOut(( DEB_ERROR,
  671. "Unable to convert drv ltr to UNC name at line %d in %s\n",
  672. __LINE__, __FILE__));
  673. goto errRtn;
  674. }
  675. // Read network type and network driver version # from stream
  676. // (They are both shorts and we discarding them, so read a LONG)
  677. if (FAILED(error = OLE1StreamToUL (pos, NULL)))
  678. {
  679. LEDebugOut(( DEB_ERROR,
  680. "Unable to get net type/ver from stream at line %d in %s\n",
  681. __LINE__, __FILE__));
  682. goto errRtn;
  683. }
  684. // Read the link-updating options from the stream. This field
  685. // use OLE 1.0 enumeration values for the link update options
  686. if (FAILED(error = OLE1StreamToUL(pos, &(pgenobj->m_lnkupdopt))))
  687. {
  688. LEDebugOut(( DEB_ERROR,
  689. "Unable to read link update opts at line %d in %s\n",
  690. __LINE__, __FILE__));
  691. goto errRtn;
  692. }
  693. // OLE 1.0 duplicates the link update options in the highword
  694. // of the LONG, and we don't want that, so clear the highword.
  695. pgenobj->m_lnkupdopt &= 0x0000FFFF;
  696. }
  697. else // This path is taken to read in embedded objects
  698. {
  699. Assert (ulFmtId == FMTID_EMBED);
  700. // Read and store the native data from the stream
  701. if (FAILED(error = GetSizedDataOLE1Stm (pos, &(pgenobj->m_dataNative))))
  702. {
  703. LEDebugOut(( DEB_ERROR,
  704. "Unable to get native data from stream at line %d in %s\n",
  705. __LINE__, __FILE__));
  706. goto errRtn;
  707. }
  708. }
  709. // For both linked and embedded objects, we need to read in any
  710. // presentation data that may be present. Note that certain formats
  711. // such as MS-Paint will not provide presentation data; this is OK
  712. // since they can be rendered by native data alone (space saving measure)
  713. if (FAILED(error = GetPresentationObject (pos, pgenobj)))
  714. {
  715. LEDebugOut(( DEB_ERROR,
  716. "Unable to get presentation data from stream at line %d in %s\n",
  717. __LINE__, __FILE__));
  718. goto errRtn;
  719. }
  720. errRtn:
  721. LEDebugOut((DEB_ITRACE, "%p OUT OLESTREAMToGenericObject ( %lx ) \n",
  722. NULL /*function*/, error));
  723. return error;
  724. }
  725. //+-------------------------------------------------------------------------
  726. //
  727. // Function: GetStaticObject, INTERNAL
  728. //
  729. // Synopsis: Reads the presentation data for a static object into the
  730. // PPRES member of GenericObject, and sets format and class
  731. // flags accordingly
  732. //
  733. // Effects:
  734. //
  735. // Arguments: [pos] -- stream we are reading OLE 1 object from
  736. // [pgenobj] -- GenericObject we are reading into
  737. // Requires:
  738. //
  739. // Returns: NOERROR On success
  740. // CONVERT10_E_OLESTREAM_FMT On unknown OLE 1 format
  741. // CONVERT10_E_OLESTREAM_GET On stream read failue
  742. // E_OUTOFMEMORY On stream I/O memory failure
  743. //
  744. // Signals: (none)
  745. //
  746. // Modifies: Stream position, GenericObject
  747. //
  748. // Algorithm:
  749. //
  750. // History: dd-mmm-yy Author Comment
  751. // 14-Feb-94 davepl Cleanup and documentation
  752. // Notes:
  753. //
  754. //--------------------------------------------------------------------------
  755. static INTERNAL GetStaticObject (LPOLESTREAM pos, PGENOBJ pgenobj)
  756. {
  757. HRESULT error;
  758. // Read the presentation data, standard or generic, into the
  759. // PPRES member of the GenericObject
  760. if (FAILED(error = GetPresentationObject(pos, pgenobj, TRUE)))
  761. {
  762. return ResultFromScode(error);
  763. }
  764. // Ensure that the format tag is a clipboard format
  765. if (ftagClipFormat != pgenobj->m_ppres->m_format.m_ftag)
  766. {
  767. return ResultFromScode(CONVERT10_E_OLESTREAM_FMT);
  768. }
  769. // If the clipboard format is a METAFILEPIC, set the CLASS
  770. // member of GenericObject to CLSID_StaticMetafile
  771. if (CF_METAFILEPICT == pgenobj->m_ppres->m_format.m_cf)
  772. {
  773. pgenobj->m_class.Set (CLSID_StaticMetafile, NULL);
  774. }
  775. // Otherwise, check to see if it is a DIB, and set the CLASS
  776. // member accordingly
  777. else if (CF_DIB == pgenobj->m_ppres->m_format.m_cf)
  778. {
  779. pgenobj->m_class.Set (CLSID_StaticDib, NULL);
  780. }
  781. // If it is neither a METAFILEPIC nor a DIB, we have a problem
  782. else
  783. {
  784. AssertSz (0, "1.0 static object not in one of 3 standard formats");
  785. return ResultFromScode (CONVERT10_E_OLESTREAM_FMT);
  786. }
  787. // Flag the GenericObject as Static
  788. pgenobj->m_fStatic = TRUE;
  789. return NOERROR;
  790. }
  791. //+-------------------------------------------------------------------------
  792. //
  793. // Function: CreateBlankPres, INTERNAL
  794. //
  795. // Synopsis: Sets up the format in the PPRES struct as ClipFormat 0
  796. //
  797. // History: dd-mmm-yy Author Comment
  798. // 16-Feb-94 davepl Cleaned up
  799. // Notes:
  800. //
  801. //--------------------------------------------------------------------------
  802. static INTERNAL CreateBlankPres(PPRES ppres)
  803. {
  804. Assert (ppres);
  805. ppres->m_format.m_ftag = ftagClipFormat;
  806. ppres->m_format.m_cf = 0;
  807. return NOERROR;
  808. }
  809. //+-------------------------------------------------------------------------
  810. //
  811. // Function: GetPresentationObject, INTERNAL
  812. //
  813. // Synopsis: Reads the presentation data into the CGenericObject object
  814. //
  815. // Arguments: [pos] -- OLE 1 stream we are reading from
  816. // [pgenobj] -- Generic object we are reading to
  817. // [fStatic] -- Flag: getting a static pres object?
  818. //
  819. // Requires: stream open, object allocated
  820. //
  821. // Returns: CONVERT10_E_OLESTREAM_FMT unknown format id in stream
  822. //
  823. //
  824. // History: dd-mmm-yy Author Comment
  825. // 16-Feb-94 davepl Cleaned up and documented
  826. //
  827. // Notes:
  828. //
  829. //--------------------------------------------------------------------------
  830. static INTERNAL GetPresentationObject(
  831. LPOLESTREAM pos,
  832. PGENOBJ pgenobj,
  833. BOOL fStatic)
  834. {
  835. LPOLESTR szClass = NULL;
  836. HRESULT hresult = NOERROR;
  837. Assert (pgenobj->m_ppres==NULL);
  838. if (TRUE != fStatic) //FALSE!
  839. {
  840. // Pull the OLE version number out of the stream, we don't want it
  841. if (FAILED(hresult = OLE1StreamToUL(pos, NULL)))
  842. {
  843. return hresult;
  844. }
  845. // Pull the OLE 1 format identifier out of the stream
  846. ULONG ulFmtId;
  847. if (FAILED(hresult = OLE1StreamToUL (pos, &ulFmtId)))
  848. {
  849. return hresult;
  850. }
  851. // If the format identifier is not FMTID_PRES, we've got a
  852. // problem... unless it's 0 in which case it simply means
  853. // that there _is no_ presentation data, ie: PBrush, Excel
  854. if (ulFmtId != FMTID_PRES)
  855. {
  856. if (0==ulFmtId)
  857. {
  858. return NOERROR;
  859. }
  860. else
  861. {
  862. return ResultFromScode(CONVERT10_E_OLESTREAM_FMT);
  863. }
  864. }
  865. }
  866. // Pull in the type name for the OLE1 data
  867. if (FAILED(hresult = OLE1StmToString (pos, &szClass)))
  868. {
  869. return hresult;
  870. }
  871. if (0==_xstrcmp (szClass, OLESTR("METAFILEPICT")))
  872. {
  873. hresult = GetStandardPresentation (pos, pgenobj, CF_METAFILEPICT);
  874. }
  875. else if (0==_xstrcmp (szClass, OLESTR("BITMAP")))
  876. {
  877. hresult = GetStandardPresentation (pos, pgenobj, CF_BITMAP);
  878. }
  879. else if (0==_xstrcmp (szClass, OLESTR("DIB")))
  880. {
  881. hresult = GetStandardPresentation (pos, pgenobj, CF_DIB);
  882. }
  883. else if (0==_xstrcmp (szClass, OLESTR("ENHMETAFILE")))
  884. {
  885. Assert (0 && "Encountered an unsupported format: ENHMETAFILE");
  886. }
  887. else
  888. {
  889. // This is a Generic Presentation stream
  890. #if DBG==1
  891. Assert (!fStatic);
  892. if (_xstrcmp (pgenobj->m_fLink
  893. ? pgenobj->m_classLast.m_szClsid
  894. : pgenobj->m_class.m_szClsid, szClass))
  895. {
  896. Assert (0 && "Class name in embedded object stream does\n"
  897. "not match class name in pres object stream");
  898. }
  899. #endif
  900. hresult = GetGenericPresentation (pos, pgenobj);
  901. }
  902. if (szClass)
  903. {
  904. PubMemFree(szClass);
  905. }
  906. return hresult;
  907. }
  908. //+-------------------------------------------------------------------------
  909. //
  910. // Function: GetBitmapAsDib, INTERNAL
  911. //
  912. // Synopsis: Reads a bitmap from the OLE1 stream, converts it to a DIB,
  913. // and stores it in the DATA member of CGenericObject
  914. //
  915. // Arguments: [pos] -- The OLE 1 stream to read from
  916. // [pdata] -- The DATA object to read into
  917. //
  918. // Requires:
  919. //
  920. // Returns: NOERROR success
  921. // CONVERT10_E_OLESTREAM_GET I/O error
  922. // CONVERT10_E_OLESTREAM_BITMAP_TO_DIB conversion error
  923. //
  924. // History: dd-mmm-yy Author Comment
  925. // 16-Feb-94 davepl Cleaned up and documented
  926. // Notes:
  927. //
  928. //--------------------------------------------------------------------------
  929. static INTERNAL GetBitmapAsDib(LPOLESTREAM pos, PDATA pdata)
  930. {
  931. HRESULT hresult= NOERROR;
  932. HGLOBAL hBits = NULL;
  933. HGLOBAL hDib = NULL;
  934. LPVOID pBits = NULL;
  935. WIN16BITMAP bm;
  936. HBITMAP hBitmap = NULL;
  937. ULONG cbBits;
  938. ULONG ul;
  939. Assert (pdata->m_h==NULL && pdata->m_pv==NULL && pdata->m_cbSize==0);
  940. // Get size of all bitmap data, including the bitmap header struct
  941. if (FAILED(hresult = OLE1StreamToUL(pos, &ul)))
  942. {
  943. return hresult;
  944. }
  945. // Read the bitmap header structure. Since this was stored as Win16
  946. // BITMAP, we have to pull a structure of that size from the stream
  947. // (A Win32 BITMAP uses LONGs and hence is larger).
  948. if (pos->lpstbl->Get (pos, &bm, sizeof(WIN16BITMAP)) < sizeof(WIN16BITMAP))
  949. {
  950. return ResultFromScode (CONVERT10_E_OLESTREAM_GET);
  951. }
  952. // The bitmap data is total size - header size
  953. // Allocate enough memory to hold the bitmap data
  954. cbBits = ul - sizeof(WIN16BITMAP);
  955. hBits = GlobalAlloc (GMEM_MOVEABLE, cbBits);
  956. if (NULL == hBits)
  957. {
  958. hresult = ResultFromScode(E_OUTOFMEMORY);
  959. goto errRtn;
  960. }
  961. pBits = (void FAR*) GlobalLock (hBits);
  962. if (pBits == NULL)
  963. {
  964. hresult = ResultFromScode(E_OUTOFMEMORY);
  965. goto errRtn;
  966. }
  967. // Read the header data into our allocated buffer
  968. if (pos->lpstbl->Get (pos, pBits, cbBits) < cbBits)
  969. {
  970. hresult = ResultFromScode (CONVERT10_E_OLESTREAM_GET);
  971. goto errRtn;
  972. }
  973. // Turn that raw data into a bitmap
  974. hBitmap = CreateBitmap (bm.bmWidth, bm.bmHeight, bm.bmPlanes,
  975. bm.bmBitsPixel, pBits);
  976. if (NULL == hBitmap)
  977. {
  978. hresult = ResultFromScode(CONVERT10_E_OLESTREAM_BITMAP_TO_DIB);
  979. goto errRtn;
  980. }
  981. // NOTE: The following call gave only the first parameter in the
  982. // (davepl) original source; The second is the palette handle, which
  983. // I've passed as NULL to indicate the default stock palette.
  984. hDib = UtConvertBitmapToDib (hBitmap, NULL);
  985. if (NULL == hDib)
  986. {
  987. hresult = ResultFromScode(CONVERT10_E_OLESTREAM_BITMAP_TO_DIB);
  988. goto errRtn;
  989. }
  990. // Set the presentation data pointers to point to this new DIB
  991. pdata->m_pv = GlobalLock (hDib);
  992. if (NULL == pdata->m_pv)
  993. {
  994. hresult = ResultFromScode(E_OUTOFMEMORY);
  995. goto errRtn;
  996. }
  997. pdata->m_cbSize = (ULONG) GlobalSize (hDib);
  998. pdata->m_h = hDib;
  999. // Free up allocations and resources, return result
  1000. errRtn:
  1001. if (pBits)
  1002. {
  1003. Verify (0==GlobalUnlock (hBits));
  1004. }
  1005. if (hBits)
  1006. {
  1007. Verify (0==GlobalFree (hBits));
  1008. }
  1009. if (hBitmap)
  1010. {
  1011. Verify (DeleteObject (hBitmap));
  1012. }
  1013. return hresult;
  1014. }
  1015. //+-------------------------------------------------------------------------
  1016. //
  1017. // Function: GetMfBits, INTERNAL
  1018. //
  1019. // Synopsis: Strips the METAFILE header from the stream and then reads
  1020. // the metafile bits into an allocated memory area; the
  1021. // presentation data member of [pos] is then set to point
  1022. // to this memory.
  1023. //
  1024. // Arguments: [pos] -- the OLE 1 stream to read from
  1025. // [pdata] -- the presentation data member of generic object
  1026. //
  1027. // Returns: NOERROR success
  1028. // CONVERT10_E_OLESTREAM_GET stream error
  1029. // E_OUTOFMEMORY allocation failure
  1030. //
  1031. // History: dd-mmm-yy Author Comment
  1032. // 16-Feb-94 davepl Cleaned up and documented
  1033. //
  1034. // Notes:
  1035. //
  1036. //--------------------------------------------------------------------------
  1037. static INTERNAL GetMfBits(LPOLESTREAM pos, PDATA pdata)
  1038. {
  1039. ULONG cbSize;
  1040. WIN16METAFILEPICT mfpictDummy;
  1041. HRESULT hresult = NOERROR;
  1042. Assert (0==pdata->m_cbSize && pdata->m_h==NULL && NULL==pdata->m_pv);
  1043. // Read the data size from the stream
  1044. if (FAILED(hresult = (OLE1StreamToUL (pos, &cbSize))))
  1045. {
  1046. return hresult;
  1047. }
  1048. // Now read the actual data
  1049. if (cbSize <= sizeof(WIN16METAFILEPICT))
  1050. {
  1051. return ResultFromScode(CONVERT10_E_OLESTREAM_FMT);
  1052. }
  1053. // An OLESTREAM contains a METAFILEPICT structure (with a meaningless
  1054. // handle) followed by the metafile bits. So consume the METAFILEPICT.
  1055. if (pos->lpstbl->Get (pos, &mfpictDummy, sizeof(WIN16METAFILEPICT))
  1056. < sizeof(WIN16METAFILEPICT))
  1057. {
  1058. return ResultFromScode(CONVERT10_E_OLESTREAM_GET);
  1059. }
  1060. // Deduct from our count of bytes to read the size of the header which
  1061. // we just consumed. Set the presentation data size to be this new size.
  1062. cbSize -= sizeof(WIN16METAFILEPICT);
  1063. pdata->m_cbSize = cbSize;
  1064. // Grad some memory to store the metafile bits
  1065. pdata->m_h = GlobalAlloc (GMEM_MOVEABLE, cbSize);
  1066. if (NULL==pdata->m_h)
  1067. {
  1068. return ResultFromScode(E_OUTOFMEMORY);
  1069. }
  1070. pdata->m_pv = GlobalLock (pdata->m_h);
  1071. if (NULL==pdata->m_pv)
  1072. {
  1073. return ResultFromScode(E_OUTOFMEMORY);
  1074. }
  1075. // Get the actual metafile bits
  1076. if (pos->lpstbl->Get (pos, pdata->m_pv, cbSize) < cbSize)
  1077. {
  1078. return ResultFromScode(CONVERT10_E_OLESTREAM_GET);
  1079. }
  1080. return hresult;
  1081. }
  1082. //+-------------------------------------------------------------------------
  1083. //
  1084. // Function: GetStandardPresentation, INTERNAL
  1085. //
  1086. // Synopsis: Allocates a PRES member for generic object, then reads
  1087. // whatever presentation may be found in the stream into
  1088. // that PRES.
  1089. //
  1090. // Arguments: [pos] -- the OLE 1 stream to read from
  1091. // [pgenobj] -- the generic object we are going to set
  1092. // up with the presentation data
  1093. // [cf] -- the clipboad format we are to read
  1094. //
  1095. // Returns: NOERROR success
  1096. // E_OUTOFMEMORY allocation failure
  1097. //
  1098. // Modifies: [pgenobj] - sets up the m_ppres member
  1099. //
  1100. // History: dd-mmm-yy Author Comment
  1101. // 16-Feb-94 davepl Cleaned up and documented
  1102. //
  1103. // Notes:
  1104. //
  1105. //--------------------------------------------------------------------------
  1106. static INTERNAL GetStandardPresentation(
  1107. LPOLESTREAM pos,
  1108. PGENOBJ pgenobj,
  1109. CLIPFORMAT cf)
  1110. {
  1111. HRESULT hresult = NOERROR;
  1112. // Allocate enough memory for the PRES object
  1113. pgenobj->m_ppres = new PRES;
  1114. if (NULL == pgenobj->m_ppres)
  1115. {
  1116. return ResultFromScode(E_OUTOFMEMORY);
  1117. }
  1118. // Set up the format tag and clipboard format
  1119. pgenobj->m_ppres->m_format.m_ftag = ftagClipFormat;
  1120. pgenobj->m_ppres->m_format.m_cf = cf;
  1121. // Get the width of the data from the stream
  1122. if (FAILED(hresult = OLE1StreamToUL(pos, &(pgenobj->m_ppres->m_ulWidth))))
  1123. {
  1124. return hresult;
  1125. }
  1126. // Get the height of the data from the stream
  1127. if (FAILED(hresult=OLE1StreamToUL(pos, &(pgenobj->m_ppres->m_ulHeight))))
  1128. {
  1129. return hresult;
  1130. }
  1131. // The height saved by OLE 1.0 objects into the stream is always a
  1132. // negative value (Y-increase in pixel is negative upward?) so we
  1133. // have to correct that value.
  1134. pgenobj->m_ppres->m_ulHeight
  1135. = (ULONG) -((LONG) pgenobj->m_ppres->m_ulHeight);
  1136. // Read the appropriate presentation data based on the clipboard
  1137. // format ID
  1138. switch(cf)
  1139. {
  1140. case CF_METAFILEPICT:
  1141. {
  1142. hresult = GetMfBits (pos, &(pgenobj->m_ppres->m_data));
  1143. break;
  1144. }
  1145. case CF_BITMAP:
  1146. {
  1147. // When reading a bitmap, we will convert from Bitmap to
  1148. // DIB in the process, so update the PRES clipboard format ID
  1149. pgenobj->m_ppres->m_format.m_cf = CF_DIB;
  1150. hresult = GetBitmapAsDib (pos, &(pgenobj->m_ppres->m_data));
  1151. break;
  1152. }
  1153. case CF_DIB:
  1154. {
  1155. Assert (CF_DIB==cf);
  1156. hresult = GetSizedDataOLE1Stm (pos, &(pgenobj->m_ppres->m_data));
  1157. break;
  1158. }
  1159. default:
  1160. {
  1161. Assert(0 && "Unexpected clipboard format reading PRES");
  1162. }
  1163. }
  1164. return hresult;
  1165. }
  1166. //+-------------------------------------------------------------------------
  1167. //
  1168. // Function: GetGenericPresentation, INTERNAL
  1169. //
  1170. // Synopsis: Allocated the PRES member of the generic object and reads
  1171. // the generic presentation data into it.
  1172. //
  1173. // Effects: If the format is a known clipboard format, we set the
  1174. // format tag to indicate this, and set the format type
  1175. // to indicate the clipboard format type. If it is unknown,
  1176. // we set the format tag to string and read the description
  1177. // of the format.
  1178. //
  1179. // Arguments: [pos] -- the OLE 1 stream we are reading from
  1180. // [pgenobj] -- the generic object we are reading to
  1181. //
  1182. // Returns: NOERROR on success
  1183. // E_OUTOFMEMORY on allocation failure
  1184. //
  1185. // History: dd-mmm-yy Author Comment
  1186. // 16-Feb-94 davepl Code cleanup and document
  1187. //
  1188. // Notes:
  1189. //
  1190. //--------------------------------------------------------------------------
  1191. static INTERNAL GetGenericPresentation(
  1192. LPOLESTREAM pos,
  1193. PGENOBJ pgenobj)
  1194. {
  1195. ULONG ulClipFormat;
  1196. HRESULT hresult = NOERROR;
  1197. // The PRES member should not exist at this point
  1198. Assert (NULL==pgenobj->m_ppres);
  1199. // Allocate the PRES member of the generic object
  1200. pgenobj->m_ppres = new PRES;
  1201. if (NULL == pgenobj->m_ppres)
  1202. {
  1203. return ResultFromScode(E_OUTOFMEMORY);
  1204. }
  1205. // Read the clipboard format ID
  1206. if (FAILED(hresult = OLE1StreamToUL (pos, &ulClipFormat)))
  1207. {
  1208. delete (pgenobj->m_ppres);
  1209. return hresult;
  1210. }
  1211. // If the clipboard format is not 0, we have a known clipboard
  1212. // format and we should set the tag type and ID accordingly
  1213. if (ulClipFormat)
  1214. {
  1215. pgenobj->m_ppres->m_format.m_ftag = ftagClipFormat;
  1216. pgenobj->m_ppres->m_format.m_cf = (CLIPFORMAT) ulClipFormat;
  1217. }
  1218. else
  1219. {
  1220. // Otherwise, we have a custom format so we need to set the
  1221. // tag type to string and read in the data format string
  1222. pgenobj->m_ppres->m_format.m_ftag = ftagString;
  1223. if (FAILED(hresult = (GetSizedDataOLE1Stm
  1224. (pos, &(pgenobj->m_ppres->m_format.m_dataFormatString)))))
  1225. {
  1226. delete (pgenobj->m_ppres);
  1227. return hresult;
  1228. }
  1229. }
  1230. // We don't know the size, so reset to 0
  1231. pgenobj->m_ppres->m_ulHeight = 0;
  1232. pgenobj->m_ppres->m_ulWidth = 0;
  1233. // Read the raw generic presentation data into the PRES member
  1234. if (FAILED(hresult=GetSizedDataOLE1Stm(pos,&(pgenobj->m_ppres->m_data))))
  1235. {
  1236. delete (pgenobj->m_ppres);
  1237. return hresult;
  1238. }
  1239. return NOERROR;
  1240. }
  1241. //+-------------------------------------------------------------------------
  1242. //
  1243. // Function: GetSizedDataOLE1Stm, INTERNAL
  1244. //
  1245. // Synopsis: Reads bytes from an OLE 1 stream into a CData object.
  1246. // Obtains the number of bytes to read from the first
  1247. // ULONG in the stream
  1248. //
  1249. // Arguments: [pos] -- the stream to read from
  1250. // [pdata] -- the CData object to read to
  1251. //
  1252. // Requires:
  1253. //
  1254. // Returns: NOERROR on success
  1255. // CONVERT10_E_OLESTREAM_GET on stream read problem
  1256. // E_OUTOFMEMORY on allocation failure
  1257. //
  1258. // History: dd-mmm-yy Author Comment
  1259. // 16-Feb-94 davepl Cleaned up and documented
  1260. // Notes:
  1261. //
  1262. //--------------------------------------------------------------------------
  1263. static INTERNAL GetSizedDataOLE1Stm(LPOLESTREAM pos, PDATA pdata)
  1264. {
  1265. ULONG cbSize;
  1266. HRESULT hr;
  1267. Assert (0==pdata->m_cbSize && pdata->m_h==NULL && NULL==pdata->m_pv);
  1268. // Read size of data
  1269. if (FAILED(hr = OLE1StreamToUL(pos, &cbSize)))
  1270. {
  1271. return hr;
  1272. }
  1273. if (cbSize==0)
  1274. {
  1275. return NOERROR;
  1276. }
  1277. // Allocate memory for data
  1278. pdata->m_cbSize = cbSize;
  1279. pdata->m_h = GlobalAlloc (GMEM_MOVEABLE, cbSize);
  1280. if (NULL==pdata->m_h)
  1281. {
  1282. return ResultFromScode(E_OUTOFMEMORY);
  1283. }
  1284. pdata->m_pv = GlobalLock (pdata->m_h);
  1285. if (NULL==pdata->m_pv)
  1286. {
  1287. return ResultFromScode(E_OUTOFMEMORY);
  1288. }
  1289. // Read data into allocated buffer
  1290. if (pos->lpstbl->Get (pos, pdata->m_pv, cbSize) < cbSize)
  1291. {
  1292. return ResultFromScode(CONVERT10_E_OLESTREAM_GET);
  1293. }
  1294. return NOERROR;
  1295. }
  1296. //+-------------------------------------------------------------------------
  1297. //
  1298. // Function: OLE1StreamToUL, INTERNAL
  1299. //
  1300. // Synopsis: Reads a ULONG from an OLE1 stream
  1301. //
  1302. // Arguments: [pos] -- the OLE 1 stream to read from
  1303. // [pul] -- the ULONG to read into
  1304. //
  1305. // Returns: NOERROR on success
  1306. // CONVERT10_E_OLESTREAM_GET on stream read failure
  1307. //
  1308. // History: dd-mmm-yy Author Comment
  1309. // 16-Feb-94 davepl Cleaned up and documented
  1310. //
  1311. // Notes: on failure [pul] is preserved
  1312. //
  1313. //--------------------------------------------------------------------------
  1314. static INTERNAL OLE1StreamToUL(LPOLESTREAM pos, ULONG FAR* pul)
  1315. {
  1316. ULONG ul;
  1317. // Read the data from the stream into the local ULONG
  1318. if (pos->lpstbl->Get (pos, &ul, sizeof(ULONG)) < sizeof(ULONG))
  1319. {
  1320. return ResultFromScode(CONVERT10_E_OLESTREAM_GET);
  1321. }
  1322. // If all went well, store the data into [pul]
  1323. if (pul != NULL)
  1324. {
  1325. Assert (IsValidPtrOut (pul, sizeof(ULONG)));
  1326. *pul = ul;
  1327. }
  1328. return NOERROR;
  1329. }
  1330. //+-------------------------------------------------------------------------
  1331. //
  1332. // Function: DataToOLE1Stm, INTERNAL INLINE
  1333. //
  1334. // Synopsis: Writes raw data out to an OLE 1 stream
  1335. //
  1336. // Arguments: [pos] -- the stream to write to
  1337. // [pvBuf] -- the buffer to write from
  1338. // [ulSize] -- the number of bytes to write
  1339. //
  1340. // Returns: NOERROR on success
  1341. // CONVERT10_E_OLESTREAM_PUT on stream write failure
  1342. //
  1343. // History: dd-mmm-yy Author Comment
  1344. // 16-Feb-94 davepl Cleaned up and documented
  1345. // Notes:
  1346. //
  1347. //--------------------------------------------------------------------------
  1348. inline static INTERNAL DataToOLE1Stm(LPOLESTREAM pos, LPVOID pvBuf, ULONG ulSize)
  1349. {
  1350. // Write the data out to the stream
  1351. if (pos->lpstbl->Put(pos, pvBuf, ulSize) < ulSize)
  1352. {
  1353. return ResultFromScode(CONVERT10_E_OLESTREAM_PUT);
  1354. }
  1355. return NOERROR;
  1356. }
  1357. //+-------------------------------------------------------------------------
  1358. //
  1359. // Function: ULToOLE1Stream, INTERNAL INLINE
  1360. //
  1361. // Synopsis: Write a ULONG to the specified OLESTREAM via the Put()
  1362. // member of the stream's VTBL
  1363. //
  1364. // Effects: Advances stream position by sizeof(ULONG) on success.
  1365. //
  1366. // Arguments: [pos] -- The stream into which the ULONG is written
  1367. // [ul] -- The ULONG, passed by value
  1368. //
  1369. // Requires:
  1370. //
  1371. // Returns: NOERROR on success
  1372. // CONVERT10_E_OLESTREAM_PUT on failure
  1373. //
  1374. // Signals: (none)
  1375. //
  1376. // Modifies: Stream position
  1377. //
  1378. // Algorithm:
  1379. //
  1380. // History: dd-mmm-yy Author Comment
  1381. // 11-Jan-93 davepl Cleaned up and documented
  1382. //
  1383. // Notes: On failure 0-3 bytes may have been written
  1384. //
  1385. //--------------------------------------------------------------------------
  1386. inline static INTERNAL ULToOLE1Stream(LPOLESTREAM pos, ULONG ul)
  1387. {
  1388. if (pos->lpstbl->Put (pos, &ul, sizeof(ULONG)) < sizeof(ULONG))
  1389. {
  1390. return ResultFromScode(CONVERT10_E_OLESTREAM_PUT);
  1391. }
  1392. return NOERROR;
  1393. }
  1394. //+-------------------------------------------------------------------------
  1395. //
  1396. // Function: StringToOLE1Stm, INTERNAL
  1397. //
  1398. // Synopsis: Converts the input OLESTR to ANSI and writes it to an
  1399. // OLE 1 stream, preceded by a ULONG indicating the number
  1400. // of bytes in the ANSI representation (terminator included).
  1401. //
  1402. // Arguments: [pos] -- The stream into which the ULONG is written
  1403. // [szOleStr] -- The STR to be written
  1404. //
  1405. // Returns: NOERROR on success
  1406. // CONVERT10_E_OLESTREAM_PUT on stream write failure
  1407. // E_NOMEMORY on allocation failure
  1408. //
  1409. // Modifies: Stream position
  1410. //
  1411. // History: dd-mmm-yy Author Comment
  1412. // 11-Feb-94 davepl Cleaned up and documented
  1413. // 15-Feb-94 davepl Re-write for ANSI/WCHAR handling
  1414. // 17-Feb-94 davepl Restructured error handling
  1415. //
  1416. // Notes: On failure, 0 to (cbSize-1) bytes may have been written
  1417. //
  1418. //--------------------------------------------------------------------------
  1419. static INTERNAL StringToOLE1Stm(LPOLESTREAM pos, LPCOLESTR pszOleStr)
  1420. {
  1421. HRESULT hr = NOERROR;
  1422. LPSTR pszAnsi = NULL; // Ansi version of OLE input string
  1423. if (pszOleStr)
  1424. {
  1425. // This handy function will calculate the size of the buffer we
  1426. // need to represent the OLESTR in ANSI format for us.
  1427. ULONG cbSize = WideCharToMultiByte(CP_ACP, // Code Page ANSI
  1428. 0, // No flags
  1429. pszOleStr, // Input OLESTR
  1430. -1, // Input len (auto detect)
  1431. NULL, // Output buffer
  1432. 0, // Output len (check only)
  1433. NULL, // Default char
  1434. NULL);// Flag: Default char used
  1435. if (cbSize == FALSE)
  1436. {
  1437. return ResultFromScode(E_UNSPEC);
  1438. }
  1439. // Now that we know the actual needed length, allocate a buffer
  1440. pszAnsi = (LPSTR) PrivMemAlloc(cbSize);
  1441. if (NULL == pszAnsi)
  1442. {
  1443. return ResultFromScode(E_OUTOFMEMORY);
  1444. }
  1445. // We've got out buffer and our length, so do the conversion now
  1446. // We don't need to check for cbSize == FALSE since that was
  1447. // already done during the length test, but we need to check
  1448. // for substitution. Iff this call sets the fDefChar even when
  1449. // only doing a length check, these two tests could be merged,
  1450. // but I don't believe this is the case.
  1451. BOOL fDefUsed = 0;
  1452. cbSize = WideCharToMultiByte(CP_ACP, // Code Page ANSI
  1453. 0, // No flags
  1454. pszOleStr, // Input OLESTR
  1455. -1, // Input len (auto detect)
  1456. pszAnsi, // Output buffer
  1457. cbSize, // Output len
  1458. NULL, // Default char (use system's)
  1459. &fDefUsed); // Flag: Default char used
  1460. // If number of bytes converted was 0, we failed
  1461. if (fDefUsed)
  1462. {
  1463. hr = ResultFromScode(E_UNSPEC);
  1464. }
  1465. // Write the size of the string (including null terminator) to stream
  1466. else if (FAILED(hr = ULToOLE1Stream(pos, cbSize)))
  1467. {
  1468. NULL;
  1469. }
  1470. // Write the Ansi version of the string into the stream
  1471. else if (pos->lpstbl->Put(pos, pszAnsi, cbSize) < cbSize)
  1472. {
  1473. hr = ResultFromScode(CONVERT10_E_OLESTREAM_PUT);
  1474. }
  1475. if (pszAnsi)
  1476. {
  1477. PrivMemFree(pszAnsi);
  1478. }
  1479. }
  1480. // If the pointer is not valid, we write a length of zero into
  1481. // the stream
  1482. else
  1483. {
  1484. hr = ULToOLE1Stream(pos, 0);
  1485. }
  1486. return hr;
  1487. }
  1488. //+-------------------------------------------------------------------------
  1489. //
  1490. // Function: OLE2StmToUL, INTERNAL
  1491. //
  1492. // Synopsis: Reads a ULONG from the specified ISTREAM and stores it at
  1493. // the ULONG deferenced by pul
  1494. //
  1495. // Effects: Writes the value read into memory at pul
  1496. //
  1497. // Arguments: [pstm] -- The stream from which the ULONG is read
  1498. // [pul] -- ULONG to hold the value read
  1499. //
  1500. // Requires:
  1501. //
  1502. // Returns: NOERROR on success
  1503. // CONVERT10_E_OLESTREAM_PUT on failure
  1504. //
  1505. // Signals: (none)
  1506. //
  1507. // Modifies: Stream position
  1508. //
  1509. // Algorithm:
  1510. //
  1511. // History: dd-mmm-yy Author Comment
  1512. // 11-Feb-93 davepl Cleaned up and documented
  1513. //
  1514. // Notes: On failure, *pul is not disturbed regardless of how
  1515. // many bytes were actually read from the stream
  1516. //
  1517. //--------------------------------------------------------------------------
  1518. static INTERNAL OLE2StmToUL(LPSTREAM pstm, ULONG FAR* pul)
  1519. {
  1520. ULONG ul;
  1521. ULONG cbRead;
  1522. HRESULT hr = NOERROR;
  1523. // Attempt to read 4 bytes from the stream to form a ULONG.
  1524. if (FAILED(hr = pstm->Read (&ul, sizeof(ULONG), &cbRead)))
  1525. {
  1526. return hr;
  1527. }
  1528. if (cbRead != sizeof(ULONG))
  1529. {
  1530. hr = STG_E_READFAULT;
  1531. }
  1532. // Ensure that the [pul] pointer is valid and that we have write
  1533. // access to all 4 bytes (assertion only). If OK, transfer the
  1534. // ULONG to [*pul]
  1535. else if (pul != NULL)
  1536. {
  1537. Assert (FALSE == !IsValidPtrOut(pul, sizeof(ULONG)));
  1538. *pul = ul;
  1539. }
  1540. return hr;
  1541. }
  1542. //+-------------------------------------------------------------------------
  1543. //
  1544. // Function: OLE1StmToString, INTERNAL
  1545. //
  1546. // Synopsis: Reads a cstr from the specified STREAM and stores it in
  1547. // a dynamically allocated buffer as an OLESTR; sets the
  1548. // user's pointer to point to this new buffer.
  1549. //
  1550. // Effects: Allocates memory on the input pointer, advances stream pos'n
  1551. //
  1552. // Arguments: [pos ] -- The stream from which the STR is read
  1553. // [ppsz] -- OLESTR ** which allows this fn to modify the
  1554. // caller's pointer to point to memory allocated
  1555. // by this fn to hold the OLESTR
  1556. //
  1557. // Requires: Stream must be set up. Caller's responsibilty to free memory.
  1558. //
  1559. // Returns: NOERROR on success
  1560. // CONVERT10_E_OLESTREAM_GET on failure
  1561. // E_OUTOFMEMORY if buffers couldn't be allocated
  1562. //
  1563. // Signals: (none)
  1564. //
  1565. // Modifies: Stream position, caller's string pointer
  1566. //
  1567. // Algorithm: if ppsz == NULL, string is read from stream and discarded
  1568. // if ppsz != NULL, string is read and converted into a
  1569. // dynamically allocated buffer. *ppsz is set
  1570. // to point to this buffer, which must be later
  1571. // freed by the caller
  1572. //
  1573. // History: dd-mmm-yy Author Comment
  1574. // 12-Jan-93 davepl Cleaned up and documented
  1575. // 14-Jan-93 davepl Changed to return LPOLESTR
  1576. //
  1577. // Notes: [ppsz] may be NULL on entry; string is read and discarded
  1578. // with no cleanup required by the caller
  1579. //
  1580. //
  1581. //--------------------------------------------------------------------------
  1582. static INTERNAL OLE1StmToString(LPOLESTREAM pos, LPOLESTR FAR* ppsz)
  1583. {
  1584. ULONG cbSize; // Size in bytes of cstr
  1585. LPOLESTR pszOleStr = NULL;
  1586. LPSTR pszAnsiStr = NULL;
  1587. HRESULT error = NOERROR;
  1588. // if ppsz is valid, NULL out *ppsz as default out parameter
  1589. if (NULL != ppsz)
  1590. {
  1591. *ppsz = NULL;
  1592. }
  1593. // Retrieve the incoming string size from the stream
  1594. if (FAILED(error = OLE1StreamToUL (pos, &cbSize)))
  1595. {
  1596. goto errRtn;
  1597. }
  1598. // If there are chars to be read, allocate memory for the
  1599. // ANSI and OLESTR versions. Read the string into the
  1600. // ANSI version and convert it to OLESTR
  1601. if (0 < cbSize)
  1602. {
  1603. // Allocate the ANSI buffer
  1604. pszAnsiStr = (LPSTR) PrivMemAlloc((size_t)cbSize);
  1605. if (NULL == pszAnsiStr)
  1606. {
  1607. error = ResultFromScode(E_OUTOFMEMORY);
  1608. goto errRtn;
  1609. }
  1610. // Read the string into the ANSI buffer
  1611. if (pos->lpstbl->Get (pos, pszAnsiStr, cbSize) < cbSize)
  1612. {
  1613. error = ResultFromScode(CONVERT10_E_OLESTREAM_GET);
  1614. goto errRtn;
  1615. }
  1616. // We only need to perform the ANSI->OLESTR conversion in those
  1617. // cases where the caller needs an out parameter
  1618. if (NULL != ppsz)
  1619. {
  1620. // Allocate the OLESTR buffer
  1621. pszOleStr = (LPOLESTR) PubMemAlloc((size_t)cbSize * 2);
  1622. if (NULL == pszOleStr)
  1623. {
  1624. error = ResultFromScode(E_OUTOFMEMORY);
  1625. goto errRtn;
  1626. }
  1627. // Convert from ANSI buffer to OLESTR buffer
  1628. if (FALSE==MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszAnsiStr,
  1629. cbSize, pszOleStr, cbSize *2))
  1630. {
  1631. error = HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION);
  1632. PubMemFree(pszOleStr);
  1633. goto errRtn;
  1634. }
  1635. *ppsz = pszOleStr;
  1636. }
  1637. }
  1638. errRtn:
  1639. if (pszAnsiStr)
  1640. {
  1641. PrivMemFree(pszAnsiStr);
  1642. }
  1643. return error;
  1644. }
  1645. //+-------------------------------------------------------------------------
  1646. //
  1647. // Function: GenericObjectToIStorage
  1648. //
  1649. // Synopsis: Write the generic object in memory out to an OLE 2 IStorage
  1650. // This invovles writing the class, native data, and
  1651. // presentation data out where applicable.
  1652. //
  1653. // Arguments: [genobj] -- the generic object holding the info
  1654. // [pstg] -- the IStorage object to write to
  1655. // [ptd] -- target device
  1656. //
  1657. // Returns: NOERROR on success
  1658. // CONVERT10_S_NO_PRESENTATION in cases where the object did
  1659. // not have needed presentation data
  1660. //
  1661. // History: dd-mmm-yy Author Comment
  1662. // 17-Feb-94 davepl Cleanup and document
  1663. //
  1664. // Notes:
  1665. //
  1666. //--------------------------------------------------------------------------
  1667. FARINTERNAL GenericObjectToIStorage(
  1668. const GENOBJ FAR& genobj,
  1669. LPSTORAGE pstg,
  1670. const DVTARGETDEVICE FAR* ptd)
  1671. {
  1672. HRESULT hr = NOERROR;
  1673. // Assert (genobj.m_class.m_clsid != CLSID_NULL);
  1674. // Write the class ID out to the storage
  1675. if (FAILED(hr = WriteClassStg (pstg, genobj.m_class.m_clsid)))
  1676. {
  1677. LEDebugOut(( DEB_ERROR,
  1678. "Unable to WriteClassStg at line %d in %s\n",
  1679. __LINE__, __FILE__));
  1680. return hr;
  1681. }
  1682. if (!genobj.m_fLink)
  1683. {
  1684. if (genobj.m_fStatic)
  1685. {
  1686. // If we are a static embedded object, get the format name from
  1687. // the registration database and write it out to the IStorage
  1688. LPOLESTR pszUserType = NULL;
  1689. OleRegGetUserType(genobj.m_class.m_clsid, USERCLASSTYPE_FULL,
  1690. &pszUserType);
  1691. WriteFmtUserTypeStg (pstg, genobj.m_ppres->m_format.m_cf,
  1692. pszUserType);
  1693. if (pszUserType)
  1694. {
  1695. PubMemFree(pszUserType);
  1696. }
  1697. }
  1698. else if (wWriteFmtUserType (pstg, genobj.m_class.m_clsid) != NOERROR)
  1699. {
  1700. // This happens when the class is not registered.
  1701. // Use ProgId as UserType.
  1702. WriteFmtUserTypeStg (pstg,
  1703. (CLIPFORMAT) RegisterClipboardFormat (genobj.m_class.m_szClsid),
  1704. genobj.m_class.m_szClsid);
  1705. }
  1706. }
  1707. if (FAILED(hr = GenObjToOLE2Stm (pstg, genobj)))
  1708. {
  1709. LEDebugOut(( DEB_ERROR,
  1710. "Unable to write gen obj to stream at line %d in %s\n",
  1711. __LINE__, __FILE__));
  1712. return hr;
  1713. }
  1714. // If it's not a link and not a static object, dump its native
  1715. // data out to the storage
  1716. if (!genobj.m_fLink && !genobj.m_fStatic)
  1717. {
  1718. if (FAILED(hr=Write20NativeStreams (pstg, genobj)))
  1719. {
  1720. LEDebugOut(( DEB_ERROR,
  1721. "Unable to write native stream at line %d in %s\n",
  1722. __LINE__, __FILE__));
  1723. return hr;
  1724. }
  1725. }
  1726. if (! genobj.m_fLink)
  1727. {
  1728. if (genobj.m_class.m_clsid == CLSID_PBrush)
  1729. {
  1730. if (! genobj.m_ppres || (genobj.m_ppres->m_format.m_cf == CF_DIB))
  1731. {
  1732. // If the object is not a link, and it is a PBrush object with
  1733. // either a DIB presentation or no presentation at all, we
  1734. // don't need to do anything.
  1735. return NOERROR;
  1736. }
  1737. }
  1738. if (genobj.m_class.m_clsid == CLSID_MSDraw)
  1739. {
  1740. if (! genobj.m_ppres ||
  1741. (genobj.m_ppres->m_format.m_cf == CF_METAFILEPICT))
  1742. {
  1743. // Similarly, if it is not a link, and it is an MSDraw object
  1744. // with no presentation or a METAFILEPICT presentation, we
  1745. // don't need to do anything.
  1746. return NOERROR;
  1747. }
  1748. }
  1749. }
  1750. // In all other cases, we have to dump the presenation data out to
  1751. // the storage.
  1752. if (FAILED(hr = PresToIStorage (pstg, genobj, ptd)))
  1753. {
  1754. LEDebugOut(( DEB_ERROR,
  1755. "Unable to write pres to IStorage at line %d in %s\n",
  1756. __LINE__, __FILE__));
  1757. return hr;
  1758. }
  1759. // If we are a static object, copy the contents of the presentation
  1760. // stream over to the contents stream.
  1761. if (genobj.m_fStatic)
  1762. {
  1763. UINT uiStatus;
  1764. return UtOlePresStmToContentsStm(pstg, OLE_PRESENTATION_STREAM,
  1765. TRUE, &uiStatus);
  1766. }
  1767. // If we don't have a presentation (but weren't one of the special
  1768. // cases handled above), we have a problem
  1769. //
  1770. // We don't care if genobj.m_pres is NULL if a blank presentation is
  1771. // permited as the routine PresToIStorage will generate a blank pres.
  1772. //
  1773. if ((NULL == genobj.m_ppres) && genobj.m_fNoBlankPres)
  1774. {
  1775. LEDebugOut(( DEB_ERROR,
  1776. "We have no presentation at line %d in %s\n",
  1777. __LINE__, __FILE__));
  1778. return ResultFromScode(CONVERT10_S_NO_PRESENTATION);
  1779. }
  1780. return NOERROR;
  1781. }
  1782. //+-------------------------------------------------------------------------
  1783. //
  1784. // Function: GenObjToOLE2Stm, INTERNAL
  1785. //
  1786. // Synopsis: Write the generic object out to the OLE 2 stream
  1787. //
  1788. // Effects: Write the whole object, including presentation data, etc.
  1789. //
  1790. // Arguments: [pstg] -- the IStorage to write to
  1791. // [genobj] -- the generic object to write
  1792. //
  1793. // Returns: NOERROR on success
  1794. // This is an upper level function, so there are numerous
  1795. // error that could be propagated up through it
  1796. //
  1797. // History: dd-mmm-yy Author Comment
  1798. // 14-Feb-94 davepl Code cleanup and document
  1799. //
  1800. // Notes: The code is enclosed in a do{}while(FALSE) block so that
  1801. // we can break out of it on any error and fall through to
  1802. // the cleanup and error return code.
  1803. //
  1804. //--------------------------------------------------------------------------
  1805. static INTERNAL GenObjToOLE2Stm(LPSTORAGE pstg, const GENOBJ FAR& genobj)
  1806. {
  1807. HRESULT hr = NOERROR;
  1808. LPSTREAM pstm=NULL;
  1809. do { // The do{}while(FALSE) allows us to break out on error
  1810. // Create a stream in the current IStorage
  1811. if (FAILED(hr = OpenOrCreateStream (pstg, OLE_STREAM, &pstm)))
  1812. {
  1813. LEDebugOut(( DEB_ERROR,
  1814. "Can't create streamat line %d in %s\n",
  1815. __LINE__, __FILE__));
  1816. break;
  1817. }
  1818. // Write the Ole version out to that new stream
  1819. if (FAILED(hr = ULToOLE2Stm (pstm, gdwOleVersion)))
  1820. {
  1821. break;
  1822. }
  1823. // Write the object flags (for links only, otherwise 0) to the stream
  1824. if (FAILED(hr = ULToOLE2Stm
  1825. (pstm, genobj.m_fLink ? OBJFLAGS_LINK : 0L)))
  1826. {
  1827. break;
  1828. }
  1829. // Write the update options out to the stream
  1830. if (genobj.m_fLink || genobj.m_class.m_clsid == CLSID_StdOleLink)
  1831. {
  1832. // If our object's link update options are UPDATE_ONCALL, we
  1833. // write out the corresponding OLE 2 flags, otherwise, we
  1834. // write out OLEUPDATE_ALWAYS
  1835. if (genobj.m_lnkupdopt==UPDATE_ONCALL)
  1836. {
  1837. if (FAILED(hr = ULToOLE2Stm (pstm, OLEUPDATE_ONCALL)))
  1838. {
  1839. break;
  1840. }
  1841. }
  1842. else
  1843. {
  1844. if (FAILED(hr = ULToOLE2Stm (pstm, OLEUPDATE_ALWAYS)))
  1845. {
  1846. break;
  1847. }
  1848. }
  1849. }
  1850. else
  1851. {
  1852. // We are neither a link nor a StdOleLink, so we have no
  1853. // update options.. just write out a 0.
  1854. if (FAILED(hr = ULToOLE2Stm (pstm, 0L)))
  1855. {
  1856. break;
  1857. }
  1858. }
  1859. // This is a reserved filed (was View Format), just write a 0
  1860. if (FAILED(hr = ULToOLE2Stm (pstm, 0L)))
  1861. {
  1862. break;
  1863. }
  1864. // We have no relative moniker, write out NULL
  1865. if (FAILED(hr = WriteMonikerStm (pstm, (LPMONIKER)NULL)))
  1866. {
  1867. LEDebugOut(( DEB_ERROR,
  1868. "Unable to write moniker to stream at line %d in %s\n",
  1869. __LINE__, __FILE__));
  1870. break;
  1871. }
  1872. // If we are a link, we have to write out all of that information...
  1873. if (genobj.m_fLink || genobj.m_class.m_clsid == CLSID_StdOleLink)
  1874. {
  1875. // relative source moniker
  1876. if (FAILED(hr = WriteMonikerStm (pstm, (LPMONIKER)NULL)))
  1877. {
  1878. LEDebugOut(( DEB_ERROR,
  1879. "Unable to write moniker to stream at line %d in %s\n",
  1880. __LINE__, __FILE__));
  1881. break;
  1882. }
  1883. // absolute source moniker
  1884. if (FAILED(hr = MonikerToOLE2Stm (pstm, genobj.m_szTopic,
  1885. genobj.m_szItem, genobj.m_classLast.m_clsid)))
  1886. {
  1887. LEDebugOut(( DEB_ERROR,
  1888. "Unable to write moniker to stream at line %d in %s\n",
  1889. __LINE__, __FILE__));
  1890. break;
  1891. }
  1892. // write the classLast field to the stream
  1893. CLSID clsid;
  1894. // If we have the classLast already, use that clsid
  1895. if (genobj.m_classLast.m_szClsid)
  1896. {
  1897. clsid = genobj.m_classLast.m_clsid;
  1898. }
  1899. else
  1900. {
  1901. // Otherwise, if it's a StdOleLink, class id is NULL
  1902. if (genobj.m_class.m_clsid == CLSID_StdOleLink)
  1903. {
  1904. clsid = CLSID_NULL;
  1905. }
  1906. else
  1907. {
  1908. // If we don't have last class and not a link, use the
  1909. // class id of the generic object
  1910. clsid = genobj.m_class.m_clsid;
  1911. }
  1912. }
  1913. if (FAILED(hr = WriteM1ClassStm(pstm, clsid)))
  1914. {
  1915. LEDebugOut(( DEB_ERROR,
  1916. "Unable to write M1 to stream at line %d in %s\n",
  1917. __LINE__, __FILE__));
  1918. break;
  1919. }
  1920. // last display == NULL string
  1921. if (FAILED(hr = ULToOLE2Stm (pstm, 0L)))
  1922. {
  1923. break;
  1924. }
  1925. // Last Change time
  1926. if (FAILED(hr = FTToOle2Stm (pstm)))
  1927. {
  1928. break;
  1929. }
  1930. // Last known up to date
  1931. if (FAILED(hr = FTToOle2Stm (pstm)))
  1932. {
  1933. break;
  1934. }
  1935. // rtUpdate
  1936. if (FAILED(hr = FTToOle2Stm (pstm)))
  1937. {
  1938. break;
  1939. }
  1940. // end marker
  1941. if (FAILED(hr = ULToOLE2Stm(pstm, (ULONG) -1L)))
  1942. {
  1943. break;
  1944. }
  1945. }
  1946. } while (FALSE); // This do{}while(FALSE) is a once-through "loop"
  1947. // that we can break out of on error and fall
  1948. // through to the return.
  1949. if (pstm)
  1950. {
  1951. pstm->Release();
  1952. }
  1953. return hr;
  1954. }
  1955. //+-------------------------------------------------------------------------
  1956. //
  1957. // Function: MonikerToOLE2Stm, INTERNAL
  1958. //
  1959. // Synopsis: Write the file and item moniker as a composite to the stream
  1960. //
  1961. // Effects: Builds a composite of the file and item monikers, and then
  1962. // writes them out. If there is no file, a NULL moniker is
  1963. // written in its place
  1964. //
  1965. // Arguments: [pstm] -- The OLE2 storage we are writing to
  1966. // [pszFile] -- The file associated with the object
  1967. // [spzItem] -- The item
  1968. // [clsid] -- The class ID of the object
  1969. //
  1970. // Returns: NOERROR on success
  1971. //
  1972. // History: dd-mmm-yy Author Comment
  1973. // 18-Feb-94 davepl Reworked, cleaned up and documented
  1974. //
  1975. // Notes:
  1976. //
  1977. //--------------------------------------------------------------------------
  1978. #pragma SEG(MonikerToOLE2Stm)
  1979. static INTERNAL MonikerToOLE2Stm(
  1980. LPSTREAM pstm,
  1981. LPOLESTR szFile,
  1982. LPOLESTR szItem,
  1983. CLSID clsid) // CLSID of the link source file, szFile
  1984. {
  1985. HRESULT hr = NOERROR;
  1986. LPMONIKER pmkFile = NULL; // File moniker
  1987. LPMONIKER pmkItem = NULL; // Item moniker
  1988. LPMONIKER pmkComp = NULL; // Composite of file + item monikers
  1989. // If we don't have a file, write a NULL moniker
  1990. if (NULL == szFile)
  1991. {
  1992. if (FAILED(hr = WriteMonikerStm (pstm, NULL)))
  1993. {
  1994. goto errRtn;
  1995. }
  1996. }
  1997. else
  1998. {
  1999. // Otherwise, create a file moniker (OLE1 or OLE2 as appplicable)
  2000. if (CoIsOle1Class (clsid))
  2001. {
  2002. if (FAILED(hr = CreateOle1FileMoniker (szFile, clsid, &pmkFile)))
  2003. {
  2004. LEDebugOut(( DEB_ERROR,
  2005. "Can't create OLE 1 moniker at line %d in %s\n",
  2006. __LINE__, __FILE__));
  2007. goto errRtn;
  2008. }
  2009. }
  2010. else
  2011. {
  2012. if (FAILED(hr = CreateFileMoniker (szFile, &pmkFile)))
  2013. {
  2014. LEDebugOut(( DEB_ERROR,
  2015. "Can't create file moniker at line %d in %s\n",
  2016. __LINE__, __FILE__));
  2017. goto errRtn;
  2018. }
  2019. }
  2020. // If we don't have an Item, write just the file moniker
  2021. if (NULL==szItem)
  2022. {
  2023. if (FAILED(hr = WriteMonikerStm (pstm, pmkFile)))
  2024. {
  2025. LEDebugOut(( DEB_ERROR,
  2026. "Unable to write moniker to stream at line %d in %s\n",
  2027. __LINE__, __FILE__));
  2028. goto errRtn;
  2029. }
  2030. }
  2031. // Otherwise, create a composite of the file + item monikers
  2032. // and write it out
  2033. else
  2034. {
  2035. if (FAILED(hr=CreateItemMoniker(OLESTR("!"), szItem, &pmkItem)))
  2036. {
  2037. LEDebugOut(( DEB_ERROR,
  2038. "Unable to create item moniker at line %d in %s\n",
  2039. __LINE__, __FILE__));
  2040. goto errRtn;
  2041. }
  2042. if (FAILED(hr=CreateGenericComposite(pmkFile, pmkItem, &pmkComp)))
  2043. {
  2044. LEDebugOut(( DEB_ERROR,
  2045. "Unable to create generic pres at line %d in %s\n",
  2046. __LINE__, __FILE__));
  2047. goto errRtn;
  2048. }
  2049. if (FAILED(hr = WriteMonikerStm (pstm, pmkComp)))
  2050. {
  2051. LEDebugOut(( DEB_ERROR,
  2052. "Unable to write moniker to stream at line %d in %s\n",
  2053. __LINE__, __FILE__));
  2054. goto errRtn;
  2055. }
  2056. }
  2057. }
  2058. errRtn:
  2059. if (pmkFile)
  2060. {
  2061. pmkFile->Release();
  2062. }
  2063. if (pmkItem)
  2064. {
  2065. pmkItem->Release();
  2066. }
  2067. if (pmkComp)
  2068. {
  2069. pmkComp->Release();
  2070. }
  2071. return hr;
  2072. }
  2073. //+-------------------------------------------------------------------------
  2074. //
  2075. // Function: IsStandardFormat, INTERNAL
  2076. //
  2077. // Synopsis: Returns TRUE if object is in clipboard format and is one
  2078. // one of the three standard formats (METAFILE, DIB, BITMAP)
  2079. //
  2080. // Arguments: [format] -- the format object which contains the
  2081. // format tag and clipboard format type
  2082. //
  2083. // Returns: TRUE if METAFILE, DIB, or BITMAP
  2084. // FALSE if other format or not clipboard format at all
  2085. //
  2086. // History: dd-mmm-yy Author Comment
  2087. // 16-Feb-94 davepl documented and chaged from big
  2088. // conditional to a switch()
  2089. // Notes:
  2090. //
  2091. //--------------------------------------------------------------------------
  2092. static INTERNAL_(BOOL) IsStandardFormat(const FORMAT FAR& format)
  2093. {
  2094. // First we must ensure that the format tag indicates that this
  2095. // object is in clipboard format at all...
  2096. if (format.m_ftag == ftagClipFormat)
  2097. {
  2098. // If so, there is a limited set of clipboard formats which
  2099. // we consider "standard". If it is not among these,
  2100. // we return FALSE.
  2101. switch(format.m_cf)
  2102. {
  2103. case CF_METAFILEPICT:
  2104. case CF_BITMAP:
  2105. case CF_DIB:
  2106. return TRUE;
  2107. default:
  2108. return FALSE;
  2109. }
  2110. }
  2111. return FALSE;
  2112. }
  2113. //+-------------------------------------------------------------------------
  2114. //
  2115. // Function: PresToIStorage, INTERNAL
  2116. //
  2117. // Synopsis: Given an generic object and an IStorage, write genobj's
  2118. // presentation data out to the storage
  2119. //
  2120. // Effects: Will call PresToNewOLE2Stm to create a stream in this
  2121. // storage to hold the presentation data
  2122. //
  2123. // Arguments: [pstg] -- the storage to save to
  2124. // [genobj] -- the generic object holding the presenation
  2125. // [ptd] -- the target device for the presentation
  2126. //
  2127. // Returns: NOERROR on success
  2128. // Various other errors may propagate back up from I/O funcs
  2129. //
  2130. // History: dd-mmm-yy Author Comment
  2131. // 18-Feb-94 davepl ARRGR! Cleanup and document
  2132. // Notes:
  2133. //
  2134. //--------------------------------------------------------------------------
  2135. static INTERNAL PresToIStorage(
  2136. LPSTORAGE pstg,
  2137. const GENOBJ FAR& genobj,
  2138. const DVTARGETDEVICE FAR* ptd)
  2139. {
  2140. HRESULT hr = NOERROR;
  2141. if (genobj.m_fNoBlankPres)
  2142. {
  2143. return NOERROR;
  2144. }
  2145. PRES pres;
  2146. if (NULL==genobj.m_ppres)
  2147. {
  2148. // If we're not a link, and we don't have a presentation, we will
  2149. // create a blank presentation and write it out. If we are a link,
  2150. // we will do nothing, and just fall through to the return.
  2151. if (!genobj.m_fLink)
  2152. {
  2153. if (FAILED(hr = CreateBlankPres (&pres)))
  2154. {
  2155. LEDebugOut(( DEB_ERROR,
  2156. "Unable to create blank pres at line %d in %s\n",
  2157. __LINE__, __FILE__));
  2158. return hr;
  2159. }
  2160. if (FAILED(hr = PresToNewOLE2Stm
  2161. (pstg, genobj.m_fLink, pres, ptd, OLE_PRESENTATION_STREAM)))
  2162. {
  2163. LEDebugOut(( DEB_ERROR,
  2164. "Unable to write pres to new stream at line %d in %s\n",
  2165. __LINE__, __FILE__));
  2166. return hr;
  2167. }
  2168. }
  2169. }
  2170. else
  2171. {
  2172. // If the object did indeed have a presentation, we write it
  2173. // out to a new stream
  2174. if (IsStandardFormat (genobj.m_ppres->m_format))
  2175. {
  2176. // If the presentation is a standard clipboard
  2177. // format, we can write it out with no other work
  2178. if (FAILED(hr = PresToNewOLE2Stm ( pstg,
  2179. genobj.m_fLink,
  2180. *(genobj.m_ppres),
  2181. ptd,
  2182. OLE_PRESENTATION_STREAM)))
  2183. {
  2184. LEDebugOut(( DEB_ERROR,
  2185. "Unable to write pres to new stream at line %d in %s\n",
  2186. __LINE__, __FILE__));
  2187. return hr;
  2188. }
  2189. }
  2190. else
  2191. {
  2192. // If the presentation is not a standard format,
  2193. // it may be a PBrush object (handled below), or if
  2194. // not, we write it as a generic presentation stream
  2195. if (genobj.m_classLast.m_clsid != CLSID_PBrush)
  2196. {
  2197. if(FAILED(hr = PresToNewOLE2Stm ( pstg,
  2198. genobj.m_fLink,
  2199. *(genobj.m_ppres),
  2200. ptd,
  2201. OLE_PRESENTATION_STREAM)))
  2202. {
  2203. LEDebugOut(( DEB_ERROR,
  2204. "Unable to write pres to new stream at line %d in %s\n",
  2205. __LINE__, __FILE__));
  2206. return hr;
  2207. }
  2208. }
  2209. else // PBrush
  2210. {
  2211. BOOL fPBrushNative = FALSE;
  2212. // We know this is a PBrush object. If the
  2213. // format tag is a format string, check to see
  2214. // if that string is "Native", in which case
  2215. // we set the flag to indicate that this is
  2216. // native pbrush data.
  2217. if (genobj.m_ppres->m_format.m_ftag == ftagString)
  2218. {
  2219. if (!strcmp( (LPCSTR) genobj.m_ppres->
  2220. m_format.m_dataFormatString.m_pv,
  2221. "Native"
  2222. )
  2223. )
  2224. {
  2225. fPBrushNative = TRUE;
  2226. }
  2227. }
  2228. if (FAILED(hr = PresToNewOLE2Stm( pstg,
  2229. genobj.m_fLink,
  2230. *(genobj.m_ppres),
  2231. ptd,
  2232. OLE_PRESENTATION_STREAM,
  2233. fPBrushNative)))
  2234. {
  2235. LEDebugOut(( DEB_ERROR,
  2236. "Unable to write pres to new stream at line %d in %s\n",
  2237. __LINE__, __FILE__));
  2238. return hr;
  2239. }
  2240. }
  2241. }
  2242. }
  2243. return NOERROR;
  2244. }
  2245. //+-------------------------------------------------------------------------
  2246. //
  2247. // Function: PresToNewOLE2Stm, INTERNAL
  2248. //
  2249. // Synopsis: Creates a new stream within a storage and writes the
  2250. // generic object's presentation data out to it.
  2251. //
  2252. // Arguments: [pstg] -- the storage in which to create the stream
  2253. // [fLink] -- flag: is this object a link?
  2254. // [pres] -- the presentation data to be saved
  2255. // [ptd] -- the target render device
  2256. // [szStream] -- the name of the new stream
  2257. // [fPBrushNative] -- flag: is this native PBrush pres data?
  2258. //
  2259. // Returns: NOERROR on success
  2260. // STG_E_WRITEFAULT on stream write failure
  2261. //
  2262. // History: dd-mmm-yy Author Comment
  2263. // 21-Feb-94 davepl Code cleanup and documentation
  2264. //
  2265. // Notes:
  2266. //
  2267. //--------------------------------------------------------------------------
  2268. static INTERNAL PresToNewOLE2Stm(
  2269. LPSTORAGE pstg,
  2270. BOOL fLink,
  2271. const PRES FAR& pres,
  2272. const DVTARGETDEVICE FAR* ptd,
  2273. LPOLESTR szStream,
  2274. BOOL fPBrushNative
  2275. )
  2276. {
  2277. HRESULT hr = NOERROR;
  2278. LPSTREAM pstm=NULL;
  2279. FORMATETC foretc;
  2280. // Create the new stream to hold the presentation data
  2281. if (FAILED(hr = OpenOrCreateStream (pstg, szStream, &pstm)))
  2282. {
  2283. goto errRtn;
  2284. }
  2285. // Fill in the FormatEtc structure
  2286. if (fPBrushNative)
  2287. {
  2288. foretc.cfFormat = CF_DIB;
  2289. }
  2290. else
  2291. {
  2292. switch( pres.m_format.m_ftag)
  2293. {
  2294. case ftagClipFormat:
  2295. foretc.cfFormat = pres.m_format.m_cf;
  2296. break;
  2297. case ftagString:
  2298. // m_dataFormatString is an ASCII string.
  2299. foretc.cfFormat = (CLIPFORMAT) SSRegisterClipboardFormatA( (LPCSTR) pres.m_format.m_dataFormatString.m_pv);
  2300. Assert(0 != foretc.cfFormat);
  2301. break;
  2302. default:
  2303. AssertSz(0,"Error in Format");
  2304. hr = E_UNEXPECTED;
  2305. goto errRtn;
  2306. break;
  2307. }
  2308. }
  2309. foretc.ptd = (DVTARGETDEVICE *) ptd;
  2310. foretc.dwAspect = DVASPECT_CONTENT;
  2311. foretc.lindex = -1;
  2312. foretc.tymed = TYMED_NULL; // tymed field is ignored by utWriteOlePresStmHeader.
  2313. if (FAILED(hr = UtWriteOlePresStmHeader(pstm,&foretc,(fLink) ? (ADVF_PRIMEFIRST) : (0L))))
  2314. {
  2315. goto errRtn;
  2316. }
  2317. if (fPBrushNative)
  2318. {
  2319. if (FAILED(hr = UtHDIBFileToOlePresStm(pres.m_data.m_h, pstm)))
  2320. {
  2321. LEDebugOut(( DEB_ERROR,
  2322. "Unable to write DIB to stream at line %d in %s\n",
  2323. __LINE__, __FILE__));
  2324. goto errRtn;
  2325. }
  2326. }
  2327. else
  2328. {
  2329. // Compression
  2330. if (FAILED(hr = ULToOLE2Stm (pstm, 0L)))
  2331. {
  2332. goto errRtn;
  2333. }
  2334. // Width / Height
  2335. if (FAILED(hr = ULToOLE2Stm (pstm, pres.m_ulWidth)))
  2336. {
  2337. goto errRtn;
  2338. }
  2339. if (FAILED(hr = ULToOLE2Stm (pstm, pres.m_ulHeight)))
  2340. {
  2341. goto errRtn;
  2342. }
  2343. // Presentation data
  2344. if (FAILED(hr = DataObjToOLE2Stm (pstm, pres.m_data)))
  2345. {
  2346. goto errRtn;
  2347. }
  2348. }
  2349. errRtn:
  2350. if (pstm)
  2351. {
  2352. pstm->Release();
  2353. }
  2354. return hr;
  2355. }
  2356. //+-------------------------------------------------------------------------
  2357. //
  2358. // Function: ULToOLE2Stm, INTERNAL
  2359. //
  2360. // Synopsis: Writes a ULONG out to an OLE2 stream
  2361. //
  2362. // Arguments: [pstm] -- the stream to write to
  2363. // [ul] -- the ULONG to write to that stream
  2364. //
  2365. // Returns: NOERROR on success
  2366. // STG_E_WRITEFAULT on write failure
  2367. //
  2368. // History: dd-mmm-yy Author Comment
  2369. // 18-Feb-94 davepl Cleaned up and documented
  2370. //
  2371. //--------------------------------------------------------------------------
  2372. inline static INTERNAL ULToOLE2Stm(LPSTREAM pstm, ULONG ul)
  2373. {
  2374. // Write the ULONG out
  2375. return pstm->Write (&ul, sizeof(ULONG), NULL);
  2376. }
  2377. //+-------------------------------------------------------------------------
  2378. //
  2379. // Function: FTToOLE2Stm, INTERNAL
  2380. //
  2381. // Synopsis: Writes a dummy filetime out to an OLE2 stream
  2382. //
  2383. // Arguments: [pstm] -- the stream to write to
  2384. //
  2385. // Returns: NOERROR on success
  2386. // STG_E_WRITEFAULT on write failure
  2387. //
  2388. // History: dd-mmm-yy Author Comment
  2389. // 31-Mar-95 scottsk Created
  2390. //
  2391. //--------------------------------------------------------------------------
  2392. inline static INTERNAL FTToOle2Stm(LPSTREAM pstm)
  2393. {
  2394. FILETIME ft = { 0, 0 };
  2395. return pstm->Write (&ft, sizeof(FILETIME), NULL);
  2396. }
  2397. //+-------------------------------------------------------------------------
  2398. //
  2399. // Function: DataObjToOLE2Stm
  2400. //
  2401. // Synopsis: Writes a fixed-size data buffer to an OLE2 stream preceded
  2402. // by a ULONG indicating the number of bytes to follow.
  2403. //
  2404. // Returns: NOERROR on success
  2405. // STG_E_WRITEFAULT on write failure
  2406. //
  2407. // History: dd-mmm-yy Author Comment
  2408. // 18-Feb-94 davepl Code cleanup
  2409. // Notes:
  2410. //
  2411. //--------------------------------------------------------------------------
  2412. static INTERNAL DataObjToOLE2Stm(LPSTREAM pstm, const DATA FAR& data)
  2413. {
  2414. HRESULT hr;
  2415. // Write a ULONG indicating the number of bytes to follow
  2416. if (FAILED(hr = ULToOLE2Stm (pstm, data.m_cbSize)))
  2417. {
  2418. return hr;
  2419. }
  2420. // If there are any bytes to follow...
  2421. if (data.m_cbSize)
  2422. {
  2423. if (FAILED(hr = pstm->Write (data.m_pv, data.m_cbSize, NULL)))
  2424. {
  2425. return hr;
  2426. }
  2427. }
  2428. return NOERROR;
  2429. }
  2430. //+-------------------------------------------------------------------------
  2431. //
  2432. // Function: SizedDataToOLE1Stm
  2433. //
  2434. // Synopsis: Writes a fixed-size data buffer to an OLE1 stream preceded
  2435. // by a ULONG indicating the number of bytes to follow.
  2436. //
  2437. // Parameters: [pos] -- The stream to write to
  2438. // [data] -- The data object to write out
  2439. //
  2440. // Returns: NOERROR on success
  2441. // STG_E_WRITEFAULT on write failure
  2442. //
  2443. // History: dd-mmm-yy Author Comment
  2444. // 18-Feb-94 davepl Code cleanup
  2445. // Notes:
  2446. //
  2447. //--------------------------------------------------------------------------
  2448. static INTERNAL SizedDataToOLE1Stm(LPOLESTREAM pos, const DATA FAR& data)
  2449. {
  2450. HRESULT hr = NOERROR;
  2451. // Ensure the memory we are going to write out is valid
  2452. Assert (data.m_pv);
  2453. // Write the ULONG representing the byte count of the sized data
  2454. if (FAILED(hr = ULToOLE1Stream (pos, data.m_cbSize)))
  2455. {
  2456. Assert (0 && "Can't write UL to ole1 stream");
  2457. return hr;
  2458. }
  2459. if (pos->lpstbl->Put (pos, data.m_pv, data.m_cbSize) < data.m_cbSize)
  2460. {
  2461. Assert (0 && "Cant write sized data to ole1 stream");
  2462. return ResultFromScode(CONVERT10_E_OLESTREAM_PUT);
  2463. }
  2464. return NOERROR;
  2465. }
  2466. //+-------------------------------------------------------------------------
  2467. //
  2468. // Function: Write20NativeStreams, INTERNAL
  2469. //
  2470. // Synopsis: Writes the generic object's native data out to an OLE 2 stream
  2471. //
  2472. // Effects: Creates an ILockBytes on the handle to the native data, and
  2473. // then attempts to create a storage on it. If it can, it uses
  2474. // the CopyTo interface to write that storage into our OLE 2
  2475. // stream. Otherwise, it manually creates a stream in the OLE 2
  2476. // storage and dumps the native data into it.
  2477. //
  2478. // Arguments: [pstg] -- the OLE 2 storage we are saving genobj to
  2479. // [genobj] -- the generic object we are writing
  2480. //
  2481. // Returns: NOERROR on success
  2482. // E_OUTOFMEMORY on allocation failure
  2483. // STG_E_WRITEFAULT on storage write failure
  2484. //
  2485. // History: dd-mmm-yy Author Comment
  2486. // 18-Feb-94 davepl Removed 14 goto's (for better or worse)
  2487. // See "Notes" for new control flow
  2488. // 24-Mar-94 alext Fix OLE 1 native case (there was an
  2489. // extra stream open)
  2490. //
  2491. // Notes: There are two possible major codepaths based on the creation
  2492. // of the Stg on ILockBytes. The outcome is handled by a
  2493. // switch statement, and both the TRUE and FALSE cases are
  2494. // loaded with break statements that will bail out to the
  2495. // bottom of the function on any failure. This gives us a
  2496. // single entry and exit point, without all the gotos
  2497. //
  2498. //--------------------------------------------------------------------------
  2499. static INTERNAL Write20NativeStreams(LPSTORAGE pstg, const GENOBJ FAR& genobj)
  2500. {
  2501. LPLOCKBYTES plkbyt = NULL;
  2502. LPSTORAGE pstgNative = NULL;
  2503. LPSTREAM pstmNative = NULL;
  2504. HRESULT hr = NOERROR;
  2505. // Create an ILockBytes instance on our generic object's native data
  2506. if (SUCCEEDED(hr = CreateILockBytesOnHGlobal
  2507. (genobj.m_dataNative.m_h, FALSE, &plkbyt)))
  2508. {
  2509. // If the ILockBytes appears to contain an IStorage, then this was
  2510. // an OLE 2 object "hiding" within the OLE 1 stream as native data
  2511. switch ((DWORD)(S_OK == StgIsStorageILockBytes (plkbyt)))
  2512. {
  2513. case (TRUE):
  2514. // Open the IStorage contained in the ILockBytes
  2515. if (FAILED(hr = StgOpenStorageOnILockBytes (plkbyt,
  2516. (LPSTORAGE)NULL,
  2517. STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT,
  2518. (SNB)NULL,
  2519. 0,
  2520. &pstgNative)))
  2521. {
  2522. LEDebugOut(( DEB_ERROR,
  2523. "Can't open storage on ILBytes at line %d in %s\n",
  2524. __LINE__, __FILE__));
  2525. break; // on failure fall through to error return
  2526. }
  2527. // Remove the stream from the native data
  2528. if (FAILED(hr = UtDoStreamOperation(pstgNative,
  2529. NULL, // pstgDst
  2530. OPCODE_REMOVE, // operation
  2531. STREAMTYPE_CACHE))) // stream
  2532. {
  2533. LEDebugOut(( DEB_ERROR,
  2534. "OPCODE REMOVE stream op failed at line %d in %s\n",
  2535. __LINE__, __FILE__));
  2536. break; // on failure fall through to error return
  2537. }
  2538. // Copy the "hidden" IStorage to our destination storage
  2539. if (FAILED(hr = pstgNative->CopyTo (0, NULL,(SNB)NULL, pstg)))
  2540. {
  2541. LEDebugOut(( DEB_ERROR,
  2542. "CopyTo member fn failed at line %d in %s\n",
  2543. __LINE__, __FILE__));
  2544. break; // on failure fall through to error return
  2545. }
  2546. break; // end case TRUE
  2547. case FALSE:
  2548. // This is the typical case, where the OLE 1 stream had just
  2549. // plain old native data, so write it to a stream inside our
  2550. // output IStorage and call it OLE10_NATIVE_STREAM
  2551. ULONG cb;
  2552. LPVOID pv = genobj.m_dataNative.m_pv;
  2553. if (NULL == pv)
  2554. {
  2555. hr = ResultFromScode(E_OUTOFMEMORY);
  2556. break;
  2557. }
  2558. // Create the new stream to hold the native data
  2559. if (FAILED(hr = OpenOrCreateStream
  2560. (pstg, OLE10_NATIVE_STREAM, &pstmNative)))
  2561. {
  2562. break; // on failure fall through to error return
  2563. }
  2564. // Write the length of the native data to the stream
  2565. if (FAILED(hr = pstmNative->Write
  2566. (&genobj.m_dataNative.m_cbSize, sizeof(ULONG), &cb)))
  2567. {
  2568. break; // on failure fall through to error return
  2569. }
  2570. // Now write the actual native data
  2571. if (FAILED(hr = pstmNative->Write
  2572. (pv, genobj.m_dataNative.m_cbSize, &cb)))
  2573. {
  2574. break; // on failure fall through to error return
  2575. }
  2576. // Write out the item name
  2577. if (genobj.m_szItem)
  2578. {
  2579. ULONG cchItem;
  2580. LPSTR pszAnsiItem;
  2581. int cbWritten;
  2582. // We need to convert m_szItem from Wide to Ansi
  2583. // The ANSI string is bounded by the byte length of the
  2584. // Unicode string (one Unicode character maximally translates
  2585. // to one double-byte char, so we just use that length
  2586. cchItem = lstrlenW(genobj.m_szItem) + 1;
  2587. pszAnsiItem = (LPSTR) PrivMemAlloc(cchItem * sizeof(OLECHAR));
  2588. if (NULL == pszAnsiItem)
  2589. {
  2590. hr = E_OUTOFMEMORY;
  2591. break;
  2592. }
  2593. // We've got out buffer and our length, so do the conversion now
  2594. // We don't need to check for cbSize == FALSE since that was
  2595. // already done during the length test, but we need to check
  2596. // for substitution. Iff this call sets the fDefChar even when
  2597. // only doing a length check, these two tests could be merged,
  2598. // but I don't believe this is the case.
  2599. BOOL fDefUsed = 0;
  2600. cbWritten = WideCharToMultiByte(CP_ACP, // Code Page ANSI
  2601. 0, // No flags
  2602. genobj.m_szItem, // Input OLESTR
  2603. cchItem, // Input len (auto detect)
  2604. pszAnsiItem, // Output buffer
  2605. cchItem * sizeof(OLECHAR), // Output len
  2606. NULL, // Default char (use system's)
  2607. &fDefUsed); // Flag: Default char used
  2608. // If number of bytes converted was 0, we failed
  2609. if ((FALSE == cbWritten) || fDefUsed)
  2610. {
  2611. hr = ResultFromScode(E_UNSPEC);
  2612. }
  2613. else
  2614. {
  2615. // Write the size of the string (including null terminator) to stream
  2616. hr = StSave10ItemName(pstg, pszAnsiItem);
  2617. }
  2618. PrivMemFree(pszAnsiItem);
  2619. if (FAILED(hr))
  2620. {
  2621. break; // on failure fall through to error return
  2622. }
  2623. }
  2624. break;
  2625. } // end switch
  2626. } // end if
  2627. // Free up any resources that may have been allocated in any of the
  2628. // code paths above
  2629. if (NULL != plkbyt)
  2630. {
  2631. plkbyt->Release();
  2632. }
  2633. if (NULL != pstgNative)
  2634. {
  2635. pstgNative->Release();
  2636. }
  2637. if (NULL != pstmNative)
  2638. {
  2639. pstmNative->Release();
  2640. }
  2641. return hr;
  2642. }
  2643. //+-------------------------------------------------------------------------
  2644. //
  2645. // Function: wConvertIStorageToOLESTREAM, INTERNAL
  2646. //
  2647. // Synopsis: Worker function; brings object from the IStorage into
  2648. // the internal generic object representation
  2649. //
  2650. // Arguments: [pstg] -- the IStorage the object resides in
  2651. // [polestream]-- the OLE 1 stream it will be going to
  2652. // [pgenobj] -- the generic object to hold the internal rep
  2653. //
  2654. // Returns: NOERROR on success
  2655. // STG_E_FILENOTFOUND bad IStorage
  2656. // CONVERT10_E_STG_NO_STD_STREAM the IStorage was missing one
  2657. // of the required standard streams
  2658. //
  2659. // History: dd-mmm-yy Author Comment
  2660. // 21-Feb-94 davepl Code cleanup and documentation
  2661. //
  2662. // Notes:
  2663. //
  2664. //--------------------------------------------------------------------------
  2665. INTERNAL wConvertIStorageToOLESTREAM (
  2666. LPSTORAGE pstg,
  2667. LPOLESTREAM polestream,
  2668. PGENOBJ pgenobj
  2669. )
  2670. {
  2671. SCODE scode = S_OK;
  2672. VDATEIFACE (pstg);
  2673. // Ensure that all of the pointers are valid
  2674. #if DBG==1
  2675. if (!IsValidReadPtrIn (polestream, sizeof(OLESTREAM)) ||
  2676. !IsValidReadPtrIn (polestream->lpstbl, sizeof(OLESTREAMVTBL)) ||
  2677. !IsValidCodePtr ((FARPROC)polestream->lpstbl->Put))
  2678. {
  2679. LEDebugOut(( DEB_ERROR,
  2680. "Bad OLESTREAM at line %d in %s\n",
  2681. __LINE__, __FILE__));
  2682. return ResultFromScode (E_INVALIDARG);
  2683. }
  2684. #endif
  2685. scode = GetScode (StorageToGenericObject (pstg, pgenobj));
  2686. // If the storage was not there, modify the return code to
  2687. // make it specific to the conversion process, otherwise just
  2688. // return whatever error code came back.
  2689. if (scode != S_OK)
  2690. {
  2691. if (scode == STG_E_FILENOTFOUND)
  2692. {
  2693. return ResultFromScode(CONVERT10_E_STG_NO_STD_STREAM);
  2694. }
  2695. else
  2696. {
  2697. return ResultFromScode(scode);
  2698. }
  2699. }
  2700. return NOERROR;
  2701. }
  2702. //+-------------------------------------------------------------------------
  2703. //
  2704. // Function: OleConvertIStorageToOLESTREAM, STDAPI
  2705. //
  2706. // Synopsis: Reads an object from an IStorage into a generic internal
  2707. // representation, then writes it back out to an OLE 1 stream
  2708. //
  2709. // Arguments: [pstg] -- the IStorage to read from
  2710. // [polestream] -- the OLESTREAM to write to
  2711. //
  2712. // Returns: NOERROR on success
  2713. // CONVERT10_E_STG_NO_STD_STREAM when one of the needed streams
  2714. // inside the IStorage was not
  2715. // present
  2716. // E_INVALIDARG bad input argument
  2717. //
  2718. // History: dd-mmm-yy Author Comment
  2719. // 21-Feb-94 davepl Cleanup and documentation
  2720. //
  2721. // Notes:
  2722. //
  2723. //--------------------------------------------------------------------------
  2724. STDAPI OleConvertIStorageToOLESTREAM(LPSTORAGE pstg, LPOLESTREAM polestream)
  2725. {
  2726. OLETRACEIN((API_OleConvertIStorageToOLESTREAM,
  2727. PARAMFMT("pstg= %p, polestream= %p"), pstg, polestream));
  2728. LEDebugOut((DEB_TRACE, "%p _IN OleConvertIStorageToOLESTREAM ("
  2729. " %p , %p )\n", 0 /*function*/,
  2730. pstg, polestream
  2731. ));
  2732. CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IStorage,(IUnknown **)&pstg);
  2733. HRESULT hr;
  2734. CGenericObject genobj;
  2735. // Read from the IStorage into the generic object
  2736. hr = wConvertIStorageToOLESTREAM(pstg, polestream, &genobj);
  2737. if (FAILED(hr))
  2738. {
  2739. goto errRtn;
  2740. }
  2741. // Write from the generic object out to the OLE 1 stream
  2742. hr = GenericObjectToOLESTREAM (genobj, polestream);
  2743. errRtn:
  2744. LEDebugOut((DEB_TRACE,"%p OUT OleConvertIStorageToOLESTREAM ( %lx ) "
  2745. "\n", 0 /*function*/, hr));
  2746. OLETRACEOUT((API_OleConvertIStorageToOLESTREAM, hr));
  2747. return hr;
  2748. }
  2749. //+-------------------------------------------------------------------------
  2750. //
  2751. // Function: wFillPpres, INTERNAL
  2752. //
  2753. // Synopsis: Fills in the generic object's presentation data by
  2754. // building a presentation out of the native data
  2755. //
  2756. // Arguments: [pstg] -- the IStorage we are reading from
  2757. // [pgenobj] -- the generic object
  2758. // [cfFormat] -- what clipboard format is being used
  2759. // [fOle10Native] -- flag: is this OLE 1 native data?
  2760. //
  2761. // Returns: NOERROR on success
  2762. // E_OUTOFMEMORY can't allocate mem for PRES member
  2763. //
  2764. // History: dd-mmm-yy Author Comment
  2765. // 21-Feb-94 davepl Code cleanup, documentation
  2766. // 19-Jul-94 davepl Fixed HMETAFILE cases
  2767. //
  2768. // Notes: Since most of this code treats HMETAFILE handles and
  2769. // HGLOBALS indentically, we need to special case the
  2770. // the HMETAFILE case by marking the pointer with a
  2771. // special value
  2772. //
  2773. //--------------------------------------------------------------------------
  2774. static INTERNAL wFillPpres(
  2775. LPSTORAGE pstg,
  2776. PGENOBJ pgenobj,
  2777. CLIPFORMAT cfFormat,
  2778. BOOL fOle10Native)
  2779. {
  2780. pgenobj->m_ppres = new PRES;
  2781. if (pgenobj->m_ppres == NULL)
  2782. {
  2783. return ResultFromScode(E_OUTOFMEMORY);
  2784. }
  2785. // Set the format tag and clipboard format in the PRES member
  2786. pgenobj->m_ppres->m_format.m_cf = cfFormat;
  2787. pgenobj->m_ppres->m_format.m_ftag = ftagClipFormat;
  2788. // Build the presentation based on the object's native data
  2789. HANDLE hpres = UtGetHPRESFromNative(pstg, NULL, pgenobj->m_ppres->m_format.m_cf,
  2790. fOle10Native);
  2791. void * lppres = NULL;
  2792. if (hpres == NULL)
  2793. {
  2794. return NOERROR;
  2795. }
  2796. // Lock the DIB or the METAFILEPICT structure
  2797. lppres = GlobalLock(hpres);
  2798. if (NULL == lppres)
  2799. {
  2800. goto errRtn;
  2801. }
  2802. if (cfFormat == CF_DIB)
  2803. {
  2804. // If it's a DIB, fill in the extents
  2805. LPBITMAPINFOHEADER lpbmi = (LPBITMAPINFOHEADER) lppres;
  2806. UtGetDibExtents(lpbmi, (LPLONG) &(pgenobj->m_ppres->m_ulWidth),
  2807. (LPLONG) &(pgenobj->m_ppres->m_ulHeight));
  2808. GlobalUnlock(hpres);
  2809. pgenobj->m_ppres->m_data.m_h = hpres;
  2810. pgenobj->m_ppres->m_data.m_cbSize
  2811. = (ULONG) GlobalSize(pgenobj->m_ppres->m_data.m_h);
  2812. pgenobj->m_ppres->m_data.m_pv
  2813. = GlobalLock(pgenobj->m_ppres->m_data.m_h);
  2814. }
  2815. else if (cfFormat == CF_METAFILEPICT)
  2816. {
  2817. LPMETAFILEPICT lpmfp = (LPMETAFILEPICT) lppres;
  2818. // If it's a METAFILE, fill in the width, height
  2819. pgenobj->m_ppres->m_ulWidth = (ULONG) lpmfp->xExt;
  2820. pgenobj->m_ppres->m_ulHeight = (ULONG) lpmfp->yExt;
  2821. pgenobj->m_ppres->m_data.m_h = lpmfp->hMF;
  2822. GlobalFree(hpres);
  2823. hpres = NULL;
  2824. // We place a special known value in the pointer field
  2825. // to indicate that the associated handle is a metafile
  2826. // handle (as opposed to a global memory handle), which
  2827. // signals us to special case its cleanup.
  2828. pgenobj->m_ppres->m_data.m_pv = METADATAPTR;
  2829. // We cannot merely GlobalSize() the HMETAFILE, so we
  2830. // ask the GDI how many bytes we will need to store the
  2831. // data.
  2832. pgenobj->m_ppres->m_data.m_cbSize =
  2833. GetMetaFileBitsEx((HMETAFILE) pgenobj->m_ppres->m_data.m_h, 0, NULL);
  2834. if (0 == pgenobj->m_ppres->m_data.m_cbSize)
  2835. {
  2836. pgenobj->m_ppres->m_data.m_h = NULL;
  2837. goto errRtn;
  2838. }
  2839. }
  2840. else
  2841. {
  2842. goto errRtn;
  2843. }
  2844. return NOERROR;
  2845. errRtn:
  2846. if (hpres)
  2847. {
  2848. Verify(GlobalUnlock(hpres));
  2849. GlobalFree(hpres);
  2850. }
  2851. delete pgenobj->m_ppres;
  2852. pgenobj->m_ppres = NULL;
  2853. return ResultFromScode(E_OUTOFMEMORY);
  2854. }
  2855. //+-------------------------------------------------------------------------
  2856. //
  2857. // Function: StorageToGenericObject, INTERNAL
  2858. //
  2859. // Synopsis: Read an object from an IStorage into the generic object,
  2860. // and set up the format type, native and pres data.
  2861. //
  2862. // Arguments: [pstg] -- the IStorage we are reading from
  2863. // [pgenobj] -- the generic object we are reading into
  2864. //
  2865. // Returns: NOERROR on success
  2866. // various possible errors from lower-level fns
  2867. //
  2868. // History: dd-mmm-yy Author Comment
  2869. // 21-Feb-94 davepl Code cleanup and documentation
  2870. //
  2871. // Notes:
  2872. //
  2873. //--------------------------------------------------------------------------
  2874. static INTERNAL StorageToGenericObject(LPSTORAGE pstg, PGENOBJ pgenobj)
  2875. {
  2876. CLSID clsid;
  2877. CLIPFORMAT cf = NULL;
  2878. BOOL fObjFmtKnown = FALSE;
  2879. HRESULT hr;
  2880. // Get the class ID from the IStorage
  2881. if (FAILED(hr = ReadRealClassStg (pstg, &clsid)))
  2882. {
  2883. return hr;
  2884. }
  2885. // Set the class ID in our generic object
  2886. if (CLSID_StaticMetafile == clsid || CLSID_StaticDib == clsid)
  2887. {
  2888. if (CLSID_StaticMetafile == clsid)
  2889. {
  2890. cf = CF_METAFILEPICT;
  2891. }
  2892. else
  2893. {
  2894. cf = CF_DIB;
  2895. }
  2896. fObjFmtKnown = TRUE;
  2897. pgenobj->m_class.Set(clsid, NULL);
  2898. pgenobj->m_fStatic = TRUE;
  2899. }
  2900. else
  2901. {
  2902. if (FAILED(hr = pgenobj->m_class.Set (clsid, pstg)))
  2903. {
  2904. return hr;
  2905. }
  2906. }
  2907. // Get the OLE version, flags, update opts, and moniker
  2908. SCODE sc = GetScode (Read20OleStream (pstg, pgenobj));
  2909. // It is okay for the Ole Stream to be missing.
  2910. if (sc != S_OK)
  2911. {
  2912. if (sc != STG_E_FILENOTFOUND)
  2913. {
  2914. return ResultFromScode (sc);
  2915. }
  2916. }
  2917. // Read the native data into the generic object
  2918. if (FAILED(hr = Read20NativeStreams (pstg, &(pgenobj->m_dataNative))))
  2919. {
  2920. return hr;
  2921. }
  2922. // Try to ascertain the clipboard format
  2923. if (cf == 0)
  2924. {
  2925. if (clsid == CLSID_PBrush)
  2926. {
  2927. cf = CF_DIB;
  2928. }
  2929. else if (clsid == CLSID_MSDraw)
  2930. {
  2931. cf = CF_METAFILEPICT;
  2932. }
  2933. else
  2934. {
  2935. ReadFmtUserTypeStg (pstg, &cf, NULL);
  2936. }
  2937. fObjFmtKnown = (cf == CF_METAFILEPICT || cf == CF_DIB);
  2938. }
  2939. // Read the presentation data if possible
  2940. if (FAILED(hr = Read20PresStream (pstg, pgenobj, fObjFmtKnown)))
  2941. {
  2942. return hr;
  2943. }
  2944. // If we don't have a presentation, it might be a PBrush object,
  2945. // which is OK because OLE 1 DLLs know how to draw them based on
  2946. // the native data. Otherwise, we will try and create a presentation
  2947. // based on the native data.
  2948. if (pgenobj->m_ppres == NULL)
  2949. {
  2950. if (clsid == CLSID_PBrush)
  2951. {
  2952. return NOERROR;
  2953. }
  2954. if (cf == CF_METAFILEPICT || cf == CF_DIB)
  2955. {
  2956. if (FAILED(hr=wFillPpres(pstg,pgenobj,cf,clsid == CLSID_MSDraw)))
  2957. {
  2958. return hr;
  2959. }
  2960. }
  2961. }
  2962. return NOERROR;
  2963. }
  2964. //+-------------------------------------------------------------------------
  2965. //
  2966. // Function: GenericObjectToOLESTREAM, INTERNAL
  2967. //
  2968. // Synopsis: Writes the interal object representation out to an OLE1
  2969. // stream.
  2970. //
  2971. // Arguments: [genobj] -- the object to write out
  2972. // [pos] -- the OLE 1 stream to write to
  2973. //
  2974. // Returns: NOERROR on success
  2975. //
  2976. // History: dd-mmm-yy Author Comment
  2977. // 22-Feb-94 davepl 32-bit port
  2978. // Notes:
  2979. //
  2980. //--------------------------------------------------------------------------
  2981. static INTERNAL GenericObjectToOLESTREAM(
  2982. const GENOBJ FAR& genobj,
  2983. LPOLESTREAM pos)
  2984. {
  2985. HRESULT hr;
  2986. if (genobj.m_fStatic)
  2987. {
  2988. return PutPresentationObject (pos, genobj.m_ppres, genobj.m_class,
  2989. TRUE /* fStatic*/ );
  2990. }
  2991. // OLE version
  2992. if (FAILED(hr = ULToOLE1Stream (pos, dwVerToFile)))
  2993. {
  2994. return hr;
  2995. }
  2996. // Format ID for embedded or linked object
  2997. if (FAILED(hr = ULToOLE1Stream
  2998. (pos, genobj.m_fLink ? FMTID_LINK : FMTID_EMBED)))
  2999. {
  3000. return hr;
  3001. }
  3002. // We must have the class id string by this point
  3003. Assert (genobj.m_class.m_szClsid);
  3004. // Write out the class ID string
  3005. if (FAILED(hr = StringToOLE1Stm (pos, genobj.m_class.m_szClsid)))
  3006. {
  3007. return hr;
  3008. }
  3009. // Write out the topic string
  3010. if (FAILED(hr = StringToOLE1Stm (pos, genobj.m_szTopic)))
  3011. {
  3012. return hr;
  3013. }
  3014. // Write out the item string
  3015. if (FAILED(hr = StringToOLE1Stm (pos, genobj.m_szItem)))
  3016. {
  3017. return hr;
  3018. }
  3019. // Write out the update options, network info for a link,
  3020. // or the native data for an embedded object
  3021. if (genobj.m_fLink)
  3022. {
  3023. // Network information
  3024. if (FAILED(hr = PutNetworkInfo (pos, genobj.m_szTopic)))
  3025. {
  3026. return hr;
  3027. }
  3028. // Link update options
  3029. if (FAILED(hr = ULToOLE1Stream (pos, genobj.m_lnkupdopt)))
  3030. {
  3031. return hr;
  3032. }
  3033. }
  3034. else
  3035. {
  3036. if (FAILED(hr = SizedDataToOLE1Stm (pos, genobj.m_dataNative)))
  3037. {
  3038. return hr;
  3039. }
  3040. }
  3041. // Write out the presentation data
  3042. return PutPresentationObject (pos, genobj.m_ppres, genobj.m_class);
  3043. }
  3044. //+-------------------------------------------------------------------------
  3045. //
  3046. // Function: PutNetworkInfo, INTERNAL
  3047. //
  3048. // Synopsis: If needed, converts a DOS-style path to a proper network
  3049. // path. In any case, writes network path to OLE 1 stream
  3050. //
  3051. // Arguments: [pos] -- the OLE 1 stream we are writing to
  3052. // [szTopic] -- the topic string for this object
  3053. //
  3054. // Returns: NOERROR on success
  3055. // Various possible I/O errors on write
  3056. //
  3057. // History: dd-mmm-yy Author Comment
  3058. // 21-Feb-94 davepl Code cleanup and documentation
  3059. //
  3060. // Notes:
  3061. //
  3062. //--------------------------------------------------------------------------
  3063. static INTERNAL PutNetworkInfo(LPOLESTREAM pos, LPOLESTR szTopic)
  3064. {
  3065. LPOLESTR szNetName = NULL;
  3066. HRESULT hr = NOERROR;
  3067. // If we have an X:\ style path, we want to convert that
  3068. // to a proper network name
  3069. if (szTopic && IsCharAlphaW(szTopic[0]) && szTopic[1]==':')
  3070. {
  3071. OLECHAR szBuf[80];
  3072. DWORD u;
  3073. OLECHAR szDrive[3];
  3074. szDrive[0] = (OLECHAR)CharUpperW((LPWSTR)szTopic[0]);
  3075. szDrive[1] = ':' ;
  3076. szDrive[2] = '\0';
  3077. if (GetDriveType (szDrive) == DRIVE_REMOTE
  3078. && WNetGetConnection (szDrive, szBuf, &u) == WN_SUCCESS)
  3079. {
  3080. szNetName =szBuf;
  3081. }
  3082. }
  3083. // We now have the network name, so write it out to OLE 1 stream
  3084. if (FAILED(hr = StringToOLE1Stm (pos, szNetName)))
  3085. {
  3086. return hr;
  3087. }
  3088. // Network type, driver version number, but we have to pad for
  3089. // the space anyway
  3090. if (FAILED(hr = ULToOLE1Stream (pos, 0L)))
  3091. {
  3092. return hr;
  3093. }
  3094. Assert (hr == NOERROR);
  3095. return hr;
  3096. }
  3097. //+-------------------------------------------------------------------------
  3098. //
  3099. // Function: OpenStream, INTERNAL
  3100. //
  3101. // Synopsis: Opens a stream in SHARE_EXCLUSIVE, READ mode
  3102. //
  3103. // Arguments: [pstg] -- the storage the stream resides in
  3104. // [szName] -- the name of the stream
  3105. // [ppstm] -- out parameter for stream
  3106. //
  3107. // History: dd-mmm-yy Author Comment
  3108. // 21-Feb-94 davepl Code cleanup and document
  3109. //
  3110. // Notes:
  3111. //
  3112. //--------------------------------------------------------------------------
  3113. static inline INTERNAL OpenStream(
  3114. LPSTORAGE pstg,
  3115. LPOLESTR szName,
  3116. LPSTREAM FAR* ppstm)
  3117. {
  3118. return pstg->OpenStream
  3119. (szName, NULL, STGM_SHARE_EXCLUSIVE| STGM_READ, 0, ppstm);
  3120. }
  3121. //+-------------------------------------------------------------------------
  3122. //
  3123. // Function: ReadRealClassStg, INTERNAL
  3124. //
  3125. // Synopsis: Reads the _real_ class of the object. ie: if the class is
  3126. // StdOleLink, we need to find out the class of the object
  3127. // to which this is linked
  3128. //
  3129. // Arguments: pstg -- the storage to read from
  3130. // pclsid -- caller's CLSID holder
  3131. //
  3132. // Returns: NOERROR on success
  3133. //
  3134. // History: dd-mmm-yy Author Comment
  3135. // 04-Mar-04 davepl 32-bit port
  3136. // Notes:
  3137. //
  3138. //--------------------------------------------------------------------------
  3139. static INTERNAL ReadRealClassStg(LPSTORAGE pstg, LPCLSID pclsid)
  3140. {
  3141. LPSTREAM pstm = NULL;
  3142. HRESULT hr = NOERROR;
  3143. // Get the class ID from the IStorage
  3144. if (FAILED(hr = ReadClassStg (pstg, pclsid)))
  3145. {
  3146. return hr;
  3147. }
  3148. // If it's a link, we have to figure out what class its a link _to_
  3149. if (CLSID_StdOleLink == *pclsid)
  3150. {
  3151. LPMONIKER pmk = NULL;
  3152. if (FAILED(hr = ReadOleStg (pstg, NULL, NULL, NULL, NULL, &pstm)))
  3153. {
  3154. return hr;
  3155. }
  3156. if (FAILED(hr = ReadMonikerStm (pstm, &pmk)))
  3157. {
  3158. goto errRtn;
  3159. }
  3160. if (pmk)
  3161. {
  3162. pmk->Release();
  3163. }
  3164. if (FAILED(hr = ReadMonikerStm (pstm, &pmk)))
  3165. {
  3166. goto errRtn;
  3167. }
  3168. if (pmk)
  3169. {
  3170. pmk->Release();
  3171. }
  3172. // Read "last class"
  3173. if (FAILED(hr = ReadM1ClassStm (pstm, pclsid)))
  3174. {
  3175. goto errRtn;
  3176. }
  3177. }
  3178. errRtn:
  3179. if (pstm)
  3180. {
  3181. pstm->Release();
  3182. }
  3183. return hr;
  3184. }
  3185. //+-------------------------------------------------------------------------
  3186. //
  3187. // Function: Read20OleStream, INTERNAL
  3188. //
  3189. // Synopsis: Reads the update options and absolute source class from
  3190. // an OLE 2 object
  3191. //
  3192. // Arguments: pstg -- the IStorage to read from
  3193. // pgenobj -- the genobj we are reading into
  3194. //
  3195. // Returns: NOERROR on success
  3196. //
  3197. // History: dd-mmm-yy Author Comment
  3198. // 06-Mar-94 davepl 32-bit port
  3199. // Notes:
  3200. //
  3201. //--------------------------------------------------------------------------
  3202. static INTERNAL Read20OleStream(LPSTORAGE pstg, PGENOBJ pgenobj)
  3203. {
  3204. LPMONIKER pmk = NULL;
  3205. HRESULT hr = NOERROR;
  3206. LPSTREAM pstm = NULL;
  3207. ULONG ul = (ULONG) -1L;
  3208. CLSID clsidLast;
  3209. if (SUCCEEDED(hr = OpenStream (pstg, OLE_STREAM, &pstm)))
  3210. {
  3211. // OLE version
  3212. if (SUCCEEDED(hr = OLE2StmToUL (pstm, NULL)))
  3213. {
  3214. // Object flags
  3215. if (SUCCEEDED(hr = OLE2StmToUL (pstm, &ul)))
  3216. {
  3217. if (ul & OBJFLAGS_LINK)
  3218. {
  3219. pgenobj->m_fLink = TRUE;
  3220. }
  3221. // Update options
  3222. hr = OLE2StmToUL (pstm, &ul);
  3223. }
  3224. }
  3225. }
  3226. // If no errors so far...
  3227. // If this is a link, get the update options
  3228. if (SUCCEEDED(hr) && pgenobj->m_fLink)
  3229. {
  3230. switch (ul)
  3231. {
  3232. case OLEUPDATE_ALWAYS:
  3233. pgenobj->m_lnkupdopt = UPDATE_ALWAYS;
  3234. break;
  3235. case OLEUPDATE_ONCALL:
  3236. pgenobj->m_lnkupdopt = UPDATE_ONCALL;
  3237. break;
  3238. default:
  3239. AssertSz (0, "Warning: Invalid update options in Storage");
  3240. hr = ResultFromScode(CONVERT10_E_STG_FMT);
  3241. }
  3242. }
  3243. if (SUCCEEDED(hr)) // Only continue if no failures so far
  3244. {
  3245. // Reserved (was view format)
  3246. if (SUCCEEDED(hr = OLE2StmToUL (pstm, NULL)))
  3247. {
  3248. if (pgenobj->m_fLink)
  3249. {
  3250. // All 4 of these calls must succeed or we simply fall
  3251. // through to the cleanup code
  3252. // ignore relative moniker
  3253. if (SUCCEEDED(hr = OLE2StmToMoniker (pstm, NULL)) &&
  3254. // ignore relative source moniker
  3255. SUCCEEDED(hr = OLE2StmToMoniker (pstm, NULL)) &&
  3256. // get absolute source moniker
  3257. SUCCEEDED(hr = OLE2StmToMoniker (pstm, &pmk)) &&
  3258. // get class from abs moniker
  3259. SUCCEEDED(hr = ReadM1ClassStm (pstm, &clsidLast)) )
  3260. {
  3261. hr = MonikerIntoGenObj (pgenobj, clsidLast, pmk);
  3262. }
  3263. }
  3264. }
  3265. }
  3266. // Clean up any resources and return status to caller
  3267. if (pstm)
  3268. {
  3269. pstm->Release();
  3270. }
  3271. if (pmk)
  3272. {
  3273. pmk->Release();
  3274. }
  3275. return hr;
  3276. }
  3277. //+-------------------------------------------------------------------------
  3278. //
  3279. // Function: OLE2StmToMoniker, INTERNAL
  3280. //
  3281. // Synopsis: Calls ReadMonikerStm to get a moniker from a stream,
  3282. // and if the ppmk parameter was NULL, it does a Release()
  3283. // on the moniker object immediately, otherwise sets the
  3284. // caller's pointer to point to the moniker that was read.
  3285. //
  3286. // Arguments: [pstm] -- the stream to read the moniker from
  3287. // [ppmk] -- points to caller's moniker ptr
  3288. //
  3289. // History: dd-mmm-yy Author Comment
  3290. // 21-Feb-94 davepl Code cleanup and documentation
  3291. //
  3292. // Notes:
  3293. //
  3294. //--------------------------------------------------------------------------
  3295. static INTERNAL OLE2StmToMoniker(LPSTREAM pstm, LPMONIKER FAR* ppmk)
  3296. {
  3297. LPMONIKER pmk = NULL;
  3298. HRESULT hr = NOERROR;
  3299. if (FAILED(hr = ReadMonikerStm (pstm, &pmk)))
  3300. {
  3301. return hr;
  3302. }
  3303. if (ppmk) // If the callers wanted a result, return the
  3304. { // moniker as an out parameter
  3305. *ppmk = pmk;
  3306. }
  3307. else // Otherwise, release it immediately and
  3308. { // return to caller
  3309. if (pmk)
  3310. {
  3311. pmk->Release();
  3312. }
  3313. }
  3314. return NOERROR;
  3315. }
  3316. //+-------------------------------------------------------------------------
  3317. //
  3318. // Function: ReadFormat, INTERNAL
  3319. //
  3320. // Synopsis: Reads the format ID type from the stream, and based on that,
  3321. // reads the format ID from the stream.
  3322. //
  3323. // Arguments: [pstm] -- the stream to read from
  3324. // [pformat] -- caller's format member object
  3325. //
  3326. // History: dd-mmm-yy Author Comment
  3327. // 21-Feb-94 davepl Code cleanup and documentation
  3328. //
  3329. // Notes: The first ULONG indicates the type (standard clipboard,
  3330. // Mac, NULL, or string) of the identifier
  3331. //
  3332. //--------------------------------------------------------------------------
  3333. static INTERNAL ReadFormat(LPSTREAM pstm, PFORMAT pformat)
  3334. {
  3335. ULONG ul;
  3336. HRESULT hr = NOERROR;
  3337. // Get the format ID type indicator
  3338. if (FAILED(hr = OLE2StmToUL (pstm, &ul)))
  3339. {
  3340. return hr;
  3341. }
  3342. // The first ULONG indicates what kind of format ID will
  3343. // found in the stream:
  3344. //
  3345. // -1 => A standard clipboard format ID
  3346. // -2 => A Macintosh format
  3347. // 0 => NULL format
  3348. // >0 => The number of bytes of the text string
  3349. // identifier to follow
  3350. switch ((signed long)ul)
  3351. {
  3352. case -1L: // Standard clipboard format
  3353. ULONG ulClipFormat;
  3354. pformat->m_ftag = ftagClipFormat;
  3355. if (FAILED(hr = OLE2StmToUL (pstm, &ulClipFormat)))
  3356. {
  3357. return hr;
  3358. }
  3359. pformat->m_cf = (CLIPFORMAT) ulClipFormat;
  3360. break;
  3361. case -2L: // Macintosh format
  3362. return ResultFromScode(CONVERT10_E_STG_FMT);
  3363. case 0: // NULL format
  3364. pformat->m_ftag = ftagNone;
  3365. pformat->m_cf = 0;
  3366. return NOERROR;
  3367. default: // ul == size of string (format name)
  3368. pformat->m_ftag = ftagString;
  3369. if (FAILED(hr = OLE2StmToSizedData
  3370. (pstm, &(pformat->m_dataFormatString), 0, ul)))
  3371. {
  3372. return hr;
  3373. }
  3374. break;
  3375. }
  3376. return NOERROR;
  3377. }
  3378. #ifdef _OBSOLETE
  3379. //+-------------------------------------------------------------------------
  3380. //
  3381. // Function: WriteFormat, INTERNAL
  3382. //
  3383. // Synopsis: Depending on what kind of format (standard cf, string, etc)
  3384. // the format object holds, this fn writes out the appropriate
  3385. // information to the stream
  3386. //
  3387. // Arguments: [pstm] -- the stream to write to
  3388. // [format] -- the format object to get info from
  3389. //
  3390. // Returns: NOERROR on success
  3391. // E_UNEXPECTED for a NULL format tag
  3392. //
  3393. // History: dd-mmm-yy Author Comment
  3394. // 21-Feb-94 davepl Code cleanup and documentation
  3395. // Notes:
  3396. //--------------------------------------------------------------------------
  3397. static INTERNAL WriteFormat(LPSTREAM pstm, const FORMAT FAR& format)
  3398. {
  3399. HRESULT hr;
  3400. switch (format.m_ftag)
  3401. {
  3402. case ftagNone:
  3403. Assert (0 && "Cant write a NULL format tag");
  3404. return ResultFromScode (E_UNEXPECTED);
  3405. case ftagClipFormat:
  3406. if (FAILED(hr = ULToOLE2Stm (pstm, (ULONG) -1L)))
  3407. {
  3408. return hr;
  3409. }
  3410. if (FAILED(hr = ULToOLE2Stm (pstm, format.m_cf)))
  3411. {
  3412. return hr;
  3413. }
  3414. break;
  3415. case ftagString:
  3416. if (FAILED(hr=DataObjToOLE2Stm(pstm,format.m_dataFormatString)))
  3417. {
  3418. return hr;
  3419. }
  3420. break;
  3421. default:
  3422. AssertSz (0, "invalid m_ftag value");
  3423. return ResultFromScode (E_UNEXPECTED);
  3424. }
  3425. return NOERROR;
  3426. }
  3427. #endif // _OBSOLETE
  3428. //+-------------------------------------------------------------------------
  3429. //
  3430. // Function: ReadDibAsBitmap, INTERNAL
  3431. //
  3432. // Synopsis: Reads a DIB from an OLE 2 stream and stores it as a
  3433. // Bitmap in a DATA structure
  3434. //
  3435. // Arguments: [pstm] -- the OLE 2 stream to read from
  3436. // [pdata] -- the data object to hold the bitmap
  3437. //
  3438. // Returns: NOERROR on success
  3439. // CONVERT10_E_STG_DIB_TO_BITMAP conversion failure
  3440. // E_OUTOFMEMORY allocation failure
  3441. //
  3442. // History: dd-mmm-yy Author Comment
  3443. // 21-Feb-94 davepl Code cleanup and documentation
  3444. //
  3445. // Notes:
  3446. //
  3447. //--------------------------------------------------------------------------
  3448. static INTERNAL ReadDibAsBitmap(LPSTREAM pstm, PDATA pdata)
  3449. {
  3450. DATA dataDib;
  3451. ULONG cb;
  3452. ULONG cbBits;
  3453. ULONG cbBitsFake;
  3454. BITMAP bm;
  3455. HBITMAP hBitmap = NULL;
  3456. HRESULT hr = NOERROR;
  3457. HGLOBAL hBits = NULL;
  3458. LPBYTE pBits = NULL;
  3459. Assert (pdata&&pdata->m_cbSize==0&&pdata->m_h==NULL&&pdata->m_pv==NULL);
  3460. // Read the DIB into our local DATA object
  3461. if (FAILED(hr = OLE2StmToSizedData (pstm, &dataDib)))
  3462. {
  3463. return hr;
  3464. }
  3465. // Convert the DIB to a Bitmap
  3466. hBitmap = UtConvertDibToBitmap (dataDib.m_h);
  3467. if (NULL == hBitmap )
  3468. {
  3469. return ResultFromScode(CONVERT10_E_STG_DIB_TO_BITMAP);
  3470. }
  3471. if (0 == GetObject (hBitmap, sizeof(BITMAP), &bm))
  3472. {
  3473. return ResultFromScode(CONVERT10_E_STG_DIB_TO_BITMAP);
  3474. }
  3475. cbBits = (DWORD) bm.bmHeight * (DWORD) bm.bmWidthBytes
  3476. * (DWORD) bm.bmPlanes;
  3477. // There was a bug in OLE 1.0. It calculated the size of a bitmap
  3478. // as Height * WidthBytes * Planes * BitsPixel.
  3479. // So we need to put that many bytes here even if most of the end of that
  3480. // data block is garbage. Otherwise OLE 1.0 will try to read too many
  3481. // bytes of the OLESTREAM as bitmap bits.
  3482. cbBitsFake = cbBits * (DWORD) bm.bmBitsPixel;
  3483. // Allocate enough memory for our resultant BITMAP & header
  3484. hBits = GlobalAlloc (GMEM_MOVEABLE, cbBitsFake + sizeof (BITMAP));
  3485. if (NULL == hBits)
  3486. {
  3487. if (hBitmap)
  3488. {
  3489. Verify (DeleteObject (hBitmap));
  3490. }
  3491. return ResultFromScode(E_OUTOFMEMORY);
  3492. }
  3493. // Get a pointer to the memory
  3494. pBits = (LPBYTE) GlobalLock (hBits);
  3495. if (NULL == pBits)
  3496. {
  3497. if (hBitmap)
  3498. {
  3499. Verify (DeleteObject (hBitmap));
  3500. }
  3501. GlobalFree(hBits);
  3502. return ResultFromScode(E_OUTOFMEMORY);
  3503. }
  3504. // Copy the raw bitmap data
  3505. cb = GetBitmapBits (hBitmap, cbBits, pBits + sizeof(BITMAP));
  3506. if (cb != cbBits)
  3507. {
  3508. if (hBitmap)
  3509. {
  3510. Verify (DeleteObject (hBitmap));
  3511. }
  3512. GlobalFree(hBits);
  3513. return ResultFromScode(CONVERT10_E_STG_DIB_TO_BITMAP);
  3514. }
  3515. // Set the caller's pointer to point to the bitmap
  3516. *((BITMAP FAR*)pBits) = bm;
  3517. pdata->m_h = hBits;
  3518. pdata->m_pv = pBits;
  3519. pdata->m_cbSize = cbBitsFake + sizeof(BITMAP);
  3520. return NOERROR;
  3521. }
  3522. //+-------------------------------------------------------------------------
  3523. //
  3524. // Function: Read20PresStream, INTERNAL
  3525. //
  3526. // Synopsis: Reads presentation data from an IStorage into a
  3527. // generic object
  3528. //
  3529. // Arguments: [pstg] -- the IStorage holding the pres stream
  3530. // [pgenobj] -- the generic object to read to
  3531. // [fObjFmtKnown] -- flag: Do we know the object format?
  3532. //
  3533. // Returns: NOEROR on success
  3534. // E_OUTOFMEMORY on allocation failure
  3535. //
  3536. // History: dd-mmm-yy Author Comment
  3537. // 22-Feb-94 davepl Code cleanup and documentation
  3538. // Notes:
  3539. //
  3540. //--------------------------------------------------------------------------
  3541. static INTERNAL Read20PresStream(
  3542. LPSTORAGE pstg,
  3543. PGENOBJ pgenobj,
  3544. BOOL fObjFmtKnown)
  3545. {
  3546. HRESULT hr = NOERROR;
  3547. LPSTREAM pstm = NULL;
  3548. // Find the best presentation stream in this IStorage
  3549. if (FAILED(hr = FindPresStream (pstg, &pstm, fObjFmtKnown)))
  3550. {
  3551. return hr;
  3552. }
  3553. if (pstm)
  3554. {
  3555. // Allocate a generic presentation object
  3556. Assert (NULL==pgenobj->m_ppres);
  3557. pgenobj->m_ppres = new PRES;
  3558. if (NULL == pgenobj->m_ppres)
  3559. {
  3560. pstm->Release();
  3561. return ResultFromScode(E_OUTOFMEMORY);
  3562. }
  3563. }
  3564. else
  3565. {
  3566. // No presentation stream
  3567. Assert (NULL == pgenobj->m_ppres);
  3568. return NOERROR;
  3569. }
  3570. // read the format
  3571. if (FAILED(hr = ReadFormat (pstm, &(pgenobj->m_ppres->m_format))))
  3572. {
  3573. pstm->Release();
  3574. return hr;
  3575. }
  3576. // This is the fix for Bug 4020, highly requested by Access
  3577. if (pgenobj->m_ppres->m_format.m_ftag == ftagNone)
  3578. {
  3579. // NULL format
  3580. delete pgenobj->m_ppres;
  3581. pgenobj->m_ppres = NULL;
  3582. Assert (hr == NOERROR);
  3583. pstm->Release();
  3584. return hr;
  3585. }
  3586. // Each of the following calls must succeed in order for the following
  3587. // one to be executed; if any fails, the if( .. && ..) will be false
  3588. // and hr will be set to the error that caused the failure
  3589. // target device
  3590. if (SUCCEEDED(hr = OLE2StmToSizedData (pstm, NULL, 4)) &&
  3591. // aspect
  3592. SUCCEEDED(hr = OLE2StmToUL (pstm, NULL)) &&
  3593. // lIndex
  3594. SUCCEEDED(hr = OLE2StmToUL (pstm, NULL)) &&
  3595. // cache flags
  3596. SUCCEEDED(hr = OLE2StmToUL (pstm, NULL)) &&
  3597. // compression
  3598. SUCCEEDED(hr = OLE2StmToUL (pstm, NULL)) &&
  3599. // width
  3600. SUCCEEDED(hr = OLE2StmToUL (pstm, &(pgenobj->m_ppres->m_ulWidth))))
  3601. { // height
  3602. hr = OLE2StmToUL (pstm, &(pgenobj->m_ppres->m_ulHeight));
  3603. }
  3604. // We only proceed if everything so far has suceeded
  3605. if (SUCCEEDED(hr))
  3606. {
  3607. if (pgenobj->m_ppres->m_format.m_ftag == ftagClipFormat &&
  3608. pgenobj->m_ppres->m_format.m_cf == CF_DIB &&
  3609. !pgenobj->m_fStatic)
  3610. {
  3611. pgenobj->m_ppres->m_format.m_cf = CF_BITMAP;
  3612. hr = ReadDibAsBitmap (pstm, &(pgenobj->m_ppres->m_data));
  3613. }
  3614. else
  3615. {
  3616. // In most cases, we look for a sized block of data in the
  3617. // stream.
  3618. hr = OLE2StmToSizedData (pstm, &(pgenobj->m_ppres->m_data));
  3619. }
  3620. }
  3621. // Free up the stream and return status to caller
  3622. if (pstm)
  3623. {
  3624. pstm->Release();
  3625. }
  3626. return hr;
  3627. }
  3628. //+-------------------------------------------------------------------------
  3629. //
  3630. // Function: OLE2StmToSizedData, INTERNAL
  3631. //
  3632. // Synopsis: Reads a set amount of data from an OLE 2 stream into a
  3633. // DATA structure. If the number of bytes are not known
  3634. // ahead of time, the data length is pulled as the first
  3635. // ULONG at the current stream position.
  3636. //
  3637. // Arguments: [pstm] -- the stream to read from
  3638. // [pdata] -- the DATA structure to read to
  3639. // [cbSizeDelta] -- amount to be subtracted from
  3640. // length; used to read target devices
  3641. // where the length of data includes
  3642. // prefixed length
  3643. // [cbSizeKnown] -- number of bytes to read if known
  3644. // ahead of time
  3645. //
  3646. // History: dd-mmm-yy Author Comment
  3647. // 21-Feb-94 davepl Code cleanup and documentation
  3648. // Notes:
  3649. //
  3650. //--------------------------------------------------------------------------
  3651. static INTERNAL OLE2StmToSizedData(
  3652. LPSTREAM pstm,
  3653. PDATA pdata,
  3654. ULONG cbSizeDelta, // default 0
  3655. ULONG cbSizeKnown) // default 0
  3656. {
  3657. ULONG cbSize;
  3658. ULONG cbRead;
  3659. LARGE_INTEGER large_integer;
  3660. HRESULT hr = NOERROR;
  3661. // If we don't know the data size ahead of time, read it from the stream;
  3662. // it will be the first ULONG at the current position
  3663. if (cbSizeKnown)
  3664. {
  3665. cbSize = cbSizeKnown;
  3666. }
  3667. else
  3668. {
  3669. if (FAILED(hr = (OLE2StmToUL (pstm, &cbSize))))
  3670. {
  3671. return hr;
  3672. }
  3673. }
  3674. cbSize -= cbSizeDelta;
  3675. // If pdata is set, it means we actually do want to read the
  3676. // data to a buffer, rather than just skip over it (the NULL case)
  3677. if (pdata)
  3678. {
  3679. Assert (pdata->m_cbSize==0 && pdata->m_h==NULL && pdata->m_pv==NULL);
  3680. // Set the number of bytes in the DATA structure
  3681. pdata->m_cbSize = cbSize;
  3682. // If there are any, allocate a buffer and read them.
  3683. if (cbSize)
  3684. {
  3685. // Allocate memory on the DATA handle
  3686. pdata->m_h = GlobalAlloc (GMEM_MOVEABLE, cbSize);
  3687. if (NULL == pdata->m_h)
  3688. {
  3689. return ResultFromScode(E_OUTOFMEMORY);
  3690. }
  3691. // Lock memory in for the read
  3692. pdata->m_pv = GlobalLock (pdata->m_h);
  3693. if (NULL == pdata->m_pv)
  3694. {
  3695. GlobalFree(pdata->m_h);
  3696. return ResultFromScode(E_OUTOFMEMORY);
  3697. }
  3698. // Read the data to the buffer
  3699. if (FAILED(hr = pstm->Read (pdata->m_pv, cbSize, &cbRead)))
  3700. {
  3701. GlobalUnlock(pdata->m_h);
  3702. GlobalFree(pdata->m_h);
  3703. return hr;
  3704. }
  3705. // If we didn't get enough bytes, bail now
  3706. if (cbRead != cbSize)
  3707. {
  3708. GlobalUnlock(pdata->m_h);
  3709. GlobalFree(pdata->m_h);
  3710. return ResultFromScode(STG_E_READFAULT);
  3711. }
  3712. }
  3713. else
  3714. {
  3715. // We have 0 bytes to read, so mark the
  3716. // memory handle and ptr as NULL
  3717. pdata->m_h = NULL;
  3718. pdata->m_pv = NULL;
  3719. }
  3720. }
  3721. else
  3722. {
  3723. // we don't care what the data is, so just skip it
  3724. LISet32( large_integer, cbSize );
  3725. if (FAILED(hr = pstm->Seek (large_integer, STREAM_SEEK_CUR, NULL)))
  3726. {
  3727. return hr;
  3728. }
  3729. }
  3730. return NOERROR;
  3731. }
  3732. //+-------------------------------------------------------------------------
  3733. //
  3734. // Function: RankOfPres, INTERNAL
  3735. //
  3736. // Synopsis: Returns a ULONG indicating the relative "goodness" of a
  3737. // presentation. The preference is, in descending order:
  3738. //
  3739. // Type Rank
  3740. // ---------- ----------
  3741. // METAFILE x30000
  3742. // DIB x20000
  3743. // none x10000
  3744. //
  3745. // Add x200 for fScreenTargDev being set
  3746. // Add x4 for Content aspect
  3747. // Add x3 for Thumbnail aspect
  3748. // Add x2 for Icon aspect
  3749. // Add x1 for Docprint aspect
  3750. //
  3751. // Eg: Metafile in Content aspect, with ScreenTargDev: 30204
  3752. //
  3753. // The whole point of this is that there may be many
  3754. // presentation streams available in the IStorage. This fn
  3755. // is used to select the best one.
  3756. //
  3757. // Arguments: [format] -- the format tag & type structure
  3758. // [fScreenTargDev]-- do we have a handle to the target dev
  3759. // [dwAspect] -- the aspect type
  3760. //
  3761. // History: dd-mmm-yy Author Comment
  3762. // 21-Feb-94 davepl Code cleanup and documentation
  3763. //
  3764. // Notes:
  3765. //
  3766. //--------------------------------------------------------------------------
  3767. static INTERNAL_(ULONG) RankOfPres(
  3768. const FORMAT FAR& format,
  3769. const BOOL fScreenTargDev,
  3770. const DWORD dwAspect)
  3771. {
  3772. ULONG ul = 0L;
  3773. if (format.m_cf==CF_METAFILEPICT)
  3774. {
  3775. ul += 0x030000;
  3776. }
  3777. else if (format.m_cf==CF_DIB)
  3778. {
  3779. ul += 0x020000;
  3780. }
  3781. else if (format.m_ftag != ftagNone)
  3782. {
  3783. ul += 0x010000;
  3784. }
  3785. ul += (fScreenTargDev + 1) * 0x0100;
  3786. switch (dwAspect)
  3787. {
  3788. case DVASPECT_CONTENT:
  3789. ul += 0x04;
  3790. break;
  3791. case DVASPECT_THUMBNAIL:
  3792. ul += 0x03;
  3793. break;
  3794. case DVASPECT_ICON:
  3795. ul += 0x02;
  3796. break;
  3797. case DVASPECT_DOCPRINT:
  3798. ul += 0x01;
  3799. break;
  3800. }
  3801. return ul;
  3802. }
  3803. //+-------------------------------------------------------------------------
  3804. //
  3805. // Function: IsBetter, INTERNAL INLINE
  3806. //
  3807. // Synopsis: Calls RankOfPres to determine if one presentation is
  3808. // better than another
  3809. //
  3810. // Effects:
  3811. //
  3812. // Arguments: [format] -- the format tag and type
  3813. // [fScreenTargDev]-- do we have a handle to target device
  3814. // [dwAspect] -- the aspect of the presentation
  3815. // [formatBest] -- the best format seen so far
  3816. // [fScreenTargDevBest] -- flag for best format seen so far
  3817. // [dwAspectBest] -- the aspect of best format seen so far
  3818. //
  3819. // History: dd-mmm-yy Author Comment
  3820. /// 21-Feb-94 davepl Code cleanup and documentation
  3821. //
  3822. // Notes:
  3823. //
  3824. //--------------------------------------------------------------------------
  3825. inline static INTERNAL_(BOOL) IsBetter(
  3826. const FORMAT FAR& format,
  3827. const BOOL fScreenTargDev,
  3828. const DWORD dwAspect,
  3829. const FORMAT FAR& formatBest,
  3830. const BOOL fScreenTargDevBest,
  3831. const DWORD dwAspectBest)
  3832. {
  3833. return RankOfPres (format, fScreenTargDev, dwAspect) >
  3834. RankOfPres (formatBest, fScreenTargDevBest, dwAspectBest);
  3835. }
  3836. //+-------------------------------------------------------------------------
  3837. //
  3838. // Function: FindPresStream, INTERNAL
  3839. //
  3840. // Synopsis: Enumerates over the streams in an IStorage, looking for
  3841. // presentation streams. Selects the best stream among
  3842. // these based on the comparison fn, IsBetter(), which uses
  3843. // for comparison the criteria established in RankOfPres().
  3844. //
  3845. // Arguments: [pstg] -- the IStorage to look in
  3846. // [ppstmBest] -- out param for best pres stream
  3847. // [fObjFmtKnown] is the object format known
  3848. //
  3849. // Returns: NOERROR on success
  3850. // If no presentation is found, it is not an error but
  3851. // *ppstm is set to NULL.
  3852. //
  3853. // History: dd-mmm-yy Author Comment
  3854. // 21-Feb-94 davepl Code cleanup and documentation
  3855. //
  3856. // Notes:
  3857. //
  3858. //--------------------------------------------------------------------------
  3859. static INTERNAL FindPresStream(
  3860. LPSTORAGE pstg,
  3861. LPSTREAM FAR* ppstmBest,
  3862. BOOL fObjFmtKnown)
  3863. {
  3864. HRESULT hr = NOERROR;
  3865. LPSTREAM pstm = NULL;
  3866. IEnumSTATSTG FAR* penumStg = NULL;
  3867. DWORD dwAspectBest = 0;
  3868. BOOL fTargDevBest = -1;
  3869. STATSTG statstg;
  3870. FORMAT formatBest;
  3871. Assert (ppstmBest);
  3872. *ppstmBest = NULL;
  3873. // Set up the enumeration on the available IStreams in the storage
  3874. if (FAILED(hr = pstg->EnumElements (NULL, NULL, NULL, &penumStg)))
  3875. {
  3876. return hr;
  3877. }
  3878. // Enumerate through them and search for the best among all
  3879. // presentation streams
  3880. while (penumStg->Next (1, &statstg, NULL) == NOERROR)
  3881. {
  3882. // Check to see if this a presentation stream
  3883. if (lstrlenW(statstg.pwcsName) >= 8 &&
  3884. 0==memcmp(statstg.pwcsName, OLESTR("\2OlePres"), 8*sizeof(WCHAR)))
  3885. {
  3886. FORMAT format;
  3887. DATA dataTargDev;
  3888. DWORD dwAspect;
  3889. // Open the presentation stream
  3890. if (FAILED(hr = OpenStream (pstg, statstg.pwcsName, &pstm)))
  3891. {
  3892. goto errRtn;
  3893. }
  3894. // Read the format from the pres stream
  3895. if (FAILED(hr = ReadFormat (pstm, &format)))
  3896. {
  3897. goto errRtn;
  3898. }
  3899. // Read the target device from the pres stream
  3900. if (FAILED(hr = OLE2StmToSizedData (pstm, &dataTargDev, 4)))
  3901. {
  3902. goto errRtn;
  3903. }
  3904. // Get the aspect from the pres stream
  3905. if (FAILED(hr = OLE2StmToUL (pstm, &dwAspect)))
  3906. {
  3907. goto errRtn;
  3908. }
  3909. // Check to see if this presentation stream is better
  3910. // than the best seen so far
  3911. if (IsBetter (format, dataTargDev.m_h==NULL, dwAspect,
  3912. formatBest, fTargDevBest, dwAspectBest))
  3913. {
  3914. // If it is, we can release the "best"
  3915. if (*ppstmBest)
  3916. {
  3917. (*ppstmBest)->Release();
  3918. }
  3919. // The king is dead, long live the king
  3920. *ppstmBest = pstm;
  3921. pstm->AddRef();
  3922. formatBest = format;
  3923. fTargDevBest = (dataTargDev.m_h==NULL);
  3924. dwAspectBest = dwAspect;
  3925. }
  3926. pstm->Release();
  3927. pstm = NULL;
  3928. }
  3929. PubMemFree(statstg.pwcsName);
  3930. statstg.pwcsName = NULL;
  3931. }
  3932. // On Windows For Workgroups machines, statstg.pwcsName!=NULL when
  3933. // Next() returns S_FALSE. Bug 3370.
  3934. statstg.pwcsName = NULL;
  3935. errRtn:
  3936. if (statstg.pwcsName)
  3937. {
  3938. PubMemFree(statstg.pwcsName);
  3939. }
  3940. if (*ppstmBest)
  3941. {
  3942. if (dwAspectBest != DVASPECT_CONTENT && fObjFmtKnown)
  3943. {
  3944. // then don't use this stream, we will get the presentaion
  3945. // from the CONTENTS stream
  3946. (*ppstmBest)->Release();
  3947. *ppstmBest = NULL;
  3948. }
  3949. else
  3950. {
  3951. LARGE_INTEGER large_integer;
  3952. LISet32( large_integer, 0);
  3953. hr = (*ppstmBest)->Seek(large_integer, STREAM_SEEK_SET,NULL);
  3954. }
  3955. }
  3956. if (penumStg)
  3957. {
  3958. penumStg->Release();
  3959. }
  3960. if (pstm)
  3961. {
  3962. pstm->Release();
  3963. }
  3964. return hr;
  3965. }
  3966. //+-------------------------------------------------------------------------
  3967. //
  3968. // Function: Reads native data from an OLE 2 stream
  3969. //
  3970. // Synopsis: If the fn can find OLE 1 native data in the stream, it is
  3971. // read out; otherwise, it attempts to create an IStorage
  3972. // in memory on the data in the stream, and then uses the
  3973. // CopyTo interface to extract the data.
  3974. //
  3975. // Arguments: [pstg] -- The OLE 2 IStorage to look in
  3976. // [pdata] -- The DATA object to read native data to
  3977. //
  3978. // Returns: NOERROR on success
  3979. // STG_E_READFAULT on read failure
  3980. // E_OUTOFMEMORY on allocation failure
  3981. //
  3982. // History: dd-mmm-yy Author Comment
  3983. // 21-feb-94 davepl Cleaned up and documented code
  3984. // Notes:
  3985. //
  3986. //--------------------------------------------------------------------------
  3987. static INTERNAL Read20NativeStreams(LPSTORAGE pstg, PDATA pdata)
  3988. {
  3989. LPSTREAM pstm = NULL;
  3990. LPLOCKBYTES plkbyt = NULL;
  3991. LPSTORAGE pstgNative= NULL;
  3992. HRESULT hr = NOERROR;
  3993. // There are two possible codepaths based on the success of
  3994. // OpenStream. If it is true, it is because we were able to
  3995. // open the OLE 1 presentation stream in the OLE 2 object.
  3996. // Thus, it must have been an OLE 1 object "hidden" in
  3997. // an OLE 2 IStream.
  3998. //
  3999. // If that fails, we create an in-memory IStorage based on
  4000. // the native data and use the CopyTo member to extract the
  4001. // natice data.
  4002. //
  4003. // If we experience a failure at any point, a "break" statement
  4004. // bails us out past everything to the error cleanup and return
  4005. // code following the closure of the switch() statement.
  4006. switch ((DWORD)(NOERROR==OpenStream (pstg, OLE10_NATIVE_STREAM, &pstm)))
  4007. {
  4008. case TRUE:
  4009. {
  4010. // This was a 1.0 object "hidden" inside a 2.0 IStorage
  4011. ULONG cbRead;
  4012. Assert (pdata->m_cbSize==0 && NULL==pdata->m_h && NULL==pdata->m_pv);
  4013. // read size
  4014. if (FAILED(hr = pstm->Read(&(pdata->m_cbSize),sizeof(DWORD),&cbRead)))
  4015. {
  4016. break;
  4017. }
  4018. if (sizeof(DWORD) != cbRead)
  4019. {
  4020. hr = ResultFromScode (STG_E_READFAULT);
  4021. break;
  4022. }
  4023. // allocate memory to store copy of stream
  4024. pdata->m_h = GlobalAlloc (GMEM_MOVEABLE, pdata->m_cbSize);
  4025. if (NULL == pdata->m_h)
  4026. {
  4027. hr = ResultFromScode(E_OUTOFMEMORY);
  4028. break;
  4029. }
  4030. pdata->m_pv = GlobalLock (pdata->m_h);
  4031. if (NULL == pdata->m_pv)
  4032. {
  4033. hr = ResultFromScode(E_OUTOFMEMORY);
  4034. break;
  4035. }
  4036. // read stream
  4037. if (FAILED(hr = pstm->Read(pdata->m_pv,pdata->m_cbSize,&cbRead)))
  4038. {
  4039. break;
  4040. }
  4041. if (pdata->m_cbSize != cbRead)
  4042. {
  4043. hr= ResultFromScode (STG_E_READFAULT);
  4044. break;
  4045. }
  4046. break;
  4047. }
  4048. case FALSE:
  4049. {
  4050. const DWORD grfCreateStg = STGM_READWRITE | STGM_SHARE_EXCLUSIVE
  4051. | STGM_DIRECT | STGM_CREATE ;
  4052. // Copy pstg into pstgNative, thereby removing slack and
  4053. // giving us access to the bits via an ILockBytes
  4054. if (FAILED(hr = CreateILockBytesOnHGlobal (NULL, FALSE, &plkbyt)))
  4055. {
  4056. break;
  4057. }
  4058. if (FAILED(hr = StgCreateDocfileOnILockBytes
  4059. (plkbyt, grfCreateStg, 0, &pstgNative)))
  4060. {
  4061. break;
  4062. }
  4063. if (FAILED(hr = pstg->CopyTo (0, NULL, 0, pstgNative)))
  4064. {
  4065. break;
  4066. }
  4067. // Set pdata->m_cbSize
  4068. STATSTG statstg;
  4069. if (FAILED(hr = plkbyt->Stat (&statstg, 0)))
  4070. {
  4071. break;
  4072. }
  4073. pdata->m_cbSize = statstg.cbSize.LowPart;
  4074. // Set pdata->m_h
  4075. if (FAILED(hr = GetHGlobalFromILockBytes (plkbyt, &(pdata->m_h))))
  4076. {
  4077. break;
  4078. }
  4079. Assert (GlobalSize (pdata->m_h) >= pdata->m_cbSize);
  4080. // Set pdata->m_pv
  4081. pdata->m_pv = GlobalLock (pdata->m_h);
  4082. if (NULL == pdata->m_pv)
  4083. {
  4084. hr = ResultFromScode(E_OUTOFMEMORY);
  4085. break;
  4086. }
  4087. } // end case
  4088. } // end switch
  4089. // Cleanup and return status to caller
  4090. if (pstm)
  4091. {
  4092. pstm->Release();
  4093. }
  4094. if (plkbyt)
  4095. {
  4096. plkbyt->Release();
  4097. }
  4098. if (pstgNative)
  4099. {
  4100. pstgNative->Release();
  4101. }
  4102. return hr;
  4103. }
  4104. //+-------------------------------------------------------------------------
  4105. //
  4106. // Function: PutPresentationObject, INTERNAL
  4107. //
  4108. // Synopsis: Writes a presentation to an OLE 1 stream.
  4109. //
  4110. // Arguments: [pos] -- the OLE 1 stream to write to
  4111. // [ppres] -- the presentation object
  4112. // [cls] -- the class object
  4113. // [fStatic] -- flag: is this a static object
  4114. //
  4115. // Returns: NOERROR on success
  4116. // various possible I/O errors on failure
  4117. //
  4118. // History: dd-mmm-yy Author Comment
  4119. // 21-Feb-94 davepl Code cleaned up and documented
  4120. // Notes:
  4121. //
  4122. //--------------------------------------------------------------------------
  4123. static INTERNAL PutPresentationObject(
  4124. LPOLESTREAM pos,
  4125. const PRES FAR* ppres,
  4126. const CLASS FAR& cls,
  4127. BOOL fStatic) // optional
  4128. {
  4129. HRESULT hr;
  4130. // Is there a real presentation?
  4131. BOOL fIsPres = FALSE;
  4132. if (ppres)
  4133. {
  4134. if (ppres->m_format.m_ftag != ftagClipFormat ||
  4135. ppres->m_format.m_cf != 0 )
  4136. {
  4137. fIsPres = TRUE;
  4138. }
  4139. }
  4140. // write the OLE version to the stream
  4141. if (FAILED(hr = ULToOLE1Stream (pos, dwVerToFile)))
  4142. {
  4143. return hr;
  4144. }
  4145. // Calc format ID for presentation object, use 0 for no presentation
  4146. ULONG id = 0L;
  4147. if (fIsPres)
  4148. {
  4149. if (fStatic)
  4150. {
  4151. id = FMTID_STATIC;
  4152. }
  4153. else
  4154. {
  4155. id = FMTID_PRES;
  4156. }
  4157. }
  4158. if (FAILED(hr = ULToOLE1Stream(pos, id)))
  4159. {
  4160. return hr;
  4161. }
  4162. if (!fIsPres)
  4163. {
  4164. // No presentation
  4165. return NOERROR;
  4166. }
  4167. if (IsStandardFormat (ppres->m_format))
  4168. {
  4169. return PutStandardPresentation (pos, ppres);
  4170. }
  4171. else
  4172. {
  4173. Assert (!fStatic);
  4174. return PutGenericPresentation (pos, ppres, cls.m_szClsid);
  4175. }
  4176. }
  4177. //+-------------------------------------------------------------------------
  4178. //
  4179. // Function: PutStandardPresentation, INTERNAL
  4180. //
  4181. // Synopsis: Writes a standard presentation (META, DIB, or BITMAP) out
  4182. // to an OLE 1 stream. Creates the METAFILEPICT header
  4183. // as required.
  4184. //
  4185. // Arguments: [pos] -- the OLE 1 stream to write to
  4186. // [ppres] -- the presentation to write
  4187. //
  4188. // Returns: NOERROR on success
  4189. // Various other errors are possible from I/O routines
  4190. //
  4191. // History: dd-mmm-yy Author Comment
  4192. // 21-Feb-94 davepl Cleaned up and documented
  4193. // Notes:
  4194. //
  4195. //--------------------------------------------------------------------------
  4196. static INTERNAL PutStandardPresentation(
  4197. LPOLESTREAM pos,
  4198. const PRES FAR* ppres)
  4199. {
  4200. HRESULT hr = NOERROR;
  4201. Assert (ppres->m_format.m_ftag == ftagClipFormat);
  4202. // Write the clipboard format string to the OLE 1 stream
  4203. // (Will be written in ANSI, not OLESTR format)
  4204. switch (ppres->m_format.m_cf)
  4205. {
  4206. case CF_METAFILEPICT:
  4207. if (FAILED(hr = StringToOLE1Stm (pos, OLESTR("METAFILEPICT"))))
  4208. {
  4209. return hr;
  4210. }
  4211. break;
  4212. case CF_DIB:
  4213. if (FAILED(hr = StringToOLE1Stm (pos, OLESTR("DIB"))))
  4214. {
  4215. return hr;
  4216. }
  4217. break;
  4218. case CF_BITMAP:
  4219. if (FAILED(hr = StringToOLE1Stm (pos, OLESTR("BITMAP"))))
  4220. {
  4221. return hr;
  4222. }
  4223. break;
  4224. default:
  4225. Assert (0 && "Don't know how to write pres format");
  4226. }
  4227. // Write width
  4228. if (FAILED(hr = ULToOLE1Stream(pos, ppres->m_ulWidth)))
  4229. {
  4230. return hr;
  4231. }
  4232. // OLE 1.0 file format expects height to be saved as a negative value
  4233. if (FAILED(hr = ULToOLE1Stream(pos, - ((LONG)ppres->m_ulHeight))))
  4234. {
  4235. return hr;
  4236. }
  4237. // Do special handling for CF_METAFILEPICT
  4238. if (ppres->m_format.m_cf == CF_METAFILEPICT)
  4239. {
  4240. // Need a header to write, crete one here
  4241. WIN16METAFILEPICT mfpict =
  4242. {
  4243. MM_ANISOTROPIC,
  4244. (short) ppres->m_ulWidth,
  4245. (short) ppres->m_ulHeight,
  4246. 0
  4247. };
  4248. // put size ater adjusting it for metafilepict
  4249. if (FAILED(hr = ULToOLE1Stream
  4250. (pos, (ppres->m_data.m_cbSize + sizeof(WIN16METAFILEPICT)))))
  4251. {
  4252. return hr;
  4253. }
  4254. // put metafilepict
  4255. if (FAILED(hr = DataToOLE1Stm(pos, &mfpict, sizeof(mfpict))))
  4256. {
  4257. return hr;
  4258. }
  4259. // put metafile bits
  4260. // There are two possible means by which we got these metafile
  4261. // bits: either we have an in-memory metafile, or raw bits
  4262. // which we read from disk. If it is an in-memory metafile,
  4263. // the m_pv ptr will have been set to METADATAPTR, and we need
  4264. // to extract the bits to our own buffer before saving them.
  4265. // If they came from disk, we can just re-write the buffer
  4266. // into which we read them.
  4267. if (METADATAPTR == ppres->m_data.m_pv)
  4268. {
  4269. BYTE *pb = (BYTE *) PrivMemAlloc(ppres->m_data.m_cbSize);
  4270. if (NULL == pb)
  4271. {
  4272. return E_OUTOFMEMORY;
  4273. }
  4274. if (0 == GetMetaFileBitsEx((HMETAFILE) ppres->m_data.m_h,
  4275. ppres->m_data.m_cbSize, pb))
  4276. {
  4277. PrivMemFree(pb);
  4278. return HRESULT_FROM_WIN32(GetLastError());
  4279. }
  4280. if (FAILED(hr = DataToOLE1Stm(pos, pb, ppres->m_data.m_cbSize)))
  4281. {
  4282. PrivMemFree(pb);
  4283. return hr;
  4284. }
  4285. PrivMemFree(pb);
  4286. }
  4287. else // Bits were originally read into our buffer from disk
  4288. {
  4289. if (FAILED(hr = DataToOLE1Stm(pos, ppres->m_data.m_pv,
  4290. ppres->m_data.m_cbSize)))
  4291. {
  4292. return hr;
  4293. }
  4294. }
  4295. }
  4296. else
  4297. {
  4298. // Not a METAFILE, just write the data
  4299. if (FAILED(hr = SizedDataToOLE1Stm (pos, ppres->m_data)))
  4300. {
  4301. return hr;
  4302. }
  4303. }
  4304. return hr;
  4305. }
  4306. //+-------------------------------------------------------------------------
  4307. //
  4308. // Function: PutGenericPresentation, INTERNAL
  4309. //
  4310. // Synopsis: Writes a generic presentation to the stream based on
  4311. // the clipboard format. (Dumps raw pres data to stm)
  4312. //
  4313. // Arguments: [pos] -- the stream to write to
  4314. // [ppres] -- the presentation
  4315. // [szClass] -- class name
  4316. //
  4317. // History: dd-mmm-yy Author Comment
  4318. // 16-Feb-94 davepl 32-bit port'n'doc
  4319. // Notes:
  4320. //
  4321. //--------------------------------------------------------------------------
  4322. static INTERNAL PutGenericPresentation(
  4323. LPOLESTREAM pos,
  4324. const PRES FAR* ppres,
  4325. LPCOLESTR szClass)
  4326. {
  4327. Assert (szClass);
  4328. HRESULT hr = NOERROR;
  4329. // Write the format class name out to the stream
  4330. if (FAILED(hr = StringToOLE1Stm(pos, szClass)))
  4331. {
  4332. return hr;
  4333. }
  4334. // This semi-mythical 0xC000 occurs in
  4335. // other code I've seen in this project also; if there's
  4336. // a constant defined, someone ought to fix this
  4337. if (ppres->m_format.m_ftag == ftagClipFormat)
  4338. {
  4339. if (ppres->m_format.m_cf < 0xc000)
  4340. {
  4341. if (FAILED(hr = ULToOLE1Stream (pos, ppres->m_format.m_cf)))
  4342. {
  4343. return hr;
  4344. }
  4345. }
  4346. else
  4347. {
  4348. if (FAILED(hr = ULToOLE1Stream (pos, 0L)))
  4349. {
  4350. return hr;
  4351. }
  4352. OLECHAR buf[256];
  4353. if (!GetClipboardFormatName(ppres->m_format.m_cf, buf,
  4354. sizeof(buf)/sizeof(OLECHAR)))
  4355. {
  4356. return ResultFromScode(DV_E_CLIPFORMAT);
  4357. }
  4358. if (FAILED(hr = StringToOLE1Stm (pos, buf)))
  4359. {
  4360. return hr;
  4361. }
  4362. }
  4363. }
  4364. else if (ppres->m_format.m_ftag == ftagString)
  4365. {
  4366. // Write the format string to the stream
  4367. if (FAILED(hr = ULToOLE1Stream (pos, 0L)))
  4368. {
  4369. return hr;
  4370. }
  4371. if (FAILED(hr = SizedDataToOLE1Stm
  4372. (pos, ppres->m_format.m_dataFormatString)))
  4373. {
  4374. return hr;
  4375. }
  4376. }
  4377. else
  4378. {
  4379. AssertSz (0, "Bad format");
  4380. }
  4381. Assert (ppres->m_data.m_cbSize && ppres->m_data.m_h);
  4382. // Write the raw presentation data out
  4383. if (FAILED(hr = SizedDataToOLE1Stm (pos, ppres->m_data)))
  4384. {
  4385. return hr;
  4386. }
  4387. return NOERROR;
  4388. }
  4389. //+-------------------------------------------------------------------------
  4390. //
  4391. // Function: wClassesMatchW, INTERNAL INLINE
  4392. //
  4393. // Synopsis: Worker function to compare classes. Special case for
  4394. // handling when the class of the file cannot be determined
  4395. // because it is not a real file; this returns NOERROR
  4396. //
  4397. // History: dd-mmm-yy Author Comment
  4398. // 21-Feb-94 davepl Cleaned up and documented
  4399. //
  4400. // Notes:
  4401. //
  4402. //--------------------------------------------------------------------------
  4403. inline INTERNAL wClassesMatchW(REFCLSID clsidIn, LPOLESTR szFile)
  4404. {
  4405. CLSID clsid;
  4406. // If we can get the CLSID for the code that works with this file,
  4407. // compare it to the CLSID passed in, and return the result of
  4408. // that comparison
  4409. if (NOERROR==GetClassFile (szFile, &clsid))
  4410. {
  4411. if (IsEqualCLSID(clsid, clsidIn))
  4412. {
  4413. return NOERROR;
  4414. }
  4415. else
  4416. {
  4417. return ResultFromScode(S_FALSE);
  4418. }
  4419. }
  4420. else
  4421. {
  4422. // If we can't determine the class of the file (because it's
  4423. // not a real file) then OK.
  4424. // Bug 3937.
  4425. return NOERROR;
  4426. }
  4427. }
  4428. //+-------------------------------------------------------------------------
  4429. //
  4430. // Function: MonikerIntoGenObj, INTERNAL
  4431. //
  4432. // Synopsis: Merges an OLE 2.0 moniker into a generic object
  4433. //
  4434. // Effects: Sets ths Topic, Item, and class members
  4435. //
  4436. // Arguments: [pgenobj] -- the generic object to receive moniker
  4437. // [clsidLast] -- if a link, what its a link to
  4438. // [pmk] -- the moniker to merge in
  4439. //
  4440. // History: dd-mmm-yy Author Comment
  4441. // 21-Feb-94 davepl Code cleanup
  4442. //
  4443. // Notes:
  4444. //
  4445. //--------------------------------------------------------------------------
  4446. static INTERNAL MonikerIntoGenObj(
  4447. PGENOBJ pgenobj,
  4448. REFCLSID clsidLast,
  4449. LPMONIKER pmk )
  4450. {
  4451. LPOLESTR szFile=NULL;
  4452. LPOLESTR szItem=NULL;
  4453. BOOL fClassesMatch = FALSE;
  4454. // If the classes match, that implies this is a link to a pseudo-object
  4455. // not to an embedded object. If GetClassFile fails because the file
  4456. // does not exist or is unsaved then we give the link the benefit
  4457. // of the doubt and let it stay a link. Only if we know the
  4458. // classes do NOT match do we change the link into an Ole2Link
  4459. // embedded object.
  4460. // Ole10_PareMoniker returns S_FALSE in the FileMoniker - ItemMoniker - ItemMoniker... case
  4461. // so check for NOERROR explicitly.
  4462. if (NOERROR == Ole10_ParseMoniker (pmk, &szFile, &szItem))
  4463. {
  4464. if (szFile)
  4465. {
  4466. SCODE sc = GetScode(wClassesMatchW(clsidLast, szFile));
  4467. if (sc == S_OK || sc == MK_E_CANTOPENFILE)
  4468. {
  4469. pgenobj->m_szTopic = szFile;
  4470. pgenobj->m_szItem = szItem;
  4471. fClassesMatch = TRUE;
  4472. }
  4473. }
  4474. }
  4475. if (FALSE == fClassesMatch)
  4476. {
  4477. // This moniker is either not a File or File::Item moniker,
  4478. // or is a link to an embedded object, so the only
  4479. // way we can convert it to OLE 1.0 is to make it an opaque Ole2Link
  4480. pgenobj->m_fLink = FALSE;
  4481. pgenobj->m_class.Reset (CLSID_StdOleLink);
  4482. }
  4483. return NOERROR;
  4484. }
  4485. //+-------------------------------------------------------------------------
  4486. //
  4487. // Function: OleConvertIStorageToOLESTREAMEx, STDAPI
  4488. //
  4489. // Synopsis: Similar to OleConvertIStorageToOLESTREAM, except that the
  4490. // presentation data that needs to be written into OLESTREAM
  4491. // is passed in. pmedium->tymed can only be TYMED_HGLOBAL
  4492. // or TYMED_ISTREAM and the medium will not be released by the
  4493. // api. cfFormat can be NULL, If it is NULL then the other
  4494. // parameters (lWidth, lHeight, dwSize, pmedium) will be ignored.
  4495. //
  4496. // Arguments: [pstg] -- the storage object to convert from
  4497. // [cfFormat] -- clipboard format
  4498. // [lWidth] -- width
  4499. // [lHeight] -- height
  4500. // [dwSize] -- size in bytes
  4501. // [pmedium] -- serialized bytes
  4502. // [polestm] -- the OLE 1 stream to write to
  4503. //
  4504. // Returns: NOERROR on success
  4505. // DV_E_TYMED invalid clipboard format
  4506. // E_INVALIDARG invalid arg, normally stg or stm
  4507. // DV_E_STGMEDIUM bad medium ptr
  4508. // E_OUTOFMEMORY allocation failure
  4509. //
  4510. // History: dd-mmm-yy Author Comment
  4511. // 21-Feb-94 davepl Cleaned up and documented
  4512. //
  4513. // Notes:
  4514. //
  4515. //--------------------------------------------------------------------------
  4516. STDAPI OleConvertIStorageToOLESTREAMEx
  4517. (
  4518. LPSTORAGE pstg,
  4519. CLIPFORMAT cfFormat,
  4520. LONG lWidth,
  4521. LONG lHeight,
  4522. DWORD dwSize,
  4523. LPSTGMEDIUM pmedium,
  4524. LPOLESTREAM polestm
  4525. )
  4526. {
  4527. OLETRACEIN((API_OleConvertIStorageToOLESTREAMEx,
  4528. PARAMFMT("pstg= %p, cfFormat= %x, lWidth= %d, lHeight= %d, dwSize= %ud, pmedium= %ts, polestm= %p"),
  4529. pstg, cfFormat, lWidth, lHeight, dwSize, pmedium, polestm));
  4530. LEDebugOut((DEB_ITRACE, "%p _IN OleConvertIStorageToOLESTREAMEx ("
  4531. " %p, %x , %lx , %lx , %x , %p , %p )\n", 0 /*function*/,
  4532. pstg, cfFormat, lWidth, lHeight, dwSize, pmedium, polestm
  4533. ));
  4534. CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IStorage,(IUnknown **)&pstg);
  4535. HGLOBAL hGlobal = NULL;
  4536. HRESULT hr = NOERROR;
  4537. BOOL fFree = FALSE;
  4538. CGenericObject genobj;
  4539. // If we are given a clipboard format...
  4540. if (cfFormat) {
  4541. VDATEPTRIN_LABEL(pmedium, STGMEDIUM, errRtn, hr);
  4542. // Check that the medium ptr is valid
  4543. if (pmedium->hGlobal == NULL)
  4544. {
  4545. hr = ResultFromScode(DV_E_STGMEDIUM);
  4546. goto errRtn;
  4547. }
  4548. // Cannot have a 0 sized clipboard representation
  4549. if (dwSize == 0)
  4550. {
  4551. hr = ResultFromScode(E_INVALIDARG);
  4552. goto errRtn;
  4553. }
  4554. switch (pmedium->tymed)
  4555. {
  4556. case TYMED_HGLOBAL:
  4557. hGlobal = pmedium->hGlobal;
  4558. break;
  4559. case TYMED_ISTREAM:
  4560. VDATEIFACE_LABEL(pmedium->pstm, errRtn, hr);
  4561. if ((hr = UtGetHGLOBALFromStm(pmedium->pstm, dwSize,
  4562. &hGlobal)) != NOERROR)
  4563. {
  4564. goto errRtn;
  4565. }
  4566. fFree = TRUE;
  4567. break;
  4568. default:
  4569. hr = ResultFromScode(DV_E_TYMED);
  4570. goto errRtn;
  4571. }
  4572. }
  4573. if (FAILED(hr = wConvertIStorageToOLESTREAM(pstg, polestm, &genobj)))
  4574. {
  4575. goto errRtn;
  4576. }
  4577. // Clean m_ppres
  4578. if (genobj.m_ppres)
  4579. {
  4580. delete genobj.m_ppres;
  4581. genobj.m_ppres = NULL;
  4582. }
  4583. if (cfFormat)
  4584. {
  4585. // fill genobj.m_ppres
  4586. PPRES ppres;
  4587. if ((genobj.m_ppres = ppres = new PRES) == NULL)
  4588. {
  4589. hr = ResultFromScode(E_OUTOFMEMORY);
  4590. goto errRtn;
  4591. }
  4592. ppres->m_ulWidth = (ULONG) lWidth;
  4593. ppres->m_ulHeight = (ULONG) lHeight;
  4594. ppres->m_data.m_cbSize = dwSize;
  4595. ppres->m_data.m_fNoFree = !fFree;
  4596. ppres->m_data.m_h = hGlobal;
  4597. ppres->m_data.m_pv = GlobalLock(hGlobal);
  4598. ppres->m_format.m_ftag = ftagClipFormat;
  4599. ppres->m_format.m_cf = cfFormat;
  4600. }
  4601. else
  4602. {
  4603. genobj.m_fNoBlankPres = TRUE;
  4604. }
  4605. // REVIEW: We may not want to allow NULL cfFormat with static object
  4606. hr = GenericObjectToOLESTREAM (genobj, polestm);
  4607. LEDebugOut((DEB_ITRACE, "%p OUT OleConvertIStorageToOLESTREAMEx ( %lx ) "
  4608. "\n", 0 /*function*/, hr));
  4609. OLETRACEOUT((API_OleConvertIStorageToOLESTREAMEx, hr));
  4610. return hr;
  4611. errRtn:
  4612. if (fFree && hGlobal != NULL)
  4613. {
  4614. GlobalFree(hGlobal);
  4615. }
  4616. LEDebugOut((DEB_ITRACE, "%p OUT OleConvertIStorageToOLESTREAMEx ( %lx ) "
  4617. "\n", 0 /*function*/, hr));
  4618. OLETRACEOUT((API_OleConvertIStorageToOLESTREAMEx, hr));
  4619. return hr;
  4620. }
  4621. //+-------------------------------------------------------------------------
  4622. //
  4623. // Function: OleConvertOLESTREAMToIStorageEx, STDAPI
  4624. //
  4625. // Synopsis: Similar to OleConvertOLESTREAMToIStorage, except that the
  4626. // presentation data that is read from OLESTREAM is passed out.
  4627. // And no presentation stream will written in to the storage.
  4628. // pmedium->tymed can be TYMED_ISTREAM ot TYMED_NULL. If
  4629. // TYMED_NULL, then the bits will be returned in a global
  4630. // handle through pmedium->hGlobal. Otherwise data will be
  4631. // written into pmedium->pstm. NULL will be returned through
  4632. // *pcfFormat, if there is no presentation in the OLESTREAM.
  4633. //
  4634. // Arguments: [pstg] -- the storage object to convert to
  4635. // [cfFormat] -- clipboard format
  4636. // [lWidth] -- width
  4637. // [lHeight] -- height
  4638. // [dwSize] -- size in bytes
  4639. // [pmedium] -- serialized bytes
  4640. // [polestm] -- the OLE 1 stream to write from
  4641. //
  4642. // Returns: DV_E_TYMED invalid clipboard format
  4643. //
  4644. // History: dd-mmm-yy Author Comment
  4645. // 21-Feb-94 davepl Cleaned up and documented
  4646. // Notes:
  4647. //
  4648. //--------------------------------------------------------------------------
  4649. STDAPI OleConvertOLESTREAMToIStorageEx
  4650. (
  4651. LPOLESTREAM polestm,
  4652. LPSTORAGE pstg,
  4653. CLIPFORMAT FAR* pcfFormat,
  4654. LONG FAR* plWidth,
  4655. LONG FAR* plHeight,
  4656. DWORD FAR* pdwSize,
  4657. LPSTGMEDIUM pmedium
  4658. )
  4659. {
  4660. OLETRACEIN((API_OleConvertOLESTREAMToIStorageEx,
  4661. PARAMFMT("polestm= %p, pstg= %p, pcfFormat= %p, plWidth= %p, plHeight= %p, pdwSize= %p, pmedium= %p"),
  4662. polestm, pstg, pcfFormat, plWidth, plHeight, pdwSize, pmedium));
  4663. LEDebugOut((DEB_ITRACE, "%p _IN OleConvertOLESTREAMToIStorageEx ("
  4664. " %p , %p , %p , %p , %p , %p , %p )\n", 0 /*function*/,
  4665. polestm, pstg, pcfFormat,plWidth,plHeight,pdwSize,pmedium
  4666. ));
  4667. HRESULT hr;
  4668. PPRES ppres = NULL;
  4669. GENOBJ genobj;
  4670. VDATEPTROUT_LABEL(pcfFormat, CLIPFORMAT, errRtn, hr);
  4671. VDATEPTROUT_LABEL(plWidth, LONG, errRtn, hr);
  4672. VDATEPTROUT_LABEL(plHeight, LONG, errRtn, hr);
  4673. VDATEPTROUT_LABEL(pdwSize, DWORD, errRtn, hr);
  4674. VDATEPTROUT_LABEL(pmedium, STGMEDIUM, errRtn, hr);
  4675. CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IStorage,(IUnknown **)&pstg);
  4676. if (pmedium->tymed == TYMED_ISTREAM)
  4677. {
  4678. VDATEIFACE_LABEL(pmedium->pstm, errRtn, hr);
  4679. }
  4680. else if (pmedium->tymed != TYMED_NULL)
  4681. {
  4682. hr = ResultFromScode(DV_E_TYMED);
  4683. goto errRtn;
  4684. }
  4685. // Bring the object into genobj
  4686. if (FAILED((hr = wConvertOLESTREAMToIStorage(polestm, pstg, &genobj))))
  4687. {
  4688. goto errRtn;
  4689. }
  4690. ppres = genobj.m_ppres;
  4691. genobj.m_ppres = NULL;
  4692. if (FAILED(hr = GenericObjectToIStorage (genobj, pstg, NULL)))
  4693. {
  4694. goto errRtn;
  4695. }
  4696. // If no presentation is available, clear our all the pres
  4697. // dimensions and format
  4698. if (ppres == NULL)
  4699. {
  4700. *pcfFormat = 0;
  4701. *plWidth = 0L;
  4702. *plHeight = 0L;
  4703. *pdwSize = 0L;
  4704. // Don't worry about the pmedium, it is already in the proper state
  4705. hr = NOERROR;
  4706. goto errRtn;
  4707. }
  4708. // If we reach here, we have a presentation, so set the OUT
  4709. // parameters accordingly
  4710. *plWidth = (LONG) ppres->m_ulWidth;
  4711. *plHeight = (LONG) ppres->m_ulHeight;
  4712. *pdwSize = ppres->m_data.m_cbSize;
  4713. Assert(ppres->m_format.m_ftag != ftagNone);
  4714. // If we have a clipboard format ID, return that in the OUT paramter,
  4715. // otherwise return whatever we get back from an attempt to register
  4716. // the format string
  4717. if (ppres->m_format.m_ftag == ftagClipFormat)
  4718. {
  4719. *pcfFormat = ppres->m_format.m_cf;
  4720. }
  4721. else
  4722. {
  4723. // m_dataFormatString is an ASCII string.
  4724. *pcfFormat = (CLIPFORMAT) SSRegisterClipboardFormatA( (LPCSTR) ppres->m_format.m_dataFormatString.m_pv);
  4725. Assert(0 != *pcfFormat);
  4726. }
  4727. if (pmedium->tymed == TYMED_NULL)
  4728. {
  4729. if (ppres->m_data.m_h)
  4730. {
  4731. Assert(ppres->m_data.m_pv != NULL);
  4732. GlobalUnlock(ppres->m_data.m_h);
  4733. }
  4734. // transfer the ownership
  4735. pmedium->tymed = TYMED_HGLOBAL;
  4736. pmedium->hGlobal = ppres->m_data.m_h;
  4737. // Null out the handle and pointer so that destructor of PRES will not
  4738. // free it.
  4739. ppres->m_data.m_h = NULL;
  4740. ppres->m_data.m_pv = NULL;
  4741. }
  4742. else
  4743. {
  4744. hr = pmedium->pstm->Write(ppres->m_data.m_pv, *pdwSize, NULL);
  4745. }
  4746. errRtn:
  4747. if (ppres)
  4748. {
  4749. delete ppres;
  4750. }
  4751. LEDebugOut((DEB_ITRACE, "%p OUT OleConvertOLESTREAMToIStorageEx ( %lx ) "
  4752. "\n", 0 /*function*/, hr));
  4753. OLETRACEOUT((API_OleConvertOLESTREAMToIStorageEx, hr));
  4754. return hr;
  4755. }
  4756. //+-------------------------------------------------------------------------
  4757. //
  4758. // Function: wWriteFmtUserType, INTERNAL
  4759. //
  4760. // Synopsis: Gets the user type for a class ID and writes it to
  4761. // an IStorage
  4762. //
  4763. //
  4764. // Arguments: [pstg] -- the storage to write to
  4765. // [clsid] -- the class ID
  4766. //
  4767. //
  4768. // Returns: NOERROR on success
  4769. //
  4770. // History: dd-mmm-yy Author Comment
  4771. // 21-Feb-94 davepl Cleaned up and documented
  4772. // Notes:
  4773. //
  4774. //--------------------------------------------------------------------------
  4775. FARINTERNAL wWriteFmtUserType(LPSTORAGE pstg, REFCLSID clsid)
  4776. {
  4777. HRESULT hr = NOERROR;
  4778. LPOLESTR szProgID = NULL;
  4779. LPOLESTR szUserType = NULL;
  4780. // Get the program ID
  4781. if (FAILED(hr = ProgIDFromCLSID (clsid, &szProgID)))
  4782. {
  4783. goto errRtn;
  4784. }
  4785. // Get the user type
  4786. if (FAILED(hr = OleRegGetUserType(clsid,USERCLASSTYPE_FULL,&szUserType)))
  4787. {
  4788. goto errRtn;
  4789. }
  4790. // Write the user type out to the storage
  4791. if (FAILED(hr = WriteFmtUserTypeStg
  4792. (pstg, (CLIPFORMAT) RegisterClipboardFormat (szProgID), szUserType)))
  4793. {
  4794. goto errRtn;
  4795. }
  4796. // Clean up and return status
  4797. errRtn:
  4798. if (szProgID)
  4799. {
  4800. PubMemFree(szProgID);
  4801. }
  4802. if (szUserType)
  4803. {
  4804. PubMemFree(szUserType);
  4805. }
  4806. return hr;
  4807. }
  4808. //+-------------------------------------------------------------------------
  4809. //
  4810. // Function: wCLSIDFromProgID
  4811. //
  4812. // Synopsis: Looks for the key HKEY_CLASSES_ROOT\{ProgID}\Clsid\ to get
  4813. // the string version of the class ID, then returns the CLSID
  4814. // value of whatever it found.
  4815. //
  4816. // History: dd-mmm-yy Author Comment
  4817. // 25-Jun-94 alexgo fixed Ole1 CLSID creation
  4818. // 15-Apr-94 davepl Rewrite
  4819. //
  4820. // Notes: Used to be in clipboard code, but used in this file
  4821. //
  4822. //--------------------------------------------------------------------------
  4823. INTERNAL wCLSIDFromProgID(LPOLESTR szProgID, LPCLSID pclsid, BOOL fForceAssign)
  4824. {
  4825. VDATEHEAP();
  4826. // Apparently some optimization. If the class name is "OLE2Link", we can
  4827. // return CLSID_StdOleLInk without even bothering to check the registry.
  4828. if (0 == _xstrcmp(szProgID, OLESTR("OLE2Link")))
  4829. {
  4830. *pclsid = CLSID_StdOleLink;
  4831. return NOERROR;
  4832. }
  4833. else
  4834. {
  4835. // this function will look for a CLSID under the ProgID entry in
  4836. // the registry or manufacture one if none present.
  4837. return CLSIDFromOle1Class(szProgID, pclsid, fForceAssign);
  4838. }
  4839. }
  4840. //+-------------------------------------------------------------------------
  4841. //
  4842. // Function: wProgIDFromCLSID
  4843. //
  4844. // Synopsis: A wrapper for ProgIDFromCLSID. The only change in
  4845. // functionality is to check and see if this is a
  4846. // CLSID_StdOleLink, and if so, return a prog ID of
  4847. // "OLE2Link" rather than failing.
  4848. //
  4849. //
  4850. // History: dd-mmm-yy Author Comment
  4851. // 15-Feb-94 davepl Rewrite
  4852. //
  4853. //--------------------------------------------------------------------------
  4854. FARINTERNAL wProgIDFromCLSID(REFCLSID clsid, LPOLESTR FAR* psz)
  4855. {
  4856. VDATEHEAP();
  4857. HRESULT hresult;
  4858. // If we can get the ProgID by conventional methods, great, just
  4859. // return it.
  4860. if (NOERROR == (hresult = ProgIDFromCLSID(clsid, psz)))
  4861. {
  4862. return hresult;
  4863. }
  4864. // If we failed, it might be because this is a standard OLE link, which
  4865. // will not have a ProgID entry in the registry, so we fake it out by
  4866. // returning the ProgID manually.
  4867. if (IsEqualCLSID(clsid, CLSID_StdOleLink))
  4868. {
  4869. *psz = UtDupString(OLESTR("OLE2Link"));
  4870. if (*psz == NULL)
  4871. {
  4872. hresult = E_OUTOFMEMORY;
  4873. }
  4874. else
  4875. {
  4876. hresult = NOERROR;
  4877. }
  4878. }
  4879. // Must not have been able to resolve for ProgID, so return the error.
  4880. return(hresult);
  4881. }
  4882. #if 0
  4883. // We don't need these conversion fns yet, but we likely will soon.
  4884. inline INTERNAL_(VOID) ConvertBM32to16(LPBITMAP lpsrc, LPWIN16BITMAP lpdest)
  4885. {
  4886. lpdest->bmType = (short)lpsrc->bmType;
  4887. lpdest->bmWidth = (short)lpsrc->bmWidth;
  4888. lpdest->bmHeight = (short)lpsrc->bmHeight;
  4889. lpdest->bmWidthBytes = (short)lpsrc->bmWidthBytes;
  4890. lpdest->bmPlanes = (BYTE)lpsrc->bmPlanes;
  4891. lpdest->bmBitsPixel = (BYTE)lpsrc->bmBitsPixel;
  4892. }
  4893. inline INTERNAL_(VOID) ConvertBM16to32(LPWIN16BITMAP lpsrc, LPBITMAP lpdest)
  4894. {
  4895. lpdest->bmType = MAKELONG(lpsrc->bmType,NULL_WORD);
  4896. lpdest->bmWidth = MAKELONG(lpsrc->bmWidth,NULL_WORD);
  4897. lpdest->bmHeight = MAKELONG(lpsrc->bmHeight,NULL_WORD);
  4898. lpdest->bmWidthBytes = MAKELONG(lpsrc->bmWidthBytes,NULL_WORD);
  4899. lpdest->bmPlanes = (WORD)lpsrc->bmPlanes;
  4900. lpdest->bmBitsPixel = (WORD)lpsrc->bmBitsPixel;
  4901. }
  4902. inline INTERNAL_(VOID) ConvertMF16to32(
  4903. LPWIN16METAFILEPICT lpsrc,
  4904. LPMETAFILEPICT lpdest )
  4905. {
  4906. lpdest->mm = (DWORD)lpsrc->mm;
  4907. lpdest->xExt = (DWORD)MAKELONG(lpsrc->xExt,NULL_WORD);
  4908. lpdest->yExt = (DWORD)MAKELONG(lpsrc->yExt,NULL_WORD);
  4909. }
  4910. inline INTERNAL_(VOID) ConvertMF32to16(
  4911. LPMETAFILEPICT lpsrc,
  4912. LPWIN16METAFILEPICT lpdest )
  4913. {
  4914. lpdest->mm = (short)lpsrc->mm;
  4915. lpdest->xExt = (short)lpsrc->xExt;
  4916. lpdest->yExt = (short)lpsrc->yExt;
  4917. }
  4918. #endif