Huw Davies : ole32: Implement cross-process drag and drop.
Alexandre Julliard
julliard at winehq.org
Thu Jul 22 12:09:36 CDT 2010
Module: wine
Branch: master
Commit: 6d1ef3a6a64f0fabf05ce1bba5f0ec4373684786
URL: http://source.winehq.org/git/wine.git/?a=commit;h=6d1ef3a6a64f0fabf05ce1bba5f0ec4373684786
Author: Huw Davies <huw at codeweavers.com>
Date: Thu Jul 22 13:37:19 2010 +0100
ole32: Implement cross-process drag and drop.
---
dlls/ole32/ole2.c | 219 +++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 188 insertions(+), 31 deletions(-)
diff --git a/dlls/ole32/ole2.c b/dlls/ole32/ole2.c
index 41989f3..f570167 100644
--- a/dlls/ole32/ole2.c
+++ b/dlls/ole32/ole2.c
@@ -116,6 +116,10 @@ static const WCHAR prop_olemenuW[] =
static const WCHAR prop_oledroptarget[] =
{'O','l','e','D','r','o','p','T','a','r','g','e','t','I','n','t','e','r','f','a','c','e',0};
+/* property to store Marshalled IDropTarget pointer */
+static const WCHAR prop_marshalleddroptarget[] =
+ {'W','i','n','e','M','a','r','s','h','a','l','l','e','d','D','r','o','p','T','a','r','g','e','t',0};
+
static const WCHAR clsidfmtW[] =
{'C','L','S','I','D','\\','{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-',
'%','0','2','x','%','0','2','x','-','%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x',
@@ -266,14 +270,134 @@ HRESULT WINAPI OleInitializeWOW(DWORD x, DWORD y) {
return 0;
}
-/***
- * OLEDD_FindDropTarget()
+/*************************************************************
+ * get_droptarget_handle
+ *
+ * Retrieve a handle to the map containing the marshalled IDropTarget.
+ * This handle belongs to the process that called RegisterDragDrop.
+ * See get_droptarget_local_handle().
+ */
+static inline HANDLE get_droptarget_handle(HWND hwnd)
+{
+ return GetPropW(hwnd, prop_marshalleddroptarget);
+}
+
+/*************************************************************
+ * is_droptarget
+ *
+ * Is the window a droptarget.
+ */
+static inline BOOL is_droptarget(HWND hwnd)
+{
+ return get_droptarget_handle(hwnd) ? TRUE : FALSE;
+}
+
+/*************************************************************
+ * get_droptarget_local_handle
+ *
+ * Retrieve a handle to the map containing the marshalled IDropTarget.
+ * The handle should be closed when finished with.
+ */
+static HANDLE get_droptarget_local_handle(HWND hwnd)
+{
+ HANDLE handle, local_handle = 0;
+
+ handle = get_droptarget_handle(hwnd);
+
+ if(handle)
+ {
+ DWORD pid;
+ HANDLE process;
+
+ GetWindowThreadProcessId(hwnd, &pid);
+ process = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid);
+ if(process)
+ {
+ DuplicateHandle(process, handle, GetCurrentProcess(), &local_handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
+ CloseHandle(process);
+ }
+ }
+ return local_handle;
+}
+
+/***********************************************************************
+ * create_map_from_stream
+ *
+ * Helper for RegisterDragDrop. Creates a file mapping object
+ * with the contents of the provided stream. The stream must
+ * be a global memory backed stream.
+ */
+static HRESULT create_map_from_stream(IStream *stream, HANDLE *map)
+{
+ HGLOBAL hmem;
+ DWORD size;
+ HRESULT hr;
+ void *data;
+
+ hr = GetHGlobalFromStream(stream, &hmem);
+ if(FAILED(hr)) return hr;
+
+ size = GlobalSize(hmem);
+ *map = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, NULL);
+ if(!*map) return E_OUTOFMEMORY;
+
+ data = MapViewOfFile(*map, FILE_MAP_WRITE, 0, 0, size);
+ memcpy(data, GlobalLock(hmem), size);
+ GlobalUnlock(hmem);
+ UnmapViewOfFile(data);
+ return S_OK;
+}
+
+/***********************************************************************
+ * create_stream_from_map
+ *
+ * Creates a stream from the provided map.
+ */
+static HRESULT create_stream_from_map(HANDLE map, IStream **stream)
+{
+ HRESULT hr = E_OUTOFMEMORY;
+ HGLOBAL hmem;
+ void *data;
+ MEMORY_BASIC_INFORMATION info;
+
+ data = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
+ if(!data) return hr;
+
+ VirtualQuery(data, &info, sizeof(info));
+ TRACE("size %d\n", (int)info.RegionSize);
+
+ hmem = GlobalAlloc(GMEM_MOVEABLE, info.RegionSize);
+ if(hmem)
+ {
+ memcpy(GlobalLock(hmem), data, info.RegionSize);
+ GlobalUnlock(hmem);
+ hr = CreateStreamOnHGlobal(hmem, TRUE, stream);
+ }
+ UnmapViewOfFile(data);
+ return hr;
+}
+
+/***********************************************************************
+ * get_droptarget_pointer
*
- * Returns IDropTarget pointer registered for this window.
+ * Retrieves the marshalled IDropTarget from the window.
*/
-static inline IDropTarget* OLEDD_FindDropTarget(HWND hwnd)
+static IDropTarget* get_droptarget_pointer(HWND hwnd)
{
- return GetPropW(hwnd, prop_oledroptarget);
+ IDropTarget *droptarget = NULL;
+ HANDLE map;
+ IStream *stream;
+
+ map = get_droptarget_local_handle(hwnd);
+ if(!map) return NULL;
+
+ if(SUCCEEDED(create_stream_from_map(map, &stream)))
+ {
+ CoUnmarshalInterface(stream, &IID_IDropTarget, (void**)&droptarget);
+ IStream_Release(stream);
+ }
+ CloseHandle(map);
+ return droptarget;
}
/***********************************************************************
@@ -282,6 +406,9 @@ static inline IDropTarget* OLEDD_FindDropTarget(HWND hwnd)
HRESULT WINAPI RegisterDragDrop(HWND hwnd, LPDROPTARGET pDropTarget)
{
DWORD pid = 0;
+ HRESULT hr;
+ IStream *stream;
+ HANDLE map;
TRACE("(%p,%p)\n", hwnd, pDropTarget);
@@ -309,13 +436,40 @@ HRESULT WINAPI RegisterDragDrop(HWND hwnd, LPDROPTARGET pDropTarget)
}
/* check if the window is already registered */
- if (OLEDD_FindDropTarget(hwnd))
+ if (is_droptarget(hwnd))
return DRAGDROP_E_ALREADYREGISTERED;
- IDropTarget_AddRef(pDropTarget);
- SetPropW(hwnd, prop_oledroptarget, pDropTarget);
+ /*
+ * Marshal the drop target pointer into a shared memory map and
+ * store the map's handle in a Wine specific window prop. We also
+ * store the drop target pointer itself in the
+ * "OleDropTargetInterface" prop for compatibility with Windows.
+ */
+
+ hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
+ if(FAILED(hr)) return hr;
- return S_OK;
+ hr = CoMarshalInterface(stream, &IID_IDropTarget, (IUnknown*)pDropTarget, MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
+ if(SUCCEEDED(hr))
+ {
+ hr = create_map_from_stream(stream, &map);
+ if(SUCCEEDED(hr))
+ {
+ IDropTarget_AddRef(pDropTarget);
+ SetPropW(hwnd, prop_oledroptarget, pDropTarget);
+ SetPropW(hwnd, prop_marshalleddroptarget, map);
+ }
+ else
+ {
+ LARGE_INTEGER zero;
+ zero.QuadPart = 0;
+ IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
+ CoReleaseMarshalData(stream);
+ }
+ }
+ IStream_Release(stream);
+
+ return hr;
}
/***********************************************************************
@@ -323,7 +477,10 @@ HRESULT WINAPI RegisterDragDrop(HWND hwnd, LPDROPTARGET pDropTarget)
*/
HRESULT WINAPI RevokeDragDrop(HWND hwnd)
{
- IDropTarget* droptarget;
+ HANDLE map;
+ IStream *stream;
+ IDropTarget *drop_target;
+ HRESULT hr;
TRACE("(%p)\n", hwnd);
@@ -334,13 +491,24 @@ HRESULT WINAPI RevokeDragDrop(HWND hwnd)
}
/* no registration data */
- if (!(droptarget = OLEDD_FindDropTarget(hwnd)))
+ if (!(map = get_droptarget_handle(hwnd)))
return DRAGDROP_E_NOTREGISTERED;
- IDropTarget_Release(droptarget);
+ drop_target = GetPropW(hwnd, prop_oledroptarget);
+ if(drop_target) IDropTarget_Release(drop_target);
+
RemovePropW(hwnd, prop_oledroptarget);
+ RemovePropW(hwnd, prop_marshalleddroptarget);
- return S_OK;
+ hr = create_stream_from_map(map, &stream);
+ if(SUCCEEDED(hr))
+ {
+ CoReleaseMarshalData(stream);
+ IStream_Release(stream);
+ }
+ CloseHandle(map);
+
+ return hr;
}
/***********************************************************************
@@ -1975,30 +2143,17 @@ static void OLEDD_TrackMouseMove(TrackerWindowInfo* trackerInfo)
* Find-out if there is a drag target under the mouse
*/
HWND next_target_wnd = hwndNewTarget;
- IDropTarget *new_target;
- DWORD pid;
trackerInfo->curTargetHWND = hwndNewTarget;
- do {
- new_target = OLEDD_FindDropTarget(next_target_wnd);
- } while (!new_target && (next_target_wnd = GetParent(next_target_wnd)));
+ while (next_target_wnd && !is_droptarget(next_target_wnd))
+ next_target_wnd = GetParent(next_target_wnd);
if (next_target_wnd) hwndNewTarget = next_target_wnd;
- GetWindowThreadProcessId(hwndNewTarget, &pid);
- if (pid != GetCurrentProcessId())
- {
- FIXME("drop to another process window is unsupported\n");
- trackerInfo->curDragTargetHWND = 0;
- trackerInfo->curTargetHWND = 0;
- trackerInfo->curDragTarget = 0;
- }
- else
- {
- trackerInfo->curDragTargetHWND = hwndNewTarget;
- trackerInfo->curDragTarget = new_target;
- }
+ trackerInfo->curDragTargetHWND = hwndNewTarget;
+ if(trackerInfo->curDragTarget) IDropTarget_Release(trackerInfo->curDragTarget);
+ trackerInfo->curDragTarget = get_droptarget_pointer(hwndNewTarget);
/*
* If there is, notify it that we just dragged-in
@@ -2016,6 +2171,7 @@ static void OLEDD_TrackMouseMove(TrackerWindowInfo* trackerInfo)
{
trackerInfo->curDragTargetHWND = 0;
trackerInfo->curTargetHWND = 0;
+ IDropTarget_Release(trackerInfo->curDragTarget);
trackerInfo->curDragTarget = 0;
}
}
@@ -2027,6 +2183,7 @@ static void OLEDD_TrackMouseMove(TrackerWindowInfo* trackerInfo)
*/
trackerInfo->curDragTargetHWND = 0;
trackerInfo->curTargetHWND = 0;
+ if(trackerInfo->curDragTarget) IDropTarget_Release(trackerInfo->curDragTarget);
trackerInfo->curDragTarget = 0;
}
}
More information about the wine-cvs
mailing list