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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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(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
);
57 *ppvObj
= (LPVOID
)This
;
64 static ULONG WINAPI
EnumFormatImpl_AddRef(IEnumFORMATETC
*iface
)
66 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
67 LONG ref
= InterlockedIncrement(&This
->ref
);
68 TRACE("(%p) ref=%ld\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=%ld\n", This
, ref
);
79 HeapFree(GetProcessHeap(), 0, This
->fmtetc
);
80 HeapFree(GetProcessHeap(), 0, This
);
86 static HRESULT WINAPI
EnumFormatImpl_Next(IEnumFORMATETC
*iface
, ULONG celt
,
87 FORMATETC
*rgelt
, ULONG
*pceltFetched
)
89 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
91 TRACE("(%p)->(%ld %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)->(%ld)\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(FORMATETC
*fmtetc
, UINT fmtetc_cnt
, IEnumFORMATETC
**lplpformatetc
)
155 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(EnumFormatImpl
));
156 ret
->lpVtbl
= &VT_EnumFormatImpl
;
159 ret
->fmtetc_cnt
= fmtetc_cnt
;
160 ret
->fmtetc
= HeapAlloc(GetProcessHeap(), 0, 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
);
173 *ppvObj
= (LPVOID
)This
;
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=%ld\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=%ld\n",This
, ref
);
195 if(This
->unicode
) GlobalFree(This
->unicode
);
196 if(This
->rtf
) GlobalFree(This
->rtf
);
197 if(This
->fmtetc
) GlobalFree(This
->fmtetc
);
198 HeapFree(GetProcessHeap(), 0, This
);
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%08lx)\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%08lx)\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
*pformatectIn
,
256 FORMATETC
*pformatetcOut
)
258 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
259 TRACE("(%p)->(%p,%p)\n", This
, pformatectIn
, pformatetcOut
);
262 memcpy(pformatetcOut
, pformatectIn
, sizeof(FORMATETC
));
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)->(%ld)\n", This
, dwDirection
);
282 if(dwDirection
!= DATADIR_GET
) {
283 FIXME("Unsupported direction: %ld\n", dwDirection
);
284 /* WinXP riched20 also returns E_NOTIMPL in this case */
287 return EnumFormatImpl_Create(This
->fmtetc
, This
->fmtetc_cnt
, ppenumFormatEtc
);
290 static HRESULT WINAPI
DataObjectImpl_DAdvise(IDataObject
* iface
, FORMATETC
*pformatetc
, DWORD advf
,
291 IAdviseSink
*pAdvSink
, DWORD
*pdwConnection
)
293 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
294 FIXME("(%p): stub\n", This
);
298 static HRESULT WINAPI
DataObjectImpl_DUnadvise(IDataObject
* iface
, DWORD dwConnection
)
300 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
301 FIXME("(%p): stub\n", This
);
305 static HRESULT WINAPI
DataObjectImpl_EnumDAdvise(IDataObject
* iface
, IEnumSTATDATA
**ppenumAdvise
)
307 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
308 FIXME("(%p): stub\n", This
);
312 static const IDataObjectVtbl VT_DataObjectImpl
=
314 DataObjectImpl_QueryInterface
,
315 DataObjectImpl_AddRef
,
316 DataObjectImpl_Release
,
317 DataObjectImpl_GetData
,
318 DataObjectImpl_GetDataHere
,
319 DataObjectImpl_QueryGetData
,
320 DataObjectImpl_GetCanonicalFormatEtc
,
321 DataObjectImpl_SetData
,
322 DataObjectImpl_EnumFormatEtc
,
323 DataObjectImpl_DAdvise
,
324 DataObjectImpl_DUnadvise
,
325 DataObjectImpl_EnumDAdvise
328 static HGLOBAL
get_unicode_text(ME_TextEditor
*editor
, CHARRANGE
*lpchrg
)
334 pars
= ME_CountParagraphsBetween(editor
, lpchrg
->cpMin
, lpchrg
->cpMax
);
335 len
= lpchrg
->cpMax
-lpchrg
->cpMin
;
336 ret
= GlobalAlloc(GMEM_MOVEABLE
, sizeof(WCHAR
)*(len
+pars
+1));
337 data
= (WCHAR
*)GlobalLock(ret
);
338 ME_GetTextW(editor
, data
, lpchrg
->cpMin
, len
, TRUE
);
343 typedef struct tagME_GlobalDestStruct
347 } ME_GlobalDestStruct
;
349 static DWORD CALLBACK
ME_AppendToHGLOBAL(DWORD_PTR dwCookie
, LPBYTE lpBuff
, LONG cb
, LONG
*pcb
)
351 ME_GlobalDestStruct
*pData
= (ME_GlobalDestStruct
*)dwCookie
;
355 nMaxSize
= GlobalSize(pData
->hData
);
356 if (pData
->nLength
+cb
+1 >= cb
) {
357 /* round up to 2^17 */
358 int nNewSize
= (((nMaxSize
+cb
+1)|0x1FFFF)+1) & 0xFFFE0000;
359 pData
->hData
= GlobalReAlloc(pData
->hData
, nNewSize
, 0);
361 pDest
= (BYTE
*)GlobalLock(pData
->hData
);
362 memcpy(pDest
+ pData
->nLength
, lpBuff
, cb
);
363 pData
->nLength
+= cb
;
364 pDest
[pData
->nLength
] = '\0';
365 GlobalUnlock(pData
->hData
);
371 static HGLOBAL
get_rtf_text(ME_TextEditor
*editor
, CHARRANGE
*lpchrg
)
374 ME_GlobalDestStruct gds
;
376 gds
.hData
= GlobalAlloc(GMEM_MOVEABLE
, 0);
378 es
.dwCookie
= (DWORD_PTR
)&gds
;
379 es
.pfnCallback
= ME_AppendToHGLOBAL
;
380 ME_StreamOutRange(editor
, SF_RTF
, lpchrg
->cpMin
, lpchrg
->cpMax
, &es
);
381 GlobalReAlloc(gds
.hData
, gds
.nLength
+1, 0);
385 HRESULT
ME_GetDataObject(ME_TextEditor
*editor
, CHARRANGE
*lpchrg
, LPDATAOBJECT
*lplpdataobj
)
388 TRACE("(%p,%ld,%ld)\n", editor
, lpchrg
->cpMin
, lpchrg
->cpMax
);
390 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl
));
392 cfRTF
= RegisterClipboardFormatA("Rich Text Format");
394 obj
->lpVtbl
= &VT_DataObjectImpl
;
396 obj
->unicode
= get_unicode_text(editor
, lpchrg
);
400 if(editor
->mode
& TM_RICHTEXT
)
402 obj
->fmtetc
= HeapAlloc(GetProcessHeap(), 0, obj
->fmtetc_cnt
*sizeof(FORMATETC
));
403 InitFormatEtc(obj
->fmtetc
[0], CF_UNICODETEXT
, TYMED_HGLOBAL
);
404 if(editor
->mode
& TM_RICHTEXT
) {
405 obj
->rtf
= get_rtf_text(editor
, lpchrg
);
406 InitFormatEtc(obj
->fmtetc
[1], cfRTF
, TYMED_HGLOBAL
);
409 *lplpdataobj
= (LPDATAOBJECT
)obj
;