summaryrefslogtreecommitdiffstats
path: root/vcl/win/dtrans
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/win/dtrans')
-rw-r--r--vcl/win/dtrans/APNDataObject.cxx327
-rw-r--r--vcl/win/dtrans/APNDataObject.hxx76
-rw-r--r--vcl/win/dtrans/DOTransferable.cxx577
-rw-r--r--vcl/win/dtrans/DOTransferable.hxx97
-rw-r--r--vcl/win/dtrans/DTransHelper.cxx205
-rw-r--r--vcl/win/dtrans/DTransHelper.hxx167
-rw-r--r--vcl/win/dtrans/DataFmtTransl.cxx252
-rw-r--r--vcl/win/dtrans/DataFmtTransl.hxx64
-rw-r--r--vcl/win/dtrans/DtObjFactory.cxx34
-rw-r--r--vcl/win/dtrans/DtObjFactory.hxx33
-rw-r--r--vcl/win/dtrans/Fetc.cxx166
-rw-r--r--vcl/win/dtrans/Fetc.hxx76
-rw-r--r--vcl/win/dtrans/FetcList.cxx340
-rw-r--r--vcl/win/dtrans/FetcList.hxx139
-rw-r--r--vcl/win/dtrans/FmtFilter.cxx435
-rw-r--r--vcl/win/dtrans/FmtFilter.hxx84
-rw-r--r--vcl/win/dtrans/ImplHelper.cxx352
-rw-r--r--vcl/win/dtrans/ImplHelper.hxx74
-rw-r--r--vcl/win/dtrans/MimeAttrib.hxx31
-rw-r--r--vcl/win/dtrans/MtaOleClipb.cxx754
-rw-r--r--vcl/win/dtrans/MtaOleClipb.hxx110
-rw-r--r--vcl/win/dtrans/TxtCnvtHlp.cxx125
-rw-r--r--vcl/win/dtrans/TxtCnvtHlp.hxx41
-rw-r--r--vcl/win/dtrans/WinClip.hxx26
-rw-r--r--vcl/win/dtrans/WinClipboard.cxx386
-rw-r--r--vcl/win/dtrans/WinClipboard.hxx109
-rw-r--r--vcl/win/dtrans/XNotifyingDataObject.cxx149
-rw-r--r--vcl/win/dtrans/XNotifyingDataObject.hxx84
-rw-r--r--vcl/win/dtrans/XTDataObject.cxx757
-rw-r--r--vcl/win/dtrans/XTDataObject.hxx134
-rw-r--r--vcl/win/dtrans/clipboardmanager.cxx216
-rw-r--r--vcl/win/dtrans/clipboardmanager.hxx90
-rw-r--r--vcl/win/dtrans/ftransl.cxx550
-rw-r--r--vcl/win/dtrans/ftransl.hxx59
-rw-r--r--vcl/win/dtrans/generic_clipboard.cxx146
-rw-r--r--vcl/win/dtrans/generic_clipboard.hxx101
-rw-r--r--vcl/win/dtrans/globals.cxx130
-rw-r--r--vcl/win/dtrans/globals.hxx70
-rw-r--r--vcl/win/dtrans/idroptarget.cxx96
-rw-r--r--vcl/win/dtrans/idroptarget.hxx65
-rw-r--r--vcl/win/dtrans/source.cxx373
-rw-r--r--vcl/win/dtrans/sourcecontext.cxx134
-rw-r--r--vcl/win/dtrans/sourcecontext.hxx66
-rw-r--r--vcl/win/dtrans/target.cxx646
-rw-r--r--vcl/win/dtrans/targetdragcontext.cxx39
-rw-r--r--vcl/win/dtrans/targetdragcontext.hxx50
-rw-r--r--vcl/win/dtrans/targetdropcontext.cxx50
-rw-r--r--vcl/win/dtrans/targetdropcontext.hxx52
48 files changed, 9137 insertions, 0 deletions
diff --git a/vcl/win/dtrans/APNDataObject.cxx b/vcl/win/dtrans/APNDataObject.cxx
new file mode 100644
index 000000000..53342f21f
--- /dev/null
+++ b/vcl/win/dtrans/APNDataObject.cxx
@@ -0,0 +1,327 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "APNDataObject.hxx"
+#include <osl/diagnose.h>
+
+#include <systools/win32/comtools.hxx>
+
+#define FREE_HGLOB_ON_RELEASE TRUE
+#define KEEP_HGLOB_ON_RELEASE FALSE
+
+// ctor
+
+CAPNDataObject::CAPNDataObject( IDataObjectPtr rIDataObject ) :
+ m_rIDataObjectOrg( rIDataObject ),
+ m_hGlobal( nullptr ),
+ m_nRefCnt( 0 )
+{
+
+ OSL_ENSURE( m_rIDataObjectOrg.get( ), "constructing CAPNDataObject with empty data object" );
+
+ // we marshal the IDataObject interface pointer here so
+ // that it can be unmarshalled multiple times when this
+ // class will be used from another apartment
+ IStreamPtr pStm;
+ HRESULT hr = CreateStreamOnHGlobal( nullptr, KEEP_HGLOB_ON_RELEASE, &pStm );
+
+ OSL_ENSURE( E_INVALIDARG != hr, "invalid args passed to CreateStreamOnHGlobal" );
+
+ if ( SUCCEEDED( hr ) )
+ {
+ HRESULT hr_marshal = CoMarshalInterface(
+ pStm.get(),
+ __uuidof(IDataObject),
+ static_cast<LPUNKNOWN>(m_rIDataObjectOrg.get()),
+ MSHCTX_LOCAL,
+ nullptr,
+ MSHLFLAGS_TABLEWEAK );
+
+ OSL_ENSURE( CO_E_NOTINITIALIZED != hr_marshal, "COM is not initialized" );
+
+ // marshalling may fail if COM is not initialized
+ // for the calling thread which is a program time
+ // error or because of stream errors which are runtime
+ // errors for instance E_OUTOFMEMORY etc.
+
+ hr = GetHGlobalFromStream(pStm.get(), &m_hGlobal );
+
+ OSL_ENSURE( E_INVALIDARG != hr, "invalid stream passed to GetHGlobalFromStream" );
+
+ // if the marshalling failed we free the
+ // global memory again and set m_hGlobal
+ // to a defined value
+ if (FAILED(hr_marshal))
+ {
+ OSL_FAIL("marshalling failed");
+
+ HGLOBAL hGlobal =
+ GlobalFree(m_hGlobal);
+ OSL_ENSURE(nullptr == hGlobal, "GlobalFree failed");
+ m_hGlobal = nullptr;
+ }
+ }
+}
+
+CAPNDataObject::~CAPNDataObject( )
+{
+ if (m_hGlobal)
+ {
+ IStreamPtr pStm;
+ HRESULT hr = CreateStreamOnHGlobal(m_hGlobal, FREE_HGLOB_ON_RELEASE, &pStm);
+
+ OSL_ENSURE( E_INVALIDARG != hr, "invalid args passed to CreateStreamOnHGlobal" );
+
+ if (SUCCEEDED(hr))
+ {
+ hr = CoReleaseMarshalData(pStm.get());
+ OSL_ENSURE(SUCCEEDED(hr), "CoReleaseMarshalData failed");
+ }
+ }
+}
+
+// IUnknown->QueryInterface
+
+STDMETHODIMP CAPNDataObject::QueryInterface( REFIID iid, void** ppvObject )
+{
+ OSL_ASSERT( nullptr != ppvObject );
+
+ if ( nullptr == ppvObject )
+ return E_INVALIDARG;
+
+ HRESULT hr = E_NOINTERFACE;
+ *ppvObject = nullptr;
+
+ if ( ( __uuidof( IUnknown ) == iid ) || ( __uuidof( IDataObject ) == iid ) )
+ {
+ *ppvObject = static_cast< IUnknown* >( this );
+ static_cast<LPUNKNOWN>(*ppvObject)->AddRef( );
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+// IUnknown->AddRef
+
+STDMETHODIMP_(ULONG) CAPNDataObject::AddRef( )
+{
+ return static_cast< ULONG >( InterlockedIncrement( &m_nRefCnt ) );
+}
+
+// IUnknown->Release
+
+STDMETHODIMP_(ULONG) CAPNDataObject::Release( )
+{
+ // we need a helper variable because it's not allowed to access
+ // a member variable after an object is destroyed
+ ULONG nRefCnt = static_cast< ULONG >( InterlockedDecrement( &m_nRefCnt ) );
+
+ if ( 0 == nRefCnt )
+ delete this;
+
+ return nRefCnt;
+}
+
+// IDataObject->GetData
+
+STDMETHODIMP CAPNDataObject::GetData( FORMATETC * pFormatetc, STGMEDIUM * pmedium )
+{
+ HRESULT hr = m_rIDataObjectOrg->GetData( pFormatetc, pmedium );
+
+ if (RPC_E_WRONG_THREAD == hr)
+ {
+ IDataObjectPtr pIDOTmp;
+ hr = MarshalIDataObjectIntoCurrentApartment(&pIDOTmp);
+
+ if (SUCCEEDED(hr))
+ hr = pIDOTmp->GetData(pFormatetc, pmedium);
+ }
+ return hr;
+}
+
+// IDataObject->EnumFormatEtc
+
+STDMETHODIMP CAPNDataObject::EnumFormatEtc( DWORD dwDirection, IEnumFORMATETC** ppenumFormatetc )
+{
+ HRESULT hr = m_rIDataObjectOrg->EnumFormatEtc(dwDirection, ppenumFormatetc);
+
+ if (RPC_E_WRONG_THREAD == hr)
+ {
+ IDataObjectPtr pIDOTmp;
+ hr = MarshalIDataObjectIntoCurrentApartment(&pIDOTmp);
+
+ if (SUCCEEDED(hr))
+ hr = pIDOTmp->EnumFormatEtc(dwDirection, ppenumFormatetc);
+ }
+ return hr;
+}
+
+// IDataObject->QueryGetData
+
+STDMETHODIMP CAPNDataObject::QueryGetData( FORMATETC * pFormatetc )
+{
+ HRESULT hr = m_rIDataObjectOrg->QueryGetData( pFormatetc );
+
+ if (RPC_E_WRONG_THREAD == hr)
+ {
+ IDataObjectPtr pIDOTmp;
+ hr = MarshalIDataObjectIntoCurrentApartment( &pIDOTmp );
+
+ if (SUCCEEDED(hr))
+ hr = pIDOTmp->QueryGetData(pFormatetc);
+ }
+ return hr;
+}
+
+// IDataObject->GetDataHere
+
+STDMETHODIMP CAPNDataObject::GetDataHere( FORMATETC * pFormatetc, STGMEDIUM * pmedium )
+{
+ HRESULT hr = m_rIDataObjectOrg->GetDataHere(pFormatetc, pmedium);
+
+ if (RPC_E_WRONG_THREAD == hr)
+ {
+ IDataObjectPtr pIDOTmp;
+ hr = MarshalIDataObjectIntoCurrentApartment(&pIDOTmp);
+
+ if (SUCCEEDED(hr))
+ hr = pIDOTmp->GetDataHere(pFormatetc, pmedium);
+ }
+ return hr;
+}
+
+// IDataObject->GetCanonicalFormatEtc
+
+STDMETHODIMP CAPNDataObject::GetCanonicalFormatEtc(FORMATETC * pFormatectIn, FORMATETC * pFormatetcOut)
+{
+ HRESULT hr = m_rIDataObjectOrg->GetCanonicalFormatEtc( pFormatectIn, pFormatetcOut );
+
+ if (RPC_E_WRONG_THREAD == hr)
+ {
+ IDataObjectPtr pIDOTmp;
+ hr = MarshalIDataObjectIntoCurrentApartment(&pIDOTmp);
+
+ if (SUCCEEDED(hr))
+ hr = pIDOTmp->GetCanonicalFormatEtc(pFormatectIn, pFormatetcOut);
+ }
+ return hr;
+}
+
+// IDataObject->SetData
+
+STDMETHODIMP CAPNDataObject::SetData( FORMATETC * pFormatetc, STGMEDIUM * pmedium, BOOL fRelease )
+{
+ HRESULT hr = m_rIDataObjectOrg->SetData( pFormatetc, pmedium, fRelease );
+
+ if (RPC_E_WRONG_THREAD == hr)
+ {
+ IDataObjectPtr pIDOTmp;
+ hr = MarshalIDataObjectIntoCurrentApartment(&pIDOTmp);
+
+ if (SUCCEEDED(hr))
+ hr = pIDOTmp->SetData(pFormatetc, pmedium, fRelease);
+ }
+ return hr;
+}
+
+// IDataObject->DAdvise
+
+STDMETHODIMP CAPNDataObject::DAdvise( FORMATETC * pFormatetc, DWORD advf, IAdviseSink * pAdvSink, DWORD * pdwConnection )
+{
+ HRESULT hr = m_rIDataObjectOrg->DAdvise(pFormatetc, advf, pAdvSink, pdwConnection);
+
+ if (RPC_E_WRONG_THREAD == hr)
+ {
+ IDataObjectPtr pIDOTmp;
+ hr = MarshalIDataObjectIntoCurrentApartment(&pIDOTmp);
+
+ if (SUCCEEDED(hr))
+ hr = pIDOTmp->DAdvise(pFormatetc, advf, pAdvSink, pdwConnection);
+ }
+ return hr;
+}
+
+// IDataObject->DUnadvise
+
+STDMETHODIMP CAPNDataObject::DUnadvise( DWORD dwConnection )
+{
+ HRESULT hr = m_rIDataObjectOrg->DUnadvise( dwConnection );
+
+ if (RPC_E_WRONG_THREAD == hr)
+ {
+ IDataObjectPtr pIDOTmp;
+ hr = MarshalIDataObjectIntoCurrentApartment(&pIDOTmp);
+
+ if (SUCCEEDED(hr))
+ hr = pIDOTmp->DUnadvise(dwConnection);
+ }
+ return hr;
+}
+
+// IDataObject->EnumDAdvise
+
+STDMETHODIMP CAPNDataObject::EnumDAdvise( IEnumSTATDATA ** ppenumAdvise )
+{
+ HRESULT hr = m_rIDataObjectOrg->EnumDAdvise(ppenumAdvise);
+
+ if (RPC_E_WRONG_THREAD == hr)
+ {
+ IDataObjectPtr pIDOTmp;
+ hr = MarshalIDataObjectIntoCurrentApartment(&pIDOTmp);
+
+ if (SUCCEEDED(hr))
+ hr = pIDOTmp->EnumDAdvise(ppenumAdvise);
+ }
+ return hr;
+}
+
+// for our convenience
+
+CAPNDataObject::operator IDataObject*( )
+{
+ return static_cast< IDataObject* >( this );
+}
+
+// helper function
+
+HRESULT CAPNDataObject::MarshalIDataObjectIntoCurrentApartment( IDataObject** ppIDataObj )
+{
+ OSL_ASSERT(nullptr != ppIDataObj);
+
+ *ppIDataObj = nullptr;
+ HRESULT hr = E_FAIL;
+
+ if (m_hGlobal)
+ {
+ IStreamPtr pStm;
+ hr = CreateStreamOnHGlobal(m_hGlobal, KEEP_HGLOB_ON_RELEASE, &pStm);
+
+ OSL_ENSURE(E_INVALIDARG != hr, "CreateStreamOnHGlobal with invalid args called");
+
+ if (SUCCEEDED(hr))
+ {
+ hr = CoUnmarshalInterface(pStm.get(), __uuidof(IDataObject), reinterpret_cast<void**>(ppIDataObj));
+ OSL_ENSURE(CO_E_NOTINITIALIZED != hr, "COM is not initialized");
+ }
+ }
+ return hr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/APNDataObject.hxx b/vcl/win/dtrans/APNDataObject.hxx
new file mode 100644
index 000000000..2d3c583ec
--- /dev/null
+++ b/vcl/win/dtrans/APNDataObject.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <objidl.h>
+
+#include <systools/win32/comtools.hxx>
+
+/*
+ an APartment Neutral dataobject wrapper; this wrapper of an IDataObject
+ pointer can be used from any apartment without RPC_E_WRONG_THREAD
+ which normally occurs if an apartment tries to use an interface
+ pointer of another apartment; we use containment to hold the original
+ DataObject
+*/
+class CAPNDataObject : public IDataObject
+{
+public:
+ explicit CAPNDataObject(IDataObjectPtr rIDataObject);
+ virtual ~CAPNDataObject();
+
+ //IUnknown interface methods
+
+ STDMETHODIMP QueryInterface(REFIID iid, void** ppvObject) override;
+ STDMETHODIMP_( ULONG ) AddRef( ) override;
+ STDMETHODIMP_( ULONG ) Release( ) override;
+
+ // IDataObject interface methods
+
+ STDMETHODIMP GetData( FORMATETC * pFormatetc, STGMEDIUM * pmedium ) override;
+ STDMETHODIMP GetDataHere( FORMATETC * pFormatetc, STGMEDIUM * pmedium ) override;
+ STDMETHODIMP QueryGetData( FORMATETC * pFormatetc ) override;
+ STDMETHODIMP GetCanonicalFormatEtc( FORMATETC * pFormatectIn, FORMATETC * pFormatetcOut ) override;
+ STDMETHODIMP SetData( FORMATETC * pFormatetc, STGMEDIUM * pmedium, BOOL fRelease ) override;
+ STDMETHODIMP EnumFormatEtc( DWORD dwDirection, IEnumFORMATETC** ppenumFormatetc ) override;
+ STDMETHODIMP DAdvise( FORMATETC * pFormatetc, DWORD advf, IAdviseSink * pAdvSink, DWORD* pdwConnection ) override;
+ STDMETHODIMP DUnadvise( DWORD dwConnection ) override;
+ STDMETHODIMP EnumDAdvise( IEnumSTATDATA** ppenumAdvise ) override;
+
+ operator IDataObject*( );
+
+private:
+ HRESULT MarshalIDataObjectIntoCurrentApartment( IDataObject** ppIDataObj );
+
+private:
+ IDataObjectPtr m_rIDataObjectOrg;
+ HGLOBAL m_hGlobal;
+ LONG m_nRefCnt;
+
+// prevent copy and assignment
+private:
+ CAPNDataObject( const CAPNDataObject& theOther );
+ CAPNDataObject& operator=( const CAPNDataObject& theOther );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/DOTransferable.cxx b/vcl/win/dtrans/DOTransferable.cxx
new file mode 100644
index 000000000..7c5b55c02
--- /dev/null
+++ b/vcl/win/dtrans/DOTransferable.cxx
@@ -0,0 +1,577 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/types.h>
+#include <rtl/process.h>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+
+#include "DOTransferable.hxx"
+#include "ImplHelper.hxx"
+#include "WinClip.hxx"
+#include "WinClipboard.hxx"
+#include "DTransHelper.hxx"
+#include "TxtCnvtHlp.hxx"
+#include "MimeAttrib.hxx"
+#include "FmtFilter.hxx"
+#include "Fetc.hxx"
+#include <com/sun/star/container/NoSuchElementException.hpp>
+#include <com/sun/star/datatransfer/MimeContentTypeFactory.hpp>
+#include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
+#include <com/sun/star/io/IOException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
+using namespace osl;
+using namespace cppu;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::io;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::container;
+
+namespace
+{
+ const Type CPPUTYPE_SEQINT8 = cppu::UnoType<Sequence< sal_Int8 >>::get();
+ const Type CPPUTYPE_OUSTRING = cppu::UnoType<OUString>::get();
+
+ bool isValidFlavor( const DataFlavor& aFlavor )
+ {
+ return ( aFlavor.MimeType.getLength( ) &&
+ ( ( aFlavor.DataType == CPPUTYPE_SEQINT8 ) ||
+ ( aFlavor.DataType == CPPUTYPE_OUSTRING ) ) );
+ }
+
+void clipDataToByteStream( CLIPFORMAT cf, STGMEDIUM stgmedium, CDOTransferable::ByteSequence_t& aByteSequence )
+{
+ CStgTransferHelper memTransferHelper;
+ LPSTREAM pStream = nullptr;
+
+ switch( stgmedium.tymed )
+ {
+ case TYMED_HGLOBAL:
+ memTransferHelper.init( stgmedium.hGlobal );
+ break;
+
+ case TYMED_MFPICT:
+ memTransferHelper.init( stgmedium.hMetaFilePict );
+ break;
+
+ case TYMED_ENHMF:
+ memTransferHelper.init( stgmedium.hEnhMetaFile );
+ break;
+
+ case TYMED_ISTREAM:
+ pStream = stgmedium.pstm;
+ break;
+
+ default:
+ throw UnsupportedFlavorException( );
+ break;
+ }
+
+ if (pStream)
+ {
+ // We have a stream, read from it.
+ STATSTG aStat;
+ HRESULT hr = pStream->Stat(&aStat, STATFLAG_NONAME);
+ if (FAILED(hr))
+ {
+ SAL_WARN("vcl.win.dtrans", "clipDataToByteStream: Stat() failed");
+ return;
+ }
+
+ size_t nMemSize = aStat.cbSize.QuadPart;
+ aByteSequence.realloc(nMemSize);
+ LARGE_INTEGER li;
+ li.QuadPart = 0;
+ hr = pStream->Seek(li, STREAM_SEEK_SET, nullptr);
+ if (FAILED(hr))
+ {
+ SAL_WARN("vcl.win.dtrans", "clipDataToByteStream: Seek() failed");
+ }
+
+ ULONG nRead = 0;
+ hr = pStream->Read(aByteSequence.getArray(), nMemSize, &nRead);
+ if (FAILED(hr))
+ {
+ SAL_WARN("vcl.win.dtrans", "clipDataToByteStream: Read() failed");
+ }
+ if (nRead < nMemSize)
+ {
+ SAL_WARN("vcl.win.dtrans", "clipDataToByteStream: Read() was partial");
+ }
+
+ return;
+ }
+
+ int nMemSize = memTransferHelper.memSize( cf );
+ aByteSequence.realloc( nMemSize );
+ memTransferHelper.read( aByteSequence.getArray( ), nMemSize );
+}
+
+OUString byteStreamToOUString( CDOTransferable::ByteSequence_t& aByteStream )
+{
+ sal_Int32 nWChars;
+ sal_Int32 nMemSize = aByteStream.getLength( );
+
+ // if there is a trailing L"\0" subtract 1 from length
+ // for unknown reason, the sequence may sometimes arrive empty
+ if ( aByteStream.getLength( ) > 1 &&
+ 0 == aByteStream[ aByteStream.getLength( ) - 2 ] &&
+ 0 == aByteStream[ aByteStream.getLength( ) - 1 ] )
+ nWChars = static_cast< sal_Int32 >( nMemSize / sizeof( sal_Unicode ) ) - 1;
+ else
+ nWChars = static_cast< sal_Int32 >( nMemSize / sizeof( sal_Unicode ) );
+
+ return OUString( reinterpret_cast< sal_Unicode* >( aByteStream.getArray( ) ), nWChars );
+}
+
+Any byteStreamToAny( CDOTransferable::ByteSequence_t& aByteStream, const Type& aRequestedDataType )
+{
+ Any aAny;
+
+ if ( aRequestedDataType == CPPUTYPE_OUSTRING )
+ {
+ OUString str = byteStreamToOUString( aByteStream );
+ if (str.isEmpty())
+ throw RuntimeException();
+ aAny <<= str;
+ }
+ else
+ aAny <<= aByteStream;
+
+ return aAny;
+}
+
+bool cmpFullMediaType(
+ const Reference< XMimeContentType >& xLhs, const Reference< XMimeContentType >& xRhs )
+{
+ return xLhs->getFullMediaType().equalsIgnoreAsciiCase( xRhs->getFullMediaType( ) );
+}
+
+bool cmpAllContentTypeParameter(
+ const Reference< XMimeContentType >& xLhs, const Reference< XMimeContentType >& xRhs )
+{
+ Sequence< OUString > xLhsFlavors = xLhs->getParameters( );
+ Sequence< OUString > xRhsFlavors = xRhs->getParameters( );
+ bool bRet = true;
+
+ try
+ {
+ if ( xLhsFlavors.getLength( ) == xRhsFlavors.getLength( ) )
+ {
+ OUString pLhs;
+ OUString pRhs;
+
+ for ( sal_Int32 i = 0; i < xLhsFlavors.getLength( ); i++ )
+ {
+ pLhs = xLhs->getParameterValue( xLhsFlavors[i] );
+ pRhs = xRhs->getParameterValue( xLhsFlavors[i] );
+
+ if ( !pLhs.equalsIgnoreAsciiCase( pRhs ) )
+ {
+ bRet = false;
+ break;
+ }
+ }
+ }
+ else
+ bRet = false;
+ }
+ catch( NoSuchElementException& )
+ {
+ bRet = false;
+ }
+ catch( IllegalArgumentException& )
+ {
+ bRet = false;
+ }
+
+ return bRet;
+}
+
+} // end namespace
+
+CDOTransferable::CDOTransferable(
+ const Reference< XComponentContext >& rxContext, IDataObjectPtr rDataObject ) :
+ m_rDataObject( rDataObject ),
+ m_xContext( rxContext ),
+ m_DataFormatTranslator( rxContext ),
+ m_bUnicodeRegistered( false ),
+ m_TxtFormatOnClipboard( CF_INVALID )
+{
+ initFlavorList();
+}
+
+CDOTransferable::CDOTransferable(
+ const Reference<XComponentContext>& rxContext,
+ const css::uno::Reference<css::datatransfer::clipboard::XClipboard>& xClipboard,
+ const std::vector<sal_uInt32>& rFormats)
+ : m_xClipboard(xClipboard)
+ , m_xContext(rxContext)
+ , m_DataFormatTranslator(rxContext)
+ , m_bUnicodeRegistered(false)
+ , m_TxtFormatOnClipboard(CF_INVALID)
+{
+ initFlavorListFromFormatList(rFormats);
+}
+
+Any SAL_CALL CDOTransferable::getTransferData( const DataFlavor& aFlavor )
+{
+ OSL_ASSERT( isValidFlavor( aFlavor ) );
+
+ MutexGuard aGuard( m_aMutex );
+
+ // convert dataflavor to formatetc
+
+ CFormatEtc fetc = m_DataFormatTranslator.getFormatEtcFromDataFlavor( aFlavor );
+ OSL_ASSERT( CF_INVALID != fetc.getClipformat() );
+
+ // get the data from clipboard in a byte stream
+
+ ByteSequence_t clipDataStream;
+
+ try
+ {
+ clipDataStream = getClipboardData( fetc );
+ }
+ catch( UnsupportedFlavorException& )
+ {
+ if ( CDataFormatTranslator::isUnicodeTextFormat( fetc.getClipformat( ) ) &&
+ m_bUnicodeRegistered )
+ {
+ OUString aUnicodeText = synthesizeUnicodeText( );
+ Any aAny( aUnicodeText );
+ return aAny;
+ }
+ // #i124085# CF_DIBV5 should not be possible, but keep for reading from the
+ // clipboard for being on the safe side
+ else if(CF_DIBV5 == fetc.getClipformat())
+ {
+ // #i123407# CF_DIBV5 has priority; if the try to fetch this failed,
+ // check CF_DIB availability as an alternative
+ fetc.setClipformat(CF_DIB);
+
+ clipDataStream = getClipboardData( fetc );
+ // pass UnsupportedFlavorException out, tried all possibilities
+ }
+ else
+ throw; // pass through exception
+ }
+
+ // return the data as any
+
+ return byteStreamToAny( clipDataStream, aFlavor.DataType );
+}
+
+// getTransferDataFlavors
+
+Sequence< DataFlavor > SAL_CALL CDOTransferable::getTransferDataFlavors( )
+{
+ return m_FlavorList;
+}
+
+// isDataFlavorSupported
+// returns true if we find a DataFlavor with the same MimeType and
+// DataType
+
+sal_Bool SAL_CALL CDOTransferable::isDataFlavorSupported( const DataFlavor& aFlavor )
+{
+ OSL_ASSERT( isValidFlavor( aFlavor ) );
+
+ for ( DataFlavor const & df : std::as_const(m_FlavorList) )
+ if ( compareDataFlavors( aFlavor, df ) )
+ return true;
+
+ return false;
+}
+
+// the list of dataflavors currently on the clipboard will be initialized
+// only once; if the client of this Transferable will hold a reference
+// to it and the underlying clipboard content changes, the client does
+// possible operate on an invalid list
+// if there is only text on the clipboard we will also offer unicode text
+// an synthesize this format on the fly if requested, to accomplish this
+// we save the first offered text format which we will later use for the
+// conversion
+
+void CDOTransferable::initFlavorList( )
+{
+ std::vector<sal_uInt32> aFormats;
+ sal::systools::COMReference<IEnumFORMATETC> pEnumFormatEtc;
+ HRESULT hr = m_rDataObject->EnumFormatEtc( DATADIR_GET, &pEnumFormatEtc );
+ if ( SUCCEEDED( hr ) )
+ {
+ pEnumFormatEtc->Reset( );
+
+ FORMATETC fetc;
+ while ( S_OK == pEnumFormatEtc->Next( 1, &fetc, nullptr ) )
+ {
+ aFormats.push_back(fetc.cfFormat);
+ // see MSDN IEnumFORMATETC
+ CoTaskMemFree( fetc.ptd );
+ }
+ initFlavorListFromFormatList(aFormats);
+ }
+}
+
+void CDOTransferable::initFlavorListFromFormatList(const std::vector<sal_uInt32>& rFormats)
+{
+ for (sal_uInt32 cfFormat : rFormats)
+ {
+ // we use locales only to determine the
+ // charset if there is text on the clipboard
+ // we don't offer this format
+ if (CF_LOCALE == cfFormat)
+ continue;
+
+ // if text or oemtext is offered we pretend to have unicode text
+ if (CDataFormatTranslator::isTextFormat(cfFormat))
+ {
+ if (!m_bUnicodeRegistered)
+ {
+ m_TxtFormatOnClipboard = cfFormat;
+ m_bUnicodeRegistered = true;
+
+ // register unicode text as format
+ addSupportedFlavor(formatEtcToDataFlavor(CF_UNICODETEXT));
+ }
+ }
+ else
+ addSupportedFlavor(formatEtcToDataFlavor(cfFormat));
+ }
+}
+
+inline
+void CDOTransferable::addSupportedFlavor( const DataFlavor& aFlavor )
+{
+ // we ignore all formats that couldn't be translated
+ if ( aFlavor.MimeType.getLength( ) )
+ {
+ OSL_ASSERT( isValidFlavor( aFlavor ) );
+
+ m_FlavorList.realloc( m_FlavorList.getLength( ) + 1 );
+ m_FlavorList.getArray()[m_FlavorList.getLength( ) - 1] = aFlavor;
+ }
+}
+
+DataFlavor CDOTransferable::formatEtcToDataFlavor(sal_uInt32 cfFormat)
+{
+ return m_DataFormatTranslator.getDataFlavorFromFormatEtc(cfFormat);
+}
+
+// returns the current locale on clipboard; if there is no locale on
+// clipboard the function returns the current thread locale
+
+LCID CDOTransferable::getLocaleFromClipboard( )
+{
+ LCID lcid = GetThreadLocale( );
+
+ try
+ {
+ CFormatEtc fetc = CDataFormatTranslator::getFormatEtcForClipformat( CF_LOCALE );
+ ByteSequence_t aLCIDSeq = getClipboardData( fetc );
+ lcid = *reinterpret_cast<LCID*>( aLCIDSeq.getArray( ) );
+
+ // because of a Win95/98 Bug; there the high word
+ // of a locale has the same value as the
+ // low word e.g. 0x07040704 that's not right
+ // correct is 0x00000704
+ lcid &= 0x0000FFFF;
+ }
+ catch(...)
+ {
+ // we take the default locale
+ }
+
+ return lcid;
+}
+
+void CDOTransferable::tryToGetIDataObjectIfAbsent()
+{
+ if (!m_rDataObject.is())
+ {
+ auto xClipboard = m_xClipboard.get(); // holding the reference while we get the object
+ if (CWinClipboard* pWinClipboard = dynamic_cast<CWinClipboard*>(xClipboard.get()))
+ {
+ m_rDataObject = pWinClipboard->getIDataObject();
+ }
+ }
+}
+
+// I think it's not necessary to call ReleaseStgMedium
+// in case of failures because nothing should have been
+// allocated etc.
+
+CDOTransferable::ByteSequence_t CDOTransferable::getClipboardData( CFormatEtc& aFormatEtc )
+{
+ STGMEDIUM stgmedium;
+ tryToGetIDataObjectIfAbsent();
+ if (!m_rDataObject.is()) // Maybe we are shutting down, and clipboard is already destroyed?
+ throw RuntimeException();
+ HRESULT hr = m_rDataObject->GetData( aFormatEtc, &stgmedium );
+
+ // in case of failure to get a WMF metafile handle, try to get a memory block
+ if( FAILED( hr ) &&
+ ( CF_METAFILEPICT == aFormatEtc.getClipformat() ) &&
+ ( TYMED_MFPICT == aFormatEtc.getTymed() ) )
+ {
+ CFormatEtc aTempFormat( aFormatEtc );
+ aTempFormat.setTymed( TYMED_HGLOBAL );
+ hr = m_rDataObject->GetData( aTempFormat, &stgmedium );
+ }
+
+ if (FAILED(hr) && aFormatEtc.getTymed() == TYMED_HGLOBAL)
+ {
+ // Handle type is not memory, try stream.
+ CFormatEtc aTempFormat(aFormatEtc);
+ aTempFormat.setTymed(TYMED_ISTREAM);
+ hr = m_rDataObject->GetData(aTempFormat, &stgmedium);
+ }
+
+ if ( FAILED( hr ) )
+ {
+ OSL_ASSERT( (hr != E_INVALIDARG) &&
+ (hr != DV_E_DVASPECT) &&
+ (hr != DV_E_LINDEX) &&
+ (hr != DV_E_TYMED) );
+
+ if ( DV_E_FORMATETC == hr )
+ throw UnsupportedFlavorException( );
+ else if ( STG_E_MEDIUMFULL == hr )
+ throw IOException( );
+ else
+ throw RuntimeException( );
+ }
+
+ ByteSequence_t byteStream;
+
+ try
+ {
+ if ( CF_ENHMETAFILE == aFormatEtc.getClipformat() )
+ byteStream = WinENHMFPictToOOMFPict( stgmedium.hEnhMetaFile );
+ else if (CF_HDROP == aFormatEtc.getClipformat())
+ byteStream = CF_HDROPToFileList(stgmedium.hGlobal);
+ else if ( CF_BITMAP == aFormatEtc.getClipformat() )
+ {
+ byteStream = WinBITMAPToOOBMP(stgmedium.hBitmap);
+ if( aFormatEtc.getTymed() == TYMED_GDI &&
+ ! stgmedium.pUnkForRelease )
+ {
+ DeleteObject(stgmedium.hBitmap);
+ }
+ }
+ else
+ {
+ clipDataToByteStream( aFormatEtc.getClipformat( ), stgmedium, byteStream );
+
+ // format conversion if necessary
+ // #i124085# DIBV5 should not happen currently, but keep as a hint here
+ if(CF_DIBV5 == aFormatEtc.getClipformat() || CF_DIB == aFormatEtc.getClipformat())
+ {
+ byteStream = WinDIBToOOBMP(byteStream);
+ }
+ else if(CF_METAFILEPICT == aFormatEtc.getClipformat())
+ {
+ byteStream = WinMFPictToOOMFPict(byteStream);
+ }
+ }
+
+ ReleaseStgMedium( &stgmedium );
+ }
+ catch( CStgTransferHelper::CStgTransferException& )
+ {
+ ReleaseStgMedium( &stgmedium );
+ throw IOException( );
+ }
+
+ return byteStream;
+}
+
+OUString CDOTransferable::synthesizeUnicodeText( )
+{
+ ByteSequence_t aTextSequence;
+ CFormatEtc fetc;
+ LCID lcid = getLocaleFromClipboard( );
+ sal_uInt32 cpForTxtCnvt = 0;
+
+ if ( CF_TEXT == m_TxtFormatOnClipboard )
+ {
+ fetc = CDataFormatTranslator::getFormatEtcForClipformat( CF_TEXT );
+ aTextSequence = getClipboardData( fetc );
+
+ // determine the codepage used for text conversion
+ cpForTxtCnvt = getWinCPFromLocaleId( lcid, LOCALE_IDEFAULTANSICODEPAGE ).toInt32( );
+ }
+ else if ( CF_OEMTEXT == m_TxtFormatOnClipboard )
+ {
+ fetc = CDataFormatTranslator::getFormatEtcForClipformat( CF_OEMTEXT );
+ aTextSequence = getClipboardData( fetc );
+
+ // determine the codepage used for text conversion
+ cpForTxtCnvt = getWinCPFromLocaleId( lcid, LOCALE_IDEFAULTCODEPAGE ).toInt32( );
+ }
+ else
+ OSL_ASSERT( false );
+
+ CStgTransferHelper stgTransferHelper;
+
+ // convert the text
+ MultiByteToWideCharEx( cpForTxtCnvt,
+ reinterpret_cast<char*>( aTextSequence.getArray( ) ),
+ -1,
+ stgTransferHelper,
+ false);
+
+ CRawHGlobalPtr ptrHGlob(stgTransferHelper);
+ sal_Unicode* pWChar = static_cast<sal_Unicode*>(ptrHGlob.GetMemPtr());
+
+ return OUString(pWChar);
+}
+
+bool CDOTransferable::compareDataFlavors(
+ const DataFlavor& lhs, const DataFlavor& rhs )
+{
+ if ( !m_rXMimeCntFactory.is( ) )
+ {
+ m_rXMimeCntFactory = MimeContentTypeFactory::create( m_xContext );
+ }
+
+ bool bRet = false;
+
+ try
+ {
+ Reference< XMimeContentType > xLhs( m_rXMimeCntFactory->createMimeContentType( lhs.MimeType ) );
+ Reference< XMimeContentType > xRhs( m_rXMimeCntFactory->createMimeContentType( rhs.MimeType ) );
+
+ if ( cmpFullMediaType( xLhs, xRhs ) )
+ {
+ bRet = cmpAllContentTypeParameter( xLhs, xRhs );
+ }
+ }
+ catch( IllegalArgumentException& )
+ {
+ OSL_FAIL( "Invalid content type detected" );
+ bRet = false;
+ }
+
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/DOTransferable.hxx b/vcl/win/dtrans/DOTransferable.hxx
new file mode 100644
index 000000000..e42555ce6
--- /dev/null
+++ b/vcl/win/dtrans/DOTransferable.hxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include "DataFmtTransl.hxx"
+#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
+#include <com/sun/star/datatransfer/XMimeContentTypeFactory.hpp>
+#include <com/sun/star/datatransfer/XMimeContentType.hpp>
+#include <com/sun/star/datatransfer/XSystemTransferable.hpp>
+#include <cppuhelper/weakref.hxx>
+
+#include <systools/win32/comtools.hxx>
+
+#include <vector>
+
+// forward
+class CFormatEtc;
+
+class CDOTransferable : public ::cppu::WeakImplHelper<
+ css::datatransfer::XTransferable>
+{
+public:
+ typedef css::uno::Sequence< sal_Int8 > ByteSequence_t;
+
+ // XTransferable
+
+ virtual css::uno::Any SAL_CALL getTransferData( const css::datatransfer::DataFlavor& aFlavor ) override;
+
+ virtual css::uno::Sequence< css::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors( ) override;
+
+ virtual sal_Bool SAL_CALL isDataFlavorSupported( const css::datatransfer::DataFlavor& aFlavor ) override;
+
+ explicit CDOTransferable(
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ const css::uno::Reference<css::datatransfer::clipboard::XClipboard>& xClipboard,
+ const std::vector<sal_uInt32>& rFormats);
+
+ explicit CDOTransferable(
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ IDataObjectPtr rDataObject );
+
+private:
+ // some helper functions
+
+ void initFlavorList( );
+ void initFlavorListFromFormatList(const std::vector<sal_uInt32>& rFormats);
+
+ void addSupportedFlavor( const css::datatransfer::DataFlavor& aFlavor );
+ css::datatransfer::DataFlavor formatEtcToDataFlavor(sal_uInt32 cfFormat);
+
+ void tryToGetIDataObjectIfAbsent();
+ ByteSequence_t getClipboardData( CFormatEtc& aFormatEtc );
+ OUString synthesizeUnicodeText( );
+
+ LCID getLocaleFromClipboard( );
+
+ bool compareDataFlavors( const css::datatransfer::DataFlavor& lhs,
+ const css::datatransfer::DataFlavor& rhs );
+
+private:
+ css::uno::WeakReference<css::datatransfer::clipboard::XClipboard> m_xClipboard;
+ IDataObjectPtr m_rDataObject;
+ css::uno::Sequence< css::datatransfer::DataFlavor > m_FlavorList;
+ const css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ CDataFormatTranslator m_DataFormatTranslator;
+ css::uno::Reference< css::datatransfer::XMimeContentTypeFactory > m_rXMimeCntFactory;
+ ::osl::Mutex m_aMutex;
+ bool m_bUnicodeRegistered;
+ CLIPFORMAT m_TxtFormatOnClipboard;
+
+// non supported operations
+private:
+ CDOTransferable( const CDOTransferable& );
+ CDOTransferable& operator=( const CDOTransferable& );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/DTransHelper.cxx b/vcl/win/dtrans/DTransHelper.cxx
new file mode 100644
index 000000000..66d18f9fb
--- /dev/null
+++ b/vcl/win/dtrans/DTransHelper.cxx
@@ -0,0 +1,205 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <rtl/ustring.h>
+#include <osl/diagnose.h>
+#include "DTransHelper.hxx"
+
+// implementation
+
+CStgTransferHelper::CStgTransferHelper( bool bAutoInit,
+ HGLOBAL hGlob,
+ bool bDelStgOnRelease ) :
+ m_lpStream( nullptr ),
+ m_bDelStgOnRelease( bDelStgOnRelease )
+{
+ if ( bAutoInit )
+ init( hGlob, m_bDelStgOnRelease );
+}
+
+// dtor
+
+CStgTransferHelper::~CStgTransferHelper( )
+{
+ if ( m_lpStream )
+ m_lpStream->Release( );
+}
+
+// TransferData into the
+
+void CStgTransferHelper::write( const void* lpData, ULONG cb, ULONG* cbWritten )
+{
+ HRESULT hr = E_FAIL;
+
+ if ( m_lpStream )
+ hr = m_lpStream->Write( lpData, cb, cbWritten );
+
+ if ( FAILED( hr ) )
+ throw CStgTransferException( hr );
+
+#if OSL_DEBUG_LEVEL > 0
+ HGLOBAL hGlob;
+ hr = GetHGlobalFromStream( m_lpStream, &hGlob );
+ OSL_ASSERT( SUCCEEDED( hr ) );
+
+ /*DWORD dwSize =*/ GlobalSize( hGlob );
+ /*LPVOID lpdbgData =*/ GlobalLock( hGlob );
+ GlobalUnlock( hGlob );
+#endif
+}
+
+// read
+
+void CStgTransferHelper::read( LPVOID pv, ULONG cb, ULONG* pcbRead )
+{
+ HRESULT hr = E_FAIL;
+
+ if ( m_lpStream )
+ hr = m_lpStream->Read( pv, cb , pcbRead );
+
+ if ( FAILED( hr ) )
+ throw CStgTransferException( hr );
+}
+
+// GetHGlobal
+
+HGLOBAL CStgTransferHelper::getHGlobal( ) const
+{
+ OSL_ASSERT( m_lpStream );
+
+ HGLOBAL hGlob = nullptr;
+
+ if ( m_lpStream )
+ {
+ HRESULT hr = GetHGlobalFromStream( m_lpStream, &hGlob );
+ if ( FAILED( hr ) )
+ hGlob = nullptr;
+ }
+
+ return hGlob;
+}
+
+// getIStream
+
+void CStgTransferHelper::getIStream( LPSTREAM* ppStream )
+{
+ OSL_ASSERT( ppStream );
+ *ppStream = m_lpStream;
+ if ( *ppStream )
+ static_cast< LPUNKNOWN >( *ppStream )->AddRef( );
+}
+
+// Init
+
+void CStgTransferHelper::init( SIZE_T newSize,
+ sal_uInt32 uiFlags,
+ bool bDelStgOnRelease )
+{
+ cleanup( );
+
+ m_bDelStgOnRelease = bDelStgOnRelease;
+
+ HGLOBAL hGlob = GlobalAlloc( uiFlags, newSize );
+ if ( nullptr == hGlob )
+ throw CStgTransferException( STG_E_MEDIUMFULL );
+
+ HRESULT hr = CreateStreamOnHGlobal( hGlob, m_bDelStgOnRelease, &m_lpStream );
+ if ( FAILED( hr ) )
+ {
+ GlobalFree( hGlob );
+ m_lpStream = nullptr;
+ throw CStgTransferException( hr );
+ }
+
+#if OSL_DEBUG_LEVEL > 0
+ STATSTG statstg;
+ hr = m_lpStream->Stat( &statstg, STATFLAG_DEFAULT );
+ OSL_ASSERT( SUCCEEDED( hr ) );
+#endif
+}
+
+// Init
+
+void CStgTransferHelper::init( HGLOBAL hGlob,
+ bool bDelStgOnRelease )
+{
+ cleanup( );
+
+ m_bDelStgOnRelease = bDelStgOnRelease;
+
+ HRESULT hr = CreateStreamOnHGlobal( hGlob, m_bDelStgOnRelease, &m_lpStream );
+ if ( FAILED( hr ) )
+ throw CStgTransferException( hr );
+}
+
+// free the global memory and invalidate the stream pointer
+
+void CStgTransferHelper::cleanup( )
+{
+ if ( m_lpStream && !m_bDelStgOnRelease )
+ {
+ HGLOBAL hGlob;
+ GetHGlobalFromStream( m_lpStream, &hGlob );
+ GlobalFree( hGlob );
+ }
+
+ if ( m_lpStream )
+ {
+ m_lpStream->Release( );
+ m_lpStream = nullptr;
+ }
+}
+
+// return the size of memory we point to
+
+sal_uInt32 CStgTransferHelper::memSize( CLIPFORMAT cf ) const
+{
+ DWORD dwSize = 0;
+
+ if ( nullptr != m_lpStream )
+ {
+ HGLOBAL hGlob;
+ GetHGlobalFromStream( m_lpStream, &hGlob );
+
+ if ( CF_TEXT == cf || RegisterClipboardFormatW( L"HTML Format" ) == cf )
+ {
+ char* pText = static_cast< char* >( GlobalLock( hGlob ) );
+ if ( pText )
+ {
+ dwSize = strlen(pText) + 1; // strlen + trailing '\0'
+ GlobalUnlock( hGlob );
+ }
+ }
+ else if ( CF_UNICODETEXT == cf )
+ {
+ sal_Unicode* pText = static_cast< sal_Unicode* >( GlobalLock( hGlob ) );
+ if ( pText )
+ {
+ dwSize = rtl_ustr_getLength( pText ) * sizeof( sal_Unicode );
+ GlobalUnlock( hGlob );
+ }
+ }
+ else
+ dwSize = GlobalSize( hGlob );
+ }
+
+ return dwSize;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/DTransHelper.hxx b/vcl/win/dtrans/DTransHelper.hxx
new file mode 100644
index 000000000..d8ab3349c
--- /dev/null
+++ b/vcl/win/dtrans/DTransHelper.hxx
@@ -0,0 +1,167 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <objidl.h>
+#include "WinClip.hxx"
+
+#define AUTO_INIT true
+
+// a helper class to manage a global memory area, the clients can write
+// into the global memory area and extract the handle to the global mem
+// note: not thread-safe
+
+class CStgTransferHelper
+{
+public:
+ // will be thrown in case of failures
+ class CStgTransferException
+ {
+ public:
+ HRESULT m_hr;
+ explicit CStgTransferException( HRESULT hr ) : m_hr( hr ) {};
+ };
+
+public:
+ CStgTransferHelper(
+ bool bAutoInit = false,
+ HGLOBAL hGlob = nullptr,
+ bool bDelStgOnRelease = false );
+
+ ~CStgTransferHelper( );
+
+ void write( const void* lpData, ULONG cb, ULONG* cbWritten = nullptr );
+ void read( LPVOID pv, ULONG cb, ULONG* pcbRead = nullptr );
+
+ HGLOBAL getHGlobal( ) const;
+ void getIStream( LPSTREAM* ppStream );
+
+ void init(
+ SIZE_T newSize,
+ sal_uInt32 uiFlags = GHND,
+ bool bDelStgOnRelease = false );
+
+ void init(
+ HGLOBAL hGlob,
+ bool bDelStgOnRelease = false );
+
+ // returns the size of the managed memory
+ sal_uInt32 memSize( CLIPFORMAT cf = CF_INVALID ) const;
+
+ // free the global memory and necessary
+ // release the internal stream pointer
+ void cleanup( );
+
+private:
+ LPSTREAM m_lpStream;
+ bool m_bDelStgOnRelease;
+
+private:
+ CStgTransferHelper( const CStgTransferHelper& );
+ CStgTransferHelper& operator=( const CStgTransferHelper& );
+};
+
+// something like an auto-pointer - allows access to the memory belonging
+// to a HGLOBAL and automatically unlocks a global memory at destruction
+// time
+
+class CRawHGlobalPtr
+{
+public:
+
+ // ctor
+
+ explicit CRawHGlobalPtr( HGLOBAL hGlob ) :
+ m_hGlob( hGlob ),
+ m_bIsLocked( false ),
+ m_pGlobMem( nullptr )
+ {
+ }
+
+ // ctor
+
+ explicit CRawHGlobalPtr( const CStgTransferHelper& theHGlobalHelper ) :
+ m_hGlob( theHGlobalHelper.getHGlobal( ) ),
+ m_bIsLocked( false ),
+ m_pGlobMem( nullptr )
+ {
+ }
+
+ // dtor
+
+ ~CRawHGlobalPtr( )
+ {
+ if ( m_bIsLocked )
+ GlobalUnlock( m_hGlob );
+ }
+
+ // lock the global memory (initializes a
+ // pointer to this memory)
+
+ BOOL Lock( )
+ {
+ if ( !m_bIsLocked && ( nullptr != m_hGlob ) )
+ {
+ m_pGlobMem = GlobalLock( m_hGlob );
+ m_bIsLocked = ( nullptr != m_pGlobMem );
+ }
+
+ return m_bIsLocked;
+ }
+
+ // unlock the global memory (invalidates the
+ // pointer to this memory)
+
+ BOOL Unlock( )
+ {
+ GlobalUnlock( m_hGlob );
+ m_bIsLocked = false;
+ m_pGlobMem = nullptr;
+
+ return ( NO_ERROR == GetLastError( ) );
+ }
+
+ // locks the global memory and returns a
+ // pointer to this memory
+
+ LPVOID GetMemPtr( )
+ {
+ Lock( );
+ return m_pGlobMem;
+ }
+
+ // size of mem we point to
+
+ int MemSize( ) const
+ {
+ return GlobalSize( m_hGlob );
+ }
+
+private:
+ HGLOBAL m_hGlob;
+ bool m_bIsLocked;
+ LPVOID m_pGlobMem;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/DataFmtTransl.cxx b/vcl/win/dtrans/DataFmtTransl.cxx
new file mode 100644
index 000000000..5daf0b453
--- /dev/null
+++ b/vcl/win/dtrans/DataFmtTransl.cxx
@@ -0,0 +1,252 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "DataFmtTransl.hxx"
+#include <rtl/string.hxx>
+#include <osl/diagnose.h>
+#include <rtl/tencinfo.h>
+#include "ImplHelper.hxx"
+#include "WinClip.hxx"
+#include "MimeAttrib.hxx"
+#include "DTransHelper.hxx"
+#include <rtl/string.h>
+#include <o3tl/char16_t2wchar_t.hxx>
+#include "Fetc.hxx"
+#include <com/sun/star/datatransfer/DataFormatTranslator.hpp>
+
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <shlobj.h>
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::lang;
+
+const Type CPPUTYPE_SALINT32 = cppu::UnoType<sal_Int32>::get();
+const Type CPPUTYPE_SALINT8 = cppu::UnoType<sal_Int8>::get();
+const Type CPPUTYPE_OUSTRING = cppu::UnoType<OUString>::get();
+const Type CPPUTYPE_SEQSALINT8 = cppu::UnoType<Sequence< sal_Int8>>::get();
+const sal_Int32 MAX_CLIPFORMAT_NAME = 256;
+
+CDataFormatTranslator::CDataFormatTranslator( const Reference< XComponentContext >& rxContext )
+{
+ m_XDataFormatTranslator = DataFormatTranslator::create( rxContext );
+}
+
+CFormatEtc CDataFormatTranslator::getFormatEtcFromDataFlavor( const DataFlavor& aDataFlavor ) const
+{
+ sal_Int32 cf = CF_INVALID;
+
+ try
+ {
+ if( m_XDataFormatTranslator.is( ) )
+ {
+ Any aFormat = m_XDataFormatTranslator->getSystemDataTypeFromDataFlavor( aDataFlavor );
+
+ if ( aFormat.hasValue( ) )
+ {
+ if ( aFormat.getValueType( ) == CPPUTYPE_SALINT32 )
+ {
+ aFormat >>= cf;
+ OSL_ENSURE( CF_INVALID != cf, "Invalid Clipboard format delivered" );
+ }
+ else if ( aFormat.getValueType( ) == CPPUTYPE_OUSTRING )
+ {
+ OUString aClipFmtName;
+ aFormat >>= aClipFmtName;
+
+ OSL_ASSERT( aClipFmtName.getLength( ) );
+ cf = RegisterClipboardFormatW( o3tl::toW(aClipFmtName.getStr( )) );
+
+ OSL_ENSURE( CF_INVALID != cf, "RegisterClipboardFormat failed" );
+ }
+ else
+ OSL_FAIL( "Wrong Any-Type detected" );
+ }
+ }
+ }
+ catch( ... )
+ {
+ OSL_FAIL( "Unexpected error" );
+ }
+
+ return sal::static_int_cast<CFormatEtc>(getFormatEtcForClipformat( sal::static_int_cast<CLIPFORMAT>(cf) ));
+}
+
+DataFlavor CDataFormatTranslator::getDataFlavorFromFormatEtc(sal_uInt32 cfFormat, LCID lcid) const
+{
+ DataFlavor aFlavor;
+
+ try
+ {
+ CLIPFORMAT aClipformat = cfFormat;
+
+ Any aAny;
+ aAny <<= static_cast< sal_Int32 >( aClipformat );
+
+ if ( isOemOrAnsiTextFormat( aClipformat ) )
+ {
+ aFlavor.MimeType = "text/plain;charset=";
+ aFlavor.MimeType += getTextCharsetFromLCID( lcid, aClipformat );
+
+ aFlavor.HumanPresentableName = "OEM/ANSI Text";
+ aFlavor.DataType = CPPUTYPE_SEQSALINT8;
+ }
+ else if ( CF_INVALID != aClipformat )
+ {
+ if ( m_XDataFormatTranslator.is( ) )
+ {
+ aFlavor = m_XDataFormatTranslator->getDataFlavorFromSystemDataType( aAny );
+
+ if ( !aFlavor.MimeType.getLength( ) )
+ {
+ // lookup of DataFlavor from clipboard format id
+ // failed, so we try to resolve via clipboard
+ // format name
+ OUString clipFormatName = getClipboardFormatName( aClipformat );
+
+ // if we could not get a clipboard format name an
+ // error must have occurred or it is a standard
+ // clipboard format that we don't translate, e.g.
+ // CF_BITMAP (the office only uses CF_DIB)
+ if ( clipFormatName.getLength( ) )
+ {
+ aAny <<= clipFormatName;
+ aFlavor = m_XDataFormatTranslator->getDataFlavorFromSystemDataType( aAny );
+ }
+ }
+ }
+ }
+ }
+ catch( ... )
+ {
+ OSL_FAIL( "Unexpected error" );
+ }
+
+ return aFlavor;
+}
+
+CFormatEtc CDataFormatTranslator::getFormatEtcForClipformatName( const OUString& aClipFmtName )
+{
+ // check parameter
+ if ( !aClipFmtName.getLength( ) )
+ return CFormatEtc( CF_INVALID );
+
+ CLIPFORMAT cf = sal::static_int_cast<CLIPFORMAT>(RegisterClipboardFormatW( o3tl::toW(aClipFmtName.getStr( )) ));
+ return getFormatEtcForClipformat( cf );
+}
+
+OUString CDataFormatTranslator::getClipboardFormatName( CLIPFORMAT aClipformat )
+{
+ OSL_PRECOND( CF_INVALID != aClipformat, "Invalid clipboard format" );
+
+ sal_Unicode wBuff[ MAX_CLIPFORMAT_NAME + 1 ]; // Null terminator isn't counted, apparently.
+ sal_Int32 nLen = GetClipboardFormatNameW( aClipformat, o3tl::toW(wBuff), MAX_CLIPFORMAT_NAME );
+
+ return OUString( wBuff, nLen );
+}
+
+CFormatEtc CDataFormatTranslator::getFormatEtcForClipformat( CLIPFORMAT cf )
+{
+ CFormatEtc fetc( cf, TYMED_NULL, nullptr, DVASPECT_CONTENT );
+
+ switch( cf )
+ {
+ case CF_METAFILEPICT:
+ fetc.setTymed( TYMED_MFPICT );
+ break;
+
+ case CF_ENHMETAFILE:
+ fetc.setTymed( TYMED_ENHMF );
+ break;
+
+ default:
+ fetc.setTymed( TYMED_HGLOBAL /*| TYMED_ISTREAM*/ );
+ }
+
+ /*
+ hack: in order to paste urls copied by Internet Explorer
+ with "copy link" we set the lindex member to 0
+ but if we really want to support CFSTR_FILECONTENT and
+ the accompany format CFSTR_FILEDESCRIPTOR (FileGroupDescriptor)
+ the client of the clipboard service has to provide a id
+ of which FileContents it wants to paste
+ see MSDN: "Handling Shell Data Transfer Scenarios"
+ */
+ if ( cf == RegisterClipboardFormat( CFSTR_FILECONTENTS ) )
+ fetc.setLindex( 0 );
+
+ return fetc;
+}
+
+bool CDataFormatTranslator::isOemOrAnsiTextFormat( CLIPFORMAT cf )
+{
+ return ( (cf == CF_TEXT) || (cf == CF_OEMTEXT) );
+}
+
+bool CDataFormatTranslator::isUnicodeTextFormat( CLIPFORMAT cf )
+{
+ return ( cf == CF_UNICODETEXT );
+}
+
+bool CDataFormatTranslator::isTextFormat( CLIPFORMAT cf )
+{
+ return ( isOemOrAnsiTextFormat( cf ) || isUnicodeTextFormat( cf ) );
+}
+
+bool CDataFormatTranslator::isHTMLFormat( CLIPFORMAT cf )
+{
+ OUString clipFormatName = getClipboardFormatName( cf );
+ return ( clipFormatName == "HTML Format" );
+}
+
+bool CDataFormatTranslator::isTextHtmlFormat( CLIPFORMAT cf )
+{
+ OUString clipFormatName = getClipboardFormatName( cf );
+ return clipFormatName.equalsIgnoreAsciiCase( "HTML (HyperText Markup Language)" );
+}
+
+OUString CDataFormatTranslator::getTextCharsetFromLCID( LCID lcid, CLIPFORMAT aClipformat )
+{
+ OSL_ASSERT( isOemOrAnsiTextFormat( aClipformat ) );
+
+ OUString charset;
+ if ( CF_TEXT == aClipformat )
+ {
+ charset = getMimeCharsetFromLocaleId(
+ lcid,
+ LOCALE_IDEFAULTANSICODEPAGE,
+ PRE_WINDOWS_CODEPAGE );
+ }
+ else if ( CF_OEMTEXT == aClipformat )
+ {
+ charset = getMimeCharsetFromLocaleId(
+ lcid,
+ LOCALE_IDEFAULTCODEPAGE,
+ PRE_OEM_CODEPAGE );
+ }
+ else // CF_UNICODE
+ OSL_ASSERT( false );
+
+ return charset;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/DataFmtTransl.hxx b/vcl/win/dtrans/DataFmtTransl.hxx
new file mode 100644
index 000000000..e003f2538
--- /dev/null
+++ b/vcl/win/dtrans/DataFmtTransl.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/datatransfer/XDataFormatTranslator.hpp>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <sal/types.h>
+#include <rtl/ustring.hxx>
+
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <objidl.h>
+
+// declaration
+
+class CFormatEtc;
+
+class CDataFormatTranslator
+{
+public:
+ explicit CDataFormatTranslator( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+
+ CFormatEtc getFormatEtcFromDataFlavor( const css::datatransfer::DataFlavor& aDataFlavor ) const;
+ css::datatransfer::DataFlavor getDataFlavorFromFormatEtc(
+ sal_uInt32 cfFormat, LCID lcid = GetThreadLocale()) const;
+
+ static CFormatEtc getFormatEtcForClipformat( CLIPFORMAT cf );
+ static CFormatEtc getFormatEtcForClipformatName( const OUString& aClipFmtName );
+ static OUString getClipboardFormatName( CLIPFORMAT aClipformat );
+
+ static bool isHTMLFormat( CLIPFORMAT cf );
+ static bool isTextHtmlFormat( CLIPFORMAT cf );
+ static bool isOemOrAnsiTextFormat( CLIPFORMAT cf );
+ static bool isUnicodeTextFormat( CLIPFORMAT cf );
+ static bool isTextFormat( CLIPFORMAT cf );
+
+private:
+ static OUString getTextCharsetFromLCID( LCID lcid, CLIPFORMAT aClipformat );
+
+private:
+ css::uno::Reference< css::datatransfer::XDataFormatTranslator > m_XDataFormatTranslator;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/DtObjFactory.cxx b/vcl/win/dtrans/DtObjFactory.cxx
new file mode 100644
index 000000000..8fe03789b
--- /dev/null
+++ b/vcl/win/dtrans/DtObjFactory.cxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "DtObjFactory.hxx"
+#include "XTDataObject.hxx"
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::lang;
+
+IDataObjectPtr
+CDTransObjFactory::createDataObjFromTransferable(const Reference<XComponentContext>& rxContext,
+ const Reference<XTransferable>& refXTransferable)
+{
+ return (IDataObjectPtr(new CXTDataObject(rxContext, refXTransferable)));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/DtObjFactory.hxx b/vcl/win/dtrans/DtObjFactory.hxx
new file mode 100644
index 000000000..b5d5f5007
--- /dev/null
+++ b/vcl/win/dtrans/DtObjFactory.hxx
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <systools/win32/comtools.hxx>
+
+namespace CDTransObjFactory
+{
+ IDataObjectPtr createDataObjFromTransferable( const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ const css::uno::Reference< css::datatransfer::XTransferable >& refXTransferable );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/Fetc.cxx b/vcl/win/dtrans/Fetc.cxx
new file mode 100644
index 000000000..9bcb2f609
--- /dev/null
+++ b/vcl/win/dtrans/Fetc.cxx
@@ -0,0 +1,166 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <osl/diagnose.h>
+#include "Fetc.hxx"
+#include "ImplHelper.hxx"
+
+CFormatEtc::CFormatEtc( )
+{
+ m_FormatEtc.cfFormat = 0;
+ m_FormatEtc.ptd = nullptr;
+ m_FormatEtc.dwAspect = 0;
+ m_FormatEtc.lindex = -1;
+ m_FormatEtc.tymed = TYMED_NULL;
+}
+
+// transfer of ownership
+
+CFormatEtc::CFormatEtc( const FORMATETC& aFormatEtc )
+{
+ CopyFormatEtc( &m_FormatEtc, &const_cast< FORMATETC& >( aFormatEtc ) );
+}
+
+CFormatEtc::~CFormatEtc( )
+{
+ DeleteTargetDevice( m_FormatEtc.ptd );
+}
+
+CFormatEtc::CFormatEtc( CLIPFORMAT cf, DWORD tymed, DVTARGETDEVICE* ptd, DWORD dwAspect, LONG lindex )
+{
+ m_FormatEtc.cfFormat = cf;
+ m_FormatEtc.ptd = CopyTargetDevice( ptd );
+ m_FormatEtc.dwAspect = dwAspect;
+ m_FormatEtc.lindex = lindex;
+ m_FormatEtc.tymed = tymed;
+}
+
+CFormatEtc::CFormatEtc( const CFormatEtc& theOther )
+{
+ m_FormatEtc.cfFormat = theOther.m_FormatEtc.cfFormat;
+ m_FormatEtc.ptd = CopyTargetDevice( theOther.m_FormatEtc.ptd );
+ m_FormatEtc.dwAspect = theOther.m_FormatEtc.dwAspect;
+ m_FormatEtc.lindex = theOther.m_FormatEtc.lindex;
+ m_FormatEtc.tymed = theOther.m_FormatEtc.tymed;
+}
+
+CFormatEtc& CFormatEtc::operator=( const CFormatEtc& theOther )
+{
+ if ( this != &theOther )
+ {
+ DeleteTargetDevice( m_FormatEtc.ptd );
+
+ m_FormatEtc.cfFormat = theOther.m_FormatEtc.cfFormat;
+ m_FormatEtc.ptd = CopyTargetDevice( theOther.m_FormatEtc.ptd );
+ m_FormatEtc.dwAspect = theOther.m_FormatEtc.dwAspect;
+ m_FormatEtc.lindex = theOther.m_FormatEtc.lindex;
+ m_FormatEtc.tymed = theOther.m_FormatEtc.tymed;
+ }
+
+ return *this;
+}
+
+CFormatEtc::operator FORMATETC*( )
+{
+ return &m_FormatEtc;
+}
+
+CFormatEtc::operator FORMATETC( )
+{
+ return m_FormatEtc;
+}
+
+void CFormatEtc::getFORMATETC( LPFORMATETC lpFormatEtc )
+{
+ OSL_ASSERT( lpFormatEtc );
+ OSL_ASSERT( !IsBadWritePtr( lpFormatEtc, sizeof( FORMATETC ) ) );
+
+ CopyFormatEtc( lpFormatEtc, &m_FormatEtc );
+}
+
+CLIPFORMAT CFormatEtc::getClipformat( ) const
+{
+ return m_FormatEtc.cfFormat;
+}
+
+DWORD CFormatEtc::getTymed( ) const
+{
+ return m_FormatEtc.tymed;
+}
+
+void CFormatEtc::getTargetDevice( DVTARGETDEVICE** lpDvTargetDevice ) const
+{
+ OSL_ASSERT( lpDvTargetDevice );
+ OSL_ASSERT( !IsBadWritePtr( lpDvTargetDevice, sizeof( DVTARGETDEVICE ) ) );
+
+ *lpDvTargetDevice = nullptr;
+
+ if ( m_FormatEtc.ptd )
+ *lpDvTargetDevice = CopyTargetDevice( m_FormatEtc.ptd );
+}
+
+DWORD CFormatEtc::getDvAspect( ) const
+{
+ return m_FormatEtc.dwAspect;
+}
+
+LONG CFormatEtc::getLindex( ) const
+{
+ return m_FormatEtc.lindex;
+}
+
+void CFormatEtc::setClipformat( CLIPFORMAT cf )
+{
+ m_FormatEtc.cfFormat = cf;
+}
+
+void CFormatEtc::setTymed( DWORD tymed )
+{
+ m_FormatEtc.tymed = tymed;
+}
+
+// transfer of ownership!
+
+void CFormatEtc::setTargetDevice( DVTARGETDEVICE* ptd )
+{
+ DeleteTargetDevice( m_FormatEtc.ptd );
+ m_FormatEtc.ptd = ptd;
+}
+
+void CFormatEtc::setDvAspect( DWORD dwAspect )
+{
+ m_FormatEtc.dwAspect = dwAspect;
+}
+
+void CFormatEtc::setLindex( LONG lindex )
+{
+ m_FormatEtc.lindex = lindex;
+}
+
+bool operator==( const CFormatEtc& lhs, const CFormatEtc& rhs )
+{
+ return CompareFormatEtc( &lhs.m_FormatEtc, &rhs.m_FormatEtc );
+}
+
+bool operator!=( const CFormatEtc& lhs, const CFormatEtc& rhs )
+{
+ return !( lhs == rhs );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/Fetc.hxx b/vcl/win/dtrans/Fetc.hxx
new file mode 100644
index 000000000..e0880acd6
--- /dev/null
+++ b/vcl/win/dtrans/Fetc.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <objidl.h>
+
+/**********************************************************************
+ stl container elements must fulfill the following requirements:
+ 1. they need a copy ctor and assignment operator(?)
+ 2. they must be comparable
+ because the FORMATETC structure has a pointer to a TARGETDEVICE
+ structure we need a simple wrapper class to fulfill these needs
+***********************************************************************/
+
+class CFormatEtc
+{
+public:
+ CFormatEtc( );
+ explicit CFormatEtc( const FORMATETC& aFormatEtc );
+ CFormatEtc( CLIPFORMAT cf, DWORD tymed = TYMED_HGLOBAL, DVTARGETDEVICE* ptd = nullptr, DWORD dwAspect = DVASPECT_CONTENT, LONG lindex = -1 );
+ CFormatEtc( const CFormatEtc& theOther );
+
+ ~CFormatEtc( );
+
+ CFormatEtc& operator=( const CFormatEtc& theOther );
+ operator FORMATETC*( );
+ operator FORMATETC( );
+
+ void getFORMATETC( LPFORMATETC lpFormatEtc );
+
+ CLIPFORMAT getClipformat( ) const;
+ DWORD getTymed( ) const;
+ void getTargetDevice( DVTARGETDEVICE** ptd ) const;
+ DWORD getDvAspect( ) const;
+ LONG getLindex( ) const;
+
+ void setClipformat( CLIPFORMAT cf );
+ void setTymed( DWORD tymed );
+ void setTargetDevice( DVTARGETDEVICE* ptd );
+ void setDvAspect( DWORD dwAspect );
+ void setLindex( LONG lindex );
+
+private:
+ FORMATETC m_FormatEtc;
+
+ friend bool operator==( const CFormatEtc& lhs, const CFormatEtc& rhs );
+ friend bool operator!=( const CFormatEtc& lhs, const CFormatEtc& rhs );
+};
+
+bool operator==( const CFormatEtc& lhs, const CFormatEtc& rhs );
+bool operator!=( const CFormatEtc& lhs, const CFormatEtc& rhs );
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/FetcList.cxx b/vcl/win/dtrans/FetcList.cxx
new file mode 100644
index 000000000..5ace3cdca
--- /dev/null
+++ b/vcl/win/dtrans/FetcList.cxx
@@ -0,0 +1,340 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <osl/diagnose.h>
+#include "FetcList.hxx"
+#include "Fetc.hxx"
+#include <com/sun/star/container/NoSuchElementException.hpp>
+#include <com/sun/star/datatransfer/MimeContentTypeFactory.hpp>
+#include <com/sun/star/datatransfer/XMimeContentType.hpp>
+
+#include "DataFmtTransl.hxx"
+#include "ImplHelper.hxx"
+#include "WinClip.hxx"
+
+#include <algorithm>
+
+#include "MimeAttrib.hxx"
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::container;
+
+LCID CFormatRegistrar::m_TxtLocale = 0;
+sal_uInt32 CFormatRegistrar::m_TxtCodePage = GetACP( );
+
+CFormatEtcContainer::CFormatEtcContainer( )
+{
+ m_EnumIterator = m_FormatMap.begin( );
+}
+
+void CFormatEtcContainer::addFormatEtc( const CFormatEtc& fetc )
+{
+ m_FormatMap.push_back( fetc );
+}
+
+void CFormatEtcContainer::removeFormatEtc( const CFormatEtc& fetc )
+{
+ FormatEtcMap_t::iterator iter =
+ find( m_FormatMap.begin(), m_FormatMap.end(), fetc );
+
+ if ( iter != m_FormatMap.end( ) )
+ m_FormatMap.erase( iter );
+}
+
+void CFormatEtcContainer::removeAllFormatEtc( )
+{
+ m_FormatMap.clear( );
+}
+
+bool CFormatEtcContainer::hasFormatEtc( const CFormatEtc& fetc ) const
+{
+ FormatEtcMap_t::const_iterator iter =
+ find( m_FormatMap.begin(), m_FormatMap.end(), fetc );
+
+ return ( iter != m_FormatMap.end( ) );
+}
+
+bool CFormatEtcContainer::hasElements( ) const
+{
+ return !m_FormatMap.empty();
+}
+
+void CFormatEtcContainer::beginEnumFormatEtc( )
+{
+ m_EnumIterator = m_FormatMap.begin( );
+}
+
+sal_uInt32 CFormatEtcContainer::nextFormatEtc( LPFORMATETC lpFetc,
+ sal_uInt32 aNum )
+{
+ OSL_ASSERT( lpFetc );
+ OSL_ASSERT( !IsBadWritePtr( lpFetc, sizeof( FORMATETC ) * aNum ) );
+
+ sal_uInt32 nFetched = 0;
+
+ for ( sal_uInt32 i = 0; i < aNum; i++, nFetched++, lpFetc++, ++m_EnumIterator )
+ {
+ if ( m_EnumIterator == m_FormatMap.end() )
+ break;
+ CopyFormatEtc( lpFetc, *m_EnumIterator );
+ }
+
+ return nFetched;
+}
+
+bool CFormatEtcContainer::skipFormatEtc( sal_uInt32 aNum )
+{
+ FormatEtcMap_t::const_iterator iter_end = m_FormatMap.end( );
+ for ( sal_uInt32 i = 0;
+ (i < aNum) && (m_EnumIterator != iter_end);
+ i++, ++m_EnumIterator )
+ ;/* intentionally left empty */
+
+ return ( m_EnumIterator != m_FormatMap.end( ) );
+}
+
+CFormatRegistrar::CFormatRegistrar( const Reference< XComponentContext >& rxContext,
+ const CDataFormatTranslator& aDataFormatTranslator ) :
+ m_DataFormatTranslator( aDataFormatTranslator ),
+ m_bHasSynthesizedLocale( false ),
+ m_xContext( rxContext )
+{
+}
+
+// this function converts all DataFlavors of the given FlavorList into
+// an appropriate FORMATETC structure, for some formats like unicodetext,
+// text and text/html we will offer an accompany format e.g.:
+//
+// DataFlavor | Registered Clipformat | Registered accompany clipformat
+// -------------------------|---------------------------|-----------------------------------
+// text/plain;charset=ansi | CF_TEXT | CF_UNICODETEXT
+// | | CF_LOCALE (if charset != GetACP()
+// | |
+// text/plain;charset=oem | CF_OEMTEXT | CF_UNICODETEXT
+// | | CF_LOCALE (if charset != GetOEMCP()
+// | |
+// text/plain;charset=utf-16| CF_UNICODETEXT | CF_TEXT
+// | |
+// text/html | HTML (Hypertext ...) | HTML Format
+// | |
+//
+// if some tries to register different text formats with different charsets the last
+// registered wins and the others are ignored
+
+void CFormatRegistrar::RegisterFormats(
+ const Reference< XTransferable >& aXTransferable, CFormatEtcContainer& aFormatEtcContainer )
+{
+ Sequence< DataFlavor > aFlavorList = aXTransferable->getTransferDataFlavors( );
+ sal_Int32 nFlavors = aFlavorList.getLength( );
+ bool bUnicodeRegistered = false;
+ DataFlavor aFlavor;
+
+ for( sal_Int32 i = 0; i < nFlavors; i++ )
+ {
+ aFlavor = aFlavorList[i];
+ CFormatEtc fetc = m_DataFormatTranslator.getFormatEtcFromDataFlavor( aFlavor );
+
+ // maybe an internal format so we ignore it
+ if ( CF_INVALID == fetc.getClipformat( ) )
+ continue;
+
+ if ( !needsToSynthesizeAccompanyFormats( fetc ) )
+ aFormatEtcContainer.addFormatEtc( fetc );
+ else
+ {
+ // if we haven't registered any text format up to now
+ if ( CDataFormatTranslator::isTextFormat( fetc.getClipformat() ) && !bUnicodeRegistered )
+ {
+ // if the transferable supports unicode text we ignore
+ // any further text format the transferable offers
+ // because we can create it from Unicode text in addition
+ // we register CF_TEXT for non unicode clients
+ if ( CDataFormatTranslator::isUnicodeTextFormat( fetc.getClipformat() ) )
+ {
+ aFormatEtcContainer.addFormatEtc( fetc ); // add CF_UNICODE
+ aFormatEtcContainer.addFormatEtc(
+ CDataFormatTranslator::getFormatEtcForClipformat( CF_TEXT ) ); // add CF_TEXT
+ bUnicodeRegistered = true;
+ }
+ else if ( !hasUnicodeFlavor( aXTransferable ) )
+ {
+ // we try to investigate the charset and make a valid
+ // windows codepage from this charset the default
+ // return value is the result of GetACP( )
+ OUString charset = getCharsetFromDataFlavor( aFlavor );
+ sal_uInt32 txtCP = getWinCPFromMimeCharset( charset );
+
+ // we try to get a Locale appropriate for this codepage
+ if ( findLocaleForTextCodePage( ) )
+ {
+ m_TxtCodePage = txtCP;
+
+ aFormatEtcContainer.addFormatEtc(
+ CDataFormatTranslator::getFormatEtcForClipformat( CF_UNICODETEXT ) );
+
+ if ( !IsOEMCP( m_TxtCodePage ) )
+ aFormatEtcContainer.addFormatEtc(
+ CDataFormatTranslator::getFormatEtcForClipformat( CF_TEXT ) );
+ else
+ aFormatEtcContainer.addFormatEtc(
+ CDataFormatTranslator::getFormatEtcForClipformat( CF_OEMTEXT ) );
+
+ aFormatEtcContainer.addFormatEtc(
+ CDataFormatTranslator::getFormatEtcForClipformat( CF_LOCALE ) );
+
+ // we save the flavor so it's easier when
+ // queried for it in XTDataObject::GetData(...)
+ m_RegisteredTextFlavor = aFlavor;
+ m_bHasSynthesizedLocale = true;
+ }
+ }
+ }
+ else if ( CDataFormatTranslator::isTextHtmlFormat( fetc.getClipformat( ) ) ) // Html (Hyper Text...)
+ {
+ // we add text/html ( HTML (HyperText Markup Language) )
+ aFormatEtcContainer.addFormatEtc( fetc );
+
+ // and HTML Format
+ aFormatEtcContainer.addFormatEtc(
+ CDataFormatTranslator::getFormatEtcForClipformatName( "HTML Format" ) );
+ }
+ }
+ }
+}
+
+bool CFormatRegistrar::hasSynthesizedLocale( ) const
+{
+ return m_bHasSynthesizedLocale;
+}
+
+LCID CFormatRegistrar::getSynthesizedLocale( )
+{
+ return m_TxtLocale;
+}
+
+sal_uInt32 CFormatRegistrar::getRegisteredTextCodePage( )
+{
+ return m_TxtCodePage;
+}
+
+DataFlavor CFormatRegistrar::getRegisteredTextFlavor( ) const
+{
+ return m_RegisteredTextFlavor;
+}
+
+bool CFormatRegistrar::isSynthesizeableFormat( const CFormatEtc& aFormatEtc )
+{
+ return ( CDataFormatTranslator::isOemOrAnsiTextFormat( aFormatEtc.getClipformat() ) ||
+ CDataFormatTranslator::isUnicodeTextFormat( aFormatEtc.getClipformat() ) ||
+ CDataFormatTranslator::isHTMLFormat( aFormatEtc.getClipformat() ) );
+}
+
+inline
+bool CFormatRegistrar::needsToSynthesizeAccompanyFormats( const CFormatEtc& aFormatEtc )
+{
+ return ( CDataFormatTranslator::isOemOrAnsiTextFormat( aFormatEtc.getClipformat() ) ||
+ CDataFormatTranslator::isUnicodeTextFormat( aFormatEtc.getClipformat() ) ||
+ CDataFormatTranslator::isTextHtmlFormat( aFormatEtc.getClipformat( ) ) );
+}
+
+OUString CFormatRegistrar::getCharsetFromDataFlavor( const DataFlavor& aFlavor )
+{
+ OUString charset;
+
+ try
+ {
+ Reference< XMimeContentTypeFactory > xMimeFac =
+ MimeContentTypeFactory::create(m_xContext);
+
+ Reference< XMimeContentType > xMimeType( xMimeFac->createMimeContentType( aFlavor.MimeType ) );
+ if ( xMimeType->hasParameter( TEXTPLAIN_PARAM_CHARSET ) )
+ charset = xMimeType->getParameterValue( TEXTPLAIN_PARAM_CHARSET );
+ else
+ charset = getMimeCharsetFromWinCP( GetACP( ), PRE_WINDOWS_CODEPAGE );
+ }
+ catch(NoSuchElementException&)
+ {
+ OSL_FAIL( "Unexpected" );
+ }
+ catch(...)
+ {
+ OSL_FAIL( "Invalid data flavor" );
+ }
+
+ return charset;
+}
+
+bool CFormatRegistrar::hasUnicodeFlavor( const Reference< XTransferable >& aXTransferable ) const
+{
+ DataFlavor aFlavor = m_DataFormatTranslator.getDataFlavorFromFormatEtc(CF_UNICODETEXT);
+
+ return aXTransferable->isDataFlavorSupported( aFlavor );
+}
+
+bool CFormatRegistrar::findLocaleForTextCodePage( )
+{
+ m_TxtLocale = 0;
+ EnumSystemLocalesA( CFormatRegistrar::EnumLocalesProc, LCID_INSTALLED );
+ return IsValidLocale( m_TxtLocale, LCID_INSTALLED );
+}
+
+bool CFormatRegistrar::isLocaleCodePage( LCID lcid, LCTYPE lctype, sal_uInt32 codepage )
+{
+ char buff[6];
+ sal_uInt32 localeCodePage;
+
+ OSL_ASSERT( IsValidLocale( lcid, LCID_INSTALLED ) );
+
+ // get the ansi codepage of the current locale
+ GetLocaleInfoA( lcid, lctype, buff, sizeof( buff ) );
+ localeCodePage = atol( buff );
+
+ return ( localeCodePage == codepage );
+}
+
+inline
+bool CFormatRegistrar::isLocaleOemCodePage( LCID lcid, sal_uInt32 codepage )
+{
+ return isLocaleCodePage( lcid, LOCALE_IDEFAULTCODEPAGE, codepage );
+}
+
+inline
+bool CFormatRegistrar::isLocaleAnsiCodePage( LCID lcid, sal_uInt32 codepage )
+{
+ return isLocaleCodePage( lcid, LOCALE_IDEFAULTANSICODEPAGE, codepage );
+}
+
+BOOL CALLBACK CFormatRegistrar::EnumLocalesProc( LPSTR lpLocaleStr )
+{
+ // the lpLocaleStr parameter is hexadecimal
+ LCID lcid = strtol( lpLocaleStr, nullptr, 16 );
+
+ if ( isLocaleAnsiCodePage( lcid, CFormatRegistrar::m_TxtCodePage ) ||
+ isLocaleOemCodePage( lcid, CFormatRegistrar::m_TxtCodePage ) )
+ {
+ CFormatRegistrar::m_TxtLocale = lcid;
+ return false; // stop enumerating
+ }
+
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/FetcList.hxx b/vcl/win/dtrans/FetcList.hxx
new file mode 100644
index 000000000..2df28ff57
--- /dev/null
+++ b/vcl/win/dtrans/FetcList.hxx
@@ -0,0 +1,139 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include "Fetc.hxx"
+
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+
+#include <vector>
+
+/*****************************************************************
+ a simple container for FORMATECT structures
+ instances of this class are not thread-safe
+*****************************************************************/
+
+class CFormatEtcContainer
+{
+public:
+ CFormatEtcContainer( );
+
+ // duplicates not allowed
+ void addFormatEtc( const CFormatEtc& fetc );
+
+ // removes the specified formatetc
+ void removeFormatEtc( const CFormatEtc& fetc );
+
+ // removes the formatetc at pos
+ void removeAllFormatEtc( );
+
+ bool hasFormatEtc( const CFormatEtc& fetc ) const;
+
+ bool hasElements( ) const;
+
+ // begin enumeration
+ void beginEnumFormatEtc( );
+
+ // copies the specified number of formatetc structures starting
+ // at the current enum position
+ // the return value is the number of copied elements; if the
+ // current enum position is at the end the return value is 0
+ sal_uInt32 nextFormatEtc( LPFORMATETC lpFetc, sal_uInt32 aNum = 1 );
+
+ // skips the specified number of elements in the container
+ bool skipFormatEtc( sal_uInt32 aNum );
+
+protected:
+ typedef std::vector< CFormatEtc > FormatEtcMap_t;
+
+private:
+ FormatEtcMap_t m_FormatMap;
+ FormatEtcMap_t::iterator m_EnumIterator;
+};
+
+/*****************************************************************
+ a helper class which converts data flavors to clipformats,
+ creates an appropriate formatetc structures and if possible
+ synthesizes clipboard formats if necessary, e.g. if text
+ is provided a locale will also be provided;
+ the class registers the formatetc within a CFormatEtcContainer
+
+ instances of this class are not thread-safe and multiple
+ instances of this class would use the same static variables
+ that's why this class should not be used by multiple threads,
+ only one thread of a process should use it
+*****************************************************************/
+
+// forward
+class CDataFormatTranslator;
+
+class CFormatRegistrar
+{
+public:
+ CFormatRegistrar( const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ const CDataFormatTranslator& aDataFormatTranslator );
+
+ void RegisterFormats( const css::uno::Reference< css::datatransfer::XTransferable >& aXTransferable,
+ CFormatEtcContainer& aFormatEtcContainer );
+
+ bool hasSynthesizedLocale( ) const;
+ static LCID getSynthesizedLocale( );
+ static sal_uInt32 getRegisteredTextCodePage( );
+ css::datatransfer::DataFlavor getRegisteredTextFlavor( ) const;
+
+ static bool isSynthesizeableFormat( const CFormatEtc& aFormatEtc );
+ static bool needsToSynthesizeAccompanyFormats( const CFormatEtc& aFormatEtc );
+
+private:
+ OUString getCharsetFromDataFlavor( const css::datatransfer::DataFlavor& aFlavor );
+
+ bool hasUnicodeFlavor(
+ const css::uno::Reference< css::datatransfer::XTransferable >& aXTransferable ) const;
+
+ static bool findLocaleForTextCodePage( );
+
+ static bool isLocaleOemCodePage( LCID lcid, sal_uInt32 codepage );
+ static bool isLocaleAnsiCodePage( LCID lcid, sal_uInt32 codepage );
+ static bool isLocaleCodePage( LCID lcid, LCTYPE lctype, sal_uInt32 codepage );
+
+ static BOOL CALLBACK EnumLocalesProc( LPSTR lpLocaleStr );
+
+private:
+ const CDataFormatTranslator& m_DataFormatTranslator;
+ bool m_bHasSynthesizedLocale;
+ css::datatransfer::DataFlavor m_RegisteredTextFlavor;
+
+ const css::uno::Reference< css::uno::XComponentContext > m_xContext;
+
+ static LCID m_TxtLocale;
+ static sal_uInt32 m_TxtCodePage;
+
+private:
+ CFormatRegistrar( const CFormatRegistrar& );
+ CFormatRegistrar& operator=( const CFormatRegistrar& );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/FmtFilter.cxx b/vcl/win/dtrans/FmtFilter.cxx
new file mode 100644
index 000000000..27d051f7e
--- /dev/null
+++ b/vcl/win/dtrans/FmtFilter.cxx
@@ -0,0 +1,435 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <string.h>
+
+#include "FmtFilter.hxx"
+
+#include <o3tl/safeint.hxx>
+#include <o3tl/unit_conversion.hxx>
+#include <osl/diagnose.h>
+
+#include <shobjidl.h>
+#include <shlguid.h>
+#include <objidl.h>
+#include <shellapi.h>
+
+#include <string>
+#include <sstream>
+#include <vector>
+#include <iomanip>
+
+#include <systools/win32/comtools.hxx>
+
+using namespace com::sun::star::uno;
+
+namespace {
+
+#pragma pack(2)
+struct METAFILEHEADER
+{
+ DWORD key;
+ short hmf;
+ SMALL_RECT bbox;
+ WORD inch;
+ DWORD reserved;
+ WORD checksum;
+};
+#pragma pack()
+
+}
+
+// convert a windows metafile picture to a LibreOffice metafile picture
+
+Sequence< sal_Int8 > WinMFPictToOOMFPict( Sequence< sal_Int8 >& aMetaFilePict )
+{
+ OSL_ASSERT( aMetaFilePict.getLength( ) == sizeof( METAFILEPICT ) );
+
+ Sequence< sal_Int8 > mfpictStream;
+ METAFILEPICT* pMFPict = reinterpret_cast< METAFILEPICT* >( aMetaFilePict.getArray( ) );
+ HMETAFILE hMf = pMFPict->hMF;
+ sal_uInt32 nCount = GetMetaFileBitsEx( hMf, 0, nullptr );
+
+ if ( nCount > 0 )
+ {
+ mfpictStream.realloc( nCount + sizeof( METAFILEHEADER ) );
+
+ METAFILEHEADER* pMFHeader = reinterpret_cast< METAFILEHEADER* >( mfpictStream.getArray( ) );
+ SMALL_RECT aRect = { 0,
+ 0,
+ static_cast< short >( pMFPict->xExt ),
+ static_cast< short >( pMFPict->yExt ) };
+ USHORT nInch;
+
+ switch( pMFPict->mm )
+ {
+ case MM_TEXT:
+ nInch = o3tl::convert(1, o3tl::Length::in, o3tl::Length::pt);
+ break;
+
+ case MM_LOMETRIC:
+ nInch = o3tl::convert(1, o3tl::Length::in, o3tl::Length::mm10);
+ break;
+
+ case MM_HIMETRIC:
+ nInch = o3tl::convert(1, o3tl::Length::in, o3tl::Length::mm100);
+ break;
+
+ case MM_LOENGLISH:
+ nInch = o3tl::convert(1, o3tl::Length::in, o3tl::Length::in100);
+ break;
+
+ case MM_HIENGLISH:
+ case MM_ISOTROPIC:
+ case MM_ANISOTROPIC:
+ nInch = o3tl::convert(1, o3tl::Length::in, o3tl::Length::in1000);
+ break;
+
+ case MM_TWIPS:
+ nInch = o3tl::convert(1, o3tl::Length::in, o3tl::Length::twip);
+ break;
+
+ default:
+ nInch = o3tl::convert(1, o3tl::Length::in, o3tl::Length::master);
+ }
+
+ pMFHeader->key = 0x9AC6CDD7L;
+ pMFHeader->hmf = 0;
+ pMFHeader->bbox = aRect;
+ pMFHeader->inch = nInch;
+ pMFHeader->reserved = 0;
+ pMFHeader->checksum = 0;
+
+ char* pMFBuff = reinterpret_cast< char* >( mfpictStream.getArray( ) );
+
+ nCount = GetMetaFileBitsEx( pMFPict->hMF, nCount, pMFBuff + sizeof( METAFILEHEADER ) );
+ OSL_ASSERT( nCount > 0 );
+ }
+
+ return mfpictStream;
+}
+
+// convert a windows enhanced metafile to a LibreOffice metafile
+
+Sequence< sal_Int8 > WinENHMFPictToOOMFPict( HENHMETAFILE hEnhMetaFile )
+{
+ Sequence< sal_Int8 > aRet;
+ UINT nSize = 0;
+
+ if( hEnhMetaFile &&
+ ( ( nSize = GetEnhMetaFileBits( hEnhMetaFile, 0, nullptr ) ) != 0 ) )
+ {
+ aRet.realloc( nSize );
+
+ if( GetEnhMetaFileBits( hEnhMetaFile, nSize, reinterpret_cast<unsigned char*>(aRet.getArray()) ) != nSize )
+ aRet.realloc( 0 );
+ }
+
+ return aRet;
+}
+
+// convert a LibreOffice metafile picture to a windows metafile picture
+
+HMETAFILEPICT OOMFPictToWinMFPict( Sequence< sal_Int8 > const & aOOMetaFilePict )
+{
+ HMETAFILEPICT hPict = nullptr;
+ HMETAFILE hMtf = SetMetaFileBitsEx( aOOMetaFilePict.getLength(), reinterpret_cast<unsigned char const *>(aOOMetaFilePict.getConstArray()) );
+
+ if( hMtf )
+ {
+ METAFILEPICT* pPict = static_cast<METAFILEPICT*>(GlobalLock( hPict = GlobalAlloc( GHND, sizeof( METAFILEPICT ) ) ));
+
+ pPict->mm = 8;
+ pPict->xExt = 0;
+ pPict->yExt = 0;
+ pPict->hMF = hMtf;
+
+ GlobalUnlock( hPict );
+ }
+
+ return hPict;
+}
+
+// convert a LibreOffice metafile picture to a windows enhanced metafile picture
+
+HENHMETAFILE OOMFPictToWinENHMFPict( Sequence< sal_Int8 > const & aOOMetaFilePict )
+{
+ HENHMETAFILE hEnhMtf = SetEnhMetaFileBits( aOOMetaFilePict.getLength(), reinterpret_cast<unsigned char const *>(aOOMetaFilePict.getConstArray()) );
+
+ return hEnhMtf;
+}
+
+// convert a windows device independent bitmap into a LibreOffice bitmap
+
+Sequence< sal_Int8 > WinDIBToOOBMP( const Sequence< sal_Int8 >& aWinDIB )
+{
+ OSL_ENSURE(o3tl::make_unsigned(aWinDIB.getLength()) > sizeof(BITMAPINFOHEADER), "CF_DIBV5/CF_DIB too small (!)");
+ Sequence< sal_Int8 > ooBmpStream;
+
+ ooBmpStream.realloc(aWinDIB.getLength( ) + sizeof(BITMAPFILEHEADER));
+ const BITMAPINFOHEADER* pBmpInfoHdr = reinterpret_cast< const BITMAPINFOHEADER* >(aWinDIB.getConstArray());
+ BITMAPFILEHEADER* pBmpFileHdr = reinterpret_cast< BITMAPFILEHEADER* >(ooBmpStream.getArray());
+ const DWORD nSizeInfoOrV5(pBmpInfoHdr->biSize > sizeof(BITMAPINFOHEADER) ? sizeof(BITMAPV5HEADER) : sizeof(BITMAPINFOHEADER));
+ DWORD nOffset(sizeof(BITMAPFILEHEADER) + nSizeInfoOrV5);
+
+ memcpy(pBmpFileHdr + 1, pBmpInfoHdr, aWinDIB.getLength());
+
+ if(pBmpInfoHdr->biBitCount <= 8)
+ {
+ nOffset += (pBmpInfoHdr->biClrUsed ? pBmpInfoHdr->biClrUsed : (1 << pBmpInfoHdr->biBitCount)) << 2;
+ }
+ else if((BI_BITFIELDS == pBmpInfoHdr->biCompression ) && ((16 == pBmpInfoHdr->biBitCount ) || (32 == pBmpInfoHdr->biBitCount )))
+ {
+ nOffset += 12;
+ }
+
+ pBmpFileHdr->bfType = ('M' << 8) | 'B';
+ pBmpFileHdr->bfSize = 0; // maybe: nMemSize + sizeof(BITMAPFILEHEADER)
+ pBmpFileHdr->bfReserved1 = 0;
+ pBmpFileHdr->bfReserved2 = 0;
+ pBmpFileHdr->bfOffBits = nOffset;
+
+ return ooBmpStream;
+}
+
+// convert a LibreOffice bitmap into a windows device independent bitmap
+
+Sequence< sal_Int8 > OOBmpToWinDIB( Sequence< sal_Int8 >& aOOBmp )
+{
+ Sequence< sal_Int8 > winDIBStream( aOOBmp.getLength( ) - sizeof( BITMAPFILEHEADER ) );
+
+ memcpy( winDIBStream.getArray( ),
+ aOOBmp.getArray( ) + sizeof( BITMAPFILEHEADER ),
+ aOOBmp.getLength( ) - sizeof( BITMAPFILEHEADER ) );
+
+ return winDIBStream;
+}
+
+static std::string GetHtmlFormatHeader(size_t startHtml, size_t endHtml, size_t startFragment, size_t endFragment)
+{
+ std::ostringstream htmlHeader;
+ htmlHeader << "Version:1.0" << '\r' << '\n';
+ htmlHeader << "StartHTML:" << std::setw(10) << std::setfill('0') << std::dec << startHtml << '\r' << '\n';
+ htmlHeader << "EndHTML:" << std::setw(10) << std::setfill('0') << std::dec << endHtml << '\r' << '\n';
+ htmlHeader << "StartFragment:" << std::setw(10) << std::setfill('0') << std::dec << startFragment << '\r' << '\n';
+ htmlHeader << "EndFragment:" << std::setw(10) << std::setfill('0') << std::dec << endFragment << '\r' << '\n';
+ return htmlHeader.str();
+}
+
+// the case of these tags has to match what we output in our filters
+// both tags don't allow parameters
+const std::string TAG_HTML("<html>");
+const std::string TAG_END_HTML("</html>");
+
+// The body tag may have parameters so we need to search for the
+// closing '>' manually e.g. <body param> #92840#
+const std::string TAG_BODY("<body");
+const std::string TAG_END_BODY("</body");
+
+Sequence<sal_Int8> TextHtmlToHTMLFormat(Sequence<sal_Int8> const & aTextHtml)
+{
+ OSL_ASSERT(aTextHtml.getLength() > 0);
+
+ if (aTextHtml.getLength() <= 0)
+ return Sequence<sal_Int8>();
+
+ // fill the buffer with dummy values to calc the exact length
+ std::string dummyHtmlHeader = GetHtmlFormatHeader(0, 0, 0, 0);
+ size_t lHtmlFormatHeader = dummyHtmlHeader.length();
+
+ std::string textHtml(
+ reinterpret_cast<const char*>(aTextHtml.getConstArray()),
+ reinterpret_cast<const char*>(aTextHtml.getConstArray()) + aTextHtml.getLength());
+
+ std::string::size_type nStartHtml = textHtml.find(TAG_HTML) + lHtmlFormatHeader - 1; // we start one before '<HTML>' Word 2000 does also so
+ std::string::size_type nEndHtml = textHtml.find(TAG_END_HTML) + lHtmlFormatHeader + TAG_END_HTML.length() + 1; // our SOffice 5.2 wants 2 behind </HTML>?
+
+ // The body tag may have parameters so we need to search for the
+ // closing '>' manually e.g. <BODY param> #92840#
+ std::string::size_type nStartFragment = textHtml.find(">", textHtml.find(TAG_BODY)) + lHtmlFormatHeader + 1;
+ std::string::size_type nEndFragment = textHtml.find(TAG_END_BODY) + lHtmlFormatHeader;
+
+ std::string htmlFormat = GetHtmlFormatHeader(nStartHtml, nEndHtml, nStartFragment, nEndFragment);
+ htmlFormat += textHtml;
+
+ Sequence<sal_Int8> byteSequence(htmlFormat.length() + 1); // space the trailing '\0'
+ memset(byteSequence.getArray(), 0, byteSequence.getLength());
+
+ memcpy(
+ static_cast<void*>(byteSequence.getArray()),
+ static_cast<const void*>(htmlFormat.c_str()),
+ htmlFormat.length());
+
+ return byteSequence;
+}
+
+static std::wstring getFileExtension(const std::wstring& aFilename)
+{
+ std::wstring::size_type idx = aFilename.rfind(L".");
+ if (idx != std::wstring::npos)
+ {
+ return std::wstring(aFilename, idx);
+ }
+ return std::wstring();
+}
+
+const std::wstring SHELL_LINK_FILE_EXTENSION = L".lnk";
+
+static bool isShellLink(const std::wstring& aFilename)
+{
+ std::wstring ext = getFileExtension(aFilename);
+ return (_wcsicmp(ext.c_str(), SHELL_LINK_FILE_EXTENSION.c_str()) == 0);
+}
+
+/** Resolve a Windows Shell Link (lnk) file. If a resolution
+ is not possible simply return the provided name of the
+ lnk file. */
+static std::wstring getShellLinkTarget(const std::wstring& aLnkFile)
+{
+ OSL_ASSERT(isShellLink(aLnkFile));
+
+ std::wstring target = aLnkFile;
+
+ try
+ {
+ sal::systools::COMReference<IShellLinkW> pIShellLink;
+ pIShellLink.CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER);
+
+ sal::systools::COMReference<IPersistFile> pIPersistFile(pIShellLink,
+ sal::systools::COM_QUERY_THROW);
+
+ HRESULT hr = pIPersistFile->Load(aLnkFile.c_str(), STGM_READ);
+ if (FAILED(hr))
+ return target;
+
+ hr = pIShellLink->Resolve(nullptr, SLR_UPDATE | SLR_NO_UI);
+ if (FAILED(hr))
+ return target;
+
+ wchar_t pathW[MAX_PATH];
+ WIN32_FIND_DATAW wfd;
+ hr = pIShellLink->GetPath(pathW, MAX_PATH, &wfd, SLGP_RAWPATH);
+ if (FAILED(hr))
+ return target;
+
+ target = pathW;
+ }
+ catch(sal::systools::ComError& ex)
+ {
+ OSL_FAIL(ex.what());
+ }
+ return target;
+}
+
+typedef Sequence<sal_Int8> ByteSequence_t;
+
+/* Calculate the size required for turning a string list into
+ a double '\0' terminated string buffer */
+static size_t CalcSizeForStringListBuffer(const std::vector<std::wstring>& fileList)
+{
+ if ( fileList.empty() )
+ return 0;
+
+ size_t size = 1; // one for the very final '\0'
+ for (auto const& elem : fileList)
+ {
+ size += elem.length() + 1; // length including terminating '\0'
+ }
+ return (size * sizeof(std::vector<std::wstring>::value_type::value_type));
+}
+
+static ByteSequence_t FileListToByteSequence(const std::vector<std::wstring>& fileList)
+{
+ ByteSequence_t bseq;
+ size_t size = CalcSizeForStringListBuffer(fileList);
+
+ if (size > 0)
+ {
+ bseq.realloc(size);
+ wchar_t* p = reinterpret_cast<wchar_t*>(bseq.getArray());
+ ZeroMemory(p, size);
+
+ for (auto const& elem : fileList)
+ {
+ wcsncpy(p, elem.c_str(), elem.length());
+ p += (elem.length() + 1);
+ }
+ }
+ return bseq;
+}
+
+css::uno::Sequence<sal_Int8> CF_HDROPToFileList(HGLOBAL hGlobal)
+{
+ UINT nFiles = DragQueryFileW(static_cast<HDROP>(hGlobal), 0xFFFFFFFF, nullptr, 0);
+ std::vector<std::wstring> files;
+
+ for (UINT i = 0; i < nFiles; i++)
+ {
+ wchar_t buff[MAX_PATH];
+ /*UINT size =*/ DragQueryFileW(static_cast<HDROP>(hGlobal), i, buff, MAX_PATH);
+ std::wstring filename = buff;
+ if (isShellLink(filename))
+ filename = getShellLinkTarget(filename);
+ files.push_back(filename);
+ }
+ return FileListToByteSequence(files);
+}
+
+// convert a windows bitmap handle into a LibreOffice bitmap
+
+Sequence< sal_Int8 > WinBITMAPToOOBMP( HBITMAP aHBMP )
+{
+ Sequence< sal_Int8 > ooBmpStream;
+
+ SIZE aBmpSize;
+ if( GetBitmapDimensionEx( aHBMP, &aBmpSize ) )
+ {
+ // fill bitmap info header
+ size_t nDataBytes = 4 * aBmpSize.cy * aBmpSize.cy;
+ Sequence< sal_Int8 > aBitmapStream(
+ sizeof(BITMAPINFO) +
+ nDataBytes
+ );
+ PBITMAPINFOHEADER pBmp = reinterpret_cast<PBITMAPINFOHEADER>(aBitmapStream.getArray());
+ pBmp->biSize = sizeof( BITMAPINFOHEADER );
+ pBmp->biWidth = aBmpSize.cx;
+ pBmp->biHeight = aBmpSize.cy;
+ pBmp->biPlanes = 1;
+ pBmp->biBitCount = 32;
+ pBmp->biCompression = BI_RGB;
+ pBmp->biSizeImage = static_cast<DWORD>(nDataBytes);
+ pBmp->biXPelsPerMeter = 1000;
+ pBmp->biYPelsPerMeter = 1000;
+ pBmp->biClrUsed = 0;
+ pBmp->biClrImportant = 0;
+ if( GetDIBits( nullptr, // DC, 0 is a default GC, basically that of the desktop
+ aHBMP,
+ 0, aBmpSize.cy,
+ aBitmapStream.getArray() + sizeof(BITMAPINFO),
+ reinterpret_cast<LPBITMAPINFO>(pBmp),
+ DIB_RGB_COLORS ) )
+ {
+ ooBmpStream = WinDIBToOOBMP( aBitmapStream );
+ }
+ }
+
+ return ooBmpStream;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/FmtFilter.hxx b/vcl/win/dtrans/FmtFilter.hxx
new file mode 100644
index 000000000..b4fb1e1fc
--- /dev/null
+++ b/vcl/win/dtrans/FmtFilter.hxx
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+
+#include <com/sun/star/uno/Sequence.hxx>
+
+#if !defined WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <objidl.h>
+
+/*------------------------------------------------------------------------
+ input:
+ aMetaFilePict - a sequence of bytes containing a METAFILEPICT struct
+------------------------------------------------------------------------*/
+css::uno::Sequence<sal_Int8> WinMFPictToOOMFPict(css::uno::Sequence<sal_Int8>& aMetaFilePict);
+css::uno::Sequence<sal_Int8> WinENHMFPictToOOMFPict(HENHMETAFILE hEnhMetaFile);
+
+/*------------------------------------------------------------------------
+ input:
+ aByteStream - a sequence of bytes containing a LibreOffice metafile
+ picture with a leading METAFILEHEADER
+------------------------------------------------------------------------*/
+HMETAFILEPICT OOMFPictToWinMFPict(css::uno::Sequence<sal_Int8> const& aOOMetaFilePict);
+HENHMETAFILE OOMFPictToWinENHMFPict(css::uno::Sequence<sal_Int8> const& aOOMetaFilePict);
+
+/*------------------------------------------------------------------------
+ input:
+ aWinDIB - sequence of bytes containing a windows device independent
+ bitmap
+------------------------------------------------------------------------*/
+css::uno::Sequence<sal_Int8> WinDIBToOOBMP(const css::uno::Sequence<sal_Int8>& aWinDIB);
+
+/*------------------------------------------------------------------------
+ input:
+ aWinDIB - sequence of bytes containing a windows bitmap handle
+------------------------------------------------------------------------*/
+css::uno::Sequence<sal_Int8> WinBITMAPToOOBMP(HBITMAP);
+
+/*------------------------------------------------------------------------
+ input:
+ aOOBmp - sequence of bytes containing a LibreOffice bitmap
+ May contain CF_DIBV5 or CF_DIB, but removing the BITMAPFILEHEADER
+ is always the same size
+------------------------------------------------------------------------*/
+css::uno::Sequence<sal_Int8> OOBmpToWinDIB(css::uno::Sequence<sal_Int8>& aOOBmp);
+
+/*------------------------------------------------------------------------
+ input:
+ aTextHtml - a sequence of text/html which will be converted to the
+ HTML Format; the HTML Format has header before the real html data
+ the Format is described in the MSDN Library under HTML Clipboard
+ Format
+------------------------------------------------------------------------*/
+css::uno::Sequence<sal_Int8> TextHtmlToHTMLFormat(css::uno::Sequence<sal_Int8> const& aTextHtml);
+
+/**
+ Return a FileList in which Windows Shell Links (lnk) are resolved.
+ If for whatever reason a resolution is not possible leave the
+ original lnk file.
+*/
+css::uno::Sequence<sal_Int8> CF_HDROPToFileList(HGLOBAL hGlobal);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/ImplHelper.cxx b/vcl/win/dtrans/ImplHelper.cxx
new file mode 100644
index 000000000..84c7383b2
--- /dev/null
+++ b/vcl/win/dtrans/ImplHelper.cxx
@@ -0,0 +1,352 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <osl/diagnose.h>
+#include "ImplHelper.hxx"
+#include <rtl/tencinfo.h>
+#include <o3tl/char16_t2wchar_t.hxx>
+#include <string.h>
+#include <memory>
+
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+
+#include <vector>
+
+#define FORMATETC_EXACT_MATCH 1
+#define FORMATETC_PARTIAL_MATCH -1
+#define FORMATETC_NO_MATCH 0
+
+// returns a windows codepage appropriate to the
+// given mime charset parameter value
+
+sal_uInt32 getWinCPFromMimeCharset( const OUString& charset )
+{
+ sal_uInt32 winCP = GetACP( );
+
+ if ( charset.getLength( ) )
+ {
+ OString osCharset(
+ charset.getStr( ), charset.getLength( ), RTL_TEXTENCODING_ASCII_US );
+
+ rtl_TextEncoding txtEnc =
+ rtl_getTextEncodingFromMimeCharset( osCharset.getStr( ) );
+
+ sal_uIntPtr winChrs = rtl_getBestWindowsCharsetFromTextEncoding( txtEnc );
+
+ CHARSETINFO chrsInf;
+ bool bRet = TranslateCharsetInfo( reinterpret_cast<DWORD*>(winChrs), &chrsInf, TCI_SRCCHARSET );
+
+ // if one of the above functions fails
+ // we will return the current ANSI codepage
+ // of this thread
+ if ( bRet )
+ winCP = chrsInf.ciACP;
+ }
+
+ return winCP;
+}
+
+// returns a windows codepage appropriate to the
+// given locale and locale type
+
+OUString getWinCPFromLocaleId( LCID lcid, LCTYPE lctype )
+{
+ OSL_ASSERT( IsValidLocale( lcid, LCID_SUPPORTED ) );
+
+ // we set a default value
+ OUString winCP;
+
+ // set a default value
+ if ( LOCALE_IDEFAULTCODEPAGE == lctype )
+ {
+ winCP = OUString::number( static_cast<sal_Int32>(GetOEMCP( )) );
+ }
+ else if ( LOCALE_IDEFAULTANSICODEPAGE == lctype )
+ {
+ winCP = OUString::number( static_cast<sal_Int32>(GetACP( )) );
+ }
+ else
+ OSL_ASSERT( false );
+
+ // First, get required buffer size, in characters
+ int nResult = GetLocaleInfoW(
+ lcid, lctype, nullptr, 0 );
+
+ OSL_ASSERT( nResult );
+
+ if ( nResult )
+ {
+ std::unique_ptr<wchar_t[]> buff( new wchar_t[nResult] );
+ // Now get the actual data
+ nResult = GetLocaleInfoW( lcid, lctype, buff.get(), nResult );
+
+ OSL_ASSERT(nResult);
+
+ if (nResult)
+ winCP = o3tl::toU( buff.get() );
+
+ }
+
+ return winCP;
+}
+
+// returns a mime charset parameter value appropriate
+// to the given codepage, optional a prefix can be
+// given, e.g. "windows-" or "cp"
+
+OUString getMimeCharsetFromWinCP( sal_uInt32 cp, std::u16string_view aPrefix )
+{
+ return aPrefix + cptostr( cp );
+}
+
+// returns a mime charset parameter value appropriate
+// to the given locale id and locale type, optional a
+// prefix can be given, e.g. "windows-" or "cp"
+
+OUString getMimeCharsetFromLocaleId( LCID lcid, LCTYPE lctype, std::u16string_view aPrefix )
+{
+ OUString charset = getWinCPFromLocaleId( lcid, lctype );
+ return aPrefix + charset;
+}
+
+// IsOEMCP
+
+bool IsOEMCP( sal_uInt32 codepage )
+{
+ OSL_ASSERT( IsValidCodePage( codepage ) );
+
+ sal_uInt32 arrOEMCP[] = { 437, 708, 709, 710, 720, 737,
+ 775, 850, 852, 855, 857, 860,
+ 861, 862, 863, 864, 865, 866,
+ 869, 874, 932, 936, 949, 950, 1361 };
+
+ for ( size_t i = 0; i < SAL_N_ELEMENTS( arrOEMCP ); ++i )
+ if ( arrOEMCP[i] == codepage )
+ return true;
+
+ return false;
+}
+
+// converts a codepage into its string representation
+
+OUString cptostr( sal_uInt32 codepage )
+{
+ OSL_ASSERT( IsValidCodePage( codepage ) );
+
+ return OUString::number( static_cast<sal_Int64>( codepage ) );
+}
+
+// OleStdDeleteTargetDevice()
+//
+// Purpose:
+//
+// Parameters:
+//
+// Return Value:
+// SCODE - S_OK if successful
+void DeleteTargetDevice( DVTARGETDEVICE* ptd )
+{
+ __try
+ {
+ CoTaskMemFree( ptd );
+ }
+ __except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ OSL_FAIL( "Error DeleteTargetDevice" );
+ }
+}
+
+// OleStdCopyTargetDevice()
+//
+// Purpose:
+// duplicate a TARGETDEVICE struct. this function allocates memory for
+// the copy. the caller MUST free the allocated copy when done with it
+// using the standard allocator returned from CoGetMalloc.
+// (OleStdFree can be used to free the copy).
+//
+// Parameters:
+// ptdSrc pointer to source TARGETDEVICE
+//
+// Return Value:
+// pointer to allocated copy of ptdSrc
+// if ptdSrc==NULL then returns NULL is returned.
+// if ptdSrc!=NULL and memory allocation fails, then NULL is returned
+DVTARGETDEVICE* CopyTargetDevice( DVTARGETDEVICE* ptdSrc )
+{
+ DVTARGETDEVICE* ptdDest = nullptr;
+
+ __try
+ {
+ if ( nullptr != ptdSrc )
+ {
+ ptdDest = static_cast< DVTARGETDEVICE* >( CoTaskMemAlloc( ptdSrc->tdSize ) );
+ memcpy( ptdDest, ptdSrc, static_cast< size_t >( ptdSrc->tdSize ) );
+ }
+ }
+ __except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ }
+
+ return ptdDest;
+}
+
+// OleStdCopyFormatEtc()
+//
+// Purpose:
+// Copies the contents of a FORMATETC structure. this function takes
+// special care to copy correctly copying the pointer to the TARGETDEVICE
+// contained within the source FORMATETC structure.
+// if the source FORMATETC has a non-NULL TARGETDEVICE, then a copy
+// of the TARGETDEVICE will be allocated for the destination of the
+// FORMATETC (petcDest).
+//
+// NOTE: the caller MUST free the allocated copy of the TARGETDEVICE
+// within the destination FORMATETC when done with it
+// using the standard allocator returned from CoGetMalloc.
+// (OleStdFree can be used to free the copy).
+//
+// Parameters:
+// petcDest pointer to destination FORMATETC
+// petcSrc pointer to source FORMATETC
+//
+// Return Value:
+// returns TRUE if copy was successful;
+// returns FALSE if not successful, e.g. one or both of the pointers
+// were invalid or the pointers were equal
+bool CopyFormatEtc( LPFORMATETC petcDest, LPFORMATETC petcSrc )
+{
+ bool bRet = false;
+
+ __try
+ {
+ if ( petcDest != petcSrc )
+ {
+
+ petcDest->cfFormat = petcSrc->cfFormat;
+
+ petcDest->ptd = nullptr;
+ if ( nullptr != petcSrc->ptd )
+ petcDest->ptd = CopyTargetDevice(petcSrc->ptd);
+
+ petcDest->dwAspect = petcSrc->dwAspect;
+ petcDest->lindex = petcSrc->lindex;
+ petcDest->tymed = petcSrc->tymed;
+
+ bRet = true;
+ }
+ }
+ __except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ OSL_FAIL( "Error CopyFormatEtc" );
+ }
+
+ return bRet;
+}
+
+// returns:
+// 1 for exact match,
+// 0 for no match,
+// -1 for partial match (which is defined to mean the left is a subset
+// of the right: fewer aspects, null target device, fewer medium).
+
+sal_Int32 CompareFormatEtc( const FORMATETC* pFetcLhs, const FORMATETC* pFetcRhs )
+{
+ sal_Int32 nMatch = FORMATETC_EXACT_MATCH;
+
+ __try
+ {
+ if ( pFetcLhs != pFetcRhs )
+ {
+ if ( ( pFetcLhs->cfFormat != pFetcRhs->cfFormat ) ||
+ ( pFetcLhs->lindex != pFetcRhs->lindex ) ||
+ !CompareTargetDevice( pFetcLhs->ptd, pFetcRhs->ptd ) )
+ {
+ nMatch = FORMATETC_NO_MATCH;
+ }
+
+ else if ( pFetcLhs->dwAspect == pFetcRhs->dwAspect )
+ // same aspects; equal
+ ;
+ else if ( ( pFetcLhs->dwAspect & ~pFetcRhs->dwAspect ) != 0 )
+ {
+ // left not subset of aspects of right; not equal
+ nMatch = FORMATETC_NO_MATCH;
+ }
+ else
+ // left subset of right
+ nMatch = FORMATETC_PARTIAL_MATCH;
+
+ if ( nMatch == FORMATETC_EXACT_MATCH || nMatch == FORMATETC_PARTIAL_MATCH )
+ {
+ if ( pFetcLhs->tymed == pFetcRhs->tymed )
+ // same medium flags; equal
+ ;
+ else if ( ( pFetcLhs->tymed & ~pFetcRhs->tymed ) != 0 )
+ {
+ // left not subset of medium flags of right; not equal
+ nMatch = FORMATETC_NO_MATCH;
+ }
+ else
+ // left subset of right
+ nMatch = FORMATETC_PARTIAL_MATCH;
+ }
+ }
+ }
+ __except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ OSL_FAIL( "Error CompareFormatEtc" );
+ nMatch = FORMATETC_NO_MATCH;
+ }
+
+ return nMatch;
+}
+
+bool CompareTargetDevice( DVTARGETDEVICE* ptdLeft, DVTARGETDEVICE const * ptdRight )
+{
+ bool bRet = false;
+
+ __try
+ {
+ if ( ptdLeft == ptdRight )
+ {
+ // same address of td; must be same (handles NULL case)
+ bRet = true;
+ }
+
+ // one of the two is NULL
+ else if ( ( nullptr != ptdRight ) && ( nullptr != ptdLeft ) )
+
+ if ( ptdLeft->tdSize == ptdRight->tdSize )
+
+ if ( memcmp( ptdLeft, ptdRight, ptdLeft->tdSize ) == 0 )
+ bRet = true;
+ }
+ __except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ OSL_FAIL( "Error CompareTargetDevice" );
+ bRet = false;
+ }
+
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/ImplHelper.hxx b/vcl/win/dtrans/ImplHelper.hxx
new file mode 100644
index 000000000..df6731ec7
--- /dev/null
+++ b/vcl/win/dtrans/ImplHelper.hxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <sal/types.h>
+#include <rtl/ustring.hxx>
+
+#if !defined WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <objidl.h>
+
+// target device and formatetc helper
+void DeleteTargetDevice(DVTARGETDEVICE* ptd);
+bool CopyFormatEtc(LPFORMATETC petcDest, LPFORMATETC petcSrc);
+sal_Int32 CompareFormatEtc(const FORMATETC* pFetcLeft, const FORMATETC* pFetcRight);
+bool CompareTargetDevice(DVTARGETDEVICE* ptdLeft, DVTARGETDEVICE const* ptdRight);
+DVTARGETDEVICE* CopyTargetDevice(DVTARGETDEVICE* ptdSrc);
+
+// some codepage helper functions
+
+// returns a windows codepage appropriate to the
+// given mime charset parameter value
+
+sal_uInt32 getWinCPFromMimeCharset(const OUString& charset);
+
+// returns a windows codepage appropriate to the
+// given locale and locale type
+
+OUString getWinCPFromLocaleId(LCID lcid, LCTYPE lctype);
+
+// returns a mime charset parameter value appropriate
+// to the given codepage, optional a prefix can be
+// given, e.g. "windows-" or "cp"
+
+OUString getMimeCharsetFromWinCP(sal_uInt32 cp, std::u16string_view aPrefix);
+
+// returns a mime charset parameter value appropriate
+// to the given locale id and locale type, optional a
+// prefix can be given, e.g. "windows-" or "cp"
+
+OUString getMimeCharsetFromLocaleId(LCID lcid, LCTYPE lctype, std::u16string_view aPrefix);
+
+// returns true, if a given codepage is an oem codepage
+
+bool IsOEMCP(sal_uInt32 codepage);
+
+// converts a codepage into a string representation
+
+OUString cptostr(sal_uInt32 codepage);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/MimeAttrib.hxx b/vcl/win/dtrans/MimeAttrib.hxx
new file mode 100644
index 000000000..875cb957a
--- /dev/null
+++ b/vcl/win/dtrans/MimeAttrib.hxx
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+
+const OUStringLiteral TEXTPLAIN_PARAM_CHARSET(u"charset");
+
+const OUStringLiteral PRE_WINDOWS_CODEPAGE(u"windows");
+const OUStringLiteral PRE_OEM_CODEPAGE(u"cp");
+const OUStringLiteral CHARSET_UTF16(u"utf-16");
+const OUStringLiteral CHARSET_UNICODE(u"unicode");
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/MtaOleClipb.cxx b/vcl/win/dtrans/MtaOleClipb.cxx
new file mode 100644
index 000000000..865025057
--- /dev/null
+++ b/vcl/win/dtrans/MtaOleClipb.cxx
@@ -0,0 +1,754 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+/*
+ MtaOleClipb.cxx - documentation
+
+ This class setup a single threaded apartment (sta) thread to deal with
+ the ole clipboard, which runs only in an sta thread.
+ The consequence is that callback from the ole clipboard are in the
+ context of this sta thread. In the soffice applications this may lead
+ to problems because they all use the one and only mutex called
+ SolarMutex.
+ In order to transfer clipboard requests to our sta thread we use a
+ hidden window and forward these requests via window messages.
+*/
+
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+
+#include "MtaOleClipb.hxx"
+
+#include <svsys.h>
+#include <win/saldata.hxx>
+
+#include <osl/thread.h>
+
+#include <wchar.h>
+#include <process.h>
+
+#include <systools/win32/comtools.hxx>
+#include <systools/win32/retry_if_failed.hxx>
+
+#include <comphelper/windowserrorstring.hxx>
+
+// namespace directives
+
+using osl::MutexGuard;
+using osl::ClearableMutexGuard;
+
+namespace /* private */
+{
+ const wchar_t g_szWndClsName[] = L"MtaOleReqWnd###";
+
+ // messages constants
+
+ const sal_uInt32 MSG_SETCLIPBOARD = WM_USER + 0x0001;
+ const sal_uInt32 MSG_GETCLIPBOARD = WM_USER + 0x0002;
+ const sal_uInt32 MSG_REGCLIPVIEWER = WM_USER + 0x0003;
+ const sal_uInt32 MSG_FLUSHCLIPBOARD = WM_USER + 0x0004;
+ const sal_uInt32 MSG_SHUTDOWN = WM_USER + 0x0005;
+
+ const sal_uInt32 MAX_WAITTIME = 10000; // msec
+ const sal_uInt32 MAX_WAIT_SHUTDOWN = 10000; // msec
+
+ const bool MANUAL_RESET = true;
+ const bool INIT_NONSIGNALED = false;
+
+ /* Cannot use osl conditions because they are blocking
+ without waking up on messages sent by another thread
+ this leads to deadlocks because we are blocking the
+ communication between inter-thread marshalled COM
+ pointers.
+ COM Proxy-Stub communication uses SendMessages for
+ synchronization purposes.
+ */
+ class Win32Condition
+ {
+ public:
+ Win32Condition() = default;
+
+ ~Win32Condition() { CloseHandle(m_hEvent); }
+
+ // wait infinite for own event (or abort event) be signaled
+ // leave messages sent through
+ bool wait(HANDLE hEvtAbort)
+ {
+ const HANDLE hWaitArray[2] = { m_hEvent, hEvtAbort };
+ while (true)
+ {
+ DWORD dwResult
+ = MsgWaitForMultipleObjects(2, hWaitArray, FALSE, INFINITE, QS_SENDMESSAGE);
+
+ switch (dwResult)
+ {
+ case WAIT_OBJECT_0: // wait successful
+ return true;
+
+ case WAIT_OBJECT_0 + 1: // wait aborted
+ return false;
+
+ case WAIT_OBJECT_0 + 2:
+ {
+ /* PeekMessage processes all messages in the SendMessage
+ queue that's what we want, messages from the PostMessage
+ queue stay untouched */
+ MSG msg;
+ PeekMessageW(&msg, nullptr, 0, 0, PM_NOREMOVE);
+
+ break;
+ }
+
+ default: // WAIT_FAILED?
+ return false;
+ }
+ }
+ }
+
+ // set the event
+ void set() { SetEvent(m_hEvent); }
+
+ private:
+ HANDLE m_hEvent = CreateEventW(nullptr, MANUAL_RESET, INIT_NONSIGNALED, nullptr);
+
+ // prevent copy/assignment
+ Win32Condition(const Win32Condition&) = delete;
+ Win32Condition& operator=(const Win32Condition&) = delete;
+ };
+
+ // we use one condition for every request
+
+ struct MsgCtx
+ {
+ Win32Condition aCondition;
+ HRESULT hr;
+ };
+
+} /* namespace private */
+
+// static member initialization
+
+CMtaOleClipboard* CMtaOleClipboard::s_theMtaOleClipboardInst = nullptr;
+
+// marshal an IDataObject
+
+//inline
+static HRESULT MarshalIDataObjectInStream( IDataObject* pIDataObject, LPSTREAM* ppStream )
+{
+ OSL_ASSERT( nullptr != pIDataObject );
+ OSL_ASSERT( nullptr != ppStream );
+
+ *ppStream = nullptr;
+ return CoMarshalInterThreadInterfaceInStream(
+ __uuidof(IDataObject), //The IID of interface to be marshalled
+ pIDataObject, //The interface pointer
+ ppStream //IStream pointer
+ );
+}
+
+// unmarshal an IDataObject
+
+//inline
+static HRESULT UnmarshalIDataObjectAndReleaseStream( LPSTREAM lpStream, IDataObject** ppIDataObject )
+{
+ OSL_ASSERT( nullptr != lpStream );
+ OSL_ASSERT( nullptr != ppIDataObject );
+
+ *ppIDataObject = nullptr;
+ return CoGetInterfaceAndReleaseStream(
+ lpStream,
+ __uuidof(IDataObject),
+ reinterpret_cast<LPVOID*>(ppIDataObject));
+}
+
+// helper class to ensure that the calling thread has com initialized
+
+namespace {
+
+class CAutoComInit
+{
+public:
+ /*
+ to be safe we call CoInitializeEx
+ although it is not necessary if
+ the calling thread was created
+ using osl_CreateThread because
+ this function calls CoInitializeEx
+ for every thread it creates
+ */
+ CAutoComInit( ) : m_hResult( CoInitializeEx( nullptr, COINIT_APARTMENTTHREADED ) )
+ {
+ if ( S_OK == m_hResult )
+ OSL_FAIL(
+ "com was not yet initialized, the thread was not created using osl_createThread" );
+ else if ( FAILED( m_hResult ) && !( RPC_E_CHANGED_MODE == m_hResult ) )
+ OSL_FAIL(
+ "com could not be initialized, maybe the thread was not created using osl_createThread" );
+ }
+
+ ~CAutoComInit( )
+ {
+ /*
+ we only call CoUninitialize when
+ CoInitializeEx returned S_FALSE, what
+ means that com was already initialize
+ for that thread so we keep the balance
+ if CoInitializeEx returned S_OK what means
+ com was not yet initialized we better
+ let com initialized or we may run into
+ the realm of undefined behaviour
+ */
+ if ( m_hResult == S_FALSE )
+ CoUninitialize( );
+ }
+
+private:
+ HRESULT m_hResult;
+};
+
+}
+
+// ctor
+
+CMtaOleClipboard::CMtaOleClipboard( ) :
+ m_hOleThread( nullptr ),
+ m_uOleThreadId( 0 ),
+ // signals that the thread was successfully setup
+ m_hEvtThrdReady(CreateEventW( nullptr, MANUAL_RESET, INIT_NONSIGNALED, nullptr )),
+ m_hwndMtaOleReqWnd( nullptr ),
+ // signals that the window is destroyed - to stop waiting any winproc result
+ m_hEvtWndDisposed(CreateEventW(nullptr, MANUAL_RESET, INIT_NONSIGNALED, nullptr)),
+ m_MtaOleReqWndClassAtom( 0 ),
+ m_pfncClipViewerCallback( nullptr ),
+ m_bRunClipboardNotifierThread( true ),
+ m_hClipboardChangedEvent( m_hClipboardChangedNotifierEvents[0] ),
+ m_hTerminateClipboardChangedNotifierEvent( m_hClipboardChangedNotifierEvents[1] ),
+ m_ClipboardChangedEventCount( 0 )
+{
+ OSL_ASSERT( nullptr != m_hEvtThrdReady );
+ SAL_WARN_IF(!m_hEvtWndDisposed, "vcl.win.dtrans", "CreateEventW failed: m_hEvtWndDisposed is nullptr");
+
+ s_theMtaOleClipboardInst = this;
+
+ m_hOleThread = CreateThread(
+ nullptr, 0, CMtaOleClipboard::oleThreadProc, this, 0, &m_uOleThreadId );
+ OSL_ASSERT( nullptr != m_hOleThread );
+
+ // setup the clipboard changed notifier thread
+
+ m_hClipboardChangedNotifierEvents[0] = CreateEventW( nullptr, MANUAL_RESET, INIT_NONSIGNALED, nullptr );
+ OSL_ASSERT( nullptr != m_hClipboardChangedNotifierEvents[0] );
+
+ m_hClipboardChangedNotifierEvents[1] = CreateEventW( nullptr, MANUAL_RESET, INIT_NONSIGNALED, nullptr );
+ OSL_ASSERT( nullptr != m_hClipboardChangedNotifierEvents[1] );
+
+ DWORD uThreadId;
+ m_hClipboardChangedNotifierThread = CreateThread(
+ nullptr, 0, CMtaOleClipboard::clipboardChangedNotifierThreadProc, this, 0, &uThreadId );
+
+ OSL_ASSERT( nullptr != m_hClipboardChangedNotifierThread );
+}
+
+// dtor
+
+CMtaOleClipboard::~CMtaOleClipboard( )
+{
+ // block calling threads out
+ if ( nullptr != m_hEvtThrdReady )
+ ResetEvent( m_hEvtThrdReady );
+
+ // terminate the clipboard changed notifier thread
+ m_bRunClipboardNotifierThread = false;
+ SetEvent( m_hTerminateClipboardChangedNotifierEvent );
+
+ // unblock whoever could still wait for event processing
+ if (m_hEvtWndDisposed)
+ SetEvent(m_hEvtWndDisposed);
+
+ sal_uInt32 dwResult = WaitForSingleObject(
+ m_hClipboardChangedNotifierThread, MAX_WAIT_SHUTDOWN );
+
+ OSL_ENSURE( dwResult == WAIT_OBJECT_0, "clipboard notifier thread could not terminate" );
+
+ if ( nullptr != m_hClipboardChangedNotifierThread )
+ CloseHandle( m_hClipboardChangedNotifierThread );
+
+ if ( nullptr != m_hClipboardChangedNotifierEvents[0] )
+ CloseHandle( m_hClipboardChangedNotifierEvents[0] );
+
+ if ( nullptr != m_hClipboardChangedNotifierEvents[1] )
+ CloseHandle( m_hClipboardChangedNotifierEvents[1] );
+
+ // end the thread
+ // because DestroyWindow can only be called
+ // from within the thread that created the window
+ sendMessage( MSG_SHUTDOWN );
+
+ // wait for thread shutdown
+ dwResult = WaitForSingleObject( m_hOleThread, MAX_WAIT_SHUTDOWN );
+ OSL_ENSURE( dwResult == WAIT_OBJECT_0, "OleThread could not terminate" );
+
+ if ( nullptr != m_hOleThread )
+ CloseHandle( m_hOleThread );
+
+ if ( nullptr != m_hEvtThrdReady )
+ CloseHandle( m_hEvtThrdReady );
+
+ if (m_hEvtWndDisposed)
+ CloseHandle(m_hEvtWndDisposed);
+
+ if ( m_MtaOleReqWndClassAtom )
+ UnregisterClassW( g_szWndClsName, nullptr );
+
+ OSL_ENSURE( ( nullptr == m_pfncClipViewerCallback ),
+ "Clipboard viewer not properly unregistered" );
+}
+
+HRESULT CMtaOleClipboard::flushClipboard( )
+{
+ if ( !WaitForThreadReady( ) )
+ {
+ OSL_FAIL( "clipboard sta thread not ready" );
+ return E_FAIL;
+ }
+
+ OSL_ENSURE( GetCurrentThreadId( ) != m_uOleThreadId,
+ "flushClipboard from within clipboard sta thread called" );
+
+ MsgCtx aMsgCtx;
+
+ const bool bWaitSuccess = postMessage(MSG_FLUSHCLIPBOARD, 0, reinterpret_cast<LPARAM>(&aMsgCtx))
+ && aMsgCtx.aCondition.wait(m_hEvtWndDisposed);
+
+ return bWaitSuccess ? aMsgCtx.hr : E_ABORT;
+}
+
+HRESULT CMtaOleClipboard::getClipboard( IDataObject** ppIDataObject )
+{
+ OSL_PRECOND( nullptr != ppIDataObject, "invalid parameter" );
+ OSL_PRECOND( GetCurrentThreadId( ) != m_uOleThreadId, "getClipboard from within clipboard sta thread called" );
+
+ if ( !WaitForThreadReady( ) )
+ {
+ OSL_FAIL( "clipboard sta thread not ready" );
+ return E_FAIL;
+ }
+
+ CAutoComInit comAutoInit;
+
+ LPSTREAM lpStream;
+
+ *ppIDataObject = nullptr;
+
+ MsgCtx aMsgCtx;
+
+ const bool bWaitSuccess = postMessage(MSG_GETCLIPBOARD, reinterpret_cast<WPARAM>(&lpStream),
+ reinterpret_cast<LPARAM>(&aMsgCtx))
+ && aMsgCtx.aCondition.wait(m_hEvtWndDisposed);
+
+ HRESULT hr = bWaitSuccess ? aMsgCtx.hr : E_ABORT;
+
+ if ( SUCCEEDED( hr ) )
+ {
+ hr = UnmarshalIDataObjectAndReleaseStream( lpStream, ppIDataObject );
+ OSL_ENSURE( SUCCEEDED( hr ), "unmarshalling clipboard data object failed" );
+ }
+
+ return hr;
+}
+
+// this is an asynchronous method that's why we don't wait until the
+// request is completed
+
+HRESULT CMtaOleClipboard::setClipboard( IDataObject* pIDataObject )
+{
+ if ( !WaitForThreadReady( ) )
+ {
+ OSL_FAIL( "clipboard sta thread not ready" );
+ return E_FAIL;
+ }
+
+ CAutoComInit comAutoInit;
+
+ OSL_ENSURE( GetCurrentThreadId( ) != m_uOleThreadId, "setClipboard from within the clipboard sta thread called" );
+
+ // because we marshall this request
+ // into the sta thread we better
+ // acquire the interface here so
+ // that the object will not be
+ // destroyed before the ole clipboard
+ // can acquire it
+ // remember: pIDataObject may be NULL
+ // which is a request to clear the
+ // current clipboard content
+ if ( pIDataObject )
+ pIDataObject->AddRef( );
+
+ postMessage(
+ MSG_SETCLIPBOARD,
+ reinterpret_cast< WPARAM >( pIDataObject ) );
+
+ // because this is an asynchronous function
+ // the return value is useless
+ return S_OK;
+}
+
+// register a clipboard viewer
+
+bool CMtaOleClipboard::registerClipViewer( LPFNC_CLIPVIEWER_CALLBACK_t pfncClipViewerCallback )
+{
+ if ( !WaitForThreadReady( ) )
+ {
+ OSL_FAIL( "clipboard sta thread not ready" );
+ return false;
+ }
+
+ OSL_ENSURE( GetCurrentThreadId( ) != m_uOleThreadId, "registerClipViewer from within the OleThread called" );
+
+ MsgCtx aMsgCtx;
+
+ if (postMessage(MSG_REGCLIPVIEWER, reinterpret_cast<WPARAM>(pfncClipViewerCallback),
+ reinterpret_cast<LPARAM>(&aMsgCtx)))
+ aMsgCtx.aCondition.wait(m_hEvtWndDisposed);
+
+ return false;
+}
+
+// register a clipboard viewer
+
+bool CMtaOleClipboard::onRegisterClipViewer( LPFNC_CLIPVIEWER_CALLBACK_t pfncClipViewerCallback )
+{
+ bool bRet = false;
+
+ // we need exclusive access because the clipboard changed notifier
+ // thread also accesses this variable
+ MutexGuard aGuard( m_pfncClipViewerCallbackMutex );
+
+ // register if not yet done
+ if ( ( nullptr != pfncClipViewerCallback ) && ( nullptr == m_pfncClipViewerCallback ) )
+ {
+ // SetClipboardViewer sends a WM_DRAWCLIPBOARD message we ignore
+ // this message if we register ourself as clip viewer
+ m_bInRegisterClipViewer = true;
+ bRet = AddClipboardFormatListener(m_hwndMtaOleReqWnd);
+ m_bInRegisterClipViewer = false;
+
+ // save the new callback function
+ m_pfncClipViewerCallback = pfncClipViewerCallback;
+ }
+ else if ( ( nullptr == pfncClipViewerCallback ) && ( nullptr != m_pfncClipViewerCallback ) )
+ {
+ m_pfncClipViewerCallback = nullptr;
+
+ // unregister if input parameter is NULL and we previously registered
+ // as clipboard viewer
+ bRet = RemoveClipboardFormatListener(m_hwndMtaOleReqWnd);
+ }
+
+ return bRet;
+}
+
+HRESULT CMtaOleClipboard::onSetClipboard( IDataObject* pIDataObject )
+{
+ return sal::systools::RetryIfFailed(10, 100,
+ [pIDataObject] { return OleSetClipboard(pIDataObject); });
+}
+
+HRESULT CMtaOleClipboard::onGetClipboard( LPSTREAM* ppStream )
+{
+ OSL_ASSERT(nullptr != ppStream);
+
+ IDataObjectPtr pIDataObject;
+
+ // forward the request to the OleClipboard
+ HRESULT hr
+ = sal::systools::RetryIfFailed(10, 100, [p = &pIDataObject] { return OleGetClipboard(p); });
+ if ( SUCCEEDED( hr ) )
+ {
+ hr = MarshalIDataObjectInStream(pIDataObject.get(), ppStream);
+ OSL_ENSURE(SUCCEEDED(hr), "marshalling clipboard data object failed");
+ }
+ return hr;
+}
+
+// flush the ole-clipboard
+
+HRESULT CMtaOleClipboard::onFlushClipboard( )
+{
+ return sal::systools::RetryIfFailed(10, 100, [] { return OleFlushClipboard(); });
+}
+
+// handle clipboard update event
+
+LRESULT CMtaOleClipboard::onClipboardUpdate()
+{
+ // we don't send a notification if we are
+ // registering ourself as clipboard
+ if ( !m_bInRegisterClipViewer )
+ {
+ MutexGuard aGuard( m_ClipboardChangedEventCountMutex );
+
+ m_ClipboardChangedEventCount++;
+ SetEvent( m_hClipboardChangedEvent );
+ }
+
+ return 0;
+}
+
+// SendMessage so we don't need to supply the HWND if we send
+// something to our wrapped window
+
+LRESULT CMtaOleClipboard::sendMessage( UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ return ::SendMessageW( m_hwndMtaOleReqWnd, msg, wParam, lParam );
+}
+
+// PostMessage so we don't need to supply the HWND if we send
+// something to our wrapped window
+
+bool CMtaOleClipboard::postMessage( UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ bool const ret = PostMessageW(m_hwndMtaOleReqWnd, msg, wParam, lParam);
+ SAL_WARN_IF(!ret, "vcl.win.dtrans", "ERROR: PostMessage() failed!");
+ return ret;
+}
+
+// the window proc
+
+LRESULT CALLBACK CMtaOleClipboard::mtaOleReqWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+ LRESULT lResult = 0;
+
+ // get a connection to the class-instance via the static member
+ CMtaOleClipboard* pImpl = CMtaOleClipboard::s_theMtaOleClipboardInst;
+ OSL_ASSERT( nullptr != pImpl );
+
+ switch( uMsg )
+ {
+ case MSG_SETCLIPBOARD:
+ {
+ IDataObject* pIDataObject = reinterpret_cast< IDataObject* >( wParam );
+ CMtaOleClipboard::onSetClipboard( pIDataObject );
+
+ // in setClipboard we did acquire the
+ // interface pointer in order to prevent
+ // destruction of the object before the
+ // ole clipboard can acquire the interface
+ // now we release the interface so that
+ // our lostOwnership mechanism works
+ // remember: pIDataObject may be NULL
+ if ( pIDataObject )
+ pIDataObject->Release( );
+ }
+ break;
+
+ case MSG_GETCLIPBOARD:
+ {
+ MsgCtx* aMsgCtx = reinterpret_cast< MsgCtx* >( lParam );
+ OSL_ASSERT( aMsgCtx );
+
+ aMsgCtx->hr = CMtaOleClipboard::onGetClipboard( reinterpret_cast< LPSTREAM* >(wParam) );
+ aMsgCtx->aCondition.set( );
+ }
+ break;
+
+ case MSG_FLUSHCLIPBOARD:
+ {
+ MsgCtx* aMsgCtx = reinterpret_cast< MsgCtx* >( lParam );
+ OSL_ASSERT( aMsgCtx );
+
+ aMsgCtx->hr = CMtaOleClipboard::onFlushClipboard( );
+ aMsgCtx->aCondition.set( );
+ }
+ break;
+
+ case MSG_REGCLIPVIEWER:
+ {
+ MsgCtx* pMsgCtx = reinterpret_cast<MsgCtx*>(lParam);
+ SAL_WARN_IF(!pMsgCtx, "vcl.win.dtrans", "pMsgCtx is nullptr");
+
+ pImpl->onRegisterClipViewer(
+ reinterpret_cast<CMtaOleClipboard::LPFNC_CLIPVIEWER_CALLBACK_t>(wParam));
+ pMsgCtx->aCondition.set();
+ }
+ break;
+
+ case WM_CLIPBOARDUPDATE:
+ lResult = pImpl->onClipboardUpdate();
+ break;
+
+ case MSG_SHUTDOWN:
+ DestroyWindow( pImpl->m_hwndMtaOleReqWnd );
+ break;
+
+ // force the sta thread to end
+ case WM_DESTROY:
+ SetEvent(pImpl->m_hEvtWndDisposed); // stop waiting for conditions set by this wndproc
+ PostQuitMessage( 0 );
+ break;
+
+ default:
+ lResult = DefWindowProcW( hWnd, uMsg, wParam, lParam );
+ break;
+ }
+
+ return lResult;
+}
+
+void CMtaOleClipboard::createMtaOleReqWnd( )
+{
+ WNDCLASSEXW wcex;
+
+ SalData* pSalData = GetSalData();
+ OSL_ASSERT(nullptr != pSalData->mhInst);
+
+ ZeroMemory( &wcex, sizeof(wcex) );
+
+ wcex.cbSize = sizeof(wcex);
+ wcex.style = 0;
+ wcex.lpfnWndProc = CMtaOleClipboard::mtaOleReqWndProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = pSalData->mhInst;
+ wcex.hIcon = nullptr;
+ wcex.hCursor = nullptr;
+ wcex.hbrBackground = nullptr;
+ wcex.lpszMenuName = nullptr;
+ wcex.lpszClassName = g_szWndClsName;
+ wcex.hIconSm = nullptr;
+
+ m_MtaOleReqWndClassAtom = RegisterClassExW( &wcex );
+
+ if ( 0 != m_MtaOleReqWndClassAtom )
+ m_hwndMtaOleReqWnd = CreateWindowW(
+ g_szWndClsName, nullptr, 0, 0, 0, 0, 0, nullptr, nullptr, pSalData->mhInst, nullptr );
+}
+
+unsigned int CMtaOleClipboard::run( )
+{
+ HRESULT hr = OleInitialize( nullptr );
+ OSL_ASSERT( SUCCEEDED( hr ) );
+
+ createMtaOleReqWnd( );
+
+ unsigned int nRet = ~0U; // = error
+
+ if ( IsWindow( m_hwndMtaOleReqWnd ) )
+ {
+ if ( nullptr != m_hEvtThrdReady )
+ SetEvent( m_hEvtThrdReady );
+
+ nRet = 0;
+
+ // pumping messages
+ for (;;)
+ {
+ MSG msg;
+ int const bRet = GetMessageW(&msg, nullptr, 0, 0);
+ if (bRet == 0)
+ {
+ break;
+ }
+ if (-1 == bRet)
+ {
+ SAL_WARN("vcl.win.dtrans", "GetMessageW failed: " << WindowsErrorString(GetLastError()));
+ nRet = ~0U;
+ break;
+ }
+ DispatchMessageW(&msg);
+ }
+ }
+
+ OleUninitialize( );
+
+ return nRet;
+}
+
+DWORD WINAPI CMtaOleClipboard::oleThreadProc( _In_ LPVOID pParam )
+{
+ osl_setThreadName("CMtaOleClipboard::run()");
+
+ CMtaOleClipboard* pInst =
+ static_cast<CMtaOleClipboard*>( pParam );
+ OSL_ASSERT( nullptr != pInst );
+
+ return pInst->run( );
+}
+
+DWORD WINAPI CMtaOleClipboard::clipboardChangedNotifierThreadProc( _In_ LPVOID pParam )
+{
+ osl_setThreadName("CMtaOleClipboard::clipboardChangedNotifierThreadProc()");
+ CMtaOleClipboard* pInst = static_cast< CMtaOleClipboard* >( pParam );
+ OSL_ASSERT( nullptr != pInst );
+
+ sal::systools::CoInitializeGuard aGuard(COINIT_APARTMENTTHREADED, false,
+ sal::systools::CoInitializeGuard::WhenFailed::NoThrow);
+
+ // assuming we don't need a lock for
+ // a boolean variable like m_bRun...
+ while ( pInst->m_bRunClipboardNotifierThread )
+ {
+ // process window messages because of CoInitializeEx
+ MSG Msg;
+ while (PeekMessageW(&Msg, nullptr, 0, 0, PM_REMOVE))
+ DispatchMessageW(&Msg);
+
+ // wait for clipboard changed or terminate event
+ MsgWaitForMultipleObjects(2, pInst->m_hClipboardChangedNotifierEvents, false, INFINITE,
+ QS_ALLINPUT | QS_ALLPOSTMESSAGE);
+
+ ClearableMutexGuard aGuard2( pInst->m_ClipboardChangedEventCountMutex );
+
+ if ( pInst->m_ClipboardChangedEventCount > 0 )
+ {
+ pInst->m_ClipboardChangedEventCount--;
+ if ( 0 == pInst->m_ClipboardChangedEventCount )
+ ResetEvent( pInst->m_hClipboardChangedEvent );
+
+ aGuard2.clear( );
+
+ // nobody should touch m_pfncClipViewerCallback while we do
+ MutexGuard aClipViewerGuard( pInst->m_pfncClipViewerCallbackMutex );
+
+ // notify all clipboard listener
+ if ( pInst->m_pfncClipViewerCallback )
+ pInst->m_pfncClipViewerCallback( );
+ }
+ else
+ aGuard2.clear( );
+ }
+
+ return 0;
+}
+
+bool CMtaOleClipboard::WaitForThreadReady( ) const
+{
+ bool bRet = false;
+
+ if ( nullptr != m_hEvtThrdReady )
+ {
+ DWORD dwResult = WaitForSingleObject(
+ m_hEvtThrdReady, MAX_WAITTIME );
+ bRet = ( dwResult == WAIT_OBJECT_0 );
+ }
+
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/MtaOleClipb.hxx b/vcl/win/dtrans/MtaOleClipb.hxx
new file mode 100644
index 000000000..a76b85e3b
--- /dev/null
+++ b/vcl/win/dtrans/MtaOleClipb.hxx
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <osl/mutex.hxx>
+
+#include <objidl.h>
+
+// the Mta-Ole clipboard class is for internal use only!
+// only one instance of this class should be created, the
+// user has to ensure this!
+// the class is not thread-safe because it will be used
+// only from within the clipboard service and the methods
+// of the clipboard service are already synchronized
+
+class CMtaOleClipboard
+{
+public:
+ typedef void ( WINAPI *LPFNC_CLIPVIEWER_CALLBACK_t )( void );
+
+public:
+ CMtaOleClipboard( );
+ ~CMtaOleClipboard( );
+
+ // clipboard functions
+ HRESULT setClipboard( IDataObject* pIDataObject );
+ HRESULT getClipboard( IDataObject** ppIDataObject );
+ HRESULT flushClipboard( );
+
+ // register/unregister a clipboard viewer; there can only
+ // be one at a time; parameter NULL means unregister
+ // a clipboard viewer
+ // returns true on success else false; use GetLastError( ) in
+ // false case
+ bool registerClipViewer( LPFNC_CLIPVIEWER_CALLBACK_t pfncClipViewerCallback );
+
+private:
+ unsigned int run( );
+
+ // create a hidden window which serves as a request target; so we
+ // guarantee synchronization
+ void createMtaOleReqWnd( );
+
+ // message support
+ bool postMessage( UINT msg, WPARAM wParam = 0, LPARAM lParam = 0 );
+ LRESULT sendMessage( UINT msg, WPARAM wParam = 0, LPARAM lParam = 0 );
+
+ // message handler functions; remember these functions are called
+ // from a different thread context!
+
+ static HRESULT onSetClipboard( IDataObject* pIDataObject );
+ static HRESULT onGetClipboard( LPSTREAM* ppStream );
+ static HRESULT onFlushClipboard( );
+ bool onRegisterClipViewer( LPFNC_CLIPVIEWER_CALLBACK_t pfncClipViewerCallback );
+
+ // win32 clipboard listener support
+ LRESULT onClipboardUpdate();
+
+ static LRESULT CALLBACK mtaOleReqWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
+ static DWORD WINAPI oleThreadProc( _In_ LPVOID pParam );
+
+ static DWORD WINAPI clipboardChangedNotifierThreadProc( _In_ LPVOID pParam );
+
+ bool WaitForThreadReady( ) const;
+
+private:
+ HANDLE m_hOleThread;
+ DWORD m_uOleThreadId;
+ HANDLE m_hEvtThrdReady;
+ HWND m_hwndMtaOleReqWnd;
+ HANDLE m_hEvtWndDisposed;
+ ATOM m_MtaOleReqWndClassAtom;
+ LPFNC_CLIPVIEWER_CALLBACK_t m_pfncClipViewerCallback;
+ bool m_bInRegisterClipViewer;
+
+ bool m_bRunClipboardNotifierThread;
+ HANDLE m_hClipboardChangedNotifierThread;
+ HANDLE m_hClipboardChangedNotifierEvents[2];
+ HANDLE& m_hClipboardChangedEvent;
+ HANDLE& m_hTerminateClipboardChangedNotifierEvent;
+ osl::Mutex m_ClipboardChangedEventCountMutex;
+ sal_Int32 m_ClipboardChangedEventCount;
+
+ osl::Mutex m_pfncClipViewerCallbackMutex;
+
+ static CMtaOleClipboard* s_theMtaOleClipboardInst;
+
+ CMtaOleClipboard( const CMtaOleClipboard& ) = delete;
+ CMtaOleClipboard& operator=( const CMtaOleClipboard& ) = delete;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/TxtCnvtHlp.cxx b/vcl/win/dtrans/TxtCnvtHlp.cxx
new file mode 100644
index 000000000..d7ab386fc
--- /dev/null
+++ b/vcl/win/dtrans/TxtCnvtHlp.cxx
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <osl/diagnose.h>
+
+#include "TxtCnvtHlp.hxx"
+#include "DTransHelper.hxx"
+#include "ImplHelper.hxx"
+
+using namespace ::com::sun::star::datatransfer;
+using namespace ::com::sun::star::uno;
+
+// assuming a '\0' terminated string if no length specified
+
+static int CalcBuffSizeForTextConversion( UINT code_page, LPCSTR lpMultiByteString, int nLen = -1 )
+{
+ return ( MultiByteToWideChar( code_page,
+ 0,
+ lpMultiByteString,
+ nLen,
+ nullptr,
+ 0 ) * sizeof( sal_Unicode ) );
+}
+
+// assuming a '\0' terminated string if no length specified
+
+static int CalcBuffSizeForTextConversion( UINT code_page, LPCWSTR lpWideCharString, int nLen = -1 )
+{
+ return WideCharToMultiByte( code_page,
+ 0,
+ lpWideCharString,
+ nLen,
+ nullptr,
+ 0,
+ nullptr,
+ nullptr );
+}
+
+// converts text in one code page into unicode text
+// automatically calculates the necessary buffer size and allocates
+// the buffer
+
+int MultiByteToWideCharEx( UINT cp_src,
+ LPCSTR lpMultiByteString,
+ int lenStr,
+ CStgTransferHelper& refDTransHelper,
+ BOOL bEnsureTrailingZero )
+{
+ OSL_ASSERT( IsValidCodePage( cp_src ) );
+ OSL_ASSERT( nullptr != lpMultiByteString );
+
+ // calculate the required buff size
+ int reqSize = CalcBuffSizeForTextConversion( cp_src, lpMultiByteString, lenStr );
+
+ if ( bEnsureTrailingZero )
+ reqSize += sizeof( sal_Unicode );
+
+ // initialize the data-transfer helper
+ refDTransHelper.init( reqSize );
+
+ // setup a global memory pointer
+ CRawHGlobalPtr ptrHGlob( refDTransHelper );
+
+ // do the conversion and return
+ return MultiByteToWideChar( cp_src,
+ 0,
+ lpMultiByteString,
+ lenStr,
+ static_cast< LPWSTR >( ptrHGlob.GetMemPtr( ) ),
+ ptrHGlob.MemSize( ) );
+}
+
+// converts unicode text into text of the specified code page
+// automatically calculates the necessary buffer size and allocates
+// the buffer
+
+int WideCharToMultiByteEx( UINT cp_dest,
+ LPCWSTR lpWideCharString,
+ int lenStr,
+ CStgTransferHelper& refDTransHelper,
+ BOOL bEnsureTrailingZero )
+{
+ OSL_ASSERT( IsValidCodePage( cp_dest ) );
+ OSL_ASSERT( nullptr != lpWideCharString );
+
+ // calculate the required buff size
+ int reqSize = CalcBuffSizeForTextConversion( cp_dest, lpWideCharString, lenStr );
+
+ if ( bEnsureTrailingZero )
+ reqSize += sizeof( sal_Int8 );
+
+ // initialize the data-transfer helper
+ refDTransHelper.init( reqSize );
+
+ // setup a global memory pointer
+ CRawHGlobalPtr ptrHGlob( refDTransHelper );
+
+ // do the conversion and return
+ return WideCharToMultiByte( cp_dest,
+ 0,
+ lpWideCharString,
+ lenStr,
+ static_cast< LPSTR >( ptrHGlob.GetMemPtr( ) ),
+ ptrHGlob.MemSize( ),
+ nullptr,
+ nullptr );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/TxtCnvtHlp.hxx b/vcl/win/dtrans/TxtCnvtHlp.hxx
new file mode 100644
index 000000000..529487933
--- /dev/null
+++ b/vcl/win/dtrans/TxtCnvtHlp.hxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/datatransfer/DataFlavor.hpp>
+
+#include "DTransHelper.hxx"
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+int MultiByteToWideCharEx( UINT cp_src,
+ LPCSTR lpMultiByteString,
+ int lenStr,
+ CStgTransferHelper& refDTransHelper,
+ BOOL bEnsureTrailingZero = TRUE );
+
+int WideCharToMultiByteEx( UINT cp_dest,
+ LPCWSTR lpWideCharString,
+ int lenStr,
+ CStgTransferHelper& refDTransHelper,
+ BOOL bEnsureTrailingZero = TRUE );
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/WinClip.hxx b/vcl/win/dtrans/WinClip.hxx
new file mode 100644
index 000000000..f90d5eea0
--- /dev/null
+++ b/vcl/win/dtrans/WinClip.hxx
@@ -0,0 +1,26 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+
+const sal_Int32 CF_INVALID = 0;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/WinClipboard.cxx b/vcl/win/dtrans/WinClipboard.cxx
new file mode 100644
index 000000000..2c33fe72e
--- /dev/null
+++ b/vcl/win/dtrans/WinClipboard.cxx
@@ -0,0 +1,386 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+#include <com/sun/star/datatransfer/clipboard/ClipboardEvent.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <vcl/svapp.hxx>
+#include <svdata.hxx>
+#include <salinst.hxx>
+
+#include <com/sun/star/datatransfer/clipboard/RenderingCapabilities.hpp>
+#include "XNotifyingDataObject.hxx"
+
+#include <systools/win32/comtools.hxx>
+#include "DtObjFactory.hxx"
+#include "APNDataObject.hxx"
+#include "DOTransferable.hxx"
+#include "WinClipboard.hxx"
+
+#if !defined WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <ole2.h>
+#include <objidl.h>
+
+using namespace com::sun::star;
+
+namespace
+{
+CWinClipboard* s_pCWinClipbImpl = nullptr;
+osl::Mutex s_aClipboardSingletonMutex;
+}
+
+/*XEventListener,*/
+CWinClipboard::CWinClipboard(const uno::Reference<uno::XComponentContext>& rxContext,
+ const OUString& aClipboardName)
+ : WeakComponentImplHelper<XSystemClipboard, XFlushableClipboard, XServiceInfo>(m_aMutex)
+ , m_xContext(rxContext)
+ , m_itsName(aClipboardName)
+ , m_pCurrentClipContent(nullptr)
+{
+ // necessary to reassociate from
+ // the static callback function
+ {
+ osl::MutexGuard aGuard(s_aClipboardSingletonMutex);
+ s_pCWinClipbImpl = this;
+ }
+
+ registerClipboardViewer();
+}
+
+CWinClipboard::~CWinClipboard()
+{
+ {
+ osl::MutexGuard aGuard(s_aClipboardSingletonMutex);
+ s_pCWinClipbImpl = nullptr;
+ }
+
+ unregisterClipboardViewer();
+}
+
+// XClipboard
+
+// to avoid unnecessary traffic we check first if there is a clipboard
+// content which was set via setContent, in this case we don't need
+// to query the content from the clipboard, create a new wrapper object
+// and so on, we simply return the original XTransferable instead of our
+// DOTransferable
+
+uno::Reference<datatransfer::XTransferable> SAL_CALL CWinClipboard::getContents()
+{
+ osl::MutexGuard aGuard(m_aContentMutex);
+
+ if (rBHelper.bDisposed)
+ throw lang::DisposedException("object is already disposed",
+ static_cast<XClipboardEx*>(this));
+
+ // use the shortcut or create a transferable from
+ // system clipboard
+ {
+ osl::MutexGuard aGuard2(m_aContentCacheMutex);
+
+ if (nullptr != m_pCurrentClipContent)
+ return m_pCurrentClipContent->m_XTransferable;
+
+ // Content cached?
+ if (m_foreignContent.is())
+ return m_foreignContent;
+
+ // release the mutex, so that the variable may be
+ // changed by other threads
+ }
+
+ uno::Reference<datatransfer::XTransferable> rClipContent;
+
+ // get the current format list from clipboard
+ if (UINT nFormats; !GetUpdatedClipboardFormats(nullptr, 0, &nFormats)
+ && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+ {
+ std::vector<UINT> aUINTFormats(nFormats);
+ if (GetUpdatedClipboardFormats(aUINTFormats.data(), nFormats, &nFormats))
+ {
+ std::vector<sal_uInt32> aFormats(aUINTFormats.begin(), aUINTFormats.end());
+ rClipContent = new CDOTransferable(m_xContext, this, aFormats);
+
+ osl::MutexGuard aGuard2(m_aContentCacheMutex);
+ m_foreignContent = rClipContent;
+ }
+ }
+
+ return rClipContent;
+}
+
+IDataObjectPtr CWinClipboard::getIDataObject()
+{
+ osl::MutexGuard aGuard(m_aContentMutex);
+
+ if (rBHelper.bDisposed)
+ throw lang::DisposedException("object is already disposed",
+ static_cast<XClipboardEx*>(this));
+
+ // get the current dataobject from clipboard
+ IDataObjectPtr pIDataObject;
+ HRESULT hr = m_MtaOleClipboard.getClipboard(&pIDataObject);
+
+ if (SUCCEEDED(hr))
+ {
+ // create an apartment neutral dataobject and initialize it with a
+ // com smart pointer to the IDataObject from clipboard
+ pIDataObject = new CAPNDataObject(pIDataObject);
+ }
+
+ return pIDataObject;
+}
+
+void SAL_CALL CWinClipboard::setContents(
+ const uno::Reference<datatransfer::XTransferable>& xTransferable,
+ const uno::Reference<datatransfer::clipboard::XClipboardOwner>& xClipboardOwner)
+{
+ osl::MutexGuard aGuard(m_aContentMutex);
+
+ if (rBHelper.bDisposed)
+ throw lang::DisposedException("object is already disposed",
+ static_cast<XClipboardEx*>(this));
+
+ IDataObjectPtr pIDataObj;
+
+ if (xTransferable.is())
+ {
+ {
+ osl::MutexGuard aGuard2(m_aContentCacheMutex);
+
+ m_foreignContent.clear();
+
+ m_pCurrentClipContent = new CXNotifyingDataObject(
+ CDTransObjFactory::createDataObjFromTransferable(m_xContext, xTransferable),
+ xTransferable, xClipboardOwner, this);
+ }
+
+ pIDataObj = IDataObjectPtr(m_pCurrentClipContent);
+ }
+
+ m_MtaOleClipboard.setClipboard(pIDataObj.get());
+}
+
+OUString SAL_CALL CWinClipboard::getName()
+{
+ if (rBHelper.bDisposed)
+ throw lang::DisposedException("object is already disposed",
+ static_cast<XClipboardEx*>(this));
+
+ return m_itsName;
+}
+
+// XFlushableClipboard
+
+void SAL_CALL CWinClipboard::flushClipboard()
+{
+ osl::MutexGuard aGuard(m_aContentMutex);
+
+ if (rBHelper.bDisposed)
+ throw lang::DisposedException("object is already disposed",
+ static_cast<XClipboardEx*>(this));
+
+ // actually it should be ClearableMutexGuard aGuard( m_aContentCacheMutex );
+ // but it does not work since FlushClipboard does a callback and frees DataObject
+ // which results in a deadlock in onReleaseDataObject.
+ // FlushClipboard had to be synchron in order to prevent shutdown until all
+ // clipboard-formats are rendered.
+ // The request is needed to prevent flushing if we are not clipboard owner (it is
+ // not known what happens if we flush but aren't clipboard owner).
+ // It may be possible to move the request to the clipboard STA thread by saving the
+ // DataObject and call OleIsCurrentClipboard before flushing.
+
+ if (nullptr != m_pCurrentClipContent)
+ m_MtaOleClipboard.flushClipboard();
+}
+
+// XClipboardEx
+
+sal_Int8 SAL_CALL CWinClipboard::getRenderingCapabilities()
+{
+ if (rBHelper.bDisposed)
+ throw lang::DisposedException("object is already disposed",
+ static_cast<XClipboardEx*>(this));
+
+ using namespace datatransfer::clipboard::RenderingCapabilities;
+ return (Delayed | Persistent);
+}
+
+// XClipboardNotifier
+
+void SAL_CALL CWinClipboard::addClipboardListener(
+ const uno::Reference<datatransfer::clipboard::XClipboardListener>& listener)
+{
+ if (rBHelper.bDisposed)
+ throw lang::DisposedException("object is already disposed",
+ static_cast<XClipboardEx*>(this));
+
+ // check input parameter
+ if (!listener.is())
+ throw lang::IllegalArgumentException("empty reference", static_cast<XClipboardEx*>(this),
+ 1);
+
+ rBHelper.aLC.addInterface(cppu::UnoType<decltype(listener)>::get(), listener);
+}
+
+void SAL_CALL CWinClipboard::removeClipboardListener(
+ const uno::Reference<datatransfer::clipboard::XClipboardListener>& listener)
+{
+ if (rBHelper.bDisposed)
+ throw lang::DisposedException("object is already disposed",
+ static_cast<XClipboardEx*>(this));
+
+ // check input parameter
+ if (!listener.is())
+ throw lang::IllegalArgumentException("empty reference", static_cast<XClipboardEx*>(this),
+ 1);
+
+ rBHelper.aLC.removeInterface(cppu::UnoType<decltype(listener)>::get(), listener);
+}
+
+void CWinClipboard::notifyAllClipboardListener()
+{
+ if (rBHelper.bDisposed)
+ return;
+
+ osl::ClearableMutexGuard aGuard(rBHelper.rMutex);
+ if (rBHelper.bDisposed)
+ return;
+ aGuard.clear();
+
+ cppu::OInterfaceContainerHelper* pICHelper = rBHelper.aLC.getContainer(
+ cppu::UnoType<datatransfer::clipboard::XClipboardListener>::get());
+ if (!pICHelper)
+ return;
+
+ try
+ {
+ cppu::OInterfaceIteratorHelper iter(*pICHelper);
+ uno::Reference<datatransfer::XTransferable> rXTransf(getContents());
+ datatransfer::clipboard::ClipboardEvent aClipbEvent(static_cast<XClipboard*>(this),
+ rXTransf);
+
+ while (iter.hasMoreElements())
+ {
+ try
+ {
+ uno::Reference<datatransfer::clipboard::XClipboardListener> xCBListener(
+ iter.next(), uno::UNO_QUERY);
+ if (xCBListener.is())
+ xCBListener->changedContents(aClipbEvent);
+ }
+ catch (uno::RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION("vcl", "");
+ }
+ }
+ }
+ catch (const lang::DisposedException&)
+ {
+ OSL_FAIL("Service Manager disposed");
+
+ // no further clipboard changed notifications
+ unregisterClipboardViewer();
+ }
+}
+
+// XServiceInfo
+
+OUString SAL_CALL CWinClipboard::getImplementationName()
+{
+ return "com.sun.star.datatransfer.clipboard.ClipboardW32";
+}
+
+sal_Bool SAL_CALL CWinClipboard::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL CWinClipboard::getSupportedServiceNames()
+{
+ return { "com.sun.star.datatransfer.clipboard.SystemClipboard" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+dtrans_CWinClipboard_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const& args)
+{
+ // We run unit tests in parallel, which is a problem when touching a shared resource
+ // like the system clipboard, so rather use the dummy GenericClipboard.
+ static const bool bRunningUnitTest = getenv("LO_TESTNAME");
+
+ if (bRunningUnitTest)
+ {
+ SolarMutexGuard aGuard;
+ auto xClipboard = ImplGetSVData()->mpDefInst->CreateClipboard(args);
+ if (xClipboard.is())
+ xClipboard->acquire();
+ return xClipboard.get();
+ }
+ else
+ {
+ return cppu::acquire(new CWinClipboard(context, ""));
+ }
+}
+
+void CWinClipboard::onReleaseDataObject(CXNotifyingDataObject* theCaller)
+{
+ OSL_ASSERT(nullptr != theCaller);
+
+ if (theCaller)
+ theCaller->lostOwnership();
+
+ // if the current caller is the one we currently hold, then set it to NULL
+ // because an external source must be the clipboardowner now
+ osl::MutexGuard aGuard(m_aContentCacheMutex);
+
+ if (m_pCurrentClipContent == theCaller)
+ m_pCurrentClipContent = nullptr;
+}
+
+void CWinClipboard::registerClipboardViewer()
+{
+ m_MtaOleClipboard.registerClipViewer(CWinClipboard::onClipboardContentChanged);
+}
+
+void CWinClipboard::unregisterClipboardViewer() { m_MtaOleClipboard.registerClipViewer(nullptr); }
+
+void WINAPI CWinClipboard::onClipboardContentChanged()
+{
+ osl::MutexGuard aGuard(s_aClipboardSingletonMutex);
+
+ // reassociation to instance through static member
+ if (nullptr != s_pCWinClipbImpl)
+ {
+ s_pCWinClipbImpl->m_foreignContent.clear();
+ s_pCWinClipbImpl->notifyAllClipboardListener();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/WinClipboard.hxx b/vcl/win/dtrans/WinClipboard.hxx
new file mode 100644
index 000000000..ac86d0d54
--- /dev/null
+++ b/vcl/win/dtrans/WinClipboard.hxx
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardEx.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardOwner.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardListener.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp>
+#include <com/sun/star/datatransfer/clipboard/XSystemClipboard.hpp>
+#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <osl/conditn.hxx>
+#include <systools/win32/comtools.hxx>
+
+#include "MtaOleClipb.hxx"
+#include "XNotifyingDataObject.hxx"
+
+// implements the XClipboard[Ex] ... interfaces
+// for the clipboard viewer mechanism we need a static callback function
+// and a static member to reassociate from this static function to the
+// class instance
+// watch out: we are using only one static member variable and not a list
+// because we assume to be instantiated only once
+// this will be assured by a OneInstanceFactory of the service and not
+// by this class!
+
+class CWinClipboard final
+ : public cppu::BaseMutex,
+ public cppu::WeakComponentImplHelper<css::datatransfer::clipboard::XSystemClipboard,
+ css::datatransfer::clipboard::XFlushableClipboard,
+ css::lang::XServiceInfo>
+{
+ friend STDMETHODIMP_(ULONG) CXNotifyingDataObject::Release();
+
+ css::uno::Reference<css::uno::XComponentContext> m_xContext;
+ const OUString m_itsName;
+ CMtaOleClipboard m_MtaOleClipboard;
+ CXNotifyingDataObject* m_pCurrentClipContent;
+ com::sun::star::uno::Reference<com::sun::star::datatransfer::XTransferable> m_foreignContent;
+ osl::Mutex m_aContentMutex;
+ osl::Mutex m_aContentCacheMutex;
+
+ void notifyAllClipboardListener();
+ void onReleaseDataObject(CXNotifyingDataObject* theCaller);
+
+ void registerClipboardViewer();
+ void unregisterClipboardViewer();
+
+ static void WINAPI onClipboardContentChanged();
+
+public:
+ CWinClipboard(const css::uno::Reference<css::uno::XComponentContext>& rxContext,
+ const OUString& aClipboardName);
+ virtual ~CWinClipboard() override;
+
+ // XClipboard
+ virtual css::uno::Reference<css::datatransfer::XTransferable> SAL_CALL getContents() override;
+ virtual void SAL_CALL setContents(
+ const css::uno::Reference<css::datatransfer::XTransferable>& xTransferable,
+ const css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner>& xClipboardOwner)
+ override;
+ virtual OUString SAL_CALL getName() override;
+
+ // XFlushableClipboard
+ virtual void SAL_CALL flushClipboard() override;
+
+ // XClipboardEx
+ virtual sal_Int8 SAL_CALL getRenderingCapabilities() override;
+
+ // XClipboardNotifier
+ virtual void SAL_CALL addClipboardListener(
+ const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener)
+ override;
+ virtual void SAL_CALL removeClipboardListener(
+ const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener)
+ override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ IDataObjectPtr getIDataObject();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/XNotifyingDataObject.cxx b/vcl/win/dtrans/XNotifyingDataObject.cxx
new file mode 100644
index 000000000..e791f5cd9
--- /dev/null
+++ b/vcl/win/dtrans/XNotifyingDataObject.cxx
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+#include "XNotifyingDataObject.hxx"
+#include "WinClipboard.hxx"
+
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::datatransfer::clipboard;
+using com::sun::star::uno::RuntimeException;
+using com::sun::star::uno::Reference;
+
+CXNotifyingDataObject::CXNotifyingDataObject(
+ const IDataObjectPtr& aIDataObject,
+ const Reference< XTransferable >& aXTransferable,
+ const Reference< XClipboardOwner >& aXClipOwner,
+ CWinClipboard* const theWinClipoard) :
+ m_nRefCnt( 0 ),
+ m_aIDataObject( aIDataObject ),
+ m_XTransferable( aXTransferable ),
+ m_XClipboardOwner( aXClipOwner ),
+ m_pWinClipImpl( theWinClipoard )
+{
+}
+
+STDMETHODIMP CXNotifyingDataObject::QueryInterface( REFIID iid, void** ppvObject )
+{
+ if ( nullptr == ppvObject )
+ return E_INVALIDARG;
+
+ HRESULT hr = E_NOINTERFACE;
+
+ *ppvObject = nullptr;
+ if ( ( __uuidof( IUnknown ) == iid ) ||
+ ( __uuidof( IDataObject ) == iid ) )
+ {
+ *ppvObject = static_cast< IUnknown* >( this );
+ static_cast<LPUNKNOWN>(*ppvObject)->AddRef( );
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+STDMETHODIMP_(ULONG) CXNotifyingDataObject::AddRef( )
+{
+ return static_cast< ULONG >( InterlockedIncrement( &m_nRefCnt ) );
+}
+
+STDMETHODIMP_(ULONG) CXNotifyingDataObject::Release( )
+{
+ ULONG nRefCnt =
+ static_cast< ULONG >( InterlockedDecrement( &m_nRefCnt ) );
+
+ if ( 0 == nRefCnt )
+ {
+ if ( m_pWinClipImpl )
+ m_pWinClipImpl->onReleaseDataObject( this );
+
+ delete this;
+ }
+
+ return nRefCnt;
+}
+
+STDMETHODIMP CXNotifyingDataObject::GetData( FORMATETC * pFormatetc, STGMEDIUM * pmedium )
+{
+ return m_aIDataObject->GetData(pFormatetc, pmedium);
+}
+
+STDMETHODIMP CXNotifyingDataObject::EnumFormatEtc(
+ DWORD dwDirection, IEnumFORMATETC** ppenumFormatetc )
+{
+ return m_aIDataObject->EnumFormatEtc(dwDirection, ppenumFormatetc);
+}
+
+STDMETHODIMP CXNotifyingDataObject::QueryGetData( FORMATETC * pFormatetc )
+{
+ return m_aIDataObject->QueryGetData(pFormatetc);
+}
+
+STDMETHODIMP CXNotifyingDataObject::GetDataHere( FORMATETC * lpFetc, STGMEDIUM * lpStgMedium )
+{
+ return m_aIDataObject->GetDataHere(lpFetc, lpStgMedium);
+}
+
+STDMETHODIMP CXNotifyingDataObject::GetCanonicalFormatEtc( FORMATETC * lpFetc, FORMATETC * lpCanonicalFetc )
+{
+ return m_aIDataObject->GetCanonicalFormatEtc(lpFetc, lpCanonicalFetc);
+}
+
+STDMETHODIMP CXNotifyingDataObject::SetData( FORMATETC * lpFetc, STGMEDIUM * lpStgMedium, BOOL bRelease )
+{
+ return m_aIDataObject->SetData( lpFetc, lpStgMedium, bRelease );
+}
+
+STDMETHODIMP CXNotifyingDataObject::DAdvise(
+ FORMATETC * lpFetc, DWORD advf, IAdviseSink * lpAdvSink, DWORD* pdwConnection )
+{
+ return m_aIDataObject->DAdvise( lpFetc, advf, lpAdvSink, pdwConnection );
+}
+
+STDMETHODIMP CXNotifyingDataObject::DUnadvise( DWORD dwConnection )
+{
+ return m_aIDataObject->DUnadvise( dwConnection );
+}
+
+STDMETHODIMP CXNotifyingDataObject::EnumDAdvise( IEnumSTATDATA ** ppenumAdvise )
+{
+ return m_aIDataObject->EnumDAdvise( ppenumAdvise );
+}
+
+CXNotifyingDataObject::operator IDataObject*( )
+{
+ return static_cast< IDataObject* >( this );
+}
+
+void CXNotifyingDataObject::lostOwnership( )
+{
+ try
+ {
+ if (m_XClipboardOwner.is())
+ m_XClipboardOwner->lostOwnership(
+ static_cast<XClipboardEx*>(m_pWinClipImpl), m_XTransferable);
+ }
+ catch(RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION( "vcl", "" );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/XNotifyingDataObject.hxx b/vcl/win/dtrans/XNotifyingDataObject.hxx
new file mode 100644
index 000000000..408413a5d
--- /dev/null
+++ b/vcl/win/dtrans/XNotifyingDataObject.hxx
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardOwner.hpp>
+
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <objidl.h>
+
+#include <systools/win32/comtools.hxx>
+
+/*--------------------------------------------------------------------------
+ To implement the lostOwnership mechanism cleanly we need this wrapper
+ object
+----------------------------------------------------------------------------*/
+
+// forward
+class CWinClipboard;
+
+class CXNotifyingDataObject final : public IDataObject
+{
+public:
+ CXNotifyingDataObject(
+ const IDataObjectPtr& aIDataObject,
+ const css::uno::Reference< css::datatransfer::XTransferable >& aXTransferable,
+ const css::uno::Reference< css::datatransfer::clipboard::XClipboardOwner >& aXClipOwner,
+ CWinClipboard* const theWinClipoard);
+
+ virtual ~CXNotifyingDataObject() {}
+
+ // ole interface implementation
+
+ //IUnknown interface methods
+ STDMETHODIMP QueryInterface(REFIID iid, void** ppvObject) override;
+ STDMETHODIMP_( ULONG ) AddRef( ) override;
+ STDMETHODIMP_( ULONG ) Release( ) override;
+
+ // IDataObject interface methods
+ STDMETHODIMP GetData( FORMATETC * pFormatetc, STGMEDIUM * pmedium ) override;
+ STDMETHODIMP GetDataHere( FORMATETC * pFormatetc, STGMEDIUM * pmedium ) override;
+ STDMETHODIMP QueryGetData( FORMATETC * pFormatetc ) override;
+ STDMETHODIMP GetCanonicalFormatEtc( FORMATETC * pFormatectIn, FORMATETC * pFormatetcOut ) override;
+ STDMETHODIMP SetData( FORMATETC * pFormatetc, STGMEDIUM * pmedium, BOOL fRelease ) override;
+ STDMETHODIMP EnumFormatEtc( DWORD dwDirection, IEnumFORMATETC** ppenumFormatetc ) override;
+ STDMETHODIMP DAdvise( FORMATETC * pFormatetc, DWORD advf, IAdviseSink * pAdvSink, DWORD* pdwConnection ) override;
+ STDMETHODIMP DUnadvise( DWORD dwConnection ) override;
+ STDMETHODIMP EnumDAdvise( IEnumSTATDATA** ppenumAdvise ) override;
+
+ operator IDataObject*( );
+
+private:
+ void lostOwnership( );
+
+ sal_Int32 m_nRefCnt;
+ IDataObjectPtr m_aIDataObject;
+ const css::uno::Reference< css::datatransfer::XTransferable > m_XTransferable;
+ const css::uno::Reference< css::datatransfer::clipboard::XClipboardOwner > m_XClipboardOwner;
+ CWinClipboard* const m_pWinClipImpl;
+
+ friend class CWinClipboard;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/XTDataObject.cxx b/vcl/win/dtrans/XTDataObject.cxx
new file mode 100644
index 000000000..adbed6bbe
--- /dev/null
+++ b/vcl/win/dtrans/XTDataObject.cxx
@@ -0,0 +1,757 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <osl/diagnose.h>
+#include <o3tl/char16_t2wchar_t.hxx>
+#include <o3tl/safeint.hxx>
+
+#include "XTDataObject.hxx"
+#include <com/sun/star/datatransfer/DataFlavor.hpp>
+#include "ImplHelper.hxx"
+#include "DTransHelper.hxx"
+#include "TxtCnvtHlp.hxx"
+#include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardEx.hpp>
+#include <com/sun/star/awt/AsyncCallback.hpp>
+#include <com/sun/star/awt/XCallback.hpp>
+#include "FmtFilter.hxx"
+#include <cppuhelper/implbase.hxx>
+
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <shlobj.h>
+
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::datatransfer::clipboard;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+
+namespace {
+
+void setupStgMedium( const FORMATETC& fetc,
+ CStgTransferHelper& stgTransHlp,
+ STGMEDIUM& stgmedium )
+{
+ stgmedium.pUnkForRelease = nullptr;
+
+ if ( fetc.cfFormat == CF_METAFILEPICT )
+ {
+ stgmedium.tymed = TYMED_MFPICT;
+ stgmedium.hMetaFilePict = static_cast< HMETAFILEPICT >( stgTransHlp.getHGlobal( ) );
+ }
+ else if ( fetc.cfFormat == CF_ENHMETAFILE )
+ {
+ stgmedium.tymed = TYMED_ENHMF;
+ stgmedium.hEnhMetaFile = static_cast< HENHMETAFILE >( stgTransHlp.getHGlobal( ) );
+ }
+ else if ( fetc.tymed & TYMED_HGLOBAL )
+ {
+ stgmedium.tymed = TYMED_HGLOBAL;
+ stgmedium.hGlobal = stgTransHlp.getHGlobal( );
+ }
+ else if ( fetc.tymed & TYMED_ISTREAM )
+ {
+ stgmedium.tymed = TYMED_ISTREAM;
+ stgTransHlp.getIStream( &stgmedium.pstm );
+ }
+ else
+ OSL_ASSERT( false );
+}
+
+/**
+ We need to destroy XTransferable in the main thread to avoid dead lock
+ when locking in the clipboard thread. So we transfer the ownership of the
+ XTransferable reference to this object and release it when the callback
+ is executed in main thread.
+*/
+class AsyncDereference : public cppu::WeakImplHelper<css::awt::XCallback>
+{
+ Reference<XTransferable> maTransferable;
+
+public:
+ AsyncDereference(css::uno::Reference<css::datatransfer::XTransferable> const & rTransferable)
+ : maTransferable(rTransferable)
+ {}
+
+ virtual void SAL_CALL notify(css::uno::Any const &) override
+ {
+ maTransferable.set(nullptr);
+ }
+};
+
+// a helper class that will be thrown by the function validateFormatEtc
+
+class CInvalidFormatEtcException
+{
+public:
+ HRESULT m_hr;
+ explicit CInvalidFormatEtcException( HRESULT hr ) : m_hr( hr ) {};
+};
+
+void validateFormatEtc( LPFORMATETC lpFormatEtc )
+{
+ OSL_ASSERT( lpFormatEtc );
+
+ if ( lpFormatEtc->lindex != -1 )
+ throw CInvalidFormatEtcException( DV_E_LINDEX );
+
+ if ( !(lpFormatEtc->dwAspect & DVASPECT_CONTENT) &&
+ !(lpFormatEtc->dwAspect & DVASPECT_SHORTNAME) )
+ throw CInvalidFormatEtcException( DV_E_DVASPECT );
+
+ if ( !(lpFormatEtc->tymed & TYMED_HGLOBAL) &&
+ !(lpFormatEtc->tymed & TYMED_ISTREAM) &&
+ !(lpFormatEtc->tymed & TYMED_MFPICT) &&
+ !(lpFormatEtc->tymed & TYMED_ENHMF) )
+ throw CInvalidFormatEtcException( DV_E_TYMED );
+
+ if ( lpFormatEtc->cfFormat == CF_METAFILEPICT &&
+ !(lpFormatEtc->tymed & TYMED_MFPICT) )
+ throw CInvalidFormatEtcException( DV_E_TYMED );
+
+ if ( lpFormatEtc->cfFormat == CF_ENHMETAFILE &&
+ !(lpFormatEtc->tymed & TYMED_ENHMF) )
+ throw CInvalidFormatEtcException( DV_E_TYMED );
+}
+
+void invalidateStgMedium( STGMEDIUM& stgmedium )
+{
+ stgmedium.tymed = TYMED_NULL;
+}
+
+HRESULT translateStgExceptionCode( HRESULT hr )
+{
+ HRESULT hrTransl;
+
+ switch( hr )
+ {
+ case STG_E_MEDIUMFULL:
+ hrTransl = hr;
+ break;
+
+ default:
+ hrTransl = E_UNEXPECTED;
+ break;
+ }
+
+ return hrTransl;
+}
+
+// inline
+void renderDataAndSetupStgMedium(
+ const sal_Int8* lpStorage, const FORMATETC& fetc, sal_uInt32 nInitStgSize,
+ sal_uInt32 nBytesToTransfer, STGMEDIUM& stgmedium )
+{
+ OSL_PRECOND( !nInitStgSize || (nInitStgSize >= nBytesToTransfer),
+ "Memory size less than number of bytes to transfer" );
+
+ CStgTransferHelper stgTransfHelper( AUTO_INIT );
+
+ // setup storage size
+ if ( nInitStgSize > 0 )
+ stgTransfHelper.init( nInitStgSize );
+
+#if OSL_DEBUG_LEVEL > 0
+ sal_uInt32 nBytesWritten = 0;
+ stgTransfHelper.write( lpStorage, nBytesToTransfer, &nBytesWritten );
+ OSL_ASSERT( nBytesWritten == nBytesToTransfer );
+#else
+ stgTransfHelper.write( lpStorage, nBytesToTransfer );
+#endif
+
+ setupStgMedium( fetc, stgTransfHelper, stgmedium );
+}
+
+}
+
+CXTDataObject::CXTDataObject( const Reference< XComponentContext >& rxContext,
+ const Reference< XTransferable >& aXTransferable )
+ : m_nRefCnt( 0 )
+ , m_XTransferable( aXTransferable )
+ , m_XComponentContext( rxContext )
+ , m_bFormatEtcContainerInitialized( false )
+ , m_DataFormatTranslator( rxContext )
+ , m_FormatRegistrar( rxContext, m_DataFormatTranslator )
+{
+}
+
+CXTDataObject::~CXTDataObject()
+{
+ css::awt::AsyncCallback::create(m_XComponentContext)->addCallback(
+ new AsyncDereference(m_XTransferable),
+ css::uno::Any());
+}
+
+// IUnknown->QueryInterface
+
+STDMETHODIMP CXTDataObject::QueryInterface( REFIID iid, void** ppvObject )
+{
+ if ( nullptr == ppvObject )
+ return E_INVALIDARG;
+
+ HRESULT hr = E_NOINTERFACE;
+
+ *ppvObject = nullptr;
+ if ( ( __uuidof( IUnknown ) == iid ) ||
+ ( __uuidof( IDataObject ) == iid ) )
+ {
+ *ppvObject = static_cast< IUnknown* >( this );
+ static_cast<LPUNKNOWN>(*ppvObject)->AddRef( );
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+// IUnknown->AddRef
+
+STDMETHODIMP_(ULONG) CXTDataObject::AddRef( )
+{
+ return static_cast< ULONG >( InterlockedIncrement( &m_nRefCnt ) );
+}
+
+// IUnknown->Release
+
+STDMETHODIMP_(ULONG) CXTDataObject::Release( )
+{
+ ULONG nRefCnt =
+ static_cast< ULONG >( InterlockedDecrement( &m_nRefCnt ) );
+
+ if ( 0 == nRefCnt )
+ delete this;
+
+ return nRefCnt;
+}
+
+STDMETHODIMP CXTDataObject::GetData( FORMATETC * pFormatetc, STGMEDIUM * pmedium )
+{
+ if ( !(pFormatetc && pmedium) )
+ return E_INVALIDARG;
+
+ try
+ {
+ // prepare data transfer
+ invalidateStgMedium( *pmedium );
+ validateFormatEtc( pFormatetc );
+
+ // handle locale request, because locale is an artificial format for us
+ if ( CF_LOCALE == pFormatetc->cfFormat )
+ renderLocaleAndSetupStgMedium( *pFormatetc, *pmedium );
+ else if ( CF_UNICODETEXT == pFormatetc->cfFormat )
+ renderUnicodeAndSetupStgMedium( *pFormatetc, *pmedium );
+ else
+ renderAnyDataAndSetupStgMedium( *pFormatetc, *pmedium );
+ }
+ catch(UnsupportedFlavorException&)
+ {
+ HRESULT hr = DV_E_FORMATETC;
+
+ CFormatEtc aFormatetc(*pFormatetc);
+ if (CFormatRegistrar::isSynthesizeableFormat(aFormatetc))
+ hr = renderSynthesizedFormatAndSetupStgMedium( *pFormatetc, *pmedium );
+
+ return hr;
+ }
+ catch( CInvalidFormatEtcException& ex )
+ {
+ return ex.m_hr;
+ }
+ catch( CStgTransferHelper::CStgTransferException& ex )
+ {
+ return translateStgExceptionCode( ex.m_hr );
+ }
+ catch(...)
+ {
+ return E_UNEXPECTED;
+ }
+
+ return S_OK;
+}
+
+//inline
+void CXTDataObject::renderLocaleAndSetupStgMedium(
+ FORMATETC const & fetc, STGMEDIUM& stgmedium )
+{
+ if ( !m_FormatRegistrar.hasSynthesizedLocale( ) )
+ throw CInvalidFormatEtcException( DV_E_FORMATETC );
+ LCID lcid = CFormatRegistrar::getSynthesizedLocale( );
+ renderDataAndSetupStgMedium(
+ reinterpret_cast< sal_Int8* >( &lcid ),
+ fetc,
+ 0,
+ sizeof( LCID ),
+ stgmedium );
+}
+
+void CXTDataObject::renderUnicodeAndSetupStgMedium(
+ FORMATETC const & fetc, STGMEDIUM& stgmedium )
+{
+ DataFlavor aFlavor = formatEtcToDataFlavor( fetc );
+
+ Any aAny = m_XTransferable->getTransferData( aFlavor );
+
+ // unfortunately not all transferables fulfill the
+ // spec. and do throw an UnsupportedFlavorException
+ // so we must check the any
+ if ( !aAny.hasValue( ) )
+ {
+ OSL_FAIL( "XTransferable should throw an exception if ask for an unsupported flavor" );
+ throw UnsupportedFlavorException( );
+ }
+
+ OUString aText;
+ aAny >>= aText;
+
+ sal_uInt32 nBytesToTransfer = aText.getLength( ) * sizeof( sal_Unicode );
+
+ // to be sure there is an ending 0
+ sal_uInt32 nRequiredMemSize = nBytesToTransfer + sizeof( sal_Unicode );
+
+ renderDataAndSetupStgMedium(
+ reinterpret_cast< const sal_Int8* >( aText.getStr( ) ),
+ fetc,
+ nRequiredMemSize,
+ nBytesToTransfer,
+ stgmedium );
+}
+
+void CXTDataObject::renderAnyDataAndSetupStgMedium(
+ FORMATETC& fetc, STGMEDIUM& stgmedium )
+{
+ DataFlavor aFlavor = formatEtcToDataFlavor( fetc );
+
+ Any aAny = m_XTransferable->getTransferData( aFlavor );
+
+ // unfortunately not all transferables fulfill the
+ // spec. and do throw an UnsupportedFlavorException
+ // so we must check the any
+ if ( !aAny.hasValue( ) )
+ {
+ OSL_FAIL( "XTransferable should throw an exception if ask for an unsupported flavor" );
+ throw UnsupportedFlavorException( );
+ }
+
+ // unfortunately not all transferables fulfill the
+ // spec. and do throw an UnsupportedFlavorException
+ // so we must check the any
+ if ( !aAny.hasValue( ) )
+ throw UnsupportedFlavorException( );
+
+ Sequence< sal_Int8 > clipDataStream;
+ aAny >>= clipDataStream;
+
+ sal_uInt32 nRequiredMemSize = 0;
+ if ( CDataFormatTranslator::isOemOrAnsiTextFormat( fetc.cfFormat ) )
+ nRequiredMemSize = sizeof( sal_Int8 ) * clipDataStream.getLength( ) + 1;
+
+ // prepare data for transmission
+ // #i124085# DIBV5 should not happen for now, but keep as hint here
+ if ( CF_DIBV5 == fetc.cfFormat || CF_DIB == fetc.cfFormat )
+ {
+#ifdef DBG_UTIL
+ if(CF_DIBV5 == fetc.cfFormat)
+ {
+ OSL_ENSURE(o3tl::make_unsigned(clipDataStream.getLength()) > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPV5HEADER)), "Wrong size on CF_DIBV5 data (!)");
+ }
+ else // CF_DIB == fetc.cfFormat
+ {
+ OSL_ENSURE(o3tl::make_unsigned(clipDataStream.getLength()) > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)), "Wrong size on CF_DIB data (!)");
+ }
+#endif
+
+ // remove BITMAPFILEHEADER
+ clipDataStream = OOBmpToWinDIB( clipDataStream );
+ }
+
+ if ( CF_METAFILEPICT == fetc.cfFormat )
+ {
+ stgmedium.tymed = TYMED_MFPICT;
+ stgmedium.hMetaFilePict = OOMFPictToWinMFPict( clipDataStream );
+ stgmedium.pUnkForRelease = nullptr;
+ }
+ else if( CF_ENHMETAFILE == fetc.cfFormat )
+ {
+ stgmedium.tymed = TYMED_ENHMF;
+ stgmedium.hMetaFilePict = OOMFPictToWinENHMFPict( clipDataStream );
+ stgmedium.pUnkForRelease = nullptr;
+ }
+ else
+ renderDataAndSetupStgMedium(
+ clipDataStream.getArray( ),
+ fetc,
+ nRequiredMemSize,
+ clipDataStream.getLength( ),
+ stgmedium );
+}
+
+HRESULT CXTDataObject::renderSynthesizedFormatAndSetupStgMedium( FORMATETC& fetc, STGMEDIUM& stgmedium )
+{
+ HRESULT hr = S_OK;
+
+ try
+ {
+ if ( CF_UNICODETEXT == fetc.cfFormat )
+ // the transferable seems to have only text
+ renderSynthesizedUnicodeAndSetupStgMedium( fetc, stgmedium );
+ else if ( CDataFormatTranslator::isOemOrAnsiTextFormat( fetc.cfFormat ) )
+ // the transferable seems to have only unicode text
+ renderSynthesizedTextAndSetupStgMedium( fetc, stgmedium );
+ else
+ // the transferable seems to have only text/html
+ renderSynthesizedHtmlAndSetupStgMedium( fetc, stgmedium );
+ }
+ catch(UnsupportedFlavorException&)
+ {
+ hr = DV_E_FORMATETC;
+ }
+ catch( CInvalidFormatEtcException& )
+ {
+ OSL_FAIL( "Unexpected exception" );
+ }
+ catch( CStgTransferHelper::CStgTransferException& ex )
+ {
+ return translateStgExceptionCode( ex.m_hr );
+ }
+ catch(...)
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ return hr;
+}
+
+// the transferable must have only text, so we will synthesize unicode text
+
+void CXTDataObject::renderSynthesizedUnicodeAndSetupStgMedium( FORMATETC const & fetc, STGMEDIUM& stgmedium )
+{
+ OSL_ASSERT( CF_UNICODETEXT == fetc.cfFormat );
+
+ Any aAny = m_XTransferable->getTransferData( m_FormatRegistrar.getRegisteredTextFlavor( ) );
+
+ // unfortunately not all transferables fulfill the
+ // spec. and do throw an UnsupportedFlavorException
+ // so we must check the any
+ if ( !aAny.hasValue( ) )
+ {
+ OSL_FAIL( "XTransferable should throw an exception if ask for an unsupported flavor" );
+ throw UnsupportedFlavorException( );
+ }
+
+ Sequence< sal_Int8 > aText;
+ aAny >>= aText;
+
+ CStgTransferHelper stgTransfHelper;
+
+ MultiByteToWideCharEx(
+ CFormatRegistrar::getRegisteredTextCodePage( ),
+ reinterpret_cast< char* >( aText.getArray( ) ),
+ aText.getLength( ),
+ stgTransfHelper );
+
+ setupStgMedium( fetc, stgTransfHelper, stgmedium );
+}
+
+// the transferable must have only unicode text so we will synthesize text
+
+void CXTDataObject::renderSynthesizedTextAndSetupStgMedium( FORMATETC& fetc, STGMEDIUM& stgmedium )
+{
+ OSL_ASSERT( CDataFormatTranslator::isOemOrAnsiTextFormat( fetc.cfFormat ) );
+
+ DataFlavor aFlavor = formatEtcToDataFlavor(
+ CDataFormatTranslator::getFormatEtcForClipformat( CF_UNICODETEXT ) );
+
+ Any aAny = m_XTransferable->getTransferData( aFlavor );
+
+ // unfortunately not all transferables fulfill the
+ // spec. and do throw an UnsupportedFlavorException
+ // so we must check the any
+ if ( !aAny.hasValue( ) )
+ {
+ OSL_FAIL( "XTransferable should throw an exception if ask for an unsupported flavor" );
+ throw UnsupportedFlavorException( );
+ }
+
+ OUString aUnicodeText;
+ aAny >>= aUnicodeText;
+
+ CStgTransferHelper stgTransfHelper;
+
+ WideCharToMultiByteEx(
+ GetACP( ),
+ o3tl::toW( aUnicodeText.getStr( ) ),
+ aUnicodeText.getLength( ),
+ stgTransfHelper );
+
+ setupStgMedium( fetc, stgTransfHelper, stgmedium );
+}
+
+void CXTDataObject::renderSynthesizedHtmlAndSetupStgMedium( FORMATETC& fetc, STGMEDIUM& stgmedium )
+{
+ OSL_ASSERT( CDataFormatTranslator::isHTMLFormat( fetc.cfFormat ) );
+
+ DataFlavor aFlavor;
+
+ // creating a DataFlavor on the fly
+ aFlavor.MimeType = "text/html";
+ aFlavor.DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
+
+ Any aAny = m_XTransferable->getTransferData( aFlavor );
+
+ // unfortunately not all transferables fulfill the
+ // spec. and do throw an UnsupportedFlavorException
+ // so we must check the any
+ if ( !aAny.hasValue( ) )
+ {
+ OSL_FAIL( "XTransferable should throw an exception if ask for an unsupported flavor" );
+ throw UnsupportedFlavorException( );
+ }
+
+ Sequence< sal_Int8 > aTextHtmlSequence;
+ aAny >>= aTextHtmlSequence;
+
+ Sequence< sal_Int8 > aHTMLFormatSequence = TextHtmlToHTMLFormat( aTextHtmlSequence );
+
+ sal_uInt32 nBytesToTransfer = aHTMLFormatSequence.getLength( );
+
+ renderDataAndSetupStgMedium(
+ reinterpret_cast< const sal_Int8* >( aHTMLFormatSequence.getArray( ) ),
+ fetc,
+ 0,
+ nBytesToTransfer,
+ stgmedium );
+}
+
+// IDataObject->EnumFormatEtc
+
+STDMETHODIMP CXTDataObject::EnumFormatEtc(
+ DWORD dwDirection, IEnumFORMATETC** ppenumFormatetc )
+{
+ if ( nullptr == ppenumFormatetc )
+ return E_INVALIDARG;
+
+ if ( DATADIR_SET == dwDirection )
+ return E_NOTIMPL;
+
+ *ppenumFormatetc = nullptr;
+
+ InitializeFormatEtcContainer( );
+
+ HRESULT hr;
+ if ( DATADIR_GET == dwDirection )
+ {
+ *ppenumFormatetc = new CEnumFormatEtc( this, m_FormatEtcContainer );
+ static_cast< LPUNKNOWN >( *ppenumFormatetc )->AddRef( );
+
+ hr = S_OK;
+ }
+ else
+ hr = E_INVALIDARG;
+
+ return hr;
+}
+
+// IDataObject->QueryGetData
+
+STDMETHODIMP CXTDataObject::QueryGetData( FORMATETC * pFormatetc )
+{
+ if ( (nullptr == pFormatetc) || IsBadReadPtr( pFormatetc, sizeof( FORMATETC ) ) )
+ return E_INVALIDARG;
+
+ InitializeFormatEtcContainer( );
+
+ CFormatEtc aFormatetc(*pFormatetc);
+ return m_FormatEtcContainer.hasFormatEtc(aFormatetc) ? S_OK : S_FALSE;
+}
+
+// IDataObject->GetDataHere
+
+STDMETHODIMP CXTDataObject::GetDataHere( FORMATETC *, STGMEDIUM * )
+{
+ return E_NOTIMPL;
+}
+
+// IDataObject->GetCanonicalFormatEtc
+
+STDMETHODIMP CXTDataObject::GetCanonicalFormatEtc( FORMATETC *, FORMATETC * )
+{
+ return E_NOTIMPL;
+}
+
+// IDataObject->SetData
+
+STDMETHODIMP CXTDataObject::SetData( FORMATETC *, STGMEDIUM *, BOOL )
+{
+ return E_NOTIMPL;
+}
+
+// IDataObject->DAdvise
+
+STDMETHODIMP CXTDataObject::DAdvise( FORMATETC *, DWORD, IAdviseSink *, DWORD * )
+{
+ return E_NOTIMPL;
+}
+
+// IDataObject->DUnadvise
+
+STDMETHODIMP CXTDataObject::DUnadvise( DWORD )
+{
+ return E_NOTIMPL;
+}
+
+// IDataObject->EnumDAdvise
+
+STDMETHODIMP CXTDataObject::EnumDAdvise( IEnumSTATDATA ** )
+{
+ return E_NOTIMPL;
+}
+
+// for our convenience
+
+CXTDataObject::operator IDataObject*( )
+{
+ return static_cast< IDataObject* >( this );
+}
+
+inline
+DataFlavor CXTDataObject::formatEtcToDataFlavor( const FORMATETC& aFormatEtc ) const
+{
+ DataFlavor aFlavor;
+
+ if ( m_FormatRegistrar.hasSynthesizedLocale( ) )
+ aFlavor = m_DataFormatTranslator.getDataFlavorFromFormatEtc(
+ aFormatEtc.cfFormat, CFormatRegistrar::getSynthesizedLocale());
+ else
+ aFlavor = m_DataFormatTranslator.getDataFlavorFromFormatEtc(aFormatEtc.cfFormat);
+
+ if ( !aFlavor.MimeType.getLength( ) )
+ throw UnsupportedFlavorException( );
+
+ return aFlavor;
+}
+
+inline void CXTDataObject::InitializeFormatEtcContainer( )
+{
+ if ( !m_bFormatEtcContainerInitialized )
+ {
+ m_FormatRegistrar.RegisterFormats( m_XTransferable, m_FormatEtcContainer );
+ m_bFormatEtcContainerInitialized = true;
+ }
+}
+
+CEnumFormatEtc::CEnumFormatEtc( LPUNKNOWN lpUnkOuter, const CFormatEtcContainer& aFormatEtcContainer ) :
+ m_nRefCnt( 0 ),
+ m_lpUnkOuter( lpUnkOuter ),
+ m_FormatEtcContainer( aFormatEtcContainer )
+{
+ Reset( );
+}
+
+// IUnknown->QueryInterface
+
+STDMETHODIMP CEnumFormatEtc::QueryInterface( REFIID iid, void** ppvObject )
+{
+ if ( nullptr == ppvObject )
+ return E_INVALIDARG;
+
+ HRESULT hr = E_NOINTERFACE;
+
+ *ppvObject = nullptr;
+
+ if ( ( __uuidof( IUnknown ) == iid ) ||
+ ( __uuidof( IEnumFORMATETC ) == iid ) )
+ {
+ *ppvObject = static_cast< IUnknown* >( this );
+ static_cast< LPUNKNOWN >( *ppvObject )->AddRef( );
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+// IUnknown->AddRef
+
+STDMETHODIMP_(ULONG) CEnumFormatEtc::AddRef( )
+{
+ // keep the dataobject alive
+ m_lpUnkOuter->AddRef( );
+ return InterlockedIncrement( &m_nRefCnt );
+}
+
+// IUnknown->Release
+
+STDMETHODIMP_(ULONG) CEnumFormatEtc::Release( )
+{
+ // release the outer dataobject
+ m_lpUnkOuter->Release( );
+
+ ULONG nRefCnt = InterlockedDecrement( &m_nRefCnt );
+ if ( 0 == nRefCnt )
+ delete this;
+
+ return nRefCnt;
+}
+
+// IEnumFORMATETC->Next
+
+STDMETHODIMP CEnumFormatEtc::Next( ULONG nRequested, FORMATETC * lpDest, ULONG* lpFetched )
+{
+ if ( ( nRequested < 1 ) ||
+ (( nRequested > 1 ) && ( nullptr == lpFetched )) ||
+ IsBadWritePtr( lpDest, sizeof( FORMATETC ) * nRequested ) )
+ return E_INVALIDARG;
+
+ sal_uInt32 nFetched = m_FormatEtcContainer.nextFormatEtc( lpDest, nRequested );
+
+ if ( nullptr != lpFetched )
+ *lpFetched = nFetched;
+
+ return (nFetched == nRequested) ? S_OK : S_FALSE;
+}
+
+// IEnumFORMATETC->Skip
+
+STDMETHODIMP CEnumFormatEtc::Skip( ULONG celt )
+{
+ return m_FormatEtcContainer.skipFormatEtc( celt ) ? S_OK : S_FALSE;
+}
+
+// IEnumFORMATETC->Reset
+
+STDMETHODIMP CEnumFormatEtc::Reset( )
+{
+ m_FormatEtcContainer.beginEnumFormatEtc( );
+ return S_OK;
+}
+
+// IEnumFORMATETC->Clone
+
+STDMETHODIMP CEnumFormatEtc::Clone( IEnumFORMATETC** ppenum )
+{
+ if ( nullptr == ppenum )
+ return E_INVALIDARG;
+
+ *ppenum = new CEnumFormatEtc( m_lpUnkOuter, m_FormatEtcContainer );
+ static_cast< LPUNKNOWN >( *ppenum )->AddRef( );
+
+ return S_OK;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/XTDataObject.hxx b/vcl/win/dtrans/XTDataObject.hxx
new file mode 100644
index 000000000..77f8c53f2
--- /dev/null
+++ b/vcl/win/dtrans/XTDataObject.hxx
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardOwner.hpp>
+
+#include "DataFmtTransl.hxx"
+
+#include "FetcList.hxx"
+
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <ole2.h>
+#include <objidl.h>
+
+/*--------------------------------------------------------------------------
+ - the function principle of the windows clipboard:
+ a data provider offers all formats he can deliver on the clipboard
+ a clipboard client ask for the available formats on the clipboard
+ and decides if there is a format he can use
+ if there is one, he requests the data in this format
+
+ - This class inherits from IDataObject and so can be placed on the
+ OleClipboard. The class wraps a transferable object which is the
+ original DataSource
+ - DataFlavors offered by this transferable will be translated into
+ appropriate clipboard formats
+ - if the transferable contains text data always text and unicodetext
+ will be offered or vice versa
+ - text data will be automatically converted between text and unicode text
+ - although the transferable may support text in different charsets
+ (codepages) only text in one codepage can be offered by the clipboard
+
+----------------------------------------------------------------------------*/
+
+class CStgTransferHelper;
+
+class CXTDataObject : public IDataObject
+{
+public:
+ CXTDataObject( const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ const css::uno::Reference< css::datatransfer::XTransferable >& aXTransferable );
+ virtual ~CXTDataObject();
+
+ // ole interface implementation
+
+ //IUnknown interface methods
+ STDMETHODIMP QueryInterface(REFIID iid, void** ppvObject) override;
+ STDMETHODIMP_( ULONG ) AddRef( ) override;
+ STDMETHODIMP_( ULONG ) Release( ) override;
+
+ // IDataObject interface methods
+ STDMETHODIMP GetData( FORMATETC * pFormatetc, STGMEDIUM * pmedium ) override;
+ STDMETHODIMP GetDataHere( FORMATETC * pFormatetc, STGMEDIUM * pmedium ) override;
+ STDMETHODIMP QueryGetData( FORMATETC * pFormatetc ) override;
+ STDMETHODIMP GetCanonicalFormatEtc( FORMATETC * pFormatectIn, FORMATETC * pFormatetcOut ) override;
+ STDMETHODIMP SetData( FORMATETC * pFormatetc, STGMEDIUM * pmedium, BOOL fRelease ) override;
+ STDMETHODIMP EnumFormatEtc( DWORD dwDirection, IEnumFORMATETC** ppenumFormatetc ) override;
+ STDMETHODIMP DAdvise( FORMATETC * pFormatetc, DWORD advf, IAdviseSink * pAdvSink, DWORD* pdwConnection ) override;
+ STDMETHODIMP DUnadvise( DWORD dwConnection ) override;
+ STDMETHODIMP EnumDAdvise( IEnumSTATDATA** ppenumAdvise ) override;
+
+ operator IDataObject*( );
+
+private:
+ css::datatransfer::DataFlavor formatEtcToDataFlavor( const FORMATETC& aFormatEtc ) const;
+
+ void renderLocaleAndSetupStgMedium( FORMATETC const & fetc, STGMEDIUM& stgmedium );
+ void renderUnicodeAndSetupStgMedium( FORMATETC const & fetc, STGMEDIUM& stgmedium );
+ void renderAnyDataAndSetupStgMedium( FORMATETC& fetc, STGMEDIUM& stgmedium );
+
+ HRESULT renderSynthesizedFormatAndSetupStgMedium( FORMATETC& fetc, STGMEDIUM& stgmedium );
+ void renderSynthesizedUnicodeAndSetupStgMedium( FORMATETC const & fetc, STGMEDIUM& stgmedium );
+ void renderSynthesizedTextAndSetupStgMedium( FORMATETC& fetc, STGMEDIUM& stgmedium );
+ void renderSynthesizedHtmlAndSetupStgMedium( FORMATETC& fetc, STGMEDIUM& stgmedium );
+
+ inline void InitializeFormatEtcContainer( );
+
+private:
+ LONG m_nRefCnt;
+ css::uno::Reference< css::datatransfer::XTransferable > m_XTransferable;
+ css::uno::Reference< css::uno::XComponentContext> m_XComponentContext;
+ CFormatEtcContainer m_FormatEtcContainer;
+ bool m_bFormatEtcContainerInitialized;
+ CDataFormatTranslator m_DataFormatTranslator;
+ CFormatRegistrar m_FormatRegistrar;
+};
+
+class CEnumFormatEtc : public IEnumFORMATETC
+{
+public:
+ CEnumFormatEtc( LPUNKNOWN lpUnkOuter, const CFormatEtcContainer& aFormatEtcContainer );
+ virtual ~CEnumFormatEtc() {}
+
+ // IUnknown
+ STDMETHODIMP QueryInterface( REFIID iid, void** ppvObject ) override;
+ STDMETHODIMP_( ULONG ) AddRef( ) override;
+ STDMETHODIMP_( ULONG ) Release( ) override;
+
+ //IEnumFORMATETC
+ STDMETHODIMP Next( ULONG nRequested, FORMATETC * lpDest, ULONG* lpFetched ) override;
+ STDMETHODIMP Skip( ULONG celt ) override;
+ STDMETHODIMP Reset( ) override;
+ STDMETHODIMP Clone( IEnumFORMATETC** ppenum ) override;
+
+private:
+ LONG m_nRefCnt;
+ LPUNKNOWN m_lpUnkOuter;
+ CFormatEtcContainer m_FormatEtcContainer;
+};
+
+typedef CEnumFormatEtc *PCEnumFormatEtc;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/clipboardmanager.cxx b/vcl/win/dtrans/clipboardmanager.cxx
new file mode 100644
index 000000000..2e04d39e1
--- /dev/null
+++ b/vcl/win/dtrans/clipboardmanager.cxx
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "clipboardmanager.hxx"
+#include <com/sun/star/container/ElementExistException.hpp>
+#include <com/sun/star/container/NoSuchElementException.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/sequence.hxx>
+#include <rtl/ref.hxx>
+
+using namespace com::sun::star::container;
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::datatransfer::clipboard;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace cppu;
+using namespace osl;
+
+using ::dtrans::ClipboardManager;
+
+static osl::Mutex g_InstanceGuard;
+static rtl::Reference<ClipboardManager> g_Instance;
+static bool g_Disposed = false;
+
+
+ClipboardManager::ClipboardManager():
+ WeakComponentImplHelper< XClipboardManager, XEventListener, XServiceInfo > (m_aMutex),
+ m_aDefaultName(OUString("default"))
+{
+}
+
+ClipboardManager::~ClipboardManager()
+{
+}
+
+OUString SAL_CALL ClipboardManager::getImplementationName( )
+{
+ return "com.sun.star.comp.datatransfer.ClipboardManager";
+}
+
+sal_Bool SAL_CALL ClipboardManager::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Sequence< OUString > SAL_CALL ClipboardManager::getSupportedServiceNames( )
+{
+ return { "com.sun.star.datatransfer.clipboard.ClipboardManager" };
+}
+
+Reference< XClipboard > SAL_CALL ClipboardManager::getClipboard( const OUString& aName )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ // object is disposed already
+ if (rBHelper.bDisposed)
+ throw DisposedException("object is disposed.",
+ static_cast < XClipboardManager * > (this));
+
+ ClipboardMap::iterator iter =
+ m_aClipboardMap.find(aName.getLength() ? aName : m_aDefaultName);
+
+ if (iter != m_aClipboardMap.end())
+ return iter->second;
+
+ throw NoSuchElementException(aName, static_cast < XClipboardManager * > (this));
+}
+
+void SAL_CALL ClipboardManager::addClipboard( const Reference< XClipboard >& xClipboard )
+{
+ OSL_ASSERT(xClipboard.is());
+
+ // check parameter
+ if (!xClipboard.is())
+ throw IllegalArgumentException("empty reference",
+ static_cast < XClipboardManager * > (this), 1);
+
+ // the name "default" is reserved for internal use
+ OUString aName = xClipboard->getName();
+ if ( m_aDefaultName == aName )
+ throw IllegalArgumentException("name reserved",
+ static_cast < XClipboardManager * > (this), 1);
+
+ // try to add new clipboard to the list
+ ClearableMutexGuard aGuard(m_aMutex);
+ if (!rBHelper.bDisposed && !rBHelper.bInDispose)
+ {
+ std::pair< const OUString, Reference< XClipboard > > value (
+ aName.getLength() ? aName : m_aDefaultName,
+ xClipboard );
+
+ std::pair< ClipboardMap::iterator, bool > p = m_aClipboardMap.insert(value);
+ aGuard.clear();
+
+ // insert failed, element must exist already
+ if (!p.second)
+ throw ElementExistException(aName, static_cast < XClipboardManager * > (this));
+
+ // request disposing notifications
+ Reference< XComponent > xComponent(xClipboard, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->addEventListener(static_cast < XEventListener * > (this));
+ }
+}
+
+void SAL_CALL ClipboardManager::removeClipboard( const OUString& aName )
+{
+ MutexGuard aGuard(m_aMutex);
+ if (!rBHelper.bDisposed)
+ m_aClipboardMap.erase(aName.getLength() ? aName : m_aDefaultName );
+}
+
+Sequence< OUString > SAL_CALL ClipboardManager::listClipboardNames()
+{
+ MutexGuard aGuard(m_aMutex);
+
+ if (rBHelper.bDisposed)
+ throw DisposedException("object is disposed.",
+ static_cast < XClipboardManager * > (this));
+
+ if (rBHelper.bInDispose)
+ return Sequence< OUString > ();
+
+ return comphelper::mapKeysToSequence(m_aClipboardMap);
+}
+
+void SAL_CALL ClipboardManager::dispose()
+{
+ {
+ osl::MutexGuard aGuard(g_InstanceGuard);
+ g_Instance.clear();
+ g_Disposed = true;
+ }
+ {
+ ClearableMutexGuard aGuard( rBHelper.rMutex );
+ if (!rBHelper.bDisposed && !rBHelper.bInDispose)
+ {
+ rBHelper.bInDispose = true;
+ aGuard.clear();
+
+ // give everyone a chance to save his clipboard instance
+ EventObject aEvt(static_cast < XClipboardManager * > (this));
+ rBHelper.aLC.disposeAndClear( aEvt );
+
+ // removeClipboard is still allowed here, so make a copy of the
+ // list (to ensure integrity) and clear the original.
+ ClearableMutexGuard aGuard2( rBHelper.rMutex );
+ ClipboardMap aCopy(m_aClipboardMap);
+ m_aClipboardMap.clear();
+ aGuard2.clear();
+
+ // dispose all clipboards still in list
+ for (auto const& elem : aCopy)
+ {
+ Reference< XComponent > xComponent(elem.second, UNO_QUERY);
+ if (xComponent.is())
+ {
+ try
+ {
+ xComponent->removeEventListener(static_cast < XEventListener * > (this));
+ xComponent->dispose();
+ }
+ catch (const Exception&)
+ {
+ // exceptions can be safely ignored here.
+ }
+ }
+ }
+
+ rBHelper.bDisposed = true;
+ rBHelper.bInDispose = false;
+ }
+ }
+}
+
+void SAL_CALL ClipboardManager::disposing( const EventObject& event )
+{
+ Reference < XClipboard > xClipboard(event.Source, UNO_QUERY);
+
+ if (xClipboard.is())
+ removeClipboard(xClipboard->getName());
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+dtrans_ClipboardManager_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ osl::MutexGuard aGuard(g_InstanceGuard);
+ if (g_Disposed)
+ return nullptr;
+ if (!g_Instance)
+ g_Instance.set(new ClipboardManager());
+ g_Instance->acquire();
+ return static_cast<cppu::OWeakObject*>(g_Instance.get());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/clipboardmanager.hxx b/vcl/win/dtrans/clipboardmanager.hxx
new file mode 100644
index 000000000..56e69617d
--- /dev/null
+++ b/vcl/win/dtrans/clipboardmanager.hxx
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cppuhelper/compbase.hxx>
+
+#include <com/sun/star/datatransfer/clipboard/XClipboardManager.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#include <map>
+
+typedef std::map< OUString, css::uno::Reference< css::datatransfer::clipboard::XClipboard > > ClipboardMap;
+
+namespace dtrans
+{
+
+ class ClipboardManager : public ::cppu::WeakComponentImplHelper <
+ css::datatransfer::clipboard::XClipboardManager,
+ css::lang::XEventListener,
+ css::lang::XServiceInfo >
+ {
+ ClipboardMap m_aClipboardMap;
+ ::osl::Mutex m_aMutex;
+
+ const OUString m_aDefaultName;
+
+ virtual ~ClipboardManager() override;
+ protected:
+ using WeakComponentImplHelperBase::disposing;
+ public:
+
+ ClipboardManager();
+
+ /*
+ * XServiceInfo
+ */
+
+ virtual OUString SAL_CALL getImplementationName( ) override;
+
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ /*
+ * XComponent
+ */
+
+ virtual void SAL_CALL dispose() override;
+
+ /*
+ * XEventListener
+ */
+
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ /*
+ * XClipboardManager
+ */
+
+ virtual css::uno::Reference< css::datatransfer::clipboard::XClipboard > SAL_CALL getClipboard( const OUString& aName ) override;
+
+ virtual void SAL_CALL addClipboard( const css::uno::Reference< css::datatransfer::clipboard::XClipboard >& xClipboard ) override;
+
+ virtual void SAL_CALL removeClipboard( const OUString& aName ) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL listClipboardNames( ) override;
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/ftransl.cxx b/vcl/win/dtrans/ftransl.cxx
new file mode 100644
index 000000000..ad41a95b0
--- /dev/null
+++ b/vcl/win/dtrans/ftransl.cxx
@@ -0,0 +1,550 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <o3tl/string_view.hxx>
+#include <osl/diagnose.h>
+
+#include "ftransl.hxx"
+#include <com/sun/star/container/NoSuchElementException.hpp>
+#include <com/sun/star/datatransfer/XMimeContentType.hpp>
+#include <com/sun/star/datatransfer/MimeContentTypeFactory.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include "ImplHelper.hxx"
+
+#include <shlobj.h>
+
+#define CPPUTYPE_SEQSALINT8 cppu::UnoType<Sequence< sal_Int8 >>::get()
+#define CPPUTYPE_DEFAULT CPPUTYPE_SEQSALINT8
+
+const OUStringLiteral Windows_FormatName = u"windows_formatname";
+const css::uno::Type CppuType_ByteSequence = cppu::UnoType<css::uno::Sequence<sal_Int8>>::get();
+const css::uno::Type CppuType_String = ::cppu::UnoType<OUString>::get();
+
+using namespace osl;
+using namespace cppu;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::container;
+
+namespace
+{
+
+struct FormatEntry
+{
+ FormatEntry(
+ const char *mime_content_type,
+ const char *human_presentable_name,
+ const char *native_format_name,
+ CLIPFORMAT std_clipboard_format_id,
+ css::uno::Type const & cppu_type
+ );
+
+ css::datatransfer::DataFlavor aDataFlavor;
+ OUString aNativeFormatName;
+ sal_Int32 aStandardFormatId;
+};
+
+}
+
+FormatEntry::FormatEntry(
+ const char *mime_content_type,
+ const char *human_presentable_name,
+ const char *native_format_name,
+ CLIPFORMAT std_clipboard_format_id,
+ css::uno::Type const & cppu_type)
+ : aDataFlavor( OUString::createFromAscii(mime_content_type), OUString::createFromAscii(human_presentable_name), cppu_type)
+{
+ if (native_format_name)
+ aNativeFormatName = OUString::createFromAscii(native_format_name);
+ else
+ aNativeFormatName = OUString::createFromAscii(human_presentable_name);
+
+ aStandardFormatId = std_clipboard_format_id;
+}
+
+// to optimize searching we add all entries with a
+// standard clipboard format number first, in the
+// table before the entries with CF_INVALID
+// if we are searching for a standard clipboard
+// format number we can stop if we find the first
+// CF_INVALID
+
+const std::vector< FormatEntry > g_TranslTable {
+ //SotClipboardFormatId::DIF
+ FormatEntry("application/x-openoffice-dif;windows_formatname=\"DIF\"", "DIF", "DIF", CF_DIF, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::BITMAP
+
+ // #i124085# CF_DIBV5 disabled, leads to problems at export. To fully support, using
+ // an own mime-type may be necessary. I have tried that, but saw no real advantages
+ // with different apps when exchanging bitmap-based data. So, disabled for now. At
+ // the same time increased png format exchange for better interoperability
+ // FormatEntry("application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"", "Bitmap", "Bitmap", CF_DIBV5, CPPUTYPE_DEFAULT),
+
+ FormatEntry("application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"", "Bitmap", "Bitmap", CF_DIB, CPPUTYPE_DEFAULT),
+ FormatEntry("application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"", "Bitmap", "Bitmap", CF_BITMAP, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::STRING
+ FormatEntry("text/plain;charset=utf-16", "Unicode-Text", "", CF_UNICODETEXT, CppuType_String),
+ // Format Locale - for internal use
+ FormatEntry("application/x-openoffice-locale;windows_formatname=\"Locale\"", "Locale", "Locale", CF_LOCALE, CPPUTYPE_DEFAULT),
+ // SOT_FORMAT_WMF
+ FormatEntry("application/x-openoffice-wmf;windows_formatname=\"Image WMF\"", "Windows MetaFile", "Image WMF", CF_METAFILEPICT, CPPUTYPE_DEFAULT),
+ // SOT_FORMAT_EMF
+ FormatEntry("application/x-openoffice-emf;windows_formatname=\"Image EMF\"", "Windows Enhanced MetaFile", "Image EMF", CF_ENHMETAFILE, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::FILE_LIST
+ FormatEntry("application/x-openoffice-filelist;windows_formatname=\"FileList\"", "FileList", "FileList", CF_HDROP, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::SYLK
+ FormatEntry("application/x-openoffice-sylk;windows_formatname=\"Sylk\"", "Sylk", "Sylk", CF_SYLK, CPPUTYPE_DEFAULT ),
+ // SotClipboardFormatId::GDIMETAFILE
+ FormatEntry("application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"", "GDIMetaFile", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::PRIVATE
+ FormatEntry("application/x-openoffice-private;windows_formatname=\"Private\"", "Private", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::SIMPLE_FILE
+ FormatEntry("application/x-openoffice-file;windows_formatname=\"FileNameW\"", "FileName", nullptr, CF_INVALID, CppuType_String),
+ // SotClipboardFormatId::RTF
+ FormatEntry("text/rtf", "Rich Text Format", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::DRAWING
+ FormatEntry("application/x-openoffice-drawing;windows_formatname=\"Drawing Format\"", "Drawing Format", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::SVXB
+ FormatEntry("application/x-openoffice-svbx;windows_formatname=\"SVXB (StarView Bitmap/Animation)\"", "SVXB (StarView Bitmap/Animation)", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::SVIM
+ FormatEntry("application/x-openoffice-svim;windows_formatname=\"SVIM (StarView ImageMap)\"", "SVIM (StarView ImageMap)", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::XFA
+ FormatEntry("application/x-libreoffice-xfa;windows_formatname=\"XFA (XOutDev FillAttr Any)\"", "XFA (XOutDev FillAttr Any)", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT
+ FormatEntry("application/vnd.oasis.opendocument.text-flat-xml", "EditEngine ODF", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::INTERNALLINK_STATE
+ FormatEntry("application/x-openoffice-internallink-state;windows_formatname=\"StatusInfo of SvxInternalLink\"", "StatusInfo of SvxInternalLink", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::SOLK
+ FormatEntry("application/x-openoffice-solk;windows_formatname=\"SOLK (StarOffice Link)\"", "SOLK (StarOffice Link)", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::NETSCAPE_BOOKMARK
+ FormatEntry("application/x-openoffice-netscape-bookmark;windows_formatname=\"Netscape Bookmark\"", "Netscape Bookmark", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::TREELISTBOX
+ FormatEntry("application/x-openoffice-treelistbox;windows_formatname=\"SV_LBOX_DD_FORMAT\"", "SV_LBOX_DD_FORMAT", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::NATIVE
+ FormatEntry("application/x-openoffice-native;windows_formatname=\"Native\"", "Native", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::OWNERLINK
+ FormatEntry("application/x-openoffice-ownerlink;windows_formatname=\"OwnerLink\"", "OwnerLink", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::STARSERVER
+ FormatEntry("application/x-openoffice-starserver;windows_formatname=\"StarServerFormat\"", "StarServerFormat", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::STAROBJECT
+ FormatEntry("application/x-openoffice-starobject;windows_formatname=\"StarObjectFormat\"", "StarObjectFormat", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::APPLETOBJECT
+ FormatEntry("application/x-openoffice-appletobject;windows_formatname=\"Applet Object\"", "Applet Object", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::PLUGIN_OBJECT
+ FormatEntry("application/x-openoffice-plugin-object;windows_formatname=\"PlugIn Object\"", "PlugIn Object", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::STARWRITER_30
+ FormatEntry("application/x-openoffice-starwriter-30;windows_formatname=\"StarWriter 3.0\"", "StarWriter 3.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARWRITER_40
+ FormatEntry("application/x-openoffice-starwriter-40;windows_formatname=\"StarWriter 4.0\"", "StarWriter 4.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARWRITER_50
+ FormatEntry("application/x-openoffice-starwriter-50;windows_formatname=\"StarWriter 5.0\"", "StarWriter 5.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARWRITERWEB_40
+ FormatEntry("application/x-openoffice-starwriterweb-40;windows_formatname=\"StarWriter/Web 4.0\"", "StarWriter/Web 4.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARWRITERWEB_50
+ FormatEntry("application/x-openoffice-starwriterweb-50;windows_formatname=\"StarWriter/Web 5.0\"", "StarWriter/Web 5.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARWRITERGLOB_40
+ FormatEntry("application/x-openoffice-starwriterglob-40;windows_formatname=\"StarWriter/Global 4.0\"", "StarWriter/Global 4.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::STARWRITERGLOB_50
+ FormatEntry("application/x-openoffice-starwriterglob-50;windows_formatname=\"StarWriter/Global 5.0\"", "StarWriter/Global 5.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARDRAW
+ FormatEntry("application/x-openoffice-stardraw;windows_formatname=\"StarDrawDocument\"", "StarDrawDocument", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARDRAW_40
+ FormatEntry("application/x-openoffice-stardraw-40;windows_formatname=\"StarDrawDocument 4.0\"", "StarDrawDocument 4.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARIMPRESS_50
+ FormatEntry("application/x-openoffice-starimpress-50;windows_formatname=\"StarImpress 5.0\"", "StarImpress 5.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::STARDRAW_50
+ FormatEntry("application/x-openoffice-stardraw-50;windows_formatname=\"StarDraw 5.0\"", "StarDraw 5.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARCALC
+ FormatEntry("application/x-openoffice-starcalc;windows_formatname=\"StarCalcDocument\"", "StarCalcDocument", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARCALC_40
+ FormatEntry("application/x-openoffice-starcalc-40;windows_formatname=\"StarCalc 4.0\"", "StarCalc 4.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::STARCALC_50
+ FormatEntry("application/x-openoffice-starcalc-50;windows_formatname=\"StarCalc 5.0\"", "StarCalc 5.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::STARCHART
+ FormatEntry("application/x-openoffice-starchart;windows_formatname=\"StarChartDocument\"", "StarChartDocument", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::STARCHART_40
+ FormatEntry("application/x-openoffice-starchart-40;windows_formatname=\"StarChartDocument 4.0\"", "StarChartDocument 4.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::STARCHART_50
+ FormatEntry("application/x-openoffice-starchart-50;windows_formatname=\"StarChart 5.0\"", "StarChart 5.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARIMAGE
+ FormatEntry("application/x-openoffice-starimage;windows_formatname=\"StarImageDocument\"", "StarImageDocument", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARIMAGE_40
+ FormatEntry("application/x-openoffice-starimage-40;windows_formatname=\"StarImageDocument 4.0\"", "StarImageDocument 4.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARIMAGE_50
+ FormatEntry("application/x-openoffice-starimage-50;windows_formatname=\"StarImage 5.0\"", "StarImage 5.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARMATH
+ FormatEntry("application/x-openoffice-starmath;windows_formatname=\"StarMath\"", "StarMath", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARMATH_40
+ FormatEntry("application/x-openoffice-starmath-40;windows_formatname=\"StarMathDocument 4.0\"", "StarMathDocument 4.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARMATH_50
+ FormatEntry("application/x-openoffice-starmath-50;windows_formatname=\"StarMath 5.0\"", "StarMath 5.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STAROBJECT_PAINTDOC
+ FormatEntry("application/x-openoffice-starobject-paintdoc;windows_formatname=\"StarObjectPaintDocument\"", "StarObjectPaintDocument", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::FILLED_AREA
+ FormatEntry("application/x-openoffice-filled-area;windows_formatname=\"FilledArea\"", "FilledArea", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::HTML
+ FormatEntry("text/html", "HTML (HyperText Markup Language)", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::HTML_SIMPLE
+ FormatEntry("application/x-openoffice-html-simple;windows_formatname=\"HTML Format\"", "HTML Format", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::CHAOS
+ FormatEntry("application/x-openoffice-chaos;windows_formatname=\"FORMAT_CHAOS\"", "FORMAT_CHAOS", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::CNT_MSGATTACHFILE
+ FormatEntry("application/x-openoffice-msgattachfile;windows_formatname=\"CNT_MSGATTACHFILE_FORMAT\"", "CNT_MSGATTACHFILE_FORMAT", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::BIFF_5
+ FormatEntry("application/x-openoffice-biff5;windows_formatname=\"Biff5\"", "Biff5", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::BIFF__5
+ FormatEntry("application/x-openoffice-biff-5;windows_formatname=\"Biff 5\"", "Biff 5", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::BIFF_8
+ FormatEntry("application/x-openoffice-biff-8;windows_formatname=\"Biff8\"", "Biff8", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::SYLK_BIGCAPS
+ FormatEntry("application/x-openoffice-sylk-bigcaps;windows_formatname=\"SYLK\"", "SYLK", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::LINK
+ FormatEntry("application/x-openoffice-link;windows_formatname=\"Link\"", "Link", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARDRAW_TABBAR
+ FormatEntry("application/x-openoffice-stardraw-tabbar;windows_formatname=\"StarDraw TabBar\"", "StarDraw TabBar", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::SONLK
+ FormatEntry("application/x-openoffice-sonlk;windows_formatname=\"SONLK (StarOffice Navi Link)\"", "SONLK (StarOffice Navi Link)", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::MSWORD_DOC
+ FormatEntry("application/msword", "MSWordDoc", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STAR_FRAMESET_DOC
+ FormatEntry("application/x-openoffice-star-frameset-doc;windows_formatname=\"StarFrameSetDocument\"", "StarFrameSetDocument", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::OFFICE_DOC
+ FormatEntry("application/x-openoffice-office-doc;windows_formatname=\"OfficeDocument\"", "OfficeDocument", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::NOTES_DOCINFO
+ FormatEntry("application/x-openoffice-notes-docinfo;windows_formatname=\"NotesDocInfo\"", "NotesDocInfo", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::NOTES_HNOTE
+ FormatEntry("application/x-openoffice-notes-hnote;windows_formatname=\"NoteshNote\"", "NoteshNote", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::NOTES_NATIVE
+ FormatEntry("application/x-openoffice-notes-native;windows_formatname=\"Native\"", "Native", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::SFX_DOC
+ FormatEntry("application/x-openoffice-sfx-doc;windows_formatname=\"SfxDocument\"", "SfxDocument", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::EVDF
+ FormatEntry("application/x-openoffice-evdf;windows_formatname=\"EVDF (Explorer View Dummy Format)\"", "EVDF (Explorer View Dummy Format)", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::ESDF
+ FormatEntry("application/x-openoffice-esdf;windows_formatname=\"ESDF (Explorer Search Dummy Format)\"", "ESDF (Explorer Search Dummy Format)", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::IDF
+ FormatEntry("application/x-openoffice-idf;windows_formatname=\"IDF (Iconview Dummy Format)\"", "IDF (Iconview Dummy Format)", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::EFTP
+ FormatEntry("application/x-openoffice-eftp;windows_formatname=\"EFTP (Explorer Ftp File)\"", "EFTP (Explorer Ftp File)", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::EFD
+ FormatEntry("application/x-openoffice-efd;windows_formatname=\"EFD (Explorer Ftp Dir)\"", "EFD (Explorer Ftp Dir)", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::SVX_FORMFIELDEXCH
+ FormatEntry("application/x-openoffice-svx-formfieldexch;windows_formatname=\"SvxFormFieldExch\"", "SvxFormFieldExch", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::EXTENDED_TABBAR
+ FormatEntry("application/x-openoffice-extended-tabbar;windows_formatname=\"ExtendedTabBar\"", "ExtendedTabBar", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::SBA_DATAEXCHANGE
+ FormatEntry("application/x-openoffice-sba-dataexchange;windows_formatname=\"SBA-DATAFORMAT\"", "SBA-DATAFORMAT", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::SBA_FIELDDATAEXCHANGE
+ FormatEntry("application/x-openoffice-sba-fielddataexchange;windows_formatname=\"SBA-FIELDFORMAT\"", "SBA-FIELDFORMAT", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::SBA_PRIVATE_URL
+ FormatEntry("application/x-openoffice-sba-private-url;windows_formatname=\"SBA-PRIVATEURLFORMAT\"", "SBA-PRIVATEURLFORMAT", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::SBA_TABED
+ FormatEntry("application/x-openoffice-sba-tabed;windows_formatname=\"Tabed\"", "Tabed", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::SBA_TABID
+ FormatEntry("application/x-openoffice-sba-tabid;windows_formatname=\"Tabid\"", "Tabid", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::SBA_JOIN
+ FormatEntry("application/x-openoffice-sba-join;windows_formatname=\"SBA-JOINFORMAT\"", "SBA-JOINFORMAT", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::OBJECTDESCRIPTOR
+ FormatEntry("application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"", "Star Object Descriptor (XML)", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::LINKSRCDESCRIPTOR
+ FormatEntry("application/x-openoffice-linksrcdescriptor-xml;windows_formatname=\"Star Link Source Descriptor (XML)\"", "Star Link Source Descriptor (XML)", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::EMBED_SOURCE
+ FormatEntry("application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"", "Star Embed Source (XML)", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::LINK_SOURCE
+ FormatEntry("application/x-openoffice-link-source-xml;windows_formatname=\"Star Link Source (XML)\"", "Star Link Source (XML)", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::EMBEDDED_OBJ
+ FormatEntry("application/x-openoffice-embedded-obj-xml;windows_formatname=\"Star Embedded Object (XML)\"", "Star Embedded Object (XML)", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::FILECONTENT
+ FormatEntry("application/x-openoffice-filecontent;windows_formatname=\"" CFSTR_FILECONTENTS "\"", CFSTR_FILECONTENTS, nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::FILEGRPDESCRIPTOR
+ FormatEntry("application/x-openoffice-filegrpdescriptor;windows_formatname=\"" CFSTR_FILEDESCRIPTOR "\"", CFSTR_FILEDESCRIPTOR, nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::FILENAME
+ FormatEntry("application/x-openoffice-filename;windows_formatname=\"" CFSTR_FILENAME "\"", CFSTR_FILENAME, nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::SD_OLE
+ FormatEntry("application/x-openoffice-sd-ole;windows_formatname=\"SD-OLE\"", "SD-OLE", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::EMBEDDED_OBJ_OLE
+ FormatEntry("application/x-openoffice-embedded-obj-ole;windows_formatname=\"Embedded Object\"", "Embedded Object", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::EMBED_SOURCE_OLE
+ FormatEntry("application/x-openoffice-embed-source-ole;windows_formatname=\"Embed Source\"", "Embed Source", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::OBJECTDESCRIPTOR_OLE
+ FormatEntry("application/x-openoffice-objectdescriptor-ole;windows_formatname=\"Object Descriptor\"", "Object Descriptor", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::LINKSRCDESCRIPTOR_OLE
+ FormatEntry("application/x-openoffice-linkdescriptor-ole;windows_formatname=\"Link Source Descriptor\"", "Link Source Descriptor", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::LINK_SOURCE_OLE
+ FormatEntry("application/x-openoffice-link-source-ole;windows_formatname=\"Link Source\"", "Link Source", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::SBA_CTRLDATAEXCHANGE
+ FormatEntry("application/x-openoffice-sba-ctrldataexchange;windows_formatname=\"SBA-CTRLFORMAT\"", "SBA-CTRLFORMAT", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::OUTPLACE_OBJ
+ FormatEntry("application/x-openoffice-outplace-obj;windows_formatname=\"OutPlace Object\"", "OutPlace Object", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::CNT_OWN_CLIP
+ FormatEntry("application/x-openoffice-cnt-own-clip;windows_formatname=\"CntOwnClipboard\"", "CntOwnClipboard", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::INET_IMAGE
+ FormatEntry("application/x-openoffice-inet-image;windows_formatname=\"SO-INet-Image\"", "SO-INet-Image", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::NETSCAPE_IMAGE
+ FormatEntry("application/x-openoffice-netscape-image;windows_formatname=\"Netscape Image Format\"", "Netscape Image Format", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::SBA_FORMEXCHANGE
+ FormatEntry("application/x-openoffice-sba-formexchange;windows_formatname=\"SBA_FORMEXCHANGE\"", "SBA_FORMEXCHANGE", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::SBA_REPORTEXCHANGE
+ FormatEntry("application/x-openoffice-sba-reportexchange;windows_formatname=\"SBA_REPORTEXCHANGE\"", "SBA_REPORTEXCHANGE", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::UNIFORMRESOURCELOCATOR
+ FormatEntry("application/x-openoffice-uniformresourcelocator;windows_formatname=\"UniformResourceLocatorW\"", "UniformResourceLocator", nullptr, CF_INVALID, CppuType_String),
+ //SotClipboardFormatId::STARCHARTDOCUMENT_50
+ FormatEntry("application/x-openoffice-starchartdocument-50;windows_formatname=\"StarChartDocument 5.0\"", "StarChartDocument 5.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::GRAPHOBJ
+ FormatEntry("application/x-openoffice-graphobj;windows_formatname=\"Graphic Object\"", "Graphic Object", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARWRITER_60
+ FormatEntry("application/vnd.sun.xml.writer", "Writer 6.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARWRITERWEB_60
+ FormatEntry("application/vnd.sun.xml.writer.web", "Writer/Web 6.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARWRITERGLOB_60
+ FormatEntry("application/vnd.sun.xml.writer.global", "Writer/Global 6.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARWDRAW_60
+ FormatEntry("application/vnd.sun.xml.draw", "Draw 6.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARIMPRESS_60
+ FormatEntry("application/vnd.sun.xml.impress", "Impress 6.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARCALC_60
+ FormatEntry("application/vnd.sun.xml.calc", "Calc 6.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARCHART_60
+ FormatEntry("application/vnd.sun.xml.chart", "Chart 6.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::STARMATH_60
+ FormatEntry("application/vnd.sun.xml.math", "Math 6.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::DIALOG_60
+ FormatEntry("application/vnd.sun.xml.dialog", "Dialog 6.0", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::BMP
+ FormatEntry("image/bmp", "Windows Bitmap", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::PNG
+ FormatEntry("image/png", "PNG", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::MATHML
+ FormatEntry("application/mathml+xml", "MathML", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::DUMMY3
+ FormatEntry("application/x-openoffice-dummy3;windows_formatname=\"SO_DUMMYFORMAT_3\"", "SO_DUMMYFORMAT_3", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ //SotClipboardFormatId::DUMMY4
+ FormatEntry("application/x-openoffice-dummy4;windows_formatname=\"SO_DUMMYFORMAT_4\"", "SO_DUMMYFORMAT_4", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ // SotClipboardFormatId::RICHTEXT
+ FormatEntry("text/richtext", "Richtext Format", nullptr, CF_INVALID, CPPUTYPE_DEFAULT),
+ };
+
+namespace {
+
+void findDataFlavorForStandardFormatId( sal_Int32 aStandardFormatId, DataFlavor& aDataFlavor )
+{
+ /*
+ we stop search if we find the first CF_INVALID
+ because in the translation table the entries with a
+ standard clipboard format id appear before the other
+ entries with CF_INVALID
+ */
+ std::vector< FormatEntry >::const_iterator citer = std::find_if(g_TranslTable.begin(), g_TranslTable.end(),
+ [&aStandardFormatId](const FormatEntry& rEntry) {
+ return rEntry.aStandardFormatId == aStandardFormatId
+ || rEntry.aStandardFormatId == CF_INVALID;
+ });
+ if (citer != g_TranslTable.end() && citer->aStandardFormatId == aStandardFormatId)
+ aDataFlavor = citer->aDataFlavor;
+}
+
+void findDataFlavorForNativeFormatName( const OUString& aNativeFormatName, DataFlavor& aDataFlavor )
+{
+ std::vector< FormatEntry >::const_iterator citer = std::find_if(g_TranslTable.begin(), g_TranslTable.end(),
+ [&aNativeFormatName](const FormatEntry& rEntry) {
+ return aNativeFormatName.equalsIgnoreAsciiCase(rEntry.aNativeFormatName); });
+ if (citer != g_TranslTable.end())
+ aDataFlavor = citer->aDataFlavor;
+}
+
+void findStandardFormatIdForCharset( const OUString& aCharset, Any& aAny )
+{
+ if ( aCharset.equalsIgnoreAsciiCase( "utf-16" ) )
+ aAny <<= static_cast< sal_Int32 >( CF_UNICODETEXT );
+ else
+ {
+ sal_Int32 wincp = getWinCPFromMimeCharset( aCharset );
+ if ( IsOEMCP ( wincp ) )
+ aAny <<= static_cast< sal_Int32 >( CF_OEMTEXT );
+ }
+}
+
+void setStandardFormatIdForNativeFormatName( const OUString& aNativeFormatName, Any& aAny )
+{
+ std::vector< FormatEntry >::const_iterator citer = std::find_if(g_TranslTable.begin(), g_TranslTable.end(),
+ [&aNativeFormatName](const FormatEntry& rEntry) {
+ return aNativeFormatName.equalsIgnoreAsciiCase(rEntry.aNativeFormatName)
+ && (CF_INVALID != rEntry.aStandardFormatId);
+ });
+ if (citer != g_TranslTable.end())
+ aAny <<= citer->aStandardFormatId;
+}
+
+void findStdFormatIdOrNativeFormatNameForFullMediaType(
+ const Reference< XMimeContentTypeFactory >& aRefXMimeFactory,
+ const OUString& aFullMediaType,
+ Any& aAny )
+{
+ std::vector< FormatEntry >::const_iterator citer = std::find_if(g_TranslTable.begin(), g_TranslTable.end(),
+ [&aRefXMimeFactory, &aFullMediaType](const FormatEntry& rEntry) {
+ Reference<XMimeContentType> refXMime( aRefXMimeFactory->createMimeContentType(rEntry.aDataFlavor.MimeType) );
+ return aFullMediaType.equalsIgnoreAsciiCase(refXMime->getFullMediaType());
+ });
+ if (citer != g_TranslTable.end())
+ {
+ sal_Int32 cf = citer->aStandardFormatId;
+ if ( CF_INVALID != cf )
+ aAny <<= cf;
+ else
+ {
+ OSL_ENSURE( citer->aNativeFormatName.getLength( ),
+ "Invalid standard format id and empty native format name in translation table" );
+ aAny <<= citer->aNativeFormatName;
+ }
+ }
+}
+
+bool isTextPlainMediaType( std::u16string_view fullMediaType )
+{
+ return o3tl::equalsIgnoreAsciiCase(fullMediaType, u"text/plain");
+}
+
+DataFlavor mkDataFlv(const OUString& cnttype, const OUString& hpname, Type dtype)
+{
+ DataFlavor dflv;
+ dflv.MimeType = cnttype;
+ dflv.HumanPresentableName = hpname;
+ dflv.DataType = dtype;
+ return dflv;
+}
+
+}
+
+CDataFormatTranslatorUNO::CDataFormatTranslatorUNO( const Reference< XComponentContext >& rxContext ) :
+ m_xContext( rxContext )
+{
+}
+
+Any SAL_CALL CDataFormatTranslatorUNO::getSystemDataTypeFromDataFlavor( const DataFlavor& aDataFlavor )
+{
+ Any aAny;
+
+ try
+ {
+ Reference< XMimeContentTypeFactory > refXMimeCntFactory = MimeContentTypeFactory::create( m_xContext );
+
+ Reference< XMimeContentType >
+ refXMimeCntType( refXMimeCntFactory->createMimeContentType( aDataFlavor.MimeType ) );
+
+ OUString fullMediaType = refXMimeCntType->getFullMediaType( );
+ if ( isTextPlainMediaType( fullMediaType ) )
+ {
+ // default is CF_TEXT
+ aAny <<= static_cast< sal_Int32 >( CF_TEXT );
+
+ if ( refXMimeCntType->hasParameter( "charset" ) )
+ {
+ // but maybe it is unicode text or oem text
+ OUString charset = refXMimeCntType->getParameterValue( "charset" );
+ findStandardFormatIdForCharset( charset, aAny );
+ }
+ }
+ else
+ {
+ if (refXMimeCntType->hasParameter(Windows_FormatName))
+ {
+ OUString winfmtname = refXMimeCntType->getParameterValue(Windows_FormatName);
+ aAny <<= winfmtname;
+
+ setStandardFormatIdForNativeFormatName( winfmtname, aAny );
+ }
+ else
+ findStdFormatIdOrNativeFormatNameForFullMediaType( refXMimeCntFactory, fullMediaType, aAny );
+ }
+ }
+ catch( IllegalArgumentException& )
+ {
+ OSL_FAIL( "Invalid content-type detected!" );
+ }
+ catch( NoSuchElementException& )
+ {
+ OSL_FAIL( "Illegal content-type parameter" );
+ }
+ catch( ... )
+ {
+ OSL_FAIL( "Unexpected error" );
+ throw;
+ }
+
+ return aAny;
+}
+
+DataFlavor SAL_CALL CDataFormatTranslatorUNO::getDataFlavorFromSystemDataType( const Any& aSysDataType )
+{
+ OSL_PRECOND( aSysDataType.hasValue( ), "Empty system data type delivered" );
+
+ DataFlavor aFlavor = mkDataFlv( OUString(), OUString(), CPPUTYPE_SEQSALINT8 );
+
+ if ( aSysDataType.getValueType( ) == cppu::UnoType<sal_Int32>::get() )
+ {
+ sal_Int32 clipformat = CF_INVALID;
+ aSysDataType >>= clipformat;
+ if ( CF_INVALID != clipformat )
+ findDataFlavorForStandardFormatId( clipformat, aFlavor );
+ }
+ else if ( aSysDataType.getValueType( ) == cppu::UnoType<OUString>::get() )
+ {
+ OUString nativeFormatName;
+ aSysDataType >>= nativeFormatName;
+
+ findDataFlavorForNativeFormatName( nativeFormatName, aFlavor );
+ }
+ else
+ OSL_FAIL( "Invalid data type received" );
+
+ return aFlavor;
+}
+
+// XServiceInfo
+
+OUString SAL_CALL CDataFormatTranslatorUNO::getImplementationName( )
+{
+ return "com.sun.star.datatransfer.DataFormatTranslator";
+}
+
+sal_Bool SAL_CALL CDataFormatTranslatorUNO::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Sequence< OUString > SAL_CALL CDataFormatTranslatorUNO::getSupportedServiceNames( )
+{
+ return { "com.sun.star.datatransfer.DataFormatTranslator" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+dtrans_CDataFormatTranslatorUNO_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new CDataFormatTranslatorUNO(context));
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/ftransl.hxx b/vcl/win/dtrans/ftransl.hxx
new file mode 100644
index 000000000..7a5041be5
--- /dev/null
+++ b/vcl/win/dtrans/ftransl.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/datatransfer/XDataFormatTranslator.hpp>
+#include <com/sun/star/datatransfer/XMimeContentTypeFactory.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include "WinClip.hxx"
+
+#include <vector>
+
+class CDataFormatTranslatorUNO : public
+ cppu::WeakImplHelper< css::datatransfer::XDataFormatTranslator,
+ css::lang::XServiceInfo >
+{
+
+public:
+ explicit CDataFormatTranslatorUNO( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+
+ // XDataFormatTranslator
+
+ virtual css::uno::Any SAL_CALL getSystemDataTypeFromDataFlavor( const css::datatransfer::DataFlavor& aDataFlavor ) override;
+
+ virtual css::datatransfer::DataFlavor SAL_CALL getDataFlavorFromSystemDataType( const css::uno::Any& aSysDataType ) override;
+
+ // XServiceInfo
+
+ virtual OUString SAL_CALL getImplementationName( ) override;
+
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+private:
+ const css::uno::Reference< css::uno::XComponentContext > m_xContext;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/generic_clipboard.cxx b/vcl/win/dtrans/generic_clipboard.cxx
new file mode 100644
index 000000000..a614a6808
--- /dev/null
+++ b/vcl/win/dtrans/generic_clipboard.cxx
@@ -0,0 +1,146 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "generic_clipboard.hxx"
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/datatransfer/clipboard/RenderingCapabilities.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::datatransfer::clipboard;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace cppu;
+using namespace osl;
+
+using ::dtrans::GenericClipboard;
+
+GenericClipboard::GenericClipboard() :
+ WeakComponentImplHelper< XClipboardEx, XClipboardNotifier, XServiceInfo, XInitialization > (m_aMutex),
+ m_bInitialized(false)
+{
+}
+
+GenericClipboard::~GenericClipboard()
+{
+}
+
+void SAL_CALL GenericClipboard::initialize( const Sequence< Any >& aArguments )
+{
+ if (!m_bInitialized)
+ {
+ for (Any const & arg : aArguments)
+ if (arg.getValueType() == cppu::UnoType<OUString>::get())
+ {
+ arg >>= m_aName;
+ break;
+ }
+ }
+}
+
+OUString SAL_CALL GenericClipboard::getImplementationName( )
+{
+ return "com.sun.star.comp.datatransfer.clipboard.GenericClipboard";
+}
+
+sal_Bool SAL_CALL GenericClipboard::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Sequence< OUString > SAL_CALL GenericClipboard::getSupportedServiceNames( )
+{
+ return { "com.sun.star.datatransfer.clipboard.GenericClipboard" };
+}
+
+Reference< XTransferable > SAL_CALL GenericClipboard::getContents()
+{
+ MutexGuard aGuard(m_aMutex);
+ return m_aContents;
+}
+
+void SAL_CALL GenericClipboard::setContents(const Reference< XTransferable >& xTrans,
+ const Reference< XClipboardOwner >& xClipboardOwner )
+{
+ // remember old values for callbacks before setting the new ones.
+ ClearableMutexGuard aGuard(m_aMutex);
+
+ Reference< XClipboardOwner > oldOwner(m_aOwner);
+ m_aOwner = xClipboardOwner;
+
+ Reference< XTransferable > oldContents(m_aContents);
+ m_aContents = xTrans;
+
+ aGuard.clear();
+
+ // notify old owner on loss of ownership
+ if( oldOwner.is() )
+ oldOwner->lostOwnership(static_cast < XClipboard * > (this), oldContents);
+
+ // notify all listeners on content changes
+ OInterfaceContainerHelper *pContainer =
+ rBHelper.aLC.getContainer(cppu::UnoType<XClipboardListener>::get());
+ if (pContainer)
+ {
+ ClipboardEvent aEvent(static_cast < XClipboard * > (this), m_aContents);
+ OInterfaceIteratorHelper aIterator(*pContainer);
+
+ while (aIterator.hasMoreElements())
+ {
+ static_cast<XClipboardListener*>(aIterator.next())->changedContents(aEvent);
+ }
+ }
+}
+
+OUString SAL_CALL GenericClipboard::getName()
+{
+ return m_aName;
+}
+
+sal_Int8 SAL_CALL GenericClipboard::getRenderingCapabilities()
+{
+ return RenderingCapabilities::Delayed;
+}
+
+void SAL_CALL GenericClipboard::addClipboardListener( const Reference< XClipboardListener >& listener )
+{
+ MutexGuard aGuard( rBHelper.rMutex );
+ OSL_ENSURE( !rBHelper.bInDispose, "do not add listeners in the dispose call" );
+ OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
+ if (!rBHelper.bInDispose && !rBHelper.bDisposed)
+ rBHelper.aLC.addInterface( cppu::UnoType<XClipboardListener>::get(), listener );
+}
+
+void SAL_CALL GenericClipboard::removeClipboardListener( const Reference< XClipboardListener >& listener )
+{
+ MutexGuard aGuard( rBHelper.rMutex );
+ OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
+ if (!rBHelper.bInDispose && !rBHelper.bDisposed)
+ rBHelper.aLC.removeInterface( cppu::UnoType<XClipboardListener>::get(), listener );
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+dtrans_GenericClipboard_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new GenericClipboard());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/generic_clipboard.hxx b/vcl/win/dtrans/generic_clipboard.hxx
new file mode 100644
index 000000000..3c9126bcc
--- /dev/null
+++ b/vcl/win/dtrans/generic_clipboard.hxx
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cppuhelper/compbase.hxx>
+
+#include <com/sun/star/datatransfer/clipboard/XClipboardEx.hpp>
+
+#include <com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+
+namespace dtrans
+{
+
+ class GenericClipboard : public ::cppu::WeakComponentImplHelper <
+ css::datatransfer::clipboard::XClipboardEx,
+ css::datatransfer::clipboard::XClipboardNotifier,
+ css::lang::XServiceInfo,
+ css::lang::XInitialization >
+ {
+ ::osl::Mutex m_aMutex;
+ OUString m_aName;
+
+ css::uno::Reference< css::datatransfer::XTransferable > m_aContents;
+ css::uno::Reference< css::datatransfer::clipboard::XClipboardOwner > m_aOwner;
+
+ bool m_bInitialized;
+ virtual ~GenericClipboard() override;
+
+ public:
+
+ GenericClipboard();
+
+ /*
+ * XInitialization
+ */
+
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ /*
+ * XServiceInfo
+ */
+
+ virtual OUString SAL_CALL getImplementationName( ) override;
+
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ /*
+ * XClipboard
+ */
+
+ virtual css::uno::Reference< css::datatransfer::XTransferable > SAL_CALL getContents() override;
+
+ virtual void SAL_CALL setContents(
+ const css::uno::Reference< css::datatransfer::XTransferable >& xTrans,
+ const css::uno::Reference< css::datatransfer::clipboard::XClipboardOwner >& xClipboardOwner ) override;
+
+ virtual OUString SAL_CALL getName() override;
+
+ /*
+ * XClipboardEx
+ */
+
+ virtual sal_Int8 SAL_CALL getRenderingCapabilities() override;
+
+ /*
+ * XClipboardNotifier
+ */
+
+ virtual void SAL_CALL addClipboardListener(
+ const css::uno::Reference< css::datatransfer::clipboard::XClipboardListener >& listener ) override;
+
+ virtual void SAL_CALL removeClipboardListener(
+ const css::uno::Reference< css::datatransfer::clipboard::XClipboardListener >& listener ) override;
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/globals.cxx b/vcl/win/dtrans/globals.cxx
new file mode 100644
index 000000000..fcddef22e
--- /dev/null
+++ b/vcl/win/dtrans/globals.cxx
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
+
+#include "globals.hxx"
+
+//--> TRA
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+
+// used as shortcut when drag-source and drop-target are the same
+css::uno::Reference< css::datatransfer::XTransferable > g_XTransferable;
+
+//<-- TRA
+
+using namespace com::sun::star::datatransfer::dnd::DNDConstants;
+
+sal_Int8 dndOleKeysToAction( DWORD grfKeyState, sal_Int8 nSourceActions)
+{
+ sal_Int8 ret= 0;
+
+ // no MK_ALT, MK_CONTROL, MK_SHIFT
+ if( !(grfKeyState & MK_CONTROL) &&
+ !(grfKeyState & MK_ALT) &&
+ !(grfKeyState & MK_RBUTTON) &&
+ !(grfKeyState & MK_SHIFT))
+ {
+ if( nSourceActions & ACTION_MOVE )
+ {
+ ret= ACTION_DEFAULT | ACTION_MOVE;
+ }
+
+ else if( nSourceActions & ACTION_COPY )
+ {
+ ret= ACTION_COPY;
+ }
+
+ else if( nSourceActions & ACTION_LINK )
+ {
+ ret= ACTION_LINK;
+ }
+
+ else
+ ret = 0;
+ }
+ else if( grfKeyState & MK_SHIFT &&
+ !(grfKeyState & MK_CONTROL))
+ {
+ ret= ACTION_MOVE;
+ }
+ else if ( grfKeyState & MK_CONTROL &&
+ !(grfKeyState & MK_SHIFT) )
+ {
+ ret= ACTION_COPY;
+ }
+ else if ( grfKeyState & MK_CONTROL &&
+ grfKeyState & MK_SHIFT)
+ {
+ ret= ACTION_LINK;
+ }
+ else if ( grfKeyState & MK_RBUTTON ||
+ grfKeyState & MK_ALT)
+ {
+ ret= ACTION_COPY_OR_MOVE | ACTION_LINK;
+ }
+ return ret;
+}
+
+sal_Int8 dndOleDropEffectsToActions( DWORD dwEffect)
+{
+ sal_Int8 ret= ACTION_NONE;
+ if( dwEffect & DROPEFFECT_COPY)
+ ret |= ACTION_COPY;
+ if( dwEffect & DROPEFFECT_MOVE)
+ ret |= ACTION_MOVE;
+ if( dwEffect & DROPEFFECT_LINK)
+ ret |= ACTION_LINK;
+
+ return ret;
+}
+
+DWORD dndActionsToDropEffects( sal_Int8 actions)
+{
+ DWORD ret= DROPEFFECT_NONE;
+ if( actions & ACTION_MOVE)
+ ret |= DROPEFFECT_MOVE;
+ if( actions & ACTION_COPY)
+ ret |= DROPEFFECT_COPY;
+ if( actions & ACTION_LINK)
+ ret |= DROPEFFECT_LINK;
+ if( actions & ACTION_DEFAULT)
+ ret |= DROPEFFECT_COPY;
+ return ret;
+}
+
+DWORD dndActionsToSingleDropEffect( sal_Int8 actions)
+{
+ DWORD effects= dndActionsToDropEffects( actions);
+
+ sal_Int8 countEffect= 0;
+
+ if( effects & DROPEFFECT_MOVE)
+ countEffect++;
+ if( effects & DROPEFFECT_COPY)
+ countEffect++;
+ if( effects & DROPEFFECT_LINK)
+ countEffect++;
+
+ // DROPEFFECT_MOVE is the default effect
+ DWORD retVal= countEffect > 1 ? DROPEFFECT_MOVE : effects;
+ return retVal;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/globals.hxx b/vcl/win/dtrans/globals.hxx
new file mode 100644
index 000000000..9bb174d0b
--- /dev/null
+++ b/vcl/win/dtrans/globals.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <osl/mutex.hxx>
+
+namespace com::sun::star::datatransfer
+{
+class XTransferable;
+}
+
+#include <wtypes.h>
+#include <sal/types.h>
+
+// This maps key states as occur as parameter, e.g. in IDropTarget::DragEnter,
+// IDropSource::QueryContinueDrag, to actions as are declared in
+// css::datatransfer::dnd::DNDConstants ( ACTION_MOVE etc).
+// If the grfKeyState indicates the ALt or right mousebutton then the returned
+// values combines all possible actions. This is because those keys and buttons are
+// used when the user expect a menu to appear when he drops. The menu then
+// contains entries, such as move, copy, link, cancel.
+// An odd fact is that the argument grfKeyState in IDropTarget::Drop does not
+// contain mouse buttons (winnt 4 SP6). That indicates that the right mouse button
+// is not considered relevant in a drag operation. Contrarily the file explorer
+// gives that button a special meaning: the user has to select the effect from
+// a context menu on drop.
+sal_Int8 dndOleKeysToAction(DWORD grfKeyState, sal_Int8 sourceActions);
+
+// The function maps a windows DROPEFFECTs to actions
+// ( css::datatransfer::dnd::DNDConstants).
+// The argument can be a combination of different DROPEFFECTS,
+// In that case the return value is also a combination of the
+// appropriate actions.
+sal_Int8 dndOleDropEffectsToActions(DWORD dwEffect);
+
+// The function maps actions ( css::datatransfer::dnd::DNDConstants)
+// to window DROPEFFECTs.
+// The argument can be a combination of different actions
+// In that case the return value is also a combination of the
+// appropriate DROPEFFECTS.
+DWORD dndActionsToDropEffects(sal_Int8 actions);
+
+// If the argument constitutes only one action then it is mapped to the
+// corresponding DROPEFFECT otherwise DROPEFFECT_MOVE is returned. This is
+// why move is the default effect (no modifiers pressed, or right mouse button
+// or Alt).
+DWORD dndActionsToSingleDropEffect(sal_Int8 actions);
+
+extern css::uno::Reference<css::datatransfer::XTransferable> g_XTransferable;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/idroptarget.cxx b/vcl/win/dtrans/idroptarget.cxx
new file mode 100644
index 000000000..8b403eb7a
--- /dev/null
+++ b/vcl/win/dtrans/idroptarget.cxx
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "idroptarget.hxx"
+
+IDropTargetImpl::IDropTargetImpl( DropTarget& pTarget): m_nRefCount( 0),
+ m_rDropTarget( pTarget)
+{
+}
+
+IDropTargetImpl::~IDropTargetImpl()
+{
+}
+
+//IDropTarget
+HRESULT STDMETHODCALLTYPE IDropTargetImpl::QueryInterface( REFIID riid, void **ppvObject)
+{
+ if( !ppvObject)
+ return E_POINTER;
+ *ppvObject= nullptr;
+
+ if( riid == __uuidof( IUnknown))
+ *ppvObject= static_cast<IUnknown*>( this);
+ else if ( riid == __uuidof( IDropTarget))
+ *ppvObject= static_cast<IDropTarget*>( this);
+
+ if(*ppvObject)
+ {
+ AddRef();
+ return S_OK;
+ }
+ else
+ return E_NOINTERFACE;
+
+}
+
+ULONG STDMETHODCALLTYPE IDropTargetImpl::AddRef()
+{
+ return InterlockedIncrement( &m_nRefCount);
+}
+
+ULONG STDMETHODCALLTYPE IDropTargetImpl::Release()
+{
+ LONG count= InterlockedDecrement( &m_nRefCount);
+ if( m_nRefCount == 0 )
+ delete this;
+ return count;
+}
+
+STDMETHODIMP IDropTargetImpl::DragEnter( IDataObject __RPC_FAR *pDataObj,
+ DWORD grfKeyState,
+ POINTL pt,
+ DWORD *pdwEffect)
+{
+ return m_rDropTarget.DragEnter( pDataObj, grfKeyState,
+ pt, pdwEffect);
+}
+
+STDMETHODIMP IDropTargetImpl::DragOver( DWORD grfKeyState,
+ POINTL pt,
+ DWORD *pdwEffect)
+{
+ return m_rDropTarget.DragOver( grfKeyState, pt, pdwEffect);
+}
+
+STDMETHODIMP IDropTargetImpl::DragLeave()
+{
+ return m_rDropTarget.DragLeave();
+}
+
+STDMETHODIMP IDropTargetImpl::Drop( IDataObject *pDataObj,
+ DWORD grfKeyState,
+ POINTL pt,
+ DWORD __RPC_FAR *pdwEffect)
+{
+ return m_rDropTarget.Drop( pDataObj, grfKeyState,
+ pt, pdwEffect);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/idroptarget.hxx b/vcl/win/dtrans/idroptarget.hxx
new file mode 100644
index 000000000..5871373c6
--- /dev/null
+++ b/vcl/win/dtrans/idroptarget.hxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <win/dnd_target.hxx>
+
+class IDropTargetImpl: public IDropTarget
+{
+ LONG m_nRefCount;
+ // Calls to IDropTarget functions are delegated to a DropTarget.
+ DropTarget& m_rDropTarget;
+
+ virtual ~IDropTargetImpl(); // delete is only called by IUnknown::Release
+ IDropTargetImpl( const IDropTargetImpl& );
+ IDropTargetImpl& operator=( const IDropTargetImpl& );
+public:
+ explicit IDropTargetImpl(DropTarget& rTarget);
+
+ // IDropTarget
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(
+ /* [in] */ REFIID riid,
+ /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject) override;
+
+ virtual ULONG STDMETHODCALLTYPE AddRef( ) override;
+
+ virtual ULONG STDMETHODCALLTYPE Release( ) override;
+
+ virtual HRESULT STDMETHODCALLTYPE DragEnter(
+ /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
+ /* [in] */ DWORD grfKeyState,
+ /* [in] */ POINTL pt,
+ /* [out][in] */ DWORD __RPC_FAR *pdwEffect) override;
+
+ virtual HRESULT STDMETHODCALLTYPE DragOver(
+ /* [in] */ DWORD grfKeyState,
+ /* [in] */ POINTL pt,
+ /* [out][in] */ DWORD __RPC_FAR *pdwEffect) override;
+
+ virtual HRESULT STDMETHODCALLTYPE DragLeave( ) override;
+
+ virtual HRESULT STDMETHODCALLTYPE Drop(
+ /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
+ /* [in] */ DWORD grfKeyState,
+ /* [in] */ POINTL pt,
+ /* [out][in] */ DWORD __RPC_FAR *pdwEffect) override;
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/source.cxx b/vcl/win/dtrans/source.cxx
new file mode 100644
index 000000000..d91e39b02
--- /dev/null
+++ b/vcl/win/dtrans/source.cxx
@@ -0,0 +1,373 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/awt/MouseButton.hpp>
+#include <com/sun/star/awt/MouseEvent.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <o3tl/any.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <process.h>
+#include <memory>
+
+#include <win/dnd_source.hxx>
+#include "globals.hxx"
+#include "sourcecontext.hxx"
+#include "DtObjFactory.hxx"
+
+#include <rtl/ustring.h>
+#include <osl/thread.h>
+#include <winuser.h>
+#include <stdio.h>
+
+using namespace cppu;
+using namespace osl;
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::datatransfer::dnd;
+using namespace com::sun::star::datatransfer::dnd::DNDConstants;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::awt::MouseButton;
+using namespace com::sun::star::awt;
+using namespace com::sun::star::lang;
+
+static DWORD WINAPI DndOleSTAFunc(_In_ LPVOID pParams);
+
+DragSource::DragSource( const Reference<XComponentContext>& rxContext):
+ WeakComponentImplHelper< XDragSource, XInitialization, XServiceInfo >(m_aMutex),
+ m_xContext( rxContext ),
+// m_pcurrentContext_impl(0),
+ m_hAppWindow(nullptr),
+ m_MouseButton(0),
+ m_RunningDndOperationCount(0)
+{
+}
+
+DragSource::~DragSource()
+{
+}
+
+/** First start a new drag and drop thread if
+ the last one has finished
+
+ ????
+ Do we really need a separate thread for
+ every Dnd operation or only if the source
+ thread is an MTA thread
+ ????
+*/
+void DragSource::StartDragImpl(
+ const DragGestureEvent& trigger,
+ sal_Int8 sourceActions,
+ sal_Int32 /*cursor*/,
+ sal_Int32 /*image*/,
+ const Reference<XTransferable >& trans,
+ const Reference<XDragSourceListener >& listener )
+{
+ // The actions supported by the drag source
+ m_sourceActions= sourceActions;
+ // We need to know which mouse button triggered the operation.
+ // If it was the left one, then the drop occurs when that button
+ // has been released and if it was the right one then the drop
+ // occurs when the right button has been released. If the event is not
+ // set then we assume that the left button is pressed.
+ MouseEvent evtMouse;
+ trigger.Event >>= evtMouse;
+ m_MouseButton= evtMouse.Buttons;
+
+ // The SourceContext class administers the XDragSourceListener s and
+ // fires events to them. An instance only exists in the scope of this
+ // function. However, the drag and drop operation causes callbacks
+ // to the IDropSource interface implemented in this class (but only
+ // while this function executes). The source context is also used
+ // in DragSource::QueryContinueDrag.
+ m_currentContext = new SourceContext(this, listener);
+
+ // Convert the XTransferable data object into an IDataObject object;
+
+ //--> TRA
+ g_XTransferable = trans;
+ //<-- TRA
+
+ m_spDataObject= CDTransObjFactory::createDataObjFromTransferable(
+ m_xContext, trans);
+
+ // Obtain the id of the thread that created the window
+ DWORD processId;
+ m_threadIdWindow= GetWindowThreadProcessId( m_hAppWindow, &processId);
+
+ // hold the instance for the DnD thread, it's too late
+ // to acquire at the start of the thread procedure
+ // the thread procedure is responsible for the release
+ acquire();
+
+ // The thread accesses members of this instance but does not call acquire.
+ // Hopefully this instance is not destroyed before the thread has terminated.
+ DWORD threadId;
+ HANDLE hThread = CreateThread(nullptr, 0, DndOleSTAFunc, this, 0, &threadId);
+
+ // detach from thread
+ CloseHandle(hThread);
+}
+
+// XInitialization
+/** aArguments contains a machine id */
+void SAL_CALL DragSource::initialize( const Sequence< Any >& aArguments )
+{
+ if( aArguments.getLength() >=2)
+ m_hAppWindow= reinterpret_cast<HWND>(static_cast<sal_uIntPtr>(*o3tl::doAccess<sal_uInt64>(aArguments[1])));
+ OSL_ASSERT( IsWindow( m_hAppWindow) );
+}
+
+/** XDragSource */
+sal_Bool SAL_CALL DragSource::isDragImageSupported( )
+{
+ return false;
+}
+
+sal_Int32 SAL_CALL DragSource::getDefaultCursor( sal_Int8 /*dragAction*/ )
+{
+ return 0;
+}
+
+/** Notifies the XDragSourceListener by
+ calling dragDropEnd */
+void SAL_CALL DragSource::startDrag(
+ const DragGestureEvent& trigger,
+ sal_Int8 sourceActions,
+ sal_Int32 cursor,
+ sal_Int32 image,
+ const Reference<XTransferable >& trans,
+ const Reference<XDragSourceListener >& listener )
+{
+ // Allow only one running dnd operation at a time,
+ // see XDragSource documentation
+
+ LONG cnt = InterlockedIncrement(&m_RunningDndOperationCount);
+
+ if (1 == cnt)
+ {
+ StartDragImpl(trigger, sourceActions, cursor, image, trans, listener);
+ }
+ else
+ {
+ cnt = InterlockedDecrement(&m_RunningDndOperationCount);
+
+ DragSourceDropEvent dsde;
+
+ dsde.DropAction = ACTION_NONE;
+ dsde.DropSuccess = false;
+
+ try
+ {
+ listener->dragDropEnd(dsde);
+ }
+ catch(RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION( "vcl", "Runtime exception during event dispatching");
+ }
+ }
+}
+
+/** IDropTarget */
+HRESULT STDMETHODCALLTYPE DragSource::QueryInterface( REFIID riid, void **ppvObject)
+{
+ if( !ppvObject)
+ return E_POINTER;
+ *ppvObject= nullptr;
+
+ if( riid == __uuidof( IUnknown) )
+ *ppvObject= static_cast<IUnknown*>( this);
+ else if ( riid == __uuidof( IDropSource) )
+ *ppvObject= static_cast<IDropSource*>( this);
+
+ if(*ppvObject)
+ {
+ AddRef();
+ return S_OK;
+ }
+ else
+ return E_NOINTERFACE;
+
+}
+
+ULONG STDMETHODCALLTYPE DragSource::AddRef()
+{
+ acquire();
+ return static_cast<ULONG>(m_refCount);
+}
+
+ULONG STDMETHODCALLTYPE DragSource::Release()
+{
+ ULONG ref= m_refCount;
+ release();
+ return --ref;
+}
+
+/** IDropSource */
+HRESULT STDMETHODCALLTYPE DragSource::QueryContinueDrag(
+/* [in] */ BOOL fEscapePressed,
+/* [in] */ DWORD grfKeyState)
+{
+#if defined DBG_CONSOLE_OUT
+ printf("\nDragSource::QueryContinueDrag");
+#endif
+
+ HRESULT retVal= S_OK; // default continue DnD
+
+ if (fEscapePressed)
+ {
+ retVal= DRAGDROP_S_CANCEL;
+ }
+ else
+ {
+ if( ( m_MouseButton == MouseButton::RIGHT && !(grfKeyState & MK_RBUTTON) ) ||
+ ( m_MouseButton == MouseButton::MIDDLE && !(grfKeyState & MK_MBUTTON) ) ||
+ ( m_MouseButton == MouseButton::LEFT && !(grfKeyState & MK_LBUTTON) ) ||
+ ( m_MouseButton == 0 && !(grfKeyState & MK_LBUTTON) ) )
+ {
+ retVal= DRAGDROP_S_DROP;
+ }
+ }
+
+ // fire dropActionChanged event.
+ // this is actually done by the context, which also detects whether the action
+ // changed at all
+ sal_Int8 dropAction= fEscapePressed ? ACTION_NONE :
+ dndOleKeysToAction( grfKeyState, m_sourceActions);
+
+ sal_Int8 userAction= fEscapePressed ? ACTION_NONE :
+ dndOleKeysToAction( grfKeyState, -1 );
+
+ static_cast<SourceContext*>(m_currentContext.get())->fire_dropActionChanged(
+ dropAction, userAction);
+
+ return retVal;
+}
+
+HRESULT STDMETHODCALLTYPE DragSource::GiveFeedback(
+/* [in] */ DWORD
+#if defined DBG_CONSOLE_OUT
+dwEffect
+#endif
+)
+{
+#if defined DBG_CONSOLE_OUT
+ printf("\nDragSource::GiveFeedback %d", dwEffect);
+#endif
+
+ return DRAGDROP_S_USEDEFAULTCURSORS;
+}
+
+// XServiceInfo
+OUString SAL_CALL DragSource::getImplementationName( )
+{
+ return "com.sun.star.comp.datatransfer.dnd.OleDragSource_V1";
+}
+// XServiceInfo
+sal_Bool SAL_CALL DragSource::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Sequence< OUString > SAL_CALL DragSource::getSupportedServiceNames( )
+{
+ return { "com.sun.star.datatransfer.dnd.OleDragSource" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+dtrans_DragSource_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new DragSource(context));
+}
+
+/** This function is called as extra thread from
+ DragSource::executeDrag. The function
+ carries out a drag and drop operation by calling
+ DoDragDrop. The thread also notifies all
+ XSourceListener. */
+DWORD WINAPI DndOleSTAFunc(_In_ LPVOID pParams)
+{
+ osl_setThreadName("DragSource DndOleSTAFunc");
+
+ // The structure contains all arguments for DoDragDrop and other
+ DragSource *pSource= static_cast<DragSource*>(pParams);
+
+ // Drag and drop only works in a thread in which OleInitialize is called.
+ HRESULT hr= OleInitialize( nullptr);
+
+ if(SUCCEEDED(hr))
+ {
+ // We force the creation of a thread message queue. This is necessary
+ // for a later call to AttachThreadInput
+ MSG msgtemp;
+ PeekMessageW( &msgtemp, nullptr, WM_USER, WM_USER, PM_NOREMOVE);
+
+ DWORD threadId= GetCurrentThreadId();
+
+ // This thread is attached to the thread that created the window. Hence
+ // this thread also receives all mouse and keyboard messages which are
+ // needed by DoDragDrop
+ AttachThreadInput( threadId , pSource->m_threadIdWindow, TRUE );
+
+ DWORD dwEffect= 0;
+ hr= DoDragDrop(
+ pSource->m_spDataObject.get(),
+ static_cast<IDropSource*>(pSource),
+ dndActionsToDropEffects( pSource->m_sourceActions),
+ &dwEffect);
+
+ // #105428 detach my message queue from the other threads
+ // message queue before calling fire_dragDropEnd else
+ // the office may appear to hang sometimes
+ AttachThreadInput( threadId, pSource->m_threadIdWindow, FALSE);
+
+ //--> TRA
+ // clear the global transferable again
+ g_XTransferable.clear();
+ //<-- TRA
+
+ OSL_ENSURE( hr != E_INVALIDARG, "IDataObject impl does not contain valid data");
+
+ //Fire event
+ sal_Int8 action= hr == DRAGDROP_S_DROP ? dndOleDropEffectsToActions( dwEffect) : ACTION_NONE;
+
+ static_cast<SourceContext*>(pSource->m_currentContext.get())->fire_dragDropEnd(
+ hr == DRAGDROP_S_DROP, action);
+
+ // Destroy SourceContextslkfgj
+ pSource->m_currentContext= nullptr;
+ // Destroy the XTransferable wrapper
+ pSource->m_spDataObject=nullptr;
+
+ OleUninitialize();
+ }
+
+ InterlockedDecrement(&pSource->m_RunningDndOperationCount);
+
+ // the DragSource was manually acquired by
+ // thread starting method DelayedStartDrag
+ pSource->release();
+
+ return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/sourcecontext.cxx b/vcl/win/dtrans/sourcecontext.cxx
new file mode 100644
index 000000000..c0e6371c5
--- /dev/null
+++ b/vcl/win/dtrans/sourcecontext.cxx
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
+
+#include "sourcecontext.hxx"
+
+using namespace com::sun::star::datatransfer::dnd;
+using namespace com::sun::star::datatransfer::dnd::DNDConstants;
+
+SourceContext::SourceContext( DragSource* pSource,
+ const Reference<XDragSourceListener>& listener):
+ WeakComponentImplHelper<XDragSourceContext>(m_aMutex),
+ m_pDragSource( pSource),
+ m_dragSource( static_cast<XDragSource*>( m_pDragSource) )
+{
+#if OSL_DEBUG_LEVEL > 1
+ if( listener.is())
+#endif
+ rBHelper.addListener( cppu::UnoType<decltype(listener)>::get(), listener );
+}
+
+SourceContext::~SourceContext()
+{
+}
+
+void SourceContext::addDragSourceListener(
+ const Reference<XDragSourceListener >& )
+{
+}
+
+void SourceContext::removeDragSourceListener(
+ const Reference<XDragSourceListener >& )
+{
+}
+
+sal_Int32 SAL_CALL SourceContext::getCurrentCursor( )
+{
+ return 0;
+}
+
+void SAL_CALL SourceContext::setCursor( sal_Int32 /*cursorId*/ )
+{
+}
+
+void SAL_CALL SourceContext::setImage( sal_Int32 /*imageId*/ )
+{
+}
+
+void SAL_CALL SourceContext::transferablesFlavorsChanged( )
+{
+}
+
+// non -interface functions
+// Fires XDragSourceListener::dragDropEnd events.
+void SourceContext::fire_dragDropEnd( bool success, sal_Int8 effect)
+{
+
+ DragSourceDropEvent e;
+
+ if( success )
+ {
+ e.DropAction= effect;
+ e.DropSuccess= true;
+ }
+ else
+ {
+ e.DropAction= ACTION_NONE;
+ e.DropSuccess= false;
+ }
+ e.DragSource= m_dragSource;
+ e.DragSourceContext= static_cast<XDragSourceContext*>( this);
+ e.Source.set( static_cast<XDragSourceContext*>( this), UNO_QUERY);
+
+ OInterfaceContainerHelper* pContainer= rBHelper.getContainer(
+ cppu::UnoType<XDragSourceListener>::get());
+
+ if( pContainer)
+ {
+ OInterfaceIteratorHelper iter( *pContainer);
+ while( iter.hasMoreElements())
+ {
+ Reference<XDragSourceListener> listener(
+ static_cast<XDragSourceListener*>( iter.next()));
+ listener->dragDropEnd( e);
+ }
+ }
+}
+
+void SourceContext::fire_dropActionChanged( sal_Int8 dropAction, sal_Int8 userAction)
+{
+ if( m_currentAction != dropAction)
+ {
+ m_currentAction= dropAction;
+ DragSourceDragEvent e;
+ e.DropAction= dropAction;
+ e.UserAction= userAction;
+ e.DragSource= m_dragSource;
+ e.DragSourceContext= static_cast<XDragSourceContext*>( this);
+ e.Source.set( static_cast<XDragSourceContext*>( this), UNO_QUERY);
+
+ OInterfaceContainerHelper* pContainer= rBHelper.getContainer(
+ cppu::UnoType<XDragSourceListener>::get());
+
+ if( pContainer)
+ {
+ OInterfaceIteratorHelper iter( *pContainer);
+ while( iter.hasMoreElements())
+ {
+ Reference<XDragSourceListener> listener(
+ static_cast<XDragSourceListener*>( iter.next()));
+ listener->dropActionChanged( e);
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/sourcecontext.hxx b/vcl/win/dtrans/sourcecontext.hxx
new file mode 100644
index 000000000..447174795
--- /dev/null
+++ b/vcl/win/dtrans/sourcecontext.hxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/datatransfer/dnd/XDragSourceContext.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+
+#include <win/dnd_source.hxx>
+
+using namespace ::com::sun::star::datatransfer;
+using namespace ::com::sun::star::datatransfer::dnd;
+using namespace ::cppu;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+
+// This class fires events to XDragSourceListener implementations.
+// Of that interface only dragDropEnd and dropActionChanged are called.
+// The functions dragEnter, dragExit and dragOver are not supported
+// currently.
+// An instance of SourceContext only lives as long as the drag and drop
+// operation lasts.
+class SourceContext : public cppu::BaseMutex, public WeakComponentImplHelper<XDragSourceContext>
+{
+ DragSource* m_pDragSource;
+ Reference<XDragSource> m_dragSource;
+ // the action ( copy, move etc)
+ sal_Int8 m_currentAction;
+
+public:
+ SourceContext(DragSource* pSource, const Reference<XDragSourceListener>& listener);
+ ~SourceContext() override;
+ SourceContext(const SourceContext&) = delete;
+ SourceContext& operator=(const SourceContext&) = delete;
+
+ /// @throws RuntimeException
+ virtual void addDragSourceListener(const Reference<XDragSourceListener>& dsl);
+ /// @throws RuntimeException
+ virtual void removeDragSourceListener(const Reference<XDragSourceListener>& dsl);
+ virtual sal_Int32 SAL_CALL getCurrentCursor() override;
+ virtual void SAL_CALL setCursor(sal_Int32 cursorId) override;
+ virtual void SAL_CALL setImage(sal_Int32 imageId) override;
+ virtual void SAL_CALL transferablesFlavorsChanged() override;
+
+ // non - interface functions
+ void fire_dragDropEnd(bool success, sal_Int8 byte);
+ void fire_dropActionChanged(sal_Int8 dropAction, sal_Int8 userAction);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/target.cxx b/vcl/win/dtrans/target.cxx
new file mode 100644
index 000000000..077aeeb0d
--- /dev/null
+++ b/vcl/win/dtrans/target.cxx
@@ -0,0 +1,646 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <o3tl/any.hxx>
+
+#include <stdio.h>
+#include <win/dnd_target.hxx>
+#include "idroptarget.hxx"
+#include "globals.hxx"
+#include "targetdropcontext.hxx"
+#include "targetdragcontext.hxx"
+#include <rtl/ustring.h>
+#include <osl/thread.h>
+#include <sal/log.hxx>
+#include <comphelper/windowserrorstring.hxx>
+
+#include "DOTransferable.hxx"
+
+using namespace cppu;
+using namespace osl;
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::datatransfer::dnd;
+using namespace com::sun::star::datatransfer::dnd::DNDConstants;
+
+#define WM_REGISTERDRAGDROP WM_USER + 1
+#define WM_REVOKEDRAGDROP WM_USER + 2
+
+DWORD WINAPI DndTargetOleSTAFunc(LPVOID pParams);
+
+DropTarget::DropTarget( const Reference<XComponentContext>& rxContext):
+ WeakComponentImplHelper<XInitialization,XDropTarget, XServiceInfo>(m_aMutex),
+ m_hWnd( nullptr),
+ m_threadIdWindow(0),
+ m_threadIdTarget(0),
+ m_hOleThread(nullptr),
+ m_oleThreadId( 0),
+ m_pDropTarget( nullptr),
+ m_xContext( rxContext ),
+ m_bActive(true),
+ m_nDefaultActions(ACTION_COPY|ACTION_MOVE|ACTION_LINK|ACTION_DEFAULT),
+ m_nCurrentDropAction( ACTION_NONE),
+ m_nLastDropAction(0),
+ m_bDropComplete(false)
+{
+}
+
+DropTarget::~DropTarget()
+{
+}
+// called from WeakComponentImplHelperX::dispose
+// WeakComponentImplHelper calls disposing before it destroys
+// itself.
+// NOTE: RevokeDragDrop decrements the ref count on the IDropTarget
+// interface. (m_pDropTarget)
+// If the HWND is invalid then it doesn't decrement and
+// the IDropTarget object will live on. MEMORY LEAK
+void SAL_CALL DropTarget::disposing()
+{
+ if( m_threadIdTarget)
+ {
+ // Call RevokeDragDrop and wait for the OLE thread to die;
+ PostThreadMessageW( m_threadIdTarget, WM_REVOKEDRAGDROP, reinterpret_cast<WPARAM>(this), 0);
+ WaitForSingleObject( m_hOleThread, INFINITE);
+ CloseHandle( m_hOleThread);
+ //OSL_ENSURE( SUCCEEDED( hr), "HWND not valid!" );
+ }
+ else
+ {
+ RevokeDragDrop( m_hWnd);
+ m_hWnd= nullptr;
+ }
+ if( m_pDropTarget)
+ {
+ CoLockObjectExternal( m_pDropTarget, FALSE, TRUE);
+ m_pDropTarget->Release();
+ m_pDropTarget = nullptr;
+ }
+
+ if( m_oleThreadId)
+ {
+ if( m_oleThreadId == CoGetCurrentProcess() )
+ OleUninitialize();
+ }
+
+}
+
+void SAL_CALL DropTarget::initialize( const Sequence< Any >& aArguments )
+{
+ // The window must be registered for Dnd by RegisterDragDrop. We must ensure
+ // that RegisterDragDrop is called from an STA ( OleInitialize) thread.
+ // As long as the window is registered we need to receive OLE messages in
+ // an OLE thread. That is to say, if DropTarget::initialize was called from an
+ // MTA thread then we create an OLE thread in which the window is registered.
+ // The thread will stay alive until aver RevokeDragDrop has been called.
+
+ // Additionally even if RegisterDragDrop is called from an STA thread we have
+ // to ensure that it is called from the same thread that created the Window
+ // otherwise messages sent during DND won't reach the windows message queue.
+ // Calling AttachThreadInput first would resolve this problem but would block
+ // the message queue of the calling thread. So if the current thread
+ // (even if it's an STA thread) and the thread that created the window are not
+ // identical we need to create a new thread as we do when the calling thread is
+ // an MTA thread.
+
+ if( aArguments.getLength() > 0)
+ {
+ // Get the window handle from aArgument. It is needed for RegisterDragDrop.
+ m_hWnd= reinterpret_cast<HWND>(static_cast<sal_uIntPtr>(*o3tl::doAccess<sal_uInt64>(aArguments[0])));
+ OSL_ASSERT( IsWindow( m_hWnd) );
+
+ // Obtain the id of the thread that created the window
+ m_threadIdWindow= GetWindowThreadProcessId( m_hWnd, nullptr);
+
+ HRESULT hr= OleInitialize( nullptr);
+
+ // Current thread is MTA or Current thread and Window thread are not identical
+ if( hr == RPC_E_CHANGED_MODE || GetCurrentThreadId() != m_threadIdWindow )
+ {
+ OSL_ENSURE( ! m_threadIdTarget,"initialize was called twice");
+ // create the IDropTargetImplementation
+ m_pDropTarget= new IDropTargetImpl( *this );
+ m_pDropTarget->AddRef();
+
+ // Obtain the id of the thread that created the window
+ m_threadIdWindow= GetWindowThreadProcessId( m_hWnd, nullptr);
+ // The event is set by the thread that we will create momentarily.
+ // It indicates that the thread is ready to receive messages.
+ HANDLE m_evtThreadReady= CreateEventW( nullptr, FALSE, FALSE, nullptr);
+
+ m_hOleThread= CreateThread( nullptr, 0, DndTargetOleSTAFunc,
+ &m_evtThreadReady, 0, &m_threadIdTarget);
+ WaitForSingleObject( m_evtThreadReady, INFINITE);
+ CloseHandle( m_evtThreadReady);
+ PostThreadMessageW( m_threadIdTarget, WM_REGISTERDRAGDROP, reinterpret_cast<WPARAM>(this), 0);
+ }
+ else if( hr == S_OK || hr == S_FALSE)
+ {
+ // current thread is STA
+ // If OleInitialize has been called by the caller then we must not call
+ // OleUninitialize
+ if( hr == S_OK)
+ {
+ // caller did not call OleInitialize, so we call OleUninitialize
+ // remember the thread that will call OleUninitialize
+ m_oleThreadId= CoGetCurrentProcess(); // get a unique thread id
+ }
+
+ // Get the window handle from aArgument. It is needed for RegisterDragDrop.
+ // create the IDropTargetImplementation
+ m_pDropTarget= new IDropTargetImpl( *this );
+ m_pDropTarget->AddRef();
+ // CoLockObjectExternal is prescribed by the protocol. It bumps up the ref count
+ if( SUCCEEDED( CoLockObjectExternal( m_pDropTarget, TRUE, FALSE)))
+ {
+ if( FAILED( RegisterDragDrop( m_hWnd, m_pDropTarget) ) )
+ {
+ // do clean up if drag and drop is not possible
+ CoLockObjectExternal( m_pDropTarget, FALSE, FALSE);
+ m_pDropTarget->Release();
+ m_pDropTarget = nullptr;
+ m_hWnd= nullptr;
+ }
+ }
+ }
+ else
+ throw Exception("OleInitialize failed with " + OUString::number(hr), nullptr);
+
+ }
+}
+
+// This function is called as extra thread from DragSource::startDrag.
+// The function carries out a drag and drop operation by calling
+// DoDragDrop. The thread also notifies all XSourceListener.
+DWORD WINAPI DndTargetOleSTAFunc(LPVOID pParams)
+{
+ osl_setThreadName("DropTarget DndTargetOleSTAFunc");
+
+ HRESULT hr= OleInitialize( nullptr);
+ if( SUCCEEDED( hr) )
+ {
+ MSG msg;
+ // force the creation of a message queue
+ PeekMessageW( &msg, nullptr, 0, 0, PM_NOREMOVE);
+ // Signal the creator ( DropTarget::initialize) that the thread is
+ // ready to receive messages.
+ SetEvent( *static_cast<HANDLE*>(pParams));
+ // Thread id is needed for attaching this message queue to the one of the
+ // thread where the window was created.
+ DWORD threadId= GetCurrentThreadId();
+ // We force the creation of a thread message queue. This is necessary
+ // for a later call to AttachThreadInput
+ for (;;)
+ {
+ int const bRet = GetMessageW(&msg, nullptr, 0, 0);
+ if (bRet == 0)
+ {
+ break;
+ }
+ if (-1 == bRet)
+ {
+ SAL_WARN("vcl.win.dtrans", "GetMessageW failed: " << WindowsErrorString(GetLastError()));
+ break;
+ }
+ if( msg.message == WM_REGISTERDRAGDROP)
+ {
+ DropTarget *pTarget= reinterpret_cast<DropTarget*>(msg.wParam);
+ // This thread is attached to the thread that created the window. Hence
+ // this thread also receives all mouse and keyboard messages which are
+ // needed
+ AttachThreadInput( threadId , pTarget->m_threadIdWindow, TRUE );
+
+ if( SUCCEEDED( CoLockObjectExternal(pTarget-> m_pDropTarget, TRUE, FALSE)))
+ {
+ if( FAILED( RegisterDragDrop( pTarget-> m_hWnd, pTarget-> m_pDropTarget) ) )
+ {
+ // do clean up if drag and drop is not possible
+ CoLockObjectExternal( pTarget->m_pDropTarget, FALSE, FALSE);
+ pTarget->m_pDropTarget->Release();
+ pTarget->m_pDropTarget = nullptr;
+ pTarget->m_hWnd= nullptr;
+ }
+ }
+ }
+ else if( msg.message == WM_REVOKEDRAGDROP)
+ {
+ DropTarget *pTarget= reinterpret_cast<DropTarget*>(msg.wParam);
+ RevokeDragDrop( pTarget-> m_hWnd);
+ // Detach this thread from the window thread
+ AttachThreadInput( threadId, pTarget->m_threadIdWindow, FALSE);
+ pTarget->m_hWnd= nullptr;
+ break;
+ }
+ TranslateMessage( &msg);
+ DispatchMessageW( &msg);
+ }
+ OleUninitialize();
+ }
+ return 0;
+}
+
+// XServiceInfo
+OUString SAL_CALL DropTarget::getImplementationName( )
+{
+ return "com.sun.star.comp.datatransfer.dnd.OleDropTarget_V1";
+}
+// XServiceInfo
+sal_Bool SAL_CALL DropTarget::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Sequence< OUString > SAL_CALL DropTarget::getSupportedServiceNames( )
+{
+ return { "com.sun.star.datatransfer.dnd.OleDropTarget" };
+}
+
+// XDropTarget
+void SAL_CALL DropTarget::addDropTargetListener( const Reference< XDropTargetListener >& dtl )
+{
+ rBHelper.addListener( cppu::UnoType<decltype(dtl)>::get(), dtl );
+}
+
+void SAL_CALL DropTarget::removeDropTargetListener( const Reference< XDropTargetListener >& dtl )
+{
+ rBHelper.removeListener( cppu::UnoType<decltype(dtl)>::get(), dtl );
+}
+
+sal_Bool SAL_CALL DropTarget::isActive( )
+{
+ return m_bActive; //m_bDropTargetRegistered;
+}
+
+void SAL_CALL DropTarget::setActive( sal_Bool _b )
+{
+ MutexGuard g(m_aMutex);
+ m_bActive= _b;
+}
+
+sal_Int8 SAL_CALL DropTarget::getDefaultActions( )
+{
+ return m_nDefaultActions;
+}
+
+void SAL_CALL DropTarget::setDefaultActions( sal_Int8 actions )
+{
+ OSL_ENSURE( actions < 8, "No valid default actions");
+ m_nDefaultActions= actions;
+}
+
+HRESULT DropTarget::DragEnter( IDataObject *pDataObj,
+ DWORD grfKeyState,
+ POINTL pt,
+ DWORD *pdwEffect)
+{
+#if defined DBG_CONSOLE_OUT
+ printf("\nDropTarget::DragEnter state: %x effect %d", grfKeyState, *pdwEffect);
+#endif
+ if( m_bActive )
+ {
+ // Intersection of pdwEffect and the allowed actions ( setDefaultActions)
+ m_nCurrentDropAction= getFilteredActions( grfKeyState, *pdwEffect);
+ // m_nLastDropAction has to be set by a listener. If no listener calls
+ //XDropTargetDragContext::acceptDrag and specifies an action then pdwEffect
+ // will be DROPEFFECT_NONE throughout
+ m_nLastDropAction= ACTION_DEFAULT | ACTION_MOVE;
+
+ m_currentDragContext = new TargetDragContext(this);
+
+ //--> TRA
+
+ // shortcut
+ if ( g_XTransferable.is( ) )
+ m_currentData = g_XTransferable;
+ else
+ {
+ // Convert the IDataObject to a XTransferable
+ m_currentData = new CDOTransferable(m_xContext, IDataObjectPtr(pDataObj));
+ }
+
+ //<-- TRA
+
+ if( m_nCurrentDropAction != ACTION_NONE)
+ {
+ DropTargetDragEnterEvent e;
+ e.SupportedDataFlavors= m_currentData->getTransferDataFlavors();
+ e.DropAction= m_nCurrentDropAction;
+ e.Source.set( static_cast<XDropTarget*>(this),UNO_QUERY);
+ e.Context= m_currentDragContext;
+ POINT point={ pt.x, pt.y};
+ ScreenToClient( m_hWnd, &point);
+ e.LocationX= point.x;
+ e.LocationY= point.y;
+ e.SourceActions= dndOleDropEffectsToActions( *pdwEffect);
+
+ fire_dragEnter( e);
+ // Check if the action derived from grfKeyState (m_nCurrentDropAction) or the action set
+ // by the listener (m_nCurrentDropAction) is allowed by the source. Only an allowed action is set
+ // in pdwEffect. The listener notification is asynchronous, that is we cannot expect that the listener
+ // has already reacted to the notification.
+ // If there is more than one valid action which is the case when ALT or RIGHT MOUSE BUTTON is pressed
+ // then getDropEffect returns DROPEFFECT_MOVE which is the default value if no other modifier is pressed.
+ // On drop the target should present the user a dialog from which the user may change the action.
+ sal_Int8 allowedActions= dndOleDropEffectsToActions( *pdwEffect);
+ *pdwEffect= dndActionsToSingleDropEffect( m_nLastDropAction & allowedActions);
+ }
+ else
+ {
+ *pdwEffect= DROPEFFECT_NONE;
+ }
+ }
+ return S_OK;
+}
+
+HRESULT DropTarget::DragOver( DWORD grfKeyState,
+ POINTL pt,
+ DWORD *pdwEffect)
+{
+ if( m_bActive)
+ {
+ m_nCurrentDropAction= getFilteredActions( grfKeyState, *pdwEffect);
+
+ if( m_nCurrentDropAction)
+ {
+ DropTargetDragEvent e;
+ e.DropAction= m_nCurrentDropAction;
+ e.Source.set(static_cast<XDropTarget*>(this),UNO_QUERY);
+ e.Context= m_currentDragContext;
+ POINT point={ pt.x, pt.y};
+ ScreenToClient( m_hWnd, &point);
+ e.LocationX= point.x;
+ e.LocationY= point.y;
+ e.SourceActions= dndOleDropEffectsToActions( *pdwEffect);
+
+ // if grfKeyState has changed since the last DragOver then fire events.
+ // A listener might change m_nCurrentDropAction by calling the
+ // XDropTargetDragContext::acceptDrag function. But this is not important
+ // because in the afterwards fired dragOver event the action reflects
+ // grgKeyState again.
+ if( m_nLastDropAction != m_nCurrentDropAction)
+ fire_dropActionChanged( e);
+
+ // The Event contains a XDropTargetDragContext implementation.
+ fire_dragOver( e);
+ // Check if the action derived from grfKeyState (m_nCurrentDropAction) or the action set
+ // by the listener (m_nCurrentDropAction) is allowed by the source. Only an allowed action is set
+ // in pdwEffect. The listener notification is asynchronous, that is we cannot expect that the listener
+ // has already reacted to the notification.
+ // If there is more than one valid action which is the case when ALT or RIGHT MOUSE BUTTON is pressed
+ // then getDropEffect returns DROPEFFECT_MOVE which is the default value if no other modifier is pressed.
+ // On drop the target should present the user a dialog from which the user may change the action.
+ sal_Int8 allowedActions= dndOleDropEffectsToActions( *pdwEffect);
+ // set the last action to the current if listener has not changed the value yet
+ *pdwEffect= dndActionsToSingleDropEffect( m_nLastDropAction & allowedActions);
+ }
+ else
+ {
+ *pdwEffect= DROPEFFECT_NONE;
+ }
+ }
+#if defined DBG_CONSOLE_OUT
+ printf("\nDropTarget::DragOver %d", *pdwEffect );
+#endif
+ return S_OK;
+}
+
+HRESULT DropTarget::DragLeave()
+{
+#if defined DBG_CONSOLE_OUT
+ printf("\nDropTarget::DragLeave");
+#endif
+ if( m_bActive)
+ {
+
+ m_currentData=nullptr;
+ m_currentDragContext= nullptr;
+ m_currentDropContext= nullptr;
+ m_nLastDropAction= 0;
+
+ if( m_nDefaultActions != ACTION_NONE)
+ {
+ DropTargetEvent e;
+ e.Source= static_cast<XDropTarget*>(this);
+
+ fire_dragExit( e);
+ }
+ }
+ return S_OK;
+}
+
+HRESULT DropTarget::Drop( IDataObject * /*pDataObj*/,
+ DWORD grfKeyState,
+ POINTL pt,
+ DWORD *pdwEffect)
+{
+#if defined DBG_CONSOLE_OUT
+ printf("\nDropTarget::Drop");
+#endif
+ if( m_bActive)
+ {
+
+ m_bDropComplete= false;
+
+ m_nCurrentDropAction= getFilteredActions( grfKeyState, *pdwEffect);
+ m_currentDropContext = new TargetDropContext(this);
+ if( m_nCurrentDropAction)
+ {
+ DropTargetDropEvent e;
+ e.DropAction= m_nCurrentDropAction;
+ e.Source.set( static_cast<XDropTarget*>(this), UNO_QUERY);
+ e.Context= m_currentDropContext;
+ POINT point={ pt.x, pt.y};
+ ScreenToClient( m_hWnd, &point);
+ e.LocationX= point.x;
+ e.LocationY= point.y;
+ e.SourceActions= dndOleDropEffectsToActions( *pdwEffect);
+ e.Transferable= m_currentData;
+ fire_drop( e);
+
+ //if fire_drop returns than a listener might have modified m_nCurrentDropAction
+ if( m_bDropComplete )
+ {
+ sal_Int8 allowedActions= dndOleDropEffectsToActions( *pdwEffect);
+ *pdwEffect= dndActionsToSingleDropEffect( m_nCurrentDropAction & allowedActions);
+ }
+ else
+ *pdwEffect= DROPEFFECT_NONE;
+ }
+ else
+ *pdwEffect= DROPEFFECT_NONE;
+
+ m_currentData= nullptr;
+ m_currentDragContext= nullptr;
+ m_currentDropContext= nullptr;
+ m_nLastDropAction= 0;
+ }
+ return S_OK;
+}
+
+void DropTarget::fire_drop( const DropTargetDropEvent& dte)
+{
+ OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get());
+ if( pContainer)
+ {
+ OInterfaceIteratorHelper iter( *pContainer);
+ while( iter.hasMoreElements())
+ {
+ Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
+ listener->drop( dte);
+ }
+ }
+}
+
+void DropTarget::fire_dragEnter( const DropTargetDragEnterEvent& e )
+{
+ OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get());
+ if( pContainer)
+ {
+ OInterfaceIteratorHelper iter( *pContainer);
+ while( iter.hasMoreElements())
+ {
+ Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
+ listener->dragEnter( e);
+ }
+ }
+}
+
+void DropTarget::fire_dragExit( const DropTargetEvent& dte )
+{
+ OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get());
+
+ if( pContainer)
+ {
+ OInterfaceIteratorHelper iter( *pContainer);
+ while( iter.hasMoreElements())
+ {
+ Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
+ listener->dragExit( dte);
+ }
+ }
+}
+
+void DropTarget::fire_dragOver( const DropTargetDragEvent& dtde )
+{
+ OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get());
+ if( pContainer)
+ {
+ OInterfaceIteratorHelper iter( *pContainer );
+ while( iter.hasMoreElements())
+ {
+ Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
+ listener->dragOver( dtde);
+ }
+ }
+}
+
+void DropTarget::fire_dropActionChanged( const DropTargetDragEvent& dtde )
+{
+ OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get());
+ if( pContainer)
+ {
+ OInterfaceIteratorHelper iter( *pContainer);
+ while( iter.hasMoreElements())
+ {
+ Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
+ listener->dropActionChanged( dtde);
+ }
+ }
+}
+
+// Non - interface functions
+// DropTarget fires events to XDropTargetListeners. The event object contains an
+// XDropTargetDropContext implementation. When the listener calls on that interface
+// then the calls are delegated from DropContext (XDropTargetDropContext) to these
+// functions.
+// Only one listener which visible area is affected is allowed to call on
+// XDropTargetDropContext
+// Returning sal_False would cause the XDropTargetDropContext or ..DragContext implementation
+// to throw an InvalidDNDOperationException, meaning that a Drag is not currently performed.
+// return sal_False results in throwing an InvalidDNDOperationException in the caller.
+
+void DropTarget::_acceptDrop(sal_Int8 dropOperation, const Reference<XDropTargetDropContext>& context)
+{
+ if( context == m_currentDropContext)
+ {
+ m_nCurrentDropAction= dropOperation;
+ }
+}
+
+void DropTarget::_rejectDrop( const Reference<XDropTargetDropContext>& context)
+{
+ if( context == m_currentDropContext)
+ {
+ m_nCurrentDropAction= ACTION_NONE;
+ }
+}
+
+void DropTarget::_dropComplete(bool success, const Reference<XDropTargetDropContext>& context)
+{
+ if(context == m_currentDropContext)
+ {
+ m_bDropComplete= success;
+ }
+}
+
+// DropTarget fires events to XDropTargetListeners. The event object can contains an
+// XDropTargetDragContext implementation. When the listener calls on that interface
+// then the calls are delegated from DragContext (XDropTargetDragContext) to these
+// functions.
+// Only one listener which visible area is affected is allowed to call on
+// XDropTargetDragContext
+void DropTarget::_acceptDrag( sal_Int8 dragOperation, const Reference<XDropTargetDragContext>& context)
+{
+ if( context == m_currentDragContext)
+ {
+ m_nLastDropAction= dragOperation;
+ }
+}
+
+void DropTarget::_rejectDrag( const Reference<XDropTargetDragContext>& context)
+{
+ if(context == m_currentDragContext)
+ {
+ m_nLastDropAction= ACTION_NONE;
+ }
+}
+
+// This function determines the action dependent on the pressed
+// key modifiers ( CTRL, SHIFT, ALT, Right Mouse Button). The result
+// is then checked against the allowed actions which can be set through
+// XDropTarget::setDefaultActions. Only those values which are also
+// default actions are returned. If setDefaultActions has not been called
+// beforehand the default actions comprise all possible actions.
+// params: grfKeyState - the modifier keys and mouse buttons currently pressed
+inline sal_Int8 DropTarget::getFilteredActions( DWORD grfKeyState, DWORD dwEffect)
+{
+ sal_Int8 actions= dndOleKeysToAction( grfKeyState, dndOleDropEffectsToActions( dwEffect));
+ return actions & m_nDefaultActions;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+dtrans_DropTarget_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new DropTarget(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/targetdragcontext.cxx b/vcl/win/dtrans/targetdragcontext.cxx
new file mode 100644
index 000000000..71e345b74
--- /dev/null
+++ b/vcl/win/dtrans/targetdragcontext.cxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "targetdragcontext.hxx"
+
+TargetDragContext::TargetDragContext(DropTarget* p)
+{
+ m_pDropTarget = p;
+ p->acquire();
+}
+
+TargetDragContext::~TargetDragContext() { m_pDropTarget->release(); }
+
+void SAL_CALL TargetDragContext::acceptDrag(sal_Int8 dragOperation)
+{
+ m_pDropTarget->_acceptDrag(dragOperation, static_cast<XDropTargetDragContext*>(this));
+}
+void SAL_CALL TargetDragContext::rejectDrag()
+{
+ m_pDropTarget->_rejectDrag(static_cast<XDropTargetDragContext*>(this));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/targetdragcontext.hxx b/vcl/win/dtrans/targetdragcontext.hxx
new file mode 100644
index 000000000..a64ab6a30
--- /dev/null
+++ b/vcl/win/dtrans/targetdragcontext.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/datatransfer/dnd/XDropTargetDragContext.hpp>
+#include <com/sun/star/datatransfer/DataFlavor.hpp>
+
+#include <win/dnd_target.hxx>
+
+using namespace ::com::sun::star::datatransfer;
+using namespace ::com::sun::star::datatransfer::dnd;
+using namespace ::cppu;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+
+class TargetDragContext : public WeakImplHelper<XDropTargetDragContext>
+{
+ // some calls to the functions of XDropTargetDragContext are delegated
+ // to non-interface functions of m_pDropTarget
+ DropTarget* m_pDropTarget;
+
+public:
+ explicit TargetDragContext(DropTarget* pTarget);
+ ~TargetDragContext() override;
+ TargetDragContext(const TargetDragContext&) = delete;
+ TargetDragContext& operator=(const TargetDragContext&) = delete;
+
+ virtual void SAL_CALL acceptDrag(sal_Int8 dragOperation) override;
+ virtual void SAL_CALL rejectDrag() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/targetdropcontext.cxx b/vcl/win/dtrans/targetdropcontext.cxx
new file mode 100644
index 000000000..fe6538943
--- /dev/null
+++ b/vcl/win/dtrans/targetdropcontext.cxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "targetdropcontext.hxx"
+
+using namespace ::com::sun::star::datatransfer::dnd;
+using namespace ::cppu;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+
+TargetDropContext::TargetDropContext(DropTarget* p)
+{
+ m_pDropTarget = p;
+ p->acquire();
+}
+
+TargetDropContext::~TargetDropContext() { m_pDropTarget->release(); }
+
+void SAL_CALL TargetDropContext::acceptDrop(sal_Int8 dropOperation)
+{
+ m_pDropTarget->_acceptDrop(dropOperation, static_cast<XDropTargetDropContext*>(this));
+}
+
+void SAL_CALL TargetDropContext::rejectDrop()
+{
+ m_pDropTarget->_rejectDrop(static_cast<XDropTargetDropContext*>(this));
+}
+
+void SAL_CALL TargetDropContext::dropComplete(sal_Bool success)
+{
+ m_pDropTarget->_dropComplete(success, static_cast<XDropTargetDropContext*>(this));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/dtrans/targetdropcontext.hxx b/vcl/win/dtrans/targetdropcontext.hxx
new file mode 100644
index 000000000..938a23f85
--- /dev/null
+++ b/vcl/win/dtrans/targetdropcontext.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/datatransfer/dnd/XDropTargetDropContext.hpp>
+
+#include <win/dnd_target.hxx>
+
+using namespace ::com::sun::star::datatransfer::dnd;
+using namespace ::cppu;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+
+class TargetDropContext : public WeakImplHelper<XDropTargetDropContext>
+{
+ // calls to the functions of XDropTargetDropContext are delegated
+ // to non-interface functions of m_pDropTarget
+ DropTarget* m_pDropTarget;
+
+public:
+ explicit TargetDropContext(DropTarget* pTarget);
+ ~TargetDropContext() override;
+ TargetDropContext(const TargetDropContext&) = delete;
+ TargetDropContext& operator=(const TargetDropContext&) = delete;
+
+ // XDropTargetDragContext
+ virtual void SAL_CALL acceptDrop(sal_Int8 dropOperation) override;
+ virtual void SAL_CALL rejectDrop() override;
+
+ // XDropTargetDropContext (inherits XDropTargetDragContext)
+ virtual void SAL_CALL dropComplete(sal_Bool success) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */