home *** CD-ROM | disk | FTP | other *** search
- // AccsCtl.cpp : Implementation of the CAccessPictCtrl OLE control class.
- //
- // This is a part of the Microsoft Foundation Classes C++ library.
- // Copyright (C) 1992-1998 Microsoft Corporation
- // All rights reserved.
- //
- // This source code is only intended as a supplement to the
- // Microsoft Foundation Classes Reference and related
- // electronic documentation provided with the library.
- // See these sources for detailed information regarding the
- // Microsoft Foundation Classes product.
-
- #include "stdafx.h"
- #include "AccsPict.h"
- #include "StrmDib.h"
- #include "AccsCtl.h"
- #include "AccsPpg.h"
-
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
-
-
- IMPLEMENT_DYNCREATE(CAccessPictCtrl, COleControl)
-
-
- /////////////////////////////////////////////////////////////////////////////
- // Message map
-
- BEGIN_MESSAGE_MAP(CAccessPictCtrl, COleControl)
- //{{AFX_MSG_MAP(CAccessPictCtrl)
- // NOTE - ClassWizard will add and remove message map entries
- // DO NOT EDIT what you see in these blocks of generated code !
- //}}AFX_MSG_MAP
- ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
- END_MESSAGE_MAP()
-
-
- /////////////////////////////////////////////////////////////////////////////
- // Dispatch map
-
- BEGIN_DISPATCH_MAP(CAccessPictCtrl, COleControl)
- //{{AFX_DISPATCH_MAP(CAccessPictCtrl)
- DISP_PROPERTY(CAccessPictCtrl, "StretchToFit", m_bStretch, VT_BOOL)
- DISP_PROPERTY(CAccessPictCtrl, "PreserveRatio", m_bPreserveRatio, VT_BOOL)
- DISP_PROPERTY_EX(CAccessPictCtrl, "IsAccessObject", GetIsAccessObject, SetNotSupported, VT_BOOL)
- DISP_PROPERTY_EX(CAccessPictCtrl, "Picture", GetPicture, SetNotSupported, VT_PICTURE)
- DISP_FUNCTION(CAccessPictCtrl, "SetData", SetData, VT_BOOL, VTS_PVARIANT)
- DISP_STOCKPROP_BORDERSTYLE()
- DISP_STOCKPROP_CAPTION()
- DISP_STOCKPROP_FONT()
- //}}AFX_DISPATCH_MAP
- DISP_FUNCTION_ID(CAccessPictCtrl, "AboutBox", DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTS_NONE)
- END_DISPATCH_MAP()
-
-
- /////////////////////////////////////////////////////////////////////////////
- // Event map
-
- BEGIN_EVENT_MAP(CAccessPictCtrl, COleControl)
- //{{AFX_EVENT_MAP(CAccessPictCtrl)
- // NOTE - ClassWizard will add and remove event map entries
- // DO NOT EDIT what you see in these blocks of generated code !
- //}}AFX_EVENT_MAP
- END_EVENT_MAP()
-
-
- /////////////////////////////////////////////////////////////////////////////
- // Property pages
-
- // TODO: Add more property pages as needed. Remember to increase the count!
- BEGIN_PROPPAGEIDS(CAccessPictCtrl, 2)
- PROPPAGEID(CAccessPictPropPage::guid)
- PROPPAGEID(CLSID_CFontPropPage)
- END_PROPPAGEIDS(CAccessPictCtrl)
-
-
- /////////////////////////////////////////////////////////////////////////////
- // Initialize class factory and guid
-
- IMPLEMENT_OLECREATE_EX(CAccessPictCtrl, "ACCESSPICT.AccessPictCtrl.1",
- 0x1f4e7c23, 0xc38f, 0x11ce, 0x96, 0x11, 0, 0xaa, 0, 0x4a, 0x75, 0xcf)
-
-
- /////////////////////////////////////////////////////////////////////////////
- // Type library ID and version
-
- IMPLEMENT_OLETYPELIB(CAccessPictCtrl, _tlid, _wVerMajor, _wVerMinor)
-
-
- /////////////////////////////////////////////////////////////////////////////
- // Interface IDs
-
- const IID BASED_CODE IID_DAccessPict =
- { 0x1f4e7c21, 0xc38f, 0x11ce, { 0x96, 0x11, 0, 0xaa, 0, 0x4a, 0x75, 0xcf } };
- const IID BASED_CODE IID_DAccessPictEvents =
- { 0x1f4e7c22, 0xc38f, 0x11ce, { 0x96, 0x11, 0, 0xaa, 0, 0x4a, 0x75, 0xcf } };
-
-
- /////////////////////////////////////////////////////////////////////////////
- // Control type information
-
- static const DWORD BASED_CODE _dwAccessPictOleMisc =
- OLEMISC_ACTIVATEWHENVISIBLE |
- OLEMISC_SETCLIENTSITEFIRST |
- OLEMISC_INSIDEOUT |
- OLEMISC_CANTLINKINSIDE |
- OLEMISC_RECOMPOSEONRESIZE;
-
- IMPLEMENT_OLECTLTYPE(CAccessPictCtrl, IDS_ACCESSPICT, _dwAccessPictOleMisc)
-
-
- /////////////////////////////////////////////////////////////////////////////
- // CAccessPictCtrl::CAccessPictCtrlFactory::UpdateRegistry -
- // Adds or removes system registry entries for CAccessPictCtrl
-
- BOOL CAccessPictCtrl::CAccessPictCtrlFactory::UpdateRegistry(BOOL bRegister)
- {
- if (bRegister)
- return AfxOleRegisterControlClass(
- AfxGetInstanceHandle(),
- m_clsid,
- m_lpszProgID,
- IDS_ACCESSPICT,
- IDB_ACCESSPICT,
- FALSE, // Not insertable
- _dwAccessPictOleMisc,
- _tlid,
- _wVerMajor,
- _wVerMinor);
- else
- return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
- }
-
-
- /////////////////////////////////////////////////////////////////////////////
- // CAccessPictCtrl::CAccessPictCtrl - Constructor
-
- CAccessPictCtrl::CAccessPictCtrl()
- {
- InitializeIIDs(&IID_DAccessPict, &IID_DAccessPictEvents);
-
- // Access Object Information
- m_bIsObject = FALSE;
-
- // Picture information
- m_bPictLoaded = FALSE;
- m_bStretch = FALSE;
- m_bPreserveRatio = FALSE;
- m_size = CSize(0,0);
- }
-
-
- /////////////////////////////////////////////////////////////////////////////
- // CAccessPictCtrl::~CAccessPictCtrl - Destructor
-
- CAccessPictCtrl::~CAccessPictCtrl()
- {
- // Make sure we clear out the data before exiting
- ResetState();
- }
-
-
- /////////////////////////////////////////////////////////////////////////////
- // CAccessPictCtrl::OnDraw - Drawing function
-
- void CAccessPictCtrl::OnDraw(
- CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
- {
- CRect rc;
- TEXTMETRIC tm;
-
- // Paint the background with the AmbientBackColor.
- CBrush bkBrush(TranslateColor(AmbientBackColor()));
- pdc->FillRect(rcBounds, &bkBrush);
-
- // Draw the picture if available otherwise draw a simple text line.
- if (m_bPictLoaded)
- {
- // Resize the rendering rectangle to that of the bitmap so
- // the aspect ratio can be preserved.
- rc = CalcRectSize(rcBounds);
- m_Pict.Render(pdc, rc, rcBounds);
- }
-
- // Render the caption property
- CString strText = InternalGetText();
- if (!strText.IsEmpty())
- {
- rc = rcBounds;
-
- // Select the stock font
- CFont* pOldFont = SelectStockFont(pdc);
- pdc->SetBkMode(TRANSPARENT);
- GetStockTextMetrics(&tm);
-
- pdc->SetTextAlign(TA_CENTER | TA_BOTTOM);
- pdc->ExtTextOut((rc.left + rc.right) / 2,
- (3*(rc.top + rc.bottom - tm.tmHeight) / 4), ETO_CLIPPED,
- rc, strText, strText.GetLength(), NULL);
-
- // CBrush* pOldBrush = pdc->SelectObject(&bkBrush);
- // pdc->SelectObject(pOldBrush);
- pdc->SelectObject(pOldFont);
- }
- }
-
-
- /////////////////////////////////////////////////////////////////////////////
- // CAccessPictCtrl::DoPropExchange - Persistence support
-
- void CAccessPictCtrl::DoPropExchange(CPropExchange* pPX)
- {
- ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
- COleControl::DoPropExchange(pPX);
- }
-
-
- /////////////////////////////////////////////////////////////////////////////
- // CAccessPictCtrl::OnResetState - Reset control to default state
-
- void CAccessPictCtrl::OnResetState()
- {
- COleControl::OnResetState(); // Resets defaults found in DoPropExchange
- m_Pict.CreateEmpty(); // Create empty picture on startup
- }
-
-
- /////////////////////////////////////////////////////////////////////////////
- // CAccessPictCtrl::AboutBox - Display an "About" box to the user
-
- void CAccessPictCtrl::AboutBox()
- {
- CDialog dlgAbout(IDD_ABOUTBOX_ACCESSPICT);
- dlgAbout.DoModal();
- }
-
-
- /////////////////////////////////////////////////////////////////////////////
- // CAccessPictCtrl automation handlers
-
- BOOL CAccessPictCtrl::GetIsAccessObject()
- {
- return m_bIsObject;
- }
-
- LPPICTUREDISP CAccessPictCtrl::GetPicture()
- {
- // Only return a valid Picture dispatch if the SetData method has
- // been called AND a valid picture object was received.
- if (m_bPictLoaded)
- return m_Pict.GetPictureDispatch();
- else
- return NULL;
- }
-
- BOOL CAccessPictCtrl::SetData(VARIANT FAR* pvarData)
- {
- // This function is called by the container with a VARIANT representing
- // the OLE data from Access. We take it and immediately try to Parse out
- // the information. The VARIANT should contain a SAFEARRAY which in turn
- // contains all of the data for the Access OLE Object.
-
- SAFEARRAY FAR* psaObjectData = NULL;
-
- TRY
- {
- // First, Reset state to abandon any picture.
- ResetState();
-
- // If NULL, user doesn't want a picture (or wishes to clear pict)
- if (pvarData == NULL)
- return TRUE;
-
- // Check that we have an actual SAFEARRAY of VT_UI1 (BYTES).
- if (pvarData->vt != (VT_ARRAY | VT_UI1))
- AfxThrowOleException(E_INVALIDARG); // Any exception will do
-
- // Attempt to copy the data so we can use it.
- if (FAILED(::SafeArrayCopy(pvarData->parray, &psaObjectData)))
- AfxThrowOleException(E_INVALIDARG);
-
- // Attempt to Read the Object
- if (!ReadObject(psaObjectData))
- AfxThrowOleException(E_INVALIDARG);
-
- // Render the new object
- InvalidateControl();
-
- // Cleanup
- ::SafeArrayDestroy(psaObjectData);
- psaObjectData = NULL;
-
- // Operation has succeeded
- return TRUE;
- }
- CATCH(CMemoryException, e)
- {
- // Cleanup our copy of the object data
- if (psaObjectData != NULL)
- {
- ::SafeArrayDestroy(psaObjectData);
- psaObjectData = NULL;
- }
-
- // Data couldn't be copied so reset data.
- ResetState();
- return FALSE;
- }
- END_CATCH
- }
-
-
- ///////////////////////////////////////////////////////////////////////////
- // Implementation
-
- BOOL CAccessPictCtrl::ReadObject(SAFEARRAY FAR* psaObject)
- {
- LPSTORAGE lpStorage = NULL; // An OLE 2.0 IStorage object
- LPSTREAM lpStream = NULL; // An OLE 2.0 Data Stream
- LARGE_INTEGER liOffset;
-
- // Reading the object takes two forms. First the header structure
- // needs to be examined to see if the SAFEARRAY contains an OLE
- // object. It doesn't determine if the object is a picture or not.
- if ((lpStorage = ReadObjectHeader(psaObject)) == NULL)
- return FALSE;
-
- // Open a stream on the storage. We want the OLE 1.0 Native
- // Data stream.
- if (FAILED(lpStorage->OpenStream(L"\1Ole10Native", NULL,
- STGM_DIRECT|STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &lpStream)))
- {
- lpStorage->Release();
- lpStorage = NULL;
- return FALSE;
- }
-
- // Access keeps its picture data 4 bytes from the beginning of the
- // Stream. Seek the stream 4 bytes to the beginning of the
- // BITMAPFILEHEADER.
- liOffset.LowPart = 4;
- liOffset.HighPart = 0;
- if (FAILED(lpStream->Seek(liOffset, STREAM_SEEK_SET, NULL)))
- {
- lpStream->Release();
- lpStorage->Release();
- return FALSE;
- }
-
- // Attempt to read the picture data in. If the object is not a
- // picture, it will return FALSE.
- BOOL bRet = ReadObjectData(lpStream);
-
- // Shutdown
- lpStream->Release();
- lpStream = NULL;
-
- lpStorage->Release();
- lpStorage = NULL;
-
- return bRet;
- }
-
- LPSTORAGE CAccessPictCtrl::ReadObjectHeader(SAFEARRAY FAR* psaObject)
- {
- void HUGEP* pArray = NULL;
- struct OLEOBJECTHEADER* pHeader = NULL;
- LPBYTE lpData = NULL;
- BOOL bAccessed = FALSE;
- LPOLE1STREAM lpStream = NULL;
- LPSTORAGE lpStorage = NULL;
-
- TRY
- {
- if (psaObject == NULL)
- AfxThrowOleException(E_INVALIDARG);
-
- // Attempt to read the object header from the safearray. Check the
- // type signature of the header. If it is correct, then read in
- // the rest of the information.
-
- // Access the data in the array.
- if (FAILED(::SafeArrayAccessData(psaObject, &pArray)))
- AfxThrowOleException(E_INVALIDARG);
- bAccessed = TRUE;
-
- pHeader = (OLEOBJECTHEADER*)pArray;
- if (pHeader->typ != 0x1C15) // 0x1C15 is Access cookie for OLE Object
- AfxThrowOleException(E_INVALIDARG);
-
- // Object is an Access OLE object set the 'IsObject' flag to TRUE
- m_bIsObject = TRUE;
-
- // Call OleConvertOLESTREAMToIStorage to convert the Access object
- // (in OLE 1.0 format) to an OLE 2.0 format.
- lpData = (LPBYTE)pArray + pHeader->cbHdr;
-
- // Create the OLESTREAM
- lpStream = CreateOleStream(lpData,
- GetStreamSize(psaObject, pHeader->cbHdr));
-
- // Create an OLE Storage (use a temporary file)
- if (FAILED(::StgCreateDocfile(NULL,
- STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_DIRECT|
- STGM_DELETEONRELEASE,0, &lpStorage)))
- AfxThrowOleException(E_INVALIDARG);
-
- if (FAILED(::OleConvertOLESTREAMToIStorage((LPOLESTREAM)lpStream,
- lpStorage, NULL)))
- AfxThrowOleException(E_INVALIDARG);
-
- DeleteOleStream(lpStream);
- ::SafeArrayUnaccessData(psaObject);
- bAccessed = FALSE;
-
- return lpStorage;
- }
- CATCH(COleException, e)
- {
- if (bAccessed)
- ::SafeArrayUnaccessData(psaObject);
-
- if (lpStream != NULL)
- {
- DeleteOleStream(lpStream);
- lpStream = NULL;
- }
-
- if (lpStorage != NULL)
- {
- lpStorage->Release();
- return NULL;
- }
- ResetState();
-
- return NULL;
- }
- END_CATCH
- }
-
- BOOL CAccessPictCtrl::ReadObjectData(LPSTREAM lpStream)
- {
- BOOL bRet;
-
- TRY
- {
- if (lpStream == NULL)
- AfxThrowOleException(E_INVALIDARG);
-
- // If the seek was successful, load the bitmap from the stream
- bRet = m_StreamDib.LoadBitmap(lpStream);
- if (bRet);
- {
- // Create the new picture from the bitmap and palette
- if (m_Pict.CreateFromBitmap(m_StreamDib.GetBitmap(),
- m_StreamDib.GetPalette()))
- {
- m_bPictLoaded = TRUE;
- m_size = m_StreamDib.GetSize();
- bRet = TRUE;
- }
- else
- {
- m_bPictLoaded = FALSE;
- ResetState();
- bRet = FALSE;
- }
- }
- }
- CATCH(COleException, e)
- {
- ResetState();
- return FALSE;
- }
- END_CATCH
-
- return bRet;
- }
-
- void CAccessPictCtrl::ResetState()
- {
- m_bIsObject = FALSE;
- m_bPictLoaded = FALSE;
- }
-
-
- ///////////////////////////////////////////////////////////////////////////
- // LPOLE1STREAM creation function
-
- LPOLE1STREAM CAccessPictCtrl::CreateOleStream(LPBYTE lpData, DWORD dwSize)
- {
- ASSERT(lpData != NULL);
-
- // Create a new OLESTREAMVTBL to handle callbacks
- LPOLESTREAMVTBL pvt = new OLESTREAMVTBL;
-
- // Initialize callbacks w/ our global functions
- pvt->Get = &Get;
- pvt->Put = &Put;
-
- // Create an OLE1STREAM
- LPOLE1STREAM pStream = new OLE1STREAM;
-
- // Initialize it with the OLESTREAMVTBL and data
- pStream->pvt = pvt;
- pStream->dwSize = dwSize;
- pStream->lpData = lpData;
-
- return pStream;
- }
-
- void CAccessPictCtrl::DeleteOleStream(LPOLE1STREAM pStream)
- {
- // Delete all the data members of the OLE1STREAM and
- // NULL the OLE1STREAM::lpData member (it will be
- // destroyed during ::SafeArrayDestroy().
-
- ASSERT(pStream != NULL);
- ASSERT(pStream->pvt != NULL);
-
- // Delete or NULL member data
- delete pStream->pvt;
- pStream->lpData = NULL;
-
- // Delete the stream itself
- delete pStream;
- pStream = NULL;
- }
-
-
- DWORD CAccessPictCtrl::GetStreamSize(SAFEARRAY FAR* psaObject, DWORD dwOffset)
- {
- ASSERT(psaObject != NULL);
- LONG lBoundLower, lBoundUpper;
-
- ::SafeArrayGetLBound(psaObject, 0, &lBoundLower);
- ::SafeArrayGetUBound(psaObject, 0, &lBoundUpper);
-
- DWORD dwSize = ((DWORD)(lBoundUpper - lBoundLower)) - dwOffset;
- if (dwSize < 0)
- dwSize = 0;
-
- return dwSize;
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // OLESTREAMVTBL Callback Functions
-
- DWORD FAR PASCAL Get(LPOLESTREAM pstm, void FAR* pb, DWORD cb)
- {
- // Check the validity of the stream and that we are not reading more
- // bytes than are in the stream.
- LPOLE1STREAM pStream = (LPOLE1STREAM)pstm;
- if ((pStream == NULL) || (pStream->lpData == NULL) ||
- (pStream->dwSize < cb))
- return 0L;
-
- // ASSUME that buffers do not overlap.
- memcpy(pb, pStream->lpData, cb);
- pStream->lpData += cb; // Update pointer
- pStream->dwSize -= cb;
-
- return cb;
- }
-
- DWORD FAR PASCAL Put(LPOLESTREAM pstm, const void FAR* pb, DWORD cb)
- {
- // Check the validity of the stream and that we are not writing
- // more data than we have space for.
- LPOLE1STREAM pStream = (LPOLE1STREAM)pstm;
- if ((pStream == NULL) || (pStream->lpData == NULL) || (pb == NULL) ||
- (pStream->dwSize < cb))
- return 0L;
-
- // ASSUME that buffers don't overlap.
- memcpy(pStream->lpData, pb, cb);
- pStream->lpData += cb; // Update pointer
- pStream->dwSize -= cb;
-
- return cb;
- }
-
- CRect CAccessPictCtrl::CalcRectSize(const CRect& rect)
- {
- CRect sizedRect;
- ASSERT(m_bPictLoaded);
-
- if (m_bStretch)
- {
- if (m_bPreserveRatio)
- {
- // Stretch to fit and preserve ratio
- sizedRect = rect;
-
- // Calculate ratio of both size & rect (x/y).
- double dfSizeRatio = (double)m_size.cx / (double)m_size.cy;
- double dfRectRatio = (double)sizedRect.Width() /
- (double)sizedRect.Height();
-
- int xOff = 0;
- int yOff = 0;
-
- if (dfSizeRatio > dfRectRatio)
- {
- // Use the X axis for the boundary axis. Calculate the
- // offset into the Y axis.
-
- yOff = (int)((m_size.cy * sizedRect.Width())/m_size.cx);
- yOff = (int)((sizedRect.Height() - yOff)/-2);
- }
- else
- {
- // Use the Y axis for the boundary axis. Calculate the
- // offset into the X axis.
-
- xOff = (int)((m_size.cx * sizedRect.Height())/m_size.cy);
- xOff = (int)((sizedRect.Width() - xOff)/-2);
- }
-
- // Change the rectangle
- sizedRect.InflateRect(xOff, yOff);
-
- }
- else
- {
- // Stretch to fit, don't preserve ratio
- // Use rcBounds as rectangle
- sizedRect = rect;
- }
- }
- else
- {
- // Don't stretch, use a centering algorithm
- sizedRect = rect;
- int xOff = (m_size.cx - sizedRect.Width()) / 2;
- int yOff = (m_size.cy - sizedRect.Height()) / 2;
- sizedRect.InflateRect(xOff, yOff);
- }
-
- return sizedRect;
- }
-