//=--------------------------------------------------------------------------= // CtlView.Cpp //=--------------------------------------------------------------------------= // Copyright 1995-1996 Microsoft Corporation. All Rights Reserved. // // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. //=--------------------------------------------------------------------------= // // implementation of the IViewObjectEx interface, which is a moderately // non-trivial bunch of code. // #include "IPServer.H" #include "CtrlObj.H" #include "Globals.H" #include "Util.H" // for ASSERT and FAIL // SZTHISFILE // local functions we're going to find useful // HDC _CreateOleDC(DVTARGETDEVICE *ptd); //=--------------------------------------------------------------------------= // COleControl::Draw [IViewObject2] //=--------------------------------------------------------------------------= // Draws a representation of an object onto the specified device context. // // Parameters: // DWORD - [in] draw aspect // LONG - [in] part of object to draw [not relevant] // void * - NULL // DVTARGETDEVICE * - [in] specifies the target device // HDC - [in] information context for target device // HDC - [in] target device context // LPCRECTL - [in] rectangle in which the object is drawn // LPCRECTL - [in] window extent and origin for metafiles // BOOL (*)(DWORD) - [in] callback for continuing or cancelling drawing // DWORD - [in] parameter to pass to callback. // // Output: // HRESULT // // Notes: // - we support the following OCX 96 extensions // a. flicker free drawing [multi-pass drawing] // b. pvAspect != NULL for optimized DC handling // c. prcBounds == NULL for windowless inplace active objects // STDMETHODIMP COleControl::Draw ( DWORD dwDrawAspect, LONG lIndex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, HDC hdcDraw, LPCRECTL prcBounds, LPCRECTL prcWBounds, BOOL (__stdcall *pfnContinue)(ULONG_PTR dwContinue), ULONG_PTR dwContinue ) { HRESULT hr; RECTL rc; POINT pVp, pW; BOOL fOptimize = FALSE; int iMode; BYTE fMetafile = FALSE; BYTE fDeleteDC = FALSE; // support the aspects required for multi-pass drawing // switch (dwDrawAspect) { case DVASPECT_CONTENT: case DVASPECT_OPAQUE: case DVASPECT_TRANSPARENT: break; default: return DV_E_DVASPECT; } // first, have to do a little bit to support printing. // if (GetDeviceCaps(hdcDraw, TECHNOLOGY) == DT_METAFILE) { // We are dealing with a metafile. // fMetafile = TRUE; // If attributes DC is NULL, create one, based on ptd. // if (!hicTargetDevice) { // Does _CreateOleDC have to return an hDC // or can it be flagged to return an hIC // for this particular case? // hicTargetDevice = _CreateOleDC(ptd); fDeleteDC = TRUE; } } // check to see if we have any flags passed in the pvAspect parameter. // if (pvAspect && ((DVASPECTINFO *)pvAspect)->cb == sizeof(DVASPECTINFO)) fOptimize = (((DVASPECTINFO *)pvAspect)->dwFlags & DVASPECTINFOFLAG_CANOPTIMIZE) ? TRUE : FALSE; // if we are windowless, then we just pass this on to the end control code. // if (m_fInPlaceActive) { // give them a rectangle with which to draw // //ASSERT(!m_fInPlaceActive || !prcBounds, "Inplace active and somebody passed in prcBounds!!!"); if (prcBounds) memcpy(&rc, prcBounds, sizeof(rc)); else memcpy(&rc, &m_rcLocation, sizeof(rc)); } else { // first -- convert the DC back to MM_TEXT mapping mode so that the // window proc and OnDraw can share the same painting code. save // some information on it, so we can restore it later [without using // a SaveDC/RestoreDC] // rc = *prcBounds; // Don't do anything to hdcDraw if it's a metafile. // The control's Draw method must make the appropriate // accomodations for drawing to a metafile // if (!fMetafile) { LPtoDP(hdcDraw, (POINT *)&rc, 2); SetViewportOrgEx(hdcDraw, 0, 0, &pVp); SetWindowOrgEx(hdcDraw, 0, 0, &pW); iMode = SetMapMode(hdcDraw, MM_TEXT); } } // prcWBounds is NULL and not used if we are not dealing with a metafile. // For metafiles, we pass on rc as *prcBounds, we should also include // prcWBounds // hr = OnDraw(dwDrawAspect, hdcDraw, &rc, prcWBounds, hicTargetDevice, fOptimize); // clean up the DC when we're done with it, if appropriate. // if (!m_fInPlaceActive) { SetViewportOrgEx(hdcDraw, pVp.x, pVp.y, NULL); SetWindowOrgEx(hdcDraw, pW.x, pW.y, NULL); SetMapMode(hdcDraw, iMode); } // if we created a dc, blow it away now // if (fDeleteDC && hicTargetDevice) DeleteDC(hicTargetDevice); return hr; } //=--------------------------------------------------------------------------= // COleControl::DoSuperClassPaint //=--------------------------------------------------------------------------= // design time painting of a subclassed control. // // Parameters: // HDC - [in] dc to work with // LPCRECTL - [in] rectangle to paint to. should be in pixels // // Output: // HRESULT // // Notes: // HRESULT COleControl::DoSuperClassPaint ( HDC hdc, LPCRECTL prcBounds ) { HWND hwnd; RECT rcClient; int iMapMode; POINT ptWOrg, ptVOrg; SIZE sWOrg, sVOrg; // make sure we have a window. // hwnd = CreateInPlaceWindow(0,0, FALSE); if (!hwnd) return E_FAIL; GetClientRect(hwnd, &rcClient); // set up the DC for painting. this code largely taken from the MFC CDK // DoSuperClassPaint() fn. doesn't always get things like command // buttons quite right ... // // NOTE: there is a windows 95 problem in which the font instance manager // will leak a bunch of bytes in the global GDI pool whenever you // change your extents and have an active font. this code gets around // this for on-screen cases, but not for printing [which shouldn't be // too serious, because you're not often changing your control size and // printing rapidly in succession] // if ((rcClient.right - rcClient.left != prcBounds->right - prcBounds->left) && (rcClient.bottom - rcClient.top != prcBounds->bottom - prcBounds->top)) { iMapMode = SetMapMode(hdc, MM_ANISOTROPIC); SetWindowExtEx(hdc, rcClient.right, rcClient.bottom, &sWOrg); SetViewportExtEx(hdc, prcBounds->right - prcBounds->left, prcBounds->bottom - prcBounds->top, &sVOrg); } SetWindowOrgEx(hdc, 0, 0, &ptWOrg); SetViewportOrgEx(hdc, prcBounds->left, prcBounds->top, &ptVOrg); #if STRICT CallWindowProc((WNDPROC)SUBCLASSWNDPROCOFCONTROL(m_ObjectType), hwnd, (g_fSysWin95Shell) ? WM_PRINT : WM_PAINT, (WPARAM)hdc, (LPARAM)(g_fSysWin95Shell ? PRF_CHILDREN | PRF_CLIENT : 0)); #else CallWindowProc((FARPROC)SUBCLASSWNDPROCOFCONTROL(m_ObjectType), hwnd, (g_fSysWin95Shell) ? WM_PRINT : WM_PAINT, (WPARAM)hdc, (LPARAM)(g_fSysWin95Shell ? PRF_CHILDREN | PRF_CLIENT : 0)); #endif // STRICT return S_OK; } //=--------------------------------------------------------------------------= // COleControl::GetColorSet [IViewObject2] //=--------------------------------------------------------------------------= // Returns the logical palette that the control will use for drawing in its // IViewObject::Draw method with the corresponding parameters. // // Parameters: // DWORD - [in] how the object is to be represented // LONG - [in] part of the object to draw [not relevant] // void * - NULL // DVTARGETDEVICE * - [in] specifies the target device // HDC - [in] information context for the target device // LOGPALETTE ** - [out] where to put palette // // Output: // S_OK - Control has a palette, and returned it through the out param. // S_FALSE - Control does not currently have a palette. // E_NOTIMPL - Control will never have a palette so optimize handling of this control. // // Notes: // STDMETHODIMP COleControl::GetColorSet ( DWORD dwDrawAspect, LONG lindex, void *IgnoreMe, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet ) { if (dwDrawAspect != DVASPECT_CONTENT) return DV_E_DVASPECT; *ppColorSet = NULL; return (OnGetPalette(hicTargetDevice, ppColorSet)) ? ((*ppColorSet) ? S_OK : S_FALSE) : E_NOTIMPL; } //=--------------------------------------------------------------------------= // COleControl::Freeze [IViewObject2] //=--------------------------------------------------------------------------= // Freezes a certain aspect of the object's presentation so that it does not // change until the IViewObject::Unfreeze method is called. // // Parameters: // DWORD - [in] aspect // LONG - [in] part of object to draw // void * - NULL // DWORD * - [out] for Unfreeze // // Output: // HRESULT // // Notes: // STDMETHODIMP COleControl::Freeze ( DWORD dwDrawAspect, LONG lIndex, void *IgnoreMe, DWORD *pdwFreeze ) { return E_NOTIMPL; } //=--------------------------------------------------------------------------= // COleControl::Unfreeze [IVewObject2] //=--------------------------------------------------------------------------= // Releases a previously frozen drawing. The most common use of this method // is for banded printing. // // Parameters: // DWORD - [in] cookie from freeze // // Output: // HRESULT // // Notes: // STDMETHODIMP COleControl::Unfreeze ( DWORD dwFreeze ) { return E_NOTIMPL; } //=--------------------------------------------------------------------------= // COleControl::SetAdvise [IViewObject2] //=--------------------------------------------------------------------------= // Sets up a connection between the control and an advise sink so that the // advise sink can be notified about changes in the control's view. // // Parameters: // DWORD - [in] aspect // DWORD - [in] info about the sink // IAdviseSink * - [in] the sink // // Output: // HRESULT // // Notes: // STDMETHODIMP COleControl::SetAdvise ( DWORD dwAspects, DWORD dwAdviseFlags, IAdviseSink *pAdviseSink ) { // if it's not a content aspect, we don't support it. // if (!(dwAspects & DVASPECT_CONTENT)) { return DV_E_DVASPECT; } // set up some flags [we gotta stash for GetAdvise ...] // m_fViewAdvisePrimeFirst = (dwAdviseFlags & ADVF_PRIMEFIRST) ? TRUE : FALSE; m_fViewAdviseOnlyOnce = (dwAdviseFlags & ADVF_ONLYONCE) ? TRUE : FALSE; RELEASE_OBJECT(m_pViewAdviseSink); m_pViewAdviseSink = pAdviseSink; ADDREF_OBJECT(m_pViewAdviseSink); // prime them if they want it [we need to store this so they can get flags later] // if (m_fViewAdvisePrimeFirst) ViewChanged(); return S_OK; } //=--------------------------------------------------------------------------= // COleControl::GetAdvise [IViewObject2] //=--------------------------------------------------------------------------= // Retrieves the existing advisory connection on the control if there is one. // This method simply returns the parameters used in the most recent call to // the IViewObject::SetAdvise method. // // Parameters: // DWORD * - [out] aspects // DWORD * - [out] advise flags // IAdviseSink ** - [out] the sink // // Output: // HRESULT // // Notes; // STDMETHODIMP COleControl::GetAdvise ( DWORD *pdwAspects, DWORD *pdwAdviseFlags, IAdviseSink **ppAdviseSink ) { // if they want it, give it to them // if (pdwAspects) *pdwAspects = DVASPECT_CONTENT; if (pdwAdviseFlags) { *pdwAdviseFlags = 0; if (m_fViewAdviseOnlyOnce) *pdwAdviseFlags |= ADVF_ONLYONCE; if (m_fViewAdvisePrimeFirst) *pdwAdviseFlags |= ADVF_PRIMEFIRST; } if (ppAdviseSink) { *ppAdviseSink = m_pViewAdviseSink; ADDREF_OBJECT(*ppAdviseSink); } return S_OK; } //=--------------------------------------------------------------------------= // COleControl::GetExtent [IViewObject2] //=--------------------------------------------------------------------------= // Returns the size that the control will be drawn on the // specified target device. // // Parameters: // DWORD - [in] draw aspect // LONG - [in] part of object to draw // DVTARGETDEVICE * - [in] information about target device // LPSIZEL - [out] where to put the size // // Output: // HRESULT // // Notes: // STDMETHODIMP COleControl::GetExtent ( DWORD dwDrawAspect, LONG lindex, DVTARGETDEVICE *ptd, LPSIZEL psizel ) { // we already have an implementation of this [from IOleObject] // return GetExtent(dwDrawAspect, psizel); } //=--------------------------------------------------------------------------= // COleControl::OnGetPalette [overridable] //=--------------------------------------------------------------------------= // called when the host wants palette information. ideally, people should use // this sparingly and carefully. // // Parameters: // HDC - [in] HIC for the target device // LOGPALETTE ** - [out] where to put the palette // // Output: // BOOL - TRUE means we processed it, false means nope. // // Notes: // BOOL COleControl::OnGetPalette ( HDC hicTargetDevice, LOGPALETTE **ppColorSet ) { return FALSE; } //=--------------------------------------------------------------------------= // COleControl::GetRect [IViewObjectEx] //=--------------------------------------------------------------------------= // returns a rectnagle describing a given drawing aspect // // Parameters: // DWORD - [in] aspect // LPRECTL - [out] region rectangle // // Output: // HRESULT // // Notes: // STDMETHODIMP COleControl::GetRect ( DWORD dvAspect, LPRECTL prcRect ) { RECTL rc; BOOL f; // call the user routine and let them return the size // f = OnGetRect(dvAspect, &rc); if (!f) return DV_E_DVASPECT; // transform these dudes. // PixelToHiMetric((LPSIZEL)&rc, (LPSIZEL)prcRect); PixelToHiMetric((LPSIZEL)(LPBYTE)&rc + sizeof(SIZEL), (LPSIZEL)((LPBYTE)prcRect + sizeof(SIZEL))); return S_OK; } //=--------------------------------------------------------------------------= // COleControl::GetViewStatus [IViewObjectEx] //=--------------------------------------------------------------------------= // returns information about the opactiy of the object and what drawing // aspects are supported // // Parameters: // DWORD * - [out] the status // /// Output: // HRESULT // // Notes: // STDMETHODIMP COleControl::GetViewStatus ( DWORD *pdwStatus ) { // depending on the flag in the CONTROLOBJECTINFO structure, indicate our // transparency vs opacity. // OVERRIDE: controls that wish to support multi-pass drawing should // override this routine and return, in addition to the flags indication // opacity, flags indicating what sort of drawing aspects they support. // *pdwStatus = FCONTROLISOPAQUE(m_ObjectType) ? VIEWSTATUS_OPAQUE : 0; return S_OK; } //=--------------------------------------------------------------------------= // COleControl::QueryHitPoint [IViewObjectEx] //=--------------------------------------------------------------------------= // indicates whether a point is within a given aspect of an object. // // Parameters: // DWORD - [in] aspect // LPCRECT - [in] Bounds rectangle // POINT - [in] hit location client coordinates // LONG - [in] what the container considers close // DWORD * - [out] info about the hit // // Output: // HRESULT // // Notes: // STDMETHODIMP COleControl::QueryHitPoint ( DWORD dvAspect, LPCRECT prcBounds, POINT ptLocation, LONG lCloseHint, DWORD *pdwHitResult ) { // OVERRIDE: override me if you want to provide additional [non-opaque] // functionality // if (dvAspect != DVASPECT_CONTENT) return DV_E_DVASPECT; *pdwHitResult = PtInRect(prcBounds, ptLocation) ? HITRESULT_HIT : HITRESULT_OUTSIDE; return S_OK; } //=--------------------------------------------------------------------------= // COleControl::QueryHitRect [IViewObjectEx] //=--------------------------------------------------------------------------= // indicates wheter any point in a rectangle is within a given drawing aspect // of an object. // // Parameters: // DWORD - [in] aspect // LPCRECT - [in] bounds // LPCRECT - [in] location // LONG - [in] what host considers close // DWORD * - [out] hit result // // Output: // HRESULT // // Notes: // STDMETHODIMP COleControl::QueryHitRect ( DWORD dvAspect, LPCRECT prcBounds, LPCRECT prcLocation, LONG lCloseHint, DWORD *pdwHitResult ) { RECT rc; // OVERRIDE: override this for additional behaviour // if (dvAspect != DVASPECT_CONTENT) return DV_E_DVASPECT; *pdwHitResult = IntersectRect(&rc, prcBounds, prcLocation) ? HITRESULT_HIT : HITRESULT_OUTSIDE; return S_OK; } //=--------------------------------------------------------------------------= // COleControl::GetNaturalExtent [IViewObjectEx] //=--------------------------------------------------------------------------= // supports two types of control sizing, content and integral. // // Parameters: // DWORD - [in] aspect // LONG - [in] index // DVTARGETDEVICE * - [in] target device information // HDC - [in] HIC // DVEXTENTINFO * - [in] sizing data // LPSIZEL - [out] sizing data retunred by control // // Output: // HRESULT // // Notes: // STDMETHODIMP COleControl::GetNaturalExtent ( DWORD dvAspect, LONG lIndex, DVTARGETDEVICE *ptd, HDC hicTargetDevice, DVEXTENTINFO *pExtentInfo, LPSIZEL pSizel ) { return E_NOTIMPL; } //=--------------------------------------------------------------------------= // COleControl::OnGetRect [overridable //=--------------------------------------------------------------------------= // returns our rectangle // // Parameters: // DWORD - [in] aspect they want the rect for // RECTL * - [out] the rectangle that matches this aspect // // Output: // BOOL - false means we don't like the aspect // // Notes: // BOOL COleControl::OnGetRect ( DWORD dvAspect, RECTL *pRect ) { // by default, we only support content drawing. // if (dvAspect != DVASPECT_CONTENT) return FALSE; // just give them our bounding rectangle // *((LPRECT)pRect) = m_rcLocation; return TRUE; } //=--------------------------------------------------------------------------= // _CreateOleDC //=--------------------------------------------------------------------------= // creates an HDC given a DVTARGETDEVICE structure. // // Parameters: // DVTARGETDEVICE * - [in] duh. // // Output: // HDC // // Notes: // HDC _CreateOleDC ( DVTARGETDEVICE *ptd ) { LPDEVMODEW pDevModeW; DEVMODEA DevModeA, *pDevModeA; LPOLESTR lpwszDriverName; LPOLESTR lpwszDeviceName; LPOLESTR lpwszPortName; HDC hdc; // return screen DC for NULL target device // if (!ptd) return CreateDC("DISPLAY", NULL, NULL, NULL); if (ptd->tdExtDevmodeOffset == 0) pDevModeW = NULL; else pDevModeW = (LPDEVMODEW)((LPSTR)ptd + ptd->tdExtDevmodeOffset); lpwszDriverName = (LPOLESTR)((BYTE*)ptd + ptd->tdDriverNameOffset); lpwszDeviceName = (LPOLESTR)((BYTE*)ptd + ptd->tdDeviceNameOffset); lpwszPortName = (LPOLESTR)((BYTE*)ptd + ptd->tdPortNameOffset); MAKE_ANSIPTR_FROMWIDE(pszDriverName, lpwszDriverName); MAKE_ANSIPTR_FROMWIDE(pszDeviceName, lpwszDeviceName); MAKE_ANSIPTR_FROMWIDE(pszPortName, lpwszPortName); // // if (pDevModeW) { WideCharToMultiByte(CP_ACP, 0, pDevModeW->dmDeviceName, -1, (LPSTR)DevModeA.dmDeviceName, CCHDEVICENAME, NULL, NULL); memcpy(&DevModeA.dmSpecVersion, &pDevModeW->dmSpecVersion, offsetof(DEVMODEA, dmFormName) - offsetof(DEVMODEA, dmSpecVersion)); WideCharToMultiByte(CP_ACP, 0, pDevModeW->dmFormName, -1, (LPSTR)DevModeA.dmFormName, CCHFORMNAME, NULL, NULL); memcpy(&DevModeA.dmLogPixels, &pDevModeW->dmLogPixels, sizeof(DEVMODEA) - offsetof(DEVMODEA, dmLogPixels)); if (pDevModeW->dmDriverExtra) { pDevModeA = (DEVMODEA *)HeapAlloc(g_hHeap, 0, sizeof(DEVMODEA) + pDevModeW->dmDriverExtra); if (!pDevModeA) return NULL; memcpy(pDevModeA, &DevModeA, sizeof(DEVMODEA)); memcpy(pDevModeA + 1, pDevModeW + 1, pDevModeW->dmDriverExtra); } else pDevModeA = &DevModeA; DevModeA.dmSize = sizeof(DEVMODEA); } else pDevModeA = NULL; hdc = CreateDC(pszDriverName, pszDeviceName, pszPortName, pDevModeA); if ((pDevModeA != &DevModeA) && pDevModeA) HeapFree(g_hHeap, 0, pDevModeA); return hdc; }