|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: gen.cpp
//
// Contents: Implementation of the generic picture object (CGenObject)
// and dib routines.
//
// Classes: CGenObject implementation
//
// Functions: DibDraw (internal)
// DibMakeLogPalette (internal)
// DibFillPaletteEntries (internal)
//
// History: dd-mmm-yy Author Comment
// 01-Feb-95 t-ScottH add Dump method and DumpCGenObject API
// 25-Jan-94 alexog first pass at converting to Cairo-style
// memory allocations.
// 11-Jan-94 alexgo added VDATEHEAP macros to every function
// and method
// 07-Dec-93 ChrisWe make default params to StSetSize explicit
// 07-Dec-93 alexgo merged 16bit RC9 changes
// 29-Nov-93 ChrisWe make default arguments to UtDupGlobal,
// UtConvertBitmapToDib explicit
// 23-Nov-93 alexgo 32bit port
// srinik 06/04/93 Added the support for demand loading and
// discarding the caches.
// SriniK 03/19/1993 Deleted dib.cpp and moved DIB drawing routines
// into this file.
// SriniK 01/07/1993 Merged dib.cpp into gen.cpp
//
//--------------------------------------------------------------------------
/*
REVIEW32::: WARNING WARNING There are many potentially bogus pointer to Palette, etc handle conversions put in to make the code compile. :( (Gee, thanks for marking them as you went) */
#include <le2int.h>
#pragma SEG(gen)
#include "gen.h"
#ifdef _DEBUG
#include <dbgdump.h>
#endif // _DEBUG
ASSERTDATA
#define M_HPRES() (m_hPres ? m_hPres : LoadHPRES())
//local functions
INTERNAL DibDraw(HANDLE hDib, HDC hdc, LPCRECTL lprc); INTERNAL_(HANDLE) DibMakeLogPalette (BYTE FAR *lpColorData, WORD wDataSize, LPLOGPALETTE FAR* lplpLogPalette); INTERNAL_(void) DibFillPaletteEntries(BYTE FAR *lpColorData, WORD wDataSize, LPLOGPALETTE lpLogPalette);
/*
* IMPLEMENTATION of CGenObject * */
NAME_SEG(Gen)
//+-------------------------------------------------------------------------
//
// Member: CGenObject::CGenObject
//
// Synopsis: Constructor
//
// Effects:
//
// Arguments: [pCacheNode] -- cache for the object
// [cfFormat] -- clipboard format of the object
// [dwAspect] -- drawing aspect of the object
//
// Requires:
//
// Returns: void
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm: just initializes member variables
//
// History: dd-mmm-yy Author Comment
// 23-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CGenObject_ctor)
CGenObject::CGenObject(LPCACHENODE pCacheNode, CLIPFORMAT cfFormat, DWORD dwAspect) { VDATEHEAP();
m_ulRefs = 1; m_dwSize = NULL; m_lWidth = NULL; m_lHeight = NULL; m_hPres = NULL; m_cfFormat = cfFormat; m_dwAspect = dwAspect; m_pCacheNode = pCacheNode; }
//+-------------------------------------------------------------------------
//
// Member: CGenObject::~CGenObject
//
// Synopsis: Destructor
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: void
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 23-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CGenObject_dtor)
CGenObject::~CGenObject(void) { VDATEHEAP();
if (m_hPres) { LEVERIFY( NULL == GlobalFree (m_hPres)); } }
//+-------------------------------------------------------------------------
//
// Member: CGenObject::QueryInterface
//
// Synopsis: returns interfaces on the generic picture object
//
// Effects:
//
// Arguments: [iid] -- the requested interface ID
// [ppvObj] -- where to put the interface pointer
//
// Requires:
//
// Returns: NOERROR, E_NOINTERFACE
//
// Signals:
//
// Modifies:
//
// Derivation: IUnkown
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 23-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CGenObject_QueryInterface)
STDMETHODIMP CGenObject::QueryInterface (REFIID iid, void FAR* FAR* ppvObj) { VDATEHEAP();
if (IsEqualIID(iid, IID_IUnknown) || IsEqualIID(iid, IID_IOlePresObj)) { *ppvObj = this; AddRef(); return NOERROR; } else { *ppvObj = NULL; return ResultFromScode(E_NOINTERFACE); } }
//+-------------------------------------------------------------------------
//
// Member: CGenObject::AddRef
//
// Synopsis: increments the reference count
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns: ULONG -- the new reference count
//
// Signals:
//
// Modifies:
//
// Derivation: IUnknown
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 23-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CGenObject_AddRef)
STDMETHODIMP_(ULONG) CGenObject::AddRef(void) { VDATEHEAP(); return ++m_ulRefs; } //+-------------------------------------------------------------------------
//
// Member: CGenObject::Release
//
// Synopsis: Decrements the reference count
//
// Effects: may delete [this] object
//
// Arguments:
//
// Requires:
//
// Returns: ULONG -- the new reference count
//
// Signals:
//
// Modifies:
//
// Derivation: IUnknown
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 23-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CGenObject_Release)
STDMETHODIMP_(ULONG) CGenObject::Release(void) { VDATEHEAP();
if (--m_ulRefs == 0) { delete this; return 0; }
return m_ulRefs; }
//+-------------------------------------------------------------------------
//
// Member: CGenObject::GetData
//
// Synopsis: retrieves data of the specified format
//
// Effects:
//
// Arguments: [pformatetcIn] -- the requested data format
// [pmedium] -- where to put the data
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOlePresObject
//
// Algorithm: If available, copies the presentation to pmedium
//
// History: dd-mmm-yy Author Comment
// 23-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CGenObject_GetData)
STDMETHODIMP CGenObject::GetData (LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium) { VDATEHEAP();
SCODE sc; if (IsBlank()) { sc = OLE_E_BLANK; } else if (pformatetcIn->cfFormat != m_cfFormat) {
if (m_cfFormat == CF_DIB && pformatetcIn->cfFormat == CF_BITMAP) { return GetBitmapData(pformatetcIn, pmedium); } else { sc = DV_E_CLIPFORMAT; } } else if (0 == (pformatetcIn->tymed & TYMED_HGLOBAL)) { sc = DV_E_TYMED; } else { if (NULL == (pmedium->hGlobal = GetCopyOfHPRES())) { sc = E_OUTOFMEMORY; goto errRtn; } pmedium->tymed = TYMED_HGLOBAL; return NOERROR; } errRtn: // null out in case of error
pmedium->tymed = TYMED_NULL; pmedium->pUnkForRelease = NULL; return ResultFromScode(sc); }
//+-------------------------------------------------------------------------
//
// Member: CGenObject::GetDataHere
//
// Synopsis: retrieves presentation data into the given pmedium
//
// Effects:
//
// Arguments: [pformatetcIn] -- the requested data format
// [pmedium] -- where to put the data
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOlePresObj
//
// Algorithm: copies presentation data into the given storage medium
// after error checking on the arguments
//
// History: dd-mmm-yy Author Comment
// 23-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CGenObject_GetDataHere)
STDMETHODIMP CGenObject::GetDataHere (LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium) { VDATEHEAP();
SCODE scode = S_OK;
if (pformatetcIn->cfFormat != m_cfFormat) { scode = DV_E_CLIPFORMAT; } else if (pmedium->tymed != TYMED_HGLOBAL && pmedium->tymed != TYMED_ISTREAM) { scode = DV_E_TYMED; } else if (pmedium->hGlobal == NULL) { scode = E_INVALIDARG; } else if (IsBlank()) { scode = OLE_E_BLANK; } else // actually get the data now
{ if (pmedium->tymed == TYMED_HGLOBAL) { // check the size of the given pmedium and then
// copy the data into it
LPVOID lpsrc = NULL; LPVOID lpdst = NULL; DWORD dwSizeDst;
scode = E_OUTOFMEMORY;
if (0 == (dwSizeDst = (DWORD) GlobalSize(pmedium->hGlobal))) { goto errRtn; }
// not enough room to copy
if (dwSizeDst < m_dwSize) { goto errRtn; } if (NULL == (lpdst = (LPVOID) GlobalLock(pmedium->hGlobal))) { goto errRtn; } if (NULL == (lpsrc = (LPVOID) GlobalLock(M_HPRES()))) { goto errMem; } _xmemcpy(lpdst, lpsrc, m_dwSize); scode = S_OK; errMem: if (lpdst) { GlobalUnlock(pmedium->hGlobal); } if (lpsrc) { GlobalUnlock(m_hPres); } } else { Assert(pmedium->tymed == TYMED_ISTREAM); if (m_cfFormat == CF_DIB) { return UtHDIBToDIBFileStm(M_HPRES(), m_dwSize,pmedium->pstm); } else { return UtHGLOBALtoStm(M_HPRES(), m_dwSize, pmedium->pstm); } } } errRtn: return ResultFromScode(scode); }
//+-------------------------------------------------------------------------
//
// Member: CGenObject::SetDataWDO
//
// Synopsis: Takes the given presentation data and stores it
//
// Effects:
//
// Arguments: [pformatetc] -- the format of the data
// [pmedium] -- the new presentation data
// [fRelease] -- if TRUE, then we keep the data, else
// we keep a copy
// [pDataObj] -- pointer to the IDataObject, may be NULL
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOlePresObj
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 23-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CGenObject::SetDataWDO (LPFORMATETC pformatetc, LPSTGMEDIUM pmedium, BOOL fRelease, IDataObject * pDataObj) { VDATEHEAP();
HRESULT error; BOOL fTakeData = FALSE; if (pformatetc->cfFormat != m_cfFormat) { if (m_cfFormat == CF_DIB && pformatetc->cfFormat == CF_BITMAP) { return SetBitmapData(pformatetc, pmedium, fRelease, pDataObj); } else { return ResultFromScode(DV_E_CLIPFORMAT); } }
if (pmedium->tymed != TYMED_HGLOBAL) { return ResultFromScode(DV_E_TYMED); }
if ((pmedium->pUnkForRelease == NULL) && fRelease) { // we can take the ownership of the data
fTakeData = TRUE; }
// ChangeData will keep the data if fRelease is TRUE, else it copies
error = ChangeData (pmedium->hGlobal, fTakeData);
if (fTakeData) { pmedium->tymed = TYMED_NULL; } else if (fRelease) { ReleaseStgMedium(pmedium); }
return error; }
//+-------------------------------------------------------------------------
//
// Member: CGenObject::ChangeData (private)
//
// Synopsis: Replaces the stored presentation
//
// Effects:
//
// Arguments: [hNewData] -- the new presentation
// [fDelete] -- if TRUE, then free hNewData
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 23-Nov-93 alexgo 32bit port
// Notes:
//
// If the routine fails then the object will be left with it's old data.
// In case of failure if fDelete is TRUE, then hNewData will be freed.
//
//--------------------------------------------------------------------------
#pragma SEG(CGenObject_ChangeData)
INTERNAL CGenObject::ChangeData (HANDLE hNewData, BOOL fDelete) { VDATEHEAP();
HRESULT hresult = ResultFromScode(E_OUTOFMEMORY); if (!hNewData) { return ResultFromScode(OLE_E_BLANK); }
if (!fDelete) { if (NULL == (hNewData = UtDupGlobal(hNewData, GMEM_MOVEABLE))) { return hresult; } } else { HANDLE hTmp; // change the ownership to yourself
hTmp = GlobalReAlloc (hNewData, 0L, GMEM_MODIFY|GMEM_SHARE); if (NULL == hTmp) { if (NULL == (hTmp = UtDupGlobal(hNewData, GMEM_MOVEABLE))) { goto errRtn; } // Realloc failed but copying succeeded. Since this is fDelete
// case, free the source global handle.
LEVERIFY( NULL == GlobalFree(hNewData)); } hNewData = hTmp; }
#ifndef _MAC
// CF_DIB format specific code. Get the it's extents
if (m_cfFormat == CF_DIB) { LPBITMAPINFOHEADER lpBi;
if (NULL == (lpBi = (LPBITMAPINFOHEADER) GlobalLock (hNewData))) { goto errRtn; } UtGetDibExtents (lpBi, &m_lWidth, &m_lHeight); GlobalUnlock (hNewData); } #endif
// free the old presentation
if (m_hPres) { LEVERIFY( NULL == GlobalFree (m_hPres)); }
// store the new presentation in m_hPres
m_dwSize = (DWORD) GlobalSize (m_hPres = hNewData); return NOERROR; errRtn: if (hNewData && fDelete) { LEVERIFY( NULL == GlobalFree (hNewData)); }
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CGenObject::Draw
//
// Synopsis: Calls DibDraw to draw the stored bitmap presentation
//
// Effects:
//
// Arguments: [pvAspect] -- drawing aspect
// [hicTargetDev] -- the target device
// [hdcDraw] -- the device context
// [lprcBounds] -- drawing boundary
// [lprcWBounds] -- boundary rectangle for metafiles
// [pfnContinue] -- callback function to periodically call
// for long drawing operations
// [dwContinue] -- argument to be passed to pfnContinue
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOlePresObj
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 23-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CGenObject_Draw)
STDMETHODIMP CGenObject::Draw(void * /* UNUSED pvAspect */, HDC /* UNUSED hicTargetDev */, HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL /* UNUSED lprcWBounds */, BOOL (CALLBACK * /*UNUSED pfcCont*/)(ULONG_PTR), ULONG_PTR /* UNUSED dwContinue */) { VDATEHEAP();
#ifndef _MAC
if (m_cfFormat == CF_DIB) { return DibDraw (M_HPRES(), hdcDraw,lprcBounds); } #endif
return ResultFromScode(E_NOTIMPL); }
//+-------------------------------------------------------------------------
//
// Member: CGenObject::Load
//
// Synopsis: Loads a stored presentation object from the given stream
//
// Effects:
//
// Arguments: [lpstream] -- the stream from which to load
// [fReadHeaderOnly] -- if TRUE, only get header info
// (such as size, width, height, etc)
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOlePresObj
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 23-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CGenObject::Load(LPSTREAM lpstream, BOOL fReadHeaderOnly) { VDATEHEAP();
DWORD dwBuf[4]; HRESULT error; /* read dwCompression, width, height, size of data */ error = StRead(lpstream, dwBuf, 4 * sizeof(DWORD)); if (error) { return error; }
// we don't allow for compression yet
AssertSz (dwBuf[0] == 0, "Picture compression factor is non-zero"); m_lWidth = (LONG) dwBuf[1]; m_lHeight = (LONG) dwBuf[2]; m_dwSize = dwBuf[3];
if (!m_dwSize || fReadHeaderOnly) { return NOERROR; }
return UtGetHGLOBALFromStm(lpstream, m_dwSize, &m_hPres); }
//+-------------------------------------------------------------------------
//
// Member: CGenObject::Save
//
// Synopsis: Stores presentation data to the given stream
//
// Effects:
//
// Arguments: [lpstream] -- where to store the data
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOlePresObj
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 23-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CGenObject::Save(LPSTREAM lpstream) { VDATEHEAP();
HRESULT error; DWORD dwBuf[4];
/* write dwCompression, width, height, size of data */
dwBuf[0] = 0L; dwBuf[1] = (DWORD) m_lWidth; dwBuf[2] = (DWORD) m_lHeight; dwBuf[3] = m_dwSize;
error = StWrite(lpstream, dwBuf, 4*sizeof(DWORD)); if (error) { return error; }
// if we're blank or don't have any presentation data, then
// nothing to else to save.
if (IsBlank() || m_hPres == NULL) { StSetSize(lpstream, 0, TRUE); return NOERROR; }
return UtHGLOBALtoStm(m_hPres, m_dwSize, lpstream); }
//+-------------------------------------------------------------------------
//
// Member: CGenObject::GetExtent
//
// Synopsis: retrieves the size (width/height) of the presentation bitmap
//
// Effects:
//
// Arguments: [dwDrawAspect] -- the drawing aspect the caller is
// interested in
// [lpsizel] -- where to put the size extents
//
// Requires:
//
// Returns: HRESULT (NOERROR, DV_E_DVASPECT, OLE_E_BLANK)
//
// Signals:
//
// Modifies:
//
// Derivation: IOlePresObj
//
// Algorithm: retrieves the stored dimensions
//
// History: dd-mmm-yy Author Comment
// 23-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CGenObject_GetExtent)
STDMETHODIMP CGenObject::GetExtent(DWORD dwDrawAspect, LPSIZEL lpsizel) { VDATEHEAP();
// aspects must match
if (!(dwDrawAspect & m_dwAspect)) { return ResultFromScode(DV_E_DVASPECT); }
if (IsBlank()) { return ResultFromScode(OLE_E_BLANK); } lpsizel->cx = m_lWidth; lpsizel->cy = m_lHeight; if (lpsizel->cx || lpsizel->cy) { return NOERROR; } else { return ResultFromScode(OLE_E_BLANK); } }
//+-------------------------------------------------------------------------
//
// Member: CGenObject::GetColorSet
//
// Synopsis: Retrieves the pallette associated with the bitmap
//
// Effects:
//
// Arguments: [pvAspect] -- the drawing aspect (unused)
// [hicTargetDev] -- the target device (unused)
// [ppColorSet] -- where to put the new palette
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOlePresObj
//
// Algorithm: Allocates a new pallette and copies the bitmap
// palette into it.
//
// History: dd-mmm-yy Author Comment
// 23-Nov-93 alexgo 32bit port, fixed bad memory bugs
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CGenObject::GetColorSet(LPVOID /* UNUSED pvAspect */, HDC /* UNUSED hicTargetDev */, LPLOGPALETTE * ppColorSet) { VDATEHEAP();
HRESULT hresult = ResultFromScode(S_FALSE);
if (m_cfFormat == CF_DIB) { if (IsBlank()) { return ResultFromScode(OLE_E_BLANK); }
LPBITMAPINFOHEADER lpbmih; LPLOGPALETTE lpLogpal; WORD wPalSize; if (NULL == (lpbmih = (LPBITMAPINFOHEADER) GlobalLock (M_HPRES()))) { return ResultFromScode(E_OUTOFMEMORY); }
// A bitmap with more than 8 bpp cannot have a palette at all,
// so we just return S_FALSE
if (lpbmih->biBitCount > 8) { goto errRtn; }
// Note: the return from UtPaletteSize can overflow the WORD
// wPalSize, but utPaletteSize asserts against this
if (0 == (wPalSize = (WORD) UtPaletteSize(lpbmih))) { goto errRtn; } lpLogpal = (LPLOGPALETTE)PubMemAlloc(wPalSize + 2*sizeof(WORD)); if (lpLogpal == NULL) { hresult = ResultFromScode(E_OUTOFMEMORY); goto errRtn; } DibFillPaletteEntries((BYTE FAR *)++lpbmih, wPalSize, lpLogpal); *ppColorSet = lpLogpal; hresult = NOERROR;
errRtn: GlobalUnlock(m_hPres); return hresult; }
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CGenObject::IsBlank
//
// Synopsis: returns TRUE if the presentation is blank
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: TRUE/FALSE
//
// Signals:
//
// Modifies:
//
// Derivation: IOlePresObject
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 23-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CGenObject_IsBlank)
STDMETHODIMP_(BOOL) CGenObject::IsBlank(void) { VDATEHEAP();
return (m_dwSize ? FALSE : TRUE); }
//+-------------------------------------------------------------------------
//
// Member: CGenObject::LoadHPRES (private)
//
// Synopsis: Loads the presentation from the internal cache's stream
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: HANDLE (to the presentation)
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 23-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
INTERNAL_(HANDLE) CGenObject::LoadHPRES() { VDATEHEAP();
LPSTREAM pstm;
pstm = m_pCacheNode->GetStm(TRUE /*fSeekToPresBits*/, STGM_READ); if (pstm) { LEVERIFY( SUCCEEDED(Load(pstm))); pstm->Release(); } return m_hPres; }
//+-------------------------------------------------------------------------
//
// Member: CGenObject::DiscardHPRES
//
// Synopsis: Deletes the object's presentation
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: void
//
// Signals:
//
// Modifies:
//
// Derivation: IOlePresObj
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 23-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP_(void) CGenObject::DiscardHPRES(void) { VDATEHEAP();
if (m_hPres) { LEVERIFY( NULL == GlobalFree(m_hPres)); m_hPres = NULL; } }
//+-------------------------------------------------------------------------
//
// Member: CGenObject::GetCopyOfHPRES (private)
//
// Synopsis: Returns a handle to a copy of the presentation data
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: HANDLE
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm: makes a copy of m_hPres if not NULL, otherwise loads it
// from the stream (without setting m_hPres)
//
// History: dd-mmm-yy Author Comment
// 23-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
INTERNAL_(HANDLE) CGenObject::GetCopyOfHPRES() { VDATEHEAP();
HANDLE hPres; // Make a copy if the presentation data is already loaded
if (m_hPres) { return(UtDupGlobal(m_hPres, GMEM_MOVEABLE)); }
// Load the presentation data now and return the same handle.
// No need to copy the data. If the caller wants the m_hPres to be
// set he would call LoadHPRES() directly.
hPres = LoadHPRES(); m_hPres = NULL; return hPres; }
//+-------------------------------------------------------------------------
//
// Member: CGenObject::GetBitmapData (private)
//
// Synopsis: Gets bitmap data from a dib
//
// Effects:
//
// Arguments: [pformatetcIn] -- the requested format
// [pmedium] -- where to put the data
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm: checks the parameters, then calls UtConvertDibtoBitmap
// to get raw bitmap data from the device-independent bitmap
//
// History: dd-mmm-yy Author Comment
// 23-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#ifndef _MAC
#pragma SEG(CGenObject_GetBitmapData)
INTERNAL CGenObject::GetBitmapData (LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium) { VDATEHEAP();
SCODE sc = E_OUTOFMEMORY; if (0 == (pformatetcIn->tymed & TYMED_GDI)) { sc = DV_E_TYMED; }
pmedium->pUnkForRelease = NULL;
pmedium->hGlobal = UtConvertDibToBitmap(M_HPRES());
// if pmedium->hGlobal is not NULL, then UtConvertDibToBitmap succeeded
// so the tymed needs to be set appropriately, and the return value
// changed to S_OK.
if (NULL != pmedium->hGlobal) { pmedium->tymed = TYMED_GDI; sc = S_OK; } else { pmedium->tymed = TYMED_NULL; } return ResultFromScode(sc); }
//+-------------------------------------------------------------------------
//
// Member: CGenObject::SetBitmapData (private)
//
// Synopsis: Converts bitmap data to a dib and stores it in [this]
// presenatation object
//
// Effects:
//
// Arguments: [pformatetc] -- the format of the data
// [pmedium] -- the data
// [fRelease] -- if TRUE, then pmedium will be free'd
//
// Returns: HRESULT
//
// Algorithm: calls UtConvertBitmapToDib and stores the result
//
// History: dd-mmm-yy Author Comment
// 07-Jul-94 DavePl Added CF_PALETTE support
//
// Notes: if [fRelease] == TRUE, then [pmedium] is released, even
// if a dib could not be built
//
//--------------------------------------------------------------------------
INTERNAL CGenObject::SetBitmapData(LPFORMATETC pformatetc, STGMEDIUM * pmedium, BOOL fRelease, IDataObject * pDataObject) { VDATEHEAP();
HGLOBAL hDib; if (pmedium->tymed != TYMED_GDI) { return ResultFromScode(DV_E_TYMED); }
// If we have a data object and if we can get the palette from it,
// use that to do the bitmap -> dib conversion. Otherwise, just
// pass a NULL palette along and the default one will be used
STGMEDIUM stgmPalette; FORMATETC fetcPalette = { CF_PALETTE, NULL, pformatetc->dwAspect, DEF_LINDEX, TYMED_GDI };
if (pDataObject && SUCCEEDED(pDataObject->GetData(&fetcPalette, &stgmPalette))) { hDib = UtConvertBitmapToDib((HBITMAP)pmedium->hGlobal, (HPALETTE) stgmPalette.hGlobal); ReleaseStgMedium(&stgmPalette); } else { hDib = UtConvertBitmapToDib((HBITMAP)pmedium->hGlobal, NULL); }
if (fRelease) { ReleaseStgMedium(pmedium); }
if (!hDib) { return ResultFromScode(E_OUTOFMEMORY); } FORMATETC foretcTmp = *pformatetc; STGMEDIUM pmedTmp = *pmedium; foretcTmp.cfFormat = CF_DIB; foretcTmp.tymed = TYMED_HGLOBAL; pmedTmp.pUnkForRelease = NULL; pmedTmp.tymed = TYMED_HGLOBAL; pmedTmp.hGlobal = hDib;
// Now that we have converted the bitmap data to DIB,
// SetData _back_ on ourselves again with the DIB info
return SetDataWDO(&foretcTmp, &pmedTmp, TRUE, NULL); }
//+-------------------------------------------------------------------------
//
// Member: CGenObject::Dump, public (_DEBUG only)
//
// Synopsis: return a string containing the contents of the data members
//
// Effects:
//
// Arguments: [ppszDump] - an out pointer to a null terminated character array
// [ulFlag] - flag determining prefix of all newlines of the
// out character array (default is 0 - no prefix)
// [nIndentLevel] - will add a indent prefix after the other prefix
// for ALL newlines (including those with no prefix)
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies: [ppszDump] - argument
//
// Derivation:
//
// Algorithm: use dbgstream to create a string containing information on the
// content of data structures
//
// History: dd-mmm-yy Author Comment
// 01-Feb-95 t-ScottH author
//
// Notes:
//
//--------------------------------------------------------------------------
#ifdef _DEBUG
HRESULT CGenObject::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel) { int i; char *pszPrefix; char *pszDVASPECT; char *pszCLIPFORMAT; dbgstream dstrPrefix; dbgstream dstrDump(500);
// determine prefix of newlines
if ( ulFlag & DEB_VERBOSE ) { dstrPrefix << this << " _VB "; }
// determine indentation prefix for all newlines
for (i = 0; i < nIndentLevel; i++) { dstrPrefix << DUMPTAB; }
pszPrefix = dstrPrefix.str();
// put data members in stream
dstrDump << pszPrefix << "No. of References = " << m_ulRefs << endl;
pszDVASPECT = DumpDVASPECTFlags(m_dwAspect); dstrDump << pszPrefix << "Aspect flags = " << pszDVASPECT << endl; CoTaskMemFree(pszDVASPECT);
dstrDump << pszPrefix << "Size = " << m_dwSize << endl;
dstrDump << pszPrefix << "Width = " << m_lWidth << endl;
dstrDump << pszPrefix << "Height = " << m_lHeight << endl;
dstrDump << pszPrefix << "Presentation Handle = " << m_hPres << endl;
pszCLIPFORMAT = DumpCLIPFORMAT(m_cfFormat); dstrDump << pszPrefix << "Clip Format = " << pszCLIPFORMAT << endl; CoTaskMemFree(pszCLIPFORMAT);
dstrDump << pszPrefix << "pCacheNode = " << m_pCacheNode << endl;
// cleanup and provide pointer to character array
*ppszDump = dstrDump.str();
if (*ppszDump == NULL) { *ppszDump = UtDupStringA(szDumpErrorMessage); }
CoTaskMemFree(pszPrefix);
return NOERROR; }
#endif // _DEBUG
//+-------------------------------------------------------------------------
//
// Function: DumpCGenObject, public (_DEBUG only)
//
// Synopsis: calls the CGenObject::Dump method, takes care of errors and
// returns the zero terminated string
//
// Effects:
//
// Arguments: [pGO] - pointer to CGenObject
// [ulFlag] - flag determining prefix of all newlines of the
// out character array (default is 0 - no prefix)
// [nIndentLevel] - will add a indent prefix after the other prefix
// for ALL newlines (including those with no prefix)
//
// Requires:
//
// Returns: character array of structure dump or error (null terminated)
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 01-Feb-95 t-ScottH author
//
// Notes:
//
//--------------------------------------------------------------------------
#ifdef _DEBUG
char *DumpCGenObject(CGenObject *pGO, ULONG ulFlag, int nIndentLevel) { HRESULT hresult; char *pszDump;
if (pGO == NULL) { return UtDupStringA(szDumpBadPtr); }
hresult = pGO->Dump(&pszDump, ulFlag, nIndentLevel);
if (hresult != NOERROR) { CoTaskMemFree(pszDump);
return DumpHRESULT(hresult); }
return pszDump; }
#endif // _DEBUG
//+-------------------------------------------------------------------------
//
// Function: DibDraw
//
// Synopsis: Draws a device independent bitmap
//
// Effects:
//
// Arguments: [hDib] -- the bitmap
// [hdc] -- the device context
// [lprc] -- the bounding rectangle
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Algorithm: Sets the palette to the palette in the dib, sizes and draws
// the dib to the bounding rectangle. The original palette
// is then restored
//
// History: dd-mmm-yy Author Comment
// 23-Nov-93 alexgo 32bit port
// 07-Dec-93 alexgo merged RC9 16bit changes. The
// error-handling code used to reset the
// old palette and then RealizePalette.
// The call to RealizePalette was removed
// 11-May-94 davepl Added support for BITMAPCOREINFO dibs
// 17-Jul-94 davepl Added 12, 32 bpp support
//
// Notes:
//
//--------------------------------------------------------------------------
INTERNAL DibDraw (HANDLE hDib, HDC hdc, LPCRECTL lprc) { VDATEHEAP();
HRESULT error = ResultFromScode(E_DRAW); BYTE FAR * lpDib; HANDLE hPalette = NULL; HPALETTE hLogPalette = NULL, hOldPalette = NULL; LPLOGPALETTE lpLogPalette; WORD wPalSize; DWORD cbHeaderSize; BOOL fNeedPalette = FALSE; WORD iHeight; WORD iWidth; int iOffBits; BITMAPINFO * pbi = NULL; BOOL fWeAllocd = FALSE;
if (NULL == hDib) { return ResultFromScode(OLE_E_BLANK); }
Assert(lprc);
if (NULL == (lpDib = (BYTE FAR *) GlobalLock (hDib))) { return ResultFromScode(E_OUTOFMEMORY); }
// The bitmap header could be BITMAPINFOHEADER or
// BITMAPCOREHEADER. Set our cbHeaderSize flag
// based on the header type. We can then calculate the
// palette size and the offset to the raw data bits. If
// we don't recognize either one of the structures here,
// we bail; the data is likely corrupt.
// Just a thought here: could be dangerous if the struct
// is not LONG aligned and this is run on an Alpha. As far
// as I've been able to find out, they always are long
// aligned
cbHeaderSize = *((ULONG *) lpDib); LEWARN( cbHeaderSize > 500, "Struct size > 500, likely invalid!"); if (cbHeaderSize == sizeof(BITMAPINFOHEADER)) { // Note: this assignment can overflow the WORD wPalSize,
// but the UtPaletteSize function asserts against this
wPalSize = (WORD) UtPaletteSize((LPBITMAPINFOHEADER)lpDib);
iWidth = (WORD) ((LPBITMAPINFOHEADER)lpDib)->biWidth; iHeight = (WORD) ((LPBITMAPINFOHEADER)lpDib)->biHeight; pbi = (LPBITMAPINFO) lpDib; iOffBits = wPalSize + sizeof(BITMAPINFOHEADER); } else if (cbHeaderSize == sizeof(BITMAPCOREHEADER)) {
// Since the clipboard itself does not support COREINFO
// bitmaps, we will not support them in the presentation
// cache. When (if) windows adds complete support for
// these, the code is here and ready.
#ifndef CACHE_SUPPORT_COREINFO
error = DV_E_TYMED; goto errRtn; #else
// Special case 32 bpp bitmaps
// If we have a palette, we need to calculate its size and
// allocate enough memory for the palette entries (remember
// we get one entry for free with the BITMAPINFO struct, so
// less one). If we don't have a palette, we only need to
// allocate enough for the BITMAPINFO struct itself.
// Bitmaps with more than 64K colors lack a palette; they
// use direct RGB entries in the pixels
if ((((LPBITMAPCOREHEADER)lpDib)->bcBitCount) > 16) { wPalSize = 0; pbi = (BITMAPINFO *) PrivMemAlloc(sizeof(BITMAPINFO)); } else { wPalSize = sizeof(RGBQUAD) * (1 << (((LPBITMAPCOREHEADER)lpDib)->bcBitCount)); pbi = (BITMAPINFO *) PrivMemAlloc(sizeof(BITMAPINFO) + wPalSize - sizeof(RGBQUAD)); } if (NULL == pbi) { return ResultFromScode(E_OUTOFMEMORY); } else { fWeAllocd = TRUE; }
// Grab the width and height
iWidth = ((LPBITMAPCOREHEADER)lpDib)->bcWidth; iHeight = ((LPBITMAPCOREHEADER)lpDib)->bcHeight; // Clear all the fields. Don't worry about color table, as if
// it exists we will set the entries explicitly.
memset(pbi, 0, sizeof(BITMAPINFOHEADER));
// Transfer what fields we do have from the COREINFO
pbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pbi->bmiHeader.biWidth = iWidth; pbi->bmiHeader.biHeight = iHeight; pbi->bmiHeader.biPlanes = 1; pbi->bmiHeader.biBitCount = ((LPBITMAPCOREHEADER)lpDib)->bcBitCount;
// Set up the color palette, if required.
// Note that we must translate from RGBTRIPLE entries to
// RGBQUAD.
for (WORD c = 0; c < wPalSize / sizeof(RGBQUAD); c++) { pbi->bmiColors[c].rgbRed = ((BITMAPCOREINFO *)lpDib)->bmciColors[c].rgbtRed; pbi->bmiColors[c].rgbBlue = ((BITMAPCOREINFO *)lpDib)->bmciColors[c].rgbtBlue; pbi->bmiColors[c].rgbGreen = ((BITMAPCOREINFO *)lpDib)->bmciColors[c].rgbtGreen; pbi->bmiColors[c].rgbReserved = 0; } iOffBits = wPalSize + sizeof(BITMAPCOREHEADER); #endif
} else { error = E_FAIL; goto errRtn; } // if color info exists, create a palette from the data and select it
// images with < 16 bpp do not have a palette from which we can create
// a logical palette
fNeedPalette = ((LPBITMAPINFOHEADER)lpDib)->biBitCount < 16; if (wPalSize && fNeedPalette) { hLogPalette = (HPALETTE)DibMakeLogPalette(lpDib + cbHeaderSize, wPalSize, &lpLogPalette); if (NULL == hLogPalette) { error = ResultFromScode(E_OUTOFMEMORY); goto errRtn; }
if (NULL == (hPalette = CreatePalette (lpLogPalette))) { goto errRtn; }
// we're done with lpLogPalette now, so unlock it
// (DibMakeLogPalette got the pointer via a GlobalLock)
GlobalUnlock(hLogPalette); // select as a background palette
hOldPalette = SelectPalette (hdc, (HPALETTE)hPalette, TRUE); if (NULL == hOldPalette) { goto errRtn; }
LEVERIFY( 0 < RealizePalette(hdc) ); }
// size the dib to fit our drawing rectangle and draw it
if (!StretchDIBits( hdc, // HDC
lprc->left, // XDest
lprc->top, // YDest
lprc->right - lprc->left, // nDestWidth
lprc->bottom - lprc->top, // nDestHeight
0, // XSrc
0, // YSrc
iWidth, // nSrcWidth
iHeight, // nSrcHeight
lpDib + iOffBits, // lpBits
pbi, // lpBitsInfo
DIB_RGB_COLORS, // iUsage
SRCCOPY // dwRop
) ) { error = ResultFromScode(E_DRAW); } else { error = NOERROR; }
errRtn:
// We only want to free the header if it is was one which we allocated,
// which can only happen when we were give a core header type in the
// first place
if (fWeAllocd) { PrivMemFree(pbi); }
if (lpDib) { GlobalUnlock (hDib); } // if color palette exists do the following
if (fNeedPalette) { hOldPalette = (HPALETTE)(OleIsDcMeta (hdc) ? GetStockObject(DEFAULT_PALETTE) : (HPALETTE)hOldPalette); if (hOldPalette) { LEVERIFY( SelectPalette (hdc, hOldPalette, TRUE) ); // Do we need to realize the palette? [Probably not]
}
if (hPalette) { LEVERIFY( DeleteObject (hPalette) ); }
if (hLogPalette) { LEVERIFY( NULL == GlobalFree (hLogPalette) ); } }
return error; }
//+-------------------------------------------------------------------------
//
// Function: DibMakeLogPalette
//
// Synopsis: Makes a logical palette from a byte array of color info
//
// Effects:
//
// Arguments: [lpColorData] -- the color data
// [wDataSize] -- size of the data
// [lplpLogPalette] -- where to put a pointer to the
//
// Requires:
//
// Returns: HANDLE to the logical palette (must be global unlock'ed
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 23-Nov-93 alexgo 32bit port
//
// Notes: The caller MUST call GlobalUnlock on the returned handle
// to avoid a memory leak (*lplpLogPalette is the result
// of a global lock on the handle)
//
//--------------------------------------------------------------------------
#pragma SEG(DibMakeLogPalette)
INTERNAL_(HANDLE) DibMakeLogPalette( BYTE FAR * lpColorData, WORD wDataSize, LPLOGPALETTE FAR *lplpLogPalette) { VDATEHEAP();
HANDLE hLogPalette=NULL; LPLOGPALETTE lpLogPalette; DWORD dwLogPalSize = wDataSize + 2 * sizeof(WORD);
if (NULL == (hLogPalette = GlobalAlloc(GMEM_MOVEABLE, dwLogPalSize))) { return NULL; }
if (NULL == (lpLogPalette = (LPLOGPALETTE) GlobalLock (hLogPalette))) { LEVERIFY( NULL == GlobalFree (hLogPalette)); return NULL; }
*lplpLogPalette = lpLogPalette; DibFillPaletteEntries(lpColorData, wDataSize, lpLogPalette); return hLogPalette; }
//+-------------------------------------------------------------------------
//
// Function: DibFillPaletteEntries
//
// Synopsis: Fills the logical palette with the color info in [lpColorData]
//
// Effects:
//
// Arguments: [lpColorData] -- the color info
// [wDataSize] -- the size of the color info
// [lpLogPalette] -- the logical palette
//
// Requires:
//
// Returns: void
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 23-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
INTERNAL_(void) DibFillPaletteEntries( BYTE FAR * lpColorData, WORD wDataSize, LPLOGPALETTE lpLogPalette) { VDATEHEAP();
LPPALETTEENTRY lpPE; RGBQUAD FAR * lpQuad;
lpLogPalette->palVersion = 0x300; lpLogPalette->palNumEntries = wDataSize / sizeof(PALETTEENTRY);
/* now convert RGBQUAD to PALETTEENTRY as we copy color info */ for (lpQuad = (RGBQUAD far *)lpColorData, lpPE = (LPPALETTEENTRY)lpLogPalette->palPalEntry, wDataSize /= sizeof(RGBQUAD); wDataSize--; ++lpQuad,++lpPE) { lpPE->peFlags = NULL; lpPE->peRed = lpQuad->rgbRed; lpPE->peBlue = lpQuad->rgbBlue; lpPE->peGreen = lpQuad->rgbGreen; } }
#endif
|