2 * Richedit clipboard handling
4 * Copyright (C) 2006 Kevin Koltzau
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 WINE_DEFAULT_DEBUG_CHANNEL(richedit
);
25 static UINT cfRTF
= 0;
27 typedef struct DataObjectImpl
{
28 IDataObject IDataObject_iface
;
38 typedef struct EnumFormatImpl
{
39 IEnumFORMATETC IEnumFORMATETC_iface
;
48 static HRESULT
EnumFormatImpl_Create(const FORMATETC
*fmtetc
, UINT size
, LPENUMFORMATETC
*lplpformatetc
);
50 static inline DataObjectImpl
*impl_from_IDataObject(IDataObject
*iface
)
52 return CONTAINING_RECORD(iface
, DataObjectImpl
, IDataObject_iface
);
55 static inline EnumFormatImpl
*impl_from_IEnumFORMATETC(IEnumFORMATETC
*iface
)
57 return CONTAINING_RECORD(iface
, EnumFormatImpl
, IEnumFORMATETC_iface
);
60 static HRESULT WINAPI
EnumFormatImpl_QueryInterface(IEnumFORMATETC
*iface
, REFIID riid
, LPVOID
*ppvObj
)
62 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
63 TRACE("%p %s\n", This
, debugstr_guid(riid
));
65 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IEnumFORMATETC
)) {
66 IEnumFORMATETC_AddRef(iface
);
74 static ULONG WINAPI
EnumFormatImpl_AddRef(IEnumFORMATETC
*iface
)
76 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
77 LONG ref
= InterlockedIncrement(&This
->ref
);
78 TRACE("(%p) ref=%d\n", This
, ref
);
82 static ULONG WINAPI
EnumFormatImpl_Release(IEnumFORMATETC
*iface
)
84 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
85 ULONG ref
= InterlockedDecrement(&This
->ref
);
86 TRACE("(%p) ref=%d\n", This
, ref
);
89 GlobalFree(This
->fmtetc
);
96 static HRESULT WINAPI
EnumFormatImpl_Next(IEnumFORMATETC
*iface
, ULONG celt
,
97 FORMATETC
*rgelt
, ULONG
*pceltFetched
)
99 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
101 TRACE("(%p)->(%d %p %p)\n", This
, celt
, rgelt
, pceltFetched
);
106 count
= min(celt
, This
->fmtetc_cnt
-This
->cur
);
108 memcpy(rgelt
, This
->fmtetc
+This
->cur
, count
*sizeof(FORMATETC
));
112 *pceltFetched
= count
;
113 return count
== celt
? S_OK
: S_FALSE
;
116 static HRESULT WINAPI
EnumFormatImpl_Skip(IEnumFORMATETC
*iface
, ULONG celt
)
118 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
120 TRACE("(%p)->(%d)\n", This
, celt
);
122 count
= min(celt
, This
->fmtetc_cnt
-This
->cur
);
124 return count
== celt
? S_OK
: S_FALSE
;
127 static HRESULT WINAPI
EnumFormatImpl_Reset(IEnumFORMATETC
*iface
)
129 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
130 TRACE("(%p)\n", This
);
136 static HRESULT WINAPI
EnumFormatImpl_Clone(IEnumFORMATETC
*iface
, IEnumFORMATETC
**ppenum
)
138 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
140 TRACE("(%p)->(%p)\n", This
, ppenum
);
144 hr
= EnumFormatImpl_Create(This
->fmtetc
, This
->fmtetc_cnt
, ppenum
);
146 hr
= IEnumFORMATETC_Skip(*ppenum
, This
->cur
);
150 static const IEnumFORMATETCVtbl VT_EnumFormatImpl
= {
151 EnumFormatImpl_QueryInterface
,
152 EnumFormatImpl_AddRef
,
153 EnumFormatImpl_Release
,
156 EnumFormatImpl_Reset
,
160 static HRESULT
EnumFormatImpl_Create(const FORMATETC
*fmtetc
, UINT fmtetc_cnt
, IEnumFORMATETC
**lplpformatetc
)
165 ret
= heap_alloc(sizeof(EnumFormatImpl
));
166 ret
->IEnumFORMATETC_iface
.lpVtbl
= &VT_EnumFormatImpl
;
169 ret
->fmtetc_cnt
= fmtetc_cnt
;
170 ret
->fmtetc
= GlobalAlloc(GMEM_ZEROINIT
, fmtetc_cnt
*sizeof(FORMATETC
));
171 memcpy(ret
->fmtetc
, fmtetc
, fmtetc_cnt
*sizeof(FORMATETC
));
172 *lplpformatetc
= (LPENUMFORMATETC
)ret
;
176 static HRESULT WINAPI
DataObjectImpl_QueryInterface(IDataObject
*iface
, REFIID riid
, LPVOID
*ppvObj
)
178 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
179 TRACE("(%p)->(%s)\n", This
, debugstr_guid(riid
));
181 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IDataObject
)) {
182 IDataObject_AddRef(iface
);
187 return E_NOINTERFACE
;
190 static ULONG WINAPI
DataObjectImpl_AddRef(IDataObject
* iface
)
192 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
193 ULONG ref
= InterlockedIncrement(&This
->ref
);
194 TRACE("(%p) ref=%d\n", This
, ref
);
198 static ULONG WINAPI
DataObjectImpl_Release(IDataObject
* iface
)
200 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
201 ULONG ref
= InterlockedDecrement(&This
->ref
);
202 TRACE("(%p) ref=%d\n",This
, ref
);
205 if(This
->unicode
) GlobalFree(This
->unicode
);
206 if(This
->rtf
) GlobalFree(This
->rtf
);
207 if(This
->fmtetc
) GlobalFree(This
->fmtetc
);
214 static HRESULT WINAPI
DataObjectImpl_GetData(IDataObject
* iface
, FORMATETC
*pformatetc
, STGMEDIUM
*pmedium
)
216 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
217 TRACE("(%p)->(fmt=0x%08x tym=0x%08x)\n", This
, pformatetc
->cfFormat
, pformatetc
->tymed
);
219 if(pformatetc
->lindex
!= -1)
222 if(!(pformatetc
->tymed
& TYMED_HGLOBAL
))
225 if(This
->unicode
&& pformatetc
->cfFormat
== CF_UNICODETEXT
)
226 pmedium
->u
.hGlobal
= This
->unicode
;
227 else if(This
->rtf
&& pformatetc
->cfFormat
== cfRTF
)
228 pmedium
->u
.hGlobal
= This
->rtf
;
230 return DV_E_FORMATETC
;
232 pmedium
->tymed
= TYMED_HGLOBAL
;
233 pmedium
->pUnkForRelease
= (LPUNKNOWN
)iface
;
234 IUnknown_AddRef(pmedium
->pUnkForRelease
);
238 static HRESULT WINAPI
DataObjectImpl_GetDataHere(IDataObject
* iface
, FORMATETC
*pformatetc
, STGMEDIUM
*pmedium
)
240 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
241 FIXME("(%p): stub\n", This
);
245 static HRESULT WINAPI
DataObjectImpl_QueryGetData(IDataObject
* iface
, FORMATETC
*pformatetc
)
247 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
249 BOOL foundFormat
= FALSE
;
250 TRACE("(%p)->(fmt=0x%08x tym=0x%08x)\n", This
, pformatetc
->cfFormat
, pformatetc
->tymed
);
252 if(pformatetc
->lindex
!= -1)
255 for(i
=0; i
<This
->fmtetc_cnt
; i
++) {
256 if(This
->fmtetc
[i
].cfFormat
== pformatetc
->cfFormat
) {
258 if(This
->fmtetc
[i
].tymed
== pformatetc
->tymed
)
262 return foundFormat
?DV_E_FORMATETC
:DV_E_TYMED
;
265 static HRESULT WINAPI
DataObjectImpl_GetCanonicalFormatEtc(IDataObject
* iface
, FORMATETC
*pformatetcIn
,
266 FORMATETC
*pformatetcOut
)
268 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
269 TRACE("(%p)->(%p,%p)\n", This
, pformatetcIn
, pformatetcOut
);
272 *pformatetcOut
= *pformatetcIn
;
273 pformatetcOut
->ptd
= NULL
;
275 return DATA_S_SAMEFORMATETC
;
278 static HRESULT WINAPI
DataObjectImpl_SetData(IDataObject
* iface
, FORMATETC
*pformatetc
,
279 STGMEDIUM
*pmedium
, BOOL fRelease
)
281 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
282 FIXME("(%p): stub\n", This
);
286 static HRESULT WINAPI
DataObjectImpl_EnumFormatEtc(IDataObject
* iface
, DWORD dwDirection
,
287 IEnumFORMATETC
**ppenumFormatEtc
)
289 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
290 TRACE("(%p)->(%d)\n", This
, dwDirection
);
292 if(dwDirection
!= DATADIR_GET
) {
293 FIXME("Unsupported direction: %d\n", dwDirection
);
294 /* WinXP riched20 also returns E_NOTIMPL in this case */
295 *ppenumFormatEtc
= NULL
;
298 return EnumFormatImpl_Create(This
->fmtetc
, This
->fmtetc_cnt
, ppenumFormatEtc
);
301 static HRESULT WINAPI
DataObjectImpl_DAdvise(IDataObject
* iface
, FORMATETC
*pformatetc
, DWORD advf
,
302 IAdviseSink
*pAdvSink
, DWORD
*pdwConnection
)
304 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
305 FIXME("(%p): stub\n", This
);
309 static HRESULT WINAPI
DataObjectImpl_DUnadvise(IDataObject
* iface
, DWORD dwConnection
)
311 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
312 FIXME("(%p): stub\n", This
);
316 static HRESULT WINAPI
DataObjectImpl_EnumDAdvise(IDataObject
* iface
, IEnumSTATDATA
**ppenumAdvise
)
318 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
319 FIXME("(%p): stub\n", This
);
323 static const IDataObjectVtbl VT_DataObjectImpl
=
325 DataObjectImpl_QueryInterface
,
326 DataObjectImpl_AddRef
,
327 DataObjectImpl_Release
,
328 DataObjectImpl_GetData
,
329 DataObjectImpl_GetDataHere
,
330 DataObjectImpl_QueryGetData
,
331 DataObjectImpl_GetCanonicalFormatEtc
,
332 DataObjectImpl_SetData
,
333 DataObjectImpl_EnumFormatEtc
,
334 DataObjectImpl_DAdvise
,
335 DataObjectImpl_DUnadvise
,
336 DataObjectImpl_EnumDAdvise
339 static HGLOBAL
get_unicode_text(ME_TextEditor
*editor
, const ME_Cursor
*start
, int nChars
)
344 ME_DisplayItem
*para
;
345 int nEnd
= ME_GetCursorOfs(start
) + nChars
;
347 /* count paragraphs in range */
349 while((para
= para
->member
.para
.next_para
) &&
350 para
->member
.para
.nCharOfs
<= nEnd
)
353 ret
= GlobalAlloc(GMEM_MOVEABLE
, sizeof(WCHAR
) * (nChars
+ pars
+ 1));
354 data
= GlobalLock(ret
);
355 ME_GetTextW(editor
, data
, nChars
+ pars
, start
, nChars
, TRUE
);
360 typedef struct tagME_GlobalDestStruct
364 } ME_GlobalDestStruct
;
366 static DWORD CALLBACK
ME_AppendToHGLOBAL(DWORD_PTR dwCookie
, LPBYTE lpBuff
, LONG cb
, LONG
*pcb
)
368 ME_GlobalDestStruct
*pData
= (ME_GlobalDestStruct
*)dwCookie
;
372 nMaxSize
= GlobalSize(pData
->hData
);
373 if (pData
->nLength
+cb
+1 >= cb
) {
374 /* round up to 2^17 */
375 int nNewSize
= (((nMaxSize
+cb
+1)|0x1FFFF)+1) & 0xFFFE0000;
376 pData
->hData
= GlobalReAlloc(pData
->hData
, nNewSize
, 0);
378 pDest
= GlobalLock(pData
->hData
);
379 memcpy(pDest
+ pData
->nLength
, lpBuff
, cb
);
380 pData
->nLength
+= cb
;
381 pDest
[pData
->nLength
] = '\0';
382 GlobalUnlock(pData
->hData
);
388 static HGLOBAL
get_rtf_text(ME_TextEditor
*editor
, const ME_Cursor
*start
, int nChars
)
391 ME_GlobalDestStruct gds
;
393 gds
.hData
= GlobalAlloc(GMEM_MOVEABLE
, 0);
395 es
.dwCookie
= (DWORD_PTR
)&gds
;
396 es
.pfnCallback
= ME_AppendToHGLOBAL
;
397 ME_StreamOutRange(editor
, SF_RTF
, start
, nChars
, &es
);
398 GlobalReAlloc(gds
.hData
, gds
.nLength
+1, 0);
402 HRESULT
ME_GetDataObject(ME_TextEditor
*editor
, const ME_Cursor
*start
,
403 int nChars
, LPDATAOBJECT
*lplpdataobj
)
406 TRACE("(%p,%d,%d)\n", editor
, ME_GetCursorOfs(start
), nChars
);
408 obj
= heap_alloc(sizeof(DataObjectImpl
));
410 cfRTF
= RegisterClipboardFormatA("Rich Text Format");
412 obj
->IDataObject_iface
.lpVtbl
= &VT_DataObjectImpl
;
414 obj
->unicode
= get_unicode_text(editor
, start
, nChars
);
418 if(editor
->mode
& TM_RICHTEXT
)
420 obj
->fmtetc
= GlobalAlloc(GMEM_ZEROINIT
, obj
->fmtetc_cnt
*sizeof(FORMATETC
));
421 InitFormatEtc(obj
->fmtetc
[0], CF_UNICODETEXT
, TYMED_HGLOBAL
);
422 if(editor
->mode
& TM_RICHTEXT
) {
423 obj
->rtf
= get_rtf_text(editor
, start
, nChars
);
424 InitFormatEtc(obj
->fmtetc
[1], cfRTF
, TYMED_HGLOBAL
);
427 *lplpdataobj
= (LPDATAOBJECT
)obj
;