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.

567 lines
18 KiB

  1. // Copyright (C) 1996-1997 Microsoft Corporation. All rights reserved.
  2. #include "header.h"
  3. #include "internet.h"
  4. #include <stddef.h>
  5. #ifndef _DEBUG
  6. #undef THIS_FILE
  7. static const char THIS_FILE[] = __FILE__;
  8. #endif
  9. HDC _CreateOleDC(DVTARGETDEVICE *ptd);
  10. //=--------------------------------------------------------------------------=
  11. // COleControl::Draw [IViewObject2]
  12. //=--------------------------------------------------------------------------=
  13. // Draws a representation of an object onto the specified device context.
  14. //
  15. // Parameters:
  16. // DWORD - [in] draw aspect
  17. // LONG - [in] part of object to draw [not relevant]
  18. // void * - NULL
  19. // DVTARGETDEVICE * - [in] specifies the target device
  20. // HDC - [in] information context for target device
  21. // HDC - [in] target device context
  22. // LPCRECTL - [in] rectangle in which the object is drawn
  23. // LPCRECTL - [in] window extent and origin for metafiles
  24. // BOOL (*)(DWORD) - [in] callback for continuing or cancelling drawing
  25. // DWORD - [in] parameter to pass to callback.
  26. //
  27. // Output:
  28. // HRESULT
  29. //
  30. // Notes:
  31. // - we support the following OCX 96 extensions
  32. // a. flicker free drawing [multi-pass drawing]
  33. // b. pvAspect != NULL for optimized DC handling
  34. // c. prcBounds == NULL for windowless inplace active objects
  35. STDMETHODIMP COleControl::Draw(DWORD dwDrawAspect, LONG lIndex,
  36. void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice,
  37. HDC hdcDraw, LPCRECTL prcBounds,
  38. LPCRECTL prcWBounds,
  39. BOOL (__stdcall *pfnContinue)(ULONG_PTR dwContinue),
  40. ULONG_PTR dwContinue)
  41. {
  42. HRESULT hr;
  43. RECTL rc;
  44. POINT pVp, pW;
  45. BOOL fOptimize = FALSE;
  46. int iMode;
  47. BYTE fMetafile = FALSE;
  48. BYTE fDeleteDC = FALSE;
  49. // support the aspects required for multi-pass drawing
  50. switch (dwDrawAspect) {
  51. case DVASPECT_CONTENT:
  52. case DVASPECT_OPAQUE:
  53. case DVASPECT_TRANSPARENT:
  54. break;
  55. default:
  56. return DV_E_DVASPECT;
  57. }
  58. // first, have to do a little bit to support printing.
  59. if (GetDeviceCaps(hdcDraw, TECHNOLOGY) == DT_METAFILE) {
  60. // We are dealing with a metafile.
  61. //
  62. fMetafile = TRUE;
  63. // If attributes DC is NULL, create one, based on ptd.
  64. if (!hicTargetDevice) {
  65. // Does _CreateOleDC have to return an hDC
  66. // or can it be flagged to return an hIC
  67. // for this particular case?
  68. //
  69. hicTargetDevice = _CreateOleDC(ptd);
  70. fDeleteDC = TRUE;
  71. }
  72. }
  73. // check to see if we have any flags passed in the pvAspect parameter.
  74. if (pvAspect && ((DVASPECTINFO *)pvAspect)->cb == sizeof(DVASPECTINFO))
  75. fOptimize = (((DVASPECTINFO *)pvAspect)->dwFlags & DVASPECTINFOFLAG_CANOPTIMIZE) ? TRUE : FALSE;
  76. // if we are windowless, then we just pass this on to the end control code.
  77. if (m_fInPlaceActive) {
  78. // Can't use CopyRect because OLE decided to use RECTL instead of RECT
  79. memcpy(&rc, &m_rcLocation, sizeof(m_rcLocation));
  80. } else {
  81. memcpy(&rc, prcBounds, sizeof(rc));
  82. // first -- convert the DC back to MM_TEXT mapping mode so that the
  83. // window proc and OnDraw can share the same painting code. save
  84. // some information on it, so we can restore it later [without using
  85. // a SaveDC/RestoreDC]
  86. //
  87. // Don't do anything to hdcDraw if it's a metafile.
  88. // The control's Draw method must make the appropriate
  89. // accomodations for drawing to a metafile
  90. //
  91. if (!fMetafile) {
  92. LPtoDP(hdcDraw, (POINT *)&rc, 2);
  93. SetViewportOrgEx(hdcDraw, 0, 0, &pVp);
  94. SetWindowOrgEx(hdcDraw, 0, 0, &pW);
  95. iMode = SetMapMode(hdcDraw, MM_TEXT);
  96. }
  97. }
  98. // prcWBounds is NULL and not used if we are not dealing with a metafile.
  99. // For metafiles, we pass on rc as *prcBounds, we should also include
  100. // prcWBounds
  101. hr = OnDraw(dwDrawAspect, hdcDraw, &rc, prcWBounds, hicTargetDevice, fOptimize);
  102. // clean up the DC when we're done with it, if appropriate.
  103. if (!m_fInPlaceActive) {
  104. SetViewportOrgEx(hdcDraw, pVp.x, pVp.y, NULL);
  105. SetWindowOrgEx(hdcDraw, pW.x, pW.y, NULL);
  106. SetMapMode(hdcDraw, iMode);
  107. }
  108. // if we created a dc, blow it away now
  109. if (fDeleteDC)
  110. DeleteDC(hicTargetDevice);
  111. return hr;
  112. }
  113. //=--------------------------------------------------------------------------=
  114. // COleControl::DoSuperClassPaint
  115. //=--------------------------------------------------------------------------=
  116. // design time painting of a subclassed control.
  117. //
  118. // Parameters:
  119. // HDC - [in] dc to work with
  120. // LPCRECTL - [in] rectangle to paint to. should be in pixels
  121. HRESULT COleControl::DoSuperClassPaint(HDC hdc, LPCRECTL prcBounds)
  122. {
  123. HWND hwnd;
  124. RECT rcClient;
  125. int iMapMode;
  126. POINT ptWOrg, ptVOrg;
  127. SIZE sWOrg, sVOrg;
  128. // make sure we have a window.
  129. hwnd = CreateInPlaceWindow(0,0, FALSE);
  130. if (!hwnd)
  131. return E_FAIL;
  132. GetClientRect(hwnd, &rcClient);
  133. // set up the DC for painting. this code largely taken from the MFC CDK
  134. // DoSuperClassPaint() fn. doesn't always get things like command
  135. // buttons quite right ...
  136. //
  137. // NOTE: there is a windows 95 problem in which the font instance manager
  138. // will leak a bunch of bytes in the global GDI pool whenever you
  139. // change your extents and have an active font. this code gets around
  140. // this for on-screen cases, but not for printing [which shouldn't be
  141. // too serious, because you're not often changing your control size and
  142. // printing rapidly in succession]
  143. if ((rcClient.right - rcClient.left != prcBounds->right - prcBounds->left)
  144. && (rcClient.bottom - rcClient.top != prcBounds->bottom - prcBounds->top)) {
  145. iMapMode = SetMapMode(hdc, MM_ANISOTROPIC);
  146. SetWindowExtEx(hdc, rcClient.right, rcClient.bottom, &sWOrg);
  147. SetViewportExtEx(hdc, prcBounds->right - prcBounds->left, prcBounds->bottom - prcBounds->top, &sVOrg);
  148. }
  149. SetWindowOrgEx(hdc, 0, 0, &ptWOrg);
  150. SetViewportOrgEx(hdc, prcBounds->left, prcBounds->top, &ptVOrg);
  151. CallWindowProc((WNDPROC)SUBCLASSWNDPROCOFCONTROL(m_ObjectType), hwnd, (g_fSysWin95Shell) ? WM_PRINT : WM_PAINT, (WPARAM)hdc, (LPARAM)(g_fSysWin95Shell ? PRF_CHILDREN | PRF_CLIENT : 0));
  152. return S_OK;
  153. }
  154. //=--------------------------------------------------------------------------=
  155. // COleControl::GetColorSet [IViewObject2]
  156. //=--------------------------------------------------------------------------=
  157. // Returns the logical palette that the control will use for drawing in its
  158. // IViewObject::Draw method with the corresponding parameters.
  159. //
  160. // Parameters:
  161. // DWORD - [in] how the object is to be represented
  162. // LONG - [in] part of the object to draw [not relevant]
  163. // void * - NULL
  164. // DVTARGETDEVICE * - [in] specifies the target device
  165. // HDC - [in] information context for the target device
  166. // LOGPALETTE ** - [out] where to put palette
  167. //
  168. // Output:
  169. // S_OK - Control has a palette, and returned it through the out param.
  170. // S_FALSE - Control does not currently have a palette.
  171. // E_NOTIMPL - Control will never have a palette so optimize handling of this control.
  172. STDMETHODIMP COleControl::GetColorSet(DWORD dwDrawAspect, LONG lindex,
  173. void *IgnoreMe, DVTARGETDEVICE *ptd, HDC hicTargetDevice,
  174. LOGPALETTE **ppColorSet)
  175. {
  176. if (dwDrawAspect != DVASPECT_CONTENT)
  177. return DV_E_DVASPECT;
  178. *ppColorSet = NULL;
  179. return (OnGetPalette(hicTargetDevice, ppColorSet)) ? ((*ppColorSet) ? S_OK : S_FALSE) : E_NOTIMPL;
  180. }
  181. //=--------------------------------------------------------------------------=
  182. // COleControl::Freeze [IViewObject2]
  183. //=--------------------------------------------------------------------------=
  184. // Freezes a certain aspect of the object's presentation so that it does not
  185. // change until the IViewObject::Unfreeze method is called.
  186. //
  187. // Parameters:
  188. // DWORD - [in] aspect
  189. // LONG - [in] part of object to draw
  190. // void * - NULL
  191. // DWORD * - [out] for Unfreeze
  192. STDMETHODIMP COleControl::Freeze(DWORD dwDrawAspect, LONG lIndex,
  193. void *IgnoreMe, DWORD *pdwFreeze)
  194. {
  195. return E_NOTIMPL;
  196. }
  197. //=--------------------------------------------------------------------------=
  198. // COleControl::Unfreeze [IVewObject2]
  199. //=--------------------------------------------------------------------------=
  200. // Releases a previously frozen drawing. The most common use of this method
  201. // is for banded printing.
  202. //
  203. // Parameters:
  204. // DWORD - [in] cookie from freeze
  205. STDMETHODIMP COleControl::Unfreeze(DWORD dwFreeze)
  206. {
  207. return E_NOTIMPL;
  208. }
  209. //=--------------------------------------------------------------------------=
  210. // COleControl::SetAdvise [IViewObject2]
  211. //=--------------------------------------------------------------------------=
  212. // Sets up a connection between the control and an advise sink so that the
  213. // advise sink can be notified about changes in the control's view.
  214. //
  215. // Parameters:
  216. // DWORD - [in] aspect
  217. // DWORD - [in] info about the sink
  218. // IAdviseSink * - [in] the sink
  219. STDMETHODIMP COleControl::SetAdvise(DWORD dwAspects, DWORD dwAdviseFlags,
  220. IAdviseSink *pAdviseSink)
  221. {
  222. // if it's not a content aspect, we don't support it.
  223. if (!(dwAspects & DVASPECT_CONTENT)) {
  224. return DV_E_DVASPECT;
  225. }
  226. // set up some flags [we gotta stash for GetAdvise ...]
  227. m_fViewAdvisePrimeFirst = (dwAdviseFlags & ADVF_PRIMEFIRST) ? TRUE : FALSE;
  228. m_fViewAdviseOnlyOnce = (dwAdviseFlags & ADVF_ONLYONCE) ? TRUE : FALSE;
  229. RELEASE_OBJECT(m_pViewAdviseSink);
  230. m_pViewAdviseSink = pAdviseSink;
  231. ADDREF_OBJECT(m_pViewAdviseSink);
  232. // prime them if they want it [we need to store this so they can get flags later]
  233. if (m_fViewAdvisePrimeFirst)
  234. ViewChanged();
  235. return S_OK;
  236. }
  237. //=--------------------------------------------------------------------------=
  238. // COleControl::GetAdvise [IViewObject2]
  239. //=--------------------------------------------------------------------------=
  240. // Retrieves the existing advisory connection on the control if there is one.
  241. // This method simply returns the parameters used in the most recent call to
  242. // the IViewObject::SetAdvise method.
  243. //
  244. // Parameters:
  245. // DWORD * - [out] aspects
  246. // DWORD * - [out] advise flags
  247. // IAdviseSink ** - [out] the sink
  248. STDMETHODIMP COleControl::GetAdvise(DWORD *pdwAspects, DWORD *pdwAdviseFlags,
  249. IAdviseSink **ppAdviseSink)
  250. {
  251. // if they want it, give it to them
  252. if (pdwAspects)
  253. *pdwAspects = DVASPECT_CONTENT;
  254. if (pdwAdviseFlags) {
  255. *pdwAdviseFlags = 0;
  256. if (m_fViewAdviseOnlyOnce) *pdwAdviseFlags |= ADVF_ONLYONCE;
  257. if (m_fViewAdvisePrimeFirst) *pdwAdviseFlags |= ADVF_PRIMEFIRST;
  258. }
  259. if (ppAdviseSink) {
  260. *ppAdviseSink = m_pViewAdviseSink;
  261. ADDREF_OBJECT(*ppAdviseSink);
  262. }
  263. return S_OK;
  264. }
  265. //=--------------------------------------------------------------------------=
  266. // COleControl::GetExtent [IViewObject2]
  267. //=--------------------------------------------------------------------------=
  268. // Returns the size that the control will be drawn on the
  269. // specified target device.
  270. //
  271. // Parameters:
  272. // DWORD - [in] draw aspect
  273. // LONG - [in] part of object to draw
  274. // DVTARGETDEVICE * - [in] information about target device
  275. // LPSIZEL - [out] where to put the size
  276. STDMETHODIMP COleControl::GetExtent(DWORD dwDrawAspect, LONG lindex,
  277. DVTARGETDEVICE *ptd, LPSIZEL psizel)
  278. {
  279. // we already have an implementation of this [from IOleObject]
  280. return GetExtent(dwDrawAspect, psizel);
  281. }
  282. //=--------------------------------------------------------------------------=
  283. // COleControl::OnGetPalette [overridable]
  284. //=--------------------------------------------------------------------------=
  285. // called when the host wants palette information. ideally, people should use
  286. // this sparingly and carefully.
  287. //
  288. // Parameters:
  289. // HDC - [in] HIC for the target device
  290. // LOGPALETTE ** - [out] where to put the palette
  291. //
  292. // Output:
  293. // BOOL - TRUE means we processed it, false means nope.
  294. BOOL COleControl::OnGetPalette(HDC hicTargetDevice, LOGPALETTE **ppColorSet)
  295. {
  296. return FALSE;
  297. }
  298. //=--------------------------------------------------------------------------=
  299. // COleControl::GetRect [IViewObjectEx]
  300. //=--------------------------------------------------------------------------=
  301. // returns a rectnagle describing a given drawing aspect
  302. //
  303. // Parameters:
  304. // DWORD - [in] aspect
  305. // LPRECTL - [out] region rectangle
  306. STDMETHODIMP COleControl::GetRect(DWORD dvAspect, LPRECTL prcRect)
  307. {
  308. RECTL rc;
  309. BOOL f;
  310. // call the user routine and let them return the size
  311. f = OnGetRect(dvAspect, &rc);
  312. if (!f) return DV_E_DVASPECT;
  313. // transform these dudes.
  314. PixelToHiMetric((LPSIZEL)&rc, (LPSIZEL)prcRect);
  315. PixelToHiMetric((LPSIZEL)(LPBYTE)&rc + sizeof(SIZEL), (LPSIZEL)((LPBYTE)prcRect + sizeof(SIZEL)));
  316. return S_OK;
  317. }
  318. //=--------------------------------------------------------------------------=
  319. // COleControl::GetViewStatus [IViewObjectEx]
  320. //=--------------------------------------------------------------------------=
  321. // returns information about the opactiy of the object and what drawing
  322. // aspects are supported
  323. //
  324. // Parameters:
  325. // DWORD * - [out] the status
  326. STDMETHODIMP COleControl::GetViewStatus(DWORD *pdwStatus)
  327. {
  328. // depending on the flag in the CONTROLOBJECTINFO structure, indicate our
  329. // transparency vs opacity.
  330. // OVERRIDE: controls that wish to support multi-pass drawing should
  331. // override this routine and return, in addition to the flags indication
  332. // opacity, flags indicating what sort of drawing aspects they support.
  333. *pdwStatus = FCONTROLISOPAQUE(m_ObjectType) ? VIEWSTATUS_OPAQUE : 0;
  334. return S_OK;
  335. }
  336. //=--------------------------------------------------------------------------=
  337. // COleControl::QueryHitPoint [IViewObjectEx]
  338. //=--------------------------------------------------------------------------=
  339. // indicates whether a point is within a given aspect of an object.
  340. //
  341. // Parameters:
  342. // DWORD - [in] aspect
  343. // LPCRECT - [in] Bounds rectangle
  344. // POINT - [in] hit location client coordinates
  345. // LONG - [in] what the container considers close
  346. // DWORD * - [out] info about the hit
  347. STDMETHODIMP COleControl::QueryHitPoint(DWORD dvAspect, LPCRECT prcBounds,
  348. POINT ptLocation, LONG lCloseHint, DWORD *pdwHitResult)
  349. {
  350. // OVERRIDE: override me if you want to provide additional [non-opaque]
  351. // functionality
  352. if (dvAspect != DVASPECT_CONTENT)
  353. return DV_E_DVASPECT;
  354. *pdwHitResult = PtInRect(prcBounds, ptLocation) ? HITRESULT_HIT : HITRESULT_OUTSIDE;
  355. return S_OK;
  356. }
  357. //=--------------------------------------------------------------------------=
  358. // COleControl::QueryHitRect [IViewObjectEx]
  359. //=--------------------------------------------------------------------------=
  360. // indicates whether any point in a rectangle is within a given drawing aspect
  361. // of an object.
  362. //
  363. // Parameters:
  364. // DWORD - [in] aspect
  365. // LPCRECT - [in] bounds
  366. // LPCRECT - [in] location
  367. // LONG - [in] what host considers close
  368. // DWORD * - [out] hit result
  369. STDMETHODIMP COleControl::QueryHitRect(DWORD dvAspect, LPCRECT prcBounds,
  370. LPCRECT prcLocation, LONG lCloseHint, DWORD *pdwHitResult)
  371. {
  372. RECT rc;
  373. // OVERRIDE: override this for additional behaviour
  374. if (dvAspect != DVASPECT_CONTENT)
  375. return DV_E_DVASPECT;
  376. *pdwHitResult = IntersectRect(&rc, prcBounds, prcLocation) ? HITRESULT_HIT : HITRESULT_OUTSIDE;
  377. return S_OK;
  378. }
  379. //=--------------------------------------------------------------------------=
  380. // COleControl::GetNaturalExtent [IViewObjectEx]
  381. //=--------------------------------------------------------------------------=
  382. // supports two types of control sizing, content and integral.
  383. //
  384. // Parameters:
  385. // DWORD - [in] aspect
  386. // LONG - [in] index
  387. // DVTARGETDEVICE * - [in] target device information
  388. // HDC - [in] HIC
  389. // DVEXTENTINFO * - [in] sizing data
  390. // LPSIZEL - [out] sizing data retunred by control
  391. STDMETHODIMP COleControl::GetNaturalExtent(DWORD dvAspect, LONG lIndex,
  392. DVTARGETDEVICE *ptd, HDC hicTargetDevice, DVEXTENTINFO *pExtentInfo,
  393. LPSIZEL pSizel)
  394. {
  395. return E_NOTIMPL;
  396. }
  397. //=--------------------------------------------------------------------------=
  398. // COleControl::OnGetRect [overridable
  399. //=--------------------------------------------------------------------------=
  400. // returns our rectangle
  401. //
  402. // Parameters:
  403. // DWORD - [in] aspect they want the rect for
  404. // RECTL * - [out] the rectangle that matches this aspect
  405. //
  406. // Output:
  407. // BOOL - false means we don't like the aspect
  408. BOOL COleControl::OnGetRect(DWORD dvAspect, RECTL *pRect)
  409. {
  410. // by default, we only support content drawing.
  411. if (dvAspect != DVASPECT_CONTENT)
  412. return FALSE;
  413. // just give them our bounding rectangle
  414. *((LPRECT)pRect) = m_rcLocation;
  415. return TRUE;
  416. }
  417. //=--------------------------------------------------------------------------=
  418. // _CreateOleDC
  419. //=--------------------------------------------------------------------------=
  420. // creates an HDC given a DVTARGETDEVICE structure.
  421. //
  422. // Parameters:
  423. // DVTARGETDEVICE * - [in] duh.
  424. HDC _CreateOleDC(DVTARGETDEVICE *ptd)
  425. {
  426. LPDEVMODEW pDevModeW;
  427. DEVMODEA DevModeA, *pDevModeA;
  428. LPOLESTR lpwszDriverName;
  429. LPOLESTR lpwszDeviceName;
  430. LPOLESTR lpwszPortName;
  431. HDC hdc;
  432. // return screen DC for NULL target device
  433. if (!ptd)
  434. return CreateDC("DISPLAY", NULL, NULL, NULL);
  435. if (ptd->tdExtDevmodeOffset == 0)
  436. pDevModeW = NULL;
  437. else
  438. pDevModeW = (LPDEVMODEW)((LPSTR)ptd + ptd->tdExtDevmodeOffset);
  439. lpwszDriverName = (LPOLESTR)((BYTE*)ptd + ptd->tdDriverNameOffset);
  440. lpwszDeviceName = (LPOLESTR)((BYTE*)ptd + ptd->tdDeviceNameOffset);
  441. lpwszPortName = (LPOLESTR)((BYTE*)ptd + ptd->tdPortNameOffset);
  442. MAKE_ANSIPTR_FROMWIDE(pszDriverName, lpwszDriverName);
  443. MAKE_ANSIPTR_FROMWIDE(pszDeviceName, lpwszDeviceName);
  444. MAKE_ANSIPTR_FROMWIDE(pszPortName, lpwszPortName);
  445. if (pDevModeW) {
  446. WideCharToMultiByte(CP_ACP, 0, pDevModeW->dmDeviceName, -1,
  447. (LPSTR) DevModeA.dmDeviceName, CCHDEVICENAME, NULL, NULL);
  448. memcpy(&DevModeA.dmSpecVersion, &pDevModeW->dmSpecVersion,
  449. offsetof(DEVMODEA, dmFormName) - offsetof(DEVMODEA, dmSpecVersion));
  450. WideCharToMultiByte(CP_ACP, 0, pDevModeW->dmFormName, -1, (LPSTR)DevModeA.dmFormName, CCHFORMNAME, NULL, NULL);
  451. memcpy(&DevModeA.dmLogPixels, &pDevModeW->dmLogPixels, sizeof(DEVMODEA) - offsetof(DEVMODEA, dmLogPixels));
  452. if (pDevModeW->dmDriverExtra) {
  453. pDevModeA = (DEVMODEA *)lcCalloc(sizeof(DEVMODEA) + pDevModeW->dmDriverExtra);
  454. if (!pDevModeA)
  455. return NULL;
  456. memcpy(pDevModeA, &DevModeA, sizeof(DEVMODEA));
  457. memcpy(pDevModeA + 1, pDevModeW + 1, pDevModeW->dmDriverExtra);
  458. }
  459. else
  460. pDevModeA = &DevModeA;
  461. DevModeA.dmSize = sizeof(DEVMODEA);
  462. }
  463. else
  464. pDevModeA = NULL;
  465. hdc = CreateDC(pszDriverName, pszDeviceName, pszPortName, pDevModeA);
  466. if (pDevModeA != &DevModeA)
  467. lcFree(pDevModeA);
  468. return hdc;
  469. }