/*
 * POLYLINE.CPP
 * Polyline Component Object Chapter 5
 *
 * Implementation of the CPolyline class that we expose as a
 * component object.
 *
 * Copyright (c)1993-1994 Microsoft Corporation, All Rights Reserved
 *
 * Kraig Brockschmidt, Software Design Engineer
 * Microsoft Systems Developer Relations
 *
 * Internet  :  kraigb@microsoft.com
 * Compuserve:  >INTERNET:kraigb@microsoft.com
 */


#include "polyline.h"


/*
 * CPolyline:CPolyline
 * CPolyline::~CPolyline
 *
 * Constructor Parameters:
 *  pUnkOuter       LPUNKNOWN of the controlling unknown.
 *  pfnDestroy      PFNDESTROYED to call when an object is
 *                  destroyed.
 *  hInst           HINSTANCE of the application we're in.
 */

CPolyline::CPolyline(LPUNKNOWN pUnkOuter, PFNDESTROYED pfnDestroy
    , HINSTANCE hInst)
    {
    m_hWnd=NULL;
    m_hInst=hInst;

    m_cRef=0;
    m_pUnkOuter=pUnkOuter;
    m_pfnDestroy=pfnDestroy;
    m_fDirty=FALSE;

    //CHAPTER5MOD
    m_pST  =NULL;
    m_cf   =0;
    m_clsID=CLSID_Polyline5;

    m_pIStorage=NULL;
    m_pIStream =NULL;

    m_pIPolyline      =NULL;
    m_pIPersistStorage=NULL;
    m_pAdv            =NULL;
    //End CHAPTER5MOD

    return;
    }


CPolyline::~CPolyline(void)
    {
    //CHAPTER5MOD
    if (NULL!=m_pST)
        delete m_pST;

    //Free our contained interfaces
    if (NULL!=m_pIPersistStorage)
        delete m_pIPersistStorage;

    if (NULL!=m_pIStream)
        m_pIStream->Release();

    if (NULL!=m_pIStorage)
        m_pIStorage->Release();
    //End CHAPTER5MOD

    if (NULL!=m_pIPolyline)
        delete m_pIPolyline;    //Interface does not free itself.

    //Reverses the AddRef in IPolyline::SetAdvise
    if (NULL!=m_pAdv)
        m_pAdv->Release();

    return;
    }




/*
 * CPolyline::FInit
 *
 * Purpose:
 *  Performs any intiailization of a CPolyline that's prone to
 *  failure that we also use internally before exposing the
 *  object outside this DLL.
 *
 * Parameters:
 *  None
 *
 * Return Value:
 *  BOOL            TRUE if the function is successful,
 *                  FALSE otherwise.
 */

BOOL CPolyline::FInit(void)
    {
    LPUNKNOWN       pIUnknown=this;

    if (NULL!=m_pUnkOuter)
        pIUnknown=m_pUnkOuter;

    //CHAPTER5MOD
    m_pST=new CStringTable(m_hInst);

    if (!m_pST->FInit(IDS_POLYLINEMIN, IDS_POLYLINEMAX))
        return FALSE;

    m_cf=RegisterClipboardFormat(PSZ(IDS_STORAGEFORMAT));
    //End CHAPTER5MOD

    //Allocate contained interfaces.
    m_pIPolyline=new CImpIPolyline(this, pIUnknown);

    //CHAPTER5MOD
    if (NULL==m_pIPolyline)
        return FALSE;

    m_pIPersistStorage=new CImpIPersistStorage(this, pIUnknown);

    if (NULL==m_pIPersistStorage)
        return FALSE;
    //End CHAPTER5MOD

    return TRUE;
    }







/*
 * CPolyline::QueryInterface
 * CPolyline::AddRef
 * CPolyline::Release
 *
 * Purpose:
 *  IUnknown members for CPolyline object.
 */

STDMETHODIMP CPolyline::QueryInterface(REFIID riid, PPVOID ppv)
    {
    *ppv=NULL;

    /*
     * The only calls we get here for IUnknown are either in a
     * non-aggregated case or when we're created in an
     * aggregation, so in either we always return our IUnknown
     * for IID_IUnknown.
     */
    if (IID_IUnknown==riid)
        *ppv=this;

    //For anything else we return contained interfaces.
    //CHAPTER5MOD
    if (IID_IPolyline5==riid)
        *ppv=m_pIPolyline;

    if (IID_IPersist==riid || IID_IPersistStorage==riid)
        *ppv=m_pIPersistStorage;
    //End CHAPTER5MOD

    //AddRef any interface we'll return.
    if (NULL!=*ppv)
        {
        ((LPUNKNOWN)*ppv)->AddRef();
        return NOERROR;
        }

    return ResultFromScode(E_NOINTERFACE);
    }


STDMETHODIMP_(ULONG) CPolyline::AddRef(void)
    {
    return ++m_cRef;
    }


STDMETHODIMP_(ULONG) CPolyline::Release(void)
    {
    ULONG       cRefT;

    cRefT=--m_cRef;

    if (0L==m_cRef)
        {
        if (NULL!=m_pfnDestroy)
            (*m_pfnDestroy)();

        delete this;
        }

    return cRefT;
    }







/*
 * CPolyline::RectConvertMappings
 *
 * Purpose:
 *  Converts the contents of a rectangle from device (MM_TEXT) or
 *  HIMETRIC to the other.
 *
 * Parameters:
 *  pRect           LPRECT containing the rectangle to convert.
 *  fToDevice       BOOL TRUE to convert from HIMETRIC to device,
 *                  FALSE to convert device to HIMETRIC.
 *
 * Return Value:
 *  None
 */

void CPolyline::RectConvertMappings(LPRECT pRect, BOOL fToDevice)
    {
    HDC      hDC;
    int      iLpx, iLpy;

    if (NULL==pRect)
        return;

    hDC=GetDC(NULL);
    iLpx=GetDeviceCaps(hDC, LOGPIXELSX);
    iLpy=GetDeviceCaps(hDC, LOGPIXELSY);
    ReleaseDC(NULL, hDC);

    if (fToDevice)
        {
        pRect->left=MulDiv(iLpx, pRect->left, HIMETRIC_PER_INCH);
        pRect->top =MulDiv(iLpy, pRect->top , HIMETRIC_PER_INCH);

        pRect->right =MulDiv(iLpx, pRect->right, HIMETRIC_PER_INCH);
        pRect->bottom=MulDiv(iLpy, pRect->bottom,HIMETRIC_PER_INCH);
        }
    else
        {
        pRect->left=MulDiv(pRect->left, HIMETRIC_PER_INCH, iLpx);
        pRect->top =MulDiv(pRect->top , HIMETRIC_PER_INCH, iLpy);

        pRect->right =MulDiv(pRect->right, HIMETRIC_PER_INCH, iLpx);
        pRect->bottom=MulDiv(pRect->bottom,HIMETRIC_PER_INCH, iLpy);
        }

    return;
    }
