Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / dtrans / source / win32 / dtobj / XTDataObject.cxx
blob6df5c9d384c190025a14c4a3f0053f20d57fe7de
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>
23 #include "XTDataObject.hxx"
24 #include <com/sun/star/datatransfer/DataFlavor.hpp>
25 #include "../misc/ImplHelper.hxx"
26 #include "DTransHelper.hxx"
27 #include "TxtCnvtHlp.hxx"
28 #include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
29 #include <com/sun/star/datatransfer/clipboard/XClipboardEx.hpp>
30 #include <com/sun/star/awt/AsyncCallback.hpp>
31 #include <com/sun/star/awt/XCallback.hpp>
32 #include "FmtFilter.hxx"
33 #include <cppuhelper/implbase.hxx>
35 #if !defined WIN32_LEAN_AND_MEAN
36 # define WIN32_LEAN_AND_MEAN
37 #endif
38 #include <windows.h>
39 #include <shlobj.h>
41 using namespace com::sun::star::datatransfer;
42 using namespace com::sun::star::datatransfer::clipboard;
43 using namespace com::sun::star::uno;
44 using namespace com::sun::star::lang;
46 namespace {
48 void setupStgMedium( const FORMATETC& fetc,
49 CStgTransferHelper& stgTransHlp,
50 STGMEDIUM& stgmedium )
52 stgmedium.pUnkForRelease = nullptr;
54 if ( fetc.cfFormat == CF_METAFILEPICT )
56 stgmedium.tymed = TYMED_MFPICT;
57 stgmedium.hMetaFilePict = static_cast< HMETAFILEPICT >( stgTransHlp.getHGlobal( ) );
59 else if ( fetc.cfFormat == CF_ENHMETAFILE )
61 stgmedium.tymed = TYMED_ENHMF;
62 stgmedium.hEnhMetaFile = static_cast< HENHMETAFILE >( stgTransHlp.getHGlobal( ) );
64 else if ( fetc.tymed & TYMED_HGLOBAL )
66 stgmedium.tymed = TYMED_HGLOBAL;
67 stgmedium.hGlobal = stgTransHlp.getHGlobal( );
69 else if ( fetc.tymed & TYMED_ISTREAM )
71 stgmedium.tymed = TYMED_ISTREAM;
72 stgTransHlp.getIStream( &stgmedium.pstm );
74 else
75 OSL_ASSERT( false );
78 /**
79 We need to destroy XTransferable in the main thread to avoid dead lock
80 when locking in the clipboard thread. So we transfer the ownership of the
81 XTransferable reference to this object and release it when the callback
82 is executed in main thread.
84 class AsyncDereference : public cppu::WeakImplHelper<css::awt::XCallback>
86 Reference<XTransferable> maTransferable;
88 public:
89 AsyncDereference(css::uno::Reference<css::datatransfer::XTransferable> const & rTransferable)
90 : maTransferable(rTransferable)
93 virtual void SAL_CALL notify(css::uno::Any const &) override
95 maTransferable.set(nullptr);
99 // a helper class that will be thrown by the function validateFormatEtc
101 class CInvalidFormatEtcException
103 public:
104 HRESULT m_hr;
105 explicit CInvalidFormatEtcException( HRESULT hr ) : m_hr( hr ) {};
108 void validateFormatEtc( LPFORMATETC lpFormatEtc )
110 OSL_ASSERT( lpFormatEtc );
112 if ( lpFormatEtc->lindex != -1 )
113 throw CInvalidFormatEtcException( DV_E_LINDEX );
115 if ( !(lpFormatEtc->dwAspect & DVASPECT_CONTENT) &&
116 !(lpFormatEtc->dwAspect & DVASPECT_SHORTNAME) )
117 throw CInvalidFormatEtcException( DV_E_DVASPECT );
119 if ( !(lpFormatEtc->tymed & TYMED_HGLOBAL) &&
120 !(lpFormatEtc->tymed & TYMED_ISTREAM) &&
121 !(lpFormatEtc->tymed & TYMED_MFPICT) &&
122 !(lpFormatEtc->tymed & TYMED_ENHMF) )
123 throw CInvalidFormatEtcException( DV_E_TYMED );
125 if ( lpFormatEtc->cfFormat == CF_METAFILEPICT &&
126 !(lpFormatEtc->tymed & TYMED_MFPICT) )
127 throw CInvalidFormatEtcException( DV_E_TYMED );
129 if ( lpFormatEtc->cfFormat == CF_ENHMETAFILE &&
130 !(lpFormatEtc->tymed & TYMED_ENHMF) )
131 throw CInvalidFormatEtcException( DV_E_TYMED );
134 void invalidateStgMedium( STGMEDIUM& stgmedium )
136 stgmedium.tymed = TYMED_NULL;
139 HRESULT translateStgExceptionCode( HRESULT hr )
141 HRESULT hrTransl;
143 switch( hr )
145 case STG_E_MEDIUMFULL:
146 hrTransl = hr;
147 break;
149 default:
150 hrTransl = E_UNEXPECTED;
151 break;
154 return hrTransl;
157 // inline
158 void renderDataAndSetupStgMedium(
159 const sal_Int8* lpStorage, const FORMATETC& fetc, sal_uInt32 nInitStgSize,
160 sal_uInt32 nBytesToTransfer, STGMEDIUM& stgmedium )
162 OSL_PRECOND( !nInitStgSize || (nInitStgSize >= nBytesToTransfer),
163 "Memory size less than number of bytes to transfer" );
165 CStgTransferHelper stgTransfHelper( AUTO_INIT );
167 // setup storage size
168 if ( nInitStgSize > 0 )
169 stgTransfHelper.init( nInitStgSize );
171 #if OSL_DEBUG_LEVEL > 0
172 sal_uInt32 nBytesWritten = 0;
173 stgTransfHelper.write( lpStorage, nBytesToTransfer, &nBytesWritten );
174 OSL_ASSERT( nBytesWritten == nBytesToTransfer );
175 #else
176 stgTransfHelper.write( lpStorage, nBytesToTransfer );
177 #endif
179 setupStgMedium( fetc, stgTransfHelper, stgmedium );
184 CXTDataObject::CXTDataObject( const Reference< XComponentContext >& rxContext,
185 const Reference< XTransferable >& aXTransferable )
186 : m_nRefCnt( 0 )
187 , m_XTransferable( aXTransferable )
188 , m_XComponentContext( rxContext )
189 , m_bFormatEtcContainerInitialized( false )
190 , m_DataFormatTranslator( rxContext )
191 , m_FormatRegistrar( rxContext, m_DataFormatTranslator )
195 CXTDataObject::~CXTDataObject()
197 css::awt::AsyncCallback::create(m_XComponentContext)->addCallback(
198 new AsyncDereference(m_XTransferable),
199 css::uno::Any());
202 // IUnknown->QueryInterface
204 STDMETHODIMP CXTDataObject::QueryInterface( REFIID iid, void** ppvObject )
206 if ( nullptr == ppvObject )
207 return E_INVALIDARG;
209 HRESULT hr = E_NOINTERFACE;
211 *ppvObject = nullptr;
212 if ( ( __uuidof( IUnknown ) == iid ) ||
213 ( __uuidof( IDataObject ) == iid ) )
215 *ppvObject = static_cast< IUnknown* >( this );
216 static_cast<LPUNKNOWN>(*ppvObject)->AddRef( );
217 hr = S_OK;
220 return hr;
223 // IUnknown->AddRef
225 STDMETHODIMP_(ULONG) CXTDataObject::AddRef( )
227 return static_cast< ULONG >( InterlockedIncrement( &m_nRefCnt ) );
230 // IUnknown->Release
232 STDMETHODIMP_(ULONG) CXTDataObject::Release( )
234 ULONG nRefCnt =
235 static_cast< ULONG >( InterlockedDecrement( &m_nRefCnt ) );
237 if ( 0 == nRefCnt )
238 delete this;
240 return nRefCnt;
243 STDMETHODIMP CXTDataObject::GetData( FORMATETC * pFormatetc, STGMEDIUM * pmedium )
245 if ( !(pFormatetc && pmedium) )
246 return E_INVALIDARG;
250 // prepare data transfer
251 invalidateStgMedium( *pmedium );
252 validateFormatEtc( pFormatetc );
254 // handle locale request, because locale is an artificial format for us
255 if ( CF_LOCALE == pFormatetc->cfFormat )
256 renderLocaleAndSetupStgMedium( *pFormatetc, *pmedium );
257 else if ( CF_UNICODETEXT == pFormatetc->cfFormat )
258 renderUnicodeAndSetupStgMedium( *pFormatetc, *pmedium );
259 else
260 renderAnyDataAndSetupStgMedium( *pFormatetc, *pmedium );
262 catch(UnsupportedFlavorException&)
264 HRESULT hr = DV_E_FORMATETC;
266 CFormatEtc aFormatetc(*pFormatetc);
267 if (CFormatRegistrar::isSynthesizeableFormat(aFormatetc))
268 hr = renderSynthesizedFormatAndSetupStgMedium( *pFormatetc, *pmedium );
270 return hr;
272 catch( CInvalidFormatEtcException& ex )
274 return ex.m_hr;
276 catch( CStgTransferHelper::CStgTransferException& ex )
278 return translateStgExceptionCode( ex.m_hr );
280 catch(...)
282 return E_UNEXPECTED;
285 return S_OK;
288 //inline
289 void CXTDataObject::renderLocaleAndSetupStgMedium(
290 FORMATETC const & fetc, STGMEDIUM& stgmedium )
292 if ( !m_FormatRegistrar.hasSynthesizedLocale( ) )
293 throw CInvalidFormatEtcException( DV_E_FORMATETC );
294 LCID lcid = CFormatRegistrar::getSynthesizedLocale( );
295 renderDataAndSetupStgMedium(
296 reinterpret_cast< sal_Int8* >( &lcid ),
297 fetc,
299 sizeof( LCID ),
300 stgmedium );
303 void CXTDataObject::renderUnicodeAndSetupStgMedium(
304 FORMATETC const & fetc, STGMEDIUM& stgmedium )
306 DataFlavor aFlavor = formatEtcToDataFlavor( fetc );
308 Any aAny = m_XTransferable->getTransferData( aFlavor );
310 // unfortunately not all transferables fulfill the
311 // spec. and do throw an UnsupportedFlavorException
312 // so we must check the any
313 if ( !aAny.hasValue( ) )
315 OSL_FAIL( "XTransferable should throw an exception if ask for an unsupported flavor" );
316 throw UnsupportedFlavorException( );
319 OUString aText;
320 aAny >>= aText;
322 sal_uInt32 nBytesToTransfer = aText.getLength( ) * sizeof( sal_Unicode );
324 // to be sure there is an ending 0
325 sal_uInt32 nRequiredMemSize = nBytesToTransfer + sizeof( sal_Unicode );
327 renderDataAndSetupStgMedium(
328 reinterpret_cast< const sal_Int8* >( aText.getStr( ) ),
329 fetc,
330 nRequiredMemSize,
331 nBytesToTransfer,
332 stgmedium );
335 void CXTDataObject::renderAnyDataAndSetupStgMedium(
336 FORMATETC& fetc, STGMEDIUM& stgmedium )
338 DataFlavor aFlavor = formatEtcToDataFlavor( fetc );
340 Any aAny = m_XTransferable->getTransferData( aFlavor );
342 // unfortunately not all transferables fulfill the
343 // spec. and do throw an UnsupportedFlavorException
344 // so we must check the any
345 if ( !aAny.hasValue( ) )
347 OSL_FAIL( "XTransferable should throw an exception if ask for an unsupported flavor" );
348 throw UnsupportedFlavorException( );
351 // unfortunately not all transferables fulfill the
352 // spec. and do throw an UnsupportedFlavorException
353 // so we must check the any
354 if ( !aAny.hasValue( ) )
355 throw UnsupportedFlavorException( );
357 Sequence< sal_Int8 > clipDataStream;
358 aAny >>= clipDataStream;
360 sal_uInt32 nRequiredMemSize = 0;
361 if ( CDataFormatTranslator::isOemOrAnsiTextFormat( fetc.cfFormat ) )
362 nRequiredMemSize = sizeof( sal_Int8 ) * clipDataStream.getLength( ) + 1;
364 // prepare data for transmission
365 // #i124085# DIBV5 should not happen for now, but keep as hint here
366 if ( CF_DIBV5 == fetc.cfFormat || CF_DIB == fetc.cfFormat )
368 #ifdef DBG_UTIL
369 if(CF_DIBV5 == fetc.cfFormat)
371 OSL_ENSURE(sal_uInt32(clipDataStream.getLength()) > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPV5HEADER)), "Wrong size on CF_DIBV5 data (!)");
373 else // CF_DIB == fetc.cfFormat
375 OSL_ENSURE(sal_uInt32(clipDataStream.getLength()) > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)), "Wrong size on CF_DIB data (!)");
377 #endif
379 // remove BITMAPFILEHEADER
380 clipDataStream = OOBmpToWinDIB( clipDataStream );
383 if ( CF_METAFILEPICT == fetc.cfFormat )
385 stgmedium.tymed = TYMED_MFPICT;
386 stgmedium.hMetaFilePict = OOMFPictToWinMFPict( clipDataStream );
387 stgmedium.pUnkForRelease = nullptr;
389 else if( CF_ENHMETAFILE == fetc.cfFormat )
391 stgmedium.tymed = TYMED_ENHMF;
392 stgmedium.hMetaFilePict = OOMFPictToWinENHMFPict( clipDataStream );
393 stgmedium.pUnkForRelease = nullptr;
395 else
396 renderDataAndSetupStgMedium(
397 clipDataStream.getArray( ),
398 fetc,
399 nRequiredMemSize,
400 clipDataStream.getLength( ),
401 stgmedium );
404 HRESULT CXTDataObject::renderSynthesizedFormatAndSetupStgMedium( FORMATETC& fetc, STGMEDIUM& stgmedium )
406 HRESULT hr = S_OK;
410 if ( CF_UNICODETEXT == fetc.cfFormat )
411 // the transferable seems to have only text
412 renderSynthesizedUnicodeAndSetupStgMedium( fetc, stgmedium );
413 else if ( CDataFormatTranslator::isOemOrAnsiTextFormat( fetc.cfFormat ) )
414 // the transferable seems to have only unicode text
415 renderSynthesizedTextAndSetupStgMedium( fetc, stgmedium );
416 else
417 // the transferable seems to have only text/html
418 renderSynthesizedHtmlAndSetupStgMedium( fetc, stgmedium );
420 catch(UnsupportedFlavorException&)
422 hr = DV_E_FORMATETC;
424 catch( CInvalidFormatEtcException& )
426 OSL_FAIL( "Unexpected exception" );
428 catch( CStgTransferHelper::CStgTransferException& ex )
430 return translateStgExceptionCode( ex.m_hr );
432 catch(...)
434 hr = E_UNEXPECTED;
437 return hr;
440 // the transferable must have only text, so we will synthesize unicode text
442 void CXTDataObject::renderSynthesizedUnicodeAndSetupStgMedium( FORMATETC const & fetc, STGMEDIUM& stgmedium )
444 OSL_ASSERT( CF_UNICODETEXT == fetc.cfFormat );
446 Any aAny = m_XTransferable->getTransferData( m_FormatRegistrar.getRegisteredTextFlavor( ) );
448 // unfortunately not all transferables fulfill the
449 // spec. and do throw an UnsupportedFlavorException
450 // so we must check the any
451 if ( !aAny.hasValue( ) )
453 OSL_FAIL( "XTransferable should throw an exception if ask for an unsupported flavor" );
454 throw UnsupportedFlavorException( );
457 Sequence< sal_Int8 > aText;
458 aAny >>= aText;
460 CStgTransferHelper stgTransfHelper;
462 MultiByteToWideCharEx(
463 CFormatRegistrar::getRegisteredTextCodePage( ),
464 reinterpret_cast< char* >( aText.getArray( ) ),
465 aText.getLength( ),
466 stgTransfHelper );
468 setupStgMedium( fetc, stgTransfHelper, stgmedium );
471 // the transferable must have only unicode text so we will synthesize text
473 void CXTDataObject::renderSynthesizedTextAndSetupStgMedium( FORMATETC& fetc, STGMEDIUM& stgmedium )
475 OSL_ASSERT( CDataFormatTranslator::isOemOrAnsiTextFormat( fetc.cfFormat ) );
477 DataFlavor aFlavor = formatEtcToDataFlavor(
478 CDataFormatTranslator::getFormatEtcForClipformat( CF_UNICODETEXT ) );
480 Any aAny = m_XTransferable->getTransferData( aFlavor );
482 // unfortunately not all transferables fulfill the
483 // spec. and do throw an UnsupportedFlavorException
484 // so we must check the any
485 if ( !aAny.hasValue( ) )
487 OSL_FAIL( "XTransferable should throw an exception if ask for an unsupported flavor" );
488 throw UnsupportedFlavorException( );
491 OUString aUnicodeText;
492 aAny >>= aUnicodeText;
494 CStgTransferHelper stgTransfHelper;
496 WideCharToMultiByteEx(
497 GetACP( ),
498 o3tl::toW( aUnicodeText.getStr( ) ),
499 aUnicodeText.getLength( ),
500 stgTransfHelper );
502 setupStgMedium( fetc, stgTransfHelper, stgmedium );
505 void CXTDataObject::renderSynthesizedHtmlAndSetupStgMedium( FORMATETC& fetc, STGMEDIUM& stgmedium )
507 OSL_ASSERT( CDataFormatTranslator::isHTMLFormat( fetc.cfFormat ) );
509 DataFlavor aFlavor;
511 // creating a DataFlavor on the fly
512 aFlavor.MimeType = "text/html";
513 aFlavor.DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
515 Any aAny = m_XTransferable->getTransferData( aFlavor );
517 // unfortunately not all transferables fulfill the
518 // spec. and do throw an UnsupportedFlavorException
519 // so we must check the any
520 if ( !aAny.hasValue( ) )
522 OSL_FAIL( "XTransferable should throw an exception if ask for an unsupported flavor" );
523 throw UnsupportedFlavorException( );
526 Sequence< sal_Int8 > aTextHtmlSequence;
527 aAny >>= aTextHtmlSequence;
529 Sequence< sal_Int8 > aHTMLFormatSequence = TextHtmlToHTMLFormat( aTextHtmlSequence );
531 sal_uInt32 nBytesToTransfer = aHTMLFormatSequence.getLength( );
533 renderDataAndSetupStgMedium(
534 reinterpret_cast< const sal_Int8* >( aHTMLFormatSequence.getArray( ) ),
535 fetc,
537 nBytesToTransfer,
538 stgmedium );
541 // IDataObject->EnumFormatEtc
543 STDMETHODIMP CXTDataObject::EnumFormatEtc(
544 DWORD dwDirection, IEnumFORMATETC** ppenumFormatetc )
546 if ( nullptr == ppenumFormatetc )
547 return E_INVALIDARG;
549 if ( DATADIR_SET == dwDirection )
550 return E_NOTIMPL;
552 *ppenumFormatetc = nullptr;
554 InitializeFormatEtcContainer( );
556 HRESULT hr;
557 if ( DATADIR_GET == dwDirection )
559 *ppenumFormatetc = new CEnumFormatEtc( this, m_FormatEtcContainer );
560 static_cast< LPUNKNOWN >( *ppenumFormatetc )->AddRef( );
562 hr = S_OK;
564 else
565 hr = E_INVALIDARG;
567 return hr;
570 // IDataObject->QueryGetData
572 STDMETHODIMP CXTDataObject::QueryGetData( FORMATETC * pFormatetc )
574 if ( (nullptr == pFormatetc) || IsBadReadPtr( pFormatetc, sizeof( FORMATETC ) ) )
575 return E_INVALIDARG;
577 InitializeFormatEtcContainer( );
579 CFormatEtc aFormatetc(*pFormatetc);
580 return m_FormatEtcContainer.hasFormatEtc(aFormatetc) ? S_OK : S_FALSE;
583 // IDataObject->GetDataHere
585 STDMETHODIMP CXTDataObject::GetDataHere( FORMATETC *, STGMEDIUM * )
587 return E_NOTIMPL;
590 // IDataObject->GetCanonicalFormatEtc
592 STDMETHODIMP CXTDataObject::GetCanonicalFormatEtc( FORMATETC *, FORMATETC * )
594 return E_NOTIMPL;
597 // IDataObject->SetData
599 STDMETHODIMP CXTDataObject::SetData( FORMATETC *, STGMEDIUM *, BOOL )
601 return E_NOTIMPL;
604 // IDataObject->DAdvise
606 STDMETHODIMP CXTDataObject::DAdvise( FORMATETC *, DWORD, IAdviseSink *, DWORD * )
608 return E_NOTIMPL;
611 // IDataObject->DUnadvise
613 STDMETHODIMP CXTDataObject::DUnadvise( DWORD )
615 return E_NOTIMPL;
618 // IDataObject->EnumDAdvise
620 STDMETHODIMP CXTDataObject::EnumDAdvise( IEnumSTATDATA ** )
622 return E_NOTIMPL;
625 // for our convenience
627 CXTDataObject::operator IDataObject*( )
629 return static_cast< IDataObject* >( this );
632 inline
633 DataFlavor CXTDataObject::formatEtcToDataFlavor( const FORMATETC& aFormatEtc ) const
635 DataFlavor aFlavor;
637 if ( m_FormatRegistrar.hasSynthesizedLocale( ) )
638 aFlavor =
639 m_DataFormatTranslator.getDataFlavorFromFormatEtc( aFormatEtc, CFormatRegistrar::getSynthesizedLocale( ) );
640 else
641 aFlavor = m_DataFormatTranslator.getDataFlavorFromFormatEtc( aFormatEtc );
643 if ( !aFlavor.MimeType.getLength( ) )
644 throw UnsupportedFlavorException( );
646 return aFlavor;
649 inline void CXTDataObject::InitializeFormatEtcContainer( )
651 if ( !m_bFormatEtcContainerInitialized )
653 m_FormatRegistrar.RegisterFormats( m_XTransferable, m_FormatEtcContainer );
654 m_bFormatEtcContainerInitialized = true;
658 CEnumFormatEtc::CEnumFormatEtc( LPUNKNOWN lpUnkOuter, const CFormatEtcContainer& aFormatEtcContainer ) :
659 m_nRefCnt( 0 ),
660 m_lpUnkOuter( lpUnkOuter ),
661 m_FormatEtcContainer( aFormatEtcContainer )
663 Reset( );
666 // IUnknown->QueryInterface
668 STDMETHODIMP CEnumFormatEtc::QueryInterface( REFIID iid, void** ppvObject )
670 if ( nullptr == ppvObject )
671 return E_INVALIDARG;
673 HRESULT hr = E_NOINTERFACE;
675 *ppvObject = nullptr;
677 if ( ( __uuidof( IUnknown ) == iid ) ||
678 ( __uuidof( IEnumFORMATETC ) == iid ) )
680 *ppvObject = static_cast< IUnknown* >( this );
681 static_cast< LPUNKNOWN >( *ppvObject )->AddRef( );
682 hr = S_OK;
685 return hr;
688 // IUnknown->AddRef
690 STDMETHODIMP_(ULONG) CEnumFormatEtc::AddRef( )
692 // keep the dataobject alive
693 m_lpUnkOuter->AddRef( );
694 return InterlockedIncrement( &m_nRefCnt );
697 // IUnknown->Release
699 STDMETHODIMP_(ULONG) CEnumFormatEtc::Release( )
701 // release the outer dataobject
702 m_lpUnkOuter->Release( );
704 ULONG nRefCnt = InterlockedDecrement( &m_nRefCnt );
705 if ( 0 == nRefCnt )
706 delete this;
708 return nRefCnt;
711 // IEnumFORMATETC->Next
713 STDMETHODIMP CEnumFormatEtc::Next( ULONG nRequested, FORMATETC * lpDest, ULONG* lpFetched )
715 if ( ( nRequested < 1 ) ||
716 (( nRequested > 1 ) && ( nullptr == lpFetched )) ||
717 IsBadWritePtr( lpDest, sizeof( FORMATETC ) * nRequested ) )
718 return E_INVALIDARG;
720 sal_uInt32 nFetched = m_FormatEtcContainer.nextFormatEtc( lpDest, nRequested );
722 if ( nullptr != lpFetched )
723 *lpFetched = nFetched;
725 return (nFetched == nRequested) ? S_OK : S_FALSE;
728 // IEnumFORMATETC->Skip
730 STDMETHODIMP CEnumFormatEtc::Skip( ULONG celt )
732 return m_FormatEtcContainer.skipFormatEtc( celt ) ? S_OK : S_FALSE;
735 // IEnumFORMATETC->Reset
737 STDMETHODIMP CEnumFormatEtc::Reset( )
739 m_FormatEtcContainer.beginEnumFormatEtc( );
740 return S_OK;
743 // IEnumFORMATETC->Clone
745 STDMETHODIMP CEnumFormatEtc::Clone( IEnumFORMATETC** ppenum )
747 if ( nullptr == ppenum )
748 return E_INVALIDARG;
750 *ppenum = new CEnumFormatEtc( m_lpUnkOuter, m_FormatEtcContainer );
751 static_cast< LPUNKNOWN >( *ppenum )->AddRef( );
753 return S_OK;
756 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */