NT4/private/ole32/ole232/util/ole2util.cpp
2020-09-30 17:12:29 +02:00

1106 lines
28 KiB
C++

//+----------------------------------------------------------------------------
//
// File:
// ole2util.cpp
//
// Contents:
// Ole internal utility routines
//
// Classes:
//
// Functions:
//
// History:
// 06/01/94 - AlexGo - UtQueryPictFormat now supports
// enhanced metafiles
// 03/18/94 - AlexGo - fixed UtGetPresStreamName (incorrect
// string processing)
// 01/11/94 - ChrisWe - don't reference unlocked handle in
// UtConvertBitmapToDib
// 01/11/94 - alexgo - added VDATEHEAP macro to every function
// 12/07/93 - ChrisWe - removed incorrect uses of (LPOLESTR);
// removed duplicate GetClassFromDataObj function, which
// is the same as UtGetClassID
// 11/30/93 - ChrisWe - continue file cleanup; don't open
// streams in UtRemoveExtraOlePresStreams()
// 11/28/93 - ChrisWe - file cleanup and inspection;
// reformatted many functions
// 11/22/93 - ChrisWe - replace overloaded ==, != with
// IsEqualIID and IsEqualCLSID
// 06/28/93 - SriniK - added UtGetDibExtents
// 11/16/92 - JasonFul - created; moved contents here from util.cpp
//
//-----------------------------------------------------------------------------
#include <le2int.h>
#pragma SEG(ole2util)
NAME_SEG(Ole2Utils)
ASSERTDATA
#define WIDTHBYTES(i) ((i+31)/32*4)
#define PALETTESIZE 256 /* Number of entries in the system palette */
// REVIEW, according to the spec, IDataObject::EnumFormatEtc() is only
// required to service one dwDirection DATADIR_ value at a time. This
// function has been asking it to do more than one at a time, and expecting
// return of FORMATETCs that match all the requested directions. Code
// seen in OleRegEnumFormatEtc() checks on creation, and fails if any
// value other than plain DATADIR_GET or plain DATADIR_SET is specified
// so this has clearly never worked for OLE1, or registration database lookups
// since the only caller of UtIsFormatSupported has always asked for both
// at the same time.
#pragma SEG(UtIsFormatSupported)
FARINTERNAL_(BOOL) UtIsFormatSupported(IDataObject FAR* lpDataObj,
DWORD dwDirection, CLIPFORMAT cfFormat)
{
VDATEHEAP();
FORMATETC formatetc; // a place to fetch formats from the enumerator
IEnumFORMATETC FAR* penm; // enumerates the formats of [lpDataObj]
ULONG ulNumFetched; // a count of the number of formats fetched
HRESULT error; // the error state so far
// try to get the enumerator from the data object
error = lpDataObj->EnumFormatEtc(dwDirection, &penm);
if (error != NOERROR)
{
if (FAILED(error))
return FALSE;
else
{
CLSID clsid;
// Use reg db; this case is primarily for the OLE1
// compatibility code since it may talk to a data
// object from a server in the same process as
// the server.
if (UtGetClassID(lpDataObj, &clsid) != TRUE)
return(FALSE);
// synthesize an enumerator
// REVIEW, if the data object is synthesized for
// the OLE1 object, why doesn't that implementation
// go ahead and synthesize this? Why does it have
// to be done like this? What if it's on the clipboard
// and someone wants to use it?
if (OleRegEnumFormatEtc(clsid, dwDirection, &penm)
!= NOERROR)
return FALSE;
Assert(penm);
}
}
// check for the format we're looking for
while(NOERROR == (error = penm->Next(1, &formatetc, &ulNumFetched)))
{
if ((ulNumFetched == 1) && (formatetc.cfFormat == cfFormat))
break;
}
// release the enumerator
penm->Release();
// if error isn't S_FALSE, we fetched an item, and broke out of the
// while loop above --> the format was found. Return TRUE indicating
// that the format is supported
return(error == NOERROR ? TRUE : FALSE);
}
#pragma SEG(UtDupPalette)
FARINTERNAL_(HPALETTE) UtDupPalette(HPALETTE hpalette)
{
VDATEHEAP();
WORD cEntries; // holds the number of entries in the palette
HANDLE hLogPal; // ia a handle to a new logical palette
LPLOGPALETTE pLogPal; // is a pointer to the new logical palette
HPALETTE hpaletteNew = NULL; // the new palette we will return
if (0 == GetObject(hpalette, sizeof(cEntries), &cEntries))
return(NULL);
if (NULL == (hLogPal = GlobalAlloc(GMEM_MOVEABLE,
sizeof (LOGPALETTE) +
cEntries * sizeof (PALETTEENTRY))))
return(NULL);
if (NULL == (pLogPal = (LPLOGPALETTE)GlobalLock(hLogPal)))
goto errRtn;
if (0 == GetPaletteEntries(hpalette, 0, cEntries,
pLogPal->palPalEntry))
goto errRtn;
pLogPal->palVersion = 0x300;
pLogPal->palNumEntries = cEntries;
if (NULL == (hpaletteNew = CreatePalette(pLogPal)))
goto errRtn;
errRtn:
if (pLogPal)
GlobalUnlock(hLogPal);
if (hLogPal)
GlobalFree(hLogPal);
AssertSz(hpaletteNew, "Warning: UtDupPalette Failed");
return(hpaletteNew);
}
//+-------------------------------------------------------------------------
//
// Function: UtFormatToTymed
//
// Synopsis: gets the right TYMED for the given rendering format
//
// Effects:
//
// Arguments: [cf] -- the clipboard format
//
// Requires:
//
// Returns: one of the TYMED enumeration
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 07-Jul-94 alexgo added EMF's
//
// Notes: This should only be called for formats that we can
// render
//
//--------------------------------------------------------------------------
#pragma SEG(UtFormatToTymed)
FARINTERNAL_(DWORD) UtFormatToTymed(CLIPFORMAT cf)
{
VDATEHEAP();
if( cf == CF_METAFILEPICT )
{
return TYMED_MFPICT;
}
else if( cf == CF_BITMAP )
{
return TYMED_GDI;
}
else if( cf == CF_DIB )
{
return TYMED_HGLOBAL;
}
else if( cf == CF_ENHMETAFILE )
{
return TYMED_ENHMF;
}
else if( cf == CF_PALETTE )
{
LEWARN(1,"Trying to render CF_PALETTE");
return TYMED_GDI;
}
LEDebugOut((DEB_WARN, "WARNING: trying to render clipformat (%lx)\n",
cf));
return TYMED_HGLOBAL;
}
//+-------------------------------------------------------------------------
//
// Function: UtQueryPictFormat
//
// Synopsis: finds our "preferred" drawing formatetc from the given
// data object
//
// Effects:
//
// Arguments: [lpSrcDataObj] -- the source data object
// [lpforetc] -- where to stuff the preferred format
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 alexgo rewrite/now supports Enhanced Metafiles
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(UtQueryPictFormat)
FARINTERNAL_(BOOL) UtQueryPictFormat(LPDATAOBJECT lpSrcDataObj,
LPFORMATETC lpforetc)
{
FORMATETC foretctemp; // local copy of current values of format desc
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN UtQueryPictFormat ( %p , %p )\n",
NULL, lpSrcDataObj, lpforetc));
// copy format descriptor
foretctemp = *lpforetc;
// set values and query for our preferred formats in order of
// preference
foretctemp.cfFormat = CF_METAFILEPICT;
foretctemp.tymed = TYMED_MFPICT;
if (lpSrcDataObj->QueryGetData(&foretctemp) == NOERROR)
{
goto QuerySuccess;
}
foretctemp.cfFormat = CF_ENHMETAFILE;
foretctemp.tymed = TYMED_ENHMF;
if( lpSrcDataObj->QueryGetData(&foretctemp) == NOERROR )
{
goto QuerySuccess;
}
foretctemp.cfFormat = CF_DIB;
foretctemp.tymed = TYMED_HGLOBAL;
if (lpSrcDataObj->QueryGetData(&foretctemp) == NOERROR)
{
goto QuerySuccess;
}
foretctemp.cfFormat = CF_BITMAP;
foretctemp.tymed = TYMED_GDI;
if (lpSrcDataObj->QueryGetData(&foretctemp) == NOERROR)
{
goto QuerySuccess;
}
LEDebugOut((DEB_ITRACE, "%p OUT UtQueryPictFormat ( %lu )\n",
NULL, FALSE));
return FALSE;
QuerySuccess:
// data object supports this format; change passed in
// format to match
lpforetc->cfFormat = foretctemp.cfFormat;
lpforetc->tymed = foretctemp.tymed;
// return success
LEDebugOut((DEB_ITRACE, "%p OUT UtQueryPictFormat ( %lu )\n",
NULL, TRUE));
return(TRUE);
}
#pragma SEG(UtConvertDibToBitmap)
FARINTERNAL_(HBITMAP) UtConvertDibToBitmap(HANDLE hDib)
{
VDATEHEAP();
LPBITMAPINFOHEADER lpbmih;
HDC hdc; // the device context to create the bitmap for
size_t uBitsOffset; // the offset to where the image begins in the DIB
HBITMAP hBitmap; // the bitmap we'll return
if (!(lpbmih = (LPBITMAPINFOHEADER)GlobalLock(hDib)))
return(NULL);
if (!(hdc = GetDC(NULL))) // Get screen DC.
{
// REVIEW: we may have to use the target device of this
// cache node.
return(NULL);
}
uBitsOffset = sizeof(BITMAPINFOHEADER) +
(lpbmih->biClrUsed ? lpbmih->biClrUsed :
UtPaletteSize(lpbmih));
hBitmap = CreateDIBitmap(hdc, lpbmih, CBM_INIT,
((BYTE *)lpbmih)+uBitsOffset,
(LPBITMAPINFO) lpbmih, DIB_RGB_COLORS);
// release the DC
ReleaseDC(NULL, hdc);
return hBitmap;
}
//+----------------------------------------------------------------------------
//
// Function:
// UtConvertBitmapToDib, internal
//
// Synopsis:
// Creates a Device Independent Bitmap capturing the content of
// the argument bitmap.
//
// Arguments:
// [hBitmap] -- Handle to the bitmap to convert
// [hpal] -- color palette for the bitmap; may be null for
// default stock palette
//
// Returns:
// Handle to the DIB. May be null if any part of the conversion
// failed.
//
// Notes:
//
// History:
// 11/29/93 - ChrisWe - file inspection and cleanup
// 07/18/94 - DavePl - fixed for 16, 32, bpp bitmaps
//
//-----------------------------------------------------------------------------
FARINTERNAL_(HANDLE) UtConvertBitmapToDib(HBITMAP hBitmap, HPALETTE hpal)
{
VDATEHEAP();
HDC hScreenDC;
BITMAP bm; // bitmap for hBitmap
UINT uBits; // number of color bits for bitmap
size_t uBmiSize; // size of bitmap info for the DIB
size_t biSizeImage; // temp to hold value in the handle memory
HANDLE hBmi; // handle for the new DIB bitmap we'll create
LPBITMAPINFOHEADER lpBmi; // pointer to the actual data area for DIB
HANDLE hDib = NULL; // the DIB we'll return
BOOL fSuccess = FALSE;
DWORD dwCompression;
BOOL fDeletePalette = FALSE;
if (NULL == hBitmap)
{
return(NULL);
}
// if no palette provided, use the default
if (NULL == hpal)
{
// This block fixes NTBUG #13029. The problem is that on a palette
// device (ie a 256 color video driver), we don't get passed the palette
// that is used by the DDB. So, we build the palette based on what
// is currently selected into the system palette.
// POSTPPC:
//
// We should change the clipboard code that calls this to ask for
// CF_PALETTE from the IDataObject that the DDB was obtained from, that
// way we know we get the colors that the calling app really intended
HDC hDCGlobal = GetDC(NULL);
int iRasterCaps = GetDeviceCaps(hDCGlobal, RASTERCAPS);
ReleaseDC(NULL, hDCGlobal);
if ((iRasterCaps & RC_PALETTE))
{
// Based the following code from the win sdk MYPAL example program.
// this creates a palette out of the currently active palette.
HANDLE hLogPal = GlobalAlloc (GHND,
(sizeof (LOGPALETTE) +
(sizeof (PALETTEENTRY) * (PALETTESIZE))));
// if we are OOM, return failure now, because we aren't going
// to make it through the allocations later on.
if (!hLogPal)
return NULL;
LPLOGPALETTE pLogPal = (LPLOGPALETTE)GlobalLock (hLogPal);
// 0x300 is a magic number required by GDI
pLogPal->palVersion = 0x300;
pLogPal->palNumEntries = PALETTESIZE;
// fill in intensities for all palette entry colors
for (int iLoop = 0; iLoop < PALETTESIZE; iLoop++)
{
*((WORD *) (&pLogPal->palPalEntry[iLoop].peRed)) = (WORD)iLoop;
pLogPal->palPalEntry[iLoop].peBlue = 0;
pLogPal->palPalEntry[iLoop].peFlags = PC_EXPLICIT;
}
// create a logical color palette according the information
// in the LOGPALETTE structure.
hpal = CreatePalette ((LPLOGPALETTE) pLogPal) ;
GlobalUnlock(hLogPal);
GlobalFree(hLogPal);
if (!hpal)
return NULL;
fDeletePalette = TRUE;
}
else
{
hpal = (HPALETTE)GetStockObject(DEFAULT_PALETTE);
}
}
if (NULL == GetObject(hBitmap, sizeof(bm), (LPVOID)&bm))
{
return(NULL);
}
uBits = bm.bmPlanes * bm.bmBitsPixel;
// Based on the number of bits per pixel, set up the size
// of the color table, and the compression type as per the
// the following table:
//
//
// BPP Palette Size Compression
// ~~~ ~~~~~~~~~~~~ ~~~~~~~~~~~
// 1,2,4,8 2^BPP * sizeof(RGBQUAD) None
// 16, 32 3 * sizeof(DWORD) masks BI_BITFIELDS
// 24 0 None
if (16 == bm.bmBitsPixel || 32 == bm.bmBitsPixel)
{
uBmiSize = sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD);
dwCompression = BI_BITFIELDS;
}
else if (24 == bm.bmBitsPixel)
{
uBmiSize = sizeof(BITMAPINFOHEADER);
dwCompression = BI_RGB;
}
else
{
Assert( bm.bmBitsPixel == 1 ||
bm.bmBitsPixel == 2 ||
bm.bmBitsPixel == 4 ||
bm.bmBitsPixel == 8 );
// VGA and EGA are planar devices on Chicago, so uBits needs
// to be used when determining the size of the bitmap info +
// the size of the color table.
uBmiSize = sizeof(BITMAPINFOHEADER) +
(1 << uBits) * sizeof(RGBQUAD);
dwCompression = BI_RGB;
}
// Allocate enough memory to hold the BITMAPINFOHEADER
hBmi = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, (DWORD)uBmiSize);
if (NULL == hBmi)
{
return NULL;
}
lpBmi = (LPBITMAPINFOHEADER) GlobalLock(hBmi);
if (NULL == lpBmi)
{
GlobalFree(hBmi);
return NULL;
}
// Set up any interesting non-zero fields
lpBmi->biSize = (LONG)sizeof(BITMAPINFOHEADER);
lpBmi->biWidth = (LONG) bm.bmWidth;
lpBmi->biHeight = (LONG) bm.bmHeight;
lpBmi->biPlanes = 1;
lpBmi->biBitCount = uBits;
lpBmi->biCompression = dwCompression;
// Grab the screen DC and set out palette into it
hScreenDC = GetDC(NULL);
if (NULL == hScreenDC)
{
GlobalUnlock(hBmi);
goto errRtn;
}
// Call GetDIBits with a NULL lpBits parm, so that it will calculate
// the biSizeImage field for us
GetDIBits(hScreenDC, // DC
hBitmap, // Bitmap handle
0, // First scan line
bm.bmHeight, // Number of scan lines
NULL, // Buffer
(LPBITMAPINFO)lpBmi, // BITMAPINFO
DIB_RGB_COLORS);
// If the driver did not fill in the biSizeImage field, make one up
if (0 == lpBmi->biSizeImage)
{
LEDebugOut((DEB_WARN, "WARNING: biSizeImage was not computed for us\n"));
lpBmi->biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * uBits) * bm.bmHeight;
}
// Realloc the buffer to provide space for the bits. Use a new handle so
// that in the failure case we do not lose the exiting handle, which we
// would need to clean up properly.
biSizeImage = lpBmi->biSizeImage;
GlobalUnlock(hBmi);
hDib = GlobalReAlloc(hBmi, (uBmiSize + biSizeImage), GMEM_MOVEABLE);
if (NULL == hDib)
{
goto errRtn;
}
// If the realloc succeeded, we can get rid of the old handle
hBmi = NULL;
// re-acquire the pointer to the handle
lpBmi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
if (NULL == lpBmi)
{
goto errRtn;
}
hpal = SelectPalette(hScreenDC, hpal, FALSE);
RealizePalette(hScreenDC);
// Call GetDIBits with a NON-NULL lpBits parm, and get the actual bits
if (GetDIBits(hScreenDC, // DC
hBitmap, // HBITMAP
0, // First scan line
(WORD)lpBmi->biHeight, // Count of scan lines
((BYTE FAR *)lpBmi)+uBmiSize, // Bitmap bits
(LPBITMAPINFO)lpBmi, // BITMAPINFOHEADER
DIB_RGB_COLORS) // Palette style
)
{
fSuccess = TRUE;
}
GlobalUnlock(hDib);
errRtn:
if (hScreenDC)
{
// Select back the old palette into the screen DC
SelectPalette(hScreenDC, hpal, FALSE);
ReleaseDC(NULL, hScreenDC);
}
if (fDeletePalette)
{
DeleteObject(hpal);
}
// If we failed, we need to free up the header and the DIB
// memory
if (FALSE == fSuccess)
{
if (hBmi)
{
GlobalFree(hBmi);
}
if (hDib)
{
GlobalFree(hDib);
hDib = NULL;
}
}
return(hDib);
}
//+----------------------------------------------------------------------------
//
// Function:
// UtPaletteSize, internal
//
// Synopsis:
// Returns the size of a color table for a palette given the
// number of bits of color desired.
//
// Basically, the number of color table entries is:
//
// 1BPP
// 1<<1 = 2
//
// 4BPP
// if pbmi->biClrUsed is not zero and is less than 16, then use pbmi->biClrUsed,
// otherwise use 1 << 4 = 16
//
// 8BPP
// if pbmi->biClrUsed is not zero and is less than 256, then use pbmi->biClrUsed,
// otherwise use 1 << 8 = 256
//
// 16BPP
// if pbmi->biCompression is BITFIELDS then there are three color entries,
// otherwise no color entries.
//
// 24BPP
// pbmi->biCompression must be BI_RGB, there is no color table.
//
// 32BPP
// if pbmi->biCompression is BITFIELDS then there are three color entries,
// otherwise no color entries.
//
//
// There is never a case with a color table larger than 256 colors.
//
// Arguments:
// [lpHeader] -- ptr to BITMAPINFOHEADER structure
//
// Returns:
// Size in bytes of color information
//
// Notes:
//
// History:
// 11/29/93 - ChrisWe - change bit count argument to unsigned,
// and return value to size_t
//
// 07/18/94 - DavePl - Fixed for 16, 24, 32bpp DIBs
//
//-----------------------------------------------------------------------------
FARINTERNAL_(size_t) UtPaletteSize(BITMAPINFOHEADER * pbmi)
{
DWORD dwSize;
WORD biBitCount = pbmi->biBitCount;
VDATEHEAP();
// Compute size of color table information in a DIB.
if (8 >= biBitCount)
{
if (pbmi->biClrUsed && (pbmi->biClrUsed < (DWORD) (1 << biBitCount)) )
{
dwSize = pbmi->biClrUsed * sizeof(RGBQUAD);
}
else
{
Assert(0 == pbmi->biClrUsed);
dwSize = (1 << biBitCount) * sizeof(RGBQUAD);
}
}
else if (BI_BITFIELDS == pbmi->biCompression)
{
Assert(24 != biBitCount); // BI_BITFIELDS should never be set for 24 bit.
dwSize = 3 * sizeof(RGBQUAD);
}
else
{
dwSize = 0;
}
Assert( (dwSize < 65536) && "Palette size overflows WORD");
return dwSize;
}
//+-------------------------------------------------------------------------
//
// Function: UtGetDibExtents
//
// Synopsis: Returns the size of the DIB in HIMETRIC units
//
// Effects:
//
// Arguments: [lpbmi] -- the BITMAPINFOHEADER for the DIB
// [plWidth] -- OUT param for width
// [plHeight] -- OUT param for height
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 04-Aug-94 Davepl Corrected logic
//
// Notes:
//
//--------------------------------------------------------------------------
FARINTERNAL_(void) UtGetDibExtents(LPBITMAPINFOHEADER lpbmi,
LONG FAR* plWidth, LONG FAR* plHeight)
{
VDATEHEAP();
#define HIMET_PER_METER 100000L // number of HIMETRIC units / meter
if (!(lpbmi->biXPelsPerMeter && lpbmi->biYPelsPerMeter))
{
HDC hdc;
hdc = GetDC(NULL);
lpbmi->biXPelsPerMeter = MulDiv(GetDeviceCaps(hdc, LOGPIXELSX),
10000, 254);
lpbmi->biYPelsPerMeter = MulDiv(GetDeviceCaps(hdc, LOGPIXELSY),
10000, 254);
ReleaseDC(NULL, hdc);
}
*plWidth = (lpbmi->biWidth * HIMET_PER_METER / lpbmi->biXPelsPerMeter);
*plHeight= (lpbmi->biHeight * HIMET_PER_METER / lpbmi->biYPelsPerMeter);
// no longer need this
#undef HIMET_PER_METER
}
#pragma SEG(UtGetClassID)
FARINTERNAL_(BOOL) UtGetClassID(LPUNKNOWN lpUnk, CLSID FAR* lpClsid)
{
VDATEHEAP();
LPOLEOBJECT lpOleObj; // IOleObject pointer
LPPERSIST lpPersist; // IPersist pointer
// try to ask it as an object
if (lpUnk->QueryInterface(IID_IOleObject,
(LPLPVOID)&lpOleObj) == NOERROR)
{
lpOleObj->GetUserClassID(lpClsid);
lpOleObj->Release();
return(TRUE);
}
// try to ask it as a persistent object
if (lpUnk->QueryInterface(IID_IPersist,
(LPLPVOID)&lpPersist) == NOERROR)
{
lpPersist->GetClassID(lpClsid);
lpPersist->Release();
return(TRUE);
}
*lpClsid = CLSID_NULL;
return(FALSE);
}
#pragma SEG(UtGetIconData)
FARINTERNAL UtGetIconData(LPDATAOBJECT lpSrcDataObj, REFCLSID rclsid,
LPFORMATETC lpforetc, LPSTGMEDIUM lpstgmed)
{
VDATEHEAP();
CLSID clsid = rclsid;
lpstgmed->tymed = TYMED_NULL;
lpstgmed->pUnkForRelease = NULL;
lpstgmed->hGlobal = NULL;
if (lpSrcDataObj)
{
if (lpSrcDataObj->GetData(lpforetc, lpstgmed) == NOERROR)
return NOERROR;
if (IsEqualCLSID(clsid, CLSID_NULL))
UtGetClassID(lpSrcDataObj, &clsid);
}
// get data from registration database
lpstgmed->hGlobal = OleGetIconOfClass(clsid, NULL, TRUE);
if (lpstgmed->hGlobal == NULL)
return ResultFromScode(E_OUTOFMEMORY);
else
lpstgmed->tymed = TYMED_MFPICT;
return NOERROR;
}
// Performs operation like COPY, MOVE, REMOVE etc.. on src, dst storages. The
// caller can specifiy which streams to be operated upon through
// grfAllowedStreams parameter.
STDAPI UtDoStreamOperation(LPSTORAGE pstgSrc, LPSTORAGE pstgDst, int iOpCode,
DWORD grfAllowedStmTypes)
{
VDATEHEAP();
HRESULT error; // error status so far
IEnumSTATSTG FAR* penumStg; // used to enumerate the storage elements
ULONG celtFetched; // how many storage elements were fetched
STATSTG statstg;
// get an enumerator over the source storage
if (error = pstgSrc->EnumElements(NULL, NULL, NULL, &penumStg))
return error;
// repeat for every storage
while(penumStg->Next(1, &statstg, &celtFetched) == NOERROR)
{
// operate on streams that we're interested in
if (statstg.type == STGTY_STREAM)
{
DWORD stmType;
// find the type of the stream
// REVIEW, we must have constants for these name
// prefixes!!!
switch (statstg.pwcsName[0])
{
case '\1':
stmType = STREAMTYPE_CONTROL;
break;
case '\2':
stmType = STREAMTYPE_CACHE;
break;
case '\3':
stmType = STREAMTYPE_CONTAINER;
break;
default:
stmType = (DWORD)STREAMTYPE_OTHER;
}
// check whether it should be operated upon
if (stmType & grfAllowedStmTypes)
{
switch(iOpCode)
{
#ifdef LATER
case OPCODE_COPY:
pstgDst->DestroyElement(
statstg.pwcsName);
error = pstgSrc->MoveElementTo(
statstg.pwcsName,
pstgDst,
statstg.pwcsName,
STGMOVE_COPY);
break;
case OPCODE_MOVE:
pstgDst->DestroyElement(
statstg.pwcsName);
error = pstgSrc->MoveElementTo(
statstg.pwcsName,
pstgDst,
statstg.pwcsName,
STGMOVE_MOVE);
break;
case OPCODE_EXCLUDEFROMCOPY:
AssertSz(FALSE, "Not yet implemented");
break;
#endif // LATER
case OPCODE_REMOVE:
error = pstgSrc->DestroyElement(
statstg.pwcsName);
break;
default:
AssertSz(FALSE, "Invalid opcode");
break;
}
}
}
// if the enumerator allocated a new name string, get rid of it
if (statstg.pwcsName)
PubMemFree(statstg.pwcsName);
// quit the enumeration loop if we've hit an error
if (error != NOERROR)
break;
}
// release the enumerator
penumStg->Release();
// return the error state
return error;
}
FARINTERNAL_(void) UtGetPresStreamName(LPOLESTR lpszName, int iStreamNum)
{
VDATEHEAP();
int i; // counts down the digits of iStreamNum
// count down the last three '0' characters of OLE_PRESENTATION_STREAM
// the -2 backs us up to the last character (remember the NULL
// terminator!)
for(lpszName += sizeof(OLE_PRESENTATION_STREAM)/sizeof(OLECHAR) - 2,
i = 3; i; --lpszName, --i)
{
*lpszName = OLESTR("0123456789")[iStreamNum % 10];
if( iStreamNum > 0 )
{
iStreamNum /= 10;
}
}
}
FARINTERNAL_(void) UtRemoveExtraOlePresStreams(LPSTORAGE pstg, int iStart)
{
VDATEHEAP();
HRESULT hr; // error code from stream deletion
OLECHAR szName[sizeof(OLE_PRESENTATION_STREAM)/sizeof(OLECHAR)];
// space for the stream names
// if the stream number is invalid, do nothing
if ((iStart < 0) || (iStart >= OLE_MAX_PRES_STREAMS))
return;
// create presentation stream name
_xstrcpy(szName, OLE_PRESENTATION_STREAM);
UtGetPresStreamName(szName, iStart);
// for each of these streams that exists, get rid of it
while((hr = pstg->DestroyElement(szName)) == NOERROR)
{
// if we've gotten to the end of the possible streams, quit
if (++iStart >= OLE_MAX_PRES_STREAMS)
break;
// Get the next presentation stream name
UtGetPresStreamName(szName, iStart);
}
// since the only reason these streams should be open, the first
// failure had better be that the file was not found, and not
// anything else (such as STG_E_ACCESSDENIED)
AssertSz(hr == STG_E_FILENOTFOUND,
"UtRemoveExtraOlePresStreams failure");
}
//+-------------------------------------------------------------------------
//
// Function: ConvertPixelsToHIMETRIC
//
// Synopsis: Converts a pixel dimension to HIMETRIC units
//
// Effects:
//
// Arguments: [hdcRef] -- the reference DC
// [ulPels] -- dimension in pixel measurement
// [pulHIMETRIC] -- OUT param of converted HIMETRIC result
// [tDimension] -- indicates XDIMENSION or YDIMENSION of input
//
// Returns: S_OK, E_FAIL
//
// Algorithm: screen_mm * input_pels HIMETRICS/
// ---------------------- * / == HIMETRICS
// screen_pels /mm
//
// History: dd-mmm-yy Author Comment
// 04-Aug-94 Davepl Created
//
// Notes: We need to know whether the input size is in the X or
// Y dimension, since the aspect ratio could vary
//
//--------------------------------------------------------------------------
FARINTERNAL ConvertPixelsToHIMETRIC (HDC hdcRef,
ULONG lPels,
ULONG * pulHIMETRIC,
DIMENSION tDimension)
{
VDATEHEAP();
VDATEPTROUT(pulHIMETRIC, ULONG *);
// Clear OUT parameter in case of error
*pulHIMETRIC = 0;
ULONG scrmm = 0;
ULONG scrpel = 0;
const ULONG HIMETRIC_PER_MM = 100;
// If we weren't given a reference DC, use the screen as a default
BOOL fLocalDC = FALSE;
if (NULL == hdcRef)
{
hdcRef = GetDC(NULL);
if (hdcRef)
{
fLocalDC = TRUE;
}
}
if (hdcRef)
{
Assert(tDimension == XDIMENSION || tDimension == YDIMENSION);
// Get the count of pixels and millimeters for the screen
if (tDimension == XDIMENSION)
{
scrmm = GetDeviceCaps(hdcRef, HORZSIZE);
scrpel = GetDeviceCaps(hdcRef, HORZRES);
}
else
{
scrmm = GetDeviceCaps(hdcRef, VERTSIZE);
scrpel = GetDeviceCaps(hdcRef, VERTRES);
}
// If we had to create a temporary DC, it can be released now
if (TRUE == fLocalDC)
{
ReleaseDC(NULL, hdcRef);
}
}
// If we successfully obtained the DC's size and resolution,
// we can compute the HIMETRIC value.
if (scrmm && scrpel)
{
*pulHIMETRIC = (scrmm * lPels * HIMETRIC_PER_MM) / scrpel;
return S_OK;
}
return E_FAIL;
}