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.
 
 
 
 
 
 

1904 lines
43 KiB

//+-------------------------------------------------------------------------
//
// 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