/****************************** Module Header ******************************\
* Module Name: BM.C
*
* Handles all API routines for the bitmap sub-dll of the ole dll.
*
* Created: 1990
*
* Copyright (c) 1990, 1991 Microsoft Corporation
*
* History:
* Raor,Srinik (../../1990,91) Designed, coded
* Curts create NT version
*
\***************************************************************************/
#include <windows.h>
#include "dll.h"
#include "pict.h"
extern int maxPixelsX, maxPixelsY;
void INTERNAL GetHimetricUnits(HBITMAP, LPPOINT);
#ifdef WIN16
#pragma alloc_text(_TEXT, BmSaveToStream, BmStreamWrite, BmLoadFromStream, BmStreamRead, GetBytes, PutBytes, PutStrWithLen, BmQueryBounds, BmChangeData, BmCopy, BmDuplicate, BmUpdateStruct, GetHimetricUnits)
#endif
OLEOBJECTVTBL vtblBM = {
ErrQueryProtocol, // check whether the speced protocol is supported
BmRelease, // Release
ErrShow, // Show
ErrPlay, // play
BmGetData, // Get the object data
ErrSetData, // Set the object data
ErrSetTargetDevice,//
ErrSetBounds, // set viewport bounds
BmEnumFormat, // enumerate supported formats
ErrSetColorScheme, //
BmRelease, // delete
ErrSetHostNames, //
BmSaveToStream, // write to file
BmClone, // clone object
ErrCopyFromLink, // Create embedded from Link
BmEqual, // compares the given objects for data equality
BmCopy, // copy to clip
BmDraw, // draw the object
ErrActivate, // open
ErrExecute, // excute
ErrClose, // Stop
ErrUpdate, // Update
ErrReconnect, // Reconnect
ErrObjectConvert, // convert object to specified type
ErrGetUpdateOptions,// update options
ErrSetUpdateOptions,// update options
ObjRename, // Change Object name
ObjQueryName, // Get current object name
ObjQueryType, // Object type
BmQueryBounds, // QueryBounds
ObjQuerySize, // Find the size of the object
ErrQueryOpen, // Query open
ErrQueryOutOfDate, // query whether object is current
ErrQueryRelease, // release related stuff
ErrQueryRelease,
ErrQueryReleaseMethod,
ErrRequestData, // requestdata
ErrObjectLong, // objectLong
BmChangeData // change data of the existing object
};
OLESTATUS FARINTERNAL BmRelease (LPOLEOBJECT lpoleobj)
{
LPOBJECT_BM lpobj = (LPOBJECT_BM)lpoleobj;
HOBJECT hobj;
if (lpobj->hBitmap) {
DeleteObject (lpobj->hBitmap);
lpobj->hBitmap = NULL;
}
if (lpobj->head.lhclientdoc)
DocDeleteObject ((LPOLEOBJECT) lpobj);
if (hobj = lpobj->head.hobj){
lpobj->head.hobj = NULL;
GlobalUnlock (hobj);
GlobalFree (hobj);
}
return OLE_OK;
}
OLESTATUS FARINTERNAL BmSaveToStream (
LPOLEOBJECT lpoleobj,
LPOLESTREAM lpstream
){
DWORD dwFileVer = GetFileVersion(lpoleobj);
LPOBJECT_BM lpobj = (LPOBJECT_BM)lpoleobj;
DWORD dwSize = lpobj->sizeBytes - sizeof(BITMAP) + sizeof(WIN16BITMAP);
if (!lpobj->hBitmap || !lpobj->sizeBytes)
return OLE_ERROR_BLANK;
if (PutBytes (lpstream, (LPSTR) &dwFileVer, sizeof(LONG)))
return OLE_ERROR_STREAM;
if (PutBytes (lpstream, (LPSTR) &lpobj->head.ctype, sizeof(LONG)))
return OLE_ERROR_STREAM;
if (PutStrWithLen(lpstream, (LPSTR)"BITMAP"))
return OLE_ERROR_STREAM;
if (!PutBytes (lpstream, (LPSTR) &lpobj->head.cx, sizeof(LONG))) {
if (!PutBytes (lpstream, (LPSTR) &lpobj->head.cy, sizeof(LONG)))
if (!PutBytes (lpstream, (LPSTR) &dwSize, sizeof(DWORD)))
return BmStreamWrite (lpstream, lpobj);
}
return OLE_ERROR_STREAM;
}
OLESTATUS FARINTERNAL BmClone (
LPOLEOBJECT lpoleobj,
LPOLECLIENT lpclient,
LHCLIENTDOC lhclientdoc,
OLE_LPCSTR lpobjname,
LPOLEOBJECT FAR * lplpoleobj
){
LPOBJECT_BM lpobjsrc = (LPOBJECT_BM)lpoleobj;
LPOBJECT_BM FAR * lplpobj = (LPOBJECT_BM FAR *)lplpoleobj;
if (!CheckClientDoc ((LPCLIENTDOC)lhclientdoc))
return OLE_ERROR_HANDLE;
if (!(*lplpobj = BmCreateObject (lpobjsrc->hBitmap, lpclient, FALSE,
lhclientdoc, lpobjname,
lpobjsrc->head.ctype)))
return OLE_ERROR_MEMORY;
else
return OLE_OK;
}
OLESTATUS FARINTERNAL BmEqual (
LPOLEOBJECT lpoleobj1,
LPOLEOBJECT lpoleobj2
){
LPOBJECT_BM lpobj1 = (LPOBJECT_BM)lpoleobj1;
LPOBJECT_BM lpobj2 = (LPOBJECT_BM)lpoleobj2;
HANDLE hBits1 = NULL, hBits2 = NULL;
LPSTR lpBits1 = NULL, lpBits2 = NULL;
OLESTATUS retVal;
DWORD dwBytes1, dwBytes2;
if (lpobj1->sizeBytes != lpobj2->sizeBytes)
return OLE_ERROR_NOT_EQUAL;
retVal = OLE_ERROR_MEMORY;
if (!(hBits1 = GlobalAlloc (GMEM_MOVEABLE, lpobj1->sizeBytes)))
goto errEqual;
if (!(lpBits1 = GlobalLock (hBits1)))
goto errEqual;
if (!(hBits2 = GlobalAlloc (GMEM_MOVEABLE, lpobj2->sizeBytes)))
goto errEqual;
if (!(lpBits2 = GlobalLock (hBits2)))
goto errEqual;
dwBytes1 = GetBitmapBits (lpobj1->hBitmap, lpobj1->sizeBytes, lpBits1);
dwBytes2 = GetBitmapBits (lpobj2->hBitmap, lpobj2->sizeBytes, lpBits2);
if (dwBytes1 != dwBytes2) {
retVal = OLE_ERROR_NOT_EQUAL;
goto errEqual;
}
// !!! UtilMemCmp has to be redone for >64k bitmaps
if (UtilMemCmp (lpBits1, lpBits2, dwBytes1))
retVal = OLE_ERROR_NOT_EQUAL;
else
retVal = OLE_OK;
errEqual:
if (lpBits1)
GlobalUnlock (hBits1);
if (lpBits2)
GlobalUnlock (hBits2);
if (hBits1)
GlobalFree (hBits1);
if (hBits2)
GlobalFree (hBits2);
return retVal;
}
OLESTATUS FARINTERNAL BmCopy (
LPOLEOBJECT lpoleobj
){
LPOBJECT_BM lpobj = (LPOBJECT_BM)lpoleobj;
HBITMAP hBitmap;
DWORD size;
if (!lpobj->hBitmap)
return OLE_ERROR_BLANK;
if(!(hBitmap = BmDuplicate (lpobj->hBitmap, &size, NULL)))
return OLE_ERROR_MEMORY;
SetClipboardData(CF_BITMAP, hBitmap);
return OLE_OK;
}
OLESTATUS FARINTERNAL BmQueryBounds (
LPOLEOBJECT lpoleobj,
LPRECT lpRc
){
LPOBJECT_BM lpobj = (LPOBJECT_BM)lpoleobj;
Puts("BmQueryBounds");
if (!lpobj->hBitmap)
return OLE_ERROR_BLANK;
lpRc->left = 0;
lpRc->top = 0;
lpRc->right = (int) lpobj->head.cx;
lpRc->bottom = (int) lpobj->head.cy;
return OLE_OK;
}
OLECLIPFORMAT FARINTERNAL BmEnumFormat (
LPOLEOBJECT lpoleobj,
OLECLIPFORMAT cfFormat
){
LPOBJECT_BM lpobj = (LPOBJECT_BM)lpoleobj;
if (!cfFormat)
return CF_BITMAP;
return 0;
}
OLESTATUS FARINTERNAL BmGetData (
LPOLEOBJECT lpoleobj,
OLECLIPFORMAT cfFormat,
LPHANDLE lphandle
){
LPOBJECT_BM lpobj = (LPOBJECT_BM)lpoleobj;
if (cfFormat != CF_BITMAP)
return OLE_ERROR_FORMAT;
if (!(*lphandle = lpobj->hBitmap))
return OLE_ERROR_BLANK;
return OLE_OK;
}
OLESTATUS FARINTERNAL BmLoadFromStream (
LPOLESTREAM lpstream,
LPOLECLIENT lpclient,
LHCLIENTDOC lhclientdoc,
LPSTR lpobjname,
LPOLEOBJECT FAR * lplpoleobject,
LONG objType
){
LPOBJECT_BM lpobj = NULL;
*lplpoleobject = NULL;
if (!(lpobj = BmCreateBlank (lhclientdoc, lpobjname, objType)))
return OLE_ERROR_MEMORY;
lpobj->head.lpclient = lpclient;
if (!GetBytes (lpstream, (LPSTR) &lpobj->head.cx, sizeof(LONG))) {
if (!GetBytes (lpstream, (LPSTR) &lpobj->head.cy, sizeof(LONG)))
if (!GetBytes (lpstream, (LPSTR) &lpobj->sizeBytes, sizeof(DWORD)))
if (BmStreamRead (lpstream, lpobj)) {
*lplpoleobject = (LPOLEOBJECT)lpobj;
return OLE_OK;
}
}
OleDelete ((LPOLEOBJECT)lpobj);
return OLE_ERROR_STREAM;;
}
OLESTATUS INTERNAL BmStreamWrite (
LPOLESTREAM lpstream,
LPOBJECT_BM lpobj
){
HANDLE hBits;
LPSTR lpBits;
int retVal = OLE_ERROR_STREAM;
BITMAP bm;
DWORD dwSize;
dwSize = lpobj->sizeBytes - sizeof(BITMAP);
if (hBits = GlobalAlloc (GMEM_MOVEABLE, dwSize)) {
if (lpBits = (LPSTR) GlobalLock (hBits)) {
if (GetBitmapBits (lpobj->hBitmap, dwSize, lpBits)) {
WIN16BITMAP w16bm;
GetObject (lpobj->hBitmap, sizeof(BITMAP), (LPSTR) &bm);
ConvertBM32to16(&bm, &w16bm);
if (!PutBytes (lpstream, (LPSTR) &w16bm, sizeof(WIN16BITMAP)))
if (!PutBytes (lpstream, (LPSTR) lpBits, dwSize))
retVal = OLE_OK;
}
GlobalUnlock(hBits);
} else
retVal = OLE_ERROR_MEMORY;
GlobalFree(hBits);
} else
retVal = OLE_ERROR_MEMORY;
return retVal;
}
BOOL INTERNAL BmStreamRead (
LPOLESTREAM lpstream,
LPOBJECT_BM lpobj
){
HANDLE hBits;
LPSTR lpBits;
BOOL retVal = FALSE;
BITMAP bm;
WIN16BITMAP w16bm;
POINT point;
if (GetBytes (lpstream, (LPSTR)&w16bm, sizeof(WIN16BITMAP)))
return FALSE;
ConvertBM16to32(&w16bm,&bm);
lpobj->sizeBytes -= sizeof(WIN16BITMAP) ;
if (hBits = GlobalAlloc (GMEM_MOVEABLE, lpobj->sizeBytes)) {
if (lpBits = (LPSTR) GlobalLock (hBits)) {
if (!GetBytes(lpstream, lpBits, lpobj->sizeBytes)) {
if (lpobj->hBitmap = CreateBitmap (bm.bmWidth,
bm.bmHeight,
bm.bmPlanes,
bm.bmBitsPixel,
lpBits)) {
retVal = TRUE;
lpobj->xSize = point.x = bm.bmWidth;
lpobj->ySize = point.y = bm.bmHeight;
// size of (bitmap header + bits)
lpobj->sizeBytes += sizeof(BITMAP);
#ifdef OLD
// !!! We shouldn't do the conversion. The info should be
// part of the stream.
if (!lpobj->head.cx) {
ConvertToHimetric (&point);
lpobj->head.cx = (LONG) point.x;
lpobj->head.cy = (LONG) point.y;
}
#endif
}
}
GlobalUnlock(hBits);
}
GlobalFree(hBits);
}
return retVal;
}
OLESTATUS FARINTERNAL BmPaste (
LPOLECLIENT lpclient,
LHCLIENTDOC lhclientdoc,
LPSTR lpobjname,
LPOLEOBJECT FAR * lplpoleobject,
LONG objType
){
HBITMAP hBitmap;
*lplpoleobject = NULL;
if ((hBitmap = (HBITMAP) GetClipboardData(CF_BITMAP)) == NULL)
return OLE_ERROR_MEMORY;
if (!(*lplpoleobject = (LPOLEOBJECT) BmCreateObject (hBitmap,
lpclient, FALSE, lhclientdoc,
lpobjname, objType)))
return OLE_ERROR_MEMORY;
return OLE_OK;
}
LPOBJECT_BM INTERNAL BmCreateObject (
HBITMAP hBitmap,
LPOLECLIENT lpclient,
BOOL fDelete,
LHCLIENTDOC lhclientdoc,
LPCSTR lpobjname,
LONG objType
){
LPOBJECT_BM lpobj;
if (lpobj = BmCreateBlank (lhclientdoc, (LPSTR)lpobjname, objType)) {
if (BmChangeData ((LPOLEOBJECT)lpobj, (HANDLE)hBitmap, lpclient, fDelete) != OLE_OK) {
BmRelease ((LPOLEOBJECT)lpobj);
lpobj = NULL;
}
}
return lpobj;
}
// If the routine fails then the object will be left with it's old data.
// If fDelete is TRUE, then hNewBitmap will be deleted whether the routine
// is successful or not.
OLESTATUS FARINTERNAL BmChangeData (
LPOLEOBJECT lpoleobj,
HANDLE hNewBitmap,
LPOLECLIENT lpclient,
BOOL fDelete
){
LPOBJECT_BM lpobj = (LPOBJECT_BM)lpoleobj;
BITMAP bm;
DWORD dwSize;
HBITMAP hOldBitmap;
hOldBitmap = lpobj->hBitmap;
if (!fDelete) {
if (!(hNewBitmap = BmDuplicate (hNewBitmap, &dwSize, &bm)))
return OLE_ERROR_MEMORY;
}
else {
if (!GetObject (hNewBitmap, sizeof(BITMAP), (LPSTR) &bm)) {
DeleteObject (hNewBitmap);
return OLE_ERROR_MEMORY;
}
//*add get bitmap bits
dwSize = ((DWORD) bm.bmHeight) * ((DWORD) bm.bmWidthBytes) *
((DWORD) bm.bmPlanes) * ((DWORD) bm.bmBitsPixel);
}
BmUpdateStruct (lpobj, lpclient, hNewBitmap, &bm, dwSize);
if (hOldBitmap)
DeleteObject (hOldBitmap);
return OLE_OK;
}
void INTERNAL BmUpdateStruct (
LPOBJECT_BM lpobj,
LPOLECLIENT lpclient,
HBITMAP hBitmap,
LPBITMAP lpBm,
DWORD dwBytes
){
POINT point;
lpobj->head.lpclient = lpclient;
lpobj->xSize = point.x = lpBm->bmWidth;
lpobj->ySize = point.y = lpBm->bmHeight;
GetHimetricUnits (hBitmap, &point);
lpobj->head.cx = (LONG) point.x;
lpobj->head.cy = (LONG) point.y;
lpobj->sizeBytes = dwBytes + sizeof(BITMAP);
lpobj->hBitmap = hBitmap;
}
LPOBJECT_BM FARINTERNAL BmCreateBlank (
LHCLIENTDOC lhclientdoc,
LPSTR lpobjname,
LONG objType
){
HOBJECT hobj;
LPOBJECT_BM lpobj;
if ((hobj = GlobalAlloc (GMEM_MOVEABLE|GMEM_ZEROINIT,sizeof (OBJECT_BM)))
== NULL)
return NULL;
if (!(lpobj = (LPOBJECT_BM) GlobalLock (hobj))){
GlobalFree (hobj);
return NULL;
}
lpobj->head.objId[0] = 'L';
lpobj->head.objId[1] = 'E';
lpobj->head.mm = MM_TEXT;
lpobj->head.ctype = objType;
lpobj->head.lpvtbl = (LPOLEOBJECTVTBL)&vtblBM;
lpobj->head.iTable = INVALID_INDEX;
lpobj->head.hobj = hobj;
if (objType == CT_STATIC)
DocAddObject ((LPCLIENTDOC) lhclientdoc,
(LPOLEOBJECT) lpobj, lpobjname);
return lpobj;
}
HBITMAP FARINTERNAL BmDuplicate (
HBITMAP hold,
DWORD FAR * lpdwSize,
LPBITMAP lpBm
){
HBITMAP hnew;
HANDLE hMem;
LPSTR lpMem;
LONG retVal = TRUE;
DWORD dwSize;
BITMAP bm;
INT iX,iY;
// !!! another way to duplicate the bitmap
GetObject (hold, sizeof(BITMAP), (LPSTR) &bm);
dwSize = ((DWORD) bm.bmHeight) * ((DWORD) bm.bmWidthBytes) *
((DWORD) bm.bmPlanes) * ((DWORD) bm.bmBitsPixel);
if (!(hMem = GlobalAlloc (GMEM_MOVEABLE, dwSize)))
return NULL;
if (!(lpMem = GlobalLock (hMem))){
GlobalFree (hMem);
return NULL;
}
GetBitmapBits (hold, dwSize, lpMem);
if (hnew = CreateBitmap (bm.bmWidth, bm.bmHeight,
bm.bmPlanes, bm.bmBitsPixel, NULL))
retVal = SetBitmapBits (hnew, dwSize, lpMem);
GlobalUnlock (hMem);
GlobalFree (hMem);
if (hnew && (!retVal)) {
DeleteObject (hnew);
hnew = NULL;
}
*lpdwSize = dwSize;
if (lpBm)
*lpBm = bm;
if (MGetBitmapDimension (hold,&iX,&iY))
MSetBitmapDimension (hnew, iX, iY);
return hnew;
}
void INTERNAL GetHimetricUnits(HBITMAP hBitmap, LPPOINT lpPoint)
{
HDC hdc;
INT iX,iY;
MGetBitmapDimension (hBitmap,&iX,&iY);
if (iX || iY) {
lpPoint->x = 10 * iX;
lpPoint->y = - (10 * iY);
return;
}
// clip if it exceeds maxPixels. Note that we have a limitation of
// 0x8FFF HIMETRIC units in OLE1.0
if (lpPoint->x > maxPixelsX)
lpPoint->x = maxPixelsX;
if (lpPoint->y > maxPixelsY)
lpPoint->y = maxPixelsY;
if (hdc = GetDC (NULL)) {
lpPoint->x = MulDiv (lpPoint->x, 2540,
GetDeviceCaps (hdc, LOGPIXELSX));
lpPoint->y = - MulDiv (lpPoint->y, 2540,
GetDeviceCaps (hdc, LOGPIXELSY));
ReleaseDC (NULL, hdc);
}
else {
lpPoint->x = 0;
lpPoint->y = 0;
}
}