From 940b4d1848e8c70ab7642901a68594e8016caffc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 18:51:28 +0200 Subject: Adding upstream version 1:7.0.4. Signed-off-by: Daniel Baumann --- dtrans/source/win32/clipb/APNDataObject.hxx | 72 ++ dtrans/source/win32/clipb/MtaOleClipb.cxx | 736 ++++++++++++++++++++ dtrans/source/win32/clipb/MtaOleClipb.hxx | 117 ++++ dtrans/source/win32/clipb/WinClipbImpl.cxx | 210 ++++++ dtrans/source/win32/clipb/WinClipbImpl.hxx | 106 +++ dtrans/source/win32/clipb/WinClipboard.cxx | 239 +++++++ dtrans/source/win32/clipb/WinClipboard.hxx | 123 ++++ dtrans/source/win32/clipb/wcbentry.cxx | 82 +++ dtrans/source/win32/dnd/dndentry.cxx | 88 +++ dtrans/source/win32/dnd/globals.cxx | 130 ++++ dtrans/source/win32/dnd/globals.hxx | 81 +++ dtrans/source/win32/dnd/idroptarget.cxx | 96 +++ dtrans/source/win32/dnd/idroptarget.hxx | 67 ++ dtrans/source/win32/dnd/source.cxx | 365 ++++++++++ dtrans/source/win32/dnd/source.hxx | 127 ++++ dtrans/source/win32/dnd/sourcecontext.cxx | 134 ++++ dtrans/source/win32/dnd/sourcecontext.hxx | 70 ++ dtrans/source/win32/dnd/target.cxx | 628 +++++++++++++++++ dtrans/source/win32/dnd/target.hxx | 177 +++++ dtrans/source/win32/dnd/targetdragcontext.cxx | 43 ++ dtrans/source/win32/dnd/targetdragcontext.hxx | 52 ++ dtrans/source/win32/dnd/targetdropcontext.cxx | 53 ++ dtrans/source/win32/dnd/targetdropcontext.hxx | 54 ++ dtrans/source/win32/dtobj/APNDataObject.cxx | 327 +++++++++ dtrans/source/win32/dtobj/APNDataObject.hxx | 74 ++ dtrans/source/win32/dtobj/DOTransferable.cxx | 589 ++++++++++++++++ dtrans/source/win32/dtobj/DOTransferable.hxx | 96 +++ dtrans/source/win32/dtobj/DTransHelper.cxx | 205 ++++++ dtrans/source/win32/dtobj/DTransHelper.hxx | 170 +++++ dtrans/source/win32/dtobj/DataFmtTransl.cxx | 259 +++++++ dtrans/source/win32/dtobj/DataFmtTransl.hxx | 67 ++ dtrans/source/win32/dtobj/DtObjFactory.cxx | 34 + dtrans/source/win32/dtobj/Fetc.cxx | 166 +++++ dtrans/source/win32/dtobj/Fetc.hxx | 79 +++ dtrans/source/win32/dtobj/FetcList.cxx | 344 ++++++++++ dtrans/source/win32/dtobj/FetcList.hxx | 142 ++++ dtrans/source/win32/dtobj/FmtFilter.cxx | 437 ++++++++++++ dtrans/source/win32/dtobj/FmtFilter.hxx | 87 +++ dtrans/source/win32/dtobj/MimeAttrib.hxx | 34 + dtrans/source/win32/dtobj/TxtCnvtHlp.cxx | 124 ++++ dtrans/source/win32/dtobj/TxtCnvtHlp.hxx | 44 ++ dtrans/source/win32/dtobj/XNotifyingDataObject.cxx | 149 ++++ dtrans/source/win32/dtobj/XNotifyingDataObject.hxx | 88 +++ dtrans/source/win32/dtobj/XTDataObject.cxx | 757 +++++++++++++++++++++ dtrans/source/win32/dtobj/XTDataObject.hxx | 137 ++++ dtrans/source/win32/ftransl/ftransl.cxx | 547 +++++++++++++++ dtrans/source/win32/ftransl/ftransl.hxx | 62 ++ dtrans/source/win32/ftransl/ftranslentry.cxx | 79 +++ dtrans/source/win32/misc/ImplHelper.cxx | 352 ++++++++++ dtrans/source/win32/misc/ImplHelper.hxx | 77 +++ dtrans/source/win32/workbench/XTDo.cxx | 358 ++++++++++ dtrans/source/win32/workbench/XTDo.hxx | 114 ++++ dtrans/source/win32/workbench/makefile.mk | 81 +++ dtrans/source/win32/workbench/test_wincb.cxx | 287 ++++++++ dtrans/source/win32/workbench/testmarshal.cxx | 213 ++++++ 55 files changed, 10429 insertions(+) create mode 100644 dtrans/source/win32/clipb/APNDataObject.hxx create mode 100644 dtrans/source/win32/clipb/MtaOleClipb.cxx create mode 100644 dtrans/source/win32/clipb/MtaOleClipb.hxx create mode 100644 dtrans/source/win32/clipb/WinClipbImpl.cxx create mode 100644 dtrans/source/win32/clipb/WinClipbImpl.hxx create mode 100644 dtrans/source/win32/clipb/WinClipboard.cxx create mode 100644 dtrans/source/win32/clipb/WinClipboard.hxx create mode 100644 dtrans/source/win32/clipb/wcbentry.cxx create mode 100644 dtrans/source/win32/dnd/dndentry.cxx create mode 100644 dtrans/source/win32/dnd/globals.cxx create mode 100644 dtrans/source/win32/dnd/globals.hxx create mode 100644 dtrans/source/win32/dnd/idroptarget.cxx create mode 100644 dtrans/source/win32/dnd/idroptarget.hxx create mode 100644 dtrans/source/win32/dnd/source.cxx create mode 100644 dtrans/source/win32/dnd/source.hxx create mode 100644 dtrans/source/win32/dnd/sourcecontext.cxx create mode 100644 dtrans/source/win32/dnd/sourcecontext.hxx create mode 100644 dtrans/source/win32/dnd/target.cxx create mode 100644 dtrans/source/win32/dnd/target.hxx create mode 100644 dtrans/source/win32/dnd/targetdragcontext.cxx create mode 100644 dtrans/source/win32/dnd/targetdragcontext.hxx create mode 100644 dtrans/source/win32/dnd/targetdropcontext.cxx create mode 100644 dtrans/source/win32/dnd/targetdropcontext.hxx create mode 100644 dtrans/source/win32/dtobj/APNDataObject.cxx create mode 100644 dtrans/source/win32/dtobj/APNDataObject.hxx create mode 100644 dtrans/source/win32/dtobj/DOTransferable.cxx create mode 100644 dtrans/source/win32/dtobj/DOTransferable.hxx create mode 100644 dtrans/source/win32/dtobj/DTransHelper.cxx create mode 100644 dtrans/source/win32/dtobj/DTransHelper.hxx create mode 100644 dtrans/source/win32/dtobj/DataFmtTransl.cxx create mode 100644 dtrans/source/win32/dtobj/DataFmtTransl.hxx create mode 100644 dtrans/source/win32/dtobj/DtObjFactory.cxx create mode 100644 dtrans/source/win32/dtobj/Fetc.cxx create mode 100644 dtrans/source/win32/dtobj/Fetc.hxx create mode 100644 dtrans/source/win32/dtobj/FetcList.cxx create mode 100644 dtrans/source/win32/dtobj/FetcList.hxx create mode 100644 dtrans/source/win32/dtobj/FmtFilter.cxx create mode 100644 dtrans/source/win32/dtobj/FmtFilter.hxx create mode 100644 dtrans/source/win32/dtobj/MimeAttrib.hxx create mode 100644 dtrans/source/win32/dtobj/TxtCnvtHlp.cxx create mode 100644 dtrans/source/win32/dtobj/TxtCnvtHlp.hxx create mode 100644 dtrans/source/win32/dtobj/XNotifyingDataObject.cxx create mode 100644 dtrans/source/win32/dtobj/XNotifyingDataObject.hxx create mode 100644 dtrans/source/win32/dtobj/XTDataObject.cxx create mode 100644 dtrans/source/win32/dtobj/XTDataObject.hxx create mode 100644 dtrans/source/win32/ftransl/ftransl.cxx create mode 100644 dtrans/source/win32/ftransl/ftransl.hxx create mode 100644 dtrans/source/win32/ftransl/ftranslentry.cxx create mode 100644 dtrans/source/win32/misc/ImplHelper.cxx create mode 100644 dtrans/source/win32/misc/ImplHelper.hxx create mode 100644 dtrans/source/win32/workbench/XTDo.cxx create mode 100644 dtrans/source/win32/workbench/XTDo.hxx create mode 100644 dtrans/source/win32/workbench/makefile.mk create mode 100644 dtrans/source/win32/workbench/test_wincb.cxx create mode 100644 dtrans/source/win32/workbench/testmarshal.cxx (limited to 'dtrans/source/win32') diff --git a/dtrans/source/win32/clipb/APNDataObject.hxx b/dtrans/source/win32/clipb/APNDataObject.hxx new file mode 100644 index 000000000..c48d14117 --- /dev/null +++ b/dtrans/source/win32/clipb/APNDataObject.hxx @@ -0,0 +1,72 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_CLIPB_APNDATAOBJECT_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_CLIPB_APNDATAOBJECT_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: + CAPNDataObject( IDataObjectPtr rIDataObject ); + ~CAPNDataObject( ); + + //IUnknown interface methods + + STDMETHODIMP QueryInterface(REFIID iid, LPVOID* ppvObject); + STDMETHODIMP_( ULONG ) AddRef( ); + STDMETHODIMP_( ULONG ) Release( ); + + // IDataObject interface methods + + STDMETHODIMP GetData( LPFORMATETC pFormatetc, LPSTGMEDIUM pmedium ); + STDMETHODIMP GetDataHere( LPFORMATETC pFormatetc, LPSTGMEDIUM pmedium ); + STDMETHODIMP QueryGetData( LPFORMATETC pFormatetc ); + STDMETHODIMP GetCanonicalFormatEtc( LPFORMATETC pFormatectIn, LPFORMATETC pFormatetcOut ); + STDMETHODIMP SetData( LPFORMATETC pFormatetc, LPSTGMEDIUM pmedium, BOOL fRelease ); + STDMETHODIMP EnumFormatEtc( DWORD dwDirection, IEnumFORMATETC** ppenumFormatetc ); + STDMETHODIMP DAdvise( LPFORMATETC pFormatetc, DWORD advf, LPADVISESINK pAdvSink, DWORD* pdwConnection ); + STDMETHODIMP DUnadvise( DWORD dwConnection ); + STDMETHODIMP EnumDAdvise( LPENUMSTATDATA* ppenumAdvise ); + + 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 ); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/clipb/MtaOleClipb.cxx b/dtrans/source/win32/clipb/MtaOleClipb.cxx new file mode 100644 index 000000000..70fce3bc6 --- /dev/null +++ b/dtrans/source/win32/clipb/MtaOleClipb.cxx @@ -0,0 +1,736 @@ +/* -*- 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 +#include + +#include "MtaOleClipb.hxx" +#include + +#include +#include + +#include + +// namespace directives + +using osl::MutexGuard; +using osl::ClearableMutexGuard; + +namespace /* private */ +{ + wchar_t CLIPSRV_DLL_NAME[] = L"sysdtrans.dll"; + 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(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 + CoInitialize returned S_FALSE, what + means that com was already initialize + for that thread so we keep the balance + if CoInitialize 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, "dtrans", "CreateEventW failed: m_hEvtWndDisposed is nullptr"); + + s_theMtaOleClipboardInst = this; + + m_hOleThread = reinterpret_cast(_beginthreadex( + 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] ); + + unsigned uThreadId; + m_hClipboardChangedNotifierThread = reinterpret_cast(_beginthreadex( + 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(&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(&lpStream), + reinterpret_cast(&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(pfncClipViewerCallback), + reinterpret_cast(&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 OleSetClipboard( pIDataObject ); +} + +HRESULT CMtaOleClipboard::onGetClipboard( LPSTREAM* ppStream ) +{ + OSL_ASSERT(nullptr != ppStream); + + IDataObjectPtr pIDataObject; + + // forward the request to the OleClipboard + HRESULT hr = OleGetClipboard( &pIDataObject ); + if ( SUCCEEDED( hr ) ) + { + hr = MarshalIDataObjectInStream(pIDataObject.get(), ppStream); + OSL_ENSURE(SUCCEEDED(hr), "marshalling cliboard data object failed"); + } + return hr; +} + +// flush the ole-clipboard + +HRESULT CMtaOleClipboard::onFlushClipboard( ) +{ + 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, "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(lParam); + SAL_WARN_IF(!pMsgCtx, "dtrans", "pMsgCtx is nullptr"); + + pImpl->onRegisterClipViewer( + reinterpret_cast(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; + + HINSTANCE hInst = GetModuleHandleW( CLIPSRV_DLL_NAME ); + OSL_ENSURE( nullptr != hInst, "The name of the clipboard service dll must have changed" ); + + ZeroMemory( &wcex, sizeof(wcex) ); + + wcex.cbSize = sizeof(wcex); + wcex.style = 0; + wcex.lpfnWndProc = CMtaOleClipboard::mtaOleReqWndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInst; + 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, hInst, nullptr ); +} + +unsigned int CMtaOleClipboard::run( ) +{ + HRESULT hr = OleInitialize( nullptr ); + OSL_ASSERT( SUCCEEDED( hr ) ); + + createMtaOleReqWnd( ); + + unsigned int nRet; + + if ( IsWindow( m_hwndMtaOleReqWnd ) ) + { + if ( nullptr != m_hEvtThrdReady ) + SetEvent( m_hEvtThrdReady ); + + // pumping messages + MSG msg; + while( GetMessageW( &msg, nullptr, 0, 0 ) ) + DispatchMessageW( &msg ); + + nRet = 0; + } + else + nRet = ~0U; + + OleUninitialize( ); + + return nRet; +} + +unsigned int WINAPI CMtaOleClipboard::oleThreadProc( LPVOID pParam ) +{ + osl_setThreadName("CMtaOleClipboard::run()"); + + CMtaOleClipboard* pInst = + static_cast( pParam ); + OSL_ASSERT( nullptr != pInst ); + + return pInst->run( ); +} + +unsigned int WINAPI CMtaOleClipboard::clipboardChangedNotifierThreadProc( LPVOID pParam ) +{ + osl_setThreadName("CMtaOleClipboard::clipboardChangedNotifierThreadProc()"); + CMtaOleClipboard* pInst = static_cast< CMtaOleClipboard* >( pParam ); + OSL_ASSERT( nullptr != pInst ); + + CoInitialize( nullptr ); + + // assuming we don't need a lock for + // a boolean variable like m_bRun... + while ( pInst->m_bRunClipboardNotifierThread ) + { + // process window messages because of CoInitialize + 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 aGuard( pInst->m_ClipboardChangedEventCountMutex ); + + if ( pInst->m_ClipboardChangedEventCount > 0 ) + { + pInst->m_ClipboardChangedEventCount--; + if ( 0 == pInst->m_ClipboardChangedEventCount ) + ResetEvent( pInst->m_hClipboardChangedEvent ); + + aGuard.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 + aGuard.clear( ); + } + + CoUninitialize( ); + + 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/dtrans/source/win32/clipb/MtaOleClipb.hxx b/dtrans/source/win32/clipb/MtaOleClipb.hxx new file mode 100644 index 000000000..bf71ac26e --- /dev/null +++ b/dtrans/source/win32/clipb/MtaOleClipb.hxx @@ -0,0 +1,117 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_CLIPB_MTAOLECLIPB_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_CLIPB_MTAOLECLIPB_HXX + +#include +#include + +#include + +// 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 unsigned int WINAPI oleThreadProc( LPVOID pParam ); + + static unsigned int WINAPI clipboardChangedNotifierThreadProc( LPVOID pParam ); + + bool WaitForThreadReady( ) const; + +private: + HANDLE m_hOleThread; + unsigned 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; + +// not allowed +private: + CMtaOleClipboard( const CMtaOleClipboard& ); + CMtaOleClipboard& operator=( const CMtaOleClipboard& ); + + friend LRESULT CALLBACK mtaOleReqWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/clipb/WinClipbImpl.cxx b/dtrans/source/win32/clipb/WinClipbImpl.cxx new file mode 100644 index 000000000..8d59be7ca --- /dev/null +++ b/dtrans/source/win32/clipb/WinClipbImpl.cxx @@ -0,0 +1,210 @@ +/* -*- 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 +#include "WinClipbImpl.hxx" + +#include +#include "../../inc/DtObjFactory.hxx" +#include "../dtobj/APNDataObject.hxx" +#include "../dtobj/DOTransferable.hxx" +#include "WinClipboard.hxx" +#include +#include "../dtobj/XNotifyingDataObject.hxx" + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include + +using namespace osl; +using namespace std; +using namespace cppu; + +using namespace com::sun::star::uno; +using namespace com::sun::star::datatransfer; +using namespace com::sun::star::datatransfer::clipboard; +using namespace com::sun::star::datatransfer::clipboard::RenderingCapabilities; + +// definition of static members +CWinClipbImpl* CWinClipbImpl::s_pCWinClipbImpl = nullptr; +osl::Mutex CWinClipbImpl::s_aMutex; + +CWinClipbImpl::CWinClipbImpl( const OUString& aClipboardName, CWinClipboard* theWinClipboard ) : + m_itsName( aClipboardName ), + m_pWinClipboard( theWinClipboard ), + m_pCurrentClipContent( nullptr ) +{ + OSL_ASSERT( nullptr != m_pWinClipboard ); + + // necessary to reassociate from + // the static callback function + s_pCWinClipbImpl = this; + registerClipboardViewer( ); +} + +CWinClipbImpl::~CWinClipbImpl( ) +{ + { + MutexGuard aGuard(s_aMutex); + s_pCWinClipbImpl = nullptr; + } + + unregisterClipboardViewer( ); +} + +Reference< XTransferable > CWinClipbImpl::getContents( ) +{ + // use the shortcut or create a transferable from + // system clipboard + { + MutexGuard aGuard(m_ClipContentMutex); + + 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 + } + + Reference< XTransferable > rClipContent; + + // 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 + IDataObjectPtr pIDo( new CAPNDataObject( pIDataObject ) ); + + // remember pIDo destroys itself due to the smart pointer + rClipContent = CDOTransferable::create( m_pWinClipboard->m_xContext, pIDo ); + + MutexGuard aGuard(m_ClipContentMutex); + m_foreignContent = rClipContent; + } + + return rClipContent; +} + +void CWinClipbImpl::setContents( + const Reference< XTransferable >& xTransferable, + const Reference< XClipboardOwner >& xClipboardOwner ) +{ + IDataObjectPtr pIDataObj; + + if ( xTransferable.is( ) ) + { + { + MutexGuard aGuard(m_ClipContentMutex); + + m_foreignContent.clear(); + + m_pCurrentClipContent + = new CXNotifyingDataObject(CDTransObjFactory::createDataObjFromTransferable( + m_pWinClipboard->m_xContext, xTransferable), + xTransferable, xClipboardOwner, this); + } + + pIDataObj = IDataObjectPtr( m_pCurrentClipContent ); + } + + m_MtaOleClipboard.setClipboard(pIDataObj.get()); +} + +OUString CWinClipbImpl::getName( ) +{ + return m_itsName; +} + +sal_Int8 CWinClipbImpl::getRenderingCapabilities( ) +{ + return ( Delayed | Persistant ); +} + +void CWinClipbImpl::flushClipboard( ) +{ + // actually it should be ClearableMutexGuard aGuard( m_ClipContentMutex ); + // 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( ); +} + +void CWinClipbImpl::registerClipboardViewer( ) +{ + m_MtaOleClipboard.registerClipViewer( CWinClipbImpl::onClipboardContentChanged ); +} + +void CWinClipbImpl::unregisterClipboardViewer( ) +{ + m_MtaOleClipboard.registerClipViewer( nullptr ); +} + +void CWinClipbImpl::dispose() +{ + OSL_ENSURE( !m_pCurrentClipContent, "Clipboard was not flushed before shutdown!" ); +} + +void WINAPI CWinClipbImpl::onClipboardContentChanged() +{ + MutexGuard aGuard( s_aMutex ); + + // reassociation to instance through static member + if ( nullptr != s_pCWinClipbImpl ) + { + s_pCWinClipbImpl->m_foreignContent.clear(); + s_pCWinClipbImpl->m_pWinClipboard->notifyAllClipboardListener( ); + } +} + +void CWinClipbImpl::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 + MutexGuard aGuard( m_ClipContentMutex ); + + if ( m_pCurrentClipContent == theCaller ) + m_pCurrentClipContent = nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/clipb/WinClipbImpl.hxx b/dtrans/source/win32/clipb/WinClipbImpl.hxx new file mode 100644 index 000000000..cd5878e6b --- /dev/null +++ b/dtrans/source/win32/clipb/WinClipbImpl.hxx @@ -0,0 +1,106 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_CLIPB_WINCLIPBIMPL_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_CLIPB_WINCLIPBIMPL_HXX + +#include +#include +#include +#include +#include +#include "MtaOleClipb.hxx" + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include + +class CWinClipboard; +class CXNotifyingDataObject; + +// impl class to avoid deadlocks between XTDataObject +// and the clipboard implementation + +class CWinClipbImpl +{ +public: + ~CWinClipbImpl( ); + +protected: + CWinClipbImpl( const OUString& aClipboardName, CWinClipboard* theWinClipboard ); + + /// @throws css::uno::RuntimeException + css::uno::Reference< css::datatransfer::XTransferable > getContents( ); + + /// @throws css::uno::RuntimeException + void setContents( + const css::uno::Reference< css::datatransfer::XTransferable >& xTransferable, + const css::uno::Reference< css::datatransfer::clipboard::XClipboardOwner >& xClipboardOwner ); + + /// @throws css::uno::RuntimeException + OUString getName( ); + + // XClipboardEx + + /// @throws css::uno::RuntimeException + static sal_Int8 getRenderingCapabilities( ); + + // XFlushableClipboard + + /// @throws css::uno::RuntimeException + void flushClipboard( ); + + // XComponent + + /// @throws css::uno::RuntimeException + void dispose( ); + + // member functions + + void registerClipboardViewer( ); + void unregisterClipboardViewer( ); + + static void WINAPI onClipboardContentChanged(); + +private: + void onReleaseDataObject( CXNotifyingDataObject* theCaller ); + +private: + OUString m_itsName; + CMtaOleClipboard m_MtaOleClipboard; + CWinClipboard* m_pWinClipboard; + CXNotifyingDataObject* m_pCurrentClipContent; + com::sun::star::uno::Reference< com::sun::star::datatransfer::XTransferable > m_foreignContent; + osl::Mutex m_ClipContentMutex; + + static osl::Mutex s_aMutex; + static CWinClipbImpl* s_pCWinClipbImpl; + +private: + CWinClipbImpl( const CWinClipbImpl& ); + CWinClipbImpl& operator=( const CWinClipbImpl& ); + + friend class CWinClipboard; + friend class CXNotifyingDataObject; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/clipb/WinClipboard.cxx b/dtrans/source/win32/clipb/WinClipboard.cxx new file mode 100644 index 000000000..919065a9f --- /dev/null +++ b/dtrans/source/win32/clipb/WinClipboard.cxx @@ -0,0 +1,239 @@ +/* -*- 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 +#include "WinClipboard.hxx" +#include +#include +#include +#include +#include "WinClipbImpl.hxx" + +using namespace osl; +using namespace std; +using namespace cppu; + +using namespace com::sun::star::uno; +using namespace com::sun::star::datatransfer; +using namespace com::sun::star::datatransfer::clipboard; +using namespace com::sun::star::lang; + +#define WINCLIPBOARD_IMPL_NAME "com.sun.star.datatransfer.clipboard.ClipboardW32" + +namespace +{ + Sequence< OUString > WinClipboard_getSupportedServiceNames() + { + Sequence< OUString > aRet { "com.sun.star.datatransfer.clipboard.SystemClipboard" }; + return aRet; + } +} + +/*XEventListener,*/ +CWinClipboard::CWinClipboard( const Reference< XComponentContext >& rxContext, const OUString& aClipboardName ) : + WeakComponentImplHelper< XSystemClipboard, XFlushableClipboard, XServiceInfo >( m_aCbListenerMutex ), + m_xContext( rxContext ) +{ + m_pImpl.reset( new CWinClipbImpl( aClipboardName, this ) ); +} + +// 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 + +Reference< XTransferable > SAL_CALL CWinClipboard::getContents( ) +{ + MutexGuard aGuard( m_aMutex ); + + if ( rBHelper.bDisposed ) + throw DisposedException("object is already disposed", + static_cast< XClipboardEx* >( this ) ); + + if ( nullptr != m_pImpl.get( ) ) + return m_pImpl->getContents( ); + + return Reference< XTransferable >( ); +} + +void SAL_CALL CWinClipboard::setContents( const Reference< XTransferable >& xTransferable, + const Reference< XClipboardOwner >& xClipboardOwner ) +{ + MutexGuard aGuard( m_aMutex ); + + if ( rBHelper.bDisposed ) + throw DisposedException("object is already disposed", + static_cast< XClipboardEx* >( this ) ); + + if ( nullptr != m_pImpl.get( ) ) + m_pImpl->setContents( xTransferable, xClipboardOwner ); +} + +OUString SAL_CALL CWinClipboard::getName( ) +{ + if ( rBHelper.bDisposed ) + throw DisposedException("object is already disposed", + static_cast< XClipboardEx* >( this ) ); + + if ( nullptr != m_pImpl.get( ) ) + return m_pImpl->getName( ); + + return OUString(); +} + +// XFlushableClipboard + +void SAL_CALL CWinClipboard::flushClipboard( ) +{ + MutexGuard aGuard( m_aMutex ); + + if ( rBHelper.bDisposed ) + throw DisposedException("object is already disposed", + static_cast< XClipboardEx* >( this ) ); + + if ( nullptr != m_pImpl.get( ) ) + m_pImpl->flushClipboard( ); +} + +// XClipboardEx + +sal_Int8 SAL_CALL CWinClipboard::getRenderingCapabilities( ) +{ + if ( rBHelper.bDisposed ) + throw DisposedException("object is already disposed", + static_cast< XClipboardEx* >( this ) ); + + if ( nullptr != m_pImpl.get( ) ) + return CWinClipbImpl::getRenderingCapabilities( ); + + return 0; +} + +// XClipboardNotifier + +void SAL_CALL CWinClipboard::addClipboardListener( const Reference< XClipboardListener >& listener ) +{ + if ( rBHelper.bDisposed ) + throw DisposedException("object is already disposed", + static_cast< XClipboardEx* >( this ) ); + + // check input parameter + if ( !listener.is( ) ) + throw IllegalArgumentException("empty reference", + static_cast< XClipboardEx* >( this ), + 1 ); + + rBHelper.aLC.addInterface( cppu::UnoType::get(), listener ); +} + +void SAL_CALL CWinClipboard::removeClipboardListener( const Reference< XClipboardListener >& listener ) +{ + if ( rBHelper.bDisposed ) + throw DisposedException("object is already disposed", + static_cast< XClipboardEx* >( this ) ); + + // check input parameter + if ( !listener.is( ) ) + throw IllegalArgumentException("empty reference", + static_cast< XClipboardEx* >( this ), + 1 ); + + rBHelper.aLC.removeInterface( cppu::UnoType::get(), listener ); +} + +void CWinClipboard::notifyAllClipboardListener( ) +{ + if ( !rBHelper.bDisposed ) + { + ClearableMutexGuard aGuard( rBHelper.rMutex ); + if ( !rBHelper.bDisposed ) + { + aGuard.clear( ); + + OInterfaceContainerHelper* pICHelper = rBHelper.aLC.getContainer( + cppu::UnoType::get()); + + if ( pICHelper ) + { + try + { + OInterfaceIteratorHelper iter(*pICHelper); + Reference rXTransf(m_pImpl->getContents()); + ClipboardEvent aClipbEvent(static_cast(this), rXTransf); + + while(iter.hasMoreElements()) + { + try + { + Reference xCBListener(iter.next(), UNO_QUERY); + if (xCBListener.is()) + xCBListener->changedContents(aClipbEvent); + } + catch(RuntimeException&) + { + OSL_FAIL( "RuntimeException caught" ); + } + } + } + catch(const css::lang::DisposedException&) + { + OSL_FAIL("Service Manager disposed"); + + // no further clipboard changed notifications + m_pImpl->unregisterClipboardViewer(); + } + + } // end if + } // end if + } // end if +} + +// overwritten base class method which will be +// called by the base class dispose method + +void SAL_CALL CWinClipboard::disposing() +{ + // do my own stuff + m_pImpl->dispose( ); + + // force destruction of the impl class + m_pImpl.reset(); +} + +// XServiceInfo + +OUString SAL_CALL CWinClipboard::getImplementationName( ) +{ + return WINCLIPBOARD_IMPL_NAME; +} + +sal_Bool SAL_CALL CWinClipboard::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > SAL_CALL CWinClipboard::getSupportedServiceNames( ) +{ + return WinClipboard_getSupportedServiceNames(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/clipb/WinClipboard.hxx b/dtrans/source/win32/clipb/WinClipboard.hxx new file mode 100644 index 000000000..db3f1ab18 --- /dev/null +++ b/dtrans/source/win32/clipb/WinClipboard.hxx @@ -0,0 +1,123 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_CLIPB_WINCLIPBOARD_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_CLIPB_WINCLIPBOARD_HXX + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// forward +class CWinClipbImpl; + +// 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! + +// helper class, so that the mutex is constructed +// before the constructor of WeakComponentImplHelper +// will be called and initialized with this mutex +class CWinClipboardDummy +{ +protected: + osl::Mutex m_aMutex; + osl::Mutex m_aCbListenerMutex; +}; + +class CWinClipboard : + public CWinClipboardDummy, + public cppu::WeakComponentImplHelper< + css::datatransfer::clipboard::XSystemClipboard, + css::datatransfer::clipboard::XFlushableClipboard, + css::lang::XServiceInfo > +{ +public: + CWinClipboard( const css::uno::Reference< css::uno::XComponentContext >& rxContext, + const OUString& aClipboardName ); + + // 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; + + // overwrite base class method, which is called + // by base class dispose function + + virtual void SAL_CALL disposing() 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: + void notifyAllClipboardListener( ); + +private: + std::unique_ptr< CWinClipbImpl > m_pImpl; + css::uno::Reference< css::uno::XComponentContext > m_xContext; + + friend class CWinClipbImpl; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/clipb/wcbentry.cxx b/dtrans/source/win32/clipb/wcbentry.cxx new file mode 100644 index 000000000..e91bde9c0 --- /dev/null +++ b/dtrans/source/win32/clipb/wcbentry.cxx @@ -0,0 +1,82 @@ +/* -*- 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 +#include +#include +#include +#include "WinClipboard.hxx" + +#define WINCLIPBOARD_SERVICE_NAME "com.sun.star.datatransfer.clipboard.SystemClipboard" + +#define WINCLIPBOARD_IMPL_NAME "com.sun.star.datatransfer.clipboard.ClipboardW32" + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::registry; +using namespace ::cppu; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::datatransfer::clipboard; + +namespace +{ + + // functions to create a new Clipboard instance; is needed by factory helper implementation + // @param rServiceManager - service manager, useful if the component needs other uno services + // so we should give it to every UNO-Implementation component + + Reference< XInterface > createInstance( const Reference< XMultiServiceFactory >& rServiceManager ) + { + return static_cast( + new CWinClipboard(comphelper::getComponentContext(rServiceManager), "")); + } +} + +extern "C" +{ + +// component_getFactory +// returns a factory to create XFilePicker-Services + +SAL_DLLPUBLIC_EXPORT void* sysdtrans_component_getFactory( const char* pImplName, void* pSrvManager, void* /*pRegistryKey*/ ) +{ + void* pRet = nullptr; + + if ( pSrvManager && ( 0 == rtl_str_compare( pImplName, WINCLIPBOARD_IMPL_NAME ) ) ) + { + Sequence< OUString > aSNS { WINCLIPBOARD_SERVICE_NAME }; + + //OUString( FPS_IMPL_NAME ) + Reference< XSingleServiceFactory > xFactory ( createOneInstanceFactory( + static_cast< XMultiServiceFactory* > ( pSrvManager ), + OUString::createFromAscii( pImplName ), + createInstance, + aSNS ) ); + if ( xFactory.is() ) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + } + + return pRet; +} + +} // extern "C" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/dndentry.cxx b/dtrans/source/win32/dnd/dndentry.cxx new file mode 100644 index 000000000..0a44283e5 --- /dev/null +++ b/dtrans/source/win32/dnd/dndentry.cxx @@ -0,0 +1,88 @@ +/* -*- 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 +#include +#include +#include + +#include "source.hxx" +#include "target.hxx" + +using namespace ::com::sun::star::uno ; +using namespace ::com::sun::star::registry ; +using namespace ::cppu ; +using namespace ::com::sun::star::lang; + +static Reference< XInterface > createDragSource( const Reference< XMultiServiceFactory >& rServiceManager ) +{ + DragSource* pSource= new DragSource( comphelper::getComponentContext(rServiceManager) ); + return Reference( static_cast(pSource), UNO_QUERY); +} + +static Reference< XInterface > createDropTarget( const Reference< XMultiServiceFactory >& rServiceManager ) +{ + DropTarget* pTarget= new DropTarget( comphelper::getComponentContext(rServiceManager) ); + return Reference( static_cast(pTarget), UNO_QUERY); +} + +extern "C" +{ + +SAL_DLLPUBLIC_EXPORT void* +dnd_component_getFactory( const char* pImplName, void* pSrvManager, void* /*pRegistryKey*/ ) +{ + void* pRet = nullptr; + Reference< XSingleServiceFactory > xFactory; + + if ( pSrvManager && ( 0 == rtl_str_compare( pImplName, DNDSOURCE_IMPL_NAME ) ) ) + { + Sequence< OUString > aSNS { DNDSOURCE_SERVICE_NAME }; + + xFactory= createSingleFactory( + static_cast< XMultiServiceFactory* > ( pSrvManager ), + OUString::createFromAscii( pImplName ), + createDragSource, + aSNS); + + } + else if( pSrvManager && ( 0 == rtl_str_compare( pImplName, DNDTARGET_IMPL_NAME ) ) ) + { + Sequence< OUString > aSNS { DNDTARGET_SERVICE_NAME }; + + xFactory= createSingleFactory( + static_cast< XMultiServiceFactory* > ( pSrvManager ), + OUString::createFromAscii( pImplName ), + createDropTarget, + aSNS); + + } + + if ( xFactory.is() ) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + + return pRet; +} + +} // extern "C" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/globals.cxx b/dtrans/source/win32/dnd/globals.cxx new file mode 100644 index 000000000..fcddef22e --- /dev/null +++ b/dtrans/source/win32/dnd/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 + +#include "globals.hxx" + +//--> TRA +#include + +// 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/dtrans/source/win32/dnd/globals.hxx b/dtrans/source/win32/dnd/globals.hxx new file mode 100644 index 000000000..7851c2eec --- /dev/null +++ b/dtrans/source/win32/dnd/globals.hxx @@ -0,0 +1,81 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DND_GLOBALS_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DND_GLOBALS_HXX + +#include + +#include +#include + +namespace com::sun::star::datatransfer { class XTransferable; } + +#include +#include + +#define DNDSOURCE_SERVICE_NAME "com.sun.star.datatransfer.dnd.OleDragSource" +#define DNDSOURCE_IMPL_NAME "com.sun.star.comp.datatransfer.dnd.OleDragSource_V1" + +#define DNDTARGET_SERVICE_NAME "com.sun.star.datatransfer.dnd.OleDropTarget" +#define DNDTARGET_IMPL_NAME "com.sun.star.comp.datatransfer.dnd.OleDropTarget_V1" + +// 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); + +struct MutexDummy +{ + osl::Mutex m_mutex; +}; + +extern css::uno::Reference g_XTransferable; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/idroptarget.cxx b/dtrans/source/win32/dnd/idroptarget.cxx new file mode 100644 index 000000000..8b403eb7a --- /dev/null +++ b/dtrans/source/win32/dnd/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( this); + else if ( riid == __uuidof( IDropTarget)) + *ppvObject= static_cast( 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/dtrans/source/win32/dnd/idroptarget.hxx b/dtrans/source/win32/dnd/idroptarget.hxx new file mode 100644 index 000000000..a86739f87 --- /dev/null +++ b/dtrans/source/win32/dnd/idroptarget.hxx @@ -0,0 +1,67 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DND_IDROPTARGET_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DND_IDROPTARGET_HXX + +#include "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; + +}; +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/source.cxx b/dtrans/source/win32/dnd/source.cxx new file mode 100644 index 000000000..c797684d2 --- /dev/null +++ b/dtrans/source/win32/dnd/source.cxx @@ -0,0 +1,365 @@ +/* -*- 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 +#include +#include +#include +#include +#include + +#include +#include + +#include "source.hxx" +#include "globals.hxx" +#include "sourcecontext.hxx" +#include "../../inc/DtObjFactory.hxx" +#include +#include +#include +#include + +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 unsigned __stdcall DndOleSTAFunc(LPVOID pParams); + +DragSource::DragSource( const Reference& rxContext): + WeakComponentImplHelper< XDragSource, XInitialization, XServiceInfo >(m_mutex), + 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& trans, + const Reference& 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. + unsigned threadId; + HANDLE hThread= reinterpret_cast(_beginthreadex( + 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(static_cast(*o3tl::doAccess(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& trans, + const Reference& 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&) + { + OSL_FAIL("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( this); + else if ( riid == __uuidof( IDropSource) ) + *ppvObject= static_cast( this); + + if(*ppvObject) + { + AddRef(); + return S_OK; + } + else + return E_NOINTERFACE; + +} + +ULONG STDMETHODCALLTYPE DragSource::AddRef() +{ + acquire(); + return static_cast(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(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 DNDSOURCE_IMPL_NAME; +} +// XServiceInfo +sal_Bool SAL_CALL DragSource::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > SAL_CALL DragSource::getSupportedServiceNames( ) +{ + return { DNDSOURCE_SERVICE_NAME }; +} + +/** 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. */ +unsigned __stdcall DndOleSTAFunc(LPVOID pParams) +{ + osl_setThreadName("DragSource DndOleSTAFunc"); + + // The structure contains all arguments for DoDragDrop and other + DragSource *pSource= static_cast(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(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(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/dtrans/source/win32/dnd/source.hxx b/dtrans/source/win32/dnd/source.hxx new file mode 100644 index 000000000..8ec0162c3 --- /dev/null +++ b/dtrans/source/win32/dnd/source.hxx @@ -0,0 +1,127 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DND_SOURCE_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DND_SOURCE_HXX + +#include +#include +#include +#include +#include +#include +#include "globals.hxx" +#include + +#include + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; +using namespace cppu; +using namespace osl; +using namespace ::com::sun::star::datatransfer; +using namespace ::com::sun::star::datatransfer::dnd; + +class SourceContext; +// RIGHT MOUSE BUTTON drag and drop not supported currently. +// ALT modifier is considered to effect a user selection of effects +class DragSource: + public MutexDummy, + public WeakComponentImplHelper, + public IDropSource + +{ + Reference m_xContext; + HWND m_hAppWindow; + + // The mouse button that set off the drag and drop operation + short m_MouseButton; + + // First starting a new drag and drop thread if + // the last one has finished + void StartDragImpl( + const DragGestureEvent& trigger, + sal_Int8 sourceActions, + sal_Int32 cursor, + sal_Int32 image, + const Reference& trans, + const Reference& listener); + +public: + long m_RunningDndOperationCount; + +public: + // only valid for one dnd operation + // the thread ID of the thread which created the window + DWORD m_threadIdWindow; + // The context notifies the XDragSourceListener s + Reference m_currentContext; + + // the wrapper for the Transferable ( startDrag) + IDataObjectPtr m_spDataObject; + + sal_Int8 m_sourceActions; + +public: + explicit DragSource(const Reference& rxContext); + virtual ~DragSource() override; + DragSource(const DragSource&) = delete; + DragSource &operator= ( const DragSource&) = delete; + + // XInitialization + virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override; + + // XDragSource + virtual sal_Bool SAL_CALL isDragImageSupported( ) override; + virtual sal_Int32 SAL_CALL getDefaultCursor( sal_Int8 dragAction ) override; + virtual void SAL_CALL startDrag( const DragGestureEvent& trigger, + sal_Int8 sourceActions, + sal_Int32 cursor, + sal_Int32 image, + const Reference& trans, + const Reference& listener ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + 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; + + // IDropSource + virtual HRESULT STDMETHODCALLTYPE QueryContinueDrag( + /* [in] */ BOOL fEscapePressed, + /* [in] */ DWORD grfKeyState) override; + + virtual HRESULT STDMETHODCALLTYPE GiveFeedback( + /* [in] */ DWORD dwEffect) override; + +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/sourcecontext.cxx b/dtrans/source/win32/dnd/sourcecontext.cxx new file mode 100644 index 000000000..8531fd8a1 --- /dev/null +++ b/dtrans/source/win32/dnd/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 + +#include "sourcecontext.hxx" + +using namespace com::sun::star::datatransfer::dnd; +using namespace com::sun::star::datatransfer::dnd::DNDConstants; + +SourceContext::SourceContext( DragSource* pSource, + const Reference& listener): + WeakComponentImplHelper(m_mutex), + m_pDragSource( pSource), + m_dragSource( static_cast( m_pDragSource) ) +{ +#if OSL_DEBUG_LEVEL > 1 + if( listener.is()) +#endif + rBHelper.addListener( cppu::UnoType::get(), listener ); +} + +SourceContext::~SourceContext() +{ +} + +void SourceContext::addDragSourceListener( + const Reference& ) +{ +} + +void SourceContext::removeDragSourceListener( + const Reference& ) +{ +} + +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( this); + e.Source.set( static_cast( this), UNO_QUERY); + + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( + cppu::UnoType::get()); + + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer); + while( iter.hasMoreElements()) + { + Reference listener( + static_cast( 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( this); + e.Source.set( static_cast( this), UNO_QUERY); + + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( + cppu::UnoType::get()); + + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer); + while( iter.hasMoreElements()) + { + Reference listener( + static_cast( iter.next())); + listener->dropActionChanged( e); + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/sourcecontext.hxx b/dtrans/source/win32/dnd/sourcecontext.hxx new file mode 100644 index 000000000..81b1682eb --- /dev/null +++ b/dtrans/source/win32/dnd/sourcecontext.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 . + */ +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DND_SOURCECONTEXT_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DND_SOURCECONTEXT_HXX + +#include +#include + +#include "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 MutexDummy, + public WeakComponentImplHelper +{ + DragSource* m_pDragSource; + Reference m_dragSource; + // the action ( copy, move etc) + sal_Int8 m_currentAction; + +public: + SourceContext( DragSource* pSource, const Reference& listener); + ~SourceContext() override; + SourceContext(const SourceContext&) = delete; + SourceContext &operator= (const SourceContext&) = delete; + + /// @throws RuntimeException + virtual void addDragSourceListener( const Reference& dsl ); + /// @throws RuntimeException + virtual void removeDragSourceListener( const Reference& 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); + +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/target.cxx b/dtrans/source/win32/dnd/target.cxx new file mode 100644 index 000000000..7592eb390 --- /dev/null +++ b/dtrans/source/win32/dnd/target.cxx @@ -0,0 +1,628 @@ +/* -*- 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 +#include +#include +#include + +#include +#include "target.hxx" +#include "idroptarget.hxx" +#include "globals.hxx" +#include "targetdropcontext.hxx" +#include "targetdragcontext.hxx" +#include +#include + +#include "../dtobj/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& rxContext): + WeakComponentImplHelper(m_mutex), + 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(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(static_cast(*o3tl::doAccess(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(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(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 + while( GetMessageW(&msg, nullptr, 0, 0) ) + { + if( msg.message == WM_REGISTERDRAGDROP) + { + DropTarget *pTarget= reinterpret_cast(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(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 DNDTARGET_IMPL_NAME; +} +// XServiceInfo +sal_Bool SAL_CALL DropTarget::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > SAL_CALL DropTarget::getSupportedServiceNames( ) +{ + return { DNDTARGET_SERVICE_NAME }; +} + +// XDropTarget +void SAL_CALL DropTarget::addDropTargetListener( const Reference< XDropTargetListener >& dtl ) +{ + rBHelper.addListener( cppu::UnoType::get(), dtl ); +} + +void SAL_CALL DropTarget::removeDropTargetListener( const Reference< XDropTargetListener >& dtl ) +{ + rBHelper.removeListener( cppu::UnoType::get(), dtl ); +} + +sal_Bool SAL_CALL DropTarget::isActive( ) +{ + return m_bActive; //m_bDropTargetRegistered; +} + +void SAL_CALL DropTarget::setActive( sal_Bool _b ) +{ + MutexGuard g(m_mutex); + 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= CDOTransferable::create( + 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(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 asynchron, 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(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 asynchron, 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(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(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::get()); + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer); + while( iter.hasMoreElements()) + { + Reference listener( static_cast( iter.next())); + listener->drop( dte); + } + } +} + +void DropTarget::fire_dragEnter( const DropTargetDragEnterEvent& e ) +{ + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType::get()); + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer); + while( iter.hasMoreElements()) + { + Reference listener( static_cast( iter.next())); + listener->dragEnter( e); + } + } +} + +void DropTarget::fire_dragExit( const DropTargetEvent& dte ) +{ + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType::get()); + + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer); + while( iter.hasMoreElements()) + { + Reference listener( static_cast( iter.next())); + listener->dragExit( dte); + } + } +} + +void DropTarget::fire_dragOver( const DropTargetDragEvent& dtde ) +{ + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType::get()); + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer ); + while( iter.hasMoreElements()) + { + Reference listener( static_cast( iter.next())); + listener->dragOver( dtde); + } + } +} + +void DropTarget::fire_dropActionChanged( const DropTargetDragEvent& dtde ) +{ + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType::get()); + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer); + while( iter.hasMoreElements()) + { + Reference listener( static_cast( 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& context) +{ + if( context == m_currentDropContext) + { + m_nCurrentDropAction= dropOperation; + } +} + +void DropTarget::_rejectDrop( const Reference& context) +{ + if( context == m_currentDropContext) + { + m_nCurrentDropAction= ACTION_NONE; + } +} + +void DropTarget::_dropComplete(bool success, const Reference& 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& context) +{ + if( context == m_currentDragContext) + { + m_nLastDropAction= dragOperation; + } +} + +void DropTarget::_rejectDrag( const Reference& 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; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/target.hxx b/dtrans/source/win32/dnd/target.hxx new file mode 100644 index 000000000..3f266b240 --- /dev/null +++ b/dtrans/source/win32/dnd/target.hxx @@ -0,0 +1,177 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DND_TARGET_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DND_TARGET_HXX + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include "globals.hxx" + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; +using namespace cppu; +using namespace osl; +using namespace ::com::sun::star::datatransfer; +using namespace ::com::sun::star::datatransfer::dnd; + +// The client +// has to call XComponent::dispose. The thread that calls initialize +// must also execute the destruction of the instance. This is because +// initialize calls OleInitialize and the destructor calls OleUninitialize. +// If the service calls OleInitialize then it also calls OleUnitialize when +// it is destroyed. Therefore no second instance may exist which was +// created in the same thread and still needs OLE. +class DropTarget: public MutexDummy, + public WeakComponentImplHelper< XInitialization, XDropTarget, XServiceInfo> + +{ +private: + friend DWORD WINAPI DndTargetOleSTAFunc(LPVOID pParams); + // The native window which acts as drop target. + // It is set in initialize. In case RegisterDragDrop fails it is set + // to NULL + HWND m_hWnd; // set by initialize + // Holds the thread id of the thread which created the window that is the + // drop target. Only used when DropTarget::initialize is called from an MTA + // thread + DWORD m_threadIdWindow; + // This is the thread id of the OLE thread that is created in DropTarget::initialize + // when the calling thread is an MTA + DWORD m_threadIdTarget; + // The handle of the thread that is created in DropTarget::initialize + // when the calling thread is an MTA + HANDLE m_hOleThread; + // The thread id of the thread which called initialize. When the service dies + // than m_oleThreadId is used to determine if the service successfully called + // OleInitialize. If so then OleUninitialize has to be called. + DWORD m_oleThreadId; + // An Instance of IDropTargetImpl which receives calls from the system's drag + // and drop implementation. It delegate the calls to name alike functions in + // this class. + IDropTarget* m_pDropTarget; + + Reference m_xContext; + // If m_bActive == sal_True then events are fired to XDropTargetListener s, + // none otherwise. The default value is sal_True. + bool m_bActive; + sal_Int8 m_nDefaultActions; + + // This value is set when a XDropTargetListener calls accept or reject on + // the XDropTargetDropContext or XDropTargetDragContext. + // The values are from the DNDConstants group. + sal_Int8 m_nCurrentDropAction; + // This value is manipulated by the XDropTargetListener + sal_Int8 m_nLastDropAction; + + Reference m_currentData; + // The current action is used to determine if the USER + // action has changed (dropActionChanged) +// sal_Int8 m_userAction; + // Set by listeners when they call XDropTargetDropContext::dropComplete + bool m_bDropComplete; + Reference m_currentDragContext; + Reference m_currentDropContext; + +public: + explicit DropTarget(const Reference& rxContext); + virtual ~DropTarget() override; + DropTarget(DropTarget const &) = delete; + DropTarget &operator= (DropTarget const &) = delete; + + // Overrides WeakComponentImplHelper::disposing which is called by + // WeakComponentImplHelper::dispose + // Must be called. + virtual void SAL_CALL disposing() override; + // XInitialization + virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override; + + // XDropTarget + virtual void SAL_CALL addDropTargetListener( const Reference< XDropTargetListener >& dtl ) override; + virtual void SAL_CALL removeDropTargetListener( const Reference< XDropTargetListener >& dtl ) override; + // Default is not active + virtual sal_Bool SAL_CALL isActive( ) override; + virtual void SAL_CALL setActive( sal_Bool isActive ) override; + virtual sal_Int8 SAL_CALL getDefaultActions( ) override; + virtual void SAL_CALL setDefaultActions( sal_Int8 actions ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // Functions called from the IDropTarget implementation ( m_pDropTarget) + virtual HRESULT DragEnter( + /* [unique][in] */ IDataObject *pDataObj, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD *pdwEffect); + + virtual HRESULT STDMETHODCALLTYPE DragOver( + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD *pdwEffect); + + virtual HRESULT STDMETHODCALLTYPE DragLeave( ) ; + + virtual HRESULT STDMETHODCALLTYPE Drop( + /* [unique][in] */ IDataObject *pDataObj, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD *pdwEffect); + +// Non - interface functions -------------------------------------------------- +// XDropTargetDropContext delegated from DropContext + + void _acceptDrop( sal_Int8 dropOperation, const Reference& context); + void _rejectDrop( const Reference& context); + void _dropComplete( bool success, const Reference& context); + +// XDropTargetDragContext delegated from DragContext + void _acceptDrag( sal_Int8 dragOperation, const Reference& context); + void _rejectDrag( const Reference& context); + +protected: + // Gets the current action dependent on the pressed modifiers, the effects + // supported by the drop source (IDropSource) and the default actions of the + // drop target (XDropTarget, this class)) + inline sal_Int8 getFilteredActions( DWORD grfKeyState, DWORD sourceActions); + // Only filters with the default actions + inline sal_Int8 getFilteredActions( DWORD grfKeyState); + + void fire_drop( const DropTargetDropEvent& dte); + void fire_dragEnter( const DropTargetDragEnterEvent& dtde ); + void fire_dragExit( const DropTargetEvent& dte ); + void fire_dragOver( const DropTargetDragEvent& dtde ); + void fire_dropActionChanged( const DropTargetDragEvent& dtde ); + +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/targetdragcontext.cxx b/dtrans/source/win32/dnd/targetdragcontext.cxx new file mode 100644 index 000000000..4ffd16123 --- /dev/null +++ b/dtrans/source/win32/dnd/targetdragcontext.cxx @@ -0,0 +1,43 @@ +/* -*- 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( this) ); + +} +void SAL_CALL TargetDragContext::rejectDrag( ) +{ + m_pDropTarget->_rejectDrag( static_cast( this) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/targetdragcontext.hxx b/dtrans/source/win32/dnd/targetdragcontext.hxx new file mode 100644 index 000000000..a8f48cad1 --- /dev/null +++ b/dtrans/source/win32/dnd/targetdragcontext.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 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DND_TARGETDRAGCONTEXT_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DND_TARGETDRAGCONTEXT_HXX + +#include +#include +#include + +#include "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 +{ + // 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; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/targetdropcontext.cxx b/dtrans/source/win32/dnd/targetdropcontext.cxx new file mode 100644 index 000000000..9719664a9 --- /dev/null +++ b/dtrans/source/win32/dnd/targetdropcontext.cxx @@ -0,0 +1,53 @@ +/* -*- 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( this) ); +} + +void SAL_CALL TargetDropContext::rejectDrop( ) +{ + m_pDropTarget->_rejectDrop( static_cast( this) ); +} + +void SAL_CALL TargetDropContext::dropComplete( sal_Bool success ) +{ + m_pDropTarget->_dropComplete( success, static_cast( this) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dnd/targetdropcontext.hxx b/dtrans/source/win32/dnd/targetdropcontext.hxx new file mode 100644 index 000000000..b7db849fe --- /dev/null +++ b/dtrans/source/win32/dnd/targetdropcontext.hxx @@ -0,0 +1,54 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DND_TARGETDROPCONTEXT_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DND_TARGETDROPCONTEXT_HXX + +#include +#include + +#include "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 +{ + // 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; +}; +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dtobj/APNDataObject.cxx b/dtrans/source/win32/dtobj/APNDataObject.cxx new file mode 100644 index 000000000..53342f21f --- /dev/null +++ b/dtrans/source/win32/dtobj/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 + +#include + +#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(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(*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(ppIDataObj)); + OSL_ENSURE(CO_E_NOTINITIALIZED != hr, "COM is not initialized"); + } + } + return hr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dtobj/APNDataObject.hxx b/dtrans/source/win32/dtobj/APNDataObject.hxx new file mode 100644 index 000000000..2c1d9718e --- /dev/null +++ b/dtrans/source/win32/dtobj/APNDataObject.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 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DTOBJ_APNDATAOBJECT_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DTOBJ_APNDATAOBJECT_HXX + +#include + +/* + 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 ); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dtobj/DOTransferable.cxx b/dtrans/source/win32/dtobj/DOTransferable.cxx new file mode 100644 index 000000000..8f27e7124 --- /dev/null +++ b/dtrans/source/win32/dtobj/DOTransferable.cxx @@ -0,0 +1,589 @@ +/* -*- 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 +#include +#include +#include + +#include "DOTransferable.hxx" +#include "../misc/ImplHelper.hxx" +#include +#include "DTransHelper.hxx" +#include "TxtCnvtHlp.hxx" +#include "MimeAttrib.hxx" +#include "FmtFilter.hxx" +#include "Fetc.hxx" +#include +#include +#include +#include +#include + +using namespace std; +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>::get(); + const Type CPPUTYPE_OUSTRING = cppu::UnoType::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("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("dtrans", "clipDataToByteStream: Seek() failed"); + } + + ULONG nRead = 0; + hr = pStream->Read(aByteSequence.getArray(), nMemSize, &nRead); + if (FAILED(hr)) + { + SAL_WARN("dtrans", "clipDataToByteStream: Read() failed"); + } + if (nRead < nMemSize) + { + SAL_WARN("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 + +Reference< XTransferable > CDOTransferable::create( const Reference< XComponentContext >& rxContext, + IDataObjectPtr pIDataObject ) +{ + CDOTransferable* pTransf = new CDOTransferable(rxContext, pIDataObject); + Reference refDOTransf(pTransf); + + pTransf->acquire(); + pTransf->initFlavorList(); + pTransf->release(); + + return refDOTransf; +} + +CDOTransferable::CDOTransferable( + const Reference< XComponentContext >& rxContext, IDataObjectPtr rDataObject ) : + m_rDataObject( rDataObject ), + m_xContext( rxContext ), + m_DataFormatTranslator( rxContext ), + m_bUnicodeRegistered( false ), + m_TxtFormatOnClipboard( CF_INVALID ) +{ +} + +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 = makeAny( 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( ) +{ + sal::systools::COMReference pEnumFormatEtc; + HRESULT hr = m_rDataObject->EnumFormatEtc( DATADIR_GET, &pEnumFormatEtc ); + if ( SUCCEEDED( hr ) ) + { + pEnumFormatEtc->Reset( ); + + FORMATETC fetc; + while ( S_OK == pEnumFormatEtc->Next( 1, &fetc, nullptr ) ) + { + // we use locales only to determine the + // charset if there is text on the cliboard + // we don't offer this format + if ( CF_LOCALE == fetc.cfFormat ) + continue; + + DataFlavor aFlavor = formatEtcToDataFlavor( fetc ); + + // if text or oemtext is offered we also pretend to have unicode text + if ( CDataFormatTranslator::isOemOrAnsiTextFormat( fetc.cfFormat ) && + !m_bUnicodeRegistered ) + { + addSupportedFlavor( aFlavor ); + + m_TxtFormatOnClipboard = fetc.cfFormat; + m_bUnicodeRegistered = true; + + // register unicode text as accompany format + aFlavor = formatEtcToDataFlavor( + CDataFormatTranslator::getFormatEtcForClipformat( CF_UNICODETEXT ) ); + addSupportedFlavor( aFlavor ); + } + else if ( (CF_UNICODETEXT == fetc.cfFormat) && !m_bUnicodeRegistered ) + { + addSupportedFlavor( aFlavor ); + m_bUnicodeRegistered = true; + } + else + addSupportedFlavor( aFlavor ); + + // see MSDN IEnumFORMATETC + CoTaskMemFree( fetc.ptd ); + } + } +} + +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[m_FlavorList.getLength( ) - 1] = aFlavor; + } +} + +DataFlavor CDOTransferable::formatEtcToDataFlavor( const FORMATETC& aFormatEtc ) +{ + LCID lcid = 0; + + // for non-unicode text format we must provide a locale to get + // the character-set of the text, if there is no locale on the + // clipboard we assume the text is in a charset appropriate for + // the current thread locale + if ( (CF_TEXT == aFormatEtc.cfFormat) || (CF_OEMTEXT == aFormatEtc.cfFormat) ) + lcid = getLocaleFromClipboard( ); + + return m_DataFormatTranslator.getDataFlavorFromFormatEtc( aFormatEtc, lcid ); +} + +// 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( 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; +} + +// 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; + 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( aTextSequence.getArray( ) ), + sal::static_int_cast(-1), // Huh ? + stgTransferHelper, + false); + + CRawHGlobalPtr ptrHGlob(stgTransferHelper); + sal_Unicode* pWChar = static_cast(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; +} + +css::uno::Any SAL_CALL CDOTransferable::getData( const Sequence< sal_Int8>& aProcessId ) +{ + Any retVal; + + sal_Int8 const * arProcCaller= aProcessId.getConstArray(); + sal_uInt8 arId[16]; + rtl_getGlobalProcessId(arId); + if( ! memcmp( arId, arProcCaller,16)) + { + if (m_rDataObject.is()) + { + IDataObject* pObj= m_rDataObject.get(); + pObj->AddRef(); + retVal.setValue( &pObj, cppu::UnoType::get()); + } + } + return retVal; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dtobj/DOTransferable.hxx b/dtrans/source/win32/dtobj/DOTransferable.hxx new file mode 100644 index 000000000..f45e18c4f --- /dev/null +++ b/dtrans/source/win32/dtobj/DOTransferable.hxx @@ -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 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DTOBJ_DOTRANSFERABLE_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DTOBJ_DOTRANSFERABLE_HXX + +#include + +#include +#include "DataFmtTransl.hxx" +#include +#include +#include + +#include + +// forward +class CFormatEtc; + +class CDOTransferable : public ::cppu::WeakImplHelper< + css::datatransfer::XTransferable, + css::datatransfer::XSystemTransferable> +{ +public: + typedef css::uno::Sequence< sal_Int8 > ByteSequence_t; + + static css::uno::Reference< css::datatransfer::XTransferable > create( + const css::uno::Reference< css::uno::XComponentContext >& rxContext, IDataObjectPtr pIDataObject ); + + // 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; + + // XSystemTransferable + + virtual css::uno::Any SAL_CALL getData( const css::uno::Sequence& aProcessId ) override; + +private: + explicit CDOTransferable( + const css::uno::Reference< css::uno::XComponentContext >& rxContext, + IDataObjectPtr rDataObject ); + + // some helper functions + + void initFlavorList( ); + + void addSupportedFlavor( const css::datatransfer::DataFlavor& aFlavor ); + css::datatransfer::DataFlavor formatEtcToDataFlavor( const FORMATETC& aFormatEtc ); + + ByteSequence_t getClipboardData( CFormatEtc& aFormatEtc ); + OUString synthesizeUnicodeText( ); + + LCID getLocaleFromClipboard( ); + + bool compareDataFlavors( const css::datatransfer::DataFlavor& lhs, + const css::datatransfer::DataFlavor& rhs ); + +private: + 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& ); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dtobj/DTransHelper.cxx b/dtrans/source/win32/dtobj/DTransHelper.cxx new file mode 100644 index 000000000..66d18f9fb --- /dev/null +++ b/dtrans/source/win32/dtobj/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 +#include +#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/dtrans/source/win32/dtobj/DTransHelper.hxx b/dtrans/source/win32/dtobj/DTransHelper.hxx new file mode 100644 index 000000000..d677184fb --- /dev/null +++ b/dtrans/source/win32/dtobj/DTransHelper.hxx @@ -0,0 +1,170 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DTOBJ_DTRANSHELPER_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DTOBJ_DTRANSHELPER_HXX + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include + +#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; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dtobj/DataFmtTransl.cxx b/dtrans/source/win32/dtobj/DataFmtTransl.cxx new file mode 100644 index 000000000..b8513c6e7 --- /dev/null +++ b/dtrans/source/win32/dtobj/DataFmtTransl.cxx @@ -0,0 +1,259 @@ +/* -*- 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 +#include +#include +#include "../misc/ImplHelper.hxx" +#include +#include "MimeAttrib.hxx" +#include "DTransHelper.hxx" +#include +#include +#include "Fetc.hxx" +#include + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include +#include + +using namespace std; +using namespace com::sun::star::uno; +using namespace com::sun::star::datatransfer; +using namespace com::sun::star::lang; + +const Type CPPUTYPE_SALINT32 = cppu::UnoType::get(); +const Type CPPUTYPE_SALINT8 = cppu::UnoType::get(); +const Type CPPUTYPE_OUSTRING = cppu::UnoType::get(); +const Type CPPUTYPE_SEQSALINT8 = cppu::UnoType>::get(); +const sal_Int32 MAX_CLIPFORMAT_NAME = 256; + +const OUString TEXT_PLAIN_CHARSET ("text/plain;charset="); +const OUString HPNAME_OEM_ANSI_TEXT ("OEM/ANSI Text"); + +const OUString HTML_FORMAT_NAME_WINDOWS ("HTML Format"); +const OUString HTML_FORMAT_NAME_SOFFICE ("HTML (HyperText Markup Language)"); + +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(getFormatEtcForClipformat( sal::static_int_cast(cf) )); +} + +DataFlavor CDataFormatTranslator::getDataFlavorFromFormatEtc( const FORMATETC& aFormatEtc, LCID lcid ) const +{ + DataFlavor aFlavor; + + try + { + CLIPFORMAT aClipformat = aFormatEtc.cfFormat; + + Any aAny; + aAny <<= static_cast< sal_Int32 >( aClipformat ); + + if ( isOemOrAnsiTextFormat( aClipformat ) ) + { + aFlavor.MimeType = TEXT_PLAIN_CHARSET; + aFlavor.MimeType += getTextCharsetFromLCID( lcid, aClipformat ); + + aFlavor.HumanPresentableName = HPNAME_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(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_NAME_WINDOWS ); +} + +bool CDataFormatTranslator::isTextHtmlFormat( CLIPFORMAT cf ) +{ + OUString clipFormatName = getClipboardFormatName( cf ); + return clipFormatName.equalsIgnoreAsciiCase( HTML_FORMAT_NAME_SOFFICE ); +} + +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/dtrans/source/win32/dtobj/DataFmtTransl.hxx b/dtrans/source/win32/dtobj/DataFmtTransl.hxx new file mode 100644 index 000000000..3fad9bbdc --- /dev/null +++ b/dtrans/source/win32/dtobj/DataFmtTransl.hxx @@ -0,0 +1,67 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DTOBJ_DATAFMTTRANSL_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DTOBJ_DATAFMTTRANSL_HXX + +#include +#include +#include +#include +#include + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include +#include + +// 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( + const FORMATETC& aFormatEtc, 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; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dtobj/DtObjFactory.cxx b/dtrans/source/win32/dtobj/DtObjFactory.cxx new file mode 100644 index 000000000..29f630bf4 --- /dev/null +++ b/dtrans/source/win32/dtobj/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 "../../inc/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& rxContext, + const Reference< XTransferable >& refXTransferable) +{ + return (IDataObjectPtr(new CXTDataObject(rxContext, refXTransferable))); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dtobj/Fetc.cxx b/dtrans/source/win32/dtobj/Fetc.cxx new file mode 100644 index 000000000..048b9228d --- /dev/null +++ b/dtrans/source/win32/dtobj/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 +#include "Fetc.hxx" +#include "../misc/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/dtrans/source/win32/dtobj/Fetc.hxx b/dtrans/source/win32/dtobj/Fetc.hxx new file mode 100644 index 000000000..5ec3e4b94 --- /dev/null +++ b/dtrans/source/win32/dtobj/Fetc.hxx @@ -0,0 +1,79 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DTOBJ_FETC_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DTOBJ_FETC_HXX + +#include + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include +#include + +/********************************************************************** + 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 ); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dtobj/FetcList.cxx b/dtrans/source/win32/dtobj/FetcList.cxx new file mode 100644 index 000000000..0a262b067 --- /dev/null +++ b/dtrans/source/win32/dtobj/FetcList.cxx @@ -0,0 +1,344 @@ +/* -*- 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 +#include "FetcList.hxx" +#include "Fetc.hxx" +#include +#include +#include + +#include "DataFmtTransl.hxx" +#include "../misc/ImplHelper.hxx" +#include + +#include + +#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; +using namespace std; + +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 +{ + CFormatEtc fetc( CF_UNICODETEXT ); + + DataFlavor aFlavor = + m_DataFormatTranslator.getDataFlavorFromFormatEtc( fetc ); + + 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/dtrans/source/win32/dtobj/FetcList.hxx b/dtrans/source/win32/dtobj/FetcList.hxx new file mode 100644 index 000000000..cf7697e1b --- /dev/null +++ b/dtrans/source/win32/dtobj/FetcList.hxx @@ -0,0 +1,142 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DTOBJ_FETCLIST_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DTOBJ_FETCLIST_HXX + +#include +#include +#include +#include "Fetc.hxx" + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include + +#include + +/***************************************************************** + 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& ); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dtobj/FmtFilter.cxx b/dtrans/source/win32/dtobj/FmtFilter.cxx new file mode 100644 index 000000000..e9c4b42f8 --- /dev/null +++ b/dtrans/source/win32/dtobj/FmtFilter.cxx @@ -0,0 +1,437 @@ +/* -*- 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 + +#include "FmtFilter.hxx" + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +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 = 72; + break; + + case MM_LOMETRIC: + nInch = 100; + break; + + case MM_HIMETRIC: + nInch = 1000; + break; + + case MM_LOENGLISH: + nInch = 254; + break; + + case MM_HIENGLISH: + case MM_ISOTROPIC: + case MM_ANISOTROPIC: + nInch = 2540; + break; + + case MM_TWIPS: + nInch = 1440; + break; + + default: + nInch = 576; + } + + 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(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(aOOMetaFilePict.getConstArray()) ); + + if( hMtf ) + { + METAFILEPICT* pPict = static_cast(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(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(""); +const std::string TAG_END_HTML(""); + +// The body tag may have parameters so we need to search for the +// closing '>' manually e.g. #92840# +const std::string TAG_BODY(" TextHtmlToHTMLFormat(Sequence const & aTextHtml) +{ + OSL_ASSERT(aTextHtml.getLength() > 0); + + if (aTextHtml.getLength() <= 0) + return Sequence(); + + // 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(aTextHtml.getConstArray()), + reinterpret_cast(aTextHtml.getConstArray()) + aTextHtml.getLength()); + + std::string::size_type nStartHtml = textHtml.find(TAG_HTML) + lHtmlFormatHeader - 1; // we start one before '' 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 ? + + // The body tag may have parameters so we need to search for the + // closing '>' manually e.g. #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 byteSequence(htmlFormat.length() + 1); // space the trailing '\0' + memset(byteSequence.getArray(), 0, byteSequence.getLength()); + + memcpy( + static_cast(byteSequence.getArray()), + static_cast(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 pIShellLink; + HRESULT hr = CoCreateInstance( + CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW, reinterpret_cast(&pIShellLink)); + if (FAILED(hr)) + return target; + + sal::systools::COMReference pIPersistFile = + pIShellLink.QueryInterface(IID_IPersistFile); + + 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 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& 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::value_type::value_type)); +} + +static ByteSequence_t FileListToByteSequence(const std::vector& fileList) +{ + ByteSequence_t bseq; + size_t size = CalcSizeForStringListBuffer(fileList); + + if (size > 0) + { + bseq.realloc(size); + wchar_t* p = reinterpret_cast(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 CF_HDROPToFileList(HGLOBAL hGlobal) +{ + UINT nFiles = DragQueryFileW(static_cast(hGlobal), 0xFFFFFFFF, nullptr, 0); + std::vector files; + + for (UINT i = 0; i < nFiles; i++) + { + wchar_t buff[MAX_PATH]; + /*UINT size =*/ DragQueryFileW(static_cast(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(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(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(pBmp), + DIB_RGB_COLORS ) ) + { + ooBmpStream = WinDIBToOOBMP( aBitmapStream ); + } + } + + return ooBmpStream; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dtobj/FmtFilter.hxx b/dtrans/source/win32/dtobj/FmtFilter.hxx new file mode 100644 index 000000000..1c2325851 --- /dev/null +++ b/dtrans/source/win32/dtobj/FmtFilter.hxx @@ -0,0 +1,87 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DTOBJ_FMTFILTER_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DTOBJ_FMTFILTER_HXX + +#include + +#include + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include +#include + +/*------------------------------------------------------------------------ + 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); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dtobj/MimeAttrib.hxx b/dtrans/source/win32/dtobj/MimeAttrib.hxx new file mode 100644 index 000000000..eb57ba750 --- /dev/null +++ b/dtrans/source/win32/dtobj/MimeAttrib.hxx @@ -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 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DTOBJ_MIMEATTRIB_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DTOBJ_MIMEATTRIB_HXX + +#include + +const OUString TEXTPLAIN_PARAM_CHARSET("charset"); + +const OUString PRE_WINDOWS_CODEPAGE ("windows"); +const OUString PRE_OEM_CODEPAGE ("cp"); +const OUString CHARSET_UTF16 ("utf-16"); +const OUString CHARSET_UNICODE ("unicode"); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dtobj/TxtCnvtHlp.cxx b/dtrans/source/win32/dtobj/TxtCnvtHlp.cxx new file mode 100644 index 000000000..1ea9f4c9f --- /dev/null +++ b/dtrans/source/win32/dtobj/TxtCnvtHlp.cxx @@ -0,0 +1,124 @@ +/* -*- 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 +#include "TxtCnvtHlp.hxx" +#include "DTransHelper.hxx" +#include "../misc/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, + sal_uInt32 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, + sal_uInt32 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/dtrans/source/win32/dtobj/TxtCnvtHlp.hxx b/dtrans/source/win32/dtobj/TxtCnvtHlp.hxx new file mode 100644 index 000000000..9f8d47209 --- /dev/null +++ b/dtrans/source/win32/dtobj/TxtCnvtHlp.hxx @@ -0,0 +1,44 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DTOBJ_TXTCNVTHLP_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DTOBJ_TXTCNVTHLP_HXX + +#include + +#include "DTransHelper.hxx" + +#define WIN32_LEAN_AND_MEAN +#include + +int MultiByteToWideCharEx( UINT cp_src, + LPCSTR lpMultiByteString, + sal_uInt32 lenStr, + CStgTransferHelper& refDTransHelper, + BOOL bEnsureTrailingZero = TRUE ); + +int WideCharToMultiByteEx( UINT cp_dest, + LPCWSTR lpWideCharString, + sal_uInt32 lenStr, + CStgTransferHelper& refDTransHelper, + BOOL bEnsureTrailingZero = TRUE ); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dtobj/XNotifyingDataObject.cxx b/dtrans/source/win32/dtobj/XNotifyingDataObject.cxx new file mode 100644 index 000000000..46f563f94 --- /dev/null +++ b/dtrans/source/win32/dtobj/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 +#include "XNotifyingDataObject.hxx" +#include "../clipb/WinClipbImpl.hxx" +#include "../clipb/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, + CWinClipbImpl* theWinClipImpl ) : + m_nRefCnt( 0 ), + m_aIDataObject( aIDataObject ), + m_XTransferable( aXTransferable ), + m_XClipboardOwner( aXClipOwner ), + m_pWinClipImpl( theWinClipImpl ) +{ +} + +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(*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(m_pWinClipImpl->m_pWinClipboard ), m_XTransferable); + } + catch(RuntimeException&) + { + OSL_FAIL( "RuntimeException caught" ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dtobj/XNotifyingDataObject.hxx b/dtrans/source/win32/dtobj/XNotifyingDataObject.hxx new file mode 100644 index 000000000..0d72c760f --- /dev/null +++ b/dtrans/source/win32/dtobj/XNotifyingDataObject.hxx @@ -0,0 +1,88 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DTOBJ_XNOTIFYINGDATAOBJECT_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DTOBJ_XNOTIFYINGDATAOBJECT_HXX + +#include +#include + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include +#include + +#include + +/*-------------------------------------------------------------------------- + To implement the lostOwnership mechanism cleanly we need this wrapper + object +----------------------------------------------------------------------------*/ + +// forward +class CWinClipbImpl; + +class CXNotifyingDataObject : public IDataObject +{ +public: + CXNotifyingDataObject( + const IDataObjectPtr& aIDataObject, + const css::uno::Reference< css::datatransfer::XTransferable >& aXTransferable, + const css::uno::Reference< css::datatransfer::clipboard::XClipboardOwner >& aXClipOwner, + CWinClipbImpl* theWinClipImpl ); + + 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( ); + +private: + 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; + CWinClipbImpl* m_pWinClipImpl; + + friend class CWinClipbImpl; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/dtobj/XTDataObject.cxx b/dtrans/source/win32/dtobj/XTDataObject.cxx new file mode 100644 index 000000000..01b1ce39f --- /dev/null +++ b/dtrans/source/win32/dtobj/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 +#include +#include + +#include "XTDataObject.hxx" +#include +#include "../misc/ImplHelper.hxx" +#include "DTransHelper.hxx" +#include "TxtCnvtHlp.hxx" +#include +#include +#include +#include +#include "FmtFilter.hxx" +#include + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include +#include + +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 +{ + Reference maTransferable; + +public: + AsyncDereference(css::uno::Reference 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(*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>::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, CFormatRegistrar::getSynthesizedLocale( ) ); + else + aFlavor = m_DataFormatTranslator.getDataFlavorFromFormatEtc( aFormatEtc ); + + 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/dtrans/source/win32/dtobj/XTDataObject.hxx b/dtrans/source/win32/dtobj/XTDataObject.hxx new file mode 100644 index 000000000..ca30bbea2 --- /dev/null +++ b/dtrans/source/win32/dtobj/XTDataObject.hxx @@ -0,0 +1,137 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_DTOBJ_XTDATAOBJECT_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_DTOBJ_XTDATAOBJECT_HXX + +#include +#include + +#include "DataFmtTransl.hxx" + +#include "FetcList.hxx" + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include + +/*-------------------------------------------------------------------------- + - 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; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/ftransl/ftransl.cxx b/dtrans/source/win32/ftransl/ftransl.cxx new file mode 100644 index 000000000..bd189b890 --- /dev/null +++ b/dtrans/source/win32/ftransl/ftransl.cxx @@ -0,0 +1,547 @@ +/* -*- 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 + +#include "ftransl.hxx" +#include +#include +#include +#include +#include +#include +#include "../misc/ImplHelper.hxx" + +#include + +#define IMPL_NAME "com.sun.star.datatransfer.DataFormatTranslator" + +#define CPPUTYPE_SEQSALINT8 cppu::UnoType>::get() +#define CPPUTYPE_DEFAULT CPPUTYPE_SEQSALINT8 +#define CPPUTYPE_OUSTR cppu::UnoType::get() +#define CPPUTYPE_SALINT32 cppu::UnoType::get() + +const OUString Windows_FormatName ("windows_formatname"); +const css::uno::Type CppuType_ByteSequence = cppu::UnoType>::get(); +const css::uno::Type CppuType_String = ::cppu::UnoType::get(); + +using namespace osl; +using namespace cppu; +using namespace std; +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 +{ + Sequence< OUString > DataFormatTranslator_getSupportedServiceNames( ) + { + Sequence< OUString > aRet { "com.sun.star.datatransfer.DataFormatTranslator" }; + return aRet; + } + +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 + +static 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=\"FileName\"", "FileName", nullptr, CF_INVALID, CPPUTYPE_DEFAULT), + // 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=\"UniformResourceLocator\"", "UniformResourceLocator", nullptr, CF_INVALID, CPPUTYPE_DEFAULT), + //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 + */ + 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 ) +{ + 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 ) +{ + 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 ) +{ + vector< FormatEntry >::const_iterator citer = std::find_if(g_TranslTable.begin(), g_TranslTable.end(), + [&aRefXMimeFactory, &aFullMediaType](const FormatEntry& rEntry) { + Reference 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( const OUString& fullMediaType ) +{ + return fullMediaType.equalsIgnoreAsciiCase("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( ) == CPPUTYPE_SALINT32 ) + { + sal_Int32 clipformat = CF_INVALID; + aSysDataType >>= clipformat; + if ( CF_INVALID != clipformat ) + findDataFlavorForStandardFormatId( clipformat, aFlavor ); + } + else if ( aSysDataType.getValueType( ) == CPPUTYPE_OUSTR ) + { + OUString nativeFormatName; + aSysDataType >>= nativeFormatName; + + findDataFlavorForNativeFormatName( nativeFormatName, aFlavor ); + } + else + OSL_FAIL( "Invalid data type received" ); + + return aFlavor; +} + +// XServiceInfo + +OUString SAL_CALL CDataFormatTranslatorUNO::getImplementationName( ) +{ + return IMPL_NAME; +} + +sal_Bool SAL_CALL CDataFormatTranslatorUNO::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > SAL_CALL CDataFormatTranslatorUNO::getSupportedServiceNames( ) +{ + return DataFormatTranslator_getSupportedServiceNames( ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/ftransl/ftransl.hxx b/dtrans/source/win32/ftransl/ftransl.hxx new file mode 100644 index 000000000..71d8038d2 --- /dev/null +++ b/dtrans/source/win32/ftransl/ftransl.hxx @@ -0,0 +1,62 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_FTRANSL_FTRANSL_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_FTRANSL_FTRANSL_HXX + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/ftransl/ftranslentry.cxx b/dtrans/source/win32/ftransl/ftranslentry.cxx new file mode 100644 index 000000000..2959e589f --- /dev/null +++ b/dtrans/source/win32/ftransl/ftranslentry.cxx @@ -0,0 +1,79 @@ +/* -*- 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 +#include +#include +#include + +#include +#include "ftransl.hxx" + +#define SERVICE_NAME "com.sun.star.datatransfer.DataFormatTranslator" + +#define IMPL_NAME "com.sun.star.datatransfer.DataFormatTranslator" + +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::registry; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::datatransfer; + +namespace +{ + + // functions to create a new Clipboard instance; is needed by factory helper implementation + // @param rServiceManager - service manager, useful if the component needs other uno services + // so we should give it to every UNO-Implementation component + + Reference< XInterface > createInstance( const Reference< XMultiServiceFactory >& rServiceManager ) + { + return Reference< XInterface >( static_cast< XDataFormatTranslator* >( new CDataFormatTranslatorUNO( comphelper::getComponentContext(rServiceManager) ) ) ); + } +} + +extern "C" +{ + +SAL_DLLPUBLIC_EXPORT void* ftransl_component_getFactory( const char* pImplName, void* pSrvManager, void* /*pRegistryKey*/ ) +{ + void* pRet = nullptr; + + if ( pSrvManager && ( 0 == rtl_str_compare( pImplName, IMPL_NAME ) ) ) + { + Sequence< OUString > aSNS { SERVICE_NAME }; + + Reference< XSingleServiceFactory > xFactory ( createOneInstanceFactory( + static_cast< XMultiServiceFactory* > ( pSrvManager ), + OUString::createFromAscii( pImplName ), + createInstance, + aSNS ) ); + if ( xFactory.is() ) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + } + + return pRet; +} + +} // extern "C" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/misc/ImplHelper.cxx b/dtrans/source/win32/misc/ImplHelper.cxx new file mode 100644 index 000000000..0e38b9183 --- /dev/null +++ b/dtrans/source/win32/misc/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 +#include "ImplHelper.hxx" +#include +#include +#include +#include + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include + +#include + +#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(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(GetOEMCP( )) ); + } + else if ( LOCALE_IDEFAULTANSICODEPAGE == lctype ) + { + winCP = OUString::number( static_cast(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 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, const OUString& 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, const OUString& 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( 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/dtrans/source/win32/misc/ImplHelper.hxx b/dtrans/source/win32/misc/ImplHelper.hxx new file mode 100644 index 000000000..2d39e0727 --- /dev/null +++ b/dtrans/source/win32/misc/ImplHelper.hxx @@ -0,0 +1,77 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_MISC_IMPLHELPER_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_MISC_IMPLHELPER_HXX + +#include +#include + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include +#include + +// 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, const OUString& 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, const OUString& 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 ); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/workbench/XTDo.cxx b/dtrans/source/win32/workbench/XTDo.cxx new file mode 100644 index 000000000..f8da707d9 --- /dev/null +++ b/dtrans/source/win32/workbench/XTDo.cxx @@ -0,0 +1,358 @@ +/* -*- 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 + +#include "../DTransHelper.hxx" + +#include "XTDo.hxx" + +#if defined _MSC_VER +#pragma warning(push,1) +#endif +#include +#include +#if defined _MSC_VER +#pragma warning(pop) +#endif +#include + +using namespace ::std; + +// OTWrapperDataObject + +/* + in the constructor we enumerate all formats offered by the transferable + and convert the formats into formatetc structures + if the transferable supports text in different charsets we use either + the charset equal to the charset of the current thread or an arbitrary + charset supported by the transferable and the system + if the transferable supports only unicodetext we offer in addition to + this text in the charset of the current thread + in order to allow the consumer of the clipboard to query for the charset + of the text in the clipboard we offer a CF_LOCALE +*/ +CXTDataObject::CXTDataObject( ) : + m_nRefCnt( 0 ) +{ + +} + +// IUnknown->QueryInterface + +STDMETHODIMP CXTDataObject::QueryInterface( REFIID iid, LPVOID* ppvObject ) +{ + OSL_ASSERT( NULL != ppvObject ); + + if ( NULL == ppvObject ) + return E_INVALIDARG; + + HRESULT hr = E_NOINTERFACE; + + *ppvObject = NULL; + + if ( ( __uuidof( IUnknown ) == iid ) || ( __uuidof( IDataObject ) == iid ) ) + { + *ppvObject = static_cast< IUnknown* >( this ); + ( (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( ) +{ + // 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 + we deliver data only into global memory + + algo: + 1. convert the given formatect struct into a valid dataflavor + 2. if the transferable directly supports the requested format + 2.1. if text data requested add a trailing '\0' in order to prevent + problems (windows needs '\0' terminated strings + 2.2. we expect unicode data as Sequence< sal_Unicode > and all other + text and raw data as Sequence< sal_Int8 > + +------------------------------------------------------------------------*/ + +STDMETHODIMP CXTDataObject::GetData( LPFORMATETC pFormatetc, LPSTGMEDIUM pmedium ) +{ + if ( ( NULL == pFormatetc ) || ( NULL == pmedium ) ) + return E_INVALIDARG; + + HRESULT hr = E_FAIL; + + if ( CF_TEXT == pFormatetc->cfFormat ) + { + CHGlobalHelper hGlobHlp( TRUE ); + + char pBuff[] = "Test OleClipboard"; + hGlobHlp.Write( pBuff, sizeof( pBuff ), NULL ); + + pmedium->tymed = TYMED_HGLOBAL; + pmedium->hGlobal = hGlobHlp.GetHGlobal( ); + pmedium->pUnkForRelease = NULL; + + hr = S_OK; + } + + return hr; +} + +// IDataObject->EnumFormatEtc + +STDMETHODIMP CXTDataObject::EnumFormatEtc( DWORD dwDirection, IEnumFORMATETC** ppenumFormatetc ) +{ + if ( ( NULL == ppenumFormatetc ) || ( DATADIR_SET == dwDirection ) ) + return E_INVALIDARG; + + *ppenumFormatetc = NULL; + + HRESULT hr = E_FAIL; + + if ( DATADIR_GET == dwDirection ) + { + *ppenumFormatetc = new CEnumFormatEtc( this ); + static_cast< LPUNKNOWN >( *ppenumFormatetc )->AddRef( ); + hr = S_OK; + } + + return hr; +} + +// IDataObject->QueryGetData + +STDMETHODIMP CXTDataObject::QueryGetData( LPFORMATETC pFormatetc ) +{ + return E_NOTIMPL; +} + +// IDataObject->GetDataHere + +STDMETHODIMP CXTDataObject::GetDataHere( LPFORMATETC, LPSTGMEDIUM ) +{ + return E_NOTIMPL; +} + +// IDataObject->GetCanonicalFormatEtc + +STDMETHODIMP CXTDataObject::GetCanonicalFormatEtc( LPFORMATETC, LPFORMATETC ) +{ + return E_NOTIMPL; +} + +// IDataObject->SetData + +STDMETHODIMP CXTDataObject::SetData( LPFORMATETC, LPSTGMEDIUM, BOOL ) +{ + return E_NOTIMPL; +} + +// IDataObject->DAdvise + +STDMETHODIMP CXTDataObject::DAdvise( LPFORMATETC, DWORD, LPADVISESINK, DWORD * ) +{ + return E_NOTIMPL; +} + +// IDataObject->DUnadvise + +STDMETHODIMP CXTDataObject::DUnadvise( DWORD ) +{ + return E_NOTIMPL; +} + +// IDataObject->EnumDAdvise + +STDMETHODIMP CXTDataObject::EnumDAdvise( LPENUMSTATDATA * ) +{ + return E_NOTIMPL; +} + +CXTDataObject::operator IDataObject*( ) +{ + return static_cast< IDataObject* >( this ); +} + +CEnumFormatEtc::CEnumFormatEtc( LPUNKNOWN pUnkDataObj ) : + m_nRefCnt( 0 ), + m_pUnkDataObj( pUnkDataObj ), + m_nCurrPos( 0 ) +{ +} + +// IUnknown->QueryInterface + +STDMETHODIMP CEnumFormatEtc::QueryInterface( REFIID iid, LPVOID* ppvObject ) +{ + if ( NULL == ppvObject ) + return E_INVALIDARG; + + HRESULT hr = E_NOINTERFACE; + + *ppvObject = NULL; + + 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_pUnkDataObj->AddRef( ); + return InterlockedIncrement( &m_nRefCnt ); +} + +// IUnknown->Release + +STDMETHODIMP_(ULONG) CEnumFormatEtc::Release( ) +{ + // release the outer dataobject + m_pUnkDataObj->Release( ); + + // we need a helper variable because it's + // not allowed to access a member variable + // after an object is destroyed + ULONG nRefCnt = InterlockedDecrement( &m_nRefCnt ); + if ( 0 == nRefCnt ) + delete this; + + return nRefCnt; +} + +// IEnumFORMATETC->Next + +STDMETHODIMP CEnumFormatEtc::Next( ULONG celt, LPFORMATETC rgelt, ULONG* pceltFetched ) +{ + if ( ( 0 != celt ) && ( NULL == rgelt ) ) + return E_INVALIDARG; + + ULONG ulFetched = 0; + ULONG ulToFetch = celt; + HRESULT hr = S_FALSE; + + while( m_nCurrPos < 1 ) + { + rgelt->cfFormat = CF_TEXT; + rgelt->ptd = NULL; + rgelt->dwAspect = DVASPECT_CONTENT; + rgelt->lindex = -1; + rgelt->tymed = TYMED_HGLOBAL; + + ++m_nCurrPos; + ++rgelt; + --ulToFetch; + ++ulFetched; + } + + if ( ulFetched == celt ) + hr = S_OK; + + if ( NULL != pceltFetched ) + { + *pceltFetched = ulFetched; + } + + return hr; +} + +// IEnumFORMATETC->Skip + +STDMETHODIMP CEnumFormatEtc::Skip( ULONG celt ) +{ + HRESULT hr = S_FALSE; + + /* + if ( ( m_nCurrPos + celt ) < m_nClipFormats ) + { + m_nCurrPos += celt; + hr = S_OK; + } + */ + + return hr; +} + +// IEnumFORMATETC->Reset + +STDMETHODIMP CEnumFormatEtc::Reset( ) +{ + m_nCurrPos = 0; + return S_OK; +} + +// IEnumFORMATETC->Clone + +STDMETHODIMP CEnumFormatEtc::Clone( IEnumFORMATETC** ppenum ) +{ + OSL_ASSERT( NULL != ppenum ); + + if ( NULL == ppenum ) + return E_INVALIDARG; + + HRESULT hr = E_FAIL; + + *ppenum = NULL; + + CEnumFormatEtc* pCEnumFEtc = new CEnumFormatEtc( m_pUnkDataObj ); + if ( NULL != pCEnumFEtc ) + { + pCEnumFEtc->m_nCurrPos = m_nCurrPos; + *ppenum = static_cast< IEnumFORMATETC* >( pCEnumFEtc ); + static_cast< LPUNKNOWN >( *ppenum )->AddRef( ); + hr = NOERROR; + } + + return hr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/workbench/XTDo.hxx b/dtrans/source/win32/workbench/XTDo.hxx new file mode 100644 index 000000000..50f842559 --- /dev/null +++ b/dtrans/source/win32/workbench/XTDo.hxx @@ -0,0 +1,114 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_DTRANS_SOURCE_WIN32_WORKBENCH_XTDO_HXX +#define INCLUDED_DTRANS_SOURCE_WIN32_WORKBENCH_XTDO_HXX + +#if defined _MSC_VER +#pragma warning(push,1) +#endif +#include +#include +#include +#if defined _MSC_VER +#pragma warning(pop) +#endif + +#include + +class EnumFormatEtc; + +/*-------------------------------------------------------------------------- + - 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 CXTDataObject : public IDataObject +{ +public: + CXTDataObject( ); + + // ole interface implementation + + //IUnknown interface methods + STDMETHODIMP QueryInterface(REFIID iid, LPVOID* ppvObject); + STDMETHODIMP_( ULONG ) AddRef( ); + STDMETHODIMP_( ULONG ) Release( ); + + // IDataObject interface methods + STDMETHODIMP GetData( LPFORMATETC pFormatetc, LPSTGMEDIUM pmedium ); + STDMETHODIMP GetDataHere( LPFORMATETC pFormatetc, LPSTGMEDIUM pmedium ); + STDMETHODIMP QueryGetData( LPFORMATETC pFormatetc ); + STDMETHODIMP GetCanonicalFormatEtc( LPFORMATETC pFormatectIn, LPFORMATETC pFormatetcOut ); + STDMETHODIMP SetData( LPFORMATETC pFormatetc, LPSTGMEDIUM pmedium, BOOL fRelease ); + STDMETHODIMP EnumFormatEtc( DWORD dwDirection, IEnumFORMATETC** ppenumFormatetc ); + STDMETHODIMP DAdvise( LPFORMATETC pFormatetc, DWORD advf, LPADVISESINK pAdvSink, DWORD* pdwConnection ); + STDMETHODIMP DUnadvise( DWORD dwConnection ); + STDMETHODIMP EnumDAdvise( LPENUMSTATDATA* ppenumAdvise ); + + operator IDataObject*( ); + +private: + +private: + LONG m_nRefCnt; +}; + +class CEnumFormatEtc : public IEnumFORMATETC +{ +public: + explicit CEnumFormatEtc( LPUNKNOWN pUnkDataObj ); + + // IUnknown + STDMETHODIMP QueryInterface( REFIID iid, LPVOID* ppvObject ); + STDMETHODIMP_( ULONG ) AddRef( ); + STDMETHODIMP_( ULONG ) Release( ); + + //IEnumFORMATETC + STDMETHODIMP Next( ULONG celt, LPFORMATETC rgelt, ULONG* pceltFetched ); + STDMETHODIMP Skip( ULONG celt ); + STDMETHODIMP Reset( ); + STDMETHODIMP Clone( IEnumFORMATETC** ppenum ); + +private: + LONG m_nRefCnt; + LPUNKNOWN m_pUnkDataObj; + ULONG m_nCurrPos; +}; + +typedef CEnumFormatEtc *PCEnumFormatEtc; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/workbench/makefile.mk b/dtrans/source/win32/workbench/makefile.mk new file mode 100644 index 000000000..3c82289f8 --- /dev/null +++ b/dtrans/source/win32/workbench/makefile.mk @@ -0,0 +1,81 @@ +# +# 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 . +# + +PRJ=..$/..$/.. + +PRJNAME= dtrans +TARGET= testwincb +TARGET1= testmshl +LIBTARGET= NO +TARGETTYPE= CUI +USE_BOUNDCHK= +TESTCB=TRUE + +.IF "$(USE_BOUNDCHK)"=="TR" +bndchk=tr +stoponerror=tr +.ENDIF + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +.IF "$(TESTCB)"=="TRUE" + +CFLAGS+=-D_WIN32_DCOM -EHsc -Ob0 + +# --- Files -------------------------------------------------------- + +OBJFILES= $(OBJ)$/test_wincb.obj +APP1TARGET= $(TARGET) +APP1OBJS= $(OBJ)$/test_wincb.obj + +APP1STDLIBS= $(SALLIB) \ + $(CPPULIB) \ + $(CPPUHELPERLIB) \ + $(USER32LIB) \ + $(OLE32LIB)\ + $(COMDLG32LIB) + +APP1LIBS= $(SLB)$/dtutils.lib + +APP1NOSAL= TRUE + +.ENDIF + +.IF "$(TESTCB)"=="" + +CFLAGS+=/D_WIN32_DCOM /EHsc /Ob0 + +OBJFILES= $(OBJ)$/testmarshal.obj +APP1TARGET= $(TARGET1) +APP1OBJS= $(OBJ)$/testmarshal.obj + +APP1STDLIBS= $(SALLIB)\ + $(USER32LIB)\ + $(OLE32LIB)\ + comsupp.lib\ + $(OLEAUT32LIB) + +APP1LIBS= +APP1NOSAL= TRUE + +.ENDIF + +# --- Targets ------------------------------------------------------ +.INCLUDE : target.mk diff --git a/dtrans/source/win32/workbench/test_wincb.cxx b/dtrans/source/win32/workbench/test_wincb.cxx new file mode 100644 index 000000000..96839e22a --- /dev/null +++ b/dtrans/source/win32/workbench/test_wincb.cxx @@ -0,0 +1,287 @@ +/* -*- 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 "../misc/ImplHelper.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#if defined _MSC_VER +#pragma warning(push,1) +#endif +#include +#include +#if defined _MSC_VER +#pragma warning(pop) +#endif + +#include + +#include + +// my defines + +#define TEST_CLIPBOARD +#define RDB_SYSPATH "d:\\projects\\src623\\dtrans\\wntmsci7\\bin\\applicat.rdb" +#define WINCLIPBOARD_SERVICE_NAME L"com.sun.star.datatransfer.clipboard.SystemClipboard" +#define WRITE_CB +#define EVT_MANUAL_RESET TRUE +#define EVT_INIT_NONSIGNALED FALSE +#define EVT_NONAME "" + +// namespaces + +using namespace ::std; +using namespace ::cppu; +using namespace ::com::sun::star::datatransfer; +using namespace ::com::sun::star::datatransfer::clipboard; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; + +// globales + +Reference< XTransferable > rXTransfRead; +HANDLE g_hEvtThreadWakeup; + +class CClipboardListener : public WeakImplHelper < XClipboardListener > +{ +public: + ~CClipboardListener( ); + + // XClipboardListener + + virtual void SAL_CALL disposing( const EventObject& Source ) throw(RuntimeException); + virtual void SAL_CALL changedContents( const ClipboardEvent& event ) throw( RuntimeException ); +}; + +CClipboardListener::~CClipboardListener( ) +{ +} + +void SAL_CALL CClipboardListener::disposing( const EventObject& Source ) throw(RuntimeException) +{ + +} + +void SAL_CALL CClipboardListener::changedContents( const ClipboardEvent& event ) throw( RuntimeException ) +{ + //MessageBox( NULL, TEXT("Clipboard content changed"), TEXT("Info"), MB_OK | MB_ICONINFORMATION ); +} + +class CTransferable : public WeakImplHelper< XClipboardOwner, XTransferable > +{ +public: + CTransferable( ); + + // XTransferable + + virtual Any SAL_CALL getTransferData( const DataFlavor& aFlavor ) + throw(UnsupportedFlavorException, IOException, RuntimeException); + + virtual Sequence< DataFlavor > SAL_CALL getTransferDataFlavors( ) throw(RuntimeException); + + virtual sal_Bool SAL_CALL isDataFlavorSupported( const DataFlavor& aFlavor ) throw(RuntimeException); + + // XClipboardOwner + + virtual void SAL_CALL lostOwnership( const Reference< XClipboard >& xClipboard, const Reference< XTransferable >& xTrans ) + throw(RuntimeException); + +private: + Sequence< DataFlavor > m_FlavorList; + OUString m_Data; +}; + +// ctor + +CTransferable::CTransferable( ) : + m_FlavorList( 1 ), + m_Data( OUString("I bought a new bike!") ) +{ + DataFlavor df; + + //df.MimeType = L"text/plain;charset=utf-16"; + //df.DataType = cppu::UnoType::get(); + + df.MimeType = L"text/plain;charset=Windows1252"; + df.DataType = cppu::UnoType>::get(); + + m_FlavorList[0] = df; +} + +// getTransferData + +Any SAL_CALL CTransferable::getTransferData( const DataFlavor& aFlavor ) + throw(UnsupportedFlavorException, IOException, RuntimeException) +{ + Any anyData; + + /* + if ( aFlavor.MimeType == m_FlavorList[0].MimeType ) + anyData = makeAny( m_Data ); + */ + if ( aFlavor.MimeType.equalsIgnoreCase( m_FlavorList[0].MimeType ) ) + { + OString text( + m_Data.getStr( ), + m_Data.getLength( ), + RTL_TEXTENCODING_ASCII_US ); + + Sequence< sal_Int8 > textStream( text.getLength( ) + 1 ); + + memcpy( textStream.getArray( ), text.getStr( ), textStream.getLength( ) ); + + anyData = makeAny( textStream ); + } + else + throw UnsupportedFlavorException( ); + + return anyData; +} + +// getTransferDataFlavors + +Sequence< DataFlavor > SAL_CALL CTransferable::getTransferDataFlavors( ) + throw(RuntimeException) +{ + return m_FlavorList; +} + +// isDataFlavorSupported + +sal_Bool SAL_CALL CTransferable::isDataFlavorSupported( const DataFlavor& aFlavor ) + throw(RuntimeException) +{ + sal_Int32 nLength = m_FlavorList.getLength( ); + + for ( sal_Int32 i = 0; i < nLength; ++i ) + if ( m_FlavorList[i].MimeType == aFlavor.MimeType ) + return sal_True; + + return sal_False; +} + +// lostOwnership + +void SAL_CALL CTransferable::lostOwnership( + const Reference< XClipboard >& xClipboard, const Reference< XTransferable >& xTrans ) + throw(RuntimeException) +{ + //MessageBox( NULL, TEXT("No longer clipboard owner"), TEXT("Info"), MB_OK | MB_ICONINFORMATION ); +} + +// main + +int SAL_CALL main( int nArgc, char* Argv[] ) +{ + // create a multi-threaded apartment; we can test only + // with a multithreaded apartment because for a single + // threaded apartment we need a message loop to deliver + // messages to our XTDataObject + //HRESULT hr = CoInitializeEx( NULL, COINIT_MULTITHREADED ); + (void)CoInitializeEx( NULL, COINIT_APARTMENTTHREADED ); + + char buff[6]; + + LCID lcid = MAKELCID( MAKELANGID( LANG_GERMAN, SUBLANG_GERMAN ), SORT_DEFAULT ); + + BOOL bValid = IsValidLocale( lcid, LCID_SUPPORTED ); + GetLocaleInfoA( lcid, LOCALE_IDEFAULTANSICODEPAGE, buff, sizeof( buff ) ); + + // get the global service-manager + + Reference< XMultiServiceFactory > g_xFactory( createRegistryServiceFactory( RDB_SYSPATH ) ); + + // Print a message if an error occurred. + if ( !g_xFactory.is( ) ) + { + OSL_FAIL("Can't create RegistryServiceFactory"); + return(-1); + } + + // try to get an Interface to a XFilePicker Service + + Reference< XTransferable > rXTransf( static_cast< XTransferable* >( new CTransferable ) ); + + Reference< XClipboard >xClipboard( g_xFactory->createInstance( WINCLIPBOARD_SERVICE_NAME ), UNO_QUERY ); + if ( !xClipboard.is( ) ) + { + OSL_FAIL( "Error creating Clipboard Service" ); + return(-1); + } + + Reference< XClipboardNotifier > xClipNotifier( xClipboard, UNO_QUERY ); + Reference< XClipboardListener > rXClipListener( static_cast< XClipboardListener* >( new CClipboardListener() ) ); + xClipNotifier->addClipboardListener( rXClipListener ); + + MessageBox( NULL, TEXT("Go"), TEXT("INFO"), MB_OK|MB_ICONINFORMATION); + + // set new clipboard content + xClipboard->setContents( rXTransf, Reference< XClipboardOwner >( rXTransf, UNO_QUERY ) ); + + /* + MessageBox( NULL, TEXT("Clear content"), TEXT("INFO"), MB_OK|MB_ICONINFORMATION); + + Reference< XClipboardOwner > rXClipOwner; + Reference< XTransferable > rXEmptyTransf; + xClipboard->setContents( rXEmptyTransf, rXClipOwner ); + */ + + MessageBox( NULL, TEXT("Stop"), TEXT("INFO"), MB_OK|MB_ICONINFORMATION); + + // flush the clipboard content + Reference< XFlushableClipboard > rXFlushableClip( xClipboard, UNO_QUERY ); + rXFlushableClip->flushClipboard( ); + rXFlushableClip.clear(); + + xClipNotifier->removeClipboardListener( rXClipListener ); + rXClipListener.clear(); + xClipNotifier.clear(); + + // shutdown the service manager + + // Cast factory to XComponent + Reference< XComponent > xComponent( g_xFactory, UNO_QUERY ); + + if ( !xComponent.is() ) + OSL_FAIL("Error shutting down"); + + // Dispose and clear factory + xComponent->dispose(); + xComponent.clear(); + + g_xFactory.clear(); + + CoUninitialize( ); + + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dtrans/source/win32/workbench/testmarshal.cxx b/dtrans/source/win32/workbench/testmarshal.cxx new file mode 100644 index 000000000..d9edfe753 --- /dev/null +++ b/dtrans/source/win32/workbench/testmarshal.cxx @@ -0,0 +1,213 @@ +/* -*- 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 +#include + +#include +#if defined _MSC_VER +#pragma warning(push,1) +#endif +#include +#include +#if defined _MSC_VER +#pragma warning(pop) +#endif + +#include + +#include +#include "XTDo.hxx" + +// my defines + +#define WRITE_CB +#define EVT_MANUAL_RESET TRUE +#define EVT_INIT_NONSIGNALED FALSE +#define EVT_NONAME "" +#define WAIT_MSGLOOP +#define RAW_MARSHALING + +// namespaces + +using namespace ::std; + +// globales + +HANDLE g_hEvtThreadWakeup; + +#ifdef RAW_MARSHALING + HGLOBAL g_hGlob; +#else + IStream* g_pStm; +#endif + +// a thread in another apartment to test apartment transparency + +unsigned int _stdcall ThreadProc(LPVOID pParam) +{ + // setup another apartment + HRESULT hr = OleInitialize( NULL ); + + WaitForSingleObject( g_hEvtThreadWakeup, INFINITE ); + + IDataObject* pIDo = NULL; + +#ifdef RAW_MARSHALING + + IStream* pStm = NULL; + hr = CreateStreamOnHGlobal( g_hGlob, FALSE, &pStm ); + if ( SUCCEEDED( hr ) ) + { + hr = CoUnmarshalInterface( + pStm, + __uuidof( IDataObject ), + (void**)&pIDo ); + + hr = pStm->Release( ); + } + +#else + + hr = CoGetInterfaceAndReleaseStream( + g_pStm, + __uuidof( IDataObject ), + (void**)&pIDo + ); + +#endif + + IEnumFORMATETC* pIEEtc; + hr = pIDo->EnumFormatEtc( DATADIR_GET, &pIEEtc ); + + hr = OleIsCurrentClipboard( pIDo ); + + hr = OleFlushClipboard( ); + + OleUninitialize( ); + + return 0; +} + +// main + +int SAL_CALL main( int nArgc, char* Argv[] ) +{ + HRESULT hr = OleInitialize( NULL ); + + g_hEvtThreadWakeup = CreateEvent( 0, + EVT_MANUAL_RESET, + EVT_INIT_NONSIGNALED, + EVT_NONAME ); + + unsigned uThreadId; + HANDLE hThread; + + // create a thread in another apartment + hThread = (void*)_beginthreadex( NULL, 0, ThreadProc, NULL, 0, &uThreadId ); + + IDataObject* pIDo = new CXTDataObject( ); + + hr = OleSetClipboard( pIDo ); + hr = E_FAIL; + + hr = OleIsCurrentClipboard( pIDo ); + + //hr = OleGetClipboard( &pIDo ); + if ( SUCCEEDED( hr ) ) + { +#ifdef RAW_MARSHALING + + IStream* pStm = NULL; + + hr = CreateStreamOnHGlobal( 0, FALSE, &pStm ); + if ( SUCCEEDED( hr ) ) + { + hr = CoMarshalInterface( + pStm, + __uuidof( IDataObject ), + pIDo, + MSHCTX_INPROC, + 0, + MSHLFLAGS_NORMAL ); + if ( SUCCEEDED( hr ) ) + hr = GetHGlobalFromStream( pStm, &g_hGlob ); + + hr = pStm->Release( ); + } + +#else + + hr = CoMarshalInterThreadInterfaceInStream( + __uuidof( IDataObject ), + pIDo, + &g_pStm ); + +#endif + + if ( SUCCEEDED( hr ) ) + { + // wakeup the thread and waiting util it ends + SetEvent( g_hEvtThreadWakeup ); + +#ifdef WAIT_MSGLOOP + + BOOL bContinue = TRUE; + + while( bContinue ) + { + DWORD dwResult = WaitForMultipleObjects( + 1, + &hThread, + TRUE, + 0 ); + + if ( WAIT_OBJECT_0 == dwResult ) + { + bContinue = FALSE; + } + else + { + MSG msg; + while( PeekMessage( + &msg, + NULL, + 0, + 0, + PM_REMOVE ) ) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + } // while + +#endif + + } // if + } // if + + OleFlushClipboard( ); + + OleUninitialize( ); + + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3