mirror of
https://github.com/reactos/wine.git
synced 2024-11-29 06:30:37 +00:00
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[] =
|
||||
{'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
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
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.
|
||||
*/
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
RemovePropW(hwnd, prop_oledroptarget);
|
||||
drop_target = GetPropW(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
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user