You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4028 lines
115 KiB
4028 lines
115 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1999 - 1999
|
|
//
|
|
// File: amcdoc.cpp
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
// AMCDoc.cpp : implementation of the CAMCDoc class
|
|
//
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include "AMC.h"
|
|
|
|
#include "AMCDoc.h"
|
|
#include "AMCView.h"
|
|
#include "treectrl.h"
|
|
#include "mainfrm.h"
|
|
#include "cclvctl.h"
|
|
#include "props.h"
|
|
#include <algorithm>
|
|
#include <vector>
|
|
#include <list>
|
|
|
|
#include "amcmsgid.h"
|
|
#include "amcpriv.h"
|
|
#include "mmcutil.h"
|
|
#include "ndmgrp.h"
|
|
#include "strtable.h"
|
|
#include "stgio.h"
|
|
#include "comdbg.h"
|
|
#include "favorite.h"
|
|
#include "mscparser.h"
|
|
#include "scriptevents.h"
|
|
// helper
|
|
tstring GetCurrentFileVersionAsString();
|
|
|
|
//############################################################################
|
|
//############################################################################
|
|
//
|
|
// Implementation of class CMMCDocument
|
|
//
|
|
//############################################################################
|
|
//############################################################################
|
|
/*+-------------------------------------------------------------------------*
|
|
* class CMMCDocument
|
|
*
|
|
*
|
|
* PURPOSE: The COM 0bject that exposes the Document interface.
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
class CMMCDocument :
|
|
public CMMCIDispatchImpl<Document>,
|
|
public CTiedComObject<CAMCDoc>
|
|
{
|
|
public:
|
|
typedef CAMCDoc CMyTiedObject;
|
|
|
|
public:
|
|
BEGIN_MMC_COM_MAP(CMMCDocument)
|
|
END_MMC_COM_MAP()
|
|
|
|
//Document interface
|
|
public:
|
|
MMC_METHOD0(Save);
|
|
MMC_METHOD1(SaveAs, BSTR /*bstrFilename*/);
|
|
MMC_METHOD1(Close, BOOL /*bSaveChanges*/);
|
|
MMC_METHOD1(CreateProperties, PPPROPERTIES /*ppProperties*/);
|
|
|
|
// properties
|
|
MMC_METHOD1(get_Views, PPVIEWS /*ppViews*/);
|
|
MMC_METHOD1(get_SnapIns, PPSNAPINS /*ppSnapIns*/);
|
|
MMC_METHOD1(get_ActiveView, PPVIEW /*ppView*/);
|
|
MMC_METHOD1(get_Name, PBSTR /*pbstrName*/);
|
|
MMC_METHOD1(put_Name, BSTR /*bstrName*/);
|
|
MMC_METHOD1(get_Location, PBSTR /*pbstrLocation*/);
|
|
MMC_METHOD1(get_IsSaved, PBOOL /*pBIsSaved*/);
|
|
MMC_METHOD1(get_Mode, PDOCUMENTMODE /*pMode*/);
|
|
MMC_METHOD1(put_Mode, DocumentMode /*mode*/);
|
|
MMC_METHOD1(get_RootNode, PPNODE /*ppNode*/);
|
|
MMC_METHOD1(get_ScopeNamespace, PPSCOPENAMESPACE /*ppScopeNamespace*/);
|
|
MMC_METHOD1(get_Application, PPAPPLICATION /*ppApplication*/);
|
|
};
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* class CMMCViews
|
|
*
|
|
*
|
|
* PURPOSE: The COM 0bject that exposes the Views interface.
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
|
|
// the real CMMCViews is typedef'd below.
|
|
class _CMMCViews :
|
|
public CMMCIDispatchImpl<Views>, // the Views interface
|
|
public CTiedComObject<CAMCDoc>
|
|
{
|
|
public:
|
|
typedef CAMCDoc CMyTiedObject;
|
|
|
|
BEGIN_MMC_COM_MAP(_CMMCViews)
|
|
END_MMC_COM_MAP()
|
|
|
|
// Views interface
|
|
public:
|
|
MMC_METHOD1(get_Count, PLONG /*pCount*/);
|
|
MMC_METHOD2(Add, PNODE /*pNode*/, ViewOptions /*fViewOptions*/);
|
|
MMC_METHOD2(Item, long /*Index*/, PPVIEW /*ppView*/);
|
|
};
|
|
|
|
// this typedefs the real CMMCViews class. Implements get__NewEnum using CMMCEnumerator and a CAMCViewPosition object
|
|
typedef CMMCNewEnumImpl<_CMMCViews, CAMCViewPosition> CMMCViews;
|
|
|
|
|
|
//############################################################################
|
|
//############################################################################
|
|
//
|
|
// Implementation of class CStringTableString
|
|
//
|
|
//############################################################################
|
|
//############################################################################
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* CStringTableString::GetStringTable
|
|
*
|
|
*
|
|
*--------------------------------------------------------------------------*/
|
|
IStringTablePrivate* CStringTableString::GetStringTable () const
|
|
{
|
|
return (CAMCDoc::GetDocument()->GetStringTable());
|
|
}
|
|
|
|
void ShowAdminToolsOnMenu(LPCTSTR lpszFilename);
|
|
|
|
|
|
enum ENodeType
|
|
{
|
|
entRoot,
|
|
entSelected,
|
|
};
|
|
|
|
//############################################################################
|
|
//############################################################################
|
|
//
|
|
// Implementation of class CAMCDoc
|
|
//
|
|
//############################################################################
|
|
//############################################################################
|
|
|
|
IMPLEMENT_DYNCREATE(CAMCDoc, CDocument)
|
|
|
|
BEGIN_MESSAGE_MAP(CAMCDoc, CDocument)
|
|
//{{AFX_MSG_MAP(CAMCDoc)
|
|
ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave)
|
|
ON_COMMAND(ID_CONSOLE_ADDREMOVESNAPIN, OnConsoleAddremovesnapin)
|
|
ON_UPDATE_COMMAND_UI(ID_CONSOLE_ADDREMOVESNAPIN, OnUpdateConsoleAddremovesnapin)
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CAMCDoc construction/destruction
|
|
|
|
CAMCDoc* CAMCDoc::m_pDoc = NULL;
|
|
|
|
CAMCDoc::CAMCDoc()
|
|
: m_MTNodeIDForNewView(ROOTNODEID),
|
|
m_ViewIDForNewView(0),
|
|
m_lNewWindowOptions(MMC_NW_OPTION_NONE),
|
|
m_bReadOnlyDoc(false),
|
|
m_fFrameModified (false),
|
|
m_eSaveStatus (eStat_Succeeded),
|
|
m_pFavorites(NULL),
|
|
m_bCanCloseViews(true)
|
|
{
|
|
TRACE_CONSTRUCTOR(CAMCDoc);
|
|
DECLARE_SC (sc, TEXT("CAMCDoc::CAMCDoc"));
|
|
|
|
CComObject<CMasterStringTable> * pStringTable;
|
|
|
|
sc = CComObject<CMasterStringTable>::CreateInstance (&pStringTable);
|
|
if(sc.IsError() || !pStringTable)
|
|
{
|
|
sc = E_OUTOFMEMORY;
|
|
sc.FatalError();
|
|
}
|
|
|
|
m_spStringTable = pStringTable; // does the addref.
|
|
if(m_spStringTable == NULL)
|
|
{
|
|
delete pStringTable;
|
|
sc = E_UNEXPECTED;
|
|
sc.FatalError();
|
|
}
|
|
|
|
m_pstrCustomTitle = new CStringTableString(m_spStringTable);
|
|
if(!m_pstrCustomTitle)
|
|
{
|
|
sc = E_OUTOFMEMORY;
|
|
sc.FatalError();
|
|
}
|
|
|
|
if (m_pDoc)
|
|
m_pDoc->OnCloseDocument();
|
|
|
|
// Set default version update dialog to one appropriate for explicit saves
|
|
SetExplicitSave(true);
|
|
m_pDoc = this;
|
|
|
|
m_ConsoleData.m_pConsoleDocument = this;
|
|
}
|
|
|
|
CAMCDoc::~CAMCDoc()
|
|
{
|
|
TRACE_DESTRUCTOR(CAMCDoc);
|
|
|
|
if (m_pDoc == this)
|
|
m_pDoc = NULL;
|
|
|
|
if(m_pFavorites != NULL)
|
|
{
|
|
delete m_pFavorites;
|
|
m_pFavorites = NULL;
|
|
}
|
|
|
|
delete m_pstrCustomTitle;
|
|
|
|
// Tell the node manager to release it's reference on the scope tree
|
|
IFramePrivatePtr spFrame;
|
|
|
|
HRESULT hr = spFrame.CreateInstance(CLSID_NodeInit, NULL, MMC_CLSCTX_INPROC);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
spFrame->SetScopeTree(NULL);
|
|
ReleaseNodeManager();
|
|
}
|
|
|
|
/*
|
|
* if we used a custom icon, revert to the default icon on the frame
|
|
*/
|
|
if (m_CustomIcon)
|
|
{
|
|
CMainFrame* pMainFrame = AMCGetMainWnd();
|
|
|
|
if (pMainFrame != NULL)
|
|
{
|
|
pMainFrame->SetIconEx (NULL, true);
|
|
pMainFrame->SetIconEx (NULL, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CAMCDoc::ReleaseNodeManager()
|
|
{
|
|
m_spScopeTreePersist = NULL;
|
|
m_spScopeTree = NULL;
|
|
m_spStorage = NULL;
|
|
}
|
|
|
|
|
|
//############################################################################
|
|
//############################################################################
|
|
//
|
|
// CAMCDoc Object model methods.
|
|
//
|
|
//############################################################################
|
|
//############################################################################
|
|
|
|
// Document interface
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* CAMCDoc::ScCreateProperties
|
|
*
|
|
* Creates an empty Properties collection.
|
|
*
|
|
* Returns:
|
|
* E_UNEXPECTED scope tree wasn't available
|
|
* other value returned by IScopeTree::CreateProperties
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
SC CAMCDoc::ScCreateProperties (Properties** ppProperties)
|
|
{
|
|
DECLARE_SC (sc, _T("CAMCDoc::ScCreateProperties"));
|
|
|
|
/*
|
|
* insure we have a scope tree; ppProperties will be validated downstream
|
|
*/
|
|
if (m_spScopeTree == NULL)
|
|
return (sc = E_UNEXPECTED);
|
|
|
|
/*
|
|
* get the scope tree to create a Properties collection for us
|
|
*/
|
|
sc = m_spScopeTree->CreateProperties (ppProperties);
|
|
if (sc)
|
|
return (sc);
|
|
|
|
return (sc);
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CAMCDoc::ScEnumNext
|
|
*
|
|
* PURPOSE: Returns the next item in the enumeration sequence
|
|
*
|
|
* PARAMETERS:
|
|
* _Position & pos :
|
|
* PDISPATCH & pDispatch :
|
|
*
|
|
* RETURNS:
|
|
* SC
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CAMCDoc::ScEnumNext(CAMCViewPosition &pos, PDISPATCH & pDispatch)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::ScEnumNext"));
|
|
|
|
CAMCView *pView = GetNextAMCView(pos);
|
|
|
|
if(NULL ==pView) // ran out of elements
|
|
{
|
|
sc = S_FALSE;
|
|
return sc;
|
|
}
|
|
|
|
// at this point, we have a valid CAMCView.
|
|
ViewPtr spMMCView = NULL;
|
|
|
|
sc = pView->ScGetMMCView(&spMMCView);
|
|
if(sc)
|
|
return sc;
|
|
|
|
if(spMMCView == NULL)
|
|
{
|
|
sc = E_UNEXPECTED; // should never happen.
|
|
return sc;
|
|
}
|
|
|
|
/*
|
|
* return the IDispatch for the object and leave a ref on it for the client
|
|
*/
|
|
pDispatch = spMMCView.Detach();
|
|
|
|
return sc;
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CAMCDoc::ScEnumSkip
|
|
*
|
|
* PURPOSE:
|
|
*
|
|
* PARAMETERS:
|
|
* unsigned long :
|
|
* CAMCViewPosition & pos :
|
|
*
|
|
* RETURNS:
|
|
* SC
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CAMCDoc::ScEnumSkip(unsigned long celt, unsigned long& celtSkipped,
|
|
CAMCViewPosition &pos)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::ScEnumSkip"));
|
|
|
|
// skip celt positions, don't check the last skip.
|
|
for(celtSkipped=0; celtSkipped<celt; celtSkipped++)
|
|
{
|
|
if (pos == NULL)
|
|
{
|
|
sc = S_FALSE;
|
|
return sc;
|
|
}
|
|
|
|
// go to the next view
|
|
GetNextAMCView(pos);
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CAMCDoc::ScEnumReset
|
|
*
|
|
* PURPOSE:
|
|
*
|
|
* PARAMETERS:
|
|
* CAMCViewPosition & pos :
|
|
*
|
|
* RETURNS:
|
|
* SC
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CAMCDoc::ScEnumReset(CAMCViewPosition &pos)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::ScEnumReset"));
|
|
|
|
// reset the position to the first view.
|
|
pos = GetFirstAMCViewPosition();
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CAMCDoc::ScSave
|
|
//
|
|
// Synopsis: Saves the document.
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CAMCDoc::ScSave ()
|
|
{
|
|
DECLARE_SC(sc, _T("CAMCDoc::ScSave"));
|
|
|
|
// Return if there is no file name given.
|
|
if (m_strPathName.IsEmpty())
|
|
return sc = ScFromMMC(IDS_UnableToSaveDocumentMessage);
|
|
|
|
// save the document (this function may produce UI, but we tried ^ to avoid it)
|
|
if (!DoFileSave())
|
|
return sc = ScFromMMC(IDS_UnableToSaveDocumentMessage);
|
|
|
|
return (sc);
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CAMCDoc::ScSaveAs
|
|
*
|
|
* PURPOSE: Saves the console file, using the specified filename.
|
|
*
|
|
* PARAMETERS:
|
|
* BSTR bstrFilename : The path to save the file to.
|
|
*
|
|
* RETURNS:
|
|
* STDMETHODIMP
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CAMCDoc::ScSaveAs(BSTR bstrFilename)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::ScSaveAs"));
|
|
|
|
USES_CONVERSION;
|
|
|
|
LPCTSTR lpctstrName = OLE2T(bstrFilename);
|
|
if(!OnSaveDocument(lpctstrName))
|
|
{
|
|
sc = ScFromMMC(IDS_UnableToSaveDocumentMessage);
|
|
return sc;
|
|
}
|
|
else
|
|
{
|
|
DeleteHelpFile ();
|
|
SetPathName(lpctstrName);
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CAMCDoc::ScClose
|
|
*
|
|
* PURPOSE: implements Document.Close for object model
|
|
*
|
|
* PARAMETERS:
|
|
* BOOL bSaveChanges - save changes before closing
|
|
*
|
|
* RETURNS:
|
|
* SC - result code
|
|
*
|
|
\***************************************************************************/
|
|
SC
|
|
CAMCDoc::ScClose(BOOL bSaveChanges)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::ScClose"));
|
|
|
|
if (bSaveChanges)
|
|
{
|
|
// cannot save ned document this way!
|
|
if (m_strPathName.IsEmpty())
|
|
return sc = ScFromMMC(IDS_UnableToSaveDocumentMessage);
|
|
|
|
// check for property sheets open
|
|
if (FArePropertySheetsOpen(NULL))
|
|
return sc = ScFromMMC(IDS_ClosePropertyPagesBeforeClosingTheDoc);
|
|
|
|
// save the document (this function may produce UI, but we tried ^ to avoid it)
|
|
if (!DoFileSave())
|
|
return sc = ScFromMMC(IDS_UnableToSaveDocumentMessage);
|
|
}
|
|
|
|
OnCloseDocument();
|
|
|
|
return sc;
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CAMCDoc::ScItem
|
|
*
|
|
* PURPOSE: Returns the view specified by the index.
|
|
*
|
|
* PARAMETERS:
|
|
* long Index :
|
|
* View ** ppView :
|
|
*
|
|
* RETURNS:
|
|
* STDMETHOD
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CAMCDoc::ScItem(long Index, PPVIEW ppView)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::ScItem"));
|
|
|
|
// check parameters
|
|
if( (Index <= 0) || (Index > GetNumberOfViews()) || (!ppView) )
|
|
{
|
|
sc = E_INVALIDARG;
|
|
return sc;
|
|
}
|
|
|
|
// step to the appropriate view
|
|
CAMCViewPosition pos = GetFirstAMCViewPosition();
|
|
CAMCView *pView = NULL;
|
|
|
|
for (int nCount = 0; (nCount< Index) && (pos != NULL); )
|
|
{
|
|
pView = GetNextAMCView(pos);
|
|
VERIFY (++nCount);
|
|
}
|
|
|
|
// make sure we have a valid view.
|
|
|
|
if( (nCount != Index) || (!pView) )
|
|
{
|
|
sc = E_UNEXPECTED;
|
|
return sc;
|
|
}
|
|
|
|
sc = pView->ScGetMMCView(ppView);
|
|
return sc;
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* ScMapViewOptions
|
|
*
|
|
* PURPOSE: helper function maps ViewOptions to view creation flags
|
|
*
|
|
* PARAMETERS:
|
|
* pNode :
|
|
*
|
|
* RETURNS:
|
|
* SC
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
|
|
static SC ScMapViewOptions( ViewOptions fViewOptions, DWORD &value)
|
|
{
|
|
DECLARE_SC(sc, TEXT("ScMapViewOptions"));
|
|
|
|
value = MMC_NW_OPTION_NONE;
|
|
|
|
// test to see if parameter is correct
|
|
const DWORD mask = (ViewOption_ScopeTreeHidden |
|
|
ViewOption_NoToolBars |
|
|
ViewOption_NotPersistable
|
|
);
|
|
|
|
if (fViewOptions & (~mask))
|
|
sc = E_INVALIDARG;
|
|
|
|
if (fViewOptions & ViewOption_ScopeTreeHidden)
|
|
value |= MMC_NW_OPTION_NOSCOPEPANE;
|
|
if (fViewOptions & ViewOption_NotPersistable)
|
|
value |= MMC_NW_OPTION_NOPERSIST;
|
|
if (fViewOptions & ViewOption_NoToolBars)
|
|
value |= MMC_NW_OPTION_NOTOOLBARS;
|
|
|
|
return sc;
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CAMCDoc::ScAdd
|
|
*
|
|
* PURPOSE: Impelements Views.Add method
|
|
*
|
|
* PARAMETERS:
|
|
* pNode :
|
|
*
|
|
* RETURNS:
|
|
* SC
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CAMCDoc::ScAdd( PNODE pNode, ViewOptions fViewOptions )
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::ScAdd"));
|
|
|
|
// lock AppEvents until this function is done
|
|
LockComEventInterface(AppEvents);
|
|
|
|
sc = ScCheckPointers(m_spScopeTree, E_POINTER);
|
|
if (sc)
|
|
return sc;
|
|
|
|
DWORD dwOptions = 0;
|
|
sc = ScMapViewOptions( fViewOptions, dwOptions );
|
|
if (sc)
|
|
return sc;
|
|
|
|
MTNODEID id;
|
|
sc = m_spScopeTree->GetNodeID(pNode, &id);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// Set the given node-id as the root.
|
|
SetMTNodeIDForNewView(id);
|
|
SetNewWindowOptions(dwOptions);
|
|
CreateNewView( true );
|
|
SetMTNodeIDForNewView(ROOTNODEID);
|
|
|
|
return sc;
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CAMCDoc::Scget_Views
|
|
*
|
|
* PURPOSE: Returns a pointer to the Views interface
|
|
* (which is implemented by the same object, but need not be)
|
|
*
|
|
* PARAMETERS:
|
|
* Views ** ppViews :
|
|
*
|
|
* RETURNS:
|
|
* STDMETHODIMP
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CAMCDoc::Scget_Views(PPVIEWS ppViews)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::Scget_Views"));
|
|
|
|
if(!ppViews)
|
|
{
|
|
sc = E_POINTER;
|
|
return sc;
|
|
}
|
|
|
|
// init out parameter
|
|
*ppViews = NULL;
|
|
|
|
// create a Views if needed.
|
|
sc = CTiedComObjectCreator<CMMCViews>::ScCreateAndConnect(*this, m_spViews);
|
|
if(sc)
|
|
return sc;
|
|
|
|
sc = ScCheckPointers(m_spViews, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// addref the pointer for the client.
|
|
m_spViews->AddRef();
|
|
*ppViews = m_spViews;
|
|
|
|
return sc;
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CAMCDoc::Scget_SnapIns
|
|
*
|
|
* PURPOSE: returns a pointer to the SnapIns object.
|
|
*
|
|
* PARAMETERS:
|
|
* SnapIns ** ppSnapIns :
|
|
*
|
|
* RETURNS:
|
|
* STDMETHODIMP
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CAMCDoc::Scget_SnapIns(PPSNAPINS ppSnapIns)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::Scget_SnapIns"));
|
|
|
|
if((NULL==ppSnapIns) || (NULL == m_spScopeTree) )
|
|
{
|
|
sc = E_POINTER;
|
|
return sc;
|
|
}
|
|
|
|
sc = m_spScopeTree->QuerySnapIns(ppSnapIns);
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CAMCDoc::Scget_ScopeNamespace
|
|
*
|
|
* PURPOSE: returns a pointer to the ScopeNamespace object.
|
|
*
|
|
* PARAMETERS:
|
|
* ScopeNamespace ** ppScopeNamespace :
|
|
*
|
|
* RETURNS:
|
|
* STDMETHODIMP
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CAMCDoc::Scget_ScopeNamespace(PPSCOPENAMESPACE ppScopeNamespace)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::Scget_ScopeNamespace"));
|
|
|
|
if((NULL==ppScopeNamespace) || (NULL == m_spScopeTree) )
|
|
{
|
|
sc = E_POINTER;
|
|
return sc;
|
|
}
|
|
|
|
sc = m_spScopeTree->QueryScopeNamespace(ppScopeNamespace);
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CAMCDoc::Scget_Count
|
|
*
|
|
* PURPOSE:
|
|
*
|
|
* PARAMETERS:
|
|
* long * pCount :
|
|
*
|
|
* RETURNS:
|
|
* STDMETHODIMP
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CAMCDoc::Scget_Count(PLONG pCount)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::Scget_Count"));
|
|
|
|
// check parameters
|
|
if(!pCount)
|
|
{
|
|
sc = E_POINTER;
|
|
return sc;
|
|
}
|
|
|
|
// this should *not* be GetNumberOfPersistedViews
|
|
*pCount = GetNumberOfViews();
|
|
|
|
return sc;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CAMCDoc::Scget_Name
|
|
//
|
|
// Synopsis: Retrive the name of the current doc.
|
|
//
|
|
// Arguments: [pbstrName] - Ptr to the name to be returned.
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CAMCDoc::Scget_Name (PBSTR pbstrName)
|
|
{
|
|
DECLARE_SC(sc, _T("CAMCDoc::Scget_Name"));
|
|
sc = ScCheckPointers(pbstrName);
|
|
if (sc)
|
|
return sc;
|
|
|
|
CString strPath = GetPathName();
|
|
|
|
*pbstrName = strPath.AllocSysString();
|
|
|
|
return (sc);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CAMCDoc::Scput_Name
|
|
//
|
|
// Synopsis: Sets the name of the current document.
|
|
//
|
|
// Arguments: [bstrName] - The new name.
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CAMCDoc::Scput_Name(BSTR bstrName)
|
|
{
|
|
DECLARE_SC(sc, _T("CAMCDoc::Scput_Name"));
|
|
|
|
USES_CONVERSION;
|
|
LPCTSTR lpszPath = OLE2CT(bstrName);
|
|
|
|
SetPathName(lpszPath, FALSE /*Dont add to MRU*/);
|
|
|
|
return (sc);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CAMCDoc::Scget_Mode
|
|
//
|
|
// Synopsis: Retrieve the document mode.
|
|
//
|
|
// Arguments: [pMode] - Ptr to doc mode.
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CAMCDoc::Scget_Mode (PDOCUMENTMODE pMode)
|
|
{
|
|
DECLARE_SC(sc, _T("CAMCDoc::Scget_Mode"));
|
|
sc = ScCheckPointers(pMode);
|
|
if (sc)
|
|
return sc;
|
|
|
|
if (! GetDocumentMode(pMode))
|
|
return (sc = E_FAIL);
|
|
|
|
return (sc);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CAMCDoc::Scput_Mode
|
|
//
|
|
// Synopsis: Modify the document mode.
|
|
//
|
|
// Arguments: [mode] - new mode for the document.
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CAMCDoc::Scput_Mode (DocumentMode mode)
|
|
{
|
|
DECLARE_SC(sc, _T("CAMCDoc::Scput_Mode"));
|
|
|
|
// SetDocumentMode fails if document mode is invalid.
|
|
if (! SetDocumentMode(mode))
|
|
return (sc = E_INVALIDARG);
|
|
|
|
return (sc);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CAMCDoc::Scget_ActiveView
|
|
//
|
|
// Synopsis: Retrieve the Active View object.
|
|
//
|
|
// Arguments: [ppView] - Ptr to a ptr of View object.
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CAMCDoc::Scget_ActiveView (PPVIEW ppView)
|
|
{
|
|
DECLARE_SC(sc, _T("CAMCDoc::Scget_ActiveView"));
|
|
sc = ScCheckPointers(ppView);
|
|
if (sc)
|
|
return sc;
|
|
|
|
*ppView = NULL;
|
|
|
|
CMainFrame* pMainFrame = AMCGetMainWnd();
|
|
sc = ScCheckPointers(pMainFrame, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
CAMCView *pView = pMainFrame->GetActiveAMCView();
|
|
if (! pView)
|
|
{
|
|
return (sc = ScFromMMC(IDS_NoActiveView)); // There are no active views.
|
|
}
|
|
|
|
// at this point, we have a valid CAMCView.
|
|
ViewPtr spMMCView = NULL;
|
|
|
|
sc = pView->ScGetMMCView(&spMMCView);
|
|
if(sc)
|
|
return sc;
|
|
|
|
sc = ScCheckPointers(spMMCView, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
/*
|
|
* return the object and leave a ref on it for the client
|
|
*/
|
|
*ppView = spMMCView.Detach();
|
|
|
|
return (sc);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CAMCDoc::Scget_IsSaved
|
|
//
|
|
// Synopsis: Returns whether the file was saved. If not,
|
|
// it is dirty and needs to be saved.
|
|
//
|
|
// Arguments: [pBIsSaved] - Ptr to BOOL (IsSaved info).
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CAMCDoc::Scget_IsSaved (PBOOL pBIsSaved)
|
|
{
|
|
DECLARE_SC(sc, _T("CAMCDoc::Scget_IsSaved"));
|
|
sc = ScCheckPointers(pBIsSaved);
|
|
if (sc)
|
|
return sc;
|
|
|
|
*pBIsSaved = (IsModified() == FALSE);
|
|
|
|
return (sc);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CAMCDoc::Scget_Location
|
|
//
|
|
// Synopsis: Gets the location of the current document.
|
|
//
|
|
// Arguments: [pbstrLocation] - Ptr to BSTR string in which result is returned.
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CAMCDoc::Scget_Location (PBSTR pbstrLocation)
|
|
{
|
|
DECLARE_SC(sc, _T("CAMCDoc::Scget_Location"));
|
|
sc = ScCheckPointers(pbstrLocation);
|
|
if (sc)
|
|
return sc;
|
|
|
|
CString strFullPath = GetPathName();
|
|
|
|
// Even if path is empty below code will return empty string.
|
|
int nSlashLoc = strFullPath.ReverseFind(_T('\\'));
|
|
CString strLocation = strFullPath.Left(nSlashLoc);
|
|
|
|
*pbstrLocation = strLocation.AllocSysString();
|
|
|
|
return (sc);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CAMCDoc::Scget_RootNode
|
|
//
|
|
// Synopsis: Returns the console root node.
|
|
//
|
|
// Arguments: [ppNode] - Ptr to ptr to root node obj.
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CAMCDoc::Scget_RootNode (PPNODE ppNode)
|
|
{
|
|
DECLARE_SC(sc, _T("CAMCDoc::Scget_RootNode"));
|
|
sc = ScCheckPointers(ppNode);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = ScCheckPointers(m_spScopeTree, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = m_spScopeTree->QueryRootNode(ppNode);
|
|
|
|
return (sc);
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CAMCDoc::ScGetMMCDocument
|
|
*
|
|
* PURPOSE: Creates, AddRef's, and returns a pointer to the tied COM object.
|
|
*
|
|
* PARAMETERS:
|
|
* Document ** ppDocument :
|
|
*
|
|
* RETURNS:
|
|
* SC
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CAMCDoc::ScGetMMCDocument(Document **ppDocument)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::ScGetMMCDocument"));
|
|
|
|
// parameter check
|
|
sc = ScCheckPointers(ppDocument);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// init out parameter
|
|
*ppDocument = NULL;
|
|
|
|
// create a CAMCDoc if needed.
|
|
sc = CTiedComObjectCreator<CMMCDocument>::ScCreateAndConnect(*this, m_sp_Document);
|
|
if(sc)
|
|
return sc;
|
|
|
|
sc = ScCheckPointers(m_sp_Document, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// addref the pointer for the client.
|
|
m_sp_Document->AddRef();
|
|
*ppDocument = m_sp_Document;
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* GetFirstAMCViewPosition
|
|
*
|
|
* PURPOSE: Returns the CAMCViewPosition of the first AMCView, or NULL if there is
|
|
* no AMCView.
|
|
*
|
|
* RETURNS:
|
|
* CAMCViewPosition
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
CAMCViewPosition
|
|
CAMCDoc::GetFirstAMCViewPosition() const
|
|
{
|
|
CAMCViewPosition vpos;
|
|
POSITION pos = GetFirstViewPosition();
|
|
|
|
while(pos != NULL)
|
|
{
|
|
POSITION posTemp = pos; // hold this value.
|
|
|
|
CAMCView *pView = dynamic_cast<CAMCView *>(GetNextView(pos));
|
|
if(pView != NULL) // found the AMCView
|
|
{
|
|
vpos.SetPosition(posTemp); // NOT pos!
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (vpos);
|
|
}
|
|
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CAMCDoc::GetNextAMCView
|
|
*
|
|
* PURPOSE: Returns the next AMCView, starting at pos (inclusive)
|
|
*
|
|
* PARAMETERS:
|
|
* CAMCViewPosition & pos : incremented to the next AMCView, NOT the next View.
|
|
*
|
|
* RETURNS:
|
|
* CAMCView *
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
|
|
CAMCView *
|
|
CAMCDoc::GetNextAMCView(CAMCViewPosition &pos) const
|
|
{
|
|
CAMCView *pView = NULL;
|
|
|
|
// check parameters
|
|
if (pos == NULL)
|
|
return NULL;
|
|
|
|
// pos is non-NULL at this point. Loop until we have a CAMCView.
|
|
// Note that unless there's a bug in GetFirstAMCViewPosition or
|
|
// GetNextAMCView, we'll only go through this loop once, since a
|
|
// non-NULL CAMCViewPosition should always refer to a CAMCView.
|
|
while( (NULL == pView) && (pos != NULL) )
|
|
{
|
|
CView *pV = GetNextView(pos.GetPosition());
|
|
pView = dynamic_cast<CAMCView *>(pV);
|
|
}
|
|
|
|
// at this point, pView is the correct return value, and it had better
|
|
// not be NULL, or we never should have had a non-NULL pos
|
|
ASSERT (pView != NULL);
|
|
|
|
// bump pos to the next CAMCView
|
|
// NOTE: This is NOT redundant. Must point to a CAMCView so that
|
|
// NULL position tests can be done.
|
|
while(pos != NULL)
|
|
{
|
|
/*
|
|
* use temporary POSITION so we won't increment the POSITION
|
|
* inside pos until we know pos doesn't refer to a CAMCView
|
|
*/
|
|
POSITION posT = pos.GetPosition();
|
|
|
|
if(dynamic_cast<CAMCView *>(GetNextView(posT)) != NULL) // found a CAMCView at pos
|
|
break;
|
|
|
|
/*
|
|
* update the CAMCViewPosition with the position incremented
|
|
* by GetNextView only if we didn't find a CAMCView at its
|
|
* previous location
|
|
*/
|
|
pos.SetPosition (posT);
|
|
}
|
|
|
|
#ifdef DBG
|
|
/*
|
|
* if we're returning a non-NULL, it'd better point to a CAMCView
|
|
*/
|
|
if (pos != NULL)
|
|
{
|
|
POSITION posT = pos.GetPosition();
|
|
ASSERT (dynamic_cast<CAMCView *>(GetNextView(posT)) != NULL);
|
|
}
|
|
#endif
|
|
|
|
return pView;
|
|
}
|
|
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CAMCDoc::InitNodeManager
|
|
*
|
|
* PURPOSE:
|
|
*
|
|
* RETURNS:
|
|
* HRESULT
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
HRESULT CAMCDoc::InitNodeManager()
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::InitNodeManager"));
|
|
|
|
TRACE_METHOD(CAMCDoc, InitNodeManager);
|
|
|
|
// Should not be currently initialized
|
|
ASSERT(m_spScopeTree == NULL && m_spScopeTreePersist == NULL);
|
|
ASSERT(m_spStorage == NULL);
|
|
|
|
// The string table should have been created by now
|
|
sc = ScCheckPointers(m_spStringTable, E_FAIL);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
// create the favorites at this stage
|
|
ASSERT(m_pFavorites == NULL);
|
|
m_pFavorites = new CFavorites;
|
|
sc = ScCheckPointers(m_pFavorites, E_OUTOFMEMORY);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
|
|
// Create the initial private frame
|
|
IFramePrivatePtr spFrame;
|
|
sc = spFrame.CreateInstance(CLSID_NodeInit, NULL, MMC_CLSCTX_INPROC);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// recheck teh pointer
|
|
sc = ScCheckPointers( spFrame, E_UNEXPECTED );
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
|
|
// Create the scope tree
|
|
sc = m_spScopeTree.CreateInstance(CLSID_ScopeTree, NULL, MMC_CLSCTX_INPROC);
|
|
if (sc)
|
|
{
|
|
ReleaseNodeManager();
|
|
return sc.ToHr();
|
|
}
|
|
|
|
// recheck the pointer
|
|
sc = ScCheckPointers( m_spScopeTree, E_UNEXPECTED );
|
|
if (sc)
|
|
{
|
|
ReleaseNodeManager();
|
|
return sc.ToHr();
|
|
}
|
|
|
|
// link frame and scope tree
|
|
sc = spFrame->SetScopeTree(m_spScopeTree);
|
|
if(sc)
|
|
{
|
|
ReleaseNodeManager();
|
|
return sc.ToHr();
|
|
}
|
|
|
|
// Initialize the tree
|
|
sc = m_spScopeTree->Initialize(AfxGetMainWnd()->m_hWnd, m_spStringTable);
|
|
if (sc)
|
|
{
|
|
ReleaseNodeManager();
|
|
return sc.ToHr();
|
|
}
|
|
|
|
// Get the IPersistStorage interface from the scope tree
|
|
m_spScopeTreePersist = m_spScopeTree; // query for IPersistStorage
|
|
ASSERT(m_spScopeTreePersist != NULL);
|
|
|
|
m_ConsoleData.SetScopeTree (m_spScopeTree);
|
|
|
|
CMainFrame* pFrame = AMCGetMainWnd();
|
|
m_ConsoleData.m_hwndMainFrame = pFrame->GetSafeHwnd();
|
|
m_ConsoleData.m_pConsoleFrame = pFrame;
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
BOOL CAMCDoc::OnNewDocument()
|
|
{
|
|
TRACE_METHOD(CAMCDoc, OnNewDocument);
|
|
|
|
USES_CONVERSION;
|
|
|
|
// Initialize the document and scope view ...
|
|
if (!CDocument::OnNewDocument())
|
|
return FALSE;
|
|
|
|
// A new file can't be read-only
|
|
SetPhysicalReadOnlyFlag (false);
|
|
|
|
// use latest file version
|
|
m_ConsoleData.m_eFileVer = FileVer_Current;
|
|
ASSERT (IsValidFileVersion (m_ConsoleData.m_eFileVer));
|
|
|
|
// Init help doc info times to current time by default
|
|
// Will update when file is first saved
|
|
::GetSystemTimeAsFileTime(&GetHelpDocInfo()->m_ftimeCreate);
|
|
GetHelpDocInfo()->m_ftimeModify = GetHelpDocInfo()->m_ftimeCreate;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CAMCDoc diagnostics
|
|
|
|
#ifdef _DEBUG
|
|
void CAMCDoc::AssertValid() const
|
|
{
|
|
CDocument::AssertValid();
|
|
}
|
|
|
|
void CAMCDoc::Dump(CDumpContext& dc) const
|
|
{
|
|
CDocument::Dump(dc);
|
|
}
|
|
#endif //_DEBUG
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CAMCDoc commands
|
|
inline bool UnableToSaveDocument()
|
|
{
|
|
if (AMCGetApp()->GetMode() == eMode_Author)
|
|
MMCMessageBox(IDS_UnableToSaveDocumentMessage);
|
|
|
|
return false;
|
|
}
|
|
|
|
static const wchar_t* AMCViewDataStreamName = L"ViewData";
|
|
static const wchar_t* AMCFrameDataStreamName = L"FrameData";
|
|
static const wchar_t* AMCStringTableStorageName = L"String Table";
|
|
static const wchar_t* AMCFavoritesStreamName = L"FavoritesStream";
|
|
static const wchar_t* AMCCustomTitleStreamName = L"Title";
|
|
static const wchar_t* AMCColumnDataStreamName = L"ColumnData";
|
|
static const wchar_t* AMCViewSettingDataStreamName = L"ViewSettingData"; // View settings data stream
|
|
|
|
#pragma warning( disable : 4800 )
|
|
|
|
struct FrameState
|
|
{
|
|
WINDOWPLACEMENT windowPlacement;
|
|
BOOL fShowStatusBarInUserMode;
|
|
BOOL fShowToolbarInAuthorMode;
|
|
}; // struct FrameState
|
|
|
|
|
|
struct FrameState2
|
|
{
|
|
UINT cbSize;
|
|
WINDOWPLACEMENT wndplFrame;
|
|
ProgramMode eMode;
|
|
DWORD dwFlags;
|
|
// NOT USED - SIZE PRESERVED FOR COMPATIBILITY
|
|
// DWORD dwHelpDocIndex;
|
|
// DWORD dwHelpDocTime[2];
|
|
DWORD dwUnused;
|
|
DWORD dwUnused2[2];
|
|
|
|
FrameState2 (ProgramMode eMode_ = eMode_Author,
|
|
DWORD dwFlags_ = eFlag_Default) :
|
|
cbSize (sizeof (FrameState2)),
|
|
eMode (eMode_),
|
|
dwFlags (dwFlags_),
|
|
// NOT USED - SIZE PRESERVED FOR COMPATIBILITY
|
|
dwUnused(0)
|
|
// dwHelpDocIndex (0)
|
|
{
|
|
// NOT USED - SIZE PRESERVED FOR COMPATIBILITY
|
|
// ZeroMemory (dwHelpDocTime, sizeof (dwHelpDocTime));
|
|
ZeroMemory (&dwUnused2, sizeof (dwUnused2));
|
|
|
|
ZeroMemory (&wndplFrame, sizeof (wndplFrame));
|
|
wndplFrame.length = sizeof (wndplFrame);
|
|
}
|
|
|
|
}; // struct FrameState2
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* CFrameState
|
|
*
|
|
* class is designated to be used instead of FrameState2 in Persist methods.
|
|
* It implements functionality of CXMLObject while containing the same data as FrameState2
|
|
* The original struct cannot be extended because many methods do relay on its size.
|
|
*
|
|
*--------------------------------------------------------------------------*/
|
|
class CFrameState : public CXMLObject, public FrameState2
|
|
{
|
|
public:
|
|
CFrameState(ProgramMode eMode_, DWORD dwFlags_) : FrameState2 (eMode_,dwFlags_) {}
|
|
protected:
|
|
DEFINE_XML_TYPE (XML_TAG_FRAME_STATE);
|
|
virtual void Persist(CPersistor &persistor)
|
|
{
|
|
persistor.Persist(CXMLWindowPlacement(wndplFrame));
|
|
|
|
// define the table to map enumeration values to strings
|
|
static const EnumLiteral frameStateFlags[] =
|
|
{
|
|
{ eFlag_ShowStatusBar, XML_ENUM_FSTATE_SHOWSTATUSBAR },
|
|
{ eFlag_HelpDocInvalid, XML_ENUM_FSTATE_HELPDOCINVALID },
|
|
{ eFlag_LogicalReadOnly, XML_ENUM_FSTATE_LOGICALREADONLY },
|
|
{ eFlag_PreventViewCustomization, XML_ENUM_FSTATE_PREVENTVIEWCUSTOMIZATION },
|
|
};
|
|
|
|
// create wrapper to persist enumeration values as strings
|
|
CXMLBitFlags flagPersistor(dwFlags, frameStateFlags, countof(frameStateFlags));
|
|
// persist the wrapper
|
|
persistor.PersistAttribute(XML_ATTR_FRAME_STATE_FLAGS, flagPersistor);
|
|
}
|
|
};
|
|
|
|
// what is the size of the Version 1.1 definition of FrameState2?
|
|
const int cbFrameState2_v11 = SIZEOF_STRUCT (FrameState2, dwUnused2 /*dwHelpDocTime*/ );
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* AdjustRect
|
|
*
|
|
* Adjusts pInnerRect so that it is completely contained within pOuterRect
|
|
*
|
|
* If AR_MOVE is specified, the origin of pInnerRect is moved enough (if
|
|
* necessary) so that the right and/or bottom edges of pInnerRect coincide
|
|
* with those of pOuterRect. pInnerRect's origin is never moved above or to
|
|
* the left of pOuterRect's origin.
|
|
*
|
|
* If AR_SIZE is specified, the right and/or bottom edges of pInnerRect are
|
|
* moved to that they coincide with those of pOuterRect.
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
#define AR_MOVE 0x0000001
|
|
#define AR_SIZE 0x0000002
|
|
|
|
void AdjustRect (LPCRECT pOuterRect, LPRECT pInnerRect, DWORD dwFlags)
|
|
{
|
|
/*
|
|
* if the inner rectangle is completely within
|
|
* the outer, there's nothing to do
|
|
*/
|
|
if ((pInnerRect->left >= pOuterRect->left ) &&
|
|
(pInnerRect->right <= pOuterRect->right ) &&
|
|
(pInnerRect->top >= pOuterRect->top ) &&
|
|
(pInnerRect->bottom <= pOuterRect->bottom))
|
|
return;
|
|
|
|
|
|
/*
|
|
* handle movement
|
|
*/
|
|
if (dwFlags & AR_MOVE)
|
|
{
|
|
int dx = 0;
|
|
|
|
/*
|
|
* shift inner rect right?
|
|
*/
|
|
if (pInnerRect->left < pOuterRect->left)
|
|
dx = pOuterRect->left - pInnerRect->left;
|
|
|
|
/*
|
|
* shift inner rect left? (make sure we don't shift it past the
|
|
* left of the outer rect)
|
|
*/
|
|
else if (pInnerRect->right > pOuterRect->right)
|
|
dx = std::_MAX (pOuterRect->right - pInnerRect->right,
|
|
pOuterRect->left - pInnerRect->left);
|
|
|
|
|
|
/*
|
|
* make sure things are right in the vertical
|
|
*/
|
|
int dy = 0;
|
|
|
|
/*
|
|
* shift inner rect down?
|
|
*/
|
|
if (pInnerRect->top < pOuterRect->top)
|
|
dy = pOuterRect->top - pInnerRect->top;
|
|
|
|
/*
|
|
* shift inner rect up? (make sure we don't shift it past the
|
|
* top of the outer rect)
|
|
*/
|
|
else if (pInnerRect->bottom > pOuterRect->bottom)
|
|
dy = std::_MAX (pOuterRect->bottom - pInnerRect->bottom,
|
|
pOuterRect->top - pInnerRect->top);
|
|
|
|
|
|
/*
|
|
* if we need to shift the inner rect, do it now
|
|
*/
|
|
if ((dx != 0) || (dy != 0))
|
|
{
|
|
ASSERT (dwFlags & AR_MOVE);
|
|
OffsetRect (pInnerRect, dx, dy);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* handle sizing
|
|
*/
|
|
if (dwFlags & AR_SIZE)
|
|
{
|
|
if (pInnerRect->right > pOuterRect->right)
|
|
pInnerRect->right = pOuterRect->right;
|
|
|
|
if (pInnerRect->bottom > pOuterRect->bottom)
|
|
pInnerRect->bottom = pOuterRect->bottom;
|
|
}
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* InsurePlacementIsOnScreen
|
|
*
|
|
* This function insures that the window will appear on the virtual screen,
|
|
* and if the whole window can't be located there, that at least the most
|
|
* interesting part is visible.
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
void InsurePlacementIsOnScreen (WINDOWPLACEMENT& wndpl)
|
|
{
|
|
/*
|
|
* find the monitor containing the window origin
|
|
*/
|
|
HMONITOR hmon = MonitorFromPoint (CPoint (wndpl.rcNormalPosition.left,
|
|
wndpl.rcNormalPosition.top),
|
|
MONITOR_DEFAULTTONEAREST);
|
|
|
|
MONITORINFO mi = { sizeof (mi) };
|
|
CRect rectBounds;
|
|
|
|
/*
|
|
* if we could get the info for the monitor containing the window origin,
|
|
* use it's workarea as the bounding rectangle; otherwise get the workarea
|
|
* for the default monitor; if that failed as well, default to 640x480
|
|
*/
|
|
if (GetMonitorInfo (hmon, &mi))
|
|
rectBounds = mi.rcWork;
|
|
else if (!SystemParametersInfo (SPI_GETWORKAREA, 0, &rectBounds, false))
|
|
rectBounds.SetRect (0, 0, 639, 479);
|
|
|
|
/*
|
|
* position the window rectangle within the bounding rectangle
|
|
*/
|
|
AdjustRect (rectBounds, &wndpl.rcNormalPosition, AR_MOVE | AR_SIZE);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: LoadFrame
|
|
//
|
|
// Synopsis: Load the Frame Data.
|
|
//
|
|
// Note: The app mode was already read by LoadAppMode.
|
|
// The child frames are created so call UpdateFrameWindow.
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: bool. TRUE if success.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
bool CAMCDoc::LoadFrame()
|
|
// The caller is resposible for calling DeleteContents() and display a message
|
|
// to the user when this function return false.
|
|
{
|
|
TRACE_METHOD(CAMCDoc, LoadFrame);
|
|
|
|
// This assertion shouldn't fail until the definition of FrameState2 changes
|
|
// in a version after 1.1. At that time, add another cbFrameState2_vXX
|
|
// with the new version's FrameState2 size.
|
|
ASSERT (cbFrameState2_v11 == sizeof (FrameState2));
|
|
|
|
if (!AssertNodeManagerIsLoaded())
|
|
return false;
|
|
|
|
// Open the stream containing data for the app and frame
|
|
IStreamPtr spStream;
|
|
HRESULT hr;
|
|
|
|
hr = OpenDebugStream (m_spStorage, AMCFrameDataStreamName,
|
|
STGM_SHARE_EXCLUSIVE | STGM_READ,
|
|
&spStream);
|
|
|
|
ASSERT(SUCCEEDED(hr) && spStream != NULL);
|
|
if (FAILED(hr))
|
|
return false;
|
|
|
|
|
|
FrameState2 fs2;
|
|
ULONG cbRead;
|
|
ASSERT (IsValidFileVersion (m_ConsoleData.m_eFileVer));
|
|
|
|
// V1.0 file? Migrate it forward
|
|
if (m_ConsoleData.m_eFileVer == FileVer_0100)
|
|
{
|
|
FrameState fs;
|
|
hr = spStream->Read (&fs, sizeof(fs), &cbRead);
|
|
|
|
// if we can't read the FrameState, the file is corrupt
|
|
if (FAILED(hr) || (cbRead != sizeof(fs)))
|
|
return (false);
|
|
|
|
// migrate FrameState into FrameState2
|
|
fs2.wndplFrame = fs.windowPlacement;
|
|
|
|
if (fs.fShowStatusBarInUserMode)
|
|
fs2.dwFlags |= eFlag_ShowStatusBar;
|
|
else
|
|
fs2.dwFlags &= ~eFlag_ShowStatusBar;
|
|
}
|
|
|
|
// otherwise, current file
|
|
else
|
|
{
|
|
hr = spStream->Read (&fs2, sizeof(fs2), &cbRead);
|
|
|
|
// if we can't read the rest of the FrameState, the file is corrupt
|
|
if (FAILED(hr) || (cbRead != sizeof(fs2)))
|
|
return (false);
|
|
}
|
|
|
|
|
|
// Set the windows size and location and state
|
|
CMainFrame* pMainFrame = AMCGetMainWnd ();
|
|
ASSERT(pMainFrame != NULL);
|
|
if (pMainFrame == NULL)
|
|
return false;
|
|
|
|
|
|
CAMCApp* pApp = AMCGetApp();
|
|
pApp->UpdateFrameWindow(true);
|
|
pMainFrame->UpdateChildSystemMenus();
|
|
|
|
// the status bar is on the child frame now
|
|
// pMainFrame->ShowStatusBar ((fs2.dwFlags & eFlag_ShowStatusBar) != 0);
|
|
|
|
|
|
// save the data from the file into the console data
|
|
m_ConsoleData.m_eAppMode = pApp->GetMode();
|
|
m_ConsoleData.m_eConsoleMode = fs2.eMode;
|
|
m_ConsoleData.m_dwFlags = fs2.dwFlags;
|
|
|
|
InsurePlacementIsOnScreen (fs2.wndplFrame);
|
|
|
|
|
|
// if we're initializing, defer the actual show until initialization is complete
|
|
// same if script is under control and MMC is hidden
|
|
if (pApp->IsInitializing()
|
|
|| ( !pApp->IsUnderUserControl() && !pMainFrame->IsWindowVisible() ) )
|
|
{
|
|
pApp->m_nCmdShow = fs2.wndplFrame.showCmd;
|
|
fs2.wndplFrame.showCmd = SW_HIDE;
|
|
}
|
|
|
|
return (pMainFrame->SetWindowPlacement (&fs2.wndplFrame));
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: LoadAppMode
|
|
//
|
|
// Synopsis: Read the app mode from the frame and store it in CAMCApp.
|
|
// This is needed during CAMCView::Load.
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: bool. TRUE if success.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
bool CAMCDoc::LoadAppMode()
|
|
{
|
|
TRACE_METHOD(CAMCDoc, LoadAppMode);
|
|
|
|
// Just load the application mode from frame data.
|
|
// This assertion shouldn't fail until the definition of FrameState2 changes
|
|
// in a version after 1.1. At that time, add another cbFrameState2_vXX
|
|
// with the new version's FrameState2 size.
|
|
ASSERT (cbFrameState2_v11 == sizeof (FrameState2));
|
|
|
|
if (!AssertNodeManagerIsLoaded())
|
|
return false;
|
|
|
|
// Open the stream containing data for the app and frame
|
|
IStreamPtr spStream;
|
|
HRESULT hr;
|
|
|
|
hr = OpenDebugStream (m_spStorage, AMCFrameDataStreamName,
|
|
STGM_SHARE_EXCLUSIVE | STGM_READ,
|
|
&spStream);
|
|
|
|
ASSERT(SUCCEEDED(hr) && spStream != NULL);
|
|
if (FAILED(hr))
|
|
return false;
|
|
|
|
|
|
FrameState2 fs2;
|
|
ULONG cbRead;
|
|
ASSERT (IsValidFileVersion (m_ConsoleData.m_eFileVer));
|
|
|
|
// V1.0 file? Migrate it forward
|
|
if (m_ConsoleData.m_eFileVer == FileVer_0100)
|
|
{
|
|
FrameState fs;
|
|
hr = spStream->Read (&fs, sizeof(fs), &cbRead);
|
|
|
|
// if we can't read the FrameState, the file is corrupt
|
|
if (FAILED(hr) || (cbRead != sizeof(fs)))
|
|
return (false);
|
|
|
|
// migrate FrameState into FrameState2
|
|
fs2.wndplFrame = fs.windowPlacement;
|
|
|
|
if (fs.fShowStatusBarInUserMode)
|
|
fs2.dwFlags |= eFlag_ShowStatusBar;
|
|
else
|
|
fs2.dwFlags &= ~eFlag_ShowStatusBar;
|
|
}
|
|
|
|
// otherwise, current file
|
|
else
|
|
{
|
|
hr = spStream->Read (&fs2, sizeof(fs2), &cbRead);
|
|
|
|
// if we can't read the rest of the FrameState, the file is corrupt
|
|
if (FAILED(hr) || (cbRead != sizeof(fs2)))
|
|
return (false);
|
|
}
|
|
|
|
CAMCApp* pApp = AMCGetApp();
|
|
pApp->SetMode (fs2.eMode);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CAMCDoc::LoadViews()
|
|
// Caller is resposible for calling DeleteContents() and displaying failure
|
|
// message if false is returned.
|
|
{
|
|
TRACE_METHOD(CAMCDoc, LoadViews);
|
|
|
|
if (!AssertNodeManagerIsLoaded())
|
|
return false;
|
|
|
|
// Open the tree data stream
|
|
IStreamPtr spStream;
|
|
HRESULT hr = OpenDebugStream(m_spStorage, AMCViewDataStreamName,
|
|
STGM_SHARE_EXCLUSIVE | STGM_READ, &spStream);
|
|
|
|
ASSERT(SUCCEEDED(hr) && spStream != NULL);
|
|
if (FAILED(hr))
|
|
return false;
|
|
|
|
// Read the number of views persisted
|
|
unsigned short numberOfViews;
|
|
unsigned long bytesRead;
|
|
hr = spStream->Read(&numberOfViews, sizeof(numberOfViews), &bytesRead);
|
|
ASSERT(SUCCEEDED(hr) && bytesRead == sizeof(numberOfViews));
|
|
if (FAILED(hr) || bytesRead != sizeof(numberOfViews))
|
|
return false;
|
|
|
|
// Loop thru and create each view
|
|
int failedCount = 0;
|
|
while (numberOfViews--)
|
|
{
|
|
// Read the node id for the root node of the view being created.
|
|
m_MTNodeIDForNewView = 0;
|
|
bool bRet = m_spScopeTree->GetNodeIDFromStream(spStream, &m_MTNodeIDForNewView);
|
|
|
|
// Read the node id for the selected node of the view being created.
|
|
ULONG idSel = 0;
|
|
bRet = m_spScopeTree->GetNodeIDFromStream(spStream, &idSel);
|
|
|
|
// Read the view id of the view being created.
|
|
hr = spStream->Read(&m_ViewIDForNewView,
|
|
sizeof(m_ViewIDForNewView), &bytesRead);
|
|
ASSERT(SUCCEEDED(hr) && bytesRead == sizeof(m_ViewIDForNewView));
|
|
if (FAILED(hr) || bytesRead != sizeof(m_ViewIDForNewView))
|
|
return false;
|
|
|
|
if (bRet || m_MTNodeIDForNewView != 0)
|
|
{
|
|
// Create the new view and load its data
|
|
CAMCView* const v = CreateNewView(true);
|
|
m_ViewIDForNewView = 0;
|
|
ASSERT(v != NULL);
|
|
if (v == NULL)
|
|
{
|
|
++failedCount;
|
|
continue;
|
|
}
|
|
if (!v->Load(*spStream))
|
|
return false;
|
|
|
|
v->ScSelectNode(idSel);
|
|
v->SaveStartingSelectedNode();
|
|
v->SetDirty (false);
|
|
//v->GetHistoryList()->Clear();
|
|
}
|
|
}
|
|
|
|
// Reset the node ID for future view creation
|
|
m_MTNodeIDForNewView = ROOTNODEID;
|
|
|
|
SetModifiedFlag(FALSE);
|
|
return (failedCount == 0);
|
|
}
|
|
|
|
SC CAMCDoc::ScCreateAndLoadView(CPersistor& persistor, int nViewID, const CBookmark& rootNode)
|
|
// Caller is resposible for calling DeleteContents() and displaying failure
|
|
// message if false is returned.
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::ScCreateAndLoadView"));
|
|
|
|
// Read the node id for the root node of the view being created.
|
|
m_MTNodeIDForNewView = 0;
|
|
|
|
MTNODEID idTemp = 0;
|
|
bool bExactMatchFound = false; // out value from GetNodeIDFromBookmark, unused
|
|
sc = m_spScopeTree->GetNodeIDFromBookmark(rootNode, &idTemp, bExactMatchFound);
|
|
if(sc)
|
|
return sc;
|
|
|
|
m_MTNodeIDForNewView = idTemp;
|
|
|
|
if (m_MTNodeIDForNewView != 0)
|
|
{
|
|
// Read the view id of the view being created.
|
|
m_ViewIDForNewView = nViewID;
|
|
// Create the new view and load its data
|
|
CAMCView* const v = CreateNewView(true);
|
|
m_ViewIDForNewView = 0;
|
|
|
|
sc = ScCheckPointers(v, E_FAIL);
|
|
if (sc)
|
|
return sc;
|
|
|
|
v->Persist(persistor);
|
|
|
|
v->SaveStartingSelectedNode();
|
|
v->SetDirty (false);
|
|
//v->GetHistoryList()->Clear();
|
|
}
|
|
else
|
|
{
|
|
return sc = SC(E_UNEXPECTED);
|
|
}
|
|
|
|
// Reset the node ID for future view creation
|
|
m_MTNodeIDForNewView = ROOTNODEID;
|
|
SetModifiedFlag(FALSE);
|
|
return sc;
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* ShowIncompatibleFileMessage
|
|
*
|
|
*
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
static void ShowIncompatibleFileMessage (
|
|
LPCTSTR pszFilename,
|
|
ConsoleFileVersion eFileVer)
|
|
{
|
|
DECLARE_SC(sc, TEXT("ShowIncompatibleFileMessage"));
|
|
TCHAR szFileVersion[16];
|
|
|
|
sc = StringCchPrintf(szFileVersion, countof(szFileVersion),
|
|
_T("%d.%d%x"), GetConsoleFileMajorVersion (eFileVer),
|
|
GetConsoleFileMinorVersion (eFileVer),
|
|
GetConsoleFileMinorSubversion (eFileVer));
|
|
// Display error and show incompatible error.
|
|
if (sc)
|
|
sc.TraceAndClear();
|
|
|
|
CString strMessage;
|
|
FormatString2 (strMessage, IDS_NewerVersionRequired, pszFilename, szFileVersion);
|
|
|
|
MMCMessageBox (strMessage);
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* CAMCDoc::OnOpenDocument
|
|
*
|
|
* WM_OPENDOCUMENT handler for CAMCDoc.
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
BOOL CAMCDoc::OnOpenDocument(LPCTSTR lpszPathName)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::OnOpenDocument"));
|
|
|
|
sc = ScOnOpenDocument(lpszPathName);
|
|
if(sc) // found an error
|
|
{
|
|
DisplayFileOpenError (sc, lpszPathName);
|
|
return false;
|
|
}
|
|
|
|
sc = ScFireEvent(CAMCDocumentObserver::ScDocumentLoadCompleted, this);
|
|
if (sc)
|
|
return false;
|
|
|
|
/*
|
|
* Success! We shouldn't think that a freshly opened console file is
|
|
* dirty. If we do, someone's dirty bit processing is bogus.
|
|
*/
|
|
ASSERT (!IsFrameModified());
|
|
|
|
/*
|
|
* Too many snap-ins leave themselves dirty after a load to leave this
|
|
* assert in, so we'll trace instead. Note that this trace doesn't
|
|
* always indicate a snap-in problem, but it frequently does.
|
|
*/
|
|
#ifdef DBG
|
|
// ASSERT (!IsModified());
|
|
if (IsModified())
|
|
TraceErrorMsg (_T("CAMCDoc::IsModified returns true after opening"));
|
|
#endif
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* DisplayFileOpenError
|
|
*
|
|
* Displays an error message if we couldn't open a console file.
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
int DisplayFileOpenError (SC sc, LPCTSTR pszFilename)
|
|
{
|
|
// if it is any of the known errors, use a friendly string.
|
|
|
|
if (sc == SC(STG_E_FILENOTFOUND) || sc == ScFromWin32(ERROR_FILE_NOT_FOUND))
|
|
(sc = ScFromMMC(IDS_FileNotFound));
|
|
else if (sc == ScFromMMC(MMC_E_INVALID_FILE))
|
|
(sc = ScFromMMC(IDS_InvalidVersion));
|
|
else if (sc == SC(STG_E_MEDIUMFULL))
|
|
(sc = ScFromMMC(IDS_DiskFull));
|
|
else
|
|
{
|
|
CString strError;
|
|
AfxFormatString1(strError, IDS_UnableToOpenDocumentMessage, pszFilename);
|
|
return (MMCErrorBox(strError));
|
|
}
|
|
|
|
return (MMCErrorBox(sc));
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* ScGetFileProperties
|
|
*
|
|
* Returns the read-only state of the given file, as well as the creation,
|
|
* last access, and last write times (all optional).
|
|
*
|
|
* We determine if the file is read-only by trying to open the file for
|
|
* writing rather than checking for FILE_ATTRIBUTE_READONLY. We do this
|
|
* because it will catch more read-only conditions, like the file living
|
|
* on a read-only share or NTFS permissions preventing a write.
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
static SC ScGetFileProperties (
|
|
LPCTSTR lpszPathName, /* I:name of file to check */
|
|
bool* pfReadOnly, /* O:is file read-only? */
|
|
FILETIME* pftCreate, /* O:creation time (optional) */
|
|
FILETIME* pftLastAccess, /* O:last access time (optional) */
|
|
FILETIME* pftLastWrite) /* O:last write time (optional) */
|
|
{
|
|
DECLARE_SC (sc, _T("ScGetFileProperties"));
|
|
|
|
/*
|
|
* validate inputs (pftCreate, pftLastAccess, and pftLastWrite are optional)
|
|
*/
|
|
sc = ScCheckPointers (lpszPathName, pfReadOnly);
|
|
if (sc)
|
|
return (sc);
|
|
|
|
/*
|
|
* try to open the file for write; if we can't, the file is read-only
|
|
*/
|
|
HANDLE hFile = CreateFile (lpszPathName, GENERIC_WRITE, 0, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
*pfReadOnly = (hFile == INVALID_HANDLE_VALUE);
|
|
|
|
/*
|
|
* if read-only then open in read mode so we'll have a handle to pass
|
|
* to GetFileTime
|
|
*/
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
hFile = CreateFile (lpszPathName, 0, 0, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
sc.FromLastError();
|
|
return (sc);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* get the timestamps on the file
|
|
*/
|
|
if (!GetFileTime (hFile, pftCreate, pftLastAccess, pftLastWrite))
|
|
sc.FromLastError();
|
|
|
|
CloseHandle (hFile);
|
|
return (sc);
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CAMCDoc::ScOnOpenDocument
|
|
*
|
|
* PURPOSE: Opens the specified document.
|
|
*
|
|
* PARAMETERS:
|
|
* LPCTSTR lpszPathName :
|
|
*
|
|
* RETURNS:
|
|
* SC
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CAMCDoc::ScOnOpenDocument(LPCTSTR lpszPathName)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::ScOnOpenDocument"));
|
|
|
|
// lock AppEvents until this function is done
|
|
LockComEventInterface(AppEvents);
|
|
|
|
#define VIVEKJ
|
|
#ifdef VIVEKJ
|
|
|
|
// upgrade the console file to the XML version.
|
|
CConsoleFile consoleFile;
|
|
consoleFile.ScUpgrade(lpszPathName);
|
|
#endif
|
|
|
|
|
|
USES_CONVERSION;
|
|
|
|
// check inputs
|
|
if (lpszPathName == NULL || *lpszPathName == 0)
|
|
return (sc = E_UNEXPECTED);
|
|
|
|
if (IsModified())
|
|
{
|
|
TRACE0("Warning: OnOpenDocument replaces an unsaved document.\n");
|
|
}
|
|
|
|
if (!AssertNodeManagerIsInitialized())
|
|
return (sc = E_UNEXPECTED);
|
|
|
|
/*
|
|
* get the times for the file, as well as its read-only state
|
|
*/
|
|
HELPDOCINFO* phdi = GetHelpDocInfo();
|
|
sc = ScCheckPointers (phdi, E_UNEXPECTED);
|
|
if (sc)
|
|
return (sc);
|
|
|
|
bool fReadOnly;
|
|
sc = ScGetFileProperties (lpszPathName, &fReadOnly,
|
|
&phdi->m_ftimeCreate, NULL, &phdi->m_ftimeModify);
|
|
if (sc)
|
|
return (sc);
|
|
|
|
// load the document using method from the base class (CConsoleFilePersistor)
|
|
bool bXmlBased = false;
|
|
CXMLDocument xmlDocument;
|
|
IStoragePtr spStorage;
|
|
sc = ScLoadConsole(lpszPathName, bXmlBased, xmlDocument, &spStorage);
|
|
if (sc)
|
|
return (sc);
|
|
|
|
if ( bXmlBased )
|
|
{
|
|
// load as XML document
|
|
sc = ScLoadFromDocument(xmlDocument);
|
|
if(sc)
|
|
return sc;
|
|
}
|
|
else
|
|
{
|
|
sc = ScCheckPointers(m_spScopeTree, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// get the console file's version
|
|
ASSERT (sizeof(m_ConsoleData.m_eFileVer) == sizeof(int));
|
|
sc = m_spScopeTree->GetFileVersion(spStorage, (int*)&m_ConsoleData.m_eFileVer);
|
|
if (sc)
|
|
return sc;
|
|
|
|
/*
|
|
* check to see if this file is from a newer MMC
|
|
*/
|
|
if (m_ConsoleData.m_eFileVer > FileVer_Current)
|
|
{
|
|
ShowIncompatibleFileMessage (lpszPathName, m_ConsoleData.m_eFileVer);
|
|
return (sc = E_UNEXPECTED);
|
|
}
|
|
|
|
// Previous storage should have been closed and released
|
|
ASSERT(m_spStorage == NULL);
|
|
|
|
/*
|
|
* Load the string table.
|
|
*/
|
|
if (!LoadStringTable (spStorage))
|
|
return (sc = E_UNEXPECTED);
|
|
|
|
// Load column settings.
|
|
do
|
|
{
|
|
IStreamPtr spStream;
|
|
sc = OpenDebugStream (spStorage, AMCColumnDataStreamName,
|
|
STGM_SHARE_EXCLUSIVE | STGM_READ,
|
|
&spStream);
|
|
if(sc)
|
|
break;
|
|
|
|
if (NULL != m_ConsoleData.m_spPersistStreamColumnData)
|
|
sc = m_ConsoleData.m_spPersistStreamColumnData->Load(spStream);
|
|
|
|
ASSERT(NULL != m_ConsoleData.m_spPersistStreamColumnData);
|
|
|
|
if (sc.IsError() || (NULL == m_ConsoleData.m_spPersistStreamColumnData) )
|
|
return (sc = E_UNEXPECTED);
|
|
|
|
} while ( FALSE );
|
|
|
|
// Load view settings.
|
|
do
|
|
{
|
|
IStreamPtr spStream;
|
|
sc = OpenDebugStream (spStorage, AMCViewSettingDataStreamName,
|
|
STGM_SHARE_EXCLUSIVE | STGM_READ,
|
|
&spStream);
|
|
|
|
if (sc)
|
|
break;
|
|
|
|
IPersistStreamPtr spIPeristStreamViewSettings;
|
|
SC sc = ScGetViewSettingsPersistorStream(&spIPeristStreamViewSettings);
|
|
if (sc)
|
|
break;
|
|
|
|
sc = ScCheckPointers(spIPeristStreamViewSettings, E_UNEXPECTED);
|
|
if (sc)
|
|
break;
|
|
|
|
sc = spIPeristStreamViewSettings->Load(spStream);
|
|
if (sc)
|
|
break;
|
|
|
|
} while ( FALSE );
|
|
|
|
|
|
// Load the tree
|
|
sc = m_spScopeTreePersist->Load(spStorage);
|
|
if (sc)
|
|
{
|
|
ReleaseNodeManager();
|
|
return sc;
|
|
}
|
|
|
|
// Save the new storage
|
|
m_spStorage = spStorage;
|
|
|
|
/*
|
|
* make sure the tree expansion happens synchronously
|
|
*/
|
|
bool fSyncExpandWasRequired = m_spScopeTree->IsSynchronousExpansionRequired() == S_OK;
|
|
m_spScopeTree->RequireSynchronousExpansion (true);
|
|
|
|
// Load the favorites data before loading views and frames,
|
|
// so that when frame/view is created the favorite data is ready.
|
|
if (!LoadFavorites())
|
|
{
|
|
// bhanlon ReleaseNodeManager();
|
|
m_spScopeTree->RequireSynchronousExpansion (fSyncExpandWasRequired);
|
|
return (sc = E_UNEXPECTED);
|
|
}
|
|
|
|
|
|
/*
|
|
* Load string table, custom data, views and frame. Load the
|
|
* custom data (including the icon) before loading the views so
|
|
* the proper icon will be used for the views as they're created.
|
|
*/
|
|
/*
|
|
* The LoadAppMode, LoadViews and LoadFrame should be called in that
|
|
* order due to following reason.
|
|
* LoadAppMode reads mode from frame-data and saves it in CAMCApp.
|
|
* The mode is used during LoadViews (in CAMCView::Load) to set the view.
|
|
* LoadFrame again reads the frame-data and calls CAMCApp::UpdateFrameWindow
|
|
* to set toolbar/menus according to the mode.
|
|
*/
|
|
if (!LoadCustomData (m_spStorage) || !LoadAppMode() || !LoadViews() || !LoadFrame())
|
|
{
|
|
// bhanlon ReleaseNodeManager();
|
|
m_spScopeTree->RequireSynchronousExpansion (fSyncExpandWasRequired);
|
|
return (sc = E_UNEXPECTED);
|
|
}
|
|
|
|
m_spScopeTree->RequireSynchronousExpansion (fSyncExpandWasRequired);
|
|
}
|
|
|
|
SetModifiedFlag (false);
|
|
SetFrameModifiedFlag (false);
|
|
|
|
SetPhysicalReadOnlyFlag (fReadOnly);
|
|
|
|
ASSERT (IsValidFileVersion (m_ConsoleData.m_eFileVer));
|
|
return sc;
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* CAMCDoc::OnSaveDocument
|
|
*
|
|
* WM_SAVEDOCUMENT handler for CAMCDoc.
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
BOOL CAMCDoc::OnSaveDocument(LPCTSTR lpszFilename)
|
|
{
|
|
DECLARE_SC(sc, _T("CAMCDoc::OnSaveDocument"));
|
|
|
|
USES_CONVERSION;
|
|
|
|
m_eSaveStatus = eStat_Succeeded;
|
|
|
|
// Check for a valid filename
|
|
ASSERT(lpszFilename != NULL && *lpszFilename != 0);
|
|
if (lpszFilename == NULL || *lpszFilename == 0)
|
|
{
|
|
return UnableToSaveDocument();
|
|
}
|
|
|
|
// Ask the each view to save any data into its data
|
|
// structures (memory) before calling IPersist*::Save.
|
|
CAMCViewPosition pos = GetFirstAMCViewPosition();
|
|
while (pos != NULL)
|
|
{
|
|
CAMCView* const pAMCView = GetNextAMCView(pos);
|
|
sc = ScCheckPointers(pAMCView, E_UNEXPECTED);
|
|
if (sc)
|
|
return UnableToSaveDocument();
|
|
}
|
|
|
|
if (!IsCurrentFileVersion (m_ConsoleData.m_eFileVer))
|
|
{
|
|
// If we've arrived at this point then the user is attempting to save the file
|
|
// from an old format into a new one and we will check to see if the user really
|
|
// wants to do this.
|
|
|
|
CString strMessage;
|
|
|
|
LPCTSTR pszPathName = m_strPathName;
|
|
|
|
// A YES/NO/(CANCEL) dialog asking if the user wants to save the file in the new format
|
|
int nResult;
|
|
|
|
/*
|
|
* Bug 277586: we don't ever want non-authors to see this dialog
|
|
*/
|
|
if (AMCGetApp()->GetMode() != eMode_Author)
|
|
{
|
|
// non-authors are only saving console settings,
|
|
// which are always in the current version
|
|
// no need to ask for conversion - original console is not converted anyway.
|
|
nResult = IDYES;
|
|
}
|
|
else if (IsExplicitSave())
|
|
{
|
|
// 2 button YES/NO dialog appears if this is an explicit save
|
|
tstring strVersion = GetCurrentFileVersionAsString();
|
|
FormatString2 (strMessage, IDS_CONVERT_FILE_FORMAT,
|
|
pszPathName, strVersion.c_str());
|
|
|
|
nResult = MMCMessageBox (strMessage, MB_YESNO | MB_DEFBUTTON2);
|
|
}
|
|
else
|
|
{
|
|
// 3 button YES/NO/CANCEL appears if this dialog appears when the program
|
|
// prompts to save changes when the user closes the document
|
|
tstring strVersion = GetCurrentFileVersionAsString();
|
|
FormatString2 (strMessage, IDS_CONVERT_FILE_FORMAT_CLOSE,
|
|
pszPathName, strVersion.c_str());
|
|
|
|
nResult = MMCMessageBox (strMessage, MB_YESNOCANCEL | MB_DEFBUTTON3);
|
|
}
|
|
|
|
// If we cancel out
|
|
if ((nResult == IDCANCEL) || ((nResult == IDNO) && IsExplicitSave()))
|
|
{
|
|
// Must set this variable otherwise MMC will delete the file
|
|
m_eSaveStatus = eStat_Cancelled;
|
|
return (false);
|
|
}
|
|
|
|
// If this will result in us exiting without saving
|
|
if ((nResult == IDNO) && !IsExplicitSave())
|
|
return (true);
|
|
}
|
|
|
|
// if we have more than one view, and we'll force SDI in user mode, prompt
|
|
if ((GetNumberOfPersistedViews() > 1) &&
|
|
(m_ConsoleData.m_eConsoleMode == eMode_User_SDI) &&
|
|
(AMCGetApp()->GetMode() == eMode_Author))
|
|
{
|
|
switch (MMCMessageBox (IDS_FORCE_SDI_PROMPT, MB_YESNOCANCEL))
|
|
{
|
|
case IDYES:
|
|
/* do nothing */
|
|
break;
|
|
|
|
case IDNO:
|
|
m_ConsoleData.m_eConsoleMode = eMode_User_MDI;
|
|
break;
|
|
|
|
case IDCANCEL:
|
|
m_eSaveStatus = eStat_Cancelled;
|
|
return (false);
|
|
}
|
|
}
|
|
|
|
// save contents to xml document
|
|
CXMLDocument xmlDocument;
|
|
sc = ScSaveToDocument( xmlDocument );
|
|
if (sc)
|
|
return UnableToSaveDocument();
|
|
|
|
// save xml document to file
|
|
bool bAuthor = (AMCGetApp()->GetMode() == eMode_Author);
|
|
sc = ScSaveConsole( lpszFilename, bAuthor, xmlDocument);
|
|
if (sc)
|
|
return UnableToSaveDocument();
|
|
|
|
SetModifiedFlag (false);
|
|
SetFrameModifiedFlag (false);
|
|
|
|
/*
|
|
* We shouldn't think that a freshly saved console file is
|
|
* dirty. If we do, someone's dirty bit processing is bogus.
|
|
*/
|
|
ASSERT (!IsFrameModified());
|
|
|
|
/*
|
|
* Too many snap-ins leave themselves dirty after a load to leave this
|
|
* assert in, so we'll trace instead. Note that this trace doesn't
|
|
* always indicate a snap-in problem, but it frequently does.
|
|
*/
|
|
#ifdef DBG
|
|
// ASSERT (!IsModified());
|
|
if (IsModified())
|
|
TraceErrorMsg (_T("CAMCDoc::IsModified returns true after saving"));
|
|
#endif
|
|
|
|
// if a save was just done, this can't be read-only
|
|
|
|
// NOTE: if MMC adds support for "Save Copy As" we have
|
|
// to determine whether a "Save As" or "Save Copy As"
|
|
// was done before clearing the read-only status
|
|
SetPhysicalReadOnlyFlag (false);
|
|
m_ConsoleData.m_eFileVer = FileVer_Current;
|
|
|
|
// Show admin tools on start menu if necessary
|
|
ShowAdminToolsOnMenu(lpszFilename);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
int CAMCDoc::GetNumberOfViews()
|
|
{
|
|
TRACE_METHOD(CAMCDoc, GetNumberOfViews);
|
|
|
|
CAMCViewPosition pos = GetFirstAMCViewPosition();
|
|
int count = 0;
|
|
|
|
while (pos != NULL)
|
|
{
|
|
GetNextAMCView(pos);
|
|
VERIFY (++count);
|
|
}
|
|
|
|
return (count);
|
|
}
|
|
|
|
|
|
int CAMCDoc::GetNumberOfPersistedViews()
|
|
{
|
|
unsigned short cPersistedViews = 0;
|
|
|
|
CAMCViewPosition pos = GetFirstAMCViewPosition();
|
|
|
|
while (pos != NULL)
|
|
{
|
|
CAMCView* v = GetNextAMCView(pos);
|
|
|
|
if (v && v->IsPersisted())
|
|
++cPersistedViews;
|
|
}
|
|
|
|
return (cPersistedViews);
|
|
}
|
|
|
|
|
|
CAMCView* CAMCDoc::CreateNewView(bool fVisible, bool bEmitScriptEvents /*= true*/)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::CreateNewView"));
|
|
TRACE_FUNCTION(CAMCDoc::CreateNewView);
|
|
|
|
CDocTemplate* pTemplate = GetDocTemplate();
|
|
ASSERT(pTemplate != NULL);
|
|
|
|
CChildFrame* pFrame = (CChildFrame*) pTemplate->CreateNewFrame(this, NULL);
|
|
ASSERT_KINDOF (CChildFrame, pFrame);
|
|
|
|
if (pFrame == NULL)
|
|
{
|
|
TRACE(_T("Warning: failed to create new frame.\n"));
|
|
return NULL; // command failed
|
|
}
|
|
|
|
bool fOldCreateVisibleState;
|
|
|
|
/*
|
|
* If we're going to create the frame invisibly, set a flag in the frame.
|
|
* When this flag is set, the frame will show itself with the
|
|
* SW_SHOWMINNOACTIVE flag instead of the default flag. Doing this will
|
|
* avoid the side effect of restoring the currently active child frame
|
|
* if it is maximized at the time the new frame is created invisibly.
|
|
*/
|
|
// The SW_SHOWMINNOACTIVE was changed to SW_SHOWNOACTIVATE.
|
|
// It does preserve the active window from mentioned side effect,
|
|
// plus it also allows scripts (using Object Moded) to create invisible views,
|
|
// position and then show them as normal (not minimized) windows,
|
|
// thus providing same result as creating visible and then hiding the view.
|
|
// While minimized window must be restored first in order to change their position.
|
|
if (!fVisible)
|
|
{
|
|
fOldCreateVisibleState = pFrame->SetCreateVisible (false);
|
|
}
|
|
|
|
/*
|
|
* update the frame as if it is to be visible; we'll hide the frame
|
|
* later if necessary
|
|
*/
|
|
// setting visibility to 'true' is required option for MFC to pass control
|
|
// to OnInitialUpdate of child windows.
|
|
pTemplate->InitialUpdateFrame (pFrame, this, true /*fVisible*/);
|
|
|
|
if (fVisible)
|
|
{
|
|
// Force drawing of frame and view windows now in case a slow OCX in the result
|
|
// pane delays the initial window update
|
|
pFrame->RedrawWindow();
|
|
}
|
|
else
|
|
{
|
|
pFrame->SetCreateVisible (fOldCreateVisibleState);
|
|
pFrame->ShowWindow (SW_HIDE);
|
|
|
|
/*
|
|
* InitialUpdateFrame will update the frame counts. When it executes
|
|
* the new, to-be-invisible frame will be visible, so it'll be included
|
|
* in the count. If the new window is the second frame, then the first
|
|
* frame will have "1:" prepended to its title. This is ugly, so we'll
|
|
* update the frame counts again after the new frame has been hidden
|
|
* to fix all of the existing frames' titles.
|
|
*/
|
|
UpdateFrameCounts();
|
|
}
|
|
|
|
CAMCView* const v = pFrame->GetAMCView();
|
|
|
|
if (!(MMC_NW_OPTION_NOPERSIST & GetNewWindowOptions()))
|
|
SetModifiedFlag();
|
|
|
|
ASSERT(v);
|
|
|
|
if (!v)
|
|
return v;
|
|
|
|
AddObserver(static_cast<CAMCDocumentObserver&>(*v));
|
|
|
|
// fire the event to the script
|
|
if (bEmitScriptEvents)
|
|
{
|
|
CAMCApp* pApp = AMCGetApp();
|
|
|
|
// check
|
|
sc = ScCheckPointers(pApp, E_UNEXPECTED);
|
|
if (sc)
|
|
return v;
|
|
|
|
// forward
|
|
sc = pApp->ScOnNewView(v);
|
|
if (sc)
|
|
return v;
|
|
}
|
|
|
|
return v;
|
|
}
|
|
|
|
|
|
void DeletePropertyPages(void)
|
|
{
|
|
HWND hWnd = NULL;
|
|
DWORD dwPid = 0; // Process Id
|
|
DWORD dwTid = 0; // Thread Id
|
|
|
|
while (TRUE)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
// Note: No need to localize this string
|
|
hWnd = ::FindWindowEx(NULL, hWnd, W2T( DATAWINDOW_CLASS_NAME ), NULL);
|
|
if (hWnd == NULL)
|
|
return; // No more windows
|
|
ASSERT(IsWindow(hWnd));
|
|
|
|
// Check if the window belongs to the current process
|
|
dwTid = ::GetWindowThreadProcessId(hWnd, &dwPid);
|
|
if (dwPid != ::GetCurrentProcessId())
|
|
continue;
|
|
|
|
DataWindowData* pData = GetDataWindowData (hWnd);
|
|
ASSERT (pData != NULL);
|
|
ASSERT (IsWindow (pData->hDlg));
|
|
|
|
if (SendMessage(pData->hDlg, WM_COMMAND, IDCANCEL, 0L) != 0)
|
|
{
|
|
DBG_OUT_LASTERROR;
|
|
}
|
|
|
|
// Note: For some reason, the send message stays stuck in the threads
|
|
// msg queue causing the sheet not to dismiss itself. By posting a another
|
|
// message( it could be anything), it kick starts the queue and the send message
|
|
// goes through.
|
|
::PostMessage(pData->hDlg, WM_COMMAND, IDCANCEL, 0L);
|
|
}
|
|
}
|
|
|
|
|
|
void CAMCDoc::DeleteContents()
|
|
{
|
|
TRACE_METHOD(CAMCDoc, DeleteContents);
|
|
|
|
CDocument::DeleteContents();
|
|
}
|
|
|
|
|
|
void CAMCDoc::DeleteHelpFile ()
|
|
{
|
|
/*
|
|
* Delete the help file on closing a console file
|
|
*/
|
|
|
|
// Get a node callback interface
|
|
ASSERT(m_spScopeTree != NULL);
|
|
// If this asserts - the document is in invalid state.
|
|
// Most probably it's because our "Load" procedures did not perform proper
|
|
// cleanup when we failed to load the document
|
|
INodeCallbackPtr spNodeCallback;
|
|
|
|
if (m_spScopeTree != NULL)
|
|
{
|
|
m_spScopeTree->QueryNodeCallback(&spNodeCallback);
|
|
ASSERT(spNodeCallback != NULL);
|
|
}
|
|
|
|
// fill in file name and send the delete request
|
|
|
|
if (spNodeCallback != NULL)
|
|
{
|
|
USES_CONVERSION;
|
|
GetHelpDocInfo()->m_pszFileName = T2COLE(GetPathName());
|
|
spNodeCallback->Notify(NULL, NCLBK_DELETEHELPDOC, (LPARAM)GetHelpDocInfo(), NULL);
|
|
}
|
|
}
|
|
|
|
|
|
void CAMCDoc::OnCloseDocument()
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::OnCloseDocument"));
|
|
|
|
TRACE_METHOD(CAMCDoc, OnCloseDocument);
|
|
|
|
// Inform nodemgr about doc-closing (should change this to observer object)
|
|
do
|
|
{
|
|
sc = ScCheckPointers(m_spScopeTree, E_UNEXPECTED);
|
|
if (sc)
|
|
break;
|
|
|
|
INodeCallbackPtr spNodeCallback;
|
|
sc = m_spScopeTree->QueryNodeCallback(&spNodeCallback);
|
|
if (sc)
|
|
break;
|
|
|
|
sc = ScCheckPointers(spNodeCallback, E_UNEXPECTED);
|
|
if (sc)
|
|
break;
|
|
|
|
sc = spNodeCallback->DocumentClosing();
|
|
if (sc)
|
|
break;
|
|
|
|
} while ( FALSE );
|
|
|
|
if (sc)
|
|
sc.TraceAndClear();
|
|
|
|
CAMCApp* pApp = AMCGetApp();
|
|
|
|
// check
|
|
sc = ScCheckPointers(pApp, E_UNEXPECTED);
|
|
if (sc)
|
|
sc.TraceAndClear();
|
|
else
|
|
{
|
|
// forward
|
|
sc = pApp->ScOnCloseDocument(this);
|
|
if (sc)
|
|
sc.TraceAndClear();
|
|
}
|
|
|
|
// If we are not instantiated as OLESERVER check for open property sheets.
|
|
if (! pApp->IsMMCRunningAsOLEServer() && FArePropertySheetsOpen(NULL))
|
|
{
|
|
CString strMsg, strTitle;
|
|
|
|
if (strMsg.LoadString(IDS_MMCWillCancelPropertySheets) &&
|
|
strTitle.LoadString(IDS_WARNING))
|
|
::MessageBox(NULL, strMsg, strTitle, MB_OK | MB_ICONWARNING);
|
|
}
|
|
|
|
DeletePropertyPages();
|
|
DeleteHelpFile ();
|
|
|
|
CDocument::OnCloseDocument();
|
|
}
|
|
|
|
|
|
BOOL CAMCDoc::SaveModified()
|
|
{
|
|
BOOL fDocModified = IsModified();
|
|
BOOL fFrameModified = IsFrameModified();
|
|
|
|
// if the file is not read-only and it is modified
|
|
if (!IsReadOnly() && (fDocModified || fFrameModified))
|
|
{
|
|
int idResponse;
|
|
bool fUserMode = (AMCGetApp()->GetMode() != eMode_Author);
|
|
bool fSaveByUserDecision = false;
|
|
|
|
// silent saves for the various flavors of user mode
|
|
if (fUserMode)
|
|
idResponse = IDYES;
|
|
|
|
// silent saves if the frame was modified but the document wasn't...
|
|
else if (fFrameModified && !fDocModified)
|
|
{
|
|
/*
|
|
* ...unless the console wasn't modified. This will happen
|
|
* if the user ran MMC without opening an existing console file
|
|
* and then moved the frame window.
|
|
*/
|
|
// ...unless the console wasn't modified.
|
|
if (m_strPathName.IsEmpty())
|
|
idResponse = IDNO;
|
|
else
|
|
idResponse = IDYES;
|
|
}
|
|
|
|
// otherwise, prompt
|
|
else
|
|
{
|
|
CString prompt;
|
|
FormatString1(prompt, IDS_ASK_TO_SAVE, m_strTitle);
|
|
idResponse = AfxMessageBox(prompt, MB_YESNOCANCEL, AFX_IDP_ASK_TO_SAVE); // dont change to MMCMessageBox - different signature.
|
|
fSaveByUserDecision = true;
|
|
}
|
|
|
|
switch (idResponse)
|
|
{
|
|
case IDCANCEL:
|
|
return FALSE; // don't continue
|
|
|
|
case IDYES:
|
|
// If so, either Save or Update, as appropriate
|
|
// (ignore failures in User mode)
|
|
|
|
// This save is not explicit and shows up when the user closes a modified
|
|
// document. Set it as such. This will result in a different dialog
|
|
// a few functions in.
|
|
SetExplicitSave(false);
|
|
if (!DoFileSave() && fSaveByUserDecision)
|
|
{
|
|
// Restore to the default explicit save
|
|
SetExplicitSave(true);
|
|
return FALSE; // don't continue
|
|
}
|
|
|
|
// Restore to the default explicit save
|
|
SetExplicitSave(true);
|
|
break;
|
|
|
|
case IDNO:
|
|
// If not saving changes, revert the document
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
// At this point we are committed to closing, so give each AMCView
|
|
// a chance to do its clean-up work
|
|
CAMCViewPosition pos = GetFirstAMCViewPosition();
|
|
while (pos != NULL)
|
|
{
|
|
CAMCView* const pView = GetNextAMCView(pos);
|
|
|
|
if (pView != NULL)
|
|
pView->CloseView();
|
|
}
|
|
|
|
return TRUE; // keep going
|
|
}
|
|
|
|
|
|
|
|
#if (_MFC_VER > 0x0600)
|
|
#error CAMCDoc::DoSave was copied from CDocument::DoSave from MFC 6.0.
|
|
#error The MFC version has changed. See if CAMCDoc::DoSave needs to be updated.
|
|
#endif
|
|
|
|
BOOL CAMCDoc::DoSave(LPCTSTR lpszPathName, BOOL bReplace)
|
|
// Save the document data to a file
|
|
// lpszPathName = path name where to save document file
|
|
// if lpszPathName is NULL then the user will be prompted (SaveAs)
|
|
// note: lpszPathName can be different than 'm_strPathName'
|
|
// if 'bReplace' is TRUE will change file name if successful (SaveAs)
|
|
// if 'bReplace' is FALSE will not change path name (SaveCopyAs)
|
|
{
|
|
CString newName = lpszPathName;
|
|
if (newName.IsEmpty())
|
|
{
|
|
CDocTemplate* pTemplate = GetDocTemplate();
|
|
ASSERT(pTemplate != NULL);
|
|
|
|
newName = m_strPathName;
|
|
if (bReplace && newName.IsEmpty())
|
|
{
|
|
newName = m_strTitle;
|
|
#ifndef _MAC
|
|
// check for dubious filename
|
|
int iBad = newName.FindOneOf(_T(" #%;/\\"));
|
|
#else
|
|
int iBad = newName.FindOneOf(_T(":"));
|
|
#endif
|
|
if (iBad != -1)
|
|
newName.ReleaseBuffer(iBad);
|
|
|
|
#ifndef _MAC
|
|
// append the default suffix if there is one
|
|
CString strExt;
|
|
if (pTemplate->GetDocString(strExt, CDocTemplate::filterExt) &&
|
|
!strExt.IsEmpty())
|
|
{
|
|
ASSERT(strExt[0] == '.');
|
|
newName += strExt;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (!AfxGetApp()->DoPromptFileName(newName,
|
|
bReplace ? AFX_IDS_SAVEFILE : AFX_IDS_SAVEFILECOPY,
|
|
OFN_HIDEREADONLY | OFN_PATHMUSTEXIST, FALSE, pTemplate))
|
|
return FALSE; // don't even attempt to save
|
|
}
|
|
|
|
CWaitCursor wait;
|
|
|
|
if (!OnSaveDocument(newName))
|
|
{
|
|
// This is the modified MMC implementation
|
|
#ifdef MMC_DELETE_EXISTING_FILE // See bug 395006
|
|
if ((lpszPathName == NULL) && (m_eSaveStatus != eStat_Cancelled))
|
|
{
|
|
// be sure to delete the file
|
|
try
|
|
{
|
|
CFile::Remove(newName);
|
|
}
|
|
catch (CException* pe)
|
|
{
|
|
TRACE0("Warning: failed to delete file after failed SaveAs.\n");
|
|
pe->Delete();
|
|
}
|
|
}
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
// if changing the name of the open document
|
|
if (bReplace)
|
|
{
|
|
/*
|
|
* Delete the help file for this console file before
|
|
* changing its name, because the help file can't be
|
|
* located once the old name is lost.
|
|
*/
|
|
DeleteHelpFile ();
|
|
|
|
// reset the title and change the document name
|
|
SetPathName(newName);
|
|
}
|
|
|
|
return TRUE; // success
|
|
}
|
|
|
|
|
|
BOOL CAMCDoc::IsModified()
|
|
{
|
|
TRACE_METHOD(CAMCDoc, IsModified);
|
|
|
|
BOOL const bModified = /*CDocument::IsModified() || */
|
|
(m_spScopeTreePersist != NULL && m_spScopeTreePersist->IsDirty() != S_FALSE);
|
|
if (bModified)
|
|
return TRUE;
|
|
|
|
// Loop thru and save each view
|
|
CAMCViewPosition pos = GetFirstAMCViewPosition();
|
|
while (pos != NULL)
|
|
{
|
|
// Get the view and skip if its the active view
|
|
CAMCView* const v = GetNextAMCView(pos);
|
|
|
|
if (v && v->IsDirty())
|
|
return TRUE;
|
|
}
|
|
|
|
// The views should be asked about dirty before
|
|
// asking the columns.
|
|
if ( (NULL != m_ConsoleData.m_spPersistStreamColumnData) &&
|
|
(S_OK == m_ConsoleData.m_spPersistStreamColumnData->IsDirty()) )
|
|
return TRUE;
|
|
|
|
// View data.
|
|
IPersistStreamPtr spIPeristStreamViewSettings;
|
|
SC sc = ScGetViewSettingsPersistorStream(&spIPeristStreamViewSettings);
|
|
if ( (! sc.IsError()) &&
|
|
(spIPeristStreamViewSettings != NULL) )
|
|
{
|
|
sc = spIPeristStreamViewSettings->IsDirty();
|
|
if (sc == S_OK)
|
|
return TRUE;
|
|
|
|
sc.TraceAndClear();
|
|
}
|
|
|
|
return CDocument::IsModified();
|
|
}
|
|
|
|
void CAMCDoc::OnUpdateFileSave(CCmdUI* pCmdUI)
|
|
{
|
|
pCmdUI->Enable (!IsReadOnly());
|
|
}
|
|
|
|
|
|
void CAMCDoc::OnConsoleAddremovesnapin()
|
|
{
|
|
ASSERT(m_spScopeTree != NULL);
|
|
|
|
// Can't run snap-in manager with active property sheets
|
|
CString strMsg;
|
|
LoadString(strMsg, IDS_SNAPINMGR_CLOSEPROPSHEET);
|
|
if (FArePropertySheetsOpen(&strMsg))
|
|
return;
|
|
|
|
m_spScopeTree->RunSnapIn(AfxGetMainWnd()->m_hWnd);
|
|
|
|
::CoFreeUnusedLibraries();
|
|
}
|
|
|
|
void CAMCDoc::OnUpdateConsoleAddremovesnapin(CCmdUI* pCmdUI)
|
|
{
|
|
pCmdUI->Enable (m_spScopeTree != NULL);
|
|
}
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------*
|
|
* CAMCDoc::SetMode
|
|
*
|
|
*
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
void CAMCDoc::SetMode (ProgramMode eMode)
|
|
{
|
|
/*
|
|
* only set the modified flag if something actually changed
|
|
*/
|
|
if (m_ConsoleData.m_eConsoleMode != eMode)
|
|
{
|
|
// should only be able to get here in author mode
|
|
ASSERT (AMCGetApp()->GetMode() == eMode_Author);
|
|
ASSERT (IsValidProgramMode (eMode));
|
|
|
|
m_ConsoleData.m_eConsoleMode = eMode;
|
|
SetModifiedFlag ();
|
|
}
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* CAMCDoc::SetConsoleFlag
|
|
*
|
|
*
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
void CAMCDoc::SetConsoleFlag (ConsoleFlags eFlag, bool fSet)
|
|
{
|
|
DWORD dwFlags = m_ConsoleData.m_dwFlags;
|
|
|
|
if (fSet)
|
|
dwFlags |= eFlag;
|
|
else
|
|
dwFlags &= ~eFlag;
|
|
|
|
/*
|
|
* only set the modified flag if something actually changed
|
|
*/
|
|
if (m_ConsoleData.m_dwFlags != dwFlags)
|
|
{
|
|
m_ConsoleData.m_dwFlags = dwFlags;
|
|
SetModifiedFlag ();
|
|
}
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* mappedModes
|
|
*
|
|
* PURPOSE: provides map to be used when persisting ProgramMode enumeration
|
|
*
|
|
* NOTE: do not remove/ change items unless you're sure no console
|
|
* files will be broken
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
static const EnumLiteral mappedModes[] =
|
|
{
|
|
{ eMode_Author, XML_ENUM_PROGRAM_MODE_AUTHOR } ,
|
|
{ eMode_User, XML_ENUM_PROGRAM_MODE_USER } ,
|
|
{ eMode_User_MDI, XML_ENUM_PROGRAM_MODE_USER_MDI } ,
|
|
{ eMode_User_SDI, XML_ENUM_PROGRAM_MODE_USER_SDI } ,
|
|
};
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CAMCDoc::Persist
|
|
*
|
|
* PURPOSE:
|
|
*
|
|
* PARAMETERS:
|
|
* CPersistor& persistor :
|
|
*
|
|
* RETURNS:
|
|
* void
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
void CAMCDoc::Persist(CPersistor& persistor)
|
|
{
|
|
DECLARE_SC (sc, _T("CAMCDoc::Persist"));
|
|
|
|
CAMCApp* pApp = AMCGetApp();
|
|
|
|
// check required pointers before going any further
|
|
sc = ScCheckPointers(m_spStringTable ? pApp : NULL, // + workaround to check more pointers
|
|
m_ConsoleData.m_pXMLPersistColumnData,
|
|
m_spScopeTree ? GetFavorites() : NULL, // + same workaround ^
|
|
E_POINTER);
|
|
if (sc)
|
|
sc.Throw();
|
|
|
|
// persist version of the document
|
|
CStr strFileVer = 0.;
|
|
if (persistor.IsStoring())
|
|
{
|
|
strFileVer = GetCurrentFileVersionAsString().c_str();
|
|
|
|
GUID guidConsoleId;
|
|
sc = CoCreateGuid(&guidConsoleId);
|
|
if (sc)
|
|
sc.Throw();
|
|
|
|
// this parameter is also updated in IDocConfig implementation
|
|
// update that code when changing following lines
|
|
CPersistor persistorGuid(persistor, XML_TAG_CONSOLE_FILE_UID);
|
|
persistorGuid.PersistContents(guidConsoleId);
|
|
}
|
|
persistor.PersistAttribute(XML_ATTR_CONSOLE_VERSION, strFileVer);
|
|
if (persistor.IsLoading())
|
|
{
|
|
// 'decode' the version
|
|
LPCTSTR pstrStart = strFileVer;
|
|
LPTSTR pstrStop = const_cast<LPTSTR>(pstrStart);
|
|
|
|
UINT uiMajorVer = _tcstol(pstrStart, &pstrStop, 10) ;
|
|
|
|
UINT uiMinorVer = 0;
|
|
if (pstrStop != pstrStart && *pstrStop == '.')
|
|
{
|
|
pstrStart = pstrStop + 1;
|
|
uiMinorVer = _tcstol(pstrStart, &pstrStop, 10) ;
|
|
}
|
|
|
|
UINT uiMinorSubVer = 0;
|
|
if (pstrStop != pstrStart && *pstrStop == '.')
|
|
{
|
|
pstrStart = pstrStop + 1;
|
|
uiMinorVer = _tcstol(pstrStart, &pstrStop, 10) ;
|
|
}
|
|
|
|
ConsoleFileVersion eVersion = (ConsoleFileVersion)MakeConsoleFileVer_(uiMajorVer,
|
|
uiMinorVer,
|
|
uiMinorSubVer);
|
|
|
|
m_ConsoleData.m_eFileVer = eVersion;
|
|
|
|
// BUGBUG: this needs to be changed when we implement 'dynamic' SC messages
|
|
if (eVersion != FileVer_Current)
|
|
sc.Throw(E_UNEXPECTED);
|
|
}
|
|
|
|
|
|
// Create a storage for binaries
|
|
// This will create "detached" XML element which may be used by persistor's
|
|
// childs to store binary informatio.
|
|
// (The element is attached to XML document by calling "CommitBinaryStorage()" )
|
|
if (persistor.IsStoring())
|
|
persistor.GetDocument().CreateBinaryStorage();
|
|
else
|
|
persistor.GetDocument().LocateBinaryStorage();
|
|
|
|
/*
|
|
* make sure the tree expansion happens synchronously
|
|
*/
|
|
bool fSyncExpandWasRequired = m_spScopeTree->IsSynchronousExpansionRequired() == S_OK;
|
|
m_spScopeTree->RequireSynchronousExpansion (true);
|
|
|
|
// historically both loading and saving is to be done in certain order
|
|
// steps are ordered by storing order
|
|
const int STEP_FRAME = 1;
|
|
const int STEP_VIEWS = 2;
|
|
const int STEP_APP_MODE = 3;
|
|
const int STEP_CUST_DATA = 4;
|
|
const int STEP_FAVORITES = 5;
|
|
const int STEP_SCOPE_TREE = 6;
|
|
const int STEP_VIEW_DATA = 7;
|
|
const int STEP_COLUMN_DATA = 8;
|
|
const int STEP_STRING_TABLE = 9;
|
|
const int MIN_STEP = 1;
|
|
const int MAX_STEP = 9;
|
|
for (int iStep = persistor.IsStoring() ? MIN_STEP : MAX_STEP;
|
|
persistor.IsStoring() ? (iStep <= MAX_STEP) : (iStep >= MIN_STEP);
|
|
persistor.IsStoring() ? ++iStep : --iStep
|
|
)
|
|
{
|
|
switch(iStep)
|
|
{
|
|
case STEP_FRAME:
|
|
PersistFrame(persistor);
|
|
break;
|
|
case STEP_VIEWS:
|
|
PersistViews(persistor);
|
|
break;
|
|
case STEP_APP_MODE:
|
|
if (persistor.IsLoading())
|
|
{
|
|
// restore proper application mode
|
|
ProgramMode eMode;
|
|
|
|
// create wrapper to persist enumeration values as strings
|
|
CXMLEnumeration modeValuePersistor(eMode, mappedModes, countof(mappedModes));
|
|
|
|
// persist the wrapper
|
|
persistor.PersistAttribute(XML_ATTR_APPLICATION_MODE, modeValuePersistor);
|
|
|
|
pApp->SetMode(eMode);
|
|
}
|
|
break;
|
|
case STEP_CUST_DATA:
|
|
PersistCustomData (persistor);
|
|
break;
|
|
case STEP_FAVORITES:
|
|
persistor.Persist(*GetFavorites());
|
|
break;
|
|
case STEP_SCOPE_TREE:
|
|
// IDocConfig relies on tree to be under the document.
|
|
// revisit that code if you do the change here
|
|
sc = m_spScopeTree->Persist(reinterpret_cast<HPERSISTOR>(&persistor));
|
|
if (sc)
|
|
sc.Throw();
|
|
break;
|
|
case STEP_VIEW_DATA:
|
|
{
|
|
INodeCallbackPtr spNodeCallback;
|
|
sc = m_spScopeTree->QueryNodeCallback(&spNodeCallback);
|
|
if (sc)
|
|
sc.Throw();
|
|
|
|
sc = ScCheckPointers(spNodeCallback, E_UNEXPECTED);
|
|
if (sc)
|
|
sc.Throw();
|
|
|
|
CXMLObject *pXMLViewSettings = NULL;
|
|
sc = spNodeCallback->QueryViewSettingsPersistor(&pXMLViewSettings);
|
|
if (sc)
|
|
sc.Throw();
|
|
|
|
sc = ScCheckPointers(pXMLViewSettings, E_UNEXPECTED);
|
|
if (sc)
|
|
sc.Throw();
|
|
|
|
persistor.Persist(*pXMLViewSettings);
|
|
}
|
|
break;
|
|
case STEP_COLUMN_DATA:
|
|
persistor.Persist(*m_ConsoleData.m_pXMLPersistColumnData);
|
|
break;
|
|
case STEP_STRING_TABLE:
|
|
CMasterStringTable *pMasterStringTable = dynamic_cast<CMasterStringTable *>((IStringTablePrivate *)m_spStringTable);
|
|
if(!pMasterStringTable)
|
|
{
|
|
sc = E_UNEXPECTED;
|
|
sc.Throw();
|
|
}
|
|
persistor.Persist(*pMasterStringTable);
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_spScopeTree->RequireSynchronousExpansion (fSyncExpandWasRequired);
|
|
SetModifiedFlag (false);
|
|
SetFrameModifiedFlag (false);
|
|
|
|
/*
|
|
* We shouldn't think that a freshly saved console file is
|
|
* dirty. If we do, someone's dirty bit processing is bogus.
|
|
*/
|
|
ASSERT (!IsFrameModified());
|
|
|
|
/*
|
|
* Too many snap-ins leave themselves dirty after a load to leave this
|
|
* assert in, so we'll trace instead. Note that this trace doesn't
|
|
* always indicate a snap-in problem, but it frequently does.
|
|
*/
|
|
#ifdef DBG
|
|
// ASSERT (!IsModified());
|
|
if (IsModified())
|
|
TraceErrorMsg (_T("CAMCDoc::IsModified returns true after %s"),
|
|
persistor.IsLoading() ? _T("opening") : _T("saving"));
|
|
#endif
|
|
|
|
// The element used to gather binary information is attached to XML document here
|
|
// Physically it will reside after all elements already added to persistor
|
|
if (persistor.IsStoring())
|
|
persistor.GetDocument().CommitBinaryStorage();
|
|
}
|
|
|
|
//***************************************************************************
|
|
// CScopedBool
|
|
//
|
|
//
|
|
// PURPOSE: Owns a bool. The bool is set to false in the constructor and true
|
|
// in the destructor.
|
|
//
|
|
//****************************************************************************
|
|
class CScopedBool
|
|
{
|
|
bool & m_bool;
|
|
|
|
public:
|
|
CScopedBool (bool &b) : m_bool(b)
|
|
{
|
|
b= false;
|
|
}
|
|
~CScopedBool()
|
|
{
|
|
m_bool = true;
|
|
}
|
|
};
|
|
|
|
void CAMCDoc::PersistViews(CPersistor& persistor)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::PersistViews"));
|
|
|
|
CScopedBool scopedBool(m_bCanCloseViews); // lock the views from being deleted during the persist operation.
|
|
|
|
if (persistor.IsLoading())
|
|
{
|
|
// Read templates for new views
|
|
CViewTemplateList view_list(XML_TAG_VIEW_LIST);
|
|
persistor.Persist(view_list);
|
|
|
|
// Get the means for enumerating loaded collection
|
|
CViewTemplateList::List_Type &rList = view_list.GetList();
|
|
CViewTemplateList::List_Type::iterator it;
|
|
|
|
// Enumerate all the views to be created
|
|
// Create them one-by-one
|
|
for (it = rList.begin(); it != rList.end(); ++it)
|
|
{
|
|
// extract information for the new view
|
|
int iViewID = it->first;
|
|
const CBookmark& pbm = it->second.first;
|
|
CPersistor& v_persistor = it->second.second;
|
|
|
|
// create it!
|
|
sc = ScCreateAndLoadView(v_persistor, iViewID, pbm);
|
|
if (sc)
|
|
sc.Throw();
|
|
}
|
|
}
|
|
else // if (persistor.IsStoring())
|
|
{
|
|
CPersistor persistorViews(persistor, XML_TAG_VIEW_LIST);
|
|
|
|
/*
|
|
* Bug 3504: enumerate views in z-order (bottom-to-top) so the
|
|
* z-order will be restored correctly on reload
|
|
*/
|
|
CMainFrame* pMainFrame = AMCGetMainWnd();
|
|
sc = ScCheckPointers (pMainFrame, E_UNEXPECTED);
|
|
if (sc)
|
|
sc.Throw();
|
|
|
|
/*
|
|
* get the top-most MDI child
|
|
*/
|
|
CWnd* pwndMDIChild = pMainFrame->MDIGetActive();
|
|
sc = ScCheckPointers (pwndMDIChild, E_UNEXPECTED);
|
|
if (sc)
|
|
sc.Throw();
|
|
|
|
/*
|
|
* iterate through each of the MDI children
|
|
*/
|
|
for (pwndMDIChild = pwndMDIChild->GetWindow (GW_HWNDLAST);
|
|
pwndMDIChild != NULL;
|
|
pwndMDIChild = pwndMDIChild->GetNextWindow (GW_HWNDPREV))
|
|
{
|
|
/*
|
|
* turn the generic CMDIChildWnd into a CChildFrame
|
|
*/
|
|
CChildFrame* pChildFrame = dynamic_cast<CChildFrame*>(pwndMDIChild);
|
|
sc = ScCheckPointers (pChildFrame, E_UNEXPECTED);
|
|
if (sc)
|
|
sc.Throw();
|
|
|
|
/*
|
|
* get the view for this child frame
|
|
*/
|
|
CAMCView* pwndView = pChildFrame->GetAMCView();
|
|
sc = ScCheckPointers (pwndView, E_UNEXPECTED);
|
|
if (sc)
|
|
sc.Throw();
|
|
|
|
// skip those not persistible
|
|
if ( !pwndView->IsPersisted() )
|
|
continue;
|
|
|
|
/*
|
|
* persist the view
|
|
*/
|
|
persistorViews.Persist (*pwndView);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CAMCDoc::PersistFrame(CPersistor& persistor)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::PersistFrame"));
|
|
|
|
CFrameState fs2 (m_ConsoleData.m_eConsoleMode, m_ConsoleData.m_dwFlags);
|
|
ASSERT (fs2.wndplFrame.length == sizeof (WINDOWPLACEMENT));
|
|
|
|
CMainFrame* pMainFrame = AMCGetMainWnd();
|
|
sc = ScCheckPointers (pMainFrame, E_UNEXPECTED);
|
|
if (sc)
|
|
sc.Throw();
|
|
|
|
if (persistor.IsStoring())
|
|
{
|
|
// Get the attributes of the window.
|
|
if (!pMainFrame->GetWindowPlacement (&fs2.wndplFrame))
|
|
sc.Throw(E_FAIL);
|
|
|
|
if (fs2.wndplFrame.showCmd == SW_SHOWMINIMIZED)
|
|
fs2.wndplFrame.showCmd = SW_SHOWNORMAL;
|
|
}
|
|
|
|
persistor.Persist(fs2);
|
|
|
|
// this application setting (AppMode) is resored in AMCDoc::Persist, but saved/loaded here
|
|
// create wrapper to persist enumeration values as strings
|
|
CXMLEnumeration modeValuePersistor(m_ConsoleData.m_eConsoleMode, mappedModes, countof(mappedModes));
|
|
// persist the wrapper
|
|
persistor.PersistAttribute(XML_ATTR_APPLICATION_MODE, modeValuePersistor);
|
|
|
|
if (persistor.IsLoading())
|
|
{
|
|
// Set the windows size and location and state
|
|
CAMCApp* pApp = AMCGetApp();
|
|
pApp->UpdateFrameWindow(true);
|
|
pMainFrame->UpdateChildSystemMenus();
|
|
|
|
// the status bar is on the child frame now
|
|
// pMainFrame->ShowStatusBar ((fs2.dwFlags & eFlag_ShowStatusBar) != 0);
|
|
|
|
// save the data from the file into the console data
|
|
m_ConsoleData.m_eAppMode = pApp->GetMode();
|
|
m_ConsoleData.m_dwFlags = fs2.dwFlags;
|
|
|
|
InsurePlacementIsOnScreen (fs2.wndplFrame);
|
|
|
|
// if we're initializing, defer the actual show until initialization is complete
|
|
// same if script is under control and MMC is hidden
|
|
if (pApp->IsInitializing()
|
|
|| ( !pApp->IsUnderUserControl() && !pMainFrame->IsWindowVisible() ) )
|
|
{
|
|
pApp->m_nCmdShow = fs2.wndplFrame.showCmd;
|
|
fs2.wndplFrame.showCmd = SW_HIDE;
|
|
}
|
|
|
|
if (!pMainFrame->SetWindowPlacement (&fs2.wndplFrame))
|
|
sc.Throw(E_FAIL);
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*
|
|
* CDocument::DoFileSave
|
|
*
|
|
* This is almost identical to CDocument::DoFileSave. We just override it
|
|
* here because we want to display a message for a read-only file before
|
|
* throwing up the Save As dialog.
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
BOOL CAMCDoc::DoFileSave()
|
|
{
|
|
DWORD dwAttrib = GetFileAttributes(m_strPathName);
|
|
|
|
// attributes does not matter for user modes - it does not
|
|
// save to the original console file anyway
|
|
if ((AMCGetApp()->GetMode() == eMode_Author) &&
|
|
(dwAttrib != 0xFFFFFFFF) &&
|
|
(dwAttrib & FILE_ATTRIBUTE_READONLY))
|
|
{
|
|
CString strMessage;
|
|
FormatString1 (strMessage, IDS_CONSOLE_READONLY, m_strPathName);
|
|
MMCMessageBox (strMessage);
|
|
|
|
// we do not have read-write access or the file does not (now) exist
|
|
if (!DoSave(NULL))
|
|
{
|
|
TRACE0("Warning: File save with new name failed.\n");
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!DoSave(m_strPathName))
|
|
{
|
|
TRACE0("Warning: File save failed.\n");
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------*
|
|
* CAMCDoc::GetDefaultMenu
|
|
*
|
|
*
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
HMENU CAMCDoc::GetDefaultMenu()
|
|
{
|
|
return (AMCGetApp()->GetMenu ());
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* CAMCDoc::GetCustomIcon
|
|
*
|
|
* Returns the small or large custom icon for the console. Ownership of and
|
|
* deletion responsibility for the icon is retained by CAMCDoc.
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
HICON CAMCDoc::GetCustomIcon (bool fLarge, CString* pstrIconFile, int* pnIconIndex) const
|
|
{
|
|
DECLARE_SC (sc, _T("CAMCDoc::ScGetCustomIcon"));
|
|
|
|
/*
|
|
* if caller wants either the icon filename or index returned, get them
|
|
*/
|
|
if ((pstrIconFile != NULL) || (pnIconIndex != NULL))
|
|
{
|
|
CPersistableIconData IconData;
|
|
m_CustomIcon.GetData (IconData);
|
|
|
|
if (pstrIconFile != NULL)
|
|
*pstrIconFile = IconData.m_strIconFile.data();
|
|
|
|
if (pnIconIndex != NULL)
|
|
*pnIconIndex = IconData.m_nIndex;
|
|
}
|
|
|
|
/*
|
|
* return the icon (m_CustomIcon will hold the reference for the
|
|
* caller)
|
|
*/
|
|
CSmartIcon icon;
|
|
sc = m_CustomIcon.GetIcon ((fLarge) ? 32 : 16, icon);
|
|
if (sc)
|
|
return (NULL);
|
|
|
|
return (icon);
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* CAMCDoc::SetCustomIcon
|
|
*
|
|
*
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
void CAMCDoc::SetCustomIcon (LPCTSTR pszIconFile, int nIconIndex)
|
|
{
|
|
DECLARE_SC (sc, _T("CAMCDoc::SetCustomIcon"));
|
|
|
|
CPersistableIconData IconData (pszIconFile, nIconIndex) ;
|
|
|
|
/*
|
|
* if there's no change, bail
|
|
*/
|
|
if (m_CustomIcon == IconData)
|
|
return;
|
|
|
|
m_CustomIcon = IconData;
|
|
|
|
HICON hLargeIcon = GetCustomIcon (true /*fLarge*/);
|
|
HICON hSmallIcon = GetCustomIcon (false /*fLarge*/);
|
|
CMainFrame* pMainFrame = AMCGetMainWnd();
|
|
|
|
sc = ScCheckPointers (hLargeIcon, hSmallIcon, pMainFrame, E_UNEXPECTED);
|
|
if (sc)
|
|
return;
|
|
|
|
/*
|
|
* change the icon on the frame
|
|
*/
|
|
pMainFrame->SetIconEx (hLargeIcon, true);
|
|
pMainFrame->SetIconEx (hSmallIcon, false);
|
|
|
|
/*
|
|
* change the icon on each MDI window
|
|
*/
|
|
CWnd* pMDIChild = pMainFrame->MDIGetActive();
|
|
|
|
while (pMDIChild != NULL)
|
|
{
|
|
ASSERT_KINDOF (CMDIChildWnd, pMDIChild);
|
|
pMDIChild->SetIcon (hLargeIcon, true);
|
|
pMDIChild->SetIcon (hSmallIcon, false);
|
|
pMDIChild = pMDIChild->GetWindow (GW_HWNDNEXT);
|
|
}
|
|
|
|
SetModifiedFlag();
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* CAMCDoc::LoadCustomData
|
|
*
|
|
*
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
bool CAMCDoc::LoadCustomData (IStorage* pStorage)
|
|
{
|
|
HRESULT hr;
|
|
IStoragePtr spCustomDataStorage;
|
|
hr = OpenDebugStorage (pStorage, g_pszCustomDataStorage,
|
|
STGM_SHARE_EXCLUSIVE | STGM_READ,
|
|
&spCustomDataStorage);
|
|
|
|
|
|
if (FAILED (hr))
|
|
return (true);
|
|
|
|
LoadCustomIconData (spCustomDataStorage);
|
|
LoadCustomTitleData (spCustomDataStorage);
|
|
|
|
return (true);
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* CAMCDoc::LoadCustomIconData
|
|
*
|
|
*
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
bool CAMCDoc::LoadCustomIconData (IStorage* pStorage)
|
|
{
|
|
HRESULT hr = m_CustomIcon.Load (pStorage);
|
|
|
|
if (FAILED (hr))
|
|
return (false);
|
|
|
|
/*
|
|
* If we get here, we have a custom icon. The view windows
|
|
* (MDI children) haven't been created yet -- they'll get the
|
|
* right icons automatically. The main frame, however, already
|
|
* exists, so we have to explicitly set its icon here.
|
|
*/
|
|
CWnd* pMainWnd = AfxGetMainWnd();
|
|
pMainWnd->SetIcon (GetCustomIcon (true), true);
|
|
pMainWnd->SetIcon (GetCustomIcon (false), false);
|
|
|
|
return (true);
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* CAMCDoc::LoadCustomTitleData
|
|
*
|
|
*
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
bool CAMCDoc::LoadCustomTitleData (IStorage* pStorage)
|
|
{
|
|
do // not a loop
|
|
{
|
|
/*
|
|
* Open the custom title data stream. It may not exist, and
|
|
* that's OK if it doesn't. It just means we don't have a
|
|
* custom title.
|
|
*/
|
|
USES_CONVERSION;
|
|
HRESULT hr;
|
|
IStreamPtr spStream;
|
|
hr = OpenDebugStream (pStorage, AMCCustomTitleStreamName,
|
|
STGM_SHARE_EXCLUSIVE | STGM_READ,
|
|
&spStream);
|
|
|
|
BREAK_ON_FAIL (hr);
|
|
|
|
try
|
|
{
|
|
/*
|
|
* Read the stream version
|
|
*/
|
|
DWORD dwVersion;
|
|
*spStream >> dwVersion;
|
|
|
|
/*
|
|
* if this is the beta custom title format, migrate it forward
|
|
*/
|
|
switch (dwVersion)
|
|
{
|
|
case 0:
|
|
{
|
|
/*
|
|
* Read the length (in bytes) of the title
|
|
*/
|
|
WORD cbTitle;
|
|
*spStream >> cbTitle;
|
|
const WORD cchTitle = cbTitle / sizeof (WCHAR);
|
|
|
|
/*
|
|
* Read the title
|
|
*/
|
|
std::auto_ptr<WCHAR> spwzWideTitle (new WCHAR[cchTitle + 1]);
|
|
LPWSTR pwzWideTitle = spwzWideTitle.get();
|
|
|
|
DWORD cbRead;
|
|
hr = spStream->Read (pwzWideTitle, cbTitle, &cbRead);
|
|
BREAK_ON_FAIL (hr);
|
|
|
|
if (cbRead != cbTitle)
|
|
break;
|
|
|
|
/*
|
|
* terminate and convert the title string
|
|
*/
|
|
pwzWideTitle[cchTitle] = 0;
|
|
if (m_pstrCustomTitle != NULL)
|
|
*m_pstrCustomTitle = W2T (pwzWideTitle);
|
|
break;
|
|
}
|
|
|
|
case 1:
|
|
if (m_pstrCustomTitle != NULL)
|
|
*spStream >> (*m_pstrCustomTitle);
|
|
break;
|
|
|
|
default:
|
|
ASSERT (false);
|
|
break;
|
|
}
|
|
}
|
|
catch (_com_error& err)
|
|
{
|
|
hr = err.Error();
|
|
ASSERT (false && "Caught _com_error");
|
|
break;
|
|
}
|
|
catch (CMemoryException* pe)
|
|
{
|
|
pe->Delete();
|
|
_com_issue_error (E_OUTOFMEMORY);
|
|
}
|
|
} while (false);
|
|
|
|
return (true);
|
|
}
|
|
|
|
|
|
|
|
bool CAMCDoc::HasCustomTitle () const
|
|
{
|
|
if(!m_pstrCustomTitle)
|
|
return false;
|
|
|
|
return (!m_pstrCustomTitle->str().empty());
|
|
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* CAMCDoc::LoadStringTable
|
|
*
|
|
*
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
bool CAMCDoc::LoadStringTable (IStorage* pStorage)
|
|
{
|
|
DECLARE_SC (sc, _T("CAMCDoc::LoadStringTable"));
|
|
|
|
/*
|
|
* open the string table storage
|
|
*/
|
|
IStoragePtr spStringTableStg;
|
|
HRESULT hr = OpenDebugStorage (pStorage, AMCStringTableStorageName,
|
|
STGM_SHARE_EXCLUSIVE | STGM_READ,
|
|
&spStringTableStg);
|
|
|
|
|
|
/*
|
|
* If there's no string table, things are OK. We allow this so
|
|
* we can continue to open older console files.
|
|
*/
|
|
if (hr == STG_E_FILENOTFOUND)
|
|
return (true);
|
|
|
|
if (SUCCEEDED (hr))
|
|
{
|
|
/*
|
|
* read the string table from the storage
|
|
*/
|
|
try
|
|
{
|
|
CMasterStringTable *pMasterStringTable = dynamic_cast<CMasterStringTable *>((IStringTablePrivate *)m_spStringTable);
|
|
if(!pMasterStringTable)
|
|
{
|
|
sc = E_UNEXPECTED;
|
|
sc.Throw();
|
|
}
|
|
|
|
*spStringTableStg >> *pMasterStringTable;
|
|
}
|
|
catch (_com_error& err)
|
|
{
|
|
hr = err.Error();
|
|
ASSERT (false && "Caught _com_error");
|
|
}
|
|
}
|
|
|
|
return (SUCCEEDED (hr));
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* CAMCDoc::SetCustomTitle
|
|
*
|
|
*
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
void CAMCDoc::SetCustomTitle (CString strNewTitle)
|
|
{
|
|
DECLARE_SC (sc, _T("CAMCDoc::SetCustomTitle"));
|
|
|
|
if(!m_pstrCustomTitle)
|
|
return;
|
|
|
|
/*
|
|
* if there's no change, just short out
|
|
*/
|
|
if ((*m_pstrCustomTitle) == strNewTitle)
|
|
return;
|
|
|
|
/*
|
|
* copy the new custom title
|
|
*/
|
|
(*m_pstrCustomTitle) = strNewTitle;
|
|
|
|
/*
|
|
* force the frame to update
|
|
*/
|
|
CMainFrame* pMainFrame = AMCGetMainWnd();
|
|
sc = ScCheckPointers (pMainFrame, E_UNEXPECTED);
|
|
if (sc)
|
|
return;
|
|
|
|
pMainFrame->OnUpdateFrameTitle (false);
|
|
|
|
SetModifiedFlag();
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* CAMCDoc::GetCustomTitle
|
|
*
|
|
*
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
CString CAMCDoc::GetCustomTitle() const
|
|
{
|
|
if (HasCustomTitle())
|
|
return (m_pstrCustomTitle->data());
|
|
|
|
CString strTitle = GetTitle();
|
|
|
|
/*
|
|
* strip the extension (extensions, including a separator,
|
|
* are 4 characters or less)
|
|
*/
|
|
int nExtSeparator = strTitle.ReverseFind (_T('.'));
|
|
|
|
if ((nExtSeparator != -1) && ((strTitle.GetLength()-nExtSeparator) <= 4))
|
|
strTitle = strTitle.Left (nExtSeparator);
|
|
|
|
return (strTitle);
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* CAMCDoc::GetStringTable
|
|
*
|
|
*
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
IStringTablePrivate* CAMCDoc::GetStringTable() const
|
|
{
|
|
return m_spStringTable;
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* CAMCDoc::LoadFavorites
|
|
*
|
|
*
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
bool CAMCDoc::LoadFavorites ()
|
|
{
|
|
ASSERT(m_spStorage != NULL);
|
|
|
|
// Open the stream for the cache
|
|
IStreamPtr spStream;
|
|
HRESULT hr = OpenDebugStream(m_spStorage, AMCFavoritesStreamName,
|
|
STGM_SHARE_EXCLUSIVE | STGM_READWRITE, L"FavoritesStream", &spStream);
|
|
if (FAILED(hr)) // did not find the stream - could be an older version.
|
|
return hr;
|
|
|
|
hr = GetFavorites()->Read(spStream);
|
|
|
|
return (SUCCEEDED (hr));
|
|
}
|
|
|
|
|
|
void ShowAdminToolsOnMenu(LPCTSTR lpszFilename)
|
|
{
|
|
static const TCHAR szAdminKey[] = _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced");
|
|
static const TCHAR szAdminValue[] = _T("StartMenuAdminTools");
|
|
static const TCHAR szBroadcastParam[] = _T("ShellMenu");
|
|
static const TCHAR szYes[] = _T("YES");
|
|
|
|
CString strPath(lpszFilename);
|
|
int nLastSepIndex = strPath.ReverseFind (_T('\\'));
|
|
|
|
if (nLastSepIndex != -1)
|
|
{
|
|
// if we got "d:\filename", make sure to include the trailing separator
|
|
if (nLastSepIndex < 3)
|
|
nLastSepIndex++;
|
|
|
|
// Form full path name (accounting for current directory info)
|
|
TCHAR szFullPathName[MAX_PATH];
|
|
GetFullPathName (strPath.Left(nLastSepIndex), countof(szFullPathName),
|
|
szFullPathName, NULL);
|
|
|
|
// if saving to admin tools
|
|
if (AMCGetApp()->GetDefaultDirectory() == szFullPathName)
|
|
{
|
|
// set reg key to add admin tools to start menu
|
|
HKEY hkey;
|
|
long r = RegOpenKeyEx (HKEY_CURRENT_USER, szAdminKey, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hkey);
|
|
ASSERT(r == ERROR_SUCCESS);
|
|
|
|
if (r == ERROR_SUCCESS)
|
|
{
|
|
// get current value
|
|
TCHAR szBuffer[4];
|
|
DWORD dwType = REG_SZ;
|
|
DWORD dwCount = sizeof(szBuffer);
|
|
r = RegQueryValueEx (hkey, szAdminValue, NULL, &dwType,(LPBYTE)szBuffer, &dwCount);
|
|
|
|
// if value isn't "YES" then change it, and broadcast change message
|
|
if (r != ERROR_SUCCESS || dwType != REG_SZ || lstrcmpi(szBuffer, szYes) != 0)
|
|
{
|
|
r = RegSetValueEx (hkey, szAdminValue, NULL, REG_SZ, (CONST BYTE *)szYes, sizeof(szYes));
|
|
ASSERT(r == ERROR_SUCCESS);
|
|
|
|
ULONG_PTR dwRes;
|
|
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, (WPARAM)0,
|
|
(LPARAM)szBroadcastParam, SMTO_ABORTIFHUNG|SMTO_NORMAL, 100, &dwRes);
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CAMCDoc::PersistCustomData (CPersistor &persistor)
|
|
{
|
|
CPersistor persistorCustom(persistor, XML_TAG_CUSTOM_DATA);
|
|
// persist custom title
|
|
// It may not exist, and that's OK if it doesn't.
|
|
// It just means we don't have a custom title.
|
|
if ((persistorCustom.IsLoading()
|
|
&& persistorCustom.HasElement(XML_TAG_STRING_TABLE_STRING, XML_ATTR_CUSTOM_TITLE))
|
|
|| (persistorCustom.IsStoring() && HasCustomTitle()))
|
|
{
|
|
if(m_pstrCustomTitle)
|
|
persistorCustom.PersistString(XML_ATTR_CUSTOM_TITLE, *m_pstrCustomTitle);
|
|
}
|
|
|
|
// persist custom icon
|
|
CXMLPersistableIcon persIcon(m_CustomIcon);
|
|
|
|
bool bHasIcon = persistorCustom.IsLoading() && persistorCustom.HasElement(persIcon.GetXMLType(), NULL);
|
|
bHasIcon = bHasIcon || persistorCustom.IsStoring() && HasCustomIcon();
|
|
|
|
if (!bHasIcon)
|
|
return;
|
|
|
|
persistorCustom.Persist(persIcon);
|
|
|
|
if (persistorCustom.IsLoading())
|
|
{
|
|
CWnd* pMainWnd = AfxGetMainWnd();
|
|
pMainWnd->SetIcon (GetCustomIcon (true), true);
|
|
pMainWnd->SetIcon (GetCustomIcon (false), false);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: GetCurrentFileVersionAsString
|
|
*
|
|
* PURPOSE: formats current file version and returns a string
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* RETURNS:
|
|
* CString - resulting string
|
|
*
|
|
\***************************************************************************/
|
|
tstring GetCurrentFileVersionAsString()
|
|
{
|
|
DECLARE_SC(sc, TEXT("GetCurrentFileVersionAsString"));
|
|
TCHAR szFileVersion[16];
|
|
int cChFileVersion = countof(szFileVersion);
|
|
|
|
// get file version data
|
|
UINT uiMajorVer = GetConsoleFileMajorVersion(FileVer_Current);
|
|
UINT uiMinorVer = GetConsoleFileMinorVersion(FileVer_Current);
|
|
UINT uiMinorSubVer = GetConsoleFileMinorSubversion(FileVer_Current);
|
|
|
|
if (uiMinorSubVer)
|
|
sc = StringCchPrintf(szFileVersion, cChFileVersion, _T("%d.%d.%d"), uiMajorVer, uiMinorVer, uiMinorSubVer);
|
|
else
|
|
sc = StringCchPrintf(szFileVersion, cChFileVersion, _T("%d.%d"), uiMajorVer, uiMinorVer);
|
|
|
|
if (sc)
|
|
return _T("");
|
|
|
|
return szFileVersion;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CAMCDoc::ScOnSnapinAdded
|
|
*
|
|
* PURPOSE: Script event firing helper. Implements interface accessible from
|
|
* node manager
|
|
*
|
|
* PARAMETERS:
|
|
* PSNAPIN pSnapIn [in] - snapin added to the console
|
|
*
|
|
* RETURNS:
|
|
* SC - result code
|
|
*
|
|
\***************************************************************************/
|
|
SC CAMCDoc::ScOnSnapinAdded(PSNAPIN pSnapIn)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::ScOnSnapinAdded"));
|
|
|
|
CAMCApp* pApp = AMCGetApp();
|
|
|
|
// check
|
|
sc = ScCheckPointers(pApp, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// forward
|
|
sc = pApp->ScOnSnapinAdded(this, pSnapIn);
|
|
if (sc)
|
|
return sc;
|
|
|
|
|
|
return sc;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CAMCDoc::ScOnSnapinRemoved
|
|
*
|
|
* PURPOSE: Script event firing helper. Implements interface accessible from
|
|
* node manager
|
|
*
|
|
* PARAMETERS:
|
|
* PSNAPIN pSnapIn [in] - snapin removed from console
|
|
*
|
|
* RETURNS:
|
|
* SC - result code
|
|
*
|
|
\***************************************************************************/
|
|
SC CAMCDoc::ScOnSnapinRemoved(PSNAPIN pSnapIn)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::ScOnSnapinRemoved"));
|
|
|
|
CAMCApp* pApp = AMCGetApp();
|
|
|
|
// check
|
|
sc = ScCheckPointers(pApp, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// forward
|
|
sc = pApp->ScOnSnapinRemoved(this, pSnapIn);
|
|
if (sc)
|
|
return sc;
|
|
|
|
return sc;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CAMCDoc::ScSetHelpCollectionInvalid
|
|
//
|
|
// Synopsis: A snapin is added/removed or extension is
|
|
// enabled/disabled therefore help collection
|
|
// no longer reflects current console file.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CAMCDoc::ScSetHelpCollectionInvalid ()
|
|
{
|
|
DECLARE_SC(sc, _T("CAMCDoc::ScSetHelpCollectionInvalid"));
|
|
|
|
HELPDOCINFO *pHelpDocInfo = GetHelpDocInfo();
|
|
sc = ScCheckPointers(pHelpDocInfo, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// console file modify time has to be updated for help collection.
|
|
GetSystemTimeAsFileTime(&pHelpDocInfo->m_ftimeModify);
|
|
|
|
return (sc);
|
|
}
|
|
|
|
|
|
|
|
SC CAMCDoc::Scget_Application(PPAPPLICATION ppApplication)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CAMCDoc::Scget_Application"));
|
|
|
|
// parameter check
|
|
sc = ScCheckPointers(ppApplication, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// initialization
|
|
*ppApplication = NULL;
|
|
|
|
CAMCApp* pApp = AMCGetApp();
|
|
|
|
// check
|
|
sc = ScCheckPointers(pApp, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = pApp->ScGet_Application(ppApplication);
|
|
if (sc)
|
|
return sc;
|
|
|
|
return sc;
|
|
}
|
|
|
|
|