Source code of Windows XP (NT5)
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.

3048 lines
90 KiB

  1. /*************************************************************************
  2. **
  3. ** OLE 2 Standard Utilities
  4. **
  5. ** olestd.c
  6. **
  7. ** This file contains utilities that are useful for most standard
  8. ** OLE 2.0 compound document type applications.
  9. **
  10. ** (c) Copyright Microsoft Corp. 1992 All Rights Reserved
  11. **
  12. *************************************************************************/
  13. // #define NONAMELESSUNION // use strict ANSI standard (for DVOBJ.H)
  14. #define STRICT 1
  15. #include "ole2ui.h"
  16. #include <stdlib.h>
  17. #include <ctype.h>
  18. #include <shellapi.h>
  19. #include "regdb.h"
  20. #include "geticon.h"
  21. #include "common.h"
  22. OLEDBGDATA
  23. static TCHAR szAssertMemAlloc[] = TEXT("CoGetMalloc failed");
  24. static int IsCloseFormatEtc(FORMATETC FAR* pFetcLeft, FORMATETC FAR* pFetcRight);
  25. /* OleStdSetupAdvises
  26. ** ------------------
  27. ** Setup the standard View advise required by a standard,
  28. ** compound document-oriented container. Such a container relies on
  29. ** Ole to manage the presentation of the Ole object. The container
  30. ** call IViewObject::Draw to render (display) the object.
  31. **
  32. ** This helper routine performs the following tasks:
  33. ** setup View advise
  34. ** Call IOleObject::SetHostNames
  35. ** Call OleSetContainedObject
  36. **
  37. ** fCreate should be set to TRUE if the object is being created. if
  38. ** an existing object is being loaded, then fCreate should be FALSE.
  39. ** if it is a creation situation, then the ADVF_PRIMEFIRST flag is
  40. ** used when settinp up the IViewObject::Advise. This will result in
  41. ** the immediate sending of the initial picture.
  42. **
  43. ** OLE2NOTE: the standard container does NOT need to set up an OLE
  44. ** Advise (IOleObject::Advise). this routine does NOT set up an OLE
  45. ** Advise (a previous version of this function used to setup this
  46. ** advise, but it was not useful).
  47. */
  48. STDAPI_(BOOL) OleStdSetupAdvises(LPOLEOBJECT lpOleObject, DWORD dwDrawAspect,
  49. LPTSTR lpszContainerApp, LPTSTR lpszContainerObj,
  50. LPADVISESINK lpAdviseSink, BOOL fCreate)
  51. {
  52. LPVIEWOBJECT lpViewObject;
  53. HRESULT hrErr;
  54. BOOL fStatus = TRUE;
  55. #if defined( SPECIAL_CONTAINER )
  56. DWORD dwTemp;
  57. #endif
  58. hrErr = lpOleObject->lpVtbl->QueryInterface(
  59. lpOleObject,
  60. &IID_IViewObject,
  61. (LPVOID FAR*)&lpViewObject
  62. );
  63. /* Setup View advise */
  64. if (hrErr == NOERROR) {
  65. OLEDBG_BEGIN2(TEXT("IViewObject::SetAdvise called\r\n"))
  66. lpViewObject->lpVtbl->SetAdvise(
  67. lpViewObject,
  68. dwDrawAspect,
  69. (fCreate ? ADVF_PRIMEFIRST : 0),
  70. lpAdviseSink
  71. );
  72. OLEDBG_END2
  73. OleStdRelease((LPUNKNOWN)lpViewObject);
  74. } else {
  75. fStatus = FALSE;
  76. }
  77. #if defined( SPECIAL_CONTAINER )
  78. /* Setup OLE advise.
  79. ** OLE2NOTE: normally containers do NOT need to setup an OLE
  80. ** advise. this advise connection is only useful for the OLE's
  81. ** DefHandler and the OleLink object implementation. some
  82. ** special container's might need to setup this advise for
  83. ** programatic reasons.
  84. **
  85. ** NOTE: this advise will be torn down automatically by the
  86. ** server when we release the object, therefore we do not need
  87. ** to store the connection id.
  88. */
  89. OLEDBG_BEGIN2(TEXT("IOleObject::Advise called\r\n"))
  90. hrErr = lpOleObject->lpVtbl->Advise(
  91. lpOleObject,
  92. lpAdviseSink,
  93. (DWORD FAR*)&dwTemp
  94. );
  95. OLEDBG_END2
  96. if (hrErr != NOERROR) fStatus = FALSE;
  97. #endif
  98. /* Setup the host names for the OLE object. */
  99. OLEDBG_BEGIN2(TEXT("IOleObject::SetHostNames called\r\n"))
  100. hrErr = CallIOleObjectSetHostNamesA(
  101. lpOleObject,
  102. lpszContainerApp,
  103. lpszContainerObj
  104. );
  105. OLEDBG_END2
  106. if (hrErr != NOERROR) fStatus = FALSE;
  107. /* Inform the loadded object's handler/inproc-server that it is in
  108. ** its embedding container's process.
  109. */
  110. OLEDBG_BEGIN2(TEXT("OleSetContainedObject(TRUE) called\r\n"))
  111. OleSetContainedObject((LPUNKNOWN)lpOleObject, TRUE);
  112. OLEDBG_END2
  113. return fStatus;
  114. }
  115. /* OleStdSwitchDisplayAspect
  116. ** -------------------------
  117. ** Switch the currently cached display aspect between DVASPECT_ICON
  118. ** and DVASPECT_CONTENT.
  119. **
  120. ** NOTE: when setting up icon aspect, any currently cached content
  121. ** cache is discarded and any advise connections for content aspect
  122. ** are broken.
  123. **
  124. ** RETURNS:
  125. ** S_OK -- new display aspect setup successfully
  126. ** E_INVALIDARG -- IOleCache interface is NOT supported (this is
  127. ** required).
  128. ** <other SCODE> -- any SCODE that can be returned by
  129. ** IOleCache::Cache method.
  130. ** NOTE: if an error occurs then the current display aspect and
  131. ** cache contents unchanged.
  132. */
  133. STDAPI OleStdSwitchDisplayAspect(
  134. LPOLEOBJECT lpOleObj,
  135. LPDWORD lpdwCurAspect,
  136. DWORD dwNewAspect,
  137. HGLOBAL hMetaPict,
  138. BOOL fDeleteOldAspect,
  139. BOOL fSetupViewAdvise,
  140. LPADVISESINK lpAdviseSink,
  141. BOOL FAR* lpfMustUpdate
  142. )
  143. {
  144. LPOLECACHE lpOleCache = NULL;
  145. LPVIEWOBJECT lpViewObj = NULL;
  146. LPENUMSTATDATA lpEnumStatData = NULL;
  147. STATDATA StatData;
  148. FORMATETC FmtEtc;
  149. STGMEDIUM Medium;
  150. DWORD dwAdvf;
  151. DWORD dwNewConnection;
  152. DWORD dwOldAspect = *lpdwCurAspect;
  153. HRESULT hrErr;
  154. if (lpfMustUpdate)
  155. *lpfMustUpdate = FALSE;
  156. lpOleCache = (LPOLECACHE)OleStdQueryInterface(
  157. (LPUNKNOWN)lpOleObj,&IID_IOleCache);
  158. // if IOleCache* is NOT available, do nothing
  159. if (! lpOleCache)
  160. return ResultFromScode(E_INVALIDARG);
  161. // Setup new cache with the new aspect
  162. FmtEtc.cfFormat = (CLIPFORMAT) NULL; // whatever is needed to draw
  163. FmtEtc.ptd = NULL;
  164. FmtEtc.dwAspect = dwNewAspect;
  165. FmtEtc.lindex = -1;
  166. FmtEtc.tymed = TYMED_NULL;
  167. /* OLE2NOTE: if we are setting up Icon aspect with a custom icon
  168. ** then we do not want DataAdvise notifications to ever change
  169. ** the contents of the data cache. thus we set up a NODATA
  170. ** advise connection. otherwise we set up a standard DataAdvise
  171. ** connection.
  172. */
  173. if (dwNewAspect == DVASPECT_ICON && hMetaPict)
  174. dwAdvf = ADVF_NODATA;
  175. else
  176. dwAdvf = ADVF_PRIMEFIRST;
  177. OLEDBG_BEGIN2(TEXT("IOleCache::Cache called\r\n"))
  178. hrErr = lpOleCache->lpVtbl->Cache(
  179. lpOleCache,
  180. (LPFORMATETC)&FmtEtc,
  181. dwAdvf,
  182. (LPDWORD)&dwNewConnection
  183. );
  184. OLEDBG_END2
  185. if (! SUCCEEDED(hrErr)) {
  186. OleDbgOutHResult(TEXT("IOleCache::Cache returned"), hrErr);
  187. OleStdRelease((LPUNKNOWN)lpOleCache);
  188. return hrErr;
  189. }
  190. *lpdwCurAspect = dwNewAspect;
  191. /* OLE2NOTE: if we are setting up Icon aspect with a custom icon,
  192. ** then stuff the icon into the cache. otherwise the cache must
  193. ** be forced to be updated. set the *lpfMustUpdate flag to tell
  194. ** caller to force the object to Run so that the cache will be
  195. ** updated.
  196. */
  197. if (dwNewAspect == DVASPECT_ICON && hMetaPict) {
  198. FmtEtc.cfFormat = CF_METAFILEPICT;
  199. FmtEtc.ptd = NULL;
  200. FmtEtc.dwAspect = DVASPECT_ICON;
  201. FmtEtc.lindex = -1;
  202. FmtEtc.tymed = TYMED_MFPICT;
  203. Medium.tymed = TYMED_MFPICT;
  204. Medium.hGlobal = hMetaPict;
  205. Medium.pUnkForRelease = NULL;
  206. OLEDBG_BEGIN2(TEXT("IOleCache::SetData called\r\n"))
  207. hrErr = lpOleCache->lpVtbl->SetData(
  208. lpOleCache,
  209. (LPFORMATETC)&FmtEtc,
  210. (LPSTGMEDIUM)&Medium,
  211. FALSE /* fRelease */
  212. );
  213. OLEDBG_END2
  214. } else {
  215. if (lpfMustUpdate)
  216. *lpfMustUpdate = TRUE;
  217. }
  218. if (fSetupViewAdvise && lpAdviseSink) {
  219. /* OLE2NOTE: re-establish the ViewAdvise connection */
  220. lpViewObj = (LPVIEWOBJECT)OleStdQueryInterface(
  221. (LPUNKNOWN)lpOleObj,&IID_IViewObject);
  222. if (lpViewObj) {
  223. OLEDBG_BEGIN2(TEXT("IViewObject::SetAdvise called\r\n"))
  224. lpViewObj->lpVtbl->SetAdvise(
  225. lpViewObj,
  226. dwNewAspect,
  227. 0,
  228. lpAdviseSink
  229. );
  230. OLEDBG_END2
  231. OleStdRelease((LPUNKNOWN)lpViewObj);
  232. }
  233. }
  234. /* OLE2NOTE: remove any existing caches that are set up for the old
  235. ** display aspect. It WOULD be possible to retain the caches set
  236. ** up for the old aspect, but this would increase the storage
  237. ** space required for the object and possibly require additional
  238. ** overhead to maintain the unused cachaes. For these reasons the
  239. ** strategy to delete the previous caches is prefered. if it is a
  240. ** requirement to quickly switch between Icon and Content
  241. ** display, then it would be better to keep both aspect caches.
  242. */
  243. if (fDeleteOldAspect) {
  244. OLEDBG_BEGIN2(TEXT("IOleCache::EnumCache called\r\n"))
  245. hrErr = lpOleCache->lpVtbl->EnumCache(
  246. lpOleCache,
  247. (LPENUMSTATDATA FAR*)&lpEnumStatData
  248. );
  249. OLEDBG_END2
  250. while(hrErr == NOERROR) {
  251. hrErr = lpEnumStatData->lpVtbl->Next(
  252. lpEnumStatData,
  253. 1,
  254. (LPSTATDATA)&StatData,
  255. NULL
  256. );
  257. if (hrErr != NOERROR)
  258. break; // DONE! no more caches.
  259. if (StatData.formatetc.dwAspect == dwOldAspect) {
  260. // Remove previous cache with old aspect
  261. OLEDBG_BEGIN2(TEXT("IOleCache::Uncache called\r\n"))
  262. lpOleCache->lpVtbl->Uncache(lpOleCache,StatData.dwConnection);
  263. OLEDBG_END2
  264. }
  265. }
  266. if (lpEnumStatData) {
  267. OleStdVerifyRelease(
  268. (LPUNKNOWN)lpEnumStatData,
  269. TEXT("OleStdSwitchDisplayAspect: Cache enumerator NOT released")
  270. );
  271. }
  272. }
  273. if (lpOleCache)
  274. OleStdRelease((LPUNKNOWN)lpOleCache);
  275. return NOERROR;
  276. }
  277. /* OleStdSetIconInCache
  278. ** --------------------
  279. ** SetData a new icon into the existing DVASPECT_ICON cache.
  280. **
  281. ** RETURNS:
  282. ** HRESULT returned from IOleCache::SetData
  283. */
  284. STDAPI OleStdSetIconInCache(LPOLEOBJECT lpOleObj, HGLOBAL hMetaPict)
  285. {
  286. LPOLECACHE lpOleCache = NULL;
  287. FORMATETC FmtEtc;
  288. STGMEDIUM Medium;
  289. HRESULT hrErr;
  290. if (! hMetaPict)
  291. return FALSE; // invalid icon
  292. lpOleCache = (LPOLECACHE)OleStdQueryInterface(
  293. (LPUNKNOWN)lpOleObj,&IID_IOleCache);
  294. if (! lpOleCache)
  295. return FALSE; // if IOleCache* is NOT available, do nothing
  296. FmtEtc.cfFormat = CF_METAFILEPICT;
  297. FmtEtc.ptd = NULL;
  298. FmtEtc.dwAspect = DVASPECT_ICON;
  299. FmtEtc.lindex = -1;
  300. FmtEtc.tymed = TYMED_MFPICT;
  301. // stuff the icon into the cache.
  302. Medium.tymed = TYMED_MFPICT;
  303. Medium.hGlobal = hMetaPict;
  304. Medium.pUnkForRelease = NULL;
  305. OLEDBG_BEGIN2(TEXT("IOleCache::SetData called\r\n"))
  306. hrErr = lpOleCache->lpVtbl->SetData(
  307. lpOleCache,
  308. (LPFORMATETC)&FmtEtc,
  309. (LPSTGMEDIUM)&Medium,
  310. FALSE /* fRelease */
  311. );
  312. OLEDBG_END2
  313. OleStdRelease((LPUNKNOWN)lpOleCache);
  314. return hrErr;
  315. }
  316. /* OleStdDoConvert
  317. ** ---------------
  318. ** Do the container-side responsibilities for converting an object.
  319. ** This function would be used in conjunction with the OleUIConvert
  320. ** dialog. If the user selects to convert an object then the
  321. ** container must do the following:
  322. ** 1. unload the object.
  323. ** 2. write the NEW CLSID and NEW user type name
  324. ** string into the storage of the object,
  325. ** BUT write the OLD format tag.
  326. ** 3. force an update of the object to force the actual
  327. ** conversion of the data bits.
  328. **
  329. ** This function takes care of step 2.
  330. */
  331. STDAPI OleStdDoConvert(LPSTORAGE lpStg, REFCLSID rClsidNew)
  332. {
  333. HRESULT error;
  334. CLSID clsidOld;
  335. CLIPFORMAT cfOld;
  336. LPTSTR lpszOld = NULL;
  337. TCHAR szNew[OLEUI_CCHKEYMAX];
  338. if ((error = ReadClassStg(lpStg, &clsidOld)) != NOERROR) {
  339. clsidOld = CLSID_NULL;
  340. goto errRtn;
  341. }
  342. // read old fmt/old user type; sets out params to NULL on error
  343. {
  344. LPOLESTR polestr;
  345. error = ReadFmtUserTypeStg(lpStg, &cfOld, &polestr);
  346. CopyAndFreeOLESTR(polestr, &lpszOld);
  347. }
  348. OleDbgAssert(error == NOERROR || (cfOld == 0 && lpszOld == NULL));
  349. // get new user type name; if error, set to NULL string
  350. if (OleStdGetUserTypeOfClass(
  351. // (LPCLSID)
  352. rClsidNew, szNew,sizeof(szNew),NULL /* hKey */) == 0)
  353. szNew[0] = TEXT('\0');
  354. // write class stg
  355. if ((error = WriteClassStg(lpStg, rClsidNew)) != NOERROR)
  356. goto errRtn;
  357. // write old fmt/new user type;
  358. #ifdef UNICODE
  359. if ((error = WriteFmtUserTypeStg(lpStg, cfOld, szNew)) != NOERROR)
  360. goto errRewriteInfo;
  361. #else
  362. {
  363. // Chicago OLE is using UNICODE, so we need to convert the string to
  364. // UNICODE.
  365. WCHAR szNewT[OLEUI_CCHKEYMAX];
  366. mbstowcs(szNewT, szNew, sizeof(szNew));
  367. if ((error = WriteFmtUserTypeStg(lpStg, cfOld, szNewT)) != NOERROR)
  368. goto errRewriteInfo;
  369. }
  370. #endif
  371. // set convert bit
  372. if ((error = SetConvertStg(lpStg, TRUE)) != NOERROR)
  373. goto errRewriteInfo;
  374. goto okRtn;
  375. errRewriteInfo:
  376. (void)WriteClassStg(lpStg, &clsidOld);
  377. (void)WriteFmtUserTypeStgA(lpStg, cfOld, lpszOld);
  378. errRtn:
  379. okRtn:
  380. OleStdFreeString(lpszOld, NULL);
  381. return error;
  382. }
  383. /* OleStdGetTreatAsFmtUserType
  384. ** ---------------------------
  385. ** Determine if the application should perform a TreatAs (ActivateAs
  386. ** object or emulation) operation for the object that is stored in
  387. ** the storage.
  388. **
  389. ** if the CLSID written in the storage is not the same as the
  390. ** application's own CLSID (clsidApp), then a TreatAs operation
  391. ** should take place. if so determine the format the data should be
  392. ** written and the user type name of the object the app should
  393. ** emulate (ie. pretend to be). if this information is not written
  394. ** in the storage then it is looked up in the REGDB. if it can not
  395. ** be found in the REGDB, then the TreatAs operation can NOT be
  396. ** executed.
  397. **
  398. ** RETURNS: TRUE -- if TreatAs should be performed.
  399. ** valid lpclsid, lplpszType, lpcfFmt to TreatAs are returned
  400. ** (NOTE: lplpszType must be freed by caller)
  401. ** FALSE -- NO TreatAs. lpszType will be NULL.
  402. ** lpclsid = CLSID_NULL; lplpszType = lpcfFmt = NULL;
  403. */
  404. STDAPI_(BOOL) OleStdGetTreatAsFmtUserType(
  405. REFCLSID rclsidApp,
  406. LPSTORAGE lpStg,
  407. CLSID FAR* lpclsid,
  408. CLIPFORMAT FAR* lpcfFmt,
  409. LPTSTR FAR* lplpszType
  410. )
  411. {
  412. HRESULT hrErr;
  413. HKEY hKey;
  414. LONG lRet;
  415. UINT lSize;
  416. TCHAR szBuf[OLEUI_CCHKEYMAX];
  417. *lpclsid = CLSID_NULL;
  418. *lpcfFmt = 0;
  419. *lplpszType = NULL;
  420. hrErr = ReadClassStg(lpStg, lpclsid);
  421. if (hrErr == NOERROR &&
  422. ! IsEqualCLSID(lpclsid, &CLSID_NULL) &&
  423. ! IsEqualCLSID(lpclsid, rclsidApp)) {
  424. hrErr = ReadFmtUserTypeStgA(lpStg,(CLIPFORMAT FAR*)lpcfFmt, lplpszType);
  425. if (hrErr == NOERROR && lplpszType && *lpcfFmt != 0)
  426. return TRUE; // Do TreatAs. info was in lpStg.
  427. /* read info from REGDB
  428. ** *lpcfFmt = value of field: CLSID\{...}\DataFormats\DefaultFile
  429. ** *lplpszType = value of field: CLSID\{...}
  430. */
  431. //Open up the root key.
  432. lRet=RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);
  433. if (lRet != (LONG)ERROR_SUCCESS)
  434. return FALSE;
  435. *lpcfFmt = OleStdGetDefaultFileFormatOfClass(lpclsid, hKey);
  436. if (*lpcfFmt == 0)
  437. return FALSE;
  438. lSize = OleStdGetUserTypeOfClass(lpclsid,szBuf,sizeof(szBuf),hKey);
  439. if (lSize == 0)
  440. return FALSE;
  441. *lplpszType = OleStdCopyString(szBuf, NULL);
  442. } else {
  443. return FALSE; // NO TreatAs
  444. }
  445. }
  446. /* OleStdDoTreatAsClass
  447. ** --------------------
  448. ** Do the container-side responsibilities for "ActivateAs" (aka.
  449. ** TreatAs) for an object.
  450. ** This function would be used in conjunction with the OleUIConvert
  451. ** dialog. If the user selects to ActivateAs an object then the
  452. ** container must do the following:
  453. ** 1. unload ALL objects of the OLD class that app knows about
  454. ** 2. add the TreatAs tag in the registration database
  455. ** by calling CoTreatAsClass().
  456. ** 3. lazily it can reload the objects; when the objects
  457. ** are reloaded the TreatAs will take effect.
  458. **
  459. ** This function takes care of step 2.
  460. */
  461. STDAPI OleStdDoTreatAsClass(LPTSTR lpszUserType, REFCLSID rclsid, REFCLSID rclsidNew)
  462. {
  463. HRESULT hrErr;
  464. LPTSTR lpszCLSID = NULL;
  465. LONG lRet;
  466. HKEY hKey;
  467. OLEDBG_BEGIN2(TEXT("CoTreatAsClass called\r\n"))
  468. hrErr = CoTreatAsClass(rclsid, rclsidNew);
  469. OLEDBG_END2
  470. if ((hrErr != NOERROR) && lpszUserType) {
  471. lRet = RegOpenKey(HKEY_CLASSES_ROOT, (LPCTSTR) TEXT("CLSID"),
  472. (HKEY FAR *)&hKey);
  473. StringFromCLSIDA(rclsid, &lpszCLSID);
  474. RegSetValue(hKey, lpszCLSID, REG_SZ, lpszUserType,
  475. lstrlen(lpszUserType));
  476. if (lpszCLSID)
  477. OleStdFreeString(lpszCLSID, NULL);
  478. hrErr = CoTreatAsClass(rclsid, rclsidNew);
  479. RegCloseKey(hKey);
  480. }
  481. return hrErr;
  482. }
  483. /* OleStdIsOleLink
  484. ** ---------------
  485. ** Returns TRUE if the OleObject is infact an OLE link object. this
  486. ** checks if IOleLink interface is supported. if so, the object is a
  487. ** link, otherwise not.
  488. */
  489. STDAPI_(BOOL) OleStdIsOleLink(LPUNKNOWN lpUnk)
  490. {
  491. LPOLELINK lpOleLink;
  492. lpOleLink = (LPOLELINK)OleStdQueryInterface(lpUnk, &IID_IOleLink);
  493. if (lpOleLink) {
  494. OleStdRelease((LPUNKNOWN)lpOleLink);
  495. return TRUE;
  496. } else
  497. return FALSE;
  498. }
  499. /* OleStdQueryInterface
  500. ** --------------------
  501. ** Returns the desired interface pointer if exposed by the given object.
  502. ** Returns NULL if the interface is not available.
  503. ** eg.:
  504. ** lpDataObj = OleStdQueryInterface(lpOleObj, &IID_DataObject);
  505. */
  506. STDAPI_(LPUNKNOWN) OleStdQueryInterface(LPUNKNOWN lpUnk, REFIID riid)
  507. {
  508. LPUNKNOWN lpInterface;
  509. HRESULT hrErr;
  510. hrErr = lpUnk->lpVtbl->QueryInterface(
  511. lpUnk,
  512. riid,
  513. (LPVOID FAR*)&lpInterface
  514. );
  515. if (hrErr == NOERROR)
  516. return lpInterface;
  517. else
  518. return NULL;
  519. }
  520. /* OleStdGetData
  521. ** -------------
  522. ** Retrieve data from an IDataObject in a specified format on a
  523. ** global memory block. This function ALWAYS returns a private copy
  524. ** of the data to the caller. if necessary a copy is made of the
  525. ** data (ie. if lpMedium->pUnkForRelease != NULL). The caller assumes
  526. ** ownership of the data block in all cases and must free the data
  527. ** when done with it. The caller may directly free the data handle
  528. ** returned (taking care whether it is a simple HGLOBAL or a HANDLE
  529. ** to a MetafilePict) or the caller may call
  530. ** ReleaseStgMedium(lpMedium). this OLE helper function will do the
  531. ** right thing.
  532. **
  533. ** PARAMETERS:
  534. ** LPDATAOBJECT lpDataObj -- object on which GetData should be
  535. ** called.
  536. ** CLIPFORMAT cfFormat -- desired clipboard format (eg. CF_TEXT)
  537. ** DVTARGETDEVICE FAR* lpTargetDevice -- target device for which
  538. ** the data should be composed. This may
  539. ** be NULL. NULL can be used whenever the
  540. ** data format is insensitive to target
  541. ** device or when the caller does not care
  542. ** what device is used.
  543. ** LPSTGMEDIUM lpMedium -- ptr to STGMEDIUM struct. the
  544. ** resultant medium from the
  545. ** IDataObject::GetData call is
  546. ** returned.
  547. **
  548. ** RETURNS:
  549. ** HGLOBAL -- global memory handle of retrieved data block.
  550. ** NULL -- if error.
  551. */
  552. STDAPI_(HGLOBAL) OleStdGetData(
  553. LPDATAOBJECT lpDataObj,
  554. CLIPFORMAT cfFormat,
  555. DVTARGETDEVICE FAR* lpTargetDevice,
  556. DWORD dwDrawAspect,
  557. LPSTGMEDIUM lpMedium
  558. )
  559. {
  560. HRESULT hrErr;
  561. FORMATETC formatetc;
  562. HGLOBAL hGlobal = NULL;
  563. HGLOBAL hCopy;
  564. LPVOID lp;
  565. formatetc.cfFormat = cfFormat;
  566. formatetc.ptd = lpTargetDevice;
  567. formatetc.dwAspect = dwDrawAspect;
  568. formatetc.lindex = -1;
  569. switch (cfFormat) {
  570. case CF_METAFILEPICT:
  571. formatetc.tymed = TYMED_MFPICT;
  572. break;
  573. case CF_BITMAP:
  574. formatetc.tymed = TYMED_GDI;
  575. break;
  576. default:
  577. formatetc.tymed = TYMED_HGLOBAL;
  578. break;
  579. }
  580. OLEDBG_BEGIN2(TEXT("IDataObject::GetData called\r\n"))
  581. hrErr = lpDataObj->lpVtbl->GetData(
  582. lpDataObj,
  583. (LPFORMATETC)&formatetc,
  584. lpMedium
  585. );
  586. OLEDBG_END2
  587. if (hrErr != NOERROR)
  588. return NULL;
  589. if ((hGlobal = lpMedium->hGlobal) == NULL)
  590. return NULL;
  591. // Check if hGlobal really points to valid memory
  592. if ((lp = GlobalLock(hGlobal)) != NULL) {
  593. if (IsBadReadPtr(lp, 1)) {
  594. GlobalUnlock(hGlobal);
  595. return NULL; // ERROR: memory is NOT valid
  596. }
  597. GlobalUnlock(hGlobal);
  598. }
  599. if (hGlobal != NULL && lpMedium->pUnkForRelease != NULL) {
  600. /* OLE2NOTE: the callee wants to retain ownership of the data.
  601. ** this is indicated by passing a non-NULL pUnkForRelease.
  602. ** thus, we will make a copy of the data and release the
  603. ** callee's copy.
  604. */
  605. hCopy = OleDuplicateData(hGlobal, cfFormat, GHND|GMEM_SHARE);
  606. ReleaseStgMedium(lpMedium); // release callee's copy of data
  607. hGlobal = hCopy;
  608. lpMedium->hGlobal = hCopy;
  609. lpMedium->pUnkForRelease = NULL;
  610. }
  611. return hGlobal;
  612. }
  613. /* OleStdMalloc
  614. ** ------------
  615. ** allocate memory using the currently active IMalloc* allocator
  616. */
  617. STDAPI_(LPVOID) OleStdMalloc(ULONG ulSize)
  618. {
  619. LPVOID pout;
  620. LPMALLOC pmalloc;
  621. if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != NOERROR) {
  622. OleDbgAssertSz(0, szAssertMemAlloc);
  623. return NULL;
  624. }
  625. pout = (LPVOID)pmalloc->lpVtbl->Alloc(pmalloc, ulSize);
  626. if (pmalloc != NULL) {
  627. ULONG refs = pmalloc->lpVtbl->Release(pmalloc);
  628. }
  629. return pout;
  630. }
  631. /* OleStdRealloc
  632. ** -------------
  633. ** re-allocate memory using the currently active IMalloc* allocator
  634. */
  635. STDAPI_(LPVOID) OleStdRealloc(LPVOID pmem, ULONG ulSize)
  636. {
  637. LPVOID pout;
  638. LPMALLOC pmalloc;
  639. if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != NOERROR) {
  640. OleDbgAssertSz(0, szAssertMemAlloc);
  641. return NULL;
  642. }
  643. pout = (LPVOID)pmalloc->lpVtbl->Realloc(pmalloc, pmem, ulSize);
  644. if (pmalloc != NULL) {
  645. ULONG refs = pmalloc->lpVtbl->Release(pmalloc);
  646. }
  647. return pout;
  648. }
  649. /* OleStdFree
  650. ** ----------
  651. ** free memory using the currently active IMalloc* allocator
  652. */
  653. STDAPI_(void) OleStdFree(LPVOID pmem)
  654. {
  655. LPMALLOC pmalloc;
  656. if (pmem == NULL)
  657. return;
  658. if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != NOERROR) {
  659. OleDbgAssertSz(0, szAssertMemAlloc);
  660. return;
  661. }
  662. pmalloc->lpVtbl->Free(pmalloc, pmem);
  663. if (pmalloc != NULL) {
  664. ULONG refs = pmalloc->lpVtbl->Release(pmalloc);
  665. }
  666. }
  667. /* OleStdGetSize
  668. ** -------------
  669. ** Get the size of a memory block that was allocated using the
  670. ** currently active IMalloc* allocator.
  671. */
  672. STDAPI_(ULONG) OleStdGetSize(LPVOID pmem)
  673. {
  674. ULONG ulSize;
  675. LPMALLOC pmalloc;
  676. if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != NOERROR) {
  677. OleDbgAssertSz(0, szAssertMemAlloc);
  678. return (ULONG)-1;
  679. }
  680. ulSize = pmalloc->lpVtbl->GetSize(pmalloc, pmem);
  681. if (pmalloc != NULL) {
  682. ULONG refs = pmalloc->lpVtbl->Release(pmalloc);
  683. }
  684. return ulSize;
  685. }
  686. /* OleStdFreeString
  687. ** ----------------
  688. ** Free a string that was allocated with the currently active
  689. ** IMalloc* allocator.
  690. **
  691. ** if the caller has the current IMalloc* handy, then it can be
  692. ** passed as a argument, otherwise this function will retrieve the
  693. ** active allocator and use it.
  694. */
  695. STDAPI_(void) OleStdFreeString(LPTSTR lpsz, LPMALLOC lpMalloc)
  696. {
  697. BOOL fMustRelease = FALSE;
  698. if (! lpMalloc) {
  699. if (CoGetMalloc(MEMCTX_TASK, &lpMalloc) != NOERROR)
  700. return;
  701. fMustRelease = TRUE;
  702. }
  703. lpMalloc->lpVtbl->Free(lpMalloc, lpsz);
  704. if (fMustRelease)
  705. lpMalloc->lpVtbl->Release(lpMalloc);
  706. }
  707. /* OleStdCopyString
  708. ** ----------------
  709. ** Copy a string into memory allocated with the currently active
  710. ** IMalloc* allocator.
  711. **
  712. ** if the caller has the current IMalloc* handy, then it can be
  713. ** passed as a argument, otherwise this function will retrieve the
  714. ** active allocator and use it.
  715. */
  716. STDAPI_(LPTSTR) OleStdCopyString(LPTSTR lpszSrc, LPMALLOC lpMalloc)
  717. {
  718. LPTSTR lpszDest = NULL;
  719. BOOL fMustRelease = FALSE;
  720. UINT lSize = lstrlen(lpszSrc);
  721. if (! lpMalloc) {
  722. if (CoGetMalloc(MEMCTX_TASK, &lpMalloc) != NOERROR)
  723. return NULL;
  724. fMustRelease = TRUE;
  725. }
  726. lpszDest = lpMalloc->lpVtbl->Alloc(lpMalloc, (lSize+1)*sizeof(TCHAR));
  727. if (lpszDest)
  728. lstrcpy(lpszDest, lpszSrc);
  729. if (fMustRelease)
  730. lpMalloc->lpVtbl->Release(lpMalloc);
  731. return lpszDest;
  732. }
  733. /*
  734. * OleStdCreateStorageOnHGlobal()
  735. *
  736. * Purpose:
  737. * Create a memory based IStorage*.
  738. *
  739. * OLE2NOTE: if fDeleteOnRelease==TRUE, then the ILockBytes is created
  740. * such that it will delete them memory on its last release.
  741. * the IStorage on created on top of the ILockBytes in NOT
  742. * created with STGM_DELETEONRELEASE. when the IStorage receives
  743. * its last release, it will release the ILockBytes which will
  744. * in turn free the memory. it is in fact an error to specify
  745. * STGM_DELETEONRELEASE in this situation.
  746. *
  747. * Parameters:
  748. * hGlobal -- handle to MEM_SHARE allocated memory. may be NULL and
  749. * memory will be automatically allocated.
  750. * fDeleteOnRelease -- controls if the memory is freed on the last release.
  751. * grfMode -- flags passed to StgCreateDocfileOnILockBytes
  752. *
  753. * NOTE: if hGlobal is NULL, then a new IStorage is created and
  754. * STGM_CREATE flag is passed to StgCreateDocfileOnILockBytes.
  755. * if hGlobal is non-NULL, then it is assumed that the hGlobal already
  756. * has an IStorage inside it and STGM_CONVERT flag is passed
  757. * to StgCreateDocfileOnILockBytes.
  758. *
  759. * Return Value:
  760. * SCODE - S_OK if successful
  761. */
  762. STDAPI_(LPSTORAGE) OleStdCreateStorageOnHGlobal(
  763. HANDLE hGlobal,
  764. BOOL fDeleteOnRelease,
  765. DWORD grfMode
  766. )
  767. {
  768. DWORD grfCreateMode=grfMode | (hGlobal==NULL ? STGM_CREATE:STGM_CONVERT);
  769. HRESULT hrErr;
  770. LPLOCKBYTES lpLockBytes = NULL;
  771. DWORD reserved = 0;
  772. LPSTORAGE lpStg = NULL;
  773. hrErr = CreateILockBytesOnHGlobal(
  774. hGlobal,
  775. fDeleteOnRelease,
  776. (LPLOCKBYTES FAR*)&lpLockBytes
  777. );
  778. if (hrErr != NOERROR)
  779. return NULL;
  780. hrErr = StgCreateDocfileOnILockBytes(
  781. lpLockBytes,
  782. grfCreateMode,
  783. reserved,
  784. (LPSTORAGE FAR*)&lpStg
  785. );
  786. if (hrErr != NOERROR) {
  787. OleStdRelease((LPUNKNOWN)lpLockBytes);
  788. return NULL;
  789. }
  790. return lpStg;
  791. }
  792. /*
  793. * OleStdCreateTempStorage()
  794. *
  795. * Purpose:
  796. * Create a temporay IStorage* that will DeleteOnRelease.
  797. * this can be either memory based or file based.
  798. *
  799. * Parameters:
  800. * fUseMemory -- controls if memory-based or file-based stg is created
  801. * grfMode -- storage mode flags
  802. *
  803. * Return Value:
  804. * LPSTORAGE - if successful, NULL otherwise
  805. */
  806. STDAPI_(LPSTORAGE) OleStdCreateTempStorage(BOOL fUseMemory, DWORD grfMode)
  807. {
  808. LPSTORAGE lpstg;
  809. HRESULT hrErr;
  810. DWORD reserved = 0;
  811. if (fUseMemory) {
  812. lpstg = OleStdCreateStorageOnHGlobal(
  813. NULL, /* auto allocate */
  814. TRUE, /* delete on release */
  815. grfMode
  816. );
  817. } else {
  818. /* allocate a temp docfile that will delete on last release */
  819. hrErr = StgCreateDocfile(
  820. NULL,
  821. grfMode | STGM_DELETEONRELEASE | STGM_CREATE,
  822. reserved,
  823. &lpstg
  824. );
  825. if (hrErr != NOERROR)
  826. return NULL;
  827. }
  828. return lpstg;
  829. }
  830. /* OleStdGetOleObjectData
  831. ** ----------------------
  832. ** Render CF_EMBEDSOURCE/CF_EMBEDDEDOBJECT data on an TYMED_ISTORAGE
  833. ** medium by asking the object to save into the storage.
  834. ** the object must support IPersistStorage.
  835. **
  836. ** if lpMedium->tymed == TYMED_NULL, then a delete-on-release
  837. ** storage is allocated (either file-based or memory-base depending
  838. ** the value of fUseMemory). this is useful to support an
  839. ** IDataObject::GetData call where the callee must allocate the
  840. ** medium.
  841. **
  842. ** if lpMedium->tymed == TYMED_ISTORAGE, then the data is writen
  843. ** into the passed in IStorage. this is useful to support an
  844. ** IDataObject::GetDataHere call where the caller has allocated his
  845. ** own IStorage.
  846. */
  847. STDAPI OleStdGetOleObjectData(
  848. LPPERSISTSTORAGE lpPStg,
  849. LPFORMATETC lpformatetc,
  850. LPSTGMEDIUM lpMedium,
  851. BOOL fUseMemory
  852. )
  853. {
  854. LPSTORAGE lpstg = NULL;
  855. DWORD reserved = 0;
  856. SCODE sc = S_OK;
  857. HRESULT hrErr;
  858. lpMedium->pUnkForRelease = NULL;
  859. if (lpMedium->tymed == TYMED_NULL) {
  860. if (lpformatetc->tymed & TYMED_ISTORAGE) {
  861. /* allocate a temp docfile that will delete on last release */
  862. lpstg = OleStdCreateTempStorage(
  863. TRUE /*fUseMemory*/,
  864. STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE
  865. );
  866. if (!lpstg)
  867. return ResultFromScode(E_OUTOFMEMORY);
  868. lpMedium->pstg = lpstg;
  869. lpMedium->tymed = TYMED_ISTORAGE;
  870. lpMedium->pUnkForRelease = NULL;
  871. } else {
  872. return ResultFromScode(DATA_E_FORMATETC);
  873. }
  874. } else if (lpMedium->tymed == TYMED_ISTORAGE) {
  875. lpMedium->tymed = TYMED_ISTORAGE;
  876. } else {
  877. return ResultFromScode(DATA_E_FORMATETC);
  878. }
  879. // OLE2NOTE: even if OleSave returns an error you should still call
  880. // SaveCompleted.
  881. OLEDBG_BEGIN2(TEXT("OleSave called\r\n"))
  882. hrErr = OleSave(lpPStg, lpMedium->pstg, FALSE /* fSameAsLoad */);
  883. OLEDBG_END2
  884. if (hrErr != NOERROR) {
  885. OleDbgOutHResult(TEXT("WARNING: OleSave returned"), hrErr);
  886. sc = GetScode(hrErr);
  887. }
  888. OLEDBG_BEGIN2(TEXT("IPersistStorage::SaveCompleted called\r\n"))
  889. hrErr = lpPStg->lpVtbl->SaveCompleted(lpPStg, NULL);
  890. OLEDBG_END2
  891. if (hrErr != NOERROR) {
  892. OleDbgOutHResult(TEXT("WARNING: SaveCompleted returned"),hrErr);
  893. if (sc == S_OK)
  894. sc = GetScode(hrErr);
  895. }
  896. return ResultFromScode(sc);
  897. }
  898. STDAPI OleStdGetLinkSourceData(
  899. LPMONIKER lpmk,
  900. LPCLSID lpClsID,
  901. LPFORMATETC lpformatetc,
  902. LPSTGMEDIUM lpMedium
  903. )
  904. {
  905. LPSTREAM lpstm = NULL;
  906. DWORD reserved = 0;
  907. HRESULT hrErr;
  908. if (lpMedium->tymed == TYMED_NULL) {
  909. if (lpformatetc->tymed & TYMED_ISTREAM) {
  910. hrErr = CreateStreamOnHGlobal(
  911. NULL, /* auto allocate */
  912. TRUE, /* delete on release */
  913. (LPSTREAM FAR*)&lpstm
  914. );
  915. if (hrErr != NOERROR) {
  916. lpMedium->pUnkForRelease = NULL;
  917. return ResultFromScode(E_OUTOFMEMORY);
  918. }
  919. lpMedium->pstm = lpstm;
  920. lpMedium->tymed = TYMED_ISTREAM;
  921. lpMedium->pUnkForRelease = NULL;
  922. } else {
  923. lpMedium->pUnkForRelease = NULL;
  924. return ResultFromScode(DATA_E_FORMATETC);
  925. }
  926. } else {
  927. if (lpMedium->tymed == TYMED_ISTREAM) {
  928. lpMedium->tymed = TYMED_ISTREAM;
  929. lpMedium->pstm = lpMedium->pstm;
  930. lpMedium->pUnkForRelease = NULL;
  931. } else {
  932. lpMedium->pUnkForRelease = NULL;
  933. return ResultFromScode(DATA_E_FORMATETC);
  934. }
  935. }
  936. hrErr = OleSaveToStream((LPPERSISTSTREAM)lpmk, lpMedium->pstm);
  937. if (hrErr != NOERROR) return hrErr;
  938. return WriteClassStm(lpMedium->pstm, lpClsID);
  939. }
  940. /*
  941. * OleStdGetObjectDescriptorData
  942. *
  943. * Purpose:
  944. * Fills and returns a OBJECTDESCRIPTOR structure.
  945. * See OBJECTDESCRIPTOR for more information.
  946. *
  947. * Parameters:
  948. * clsid CLSID CLSID of object being transferred
  949. * dwDrawAspect DWORD Display Aspect of object
  950. * sizel SIZEL Size of object in HIMETRIC
  951. * pointl POINTL Offset from upper-left corner of object where mouse went
  952. * down for drag. Meaningful only when drag-drop is used.
  953. * dwStatus DWORD OLEMISC flags
  954. * lpszFullUserTypeName LPSTR Full User Type Name
  955. * lpszSrcOfCopy LPSTR Source of Copy
  956. *
  957. * Return Value:
  958. * HBGLOBAL Handle to OBJECTDESCRIPTOR structure.
  959. */
  960. STDAPI_(HGLOBAL) OleStdGetObjectDescriptorData(
  961. CLSID clsid,
  962. DWORD dwDrawAspect,
  963. SIZEL sizel,
  964. POINTL pointl,
  965. DWORD dwStatus,
  966. LPTSTR lpszFullUserTypeNameA,
  967. LPTSTR lpszSrcOfCopyA
  968. )
  969. {
  970. HGLOBAL hMem = NULL;
  971. IBindCtx FAR *pbc = NULL;
  972. LPOBJECTDESCRIPTOR lpOD;
  973. DWORD dwObjectDescSize, dwFullUserTypeNameLen, dwSrcOfCopyLen;
  974. LPOLESTR lpszFullUserTypeName,
  975. lpszSrcOfCopy;
  976. // convert out strings to UNICODE
  977. if( lpszSrcOfCopyA )
  978. {
  979. lpszSrcOfCopy = CreateOLESTR(lpszSrcOfCopyA);
  980. }
  981. lpszFullUserTypeName = CreateOLESTR(lpszFullUserTypeNameA);
  982. // Get the length of Full User Type Name; Add 1 for the null terminator
  983. dwFullUserTypeNameLen = lpszFullUserTypeName ? wcslen(lpszFullUserTypeName)+1 : 0;
  984. // Get the Source of Copy string and it's length; Add 1 for the null terminator
  985. if (lpszSrcOfCopy)
  986. dwSrcOfCopyLen = wcslen(lpszSrcOfCopy)+1;
  987. else {
  988. // No src moniker so use user type name as source string.
  989. lpszSrcOfCopy = lpszFullUserTypeName;
  990. dwSrcOfCopyLen = dwFullUserTypeNameLen;
  991. }
  992. // Allocate space for OBJECTDESCRIPTOR and the additional string data
  993. dwObjectDescSize = sizeof(OBJECTDESCRIPTOR);
  994. hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, dwObjectDescSize +
  995. (dwFullUserTypeNameLen + dwSrcOfCopyLen)*sizeof(OLECHAR));
  996. if (NULL == hMem)
  997. goto error;
  998. lpOD = (LPOBJECTDESCRIPTOR)GlobalLock(hMem);
  999. // Set the FullUserTypeName offset and copy the string
  1000. if (lpszFullUserTypeName)
  1001. {
  1002. lpOD->dwFullUserTypeName = dwObjectDescSize;
  1003. wcscpy((LPOLESTR)(((BYTE FAR *)lpOD)+lpOD->dwFullUserTypeName),
  1004. lpszFullUserTypeName);
  1005. }
  1006. else lpOD->dwFullUserTypeName = 0; // zero offset indicates that string is not present
  1007. // Set the SrcOfCopy offset and copy the string
  1008. if (lpszSrcOfCopy)
  1009. {
  1010. lpOD->dwSrcOfCopy = dwObjectDescSize +
  1011. dwFullUserTypeNameLen*sizeof(OLECHAR);
  1012. wcscpy((LPOLESTR)(((BYTE FAR *)lpOD)+lpOD->dwSrcOfCopy), lpszSrcOfCopy);
  1013. }
  1014. else lpOD->dwSrcOfCopy = 0; // zero offset indicates that string is not present
  1015. // Initialize the rest of the OBJECTDESCRIPTOR
  1016. lpOD->cbSize = dwObjectDescSize +
  1017. (dwFullUserTypeNameLen + dwSrcOfCopyLen)*sizeof(OLECHAR);
  1018. lpOD->clsid = clsid;
  1019. lpOD->dwDrawAspect = dwDrawAspect;
  1020. lpOD->sizel = sizel;
  1021. lpOD->pointl = pointl;
  1022. lpOD->dwStatus = dwStatus;
  1023. GlobalUnlock(hMem);
  1024. FREEOLESTR(lpszFullUserTypeName);
  1025. FREEOLESTR(lpszSrcOfCopy);
  1026. return hMem;
  1027. error:
  1028. if (hMem)
  1029. {
  1030. GlobalUnlock(hMem);
  1031. GlobalFree(hMem);
  1032. }
  1033. return NULL;
  1034. }
  1035. /*
  1036. * OleStdGetObjectDescriptorDataFromOleObject
  1037. *
  1038. * Purpose:
  1039. * Fills and returns a OBJECTDESCRIPTOR structure. Information for the structure is
  1040. * obtained from an OLEOBJECT.
  1041. * See OBJECTDESCRIPTOR for more information.
  1042. *
  1043. * Parameters:
  1044. * lpOleObj LPOLEOBJECT OleObject from which ONJECTDESCRIPTOR info
  1045. * is obtained.
  1046. * lpszSrcOfCopy LPSTR string to identify source of copy.
  1047. * May be NULL in which case IOleObject::GetMoniker is called
  1048. * to get the moniker of the object. if the object is loaded
  1049. * as part of a data transfer document, then usually
  1050. * lpOleClientSite==NULL is passed to OleLoad when loading
  1051. * the object. in this case the IOleObject:GetMoniker call
  1052. * will always fail (it tries to call back to the object's
  1053. * client site). in this situation a non-NULL lpszSrcOfCopy
  1054. * parameter should be passed.
  1055. * dwDrawAspect DWORD Display Aspect of object
  1056. * pointl POINTL Offset from upper-left corner of object where
  1057. * mouse went down for drag. Meaningful only when drag-drop
  1058. * is used.
  1059. * lpSizelHim SIZEL (optional) If the object is being scaled in its
  1060. * container, then the container should pass the extents
  1061. * that it is using to display the object.
  1062. * May be NULL if the object is NOT being scaled. in this
  1063. * case, IViewObject2::GetExtent will be called to get the
  1064. * extents from the object.
  1065. *
  1066. * Return Value:
  1067. * HBGLOBAL Handle to OBJECTDESCRIPTOR structure.
  1068. */
  1069. STDAPI_(HGLOBAL) OleStdGetObjectDescriptorDataFromOleObject(
  1070. LPOLEOBJECT lpOleObj,
  1071. LPTSTR lpszSrcOfCopy,
  1072. DWORD dwDrawAspect,
  1073. POINTL pointl,
  1074. LPSIZEL lpSizelHim
  1075. )
  1076. {
  1077. CLSID clsid;
  1078. LPTSTR lpszFullUserTypeName = NULL;
  1079. LPMONIKER lpSrcMonikerOfCopy = NULL;
  1080. HGLOBAL hObjDesc;
  1081. IBindCtx FAR *pbc = NULL;
  1082. HRESULT hrErr;
  1083. SIZEL sizelHim;
  1084. BOOL fFreeSrcOfCopy = FALSE;
  1085. LPOLELINK lpOleLink = (LPOLELINK)
  1086. OleStdQueryInterface((LPUNKNOWN)lpOleObj,&IID_IOleLink);
  1087. #ifdef OLE201
  1088. LPVIEWOBJECT2 lpViewObj2 = (LPVIEWOBJECT2)
  1089. OleStdQueryInterface((LPUNKNOWN)lpOleObj, &IID_IViewObject2);
  1090. #endif
  1091. BOOL fIsLink = (lpOleLink ? TRUE : FALSE);
  1092. TCHAR szLinkedTypeFmt[80];
  1093. LPTSTR lpszBuf = NULL;
  1094. DWORD dwStatus = 0;
  1095. // Get CLSID
  1096. OLEDBG_BEGIN2(TEXT("IOleObject::GetUserClassID called\r\n"))
  1097. hrErr = lpOleObj->lpVtbl->GetUserClassID(lpOleObj, &clsid);
  1098. OLEDBG_END2
  1099. if (hrErr != NOERROR)
  1100. clsid = CLSID_NULL;
  1101. // Get FullUserTypeName
  1102. OLEDBG_BEGIN2(TEXT("IOleObject::GetUserType called\r\n"))
  1103. {
  1104. LPOLESTR polestr;
  1105. hrErr = lpOleObj->lpVtbl->GetUserType(
  1106. lpOleObj,
  1107. USERCLASSTYPE_FULL,
  1108. &polestr
  1109. );
  1110. CopyAndFreeOLESTR(polestr, &lpszFullUserTypeName);
  1111. }
  1112. OLEDBG_END2
  1113. // REVIEW: added IDS_OLE2UILINKEDTYPE to strings.rc
  1114. /* if object is a link, then expand usertypename to be "Linked %s" */
  1115. if (fIsLink && lpszFullUserTypeName) {
  1116. if (0 == LoadString(ghInst, IDS_OLE2UIPASTELINKEDTYPE,
  1117. (LPTSTR)szLinkedTypeFmt, sizeof(szLinkedTypeFmt)/sizeof(TCHAR)))
  1118. lstrcpy(szLinkedTypeFmt, (LPTSTR) TEXT("Linked %s"));
  1119. lpszBuf = OleStdMalloc(
  1120. (lstrlen(lpszFullUserTypeName)+lstrlen(szLinkedTypeFmt)+1) *
  1121. sizeof(TCHAR));
  1122. if (lpszBuf) {
  1123. wsprintf(lpszBuf, szLinkedTypeFmt, lpszFullUserTypeName);
  1124. OleStdFreeString(lpszFullUserTypeName, NULL);
  1125. lpszFullUserTypeName = lpszBuf;
  1126. }
  1127. }
  1128. /* Get Source Of Copy
  1129. ** if the object is an embedding, then get the object's moniker
  1130. ** if the object is a link, then get the link source moniker
  1131. */
  1132. if (fIsLink) {
  1133. OLEDBG_BEGIN2(TEXT("IOleLink::GetSourceDisplayName called\r\n"))
  1134. {
  1135. LPOLESTR polestr;
  1136. hrErr = lpOleLink->lpVtbl->GetSourceDisplayName(
  1137. lpOleLink, &polestr );
  1138. CopyAndFreeOLESTR(polestr, &lpszSrcOfCopy);
  1139. }
  1140. OLEDBG_END2
  1141. fFreeSrcOfCopy = TRUE;
  1142. } else {
  1143. if (lpszSrcOfCopy == NULL) {
  1144. OLEDBG_BEGIN2(TEXT("IOleObject::GetMoniker called\r\n"))
  1145. hrErr = lpOleObj->lpVtbl->GetMoniker(
  1146. lpOleObj,
  1147. OLEGETMONIKER_TEMPFORUSER,
  1148. OLEWHICHMK_OBJFULL,
  1149. (LPMONIKER FAR*)&lpSrcMonikerOfCopy
  1150. );
  1151. OLEDBG_END2
  1152. if (hrErr == NOERROR)
  1153. {
  1154. #ifdef OLE201
  1155. CreateBindCtx(0, (LPBC FAR*)&pbc);
  1156. #endif
  1157. CallIMonikerGetDisplayNameA(
  1158. lpSrcMonikerOfCopy, pbc, NULL, &lpszSrcOfCopy);
  1159. pbc->lpVtbl->Release(pbc);
  1160. fFreeSrcOfCopy = TRUE;
  1161. }
  1162. }
  1163. }
  1164. // Get SIZEL
  1165. if (lpSizelHim) {
  1166. // Use extents passed by the caller
  1167. sizelHim = *lpSizelHim;
  1168. } else if (lpViewObj2) {
  1169. // Get the current extents from the object
  1170. OLEDBG_BEGIN2(TEXT("IViewObject2::GetExtent called\r\n"))
  1171. hrErr = lpViewObj2->lpVtbl->GetExtent(
  1172. lpViewObj2,
  1173. dwDrawAspect,
  1174. -1, /*lindex*/
  1175. NULL, /*ptd*/
  1176. (LPSIZEL)&sizelHim
  1177. );
  1178. OLEDBG_END2
  1179. if (hrErr != NOERROR)
  1180. sizelHim.cx = sizelHim.cy = 0;
  1181. } else {
  1182. sizelHim.cx = sizelHim.cy = 0;
  1183. }
  1184. // Get DWSTATUS
  1185. OLEDBG_BEGIN2(TEXT("IOleObject::GetMiscStatus called\r\n"))
  1186. hrErr = lpOleObj->lpVtbl->GetMiscStatus(
  1187. lpOleObj,
  1188. dwDrawAspect,
  1189. &dwStatus
  1190. );
  1191. OLEDBG_END2
  1192. if (hrErr != NOERROR)
  1193. dwStatus = 0;
  1194. // Get OBJECTDESCRIPTOR
  1195. hObjDesc = OleStdGetObjectDescriptorData(
  1196. clsid,
  1197. dwDrawAspect,
  1198. sizelHim,
  1199. pointl,
  1200. dwStatus,
  1201. lpszFullUserTypeName,
  1202. lpszSrcOfCopy
  1203. );
  1204. if (! hObjDesc)
  1205. goto error;
  1206. // Clean up
  1207. if (lpszFullUserTypeName)
  1208. OleStdFreeString(lpszFullUserTypeName, NULL);
  1209. if (fFreeSrcOfCopy && lpszSrcOfCopy)
  1210. OleStdFreeString(lpszSrcOfCopy, NULL);
  1211. if (lpSrcMonikerOfCopy)
  1212. OleStdRelease((LPUNKNOWN)lpSrcMonikerOfCopy);
  1213. if (lpOleLink)
  1214. OleStdRelease((LPUNKNOWN)lpOleLink);
  1215. if (lpViewObj2)
  1216. OleStdRelease((LPUNKNOWN)lpViewObj2);
  1217. return hObjDesc;
  1218. error:
  1219. if (lpszFullUserTypeName)
  1220. OleStdFreeString(lpszFullUserTypeName, NULL);
  1221. if (fFreeSrcOfCopy && lpszSrcOfCopy)
  1222. OleStdFreeString(lpszSrcOfCopy, NULL);
  1223. if (lpSrcMonikerOfCopy)
  1224. OleStdRelease((LPUNKNOWN)lpSrcMonikerOfCopy);
  1225. if (lpOleLink)
  1226. OleStdRelease((LPUNKNOWN)lpOleLink);
  1227. if (lpViewObj2)
  1228. OleStdRelease((LPUNKNOWN)lpViewObj2);
  1229. return NULL;
  1230. }
  1231. /*
  1232. * OleStdFillObjectDescriptorFromData
  1233. *
  1234. * Purpose:
  1235. * Fills and returns a OBJECTDESCRIPTOR structure. The source object will
  1236. * offer CF_OBJECTDESCRIPTOR if it is an OLE2 object, CF_OWNERLINK if it
  1237. * is an OLE1 object, or CF_FILENAME if it has been copied to the clipboard
  1238. * by FileManager.
  1239. *
  1240. * Parameters:
  1241. * lpDataObject LPDATAOBJECT Source object
  1242. * lpmedium LPSTGMEDIUM Storage medium
  1243. * lpcfFmt CLIPFORMAT FAR * Format offered by lpDataObject
  1244. * (OUT parameter)
  1245. *
  1246. * Return Value:
  1247. * HBGLOBAL Handle to OBJECTDESCRIPTOR structure.
  1248. */
  1249. STDAPI_(HGLOBAL) OleStdFillObjectDescriptorFromData(
  1250. LPDATAOBJECT lpDataObject,
  1251. LPSTGMEDIUM lpmedium,
  1252. CLIPFORMAT FAR* lpcfFmt
  1253. )
  1254. {
  1255. CLSID clsid;
  1256. SIZEL sizelHim;
  1257. POINTL pointl;
  1258. LPTSTR lpsz, szFullUserTypeName, szSrcOfCopy, szClassName, szDocName, szItemName;
  1259. int nClassName, nDocName, nItemName, nFullUserTypeName;
  1260. LPTSTR szBuf = NULL;
  1261. HGLOBAL hMem = NULL;
  1262. HKEY hKey = NULL;
  1263. LPMALLOC pIMalloc = NULL;
  1264. DWORD dw = OLEUI_CCHKEYMAX_SIZE;
  1265. HGLOBAL hObjDesc;
  1266. HRESULT hrErr;
  1267. // GetData CF_OBJECTDESCRIPTOR format from the object on the clipboard.
  1268. // Only OLE 2 objects on the clipboard will offer CF_OBJECTDESCRIPTOR
  1269. if (hMem = OleStdGetData(
  1270. lpDataObject,
  1271. (CLIPFORMAT) cfObjectDescriptor,
  1272. NULL,
  1273. DVASPECT_CONTENT,
  1274. lpmedium))
  1275. {
  1276. *lpcfFmt = cfObjectDescriptor;
  1277. return hMem; // Don't drop to clean up at the end of this function
  1278. }
  1279. // If CF_OBJECTDESCRIPTOR is not available, i.e. if this is not an OLE2 object,
  1280. // check if this is an OLE 1 object. OLE 1 objects will offer CF_OWNERLINK
  1281. else if (hMem = OleStdGetData(
  1282. lpDataObject,
  1283. (CLIPFORMAT) cfOwnerLink,
  1284. NULL,
  1285. DVASPECT_CONTENT,
  1286. lpmedium))
  1287. {
  1288. *lpcfFmt = cfOwnerLink;
  1289. // CF_OWNERLINK contains null-terminated strings for class name, document name
  1290. // and item name with two null terminating characters at the end
  1291. szClassName = (LPTSTR)GlobalLock(hMem);
  1292. nClassName = lstrlen(szClassName);
  1293. szDocName = szClassName + nClassName + 1;
  1294. nDocName = lstrlen(szDocName);
  1295. szItemName = szDocName + nDocName + 1;
  1296. nItemName = lstrlen(szItemName);
  1297. hrErr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);
  1298. if (hrErr != NOERROR)
  1299. goto error;
  1300. // Find FullUserTypeName from Registration database using class name
  1301. if (RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey) != ERROR_SUCCESS)
  1302. goto error;
  1303. // Allocate space for szFullUserTypeName & szSrcOfCopy. Maximum length of FullUserTypeName
  1304. // is OLEUI_CCHKEYMAX_SIZE. SrcOfCopy is constructed by concatenating FullUserTypeName, Document
  1305. // Name and ItemName separated by spaces.
  1306. szBuf = (LPTSTR)pIMalloc->lpVtbl->Alloc(pIMalloc,
  1307. (DWORD)2*OLEUI_CCHKEYMAX_SIZE+
  1308. (nDocName+nItemName+4)*sizeof(TCHAR));
  1309. if (NULL == szBuf)
  1310. goto error;
  1311. szFullUserTypeName = szBuf;
  1312. szSrcOfCopy = szFullUserTypeName+OLEUI_CCHKEYMAX_SIZE+1;
  1313. // Get FullUserTypeName
  1314. if (RegQueryValue(hKey, NULL, szFullUserTypeName, &dw) != ERROR_SUCCESS)
  1315. goto error;
  1316. // Build up SrcOfCopy string from FullUserTypeName, DocumentName & ItemName
  1317. lpsz = szSrcOfCopy;
  1318. lstrcpy(lpsz, szFullUserTypeName);
  1319. nFullUserTypeName = lstrlen(szFullUserTypeName);
  1320. lpsz[nFullUserTypeName]= TEXT(' ');
  1321. lpsz += nFullUserTypeName+1;
  1322. lstrcpy(lpsz, szDocName);
  1323. lpsz[nDocName] = TEXT(' ');
  1324. lpsz += nDocName+1;
  1325. lstrcpy(lpsz, szItemName);
  1326. sizelHim.cx = sizelHim.cy = 0;
  1327. pointl.x = pointl.y = 0;
  1328. CLSIDFromProgIDA(szClassName, &clsid);
  1329. hObjDesc = OleStdGetObjectDescriptorData(
  1330. clsid,
  1331. DVASPECT_CONTENT,
  1332. sizelHim,
  1333. pointl,
  1334. 0,
  1335. szFullUserTypeName,
  1336. szSrcOfCopy
  1337. );
  1338. if (!hObjDesc)
  1339. goto error;
  1340. }
  1341. // Check if object is CF_FILENAME
  1342. else if (hMem = OleStdGetData(
  1343. lpDataObject,
  1344. (CLIPFORMAT) cfFileName,
  1345. NULL,
  1346. DVASPECT_CONTENT,
  1347. lpmedium))
  1348. {
  1349. *lpcfFmt = cfFileName;
  1350. lpsz = (LPTSTR)GlobalLock(hMem);
  1351. hrErr = GetClassFileA(lpsz, &clsid);
  1352. /* OLE2NOTE: if the file does not have an OLE class
  1353. ** associated, then use the OLE 1 Packager as the class of
  1354. ** the object to be created. this is the behavior of
  1355. ** OleCreateFromData API
  1356. */
  1357. if (hrErr != NOERROR)
  1358. CLSIDFromProgIDA("Package", &clsid);
  1359. sizelHim.cx = sizelHim.cy = 0;
  1360. pointl.x = pointl.y = 0;
  1361. hrErr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);
  1362. if (hrErr != NOERROR)
  1363. goto error;
  1364. szBuf = (LPTSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, (DWORD)OLEUI_CCHKEYMAX_SIZE);
  1365. if (NULL == szBuf)
  1366. goto error;
  1367. OleStdGetUserTypeOfClass(&clsid, szBuf, OLEUI_CCHKEYMAX_SIZE, NULL);
  1368. hObjDesc = OleStdGetObjectDescriptorData(
  1369. clsid,
  1370. DVASPECT_CONTENT,
  1371. sizelHim,
  1372. pointl,
  1373. 0,
  1374. szBuf,
  1375. lpsz
  1376. );
  1377. if (!hObjDesc)
  1378. goto error;
  1379. }
  1380. else goto error;
  1381. // Clean up
  1382. if (szBuf)
  1383. pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)szBuf);
  1384. if (pIMalloc)
  1385. pIMalloc->lpVtbl->Release(pIMalloc);
  1386. if (hMem)
  1387. {
  1388. GlobalUnlock(hMem);
  1389. GlobalFree(hMem);
  1390. }
  1391. if (hKey)
  1392. RegCloseKey(hKey);
  1393. return hObjDesc;
  1394. error:
  1395. if (szBuf)
  1396. pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)szBuf);
  1397. if (pIMalloc)
  1398. pIMalloc->lpVtbl->Release(pIMalloc);
  1399. if (hMem)
  1400. {
  1401. GlobalUnlock(hMem);
  1402. GlobalFree(hMem);
  1403. }
  1404. if (hKey)
  1405. RegCloseKey(hKey);
  1406. return NULL;
  1407. }
  1408. #if defined( OBSOLETE )
  1409. /*************************************************************************
  1410. ** The following API's have been converted into macros:
  1411. ** OleStdQueryOleObjectData
  1412. ** OleStdQueryLinkSourceData
  1413. ** OleStdQueryObjectDescriptorData
  1414. ** OleStdQueryFormatMedium
  1415. ** OleStdCopyMetafilePict
  1416. ** OleStdGetDropEffect
  1417. **
  1418. ** These macros are defined in olestd.h
  1419. *************************************************************************/
  1420. STDAPI OleStdQueryOleObjectData(LPFORMATETC lpformatetc)
  1421. {
  1422. if (lpformatetc->tymed & TYMED_ISTORAGE) {
  1423. return NOERROR;
  1424. } else {
  1425. return ResultFromScode(DATA_E_FORMATETC);
  1426. }
  1427. }
  1428. STDAPI OleStdQueryLinkSourceData(LPFORMATETC lpformatetc)
  1429. {
  1430. if (lpformatetc->tymed & TYMED_ISTREAM) {
  1431. return NOERROR;
  1432. } else {
  1433. return ResultFromScode(DATA_E_FORMATETC);
  1434. }
  1435. }
  1436. STDAPI OleStdQueryObjectDescriptorData(LPFORMATETC lpformatetc)
  1437. {
  1438. if (lpformatetc->tymed & TYMED_HGLOBAL) {
  1439. return NOERROR;
  1440. } else {
  1441. return ResultFromScode(DATA_E_FORMATETC);
  1442. }
  1443. }
  1444. STDAPI OleStdQueryFormatMedium(LPFORMATETC lpformatetc, TYMED tymed)
  1445. {
  1446. if (lpformatetc->tymed & tymed) {
  1447. return NOERROR;
  1448. } else {
  1449. return ResultFromScode(DATA_E_FORMATETC);
  1450. }
  1451. }
  1452. /*
  1453. * OleStdCopyMetafilePict()
  1454. *
  1455. * Purpose:
  1456. * Make an independent copy of a MetafilePict
  1457. * Parameters:
  1458. *
  1459. * Return Value:
  1460. * TRUE if successful, else FALSE.
  1461. */
  1462. STDAPI_(BOOL) OleStdCopyMetafilePict(HANDLE hpictin, HANDLE FAR* phpictout)
  1463. {
  1464. HANDLE hpictout;
  1465. LPMETAFILEPICT ppictin, ppictout;
  1466. if (hpictin == NULL || phpictout == NULL) {
  1467. OleDbgAssert(hpictin == NULL || phpictout == NULL);
  1468. return FALSE;
  1469. }
  1470. *phpictout = NULL;
  1471. if ((ppictin = (LPMETAFILEPICT)GlobalLock(hpictin)) == NULL) {
  1472. return FALSE;
  1473. }
  1474. hpictout = GlobalAlloc(GHND|GMEM_SHARE, sizeof(METAFILEPICT));
  1475. if (hpictout && (ppictout = (LPMETAFILEPICT)GlobalLock(hpictout))){
  1476. ppictout->hMF = CopyMetaFile(ppictin->hMF, NULL);
  1477. ppictout->xExt = ppictin->xExt;
  1478. ppictout->yExt = ppictin->yExt;
  1479. ppictout->mm = ppictin->mm;
  1480. GlobalUnlock(hpictout);
  1481. }
  1482. *phpictout = hpictout;
  1483. return TRUE;
  1484. }
  1485. /* OleStdGetDropEffect
  1486. ** -------------------
  1487. **
  1488. ** Convert a keyboard state into a DROPEFFECT.
  1489. **
  1490. ** returns the DROPEFFECT value derived from the key state.
  1491. ** the following is the standard interpretation:
  1492. ** no modifier -- Default Drop (NULL is returned)
  1493. ** CTRL -- DROPEFFECT_COPY
  1494. ** SHIFT -- DROPEFFECT_MOVE
  1495. ** CTRL-SHIFT -- DROPEFFECT_LINK
  1496. **
  1497. ** Default Drop: this depends on the type of the target application.
  1498. ** this is re-interpretable by each target application. a typical
  1499. ** interpretation is if the drag is local to the same document
  1500. ** (which is source of the drag) then a MOVE operation is
  1501. ** performed. if the drag is not local, then a COPY operation is
  1502. ** performed.
  1503. */
  1504. STDAPI_(DWORD) OleStdGetDropEffect( DWORD grfKeyState )
  1505. {
  1506. if (grfKeyState & MK_CONTROL) {
  1507. if (grfKeyState & MK_SHIFT)
  1508. return DROPEFFECT_LINK;
  1509. else
  1510. return DROPEFFECT_COPY;
  1511. } else if (grfKeyState & MK_SHIFT)
  1512. return DROPEFFECT_MOVE;
  1513. return 0; // no modifier -- do default operation
  1514. }
  1515. #endif // OBSOLETE
  1516. /*
  1517. * OleStdGetMetafilePictFromOleObject()
  1518. *
  1519. * Purpose:
  1520. * Generate a MetafilePict by drawing the OLE object.
  1521. * Parameters:
  1522. * lpOleObj LPOLEOBJECT pointer to OLE Object
  1523. * dwDrawAspect DWORD Display Aspect of object
  1524. * lpSizelHim SIZEL (optional) If the object is being scaled in its
  1525. * container, then the container should pass the extents
  1526. * that it is using to display the object.
  1527. * May be NULL if the object is NOT being scaled. in this
  1528. * case, IViewObject2::GetExtent will be called to get the
  1529. * extents from the object.
  1530. * ptd TARGETDEVICE FAR* (optional) target device to render
  1531. * metafile for. May be NULL.
  1532. *
  1533. * Return Value:
  1534. * HANDLE -- handle of allocated METAFILEPICT
  1535. */
  1536. STDAPI_(HANDLE) OleStdGetMetafilePictFromOleObject(
  1537. LPOLEOBJECT lpOleObj,
  1538. DWORD dwDrawAspect,
  1539. LPSIZEL lpSizelHim,
  1540. DVTARGETDEVICE FAR* ptd
  1541. )
  1542. {
  1543. LPVIEWOBJECT2 lpViewObj2 = NULL;
  1544. HDC hDC;
  1545. HMETAFILE hmf;
  1546. HANDLE hMetaPict;
  1547. LPMETAFILEPICT lpPict;
  1548. RECT rcHim;
  1549. RECTL rclHim;
  1550. SIZEL sizelHim;
  1551. HRESULT hrErr;
  1552. SIZE size;
  1553. POINT point;
  1554. #ifdef OLE201
  1555. lpViewObj2 = (LPVIEWOBJECT2)OleStdQueryInterface(
  1556. (LPUNKNOWN)lpOleObj, &IID_IViewObject2);
  1557. #endif
  1558. if (! lpViewObj2)
  1559. return NULL;
  1560. // Get SIZEL
  1561. if (lpSizelHim) {
  1562. // Use extents passed by the caller
  1563. sizelHim = *lpSizelHim;
  1564. } else {
  1565. // Get the current extents from the object
  1566. OLEDBG_BEGIN2(TEXT("IViewObject2::GetExtent called\r\n"))
  1567. hrErr = lpViewObj2->lpVtbl->GetExtent(
  1568. lpViewObj2,
  1569. dwDrawAspect,
  1570. -1, /*lindex*/
  1571. ptd, /*ptd*/
  1572. (LPSIZEL)&sizelHim
  1573. );
  1574. OLEDBG_END2
  1575. if (hrErr != NOERROR)
  1576. sizelHim.cx = sizelHim.cy = 0;
  1577. }
  1578. hDC = CreateMetaFile(NULL);
  1579. rclHim.left = 0;
  1580. rclHim.top = 0;
  1581. rclHim.right = sizelHim.cx;
  1582. rclHim.bottom = sizelHim.cy;
  1583. rcHim.left = (int)rclHim.left;
  1584. rcHim.top = (int)rclHim.top;
  1585. rcHim.right = (int)rclHim.right;
  1586. rcHim.bottom = (int)rclHim.bottom;
  1587. SetWindowOrgEx(hDC, rcHim.left, rcHim.top, &point);
  1588. SetWindowExtEx(hDC, rcHim.right-rcHim.left, rcHim.bottom-rcHim.top,&size);
  1589. OLEDBG_BEGIN2(TEXT("IViewObject::Draw called\r\n"))
  1590. hrErr = lpViewObj2->lpVtbl->Draw(
  1591. lpViewObj2,
  1592. dwDrawAspect,
  1593. -1,
  1594. NULL,
  1595. ptd,
  1596. NULL,
  1597. hDC,
  1598. (LPRECTL)&rclHim,
  1599. (LPRECTL)&rclHim,
  1600. NULL,
  1601. 0
  1602. );
  1603. OLEDBG_END2
  1604. OleStdRelease((LPUNKNOWN)lpViewObj2);
  1605. if (hrErr != NOERROR) {
  1606. OleDbgOutHResult(TEXT("IViewObject::Draw returned"), hrErr);
  1607. }
  1608. hmf = CloseMetaFile(hDC);
  1609. hMetaPict = GlobalAlloc(GHND|GMEM_SHARE, sizeof(METAFILEPICT));
  1610. if (hMetaPict && (lpPict = (LPMETAFILEPICT)GlobalLock(hMetaPict))){
  1611. lpPict->hMF = hmf;
  1612. lpPict->xExt = (int)sizelHim.cx ;
  1613. lpPict->yExt = (int)sizelHim.cy ;
  1614. lpPict->mm = MM_ANISOTROPIC;
  1615. GlobalUnlock(hMetaPict);
  1616. }
  1617. return hMetaPict;
  1618. }
  1619. /* Call Release on the object that is expected to go away.
  1620. ** if the refcnt of the object did no go to 0 then give a debug message.
  1621. */
  1622. STDAPI_(ULONG) OleStdVerifyRelease(LPUNKNOWN lpUnk, LPTSTR lpszMsg)
  1623. {
  1624. ULONG cRef;
  1625. cRef = lpUnk->lpVtbl->Release(lpUnk);
  1626. #if defined( _DEBUG )
  1627. if (cRef != 0) {
  1628. TCHAR szBuf[80];
  1629. if (lpszMsg)
  1630. MessageBox(NULL, lpszMsg, NULL, MB_ICONEXCLAMATION | MB_OK);
  1631. wsprintf(
  1632. (LPTSTR)szBuf,
  1633. TEXT("refcnt (%ld) != 0 after object (0x%lx) release\n"),
  1634. cRef,
  1635. lpUnk
  1636. );
  1637. if (lpszMsg)
  1638. OleDbgOut1(lpszMsg);
  1639. OleDbgOut1((LPTSTR)szBuf);
  1640. OleDbgAssertSz(cRef == 0, (LPTSTR)szBuf);
  1641. } else {
  1642. TCHAR szBuf[80];
  1643. wsprintf(
  1644. (LPTSTR)szBuf,
  1645. TEXT("refcnt = 0 after object (0x%lx) release\n"), lpUnk
  1646. );
  1647. OleDbgOut4((LPTSTR)szBuf);
  1648. }
  1649. #endif
  1650. return cRef;
  1651. }
  1652. /* Call Release on the object that is NOT necessarily expected to go away.
  1653. */
  1654. STDAPI_(ULONG) OleStdRelease(LPUNKNOWN lpUnk)
  1655. {
  1656. ULONG cRef;
  1657. cRef = lpUnk->lpVtbl->Release(lpUnk);
  1658. #if defined( _DEBUG )
  1659. {
  1660. TCHAR szBuf[80];
  1661. wsprintf(
  1662. (LPTSTR)szBuf,
  1663. TEXT("refcnt = %ld after object (0x%lx) release\n"),
  1664. cRef,
  1665. lpUnk
  1666. );
  1667. OleDbgOut4((LPTSTR)szBuf);
  1668. }
  1669. #endif
  1670. return cRef;
  1671. }
  1672. /* OleStdInitVtbl
  1673. ** --------------
  1674. **
  1675. ** Initialize an interface Vtbl to ensure that there are no NULL
  1676. ** function pointers in the Vtbl. All entries in the Vtbl are
  1677. ** set to a valid funtion pointer (OleStdNullMethod) that issues
  1678. ** debug assert message (message box) and returns E_NOTIMPL if called.
  1679. **
  1680. ** NOTE: this funtion does not initialize the Vtbl with usefull
  1681. ** function pointers, only valid function pointers to avoid the
  1682. ** horrible run-time crash when a call is made through the Vtbl with
  1683. ** a NULL function pointer. this API is only necessary when
  1684. ** initializing the Vtbl's in C. C++ guarantees that all interface
  1685. ** functions (in C++ terms -- pure virtual functions) are implemented.
  1686. */
  1687. STDAPI_(void) OleStdInitVtbl(LPVOID lpVtbl, UINT nSizeOfVtbl)
  1688. {
  1689. LPVOID FAR* lpFuncPtrArr = (LPVOID FAR*)lpVtbl;
  1690. UINT nMethods = nSizeOfVtbl/sizeof(VOID FAR*);
  1691. UINT i;
  1692. for (i = 0; i < nMethods; i++) {
  1693. lpFuncPtrArr[i] = OleStdNullMethod;
  1694. }
  1695. }
  1696. /* OleStdCheckVtbl
  1697. ** ---------------
  1698. **
  1699. ** Check if all entries in the Vtbl are properly initialized with
  1700. ** valid function pointers. If any entries are either NULL or
  1701. ** OleStdNullMethod, then this function returns FALSE. If compiled
  1702. ** for _DEBUG this function reports which function pointers are
  1703. ** invalid.
  1704. **
  1705. ** RETURNS: TRUE if all entries in Vtbl are valid
  1706. ** FALSE otherwise.
  1707. */
  1708. STDAPI_(BOOL) OleStdCheckVtbl(LPVOID lpVtbl, UINT nSizeOfVtbl, LPTSTR lpszIface)
  1709. {
  1710. LPVOID FAR* lpFuncPtrArr = (LPVOID FAR*)lpVtbl;
  1711. UINT nMethods = nSizeOfVtbl/sizeof(VOID FAR*);
  1712. UINT i;
  1713. BOOL fStatus = TRUE;
  1714. int nChar = 0;
  1715. for (i = 0; i < nMethods; i++) {
  1716. if (lpFuncPtrArr[i] == NULL || lpFuncPtrArr[i] == OleStdNullMethod) {
  1717. #if defined( _DEBUG )
  1718. TCHAR szBuf[256];
  1719. wsprintf(szBuf, TEXT("%s::method# %d NOT valid!"), lpszIface, i);
  1720. OleDbgOut1((LPTSTR)szBuf);
  1721. #endif
  1722. fStatus = FALSE;
  1723. }
  1724. }
  1725. return fStatus;
  1726. }
  1727. /* OleStdNullMethod
  1728. ** ----------------
  1729. ** Dummy method used by OleStdInitVtbl to initialize an interface
  1730. ** Vtbl to ensure that there are no NULL function pointers in the
  1731. ** Vtbl. All entries in the Vtbl are set to this function. this
  1732. ** function issues a debug assert message (message box) and returns
  1733. ** E_NOTIMPL if called. If all is done properly, this function will
  1734. ** NEVER be called!
  1735. */
  1736. STDMETHODIMP OleStdNullMethod(LPUNKNOWN lpThis)
  1737. {
  1738. MessageBox(
  1739. NULL,
  1740. TEXT("ERROR: INTERFACE METHOD NOT IMPLEMENTED!\r\n"),
  1741. NULL,
  1742. MB_SYSTEMMODAL | MB_ICONHAND | MB_OK
  1743. );
  1744. return ResultFromScode(E_NOTIMPL);
  1745. }
  1746. static BOOL GetFileTimes(LPTSTR lpszFileName, FILETIME FAR* pfiletime)
  1747. {
  1748. #ifdef WIN32
  1749. WIN32_FIND_DATA fd;
  1750. HANDLE hFind;
  1751. hFind = FindFirstFile(lpszFileName,&fd);
  1752. if (hFind == NULL || hFind == INVALID_HANDLE_VALUE) {
  1753. return FALSE;
  1754. }
  1755. FindClose(hFind);
  1756. *pfiletime = fd.ftLastWriteTime;
  1757. return TRUE;
  1758. #else // !Win32
  1759. static char sz[256];
  1760. static struct _find_t fileinfo;
  1761. LSTRCPYN((LPTSTR)sz, lpszFileName, sizeof(sz)-1);
  1762. sz[sizeof(sz)-1]= TEXT('\0');
  1763. AnsiToOem(sz, sz);
  1764. return (_dos_findfirst(sz,_A_NORMAL|_A_HIDDEN|_A_SUBDIR|_A_SYSTEM,
  1765. (struct _find_t *)&fileinfo) == 0 &&
  1766. CoDosDateTimeToFileTime(fileinfo.wr_date,fileinfo.wr_time,pfiletime));
  1767. #endif // Win32
  1768. }
  1769. /* OleStdRegisterAsRunning
  1770. ** -----------------------
  1771. ** Register a moniker in the RunningObjectTable.
  1772. ** if there is an existing registration (*lpdwRegister!=NULL), then
  1773. ** first revoke that registration.
  1774. **
  1775. ** new dwRegister key is returned via *lpdwRegister parameter.
  1776. */
  1777. STDAPI_(void) OleStdRegisterAsRunning(LPUNKNOWN lpUnk, LPMONIKER lpmkFull, DWORD FAR* lpdwRegister)
  1778. {
  1779. LPRUNNINGOBJECTTABLE lpROT;
  1780. HRESULT hrErr;
  1781. DWORD dwOldRegister = *lpdwRegister;
  1782. OLEDBG_BEGIN2(TEXT("OleStdRegisterAsRunning\r\n"))
  1783. OLEDBG_BEGIN2(TEXT("GetRunningObjectTable called\r\n"))
  1784. hrErr = GetRunningObjectTable(0,(LPRUNNINGOBJECTTABLE FAR*)&lpROT);
  1785. OLEDBG_END2
  1786. if (hrErr == NOERROR) {
  1787. /* register as running if a valid moniker is passed
  1788. **
  1789. ** OLE2NOTE: we deliberately register the new moniker BEFORE
  1790. ** revoking the old moniker just in case the object
  1791. ** currently has no external locks. if the object has no
  1792. ** locks then revoking it from the running object table will
  1793. ** cause the object's StubManager to initiate shutdown of
  1794. ** the object.
  1795. */
  1796. if (lpmkFull) {
  1797. OLEDBG_BEGIN2(TEXT("IRunningObjectTable::Register called\r\n"))
  1798. lpROT->lpVtbl->Register(lpROT, 0, lpUnk,lpmkFull,lpdwRegister);
  1799. OLEDBG_END2
  1800. #if defined(_DEBUG)
  1801. {
  1802. TCHAR szBuf[512];
  1803. LPTSTR lpszDisplay;
  1804. LPBC lpbc;
  1805. #ifdef OLE201
  1806. CreateBindCtx(0, (LPBC FAR*)&lpbc);
  1807. #endif
  1808. CallIMonikerGetDisplayNameA(
  1809. lpmkFull,
  1810. lpbc,
  1811. NULL,
  1812. &lpszDisplay
  1813. );
  1814. OleStdRelease((LPUNKNOWN)lpbc);
  1815. wsprintf(
  1816. szBuf,
  1817. TEXT("Moniker '%s' REGISTERED as [0x%lx] in ROT\r\n"),
  1818. lpszDisplay,
  1819. *lpdwRegister
  1820. );
  1821. OleDbgOut2(szBuf);
  1822. OleStdFreeString(lpszDisplay, NULL);
  1823. }
  1824. #endif // _DEBUG
  1825. }
  1826. // if already registered, revoke
  1827. if (dwOldRegister != 0) {
  1828. #if defined(_DEBUG)
  1829. {
  1830. TCHAR szBuf[512];
  1831. wsprintf(
  1832. szBuf,
  1833. TEXT("Moniker [0x%lx] REVOKED from ROT\r\n"),
  1834. dwOldRegister
  1835. );
  1836. OleDbgOut2(szBuf);
  1837. }
  1838. #endif // _DEBUG
  1839. OLEDBG_BEGIN2(TEXT("IRunningObjectTable::Revoke called\r\n"))
  1840. lpROT->lpVtbl->Revoke(lpROT, dwOldRegister);
  1841. OLEDBG_END2
  1842. }
  1843. OleStdRelease((LPUNKNOWN)lpROT);
  1844. } else {
  1845. OleDbgAssertSz(
  1846. lpROT != NULL,
  1847. TEXT("OleStdRegisterAsRunning: GetRunningObjectTable FAILED\r\n")
  1848. );
  1849. }
  1850. OLEDBG_END2
  1851. }
  1852. /* OleStdRevokeAsRunning
  1853. ** ---------------------
  1854. ** Revoke a moniker from the RunningObjectTable if there is an
  1855. ** existing registration (*lpdwRegister!=NULL).
  1856. **
  1857. ** *lpdwRegister parameter will be set to NULL.
  1858. */
  1859. STDAPI_(void) OleStdRevokeAsRunning(DWORD FAR* lpdwRegister)
  1860. {
  1861. LPRUNNINGOBJECTTABLE lpROT;
  1862. HRESULT hrErr;
  1863. OLEDBG_BEGIN2(TEXT("OleStdRevokeAsRunning\r\n"))
  1864. // if still registered, then revoke
  1865. if (*lpdwRegister != 0) {
  1866. OLEDBG_BEGIN2(TEXT("GetRunningObjectTable called\r\n"))
  1867. hrErr = GetRunningObjectTable(0,(LPRUNNINGOBJECTTABLE FAR*)&lpROT);
  1868. OLEDBG_END2
  1869. if (hrErr == NOERROR) {
  1870. #if defined(_DEBUG)
  1871. {
  1872. TCHAR szBuf[512];
  1873. wsprintf(
  1874. szBuf,
  1875. TEXT("Moniker [0x%lx] REVOKED from ROT\r\n"),
  1876. *lpdwRegister
  1877. );
  1878. OleDbgOut2(szBuf);
  1879. }
  1880. #endif // _DEBUG
  1881. OLEDBG_BEGIN2(TEXT("IRunningObjectTable::Revoke called\r\n"))
  1882. lpROT->lpVtbl->Revoke(lpROT, *lpdwRegister);
  1883. OLEDBG_END2
  1884. *lpdwRegister = 0;
  1885. OleStdRelease((LPUNKNOWN)lpROT);
  1886. } else {
  1887. OleDbgAssertSz(
  1888. lpROT != NULL,
  1889. TEXT("OleStdRevokeAsRunning: GetRunningObjectTable FAILED\r\n")
  1890. );
  1891. }
  1892. }
  1893. OLEDBG_END2
  1894. }
  1895. /* OleStdNoteFileChangeTime
  1896. ** ------------------------
  1897. ** Note the time a File-Based object has been saved in the
  1898. ** RunningObjectTable. These change times are used as the basis for
  1899. ** IOleObject::IsUpToDate.
  1900. ** It is important to set the time of the file-based object
  1901. ** following a save operation to exactly the time of the saved file.
  1902. ** this helps IOleObject::IsUpToDate to give the correct answer
  1903. ** after a file has been saved.
  1904. */
  1905. STDAPI_(void) OleStdNoteFileChangeTime(LPTSTR lpszFileName, DWORD dwRegister)
  1906. {
  1907. if (dwRegister != 0) {
  1908. LPRUNNINGOBJECTTABLE lprot;
  1909. FILETIME filetime;
  1910. if (GetFileTimes(lpszFileName, &filetime) &&
  1911. GetRunningObjectTable(0,&lprot) == NOERROR)
  1912. {
  1913. lprot->lpVtbl->NoteChangeTime( lprot, dwRegister, &filetime );
  1914. lprot->lpVtbl->Release(lprot);
  1915. OleDbgOut2(TEXT("IRunningObjectTable::NoteChangeTime called\r\n"));
  1916. }
  1917. }
  1918. }
  1919. /* OleStdNoteObjectChangeTime
  1920. ** --------------------------
  1921. ** Set the last change time of an object that is registered in the
  1922. ** RunningObjectTable. These change times are used as the basis for
  1923. ** IOleObject::IsUpToDate.
  1924. **
  1925. ** every time the object sends out a OnDataChange notification, it
  1926. ** should update the Time of last change in the ROT.
  1927. **
  1928. ** NOTE: this function set the change time to the current time.
  1929. */
  1930. STDAPI_(void) OleStdNoteObjectChangeTime(DWORD dwRegister)
  1931. {
  1932. if (dwRegister != 0) {
  1933. LPRUNNINGOBJECTTABLE lprot;
  1934. FILETIME filetime;
  1935. if (GetRunningObjectTable(0,&lprot) == NOERROR)
  1936. {
  1937. #ifdef OLE201
  1938. CoFileTimeNow( &filetime );
  1939. lprot->lpVtbl->NoteChangeTime( lprot, dwRegister, &filetime );
  1940. #endif
  1941. lprot->lpVtbl->Release(lprot);
  1942. OleDbgOut2(TEXT("IRunningObjectTable::NoteChangeTime called\r\n"));
  1943. }
  1944. }
  1945. }
  1946. /* OleStdCreateTempFileMoniker
  1947. ** ---------------------------
  1948. ** return the next available FileMoniker that can be used as the
  1949. ** name of an untitled document.
  1950. ** the FileMoniker is built of the form:
  1951. ** <lpszPrefixString><number>
  1952. ** eg. "Outline1", "Outline2", etc.
  1953. **
  1954. ** The RunningObjectTable (ROT) is consulted to determine if a
  1955. ** FileMoniker is in use. If the name is in use then the number is
  1956. ** incremented and the ROT is checked again.
  1957. **
  1958. ** Parameters:
  1959. ** LPSTR lpszPrefixString - prefix used to build the name
  1960. ** UINT FAR* lpuUnique - (IN-OUT) last used number.
  1961. ** this number is used to make the
  1962. ** name unique. on entry, the input
  1963. ** number is incremented. on output,
  1964. ** the number used is returned. this
  1965. ** number should be passed again
  1966. ** unchanged on the next call.
  1967. ** LPSTR lpszName - (OUT) buffer used to build string.
  1968. ** caller must be sure buffer is large
  1969. ** enough to hold the generated string.
  1970. ** LPMONIKER FAR* lplpmk - (OUT) next unused FileMoniker
  1971. **
  1972. ** Returns:
  1973. ** void
  1974. **
  1975. ** Comments:
  1976. ** This function is similar in spirit to the Windows API
  1977. ** CreateTempFileName.
  1978. */
  1979. STDAPI_(void) OleStdCreateTempFileMoniker(
  1980. LPTSTR lpszPrefixString,
  1981. UINT FAR* lpuUnique,
  1982. LPTSTR lpszName,
  1983. LPMONIKER FAR* lplpmk
  1984. )
  1985. {
  1986. LPRUNNINGOBJECTTABLE lpROT = NULL;
  1987. UINT i = (lpuUnique != NULL ? *lpuUnique : 1);
  1988. HRESULT hrErr;
  1989. wsprintf(lpszName, TEXT("%s%d"), lpszPrefixString, i++);
  1990. CreateFileMonikerA(lpszName, lplpmk);
  1991. OLEDBG_BEGIN2(TEXT("GetRunningObjectTable called\r\n"))
  1992. hrErr = GetRunningObjectTable(0,(LPRUNNINGOBJECTTABLE FAR*)&lpROT);
  1993. OLEDBG_END2
  1994. if (hrErr == NOERROR) {
  1995. while (1) {
  1996. if (! *lplpmk)
  1997. break; // failed to create FileMoniker
  1998. OLEDBG_BEGIN2(TEXT("IRunningObjectTable::IsRunning called\r\n"))
  1999. hrErr = lpROT->lpVtbl->IsRunning(lpROT,*lplpmk);
  2000. OLEDBG_END2
  2001. if (hrErr != NOERROR)
  2002. break; // the Moniker is NOT running; found unused one!
  2003. OleStdVerifyRelease(
  2004. (LPUNKNOWN)*lplpmk,
  2005. TEXT("OleStdCreateTempFileMoniker: Moniker NOT released")
  2006. );
  2007. wsprintf(lpszName, TEXT("%s%d"), lpszPrefixString, i++);
  2008. CreateFileMonikerA(lpszName, lplpmk);
  2009. }
  2010. OleStdRelease((LPUNKNOWN)lpROT);
  2011. }
  2012. if (lpuUnique != NULL)
  2013. *lpuUnique = i;
  2014. }
  2015. /* OleStdGetFirstMoniker
  2016. ** ---------------------
  2017. ** return the first piece of a moniker.
  2018. **
  2019. ** NOTE: if the given moniker is not a generic composite moniker,
  2020. ** then an AddRef'ed pointer to the given moniker is returned.
  2021. */
  2022. STDAPI_(LPMONIKER) OleStdGetFirstMoniker(LPMONIKER lpmk)
  2023. {
  2024. LPMONIKER lpmkFirst = NULL;
  2025. LPENUMMONIKER lpenumMoniker;
  2026. DWORD dwMksys;
  2027. HRESULT hrErr;
  2028. if (! lpmk)
  2029. return NULL;
  2030. if (lpmk->lpVtbl->IsSystemMoniker(lpmk, (LPDWORD)&dwMksys) == NOERROR
  2031. && dwMksys == MKSYS_GENERICCOMPOSITE) {
  2032. /* OLE2NOTE: the moniker is a GenericCompositeMoniker.
  2033. ** enumerate the moniker to pull off the first piece.
  2034. */
  2035. hrErr = lpmk->lpVtbl->Enum(
  2036. lpmk,
  2037. TRUE /* fForward */,
  2038. (LPENUMMONIKER FAR*)&lpenumMoniker
  2039. );
  2040. if (hrErr != NOERROR)
  2041. return NULL; // ERROR: give up!
  2042. hrErr = lpenumMoniker->lpVtbl->Next(
  2043. lpenumMoniker,
  2044. 1,
  2045. (LPMONIKER FAR*)&lpmkFirst,
  2046. NULL
  2047. );
  2048. lpenumMoniker->lpVtbl->Release(lpenumMoniker);
  2049. return lpmkFirst;
  2050. } else {
  2051. /* OLE2NOTE: the moniker is NOT a GenericCompositeMoniker.
  2052. ** return an AddRef'ed pointer to the input moniker.
  2053. */
  2054. lpmk->lpVtbl->AddRef(lpmk);
  2055. return lpmk;
  2056. }
  2057. }
  2058. /* OleStdGetLenFilePrefixOfMoniker
  2059. ** -------------------------------
  2060. ** if the first piece of the Moniker is a FileMoniker, then return
  2061. ** the length of the filename string.
  2062. **
  2063. ** lpmk pointer to moniker
  2064. **
  2065. ** Returns
  2066. ** 0 if moniker does NOT start with a FileMoniker
  2067. ** uLen string length of filename prefix of the display name
  2068. ** retrieved from the given (lpmk) moniker.
  2069. */
  2070. STDAPI_(ULONG) OleStdGetLenFilePrefixOfMoniker(LPMONIKER lpmk)
  2071. {
  2072. LPMONIKER lpmkFirst = NULL;
  2073. DWORD dwMksys;
  2074. LPTSTR lpsz = NULL;
  2075. LPBC lpbc = NULL;
  2076. ULONG uLen = 0;
  2077. HRESULT hrErr;
  2078. if (! lpmk)
  2079. return 0;
  2080. lpmkFirst = OleStdGetFirstMoniker(lpmk);
  2081. if (lpmkFirst) {
  2082. if ( (lpmkFirst->lpVtbl->IsSystemMoniker(
  2083. lpmkFirst, (LPDWORD)&dwMksys) == NOERROR)
  2084. && dwMksys == MKSYS_FILEMONIKER) {
  2085. #ifdef OLE201
  2086. hrErr = CreateBindCtx(0, (LPBC FAR*)&lpbc);
  2087. #endif
  2088. if (hrErr == NOERROR) {
  2089. hrErr = CallIMonikerGetDisplayNameA(lpmkFirst, lpbc, NULL,
  2090. &lpsz);
  2091. if (hrErr == NOERROR && lpsz != NULL) {
  2092. uLen = lstrlen(lpsz);
  2093. OleStdFreeString(lpsz, NULL);
  2094. }
  2095. OleStdRelease((LPUNKNOWN)lpbc);
  2096. }
  2097. }
  2098. lpmkFirst->lpVtbl->Release(lpmkFirst);
  2099. }
  2100. return uLen;
  2101. }
  2102. /* OleStdMkParseDisplayName
  2103. ** Parse a string into a Moniker by calling the OLE API
  2104. ** MkParseDisplayName. if the original link source class was an OLE1
  2105. ** class, then attempt the parsing assuming the same class applies.
  2106. **
  2107. ** if the class of the previous link source was an OLE1 class,
  2108. ** then first attempt to parse a string that it is qualified
  2109. ** with the progID associated with the OLE1 class. this more
  2110. ** closely matches the semantics of OLE1 where the class of
  2111. ** link sources is not expected to change. prefixing the
  2112. ** string with "@<ProgID -- OLE1 class name>!" will force the
  2113. ** parsing of the string to assume the file is of that
  2114. ** class.
  2115. ** NOTE: this trick of prepending the string with "@<ProgID>
  2116. ** only works for OLE1 classes.
  2117. **
  2118. ** PARAMETERS:
  2119. ** REFCLSID rClsid -- original class of link source.
  2120. ** CLSID_NULL if class is unknown
  2121. ** ... other parameters the same as MkParseDisplayName API ...
  2122. **
  2123. ** RETURNS
  2124. ** NOERROR if string parsed successfully
  2125. ** else error code returned by MkParseDisplayName
  2126. */
  2127. STDAPI OleStdMkParseDisplayName(
  2128. REFCLSID rClsid,
  2129. LPBC lpbc,
  2130. LPTSTR lpszUserName,
  2131. ULONG FAR* lpchEaten,
  2132. LPMONIKER FAR* lplpmk
  2133. )
  2134. {
  2135. HRESULT hrErr;
  2136. if (!IsEqualCLSID(rClsid,&CLSID_NULL) && CoIsOle1Class(rClsid) &&
  2137. lpszUserName[0] != '@') {
  2138. LPTSTR lpszBuf;
  2139. LPTSTR lpszProgID;
  2140. // Prepend "@<ProgID>!" to the input string
  2141. ProgIDFromCLSIDA(rClsid, &lpszProgID);
  2142. if (lpszProgID == NULL)
  2143. goto Cont1;
  2144. lpszBuf = OleStdMalloc(
  2145. ((ULONG)lstrlen(lpszUserName)+
  2146. #ifdef UNICODE
  2147. // OLE in Win32 is always UNICODE
  2148. wcslen(lpszProgID)
  2149. #else
  2150. lstrlen(lpszProgID)
  2151. #endif
  2152. +3)*sizeof(TCHAR));
  2153. if (lpszBuf == NULL) {
  2154. if (lpszProgID)
  2155. OleStdFree(lpszProgID);
  2156. goto Cont1;
  2157. }
  2158. wsprintf(lpszBuf, TEXT("@%s!%s"), lpszProgID, lpszUserName);
  2159. OLEDBG_BEGIN2(TEXT("MkParseDisplayName called\r\n"))
  2160. hrErr = MkParseDisplayNameA(lpbc, lpszBuf, lpchEaten, lplpmk);
  2161. OLEDBG_END2
  2162. if (lpszProgID)
  2163. OleStdFree(lpszProgID);
  2164. if (lpszBuf)
  2165. OleStdFree(lpszBuf);
  2166. if (hrErr == NOERROR)
  2167. return NOERROR;
  2168. }
  2169. Cont1:
  2170. OLEDBG_BEGIN2(TEXT("MkParseDisplayName called\r\n"))
  2171. hrErr = MkParseDisplayNameA(lpbc, lpszUserName, lpchEaten, lplpmk);
  2172. OLEDBG_END2
  2173. return hrErr;
  2174. }
  2175. /*
  2176. * OleStdMarkPasteEntryList
  2177. *
  2178. * Purpose:
  2179. * Mark each entry in the PasteEntryList if its format is available from
  2180. * the source IDataObject*. the dwScratchSpace field of each PasteEntry
  2181. * is set to TRUE if available, else FALSE.
  2182. *
  2183. * Parameters:
  2184. * LPOLEUIPASTEENTRY array of PasteEntry structures
  2185. * int count of elements in PasteEntry array
  2186. * LPDATAOBJECT source IDataObject* pointer
  2187. *
  2188. * Return Value:
  2189. * none
  2190. */
  2191. STDAPI_(void) OleStdMarkPasteEntryList(
  2192. LPDATAOBJECT lpSrcDataObj,
  2193. LPOLEUIPASTEENTRY lpPriorityList,
  2194. int cEntries
  2195. )
  2196. {
  2197. LPENUMFORMATETC lpEnumFmtEtc = NULL;
  2198. #define FORMATETC_MAX 20
  2199. FORMATETC rgfmtetc[FORMATETC_MAX];
  2200. int i;
  2201. HRESULT hrErr;
  2202. long j, cFetched;
  2203. // Clear all marks
  2204. for (i = 0; i < cEntries; i++) {
  2205. lpPriorityList[i].dwScratchSpace = FALSE;
  2206. if (! lpPriorityList[i].fmtetc.cfFormat) {
  2207. // caller wants this item always considered available
  2208. // (by specifying a NULL format)
  2209. lpPriorityList[i].dwScratchSpace = TRUE;
  2210. } else if (lpPriorityList[i].fmtetc.cfFormat == cfEmbeddedObject
  2211. || lpPriorityList[i].fmtetc.cfFormat == cfEmbedSource
  2212. || lpPriorityList[i].fmtetc.cfFormat == cfFileName) {
  2213. // if there is an OLE object format, then handle it
  2214. // specially by calling OleQueryCreateFromData. the caller
  2215. // need only specify one object type format.
  2216. OLEDBG_BEGIN2(TEXT("OleQueryCreateFromData called\r\n"))
  2217. hrErr = OleQueryCreateFromData(lpSrcDataObj);
  2218. OLEDBG_END2
  2219. if(NOERROR == hrErr) {
  2220. lpPriorityList[i].dwScratchSpace = TRUE;
  2221. }
  2222. } else if (lpPriorityList[i].fmtetc.cfFormat == cfLinkSource) {
  2223. // if there is OLE 2.0 LinkSource format, then handle it
  2224. // specially by calling OleQueryLinkFromData.
  2225. OLEDBG_BEGIN2(TEXT("OleQueryLinkFromData called\r\n"))
  2226. hrErr = OleQueryLinkFromData(lpSrcDataObj);
  2227. OLEDBG_END2
  2228. if(NOERROR == hrErr) {
  2229. lpPriorityList[i].dwScratchSpace = TRUE;
  2230. }
  2231. }
  2232. }
  2233. OLEDBG_BEGIN2(TEXT("IDataObject::EnumFormatEtc called\r\n"))
  2234. hrErr = lpSrcDataObj->lpVtbl->EnumFormatEtc(
  2235. lpSrcDataObj,
  2236. DATADIR_GET,
  2237. (LPENUMFORMATETC FAR*)&lpEnumFmtEtc
  2238. );
  2239. OLEDBG_END2
  2240. if (hrErr != NOERROR)
  2241. return; // unable to get format enumerator
  2242. // Enumerate the formats offered by the source
  2243. // Loop over all formats offered by the source
  2244. cFetched = 0;
  2245. _fmemset(rgfmtetc,0,sizeof(rgfmtetc[FORMATETC_MAX]) );
  2246. if (lpEnumFmtEtc->lpVtbl->Next(
  2247. lpEnumFmtEtc, FORMATETC_MAX, rgfmtetc, &cFetched) == NOERROR
  2248. || (cFetched > 0 && cFetched <= FORMATETC_MAX) )
  2249. {
  2250. for (j = 0; j < cFetched; j++)
  2251. {
  2252. for (i = 0; i < cEntries; i++)
  2253. {
  2254. if (! lpPriorityList[i].dwScratchSpace &&
  2255. IsCloseFormatEtc(&rgfmtetc[j], &lpPriorityList[i].fmtetc))
  2256. {
  2257. lpPriorityList[i].dwScratchSpace = TRUE;
  2258. }
  2259. }
  2260. }
  2261. } // endif
  2262. // Clean up
  2263. if (lpEnumFmtEtc)
  2264. OleStdRelease((LPUNKNOWN)lpEnumFmtEtc);
  2265. }
  2266. /* OleStdGetPriorityClipboardFormat
  2267. ** --------------------------------
  2268. **
  2269. ** Retrieve the first clipboard format in a list for which data
  2270. ** exists in the source IDataObject*.
  2271. **
  2272. ** Returns -1 if no acceptable match is found.
  2273. ** index of first acceptable match in the priority list.
  2274. **
  2275. */
  2276. STDAPI_(int) OleStdGetPriorityClipboardFormat(
  2277. LPDATAOBJECT lpSrcDataObj,
  2278. LPOLEUIPASTEENTRY lpPriorityList,
  2279. int cEntries
  2280. )
  2281. {
  2282. int i;
  2283. int nFmtEtc = -1;
  2284. // Mark all entries that the Source provides
  2285. OleStdMarkPasteEntryList(lpSrcDataObj, lpPriorityList, cEntries);
  2286. // Loop over the target's priority list of formats
  2287. for (i = 0; i < cEntries; i++)
  2288. {
  2289. if (lpPriorityList[i].dwFlags != OLEUIPASTE_PASTEONLY &&
  2290. !(lpPriorityList[i].dwFlags & OLEUIPASTE_PASTE))
  2291. continue;
  2292. // get first marked entry
  2293. if (lpPriorityList[i].dwScratchSpace) {
  2294. nFmtEtc = i;
  2295. break; // Found priority format; DONE
  2296. }
  2297. }
  2298. return nFmtEtc;
  2299. }
  2300. /* OleStdIsDuplicateFormat
  2301. ** -----------------------
  2302. ** Returns TRUE if the lpFmtEtc->cfFormat is found in the array of
  2303. ** FormatEtc structures.
  2304. */
  2305. STDAPI_(BOOL) OleStdIsDuplicateFormat(
  2306. LPFORMATETC lpFmtEtc,
  2307. LPFORMATETC arrFmtEtc,
  2308. int nFmtEtc
  2309. )
  2310. {
  2311. int i;
  2312. for (i = 0; i < nFmtEtc; i++) {
  2313. if (IsEqualFORMATETC((*lpFmtEtc), arrFmtEtc[i]))
  2314. return TRUE;
  2315. }
  2316. return FALSE;
  2317. }
  2318. /* OleStdGetItemToken
  2319. * ------------------
  2320. *
  2321. * LPTSTR lpszSrc - Pointer to a source string
  2322. * LPTSTR lpszDst - Pointer to destination buffer
  2323. *
  2324. * Will copy one token from the lpszSrc buffer to the lpszItem buffer.
  2325. * It considers all alpha-numeric and white space characters as valid
  2326. * characters for a token. the first non-valid character delimates the
  2327. * token.
  2328. *
  2329. * returns the number of charaters eaten.
  2330. */
  2331. STDAPI_(ULONG) OleStdGetItemToken(LPTSTR lpszSrc, LPTSTR lpszDst, int nMaxChars)
  2332. {
  2333. ULONG chEaten = 0L;
  2334. // skip leading delimeter characters
  2335. while (*lpszSrc && --nMaxChars > 0
  2336. && ((*lpszSrc==TEXT('/')) || (*lpszSrc==TEXT('\\')) ||
  2337. (*lpszSrc==TEXT('!')) || (*lpszSrc==TEXT(':')))) {
  2338. *lpszSrc++;
  2339. chEaten++;
  2340. }
  2341. // Extract token string (up to first delimeter char or EOS)
  2342. while (*lpszSrc && --nMaxChars > 0
  2343. && !((*lpszSrc==TEXT('/')) || (*lpszSrc==TEXT('\\')) ||
  2344. (*lpszSrc==TEXT('!')) || (*lpszSrc==TEXT(':')))) {
  2345. *lpszDst++ = *lpszSrc++;
  2346. chEaten++;
  2347. }
  2348. *lpszDst = TEXT('\0');
  2349. return chEaten;
  2350. }
  2351. /*************************************************************************
  2352. ** OleStdCreateRootStorage
  2353. ** create a root level Storage given a filename that is compatible
  2354. ** to be used by a top-level OLE container. if the filename
  2355. ** specifies an existing file, then an error is returned.
  2356. ** the root storage (Docfile) that is created by this function
  2357. ** is suitable to be used to create child storages for embedings.
  2358. ** (CreateChildStorage can be used to create child storages.)
  2359. ** NOTE: the root-level storage is opened in transacted mode.
  2360. *************************************************************************/
  2361. STDAPI_(LPSTORAGE) OleStdCreateRootStorage(LPTSTR lpszStgName, DWORD grfMode)
  2362. {
  2363. HRESULT hr;
  2364. DWORD grfCreateMode = STGM_READWRITE | STGM_TRANSACTED;
  2365. DWORD reserved = 0;
  2366. LPSTORAGE lpRootStg;
  2367. TCHAR szMsg[64];
  2368. // if temp file is being created, enable delete-on-release
  2369. if (! lpszStgName)
  2370. grfCreateMode |= STGM_DELETEONRELEASE;
  2371. hr = StgCreateDocfileA(
  2372. lpszStgName,
  2373. grfMode | grfCreateMode,
  2374. reserved,
  2375. (LPSTORAGE FAR*)&lpRootStg
  2376. );
  2377. if (hr == NOERROR)
  2378. return lpRootStg; // existing file successfully opened
  2379. OleDbgOutHResult(TEXT("StgCreateDocfile returned"), hr);
  2380. if (0 == LoadString(ghInst, IDS_OLESTDNOCREATEFILE, (LPTSTR)szMsg, 64))
  2381. return NULL;
  2382. MessageBox(NULL, (LPTSTR)szMsg, NULL,MB_ICONEXCLAMATION | MB_OK);
  2383. return NULL;
  2384. }
  2385. /*************************************************************************
  2386. ** OleStdOpenRootStorage
  2387. ** open a root level Storage given a filename that is compatible
  2388. ** to be used by a top-level OLE container. if the file does not
  2389. ** exist then an error is returned.
  2390. ** the root storage (Docfile) that is opened by this function
  2391. ** is suitable to be used to create child storages for embedings.
  2392. ** (CreateChildStorage can be used to create child storages.)
  2393. ** NOTE: the root-level storage is opened in transacted mode.
  2394. *************************************************************************/
  2395. STDAPI_(LPSTORAGE) OleStdOpenRootStorage(LPTSTR lpszStgName, DWORD grfMode)
  2396. {
  2397. HRESULT hr;
  2398. DWORD reserved = 0;
  2399. LPSTORAGE lpRootStg;
  2400. TCHAR szMsg[64];
  2401. if (lpszStgName) {
  2402. hr = StgOpenStorageA(
  2403. lpszStgName,
  2404. NULL,
  2405. grfMode | STGM_TRANSACTED,
  2406. NULL,
  2407. reserved,
  2408. (LPSTORAGE FAR*)&lpRootStg
  2409. );
  2410. if (hr == NOERROR)
  2411. return lpRootStg; // existing file successfully opened
  2412. OleDbgOutHResult(TEXT("StgOpenStorage returned"), hr);
  2413. }
  2414. if (0 == LoadString(ghInst, IDS_OLESTDNOOPENFILE, szMsg, 64))
  2415. return NULL;
  2416. MessageBox(NULL, (LPTSTR)szMsg, NULL,MB_ICONEXCLAMATION | MB_OK);
  2417. return NULL;
  2418. }
  2419. /*************************************************************************
  2420. ** OpenOrCreateRootStorage
  2421. ** open a root level Storage given a filename that is compatible
  2422. ** to be used by a top-level OLE container. if the filename
  2423. ** specifies an existing file, then it is open, otherwise a new file
  2424. ** with the given name is created.
  2425. ** the root storage (Docfile) that is created by this function
  2426. ** is suitable to be used to create child storages for embedings.
  2427. ** (CreateChildStorage can be used to create child storages.)
  2428. ** NOTE: the root-level storage is opened in transacted mode.
  2429. *************************************************************************/
  2430. STDAPI_(LPSTORAGE) OleStdOpenOrCreateRootStorage(LPTSTR lpszStgName, DWORD grfMode)
  2431. {
  2432. HRESULT hrErr;
  2433. SCODE sc;
  2434. DWORD reserved = 0;
  2435. LPSTORAGE lpRootStg;
  2436. TCHAR szMsg[64];
  2437. if (lpszStgName) {
  2438. hrErr = StgOpenStorageA(
  2439. lpszStgName,
  2440. NULL,
  2441. grfMode | STGM_READWRITE | STGM_TRANSACTED,
  2442. NULL,
  2443. reserved,
  2444. (LPSTORAGE FAR*)&lpRootStg
  2445. );
  2446. if (hrErr == NOERROR)
  2447. return lpRootStg; // existing file successfully opened
  2448. OleDbgOutHResult(TEXT("StgOpenStorage returned"), hrErr);
  2449. sc = GetScode(hrErr);
  2450. if (sc!=STG_E_FILENOTFOUND && sc!=STG_E_FILEALREADYEXISTS) {
  2451. return NULL;
  2452. }
  2453. }
  2454. /* if file did not already exist, try to create a new one */
  2455. hrErr = StgCreateDocfileA(
  2456. lpszStgName,
  2457. grfMode | STGM_READWRITE | STGM_TRANSACTED,
  2458. reserved,
  2459. (LPSTORAGE FAR*)&lpRootStg
  2460. );
  2461. if (hrErr == NOERROR)
  2462. return lpRootStg; // existing file successfully opened
  2463. OleDbgOutHResult(TEXT("StgCreateDocfile returned"), hrErr);
  2464. if (0 == LoadString(ghInst, IDS_OLESTDNOCREATEFILE, (LPTSTR)szMsg, 64))
  2465. return NULL;
  2466. MessageBox(NULL, (LPTSTR)szMsg, NULL, MB_ICONEXCLAMATION | MB_OK);
  2467. return NULL;
  2468. }
  2469. /*
  2470. ** OleStdCreateChildStorage
  2471. ** create a child Storage inside the given lpStg that is compatible
  2472. ** to be used by an embedded OLE object. the return value from this
  2473. ** function can be passed to OleCreateXXX functions.
  2474. ** NOTE: the child storage is opened in transacted mode.
  2475. */
  2476. STDAPI_(LPSTORAGE) OleStdCreateChildStorage(LPSTORAGE lpStg, LPTSTR lpszStgName)
  2477. {
  2478. if (lpStg != NULL) {
  2479. LPSTORAGE lpChildStg;
  2480. DWORD grfMode = (STGM_READWRITE | STGM_TRANSACTED |
  2481. STGM_SHARE_EXCLUSIVE);
  2482. DWORD reserved = 0;
  2483. HRESULT hrErr = CallIStorageCreateStorageA(
  2484. lpStg,
  2485. lpszStgName,
  2486. grfMode,
  2487. reserved,
  2488. reserved,
  2489. (LPSTORAGE FAR*)&lpChildStg
  2490. );
  2491. if (hrErr == NOERROR)
  2492. return lpChildStg;
  2493. OleDbgOutHResult(TEXT("lpStg->lpVtbl->CreateStorage returned"), hrErr);
  2494. }
  2495. return NULL;
  2496. }
  2497. /*
  2498. ** OleStdOpenChildStorage
  2499. ** open a child Storage inside the given lpStg that is compatible
  2500. ** to be used by an embedded OLE object. the return value from this
  2501. ** function can be passed to OleLoad function.
  2502. ** NOTE: the child storage is opened in transacted mode.
  2503. */
  2504. STDAPI_(LPSTORAGE) OleStdOpenChildStorage(LPSTORAGE lpStg, LPTSTR lpszStgName, DWORD grfMode)
  2505. {
  2506. LPSTORAGE lpChildStg;
  2507. LPSTORAGE lpstgPriority = NULL;
  2508. DWORD reserved = 0;
  2509. HRESULT hrErr;
  2510. if (lpStg != NULL) {
  2511. hrErr = CallIStorageOpenStorageA(
  2512. lpStg,
  2513. lpszStgName,
  2514. lpstgPriority,
  2515. grfMode | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE,
  2516. NULL,
  2517. reserved,
  2518. (LPSTORAGE FAR*)&lpChildStg
  2519. );
  2520. if (hrErr == NOERROR)
  2521. return lpChildStg;
  2522. OleDbgOutHResult(TEXT("lpStg->lpVtbl->OpenStorage returned"), hrErr);
  2523. }
  2524. return NULL;
  2525. }
  2526. /* OleStdCommitStorage
  2527. ** -------------------
  2528. ** Commit the changes to the given IStorage*. This routine can be
  2529. ** called on either a root-level storage as used by an OLE-Container
  2530. ** or by a child storage as used by an embedded object.
  2531. **
  2532. ** This routine first attempts to perform this commit in a safe
  2533. ** manner. if this fails it then attempts to do the commit in a less
  2534. ** robust manner (STGC_OVERWRITE).
  2535. */
  2536. STDAPI_(BOOL) OleStdCommitStorage(LPSTORAGE lpStg)
  2537. {
  2538. HRESULT hrErr;
  2539. // make the changes permanent
  2540. hrErr = lpStg->lpVtbl->Commit(lpStg, 0);
  2541. if (GetScode(hrErr) == STG_E_MEDIUMFULL) {
  2542. // try to commit changes in less robust manner.
  2543. OleDbgOut(TEXT("Warning: commiting with STGC_OVERWRITE specified\n"));
  2544. hrErr = lpStg->lpVtbl->Commit(lpStg, STGC_OVERWRITE);
  2545. }
  2546. if (hrErr != NOERROR)
  2547. {
  2548. TCHAR szMsg[64];
  2549. if (0 == LoadString(ghInst, IDS_OLESTDDISKFULL, (LPTSTR)szMsg, 64))
  2550. return FALSE;
  2551. MessageBox(NULL, (LPTSTR)szMsg, NULL, MB_ICONEXCLAMATION | MB_OK);
  2552. return FALSE;
  2553. }
  2554. else {
  2555. return TRUE;
  2556. }
  2557. }
  2558. /* OleStdDestroyAllElements
  2559. ** ------------------------
  2560. ** Destroy all elements within an open storage. this is subject
  2561. ** to the current transaction.
  2562. */
  2563. STDAPI OleStdDestroyAllElements(LPSTORAGE lpStg)
  2564. {
  2565. IEnumSTATSTG FAR* lpEnum;
  2566. STATSTG sstg;
  2567. HRESULT hrErr;
  2568. hrErr = lpStg->lpVtbl->EnumElements(
  2569. lpStg, 0, NULL, 0, (IEnumSTATSTG FAR* FAR*)&lpEnum);
  2570. if (hrErr != NOERROR)
  2571. return hrErr;
  2572. while (1) {
  2573. if (lpEnum->lpVtbl->Next(lpEnum, 1, &sstg, NULL) != NOERROR)
  2574. break;
  2575. lpStg->lpVtbl->DestroyElement(lpStg, sstg.pwcsName);
  2576. OleStdFree(sstg.pwcsName);
  2577. }
  2578. lpEnum->lpVtbl->Release(lpEnum);
  2579. return NOERROR;
  2580. }
  2581. // returns 1 for a close match
  2582. // (all fields match exactly except the tymed which simply overlaps)
  2583. // 0 for no match
  2584. int IsCloseFormatEtc(FORMATETC FAR* pFetcLeft, FORMATETC FAR* pFetcRight)
  2585. {
  2586. if (pFetcLeft->cfFormat != pFetcRight->cfFormat)
  2587. return 0;
  2588. else if (!OleStdCompareTargetDevice (pFetcLeft->ptd, pFetcRight->ptd))
  2589. return 0;
  2590. if (pFetcLeft->dwAspect != pFetcRight->dwAspect)
  2591. return 0;
  2592. return((pFetcLeft->tymed | pFetcRight->tymed) != 0);
  2593. }