[3/2] ole32: store window to drop target mappings in wineserver [try 2]

Damjan Jovanovic damjan.jov at gmail.com
Sat Feb 6 04:07:19 CST 2010


Changelog:
* ole32: store window to drop target mappings in wineserver

Damjan Jovanovic
-------------- next part --------------
diff --git a/dlls/ole32/ole2.c b/dlls/ole32/ole2.c
index 6bf79fd..5c7c042 100644
--- a/dlls/ole32/ole2.c
+++ b/dlls/ole32/ole2.c
@@ -34,6 +34,8 @@
 #define NONAMELESSUNION
 #define NONAMELESSSTRUCT
 
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
 #include "windef.h"
 #include "winbase.h"
 #include "winerror.h"
@@ -57,12 +59,6 @@ WINE_DECLARE_DEBUG_CHANNEL(accel);
  * These are static/global variables and internal data structures that the
  * OLE module uses to maintain it's state.
  */
-typedef struct tagDropTargetNode
-{
-  HWND          hwndTarget;
-  IDropTarget*  dropTarget;
-  struct list   entry;
-} DropTargetNode;
 
 typedef struct tagTrackerWindowInfo
 {
@@ -112,11 +108,6 @@ static LONG OLE_moduleLockCount = 0;
  */
 static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32";
 
-/*
- * This is the head of the Drop target container.
- */
-static struct list targetListHead = LIST_INIT(targetListHead);
-
 /******************************************************************************
  * These are the prototypes of miscellaneous utility methods
  */
@@ -145,9 +136,8 @@ extern void OLEClipbrd_Initialize(void);
  * These are the prototypes of the utility methods used for OLE Drag n Drop
  */
 static void            OLEDD_Initialize(void);
-static DropTargetNode* OLEDD_FindDropTarget(
-                         HWND hwndOfTarget);
-static void            OLEDD_FreeDropTarget(DropTargetNode*, BOOL);
+static IDropTarget*    OLEDD_FindDropTarget(
+                         HWND hwndOfTarget, BOOL destroy);
 static LRESULT WINAPI  OLEDD_DragTrackerWindowProc(
 			 HWND   hwnd,
 			 UINT   uMsg,
@@ -277,7 +267,9 @@ HRESULT WINAPI RegisterDragDrop(
 	HWND hwnd,
 	LPDROPTARGET pDropTarget)
 {
-  DropTargetNode* dropTargetInfo;
+  HGLOBAL hGlobal;
+  HRESULT hr;
+  NTSTATUS wine_set_window_droptarget(HWND, char*, size_t);
 
   TRACE("(%p,%p)\n", hwnd, pDropTarget);
 
@@ -296,34 +288,53 @@ HRESULT WINAPI RegisterDragDrop(
     return DRAGDROP_E_INVALIDHWND;
   }
 
-  /*
-   * First, check if the window is already registered.
-   */
-  dropTargetInfo = OLEDD_FindDropTarget(hwnd);
-
-  if (dropTargetInfo!=NULL)
-    return DRAGDROP_E_ALREADYREGISTERED;
-
-  /*
-   * If it's not there, we can add it. We first create a node for it.
-   */
-  dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode));
-
-  if (dropTargetInfo==NULL)
-    return E_OUTOFMEMORY;
-
-  dropTargetInfo->hwndTarget     = hwnd;
-
-  /*
-   * Don't forget that this is an interface pointer, need to nail it down since
-   * we keep a copy of it.
-   */
-  IDropTarget_AddRef(pDropTarget);
-  dropTargetInfo->dropTarget  = pDropTarget;
+  hGlobal = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 0);
+  if (hGlobal)
+  {
+    IStream *stream;
+    hr = CreateStreamOnHGlobal(hGlobal, FALSE, &stream);
+    if (SUCCEEDED(hr))
+    {
+      DWORD size = 0;
+      BOOL succeeded = FALSE;
+      /* MSDN: "MSHLFLAGS_TABLESTRONG is used by the RegisterDragDrop function when registering a window as a drop target.
+       * This keeps the window registered as a drop target no matter how many times the end user drags across the window.
+       * The RevokeDragDrop function calls CoReleaseMarshalData."
+       */
+      hr = CoMarshalInterface(stream, &IID_IDropTarget, (IUnknown*)pDropTarget,
+        MSHCTX_NOSHAREDMEM, NULL, MSHLFLAGS_TABLESTRONG);
+      if (SUCCEEDED(hr))
+      {
+        LARGE_INTEGER offset;
+        ULARGE_INTEGER position;
+        offset.QuadPart = 0;
+        hr = IStream_Seek(stream, offset, STREAM_SEEK_CUR, &position);
+        if (SUCCEEDED(hr))
+        {
+          succeeded = TRUE;
+          size = (DWORD)position.QuadPart;
+        }
+      }
+      IStream_Release(stream);
 
-  list_add_tail(&targetListHead, &dropTargetInfo->entry);
+      if (succeeded)
+      {
+        NTSTATUS status;
+        void *marshalledDropTarget = GlobalLock(hGlobal);
+        status = wine_set_window_droptarget(hwnd, marshalledDropTarget, size);
+        GlobalUnlock(hGlobal);
+        if (status == STATUS_SUCCESS)
+          hr = S_OK;
+        else if (status == STATUS_OBJECT_NAME_COLLISION)
+          hr = DRAGDROP_E_ALREADYREGISTERED;
+      }
+    }
+    GlobalFree(hGlobal);
+  }
+  else
+    hr = E_OUTOFMEMORY;
 
-  return S_OK;
+  return hr;
 }
 
 /***********************************************************************
@@ -332,7 +343,9 @@ HRESULT WINAPI RegisterDragDrop(
 HRESULT WINAPI RevokeDragDrop(
 	HWND hwnd)
 {
-  DropTargetNode* dropTargetInfo;
+  NTSTATUS status;
+  HRESULT hr = E_FAIL;
+  NTSTATUS wine_set_window_droptarget(HWND, char*, size_t);
 
   TRACE("(%p)\n", hwnd);
 
@@ -342,20 +355,16 @@ HRESULT WINAPI RevokeDragDrop(
     return DRAGDROP_E_INVALIDHWND;
   }
 
-  /*
-   * First, check if the window is already registered.
-   */
-  dropTargetInfo = OLEDD_FindDropTarget(hwnd);
+  OLEDD_FindDropTarget(hwnd, TRUE);
 
-  /*
-   * If it ain't in there, it's an error.
-   */
-  if (dropTargetInfo==NULL)
-    return DRAGDROP_E_NOTREGISTERED;
+  status = wine_set_window_droptarget(hwnd, NULL, 0);
 
-  OLEDD_FreeDropTarget(dropTargetInfo, TRUE);
+  if (status == STATUS_SUCCESS)
+    hr = S_OK;
+  else if (status == STATUS_OBJECT_NAME_NOT_FOUND)
+    hr = DRAGDROP_E_NOTREGISTERED;
 
-  return S_OK;
+  return hr;
 }
 
 /***********************************************************************
@@ -1885,32 +1894,12 @@ static void OLEDD_Initialize(void)
 }
 
 /***
- * OLEDD_FreeDropTarget()
- *
- * Frees the drag and drop data structure
- */
-static void OLEDD_FreeDropTarget(DropTargetNode *dropTargetInfo, BOOL release_drop_target)
-{
-  list_remove(&dropTargetInfo->entry);
-  if (release_drop_target) IDropTarget_Release(dropTargetInfo->dropTarget);
-  HeapFree(GetProcessHeap(), 0, dropTargetInfo);
-}
-
-/***
  * OLEDD_UnInitialize()
  *
  * Releases the OLE drag and drop data structures.
  */
 void OLEDD_UnInitialize(void)
 {
-  /*
-   * Simply empty the list.
-   */
-  while (!list_empty(&targetListHead))
-  {
-    DropTargetNode* curNode = LIST_ENTRY(list_head(&targetListHead), DropTargetNode, entry);
-    OLEDD_FreeDropTarget(curNode, FALSE);
-  }
 }
 
 /***
@@ -1918,21 +1907,43 @@ void OLEDD_UnInitialize(void)
  *
  * Finds information about the drop target.
  */
-static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
+static IDropTarget* OLEDD_FindDropTarget(HWND hwndOfTarget, BOOL destroy)
 {
-  DropTargetNode*  curNode;
+  HGLOBAL hGlobal;
+  void *buffer;
+  int bufferSize = 4096;
+  size_t replySize;
+  IStream *stream;
+  IDropTarget *dropTarget = NULL;
+  HRESULT hr;
+  extern size_t wine_get_window_droptarget(HWND, char*, size_t);
 
-  /*
-   * Iterate the list to find the HWND value.
-   */
-  LIST_FOR_EACH_ENTRY(curNode, &targetListHead, DropTargetNode, entry)
-    if (hwndOfTarget==curNode->hwndTarget)
-      return curNode;
+  do
+  {
+    hGlobal = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, bufferSize);
+    if (hGlobal == NULL)
+      return NULL;
+    buffer = GlobalLock(hGlobal);
+    replySize = wine_get_window_droptarget(hwndOfTarget, buffer, bufferSize);
+    GlobalUnlock(hGlobal);
+    if (replySize >= bufferSize)
+    {
+      GlobalFree(hGlobal);
+      bufferSize *= 2;
+    }
+  } while (replySize >= bufferSize);
 
-  /*
-   * If we get here, the item is not in the list
-   */
-  return NULL;
+  hr = CreateStreamOnHGlobal(hGlobal, FALSE, &stream);
+  if (SUCCEEDED(hr))
+  {
+    if (destroy)
+      hr = CoReleaseMarshalData(stream);
+    else
+      hr = CoUnmarshalInterface(stream, &IID_IDropTarget, (void**)&dropTarget);
+    IStream_Release(stream);
+  }
+  GlobalFree(hGlobal);
+  return dropTarget;
 }
 
 /***
@@ -2038,7 +2049,7 @@ static void OLEDD_TrackMouseMove(TrackerWindowInfo* trackerInfo)
   }
   else
   {
-    DropTargetNode* newDropTargetNode = 0;
+    IDropTarget* newDropTarget = 0;
 
     /*
      * If we changed window, we have to notify our old target and check for
@@ -2061,12 +2072,12 @@ static void OLEDD_TrackMouseMove(TrackerWindowInfo* trackerInfo)
       trackerInfo->curTargetHWND = hwndNewTarget;
 
       do {
-	newDropTargetNode = OLEDD_FindDropTarget(nexttar);
-      } while (!newDropTargetNode && (nexttar = GetParent(nexttar)) != 0);
+	newDropTarget = OLEDD_FindDropTarget(nexttar, FALSE);
+      } while (!newDropTarget && (nexttar = GetParent(nexttar)) != 0);
       if(nexttar) hwndNewTarget = nexttar;
 
       trackerInfo->curDragTargetHWND = hwndNewTarget;
-      trackerInfo->curDragTarget     = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
+      trackerInfo->curDragTarget     = newDropTarget;
 
       /*
        * If there is, notify it that we just dragged-in
diff --git a/dlls/ole32/tests/dragdrop.c b/dlls/ole32/tests/dragdrop.c
index b28a831..a514455 100644
--- a/dlls/ole32/tests/dragdrop.c
+++ b/dlls/ole32/tests/dragdrop.c
@@ -152,18 +152,18 @@ START_TEST(dragdrop)
     ok(droptarget_addref_called == 0, "DropTarget_AddRef shouldn't have been called\n");
     hr = RegisterDragDrop(hwnd, &DropTarget);
     ok_ole_success(hr, "RegisterDragDrop");
-    ok(droptarget_addref_called == 1, "DropTarget_AddRef should have been called once, not %d times\n", droptarget_addref_called);
+    todo_wine ok(droptarget_addref_called == 1, "DropTarget_AddRef should have been called once, not %d times\n", droptarget_addref_called);
 
     hr = RegisterDragDrop(hwnd, &DropTarget);
     ok(hr == DRAGDROP_E_ALREADYREGISTERED, "RegisterDragDrop with already registered hwnd should return DRAGDROP_E_ALREADYREGISTERED instead of 0x%08x\n", hr);
 
-    ok(droptarget_release_called == 0, "DropTarget_Release shouldn't have been called\n");
+    todo_wine ok(droptarget_release_called == 0, "DropTarget_Release shouldn't have been called\n");
     OleUninitialize();
-    ok(droptarget_release_called == 0, "DropTarget_Release shouldn't have been called\n");
+    todo_wine ok(droptarget_release_called == 0, "DropTarget_Release shouldn't have been called\n");
 
     hr = RevokeDragDrop(hwnd);
     ok_ole_success(hr, "RevokeDragDrop");
-    ok(droptarget_release_called == 1 ||
+    todo_wine ok(droptarget_release_called == 1 ||
         broken(droptarget_release_called == 0), /* NT4 */
         "DropTarget_Release should have been called once, not %d times\n", droptarget_release_called);
 


More information about the wine-patches mailing list