nss: upgrade to release 3.73
[LibreOffice.git] / vcl / win / dtrans / XTDataObject.cxx
blobadbed6bbec9f0d807ad12c8e6f7d1b87bd88a23b
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.set(nullptr);
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 OSL_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 // unfortunately not all transferables fulfill the
353 // spec. and do throw an UnsupportedFlavorException
354 // so we must check the any
355 if ( !aAny.hasValue( ) )
356 throw UnsupportedFlavorException( );
358 Sequence< sal_Int8 > clipDataStream;
359 aAny >>= clipDataStream;
361 sal_uInt32 nRequiredMemSize = 0;
362 if ( CDataFormatTranslator::isOemOrAnsiTextFormat( fetc.cfFormat ) )
363 nRequiredMemSize = sizeof( sal_Int8 ) * clipDataStream.getLength( ) + 1;
365 // prepare data for transmission
366 // #i124085# DIBV5 should not happen for now, but keep as hint here
367 if ( CF_DIBV5 == fetc.cfFormat || CF_DIB == fetc.cfFormat )
369 #ifdef DBG_UTIL
370 if(CF_DIBV5 == fetc.cfFormat)
372 OSL_ENSURE(o3tl::make_unsigned(clipDataStream.getLength()) > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPV5HEADER)), "Wrong size on CF_DIBV5 data (!)");
374 else // CF_DIB == fetc.cfFormat
376 OSL_ENSURE(o3tl::make_unsigned(clipDataStream.getLength()) > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)), "Wrong size on CF_DIB data (!)");
378 #endif
380 // remove BITMAPFILEHEADER
381 clipDataStream = OOBmpToWinDIB( clipDataStream );
384 if ( CF_METAFILEPICT == fetc.cfFormat )
386 stgmedium.tymed = TYMED_MFPICT;
387 stgmedium.hMetaFilePict = OOMFPictToWinMFPict( clipDataStream );
388 stgmedium.pUnkForRelease = nullptr;
390 else if( CF_ENHMETAFILE == fetc.cfFormat )
392 stgmedium.tymed = TYMED_ENHMF;
393 stgmedium.hMetaFilePict = OOMFPictToWinENHMFPict( clipDataStream );
394 stgmedium.pUnkForRelease = nullptr;
396 else
397 renderDataAndSetupStgMedium(
398 clipDataStream.getArray( ),
399 fetc,
400 nRequiredMemSize,
401 clipDataStream.getLength( ),
402 stgmedium );
405 HRESULT CXTDataObject::renderSynthesizedFormatAndSetupStgMedium( FORMATETC& fetc, STGMEDIUM& stgmedium )
407 HRESULT hr = S_OK;
411 if ( CF_UNICODETEXT == fetc.cfFormat )
412 // the transferable seems to have only text
413 renderSynthesizedUnicodeAndSetupStgMedium( fetc, stgmedium );
414 else if ( CDataFormatTranslator::isOemOrAnsiTextFormat( fetc.cfFormat ) )
415 // the transferable seems to have only unicode text
416 renderSynthesizedTextAndSetupStgMedium( fetc, stgmedium );
417 else
418 // the transferable seems to have only text/html
419 renderSynthesizedHtmlAndSetupStgMedium( fetc, stgmedium );
421 catch(UnsupportedFlavorException&)
423 hr = DV_E_FORMATETC;
425 catch( CInvalidFormatEtcException& )
427 OSL_FAIL( "Unexpected exception" );
429 catch( CStgTransferHelper::CStgTransferException& ex )
431 return translateStgExceptionCode( ex.m_hr );
433 catch(...)
435 hr = E_UNEXPECTED;
438 return hr;
441 // the transferable must have only text, so we will synthesize unicode text
443 void CXTDataObject::renderSynthesizedUnicodeAndSetupStgMedium( FORMATETC const & fetc, STGMEDIUM& stgmedium )
445 OSL_ASSERT( CF_UNICODETEXT == fetc.cfFormat );
447 Any aAny = m_XTransferable->getTransferData( m_FormatRegistrar.getRegisteredTextFlavor( ) );
449 // unfortunately not all transferables fulfill the
450 // spec. and do throw an UnsupportedFlavorException
451 // so we must check the any
452 if ( !aAny.hasValue( ) )
454 OSL_FAIL( "XTransferable should throw an exception if ask for an unsupported flavor" );
455 throw UnsupportedFlavorException( );
458 Sequence< sal_Int8 > aText;
459 aAny >>= aText;
461 CStgTransferHelper stgTransfHelper;
463 MultiByteToWideCharEx(
464 CFormatRegistrar::getRegisteredTextCodePage( ),
465 reinterpret_cast< char* >( aText.getArray( ) ),
466 aText.getLength( ),
467 stgTransfHelper );
469 setupStgMedium( fetc, stgTransfHelper, stgmedium );
472 // the transferable must have only unicode text so we will synthesize text
474 void CXTDataObject::renderSynthesizedTextAndSetupStgMedium( FORMATETC& fetc, STGMEDIUM& stgmedium )
476 OSL_ASSERT( CDataFormatTranslator::isOemOrAnsiTextFormat( fetc.cfFormat ) );
478 DataFlavor aFlavor = formatEtcToDataFlavor(
479 CDataFormatTranslator::getFormatEtcForClipformat( CF_UNICODETEXT ) );
481 Any aAny = m_XTransferable->getTransferData( aFlavor );
483 // unfortunately not all transferables fulfill the
484 // spec. and do throw an UnsupportedFlavorException
485 // so we must check the any
486 if ( !aAny.hasValue( ) )
488 OSL_FAIL( "XTransferable should throw an exception if ask for an unsupported flavor" );
489 throw UnsupportedFlavorException( );
492 OUString aUnicodeText;
493 aAny >>= aUnicodeText;
495 CStgTransferHelper stgTransfHelper;
497 WideCharToMultiByteEx(
498 GetACP( ),
499 o3tl::toW( aUnicodeText.getStr( ) ),
500 aUnicodeText.getLength( ),
501 stgTransfHelper );
503 setupStgMedium( fetc, stgTransfHelper, stgmedium );
506 void CXTDataObject::renderSynthesizedHtmlAndSetupStgMedium( FORMATETC& fetc, STGMEDIUM& stgmedium )
508 OSL_ASSERT( CDataFormatTranslator::isHTMLFormat( fetc.cfFormat ) );
510 DataFlavor aFlavor;
512 // creating a DataFlavor on the fly
513 aFlavor.MimeType = "text/html";
514 aFlavor.DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
516 Any aAny = m_XTransferable->getTransferData( aFlavor );
518 // unfortunately not all transferables fulfill the
519 // spec. and do throw an UnsupportedFlavorException
520 // so we must check the any
521 if ( !aAny.hasValue( ) )
523 OSL_FAIL( "XTransferable should throw an exception if ask for an unsupported flavor" );
524 throw UnsupportedFlavorException( );
527 Sequence< sal_Int8 > aTextHtmlSequence;
528 aAny >>= aTextHtmlSequence;
530 Sequence< sal_Int8 > aHTMLFormatSequence = TextHtmlToHTMLFormat( aTextHtmlSequence );
532 sal_uInt32 nBytesToTransfer = aHTMLFormatSequence.getLength( );
534 renderDataAndSetupStgMedium(
535 reinterpret_cast< const sal_Int8* >( aHTMLFormatSequence.getArray( ) ),
536 fetc,
538 nBytesToTransfer,
539 stgmedium );
542 // IDataObject->EnumFormatEtc
544 STDMETHODIMP CXTDataObject::EnumFormatEtc(
545 DWORD dwDirection, IEnumFORMATETC** ppenumFormatetc )
547 if ( nullptr == ppenumFormatetc )
548 return E_INVALIDARG;
550 if ( DATADIR_SET == dwDirection )
551 return E_NOTIMPL;
553 *ppenumFormatetc = nullptr;
555 InitializeFormatEtcContainer( );
557 HRESULT hr;
558 if ( DATADIR_GET == dwDirection )
560 *ppenumFormatetc = new CEnumFormatEtc( this, m_FormatEtcContainer );
561 static_cast< LPUNKNOWN >( *ppenumFormatetc )->AddRef( );
563 hr = S_OK;
565 else
566 hr = E_INVALIDARG;
568 return hr;
571 // IDataObject->QueryGetData
573 STDMETHODIMP CXTDataObject::QueryGetData( FORMATETC * pFormatetc )
575 if ( (nullptr == pFormatetc) || IsBadReadPtr( pFormatetc, sizeof( FORMATETC ) ) )
576 return E_INVALIDARG;
578 InitializeFormatEtcContainer( );
580 CFormatEtc aFormatetc(*pFormatetc);
581 return m_FormatEtcContainer.hasFormatEtc(aFormatetc) ? S_OK : S_FALSE;
584 // IDataObject->GetDataHere
586 STDMETHODIMP CXTDataObject::GetDataHere( FORMATETC *, STGMEDIUM * )
588 return E_NOTIMPL;
591 // IDataObject->GetCanonicalFormatEtc
593 STDMETHODIMP CXTDataObject::GetCanonicalFormatEtc( FORMATETC *, FORMATETC * )
595 return E_NOTIMPL;
598 // IDataObject->SetData
600 STDMETHODIMP CXTDataObject::SetData( FORMATETC *, STGMEDIUM *, BOOL )
602 return E_NOTIMPL;
605 // IDataObject->DAdvise
607 STDMETHODIMP CXTDataObject::DAdvise( FORMATETC *, DWORD, IAdviseSink *, DWORD * )
609 return E_NOTIMPL;
612 // IDataObject->DUnadvise
614 STDMETHODIMP CXTDataObject::DUnadvise( DWORD )
616 return E_NOTIMPL;
619 // IDataObject->EnumDAdvise
621 STDMETHODIMP CXTDataObject::EnumDAdvise( IEnumSTATDATA ** )
623 return E_NOTIMPL;
626 // for our convenience
628 CXTDataObject::operator IDataObject*( )
630 return static_cast< IDataObject* >( this );
633 inline
634 DataFlavor CXTDataObject::formatEtcToDataFlavor( const FORMATETC& aFormatEtc ) const
636 DataFlavor aFlavor;
638 if ( m_FormatRegistrar.hasSynthesizedLocale( ) )
639 aFlavor = m_DataFormatTranslator.getDataFlavorFromFormatEtc(
640 aFormatEtc.cfFormat, CFormatRegistrar::getSynthesizedLocale());
641 else
642 aFlavor = m_DataFormatTranslator.getDataFlavorFromFormatEtc(aFormatEtc.cfFormat);
644 if ( !aFlavor.MimeType.getLength( ) )
645 throw UnsupportedFlavorException( );
647 return aFlavor;
650 inline void CXTDataObject::InitializeFormatEtcContainer( )
652 if ( !m_bFormatEtcContainerInitialized )
654 m_FormatRegistrar.RegisterFormats( m_XTransferable, m_FormatEtcContainer );
655 m_bFormatEtcContainerInitialized = true;
659 CEnumFormatEtc::CEnumFormatEtc( LPUNKNOWN lpUnkOuter, const CFormatEtcContainer& aFormatEtcContainer ) :
660 m_nRefCnt( 0 ),
661 m_lpUnkOuter( lpUnkOuter ),
662 m_FormatEtcContainer( aFormatEtcContainer )
664 Reset( );
667 // IUnknown->QueryInterface
669 STDMETHODIMP CEnumFormatEtc::QueryInterface( REFIID iid, void** ppvObject )
671 if ( nullptr == ppvObject )
672 return E_INVALIDARG;
674 HRESULT hr = E_NOINTERFACE;
676 *ppvObject = nullptr;
678 if ( ( __uuidof( IUnknown ) == iid ) ||
679 ( __uuidof( IEnumFORMATETC ) == iid ) )
681 *ppvObject = static_cast< IUnknown* >( this );
682 static_cast< LPUNKNOWN >( *ppvObject )->AddRef( );
683 hr = S_OK;
686 return hr;
689 // IUnknown->AddRef
691 STDMETHODIMP_(ULONG) CEnumFormatEtc::AddRef( )
693 // keep the dataobject alive
694 m_lpUnkOuter->AddRef( );
695 return InterlockedIncrement( &m_nRefCnt );
698 // IUnknown->Release
700 STDMETHODIMP_(ULONG) CEnumFormatEtc::Release( )
702 // release the outer dataobject
703 m_lpUnkOuter->Release( );
705 ULONG nRefCnt = InterlockedDecrement( &m_nRefCnt );
706 if ( 0 == nRefCnt )
707 delete this;
709 return nRefCnt;
712 // IEnumFORMATETC->Next
714 STDMETHODIMP CEnumFormatEtc::Next( ULONG nRequested, FORMATETC * lpDest, ULONG* lpFetched )
716 if ( ( nRequested < 1 ) ||
717 (( nRequested > 1 ) && ( nullptr == lpFetched )) ||
718 IsBadWritePtr( lpDest, sizeof( FORMATETC ) * nRequested ) )
719 return E_INVALIDARG;
721 sal_uInt32 nFetched = m_FormatEtcContainer.nextFormatEtc( lpDest, nRequested );
723 if ( nullptr != lpFetched )
724 *lpFetched = nFetched;
726 return (nFetched == nRequested) ? S_OK : S_FALSE;
729 // IEnumFORMATETC->Skip
731 STDMETHODIMP CEnumFormatEtc::Skip( ULONG celt )
733 return m_FormatEtcContainer.skipFormatEtc( celt ) ? S_OK : S_FALSE;
736 // IEnumFORMATETC->Reset
738 STDMETHODIMP CEnumFormatEtc::Reset( )
740 m_FormatEtcContainer.beginEnumFormatEtc( );
741 return S_OK;
744 // IEnumFORMATETC->Clone
746 STDMETHODIMP CEnumFormatEtc::Clone( IEnumFORMATETC** ppenum )
748 if ( nullptr == ppenum )
749 return E_INVALIDARG;
751 *ppenum = new CEnumFormatEtc( m_lpUnkOuter, m_FormatEtcContainer );
752 static_cast< LPUNKNOWN >( *ppenum )->AddRef( );
754 return S_OK;
757 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */