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.
755 lines
18 KiB
755 lines
18 KiB
#include "precomp.h"
|
|
#include "mcinc.h"
|
|
#include "marswin.h"
|
|
#include "panel.h"
|
|
#include "place.h"
|
|
|
|
////static void DebugLog( LPCWSTR szMessageFmt ,
|
|
//// ... )
|
|
////{
|
|
//// const int BUFFER_LINE_LENGTH = 512;
|
|
//// WCHAR rgLine[BUFFER_LINE_LENGTH+1];
|
|
//// va_list arglist;
|
|
//// int iLen;
|
|
//// BOOL bRetVal = TRUE;
|
|
////
|
|
////
|
|
//// //
|
|
//// // Format the log line.
|
|
//// //
|
|
//// va_start( arglist, szMessageFmt );
|
|
//// iLen = _vsnwprintf( rgLine, BUFFER_LINE_LENGTH, szMessageFmt, arglist );
|
|
//// va_end( arglist );
|
|
////
|
|
//// //
|
|
//// // Is the arglist too big for us?
|
|
//// //
|
|
//// if(iLen < 0)
|
|
//// {
|
|
//// iLen = BUFFER_LINE_LENGTH;
|
|
//// }
|
|
//// rgLine[iLen] = 0;
|
|
////
|
|
//// ::OutputDebugStringW( rgLine );
|
|
////}
|
|
|
|
|
|
//==================================================================
|
|
// CPlacePanelCollection
|
|
//==================================================================
|
|
|
|
CPlacePanelCollection::~CPlacePanelCollection()
|
|
{
|
|
for (int i=0; i<GetSize(); i++)
|
|
{
|
|
delete (*this)[i];
|
|
}
|
|
}
|
|
|
|
//==================================================================
|
|
// CPlacePanel
|
|
//==================================================================
|
|
|
|
CPlacePanel::CPlacePanel( MarsAppDef_PlacePanel* pp) :
|
|
m_bstrName(pp->szName),
|
|
m_fWasVisible(pp->fStartVisible),
|
|
m_PersistVisible(pp->persistVisible)
|
|
{
|
|
}
|
|
|
|
VARIANT_BOOL CPlacePanel::ShowOnTransition(CMarsPanel *pPanel)
|
|
{
|
|
VARIANT_BOOL bResult;
|
|
|
|
switch(m_PersistVisible)
|
|
{
|
|
case PANEL_PERSIST_VISIBLE_DONTTOUCH:
|
|
if(pPanel->WasInPreviousPlace())
|
|
{
|
|
bResult = pPanel->IsVisible();
|
|
break;
|
|
}
|
|
|
|
case PANEL_PERSIST_VISIBLE_ALWAYS:
|
|
bResult = m_fWasVisible ? VARIANT_TRUE : VARIANT_FALSE;
|
|
break;
|
|
|
|
default:
|
|
bResult = VARIANT_TRUE;
|
|
break;
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
void CPlacePanel::SaveLayout(CMarsPanel *pPanel)
|
|
{
|
|
m_fWasVisible = pPanel->IsVisible();
|
|
}
|
|
|
|
|
|
//==================================================================
|
|
// CMarsPlace
|
|
//==================================================================
|
|
|
|
CMarsPlace::CMarsPlace(CPlaceCollection *pParent, CMarsDocument *pMarsDocument)
|
|
{
|
|
m_spPlaceCollection = pParent;
|
|
m_spMarsDocument = pMarsDocument;
|
|
}
|
|
|
|
HRESULT CMarsPlace::DoPassivate()
|
|
{
|
|
m_spPlaceCollection.Release();
|
|
m_spMarsDocument.Release();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CMarsPlace::Init(LPCWSTR pwszName)
|
|
{
|
|
m_bstrName = pwszName;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
IMPLEMENT_ADDREF_RELEASE(CMarsPlace);
|
|
|
|
STDMETHODIMP CMarsPlace::QueryInterface(REFIID iid, void ** ppvObject)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if(API_IsValidWritePtr(ppvObject))
|
|
{
|
|
hr = E_NOINTERFACE;
|
|
*ppvObject = NULL;
|
|
|
|
if((iid == IID_IMarsPlace) ||
|
|
(iid == IID_IDispatch ) ||
|
|
(iid == IID_IUnknown ) )
|
|
{
|
|
*ppvObject = SAFECAST(this, IMarsPlace *);
|
|
}
|
|
|
|
if(*ppvObject)
|
|
{
|
|
hr = S_OK;
|
|
AddRef();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// IMarsPlace
|
|
STDMETHODIMP CMarsPlace::get_name(BSTR *pbstrName)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if(API_IsValidWritePtr(pbstrName) && VerifyNotPassive(&hr))
|
|
{
|
|
hr = SUCCEEDED(m_bstrName.CopyTo(pbstrName)) ? S_OK : S_FALSE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsPlace::transitionTo()
|
|
{
|
|
FAIL_AFTER_PASSIVATE();
|
|
|
|
return m_spPlaceCollection->transitionTo(m_bstrName);
|
|
}
|
|
|
|
HRESULT CMarsPlace::DoTransition()
|
|
{
|
|
FAIL_AFTER_PASSIVATE();
|
|
|
|
CPanelCollection *pPanels = m_spMarsDocument->GetPanels();
|
|
|
|
if(pPanels)
|
|
{
|
|
pPanels->lockLayout();
|
|
|
|
//
|
|
// For each panel in our window, show or hide it depending on if it is visible within our place.
|
|
//
|
|
for(int i=0; i<pPanels->GetSize(); i++)
|
|
{
|
|
CMarsPanel* pPanel = (*pPanels)[i];
|
|
|
|
if(pPanel)
|
|
{
|
|
LPCWSTR pwszName = pPanel->GetName();
|
|
VARIANT_BOOL bMakeVisible = VARIANT_FALSE;
|
|
|
|
for(int j=0; j<m_PlacePanels.GetSize(); j++)
|
|
{
|
|
CPlacePanel* pPlacePanel = m_PlacePanels[j];
|
|
|
|
if(pPlacePanel && StrEqlW(pwszName, pPlacePanel->GetName()))
|
|
{
|
|
// Let the place panel decide whether it should be shown
|
|
bMakeVisible = pPlacePanel->ShowOnTransition( pPanel );
|
|
break;
|
|
}
|
|
}
|
|
|
|
pPanel->put_visible( bMakeVisible );
|
|
}
|
|
}
|
|
|
|
pPanels->unlockLayout();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CMarsPlace::AddPanel(CPlacePanel *pPlacePanel)
|
|
{
|
|
ATLASSERT(!IsPassive());
|
|
|
|
m_PlacePanels.Add(pPlacePanel);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT local_TranslateFocusAccelerator(MSG *pMsg, CComPtr<IOleInPlaceActiveObject> pObj)
|
|
{
|
|
// identify Ctrl-Tab and F6 keystrokes
|
|
BOOL isKeydown = (pMsg && (pMsg->message == WM_KEYDOWN));
|
|
BOOL isCtrlTab = (isKeydown && (pMsg->wParam == VK_TAB) &&
|
|
(::GetKeyState( VK_CONTROL ) & 0x8000));
|
|
BOOL isF6 = (isKeydown && (pMsg->wParam == VK_F6));
|
|
|
|
// map F6 and Ctrl-TAB to TAB for the Control in panel can set
|
|
// focus to the first item
|
|
HRESULT hr = S_FALSE;
|
|
|
|
if (isF6 || isCtrlTab)
|
|
{
|
|
BYTE bState[256];
|
|
if (isCtrlTab)
|
|
{
|
|
::GetKeyboardState(bState);
|
|
bState[VK_CONTROL] &= 0x7F;
|
|
::SetKeyboardState(bState);
|
|
}
|
|
|
|
pMsg->wParam = VK_TAB;
|
|
hr = pObj->TranslateAccelerator(pMsg);
|
|
|
|
if (isCtrlTab)
|
|
{
|
|
bState[VK_CONTROL] |= 0x80;
|
|
::SetKeyboardState(bState);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CMarsPlace::TranslateAccelerator(MSG *pMsg)
|
|
{
|
|
FAIL_AFTER_PASSIVATE();
|
|
|
|
HRESULT hr = S_FALSE;
|
|
CMarsPanel *pActivePanel = m_spPlaceCollection->Document()->GetPanels()->ActivePanel();
|
|
|
|
// First give the active panel a shot.
|
|
if(pActivePanel)
|
|
{
|
|
pActivePanel->ResetTabCycle();
|
|
|
|
hr = pActivePanel->TranslateAccelerator(pMsg);
|
|
|
|
// Trident will return S_OK but we may have decided
|
|
// we want it. This happens when you tab past the last
|
|
// focusable item on the page.
|
|
if(pActivePanel->GetTabCycle())
|
|
{
|
|
pActivePanel->ResetTabCycle();
|
|
|
|
hr = S_FALSE;
|
|
}
|
|
}
|
|
|
|
if(S_OK != hr)
|
|
{
|
|
int i;
|
|
int nCurrent = -1;
|
|
int nPanels = m_PlacePanels.GetSize();
|
|
|
|
ATLASSERT(nPanels > 0);
|
|
|
|
if(pActivePanel)
|
|
{
|
|
for (i = 0; i < nPanels; i++)
|
|
{
|
|
if(StrEql(pActivePanel->GetName(), m_PlacePanels[i]->GetName()))
|
|
{
|
|
nCurrent = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// This will force us to start at 0 in the for loop below
|
|
nCurrent = nPanels;
|
|
}
|
|
|
|
CMarsPanel *pPanel;
|
|
|
|
if(IsGlobalKeyMessage(pMsg))
|
|
{
|
|
// Now give the rest of the panels a crack at it
|
|
for (i = 0; (i < nPanels) && (S_OK != hr); i++)
|
|
{
|
|
nCurrent++;
|
|
|
|
if(nCurrent >= nPanels)
|
|
{
|
|
nCurrent = 0;
|
|
}
|
|
|
|
pPanel = m_spMarsDocument->GetPanels()->FindPanel(m_PlacePanels[nCurrent]->GetName());
|
|
|
|
if(pPanel != pActivePanel)
|
|
{
|
|
hr = pPanel->TranslateAccelerator(pMsg);
|
|
}
|
|
else
|
|
{
|
|
// We're right back where we started
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int nTab = IsVK_TABCycler(pMsg);
|
|
|
|
if(nTab)
|
|
{
|
|
int nCount = nPanels;
|
|
|
|
if(pActivePanel)
|
|
{
|
|
nCurrent += nTab;
|
|
if(nCurrent < 0)
|
|
{
|
|
nCurrent = nPanels - 1;
|
|
}
|
|
else if(nCurrent >= nPanels)
|
|
{
|
|
nCurrent = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If there is no active panel then let's tab to the first one
|
|
nCurrent = 0;
|
|
}
|
|
|
|
while(nCount-- > 0)
|
|
{
|
|
pPanel = m_spMarsDocument->GetPanels()->FindPanel(m_PlacePanels[nCurrent]->GetName());
|
|
if(pPanel && pPanel->IsVisible())
|
|
{
|
|
CComPtr<IOleInPlaceActiveObject> pObj;
|
|
|
|
if(SUCCEEDED(pPanel->Window()->QueryControl( IID_IOleInPlaceActiveObject, (LPVOID*)&pObj )))
|
|
{
|
|
pPanel->ResetTabCycle();
|
|
|
|
hr = pObj->TranslateAccelerator( pMsg );
|
|
|
|
if(hr == S_FALSE)
|
|
{
|
|
// The WebOC behaves a little differently -- go figure :)
|
|
// It seems to rely on getting the TranslateAccelerator call to do the
|
|
// right UI activation the very first time.
|
|
if(pPanel->IsWebBrowser())
|
|
{
|
|
pPanel->activate();
|
|
|
|
// Fix up the hwnd so the panel will think it was intended for it.
|
|
pMsg->hwnd = pPanel->Window()->m_hWnd;
|
|
hr = pPanel->TranslateAccelerator(pMsg);
|
|
if(hr == S_OK)
|
|
{
|
|
local_TranslateFocusAccelerator(pMsg, pObj);
|
|
break;
|
|
}
|
|
|
|
// REVIEW -- this happens when we tab into a panel with no place to
|
|
// tab to. IOW, it has nothing which can take the focus so we might
|
|
// want to loop until we find someone who does.
|
|
if(pPanel->GetTabCycle())
|
|
{
|
|
pPanel->ResetTabCycle();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(pPanel->IsWebBrowser () ||
|
|
pPanel->IsCustomControl() )
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(pPanel->GetTabCycle() == false)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pPanel->ResetTabCycle();
|
|
|
|
hr = local_TranslateFocusAccelerator(pMsg, pObj);
|
|
|
|
if (hr == S_OK && pPanel->GetTabCycle() == false)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
nCurrent += nTab;
|
|
if(nCurrent < 0)
|
|
{
|
|
nCurrent = nPanels - 1;
|
|
}
|
|
else if(nCurrent >= nPanels)
|
|
{
|
|
nCurrent = 0;
|
|
}
|
|
}
|
|
|
|
if(pPanel && pPanel != pActivePanel)
|
|
{
|
|
m_spMarsDocument->GetPanels()->SetActivePanel( pPanel, TRUE );
|
|
}
|
|
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
void CMarsPlace::SaveLayout()
|
|
{
|
|
if(IsPassive()) return;
|
|
|
|
|
|
//
|
|
// For each panel in our window, save the layout and flag if it's present in the current place.
|
|
//
|
|
CPanelCollection *pPanels = m_spMarsDocument->GetPanels();
|
|
for(int i=0; i<pPanels->GetSize(); i++)
|
|
{
|
|
CMarsPanel* pPanel = (*pPanels)[i];
|
|
|
|
if(pPanel)
|
|
{
|
|
LPCWSTR pwszName = pPanel->GetName();
|
|
BOOL fPresent = FALSE;
|
|
|
|
for(int j=0; j<m_PlacePanels.GetSize(); j++)
|
|
{
|
|
CPlacePanel* pPlacePanel = m_PlacePanels[j];
|
|
if(pPlacePanel && StrEqlW(pwszName, pPlacePanel->GetName()))
|
|
{
|
|
pPlacePanel->SaveLayout(pPanel);
|
|
fPresent = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pPanel->SetPresenceInPlace( fPresent );
|
|
}
|
|
}
|
|
}
|
|
|
|
//==================================================================
|
|
//
|
|
// CPlaceCollection implementation
|
|
//
|
|
//==================================================================
|
|
|
|
CPlaceCollection::CPlaceCollection(CMarsDocument *pMarsDocument)
|
|
{
|
|
m_spMarsDocument = pMarsDocument;
|
|
m_lCurrentPlaceIndex = -1;
|
|
m_lOldPlaceIndex = -1;
|
|
}
|
|
|
|
void CPlaceCollection::FreePlaces()
|
|
{
|
|
for (int i=0; i<GetSize(); i++)
|
|
{
|
|
(*this)[i]->Passivate();
|
|
(*this)[i]->Release();
|
|
}
|
|
|
|
RemoveAll();
|
|
}
|
|
|
|
HRESULT CPlaceCollection::DoPassivate()
|
|
{
|
|
FreePlaces();
|
|
|
|
m_spMarsDocument.Release();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
IMPLEMENT_ADDREF_RELEASE(CPlaceCollection);
|
|
|
|
STDMETHODIMP CPlaceCollection::QueryInterface(REFIID iid, void ** ppvObject)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if(API_IsValidWritePtr(ppvObject))
|
|
{
|
|
if((iid == IID_IUnknown ) ||
|
|
(iid == IID_IDispatch ) ||
|
|
(iid == IID_IMarsPlaceCollection) )
|
|
{
|
|
AddRef();
|
|
*ppvObject = SAFECAST(this, IMarsPlaceCollection *);
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
*ppvObject = NULL;
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// IMarsPlaceCollection
|
|
STDMETHODIMP CPlaceCollection::place(LPWSTR pwszName, IMarsPlace **ppMarsPlace)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if(API_IsValidString(pwszName) && API_IsValidWritePtr(ppMarsPlace))
|
|
{
|
|
*ppMarsPlace = NULL;
|
|
|
|
if(VerifyNotPassive(&hr))
|
|
{
|
|
CMarsPlace *pPlace;
|
|
|
|
if(SUCCEEDED(GetPlace(pwszName, &pPlace)))
|
|
{
|
|
(*ppMarsPlace) = SAFECAST(pPlace, IMarsPlace *);
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CPlaceCollection::get_currentPlace(/* out, retval */ IMarsPlace **ppMarsPlace)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if(API_IsValidWritePtr(ppMarsPlace))
|
|
{
|
|
*ppMarsPlace = NULL;
|
|
|
|
if(VerifyNotPassive(&hr))
|
|
{
|
|
if(m_lCurrentPlaceIndex != -1)
|
|
{
|
|
CMarsPlace *pPlace = (*this)[m_lCurrentPlaceIndex];
|
|
|
|
*ppMarsPlace = SAFECAST(pPlace, IMarsPlace *);
|
|
pPlace->AddRef();
|
|
}
|
|
|
|
hr = (*ppMarsPlace) ? S_OK : S_FALSE;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
void CPlaceCollection::OnPanelReady()
|
|
{
|
|
// First see if we need to bother with this
|
|
if(m_lCurrentPlaceIndex != m_lOldPlaceIndex)
|
|
{
|
|
CPlacePanelCollection& PlacePanels = GetCurrentPlace()->m_PlacePanels;
|
|
CPanelCollection* pPanels = m_spMarsDocument->GetPanels();
|
|
|
|
int nPanels = PlacePanels.GetSize();
|
|
int nPanelsReady = 0;
|
|
|
|
for(int i = 0; i < nPanels; i++)
|
|
{
|
|
CMarsPanel *pPanel = pPanels->FindPanel(PlacePanels[i]->GetName());
|
|
|
|
if(pPanel && (!pPanel->IsTrusted() || (pPanel->GetReadyState()==READYSTATE_COMPLETE)))
|
|
{
|
|
nPanelsReady++;
|
|
}
|
|
}
|
|
|
|
if(nPanelsReady >= nPanels)
|
|
{
|
|
if(m_lCurrentPlaceIndex != m_lOldPlaceIndex)
|
|
{
|
|
m_spMarsDocument->MarsWindow()->OnTransitionComplete();
|
|
m_lOldPlaceIndex = m_lCurrentPlaceIndex;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP CPlaceCollection::transitionTo(/* in */ BSTR bstrName)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if(API_IsValidString(bstrName))
|
|
{
|
|
if(VerifyNotPassive())
|
|
{
|
|
hr = S_FALSE;
|
|
|
|
long lNewPlaceIndex;
|
|
|
|
if(SUCCEEDED(FindPlaceIndex(bstrName, &lNewPlaceIndex)))
|
|
{
|
|
if(m_lCurrentPlaceIndex != lNewPlaceIndex)
|
|
{
|
|
if(m_lCurrentPlaceIndex >= 0)
|
|
{
|
|
GetCurrentPlace()->SaveLayout();
|
|
}
|
|
|
|
if(m_spMarsDocument->MarsWindow()->IsEventCancelled() == VARIANT_FALSE)
|
|
{
|
|
// Layout panels for new place
|
|
m_lCurrentPlaceIndex = lNewPlaceIndex;
|
|
(*this)[m_lCurrentPlaceIndex]->DoTransition();
|
|
OnPanelReady();
|
|
}
|
|
|
|
hr = S_OK;
|
|
}
|
|
|
|
m_spMarsDocument->MarsWindow()->NotifyHost( MARSHOST_ON_PLACE_TRANSITION_DONE, SAFECAST(GetCurrentPlace(), IMarsPlace *), 0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CPlaceCollection::FindPlaceIndex(LPCWSTR pwszName, long *plIndex)
|
|
{
|
|
ATLASSERT(!IsPassive());
|
|
|
|
int i;
|
|
|
|
*plIndex = -1;
|
|
|
|
for (i=0; i<GetSize(); i++)
|
|
{
|
|
if(pwszName == NULL || StrEqlW(pwszName, (*this)[i]->GetName()))
|
|
{
|
|
*plIndex = (long)i;
|
|
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT CPlaceCollection::GetPlace(LPCWSTR pwszName, /*optional*/ CMarsPlace **ppPlace)
|
|
{
|
|
ATLASSERT(!IsPassive());
|
|
|
|
long lIndex;
|
|
HRESULT hrRet;
|
|
|
|
if(ppPlace)
|
|
{
|
|
*ppPlace = NULL;
|
|
}
|
|
|
|
if(SUCCEEDED(hrRet = FindPlaceIndex(pwszName, &lIndex)))
|
|
{
|
|
if(ppPlace)
|
|
{
|
|
*ppPlace = (*this)[lIndex];
|
|
(*ppPlace)->AddRef();
|
|
}
|
|
}
|
|
|
|
return hrRet;
|
|
}
|
|
|
|
// Called by our XML parser only
|
|
HRESULT CPlaceCollection::AddPlace(LPCWSTR pwszName, CMarsPlace **ppPlace)
|
|
{
|
|
*ppPlace = NULL;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if(VerifyNotPassive(&hr))
|
|
{
|
|
if(SUCCEEDED(GetPlace(pwszName, NULL)))
|
|
{
|
|
// Place of this name already exists
|
|
return E_FAIL;
|
|
}
|
|
|
|
CMarsPlace *pPlace = new CMarsPlace(this, m_spMarsDocument);
|
|
|
|
if(pPlace)
|
|
{
|
|
if(Add(pPlace))
|
|
{
|
|
pPlace->Init(pwszName);
|
|
pPlace->AddRef();
|
|
*ppPlace = pPlace;
|
|
}
|
|
else
|
|
{
|
|
pPlace->Release();
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|