tdf#164627 docx export: consolidate getWordCompatibilityMode()
[LibreOffice.git] / vcl / win / dtrans / XTDataObject.cxx
blob1997ec8386a66329677855c0b2422e1a91eb451f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <osl/diagnose.h>
21 #include <o3tl/char16_t2wchar_t.hxx>
22 #include <o3tl/safeint.hxx>
24 #include "XTDataObject.hxx"
25 #include <com/sun/star/datatransfer/DataFlavor.hpp>
26 #include "ImplHelper.hxx"
27 #include "DTransHelper.hxx"
28 #include "TxtCnvtHlp.hxx"
29 #include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
30 #include <com/sun/star/datatransfer/clipboard/XClipboardEx.hpp>
31 #include <com/sun/star/awt/AsyncCallback.hpp>
32 #include <com/sun/star/awt/XCallback.hpp>
33 #include "FmtFilter.hxx"
34 #include <cppuhelper/implbase.hxx>
36 #if !defined WIN32_LEAN_AND_MEAN
37 # define WIN32_LEAN_AND_MEAN
38 #endif
39 #include <windows.h>
40 #include <shlobj.h>
42 using namespace com::sun::star::datatransfer;
43 using namespace com::sun::star::datatransfer::clipboard;
44 using namespace com::sun::star::uno;
45 using namespace com::sun::star::lang;
47 namespace {
49 void setupStgMedium( const FORMATETC& fetc,
50 CStgTransferHelper& stgTransHlp,
51 STGMEDIUM& stgmedium )
53 stgmedium.pUnkForRelease = nullptr;
55 if ( fetc.cfFormat == CF_METAFILEPICT )
57 stgmedium.tymed = TYMED_MFPICT;
58 stgmedium.hMetaFilePict = static_cast< HMETAFILEPICT >( stgTransHlp.getHGlobal( ) );
60 else if ( fetc.cfFormat == CF_ENHMETAFILE )
62 stgmedium.tymed = TYMED_ENHMF;
63 stgmedium.hEnhMetaFile = static_cast< HENHMETAFILE >( stgTransHlp.getHGlobal( ) );
65 else if ( fetc.tymed & TYMED_HGLOBAL )
67 stgmedium.tymed = TYMED_HGLOBAL;
68 stgmedium.hGlobal = stgTransHlp.getHGlobal( );
70 else if ( fetc.tymed & TYMED_ISTREAM )
72 stgmedium.tymed = TYMED_ISTREAM;
73 stgTransHlp.getIStream( &stgmedium.pstm );
75 else
76 OSL_ASSERT( false );
79 /**
80 We need to destroy XTransferable in the main thread to avoid dead lock
81 when locking in the clipboard thread. So we transfer the ownership of the
82 XTransferable reference to this object and release it when the callback
83 is executed in main thread.
85 class AsyncDereference : public cppu::WeakImplHelper<css::awt::XCallback>
87 Reference<XTransferable> maTransferable;
89 public:
90 AsyncDereference(css::uno::Reference<css::datatransfer::XTransferable> const & rTransferable)
91 : maTransferable(rTransferable)
94 virtual void SAL_CALL notify(css::uno::Any const &) override
96 maTransferable.clear();
100 // a helper class that will be thrown by the function validateFormatEtc
102 class CInvalidFormatEtcException
104 public:
105 HRESULT m_hr;
106 explicit CInvalidFormatEtcException( HRESULT hr ) : m_hr( hr ) {};
109 void validateFormatEtc( LPFORMATETC lpFormatEtc )
111 assert(lpFormatEtc);
113 if ( lpFormatEtc->lindex != -1 )
114 throw CInvalidFormatEtcException( DV_E_LINDEX );
116 if ( !(lpFormatEtc->dwAspect & DVASPECT_CONTENT) &&
117 !(lpFormatEtc->dwAspect & DVASPECT_SHORTNAME) )
118 throw CInvalidFormatEtcException( DV_E_DVASPECT );
120 if ( !(lpFormatEtc->tymed & TYMED_HGLOBAL) &&
121 !(lpFormatEtc->tymed & TYMED_ISTREAM) &&
122 !(lpFormatEtc->tymed & TYMED_MFPICT) &&
123 !(lpFormatEtc->tymed & TYMED_ENHMF) )
124 throw CInvalidFormatEtcException( DV_E_TYMED );
126 if ( lpFormatEtc->cfFormat == CF_METAFILEPICT &&
127 !(lpFormatEtc->tymed & TYMED_MFPICT) )
128 throw CInvalidFormatEtcException( DV_E_TYMED );
130 if ( lpFormatEtc->cfFormat == CF_ENHMETAFILE &&
131 !(lpFormatEtc->tymed & TYMED_ENHMF) )
132 throw CInvalidFormatEtcException( DV_E_TYMED );
135 void invalidateStgMedium( STGMEDIUM& stgmedium )
137 stgmedium.tymed = TYMED_NULL;
140 HRESULT translateStgExceptionCode( HRESULT hr )
142 HRESULT hrTransl;
144 switch( hr )
146 case STG_E_MEDIUMFULL:
147 hrTransl = hr;
148 break;
150 default:
151 hrTransl = E_UNEXPECTED;
152 break;
155 return hrTransl;
158 // inline
159 void renderDataAndSetupStgMedium(
160 const sal_Int8* lpStorage, const FORMATETC& fetc, sal_uInt32 nInitStgSize,
161 sal_uInt32 nBytesToTransfer, STGMEDIUM& stgmedium )
163 OSL_PRECOND( !nInitStgSize || (nInitStgSize >= nBytesToTransfer),
164 "Memory size less than number of bytes to transfer" );
166 CStgTransferHelper stgTransfHelper( AUTO_INIT );
168 // setup storage size
169 if ( nInitStgSize > 0 )
170 stgTransfHelper.init( nInitStgSize );
172 #if OSL_DEBUG_LEVEL > 0
173 sal_uInt32 nBytesWritten = 0;
174 stgTransfHelper.write( lpStorage, nBytesToTransfer, &nBytesWritten );
175 OSL_ASSERT( nBytesWritten == nBytesToTransfer );
176 #else
177 stgTransfHelper.write( lpStorage, nBytesToTransfer );
178 #endif
180 setupStgMedium( fetc, stgTransfHelper, stgmedium );
185 CXTDataObject::CXTDataObject( const Reference< XComponentContext >& rxContext,
186 const Reference< XTransferable >& aXTransferable )
187 : m_nRefCnt( 0 )
188 , m_XTransferable( aXTransferable )
189 , m_XComponentContext( rxContext )
190 , m_bFormatEtcContainerInitialized( false )
191 , m_DataFormatTranslator( rxContext )
192 , m_FormatRegistrar( rxContext, m_DataFormatTranslator )
196 CXTDataObject::~CXTDataObject()
198 css::awt::AsyncCallback::create(m_XComponentContext)->addCallback(
199 new AsyncDereference(m_XTransferable),
200 css::uno::Any());
203 // IUnknown->QueryInterface
205 STDMETHODIMP CXTDataObject::QueryInterface( REFIID iid, void** ppvObject )
207 if ( nullptr == ppvObject )
208 return E_INVALIDARG;
210 HRESULT hr = E_NOINTERFACE;
212 *ppvObject = nullptr;
213 if ( ( __uuidof( IUnknown ) == iid ) ||
214 ( __uuidof( IDataObject ) == iid ) )
216 *ppvObject = static_cast< IUnknown* >( this );
217 static_cast<LPUNKNOWN>(*ppvObject)->AddRef( );
218 hr = S_OK;
221 return hr;
224 // IUnknown->AddRef
226 STDMETHODIMP_(ULONG) CXTDataObject::AddRef( )
228 return static_cast< ULONG >( InterlockedIncrement( &m_nRefCnt ) );
231 // IUnknown->Release
233 STDMETHODIMP_(ULONG) CXTDataObject::Release( )
235 ULONG nRefCnt =
236 static_cast< ULONG >( InterlockedDecrement( &m_nRefCnt ) );
238 if ( 0 == nRefCnt )
239 delete this;
241 return nRefCnt;
244 STDMETHODIMP CXTDataObject::GetData( FORMATETC * pFormatetc, STGMEDIUM * pmedium )
246 if ( !(pFormatetc && pmedium) )
247 return E_INVALIDARG;
251 // prepare data transfer
252 invalidateStgMedium( *pmedium );
253 validateFormatEtc( pFormatetc );
255 // handle locale request, because locale is an artificial format for us
256 if ( CF_LOCALE == pFormatetc->cfFormat )
257 renderLocaleAndSetupStgMedium( *pFormatetc, *pmedium );
258 else if ( CF_UNICODETEXT == pFormatetc->cfFormat )
259 renderUnicodeAndSetupStgMedium( *pFormatetc, *pmedium );
260 else
261 renderAnyDataAndSetupStgMedium( *pFormatetc, *pmedium );
263 catch(UnsupportedFlavorException&)
265 HRESULT hr = DV_E_FORMATETC;
267 CFormatEtc aFormatetc(*pFormatetc);
268 if (CFormatRegistrar::isSynthesizeableFormat(aFormatetc))
269 hr = renderSynthesizedFormatAndSetupStgMedium( *pFormatetc, *pmedium );
271 return hr;
273 catch( CInvalidFormatEtcException& ex )
275 return ex.m_hr;
277 catch( CStgTransferHelper::CStgTransferException& ex )
279 return translateStgExceptionCode( ex.m_hr );
281 catch(...)
283 return E_UNEXPECTED;
286 return S_OK;
289 //inline
290 void CXTDataObject::renderLocaleAndSetupStgMedium(
291 FORMATETC const & fetc, STGMEDIUM& stgmedium )
293 if ( !m_FormatRegistrar.hasSynthesizedLocale( ) )
294 throw CInvalidFormatEtcException( DV_E_FORMATETC );
295 LCID lcid = CFormatRegistrar::getSynthesizedLocale( );
296 renderDataAndSetupStgMedium(
297 reinterpret_cast< sal_Int8* >( &lcid ),
298 fetc,
300 sizeof( LCID ),
301 stgmedium );
304 void CXTDataObject::renderUnicodeAndSetupStgMedium(
305 FORMATETC const & fetc, STGMEDIUM& stgmedium )
307 DataFlavor aFlavor = formatEtcToDataFlavor( fetc );
309 Any aAny = m_XTransferable->getTransferData( aFlavor );
311 // unfortunately not all transferables fulfill the
312 // spec. and do throw an UnsupportedFlavorException
313 // so we must check the any
314 if ( !aAny.hasValue( ) )
316 OSL_FAIL( "XTransferable should throw an exception if ask for an unsupported flavor" );
317 throw UnsupportedFlavorException( );
320 OUString aText;
321 aAny >>= aText;
323 sal_uInt32 nBytesToTransfer = aText.getLength( ) * sizeof( sal_Unicode );
325 // to be sure there is an ending 0
326 sal_uInt32 nRequiredMemSize = nBytesToTransfer + sizeof( sal_Unicode );
328 renderDataAndSetupStgMedium(
329 reinterpret_cast< const sal_Int8* >( aText.getStr( ) ),
330 fetc,
331 nRequiredMemSize,
332 nBytesToTransfer,
333 stgmedium );
336 void CXTDataObject::renderAnyDataAndSetupStgMedium(
337 FORMATETC& fetc, STGMEDIUM& stgmedium )
339 DataFlavor aFlavor = formatEtcToDataFlavor( fetc );
341 Any aAny = m_XTransferable->getTransferData( aFlavor );
343 // unfortunately not all transferables fulfill the
344 // spec. and do throw an UnsupportedFlavorException
345 // so we must check the any
346 if ( !aAny.hasValue( ) )
348 OSL_FAIL( "XTransferable should throw an exception if ask for an unsupported flavor" );
349 throw UnsupportedFlavorException( );
352 Sequence< sal_Int8 > clipDataStream;
353 aAny >>= clipDataStream;
355 sal_uInt32 nRequiredMemSize = 0;
356 if ( CDataFormatTranslator::isOemOrAnsiTextFormat( fetc.cfFormat ) )
357 nRequiredMemSize = sizeof( sal_Int8 ) * clipDataStream.getLength( ) + 1;
359 // prepare data for transmission
360 // #i124085# DIBV5 should not happen for now, but keep as hint here
361 if ( CF_DIBV5 == fetc.cfFormat || CF_DIB == fetc.cfFormat )
363 #ifdef DBG_UTIL
364 if(CF_DIBV5 == fetc.cfFormat)
366 OSL_ENSURE(o3tl::make_unsigned(clipDataStream.getLength()) > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPV5HEADER)), "Wrong size on CF_DIBV5 data (!)");
368 else // CF_DIB == fetc.cfFormat
370 OSL_ENSURE(o3tl::make_unsigned(clipDataStream.getLength()) > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)), "Wrong size on CF_DIB data (!)");
372 #endif
374 // remove BITMAPFILEHEADER
375 clipDataStream = OOBmpToWinDIB( clipDataStream );
378 if ( CF_METAFILEPICT == fetc.cfFormat )
380 stgmedium.tymed = TYMED_MFPICT;
381 stgmedium.hMetaFilePict = OOMFPictToWinMFPict( clipDataStream );
382 stgmedium.pUnkForRelease = nullptr;
384 else if( CF_ENHMETAFILE == fetc.cfFormat )
386 stgmedium.tymed = TYMED_ENHMF;
387 stgmedium.hMetaFilePict = OOMFPictToWinENHMFPict( clipDataStream );
388 stgmedium.pUnkForRelease = nullptr;
390 else
391 renderDataAndSetupStgMedium(
392 clipDataStream.getArray( ),
393 fetc,
394 nRequiredMemSize,
395 clipDataStream.getLength( ),
396 stgmedium );
399 HRESULT CXTDataObject::renderSynthesizedFormatAndSetupStgMedium( FORMATETC& fetc, STGMEDIUM& stgmedium )
401 HRESULT hr = S_OK;
405 if ( CF_UNICODETEXT == fetc.cfFormat )
406 // the transferable seems to have only text
407 renderSynthesizedUnicodeAndSetupStgMedium( fetc, stgmedium );
408 else if ( CDataFormatTranslator::isOemOrAnsiTextFormat( fetc.cfFormat ) )
409 // the transferable seems to have only unicode text
410 renderSynthesizedTextAndSetupStgMedium( fetc, stgmedium );
411 else
412 // the transferable seems to have only text/html
413 renderSynthesizedHtmlAndSetupStgMedium( fetc, stgmedium );
415 catch(UnsupportedFlavorException&)
417 hr = DV_E_FORMATETC;
419 catch( CInvalidFormatEtcException& )
421 OSL_FAIL( "Unexpected exception" );
423 catch( CStgTransferHelper::CStgTransferException& ex )
425 return translateStgExceptionCode( ex.m_hr );
427 catch(...)
429 hr = E_UNEXPECTED;
432 return hr;
435 // the transferable must have only text, so we will synthesize unicode text
437 void CXTDataObject::renderSynthesizedUnicodeAndSetupStgMedium( FORMATETC const & fetc, STGMEDIUM& stgmedium )
439 OSL_ASSERT( CF_UNICODETEXT == fetc.cfFormat );
441 Any aAny = m_XTransferable->getTransferData( m_FormatRegistrar.getRegisteredTextFlavor( ) );
443 // unfortunately not all transferables fulfill the
444 // spec. and do throw an UnsupportedFlavorException
445 // so we must check the any
446 if ( !aAny.hasValue( ) )
448 OSL_FAIL( "XTransferable should throw an exception if ask for an unsupported flavor" );
449 throw UnsupportedFlavorException( );
452 Sequence< sal_Int8 > aText;
453 aAny >>= aText;
455 CStgTransferHelper stgTransfHelper;
457 MultiByteToWideCharEx(
458 CFormatRegistrar::getRegisteredTextCodePage( ),
459 reinterpret_cast< char* >( aText.getArray( ) ),
460 aText.getLength( ),
461 stgTransfHelper );
463 setupStgMedium( fetc, stgTransfHelper, stgmedium );
466 // the transferable must have only unicode text so we will synthesize text
468 void CXTDataObject::renderSynthesizedTextAndSetupStgMedium( FORMATETC& fetc, STGMEDIUM& stgmedium )
470 OSL_ASSERT( CDataFormatTranslator::isOemOrAnsiTextFormat( fetc.cfFormat ) );
472 DataFlavor aFlavor = formatEtcToDataFlavor(
473 CDataFormatTranslator::getFormatEtcForClipformat( CF_UNICODETEXT ) );
475 Any aAny = m_XTransferable->getTransferData( aFlavor );
477 // unfortunately not all transferables fulfill the
478 // spec. and do throw an UnsupportedFlavorException
479 // so we must check the any
480 if ( !aAny.hasValue( ) )
482 OSL_FAIL( "XTransferable should throw an exception if ask for an unsupported flavor" );
483 throw UnsupportedFlavorException( );
486 OUString aUnicodeText;
487 aAny >>= aUnicodeText;
489 CStgTransferHelper stgTransfHelper;
491 WideCharToMultiByteEx(
492 GetACP( ),
493 o3tl::toW( aUnicodeText.getStr( ) ),
494 aUnicodeText.getLength( ),
495 stgTransfHelper );
497 setupStgMedium( fetc, stgTransfHelper, stgmedium );
500 void CXTDataObject::renderSynthesizedHtmlAndSetupStgMedium( FORMATETC& fetc, STGMEDIUM& stgmedium )
502 OSL_ASSERT( CDataFormatTranslator::isHTMLFormat( fetc.cfFormat ) );
504 DataFlavor aFlavor;
506 // creating a DataFlavor on the fly
507 aFlavor.MimeType = "text/html";
508 aFlavor.DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
510 Any aAny = m_XTransferable->getTransferData( aFlavor );
512 // unfortunately not all transferables fulfill the
513 // spec. and do throw an UnsupportedFlavorException
514 // so we must check the any
515 if ( !aAny.hasValue( ) )
517 OSL_FAIL( "XTransferable should throw an exception if ask for an unsupported flavor" );
518 throw UnsupportedFlavorException( );
521 Sequence< sal_Int8 > aTextHtmlSequence;
522 aAny >>= aTextHtmlSequence;
524 Sequence< sal_Int8 > aHTMLFormatSequence = TextHtmlToHTMLFormat( aTextHtmlSequence );
526 sal_uInt32 nBytesToTransfer = aHTMLFormatSequence.getLength( );
528 renderDataAndSetupStgMedium(
529 reinterpret_cast< const sal_Int8* >( aHTMLFormatSequence.getArray( ) ),
530 fetc,
532 nBytesToTransfer,
533 stgmedium );
536 // IDataObject->EnumFormatEtc
538 STDMETHODIMP CXTDataObject::EnumFormatEtc(
539 DWORD dwDirection, IEnumFORMATETC** ppenumFormatetc )
541 if ( nullptr == ppenumFormatetc )
542 return E_INVALIDARG;
544 if ( DATADIR_SET == dwDirection )
545 return E_NOTIMPL;
547 *ppenumFormatetc = nullptr;
549 InitializeFormatEtcContainer( );
551 HRESULT hr;
552 if ( DATADIR_GET == dwDirection )
554 *ppenumFormatetc = new CEnumFormatEtc( this, m_FormatEtcContainer );
555 static_cast< LPUNKNOWN >( *ppenumFormatetc )->AddRef( );
557 hr = S_OK;
559 else
560 hr = E_INVALIDARG;
562 return hr;
565 // IDataObject->QueryGetData
567 STDMETHODIMP CXTDataObject::QueryGetData( FORMATETC * pFormatetc )
569 if ( (nullptr == pFormatetc) || IsBadReadPtr( pFormatetc, sizeof( FORMATETC ) ) )
570 return E_INVALIDARG;
572 InitializeFormatEtcContainer( );
574 CFormatEtc aFormatetc(*pFormatetc);
575 return m_FormatEtcContainer.hasFormatEtc(aFormatetc) ? S_OK : S_FALSE;
578 // IDataObject->GetDataHere
580 STDMETHODIMP CXTDataObject::GetDataHere( FORMATETC *, STGMEDIUM * )
582 return E_NOTIMPL;
585 // IDataObject->GetCanonicalFormatEtc
587 STDMETHODIMP CXTDataObject::GetCanonicalFormatEtc( FORMATETC *, FORMATETC * )
589 return E_NOTIMPL;
592 // IDataObject->SetData
594 STDMETHODIMP CXTDataObject::SetData( FORMATETC *, STGMEDIUM *, BOOL )
596 return E_NOTIMPL;
599 // IDataObject->DAdvise
601 STDMETHODIMP CXTDataObject::DAdvise( FORMATETC *, DWORD, IAdviseSink *, DWORD * )
603 return E_NOTIMPL;
606 // IDataObject->DUnadvise
608 STDMETHODIMP CXTDataObject::DUnadvise( DWORD )
610 return E_NOTIMPL;
613 // IDataObject->EnumDAdvise
615 STDMETHODIMP CXTDataObject::EnumDAdvise( IEnumSTATDATA ** )
617 return E_NOTIMPL;
620 // for our convenience
622 CXTDataObject::operator IDataObject*( )
624 return static_cast< IDataObject* >( this );
627 inline
628 DataFlavor CXTDataObject::formatEtcToDataFlavor( const FORMATETC& aFormatEtc ) const
630 DataFlavor aFlavor;
632 if ( m_FormatRegistrar.hasSynthesizedLocale( ) )
633 aFlavor = m_DataFormatTranslator.getDataFlavorFromFormatEtc(
634 aFormatEtc.cfFormat, CFormatRegistrar::getSynthesizedLocale());
635 else
636 aFlavor = m_DataFormatTranslator.getDataFlavorFromFormatEtc(aFormatEtc.cfFormat);
638 if ( !aFlavor.MimeType.getLength( ) )
639 throw UnsupportedFlavorException( );
641 return aFlavor;
644 inline void CXTDataObject::InitializeFormatEtcContainer( )
646 if ( !m_bFormatEtcContainerInitialized )
648 m_FormatRegistrar.RegisterFormats( m_XTransferable, m_FormatEtcContainer );
649 m_bFormatEtcContainerInitialized = true;
653 CEnumFormatEtc::CEnumFormatEtc( LPUNKNOWN lpUnkOuter, const CFormatEtcContainer& aFormatEtcContainer ) :
654 m_nRefCnt( 0 ),
655 m_lpUnkOuter( lpUnkOuter ),
656 m_FormatEtcContainer( aFormatEtcContainer )
658 Reset( );
661 // IUnknown->QueryInterface
663 STDMETHODIMP CEnumFormatEtc::QueryInterface( REFIID iid, void** ppvObject )
665 if ( nullptr == ppvObject )
666 return E_INVALIDARG;
668 HRESULT hr = E_NOINTERFACE;
670 *ppvObject = nullptr;
672 if ( ( __uuidof( IUnknown ) == iid ) ||
673 ( __uuidof( IEnumFORMATETC ) == iid ) )
675 *ppvObject = static_cast< IUnknown* >( this );
676 static_cast< LPUNKNOWN >( *ppvObject )->AddRef( );
677 hr = S_OK;
680 return hr;
683 // IUnknown->AddRef
685 STDMETHODIMP_(ULONG) CEnumFormatEtc::AddRef( )
687 // keep the dataobject alive
688 m_lpUnkOuter->AddRef( );
689 return InterlockedIncrement( &m_nRefCnt );
692 // IUnknown->Release
694 STDMETHODIMP_(ULONG) CEnumFormatEtc::Release( )
696 // release the outer dataobject
697 m_lpUnkOuter->Release( );
699 ULONG nRefCnt = InterlockedDecrement( &m_nRefCnt );
700 if ( 0 == nRefCnt )
701 delete this;
703 return nRefCnt;
706 // IEnumFORMATETC->Next
708 STDMETHODIMP CEnumFormatEtc::Next( ULONG nRequested, FORMATETC * lpDest, ULONG* lpFetched )
710 if ( ( nRequested < 1 ) ||
711 (( nRequested > 1 ) && ( nullptr == lpFetched )) ||
712 IsBadWritePtr( lpDest, sizeof( FORMATETC ) * nRequested ) )
713 return E_INVALIDARG;
715 sal_uInt32 nFetched = m_FormatEtcContainer.nextFormatEtc( lpDest, nRequested );
717 if ( nullptr != lpFetched )
718 *lpFetched = nFetched;
720 return (nFetched == nRequested) ? S_OK : S_FALSE;
723 // IEnumFORMATETC->Skip
725 STDMETHODIMP CEnumFormatEtc::Skip( ULONG celt )
727 return m_FormatEtcContainer.skipFormatEtc( celt ) ? S_OK : S_FALSE;
730 // IEnumFORMATETC->Reset
732 STDMETHODIMP CEnumFormatEtc::Reset( )
734 m_FormatEtcContainer.beginEnumFormatEtc( );
735 return S_OK;
738 // IEnumFORMATETC->Clone
740 STDMETHODIMP CEnumFormatEtc::Clone( IEnumFORMATETC** ppenum )
742 if ( nullptr == ppenum )
743 return E_INVALIDARG;
745 *ppenum = new CEnumFormatEtc( m_lpUnkOuter, m_FormatEtcContainer );
746 static_cast< LPUNKNOWN >( *ppenum )->AddRef( );
748 return S_OK;
751 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */