/* 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 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