LibreOffice Module dtrans (master)  1
DOTransferable.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/types.h>
21 #include <rtl/process.h>
22 #include <osl/diagnose.h>
23 #include <sal/log.hxx>
24 
25 #include "DOTransferable.hxx"
26 #include "../misc/ImplHelper.hxx"
27 #include <WinClip.hxx>
28 #include "DTransHelper.hxx"
29 #include "TxtCnvtHlp.hxx"
30 #include "MimeAttrib.hxx"
31 #include "FmtFilter.hxx"
32 #include "Fetc.hxx"
33 #include <com/sun/star/container/NoSuchElementException.hpp>
34 #include <com/sun/star/datatransfer/MimeContentTypeFactory.hpp>
35 #include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
36 #include <com/sun/star/io/IOException.hpp>
37 #include <com/sun/star/lang/IllegalArgumentException.hpp>
38 
39 using namespace std;
40 using namespace osl;
41 using namespace cppu;
42 using namespace com::sun::star::uno;
43 using namespace com::sun::star::datatransfer;
44 using namespace com::sun::star::io;
45 using namespace com::sun::star::lang;
46 using namespace com::sun::star::container;
47 
48 namespace
49 {
50  const Type CPPUTYPE_SEQINT8 = cppu::UnoType<Sequence< sal_Int8 >>::get();
52 
53  bool isValidFlavor( const DataFlavor& aFlavor )
54  {
55  return ( aFlavor.MimeType.getLength( ) &&
56  ( ( aFlavor.DataType == CPPUTYPE_SEQINT8 ) ||
57  ( aFlavor.DataType == CPPUTYPE_OUSTRING ) ) );
58  }
59 
60 void clipDataToByteStream( CLIPFORMAT cf, STGMEDIUM stgmedium, CDOTransferable::ByteSequence_t& aByteSequence )
61 {
62  CStgTransferHelper memTransferHelper;
63  LPSTREAM pStream = nullptr;
64 
65  switch( stgmedium.tymed )
66  {
67  case TYMED_HGLOBAL:
68  memTransferHelper.init( stgmedium.hGlobal );
69  break;
70 
71  case TYMED_MFPICT:
72  memTransferHelper.init( stgmedium.hMetaFilePict );
73  break;
74 
75  case TYMED_ENHMF:
76  memTransferHelper.init( stgmedium.hEnhMetaFile );
77  break;
78 
79  case TYMED_ISTREAM:
80  pStream = stgmedium.pstm;
81  break;
82 
83  default:
84  throw UnsupportedFlavorException( );
85  break;
86  }
87 
88  if (pStream)
89  {
90  // We have a stream, read from it.
91  STATSTG aStat;
92  HRESULT hr = pStream->Stat(&aStat, STATFLAG_NONAME);
93  if (FAILED(hr))
94  {
95  SAL_WARN("dtrans", "clipDataToByteStream: Stat() failed");
96  return;
97  }
98 
99  size_t nMemSize = aStat.cbSize.QuadPart;
100  aByteSequence.realloc(nMemSize);
101  LARGE_INTEGER li;
102  li.QuadPart = 0;
103  hr = pStream->Seek(li, STREAM_SEEK_SET, nullptr);
104  if (FAILED(hr))
105  {
106  SAL_WARN("dtrans", "clipDataToByteStream: Seek() failed");
107  }
108 
109  ULONG nRead = 0;
110  hr = pStream->Read(aByteSequence.getArray(), nMemSize, &nRead);
111  if (FAILED(hr))
112  {
113  SAL_WARN("dtrans", "clipDataToByteStream: Read() failed");
114  }
115  if (nRead < nMemSize)
116  {
117  SAL_WARN("dtrans", "clipDataToByteStream: Read() was partial");
118  }
119 
120  return;
121  }
122 
123  int nMemSize = memTransferHelper.memSize( cf );
124  aByteSequence.realloc( nMemSize );
125  memTransferHelper.read( aByteSequence.getArray( ), nMemSize );
126 }
127 
128 OUString byteStreamToOUString( CDOTransferable::ByteSequence_t& aByteStream )
129 {
130  sal_Int32 nWChars;
131  sal_Int32 nMemSize = aByteStream.getLength( );
132 
133  // if there is a trailing L"\0" subtract 1 from length
134  // for unknown reason, the sequence may sometimes arrive empty
135  if ( aByteStream.getLength( ) > 1 &&
136  0 == aByteStream[ aByteStream.getLength( ) - 2 ] &&
137  0 == aByteStream[ aByteStream.getLength( ) - 1 ] )
138  nWChars = static_cast< sal_Int32 >( nMemSize / sizeof( sal_Unicode ) ) - 1;
139  else
140  nWChars = static_cast< sal_Int32 >( nMemSize / sizeof( sal_Unicode ) );
141 
142  return OUString( reinterpret_cast< sal_Unicode* >( aByteStream.getArray( ) ), nWChars );
143 }
144 
145 Any byteStreamToAny( CDOTransferable::ByteSequence_t& aByteStream, const Type& aRequestedDataType )
146 {
147  Any aAny;
148 
149  if ( aRequestedDataType == CPPUTYPE_OUSTRING )
150  {
151  OUString str = byteStreamToOUString( aByteStream );
152  if (str.isEmpty())
153  throw RuntimeException();
154  aAny <<= str;
155  }
156  else
157  aAny <<= aByteStream;
158 
159  return aAny;
160 }
161 
162 bool cmpFullMediaType(
164 {
165  return xLhs->getFullMediaType().equalsIgnoreAsciiCase( xRhs->getFullMediaType( ) );
166 }
167 
168 bool cmpAllContentTypeParameter(
170 {
171  Sequence< OUString > xLhsFlavors = xLhs->getParameters( );
172  Sequence< OUString > xRhsFlavors = xRhs->getParameters( );
173  bool bRet = true;
174 
175  try
176  {
177  if ( xLhsFlavors.getLength( ) == xRhsFlavors.getLength( ) )
178  {
179  OUString pLhs;
180  OUString pRhs;
181 
182  for ( sal_Int32 i = 0; i < xLhsFlavors.getLength( ); i++ )
183  {
184  pLhs = xLhs->getParameterValue( xLhsFlavors[i] );
185  pRhs = xRhs->getParameterValue( xLhsFlavors[i] );
186 
187  if ( !pLhs.equalsIgnoreAsciiCase( pRhs ) )
188  {
189  bRet = false;
190  break;
191  }
192  }
193  }
194  else
195  bRet = false;
196  }
197  catch( NoSuchElementException& )
198  {
199  bRet = false;
200  }
201  catch( IllegalArgumentException& )
202  {
203  bRet = false;
204  }
205 
206  return bRet;
207 }
208 
209 } // end namespace
210 
212  IDataObjectPtr pIDataObject )
213 {
214  CDOTransferable* pTransf = new CDOTransferable(rxContext, pIDataObject);
215  Reference<XTransferable> refDOTransf(pTransf);
216 
217  pTransf->acquire();
218  pTransf->initFlavorList();
219  pTransf->release();
220 
221  return refDOTransf;
222 }
223 
225  const Reference< XComponentContext >& rxContext, IDataObjectPtr rDataObject ) :
226  m_rDataObject( rDataObject ),
227  m_xContext( rxContext ),
228  m_DataFormatTranslator( rxContext ),
229  m_bUnicodeRegistered( false ),
230  m_TxtFormatOnClipboard( CF_INVALID )
231 {
232 }
233 
234 Any SAL_CALL CDOTransferable::getTransferData( const DataFlavor& aFlavor )
235 {
236  OSL_ASSERT( isValidFlavor( aFlavor ) );
237 
238  MutexGuard aGuard( m_aMutex );
239 
240  // convert dataflavor to formatetc
241 
243  OSL_ASSERT( CF_INVALID != fetc.getClipformat() );
244 
245  // get the data from clipboard in a byte stream
246 
247  ByteSequence_t clipDataStream;
248 
249  try
250  {
251  clipDataStream = getClipboardData( fetc );
252  }
253  catch( UnsupportedFlavorException& )
254  {
257  {
258  OUString aUnicodeText = synthesizeUnicodeText( );
259  Any aAny = makeAny( aUnicodeText );
260  return aAny;
261  }
262  // #i124085# CF_DIBV5 should not be possible, but keep for reading from the
263  // clipboard for being on the safe side
264  else if(CF_DIBV5 == fetc.getClipformat())
265  {
266  // #i123407# CF_DIBV5 has priority; if the try to fetch this failed,
267  // check CF_DIB availability as an alternative
268  fetc.setClipformat(CF_DIB);
269 
270  clipDataStream = getClipboardData( fetc );
271  // pass UnsupportedFlavorException out, tried all possibilities
272  }
273  else
274  throw; // pass through exception
275  }
276 
277  // return the data as any
278 
279  return byteStreamToAny( clipDataStream, aFlavor.DataType );
280 }
281 
282 // getTransferDataFlavors
283 
285 {
286  return m_FlavorList;
287 }
288 
289 // isDataFlavorSupported
290 // returns true if we find a DataFlavor with the same MimeType and
291 // DataType
292 
293 sal_Bool SAL_CALL CDOTransferable::isDataFlavorSupported( const DataFlavor& aFlavor )
294 {
295  OSL_ASSERT( isValidFlavor( aFlavor ) );
296 
297  for ( DataFlavor const & df : std::as_const(m_FlavorList) )
298  if ( compareDataFlavors( aFlavor, df ) )
299  return true;
300 
301  return false;
302 }
303 
304 // the list of dataflavors currently on the clipboard will be initialized
305 // only once; if the client of this Transferable will hold a reference
306 // to it and the underlying clipboard content changes, the client does
307 // possible operate on an invalid list
308 // if there is only text on the clipboard we will also offer unicode text
309 // an synthesize this format on the fly if requested, to accomplish this
310 // we save the first offered text format which we will later use for the
311 // conversion
312 
314 {
315  sal::systools::COMReference<IEnumFORMATETC> pEnumFormatEtc;
316  HRESULT hr = m_rDataObject->EnumFormatEtc( DATADIR_GET, &pEnumFormatEtc );
317  if ( SUCCEEDED( hr ) )
318  {
319  pEnumFormatEtc->Reset( );
320 
321  FORMATETC fetc;
322  while ( S_OK == pEnumFormatEtc->Next( 1, &fetc, nullptr ) )
323  {
324  // we use locales only to determine the
325  // charset if there is text on the cliboard
326  // we don't offer this format
327  if ( CF_LOCALE == fetc.cfFormat )
328  continue;
329 
330  DataFlavor aFlavor = formatEtcToDataFlavor( fetc );
331 
332  // if text or oemtext is offered we also pretend to have unicode text
333  if ( CDataFormatTranslator::isOemOrAnsiTextFormat( fetc.cfFormat ) &&
335  {
336  addSupportedFlavor( aFlavor );
337 
338  m_TxtFormatOnClipboard = fetc.cfFormat;
339  m_bUnicodeRegistered = true;
340 
341  // register unicode text as accompany format
342  aFlavor = formatEtcToDataFlavor(
344  addSupportedFlavor( aFlavor );
345  }
346  else if ( (CF_UNICODETEXT == fetc.cfFormat) && !m_bUnicodeRegistered )
347  {
348  addSupportedFlavor( aFlavor );
349  m_bUnicodeRegistered = true;
350  }
351  else
352  addSupportedFlavor( aFlavor );
353 
354  // see MSDN IEnumFORMATETC
355  CoTaskMemFree( fetc.ptd );
356  }
357  }
358 }
359 
360 inline
361 void CDOTransferable::addSupportedFlavor( const DataFlavor& aFlavor )
362 {
363  // we ignore all formats that couldn't be translated
364  if ( aFlavor.MimeType.getLength( ) )
365  {
366  OSL_ASSERT( isValidFlavor( aFlavor ) );
367 
368  m_FlavorList.realloc( m_FlavorList.getLength( ) + 1 );
369  m_FlavorList[m_FlavorList.getLength( ) - 1] = aFlavor;
370  }
371 }
372 
373 DataFlavor CDOTransferable::formatEtcToDataFlavor( const FORMATETC& aFormatEtc )
374 {
375  LCID lcid = 0;
376 
377  // for non-unicode text format we must provide a locale to get
378  // the character-set of the text, if there is no locale on the
379  // clipboard we assume the text is in a charset appropriate for
380  // the current thread locale
381  if ( (CF_TEXT == aFormatEtc.cfFormat) || (CF_OEMTEXT == aFormatEtc.cfFormat) )
382  lcid = getLocaleFromClipboard( );
383 
384  return m_DataFormatTranslator.getDataFlavorFromFormatEtc( aFormatEtc, lcid );
385 }
386 
387 // returns the current locale on clipboard; if there is no locale on
388 // clipboard the function returns the current thread locale
389 
391 {
392  LCID lcid = GetThreadLocale( );
393 
394  try
395  {
397  ByteSequence_t aLCIDSeq = getClipboardData( fetc );
398  lcid = *reinterpret_cast<LCID*>( aLCIDSeq.getArray( ) );
399 
400  // because of a Win95/98 Bug; there the high word
401  // of a locale has the same value as the
402  // low word e.g. 0x07040704 that's not right
403  // correct is 0x00000704
404  lcid &= 0x0000FFFF;
405  }
406  catch(...)
407  {
408  // we take the default locale
409  }
410 
411  return lcid;
412 }
413 
414 // I think it's not necessary to call ReleaseStgMedium
415 // in case of failures because nothing should have been
416 // allocated etc.
417 
419 {
420  STGMEDIUM stgmedium;
421  HRESULT hr = m_rDataObject->GetData( aFormatEtc, &stgmedium );
422 
423  // in case of failure to get a WMF metafile handle, try to get a memory block
424  if( FAILED( hr ) &&
425  ( CF_METAFILEPICT == aFormatEtc.getClipformat() ) &&
426  ( TYMED_MFPICT == aFormatEtc.getTymed() ) )
427  {
428  CFormatEtc aTempFormat( aFormatEtc );
429  aTempFormat.setTymed( TYMED_HGLOBAL );
430  hr = m_rDataObject->GetData( aTempFormat, &stgmedium );
431  }
432 
433  if (FAILED(hr) && aFormatEtc.getTymed() == TYMED_HGLOBAL)
434  {
435  // Handle type is not memory, try stream.
436  CFormatEtc aTempFormat(aFormatEtc);
437  aTempFormat.setTymed(TYMED_ISTREAM);
438  hr = m_rDataObject->GetData(aTempFormat, &stgmedium);
439  }
440 
441  if ( FAILED( hr ) )
442  {
443  OSL_ASSERT( (hr != E_INVALIDARG) &&
444  (hr != DV_E_DVASPECT) &&
445  (hr != DV_E_LINDEX) &&
446  (hr != DV_E_TYMED) );
447 
448  if ( DV_E_FORMATETC == hr )
449  throw UnsupportedFlavorException( );
450  else if ( STG_E_MEDIUMFULL == hr )
451  throw IOException( );
452  else
453  throw RuntimeException( );
454  }
455 
456  ByteSequence_t byteStream;
457 
458  try
459  {
460  if ( CF_ENHMETAFILE == aFormatEtc.getClipformat() )
461  byteStream = WinENHMFPictToOOMFPict( stgmedium.hEnhMetaFile );
462  else if (CF_HDROP == aFormatEtc.getClipformat())
463  byteStream = CF_HDROPToFileList(stgmedium.hGlobal);
464  else if ( CF_BITMAP == aFormatEtc.getClipformat() )
465  {
466  byteStream = WinBITMAPToOOBMP(stgmedium.hBitmap);
467  if( aFormatEtc.getTymed() == TYMED_GDI &&
468  ! stgmedium.pUnkForRelease )
469  {
470  DeleteObject(stgmedium.hBitmap);
471  }
472  }
473  else
474  {
475  clipDataToByteStream( aFormatEtc.getClipformat( ), stgmedium, byteStream );
476 
477  // format conversion if necessary
478  // #i124085# DIBV5 should not happen currently, but keep as a hint here
479  if(CF_DIBV5 == aFormatEtc.getClipformat() || CF_DIB == aFormatEtc.getClipformat())
480  {
481  byteStream = WinDIBToOOBMP(byteStream);
482  }
483  else if(CF_METAFILEPICT == aFormatEtc.getClipformat())
484  {
485  byteStream = WinMFPictToOOMFPict(byteStream);
486  }
487  }
488 
489  ReleaseStgMedium( &stgmedium );
490  }
492  {
493  ReleaseStgMedium( &stgmedium );
494  throw IOException( );
495  }
496 
497  return byteStream;
498 }
499 
501 {
502  ByteSequence_t aTextSequence;
503  CFormatEtc fetc;
504  LCID lcid = getLocaleFromClipboard( );
505  sal_uInt32 cpForTxtCnvt = 0;
506 
507  if ( CF_TEXT == m_TxtFormatOnClipboard )
508  {
510  aTextSequence = getClipboardData( fetc );
511 
512  // determine the codepage used for text conversion
513  cpForTxtCnvt = getWinCPFromLocaleId( lcid, LOCALE_IDEFAULTANSICODEPAGE ).toInt32( );
514  }
515  else if ( CF_OEMTEXT == m_TxtFormatOnClipboard )
516  {
518  aTextSequence = getClipboardData( fetc );
519 
520  // determine the codepage used for text conversion
521  cpForTxtCnvt = getWinCPFromLocaleId( lcid, LOCALE_IDEFAULTCODEPAGE ).toInt32( );
522  }
523  else
524  OSL_ASSERT( false );
525 
526  CStgTransferHelper stgTransferHelper;
527 
528  // convert the text
529  MultiByteToWideCharEx( cpForTxtCnvt,
530  reinterpret_cast<char*>( aTextSequence.getArray( ) ),
531  sal::static_int_cast<sal_uInt32>(-1), // Huh ?
532  stgTransferHelper,
533  false);
534 
535  CRawHGlobalPtr ptrHGlob(stgTransferHelper);
536  sal_Unicode* pWChar = static_cast<sal_Unicode*>(ptrHGlob.GetMemPtr());
537 
538  return OUString(pWChar);
539 }
540 
542  const DataFlavor& lhs, const DataFlavor& rhs )
543 {
544  if ( !m_rXMimeCntFactory.is( ) )
545  {
546  m_rXMimeCntFactory = MimeContentTypeFactory::create( m_xContext );
547  }
548 
549  bool bRet = false;
550 
551  try
552  {
553  Reference< XMimeContentType > xLhs( m_rXMimeCntFactory->createMimeContentType( lhs.MimeType ) );
554  Reference< XMimeContentType > xRhs( m_rXMimeCntFactory->createMimeContentType( rhs.MimeType ) );
555 
556  if ( cmpFullMediaType( xLhs, xRhs ) )
557  {
558  bRet = cmpAllContentTypeParameter( xLhs, xRhs );
559  }
560  }
561  catch( IllegalArgumentException& )
562  {
563  OSL_FAIL( "Invalid content type detected" );
564  bRet = false;
565  }
566 
567  return bRet;
568 }
569 
570 css::uno::Any SAL_CALL CDOTransferable::getData( const Sequence< sal_Int8>& aProcessId )
571 {
572  Any retVal;
573 
574  sal_Int8 const * arProcCaller= aProcessId.getConstArray();
575  sal_uInt8 arId[16];
576  rtl_getGlobalProcessId(arId);
577  if( ! memcmp( arId, arProcCaller,16))
578  {
579  if (m_rDataObject.is())
580  {
581  IDataObject* pObj= m_rDataObject.get();
582  pObj->AddRef();
583  retVal.setValue( &pObj, cppu::UnoType<sal_uInt32>::get());
584  }
585  }
586  return retVal;
587 }
588 
589 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const Type CPPUTYPE_OUSTRING
::osl::Mutex m_aMutex
Type
Sequence< sal_Int8 > WinENHMFPictToOOMFPict(HENHMETAFILE hEnhMetaFile)
Definition: FmtFilter.cxx:129
virtual css::uno::Sequence< css::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors() override
sal_uInt32 memSize(CLIPFORMAT cf=CF_INVALID) const
ByteSequence_t getClipboardData(CFormatEtc &aFormatEtc)
css::datatransfer::DataFlavor formatEtcToDataFlavor(const FORMATETC &aFormatEtc)
int MultiByteToWideCharEx(UINT cp_src, LPCSTR lpMultiByteString, sal_uInt32 lenStr, CStgTransferHelper &refDTransHelper, BOOL bEnsureTrailingZero)
Definition: TxtCnvtHlp.cxx:58
css::uno::Sequence< css::datatransfer::DataFlavor > m_FlavorList
signed char sal_Int8
EXTERN_C BOOL BOOL const wchar_t *pProgramPath HRESULT hr
virtual css::uno::Any SAL_CALL getData(const css::uno::Sequence< sal_Int8 > &aProcessId) override
OUString synthesizeUnicodeText()
static bool isUnicodeTextFormat(CLIPFORMAT cf)
CFormatEtc getFormatEtcFromDataFlavor(const css::datatransfer::DataFlavor &aDataFlavor) const
CLIPFORMAT getClipformat() const
Definition: Fetc.cxx:97
css::uno::Sequence< sal_Int8 > ByteSequence_t
css::uno::Sequence< sal_Int8 > CF_HDROPToFileList(HGLOBAL hGlobal)
Return a FileList in which Windows Shell Links (lnk) are resolved.
Definition: FmtFilter.cxx:379
sal_uInt16 sal_Unicode
void setClipformat(CLIPFORMAT cf)
Definition: Fetc.cxx:128
css::uno::Reference< css::datatransfer::XMimeContentTypeFactory > m_rXMimeCntFactory
css::datatransfer::DataFlavor getDataFlavorFromFormatEtc(const FORMATETC &aFormatEtc, LCID lcid=GetThreadLocale()) const
OUString getWinCPFromLocaleId(LCID lcid, LCTYPE lctype)
Definition: ImplHelper.cxx:71
CDOTransferable(const css::uno::Reference< css::uno::XComponentContext > &rxContext, IDataObjectPtr rDataObject)
virtual sal_Bool SAL_CALL isDataFlavorSupported(const css::datatransfer::DataFlavor &aFlavor) override
const css::uno::Reference< css::uno::XComponentContext > m_xContext
static css::uno::Reference< css::datatransfer::XTransferable > create(const css::uno::Reference< css::uno::XComponentContext > &rxContext, IDataObjectPtr pIDataObject)
static CFormatEtc getFormatEtcForClipformat(CLIPFORMAT cf)
static bool isOemOrAnsiTextFormat(CLIPFORMAT cf)
int i
Sequence< sal_Int8 > WinBITMAPToOOBMP(HBITMAP aHBMP)
Definition: FmtFilter.cxx:398
unsigned char sal_Bool
CDataFormatTranslator m_DataFormatTranslator
virtual css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor &aFlavor) override
css::uno::Type const & get()
Sequence< sal_Int8 > WinMFPictToOOMFPict(Sequence< sal_Int8 > &aMetaFilePict)
Definition: FmtFilter.cxx:59
bool compareDataFlavors(const css::datatransfer::DataFlavor &lhs, const css::datatransfer::DataFlavor &rhs)
unsigned char sal_uInt8
void init(SIZE_T newSize, sal_uInt32 uiFlags=GHND, bool bDelStgOnRelease=false)
DWORD getTymed() const
Definition: Fetc.cxx:102
IDataObjectPtr m_rDataObject
Sequence< sal_Int8 > WinDIBToOOBMP(const Sequence< sal_Int8 > &aWinDIB)
Definition: FmtFilter.cxx:179
#define SAL_WARN(area, stream)
void addSupportedFlavor(const css::datatransfer::DataFlavor &aFlavor)
Reference< XComponentContext > m_xContext
void read(LPVOID pv, ULONG cb, ULONG *pcbRead=nullptr)
LCID getLocaleFromClipboard()
void setTymed(DWORD tymed)
Definition: Fetc.cxx:133
const sal_Int32 CF_INVALID
Definition: WinClip.hxx:25
CLIPFORMAT m_TxtFormatOnClipboard
css::uno::Any SAL_CALL makeAny(const SharedUNOComponent< INTERFACE, COMPONENT > &value)