home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / winfe / gendoc.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  40.7 KB  |  1,225 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. // gendoc.cpp : implementation file
  20. //
  21.  
  22. #include "stdafx.h"
  23.  
  24. #include "cntritem.h"
  25. #include "srvritem.h"
  26. #include "feembed.h" 
  27. #include "np.h"
  28. #include "nppg.h"
  29. #include "plginvw.h"
  30. #include "edt.h"
  31. #include "il_icons.h"
  32. #include "edframe.h"
  33. #include "ipframe.h"
  34.  
  35. #ifdef _DEBUG
  36. #undef THIS_FILE
  37. static char BASED_CODE THIS_FILE[] = __FILE__;
  38. #endif
  39.  
  40. #ifdef XP_WIN16
  41. #define T2COLE(str) str
  42. #define LPCOLESTR LPCTSTR
  43. #endif
  44. /////////////////////////////////////////////////////////////////////////////
  45. // CGenericDoc
  46.  
  47. #ifndef _AFXDLL
  48. #undef new
  49. #endif
  50. IMPLEMENT_DYNCREATE(CGenericDoc, COleServerDoc)
  51. #ifndef _AFXDLL
  52. #define new DEBUG_NEW
  53. #endif
  54.  
  55. //  Default extent values.
  56. #define HIY 7000
  57. #define HIX 7000
  58.  
  59.  
  60. LPUNKNOWN AFXAPI _myQueryInterface(LPUNKNOWN lpUnknown, REFIID iid)
  61. {
  62.     ASSERT(lpUnknown != NULL);
  63.  
  64.     LPUNKNOWN lpW = NULL;
  65.     if (lpUnknown->QueryInterface(iid, (void**)&lpW) != S_OK)
  66.         return NULL;
  67.  
  68.     return lpW;
  69. }
  70. #define QUERYINTERFACE(lpUnknown, iface) \
  71.     (iface*)_myQueryInterface(lpUnknown, IID_##iface)
  72.  
  73. CGenericDoc::CGenericDoc()
  74. {
  75.     // In case someone forgets to tell us.
  76.     m_pContext = NULL;
  77.  
  78.     //  Haven't set a document file yet.
  79.     m_bOpenDocumentFileSet = FALSE;
  80.  
  81.     //    We can close the document.
  82.     m_bCanClose = TRUE;
  83.  
  84.     //  Default extents.
  85.     m_csViewExtent = CSize(HIX, HIY);
  86.     m_csDocumentExtent = CSize(HIX, HIY);
  87.  
  88. }
  89.  
  90. CGenericDoc::~CGenericDoc()
  91. {
  92.  
  93.     //    When the document goes down, it's a good idea to let the context
  94.     //        know it's no longer there.
  95.     if(GetContext() != NULL)    {
  96.         GetContext()->ClearDoc();
  97.     }
  98.  
  99.     //    Get rid of the context if around.
  100.     if(GetContext() && GetContext()->IsDestroyed() == FALSE)    {
  101.         GetContext()->DestroyContext();
  102.     }
  103. }
  104.  
  105.  
  106. BEGIN_MESSAGE_MAP(CGenericDoc, COleServerDoc)
  107.     //{{AFX_MSG_MAP(CGenericDoc)
  108.     ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
  109.     ON_COMMAND(ID_OLE_UPDATE, OnOleUpdate)
  110.     ON_UPDATE_COMMAND_UI(ID_OLE_UPDATE, OnUpdateOleUpdate)
  111.     //}}AFX_MSG_MAP
  112. END_MESSAGE_MAP()
  113.  
  114.  
  115.  
  116. /////////////////////////////////////////////////////////////////////////////
  117. // CGenericDoc diagnostics
  118.  
  119. #ifdef _DEBUG
  120. void CGenericDoc::AssertValid() const
  121. {
  122.     COleServerDoc::AssertValid();
  123. }
  124.  
  125. void CGenericDoc::Dump(CDumpContext& dc) const
  126. {
  127.     COleServerDoc::Dump(dc);
  128. }
  129. #endif //_DEBUG
  130.  
  131. /////////////////////////////////////////////////////////////////////////////
  132. // CGenericDoc serialization
  133.  
  134. void CGenericDoc::Serialize(CArchive& ar)
  135. {
  136.     TRACE("CGenericDoc::Serialize called\n");
  137.  
  138.     BOOL bCanSerialize = TRUE;
  139.     if(ar.IsLoading())  {
  140. #ifdef XP_WIN32
  141.         //  Determine name of actual document.
  142.         CFile *pFile = ar.GetFile();
  143.         CString csFile;
  144.         if(pFile)   {
  145.             csFile = pFile->GetFilePath();
  146.         }
  147.  
  148.         //  Determine if this is the same file that was passed into the
  149.         //      OnOpenDocument function.
  150.         //  If so, then we can not read our OLE format.
  151.         bCanSerialize = (csFile.CompareNoCase(m_csOpenDocumentFile) != 0);
  152.  
  153.         //  However, if they're both empty, then we need to allow this.
  154.         if(csFile.IsEmpty() && m_csOpenDocumentFile.IsEmpty())  {
  155.             bCanSerialize = TRUE;
  156.         }
  157.         TRACE("%d = !(%s==%s)\n", bCanSerialize, (const char *)csFile, (const char *)m_csOpenDocumentFile);
  158. #else
  159.         //  16 bit can not turn a file handle into a file name.
  160.         //  If our document name is set, then say we can't serialize.
  161.         bCanSerialize = !(m_bOpenDocumentFileSet && !m_csOpenDocumentFile.IsEmpty());
  162.         TRACE("%d = !(%d && !%d)\n", m_bOpenDocumentFileSet, !m_csOpenDocumentFile.IsEmpty());
  163. #endif
  164.     }
  165.  
  166.     //  We can only serialize if we're not looking at a local file which we've opened up.
  167.     if(bCanSerialize)   {
  168.         //    Fleshed out for OLE server work.
  169.         //    The below is the common implementation that should work across the
  170.         //        board for all versions of the navigator.
  171.         //    All it does is either read in or write out a URL.
  172.         if(GetContext() && GetContext()->IsDestroyed() == FALSE)    {
  173.             if (ar.IsStoring())
  174.             {
  175.                 TRACE("Storing\n");
  176.                 //    Just shove our current URL into the file.
  177.                 //    Get the current history entry.
  178.                 History_entry *pHist = SHIST_GetCurrent(&(GetContext()->GetContext()->hist));
  179.                 if(pHist != NULL && pHist->address != NULL)    {
  180.                     CString csAddress = pHist->address;
  181.                     ar << csAddress;
  182.                     TRACE("URL is %s\n", (const char *)csAddress);
  183.                 }
  184.                 else    {
  185.                     TRACE("no history!\n");
  186.                     CString csEmpty;
  187.                     ar << csEmpty;
  188.                 }
  189.             }
  190.             else
  191.             {
  192.                 TRACE("Reading\n");
  193.  
  194.                 //    Pretty much just read this in as internet shortcut
  195.                 //        format and load it.
  196.                 CString csLoadMe;
  197.                 ar >> csLoadMe;
  198.  
  199.                 //    Do it.
  200.                 TRACE("URL is %s\n", (const char *)csLoadMe);
  201.                 GetContext()->NormalGetUrl(csLoadMe);
  202.             }
  203.         }
  204.         else    {
  205.             TRACE("no context!\n");
  206.             if (ar.IsStoring())
  207.             {
  208.                 TRACE("Storing\n");
  209.                 //    Hope that ephemeral data were cached, otherwise, no real
  210.                 //        harm done.
  211.                 ar << m_csEphemeralHistoryAddress;
  212.             }
  213.             else
  214.             {
  215.                 TRACE("Reading\n");
  216.                 CString csDontcare;
  217.                 ar >> csDontcare;
  218.             }
  219.         }
  220.  
  221.         //    Next in line should be a string identifying the client which wrote
  222.         //        out the information.
  223.         //  ALL NUMBERS TO BE CONVERTED TO NETWORK BYTE ORDER, SO WORKS ACROSS PLATFORMS.
  224.         CString csNetscapeVersion;
  225.         if(ar.IsStoring())    {
  226.             //    Write out our document version number.
  227.             //    This is initially 2.0
  228.             ar << theApp.ResolveAppVersion();
  229.             TRACE("App version is %s\n", (const char *)theApp.ResolveAppVersion());
  230.  
  231.             //    Write out any other information for a particular version here,
  232.             //        prepended by the amount of total bytes to be written.
  233.             //    Hold all integer values (all XP values) to a size that will
  234.             //        translate between win16 and win32.
  235.             TRACE("Writing version specific information.\n");
  236.  
  237.             //  Figure up the size of extra info we'll be writing out.
  238.             u_long arExtraBytes = 0;
  239.  
  240.             //  3.0 beta 6 has some extra information
  241.             arExtraBytes += sizeof(u_long); //  extent.cx
  242.             arExtraBytes += sizeof(u_long); //  extent.cy
  243.             arExtraBytes += sizeof(u_long); //  extent.cx
  244.             arExtraBytes += sizeof(u_long); //  extent.cy
  245.  
  246.             //    For version 2.0, there was no extra information.
  247.             ar << htonl(arExtraBytes);
  248.  
  249.             //  Now, begin writing out extra information.
  250.  
  251.             //  3.0 beta 6
  252.             TRACE("3.0 beta 6 and later information being written\n");
  253.             ar << htonl((u_long)m_csViewExtent.cx);
  254.             ar << htonl((u_long)m_csViewExtent.cy);
  255.             TRACE("Write cx=%lu cy=%lu\n", (uint32)m_csViewExtent.cx, (uint32)m_csViewExtent.cy);
  256.             ar << htonl((u_long)m_csDocumentExtent.cx);
  257.             ar << htonl((u_long)m_csDocumentExtent.cy);
  258.             TRACE("Write cx=%lu cy=%lu\n", (uint32)m_csDocumentExtent.cx, (uint32)m_csDocumentExtent.cy);
  259.         }
  260.         else    {
  261.             //    Read in our document version number.
  262.             ar >> csNetscapeVersion;
  263.             TRACE("App version is %s\n", (const char *)csNetscapeVersion);
  264.  
  265.             //    Next, read in the amount of bytes that are stored.
  266.             u_long lBytes;
  267.             ar >> lBytes;
  268.             lBytes = ntohl(lBytes);
  269.  
  270.             if(lBytes != 0)    {
  271.                 //    Now, depending on which version we're reading from,
  272.                 //        figure out the information in the file if we understand
  273.                 //        that particular version's file format.
  274.                 //    2.0 won't understand anything, so just read in the number of
  275.                 //        extra bytes and continue.
  276.                 //    Let the caller of serialize handle thrown exceptions.
  277.                 TRACE("Reading version specific information of %lu bytes.\n", lBytes);
  278.                 char *pBuf = new char[lBytes];
  279.                 if(pBuf == NULL)    {
  280.                     AfxThrowMemoryException();
  281.                 }
  282.                 ar.Read((void *)pBuf, CASTUINT(lBytes));
  283.  
  284.                 //  Use and increment this pointer appropriately to read in
  285.                 //      extra information.
  286.                 char *va_start = pBuf;
  287.  
  288.                 //  If and only if there are extra bytes, decide what was written out.
  289.                 //  In 3.0 beta 6, we wrote out two uint32's first.
  290.                 u_long arVersion30b6 = 0;
  291.                 arVersion30b6 += sizeof(u_long);
  292.                 arVersion30b6 += sizeof(u_long);
  293.                 arVersion30b6 += sizeof(u_long);
  294.                 arVersion30b6 += sizeof(u_long);
  295.  
  296.                 //  Read in this information, otherwise, use a default.
  297.                 if(lBytes >= arVersion30b6) {
  298.                     TRACE("3.0 beta 6 information being retrieved\n");
  299.                     m_csViewExtent.cx = CASTINT(ntohl(*((u_long *)va_start)));
  300.                     va_start += sizeof(u_long);
  301.                     m_csViewExtent.cy = CASTINT(ntohl(*((u_long *)va_start)));
  302.                     va_start += sizeof(u_long);
  303.                     TRACE("Read cx=%lu cy=%lu\n", (uint32)m_csViewExtent.cx, (uint32)m_csViewExtent.cy);
  304.                     m_csDocumentExtent.cx = CASTINT(ntohl(*((u_long *)va_start)));
  305.                     va_start += sizeof(u_long);
  306.                     m_csDocumentExtent.cy = CASTINT(ntohl(*((u_long *)va_start)));
  307.                     va_start += sizeof(u_long);
  308.                     TRACE("Read cx=%lu cy=%lu\n", (uint32)m_csDocumentExtent.cx, (uint32)m_csDocumentExtent.cy);
  309.                 }
  310.                 else    {
  311.                     TRACE("Using default 3.0 beta 6 information\n");
  312.                     m_csViewExtent = CSize(HIX, HIY);
  313.                     m_csDocumentExtent = CSize(HIX, HIY);
  314.                 }
  315.  
  316.                 delete[] pBuf;
  317.             }
  318.         }
  319.  
  320.         //  Calling the base class CGenericDoc enables serialization
  321.         //      of the conainer document's COleclientItem objects.
  322.         TRACE("Calling base serialize\n");
  323.         COleServerDoc::Serialize(ar);
  324.     }
  325. }
  326.  
  327. UINT GetChildID()
  328. {
  329.     static UINT s_uChildID;
  330.     return s_uChildID++;
  331. }
  332.  
  333. //  Get the size of an embedded item.
  334. void CGenericDoc::GetEmbedSize(MWContext *pContext, LO_EmbedStruct *pLayoutData, NET_ReloadMethod Reload) {
  335.     //  First, see if we've already got what Layout is asking for.
  336.     POSITION rIndex = GetStartPosition();
  337.     char *pLayoutAddress = (char *)pLayoutData->embed_src;
  338.     CNetscapeCntrItem *pItem = NULL;
  339.     CString csLoad = pLayoutAddress;
  340.  
  341.     while(rIndex != NULL)   {
  342.         pItem = (CNetscapeCntrItem *)GetNextClientItem(rIndex);
  343.         if(pItem == NULL)   {
  344.             break;
  345.         }
  346.  
  347.         //  Compare the address to the one layout has.
  348.         if(pItem->m_csAddress == csLoad)    {
  349.             //  One in the same. If this is an OLE container item, then just
  350.             // reuse the pItem. This allows us to use the existing temp file
  351.             // and to avoid downloading the file multiple times
  352.             //
  353.             // Plugins work differently. A new plugin instance will be created
  354.             // for each embed, and each plugin instance will have a stream associated
  355.             // with it. Because the plugin data is cached, we won't be reloading
  356.             // multiple times
  357.             //
  358.             // Only reuse this pItem if it corresponds to an OLE object. We can
  359.             // tell by looking at the first NPEmbeddedApp. Unfortunately this isn't
  360.             // very reliable, because the previous embed may still be untyped
  361.             POSITION rIndex = pItem->m_cplElements.GetHeadPosition();
  362.             ASSERT(rIndex != NULL);
  363.  
  364.             if (rIndex) {
  365.                 LO_EmbedStruct* pLayoutData = (LO_EmbedStruct *)pItem->m_cplElements.GetNext(rIndex);
  366.  
  367.                 ASSERT(pLayoutData && pLayoutData->type == LO_EMBED);
  368.                 if (pLayoutData) {
  369.                     NPEmbeddedApp* pEmbeddedApp = (NPEmbeddedApp*)pLayoutData->FE_Data;
  370.  
  371.                     ASSERT(pEmbeddedApp);
  372.                     if (pEmbeddedApp && pEmbeddedApp->type == NP_OLE)
  373.                         break;  // it's okay to reuse this pItem
  374.                 }
  375.             }
  376.         }
  377.  
  378.         //  Not a match, reset the value.
  379.         pItem = NULL;
  380.     }
  381.  
  382.     //  See if we have a match. Note that this should never happen with plugins
  383.     // (OLE only)
  384.     if(pItem != NULL)   {
  385.         //  We have a match.
  386.         //  Add this layout item to the number of layout items accessing us.
  387.         pItem->m_cplElements.AddTail(pLayoutData);
  388.  
  389.         // create and init new structures for managing an embedded plugin
  390.         NPEmbeddedApp *pEmbeddedApp = NULL;
  391.        
  392.         NPWindow *pAppWin = XP_NEW_ZAP(NPWindow);
  393.         if(pAppWin == NULL)
  394.         {
  395.             return;
  396.         }
  397.  
  398.         if(!(pEmbeddedApp = XP_NEW_ZAP(NPEmbeddedApp)))
  399.         {
  400.             XP_FREE(pAppWin);
  401.             return;
  402.         }
  403.  
  404.         pEmbeddedApp->next = pContext->pluginList;
  405.         pContext->pluginList = pEmbeddedApp;
  406.         pEmbeddedApp->type  = NP_Untyped; // figure it out in EmbedStream
  407.         pEmbeddedApp->fe_data = (void *)pItem;
  408.         pEmbeddedApp->wdata = pAppWin;
  409.  
  410.         //  Go ahead and assign it into the layout data for use in other functions.
  411.         pLayoutData->FE_Data = (void *)pEmbeddedApp;
  412.         pItem->m_iLock++;
  413.  
  414.         //  Is layout blocking for this information?
  415.         if(pLayoutData->width == 0 || pLayoutData->height == 0) {
  416.  
  417.             if(pItem->m_bLoading == TRUE)   {
  418.                 //  Add this layout element to those that will be unblocked once loaded.
  419.                 pItem->m_cplUnblock.AddTail(pLayoutData);
  420.                 return;
  421.             }
  422.  
  423.             //  We have to switch here to handle the old way of doing things, and the new.
  424.             //  Base class which handles embeds is CDCCX.
  425.             CDCCX *pCX = VOID2CX(pContext->fe.cx, CDCCX);
  426.  
  427.             //  Go ahead and set the size of the item.
  428.             if(pItem->m_bDelayed == TRUE)   {
  429.                 LTRB Rect;
  430.                 pCX->DisplayIcon(Rect.left, Rect.top, IL_IMAGE_DELAYED);
  431.             }
  432.             else if(pItem->m_bBroken == TRUE)   {
  433.                 LTRB Rect;
  434.                 pCX->DisplayIcon(Rect.left, Rect.top, IL_IMAGE_BAD_DATA);
  435.             }
  436.             else    {
  437.                 CSize csExtents;
  438.                 pItem->GetExtent(&csExtents);
  439.                 csExtents.cx = pCX->Metric2TwipsX(csExtents.cx);
  440.                 csExtents.cy = pCX->Metric2TwipsY(csExtents.cy);
  441.  
  442.                 if ( pLayoutData->width )
  443.                     csExtents.cx = pLayoutData->width;
  444.                 if ( pLayoutData->height )
  445.                     csExtents.cy = pLayoutData->height; 
  446.                 pLayoutData->width = csExtents.cx;
  447.                 pLayoutData->height = csExtents.cy;
  448.             }
  449.  
  450.             return;
  451.         }
  452.         else    {
  453.             if(pItem->m_bLoading == TRUE)   {
  454.                 //  We'll need to update this once the load is completed.
  455.                 pItem->m_cplDisplay.AddTail(pLayoutData);
  456.                 return;
  457.             }
  458.         }
  459.     }
  460.     else    {
  461.         BOOL            bPrinting = GetContext()->IsPrintContext();
  462.         NPEmbeddedApp*     pEmbeddedApp;
  463.  
  464.         CString theURL;
  465.         const char * tempURL;
  466.         PA_LOCK(tempURL, const char*, pLayoutData->embed_src);
  467.         theURL = tempURL;
  468.         BOOL fullPageOLE = FALSE;
  469.         int index;
  470.         if ((index = theURL.Find( "internal-ole-viewer:")) > 0) {
  471.             PA_UNLOCK(pLayoutData->embed_src); 
  472.             index += strlen("internal-ole-viewer:");
  473.             PA_FREE(pLayoutData->embed_src);
  474.             int newEmbed_len = (theURL.GetLength() - index) + 1;
  475.             pLayoutData->embed_src = (PA_Block)PA_ALLOC(newEmbed_len);
  476.             char* str;
  477.             PA_LOCK(str, char *, pLayoutData->embed_src);
  478.             tempURL = theURL;
  479.             strncpy(str, tempURL+index, newEmbed_len - 1);
  480.             str[newEmbed_len - 1] = 0;  // null terminated.
  481.             pLayoutAddress = (char *)pLayoutData->embed_src;
  482.             PA_UNLOCK(pLayoutData->embed_src);
  483.             fullPageOLE = TRUE;
  484.  
  485.         }
  486.         else
  487.             PA_UNLOCK(pLayoutData->embed_src); 
  488.  
  489.  
  490.         // Create and init new structures for managing an embedded plugin
  491.         pEmbeddedApp = NPL_EmbedCreate(pContext, pLayoutData);
  492.         if(pEmbeddedApp == NULL)
  493.             return;
  494.  
  495.         //  We're going to have to load.
  496.         pItem = new CNetscapeCntrItem(this);
  497.         if (fullPageOLE)
  498.             pItem->m_isFullPage = TRUE;
  499.         pItem->m_iLock++;
  500.  
  501.         //  Add this layout item to the number of layout items accessing us.
  502.         pItem->m_cplElements.AddTail(pLayoutData);
  503.  
  504.         // Mark what actions to take with layout, depending on blocking or non blocking.
  505.         // Note that hidden plugins never block layout and they don't require displaying
  506.         //
  507.         // If we're printing we will use a cached app from the session data so we don't
  508.         // need to do either of these
  509.         if ((pLayoutData->ele_attrmask & LO_ELE_HIDDEN) == 0 && !bPrinting) {
  510.             if(pLayoutData->width == 0 || pLayoutData->height == 0) {
  511.                 //  Layout is blocking, be sure to unblock once loaded.
  512.                 pItem->m_cplUnblock.AddTail(pLayoutData);
  513.             }
  514.             else    {
  515.                 //  Layout isn't blocking, but we'll need to manually display this once it is loaded.
  516.                 pItem->m_cplDisplay.AddTail(pLayoutData);
  517.             }
  518.         }
  519.  
  520.         // If we are printing a plugin then NPL_EmbedCreate() just returns the
  521.         // cached app from the session data
  522.         if (bPrinting) {
  523.             // Because we are using a cached app from the session data, save
  524.             // the existing pItem so we can restore it when we free the embed item
  525.             pItem->m_pOriginalItem = (CNetscapeCntrItem*)pEmbeddedApp->fe_data;
  526.  
  527.             ASSERT(pItem->m_pOriginalItem);
  528.  
  529.             if (pEmbeddedApp->type == NP_OLE && pItem->m_pOriginalItem && 
  530.                 pItem->m_pOriginalItem->m_bDelayed == FALSE &&
  531.                 pItem->m_pOriginalItem->m_bBroken == FALSE &&
  532.                 pItem->m_pOriginalItem->m_bLoading == FALSE) {
  533.                 // Have the OLE object load itself from the same temp file
  534.                 if (pItem->m_pOriginalItem) {
  535.                     pItem->m_csFileName = pItem->m_pOriginalItem->m_csFileName;                        
  536.                     pItem->CreateCloneFrom( pItem->m_pOriginalItem);
  537.                 }
  538.                 CSize  csExtents;
  539.                 CDCCX* pCX = VOID2CX(pContext->fe.cx, CDCCX);
  540.  
  541.                 pItem->m_pOriginalItem->GetExtent(&csExtents);
  542.  
  543.                 csExtents.cx = pCX->Metric2TwipsX(csExtents.cx);
  544.                 csExtents.cy = pCX->Metric2TwipsY(csExtents.cy);
  545.                 if ( pLayoutData->width )
  546.                     csExtents.cx = pLayoutData->width; 
  547.                 if ( pLayoutData->height )
  548.                     csExtents.cy = pLayoutData->height; 
  549.                 pLayoutData->width = csExtents.cx;
  550.                 pLayoutData->height = csExtents.cy;
  551.                 // In the printing case, an OLE container is not windowed
  552.                 LO_SetEmbedType(pLayoutData, PR_FALSE);
  553.             }
  554.             else { 
  555.                 // so layout will not block on us. Since this embed element is missing.
  556.                 pLayoutData->width = 1;
  557.                 pLayoutData->height = 1;
  558.  
  559.             }
  560.  
  561.         } else {
  562.             if(pEmbeddedApp->wdata == NULL) {
  563.                 // Just created
  564.                 pEmbeddedApp->wdata = XP_NEW_ZAP(NPWindow);
  565.                 if(pEmbeddedApp->wdata == NULL)
  566.                     return;
  567.  
  568.             } else {
  569.                 // Check if there's a child window and if we're in a frame cell. Note:
  570.                 // there may not be a window, especially if the plugin is in a nested table
  571.                 if (pContext->is_grid_cell && pEmbeddedApp->wdata->window &&
  572.                     (pEmbeddedApp->wdata->type == NPWindowTypeWindow)) {
  573.                     // Reparent the window onto the current window in case it got
  574.                     // moved from a frame cell (e.g. during a resize)
  575.                     ::SetParent((HWND)pEmbeddedApp->wdata->window, WINCX(pContext)->GetView()->m_hWnd);
  576.                     ::ShowWindow((HWND)pEmbeddedApp->wdata->window, SW_SHOW);
  577.  
  578.                     // Adobe hack. Turn on clip children
  579.                     CGenericView *pGView =  WINCX(pContext)->GetView();
  580.                     if(pGView) {
  581.                         CFrameGlue *pGlue = pGView->GetFrame();
  582.                         if(pGlue) {
  583.                             pGlue->ClipChildren(CWnd::FromHandle((HWND)pEmbeddedApp->wdata->window), TRUE);
  584.                         }
  585.                     }
  586.                 }
  587.             }
  588.  
  589.             pItem->m_bLoading = TRUE;
  590.         }
  591.  
  592.         pEmbeddedApp->fe_data = (void *)pItem;
  593.         pItem->m_csAddress = pLayoutAddress;
  594.  
  595.         //  Go ahead and assign it into the layout data for use in other functions.
  596.         pLayoutData->FE_Data = (void *)pEmbeddedApp;
  597.  
  598.         // Now that we've set the NPEmbeddedApp's fe_data and layout's FE_Data we can start the embed
  599.         if (NPL_EmbedStart(pContext, pLayoutData, pEmbeddedApp) != NPERR_NO_ERROR) {
  600.             // Something went wrong. Time to clean up. The XP code has already deleted
  601.             // the NPEmbeddedApp
  602.             pLayoutData->FE_Data = NULL;
  603.             pItem->m_bLoading = FALSE;
  604.             delete pItem;
  605.         }
  606.     }
  607.  
  608. }
  609.  
  610. void CGenericDoc::FreeEmbedElement(MWContext *pContext, LO_EmbedStruct *pLayoutData)
  611. {
  612.     NPEmbeddedApp*         pEmbeddedApp = (NPEmbeddedApp*)pLayoutData->FE_Data;
  613.     CNetscapeCntrItem*    pItem = NULL;
  614.     CNetscapeCntrItem*    curItem = NULL;
  615.     int32 iRefCountIndicator = 0;
  616.  
  617.  
  618.     // It's possible that pEmbeddedApp is NULL if the plugin failed to
  619.     // initialize
  620.     if (! pEmbeddedApp)
  621.         return;
  622.  
  623.     // this thing is going to be decremented in NPL_EmbedDelete, so 
  624.     iRefCountIndicator = NPL_GetEmbedReferenceCount(pEmbeddedApp);
  625.  
  626.     pItem = (CNetscapeCntrItem *)pEmbeddedApp->fe_data;
  627.  
  628.     if(iRefCountIndicator > 0)
  629.         {
  630.             // Restore the pItem if necessary. This is needed for printing of
  631.             // embedded apps because we use the cached app from the session data
  632.             // See comments in GetEmbedSize()
  633.             if (pItem && pItem->m_pOriginalItem)
  634.                 pEmbeddedApp->fe_data = (void *)pItem->m_pOriginalItem;
  635.         }
  636.  
  637.     // pEmbeddedApp will be freed in the call to NPL_EmbedDelete
  638.     NPWindow *pAppWin = pEmbeddedApp->wdata;
  639.     BOOL      bFullPage = pEmbeddedApp->pagePluginType == NP_FullPage;
  640.  
  641.     // for OLE to clean up the CNetscapeCntrItem.
  642.     if (pEmbeddedApp->type == NP_OLE)
  643.         curItem = (CNetscapeCntrItem*)pEmbeddedApp->fe_data;
  644.  
  645.     NPL_EmbedDelete(pContext, pLayoutData);
  646.     pLayoutData->FE_Data = NULL;
  647.  
  648.     //    If the item is already gone, bail now.
  649.     // Also check for npdata->refs being greater or equal 0
  650.     // It should not happen but
  651.     // www.msn.com cashes us on resizing if this is not checked.
  652.  
  653.     // but first... Just in case since if pContext were 0 it would've crashed already
  654.     if(pContext == NULL)
  655.         iRefCountIndicator++;
  656.     // because in this case NPL_EmbedDelete does not decrement it
  657.  
  658.     if ((pItem == NULL) || (iRefCountIndicator <= 0))
  659.         return;
  660.  
  661.     //  Decrement the lock.
  662.     pItem->m_iLock--;
  663.  
  664.     //  Remove this element from the list of items accessing us.
  665.     pItem->m_cplElements.RemoveAt(pItem->m_cplElements.Find(pLayoutData));
  666.  
  667.     //  If the lock is zero'd, then we can free off the embed completely when it expires.
  668.     //  We should probably try saving modified files here....  If I knew how.
  669.     if(pItem->m_iLock == 0) {
  670.         CString csRemoveMe = pItem->m_csFileName;
  671.  
  672.         //  If the app hasn't been deleted, break the reference
  673.         //  from the app to the CNetscapeCntrItem.
  674.         if (curItem == pItem) { 
  675.             if (pEmbeddedApp != NULL)
  676.                 pEmbeddedApp->fe_data = NULL;
  677.             if ( pItem->m_lpObject) {
  678.                 LPPERSISTSTORAGE lpPersistStorage =
  679.                     QUERYINTERFACE(pItem->m_lpObject, IPersistStorage);
  680.                 ASSERT(lpPersistStorage != NULL);
  681.                 // removed    pItem->IsDirty() when I figure out how to get lpPersistStorage->IsDirty()
  682.                 // to do the right thing.
  683.                 const char* tempPtr = pItem->m_csAddress;
  684.                 if (lpPersistStorage && (pItem->IsDirty())) { 
  685.                     lpPersistStorage->Release();
  686.  
  687.                     CString    destFileName;
  688.                     if (pItem->m_bCanSavedByOLE) {
  689.                         CString buf;
  690.                         int ret;
  691.                         destFileName.Empty();
  692.                         if (!NET_IsLocalFileURL((char*)tempPtr)) {
  693.                             AfxFormatString1(buf, IDS_SAVE_HTTP_PROMPT, pItem->m_csAddress);
  694.                             ret = AfxMessageBox(buf, MB_YESNO | MB_ICONEXCLAMATION);
  695.                             if (ret == IDYES) {
  696.                                 BOOL result = PromptForFileName(pItem, destFileName, destFileName, FALSE);
  697.                                 if (!result) // user cancel from the getFileDialog
  698.                                     ret = IDNO;
  699.                             }
  700.                         }
  701.                         else  {
  702.                             AfxFormatString1(buf, IDS_SAVE_DOC_PROMPT, pItem->m_csDosName);
  703.                             ret = AfxMessageBox(buf, MB_YESNO | MB_ICONEXCLAMATION);
  704.                             destFileName = pItem->m_csDosName;
  705.                         }
  706.                         
  707.                         switch (ret) {
  708.  
  709.                         case IDYES:     {
  710. #ifdef XP_WIN32
  711.                             SCODE sc = S_OK;
  712. #else
  713.                             HRESULT sc = S_OK;
  714. #endif
  715.                             LPSTORAGE lpStorage = NULL;
  716.                             BOOL result = FALSE;
  717.                             while (!result) {
  718.                                 result =  DoSaveFile( pItem, destFileName);
  719.                                 if (!result) {
  720.                                     CString buf;
  721.                                     AfxFormatString1(buf, IDS_FILESAVEFAILED, destFileName);
  722.                                     AfxMessageBox(buf, MB_OK | MB_ICONEXCLAMATION);
  723.                                     if (!PromptForFileName(pItem, destFileName, destFileName, FALSE))
  724.                                         break;
  725.                                 }
  726.                             }
  727.                             break;
  728.                         }
  729.                         case IDNO:
  730.                             break;
  731.                         }
  732.                     }
  733.                 }
  734.             }
  735.  
  736.             //  If we've a file to remove, do so now.
  737.             if(csRemoveMe.IsEmpty() == FALSE) {
  738.                 TRY {
  739.                     CFile::Remove(csRemoveMe);
  740.                 }
  741.                 CATCH(CFileException, e)    {
  742.                     //  Well, we couldn't remove the file on our own.
  743.                     //      Some locking must still be in place.
  744.                     //  Add it to the list of files to remove on exit.
  745.                     FE_DeleteFileOnExit(csRemoveMe, (const char *)pLayoutData->embed_src);
  746.                 }
  747.                 END_CATCH
  748.                     }
  749.         }
  750.         delete pItem;
  751.  
  752.     }
  753. }
  754.  
  755.  
  756. /////////////////////////////////////////////////////////////////////////////
  757. // CGenericDoc commands
  758.  
  759. BOOL CGenericDoc::OnOpenDocument(const char *pszPathName)   {
  760.     TRACE("CGenericDoc::OnOpenDocument(%s)\n", pszPathName);
  761.  
  762.     //  Check if we need to set our ability to serialize.
  763.     //  Simply save or empty out the name if available.
  764.     if(!m_bOpenDocumentFileSet) {
  765.         m_bOpenDocumentFileSet = TRUE;
  766.         if(pszPathName) {
  767.             m_csOpenDocumentFile = pszPathName;
  768.         }
  769.     }
  770.     
  771.     //  Regardless, call the base.
  772.     //  It ends up calling serialize and we handle correctly by
  773.     //      setting the above serialize flag.
  774.     BOOL bRetval = COleServerDoc::OnOpenDocument(pszPathName);
  775.  
  776.     //  We only handle loads on real file names passed in.
  777.     //  This causes the actual load.
  778.     if(pszPathName && m_pContext) {
  779.         bRetval = m_pContext->OnOpenDocumentCX(pszPathName);
  780.     }
  781.  
  782.     return(bRetval);
  783. }
  784.  
  785. //    Don't allow the frame to close if we've been told not to let it close.
  786. BOOL CGenericDoc::CanCloseFrame(CFrameWnd *pFrame)  {
  787.  
  788.     if (pFrame && pFrame->m_hWnd) {
  789.         HWND    hPopup;
  790.  
  791.         // Check if the frame is displaying a dialog box. If so, don't quit
  792.         // that window
  793.         hPopup = ::GetLastActivePopup(pFrame->m_hWnd);
  794.  
  795.         if (hPopup != pFrame->m_hWnd) {
  796.             // Bring the window to the top of the z-order so the user can get a
  797.             // visual clue as to why we aren't closing
  798.             ::BringWindowToTop(hPopup);
  799.             return FALSE;
  800.         }
  801.  
  802. #ifdef EDITOR
  803.         // Check for changes to edit document and prompt to save:
  804.         CFrameGlue *pGlue = CFrameGlue::GetFrameGlue(pFrame);
  805.         if(pGlue && pGlue->GetMainContext() && !pGlue->GetMainContext()->IsDestroyed() ){
  806.             MWContext *pMWContext = pGlue->GetMainContext()->GetContext();
  807.             if( pMWContext ){
  808.                 // Don't close if something is in progess, like drag and drop
  809.                 // (Browser or Editor)
  810.  
  811.                 // Stop any active Editor plugin
  812.                 if (EDT_IS_EDITOR(pMWContext) && !CheckAndCloseEditorPlugin(pMWContext))
  813.                     return FALSE;
  814.  
  815.                 //  do NOT return false when in waitingMode.
  816.                 //      pMWContext->waitingMode
  817.                 //  waitingMode is the mode we are in when a user can not click on
  818.                 //      another link, not for whatever bastardized purpose you have
  819.                 //      come up with.
  820.                 //  Blocking this on criteria in general is confusing as hell to
  821.                 //      the user, because when they select exit, and we're looking
  822.                 //      up a host, they can't exit.  Whey they say exit, we exit.
  823.                 //  End of story.
  824.  
  825.                     // Don't close if we are in the process of saving
  826.                     //   a file or user cancels when prompted to save,
  827.                     if( pMWContext && EDT_IS_EDITOR(pMWContext) &&
  828.                       pMWContext->edit_saving_url ||
  829.                       (LO_GetEDBuffer( ABSTRACTCX(pMWContext)->GetDocumentContext() ) &&
  830.                        !FE_CheckAndSaveDocument(pMWContext)) ) {
  831.                     return FALSE;
  832.                 }
  833.             }
  834.         }
  835. #endif /* EDITOR */                    
  836.     }
  837.  
  838.  
  839.     //  Don't ask the base, it will ask the user to save a file.
  840.     return(CanClose());
  841. }
  842.  
  843. BOOL CGenericDoc::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) {
  844.     //  Don't handle ID_FILE_CLOSE, let someone else deal with it.
  845.     if(nID == ID_FILE_CLOSE)    {
  846.         return(FALSE);
  847.     }
  848.     else if(nID == ID_EDIT_COPY)    {
  849.         //    If we have an embedded item, we'll want to copy it.
  850.         //    Otherwise, don't handle this message.
  851.         //    By not returning false, we decide to handle it.
  852.         if(m_pEmbeddedItem == NULL)    {
  853.             //    Don't handle it.
  854.             //    This let's the frame deal with it in whatever manner
  855.             //        it needs to.
  856.             return(FALSE);
  857.         }
  858.     }
  859.  
  860.     //  Otherwise, let the base class handle it.
  861.     return(COleServerDoc::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo));
  862. }
  863.  
  864. COleServerItem *CGenericDoc::OnGetEmbeddedItem()    {
  865.     TRACE("CGenericDoc::OnGetEmbeddedItem() %p\n", this);
  866.  
  867.     //  Called by the framework only when needed to get a COleServerItem
  868.     //      that is associated with the document.
  869.     CNetscapeSrvrItem *pItem = new CNetscapeSrvrItem(this);
  870.     ASSERT_VALID(pItem);
  871.     return(pItem);  
  872. }
  873.  
  874. void CGenericDoc::OnEditCopy() 
  875. {
  876.     //    See OnCmdMsg to see exactly when this is called (special cased).
  877.  
  878.     //    If there's an embedded item, copy it to the clipboard.
  879.     //    Disable this functionality, and you disable OLE linked documents.
  880.     //    Work around it.  Forcing me to implement a solution here is the wrong
  881.     //        thing to do.
  882.     CNetscapeSrvrItem *pItem = GetEmbeddedItem();
  883.     if(pItem != NULL)    {
  884.         pItem->CopyToClipboard(TRUE);
  885.     }
  886. }
  887.  
  888. void CGenericDoc::OnOleUpdate() 
  889. {
  890.     TRACE("Updating OLE Embedded Server.\n");
  891.     //    Have the document update in whatever terms are normally
  892.     //        handled in MFC.
  893.     //    The call to update all items causes the redraw in the container.
  894.     //    The OnUpdateDocument call causes serialization fo the current state.
  895.     //    Also, call SetModifiedFlag to force the implementations to think
  896.     //        that the document is dirty.
  897.  
  898.     UpdateAllItems(NULL);
  899.     SetModifiedFlag();
  900.     if(IsInPlaceActive() == FALSE)    {
  901.         //    Only update the document if embedded, not in place.
  902.         OnUpdateDocument();
  903.     }
  904. }
  905.  
  906. void CGenericDoc::OnUpdateOleUpdate(CCmdUI* pCmdUI) 
  907. {
  908.     //    Always leave it enabled, don't know exactly when to turn it off or
  909.     //        how to detect.
  910.     pCmdUI->Enable(TRUE);    
  911. }
  912.  
  913. void CGenericDoc::OnCloseDocument()    {
  914.      // set the flag so we will not realize the Palette. when closing.
  915.  
  916.     //    Call the base.
  917.     COleServerDoc::OnCloseDocument();
  918. }
  919.  
  920.  
  921. void CGenericDoc::OnDeactivateUI( BOOL bUndoable )
  922. {
  923.  
  924.     CInPlaceFrame* pFrameWnd = (CInPlaceFrame*)m_pInPlaceFrame;
  925.  
  926.     COleServerDoc::OnDeactivateUI(bUndoable);
  927.  
  928.     if(pFrameWnd)
  929.         pFrameWnd->ReparentControlBars();
  930. }
  931.  
  932. void CGenericDoc::OnShowControlBars( CFrameWnd *pFrameWnd, BOOL bShow )
  933. {
  934.  
  935.     CInPlaceFrame* pInPlace = (CInPlaceFrame*)m_pInPlaceFrame;
  936.  
  937.     if(pInPlace)
  938.         pInPlace->ShowControlBars(pFrameWnd, bShow);
  939.  
  940.  
  941. }
  942.  
  943.  
  944.  
  945. //    OLE server extension to allow document and server item
  946. //        to minimally function without a context being
  947. //        present.
  948. void CGenericDoc::CacheEphemeralData()
  949. {
  950.     ASSERT(GetContext());
  951.     ASSERT(GetContext()->IsDestroyed() == FALSE);
  952.  
  953.     //    Basically take any data that we'll need in order to serialize
  954.     //        the document.
  955.     //    That is only in the 2.0 timeline the address of the current
  956.     //        history entry!  Whew....
  957.  
  958.     //    Do we have a history entry from which to create
  959.     //        the address?
  960.     History_entry *pHistoryEntry = SHIST_GetCurrent(&(GetContext()->GetContext()->hist));
  961.     if(pHistoryEntry == NULL)    {
  962.         //    Nothing to do really.
  963.     }
  964.     else    {
  965.         //    Save anything.
  966.         //    If in the future, we attempt to access the context, and
  967.         //        are unable, we will fall back to this information.
  968.         m_csEphemeralHistoryAddress = pHistoryEntry->address;
  969.     }
  970. }
  971.  
  972. //    Resolve between actual context and ephemeral data.
  973. void CGenericDoc::GetContextHistoryAddress(CString &csRetval)    {
  974.     if(GetContext() && GetContext()->IsDestroyed() == FALSE)    {
  975.         History_entry *pHistoryEntry = SHIST_GetCurrent(&(GetContext()->GetContext()->hist));
  976.         if(pHistoryEntry == NULL)    {
  977.             csRetval.Empty();
  978.         }
  979.         else    {
  980.             csRetval = pHistoryEntry->address;
  981.         }
  982.     }
  983.     else    {
  984.         //    Return whatever epemeral data we have.
  985.         csRetval = m_csEphemeralHistoryAddress;
  986.     }
  987. }
  988.  
  989.  
  990. //    Enable or disable closing of the frame window.
  991. void CGenericDoc::EnableClose(BOOL bEnable)
  992. {
  993.     //    Just remember the value.
  994.     m_bCanClose = bEnable;
  995.  
  996.     //    We want to recusively walk down all child contexts to
  997.     //        set their values also.
  998.     MWContext *pChild;
  999.     XP_List *pTraverse = GetContext()->GetContext()->grid_children;
  1000.     while((pChild = (MWContext*)XP_ListNextObject(pTraverse)))    {
  1001.         if(ABSTRACTCX(pChild) && ABSTRACTCX(pChild)->IsDCContext() && VOID2CX(pChild->fe.cx, CDCCX)->GetDocument()) {
  1002.             VOID2CX(pChild->fe.cx, CDCCX)->GetDocument()->EnableClose(bEnable);
  1003.         }
  1004.     }
  1005. }
  1006.  
  1007. BOOL CGenericDoc::CanClose()
  1008. {
  1009.     //    Assume our retval is initially what we have set.
  1010.     //    We want to recursively walk down all child contexts to
  1011.     //        see if they are not allowing close.
  1012.     BOOL bRetval = m_bCanClose;
  1013.     if(GetContext())    {
  1014.         MWContext *pChild;
  1015.         XP_List *pTraverse = GetContext()->GetContext()->grid_children;
  1016.         while(bRetval && (pChild = (MWContext*)XP_ListNextObject(pTraverse))) {
  1017.             if(ABSTRACTCX(pChild) && ABSTRACTCX(pChild)->IsDCContext() && VOID2CX(pChild->fe.cx, CDCCX)->GetDocument()) {
  1018.                 bRetval = VOID2CX(pChild->fe.cx, CDCCX)->GetDocument()->CanClose();
  1019.             }
  1020.         }
  1021.     }
  1022.     return(bRetval);
  1023. }
  1024.  
  1025. // This OnSaveDocument should take care of 3 types of saving, when this routine is
  1026. // changed should test on the followin.
  1027. // 1. saving an HTML file from the File|SaveAs menu.
  1028. // 2. Save a OLE container item, opening up a .doc file from the directory listing,
  1029. // after the page is loaded, double click on the item, start in-place edit, type in
  1030. // some changes, then do File |Save As.
  1031. // 3. Test as an OLE inplace server.  Opening up wordPad, do insert object with
  1032. // create from file.
  1033. BOOL CGenericDoc::OnSaveDocument( LPCTSTR lpszPathName )
  1034. {
  1035.     // Since this will only happen with File | Save as, so it is safe to do this.
  1036.     CWinCX* pwincx = (CWinCX*)m_pContext;
  1037.     CNetscapeCntrItem *pItem = (CNetscapeCntrItem *)GetInPlaceActiveItem(CWnd::FromHandle(pwincx->GetPane()));
  1038.     if (pItem) { // we had an inplace edited item.
  1039.         CString fileName;
  1040.     
  1041.         if (lpszPathName == NULL) {// need to bring up the saveAs dialog box
  1042.                               // here.
  1043.             BOOL result = PromptForFileName(pItem, fileName, pItem->m_csAddress, FALSE);
  1044.             if (!result)
  1045.                 return TRUE;  // user cancel here.
  1046.         }
  1047.         else {// using the default control item name.
  1048.             fileName = pItem->m_csDosName;
  1049.         }
  1050.         BOOL result = DoSaveFile(pItem, fileName);
  1051.  
  1052.         if (!result) {
  1053.             CString buf;
  1054.             AfxFormatString1(buf, IDS_FILESAVEFAILED, fileName);
  1055.             AfxMessageBox(buf, MB_OK | MB_ICONEXCLAMATION);
  1056.         }
  1057.         return TRUE;  // return true here, so the regular navigator save as dialog box 
  1058.                     // will not shows up. This is to handle File | Save As ... 
  1059.                     // when we are in inplace edited.
  1060.     }
  1061.  
  1062.     POSITION pos = GetStartPosition( );
  1063.     if (GetNextServerItem(pos)) // OLE contain as us to save the document.
  1064.         return COleServerDoc::OnSaveDocument(lpszPathName);
  1065.     else 
  1066.         return FALSE; // let navigator does the normal saveAs operation.
  1067. }
  1068.  
  1069.  
  1070. BOOL CGenericDoc::PromptForFileName(CNetscapeCntrItem* pItem, CString& lpszPathName, CString &orgFileName, BOOL useDefaultDocName)
  1071. {
  1072.     CString filter;
  1073.     CString ext;
  1074.  
  1075.     int dot_index = orgFileName.ReverseFind('.');
  1076.     if (dot_index > 0) {
  1077.        ext = orgFileName.Right(3);
  1078.     }
  1079.  
  1080.     char name[255];
  1081.     pItem->GetUserType(USERCLASSTYPE_FULL, filter);
  1082.  
  1083.     OPENFILENAME fname;
  1084.     filter += '\0';
  1085.     filter += "*.";
  1086.     filter += ext;
  1087.     filter += '\0';
  1088.     CString s;
  1089.     s.LoadString(IDS_FILTER_ALLFILES);
  1090.     filter += s;
  1091.     filter += '\0';
  1092.     filter += "*.*";
  1093.     filter += '\0';
  1094.     filter += '\0';
  1095.     memset(&fname, 0, sizeof(fname));
  1096.     fname.lStructSize = sizeof(OPENFILENAME);
  1097.     fname.hwndOwner = pItem->GetActiveView()->GetSafeHwnd();
  1098.     fname.lpstrFilter = filter;
  1099.     fname.lpstrCustomFilter = NULL;
  1100.     fname.nFilterIndex = 1;
  1101.     char FullName[255];
  1102.     FullName[0] = 0;
  1103.     strcpy(&FullName[1], ext);
  1104.     fname.lpstrFile = FullName;
  1105.     fname.nMaxFile = _MAX_PATH;
  1106.     fname.lpstrFileTitle = name;
  1107.     fname.nMaxFileTitle = _MAX_FNAME;
  1108.     fname.lpstrInitialDir = NULL;
  1109.     CString title;
  1110.     CString temp;
  1111.     title.LoadString(IDS_SAVE_AS);
  1112.     pItem->GetUserType(USERCLASSTYPE_FULL, temp);
  1113.     title += temp;
  1114.     pItem->GetUserType(USERCLASSTYPE_FULL, title);
  1115.     fname.lpstrTitle = title;
  1116.     fname.lpstrDefExt = ext;
  1117.     fname.Flags = OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
  1118.     BOOL bResult;
  1119.     bResult = FEU_GetSaveFileName(&fname);
  1120.     // prompt, filter, index, CWnd::FromHandle(m_hWnd));
  1121.     if (bResult) { // user choose OK
  1122.         lpszPathName = FullName;
  1123.     }
  1124.     return bResult;
  1125. }
  1126.  
  1127. // If there is an error, an should ask user for futher info to save to the file, then return FALSE,
  1128. // otherwise return TRUE.  meaning this file can not be saved at all.
  1129. BOOL CGenericDoc::DoSaveFile( CNetscapeCntrItem* pItem, LPCTSTR lpszPathName)
  1130. {
  1131.     COleDispatchDriver pDispDrv;
  1132.     int _convert;
  1133.     BOOL cont = TRUE;
  1134.     LPCOLESTR lpsz =T2COLE(lpszPathName); 
  1135. #ifdef XP_WIN32
  1136.     LPDISPATCH pdisp = QUERYINTERFACE(pItem->m_lpObject, IDispatch);
  1137.     WIN32_FIND_DATA fileHandle;
  1138.  
  1139.     HANDLE fHandle = FindFirstFile(lpszPathName, &fileHandle);
  1140.     // only do this for existing file.
  1141.     if ((fHandle != INVALID_HANDLE_VALUE) && pdisp && (pItem->m_idSavedAs != DISPID_UNKNOWN)){
  1142.         pDispDrv.AttachDispatch( pdisp, FALSE);
  1143.         if (pItem->m_idSavedAs) {
  1144.             VARIANT v;    
  1145.             TRY {
  1146.                 static BYTE parms[] = VTS_VARIANT;
  1147.                 V_VT(&v) = VT_BSTR;
  1148.                 V_BSTR(&v) = SysAllocString(lpsz);
  1149.                 pDispDrv.InvokeHelper(pItem->m_idSavedAs, DISPATCH_METHOD, VT_EMPTY, (void*)NULL, parms,
  1150.                     &v);
  1151.                 cont =  FALSE;
  1152.             }
  1153.             CATCH( COleException, e) {
  1154.                 if (StgIsStorageFile(lpsz) != S_OK) {
  1155.                     // this doc object does not support compound file,
  1156.                     // should abort saving operation here.
  1157.                     if (!pItem->ReportError(e->m_sc)) {
  1158.                         AfxMessageBox(AFX_IDP_FAILED_TO_SAVE_DOC);
  1159.                     }
  1160.                     cont = FALSE;
  1161.                 }
  1162.             }
  1163.             AND_CATCH( COleDispatchException, e) {
  1164.                 if (StgIsStorageFile(lpsz) != S_OK) {
  1165.                     // this doc object does not support compound file,
  1166.                     // should abort saving operation here.
  1167.                     // Display message box for dispatch exceptions.
  1168.                     AfxMessageBox((LPCTSTR)e->m_strDescription, 
  1169.                         MB_ICONEXCLAMATION | MB_OK);
  1170.                     cont = FALSE;
  1171.                 }
  1172.             }
  1173.             END_CATCH
  1174.         }
  1175.     }
  1176.  
  1177.     if (!cont) {
  1178.         pDispDrv.DetachDispatch();
  1179.         pdisp->Release();
  1180.         return TRUE;
  1181.     }
  1182. #endif
  1183.     HRESULT sc;
  1184.     lpsz =T2COLE(lpszPathName); 
  1185.  
  1186.     IStorage * pStg;
  1187.  
  1188.     sc = StgOpenStorage(lpsz, NULL,
  1189.         STGM_READWRITE|STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE,
  1190.         0, 0, &pStg);
  1191.     if (sc != S_OK) {
  1192.         // convert existing storage file
  1193.         sc = StgCreateDocfile(lpsz, STGM_READWRITE|
  1194.             STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE,
  1195.             0, &pStg);
  1196.     }
  1197.  
  1198.          
  1199.     if  (sc == S_OK) { 
  1200.  
  1201.         LPPERSISTSTORAGE lpPersistStorage =
  1202.             QUERYINTERFACE(pItem->m_lpObject, IPersistStorage);
  1203.         ASSERT(lpPersistStorage != NULL);
  1204.         if (lpPersistStorage) {
  1205.             sc = lpPersistStorage->HandsOffStorage();
  1206.             if (sc == S_OK) {
  1207.                 sc = ::OleSave(lpPersistStorage, pStg, FALSE);
  1208.                 if (sc == S_OK) {
  1209.                     lpPersistStorage->SaveCompleted(NULL);
  1210.                     pStg->Commit(STGC_DEFAULT);
  1211.                 }
  1212.                 pStg->Release();
  1213.             }
  1214.             lpPersistStorage->Release();
  1215.             if (sc != S_OK) {
  1216.                 // error handling here.
  1217.                 return FALSE;
  1218.             }
  1219.             else return TRUE;
  1220.         }
  1221.     }
  1222.     return FALSE;
  1223. }
  1224.  
  1225.