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 const IDataObjectVtbl
*lpVtbl
;
38 typedef struct EnumFormatImpl
{
39 const IEnumFORMATETCVtbl
*lpVtbl
;
48 static HRESULT
EnumFormatImpl_Create(const FORMATETC
*fmtetc
, UINT size
, LPENUMFORMATETC
*lplpformatetc
);
50 static HRESULT WINAPI
EnumFormatImpl_QueryInterface(IEnumFORMATETC
*iface
, REFIID riid
, LPVOID
*ppvObj
)
52 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
53 TRACE("%p %s\n", This
, debugstr_guid(riid
));
55 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IEnumFORMATETC
)) {
56 IEnumFORMATETC_AddRef(iface
);
64 static ULONG WINAPI
EnumFormatImpl_AddRef(IEnumFORMATETC
*iface
)
66 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
67 LONG ref
= InterlockedIncrement(&This
->ref
);
68 TRACE("(%p) ref=%d\n", This
, ref
);
72 static ULONG WINAPI
EnumFormatImpl_Release(IEnumFORMATETC
*iface
)
74 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
75 ULONG ref
= InterlockedDecrement(&This
->ref
);
76 TRACE("(%p) ref=%d\n", This
, ref
);
79 GlobalFree(This
->fmtetc
);
86 static HRESULT WINAPI
EnumFormatImpl_Next(IEnumFORMATETC
*iface
, ULONG celt
,
87 FORMATETC
*rgelt
, ULONG
*pceltFetched
)
89 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
91 TRACE("(%p)->(%d %p %p)\n", This
, celt
, rgelt
, pceltFetched
);
96 count
= min(celt
, This
->fmtetc_cnt
-This
->cur
);
98 memcpy(rgelt
, This
->fmtetc
+This
->cur
, count
*sizeof(FORMATETC
));
102 *pceltFetched
= count
;
103 return count
== celt
? S_OK
: S_FALSE
;
106 static HRESULT WINAPI
EnumFormatImpl_Skip(IEnumFORMATETC
*iface
, ULONG celt
)
108 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
110 TRACE("(%p)->(%d)\n", This
, celt
);
112 count
= min(celt
, This
->fmtetc_cnt
-This
->cur
);
114 return count
== celt
? S_OK
: S_FALSE
;
117 static HRESULT WINAPI
EnumFormatImpl_Reset(IEnumFORMATETC
*iface
)
119 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
120 TRACE("(%p)\n", This
);
126 static HRESULT WINAPI
EnumFormatImpl_Clone(IEnumFORMATETC
*iface
, IEnumFORMATETC
**ppenum
)
128 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
130 TRACE("(%p)->(%p)\n", This
, ppenum
);
134 hr
= EnumFormatImpl_Create(This
->fmtetc
, This
->fmtetc_cnt
, ppenum
);
136 hr
= IEnumFORMATETC_Skip(*ppenum
, This
->cur
);
140 static const IEnumFORMATETCVtbl VT_EnumFormatImpl
= {
141 EnumFormatImpl_QueryInterface
,
142 EnumFormatImpl_AddRef
,
143 EnumFormatImpl_Release
,
146 EnumFormatImpl_Reset
,
150 static HRESULT
EnumFormatImpl_Create(const FORMATETC
*fmtetc
, UINT fmtetc_cnt
, IEnumFORMATETC
**lplpformatetc
)
155 ret
= heap_alloc(sizeof(EnumFormatImpl
));
156 ret
->lpVtbl
= &VT_EnumFormatImpl
;
159 ret
->fmtetc_cnt
= fmtetc_cnt
;
160 ret
->fmtetc
= GlobalAlloc(GMEM_ZEROINIT
, fmtetc_cnt
*sizeof(FORMATETC
));
161 memcpy(ret
->fmtetc
, fmtetc
, fmtetc_cnt
*sizeof(FORMATETC
));
162 *lplpformatetc
= (LPENUMFORMATETC
)ret
;
166 static HRESULT WINAPI
DataObjectImpl_QueryInterface(IDataObject
*iface
, REFIID riid
, LPVOID
*ppvObj
)
168 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
169 TRACE("(%p)->(%s)\n", This
, debugstr_guid(riid
));
171 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IDataObject
)) {
172 IDataObject_AddRef(iface
);
177 return E_NOINTERFACE
;
180 static ULONG WINAPI
DataObjectImpl_AddRef(IDataObject
* iface
)
182 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
183 ULONG ref
= InterlockedIncrement(&This
->ref
);
184 TRACE("(%p) ref=%d\n", This
, ref
);
188 static ULONG WINAPI
DataObjectImpl_Release(IDataObject
* iface
)
190 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
191 ULONG ref
= InterlockedDecrement(&This
->ref
);
192 TRACE("(%p) ref=%d\n",This
, ref
);
195 if(This
->unicode
) GlobalFree(This
->unicode
);
196 if(This
->rtf
) GlobalFree(This
->rtf
);
197 if(This
->fmtetc
) GlobalFree(This
->fmtetc
);
204 static HRESULT WINAPI
DataObjectImpl_GetData(IDataObject
* iface
, FORMATETC
*pformatetc
, STGMEDIUM
*pmedium
)
206 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
207 TRACE("(%p)->(fmt=0x%08x tym=0x%08x)\n", This
, pformatetc
->cfFormat
, pformatetc
->tymed
);
209 if(pformatetc
->lindex
!= -1)
212 if(!(pformatetc
->tymed
& TYMED_HGLOBAL
))
215 if(This
->unicode
&& pformatetc
->cfFormat
== CF_UNICODETEXT
)
216 pmedium
->u
.hGlobal
= This
->unicode
;
217 else if(This
->rtf
&& pformatetc
->cfFormat
== cfRTF
)
218 pmedium
->u
.hGlobal
= This
->rtf
;
220 return DV_E_FORMATETC
;
222 pmedium
->tymed
= TYMED_HGLOBAL
;
223 pmedium
->pUnkForRelease
= (LPUNKNOWN
)iface
;
224 IUnknown_AddRef(pmedium
->pUnkForRelease
);
228 static HRESULT WINAPI
DataObjectImpl_GetDataHere(IDataObject
* iface
, FORMATETC
*pformatetc
, STGMEDIUM
*pmedium
)
230 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
231 FIXME("(%p): stub\n", This
);
235 static HRESULT WINAPI
DataObjectImpl_QueryGetData(IDataObject
* iface
, FORMATETC
*pformatetc
)
237 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
239 BOOL foundFormat
= FALSE
;
240 TRACE("(%p)->(fmt=0x%08x tym=0x%08x)\n", This
, pformatetc
->cfFormat
, pformatetc
->tymed
);
242 if(pformatetc
->lindex
!= -1)
245 for(i
=0; i
<This
->fmtetc_cnt
; i
++) {
246 if(This
->fmtetc
[i
].cfFormat
== pformatetc
->cfFormat
) {
248 if(This
->fmtetc
[i
].tymed
== pformatetc
->tymed
)
252 return foundFormat
?DV_E_FORMATETC
:DV_E_TYMED
;
255 static HRESULT WINAPI
DataObjectImpl_GetCanonicalFormatEtc(IDataObject
* iface
, FORMATETC
*pformatetcIn
,
256 FORMATETC
*pformatetcOut
)
258 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
259 TRACE("(%p)->(%p,%p)\n", This
, pformatetcIn
, pformatetcOut
);
262 *pformatetcOut
= *pformatetcIn
;
263 pformatetcOut
->ptd
= NULL
;
265 return DATA_S_SAMEFORMATETC
;
268 static HRESULT WINAPI
DataObjectImpl_SetData(IDataObject
* iface
, FORMATETC
*pformatetc
,
269 STGMEDIUM
*pmedium
, BOOL fRelease
)
271 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
272 FIXME("(%p): stub\n", This
);
276 static HRESULT WINAPI
DataObjectImpl_EnumFormatEtc(IDataObject
* iface
, DWORD dwDirection
,
277 IEnumFORMATETC
**ppenumFormatEtc
)
279 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
280 TRACE("(%p)->(%d)\n", This
, dwDirection
);
282 if(dwDirection
!= DATADIR_GET
) {
283 FIXME("Unsupported direction: %d\n", dwDirection
);
284 /* WinXP riched20 also returns E_NOTIMPL in this case */
285 *ppenumFormatEtc
= NULL
;
288 return EnumFormatImpl_Create(This
->fmtetc
, This
->fmtetc_cnt
, ppenumFormatEtc
);
291 static HRESULT WINAPI
DataObjectImpl_DAdvise(IDataObject
* iface
, FORMATETC
*pformatetc
, DWORD advf
,
292 IAdviseSink
*pAdvSink
, DWORD
*pdwConnection
)
294 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
295 FIXME("(%p): stub\n", This
);
299 static HRESULT WINAPI
DataObjectImpl_DUnadvise(IDataObject
* iface
, DWORD dwConnection
)
301 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
302 FIXME("(%p): stub\n", This
);
306 static HRESULT WINAPI
DataObjectImpl_EnumDAdvise(IDataObject
* iface
, IEnumSTATDATA
**ppenumAdvise
)
308 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
309 FIXME("(%p): stub\n", This
);
313 static const IDataObjectVtbl VT_DataObjectImpl
=
315 DataObjectImpl_QueryInterface
,
316 DataObjectImpl_AddRef
,
317 DataObjectImpl_Release
,
318 DataObjectImpl_GetData
,
319 DataObjectImpl_GetDataHere
,
320 DataObjectImpl_QueryGetData
,
321 DataObjectImpl_GetCanonicalFormatEtc
,
322 DataObjectImpl_SetData
,
323 DataObjectImpl_EnumFormatEtc
,
324 DataObjectImpl_DAdvise
,
325 DataObjectImpl_DUnadvise
,
326 DataObjectImpl_EnumDAdvise
329 static HGLOBAL
get_unicode_text(ME_TextEditor
*editor
, const ME_Cursor
*start
, int nChars
)
334 ME_DisplayItem
*para
;
335 int nEnd
= ME_GetCursorOfs(start
) + nChars
;
337 /* count paragraphs in range */
339 while((para
= para
->member
.para
.next_para
) &&
340 para
->member
.para
.nCharOfs
<= nEnd
)
343 ret
= GlobalAlloc(GMEM_MOVEABLE
, sizeof(WCHAR
) * (nChars
+ pars
+ 1));
344 data
= GlobalLock(ret
);
345 ME_GetTextW(editor
, data
, nChars
+ pars
, start
, nChars
, TRUE
);
350 typedef struct tagME_GlobalDestStruct
354 } ME_GlobalDestStruct
;
356 static DWORD CALLBACK
ME_AppendToHGLOBAL(DWORD_PTR dwCookie
, LPBYTE lpBuff
, LONG cb
, LONG
*pcb
)
358 ME_GlobalDestStruct
*pData
= (ME_GlobalDestStruct
*)dwCookie
;
362 nMaxSize
= GlobalSize(pData
->hData
);
363 if (pData
->nLength
+cb
+1 >= cb
) {
364 /* round up to 2^17 */
365 int nNewSize
= (((nMaxSize
+cb
+1)|0x1FFFF)+1) & 0xFFFE0000;
366 pData
->hData
= GlobalReAlloc(pData
->hData
, nNewSize
, 0);
368 pDest
= GlobalLock(pData
->hData
);
369 memcpy(pDest
+ pData
->nLength
, lpBuff
, cb
);
370 pData
->nLength
+= cb
;
371 pDest
[pData
->nLength
] = '\0';
372 GlobalUnlock(pData
->hData
);
378 static HGLOBAL
get_rtf_text(ME_TextEditor
*editor
, const ME_Cursor
*start
, int nChars
)
381 ME_GlobalDestStruct gds
;
383 gds
.hData
= GlobalAlloc(GMEM_MOVEABLE
, 0);
385 es
.dwCookie
= (DWORD_PTR
)&gds
;
386 es
.pfnCallback
= ME_AppendToHGLOBAL
;
387 ME_StreamOutRange(editor
, SF_RTF
, start
, nChars
, &es
);
388 GlobalReAlloc(gds
.hData
, gds
.nLength
+1, 0);
392 HRESULT
ME_GetDataObject(ME_TextEditor
*editor
, const ME_Cursor
*start
,
393 int nChars
, LPDATAOBJECT
*lplpdataobj
)
396 TRACE("(%p,%d,%d)\n", editor
, ME_GetCursorOfs(start
), nChars
);
398 obj
= heap_alloc(sizeof(DataObjectImpl
));
400 cfRTF
= RegisterClipboardFormatA("Rich Text Format");
402 obj
->lpVtbl
= &VT_DataObjectImpl
;
404 obj
->unicode
= get_unicode_text(editor
, start
, nChars
);
408 if(editor
->mode
& TM_RICHTEXT
)
410 obj
->fmtetc
= GlobalAlloc(GMEM_ZEROINIT
, obj
->fmtetc_cnt
*sizeof(FORMATETC
));
411 InitFormatEtc(obj
->fmtetc
[0], CF_UNICODETEXT
, TYMED_HGLOBAL
);
412 if(editor
->mode
& TM_RICHTEXT
) {
413 obj
->rtf
= get_rtf_text(editor
, start
, nChars
);
414 InitFormatEtc(obj
->fmtetc
[1], cfRTF
, TYMED_HGLOBAL
);
417 *lplpdataobj
= (LPDATAOBJECT
)obj
;