536 lines
14 KiB
C++
536 lines
14 KiB
C++
/*
|
|
|
|
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;
|
|
}
|
|
|
|
|