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
21 #define NONAMELESSUNION
25 WINE_DEFAULT_DEBUG_CHANNEL(richedit
);
27 static UINT cfRTF
= 0;
29 typedef struct DataObjectImpl
{
30 IDataObject IDataObject_iface
;
40 typedef struct EnumFormatImpl
{
41 IEnumFORMATETC IEnumFORMATETC_iface
;
50 static HRESULT
EnumFormatImpl_Create(const FORMATETC
*fmtetc
, UINT size
, LPENUMFORMATETC
*lplpformatetc
);
52 static inline DataObjectImpl
*impl_from_IDataObject(IDataObject
*iface
)
54 return CONTAINING_RECORD(iface
, DataObjectImpl
, IDataObject_iface
);
57 static inline EnumFormatImpl
*impl_from_IEnumFORMATETC(IEnumFORMATETC
*iface
)
59 return CONTAINING_RECORD(iface
, EnumFormatImpl
, IEnumFORMATETC_iface
);
62 static HRESULT WINAPI
EnumFormatImpl_QueryInterface(IEnumFORMATETC
*iface
, REFIID riid
, LPVOID
*ppvObj
)
64 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
65 TRACE("%p %s\n", This
, debugstr_guid(riid
));
67 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IEnumFORMATETC
)) {
68 IEnumFORMATETC_AddRef(iface
);
69 *ppvObj
= &This
->IEnumFORMATETC_iface
;
76 static ULONG WINAPI
EnumFormatImpl_AddRef(IEnumFORMATETC
*iface
)
78 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
79 LONG ref
= InterlockedIncrement(&This
->ref
);
80 TRACE("(%p) ref=%d\n", This
, ref
);
84 static ULONG WINAPI
EnumFormatImpl_Release(IEnumFORMATETC
*iface
)
86 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
87 ULONG ref
= InterlockedDecrement(&This
->ref
);
88 TRACE("(%p) ref=%d\n", This
, ref
);
91 GlobalFree(This
->fmtetc
);
98 static HRESULT WINAPI
EnumFormatImpl_Next(IEnumFORMATETC
*iface
, ULONG celt
,
99 FORMATETC
*rgelt
, ULONG
*pceltFetched
)
101 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
103 TRACE("(%p)->(%d %p %p)\n", This
, celt
, rgelt
, pceltFetched
);
108 count
= min(celt
, This
->fmtetc_cnt
-This
->cur
);
110 memcpy(rgelt
, This
->fmtetc
+This
->cur
, count
*sizeof(FORMATETC
));
114 *pceltFetched
= count
;
115 return count
== celt
? S_OK
: S_FALSE
;
118 static HRESULT WINAPI
EnumFormatImpl_Skip(IEnumFORMATETC
*iface
, ULONG celt
)
120 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
122 TRACE("(%p)->(%d)\n", This
, celt
);
124 count
= min(celt
, This
->fmtetc_cnt
-This
->cur
);
126 return count
== celt
? S_OK
: S_FALSE
;
129 static HRESULT WINAPI
EnumFormatImpl_Reset(IEnumFORMATETC
*iface
)
131 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
132 TRACE("(%p)\n", This
);
138 static HRESULT WINAPI
EnumFormatImpl_Clone(IEnumFORMATETC
*iface
, IEnumFORMATETC
**ppenum
)
140 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
142 TRACE("(%p)->(%p)\n", This
, ppenum
);
146 hr
= EnumFormatImpl_Create(This
->fmtetc
, This
->fmtetc_cnt
, ppenum
);
148 hr
= IEnumFORMATETC_Skip(*ppenum
, This
->cur
);
152 static const IEnumFORMATETCVtbl VT_EnumFormatImpl
= {
153 EnumFormatImpl_QueryInterface
,
154 EnumFormatImpl_AddRef
,
155 EnumFormatImpl_Release
,
158 EnumFormatImpl_Reset
,
162 static HRESULT
EnumFormatImpl_Create(const FORMATETC
*fmtetc
, UINT fmtetc_cnt
,
163 IEnumFORMATETC
**formatetc
)
168 ret
= heap_alloc(sizeof(EnumFormatImpl
));
169 ret
->IEnumFORMATETC_iface
.lpVtbl
= &VT_EnumFormatImpl
;
172 ret
->fmtetc_cnt
= fmtetc_cnt
;
173 ret
->fmtetc
= GlobalAlloc(GMEM_ZEROINIT
, fmtetc_cnt
*sizeof(FORMATETC
));
174 memcpy(ret
->fmtetc
, fmtetc
, fmtetc_cnt
*sizeof(FORMATETC
));
175 *formatetc
= &ret
->IEnumFORMATETC_iface
;
179 static HRESULT WINAPI
DataObjectImpl_QueryInterface(IDataObject
*iface
, REFIID riid
, LPVOID
*ppvObj
)
181 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
182 TRACE("(%p)->(%s)\n", This
, debugstr_guid(riid
));
184 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IDataObject
)) {
185 IDataObject_AddRef(iface
);
186 *ppvObj
= &This
->IDataObject_iface
;
190 return E_NOINTERFACE
;
193 static ULONG WINAPI
DataObjectImpl_AddRef(IDataObject
* iface
)
195 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
196 ULONG ref
= InterlockedIncrement(&This
->ref
);
197 TRACE("(%p) ref=%d\n", This
, ref
);
201 static ULONG WINAPI
DataObjectImpl_Release(IDataObject
* iface
)
203 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
204 ULONG ref
= InterlockedDecrement(&This
->ref
);
205 TRACE("(%p) ref=%d\n",This
, ref
);
208 if(This
->unicode
) GlobalFree(This
->unicode
);
209 if(This
->rtf
) GlobalFree(This
->rtf
);
210 if(This
->fmtetc
) GlobalFree(This
->fmtetc
);
217 static HRESULT WINAPI
DataObjectImpl_GetData(IDataObject
* iface
, FORMATETC
*pformatetc
, STGMEDIUM
*pmedium
)
219 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
220 TRACE("(%p)->(fmt=0x%08x tym=0x%08x)\n", This
, pformatetc
->cfFormat
, pformatetc
->tymed
);
222 if(pformatetc
->lindex
!= -1)
225 if(!(pformatetc
->tymed
& TYMED_HGLOBAL
))
228 if(This
->unicode
&& pformatetc
->cfFormat
== CF_UNICODETEXT
)
229 pmedium
->u
.hGlobal
= This
->unicode
;
230 else if(This
->rtf
&& pformatetc
->cfFormat
== cfRTF
)
231 pmedium
->u
.hGlobal
= This
->rtf
;
233 return DV_E_FORMATETC
;
235 pmedium
->tymed
= TYMED_HGLOBAL
;
236 pmedium
->pUnkForRelease
= (LPUNKNOWN
)iface
;
237 IUnknown_AddRef(pmedium
->pUnkForRelease
);
241 static HRESULT WINAPI
DataObjectImpl_GetDataHere(IDataObject
* iface
, FORMATETC
*pformatetc
, STGMEDIUM
*pmedium
)
243 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
244 FIXME("(%p): stub\n", This
);
248 static HRESULT WINAPI
DataObjectImpl_QueryGetData(IDataObject
* iface
, FORMATETC
*pformatetc
)
250 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
252 BOOL foundFormat
= FALSE
;
253 TRACE("(%p)->(fmt=0x%08x tym=0x%08x)\n", This
, pformatetc
->cfFormat
, pformatetc
->tymed
);
255 if(pformatetc
->lindex
!= -1)
258 for(i
=0; i
<This
->fmtetc_cnt
; i
++) {
259 if(This
->fmtetc
[i
].cfFormat
== pformatetc
->cfFormat
) {
261 if(This
->fmtetc
[i
].tymed
== pformatetc
->tymed
)
265 return foundFormat
?DV_E_FORMATETC
:DV_E_TYMED
;
268 static HRESULT WINAPI
DataObjectImpl_GetCanonicalFormatEtc(IDataObject
* iface
, FORMATETC
*pformatetcIn
,
269 FORMATETC
*pformatetcOut
)
271 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
272 TRACE("(%p)->(%p,%p)\n", This
, pformatetcIn
, pformatetcOut
);
275 *pformatetcOut
= *pformatetcIn
;
276 pformatetcOut
->ptd
= NULL
;
278 return DATA_S_SAMEFORMATETC
;
281 static HRESULT WINAPI
DataObjectImpl_SetData(IDataObject
* iface
, FORMATETC
*pformatetc
,
282 STGMEDIUM
*pmedium
, BOOL fRelease
)
284 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
285 FIXME("(%p): stub\n", This
);
289 static HRESULT WINAPI
DataObjectImpl_EnumFormatEtc(IDataObject
* iface
, DWORD dwDirection
,
290 IEnumFORMATETC
**ppenumFormatEtc
)
292 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
293 TRACE("(%p)->(%d)\n", This
, dwDirection
);
295 if(dwDirection
!= DATADIR_GET
) {
296 FIXME("Unsupported direction: %d\n", dwDirection
);
297 /* WinXP riched20 also returns E_NOTIMPL in this case */
298 *ppenumFormatEtc
= NULL
;
301 return EnumFormatImpl_Create(This
->fmtetc
, This
->fmtetc_cnt
, ppenumFormatEtc
);
304 static HRESULT WINAPI
DataObjectImpl_DAdvise(IDataObject
* iface
, FORMATETC
*pformatetc
, DWORD advf
,
305 IAdviseSink
*pAdvSink
, DWORD
*pdwConnection
)
307 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
308 FIXME("(%p): stub\n", This
);
312 static HRESULT WINAPI
DataObjectImpl_DUnadvise(IDataObject
* iface
, DWORD dwConnection
)
314 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
315 FIXME("(%p): stub\n", This
);
319 static HRESULT WINAPI
DataObjectImpl_EnumDAdvise(IDataObject
* iface
, IEnumSTATDATA
**ppenumAdvise
)
321 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
322 FIXME("(%p): stub\n", This
);
326 static const IDataObjectVtbl VT_DataObjectImpl
=
328 DataObjectImpl_QueryInterface
,
329 DataObjectImpl_AddRef
,
330 DataObjectImpl_Release
,
331 DataObjectImpl_GetData
,
332 DataObjectImpl_GetDataHere
,
333 DataObjectImpl_QueryGetData
,
334 DataObjectImpl_GetCanonicalFormatEtc
,
335 DataObjectImpl_SetData
,
336 DataObjectImpl_EnumFormatEtc
,
337 DataObjectImpl_DAdvise
,
338 DataObjectImpl_DUnadvise
,
339 DataObjectImpl_EnumDAdvise
342 static HGLOBAL
get_unicode_text(ME_TextEditor
*editor
, const ME_Cursor
*start
, int nChars
)
347 ME_DisplayItem
*para
;
348 int nEnd
= ME_GetCursorOfs(start
) + nChars
;
350 /* count paragraphs in range */
352 while((para
= para
->member
.para
.next_para
) &&
353 para
->member
.para
.nCharOfs
<= nEnd
)
356 ret
= GlobalAlloc(GMEM_MOVEABLE
, sizeof(WCHAR
) * (nChars
+ pars
+ 1));
357 data
= GlobalLock(ret
);
358 ME_GetTextW(editor
, data
, nChars
+ pars
, start
, nChars
, TRUE
, FALSE
);
363 typedef struct tagME_GlobalDestStruct
367 } ME_GlobalDestStruct
;
369 static DWORD CALLBACK
ME_AppendToHGLOBAL(DWORD_PTR dwCookie
, LPBYTE lpBuff
, LONG cb
, LONG
*pcb
)
371 ME_GlobalDestStruct
*pData
= (ME_GlobalDestStruct
*)dwCookie
;
375 nMaxSize
= GlobalSize(pData
->hData
);
376 if (pData
->nLength
+cb
+1 >= cb
) {
377 /* round up to 2^17 */
378 int nNewSize
= (((nMaxSize
+cb
+1)|0x1FFFF)+1) & 0xFFFE0000;
379 pData
->hData
= GlobalReAlloc(pData
->hData
, nNewSize
, 0);
381 pDest
= GlobalLock(pData
->hData
);
382 memcpy(pDest
+ pData
->nLength
, lpBuff
, cb
);
383 pData
->nLength
+= cb
;
384 pDest
[pData
->nLength
] = '\0';
385 GlobalUnlock(pData
->hData
);
391 static HGLOBAL
get_rtf_text(ME_TextEditor
*editor
, const ME_Cursor
*start
, int nChars
)
394 ME_GlobalDestStruct gds
;
396 gds
.hData
= GlobalAlloc(GMEM_MOVEABLE
, 0);
398 es
.dwCookie
= (DWORD_PTR
)&gds
;
399 es
.pfnCallback
= ME_AppendToHGLOBAL
;
400 ME_StreamOutRange(editor
, SF_RTF
, start
, nChars
, &es
);
401 GlobalReAlloc(gds
.hData
, gds
.nLength
+1, 0);
405 HRESULT
ME_GetDataObject(ME_TextEditor
*editor
, const ME_Cursor
*start
, int nChars
,
406 IDataObject
**dataobj
)
409 TRACE("(%p,%d,%d)\n", editor
, ME_GetCursorOfs(start
), nChars
);
411 obj
= heap_alloc(sizeof(DataObjectImpl
));
413 cfRTF
= RegisterClipboardFormatA("Rich Text Format");
415 obj
->IDataObject_iface
.lpVtbl
= &VT_DataObjectImpl
;
417 obj
->unicode
= get_unicode_text(editor
, start
, nChars
);
421 if(editor
->mode
& TM_RICHTEXT
)
423 obj
->fmtetc
= GlobalAlloc(GMEM_ZEROINIT
, obj
->fmtetc_cnt
*sizeof(FORMATETC
));
424 InitFormatEtc(obj
->fmtetc
[0], CF_UNICODETEXT
, TYMED_HGLOBAL
);
425 if(editor
->mode
& TM_RICHTEXT
) {
426 obj
->rtf
= get_rtf_text(editor
, start
, nChars
);
427 InitFormatEtc(obj
->fmtetc
[1], cfRTF
, TYMED_HGLOBAL
);
430 *dataobj
= &obj
->IDataObject_iface
;