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 / chap11 / freeload / document.cpp < prev    next >
C/C++ Source or Header  |  1995-05-03  |  19KB  |  769 lines

  1. /*
  2.  * DOCUMENT.CPP
  3.  * Freeloader Chapter 11
  4.  *
  5.  * Implementation of the CFreeloaderDoc derivation of CDocument.
  6.  * We create a default handler object and use it for drawing, data
  7.  * caching, and serialization.
  8.  *
  9.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  10.  *
  11.  * Kraig Brockschmidt, Microsoft
  12.  * Internet  :  kraigb@microsoft.com
  13.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  14.  */
  15.  
  16.  
  17. #include "freeload.h"
  18.  
  19.  
  20. /*
  21.  * CFreeloaderDoc::CFreeloaderDoc
  22.  * CFreeloaderDoc::~CFreeloaderDoc
  23.  *
  24.  * Constructor Parameters:
  25.  *  hInst           HINSTANCE of the application.
  26.  *  pFR             PCFrame of the frame object.
  27.  *  pAdv            PCDocumentAdviseSink to notify on events
  28.  */
  29.  
  30. CFreeloaderDoc::CFreeloaderDoc(HINSTANCE hInst, PCFrame pFR
  31.     , PCDocumentAdviseSink pAdv)
  32.     : CDocument(hInst, pFR, pAdv)
  33.     {
  34.     m_pIStorage=NULL;
  35.     m_pIUnknown=NULL;
  36.     m_dwConn=0;
  37.     m_clsID=CLSID_NULL;
  38.     return;
  39.     }
  40.  
  41.  
  42. CFreeloaderDoc::~CFreeloaderDoc(void)
  43.     {
  44.     ReleaseObject();
  45.     ReleaseInterface(m_pIStorage);
  46.     return;
  47.     }
  48.  
  49.  
  50.  
  51.  
  52. /*
  53.  * CFreeloaderDoc::ReleaseObject
  54.  *
  55.  * Purpose:
  56.  *  Centralizes cleanup code for the object and its cache.
  57.  *
  58.  * Parameters:
  59.  *  None
  60.  *
  61.  * Return Value:
  62.  *  None
  63.  */
  64.  
  65. void CFreeloaderDoc::ReleaseObject(void)
  66.     {
  67.     LPOLECACHE      pIOleCache;
  68.     HRESULT         hr;
  69.  
  70.     if (0!=m_dwConn)
  71.         {
  72.         hr=m_pIUnknown->QueryInterface(IID_IOleCache
  73.             , (PPVOID)&pIOleCache);
  74.  
  75.         if (SUCCEEDED(hr))
  76.             {
  77.             pIOleCache->Uncache(m_dwConn);
  78.             pIOleCache->Release();
  79.             }
  80.         }
  81.  
  82.     ReleaseInterface(m_pIUnknown);
  83.     CoFreeUnusedLibraries();
  84.     m_dwConn=0;
  85.     return;
  86.     }
  87.  
  88.  
  89.  
  90. /*
  91.  * CFreeloaderDoc::FInit
  92.  *
  93.  * Purpose:
  94.  *  Initializes an already created document window.  Here we
  95.  *  only change the stringtable bounds.
  96.  *
  97.  * Parameters:
  98.  *  pDI             PDOCUMENTINIT containing initialization
  99.  *                  parameters.
  100.  *
  101.  * Return Value:
  102.  *  BOOL            TRUE if the function succeeded, FALSE otherwise.
  103.  */
  104.  
  105. BOOL CFreeloaderDoc::FInit(PDOCUMENTINIT pDI)
  106.     {
  107.     //Change the stringtable range to our customization.
  108.     pDI->idsMin=IDS_DOCUMENTMIN;
  109.     pDI->idsMax=IDS_DOCUMENTMAX;
  110.  
  111.     //Do default initialization
  112.     return CDocument::Init(pDI);
  113.     }
  114.  
  115.  
  116.  
  117.  
  118.  
  119. /*
  120.  * CFreeloaderDoc::FMessageHook
  121.  *
  122.  * Purpose:
  123.  *  Processes WM_PAINT for the document so we can draw the object.
  124.  *
  125.  * Parameters:
  126.  *  <WndProc Parameters>
  127.  *  pLRes           LRESULT * in which to store the return
  128.  *                  value for the message.
  129.  *
  130.  * Return Value:
  131.  *  BOOL            TRUE to prevent further processing,
  132.  *                  FALSE otherwise.
  133.  */
  134.  
  135. BOOL CFreeloaderDoc::FMessageHook(HWND hWnd, UINT iMsg
  136.     , WPARAM wParam, LPARAM lParam, LRESULT *pLRes)
  137.     {
  138.     PAINTSTRUCT     ps;
  139.     HDC             hDC;
  140.     RECT            rc;
  141.     RECTL           rcl;
  142.     LPVIEWOBJECT2   pIViewObject2;
  143.     HRESULT         hr;
  144.  
  145.     if (WM_PAINT!=iMsg)
  146.         return FALSE;
  147.  
  148.     hDC=BeginPaint(hWnd, &ps);
  149.     GetClientRect(hWnd, &rc);
  150.  
  151.     //Draw the object with IViewObject2::Draw, allowing ESC
  152.     if (NULL!=m_pIUnknown)
  153.         {
  154.         hr=m_pIUnknown->QueryInterface(IID_IViewObject2
  155.             , (PPVOID)&pIViewObject2);
  156.  
  157.         if (SUCCEEDED(hr))
  158.             {
  159.             //Put "Hit Esc to stop" in the status line
  160.             m_pFR->StatusLine()->MessageSet(PSZ(IDS_HITESCTOSTOP));
  161.  
  162.             RECTLFROMRECT(rcl, rc);
  163.             pIViewObject2->Draw(DVASPECT_CONTENT, -1, NULL, NULL
  164.                 , 0, hDC, &rcl, NULL, ContinuePaint, 0);
  165.             pIViewObject2->Release();
  166.  
  167.             m_pFR->StatusLine()->MessageDisplay(ID_MESSAGEREADY);
  168.             }
  169.         }
  170.  
  171.     EndPaint(hWnd, &ps);
  172.     return FALSE;
  173.     }
  174.  
  175.  
  176.  
  177. /*
  178.  * ContinuePaint
  179.  *
  180.  * Purpose:
  181.  *  Callback function for IViewObject2::Draw that allows us to
  182.  *  abort a long repaint.  This implementation watches the
  183.  *  Esc key through GetAsyncKeyState.
  184.  *
  185.  * Parameters:
  186.  *  dwContinue      DWORD custom data passed to IViewObject::Draw
  187.  *                  which in our case holds the document pointer.
  188.  *
  189.  * Return Value:
  190.  *  BOOL            TRUE to continue painting, FALSE to stop it.
  191.  */
  192.  
  193. BOOL CALLBACK ContinuePaint(DWORD dwContinue)
  194.     {
  195.     return !(GetAsyncKeyState(VK_ESCAPE) < 0);
  196.     }
  197.  
  198.  
  199.  
  200.  
  201.  
  202. /*
  203.  * CFreeloaderDoc::Load
  204.  *
  205.  * Purpose:
  206.  *  Loads a given document without any user interface overwriting
  207.  *  the previous contents of the window.
  208.  *
  209.  * Parameters:
  210.  *  fChangeFile     BOOL indicating if we're to update the window
  211.  *                  title and the filename from using this file.
  212.  *  pszFile         LPTSTR to the filename to load, NULL if the file
  213.  *                  is new and untitled.
  214.  *
  215.  * Return Value:
  216.  *  UINT            An error value from DOCERR_...
  217.  */
  218.  
  219. UINT CFreeloaderDoc::Load(BOOL fChangeFile, LPTSTR pszFile)
  220.     {
  221.     HRESULT             hr;
  222.     LPSTORAGE           pIStorage;
  223.     LPUNKNOWN           pIUnknown;
  224.     LPPERSISTSTORAGE    pIPersistStorage;
  225.     DWORD               dwMode=STGM_TRANSACTED | STGM_READWRITE
  226.                             | STGM_SHARE_EXCLUSIVE;
  227.     CLSID               clsID;
  228.  
  229.     if (NULL==pszFile)
  230.         {
  231.         //Create a new temp file.
  232.         hr=StgCreateDocfile(NULL, dwMode | STGM_CREATE
  233.             | STGM_DELETEONRELEASE, 0, &pIStorage);
  234.  
  235.         if (FAILED(hr))
  236.             return DOCERR_COULDNOTOPEN;
  237.  
  238.         m_pIStorage=pIStorage;
  239.  
  240.         FDirtySet(FALSE);
  241.         Rename(NULL);
  242.         return DOCERR_NONE;
  243.         }
  244.  
  245.     //Attempt to open the storage.
  246.     hr=StgOpenStorage(pszFile, NULL, dwMode, NULL, 0, &pIStorage);
  247.  
  248.     if (FAILED(hr))
  249.         return DOCERR_COULDNOTOPEN;
  250.  
  251.     /*
  252.      * When we previously called IPersistStorage::Save, we saved
  253.      * the class of this object type with WriteClassStg.  Now
  254.      * we read that CLSID, create a data cache for it, then
  255.      * have it reload its data into the cache through
  256.      * IPersistStorage::Load.
  257.      */
  258.  
  259.     hr=ReadClassStg(pIStorage, &clsID);
  260.  
  261.     hr=CreateDataCache(NULL, clsID, IID_IUnknown
  262.         , (PPVOID)&pIUnknown);
  263.  
  264.     if (FAILED(hr))
  265.         {
  266.         pIStorage->Release();
  267.         return DOCERR_READFAILURE;
  268.         }
  269.  
  270.     //Get IPersistStorage for the data we hold.
  271.     pIUnknown->QueryInterface(IID_IPersistStorage
  272.         , (PPVOID)&pIPersistStorage);
  273.  
  274.     //Load might fail because the object is already open...
  275.     hr=pIPersistStorage->Load(pIStorage);
  276.     pIPersistStorage->Release();
  277.  
  278.     if (FAILED(hr))
  279.         {
  280.         pIUnknown->Release();
  281.         pIStorage->Release();
  282.         return DOCERR_READFAILURE;
  283.         }
  284.  
  285.     m_pIStorage=pIStorage;
  286.     m_pIUnknown=pIUnknown;
  287.  
  288.     Rename(pszFile);
  289.     SizeToGraphic(FALSE);
  290.     FDirtySet(FALSE);
  291.     return DOCERR_NONE;
  292.     }
  293.  
  294.  
  295.  
  296.  
  297.  
  298.  
  299.  
  300. /*
  301.  * CFreeloaderDoc::Save
  302.  *
  303.  * Purpose:
  304.  *  Writes the file to a known filename, requiring that the user
  305.  *  has previously used FileOpen or FileSaveAs in order to have
  306.  *  a filename.
  307.  *
  308.  * Parameters:
  309.  *  uType           UINT indicating the type of file the user
  310.  *                  requested to save in the File Save As dialog.
  311.  *  pszFile         LPTSTR under which to save.  If NULL, use the
  312.  *                  current name.
  313.  *
  314.  * Return Value:
  315.  *  UINT            An error value from DOCERR_...
  316.  */
  317.  
  318. UINT CFreeloaderDoc::Save(UINT uType, LPTSTR pszFile)
  319.     {
  320.     HRESULT             hr;
  321.     LPSTORAGE           pIStorage;
  322.     LPPERSISTSTORAGE    pIPersistStorage;
  323.     CLSID               clsID;
  324.  
  325.     //If we have no data object, there's nothing to save.
  326.     if (NULL==m_pIUnknown)
  327.         return DOCERR_WRITEFAILURE;
  328.  
  329.     //Get IPersistStorage for the data we hold.
  330.     hr=m_pIUnknown->QueryInterface(IID_IPersistStorage
  331.         , (PPVOID)&pIPersistStorage);
  332.  
  333.     if (FAILED(hr))
  334.         return DOCERR_WRITEFAILURE;
  335.  
  336.     //Save or Save As with the same file is just a commit.
  337.     if (NULL==pszFile || (NULL!=pszFile
  338.         && 0==lstrcmpi(pszFile, m_szFile)))
  339.         {
  340.         pIPersistStorage->Save(m_pIStorage, TRUE);
  341.         m_pIStorage->Commit(STGC_ONLYIFCURRENT);
  342.  
  343.         pIPersistStorage->SaveCompleted(NULL);
  344.         pIPersistStorage->Release();
  345.  
  346.         FDirtySet(FALSE);
  347.         return DOCERR_NONE;
  348.         }
  349.  
  350.     /*
  351.      * When we're given a name, open the storage, creating it new
  352.      * ifit does not exist or overwriting the old one.  Then CopyTo
  353.      * from the current to the new, Commit the new, then Release
  354.      * the old.
  355.      */
  356.  
  357.     hr=StgCreateDocfile(pszFile, STGM_TRANSACTED | STGM_READWRITE
  358.         | STGM_CREATE | STGM_SHARE_EXCLUSIVE, 0, &pIStorage);
  359.  
  360.     if (FAILED(hr))
  361.         return DOCERR_COULDNOTOPEN;
  362.  
  363.     //Insure the image is up to date, then tell it we're changing
  364.     pIPersistStorage->Save(m_pIStorage, TRUE);
  365.     pIPersistStorage->HandsOffStorage();
  366.  
  367.     //Save the class, bitmap or metafile
  368.     if (FAILED(pIPersistStorage->GetClassID(&clsID)))
  369.         clsID=m_clsID;
  370.  
  371.     hr=WriteClassStg(m_pIStorage, clsID);
  372.  
  373.     hr=m_pIStorage->CopyTo(NULL, NULL, NULL, pIStorage);
  374.  
  375.     if (FAILED(hr))
  376.         {
  377.         pIPersistStorage->SaveCompleted(m_pIStorage);
  378.         pIPersistStorage->Release();
  379.         pIStorage->Release();
  380.         return DOCERR_WRITEFAILURE;
  381.         }
  382.  
  383.     pIStorage->Commit(STGC_ONLYIFCURRENT);
  384.  
  385.     /*
  386.      * Revert changes on the original storage.  If this was a temp
  387.      * file, it's deleted since we used STGM_DELETEONRELEASE.
  388.      */
  389.     m_pIStorage->Release();
  390.  
  391.     //Make this new storage current
  392.     m_pIStorage=pIStorage;
  393.     pIPersistStorage->SaveCompleted(m_pIStorage);
  394.     pIPersistStorage->Release();
  395.  
  396.     Rename(pszFile);
  397.     FDirtySet(FALSE);
  398.     return DOCERR_NONE;
  399.     }
  400.  
  401.  
  402.  
  403.  
  404.  
  405.  
  406. /*
  407.  * CFreeloaderDoc::Clip
  408.  *
  409.  * Purpose:
  410.  *  Places a private format, a metafile, and a bitmap of the display
  411.  *  on the clipboard, optionally implementing Cut by deleting the
  412.  *  data in the current window after rendering.
  413.  *
  414.  * Parameters:
  415.  *  hWndFrame       HWND of the main window.
  416.  *  fCut            BOOL indicating cut (TRUE) or copy (FALSE).
  417.  *
  418.  * Return Value:
  419.  *  BOOL            TRUE if successful, FALSE otherwise.
  420.  */
  421.  
  422. BOOL CFreeloaderDoc::Clip(HWND hWndFrame, BOOL fCut)
  423.     {
  424.     BOOL            fRet=TRUE;
  425.     static UINT     rgcf[3]={CF_METAFILEPICT, CF_DIB, CF_BITMAP};
  426.     const UINT      cFormats=3;
  427.     UINT            i;
  428.     HGLOBAL         hMem;
  429.  
  430.     if (NULL==m_pIUnknown)
  431.         return FALSE;
  432.  
  433.     if (!OpenClipboard(hWndFrame))
  434.         return FALSE;
  435.  
  436.     //Clean out whatever junk is in the clipboard.
  437.     EmptyClipboard();
  438.  
  439.     for (i=0; i < cFormats; i++)
  440.         {
  441.         hMem=RenderFormat(rgcf[i]);
  442.  
  443.         if (NULL!=hMem)
  444.             {
  445.             SetClipboardData(rgcf[i], hMem);
  446.             fRet=TRUE;
  447.             break;
  448.             }
  449.         }
  450.  
  451.     //Free clipboard ownership.
  452.     CloseClipboard();
  453.  
  454.     //If we're cutting, clean out the cache and the object we hold.
  455.     if (fRet && fCut)
  456.         {
  457.         ReleaseObject();
  458.         InvalidateRect(m_hWnd, NULL, TRUE);
  459.         UpdateWindow(m_hWnd);
  460.         FDirtySet(TRUE);
  461.         }
  462.  
  463.     return fRet;
  464.     }
  465.  
  466.  
  467.  
  468.  
  469.  
  470. /*
  471.  * CFreeloaderDoc::RenderFormat
  472.  *
  473.  * Purpose:
  474.  *  Renders a specific clipboard format into global memory.
  475.  *
  476.  * Parameters:
  477.  *  cf              UINT format to render.
  478.  *
  479.  * Return Value:
  480.  *  HGLOBAL         Global memory handle containing the data.
  481.  */
  482.  
  483. HGLOBAL CFreeloaderDoc::RenderFormat(UINT cf)
  484.     {
  485.     LPDATAOBJECT        pIDataObject;
  486.     FORMATETC           fe;
  487.     STGMEDIUM           stm;
  488.  
  489.     if (NULL==m_pIUnknown)
  490.         return NULL;
  491.  
  492.     //We only have to ask the data object (cache) for the data.
  493.     switch (cf)
  494.         {
  495.         case CF_METAFILEPICT:
  496.             stm.tymed=TYMED_MFPICT;
  497.             break;
  498.  
  499.        case CF_DIB:
  500.             stm.tymed=TYMED_HGLOBAL;
  501.             break;
  502.  
  503.        case CF_BITMAP:
  504.             stm.tymed=TYMED_GDI;
  505.             break;
  506.  
  507.         default:
  508.             return NULL;
  509.         }
  510.  
  511.     stm.hGlobal=NULL;
  512.     SETDefFormatEtc(fe, cf, stm.tymed);
  513.  
  514.     m_pIUnknown->QueryInterface(IID_IDataObject
  515.         , (PPVOID)&pIDataObject);
  516.     pIDataObject->GetData(&fe, &stm);
  517.     pIDataObject->Release();
  518.  
  519.     return stm.hGlobal;
  520.     }
  521.  
  522.  
  523.  
  524.  
  525.  
  526.  
  527. /*
  528.  * CFreeloaderDoc::FQueryPaste
  529.  *
  530.  * Purpose:
  531.  *  Determines if we can paste data from the clipboard.
  532.  *
  533.  * Parameters:
  534.  *  None
  535.  *
  536.  * Return Value:
  537.  *  BOOL            TRUE if data is available, FALSE otherwise.
  538.  */
  539.  
  540. BOOL CFreeloaderDoc::FQueryPaste(void)
  541.     {
  542.     return IsClipboardFormatAvailable(CF_BITMAP)
  543.         || IsClipboardFormatAvailable(CF_DIB)
  544.         || IsClipboardFormatAvailable(CF_METAFILEPICT);
  545.     }
  546.  
  547.  
  548.  
  549.  
  550.  
  551. /*
  552.  * CFreeloaderDoc::Paste
  553.  *
  554.  * Purpose:
  555.  *  Retrieves the private data format from the clipboard and sets it
  556.  *  to the current figure in the editor window.
  557.  *
  558.  *  Note that if this function is called, then the clipboard format
  559.  *  is available because the Paste menu item is only enabled if the
  560.  *  format is present.
  561.  *
  562.  * Parameters:
  563.  *  hWndFrame       HWND of the main window.
  564.  *
  565.  * Return Value:
  566.  *  BOOL            TRUE if successful, FALSE otherwise.
  567.  */
  568.  
  569. BOOL CFreeloaderDoc::Paste(HWND hWndFrame)
  570.     {
  571.     UINT                cf=0;
  572.     HGLOBAL             hMem;
  573.     HRESULT             hr;
  574.     DWORD               dwConn;
  575.     LPUNKNOWN           pIUnknown;
  576.     LPOLECACHE          pIOleCache;
  577.     LPPERSISTSTORAGE    pIPersistStorage;
  578.     FORMATETC           fe;
  579.     STGMEDIUM           stm;
  580.     CLSID               clsID;
  581.  
  582.     if (!OpenClipboard(hWndFrame))
  583.         return FALSE;
  584.  
  585.     /*
  586.      * Try to get data in order of metafile, dib, bitmap.  We set
  587.      * stm.tymed up front so if we actually get something a call
  588.      * to ReleaseStgMedium will clean it up for us.
  589.      */
  590.  
  591.     stm.pUnkForRelease=NULL;
  592.     stm.tymed=TYMED_MFPICT;
  593.     hMem=GetClipboardData(CF_METAFILEPICT);
  594.  
  595.     if (NULL!=hMem)
  596.         cf=CF_METAFILEPICT;
  597.  
  598.     if (0==cf)
  599.         {
  600.         stm.tymed=TYMED_HGLOBAL;
  601.         hMem=GetClipboardData(CF_DIB);
  602.  
  603.         if (NULL!=hMem)
  604.             cf=CF_DIB;
  605.         }
  606.  
  607.     if (0==cf)
  608.         {
  609.         stm.tymed=TYMED_GDI;
  610.         hMem=GetClipboardData(CF_BITMAP);
  611.  
  612.         if (NULL!=hMem)
  613.             cf=CF_BITMAP;
  614.         }
  615.  
  616.     stm.hGlobal=OleDuplicateData(hMem, cf, NULL);
  617.     CloseClipboard();
  618.  
  619.     //Didn't get anything?  Then we're finished.
  620.     if (0==cf)
  621.         return FALSE;
  622.  
  623.     //This now describes the data we have.
  624.     SETDefFormatEtc(fe, cf, stm.tymed);
  625.  
  626.  
  627.     /*
  628.      * Create a data cache to deal with this data using
  629.      * either CoCreateInstance for an OLE-supported CLSID or
  630.      * CreateDataCache.  The first will go through all the
  631.      * exercises of looking up the CLSID in the regDB, finding
  632.      * the OLE DLL (registered for these classes), getting a class
  633.      * factory, and using IClassFactory::CreateInstance.  The
  634.      * second goes into OLE directly, creating the same object
  635.      * with less overhead.  Thus we use CreateDataCache.
  636.      */
  637.  
  638.     if (CF_METAFILEPICT==cf)
  639.         clsID=CLSID_Picture_Metafile;
  640.     else
  641.         clsID=CLSID_Picture_Dib;
  642.  
  643.     hr=CreateDataCache(NULL, clsID, IID_IUnknown
  644.         , (PPVOID)&pIUnknown);
  645.  
  646.     if (FAILED(hr))
  647.         {
  648.         ReleaseStgMedium(&stm);
  649.         return FALSE;
  650.         }
  651.  
  652.     /*
  653.      * Our contract says we provide storage through
  654.      * IPersistStorage::InitNew.  We know that the object we're
  655.      * dealing with supports IPersistStorage and IOleCache, so
  656.      * we don't bother to check return values.  I guess we're
  657.      * living dangerously...
  658.      */
  659.     pIUnknown->QueryInterface(IID_IPersistStorage
  660.         , (PPVOID)&pIPersistStorage);
  661.     pIPersistStorage->InitNew(m_pIStorage);
  662.     pIPersistStorage->Release();
  663.  
  664.     /*
  665.      * Now that we have the cache object, shove the data into it.
  666.      * No advise flags are necessary for static data.
  667.      */
  668.     pIUnknown->QueryInterface(IID_IOleCache, (PPVOID)&pIOleCache);
  669.     pIOleCache->Cache(&fe, ADVF_PRIMEFIRST, &dwConn);
  670.  
  671.     hr=pIOleCache->SetData(&fe, &stm, TRUE);
  672.     pIOleCache->Release();
  673.  
  674.     if (FAILED(hr))
  675.         {
  676.         ReleaseStgMedium(&stm);
  677.         pIUnknown->Release();
  678.         return FALSE;
  679.         }
  680.  
  681.     //Now that that's all done, replace our current with the new.
  682.     ReleaseObject();
  683.     m_pIUnknown=pIUnknown;
  684.     m_dwConn=dwConn;
  685.     m_clsID=clsID;
  686.  
  687.     FDirtySet(TRUE);
  688.  
  689.     InvalidateRect(m_hWnd, NULL, TRUE);
  690.     UpdateWindow(m_hWnd);
  691.     return TRUE;
  692.     }
  693.  
  694.  
  695.  
  696. /*
  697.  * CFreeloaderDoc::SizeToGraphic
  698.  *
  699.  * Purpose:
  700.  *  Determines if we can size the window to the contained
  701.  *  graphic and alternately performs the operation.
  702.  *
  703.  * Parameters:
  704.  *  fQueryOnly      BOOL indicating if we just want to know
  705.  *                  if sizing is possible (TRUE) or that we
  706.  *                  want to perform the sizing (FALSE).
  707.  *
  708.  * Return Value:
  709.  *  BOOL            TRUE if data is available, FALSE otherwise.
  710.  */
  711.  
  712. BOOL CFreeloaderDoc::SizeToGraphic(BOOL fQueryOnly)
  713.     {
  714.     HRESULT             hr;
  715.     LPVIEWOBJECT2       pIViewObject2;
  716.     SIZEL               szl;
  717.     RECT                rc;
  718.     UINT                cx, cy;
  719.     HDC                 hDC;
  720.     DWORD               dwStyle;
  721.  
  722.     if (NULL==m_pIUnknown)
  723.         return FALSE;
  724.  
  725.     m_pIUnknown->QueryInterface(IID_IViewObject2
  726.         , (PPVOID)&pIViewObject2);
  727.  
  728.     if (FAILED(hr))
  729.         return FALSE;
  730.  
  731.     if (fQueryOnly)
  732.         {
  733.         pIViewObject2->Release();
  734.         return TRUE;
  735.         }
  736.  
  737.     hr=pIViewObject2->GetExtent(DVASPECT_CONTENT, -1, NULL, &szl);
  738.     pIViewObject2->Release();
  739.  
  740.     if (FAILED(hr))
  741.         return FALSE;
  742.  
  743.     //Calculate new doc rectangle based on these extents.
  744.  
  745.     hDC=GetDC(NULL);
  746.     cx=MulDiv((int)szl.cx, GetDeviceCaps(hDC, LOGPIXELSX)
  747.         , HIMETRIC_PER_INCH);
  748.     cy=MulDiv((int)szl.cy, GetDeviceCaps(hDC, LOGPIXELSY)
  749.         , HIMETRIC_PER_INCH);
  750.     ReleaseDC(NULL, hDC);
  751.  
  752.     SetRect(&rc, 0, 0, cx, cy);
  753.     dwStyle=GetWindowLong(m_hWnd, GWL_STYLE);
  754.     AdjustWindowRect(&rc, dwStyle, FALSE);
  755.  
  756.     /*
  757.      * If the window is currently maximized, then we have to
  758.      * restore it first before sizing.
  759.      */
  760.     if (IsZoomed(m_hWnd))
  761.         ShowWindow(m_hWnd, SW_RESTORE);
  762.  
  763.     SetWindowPos(m_hWnd, NULL, 0, 0
  764.         , rc.right-rc.left , rc.bottom-rc.top
  765.         , SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
  766.  
  767.     return TRUE;
  768.     }
  769.