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.

1710 lines
46 KiB

  1. #include "priv.h"
  2. #include "sccls.h"
  3. #include <mluisupp.h>
  4. #define IPSMSG(psz) TraceMsg(TF_SHDCONTROL, "she TR-IPS::%s called", psz)
  5. #define IPSMSG2(psz, hres) TraceMsg(TF_SHDCONTROL, "she TR-IPS::%s %x", psz, hres)
  6. #define IPSMSG3(pszName, psz) TraceMsg(TF_SHDCONTROL, "she TR-IPS::%s:%s called", pszName,psz)
  7. #define IOOMSG(psz) TraceMsg(TF_SHDCONTROL, "she TR-IOO::%s called", psz)
  8. #define IOOMSGX(psz, hres) TraceMsg(TF_SHDCONTROL, "she TR-IOO::%s returning %x", psz, hres)
  9. #define IOOMSG2(psz, i) TraceMsg(TF_SHDCONTROL, "she TR-IOO::%s called with (%d)", psz, i)
  10. #define IOOMSG3(psz, i, j) TraceMsg(TF_SHDCONTROL, "she TR-IOO::%s called with (%d, %d)", psz, i, j)
  11. #define IVOMSG(psz) TraceMsg(TF_SHDCONTROL, "she TR-IVO::%s called", psz)
  12. #define IVOMSG2(psz, i) TraceMsg(TF_SHDCONTROL, "she TR-IVO::%s called with (%d)", psz, i)
  13. #define IVOMSG3(psz, i, j) TraceMsg(TF_SHDCONTROL, "she TR-IVO::%s with (%d, %d)", psz, i, j)
  14. #define CCDMSG(psz, punk) TraceMsg(TF_SHDCONTROL, "she TR-CSV::%s called punk=%x", psz, punk)
  15. #define IDTMSG(psz) TraceMsg(TF_SHDCONTROL, "she TR-IDT::%s called", psz)
  16. #define IDTMSG2(psz, i) TraceMsg(TF_SHDCONTROL, "she TR-IDT::%s called with %d", psz, i)
  17. #define IDTMSG3(psz, x) TraceMsg(TF_SHDCONTROL, "she TR-IDT::%s %x", psz, x)
  18. #define IDTMSG4(psz, i, j) TraceMsg(TF_SHDCONTROL, "she TR-IDT::%s called with %x,%x", psz, i, j)
  19. #define IIPMSG(psz) TraceMsg(TF_SHDCONTROL, "she TR-IOIPO::%s called", psz)
  20. #define IIAMSG(psz) TraceMsg(TF_SHDCONTROL, "she TR-IOIPAO::%s called", psz)
  21. #define IEVMSG(psz, i, j, ps) TraceMsg(TF_SHDCONTROL, "she TR-IEV::%s called celt=%d, _iCur=%d, %x", psz, i, j, ps)
  22. const TCHAR c_szShellEmbedding[] = TEXT("Shell Embedding");
  23. //
  24. // A special lindex value to be passed to ::Draw member indicating
  25. // that it is an internal call from ::GetData
  26. //
  27. #define LINDEX_INTERNAL 12345
  28. // REVIEW: We may want to use the functions in UTIL.C -- they look more efficient...
  29. //
  30. //=========================================================================
  31. // Helper functions
  32. //=========================================================================
  33. #define HIM_PER_IN 2540
  34. int g_iXppli = 0;
  35. int g_iYppli = 0;
  36. void GetLogPixels()
  37. {
  38. HDC hdc = GetDC(NULL);
  39. if (hdc)
  40. {
  41. g_iXppli = GetDeviceCaps(hdc, LOGPIXELSX);
  42. g_iYppli = GetDeviceCaps(hdc, LOGPIXELSY);
  43. ReleaseDC(NULL, hdc);
  44. }
  45. }
  46. // Scalar conversion of MM_HIMETRIC to MM_TEXT
  47. void MetricToPixels(SIZEL* psize)
  48. {
  49. ASSERT(g_iXppli);
  50. psize->cx = MulDiv(psize->cx, g_iXppli, HIM_PER_IN);
  51. psize->cy = MulDiv(psize->cy, g_iYppli, HIM_PER_IN);
  52. }
  53. // Scalar conversion of MM_TEXT to MM_HIMETRIC
  54. void PixelsToMetric(SIZEL* psize)
  55. {
  56. ASSERT(g_iYppli);
  57. psize->cx = MulDiv(psize->cx, HIM_PER_IN, g_iXppli);
  58. psize->cy = MulDiv(psize->cy, HIM_PER_IN, g_iYppli);
  59. }
  60. //=========================================================================
  61. // CShellEmbedding implementaiton
  62. //=========================================================================
  63. HRESULT CShellEmbedding::v_InternalQueryInterface(REFIID riid, LPVOID * ppvObj)
  64. {
  65. static const QITAB qit[] = {
  66. QITABENT(CShellEmbedding, IPersist),
  67. QITABENT(CShellEmbedding, IOleObject),
  68. QITABENT(CShellEmbedding, IViewObject2),
  69. QITABENTMULTI(CShellEmbedding, IViewObject, IViewObject2),
  70. QITABENT(CShellEmbedding, IDataObject),
  71. QITABENT(CShellEmbedding, IOleInPlaceObject),
  72. QITABENTMULTI(CShellEmbedding, IOleWindow, IOleInPlaceObject),
  73. QITABENT(CShellEmbedding, IOleInPlaceActiveObject),
  74. QITABENT(CShellEmbedding, IInternetSecurityMgrSite),
  75. { 0 },
  76. };
  77. return QISearch(this, qit, riid, ppvObj);
  78. }
  79. CShellEmbedding::CShellEmbedding(IUnknown* punkOuter, LPCOBJECTINFO poi, const OLEVERB* pverbs)
  80. : _pverbs(pverbs)
  81. , _nActivate(OC_DEACTIVE)
  82. , CAggregatedUnknown(punkOuter)
  83. {
  84. TraceMsg(TF_SHDCONTROL, "ctor CShellEmbedding %x", this);
  85. DllAddRef();
  86. _RegisterWindowClass();
  87. _pObjectInfo = poi;
  88. _size.cx = 50;
  89. _size.cy = 20;
  90. // make sure some globals are set
  91. GetLogPixels();
  92. // let our logical size match our physical size
  93. _sizeHIM = _size;
  94. PixelsToMetric(&_sizeHIM);
  95. }
  96. CShellEmbedding::~CShellEmbedding()
  97. {
  98. ASSERT(_hwnd==NULL);
  99. // IE v 4.1 bug 44541. In an Office 97 user form, we were seeing this destructor get entered
  100. // with a non-null hwnd, which would cause a fault the next time the hwnd received a message.
  101. //
  102. if (_hwnd)
  103. {
  104. DestroyWindow(_hwnd);
  105. _hwnd = NULL;
  106. }
  107. ASSERT(_hwndChild==NULL);
  108. ASSERT(_pcli==NULL);
  109. ASSERT(_pipsite==NULL);
  110. ASSERT(_pipframe==NULL);
  111. ASSERT(_pipui==NULL);
  112. //
  113. // WARNING: Don't call any of virtual functions of this object
  114. // itself for clean-up purpose. The Vtable is alreadly adjusted
  115. // and we won't be able to perform any full clean up. Do it
  116. // right before you delete in CShellEmbedding::CSVInner::Release.
  117. //
  118. TraceMsg(TF_SHDCONTROL, "dtor CShellEmbedding %x", this);
  119. // Warning: if the client site has not been released do not release the advise
  120. // object as some applications like VC5 will fault on this...
  121. if (_padv) {
  122. _padv->OnClose();
  123. if (!_pcli)
  124. ATOMICRELEASE(_padv);
  125. }
  126. if (!_pcli)
  127. {
  128. ATOMICRELEASE(_pdah);
  129. ATOMICRELEASE(_poah);
  130. }
  131. ATOMICRELEASE(_pstg);
  132. ATOMICRELEASE(_pcliHold);
  133. DllRelease();
  134. }
  135. // **************** IPersist ****************
  136. HRESULT CShellEmbedding::GetClassID(CLSID *pClassID)
  137. {
  138. *pClassID = CLSIDOFOBJECT(this);
  139. return S_OK;
  140. }
  141. BOOL CShellEmbedding::_ShouldDraw(LONG lindex)
  142. {
  143. // Don't draw if the window is visible.
  144. return ! (_pipsite && lindex!=LINDEX_INTERNAL);
  145. }
  146. // **************** IViewObject ****************
  147. HRESULT CShellEmbedding::Draw(
  148. DWORD dwDrawAspect,
  149. LONG lindex,
  150. void *pvAspect,
  151. DVTARGETDEVICE *ptd,
  152. HDC hdcTargetDev,
  153. HDC hdcDraw,
  154. LPCRECTL lprcBounds,
  155. LPCRECTL lprcWBounds,
  156. BOOL ( __stdcall *pfnContinue )(ULONG_PTR dwContinue),
  157. ULONG_PTR dwContinue)
  158. {
  159. IVOMSG3(TEXT("Draw called"), lprcBounds->top, lprcBounds->bottom);
  160. // WARNING: this looks wrong to me -- I think we should always respond
  161. // to a Draw request, as the hdcDraw may not be the screen!
  162. //
  163. // Don't draw if the window is visible.
  164. if (!_ShouldDraw(lindex)) {
  165. return S_OK;
  166. }
  167. if (_hwnd) {
  168. int iDC = SaveDC(hdcDraw);
  169. RECTL rcBounds = *lprcBounds;
  170. ::LPtoDP(hdcDraw, (LPPOINT)&rcBounds, 2);
  171. IVOMSG3(TEXT("Draw DP=="), rcBounds.top, rcBounds.bottom);
  172. TraceMsg(TF_SHDCONTROL, "she Draw cx=%d cy=%d", rcBounds.right-rcBounds.left, rcBounds.bottom-rcBounds.top);
  173. SetMapMode(hdcDraw, MM_TEXT); // make it 1:1
  174. SetMapMode(hdcDraw, MM_ANISOTROPIC); // inherit call from MM_TEXT
  175. POINT pt;
  176. SetViewportOrgEx(hdcDraw, rcBounds.left, rcBounds.top, &pt);
  177. // APPCOMPAT: WordPad does a GetExtent to get the size and passes that in as lprcBounds
  178. // *without* doing a SetExtent, so when we resize larger (due to a BROWSE verb) _hwnd
  179. // is still the old size. So we IntersectClipRect to _hwnd but WordPad draws the border
  180. // to rcBounds. Ugly.
  181. RECT rc;
  182. GetClientRect(_hwnd, &rc);
  183. IntersectClipRect(hdcDraw, 0, 0, rc.right, rc.bottom);
  184. SendMessage(_hwnd, WM_PRINT, (WPARAM)hdcDraw,
  185. PRF_NONCLIENT|PRF_CLIENT|PRF_CHILDREN|PRF_ERASEBKGND);
  186. SetViewportOrgEx(hdcDraw, pt.x, pt.y, NULL);
  187. RestoreDC(hdcDraw, iDC);
  188. return S_OK;
  189. }
  190. return OLE_E_BLANK;
  191. }
  192. HRESULT CShellEmbedding::GetColorSet(
  193. DWORD dwDrawAspect,
  194. LONG lindex,
  195. void *pvAspect,
  196. DVTARGETDEVICE *ptd,
  197. HDC hicTargetDev,
  198. LOGPALETTE **ppColorSet)
  199. {
  200. IVOMSG(TEXT("GetColorSet"));
  201. return S_FALSE; // Indicating that the object doesn't care
  202. }
  203. HRESULT CShellEmbedding::Freeze(
  204. DWORD dwDrawAspect,
  205. LONG lindex,
  206. void *pvAspect,
  207. DWORD *pdwFreeze)
  208. {
  209. IVOMSG(TEXT("Freeze"));
  210. *pdwFreeze = 0;
  211. return S_OK;
  212. }
  213. HRESULT CShellEmbedding::Unfreeze(DWORD dwFreeze)
  214. {
  215. IVOMSG(TEXT("Unfreeze"));
  216. return S_OK;
  217. }
  218. HRESULT CShellEmbedding::SetAdvise(
  219. DWORD aspects,
  220. DWORD advf,
  221. IAdviseSink *pAdvSink)
  222. {
  223. IVOMSG2(TEXT("SetAdvise"), pAdvSink);
  224. if (advf & ~(ADVF_ONLYONCE | ADVF_PRIMEFIRST))
  225. return E_INVALIDARG;
  226. if (pAdvSink != _padv)
  227. {
  228. ATOMICRELEASE(_padv);
  229. if (pAdvSink)
  230. {
  231. _padv = pAdvSink;
  232. _padv->AddRef();
  233. }
  234. }
  235. _asp = aspects;
  236. _advf = advf;
  237. if (advf & ADVF_PRIMEFIRST)
  238. _SendAdvise(OBJECTCODE_VIEWCHANGED);
  239. return S_OK;
  240. }
  241. HRESULT CShellEmbedding::GetAdvise(
  242. DWORD *pAspects,
  243. DWORD *pAdvf,
  244. IAdviseSink **ppAdvSink)
  245. {
  246. IVOMSG(TEXT("GetAdvise"));
  247. if (pAspects) {
  248. *pAspects = _asp;
  249. }
  250. if (pAdvf) {
  251. *pAdvf = _advf;
  252. }
  253. if (ppAdvSink) {
  254. *ppAdvSink = _padv;
  255. if (_padv) {
  256. _padv->AddRef();
  257. }
  258. }
  259. return S_OK;
  260. }
  261. // **************** IViewObject2 ****************
  262. HRESULT CShellEmbedding::GetExtent(
  263. DWORD dwDrawAspect,
  264. LONG lindex,
  265. DVTARGETDEVICE *ptd,
  266. LPSIZEL lpsizel)
  267. {
  268. TraceMsg(TF_SHDCONTROL, "she GetExtent cx=%d cy=%d", _size.cx, _size.cy);
  269. lpsizel->cx = _size.cx;
  270. lpsizel->cy = _size.cy;
  271. PixelsToMetric(lpsizel);
  272. return S_OK;
  273. }
  274. //
  275. // **************** IOleObject ****************
  276. //
  277. void CShellEmbedding::_OnSetClientSite()
  278. {
  279. if (_pcli)
  280. {
  281. IOleInPlaceSite* pipsite;
  282. if (SUCCEEDED(_pcli->QueryInterface(IID_IOleInPlaceSite, (LPVOID*)&pipsite)))
  283. {
  284. _CreateWindowOrSetParent(pipsite);
  285. pipsite->Release();
  286. }
  287. }
  288. else if (_hwnd)
  289. {
  290. DestroyWindow(_hwnd);
  291. _hwnd = NULL;
  292. }
  293. }
  294. HRESULT CShellEmbedding::SetClientSite(IOleClientSite *pClientSite)
  295. {
  296. IOOMSG2(TEXT("SetClientSite"), pClientSite);
  297. // If I have a client site on hold, get rid of it.
  298. //
  299. ATOMICRELEASE(_pcliHold);
  300. if (_pcli == pClientSite)
  301. {
  302. // mshtml is hitting their initialization code twice
  303. // no need for us to do anything here.
  304. }
  305. else
  306. {
  307. ATOMICRELEASE(_pcli);
  308. ATOMICRELEASE(_pipsite);
  309. ATOMICRELEASE(_pipframe);
  310. ATOMICRELEASE(_pipui);
  311. _pcli = pClientSite;
  312. if (_pcli)
  313. _pcli->AddRef();
  314. _OnSetClientSite();
  315. }
  316. return S_OK;
  317. }
  318. //
  319. // This function create _hwnd (the parent of this embedding) if it not
  320. // created yet. Otherwise, it simply SetParent appropriately.
  321. //
  322. // NOTE: When this object is embedded in PowerPoint 95, the first
  323. // CreateWindowEx fails when this function if called from SetClientSite
  324. // for some unknown reason.
  325. // It, however, succeeds when it is called from DoVerb. We should find
  326. // it out.
  327. //
  328. HRESULT CShellEmbedding::_CreateWindowOrSetParent(IOleWindow* pwin)
  329. {
  330. HWND hwndParent = NULL;
  331. HRESULT hres = S_OK;
  332. //
  333. // NOTES: Unlike IE3.0, we don't fail even if pwin->GetWindow fails.
  334. // It allows Trident to SetClientSite (and Navigate) before they
  335. // are In-place Activated. In that case (hwndParent==NULL), we
  336. // create a top-level window hidden and use it for navigation.
  337. // When we are being InPlaceActivated, we hit this function again
  338. // and set the parent (and window styles) correctly. Notice that
  339. // we need to set WS_POPUP to avoid the Window Manager automatically
  340. // add other random styles for verlapped window.
  341. //
  342. pwin->GetWindow(&hwndParent);
  343. #ifdef DEBUG
  344. // Pretend that GetWindow failed here.
  345. if (_hwnd==NULL && (g_dwPrototype & 0x00000200))
  346. {
  347. TraceMsg(DM_TRACE, "CSE::_CreateWindowOrSetParent pretend unsuccessful GetWindow");
  348. hwndParent = NULL;
  349. }
  350. #endif
  351. _fOpen = TRUE;
  352. if (_hwnd)
  353. {
  354. SetParentHwnd(_hwnd, hwndParent);
  355. }
  356. else
  357. {
  358. _hwnd = SHNoFusionCreateWindowEx(
  359. WS_EX_WINDOWEDGE,
  360. c_szShellEmbedding, NULL,
  361. (hwndParent ?
  362. (WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_TABSTOP)
  363. : (WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_TABSTOP)),
  364. 0, 0, _rcPos.right - _rcPos.left, _rcPos.bottom - _rcPos.top,
  365. hwndParent,
  366. (HMENU)0,
  367. HINST_THISDLL,
  368. (LPVOID)SAFECAST(this, CImpWndProc*));
  369. if (!_hwnd)
  370. {
  371. hres = E_FAIL;
  372. TraceMsg(TF_SHDCONTROL, "sdv TR-IOO::_CreateWindowOrSetParent CreateWindowEx failed (%d)", GetLastError());
  373. }
  374. }
  375. return hres;
  376. }
  377. HRESULT CShellEmbedding::GetClientSite(IOleClientSite **ppClientSite)
  378. {
  379. IOOMSG(TEXT("GetClientSite"));
  380. *ppClientSite = _pcli;
  381. if (_pcli) {
  382. _pcli->AddRef();
  383. }
  384. return S_OK;
  385. }
  386. HRESULT CShellEmbedding::SetHostNames(
  387. LPCOLESTR szContainerApp,
  388. LPCOLESTR szContainerObj)
  389. {
  390. IOOMSG(TEXT("SetHostNames"));
  391. // We are not interested in host name
  392. return S_OK;
  393. }
  394. // A container application calls IOleObject::Close when it wants
  395. // to move the object from a running to a loaded state. Following
  396. // such a call, the object still appears in its container but is
  397. // not open for editing. Calling IOleObject::Close on an object
  398. // that is loaded but not running has no effect.
  399. //
  400. HRESULT CShellEmbedding::Close(DWORD dwSaveOption)
  401. {
  402. IOOMSG2(TEXT("Close"), dwSaveOption);
  403. // Change the state of object back to TEXT("loaded") state.
  404. BOOL fSave = FALSE;
  405. if (_fDirty &&
  406. ((OLECLOSE_SAVEIFDIRTY==dwSaveOption)
  407. || (dwSaveOption==OLECLOSE_PROMPTSAVE))) {
  408. fSave = TRUE;
  409. }
  410. if (fSave) {
  411. _SendAdvise(OBJECTCODE_SAVEOBJECT);
  412. _SendAdvise(OBJECTCODE_SAVED);
  413. }
  414. _SendAdvise(OBJECTCODE_CLOSED);
  415. _fOpen = FALSE;
  416. // "loaded but not running" is confusing wording... If you look
  417. // at the OLEIVERB_HIDE comment in _OnActivateChange, it mentions
  418. // that OLEIVERB_HIDE puts it in the state "just after loading"
  419. // and puts us in OC_DEACTIVE state. Let's do that here as well.
  420. //
  421. // it just came to my awareness that OCs UIDeactivate,
  422. // not IPDeactivate...
  423. _DoActivateChange(NULL, OC_DEACTIVE, FALSE);
  424. // It seems like some containers (Trident frame set) don't
  425. // do a SetClientSite(NULL) on us, so do it here. Old code here
  426. // did a DestroyWindow(_hwnd), which SetClientSite(NULL) will do.
  427. // NOTE: VB does call SetClientSite, but they do it after Close.
  428. // If we already have one on hold, release it.
  429. //
  430. ATOMICRELEASE(_pcliHold);
  431. // Hold onto our client site. We may need it if we're DoVerbed, as Office tends to do.
  432. //
  433. IOleClientSite *pOleClientSite = _pcli;
  434. if (pOleClientSite)
  435. {
  436. pOleClientSite->AddRef();
  437. }
  438. SetClientSite(NULL);
  439. _pcliHold = pOleClientSite;
  440. return S_OK;
  441. }
  442. HRESULT CShellEmbedding::SetMoniker(
  443. DWORD dwWhichMoniker,
  444. IMoniker *pmk)
  445. {
  446. IOOMSG(TEXT("SetMoniker"));
  447. // We are not interested in moniker.
  448. return S_OK;
  449. }
  450. HRESULT CShellEmbedding::GetMoniker(
  451. DWORD dwAssign,
  452. DWORD dwWhichMoniker,
  453. IMoniker **ppmk)
  454. {
  455. IOOMSG(TEXT("GetMoniker"));
  456. return E_NOTIMPL;
  457. }
  458. HRESULT CShellEmbedding::InitFromData(
  459. IDataObject *pDataObject,
  460. BOOL fCreation,
  461. DWORD dwReserved)
  462. {
  463. IOOMSG(TEXT("InitFromData"));
  464. // LATER: We may want to implement this later.
  465. return E_FAIL;
  466. }
  467. HRESULT CShellEmbedding::GetClipboardData(
  468. DWORD dwReserved,
  469. IDataObject **ppDataObject)
  470. {
  471. IOOMSG(TEXT("GetClipboardData"));
  472. return E_FAIL;
  473. }
  474. HRESULT CShellEmbedding::DoVerb(
  475. LONG iVerb,
  476. LPMSG lpmsg,
  477. IOleClientSite *pActiveSite,
  478. LONG lindex,
  479. HWND hwndParent,
  480. LPCRECT lprcPosRect)
  481. {
  482. IOOMSG2(TEXT("DoVerb"), iVerb);
  483. HRESULT hres = S_OK;
  484. // If I don't have a client site, but I have one on "hold", I need to set it up again.
  485. //
  486. if (_pcli == NULL
  487. && _pcliHold)
  488. {
  489. IOleClientSite *pOleClientSite = _pcliHold;
  490. _pcliHold = NULL;
  491. SetClientSite(pOleClientSite);
  492. pOleClientSite->Release();
  493. }
  494. switch(iVerb)
  495. {
  496. case OLEIVERB_HIDE:
  497. hres = _DoActivateChange(NULL, OC_DEACTIVE, FALSE);
  498. break;
  499. case OLEIVERB_OPEN:
  500. hres = E_FAIL;
  501. break;
  502. case OLEIVERB_PRIMARY:
  503. case OLEIVERB_SHOW:
  504. if (_pipsite) {
  505. return S_OK;
  506. }
  507. // Fall through
  508. case OLEIVERB_UIACTIVATE:
  509. hres = _DoActivateChange(pActiveSite, OC_UIACTIVE, TRUE); //TRUE => We want to force UIACTIVE even if we are already active.
  510. break;
  511. case OLEIVERB_INPLACEACTIVATE:
  512. hres = _DoActivateChange(pActiveSite, OC_INPLACEACTIVE, FALSE);
  513. break;
  514. default:
  515. hres = E_FAIL; // OLEOBJ_S_INVALDVERB;
  516. break;
  517. }
  518. IOOMSGX(TEXT("DoVerb"), hres);
  519. return hres;
  520. }
  521. //
  522. // fForce == TRUE indicates that we need to call _OnActivateChange even if we
  523. // are already in OC_UIACITVE state.
  524. //
  525. HRESULT CShellEmbedding::_DoActivateChange(IOleClientSite* pActiveSite, UINT uState, BOOL fForce)
  526. {
  527. if (uState == _nActivate)
  528. {
  529. // in general, we have nothing to do if we're already in
  530. // the correct state. HOWEVER, OLEIVERB_UIACTIVATE is supposed
  531. // to set focus if we (or our children?) don't currently have it.
  532. // Fall into _OnActivateChange so CWebBrowserOC can tell the
  533. // base browser to go uiactive.
  534. //
  535. if ((uState != OC_UIACTIVE) || !fForce)
  536. return S_OK;
  537. }
  538. #define STATETOSTRING(n) (n==OC_DEACTIVE ? TEXT("OC_DEACTIVE") : (n==OC_INPLACEACTIVE ? TEXT("OC_INPLACEACTIVE") : (n== OC_UIACTIVE ? TEXT("OC_UIACTIVE") : TEXT("ERROR"))))
  539. TraceMsg(TF_SHDCONTROL, "she _DoActivateChange from %s to %s", STATETOSTRING(_nActivate), STATETOSTRING(uState));
  540. return _OnActivateChange(pActiveSite, uState);
  541. }
  542. HRESULT CShellEmbedding::_OnActivateChange(IOleClientSite* pActiveSite, UINT uState)
  543. {
  544. if (uState != _nActivate)
  545. {
  546. // mark us in our new state immediately. this avoids recursion death with bad containers (ipstool)
  547. UINT uOldState = _nActivate;
  548. _nActivate = uState;
  549. if (uOldState == OC_DEACTIVE) // going from deactive to IP or UI active
  550. {
  551. if (pActiveSite==NULL)
  552. {
  553. _nActivate = uOldState;
  554. return E_INVALIDARG;
  555. }
  556. ASSERT(!_pipsite); // always true, so why check below?
  557. if (!_pipsite)
  558. {
  559. HRESULT hres = pActiveSite->QueryInterface(IID_IOleInPlaceSite, (LPVOID*)&_pipsite);
  560. if (FAILED(hres))
  561. {
  562. _nActivate = uOldState;
  563. return hres;
  564. }
  565. hres = _pipsite->CanInPlaceActivate();
  566. if (hres != S_OK) {
  567. ATOMICRELEASE(_pipsite);
  568. TraceMsg(TF_SHDCONTROL, "she - CanInPlaceActivate returned %x", hres);
  569. _nActivate = uOldState;
  570. return E_FAIL;
  571. }
  572. _OnInPlaceActivate(); // do it
  573. }
  574. }
  575. else if (uOldState == OC_UIACTIVE) // going from UIActive to IPActive or deactive
  576. {
  577. _OnUIDeactivate();
  578. }
  579. if (uState == OC_UIACTIVE) // going to UIActive
  580. {
  581. _OnUIActivate();
  582. }
  583. else if (uState == OC_DEACTIVE) // going to Deactive
  584. {
  585. // We fail creation (OLEIVERB_PRIMARY, OLEIVERB_SHOW,
  586. // OLEIVERB_UIACTIVATE, or OLEIVERB_INPLACEACTIVATE) if we don't
  587. // get a pipsite, so we should never hit this case.
  588. ASSERT(_pipsite);
  589. // OLEIVERB_HIDE should ... return it to the visual state just after
  590. // initial creation or reloading, before OLEIVERB_SHOW or OLEIVERB_OPEN
  591. // is sent. Which is what _InPlaceDeactivate does. What's the point of this?
  592. // htmlobj calls OLEIVERB_HIDE and then ::InPlaceDeactivate
  593. _OnInPlaceDeactivate();
  594. }
  595. }
  596. return S_OK;
  597. }
  598. // move from de-active to in-place-active
  599. void CShellEmbedding::_OnInPlaceActivate()
  600. {
  601. //
  602. // Set the appropriate parent window.
  603. //
  604. _CreateWindowOrSetParent(_pipsite);
  605. _pipsite->OnInPlaceActivate();
  606. ASSERT(_pipframe == NULL);
  607. ASSERT(_pipui == NULL);
  608. _finfo.cb = sizeof(OLEINPLACEFRAMEINFO);
  609. _pipsite->GetWindowContext(&_pipframe, &_pipui,
  610. &_rcPos, &_rcClip, &_finfo);
  611. TraceMsg(TF_SHDCONTROL, "she::_OnInPlaceActivate x=%d y=%d cx=%d cy=%d (_cx=%d _cy=%d)", _rcPos.left, _rcPos.top, _rcPos.right-_rcPos.left, _rcPos.bottom-_rcPos.top, _size.cx, _size.cy);
  612. SetWindowPos(_hwnd, 0,
  613. _rcPos.left, _rcPos.top,
  614. _rcPos.right-_rcPos.left,
  615. _rcPos.bottom-_rcPos.top,
  616. SWP_SHOWWINDOW | SWP_NOZORDER);
  617. _SendAdvise(OBJECTCODE_SHOWOBJECT); // just like OLE 2nd ed (p.1074)
  618. }
  619. // Move from in-place-active to de-active
  620. void CShellEmbedding::_OnInPlaceDeactivate(void)
  621. {
  622. if (_hwnd) {
  623. ShowWindow(_hwnd, SW_HIDE);
  624. // re-parent our _hwnd... when we're not active we can't rely on
  625. // what our parent window is doing. The container can even destroy it!
  626. //
  627. // FEATURE: the standard thing to do here is DESTROY our HWND and
  628. // recreate it if/when we are reactivated. This may break our hosted
  629. // IShellView and draw code. Investigate this.
  630. //
  631. // APPCOMPAT: this has been taken out by CDturner, MikeSH assures me we don't need it, and
  632. // this is causing our app to lose activation and regain it which causes the
  633. // palette to flash on 256 colour machines...y
  634. // SetParentHwnd(_hwnd, NULL);
  635. }
  636. if (_pipsite) {
  637. _pipsite->OnInPlaceDeactivate();
  638. ATOMICRELEASE(_pipsite);
  639. }
  640. ATOMICRELEASE(_pipframe);
  641. ATOMICRELEASE(_pipui);
  642. //
  643. // We need to tell the container to update the cached metafile, if any.
  644. //
  645. _SendAdvise(OBJECTCODE_DATACHANGED);
  646. }
  647. // move from in-place-active to ui-active
  648. void CShellEmbedding::_OnUIActivate(void)
  649. {
  650. if (_pipsite) {
  651. _pipsite->OnUIActivate();
  652. }
  653. //
  654. // HACK: When we are in Excel, _pipui->SetActiveObject sets the focus
  655. // to us (for some unknown reason -- trying to be nice?). Since _hwnd
  656. // simply forward the focus to the _hwndChild, setting focus to _hwnd
  657. // twice causes this:
  658. //
  659. // 1. SetFocus(_hwnd) by us (if we call SetFocus(_hwnd))
  660. // 2. SetFocus(_hwndChild) in _hwnd's wndproc
  661. // 3. SetFocus(_hwnd) by Excel
  662. // 4. SetFocus(_hwndChild) in _hwnd's wndproc
  663. //
  664. // If _hwndChild is a control, it notifies to the parent that it
  665. // lost the focus. Then, we think "oh, we lost the focus. We should
  666. // deactivate this object". To avoid it, we don't call SetFocus before
  667. // we call _pipui->SetActiveObject and do some tricky thing below.
  668. //
  669. // SetFocus(_hwnd);
  670. //
  671. // RDuke suggest us to change the second parameter to NULL (instead of
  672. // "FOO" in IE3, but we don't know the side effect of it. I'm changing
  673. // it to "item" for IE4. (SatoNa)
  674. //
  675. if (_pipframe) {
  676. _pipframe->SetActiveObject(SAFECAST(this, IOleInPlaceActiveObject*), L"item");
  677. }
  678. if (_pipui) {
  679. _pipui->SetActiveObject(SAFECAST(this, IOleInPlaceActiveObject*), L"item");
  680. }
  681. //
  682. // We don't have any menu, so tell the container to use its own menu.
  683. //
  684. if (_pipframe) {
  685. _pipframe->SetMenu(NULL, NULL, _hwnd);
  686. }
  687. // Find-out if one of our child window has the input focus.
  688. for (HWND hwndFocus = GetFocus();
  689. hwndFocus && hwndFocus!=_hwnd;
  690. hwndFocus = GetParent(hwndFocus))
  691. {}
  692. // If not, set it.
  693. if (hwndFocus==NULL) {
  694. SetFocus(_hwnd);
  695. }
  696. // If this UIActivate came from below (i.e., our hosted DocObject), then we need to inform
  697. // our container. We do this by calling IOleControlSite::OnFocus. VB5 and Visual FoxPro
  698. // (at least) rely on this call being made for proper focus handling.
  699. //
  700. IUnknown_OnFocusOCS(_pcli, TRUE);
  701. }
  702. void CShellEmbedding::_OnUIDeactivate(void)
  703. {
  704. //
  705. // We don't have any shared menu or tools to clean up.
  706. //
  707. if (_pipframe) {
  708. _pipframe->SetActiveObject(NULL, NULL);
  709. }
  710. if (_pipui) {
  711. _pipui->SetActiveObject(NULL, NULL);
  712. }
  713. if (_pipsite) {
  714. _pipsite->OnUIDeactivate(FALSE);
  715. }
  716. // If this UIDeactivate came from below (i.e., our hosted DocObject), then we need to inform
  717. // our container. We do this by calling IOleControlSite::OnFocus. VB5 and Visual FoxPro
  718. // (at least) rely on this call being made for proper focus handling.
  719. //
  720. IUnknown_OnFocusOCS(_pcli, FALSE);
  721. }
  722. HRESULT CShellEmbedding::EnumVerbs(
  723. IEnumOLEVERB **ppEnumOleVerb)
  724. {
  725. IOOMSG(TEXT("EnumVerbs"));
  726. *ppEnumOleVerb = new CSVVerb(_pverbs);
  727. return *ppEnumOleVerb ? S_OK : E_OUTOFMEMORY;
  728. }
  729. HRESULT CShellEmbedding::Update( void)
  730. {
  731. IOOMSG(TEXT("Update"));
  732. // Always up-to-date
  733. return S_OK;
  734. }
  735. HRESULT CShellEmbedding::IsUpToDate( void)
  736. {
  737. IOOMSG(TEXT("IsUpToDate"));
  738. // Always up-to-date
  739. return S_OK;
  740. }
  741. HRESULT CShellEmbedding::GetUserClassID(CLSID *pClsid)
  742. {
  743. IOOMSG(TEXT("GetUserClassID"));
  744. return GetClassID(pClsid);
  745. }
  746. HRESULT CShellEmbedding::GetUserType(DWORD dwFormOfType, LPOLESTR *pszUserType)
  747. {
  748. return OleRegGetUserType(CLSIDOFOBJECT(this), dwFormOfType, pszUserType);
  749. }
  750. HRESULT CShellEmbedding::SetExtent(DWORD dwDrawAspect, SIZEL *psizel)
  751. {
  752. // SetExtent sets the LOGICAL size of an object. SetObjectRects determins
  753. // the size of the object on the screen. If we cared about zooming, we'd
  754. // keep track of this and do some sort of scaling. But we don't.
  755. // We still need to remember this value so we return it on GetExtent.
  756. //
  757. _sizeHIM = *psizel;
  758. // HOWEVER, IE3 shipped a SetExtent that changed the physical size of the
  759. // object. For compat (AOL uses SetExtent to change the size), if we're the
  760. // old WebBrowser, continue to resize.
  761. //
  762. if (_pObjectInfo->pclsid == &CLSID_WebBrowser_V1)
  763. {
  764. RECT rc;
  765. HDC hdc;
  766. int mmOld;
  767. POINT pt;
  768. // Make sure a container doesn't do anything strange like
  769. // make us negative size
  770. //
  771. // APPCOMPAT: this breaks Trident because it sizes us negative
  772. // and we fail that sizing and they get confused...
  773. //
  774. //ASSERT(psizel->cx >= 0 && psizel->cy <= 0);
  775. //if (psizel->cx < 0 || psizel->cy > 0)
  776. // return E_FAIL;
  777. // We only support DVASPECT_CONTENT
  778. if (dwDrawAspect != DVASPECT_CONTENT)
  779. return E_NOTIMPL;
  780. // Map this to a SetObjectRects call -- that way superclasses
  781. // only have to watch one function for size changes
  782. //
  783. int nScaleFactorX = 1, nScaleFactorY = 1;
  784. pt.x = psizel->cx;
  785. pt.y = psizel->cy;
  786. hdc = GetDC(NULL);
  787. if (hdc)
  788. {
  789. mmOld = SetMapMode(hdc, MM_HIMETRIC);
  790. if (!g_fRunningOnNT) // if running on Win95
  791. {
  792. // Win95 doesn't like coordinates over 32K
  793. // SHRT_MIN and SHRT_MAX defined in $NT/public/sdk/inc/crt/limits.h
  794. while (pt.x > SHRT_MAX || pt.x < SHRT_MIN)
  795. {
  796. pt.x >>= 1;
  797. nScaleFactorX <<= 1;
  798. }
  799. while (pt.y > SHRT_MAX || pt.y < SHRT_MIN)
  800. {
  801. pt.y >>= 1;
  802. nScaleFactorY <<= 1;
  803. }
  804. }
  805. LPtoDP(hdc, &pt, 1);
  806. if (!g_fRunningOnNT)
  807. {
  808. pt.x *= nScaleFactorX;
  809. pt.y *= nScaleFactorY;
  810. }
  811. pt.y = -pt.y;
  812. SetMapMode(hdc, mmOld);
  813. ReleaseDC(NULL, hdc);
  814. }
  815. rc.left = _rcPos.left;
  816. rc.right = rc.left + pt.x;
  817. rc.top = _rcPos.top;
  818. rc.bottom = rc.top + pt.y;
  819. // Assume that using SetExtent adjusts both the pos and clip rects
  820. return SetObjectRects(&rc, NULL);
  821. }
  822. else
  823. {
  824. return S_OK;
  825. }
  826. }
  827. HRESULT CShellEmbedding::GetExtent(DWORD dwDrawAspect, SIZEL *psizel)
  828. {
  829. *psizel = _sizeHIM;
  830. return S_OK;
  831. }
  832. HRESULT CShellEmbedding::Advise(IAdviseSink *pAdvSink, DWORD *pdwConnection)
  833. {
  834. IOOMSG2(TEXT("Advise"), pAdvSink);
  835. HRESULT hr = E_INVALIDARG;
  836. if (!pdwConnection)
  837. return hr;
  838. *pdwConnection = NULL; // set out params to NULL
  839. if (!_poah)
  840. hr = ::CreateOleAdviseHolder(&_poah);
  841. else
  842. hr = NOERROR;
  843. if( SUCCEEDED(hr) )
  844. hr = _poah->Advise(pAdvSink, pdwConnection);
  845. return(hr);
  846. }
  847. HRESULT CShellEmbedding::Unadvise(DWORD dwConnection)
  848. {
  849. IOOMSG(TEXT("Unadvise"));
  850. HRESULT hr;
  851. if (!_poah)
  852. return(OLE_E_NOCONNECTION);
  853. hr = _poah->Unadvise(dwConnection);
  854. return(hr);
  855. }
  856. HRESULT CShellEmbedding::EnumAdvise(IEnumSTATDATA **ppenumAdvise)
  857. {
  858. IOOMSG(TEXT("EnumAdvise"));
  859. HRESULT hr;
  860. if (!ppenumAdvise)
  861. return(E_INVALIDARG);
  862. if (!_poah)
  863. {
  864. *ppenumAdvise = NULL;
  865. hr = S_OK;
  866. }
  867. else
  868. {
  869. hr = _poah->EnumAdvise(ppenumAdvise);
  870. }
  871. return(hr);
  872. }
  873. HRESULT CShellEmbedding::GetMiscStatus(DWORD dwAspect, DWORD *pdwStatus)
  874. {
  875. IOOMSG(TEXT("GetMiscStatus"));
  876. *pdwStatus = OLEMISCFLAGSOFCONTROL(this);
  877. return S_OK;
  878. }
  879. HRESULT CShellEmbedding::SetColorScheme(LOGPALETTE *pLogpal)
  880. {
  881. IOOMSG(TEXT("GetColorScheme"));
  882. return S_OK;
  883. }
  884. //
  885. // Helper function to create an HDC from an OLE DVTARGETDEVICE structure.
  886. // Very useful for metafile drawing, where the Metafile DC will be the
  887. // actual "draw to" dc, and the TargetDC, if present, will describe the ultimate output device.
  888. //
  889. HDC CShellEmbedding::_OleStdCreateDC(DVTARGETDEVICE *ptd)
  890. {
  891. HDC hdc = NULL;
  892. LPDEVNAMES lpDevNames = NULL;
  893. LPDEVMODEA lpDevMode = NULL;
  894. LPSTR lpszDriverName = NULL;
  895. LPSTR lpszDeviceName = NULL;
  896. LPSTR lpszPortName = NULL;
  897. if (ptd)
  898. {
  899. lpDevNames = (LPDEVNAMES) ptd;
  900. if (ptd->tdExtDevmodeOffset)
  901. {
  902. lpDevMode = (LPDEVMODEA) ( (LPSTR) ptd + ptd->tdExtDevmodeOffset);
  903. }
  904. lpszDriverName = (LPSTR) lpDevNames + ptd->tdDriverNameOffset;
  905. lpszDeviceName = (LPSTR) lpDevNames + ptd->tdDeviceNameOffset;
  906. lpszPortName = (LPSTR) lpDevNames + ptd->tdPortNameOffset;
  907. hdc = CreateDCA(lpszDriverName, lpszDeviceName, lpszPortName, lpDevMode);
  908. }
  909. return hdc;
  910. }
  911. // *** IDataObject ***
  912. //
  913. // WARNING:
  914. // It is well-known fact that Word and Excel (in Office95) does not call
  915. // IViewObject::Draw to draw embedding. Instead, they GetData(CF_METAFILEPICT).
  916. // If we don't offer it, Word will fail to embed it and Excel will draw
  917. // white rectangle when our object is deactivated. To be embedded correctly
  918. // on those apps, we must support CF_METAFILEPICT. (SatoNa)
  919. //
  920. HRESULT CShellEmbedding::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
  921. {
  922. IDTMSG4(TEXT("GetData"), pformatetcIn->cfFormat, pformatetcIn->tymed);
  923. HRESULT hres = DV_E_FORMATETC;
  924. HDC hdcTargetDevice = NULL;
  925. HENHMETAFILE hemf = NULL;
  926. // If a Target device is specified in the FORMATETC structure, create a DC for it.
  927. // This gets passed to CreateEnhMetaFile and IViewObject::Draw.
  928. //
  929. if (pformatetcIn->ptd)
  930. {
  931. hdcTargetDevice = _OleStdCreateDC(pformatetcIn->ptd);
  932. if (!hdcTargetDevice)
  933. {
  934. return E_FAIL;
  935. }
  936. }
  937. // Enhanced metafiles need special processing.
  938. //
  939. if (pformatetcIn->cfFormat == CF_ENHMETAFILE
  940. && (pformatetcIn->tymed & TYMED_ENHMF))
  941. {
  942. if (_hwnd)
  943. {
  944. RECTL rectBounds = { 0, 0, _sizeHIM.cx, _sizeHIM.cy };
  945. //
  946. // Call the "A" version since we're not passing in strings and
  947. // this needs to work on W95.
  948. HDC hdc = CreateEnhMetaFileA(hdcTargetDevice, NULL, (RECT*)&rectBounds, NULL);
  949. IDTMSG3(TEXT("_EnhMetafileFromWindow CreateEnhMetaFile returned"), hdc);
  950. if (hdc)
  951. {
  952. SetMapMode(hdc, MM_HIMETRIC);
  953. rectBounds.bottom = -rectBounds.bottom;
  954. Draw(DVASPECT_CONTENT, LINDEX_INTERNAL, NULL, pformatetcIn->ptd,
  955. hdcTargetDevice, hdc, &rectBounds, NULL, NULL, 0);
  956. hemf = CloseEnhMetaFile(hdc);
  957. IDTMSG3(TEXT("_EnhMetafileFromWindow CloseEnhMetaFile returned"), hemf);
  958. }
  959. }
  960. pmedium->hEnhMetaFile = hemf;
  961. if (pmedium->hEnhMetaFile)
  962. {
  963. pmedium->tymed = TYMED_ENHMF;
  964. pmedium->pUnkForRelease = NULL;
  965. hres = S_OK;
  966. }
  967. else
  968. {
  969. hres = E_FAIL;
  970. }
  971. }
  972. // Create a standard metafile
  973. //
  974. else if (pformatetcIn->cfFormat == CF_METAFILEPICT
  975. && (pformatetcIn->tymed & TYMED_MFPICT))
  976. {
  977. hres = E_OUTOFMEMORY;
  978. HGLOBAL hmem = GlobalAlloc(GPTR, sizeof(METAFILEPICT));
  979. if (hmem)
  980. {
  981. LPMETAFILEPICT pmf = (LPMETAFILEPICT) hmem;
  982. RECTL rectBounds = { 0, 0, _sizeHIM.cx, _sizeHIM.cy };
  983. HDC hdc = CreateMetaFile(NULL);
  984. if (hdc)
  985. {
  986. SetMapMode(hdc, MM_HIMETRIC);
  987. rectBounds.bottom = -rectBounds.bottom;
  988. SetWindowOrgEx(hdc, 0, 0, NULL);
  989. SetWindowExtEx(hdc, _sizeHIM.cx, _sizeHIM.cy, NULL);
  990. Draw(DVASPECT_CONTENT, LINDEX_INTERNAL, NULL,
  991. pformatetcIn->ptd, hdcTargetDevice,
  992. hdc, &rectBounds, &rectBounds, NULL, 0);
  993. pmf->hMF = CloseMetaFile(hdc);
  994. if (pmf->hMF)
  995. {
  996. pmf->mm = MM_ANISOTROPIC;
  997. pmf->xExt = _sizeHIM.cx;
  998. pmf->yExt = _sizeHIM.cy;
  999. TraceMsg(TF_SHDCONTROL, "sdv TR ::GetData (%d,%d)-(%d,%d)",
  1000. _size.cx, _size.cy, _sizeHIM.cx, _sizeHIM.cy);
  1001. pmedium->tymed = TYMED_MFPICT;
  1002. pmedium->hMetaFilePict = hmem;
  1003. pmedium->pUnkForRelease = NULL;
  1004. hres = S_OK;
  1005. }
  1006. }
  1007. if (FAILED(hres))
  1008. {
  1009. GlobalFree(hmem);
  1010. hmem = NULL;
  1011. }
  1012. }
  1013. }
  1014. if (hdcTargetDevice)
  1015. DeleteDC(hdcTargetDevice);
  1016. return hres;
  1017. }
  1018. HRESULT CShellEmbedding::GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium)
  1019. {
  1020. IDTMSG2(TEXT("GetDataHere"), pformatetc->cfFormat);
  1021. return E_NOTIMPL;
  1022. }
  1023. HRESULT CShellEmbedding::QueryGetData(FORMATETC *pformatetc)
  1024. {
  1025. IDTMSG2(TEXT("QueryGetData"), pformatetc->cfFormat);
  1026. HRESULT hres = S_FALSE;
  1027. if (pformatetc->cfFormat == CF_ENHMETAFILE
  1028. && (pformatetc->tymed & TYMED_ENHMF))
  1029. {
  1030. hres = S_OK;
  1031. }
  1032. else if (pformatetc->cfFormat == CF_METAFILEPICT
  1033. && (pformatetc->tymed & TYMED_MFPICT))
  1034. {
  1035. hres = S_OK;
  1036. }
  1037. return hres;
  1038. }
  1039. HRESULT CShellEmbedding::GetCanonicalFormatEtc(FORMATETC *pformatetcIn, FORMATETC *pformatetcOut)
  1040. {
  1041. IDTMSG2(TEXT("GetCanonicalFormatEtc"), pformatetcIn->cfFormat);
  1042. *pformatetcOut = *pformatetcIn;
  1043. return DATA_S_SAMEFORMATETC;
  1044. }
  1045. HRESULT CShellEmbedding::SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
  1046. {
  1047. IDTMSG(TEXT("SetData"));
  1048. return E_NOTIMPL;
  1049. }
  1050. HRESULT CShellEmbedding::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
  1051. {
  1052. IDTMSG(TEXT("EnumFormatEtc"));
  1053. return E_NOTIMPL;
  1054. }
  1055. HRESULT CShellEmbedding::DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
  1056. {
  1057. IDTMSG(TEXT("DAdvise"));
  1058. HRESULT hr = E_INVALIDARG;
  1059. if (!pdwConnection)
  1060. return hr;
  1061. *pdwConnection = NULL; // set out params to NULL
  1062. if (!_pdah)
  1063. hr = ::CreateDataAdviseHolder(&_pdah);
  1064. else
  1065. hr = NOERROR;
  1066. if( SUCCEEDED(hr) )
  1067. hr = _pdah->Advise(this, pformatetc, advf, pAdvSink, pdwConnection);
  1068. return(hr);
  1069. }
  1070. HRESULT CShellEmbedding::DUnadvise(DWORD dwConnection)
  1071. {
  1072. IDTMSG(TEXT("DUnadvise"));
  1073. HRESULT hr;
  1074. if (!_pdah)
  1075. return(OLE_E_NOCONNECTION);
  1076. hr = _pdah->Unadvise(dwConnection);
  1077. return(hr);
  1078. }
  1079. HRESULT CShellEmbedding::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
  1080. {
  1081. IDTMSG(TEXT("EnumDAdvise"));
  1082. HRESULT hr;
  1083. if (!ppenumAdvise)
  1084. return(E_INVALIDARG);
  1085. if (!_pdah)
  1086. {
  1087. *ppenumAdvise = NULL;
  1088. hr = S_OK;
  1089. }
  1090. else
  1091. {
  1092. hr = _pdah->EnumAdvise(ppenumAdvise);
  1093. }
  1094. return(hr);
  1095. }
  1096. // *** IOleWindow ***
  1097. HRESULT CShellEmbedding::GetWindow(HWND * lphwnd)
  1098. {
  1099. *lphwnd = _hwnd;
  1100. return S_OK;
  1101. }
  1102. HRESULT CShellEmbedding::ContextSensitiveHelp(BOOL fEnterMode)
  1103. {
  1104. return S_OK;
  1105. }
  1106. // *** IOleInPlaceObject ***
  1107. HRESULT CShellEmbedding::InPlaceDeactivate(void)
  1108. {
  1109. IIPMSG(TEXT("InPlaceDeactivate"));
  1110. return _DoActivateChange(NULL, OC_DEACTIVE, FALSE);
  1111. }
  1112. HRESULT CShellEmbedding::UIDeactivate(void)
  1113. {
  1114. IIPMSG(TEXT("UIDeactivate"));
  1115. return _DoActivateChange(NULL, OC_INPLACEACTIVE, FALSE);
  1116. }
  1117. HRESULT CShellEmbedding::SetObjectRects(LPCRECT lprcPosRect, LPCRECT lprcClipRect)
  1118. {
  1119. RECT rcVisible;
  1120. _rcPos = *lprcPosRect;
  1121. if (lprcClipRect)
  1122. {
  1123. _rcClip = *lprcClipRect;
  1124. }
  1125. else
  1126. {
  1127. _rcClip = _rcPos;
  1128. }
  1129. IntersectRect(&rcVisible, &_rcPos, &_rcClip);
  1130. if (EqualRect(&rcVisible, &_rcPos))
  1131. {
  1132. if (_fUsingWindowRgn)
  1133. {
  1134. SetWindowRgn(_hwnd, NULL, TRUE);
  1135. _fUsingWindowRgn = FALSE;
  1136. }
  1137. }
  1138. else
  1139. {
  1140. _fUsingWindowRgn = TRUE;
  1141. OffsetRect(&rcVisible, -_rcPos.left, -_rcPos.top);
  1142. SetWindowRgn(_hwnd,
  1143. CreateRectRgnIndirect(&rcVisible),
  1144. TRUE);
  1145. }
  1146. // We should consider this equivalent to a SetExtent as well...
  1147. // But only for valid sizes (html viewer gives us invalid
  1148. // sizes during it's reformat routine). Note: we still need
  1149. // the SetWindowPos because we may move off the window.
  1150. int cx = _rcPos.right - _rcPos.left;
  1151. int cy = _rcPos.bottom - _rcPos.top;
  1152. TraceMsg(TF_SHDCONTROL, "she SetObjectRects to x=%d y=%d cx=%d cy=%d (from cx=%d cy=%d)", _rcPos.left, _rcPos.top, cx, cy, _size.cx, _size.cy);
  1153. if (cx >= 0 && cy >= 0)
  1154. {
  1155. _size.cx = cx;
  1156. _size.cy = cy;
  1157. }
  1158. if (_hwnd)
  1159. {
  1160. SetWindowPos(_hwnd, NULL,
  1161. _rcPos.left, _rcPos.top,
  1162. _size.cx,
  1163. _size.cy,
  1164. SWP_NOZORDER | SWP_NOACTIVATE);
  1165. }
  1166. return S_OK;
  1167. }
  1168. HRESULT CShellEmbedding::ReactivateAndUndo(void)
  1169. {
  1170. IIPMSG(TEXT("ReactivateAndUndo"));
  1171. return INPLACE_E_NOTUNDOABLE;
  1172. }
  1173. // *** IOleInPlaceActiveObject ***
  1174. HRESULT CShellEmbedding::TranslateAccelerator(LPMSG lpmsg)
  1175. {
  1176. extern BOOL IsVK_TABCycler(MSG * pMsg);
  1177. HRESULT hr = S_FALSE;
  1178. // IIAMSG(TEXT("TranslateAccelerator"));
  1179. // We have no accelerators (other than TAB, which we must pass up
  1180. // to IOCS::TA to move on to the next control if any)
  1181. if (IsVK_TABCycler(lpmsg)) {
  1182. // NOTE: grfMods?
  1183. hr = IUnknown_TranslateAcceleratorOCS(_pcli, lpmsg, /*grfMods*/ 0);
  1184. }
  1185. return hr;
  1186. }
  1187. HRESULT CShellEmbedding::OnFrameWindowActivate(BOOL fActivate)
  1188. {
  1189. IIAMSG(TEXT("OnFrameWindowActivate"));
  1190. if (fActivate)
  1191. {
  1192. // our frame has been activated and we are the active object
  1193. // make sure we have focus
  1194. SetFocus(_hwnd);
  1195. }
  1196. return S_OK;
  1197. }
  1198. HRESULT CShellEmbedding::OnDocWindowActivate(BOOL fActivate)
  1199. {
  1200. IIAMSG(TEXT("OnDocWindowActivate"));
  1201. // We don't care
  1202. return S_OK;
  1203. }
  1204. HRESULT CShellEmbedding::ResizeBorder(LPCRECT prcBorder,
  1205. IOleInPlaceUIWindow *pUIWindow, BOOL fFrameWindow)
  1206. {
  1207. IIAMSG(TEXT("ResizeBorder"));
  1208. // We have no toolbars.
  1209. return S_OK;
  1210. }
  1211. HRESULT CShellEmbedding::EnableModeless(BOOL fEnable)
  1212. {
  1213. IIAMSG(TEXT("EnableModeless"));
  1214. // We have no dialogs.
  1215. return S_OK;
  1216. }
  1217. void CShellEmbedding::_RegisterWindowClass(void)
  1218. {
  1219. WNDCLASS wc = {0};
  1220. wc.style = CS_DBLCLKS;
  1221. wc.lpfnWndProc = s_WndProc ;
  1222. //wc.cbClsExtra = 0;
  1223. wc.cbWndExtra = SIZEOF(CShellEmbedding*) * 2;
  1224. wc.hInstance = g_hinst ;
  1225. //wc.hIcon = NULL ;
  1226. wc.hCursor = LoadCursor(NULL, IDC_ARROW) ;
  1227. wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  1228. //wc.lpszMenuName = NULL ;
  1229. wc.lpszClassName = c_szShellEmbedding;
  1230. SHRegisterClass(&wc);
  1231. }
  1232. LRESULT CShellEmbedding::v_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1233. {
  1234. switch(uMsg)
  1235. {
  1236. case WM_NCCREATE:
  1237. DWORD dwExStyles;
  1238. if ((dwExStyles = GetWindowLong(hwnd, GWL_EXSTYLE)) & RTL_MIRRORED_WINDOW)
  1239. {
  1240. SetWindowLong(hwnd, GWL_EXSTYLE, dwExStyles &~ RTL_MIRRORED_WINDOW);
  1241. }
  1242. goto DoDefault;
  1243. case WM_SETFOCUS:
  1244. if (_hwndChild)
  1245. SetFocus(_hwndChild);
  1246. // If this SETFOCUS came from TABbing onto the control, VB5 expects us to call its
  1247. // IOleControlSite::OnFocus. Then it will UIActivate us.
  1248. //
  1249. IUnknown_OnFocusOCS(_pcli, TRUE);
  1250. break;
  1251. case WM_KILLFOCUS:
  1252. // If this KILLFOCUS came from TABbing off the control, VB5 expects us to call its
  1253. // IOleControlSite::OnFocus. Then it will UIDeactivate us.
  1254. //
  1255. IUnknown_OnFocusOCS(_pcli, FALSE);
  1256. break;
  1257. case WM_WINDOWPOSCHANGED:
  1258. if (_hwndChild)
  1259. {
  1260. LPWINDOWPOS lpwp = (LPWINDOWPOS)lParam;
  1261. if (!(lpwp->flags & SWP_NOSIZE))
  1262. {
  1263. SetWindowPos(_hwndChild, NULL,
  1264. 0, 0, lpwp->cx, lpwp->cy,
  1265. SWP_NOZORDER|SWP_NOMOVE|SWP_NOACTIVATE|
  1266. (lpwp->flags&(SWP_NOREDRAW|SWP_NOCOPYBITS)));
  1267. }
  1268. }
  1269. goto DoDefault;
  1270. #ifdef DEBUG
  1271. // FEATURE: we'll never get this with ShellExplorer OC, but if we did,
  1272. // we'd need to call _DoActivateChange(OC_UIACTIVE, FALSE);
  1273. case WM_LBUTTONDOWN:
  1274. case WM_RBUTTONDOWN:
  1275. TraceMsg(TF_SHDCONTROL, "she ::v_WndProc(WM_xBUTTONDOWN) - we need to UIActivate");
  1276. goto DoDefault;
  1277. #endif
  1278. default:
  1279. DoDefault:
  1280. return DefWindowProc(_hwnd, uMsg, wParam, lParam);
  1281. }
  1282. return 0L;
  1283. }
  1284. void CShellEmbedding::_ViewChange(DWORD dwAspect, LONG lindex)
  1285. {
  1286. dwAspect &= _asp;
  1287. if (dwAspect && _padv)
  1288. {
  1289. IAdviseSink *padv = _padv;
  1290. IUnknown *punkRelease;
  1291. if (_advf & ADVF_ONLYONCE)
  1292. {
  1293. _padv = NULL;
  1294. punkRelease = padv;
  1295. }
  1296. else
  1297. punkRelease = NULL;
  1298. padv->OnViewChange(dwAspect, lindex);
  1299. if (punkRelease)
  1300. punkRelease->Release();
  1301. }
  1302. }
  1303. void CShellEmbedding::_SendAdvise(UINT uCode)
  1304. {
  1305. DWORD dwAspect=DVASPECT_CONTENT | DVASPECT_THUMBNAIL;
  1306. switch (uCode)
  1307. {
  1308. case OBJECTCODE_SAVED:
  1309. if (NULL!=_poah)
  1310. _poah->SendOnSave();
  1311. break;
  1312. case OBJECTCODE_CLOSED:
  1313. if (NULL!=_poah)
  1314. _poah->SendOnClose();
  1315. break;
  1316. case OBJECTCODE_RENAMED:
  1317. //Call IOleAdviseHolder::SendOnRename (later)
  1318. break;
  1319. case OBJECTCODE_SAVEOBJECT:
  1320. if (_fDirty && NULL!=_pcli)
  1321. _pcli->SaveObject();
  1322. _fDirty=FALSE;
  1323. break;
  1324. case OBJECTCODE_DATACHANGED:
  1325. // _fDirty=TRUE;
  1326. //No flags are necessary here.
  1327. if (NULL!=_pdah)
  1328. _pdah->SendOnDataChange(this, 0, 0);
  1329. //
  1330. // fall through
  1331. //
  1332. case OBJECTCODE_VIEWCHANGED:
  1333. _ViewChange(dwAspect, -1);
  1334. break;
  1335. case OBJECTCODE_SHOWOBJECT:
  1336. if (NULL!=_pcli)
  1337. _pcli->ShowObject();
  1338. break;
  1339. }
  1340. }
  1341. HRESULT CSVVerb::QueryInterface(REFIID riid, LPVOID * ppvObj)
  1342. {
  1343. if (IsEqualIID(riid, IID_IEnumOLEVERB) || IsEqualIID(riid, IID_IUnknown))
  1344. {
  1345. *ppvObj = SAFECAST(this, IEnumOLEVERB*);
  1346. }
  1347. else
  1348. {
  1349. *ppvObj = NULL;
  1350. return E_NOINTERFACE;
  1351. }
  1352. _cRef++;
  1353. return S_OK;
  1354. }
  1355. ULONG CSVVerb::AddRef()
  1356. {
  1357. return ++_cRef;
  1358. }
  1359. ULONG CSVVerb::Release()
  1360. {
  1361. if (--_cRef > 0) {
  1362. return _cRef;
  1363. }
  1364. delete this;
  1365. return 0;
  1366. }
  1367. HRESULT CSVVerb::Next(
  1368. /* [in] */ ULONG celt,
  1369. /* [out] */ LPOLEVERB rgelt,
  1370. /* [out] */ ULONG *pceltFetched)
  1371. {
  1372. HRESULT hres = S_FALSE;
  1373. ULONG celtFetched = 0;
  1374. // We need to enumerate the predefined verbs we support,
  1375. // or some containers will never call them. This list
  1376. // of verbs comes from our ::DoVerb function
  1377. //
  1378. static const OLEVERB rgVerbs[5] =
  1379. {
  1380. {OLEIVERB_PRIMARY, NULL, 0, 0},
  1381. {OLEIVERB_INPLACEACTIVATE, NULL, 0, 0},
  1382. {OLEIVERB_UIACTIVATE, NULL, 0, 0},
  1383. {OLEIVERB_SHOW, NULL, 0, 0},
  1384. {OLEIVERB_HIDE, NULL, 0, 0}
  1385. };
  1386. if (_iCur < ARRAYSIZE(rgVerbs))
  1387. {
  1388. IEVMSG(TEXT("Next"), celt, _iCur, TEXT("OLEIVERB_..."));
  1389. *rgelt = rgVerbs[_iCur++];
  1390. hres = S_OK;
  1391. }
  1392. else if (_pverbs)
  1393. {
  1394. int iCur = _iCur - ARRAYSIZE(rgVerbs);
  1395. IEVMSG(TEXT("Next"), celt, _iCur, _pverbs[iCur].lpszVerbName);
  1396. //
  1397. // FEATURE: Should we do while(celt--)?
  1398. //
  1399. if (_pverbs[iCur].lpszVerbName)
  1400. {
  1401. *rgelt = _pverbs[_iCur++];
  1402. WCHAR* pwszVerb = (WCHAR *)CoTaskMemAlloc(128 * sizeof(WCHAR));
  1403. if (pwszVerb)
  1404. {
  1405. MLLoadStringW(PtrToUint(_pverbs[iCur].lpszVerbName), pwszVerb, 128);
  1406. rgelt->lpszVerbName = pwszVerb;
  1407. celtFetched++;
  1408. hres = S_OK;
  1409. }
  1410. else
  1411. {
  1412. hres = E_OUTOFMEMORY;
  1413. }
  1414. }
  1415. }
  1416. if (pceltFetched) {
  1417. *pceltFetched = celtFetched;
  1418. }
  1419. return hres;
  1420. }
  1421. HRESULT CSVVerb::Skip(ULONG celt)
  1422. {
  1423. return S_OK;
  1424. }
  1425. HRESULT CSVVerb::Reset( void)
  1426. {
  1427. _iCur = 0;
  1428. return S_OK;
  1429. }
  1430. HRESULT CSVVerb::Clone(IEnumOLEVERB **ppenum)
  1431. {
  1432. *ppenum = new CSVVerb(_pverbs);
  1433. return *ppenum ? S_OK : E_OUTOFMEMORY;
  1434. }