//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1993. // // File: gendata.cpp // // Contents: implementation of CGenDataObject // // Classes: // // Functions: // // History: dd-mmm-yy Author Comment // 06-Jun-94 alexgo added support for OLE1 tests // 24-Mar-94 alexgo author // //-------------------------------------------------------------------------- #include "oletest.h" #include "gendata.h" static const CLSID CLSID_TestCLSID = {0xaabbccee, 0x1122, 0x3344, { 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0xaa, 0xbb }}; static const char szTestString[] = "A carefully chosen test string"; static const OLECHAR wszTestStream[] = OLESTR("TestStream"); static const char szNativeData[] = "Ole1Test NATIVE data"; static const char szOwnerLinkData[] = "PBrush\0foo.bmp\00 0 200 160\0\0"; //+------------------------------------------------------------------------- // // Member: CGenDataObject::CGenDataObject // // Synopsis: constructor // // Effects: // // Arguments: // // Requires: // // Returns: // // Signals: // // Modifies: // // Derivation: // // Algorithm: // // History: dd-mmm-yy Author Comment // 06-Jun-94 alexgo added OLE1 support // 24-Mar-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- CGenDataObject::CGenDataObject( ) { m_refs = 0; m_fQICalled = FALSE; // now set up the formats that we support m_cfTestStorage = RegisterClipboardFormat("OleTest Storage Format"); m_cfEmbeddedObject = RegisterClipboardFormat("Embedded Object"); m_cfEmbedSource = RegisterClipboardFormat("Embed Source"); m_cfLinkSource = RegisterClipboardFormat("Link Source"); m_cfObjectDescriptor = RegisterClipboardFormat("Object Descriptor"); m_cfLinkSrcDescriptor = RegisterClipboardFormat("Link Source " "Descriptor"); m_cfOwnerLink = RegisterClipboardFormat("OwnerLink"); m_cfNative = RegisterClipboardFormat("Native"); m_cfObjectLink = RegisterClipboardFormat("ObjectLink"); // now set up the array of formatetc's. SetupOle1Mode must be // called if you want OLE1 formats m_rgFormats = new FORMATETC[2]; assert(m_rgFormats); m_rgFormats[0].cfFormat = m_cfTestStorage; m_rgFormats[0].ptd = NULL; m_rgFormats[0].dwAspect = DVASPECT_CONTENT; m_rgFormats[0].lindex = -1; m_rgFormats[0].tymed = TYMED_ISTORAGE; m_rgFormats[1].cfFormat = m_cfEmbeddedObject; m_rgFormats[1].ptd = NULL; m_rgFormats[1].dwAspect = DVASPECT_CONTENT; m_rgFormats[1].lindex = -1; m_rgFormats[1].tymed = TYMED_ISTORAGE; m_cFormats = 2; } //+------------------------------------------------------------------------- // // Member: CGenDataObject::QueryInterface // // Synopsis: returns requested interfaces // // Effects: // // Arguments: [riid] -- the requested interface // [ppvObj] -- where to put the interface pointer // // Requires: // // Returns: HRESULT // // Signals: // // Modifies: // // Derivation: IDataObject // // Algorithm: // // History: dd-mmm-yy Author Comment // 24-Mar-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- STDMETHODIMP CGenDataObject::QueryInterface( REFIID riid, LPVOID *ppvObj ) { HRESULT hresult = NOERROR; m_fQICalled = TRUE; if( IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IDataObject) ) { *ppvObj = this; AddRef(); } else { *ppvObj = NULL; hresult = ResultFromScode(E_NOINTERFACE); } return hresult; } //+------------------------------------------------------------------------- // // Member: CGenDataObject::AddRef // // Synopsis: increments the reference count // // Effects: // // Arguments: void // // Requires: // // Returns: ULONG-- the new reference count // // Signals: // // Modifies: // // Derivation: IDataObject // // Algorithm: // // History: dd-mmm-yy Author Comment // 24-Mar-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CGenDataObject::AddRef( ) { return ++m_refs; } //+------------------------------------------------------------------------- // // Member: CGenDataObject::Release // // Synopsis: decrements the reference count on the object // // Effects: // // Arguments: void // // Requires: // // Returns: ULONG -- the new reference count // // Signals: // // Modifies: // // Derivation: IDataObject // // Algorithm: // // History: dd-mmm-yy Author Comment // 24-Mar-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CGenDataObject::Release( ) { ULONG cRefs; if( (cRefs = --m_refs ) == 0 ) { delete this; } return cRefs; } //+------------------------------------------------------------------------- // // Member: CGenDataObject::GetData // // Synopsis: retrieves data of the specified format // // Effects: // // Arguments: [pformatetc] -- the requested format // [pmedium] -- where to put the data // // Requires: // // Returns: HRESULT // // Signals: // // Modifies: // // Derivation: IDataObject // // Algorithm: // // History: dd-mmm-yy Author Comment // 06-Jun-94 alexgo added OLE1 support // 24-Mar-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- STDMETHODIMP CGenDataObject::GetData( LPFORMATETC pformatetc, LPSTGMEDIUM pmedium) { HRESULT hresult = NOERROR; if( (pformatetc->cfFormat == m_cfTestStorage || pformatetc->cfFormat == m_cfEmbeddedObject ) && (pformatetc->tymed & TYMED_ISTORAGE) ) { pmedium->tymed = TYMED_ISTORAGE; pmedium->pstg = GetTestStorage(); assert(pmedium->pstg); } // test for OLE1 formats else if( pformatetc->cfFormat == m_cfOwnerLink && (m_fOle1 & OLE1_OFFER_OWNERLINK ) && (pformatetc->tymed & TYMED_HGLOBAL) ) { pmedium->tymed = TYMED_HGLOBAL; pmedium->hGlobal = GetOwnerOrObjectLink(); assert(pmedium->hGlobal); } else if( pformatetc->cfFormat == m_cfObjectLink && (m_fOle1 & OLE1_OFFER_OBJECTLINK ) && (pformatetc->tymed & TYMED_HGLOBAL) ) { pmedium->tymed = TYMED_HGLOBAL; pmedium->hGlobal = GetOwnerOrObjectLink(); assert(pmedium->hGlobal); } else if( pformatetc->cfFormat == m_cfNative && (m_fOle1 & OLE1_OFFER_NATIVE ) && (pformatetc->tymed &TYMED_HGLOBAL ) ) { pmedium->tymed = TYMED_HGLOBAL; pmedium->hGlobal = GetNativeData(); } else { hresult = ResultFromScode(E_FAIL); } return hresult; } //+------------------------------------------------------------------------- // // Member: CGenDataObject::GetDataHere // // Synopsis: retrieves data of the specified format // // Effects: // // Arguments: [pformatetc] -- the requested format // [pmedium] -- where to put the data // // Requires: // // Returns: HRESULT // // Signals: // // Modifies: // // Derivation: IDataObject // // Algorithm: // // History: dd-mmm-yy Author Comment // 24-Mar-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- STDMETHODIMP CGenDataObject::GetDataHere( LPFORMATETC pformatetc, LPSTGMEDIUM pmedium) { (void)pformatetc; (void)pmedium; return ResultFromScode(E_NOTIMPL); } //+------------------------------------------------------------------------- // // Member: CGenDataObject::QueryGetData // // Synopsis: queries whether a GetData call would succeed // // Effects: // // Arguments: [pformatetc] -- the requested format // // Requires: // // Returns: HRESULT // // Signals: // // Modifies: // // Derivation: IDataObject // // Algorithm: // // History: dd-mmm-yy Author Comment // 24-Mar-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- STDMETHODIMP CGenDataObject::QueryGetData( LPFORMATETC pformatetc ) { (void)pformatetc; return ResultFromScode(E_NOTIMPL); } //+------------------------------------------------------------------------- // // Member: CGenDataObject::GetCanonicalFormatEtc // // Synopsis: retrieve the canonical format // // Effects: // // Arguments: [pformatetc] -- the requested format // [pformatetcOut] -- the canonical format // // Requires: // // Returns: HRESULT // // Signals: // // Modifies: // // Derivation: IDataObject // // Algorithm: // // History: dd-mmm-yy Author Comment // 24-Mar-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- STDMETHODIMP CGenDataObject::GetCanonicalFormatEtc( LPFORMATETC pformatetc, LPFORMATETC pformatetcOut) { (void)pformatetc; (void)pformatetcOut; return ResultFromScode(E_NOTIMPL); } //+------------------------------------------------------------------------- // // Member: CGenDataObject::SetData // // Synopsis: sets data of the specified format // // Effects: // // Arguments: [pformatetc] -- the format of the data // [pmedium] -- the data // // Requires: // // Returns: HRESULT // // Signals: // // Modifies: // // Derivation: IDataObject // // Algorithm: // // History: dd-mmm-yy Author Comment // 24-Mar-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- STDMETHODIMP CGenDataObject::SetData( LPFORMATETC pformatetc, LPSTGMEDIUM pmedium, BOOL fRelease) { (void)pformatetc; (void)pmedium; (void)fRelease; return ResultFromScode(E_NOTIMPL); } //+------------------------------------------------------------------------- // // Member: CGenDataObject::EnumFormatEtc // // Synopsis: return an enumerator for the available data formats // // Effects: // // Arguments: [dwDirection] -- the direction (GET or SET) // [ppenum] -- where to put the enumerator // // Requires: // // Returns: HRESULT // // Signals: // // Modifies: // // Derivation: IDataObject // // Algorithm: // // History: dd-mmm-yy Author Comment // 24-Mar-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- STDMETHODIMP CGenDataObject::EnumFormatEtc( DWORD dwDirection, LPENUMFORMATETC * ppenum ) { HRESULT hresult; if( dwDirection == DATADIR_GET ) { hresult = CGenEnumFormatEtc::Create( ppenum, m_rgFormats, m_cFormats); assert(hresult == NOERROR); return hresult; } else { return ResultFromScode(E_NOTIMPL); } } //+------------------------------------------------------------------------- // // Member: CGenDataObject::DAdvise // // Synopsis: register a data advise // // Effects: // // Arguments: [pformatetc] -- the requested format // [dwAdvf] -- advise flags // [pAdvSink] -- the advise sink // [pdwConnection] -- where to put the connection ID // // Requires: // // Returns: HRESULT // // Signals: // // Modifies: // // Derivation: IDataObject // // Algorithm: // // History: dd-mmm-yy Author Comment // 24-Mar-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- STDMETHODIMP CGenDataObject::DAdvise( LPFORMATETC pformatetc, DWORD dwAdvf, IAdviseSink * pAdvSink, DWORD *pdwConnection ) { (void)pformatetc; (void)dwAdvf; (void)pAdvSink; (void)pdwConnection; return ResultFromScode(E_NOTIMPL); } //+------------------------------------------------------------------------- // // Member: CGenDataObject::DUnadvise // // Synopsis: unadvises an advise connection // // Effects: // // Arguments: [dwConnection] -- the connection to remove // // Requires: // // Returns: HRESULT // // Signals: // // Modifies: // // Derivation: IDataObject // // Algorithm: // // History: dd-mmm-yy Author Comment // 24-Mar-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- STDMETHODIMP CGenDataObject::DUnadvise(DWORD dwConnection) { (void)dwConnection; return ResultFromScode(E_NOTIMPL); } //+------------------------------------------------------------------------- // // Member: CGenDataObject::EnumDAdvise // // Synopsis: enumerates data advises // // Effects: // // Arguments: [ppenum] -- where to put the enumerator // // Requires: // // Returns: HRESULT // // Signals: // // Modifies: // // Derivation: IDataObject // // Algorithm: // // History: dd-mmm-yy Author Comment // 24-Mar-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- STDMETHODIMP CGenDataObject::EnumDAdvise( LPENUMSTATDATA *ppenum) { (void)ppenum; return ResultFromScode(E_NOTIMPL); } //+------------------------------------------------------------------------- // // Member: CGenDataObject::VerifyMedium // // Synopsis: verifies the contents of the given medium // // Effects: // // Arguments: [pmedium] -- the medium to verify // // Requires: // // Returns: BOOL // // Signals: // // Modifies: // // Derivation: // // Algorithm: For OLE1 formats, the following must be true: // cfEmbeddedObject: // must have OWNERLINK and !NATIVE // or OWNERLINK precedes NATIVE // cfEmbedSource: // must have NATIVE && OWNERLINK and // OWNERLINK must not precede NATIVE // cfObjectDescriptor: // same as EmbedSource // cfLinkSource: // must have either OBJECTLINK or // OWNERLINK must precede NATIVE // cfLinkSrcDescriptor: // same as LinkSource // // History: dd-mmm-yy Author Comment // 06-Jun-94 alexgo added OLE1 support // 15-Apr-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- BOOL CGenDataObject::VerifyFormatAndMedium( FORMATETC *pformatetc, STGMEDIUM *pmedium ) { // if any of these flags are set, then we were offering OLE1 // data. Do relevant tests. if( (m_fOle1 & (OLE1_OFFER_OWNERLINK | OLE1_OFFER_OBJECTLINK | OLE1_OFFER_NATIVE) ) ) { // now do individual tests for formats if( pformatetc->cfFormat == m_cfEmbedSource || pformatetc->cfFormat == m_cfObjectDescriptor) { if( (m_fOle1 & OLE1_OFFER_NATIVE) && (m_fOle1 & OLE1_OFFER_OWNERLINK) && !(m_fOle1 & OLE1_OWNERLINK_PRECEDES_NATIVE) ) { return TRUE; } } else if( pformatetc->cfFormat == m_cfLinkSource || pformatetc->cfFormat == m_cfLinkSrcDescriptor) { if( (m_fOle1 & OLE1_OFFER_OBJECTLINK) || ((m_fOle1 & OLE1_OFFER_OWNERLINK) && (m_fOle1 & OLE1_OFFER_NATIVE) && (m_fOle1 & OLE1_OWNERLINK_PRECEDES_NATIVE))) { return TRUE; } } // no 'else' so we check for cfObjectDescriptor again if( pformatetc->cfFormat == m_cfEmbeddedObject || pformatetc->cfFormat == m_cfObjectDescriptor ) { if( ((m_fOle1 & OLE1_OFFER_NATIVE) && (m_fOle1 & OLE1_OFFER_OWNERLINK) && (m_fOle1 & OLE1_OWNERLINK_PRECEDES_NATIVE)) || ((m_fOle1 & OLE1_OFFER_OWNERLINK) && !(m_fOle1 & OLE1_OFFER_NATIVE)) ) { return TRUE; } } // fall through and do rest of testing, in case we didn't // hit one of the synthesized formats. } if( pformatetc->cfFormat == m_cfTestStorage || pformatetc->cfFormat == m_cfEmbeddedObject ) { return VerifyTestStorage( pformatetc, pmedium ); } else if( pformatetc->cfFormat == m_cfOwnerLink || pformatetc->cfFormat == m_cfObjectLink ) { return VerifyOwnerOrObjectLink(pformatetc, pmedium); } else if( pformatetc->cfFormat == m_cfNative ) { return VerifyNativeData(pformatetc, pmedium); } return FALSE; } //+------------------------------------------------------------------------- // // Member: CGenDataObject::VerifyTestStorage // // Synopsis: verifies the test storage format // // Effects: // // Arguments: // // Requires: // // Returns: BOOL // // Signals: // // Modifies: // // Derivation: // // Algorithm: // // History: dd-mmm-yy Author Comment // 15-Apr-94 alexgo author; tax day :-( // // Notes: // //-------------------------------------------------------------------------- BOOL CGenDataObject::VerifyTestStorage( FORMATETC *pformatetc, STGMEDIUM *pmedium) { IStream * pstm; STATSTG statstg; char szBuf[sizeof(szTestString)]; HRESULT hresult; if( pmedium->tymed != TYMED_ISTORAGE ) { //REVIEW: we may want to convert and test different //mediums at a later date return FALSE; } // check the class ID pmedium->pstg->Stat(&statstg, STATFLAG_NONAME); if( !IsEqualCLSID(statstg.clsid, CLSID_TestCLSID) ) { OutputString("Failed CLSID check on storage in " "VerifyTestStorage!!\r\n"); return FALSE; } // now open the test stream hresult = pmedium->pstg->OpenStream(wszTestStream, NULL, (STGM_READ | STGM_SHARE_EXCLUSIVE), 0, &pstm); if( hresult != NOERROR ) { OutputString("OpenStream in VerifyTestStorage failed! (%lx)" "\r\n", hresult); return FALSE; } hresult = pstm->Read((void *)szBuf, sizeof(szTestString), NULL); if( hresult != NOERROR ) { OutputString("Stream->Read failed in VerifyTestStorage (%lx)" "\r\n", hresult); pstm->Release(); return FALSE; } if( strcmp(szBuf, szTestString) != 0 ) { OutputString("'%s' != '%s'\r\n", szBuf, szTestString); return FALSE; } pstm->Release(); return TRUE; } //+------------------------------------------------------------------------- // // Member: CGenDataObject::GetTestStorage (private) // // Synopsis: // // Effects: // // Arguments: // // Requires: // // Returns: a new storage // // Signals: // // Modifies: // // Derivation: // // Algorithm: // // History: dd-mmm-yy Author Comment // 15-Apr-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- IStorage * CGenDataObject::GetTestStorage( void ) { IStorage * pstg; IStream * pstm; HRESULT hresult; // create the docfile hresult = StgCreateDocfile(NULL, (STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE), NULL, &pstg); if( hresult != NOERROR ) { OutputString("GetTestStorage: CreateDocfile failed!! (%lx)" "\r\n", hresult); return NULL; } // set the class ID hresult = pstg->SetClass(CLSID_TestCLSID); // now create the stream hresult = pstg->CreateStream(wszTestStream, (STGM_READWRITE | STGM_SHARE_EXCLUSIVE ), 0, 0, &pstm); if( hresult != NOERROR ) { OutputString("GetTestStorage: CreateStream failed! (%lx)\r\n", hresult); pstg->Release(); return NULL; } hresult = pstm->Write((void *)szTestString, sizeof(szTestString), NULL); if( hresult != NOERROR ) { OutputString("GetTestStorage: Stream->Write failed! (%lx)\r\n", hresult); pstm->Release(); pstg->Release(); return NULL; } pstm->Release(); return pstg; } //+------------------------------------------------------------------------- // // Member: CGenDataObject::GetOwnerOrObjectLink (private) // // Synopsis: Creates either cfOwnerLink or cfObjectLink for a dummy // Paintbrush (ole1) object // // Effects: allocates an HGLOBAL // // Arguments: void // // Requires: // // Returns: HGLOBAL // // Signals: // // Modifies: // // Derivation: // // Algorithm: // // History: dd-mmm-yy Author Comment // 06-Jun-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- HGLOBAL CGenDataObject::GetOwnerOrObjectLink( void ) { HGLOBAL hglobal; char *pdata; hglobal = GlobalAlloc(GMEM_MOVEABLE, sizeof(szOwnerLinkData)); assert(hglobal); pdata = (char *)GlobalLock(hglobal); assert(pdata); memcpy(pdata, szOwnerLinkData, sizeof(szOwnerLinkData)); GlobalUnlock(hglobal); return hglobal; } //+------------------------------------------------------------------------- // // Member: CGenDataObject::GetNativeData (private) // // Synopsis: Creates OLE1 Native data // // Effects: allocates an hglobal // // Arguments: void // // Requires: // // Returns: HGLOBAL // // Signals: // // Modifies: // // Derivation: // // Algorithm: // // History: dd-mmm-yy Author Comment // 06-Jun-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- HGLOBAL CGenDataObject::GetNativeData( void ) { HGLOBAL hglobal; char *pdata; hglobal = GlobalAlloc(GMEM_MOVEABLE, sizeof(szNativeData) + 1); assert(hglobal); pdata = (char *)GlobalLock(hglobal); assert(pdata); memcpy(pdata, szNativeData, sizeof(szNativeData)+1); GlobalUnlock(hglobal); return hglobal; } //+------------------------------------------------------------------------- // // Member: CGenDataObject::VerifyOwnerOrObjectLink // // Synopsis: verifies that the owner or object link data is correct // // Effects: // // Arguments: [pformatetc] -- the formatetc describing the data // [pmedium] -- the data // // Requires: pformatetc must be for OwnerLink or ObjectLink // // Returns: BOOL // // Signals: // // Modifies: // // Derivation: // // Algorithm: // // History: dd-mmm-yy Author Comment // 06-Jun-94 alexgo author // // Notes: // NB!!: must be expanded to cover container-side cases // //-------------------------------------------------------------------------- BOOL CGenDataObject::VerifyOwnerOrObjectLink( FORMATETC *pformatetc, STGMEDIUM *pmedium ) { char * pdata; BOOL fRet = FALSE; assert(pformatetc->cfFormat == m_cfOwnerLink || pformatetc->cfFormat == m_cfObjectLink ); // check standard stuff if( !(pformatetc->tymed & TYMED_HGLOBAL ) || pformatetc->dwAspect != DVASPECT_CONTENT || pformatetc->ptd != NULL || pformatetc->lindex != -1 || pmedium->tymed != TYMED_HGLOBAL ) { return FALSE; } // if we offered the data natively from OLE1, then // check the contents. // this conditional tests to see if the format in question // was originally offered by us if( ((m_fOle1 & OLE1_OFFER_OWNERLINK) && pformatetc->cfFormat == m_cfOwnerLink) || ((m_fOle1 & OLE1_OFFER_OBJECTLINK) && pformatetc->cfFormat == m_cfObjectLink) ) { pdata = (char *)GlobalLock(pmedium->hGlobal); if( memcmp(pdata, szOwnerLinkData, sizeof(szOwnerLinkData)) == 0 ) { fRet = TRUE; } GlobalUnlock(pmedium->hGlobal); } // else CHECK SYNTHESIZED OLE1 FORMATS WHEN IMPLEMENTED return fRet; } //+------------------------------------------------------------------------- // // Member: CGenDataObject::VerifyNativeData (private) // // Synopsis: verifies OLE1 Native data // // Effects: // // Arguments: [pformatetc] -- formatetc for the data // [pmedium] -- location of the native data // // Requires: // // Returns: // // Signals: // // Modifies: // // Derivation: // // Algorithm: // // History: dd-mmm-yy Author Comment // 06-Jun-95 alexgo author // Notes: // //-------------------------------------------------------------------------- BOOL CGenDataObject::VerifyNativeData( FORMATETC *pformatetc, STGMEDIUM *pmedium ) { char * pdata; BOOL fRet = FALSE; assert(pformatetc->cfFormat == m_cfNative ); // check standard stuff if( !(pformatetc->tymed & TYMED_HGLOBAL) || pformatetc->dwAspect != DVASPECT_CONTENT || pformatetc->ptd != NULL || pformatetc->lindex != -1 || pmedium->tymed != TYMED_HGLOBAL ) { return FALSE; } // if we offered the data natively from OLE1, then // check the contents. // this conditional tests to see if the format in question // was originally offered by us if( (m_fOle1 & OLE1_OFFER_NATIVE) ) { pdata = (char *)GlobalLock(pmedium->hGlobal); if( memcmp(pdata, szNativeData, sizeof(szNativeData)) == 0 ) { fRet = TRUE; } GlobalUnlock(pmedium->hGlobal); } // else CHECK SYNTHESIZED OLE1 FORMATS WHEN IMPLEMENTED return fRet; } //+------------------------------------------------------------------------- // // Member: CGenDataObject::SetupOle1Mode (public) // // Synopsis: Sets the data object up for OLE1 compatibility mode // // Effects: // // Arguments: [fFlags] -- specifies various OLE1 options // // Requires: // // Returns: void // // Signals: // // Modifies: // // Derivation: // // Algorithm: // // History: dd-mmm-yy Author Comment // 06-Jun-94 alexgo author // // Notes: // The default test information in the data object will be // lost by this call. Simply create a new data object if // it is needed again. // //-------------------------------------------------------------------------- void CGenDataObject::SetupOle1Mode( Ole1TestFlags fFlags ) { DWORD count = 0, i = 0; UINT cfFormats[3]; // OLE1 formats offered if( fFlags == 0 ) { // don't need to do anything return; } // the formats we had previously delete m_rgFormats; // first figure out how many formats we need if( (fFlags & OLE1_OFFER_NATIVE) ) { if( !((fFlags & OLE1_OWNERLINK_PRECEDES_NATIVE) && (fFlags & OLE1_OFFER_OWNERLINK)) ) { cfFormats[i] = m_cfNative; i++; } count++; } if( (fFlags & OLE1_OFFER_OWNERLINK) ) { cfFormats[i] = m_cfOwnerLink; i++; if( (fFlags & OLE1_OWNERLINK_PRECEDES_NATIVE) && (fFlags & OLE1_OFFER_NATIVE) ) { cfFormats[i] = m_cfNative; i++; } count++; } if( (fFlags & OLE1_OFFER_OBJECTLINK) ) { cfFormats[i] = m_cfObjectLink; count++; } m_rgFormats = new FORMATETC[count]; assert(m_rgFormats); for(i = 0; i < count; i++ ) { m_rgFormats[i].cfFormat = cfFormats[i]; m_rgFormats[i].ptd = NULL; m_rgFormats[i].dwAspect = DVASPECT_CONTENT; m_rgFormats[i].lindex = -1; m_rgFormats[i].tymed = TYMED_HGLOBAL; } m_cFormats = count; m_fOle1 = fFlags; return; } //+------------------------------------------------------------------------- // // Member: CGenDataObject::SetOle1ToClipboard // // Synopsis: stuffs available OLE1 formats to the clipboard // // Effects: // // Arguments: void // // Requires: SetOle1Mode *must* have been called // // Returns: HRESULT // // Signals: // // Modifies: // // Derivation: // // Algorithm: // // History: dd-mmm-yy Author Comment // 06-Jun-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- HRESULT CGenDataObject::SetOle1ToClipboard( void ) { HRESULT hresult = NOERROR; DWORD i; HGLOBAL hglobal; assert((m_fOle1 & (OLE1_OFFER_OWNERLINK | OLE1_OFFER_OBJECTLINK | OLE1_OFFER_NATIVE))); if( !OpenClipboard(vApp.m_hwndMain) ) { return ResultFromScode(CLIPBRD_E_CANT_OPEN); } if( !EmptyClipboard() ) { CloseClipboard(); return ResultFromScode(CLIPBRD_E_CANT_EMPTY); } for( i = 0 ; i < m_cFormats; i++ ) { if( m_rgFormats[i].cfFormat == m_cfNative ) { hglobal = GetNativeData(); SetClipboardData(m_cfNative, hglobal); } else if( m_rgFormats[i].cfFormat == m_cfOwnerLink ) { hglobal = GetOwnerOrObjectLink(); SetClipboardData(m_cfOwnerLink, hglobal); } else if( m_rgFormats[i].cfFormat == m_cfObjectLink ) { hglobal = GetOwnerOrObjectLink(); SetClipboardData(m_cfObjectLink, hglobal); } else { hresult = ResultFromScode(E_UNEXPECTED); } } CloseClipboard(); return hresult; } //+------------------------------------------------------------------------- // // Member: CGenDataObject::HasQIBeenCalled (public) // // Synopsis: returns wether or not QueryInterface has been called on // this data object. Used in testing OleQueryCreateFromData // // Effects: // // Arguments: none // // Requires: // // Returns: TRUE/FALSE // // Signals: // // Modifies: // // Derivation: // // Algorithm: // // History: dd-mmm-yy Author Comment // 23-Aug-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- BOOL CGenDataObject::HasQIBeenCalled() { return m_fQICalled; } //+------------------------------------------------------------------------- // // Member: CGenDataObject::SetDatFormats // // Synopsis: sets the formats that the data object will offer // // Effects: // // Arguments: [fFlags] -- formats to offer // // Requires: // // Returns: void // // Signals: // // Modifies: // // Derivation: // // Algorithm: // // History: dd-mmm-yy Author Comment // 23-Aug-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- void CGenDataObject::SetDataFormats( DataFlags fFlags ) { DWORD cFormats = 0; DWORD flags = (DWORD)fFlags; DWORD i =0; if( m_rgFormats ) { delete m_rgFormats; m_rgFormats = NULL; } if( flags == 0 ) { return; } // count the number of formats to offer cFormats++; while( flags &= (flags -1) ) { cFormats++; } m_rgFormats = new FORMATETC[cFormats]; assert(m_rgFormats); memset(m_rgFormats, 0, sizeof(FORMATETC)*cFormats); if( fFlags & OFFER_TESTSTORAGE ) { m_rgFormats[i].cfFormat = m_cfTestStorage; m_rgFormats[i].ptd = NULL; m_rgFormats[i].dwAspect = DVASPECT_CONTENT; m_rgFormats[i].lindex = -1; m_rgFormats[i].tymed = TYMED_ISTORAGE; i++; } if( fFlags & OFFER_EMBEDDEDOBJECT ) { m_rgFormats[i].cfFormat = m_cfEmbeddedObject; m_rgFormats[i].ptd = NULL; m_rgFormats[i].dwAspect = DVASPECT_CONTENT; m_rgFormats[i].lindex = -1; m_rgFormats[i].tymed = TYMED_ISTORAGE; i++; } m_cFormats = i; } // // Generic Data Object formatetc enumerator // //+------------------------------------------------------------------------- // // Member: CGenEnumFormatEtc::QueryInterface // // Synopsis: returns requested interfaces // // Effects: // // Arguments: [riid] -- the requested interface // [ppvObj] -- where to put the interface pointer // // Requires: // // Returns: HRESULT // // Signals: // // Modifies: // // Derivation: IEnumFORMATETC // // Algorithm: // // History: dd-mmm-yy Author Comment // 15-Apr-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- STDMETHODIMP CGenEnumFormatEtc::QueryInterface( REFIID riid, LPVOID *ppvObj ) { HRESULT hresult = NOERROR; if( IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IEnumFORMATETC) ) { *ppvObj = this; AddRef(); } else { *ppvObj = NULL; hresult = ResultFromScode(E_NOINTERFACE); } return hresult; } //+------------------------------------------------------------------------- // // Member: CGenEnumFormatEtc::AddRef // // Synopsis: increments the reference count // // Effects: // // Arguments: void // // Requires: // // Returns: ULONG-- the new reference count // // Signals: // // Modifies: // // Derivation: IEnumFORMATETC // // Algorithm: // // History: dd-mmm-yy Author Comment // 15-Apr-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CGenEnumFormatEtc::AddRef( ) { return ++m_refs; } //+------------------------------------------------------------------------- // // Member: CGenEnumFormatEtc::Release // // Synopsis: decrements the reference count on the object // // Effects: // // Arguments: void // // Requires: // // Returns: ULONG -- the new reference count // // Signals: // // Modifies: // // Derivation: IEnumFORMATETC // // Algorithm: // // History: dd-mmm-yy Author Comment // 15-Apr-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CGenEnumFormatEtc::Release( ) { ULONG cRefs; if( (cRefs = --m_refs ) == 0 ) { delete this; } return cRefs; } //+------------------------------------------------------------------------- // // Member: CGenEnumFormatEtc::Next // // Synopsis: gets the next [celt] formats // // Effects: // // Arguments: [celt] -- the number of elements to fetch // [rgelt] -- where to put them // [pceltFetched] -- the number of formats actually fetched // // Requires: // // Returns: NOERROR // // Signals: // // Modifies: // // Derivation: IEnumFORMATETC // // Algorithm: // // History: dd-mmm-yy Author Comment // 15-Apr-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- STDMETHODIMP CGenEnumFormatEtc::Next( ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched) { HRESULT hresult = NOERROR; ULONG cFetched; if( celt > m_cTotal - m_iCurrent ) { cFetched = m_cTotal - m_iCurrent; hresult = ResultFromScode(S_FALSE); } else { cFetched = celt; } memcpy( rgelt, m_rgFormats + m_iCurrent, cFetched * sizeof(FORMATETC) ); m_iCurrent += cFetched; if( pceltFetched ) { *pceltFetched = cFetched; } return hresult; } //+------------------------------------------------------------------------- // // Member: CGenEnumFormatEtc::Skip // // Synopsis: skips the next [celt] formats // // Effects: // // Arguments: [celt] -- the number of elements to skip // // Requires: // // Returns: NOERROR // // Signals: // // Modifies: // // Derivation: IEnumFORMATETC // // Algorithm: // // History: dd-mmm-yy Author Comment // 15-Apr-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- STDMETHODIMP CGenEnumFormatEtc::Skip( ULONG celt ) { HRESULT hresult = NOERROR; m_iCurrent += celt; if( m_iCurrent > m_cTotal ) { // whoops, skipped to far ahead. Set us to the max limit. m_iCurrent = m_cTotal; hresult = ResultFromScode(S_FALSE); } return hresult; } //+------------------------------------------------------------------------- // // Member: CGenEnumFormatEtc::Reset // // Synopsis: resets the seek pointer to zero // // Effects: // // Arguments: void // // Requires: // // Returns: NOERROR // // Signals: // // Modifies: // // Derivation: IEnumFORMATETC // // Algorithm: // // History: dd-mmm-yy Author Comment // 15-Apr-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- STDMETHODIMP CGenEnumFormatEtc::Reset( void ) { m_iCurrent = 0; return NOERROR; } //+------------------------------------------------------------------------- // // Member: CGenEnumFormatEtc::Clone // // Synopsis: clones the enumerator // // Effects: // // Arguments: [ppIEnum] -- where to put the cloned enumerator // // Requires: // // Returns: HRESULT // // Signals: // // Modifies: // // Derivation: IEnumFORMATETC // // Algorithm: // // History: dd-mmm-yy Author Comment // 15-Apr-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- STDMETHODIMP CGenEnumFormatEtc::Clone( IEnumFORMATETC **ppIEnum ) { HRESULT hresult = ResultFromScode(E_OUTOFMEMORY); CGenEnumFormatEtc * pClipEnum; *ppIEnum = NULL; pClipEnum = new CGenEnumFormatEtc(); // ref count will be 1 and m_iCurrent will be zero. if( pClipEnum ) { pClipEnum->m_cTotal = m_cTotal; pClipEnum->m_rgFormats = new FORMATETC[m_cTotal]; pClipEnum->m_iCurrent = m_iCurrent; assert(pClipEnum->m_rgFormats); if( pClipEnum->m_rgFormats ) { // copy our formatetc's into the cloned enumerator's // array memcpy(pClipEnum->m_rgFormats, m_rgFormats, m_cTotal * sizeof(FORMATETC) ); *ppIEnum = pClipEnum; hresult = NOERROR; } else { delete pClipEnum; } } return hresult; } //+------------------------------------------------------------------------- // // Member: CGenEnumFormatEtc::CGenEnumFormatEtc, private // // Synopsis: constructor // // Effects: // // Arguments: void // // Requires: // // Returns: // // Signals: // // Modifies: // // Derivation: // // Algorithm: // // History: dd-mmm-yy Author Comment // 15-Apr-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- CGenEnumFormatEtc::CGenEnumFormatEtc( void ) { m_refs = 1; // give the intial reference m_rgFormats = NULL; m_iCurrent = 0; m_cTotal = 0; } //+------------------------------------------------------------------------- // // Member: CGenEnumFormatEtc::~CGenEnumFormatEtc, private // // Synopsis: destructor // // Effects: // // Arguments: void // // Requires: // // Returns: // // Signals: // // Modifies: // // Derivation: // // Algorithm: // // History: dd-mmm-yy Author Comment // 15-Apr-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- CGenEnumFormatEtc::~CGenEnumFormatEtc( void ) { if( m_rgFormats ) { delete m_rgFormats; } } //+------------------------------------------------------------------------- // // Member: CGenEnumFormatEtc::Create, static, public // // Synopsis: Creates a clipboard formatetc enumerator // // Effects: // // Arguments: [ppIEnum] -- where to put the enumerator // // Requires: the clipboard must be open // // Returns: HRESULT // // Signals: // // Modifies: // // Derivation: // // Algorithm: // // History: dd-mmm-yy Author Comment // 15-Apr-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- HRESULT CGenEnumFormatEtc::Create( IEnumFORMATETC **ppIEnum, FORMATETC *prgFormats, DWORD cFormats ) { HRESULT hresult = ResultFromScode(E_OUTOFMEMORY); CGenEnumFormatEtc * pClipEnum; *ppIEnum = NULL; pClipEnum = new CGenEnumFormatEtc(); assert(pClipEnum); // now allocate memory for the array pClipEnum->m_rgFormats = new FORMATETC[cFormats]; assert(pClipEnum->m_rgFormats); pClipEnum->m_cTotal = cFormats; memcpy(pClipEnum->m_rgFormats, prgFormats, cFormats * sizeof(FORMATETC)); *ppIEnum = pClipEnum; return NOERROR; }