private int QueryContinueDrag(int fEscapePressed, int grfKeyState) {
    if (topControl != null && topControl.isDisposed()) return COM.DRAGDROP_S_CANCEL;
    if (fEscapePressed != 0) {
      if (hwndDrag != 0) OS.ImageList_DragLeave(hwndDrag);
      return COM.DRAGDROP_S_CANCEL;
    }
    /*
     * Bug in Windows.  On some machines that do not have XBUTTONs,
     * the MK_XBUTTON1 and OS.MK_XBUTTON2 bits are sometimes set,
     * causing mouse capture to become stuck.  The fix is to test
     * for the extra buttons only when they exist.
     */
    int mask = OS.MK_LBUTTON | OS.MK_MBUTTON | OS.MK_RBUTTON;
    //	if (display.xMouse) mask |= OS.MK_XBUTTON1 | OS.MK_XBUTTON2;
    if ((grfKeyState & mask) == 0) {
      if (hwndDrag != 0) OS.ImageList_DragLeave(hwndDrag);
      return COM.DRAGDROP_S_DROP;
    }

    if (hwndDrag != 0) {
      POINT pt = new POINT();
      OS.GetCursorPos(pt);
      RECT rect = new RECT();
      OS.GetWindowRect(hwndDrag, rect);
      OS.ImageList_DragMove(pt.x - rect.left, pt.y - rect.top);
    }
    return COM.S_OK;
  }
  private void drag(Event dragEvent) {
    DNDEvent event = new DNDEvent();
    event.widget = this;
    event.x = dragEvent.x;
    event.y = dragEvent.y;
    event.time = OS.GetMessageTime();
    event.doit = true;
    notifyListeners(DND.DragStart, event);
    if (!event.doit || transferAgents == null || transferAgents.length == 0) return;

    int[] pdwEffect = new int[1];
    int operations = opToOs(getStyle());
    Display display = control.getDisplay();
    String key = "org.eclipse.swt.internal.win32.runMessagesInIdle"; // $NON-NLS-1$
    Object oldValue = display.getData(key);
    display.setData(key, Boolean.TRUE);
    ImageList imagelist = null;
    Image image = event.image;
    hwndDrag = 0;
    topControl = null;
    if (image != null) {
      imagelist = new ImageList(SWT.NONE);
      imagelist.add(image);
      topControl = control.getShell();
      /*
       * Bug in Windows. The image is inverted if the shell is RIGHT_TO_LEFT.
       * The fix is to create a transparent window that covers the shell client
       * area and use it during the drag to prevent the image from being inverted.
       * On XP if the shell is RTL, the image is not displayed.
       */
      int offsetX = event.offsetX;
      hwndDrag = topControl.handle;
      if ((topControl.getStyle() & SWT.RIGHT_TO_LEFT) != 0) {
        offsetX = image.getBounds().width - offsetX;
        RECT rect = new RECT();
        OS.GetClientRect(topControl.handle, rect);
        hwndDrag =
            OS.CreateWindowEx(
                OS.WS_EX_TRANSPARENT | OS.WS_EX_NOINHERITLAYOUT,
                WindowClass,
                null,
                OS.WS_CHILD | OS.WS_CLIPSIBLINGS,
                0,
                0,
                rect.right - rect.left,
                rect.bottom - rect.top,
                topControl.handle,
                0,
                OS.GetModuleHandle(null),
                null);
        OS.ShowWindow(hwndDrag, OS.SW_SHOW);
      }
      OS.ImageList_BeginDrag(imagelist.getHandle(), 0, offsetX, event.offsetY);
      /*
       * Feature in Windows. When ImageList_DragEnter() is called,
       * it takes a snapshot of the screen  If a drag is started
       * when another window is in front, then the snapshot will
       * contain part of the other window, causing pixel corruption.
       * The fix is to force all paints to be delivered before
       * calling ImageList_DragEnter().
       */
      if (OS.IsWinCE) {
        OS.UpdateWindow(topControl.handle);
      } else {
        int flags = OS.RDW_UPDATENOW | OS.RDW_ALLCHILDREN;
        OS.RedrawWindow(topControl.handle, null, 0, flags);
      }
      POINT pt = new POINT();
      pt.x = dragEvent.x;
      pt.y = dragEvent.y;
      OS.MapWindowPoints(control.handle, 0, pt, 1);
      RECT rect = new RECT();
      OS.GetWindowRect(hwndDrag, rect);
      OS.ImageList_DragEnter(hwndDrag, pt.x - rect.left, pt.y - rect.top);
    }
    int result = COM.DRAGDROP_S_CANCEL;
    try {
      result =
          COM.DoDragDrop(iDataObject.getAddress(), iDropSource.getAddress(), operations, pdwEffect);
    } finally {
      // ensure that we don't leave transparent window around
      if (hwndDrag != 0) {
        OS.ImageList_DragLeave(hwndDrag);
        OS.ImageList_EndDrag();
        imagelist.dispose();
        if (hwndDrag != topControl.handle) OS.DestroyWindow(hwndDrag);
        hwndDrag = 0;
        topControl = null;
      }
      display.setData(key, oldValue);
    }
    int operation = osToOp(pdwEffect[0]);
    if (dataEffect == DND.DROP_MOVE) {
      operation =
          (operation == DND.DROP_NONE || operation == DND.DROP_COPY)
              ? DND.DROP_TARGET_MOVE
              : DND.DROP_MOVE;
    } else {
      if (dataEffect != DND.DROP_NONE) {
        operation = dataEffect;
      }
    }
    event = new DNDEvent();
    event.widget = this;
    event.time = OS.GetMessageTime();
    event.doit = (result == COM.DRAGDROP_S_DROP);
    event.detail = operation;
    notifyListeners(DND.DragEnd, event);
    dataEffect = DND.DROP_NONE;
  }