Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenclipboard.c
Go to the documentation of this file.
00001 /* 00002 * OLE 2 clipboard support 00003 * 00004 * Copyright 1999 Noel Borthwick <noel@macadamian.com> 00005 * Copyright 2000 Abey George <abey@macadamian.com> 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 * 00021 * NOTES: 00022 * This file contains the implementation for the OLE Clipboard and its 00023 * internal interfaces. The OLE clipboard interacts with an IDataObject 00024 * interface via the OleSetClipboard, OleGetClipboard and 00025 * OleIsCurrentClipboard API's. An internal IDataObject delegates 00026 * to a client supplied IDataObject or the WIN32 clipboard API depending 00027 * on whether OleSetClipboard has been invoked. 00028 * Here are some operating scenarios: 00029 * 00030 * 1. OleSetClipboard called: In this case the internal IDataObject 00031 * delegates to the client supplied IDataObject. Additionally OLE takes 00032 * ownership of the Windows clipboard and any HGLOCBAL IDataObject 00033 * items are placed on the Windows clipboard. This allows non OLE aware 00034 * applications to access these. A local WinProc fields WM_RENDERFORMAT 00035 * and WM_RENDERALLFORMATS messages in this case. 00036 * 00037 * 2. OleGetClipboard called without previous OleSetClipboard. Here the internal 00038 * IDataObject functionality wraps around the WIN32 clipboard API. 00039 * 00040 * 3. OleGetClipboard called after previous OleSetClipboard. Here the internal 00041 * IDataObject delegates to the source IDataObjects functionality directly, 00042 * thereby bypassing the Windows clipboard. 00043 * 00044 * Implementation references : Inside OLE 2'nd edition by Kraig Brockschmidt 00045 * 00046 * TODO: 00047 * - Support for pasting between different processes. OLE clipboard support 00048 * currently works only for in process copy and paste. Since we internally 00049 * store a pointer to the source's IDataObject and delegate to that, this 00050 * will fail if the IDataObject client belongs to a different process. 00051 * - IDataObject::GetDataHere is not implemented 00052 * - OleFlushClipboard needs to additionally handle TYMED_IStorage media 00053 * by copying the storage into global memory. Subsequently the default 00054 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL 00055 * back to TYMED_IStorage. 00056 * - OLE1 compatibility formats to be synthesized from OLE2 formats and put on 00057 * clipboard in OleSetClipboard. 00058 * 00059 */ 00060 00061 #include <assert.h> 00062 #include <stdarg.h> 00063 #include <string.h> 00064 #include <stdio.h> 00065 00066 #define COBJMACROS 00067 #define NONAMELESSUNION 00068 #define NONAMELESSSTRUCT 00069 00070 #include "windef.h" 00071 #include "winbase.h" 00072 #include "wingdi.h" 00073 #include "winuser.h" 00074 #include "winerror.h" 00075 #include "winnls.h" 00076 #include "ole2.h" 00077 #include "wine/debug.h" 00078 #include "olestd.h" 00079 00080 #include "storage32.h" 00081 00082 #include "compobj_private.h" 00083 00084 WINE_DEFAULT_DEBUG_CHANNEL(ole); 00085 00086 #define HANDLE_ERROR(err) do { hr = err; TRACE("(HRESULT=%x)\n", (HRESULT)err); goto CLEANUP; } while (0) 00087 00088 /* Structure of 'Ole Private Data' clipboard format */ 00089 typedef struct 00090 { 00091 FORMATETC fmtetc; 00092 DWORD first_use; /* Has this cf been added to the list already */ 00093 DWORD unk[2]; 00094 } ole_priv_data_entry; 00095 00096 typedef struct 00097 { 00098 DWORD unk1; 00099 DWORD size; /* in bytes of the entire structure */ 00100 DWORD unk2; 00101 DWORD count; /* no. of format entries */ 00102 DWORD unk3[2]; 00103 ole_priv_data_entry entries[1]; /* array of size count */ 00104 /* then follows any DVTARGETDEVICE structures referenced in the FORMATETCs */ 00105 } ole_priv_data; 00106 00107 /***************************************************************************** 00108 * td_offs_to_ptr 00109 * 00110 * Returns a ptr to a target device at a given offset from the 00111 * start of the ole_priv_data. 00112 * 00113 * Used when unpacking ole private data from the clipboard. 00114 */ 00115 static inline DVTARGETDEVICE *td_offs_to_ptr(ole_priv_data *data, DWORD_PTR off) 00116 { 00117 if(off == 0) return NULL; 00118 return (DVTARGETDEVICE*)((char*)data + off); 00119 } 00120 00121 /***************************************************************************** 00122 * td_get_offs 00123 * 00124 * Get the offset from the start of the ole_priv_data of the idx'th 00125 * target device. 00126 * 00127 * Used when packing ole private data to the clipboard. 00128 */ 00129 static inline DWORD_PTR td_get_offs(ole_priv_data *data, DWORD idx) 00130 { 00131 if(data->entries[idx].fmtetc.ptd == NULL) return 0; 00132 return (char*)data->entries[idx].fmtetc.ptd - (char*)data; 00133 } 00134 00135 /**************************************************************************** 00136 * Consumer snapshot. Represents the state of the ole clipboard 00137 * returned by OleGetClipboard(). 00138 */ 00139 typedef struct snapshot 00140 { 00141 IDataObject IDataObject_iface; 00142 LONG ref; 00143 00144 DWORD seq_no; /* Clipboard sequence number corresponding to this snapshot */ 00145 00146 IDataObject *data; /* If we unmarshal a remote data object we hold a ref here */ 00147 } snapshot; 00148 00149 /**************************************************************************** 00150 * ole_clipbrd 00151 */ 00152 typedef struct ole_clipbrd 00153 { 00154 snapshot *latest_snapshot; /* Latest consumer snapshot */ 00155 00156 HWND window; /* Hidden clipboard window */ 00157 IDataObject *src_data; /* Source object passed to OleSetClipboard */ 00158 ole_priv_data *cached_enum; /* Cached result from the enumeration of src data object */ 00159 IStream *marshal_data; /* Stream onto which to marshal src_data */ 00160 } ole_clipbrd; 00161 00162 static inline snapshot *impl_from_IDataObject(IDataObject *iface) 00163 { 00164 return CONTAINING_RECORD(iface, snapshot, IDataObject_iface); 00165 } 00166 00167 typedef struct PresentationDataHeader 00168 { 00169 BYTE unknown1[28]; 00170 DWORD dwObjectExtentX; 00171 DWORD dwObjectExtentY; 00172 DWORD dwSize; 00173 } PresentationDataHeader; 00174 00175 /* 00176 * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize() 00177 */ 00178 static ole_clipbrd* theOleClipboard; 00179 00180 static inline HRESULT get_ole_clipbrd(ole_clipbrd **clipbrd) 00181 { 00182 struct oletls *info = COM_CurrentInfo(); 00183 *clipbrd = NULL; 00184 00185 if(!info->ole_inits) 00186 return CO_E_NOTINITIALIZED; 00187 *clipbrd = theOleClipboard; 00188 00189 return S_OK; 00190 } 00191 00192 /* 00193 * Name of our registered OLE clipboard window class 00194 */ 00195 static const WCHAR clipbrd_wndclass[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0}; 00196 00197 static const WCHAR wine_marshal_dataobject[] = {'W','i','n','e',' ','m','a','r','s','h','a','l',' ','d','a','t','a','o','b','j','e','c','t',0}; 00198 00199 UINT ownerlink_clipboard_format = 0; 00200 UINT filename_clipboard_format = 0; 00201 UINT filenameW_clipboard_format = 0; 00202 UINT dataobject_clipboard_format = 0; 00203 UINT embedded_object_clipboard_format = 0; 00204 UINT embed_source_clipboard_format = 0; 00205 UINT custom_link_source_clipboard_format = 0; 00206 UINT link_source_clipboard_format = 0; 00207 UINT object_descriptor_clipboard_format = 0; 00208 UINT link_source_descriptor_clipboard_format = 0; 00209 UINT ole_private_data_clipboard_format = 0; 00210 00211 static UINT wine_marshal_clipboard_format; 00212 00213 static inline char *dump_fmtetc(FORMATETC *fmt) 00214 { 00215 static char buf[100]; 00216 00217 snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x", 00218 fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed); 00219 return buf; 00220 } 00221 00222 /*---------------------------------------------------------------------* 00223 * Implementation of the internal IEnumFORMATETC interface returned by 00224 * the OLE clipboard's IDataObject. 00225 *---------------------------------------------------------------------*/ 00226 00227 typedef struct enum_fmtetc 00228 { 00229 IEnumFORMATETC IEnumFORMATETC_iface; 00230 LONG ref; 00231 00232 UINT pos; /* current enumerator position */ 00233 ole_priv_data *data; 00234 } enum_fmtetc; 00235 00236 static inline enum_fmtetc *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface) 00237 { 00238 return CONTAINING_RECORD(iface, enum_fmtetc, IEnumFORMATETC_iface); 00239 } 00240 00241 /************************************************************************ 00242 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown) 00243 * 00244 * See Windows documentation for more details on IUnknown methods. 00245 */ 00246 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface 00247 (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj) 00248 { 00249 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface); 00250 00251 TRACE("(%p)->(IID: %s, %p)\n", This, debugstr_guid(riid), ppvObj); 00252 00253 *ppvObj = NULL; 00254 00255 if(IsEqualIID(riid, &IID_IUnknown) || 00256 IsEqualIID(riid, &IID_IEnumFORMATETC)) 00257 { 00258 *ppvObj = iface; 00259 } 00260 00261 if(*ppvObj) 00262 { 00263 IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj); 00264 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj); 00265 return S_OK; 00266 } 00267 00268 TRACE("-- Interface: E_NOINTERFACE\n"); 00269 return E_NOINTERFACE; 00270 } 00271 00272 /************************************************************************ 00273 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown) 00274 * 00275 */ 00276 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface) 00277 { 00278 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface); 00279 TRACE("(%p)->(count=%u)\n",This, This->ref); 00280 00281 return InterlockedIncrement(&This->ref); 00282 } 00283 00284 /************************************************************************ 00285 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown) 00286 * 00287 * See Windows documentation for more details on IUnknown methods. 00288 */ 00289 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface) 00290 { 00291 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface); 00292 ULONG ref; 00293 00294 TRACE("(%p)->(count=%u)\n",This, This->ref); 00295 00296 ref = InterlockedDecrement(&This->ref); 00297 if (!ref) 00298 { 00299 TRACE("() - destroying IEnumFORMATETC(%p)\n",This); 00300 HeapFree(GetProcessHeap(), 0, This->data); 00301 HeapFree(GetProcessHeap(), 0, This); 00302 } 00303 return ref; 00304 } 00305 00306 /************************************************************************ 00307 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC) 00308 * 00309 * Standard enumerator members for IEnumFORMATETC 00310 */ 00311 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next 00312 (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed) 00313 { 00314 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface); 00315 UINT cfetch, i; 00316 HRESULT hres = S_FALSE; 00317 00318 TRACE("(%p)->(pos=%u)\n", This, This->pos); 00319 00320 if (This->pos < This->data->count) 00321 { 00322 cfetch = This->data->count - This->pos; 00323 if (cfetch >= celt) 00324 { 00325 cfetch = celt; 00326 hres = S_OK; 00327 } 00328 00329 for(i = 0; i < cfetch; i++) 00330 { 00331 rgelt[i] = This->data->entries[This->pos++].fmtetc; 00332 if(rgelt[i].ptd) 00333 { 00334 DVTARGETDEVICE *target = rgelt[i].ptd; 00335 rgelt[i].ptd = CoTaskMemAlloc(target->tdSize); 00336 if(!rgelt[i].ptd) return E_OUTOFMEMORY; 00337 memcpy(rgelt[i].ptd, target, target->tdSize); 00338 } 00339 } 00340 } 00341 else 00342 { 00343 cfetch = 0; 00344 } 00345 00346 if (pceltFethed) 00347 { 00348 *pceltFethed = cfetch; 00349 } 00350 00351 return hres; 00352 } 00353 00354 /************************************************************************ 00355 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC) 00356 * 00357 * Standard enumerator members for IEnumFORMATETC 00358 */ 00359 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt) 00360 { 00361 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface); 00362 TRACE("(%p)->(num=%u)\n", This, celt); 00363 00364 This->pos += celt; 00365 if (This->pos > This->data->count) 00366 { 00367 This->pos = This->data->count; 00368 return S_FALSE; 00369 } 00370 return S_OK; 00371 } 00372 00373 /************************************************************************ 00374 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC) 00375 * 00376 * Standard enumerator members for IEnumFORMATETC 00377 */ 00378 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface) 00379 { 00380 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface); 00381 TRACE("(%p)->()\n", This); 00382 00383 This->pos = 0; 00384 return S_OK; 00385 } 00386 00387 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj); 00388 00389 /************************************************************************ 00390 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC) 00391 * 00392 * Standard enumerator members for IEnumFORMATETC 00393 */ 00394 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone 00395 (LPENUMFORMATETC iface, LPENUMFORMATETC* obj) 00396 { 00397 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface); 00398 ole_priv_data *new_data; 00399 DWORD i; 00400 00401 TRACE("(%p)->(%p)\n", This, obj); 00402 00403 if ( !obj ) return E_INVALIDARG; 00404 *obj = NULL; 00405 00406 new_data = HeapAlloc(GetProcessHeap(), 0, This->data->size); 00407 if(!new_data) return E_OUTOFMEMORY; 00408 memcpy(new_data, This->data, This->data->size); 00409 00410 /* Fixup any target device ptrs */ 00411 for(i = 0; i < This->data->count; i++) 00412 new_data->entries[i].fmtetc.ptd = 00413 td_offs_to_ptr(new_data, td_get_offs(This->data, i)); 00414 00415 return enum_fmtetc_construct(new_data, This->pos, obj); 00416 } 00417 00418 static const IEnumFORMATETCVtbl efvt = 00419 { 00420 OLEClipbrd_IEnumFORMATETC_QueryInterface, 00421 OLEClipbrd_IEnumFORMATETC_AddRef, 00422 OLEClipbrd_IEnumFORMATETC_Release, 00423 OLEClipbrd_IEnumFORMATETC_Next, 00424 OLEClipbrd_IEnumFORMATETC_Skip, 00425 OLEClipbrd_IEnumFORMATETC_Reset, 00426 OLEClipbrd_IEnumFORMATETC_Clone 00427 }; 00428 00429 /************************************************************************ 00430 * enum_fmtetc_construct 00431 * 00432 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns. 00433 */ 00434 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj) 00435 { 00436 enum_fmtetc* ef; 00437 00438 *obj = NULL; 00439 ef = HeapAlloc(GetProcessHeap(), 0, sizeof(*ef)); 00440 if (!ef) return E_OUTOFMEMORY; 00441 00442 ef->ref = 1; 00443 ef->IEnumFORMATETC_iface.lpVtbl = &efvt; 00444 ef->data = data; 00445 ef->pos = pos; 00446 00447 TRACE("(%p)->()\n", ef); 00448 *obj = &ef->IEnumFORMATETC_iface; 00449 return S_OK; 00450 } 00451 00452 /*********************************************************************** 00453 * dup_global_mem 00454 * 00455 * Helper method to duplicate an HGLOBAL chunk of memory 00456 */ 00457 static HRESULT dup_global_mem( HGLOBAL src, DWORD flags, HGLOBAL *dst ) 00458 { 00459 void *src_ptr, *dst_ptr; 00460 DWORD size; 00461 00462 *dst = NULL; 00463 if ( !src ) return S_FALSE; 00464 00465 size = GlobalSize(src); 00466 00467 *dst = GlobalAlloc( flags, size ); 00468 if ( !*dst ) return E_OUTOFMEMORY; 00469 00470 src_ptr = GlobalLock(src); 00471 dst_ptr = GlobalLock(*dst); 00472 00473 memcpy(dst_ptr, src_ptr, size); 00474 00475 GlobalUnlock(*dst); 00476 GlobalUnlock(src); 00477 00478 return S_OK; 00479 } 00480 00481 /*********************************************************************** 00482 * dup_metafilepict 00483 * 00484 * Helper function to duplicate a handle to a METAFILEPICT, and the 00485 * contained HMETAFILE. 00486 */ 00487 static HRESULT dup_metafilepict(HGLOBAL src, HGLOBAL *pdest) 00488 { 00489 HRESULT hr; 00490 HGLOBAL dest; 00491 METAFILEPICT *dest_ptr; 00492 00493 *pdest = NULL; 00494 00495 /* Copy the METAFILEPICT structure. */ 00496 hr = dup_global_mem(src, GMEM_DDESHARE|GMEM_MOVEABLE, &dest); 00497 if (FAILED(hr)) return hr; 00498 00499 dest_ptr = GlobalLock(dest); 00500 if (!dest_ptr) return E_FAIL; 00501 00502 /* Give the new METAFILEPICT a separate HMETAFILE. */ 00503 dest_ptr->hMF = CopyMetaFileW(dest_ptr->hMF, NULL); 00504 if (dest_ptr->hMF) 00505 { 00506 GlobalUnlock(dest); 00507 *pdest = dest; 00508 return S_OK; 00509 } 00510 else 00511 { 00512 GlobalUnlock(dest); 00513 GlobalFree(dest); 00514 return E_FAIL; 00515 } 00516 } 00517 00518 /*********************************************************************** 00519 * free_metafilepict 00520 * 00521 * Helper function to GlobalFree a handle to a METAFILEPICT, and also 00522 * free the contained HMETAFILE. 00523 */ 00524 static void free_metafilepict(HGLOBAL src) 00525 { 00526 METAFILEPICT *src_ptr; 00527 00528 src_ptr = GlobalLock(src); 00529 if (src_ptr) 00530 { 00531 DeleteMetaFile(src_ptr->hMF); 00532 GlobalUnlock(src); 00533 } 00534 GlobalFree(src); 00535 } 00536 00537 /*********************************************************************** 00538 * dup_bitmap 00539 * 00540 * Helper function to duplicate an HBITMAP. 00541 */ 00542 static HRESULT dup_bitmap(HBITMAP src, HBITMAP *pdest) 00543 { 00544 HDC src_dc; 00545 HGDIOBJ orig_src_bitmap; 00546 BITMAP bm; 00547 HBITMAP dest; 00548 00549 src_dc = CreateCompatibleDC(NULL); 00550 orig_src_bitmap = SelectObject(src_dc, src); 00551 GetObjectW(src, sizeof bm, &bm); 00552 dest = CreateCompatibleBitmap(src_dc, bm.bmWidth, bm.bmHeight); 00553 if (dest) 00554 { 00555 HDC dest_dc = CreateCompatibleDC(NULL); 00556 HGDIOBJ orig_dest_bitmap = SelectObject(dest_dc, dest); 00557 BitBlt(dest_dc, 0, 0, bm.bmWidth, bm.bmHeight, src_dc, 0, 0, SRCCOPY); 00558 SelectObject(dest_dc, orig_dest_bitmap); 00559 DeleteDC(dest_dc); 00560 } 00561 SelectObject(src_dc, orig_src_bitmap); 00562 DeleteDC(src_dc); 00563 *pdest = dest; 00564 return dest ? S_OK : E_FAIL; 00565 } 00566 00567 /************************************************************ 00568 * render_embed_source_hack 00569 * 00570 * This is clearly a hack and has no place in the clipboard code. 00571 * 00572 */ 00573 static HRESULT render_embed_source_hack(IDataObject *data, LPFORMATETC fmt) 00574 { 00575 STGMEDIUM std; 00576 HGLOBAL hStorage = 0; 00577 HRESULT hr = S_OK; 00578 ILockBytes *ptrILockBytes; 00579 00580 memset(&std, 0, sizeof(STGMEDIUM)); 00581 std.tymed = fmt->tymed = TYMED_ISTORAGE; 00582 00583 hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0); 00584 if (hStorage == NULL) return E_OUTOFMEMORY; 00585 hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes); 00586 hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg); 00587 ILockBytes_Release(ptrILockBytes); 00588 00589 if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->src_data, fmt, &std))) 00590 { 00591 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr); 00592 GlobalFree(hStorage); 00593 return hr; 00594 } 00595 00596 if (1) /* check whether the presentation data is already -not- present */ 00597 { 00598 FORMATETC fmt2; 00599 STGMEDIUM std2; 00600 METAFILEPICT *mfp = 0; 00601 00602 fmt2.cfFormat = CF_METAFILEPICT; 00603 fmt2.ptd = 0; 00604 fmt2.dwAspect = DVASPECT_CONTENT; 00605 fmt2.lindex = -1; 00606 fmt2.tymed = TYMED_MFPICT; 00607 00608 memset(&std2, 0, sizeof(STGMEDIUM)); 00609 std2.tymed = TYMED_MFPICT; 00610 00611 /* Get the metafile picture out of it */ 00612 00613 if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->src_data, &fmt2, &std2))) 00614 { 00615 mfp = GlobalLock(std2.u.hGlobal); 00616 } 00617 00618 if (mfp) 00619 { 00620 OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0}; 00621 IStream *pStream = 0; 00622 void *mfBits; 00623 PresentationDataHeader pdh; 00624 INT nSize; 00625 CLSID clsID; 00626 LPOLESTR strProgID; 00627 CHAR strOleTypeName[51]; 00628 BYTE OlePresStreamHeader [] = 00629 { 00630 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 00631 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 00632 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 00633 0x00, 0x00, 0x00, 0x00 00634 }; 00635 00636 nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL); 00637 00638 memset(&pdh, 0, sizeof(PresentationDataHeader)); 00639 memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader)); 00640 00641 pdh.dwObjectExtentX = mfp->xExt; 00642 pdh.dwObjectExtentY = mfp->yExt; 00643 pdh.dwSize = nSize; 00644 00645 hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream); 00646 00647 hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL); 00648 00649 mfBits = HeapAlloc(GetProcessHeap(), 0, nSize); 00650 nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits); 00651 00652 hr = IStream_Write(pStream, mfBits, nSize, NULL); 00653 00654 IStream_Release(pStream); 00655 00656 HeapFree(GetProcessHeap(), 0, mfBits); 00657 00658 GlobalUnlock(std2.u.hGlobal); 00659 ReleaseStgMedium(&std2); 00660 00661 ReadClassStg(std.u.pstg, &clsID); 00662 ProgIDFromCLSID(&clsID, &strProgID); 00663 00664 WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL ); 00665 OLECONVERT_CreateOleStream(std.u.pstg); 00666 OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName); 00667 } 00668 } 00669 00670 if ( !SetClipboardData( fmt->cfFormat, hStorage ) ) 00671 { 00672 WARN("() : Failed to set rendered clipboard data into clipboard!\n"); 00673 GlobalFree(hStorage); 00674 hr = CLIPBRD_E_CANT_SET; 00675 } 00676 00677 ReleaseStgMedium(&std); 00678 return hr; 00679 } 00680 00681 /************************************************************************ 00682 * find_format_in_list 00683 * 00684 * Returns the first entry that matches the provided clipboard format. 00685 */ 00686 static inline ole_priv_data_entry *find_format_in_list(ole_priv_data_entry *entries, DWORD num, UINT cf) 00687 { 00688 DWORD i; 00689 for(i = 0; i < num; i++) 00690 if(entries[i].fmtetc.cfFormat == cf) 00691 return &entries[i]; 00692 00693 return NULL; 00694 } 00695 00696 /*************************************************************************** 00697 * get_data_from_storage 00698 * 00699 * Returns storage data in an HGLOBAL. 00700 */ 00701 static HRESULT get_data_from_storage(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem) 00702 { 00703 HGLOBAL h; 00704 IStorage *stg; 00705 HRESULT hr; 00706 FORMATETC stg_fmt; 00707 STGMEDIUM med; 00708 ILockBytes *lbs; 00709 00710 *mem = NULL; 00711 00712 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 ); 00713 if(!h) return E_OUTOFMEMORY; 00714 00715 hr = CreateILockBytesOnHGlobal(h, FALSE, &lbs); 00716 if(SUCCEEDED(hr)) 00717 { 00718 hr = StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stg); 00719 ILockBytes_Release(lbs); 00720 } 00721 if(FAILED(hr)) 00722 { 00723 GlobalFree(h); 00724 return hr; 00725 } 00726 00727 stg_fmt = *fmt; 00728 med.tymed = stg_fmt.tymed = TYMED_ISTORAGE; 00729 med.u.pstg = stg; 00730 med.pUnkForRelease = NULL; 00731 00732 hr = IDataObject_GetDataHere(data, &stg_fmt, &med); 00733 if(FAILED(hr)) 00734 { 00735 med.u.pstg = NULL; 00736 hr = IDataObject_GetData(data, &stg_fmt, &med); 00737 if(FAILED(hr)) goto end; 00738 00739 hr = IStorage_CopyTo(med.u.pstg, 0, NULL, NULL, stg); 00740 ReleaseStgMedium(&med); 00741 if(FAILED(hr)) goto end; 00742 } 00743 *mem = h; 00744 00745 end: 00746 IStorage_Release(stg); 00747 if(FAILED(hr)) GlobalFree(h); 00748 return hr; 00749 } 00750 00751 /*************************************************************************** 00752 * get_data_from_stream 00753 * 00754 * Returns stream data in an HGLOBAL. 00755 */ 00756 static HRESULT get_data_from_stream(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem) 00757 { 00758 HGLOBAL h; 00759 IStream *stm = NULL; 00760 HRESULT hr; 00761 FORMATETC stm_fmt; 00762 STGMEDIUM med; 00763 00764 *mem = NULL; 00765 00766 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 ); 00767 if(!h) return E_OUTOFMEMORY; 00768 00769 hr = CreateStreamOnHGlobal(h, FALSE, &stm); 00770 if(FAILED(hr)) goto error; 00771 00772 stm_fmt = *fmt; 00773 med.tymed = stm_fmt.tymed = TYMED_ISTREAM; 00774 med.u.pstm = stm; 00775 med.pUnkForRelease = NULL; 00776 00777 hr = IDataObject_GetDataHere(data, &stm_fmt, &med); 00778 if(FAILED(hr)) 00779 { 00780 LARGE_INTEGER offs; 00781 ULARGE_INTEGER pos; 00782 00783 med.u.pstm = NULL; 00784 hr = IDataObject_GetData(data, &stm_fmt, &med); 00785 if(FAILED(hr)) goto error; 00786 00787 offs.QuadPart = 0; 00788 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_CUR, &pos); 00789 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_SET, NULL); 00790 hr = IStream_CopyTo(med.u.pstm, stm, pos, NULL, NULL); 00791 ReleaseStgMedium(&med); 00792 if(FAILED(hr)) goto error; 00793 } 00794 *mem = h; 00795 IStream_Release(stm); 00796 return S_OK; 00797 00798 error: 00799 if(stm) IStream_Release(stm); 00800 GlobalFree(h); 00801 return hr; 00802 } 00803 00804 /*************************************************************************** 00805 * get_data_from_global 00806 * 00807 * Returns global data in an HGLOBAL. 00808 */ 00809 static HRESULT get_data_from_global(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem) 00810 { 00811 HGLOBAL h; 00812 HRESULT hr; 00813 FORMATETC mem_fmt; 00814 STGMEDIUM med; 00815 00816 *mem = NULL; 00817 00818 mem_fmt = *fmt; 00819 mem_fmt.tymed = TYMED_HGLOBAL; 00820 00821 hr = IDataObject_GetData(data, &mem_fmt, &med); 00822 if(FAILED(hr)) return hr; 00823 00824 hr = dup_global_mem(med.u.hGlobal, GMEM_DDESHARE|GMEM_MOVEABLE, &h); 00825 00826 if(SUCCEEDED(hr)) *mem = h; 00827 00828 ReleaseStgMedium(&med); 00829 00830 return hr; 00831 } 00832 00833 /*************************************************************************** 00834 * get_data_from_enhmetafile 00835 */ 00836 static HRESULT get_data_from_enhmetafile(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem) 00837 { 00838 HENHMETAFILE copy; 00839 HRESULT hr; 00840 FORMATETC mem_fmt; 00841 STGMEDIUM med; 00842 00843 *mem = NULL; 00844 00845 mem_fmt = *fmt; 00846 mem_fmt.tymed = TYMED_ENHMF; 00847 00848 hr = IDataObject_GetData(data, &mem_fmt, &med); 00849 if(FAILED(hr)) return hr; 00850 00851 copy = CopyEnhMetaFileW(med.u.hEnhMetaFile, NULL); 00852 if(copy) *mem = (HGLOBAL)copy; 00853 else hr = E_FAIL; 00854 00855 ReleaseStgMedium(&med); 00856 00857 return hr; 00858 } 00859 00860 /*************************************************************************** 00861 * get_data_from_metafilepict 00862 */ 00863 static HRESULT get_data_from_metafilepict(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem) 00864 { 00865 HGLOBAL copy; 00866 HRESULT hr; 00867 FORMATETC mem_fmt; 00868 STGMEDIUM med; 00869 00870 *mem = NULL; 00871 00872 mem_fmt = *fmt; 00873 mem_fmt.tymed = TYMED_MFPICT; 00874 00875 hr = IDataObject_GetData(data, &mem_fmt, &med); 00876 if(FAILED(hr)) return hr; 00877 00878 hr = dup_metafilepict(med.u.hMetaFilePict, ©); 00879 00880 if(SUCCEEDED(hr)) *mem = copy; 00881 00882 ReleaseStgMedium(&med); 00883 00884 return hr; 00885 } 00886 00887 /*************************************************************************** 00888 * get_data_from_bitmap 00889 * 00890 * Returns bitmap in an HBITMAP. 00891 */ 00892 static HRESULT get_data_from_bitmap(IDataObject *data, FORMATETC *fmt, HBITMAP *hbm) 00893 { 00894 HBITMAP copy; 00895 HRESULT hr; 00896 FORMATETC mem_fmt; 00897 STGMEDIUM med; 00898 00899 *hbm = NULL; 00900 00901 mem_fmt = *fmt; 00902 mem_fmt.tymed = TYMED_GDI; 00903 00904 hr = IDataObject_GetData(data, &mem_fmt, &med); 00905 if(FAILED(hr)) return hr; 00906 00907 hr = dup_bitmap(med.u.hBitmap, ©); 00908 00909 if(SUCCEEDED(hr)) *hbm = copy; 00910 00911 ReleaseStgMedium(&med); 00912 00913 return hr; 00914 } 00915 00916 /*********************************************************************** 00917 * render_format 00918 * 00919 * Render the clipboard data. Note that this call will delegate to the 00920 * source data object. 00921 */ 00922 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt) 00923 { 00924 HANDLE clip_data = NULL; /* HGLOBAL unless otherwise specified */ 00925 HRESULT hr; 00926 00927 /* Embed source hack */ 00928 if(fmt->cfFormat == embed_source_clipboard_format) 00929 { 00930 return render_embed_source_hack(data, fmt); 00931 } 00932 00933 if(fmt->tymed & TYMED_ISTORAGE) 00934 { 00935 hr = get_data_from_storage(data, fmt, &clip_data); 00936 } 00937 else if(fmt->tymed & TYMED_ISTREAM) 00938 { 00939 hr = get_data_from_stream(data, fmt, &clip_data); 00940 } 00941 else if(fmt->tymed & TYMED_HGLOBAL) 00942 { 00943 hr = get_data_from_global(data, fmt, &clip_data); 00944 } 00945 else if(fmt->tymed & TYMED_ENHMF) 00946 { 00947 hr = get_data_from_enhmetafile(data, fmt, &clip_data); 00948 } 00949 else if(fmt->tymed & TYMED_MFPICT) 00950 { 00951 /* Returns global handle to METAFILEPICT, containing a copied HMETAFILE */ 00952 hr = get_data_from_metafilepict(data, fmt, &clip_data); 00953 } 00954 else if(fmt->tymed & TYMED_GDI) 00955 { 00956 /* Returns HBITMAP not HGLOBAL */ 00957 hr = get_data_from_bitmap(data, fmt, (HBITMAP *)&clip_data); 00958 } 00959 else 00960 { 00961 FIXME("Unhandled tymed %x\n", fmt->tymed); 00962 hr = DV_E_FORMATETC; 00963 } 00964 00965 if(SUCCEEDED(hr)) 00966 { 00967 if ( !SetClipboardData(fmt->cfFormat, clip_data) ) 00968 { 00969 WARN("() : Failed to set rendered clipboard data into clipboard!\n"); 00970 if(fmt->tymed & TYMED_MFPICT) 00971 free_metafilepict(clip_data); 00972 else if(fmt->tymed & TYMED_GDI) 00973 DeleteObject(clip_data); 00974 else 00975 GlobalFree(clip_data); 00976 hr = CLIPBRD_E_CANT_SET; 00977 } 00978 } 00979 00980 return hr; 00981 } 00982 00983 /*---------------------------------------------------------------------* 00984 * Implementation of the internal IDataObject interface exposed by 00985 * the OLE clipboard. 00986 *---------------------------------------------------------------------*/ 00987 00988 00989 /************************************************************************ 00990 * snapshot_QueryInterface 00991 */ 00992 static HRESULT WINAPI snapshot_QueryInterface(IDataObject *iface, 00993 REFIID riid, void **ppvObject) 00994 { 00995 snapshot *This = impl_from_IDataObject(iface); 00996 TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject); 00997 00998 if ( (This==0) || (ppvObject==0) ) 00999 return E_INVALIDARG; 01000 01001 *ppvObject = 0; 01002 01003 if (IsEqualIID(&IID_IUnknown, riid) || 01004 IsEqualIID(&IID_IDataObject, riid)) 01005 { 01006 *ppvObject = iface; 01007 } 01008 else 01009 { 01010 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid)); 01011 return E_NOINTERFACE; 01012 } 01013 01014 IUnknown_AddRef((IUnknown*)*ppvObject); 01015 01016 return S_OK; 01017 } 01018 01019 /************************************************************************ 01020 * snapshot_AddRef 01021 */ 01022 static ULONG WINAPI snapshot_AddRef(IDataObject *iface) 01023 { 01024 snapshot *This = impl_from_IDataObject(iface); 01025 01026 TRACE("(%p)->(count=%u)\n", This, This->ref); 01027 01028 return InterlockedIncrement(&This->ref); 01029 } 01030 01031 /************************************************************************ 01032 * snapshot_Release 01033 */ 01034 static ULONG WINAPI snapshot_Release(IDataObject *iface) 01035 { 01036 snapshot *This = impl_from_IDataObject(iface); 01037 ULONG ref; 01038 01039 TRACE("(%p)->(count=%u)\n", This, This->ref); 01040 01041 ref = InterlockedDecrement(&This->ref); 01042 01043 if (ref == 0) 01044 { 01045 ole_clipbrd *clipbrd; 01046 HRESULT hr = get_ole_clipbrd(&clipbrd); 01047 01048 if(This->data) IDataObject_Release(This->data); 01049 01050 if(SUCCEEDED(hr) && clipbrd->latest_snapshot == This) 01051 clipbrd->latest_snapshot = NULL; 01052 HeapFree(GetProcessHeap(), 0, This); 01053 } 01054 01055 return ref; 01056 } 01057 01058 /************************************************************ 01059 * get_current_ole_clip_window 01060 * 01061 * Return the window that owns the ole clipboard. 01062 * 01063 * If the clipboard is flushed or not owned by ole this will 01064 * return NULL. 01065 */ 01066 static HWND get_current_ole_clip_window(void) 01067 { 01068 HGLOBAL h; 01069 HWND *ptr, wnd; 01070 01071 h = GetClipboardData(dataobject_clipboard_format); 01072 if(!h) return NULL; 01073 ptr = GlobalLock(h); 01074 if(!ptr) return NULL; 01075 wnd = *ptr; 01076 GlobalUnlock(h); 01077 return wnd; 01078 } 01079 01080 /************************************************************ 01081 * get_current_dataobject 01082 * 01083 * Return an unmarshalled IDataObject if there is a current 01084 * (ie non-flushed) object on the ole clipboard. 01085 */ 01086 static HRESULT get_current_dataobject(IDataObject **data) 01087 { 01088 HRESULT hr = S_FALSE; 01089 HWND wnd = get_current_ole_clip_window(); 01090 HGLOBAL h; 01091 void *ptr; 01092 IStream *stm; 01093 LARGE_INTEGER pos; 01094 01095 *data = NULL; 01096 if(!wnd) return S_FALSE; 01097 01098 h = GetClipboardData(wine_marshal_clipboard_format); 01099 if(!h) return S_FALSE; 01100 if(GlobalSize(h) == 0) return S_FALSE; 01101 ptr = GlobalLock(h); 01102 if(!ptr) return S_FALSE; 01103 01104 hr = CreateStreamOnHGlobal(NULL, TRUE, &stm); 01105 if(FAILED(hr)) goto end; 01106 01107 hr = IStream_Write(stm, ptr, GlobalSize(h), NULL); 01108 if(SUCCEEDED(hr)) 01109 { 01110 pos.QuadPart = 0; 01111 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL); 01112 hr = CoUnmarshalInterface(stm, &IID_IDataObject, (void**)data); 01113 } 01114 IStream_Release(stm); 01115 01116 end: 01117 GlobalUnlock(h); 01118 return hr; 01119 } 01120 01121 static DWORD get_tymed_from_nonole_cf(UINT cf) 01122 { 01123 if(cf >= 0xc000) return TYMED_ISTREAM | TYMED_HGLOBAL; 01124 01125 switch(cf) 01126 { 01127 case CF_TEXT: 01128 case CF_OEMTEXT: 01129 case CF_UNICODETEXT: 01130 return TYMED_ISTREAM | TYMED_HGLOBAL; 01131 case CF_ENHMETAFILE: 01132 return TYMED_ENHMF; 01133 case CF_METAFILEPICT: 01134 return TYMED_MFPICT; 01135 default: 01136 FIXME("returning TYMED_NULL for cf %04x\n", cf); 01137 return TYMED_NULL; 01138 } 01139 } 01140 01141 /*********************************************************** 01142 * get_priv_data 01143 * 01144 * Returns a copy of the Ole Private Data 01145 */ 01146 static HRESULT get_priv_data(ole_priv_data **data) 01147 { 01148 HGLOBAL handle; 01149 HRESULT hr = S_OK; 01150 ole_priv_data *ret = NULL; 01151 01152 *data = NULL; 01153 01154 handle = GetClipboardData( ole_private_data_clipboard_format ); 01155 if(handle) 01156 { 01157 ole_priv_data *src = GlobalLock(handle); 01158 if(src) 01159 { 01160 DWORD i; 01161 01162 /* FIXME: sanity check on size */ 01163 ret = HeapAlloc(GetProcessHeap(), 0, src->size); 01164 if(!ret) 01165 { 01166 GlobalUnlock(handle); 01167 return E_OUTOFMEMORY; 01168 } 01169 memcpy(ret, src, src->size); 01170 GlobalUnlock(handle); 01171 01172 /* Fixup any target device offsets to ptrs */ 01173 for(i = 0; i < ret->count; i++) 01174 ret->entries[i].fmtetc.ptd = 01175 td_offs_to_ptr(ret, (DWORD_PTR) ret->entries[i].fmtetc.ptd); 01176 } 01177 } 01178 01179 if(!ret) /* Non-ole data */ 01180 { 01181 UINT cf; 01182 DWORD count = 0, idx, size = FIELD_OFFSET(ole_priv_data, entries); 01183 01184 for(cf = 0; (cf = EnumClipboardFormats(cf)) != 0; count++) 01185 { 01186 char buf[100]; 01187 GetClipboardFormatNameA(cf, buf, sizeof(buf)); 01188 TRACE("cf %04x %s\n", cf, buf); 01189 } 01190 TRACE("count %d\n", count); 01191 size += count * sizeof(ret->entries[0]); 01192 01193 /* There are holes in fmtetc so zero init */ 01194 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); 01195 if(!ret) return E_OUTOFMEMORY; 01196 ret->size = size; 01197 ret->count = count; 01198 01199 for(cf = 0, idx = 0; (cf = EnumClipboardFormats(cf)) != 0; idx++) 01200 { 01201 ret->entries[idx].fmtetc.cfFormat = cf; 01202 ret->entries[idx].fmtetc.ptd = NULL; 01203 ret->entries[idx].fmtetc.dwAspect = DVASPECT_CONTENT; 01204 ret->entries[idx].fmtetc.lindex = -1; 01205 ret->entries[idx].fmtetc.tymed = get_tymed_from_nonole_cf(cf); 01206 ret->entries[idx].first_use = 1; 01207 } 01208 } 01209 01210 *data = ret; 01211 return hr; 01212 } 01213 01214 /************************************************************************ 01215 * get_stgmed_for_global 01216 * 01217 * Returns a stg medium with a copy of the global handle 01218 */ 01219 static HRESULT get_stgmed_for_global(HGLOBAL h, STGMEDIUM *med) 01220 { 01221 HRESULT hr; 01222 01223 med->pUnkForRelease = NULL; 01224 med->tymed = TYMED_NULL; 01225 01226 hr = dup_global_mem(h, GMEM_MOVEABLE, &med->u.hGlobal); 01227 01228 if(SUCCEEDED(hr)) med->tymed = TYMED_HGLOBAL; 01229 01230 return hr; 01231 } 01232 01233 /************************************************************************ 01234 * get_stgmed_for_stream 01235 * 01236 * Returns a stg medium with a stream based on the handle 01237 */ 01238 static HRESULT get_stgmed_for_stream(HGLOBAL h, STGMEDIUM *med) 01239 { 01240 HRESULT hr; 01241 HGLOBAL dst; 01242 01243 med->pUnkForRelease = NULL; 01244 med->tymed = TYMED_NULL; 01245 01246 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst); 01247 if(FAILED(hr)) return hr; 01248 01249 hr = CreateStreamOnHGlobal(dst, TRUE, &med->u.pstm); 01250 if(FAILED(hr)) 01251 { 01252 GlobalFree(dst); 01253 return hr; 01254 } 01255 01256 med->tymed = TYMED_ISTREAM; 01257 return hr; 01258 } 01259 01260 /************************************************************************ 01261 * get_stgmed_for_storage 01262 * 01263 * Returns a stg medium with a storage based on the handle 01264 */ 01265 static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med) 01266 { 01267 HRESULT hr; 01268 HGLOBAL dst; 01269 ILockBytes *lbs; 01270 01271 med->pUnkForRelease = NULL; 01272 med->tymed = TYMED_NULL; 01273 01274 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst); 01275 if(FAILED(hr)) return hr; 01276 01277 hr = CreateILockBytesOnHGlobal(dst, TRUE, &lbs); 01278 if(FAILED(hr)) 01279 { 01280 GlobalFree(dst); 01281 return hr; 01282 } 01283 01284 hr = StgOpenStorageOnILockBytes(lbs, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &med->u.pstg); 01285 ILockBytes_Release(lbs); 01286 if(FAILED(hr)) 01287 { 01288 GlobalFree(dst); 01289 return hr; 01290 } 01291 01292 med->tymed = TYMED_ISTORAGE; 01293 return hr; 01294 } 01295 01296 /************************************************************************ 01297 * get_stgmed_for_emf 01298 * 01299 * Returns a stg medium with an enhanced metafile based on the handle 01300 */ 01301 static HRESULT get_stgmed_for_emf(HENHMETAFILE hemf, STGMEDIUM *med) 01302 { 01303 med->pUnkForRelease = NULL; 01304 med->tymed = TYMED_NULL; 01305 01306 med->u.hEnhMetaFile = CopyEnhMetaFileW(hemf, NULL); 01307 if(!med->u.hEnhMetaFile) return E_OUTOFMEMORY; 01308 med->tymed = TYMED_ENHMF; 01309 return S_OK; 01310 } 01311 01312 static inline BOOL string_off_equal(const DVTARGETDEVICE *t1, WORD off1, const DVTARGETDEVICE *t2, WORD off2) 01313 { 01314 const WCHAR *str1, *str2; 01315 01316 if(off1 == 0 && off2 == 0) return TRUE; 01317 if(off1 == 0 || off2 == 0) return FALSE; 01318 01319 str1 = (const WCHAR*)((const char*)t1 + off1); 01320 str2 = (const WCHAR*)((const char*)t2 + off2); 01321 01322 return !lstrcmpW(str1, str2); 01323 } 01324 01325 static inline BOOL td_equal(const DVTARGETDEVICE *t1, const DVTARGETDEVICE *t2) 01326 { 01327 if(t1 == NULL && t2 == NULL) return TRUE; 01328 if(t1 == NULL || t2 == NULL) return FALSE; 01329 01330 if(!string_off_equal(t1, t1->tdDriverNameOffset, t2, t2->tdDriverNameOffset)) 01331 return FALSE; 01332 if(!string_off_equal(t1, t1->tdDeviceNameOffset, t2, t2->tdDeviceNameOffset)) 01333 return FALSE; 01334 if(!string_off_equal(t1, t1->tdPortNameOffset, t2, t2->tdPortNameOffset)) 01335 return FALSE; 01336 01337 /* FIXME check devmode? */ 01338 01339 return TRUE; 01340 } 01341 01342 /************************************************************************ 01343 * snapshot_GetData 01344 */ 01345 static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt, 01346 STGMEDIUM *med) 01347 { 01348 snapshot *This = impl_from_IDataObject(iface); 01349 HANDLE h; 01350 HRESULT hr; 01351 ole_priv_data *enum_data = NULL; 01352 ole_priv_data_entry *entry; 01353 DWORD mask; 01354 01355 TRACE("(%p, %p {%s}, %p)\n", iface, fmt, dump_fmtetc(fmt), med); 01356 01357 if ( !fmt || !med ) return E_INVALIDARG; 01358 01359 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN; 01360 01361 if(!This->data) 01362 hr = get_current_dataobject(&This->data); 01363 01364 if(This->data) 01365 { 01366 hr = IDataObject_GetData(This->data, fmt, med); 01367 CloseClipboard(); 01368 return hr; 01369 } 01370 01371 h = GetClipboardData(fmt->cfFormat); 01372 if(!h) 01373 { 01374 hr = DV_E_FORMATETC; 01375 goto end; 01376 } 01377 01378 hr = get_priv_data(&enum_data); 01379 if(FAILED(hr)) goto end; 01380 01381 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat); 01382 if(entry) 01383 { 01384 if(!td_equal(fmt->ptd, entry->fmtetc.ptd)) 01385 { 01386 hr = DV_E_FORMATETC; 01387 goto end; 01388 } 01389 mask = fmt->tymed & entry->fmtetc.tymed; 01390 if(!mask) mask = fmt->tymed & (TYMED_ISTREAM | TYMED_HGLOBAL); 01391 } 01392 else /* non-Ole format */ 01393 mask = fmt->tymed & TYMED_HGLOBAL; 01394 01395 if(mask & TYMED_ISTORAGE) 01396 hr = get_stgmed_for_storage(h, med); 01397 else if(mask & TYMED_HGLOBAL) 01398 hr = get_stgmed_for_global(h, med); 01399 else if(mask & TYMED_ISTREAM) 01400 hr = get_stgmed_for_stream(h, med); 01401 else if(mask & TYMED_ENHMF) 01402 hr = get_stgmed_for_emf((HENHMETAFILE)h, med); 01403 else 01404 { 01405 FIXME("Unhandled tymed - mask %x req tymed %x\n", mask, fmt->tymed); 01406 hr = E_FAIL; 01407 goto end; 01408 } 01409 01410 end: 01411 HeapFree(GetProcessHeap(), 0, enum_data); 01412 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE; 01413 return hr; 01414 } 01415 01416 /************************************************************************ 01417 * snapshot_GetDataHere 01418 */ 01419 static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt, 01420 STGMEDIUM *med) 01421 { 01422 snapshot *This = impl_from_IDataObject(iface); 01423 HANDLE h; 01424 HRESULT hr; 01425 ole_priv_data *enum_data = NULL; 01426 ole_priv_data_entry *entry; 01427 TYMED supported; 01428 01429 if ( !fmt || !med ) return E_INVALIDARG; 01430 01431 TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface, fmt, dump_fmtetc(fmt), med, med->tymed); 01432 01433 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN; 01434 01435 if(!This->data) 01436 hr = get_current_dataobject(&This->data); 01437 01438 if(This->data) 01439 { 01440 hr = IDataObject_GetDataHere(This->data, fmt, med); 01441 if(SUCCEEDED(hr)) 01442 { 01443 CloseClipboard(); 01444 return hr; 01445 } 01446 } 01447 01448 h = GetClipboardData(fmt->cfFormat); 01449 if(!h) 01450 { 01451 hr = DV_E_FORMATETC; 01452 goto end; 01453 } 01454 01455 hr = get_priv_data(&enum_data); 01456 if(FAILED(hr)) goto end; 01457 01458 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat); 01459 if(entry) 01460 { 01461 if(!td_equal(fmt->ptd, entry->fmtetc.ptd)) 01462 { 01463 hr = DV_E_FORMATETC; 01464 goto end; 01465 } 01466 supported = entry->fmtetc.tymed; 01467 } 01468 else /* non-Ole format */ 01469 supported = TYMED_HGLOBAL; 01470 01471 switch(med->tymed) 01472 { 01473 case TYMED_HGLOBAL: 01474 { 01475 DWORD src_size = GlobalSize(h); 01476 DWORD dst_size = GlobalSize(med->u.hGlobal); 01477 hr = E_FAIL; 01478 if(dst_size >= src_size) 01479 { 01480 void *src = GlobalLock(h); 01481 void *dst = GlobalLock(med->u.hGlobal); 01482 01483 memcpy(dst, src, src_size); 01484 GlobalUnlock(med->u.hGlobal); 01485 GlobalUnlock(h); 01486 hr = S_OK; 01487 } 01488 break; 01489 } 01490 case TYMED_ISTREAM: 01491 { 01492 DWORD src_size = GlobalSize(h); 01493 void *src = GlobalLock(h); 01494 hr = IStream_Write(med->u.pstm, src, src_size, NULL); 01495 GlobalUnlock(h); 01496 break; 01497 } 01498 case TYMED_ISTORAGE: 01499 { 01500 STGMEDIUM copy; 01501 if(!(supported & TYMED_ISTORAGE)) 01502 { 01503 hr = E_FAIL; 01504 goto end; 01505 } 01506 hr = get_stgmed_for_storage(h, ©); 01507 if(SUCCEEDED(hr)) 01508 { 01509 hr = IStorage_CopyTo(copy.u.pstg, 0, NULL, NULL, med->u.pstg); 01510 ReleaseStgMedium(©); 01511 } 01512 break; 01513 } 01514 default: 01515 FIXME("Unhandled tymed - supported %x req tymed %x\n", supported, med->tymed); 01516 hr = E_FAIL; 01517 goto end; 01518 } 01519 01520 end: 01521 HeapFree(GetProcessHeap(), 0, enum_data); 01522 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE; 01523 return hr; 01524 } 01525 01526 /************************************************************************ 01527 * snapshot_QueryGetData 01528 * 01529 * The OLE Clipboard's implementation of this method delegates to 01530 * a data source if there is one or wraps around the windows clipboard 01531 * function IsClipboardFormatAvailable() otherwise. 01532 * 01533 */ 01534 static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt) 01535 { 01536 FIXME("(%p, %p {%s})\n", iface, fmt, dump_fmtetc(fmt)); 01537 01538 if (!fmt) return E_INVALIDARG; 01539 01540 if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC; 01541 01542 if ( fmt->lindex != -1 ) return DV_E_FORMATETC; 01543 01544 return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT; 01545 } 01546 01547 /************************************************************************ 01548 * snapshot_GetCanonicalFormatEtc 01549 */ 01550 static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in, 01551 FORMATETC *fmt_out) 01552 { 01553 TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out); 01554 01555 if ( !fmt_in || !fmt_out ) return E_INVALIDARG; 01556 01557 *fmt_out = *fmt_in; 01558 return DATA_S_SAMEFORMATETC; 01559 } 01560 01561 /************************************************************************ 01562 * snapshot_SetData 01563 * 01564 * The OLE Clipboard does not implement this method 01565 */ 01566 static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt, 01567 STGMEDIUM *med, BOOL release) 01568 { 01569 TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release); 01570 return E_NOTIMPL; 01571 } 01572 01573 /************************************************************************ 01574 * snapshot_EnumFormatEtc 01575 * 01576 */ 01577 static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir, 01578 IEnumFORMATETC **enum_fmt) 01579 { 01580 HRESULT hr; 01581 ole_priv_data *data = NULL; 01582 01583 TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt); 01584 01585 *enum_fmt = NULL; 01586 01587 if ( dir != DATADIR_GET ) return E_NOTIMPL; 01588 if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN; 01589 01590 hr = get_priv_data(&data); 01591 01592 if(FAILED(hr)) goto end; 01593 01594 hr = enum_fmtetc_construct( data, 0, enum_fmt ); 01595 01596 end: 01597 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE; 01598 return hr; 01599 } 01600 01601 /************************************************************************ 01602 * snapshot_DAdvise 01603 * 01604 * The OLE Clipboard does not implement this method 01605 */ 01606 static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt, 01607 DWORD flags, IAdviseSink *sink, 01608 DWORD *conn) 01609 { 01610 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn); 01611 return E_NOTIMPL; 01612 } 01613 01614 /************************************************************************ 01615 * snapshot_DUnadvise 01616 * 01617 * The OLE Clipboard does not implement this method 01618 */ 01619 static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn) 01620 { 01621 TRACE("(%p, %d): not implemented\n", iface, conn); 01622 return E_NOTIMPL; 01623 } 01624 01625 /************************************************************************ 01626 * snapshot_EnumDAdvise 01627 * 01628 * The OLE Clipboard does not implement this method 01629 */ 01630 static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface, 01631 IEnumSTATDATA** enum_advise) 01632 { 01633 TRACE("(%p, %p): not implemented\n", iface, enum_advise); 01634 return E_NOTIMPL; 01635 } 01636 01637 static const IDataObjectVtbl snapshot_vtable = 01638 { 01639 snapshot_QueryInterface, 01640 snapshot_AddRef, 01641 snapshot_Release, 01642 snapshot_GetData, 01643 snapshot_GetDataHere, 01644 snapshot_QueryGetData, 01645 snapshot_GetCanonicalFormatEtc, 01646 snapshot_SetData, 01647 snapshot_EnumFormatEtc, 01648 snapshot_DAdvise, 01649 snapshot_DUnadvise, 01650 snapshot_EnumDAdvise 01651 }; 01652 01653 /*---------------------------------------------------------------------* 01654 * Internal implementation methods for the OLE clipboard 01655 *---------------------------------------------------------------------*/ 01656 01657 static snapshot *snapshot_construct(DWORD seq_no) 01658 { 01659 snapshot *This; 01660 01661 This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) ); 01662 if (!This) return NULL; 01663 01664 This->IDataObject_iface.lpVtbl = &snapshot_vtable; 01665 This->ref = 0; 01666 This->seq_no = seq_no; 01667 This->data = NULL; 01668 01669 return This; 01670 } 01671 01672 /********************************************************* 01673 * register_clipboard_formats 01674 */ 01675 static void register_clipboard_formats(void) 01676 { 01677 static const WCHAR OwnerLink[] = {'O','w','n','e','r','L','i','n','k',0}; 01678 static const WCHAR FileName[] = {'F','i','l','e','N','a','m','e',0}; 01679 static const WCHAR FileNameW[] = {'F','i','l','e','N','a','m','e','W',0}; 01680 static const WCHAR DataObject[] = {'D','a','t','a','O','b','j','e','c','t',0}; 01681 static const WCHAR EmbeddedObject[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0}; 01682 static const WCHAR EmbedSource[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0}; 01683 static const WCHAR CustomLinkSource[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0}; 01684 static const WCHAR LinkSource[] = {'L','i','n','k',' ','S','o','u','r','c','e',0}; 01685 static const WCHAR ObjectDescriptor[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0}; 01686 static const WCHAR LinkSourceDescriptor[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ', 01687 'D','e','s','c','r','i','p','t','o','r',0}; 01688 static const WCHAR OlePrivateData[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0}; 01689 01690 static const WCHAR WineMarshalledDataObject[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ', 01691 'D','a','t','a','O','b','j','e','c','t',0}; 01692 01693 ownerlink_clipboard_format = RegisterClipboardFormatW(OwnerLink); 01694 filename_clipboard_format = RegisterClipboardFormatW(FileName); 01695 filenameW_clipboard_format = RegisterClipboardFormatW(FileNameW); 01696 dataobject_clipboard_format = RegisterClipboardFormatW(DataObject); 01697 embedded_object_clipboard_format = RegisterClipboardFormatW(EmbeddedObject); 01698 embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSource); 01699 custom_link_source_clipboard_format = RegisterClipboardFormatW(CustomLinkSource); 01700 link_source_clipboard_format = RegisterClipboardFormatW(LinkSource); 01701 object_descriptor_clipboard_format = RegisterClipboardFormatW(ObjectDescriptor); 01702 link_source_descriptor_clipboard_format = RegisterClipboardFormatW(LinkSourceDescriptor); 01703 ole_private_data_clipboard_format = RegisterClipboardFormatW(OlePrivateData); 01704 01705 wine_marshal_clipboard_format = RegisterClipboardFormatW(WineMarshalledDataObject); 01706 } 01707 01708 /*********************************************************************** 01709 * OLEClipbrd_Initialize() 01710 * Initializes the OLE clipboard. 01711 */ 01712 void OLEClipbrd_Initialize(void) 01713 { 01714 register_clipboard_formats(); 01715 01716 if ( !theOleClipboard ) 01717 { 01718 ole_clipbrd* clipbrd; 01719 HGLOBAL h; 01720 01721 TRACE("()\n"); 01722 01723 clipbrd = HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd) ); 01724 if (!clipbrd) return; 01725 01726 clipbrd->latest_snapshot = NULL; 01727 clipbrd->window = NULL; 01728 clipbrd->src_data = NULL; 01729 clipbrd->cached_enum = NULL; 01730 01731 h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0); 01732 if(!h) 01733 { 01734 HeapFree(GetProcessHeap(), 0, clipbrd); 01735 return; 01736 } 01737 01738 if(FAILED(CreateStreamOnHGlobal(h, TRUE, &clipbrd->marshal_data))) 01739 { 01740 GlobalFree(h); 01741 HeapFree(GetProcessHeap(), 0, clipbrd); 01742 return; 01743 } 01744 01745 theOleClipboard = clipbrd; 01746 } 01747 } 01748 01749 /*********************************************************************** 01750 * OLEClipbrd_UnInitialize() 01751 * Un-Initializes the OLE clipboard 01752 */ 01753 void OLEClipbrd_UnInitialize(void) 01754 { 01755 ole_clipbrd *clipbrd = theOleClipboard; 01756 01757 TRACE("()\n"); 01758 01759 if ( clipbrd ) 01760 { 01761 static const WCHAR ole32W[] = {'o','l','e','3','2',0}; 01762 HINSTANCE hinst = GetModuleHandleW(ole32W); 01763 01764 if ( clipbrd->window ) 01765 { 01766 DestroyWindow(clipbrd->window); 01767 UnregisterClassW( clipbrd_wndclass, hinst ); 01768 } 01769 01770 IStream_Release(clipbrd->marshal_data); 01771 if (clipbrd->src_data) IDataObject_Release(clipbrd->src_data); 01772 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum); 01773 HeapFree(GetProcessHeap(), 0, clipbrd); 01774 theOleClipboard = NULL; 01775 } 01776 } 01777 01778 /********************************************************************* 01779 * set_clipboard_formats 01780 * 01781 * Enumerate all formats supported by the source and make 01782 * those formats available using delayed rendering using SetClipboardData. 01783 * Cache the enumeration list and make that list visibile as the 01784 * 'Ole Private Data' format on the clipboard. 01785 * 01786 */ 01787 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data) 01788 { 01789 HRESULT hr; 01790 FORMATETC fmt; 01791 IEnumFORMATETC *enum_fmt; 01792 HGLOBAL priv_data_handle; 01793 DWORD_PTR target_offset; 01794 ole_priv_data *priv_data; 01795 DWORD count = 0, needed = sizeof(*priv_data), idx; 01796 01797 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt); 01798 if(FAILED(hr)) return hr; 01799 01800 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK) 01801 { 01802 count++; 01803 needed += sizeof(priv_data->entries[0]); 01804 if(fmt.ptd) 01805 { 01806 needed += fmt.ptd->tdSize; 01807 CoTaskMemFree(fmt.ptd); 01808 } 01809 } 01810 01811 /* Windows pads the list with two empty ole_priv_data_entries, one 01812 * after the entries array and one after the target device data. 01813 * Allocating with zero init to zero these pads. */ 01814 01815 needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */ 01816 priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed); 01817 priv_data = GlobalLock(priv_data_handle); 01818 01819 priv_data->unk1 = 0; 01820 priv_data->size = needed; 01821 priv_data->unk2 = 1; 01822 priv_data->count = count; 01823 priv_data->unk3[0] = 0; 01824 priv_data->unk3[1] = 0; 01825 01826 IEnumFORMATETC_Reset(enum_fmt); 01827 01828 idx = 0; 01829 target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */ 01830 01831 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK) 01832 { 01833 TRACE("%s\n", dump_fmtetc(&fmt)); 01834 01835 priv_data->entries[idx].fmtetc = fmt; 01836 if(fmt.ptd) 01837 { 01838 memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize); 01839 priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset; 01840 target_offset += fmt.ptd->tdSize; 01841 CoTaskMemFree(fmt.ptd); 01842 } 01843 01844 priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat); 01845 priv_data->entries[idx].unk[0] = 0; 01846 priv_data->entries[idx].unk[1] = 0; 01847 01848 if (priv_data->entries[idx].first_use) 01849 SetClipboardData(fmt.cfFormat, NULL); 01850 01851 idx++; 01852 } 01853 01854 IEnumFORMATETC_Release(enum_fmt); 01855 01856 /* Cache the list and fixup any target device offsets to ptrs */ 01857 clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed); 01858 memcpy(clipbrd->cached_enum, priv_data, needed); 01859 for(idx = 0; idx < clipbrd->cached_enum->count; idx++) 01860 clipbrd->cached_enum->entries[idx].fmtetc.ptd = 01861 td_offs_to_ptr(clipbrd->cached_enum, (DWORD_PTR)clipbrd->cached_enum->entries[idx].fmtetc.ptd); 01862 01863 GlobalUnlock(priv_data_handle); 01864 if(!SetClipboardData(ole_private_data_clipboard_format, priv_data_handle)) 01865 { 01866 GlobalFree(priv_data_handle); 01867 return CLIPBRD_E_CANT_SET; 01868 } 01869 01870 return S_OK; 01871 } 01872 01873 static HWND create_clipbrd_window(void); 01874 01875 /*********************************************************************** 01876 * get_clipbrd_window 01877 */ 01878 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd) 01879 { 01880 if ( !clipbrd->window ) 01881 clipbrd->window = create_clipbrd_window(); 01882 01883 *wnd = clipbrd->window; 01884 return *wnd ? S_OK : E_FAIL; 01885 } 01886 01887 01888 /********************************************************************** 01889 * release_marshal_data 01890 * 01891 * Releases the data and sets the stream back to zero size. 01892 */ 01893 static inline void release_marshal_data(IStream *stm) 01894 { 01895 LARGE_INTEGER pos; 01896 ULARGE_INTEGER size; 01897 pos.QuadPart = size.QuadPart = 0; 01898 01899 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL); 01900 CoReleaseMarshalData(stm); 01901 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL); 01902 IStream_SetSize(stm, size); 01903 } 01904 01905 /*********************************************************************** 01906 * expose_marshalled_dataobject 01907 * 01908 * Sets the marshalled dataobject to the clipboard. In the flushed case 01909 * we set a zero sized HGLOBAL to clear the old marshalled data. 01910 */ 01911 static HRESULT expose_marshalled_dataobject(ole_clipbrd *clipbrd, IDataObject *data) 01912 { 01913 HGLOBAL h; 01914 01915 if(data) 01916 { 01917 HGLOBAL h_stm; 01918 GetHGlobalFromStream(clipbrd->marshal_data, &h_stm); 01919 dup_global_mem(h_stm, GMEM_DDESHARE|GMEM_MOVEABLE, &h); 01920 } 01921 else /* flushed */ 01922 h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 0); 01923 01924 if(!h) return E_OUTOFMEMORY; 01925 01926 if(!SetClipboardData(wine_marshal_clipboard_format, h)) 01927 { 01928 GlobalFree(h); 01929 return CLIPBRD_E_CANT_SET; 01930 } 01931 return S_OK; 01932 } 01933 01934 /*********************************************************************** 01935 * set_src_dataobject 01936 * 01937 * Clears and sets the clipboard's src IDataObject. 01938 * 01939 * To marshal the source dataobject we do something rather different from Windows. 01940 * We set a clipboard format which contains the marshalled data. 01941 * Windows sets two window props one of which is an IID, the other is an endpoint number. 01942 */ 01943 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data) 01944 { 01945 HRESULT hr; 01946 HWND wnd; 01947 01948 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr; 01949 01950 if(clipbrd->src_data) 01951 { 01952 release_marshal_data(clipbrd->marshal_data); 01953 01954 IDataObject_Release(clipbrd->src_data); 01955 clipbrd->src_data = NULL; 01956 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum); 01957 clipbrd->cached_enum = NULL; 01958 } 01959 01960 if(data) 01961 { 01962 IUnknown *unk; 01963 01964 IDataObject_AddRef(data); 01965 clipbrd->src_data = data; 01966 01967 IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk); 01968 hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk, 01969 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG); 01970 IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */ 01971 if(FAILED(hr)) return hr; 01972 hr = set_clipboard_formats(clipbrd, data); 01973 } 01974 return hr; 01975 } 01976 01977 /*********************************************************************** 01978 * clipbrd_wndproc 01979 */ 01980 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) 01981 { 01982 ole_clipbrd *clipbrd; 01983 01984 get_ole_clipbrd(&clipbrd); 01985 01986 switch (message) 01987 { 01988 case WM_RENDERFORMAT: 01989 { 01990 UINT cf = wparam; 01991 ole_priv_data_entry *entry; 01992 01993 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf); 01994 entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf); 01995 01996 if(entry) 01997 render_format(clipbrd->src_data, &entry->fmtetc); 01998 01999 break; 02000 } 02001 02002 case WM_RENDERALLFORMATS: 02003 { 02004 DWORD i; 02005 ole_priv_data_entry *entries = clipbrd->cached_enum->entries; 02006 02007 TRACE("(): WM_RENDERALLFORMATS\n"); 02008 02009 for(i = 0; i < clipbrd->cached_enum->count; i++) 02010 { 02011 if(entries[i].first_use) 02012 render_format(clipbrd->src_data, &entries[i].fmtetc); 02013 } 02014 break; 02015 } 02016 02017 case WM_DESTROYCLIPBOARD: 02018 { 02019 TRACE("(): WM_DESTROYCLIPBOARD\n"); 02020 02021 set_src_dataobject(clipbrd, NULL); 02022 break; 02023 } 02024 02025 default: 02026 return DefWindowProcW(hwnd, message, wparam, lparam); 02027 } 02028 02029 return 0; 02030 } 02031 02032 02033 /*********************************************************************** 02034 * create_clipbrd_window 02035 */ 02036 static HWND create_clipbrd_window(void) 02037 { 02038 WNDCLASSEXW class; 02039 static const WCHAR ole32W[] = {'o','l','e','3','2',0}; 02040 static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0}; 02041 HINSTANCE hinst = GetModuleHandleW(ole32W); 02042 02043 class.cbSize = sizeof(class); 02044 class.style = 0; 02045 class.lpfnWndProc = clipbrd_wndproc; 02046 class.cbClsExtra = 0; 02047 class.cbWndExtra = 0; 02048 class.hInstance = hinst; 02049 class.hIcon = 0; 02050 class.hCursor = 0; 02051 class.hbrBackground = 0; 02052 class.lpszMenuName = NULL; 02053 class.lpszClassName = clipbrd_wndclass; 02054 class.hIconSm = NULL; 02055 02056 RegisterClassExW(&class); 02057 02058 return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED, 02059 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 02060 NULL, NULL, hinst, 0); 02061 } 02062 02063 /********************************************************************* 02064 * set_dataobject_format 02065 * 02066 * Windows creates a 'DataObject' clipboard format that contains the 02067 * clipboard window's HWND or NULL if the Ole clipboard has been flushed. 02068 */ 02069 static HRESULT set_dataobject_format(HWND hwnd) 02070 { 02071 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd)); 02072 HWND *data; 02073 02074 if(!h) return E_OUTOFMEMORY; 02075 02076 data = GlobalLock(h); 02077 *data = hwnd; 02078 GlobalUnlock(h); 02079 02080 if(!SetClipboardData(dataobject_clipboard_format, h)) 02081 { 02082 GlobalFree(h); 02083 return CLIPBRD_E_CANT_SET; 02084 } 02085 02086 return S_OK; 02087 } 02088 02089 /*---------------------------------------------------------------------* 02090 * Win32 OLE clipboard API 02091 *---------------------------------------------------------------------*/ 02092 02093 /*********************************************************************** 02094 * OleSetClipboard [OLE32.@] 02095 * Places a pointer to the specified data object onto the clipboard, 02096 * making the data object accessible to the OleGetClipboard function. 02097 * 02098 * RETURNS 02099 * 02100 * S_OK IDataObject pointer placed on the clipboard 02101 * CLIPBRD_E_CANT_OPEN OpenClipboard failed 02102 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed 02103 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed 02104 * CLIPBRD_E_CANT_SET SetClipboard failed 02105 */ 02106 02107 HRESULT WINAPI OleSetClipboard(IDataObject* data) 02108 { 02109 HRESULT hr; 02110 ole_clipbrd *clipbrd; 02111 HWND wnd; 02112 02113 TRACE("(%p)\n", data); 02114 02115 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr; 02116 02117 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr; 02118 02119 if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN; 02120 02121 if ( !EmptyClipboard() ) 02122 { 02123 hr = CLIPBRD_E_CANT_EMPTY; 02124 goto end; 02125 } 02126 02127 hr = set_src_dataobject(clipbrd, data); 02128 if(FAILED(hr)) goto end; 02129 02130 if(data) 02131 { 02132 hr = expose_marshalled_dataobject(clipbrd, data); 02133 if(FAILED(hr)) goto end; 02134 hr = set_dataobject_format(wnd); 02135 } 02136 02137 end: 02138 02139 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE; 02140 02141 if ( FAILED(hr) ) 02142 { 02143 expose_marshalled_dataobject(clipbrd, NULL); 02144 set_src_dataobject(clipbrd, NULL); 02145 } 02146 02147 return hr; 02148 } 02149 02150 02151 /*********************************************************************** 02152 * OleGetClipboard [OLE32.@] 02153 * Returns a pointer to our internal IDataObject which represents the conceptual 02154 * state of the Windows clipboard. If the current clipboard already contains 02155 * an IDataObject, our internal IDataObject will delegate to this object. 02156 */ 02157 HRESULT WINAPI OleGetClipboard(IDataObject **obj) 02158 { 02159 HRESULT hr; 02160 ole_clipbrd *clipbrd; 02161 DWORD seq_no; 02162 02163 TRACE("(%p)\n", obj); 02164 02165 if(!obj) return E_INVALIDARG; 02166 02167 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr; 02168 02169 seq_no = GetClipboardSequenceNumber(); 02170 if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no) 02171 clipbrd->latest_snapshot = NULL; 02172 02173 if(!clipbrd->latest_snapshot) 02174 { 02175 clipbrd->latest_snapshot = snapshot_construct(seq_no); 02176 if(!clipbrd->latest_snapshot) return E_OUTOFMEMORY; 02177 } 02178 02179 *obj = &clipbrd->latest_snapshot->IDataObject_iface; 02180 IDataObject_AddRef(*obj); 02181 02182 return S_OK; 02183 } 02184 02185 /****************************************************************************** 02186 * OleFlushClipboard [OLE32.@] 02187 * Renders the data from the source IDataObject into the windows clipboard 02188 * 02189 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media 02190 * by copying the storage into global memory. Subsequently the default 02191 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL 02192 * back to TYMED_IStorage. 02193 */ 02194 HRESULT WINAPI OleFlushClipboard(void) 02195 { 02196 HRESULT hr; 02197 ole_clipbrd *clipbrd; 02198 HWND wnd; 02199 02200 TRACE("()\n"); 02201 02202 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr; 02203 02204 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr; 02205 02206 /* 02207 * Already flushed or no source DataObject? Nothing to do. 02208 */ 02209 if (!clipbrd->src_data) return S_OK; 02210 02211 if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN; 02212 02213 SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0); 02214 02215 hr = set_dataobject_format(NULL); 02216 02217 expose_marshalled_dataobject(clipbrd, NULL); 02218 set_src_dataobject(clipbrd, NULL); 02219 02220 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE; 02221 02222 return hr; 02223 } 02224 02225 02226 /*********************************************************************** 02227 * OleIsCurrentClipboard [OLE32.@] 02228 */ 02229 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data) 02230 { 02231 HRESULT hr; 02232 ole_clipbrd *clipbrd; 02233 TRACE("()\n"); 02234 02235 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr; 02236 02237 if (data == NULL) return S_FALSE; 02238 02239 return (data == clipbrd->src_data) ? S_OK : S_FALSE; 02240 } Generated on Sat May 26 2012 04:24:05 for ReactOS by
1.7.6.1
|