// if you use precompiled headers, place these #include in stdafx.h #include #include #include /* * Sample FORMATETC enumerating object, which assumes that the data object only * exports a single CF_TEXT format with standard aspects/media/etc */ class CEnumFORMATETCImpl : public IEnumFORMATETC { public: // IUnknown methods STDMETHOD(QueryInterface)(REFIID iid, void** pp) { OutputDebugString(_T("IEnumFORMATETCImpl::QueryInterface\n")); return E_NOTIMPL; // nobody is ever likely to query us for something else } STDMETHOD_(ULONG, AddRef)() { TCHAR buf_[100]; sprintf(buf_, _T("IEnumFORMATETCImpl::AddRef (cnt=%d)\n"), m_dwRef+1); OutputDebugString(buf_); return ++m_dwRef; } STDMETHOD_(ULONG, Release)() { TCHAR buf_[100]; sprintf(buf_, _T("IEnumFORMATETCImpl::Release (cnt=%d)\n"), m_dwRef-1); OutputDebugString(buf_); return --m_dwRef; } // enum stuffen STDMETHOD(Next)(ULONG celt, FORMATETC* rgelt, ULONG* pceltFetched) { OutputDebugString(_T("IEnumFORMATETCImpl::Next\n")); if (rgelt == NULL || (celt != 1 && pceltFetched == NULL)) return E_POINTER; if(!m_dwIndex) { // only one position we support m_dwIndex++; rgelt->cfFormat = CF_TEXT; rgelt->dwAspect = DVASPECT_CONTENT; rgelt->lindex = -1; rgelt->ptd = NULL; // nothing especial rgelt->tymed = TYMED_HGLOBAL; if(pceltFetched) *pceltFetched = 1; // alwayz return S_OK; } else m_dwIndex = 0; // quick fix to make object reentrant return S_FALSE; // indicates there's nothing more } STDMETHOD(Skip)(ULONG celt) { OutputDebugString(_T("IEnumFORMATETCImpl::Skip\n")); m_dwIndex += celt; if(m_dwIndex > 1) { m_dwIndex = 0; return S_FALSE; } return S_OK; } STDMETHOD(Reset)(void) { OutputDebugString(_T("IEnumFORMATETCImpl::Reset\n")); m_dwIndex = 0; return S_OK; } STDMETHOD(Clone)(IEnumFORMATETC** /*ppEnum*/) { OutputDebugString(_T("IEnumFORMATETCImpl::Clone\n")); return E_NOTIMPL; } // finally constructor CEnumFORMATETCImpl() {m_dwRef = m_dwIndex = 0;} private: DWORD m_dwRef; // reference count DWORD m_dwIndex; // which of the various formats is next in line }; /* * Accompanying data object, bearer of the fixed text to be placed in the clipboard. * Most functionality is missing (E_NOTIMPL) but it should be enough to experiment * with the OLE clipboard. */ class CDataObjectImpl : public IDataObject { public: // IUnknown methods STDMETHOD(QueryInterface)(REFIID iid, void** pp) { OutputDebugString(_T("IDataObjectImpl::QueryInterface\n")); return E_NOTIMPL; } STDMETHOD_(ULONG, AddRef)() { TCHAR buf_[100]; sprintf(buf_, _T("IDataObjectImpl::AddRef (cnt=%d)\n"), m_dwRef+1); OutputDebugString(buf_); return ++m_dwRef; } STDMETHOD_(ULONG, Release)() { TCHAR buf_[100]; sprintf(buf_, _T("IDataObjectImpl::Release (cnt=%d)\n"), m_dwRef-1); OutputDebugString(buf_); return --m_dwRef; // obviously we don't "delete" ourselves, we are always on the stack } // other DataObject stuff STDMETHOD(GetData)(FORMATETC *pformatetcIn, STGMEDIUM *pmedium) { OutputDebugString(_T("IDataObjectImpl::GetData (")); // in lieu of trace TCHAR buf_[100]; sprintf(buf_, _T("Format = 0x%x, Medium = 0x%x)\n"), pformatetcIn->cfFormat, pformatetcIn->tymed); OutputDebugString(buf_); if ( !(pformatetcIn && pmedium) ) return E_POINTER; ZeroMemory(pmedium, sizeof(pmedium)); HRESULT hr = QueryGetData(pformatetcIn); // shared functionality if(hr != S_OK) return hr; LPCTSTR txt = _T("Hello dude!"); // same thing all the time HGLOBAL hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, (lstrlen(txt)+1)*sizeof(txt[0]) ); if (NULL==hMem) return STG_E_MEDIUMFULL; LPTSTR pText =(LPTSTR)GlobalLock(hMem); lstrcpy(pText, txt); GlobalUnlock(hMem); // never mind what he asked in the formatEtc, pass what he's getting pmedium->hGlobal = hMem; pmedium->tymed = TYMED_HGLOBAL; pmedium->pUnkForRelease = NULL; // regular deletion with GlobalFree return S_OK; } STDMETHOD(GetDataHere)(FORMATETC* /* pformatetc */, STGMEDIUM* /* pmedium */) { OutputDebugString(_T("IDataObjectImpl::GetDataHere\n")); return E_NOTIMPL; } STDMETHOD(QueryGetData)(FORMATETC* pformatetcIn) { OutputDebugString(_T("IDataObjectImpl::QueryGetData\n")); if ( !pformatetcIn ) return E_POINTER; // supply rich error information for callers if ((pformatetcIn->tymed & TYMED_HGLOBAL) == 0) return DV_E_TYMED; if(pformatetcIn->cfFormat != CF_TEXT) return DATA_E_FORMATETC; if(pformatetcIn->dwAspect != DVASPECT_CONTENT) return DV_E_DVASPECT; if(pformatetcIn->lindex != -1) return DV_E_LINDEX; if(pformatetcIn->ptd) return DATA_E_FORMATETC; return S_OK; // should be ok } STDMETHOD(GetCanonicalFormatEtc)(FORMATETC* /* pformatectIn */,FORMATETC* /* pformatetcOut */) { OutputDebugString(_T("IDataObjectImpl::GetCanonicalFormatEtc\n")); return E_NOTIMPL; } STDMETHOD(SetData)(FORMATETC* /* pformatetc */, STGMEDIUM* /* pmedium */, BOOL /* fRelease */) { OutputDebugString(_T("IDataObjectImpl::SetData\n")); return E_NOTIMPL; } STDMETHOD(EnumFormatEtc)(DWORD dwDirection, IEnumFORMATETC** ppenumFormatEtc) { // this is the first called when we OleSetClipboard OutputDebugString(_T("IDataObjectImpl::EnumFormatEtc\n")); if(dwDirection == DATADIR_GET) { *ppenumFormatEtc = &m_enumResident; m_enumResident.AddRef(); return S_OK; } *ppenumFormatEtc = NULL; return E_NOTIMPL; } STDMETHOD(DAdvise)(FORMATETC* /*pformatetc*/, DWORD /*advf*/, IAdviseSink* /*pAdvSink*/, DWORD* /*pdwConnection*/) { OutputDebugString(_T("IDataObjectImpl::DAdvise\n")); return E_NOTIMPL; } STDMETHOD(DUnadvise)(DWORD /*dwConnection*/) { OutputDebugString(_T("IDataObjectImpl::DUnadvise\n")); return E_NOTIMPL; } STDMETHOD(EnumDAdvise)(IEnumSTATDATA ** /*ppenumAdvise*/) { OutputDebugString(_T("IDataObjectImpl::EnumDAdvise\n")); return E_NOTIMPL; } // finally constructor CDataObjectImpl() {m_dwRef = 0;} private: DWORD m_dwRef; // reference count CEnumFORMATETCImpl m_enumResident; // lokali };