ole32: Implement cross-process drag and drop.
This commit is contained in:
parent
a2e1dd29dc
commit
6d1ef3a6a6
|
@ -116,6 +116,10 @@ static const WCHAR prop_olemenuW[] =
|
||||||
static const WCHAR prop_oledroptarget[] =
|
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};
|
{'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[] =
|
static const WCHAR clsidfmtW[] =
|
||||||
{'C','L','S','I','D','\\','{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-',
|
{'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',
|
'%','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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
/*************************************************************
|
||||||
* OLEDD_FindDropTarget()
|
* get_droptarget_handle
|
||||||
*
|
*
|
||||||
* Returns IDropTarget pointer registered for this window.
|
* 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 IDropTarget* OLEDD_FindDropTarget(HWND hwnd)
|
static inline HANDLE get_droptarget_handle(HWND hwnd)
|
||||||
{
|
{
|
||||||
return GetPropW(hwnd, prop_oledroptarget);
|
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
|
||||||
|
*
|
||||||
|
* Retrieves the marshalled IDropTarget from the window.
|
||||||
|
*/
|
||||||
|
static IDropTarget* get_droptarget_pointer(HWND hwnd)
|
||||||
|
{
|
||||||
|
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)
|
HRESULT WINAPI RegisterDragDrop(HWND hwnd, LPDROPTARGET pDropTarget)
|
||||||
{
|
{
|
||||||
DWORD pid = 0;
|
DWORD pid = 0;
|
||||||
|
HRESULT hr;
|
||||||
|
IStream *stream;
|
||||||
|
HANDLE map;
|
||||||
|
|
||||||
TRACE("(%p,%p)\n", hwnd, pDropTarget);
|
TRACE("(%p,%p)\n", hwnd, pDropTarget);
|
||||||
|
|
||||||
|
@ -309,13 +436,40 @@ HRESULT WINAPI RegisterDragDrop(HWND hwnd, LPDROPTARGET pDropTarget)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if the window is already registered */
|
/* check if the window is already registered */
|
||||||
if (OLEDD_FindDropTarget(hwnd))
|
if (is_droptarget(hwnd))
|
||||||
return DRAGDROP_E_ALREADYREGISTERED;
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
return S_OK;
|
hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
|
||||||
|
if(FAILED(hr)) return hr;
|
||||||
|
|
||||||
|
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)
|
HRESULT WINAPI RevokeDragDrop(HWND hwnd)
|
||||||
{
|
{
|
||||||
IDropTarget* droptarget;
|
HANDLE map;
|
||||||
|
IStream *stream;
|
||||||
|
IDropTarget *drop_target;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
TRACE("(%p)\n", hwnd);
|
TRACE("(%p)\n", hwnd);
|
||||||
|
|
||||||
|
@ -334,13 +491,24 @@ HRESULT WINAPI RevokeDragDrop(HWND hwnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* no registration data */
|
/* no registration data */
|
||||||
if (!(droptarget = OLEDD_FindDropTarget(hwnd)))
|
if (!(map = get_droptarget_handle(hwnd)))
|
||||||
return DRAGDROP_E_NOTREGISTERED;
|
return DRAGDROP_E_NOTREGISTERED;
|
||||||
|
|
||||||
IDropTarget_Release(droptarget);
|
drop_target = GetPropW(hwnd, prop_oledroptarget);
|
||||||
RemovePropW(hwnd, prop_oledroptarget);
|
if(drop_target) IDropTarget_Release(drop_target);
|
||||||
|
|
||||||
return S_OK;
|
RemovePropW(hwnd, prop_oledroptarget);
|
||||||
|
RemovePropW(hwnd, prop_marshalleddroptarget);
|
||||||
|
|
||||||
|
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
|
* Find-out if there is a drag target under the mouse
|
||||||
*/
|
*/
|
||||||
HWND next_target_wnd = hwndNewTarget;
|
HWND next_target_wnd = hwndNewTarget;
|
||||||
IDropTarget *new_target;
|
|
||||||
DWORD pid;
|
|
||||||
|
|
||||||
trackerInfo->curTargetHWND = hwndNewTarget;
|
trackerInfo->curTargetHWND = hwndNewTarget;
|
||||||
|
|
||||||
do {
|
while (next_target_wnd && !is_droptarget(next_target_wnd))
|
||||||
new_target = OLEDD_FindDropTarget(next_target_wnd);
|
next_target_wnd = GetParent(next_target_wnd);
|
||||||
} while (!new_target && (next_target_wnd = GetParent(next_target_wnd)));
|
|
||||||
|
|
||||||
if (next_target_wnd) hwndNewTarget = next_target_wnd;
|
if (next_target_wnd) hwndNewTarget = next_target_wnd;
|
||||||
|
|
||||||
GetWindowThreadProcessId(hwndNewTarget, &pid);
|
trackerInfo->curDragTargetHWND = hwndNewTarget;
|
||||||
if (pid != GetCurrentProcessId())
|
if(trackerInfo->curDragTarget) IDropTarget_Release(trackerInfo->curDragTarget);
|
||||||
{
|
trackerInfo->curDragTarget = get_droptarget_pointer(hwndNewTarget);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there is, notify it that we just dragged-in
|
* If there is, notify it that we just dragged-in
|
||||||
|
@ -2016,6 +2171,7 @@ static void OLEDD_TrackMouseMove(TrackerWindowInfo* trackerInfo)
|
||||||
{
|
{
|
||||||
trackerInfo->curDragTargetHWND = 0;
|
trackerInfo->curDragTargetHWND = 0;
|
||||||
trackerInfo->curTargetHWND = 0;
|
trackerInfo->curTargetHWND = 0;
|
||||||
|
IDropTarget_Release(trackerInfo->curDragTarget);
|
||||||
trackerInfo->curDragTarget = 0;
|
trackerInfo->curDragTarget = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2027,6 +2183,7 @@ static void OLEDD_TrackMouseMove(TrackerWindowInfo* trackerInfo)
|
||||||
*/
|
*/
|
||||||
trackerInfo->curDragTargetHWND = 0;
|
trackerInfo->curDragTargetHWND = 0;
|
||||||
trackerInfo->curTargetHWND = 0;
|
trackerInfo->curTargetHWND = 0;
|
||||||
|
if(trackerInfo->curDragTarget) IDropTarget_Release(trackerInfo->curDragTarget);
|
||||||
trackerInfo->curDragTarget = 0;
|
trackerInfo->curDragTarget = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue