/*
copyright (c) 1992 Microsoft Corporation
Module Name:
ddeStg.cpp
Abstract:
This module contains the DdeObject::PersistStg and
DdeObject::ProxyManager methods
Author:
Srini Koppolu (srinik) 22-June-1992
Jason Fuller (jasonful) 24-July-1992
*/
#include "ddeproxy.h"
ASSERTDATA
/*
* IMPLEMENTATION of CPersistStgImpl methods
*
*/
STDUNKIMPL_FORDERIVED(DdeObject, PersistStgImpl)
#pragma SEG(CDdeObject_CPersistStgImpl_GetClassID)
STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::GetClassID (CLSID FAR* pClassID)
{
*pClassID = m_pDdeObject->m_clsid;
return NOERROR;
}
#pragma SEG(CDdeObject_CPersistStgImpl_IsDirty)
STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::IsDirty ()
{
return NOERROR;
}
#pragma SEG(CDdeObject_CPersistStgImpl_InitNew)
STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::InitNew
(IStorage FAR* pstg)
{
HRESULT hres;
intrDebugOut((DEB_ITRACE,
"DdeObejct::InitNew(%x,pstg=%x)\n",
this,
pstg));
if (hres = m_pDdeObject->PostSysCommand (m_pDdeObject->m_pSysChannel,
(LPSTR)&achStdNewDocument,
TRUE))
return hres;
if (hres = m_pDdeObject->m_ProxyMgr.Connect (IID_NULL, CLSID_NULL))
return hres;
RetErr (m_pDdeObject->TermConv (m_pDdeObject->m_pSysChannel));
if (m_pDdeObject->m_pstg)
{
m_pDdeObject->m_pstg->Release();
}
m_pDdeObject->m_pstg = pstg;
pstg->AddRef();
return hres;
}
#pragma SEG(CDdeObject_CPersistStgImpl_Load)
STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::Load (IStorage FAR* pstg)
{
LPSTR lpBuf=NULL;
HANDLE hDdePoke = NULL;
DWORD dwSize;
CStmBufRead StmRead;
CStmBufRead StmReadItem;
HRESULT hresult;
intrDebugOut((DEB_ITRACE,"CDdeObject::Load(%x,pstg=%x)\n",this,pstg));
{
if (hresult = StmRead.OpenStream(pstg, OLE10_NATIVE_STREAM))
{
intrDebugOut((DEB_ITRACE,
"::Load(%x) OpenStream failed(%x)\n",
this,
hresult));
return hresult;
}
if (hresult = StmRead.Read(&dwSize, sizeof(DWORD)))
{
intrDebugOut((DEB_ITRACE,
"::Load(%x) StRead failed(%x)\n",
this,
hresult));
goto errRtn;
}
lpBuf = wAllocDdePokeBlock (dwSize, g_cfNative, &hDdePoke);
if (lpBuf == NULL)
{
intrDebugOut((DEB_ITRACE,
"::Load(%x) wAllocDdePokeBlock failed(%x)\n",
this,
hresult));
hresult = E_OUTOFMEMORY;
goto errRtn;
}
if (hresult = StmRead.Read(lpBuf, dwSize))
{
intrDebugOut((DEB_ITRACE,
"::Load(%x) StRead of cfNative failed(%x)\n",
this,
hresult));
goto errRtn;
}
if (m_pDdeObject->m_hNative)
{
GlobalFree (m_pDdeObject->m_hNative);
}
m_pDdeObject->m_hNative = wNewHandle (lpBuf, dwSize);
if (m_pDdeObject->m_hNative == NULL)
{
intrDebugOut((DEB_ITRACE,
"::Load(%x) m_hNative NULL\n",
this));
}
}
GlobalUnlock (hDdePoke); // done with lpBuf
if (hresult = m_pDdeObject->PostSysCommand (m_pDdeObject->m_pSysChannel,
(LPSTR)&achStdEditDocument,
FALSE))
{
intrDebugOut((DEB_ITRACE,
"::Load(%x) PostSysCommand %s failed (%x)\n",
this,
&achStdEditDocument,
hresult));
goto errRtn;
}
// Read Item Name, if there is one
if (NOERROR == StmReadItem.OpenStream(pstg, OLE10_ITEMNAME_STREAM))
{
LPSTR szItemName = NULL;
ErrRtnH (ReadStringStreamA (StmReadItem, &szItemName));
m_pDdeObject->ChangeItem (szItemName);
PubMemFree(szItemName);
}
if (hresult = m_pDdeObject->m_ProxyMgr.Connect (IID_NULL, CLSID_NULL))
{
intrDebugOut((DEB_ITRACE,
"::Load(%x) ProxyMgr.Connect failed(%x)\n",
this,
hresult));
goto errRtn;
}
if ((hresult = m_pDdeObject->Poke(m_pDdeObject->m_aItem, hDdePoke))
!= NOERROR)
{
intrDebugOut((DEB_ITRACE,
"::Load(%x) Poke failed(%x)\n",
this,
hresult));
// the Poke calls frees the Poke data even in case of failure.
#ifdef LATER
if (hresult = m_pDdeObject->Execute (m_pDdeObject->m_pDocChannel,
wNewHandle ((LPSTR)achStdCloseDocument,sizeof(achStdCloseDocument)));
goto errDoc;
#elseif
goto errDoc;
#endif
}
hresult = m_pDdeObject->TermConv (m_pDdeObject->m_pSysChannel);
if (hresult != NOERROR)
{
intrDebugOut((DEB_ITRACE,
"::Load(%x) TermConv on SysChannel failed(%x)\n",
this,
hresult));
goto errRtn;
}
if (m_pDdeObject->m_pstg)
{
m_pDdeObject->m_pstg->Release();
}
m_pDdeObject->m_pstg = pstg;
pstg->AddRef();
goto LExit;
errRtn:
if (hDdePoke)
GlobalFree (hDdePoke);
if (m_pDdeObject->m_pDocChannel)
m_pDdeObject->TermConv (m_pDdeObject->m_pDocChannel);
LExit:
StmReadItem.Release();
StmRead.Release();
intrDebugOut((DEB_ITRACE,"::Load(%x) returning (%x)\n",this,hresult));
return hresult;
}
#pragma SEG(CDdeObject_CPersistStgImpl_Save)
STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::Save
(IStorage FAR* pstgSave, BOOL fSameAsLoad)
{
intrDebugOut((DEB_ITRACE,
"DdeObject::Save(%x,pstgSave=%x)\n",
this,
pstgSave));
HRESULT hresult=NOERROR;
if (m_pDdeObject->m_fUpdateOnSave
&& (m_pDdeObject->m_clsid != CLSID_Package
|| m_pDdeObject->m_hNative == NULL))
{
// Get latest data from server, if it is not shutting down
// or telling us to Save, in which case it just gave us data.
// (If it is shutting down, it probably won't respond.
// Draw does respond, but gives bad data.)
// Packager gives truncated native data (header info with no
// actual embedded file) if you DDE_REQUEST it. Bug 3103
m_pDdeObject->Update (FALSE);
}
if (m_pDdeObject->m_hNative == NULL)
{
// we still have nothing to save
return ResultFromScode (E_BLANK);
}
hresult = m_pDdeObject->Save (pstgSave);
Puts ("PersistStg::Save done\n");
return hresult;
}
#pragma SEG(CDdeObject_CPersistStgImpl_SaveCompleted)
STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::SaveCompleted
(IStorage FAR* pstgNew)
{
intrDebugOut((DEB_ITRACE,
"DdeObejct::SaveCompleted(%x,pstgNew=%x)\n",
this,
pstgNew));
RetZ (m_pDdeObject->m_pOleAdvHolder);
m_pDdeObject->m_pOleAdvHolder->SendOnSave();
if (pstgNew)
{
if (m_pDdeObject->m_pstg)
m_pDdeObject->m_pstg->Release();
m_pDdeObject->m_pstg = pstgNew;
pstgNew->AddRef();
}
return NOERROR;
}
#pragma SEG(CDdeObject_CPersistStgImpl_HandsOffStorage)
STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::HandsOffStorage(void)
{
intrDebugOut((DEB_ITRACE,"DdeObejct::HandsOffStorage(%x)\n",this));
if (m_pDdeObject->m_pstg)
{
m_pDdeObject->m_pstg->Release();
m_pDdeObject->m_pstg = NULL;
}
return NOERROR;
}
/*
* IMPLEMENTATION of CProxyManagerImpl methods
*
*/
STDUNKIMPL_FORDERIVED(DdeObject, ProxyManagerImpl)
#pragma SEG(CDdeObject_CProxyManagerImpl_CreateServer)
STDMETHODIMP NC(CDdeObject, CProxyManagerImpl)::CreateServer(REFCLSID rclsid,
DWORD clsctx,
void *pv)
{
intrDebugOut((DEB_ITRACE,"DdeObejct::CreateServer(%x)\n",this));
HRESULT hresult = NOERROR;
if (m_pDdeObject->m_pSysChannel)
{
intrDebugOut((DEB_ITRACE,
"::CreateServer(%x)m_pSysChannel exists\n",
this));
return NOERROR;
}
if (m_pDdeObject->m_aExeName == NULL)
{
intrDebugOut((DEB_ITRACE,
"::CreateServer(%x) Class Not Registered\n",
this));
return(REGDB_E_CLASSNOTREG);
}
if (!m_pDdeObject->AllocDdeChannel(&m_pDdeObject->m_pSysChannel,SYS_CLASSA))
{
intrDebugOut((DEB_ITRACE,
"::CreateServer(%x)AllocDdeChannel is failing\n",
this));
return ReportResult(0, E_OUTOFMEMORY,0,0);
}
if (!m_pDdeObject->InitSysConv())
{
if (!(m_pDdeObject->LaunchApp()))
{
intrDebugOut((DEB_IERROR,"::CreateServer Could not launch app\n"));
hresult = ResultFromScode (CO_E_APPNOTFOUND);
goto errRtn;
}
if (!m_pDdeObject->InitSysConv())
{
intrDebugOut((DEB_IERROR,"::CreateServer Second init failed\n"));
hresult = ResultFromScode (CO_E_APPDIDNTREG);
goto errRtn;
}
}
return NOERROR;
errRtn:
intrDebugOut((DEB_ITRACE,"DdeObejct::CreateServer(%x) is failing(%x)\n",this,hresult));
m_pDdeObject->DeleteChannel (m_pDdeObject->m_pSysChannel);
Assert (hresult != NOERROR); // This is an error path
return hresult;
}
#pragma SEG(CDdeObject_CProxyManagerImpl_Connect)
STDMETHODIMP NC(CDdeObject, CProxyManagerImpl)::Connect(OID oid, REFCLSID rclsid)
{
intrDebugOut((DEB_ITRACE,"DdeObject::Connect(%x)\n",this));
if (m_pDdeObject->m_pDocChannel)
return NOERROR;
if (!m_pDdeObject->AllocDdeChannel (&m_pDdeObject->m_pDocChannel,CLIENT_CLASSA))
{
intrDebugOut((DEB_ITRACE,
"::Connect(%x) AllocDdeChannel failed, return E_OUTOFMEMORY\n",
this));
return ReportResult(0, E_OUTOFMEMORY,0,0);
}
// Bug 3701
m_pDdeObject->m_fDidSendOnClose = FALSE;
if (wInitiate (m_pDdeObject->m_pDocChannel, m_pDdeObject->m_aClass,
m_pDdeObject->m_aTopic))
{
return NOERROR;
}
intrDebugOut((DEB_ITRACE,"::Connect(%x) wInitiate failed\n",this));
m_pDdeObject->DeleteChannel (m_pDdeObject->m_pDocChannel);
return ResultFromScode (E_FAIL);
}
#pragma SEG(CDdeObject_CProxyManagerImpl_LockConnection)
STDMETHODIMP NC(CDdeObject, CProxyManagerImpl)::LockConnection(BOOL fLock, BOOL fLastUnlockReleases)
{
intrDebugOut((DEB_ITRACE,
"DdeObject::LockConnection(%x,fLock=%x,fLastUnlockReleases=%x)\n",
this,
fLock,
fLastUnlockReleases));
if (fLock)
m_pDdeObject->m_cLocks++;
else
{
if (m_pDdeObject->m_cLocks!=0 && 0 == --m_pDdeObject->m_cLocks &&
fLastUnlockReleases && !m_pDdeObject->m_fVisible)
(void)m_pDdeObject->m_Ole.Close (OLECLOSE_SAVEIFDIRTY);
}
return NOERROR;
}
#ifdef NOTNEEDED
#pragma SEG(CDdeObject_CProxyManagerImpl_GetClassID)
STDMETHODIMP_(void) NC(CDdeObject, CProxyManagerImpl)::GetClassID(CLSID FAR* pClsid)
{
*pClsid = m_pDdeObject->m_clsid;
}
#pragma SEG(CDdeObject_CProxyManagerImpl_GetOID)
STDMETHODIMP_(OID) NC(CDdeObject, CProxyManagerImpl)::GetOID()
{
if (m_pDdeObject->m_pSysChannel)
return (OID) m_pDdeObject->m_pSysChannel;
if (m_pDdeObject->m_pDocChannel)
return (OID) m_pDdeObject->m_pDocChannel;
return NULL;
}
#endif
#pragma SEG(CDdeObject_CProxyManagerImpl_IsConnected)
STDMETHODIMP_(BOOL) NC(CDdeObject, CProxyManagerImpl)::IsConnected(void)
{
return m_pDdeObject->m_pDocChannel != NULL;
}
#pragma SEG(CDdeObject_CProxyManagerImpl_EstablishIID)
STDMETHODIMP NC(CDdeObject, CProxyManagerImpl)::EstablishIID(REFIID iid, LPVOID FAR* ppv)
{
// REVIEW: this is correct, but can we be smarter like in the real PM?
return QueryInterface(iid, ppv);
}
#pragma SEG(wTerminateIsComing)
INTERNAL_(BOOL) wTerminateIsComing (LPDDE_CHANNEL pChannel)
{
MSG msg;
return SSPeekMessage (&msg, pChannel->hwndCli, 0, 0, PM_NOREMOVE)
&& msg.message == WM_DDE_TERMINATE
&& (HWND)msg.wParam==pChannel->hwndSvr;
}
#pragma SEG(CDdeObject_CProxyManagerImpl_Disconnect)
STDMETHODIMP_(void) NC(CDdeObject, CProxyManagerImpl)::Disconnect()
{
intrDebugOut((DEB_ITRACE,"DdeObject::Disonnect(%x)\n",this));
#define p m_pDdeObject
if (m_pDdeObject->m_pDocChannel)
{
BOOL fTermComing = wTerminateIsComing (m_pDdeObject->m_pDocChannel);
if ((!m_pDdeObject->m_fNoStdCloseDoc
|| (!m_pDdeObject->m_fWasEverVisible // invisible update or
&& !m_pDdeObject->m_fDidGetObject // link from file case.
&& m_pDdeObject->m_fDidStdOpenDoc)) // only do StdClose if did StdOpen
&& !m_pDdeObject->m_fDidStdCloseDoc
&& !fTermComing)
{
m_pDdeObject->Execute (m_pDdeObject->m_pDocChannel,
wNewHandle ((LPSTR)&achStdCloseDocument,sizeof(achStdCloseDocument)),
/*fStdClose*/TRUE,
/*fWait*/TRUE,
/*fDetectTerminate*/TRUE);
m_pDdeObject->m_fDidStdCloseDoc = TRUE;
}
if (!m_pDdeObject->m_fDidSendOnClose /*|| fTermComing*/)
{
// if we did not call SendOnClose() then Disconnect() was called
// by a Release method, not by SendOnClose().
// This happens when user deletes object in container.
BOOL fVisible = m_pDdeObject->m_fWasEverVisible; // TermConv clears this flag
m_pDdeObject->TermConv (m_pDdeObject->m_pDocChannel);
if (!fVisible)
m_pDdeObject->MaybeUnlaunchApp();
}
}
if (m_pDdeObject->m_pSysChannel)
{
intrDebugOut((DEB_IWARN,"Terminating system conversation in Disconnect()\n"));
// This should never happen, I think.
m_pDdeObject->TermConv (m_pDdeObject->m_pSysChannel);
}
#undef p
}
//
// There is no ServerHandler with DDE servers. Therefore, this function returns E_NOTIMPL
// back to the handler.
//
STDMETHODIMP NC(CDdeObject, CProxyManagerImpl)::CreateServerWithHandler (REFCLSID rclsid, DWORD clsctx, void *pv,
REFCLSID rclsidHandler, IID iidSrv, void **ppv,
IID iidClnt, void *pClientSiteInterface)
{
return E_NOTIMPL;
}