olecli1.cpp 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277
  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10. #include "stdafx.h"
  11. #ifdef AFX_OLE_SEG
  12. #pragma code_seg(AFX_OLE_SEG)
  13. #endif
  14. #ifdef _DEBUG
  15. #undef THIS_FILE
  16. static char THIS_FILE[] = __FILE__;
  17. #endif
  18. #define new DEBUG_NEW
  19. /////////////////////////////////////////////////////////////////////////////
  20. // COleClientItem - Container view of IOleObject and related interfaces
  21. COleClientItem::COleClientItem(COleDocument* pContainerDoc)
  22. {
  23. if (pContainerDoc != NULL)
  24. ASSERT_VALID(pContainerDoc);
  25. // initialize OLE client side view of IOleObject
  26. m_lpObject = NULL;
  27. m_lpViewObject = NULL;
  28. m_dwConnection = 0;
  29. m_lpStorage = NULL;
  30. m_lpLockBytes = NULL;
  31. m_scLast = S_OK;
  32. m_pView = NULL;
  33. m_pInPlaceFrame = NULL;
  34. m_pInPlaceDoc = NULL;
  35. m_nItemState = emptyState; // initially empty until OleLoad, OleCreate
  36. m_bMoniker = FALSE;
  37. m_nDrawAspect = DVASPECT_CONTENT; // default draw aspect
  38. m_dwItemNumber = 0;
  39. m_bLinkUnavail = FALSE; // set to TRUE on failed DoVerb, or in links dialog
  40. m_nItemType = OT_UNKNOWN; // type unknown so far
  41. m_hWndServer = NULL;
  42. m_bClosing = FALSE; // COleClientItem::Close in process
  43. m_bLocked = FALSE; // need CoLockObjectExternal(..., FALSE, ...)
  44. // initialize compound file support
  45. m_lpNewStorage = NULL;
  46. m_bNeedCommit = FALSE;
  47. if (pContainerDoc != NULL)
  48. pContainerDoc->AddItem(this);
  49. ASSERT(m_pDocument == pContainerDoc);
  50. ASSERT_VALID(this);
  51. AfxOleLockApp();
  52. }
  53. COleClientItem::~COleClientItem()
  54. {
  55. ASSERT_VALID(this);
  56. // release any references we may have to other objects
  57. Release();
  58. // only remove it from the associated document if it hasn't been detached
  59. // from the document already!
  60. if (m_pDocument != NULL)
  61. m_pDocument->RemoveItem(this);
  62. // make sure all outside connections are disconnected
  63. ExternalDisconnect();
  64. AfxOleUnlockApp();
  65. }
  66. void COleClientItem::Delete(BOOL bAutoDelete)
  67. {
  68. USES_CONVERSION;
  69. ASSERT_VALID(this);
  70. Release(); // first close it
  71. COleDocument* pDoc = GetDocument();
  72. if (pDoc != NULL && pDoc->m_bCompoundFile)
  73. {
  74. // cleanup docfile storage first
  75. COleDocument* pDoc = GetDocument();
  76. ASSERT_VALID(pDoc);
  77. if (pDoc->m_lpRootStg != NULL)
  78. {
  79. // get item name
  80. TCHAR szItemName[OLE_MAXITEMNAME];
  81. GetItemName(szItemName);
  82. // attempt to remove it from the storage, ignore errors
  83. pDoc->m_lpRootStg->DestroyElement(T2COLE(szItemName));
  84. }
  85. }
  86. if (bAutoDelete)
  87. {
  88. // remove item from document
  89. if (pDoc != NULL)
  90. pDoc->RemoveItem(this);
  91. InternalRelease(); // remove the item from memory
  92. }
  93. }
  94. void COleClientItem::Release(OLECLOSE dwCloseOption)
  95. {
  96. ASSERT_VALID(this);
  97. m_scLast = S_OK;
  98. // cleanup view advise
  99. if (m_lpViewObject != NULL)
  100. {
  101. DWORD dwAspect;
  102. IAdviseSink* pAdviseSink;
  103. pAdviseSink = NULL;
  104. VERIFY(m_lpViewObject->GetAdvise(&dwAspect, NULL, &pAdviseSink) == S_OK);
  105. if( pAdviseSink != NULL )
  106. {
  107. RELEASE( pAdviseSink );
  108. }
  109. VERIFY(m_lpViewObject->SetAdvise(dwAspect, 0, NULL) == S_OK);
  110. RELEASE(m_lpViewObject);
  111. }
  112. // cleanup the OLE object itself
  113. if (m_lpObject != NULL)
  114. {
  115. // cleanup object advise
  116. if (m_dwConnection != 0)
  117. {
  118. VERIFY(m_lpObject->Unadvise(m_dwConnection) == S_OK);
  119. m_dwConnection = 0;
  120. }
  121. // close object and save (except now when called from destructor)
  122. // (NOTE: errors are _not_ reported as an exception)
  123. m_scLast = m_lpObject->Close(dwCloseOption);
  124. RELEASE(m_lpObject);
  125. }
  126. // cleanup storage related data
  127. RELEASE(m_lpStorage);
  128. RELEASE(m_lpLockBytes);
  129. // cleanup in-place editing data
  130. if (m_pInPlaceFrame != NULL)
  131. {
  132. m_pInPlaceFrame->InternalRelease();
  133. m_pInPlaceFrame = NULL;
  134. if (m_pInPlaceDoc != NULL)
  135. {
  136. m_pInPlaceDoc->InternalRelease();
  137. m_pInPlaceDoc = NULL;
  138. }
  139. }
  140. ASSERT(m_pInPlaceFrame == NULL);
  141. ASSERT(m_pInPlaceDoc == NULL);
  142. }
  143. void COleClientItem::Close(OLECLOSE dwCloseOption)
  144. {
  145. ASSERT_VALID(this);
  146. ASSERT(m_lpObject != NULL);
  147. // gaurd against re-entry
  148. if (m_bClosing)
  149. return;
  150. m_bClosing = TRUE;
  151. // attempt to close the object
  152. m_scLast = m_lpObject->Close(dwCloseOption);
  153. // remove external lock placed on item during in-place activation
  154. if (m_bLocked)
  155. {
  156. OleLockRunning(m_lpObject, FALSE, TRUE);
  157. m_bLocked = FALSE;
  158. }
  159. // handle failure cases -- COleClientItem::Close can be used to
  160. // robustly handle a server crashing (ie. something unexpected happens,
  161. // we'll call COleClientItem::Close to attempt safe shutdown)
  162. if (GetItemState() != loadedState)
  163. {
  164. // We'll call COleClientItem::Close anywhere a catastrophe
  165. // happens inside of other portions of COleClientItem. We must
  166. // completely exit from any in-place/open state.
  167. // force transition from activeUIState to activeState
  168. if (GetItemState() == activeUIState)
  169. OnDeactivateUI(FALSE);
  170. // force transition from activeState to loadedState
  171. if (GetItemState() == activeState)
  172. OnDeactivate();
  173. if (m_nItemState != loadedState)
  174. {
  175. // in case of extreme failure, force loadedState
  176. OnChange(OLE_CHANGED_STATE, (DWORD)loadedState);
  177. m_nItemState = loadedState; // force it to loaded state
  178. }
  179. }
  180. m_bClosing = FALSE; // now safe for further close calls
  181. }
  182. /////////////////////////////////////////////////////////////////////////////
  183. // COleClientItem name management
  184. DWORD COleClientItem::GetNewItemNumber()
  185. {
  186. ASSERT_VALID(this);
  187. COleDocument* pDoc = GetDocument();
  188. ASSERT_VALID(pDoc);
  189. DWORD dwNextItemNumber = pDoc->m_dwNextItemNumber;
  190. for (;;)
  191. {
  192. // make sure that m_dwNextItemNumber is not used in another item first
  193. POSITION pos = pDoc->GetStartPosition();
  194. COleClientItem* pItem;
  195. while ((pItem = pDoc->GetNextClientItem(pos)) != NULL)
  196. {
  197. if (pItem->m_dwItemNumber == dwNextItemNumber)
  198. break;
  199. }
  200. if (pItem == NULL)
  201. break; // no item using m_dwNextItemNumber
  202. // m_dwNextItemNumber is in use, bump to next one!
  203. ++dwNextItemNumber;
  204. }
  205. pDoc->m_dwNextItemNumber = dwNextItemNumber + 1;
  206. return dwNextItemNumber;
  207. }
  208. void COleClientItem::GetItemName(LPTSTR lpszItemName) const
  209. {
  210. ASSERT_VALID(this);
  211. ASSERT(lpszItemName != NULL);
  212. wsprintf(lpszItemName, _T("Embedding %lu"), m_dwItemNumber);
  213. ASSERT(lstrlen(lpszItemName) < OLE_MAXITEMNAME);
  214. }
  215. // extracts icon resource ID and path name from registry "file.exe,35" format
  216. static void AfxGetIconInfo(LPCTSTR lpszRegInfo, LPTSTR lpszImagePath,
  217. UINT& nIndex)
  218. {
  219. LPTSTR pstrTarget = lpszImagePath;
  220. LPCTSTR pstrSource = lpszRegInfo;
  221. while (*pstrSource != ',' && *pstrSource != '\0')
  222. {
  223. *pstrTarget = *pstrSource;
  224. pstrTarget = _tcsinc(pstrTarget);
  225. pstrSource = _tcsinc(pstrSource);
  226. }
  227. *pstrTarget = '\0';
  228. // extract the index
  229. if (*pstrSource != '\0')
  230. {
  231. LPCTSTR pstrIndex = _tcsinc(pstrSource);
  232. nIndex = (UINT) _ttol(pstrIndex);
  233. }
  234. else
  235. nIndex = 0;
  236. }
  237. HICON COleClientItem::GetIconFromRegistry() const
  238. {
  239. CLSID clsid;
  240. GetClassID(&clsid);
  241. if (clsid == CLSID_NULL)
  242. return NULL;
  243. return GetIconFromRegistry(clsid);
  244. }
  245. HICON COleClientItem::GetIconFromRegistry(CLSID& clsid)
  246. {
  247. // This function will extract the icon registered as the DefaultIcon
  248. // for the server referred to by clsid. We get the ProgID for the server
  249. // and then extract \\hkcr\progid\DefaultIcon. If that doesn't exist, we
  250. // get a default icon from \\hkcr\DocShortcut\DefaultIcon and if that fails
  251. // we just return 0.
  252. USES_CONVERSION;
  253. HICON hIcon = NULL;
  254. HRESULT hr;
  255. OLECHAR *szCLSID;
  256. DWORD dwType = 0;
  257. TCHAR szName[MAX_PATH+1];
  258. TCHAR szPathName[MAX_PATH+1];
  259. HKEY hkeyObj;
  260. HKEY hkeyDefIcon;
  261. HKEY hkeyCLSID;
  262. UINT nIndex;
  263. hr = ::StringFromCLSID(clsid, &szCLSID);
  264. if (!SUCCEEDED(hr))
  265. return NULL;
  266. // first, try for the real icon
  267. if (RegOpenKeyEx(HKEY_CLASSES_ROOT, _T("clsid"), 0, KEY_READ, &hkeyCLSID) == ERROR_SUCCESS)
  268. {
  269. if (RegOpenKeyEx(hkeyCLSID, OLE2T(szCLSID), 0, KEY_READ, &hkeyObj) == ERROR_SUCCESS)
  270. {
  271. if (RegOpenKeyEx(hkeyObj, _T("DefaultIcon"), 0, KEY_READ, &hkeyDefIcon) == ERROR_SUCCESS)
  272. {
  273. DWORD dwCount;
  274. dwCount = sizeof(szName);
  275. if (RegQueryValueEx(hkeyDefIcon, NULL, NULL, &dwType, (BYTE*) szName, &dwCount) == ERROR_SUCCESS)
  276. {
  277. AfxGetIconInfo(szName, szPathName, nIndex);
  278. // Load the icon
  279. hIcon = ::ExtractIcon(AfxGetApp()->m_hInstance, szPathName, nIndex);
  280. // ExtractIcon() failure case means NULL return
  281. if (int(hIcon) == 1)
  282. hIcon = NULL;
  283. }
  284. RegCloseKey(hkeyDefIcon);
  285. }
  286. RegCloseKey(hkeyObj);
  287. }
  288. RegCloseKey(hkeyCLSID);
  289. }
  290. // if we didn't get the real icon, try the default icon
  291. if (hIcon == NULL)
  292. {
  293. if (RegOpenKeyEx(HKEY_CLASSES_ROOT, _T("DocShortcut"), 0, KEY_READ,&hkeyObj) == ERROR_SUCCESS)
  294. {
  295. if (RegOpenKeyEx(hkeyObj, _T("DefaultIcon"), 0, KEY_READ, &hkeyDefIcon) == ERROR_SUCCESS)
  296. {
  297. DWORD dwCount;
  298. dwCount = sizeof(szName);
  299. if (RegQueryValueEx(hkeyDefIcon, NULL, NULL, &dwType, (BYTE*) szName, &dwCount) == ERROR_SUCCESS)
  300. {
  301. AfxGetIconInfo(szName, szPathName, nIndex);
  302. // Load the icon
  303. hIcon = ::ExtractIcon(AfxGetApp()->m_hInstance, szPathName, nIndex);
  304. // ExtractIcon() failure case means NULL return
  305. if (int(hIcon) == 1)
  306. hIcon = NULL;
  307. }
  308. RegCloseKey(hkeyDefIcon);
  309. }
  310. RegCloseKey(hkeyObj);
  311. }
  312. }
  313. ::CoTaskMemFree(szCLSID);
  314. return hIcon;
  315. }
  316. /////////////////////////////////////////////////////////////////////////////
  317. // COleClientItem creation helpers
  318. void COleClientItem::UpdateItemType()
  319. {
  320. ASSERT_VALID(this);
  321. ASSERT(m_lpObject != NULL);
  322. // check for linked object
  323. LPOLELINK lpOleLink = QUERYINTERFACE(m_lpObject, IOleLink);
  324. if (lpOleLink != NULL)
  325. {
  326. lpOleLink->Release();
  327. m_nItemType = OT_LINK;
  328. return;
  329. }
  330. // check for static object
  331. DWORD dwStatus;
  332. if (m_lpObject->GetMiscStatus(DVASPECT_CONTENT, &dwStatus) == S_OK
  333. && (dwStatus & OLEMISC_STATIC) == 0)
  334. {
  335. m_nItemType = OT_EMBEDDED;
  336. return;
  337. }
  338. // not not link, not embedding -- must be static
  339. m_nItemType = OT_STATIC;
  340. }
  341. BOOL COleClientItem::FinishCreate(SCODE sc)
  342. {
  343. USES_CONVERSION;
  344. ASSERT_VALID(this);
  345. ASSERT(m_pView == NULL);
  346. TRY
  347. {
  348. // m_lpObject is currently an IUnknown, convert to IOleObject
  349. if (m_lpObject != NULL)
  350. {
  351. LPUNKNOWN lpUnk = m_lpObject;
  352. m_lpObject = QUERYINTERFACE(lpUnk, IOleObject);
  353. lpUnk->Release();
  354. if (m_lpObject == NULL)
  355. AfxThrowOleException(E_OUTOFMEMORY);
  356. }
  357. // check return code from create function
  358. CheckGeneral(sc);
  359. UpdateItemType();
  360. // cache the IViewObject interface
  361. m_lpViewObject = QUERYINTERFACE(m_lpObject, IViewObject2);
  362. if (m_lpViewObject == NULL)
  363. CheckGeneral(E_NOINTERFACE);
  364. ASSERT(m_lpViewObject != NULL);
  365. if (GetType() != OT_STATIC)
  366. {
  367. // setup for advises; we assume that OLE cleans them up properly
  368. LPADVISESINK lpAdviseSink =
  369. (LPADVISESINK)GetInterface(&IID_IAdviseSink);
  370. ASSERT(lpAdviseSink != NULL);
  371. CheckGeneral(m_lpObject->Advise(lpAdviseSink, &m_dwConnection));
  372. ASSERT(m_dwConnection != 0);
  373. // set up view advise
  374. VERIFY(m_lpViewObject->SetAdvise(DVASPECT_CONTENT, 0, lpAdviseSink)
  375. == S_OK);
  376. // the server shows these in its user-interface
  377. // (as document title and in File Exit menu)
  378. m_lpObject->SetHostNames(T2COLE(AfxGetAppName()),
  379. T2COLE(m_pDocument->GetTitle()));
  380. }
  381. // all items are "contained" -- this makes our reference to this object
  382. // weak -- which is needed for links to embedding silent update.
  383. OleSetContainedObject(m_lpObject, TRUE);
  384. // considered loaded at this point
  385. m_nItemState = loadedState;
  386. }
  387. CATCH_ALL(e)
  388. {
  389. Release(); // release the object just in case
  390. ASSERT_VALID(this);
  391. DELETE_EXCEPTION(e);
  392. return FALSE;
  393. }
  394. END_CATCH_ALL
  395. // set state to loaded
  396. ASSERT(m_nItemState != emptyState);
  397. // otherwise no errors, return success!
  398. ASSERT_VALID(this);
  399. return TRUE;
  400. }
  401. //////////////////////////////////////////////////////////////////////////////
  402. // COleClientItem create API variants
  403. BOOL COleClientItem::CreateFromClipboard(
  404. OLERENDER render, CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  405. {
  406. ASSERT_VALID(this);
  407. ASSERT(m_lpObject == NULL); // one time only
  408. ASSERT(m_pDocument != NULL);
  409. ASSERT(lpFormatEtc == NULL ||
  410. AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  411. // get clipboard contents
  412. COleDataObject dataObject;
  413. if (!dataObject.AttachClipboard())
  414. return FALSE;
  415. // create from IDataObject
  416. BOOL bResult = CreateFromData(&dataObject, render, cfFormat, lpFormatEtc);
  417. ASSERT_VALID(this);
  418. return bResult;
  419. }
  420. BOOL COleClientItem::CreateLinkFromClipboard(
  421. OLERENDER render, CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  422. {
  423. ASSERT_VALID(this);
  424. ASSERT(m_lpObject == NULL); // one time only
  425. ASSERT(m_pDocument != NULL);
  426. ASSERT(lpFormatEtc == NULL ||
  427. AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  428. // get clipboard contents
  429. COleDataObject dataObject;
  430. if (!dataObject.AttachClipboard())
  431. return FALSE;
  432. // create from IDataObject
  433. BOOL bResult = CreateLinkFromData(&dataObject, render, cfFormat, lpFormatEtc);
  434. ASSERT_VALID(this);
  435. return bResult;
  436. }
  437. BOOL COleClientItem::CreateStaticFromClipboard(
  438. OLERENDER render, CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  439. {
  440. ASSERT_VALID(this);
  441. ASSERT(m_lpObject == NULL); // one time only
  442. ASSERT(m_pDocument != NULL);
  443. ASSERT(lpFormatEtc == NULL ||
  444. AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  445. // get clipboard contents
  446. COleDataObject dataObject;
  447. if (!dataObject.AttachClipboard())
  448. return FALSE;
  449. // create from IDataObject
  450. BOOL bResult = CreateStaticFromData(&dataObject, render, cfFormat,
  451. lpFormatEtc);
  452. ASSERT_VALID(this);
  453. return bResult;
  454. }
  455. // Creation from IDataObject (used for drag-drop)
  456. BOOL COleClientItem::CreateFromData(COleDataObject* pDataObject,
  457. OLERENDER render, CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  458. {
  459. ASSERT_VALID(this);
  460. ASSERT(m_lpObject == NULL); // one time only
  461. ASSERT(m_pDocument != NULL);
  462. ASSERT(lpFormatEtc == NULL ||
  463. AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  464. // get storage for the object via virtual function call
  465. m_dwItemNumber = GetNewItemNumber();
  466. GetItemStorage();
  467. ASSERT(m_lpStorage != NULL);
  468. // fill in FORMATETC struct
  469. FORMATETC formatEtc;
  470. lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
  471. // attempt to create the object
  472. LPOLECLIENTSITE lpClientSite = GetClientSite();
  473. LPDATAOBJECT lpDataObject = pDataObject->GetIDataObject(FALSE);
  474. SCODE sc = ::OleCreateFromData(lpDataObject, IID_IUnknown, render,
  475. lpFormatEtc, lpClientSite, m_lpStorage, (LPLP)&m_lpObject);
  476. BOOL bResult = FinishCreate(sc);
  477. ASSERT_VALID(this);
  478. return bResult;
  479. }
  480. BOOL COleClientItem::CreateLinkFromData(COleDataObject* pDataObject,
  481. OLERENDER render, CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  482. {
  483. ASSERT_VALID(this);
  484. ASSERT(m_lpObject == NULL); // one time only
  485. ASSERT(m_pDocument != NULL);
  486. ASSERT(lpFormatEtc == NULL ||
  487. AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  488. // get storage for the object via virtual function call
  489. m_dwItemNumber = GetNewItemNumber();
  490. GetItemStorage();
  491. ASSERT(m_lpStorage != NULL);
  492. // fill in FORMATETC struct
  493. FORMATETC formatEtc;
  494. lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
  495. // attempt to create the link
  496. LPOLECLIENTSITE lpClientSite = GetClientSite();
  497. LPDATAOBJECT lpDataObject = pDataObject->GetIDataObject(FALSE);
  498. SCODE sc = ::OleCreateLinkFromData(lpDataObject, IID_IUnknown,
  499. render, lpFormatEtc, lpClientSite, m_lpStorage, (LPLP)&m_lpObject);
  500. BOOL bResult = FinishCreate(sc);
  501. ASSERT_VALID(this);
  502. return bResult;
  503. }
  504. BOOL COleClientItem::CreateStaticFromData(COleDataObject* pDataObject,
  505. OLERENDER render, CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  506. {
  507. ASSERT_VALID(this);
  508. ASSERT(m_lpObject == NULL); // one time only
  509. ASSERT(m_pDocument != NULL);
  510. ASSERT(lpFormatEtc == NULL ||
  511. AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  512. // get storage for the object via virtual function call
  513. m_dwItemNumber = GetNewItemNumber();
  514. GetItemStorage();
  515. ASSERT(m_lpStorage != NULL);
  516. // fill in FORMATETC struct
  517. FORMATETC formatEtc;
  518. lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
  519. // attempt to create the link
  520. LPOLECLIENTSITE lpClientSite = GetClientSite();
  521. LPDATAOBJECT lpDataObject = pDataObject->GetIDataObject(FALSE);
  522. SCODE sc = ::OleCreateStaticFromData(lpDataObject, IID_IUnknown,
  523. render, lpFormatEtc, lpClientSite, m_lpStorage, (LPLP)&m_lpObject);
  524. BOOL bResult = FinishCreate(sc);
  525. ASSERT_VALID(this);
  526. return bResult;
  527. }
  528. // Creation from files (in OLE 1.0, the user did this through packager)
  529. BOOL COleClientItem::CreateFromFile(LPCTSTR lpszFileName, REFCLSID clsid,
  530. OLERENDER render, CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  531. {
  532. USES_CONVERSION;
  533. ASSERT_VALID(this);
  534. ASSERT(m_lpObject == NULL); // one time only
  535. ASSERT(m_pDocument != NULL);
  536. ASSERT(lpFormatEtc == NULL ||
  537. AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  538. // get storage for the object via virtual function call
  539. m_dwItemNumber = GetNewItemNumber();
  540. GetItemStorage();
  541. ASSERT(m_lpStorage != NULL);
  542. // fill in FORMATETC struct
  543. FORMATETC formatEtc;
  544. lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
  545. // attempt to create the object
  546. LPOLECLIENTSITE lpClientSite = GetClientSite();
  547. SCODE sc = ::OleCreateFromFile(clsid, T2COLE(lpszFileName),
  548. IID_IUnknown, render, lpFormatEtc, lpClientSite, m_lpStorage,
  549. (LPLP)&m_lpObject);
  550. BOOL bResult = FinishCreate(sc);
  551. ASSERT_VALID(this);
  552. return bResult;
  553. }
  554. BOOL COleClientItem::CreateLinkFromFile(LPCTSTR lpszFileName,
  555. OLERENDER render, CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  556. {
  557. USES_CONVERSION;
  558. ASSERT_VALID(this);
  559. ASSERT(m_lpObject == NULL); // one time only
  560. ASSERT(m_pDocument != NULL);
  561. ASSERT(lpFormatEtc == NULL ||
  562. AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  563. // get storage for the object via virtual function call
  564. m_dwItemNumber = GetNewItemNumber();
  565. GetItemStorage();
  566. ASSERT(m_lpStorage != NULL);
  567. // fill in FORMATETC struct
  568. FORMATETC formatEtc;
  569. lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
  570. // attempt to create the link
  571. LPOLECLIENTSITE lpClientSite = GetClientSite();
  572. SCODE sc = ::OleCreateLinkToFile(T2COLE(lpszFileName),
  573. IID_IUnknown, render, lpFormatEtc, lpClientSite, m_lpStorage,
  574. (LPLP)&m_lpObject);
  575. BOOL bResult = FinishCreate(sc);
  576. ASSERT_VALID(this);
  577. return bResult;
  578. }
  579. // create from class name (for insert item dialog)
  580. BOOL COleClientItem::CreateNewItem(REFCLSID clsid,
  581. OLERENDER render, CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  582. {
  583. ASSERT_VALID(this);
  584. ASSERT(m_lpObject == NULL); // one time only
  585. ASSERT(m_pDocument != NULL);
  586. ASSERT(lpFormatEtc == NULL ||
  587. AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  588. // get storage for the object via virtual function call
  589. m_dwItemNumber = GetNewItemNumber();
  590. GetItemStorage();
  591. ASSERT(m_lpStorage != NULL);
  592. // fill in FORMATETC struct
  593. FORMATETC formatEtc;
  594. lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
  595. // attempt to create the object
  596. LPOLECLIENTSITE lpClientSite = GetClientSite();
  597. SCODE sc = ::OleCreate(clsid, IID_IUnknown,
  598. render, lpFormatEtc, lpClientSite, m_lpStorage, (LPLP)&m_lpObject);
  599. BOOL bResult = FinishCreate(sc);
  600. ASSERT_VALID(this);
  601. return bResult;
  602. }
  603. /////////////////////////////////////////////////////////////////////////////
  604. // More advanced creation
  605. BOOL COleClientItem::CreateCloneFrom(const COleClientItem* pSrcItem)
  606. {
  607. ASSERT_VALID(this);
  608. ASSERT(m_lpObject == NULL); // one time only
  609. ASSERT_VALID(pSrcItem);
  610. ASSERT(m_pDocument != NULL);
  611. // create storage for the item
  612. m_dwItemNumber = GetNewItemNumber();
  613. GetItemStorage();
  614. ASSERT(m_lpStorage != NULL);
  615. // save the object first
  616. LPPERSISTSTORAGE lpPersistStorage =
  617. QUERYINTERFACE(pSrcItem->m_lpObject, IPersistStorage);
  618. ASSERT(lpPersistStorage != NULL);
  619. SCODE sc = ::OleSave(lpPersistStorage, m_lpStorage, FALSE);
  620. lpPersistStorage->SaveCompleted(NULL);
  621. lpPersistStorage->Release();
  622. if (sc != S_OK)
  623. {
  624. // failed the save, do not attempt to create clone
  625. m_scLast = sc;
  626. return FALSE;
  627. }
  628. // get information on the view advise type
  629. ASSERT(pSrcItem->m_lpViewObject != NULL);
  630. DWORD dwAspect;
  631. IAdviseSink* pAdviseSink;
  632. pAdviseSink = NULL;
  633. VERIFY(pSrcItem->m_lpViewObject->GetAdvise(&dwAspect, NULL, &pAdviseSink) ==
  634. S_OK);
  635. if( pAdviseSink != NULL )
  636. {
  637. RELEASE(pAdviseSink);
  638. }
  639. // then load the new object from the new storage
  640. LPOLECLIENTSITE lpClientSite = GetClientSite();
  641. sc = ::OleLoad(m_lpStorage, IID_IUnknown,
  642. lpClientSite, (LPLP)&m_lpObject);
  643. BOOL bResult = FinishCreate(sc);
  644. ASSERT_VALID(this);
  645. return bResult;
  646. }
  647. /////////////////////////////////////////////////////////////////////////////
  648. // Storage for COleClientItem objects (memory and compound files)
  649. BOOL COleClientItem::IsModified() const
  650. {
  651. SCODE sc;
  652. ASSERT_VALID(this);
  653. ASSERT(m_lpObject != NULL);
  654. // get IPersistStorage interface, and call IsDirty
  655. LPPERSISTSTORAGE lpPersistStorage =
  656. QUERYINTERFACE(m_lpObject, IPersistStorage);
  657. if( lpPersistStorage != NULL )
  658. {
  659. sc = lpPersistStorage->IsDirty();
  660. lpPersistStorage->Release();
  661. }
  662. else
  663. {
  664. LPPERSISTSTREAMINIT lpPersistStreamInit;
  665. lpPersistStreamInit = QUERYINTERFACE( m_lpObject, IPersistStreamInit );
  666. if( lpPersistStreamInit != NULL )
  667. {
  668. sc = lpPersistStreamInit->IsDirty();
  669. lpPersistStreamInit->Release();
  670. }
  671. else
  672. {
  673. LPPERSISTSTREAM lpPersistStream;
  674. lpPersistStream = QUERYINTERFACE( m_lpObject, IPersistStream );
  675. if( lpPersistStream != NULL )
  676. {
  677. sc = lpPersistStream->IsDirty();
  678. lpPersistStream->Release();
  679. }
  680. else
  681. {
  682. sc = E_NOINTERFACE;
  683. }
  684. }
  685. }
  686. // S_OK == S_TRUE, therefore object dirty!
  687. return sc == S_OK || FAILED(sc);
  688. }
  689. void COleClientItem::GetItemStorageFlat()
  690. {
  691. ASSERT_VALID(this);
  692. ASSERT(m_lpStorage == NULL);
  693. ASSERT(m_lpLockBytes == NULL);
  694. SCODE sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &m_lpLockBytes);
  695. if (sc != S_OK)
  696. AfxThrowOleException(sc);
  697. ASSERT(m_lpLockBytes != NULL);
  698. sc = ::StgCreateDocfileOnILockBytes(m_lpLockBytes,
  699. STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &m_lpStorage);
  700. if (sc != S_OK)
  701. {
  702. VERIFY(m_lpLockBytes->Release() == 0);
  703. m_lpLockBytes = NULL;
  704. AfxThrowOleException(sc);
  705. }
  706. ASSERT(m_lpStorage != NULL);
  707. ASSERT_VALID(this);
  708. }
  709. void COleClientItem::ReadItemFlat(CArchive& ar)
  710. {
  711. ASSERT_VALID(this);
  712. ASSERT(m_lpStorage == NULL);
  713. ASSERT(m_lpLockBytes == NULL);
  714. // read number of bytes in the ILockBytes
  715. DWORD dwBytes;
  716. ar >> dwBytes;
  717. // allocate enough memory to read entire block
  718. HGLOBAL hStorage = ::GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, dwBytes);
  719. if (hStorage == NULL)
  720. AfxThrowMemoryException();
  721. LPVOID lpBuf = ::GlobalLock(hStorage);
  722. ASSERT(lpBuf != NULL);
  723. DWORD dwBytesRead = ar.Read(lpBuf, dwBytes);
  724. ::GlobalUnlock(hStorage);
  725. // throw exception in case of partial object
  726. if (dwBytesRead != dwBytes)
  727. {
  728. ::GlobalFree(hStorage);
  729. AfxThrowArchiveException(CArchiveException::endOfFile);
  730. }
  731. SCODE sc = CreateILockBytesOnHGlobal(hStorage, TRUE, &m_lpLockBytes);
  732. if (sc != S_OK)
  733. {
  734. ::GlobalFree(hStorage);
  735. AfxThrowOleException(sc);
  736. }
  737. ASSERT(m_lpLockBytes != NULL);
  738. ASSERT(::StgIsStorageILockBytes(m_lpLockBytes) == S_OK);
  739. sc = ::StgOpenStorageOnILockBytes(m_lpLockBytes, NULL,
  740. STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &m_lpStorage);
  741. if (sc != S_OK)
  742. {
  743. VERIFY(m_lpLockBytes->Release() == 0);
  744. m_lpLockBytes = NULL;
  745. // ILockBytes::Release will GlobalFree the hStorage
  746. AfxThrowOleException(sc);
  747. }
  748. // attempt to load the object from the storage
  749. LPUNKNOWN lpUnk = NULL;
  750. sc = ::OleLoad(m_lpStorage, IID_IUnknown, GetClientSite(),
  751. (LPLP)&lpUnk);
  752. CheckGeneral(sc);
  753. ASSERT(lpUnk != NULL);
  754. m_lpObject = QUERYINTERFACE(lpUnk, IOleObject);
  755. lpUnk->Release();
  756. if (m_lpObject == NULL)
  757. AfxThrowOleException(E_OUTOFMEMORY);
  758. ASSERT_VALID(this);
  759. }
  760. void COleClientItem::WriteItemFlat(CArchive& ar)
  761. {
  762. ASSERT_VALID(this);
  763. ASSERT(m_lpStorage != NULL);
  764. ASSERT(m_lpLockBytes != NULL);
  765. // save the OLE object to its storage first
  766. LPPERSISTSTORAGE lpPersistStorage =
  767. QUERYINTERFACE(m_lpObject, IPersistStorage);
  768. ASSERT(lpPersistStorage != NULL);
  769. SCODE sc;
  770. if (GetDocument()->m_bCompoundFile || lpPersistStorage->IsDirty() == S_OK)
  771. {
  772. sc = ::OleSave(lpPersistStorage, m_lpStorage,
  773. !GetDocument()->m_bCompoundFile);
  774. lpPersistStorage->SaveCompleted(NULL);
  775. }
  776. lpPersistStorage->Release();
  777. m_lpStorage->Commit(STGC_OVERWRITE);
  778. ASSERT(::StgIsStorageILockBytes(m_lpLockBytes) == S_OK);
  779. // attempt to get the handle to the global memory
  780. HGLOBAL hStorage;
  781. sc = ::GetHGlobalFromILockBytes(m_lpLockBytes, &hStorage);
  782. if (sc != S_OK)
  783. AfxThrowOleException(sc);
  784. // first write a byte count
  785. STATSTG statstg;
  786. sc = m_lpLockBytes->Stat(&statstg, STATFLAG_NONAME);
  787. if (sc != S_OK)
  788. AfxThrowOleException(sc);
  789. ASSERT(statstg.cbSize.HighPart == 0); // don't support >4GB objects
  790. DWORD dwBytes = statstg.cbSize.LowPart;
  791. ar << dwBytes;
  792. // write the contents of the block
  793. LPVOID lpBuf = GlobalLock(hStorage);
  794. ASSERT(lpBuf != NULL);
  795. ar.Write(lpBuf, (UINT)dwBytes);
  796. ::GlobalUnlock(hStorage);
  797. }
  798. void COleClientItem::GetItemStorageCompound()
  799. {
  800. USES_CONVERSION;
  801. COleDocument* pDoc = GetDocument();
  802. ASSERT_VALID(pDoc);
  803. ASSERT(pDoc->m_bCompoundFile);
  804. if (pDoc->m_lpRootStg == NULL)
  805. {
  806. ASSERT(pDoc->m_bEmbedded);
  807. pDoc->m_bEmbedded = FALSE;
  808. if (!pDoc->OnNewDocument())
  809. {
  810. TRACE0("Warning OnNewDocument failed during COleClientItem::CreateXXXX\n");
  811. AfxThrowMemoryException();
  812. }
  813. }
  814. ASSERT(pDoc->m_lpRootStg != NULL);
  815. // get item name
  816. TCHAR szItemName[OLE_MAXITEMNAME];
  817. GetItemName(szItemName);
  818. // create storage for this item
  819. LPSTORAGE lpStorage;
  820. SCODE sc = pDoc->m_lpRootStg->CreateStorage(T2COLE(szItemName),
  821. STGM_CREATE|STGM_READWRITE|STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE,
  822. 0, 0, &lpStorage);
  823. if (sc != S_OK)
  824. {
  825. TRACE1("Warning: unable to create child storage %s.\n", szItemName);
  826. // upon failure throw file exception (item will be cleaned up)
  827. AfxThrowOleException(sc);
  828. }
  829. ASSERT(lpStorage != NULL);
  830. // everything should have worked
  831. m_lpStorage = lpStorage;
  832. ASSERT(m_lpStorage != NULL);
  833. }
  834. void COleClientItem::ReadItemCompound(CArchive& ar)
  835. {
  836. USES_CONVERSION;
  837. COleDocument* pDoc = GetDocument();
  838. ASSERT_VALID(pDoc);
  839. ASSERT(pDoc->m_lpRootStg != NULL);
  840. ASSERT(pDoc->m_bCompoundFile);
  841. ASSERT(m_lpStorage == NULL);
  842. ASSERT(m_lpLockBytes == NULL);
  843. if (ar.m_bForceFlat)
  844. {
  845. ReadItemFlat(ar);
  846. RELEASE(m_lpStorage);
  847. RELEASE(m_lpLockBytes);
  848. // change the number to something definitely unique
  849. m_dwItemNumber = GetNewItemNumber();
  850. // create new storage
  851. GetItemStorageCompound();
  852. LPPERSISTSTORAGE lpPersistStorage =
  853. QUERYINTERFACE(m_lpObject, IPersistStorage);
  854. ASSERT(lpPersistStorage != NULL);
  855. SCODE sc = ::OleSave(lpPersistStorage, m_lpStorage, FALSE);
  856. if (FAILED(sc))
  857. {
  858. lpPersistStorage->Release();
  859. CheckGeneral(sc);
  860. }
  861. VERIFY(lpPersistStorage->SaveCompleted(m_lpStorage) == S_OK);
  862. lpPersistStorage->Release();
  863. }
  864. else
  865. {
  866. // get item name
  867. TCHAR szItemName[OLE_MAXITEMNAME];
  868. GetItemName(szItemName);
  869. // open storage for this item
  870. LPSTORAGE lpStorage;
  871. SCODE sc = pDoc->m_lpRootStg->OpenStorage(T2COLE(szItemName), NULL,
  872. STGM_READWRITE|STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE,
  873. 0, 0, &lpStorage);
  874. if (sc != S_OK)
  875. {
  876. TRACE1("Warning: unable to open child storage %s.\n", szItemName);
  877. // upon failure throw file exception (item will be cleaned up)
  878. AfxThrowOleException(sc);
  879. }
  880. ASSERT(lpStorage != NULL);
  881. // remember the storage
  882. m_lpStorage = lpStorage;
  883. ASSERT(m_lpStorage != NULL);
  884. // attempt to load the object from the storage
  885. LPUNKNOWN lpUnk = NULL;
  886. sc = ::OleLoad(m_lpStorage, IID_IUnknown, GetClientSite(),
  887. (LPLP)&lpUnk);
  888. CheckGeneral(sc);
  889. // get IOleObject interface for the newly loaded object
  890. ASSERT(lpUnk != NULL);
  891. m_lpObject = QUERYINTERFACE(lpUnk, IOleObject);
  892. lpUnk->Release();
  893. if (m_lpObject == NULL)
  894. AfxThrowOleException(E_OUTOFMEMORY);
  895. }
  896. }
  897. void COleClientItem::WriteItemCompound(CArchive& ar)
  898. {
  899. USES_CONVERSION;
  900. COleDocument* pDoc = GetDocument();
  901. ASSERT_VALID(pDoc);
  902. ASSERT(pDoc->m_lpRootStg != NULL);
  903. ASSERT(pDoc->m_bCompoundFile);
  904. ASSERT(m_lpNewStorage == NULL);
  905. if (ar.m_bForceFlat)
  906. {
  907. LPSTORAGE pTempStorage = m_lpStorage;
  908. LPLOCKBYTES pTempLockBytes = m_lpLockBytes;
  909. m_lpStorage = NULL;
  910. m_lpLockBytes = NULL;
  911. GetItemStorageFlat();
  912. WriteItemFlat(ar);
  913. RELEASE(m_lpStorage);
  914. RELEASE(m_lpLockBytes);
  915. m_lpStorage = pTempStorage;
  916. m_lpLockBytes = pTempLockBytes;
  917. return;
  918. }
  919. // get item name
  920. TCHAR szItemName[OLE_MAXITEMNAME];
  921. GetItemName(szItemName);
  922. // determine destination storage
  923. ASSERT(m_lpStorage != NULL);
  924. LPSTORAGE lpStorage = m_lpStorage;
  925. if (!pDoc->m_bSameAsLoad)
  926. {
  927. // need to create new storage for this item
  928. SCODE sc = pDoc->m_lpRootStg->CreateStorage(T2COLE(szItemName),
  929. STGM_CREATE|STGM_READWRITE|STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE,
  930. 0, 0, &lpStorage);
  931. if (sc != S_OK)
  932. {
  933. TRACE1("Warning: unable to create child storage %s.\n",
  934. szItemName);
  935. AfxThrowOleException(sc);
  936. }
  937. // remember the storage for CommitItem stage
  938. m_lpNewStorage = lpStorage;
  939. m_bNeedCommit = TRUE;
  940. }
  941. ASSERT(lpStorage != NULL);
  942. // save dirty object
  943. LPPERSISTSTORAGE lpPersistStorage =
  944. QUERYINTERFACE(m_lpObject, IPersistStorage);
  945. ASSERT(lpPersistStorage != NULL);
  946. SCODE sc = S_OK;
  947. if (!pDoc->m_bSameAsLoad || lpPersistStorage->IsDirty() == S_OK)
  948. {
  949. // call OleSave now and IPersistStorage::SaveCompleted later
  950. sc = ::OleSave(lpPersistStorage, lpStorage, pDoc->m_bSameAsLoad);
  951. }
  952. lpPersistStorage->Release();
  953. // if it fails, abort the save
  954. if (FAILED(sc))
  955. AfxThrowOleException(sc);
  956. // now will need to call CommitItem for this item
  957. m_bNeedCommit = TRUE;
  958. lpStorage->Commit(STGC_ONLYIFCURRENT);
  959. }
  960. void COleClientItem::GetItemStorage()
  961. {
  962. if (GetDocument()->m_bCompoundFile)
  963. GetItemStorageCompound();
  964. else
  965. GetItemStorageFlat();
  966. }
  967. void COleClientItem::ReadItem(CArchive& ar)
  968. {
  969. if (GetDocument()->m_bCompoundFile)
  970. ReadItemCompound(ar);
  971. else
  972. ReadItemFlat(ar);
  973. }
  974. void COleClientItem::WriteItem(CArchive& ar)
  975. {
  976. if (GetDocument()->m_bCompoundFile)
  977. WriteItemCompound(ar);
  978. else
  979. WriteItemFlat(ar);
  980. }
  981. void COleClientItem::CommitItem(BOOL bSuccess)
  982. {
  983. ASSERT_VALID(this);
  984. ASSERT(m_lpObject != NULL);
  985. if (!m_bNeedCommit)
  986. return;
  987. LPPERSISTSTORAGE lpPersistStorage =
  988. QUERYINTERFACE(m_lpObject, IPersistStorage);
  989. ASSERT(lpPersistStorage != NULL);
  990. // forget about new storage if save failed along the way...
  991. if (m_lpNewStorage != NULL && !bSuccess)
  992. RELEASE(m_lpNewStorage);
  993. // let the object remember the new storage
  994. VERIFY(lpPersistStorage->SaveCompleted(m_lpNewStorage) == S_OK);
  995. lpPersistStorage->Release();
  996. // determine/remember new storage
  997. if (m_lpNewStorage != NULL)
  998. {
  999. m_lpStorage->Release();
  1000. m_lpStorage = m_lpNewStorage;
  1001. m_lpNewStorage = NULL;
  1002. }
  1003. m_bNeedCommit = FALSE;
  1004. }
  1005. /////////////////////////////////////////////////////////////////////////////
  1006. // COleClientItem serialization
  1007. void COleClientItem::Serialize(CArchive& ar)
  1008. {
  1009. ASSERT_VALID(this);
  1010. CDocItem::Serialize(ar);
  1011. ASSERT(m_pDocument != NULL); // must 'SetDocument' first
  1012. if (ar.IsStoring())
  1013. {
  1014. ASSERT(m_lpObject != NULL);
  1015. // first, save the type flag (this is used for versioning)
  1016. ar << (DWORD)OT_OLE2;
  1017. ar << m_dwItemNumber; // save the item number
  1018. // write the view advise type to storage
  1019. ASSERT(m_lpViewObject != NULL);
  1020. DWORD dwAspect;
  1021. IAdviseSink* pAdviseSink;
  1022. pAdviseSink = NULL;
  1023. VERIFY(m_lpViewObject->GetAdvise(&dwAspect, NULL, &pAdviseSink) == S_OK);
  1024. if( pAdviseSink != NULL )
  1025. {
  1026. RELEASE(pAdviseSink);
  1027. }
  1028. ar << dwAspect; // save the display aspect
  1029. // write flag indicating whether to create moniker upon load
  1030. ar << (WORD)m_bMoniker;
  1031. // save current default display aspect
  1032. ar << (DWORD)m_nDrawAspect;
  1033. // save object to storage (calls OleSave)
  1034. WriteItem(ar);
  1035. }
  1036. else
  1037. {
  1038. ASSERT(m_lpObject == NULL);
  1039. // first, get the type flag (for OLE 1.0 compatible reading)
  1040. DWORD dwType;
  1041. ar >> dwType;
  1042. if (dwType != OT_OLE2)
  1043. AfxThrowArchiveException(CArchiveException::generic);
  1044. ar >> m_dwItemNumber; // get the item number
  1045. DWORD dwAspect; // read the display aspect (aspects that are cached)
  1046. ar >> dwAspect;
  1047. WORD bMoniker; // see if we should create & set the moniker
  1048. ar >> bMoniker;
  1049. DWORD nDrawAspect; // read the default display aspect
  1050. ar >> nDrawAspect;
  1051. m_nDrawAspect = (DVASPECT)nDrawAspect;
  1052. // read the OLE object from storage (calls OleLoad)
  1053. ReadItem(ar);
  1054. // finish OLE object creation process, setup advises, etc.
  1055. if (!FinishCreate(S_OK))
  1056. AfxThrowArchiveException(CArchiveException::generic);
  1057. if (bMoniker)
  1058. {
  1059. // force moniker creation by calling GetMoniker
  1060. LPMONIKER lpMoniker;
  1061. if (GetClientSite()->GetMoniker(OLEGETMONIKER_FORCEASSIGN,
  1062. OLEWHICHMK_OBJREL, &lpMoniker) == S_OK)
  1063. {
  1064. ASSERT(lpMoniker != NULL);
  1065. lpMoniker->Release();
  1066. ASSERT(m_bMoniker); // moniker should have been assigned
  1067. }
  1068. }
  1069. // fix up the document's m_dwNextItemNumber
  1070. if (m_dwItemNumber >= GetDocument()->m_dwNextItemNumber)
  1071. GetDocument()->m_dwNextItemNumber = m_dwItemNumber + 1;
  1072. }
  1073. }
  1074. /////////////////////////////////////////////////////////////////////////////
  1075. // default callback implementation
  1076. void COleClientItem::OnChange(OLE_NOTIFICATION nCode, DWORD /*dwParam*/)
  1077. {
  1078. ASSERT_VALID(this);
  1079. switch (nCode)
  1080. {
  1081. case OLE_CLOSED:
  1082. break; // no default implementation
  1083. case OLE_CHANGED:
  1084. case OLE_SAVED:
  1085. ASSERT(m_pDocument != NULL);
  1086. m_pDocument->SetModifiedFlag();
  1087. break;
  1088. case OLE_CHANGED_STATE:
  1089. case OLE_CHANGED_ASPECT:
  1090. break; // no default implementation
  1091. default:
  1092. ASSERT(FALSE);
  1093. }
  1094. ASSERT_VALID(this);
  1095. }
  1096. void COleClientItem::OnDataChange(
  1097. LPFORMATETC /*lpFormatEtc*/, LPSTGMEDIUM /*lpStgMedium*/)
  1098. {
  1099. ASSERT(FALSE); // derivative must override -- must not call base class
  1100. }
  1101. void COleClientItem::OnGetItemPosition(CRect& /*rPosition*/)
  1102. {
  1103. // default does nothing
  1104. }
  1105. void COleClientItem::OnGetClipRect(CRect& rClipRect)
  1106. {
  1107. ASSERT_VALID(this);
  1108. ASSERT(AfxIsValidAddress(&rClipRect, sizeof(RECT)));
  1109. // default clips rectClip to client area of the active view
  1110. ASSERT_VALID(m_pView);
  1111. m_pView->GetClientRect(&rClipRect);
  1112. }
  1113. void COleClientItem::OnShowItem()
  1114. {
  1115. ASSERT_VALID(this);
  1116. CDocument* pDoc = GetDocument();
  1117. ASSERT_VALID(pDoc);
  1118. // attempt to use m_pView set during activation
  1119. CView* pView = m_pView;
  1120. if (pView == NULL)
  1121. {
  1122. // otherwise, find the first view of this document
  1123. POSITION pos = pDoc->GetFirstViewPosition();
  1124. if (pos == NULL || (pView = pDoc->GetNextView(pos)) == NULL)
  1125. return;
  1126. }
  1127. CFrameWnd* pFrameWnd = pView->GetParentFrame();
  1128. if (pFrameWnd != NULL)
  1129. {
  1130. // activate frame holding view
  1131. pFrameWnd->ActivateFrame();
  1132. pFrameWnd->OnUpdateFrameTitle(TRUE);
  1133. // activate app frame if necessary
  1134. pFrameWnd = pFrameWnd->GetParentFrame();
  1135. if (pFrameWnd != NULL)
  1136. {
  1137. ASSERT_KINDOF(CFrameWnd, pFrameWnd);
  1138. pFrameWnd->ActivateFrame();
  1139. pFrameWnd->OnUpdateFrameTitle(TRUE);
  1140. }
  1141. }
  1142. if (!pDoc->GetPathName().IsEmpty())
  1143. {
  1144. // user is also in control of the application, when a file-based
  1145. // document becomes visible.
  1146. AfxOleSetUserCtrl(TRUE);
  1147. }
  1148. }
  1149. /////////////////////////////////////////////////////////////////////////////
  1150. // COleClientItem - attributes
  1151. void COleClientItem::GetClassID(CLSID* pClassID) const
  1152. {
  1153. ASSERT_VALID(this);
  1154. ASSERT(m_lpObject != NULL);
  1155. ASSERT(AfxIsValidAddress(pClassID, sizeof(CLSID)));
  1156. if (m_lpObject->GetUserClassID(pClassID) != S_OK)
  1157. *pClassID = CLSID_NULL;
  1158. }
  1159. BOOL COleClientItem::GetExtent(LPSIZE lpSize, DVASPECT nDrawAspect)
  1160. {
  1161. ASSERT_VALID(this);
  1162. ASSERT(m_lpObject != NULL);
  1163. ASSERT(AfxIsValidAddress(lpSize, sizeof(CSize)));
  1164. // use current default aspect if specific one not specified
  1165. if (nDrawAspect == -1)
  1166. nDrawAspect = m_nDrawAspect;
  1167. // get the extent
  1168. m_scLast = m_lpObject->GetExtent(nDrawAspect, lpSize);
  1169. return m_scLast == S_OK;
  1170. }
  1171. BOOL COleClientItem::GetCachedExtent(LPSIZE lpSize, DVASPECT nDrawAspect)
  1172. {
  1173. ASSERT_VALID(this);
  1174. ASSERT(m_lpViewObject != NULL);
  1175. ASSERT(AfxIsValidAddress(lpSize, sizeof(CSize)));
  1176. // use current default aspect if specific one not specified
  1177. if (nDrawAspect == -1)
  1178. nDrawAspect = m_nDrawAspect;
  1179. COleDocument* pDoc = (COleDocument*)GetDocument();
  1180. ASSERT_VALID(pDoc);
  1181. // get the extent
  1182. m_scLast = m_lpViewObject->GetExtent(nDrawAspect, -1, pDoc->m_ptd, lpSize);
  1183. return m_scLast == S_OK;
  1184. }
  1185. BOOL COleClientItem::SetIconicMetafile(HGLOBAL hMetaPict)
  1186. {
  1187. ASSERT_VALID(this);
  1188. ASSERT(m_lpObject != NULL);
  1189. // get IOleCache interface
  1190. LPOLECACHE lpOleCache = QUERYINTERFACE(m_lpObject, IOleCache);
  1191. if (lpOleCache == NULL)
  1192. {
  1193. TRACE0("Warning: object does not support IOleCache interface.\n");
  1194. return FALSE;
  1195. }
  1196. ASSERT(lpOleCache != NULL);
  1197. // new cache is for CF_METAFILEPICT, DVASPECT_ICON
  1198. FORMATETC formatEtc;
  1199. formatEtc.cfFormat = CF_METAFILEPICT;
  1200. formatEtc.ptd = NULL;
  1201. formatEtc.dwAspect = DVASPECT_ICON;
  1202. formatEtc.lindex = -1;
  1203. formatEtc.tymed = TYMED_MFPICT;
  1204. // setup the cache so iconic aspect is now included
  1205. DWORD dwConnection;
  1206. SCODE sc = lpOleCache->Cache(&formatEtc,
  1207. ADVF_NODATA|ADVF_PRIMEFIRST|ADVF_ONLYONCE, &dwConnection);
  1208. if (FAILED(sc))
  1209. {
  1210. lpOleCache->Release();
  1211. return FALSE;
  1212. }
  1213. // set data if iconic image provided
  1214. if (hMetaPict != NULL)
  1215. {
  1216. STGMEDIUM stgMedium;
  1217. stgMedium.tymed = TYMED_MFPICT;
  1218. stgMedium.hGlobal = hMetaPict;
  1219. stgMedium.pUnkForRelease = NULL;
  1220. sc = lpOleCache->SetData(&formatEtc, &stgMedium, FALSE);
  1221. if (FAILED(sc))
  1222. {
  1223. lpOleCache->Release();
  1224. return FALSE;
  1225. }
  1226. }
  1227. lpOleCache->Release();
  1228. return TRUE;
  1229. }
  1230. HGLOBAL COleClientItem::GetIconicMetafile()
  1231. {
  1232. USES_CONVERSION;
  1233. ASSERT_VALID(this);
  1234. ASSERT(m_lpObject != NULL);
  1235. // get IDataObject interface
  1236. LPDATAOBJECT lpDataObject = QUERYINTERFACE(m_lpObject, IDataObject);
  1237. ASSERT(lpDataObject != NULL);
  1238. // cache is for CF_METAFILEPICT, DVASPECT_ICON
  1239. FORMATETC formatEtc;
  1240. formatEtc.cfFormat = CF_METAFILEPICT;
  1241. formatEtc.ptd = NULL;
  1242. formatEtc.dwAspect = DVASPECT_ICON;
  1243. formatEtc.lindex = -1;
  1244. formatEtc.tymed = TYMED_MFPICT;
  1245. // attempt to get the icon picture
  1246. STGMEDIUM stgMedium;
  1247. if (lpDataObject->GetData(&formatEtc, &stgMedium) != S_OK)
  1248. {
  1249. lpDataObject->Release();
  1250. // no current picture, attempt to get from class ID
  1251. CLSID clsid;
  1252. if (m_lpObject->GetUserClassID(&clsid) != S_OK)
  1253. return NULL;
  1254. TCHAR szTemp[_MAX_PATH];
  1255. LPTSTR lpszLabel = NULL;
  1256. if (GetType() == OT_LINK)
  1257. {
  1258. // it is a link, attempt to get link name
  1259. LPOLELINK lpOleLink = QUERYINTERFACE(m_lpObject, IOleLink);
  1260. if (lpOleLink != NULL)
  1261. {
  1262. LPOLESTR lpszDisplayName = NULL;
  1263. lpOleLink->GetSourceDisplayName(&lpszDisplayName);
  1264. if (lpszDisplayName != NULL)
  1265. {
  1266. szTemp[0] = 0;
  1267. AfxGetFileTitle(OLE2CT(lpszDisplayName), szTemp, _countof(szTemp));
  1268. if (szTemp[0] != '\0')
  1269. lpszLabel = szTemp;
  1270. CoTaskMemFree(lpszDisplayName);
  1271. }
  1272. lpOleLink->Release();
  1273. }
  1274. }
  1275. HGLOBAL hMetaPict = OleGetIconOfClass(clsid, T2OLE(lpszLabel), lpszLabel == NULL);
  1276. if (hMetaPict != NULL)
  1277. {
  1278. // cache it for later GetData (or drawing)
  1279. SetIconicMetafile(hMetaPict);
  1280. return hMetaPict;
  1281. }
  1282. return NULL;
  1283. }
  1284. lpDataObject->Release();
  1285. // can't handle data where punkForRelease is set
  1286. if (stgMedium.pUnkForRelease != NULL)
  1287. {
  1288. ::ReleaseStgMedium(&stgMedium);
  1289. return NULL;
  1290. }
  1291. ASSERT(stgMedium.tymed == TYMED_MFPICT);
  1292. ASSERT(stgMedium.hGlobal != NULL);
  1293. return stgMedium.hGlobal; // return HGLOBAL to METAFILEPICT
  1294. }
  1295. void COleClientItem::SetDrawAspect(DVASPECT nDrawAspect)
  1296. {
  1297. ASSERT_VALID(this);
  1298. // prime iconic cache (in case object has never displayed iconic)
  1299. if (nDrawAspect == DVASPECT_ICON)
  1300. {
  1301. SetIconicMetafile(NULL); // allow object to provide own icon
  1302. HGLOBAL hMetaPict = GetIconicMetafile();
  1303. _AfxDeleteMetafilePict(hMetaPict);
  1304. }
  1305. // Note: the aspect you are setting may be uncached and therefore blank.
  1306. // To make sure it is cached use SetIconPicture or use IOleCache to
  1307. // set the cache yourself.
  1308. m_nDrawAspect = nDrawAspect;
  1309. // mark document as dirty (m_nDrawAspect is part of persistent state)
  1310. ASSERT_VALID(m_pDocument);
  1311. m_pDocument->SetModifiedFlag();
  1312. }
  1313. // Helper used to get the DVTARGETDEVICE pointer for the first printer.
  1314. BOOL COleClientItem::GetPrintDeviceInfo(
  1315. LPOLECACHE* plpOleCache, DVTARGETDEVICE** pptd, DWORD* pdwConnection)
  1316. {
  1317. *plpOleCache = NULL;
  1318. *pptd = NULL;
  1319. // get IOleCache interface
  1320. LPOLECACHE lpOleCache = QUERYINTERFACE(m_lpObject, IOleCache);
  1321. if (lpOleCache == NULL)
  1322. {
  1323. TRACE0("Warning: object does not support IOleCache interface.\n");
  1324. return FALSE; // no cache -- no possible print device
  1325. }
  1326. ASSERT(lpOleCache != NULL);
  1327. // get enumerator for the cache
  1328. LPENUMSTATDATA lpEnumSTATDATA;
  1329. if (lpOleCache->EnumCache(&lpEnumSTATDATA) != S_OK || lpEnumSTATDATA == NULL)
  1330. {
  1331. lpOleCache->Release();
  1332. return FALSE;
  1333. }
  1334. // enumerate entries in the cache (look for one with ptd != NULL)
  1335. STATDATA statData;
  1336. while (lpEnumSTATDATA->Next(1, &statData, NULL) == S_OK)
  1337. {
  1338. ASSERT(statData.pAdvSink == NULL);
  1339. // return first non-NULL ptd (we assume this is a printer cache)
  1340. if (statData.formatetc.ptd != NULL)
  1341. {
  1342. if (pdwConnection != NULL)
  1343. *pdwConnection = statData.dwConnection;
  1344. *pptd = statData.formatetc.ptd;
  1345. lpEnumSTATDATA->Release();
  1346. *plpOleCache = lpOleCache;
  1347. return TRUE; // Note: lpOleCache pointer is still alive
  1348. }
  1349. }
  1350. // release interfaces
  1351. lpEnumSTATDATA->Release();
  1352. lpOleCache->Release();
  1353. return FALSE; // data not found
  1354. }
  1355. void COleClientItem::AttachDataObject(COleDataObject& rDataObject) const
  1356. {
  1357. ASSERT_VALID(this);
  1358. ASSERT(m_lpObject != NULL);
  1359. // get the IDataObject interface for the item
  1360. LPDATAOBJECT lpDataObject = QUERYINTERFACE(m_lpObject, IDataObject);
  1361. ASSERT(lpDataObject != NULL);
  1362. // return it by attaching it
  1363. rDataObject.Attach(lpDataObject, TRUE);
  1364. }
  1365. /////////////////////////////////////////////////////////////////////////////
  1366. // COleClientItem - general operations
  1367. BOOL COleClientItem::Draw(CDC* pDC, LPCRECT lpBounds, DVASPECT nDrawAspect)
  1368. {
  1369. ASSERT_VALID(this);
  1370. ASSERT(AfxIsValidAddress(lpBounds, sizeof(RECT), FALSE));
  1371. ASSERT_VALID(pDC);
  1372. if (m_lpObject == NULL || m_lpViewObject == NULL)
  1373. return FALSE; // partially created COleClientItem object
  1374. // use current draw aspect if aspect is -1 (default)
  1375. if (nDrawAspect == -1)
  1376. nDrawAspect = m_nDrawAspect;
  1377. // convert RECT lpBounds to RECTL rclBounds
  1378. RECTL rclBounds;
  1379. rclBounds.left = lpBounds->left;
  1380. rclBounds.top = lpBounds->top;
  1381. rclBounds.right = lpBounds->right;
  1382. rclBounds.bottom = lpBounds->bottom;
  1383. // get RECTL describing window extents and origin
  1384. RECTL rclWBounds;
  1385. CPoint ptOrg = pDC->GetWindowOrg();
  1386. CSize sizeExt = pDC->GetWindowExt();
  1387. rclWBounds.left = ptOrg.x;
  1388. rclWBounds.top = ptOrg.y;
  1389. rclWBounds.right = sizeExt.cx;
  1390. rclWBounds.bottom = sizeExt.cy;
  1391. // get target device to use for draw
  1392. COleDocument* pDoc = GetDocument();
  1393. const DVTARGETDEVICE* ptd = NULL;
  1394. HDC hdcTarget = NULL;
  1395. if (pDC->IsPrinting() && pDoc->m_ptd != NULL)
  1396. {
  1397. ptd = pDoc->m_ptd;
  1398. hdcTarget = pDC->m_hAttribDC;
  1399. }
  1400. // attempt draw with target device
  1401. SCODE sc = m_lpViewObject->Draw(nDrawAspect, -1, NULL,
  1402. (DVTARGETDEVICE*)ptd, hdcTarget, pDC->m_hDC,
  1403. &rclBounds, &rclWBounds, NULL, 0);
  1404. if (ptd != NULL && sc == OLE_E_BLANK)
  1405. {
  1406. // attempt draw without target device
  1407. sc = m_lpViewObject->Draw(nDrawAspect, -1, NULL,
  1408. NULL, NULL, pDC->m_hDC,
  1409. &rclBounds, &rclWBounds, NULL, 0);
  1410. }
  1411. if (sc != S_OK && sc == OLE_E_BLANK)
  1412. return FALSE; // return FALSE if the object is blank
  1413. CheckGeneral(sc); // otherwise, may throw exception on error
  1414. return TRUE;
  1415. }
  1416. /////////////////////////////////////////////////////////////////////////////
  1417. // COleClientItem clipboard helpers
  1418. void COleClientItem::GetEmbeddedItemData(LPSTGMEDIUM lpStgMedium)
  1419. {
  1420. ASSERT_VALID(this);
  1421. ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));
  1422. LPLOCKBYTES lpLockBytes;
  1423. SCODE sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);
  1424. if (sc != S_OK)
  1425. AfxThrowOleException(sc);
  1426. ASSERT(lpLockBytes != NULL);
  1427. LPSTORAGE lpStorage;
  1428. sc = ::StgCreateDocfileOnILockBytes(lpLockBytes,
  1429. STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &lpStorage);
  1430. if (sc != S_OK)
  1431. {
  1432. VERIFY(lpLockBytes->Release() == 0);
  1433. AfxThrowOleException(sc);
  1434. }
  1435. ASSERT(lpStorage != NULL);
  1436. lpLockBytes->Release();
  1437. // save the object into the storage
  1438. LPPERSISTSTORAGE lpPersistStorage =
  1439. QUERYINTERFACE(m_lpObject, IPersistStorage);
  1440. ASSERT(lpPersistStorage != NULL);
  1441. sc = ::OleSave(lpPersistStorage, lpStorage, FALSE);
  1442. lpPersistStorage->SaveCompleted(NULL);
  1443. lpPersistStorage->Release();
  1444. if (sc != S_OK)
  1445. {
  1446. VERIFY(lpStorage->Release() == 0);
  1447. AfxThrowOleException(sc);
  1448. }
  1449. // add it to the data source
  1450. lpStgMedium->tymed = TYMED_ISTORAGE;
  1451. lpStgMedium->pstg = lpStorage;
  1452. lpStgMedium->pUnkForRelease = NULL;
  1453. }
  1454. void COleClientItem::AddCachedData(COleDataSource* pDataSource)
  1455. {
  1456. ASSERT_VALID(this);
  1457. ASSERT_VALID(pDataSource);
  1458. // get IOleCache interface
  1459. LPOLECACHE lpOleCache = QUERYINTERFACE(m_lpObject, IOleCache);
  1460. if (lpOleCache == NULL)
  1461. {
  1462. TRACE0("Warning: object does not support IOleCache interface.\n");
  1463. return;
  1464. }
  1465. ASSERT(lpOleCache != NULL);
  1466. // Get IEnumSTATDATA interface for IOleCache
  1467. LPENUMSTATDATA lpEnumSTATDATA;
  1468. if (lpOleCache->EnumCache(&lpEnumSTATDATA) != S_OK || lpEnumSTATDATA == NULL)
  1469. {
  1470. lpOleCache->Release();
  1471. return;
  1472. }
  1473. // get IDataObject interface
  1474. LPDATAOBJECT lpDataObject = QUERYINTERFACE(m_lpObject, IDataObject);
  1475. ASSERT(lpDataObject != NULL);
  1476. // enumerate all of the cached formats
  1477. STATDATA statData;
  1478. while (lpEnumSTATDATA->Next(1, &statData, NULL) == S_OK)
  1479. {
  1480. ASSERT(statData.pAdvSink == NULL);
  1481. // for each format supported, attempt to get copy of the data
  1482. STGMEDIUM stgMedium;
  1483. if (lpDataObject->GetData(&statData.formatetc, &stgMedium) != S_OK)
  1484. {
  1485. // data is not available
  1486. CoTaskMemFree(statData.formatetc.ptd);
  1487. }
  1488. else if (stgMedium.pUnkForRelease != NULL)
  1489. {
  1490. // don't cache data with pUnkForRelease != NULL
  1491. ::ReleaseStgMedium(&stgMedium);
  1492. CoTaskMemFree(statData.formatetc.ptd);
  1493. }
  1494. else
  1495. {
  1496. // format was acceptable -- add it to the clipboard
  1497. pDataSource->CacheData(0, &stgMedium, &statData.formatetc);
  1498. }
  1499. }
  1500. // release interfaces
  1501. lpEnumSTATDATA->Release();
  1502. lpDataObject->Release();
  1503. lpOleCache->Release();
  1504. }
  1505. BOOL COleClientItem::GetLinkSourceData(LPSTGMEDIUM lpStgMedium)
  1506. {
  1507. ASSERT_VALID(this);
  1508. ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));
  1509. LPMONIKER lpMoniker = NULL;
  1510. LPOLELINK lpOleLink = QUERYINTERFACE(m_lpObject, IOleLink);
  1511. if (lpOleLink == NULL)
  1512. {
  1513. // get moniker from client site
  1514. LPOLECLIENTSITE lpClientSite = GetClientSite();
  1515. ASSERT(lpClientSite != NULL);
  1516. SCODE sc = lpClientSite->GetMoniker(OLEGETMONIKER_TEMPFORUSER,
  1517. OLEWHICHMK_OBJFULL, &lpMoniker);
  1518. if (sc != S_OK)
  1519. {
  1520. TRACE0("Warning: unable to get moniker from client site.\n");
  1521. return FALSE;
  1522. }
  1523. ASSERT(lpMoniker != NULL);
  1524. }
  1525. else
  1526. {
  1527. // get moniker from the link object itself
  1528. SCODE sc = lpOleLink->GetSourceMoniker(&lpMoniker);
  1529. lpOleLink->Release();
  1530. if (sc != S_OK)
  1531. {
  1532. TRACE0("Warning: unable to get moniker from link source.\n");
  1533. return FALSE;
  1534. }
  1535. ASSERT(lpMoniker != NULL);
  1536. }
  1537. // create a memory based stream to write the moniker to
  1538. LPSTREAM lpStream;
  1539. if (::CreateStreamOnHGlobal(NULL, TRUE, &lpStream) != S_OK)
  1540. {
  1541. lpMoniker->Release();
  1542. AfxThrowMemoryException();
  1543. }
  1544. ASSERT(lpStream != NULL);
  1545. // write the moniker to the stream, and add it to the clipboard
  1546. SCODE sc = ::OleSaveToStream(lpMoniker, lpStream);
  1547. lpMoniker->Release();
  1548. if (sc != S_OK)
  1549. {
  1550. lpStream->Release();
  1551. AfxThrowOleException(sc);
  1552. }
  1553. // write the class ID of the document to the stream as well
  1554. CLSID clsid;
  1555. sc = m_lpObject->GetUserClassID(&clsid);
  1556. if (sc != S_OK)
  1557. {
  1558. lpStream->Release();
  1559. AfxThrowOleException(sc);
  1560. }
  1561. sc = WriteClassStm(lpStream, clsid);
  1562. if (sc != S_OK)
  1563. {
  1564. lpStream->Release();
  1565. AfxThrowOleException(sc);
  1566. }
  1567. // add it to the data source
  1568. lpStgMedium->tymed = TYMED_ISTREAM;
  1569. lpStgMedium->pstm = lpStream;
  1570. lpStgMedium->pUnkForRelease = NULL;
  1571. return TRUE;
  1572. }
  1573. void COleClientItem::GetObjectDescriptorData(
  1574. LPPOINT lpOffset, LPSIZE lpSize, LPSTGMEDIUM lpStgMedium)
  1575. {
  1576. USES_CONVERSION;
  1577. ASSERT_VALID(this);
  1578. ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));
  1579. ASSERT(lpOffset == NULL ||
  1580. AfxIsValidAddress(lpOffset, sizeof(CPoint), FALSE));
  1581. POINTL pointT;
  1582. if (lpOffset != NULL)
  1583. {
  1584. pointT.x = lpOffset->x;
  1585. pointT.y = lpOffset->y;
  1586. ((CDC*)NULL)->DPtoHIMETRIC((SIZE*)&pointT);
  1587. }
  1588. else
  1589. {
  1590. pointT.x = 0;
  1591. pointT.y = 0;
  1592. }
  1593. SIZE sizeT;
  1594. if (lpSize != NULL)
  1595. {
  1596. sizeT.cx = lpSize->cx;
  1597. sizeT.cy = lpSize->cy;
  1598. ((CDC*)NULL)->DPtoHIMETRIC(&sizeT);
  1599. }
  1600. else
  1601. {
  1602. sizeT.cx = 0;
  1603. sizeT.cy = 0;
  1604. }
  1605. COleDocument* pDoc = GetDocument();
  1606. // get the object descriptor for the IOleObject
  1607. InterlockedIncrement(&m_dwRef);
  1608. HGLOBAL hGlobal = _AfxOleGetObjectDescriptorData(
  1609. m_lpObject, T2COLE(pDoc->GetPathName()), m_nDrawAspect, pointT, &sizeT);
  1610. InterlockedDecrement(&m_dwRef);
  1611. if (hGlobal == NULL)
  1612. AfxThrowMemoryException();
  1613. // setup the STGMEDIUM
  1614. lpStgMedium->tymed = TYMED_HGLOBAL;
  1615. lpStgMedium->hGlobal = hGlobal;
  1616. lpStgMedium->pUnkForRelease = NULL;
  1617. }
  1618. /////////////////////////////////////////////////////////////////////////////
  1619. // Embedded COleClientItem operations
  1620. void COleClientItem::SetHostNames(LPCTSTR lpszHost, LPCTSTR lpszHostObj)
  1621. {
  1622. USES_CONVERSION;
  1623. ASSERT_VALID(this);
  1624. ASSERT(m_lpObject != NULL);
  1625. ASSERT(AfxIsValidString(lpszHost));
  1626. ASSERT(AfxIsValidString(lpszHostObj));
  1627. CheckGeneral(m_lpObject->SetHostNames(T2COLE(lpszHost),
  1628. T2COLE(lpszHostObj)));
  1629. }
  1630. void COleClientItem::SetExtent(const CSize& size, DVASPECT nDrawAspect)
  1631. {
  1632. ASSERT_VALID(this);
  1633. ASSERT(m_lpObject != NULL);
  1634. CheckGeneral(m_lpObject->SetExtent(nDrawAspect, (SIZE*)&size));
  1635. }
  1636. /////////////////////////////////////////////////////////////////////////////
  1637. // COleClientItem OLE interface implementation
  1638. BEGIN_INTERFACE_MAP(COleClientItem, CDocItem)
  1639. INTERFACE_PART(COleClientItem, IID_IOleClientSite, OleClientSite)
  1640. INTERFACE_PART(COleClientItem, IID_IAdviseSink, AdviseSink)
  1641. INTERFACE_PART(COleClientItem, IID_IOleWindow, OleIPSite)
  1642. INTERFACE_PART(COleClientItem, IID_IOleInPlaceSite, OleIPSite)
  1643. END_INTERFACE_MAP()
  1644. /////////////////////////////////////////////////////////////////////////////
  1645. // Implementation of IOleClientSite
  1646. STDMETHODIMP_(ULONG) COleClientItem::XOleClientSite::AddRef()
  1647. {
  1648. METHOD_PROLOGUE_EX_(COleClientItem, OleClientSite)
  1649. return pThis->ExternalAddRef();
  1650. }
  1651. STDMETHODIMP_(ULONG) COleClientItem::XOleClientSite::Release()
  1652. {
  1653. METHOD_PROLOGUE_EX_(COleClientItem, OleClientSite)
  1654. return pThis->ExternalRelease();
  1655. }
  1656. STDMETHODIMP COleClientItem::XOleClientSite::QueryInterface(
  1657. REFIID iid, LPVOID* ppvObj)
  1658. {
  1659. METHOD_PROLOGUE_EX_(COleClientItem, OleClientSite)
  1660. return pThis->ExternalQueryInterface(&iid, ppvObj);
  1661. }
  1662. STDMETHODIMP COleClientItem::XOleClientSite::SaveObject()
  1663. {
  1664. METHOD_PROLOGUE_EX(COleClientItem, OleClientSite)
  1665. ASSERT_VALID(pThis);
  1666. LPPERSISTSTORAGE lpPersistStorage =
  1667. QUERYINTERFACE(pThis->m_lpObject, IPersistStorage);
  1668. ASSERT(lpPersistStorage != NULL);
  1669. SCODE sc = S_OK;
  1670. if (lpPersistStorage->IsDirty() == S_OK)
  1671. {
  1672. // S_OK == S_TRUE != S_FALSE, therefore object is dirty!
  1673. sc = ::OleSave(lpPersistStorage, pThis->m_lpStorage, TRUE);
  1674. if (sc == S_OK)
  1675. sc = lpPersistStorage->SaveCompleted(NULL);
  1676. // mark the document as dirty, if save sucessful.
  1677. pThis->m_pDocument->SetModifiedFlag();
  1678. }
  1679. lpPersistStorage->Release();
  1680. return sc;
  1681. }
  1682. STDMETHODIMP COleClientItem::XOleClientSite::GetMoniker(
  1683. DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER* ppMoniker)
  1684. {
  1685. METHOD_PROLOGUE_EX(COleClientItem, OleClientSite)
  1686. ASSERT_VALID(pThis);
  1687. USES_CONVERSION;
  1688. COleDocument* pDoc = pThis->GetDocument();
  1689. ASSERT_VALID(pDoc);
  1690. ASSERT(ppMoniker != NULL);
  1691. *ppMoniker = NULL;
  1692. switch (dwWhichMoniker)
  1693. {
  1694. case OLEWHICHMK_CONTAINER:
  1695. // return the current moniker for the document
  1696. *ppMoniker = pDoc->GetMoniker((OLEGETMONIKER)dwAssign);
  1697. break;
  1698. case OLEWHICHMK_OBJREL:
  1699. {
  1700. if (!pDoc->IsKindOf(RUNTIME_CLASS(COleLinkingDoc)))
  1701. break;
  1702. // don't return relative moniker if no document moniker
  1703. LPMONIKER lpMoniker = pDoc->GetMoniker((OLEGETMONIKER)dwAssign);
  1704. if (lpMoniker == NULL)
  1705. break;
  1706. lpMoniker->Release();
  1707. // relative monikers have to handle assignment correctly
  1708. switch (dwAssign)
  1709. {
  1710. case OLEGETMONIKER_ONLYIFTHERE:
  1711. if (!pThis->m_bMoniker)
  1712. break; // no moniker assigned, don't return one
  1713. // fall through...
  1714. case OLEGETMONIKER_TEMPFORUSER:
  1715. case OLEGETMONIKER_FORCEASSIGN:
  1716. {
  1717. // create item moniker from item name
  1718. TCHAR szItemName[OLE_MAXITEMNAME];
  1719. pThis->GetItemName(szItemName);
  1720. CreateItemMoniker(OLESTDDELIMOLE, T2COLE(szItemName),
  1721. ppMoniker);
  1722. // notify the object of the assignment
  1723. if (dwAssign != OLEGETMONIKER_TEMPFORUSER &&
  1724. *ppMoniker != NULL && !pThis->m_bMoniker)
  1725. {
  1726. pThis->m_bMoniker = TRUE;
  1727. VERIFY(pThis->m_lpObject->SetMoniker(
  1728. OLEWHICHMK_OBJREL, *ppMoniker) == S_OK);
  1729. ASSERT_VALID(pThis->m_pDocument);
  1730. pThis->m_pDocument->SetModifiedFlag();
  1731. }
  1732. }
  1733. break;
  1734. case OLEGETMONIKER_UNASSIGN:
  1735. pThis->m_bMoniker = FALSE;
  1736. break;
  1737. }
  1738. }
  1739. break;
  1740. case OLEWHICHMK_OBJFULL:
  1741. {
  1742. // get each sub-moniker: item & document
  1743. LPMONIKER lpMoniker1, lpMoniker2;
  1744. GetMoniker(dwAssign, OLEWHICHMK_CONTAINER, &lpMoniker1);
  1745. GetMoniker(dwAssign, OLEWHICHMK_OBJREL, &lpMoniker2);
  1746. // create composite moniker
  1747. if (lpMoniker1 != NULL && lpMoniker2 != NULL)
  1748. ::CreateGenericComposite(lpMoniker1, lpMoniker2, ppMoniker);
  1749. // release sub-monikers
  1750. RELEASE(lpMoniker1);
  1751. RELEASE(lpMoniker2);
  1752. }
  1753. break;
  1754. }
  1755. return *ppMoniker != NULL ? S_OK : E_FAIL;
  1756. }
  1757. STDMETHODIMP COleClientItem::XOleClientSite::GetContainer(
  1758. LPOLECONTAINER* ppContainer)
  1759. {
  1760. #ifdef _DEBUG
  1761. METHOD_PROLOGUE_EX(COleClientItem, OleClientSite)
  1762. #else
  1763. METHOD_PROLOGUE_EX_(COleClientItem, OleClientSite)
  1764. #endif
  1765. // return the IOleItemContainer interface in the document
  1766. COleDocument* pDoc = pThis->GetDocument();
  1767. ASSERT_VALID(pDoc);
  1768. *ppContainer = pDoc->GetContainer();
  1769. return *ppContainer != NULL ? S_OK : E_NOINTERFACE;
  1770. }
  1771. STDMETHODIMP COleClientItem::XOleClientSite::ShowObject()
  1772. {
  1773. METHOD_PROLOGUE_EX(COleClientItem, OleClientSite)
  1774. ASSERT_VALID(pThis);
  1775. TRY
  1776. {
  1777. pThis->OnShowItem();
  1778. }
  1779. END_TRY
  1780. return S_OK;
  1781. }
  1782. STDMETHODIMP COleClientItem::XOleClientSite::OnShowWindow(BOOL fShow)
  1783. {
  1784. METHOD_PROLOGUE_EX(COleClientItem, OleClientSite)
  1785. ASSERT_VALID(pThis);
  1786. // ignore this if the item is already in-place
  1787. if (pThis->IsInPlaceActive())
  1788. return S_OK;
  1789. TRY
  1790. {
  1791. // store new state of object -- determines how object may be drawn
  1792. COleClientItem::ItemState uNewState;
  1793. uNewState = fShow ? COleClientItem::openState :
  1794. COleClientItem::loadedState;
  1795. if (uNewState != pThis->m_nItemState)
  1796. {
  1797. pThis->OnChange(OLE_CHANGED_STATE, (DWORD)uNewState);
  1798. pThis->m_nItemState = uNewState;
  1799. }
  1800. }
  1801. END_TRY
  1802. return S_OK;
  1803. }
  1804. STDMETHODIMP COleClientItem::XOleClientSite::RequestNewObjectLayout()
  1805. {
  1806. return E_NOTIMPL;
  1807. }
  1808. /////////////////////////////////////////////////////////////////////////////
  1809. // Implementation of IAdviseSink
  1810. STDMETHODIMP_(ULONG) COleClientItem::XAdviseSink::AddRef()
  1811. {
  1812. METHOD_PROLOGUE_EX_(COleClientItem, AdviseSink)
  1813. return pThis->ExternalAddRef();
  1814. }
  1815. STDMETHODIMP_(ULONG) COleClientItem::XAdviseSink::Release()
  1816. {
  1817. METHOD_PROLOGUE_EX_(COleClientItem, AdviseSink)
  1818. return pThis->ExternalRelease();
  1819. }
  1820. STDMETHODIMP COleClientItem::XAdviseSink::QueryInterface(
  1821. REFIID iid, LPVOID* ppvObj)
  1822. {
  1823. METHOD_PROLOGUE_EX_(COleClientItem, AdviseSink)
  1824. return pThis->ExternalQueryInterface(&iid, ppvObj);
  1825. }
  1826. STDMETHODIMP_(void) COleClientItem::XAdviseSink::OnDataChange(
  1827. LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
  1828. {
  1829. METHOD_PROLOGUE_EX(COleClientItem, AdviseSink)
  1830. ASSERT_VALID(pThis);
  1831. // Only interesting for advanced containers. Forward it such that
  1832. // containers do not have to implement the entire interface.
  1833. pThis->OnDataChange(lpFormatEtc, lpStgMedium);
  1834. }
  1835. STDMETHODIMP_(void) COleClientItem::XAdviseSink::OnViewChange(
  1836. DWORD aspects, LONG /*lindex*/)
  1837. {
  1838. METHOD_PROLOGUE_EX(COleClientItem, AdviseSink)
  1839. ASSERT_VALID(pThis);
  1840. pThis->OnChange(OLE_CHANGED, (DVASPECT)aspects);
  1841. }
  1842. STDMETHODIMP_(void) COleClientItem::XAdviseSink::OnRename(
  1843. LPMONIKER /*lpMoniker*/)
  1844. {
  1845. // only interesting to the OLE link object. Containers ignore this.
  1846. }
  1847. STDMETHODIMP_(void) COleClientItem::XAdviseSink::OnSave()
  1848. {
  1849. METHOD_PROLOGUE_EX(COleClientItem, AdviseSink)
  1850. ASSERT_VALID(pThis);
  1851. pThis->OnChange(OLE_SAVED, (DVASPECT)0);
  1852. }
  1853. STDMETHODIMP_(void) COleClientItem::XAdviseSink::OnClose()
  1854. {
  1855. METHOD_PROLOGUE_EX(COleClientItem, AdviseSink)
  1856. ASSERT_VALID(pThis);
  1857. pThis->OnChange(OLE_CLOSED, (DVASPECT)0);
  1858. }
  1859. /////////////////////////////////////////////////////////////////////////////
  1860. // COleClientItem diagnostics
  1861. #ifdef _DEBUG
  1862. void COleClientItem::AssertValid() const
  1863. {
  1864. CDocItem::AssertValid();
  1865. if (m_lpNewStorage != NULL)
  1866. ASSERT(m_bNeedCommit);
  1867. if (m_pView != NULL)
  1868. m_pView->AssertValid();
  1869. if (m_pInPlaceFrame != NULL)
  1870. m_pInPlaceFrame->AssertValid();
  1871. if (m_pInPlaceDoc != NULL)
  1872. m_pInPlaceDoc->AssertValid();
  1873. }
  1874. void COleClientItem::Dump(CDumpContext& dc) const
  1875. {
  1876. CDocItem::Dump(dc);
  1877. // shallow dump
  1878. dc << "m_lpObject = " << (void*)m_lpObject;
  1879. dc << "\nm_dwItemNumber = " << m_dwItemNumber;
  1880. dc << "\nm_nDrawAspect = " << (int)m_nDrawAspect;
  1881. dc << "\nm_scLast = " << m_scLast;
  1882. dc << "\nm_lpStorage = " << m_lpStorage;
  1883. dc << "\nm_lpLockBytes = " << m_lpLockBytes;
  1884. dc << "\nm_dwConnection = " << m_dwConnection;
  1885. dc << "\nm_bLinkUnavail = " << m_bLinkUnavail;
  1886. dc << "\nm_bMoniker = " << m_bMoniker;
  1887. dc << "\nm_lpNewStorage = " << m_lpNewStorage;
  1888. dc << "\nm_bNeedCommit = " << m_bNeedCommit;
  1889. dc << "\nm_nItemState = " << (int)m_nItemState;
  1890. dc << "\nm_pView = " << (void*)m_pView;
  1891. dc << "\nm_dwContainerStyle = " << m_dwContainerStyle;
  1892. dc << "\nm_pInPlaceFrame = " << (void*)m_pInPlaceFrame;
  1893. dc << "\nm_hWndServer = " << m_hWndServer;
  1894. }
  1895. #endif //_DEBUG
  1896. /////////////////////////////////////////////////////////////////////////////
  1897. // Inline function declarations expanded out-of-line
  1898. #ifndef _AFX_ENABLE_INLINES
  1899. // expand inlines for OLE client APIs
  1900. static char _szAfxOleInl[] = "afxole.inl";
  1901. #undef THIS_FILE
  1902. #define THIS_FILE _szAfxOleInl
  1903. #define _AFXOLECLI_INLINE
  1904. #define _AFXOLEDOBJ_INLINE
  1905. #include "afxole.inl"
  1906. #endif //!_AFX_ENABLE_INLINES
  1907. #ifdef AFX_INIT_SEG
  1908. #pragma code_seg(AFX_INIT_SEG)
  1909. #endif
  1910. // IMPLEMENT_DYNAMIC for COleLinkingDoc here for better .OBJ granularity
  1911. IMPLEMENT_DYNAMIC(COleLinkingDoc, COleDocument)
  1912. /////////////////////////////////////////////////////////////////////////////