[WIN32K]
[reactos.git] / dll / win32 / ole32 / ole2.c
index 41989f3..a9a4885 100644 (file)
@@ -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,10 @@ static inline IDropTarget* OLEDD_FindDropTarget(HWND hwnd)
 HRESULT WINAPI RegisterDragDrop(HWND hwnd, LPDROPTARGET pDropTarget)
 {
   DWORD pid = 0;
+  HRESULT hr;
+  IStream *stream;
+  HANDLE map;
+  IUnknown *unk;
 
   TRACE("(%p,%p)\n", hwnd, pDropTarget);
 
@@ -309,13 +437,48 @@ 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 = IDropTarget_QueryInterface(pDropTarget, &IID_IUnknown, (void**)&unk);
+  if(FAILED(hr))
+  {
+      IStream_Release(stream);
+      return hr;
+  }
+  hr = CoMarshalInterface(stream, &IID_IDropTarget, unk, MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
+  IUnknown_Release(unk);
+
+  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 +486,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 +500,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 +2152,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 +2180,7 @@ static void OLEDD_TrackMouseMove(TrackerWindowInfo* trackerInfo)
         {
           trackerInfo->curDragTargetHWND = 0;
           trackerInfo->curTargetHWND     = 0;
+          IDropTarget_Release(trackerInfo->curDragTarget);
           trackerInfo->curDragTarget     = 0;
         }
       }
@@ -2027,6 +2192,7 @@ static void OLEDD_TrackMouseMove(TrackerWindowInfo* trackerInfo)
        */
       trackerInfo->curDragTargetHWND = 0;
       trackerInfo->curTargetHWND     = 0;
+      if(trackerInfo->curDragTarget) IDropTarget_Release(trackerInfo->curDragTarget);
       trackerInfo->curDragTarget     = 0;
     }
   }