home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / mfc / database / daoctl / accspict / accsctl.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-27  |  17.2 KB  |  645 lines

  1. // AccsCtl.cpp : Implementation of the CAccessPictCtrl OLE control class.
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992-1998 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12.  
  13. #include "stdafx.h"
  14. #include "AccsPict.h"
  15. #include "StrmDib.h"
  16. #include "AccsCtl.h"
  17. #include "AccsPpg.h"
  18.  
  19. #ifdef _DEBUG
  20. #define new DEBUG_NEW
  21. #undef THIS_FILE
  22. static char THIS_FILE[] = __FILE__;
  23. #endif
  24.  
  25.  
  26. IMPLEMENT_DYNCREATE(CAccessPictCtrl, COleControl)
  27.  
  28.  
  29. /////////////////////////////////////////////////////////////////////////////
  30. // Message map
  31.  
  32. BEGIN_MESSAGE_MAP(CAccessPictCtrl, COleControl)
  33.     //{{AFX_MSG_MAP(CAccessPictCtrl)
  34.     // NOTE - ClassWizard will add and remove message map entries
  35.     //    DO NOT EDIT what you see in these blocks of generated code !
  36.     //}}AFX_MSG_MAP
  37.     ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
  38. END_MESSAGE_MAP()
  39.  
  40.  
  41. /////////////////////////////////////////////////////////////////////////////
  42. // Dispatch map
  43.  
  44. BEGIN_DISPATCH_MAP(CAccessPictCtrl, COleControl)
  45.     //{{AFX_DISPATCH_MAP(CAccessPictCtrl)
  46.     DISP_PROPERTY(CAccessPictCtrl, "StretchToFit", m_bStretch, VT_BOOL)
  47.     DISP_PROPERTY(CAccessPictCtrl, "PreserveRatio", m_bPreserveRatio, VT_BOOL)
  48.     DISP_PROPERTY_EX(CAccessPictCtrl, "IsAccessObject", GetIsAccessObject, SetNotSupported, VT_BOOL)
  49.     DISP_PROPERTY_EX(CAccessPictCtrl, "Picture", GetPicture, SetNotSupported, VT_PICTURE)
  50.     DISP_FUNCTION(CAccessPictCtrl, "SetData", SetData, VT_BOOL, VTS_PVARIANT)
  51.     DISP_STOCKPROP_BORDERSTYLE()
  52.     DISP_STOCKPROP_CAPTION()
  53.     DISP_STOCKPROP_FONT()
  54.     //}}AFX_DISPATCH_MAP
  55.     DISP_FUNCTION_ID(CAccessPictCtrl, "AboutBox", DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTS_NONE)
  56. END_DISPATCH_MAP()
  57.  
  58.  
  59. /////////////////////////////////////////////////////////////////////////////
  60. // Event map
  61.  
  62. BEGIN_EVENT_MAP(CAccessPictCtrl, COleControl)
  63.     //{{AFX_EVENT_MAP(CAccessPictCtrl)
  64.     // NOTE - ClassWizard will add and remove event map entries
  65.     //    DO NOT EDIT what you see in these blocks of generated code !
  66.     //}}AFX_EVENT_MAP
  67. END_EVENT_MAP()
  68.  
  69.  
  70. /////////////////////////////////////////////////////////////////////////////
  71. // Property pages
  72.  
  73. // TODO: Add more property pages as needed.  Remember to increase the count!
  74. BEGIN_PROPPAGEIDS(CAccessPictCtrl, 2)
  75.     PROPPAGEID(CAccessPictPropPage::guid)
  76.     PROPPAGEID(CLSID_CFontPropPage)
  77. END_PROPPAGEIDS(CAccessPictCtrl)
  78.  
  79.  
  80. /////////////////////////////////////////////////////////////////////////////
  81. // Initialize class factory and guid
  82.  
  83. IMPLEMENT_OLECREATE_EX(CAccessPictCtrl, "ACCESSPICT.AccessPictCtrl.1",
  84.     0x1f4e7c23, 0xc38f, 0x11ce, 0x96, 0x11, 0, 0xaa, 0, 0x4a, 0x75, 0xcf)
  85.  
  86.  
  87. /////////////////////////////////////////////////////////////////////////////
  88. // Type library ID and version
  89.  
  90. IMPLEMENT_OLETYPELIB(CAccessPictCtrl, _tlid, _wVerMajor, _wVerMinor)
  91.  
  92.  
  93. /////////////////////////////////////////////////////////////////////////////
  94. // Interface IDs
  95.  
  96. const IID BASED_CODE IID_DAccessPict =
  97.         { 0x1f4e7c21, 0xc38f, 0x11ce, { 0x96, 0x11, 0, 0xaa, 0, 0x4a, 0x75, 0xcf } };
  98. const IID BASED_CODE IID_DAccessPictEvents =
  99.         { 0x1f4e7c22, 0xc38f, 0x11ce, { 0x96, 0x11, 0, 0xaa, 0, 0x4a, 0x75, 0xcf } };
  100.  
  101.  
  102. /////////////////////////////////////////////////////////////////////////////
  103. // Control type information
  104.  
  105. static const DWORD BASED_CODE _dwAccessPictOleMisc =
  106.     OLEMISC_ACTIVATEWHENVISIBLE |
  107.     OLEMISC_SETCLIENTSITEFIRST |
  108.     OLEMISC_INSIDEOUT |
  109.     OLEMISC_CANTLINKINSIDE |
  110.     OLEMISC_RECOMPOSEONRESIZE;
  111.  
  112. IMPLEMENT_OLECTLTYPE(CAccessPictCtrl, IDS_ACCESSPICT, _dwAccessPictOleMisc)
  113.  
  114.  
  115. /////////////////////////////////////////////////////////////////////////////
  116. // CAccessPictCtrl::CAccessPictCtrlFactory::UpdateRegistry -
  117. // Adds or removes system registry entries for CAccessPictCtrl
  118.  
  119. BOOL CAccessPictCtrl::CAccessPictCtrlFactory::UpdateRegistry(BOOL bRegister)
  120. {
  121.     if (bRegister)
  122.         return AfxOleRegisterControlClass(
  123.             AfxGetInstanceHandle(),
  124.             m_clsid,
  125.             m_lpszProgID,
  126.             IDS_ACCESSPICT,
  127.             IDB_ACCESSPICT,
  128.             FALSE,                      //  Not insertable
  129.             _dwAccessPictOleMisc,
  130.             _tlid,
  131.             _wVerMajor,
  132.             _wVerMinor);
  133.     else
  134.         return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
  135. }
  136.  
  137.  
  138. /////////////////////////////////////////////////////////////////////////////
  139. // CAccessPictCtrl::CAccessPictCtrl - Constructor
  140.  
  141. CAccessPictCtrl::CAccessPictCtrl()
  142. {
  143.     InitializeIIDs(&IID_DAccessPict, &IID_DAccessPictEvents);
  144.  
  145.     // Access Object Information
  146.     m_bIsObject = FALSE;
  147.  
  148.     // Picture information
  149.     m_bPictLoaded = FALSE;
  150.     m_bStretch = FALSE;
  151.     m_bPreserveRatio = FALSE;
  152.     m_size = CSize(0,0);
  153. }
  154.  
  155.  
  156. /////////////////////////////////////////////////////////////////////////////
  157. // CAccessPictCtrl::~CAccessPictCtrl - Destructor
  158.  
  159. CAccessPictCtrl::~CAccessPictCtrl()
  160. {
  161.     // Make sure we clear out the data before exiting
  162.     ResetState();
  163. }
  164.  
  165.  
  166. /////////////////////////////////////////////////////////////////////////////
  167. // CAccessPictCtrl::OnDraw - Drawing function
  168.  
  169. void CAccessPictCtrl::OnDraw(
  170.             CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
  171. {
  172.     CRect       rc;
  173.     TEXTMETRIC  tm;
  174.  
  175.     // Paint the background with the AmbientBackColor.
  176.     CBrush bkBrush(TranslateColor(AmbientBackColor()));
  177.     pdc->FillRect(rcBounds, &bkBrush);
  178.  
  179.     // Draw the picture if available otherwise draw a simple text line.
  180.     if (m_bPictLoaded)
  181.     {
  182.         // Resize the rendering rectangle to that of the bitmap so
  183.         // the aspect ratio can be preserved.
  184.         rc = CalcRectSize(rcBounds);
  185.         m_Pict.Render(pdc, rc, rcBounds);
  186.     }
  187.  
  188.     // Render the caption property
  189.     CString strText = InternalGetText();
  190.     if (!strText.IsEmpty())
  191.     {
  192.         rc = rcBounds;
  193.  
  194.         // Select the stock font
  195.         CFont* pOldFont = SelectStockFont(pdc);
  196.         pdc->SetBkMode(TRANSPARENT);
  197.         GetStockTextMetrics(&tm);
  198.  
  199.         pdc->SetTextAlign(TA_CENTER | TA_BOTTOM);
  200.         pdc->ExtTextOut((rc.left + rc.right) / 2,
  201.             (3*(rc.top + rc.bottom - tm.tmHeight) / 4), ETO_CLIPPED,
  202.             rc, strText, strText.GetLength(), NULL);
  203.  
  204. //  CBrush* pOldBrush = pdc->SelectObject(&bkBrush);
  205. //  pdc->SelectObject(pOldBrush);
  206.         pdc->SelectObject(pOldFont);
  207.     }
  208. }
  209.  
  210.  
  211. /////////////////////////////////////////////////////////////////////////////
  212. // CAccessPictCtrl::DoPropExchange - Persistence support
  213.  
  214. void CAccessPictCtrl::DoPropExchange(CPropExchange* pPX)
  215. {
  216.     ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
  217.     COleControl::DoPropExchange(pPX);
  218. }
  219.  
  220.  
  221. /////////////////////////////////////////////////////////////////////////////
  222. // CAccessPictCtrl::OnResetState - Reset control to default state
  223.  
  224. void CAccessPictCtrl::OnResetState()
  225. {
  226.     COleControl::OnResetState();  // Resets defaults found in DoPropExchange
  227.     m_Pict.CreateEmpty();         // Create empty picture on startup
  228. }
  229.  
  230.  
  231. /////////////////////////////////////////////////////////////////////////////
  232. // CAccessPictCtrl::AboutBox - Display an "About" box to the user
  233.  
  234. void CAccessPictCtrl::AboutBox()
  235. {
  236.     CDialog dlgAbout(IDD_ABOUTBOX_ACCESSPICT);
  237.     dlgAbout.DoModal();
  238. }
  239.  
  240.  
  241. /////////////////////////////////////////////////////////////////////////////
  242. // CAccessPictCtrl automation handlers
  243.  
  244. BOOL CAccessPictCtrl::GetIsAccessObject()
  245. {
  246.     return m_bIsObject;
  247. }
  248.  
  249. LPPICTUREDISP CAccessPictCtrl::GetPicture()
  250. {
  251.     // Only return a valid Picture dispatch if the SetData method has
  252.     // been called AND a valid picture object was received.
  253.     if (m_bPictLoaded)
  254.         return m_Pict.GetPictureDispatch();
  255.     else
  256.         return NULL;
  257. }
  258.  
  259. BOOL CAccessPictCtrl::SetData(VARIANT FAR* pvarData)
  260. {
  261.     // This function is called by the container with a VARIANT representing
  262.     // the OLE data from Access.  We take it and immediately try to Parse out
  263.     // the information.  The VARIANT should contain a SAFEARRAY which in turn
  264.     // contains all of the data for the Access OLE Object.
  265.  
  266.     SAFEARRAY FAR*  psaObjectData = NULL;
  267.  
  268.     TRY
  269.     {
  270.         // First, Reset state to abandon any picture.
  271.         ResetState();
  272.  
  273.         // If NULL, user doesn't want a picture (or wishes to clear pict)
  274.         if (pvarData == NULL)
  275.             return TRUE;
  276.  
  277.         // Check that we have an actual SAFEARRAY of VT_UI1 (BYTES).
  278.         if (pvarData->vt != (VT_ARRAY | VT_UI1))
  279.             AfxThrowOleException(E_INVALIDARG); // Any exception will do
  280.  
  281.         // Attempt to copy the data so we can use it.
  282.         if (FAILED(::SafeArrayCopy(pvarData->parray, &psaObjectData)))
  283.             AfxThrowOleException(E_INVALIDARG);
  284.  
  285.         // Attempt to Read the Object
  286.         if (!ReadObject(psaObjectData))
  287.             AfxThrowOleException(E_INVALIDARG);
  288.  
  289.         // Render the new object
  290.         InvalidateControl();
  291.  
  292.         // Cleanup
  293.         ::SafeArrayDestroy(psaObjectData);
  294.         psaObjectData = NULL;
  295.  
  296.         // Operation has succeeded
  297.         return TRUE;
  298.     }
  299.     CATCH(CMemoryException, e)
  300.     {
  301.         // Cleanup our copy of the object data
  302.         if (psaObjectData != NULL)
  303.         {
  304.             ::SafeArrayDestroy(psaObjectData);
  305.             psaObjectData = NULL;
  306.         }
  307.  
  308.         // Data couldn't be copied so reset data.
  309.         ResetState();
  310.         return FALSE;
  311.     }
  312.     END_CATCH
  313. }
  314.  
  315.  
  316. ///////////////////////////////////////////////////////////////////////////
  317. // Implementation
  318.  
  319. BOOL CAccessPictCtrl::ReadObject(SAFEARRAY FAR* psaObject)
  320. {
  321.     LPSTORAGE       lpStorage = NULL;   // An OLE 2.0 IStorage object
  322.     LPSTREAM        lpStream = NULL;    // An OLE 2.0 Data Stream
  323.     LARGE_INTEGER   liOffset;
  324.  
  325.     // Reading the object takes two forms.  First the header structure
  326.     // needs to be examined to see if the SAFEARRAY contains an OLE
  327.     // object.  It doesn't determine if the object is a picture or not.
  328.     if ((lpStorage = ReadObjectHeader(psaObject)) == NULL)
  329.         return FALSE;
  330.  
  331.     // Open a stream on the storage.  We want the OLE 1.0 Native
  332.     // Data stream.
  333.     if (FAILED(lpStorage->OpenStream(L"\1Ole10Native", NULL,
  334.         STGM_DIRECT|STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &lpStream)))
  335.     {
  336.         lpStorage->Release();
  337.         lpStorage = NULL;
  338.         return FALSE;
  339.     }
  340.  
  341.     // Access keeps its picture data 4 bytes from the beginning of the
  342.     // Stream.  Seek the stream 4 bytes to the beginning of the
  343.     // BITMAPFILEHEADER.
  344.     liOffset.LowPart = 4;
  345.     liOffset.HighPart = 0;
  346.     if (FAILED(lpStream->Seek(liOffset, STREAM_SEEK_SET, NULL)))
  347.     {
  348.         lpStream->Release();
  349.         lpStorage->Release();
  350.         return FALSE;
  351.     }
  352.  
  353.     // Attempt to read the picture data in.  If the object is not a
  354.     // picture, it will return FALSE.
  355.     BOOL bRet = ReadObjectData(lpStream);
  356.  
  357.     // Shutdown
  358.     lpStream->Release();
  359.     lpStream = NULL;
  360.  
  361.     lpStorage->Release();
  362.     lpStorage = NULL;
  363.  
  364.     return bRet;
  365. }
  366.  
  367. LPSTORAGE CAccessPictCtrl::ReadObjectHeader(SAFEARRAY FAR* psaObject)
  368. {
  369.     void HUGEP*             pArray = NULL;
  370.     struct OLEOBJECTHEADER* pHeader = NULL;
  371.     LPBYTE                  lpData = NULL;
  372.     BOOL                    bAccessed = FALSE;
  373.     LPOLE1STREAM            lpStream = NULL;
  374.     LPSTORAGE               lpStorage = NULL;
  375.  
  376.     TRY
  377.     {
  378.         if (psaObject == NULL)
  379.             AfxThrowOleException(E_INVALIDARG);
  380.  
  381.         // Attempt to read the object header from the safearray.  Check the
  382.         // type signature of the header.  If it is correct, then read in
  383.         // the rest of the information.
  384.  
  385.         // Access the data in the array.
  386.         if (FAILED(::SafeArrayAccessData(psaObject, &pArray)))
  387.             AfxThrowOleException(E_INVALIDARG);
  388.         bAccessed = TRUE;
  389.  
  390.         pHeader = (OLEOBJECTHEADER*)pArray;
  391.         if (pHeader->typ != 0x1C15) // 0x1C15 is Access cookie for OLE Object
  392.             AfxThrowOleException(E_INVALIDARG);
  393.  
  394.         // Object is an Access OLE object set the 'IsObject' flag to TRUE
  395.         m_bIsObject = TRUE;
  396.  
  397.         // Call OleConvertOLESTREAMToIStorage to convert the Access object
  398.         // (in OLE 1.0 format) to an OLE 2.0 format.
  399.         lpData = (LPBYTE)pArray + pHeader->cbHdr;
  400.  
  401.         // Create the OLESTREAM
  402.         lpStream = CreateOleStream(lpData,
  403.             GetStreamSize(psaObject, pHeader->cbHdr));
  404.  
  405.         // Create an OLE Storage (use a temporary file)
  406.         if (FAILED(::StgCreateDocfile(NULL,
  407.             STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_DIRECT|
  408.             STGM_DELETEONRELEASE,0, &lpStorage)))
  409.             AfxThrowOleException(E_INVALIDARG);
  410.  
  411.         if (FAILED(::OleConvertOLESTREAMToIStorage((LPOLESTREAM)lpStream,
  412.             lpStorage, NULL)))
  413.             AfxThrowOleException(E_INVALIDARG);
  414.  
  415.         DeleteOleStream(lpStream);
  416.         ::SafeArrayUnaccessData(psaObject);
  417.         bAccessed = FALSE;
  418.  
  419.         return lpStorage;
  420.     }
  421.     CATCH(COleException, e)
  422.     {
  423.         if (bAccessed)
  424.             ::SafeArrayUnaccessData(psaObject);
  425.  
  426.         if (lpStream != NULL)
  427.         {
  428.             DeleteOleStream(lpStream);
  429.             lpStream = NULL;
  430.         }
  431.  
  432.         if (lpStorage != NULL)
  433.         {
  434.             lpStorage->Release();
  435.             return NULL;
  436.         }
  437.         ResetState();
  438.  
  439.         return NULL;
  440.     }
  441.     END_CATCH
  442. }
  443.  
  444. BOOL CAccessPictCtrl::ReadObjectData(LPSTREAM lpStream)
  445. {
  446.     BOOL bRet;
  447.  
  448.     TRY
  449.     {
  450.         if (lpStream == NULL)
  451.             AfxThrowOleException(E_INVALIDARG);
  452.  
  453.         // If the seek was successful, load the bitmap from the stream
  454.         bRet = m_StreamDib.LoadBitmap(lpStream);
  455.         if (bRet);
  456.         {
  457.             // Create the new picture from the bitmap and palette
  458.             if (m_Pict.CreateFromBitmap(m_StreamDib.GetBitmap(),
  459.                     m_StreamDib.GetPalette()))
  460.             {
  461.                 m_bPictLoaded = TRUE;
  462.                 m_size = m_StreamDib.GetSize();
  463.                 bRet = TRUE;
  464.             }
  465.             else
  466.             {
  467.                 m_bPictLoaded = FALSE;
  468.                 ResetState();
  469.                 bRet = FALSE;
  470.             }
  471.         }
  472.     }
  473.     CATCH(COleException, e)
  474.     {
  475.         ResetState();
  476.         return FALSE;
  477.     }
  478.     END_CATCH
  479.  
  480.     return bRet;
  481. }
  482.  
  483. void CAccessPictCtrl::ResetState()
  484. {
  485.     m_bIsObject = FALSE;
  486.     m_bPictLoaded = FALSE;
  487. }
  488.  
  489.  
  490. ///////////////////////////////////////////////////////////////////////////
  491. // LPOLE1STREAM creation function
  492.  
  493. LPOLE1STREAM CAccessPictCtrl::CreateOleStream(LPBYTE lpData, DWORD dwSize)
  494. {
  495.     ASSERT(lpData != NULL);
  496.  
  497.     // Create a new OLESTREAMVTBL to handle callbacks
  498.     LPOLESTREAMVTBL pvt = new OLESTREAMVTBL;
  499.  
  500.     // Initialize callbacks w/ our global functions
  501.     pvt->Get = &Get;
  502.     pvt->Put = &Put;
  503.  
  504.     // Create an OLE1STREAM
  505.     LPOLE1STREAM pStream = new OLE1STREAM;
  506.  
  507.     // Initialize it with the OLESTREAMVTBL and data
  508.     pStream->pvt = pvt;
  509.     pStream->dwSize = dwSize;
  510.     pStream->lpData = lpData;
  511.  
  512.     return pStream;
  513. }
  514.  
  515. void CAccessPictCtrl::DeleteOleStream(LPOLE1STREAM pStream)
  516. {
  517.     // Delete all the data members of the OLE1STREAM and
  518.     // NULL the OLE1STREAM::lpData member (it will be
  519.     // destroyed during ::SafeArrayDestroy().
  520.  
  521.     ASSERT(pStream != NULL);
  522.     ASSERT(pStream->pvt != NULL);
  523.  
  524.     // Delete or NULL member data
  525.     delete pStream->pvt;
  526.     pStream->lpData = NULL;
  527.  
  528.     // Delete the stream itself
  529.     delete pStream;
  530.     pStream = NULL;
  531. }
  532.  
  533.  
  534. DWORD CAccessPictCtrl::GetStreamSize(SAFEARRAY FAR* psaObject, DWORD dwOffset)
  535. {
  536.     ASSERT(psaObject != NULL);
  537.     LONG lBoundLower, lBoundUpper;
  538.  
  539.     ::SafeArrayGetLBound(psaObject, 0, &lBoundLower);
  540.     ::SafeArrayGetUBound(psaObject, 0, &lBoundUpper);
  541.  
  542.     DWORD dwSize = ((DWORD)(lBoundUpper - lBoundLower)) - dwOffset;
  543.     if (dwSize < 0)
  544.         dwSize = 0;
  545.  
  546.     return dwSize;
  547. }
  548.  
  549. ///////////////////////////////////////////////////////////////////////////
  550. // OLESTREAMVTBL Callback Functions
  551.  
  552. DWORD FAR PASCAL Get(LPOLESTREAM pstm, void FAR* pb, DWORD cb)
  553. {
  554.     // Check the validity of the stream and that we are not reading more
  555.     // bytes than are in the stream.
  556.     LPOLE1STREAM pStream = (LPOLE1STREAM)pstm;
  557.     if ((pStream == NULL) || (pStream->lpData == NULL) ||
  558.         (pStream->dwSize < cb))
  559.         return 0L;
  560.  
  561.     // ASSUME that buffers do not overlap.
  562.     memcpy(pb, pStream->lpData, cb);
  563.     pStream->lpData += cb;      // Update pointer
  564.     pStream->dwSize -= cb;
  565.  
  566.     return cb;
  567. }
  568.  
  569. DWORD FAR PASCAL Put(LPOLESTREAM pstm, const void FAR* pb, DWORD cb)
  570. {
  571.     // Check the validity of the stream and that we are not writing
  572.     // more data than we have space for.
  573.     LPOLE1STREAM pStream = (LPOLE1STREAM)pstm;
  574.     if ((pStream == NULL) || (pStream->lpData == NULL) || (pb == NULL) ||
  575.         (pStream->dwSize < cb))
  576.         return 0L;
  577.  
  578.     // ASSUME that buffers don't overlap.
  579.     memcpy(pStream->lpData, pb, cb);
  580.     pStream->lpData += cb;      // Update pointer
  581.     pStream->dwSize -= cb;
  582.  
  583.     return cb;
  584. }
  585.  
  586. CRect CAccessPictCtrl::CalcRectSize(const CRect& rect)
  587. {
  588.     CRect sizedRect;
  589.     ASSERT(m_bPictLoaded);
  590.  
  591.     if (m_bStretch)
  592.     {
  593.         if (m_bPreserveRatio)
  594.         {
  595.             // Stretch to fit and preserve ratio
  596.             sizedRect = rect;
  597.  
  598.             // Calculate ratio of both size & rect (x/y).
  599.             double dfSizeRatio = (double)m_size.cx / (double)m_size.cy;
  600.             double dfRectRatio = (double)sizedRect.Width() /
  601.                 (double)sizedRect.Height();
  602.  
  603.             int xOff = 0;
  604.             int yOff = 0;
  605.  
  606.             if (dfSizeRatio > dfRectRatio)
  607.             {
  608.                 // Use the X axis for the boundary axis.  Calculate the
  609.                 // offset into the Y axis.
  610.  
  611.                 yOff = (int)((m_size.cy * sizedRect.Width())/m_size.cx);
  612.                 yOff = (int)((sizedRect.Height() - yOff)/-2);
  613.             }
  614.             else
  615.             {
  616.                 // Use the Y axis for the boundary axis.  Calculate the
  617.                 // offset into the X axis.
  618.  
  619.                 xOff = (int)((m_size.cx * sizedRect.Height())/m_size.cy);
  620.                 xOff = (int)((sizedRect.Width() - xOff)/-2);
  621.             }
  622.  
  623.             // Change the rectangle
  624.             sizedRect.InflateRect(xOff, yOff);
  625.  
  626.         }
  627.         else
  628.         {
  629.             // Stretch to fit, don't preserve ratio
  630.             // Use rcBounds as rectangle
  631.             sizedRect = rect;
  632.         }
  633.     }
  634.     else
  635.     {
  636.         // Don't stretch, use a centering algorithm
  637.         sizedRect = rect;
  638.         int xOff = (m_size.cx - sizedRect.Width()) / 2;
  639.         int yOff = (m_size.cy - sizedRect.Height()) / 2;
  640.         sizedRect.InflateRect(xOff, yOff);
  641.     }
  642.  
  643.     return sizedRect;
  644. }
  645.