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.

734 lines
22 KiB

  1. //=--------------------------------------------------------------------------=
  2. // CtlView.Cpp
  3. //=--------------------------------------------------------------------------=
  4. // Copyright 1995 Microsoft Corporation. All Rights Reserved.
  5. //
  6. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  7. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  8. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  9. // PARTICULAR PURPOSE.
  10. //=--------------------------------------------------------------------------=
  11. //
  12. // implementation of the IViewObjectEx interface, which is a moderately
  13. // non-trivial bunch of code.
  14. //
  15. #include "pch.h"
  16. #include "CtrlObj.H"
  17. // for ASSERT and FAIL
  18. //
  19. SZTHISFILE
  20. // local functions we're going to find useful
  21. //
  22. HDC _CreateOleDC(DVTARGETDEVICE *ptd);
  23. //=--------------------------------------------------------------------------=
  24. // COleControl::Draw [IViewObject2]
  25. //=--------------------------------------------------------------------------=
  26. // Draws a representation of an object onto the specified device context.
  27. //
  28. // Parameters:
  29. // DWORD - [in] draw aspect
  30. // LONG - [in] part of object to draw [not relevant]
  31. // void * - NULL
  32. // DVTARGETDEVICE * - [in] specifies the target device
  33. // HDC - [in] information context for target device
  34. // HDC - [in] target device context
  35. // LPCRECTL - [in] rectangle in which the object is drawn
  36. // LPCRECTL - [in] window extent and origin for metafiles
  37. // BOOL (*)(DWORD) - [in] callback for continuing or cancelling drawing
  38. // DWORD - [in] parameter to pass to callback.
  39. //
  40. // Output:
  41. // HRESULT
  42. //
  43. // Notes:
  44. // - we support the following OCX 96 extensions
  45. // a. flicker free drawing [multi-pass drawing]
  46. // b. pvAspect != NULL for optimized DC handling
  47. // c. prcBounds == NULL for windowless inplace active objects
  48. //
  49. STDMETHODIMP COleControl::Draw
  50. (
  51. DWORD dwDrawAspect,
  52. LONG lIndex,
  53. void *pvAspect,
  54. DVTARGETDEVICE *ptd,
  55. HDC hicTargetDevice,
  56. HDC hdcDraw,
  57. LPCRECTL prcBounds,
  58. LPCRECTL prcWBounds,
  59. BOOL (__stdcall *pfnContinue)(DWORD dwContinue),
  60. DWORD dwContinue
  61. )
  62. {
  63. HRESULT hr;
  64. RECTL rc;
  65. POINT pVp, pW;
  66. BOOL fOptimize = FALSE;
  67. int iMode;
  68. BYTE fMetafile = FALSE;
  69. BYTE fDeleteDC = FALSE;
  70. SIZE sWindowExt, sViewportExt;
  71. // support the aspects required for multi-pass drawing
  72. //
  73. switch (dwDrawAspect) {
  74. case DVASPECT_CONTENT:
  75. case DVASPECT_OPAQUE:
  76. case DVASPECT_TRANSPARENT:
  77. break;
  78. default:
  79. return DV_E_DVASPECT;
  80. }
  81. // first, have to do a little bit to support printing.
  82. //
  83. if (GetDeviceCaps(hdcDraw, TECHNOLOGY) == DT_METAFILE) {
  84. // We are dealing with a metafile.
  85. //
  86. fMetafile = TRUE;
  87. // If attributes DC is NULL, create one, based on ptd.
  88. //
  89. if (!hicTargetDevice) {
  90. // Does _CreateOleDC have to return an hDC
  91. // or can it be flagged to return an hIC
  92. // for this particular case?
  93. //
  94. hicTargetDevice = _CreateOleDC(ptd);
  95. fDeleteDC = TRUE;
  96. }
  97. }
  98. // check to see if we have any flags passed in the pvAspect parameter.
  99. //
  100. if (pvAspect && ((DVASPECTINFO *)pvAspect)->cb == sizeof(DVASPECTINFO))
  101. fOptimize = (((DVASPECTINFO *)pvAspect)->dwFlags & DVASPECTINFOFLAG_CANOPTIMIZE) ? TRUE : FALSE;
  102. // if they didn't give us a rectangle, just copy over ours
  103. //
  104. if (!prcBounds) {
  105. memcpy(&rc, &m_rcLocation, sizeof(rc));
  106. } else {
  107. // first -- convert the DC back to MM_TEXT mapping mode so that the
  108. // window proc and OnDraw can share the same painting code. save
  109. // some information on it, so we can restore it later [without using
  110. // a SaveDC/RestoreDC]
  111. //
  112. rc = *prcBounds;
  113. // Don't do anything to hdcDraw if it's a metafile.
  114. // The control's Draw method must make the appropriate
  115. // accomodations for drawing to a metafile
  116. //
  117. if (!fMetafile) {
  118. LPtoDP(hdcDraw, (POINT *)&rc, 2);
  119. SetViewportOrgEx(hdcDraw, 0, 0, &pVp);
  120. SetWindowOrgEx(hdcDraw, 0, 0, &pW);
  121. GetWindowExtEx(hdcDraw, &sWindowExt);
  122. GetViewportExtEx(hdcDraw, &sViewportExt);
  123. iMode = SetMapMode(hdcDraw, MM_TEXT);
  124. }
  125. }
  126. // prcWBounds is NULL and not used if we are not dealing with a metafile.
  127. // For metafiles, we pass on rc as *prcBounds, we should also include
  128. // prcWBounds
  129. //
  130. hr = OnDraw(dwDrawAspect, hdcDraw, &rc, prcWBounds, hicTargetDevice, fOptimize);
  131. // clean up the DC when we're done with it, if appropriate.
  132. //
  133. if (prcBounds && !fMetafile) {
  134. SetWindowOrgEx(hdcDraw, pW.x, pW.y, NULL);
  135. SetViewportOrgEx(hdcDraw, pVp.x, pVp.y, NULL);
  136. SetWindowExtEx(hdcDraw, sWindowExt.cx, sWindowExt.cy, NULL);
  137. SetViewportExtEx(hdcDraw, sViewportExt.cx, sViewportExt.cy, NULL);
  138. SetMapMode(hdcDraw, iMode);
  139. }
  140. // if we created a dc, blow it away now
  141. //
  142. if (fDeleteDC) DeleteDC(hicTargetDevice);
  143. return hr;
  144. }
  145. //=--------------------------------------------------------------------------=
  146. // COleControl::DoSuperClassPaint
  147. //=--------------------------------------------------------------------------=
  148. // design time painting of a subclassed control.
  149. //
  150. // Parameters:
  151. // HDC - [in] dc to work with
  152. // LPCRECTL - [in] rectangle to paint to. should be in pixels
  153. //
  154. // Output:
  155. // HRESULT
  156. //
  157. // Notes:
  158. //
  159. HRESULT COleControl::DoSuperClassPaint
  160. (
  161. HDC hdc,
  162. LPCRECTL prcBounds
  163. )
  164. {
  165. HWND hwnd;
  166. RECT rcClient;
  167. int iMapMode;
  168. POINT ptWOrg, ptVOrg;
  169. SIZE sWOrg, sVOrg;
  170. // make sure we have a window.
  171. //
  172. hwnd = CreateInPlaceWindow(0,0, FALSE);
  173. if (!hwnd)
  174. return E_FAIL;
  175. GetClientRect(hwnd, &rcClient);
  176. // set up the DC for painting. this code largely taken from the MFC CDK
  177. // DoSuperClassPaint() fn. doesn't always get things like command
  178. // buttons quite right ...
  179. //
  180. // NOTE: there is a windows 95 problem in which the font instance manager
  181. // will leak a bunch of bytes in the global GDI pool whenever you
  182. // change your extents and have an active font. this code gets around
  183. // this for on-screen cases, but not for printing [which shouldn't be
  184. // too serious, because you're not often changing your control size and
  185. // printing rapidly in succession]
  186. //
  187. if ((rcClient.right - rcClient.left != prcBounds->right - prcBounds->left)
  188. && (rcClient.bottom - rcClient.top != prcBounds->bottom - prcBounds->top)) {
  189. iMapMode = SetMapMode(hdc, MM_ANISOTROPIC);
  190. SetWindowExtEx(hdc, rcClient.right, rcClient.bottom, &sWOrg);
  191. SetViewportExtEx(hdc, prcBounds->right - prcBounds->left, prcBounds->bottom - prcBounds->top, &sVOrg);
  192. }
  193. SetWindowOrgEx(hdc, 0, 0, &ptWOrg);
  194. SetViewportOrgEx(hdc, prcBounds->left, prcBounds->top, &ptVOrg);
  195. #if STRICT
  196. CallWindowProc((WNDPROC)SUBCLASSWNDPROCOFCONTROL(m_ObjectType), hwnd, (g_fSysWin95Shell) ? WM_PRINT : WM_PAINT, (WPARAM)hdc, (LPARAM)(g_fSysWin95Shell ? PRF_CHILDREN | PRF_CLIENT : 0));
  197. #else
  198. CallWindowProc((FARPROC)SUBCLASSWNDPROCOFCONTROL(m_ObjectType), hwnd, (g_fSysWin95Shell) ? WM_PRINT : WM_PAINT, (WPARAM)hdc, (LPARAM)(g_fSysWin95Shell ? PRF_CHILDREN | PRF_CLIENT : 0));
  199. #endif // STRICT
  200. return S_OK;
  201. }
  202. //=--------------------------------------------------------------------------=
  203. // COleControl::GetColorSet [IViewObject2]
  204. //=--------------------------------------------------------------------------=
  205. // Returns the logical palette that the control will use for drawing in its
  206. // IViewObject::Draw method with the corresponding parameters.
  207. //
  208. // Parameters:
  209. // DWORD - [in] how the object is to be represented
  210. // LONG - [in] part of the object to draw [not relevant]
  211. // void * - NULL
  212. // DVTARGETDEVICE * - [in] specifies the target device
  213. // HDC - [in] information context for the target device
  214. // LOGPALETTE ** - [out] where to put palette
  215. //
  216. // Output:
  217. // S_OK - Control has a palette, and returned it through the out param.
  218. // S_FALSE - Control does not currently have a palette.
  219. // E_NOTIMPL - Control will never have a palette so optimize handling of this control.
  220. //
  221. // Notes:
  222. //
  223. STDMETHODIMP COleControl::GetColorSet
  224. (
  225. DWORD dwDrawAspect,
  226. LONG lindex,
  227. void *IgnoreMe,
  228. DVTARGETDEVICE *ptd,
  229. HDC hicTargetDevice,
  230. LOGPALETTE **ppColorSet
  231. )
  232. {
  233. if (dwDrawAspect != DVASPECT_CONTENT)
  234. return DV_E_DVASPECT;
  235. *ppColorSet = NULL;
  236. return (OnGetPalette(hicTargetDevice, ppColorSet)) ? ((*ppColorSet) ? S_OK : S_FALSE) : E_NOTIMPL;
  237. }
  238. //=--------------------------------------------------------------------------=
  239. // COleControl::Freeze [IViewObject2]
  240. //=--------------------------------------------------------------------------=
  241. // Freezes a certain aspect of the object's presentation so that it does not
  242. // change until the IViewObject::Unfreeze method is called.
  243. //
  244. // Parameters:
  245. // DWORD - [in] aspect
  246. // LONG - [in] part of object to draw
  247. // void * - NULL
  248. // DWORD * - [out] for Unfreeze
  249. //
  250. // Output:
  251. // HRESULT
  252. //
  253. // Notes:
  254. //
  255. STDMETHODIMP COleControl::Freeze
  256. (
  257. DWORD dwDrawAspect,
  258. LONG lIndex,
  259. void *IgnoreMe,
  260. DWORD *pdwFreeze
  261. )
  262. {
  263. return E_NOTIMPL;
  264. }
  265. //=--------------------------------------------------------------------------=
  266. // COleControl::Unfreeze [IVewObject2]
  267. //=--------------------------------------------------------------------------=
  268. // Releases a previously frozen drawing. The most common use of this method
  269. // is for banded printing.
  270. //
  271. // Parameters:
  272. // DWORD - [in] cookie from freeze
  273. //
  274. // Output:
  275. // HRESULT
  276. //
  277. // Notes:
  278. //
  279. STDMETHODIMP COleControl::Unfreeze
  280. (
  281. DWORD dwFreeze
  282. )
  283. {
  284. return E_NOTIMPL;
  285. }
  286. //=--------------------------------------------------------------------------=
  287. // COleControl::SetAdvise [IViewObject2]
  288. //=--------------------------------------------------------------------------=
  289. // Sets up a connection between the control and an advise sink so that the
  290. // advise sink can be notified about changes in the control's view.
  291. //
  292. // Parameters:
  293. // DWORD - [in] aspect
  294. // DWORD - [in] info about the sink
  295. // IAdviseSink * - [in] the sink
  296. //
  297. // Output:
  298. // HRESULT
  299. //
  300. // Notes:
  301. //
  302. STDMETHODIMP COleControl::SetAdvise
  303. (
  304. DWORD dwAspects,
  305. DWORD dwAdviseFlags,
  306. IAdviseSink *pAdviseSink
  307. )
  308. {
  309. // if it's not a content aspect, we don't support it.
  310. //
  311. if (!(dwAspects & DVASPECT_CONTENT)) {
  312. return DV_E_DVASPECT;
  313. }
  314. // set up some flags [we gotta stash for GetAdvise ...]
  315. //
  316. m_fViewAdvisePrimeFirst = (dwAdviseFlags & ADVF_PRIMEFIRST) ? TRUE : FALSE;
  317. m_fViewAdviseOnlyOnce = (dwAdviseFlags & ADVF_ONLYONCE) ? TRUE : FALSE;
  318. RELEASE_OBJECT(m_pViewAdviseSink);
  319. m_pViewAdviseSink = pAdviseSink;
  320. ADDREF_OBJECT(m_pViewAdviseSink);
  321. // prime them if they want it [we need to store this so they can get flags later]
  322. //
  323. if (m_fViewAdvisePrimeFirst)
  324. ViewChanged();
  325. return S_OK;
  326. }
  327. //=--------------------------------------------------------------------------=
  328. // COleControl::GetAdvise [IViewObject2]
  329. //=--------------------------------------------------------------------------=
  330. // Retrieves the existing advisory connection on the control if there is one.
  331. // This method simply returns the parameters used in the most recent call to
  332. // the IViewObject::SetAdvise method.
  333. //
  334. // Parameters:
  335. // DWORD * - [out] aspects
  336. // DWORD * - [out] advise flags
  337. // IAdviseSink ** - [out] the sink
  338. //
  339. // Output:
  340. // HRESULT
  341. //
  342. // Notes;
  343. //
  344. STDMETHODIMP COleControl::GetAdvise
  345. (
  346. DWORD *pdwAspects,
  347. DWORD *pdwAdviseFlags,
  348. IAdviseSink **ppAdviseSink
  349. )
  350. {
  351. // if they want it, give it to them
  352. //
  353. if (pdwAspects)
  354. *pdwAspects = DVASPECT_CONTENT;
  355. if (pdwAdviseFlags) {
  356. *pdwAdviseFlags = 0;
  357. if (m_fViewAdviseOnlyOnce) *pdwAdviseFlags |= ADVF_ONLYONCE;
  358. if (m_fViewAdvisePrimeFirst) *pdwAdviseFlags |= ADVF_PRIMEFIRST;
  359. }
  360. if (ppAdviseSink) {
  361. *ppAdviseSink = m_pViewAdviseSink;
  362. ADDREF_OBJECT(*ppAdviseSink);
  363. }
  364. return S_OK;
  365. }
  366. //=--------------------------------------------------------------------------=
  367. // COleControl::GetExtent [IViewObject2]
  368. //=--------------------------------------------------------------------------=
  369. // Returns the size that the control will be drawn on the
  370. // specified target device.
  371. //
  372. // Parameters:
  373. // DWORD - [in] draw aspect
  374. // LONG - [in] part of object to draw
  375. // DVTARGETDEVICE * - [in] information about target device
  376. // LPSIZEL - [out] where to put the size
  377. //
  378. // Output:
  379. // HRESULT
  380. //
  381. // Notes:
  382. //
  383. STDMETHODIMP COleControl::GetExtent
  384. (
  385. DWORD dwDrawAspect,
  386. LONG lindex,
  387. DVTARGETDEVICE *ptd,
  388. LPSIZEL psizel
  389. )
  390. {
  391. // we already have an implementation of this [from IOleObject]
  392. //
  393. return GetExtent(dwDrawAspect, psizel);
  394. }
  395. //=--------------------------------------------------------------------------=
  396. // COleControl::OnGetPalette [overridable]
  397. //=--------------------------------------------------------------------------=
  398. // called when the host wants palette information. ideally, people should use
  399. // this sparingly and carefully.
  400. //
  401. // Parameters:
  402. // HDC - [in] HIC for the target device
  403. // LOGPALETTE ** - [out] where to put the palette
  404. //
  405. // Output:
  406. // BOOL - TRUE means we processed it, false means nope.
  407. //
  408. // Notes:
  409. //
  410. BOOL COleControl::OnGetPalette
  411. (
  412. HDC hicTargetDevice,
  413. LOGPALETTE **ppColorSet
  414. )
  415. {
  416. return FALSE;
  417. }
  418. //=--------------------------------------------------------------------------=
  419. // COleControl::GetRect [IViewObjectEx]
  420. //=--------------------------------------------------------------------------=
  421. // returns a rectnagle describing a given drawing aspect
  422. //
  423. // Parameters:
  424. // DWORD - [in] aspect
  425. // LPRECTL - [out] region rectangle
  426. //
  427. // Output:
  428. // HRESULT
  429. //
  430. // Notes:
  431. //
  432. STDMETHODIMP COleControl::GetRect
  433. (
  434. DWORD dvAspect,
  435. LPRECTL prcRect
  436. )
  437. {
  438. RECTL rc;
  439. BOOL f;
  440. // call the user routine and let them return the size
  441. //
  442. f = OnGetRect(dvAspect, &rc);
  443. if (!f) return DV_E_DVASPECT;
  444. // transform these dudes.
  445. //
  446. PixelToHiMetric((LPSIZEL)&rc, (LPSIZEL)prcRect);
  447. PixelToHiMetric((LPSIZEL)((LPBYTE)&rc + sizeof(SIZEL)), (LPSIZEL)((LPBYTE)prcRect + sizeof(SIZEL)));
  448. return S_OK;
  449. }
  450. //=--------------------------------------------------------------------------=
  451. // COleControl::GetViewStatus [IViewObjectEx]
  452. //=--------------------------------------------------------------------------=
  453. // returns information about the opactiy of the object and what drawing
  454. // aspects are supported
  455. //
  456. // Parameters:
  457. // DWORD * - [out] the status
  458. //
  459. /// Output:
  460. // HRESULT
  461. //
  462. // Notes:
  463. //
  464. STDMETHODIMP COleControl::GetViewStatus
  465. (
  466. DWORD *pdwStatus
  467. )
  468. {
  469. // depending on the flag in the CONTROLOBJECTINFO structure, indicate our
  470. // transparency vs opacity.
  471. // OVERRIDE: controls that wish to support multi-pass drawing should
  472. // override this routine and return, in addition to the flags indication
  473. // opacity, flags indicating what sort of drawing aspects they support.
  474. //
  475. *pdwStatus = FCONTROLISOPAQUE(m_ObjectType) ? VIEWSTATUS_OPAQUE : 0;
  476. return S_OK;
  477. }
  478. //=--------------------------------------------------------------------------=
  479. // COleControl::QueryHitPoint [IViewObjectEx]
  480. //=--------------------------------------------------------------------------=
  481. // indicates whether a point is within a given aspect of an object.
  482. //
  483. // Parameters:
  484. // DWORD - [in] aspect
  485. // LPCRECT - [in] Bounds rectangle
  486. // POINT - [in] hit location client coordinates
  487. // LONG - [in] what the container considers close
  488. // DWORD * - [out] info about the hit
  489. //
  490. // Output:
  491. // HRESULT
  492. //
  493. // Notes:
  494. //
  495. STDMETHODIMP COleControl::QueryHitPoint
  496. (
  497. DWORD dvAspect,
  498. LPCRECT prcBounds,
  499. POINT ptLocation,
  500. LONG lCloseHint,
  501. DWORD *pdwHitResult
  502. )
  503. {
  504. // OVERRIDE: override me if you want to provide additional [non-opaque]
  505. // functionality
  506. //
  507. if (dvAspect != DVASPECT_CONTENT)
  508. return DV_E_DVASPECT;
  509. *pdwHitResult = PtInRect(prcBounds, ptLocation) ? HITRESULT_HIT : HITRESULT_OUTSIDE;
  510. return S_OK;
  511. }
  512. //=--------------------------------------------------------------------------=
  513. // COleControl::QueryHitRect [IViewObjectEx]
  514. //=--------------------------------------------------------------------------=
  515. // indicates wheter any point in a rectangle is within a given drawing aspect
  516. // of an object.
  517. //
  518. // Parameters:
  519. // DWORD - [in] aspect
  520. // LPCRECT - [in] bounds
  521. // LPCRECT - [in] location
  522. // LONG - [in] what host considers close
  523. // DWORD * - [out] hit result
  524. //
  525. // Output:
  526. // HRESULT
  527. //
  528. // Notes:
  529. //
  530. STDMETHODIMP COleControl::QueryHitRect
  531. (
  532. DWORD dvAspect,
  533. LPCRECT prcBounds,
  534. LPCRECT prcLocation,
  535. LONG lCloseHint,
  536. DWORD *pdwHitResult
  537. )
  538. {
  539. RECT rc;
  540. // OVERRIDE: override this for additional behaviour
  541. //
  542. if (dvAspect != DVASPECT_CONTENT)
  543. return DV_E_DVASPECT;
  544. *pdwHitResult = IntersectRect(&rc, prcBounds, prcLocation) ? HITRESULT_HIT : HITRESULT_OUTSIDE;
  545. return S_OK;
  546. }
  547. //=--------------------------------------------------------------------------=
  548. // COleControl::GetNaturalExtent [IViewObjectEx]
  549. //=--------------------------------------------------------------------------=
  550. // supports two types of control sizing, content and integral.
  551. //
  552. // Parameters:
  553. // DWORD - [in] aspect
  554. // LONG - [in] index
  555. // DVTARGETDEVICE * - [in] target device information
  556. // HDC - [in] HIC
  557. // DVEXTENTINFO * - [in] sizing data
  558. // LPSIZEL - [out] sizing data retunred by control
  559. //
  560. // Output:
  561. // HRESULT
  562. //
  563. // Notes:
  564. //
  565. STDMETHODIMP COleControl::GetNaturalExtent
  566. (
  567. DWORD dvAspect,
  568. LONG lIndex,
  569. DVTARGETDEVICE *ptd,
  570. HDC hicTargetDevice,
  571. DVEXTENTINFO *pExtentInfo,
  572. LPSIZEL pSizel
  573. )
  574. {
  575. return E_NOTIMPL;
  576. }
  577. //=--------------------------------------------------------------------------=
  578. // COleControl::OnGetRect [overridable
  579. //=--------------------------------------------------------------------------=
  580. // returns our rectangle
  581. //
  582. // Parameters:
  583. // DWORD - [in] aspect they want the rect for
  584. // RECTL * - [out] the rectangle that matches this aspect
  585. //
  586. // Output:
  587. // BOOL - false means we don't like the aspect
  588. //
  589. // Notes:
  590. //
  591. BOOL COleControl::OnGetRect
  592. (
  593. DWORD dvAspect,
  594. RECTL *pRect
  595. )
  596. {
  597. // by default, we only support content drawing.
  598. //
  599. if (dvAspect != DVASPECT_CONTENT)
  600. return FALSE;
  601. // just give them our bounding rectangle
  602. //
  603. *((LPRECT)pRect) = m_rcLocation;
  604. return TRUE;
  605. }
  606. //=--------------------------------------------------------------------------=
  607. // _CreateOleDC
  608. //=--------------------------------------------------------------------------=
  609. // creates an HDC given a DVTARGETDEVICE structure.
  610. //
  611. // Parameters:
  612. // DVTARGETDEVICE * - [in] duh.
  613. //
  614. // Output:
  615. // HDC
  616. //
  617. // Notes:
  618. //
  619. HDC _CreateOleDC
  620. (
  621. DVTARGETDEVICE *ptd
  622. )
  623. {
  624. LPDEVMODEW pDevModeW;
  625. DEVMODEA DevModeA, *pDevModeA;
  626. LPOLESTR lpwszDriverName;
  627. LPOLESTR lpwszDeviceName;
  628. LPOLESTR lpwszPortName;
  629. HDC hdc;
  630. // return screen DC for NULL target device
  631. //
  632. if (!ptd)
  633. return CreateDC("DISPLAY", NULL, NULL, NULL);
  634. if (ptd->tdExtDevmodeOffset == 0)
  635. pDevModeW = NULL;
  636. else
  637. pDevModeW = (LPDEVMODEW)((LPSTR)ptd + ptd->tdExtDevmodeOffset);
  638. lpwszDriverName = (LPOLESTR)((BYTE*)ptd + ptd->tdDriverNameOffset);
  639. lpwszDeviceName = (LPOLESTR)((BYTE*)ptd + ptd->tdDeviceNameOffset);
  640. lpwszPortName = (LPOLESTR)((BYTE*)ptd + ptd->tdPortNameOffset);
  641. MAKE_ANSIPTR_FROMWIDE(pszDriverName, lpwszDriverName);
  642. MAKE_ANSIPTR_FROMWIDE(pszDeviceName, lpwszDeviceName);
  643. MAKE_ANSIPTR_FROMWIDE(pszPortName, lpwszPortName);
  644. // wow, this sucks.
  645. //
  646. if (pDevModeW) {
  647. WideCharToMultiByte(CP_ACP, 0, pDevModeW->dmDeviceName, -1, (LPSTR)DevModeA.dmDeviceName, CCHDEVICENAME, NULL, NULL);
  648. memcpy(&DevModeA.dmSpecVersion, &pDevModeW->dmSpecVersion,
  649. offsetof(DEVMODEA, dmFormName) - offsetof(DEVMODEA, dmSpecVersion));
  650. WideCharToMultiByte(CP_ACP, 0, pDevModeW->dmFormName, -1, (LPSTR)DevModeA.dmFormName, CCHFORMNAME, NULL, NULL);
  651. memcpy(&DevModeA.dmLogPixels, &pDevModeW->dmLogPixels, sizeof(DEVMODEA) - offsetof(DEVMODEA, dmLogPixels));
  652. if (pDevModeW->dmDriverExtra) {
  653. pDevModeA = (DEVMODEA *)CtlHeapAlloc(g_hHeap, 0, sizeof(DEVMODEA) + pDevModeW->dmDriverExtra);
  654. if (!pDevModeA) return NULL;
  655. memcpy(pDevModeA, &DevModeA, sizeof(DEVMODEA));
  656. memcpy(pDevModeA + 1, pDevModeW + 1, pDevModeW->dmDriverExtra);
  657. } else
  658. pDevModeA = &DevModeA;
  659. DevModeA.dmSize = sizeof(DEVMODEA);
  660. } else
  661. pDevModeA = NULL;
  662. hdc = CreateDC(pszDriverName, pszDeviceName, pszPortName, pDevModeA);
  663. if (pDevModeA != &DevModeA) CtlHeapFree(g_hHeap, 0, pDevModeA);
  664. return hdc;
  665. }