protected void checkSubclass() {
   String name = getClass().getName();
   String validName = DragSource.class.getName();
   if (!validName.equals(name)) {
     DND.error(SWT.ERROR_INVALID_SUBCLASS);
   }
 }
 /**
  * This implementation of <code>javaToNative</code> converts a list of file names represented by a
  * java <code>String[]</code> to a platform specific representation. Each <code>String</code> in
  * the array contains the absolute path for a single file or directory. For additional information
  * see <code>Transfer#javaToNative</code>.
  *
  * @param object a java <code>String[]</code> containing the file names to be converted
  * @param transferData an empty <code>TransferData</code> object; this object will be filled in on
  *     return with the platform specific format of the data
  */
 public void javaToNative(Object object, TransferData transferData) {
   if (!checkFile(object) || !isSupportedType(transferData)) {
     DND.error(DND.ERROR_INVALID_DATA);
   }
   String[] fileNames = (String[]) object;
   StringBuffer allFiles = new StringBuffer();
   for (int i = 0; i < fileNames.length; i++) {
     allFiles.append(fileNames[i]);
     allFiles.append(CF_HDROP_SEPARATOR); // each name is null terminated
   }
   TCHAR buffer =
       new TCHAR(
           0, allFiles.toString(), true); // there is an extra null terminator at the very end
   DROPFILES dropfiles = new DROPFILES();
   dropfiles.pFiles = DROPFILES.sizeof;
   dropfiles.pt_x = dropfiles.pt_y = 0;
   dropfiles.fNC = 0;
   dropfiles.fWide = OS.IsUnicode ? 1 : 0;
   // Allocate the memory because the caller (DropTarget) has not handed it in
   // The caller of this method must release the data when it is done with it.
   int byteCount = buffer.length() * TCHAR.sizeof;
   int /*long*/ newPtr =
       OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, DROPFILES.sizeof + byteCount);
   OS.MoveMemory(newPtr, dropfiles, DROPFILES.sizeof);
   OS.MoveMemory(newPtr + DROPFILES.sizeof, buffer, byteCount);
   transferData.stgmedium = new STGMEDIUM();
   transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
   transferData.stgmedium.unionField = newPtr;
   transferData.stgmedium.pUnkForRelease = 0;
   transferData.result = COM.S_OK;
 }
 /**
  * Adds the listener to the collection of listeners who will be notified when a drag and drop
  * operation is in progress, by sending it one of the messages defined in the <code>
  * DragSourceListener</code> interface.
  *
  * <p>
  *
  * <ul>
  *   <li><code>dragStart</code> is called when the user has begun the actions required to drag the
  *       widget. This event gives the application the chance to decide if a drag should be
  *       started.
  *   <li><code>dragSetData</code> is called when the data is required from the drag source.
  *   <li><code>dragFinished</code> is called when the drop has successfully completed (mouse up
  *       over a valid target) or has been terminated (such as hitting the ESC key). Perform
  *       cleanup such as removing data from the source side on a successful move operation.
  * </ul>
  *
  * @param listener the listener which should be notified
  * @exception IllegalArgumentException
  *     <ul>
  *       <li>ERROR_NULL_ARGUMENT - if the listener is null
  *     </ul>
  *
  * @exception SWTException
  *     <ul>
  *       <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed
  *       <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
  *     </ul>
  *
  * @see DragSourceListener
  * @see #getDragListeners
  * @see #removeDragListener
  * @see DragSourceEvent
  */
 public void addDragListener(DragSourceListener listener) {
   if (listener == null) DND.error(SWT.ERROR_NULL_ARGUMENT);
   DNDListener typedListener = new DNDListener(listener);
   typedListener.dndWidget = this;
   addListener(DND.DragStart, typedListener);
   addListener(DND.DragSetData, typedListener);
   addListener(DND.DragEnd, typedListener);
 }
  /**
   * Creates a new <code>DragSource</code> to handle dragging from the specified <code>Control
   * </code>. Creating an instance of a DragSource may cause system resources to be allocated
   * depending on the platform. It is therefore mandatory that the DragSource instance be disposed
   * when no longer required.
   *
   * @param control the <code>Control</code> that the user clicks on to initiate the drag
   * @param style the bitwise OR'ing of allowed operations; this may be a combination of any of
   *     DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK
   * @exception SWTException
   *     <ul>
   *       <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent
   *       <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass
   *     </ul>
   *
   * @exception SWTError
   *     <ul>
   *       <li>ERROR_CANNOT_INIT_DRAG - unable to initiate drag source; this will occur if more than
   *           one drag source is created for a control or if the operating system will not allow
   *           the creation of the drag source
   *     </ul>
   *     <p>NOTE: ERROR_CANNOT_INIT_DRAG should be an SWTException, since it is a recoverable error,
   *     but can not be changed due to backward compatibility.
   * @see Widget#dispose
   * @see DragSource#checkSubclass
   * @see DND#DROP_NONE
   * @see DND#DROP_COPY
   * @see DND#DROP_MOVE
   * @see DND#DROP_LINK
   */
  public DragSource(Control control, int style) {
    super(control, checkStyle(style));
    this.control = control;
    if (control.getData(DND.DRAG_SOURCE_KEY) != null) {
      DND.error(DND.ERROR_CANNOT_INIT_DRAG);
    }
    control.setData(DND.DRAG_SOURCE_KEY, this);
    createCOMInterfaces();
    this.AddRef();

    controlListener =
        new Listener() {
          public void handleEvent(Event event) {
            if (event.type == SWT.Dispose) {
              if (!DragSource.this.isDisposed()) {
                DragSource.this.dispose();
              }
            }
            if (event.type == SWT.DragDetect) {
              if (!DragSource.this.isDisposed()) {
                DragSource.this.drag(event);
              }
            }
          }
        };
    control.addListener(SWT.Dispose, controlListener);
    control.addListener(SWT.DragDetect, controlListener);

    this.addListener(
        SWT.Dispose,
        new Listener() {
          public void handleEvent(Event e) {
            DragSource.this.onDispose();
          }
        });

    Object effect = control.getData(DEFAULT_DRAG_SOURCE_EFFECT);
    if (effect instanceof DragSourceEffect) {
      dragEffect = (DragSourceEffect) effect;
    } else if (control instanceof Tree) {
      dragEffect = new TreeDragSourceEffect((Tree) control);
    } else if (control instanceof Table) {
      dragEffect = new TableDragSourceEffect((Table) control);
    }
  }
 /**
  * Removes the listener from the collection of listeners who will be notified when a drag and drop
  * operation is in progress.
  *
  * @param listener the listener which should no longer be notified
  * @exception IllegalArgumentException
  *     <ul>
  *       <li>ERROR_NULL_ARGUMENT - if the listener is null
  *     </ul>
  *
  * @exception SWTException
  *     <ul>
  *       <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed
  *       <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
  *     </ul>
  *
  * @see DragSourceListener
  * @see #addDragListener
  * @see #getDragListeners
  */
 public void removeDragListener(DragSourceListener listener) {
   if (listener == null) DND.error(SWT.ERROR_NULL_ARGUMENT);
   removeListener(DND.DragStart, listener);
   removeListener(DND.DragSetData, listener);
   removeListener(DND.DragEnd, listener);
 }