home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / inole2 / chap18 / cosmo / document.cpp < prev    next >
C/C++ Source or Header  |  1995-05-03  |  32KB  |  1,375 lines

  1. /*
  2.  * DOCUMENT.CPP
  3.  * Cosmo Chapter 18
  4.  *
  5.  * Implementation of the CCosmoDoc derivation of CDocument as
  6.  * well as an implementation of CPolylineAdviseSink.
  7.  *
  8.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  9.  *
  10.  * Kraig Brockschmidt, Microsoft
  11.  * Internet  :  kraigb@microsoft.com
  12.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  13.  */
  14.  
  15.  
  16. #include "cosmo.h"
  17.  
  18.  
  19. /*
  20.  * CCosmoDoc::CCosmoDoc
  21.  * CCosmoDoc::~CCosmoDoc
  22.  *
  23.  * Constructor Parameters:
  24.  *  hInst           HINSTANCE of the application.
  25.  *  pFR             PCFrame of the frame object.
  26.  *  pAdv            PCDocumentAdviseSink to notify on events
  27.  */
  28.  
  29. CCosmoDoc::CCosmoDoc(HINSTANCE hInst, PCFrame pFR
  30.     , PCDocumentAdviseSink pAdv)
  31.     : CDocument(hInst, pFR, pAdv)
  32.     {
  33.     m_pPL=NULL;
  34.     m_pPLAdv=NULL;
  35.     m_uPrevSize=SIZE_RESTORED;
  36.  
  37.     m_pDropTarget=NULL;
  38.     m_fDragSource=FALSE;
  39.  
  40.     //CHAPTER18MOD
  41.     m_cfEmbedSource=RegisterClipboardFormat(CFSTR_EMBEDSOURCE);
  42.     m_cfObjectDescriptor=RegisterClipboardFormat
  43.         (CFSTR_OBJECTDESCRIPTOR);
  44.  
  45.     m_pFigure=NULL;
  46.     //End CHAPTER18MOD
  47.     return;
  48.     }
  49.  
  50.  
  51. CCosmoDoc::~CCosmoDoc(void)
  52.     {
  53.     //CHAPTER18MOD
  54.     //Make sure the object is saved
  55.     m_pFigure->SendAdvise(OBJECTCODE_SAVEOBJECT);
  56.     m_pFigure->SendAdvise(OBJECTCODE_HIDEWINDOW);
  57.     m_pFigure->SendAdvise(OBJECTCODE_CLOSED);
  58.  
  59.     /*
  60.      * The AddRef here preserves a reference count on the object
  61.      * even after our call to CoDisconnectObject.  When we then
  62.      * Release that reference count, the figure will start
  63.      * shutdown.  In some cases shutdown will begin before this
  64.      * time in which case we need to clean up before the
  65.      * Figure is destroyed, so we delete the figure ourselves.
  66.      * This could also be handled with IExternalConnection.
  67.      */
  68.  
  69.     if (NULL!=m_pFigure)
  70.         {
  71.         m_pFigure->AddRef();
  72.         CoDisconnectObject(m_pFigure, 0L);
  73.         m_pFigure->Release();   //Starts shutdown if necessary.
  74.         delete m_pFigure;
  75.         }
  76.     //End CHAPTER18MOD
  77.  
  78.     //Clean up the allocations we did in Init
  79.     if (NULL!=m_pPL)
  80.         delete m_pPL;
  81.  
  82.     if (NULL!=m_pPLAdv)
  83.         delete m_pPLAdv;
  84.  
  85.     return;
  86.     }
  87.  
  88.  
  89.  
  90.  
  91.  
  92.  
  93. /*
  94.  * CCosmoDoc::Init
  95.  *
  96.  * Purpose:
  97.  *  Initializes an already created document window.  The client
  98.  *  actually creates the window for us, then passes that here for
  99.  *  further initialization.
  100.  *
  101.  * Parameters:
  102.  *  pDI             PDOCUMENTINIT containing initialization
  103.  *                  parameters.
  104.  *
  105.  * Return Value:
  106.  *  BOOL            TRUE if the function succeeded, FALSE otherwise.
  107.  */
  108.  
  109. BOOL CCosmoDoc::Init(PDOCUMENTINIT pDI)
  110.     {
  111.     RECT        rc;
  112.  
  113.     //Change the stringtable range to our customization.
  114.     pDI->idsMin=IDS_DOCUMENTMIN;
  115.     pDI->idsMax=IDS_DOCUMENTMAX;
  116.  
  117.     //Do default initialization
  118.     if (!CDocument::Init(pDI))
  119.         return FALSE;
  120.  
  121.     //Add the Polyline stuff we need.
  122.     m_pPLAdv=new CPolylineAdviseSink(this);
  123.     m_pPL   =new CPolyline(m_hInst);
  124.  
  125.     //Attempt to create our contained Polyline.
  126.     GetClientRect(m_hWnd, &rc);
  127.     InflateRect(&rc, -8, -8);
  128.  
  129.     if (!m_pPL->Init(m_hWnd, &rc, WS_CHILD | WS_VISIBLE
  130.         , ID_POLYLINE, m_pPLAdv))
  131.         return FALSE;
  132.  
  133.     m_pDropTarget=new CDropTarget(this);
  134.  
  135.     if (NULL!=m_pDropTarget)
  136.         {
  137.         m_pDropTarget->AddRef();
  138.         CoLockObjectExternal(m_pDropTarget, TRUE, FALSE);
  139.         RegisterDragDrop(m_hWnd, m_pDropTarget);
  140.         }
  141.  
  142.     //CHAPTER18MOD
  143.     m_pFigure=new CFigure(ObjectDestroyed, this);
  144.  
  145.     if (NULL==m_pFigure)
  146.         return FALSE;
  147.  
  148.     //We created an object, so count it.
  149.     g_cObj++;
  150.  
  151.     if (!m_pFigure->Init())
  152.         return FALSE;
  153.     //End CHAPTER18MOD
  154.  
  155.     return TRUE;
  156.     }
  157.  
  158.  
  159.  
  160.  
  161.  
  162.  
  163.  
  164. /*
  165.  * CCosmoDoc::FMessageHook
  166.  *
  167.  * Purpose:
  168.  *  Processes WM_SIZE for the document so we can resize
  169.  *  the Polyline.
  170.  *
  171.  * Parameters:
  172.  *  <WndProc Parameters>
  173.  *  pLRes           LRESULT * in which to store the return
  174.  *                  value for the message.
  175.  *
  176.  * Return Value:
  177.  *  BOOL            TRUE to prevent further processing,
  178.  *                  FALSE otherwise.
  179.  */
  180.  
  181. BOOL CCosmoDoc::FMessageHook(HWND hWnd, UINT iMsg, WPARAM wParam
  182.     , LPARAM lParam, LRESULT *pLRes)
  183.     {
  184.     UINT        dx, dy;
  185.     RECT        rc;
  186.  
  187.     *pLRes=0;
  188.  
  189.     if (WM_SIZE==iMsg)
  190.         {
  191.         //Don't effect the Polyline size to or from minimized state.
  192.         if (SIZE_MINIMIZED!=wParam && SIZE_MINIMIZED !=m_uPrevSize)
  193.             {
  194.             //When we change size, resize any Polyline we hold.
  195.             dx=LOWORD(lParam);
  196.             dy=HIWORD(lParam);
  197.  
  198.             /*
  199.              * If we are getting WM_SIZE in response to a Polyline
  200.              * notification, then don't resize the Polyline window
  201.              * again.
  202.              */
  203.             if (!m_fNoSize && NULL!=m_pPL)
  204.                 {
  205.                 //Resize the polyline to fit the new client
  206.                 SetRect(&rc, 8, 8, dx-8, dy-8);
  207.                 m_pPL->RectSet(&rc, FALSE);
  208.  
  209.                 /*
  210.                  * We consider sizing something that makes the file
  211.                  * dirty, but not until we've finished the create
  212.                  * process, which is why we set fNoDirty to FALSE
  213.                  * in WM_CREATE since we get a WM_SIZE on the first
  214.                  * creation.
  215.                  */
  216.                 if (!m_fNoDirty)
  217.                     FDirtySet(TRUE);
  218.  
  219.                 SetRect(&rc, 0, 0, dx, dy);
  220.  
  221.                 if (NULL!=m_pAdv)
  222.                     m_pAdv->OnSizeChange(this, &rc);
  223.  
  224.                 m_fNoDirty=FALSE;
  225.                 }
  226.             }
  227.  
  228.         m_uPrevSize=wParam;
  229.         }
  230.  
  231.     if (WM_LBUTTONDOWN==iMsg)
  232.         {
  233.         LPDROPSOURCE    pIDropSource;
  234.         LPDATAOBJECT    pIDataObject;
  235.         HRESULT         hr;
  236.         SCODE           sc;
  237.         DWORD           dwEffect;
  238.  
  239.         /*
  240.          * The document has an 8 pixel border around the polyline
  241.          * window where we'll see mouse clicks.  A left mouse button
  242.          * click here means the start of a drag-drop operation.
  243.          *
  244.          * Since this is a modal operation, this IDropSource
  245.          * is entirely local.
  246.          */
  247.  
  248.         pIDropSource=new CDropSource(this);
  249.  
  250.         if (NULL==pIDropSource)
  251.             return FALSE;
  252.  
  253.         pIDropSource->AddRef();
  254.         m_fDragSource=TRUE;
  255.  
  256.         //Go get the data and start the ball rolling.
  257.         pIDataObject=TransferObjectCreate(FALSE);
  258.  
  259.         if (NULL!=pIDataObject)
  260.             {
  261.             hr=DoDragDrop(pIDataObject, pIDropSource
  262.                 , DROPEFFECT_COPY | DROPEFFECT_MOVE, &dwEffect);
  263.  
  264.             pIDataObject->Release();
  265.             sc=GetScode(hr);
  266.             }
  267.         else
  268.             sc=E_FAIL;
  269.  
  270.         /*
  271.          * When we return from DoDragDrop, either cancel or drop.
  272.          * First toss the IDropSource we have here, then bail out
  273.          * on cancel, and possibly clear our data on a move drop.
  274.          */
  275.  
  276.         pIDropSource->Release();
  277.  
  278.         /*
  279.          * If dropped on the same document (determined using
  280.          * this flag, then dwEffect will be DROPEFFECT_NONE (see
  281.          * IDropTarget::Drop in DROPTGT.CPP).  In any case,
  282.          * reset this since the operation is done.
  283.          */
  284.  
  285.         m_fDragSource=FALSE;
  286.  
  287.         if (DRAGDROP_S_DROP==sc && DROPEFFECT_MOVE==dwEffect)
  288.             {
  289.             m_pPL->New();
  290.             FDirtySet(TRUE);
  291.             }
  292.  
  293.         //On a canceled drop or a copy we don't do anything else
  294.         return TRUE;
  295.         }
  296.  
  297.     if (WM_DESTROY==iMsg)
  298.         {
  299.         /*
  300.          * We have to revoke the drop target here because the window
  301.          * will be destroyed and the property forcefully removed
  302.          * before we could do this in the destructor.
  303.          */
  304.         if (NULL!=m_pDropTarget)
  305.             {
  306.             RevokeDragDrop(m_hWnd);
  307.             CoLockObjectExternal(m_pDropTarget, FALSE, TRUE);
  308.             ReleaseInterface(m_pDropTarget);
  309.             }
  310.  
  311.         return FALSE;
  312.         }
  313.  
  314.  
  315.     /*
  316.      * We return FALSE even on WM_SIZE so we can let the default
  317.      * procedure handle maximized MDI child windows appropriately.
  318.      */
  319.     return FALSE;
  320.     }
  321.  
  322.  
  323.  
  324.  
  325.  
  326.  
  327.  
  328.  
  329. /*
  330.  * CCosmoDoc::Clear
  331.  *
  332.  * Purpose:
  333.  *  Sets all contents in the document back to defaults with
  334.  *  no filename.
  335.  *
  336.  * Paramters:
  337.  *  None
  338.  *
  339.  * Return Value:
  340.  *  None
  341.  */
  342.  
  343. void CCosmoDoc::Clear(void)
  344.     {
  345.     //Completely reset the polyline
  346.     m_pPL->New();
  347.  
  348.     CDocument::Clear();
  349.     m_lVer=0;
  350.     return;
  351.     }
  352.  
  353.  
  354.  
  355. //CHAPTER18MOD
  356. /*
  357.  * CCosmoDoc::FDirtySet
  358.  *
  359.  * Purpose:
  360.  *  Sets or clears the document 'dirty' flag returning the previous
  361.  *  state of that same flag.  We override this in Cosmo server to
  362.  *  send the OnDataChange notification as necessary.
  363.  *
  364.  * Parameters:
  365.  *  fDirty          BOOL indicating the new contents of the dirty
  366.  *                  flag.
  367.  *
  368.  * Return Value:
  369.  *  BOOL            Previous value of the dirty flag.
  370.  */
  371.  
  372. BOOL CCosmoDoc::FDirtySet(BOOL fDirty)
  373.     {
  374.     BOOL        fRet;
  375.  
  376.     fRet=CDocument::FDirtySet(fDirty);
  377.     m_pFigure->SendAdvise(OBJECTCODE_DATACHANGED);
  378.  
  379.     return fRet;
  380.     }
  381.  
  382.  
  383.  
  384.  
  385. /*
  386.  * CCosmoDoc::FDirtyGet
  387.  *
  388.  * Purpose:
  389.  *  Override of the normal FDirtyGet such that we never return dirty
  390.  *  for an embedded object we're serving since updates constantly
  391.  *  happen and since the object will be saved on closure.  This then
  392.  *  prevents any message boxes asking the user to save.
  393.  *
  394.  * Parameters:
  395.  *  None
  396.  *
  397.  * Return Value:
  398.  *  BOOL            TRUE if the document is dirty, FALSE otherwise.
  399.  */
  400.  
  401. BOOL CCosmoDoc::FDirtyGet(void)
  402.     {
  403.     if (m_pFigure->FIsEmbedded())
  404.         return FALSE;
  405.  
  406.     return m_fDirty;
  407.     }
  408. //End CHAPTER18MOD
  409.  
  410.  
  411.  
  412. /*
  413.  * CCosmoDoc::Load
  414.  *
  415.  * Purpose:
  416.  *  Loads a given document without any user interface overwriting
  417.  *  the previous contents of the Polyline window.  We do this by
  418.  *  opening the file and telling the Polyline to load itself from
  419.  *  that file.
  420.  *
  421.  * Parameters:
  422.  *  fChangeFile     BOOL indicating if we're to update the window
  423.  *                  title and the filename from using this file.
  424.  *  pszFile         LPTSTR to the filename to load, NULL if the file
  425.  *                  is new and untitled.
  426.  *
  427.  * Return Value:
  428.  *  UINT            An error value from DOCERR_*
  429.  */
  430.  
  431. UINT CCosmoDoc::Load(BOOL fChangeFile, LPTSTR pszFile)
  432.     {
  433.     HRESULT         hr;
  434.     LPSTORAGE       pIStorage;
  435.  
  436.     if (NULL==pszFile)
  437.         {
  438.         //For a new untitled document, just rename ourselves.
  439.         Rename(NULL);
  440.         m_lVer=VERSIONCURRENT;
  441.         return DOCERR_NONE;
  442.         }
  443.  
  444.     /*
  445.      * If not a Compound File, open the file using STGM_CONVERT in
  446.      * transacted mode to see old files as a storage with one stream
  447.      * called "CONTENTS" (which is conveniently the name we use
  448.      * in the new files).  We must use STGM_TRANSACTED here or else
  449.      * the old file will be immediately converted on disk:  we only
  450.      * want a converted image in memory from which to read.  In
  451.      * addition, note that we need STGM_READWRITE as well since
  452.      * conversion is inherently a write operation.
  453.      */
  454.  
  455.     pIStorage=NULL;
  456.  
  457.     if (NOERROR!=StgIsStorageFile(pszFile))
  458.         {
  459.         hr=StgCreateDocfile(pszFile,STGM_TRANSACTED | STGM_READWRITE
  460.             | STGM_CONVERT | STGM_SHARE_EXCLUSIVE, 0, &pIStorage);
  461.  
  462.         if (FAILED(hr))
  463.             {
  464.             //If denied write access, try to load the old way
  465.             if (STG_E_ACCESSDENIED==GetScode(hr))
  466.                 m_lVer=m_pPL->ReadFromFile(pszFile);
  467.             else
  468.                 return DOCERR_COULDNOTOPEN;
  469.             }
  470.         }
  471.     else
  472.         {
  473.         hr=StgOpenStorage(pszFile, NULL, STGM_DIRECT | STGM_READ
  474.             | STGM_SHARE_EXCLUSIVE, NULL, 0, &pIStorage);
  475.  
  476.         if (FAILED(hr))
  477.             return DOCERR_COULDNOTOPEN;
  478.         }
  479.  
  480.     if (NULL!=pIStorage)
  481.         {
  482.         m_lVer=m_pPL->ReadFromStorage(pIStorage);
  483.         pIStorage->Release();
  484.         }
  485.  
  486.     if (POLYLINE_E_READFAILURE==m_lVer)
  487.         return DOCERR_READFAILURE;
  488.  
  489.     if (POLYLINE_E_UNSUPPORTEDVERSION==m_lVer)
  490.         return DOCERR_UNSUPPORTEDVERSION;
  491.  
  492.     if (fChangeFile)
  493.         Rename(pszFile);
  494.  
  495.     //Importing a file makes things dirty
  496.     FDirtySet(!fChangeFile);
  497.  
  498.     return DOCERR_NONE;
  499.     }
  500.  
  501.  
  502.  
  503.  
  504.  
  505.  
  506.  
  507. /*
  508.  * CCosmoDoc::Save
  509.  *
  510.  * Purpose:
  511.  *  Writes the file to a known filename, requiring that the user has
  512.  *  previously used FileOpen or FileSaveAs to provide a filename.
  513.  *
  514.  * Parameters:
  515.  *  uType           UINT indicating the type of file the user
  516.  *                  requested to save in the File Save As dialog.
  517.  *  pszFile         LPTSTR under which to save.  If NULL, use the
  518.  *                  current name.
  519.  *
  520.  * Return Value:
  521.  *  UINT            An error value from DOCERR_*
  522.  */
  523.  
  524. UINT CCosmoDoc::Save(UINT uType, LPTSTR pszFile)
  525.     {
  526.     LONG        lVer, lRet;
  527.     UINT        uTemp;
  528.     BOOL        fRename=TRUE;
  529.     HRESULT     hr;
  530.     LPSTORAGE   pIStorage;
  531.     //CHAPTER18MOD
  532.     BOOL        fEmbedding;
  533.  
  534.     fEmbedding=m_pFigure->FIsEmbedded();
  535.     //End CHAPTER18MOD
  536.  
  537.     if (NULL==pszFile)
  538.         {
  539.         fRename=FALSE;
  540.         pszFile=m_szFile;
  541.         }
  542.  
  543.     /*
  544.      * Type 1 is the current version, type 2 is version 1.0 of the
  545.      * Polyline so we use this to send the right version to
  546.      * CPolyline::WriteToFile/WriteToStorage.
  547.      */
  548.  
  549.     switch (uType)
  550.         {
  551.         case 0:         //From Save, use loaded version.
  552.             lVer=m_lVer;
  553.             break;
  554.  
  555.         case 1:
  556.             lVer=VERSIONCURRENT;
  557.             break;
  558.  
  559.         case 2:
  560.             lVer=MAKELONG(0, 1);    //1.0
  561.             break;
  562.  
  563.         default:
  564.             return DOCERR_UNSUPPORTEDVERSION;
  565.         }
  566.  
  567.     /*
  568.      * If the version the user wants to save is different from the
  569.      * version that we loaded and m_lVer is not zero (new doc),
  570.      * then inform the user of the version change and verify.
  571.      */
  572.  
  573.     //CHAPTER18MOD
  574.     //For embedding, this is Save Copy As, so don't ask about versions.
  575.     if (0!=m_lVer && m_lVer!=lVer && !fEmbedding)
  576.     //End CHAPTER18MOD
  577.         {
  578.         TCHAR       szMsg[128];
  579.  
  580.         wsprintf(szMsg, PSZ(IDS_VERSIONCHANGE)
  581.             , (UINT)HIWORD(m_lVer), (UINT)LOWORD(m_lVer)
  582.             , (UINT)HIWORD(lVer), (UINT)LOWORD(lVer));
  583.  
  584.         uTemp=MessageBox(m_hWnd, szMsg, PSZ(IDS_DOCUMENTCAPTION)
  585.             , MB_YESNOCANCEL);
  586.  
  587.         if (IDCANCEL==uTemp)
  588.             return DOCERR_CANCELLED;
  589.  
  590.         //If the user won't upgrade, revert to loaded version.
  591.         if (IDNO==uTemp)
  592.             lVer=m_lVer;
  593.         }
  594.  
  595.     /*
  596.      * For 1.0 files, still use the old code.  For new files, use
  597.      * storages instead
  598.      */
  599.     if (lVer==MAKELONG(0, 1))
  600.         lRet=m_pPL->WriteToFile(pszFile, lVer);
  601.     else
  602.         {
  603.         hr=StgCreateDocfile(pszFile, STGM_DIRECT | STGM_READWRITE
  604.             | STGM_CREATE | STGM_SHARE_EXCLUSIVE, 0, &pIStorage);
  605.  
  606.         if (FAILED(hr))
  607.             return DOCERR_COULDNOTOPEN;
  608.  
  609.         //Mark this as one of our class
  610.         WriteClassStg(pIStorage, CLSID_CosmoFigure);
  611.  
  612.         //Write user-readable class information
  613.         WriteFmtUserTypeStg(pIStorage, m_cf
  614.             , PSZ(IDS_CLIPBOARDFORMAT));
  615.  
  616.         lRet=m_pPL->WriteToStorage(pIStorage, lVer);
  617.         pIStorage->Release();
  618.         }
  619.  
  620.     if (POLYLINE_E_NONE!=lRet)
  621.         return DOCERR_WRITEFAILURE;
  622.  
  623.     //CHAPTER18MOD
  624.     //Saving makes us clean, but this doesn't apply to embedding.
  625.     if (!fEmbedding)
  626.         FDirtySet(FALSE);
  627.     //End CHAPTER18MOD
  628.  
  629.     //Update the known version of this document.
  630.     m_lVer=lVer;
  631.  
  632.     //CHAPTER18MOD
  633.     /*
  634.      * If we're embedding, this is Save Copy As, so no rename.
  635.      * Note that we also don't care about having been set to clean
  636.      * since we're always 'clean' as an embedded object from
  637.      * the user's perspective.
  638.      */
  639.     if (fRename && !fEmbedding)
  640.         Rename(pszFile);
  641.     //End CHAPTER18MOD
  642.  
  643.     return DOCERR_NONE;
  644.     }
  645.  
  646.  
  647.  
  648.  
  649.  
  650.  
  651. /*
  652.  * CCosmoDoc::Undo
  653.  *
  654.  * Purpose:
  655.  *  Reverses a previous action.
  656.  *
  657.  * Parameters:
  658.  *  None
  659.  *
  660.  * Return Value:
  661.  *  None
  662.  */
  663.  
  664. void CCosmoDoc::Undo(void)
  665.     {
  666.     m_pPL->Undo();
  667.     return;
  668.     }
  669.  
  670.  
  671.  
  672.  
  673.  
  674.  
  675. /*
  676.  * CCosmoDoc::Clip
  677.  *
  678.  * Purpose:
  679.  *  Places a private format, a metafile, and a bitmap of the display
  680.  *  on the clipboard, optionally implementing Cut by deleting the
  681.  *  data in the current window after rendering.
  682.  *
  683.  * Parameters:
  684.  *  hWndFrame       HWND of the main window.
  685.  *  fCut            BOOL indicating cut (TRUE) or copy (FALSE).
  686.  *
  687.  * Return Value:
  688.  *  BOOL            TRUE if successful, FALSE otherwise.
  689.  */
  690.  
  691. BOOL CCosmoDoc::Clip(HWND hWndFrame, BOOL fCut)
  692.     {
  693.     BOOL            fRet=TRUE;
  694.     LPDATAOBJECT    pIDataObject;
  695.  
  696.     pIDataObject=TransferObjectCreate(fCut);
  697.  
  698.     if (NULL==pIDataObject)
  699.         return FALSE;
  700.  
  701.     fRet=SUCCEEDED(OleSetClipboard(pIDataObject));
  702.     pIDataObject->Release();
  703.  
  704.     //Delete our current data if "cut" succeeded.
  705.     if (fRet && fCut)
  706.         {
  707.         m_pPL->New();
  708.         FDirtySet(TRUE);
  709.         }
  710.  
  711.  
  712.     return fRet;
  713.     }
  714.  
  715.  
  716.  
  717.  
  718.  
  719. /*
  720.  * CCosmoDoc::RenderFormat
  721.  *
  722.  * Purpose:
  723.  *  Renders a specific clipboard format into global memory.
  724.  *
  725.  * Parameters:
  726.  *  cf              UINT format to render.
  727.  *
  728.  * Return Value:
  729.  *  HGLOBAL         Global memory handle containing the data.
  730.  */
  731.  
  732. HGLOBAL CCosmoDoc::RenderFormat(UINT cf)
  733.     {
  734.     HGLOBAL     hMem;
  735.  
  736.     if (cf==m_cf)
  737.         {
  738.         m_pPL->DataGetMem(VERSIONCURRENT, &hMem);
  739.         return hMem;
  740.         }
  741.  
  742.     switch (cf)
  743.         {
  744.         case CF_METAFILEPICT:
  745.             return m_pPL->RenderMetafilePict();
  746.  
  747.         case CF_BITMAP:
  748.             return (HGLOBAL)m_pPL->RenderBitmap();
  749.         }
  750.  
  751.     return NULL;
  752.     }
  753.  
  754.  
  755.  
  756.  
  757. //CHAPTER18MOD
  758. /*
  759.  * CCosmoDoc::RenderMedium
  760.  *
  761.  * Purpose:
  762.  *  Like RenderFormat, this function creates a specific data format
  763.  *  based on the cf parameter.  Unlike RenderFormat, we store the
  764.  *  result in a STGMEDIUM in case it has a medium other than
  765.  *  TYMED_HGLOBAL.  For conveniece we'll centralize all compound
  766.  *  document formats here, hGlobal or not.
  767.  *
  768.  * Parameters:
  769.  *  cf              UINT clipboard format of interest.
  770.  *  pSTM            LSTGMEDIUM to fill.  We only fill the union
  771.  *                  and tymed.
  772.  *
  773.  * Return Value:
  774.  *  BOOL            TRUE if we could render the format,
  775.  *                  FALSE otherwise.
  776.  */
  777.  
  778. BOOL CCosmoDoc::RenderMedium(UINT cf, LPSTGMEDIUM pSTM)
  779.     {
  780.     if (NULL==pSTM)
  781.         return FALSE;
  782.  
  783.     if (cf==m_cfEmbedSource)
  784.         {
  785.         /*
  786.          * Embed Source data is an IStorage containing the native
  787.          * data (same as Embedded Object).  Since our data is small,
  788.          * it makes the most sense to create an IStorage in memory
  789.          * and put transfer that instead of a disk-based IStorage.
  790.          */
  791.  
  792.         pSTM->pstg=INOLE_CreateStorageOnHGlobal(STGM_DIRECT
  793.             | STGM_READWRITE | STGM_SHARE_EXCLUSIVE);
  794.  
  795.         if (NULL==pSTM->pstg)
  796.             return FALSE;
  797.  
  798.         //Now save the data to the storage.
  799.         WriteClassStg(pSTM->pstg, CLSID_CosmoFigure);
  800.         WriteFmtUserTypeStg(pSTM->pstg, m_cf
  801.             , PSZ(IDS_CLIPBOARDFORMAT));
  802.  
  803.         if (POLYLINE_E_NONE!=m_pPL->WriteToStorage(pSTM->pstg
  804.             , VERSIONCURRENT))
  805.             {
  806.             /*
  807.              * When someone releases the IStorage, STORAGE.DLL will
  808.              * release the ILockBytes which, having fDeleteOnRelease
  809.              * TRUE (second parameter) will release the memory.
  810.              * That's why we don't have STGM_DELETEONRELEASE on the
  811.              * IStorage.
  812.              */
  813.             pSTM->pstg->Release();
  814.             return FALSE;
  815.             }
  816.  
  817.         pSTM->tymed=TYMED_ISTORAGE;
  818.         return TRUE;
  819.         }
  820.  
  821.     if (cf==m_cfObjectDescriptor)
  822.         {
  823.         SIZEL   szl, szlT;
  824.         POINTL  ptl;
  825.         RECT    rc;
  826.  
  827.         m_pPL->SizeGet(&rc);
  828.         SETSIZEL(szlT, rc.right, rc.bottom);
  829.         XformSizeInPixelsToHimetric(NULL, &szlT, &szl);
  830.  
  831.         SETPOINTL(ptl, 0, 0);
  832.  
  833.         pSTM->hGlobal=INOLE_AllocObjectDescriptor
  834.             (CLSID_CosmoFigure, DVASPECT_CONTENT, szl, ptl
  835.             , OLEMISC_RECOMPOSEONRESIZE, PSZ(IDS_OBJECTDESCRIPTION)
  836.             , NULL);
  837.  
  838.         pSTM->tymed=TYMED_HGLOBAL;
  839.         return (NULL!=pSTM->hGlobal);
  840.         }
  841.  
  842.     return FALSE;
  843.     }
  844.  
  845.  
  846. //End CHAPTER18MOD
  847.  
  848.  
  849.  
  850. /*
  851.  * CCosmoDoc::FQueryPaste
  852.  *
  853.  * Purpose:
  854.  *  Determines if we can paste data from the clipboard.
  855.  *
  856.  * Parameters:
  857.  *  None
  858.  *
  859.  * Return Value:
  860.  *  BOOL            TRUE if data is available, FALSE otherwise.
  861.  */
  862.  
  863. BOOL CCosmoDoc::FQueryPaste(void)
  864.     {
  865.     LPDATAOBJECT    pIDataObject;
  866.     BOOL            fRet;
  867.  
  868.     if (FAILED(OleGetClipboard(&pIDataObject)))
  869.         return FALSE;
  870.  
  871.     fRet=FQueryPasteFromData(pIDataObject);
  872.     pIDataObject->Release();
  873.     return fRet;
  874.     }
  875.  
  876.  
  877.  
  878. /*
  879.  * CCosmoDoc::FQueryPasteFromData
  880.  * (Protected)
  881.  *
  882.  * Purpose:
  883.  *  Determines if we can paste data from a data object.
  884.  *
  885.  * Parameters:
  886.  *  pIDataObject    LPDATAOBJECT from which we might want to paste.
  887.  *
  888.  * Return Value:
  889.  *  BOOL            TRUE if data is available, FALSE otherwise.
  890.  */
  891.  
  892. BOOL CCosmoDoc::FQueryPasteFromData(LPDATAOBJECT pIDataObject)
  893.     {
  894.     FORMATETC       fe;
  895.  
  896.     SETDefFormatEtc(fe, m_cf, TYMED_HGLOBAL);
  897.     return (NOERROR==pIDataObject->QueryGetData(&fe));
  898.     }
  899.  
  900.  
  901.  
  902.  
  903. /*
  904.  * CCosmoDoc::Paste
  905.  *
  906.  * Purpose:
  907.  *  Retrieves the private data format from the clipboard and sets it
  908.  *  to the current figure in the editor window.
  909.  *
  910.  *  Note that if this function is called, then the clipboard format
  911.  *  is available because the Paste menu item is only enabled if the
  912.  *  format is present.
  913.  *
  914.  * Parameters:
  915.  *  hWndFrame       HWND of the main window.
  916.  *
  917.  * Return Value:
  918.  *  BOOL            TRUE if successful, FALSE otherwise.
  919.  */
  920.  
  921. BOOL CCosmoDoc::Paste(HWND hWndFrame)
  922.     {
  923.     LPDATAOBJECT    pIDataObject;
  924.     BOOL            fRet;
  925.  
  926.     if (FAILED(OleGetClipboard(&pIDataObject)))
  927.         return FALSE;
  928.  
  929.     fRet=PasteFromData(pIDataObject);
  930.     pIDataObject->Release();
  931.  
  932.     return fRet;
  933.     }
  934.  
  935.  
  936.  
  937.  
  938. /*
  939.  * CCosmoDoc::PasteFromData
  940.  * (Protected)
  941.  *
  942.  * Purpose:
  943.  *  Retrieves the private data format from a data object and sets
  944.  *  it to the current figure in the editor window.
  945.  *
  946.  * Parameters:
  947.  *  pIDataObject    LPDATAOBJECT from which to paste.
  948.  *
  949.  * Return Value:
  950.  *  BOOL            TRUE if successful, FALSE otherwise.
  951.  */
  952.  
  953. BOOL CCosmoDoc::PasteFromData(LPDATAOBJECT pIDataObject)
  954.     {
  955.     FORMATETC       fe;
  956.     STGMEDIUM       stm;
  957.     BOOL            fRet;
  958.  
  959.     SETDefFormatEtc(fe, m_cf, TYMED_HGLOBAL);
  960.     fRet=SUCCEEDED(pIDataObject->GetData(&fe, &stm));
  961.  
  962.     if (fRet && NULL!=stm.hGlobal)
  963.         {
  964.         m_pPL->DataSetMem(stm.hGlobal, FALSE, FALSE, TRUE);
  965.         ReleaseStgMedium(&stm);
  966.         FDirtySet(TRUE);
  967.         }
  968.  
  969.     return fRet;
  970.     }
  971.  
  972.  
  973.  
  974.  
  975. /*
  976.  * CCosmoDoc::TransferObjectCreate
  977.  * (Protected)
  978.  *
  979.  * Purpose:
  980.  *  Creates a DataTransferObject and stuffs the current Polyline
  981.  *  data into it, used for both clipboard and drag-drop operations.
  982.  *
  983.  * Parameters:
  984.  *  fCut            BOOL TRUE if we're cutting, FALSE if we're
  985.  *                  copying.
  986.  *
  987.  * Return Value:
  988.  *  LPDATAOBJECT    Pointer to the object created, NULL on failure
  989.  */
  990.  
  991. LPDATAOBJECT CCosmoDoc::TransferObjectCreate(BOOL fCut)
  992.     {
  993.     UINT            i;
  994.     HRESULT         hr;
  995.     STGMEDIUM       stm;
  996.     FORMATETC       fe;
  997.     LPDATAOBJECT    pIDataObject=NULL;
  998.     //CHAPTER18MOD
  999.     const UINT      cFormats=5;
  1000.     static UINT     rgcf[5]={0, 0, 0, CF_METAFILEPICT, CF_BITMAP};
  1001.     static DWORD    rgtm[5]={TYMED_HGLOBAL, TYMED_ISTORAGE
  1002.                         , TYMED_HGLOBAL, TYMED_MFPICT, TYMED_GDI};
  1003.     //CHAPTER18MOD
  1004.  
  1005.     hr=CoCreateInstance(CLSID_DataTransferObject, NULL
  1006.         , CLSCTX_INPROC_SERVER, IID_IDataObject
  1007.         , (PPVOID)&pIDataObject);
  1008.  
  1009.     if (FAILED(hr))
  1010.         return NULL;
  1011.  
  1012.     rgcf[0]=m_cf;
  1013.     //CHAPTER18MOD
  1014.     rgcf[1]=m_cfEmbedSource;
  1015.     rgcf[2]=m_cfObjectDescriptor;
  1016.     //End CHAPTER18MOD
  1017.  
  1018.     for (i=0; i < cFormats; i++)
  1019.         {
  1020.         //CHAPTER18MOD
  1021.         /*
  1022.          * RenderFormat handles memory handles, but for compound doc
  1023.          * formats we need something more.  So if RenderFormat fails
  1024.          * (which it will for i=1, try our latest addition which
  1025.          * writes to a different field in the STGMEDIUM.
  1026.          */
  1027.         stm.hGlobal=RenderFormat(rgcf[i]);
  1028.  
  1029.         if (NULL==stm.hGlobal)
  1030.             {
  1031.             if (!RenderMedium(rgcf[i], &stm))
  1032.                 continue;
  1033.             }
  1034.  
  1035.         stm.tymed=rgtm[i];
  1036.         stm.pUnkForRelease=NULL;
  1037.         SETDefFormatEtc(fe, rgcf[i], rgtm[i]);
  1038.         pIDataObject->SetData(&fe, &stm, TRUE);
  1039.         //End CHAPTER18MOD
  1040.         }
  1041.  
  1042.     return pIDataObject;    //Caller now responsible
  1043.     }
  1044.  
  1045.  
  1046.  
  1047. /*
  1048.  * CCosmoDoc::DropSelectTargetWindow
  1049.  * (Protected)
  1050.  *
  1051.  * Purpose:
  1052.  *  Creates a thin inverted frame around a window that we use to
  1053.  *  show the window as a drop target.  This is a toggle function:
  1054.  *  It uses XOR to create the effect so it must be called twice to
  1055.  *  leave the window as it was.
  1056.  *
  1057.  * Parameters:
  1058.  *  None
  1059.  *
  1060.  * Return Value:
  1061.  *  None
  1062.  */
  1063.  
  1064. void CCosmoDoc::DropSelectTargetWindow(void)
  1065.     {
  1066.     HDC         hDC;
  1067.     RECT        rc;
  1068.     UINT        dd=3;
  1069.     HWND        hWnd;
  1070.  
  1071.     hWnd=m_pPL->Window();
  1072.     hDC=GetWindowDC(hWnd);
  1073.     GetClientRect(hWnd, &rc);
  1074.  
  1075.     //Frame this window with inverted pixels
  1076.  
  1077.     //Top
  1078.     PatBlt(hDC, rc.left, rc.top, rc.right-rc.left, dd, DSTINVERT);
  1079.  
  1080.     //Bottom
  1081.     PatBlt(hDC, rc.left, rc.bottom-dd, rc.right-rc.left, dd
  1082.         , DSTINVERT);
  1083.  
  1084.     //Left excluding regions already affected by top and bottom
  1085.     PatBlt(hDC, rc.left, rc.top+dd, dd, rc.bottom-rc.top-(2*dd)
  1086.         , DSTINVERT);
  1087.  
  1088.     //Right excluding regions already affected by top and bottom
  1089.     PatBlt(hDC, rc.right-dd, rc.top+dd, dd, rc.bottom-rc.top-(2*dd)
  1090.         , DSTINVERT);
  1091.  
  1092.     ReleaseDC(hWnd, hDC);
  1093.     return;
  1094.     }
  1095.  
  1096.  
  1097.  
  1098.  
  1099.  
  1100. /*
  1101.  * CCosmoDoc::ColorSet
  1102.  *
  1103.  * Purpose:
  1104.  *  Changes a color used in our contained Polyline.
  1105.  *
  1106.  * Parameters:
  1107.  *  iColor          UINT index of the color to change.
  1108.  *  cr              COLORREF new color.
  1109.  *
  1110.  * Return Value:
  1111.  *  COLORREF        Previous color for the given index.
  1112.  */
  1113.  
  1114. COLORREF CCosmoDoc::ColorSet(UINT iColor, COLORREF cr)
  1115.     {
  1116.     return m_pPL->ColorSet(iColor, cr);
  1117.     }
  1118.  
  1119.  
  1120.  
  1121.  
  1122.  
  1123. /*
  1124.  * CCosmoDoc::ColorGet
  1125.  *
  1126.  * Purpose:
  1127.  *  Retrieves a color currently in use in the Polyline.
  1128.  *
  1129.  * Parameters:
  1130.  *  iColor          UINT index of the color to retrieve.
  1131.  *
  1132.  * Return Value:
  1133.  *  COLORREF        Current color for the given index.
  1134.  */
  1135.  
  1136. COLORREF CCosmoDoc::ColorGet(UINT iColor)
  1137.     {
  1138.     return m_pPL->ColorGet(iColor);
  1139.     }
  1140.  
  1141.  
  1142.  
  1143.  
  1144.  
  1145.  
  1146. /*
  1147.  * CCosmoDoc::LineStyleSet
  1148.  *
  1149.  * Purpose:
  1150.  *  Changes the line style currently used in the Polyline
  1151.  *
  1152.  * Parameters:
  1153.  *  iStyle          UINT index of the new line style to use.
  1154.  *
  1155.  * Return Value:
  1156.  *  UINT            Previous line style.
  1157.  */
  1158.  
  1159.  
  1160. UINT CCosmoDoc::LineStyleSet(UINT iStyle)
  1161.     {
  1162.     return m_pPL->LineStyleSet(iStyle);
  1163.     }
  1164.  
  1165.  
  1166.  
  1167.  
  1168.  
  1169.  
  1170.  
  1171. /*
  1172.  * CCosmoDoc::LineStyleGet
  1173.  *
  1174.  * Purpose:
  1175.  *  Retrieves the line style currently used in the Polyline
  1176.  *
  1177.  * Parameters:
  1178.  *  None
  1179.  *
  1180.  * Return Value:
  1181.  *  UINT            Current line style.
  1182.  */
  1183.  
  1184.  
  1185. UINT CCosmoDoc::LineStyleGet(void)
  1186.     {
  1187.     if (NULL==m_pPL)    //m_pPL might not be valid yet
  1188.         return 0L;
  1189.  
  1190.     return m_pPL->LineStyleGet();
  1191.     }
  1192.  
  1193.  
  1194.  
  1195.  
  1196.  
  1197.  
  1198.  
  1199.  
  1200. /*
  1201.  * CPolylineAdviseSink::CPolylineAdviseSink
  1202.  * CPolylineAdviseSink::~CPolylineAdviseSink
  1203.  *
  1204.  * Constructor Parameters:
  1205.  *  pv              LPVOID to store in this object
  1206.  */
  1207.  
  1208. CPolylineAdviseSink::CPolylineAdviseSink(LPVOID pv)
  1209.     {
  1210.     m_pv=pv;
  1211.     return;
  1212.     }
  1213.  
  1214.  
  1215. CPolylineAdviseSink::~CPolylineAdviseSink(void)
  1216.     {
  1217.     return;
  1218.     }
  1219.  
  1220.  
  1221.  
  1222.  
  1223.  
  1224. /*
  1225.  * CPolylineAdviseSink::OnPointChange
  1226.  *
  1227.  * Purpose:
  1228.  *  Informs the document that the polyline added or removed a point.
  1229.  *
  1230.  * Parameters:
  1231.  *  None
  1232.  *
  1233.  * Return Value:
  1234.  *  None
  1235.  */
  1236.  
  1237. void CPolylineAdviseSink::OnPointChange(void)
  1238.     {
  1239.     PCDocument      pDoc=(PCDocument)m_pv;
  1240.  
  1241.     pDoc->FDirtySet(TRUE);
  1242.     return;
  1243.     }
  1244.  
  1245.  
  1246.  
  1247.  
  1248.  
  1249.  
  1250. /*
  1251.  * CPolylineAdviseSink::OnSizeChange
  1252.  *
  1253.  * Purpose:
  1254.  *  Informs the document that the polyline changed size.
  1255.  *
  1256.  * Parameters:
  1257.  *  None
  1258.  *
  1259.  * Return Value:
  1260.  *  None
  1261.  */
  1262.  
  1263. void CPolylineAdviseSink::OnSizeChange(void)
  1264.     {
  1265.     PCCosmoDoc      pDoc=(PCCosmoDoc)m_pv;
  1266.     RECT            rc;
  1267.     DWORD           dwStyle;
  1268.  
  1269.     /*
  1270.      * Polyline window is informing us that it changed size in
  1271.      * response to setting it's data.  Therefore we have to
  1272.      * size ourselves accordingly but without moving the screen
  1273.      * position of the polyline window.
  1274.      */
  1275.  
  1276.     pDoc->m_fNoSize=TRUE;
  1277.  
  1278.     //Set the document window size.
  1279.     GetWindowRect(pDoc->m_pPL->Window(), &rc);
  1280.     InflateRect(&rc, 8, 8);
  1281.  
  1282.     //Adjust for a window sans menu
  1283.     dwStyle=GetWindowLong(pDoc->m_hWnd, GWL_STYLE);
  1284.     AdjustWindowRect(&rc, dwStyle, FALSE);
  1285.  
  1286.     SetWindowPos(pDoc->m_hWnd, NULL, 0, 0, rc.right-rc.left
  1287.         , rc.bottom-rc.top, SWP_NOMOVE | SWP_NOZORDER);
  1288.  
  1289.     if (NULL!=pDoc->m_pAdv)
  1290.         pDoc->m_pAdv->OnSizeChange(pDoc, &rc);
  1291.  
  1292.     pDoc->m_fNoSize=FALSE;
  1293.     pDoc->FDirtySet(TRUE);
  1294.  
  1295.     return;
  1296.     }
  1297.  
  1298.  
  1299.  
  1300.  
  1301.  
  1302. /*
  1303.  * CPolylineAdviseSink::OnDataChange
  1304.  *
  1305.  * Purpose:
  1306.  *  Informs the document that the polyline data changed.
  1307.  *
  1308.  * Parameters:
  1309.  *  None
  1310.  *
  1311.  * Return Value:
  1312.  *  None
  1313.  */
  1314.  
  1315. void CPolylineAdviseSink::OnDataChange(void)
  1316.     {
  1317.     PCCosmoDoc      pDoc=(PCCosmoDoc)m_pv;
  1318.  
  1319.     if (NULL!=pDoc->m_pAdv)
  1320.         pDoc->m_pAdv->OnDataChange(pDoc);
  1321.  
  1322.     pDoc->FDirtySet(TRUE);
  1323.     return;
  1324.     }
  1325.  
  1326.  
  1327.  
  1328.  
  1329.  
  1330. /*
  1331.  * CPolylineAdviseSink::OnColorChange
  1332.  *
  1333.  * Purpose:
  1334.  *  Informs the document that the polyline data changed a color.
  1335.  *
  1336.  * Parameters:
  1337.  *  None
  1338.  *
  1339.  * Return Value:
  1340.  *  None
  1341.  */
  1342.  
  1343. void CPolylineAdviseSink::OnColorChange(void)
  1344.     {
  1345.     PCCosmoDoc      pDoc=(PCCosmoDoc)m_pv;
  1346.  
  1347.     pDoc->FDirtySet(TRUE);
  1348.     return;
  1349.     }
  1350.  
  1351.  
  1352.  
  1353.  
  1354.  
  1355. /*
  1356.  * CPolylineAdviseSink::OnLineStyleChange
  1357.  *
  1358.  * Purpose:
  1359.  *  Informs the document that the polyline changed its line style.
  1360.  *
  1361.  * Parameters:
  1362.  *  None
  1363.  *
  1364.  * Return Value:
  1365.  *  None
  1366.  */
  1367.  
  1368. void CPolylineAdviseSink::OnLineStyleChange(void)
  1369.     {
  1370.     PCCosmoDoc      pDoc=(PCCosmoDoc)m_pv;
  1371.  
  1372.     pDoc->FDirtySet(TRUE);
  1373.     return;
  1374.     }
  1375.