NT4/private/ole32/com/remote/dde/client/ddeoo.cxx
2020-09-30 17:12:29 +02:00

771 lines
19 KiB
C++

/*
ddeoo.cpp
DDE Ole Object
copyright (c) 1992 Microsoft Corporation
Module Name:
ddeoo.cpp
Abstract:
This module contains the methods for DdeObject::OleObject
Author:
Jason Fuller (jasonful) 24-July-1992
*/
#include "ddeproxy.h"
#include <limits.h>
ASSERTDATA
//
// OleObject methods
//
STDUNKIMPL_FORDERIVED(DdeObject, OleObjectImpl)
STDMETHODIMP NC(CDdeObject,COleObjectImpl)::SetClientSite
(IOleClientSite FAR* pClientSite)
{
intrDebugOut((DEB_ITRACE,
"CDdeObject::SetClientSite(%x,pClientSite=%x)\n",
this,
pClientSite));
ChkD (m_pDdeObject);
if (m_pDdeObject->m_pOleClientSite)
m_pDdeObject->m_pOleClientSite->Release();
// we've decided to keep the pointer that's been passed to us. So we
// must AddRef()
if (m_pDdeObject->m_pOleClientSite = pClientSite)
pClientSite->AddRef();
// this pointer need not be sent to the server, because we will always
// send our &m_MyDataSite as the client site
return NOERROR;
}
STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetClientSite
(IOleClientSite FAR* FAR* ppClientSite)
{
intrDebugOut((DEB_ITRACE,
"CDdeObject::GetClientSite(%x)\n",
this));
ChkD (m_pDdeObject);
// we've been asked to give the pointer so we should AddRef()
if (*ppClientSite = m_pDdeObject->m_pOleClientSite)
m_pDdeObject->m_pOleClientSite->AddRef();
return NOERROR;
}
STDMETHODIMP NC(CDdeObject,COleObjectImpl)::EnumVerbs
(IEnumOLEVERB FAR* FAR* ppenumOleVerb)
{
intrDebugOut((DEB_ITRACE,
"CDdeObject::EnumVerbs(%x)\n",
this));
ChkD (m_pDdeObject);
return ReportResult(0, OLE_S_USEREG, 0, 0);
}
STDMETHODIMP NC(CDdeObject,COleObjectImpl)::Update
( void )
{
HRESULT hr;
intrDebugOut((DEB_ITRACE,
"CDdeObject::Update(%x)\n",
this));
ChkD (m_pDdeObject);
hr = m_pDdeObject->Update(TRUE);
if (hr == NOERROR)
{
hr = m_pDdeObject->Save(m_pDdeObject->m_pstg);
}
return hr;
}
STDMETHODIMP NC(CDdeObject,COleObjectImpl)::IsUpToDate
( void )
{
intrDebugOut((DEB_ITRACE,
"CDdeObject::IsUpToDate(%x)\n",
this));
ChkD (m_pDdeObject);
// There is no way to know if a 1.0 server has edited its embedded
// object, so we assume it has, to be on the safe side.
return ResultFromScode (m_pDdeObject->m_ulObjType==OT_EMBEDDED
? S_FALSE : S_OK);
}
STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetUserClassID
(CLSID FAR* pClsid)
{
intrDebugOut((DEB_ITRACE,
"CDdeObject::GetUserClassID(%x)\n",
this));
*pClsid = m_pDdeObject->m_clsid;
return NOERROR;
}
STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetUserType
(DWORD dwFormOfType,
LPOLESTR * pszUserType)
{
intrDebugOut((DEB_ITRACE,
"CDdeObject::GetUserType(%x)\n",
this));
return ReportResult (0, OLE_S_USEREG, 0, 0);
}
STDMETHODIMP NC(CDdeObject,COleObjectImpl)::SetExtent
( DWORD dwAspect, LPSIZEL lpsizel)
{
intrDebugOut((DEB_ITRACE,
"CDdeObject::SetExtent(%x)\n",
this));
HANDLE hDdePoke;
LPRECT16 lprc;
ChkD (m_pDdeObject);
Puts ("OleObject::SetExtent\n");
if (!(dwAspect // at least one bit
&& !(dwAspect & (dwAspect-1)) // exactly one bit
&& (dwAspect & DVASPECT_CONTENT))) // a bit we support
{
return ResultFromScode (DV_E_DVASPECT);
}
#ifdef OLD
m_pDdeObject->m_cxContentExtent = lpsizel->cx;
m_pDdeObject->m_cyContentExtent = lpsizel->cy;
#endif
if (!m_pDdeObject->m_pDocChannel)
{
return OLE_E_NOTRUNNING;
}
lprc = (LPRECT16) wAllocDdePokeBlock (sizeof(RECT16), g_cfBinary, &hDdePoke);
lprc->left = lprc->right = (SHORT) min(INT_MAX,lpsizel->cx);
lprc->top = lprc->bottom= (SHORT) min(INT_MAX,lpsizel->cy);
aStdDocDimensions = GlobalAddAtom (OLESTR("StdDocDimensions"));
intrAssert(wIsValidAtom(aStdDocDimensions));
GlobalUnlock (hDdePoke);
return m_pDdeObject->Poke(aStdDocDimensions, hDdePoke);
}
STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetExtent
( DWORD dwAspect, LPSIZEL lpsizel)
{
intrDebugOut((DEB_ITRACE,
"CDdeObject::GetExtent(%x)\n",
this));
ChkD (m_pDdeObject);
#ifdef OLD
VDATEPTROUT (lpsizel, SIZEL);
if (!(dwAspect // at least one bit
&& !(dwAspect & (dwAspect-1)) // exactly one bit
&& !(dwAspect & (DVASPECT_CONTENT | DVASPECT_ICON)))) // a bit we support
{
return ResultFromScode (DV_E_DVASPECT);
}
if (dwAspect & DVASPECT_CONTENT)
{
lpsizel->cx = m_pDdeObject->m_cxContentExtent;
lpsizel->cy = m_pDdeObject->m_cyContentExtent;
}
return NOERROR;
#endif
return ResultFromScode(E_NOTIMPL);
}
//+---------------------------------------------------------------------------
//
// Method: CDdeObject::DoVerb
//
// Synopsis: Send the server a message asking it to do a verb.
//
// Effects: OLE1.0 servers only know how to do a couple of
// verbs. Specifically, it will respond to PRIMARY,
// HIDE, OPEN, and SHOW. All others return error
//
//
// Arguments: [iVerb] -- Verb number
// [lpmsg] -- Window message (ignored)
// [pActiveSite] -- ActiveSite (ignored)
// [lindex] -- Index (ignored)
// [hwndParent] -- (ignored)
// [lprcPosRect] -- (ignored)
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: 5-12-94 kevinro Created
//
// Notes:
//
// ANSI ALERT!
//
// The server is going to accept a command string from us. This string
// needs to be done in ANSI, since we are going to pass it to old
// servers. Therefore, the following code generates an ANSI string
// The following are the supported verb strings
//
// [StdShowItem("aItem",FALSE)]
// [StdDoVerbItem("aItem",verb,FALSE,FALSE)]
//
//----------------------------------------------------------------------------
STDMETHODIMP NC(CDdeObject,COleObjectImpl)::DoVerb
(LONG iVerb, LPMSG lpmsg, LPOLECLIENTSITE pActiveSite,
LONG lindex, HWND hwndParent, const RECT FAR* lprcPosRect)
{
WORD len;
ULONG size;
LPSTR lpdata = NULL;
LPSTR lpdataStart = NULL;
HANDLE hdata = NULL;
BOOL bShow;
HRESULT hresult;
ChkD (m_pDdeObject);
intrDebugOut((DEB_ITRACE,
"CDdeObject::DoVerb(%x,iVerb=%x,lindex=%x)\n",
this,iVerb,lindex));
if (iVerb < OLEIVERB_HIDE)
{
intrDebugOut((DEB_ITRACE,
"CDdeObject::DoVerb(%x)Returning invalid verb\n",
this));
return OLEOBJ_E_INVALIDVERB;
}
if (iVerb == OLEIVERB_HIDE)
{
intrDebugOut((DEB_ITRACE,"::DoVerb(%x) OLEIVERB_HIDE\n",this));
if (m_pDdeObject->m_fVisible || OT_LINK==m_pDdeObject->m_ulObjType)
{
intrDebugOut((DEB_ITRACE,
"::DoVerb(%x) CANNOT_DOVERB_NOW\n",this));
return OLEOBJ_S_CANNOT_DOVERB_NOW;
}
intrDebugOut((DEB_ITRACE,"::DoVerb(%x) returns NOERROR\n",this));
return NOERROR;
}
//
// Calculate the number of bytes needed to pass the
// execute command to the server.
//
if (bShow = (iVerb == OLEIVERB_SHOW
|| iVerb == OLEIVERB_OPEN
|| m_pDdeObject->m_bOldSvr))
{
//
// [StdShowItem("aItem",FALSE)]
//
len = 23 + wAtomLenA (m_pDdeObject->m_aItem) + 1;
}
else
{
// [StdDoVerbItem("aItem",verb,FALSE,FALSE)]
len = 32 + 10 /* for verb */ + wAtomLenA (m_pDdeObject->m_aItem) + 1;
}
if (!(hdata = GlobalAlloc (GMEM_DDESHARE, size = len)))
{
intrDebugOut((DEB_ITRACE,
"::DoVerb(%x) cannot alloc %x bytes\n",
this,size));
return ReportResult(0, E_OUTOFMEMORY, 0, 0);
}
if (!(lpdata = (LPSTR)GlobalLock (hdata)))
{
intrDebugOut((DEB_ITRACE,
"::DoVerb(%x) cannot lock\n",
this));
GlobalFree (hdata);
return ReportResult(0, E_OUTOFMEMORY, 0, 0);
}
lpdataStart = lpdata;
strcpy (lpdata, bShow ? "[StdShowItem(\"" : "[StdDoVerbItem(\"");
len = strlen (lpdata);
lpdata += len;
// For links
if (m_pDdeObject->m_aItem)
lpdata += GlobalGetAtomNameA (m_pDdeObject->m_aItem, lpdata, size - len);
if (!bShow) {
wsprintfA (lpdata,"\",%lu,TRUE,FALSE)]", iVerb);
} else {
strcpy (lpdata, "\")]");
// apps like excel and wingraph do not support activate at item level.
}
intrDebugOut((DEB_ITRACE,"::DoVerb(%x)lpdata(%s)\n",this,lpdataStart));
Assert (strlen(lpdata) < size);
GlobalUnlock (hdata);
hresult = m_pDdeObject->Execute (m_pDdeObject->m_pDocChannel, hdata);
if (NOERROR==hresult)
{
// Assume doing a verb makes the server visible.
// This is not strictly true.
m_pDdeObject->DeclareVisibility (TRUE);
}
else
{
intrDebugOut((DEB_ITRACE,
"::DoVerb(%x)Execute returned %x\n",
this,
hresult));
}
return hresult;
}
//+---------------------------------------------------------------------------
//
// Method: CDdeObject::SetHostNames
//
// Synopsis: Sets the host names
//
// Effects:
//
// Arguments: [szContainerApp] -- Name of container app
// [szContainerObj] -- Name of contained object
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: 5-12-94 kevinro Created
//
// Notes:
// ANSI ALERT!
//
// The server is going to accept a command string from us. This string
// needs to be done in ANSI, since we are going to pass it to old
// servers. Therefore, the following code generates an ANSI string
//
//----------------------------------------------------------------------------
STDMETHODIMP NC(CDdeObject,COleObjectImpl)::SetHostNames
(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj)
{
intrDebugOut((DEB_ITRACE,
"CDdeObject::SetHostNames(%x,App=%ws,Obj=%ws)\n",
this,szContainerApp,szContainerObj));
WORD cbName;
WORD wSize;
LPSTR lpBuf;
HANDLE hDdePoke;
ChkD (m_pDdeObject);
VDATEPTRIN (szContainerApp, char);
if (!m_pDdeObject->m_pDocChannel)
return NOERROR;
if (szContainerObj==NULL)
szContainerObj=OLESTR("");
if (szContainerApp[0]=='\0')
szContainerApp = OLESTR("Container Application");
//
// The OLE 1.0 server is going to want ANSI strings.
// convert the two that we have
//
char pszContainerApp[MAX_STR];
char pszContainerObj[MAX_STR];
if (WideCharToMultiByte(CP_ACP,
0,
szContainerApp,
-1,
pszContainerApp,
MAX_STR,
NULL,
NULL) == FALSE)
{
intrDebugOut((DEB_ERROR,
"::SetHostNames(%x) can't convert szContainerApp(%ws) err=%x\n",
this,szContainerApp,GetLastError()));
//
// Couldn't convert string
//
return(E_UNEXPECTED);
}
if (WideCharToMultiByte(CP_ACP,
0,
szContainerObj,
-1,
pszContainerObj,
MAX_STR,
NULL,
NULL) == FALSE)
{
intrDebugOut((DEB_ERROR,
"::SetHostNames(%x) can't convert szContainerObj(%ws) err=%x\n",
this,szContainerObj,GetLastError));
//
// Couldn't convert string
//
return(E_UNEXPECTED);
}
//
// We have found through experience that some OLE applications, like
// Clipart, use a fixed size buffer for these names. Therefore, we
// are going to limit the sizes of the strings, in case they are
// too long to send. We do this by always sticking a NULL at offset
// 80 in the file.
//
pszContainerApp[80]=0;
pszContainerObj[80]=0;
WORD cbObj;
wSize = (cbName = strlen(pszContainerApp)+1)
+ (cbObj = strlen(pszContainerObj)+1)
+ 2 * sizeof(WORD); // for the two offsets
lpBuf = wAllocDdePokeBlock ((DWORD)wSize, g_cfBinary, &hDdePoke);
((WORD FAR*)lpBuf)[0] = 0;
((WORD FAR*)lpBuf)[1] = cbName;
lpBuf += 2*sizeof(WORD);
memcpy (lpBuf,pszContainerApp,cbName);
memcpy (lpBuf+cbName, pszContainerObj,cbObj);
GlobalUnlock (hDdePoke);
aStdHostNames = GlobalAddAtom (OLESTR("StdHostNames"));
intrAssert(wIsValidAtom(aStdHostNames));
m_pDdeObject->Poke(aStdHostNames, hDdePoke);
return NOERROR;
}
STDMETHODIMP NC(CDdeObject,COleObjectImpl)::Close
(DWORD dwSaveOption)
{
intrDebugOut((DEB_ITRACE,
"CDdeObject::Close(%x,dwSaveOption=%x)\n",
this,dwSaveOption));
ChkDR (m_pDdeObject);
HRESULT hresult;
if (m_pDdeObject->m_fDidSendOnClose)
return ResultFromScode (RPC_E_CANTCALLOUT_INASYNCCALL);
if (((OLECLOSE_SAVEIFDIRTY == dwSaveOption) ||
(OLECLOSE_PROMPTSAVE==dwSaveOption)) &&
(m_pDdeObject->m_clsid != CLSID_Package))
{
// Packager gives truncated native data (header info with no
// actual embedded file) if you DDE_REQUEST it. Bug 3103
Update(); // IOleObject::Update
m_pDdeObject->OleCallBack (ON_SAVE,NULL);
}
RetZ (m_pDdeObject->m_pDocChannel);
hresult=m_pDdeObject->Execute (m_pDdeObject->m_pDocChannel,
wNewHandle ((LPSTR)&achStdCloseDocument,sizeof(achStdCloseDocument)),
TRUE);
if (NOERROR==hresult)
m_pDdeObject->m_fDidStdCloseDoc = TRUE;
// Client sends StdCloseDocument. Srvr sends ACK. Srvr may or may not
// send Terminate. We may interpret the TERMINATE the server sends
// as the reply to ours even if he posted first. But since some servers
// post first and others wait for the client, this is what we need to do.
BOOL fVisible = m_pDdeObject->m_fWasEverVisible; // TermConv clears this flag
m_pDdeObject->TermConv (m_pDdeObject->m_pDocChannel);
if (!fVisible)
m_pDdeObject->MaybeUnlaunchApp();
return hresult;
}
STDMETHODIMP NC(CDdeObject,COleObjectImpl)::SetMoniker
(DWORD dwWhichMoniker, LPMONIKER pmk)
{
intrDebugOut((DEB_ITRACE,
"CDdeObject::SetMoniker(%x,dwWhichMoniker=%x)\n",
this,dwWhichMoniker));
ChkD (m_pDdeObject);
Puts ("OleObject::SetMoniker\r\n");
// we ignore this always
return NOERROR;
}
STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetMoniker
(DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER FAR* ppmk)
{
intrDebugOut((DEB_ITRACE,
"CDdeObject::GetMoniker(%x,dwWhichMoniker=%x)\n",
this,dwWhichMoniker));
ChkD (m_pDdeObject);
if (m_pDdeObject->m_pOleClientSite)
return m_pDdeObject->m_pOleClientSite->GetMoniker(dwAssign,
dwWhichMoniker, ppmk);
else {
// no client site
*ppmk = NULL;
return ReportResult(0, E_UNSPEC, 0, 0);
}
}
STDMETHODIMP NC(CDdeObject,COleObjectImpl)::InitFromData
(LPDATAOBJECT pDataObject, BOOL fCreation, DWORD dwReserved)
{
intrDebugOut((DEB_ITRACE,
"CDdeObject::InitFromData(%x)\n",
this));
Puts ("OleObject::InitFromData\r\n");
return ReportResult(0, E_NOTIMPL, 0, 0);
}
STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetClipboardData
(DWORD dwReserved, LPDATAOBJECT FAR* ppDataObject)
{
intrDebugOut((DEB_ITRACE,
"CDdeObject::GetClipboardData(%x)\n",
this));
Puts ("OleObject::GetClipboardData\r\n");
return ReportResult(0, E_NOTIMPL, 0, 0);
}
STDMETHODIMP NC(CDdeObject,COleObjectImpl)::Advise
(IAdviseSink FAR* pAdvSink,
DWORD FAR* pdwConnection)
{
HRESULT hres;
intrDebugOut((DEB_ITRACE,
"CDdeObject::Advise(%x)\n",
this));
ChkD (m_pDdeObject);
Puts ("OleObject::Advise\n");
// Esstablish a DDE advise connection.
if (m_pDdeObject->m_ulObjType == OT_EMBEDDED
&& !m_pDdeObject->m_fDidAdvNative)
{
// Embedded case.
// Always advise on Save and Close.
if (hres = m_pDdeObject->AdviseOn (g_cfNative, ON_SAVE))
return hres;
if (hres = m_pDdeObject->AdviseOn (g_cfNative, ON_CLOSE))
return hres;
if (m_pDdeObject->m_clsid == CLSID_MSDraw)
{
// MSDraw has (another) bug. If you do not do an Advise on
// presentation, then File.Update does not work, and you
// cannot close the app unless you answer "no" to the update
// dialog. This would happen when you "Display As Icon"
// because ordinarily there is no need to advise on presentation.
// The following "unnecessary" advise fixes this problem.
if (hres = m_pDdeObject->AdviseOn (CF_METAFILEPICT, ON_SAVE))
return hres;
if (hres = m_pDdeObject->AdviseOn (CF_METAFILEPICT, ON_CLOSE))
return hres;
}
}
else {
/* Linked case */
if (hres = m_pDdeObject->AdviseOn (g_cfBinary, ON_RENAME))
return hres;
}
RetZS (m_pDdeObject->m_pOleAdvHolder, E_OUTOFMEMORY);
return m_pDdeObject->m_pOleAdvHolder->Advise (pAdvSink, pdwConnection);
}
STDMETHODIMP NC(CDdeObject,COleObjectImpl)::Unadvise
(DWORD dwConnection)
{
intrDebugOut((DEB_ITRACE,
"CDdeObject::Unadvise(%x,dwConnection=%x)\n",
this,dwConnection));
HRESULT hres;
ChkD (m_pDdeObject);
// Terminate the DDE advise connection
if (m_pDdeObject->m_ulObjType == OT_EMBEDDED)
{
// Embedded case.
if (hres = m_pDdeObject->UnAdviseOn (g_cfNative, ON_SAVE))
return hres;
if (hres = m_pDdeObject->UnAdviseOn (g_cfNative, ON_CLOSE))
return hres;
}
else
{
/* Linked case */
if (hres = m_pDdeObject->UnAdviseOn (g_cfBinary, ON_RENAME))
return hres;
}
RetZS (m_pDdeObject->m_pOleAdvHolder, E_OUTOFMEMORY);
return m_pDdeObject->m_pOleAdvHolder->Unadvise (dwConnection);
}
STDMETHODIMP NC(CDdeObject,COleObjectImpl)::EnumAdvise
(THIS_ LPENUMSTATDATA FAR* ppenumAdvise)
{
ChkD (m_pDdeObject);
RetZS (m_pDdeObject->m_pOleAdvHolder, E_OUTOFMEMORY);
return m_pDdeObject->m_pOleAdvHolder->EnumAdvise(ppenumAdvise);
}
STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetMiscStatus
(DWORD dwAspect,
DWORD FAR* pdwStatus)
{
intrDebugOut((DEB_ITRACE,
"CDdeObject::GetMiscStatus(%x)\n",
this));
VDATEPTRIN (pdwStatus, DWORD);
*pdwStatus = 0L;
return ResultFromScode (OLE_S_USEREG);
}
STDMETHODIMP NC(CDdeObject,COleObjectImpl)::SetColorScheme
(LPLOGPALETTE lpLogpal)
{
HANDLE hDdePoke;
LPLOGPALETTE lptmpLogpal;
intrDebugOut((DEB_ITRACE,
"CDdeObject::SetColorScheme(%x)\n",
this));
ChkD (m_pDdeObject);
if (!m_pDdeObject->m_pDocChannel)
return NOERROR;
aStdColorScheme = GlobalAddAtom (OLESTR("StdColorScheme"));
intrAssert(wIsValidAtom(aStdColorScheme));
DWORD dwSize = (lpLogpal->palNumEntries - 1) * sizeof(PALETTEENTRY)
+ sizeof(LOGPALETTE);
lptmpLogpal = (LPLOGPALETTE) wAllocDdePokeBlock (dwSize, g_cfBinary, &hDdePoke);
memcpy(lptmpLogpal, lpLogpal, dwSize);
GlobalUnlock(hDdePoke);
return m_pDdeObject->Poke(aStdColorScheme, hDdePoke);
}
#ifdef _DEBUG
STDMETHODIMP_(void) NC(CDdeObject,CDebug)::Dump( IDebugStream FAR * pdbstm)
{
}
STDMETHODIMP_(BOOL) NC(CDdeObject,CDebug)::IsValid( BOOL fSuspicious )
{
if( m_pDdeObject->m_refs > 0 && m_pDdeObject->m_chk == chkDdeObj )
return TRUE;
else
return FALSE;
}
#endif